Rizin
unix-like reverse engineering framework and cli tools
io_gdb.c
Go to the documentation of this file.
1 // SPDX-FileCopyrightText: 2010-2020 pancake <pancake@nopcode.org>
2 // SPDX-License-Identifier: LGPL-3.0-only
3 
4 #include <rz_io.h>
5 #include <rz_lib.h>
6 #include <rz_socket.h>
7 #include <rz_util.h>
8 #include <ctype.h>
9 #define IRAPI static inline
10 #include <libgdbr.h>
11 #include <gdbclient/commands.h>
12 #include <gdbclient/responses.h>
13 
14 typedef struct {
16 } RzIOGdb;
17 
18 #define RZ_GDB_MAGIC rz_str_djb2_hash("gdb")
19 
20 static int __close(RzIODesc *fd);
21 static libgdbr_t *desc = NULL;
22 
23 static bool __plugin_open(RzIO *io, const char *file, bool many) {
24  return (!strncmp(file, "gdb://", 6));
25 }
26 
27 static int debug_gdb_read_at(ut8 *buf, int sz, ut64 addr) {
28  if (sz < 1 || addr >= UT64_MAX || !desc) {
29  return -1;
30  }
31  return gdbr_read_memory(desc, addr, buf, sz);
32 }
33 
34 static int debug_gdb_write_at(const ut8 *buf, int sz, ut64 addr) {
35  ut32 x, size_max;
36  ut32 packets;
37  ut32 last;
38  if (sz < 1 || addr >= UT64_MAX || !desc) {
39  return -1;
40  }
41  size_max = desc->read_max;
42  packets = sz / size_max;
43  last = sz % size_max;
44  ut64 offset = 0;
45  for (x = 0; x < packets; x++, offset += size_max) {
46  gdbr_write_memory(desc, addr + offset, buf + offset, size_max);
47  }
48  if (last) {
50  }
51  return sz;
52 }
53 
54 static RzIODesc *__open(RzIO *io, const char *file, int rw, int mode) {
55  RzIODesc *riogdb = NULL;
56  RzIOGdb *riog;
57  char host[128], *port, *pid;
58  int i_port = -1;
59  bool isdev = false;
60 
61  if (!__plugin_open(io, file, 0)) {
62  return NULL;
63  }
64  strncpy(host, file + 6, sizeof(host) - 1);
65  host[sizeof(host) - 1] = '\0';
66  if (host[0] == '/') {
67  isdev = true;
68  }
69 
70  if (isdev) {
71  port = strchr(host, '@');
72  if (port) {
73  *port = '\0';
74  port++;
75  pid = strchr(port, ':');
76  } else {
77  pid = strchr(host, ':');
78  }
79  } else {
80  port = strchr(host, ':');
81  if (!port) {
82  eprintf("Invalid debugger URI. Port missing?\nPlease use either\n"
83  " - gdb://host:port[/pid] for a network gdbserver.\n"
84  " - gdb:///dev/DEVICENAME[@speed][:pid] for a serial gdbserver.\n");
85  return NULL;
86  }
87  *port = '\0';
88  port++;
89  pid = strchr(port, '/');
90  }
91 
92  int i_pid = -1;
93  if (pid) {
94  *pid = 0;
95  pid++;
96  i_pid = atoi(pid);
97  }
98 
99  if (port) {
100  i_port = atoi(port);
101  }
102 
103  if (!(riog = RZ_NEW0(RzIOGdb))) {
104  return NULL;
105  }
106  gdbr_init(&riog->desc, false);
107 
108  if (gdbr_connect(&riog->desc, host, i_port) == 0) {
109  __close(NULL);
110  // RZ_FREE (desc);
111  desc = &riog->desc;
112  if (pid > 0) { // FIXME this is here for now because RzDebug's pid and libgdbr's aren't properly synced.
113  desc->pid = i_pid;
114  if (gdbr_attach(desc, i_pid) < 0) {
115  eprintf("gdbr: Failed to attach to PID %i\n", i_pid);
116  return NULL;
117  }
118  } else if ((i_pid = desc->pid) < 0) {
119  i_pid = -1;
120  }
121  riogdb = rz_io_desc_new(io, &rz_io_plugin_gdb, file, RZ_PERM_RWX, mode, riog);
122  }
123  // Get name
124  if (riogdb) {
125  riogdb->name = gdbr_exec_file_read(desc, i_pid);
126  } else {
127  eprintf("gdb.io.open: Cannot connect to host.\n");
128  free(riog);
129  }
130  return riogdb;
131 }
132 
133 static int __write(RzIO *io, RzIODesc *fd, const ut8 *buf, int count) {
134  ut64 addr = io->off;
135  if (!desc || !desc->data) {
136  return -1;
137  }
138  return debug_gdb_write_at(buf, count, addr);
139 }
140 
141 static ut64 __lseek(RzIO *io, RzIODesc *fd, ut64 offset, int whence) {
142  switch (whence) {
143  case RZ_IO_SEEK_SET:
144  io->off = offset;
145  break;
146  case RZ_IO_SEEK_CUR:
147  io->off += offset;
148  break;
149  case RZ_IO_SEEK_END:
150  io->off = ST64_MAX;
151  }
152  return io->off;
153 }
154 
155 static int __read(RzIO *io, RzIODesc *fd, ut8 *buf, int count) {
156  if (!io || !fd || !buf || count < 1) {
157  return -1;
158  }
159  memset(buf, 0xff, count);
160  ut64 addr = io->off;
161  if (!desc || !desc->data) {
162  return -1;
163  }
164  return debug_gdb_read_at(buf, count, addr);
165 }
166 
167 static int __close(RzIODesc *fd) {
168  if (fd) {
169  RZ_FREE(fd->name);
170  }
173  RZ_FREE(desc);
174  return -1;
175 }
176 
177 static int __getpid(RzIODesc *fd) {
178  // XXX don't use globals
179  return desc ? desc->pid : -1;
180 #if 0
181  // dupe for ? rz_io_desc_get_pid (desc);
182  if (!desc || !desc->data) {
183  return -1;
184  }
185  RzIODescData *iodd = desc->data;
186  if (iodd) {
187  if (iodd->magic != RZ_GDB_MAGIC) {
188  return -1;
189  }
190  return iodd->pid;
191  }
192  return -1;
193 #endif
194 }
195 
196 static int __gettid(RzIODesc *fd) {
197  return desc ? desc->tid : -1;
198 }
199 
200 extern int send_msg(libgdbr_t *g, const char *command);
201 extern int read_packet(libgdbr_t *instance, bool vcont);
202 
203 static char *__system(RzIO *io, RzIODesc *fd, const char *cmd) {
204  if (!desc) {
205  return NULL;
206  }
207  if (!*cmd) {
208  return NULL;
209  }
210  if (cmd[0] == '?' || !strcmp(cmd, "help")) {
211  eprintf("Usage: R!cmd args\n"
212  " R!pid - show targeted pid\n"
213  " R!pkt s - send packet 's'\n"
214  " R!rd - show reverse debugging availability\n"
215  " R!dsb - step backwards\n"
216  " R!dcb - continue backwards\n"
217  " R!monitor cmd - hex-encode monitor command and pass"
218  " to target interpreter\n"
219  " R!detach [pid] - detach from remote/detach specific pid\n"
220  " R!inv.reg - invalidate reg cache\n"
221  " R!pktsz - get max packet size used\n"
222  " R!pktsz bytes - set max. packet size as 'bytes' bytes\n"
223  " R!exec_file [pid] - get file which was executed for"
224  " current/specified pid\n");
225  return NULL;
226  }
227  if (rz_str_startswith(cmd, "pktsz")) {
228  const char *ptr = rz_str_trim_head_ro(cmd + 5);
229  if (!isdigit((ut8)*ptr)) {
230  io->cb_printf("packet size: %u bytes\n",
232  return NULL;
233  }
234  ut32 pktsz;
235  if (!(pktsz = (ut32)strtoul(ptr, NULL, 10))) {
236  // pktsz = 0 doesn't make sense
237  return NULL;
238  }
239  desc->stub_features.pkt_sz = RZ_MAX(pktsz, 8); // min = 64
240  return NULL;
241  }
242  if (rz_str_startswith(cmd, "detach")) {
243  int res;
244  if (!isspace((ut8)cmd[6]) || !desc->stub_features.multiprocess) {
245  res = gdbr_detach(desc) >= 0;
246  } else {
247  int pid = 0;
248  cmd = rz_str_trim_head_ro(cmd + 6);
249  if (!*cmd || !(pid = strtoul(cmd, NULL, 10))) {
250  res = gdbr_detach(desc) >= 0;
251  } else {
252  res = gdbr_detach_pid(desc, pid) >= 0;
253  }
254  }
255  eprintf("%d\n", res);
256  return NULL;
257  }
258  if (rz_str_startswith(cmd, "pkt ")) {
259  if (!gdbr_lock_enter(desc)) {
260  goto gdb_lock_leave;
261  }
262  if (send_msg(desc, cmd + 4) >= 0) {
263  (void)read_packet(desc, false);
264  desc->data[desc->data_len] = '\0';
265  io->cb_printf("reply:\n%s\n", desc->data);
266  if (!desc->no_ack) {
267  eprintf("[waiting for ack]\n");
268  }
269  }
270  goto gdb_lock_leave;
271  }
272  if (rz_str_startswith(cmd, "rd")) {
273  PJ *pj = pj_new();
274  pj_o(pj);
275  pj_kb(pj, "reverse-continue", desc->stub_features.ReverseStep);
276  pj_kb(pj, "reverse-step", desc->stub_features.ReverseContinue);
277  pj_end(pj);
278  io->cb_printf("%s\n", pj_string(pj));
279  pj_free(pj);
280  return NULL;
281  }
282  if (rz_str_startswith(cmd, "dsb")) {
284  eprintf("Stepping backwards is not supported in this gdbserver implementation\n");
285  return NULL;
286  }
287  if (!gdbr_lock_enter(desc)) {
288  goto gdb_lock_leave;
289  }
290  if (send_msg(desc, "bs") >= 0) {
291  (void)read_packet(desc, false);
292  desc->data[desc->data_len] = '\0';
293  if (!desc->no_ack) {
294  eprintf("[waiting for ack]\n");
295  } else {
297  if (desc->stop_reason.is_valid == false) {
298  eprintf("Thread (%d) stopped for an invalid reason: %d\n",
300  }
301  }
303  }
304  goto gdb_lock_leave;
305  }
306  if (rz_str_startswith(cmd, "dcb")) {
308  eprintf("Continue backwards is not supported in this gdbserver implementation\n");
309  return NULL;
310  }
311  if (!gdbr_lock_enter(desc)) {
312  goto gdb_lock_leave;
313  }
314  if (send_msg(desc, "bc") >= 0) {
315  (void)read_packet(desc, false);
316  desc->data[desc->data_len] = '\0';
317  if (!desc->no_ack) {
318  eprintf("[waiting for ack]\n");
319  } else {
321  if (desc->stop_reason.is_valid == false) {
322  eprintf("Thread (%d) stopped for an invalid reason: %d\n",
324  }
325  }
327  }
328  goto gdb_lock_leave;
329  }
330  if (rz_str_startswith(cmd, "pid")) {
331  int pid = desc ? desc->pid : -1;
332  if (!cmd[3]) {
333  io->cb_printf("%d\n", pid);
334  }
335  return rz_str_newf("%d", pid);
336  }
337  if (rz_str_startswith(cmd, "monitor")) {
338  const char *qrcmd = cmd + 8;
339  if (!isspace((ut8)cmd[7])) {
340  qrcmd = "help";
341  }
342  if (gdbr_send_qRcmd(desc, qrcmd, io->cb_printf) < 0) {
343  eprintf("remote error\n");
344  return NULL;
345  }
346  return NULL;
347  }
348  if (rz_str_startswith(cmd, "inv.reg")) {
350  return NULL;
351  }
352  if (rz_str_startswith(cmd, "exec_file")) {
353  const char *ptr = cmd + strlen("exec_file");
354  char *file;
355  if (!isspace((ut8)*ptr)) {
357  } else {
358  while (isspace((ut8)*ptr)) {
359  ptr++;
360  }
361  if (isdigit((ut8)*ptr)) {
362  int pid = atoi(ptr);
364  } else {
366  }
367  }
368  if (!file) {
369  return NULL;
370  }
371  io->cb_printf("%s\n", file);
372  return file;
373  }
374  // These are internal, not available to user directly
375  if (rz_str_startswith(cmd, "retries")) {
376  int num_retries;
377  if (isspace((ut8)cmd[7]) && isdigit((ut8)cmd[8])) {
378  if ((num_retries = atoi(cmd + 8)) >= 1) {
379  desc->num_retries = num_retries;
380  }
381  return NULL;
382  }
383  io->cb_printf("num_retries: %d byte(s)\n", desc->page_size);
384  return NULL;
385  }
386  if (rz_str_startswith(cmd, "page_size")) {
387  int page_size;
388  if (isspace((ut8)cmd[9]) && isdigit((ut8)cmd[10])) {
389  if ((page_size = atoi(cmd + 10)) >= 64) {
390  desc->page_size = page_size;
391  }
392  return NULL;
393  }
394  io->cb_printf("page size: %d byte(s)\n", desc->page_size);
395  return NULL;
396  }
397  // Sets a flag that next call to get memmap will be for getting baddr
398  if (!strcmp(cmd, "baddr")) {
399  desc->get_baddr = true;
400  return NULL;
401  }
402  eprintf("Try: 'R!?'\n");
403  return NULL;
404 
405 gdb_lock_leave:
407  return NULL;
408 }
409 
411  // void *plugin;
412  .name = "gdb",
413  .license = "LGPL3",
414  .desc = "Attach to gdbserver instance",
415  .uris = "gdb://",
416  .open = __open,
417  .close = __close,
418  .read = __read,
419  .write = __write,
420  .check = __plugin_open,
421  .lseek = __lseek,
422  .system = __system,
423  .getpid = __getpid,
424  .gettid = __gettid,
425  .isdbg = true
426 };
427 
428 #ifndef RZ_PLUGIN_INCORE
430  .type = RZ_LIB_TYPE_IO,
431  .data = &rz_io_plugin_gdb,
433 };
434 #endif
int gdbr_disconnect(libgdbr_t *g)
disconnects the lib
Definition: core.c:283
int gdbr_read_memory(libgdbr_t *g, ut64 address, ut8 *buf, int len)
Definition: core.c:812
int gdbr_connect(libgdbr_t *g, const char *server, int port)
Function connects to a gdbserver instance.
Definition: core.c:155
int gdbr_attach(libgdbr_t *g, int pid)
attaches to a process
Definition: core.c:439
int gdbr_detach(libgdbr_t *g)
detaches from a process
Definition: core.c:495
bool gdbr_lock_enter(libgdbr_t *g)
Acquires the gdbr lock and sets up breaking.
Definition: core.c:105
char * gdbr_exec_file_read(libgdbr_t *g, int pid)
Definition: core.c:1635
void gdbr_lock_leave(libgdbr_t *g)
Releases the gdbr lock.
Definition: core.c:117
int gdbr_detach_pid(libgdbr_t *g, int pid)
Definition: core.c:520
void gdbr_invalidate_reg_cache(void)
invalidates the reg cache
Definition: core.c:1570
int gdbr_write_memory(libgdbr_t *g, ut64 address, const uint8_t *data, ut64 len)
Definition: core.c:860
int gdbr_send_qRcmd(libgdbr_t *g, const char *cmd, PrintfCallback cb_printf)
sends a qRcmd packet which basically passes a command to the remote target's interpreter.
Definition: core.c:1574
#define RZ_API
#define NULL
Definition: cris-opc.c:27
static static sync static getppid static getegid const char static filename char static len const char char static bufsiz static mask static vfork const void static prot static getpgrp const char static swapflags static arg static fd static protocol static who struct sockaddr static addrlen static backlog struct timeval struct timezone static tz const struct iovec static count static mode const void const struct sockaddr static tolen const char static pathname void count
Definition: sflib.h:98
static static sync static getppid static getegid const char static filename char static len const char char static bufsiz static mask static vfork const void static prot static getpgrp const char static swapflags cmd
Definition: sflib.h:79
uint32_t ut32
struct @667 g
RZ_API void Ht_() free(HtName_(Ht) *ht)
Definition: ht_inc.c:130
static int __read(RzIO *io, RzIODesc *fd, ut8 *buf, int count)
Definition: io_gdb.c:155
static int __gettid(RzIODesc *fd)
Definition: io_gdb.c:196
RzIOPlugin rz_io_plugin_gdb
Definition: io_gdb.c:410
static int debug_gdb_read_at(ut8 *buf, int sz, ut64 addr)
Definition: io_gdb.c:27
static bool __plugin_open(RzIO *io, const char *file, bool many)
Definition: io_gdb.c:23
RZ_API RzLibStruct rizin_plugin
Definition: io_gdb.c:429
static RzIODesc * __open(RzIO *io, const char *file, int rw, int mode)
Definition: io_gdb.c:54
#define RZ_GDB_MAGIC
Definition: io_gdb.c:18
int read_packet(libgdbr_t *instance, bool vcont)
Definition: packet.c:143
static int __write(RzIO *io, RzIODesc *fd, const ut8 *buf, int count)
Definition: io_gdb.c:133
int send_msg(libgdbr_t *g, const char *command)
Definition: common.c:146
static ut64 __lseek(RzIO *io, RzIODesc *fd, ut64 offset, int whence)
Definition: io_gdb.c:141
static int __close(RzIODesc *fd)
Definition: io_gdb.c:167
static char * __system(RzIO *io, RzIODesc *fd, const char *cmd)
Definition: io_gdb.c:203
static int __getpid(RzIODesc *fd)
Definition: io_gdb.c:177
static int debug_gdb_write_at(const ut8 *buf, int sz, ut64 addr)
Definition: io_gdb.c:34
static libgdbr_t * desc
Definition: io_gdb.c:21
voidpf uLong offset
Definition: ioapi.h:144
const char int mode
Definition: ioapi.h:137
voidpf void * buf
Definition: ioapi.h:138
uint8_t ut8
Definition: lh5801.h:11
return memset(p, 0, total)
int gdbr_cleanup(libgdbr_t *g)
frees all buffers and cleans the libgdbr instance stuff
Definition: libgdbr.c:146
int gdbr_init(libgdbr_t *g, bool is_server)
Function initializes the libgdbr lib.
Definition: libgdbr.c:9
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
int x
Definition: mipsasm.c:20
int handle_stop_reason(libgdbr_t *g)
Definition: responses.c:244
#define eprintf(x, y...)
Definition: rlcc.c:7
#define RZ_IO_SEEK_CUR
Definition: rz_io.h:16
RZ_API RzIODesc * rz_io_desc_new(RzIO *io, RzIOPlugin *plugin, const char *uri, int flags, int mode, void *data)
Definition: io_desc.c:11
#define RZ_IO_SEEK_SET
Definition: rz_io.h:15
#define RZ_IO_SEEK_END
Definition: rz_io.h:17
@ RZ_LIB_TYPE_IO
Definition: rz_lib.h:69
RZ_API PJ * pj_new(void)
Definition: pj.c:25
RZ_API PJ * pj_kb(PJ *j, const char *k, bool v)
Definition: pj.c:177
RZ_API PJ * pj_end(PJ *j)
Definition: pj.c:87
RZ_API const char * pj_string(PJ *pj)
Definition: pj.c:57
RZ_API void pj_free(PJ *j)
Definition: pj.c:34
RZ_API PJ * pj_o(PJ *j)
Definition: pj.c:75
RZ_API char * rz_str_newf(const char *fmt,...) RZ_PRINTF_CHECK(1
RZ_API const char * rz_str_trim_head_ro(const char *str)
Definition: str_trim.c:86
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 RZ_NEW0(x)
Definition: rz_types.h:284
#define RZ_PERM_RWX
Definition: rz_types.h:98
#define RZ_FREE(x)
Definition: rz_types.h:369
#define RZ_MAX(x, y)
#define UT64_MAX
Definition: rz_types_base.h:86
#define ST64_MAX
Definition: rz_types_base.h:84
#define RZ_VERSION
Definition: rz_version.h:8
#define isspace(c)
Definition: safe-ctype.h:141
#define isdigit(c)
Definition: safe-ctype.h:131
int pid
Definition: rz_io.h:109
ut64 magic
Definition: rz_io.h:108
libgdbr_t desc
Definition: debug_gdb.c:11
Definition: gzappend.c:170
struct libgdbr_stop_reason::@441 thread
bool get_baddr
Definition: libgdbr.h:189
char * data
Definition: libgdbr.h:171
int page_size
Definition: libgdbr.h:178
bool no_ack
Definition: libgdbr.h:186
int pid
Definition: libgdbr.h:176
ssize_t data_len
Definition: libgdbr.h:172
libgdbr_stop_reason_t stop_reason
Definition: libgdbr.h:190
libgdbr_stub_features_t stub_features
Definition: libgdbr.h:180
int tid
Definition: libgdbr.h:177
ssize_t read_max
Definition: libgdbr.h:164
int num_retries
Definition: libgdbr.h:183
Definition: rz_pj.h:12
char * name
Definition: rz_io.h:99
const char * name
Definition: rz_io.h:115
const char * version
Definition: rz_io.h:117
Definition: rz_io.h:59
ut64 off
Definition: rz_io.h:61
PrintfCallback cb_printf
Definition: rz_io.h:91
char * name
Definition: z80_tab.h:24
const char * command
Definition: main.c:7
ut64(WINAPI *w32_GetEnabledXStateFeatures)()
static const z80_opcode fd[]
Definition: z80_tab.h:997
static int file
Definition: z80asm.c:58
static int addr
Definition: z80asm.c:58