ROSE  0.11.50.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 <array>
7 #include <Rose/BitFlags.h>
8 #include <boost/filesystem.hpp>
9 #include <boost/noncopyable.hpp>
10 #include <boost/regex.hpp>
11 #include <Rose/BinaryAnalysis/Disassembler.h>
12 #include <Sawyer/BitVector.h>
13 #include <Sawyer/Message.h>
14 #include <Sawyer/Optional.h>
15 #include <Sawyer/Trace.h>
16 
17 namespace Rose {
18 namespace BinaryAnalysis {
19 
22 
26 class Debugger: private boost::noncopyable, public Sawyer::SharedObject {
27 public:
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_; // process being debugged (int, not pid_t, for Windows portability)
240  DetachMode autoDetach_; // how to detach from the subordinate when deleting this debugger
241  int wstat_; // last status from waitpid
242  AddressIntervalSet breakpoints_; // list of breakpoint addresses
243  int sendSignal_; // 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_; // cached width in bits of kernel's words
247  RegisterPage regsPage_; // latest register information read from subordinate
248  RegPageStatus regsPageStatus_; // what are the contents of regsPage_?
249  Disassembler *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  : child_(0), autoDetach_(KILL), wstat_(-1), sendSignal_(0), kernelWordSize_(0), regsPageStatus_(REGPAGE_NONE),
258  disassembler_(NULL) {
259  init();
260  }
261 
263  explicit Debugger(const Specimen &specimen)
264  : child_(0), autoDetach_(KILL), wstat_(-1), sendSignal_(0), kernelWordSize_(0), regsPageStatus_(REGPAGE_NONE),
265  disassembler_(NULL) {
266  init();
267  attach(specimen);
268  }
269 
270 public:
271  ~Debugger() {
272  detach(autoDetach_);
273  }
274 
275  //----------------------------------------
276  // Static allocating constructors
277  //----------------------------------------
278 public:
280  static Ptr instance() {
281  return Ptr(new Debugger);
282  }
283 
285  static Ptr instance(const Specimen &specimen) {
286  return Ptr(new Debugger(specimen));
287  }
288 
289  //----------------------------------------
290  // Attaching to subordinate
291  //----------------------------------------
292 public:
300  void attach(const Specimen&, Sawyer::Optional<DetachMode> onDelete = Sawyer::Nothing());
304  int isAttached() { return child_; }
305 
311 
313  void terminate();
314 
315  //----------------------------------------
316  // Operations on a subordinate
317  //----------------------------------------
318 public:
320  void executionAddress(rose_addr_t va);
321 
323  rose_addr_t executionAddress();
324 
326  void setBreakpoint(const AddressInterval&);
327 
329  void clearBreakpoint(const AddressInterval&);
330 
332  void clearBreakpoints() { breakpoints_.clear(); }
333 
335  void singleStep();
336 
338  void stepIntoSyscall();
339 
340 #if 0 // [Robb Matzke 2021-05-26]: doesn't seem to work on Linux 5.4: always says PTRACE_SYSCALL_INFO_NONE
341 
342  struct SyscallEntry {
343  uint64_t functionNumber;
344  std::vector<uint64_t> arguments;
346  SyscallEntry()
347  : functionNumber(0) {}
348  SyscallEntry(uint64_t functionNumber, uint64_t arguments[6])
349  : functionNumber(functionNumber), arguments(arguments+0, arguments+6) {}
350  };
351 
356  Sawyer::Optional<SyscallEntry> syscallEntryInfo();
357 
359  class SyscallExit {
360  bool isError_; // if true, then retval is -errno
361  int64_t retval_;
362  public:
363  SyscallExit()
364  : isError_(true), retval_(-EINVAL) {}
365  SyscallExit(int64_t retval, uint8_t isError)
366  : isError_(isError != 0), retval_(retval) {}
367 
369  Sawyer::Optional<int64_t> returnValue() const {
370  if (isError_) {
371  return Sawyer::Nothing();
372  } else {
373  return retval_;
374  }
375  }
376 
378  Sawyer::Optional<int> errorNumber() const {
379  if (isError_) {
380  return -retval_;
381  } else {
382  return Sawyer::Nothing();
383  }
384  }
385 
387  uint64_t rawReturn() const {
388  return (uint64_t)retval_;
389  }
390  };
391 
396  Sawyer::Optional<SyscallExit> syscallExitInfo();
397 #endif
398 
400  void runToBreakpoint();
401 
406  void runToSyscall();
407 
410 
413  REJECT = 0x00000001,
414  STOP = 0x00000002
415  };
416 
423 
429  template<class Filter>
432  while (!isTerminated()) {
433  rose_addr_t va = executionAddress();
434  FilterAction action = filter(va);
435  if (action.isClear(REJECT))
436  retval.append(va);
437  if (action.isSet(STOP))
438  return retval;
439  singleStep();
440  }
441  return retval;
442  }
443 
446  size_t kernelWordSize();
447 
457 
462  void writeRegister(RegisterDescriptor, uint64_t value);
468  AllRegisters readAllRegisters();
469 
473  void writeAllRegisters(const AllRegisters&);
474 
479  size_t readMemory(rose_addr_t va, size_t nBytes, uint8_t *buffer);
480 
484  std::vector<uint8_t> readMemory(rose_addr_t va, size_t nBytes);
485 
491  Sawyer::Container::BitVector readMemory(rose_addr_t va, size_t nBytes, ByteOrder::Endianness order);
492 
496  size_t writeMemory(rose_addr_t va, size_t nBytes, const uint8_t *bytes);
497 
501  template<typename T>
502  void writeMemory(rose_addr_t va, const T &value) {
503  size_t n = writeMemory(va, sizeof(T), (const uint8_t*)&value);
504  ASSERT_always_require(n == sizeof(T));
505  }
506 
512  std::string readCString(rose_addr_t va, size_t maxBytes = UNLIMITED);
513 
515  bool isTerminated();
516 
518  std::string howTerminated();
519 
521  const RegisterDictionary* registerDictionary() const;
522 
525  return disassembler_;
526  }
527 
529  int waitpidStatus() const { return wstat_; }
530 
534  int64_t remoteSystemCall(int syscallNumber);
535  int64_t remoteSystemCall(int syscallNumber,
536  uint64_t arg1);
537  int64_t remoteSystemCall(int syscallNumber,
538  uint64_t arg1, uint64_t arg2);
539  int64_t remoteSystemCall(int syscallNumber,
540  uint64_t arg1, uint64_t arg2, uint64_t arg3);
541  int64_t remoteSystemCall(int syscallNumber,
542  uint64_t arg1, uint64_t arg2, uint64_t arg3, uint64_t arg4);
543  int64_t remoteSystemCall(int syscallNumber,
544  uint64_t arg1, uint64_t arg2, uint64_t arg3, uint64_t arg4, uint64_t arg5);
545  int64_t remoteSystemCall(int syscallNumber,
546  uint64_t arg1, uint64_t arg2, uint64_t arg3, uint64_t arg4, uint64_t arg5, uint64_t arg6);
547  int64_t remoteSystemCall(int syscallNumber, std::vector<uint64_t> args);
554  int remoteOpenFile(const boost::filesystem::path &fileName, unsigned flags, mode_t mode);
555 
557  int remoteCloseFile(unsigned remoteFd);
558 
562  rose_addr_t remoteMmap(rose_addr_t va, size_t nBytes, unsigned prot, unsigned flags, const boost::filesystem::path&,
563  off_t offset);
564 
565 public:
567  static void initDiagnostics();
568 
569 private:
570  // Initialize tables during construction
571  void init();
572 
573  // Wait for subordinate or throw on error
574  void waitForChild();
575 
576  // Open /dev/null with the specified flags as the indicated file descriptor, closing what was previously on that
577  // descriptor. If an error occurs, the targetFd is closed anyway.
578  void devNullTo(int targetFd, int openFlags);
579 
580  // Get/set personality in a portable way
581  static unsigned long getPersonality();
582  static void setPersonality(unsigned long);
583 
584  // Address of a system call instruction. The initial search can be expensive, so the result is cached.
585  Sawyer::Optional<rose_addr_t> findSystemCall();
586 
587 };
588 
589 std::ostream& operator<<(std::ostream&, const Debugger::Specimen&);
590 
591 } // namespace
592 } // namespace
593 
594 #endif
595 #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:304
void clearBreakpoints()
Remove all breakpoints.
Definition: Debugger.h:332
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
const size_t UNLIMITED(-1)
Effictively unlimited size.
void workingDirectory(const boost::filesystem::path &name)
Property: Current working directory for running a program.
Definition: Debugger.h:155
Debugger(const Specimen &specimen)
Construct a debugger attached to a specimen.
Definition: Debugger.h:263
void stepIntoSyscall()
Execute to a system call.
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:280
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
Sawyer::SharedPointer< class Debugger > DebuggerPtr
Shared-ownership pointer to Debugger.
Definition: Debugger.h:21
void detach(Sawyer::Optional< DetachMode > mode=Sawyer::Nothing())
Detach from the subordinate.
Sawyer::SharedPointer< Debugger > Ptr
Shared-ownership pointer to Debugger.
Definition: Debugger.h:29
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:529
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:502
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:430
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.
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:422
static Ptr instance(const Specimen &specimen)
Create a debugger and start debugging a specimen.
Definition: Debugger.h:285
Disassembler * disassembler() const
Disassembler.
Definition: Debugger.h:524
Specimen(const std::vector< std::string > &nameAndArgs)
Construct a specimen description from combined program and arguments.
Definition: Debugger.h:84
void clear()
Remove all values.
Definition: IntervalSet.h:487
FilterActionFlags
Action for trace filter callback.
Definition: Debugger.h:412
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.
const RegisterDictionary * registerDictionary() const
Available registers.
unsigned long persona() const
Property: Personality flags.
Definition: Debugger.h:180
Defines registers available for a particular architecture.
Definition: Registers.h:37
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.
Virtual base class for instruction disassemblers.
Definition: Disassembler.h:50
Abort tracing, either appending or rejecting the current address.
Definition: Debugger.h:414
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:413
std::string readCString(rose_addr_t va, size_t maxBytes=UNLIMITED)
Read C-style NUL-terminated string from subordinate.