Rizin
unix-like reverse engineering framework and cli tools
responses.c
Go to the documentation of this file.
1 // SPDX-FileCopyrightText: 2014 defragger <rlaemmert@gmail.com>
2 // SPDX-License-Identifier: LGPL-3.0-only
3 
4 #include "arch.h"
5 #include "gdbclient/responses.h"
6 #include "gdbclient/core.h"
7 #include "gdbr_common.h"
8 #include "utils.h"
9 #include "rz_util/rz_str.h"
10 
12  if (unpack_hex(g->data, g->data_len, g->data) < 0) {
13  return -1;
14  }
15  g->data_len = g->data_len / 2;
16  return send_ack(g);
17 }
18 
20  return send_ack(g);
21 }
22 
24  return send_ack(g);
25 }
26 
28  if (g->data_len == 0) {
29  g->last_code = MSG_NOT_SUPPORTED;
30  } else {
31  g->last_code = MSG_OK;
32  }
33  return send_ack(g);
34 }
35 
37  if (g->data_len == 3 && g->data[0] == 'E') {
38  // TODO: figure out if this is a problem
39  send_ack(g);
40  return -1;
41  }
42  int len = strlen(g->data);
43  g->data_len = len / 2;
44  unpack_hex(g->data, len, g->data);
45  return send_ack(g);
46 }
47 
49  if (!g || !g->data || !*g->data) {
50  return -1;
51  }
52  char *data = strdup(g->data);
53  char *tok = strtok(data, ";");
54  if (!tok) {
55  free(data);
56  return -1;
57  }
58  // TODO: We do not yet handle the case where a trace is already running
59  if (strncmp(tok, "T0", 2)) {
60  send_ack(g);
61  free(data);
62  return -1;
63  }
64  // Ensure that trace was never run
65  while (tok != NULL) {
66  if (!strncmp(tok, "tnotrun:0", 9)) {
67  free(data);
68  return send_ack(g);
69  }
70  tok = strtok(NULL, ";");
71  }
72  send_ack(g);
73  free(data);
74  return -1;
75 }
76 
78  // We get process and thread ID
79  if (strncmp(g->data, "QC", 2)) {
80  send_ack(g);
81  return -1;
82  }
83  g->data[g->data_len] = '\0';
84  if (read_thread_id(g->data + 2, &g->pid, &g->tid, g->stub_features.multiprocess) < 0) {
85  send_ack(g);
86  return -1;
87  }
88  return send_ack(g);
89 }
90 
91 /*
92 int handle_execFileRead(libgdbr_t *g) {
93  if (g->data[0] == 'E') {
94  send_ack (g);
95  return -1;
96  }
97  if (!g->data[1]) {
98  // We're supposed to get filename too
99  send_ack (g);
100  return -1;
101  }
102  g->exec_file_name = strdup (g->data + 1);
103  return send_ack (g);
104 }
105 
106 int handle_fOpen(libgdbr_t *g) {
107  if (!*g->data || g->data[0] != 'F') {
108  send_ack (g);
109  return -1;
110  }
111  g->exec_fd = strtol (g->data + 1, NULL, 16);
112  return send_ack (g);
113 }
114  */
115 
117  return send_ack(g);
118 }
119 
121  return send_ack(g);
122 }
123 
125  if (g->data_len == 3 && g->data[0] == 'E') {
126  send_ack(g);
127  return -1;
128  }
129  return send_ack(g);
130 }
131 
133  if (g->data_len < 2 || g->data[0] != 'F' || g->data[1] == '-' || !isxdigit(g->data[1])) {
134  send_ack(g);
135  return -1;
136  }
137  g->data[g->data_len] = '\0';
138  if ((g->remote_file_fd = strtol(g->data + 1, NULL, 16)) <= 0) {
139  send_ack(g);
140  return -1;
141  }
142  return send_ack(g);
143 }
144 
146  send_ack(g);
147  char *ptr;
148  int len;
149  if (g->data_len < 3 || g->data[0] != 'F') {
150  return -1;
151  }
152  // F-1 is an error, yes, but it probably should not be fatal, since it might
153  // mean we're reading beyond file end. So this is handled in gdbr_read_file
154  if (g->data[1] == '-') {
155  return 0;
156  }
157  if (!isxdigit(g->data[1])) {
158  return -1;
159  }
160  if (sscanf(g->data, "F%x;", &len) != 1) {
161  return -1;
162  }
163  // Again, this is probably the end of file
164  if (len == 0) {
165  return 0;
166  }
167  if (!(ptr = strchr(g->data, ';')) || ptr >= g->data + g->data_len) {
168  return -1;
169  }
170  ptr++;
171  if (len > 0) {
172  memcpy(buf, ptr, len);
173  }
174  return len;
175 }
176 
178  if (g->data_len < 2 || g->data[0] != 'F' || g->data[1] == '-' || !isxdigit(g->data[1])) {
179  send_ack(g);
180  return -1;
181  }
182  return send_ack(g);
183 }
184 
185 #include <rz_debug.h>
186 #include <gdbclient/commands.h>
187 
189  int status = 0, pid = g->pid;
190  g->stop_reason.reason = RZ_DEBUG_REASON_DEAD;
191  if (g->stub_features.multiprocess && g->data_len > 3) {
192  if (sscanf(g->data + 1, "%x;process:%x", &status, &pid) != 2) {
193  eprintf("Message from remote: %s\n", g->data);
194  return -1;
195  }
196  eprintf("Process %d exited with status %d\n", pid, status);
197  g->stop_reason.thread.pid = pid;
198  g->stop_reason.thread.tid = pid;
199  g->stop_reason.is_valid = true;
200  return 0;
201  }
202  if (!isxdigit(g->data[1])) {
203  eprintf("Message from remote: %s\n", g->data);
204  return -1;
205  }
206  status = (int)strtol(g->data + 1, NULL, 16);
207  eprintf("Process %d exited with status %d\n", g->pid, status);
208  g->stop_reason.thread.pid = pid;
209  g->stop_reason.thread.tid = pid;
210  g->stop_reason.is_valid = true;
211  // Just to be sure, disconnect
212  return gdbr_disconnect(g);
213 }
214 
216  int signal = 0, pid = g->pid;
217  g->stop_reason.reason = RZ_DEBUG_REASON_DEAD;
218  if (g->stub_features.multiprocess && g->data_len > 3) {
219  if (sscanf(g->data + 1, "%x;process:%x", &signal, &pid) != 2) {
220  eprintf("Message from remote: %s\n", g->data);
221  return -1;
222  }
223  eprintf("Process %d terminated with signal %d\n", pid, signal);
224  g->stop_reason.thread.pid = pid;
225  g->stop_reason.thread.tid = pid;
226  g->stop_reason.signum = signal;
227  g->stop_reason.is_valid = true;
228  return 0;
229  }
230  if (!isxdigit(g->data[1])) {
231  eprintf("Message from remote: %s\n", g->data);
232  return -1;
233  }
234  signal = (int)strtol(g->data + 1, NULL, 16);
235  eprintf("Process %d terminated with signal %d\n", g->pid, signal);
236  g->stop_reason.thread.pid = pid;
237  g->stop_reason.thread.tid = pid;
238  g->stop_reason.signum = signal;
239  g->stop_reason.is_valid = true;
240  // Just to be sure, disconnect
241  return gdbr_disconnect(g);
242 }
243 
245  send_ack(g);
246  if (g->data_len < 3) {
247  return -1;
248  }
249  switch (g->data[0]) {
250  case 'O':
251  unpack_hex(g->data + 1, g->data_len - 1, g->data + 1);
252  // g->data[g->data_len - 1] = '\0';
253  eprintf("%s", g->data + 1);
254  if (send_ack(g) < 0) {
255  return -1;
256  }
257  memset(&g->stop_reason, 0, sizeof(libgdbr_stop_reason_t));
258  g->stop_reason.signum = -1;
259  g->stop_reason.reason = RZ_DEBUG_REASON_NONE;
260  return 0;
261  case 'W':
262  return stop_reason_exit(g);
263  case 'X':
264  return stop_reason_terminated(g);
265  }
266  if (g->data[0] != 'T') {
267  return -1;
268  }
269  char *ptr1, *ptr2;
270  g->data[g->data_len] = '\0';
271  free(g->stop_reason.exec.path);
272  memset(&g->stop_reason, 0, sizeof(libgdbr_stop_reason_t));
273  g->stop_reason.core = -1;
274  if (sscanf(g->data + 1, "%02x", &g->stop_reason.signum) != 1) {
275  return -1;
276  }
277  g->stop_reason.is_valid = true;
278  g->stop_reason.reason = RZ_DEBUG_REASON_SIGNAL;
279  for (ptr1 = strtok(g->data + 3, ";"); ptr1; ptr1 = strtok(NULL, ";")) {
280  if (rz_str_startswith(ptr1, "thread") && !g->stop_reason.thread.present) {
281  if (!(ptr2 = strchr(ptr1, ':'))) {
282  continue;
283  }
284  ptr2++;
285  if (read_thread_id(ptr2, &g->stop_reason.thread.pid,
286  &g->stop_reason.thread.tid,
287  g->stub_features.multiprocess) < 0) {
288  continue;
289  }
290  g->stop_reason.thread.present = true;
291  continue;
292  }
293  if (rz_str_startswith(ptr1, "core")) {
294  if (!(ptr2 = strchr(ptr1, ':'))) {
295  continue;
296  }
297  ptr2++;
298  if (!isxdigit(*ptr2)) {
299  continue;
300  }
301  g->stop_reason.core = (int)strtol(ptr2, NULL, 16);
302  continue;
303  }
304  if (g->stop_reason.signum == 5) {
305  if (rz_str_startswith(ptr1, "watch") || rz_str_startswith(ptr1, "rwatch") || rz_str_startswith(ptr1, "awatch")) {
306  if (!(ptr2 = strchr(ptr1, ':'))) {
307  continue;
308  }
309  ptr2++;
310  if (!isxdigit(*ptr2)) {
311  continue;
312  }
313  g->stop_reason.watchpoint.addr = strtoll(ptr2, NULL, 16);
314  g->stop_reason.watchpoint.present = true;
315  continue;
316  }
317  if (rz_str_startswith(ptr1, "exec") && !g->stop_reason.exec.present) {
318  if (!(ptr2 = strchr(ptr1, ':'))) {
319  continue;
320  }
321  ptr2++;
322  if (!(g->stop_reason.exec.path = calloc(strlen(ptr1) / 2, 1))) {
323  continue;
324  }
325  unpack_hex(ptr2, strlen(ptr2), g->stop_reason.exec.path);
326  g->stop_reason.exec.present = true;
327  continue;
328  }
329  if (rz_str_startswith(ptr1, "fork") && !g->stop_reason.fork.present) {
330  if (!(ptr2 = strchr(ptr1, ':'))) {
331  continue;
332  }
333  ptr2++;
334  if (read_thread_id(ptr2, &g->stop_reason.fork.pid,
335  &g->stop_reason.fork.tid,
336  g->stub_features.multiprocess) < 0) {
337  continue;
338  }
339  g->stop_reason.fork.present = true;
340  continue;
341  }
342  if (rz_str_startswith(ptr1, "vfork") && !g->stop_reason.vfork.present) {
343  if (!(ptr2 = strchr(ptr1, ':'))) {
344  continue;
345  }
346  ptr2++;
347  if (read_thread_id(ptr2, &g->stop_reason.vfork.pid,
348  &g->stop_reason.vfork.tid,
349  g->stub_features.multiprocess) < 0) {
350  continue;
351  }
352  g->stop_reason.vfork.present = true;
353  continue;
354  }
355  if (rz_str_startswith(ptr1, "vforkdone")) {
356  g->stop_reason.vforkdone = true;
357  continue;
358  }
359  if (rz_str_startswith(ptr1, "library")) {
360  g->stop_reason.library = true;
361  continue;
362  }
363  if (rz_str_startswith(ptr1, "swbreak")) {
364  g->stop_reason.swbreak = true;
365  continue;
366  }
367  if (rz_str_startswith(ptr1, "hwbreak")) {
368  g->stop_reason.hwbreak = true;
369  continue;
370  }
371  if (rz_str_startswith(ptr1, "create")) {
372  g->stop_reason.create = true;
373  continue;
374  }
375  }
376  }
377  if (g->stop_reason.signum == 5) {
378  g->stop_reason.reason = RZ_DEBUG_REASON_BREAKPOINT;
379  }
380  return 0;
381 }
382 
384  return handle_stop_reason(g);
385 }
386 
388  if (send_ack(g) < 0) {
389  return -1;
390  }
391  char *ptr, *ptr2, *buf;
392  size_t regnum, tot_regs, buflen = 0;
393 
394  // Get maximum register number
395  for (regnum = 0; *g->registers[regnum].name; regnum++) {
396  if (g->registers[regnum].offset + g->registers[regnum].size > buflen) {
397  buflen = g->registers[regnum].offset + g->registers[regnum].size;
398  }
399  }
400  tot_regs = regnum;
401 
402  // We're not using the receive buffer till next packet anyway. Better use it
403  buf = g->read_buff;
404  memset(buf, 0, buflen);
405 
406  if (!(ptr = strtok(g->data, ";"))) {
407  return -1;
408  }
409  while (ptr) {
410  if (!isxdigit(*ptr)) {
411  // This is not a reg value. Skip
412  ptr = strtok(NULL, ";");
413  continue;
414  }
415  // Get register number
416  regnum = (int)strtoul(ptr, NULL, 16);
417  if (regnum >= tot_regs || !(ptr2 = strchr(ptr, ':'))) {
418  ptr = strtok(NULL, ";");
419  continue;
420  }
421  ptr2++;
422  // Write to offset
423  unpack_hex(ptr2, strlen(ptr2), buf + g->registers[regnum].offset);
424  ptr = strtok(NULL, ";");
425  continue;
426  }
427  memcpy(g->data, buf, buflen);
428  g->data_len = buflen;
429  return 0;
430 }
size_t len
Definition: 6502dis.c:15
int gdbr_disconnect(libgdbr_t *g)
disconnects the lib
Definition: core.c:283
#define NULL
Definition: cris-opc.c:27
struct @667 g
int send_ack(libgdbr_t *g)
Functions sends a single ack ('+')
Definition: common.c:130
RZ_API void Ht_() free(HtName_(Ht) *ht)
Definition: ht_inc.c:130
voidpf void * buf
Definition: ioapi.h:138
uint8_t ut8
Definition: lh5801.h:11
return memset(p, 0, total)
memcpy(mem, inblock.get(), min(CONTAINING_RECORD(inblock.get(), MEMBLOCK, data) ->size, size))
#define MSG_OK
Definition: libgdbr.h:15
#define MSG_NOT_SUPPORTED
Definition: libgdbr.h:16
void * calloc(size_t number, size_t size)
Definition: malloc.c:102
static static fork const void static count static fd const char const char static newpath char char char static envp time_t static t const char static mode static whence const char static dir time_t static t unsigned static seconds const char struct utimbuf static buf static inc pid
Definition: sflib.h:64
return strdup("=SP r13\n" "=LR r14\n" "=PC r15\n" "=A0 r0\n" "=A1 r1\n" "=A2 r2\n" "=A3 r3\n" "=ZF zf\n" "=SF nf\n" "=OF vf\n" "=CF cf\n" "=SN or0\n" "gpr lr .32 56 0\n" "gpr pc .32 60 0\n" "gpr cpsr .32 64 0 ____tfiae_________________qvczn\n" "gpr or0 .32 68 0\n" "gpr tf .1 64.5 0 thumb\n" "gpr ef .1 64.9 0 endian\n" "gpr jf .1 64.24 0 java\n" "gpr qf .1 64.27 0 sticky_overflow\n" "gpr vf .1 64.28 0 overflow\n" "gpr cf .1 64.29 0 carry\n" "gpr zf .1 64.30 0 zero\n" "gpr nf .1 64.31 0 negative\n" "gpr itc .4 64.10 0 if_then_count\n" "gpr gef .4 64.16 0 great_or_equal\n" "gpr r0 .32 0 0\n" "gpr r1 .32 4 0\n" "gpr r2 .32 8 0\n" "gpr r3 .32 12 0\n" "gpr r4 .32 16 0\n" "gpr r5 .32 20 0\n" "gpr r6 .32 24 0\n" "gpr r7 .32 28 0\n" "gpr r8 .32 32 0\n" "gpr r9 .32 36 0\n" "gpr r10 .32 40 0\n" "gpr r11 .32 44 0\n" "gpr r12 .32 48 0\n" "gpr r13 .32 52 0\n" "gpr r14 .32 56 0\n" "gpr r15 .32 60 0\n" "gpr r16 .32 64 0\n" "gpr r17 .32 68 0\n")
static static fork const void static count static fd const char static mode const char static pathname const char static path const char static dev const char static group static getpid static getuid void void static data static pause const char static mode static sync const char const char static newpath const char static pathname unsigned long static filedes void static end_data_segment signal
Definition: sflib.h:79
static const char struct stat static buf struct stat static buf static vhangup int status
Definition: sflib.h:145
static int stop_reason_exit(libgdbr_t *g)
Definition: responses.c:188
int handle_G(libgdbr_t *g)
Definition: responses.c:19
int handle_qStatus(libgdbr_t *g)
Definition: responses.c:48
int handle_M(libgdbr_t *g)
Definition: responses.c:23
int handle_lldb_read_reg(libgdbr_t *g)
Definition: responses.c:387
int handle_vFile_pread(libgdbr_t *g, ut8 *buf)
Definition: responses.c:145
int handle_m(libgdbr_t *g)
Definition: responses.c:36
int handle_vFile_close(libgdbr_t *g)
Definition: responses.c:177
int handle_setbp(libgdbr_t *g)
Definition: responses.c:116
int handle_cont(libgdbr_t *g)
Definition: responses.c:383
int handle_stop_reason(libgdbr_t *g)
Definition: responses.c:244
int handle_g(libgdbr_t *g)
Definition: responses.c:11
int handle_removebp(libgdbr_t *g)
Definition: responses.c:120
int handle_attach(libgdbr_t *g)
Definition: responses.c:124
int handle_vFile_open(libgdbr_t *g)
Definition: responses.c:132
static int stop_reason_terminated(libgdbr_t *g)
Definition: responses.c:215
int handle_qC(libgdbr_t *g)
Definition: responses.c:77
int handle_P(libgdbr_t *g)
Definition: responses.c:27
#define eprintf(x, y...)
Definition: rlcc.c:7
@ RZ_DEBUG_REASON_DEAD
Definition: rz_debug.h:90
@ RZ_DEBUG_REASON_BREAKPOINT
Definition: rz_debug.h:94
@ RZ_DEBUG_REASON_NONE
Definition: rz_debug.h:91
@ RZ_DEBUG_REASON_SIGNAL
Definition: rz_debug.h:92
RZ_API bool rz_str_startswith(RZ_NONNULL const char *str, RZ_NONNULL const char *needle)
Checks if a string starts with a specifc sequence of characters (case sensitive)
Definition: str.c:3286
#define isxdigit(c)
Definition: safe-ctype.h:145
static int
Definition: sfsocketcall.h:114
int unpack_hex(const char *src, ut64 len, char *dst)
Definition: utils.c:95
int read_thread_id(const char *src, int *pid, int *tid, bool multiprocess)
Definition: utils.c:161
ut64 buflen
Definition: core.c:76