ROSE 0.11.145.317
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);
97 void print(std::ostream&) const;
98
100 std::string toString() const;
101 };
102
103 // Thread-safe FIFO
104 template<class T>
105 class Fifo {
106 public:
107 using Value = T;
108
109 private:
110 std::condition_variable cond_; // notified by append()
111 std::mutex mutex_; // protects the following data members
112 std::list<Value> items_;
113 bool isClosed_ = false;
114
115 public:
116 // Append an item to the list
117 void append(const Value &item) {
118 const std::lock_guard<std::mutex> lock(mutex_);
119 items_.push_back(item);
120 cond_.notify_one();
121 }
122
123 // Remove all items from this FIFO
124 void clear() {
125 const std::lock_guard<std::mutex> lock(mutex_);
126 items_.clear();
127 cond_.notify_all();
128 }
129
130 // Mark the list as closed. No more items can be appended.
131 void close() {
132 {
133 const std::lock_guard<std::mutex> lock(mutex_);
134 isClosed_ = true;
135 }
136 cond_.notify_all();
137 }
138
139 // Returns the item from the queue, if any.
140 Sawyer::Optional<Value> nonblockingNext() {
141 const std::lock_guard<std::mutex> lock(mutex_);
142 if (items_.empty()) {
143 return Sawyer::Nothing();
144 } else {
145 Value item = items_.front();
146 items_.pop_front();
147 return item;
148 }
149 }
150
151 // Blocks until an item can be returned or the queue is closed
152 Sawyer::Optional<Value> blockingNext() {
153 std::unique_lock<std::mutex> lock(mutex_);
154 while (items_.empty() && !isClosed_)
155 cond_.wait(lock);
156 if (items_.empty()) {
157 return Sawyer::Nothing();
158 } else {
159 Value item = items_.front();
160 items_.pop_front();
161 return item;
162 }
163 }
164
165 // Remvoe all items
166 void reset() {
167 std::lock_guard<std::mutex> lock(mutex_);
168 items_.clear();
169 isClosed_ = false;
170 }
171 };
172
173 // GDB command response record
174 struct Response {
175 bool hasEndMarker = false;
176
177 struct ResultRecord {
178 enum ResultClass { EMPTY, DONE, RUNNING, CONNECTED, ERROR, EXIT };
179 ResultClass rclass = EMPTY;
180 std::string token;
181 std::list<Yaml::Node> results;
182 };
183
184 std::list<ResultRecord> resultRecord;
185 };
186
187 // A register descriptor or just a size in bits.
188 class RegInfo {
189 RegisterDescriptor reg_; // might be invalid (default constructed, false)
190 size_t nBits_ = 0; // valid only if `reg` is invalid
191 public:
192 explicit RegInfo(RegisterDescriptor);
193 explicit RegInfo(size_t);
194 RegisterDescriptor reg() const;
195 size_t nBits() const;
196 };
197
199 // Data members
201private:
202 std::thread gdbThread_;
203 Fifo<std::string> gdbOutput_;
204 boost::asio::io_context ioctx_;
205 boost::process::async_pipe gdbOutputPipe_;
206 boost::process::opstream gdbInput_;
207 boost::asio::streambuf gdbOutputBuffer_;
208 std::vector<std::pair<std::string, RegInfo>> registers_; // info about registers obtained from GDB; some entries empty
209 std::list<GdbResponse> responses_; // accumulated responses
210 AddressIntervalSet breakPoints_; // all break points
211 std::map<Address, unsigned /*bp_id*/> gdbBreakPoints_; // subset of breakpoints known to GDB
212 std::future<int> exitCodeFuture_; // exit code returned from GDB thread
213 Sawyer::Optional<int> exitCode_; // exit code from the GDB process
214#ifdef NDEBUG
215 bool checkWrites_ = false; // perform a read after each write to verify what we wrote
216#else
217 bool checkWrites_ = true;
218#endif
219
221 // Constructors and destructors
223protected:
224 Gdb();
225public:
226 ~Gdb();
227
228public:
232 static Ptr instance();
233
237 static Ptr instance(const Specimen&);
238
240 // Properties
242public:
250 bool checkWrites() const;
251 void checkWrites(bool);
255 // Attaching and detaching
257public:
261 virtual void attach(const Specimen&);
262
264 // Low-level stuff not often used publically but available nonetheless.
266public:
273 const std::list<GdbResponse>& sendCommand(const std::string&);
274
279 std::list<GdbResponse> readRequiredResponses();
280
285 std::list<GdbResponse> readOptionalResponses();
286
290 const std::list<GdbResponse>& responses() const;
291
293 void resetResponses();
294
298 const std::vector<std::pair<std::string, RegInfo>>& registerNames() const;
299
301 // Overrides for methods declared and documented in the super class.
303public:
304 virtual bool isAttached() override;
305 virtual void detach() override;
306 virtual void terminate() override;
307 virtual std::vector<ThreadId> threadIds() override;
308 virtual void setBreakPoint(const AddressInterval&) override;
309 virtual void setBreakPoints(const AddressIntervalSet&) override;
310 virtual AddressIntervalSet breakPoints() override;
311 virtual void clearBreakPoint(const AddressInterval&) override;
312 virtual void clearBreakPoints() override;
313 virtual void singleStep(ThreadId) override;
314 virtual void runToBreakPoint(ThreadId) override;
315 virtual Sawyer::Container::BitVector readRegister(ThreadId, RegisterDescriptor) override;
316 virtual std::vector<RegisterDescriptor> availableRegisters() override;
317 virtual void writeRegister(ThreadId, RegisterDescriptor, const Sawyer::Container::BitVector&) override;
318 virtual void writeRegister(ThreadId, RegisterDescriptor, uint64_t value) override;
319 virtual size_t readMemory(Address va, size_t nBytes, uint8_t *buffer) override;
320 virtual std::vector<uint8_t> readMemory(Address va, size_t nBytes) override;
321 virtual Sawyer::Container::BitVector readMemory(Address va, size_t nBytes, ByteOrder::Endianness order) override;
322 virtual size_t writeMemory(Address va, size_t nBytes, const uint8_t *bytes) override;
323 virtual bool isTerminated() override;
324 virtual std::string howTerminated() override;
325 virtual Sawyer::Container::BitVector readAllRegisters(ThreadId) override;
326 virtual void writeAllRegisters(ThreadId, const Sawyer::Container::BitVector&) override;
327
329 // Supporting functions
331private:
332 // Read GDB's multi-line response to a command
333 std::list<GdbResponse> readResponseSet(bool required);
334
335 // Find the index for the GDB register whose major and minor numbers match the specified register.
336 Sawyer::Optional<size_t> findRegisterIndex(RegisterDescriptor) const;
337
338 // Find the register descriptor for the GDB register whose major and minor numbers match the specified register. Returns an
339 // empty descriptor if not found.
340 RegisterDescriptor findRegister(RegisterDescriptor) const;
341
342 // True if GDB should handle the break points; false if ROSE should handle the break points.
343 bool gdbHandlesBreakPoints() const;
344
345 // Parse a result from -data-list-register-values. Specifically, the command returns a vector of objects each of which has
346 // a "number" and a "value" field. The number is the GDB register index, and the "value" is the string that this function
347 // is attempting to parse. The value (assuming the first argument to the command was "x") is either a hexadecimal string
348 // of arbitrary length, or a string that starts with "{uint<N> = <HEX>," where "<N>" is the number of bits and "<HEX>" is
349 // the string this function returns.
350 std::string parseDataListRegisterValuesValue(const std::string&);
351
352 // Read a register according to its GDB index.
353 Sawyer::Container::BitVector readRegisterIndexed(ThreadId, size_t);
354};
355
356std::ostream& operator<<(std::ostream&, const Gdb::Specimen&);
357
358} // namespace
359} // namespace
360} // namespace
361
362#endif
363#endif
Represents no value.
Definition Optional.h:34
Holds a value or nothing.
Definition Optional.h:54
Sawyer::SharedPointer< Node > Ptr
Reference counting pointer.
void print(const GlobalVariables &, const Partitioner2::PartitionerConstPtr &, std::ostream &out, const std::string &prefix="")
Print info about multiple global variables.
Sawyer::Container::IntervalSet< AddressInterval > AddressIntervalSet
A set of virtual addresses.
std::uint64_t Address
Address.
Definition Address.h:11
size_t nBits(Unsigned=Unsigned(0))
Number of bits in a type or value.
Definition BitOps.h:20
ROSE_UTIL_API std::string toString(const Path &)
Convert a path to a string.
ROSE_DLL_API void clear()
Empties the memory pool of all nodes.
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...