Rizin
unix-like reverse engineering framework and cli tools
core.c File Reference
#include "gdbclient/responses.h"
#include "gdbclient/commands.h"
#include "gdbclient/core.h"
#include "gdbclient/xml.h"
#include "arch.h"
#include "libgdbr.h"
#include "gdbr_common.h"
#include "packet.h"
#include "rz_util/rz_strbuf.h"
#include "rz_cons.h"
#include "rz_debug.h"
#include <assert.h>

Go to the source code of this file.

Macros

#define QSUPPORTED_MAX_RETRIES   5
 

Functions

char hex2char (char *hex)
 
static void reg_cache_init (libgdbr_t *g)
 
static void gdbr_break_process (void *arg)
 
bool gdbr_lock_tryenter (libgdbr_t *g)
 
bool gdbr_lock_enter (libgdbr_t *g)
 Acquires the gdbr lock and sets up breaking. More...
 
void gdbr_lock_leave (libgdbr_t *g)
 Releases the gdbr lock. More...
 
static int gdbr_connect_lldb (libgdbr_t *g)
 
int gdbr_connect (libgdbr_t *g, const char *host, int port)
 Function connects to a gdbserver instance. More...
 
int gdbr_disconnect (libgdbr_t *g)
 disconnects the lib More...
 
int gdbr_select (libgdbr_t *g, int pid, int tid)
 
int gdbr_check_vcont (libgdbr_t *g)
 checks which subcommands of the vCont packet are supported More...
 
int gdbr_stop_reason (libgdbr_t *g)
 gets reason why remote target stopped More...
 
int gdbr_check_extended_mode (libgdbr_t *g)
 checks for extended mode availability More...
 
int gdbr_attach (libgdbr_t *g, int pid)
 attaches to a process More...
 
int gdbr_detach (libgdbr_t *g)
 detaches from a process More...
 
int gdbr_detach_pid (libgdbr_t *g, int pid)
 
int gdbr_kill (libgdbr_t *g)
 kills the process the remote gdbserver is debugging (TODO: handle pid) More...
 
int gdbr_kill_pid (libgdbr_t *g, int pid)
 
static int gdbr_read_registers_lldb (libgdbr_t *g)
 
int gdbr_read_registers (libgdbr_t *g)
 
static int gdbr_read_memory_page (libgdbr_t *g, ut64 address, ut8 *buf, int len)
 
int gdbr_read_memory (libgdbr_t *g, ut64 address, ut8 *buf, int len)
 
int gdbr_write_memory (libgdbr_t *g, ut64 address, const uint8_t *data, ut64 len)
 
int gdbr_step (libgdbr_t *g, int tid)
 
int gdbr_continue (libgdbr_t *g, int pid, int tid, int sig)
 
int gdbr_write_bin_registers (libgdbr_t *g, const char *regs, int len)
 Function writes general purpose registers. More...
 
int gdbr_write_register (libgdbr_t *g, int index, char *value, int len)
 
int gdbr_write_reg (libgdbr_t *g, const char *name, char *value, int len)
 
int gdbr_write_registers (libgdbr_t *g, char *registers)
 
int test_command (libgdbr_t *g, const char *command)
 
int send_vcont (libgdbr_t *g, const char *command, const char *thread_id)
 Function sends a vCont command to the gdbserver. More...
 
int set_bp (libgdbr_t *g, ut64 address, const char *conditions, enum Breakpoint type, int sizebp)
 
int gdbr_set_bp (libgdbr_t *g, ut64 address, const char *conditions, int sizebp)
 Function sets normal breakpoint (0xcc, int3) More...
 
int gdbr_set_hwbp (libgdbr_t *g, ut64 address, const char *conditions, int sizebp)
 
int gdbr_set_hww (libgdbr_t *g, ut64 address, const char *conditions, int sizebp)
 
int gdbr_set_hwr (libgdbr_t *g, ut64 address, const char *conditions, int sizebp)
 
int gdbr_set_hwa (libgdbr_t *g, ut64 address, const char *conditions, int sizebp)
 
int gdbr_remove_bp (libgdbr_t *g, ut64 address, int sizebp)
 
int gdbr_remove_hwbp (libgdbr_t *g, ut64 address, int sizebp)
 
int gdbr_remove_hww (libgdbr_t *g, ut64 address, int sizebp)
 
int gdbr_remove_hwr (libgdbr_t *g, ut64 address, int sizebp)
 
int gdbr_remove_hwa (libgdbr_t *g, ut64 address, int sizebp)
 
int remove_bp (libgdbr_t *g, ut64 address, enum Breakpoint type, int sizebp)
 
int gdbr_open_file (libgdbr_t *g, const char *filename, int flags, int mode)
 
int gdbr_read_file (libgdbr_t *g, ut8 *buf, ut64 max_len)
 
int gdbr_close_file (libgdbr_t *g)
 
void gdbr_invalidate_reg_cache ()
 invalidates the reg cache More...
 
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. More...
 
char * gdbr_exec_file_read (libgdbr_t *g, int pid)
 
bool gdbr_is_thread_dead (libgdbr_t *g, int pid, int tid)
 
RzListgdbr_pids_list (libgdbr_t *g, int pid)
 get a list of the child processes of the given pid More...
 
RzListgdbr_threads_list (libgdbr_t *g, int pid)
 get list of threads for given pid More...
 
ut64 gdbr_get_baddr (libgdbr_t *g)
 

Variables

struct {
   ut8 *   buf
 
   ut64   buflen
 
   ut64   maxlen
 
   bool   valid
 
   bool   init
 
reg_cache
 

Macro Definition Documentation

◆ QSUPPORTED_MAX_RETRIES

#define QSUPPORTED_MAX_RETRIES   5

Definition at line 29 of file core.c.

Function Documentation

◆ gdbr_attach()

int gdbr_attach ( libgdbr_t g,
int  pid 
)

attaches to a process

Parameters
pidof the process to attach to
Returns
a failure code (currently -1) or 0 if call successfully

Definition at line 439 of file core.c.

439  {
440  int ret = -1;
441  char *cmd = NULL;
442  size_t buffer_size;
443 
444  if (!g || !g->sock) {
445  return -1;
446  }
447 
448  if (!gdbr_lock_enter(g)) {
449  goto end;
450  }
451  g->stop_reason.is_valid = false;
452  reg_cache.valid = false;
453 
454  if (g->stub_features.extended_mode == -1) {
456  }
457 
458  if (!g->stub_features.extended_mode) {
459  // vAttach needs extended mode to do anything.
460  ret = -2;
461  goto end;
462  }
463 
464  buffer_size = strlen(CMD_ATTACH) + (sizeof(int) * 2) + 1;
465  cmd = calloc(buffer_size, sizeof(char));
466  if (!cmd) {
467  ret = -1;
468  goto end;
469  }
470 
471  ret = snprintf(cmd, buffer_size, "%s%x", CMD_ATTACH, pid);
472  if (ret < 0) {
473  goto end;
474  }
475 
476  ret = send_msg(g, cmd);
477  if (ret < 0) {
478  goto end;
479  }
480 
481  if (read_packet(g, false) < 0) {
482  ret = -1;
483  goto end;
484  }
485 
486  ret = handle_attach(g);
487 end:
488  if (cmd) {
489  free(cmd);
490  }
492  return ret;
493 }
#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 cmd
Definition: sflib.h:79
struct @667 g
RZ_API void Ht_() free(HtName_(Ht) *ht)
Definition: ht_inc.c:130
int read_packet(libgdbr_t *instance, bool vcont)
Definition: packet.c:143
int send_msg(libgdbr_t *g, const char *command)
Definition: common.c:146
snprintf
Definition: kernel.h:364
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
int handle_attach(libgdbr_t *g)
Definition: responses.c:124
#define CMD_ATTACH
Definition: core.h:19
static int
Definition: sfsocketcall.h:114
int gdbr_check_extended_mode(libgdbr_t *g)
checks for extended mode availability
Definition: core.c:406
bool gdbr_lock_enter(libgdbr_t *g)
Acquires the gdbr lock and sets up breaking.
Definition: core.c:105
void gdbr_lock_leave(libgdbr_t *g)
Releases the gdbr lock.
Definition: core.c:117
static struct @443 reg_cache
#define buffer_size(buffer)

References buffer_size, calloc(), cmd, CMD_ATTACH, test_evm::end, free(), g, gdbr_check_extended_mode(), gdbr_lock_enter(), gdbr_lock_leave(), handle_attach(), int, NULL, pid, read_packet(), reg_cache, send_msg(), and snprintf.

Referenced by __open().

◆ gdbr_break_process()

static void gdbr_break_process ( void *  arg)
static

Definition at line 90 of file core.c.

90  {
91  libgdbr_t *g = (libgdbr_t *)arg;
92  (void)g;
93  g->isbreaked = true;
94 }

References g.

Referenced by gdbr_connect(), gdbr_lock_enter(), and gdbr_lock_tryenter().

◆ gdbr_check_extended_mode()

int gdbr_check_extended_mode ( libgdbr_t g)

checks for extended mode availability

Returns
a failure code (currently -1) or 0 if call successfully

Definition at line 406 of file core.c.

406  {
407  int ret = -1;
408 
409  if (!gdbr_lock_enter(g)) {
410  goto end;
411  }
412  g->stop_reason.is_valid = false;
413  reg_cache.valid = false;
414  // Activate extended mode if possible.
415  ret = send_msg(g, "!");
416  if (ret < 0) {
417  g->stub_features.extended_mode = 0;
418  goto end;
419  }
420  read_packet(g, false);
421  ret = send_ack(g);
422  if (ret < 0) {
423  g->stub_features.extended_mode = 0;
424  goto end;
425  }
426  if (strncmp(g->data, "OK", 2)) {
427  g->stub_features.extended_mode = 0;
428  ret = -1;
429  goto end;
430  }
431  g->stub_features.extended_mode = 1;
432 
433  ret = 0;
434 end:
436  return ret;
437 }
int send_ack(libgdbr_t *g)
Functions sends a single ack ('+')
Definition: common.c:130

References test_evm::end, g, gdbr_lock_enter(), gdbr_lock_leave(), read_packet(), reg_cache, send_ack(), and send_msg().

Referenced by gdbr_attach().

◆ gdbr_check_vcont()

int gdbr_check_vcont ( libgdbr_t g)

checks which subcommands of the vCont packet are supported

Definition at line 335 of file core.c.

335  {
336  int ret = -1;
337  char *ptr = NULL;
338 
339  if (!g) {
340  return -1;
341  }
342 
343  if (!gdbr_lock_enter(g)) {
344  goto end;
345  }
346  if (send_msg(g, "vCont?") < 0 || read_packet(g, false) < 0 || send_ack(g) < 0) {
347  ret = -1;
348  goto end;
349  }
350  if (g->data_len == 0) {
351  g->stub_features.vContSupported = false;
352  ret = 0;
353  goto end;
354  }
355  g->data[g->data_len] = '\0';
356  if (!(ptr = strtok(g->data + strlen("vCont;"), ";"))) {
357  ret = 0;
358  goto end;
359  }
360  while (ptr) {
361  switch (*ptr) {
362  case 's':
363  g->stub_features.vcont.s = true;
364  break;
365  case 'S':
366  g->stub_features.vcont.S = true;
367  break;
368  case 'c':
369  g->stub_features.vcont.c = true;
370  break;
371  case 'C':
372  g->stub_features.vcont.C = true;
373  break;
374  case 't':
375  g->stub_features.vcont.t = true;
376  break;
377  case 'r':
378  g->stub_features.vcont.r = true;
379  break;
380  }
381  g->stub_features.vContSupported = true;
382  ptr = strtok(NULL, ";");
383  }
384 
385  ret = 0;
386 end:
388  return ret;
389 }

References test_evm::end, g, gdbr_lock_enter(), gdbr_lock_leave(), NULL, read_packet(), send_ack(), and send_msg().

Referenced by gdbr_connect().

◆ gdbr_close_file()

int gdbr_close_file ( libgdbr_t g)

Definition at line 1539 of file core.c.

1539  {
1540  int ret = -1;
1541  char buf[64];
1542 
1543  if (!g) {
1544  return -1;
1545  }
1546  if (g->remote_file_fd < 0) {
1547  eprintf("%s: No remote file opened\n", __func__);
1548  return -1;
1549  }
1550 
1551  if (!gdbr_lock_enter(g)) {
1552  goto end;
1553  }
1554  snprintf(buf, sizeof(buf) - 1, "vFile:close:%x", g->remote_file_fd);
1555  if ((ret = send_msg(g, buf)) < 0) {
1556  goto end;
1557  }
1558  read_packet(g, false);
1559  if ((ret = handle_vFile_close(g)) < 0) {
1560  goto end;
1561  }
1562  g->remote_file_fd = -1;
1563 
1564  ret = 0;
1565 end:
1566  gdbr_lock_leave(g);
1567  return ret;
1568 }
voidpf void * buf
Definition: ioapi.h:138
int handle_vFile_close(libgdbr_t *g)
Definition: responses.c:177
#define eprintf(x, y...)
Definition: rlcc.c:7

References test_evm::end, eprintf, g, gdbr_lock_enter(), gdbr_lock_leave(), handle_vFile_close(), read_packet(), send_msg(), and snprintf.

Referenced by gdbr_parse_processes_xml(), and rz_debug_gdb_map_get().

◆ gdbr_connect()

int gdbr_connect ( libgdbr_t g,
const char *  server,
int  port 
)

Function connects to a gdbserver instance.

Parameters
serverstring that represents the host
numberthat represents the port
Returns
a failure code (currently -1) or 0 if call successfully

Definition at line 155 of file core.c.

155  {
156  const char *message = "qSupported:multiprocess+;qRelocInsn+;xmlRegisters=i386";
157  int i;
158  int ret = -1;
159  void *bed = NULL;
160 
161  if (!g || !host) {
162  return -1;
163  }
164  if (!gdbr_lock_enter(g)) {
165  goto end;
166  }
167  // Initial max_packet_size for remote target (minimum so far for AVR = 64)
168  g->stub_features.pkt_sz = 64;
169  char *env_pktsz_str;
170  ut32 env_pktsz = 0;
171  if ((env_pktsz_str = rz_sys_getenv("RZ_GDB_PKTSZ"))) {
172  if ((env_pktsz = (ut32)strtoul(env_pktsz_str, NULL, 10))) {
173  g->stub_features.pkt_sz = RZ_MAX(env_pktsz, GDB_MAX_PKTSZ);
174  }
175  }
176  // Use the default break handler for rz_socket_connect to send a signal
178  bed = rz_cons_sleep_begin();
179  if (*host == '/') {
180  ret = rz_socket_connect_serial(g->sock, host, port, 1);
181  } else {
182  ret = rz_socket_connect_tcp(g->sock, host, sdb_fmt("%d", port), 1);
183  }
184  rz_cons_sleep_end(bed);
186  if (!ret) {
187  ret = -1;
188  goto end;
189  }
190  if ((ret = send_ack(g)) < 0) {
191  goto end;
192  }
193  read_packet(g, true); // vcont=true lets us skip if we get no reply
194  g->connected = 1;
195  bed = rz_cons_sleep_begin();
196  // TODO add config possibility here
197  for (i = 0; i < QSUPPORTED_MAX_RETRIES && !g->isbreaked; i++) {
198  ret = send_msg(g, message);
199  if (ret < 0) {
200  continue;
201  }
202  ret = read_packet(g, false);
203  if (ret < 0) {
204  continue;
205  }
206  ret = handle_qSupported(g);
207  if (ret < 0) {
208  continue;
209  }
210  break;
211  }
212  rz_cons_sleep_end(bed);
213  if (g->isbreaked) {
214  g->isbreaked = false;
215  ret = -1;
216  goto end;
217  }
218  if (ret < 0) {
219  goto end;
220  }
221  if (env_pktsz > 0) {
222  g->stub_features.pkt_sz = RZ_MAX(RZ_MIN(env_pktsz, g->stub_features.pkt_sz), GDB_MAX_PKTSZ);
223  }
224  // If no-ack supported, enable no-ack mode (should speed up things)
225  if (g->stub_features.QStartNoAckMode) {
226  if ((ret = send_msg(g, "QStartNoAckMode")) < 0) {
227  goto end;
228  }
229  read_packet(g, false);
230  if (!strncmp(g->data, "OK", 2)) {
231  // Just in case, send ack
232  send_ack(g);
233  g->no_ack = true;
234  }
235  }
236  if (g->remote_type == GDB_REMOTE_TYPE_LLDB) {
237  if ((ret = gdbr_connect_lldb(g)) < 0) {
238  goto end;
239  }
240  }
241  // Query the thread / process id
242  g->stub_features.qC = true;
243  g->pid = g->tid = 0;
244  if ((ret = send_msg(g, "qC")) < 0) {
245  goto end;
246  }
247  read_packet(g, false);
248  if (handle_qC(g) < 0) {
249  g->stub_features.qC = false;
250  }
251  // Check if vCont is supported
253  // Set pid/thread for operations other than "step" and "continue"
254  if (gdbr_select(g, g->pid, g->tid) < 0) {
255  // return -1;
256  }
257  // Set thread for "step" and "continue" operations
258  if ((ret = send_msg(g, "Hc-1")) < 0) {
259  goto end;
260  }
261  read_packet(g, false);
262  ret = send_ack(g);
263  if (ret < 0) {
264  goto end;
265  }
266  if (strcmp(g->data, "OK")) {
267  // return -1;
268  }
269  if (g->stub_features.qXfer_features_read) {
271  }
272  reg_cache_init(g);
273 
274  ret = 0;
275 end:
276  if (ret != 0) {
277  rz_socket_close(g->sock);
278  }
280  return ret;
281 }
lzma_index ** i
Definition: index.h:629
RZ_API void * rz_cons_sleep_begin(void)
Definition: cons.c:443
RZ_API void rz_cons_break_pop(void)
Definition: cons.c:361
RZ_API void rz_cons_break_push(RzConsBreak cb, void *user)
Definition: cons.c:357
RZ_API void rz_cons_sleep_end(void *user)
Definition: cons.c:450
uint32_t ut32
RZ_API char * sdb_fmt(const char *fmt,...)
Definition: fmt.c:26
#define GDB_MAX_PKTSZ
Definition: libgdbr.h:21
#define GDB_REMOTE_TYPE_LLDB
Definition: libgdbr.h:20
int handle_qSupported(libgdbr_t *g)
Definition: common.c:12
int handle_qC(libgdbr_t *g)
Definition: responses.c:77
RZ_API int rz_socket_close(RzSocket *s)
Definition: socket.c:419
RZ_API int rz_socket_connect_serial(RzSocket *sock, const char *path, int speed, int parity)
Definition: socket_serial.c:63
#define rz_socket_connect_tcp(a, b, c, d)
Definition: rz_socket.h:99
RZ_API char * rz_sys_getenv(const char *key)
Get the value of an environment variable named key or NULL if none exists.
Definition: sys.c:483
#define RZ_MIN(x, y)
#define RZ_MAX(x, y)
char * message
Definition: main.c:12
static int gdbr_connect_lldb(libgdbr_t *g)
Definition: core.c:129
static void gdbr_break_process(void *arg)
Definition: core.c:90
int gdbr_check_vcont(libgdbr_t *g)
checks which subcommands of the vCont packet are supported
Definition: core.c:335
static void reg_cache_init(libgdbr_t *g)
Definition: core.c:80
#define QSUPPORTED_MAX_RETRIES
Definition: core.c:29
int gdbr_select(libgdbr_t *g, int pid, int tid)
Definition: core.c:304
int gdbr_read_target_xml(libgdbr_t *g)
Definition: xml.c:460

References test_evm::end, g, GDB_MAX_PKTSZ, GDB_REMOTE_TYPE_LLDB, gdbr_break_process(), gdbr_check_vcont(), gdbr_connect_lldb(), gdbr_lock_enter(), gdbr_lock_leave(), gdbr_read_target_xml(), gdbr_select(), handle_qC(), handle_qSupported(), i, message, NULL, QSUPPORTED_MAX_RETRIES, read_packet(), reg_cache_init(), rz_cons_break_pop(), rz_cons_break_push(), rz_cons_sleep_begin(), rz_cons_sleep_end(), RZ_MAX, RZ_MIN, rz_socket_close(), rz_socket_connect_serial(), rz_socket_connect_tcp, rz_sys_getenv(), sdb_fmt(), send_ack(), and send_msg().

Referenced by __open().

◆ gdbr_connect_lldb()

static int gdbr_connect_lldb ( libgdbr_t g)
static

Definition at line 129 of file core.c.

129  {
130  int ret = -1;
131  if (!gdbr_lock_enter(g)) {
132  goto end;
133  }
134  reg_cache_init(g);
135  if (g->stub_features.qXfer_features_read) {
137  }
138  // Check if 'g' packet is supported
139  if (send_msg(g, "g") < 0 || read_packet(g, false) < 0 || send_ack(g) < 0) {
140  ret = -1;
141  goto end;
142  }
143  if (g->data_len == 0 || (g->data_len == 3 && g->data[0] == 'E')) {
144  ret = -1;
145  goto end;
146  }
147  g->stub_features.lldb.g = true;
148 
149  ret = 0;
150 end:
152  return ret;
153 }

References test_evm::end, g, gdbr_lock_enter(), gdbr_lock_leave(), gdbr_read_target_xml(), read_packet(), reg_cache_init(), send_ack(), and send_msg().

Referenced by gdbr_connect().

◆ gdbr_continue()

int gdbr_continue ( libgdbr_t g,
int  pid,
int  tid,
int  sig 
)

Definition at line 950 of file core.c.

950  {
951  char thread_id[64] = { 0 };
952  char command[16] = { 0 };
953  int ret = -1;
954 
955  if (!gdbr_lock_enter(g)) {
956  goto end;
957  }
958 
959  if (sig <= 0) {
960  strncpy(command, CMD_C_CONT, sizeof(command) - 1);
961  } else {
962  snprintf(command, sizeof(command) - 1, "%s%02x", CMD_C_CONT_SIG, sig);
963  }
964  if (tid <= 0 || write_thread_id(thread_id, sizeof(thread_id) - 1, g->pid, tid, g->stub_features.multiprocess) < 0) {
965  ret = send_vcont(g, command, NULL);
966  goto end;
967  }
968 
969  ret = send_vcont(g, command, thread_id);
970 end:
972  return ret;
973 }
#define CMD_C_CONT_SIG
Definition: core.h:43
#define CMD_C_CONT
Definition: core.h:42
const char * command
Definition: main.c:7
int write_thread_id(char *dest, int len, int pid, int tid, bool multiprocess)
Definition: utils.c:144
int send_vcont(libgdbr_t *g, const char *command, const char *thread_id)
Function sends a vCont command to the gdbserver.
Definition: core.c:1212

References CMD_C_CONT, CMD_C_CONT_SIG, command, test_evm::end, g, gdbr_lock_enter(), gdbr_lock_leave(), NULL, send_vcont(), snprintf, and write_thread_id().

Referenced by rz_debug_gdb_continue().

◆ gdbr_detach()

int gdbr_detach ( libgdbr_t g)

detaches from a process

Parameters
pidof the process to detach from (only the multiprocess/pid variant)
Returns
a failure code (currently -1) or 0 if call successfully

Definition at line 495 of file core.c.

495  {
496  int ret = -1;
497 
498  if (!g || !g->sock) {
499  return -1;
500  }
501 
502  if (!gdbr_lock_enter(g)) {
503  goto end;
504  }
505 
506  reg_cache.valid = false;
507  g->stop_reason.is_valid = false;
508  ret = send_msg(g, "D");
509  if (ret < 0) {
510  ret = -1;
511  goto end;
512  }
513  // Disconnect
514  ret = gdbr_disconnect(g);
515 end:
517  return ret;
518 }
int gdbr_disconnect(libgdbr_t *g)
disconnects the lib
Definition: core.c:283

References test_evm::end, g, gdbr_disconnect(), gdbr_lock_enter(), gdbr_lock_leave(), reg_cache, and send_msg().

Referenced by __system(), and rz_debug_gdb_detach().

◆ gdbr_detach_pid()

int gdbr_detach_pid ( libgdbr_t g,
int  pid 
)

Definition at line 520 of file core.c.

520  {
521  char *cmd = NULL;
522  int ret = -1;
523  size_t buffer_size;
524 
525  if (!g || !g->sock || !g->stub_features.multiprocess) {
526  return -1;
527  }
528 
529  if (!gdbr_lock_enter(g)) {
530  goto end;
531  }
532 
533  reg_cache.valid = false;
534  g->stop_reason.is_valid = false;
535 
536  buffer_size = strlen(CMD_DETACH_MP) + (sizeof(pid) * 2) + 1;
537  cmd = calloc(buffer_size, sizeof(char));
538  if (!cmd) {
539  ret = -1;
540  goto end;
541  }
542 
543  if ((snprintf(cmd, buffer_size, "%s%x", CMD_DETACH_MP, g->pid)) < 0) {
544  ret = -1;
545  goto end;
546  }
547 
548  ret = send_msg(g, cmd);
549  if (ret < 0) {
550  goto end;
551  }
552 
553  read_packet(g, false);
554  if ((ret = send_ack(g)) < 0) {
555  goto end;
556  }
557 
558  if (strncmp(g->data, "OK", 2)) {
559  ret = -1;
560  goto end;
561  }
562 
563  ret = 0;
564 end:
565  if (cmd) {
566  free(cmd);
567  }
569  return ret;
570 }
#define CMD_DETACH_MP
Definition: core.h:20

References buffer_size, calloc(), cmd, CMD_DETACH_MP, test_evm::end, free(), g, gdbr_lock_enter(), gdbr_lock_leave(), NULL, pid, read_packet(), reg_cache, send_ack(), send_msg(), and snprintf.

Referenced by __system(), and rz_debug_gdb_detach().

◆ gdbr_disconnect()

int gdbr_disconnect ( libgdbr_t g)

disconnects the lib

Returns
a failure code (currently -1) or 0 if call successfully

Definition at line 283 of file core.c.

283  {
284  // TODO Disconnect maybe send something to gdbserver
285  if (!g || !rz_socket_close(g->sock)) {
286  return -1;
287  }
288  if (!gdbr_lock_enter(g)) {
289  goto end;
290  }
291  reg_cache.valid = false;
292  g->stop_reason.is_valid = false;
293  free(reg_cache.buf);
294  if (g->target.valid) {
295  free(g->target.regprofile);
296  free(g->registers);
297  }
298  g->connected = 0;
299 end:
301  return 0;
302 }

References test_evm::end, free(), g, gdbr_lock_enter(), gdbr_lock_leave(), reg_cache, and rz_socket_close().

Referenced by __close(), gdbr_detach(), stop_reason_exit(), and stop_reason_terminated().

◆ gdbr_exec_file_read()

char* gdbr_exec_file_read ( libgdbr_t g,
int  pid 
)

Get absolute name of file executed to create a process

Definition at line 1635 of file core.c.

1635  {
1636  char msg[128], pidstr[16];
1637  char *path = NULL;
1638  ut64 len, off = 0;
1639  int ret = -1;
1640 
1641  if (!g) {
1642  return NULL;
1643  }
1644 
1645  len = g->stub_features.pkt_sz;
1646  memset(pidstr, 0, sizeof(pidstr));
1647  if (g->stub_features.multiprocess && pid > 0) {
1648  snprintf(pidstr, sizeof(pidstr), "%x", pid);
1649  }
1650 
1651  if (!gdbr_lock_enter(g)) {
1652  goto end;
1653  }
1654  while (1) {
1655  if (snprintf(msg, sizeof(msg) - 1,
1656  "qXfer:exec-file:read:%s:%" PFMT64x ",%" PFMT64x,
1657  pidstr, off, len) < 0) {
1658  ret = -1;
1659  goto end;
1660  }
1661  if (send_msg(g, msg) < 0 || read_packet(g, false) < 0 || send_ack(g) < 0 || g->data_len == 0) {
1662  ret = -1;
1663  goto end;
1664  }
1665  g->data[g->data_len] = '\0';
1666  if (g->data[0] == 'l') {
1667  if (g->data_len == 1) {
1668  break;
1669  }
1670  path = rz_str_append(path, g->data + 1);
1671  break;
1672  }
1673  if (g->data[0] != 'm') {
1674  ret = -1;
1675  goto end;
1676  }
1677  off += strlen(g->data + 1);
1678  if (!(path = rz_str_append(path, g->data + 1))) {
1679  ret = -1;
1680  goto end;
1681  }
1682  }
1683 
1684  ret = 0;
1685 end:
1686  gdbr_lock_leave(g);
1687  if (ret != 0) {
1688  if (path) {
1689  free(path);
1690  }
1691  return NULL;
1692  }
1693  return path;
1694 }
size_t len
Definition: 6502dis.c:15
static static fork const void static count static fd const char const char static newpath const char static path const char path
Definition: sflib.h:35
return memset(p, 0, total)
int off
Definition: pal.c:13
RZ_API char * rz_str_append(char *ptr, const char *string)
Definition: str.c:1063
#define PFMT64x
Definition: rz_types.h:393
static struct sockaddr static addrlen static backlog const void msg
Definition: sfsocketcall.h:119
ut64(WINAPI *w32_GetEnabledXStateFeatures)()

References test_evm::end, free(), g, gdbr_lock_enter(), gdbr_lock_leave(), len, memset(), msg, NULL, off, path, PFMT64x, pid, read_packet(), rz_str_append(), send_ack(), send_msg(), snprintf, and ut64().

Referenced by __open(), __system(), gdbr_pids_list(), gdbr_threads_list(), and rz_debug_gdb_info().

◆ gdbr_get_baddr()

ut64 gdbr_get_baddr ( libgdbr_t g)

Get offset of lowest segment returned by 'qOffsets'

Definition at line 1931 of file core.c.

1931  {
1932  ut64 off, min = UINT64_MAX;
1933  char *ptr;
1934  if (!g) {
1935  return UINT64_MAX;
1936  }
1937 
1938  if (!gdbr_lock_enter(g)) {
1939  goto end;
1940  }
1941  if (send_msg(g, "qOffsets") < 0 || read_packet(g, false) < 0 || send_ack(g) < 0 || g->data_len == 0) {
1942  min = UINT64_MAX;
1943  goto end;
1944  }
1945  if (rz_str_startswith(g->data, "TextSeg=")) {
1946  ptr = g->data + strlen("TextSeg=");
1947  if (!isxdigit(*ptr)) {
1948  goto end;
1949  }
1950  off = strtoull(ptr, NULL, 16);
1951  if (off < min) {
1952  min = off;
1953  }
1954  if (!(ptr = strchr(ptr, ';'))) {
1955  goto end;
1956  }
1957  ptr++;
1958  if (*ptr && rz_str_startswith(ptr, "DataSeg=")) {
1959  ptr += strlen("DataSeg=");
1960  if (!isxdigit(*ptr)) {
1961  goto end;
1962  }
1963  off = strtoull(ptr, NULL, 16);
1964  if (off < min) {
1965  min = off;
1966  }
1967  }
1968  goto end;
1969  }
1970  if (!rz_str_startswith(g->data, "Text=")) {
1971  goto end;
1972  }
1973  ptr = g->data + strlen("Text=");
1974  if (!isxdigit(*ptr)) {
1975  goto end;
1976  }
1977  off = strtoull(ptr, NULL, 16);
1978  if (off < min) {
1979  min = off;
1980  }
1981  if (!(ptr = strchr(ptr, ';')) || !rz_str_startswith(ptr + 1, "Data=")) {
1982  min = UINT64_MAX;
1983  goto end;
1984  }
1985  ptr += strlen(";Data=");
1986  if (!isxdigit(*ptr)) {
1987  min = UINT64_MAX;
1988  goto end;
1989  }
1990  off = strtoull(ptr, NULL, 16);
1991  if (off < min) {
1992  min = off;
1993  }
1994  if (!(ptr = strchr(ptr, ';'))) {
1995  goto end;
1996  }
1997  ptr++;
1998  if (rz_str_startswith(ptr, "Bss=")) {
1999  ptr += strlen("Bss=");
2000  if (!isxdigit(*ptr)) {
2001  goto end;
2002  }
2003  off = strtoull(ptr, NULL, 16);
2004  if (off < min) {
2005  min = off;
2006  }
2007  }
2008 end:
2009  gdbr_lock_leave(g);
2010  return min;
2011 }
#define min(a, b)
Definition: qsort.h:83
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
#define UINT64_MAX

References test_evm::end, g, gdbr_lock_enter(), gdbr_lock_leave(), isxdigit, min, NULL, off, read_packet(), rz_str_startswith(), send_ack(), send_msg(), UINT64_MAX, and ut64().

Referenced by rz_debug_gdb_map_get().

◆ gdbr_invalidate_reg_cache()

void gdbr_invalidate_reg_cache ( void  )

invalidates the reg cache

Definition at line 1570 of file core.c.

1570  {
1571  reg_cache.valid = false;
1572 }

References reg_cache.

Referenced by __system().

◆ gdbr_is_thread_dead()

bool gdbr_is_thread_dead ( libgdbr_t g,
int  pid,
int  tid 
)

Definition at line 1696 of file core.c.

1696  {
1697  bool ret = false;
1698 
1699  if (!g) {
1700  return false;
1701  }
1702  if (g->stub_features.multiprocess && pid <= 0) {
1703  return false;
1704  }
1705 
1706  if (!gdbr_lock_enter(g)) {
1707  goto end;
1708  }
1709  char msg[64] = { 0 }, thread_id[63] = { 0 };
1710  if (write_thread_id(thread_id, sizeof(thread_id) - 1, pid, tid,
1711  g->stub_features.multiprocess) < 0) {
1712  goto end;
1713  }
1714  if (snprintf(msg, sizeof(msg) - 1, "T%s", thread_id) < 0) {
1715  goto end;
1716  }
1717  if (send_msg(g, msg) < 0 || read_packet(g, false) < 0 || send_ack(g) < 0) {
1718  goto end;
1719  }
1720  if (g->data_len == 3 && g->data[0] == 'E') {
1721  ret = true;
1722  } else {
1723  ret = false;
1724  }
1725 
1726 end:
1727  gdbr_lock_leave(g);
1728  return ret;
1729 }

References test_evm::end, g, gdbr_lock_enter(), gdbr_lock_leave(), msg, pid, read_packet(), send_ack(), send_msg(), snprintf, and write_thread_id().

Referenced by gdbr_threads_list().

◆ gdbr_kill()

int gdbr_kill ( libgdbr_t g)

kills the process the remote gdbserver is debugging (TODO: handle pid)

Parameters
pidof the process to detach from (only the multiprocess/pid variant) \retuns a failure code (currently -1) or 0 if call successfully

Definition at line 572 of file core.c.

572  {
573  int ret = -1;
574 
575  if (!g || !g->sock) {
576  return -1;
577  }
578 
579  if (!gdbr_lock_enter(g)) {
580  goto end;
581  }
582 
583  reg_cache.valid = false;
584  g->stop_reason.is_valid = false;
585 
586  if (g->stub_features.multiprocess) {
587  if (g->pid <= 0) {
588  ret = -1;
589  goto end;
590  }
591  ret = gdbr_kill_pid(g, g->pid);
592  goto end;
593  }
594 
595  if ((ret = send_msg(g, "k")) < 0) {
596  goto end;
597  }
598 
599  ret = 0;
600 end:
602  return ret;
603 }
int gdbr_kill_pid(libgdbr_t *g, int pid)
Definition: core.c:605

References test_evm::end, g, gdbr_kill_pid(), gdbr_lock_enter(), gdbr_lock_leave(), reg_cache, and send_msg().

Referenced by rz_debug_gdb_kill().

◆ gdbr_kill_pid()

int gdbr_kill_pid ( libgdbr_t g,
int  pid 
)

Definition at line 605 of file core.c.

605  {
606  char *cmd = NULL;
607  int ret = -1;
608  size_t buffer_size;
609 
610  if (!g || !g->sock || !g->stub_features.multiprocess) {
611  return -1;
612  }
613 
614  if (!gdbr_lock_enter(g)) {
615  goto end;
616  }
617 
618  reg_cache.valid = false;
619  g->stop_reason.is_valid = false;
620 
621  buffer_size = strlen(CMD_KILL_MP) + (sizeof(pid) * 2) + 1;
622  cmd = calloc(buffer_size, sizeof(char));
623  if (!cmd) {
624  ret = -1;
625  goto end;
626  }
627 
628  if ((snprintf(cmd, buffer_size, "%s%x", CMD_KILL_MP, g->pid)) < 0) {
629  ret = -1;
630  goto end;
631  }
632  if ((ret = send_msg(g, cmd)) < 0) {
633  goto end;
634  }
635 
636  read_packet(g, false);
637  if ((ret = send_ack(g)) < 0) {
638  goto end;
639  }
640  if (strncmp(g->data, "OK", 2)) {
641  ret = -1;
642  goto end;
643  }
644 
645 end:
646  if (cmd) {
647  free(cmd);
648  }
650  return ret;
651 }
#define CMD_KILL_MP
Definition: core.h:21

References buffer_size, calloc(), cmd, CMD_KILL_MP, test_evm::end, free(), g, gdbr_lock_enter(), gdbr_lock_leave(), NULL, pid, read_packet(), reg_cache, send_ack(), send_msg(), and snprintf.

Referenced by gdbr_kill().

◆ gdbr_lock_enter()

◆ gdbr_lock_leave()

void gdbr_lock_leave ( libgdbr_t g)

Releases the gdbr lock.

Definition at line 117 of file core.c.

117  {
119  assert(g->gdbr_lock_depth > 0);
120  bool last_leave = g->gdbr_lock_depth == 1;
121  g->gdbr_lock_depth--;
122  rz_th_lock_leave(g->gdbr_lock);
123  // if this is the last lock this thread holds make sure that we disable the break
124  if (last_leave) {
125  g->isbreaked = false;
126  }
127 }
assert(limit<=UINT32_MAX/2)
RZ_API void rz_th_lock_leave(RZ_NONNULL RzThreadLock *thl)
Releases a RzThreadLock structure.
Definition: thread_lock.c:75

References assert(), g, rz_cons_break_pop(), and rz_th_lock_leave().

Referenced by __system(), gdbr_attach(), gdbr_check_extended_mode(), gdbr_check_vcont(), gdbr_close_file(), gdbr_connect(), gdbr_connect_lldb(), gdbr_continue(), gdbr_detach(), gdbr_detach_pid(), gdbr_disconnect(), gdbr_exec_file_read(), gdbr_get_baddr(), gdbr_is_thread_dead(), gdbr_kill(), gdbr_kill_pid(), gdbr_open_file(), gdbr_pids_list(), gdbr_read_file(), gdbr_read_memory(), gdbr_read_memory_page(), gdbr_read_registers(), gdbr_read_registers_lldb(), gdbr_select(), gdbr_send_qRcmd(), gdbr_step(), gdbr_stop_reason(), gdbr_threads_list(), gdbr_write_bin_registers(), gdbr_write_memory(), gdbr_write_reg(), gdbr_write_register(), gdbr_write_registers(), remove_bp(), send_vcont(), set_bp(), and test_command().

◆ gdbr_lock_tryenter()

bool gdbr_lock_tryenter ( libgdbr_t g)

Definition at line 96 of file core.c.

96  {
97  if (!rz_th_lock_tryenter(g->gdbr_lock)) {
98  return false;
99  }
100  g->gdbr_lock_depth++;
102  return true;
103 }
RZ_API bool rz_th_lock_tryenter(RZ_NONNULL RzThreadLock *thl)
Tries to acquire a RzThreadLock structure.
Definition: thread_lock.c:61

References g, gdbr_break_process(), rz_cons_break_push(), and rz_th_lock_tryenter().

Referenced by gdbr_read_registers().

◆ gdbr_open_file()

int gdbr_open_file ( libgdbr_t g,
const char *  filename,
int  flags,
int  mode 
)

File read from remote target (only one file open at a time for now)

Definition at line 1445 of file core.c.

1445  {
1446  int ret = -1;
1447  char *buf;
1448  size_t buf_len;
1449 
1450  if (!g || !filename || !*filename) {
1451  return -1;
1452  }
1453  if (g->remote_file_fd >= 0) {
1454  eprintf("%s: Remote file already open\n", __func__);
1455  return -1;
1456  }
1457  buf_len = (strlen(filename) * 2) + strlen("vFile:open:") + 30;
1458  if (!(buf = calloc(buf_len, sizeof(char)))) {
1459  return -1;
1460  }
1461 
1462  if (!gdbr_lock_enter(g)) {
1463  goto end;
1464  }
1465  strcpy(buf, "vFile:open:");
1466  pack_hex(filename, strlen(filename), buf + strlen(buf));
1467  snprintf(buf + strlen(buf), buf_len - strlen(buf) - 1, ",%x,%x", flags, mode);
1468  if ((ret = send_msg(g, buf)) < 0) {
1469  goto end;
1470  }
1471  read_packet(g, false);
1472  if ((ret = handle_vFile_open(g)) < 0) {
1473  goto end;
1474  }
1475 
1476  ret = 0;
1477 end:
1478  if (buf) {
1479  free(buf);
1480  }
1481  gdbr_lock_leave(g);
1482  return ret;
1483 }
static int buf_len
Definition: asm_arc.c:22
const char * filename
Definition: ioapi.h:137
const char int mode
Definition: ioapi.h:137
int handle_vFile_open(libgdbr_t *g)
Definition: responses.c:132
static struct sockaddr static addrlen static backlog const void static flags void flags
Definition: sfsocketcall.h:123
int pack_hex(const char *src, ut64 len, char *dst)
Definition: utils.c:111
ut8 * buf
Definition: core.c:75

References buf, buf_len, calloc(), test_evm::end, eprintf, flags, free(), g, gdbr_lock_enter(), gdbr_lock_leave(), handle_vFile_open(), pack_hex(), read_packet(), send_msg(), and snprintf.

Referenced by gdbr_parse_processes_xml(), and rz_debug_gdb_map_get().

◆ gdbr_pids_list()

RzList* gdbr_pids_list ( libgdbr_t g,
int  pid 
)

get a list of the child processes of the given pid

Definition at line 1731 of file core.c.

1731  {
1732  int ret = -1;
1733  RzList *list = NULL;
1734  int tpid = -1, ttid = -1;
1735  char *ptr, *ptr2, *exec_file;
1736  RzDebugPid *dpid = NULL;
1737  RzListIter *iter = NULL;
1738 
1739  if (!g) {
1740  return NULL;
1741  }
1742 
1743  if (!gdbr_lock_enter(g)) {
1744  goto end;
1745  }
1746  if (!(list = rz_list_new())) {
1747  ret = -1;
1748  goto end;
1749  }
1750  // Use qfThreadInfo as a fallback since it doesn't actually show all children
1751  if (g->stub_features.qXfer_threads_read) {
1752  if (gdbr_read_processes_xml(g, pid, list) == 0) {
1753  ret = 0;
1754  goto end;
1755  }
1756  }
1757  // Child processes will only show up in ThreadInfo if gdbr is currently processing a
1758  // fork/vfork/exec event or if the children weren't detached yet. This is intended
1759  // gdb `info inferiors` behavior that can only be avoided using xml.
1760  eprintf("WARNING: Showing possibly incomplete pid list due to xml protocol failure\n");
1761 
1762  if (!g->stub_features.qXfer_exec_file_read || !(exec_file = gdbr_exec_file_read(g, pid))) {
1763  exec_file = "";
1764  }
1765  if (send_msg(g, "qfThreadInfo") < 0 || read_packet(g, false) < 0 || send_ack(g) < 0 || g->data_len == 0 || g->data[0] != 'm') {
1766  ret = -1;
1767  goto end;
1768  }
1769  while (1) {
1770  g->data[g->data_len] = '\0';
1771  ptr = g->data + 1;
1772  while (ptr) {
1773  if ((ptr2 = strchr(ptr, ','))) {
1774  *ptr2 = '\0';
1775  ptr2++;
1776  }
1777  if (read_thread_id(ptr, &tpid, &ttid, g->stub_features.multiprocess) < 0) {
1778  ptr = ptr2;
1779  continue;
1780  }
1781  // Avoid adding the same pid twice(could show more than once if it has threads)
1782  rz_list_foreach (list, iter, dpid) {
1783  if (tpid == dpid->pid) {
1784  continue;
1785  }
1786  }
1787  if (!(dpid = RZ_NEW0(RzDebugPid)) || !(dpid->path = strdup(exec_file))) {
1788  ret = -1;
1789  goto end;
1790  }
1791  dpid->pid = tpid;
1792  // If the pid isn't the debugged pid it must be a child pid
1793  if (tpid != g->pid) {
1794  dpid->ppid = g->pid;
1795  }
1796  dpid->uid = dpid->gid = -1;
1797  dpid->runnable = true;
1798  dpid->status = RZ_DBG_PROC_STOP;
1799  rz_list_append(list, dpid);
1800  ptr = ptr2;
1801  }
1802  if (send_msg(g, "qsThreadInfo") < 0 || read_packet(g, false) < 0 || send_ack(g) < 0 || g->data_len == 0 || (g->data[0] != 'm' && g->data[0] != 'l')) {
1803  ret = -1;
1804  goto end;
1805  }
1806  if (g->data[0] == 'l') {
1807  break;
1808  }
1809  }
1810 
1811  ret = 0;
1812 end:
1813  gdbr_lock_leave(g);
1814  if (ret != 0) {
1815  if (dpid) {
1816  free(dpid);
1817  }
1818  // We can't use rz_debug_pid_free here
1819  if (list) {
1820  rz_list_foreach (list, iter, dpid) {
1821  if (dpid->path) {
1822  free(dpid->path);
1823  }
1824  free(dpid);
1825  }
1826  rz_list_free(list);
1827  }
1828  return NULL;
1829  }
1830  return list;
1831 }
static void list(RzEgg *egg)
Definition: rz-gg.c:52
RZ_API RZ_OWN RzList * rz_list_new(void)
Returns a new initialized RzList pointer (free method is not initialized)
Definition: list.c:235
RZ_API RZ_BORROW RzListIter * rz_list_append(RZ_NONNULL RzList *list, void *data)
Appends at the end of the list a new element.
Definition: list.c:288
RZ_API void rz_list_free(RZ_NONNULL RzList *list)
Empties the list and frees the list pointer.
Definition: list.c:137
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")
@ RZ_DBG_PROC_STOP
Definition: rz_debug.h:60
#define RZ_NEW0(x)
Definition: rz_types.h:284
char * path
Definition: rz_debug.h:414
int read_thread_id(const char *src, int *pid, int *tid, bool multiprocess)
Definition: utils.c:161
char * gdbr_exec_file_read(libgdbr_t *g, int pid)
Definition: core.c:1635
int gdbr_read_processes_xml(libgdbr_t *g, int pid, RzList *list)
Definition: xml.c:474

References test_evm::end, eprintf, free(), g, gdbr_exec_file_read(), gdbr_lock_enter(), gdbr_lock_leave(), gdbr_read_processes_xml(), rz_debug_pid_t::gid, list(), NULL, rz_debug_pid_t::path, rz_debug_pid_t::pid, pid, rz_debug_pid_t::ppid, read_packet(), read_thread_id(), rz_debug_pid_t::runnable, RZ_DBG_PROC_STOP, rz_list_append(), rz_list_free(), rz_list_new(), RZ_NEW0, send_ack(), send_msg(), rz_debug_pid_t::status, strdup(), and rz_debug_pid_t::uid.

Referenced by rz_debug_gdb_pids().

◆ gdbr_read_file()

int gdbr_read_file ( libgdbr_t g,
ut8 buf,
ut64  max_len 
)

Definition at line 1485 of file core.c.

1485  {
1486  int ret, ret1;
1487  char command[64];
1488  ut64 data_sz;
1489  ret = 0;
1490  if (!g || !buf || !max_len) {
1491  return -1;
1492  }
1493  if (max_len >= INT32_MAX) {
1494  eprintf("%s: Too big a file read requested: %" PFMT64d, __func__, max_len);
1495  return -1;
1496  }
1497  if (g->remote_file_fd < 0) {
1498  eprintf("%s: No remote file opened\n", __func__);
1499  return -1;
1500  }
1501 
1502  if (!gdbr_lock_enter(g)) {
1503  goto end;
1504  }
1505  g->stub_features.pkt_sz = RZ_MAX(g->stub_features.pkt_sz, GDB_MAX_PKTSZ);
1506  data_sz = g->stub_features.pkt_sz / 2;
1507  ret = 0;
1508  while (ret < max_len) {
1509  if (snprintf(command, sizeof(command) - 1,
1510  "vFile:pread:%x,%" PFMT64x ",%" PFMT64x,
1511  (int)g->remote_file_fd, (ut64)RZ_MIN(data_sz, max_len - ret),
1512  (ut64)ret) < 0) {
1513  ret = -1;
1514  goto end;
1515  }
1516  if (send_msg(g, command) < 0) {
1517  ret = -1;
1518  goto end;
1519  }
1520  if (read_packet(g, false) < 0) {
1521  ret = -1;
1522  goto end;
1523  }
1524  if ((ret1 = handle_vFile_pread(g, buf + ret)) < 0) {
1525  ret = ret1;
1526  goto end;
1527  }
1528  if (ret1 == 0) {
1529  goto end;
1530  }
1531  ret += ret1;
1532  }
1533 
1534 end:
1535  gdbr_lock_leave(g);
1536  return ret;
1537 }
int handle_vFile_pread(libgdbr_t *g, ut8 *buf)
Definition: responses.c:145
#define PFMT64d
Definition: rz_types.h:394
#define INT32_MAX

References command, test_evm::end, eprintf, g, GDB_MAX_PKTSZ, gdbr_lock_enter(), gdbr_lock_leave(), handle_vFile_pread(), INT32_MAX, PFMT64d, PFMT64x, read_packet(), RZ_MAX, RZ_MIN, send_msg(), snprintf, and ut64().

Referenced by gdbr_parse_processes_xml(), and rz_debug_gdb_map_get().

◆ gdbr_read_memory()

int gdbr_read_memory ( libgdbr_t g,
ut64  address,
ut8 buf,
int  len 
)

Definition at line 812 of file core.c.

812  {
813  int ret_len, ret, tmp;
814  int page_size = g->page_size;
815  ret_len = 0;
816 
817  if (!gdbr_lock_enter(g)) {
818  goto end;
819  }
820 
821  // Read and round up to page size
822  tmp = page_size - (address & (page_size - 1));
823  if (tmp >= len) {
824  ret_len = gdbr_read_memory_page(g, address, buf, len);
825  goto end;
826  }
827  if ((ret = gdbr_read_memory_page(g, address, buf, tmp)) != tmp) {
828  ret_len = ret;
829  goto end;
830  }
831  len -= tmp;
832  address += tmp;
833  buf += tmp;
834  ret_len += ret;
835  // Read complete pages
836  while (len > page_size) {
837  if ((ret = gdbr_read_memory_page(g, address, buf, page_size)) != page_size) {
838  if (ret < 1) {
839  goto end;
840  }
841  ret_len += ret;
842  goto end;
843  }
844  len -= page_size;
845  address += page_size;
846  buf += page_size;
847  ret_len += page_size;
848  }
849  // Read left-overs
850  if ((ret = gdbr_read_memory_page(g, address, buf, len)) < 0) {
851  goto end;
852  }
853 
854  ret_len += ret;
855 end:
857  return ret_len;
858 }
static int gdbr_read_memory_page(libgdbr_t *g, ut64 address, ut8 *buf, int len)
Definition: core.c:727

References test_evm::end, g, gdbr_lock_enter(), gdbr_lock_leave(), gdbr_read_memory_page(), len, and autogen_x86imm::tmp.

Referenced by debug_gdb_read_at().

◆ gdbr_read_memory_page()

static int gdbr_read_memory_page ( libgdbr_t g,
ut64  address,
ut8 buf,
int  len 
)
static

Definition at line 727 of file core.c.

727  {
728  char command[128] = { 0 };
729  int last, ret_len, pkt;
730  ret_len = 0;
731 
732  if (!g) {
733  return -1;
734  }
735  if (len < 1) {
736  return len;
737  }
738 
739  if (!gdbr_lock_enter(g)) {
740  goto end;
741  }
742 
743  g->stub_features.pkt_sz = RZ_MAX(g->stub_features.pkt_sz, GDB_MAX_PKTSZ);
744  int data_sz = g->stub_features.pkt_sz / 2;
745  int num_pkts = len / data_sz;
746  last = len % data_sz;
747  ret_len = 0;
748  for (pkt = 0; pkt < num_pkts; pkt++) {
749  if (snprintf(command, sizeof(command) - 1,
750  "%s%" PFMT64x ",%" PFMT64x, CMD_READMEM,
751  (ut64)address + (pkt * data_sz),
752  (ut64)data_sz) < 0) {
753  ret_len = -1;
754  goto end;
755  }
756  if (send_msg(g, command) < 0) {
757  ret_len = -1;
758  goto end;
759  }
760  if (read_packet(g, false) < 0) {
761  ret_len = -1;
762  goto end;
763  }
764  if (handle_m(g) < 0) {
765  ret_len = -1;
766  goto end;
767  }
768  int delta = (pkt * data_sz);
769 
770  if (delta > len) {
771  eprintf("oops\n");
772  break;
773  }
774  int left = RZ_MIN(g->data_len, len - delta);
775  if (left > 0) {
776  memcpy(buf + delta, g->data, left);
777  ret_len += g->data_len;
778  }
779  }
780  if (last) {
781  if (snprintf(command, sizeof(command) - 1,
782  "%s%016" PFMT64x ",%" PFMT64x, CMD_READMEM,
783  (ut64)(address + (num_pkts * data_sz)),
784  (ut64)last) < 0) {
785  ret_len = -1;
786  goto end;
787  }
788  if (send_msg(g, command) < 0) {
789  ret_len = -1;
790  goto end;
791  }
792  if (read_packet(g, false) < 0) {
793  ret_len = -1;
794  goto end;
795  }
796  if (handle_m(g) < 0) {
797  ret_len = -1;
798  goto end;
799  }
800  int delta = num_pkts * data_sz;
801  int left = RZ_MIN(g->data_len, len - delta);
802  if (left > 0) {
803  memcpy(buf + delta, g->data, left);
804  ret_len += g->data_len;
805  }
806  }
807 end:
809  return ret_len;
810 }
memcpy(mem, inblock.get(), min(CONTAINING_RECORD(inblock.get(), MEMBLOCK, data) ->size, size))
int handle_m(libgdbr_t *g)
Definition: responses.c:36
#define CMD_READMEM
Definition: core.h:28
static st64 delta
Definition: vmenus.c:2425

References CMD_READMEM, command, delta, test_evm::end, eprintf, g, GDB_MAX_PKTSZ, gdbr_lock_enter(), gdbr_lock_leave(), handle_m(), len, memcpy(), PFMT64x, read_packet(), RZ_MAX, RZ_MIN, send_msg(), snprintf, and ut64().

Referenced by gdbr_read_memory().

◆ gdbr_read_registers()

int gdbr_read_registers ( libgdbr_t g)

Definition at line 685 of file core.c.

685  {
686  int ret = -1;
687 
688  if (!g || !g->data) {
689  return -1;
690  }
691  if (reg_cache.init && reg_cache.valid) {
692  g->data_len = reg_cache.buflen;
693  memcpy(g->data, reg_cache.buf, reg_cache.buflen);
694  return 0;
695  }
696  // Don't wait on the lock in read_registers since it's frequently called, including
697  // each time "enter" is pressed. Otherwise the user will be forced to interrupt exit
698  // read_registers constantly while another task is in progress
699  if (!gdbr_lock_tryenter(g)) {
700  return -1;
701  }
702 
703  if (g->remote_type == GDB_REMOTE_TYPE_LLDB && !g->stub_features.lldb.g) {
705  goto end;
706  }
707  if ((ret = send_msg(g, CMD_READREGS)) < 0) {
708  goto end;
709  }
710  if (read_packet(g, false) < 0 || handle_g(g) < 0) {
711  ret = -1;
712  goto end;
713  }
714  if (reg_cache.init) {
715  reg_cache.buflen = g->data_len;
716  memset(reg_cache.buf, 0, reg_cache.buflen);
717  memcpy(reg_cache.buf, g->data, reg_cache.buflen);
718  reg_cache.valid = true;
719  }
720 
721  ret = 0;
722 end:
724  return ret;
725 }
int handle_g(libgdbr_t *g)
Definition: responses.c:11
#define CMD_READREGS
Definition: core.h:23
bool gdbr_lock_tryenter(libgdbr_t *g)
Definition: core.c:96
static int gdbr_read_registers_lldb(libgdbr_t *g)
Definition: core.c:653

References CMD_READREGS, test_evm::end, g, GDB_REMOTE_TYPE_LLDB, gdbr_lock_leave(), gdbr_lock_tryenter(), gdbr_read_registers_lldb(), handle_g(), memcpy(), memset(), read_packet(), reg_cache, and send_msg().

Referenced by gdbr_write_reg(), gdbr_write_registers(), and rz_debug_gdb_reg_read().

◆ gdbr_read_registers_lldb()

static int gdbr_read_registers_lldb ( libgdbr_t g)
static

Definition at line 653 of file core.c.

653  {
654  // Send the stop reply query packet and get register info
655  // (this is what lldb does)
656  int ret = -1;
657 
658  if (!g || !g->sock) {
659  return -1;
660  }
661 
662  if (!gdbr_lock_enter(g)) {
663  goto end;
664  }
665 
666  if (send_msg(g, "?") < 0 || read_packet(g, false) < 0) {
667  ret = -1;
668  goto end;
669  }
670  if ((ret = handle_lldb_read_reg(g)) < 0) {
671  goto end;
672  }
673  if (reg_cache.init) {
674  reg_cache.buflen = g->data_len;
675  memcpy(reg_cache.buf, g->data, reg_cache.buflen);
676  reg_cache.valid = true;
677  }
678 
679  ret = 0;
680 end:
682  return ret;
683 }
int handle_lldb_read_reg(libgdbr_t *g)
Definition: responses.c:387

References test_evm::end, g, gdbr_lock_enter(), gdbr_lock_leave(), handle_lldb_read_reg(), memcpy(), read_packet(), reg_cache, and send_msg().

Referenced by gdbr_read_registers().

◆ gdbr_remove_bp()

int gdbr_remove_bp ( libgdbr_t g,
ut64  address,
int  sizebp 
)

Definition at line 1377 of file core.c.

1377  {
1378  return remove_bp(g, address, BREAKPOINT, sizebp);
1379 }
@ BREAKPOINT
Definition: core.h:47
int remove_bp(libgdbr_t *g, ut64 address, enum Breakpoint type, int sizebp)
Definition: core.c:1396

References BREAKPOINT, g, and remove_bp().

Referenced by rz_debug_gdb_breakpoint().

◆ gdbr_remove_hwa()

int gdbr_remove_hwa ( libgdbr_t g,
ut64  address,
int  sizebp 
)

Definition at line 1392 of file core.c.

1392  {
1393  return remove_bp(g, address, ACCESS_WATCHPOINT, sizebp);
1394 }
@ ACCESS_WATCHPOINT
Definition: core.h:51

References ACCESS_WATCHPOINT, g, and remove_bp().

Referenced by rz_debug_gdb_breakpoint().

◆ gdbr_remove_hwbp()

int gdbr_remove_hwbp ( libgdbr_t g,
ut64  address,
int  sizebp 
)

Definition at line 1380 of file core.c.

1380  {
1381  return remove_bp(g, address, HARDWARE_BREAKPOINT, sizebp);
1382 }
@ HARDWARE_BREAKPOINT
Definition: core.h:48

References g, HARDWARE_BREAKPOINT, and remove_bp().

Referenced by rz_debug_gdb_breakpoint().

◆ gdbr_remove_hwr()

int gdbr_remove_hwr ( libgdbr_t g,
ut64  address,
int  sizebp 
)

Definition at line 1388 of file core.c.

1388  {
1389  return remove_bp(g, address, READ_WATCHPOINT, sizebp);
1390 }
@ READ_WATCHPOINT
Definition: core.h:50

References g, READ_WATCHPOINT, and remove_bp().

Referenced by rz_debug_gdb_breakpoint().

◆ gdbr_remove_hww()

int gdbr_remove_hww ( libgdbr_t g,
ut64  address,
int  sizebp 
)

Definition at line 1384 of file core.c.

1384  {
1385  return remove_bp(g, address, WRITE_WATCHPOINT, sizebp);
1386 }
@ WRITE_WATCHPOINT
Definition: core.h:49

References g, remove_bp(), and WRITE_WATCHPOINT.

Referenced by rz_debug_gdb_breakpoint().

◆ gdbr_select()

int gdbr_select ( libgdbr_t g,
int  pid,
int  tid 
)

Select pid-tid

Definition at line 304 of file core.c.

304  {
305  char cmd[64] = { 0 };
306  int ret = -1;
307 
308  if (!gdbr_lock_enter(g)) {
309  goto end;
310  }
311  reg_cache.valid = false;
312  g->pid = pid;
313  g->tid = tid;
314  strcpy(cmd, "Hg");
315  if ((ret = write_thread_id(cmd + 2, sizeof(cmd) - 3, pid, tid,
316  g->stub_features.multiprocess)) < 0) {
317  goto end;
318  }
319  g->stop_reason.is_valid = false;
320  if (send_msg(g, cmd) < 0 || read_packet(g, false) < 0 || send_ack(g) < 0) {
321  ret = -1;
322  goto end;
323  }
324  if (strcmp(g->data, "OK")) {
325  ret = -1;
326  goto end;
327  }
328 
329  ret = 0;
330 end:
332  return ret;
333 }

References cmd, test_evm::end, g, gdbr_lock_enter(), gdbr_lock_leave(), pid, read_packet(), reg_cache, send_ack(), send_msg(), and write_thread_id().

Referenced by gdbr_connect(), rz_debug_gdb_select(), and rz_debug_gdb_wait().

◆ gdbr_send_qRcmd()

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.

Returns
0 on success and -1 on failure

Definition at line 1574 of file core.c.

1574  {
1575  int ret = -1;
1576  char *buf;
1577  size_t len;
1578 
1579  if (!g || !cmd) {
1580  return -1;
1581  }
1582  len = strlen(cmd) * 2 + 8;
1583  if (!(buf = calloc(len, sizeof(char)))) {
1584  return -1;
1585  }
1586  strcpy(buf, "qRcmd,");
1587 
1588  if (!gdbr_lock_enter(g)) {
1589  goto end;
1590  }
1591  g->stop_reason.is_valid = false;
1592  reg_cache.valid = false;
1593  pack_hex(cmd, strlen(cmd), buf + 6);
1594  if ((ret = send_msg(g, buf)) < 0) {
1595  goto end;
1596  }
1597  if ((ret = read_packet(g, false)) < 0) {
1598  goto end;
1599  }
1600  while (1) {
1601  if ((ret = send_ack(g)) < 0) {
1602  goto end;
1603  }
1604  if (g->data_len == 0) {
1605  ret = -1;
1606  goto end;
1607  }
1608  if (g->data_len == 3 && g->data[0] == 'E' && isxdigit(g->data[1]) && isxdigit(g->data[2])) {
1609  ret = -1;
1610  goto end;
1611  }
1612  if (!strncmp(g->data, "OK", 2)) {
1613  break;
1614  }
1615  if (g->data[0] == 'O' && g->data_len % 2 == 1) {
1616  // Console output from gdbserver
1617  unpack_hex(g->data + 1, g->data_len - 1, g->data + 1);
1618  g->data[g->data_len - 1] = '\0';
1619  cb_printf("%s", g->data + 1);
1620  }
1621  if ((ret = read_packet(g, false)) < 0) {
1622  goto end;
1623  }
1624  }
1625 
1626  ret = 0;
1627 end:
1628  if (buf) {
1629  free(buf);
1630  }
1631  gdbr_lock_leave(g);
1632  return ret;
1633 }
int unpack_hex(const char *src, ut64 len, char *dst)
Definition: utils.c:95

References buf, calloc(), cmd, test_evm::end, free(), g, gdbr_lock_enter(), gdbr_lock_leave(), isxdigit, len, pack_hex(), read_packet(), reg_cache, send_ack(), send_msg(), and unpack_hex().

Referenced by __system().

◆ gdbr_set_bp()

int gdbr_set_bp ( libgdbr_t g,
ut64  address,
const char *  conditions,
int  sizebp 
)

Function sets normal breakpoint (0xcc, int3)

Parameters
gdbrinstance that contains the current context
addrressat this position the breakpoint will be added
conditionsTODO: examine how this condition string should look like
Returns
a failure code (currently -1) or 0 if call successfully

Definition at line 1357 of file core.c.

1357  {
1358  return set_bp(g, address, conditions, BREAKPOINT, sizebp);
1359 }
static const char * conditions[]
int set_bp(libgdbr_t *g, ut64 address, const char *conditions, enum Breakpoint type, int sizebp)
Definition: core.c:1302

References BREAKPOINT, conditions, g, and set_bp().

Referenced by rz_debug_gdb_breakpoint().

◆ gdbr_set_hwa()

int gdbr_set_hwa ( libgdbr_t g,
ut64  address,
const char *  conditions,
int  sizebp 
)

Definition at line 1373 of file core.c.

1373  {
1374  return set_bp(g, address, conditions, ACCESS_WATCHPOINT, sizebp);
1375 }

References ACCESS_WATCHPOINT, conditions, g, and set_bp().

Referenced by rz_debug_gdb_breakpoint().

◆ gdbr_set_hwbp()

int gdbr_set_hwbp ( libgdbr_t g,
ut64  address,
const char *  conditions,
int  sizebp 
)

Definition at line 1361 of file core.c.

1361  {
1362  return set_bp(g, address, conditions, HARDWARE_BREAKPOINT, sizebp);
1363 }

References conditions, g, HARDWARE_BREAKPOINT, and set_bp().

Referenced by rz_debug_gdb_breakpoint().

◆ gdbr_set_hwr()

int gdbr_set_hwr ( libgdbr_t g,
ut64  address,
const char *  conditions,
int  sizebp 
)

Definition at line 1369 of file core.c.

1369  {
1370  return set_bp(g, address, conditions, READ_WATCHPOINT, sizebp);
1371 }

References conditions, g, READ_WATCHPOINT, and set_bp().

Referenced by rz_debug_gdb_breakpoint().

◆ gdbr_set_hww()

int gdbr_set_hww ( libgdbr_t g,
ut64  address,
const char *  conditions,
int  sizebp 
)

Definition at line 1365 of file core.c.

1365  {
1366  return set_bp(g, address, conditions, WRITE_WATCHPOINT, sizebp);
1367 }

References conditions, g, set_bp(), and WRITE_WATCHPOINT.

Referenced by rz_debug_gdb_breakpoint().

◆ gdbr_step()

int gdbr_step ( libgdbr_t g,
int  tid 
)

Definition at line 929 of file core.c.

929  {
930  int ret = -1;
931  char thread_id[64] = { 0 };
932 
933  if (!gdbr_lock_enter(g)) {
934  goto end;
935  }
936 
937  if (tid <= 0 || write_thread_id(thread_id, sizeof(thread_id) - 1, g->pid, tid, g->stub_features.multiprocess) < 0) {
938  send_vcont(g, "vCont?", NULL);
939  send_vcont(g, sdb_fmt("Hc%d", tid), NULL);
940  ret = send_vcont(g, CMD_C_STEP, NULL);
941  goto end;
942  }
943 
944  ret = send_vcont(g, CMD_C_STEP, thread_id);
945 end:
947  return ret;
948 }
#define CMD_C_STEP
Definition: core.h:44

References CMD_C_STEP, test_evm::end, g, gdbr_lock_enter(), gdbr_lock_leave(), NULL, sdb_fmt(), send_vcont(), and write_thread_id().

Referenced by rz_debug_gdb_step().

◆ gdbr_stop_reason()

int gdbr_stop_reason ( libgdbr_t g)

gets reason why remote target stopped

Definition at line 391 of file core.c.

391  {
392  int ret = -1;
393  if (!gdbr_lock_enter(g)) {
394  goto end;
395  }
396  if (!g || send_msg(g, "?") < 0 || read_packet(g, false) < 0) {
397  ret = -1;
398  goto end;
399  }
400  ret = handle_stop_reason(g);
401 end:
403  return ret;
404 }
int handle_stop_reason(libgdbr_t *g)
Definition: responses.c:244

References test_evm::end, g, gdbr_lock_enter(), gdbr_lock_leave(), handle_stop_reason(), read_packet(), and send_msg().

Referenced by rz_debug_gdb_info(), and rz_debug_gdb_wait().

◆ gdbr_threads_list()

RzList* gdbr_threads_list ( libgdbr_t g,
int  pid 
)

get list of threads for given pid

Definition at line 1833 of file core.c.

1833  {
1834  int ret = -1;
1835  RzList *list = NULL;
1836  int tpid = -1, ttid = -1;
1837  char *ptr, *ptr2, *exec_file;
1838  RzDebugPid *dpid = NULL;
1839  RzListIter *iter = NULL;
1840 
1841  if (!g) {
1842  return NULL;
1843  }
1844 
1845  if (!gdbr_lock_enter(g)) {
1846  goto end;
1847  }
1848  if (!g->stub_features.qXfer_exec_file_read || !(exec_file = gdbr_exec_file_read(g, pid))) {
1849  exec_file = "";
1850  }
1851  if (g->stub_features.qXfer_threads_read) {
1852  // XML thread description is supported
1853  // TODO: Handle this case
1854  }
1855  if (send_msg(g, "qfThreadInfo") < 0 || read_packet(g, false) < 0 || send_ack(g) < 0 || g->data_len == 0 || g->data[0] != 'm') {
1856  ret = -1;
1857  goto end;
1858  }
1859  if (!(list = rz_list_new())) {
1860  ret = -1;
1861  goto end;
1862  }
1863  while (1) {
1864  g->data[g->data_len] = '\0';
1865  ptr = g->data + 1;
1866  while (ptr) {
1867  if ((ptr2 = strchr(ptr, ','))) {
1868  *ptr2 = '\0';
1869  ptr2++;
1870  }
1871  if (read_thread_id(ptr, &tpid, &ttid,
1872  g->stub_features.multiprocess) < 0) {
1873  ptr = ptr2;
1874  continue;
1875  }
1876  if (g->stub_features.multiprocess && tpid != pid) {
1877  ptr = ptr2;
1878  continue;
1879  }
1880  if (!(dpid = RZ_NEW0(RzDebugPid)) || !(dpid->path = strdup(exec_file))) {
1881  ret = -1;
1882  goto end;
1883  }
1884  dpid->uid = dpid->gid = -1; // TODO
1885  dpid->pid = ttid;
1886  dpid->runnable = true;
1887  // This is what linux native does as fallback, but
1888  // probably not correct.
1889  // TODO: Implement getting correct thread status from GDB
1890  dpid->status = RZ_DBG_PROC_STOP;
1891  rz_list_append(list, dpid);
1892  ptr = ptr2;
1893  }
1894  if (send_msg(g, "qsThreadInfo") < 0 || read_packet(g, false) < 0 || send_ack(g) < 0 || g->data_len == 0 || (g->data[0] != 'm' && g->data[0] != 'l')) {
1895  ret = -1;
1896  goto end;
1897  }
1898  if (g->data[0] == 'l') {
1899  break;
1900  }
1901  }
1902  // This is the all I've been able to extract from gdb so far
1903  rz_list_foreach (list, iter, dpid) {
1904  if (gdbr_is_thread_dead(g, pid, dpid->pid)) {
1905  dpid->status = RZ_DBG_PROC_DEAD;
1906  }
1907  }
1908 
1909  ret = 0;
1910 end:
1911  gdbr_lock_leave(g);
1912  if (ret != 0) {
1913  if (dpid) {
1914  free(dpid);
1915  }
1916  // We can't use rz_debug_pid_free here
1917  if (list) {
1918  rz_list_foreach (list, iter, dpid) {
1919  if (dpid->path) {
1920  free(dpid->path);
1921  }
1922  free(dpid);
1923  }
1924  rz_list_free(list);
1925  }
1926  return NULL;
1927  }
1928  return list;
1929 }
@ RZ_DBG_PROC_DEAD
Definition: rz_debug.h:64
bool gdbr_is_thread_dead(libgdbr_t *g, int pid, int tid)
Definition: core.c:1696

References test_evm::end, free(), g, gdbr_exec_file_read(), gdbr_is_thread_dead(), gdbr_lock_enter(), gdbr_lock_leave(), rz_debug_pid_t::gid, list(), NULL, rz_debug_pid_t::path, rz_debug_pid_t::pid, pid, read_packet(), read_thread_id(), rz_debug_pid_t::runnable, RZ_DBG_PROC_DEAD, RZ_DBG_PROC_STOP, rz_list_append(), rz_list_free(), rz_list_new(), RZ_NEW0, send_ack(), send_msg(), rz_debug_pid_t::status, strdup(), and rz_debug_pid_t::uid.

Referenced by rz_debug_gdb_threads().

◆ gdbr_write_bin_registers()

int gdbr_write_bin_registers ( libgdbr_t g,
const char *  regs,
int  len 
)

Function writes general purpose registers.

Parameters
gdbrinstance that contains the current context
regcontains the registers that should be written reg contains a comma separated string that uses <regname>=value,<regname>=value i.e. eax=0x123,ebx=0x234
Returns
a failurre code (currently -1) or 0 if call successfully

Definition at line 975 of file core.c.

975  {
976  int ret = -1;
977  uint64_t buffer_size = 0;
978  char *command = NULL;
979 
980  if (!g) {
981  return -1;
982  }
983 
984  if (!gdbr_lock_enter(g)) {
985  goto end;
986  }
987 
988  buffer_size = len * 2 + 8;
989  reg_cache.valid = false;
990 
991  command = calloc(buffer_size, sizeof(char));
992  if (!command) {
993  ret = -1;
994  goto end;
995  }
997  pack_hex(regs, len, command + 1);
998  if (send_msg(g, command) < 0) {
999  ret = -1;
1000  goto end;
1001  }
1002  if (read_packet(g, false) >= 0) {
1003  handle_G(g);
1004  } else {
1005  ret = -1;
1006  goto end;
1007  }
1008 
1009  ret = 0;
1010 end:
1011  gdbr_lock_leave(g);
1012  if (command) {
1013  free(command);
1014  }
1015  return ret;
1016 }
static char * regs[]
Definition: analysis_sh.c:203
int handle_G(libgdbr_t *g)
Definition: responses.c:19
#define CMD_WRITEREGS
Definition: core.h:24
unsigned long uint64_t
Definition: sftypes.h:28

References buffer_size, calloc(), CMD_WRITEREGS, command, test_evm::end, free(), g, gdbr_lock_enter(), gdbr_lock_leave(), handle_G(), len, NULL, pack_hex(), read_packet(), reg_cache, regs, send_msg(), and snprintf.

Referenced by gdbr_write_reg().

◆ gdbr_write_memory()

int gdbr_write_memory ( libgdbr_t g,
ut64  address,
const uint8_t data,
ut64  len 
)

Definition at line 860 of file core.c.

860  {
861  int ret = -1;
862  int command_len, pkt, max_cmd_len = 64;
863  ut64 num_pkts, last, data_sz;
864  char *tmp;
865  if (!g || !data) {
866  return -1;
867  }
868  g->stub_features.pkt_sz = RZ_MAX(g->stub_features.pkt_sz, GDB_MAX_PKTSZ);
869  data_sz = g->stub_features.pkt_sz / 2;
870  if (data_sz < 1) {
871  return -1;
872  }
873  num_pkts = len / data_sz;
874  last = len % data_sz;
875  if (!(tmp = calloc(max_cmd_len + g->stub_features.pkt_sz, sizeof(char)))) {
876  return -1;
877  }
878 
879  if (!gdbr_lock_enter(g)) {
880  goto end;
881  }
882 
883  for (pkt = num_pkts - 1; pkt >= 0; pkt--) {
884  if ((command_len = snprintf(tmp, max_cmd_len,
885  "%s%016" PFMT64x ",%" PFMT64x ":", CMD_WRITEMEM,
886  address + (pkt * data_sz), data_sz)) < 0) {
887  ret = -1;
888  goto end;
889  }
890  pack_hex((char *)data + (pkt * data_sz), data_sz, (tmp + command_len));
891  if ((ret = send_msg(g, tmp)) < 0) {
892  goto end;
893  }
894  if ((ret = read_packet(g, false)) < 0) {
895  goto end;
896  }
897  if ((ret = handle_M(g)) < 0) {
898  goto end;
899  }
900  }
901  if (last) {
902  if ((command_len = snprintf(tmp, max_cmd_len,
903  "%s%016" PFMT64x ",%" PFMT64x ":", CMD_WRITEMEM,
904  address + (num_pkts * data_sz), last)) < 0) {
905  ret = -1;
906  goto end;
907  }
908  pack_hex((char *)data + (num_pkts * data_sz), last, (tmp + command_len));
909  if ((ret = send_msg(g, tmp)) < 0) {
910  goto end;
911  }
912  if ((ret = read_packet(g, false)) < 0) {
913  goto end;
914  }
915  if ((ret = handle_M(g)) < 0) {
916  goto end;
917  }
918  }
919 
920  ret = 0;
921 end:
923  if (tmp) {
924  free(tmp);
925  }
926  return ret;
927 }
int handle_M(libgdbr_t *g)
Definition: responses.c:23
#define CMD_WRITEMEM
Definition: core.h:27

References calloc(), CMD_WRITEMEM, test_evm::end, free(), g, GDB_MAX_PKTSZ, gdbr_lock_enter(), gdbr_lock_leave(), handle_M(), len, pack_hex(), PFMT64x, read_packet(), RZ_MAX, send_msg(), snprintf, autogen_x86imm::tmp, and ut64().

Referenced by debug_gdb_write_at().

◆ gdbr_write_reg()

int gdbr_write_reg ( libgdbr_t g,
const char *  name,
char *  value,
int  len 
)

Definition at line 1058 of file core.c.

1058  {
1059  int i = 0;
1060  int ret = -1;
1061  if (!g) {
1062  return -1;
1063  }
1064 
1065  if (!gdbr_lock_enter(g)) {
1066  goto end;
1067  }
1068 
1069  reg_cache.valid = false;
1070  while (g->registers[i].size > 0) {
1071  if (!strcmp(g->registers[i].name, name)) {
1072  break;
1073  }
1074  i++;
1075  }
1076  if (g->registers[i].size == 0) {
1077  eprintf("Error registername <%s> not found in profile\n", name);
1078  ret = -1;
1079  goto end;
1080  }
1081  if (g->stub_features.P && (ret = gdbr_write_register(g, i, value, len)) == 0) {
1082  goto end;
1083  }
1084 
1085  // Use 'G' if write_register failed/isn't supported
1087  memcpy(g->data + (g->registers[i].offset / 8), value, len);
1088  gdbr_write_bin_registers(g, g->data, g->data_len);
1089 
1090  ret = 0;
1091 end:
1092  gdbr_lock_leave(g);
1093  return ret;
1094 }
static int value
Definition: cmd_api.c:93
Definition: z80asm.h:102
int gdbr_write_register(libgdbr_t *g, int index, char *value, int len)
Definition: core.c:1018
int gdbr_read_registers(libgdbr_t *g)
Definition: core.c:685
int gdbr_write_bin_registers(libgdbr_t *g, const char *regs, int len)
Function writes general purpose registers.
Definition: core.c:975

References test_evm::end, eprintf, g, gdbr_lock_enter(), gdbr_lock_leave(), gdbr_read_registers(), gdbr_write_bin_registers(), gdbr_write_register(), i, len, memcpy(), reg_cache, and value.

Referenced by rz_debug_gdb_reg_write().

◆ gdbr_write_register()

int gdbr_write_register ( libgdbr_t g,
int  index,
char *  value,
int  len 
)

Definition at line 1018 of file core.c.

1018  {
1019  int ret = -1;
1020  char command[255] = { 0 };
1021  if (!g || !g->stub_features.P) {
1022  return -1;
1023  }
1024  if (!gdbr_lock_enter(g)) {
1025  goto end;
1026  }
1027 
1028  reg_cache.valid = false;
1029  ret = snprintf(command, sizeof(command) - 1, "%s%x=", CMD_WRITEREG, index);
1030  if (len + ret >= sizeof(command)) {
1031  eprintf("command is too small\n");
1032  ret = -1;
1033  goto end;
1034  }
1035  // Pad with zeroes
1036  memset(command + ret, atoi("0"), len);
1037  pack_hex(value, len, (command + ret));
1038  if (send_msg(g, command) < 0) {
1039  ret = -1;
1040  goto end;
1041  }
1042  if (read_packet(g, false) < 0 || handle_P(g) < 0) {
1043  ret = -1;
1044  goto end;
1045  }
1046  if (g->last_code == MSG_NOT_SUPPORTED) {
1047  g->stub_features.P = false;
1048  ret = -1;
1049  goto end;
1050  }
1051 
1052  ret = 0;
1053 end:
1054  gdbr_lock_leave(g);
1055  return ret;
1056 }
#define MSG_NOT_SUPPORTED
Definition: libgdbr.h:16
int handle_P(libgdbr_t *g)
Definition: responses.c:27
#define CMD_WRITEREG
Definition: core.h:26

References CMD_WRITEREG, command, test_evm::end, eprintf, g, gdbr_lock_enter(), gdbr_lock_leave(), handle_P(), len, memset(), MSG_NOT_SUPPORTED, pack_hex(), read_packet(), reg_cache, send_msg(), snprintf, and value.

Referenced by gdbr_write_reg().

◆ gdbr_write_registers()

int gdbr_write_registers ( libgdbr_t g,
char *  registers 
)

Definition at line 1096 of file core.c.

1096  {
1098  int i = 0;
1099  int ret = -1;
1100  unsigned int x, len;
1101  char *command, *reg, *buff, *value;
1102  // read current register set
1103 
1104  command = buff = value = NULL;
1105 
1106  if (!g) {
1107  return -1;
1108  }
1109 
1110  if (!gdbr_lock_enter(g)) {
1111  goto end;
1112  }
1113 
1115  reg_cache.valid = false;
1116  len = strlen(registers);
1117  buff = calloc(len, sizeof(char));
1118  if (!buff) {
1119  ret = -1;
1120  goto end;
1121  }
1122  memcpy(buff, registers, len);
1123  reg = strtok(buff, ",");
1124  while (reg) {
1125  char *name_end = strchr(reg, '=');
1126  if (name_end == NULL) {
1127  eprintf("Malformed argument: %s\n", reg);
1128  ret = -1;
1129  goto end;
1130  }
1131  *name_end = '\0'; // change '=' to '\0'
1132 
1133  // time to find the current register
1134  while (g->registers[i].size > 0) {
1135  if (strcmp(g->registers[i].name, reg) == 0) {
1136  const ut64 register_size = g->registers[i].size;
1137  const ut64 offset = g->registers[i].offset;
1138  value = calloc(register_size + 1, 2);
1139  if (!value) {
1140  ret = -1;
1141  goto end;
1142  }
1143 
1144  memset(value, '0', register_size * 2);
1145  name_end++;
1146  // be able to take hex with and without 0x
1147  if (name_end[1] == 'x' || name_end[1] == 'X') {
1148  name_end += 2;
1149  }
1150  const int val_len = strlen(name_end); // size of the rest
1151  strcpy(value + (register_size * 2 - val_len), name_end);
1152 
1153  for (x = 0; x < register_size; x++) {
1154  g->data[offset + register_size - x - 1] = hex2char(&value[x * 2]);
1155  }
1156  RZ_FREE(value);
1157  }
1158  i++;
1159  }
1160  reg = strtok(NULL, " ,");
1161  }
1162 
1163  buffer_size = g->data_len * 2 + 8;
1164  command = calloc(buffer_size, sizeof(char));
1165  if (!command) {
1166  ret = -1;
1167  goto end;
1168  }
1170  pack_hex(g->data, g->data_len, command + 1);
1171  ret = send_msg(g, command);
1172  if (ret < 0) {
1173  goto end;
1174  }
1175  read_packet(g, false);
1176  handle_G(g);
1177 
1178  ret = 0;
1179 end:
1180  if (command) {
1181  free(command);
1182  }
1183  if (buff) {
1184  free(buff);
1185  }
1186  if (value) {
1187  free(value);
1188  }
1189  gdbr_lock_leave(g);
1190  return ret;
1191 }
voidpf uLong offset
Definition: ioapi.h:144
#define reg(n)
int x
Definition: mipsasm.c:20
#define RZ_FREE(x)
Definition: rz_types.h:369
char hex2char(char *hex)
Definition: utils.c:88

References buffer_size, calloc(), CMD_WRITEREGS, command, test_evm::end, eprintf, free(), g, gdbr_lock_enter(), gdbr_lock_leave(), gdbr_read_registers(), handle_G(), hex2char(), i, len, memcpy(), memset(), NULL, pack_hex(), read_packet(), reg, reg_cache, RZ_FREE, send_msg(), snprintf, ut64(), value, and x.

◆ hex2char()

char hex2char ( char *  hex)

Definition at line 88 of file utils.c.

88  {
89  uint8_t result = hex2int((int)hex[0]);
90  result <<= 4;
91  result |= hex2int(hex[1]);
92  return (char)result;
93 }
static const char hex[16]
Definition: print.c:21
unsigned char uint8_t
Definition: sftypes.h:31
int hex2int(int ch)
Definition: utils.c:61

References hex, and hex2int().

Referenced by gdbr_write_registers().

◆ reg_cache_init()

static void reg_cache_init ( libgdbr_t g)
static

Definition at line 80 of file core.c.

80  {
81  reg_cache.maxlen = g->data_max;
82  reg_cache.buflen = 0;
83  reg_cache.valid = false;
84  reg_cache.init = false;
85  if ((reg_cache.buf = malloc(reg_cache.maxlen))) {
86  reg_cache.init = true;
87  }
88 }
void * malloc(size_t size)
Definition: malloc.c:123

References g, malloc(), and reg_cache.

Referenced by gdbr_connect(), and gdbr_connect_lldb().

◆ remove_bp()

int remove_bp ( libgdbr_t g,
ut64  address,
enum Breakpoint  type,
int  sizebp 
)

Definition at line 1396 of file core.c.

1396  {
1397  char tmp[255] = { 0 };
1398  int ret = -1;
1399 
1400  if (!g) {
1401  return -1;
1402  }
1403 
1404  switch (type) {
1405  case BREAKPOINT:
1406  ret = snprintf(tmp, sizeof(tmp) - 1, "%s,%" PFMT64x ",%d", CMD_RBP, address, sizebp);
1407  break;
1408  case HARDWARE_BREAKPOINT:
1409  ret = snprintf(tmp, sizeof(tmp) - 1, "%s,%" PFMT64x ",%d", CMD_RHBP, address, sizebp);
1410  break;
1411  case WRITE_WATCHPOINT:
1412  ret = snprintf(tmp, sizeof(tmp) - 1, "%s,%" PFMT64x ",%d", CMD_RHWW, address, sizebp);
1413  break;
1414  case READ_WATCHPOINT:
1415  ret = snprintf(tmp, sizeof(tmp) - 1, "%s,%" PFMT64x ",%d", CMD_RHWR, address, sizebp);
1416  break;
1417  case ACCESS_WATCHPOINT:
1418  ret = snprintf(tmp, sizeof(tmp) - 1, "%s,%" PFMT64x ",%d", CMD_RHWA, address, sizebp);
1419  break;
1420  default:
1421  break;
1422  }
1423  if (ret < 0) {
1424  return ret;
1425  }
1426 
1427  if (!gdbr_lock_enter(g)) {
1428  goto end;
1429  }
1430 
1431  g->stop_reason.is_valid = false;
1432  if ((ret = send_msg(g, tmp)) < 0) {
1433  goto end;
1434  }
1435  if ((ret = read_packet(g, false)) < 0) {
1436  goto end;
1437  }
1438 
1439  ret = handle_removebp(g);
1440 end:
1441  gdbr_lock_leave(g);
1442  return ret;
1443 }
int type
Definition: mipsasm.c:17
int handle_removebp(libgdbr_t *g)
Definition: responses.c:120
#define CMD_RHWA
Definition: core.h:39
#define CMD_RBP
Definition: core.h:31
#define CMD_RHBP
Definition: core.h:33
#define CMD_RHWR
Definition: core.h:37
#define CMD_RHWW
Definition: core.h:35

References ACCESS_WATCHPOINT, BREAKPOINT, CMD_RBP, CMD_RHBP, CMD_RHWA, CMD_RHWR, CMD_RHWW, test_evm::end, g, gdbr_lock_enter(), gdbr_lock_leave(), handle_removebp(), HARDWARE_BREAKPOINT, PFMT64x, read_packet(), READ_WATCHPOINT, send_msg(), snprintf, autogen_x86imm::tmp, type, and WRITE_WATCHPOINT.

Referenced by gdbr_remove_bp(), gdbr_remove_hwa(), gdbr_remove_hwbp(), gdbr_remove_hwr(), and gdbr_remove_hww().

◆ send_vcont()

int send_vcont ( libgdbr_t g,
const char *  command,
const char *  thread_id 
)

Function sends a vCont command to the gdbserver.

Parameters
gthre "instance" of the current libgdbr session
commandthe command that will be sent (i.e. 's,S,c,C...')
Returns
-1 if something went wrong

Definition at line 1212 of file core.c.

1212  {
1213  char tmp[255] = { 0 };
1214  int ret = -1;
1215  void *bed = NULL;
1216 
1217  if (!g) {
1218  return -1;
1219  }
1220 
1221  if (!g->stub_features.vContSupported) {
1222  ret = snprintf(tmp, sizeof(tmp) - 1, "%s", command);
1223  } else {
1224  bool supported = false;
1225  switch (*command) {
1226  case 's':
1227  if (g->stub_features.vcont.s) {
1228  supported = true;
1229  }
1230  break;
1231  case 'S':
1232  if (g->stub_features.vcont.S) {
1233  supported = true;
1234  }
1235  break;
1236  case 'c':
1237  if (g->stub_features.vcont.c) {
1238  supported = true;
1239  }
1240  break;
1241  case 'C':
1242  if (g->stub_features.vcont.C) {
1243  supported = true;
1244  }
1245  break;
1246  case 't':
1247  if (g->stub_features.vcont.t) {
1248  supported = true;
1249  }
1250  break;
1251  case 'r':
1252  if (g->stub_features.vcont.r) {
1253  supported = true;
1254  }
1255  break;
1256  }
1257  if (supported) {
1258  if (!thread_id) {
1259  ret = snprintf(tmp, sizeof(tmp) - 1, "%s;%s", CMD_C, command);
1260  } else {
1261  ret = snprintf(tmp, sizeof(tmp) - 1, "%s;%s:%s", CMD_C, command, thread_id);
1262  }
1263  } else {
1264  ret = snprintf(tmp, sizeof(tmp) - 1, "%s", command);
1265  }
1266  }
1267  if (ret < 0) {
1268  return ret;
1269  }
1270 
1271  if (!gdbr_lock_enter(g)) {
1272  goto end;
1273  }
1274  reg_cache.valid = false;
1275  g->stop_reason.is_valid = false;
1276  ret = send_msg(g, tmp);
1277  if (ret < 0) {
1278  goto end;
1279  }
1280 
1281  bed = rz_cons_sleep_begin();
1282  while (read_packet(g, true) < 0 && !g->isbreaked && rz_socket_is_connected(g->sock))
1283  ;
1284  if (g->isbreaked) {
1285  g->isbreaked = false;
1286  // Stop target
1287  rz_socket_write(g->sock, "\x03", 1);
1288  // Read the stop reason
1289  if (read_packet(g, false) < 0) {
1290  ret = -1;
1291  goto end;
1292  }
1293  }
1294 
1295  ret = handle_cont(g);
1296 end:
1297  rz_cons_sleep_end(bed);
1298  gdbr_lock_leave(g);
1299  return ret;
1300 }
int handle_cont(libgdbr_t *g)
Definition: responses.c:383
RZ_API bool rz_socket_is_connected(RzSocket *)
Definition: socket.c:101
RZ_API int rz_socket_write(RzSocket *s, void *buf, int len)
Definition: socket.c:724
#define CMD_C
Definition: core.h:41

References CMD_C, command, test_evm::end, g, gdbr_lock_enter(), gdbr_lock_leave(), handle_cont(), NULL, read_packet(), reg_cache, rz_cons_sleep_begin(), rz_cons_sleep_end(), rz_socket_is_connected(), rz_socket_write(), send_msg(), snprintf, and autogen_x86imm::tmp.

Referenced by gdbr_continue(), and gdbr_step().

◆ set_bp()

int set_bp ( libgdbr_t g,
ut64  address,
const char *  conditions,
enum Breakpoint  type,
int  sizebp 
)

Definition at line 1302 of file core.c.

1302  {
1303  char tmp[255] = { 0 };
1304  int ret = -1;
1305 
1306  if (!g) {
1307  return -1;
1308  }
1309 
1310  switch (type) {
1311  case BREAKPOINT:
1312  ret = snprintf(tmp, sizeof(tmp) - 1,
1313  "%s,%" PFMT64x ",%d", CMD_BP, address, sizebp);
1314  break;
1315  case HARDWARE_BREAKPOINT:
1316  ret = snprintf(tmp, sizeof(tmp) - 1,
1317  "%s,%" PFMT64x ",%d", CMD_HBP, address, sizebp);
1318  break;
1319  case WRITE_WATCHPOINT:
1320  ret = snprintf(tmp, sizeof(tmp) - 1,
1321  "%s,%" PFMT64x ",%d", CMD_HWW, address, sizebp);
1322  break;
1323  case READ_WATCHPOINT:
1324  ret = snprintf(tmp, sizeof(tmp) - 1,
1325  "%s,%" PFMT64x ",%d", CMD_HWR, address, sizebp);
1326  break;
1327  case ACCESS_WATCHPOINT:
1328  ret = snprintf(tmp, sizeof(tmp) - 1,
1329  "%s,%" PFMT64x ",%d", CMD_HWA, address, sizebp);
1330  break;
1331  default:
1332  break;
1333  }
1334  if (ret < 0) {
1335  return ret;
1336  }
1337 
1338  if (!gdbr_lock_enter(g)) {
1339  goto end;
1340  }
1341 
1342  g->stop_reason.is_valid = false;
1343  if ((ret = send_msg(g, tmp)) < 0) {
1344  goto end;
1345  }
1346 
1347  if ((ret = read_packet(g, false)) < 0) {
1348  goto end;
1349  }
1350 
1351  ret = handle_setbp(g);
1352 end:
1353  gdbr_lock_leave(g);
1354  return ret;
1355 }
int handle_setbp(libgdbr_t *g)
Definition: responses.c:116
#define CMD_BP
Definition: core.h:30
#define CMD_HWR
Definition: core.h:36
#define CMD_HBP
Definition: core.h:32
#define CMD_HWW
Definition: core.h:34
#define CMD_HWA
Definition: core.h:38

References ACCESS_WATCHPOINT, BREAKPOINT, CMD_BP, CMD_HBP, CMD_HWA, CMD_HWR, CMD_HWW, test_evm::end, g, gdbr_lock_enter(), gdbr_lock_leave(), handle_setbp(), HARDWARE_BREAKPOINT, PFMT64x, read_packet(), READ_WATCHPOINT, send_msg(), snprintf, autogen_x86imm::tmp, type, and WRITE_WATCHPOINT.

Referenced by gdbr_set_bp(), gdbr_set_hwa(), gdbr_set_hwbp(), gdbr_set_hwr(), and gdbr_set_hww().

◆ test_command()

int test_command ( libgdbr_t g,
const char *  command 
)

Definition at line 1193 of file core.c.

1193  {
1194  int ret = -1;
1195 
1196  if (!gdbr_lock_enter(g)) {
1197  goto end;
1198  }
1199 
1200  if ((ret = send_msg(g, command)) < 0) {
1201  goto end;
1202  }
1203  read_packet(g, false);
1204  hexdump(g->read_buff, g->data_len, 0);
1205 
1206  ret = 0;
1207 end:
1208  gdbr_lock_leave(g);
1209  return ret;
1210 }
static void hexdump(const zip_uint8_t *data, zip_uint16_t len)
Definition: ziptool.c:692

References command, test_evm::end, g, gdbr_lock_enter(), gdbr_lock_leave(), hexdump(), read_packet(), and send_msg().

Variable Documentation

◆ buf

◆ buflen

◆ init

◆ maxlen

◆ 

◆ valid