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