Rizin
unix-like reverse engineering framework and cli tools
responses.c File Reference
#include "arch.h"
#include "gdbclient/responses.h"
#include "gdbclient/core.h"
#include "gdbr_common.h"
#include "utils.h"
#include "rz_util/rz_str.h"
#include <rz_debug.h>
#include <gdbclient/commands.h>

Go to the source code of this file.

Functions

int handle_g (libgdbr_t *g)
 
int handle_G (libgdbr_t *g)
 
int handle_M (libgdbr_t *g)
 
int handle_P (libgdbr_t *g)
 
int handle_m (libgdbr_t *g)
 
int handle_qStatus (libgdbr_t *g)
 
int handle_qC (libgdbr_t *g)
 
int handle_setbp (libgdbr_t *g)
 
int handle_removebp (libgdbr_t *g)
 
int handle_attach (libgdbr_t *g)
 
int handle_vFile_open (libgdbr_t *g)
 
int handle_vFile_pread (libgdbr_t *g, ut8 *buf)
 
int handle_vFile_close (libgdbr_t *g)
 
static int stop_reason_exit (libgdbr_t *g)
 
static int stop_reason_terminated (libgdbr_t *g)
 
int handle_stop_reason (libgdbr_t *g)
 
int handle_cont (libgdbr_t *g)
 
int handle_lldb_read_reg (libgdbr_t *g)
 

Function Documentation

◆ handle_attach()

int handle_attach ( libgdbr_t g)

Definition at line 124 of file responses.c.

124  {
125  if (g->data_len == 3 && g->data[0] == 'E') {
126  send_ack(g);
127  return -1;
128  }
129  return send_ack(g);
130 }
struct @667 g
int send_ack(libgdbr_t *g)
Functions sends a single ack ('+')
Definition: common.c:130

References g, and send_ack().

Referenced by gdbr_attach().

◆ handle_cont()

int handle_cont ( libgdbr_t g)

Definition at line 383 of file responses.c.

383  {
384  return handle_stop_reason(g);
385 }
int handle_stop_reason(libgdbr_t *g)
Definition: responses.c:244

References g, and handle_stop_reason().

Referenced by send_vcont().

◆ handle_g()

int handle_g ( libgdbr_t g)

For handling responses from gdbserver See Appendix E in the gdb manual (GDB Remote Serial Protocol) Packets look following: $ starts a command/packet, the end is indicated with # and a final checksum $<command>#<checksum>

Definition at line 11 of file responses.c.

11  {
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 }
int unpack_hex(const char *src, ut64 len, char *dst)
Definition: utils.c:95

References g, send_ack(), and unpack_hex().

Referenced by gdbr_read_registers().

◆ handle_G()

int handle_G ( libgdbr_t g)

Definition at line 19 of file responses.c.

19  {
20  return send_ack(g);
21 }

References g, and send_ack().

Referenced by gdbr_write_bin_registers(), and gdbr_write_registers().

◆ handle_lldb_read_reg()

int handle_lldb_read_reg ( libgdbr_t g)

Definition at line 387 of file responses.c.

387  {
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 }
#define NULL
Definition: cris-opc.c:27
voidpf void * buf
Definition: ioapi.h:138
return memset(p, 0, total)
memcpy(mem, inblock.get(), min(CONTAINING_RECORD(inblock.get(), MEMBLOCK, data) ->size, size))
#define isxdigit(c)
Definition: safe-ctype.h:145
static int
Definition: sfsocketcall.h:114
ut64 buflen
Definition: core.c:76

References buflen, g, int, isxdigit, memcpy(), memset(), NULL, send_ack(), and unpack_hex().

Referenced by gdbr_read_registers_lldb().

◆ handle_M()

int handle_M ( libgdbr_t g)

Definition at line 23 of file responses.c.

23  {
24  return send_ack(g);
25 }

References g, and send_ack().

Referenced by gdbr_write_memory().

◆ handle_m()

int handle_m ( libgdbr_t g)

Definition at line 36 of file responses.c.

36  {
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 }
size_t len
Definition: 6502dis.c:15

References g, len, send_ack(), and unpack_hex().

Referenced by gdbr_read_memory_page().

◆ handle_P()

int handle_P ( libgdbr_t g)

Definition at line 27 of file responses.c.

27  {
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 }
#define MSG_OK
Definition: libgdbr.h:15
#define MSG_NOT_SUPPORTED
Definition: libgdbr.h:16

References g, MSG_NOT_SUPPORTED, MSG_OK, and send_ack().

Referenced by gdbr_write_register().

◆ handle_qC()

int handle_qC ( libgdbr_t g)

Definition at line 77 of file responses.c.

77  {
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 }
int read_thread_id(const char *src, int *pid, int *tid, bool multiprocess)
Definition: utils.c:161

References g, read_thread_id(), and send_ack().

Referenced by gdbr_connect().

◆ handle_qStatus()

int handle_qStatus ( libgdbr_t g)

Definition at line 48 of file responses.c.

48  {
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 }
RZ_API void Ht_() free(HtName_(Ht) *ht)
Definition: ht_inc.c:130
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")

References free(), g, NULL, send_ack(), and strdup().

◆ handle_removebp()

int handle_removebp ( libgdbr_t g)

Definition at line 120 of file responses.c.

120  {
121  return send_ack(g);
122 }

References g, and send_ack().

Referenced by remove_bp().

◆ handle_setbp()

int handle_setbp ( libgdbr_t g)

Definition at line 116 of file responses.c.

116  {
117  return send_ack(g);
118 }

References g, and send_ack().

Referenced by set_bp().

◆ handle_stop_reason()

int handle_stop_reason ( libgdbr_t g)

Definition at line 244 of file responses.c.

244  {
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 }
void * calloc(size_t number, size_t size)
Definition: malloc.c:102
static int stop_reason_exit(libgdbr_t *g)
Definition: responses.c:188
static int stop_reason_terminated(libgdbr_t *g)
Definition: responses.c:215
#define eprintf(x, y...)
Definition: rlcc.c:7
@ 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

References calloc(), eprintf, free(), g, int, isxdigit, memset(), NULL, read_thread_id(), RZ_DEBUG_REASON_BREAKPOINT, RZ_DEBUG_REASON_NONE, RZ_DEBUG_REASON_SIGNAL, rz_str_startswith(), send_ack(), stop_reason_exit(), stop_reason_terminated(), and unpack_hex().

Referenced by __system(), gdbr_stop_reason(), and handle_cont().

◆ handle_vFile_close()

int handle_vFile_close ( libgdbr_t g)

Definition at line 177 of file responses.c.

177  {
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 }

References g, isxdigit, and send_ack().

Referenced by gdbr_close_file().

◆ handle_vFile_open()

int handle_vFile_open ( libgdbr_t g)

Definition at line 132 of file responses.c.

132  {
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 }

References g, isxdigit, NULL, and send_ack().

Referenced by gdbr_open_file().

◆ handle_vFile_pread()

int handle_vFile_pread ( libgdbr_t g,
ut8 buf 
)

Definition at line 145 of file responses.c.

145  {
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 }

References g, isxdigit, len, memcpy(), and send_ack().

Referenced by gdbr_read_file().

◆ stop_reason_exit()

static int stop_reason_exit ( libgdbr_t g)
static

Definition at line 188 of file responses.c.

188  {
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 }
int gdbr_disconnect(libgdbr_t *g)
disconnects the lib
Definition: core.c:283
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
static const char struct stat static buf struct stat static buf static vhangup int status
Definition: sflib.h:145
@ RZ_DEBUG_REASON_DEAD
Definition: rz_debug.h:90

References eprintf, g, gdbr_disconnect(), int, isxdigit, NULL, pid, RZ_DEBUG_REASON_DEAD, and status.

Referenced by handle_stop_reason().

◆ stop_reason_terminated()

static int stop_reason_terminated ( libgdbr_t g)
static

Definition at line 215 of file responses.c.

215  {
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 }
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

References eprintf, g, gdbr_disconnect(), int, isxdigit, NULL, pid, RZ_DEBUG_REASON_DEAD, and signal.

Referenced by handle_stop_reason().