ROSE  0.11.145.0
Gdb.h
1 #ifndef ROSE_BinaryAnalysis_Debugger_Gdb_H
2 #define ROSE_BinaryAnalysis_Debugger_Gdb_H
3 #include <featureTests.h>
4 #ifdef ROSE_ENABLE_DEBUGGER_GDB
5 
6 #include <Rose/BinaryAnalysis/Debugger/Base.h>
7 #include <Rose/BinaryAnalysis/Debugger/GdbResponse.h>
8 #include <Rose/Yaml.h>
9 
10 #include <boost/asio.hpp>
11 #include <boost/filesystem.hpp>
12 #include <boost/process.hpp>
13 
14 #include <condition_variable>
15 #include <future>
16 #include <string>
17 #include <thread>
18 
19 namespace Rose {
20 namespace BinaryAnalysis {
21 namespace Debugger {
22 
24 class Gdb: public Base {
25 
27  // Types
29 public:
31  using Ptr = GdbPtr;
32 
34  class Specimen {
35  public:
39  struct Remote {
40  std::string host = "localhost";
41  uint16_t port = 1234;
42  };
43 
44  private:
45  boost::filesystem::path gdbName_ = "gdb-multiarch"; // name of the GDB executable
46  boost::filesystem::path executable_; // optional name of executable containing symbols
47  Remote remote_; // how to connect to the GDB server
48 
49  public:
51  Specimen();
52 
58  Specimen(const boost::filesystem::path &exeName);
59 
67  Specimen(const boost::filesystem::path &exeName, const std::string &host, uint16_t port);
68 
69  public:
73  const boost::filesystem::path &gdbName() const;
74  void gdbName(const boost::filesystem::path&);
83  const boost::filesystem::path& executable() const;
84  void executable(const boost::filesystem::path&);
90  const Remote& remote() const;
91  void remote(const Remote&);
92  void remote(const std::string &host, uint16_t port);
94  };
95 
96  // Thread-safe FIFO
97  template<class T>
98  class Fifo {
99  public:
100  using Value = T;
101 
102  private:
103  std::condition_variable cond_; // notified by append()
104  std::mutex mutex_; // protects the following data members
105  std::list<Value> items_;
106  bool isClosed_ = false;
107 
108  public:
109  // Append an item to the list
110  void append(const Value &item) {
111  const std::lock_guard<std::mutex> lock(mutex_);
112  items_.push_back(item);
113  cond_.notify_one();
114  }
115 
116  // Remove all items from this FIFO
117  void clear() {
118  const std::lock_guard<std::mutex> lock(mutex_);
119  items_.clear();
120  cond_.notify_all();
121  }
122 
123  // Mark the list as closed. No more items can be appended.
124  void close() {
125  {
126  const std::lock_guard<std::mutex> lock(mutex_);
127  isClosed_ = true;
128  }
129  cond_.notify_all();
130  }
131 
132  // Returns the item from the queue, if any.
133  Sawyer::Optional<Value> nonblockingNext() {
134  const std::lock_guard<std::mutex> lock(mutex_);
135  if (items_.empty()) {
136  return Sawyer::Nothing();
137  } else {
138  Value item = items_.front();
139  items_.pop_front();
140  return item;
141  }
142  }
143 
144  // Blocks until an item can be returned or the queue is closed
145  Sawyer::Optional<Value> blockingNext() {
146  std::unique_lock<std::mutex> lock(mutex_);
147  while (items_.empty() && !isClosed_)
148  cond_.wait(lock);
149  if (items_.empty()) {
150  return Sawyer::Nothing();
151  } else {
152  Value item = items_.front();
153  items_.pop_front();
154  return item;
155  }
156  }
157 
158  // Remvoe all items
159  void reset() {
160  std::lock_guard<std::mutex> lock(mutex_);
161  items_.clear();
162  isClosed_ = false;
163  }
164  };
165 
166  // GDB command response record
167  struct Response {
168  bool hasEndMarker = false;
169 
170  struct ResultRecord {
171  enum ResultClass { EMPTY, DONE, RUNNING, CONNECTED, ERROR, EXIT };
172  ResultClass rclass = EMPTY;
173  std::string token;
174  std::list<Yaml::Node> results;
175  };
176 
177  std::list<ResultRecord> resultRecord;
178  };
179 
180 
182  // Data members
184 private:
185  std::thread gdbThread_;
186  Fifo<std::string> gdbOutput_;
187  boost::asio::io_service ios_;
188  boost::process::async_pipe gdbOutputPipe_;
189  boost::process::opstream gdbInput_;
190  boost::asio::streambuf gdbOutputBuffer_;
191  std::vector<std::pair<std::string, RegisterDescriptor>> registers_;
192  std::list<GdbResponse> responses_; // accumulated responses
193  AddressIntervalSet breakPoints_; // all break points
194  std::map<rose_addr_t, unsigned /*bp_id*/> gdbBreakPoints_; // subset of breakpoints known to GDB
195  std::future<int> exitCodeFuture_; // exit code returned from GDB thread
196  Sawyer::Optional<int> exitCode_; // exit code from the GDB process
197 
199  // Constructors and destructors
201 protected:
202  Gdb();
203 public:
204  ~Gdb();
205 
206 public:
210  static Ptr instance();
211 
215  static Ptr instance(const Specimen&);
216 
218  // Attaching and detaching
220 public:
224  virtual void attach(const Specimen&);
225 
227  // Low-level stuff not often used publically but available nonetheless.
229 public:
236  const std::list<GdbResponse>& sendCommand(const std::string&);
237 
242  std::list<GdbResponse> readRequiredResponses();
243 
248  std::list<GdbResponse> readOptionalResponses();
249 
253  const std::list<GdbResponse>& responses() const;
254 
256  void resetResponses();
257 
261  const std::vector<std::pair<std::string, RegisterDescriptor>>& registerNames() const;
262 
264  // Overrides for methods declared and documented in the super class.
266 public:
267  virtual bool isAttached() override;
268  virtual void detach() override;
269  virtual void terminate() override;
270  virtual std::vector<ThreadId> threadIds() override;
271  virtual void setBreakPoint(const AddressInterval&) override;
272  virtual void clearBreakPoint(const AddressInterval&) override;
273  virtual void clearBreakPoints() override;
274  virtual void singleStep(ThreadId) override;
275  virtual void runToBreakPoint(ThreadId) override;
276  virtual Sawyer::Container::BitVector readRegister(ThreadId, RegisterDescriptor) override;
277  virtual std::vector<RegisterDescriptor> availableRegisters() override;
278  virtual void writeRegister(ThreadId, RegisterDescriptor, const Sawyer::Container::BitVector&) override;
279  virtual void writeRegister(ThreadId, RegisterDescriptor, uint64_t value) override;
280  virtual size_t readMemory(rose_addr_t va, size_t nBytes, uint8_t *buffer) override;
281  virtual std::vector<uint8_t> readMemory(rose_addr_t va, size_t nBytes) override;
282  virtual Sawyer::Container::BitVector readMemory(rose_addr_t va, size_t nBytes, ByteOrder::Endianness order) override;
283  virtual size_t writeMemory(rose_addr_t va, size_t nBytes, const uint8_t *bytes) override;
284  virtual bool isTerminated() override;
285  virtual std::string howTerminated() override;
286  virtual Sawyer::Container::BitVector readAllRegisters(ThreadId) override;
287  virtual void writeAllRegisters(ThreadId, const Sawyer::Container::BitVector&) override;
288 
290  // Supporting functions
292 private:
293  // Read GDB's multi-line response to a command
294  std::list<GdbResponse> readResponseSet(bool required);
295 
296  // Find the index for the GDB register whose major and minor numbers match the specified register.
297  Sawyer::Optional<size_t> findRegisterIndex(RegisterDescriptor) const;
298 
299  // Find the register descriptor for the GDB register whose major and minor numbers match the specified register. Returns
300  // an empty descriptor if not found.
301  RegisterDescriptor findRegister(RegisterDescriptor) const;
302 
303  // True if GDB should handle the break points; false if ROSE should handle the break points.
304  bool gdbHandlesBreakPoints() const;
305 };
306 
307 } // namespace
308 } // namespace
309 } // namespace
310 
311 #endif
312 #endif
ROSE_DLL_API void clear()
Empties the memory pool of all nodes.
Error messages that indicate an abnormal situation from which the program was able to at least partia...
Definition: Message.h:330
Main namespace for the ROSE library.
const char * ResultClass(int64_t)
Convert Rose::BinaryAnalysis::Debugger::Gdb::Response::ResultRecord::ResultClass enum constant to a s...
Sawyer::SharedPointer< Node > Ptr
Reference counting pointer.
Represents no value.
Definition: Optional.h:32