Save/restore tselect. Set dmode.
[riscv-isa-sim.git] / riscv / gdbserver.h
1 #ifndef _RISCV_GDBSERVER_H
2 #define _RISCV_GDBSERVER_H
3
4 #include <map>
5 #include <queue>
6
7 #include <stdint.h>
8
9 class sim_t;
10
11 template <typename T>
12 class circular_buffer_t
13 {
14 public:
15 // The buffer can store capacity-1 data elements.
16 circular_buffer_t(unsigned int capacity) : data(new T[capacity]),
17 start(0), end(0), capacity(capacity) {}
18 circular_buffer_t() : start(0), end(0), capacity(0) {}
19 ~circular_buffer_t() { delete[] data; }
20
21 T *data;
22 unsigned int start; // Data start, inclusive.
23 unsigned int end; // Data end, exclusive.
24 unsigned int capacity; // Size of the buffer.
25 unsigned int size() const;
26 bool empty() const { return start == end; }
27 bool full() const { return ((end+1) % capacity) == start; }
28
29 // Return size and address of the block of RAM where more data can be copied
30 // to be added to the buffer.
31 unsigned int contiguous_empty_size() const;
32 T *contiguous_empty() { return data + end; }
33 void data_added(unsigned int bytes);
34
35 unsigned int contiguous_data_size() const;
36 T *contiguous_data() { return data + start; }
37 // Tell the buffer that some bytes were consumed from the start of the
38 // buffer.
39 void consume(unsigned int bytes);
40
41 void reset();
42
43 T operator[](unsigned int i) const { return data[(start + i) % capacity]; }
44
45 void append(const T *src, unsigned int count);
46 };
47
48 // Class to track software breakpoints that we set.
49 class software_breakpoint_t
50 {
51 public:
52 reg_t vaddr;
53 unsigned int size;
54 unsigned char instruction[4];
55 };
56
57 class hardware_breakpoint_t
58 {
59 public:
60 reg_t vaddr;
61 unsigned int size;
62 unsigned int index;
63 bool load, store, execute;
64 };
65
66 struct hardware_breakpoint_compare_t {
67 bool operator()(const hardware_breakpoint_t& a, const hardware_breakpoint_t& b) const {
68 if (a.vaddr != b.vaddr)
69 return a.vaddr < b.vaddr;
70 return a.size < b.size;
71 }
72 };
73
74 class gdbserver_t;
75
76 class operation_t
77 {
78 public:
79 operation_t(gdbserver_t& gdbserver) : gs(gdbserver), current_step(0) {}
80 virtual ~operation_t() {}
81
82 bool step() {
83 bool result = perform_step(current_step);
84 current_step++;
85 return result;
86 }
87
88 // Perform the next step of this operation (which is probably to write to
89 // Debug RAM and assert the debug interrupt).
90 // Return true if this operation is complete. In that case the object will
91 // be deleted.
92 // Return false if more steps are required the next time the debug
93 // interrupt is clear.
94 virtual bool perform_step(unsigned int step) = 0;
95
96 protected:
97 gdbserver_t& gs;
98 unsigned int current_step;
99 };
100
101 /*
102 * word 32 64 128
103 * 0 inst/0 inst/0 inst/0
104 * 1 inst inst/0 inst/0
105 * 2 inst inst inst/0
106 * 3 inst inst inst/0
107 * 4 data0 data0 data0
108 * 5 data1 data0 data0
109 * 6 data2 data1 data0
110 * 7 data1 data0
111 * 8 data2 data1
112 * 9 data2 data1
113 * 10 data1
114 * 11 data1
115 * 12 data2
116 * 13 data2
117 * 14 data2
118 * 15 data2
119 */
120 enum slot {
121 SLOT_INST0,
122 SLOT_DATA0,
123 SLOT_DATA1,
124 SLOT_DATA_LAST,
125 };
126
127 static const unsigned int slot_offset32[] = {0, 4, 5, DEBUG_RAM_SIZE/4 - 1};
128 static const unsigned int slot_offset64[] = {0, 4, 6, DEBUG_RAM_SIZE/4 - 2};
129 static const unsigned int slot_offset128[] = {0, 4, 8, DEBUG_RAM_SIZE/4 - 4};
130
131 typedef enum {
132 GB_SOFTWARE = 0,
133 GB_HARDWARE = 1,
134 GB_WRITE = 2,
135 GB_READ = 3,
136 GB_ACCESS = 4,
137 } gdb_breakpoint_type_t;
138
139 class gdbserver_t
140 {
141 public:
142 // Create a new server, listening for connections from localhost on the given
143 // port.
144 gdbserver_t(uint16_t port, sim_t *sim);
145
146 // Process all pending messages from a client.
147 void handle();
148
149 void handle_packet(const std::vector<uint8_t> &packet);
150 void handle_interrupt();
151
152 void software_breakpoint_remove(reg_t vaddr, unsigned int size);
153 void software_breakpoint_insert(reg_t vaddr, unsigned int size);
154 void hardware_breakpoint_remove(const hardware_breakpoint_t &bp);
155 void hardware_breakpoint_insert(const hardware_breakpoint_t &bp);
156
157 void handle_breakpoint(const std::vector<uint8_t> &packet);
158 void handle_continue(const std::vector<uint8_t> &packet);
159 void handle_extended(const std::vector<uint8_t> &packet);
160 void handle_general_registers_read(const std::vector<uint8_t> &packet);
161 void continue_general_registers_read();
162 void handle_halt_reason(const std::vector<uint8_t> &packet);
163 void handle_kill(const std::vector<uint8_t> &packet);
164 void handle_memory_binary_write(const std::vector<uint8_t> &packet);
165 void handle_memory_read(const std::vector<uint8_t> &packet);
166 void handle_query(const std::vector<uint8_t> &packet);
167 void handle_register_read(const std::vector<uint8_t> &packet);
168 void continue_register_read();
169 void handle_register_write(const std::vector<uint8_t> &packet);
170 void handle_step(const std::vector<uint8_t> &packet);
171
172 bool connected() const { return client_fd > 0; }
173
174 // TODO: Move this into its own packet sending class?
175 // Add the given message to send_buf.
176 void send(const char* msg);
177 // Hex-encode a 64-bit value, and send it to gcc in target byte order (little
178 // endian).
179 void send(uint64_t value);
180 // Hex-encode a 32-bit value, and send it to gcc in target byte order (little
181 // endian).
182 void send(uint32_t value);
183 // Hex-encode an 8-bit value, and send it to gcc.
184 void send(uint8_t value);
185 void send_packet(const char* data);
186 uint8_t running_checksum;
187 // Send "$" and clear running checksum.
188 void start_packet();
189 // Send "#" and checksum.
190 void end_packet(const char* data=NULL);
191
192 // Write value to the index'th word in Debug RAM.
193 void dr_write32(unsigned int index, uint32_t value);
194 void dr_write64(unsigned int index, uint64_t value);
195 void dr_write(enum slot slot, uint64_t value);
196 // Write jump-to-resume instruction to the index'th word in Debug RAM.
197 void dr_write_jump(unsigned int index);
198 // Write an xlen-bit store instruction.
199 void dr_write_store(unsigned int index, unsigned int reg, enum slot);
200 void dr_write_load(unsigned int index, unsigned int reg, enum slot);
201 uint32_t dr_read32(unsigned int index);
202 uint64_t dr_read64(unsigned int index);
203 uint64_t dr_read(enum slot slot);
204
205 // Return access size to use when writing length bytes to address, so that
206 // every write will be aligned.
207 unsigned int find_access_size(reg_t address, int length);
208
209 void set_interrupt(uint32_t hartid);
210
211 // Members that ought to be privated, but that we'd really like to access
212 // from operation classes.
213 reg_t dpc;
214 reg_t dcsr;
215 reg_t mstatus;
216 reg_t sptbr;
217 bool sptbr_valid;
218 reg_t tselect;
219 bool tselect_valid;
220 bool fence_i_required;
221
222 std::map<reg_t, reg_t> pte_cache;
223
224 reg_t translate(reg_t vaddr);
225 // Return the PRV_x that is used when the code under debug performs a memory
226 // access.
227 unsigned int privilege_mode();
228 // Return the VM_x that is used when the code under debug performs a memory
229 // access.
230 unsigned int virtual_memory();
231
232 unsigned int xlen;
233
234 std::set<hardware_breakpoint_t, hardware_breakpoint_compare_t>
235 hardware_breakpoints;
236
237 private:
238 sim_t *sim;
239 int socket_fd;
240 int client_fd;
241 circular_buffer_t<uint8_t> recv_buf;
242 circular_buffer_t<uint8_t> send_buf;
243
244 bool expect_ack;
245 bool extended_mode;
246 // Used to track whether we think the target is running. If we think it is
247 // but it isn't, we need to tell gdb about it.
248 bool running;
249
250 std::map<reg_t, software_breakpoint_t> software_breakpoints;
251
252 // Read pending data from the client.
253 void read();
254 void write();
255 // Accept a new client if there isn't one already connected.
256 void accept();
257 // Process all complete requests in recv_buf.
258 void process_requests();
259
260 std::queue<operation_t*> operation_queue;
261 void add_operation(operation_t* operation);
262 };
263
264 #endif