ROSE  0.11.98.0
Debugger.h
1 #ifndef ROSE_BinaryAnalysis_Debugger_H
2 #define ROSE_BinaryAnalysis_Debugger_H
3 #include <featureTests.h>
4 #ifdef ROSE_ENABLE_BINARY_ANALYSIS
5 
6 #include <Rose/BinaryAnalysis/BasicTypes.h>
7 #include <Rose/BinaryAnalysis/Disassembler/BasicTypes.h>
8 #include <Rose/BitFlags.h>
9 
10 #include <Sawyer/BitVector.h>
11 #include <Sawyer/Message.h>
12 #include <Sawyer/Optional.h>
13 #include <Sawyer/Trace.h>
14 
15 #include <array>
16 #include <boost/filesystem.hpp>
17 #include <boost/noncopyable.hpp>
18 #include <boost/regex.hpp>
19 
20 namespace Rose {
21 namespace BinaryAnalysis {
22 
26 class Debugger: private boost::noncopyable, public Sawyer::SharedObject {
27 public:
29  using Ptr = DebuggerPtr;
30 
32  enum DetachMode {
33  KILL,
37  };
38 
40  enum Flag {
41  ATTACH = 0x00000001,
42  REDIRECT_INPUT = 0x00000002,
43  REDIRECT_OUTPUT = 0x00000004,
44  REDIRECT_ERROR = 0x00000008,
45  CLOSE_FILES = 0x00000010,
46  DEFAULT_FLAGS = 0x00000013
47  };
48 
52  class Specimen {
53  BitFlags<Flag> flags_; // operational flags
54  unsigned long persona_; // personality(2) flags
55 
56  // Members for running a program
57  boost::filesystem::path program_; // full path of executable program
58  std::vector<std::string> arguments_; // command-line arguments of executable program
59  boost::filesystem::path workingDirectory_; // name or working directory, or use CWD if empty
60  std::vector<boost::regex> clearEnvVars_; // clear environment variables matching these patterns
61  std::map<std::string, std::string> setEnvVars_; // environment variables to be set
62 
63  // Members for attaching to a process
64  int pid_; // process ID (int instead of pid_t for portability)
65 
66  public:
69  : persona_(getPersonality()), pid_(-1) {}
70 
72  Specimen(int pid) /*implicit*/
73  : flags_(DEFAULT_FLAGS), persona_(getPersonality()), pid_(pid) {}
74 
76  Specimen(const boost::filesystem::path &name) /*implicit*/
77  : flags_(DEFAULT_FLAGS), persona_(getPersonality()), program_(name), pid_(-1) {}
78 
80  Specimen(const boost::filesystem::path &name, const std::vector<std::string> &args)
81  : flags_(DEFAULT_FLAGS), persona_(getPersonality()), program_(name), arguments_(args), pid_(-1) {}
82 
84  Specimen(const std::vector<std::string> &nameAndArgs) /*implicit*/
85  : flags_(DEFAULT_FLAGS), persona_(getPersonality()), program_(nameAndArgs.front()),
86  arguments_(nameAndArgs.begin()+1, nameAndArgs.end()), pid_(-1) {
87  }
88 
89  public:
96  boost::filesystem::path program() const {
97  return program_;
98  }
99  void program(const boost::filesystem::path &name) {
100  program_ = name;
101  pid_ = -1;
102  }
111  const std::vector<std::string>& arguments() const {
112  return arguments_;
113  }
114  void arguments(const std::vector<std::string> &args) {
115  arguments_ = args;
116  }
124  void eraseEnvironmentVariable(const std::string&);
125 
131  void eraseMatchingEnvironmentVariables(const boost::regex&);
132 
137 
143  void insertEnvironmentVariable(const std::string &name, const std::string &value);
144 
152  boost::filesystem::path workingDirectory() const {
153  return workingDirectory_;
154  }
155  void workingDirectory(const boost::filesystem::path &name) {
156  workingDirectory_ = name;
157  }
165  const BitFlags<Flag>& flags() const {
166  return flags_;
167  }
169  return flags_;
170  }
180  unsigned long persona() const {
181  return persona_;
182  }
183  void persona(unsigned long bits) {
184  persona_ = bits;
185  }
196  bool randomizedAddresses() const;
197  void randomizedAddresses(bool);
206  int process() const {
207  return pid_;
208  }
209  void process(int pid) {
210  pid_ = pid;
211  program_.clear();
212  }
216  void print(std::ostream &out) const;
217 
218  // Used internally.
219  char** prepareEnvAdjustments() const;
220  };
221 
222 public:
226  using RegisterPage = std::array<uint8_t, 512>;
227 
229  struct AllRegisters {
230  RegisterPage regs;
231  RegisterPage fpregs;
232  };
233 
234 private:
236  enum RegPageStatus { REGPAGE_NONE, REGPAGE_REGS, REGPAGE_FPREGS };
237 
238  Specimen specimen_; // description of specimen being debugged
239  int child_ = 0; // process being debugged (int, not pid_t, for Windows portability)
240  DetachMode autoDetach_ = KILL; // how to detach from the subordinate when deleting this debugger
241  int wstat_ = -1; // last status from waitpid
242  AddressIntervalSet breakpoints_; // list of breakpoint addresses
243  int sendSignal_ = 0; // pending signal
244  UserRegDefs userRegDefs_; // how registers map to user_regs_struct in <sys/user.h>
245  UserRegDefs userFpRegDefs_; // how registers map to user_fpregs_struct in <sys/user.h>
246  size_t kernelWordSize_ = 0; // cached width in bits of kernel's words
247  RegisterPage regsPage_; // latest register information read from subordinate
248  RegPageStatus regsPageStatus_ = REGPAGE_NONE; // what are the contents of regsPage_?
249  Disassembler::BasePtr disassembler_; // how to disassemble instructions
250  Sawyer::Optional<rose_addr_t> syscallVa_; // address of some executable system call instruction.
251 
252  //----------------------------------------
253  // Real constructors
254  //----------------------------------------
255 protected:
256  Debugger();
257 
259  explicit Debugger(const Specimen &specimen);
260 
261 public:
262  ~Debugger();
263 
264  //----------------------------------------
265  // Static allocating constructors
266  //----------------------------------------
267 public:
269  static Ptr instance() {
270  return Ptr(new Debugger);
271  }
272 
274  static Ptr instance(const Specimen &specimen) {
275  return Ptr(new Debugger(specimen));
276  }
277 
278  //----------------------------------------
279  // Attaching to subordinate
280  //----------------------------------------
281 public:
289  void attach(const Specimen&, Sawyer::Optional<DetachMode> onDelete = Sawyer::Nothing());
293  int isAttached() { return child_; }
294 
300 
302  void terminate();
303 
304  //----------------------------------------
305  // Operations on a subordinate
306  //----------------------------------------
307 public:
309  void executionAddress(rose_addr_t va);
310 
312  rose_addr_t executionAddress();
313 
315  void setBreakpoint(const AddressInterval&);
316 
318  void clearBreakpoint(const AddressInterval&);
319 
321  void clearBreakpoints() { breakpoints_.clear(); }
322 
324  void singleStep();
325 
327  void stepIntoSyscall();
328 
329 #if 0 // [Robb Matzke 2021-05-26]: doesn't seem to work on Linux 5.4: always says PTRACE_SYSCALL_INFO_NONE
330 
331  struct SyscallEntry {
332  uint64_t functionNumber;
333  std::vector<uint64_t> arguments;
335  SyscallEntry()
336  : functionNumber(0) {}
337  SyscallEntry(uint64_t functionNumber, uint64_t arguments[6])
338  : functionNumber(functionNumber), arguments(arguments+0, arguments+6) {}
339  };
340 
345  Sawyer::Optional<SyscallEntry> syscallEntryInfo();
346 
348  class SyscallExit {
349  bool isError_; // if true, then retval is -errno
350  int64_t retval_;
351  public:
352  SyscallExit()
353  : isError_(true), retval_(-EINVAL) {}
354  SyscallExit(int64_t retval, uint8_t isError)
355  : isError_(isError != 0), retval_(retval) {}
356 
358  Sawyer::Optional<int64_t> returnValue() const {
359  if (isError_) {
360  return Sawyer::Nothing();
361  } else {
362  return retval_;
363  }
364  }
365 
367  Sawyer::Optional<int> errorNumber() const {
368  if (isError_) {
369  return -retval_;
370  } else {
371  return Sawyer::Nothing();
372  }
373  }
374 
376  uint64_t rawReturn() const {
377  return (uint64_t)retval_;
378  }
379  };
380 
385  Sawyer::Optional<SyscallExit> syscallExitInfo();
386 #endif
387 
389  void runToBreakpoint();
390 
395  void runToSyscall();
396 
399 
402  REJECT = 0x00000001,
403  STOP = 0x00000002
404  };
405 
412 
418  template<class Filter>
421  while (!isTerminated()) {
422  rose_addr_t va = executionAddress();
423  FilterAction action = filter(va);
424  if (action.isClear(REJECT))
425  retval.append(va);
426  if (action.isSet(STOP))
427  return retval;
428  singleStep();
429  }
430  return retval;
431  }
432 
435  size_t kernelWordSize();
436 
446 
451  void writeRegister(RegisterDescriptor, uint64_t value);
457  AllRegisters readAllRegisters();
458 
462  void writeAllRegisters(const AllRegisters&);
463 
468  size_t readMemory(rose_addr_t va, size_t nBytes, uint8_t *buffer);
469 
473  std::vector<uint8_t> readMemory(rose_addr_t va, size_t nBytes);
474 
480  Sawyer::Container::BitVector readMemory(rose_addr_t va, size_t nBytes, ByteOrder::Endianness order);
481 
485  size_t writeMemory(rose_addr_t va, size_t nBytes, const uint8_t *bytes);
486 
490  template<typename T>
491  void writeMemory(rose_addr_t va, const T &value) {
492  size_t n = writeMemory(va, sizeof(T), (const uint8_t*)&value);
493  ASSERT_always_require(n == sizeof(T));
494  }
495 
501  std::string readCString(rose_addr_t va, size_t maxBytes = UNLIMITED);
502 
504  bool isTerminated();
505 
507  std::string howTerminated();
508 
511 
514 
516  int waitpidStatus() const { return wstat_; }
517 
521  int64_t remoteSystemCall(int syscallNumber);
522  int64_t remoteSystemCall(int syscallNumber,
523  uint64_t arg1);
524  int64_t remoteSystemCall(int syscallNumber,
525  uint64_t arg1, uint64_t arg2);
526  int64_t remoteSystemCall(int syscallNumber,
527  uint64_t arg1, uint64_t arg2, uint64_t arg3);
528  int64_t remoteSystemCall(int syscallNumber,
529  uint64_t arg1, uint64_t arg2, uint64_t arg3, uint64_t arg4);
530  int64_t remoteSystemCall(int syscallNumber,
531  uint64_t arg1, uint64_t arg2, uint64_t arg3, uint64_t arg4, uint64_t arg5);
532  int64_t remoteSystemCall(int syscallNumber,
533  uint64_t arg1, uint64_t arg2, uint64_t arg3, uint64_t arg4, uint64_t arg5, uint64_t arg6);
534  int64_t remoteSystemCall(int syscallNumber, std::vector<uint64_t> args);
541  int remoteOpenFile(const boost::filesystem::path &fileName, unsigned flags, mode_t mode);
542 
544  int remoteCloseFile(unsigned remoteFd);
545 
549  rose_addr_t remoteMmap(rose_addr_t va, size_t nBytes, unsigned prot, unsigned flags, const boost::filesystem::path&,
550  off_t offset);
551 
552 public:
554  static void initDiagnostics();
555 
556 private:
557  // Initialize tables during construction
558  void init();
559 
560  // Wait for subordinate or throw on error
561  void waitForChild();
562 
563  // Open /dev/null with the specified flags as the indicated file descriptor, closing what was previously on that
564  // descriptor. If an error occurs, the targetFd is closed anyway.
565  void devNullTo(int targetFd, int openFlags);
566 
567  // Get/set personality in a portable way
568  static unsigned long getPersonality();
569  static void setPersonality(unsigned long);
570 
571  // Address of a system call instruction. The initial search can be expensive, so the result is cached.
572  Sawyer::Optional<rose_addr_t> findSystemCall();
573 
574 };
575 
576 std::ostream& operator<<(std::ostream&, const Debugger::Specimen&);
577 
578 } // namespace
579 } // namespace
580 
581 #endif
582 #endif
Close all file descriptors > 2.
Definition: Debugger.h:45
size_t readMemory(rose_addr_t va, size_t nBytes, uint8_t *buffer)
Read subordinate memory.
void print(std::ostream &out) const
Print some basic info about the specimen.
Records and replays traces.
Definition: Trace.h:262
const std::vector< std::string > & arguments() const
Property: Program command-line arguments.
Definition: Debugger.h:111
int isAttached()
Returns true if attached to a subordinate.
Definition: Debugger.h:293
void clearBreakpoints()
Remove all breakpoints.
Definition: Debugger.h:321
void singleStep()
Execute one instruction.
void append(const Label &label)
Append a label to a trace.
Definition: Trace.h:476
Attach to existing process.
Definition: Debugger.h:41
void workingDirectory(const boost::filesystem::path &name)
Property: Current working directory for running a program.
Definition: Debugger.h:155
void stepIntoSyscall()
Execute to a system call.
DebuggerPtr Ptr
Shared-ownership pointer to Debugger.
Definition: Debugger.h:29
Sawyer::Container::Trace< rose_addr_t > trace()
Run the program and return an execution trace.
Collection of streams.
Definition: Message.h:1606
boost::filesystem::path workingDirectory() const
Property: Current working directory for running a program.
Definition: Debugger.h:152
int remoteOpenFile(const boost::filesystem::path &fileName, unsigned flags, mode_t mode)
Cause the subordinate to open a file.
DetachMode
How to detach from a process when the debugger is destroyed.
Definition: Debugger.h:32
Redirect output to /dev/null.
Definition: Debugger.h:43
size_t kernelWordSize()
Obtain and cache kernel's word size in bits.
int64_t remoteSystemCall(int syscallNumber)
Cause the subordinate to execute a system call.
void eraseMatchingEnvironmentVariables(const boost::regex &)
Remove some environment variables.
Specimen(const boost::filesystem::path &name, const std::vector< std::string > &args)
Construct a specimen description for a program with arguments.
Definition: Debugger.h:80
bool isSet(Enum e) const
Test whether a bit is set.
std::array< uint8_t, 512 > RegisterPage
Opaque collection of register values.
Definition: Debugger.h:226
Redirect input from /dev/null.
Definition: Debugger.h:42
static Ptr instance()
Create a debugger object that isn't attached to any subordinate process.
Definition: Debugger.h:269
Redirect standard error to /dev/null.
Definition: Debugger.h:44
void runToBreakpoint()
Run until the next breakpoint is reached.
Main namespace for the ROSE library.
boost::filesystem::path program() const
Property: Name of executable program to run.
Definition: Debugger.h:96
const size_t UNLIMITED(static_cast< size_t >(-1))
Effictively unlimited size.
void detach(Sawyer::Optional< DetachMode > mode=Sawyer::Nothing())
Detach from the subordinate.
Sawyer::Container::BitVector readRegister(RegisterDescriptor)
Read subordinate register.
void attach(const Specimen &, Sawyer::Optional< DetachMode > onDelete=Sawyer::Nothing())
Attach to a specimen.
Reference-counting intrusive smart pointer.
Definition: SharedPointer.h:68
int waitpidStatus() const
Returns the last status from a call to waitpid.
Definition: Debugger.h:516
Specimen(int pid)
Construct a specimen description for a process.
Definition: Debugger.h:72
Specimen()
Default construct an empty specimen descriptor.
Definition: Debugger.h:68
bool randomizedAddresses() const
Property: Whether to randomize addresses of a process.
void writeMemory(rose_addr_t va, const T &value)
Write subordinate memory.
Definition: Debugger.h:491
const BitFlags< Flag > & flags() const
Property: Operational flags.
Definition: Debugger.h:165
AllRegisters readAllRegisters()
Read all registers.
Sawyer::Container::Trace< rose_addr_t > trace(Filter &filter)
Run the program and return an execution trace.
Definition: Debugger.h:419
void writeRegister(RegisterDescriptor, const Sawyer::Container::BitVector &)
Write subordinate register.
void persona(unsigned long bits)
Property: Personality flags.
Definition: Debugger.h:183
int remoteCloseFile(unsigned remoteFd)
Cause the subordinate to close a file.
Describes (part of) a physical CPU register.
static void initDiagnostics()
Initialize diagnostic output.
void terminate()
Terminate the subordinate.
RegisterDictionaryPtr registerDictionary() const
Available registers.
Simple debugger.
Definition: Debugger.h:26
Describes the specimen to be debugged.
Definition: Debugger.h:52
int process() const
Property: Process ID.
Definition: Debugger.h:206
void arguments(const std::vector< std::string > &args)
Property: Program command-line arguments.
Definition: Debugger.h:114
bool isClear(Enum e) const
Test whether a bit is clear.
void setBreakpoint(const AddressInterval &)
Set breakpoints.
BitFlags< FilterActionFlags > FilterAction
Return value for tracing.
Definition: Debugger.h:411
static Ptr instance(const Specimen &specimen)
Create a debugger and start debugging a specimen.
Definition: Debugger.h:274
Binary analysis.
Specimen(const std::vector< std::string > &nameAndArgs)
Construct a specimen description from combined program and arguments.
Definition: Debugger.h:84
Disassembler::BasePtr disassembler() const
Disassembler.
void clear()
Remove all values.
Definition: IntervalSet.h:487
FilterActionFlags
Action for trace filter callback.
Definition: Debugger.h:401
void eraseAllEnvironmentVariables()
Remove all environment variables.
void process(int pid)
Property: Process ID.
Definition: Debugger.h:209
void runToSyscall()
Run until the next system call.
void program(const boost::filesystem::path &name)
Property: Name of executable program to run.
Definition: Debugger.h:99
static Sawyer::Message::Facility mlog
Diagnostic facility for debugger.
Definition: Debugger.h:223
Specimen(const boost::filesystem::path &name)
Construct a specimen description for a program with no arguments.
Definition: Debugger.h:76
Base class for reference counted objects.
Definition: SharedObject.h:64
size_t writeMemory(rose_addr_t va, size_t nBytes, const uint8_t *bytes)
Writes some bytes to subordinate memory.
void writeAllRegisters(const AllRegisters &)
Write all registers.
void clearBreakpoint(const AddressInterval &)
Remove breakpoints.
void eraseEnvironmentVariable(const std::string &)
Remove an environment variable.
std::string howTerminated()
String describing how the subordinate process terminated.
unsigned long persona() const
Property: Personality flags.
Definition: Debugger.h:180
Represents no value.
Definition: Optional.h:32
void insertEnvironmentVariable(const std::string &name, const std::string &value)
Add an environment variable.
Simply detach leaving process in current state.
Definition: Debugger.h:34
rose_addr_t remoteMmap(rose_addr_t va, size_t nBytes, unsigned prot, unsigned flags, const boost::filesystem::path &, off_t offset)
Map a new memory region in the subordinate.
bool isTerminated()
Returns true if the subordinate terminated.
Abort tracing, either appending or rejecting the current address.
Definition: Debugger.h:403
Detach from process and cause it to continue running.
Definition: Debugger.h:35
rose_addr_t executionAddress()
Get execution address.
BitFlags< Flag > & flags()
Property: Operational flags.
Definition: Debugger.h:168
Normal and floating point register values.
Definition: Debugger.h:229
Flag
Flags controlling operation.
Definition: Debugger.h:40
Reject the current address, not appending it to the trace.
Definition: Debugger.h:402
std::string readCString(rose_addr_t va, size_t maxBytes=UNLIMITED)
Read C-style NUL-terminated string from subordinate.