int gdbr_server_read(libgdbr_t *g, char *buf, size_t max_len) { bool loop_continue; int ret; if (!g) { return -1; } memset (buf, 0, max_len); do { loop_continue = false; read_packet (g); while (!*g->data) { read_packet (g); } if (r_str_startswith (g->data, "qSupported")) { loop_continue = true; if ((ret = _server_handle_qSupported (g)) < 0) { return ret; } } else if (r_str_startswith (g->data, "qTStatus")) { loop_continue = true; if ((ret = _server_handle_qTStatus (g)) < 0) { return ret; } } else if (r_str_startswith (g->data, "qC")) { if ((ret = _server_handle_qC (g, buf, max_len)) < 0) { return ret; } } } while (loop_continue); return ret; }
static int lang_lib_file_run (RLang *user, const char *file) { char *libpath; void *lib; if (!(libpath = r_str_new (file))) { return -1; } if (!r_str_startswith (libpath, "/") && !r_str_startswith (libpath, "./")) { libpath = r_str_prefix (libpath, "./"); } if (!r_file_exists (libpath)) { if (!r_str_endswith (libpath, R_LIB_EXT)) { libpath = r_str_appendf (libpath, ".%s", R_LIB_EXT); } } if (!r_file_exists (libpath)) { free (libpath); return -1; } lib = r_lib_dl_open (libpath); if (lib) { void (*fcn)(RCore *); fcn = r_lib_dl_sym (lib, "entry"); if (fcn) { fcn (user->user); } else { eprintf ("Cannot find 'entry' symbol in library\n"); } r_lib_dl_close (lib); } free (libpath); return 0; }
static int __io_posix_open(const char *file, int perm, int mode) { int fd; if (r_str_startswith (file, "file://")) { file += strlen ("file://"); } if (r_file_is_directory (file)) { return -1; } #if __WINDOWS__ // probably unnecessary to have this ifdef nowadays windows is posix enough if (perm & R_PERM_W) { fd = r_sandbox_open (file, O_BINARY | O_RDWR, 0); if (fd == -1 && perm & R_PERM_CREAT) { r_sandbox_creat (file, 0644); fd = r_sandbox_open (file, O_BINARY | O_RDWR | O_CREAT, 0); } } else { fd = r_sandbox_open (file, O_BINARY, 0); } #else const int posixFlags = (perm & R_PERM_W) ? (perm & R_PERM_CREAT) ? (O_RDWR | O_CREAT) : O_RDWR : O_RDONLY; fd = r_sandbox_open (file, posixFlags, mode); #endif return fd; }
static int _resolve_arch(libgdbr_t *g, char *xml_data) { char *arch; // Find architecture g->target.arch = R_SYS_ARCH_NONE; if ((arch = strstr (xml_data, "<architecture"))) { if (!(arch = strchr (arch, '>'))) { return -1; } arch++; if (r_str_startswith (arch, "i386")) { g->target.arch = R_SYS_ARCH_X86; g->target.bits = 32; arch += 4; if (r_str_startswith (arch, ":x86-64")) { g->target.bits = 64; } } else if (r_str_startswith (arch, "aarch64")) { g->target.arch = R_SYS_ARCH_ARM; g->target.bits = 64; } else if (r_str_startswith (arch, "arm")) { g->target.arch = R_SYS_ARCH_ARM; g->target.bits = 32; } else if (r_str_startswith (arch, "mips")) { g->target.arch = R_SYS_ARCH_MIPS; g->target.bits = 32; } // TODO others } else { // apple's debugserver on ios9 if (strstr (xml_data, "com.apple.debugserver.arm64")) { g->target.arch = R_SYS_ARCH_ARM; g->target.bits = 64; } else if (strstr (xml_data, "org.gnu.gdb.mips")) { // openocd mips? g->target.arch = R_SYS_ARCH_MIPS; g->target.bits = 32; } else { eprintf ("Unknown architecture parsing XML (%s)\n", xml_data); } } return 0; }
// default open should permit opening static RIODesc *__open_default(RIO *io, const char *file, int flags, int mode) { if (r_str_startswith (file, "file://")) { file += strlen ("file://"); } if (!r_io_def_mmap_check_default (file)) { return NULL; } RIODesc *iod = r_io_def_mmap_open (io, file, flags, mode); return iod; // NTOE: uncomment this line to support loading files in ro as fallback is rw fails // return iod? iod: r_io_def_mmap_open (io, file, R_IO_READ, mode); }
static bool r_io_def_mmap_check_default (const char *filename) { if (filename) { if (r_str_startswith (filename, "file://")) { filename += strlen ("file://"); } const char * peekaboo = (!strncmp (filename, "nocache://", 10)) ? NULL : strstr (filename, "://"); if (!peekaboo || (peekaboo-filename) > 10) { return true; } } return false; }
static int __io_posix_open(const char *file, int flags, int mode) { int fd; if (r_str_startswith (file, "file://")) { file += strlen ("file://"); } if (r_file_is_directory (file)) { return -1; } #if __WINDOWS__ if (flags & R_IO_WRITE) { fd = r_sandbox_open (file, O_BINARY | O_RDWR, 0); if (fd == -1) { r_sandbox_creat (file, 0644); fd = r_sandbox_open (file, O_BINARY | O_RDWR, 0); } } else { fd = r_sandbox_open (file, O_BINARY, 0); } #else fd = r_sandbox_open (file, (flags & R_IO_WRITE) ? (O_RDWR|O_CREAT) : O_RDONLY, mode); #endif return fd; }
ut64 gdbr_get_baddr(libgdbr_t *g) { if (!g || send_msg (g, "qOffsets") < 0 || read_packet (g) < 0 || send_ack (g) < 0 || g->data_len == 0) { return UINT64_MAX; } ut64 off, min = UINT64_MAX; char *ptr; if (r_str_startswith (g->data, "TextSeg=")) { ptr = g->data + strlen ("TextSeg="); if (!isxdigit (*ptr)) { return min; } off = strtoull (ptr, NULL, 16); if (off < min) { min = off; } if (!(ptr = strchr (ptr, ';'))) { return min; } ptr++; if (*ptr && r_str_startswith (ptr, "DataSeg=")) { ptr += strlen ("DataSeg="); if (!isxdigit (*ptr)) { return min; } off = strtoull (ptr, NULL, 16); if (off < min) { min = off; } } return min; } if (!r_str_startswith (g->data, "Text=")) { return min; } ptr = g->data + strlen ("Text="); if (!isxdigit (*ptr)) { return min; } off = strtoull (ptr, NULL, 16); if (off < min) { min = off; } if (!(ptr = strchr (ptr, ';')) || !r_str_startswith (ptr + 1, "Data=")) { return UINT64_MAX; } ptr += strlen (";Data="); if (!isxdigit (*ptr)) { return UINT64_MAX; } off = strtoull (ptr, NULL, 16); if (off < min) { min = off; } if (!(ptr = strchr (ptr, ';'))) { return min; } ptr++; if (r_str_startswith (ptr, "Bss=")) { ptr += strlen ("Bss="); if (!isxdigit (*ptr)) { return min; } off = strtoull (ptr, NULL, 16); if (off < min) { min = off; } } return min; }
static RList* _extract_regs(char *regstr, RList *flags, char *pc_alias) { char *regstr_end, *regname, *regtype, *tmp1; ut32 flagnum, regname_len, regsize, regnum; RList *regs; RListIter *iter; gdbr_xml_reg_t *tmpreg; gdbr_xml_flags_t *tmpflag; if (!(regs = r_list_new ())) { return NULL; } while ((regstr = strstr (regstr, "<reg"))) { if (!(regstr_end = strchr (regstr, '/'))) { goto exit_err; } *regstr_end = '\0'; // name if (!(regname = strstr (regstr, "name="))) { goto exit_err; } regname += 6; if (!(tmp1 = strchr (regname, '"'))) { goto exit_err; } regname_len = tmp1 - regname; // size if (!(tmp1 = strstr (regstr, "bitsize="))) { goto exit_err; } tmp1 += 9; if (!isdigit (*tmp1)) { goto exit_err; } regsize = strtoul (tmp1, NULL, 10); // regnum regnum = UINT32_MAX; if ((tmp1 = strstr (regstr, "regnum="))) { tmp1 += 8; if (!isdigit (*tmp1)) { goto exit_err; } regnum = strtoul (tmp1, NULL, 10); } // type regtype = "gpr"; flagnum = r_list_length (flags); if ((tmp1 = strstr (regstr, "group="))) { tmp1 += 7; if (r_str_startswith (tmp1, "float")) { regtype = "fpu"; } // We need type information in r2 register profiles } else if ((tmp1 = strstr (regstr, "type="))) { tmp1 += 6; if (r_str_startswith (tmp1, "vec") || r_str_startswith (tmp1, "i387_ext") || r_str_startswith (tmp1, "ieee_single") || r_str_startswith (tmp1, "ieee_double")) { regtype = "fpu"; } else if (r_str_startswith (tmp1, "code_ptr")) { strcpy (pc_alias, "=PC "); strncpy (pc_alias + 4, regname, regname_len); strcpy (pc_alias + 4 + regname_len, "\n"); } else { // Check all flags. If reg is a flag, write flag data flagnum = 0; r_list_foreach (flags, iter, tmpflag) { if (r_str_startswith (tmp1, tmpflag->type)) { // Max 64-bit :/ if (tmpflag->num_bits <= 64) { break; } } flagnum++; } } // We need type information in r2 register profiles } if (!(tmpreg = calloc (1, sizeof (gdbr_xml_reg_t)))) { goto exit_err; } regname[regname_len] = '\0'; if (regname_len > sizeof (tmpreg->name) - 1) { eprintf ("Register name too long: %s\n", regname); } strncpy (tmpreg->name, regname, sizeof (tmpreg->name) - 1); tmpreg->name[sizeof (tmpreg->name) - 1] = '\0'; regname[regname_len] = '"'; strncpy (tmpreg->type, regtype, sizeof (tmpreg->type) - 1); tmpreg->type[sizeof (tmpreg->type) - 1] = '\0'; tmpreg->size = regsize / 8; tmpreg->flagnum = flagnum; if (regnum == UINT32_MAX) { r_list_push (regs, tmpreg); } else if (regnum >= r_list_length (regs)) { int i; for (i = regnum - r_list_length (regs); i > 0; i--) { // temporary placeholder reg. we trust the xml is correct and this will be replaced. r_list_push (regs, tmpreg); r_list_tail (regs)->data = NULL; } r_list_push (regs, tmpreg); } else { // this is where we replace those placeholder regs r_list_set_n (regs, regnum, tmpreg); } *regstr_end = '/'; regstr = regstr_end + 2; }
int handle_stop_reason(libgdbr_t *g) { send_ack (g); if (g->data_len < 3) { return -1; } switch (g->data[0]) { case 'O': unpack_hex (g->data + 1, g->data_len - 1, g->data + 1); //g->data[g->data_len - 1] = '\0'; eprintf ("%s", g->data + 1); if (send_ack (g) < 0) { return -1; } return handle_stop_reason (g); // Wait for next stop message case 'W': return stop_reason_exit (g); case 'X': return stop_reason_terminated (g); } if (g->data[0] != 'T') { return -1; } char *ptr1, *ptr2; g->data[g->data_len] = '\0'; free (g->stop_reason.exec.path); memset (&g->stop_reason, 0, sizeof (libgdbr_stop_reason_t)); g->stop_reason.core = -1; if (sscanf (g->data + 1, "%02x", &g->stop_reason.signum) != 1) { return -1; } g->stop_reason.is_valid = true; g->stop_reason.reason = R_DEBUG_REASON_SIGNAL; for (ptr1 = strtok (g->data + 3, ";"); ptr1; ptr1 = strtok (NULL, ";")) { if (r_str_startswith (ptr1, "thread") && !g->stop_reason.thread.present) { if (!(ptr2 = strchr (ptr1, ':'))) { continue; } ptr2++; if (read_thread_id (ptr2, &g->stop_reason.thread.pid, &g->stop_reason.thread.tid, g->stub_features.multiprocess) < 0) { continue; } g->stop_reason.thread.present = true; continue; } if (r_str_startswith (ptr1, "core")) { if (!(ptr2 = strchr (ptr1, ':'))) { continue; } ptr2++; if (!isxdigit (*ptr2)) { continue; } g->stop_reason.core = (int) strtol (ptr2, NULL, 16); continue; } if (g->stop_reason.signum == 5) { if (r_str_startswith (ptr1, "watch") || r_str_startswith (ptr1, "rwatch") || r_str_startswith (ptr1, "awatch")) { if (!(ptr2 = strchr (ptr1, ':'))) { continue; } ptr2++; if (!isxdigit (*ptr2)) { continue; } g->stop_reason.watchpoint.addr = strtoll (ptr2, NULL, 16); g->stop_reason.watchpoint.present = true; continue; } if (r_str_startswith (ptr1, "exec") && !g->stop_reason.exec.present) { if (!(ptr2 = strchr (ptr1, ':'))) { continue; } ptr2++; if (!(g->stop_reason.exec.path = calloc (strlen (ptr1) / 2, 1))) { continue; } unpack_hex (ptr2, strlen (ptr2), g->stop_reason.exec.path); g->stop_reason.exec.present = true; continue; } if (r_str_startswith (ptr1, "fork") && !g->stop_reason.fork.present) { if (!(ptr2 = strchr (ptr1, ':'))) { continue; } ptr2++; if (read_thread_id (ptr2, &g->stop_reason.fork.pid, &g->stop_reason.fork.tid, g->stub_features.multiprocess) < 0) { continue; } g->stop_reason.fork.present = true; continue; } if (r_str_startswith (ptr1, "vfork") && !g->stop_reason.vfork.present) { if (!(ptr2 = strchr (ptr1, ':'))) { continue; } ptr2++; if (read_thread_id (ptr2, &g->stop_reason.vfork.pid, &g->stop_reason.vfork.tid, g->stub_features.multiprocess) < 0) { continue; } g->stop_reason.vfork.present = true; continue; } if (r_str_startswith (ptr1, "vforkdone")) { g->stop_reason.vforkdone = true; continue; } if (r_str_startswith (ptr1, "library")) { g->stop_reason.library = true; continue; } if (r_str_startswith (ptr1, "swbreak")) { g->stop_reason.swbreak = true; continue; } if (r_str_startswith (ptr1, "hwbreak")) { g->stop_reason.hwbreak = true; continue; } if (r_str_startswith (ptr1, "create")) { g->stop_reason.create = true; continue; } } } if (g->stop_reason.signum == 5) { g->stop_reason.reason = R_DEBUG_REASON_BREAKPOINT; } return 0; }
R_API char *r_type_get_struct_memb(Sdb *TDB, const char *type, int offset) { int i, prev_typesize, typesize = 0; char *res = NULL; if (offset < 0) { return NULL; } char* query = sdb_fmt ("struct.%s", type); char *members = sdb_get (TDB, query, 0); if (!members) { //eprintf ("%s is not a struct\n", type); return NULL; } int nargs = r_str_split (members, ','); for (i = 0; i < nargs ; i++) { const char *name = r_str_word_get0 (members, i); if (!name) { break; } query = sdb_fmt ("struct.%s.%s", type, name); char *subtype = sdb_get (TDB, query, 0); if (!subtype) { break; } int len = r_str_split (subtype, ','); if (len < 3) { free (subtype); break; } int val = r_num_math (NULL, r_str_word_get0 (subtype, len - 1)); int arrsz = val ? val : 1; if ((typesize / 8) == offset) { res = r_str_newf ("%s.%s", type, name); free (subtype); break; } prev_typesize = typesize; typesize += r_type_get_bitsize (TDB, subtype) * arrsz; // Handle nested structs if (offset < (typesize / 8)) { char *nested_type = (char *)r_str_word_get0 (subtype, 0); if (r_str_startswith (nested_type, "struct ") && !r_str_endswith (nested_type, " *")) { len = r_str_split (nested_type, ' '); if (len < 2) { free (subtype); break; } nested_type = (char *)r_str_word_get0 (nested_type, 1); char *nested_res = r_type_get_struct_memb (TDB, nested_type, offset - (prev_typesize / 8)); if (nested_res) { len = r_str_split(nested_res, '.'); res = r_str_newf ("%s.%s.%s", type, name, r_str_word_get0 (nested_res, len - 1)); free (nested_res); free (subtype); break; } } } free (subtype); } free (members); return res; }
int gdbr_server_serve(libgdbr_t *g, gdbr_server_cmd_cb cmd_cb, void *core_ptr) { int ret; if (!g) { return -1; } while (1) { read_packet (g); if (g->data_len == 0) { continue; } if (r_str_startswith (g->data, "k")) { return _server_handle_k (g, cmd_cb, core_ptr); } if (r_str_startswith (g->data, "vKill")) { return _server_handle_vKill (g, cmd_cb, core_ptr); } if (r_str_startswith (g->data, "qSupported")) { if ((ret = _server_handle_qSupported (g)) < 0) { return ret; } continue; } if (r_str_startswith (g->data, "qTStatus")) { if ((ret = _server_handle_qTStatus (g)) < 0) { return ret; } continue; } if (r_str_startswith (g->data, "qC") && g->data_len == 2) { if ((ret = _server_handle_qC (g, cmd_cb, core_ptr)) < 0) { return ret; } continue; } if (r_str_startswith (g->data, "qAttached")) { if ((ret = _server_handle_qAttached (g, cmd_cb, core_ptr)) < 0) { return ret; } continue; } if (r_str_startswith (g->data, "vMustReplyEmpty")) { if ((ret = _server_handle_vMustReplyEmpty (g)) < 0) { return ret; } continue; } if (r_str_startswith (g->data, "qTfV")) { if ((ret = _server_handle_qTfV (g, cmd_cb, core_ptr)) < 0) { return ret; } continue; } if (r_str_startswith (g->data, "qfThreadInfo")) { if ((ret = _server_handle_qfThreadInfo (g, cmd_cb, core_ptr)) < 0) { return ret; } continue; } if (r_str_startswith (g->data, "qsThreadInfo")) { if ((ret = _server_handle_qsThreadInfo (g, cmd_cb, core_ptr)) < 0) { return ret; } continue; } if (r_str_startswith (g->data, "Hg")) { if ((ret = _server_handle_Hg (g, cmd_cb, core_ptr)) < 0) { return ret; } continue; } if (r_str_startswith (g->data, "Hc")) { if ((ret = _server_handle_Hc (g, cmd_cb, core_ptr)) < 0) { return ret; } continue; } if (r_str_startswith (g->data, "?")) { if ((ret = _server_handle_ques (g, cmd_cb, core_ptr)) < 0) { return ret; } continue; } if (r_str_startswith (g->data, "g") && g->data_len == 1) { if ((ret = _server_handle_g (g, cmd_cb, core_ptr)) < 0) { return ret; } continue; } if (r_str_startswith (g->data, "vCont")) { if ((ret = _server_handle_vCont (g, cmd_cb, core_ptr)) < 0) { return ret; } continue; } if (r_str_startswith (g->data, "qOffsets")) { if ((ret = _server_handle_qOffsets (g, cmd_cb, core_ptr)) < 0) { return ret; } continue; } if (g->data[0] == 'z' || g->data[0] == 'Z') { if ((ret = _server_handle_z (g, cmd_cb, core_ptr)) < 0) { return ret; } continue; } if (g->data[0] == 's') { if ((ret = _server_handle_s (g, cmd_cb, core_ptr)) < 0) { return ret; } continue; } if (g->data[0] == 'c') { if ((ret = _server_handle_c (g, cmd_cb, core_ptr)) < 0) { return ret; } continue; } if (r_str_startswith (g->data, "m")) { if ((ret = _server_handle_m (g, cmd_cb, core_ptr)) < 0) { return ret; } continue; } if (r_str_startswith (g->data, "QStartNoAckMode")) { if (send_ack (g) < 0 || send_msg (g, "OK") < 0) { return -1; } g->no_ack = true; continue; } // Unrecognized packet if (send_ack (g) < 0 || send_msg (g, "") < 0) { g->data[g->data_len] = '\0'; eprintf ("Unknown packet: %s\n", g->data); return -1; } }; return ret; }