radare2/libr/core/cmd_debug.c

3530 lines
100 KiB
C
Raw Normal View History

/* radare - LGPL - Copyright 2009-2016 - pancake */
2016-07-05 20:48:48 +00:00
#include "r_heap_glibc.h"
2016-05-03 02:52:41 +00:00
#include "r_core.h"
#include "r_util.h"
#include "sdb/sdb.h"
#define TN_KEY_LEN 32
#define TN_KEY_FMT "%"PFMT64u
struct dot_trace_ght {
RGraph *graph;
Sdb *graphnodes;
};
struct trace_node {
ut64 addr;
int refs;
};
2015-10-19 08:33:06 +00:00
// Get base address from a loaded file.
static ut64 r_debug_get_baddr(RCore *r, const char *file) {
char *abspath;
RListIter *iter;
RDebugMap *map;
if (!r || !r->io || !r->io->desc)
return 0LL;
r_debug_attach (r->dbg, r->io->desc->fd);
r_debug_map_sync (r->dbg);
abspath = r_file_abspath (file);
if (!abspath) abspath = strdup (file);
r_list_foreach (r->dbg->maps, iter, map) {
if (!strcmp (abspath, map->name)) {
free (abspath);
return map->addr;
}
}
free (abspath);
// fallback resolution (osx/w32?)
// we asume maps to be loaded in order, so lower addresses come first
r_list_foreach (r->dbg->maps, iter, map) {
if (map->perm == 5) { // r-x
return map->addr;
}
}
return 0LL;
2015-10-19 08:33:06 +00:00
}
static void cmd_debug_cont_syscall (RCore *core, const char *_str) {
// TODO : handle more than one stopping syscall
2014-10-09 16:31:55 +00:00
int i, *syscalls = NULL;
int count = 0;
if (_str && *_str) {
char *str = strdup (_str);
count = r_str_word_set0 (str);
syscalls = calloc (sizeof (int), count);
for (i=0; i<count; i++) {
const char *sysnumstr = r_str_word_get0 (str, i);
int sig = (int)r_num_math (core->num, sysnumstr);
if (sig == -1) { // trace ALL syscalls
syscalls[i] = -1;
} else
if (sig == 0) {
sig = r_syscall_get_num (core->anal->syscall, sysnumstr);
if (sig == -1) {
eprintf ("Unknown syscall number\n");
free (str);
free (syscalls);
return;
}
syscalls[i] = sig;
}
}
2014-10-09 16:31:55 +00:00
eprintf ("Running child until syscalls:");
for (i=0; i < count; i++)
2014-10-09 16:31:55 +00:00
eprintf ("%d ", syscalls[i]);
eprintf ("\n");
free (str);
} else {
eprintf ("Running child until next syscall\n");
}
2015-09-14 10:35:38 +00:00
r_reg_arena_swap (core->dbg->reg, true);
r_debug_continue_syscalls (core->dbg, syscalls, count);
free (syscalls);
}
static RGraphNode *get_graphtrace_node (RGraph *g, Sdb *nodes, struct trace_node *tn) {
RGraphNode *gn;
char tn_key[TN_KEY_LEN];
snprintf (tn_key, TN_KEY_LEN, TN_KEY_FMT, tn->addr);
gn = (RGraphNode *)(size_t)sdb_num_get (nodes, tn_key, NULL);
if (!gn) {
gn = r_graph_add_node (g, tn);
sdb_num_set (nodes, tn_key, (ut64)(size_t)gn, 0);
}
return gn;
}
static void dot_trace_create_node (RTreeNode *n, RTreeVisitor *vis) {
struct dot_trace_ght *data = (struct dot_trace_ght *)vis->data;
struct trace_node *tn = n->data;
if (tn) get_graphtrace_node (data->graph, data->graphnodes, tn);
}
static void dot_trace_discover_child (RTreeNode *n, RTreeVisitor *vis) {
struct dot_trace_ght *data = (struct dot_trace_ght *)vis->data;
RGraph *g = data->graph;
Sdb *gnodes = data->graphnodes;
RTreeNode *parent = n->parent;
struct trace_node *tn = n->data;
struct trace_node *tn_parent = parent->data;
if (tn && tn_parent) {
RGraphNode *gn = get_graphtrace_node (g, gnodes, tn);
RGraphNode *gn_parent = get_graphtrace_node (g, gnodes, tn_parent);
if (!r_graph_adjacent (g, gn_parent, gn))
r_graph_add_edge (g, gn_parent, gn);
}
}
static void dot_trace_traverse(RCore *core, RTree *t, int fmt) {
const char *gfont = r_config_get (core->config, "graph.font");
struct dot_trace_ght aux_data;
RTreeVisitor vis = { 0 };
const RList *nodes;
RListIter *iter;
RGraphNode *n;
if (fmt == 'i') {
r_core_cmd0 (core, "ag-;.dtg*;aggi");
return;
}
aux_data.graph = r_graph_new ();
aux_data.graphnodes = sdb_new0 ();
/* build a callgraph from the execution trace */
vis.data = &aux_data;
vis.pre_visit = (RTreeNodeVisitCb)dot_trace_create_node;
vis.discover_child = (RTreeNodeVisitCb)dot_trace_discover_child;
r_tree_bfs (t, &vis);
/* traverse the callgraph to print the dot file */
nodes = r_graph_get_nodes (aux_data.graph);
if (fmt == 0) {
r_cons_printf ("digraph code {\n"
"graph [bgcolor=white];\n"
" node [color=lightgray, style=filled"
" shape=box fontname=\"%s\" fontsize=\"8\"];\n", gfont);
}
r_list_foreach (nodes, iter, n) {
struct trace_node *tn = (struct trace_node *)n->data;
const RList *neighbours = r_graph_get_neighbours (aux_data.graph, n);
RListIter *it_n;
RGraphNode *w;
if (!fmt && tn) {
r_cons_printf ("\"0x%08"PFMT64x"\" [URL=\"0x%08"PFMT64x
"\" color=\"lightgray\" label=\"0x%08"PFMT64x
" (%d)\"]\n", tn->addr, tn->addr, tn->addr, tn->refs);
}
r_list_foreach (neighbours, it_n, w) {
struct trace_node *tv = (struct trace_node *)w->data;
if (tv && tn) {
if (fmt) {
r_cons_printf ("agn 0x%08"PFMT64x"\n", tn->addr);
r_cons_printf ("agn 0x%08"PFMT64x"\n", tv->addr);
r_cons_printf ("age 0x%08"PFMT64x" 0x%08"PFMT64x"\n",
tn->addr, tv->addr);
} else {
r_cons_printf ("\"0x%08"PFMT64x"\" -> \"0x%08"PFMT64x
"\" [color=\"red\"];\n", tn->addr, tv->addr);
}
}
}
}
if (!fmt) {
r_cons_printf ("}\n");
}
r_graph_free (aux_data.graph);
sdb_free (aux_data.graphnodes);
}
/* TODO: refactor all those step_until* function into a single one
* TODO: handle when the process is dead
* TODO: handle ^C */
2012-02-27 01:40:27 +00:00
static int step_until(RCore *core, ut64 addr) {
2015-10-31 00:57:52 +00:00
ut64 off = r_debug_reg_get (core->dbg, "PC");
2012-02-27 01:40:27 +00:00
if (off == 0LL) {
eprintf ("Cannot 'drn pc'\n");
2015-09-14 10:35:38 +00:00
return false;
2012-02-27 01:40:27 +00:00
}
if (addr == 0LL) {
eprintf ("Cannot continue until address 0\n");
2015-09-14 10:35:38 +00:00
return false;
2012-02-27 01:40:27 +00:00
}
r_cons_break (NULL, NULL);
2012-02-27 01:40:27 +00:00
do {
if (r_cons_singleton ()->breaked)
break;
if (r_debug_is_dead (core->dbg))
break;
2012-02-27 01:40:27 +00:00
r_debug_step (core->dbg, 1);
2015-10-31 00:57:52 +00:00
off = r_debug_reg_get (core->dbg, "PC");
2012-02-27 01:40:27 +00:00
// check breakpoint here
} while (off != addr);
r_cons_break_end();
2015-09-14 10:35:38 +00:00
return true;
2012-02-27 01:40:27 +00:00
}
static int step_until_esil(RCore *core, const char *esilstr) {
if (!core || !esilstr || !core->dbg || !core->dbg->anal \
|| !core->dbg->anal->esil) {
eprintf ("Not initialized %p. Run 'aei' first.\n", core->anal->esil);
2015-09-14 10:35:38 +00:00
return false;
}
r_cons_break (NULL, NULL);
for (;;) {
if (r_cons_singleton ()->breaked)
break;
if (r_debug_is_dead (core->dbg))
break;
r_debug_step (core->dbg, 1);
r_debug_reg_sync (core->dbg, -1, 0);
if (r_anal_esil_condition (core->anal->esil, esilstr)) {
eprintf ("ESIL BREAK!\n");
break;
}
}
r_cons_break_end();
2015-09-14 10:35:38 +00:00
return true;
}
static int step_until_inst(RCore *core, const char *instr) {
RAsmOp asmop;
ut8 buf[32];
ut64 pc;
int ret;
instr = r_str_chop_ro (instr);
if (!core || !instr|| !core->dbg) {
eprintf ("Wrong state\n");
2015-09-14 10:35:38 +00:00
return false;
}
r_cons_break (NULL, NULL);
for (;;) {
if (r_cons_singleton ()->breaked)
break;
if (r_debug_is_dead (core->dbg))
break;
r_debug_step (core->dbg, 1);
r_debug_reg_sync (core->dbg, -1, 0);
/* TODO: disassemble instruction and strstr */
2015-10-31 00:57:52 +00:00
pc = r_debug_reg_get (core->dbg, "PC");
r_asm_set_pc (core->assembler, pc);
// TODO: speedup if instructions are in the same block as the previous
r_io_read_at (core->io, pc, buf, sizeof (buf));
ret = r_asm_disassemble (core->assembler, &asmop, buf, sizeof (buf));
eprintf ("0x%08"PFMT64x" %d %s\n", pc, ret, asmop.buf_asm);
if (ret>0) {
if (strstr (asmop.buf_asm, instr)) {
eprintf ("Stop.\n");
break;
}
}
}
r_cons_break_end();
2015-09-14 10:35:38 +00:00
return true;
}
static int step_until_flag(RCore *core, const char *instr) {
const RList *list;
RListIter *iter;
RFlagItem *f;
ut64 pc;
instr = r_str_chop_ro (instr);
if (!core || !instr|| !core->dbg) {
eprintf ("Wrong state\n");
2015-09-14 10:35:38 +00:00
return false;
}
r_cons_break (NULL, NULL);
for (;;) {
if (r_cons_singleton ()->breaked)
break;
if (r_debug_is_dead (core->dbg))
break;
r_debug_step (core->dbg, 1);
r_debug_reg_sync (core->dbg, -1, 0);
2015-10-31 00:57:52 +00:00
pc = r_debug_reg_get (core->dbg, "PC");
list = r_flag_get_list (core->flags, pc);
r_list_foreach (list, iter, f) {
if (!instr|| !*instr || strstr(f->realname, instr)) {
r_cons_printf ("[ 0x%08"PFMT64x" ] %s\n",
f->offset, f->realname);
goto beach;
}
}
}
beach:
r_cons_break_end();
2015-09-14 10:35:38 +00:00
return true;
}
2012-11-13 03:38:26 +00:00
/* until end of frame */
static int step_until_eof(RCore *core) {
2015-10-31 00:57:52 +00:00
ut64 off, now = r_debug_reg_get (core->dbg, "SP");
r_cons_break (NULL, NULL);
2012-11-13 03:38:26 +00:00
do {
if (r_cons_singleton ()->breaked)
break;
2014-02-18 02:06:13 +00:00
if (!r_debug_step (core->dbg, 1))
break;
2015-10-31 00:57:52 +00:00
off = r_debug_reg_get (core->dbg, "SP");
2012-11-13 03:38:26 +00:00
// check breakpoint here
} while (off <= now);
r_cons_break_end();
2015-09-14 10:35:38 +00:00
return true;
2012-11-13 03:38:26 +00:00
}
2012-02-27 01:40:27 +00:00
static int step_line(RCore *core, int times) {
char file[512], file2[512];
int find_meta, line = -1, line2 = -1;
2014-05-03 23:43:25 +00:00
char *tmp_ptr = NULL;
2015-10-31 00:57:52 +00:00
ut64 off = r_debug_reg_get (core->dbg, "PC");
2012-02-27 01:40:27 +00:00
if (off == 0LL) {
eprintf ("Cannot 'drn pc'\n");
2015-09-14 10:35:38 +00:00
return false;
2012-02-27 01:40:27 +00:00
}
file[0] = 0;
file2[0] = 0;
2014-03-10 01:27:32 +00:00
if (r_bin_addr2line (core->bin, off, file, sizeof (file), &line)) {
2014-08-18 01:22:16 +00:00
char* ptr = r_file_slurp_line (file, line, 0);
2012-02-27 01:40:27 +00:00
eprintf ("--> 0x%08"PFMT64x" %s : %d\n", off, file, line);
2014-08-18 01:22:16 +00:00
eprintf ("--> %s\n", ptr);
2015-09-14 10:35:38 +00:00
find_meta = false;
2014-08-18 01:22:16 +00:00
free (ptr);
2012-02-27 01:40:27 +00:00
} else {
eprintf ("--> Stepping until dwarf line\n");
2015-09-14 10:35:38 +00:00
find_meta = true;
2012-02-27 01:40:27 +00:00
}
do {
r_debug_step (core->dbg, 1);
2015-10-31 00:57:52 +00:00
off = r_debug_reg_get (core->dbg, "PC");
2014-03-10 01:27:32 +00:00
if (!r_bin_addr2line (core->bin, off, file2, sizeof (file2), &line2)) {
2012-02-27 01:40:27 +00:00
if (find_meta)
continue;
eprintf ("Cannot retrieve dwarf info at 0x%08"PFMT64x"\n", off);
2015-09-14 10:35:38 +00:00
return false;
2012-02-27 01:40:27 +00:00
}
} while (!strcmp (file, file2) && line == line2);
2014-05-03 23:43:25 +00:00
2012-02-27 01:40:27 +00:00
eprintf ("--> 0x%08"PFMT64x" %s : %d\n", off, file2, line2);
2014-05-03 23:43:25 +00:00
tmp_ptr = r_file_slurp_line (file2, line2, 0);
eprintf ("--> %s\n", tmp_ptr);
free (tmp_ptr);
2015-09-14 10:35:38 +00:00
return true;
2012-02-27 01:40:27 +00:00
}
static void cmd_debug_pid(RCore *core, const char *input) {
int pid, sig;
const char *ptr, *help_msg[] = {
"Usage:", "dp", " # Process commands",
"dp", "", "List current pid and childrens",
"dp", " <pid>", "List children of pid",
"dp*", "", "List all attachable pids",
"dp=", "<pid>", "Select pid",
2015-11-16 23:49:59 +00:00
"dp-", " <pid>", "Dettach select pid",
"dpa", " <pid>", "Attach and select pid",
"dpc", "", "Select forked pid (see dbg.forks)",
"dpc*", "", "Display forked pid (see dbg.forks)",
"dpe", "", "Show path to executable",
"dpf", "", "Attach to pid like file fd // HACK",
"dpk", " <pid> [<signal>]", "Send signal to process (default 0)",
"dpn", "", "Create new process (fork)",
"dptn", "", "Create new thread (clone)",
"dpt", "", "List threads of current pid",
"dpt", " <pid>", "List threads of process",
"dpt=", "<thread>", "Attach to thread",
NULL};
2012-02-27 01:40:27 +00:00
switch (input[1]) {
case 0:
eprintf ("Selected: %d %d\n", core->dbg->pid, core->dbg->tid);
r_debug_pid_list (core->dbg, core->dbg->pid, 0);
break;
case '-': // "dp-"
2015-11-16 23:49:59 +00:00
if (input[2]== ' ') {
Major rework to the native debugger (esp on Linux) (#5185) The major contribution here is completely re-worked breakpoint hit/recoil handling. This work fixes #4907 and lays the ground work for future native debugger improvements (multi-threading, etc). * Give a human friendly type to enums * Change many wait functions to return RDebugReasonType * Better return checking (from r_debug_reg_sync, r_bp_restore) * Optimized register synchronization * Lots of comments and whitespace changes * Improved inferior death detection Handle EXIT_PID events differently than DEAD process events * Move breakpoint/recoil handling to wait/cont/step Rather than handing breakpoint related things inside cmd_debug.c, do that inside the r_debug API functions. This seems like the most logical place for it to live since it should apply to just about any platform/architecture. This also centralizes calling into "cmd.bp" handling via the CoreBind callback. * Track how the caller wishes to continue It turns out that handling break point recoils is very complicated. The ptrace API on Linux returns SIGTRAP for just about every type of operation (not just breakpoints getting hit). Add the "recoil_mode" flag to indicate whether we are single-stepping or continuing and whether or not we are inside the recoil. * Proper handling for swstep=true Since r_debug_step_soft calls r_debug_continue, it's already hitting the recoil case there. Move the recoil handling from r_debug_step to r_debug_step_hard only. For the swstep=true case, special handling is required inside r_debug_recoil. By resetting all of the breakpoints except the one we just hit, we ensure we can step the original instruction and hit the new swstep breakpoint. Add a new bp function called r_bp_restore_except to do this. To make matters worse, we cannot use a BreakpointItem pointer because that leads to a use-after-free condition. Instead, we the breakpoint address instead. Now breakpoints should work regardless of the swtep setting. * Always call the recoil before continuing Some callers of r_debug_continue might not have ever inserted any breakpoints before. If we don't restore breakpoints before each call to the underlying continue we won't hit them. * Hide software step breakpoint events from the user When a breakpoint even happens due to a software-step, hide it from the user. They aren't really breakpoints as far as they are concerned. * Improve process exit handling on Linux There are three types of process exiting events on Linux: 1. PTRACE_EVENT_EXIT occurs just before a process exits. It's not possible to prevent it from exiting, but it can be used to inspect the pre-exit state. 2. The process can exit for a variety of reasons and we can notice when we call waitpid(2). 3. The process could die randomly on us :-/ On Windows, h->wait will return R_DEBUG_REASON_EXIT_PID, but it's more likely on Linux to find out the process is already dead. * Check more bits within waitpid status We can often make a decision about what happened strictly by looking at the status returned from waitpid. In other cases, we need to call r_debug_handle_signals. If we reach the end of this function without knowing what happened, consider it an error.
2016-06-22 08:34:45 +00:00
r_debug_detach (core->dbg, r_num_math (core->num, input + 2));
2015-11-16 23:49:59 +00:00
} else {
r_debug_detach (core->dbg, core->dbg->pid);
}
break;
case 'c': // "dpc"
if (core->dbg->forked_pid != -1) {
if (input[2] == '*') {
eprintf ("dp %d\n", core->dbg->forked_pid);
} else {
r_debug_select (core->dbg, core->dbg->forked_pid, core->dbg->tid);
core->dbg->forked_pid = -1;
}
} else {
eprintf ("No recently forked children\n");
}
break;
case 'k': // "dpk"
/* stop, print, pass -- just use flags*/
2012-02-27 01:40:27 +00:00
/* XXX: not for threads? signal is for a whole process!! */
/* XXX: but we want fine-grained access to process resources */
pid = atoi (input + 2);
2012-02-27 01:40:27 +00:00
if (pid > 0) {
ptr = r_str_chop_ro (input + 2);
ptr = strchr (ptr, ' ');
sig = ptr? atoi (ptr + 1): 0;
2012-02-27 01:40:27 +00:00
eprintf ("Sending signal '%d' to pid '%d'\n", sig, pid);
2015-09-14 10:35:38 +00:00
r_debug_kill (core->dbg, 0, false, sig);
} else eprintf ("cmd_debug_pid: Invalid arguments (%s)\n", input);
2012-02-27 01:40:27 +00:00
break;
case 'n': // "dpn"
2013-07-15 00:51:55 +00:00
eprintf ("TODO: debug_fork: %d\n", r_debug_child_fork (core->dbg));
2012-02-27 01:40:27 +00:00
break;
2016-04-21 13:21:56 +00:00
case 't': // "dpt"
2012-02-27 01:40:27 +00:00
switch (input[2]) {
case 0:
r_debug_thread_list (core->dbg, core->dbg->pid);
break;
2012-02-27 01:40:27 +00:00
case 'n':
2013-07-15 00:51:55 +00:00
eprintf ("TODO: debug_clone: %d\n", r_debug_child_clone (core->dbg));
2012-02-27 01:40:27 +00:00
break;
case '=':
r_debug_select (core->dbg, core->dbg->pid,
Major rework to the native debugger (esp on Linux) (#5185) The major contribution here is completely re-worked breakpoint hit/recoil handling. This work fixes #4907 and lays the ground work for future native debugger improvements (multi-threading, etc). * Give a human friendly type to enums * Change many wait functions to return RDebugReasonType * Better return checking (from r_debug_reg_sync, r_bp_restore) * Optimized register synchronization * Lots of comments and whitespace changes * Improved inferior death detection Handle EXIT_PID events differently than DEAD process events * Move breakpoint/recoil handling to wait/cont/step Rather than handing breakpoint related things inside cmd_debug.c, do that inside the r_debug API functions. This seems like the most logical place for it to live since it should apply to just about any platform/architecture. This also centralizes calling into "cmd.bp" handling via the CoreBind callback. * Track how the caller wishes to continue It turns out that handling break point recoils is very complicated. The ptrace API on Linux returns SIGTRAP for just about every type of operation (not just breakpoints getting hit). Add the "recoil_mode" flag to indicate whether we are single-stepping or continuing and whether or not we are inside the recoil. * Proper handling for swstep=true Since r_debug_step_soft calls r_debug_continue, it's already hitting the recoil case there. Move the recoil handling from r_debug_step to r_debug_step_hard only. For the swstep=true case, special handling is required inside r_debug_recoil. By resetting all of the breakpoints except the one we just hit, we ensure we can step the original instruction and hit the new swstep breakpoint. Add a new bp function called r_bp_restore_except to do this. To make matters worse, we cannot use a BreakpointItem pointer because that leads to a use-after-free condition. Instead, we the breakpoint address instead. Now breakpoints should work regardless of the swtep setting. * Always call the recoil before continuing Some callers of r_debug_continue might not have ever inserted any breakpoints before. If we don't restore breakpoints before each call to the underlying continue we won't hit them. * Hide software step breakpoint events from the user When a breakpoint even happens due to a software-step, hide it from the user. They aren't really breakpoints as far as they are concerned. * Improve process exit handling on Linux There are three types of process exiting events on Linux: 1. PTRACE_EVENT_EXIT occurs just before a process exits. It's not possible to prevent it from exiting, but it can be used to inspect the pre-exit state. 2. The process can exit for a variety of reasons and we can notice when we call waitpid(2). 3. The process could die randomly on us :-/ On Windows, h->wait will return R_DEBUG_REASON_EXIT_PID, but it's more likely on Linux to find out the process is already dead. * Check more bits within waitpid status We can often make a decision about what happened strictly by looking at the status returned from waitpid. In other cases, we need to call r_debug_handle_signals. If we reach the end of this function without knowing what happened, consider it an error.
2016-06-22 08:34:45 +00:00
(int) r_num_math (core->num, input + 3));
2012-02-27 01:40:27 +00:00
break;
2016-04-21 13:21:56 +00:00
case ' ':
Major rework to the native debugger (esp on Linux) (#5185) The major contribution here is completely re-worked breakpoint hit/recoil handling. This work fixes #4907 and lays the ground work for future native debugger improvements (multi-threading, etc). * Give a human friendly type to enums * Change many wait functions to return RDebugReasonType * Better return checking (from r_debug_reg_sync, r_bp_restore) * Optimized register synchronization * Lots of comments and whitespace changes * Improved inferior death detection Handle EXIT_PID events differently than DEAD process events * Move breakpoint/recoil handling to wait/cont/step Rather than handing breakpoint related things inside cmd_debug.c, do that inside the r_debug API functions. This seems like the most logical place for it to live since it should apply to just about any platform/architecture. This also centralizes calling into "cmd.bp" handling via the CoreBind callback. * Track how the caller wishes to continue It turns out that handling break point recoils is very complicated. The ptrace API on Linux returns SIGTRAP for just about every type of operation (not just breakpoints getting hit). Add the "recoil_mode" flag to indicate whether we are single-stepping or continuing and whether or not we are inside the recoil. * Proper handling for swstep=true Since r_debug_step_soft calls r_debug_continue, it's already hitting the recoil case there. Move the recoil handling from r_debug_step to r_debug_step_hard only. For the swstep=true case, special handling is required inside r_debug_recoil. By resetting all of the breakpoints except the one we just hit, we ensure we can step the original instruction and hit the new swstep breakpoint. Add a new bp function called r_bp_restore_except to do this. To make matters worse, we cannot use a BreakpointItem pointer because that leads to a use-after-free condition. Instead, we the breakpoint address instead. Now breakpoints should work regardless of the swtep setting. * Always call the recoil before continuing Some callers of r_debug_continue might not have ever inserted any breakpoints before. If we don't restore breakpoints before each call to the underlying continue we won't hit them. * Hide software step breakpoint events from the user When a breakpoint even happens due to a software-step, hide it from the user. They aren't really breakpoints as far as they are concerned. * Improve process exit handling on Linux There are three types of process exiting events on Linux: 1. PTRACE_EVENT_EXIT occurs just before a process exits. It's not possible to prevent it from exiting, but it can be used to inspect the pre-exit state. 2. The process can exit for a variety of reasons and we can notice when we call waitpid(2). 3. The process could die randomly on us :-/ On Windows, h->wait will return R_DEBUG_REASON_EXIT_PID, but it's more likely on Linux to find out the process is already dead. * Check more bits within waitpid status We can often make a decision about what happened strictly by looking at the status returned from waitpid. In other cases, we need to call r_debug_handle_signals. If we reach the end of this function without knowing what happened, consider it an error.
2016-06-22 08:34:45 +00:00
r_debug_thread_list (core->dbg, atoi (input + 2));
2016-04-21 13:21:56 +00:00
break;
case '?':
2012-02-27 01:40:27 +00:00
default:
r_core_cmd_help (core, help_msg);
2012-02-27 01:40:27 +00:00
break;
}
break;
case 'a': // "dpa"
if (input[2]) {
r_debug_attach (core->dbg, (int) r_num_math (
Major rework to the native debugger (esp on Linux) (#5185) The major contribution here is completely re-worked breakpoint hit/recoil handling. This work fixes #4907 and lays the ground work for future native debugger improvements (multi-threading, etc). * Give a human friendly type to enums * Change many wait functions to return RDebugReasonType * Better return checking (from r_debug_reg_sync, r_bp_restore) * Optimized register synchronization * Lots of comments and whitespace changes * Improved inferior death detection Handle EXIT_PID events differently than DEAD process events * Move breakpoint/recoil handling to wait/cont/step Rather than handing breakpoint related things inside cmd_debug.c, do that inside the r_debug API functions. This seems like the most logical place for it to live since it should apply to just about any platform/architecture. This also centralizes calling into "cmd.bp" handling via the CoreBind callback. * Track how the caller wishes to continue It turns out that handling break point recoils is very complicated. The ptrace API on Linux returns SIGTRAP for just about every type of operation (not just breakpoints getting hit). Add the "recoil_mode" flag to indicate whether we are single-stepping or continuing and whether or not we are inside the recoil. * Proper handling for swstep=true Since r_debug_step_soft calls r_debug_continue, it's already hitting the recoil case there. Move the recoil handling from r_debug_step to r_debug_step_hard only. For the swstep=true case, special handling is required inside r_debug_recoil. By resetting all of the breakpoints except the one we just hit, we ensure we can step the original instruction and hit the new swstep breakpoint. Add a new bp function called r_bp_restore_except to do this. To make matters worse, we cannot use a BreakpointItem pointer because that leads to a use-after-free condition. Instead, we the breakpoint address instead. Now breakpoints should work regardless of the swtep setting. * Always call the recoil before continuing Some callers of r_debug_continue might not have ever inserted any breakpoints before. If we don't restore breakpoints before each call to the underlying continue we won't hit them. * Hide software step breakpoint events from the user When a breakpoint even happens due to a software-step, hide it from the user. They aren't really breakpoints as far as they are concerned. * Improve process exit handling on Linux There are three types of process exiting events on Linux: 1. PTRACE_EVENT_EXIT occurs just before a process exits. It's not possible to prevent it from exiting, but it can be used to inspect the pre-exit state. 2. The process can exit for a variety of reasons and we can notice when we call waitpid(2). 3. The process could die randomly on us :-/ On Windows, h->wait will return R_DEBUG_REASON_EXIT_PID, but it's more likely on Linux to find out the process is already dead. * Check more bits within waitpid status We can often make a decision about what happened strictly by looking at the status returned from waitpid. In other cases, we need to call r_debug_handle_signals. If we reach the end of this function without knowing what happened, consider it an error.
2016-06-22 08:34:45 +00:00
core->num, input + 2));
} else {
if (core->file && core->file->desc) {
r_debug_attach (core->dbg, core->file->desc->fd);
}
}
2012-02-27 01:40:27 +00:00
r_debug_select (core->dbg, core->dbg->pid, core->dbg->tid);
r_config_set_i (core->config, "dbg.swstep",
(core->dbg->h && !core->dbg->h->canstep));
r_core_cmdf (core, "=!pid %d", core->dbg->pid);
2012-02-27 01:40:27 +00:00
break;
case 'f': // "dpf"
2014-12-01 10:43:32 +00:00
if (core->file && core->file->desc) {
r_debug_select (core->dbg, core->file->desc->fd, core->dbg->tid);
}
2012-02-27 01:40:27 +00:00
break;
case '=': // "dp="
2012-02-27 01:40:27 +00:00
r_debug_select (core->dbg,
Major rework to the native debugger (esp on Linux) (#5185) The major contribution here is completely re-worked breakpoint hit/recoil handling. This work fixes #4907 and lays the ground work for future native debugger improvements (multi-threading, etc). * Give a human friendly type to enums * Change many wait functions to return RDebugReasonType * Better return checking (from r_debug_reg_sync, r_bp_restore) * Optimized register synchronization * Lots of comments and whitespace changes * Improved inferior death detection Handle EXIT_PID events differently than DEAD process events * Move breakpoint/recoil handling to wait/cont/step Rather than handing breakpoint related things inside cmd_debug.c, do that inside the r_debug API functions. This seems like the most logical place for it to live since it should apply to just about any platform/architecture. This also centralizes calling into "cmd.bp" handling via the CoreBind callback. * Track how the caller wishes to continue It turns out that handling break point recoils is very complicated. The ptrace API on Linux returns SIGTRAP for just about every type of operation (not just breakpoints getting hit). Add the "recoil_mode" flag to indicate whether we are single-stepping or continuing and whether or not we are inside the recoil. * Proper handling for swstep=true Since r_debug_step_soft calls r_debug_continue, it's already hitting the recoil case there. Move the recoil handling from r_debug_step to r_debug_step_hard only. For the swstep=true case, special handling is required inside r_debug_recoil. By resetting all of the breakpoints except the one we just hit, we ensure we can step the original instruction and hit the new swstep breakpoint. Add a new bp function called r_bp_restore_except to do this. To make matters worse, we cannot use a BreakpointItem pointer because that leads to a use-after-free condition. Instead, we the breakpoint address instead. Now breakpoints should work regardless of the swtep setting. * Always call the recoil before continuing Some callers of r_debug_continue might not have ever inserted any breakpoints before. If we don't restore breakpoints before each call to the underlying continue we won't hit them. * Hide software step breakpoint events from the user When a breakpoint even happens due to a software-step, hide it from the user. They aren't really breakpoints as far as they are concerned. * Improve process exit handling on Linux There are three types of process exiting events on Linux: 1. PTRACE_EVENT_EXIT occurs just before a process exits. It's not possible to prevent it from exiting, but it can be used to inspect the pre-exit state. 2. The process can exit for a variety of reasons and we can notice when we call waitpid(2). 3. The process could die randomly on us :-/ On Windows, h->wait will return R_DEBUG_REASON_EXIT_PID, but it's more likely on Linux to find out the process is already dead. * Check more bits within waitpid status We can often make a decision about what happened strictly by looking at the status returned from waitpid. In other cases, we need to call r_debug_handle_signals. If we reach the end of this function without knowing what happened, consider it an error.
2016-06-22 08:34:45 +00:00
(int) r_num_math (core->num, input + 2), core->dbg->tid);
2012-02-27 01:40:27 +00:00
break;
case '*': // "dp*"
2014-10-01 19:39:28 +00:00
r_debug_pid_list (core->dbg, 0, 0);
2012-02-27 01:40:27 +00:00
break;
case 'j': // "dpj"
2014-10-01 19:39:28 +00:00
r_debug_pid_list (core->dbg, core->dbg->pid, 'j');
break;
case 'e': // "dpe"
{
Major rework to the native debugger (esp on Linux) (#5185) The major contribution here is completely re-worked breakpoint hit/recoil handling. This work fixes #4907 and lays the ground work for future native debugger improvements (multi-threading, etc). * Give a human friendly type to enums * Change many wait functions to return RDebugReasonType * Better return checking (from r_debug_reg_sync, r_bp_restore) * Optimized register synchronization * Lots of comments and whitespace changes * Improved inferior death detection Handle EXIT_PID events differently than DEAD process events * Move breakpoint/recoil handling to wait/cont/step Rather than handing breakpoint related things inside cmd_debug.c, do that inside the r_debug API functions. This seems like the most logical place for it to live since it should apply to just about any platform/architecture. This also centralizes calling into "cmd.bp" handling via the CoreBind callback. * Track how the caller wishes to continue It turns out that handling break point recoils is very complicated. The ptrace API on Linux returns SIGTRAP for just about every type of operation (not just breakpoints getting hit). Add the "recoil_mode" flag to indicate whether we are single-stepping or continuing and whether or not we are inside the recoil. * Proper handling for swstep=true Since r_debug_step_soft calls r_debug_continue, it's already hitting the recoil case there. Move the recoil handling from r_debug_step to r_debug_step_hard only. For the swstep=true case, special handling is required inside r_debug_recoil. By resetting all of the breakpoints except the one we just hit, we ensure we can step the original instruction and hit the new swstep breakpoint. Add a new bp function called r_bp_restore_except to do this. To make matters worse, we cannot use a BreakpointItem pointer because that leads to a use-after-free condition. Instead, we the breakpoint address instead. Now breakpoints should work regardless of the swtep setting. * Always call the recoil before continuing Some callers of r_debug_continue might not have ever inserted any breakpoints before. If we don't restore breakpoints before each call to the underlying continue we won't hit them. * Hide software step breakpoint events from the user When a breakpoint even happens due to a software-step, hide it from the user. They aren't really breakpoints as far as they are concerned. * Improve process exit handling on Linux There are three types of process exiting events on Linux: 1. PTRACE_EVENT_EXIT occurs just before a process exits. It's not possible to prevent it from exiting, but it can be used to inspect the pre-exit state. 2. The process can exit for a variety of reasons and we can notice when we call waitpid(2). 3. The process could die randomly on us :-/ On Windows, h->wait will return R_DEBUG_REASON_EXIT_PID, but it's more likely on Linux to find out the process is already dead. * Check more bits within waitpid status We can often make a decision about what happened strictly by looking at the status returned from waitpid. In other cases, we need to call r_debug_handle_signals. If we reach the end of this function without knowing what happened, consider it an error.
2016-06-22 08:34:45 +00:00
int pid = (input[2] == ' ')? atoi (input + 2): core->dbg->pid;
char *exe = r_sys_pid_to_path (pid);
if (exe) {
r_cons_println (exe);
free (exe);
}
}
break;
2012-02-27 01:40:27 +00:00
case ' ':
r_debug_pid_list (core->dbg,
Major rework to the native debugger (esp on Linux) (#5185) The major contribution here is completely re-worked breakpoint hit/recoil handling. This work fixes #4907 and lays the ground work for future native debugger improvements (multi-threading, etc). * Give a human friendly type to enums * Change many wait functions to return RDebugReasonType * Better return checking (from r_debug_reg_sync, r_bp_restore) * Optimized register synchronization * Lots of comments and whitespace changes * Improved inferior death detection Handle EXIT_PID events differently than DEAD process events * Move breakpoint/recoil handling to wait/cont/step Rather than handing breakpoint related things inside cmd_debug.c, do that inside the r_debug API functions. This seems like the most logical place for it to live since it should apply to just about any platform/architecture. This also centralizes calling into "cmd.bp" handling via the CoreBind callback. * Track how the caller wishes to continue It turns out that handling break point recoils is very complicated. The ptrace API on Linux returns SIGTRAP for just about every type of operation (not just breakpoints getting hit). Add the "recoil_mode" flag to indicate whether we are single-stepping or continuing and whether or not we are inside the recoil. * Proper handling for swstep=true Since r_debug_step_soft calls r_debug_continue, it's already hitting the recoil case there. Move the recoil handling from r_debug_step to r_debug_step_hard only. For the swstep=true case, special handling is required inside r_debug_recoil. By resetting all of the breakpoints except the one we just hit, we ensure we can step the original instruction and hit the new swstep breakpoint. Add a new bp function called r_bp_restore_except to do this. To make matters worse, we cannot use a BreakpointItem pointer because that leads to a use-after-free condition. Instead, we the breakpoint address instead. Now breakpoints should work regardless of the swtep setting. * Always call the recoil before continuing Some callers of r_debug_continue might not have ever inserted any breakpoints before. If we don't restore breakpoints before each call to the underlying continue we won't hit them. * Hide software step breakpoint events from the user When a breakpoint even happens due to a software-step, hide it from the user. They aren't really breakpoints as far as they are concerned. * Improve process exit handling on Linux There are three types of process exiting events on Linux: 1. PTRACE_EVENT_EXIT occurs just before a process exits. It's not possible to prevent it from exiting, but it can be used to inspect the pre-exit state. 2. The process can exit for a variety of reasons and we can notice when we call waitpid(2). 3. The process could die randomly on us :-/ On Windows, h->wait will return R_DEBUG_REASON_EXIT_PID, but it's more likely on Linux to find out the process is already dead. * Check more bits within waitpid status We can often make a decision about what happened strictly by looking at the status returned from waitpid. In other cases, we need to call r_debug_handle_signals. If we reach the end of this function without knowing what happened, consider it an error.
2016-06-22 08:34:45 +00:00
(int) R_MAX (0, (int)r_num_math (core->num, input + 2)), 0);
2012-02-27 01:40:27 +00:00
break;
case '?':
2012-02-27 01:40:27 +00:00
default:
r_core_cmd_help (core, help_msg);
2012-02-27 01:40:27 +00:00
break;
}
}
static void cmd_debug_backtrace (RCore *core, const char *input) {
RAnalOp analop;
ut64 addr, len = r_num_math (core->num, input);
if (len == 0) {
r_bp_traptrace_list (core->dbg->bp);
} else {
ut64 oaddr = 0LL;
eprintf ("Trap tracing 0x%08"PFMT64x"-0x%08"PFMT64x"\n",
core->offset, core->offset+len);
2015-09-14 10:35:38 +00:00
r_reg_arena_swap (core->dbg->reg, true);
r_bp_traptrace_reset (core->dbg->bp, true);
2012-02-27 01:40:27 +00:00
r_bp_traptrace_add (core->dbg->bp, core->offset, core->offset+len);
2015-09-14 10:35:38 +00:00
r_bp_traptrace_enable (core->dbg->bp, true);
2012-02-27 01:40:27 +00:00
do {
ut8 buf[32];
r_debug_continue (core->dbg);
2015-10-31 00:57:52 +00:00
addr = r_debug_reg_get (core->dbg, "PC");
2012-02-27 01:40:27 +00:00
if (addr == 0LL) {
eprintf ("pc=0\n");
break;
}
if (addr == oaddr) {
eprintf ("pc=opc\n");
break;
}
oaddr = addr;
/* XXX Bottleneck..we need to reuse the bytes read by traptrace */
// XXX Do asm.arch should define the max size of opcode?
r_core_read_at (core, addr, buf, 32); // XXX longer opcodes?
r_anal_op (core->anal, &analop, addr, buf, sizeof (buf));
} while (r_bp_traptrace_at (core->dbg->bp, addr, analop.size));
2015-09-14 10:35:38 +00:00
r_bp_traptrace_enable (core->dbg->bp, false);
2012-02-27 01:40:27 +00:00
}
}
static int __r_debug_snap_diff(RCore *core, int idx) {
ut32 count = 0;
RDebug *dbg = core->dbg;
ut32 oflags = core->print->flags;
int col = core->cons->columns>123;
RDebugSnap *snap;
RListIter *iter;
core->print->flags |= R_PRINT_FLAGS_DIFFOUT;
r_list_foreach (dbg->snaps, iter, snap) {
if (count == idx) {
ut8 *b = malloc (snap->size);
if (!b) {
eprintf ("Cannot allocate snapshot\n");
continue;
}
2015-03-17 23:10:43 +00:00
dbg->iob.read_at (dbg->iob.io, snap->addr, b , snap->size);
r_print_hexdiff (core->print,
snap->addr, snap->data,
snap->addr, b,
snap->size, col);
free (b);
}
count ++;
}
core->print->flags = oflags;
return 0;
}
static int cmd_debug_map_snapshot(RCore *core, const char *input) {
const char* help_msg[] = {
"Usage:", "dms", " # Memory map snapshots",
"dms", "", "List memory snapshots",
"dmsj", "", "list snapshots in JSON",
"dms*", "", "list snapshots in r2 commands",
"dms", " addr", "take snapshot with given id of map at address",
"dms", "-id", "delete memory snapshot",
"dmsC", " id comment", "add comment for given snapshot",
"dmsd", " id", "hexdiff given snapshot. See `ccc`.",
"dmsw", "", "snapshot of the writable maps",
"dmsa", "", "full snapshot of all `dm` maps",
"dmsf", " [file] @ addr", "read snapshot from disk",
"dmst", " [file] @ addr", "dump snapshot to disk",
// TODO: dmsj - for json
NULL
};
switch (*input) {
case 'f':
{
char *file;
RDebugSnap *snap;
if (input[1] == ' ') {
Major rework to the native debugger (esp on Linux) (#5185) The major contribution here is completely re-worked breakpoint hit/recoil handling. This work fixes #4907 and lays the ground work for future native debugger improvements (multi-threading, etc). * Give a human friendly type to enums * Change many wait functions to return RDebugReasonType * Better return checking (from r_debug_reg_sync, r_bp_restore) * Optimized register synchronization * Lots of comments and whitespace changes * Improved inferior death detection Handle EXIT_PID events differently than DEAD process events * Move breakpoint/recoil handling to wait/cont/step Rather than handing breakpoint related things inside cmd_debug.c, do that inside the r_debug API functions. This seems like the most logical place for it to live since it should apply to just about any platform/architecture. This also centralizes calling into "cmd.bp" handling via the CoreBind callback. * Track how the caller wishes to continue It turns out that handling break point recoils is very complicated. The ptrace API on Linux returns SIGTRAP for just about every type of operation (not just breakpoints getting hit). Add the "recoil_mode" flag to indicate whether we are single-stepping or continuing and whether or not we are inside the recoil. * Proper handling for swstep=true Since r_debug_step_soft calls r_debug_continue, it's already hitting the recoil case there. Move the recoil handling from r_debug_step to r_debug_step_hard only. For the swstep=true case, special handling is required inside r_debug_recoil. By resetting all of the breakpoints except the one we just hit, we ensure we can step the original instruction and hit the new swstep breakpoint. Add a new bp function called r_bp_restore_except to do this. To make matters worse, we cannot use a BreakpointItem pointer because that leads to a use-after-free condition. Instead, we the breakpoint address instead. Now breakpoints should work regardless of the swtep setting. * Always call the recoil before continuing Some callers of r_debug_continue might not have ever inserted any breakpoints before. If we don't restore breakpoints before each call to the underlying continue we won't hit them. * Hide software step breakpoint events from the user When a breakpoint even happens due to a software-step, hide it from the user. They aren't really breakpoints as far as they are concerned. * Improve process exit handling on Linux There are three types of process exiting events on Linux: 1. PTRACE_EVENT_EXIT occurs just before a process exits. It's not possible to prevent it from exiting, but it can be used to inspect the pre-exit state. 2. The process can exit for a variety of reasons and we can notice when we call waitpid(2). 3. The process could die randomly on us :-/ On Windows, h->wait will return R_DEBUG_REASON_EXIT_PID, but it's more likely on Linux to find out the process is already dead. * Check more bits within waitpid status We can often make a decision about what happened strictly by looking at the status returned from waitpid. In other cases, we need to call r_debug_handle_signals. If we reach the end of this function without knowing what happened, consider it an error.
2016-06-22 08:34:45 +00:00
file = strdup (input + 2);
} else {
file = r_str_newf ("0x%08"PFMT64x".dump", core->offset);
}
snap = r_debug_snap_get (core->dbg, core->offset);
if (!snap) {
r_debug_snap (core->dbg, core->offset);
snap = r_debug_snap_get (core->dbg, core->offset);
}
if (snap) {
int fsz = 0;
char *data = r_file_slurp (file, &fsz);
if (data) {
if (fsz >= snap->size) {
memcpy (snap->data, data, snap->size);
} else {
eprintf ("This file is smaller than the snapshot size\n");
}
free (data);
} else eprintf ("Cannot slurp '%s'\n", file);
} else {
eprintf ("Unable to find a snapshot for 0x%08"PFMT64x"\n", core->offset);
}
free (file);
}
break;
case 't':
{
char *file;
RDebugSnap *snap;
if (input[1] == ' ') {
Major rework to the native debugger (esp on Linux) (#5185) The major contribution here is completely re-worked breakpoint hit/recoil handling. This work fixes #4907 and lays the ground work for future native debugger improvements (multi-threading, etc). * Give a human friendly type to enums * Change many wait functions to return RDebugReasonType * Better return checking (from r_debug_reg_sync, r_bp_restore) * Optimized register synchronization * Lots of comments and whitespace changes * Improved inferior death detection Handle EXIT_PID events differently than DEAD process events * Move breakpoint/recoil handling to wait/cont/step Rather than handing breakpoint related things inside cmd_debug.c, do that inside the r_debug API functions. This seems like the most logical place for it to live since it should apply to just about any platform/architecture. This also centralizes calling into "cmd.bp" handling via the CoreBind callback. * Track how the caller wishes to continue It turns out that handling break point recoils is very complicated. The ptrace API on Linux returns SIGTRAP for just about every type of operation (not just breakpoints getting hit). Add the "recoil_mode" flag to indicate whether we are single-stepping or continuing and whether or not we are inside the recoil. * Proper handling for swstep=true Since r_debug_step_soft calls r_debug_continue, it's already hitting the recoil case there. Move the recoil handling from r_debug_step to r_debug_step_hard only. For the swstep=true case, special handling is required inside r_debug_recoil. By resetting all of the breakpoints except the one we just hit, we ensure we can step the original instruction and hit the new swstep breakpoint. Add a new bp function called r_bp_restore_except to do this. To make matters worse, we cannot use a BreakpointItem pointer because that leads to a use-after-free condition. Instead, we the breakpoint address instead. Now breakpoints should work regardless of the swtep setting. * Always call the recoil before continuing Some callers of r_debug_continue might not have ever inserted any breakpoints before. If we don't restore breakpoints before each call to the underlying continue we won't hit them. * Hide software step breakpoint events from the user When a breakpoint even happens due to a software-step, hide it from the user. They aren't really breakpoints as far as they are concerned. * Improve process exit handling on Linux There are three types of process exiting events on Linux: 1. PTRACE_EVENT_EXIT occurs just before a process exits. It's not possible to prevent it from exiting, but it can be used to inspect the pre-exit state. 2. The process can exit for a variety of reasons and we can notice when we call waitpid(2). 3. The process could die randomly on us :-/ On Windows, h->wait will return R_DEBUG_REASON_EXIT_PID, but it's more likely on Linux to find out the process is already dead. * Check more bits within waitpid status We can often make a decision about what happened strictly by looking at the status returned from waitpid. In other cases, we need to call r_debug_handle_signals. If we reach the end of this function without knowing what happened, consider it an error.
2016-06-22 08:34:45 +00:00
file = strdup (input + 2);
} else {
file = r_str_newf ("0x%08"PFMT64x".dump", core->offset);
}
snap = r_debug_snap_get (core->dbg, core->offset);
if (snap) {
if (!r_file_dump (file, snap->data, snap->size, 0)) {
eprintf ("Cannot slurp '%s'\n", file);
}
} else {
eprintf ("Unable to find a snapshot for 0x%08"PFMT64x"\n", core->offset);
}
free (file);
}
break;
case '?':
r_core_cmd_help (core, help_msg);
break;
case '-':
if (input[1]=='*') {
r_debug_snap_delete (core->dbg, -1);
} else {
Major rework to the native debugger (esp on Linux) (#5185) The major contribution here is completely re-worked breakpoint hit/recoil handling. This work fixes #4907 and lays the ground work for future native debugger improvements (multi-threading, etc). * Give a human friendly type to enums * Change many wait functions to return RDebugReasonType * Better return checking (from r_debug_reg_sync, r_bp_restore) * Optimized register synchronization * Lots of comments and whitespace changes * Improved inferior death detection Handle EXIT_PID events differently than DEAD process events * Move breakpoint/recoil handling to wait/cont/step Rather than handing breakpoint related things inside cmd_debug.c, do that inside the r_debug API functions. This seems like the most logical place for it to live since it should apply to just about any platform/architecture. This also centralizes calling into "cmd.bp" handling via the CoreBind callback. * Track how the caller wishes to continue It turns out that handling break point recoils is very complicated. The ptrace API on Linux returns SIGTRAP for just about every type of operation (not just breakpoints getting hit). Add the "recoil_mode" flag to indicate whether we are single-stepping or continuing and whether or not we are inside the recoil. * Proper handling for swstep=true Since r_debug_step_soft calls r_debug_continue, it's already hitting the recoil case there. Move the recoil handling from r_debug_step to r_debug_step_hard only. For the swstep=true case, special handling is required inside r_debug_recoil. By resetting all of the breakpoints except the one we just hit, we ensure we can step the original instruction and hit the new swstep breakpoint. Add a new bp function called r_bp_restore_except to do this. To make matters worse, we cannot use a BreakpointItem pointer because that leads to a use-after-free condition. Instead, we the breakpoint address instead. Now breakpoints should work regardless of the swtep setting. * Always call the recoil before continuing Some callers of r_debug_continue might not have ever inserted any breakpoints before. If we don't restore breakpoints before each call to the underlying continue we won't hit them. * Hide software step breakpoint events from the user When a breakpoint even happens due to a software-step, hide it from the user. They aren't really breakpoints as far as they are concerned. * Improve process exit handling on Linux There are three types of process exiting events on Linux: 1. PTRACE_EVENT_EXIT occurs just before a process exits. It's not possible to prevent it from exiting, but it can be used to inspect the pre-exit state. 2. The process can exit for a variety of reasons and we can notice when we call waitpid(2). 3. The process could die randomly on us :-/ On Windows, h->wait will return R_DEBUG_REASON_EXIT_PID, but it's more likely on Linux to find out the process is already dead. * Check more bits within waitpid status We can often make a decision about what happened strictly by looking at the status returned from waitpid. In other cases, we need to call r_debug_handle_signals. If we reach the end of this function without knowing what happened, consider it an error.
2016-06-22 08:34:45 +00:00
r_debug_snap_delete (core->dbg, r_num_math (core->num, input + 1));
}
break;
case ' ':
Major rework to the native debugger (esp on Linux) (#5185) The major contribution here is completely re-worked breakpoint hit/recoil handling. This work fixes #4907 and lays the ground work for future native debugger improvements (multi-threading, etc). * Give a human friendly type to enums * Change many wait functions to return RDebugReasonType * Better return checking (from r_debug_reg_sync, r_bp_restore) * Optimized register synchronization * Lots of comments and whitespace changes * Improved inferior death detection Handle EXIT_PID events differently than DEAD process events * Move breakpoint/recoil handling to wait/cont/step Rather than handing breakpoint related things inside cmd_debug.c, do that inside the r_debug API functions. This seems like the most logical place for it to live since it should apply to just about any platform/architecture. This also centralizes calling into "cmd.bp" handling via the CoreBind callback. * Track how the caller wishes to continue It turns out that handling break point recoils is very complicated. The ptrace API on Linux returns SIGTRAP for just about every type of operation (not just breakpoints getting hit). Add the "recoil_mode" flag to indicate whether we are single-stepping or continuing and whether or not we are inside the recoil. * Proper handling for swstep=true Since r_debug_step_soft calls r_debug_continue, it's already hitting the recoil case there. Move the recoil handling from r_debug_step to r_debug_step_hard only. For the swstep=true case, special handling is required inside r_debug_recoil. By resetting all of the breakpoints except the one we just hit, we ensure we can step the original instruction and hit the new swstep breakpoint. Add a new bp function called r_bp_restore_except to do this. To make matters worse, we cannot use a BreakpointItem pointer because that leads to a use-after-free condition. Instead, we the breakpoint address instead. Now breakpoints should work regardless of the swtep setting. * Always call the recoil before continuing Some callers of r_debug_continue might not have ever inserted any breakpoints before. If we don't restore breakpoints before each call to the underlying continue we won't hit them. * Hide software step breakpoint events from the user When a breakpoint even happens due to a software-step, hide it from the user. They aren't really breakpoints as far as they are concerned. * Improve process exit handling on Linux There are three types of process exiting events on Linux: 1. PTRACE_EVENT_EXIT occurs just before a process exits. It's not possible to prevent it from exiting, but it can be used to inspect the pre-exit state. 2. The process can exit for a variety of reasons and we can notice when we call waitpid(2). 3. The process could die randomly on us :-/ On Windows, h->wait will return R_DEBUG_REASON_EXIT_PID, but it's more likely on Linux to find out the process is already dead. * Check more bits within waitpid status We can often make a decision about what happened strictly by looking at the status returned from waitpid. In other cases, we need to call r_debug_handle_signals. If we reach the end of this function without knowing what happened, consider it an error.
2016-06-22 08:34:45 +00:00
r_debug_snap (core->dbg, r_num_math (core->num, input + 1));
break;
case 'C':
Major rework to the native debugger (esp on Linux) (#5185) The major contribution here is completely re-worked breakpoint hit/recoil handling. This work fixes #4907 and lays the ground work for future native debugger improvements (multi-threading, etc). * Give a human friendly type to enums * Change many wait functions to return RDebugReasonType * Better return checking (from r_debug_reg_sync, r_bp_restore) * Optimized register synchronization * Lots of comments and whitespace changes * Improved inferior death detection Handle EXIT_PID events differently than DEAD process events * Move breakpoint/recoil handling to wait/cont/step Rather than handing breakpoint related things inside cmd_debug.c, do that inside the r_debug API functions. This seems like the most logical place for it to live since it should apply to just about any platform/architecture. This also centralizes calling into "cmd.bp" handling via the CoreBind callback. * Track how the caller wishes to continue It turns out that handling break point recoils is very complicated. The ptrace API on Linux returns SIGTRAP for just about every type of operation (not just breakpoints getting hit). Add the "recoil_mode" flag to indicate whether we are single-stepping or continuing and whether or not we are inside the recoil. * Proper handling for swstep=true Since r_debug_step_soft calls r_debug_continue, it's already hitting the recoil case there. Move the recoil handling from r_debug_step to r_debug_step_hard only. For the swstep=true case, special handling is required inside r_debug_recoil. By resetting all of the breakpoints except the one we just hit, we ensure we can step the original instruction and hit the new swstep breakpoint. Add a new bp function called r_bp_restore_except to do this. To make matters worse, we cannot use a BreakpointItem pointer because that leads to a use-after-free condition. Instead, we the breakpoint address instead. Now breakpoints should work regardless of the swtep setting. * Always call the recoil before continuing Some callers of r_debug_continue might not have ever inserted any breakpoints before. If we don't restore breakpoints before each call to the underlying continue we won't hit them. * Hide software step breakpoint events from the user When a breakpoint even happens due to a software-step, hide it from the user. They aren't really breakpoints as far as they are concerned. * Improve process exit handling on Linux There are three types of process exiting events on Linux: 1. PTRACE_EVENT_EXIT occurs just before a process exits. It's not possible to prevent it from exiting, but it can be used to inspect the pre-exit state. 2. The process can exit for a variety of reasons and we can notice when we call waitpid(2). 3. The process could die randomly on us :-/ On Windows, h->wait will return R_DEBUG_REASON_EXIT_PID, but it's more likely on Linux to find out the process is already dead. * Check more bits within waitpid status We can often make a decision about what happened strictly by looking at the status returned from waitpid. In other cases, we need to call r_debug_handle_signals. If we reach the end of this function without knowing what happened, consider it an error.
2016-06-22 08:34:45 +00:00
r_debug_snap_comment (core->dbg, atoi (input + 1), strchr (input, ' '));
break;
case 'd':
Major rework to the native debugger (esp on Linux) (#5185) The major contribution here is completely re-worked breakpoint hit/recoil handling. This work fixes #4907 and lays the ground work for future native debugger improvements (multi-threading, etc). * Give a human friendly type to enums * Change many wait functions to return RDebugReasonType * Better return checking (from r_debug_reg_sync, r_bp_restore) * Optimized register synchronization * Lots of comments and whitespace changes * Improved inferior death detection Handle EXIT_PID events differently than DEAD process events * Move breakpoint/recoil handling to wait/cont/step Rather than handing breakpoint related things inside cmd_debug.c, do that inside the r_debug API functions. This seems like the most logical place for it to live since it should apply to just about any platform/architecture. This also centralizes calling into "cmd.bp" handling via the CoreBind callback. * Track how the caller wishes to continue It turns out that handling break point recoils is very complicated. The ptrace API on Linux returns SIGTRAP for just about every type of operation (not just breakpoints getting hit). Add the "recoil_mode" flag to indicate whether we are single-stepping or continuing and whether or not we are inside the recoil. * Proper handling for swstep=true Since r_debug_step_soft calls r_debug_continue, it's already hitting the recoil case there. Move the recoil handling from r_debug_step to r_debug_step_hard only. For the swstep=true case, special handling is required inside r_debug_recoil. By resetting all of the breakpoints except the one we just hit, we ensure we can step the original instruction and hit the new swstep breakpoint. Add a new bp function called r_bp_restore_except to do this. To make matters worse, we cannot use a BreakpointItem pointer because that leads to a use-after-free condition. Instead, we the breakpoint address instead. Now breakpoints should work regardless of the swtep setting. * Always call the recoil before continuing Some callers of r_debug_continue might not have ever inserted any breakpoints before. If we don't restore breakpoints before each call to the underlying continue we won't hit them. * Hide software step breakpoint events from the user When a breakpoint even happens due to a software-step, hide it from the user. They aren't really breakpoints as far as they are concerned. * Improve process exit handling on Linux There are three types of process exiting events on Linux: 1. PTRACE_EVENT_EXIT occurs just before a process exits. It's not possible to prevent it from exiting, but it can be used to inspect the pre-exit state. 2. The process can exit for a variety of reasons and we can notice when we call waitpid(2). 3. The process could die randomly on us :-/ On Windows, h->wait will return R_DEBUG_REASON_EXIT_PID, but it's more likely on Linux to find out the process is already dead. * Check more bits within waitpid status We can often make a decision about what happened strictly by looking at the status returned from waitpid. In other cases, we need to call r_debug_handle_signals. If we reach the end of this function without knowing what happened, consider it an error.
2016-06-22 08:34:45 +00:00
__r_debug_snap_diff (core, atoi (input + 1));
break;
case 'a':
r_debug_snap_all (core->dbg, 0);
break;
case 'w':
r_debug_snap_all (core->dbg, R_IO_RW);
break;
case 0:
case 'j':
case '*':
r_debug_snap_list (core->dbg, -1, input[0]);
break;
}
return 0;
}
#define MAX_MAP_SIZE 1024*1024*512
static int dump_maps(RCore *core, int perm, const char *filename) {
RDebugMap *map;
char file[128];
RListIter *iter;
r_debug_map_sync (core->dbg); // update process memory maps
ut64 addr = core->offset;
2015-09-14 10:35:38 +00:00
int do_dump = false;
int ret = r_list_empty(core->dbg->maps)? false: true;
r_list_foreach (core->dbg->maps, iter, map) {
2015-09-14 10:35:38 +00:00
do_dump = false;
if (perm == -1) {
if (addr >= map->addr && addr < map->addr_end) {
2015-09-14 10:35:38 +00:00
do_dump = true;
}
} else if (perm == 0) {
2015-09-14 10:35:38 +00:00
do_dump = true;
} else if (perm == (map->perm & perm)) {
2015-09-14 10:35:38 +00:00
do_dump = true;
}
if (do_dump) {
ut8 *buf = malloc (map->size);
//TODO: use mmap here. we need a portable implementation
if (!buf) {
eprintf ("Cannot allocate 0x%08"PFMT64x" bytes\n", map->size);
2015-07-24 21:59:38 +00:00
free (buf);
/// XXX: TODO: read by blocks!!1
continue;
}
if (map->size > MAX_MAP_SIZE) {
eprintf ("Do not dumping 0x%08"PFMT64x" because it's too big\n", map->addr);
2015-07-24 21:59:38 +00:00
free (buf);
continue;
}
r_io_read_at (core->io, map->addr, buf, map->size);
if (filename) {
snprintf (file, sizeof (file), "%s", filename);
} else snprintf (file, sizeof (file),
"0x%08"PFMT64x"-0x%08"PFMT64x"-%s.dmp",
map->addr, map->addr_end, r_str_rwx_i (map->perm));
if (!r_file_dump (file, buf, map->size, 0)) {
eprintf ("Cannot write '%s'\n", file);
ret = 0;
} else {
eprintf ("Dumped %d bytes into %s\n", (int)map->size, file);
}
free (buf);
}
}
//eprintf ("No debug region found here\n");
return ret;
}
static void cmd_debug_modules(RCore *core, int mode) { // "dmm"
2015-08-24 11:22:52 +00:00
ut64 addr = core->offset;
RDebugMap *map;
RList *list;
RListIter *iter;
const char* help_msg[] = {
"Usage:", "dmm", " # Module memory maps commands",
"dmm", "", "List modules of target process",
"dmm.", "", "List memory map of current module",
"dmmj", "", "List modules of target process (JSON)",
"dmm*", "", "List modules of target process (r2 commands)",
NULL
};
/* avoid processing the list if the user only wants help */
if (mode == '?') {
show_help:
r_core_cmd_help (core, help_msg);
return;
}
if (mode == 'j') {
r_cons_printf ("[");
}
// TODO: honor mode
list = r_debug_modules_list (core->dbg);
r_list_foreach (list, iter, map) {
switch (mode) {
case 0:
r_cons_printf ("0x%08"PFMT64x" %s\n", map->addr, map->file);
break;
case ':':
if (addr >= map->addr && addr < map->addr_end) {
char *fn = strdup (map->file);
r_name_filter (fn, 0);
//r_cons_printf ("fs+module_%s\n", fn);
r_cons_printf ("f mod.%s = 0x%08"PFMT64x"\n",
fn, map->addr);
r_cons_printf (".!rabin2 -rsB 0x%08"PFMT64x" '%s'\n",
map->addr, map->file);
//r_cons_printf ("fs-\n");
free (fn);
}
break;
2015-08-24 11:22:52 +00:00
case '.':
if (addr >= map->addr && addr < map->addr_end) {
r_cons_printf ("0x%08"PFMT64x" %s\n",
map->addr, map->file);
goto beach;
}
break;
case 'j':
r_cons_printf ("{\"address\":%"PFMT64d",\"name\":\"%s\",\"file\":\"%s\"}%s",
map->addr, map->name, map->file, iter->n?",":"");
break;
case '*':
{
char *fn = strdup (map->file);
r_name_filter (fn, 0);
//r_cons_printf ("fs+module_%s\n", fn);
2015-08-25 10:40:21 +00:00
r_cons_printf ("f mod.%s = 0x%08"PFMT64x"\n",
fn, map->addr);
r_cons_printf (".!rabin2 -rsB 0x%08"PFMT64x" '%s'\n",
map->addr, map->file);
//r_cons_printf ("fs-\n");
2015-08-25 10:40:21 +00:00
free (fn);
}
break;
default:
r_list_free (list);
goto show_help;
/* not reached */
}
}
2015-08-24 11:22:52 +00:00
beach:
if (mode == 'j') {
r_cons_printf ("]\n");
}
r_list_free (list);
}
2016-07-05 20:48:48 +00:00
static void update_main_arena(RCore *core, ut64 m_arena, RHeap_MallocState *main_arena) {
r_core_read_at (core, m_arena, (ut8 *)main_arena, sizeof (RHeap_MallocState));
}
#define PRINTF_A(color, fmt , ...) r_cons_printf (color fmt Color_RESET, __VA_ARGS__)
#define PRINTF_GA(fmt, ...) PRINTF_A (Color_GREEN, fmt, __VA_ARGS__)
#define PRINTF_BA(fmt, ...) PRINTF_A (Color_BLUE, fmt, __VA_ARGS__)
#define PRINT_A(color, msg) r_cons_print (color msg Color_RESET)
#define PRINT_GA(msg) PRINT_A (Color_GREEN, msg)
#define PRINT_BA(msg) PRINT_A (Color_BLUE, msg)
static void print_main_arena(ut64 m_arena, RHeap_MallocState *main_arena) {
int i, offset;
PRINT_GA ("main_arena @ ");
PRINTF_BA ("0x%"PFMT64x"\n\n", (ut64)(size_t)m_arena);
PRINT_GA ("struct malloc_state main_arena {\n");
PRINT_GA (" mutex = ");
PRINTF_BA ("0x%x\n", (int)main_arena->mutex);
PRINT_GA (" flags = ");
PRINTF_BA ("0x%x\n", (int)main_arena->flags);
PRINT_GA (" fastbinsY = {");
for (i = 0; i < NFASTBINS; i++) {
PRINTF_BA ("0x%"PFMT64x, (ut64)(size_t)main_arena->fastbinsY[i]);
if (i < NFASTBINS - 1) {
PRINT_GA (",");
}
}
PRINT_GA ("}\n");
PRINT_GA (" top = ");
PRINTF_BA ("0x%"PFMT64x, (ut64)(size_t)main_arena->top);
PRINT_GA (",\n");
PRINT_GA (" last_remainder = ");
PRINTF_BA ("0x%"PFMT64x, (ut64)(size_t)main_arena->last_remainder);
PRINT_GA (",\n");
PRINT_GA (" bins {");
offset = (size_t)&main_arena->last_remainder - (size_t)&main_arena->mutex + sizeof (size_t);
for (i = 0; i < NBINS * 2 - 2; i += 2) {
if (i % 2 == 0) r_cons_print ("\n ");
if (!main_arena->bins[i]) {
PRINT_BA ("0x0 ");
PRINT_GA ("<repeats 254 times>");
break;
} else {
PRINTF_GA ("0x%"PFMT64x"->fd = ", (size_t)m_arena + (size_t)offset + sizeof (size_t) * i - sizeof (size_t) * 2);
PRINTF_BA ("0x%"PFMT64x, (ut64)(size_t)main_arena->bins[i]);
PRINT_GA (", ");
PRINTF_GA ("0x%"PFMT64x"->bk = ", (size_t)m_arena + (size_t)offset + sizeof (size_t) * i - sizeof (size_t) * 2);
PRINTF_BA ("0x%"PFMT64x, (ut64)(size_t)main_arena->bins[i + 1]);
PRINT_GA (", ");
}
}
PRINT_GA ("\n }\n");
PRINT_GA (" binmap = {");
for(i = 0; i < BINMAPSIZE; i++) {
PRINTF_BA ("0x%x", (int)main_arena->binmap[i]);
if (i < BINMAPSIZE - 1) {
PRINT_GA (",");
}
}
PRINT_GA ("}\n");
PRINT_GA (" next = ");
PRINTF_BA ("0x%"PFMT64x, (ut64)(size_t)main_arena->next);
PRINT_GA (",\n");
PRINT_GA (" next_free = ");
PRINTF_BA ("0x%"PFMT64x, (ut64)(size_t)main_arena->next_free);
PRINT_GA (",\n");
PRINT_GA (" system_mem = ");
PRINTF_BA ("0x%"PFMT64x, (ut64)(size_t)main_arena->system_mem);
PRINT_GA (",\n");
PRINT_GA (" max_system_mem = ");
PRINTF_BA ("0x%"PFMT64x, (ut64)(size_t)main_arena->max_system_mem);
PRINT_GA (",\n");
PRINT_GA ("}\n\n");
}
static ut64 get_vaddr_symbol(const char *path, const char *symname) {
RListIter *iter;
RBinSymbol *s;
RCore *core = r_core_new ();
RList * syms = NULL;
ut64 vaddr = 0LL;
if (!core) {
return UT64_MAX;
}
r_bin_load (core->bin, path, 0, 0, 0, -1, false);
syms = r_bin_get_symbols (core->bin);
if (!syms) {
return UT64_MAX;
}
r_list_foreach (syms, iter, s) {
if (strstr (s->name, symname)) {
vaddr = s->vaddr;
break;
}
}
r_core_free (core);
return vaddr;
}
static void get_hash_debug_file(const char *path, char *hash, int hash_len) {
RListIter *iter;
RBinSection *s;
RCore *core = r_core_new ();
RList * sects = NULL;
char buf[20] = {0};
int offset, err, i, j = 0;
if (!core) {
return;
}
r_bin_load (core->bin, path, 0, 0, 0, -1, false);
sects = r_bin_get_sections (core->bin);
if (!sects) {
goto out_error;
}
r_list_foreach (sects, iter, s) {
if (strstr (s->name, ".note.gnu.build-id")) {
err = r_io_read_at (core->io, s->vaddr + 16, (ut8 *) buf, 20);
if (!err) {
eprintf ("We couldn't read from memory\n");
goto out_error;
}
break;
}
}
for (i = 0; i < 20; i++) {
if (i <= 1) {
hash[i + 2 * j++] = (ut8) '/';
}
offset = j + 2 * i;
snprintf (hash + offset, hash_len - offset, "%02x", (ut8) buf[i]);
}
offset = j + 2 * i;
snprintf (hash + offset, hash_len - offset - strlen (".debug"), ".debug");
out_error:
r_core_free (core);
}
bool str_start_with(const char *ptr, const char *str) {
return !strncmp (ptr, str, (size_t)strlen (str));
}
static void r_resolve_main_arena(RCore *core, ut64 *m_arena) {
RDebugMap *map;
RListIter *iter;
const char *dir_dbg = "/usr/lib/debug";
const char *dir_build_id = "/.build-id";
const char *symname = "main_arena";
const char *libc_ver_end = NULL;
char hash[64] = {0}, path[1024] = {0};
char *custom_libc = NULL;
bool is_debug_file[2];
ut64 libc_addr = UT64_MAX;
if (!core || !core->dbg || !core->dbg->maps) return;
r_debug_map_sync (core->dbg);
r_list_foreach (core->dbg->maps, iter, map) {
if (strstr (map->name, "/libc-")) {
libc_addr = (SIZE_SZ == 4) ? (map->addr_end) : (map->addr);
libc_ver_end = map->name;
break;
}
}
if (!libc_ver_end) {
eprintf ("Warning: Is glibc mapped in memory? (see dm command)\n");
return;
}
is_debug_file[0] = str_start_with (libc_ver_end, "/usr/lib/");
is_debug_file[1] = str_start_with (libc_ver_end, "/lib/");
if (!is_debug_file[0] && !is_debug_file[1]) {
custom_libc = r_cons_input ("Is a custom library? (LD_PRELOAD=..) Enter full path glibc: ");
snprintf (path, sizeof (path), "%s", custom_libc);
free (custom_libc);
goto arena;
}
if (is_debug_file[0]) {
snprintf (path, sizeof (path), "%s", libc_ver_end);
goto arena;
}
if (is_debug_file[1] && r_file_is_directory ("/usr/lib/debug") && !r_file_is_directory ("/usr/lib/debug/.build-id")) {
snprintf (path, sizeof (path), "%s%s", dir_dbg, libc_ver_end);
}
if (is_debug_file[1] && r_file_is_directory ("/usr/lib/debug/.build-id")) {
get_hash_debug_file (libc_ver_end, hash, sizeof (hash));
libc_ver_end = hash;
snprintf (path, sizeof (path), "%s%s%s", dir_dbg, dir_build_id, libc_ver_end);
}
arena:
if (r_file_exists (path)) {
ut64 vaddr = get_vaddr_symbol (path, symname);
if (libc_addr != UT64_MAX && vaddr && vaddr != UT64_MAX) {
*m_arena = libc_addr + vaddr;
RHeap_MallocState *main_arena = R_NEW0 (RHeap_MallocState);
if (!main_arena) {
eprintf ("Warning: out of memory\n");
return;
}
update_main_arena (core, *m_arena, main_arena);
print_main_arena (*m_arena, main_arena);
free (main_arena);
} else {
eprintf ("Warning: virtual address of symbol main_arena could not be found. Is libc6-dbg installed?\n");
}
} else {
eprintf ("Warning: glibc library with symbol main_arena could not be found. Is libc6-dbg installed?\n");
}
}
static int cmd_debug_map_heap(RCore *core, const char *input) {
RHeap_MallocState *main_arena;
static ut64 m_arena = UT64_MAX;
const char* help_msg[] = {
"Usage:", "dmh", " # Memory map heap",
"dmha", "", "Struct Malloc State (main_arena)",
"dmh?", "", "Show map heap help",
NULL
};
switch (input[0]) {
case 'a': // "dmha"
if (m_arena == UT64_MAX) {
r_resolve_main_arena (core, &m_arena);
} else {
main_arena = R_NEW0 (RHeap_MallocState);
if (!main_arena) {
eprintf ("Warning: out of memory\n");
break;
}
update_main_arena (core, m_arena, main_arena);
print_main_arena (m_arena, main_arena);
free (main_arena);
}
break;
case '?':
r_core_cmd_help (core, help_msg);
break;
}
return true;
}
2012-02-27 01:40:27 +00:00
static int cmd_debug_map(RCore *core, const char *input) {
const char* help_msg[] = {
"Usage:", "dm", " # Memory maps commands",
"dm", "", "List memory maps of target process",
2015-10-13 15:18:20 +00:00
"dm=", "", "List memory maps of target process (ascii-art bars)",
"dm", " <address> <size>", "Allocate <size> bytes at <address> (anywhere if address is -1) in child process",
"dm.", "", "Show map name of current address",
"dm*", "", "List memmaps in radare commands",
"dm-", "<address>", "Deallocate memory map of <address>",
"dmd", "[a] [file]", "Dump current (all) debug map region to a file (from-to.dmp) (see Sd)",
"dmi", " [addr|libname] [symname]", "List symbols of target lib",
"dmi*", " [addr|libname] [symname]", "List symbols of target lib in radare commands",
"dmj", "", "List memmaps in JSON format",
"dml", " <file>", "Load contents of file into the current map region (see Sl)",
"dmm", "[j*]", "List modules (libraries, binaries loaded in memory)",
"dmp", " <address> <size> <perms>", "Change page at <address> with <size>, protection <perms> (rwx)",
"dms", " <id> <mapaddr>", "take memory snapshot",
"dms-", " <id> <mapaddr>", "restore memory snapshot",
2016-07-05 20:48:48 +00:00
"dmh", "", "Show map heap",
//"dm, " rw- esp 9K", "set 9KB of the stack as read+write (no exec)",
"TODO:", "", "map files in process memory. (dmf file @ [addr])",
NULL};
2012-02-27 01:40:27 +00:00
RListIter *iter;
RDebugMap *map;
ut64 addr = core->offset;
switch (input[0]) {
case 's':
Major rework to the native debugger (esp on Linux) (#5185) The major contribution here is completely re-worked breakpoint hit/recoil handling. This work fixes #4907 and lays the ground work for future native debugger improvements (multi-threading, etc). * Give a human friendly type to enums * Change many wait functions to return RDebugReasonType * Better return checking (from r_debug_reg_sync, r_bp_restore) * Optimized register synchronization * Lots of comments and whitespace changes * Improved inferior death detection Handle EXIT_PID events differently than DEAD process events * Move breakpoint/recoil handling to wait/cont/step Rather than handing breakpoint related things inside cmd_debug.c, do that inside the r_debug API functions. This seems like the most logical place for it to live since it should apply to just about any platform/architecture. This also centralizes calling into "cmd.bp" handling via the CoreBind callback. * Track how the caller wishes to continue It turns out that handling break point recoils is very complicated. The ptrace API on Linux returns SIGTRAP for just about every type of operation (not just breakpoints getting hit). Add the "recoil_mode" flag to indicate whether we are single-stepping or continuing and whether or not we are inside the recoil. * Proper handling for swstep=true Since r_debug_step_soft calls r_debug_continue, it's already hitting the recoil case there. Move the recoil handling from r_debug_step to r_debug_step_hard only. For the swstep=true case, special handling is required inside r_debug_recoil. By resetting all of the breakpoints except the one we just hit, we ensure we can step the original instruction and hit the new swstep breakpoint. Add a new bp function called r_bp_restore_except to do this. To make matters worse, we cannot use a BreakpointItem pointer because that leads to a use-after-free condition. Instead, we the breakpoint address instead. Now breakpoints should work regardless of the swtep setting. * Always call the recoil before continuing Some callers of r_debug_continue might not have ever inserted any breakpoints before. If we don't restore breakpoints before each call to the underlying continue we won't hit them. * Hide software step breakpoint events from the user When a breakpoint even happens due to a software-step, hide it from the user. They aren't really breakpoints as far as they are concerned. * Improve process exit handling on Linux There are three types of process exiting events on Linux: 1. PTRACE_EVENT_EXIT occurs just before a process exits. It's not possible to prevent it from exiting, but it can be used to inspect the pre-exit state. 2. The process can exit for a variety of reasons and we can notice when we call waitpid(2). 3. The process could die randomly on us :-/ On Windows, h->wait will return R_DEBUG_REASON_EXIT_PID, but it's more likely on Linux to find out the process is already dead. * Check more bits within waitpid status We can often make a decision about what happened strictly by looking at the status returned from waitpid. In other cases, we need to call r_debug_handle_signals. If we reach the end of this function without knowing what happened, consider it an error.
2016-06-22 08:34:45 +00:00
cmd_debug_map_snapshot (core, input + 1);
break;
case '.':
r_list_foreach (core->dbg->maps, iter, map) {
if (addr >= map->addr && addr < map->addr_end) {
r_cons_println (map->name);
break;
}
}
break;
case 'm': // "dmm"
Major rework to the native debugger (esp on Linux) (#5185) The major contribution here is completely re-worked breakpoint hit/recoil handling. This work fixes #4907 and lays the ground work for future native debugger improvements (multi-threading, etc). * Give a human friendly type to enums * Change many wait functions to return RDebugReasonType * Better return checking (from r_debug_reg_sync, r_bp_restore) * Optimized register synchronization * Lots of comments and whitespace changes * Improved inferior death detection Handle EXIT_PID events differently than DEAD process events * Move breakpoint/recoil handling to wait/cont/step Rather than handing breakpoint related things inside cmd_debug.c, do that inside the r_debug API functions. This seems like the most logical place for it to live since it should apply to just about any platform/architecture. This also centralizes calling into "cmd.bp" handling via the CoreBind callback. * Track how the caller wishes to continue It turns out that handling break point recoils is very complicated. The ptrace API on Linux returns SIGTRAP for just about every type of operation (not just breakpoints getting hit). Add the "recoil_mode" flag to indicate whether we are single-stepping or continuing and whether or not we are inside the recoil. * Proper handling for swstep=true Since r_debug_step_soft calls r_debug_continue, it's already hitting the recoil case there. Move the recoil handling from r_debug_step to r_debug_step_hard only. For the swstep=true case, special handling is required inside r_debug_recoil. By resetting all of the breakpoints except the one we just hit, we ensure we can step the original instruction and hit the new swstep breakpoint. Add a new bp function called r_bp_restore_except to do this. To make matters worse, we cannot use a BreakpointItem pointer because that leads to a use-after-free condition. Instead, we the breakpoint address instead. Now breakpoints should work regardless of the swtep setting. * Always call the recoil before continuing Some callers of r_debug_continue might not have ever inserted any breakpoints before. If we don't restore breakpoints before each call to the underlying continue we won't hit them. * Hide software step breakpoint events from the user When a breakpoint even happens due to a software-step, hide it from the user. They aren't really breakpoints as far as they are concerned. * Improve process exit handling on Linux There are three types of process exiting events on Linux: 1. PTRACE_EVENT_EXIT occurs just before a process exits. It's not possible to prevent it from exiting, but it can be used to inspect the pre-exit state. 2. The process can exit for a variety of reasons and we can notice when we call waitpid(2). 3. The process could die randomly on us :-/ On Windows, h->wait will return R_DEBUG_REASON_EXIT_PID, but it's more likely on Linux to find out the process is already dead. * Check more bits within waitpid status We can often make a decision about what happened strictly by looking at the status returned from waitpid. In other cases, we need to call r_debug_handle_signals. If we reach the end of this function without knowing what happened, consider it an error.
2016-06-22 08:34:45 +00:00
if (!strcmp (input + 1, ".*")) {
cmd_debug_modules (core, ':');
} else cmd_debug_modules (core, input[1]);
break;
case '?':
r_core_cmd_help (core, help_msg);
2012-02-27 01:40:27 +00:00
break;
case 'p': // "dmp"
2012-02-27 01:40:27 +00:00
if (input[1] == ' ') {
int perms;
char *p, *q;
ut64 size, addr;
Major rework to the native debugger (esp on Linux) (#5185) The major contribution here is completely re-worked breakpoint hit/recoil handling. This work fixes #4907 and lays the ground work for future native debugger improvements (multi-threading, etc). * Give a human friendly type to enums * Change many wait functions to return RDebugReasonType * Better return checking (from r_debug_reg_sync, r_bp_restore) * Optimized register synchronization * Lots of comments and whitespace changes * Improved inferior death detection Handle EXIT_PID events differently than DEAD process events * Move breakpoint/recoil handling to wait/cont/step Rather than handing breakpoint related things inside cmd_debug.c, do that inside the r_debug API functions. This seems like the most logical place for it to live since it should apply to just about any platform/architecture. This also centralizes calling into "cmd.bp" handling via the CoreBind callback. * Track how the caller wishes to continue It turns out that handling break point recoils is very complicated. The ptrace API on Linux returns SIGTRAP for just about every type of operation (not just breakpoints getting hit). Add the "recoil_mode" flag to indicate whether we are single-stepping or continuing and whether or not we are inside the recoil. * Proper handling for swstep=true Since r_debug_step_soft calls r_debug_continue, it's already hitting the recoil case there. Move the recoil handling from r_debug_step to r_debug_step_hard only. For the swstep=true case, special handling is required inside r_debug_recoil. By resetting all of the breakpoints except the one we just hit, we ensure we can step the original instruction and hit the new swstep breakpoint. Add a new bp function called r_bp_restore_except to do this. To make matters worse, we cannot use a BreakpointItem pointer because that leads to a use-after-free condition. Instead, we the breakpoint address instead. Now breakpoints should work regardless of the swtep setting. * Always call the recoil before continuing Some callers of r_debug_continue might not have ever inserted any breakpoints before. If we don't restore breakpoints before each call to the underlying continue we won't hit them. * Hide software step breakpoint events from the user When a breakpoint even happens due to a software-step, hide it from the user. They aren't really breakpoints as far as they are concerned. * Improve process exit handling on Linux There are three types of process exiting events on Linux: 1. PTRACE_EVENT_EXIT occurs just before a process exits. It's not possible to prevent it from exiting, but it can be used to inspect the pre-exit state. 2. The process can exit for a variety of reasons and we can notice when we call waitpid(2). 3. The process could die randomly on us :-/ On Windows, h->wait will return R_DEBUG_REASON_EXIT_PID, but it's more likely on Linux to find out the process is already dead. * Check more bits within waitpid status We can often make a decision about what happened strictly by looking at the status returned from waitpid. In other cases, we need to call r_debug_handle_signals. If we reach the end of this function without knowing what happened, consider it an error.
2016-06-22 08:34:45 +00:00
p = strchr (input + 2, ' ');
2012-02-27 01:40:27 +00:00
if (p) {
*p++ = 0;
q = strchr (p, ' ');
if (q) {
*q++ = 0;
Major rework to the native debugger (esp on Linux) (#5185) The major contribution here is completely re-worked breakpoint hit/recoil handling. This work fixes #4907 and lays the ground work for future native debugger improvements (multi-threading, etc). * Give a human friendly type to enums * Change many wait functions to return RDebugReasonType * Better return checking (from r_debug_reg_sync, r_bp_restore) * Optimized register synchronization * Lots of comments and whitespace changes * Improved inferior death detection Handle EXIT_PID events differently than DEAD process events * Move breakpoint/recoil handling to wait/cont/step Rather than handing breakpoint related things inside cmd_debug.c, do that inside the r_debug API functions. This seems like the most logical place for it to live since it should apply to just about any platform/architecture. This also centralizes calling into "cmd.bp" handling via the CoreBind callback. * Track how the caller wishes to continue It turns out that handling break point recoils is very complicated. The ptrace API on Linux returns SIGTRAP for just about every type of operation (not just breakpoints getting hit). Add the "recoil_mode" flag to indicate whether we are single-stepping or continuing and whether or not we are inside the recoil. * Proper handling for swstep=true Since r_debug_step_soft calls r_debug_continue, it's already hitting the recoil case there. Move the recoil handling from r_debug_step to r_debug_step_hard only. For the swstep=true case, special handling is required inside r_debug_recoil. By resetting all of the breakpoints except the one we just hit, we ensure we can step the original instruction and hit the new swstep breakpoint. Add a new bp function called r_bp_restore_except to do this. To make matters worse, we cannot use a BreakpointItem pointer because that leads to a use-after-free condition. Instead, we the breakpoint address instead. Now breakpoints should work regardless of the swtep setting. * Always call the recoil before continuing Some callers of r_debug_continue might not have ever inserted any breakpoints before. If we don't restore breakpoints before each call to the underlying continue we won't hit them. * Hide software step breakpoint events from the user When a breakpoint even happens due to a software-step, hide it from the user. They aren't really breakpoints as far as they are concerned. * Improve process exit handling on Linux There are three types of process exiting events on Linux: 1. PTRACE_EVENT_EXIT occurs just before a process exits. It's not possible to prevent it from exiting, but it can be used to inspect the pre-exit state. 2. The process can exit for a variety of reasons and we can notice when we call waitpid(2). 3. The process could die randomly on us :-/ On Windows, h->wait will return R_DEBUG_REASON_EXIT_PID, but it's more likely on Linux to find out the process is already dead. * Check more bits within waitpid status We can often make a decision about what happened strictly by looking at the status returned from waitpid. In other cases, we need to call r_debug_handle_signals. If we reach the end of this function without knowing what happened, consider it an error.
2016-06-22 08:34:45 +00:00
addr = r_num_math (core->num, input + 2);
2012-02-27 01:40:27 +00:00
size = r_num_math (core->num, p);
perms = r_str_rwx (q);
Major rework to the native debugger (esp on Linux) (#5185) The major contribution here is completely re-worked breakpoint hit/recoil handling. This work fixes #4907 and lays the ground work for future native debugger improvements (multi-threading, etc). * Give a human friendly type to enums * Change many wait functions to return RDebugReasonType * Better return checking (from r_debug_reg_sync, r_bp_restore) * Optimized register synchronization * Lots of comments and whitespace changes * Improved inferior death detection Handle EXIT_PID events differently than DEAD process events * Move breakpoint/recoil handling to wait/cont/step Rather than handing breakpoint related things inside cmd_debug.c, do that inside the r_debug API functions. This seems like the most logical place for it to live since it should apply to just about any platform/architecture. This also centralizes calling into "cmd.bp" handling via the CoreBind callback. * Track how the caller wishes to continue It turns out that handling break point recoils is very complicated. The ptrace API on Linux returns SIGTRAP for just about every type of operation (not just breakpoints getting hit). Add the "recoil_mode" flag to indicate whether we are single-stepping or continuing and whether or not we are inside the recoil. * Proper handling for swstep=true Since r_debug_step_soft calls r_debug_continue, it's already hitting the recoil case there. Move the recoil handling from r_debug_step to r_debug_step_hard only. For the swstep=true case, special handling is required inside r_debug_recoil. By resetting all of the breakpoints except the one we just hit, we ensure we can step the original instruction and hit the new swstep breakpoint. Add a new bp function called r_bp_restore_except to do this. To make matters worse, we cannot use a BreakpointItem pointer because that leads to a use-after-free condition. Instead, we the breakpoint address instead. Now breakpoints should work regardless of the swtep setting. * Always call the recoil before continuing Some callers of r_debug_continue might not have ever inserted any breakpoints before. If we don't restore breakpoints before each call to the underlying continue we won't hit them. * Hide software step breakpoint events from the user When a breakpoint even happens due to a software-step, hide it from the user. They aren't really breakpoints as far as they are concerned. * Improve process exit handling on Linux There are three types of process exiting events on Linux: 1. PTRACE_EVENT_EXIT occurs just before a process exits. It's not possible to prevent it from exiting, but it can be used to inspect the pre-exit state. 2. The process can exit for a variety of reasons and we can notice when we call waitpid(2). 3. The process could die randomly on us :-/ On Windows, h->wait will return R_DEBUG_REASON_EXIT_PID, but it's more likely on Linux to find out the process is already dead. * Check more bits within waitpid status We can often make a decision about what happened strictly by looking at the status returned from waitpid. In other cases, we need to call r_debug_handle_signals. If we reach the end of this function without knowing what happened, consider it an error.
2016-06-22 08:34:45 +00:00
eprintf ("(%s)(%s)(%s)\n", input + 2, p, q);
2012-02-27 01:40:27 +00:00
eprintf ("0x%08"PFMT64x" %d %o\n", addr, (int) size, perms);
r_debug_map_protect (core->dbg, addr, size, perms);
} else eprintf ("See dmp?\n");
} else eprintf ("See dmp?\n");
} else eprintf ("See dmp?\n");
2012-02-27 01:40:27 +00:00
break;
case 'd':
switch (input[1]) {
case 'a': return dump_maps (core, 0, NULL);
case 'w': return dump_maps (core, R_IO_RW, NULL);
Major rework to the native debugger (esp on Linux) (#5185) The major contribution here is completely re-worked breakpoint hit/recoil handling. This work fixes #4907 and lays the ground work for future native debugger improvements (multi-threading, etc). * Give a human friendly type to enums * Change many wait functions to return RDebugReasonType * Better return checking (from r_debug_reg_sync, r_bp_restore) * Optimized register synchronization * Lots of comments and whitespace changes * Improved inferior death detection Handle EXIT_PID events differently than DEAD process events * Move breakpoint/recoil handling to wait/cont/step Rather than handing breakpoint related things inside cmd_debug.c, do that inside the r_debug API functions. This seems like the most logical place for it to live since it should apply to just about any platform/architecture. This also centralizes calling into "cmd.bp" handling via the CoreBind callback. * Track how the caller wishes to continue It turns out that handling break point recoils is very complicated. The ptrace API on Linux returns SIGTRAP for just about every type of operation (not just breakpoints getting hit). Add the "recoil_mode" flag to indicate whether we are single-stepping or continuing and whether or not we are inside the recoil. * Proper handling for swstep=true Since r_debug_step_soft calls r_debug_continue, it's already hitting the recoil case there. Move the recoil handling from r_debug_step to r_debug_step_hard only. For the swstep=true case, special handling is required inside r_debug_recoil. By resetting all of the breakpoints except the one we just hit, we ensure we can step the original instruction and hit the new swstep breakpoint. Add a new bp function called r_bp_restore_except to do this. To make matters worse, we cannot use a BreakpointItem pointer because that leads to a use-after-free condition. Instead, we the breakpoint address instead. Now breakpoints should work regardless of the swtep setting. * Always call the recoil before continuing Some callers of r_debug_continue might not have ever inserted any breakpoints before. If we don't restore breakpoints before each call to the underlying continue we won't hit them. * Hide software step breakpoint events from the user When a breakpoint even happens due to a software-step, hide it from the user. They aren't really breakpoints as far as they are concerned. * Improve process exit handling on Linux There are three types of process exiting events on Linux: 1. PTRACE_EVENT_EXIT occurs just before a process exits. It's not possible to prevent it from exiting, but it can be used to inspect the pre-exit state. 2. The process can exit for a variety of reasons and we can notice when we call waitpid(2). 3. The process could die randomly on us :-/ On Windows, h->wait will return R_DEBUG_REASON_EXIT_PID, but it's more likely on Linux to find out the process is already dead. * Check more bits within waitpid status We can often make a decision about what happened strictly by looking at the status returned from waitpid. In other cases, we need to call r_debug_handle_signals. If we reach the end of this function without knowing what happened, consider it an error.
2016-06-22 08:34:45 +00:00
case ' ': return dump_maps (core, -1, input + 2);
case 0: return dump_maps (core, -1, NULL);
case '?':
default:
eprintf ("Usage: dmd[aw] - dump (all-or-writable) debug maps\n");
break;
2012-02-27 01:40:27 +00:00
}
2015-07-24 23:34:58 +00:00
break;
2012-02-27 01:40:27 +00:00
case 'l':
if (input[1] != ' ') {
eprintf ("Usage: dml [file]\n");
2015-09-14 10:35:38 +00:00
return false;
2012-02-27 01:40:27 +00:00
}
r_debug_map_sync (core->dbg); // update process memory maps
r_list_foreach (core->dbg->maps, iter, map) {
if (addr >= map->addr && addr < map->addr_end) {
int sz;
Major rework to the native debugger (esp on Linux) (#5185) The major contribution here is completely re-worked breakpoint hit/recoil handling. This work fixes #4907 and lays the ground work for future native debugger improvements (multi-threading, etc). * Give a human friendly type to enums * Change many wait functions to return RDebugReasonType * Better return checking (from r_debug_reg_sync, r_bp_restore) * Optimized register synchronization * Lots of comments and whitespace changes * Improved inferior death detection Handle EXIT_PID events differently than DEAD process events * Move breakpoint/recoil handling to wait/cont/step Rather than handing breakpoint related things inside cmd_debug.c, do that inside the r_debug API functions. This seems like the most logical place for it to live since it should apply to just about any platform/architecture. This also centralizes calling into "cmd.bp" handling via the CoreBind callback. * Track how the caller wishes to continue It turns out that handling break point recoils is very complicated. The ptrace API on Linux returns SIGTRAP for just about every type of operation (not just breakpoints getting hit). Add the "recoil_mode" flag to indicate whether we are single-stepping or continuing and whether or not we are inside the recoil. * Proper handling for swstep=true Since r_debug_step_soft calls r_debug_continue, it's already hitting the recoil case there. Move the recoil handling from r_debug_step to r_debug_step_hard only. For the swstep=true case, special handling is required inside r_debug_recoil. By resetting all of the breakpoints except the one we just hit, we ensure we can step the original instruction and hit the new swstep breakpoint. Add a new bp function called r_bp_restore_except to do this. To make matters worse, we cannot use a BreakpointItem pointer because that leads to a use-after-free condition. Instead, we the breakpoint address instead. Now breakpoints should work regardless of the swtep setting. * Always call the recoil before continuing Some callers of r_debug_continue might not have ever inserted any breakpoints before. If we don't restore breakpoints before each call to the underlying continue we won't hit them. * Hide software step breakpoint events from the user When a breakpoint even happens due to a software-step, hide it from the user. They aren't really breakpoints as far as they are concerned. * Improve process exit handling on Linux There are three types of process exiting events on Linux: 1. PTRACE_EVENT_EXIT occurs just before a process exits. It's not possible to prevent it from exiting, but it can be used to inspect the pre-exit state. 2. The process can exit for a variety of reasons and we can notice when we call waitpid(2). 3. The process could die randomly on us :-/ On Windows, h->wait will return R_DEBUG_REASON_EXIT_PID, but it's more likely on Linux to find out the process is already dead. * Check more bits within waitpid status We can often make a decision about what happened strictly by looking at the status returned from waitpid. In other cases, we need to call r_debug_handle_signals. If we reach the end of this function without knowing what happened, consider it an error.
2016-06-22 08:34:45 +00:00
char *buf = r_file_slurp (input + 2, &sz);
//TODO: use mmap here. we need a portable implementation
2012-02-27 01:40:27 +00:00
if (!buf) {
eprintf ("Cannot allocate 0x%08"PFMT64x" bytes\n", map->size);
2015-09-14 10:35:38 +00:00
return false;
2012-02-27 01:40:27 +00:00
}
r_io_write_at (core->io, map->addr, (const ut8*)buf, sz);
if (sz != map->size)
eprintf ("File size differs from region size (%d vs %"PFMT64d")\n",
sz, map->size);
eprintf ("Loaded %d bytes into the map region at 0x%08"PFMT64x"\n",
sz, map->addr);
free (buf);
2015-09-14 10:35:38 +00:00
return true;
2012-02-27 01:40:27 +00:00
}
}
eprintf ("No debug region found here\n");
2015-09-14 10:35:38 +00:00
return false;
2015-11-15 00:06:42 +00:00
case 'i': // "dmi"
2012-02-27 01:40:27 +00:00
{ // Move to a separate function
RCoreBinFilter filter;
2015-11-15 00:06:42 +00:00
const char *libname = NULL, *symname = NULL, *mode = "";
ut64 baddr = 0LL;
char *ptr;
2012-02-27 01:40:27 +00:00
int i;
2015-11-15 00:06:42 +00:00
if (input[1]=='*') {
Major rework to the native debugger (esp on Linux) (#5185) The major contribution here is completely re-worked breakpoint hit/recoil handling. This work fixes #4907 and lays the ground work for future native debugger improvements (multi-threading, etc). * Give a human friendly type to enums * Change many wait functions to return RDebugReasonType * Better return checking (from r_debug_reg_sync, r_bp_restore) * Optimized register synchronization * Lots of comments and whitespace changes * Improved inferior death detection Handle EXIT_PID events differently than DEAD process events * Move breakpoint/recoil handling to wait/cont/step Rather than handing breakpoint related things inside cmd_debug.c, do that inside the r_debug API functions. This seems like the most logical place for it to live since it should apply to just about any platform/architecture. This also centralizes calling into "cmd.bp" handling via the CoreBind callback. * Track how the caller wishes to continue It turns out that handling break point recoils is very complicated. The ptrace API on Linux returns SIGTRAP for just about every type of operation (not just breakpoints getting hit). Add the "recoil_mode" flag to indicate whether we are single-stepping or continuing and whether or not we are inside the recoil. * Proper handling for swstep=true Since r_debug_step_soft calls r_debug_continue, it's already hitting the recoil case there. Move the recoil handling from r_debug_step to r_debug_step_hard only. For the swstep=true case, special handling is required inside r_debug_recoil. By resetting all of the breakpoints except the one we just hit, we ensure we can step the original instruction and hit the new swstep breakpoint. Add a new bp function called r_bp_restore_except to do this. To make matters worse, we cannot use a BreakpointItem pointer because that leads to a use-after-free condition. Instead, we the breakpoint address instead. Now breakpoints should work regardless of the swtep setting. * Always call the recoil before continuing Some callers of r_debug_continue might not have ever inserted any breakpoints before. If we don't restore breakpoints before each call to the underlying continue we won't hit them. * Hide software step breakpoint events from the user When a breakpoint even happens due to a software-step, hide it from the user. They aren't really breakpoints as far as they are concerned. * Improve process exit handling on Linux There are three types of process exiting events on Linux: 1. PTRACE_EVENT_EXIT occurs just before a process exits. It's not possible to prevent it from exiting, but it can be used to inspect the pre-exit state. 2. The process can exit for a variety of reasons and we can notice when we call waitpid(2). 3. The process could die randomly on us :-/ On Windows, h->wait will return R_DEBUG_REASON_EXIT_PID, but it's more likely on Linux to find out the process is already dead. * Check more bits within waitpid status We can often make a decision about what happened strictly by looking at the status returned from waitpid. In other cases, we need to call r_debug_handle_signals. If we reach the end of this function without knowing what happened, consider it an error.
2016-06-22 08:34:45 +00:00
ptr = strdup (r_str_trim_head ((char*)input + 2));
2015-11-15 00:06:42 +00:00
mode = "-r ";
} else {
2016-07-05 20:48:48 +00:00
ptr = strdup (r_str_trim_head ((char*)input + 1));
2015-11-15 00:06:42 +00:00
}
2012-02-27 01:40:27 +00:00
i = r_str_word_set0 (ptr);
switch (i) {
case 2: // get symname
symname = r_str_word_get0 (ptr, 1);
case 1: // get addr|libname
addr = r_num_math (core->num, r_str_word_get0 (ptr, 0));
if (!addr) libname = r_str_word_get0 (ptr, 0);
2015-11-15 00:06:42 +00:00
break;
2012-02-27 01:40:27 +00:00
}
r_debug_map_sync (core->dbg); // update process memory maps
r_list_foreach (core->dbg->maps, iter, map) {
if (core->bin &&
((addr != -1 && (addr >= map->addr && addr < map->addr_end)) ||
(libname != NULL && (strstr (map->name, libname))))) {
2012-02-27 01:40:27 +00:00
filter.offset = 0LL;
filter.name = (char *)symname;
baddr = r_bin_get_baddr (core->bin);
2015-11-15 00:06:42 +00:00
if (libname) {
char *cmd, *res;
if (symname) {
cmd = r_str_newf ("rabin2 %s-B 0x%08"PFMT64x" -s %s | grep %s", mode, baddr, map->name, symname);
} else {
cmd = r_str_newf ("rabin2 %s-B 0x%08"PFMT64x" -s %s", mode, baddr, map->name);
}
res = r_sys_cmd_str (cmd, NULL, NULL);
2016-07-05 20:48:48 +00:00
r_cons_println (res);
2015-11-15 00:06:42 +00:00
free (res);
free (cmd);
} else {
r_bin_set_baddr (core->bin, map->addr);
r_core_bin_info (core, R_CORE_BIN_ACC_SYMBOLS, (input[1]=='*'), true, &filter, NULL);
r_bin_set_baddr (core->bin, baddr);
}
2012-02-27 01:40:27 +00:00
break;
}
}
free (ptr);
}
break;
case ' ':
{
char *p;
int size;
Major rework to the native debugger (esp on Linux) (#5185) The major contribution here is completely re-worked breakpoint hit/recoil handling. This work fixes #4907 and lays the ground work for future native debugger improvements (multi-threading, etc). * Give a human friendly type to enums * Change many wait functions to return RDebugReasonType * Better return checking (from r_debug_reg_sync, r_bp_restore) * Optimized register synchronization * Lots of comments and whitespace changes * Improved inferior death detection Handle EXIT_PID events differently than DEAD process events * Move breakpoint/recoil handling to wait/cont/step Rather than handing breakpoint related things inside cmd_debug.c, do that inside the r_debug API functions. This seems like the most logical place for it to live since it should apply to just about any platform/architecture. This also centralizes calling into "cmd.bp" handling via the CoreBind callback. * Track how the caller wishes to continue It turns out that handling break point recoils is very complicated. The ptrace API on Linux returns SIGTRAP for just about every type of operation (not just breakpoints getting hit). Add the "recoil_mode" flag to indicate whether we are single-stepping or continuing and whether or not we are inside the recoil. * Proper handling for swstep=true Since r_debug_step_soft calls r_debug_continue, it's already hitting the recoil case there. Move the recoil handling from r_debug_step to r_debug_step_hard only. For the swstep=true case, special handling is required inside r_debug_recoil. By resetting all of the breakpoints except the one we just hit, we ensure we can step the original instruction and hit the new swstep breakpoint. Add a new bp function called r_bp_restore_except to do this. To make matters worse, we cannot use a BreakpointItem pointer because that leads to a use-after-free condition. Instead, we the breakpoint address instead. Now breakpoints should work regardless of the swtep setting. * Always call the recoil before continuing Some callers of r_debug_continue might not have ever inserted any breakpoints before. If we don't restore breakpoints before each call to the underlying continue we won't hit them. * Hide software step breakpoint events from the user When a breakpoint even happens due to a software-step, hide it from the user. They aren't really breakpoints as far as they are concerned. * Improve process exit handling on Linux There are three types of process exiting events on Linux: 1. PTRACE_EVENT_EXIT occurs just before a process exits. It's not possible to prevent it from exiting, but it can be used to inspect the pre-exit state. 2. The process can exit for a variety of reasons and we can notice when we call waitpid(2). 3. The process could die randomly on us :-/ On Windows, h->wait will return R_DEBUG_REASON_EXIT_PID, but it's more likely on Linux to find out the process is already dead. * Check more bits within waitpid status We can often make a decision about what happened strictly by looking at the status returned from waitpid. In other cases, we need to call r_debug_handle_signals. If we reach the end of this function without knowing what happened, consider it an error.
2016-06-22 08:34:45 +00:00
p = strchr (input + 2, ' ');
if (p) {
*p++ = 0;
Major rework to the native debugger (esp on Linux) (#5185) The major contribution here is completely re-worked breakpoint hit/recoil handling. This work fixes #4907 and lays the ground work for future native debugger improvements (multi-threading, etc). * Give a human friendly type to enums * Change many wait functions to return RDebugReasonType * Better return checking (from r_debug_reg_sync, r_bp_restore) * Optimized register synchronization * Lots of comments and whitespace changes * Improved inferior death detection Handle EXIT_PID events differently than DEAD process events * Move breakpoint/recoil handling to wait/cont/step Rather than handing breakpoint related things inside cmd_debug.c, do that inside the r_debug API functions. This seems like the most logical place for it to live since it should apply to just about any platform/architecture. This also centralizes calling into "cmd.bp" handling via the CoreBind callback. * Track how the caller wishes to continue It turns out that handling break point recoils is very complicated. The ptrace API on Linux returns SIGTRAP for just about every type of operation (not just breakpoints getting hit). Add the "recoil_mode" flag to indicate whether we are single-stepping or continuing and whether or not we are inside the recoil. * Proper handling for swstep=true Since r_debug_step_soft calls r_debug_continue, it's already hitting the recoil case there. Move the recoil handling from r_debug_step to r_debug_step_hard only. For the swstep=true case, special handling is required inside r_debug_recoil. By resetting all of the breakpoints except the one we just hit, we ensure we can step the original instruction and hit the new swstep breakpoint. Add a new bp function called r_bp_restore_except to do this. To make matters worse, we cannot use a BreakpointItem pointer because that leads to a use-after-free condition. Instead, we the breakpoint address instead. Now breakpoints should work regardless of the swtep setting. * Always call the recoil before continuing Some callers of r_debug_continue might not have ever inserted any breakpoints before. If we don't restore breakpoints before each call to the underlying continue we won't hit them. * Hide software step breakpoint events from the user When a breakpoint even happens due to a software-step, hide it from the user. They aren't really breakpoints as far as they are concerned. * Improve process exit handling on Linux There are three types of process exiting events on Linux: 1. PTRACE_EVENT_EXIT occurs just before a process exits. It's not possible to prevent it from exiting, but it can be used to inspect the pre-exit state. 2. The process can exit for a variety of reasons and we can notice when we call waitpid(2). 3. The process could die randomly on us :-/ On Windows, h->wait will return R_DEBUG_REASON_EXIT_PID, but it's more likely on Linux to find out the process is already dead. * Check more bits within waitpid status We can often make a decision about what happened strictly by looking at the status returned from waitpid. In other cases, we need to call r_debug_handle_signals. If we reach the end of this function without knowing what happened, consider it an error.
2016-06-22 08:34:45 +00:00
addr = r_num_math (core->num, input + 1);
size = r_num_math (core->num, p);
r_debug_map_alloc(core->dbg, addr, size);
} else {
eprintf ("Usage: dm addr size\n");
2015-09-14 10:35:38 +00:00
return false;
}
}
break;
case '-':
if (input[1] != ' ') {
eprintf ("|ERROR| Usage: dm- [addr]\n");
break;
}
Major rework to the native debugger (esp on Linux) (#5185) The major contribution here is completely re-worked breakpoint hit/recoil handling. This work fixes #4907 and lays the ground work for future native debugger improvements (multi-threading, etc). * Give a human friendly type to enums * Change many wait functions to return RDebugReasonType * Better return checking (from r_debug_reg_sync, r_bp_restore) * Optimized register synchronization * Lots of comments and whitespace changes * Improved inferior death detection Handle EXIT_PID events differently than DEAD process events * Move breakpoint/recoil handling to wait/cont/step Rather than handing breakpoint related things inside cmd_debug.c, do that inside the r_debug API functions. This seems like the most logical place for it to live since it should apply to just about any platform/architecture. This also centralizes calling into "cmd.bp" handling via the CoreBind callback. * Track how the caller wishes to continue It turns out that handling break point recoils is very complicated. The ptrace API on Linux returns SIGTRAP for just about every type of operation (not just breakpoints getting hit). Add the "recoil_mode" flag to indicate whether we are single-stepping or continuing and whether or not we are inside the recoil. * Proper handling for swstep=true Since r_debug_step_soft calls r_debug_continue, it's already hitting the recoil case there. Move the recoil handling from r_debug_step to r_debug_step_hard only. For the swstep=true case, special handling is required inside r_debug_recoil. By resetting all of the breakpoints except the one we just hit, we ensure we can step the original instruction and hit the new swstep breakpoint. Add a new bp function called r_bp_restore_except to do this. To make matters worse, we cannot use a BreakpointItem pointer because that leads to a use-after-free condition. Instead, we the breakpoint address instead. Now breakpoints should work regardless of the swtep setting. * Always call the recoil before continuing Some callers of r_debug_continue might not have ever inserted any breakpoints before. If we don't restore breakpoints before each call to the underlying continue we won't hit them. * Hide software step breakpoint events from the user When a breakpoint even happens due to a software-step, hide it from the user. They aren't really breakpoints as far as they are concerned. * Improve process exit handling on Linux There are three types of process exiting events on Linux: 1. PTRACE_EVENT_EXIT occurs just before a process exits. It's not possible to prevent it from exiting, but it can be used to inspect the pre-exit state. 2. The process can exit for a variety of reasons and we can notice when we call waitpid(2). 3. The process could die randomly on us :-/ On Windows, h->wait will return R_DEBUG_REASON_EXIT_PID, but it's more likely on Linux to find out the process is already dead. * Check more bits within waitpid status We can often make a decision about what happened strictly by looking at the status returned from waitpid. In other cases, we need to call r_debug_handle_signals. If we reach the end of this function without knowing what happened, consider it an error.
2016-06-22 08:34:45 +00:00
addr = r_num_math (core->num, input + 2);
r_list_foreach (core->dbg->maps, iter, map) {
if (addr >= map->addr && addr < map->addr_end) {
r_debug_map_dealloc(core->dbg, map);
r_debug_map_sync (core->dbg);
2015-09-14 10:35:38 +00:00
return true;
}
}
eprintf ("The address doesn't match with any map.\n");
break;
case '\0':
case '*':
case 'j':
2012-02-27 01:40:27 +00:00
r_debug_map_sync (core->dbg); // update process memory maps
r_debug_map_list (core->dbg, core->offset, input[0]);
2012-02-27 01:40:27 +00:00
break;
2015-10-13 15:18:20 +00:00
case '=':
r_debug_map_sync (core->dbg);
r_debug_map_list_visual (core->dbg, core->offset,
2016-06-06 15:30:07 +00:00
r_config_get_i (core->config, "scr.color"),
r_cons_get_size (NULL));
2015-10-13 15:18:20 +00:00
break;
2016-07-05 20:48:48 +00:00
case 'h': // "dmh"
#if __linux__ && __GNU_LIBRARY__ && __GLIBC__ && __GLIBC_MINOR__
cmd_debug_map_heap (core, input + 1);
#else
eprintf ("GLIBC not installed\n");
#endif
break;
2012-02-27 01:40:27 +00:00
}
2015-09-14 10:35:38 +00:00
return true;
2012-02-27 01:40:27 +00:00
}
R_API void r_core_debug_rr(RCore *core, RReg *reg) {
ut64 value;
int bits = core->assembler->bits;
RList *list = r_reg_get_list (reg, R_REG_TYPE_GPR);
RListIter *iter;
RRegItem *r;
r_debug_map_sync (core->dbg);
r_list_foreach (list, iter, r) {
char *rrstr;
2015-10-05 12:43:17 +00:00
if (r->size != bits) continue;
value = r_reg_get_value (core->dbg->reg, r);
2015-10-05 12:43:17 +00:00
rrstr = r_core_anal_hasrefs (core, value);
if (bits == 64) {
r_cons_printf ("%6s 0x%016"PFMT64x, r->name, value);
} else {
r_cons_printf ("%6s 0x%08"PFMT64x, r->name, value);
}
if (rrstr) {
r_cons_printf (" %s\n", rrstr);
free (rrstr);
}
}
}
static void cmd_reg_profile (RCore *core, int from, const char *str) { // "arp" and "drp"
switch (str[1]) {
case 0:
if (core->dbg->reg->reg_profile_str) {
//core->anal->reg = core->dbg->reg;
r_cons_println (core->dbg->reg->reg_profile_str);
//r_cons_printf ("%s\n", core->anal->reg->reg_profile);
} else eprintf ("No register profile defined. Try 'dr.'\n");
break;
case ' ':
r_reg_set_profile (core->dbg->reg, str+2);
break;
case '.':
{
RRegSet *rs = r_reg_regset_get (core->dbg->reg, R_REG_TYPE_GPR);
if (rs) {
eprintf ("size = %d\n", rs->arena->size);
}
}
break;
case 's':
if (str[2] == ' ') {
ut64 n = r_num_math (core->num, str+2);
2016-02-03 11:09:58 +00:00
// TODO: move this thing into the r_reg API
RRegSet *rs = r_reg_regset_get (core->dbg->reg, R_REG_TYPE_GPR);
if (rs && n>0) {
2016-02-03 11:09:58 +00:00
RListIter *iter;
RRegArena *arena;
r_list_foreach (rs->pool, iter, arena) {
ut8 *newbytes = calloc (1, n);
if (newbytes) {
free (arena->bytes);
arena->bytes = newbytes;
arena->size = n;
} else {
2016-02-03 11:29:32 +00:00
eprintf ("Cannot allocate %d\n", (int)n);
2016-02-03 11:09:58 +00:00
}
}
} else {
eprintf ("Invalid arena size\n");
}
} else {
RRegSet *rs = r_reg_regset_get (core->dbg->reg, R_REG_TYPE_GPR);
if (rs) {
r_cons_printf ("%d\n", rs->arena->size);
} else eprintf ("Cannot find GPR register arena.\n");
}
break;
case 'j':
{
// "drpj" .. dup from "arpj"
RListIter *iter;
RRegItem *r;
int i;
int first = 1;
r_cons_printf ("{\"alias_info\":[");
for (i = 0; i < R_REG_NAME_LAST; i++) {
if (core->dbg->reg->name[i]) {
if (!first) r_cons_printf (",");
r_cons_printf ("{\"role\":%d,", i);
r_cons_printf ("\"role_str\":\"%s\",",
r_reg_get_role (i));
r_cons_printf ("\"reg\":\"%s\"}",
core->dbg->reg->name[i]);
first = 0;
}
}
r_cons_printf ("],\"reg_info\":[");
first = 1;
for (i = 0; i < R_REG_TYPE_LAST; i++) {
r_list_foreach (core->dbg->reg->regset[i].regs, iter, r) {
if (!first) r_cons_printf (",");
r_cons_printf ("{\"type\":%d,", r->type);
r_cons_printf ("\"type_str\":\"%s\",",
r_reg_get_type (r->type));
r_cons_printf ("\"name\":\"%s\",", r->name);
r_cons_printf ("\"size\":%d,", r->size);
r_cons_printf ("\"offset\":%d}", r->offset);
first = 0;
}
}
r_cons_printf ("]}");
}
break;
case '?':
default:
{
const char *from_a[] = { "arp", "arp.", "arpj", "arps" };
const char *help_msg[] = {
"Usage:", "drp", " # Register profile commands",
"drp", "", "Show the current register profile",
"drp", " [regprofile-file]", "Set the current register profile",
"drp.", "", "Show the current fake size",
"drpj", "", "Show the current register profile (JSON)",
"drps", " [new fake size]", "Set the fake size",
NULL
};
if (from == 'a') {
help_msg[1] = help_msg[3] = help_msg[6] = from_a[0];
help_msg[9] = from_a[1];
help_msg[12] = from_a[2];
help_msg[15] = from_a[3];
}
r_core_cmd_help (core, help_msg);
break;
}
}
}
2012-02-27 01:40:27 +00:00
static void cmd_debug_reg(RCore *core, const char *str) {
2016-02-25 01:58:26 +00:00
char *arg;
struct r_reg_item_t *r;
const char *name, *use_color;
int size, i, type = R_REG_TYPE_GPR;
int bits = (core->dbg->bits & R_SYS_BITS_64)? 64: 32;
int use_colors = r_config_get_i (core->config, "scr.color");
if (use_colors) {
#undef ConsP
#define ConsP(x) (core->cons && core->cons->pal.x)? core->cons->pal.x
use_color = ConsP(creg): Color_BWHITE;
} else {
use_color = NULL;
}
2012-02-27 01:40:27 +00:00
switch (str[0]) {
case 'C': // "drC"
if (core->dbg->reg->reg_profile_cmt) {
r_cons_println (core->dbg->reg->reg_profile_cmt);
}
break;
2015-10-31 02:45:14 +00:00
case '-': // "dr-"
2014-07-31 18:53:18 +00:00
r_debug_reg_list (core->dbg, R_REG_TYPE_GPR, bits, '-', 0);
break;
2015-10-31 02:45:14 +00:00
case '?': // "dr?"
2012-02-27 01:40:27 +00:00
if (str[1]) {
const char *p = str+1;
2012-02-27 01:40:27 +00:00
ut64 off;
while (IS_WHITESPACE (*p)) p++;
2015-09-14 10:35:38 +00:00
r_debug_reg_sync (core->dbg, -1, 0); //R_REG_TYPE_GPR, false);
off = r_debug_reg_get (core->dbg, p);
2012-02-27 01:40:27 +00:00
// r = r_reg_get (core->dbg->reg, str+1, 0);
// if (r == NULL) eprintf ("Unknown register (%s)\n", str+1);
2014-05-03 23:41:32 +00:00
r_cons_printf ("0x%08"PFMT64x"\n", off);
core->num->value = off;
2012-02-27 01:40:27 +00:00
//r_reg_get_value (core->dbg->reg, r));
} else {
const char * help_message[] = {
"Usage: dr", "", "Registers commands",
"dr", "", "Show 'gpr' registers",
"dr", " <register>=<val>", "Set register value",
"dr=", "", "Show registers in columns",
2014-08-01 11:36:12 +00:00
"dr?", "<register>", "Show value of given register",
"drb", " [type]", "Display hexdump of gpr arena (WIP)",
"drC", "", "Show register profile comments",
"drc", " [name]", "Related to conditional flag registers",
"drd", "", "Show only different registers",
"drl", "", "List all register names",
"drn", " <pc>", "Get regname for pc,sp,bp,a0-3,zf,cf,of,sg",
"dro", "", "Show previous (old) values of registers",
"drp", " <file>", "Load register metadata file",
"drp", "", "Display current register profile",
2016-02-03 11:09:58 +00:00
"drps", "", "Fake register profile size",
"drr", "", "Show registers references (telescoping)",
2014-11-05 08:56:14 +00:00
"drs", " [?]", "Stack register states",
"drt", "", "Show all register types",
2015-08-23 12:46:25 +00:00
"drt", " flg", "Show flag registers",
"drt", " all", "Show all registers",
"drt", " 16", "Show 16 bit registers",
"drt", " 32", "Show 32 bit registers",
"drt", " 80", "Show 80 bit registers (long double)",
2014-11-05 08:56:14 +00:00
"drx", "", "Show all debug registers",
"drx", " idx addr len rwx", "Modify hardware breakpoint",
2014-11-05 08:56:14 +00:00
"drx-", "number", "Clear hardware breakpoint",
"drf","","show fpu registers (80 bit long double)",
"drm","","show multimedia packed registers",
"drm"," mmx0 0 32 = 12","set the first 32 bit word of the mmx reg to 12",
2016-03-29 18:56:43 +00:00
"drw"," <hexnum>", "Set contents of the register arena",
".dr", "*", "Include common register values in flags",
".dr", "-", "Unflag all registers",
NULL
};
// TODO: 'drs' to swap register arenas and display old register valuez
r_core_cmd_help (core, help_message);
}
2012-02-27 01:40:27 +00:00
break;
2015-10-31 02:45:14 +00:00
case 'l': // "drl"
//r_core_cmd0 (core, "drp~[1]");
{
RRegSet *rs = r_reg_regset_get (core->dbg->reg, R_REG_TYPE_GPR);
if (rs) {
RRegItem *r;
RListIter *iter;
r_list_foreach (rs->regs, iter, r) {
r_cons_println (r->name);
}
}
}
break;
2015-10-31 02:45:14 +00:00
case 'b': // "drb"
2012-02-27 01:40:27 +00:00
{ // WORK IN PROGRESS // DEBUG COMMAND
int len;
2016-04-10 21:16:57 +00:00
ut8 *buf = r_reg_get_bytes (core->dbg->reg, R_REG_TYPE_GPR, &len);
2012-02-27 01:40:27 +00:00
//r_print_hexdump (core->print, 0LL, buf, len, 16, 16);
r_print_hexdump (core->print, 0LL, buf, len, 32, 4);
2016-04-09 13:00:36 +00:00
free (buf);
2012-02-27 01:40:27 +00:00
}
break;
2015-10-31 02:45:14 +00:00
case 'c': // "drc"
// TODO: set flag values with drc zf=1
{
RRegItem *r;
const char *name = str+1;
while (*name==' ') name++;
if (*name && name[1]) {
r = r_reg_cond_get (core->dbg->reg, name);
if (r) {
r_cons_println (r->name);
} else {
int id = r_reg_cond_from_string (name);
RRegFlags* rf = r_reg_cond_retrieve (core->dbg->reg, NULL);
if (rf) {
int o = r_reg_cond_bits (core->dbg->reg, id, rf);
core->num->value = o;
// ORLY?
r_cons_printf ("%d\n", o);
free (rf);
} else eprintf ("unknown conditional or flag register\n");
}
} else {
RRegFlags *rf = r_reg_cond_retrieve (core->dbg->reg, NULL);
if (rf) {
r_cons_printf ("| s:%d z:%d c:%d o:%d p:%d\n",
rf->s, rf->z, rf->c, rf->o, rf->p);
if (*name=='=') {
for (i=0; i<R_REG_COND_LAST; i++) {
r_cons_printf ("%s:%d ",
r_reg_cond_to_string (i),
r_reg_cond_bits (core->dbg->reg, i, rf));
}
r_cons_newline ();
} else {
for (i=0; i<R_REG_COND_LAST; i++) {
r_cons_printf ("%d %s\n",
r_reg_cond_bits (core->dbg->reg, i, rf),
r_reg_cond_to_string (i));
}
}
free (rf);
}
}
}
break;
2015-10-31 02:45:14 +00:00
case 'x': // "drx"
switch (str[1]) {
case '\0':
r_debug_reg_sync (core->dbg, R_REG_TYPE_DRX, false);
r_debug_drx_list (core->dbg);
break;
case '-':
2015-09-14 10:35:38 +00:00
r_debug_reg_sync (core->dbg, R_REG_TYPE_DRX, false);
r_debug_drx_unset (core->dbg, atoi (str+2));
2015-09-14 10:35:38 +00:00
r_debug_reg_sync (core->dbg, R_REG_TYPE_DRX, true);
break;
case ' ': {
char *s = strdup (str+2);
char sl, n, rwx;
int len;
ut64 off;
sl = r_str_word_set0 (s);
if (sl == 4) {
#define ARG(x) r_str_word_get0(s,x)
n = (char)r_num_math (core->num, ARG(0));
off = r_num_math (core->num, ARG(1));
len = (int)r_num_math (core->num, ARG(2));
rwx = (char)r_str_rwx (ARG(3));
2014-01-12 03:31:04 +00:00
if (len== -1) {
2015-09-14 10:35:38 +00:00
r_debug_reg_sync (core->dbg, R_REG_TYPE_DRX, false);
2014-01-12 03:31:04 +00:00
r_debug_drx_set (core->dbg, n, 0, 0, 0, 0);
2015-09-14 10:35:38 +00:00
r_debug_reg_sync (core->dbg, R_REG_TYPE_DRX, true);
2014-01-12 03:31:04 +00:00
} else {
2015-09-14 10:35:38 +00:00
r_debug_reg_sync (core->dbg, R_REG_TYPE_DRX, false);
2014-01-12 03:31:04 +00:00
r_debug_drx_set (core->dbg, n, off, len, rwx, 0);
2015-09-14 10:35:38 +00:00
r_debug_reg_sync (core->dbg, R_REG_TYPE_DRX, true);
2014-01-12 03:31:04 +00:00
}
} else eprintf ("|Usage: drx N [address] [length] [rwx]\n");
free (s);
} break;
case '?':
default:
{
const char * help_message[] = {
"Usage: drx", "", "Hardware breakpoints commands",
"drx", "", "List all (x86?) hardware breakpoints",
"drx", " <number> <address> <length> <perms>", "Modify hardware breakpoint",
"drx-", "<number>", "Clear hardware breakpoint",
NULL
};
r_core_cmd_help (core, help_message);
}
break;
}
break;
case 's': // "drs"
switch (str[1]) {
case 0:
r_cons_printf ("%d\n", r_list_length (
core->dbg->reg->regset[0].pool));
break;
case '-':
r_reg_arena_pop (core->dbg->reg);
// restore debug registers if in debugger mode
r_debug_reg_sync (core->dbg, 0, 1);
break;
case '+':
r_reg_arena_push (core->dbg->reg);
break;
case '?':
default:
{
const char * help_message[] = {
"Usage: drs", "", "Register states commands",
"drs", "", "List register stack",
"drs", "+", "Push register state",
"drs", "-", "Pop register state",
NULL
};
r_core_cmd_help (core, help_message);
}
break;
}
break;
case 'm': // "drm"
if (str[1]=='?') {
eprintf ("Usage: drm [reg] [idx] [wordsize] [= value]\n");
} else if (str[1]==' ') {
int word = 0;
int size = 0; // auto
char *q, *p, *name = strdup (str+2);
char *eq = strchr (name, '=');
if (eq) {
*eq++ = 0;
}
p = strchr (name, ' ');
if (p) {
*p++ = 0;
q = strchr (p, ' ');
if (q) {
*q++ = 0;
size = r_num_math (core->num, q);
}
word = r_num_math (core->num, p);
}
RRegItem *item = r_reg_get (core->dbg->reg, name, -1);
if (item) {
if (eq) {
ut64 val = r_num_math (core->num, eq);
r_reg_set_pack (core->dbg->reg, item, word, size, val);
2015-09-14 10:35:38 +00:00
r_debug_reg_sync (core->dbg, R_REG_TYPE_GPR, true);
r_debug_reg_sync (core->dbg, R_REG_TYPE_MMX, true);
} else {
2015-09-14 10:35:38 +00:00
r_debug_reg_sync (core->dbg, R_REG_TYPE_GPR, false);
r_debug_reg_sync (core->dbg, R_REG_TYPE_MMX, false);
ut64 res = r_reg_get_pack (core->dbg->reg, item, word, size);
r_cons_printf ("0x%08"PFMT64x"\n", res);
}
} else {
eprintf ("Cannot find multimedia register '%s'\n", name);
}
free (name);
} else {
2015-09-14 10:35:38 +00:00
r_debug_reg_sync (core->dbg, -R_REG_TYPE_MMX, false);
}
//r_debug_drx_list (core->dbg);
break;
case 'f': // "drf"
/* Note, that negative type forces sync to print the regs from the backend */
2015-09-14 10:35:38 +00:00
r_debug_reg_sync (core->dbg, -R_REG_TYPE_FPU, false);
//r_debug_drx_list (core->dbg);
if (str[1]=='?') {
eprintf ("Usage: drf [fpureg] [= value]\n");
} else if (str[1]==' ') {
char *p, *name = strdup (str+2);
char *eq = strchr (name, '=');
if (eq) {
*eq++ = 0;
}
p = strchr (name, ' ');
if (p) {
*p++ = 0;
}
RRegItem *item = r_reg_get (core->dbg->reg, name, -1);
if (item) {
if (eq) {
long double val = 0.0f;
2015-10-08 09:14:10 +00:00
#if __WINDOWS__
double dval = 0.0f;
sscanf (eq, "%lf", (double*)&dval);
val = dval;
#else
sscanf (eq, "%Lf", &val);
2015-10-08 09:14:10 +00:00
#endif
r_reg_set_double (core->dbg->reg, item, val);
2015-09-14 10:35:38 +00:00
r_debug_reg_sync (core->dbg, R_REG_TYPE_GPR, true);
r_debug_reg_sync (core->dbg, R_REG_TYPE_FPU, true);
} else {
2015-09-14 10:35:38 +00:00
r_debug_reg_sync (core->dbg, R_REG_TYPE_GPR, false);
r_debug_reg_sync (core->dbg, R_REG_TYPE_FPU, false);
long double res = r_reg_get_double (core->dbg->reg, item);
r_cons_printf ("%Lf\n", res);
}
} else {
eprintf ("Cannot find multimedia register '%s'\n", name);
}
free (name);
} else {
2015-09-14 10:35:38 +00:00
r_debug_reg_sync (core->dbg, -R_REG_TYPE_FPU, false);
}
break;
case 'p': // "drp"
cmd_reg_profile (core, 'd', str);
2012-02-27 01:40:27 +00:00
break;
case 't': // "drt"
switch (str[1]) {
case 0:
for (i = 0; (name = r_reg_get_type (i)); i++) {
r_cons_println (name);
}
break;
case ' ':
{
int role = r_reg_get_name_idx (str+2);
const char *regname = r_reg_get_name (core->dbg->reg, role);
if (!regname)
regname = str+2;
size = atoi (regname);
if (size<1) {
char *arg = strchr (str+2, ' ');
size = -1;
if (arg) {
*arg++ = 0;
size = atoi (arg);
}
type = r_reg_type_by_name (str+2);
if (size < 0)
size = core->dbg->bits * 8;
2015-09-14 10:35:38 +00:00
r_debug_reg_sync (core->dbg, type, false);
r_debug_reg_list (core->dbg, type, size,
strchr (str,'*')? 1: 0, use_color);
} else {
if (type != R_REG_TYPE_LAST) {
2015-09-14 10:35:38 +00:00
r_debug_reg_sync (core->dbg, type, false);
r_debug_reg_list (core->dbg, type, size,
strchr (str,'*')?1:0, use_color);
} else eprintf ("cmd_debug_reg: Unknown type\n");
}
} break;
case '?':
default:
{
const char *help_msg[] = {
"Usage:", "drt", " [type] [size] # debug register types",
"drt", "", "List all available register types",
"drt", " [size]", "Show all regs in the profile of size",
"drt", " [type]", "Show all regs in the profile of this type",
"drt", " [type] [size]", "Same as above for type and size",
NULL};
r_core_cmd_help (core, help_msg);
}
break;
}
2012-02-27 01:40:27 +00:00
break;
2016-02-03 11:09:58 +00:00
case 'n': // "drn"
{
char *foo = strdup (str+2);
r_str_case (foo, true);
name = r_reg_get_name (core->dbg->reg, r_reg_get_name_idx (foo));
if (name && *name) {
r_cons_println (name);
2016-04-04 20:01:37 +00:00
} else eprintf ("Oops. try drn [PC|SP|BP|A0|A1|A2|A3|A4|R0|R1|ZF|SF|NF|OF]\n");
2016-02-03 11:09:58 +00:00
free (foo);
}
2012-02-27 01:40:27 +00:00
break;
case 'd':
r_debug_reg_list (core->dbg, R_REG_TYPE_GPR, bits, 3, use_color); // XXX detect which one is current usage
2012-02-27 01:40:27 +00:00
break;
case 'o':
2015-09-14 10:35:38 +00:00
r_reg_arena_swap (core->dbg->reg, false);
r_debug_reg_list (core->dbg, R_REG_TYPE_GPR, bits, 0, use_color); // XXX detect which one is current usage
2015-09-14 10:35:38 +00:00
r_reg_arena_swap (core->dbg->reg, false);
2012-02-27 01:40:27 +00:00
break;
2015-11-25 11:49:02 +00:00
case '=': // "dr="
{
int pcbits = 0;
{
const char *pcname = r_reg_get_name (core->anal->reg, R_REG_NAME_PC);
RRegItem *reg = r_reg_get (core->anal->reg, pcname, 0);
if (reg) {
if (core->assembler->bits != reg->size)
pcbits = reg->size;
}
}
if (r_config_get_i (core->config, "cfg.debug")) {
2015-09-14 10:35:38 +00:00
if (r_debug_reg_sync (core->dbg, R_REG_TYPE_GPR, false)) {
2015-11-25 11:49:02 +00:00
if (pcbits && pcbits != bits)
r_debug_reg_list (core->dbg, R_REG_TYPE_GPR, pcbits, 2, use_color); // XXX detect which one is current usage
r_debug_reg_list (core->dbg, R_REG_TYPE_GPR, bits, 2, use_color); // XXX detect which one is current usage
} //else eprintf ("Cannot retrieve registers from pid %d\n", core->dbg->pid);
} else {
RReg *orig = core->dbg->reg;
core->dbg->reg = core->anal->reg;
2015-11-25 11:49:02 +00:00
if (pcbits && pcbits != bits)
r_debug_reg_list (core->dbg, R_REG_TYPE_GPR, pcbits, 2, use_color); // XXX detect which one is current usage
r_debug_reg_list (core->dbg, R_REG_TYPE_GPR, bits, 2, use_color); // XXX detect which one is current usage
core->dbg->reg = orig;
}
}
2012-02-27 01:40:27 +00:00
break;
case '*':
2015-09-14 10:35:38 +00:00
if (r_debug_reg_sync (core->dbg, R_REG_TYPE_GPR, false)) {
int pcbits = core->anal->bits;
const char *pcname = r_reg_get_name (core->anal->reg, R_REG_NAME_PC);
RRegItem *reg = r_reg_get (core->anal->reg, pcname, 0);
if (reg) {
if (core->assembler->bits != reg->size)
pcbits = reg->size;
}
r_cons_printf ("fs+regs\n");
r_debug_reg_list (core->dbg, R_REG_TYPE_GPR, pcbits, '*', use_color);
r_flag_space_pop (core->flags);
r_cons_printf ("fs-\n");
}
2012-02-27 01:40:27 +00:00
break;
case 'r': // "drr"
r_core_debug_rr (core, core->dbg->reg);
break;
2012-12-23 17:34:30 +00:00
case 'j':
2012-02-27 01:40:27 +00:00
case '\0':
2015-09-14 10:35:38 +00:00
if (r_debug_reg_sync (core->dbg, R_REG_TYPE_GPR, false)) {
int pcbits = core->anal->bits;
const char *pcname = r_reg_get_name (core->anal->reg, R_REG_NAME_PC);
RRegItem *reg = r_reg_get (core->anal->reg, pcname, 0);
if (reg) {
if (core->assembler->bits != reg->size)
pcbits = reg->size;
}
r_debug_reg_list (core->dbg, R_REG_TYPE_GPR, pcbits, str[0], use_color);
} else eprintf ("Cannot retrieve registers from pid %d\n", core->dbg->pid);
2012-02-27 01:40:27 +00:00
break;
case ' ':
arg = strchr (str+1, '=');
if (arg) {
2014-09-11 02:44:55 +00:00
char *string;
2014-09-15 08:18:00 +00:00
const char *regname;
2012-02-27 01:40:27 +00:00
*arg = 0;
2014-09-11 02:44:55 +00:00
string = r_str_chop (strdup (str+1));
regname = r_reg_get_name (core->dbg->reg,
r_reg_get_name_idx (string));
2014-09-11 02:29:28 +00:00
if (!regname)
regname = string;
2014-09-11 02:29:28 +00:00
r = r_reg_get (core->dbg->reg, regname, -1); //R_REG_TYPE_GPR);
2012-02-27 01:40:27 +00:00
if (r) {
if (r->flags) {
r_cons_printf ("0x%08"PFMT64x" ->",
r_reg_get_value (core->dbg->reg, r));
r_reg_set_bvalue (core->dbg->reg, r, arg+1);
2015-09-14 10:35:38 +00:00
r_debug_reg_sync (core->dbg, -1, true);
r_cons_printf ("0x%08"PFMT64x"\n",
r_reg_get_value (core->dbg->reg, r));
} else {
r_cons_printf ("0x%08"PFMT64x" ->",
r_reg_get_value (core->dbg->reg, r));
r_reg_set_value (core->dbg->reg, r,
r_num_math (core->num, arg+1));
2015-09-14 10:35:38 +00:00
r_debug_reg_sync (core->dbg, -1, true);
r_cons_printf ("0x%08"PFMT64x"\n",
r_reg_get_value (core->dbg->reg, r));
}
2014-09-11 02:44:55 +00:00
} else eprintf ("Unknown register '%s'\n", string);
free (string);
2015-10-03 12:02:21 +00:00
// update flags here
r_core_cmd0 (core, ".dr*");
2012-02-27 01:40:27 +00:00
return;
2014-09-11 02:29:28 +00:00
} else {
ut64 off;
2015-09-14 10:35:38 +00:00
r_debug_reg_sync (core->dbg, -1, 0); //R_REG_TYPE_GPR, false);
off = r_debug_reg_get (core->dbg, str+1);
// r = r_reg_get (core->dbg->reg, str+1, 0);
// if (r == NULL) eprintf ("Unknown register (%s)\n", str+1);
r_cons_printf ("0x%08"PFMT64x"\n", off);
core->num->value = off;
//r_reg_get_value (core->dbg->reg, r));
2012-02-27 01:40:27 +00:00
}
}
}
static int validAddress(RCore *core, ut64 addr) {
RDebugMap *map;
RListIter *iter;
if (!r_config_get_i (core->config, "dbg.bpinmaps")) {
return core->num->value = 1;
}
r_debug_map_sync (core->dbg);
r_list_foreach (core->dbg->maps, iter, map) {
if (addr >= map->addr && addr < map->addr_end) {
return core->num->value = 1;
}
}
// TODO: try to read memory, expect no 0xffff
// TODO: check map permissions
return core->num->value = 0;
}
2012-02-27 01:40:27 +00:00
static void static_debug_stop(void *u) {
RDebug *dbg = (RDebug *)u;
r_debug_stop (dbg);
}
static void r_core_cmd_bp(RCore *core, const char *input) {
RBreakpointItem *bpi;
const char* help_msg[] = {
"Usage: db", "", " # Breakpoints commands",
"db", "", "List breakpoints",
"db", " sym.main", "Add breakpoint into sym.main",
"db", " <addr>", "Add breakpoint",
"db", " -<addr>", "Remove breakpoint",
2015-08-16 23:43:45 +00:00
"db.", "", "Show breakpoint info in current offset",
"dbj", "", "List breakpoints in JSON format",
// "dbi", " 0x848 ecx=3", "stop execution when condition matches",
"dbc", " <addr> <cmd>", "Run command when breakpoint is hit",
"dbd", " <addr>", "Disable breakpoint",
"dbe", " <addr>", "Enable breakpoint",
"dbs", " <addr>", "Toggle breakpoint",
2015-08-22 12:19:33 +00:00
"dbt", "", "Display backtrace based on dbg.btdepth and dbg.btalgo",
2015-10-22 11:38:30 +00:00
"dbt*", "", "Display backtrace in flags",
2015-10-22 10:53:34 +00:00
"dbt=", "", "Display backtrace in one line (see dbt=s and dbt=b for sp or bp)",
"dbtj", "", "Display backtrace in JSON",
"dbte", " <addr>", "Enable Breakpoint Trace",
"dbtd", " <addr>", "Disable Breakpoint Trace",
"dbts", " <addr>", "Swap Breakpoint Trace",
"dbm", " <module> <offset>", "Add a breakpoint at an offset from a module's base",
2015-08-16 23:43:45 +00:00
"dbn", " [<name>]", "Show or set name for current breakpoint",
//
"dbi", "", "List breakpoint indexes",
"dbic", " <index> <cmd>", "Run command at breakpoint index",
"dbie", " <index>", "Enable breakpoint by index",
"dbid", " <index>", "Disable breakpoint by index",
"dbis", " <index>", "Swap Nth breakpoint",
"dbite", " <index>", "Enable breakpoint Trace by index",
"dbitd", " <index>", "Disable breakpoint Trace by index",
"dbits", " <index>", "Swap Nth breakpoint trace",
//
"dbh", " x86", "Set/list breakpoint plugin handlers",
2015-05-14 13:46:28 +00:00
"drx", " number addr len rwx", "Modify hardware breakpoint",
"drx-", "number", "Clear hardware breakpoint",
NULL};
int i, hwbp = r_config_get_i (core->config, "dbg.hwbp");
2013-06-20 07:54:42 +00:00
RDebugFrame *frame;
RListIter *iter;
const char *p;
RList *list;
ut64 addr;
p = strchr (input, ' ');
addr = p? r_num_math (core->num, p+1): 0LL;
2012-02-27 01:40:27 +00:00
switch (input[1]) {
2015-08-16 23:43:45 +00:00
case '.':
if (input[2]) {
Major rework to the native debugger (esp on Linux) (#5185) The major contribution here is completely re-worked breakpoint hit/recoil handling. This work fixes #4907 and lays the ground work for future native debugger improvements (multi-threading, etc). * Give a human friendly type to enums * Change many wait functions to return RDebugReasonType * Better return checking (from r_debug_reg_sync, r_bp_restore) * Optimized register synchronization * Lots of comments and whitespace changes * Improved inferior death detection Handle EXIT_PID events differently than DEAD process events * Move breakpoint/recoil handling to wait/cont/step Rather than handing breakpoint related things inside cmd_debug.c, do that inside the r_debug API functions. This seems like the most logical place for it to live since it should apply to just about any platform/architecture. This also centralizes calling into "cmd.bp" handling via the CoreBind callback. * Track how the caller wishes to continue It turns out that handling break point recoils is very complicated. The ptrace API on Linux returns SIGTRAP for just about every type of operation (not just breakpoints getting hit). Add the "recoil_mode" flag to indicate whether we are single-stepping or continuing and whether or not we are inside the recoil. * Proper handling for swstep=true Since r_debug_step_soft calls r_debug_continue, it's already hitting the recoil case there. Move the recoil handling from r_debug_step to r_debug_step_hard only. For the swstep=true case, special handling is required inside r_debug_recoil. By resetting all of the breakpoints except the one we just hit, we ensure we can step the original instruction and hit the new swstep breakpoint. Add a new bp function called r_bp_restore_except to do this. To make matters worse, we cannot use a BreakpointItem pointer because that leads to a use-after-free condition. Instead, we the breakpoint address instead. Now breakpoints should work regardless of the swtep setting. * Always call the recoil before continuing Some callers of r_debug_continue might not have ever inserted any breakpoints before. If we don't restore breakpoints before each call to the underlying continue we won't hit them. * Hide software step breakpoint events from the user When a breakpoint even happens due to a software-step, hide it from the user. They aren't really breakpoints as far as they are concerned. * Improve process exit handling on Linux There are three types of process exiting events on Linux: 1. PTRACE_EVENT_EXIT occurs just before a process exits. It's not possible to prevent it from exiting, but it can be used to inspect the pre-exit state. 2. The process can exit for a variety of reasons and we can notice when we call waitpid(2). 3. The process could die randomly on us :-/ On Windows, h->wait will return R_DEBUG_REASON_EXIT_PID, but it's more likely on Linux to find out the process is already dead. * Check more bits within waitpid status We can often make a decision about what happened strictly by looking at the status returned from waitpid. In other cases, we need to call r_debug_handle_signals. If we reach the end of this function without knowing what happened, consider it an error.
2016-06-22 08:34:45 +00:00
ut64 addr = r_num_tail (core->num, core->offset, input + 2);
if (validAddress (core, addr)) {
bpi = r_debug_bp_add (core->dbg, addr, hwbp, NULL, 0);
Major rework to the native debugger (esp on Linux) (#5185) The major contribution here is completely re-worked breakpoint hit/recoil handling. This work fixes #4907 and lays the ground work for future native debugger improvements (multi-threading, etc). * Give a human friendly type to enums * Change many wait functions to return RDebugReasonType * Better return checking (from r_debug_reg_sync, r_bp_restore) * Optimized register synchronization * Lots of comments and whitespace changes * Improved inferior death detection Handle EXIT_PID events differently than DEAD process events * Move breakpoint/recoil handling to wait/cont/step Rather than handing breakpoint related things inside cmd_debug.c, do that inside the r_debug API functions. This seems like the most logical place for it to live since it should apply to just about any platform/architecture. This also centralizes calling into "cmd.bp" handling via the CoreBind callback. * Track how the caller wishes to continue It turns out that handling break point recoils is very complicated. The ptrace API on Linux returns SIGTRAP for just about every type of operation (not just breakpoints getting hit). Add the "recoil_mode" flag to indicate whether we are single-stepping or continuing and whether or not we are inside the recoil. * Proper handling for swstep=true Since r_debug_step_soft calls r_debug_continue, it's already hitting the recoil case there. Move the recoil handling from r_debug_step to r_debug_step_hard only. For the swstep=true case, special handling is required inside r_debug_recoil. By resetting all of the breakpoints except the one we just hit, we ensure we can step the original instruction and hit the new swstep breakpoint. Add a new bp function called r_bp_restore_except to do this. To make matters worse, we cannot use a BreakpointItem pointer because that leads to a use-after-free condition. Instead, we the breakpoint address instead. Now breakpoints should work regardless of the swtep setting. * Always call the recoil before continuing Some callers of r_debug_continue might not have ever inserted any breakpoints before. If we don't restore breakpoints before each call to the underlying continue we won't hit them. * Hide software step breakpoint events from the user When a breakpoint even happens due to a software-step, hide it from the user. They aren't really breakpoints as far as they are concerned. * Improve process exit handling on Linux There are three types of process exiting events on Linux: 1. PTRACE_EVENT_EXIT occurs just before a process exits. It's not possible to prevent it from exiting, but it can be used to inspect the pre-exit state. 2. The process can exit for a variety of reasons and we can notice when we call waitpid(2). 3. The process could die randomly on us :-/ On Windows, h->wait will return R_DEBUG_REASON_EXIT_PID, but it's more likely on Linux to find out the process is already dead. * Check more bits within waitpid status We can often make a decision about what happened strictly by looking at the status returned from waitpid. In other cases, we need to call r_debug_handle_signals. If we reach the end of this function without knowing what happened, consider it an error.
2016-06-22 08:34:45 +00:00
if (!bpi)
eprintf ("Unable to add breakpoint (%s)\n", input + 2);
} else {
eprintf ("Invalid address\n");
}
} else {
bpi = r_bp_get_at (core->dbg->bp, core->offset);
if (bpi) {
r_cons_printf ("breakpoint %s %s %s\n",
r_str_rwx_i (bpi->rwx),
bpi->enabled ? "enabled" : "disabled",
bpi->name ? bpi->name : "");
}
2015-08-16 23:43:45 +00:00
}
break;
2015-10-19 01:13:42 +00:00
case 't': // "dbt"
switch (input[2]) {
2015-10-19 01:13:42 +00:00
case 'e': // "dbte"
for (p = input + 3; *p == ' '; p++) { /* nothing to do here */ }
if (*p == '*') {
2015-09-14 10:35:38 +00:00
r_bp_set_trace_all (core->dbg->bp,true);
} else if (!r_bp_set_trace (core->dbg->bp,
2015-09-14 10:35:38 +00:00
addr, true)) {
eprintf ("Cannot set tracepoint\n");
}
break;
2015-10-19 01:13:42 +00:00
case 'd': // "dbtd"
for (p = input + 3; *p==' ';p++);
if (*p == '*') {
2015-09-14 10:35:38 +00:00
r_bp_set_trace_all (core->dbg->bp,false);
} else if (!r_bp_set_trace (core->dbg->bp, addr, false))
eprintf ("Cannot unset tracepoint\n");
break;
2015-10-19 01:13:42 +00:00
case 's': // "dbts"
bpi = r_bp_get_at (core->dbg->bp, addr);
if (bpi) bpi->trace = !!!bpi->trace;
else eprintf ("Cannot unset tracepoint\n");
break;
2015-10-19 01:13:42 +00:00
case 'j': // "dbtj"
addr = UT64_MAX;
if (input[2] == ' ' && input[3])
Major rework to the native debugger (esp on Linux) (#5185) The major contribution here is completely re-worked breakpoint hit/recoil handling. This work fixes #4907 and lays the ground work for future native debugger improvements (multi-threading, etc). * Give a human friendly type to enums * Change many wait functions to return RDebugReasonType * Better return checking (from r_debug_reg_sync, r_bp_restore) * Optimized register synchronization * Lots of comments and whitespace changes * Improved inferior death detection Handle EXIT_PID events differently than DEAD process events * Move breakpoint/recoil handling to wait/cont/step Rather than handing breakpoint related things inside cmd_debug.c, do that inside the r_debug API functions. This seems like the most logical place for it to live since it should apply to just about any platform/architecture. This also centralizes calling into "cmd.bp" handling via the CoreBind callback. * Track how the caller wishes to continue It turns out that handling break point recoils is very complicated. The ptrace API on Linux returns SIGTRAP for just about every type of operation (not just breakpoints getting hit). Add the "recoil_mode" flag to indicate whether we are single-stepping or continuing and whether or not we are inside the recoil. * Proper handling for swstep=true Since r_debug_step_soft calls r_debug_continue, it's already hitting the recoil case there. Move the recoil handling from r_debug_step to r_debug_step_hard only. For the swstep=true case, special handling is required inside r_debug_recoil. By resetting all of the breakpoints except the one we just hit, we ensure we can step the original instruction and hit the new swstep breakpoint. Add a new bp function called r_bp_restore_except to do this. To make matters worse, we cannot use a BreakpointItem pointer because that leads to a use-after-free condition. Instead, we the breakpoint address instead. Now breakpoints should work regardless of the swtep setting. * Always call the recoil before continuing Some callers of r_debug_continue might not have ever inserted any breakpoints before. If we don't restore breakpoints before each call to the underlying continue we won't hit them. * Hide software step breakpoint events from the user When a breakpoint even happens due to a software-step, hide it from the user. They aren't really breakpoints as far as they are concerned. * Improve process exit handling on Linux There are three types of process exiting events on Linux: 1. PTRACE_EVENT_EXIT occurs just before a process exits. It's not possible to prevent it from exiting, but it can be used to inspect the pre-exit state. 2. The process can exit for a variety of reasons and we can notice when we call waitpid(2). 3. The process could die randomly on us :-/ On Windows, h->wait will return R_DEBUG_REASON_EXIT_PID, but it's more likely on Linux to find out the process is already dead. * Check more bits within waitpid status We can often make a decision about what happened strictly by looking at the status returned from waitpid. In other cases, we need to call r_debug_handle_signals. If we reach the end of this function without knowing what happened, consider it an error.
2016-06-22 08:34:45 +00:00
addr = r_num_math (core->num, input + 2);
i = 0;
list = r_debug_frames (core->dbg, addr);
r_cons_printf ("[");
r_list_foreach (list, iter, frame) {
r_cons_printf ("%s%08"PFMT64d,
(i ? "," : ""), frame->addr);
i++;
}
r_cons_printf ("]\n");
r_list_free (list);
break;
case '=': // dbt=
addr = UT64_MAX;
if (input[2] == ' ' && input[3])
Major rework to the native debugger (esp on Linux) (#5185) The major contribution here is completely re-worked breakpoint hit/recoil handling. This work fixes #4907 and lays the ground work for future native debugger improvements (multi-threading, etc). * Give a human friendly type to enums * Change many wait functions to return RDebugReasonType * Better return checking (from r_debug_reg_sync, r_bp_restore) * Optimized register synchronization * Lots of comments and whitespace changes * Improved inferior death detection Handle EXIT_PID events differently than DEAD process events * Move breakpoint/recoil handling to wait/cont/step Rather than handing breakpoint related things inside cmd_debug.c, do that inside the r_debug API functions. This seems like the most logical place for it to live since it should apply to just about any platform/architecture. This also centralizes calling into "cmd.bp" handling via the CoreBind callback. * Track how the caller wishes to continue It turns out that handling break point recoils is very complicated. The ptrace API on Linux returns SIGTRAP for just about every type of operation (not just breakpoints getting hit). Add the "recoil_mode" flag to indicate whether we are single-stepping or continuing and whether or not we are inside the recoil. * Proper handling for swstep=true Since r_debug_step_soft calls r_debug_continue, it's already hitting the recoil case there. Move the recoil handling from r_debug_step to r_debug_step_hard only. For the swstep=true case, special handling is required inside r_debug_recoil. By resetting all of the breakpoints except the one we just hit, we ensure we can step the original instruction and hit the new swstep breakpoint. Add a new bp function called r_bp_restore_except to do this. To make matters worse, we cannot use a BreakpointItem pointer because that leads to a use-after-free condition. Instead, we the breakpoint address instead. Now breakpoints should work regardless of the swtep setting. * Always call the recoil before continuing Some callers of r_debug_continue might not have ever inserted any breakpoints before. If we don't restore breakpoints before each call to the underlying continue we won't hit them. * Hide software step breakpoint events from the user When a breakpoint even happens due to a software-step, hide it from the user. They aren't really breakpoints as far as they are concerned. * Improve process exit handling on Linux There are three types of process exiting events on Linux: 1. PTRACE_EVENT_EXIT occurs just before a process exits. It's not possible to prevent it from exiting, but it can be used to inspect the pre-exit state. 2. The process can exit for a variety of reasons and we can notice when we call waitpid(2). 3. The process could die randomly on us :-/ On Windows, h->wait will return R_DEBUG_REASON_EXIT_PID, but it's more likely on Linux to find out the process is already dead. * Check more bits within waitpid status We can often make a decision about what happened strictly by looking at the status returned from waitpid. In other cases, we need to call r_debug_handle_signals. If we reach the end of this function without knowing what happened, consider it an error.
2016-06-22 08:34:45 +00:00
addr = r_num_math (core->num, input + 2);
i = 0;
list = r_debug_frames (core->dbg, addr);
r_list_reverse (list);
r_list_foreach (list, iter, frame) {
2015-10-22 10:53:34 +00:00
switch (input[3]) {
case 0:
r_cons_printf ("%s0x%08"PFMT64x,
(i ? " " : ""), frame->addr);
break;
2015-10-22 10:53:34 +00:00
case 's':
r_cons_printf ("%s0x%08"PFMT64x,
(i ? " " : ""), frame->sp);
2015-10-22 10:53:34 +00:00
break;
case 'b':
r_cons_printf ("%s0x%08"PFMT64x,
(i ? " " : ""), frame->bp);
2015-10-22 10:53:34 +00:00
break;
case '?':
2015-10-22 10:53:34 +00:00
default:
r_core_cmd0 (core, "db?~dbt");
2015-10-22 10:53:34 +00:00
break;
}
i++;
}
r_cons_newline ();
r_list_free (list);
break;
case '*': // dbt*
addr = UT64_MAX;
if (input[2] == ' ' && input[3])
addr = r_num_math (core->num, input + 2);
i = 0;
list = r_debug_frames (core->dbg, addr);
r_list_reverse (list);
r_cons_printf ("f-bt.*\n");
r_list_foreach (list, iter, frame) {
r_cons_printf ("f bt.frame%d = 0x%08"PFMT64x"\n", i, frame->addr);
2015-10-22 10:53:34 +00:00
r_cons_printf ("f bt.frame%d.stack %d 0x%08"PFMT64x"\n", i, frame->size, frame->sp);
i++;
}
r_list_free (list);
break;
2015-10-19 01:13:42 +00:00
case 0: // "dbt" -- backtrace
addr = UT64_MAX;
if (input[2] == ' ' && input[3])
addr = r_num_math (core->num, input + 2);
i = 0;
list = r_debug_frames (core->dbg, addr);
r_list_foreach (list, iter, frame) {
char flagdesc[1024], flagdesc2[1024], pcstr[32], spstr[32];
2015-10-19 01:13:42 +00:00
RFlagItem *f = r_flag_get_at (core->flags, frame->addr);
2015-10-19 01:13:42 +00:00
flagdesc[0] = flagdesc2[0] = 0;
if (f) {
if (f->offset != addr) {
int delta = (int)(frame->addr - f->offset);
if (delta > 0) {
snprintf (flagdesc, sizeof (flagdesc),
"%s+%d", f->name, delta);
} else if (delta < 0) {
snprintf (flagdesc, sizeof (flagdesc),
"%s%d", f->name, delta);
} else {
snprintf (flagdesc, sizeof (flagdesc),
"%s", f->name);
}
} else {
snprintf (flagdesc, sizeof (flagdesc),
"%s", f->name);
}
}
2015-10-19 01:13:42 +00:00
f = r_flag_get_at (core->flags, frame->addr);
if (f && !strchr (f->name, '.')) {
f = r_flag_get_at (core->flags, frame->addr-1);
}
if (f) {
if (f->offset != addr) {
int delta = (int)(frame->addr - 1 - f->offset);
if (delta > 0) {
snprintf (flagdesc2, sizeof (flagdesc2),
"%s+%d", f->name, delta + 1);
} else if (delta<0) {
snprintf (flagdesc2, sizeof (flagdesc2),
"%s%d", f->name, delta + 1);
} else {
snprintf (flagdesc2, sizeof (flagdesc2),
"%s+1", f->name);
}
} else {
snprintf (flagdesc2, sizeof (flagdesc2),
"%s", f->name);
}
}
if (!strcmp (flagdesc, flagdesc2)) {
flagdesc2[0] = 0;
}
if (core->dbg->bits & R_SYS_BITS_64) {
snprintf (pcstr, sizeof (pcstr), "0x%-16" PFMT64x, frame->addr);
snprintf (spstr, sizeof (spstr), "0x%-16" PFMT64x, frame->sp);
} else if (core->dbg->bits & R_SYS_BITS_32) {
snprintf (pcstr, sizeof (pcstr), "0x%-8" PFMT64x, frame->addr);
snprintf (spstr, sizeof (spstr), "0x%-8" PFMT64x, frame->sp);
2015-06-03 15:20:03 +00:00
} else {
snprintf (pcstr, sizeof (pcstr), "0x%" PFMT64x, frame->addr);
snprintf (spstr, sizeof (spstr), "0x%" PFMT64x, frame->sp);
2015-06-03 15:20:03 +00:00
}
RAnalFunction *fcn = r_anal_get_fcn_in (core->anal, frame->addr, 0);
r_cons_printf ("%d %s sp: %s %-5d"
"[%s] %s %s\n", i++,
pcstr, spstr,
(int)frame->size,
fcn ? fcn->name : "??",
flagdesc,
flagdesc2);
}
r_list_free (list);
break;
case '?':
default:
2015-10-19 01:13:42 +00:00
r_core_cmd0 (core, "db?~dbt");
break;
2012-02-27 01:40:27 +00:00
}
break;
2016-07-05 20:48:48 +00:00
case 'b': // "dbb"
if (input[2]) {
core->dbg->bp->delta = (st64)r_num_math (core->num, input + 2);
} else {
r_cons_printf ("%"PFMT64d"\n", core->dbg->bp->delta);
}
2016-05-17 07:15:51 +00:00
break;
case 'm': // "dbm"
if (input[2] && input[3]) {
char *string = strdup (input + 3);
char *module = NULL;
st64 delta = 0;
module = strtok (string, " ");
delta = (ut64)r_num_math (core->num, strtok (NULL, ""));
bpi = r_debug_bp_add (core->dbg, 0, hwbp, module, delta);
free (string);
}
break;
case 'j': r_bp_list (core->dbg->bp, 'j'); break;
2013-06-20 07:54:42 +00:00
case '*': r_bp_list (core->dbg->bp, 1); break;
case '\0': r_bp_list (core->dbg->bp, 0); break;
case '-': // "db-"
if (input[2] == '*') r_bp_del_all (core->dbg->bp);
else r_bp_del (core->dbg->bp, r_num_math (core->num, input + 2));
2012-02-27 01:40:27 +00:00
break;
case 'c': // "dbc"
2016-05-27 11:14:43 +00:00
if (input[2] == ' ') {
char *inp = strdup (input + 3);
if (inp) {
char *arg = strchr (inp, ' ');
if (arg) {
*arg++ = 0;
addr = r_num_math (core->num, inp);
bpi = r_bp_get_at (core->dbg->bp, addr);
if (bpi) {
free (bpi->data);
bpi->data = strdup (arg);
} else {
eprintf ("No breakpoint defined at 0x%08"PFMT64x"\n", addr);
}
} else {
eprintf ("Missing argument\n");
}
2016-06-02 01:19:31 +00:00
free (inp);
} else {
2016-05-27 11:14:43 +00:00
eprintf ("Cannot strdup. Your heap is fucked up\n");
}
2016-05-27 11:14:43 +00:00
} else {
eprintf ("Use: dbc [addr] [command]\n");
}
2012-02-27 01:40:27 +00:00
break;
case 's': // "dbs"
addr = r_num_math (core->num, input + 2);
bpi = r_bp_get_at (core->dbg->bp, addr);
if (bpi) {
//bp->enabled = !bp->enabled;
Major rework to the native debugger (esp on Linux) (#5185) The major contribution here is completely re-worked breakpoint hit/recoil handling. This work fixes #4907 and lays the ground work for future native debugger improvements (multi-threading, etc). * Give a human friendly type to enums * Change many wait functions to return RDebugReasonType * Better return checking (from r_debug_reg_sync, r_bp_restore) * Optimized register synchronization * Lots of comments and whitespace changes * Improved inferior death detection Handle EXIT_PID events differently than DEAD process events * Move breakpoint/recoil handling to wait/cont/step Rather than handing breakpoint related things inside cmd_debug.c, do that inside the r_debug API functions. This seems like the most logical place for it to live since it should apply to just about any platform/architecture. This also centralizes calling into "cmd.bp" handling via the CoreBind callback. * Track how the caller wishes to continue It turns out that handling break point recoils is very complicated. The ptrace API on Linux returns SIGTRAP for just about every type of operation (not just breakpoints getting hit). Add the "recoil_mode" flag to indicate whether we are single-stepping or continuing and whether or not we are inside the recoil. * Proper handling for swstep=true Since r_debug_step_soft calls r_debug_continue, it's already hitting the recoil case there. Move the recoil handling from r_debug_step to r_debug_step_hard only. For the swstep=true case, special handling is required inside r_debug_recoil. By resetting all of the breakpoints except the one we just hit, we ensure we can step the original instruction and hit the new swstep breakpoint. Add a new bp function called r_bp_restore_except to do this. To make matters worse, we cannot use a BreakpointItem pointer because that leads to a use-after-free condition. Instead, we the breakpoint address instead. Now breakpoints should work regardless of the swtep setting. * Always call the recoil before continuing Some callers of r_debug_continue might not have ever inserted any breakpoints before. If we don't restore breakpoints before each call to the underlying continue we won't hit them. * Hide software step breakpoint events from the user When a breakpoint even happens due to a software-step, hide it from the user. They aren't really breakpoints as far as they are concerned. * Improve process exit handling on Linux There are three types of process exiting events on Linux: 1. PTRACE_EVENT_EXIT occurs just before a process exits. It's not possible to prevent it from exiting, but it can be used to inspect the pre-exit state. 2. The process can exit for a variety of reasons and we can notice when we call waitpid(2). 3. The process could die randomly on us :-/ On Windows, h->wait will return R_DEBUG_REASON_EXIT_PID, but it's more likely on Linux to find out the process is already dead. * Check more bits within waitpid status We can often make a decision about what happened strictly by looking at the status returned from waitpid. In other cases, we need to call r_debug_handle_signals. If we reach the end of this function without knowing what happened, consider it an error.
2016-06-22 08:34:45 +00:00
// XXX(jjd): this ^^ is what I would think toggling means...
r_bp_del (core->dbg->bp, addr);
} else {
Major rework to the native debugger (esp on Linux) (#5185) The major contribution here is completely re-worked breakpoint hit/recoil handling. This work fixes #4907 and lays the ground work for future native debugger improvements (multi-threading, etc). * Give a human friendly type to enums * Change many wait functions to return RDebugReasonType * Better return checking (from r_debug_reg_sync, r_bp_restore) * Optimized register synchronization * Lots of comments and whitespace changes * Improved inferior death detection Handle EXIT_PID events differently than DEAD process events * Move breakpoint/recoil handling to wait/cont/step Rather than handing breakpoint related things inside cmd_debug.c, do that inside the r_debug API functions. This seems like the most logical place for it to live since it should apply to just about any platform/architecture. This also centralizes calling into "cmd.bp" handling via the CoreBind callback. * Track how the caller wishes to continue It turns out that handling break point recoils is very complicated. The ptrace API on Linux returns SIGTRAP for just about every type of operation (not just breakpoints getting hit). Add the "recoil_mode" flag to indicate whether we are single-stepping or continuing and whether or not we are inside the recoil. * Proper handling for swstep=true Since r_debug_step_soft calls r_debug_continue, it's already hitting the recoil case there. Move the recoil handling from r_debug_step to r_debug_step_hard only. For the swstep=true case, special handling is required inside r_debug_recoil. By resetting all of the breakpoints except the one we just hit, we ensure we can step the original instruction and hit the new swstep breakpoint. Add a new bp function called r_bp_restore_except to do this. To make matters worse, we cannot use a BreakpointItem pointer because that leads to a use-after-free condition. Instead, we the breakpoint address instead. Now breakpoints should work regardless of the swtep setting. * Always call the recoil before continuing Some callers of r_debug_continue might not have ever inserted any breakpoints before. If we don't restore breakpoints before each call to the underlying continue we won't hit them. * Hide software step breakpoint events from the user When a breakpoint even happens due to a software-step, hide it from the user. They aren't really breakpoints as far as they are concerned. * Improve process exit handling on Linux There are three types of process exiting events on Linux: 1. PTRACE_EVENT_EXIT occurs just before a process exits. It's not possible to prevent it from exiting, but it can be used to inspect the pre-exit state. 2. The process can exit for a variety of reasons and we can notice when we call waitpid(2). 3. The process could die randomly on us :-/ On Windows, h->wait will return R_DEBUG_REASON_EXIT_PID, but it's more likely on Linux to find out the process is already dead. * Check more bits within waitpid status We can often make a decision about what happened strictly by looking at the status returned from waitpid. In other cases, we need to call r_debug_handle_signals. If we reach the end of this function without knowing what happened, consider it an error.
2016-06-22 08:34:45 +00:00
// XXX(jjd): does t his need an address validity check??
bpi = r_debug_bp_add (core->dbg, addr, hwbp, NULL, 0);
if (!bpi) eprintf ("Cannot set breakpoint (%s)\n", input + 2);
}
r_bp_enable (core->dbg->bp, r_num_math (core->num, input + 2), 0);
break;
case 'n': // "dbn"
2015-08-16 23:43:45 +00:00
bpi = r_bp_get_at (core->dbg->bp, core->offset);
if (input[2] == ' ') {
if (bpi) {
free (bpi->name);
bpi->name = strdup (input + 3);
} else {
eprintf ("Cannot find breakpoint at "
"0x%08"PFMT64x"\n", core->offset);
2015-08-16 23:43:45 +00:00
}
} else {
if (bpi && bpi->name) {
r_cons_println (bpi->name);
}
2015-08-16 23:43:45 +00:00
}
break;
2012-02-27 01:40:27 +00:00
case 'e':
for (p = input + 2; *p == ' '; p++);
2015-09-14 10:35:38 +00:00
if (*p == '*') r_bp_enable_all (core->dbg->bp,true);
else r_bp_enable (core->dbg->bp, r_num_math (core->num,
2015-09-14 10:35:38 +00:00
input + 2), true);
2012-02-27 01:40:27 +00:00
break;
case 'd':
for (p = input + 2; *p == ' '; p++);
2015-09-14 10:35:38 +00:00
if (*p == '*') r_bp_enable_all (core->dbg->bp, false);
r_bp_enable (core->dbg->bp, r_num_math (core->num,
2015-09-14 10:35:38 +00:00
input + 2), false);
2012-02-27 01:40:27 +00:00
break;
case 'h':
2015-06-12 00:56:54 +00:00
switch (input[2]) {
case 0:
r_bp_plugin_list (core->dbg->bp);
break;
2015-06-12 00:56:54 +00:00
case ' ':
if (!r_bp_use (core->dbg->bp, input + 3, core->anal->bits))
Major rework to the native debugger (esp on Linux) (#5185) The major contribution here is completely re-worked breakpoint hit/recoil handling. This work fixes #4907 and lays the ground work for future native debugger improvements (multi-threading, etc). * Give a human friendly type to enums * Change many wait functions to return RDebugReasonType * Better return checking (from r_debug_reg_sync, r_bp_restore) * Optimized register synchronization * Lots of comments and whitespace changes * Improved inferior death detection Handle EXIT_PID events differently than DEAD process events * Move breakpoint/recoil handling to wait/cont/step Rather than handing breakpoint related things inside cmd_debug.c, do that inside the r_debug API functions. This seems like the most logical place for it to live since it should apply to just about any platform/architecture. This also centralizes calling into "cmd.bp" handling via the CoreBind callback. * Track how the caller wishes to continue It turns out that handling break point recoils is very complicated. The ptrace API on Linux returns SIGTRAP for just about every type of operation (not just breakpoints getting hit). Add the "recoil_mode" flag to indicate whether we are single-stepping or continuing and whether or not we are inside the recoil. * Proper handling for swstep=true Since r_debug_step_soft calls r_debug_continue, it's already hitting the recoil case there. Move the recoil handling from r_debug_step to r_debug_step_hard only. For the swstep=true case, special handling is required inside r_debug_recoil. By resetting all of the breakpoints except the one we just hit, we ensure we can step the original instruction and hit the new swstep breakpoint. Add a new bp function called r_bp_restore_except to do this. To make matters worse, we cannot use a BreakpointItem pointer because that leads to a use-after-free condition. Instead, we the breakpoint address instead. Now breakpoints should work regardless of the swtep setting. * Always call the recoil before continuing Some callers of r_debug_continue might not have ever inserted any breakpoints before. If we don't restore breakpoints before each call to the underlying continue we won't hit them. * Hide software step breakpoint events from the user When a breakpoint even happens due to a software-step, hide it from the user. They aren't really breakpoints as far as they are concerned. * Improve process exit handling on Linux There are three types of process exiting events on Linux: 1. PTRACE_EVENT_EXIT occurs just before a process exits. It's not possible to prevent it from exiting, but it can be used to inspect the pre-exit state. 2. The process can exit for a variety of reasons and we can notice when we call waitpid(2). 3. The process could die randomly on us :-/ On Windows, h->wait will return R_DEBUG_REASON_EXIT_PID, but it's more likely on Linux to find out the process is already dead. * Check more bits within waitpid status We can often make a decision about what happened strictly by looking at the status returned from waitpid. In other cases, we need to call r_debug_handle_signals. If we reach the end of this function without knowing what happened, consider it an error.
2016-06-22 08:34:45 +00:00
eprintf ("Invalid name: '%s'.\n", input + 3);
2015-06-12 00:56:54 +00:00
break;
case '?':
2015-06-12 00:56:54 +00:00
default:
eprintf ("Usage: dh [plugin-name] # select a debug handler plugin\n");
break;
}
2012-02-27 01:40:27 +00:00
break;
2013-06-20 07:54:42 +00:00
case ' ':
for (p = input + 1; *p == ' '; p++);
2013-06-20 07:54:42 +00:00
if (*p == '-') {
r_bp_del (core->dbg->bp, r_num_math (core->num, p + 1));
2013-06-20 07:54:42 +00:00
} else {
addr = r_num_math (core->num, input + 2);
if (validAddress (core, addr)) {
bpi = r_debug_bp_add (core->dbg, addr, hwbp, NULL, 0);
2015-08-16 23:43:45 +00:00
if (bpi) {
free (bpi->name);
if (!strcmp (input + 2, "$$")) {
char *newname = NULL;
RFlagItem *f = r_flag_get_i2 (core->flags, addr);
if (f) {
if (addr > f->offset) {
newname = r_str_newf ("%s+0x%" PFMT64x, f->name, addr - f->offset);
} else {
newname = strdup (f->name);
}
}
bpi->name = newname;
} else {
bpi->name = strdup (input + 2);
}
2015-08-16 23:43:45 +00:00
} else {
eprintf ("Cannot set breakpoint at '%s'\n", input + 2);
2015-08-16 23:43:45 +00:00
}
} else {
eprintf ("Cannot place a breakpoint on 0x%08"PFMT64x" unmapped memory. See dbg.bpinmaps\n", addr);
}
2013-06-20 07:54:42 +00:00
}
break;
case 'i':
switch (input[2]) {
case 0: // "dbi"
for (i = 0;i < core->dbg->bp->bps_idx_count; i++) {
if ((bpi = core->dbg->bp->bps_idx[i])) {
r_cons_printf ("%d 0x%08"PFMT64x" E:%d T:%d\n",
i, bpi->addr, bpi->enabled, bpi->trace);
}
}
break;
case 'c': // "dbic"
Major rework to the native debugger (esp on Linux) (#5185) The major contribution here is completely re-worked breakpoint hit/recoil handling. This work fixes #4907 and lays the ground work for future native debugger improvements (multi-threading, etc). * Give a human friendly type to enums * Change many wait functions to return RDebugReasonType * Better return checking (from r_debug_reg_sync, r_bp_restore) * Optimized register synchronization * Lots of comments and whitespace changes * Improved inferior death detection Handle EXIT_PID events differently than DEAD process events * Move breakpoint/recoil handling to wait/cont/step Rather than handing breakpoint related things inside cmd_debug.c, do that inside the r_debug API functions. This seems like the most logical place for it to live since it should apply to just about any platform/architecture. This also centralizes calling into "cmd.bp" handling via the CoreBind callback. * Track how the caller wishes to continue It turns out that handling break point recoils is very complicated. The ptrace API on Linux returns SIGTRAP for just about every type of operation (not just breakpoints getting hit). Add the "recoil_mode" flag to indicate whether we are single-stepping or continuing and whether or not we are inside the recoil. * Proper handling for swstep=true Since r_debug_step_soft calls r_debug_continue, it's already hitting the recoil case there. Move the recoil handling from r_debug_step to r_debug_step_hard only. For the swstep=true case, special handling is required inside r_debug_recoil. By resetting all of the breakpoints except the one we just hit, we ensure we can step the original instruction and hit the new swstep breakpoint. Add a new bp function called r_bp_restore_except to do this. To make matters worse, we cannot use a BreakpointItem pointer because that leads to a use-after-free condition. Instead, we the breakpoint address instead. Now breakpoints should work regardless of the swtep setting. * Always call the recoil before continuing Some callers of r_debug_continue might not have ever inserted any breakpoints before. If we don't restore breakpoints before each call to the underlying continue we won't hit them. * Hide software step breakpoint events from the user When a breakpoint even happens due to a software-step, hide it from the user. They aren't really breakpoints as far as they are concerned. * Improve process exit handling on Linux There are three types of process exiting events on Linux: 1. PTRACE_EVENT_EXIT occurs just before a process exits. It's not possible to prevent it from exiting, but it can be used to inspect the pre-exit state. 2. The process can exit for a variety of reasons and we can notice when we call waitpid(2). 3. The process could die randomly on us :-/ On Windows, h->wait will return R_DEBUG_REASON_EXIT_PID, but it's more likely on Linux to find out the process is already dead. * Check more bits within waitpid status We can often make a decision about what happened strictly by looking at the status returned from waitpid. In other cases, we need to call r_debug_handle_signals. If we reach the end of this function without knowing what happened, consider it an error.
2016-06-22 08:34:45 +00:00
p = strchr (input + 3, ' ');
if (p) {
if ((bpi = r_bp_get_index (core->dbg->bp, addr))) {
bpi->data = strdup (p+1);
} else eprintf ("Cannot set command\n");
} else {
eprintf ("|Usage: dbic # cmd\n");
}
break;
case 'e': // "dbie"
if ((bpi = r_bp_get_index (core->dbg->bp, addr))) {
2015-09-14 10:35:38 +00:00
bpi->enabled = true;
} else eprintf ("Cannot unset tracepoint\n");
break;
case 'd': // "dbid"
if ((bpi = r_bp_get_index (core->dbg->bp, addr))) {
2015-09-14 10:35:38 +00:00
bpi->enabled = false;
} else eprintf ("Cannot unset tracepoint\n");
break;
case 's': // "dbis"
if ((bpi = r_bp_get_index (core->dbg->bp, addr))) {
bpi->enabled = !!!bpi->enabled;
} else eprintf ("Cannot unset tracepoint\n");
break;
case 't': // "dbite" "dbitd" ...
switch (input[3]) {
case 'e':
if ((bpi = r_bp_get_index (core->dbg->bp, addr))) {
2015-09-14 10:35:38 +00:00
bpi->trace = true;
} else eprintf ("Cannot unset tracepoint\n");
break;
case 'd':
if ((bpi = r_bp_get_index (core->dbg->bp, addr))) {
2015-09-14 10:35:38 +00:00
bpi->trace = false;
} else eprintf ("Cannot unset tracepoint\n");
break;
case 's':
if ((bpi = r_bp_get_index (core->dbg->bp, addr))) {
bpi->trace = !!!bpi->trace;
} else eprintf ("Cannot unset tracepoint\n");
break;
}
break;
}
break;
2012-02-27 01:40:27 +00:00
case '?':
default:
r_core_cmd_help (core, help_msg);
2012-02-27 01:40:27 +00:00
break;
}
}
static RTreeNode *add_trace_tree_child (Sdb *db, RTree *t, RTreeNode *cur, ut64 addr) {
struct trace_node *t_node;
RTreeNode *node;
char dbkey[TN_KEY_LEN];
snprintf (dbkey, TN_KEY_LEN, TN_KEY_FMT, addr);
t_node = (struct trace_node *)(size_t)sdb_num_get (db, dbkey, NULL);
if (!t_node) {
t_node = (struct trace_node *)malloc (sizeof (*t_node));
t_node->addr = addr;
t_node->refs = 1;
sdb_num_set (db, dbkey, (ut64)(size_t)t_node, 0);
} else {
t_node->refs++;
}
node = r_tree_add_node (t, cur, t_node);
return node;
}
static RCore *_core = NULL;
static void trace_traverse_pre (RTreeNode *n, RTreeVisitor *vis) {
const char *name = "";
struct trace_node *tn = n->data;
unsigned int i;
if (!tn) return;
for (i = 0; i < n->depth - 1; ++i)
r_cons_printf (" ");
if (_core) {
RFlagItem *f = r_flag_get_at (_core->flags, tn->addr);
if (f) name = f->name;
}
r_cons_printf (" 0x%08"PFMT64x" refs %d %s\n",
tn->addr, tn->refs, name);
}
static void trace_traverse (RTree *t) {
RTreeVisitor vis = { 0 };
/* clear the line on stderr, because somebody has written there */
fprintf (stderr, "\x1b[2K\r");
fflush (stderr);
vis.pre_visit = (RTreeNodeVisitCb)trace_traverse_pre;
r_tree_dfs (t, &vis);
}
static void do_debug_trace_calls (RCore *core, ut64 from, ut64 to, ut64 final_addr) {
int shallow_trace = r_config_get_i (core->config, "dbg.shallow_trace");
Sdb *tracenodes = core->dbg->tracenodes;
RTree *tr = core->dbg->tree;
RDebug *dbg = core->dbg;
ut64 debug_to = UT64_MAX;
RTreeNode *cur;
int n = 0;
/* set root if not already present */
r_tree_add_node (tr, NULL, NULL);
cur = tr->root;
2015-09-14 10:35:38 +00:00
while (true) {
ut8 buf[32];
ut64 addr;
RAnalOp aop;
int addr_in_range;
if (r_cons_singleton ()->breaked)
break;
if (r_debug_is_dead (dbg))
break;
if (debug_to != UT64_MAX && !r_debug_continue_until (dbg, debug_to))
2014-11-23 22:31:55 +00:00
break;
else if (!r_debug_step (dbg, 1))
2014-11-23 22:31:55 +00:00
break;
debug_to = UT64_MAX;
2015-09-14 10:35:38 +00:00
if (!r_debug_reg_sync (dbg, R_REG_TYPE_GPR, false))
break;
2015-10-31 00:57:52 +00:00
addr = r_debug_reg_get (dbg, "PC");
addr_in_range = addr >= from && addr < to;
r_io_read_at (core->io, addr, buf, sizeof (buf));
r_anal_op (core->anal, &aop, addr, buf, sizeof (buf));
eprintf (" %d %"PFMT64x"\r", n++, addr);
switch (aop.type) {
case R_ANAL_OP_TYPE_UCALL:
{
ut64 called_addr;
int called_in_range;
// store regs
// step into
// get pc
r_debug_step (dbg, 1);
2015-09-14 10:35:38 +00:00
r_debug_reg_sync (dbg, R_REG_TYPE_GPR, false);
2015-10-31 00:57:52 +00:00
called_addr = r_debug_reg_get (dbg, "PC");
called_in_range = called_addr >= from && called_addr < to;
if (!called_in_range && addr_in_range && shallow_trace)
debug_to = addr;
if (addr_in_range) {
cur = add_trace_tree_child(tracenodes, tr, cur, addr);
if (debug_to != UT64_MAX)
cur = cur->parent;
}
// TODO: push pc+aop.length into the call path stack
break;
}
case R_ANAL_OP_TYPE_CALL:
{
int called_in_range = aop.jump >= from && aop.jump < to;
if (!called_in_range && addr_in_range && shallow_trace)
debug_to = aop.addr + aop.size;
if (addr_in_range) {
cur = add_trace_tree_child(tracenodes, tr, cur, addr);
if (debug_to != UT64_MAX)
cur = cur->parent;
}
break;
}
case R_ANAL_OP_TYPE_RET:
#if 0
// TODO: we must store ret value for each call in the graph path to do this check
r_debug_step (dbg, 1);
2015-09-14 10:35:38 +00:00
r_debug_reg_sync (dbg, R_REG_TYPE_GPR, false);
2015-10-31 00:57:52 +00:00
addr = r_debug_reg_get (dbg, "PC");
// TODO: step into and check return address if correct
// if not correct we are hijacking the control flow (exploit!)
#endif
if (cur != tr->root)
cur = cur->parent;
#if 0
if (addr != gn->addr) {
eprintf ("Oops. invalid return address 0x%08"PFMT64x
"\n0x%08"PFMT64x"\n", addr, gn->addr);
}
#endif
break;
}
}
}
static void debug_trace_calls (RCore *core, const char *input) {
RBreakpointItem *bp_final = NULL;
int t = core->dbg->trace->enabled;
ut64 from = 0, to = UT64_MAX, final_addr = UT64_MAX;
if (r_debug_is_dead (core->dbg)) {
eprintf ("No process to debug.");
return;
}
if (*input == ' ') {
ut64 first_n;
while (*input == ' ') input++;
first_n = r_num_math (core->num, input);
input = strchr (input, ' ');
if (input) {
while (*input == ' ') input++;
from = first_n;
to = r_num_math (core->num, input);
input = strchr (input, ' ');
if (input) {
while (*input == ' ') input++;
final_addr = r_num_math (core->num, input);
}
} else {
final_addr = first_n;
}
}
core->dbg->trace->enabled = 0;
r_cons_break (static_debug_stop, core->dbg);
2015-09-14 10:35:38 +00:00
r_reg_arena_swap (core->dbg->reg, true);
if (final_addr != UT64_MAX) {
int hwbp = r_config_get_i (core->config, "dbg.hwbp");
Major rework to the native debugger (esp on Linux) (#5185) The major contribution here is completely re-worked breakpoint hit/recoil handling. This work fixes #4907 and lays the ground work for future native debugger improvements (multi-threading, etc). * Give a human friendly type to enums * Change many wait functions to return RDebugReasonType * Better return checking (from r_debug_reg_sync, r_bp_restore) * Optimized register synchronization * Lots of comments and whitespace changes * Improved inferior death detection Handle EXIT_PID events differently than DEAD process events * Move breakpoint/recoil handling to wait/cont/step Rather than handing breakpoint related things inside cmd_debug.c, do that inside the r_debug API functions. This seems like the most logical place for it to live since it should apply to just about any platform/architecture. This also centralizes calling into "cmd.bp" handling via the CoreBind callback. * Track how the caller wishes to continue It turns out that handling break point recoils is very complicated. The ptrace API on Linux returns SIGTRAP for just about every type of operation (not just breakpoints getting hit). Add the "recoil_mode" flag to indicate whether we are single-stepping or continuing and whether or not we are inside the recoil. * Proper handling for swstep=true Since r_debug_step_soft calls r_debug_continue, it's already hitting the recoil case there. Move the recoil handling from r_debug_step to r_debug_step_hard only. For the swstep=true case, special handling is required inside r_debug_recoil. By resetting all of the breakpoints except the one we just hit, we ensure we can step the original instruction and hit the new swstep breakpoint. Add a new bp function called r_bp_restore_except to do this. To make matters worse, we cannot use a BreakpointItem pointer because that leads to a use-after-free condition. Instead, we the breakpoint address instead. Now breakpoints should work regardless of the swtep setting. * Always call the recoil before continuing Some callers of r_debug_continue might not have ever inserted any breakpoints before. If we don't restore breakpoints before each call to the underlying continue we won't hit them. * Hide software step breakpoint events from the user When a breakpoint even happens due to a software-step, hide it from the user. They aren't really breakpoints as far as they are concerned. * Improve process exit handling on Linux There are three types of process exiting events on Linux: 1. PTRACE_EVENT_EXIT occurs just before a process exits. It's not possible to prevent it from exiting, but it can be used to inspect the pre-exit state. 2. The process can exit for a variety of reasons and we can notice when we call waitpid(2). 3. The process could die randomly on us :-/ On Windows, h->wait will return R_DEBUG_REASON_EXIT_PID, but it's more likely on Linux to find out the process is already dead. * Check more bits within waitpid status We can often make a decision about what happened strictly by looking at the status returned from waitpid. In other cases, we need to call r_debug_handle_signals. If we reach the end of this function without knowing what happened, consider it an error.
2016-06-22 08:34:45 +00:00
bp_final = r_debug_bp_add (core->dbg, final_addr, hwbp, NULL, 0);
if (!bp_final)
eprintf ("Cannot set breakpoint at final address (%"PFMT64x")\n", final_addr);
}
do_debug_trace_calls (core, from, to, final_addr);
if (bp_final)
r_bp_del (core->dbg->bp, final_addr);
_core = core;
trace_traverse (core->dbg->tree);
core->dbg->trace->enabled = t;
r_cons_break_end();
}
static void r_core_debug_esil (RCore *core, const char *input) {
switch (input[0]) {
case ' ':
{
Major rework to the native debugger (esp on Linux) (#5185) The major contribution here is completely re-worked breakpoint hit/recoil handling. This work fixes #4907 and lays the ground work for future native debugger improvements (multi-threading, etc). * Give a human friendly type to enums * Change many wait functions to return RDebugReasonType * Better return checking (from r_debug_reg_sync, r_bp_restore) * Optimized register synchronization * Lots of comments and whitespace changes * Improved inferior death detection Handle EXIT_PID events differently than DEAD process events * Move breakpoint/recoil handling to wait/cont/step Rather than handing breakpoint related things inside cmd_debug.c, do that inside the r_debug API functions. This seems like the most logical place for it to live since it should apply to just about any platform/architecture. This also centralizes calling into "cmd.bp" handling via the CoreBind callback. * Track how the caller wishes to continue It turns out that handling break point recoils is very complicated. The ptrace API on Linux returns SIGTRAP for just about every type of operation (not just breakpoints getting hit). Add the "recoil_mode" flag to indicate whether we are single-stepping or continuing and whether or not we are inside the recoil. * Proper handling for swstep=true Since r_debug_step_soft calls r_debug_continue, it's already hitting the recoil case there. Move the recoil handling from r_debug_step to r_debug_step_hard only. For the swstep=true case, special handling is required inside r_debug_recoil. By resetting all of the breakpoints except the one we just hit, we ensure we can step the original instruction and hit the new swstep breakpoint. Add a new bp function called r_bp_restore_except to do this. To make matters worse, we cannot use a BreakpointItem pointer because that leads to a use-after-free condition. Instead, we the breakpoint address instead. Now breakpoints should work regardless of the swtep setting. * Always call the recoil before continuing Some callers of r_debug_continue might not have ever inserted any breakpoints before. If we don't restore breakpoints before each call to the underlying continue we won't hit them. * Hide software step breakpoint events from the user When a breakpoint even happens due to a software-step, hide it from the user. They aren't really breakpoints as far as they are concerned. * Improve process exit handling on Linux There are three types of process exiting events on Linux: 1. PTRACE_EVENT_EXIT occurs just before a process exits. It's not possible to prevent it from exiting, but it can be used to inspect the pre-exit state. 2. The process can exit for a variety of reasons and we can notice when we call waitpid(2). 3. The process could die randomly on us :-/ On Windows, h->wait will return R_DEBUG_REASON_EXIT_PID, but it's more likely on Linux to find out the process is already dead. * Check more bits within waitpid status We can often make a decision about what happened strictly by looking at the status returned from waitpid. In other cases, we need to call r_debug_handle_signals. If we reach the end of this function without knowing what happened, consider it an error.
2016-06-22 08:34:45 +00:00
char *line = strdup (input + 1);
char *p, *q;
int done = 0;
int rwx = 0, dev = 0;
p = strchr (line, ' ');
if (p) {
*p++ = 0;
if (strchr (line, 'r')) rwx |= R_IO_READ;
if (strchr (line, 'w')) rwx |= R_IO_WRITE;
if (strchr (line, 'x')) rwx |= R_IO_EXEC;
q = strchr (p, ' ');
if (q) {
*q++ = 0;
dev = p[0];
if (q) {
r_debug_esil_watch (core->dbg, rwx, dev, q);
done = 1;
}
}
}
if (!done) {
eprintf ("Usage: de [rwx] [reg|mem] [expr]\n");
}
2015-07-21 16:08:32 +00:00
free (line);
}
break;
case '-':
r_debug_esil_watch_reset (core->dbg);
break;
case 's':
if (input[1] == 'u' && input[2] == ' ') { // "desu"
ut64 addr, naddr, fin = r_num_math (core->num, input + 2);
r_core_cmd0 (core, "aei");
2015-10-31 00:57:52 +00:00
addr = r_debug_reg_get (core->dbg, "PC");
while (addr != fin) {
r_debug_esil_prestep (core->dbg, r_config_get_i (
core->config, "esil.prestep"));
r_debug_esil_step (core->dbg, 1);
2015-10-31 00:57:52 +00:00
naddr = r_debug_reg_get (core->dbg, "PC");
if (naddr == addr) {
eprintf ("Detected loophole\n");
break;
}
addr = naddr;
}
} else if (input[1] == '?' || !input[1]) {
// TODO: use r_core_help here
eprintf ("Usage: des[u] [arg]\n");
eprintf (" des [num-of-instructions]\n");
eprintf (" desu [address]\n");
} else {
r_core_cmd0 (core, "aei");
r_debug_esil_prestep (core->dbg, r_config_get_i (core->config, "esil.prestep"));
// continue
Major rework to the native debugger (esp on Linux) (#5185) The major contribution here is completely re-worked breakpoint hit/recoil handling. This work fixes #4907 and lays the ground work for future native debugger improvements (multi-threading, etc). * Give a human friendly type to enums * Change many wait functions to return RDebugReasonType * Better return checking (from r_debug_reg_sync, r_bp_restore) * Optimized register synchronization * Lots of comments and whitespace changes * Improved inferior death detection Handle EXIT_PID events differently than DEAD process events * Move breakpoint/recoil handling to wait/cont/step Rather than handing breakpoint related things inside cmd_debug.c, do that inside the r_debug API functions. This seems like the most logical place for it to live since it should apply to just about any platform/architecture. This also centralizes calling into "cmd.bp" handling via the CoreBind callback. * Track how the caller wishes to continue It turns out that handling break point recoils is very complicated. The ptrace API on Linux returns SIGTRAP for just about every type of operation (not just breakpoints getting hit). Add the "recoil_mode" flag to indicate whether we are single-stepping or continuing and whether or not we are inside the recoil. * Proper handling for swstep=true Since r_debug_step_soft calls r_debug_continue, it's already hitting the recoil case there. Move the recoil handling from r_debug_step to r_debug_step_hard only. For the swstep=true case, special handling is required inside r_debug_recoil. By resetting all of the breakpoints except the one we just hit, we ensure we can step the original instruction and hit the new swstep breakpoint. Add a new bp function called r_bp_restore_except to do this. To make matters worse, we cannot use a BreakpointItem pointer because that leads to a use-after-free condition. Instead, we the breakpoint address instead. Now breakpoints should work regardless of the swtep setting. * Always call the recoil before continuing Some callers of r_debug_continue might not have ever inserted any breakpoints before. If we don't restore breakpoints before each call to the underlying continue we won't hit them. * Hide software step breakpoint events from the user When a breakpoint even happens due to a software-step, hide it from the user. They aren't really breakpoints as far as they are concerned. * Improve process exit handling on Linux There are three types of process exiting events on Linux: 1. PTRACE_EVENT_EXIT occurs just before a process exits. It's not possible to prevent it from exiting, but it can be used to inspect the pre-exit state. 2. The process can exit for a variety of reasons and we can notice when we call waitpid(2). 3. The process could die randomly on us :-/ On Windows, h->wait will return R_DEBUG_REASON_EXIT_PID, but it's more likely on Linux to find out the process is already dead. * Check more bits within waitpid status We can often make a decision about what happened strictly by looking at the status returned from waitpid. In other cases, we need to call r_debug_handle_signals. If we reach the end of this function without knowing what happened, consider it an error.
2016-06-22 08:34:45 +00:00
r_debug_esil_step (core->dbg, r_num_math (core->num, input + 1));
}
break;
case 'c':
if (r_debug_esil_watch_empty (core->dbg)) {
eprintf ("Error: no esil watchpoints defined\n");
} else {
r_core_cmd0 (core, "aei");
r_debug_esil_prestep (core->dbg, r_config_get_i (core->config, "esil.prestep"));
r_debug_esil_continue (core->dbg);
}
break;
case 0:
// list
r_debug_esil_watch_list (core->dbg);
break;
case '?':
default:
eprintf ("Usage: de[-sc] [rwx] [rm] [expr]\n");
eprintf ("Examples:\n");
eprintf ("> de # list esil watchpoints\n");
eprintf ("> de-* # delete all esil watchpoints\n");
eprintf ("> de r r rip # stop when reads rip\n");
eprintf ("> de rw m ADDR # stop when read or write in ADDR\n");
eprintf ("> de w r rdx # stop when rdx register is modified\n");
eprintf ("> de x m FROM..TO # stop when rip in range\n");
eprintf ("> dec # continue execution until matching expression\n");
eprintf ("> des [num] # step-in N instructions with esildebug\n");
eprintf ("> desu [addr] # esildebug until specific address\n");
eprintf ("TODO: Add support for conditionals in expressions like rcx == 4 or rcx<10\n");
eprintf ("TODO: Turn on/off debugger trace of esil debugging\n");
break;
}
}
static void r_core_debug_kill (RCore *core, const char *input) {
if (!input || *input=='?') {
if (input && input[1]) {
Major rework to the native debugger (esp on Linux) (#5185) The major contribution here is completely re-worked breakpoint hit/recoil handling. This work fixes #4907 and lays the ground work for future native debugger improvements (multi-threading, etc). * Give a human friendly type to enums * Change many wait functions to return RDebugReasonType * Better return checking (from r_debug_reg_sync, r_bp_restore) * Optimized register synchronization * Lots of comments and whitespace changes * Improved inferior death detection Handle EXIT_PID events differently than DEAD process events * Move breakpoint/recoil handling to wait/cont/step Rather than handing breakpoint related things inside cmd_debug.c, do that inside the r_debug API functions. This seems like the most logical place for it to live since it should apply to just about any platform/architecture. This also centralizes calling into "cmd.bp" handling via the CoreBind callback. * Track how the caller wishes to continue It turns out that handling break point recoils is very complicated. The ptrace API on Linux returns SIGTRAP for just about every type of operation (not just breakpoints getting hit). Add the "recoil_mode" flag to indicate whether we are single-stepping or continuing and whether or not we are inside the recoil. * Proper handling for swstep=true Since r_debug_step_soft calls r_debug_continue, it's already hitting the recoil case there. Move the recoil handling from r_debug_step to r_debug_step_hard only. For the swstep=true case, special handling is required inside r_debug_recoil. By resetting all of the breakpoints except the one we just hit, we ensure we can step the original instruction and hit the new swstep breakpoint. Add a new bp function called r_bp_restore_except to do this. To make matters worse, we cannot use a BreakpointItem pointer because that leads to a use-after-free condition. Instead, we the breakpoint address instead. Now breakpoints should work regardless of the swtep setting. * Always call the recoil before continuing Some callers of r_debug_continue might not have ever inserted any breakpoints before. If we don't restore breakpoints before each call to the underlying continue we won't hit them. * Hide software step breakpoint events from the user When a breakpoint even happens due to a software-step, hide it from the user. They aren't really breakpoints as far as they are concerned. * Improve process exit handling on Linux There are three types of process exiting events on Linux: 1. PTRACE_EVENT_EXIT occurs just before a process exits. It's not possible to prevent it from exiting, but it can be used to inspect the pre-exit state. 2. The process can exit for a variety of reasons and we can notice when we call waitpid(2). 3. The process could die randomly on us :-/ On Windows, h->wait will return R_DEBUG_REASON_EXIT_PID, but it's more likely on Linux to find out the process is already dead. * Check more bits within waitpid status We can often make a decision about what happened strictly by looking at the status returned from waitpid. In other cases, we need to call r_debug_handle_signals. If we reach the end of this function without knowing what happened, consider it an error.
2016-06-22 08:34:45 +00:00
const char *signame, *arg = input + 1;
int signum = atoi (arg);
if (signum>0) {
signame = r_debug_signal_resolve_i (core->dbg, signum);
if (signame)
r_cons_println (signame);
} else {
signum = r_debug_signal_resolve (core->dbg, arg);
if (signum > 0) {
r_cons_printf ("%d\n", signum);
}
}
} else {
const char * help_message[] = {
"Usage: dk", "", "Signal commands",
"dk", "", "List all signal handlers of child process",
"dk", " <signal>", "Send KILL signal to child",
"dk", " <signal>=1", "Set signal handler for <signal> in child",
"dk?", "<signal>", "Name/signum resolver",
"dko", " <signal>", "Reset skip or cont options for given signal",
"dko", " <signal> [|skip|cont]", "On signal SKIP handler or CONT into",
2015-09-02 11:19:09 +00:00
"dkj", "", "List all signal handlers in JSON",
NULL
};
r_core_cmd_help (core, help_message);
}
} else if (*input=='o') {
switch (input[1]) {
case 0: // "dko" - list signal skip/conts
r_debug_signal_list (core->dbg, 1);
break;
case ' ': // dko SIGNAL
if (input[2]) {
char *p, *name = strdup (input + 2);
int signum = atoi (name);
p = strchr (name, ' ');
if (p) *p++ = 0; /* got SIGNAL and an action */
// Actions:
// - pass
// - trace
// - stop
if (signum<1) signum = r_debug_signal_resolve (core->dbg, name);
if (signum>0) {
if (!p || !p[0]) { // stop (the usual)
r_debug_signal_setup (core->dbg, signum, 0);
} else if (*p == 's') { // skip
r_debug_signal_setup (core->dbg, signum, R_DBG_SIGNAL_SKIP);
} else if (*p == 'c') { // cont
r_debug_signal_setup (core->dbg, signum, R_DBG_SIGNAL_CONT);
} else {
eprintf ("Invalid option: %s\n", p);
}
} else {
eprintf ("Invalid signal: %s\n", input + 2);
}
free (name);
break;
}
/* fall through */
case '?':
default:
{
const char* help_msg[] = {
"Usage:", "dko", " # Signal handling commands",
"dko", "", "List existing signal handling",
"dko", " [signal]", "Clear handling for a signal",
"dko", " [signal] [skip|cont]", "Set handling for a signal",
NULL
};
r_core_cmd_help (core, help_msg);
eprintf ("NOTE: [signal] can be a number or a string that resolves with dk?\n"
" skip means do not enter into the signal handler\n"
" continue means enter into the signal handler\n");
}
}
2015-10-05 12:43:17 +00:00
} else if (*input == 'j') {
2015-09-02 11:19:09 +00:00
r_debug_signal_list (core->dbg, 2);
} else if (!*input) {
r_debug_signal_list (core->dbg, 0);
#if 0
RListIter *iter;
RDebugSignal *ds;
eprintf ("TODO: list signal handlers of child\n");
RList *list = r_debug_kill_list (core->dbg);
r_list_foreach (list, iter, ds) {
// TODO: resolve signal name by number and show handler offset
eprintf ("--> %d\n", ds->num);
}
r_list_free (list);
#endif
} else {
int sig = atoi (input);
char *p = strchr (input, '=');
if (p) {
r_debug_kill_setup (core->dbg, sig, r_num_math (core->num, p+1));
} else {
r_debug_kill (core->dbg, core->dbg->pid, core->dbg->tid, sig);
}
}
}
static bool cmd_dcu (RCore *core, const char *input) {
const char *ptr = NULL;
ut64 from, to, pc;
bool dcu_range = false;
bool invalid = (!input[0] || !input[1] || !input[2]);
if (invalid || (input[2] != ' ' && input[2] != '.')) {
eprintf ("|Usage: dcu <address>\n");
eprintf ("|Usage: dcu[..tail]\n");
eprintf ("|Usage: dcu [from] [to]\n");
return false;
}
from = UT64_MAX;
if (input[2] == '.') {
Major rework to the native debugger (esp on Linux) (#5185) The major contribution here is completely re-worked breakpoint hit/recoil handling. This work fixes #4907 and lays the ground work for future native debugger improvements (multi-threading, etc). * Give a human friendly type to enums * Change many wait functions to return RDebugReasonType * Better return checking (from r_debug_reg_sync, r_bp_restore) * Optimized register synchronization * Lots of comments and whitespace changes * Improved inferior death detection Handle EXIT_PID events differently than DEAD process events * Move breakpoint/recoil handling to wait/cont/step Rather than handing breakpoint related things inside cmd_debug.c, do that inside the r_debug API functions. This seems like the most logical place for it to live since it should apply to just about any platform/architecture. This also centralizes calling into "cmd.bp" handling via the CoreBind callback. * Track how the caller wishes to continue It turns out that handling break point recoils is very complicated. The ptrace API on Linux returns SIGTRAP for just about every type of operation (not just breakpoints getting hit). Add the "recoil_mode" flag to indicate whether we are single-stepping or continuing and whether or not we are inside the recoil. * Proper handling for swstep=true Since r_debug_step_soft calls r_debug_continue, it's already hitting the recoil case there. Move the recoil handling from r_debug_step to r_debug_step_hard only. For the swstep=true case, special handling is required inside r_debug_recoil. By resetting all of the breakpoints except the one we just hit, we ensure we can step the original instruction and hit the new swstep breakpoint. Add a new bp function called r_bp_restore_except to do this. To make matters worse, we cannot use a BreakpointItem pointer because that leads to a use-after-free condition. Instead, we the breakpoint address instead. Now breakpoints should work regardless of the swtep setting. * Always call the recoil before continuing Some callers of r_debug_continue might not have ever inserted any breakpoints before. If we don't restore breakpoints before each call to the underlying continue we won't hit them. * Hide software step breakpoint events from the user When a breakpoint even happens due to a software-step, hide it from the user. They aren't really breakpoints as far as they are concerned. * Improve process exit handling on Linux There are three types of process exiting events on Linux: 1. PTRACE_EVENT_EXIT occurs just before a process exits. It's not possible to prevent it from exiting, but it can be used to inspect the pre-exit state. 2. The process can exit for a variety of reasons and we can notice when we call waitpid(2). 3. The process could die randomly on us :-/ On Windows, h->wait will return R_DEBUG_REASON_EXIT_PID, but it's more likely on Linux to find out the process is already dead. * Check more bits within waitpid status We can often make a decision about what happened strictly by looking at the status returned from waitpid. In other cases, we need to call r_debug_handle_signals. If we reach the end of this function without knowing what happened, consider it an error.
2016-06-22 08:34:45 +00:00
ptr = strchr (input + 3, ' ');
if (ptr) { // TODO: put '\0' in *ptr to avoid
from = r_num_tail (core->num, core->offset, input + 2);
if (ptr[1]=='.') {
to = r_num_tail (core->num, core->offset, ptr+2);
} else {
to = r_num_math (core->num, ptr+1);
}
dcu_range = true;
} else {
from = r_num_tail (core->num, core->offset, input + 2);
}
} else {
Major rework to the native debugger (esp on Linux) (#5185) The major contribution here is completely re-worked breakpoint hit/recoil handling. This work fixes #4907 and lays the ground work for future native debugger improvements (multi-threading, etc). * Give a human friendly type to enums * Change many wait functions to return RDebugReasonType * Better return checking (from r_debug_reg_sync, r_bp_restore) * Optimized register synchronization * Lots of comments and whitespace changes * Improved inferior death detection Handle EXIT_PID events differently than DEAD process events * Move breakpoint/recoil handling to wait/cont/step Rather than handing breakpoint related things inside cmd_debug.c, do that inside the r_debug API functions. This seems like the most logical place for it to live since it should apply to just about any platform/architecture. This also centralizes calling into "cmd.bp" handling via the CoreBind callback. * Track how the caller wishes to continue It turns out that handling break point recoils is very complicated. The ptrace API on Linux returns SIGTRAP for just about every type of operation (not just breakpoints getting hit). Add the "recoil_mode" flag to indicate whether we are single-stepping or continuing and whether or not we are inside the recoil. * Proper handling for swstep=true Since r_debug_step_soft calls r_debug_continue, it's already hitting the recoil case there. Move the recoil handling from r_debug_step to r_debug_step_hard only. For the swstep=true case, special handling is required inside r_debug_recoil. By resetting all of the breakpoints except the one we just hit, we ensure we can step the original instruction and hit the new swstep breakpoint. Add a new bp function called r_bp_restore_except to do this. To make matters worse, we cannot use a BreakpointItem pointer because that leads to a use-after-free condition. Instead, we the breakpoint address instead. Now breakpoints should work regardless of the swtep setting. * Always call the recoil before continuing Some callers of r_debug_continue might not have ever inserted any breakpoints before. If we don't restore breakpoints before each call to the underlying continue we won't hit them. * Hide software step breakpoint events from the user When a breakpoint even happens due to a software-step, hide it from the user. They aren't really breakpoints as far as they are concerned. * Improve process exit handling on Linux There are three types of process exiting events on Linux: 1. PTRACE_EVENT_EXIT occurs just before a process exits. It's not possible to prevent it from exiting, but it can be used to inspect the pre-exit state. 2. The process can exit for a variety of reasons and we can notice when we call waitpid(2). 3. The process could die randomly on us :-/ On Windows, h->wait will return R_DEBUG_REASON_EXIT_PID, but it's more likely on Linux to find out the process is already dead. * Check more bits within waitpid status We can often make a decision about what happened strictly by looking at the status returned from waitpid. In other cases, we need to call r_debug_handle_signals. If we reach the end of this function without knowing what happened, consider it an error.
2016-06-22 08:34:45 +00:00
ptr = strchr (input + 3, ' ');
if (ptr) { // TODO: put '\0' in *ptr to avoid
Major rework to the native debugger (esp on Linux) (#5185) The major contribution here is completely re-worked breakpoint hit/recoil handling. This work fixes #4907 and lays the ground work for future native debugger improvements (multi-threading, etc). * Give a human friendly type to enums * Change many wait functions to return RDebugReasonType * Better return checking (from r_debug_reg_sync, r_bp_restore) * Optimized register synchronization * Lots of comments and whitespace changes * Improved inferior death detection Handle EXIT_PID events differently than DEAD process events * Move breakpoint/recoil handling to wait/cont/step Rather than handing breakpoint related things inside cmd_debug.c, do that inside the r_debug API functions. This seems like the most logical place for it to live since it should apply to just about any platform/architecture. This also centralizes calling into "cmd.bp" handling via the CoreBind callback. * Track how the caller wishes to continue It turns out that handling break point recoils is very complicated. The ptrace API on Linux returns SIGTRAP for just about every type of operation (not just breakpoints getting hit). Add the "recoil_mode" flag to indicate whether we are single-stepping or continuing and whether or not we are inside the recoil. * Proper handling for swstep=true Since r_debug_step_soft calls r_debug_continue, it's already hitting the recoil case there. Move the recoil handling from r_debug_step to r_debug_step_hard only. For the swstep=true case, special handling is required inside r_debug_recoil. By resetting all of the breakpoints except the one we just hit, we ensure we can step the original instruction and hit the new swstep breakpoint. Add a new bp function called r_bp_restore_except to do this. To make matters worse, we cannot use a BreakpointItem pointer because that leads to a use-after-free condition. Instead, we the breakpoint address instead. Now breakpoints should work regardless of the swtep setting. * Always call the recoil before continuing Some callers of r_debug_continue might not have ever inserted any breakpoints before. If we don't restore breakpoints before each call to the underlying continue we won't hit them. * Hide software step breakpoint events from the user When a breakpoint even happens due to a software-step, hide it from the user. They aren't really breakpoints as far as they are concerned. * Improve process exit handling on Linux There are three types of process exiting events on Linux: 1. PTRACE_EVENT_EXIT occurs just before a process exits. It's not possible to prevent it from exiting, but it can be used to inspect the pre-exit state. 2. The process can exit for a variety of reasons and we can notice when we call waitpid(2). 3. The process could die randomly on us :-/ On Windows, h->wait will return R_DEBUG_REASON_EXIT_PID, but it's more likely on Linux to find out the process is already dead. * Check more bits within waitpid status We can often make a decision about what happened strictly by looking at the status returned from waitpid. In other cases, we need to call r_debug_handle_signals. If we reach the end of this function without knowing what happened, consider it an error.
2016-06-22 08:34:45 +00:00
from = r_num_math (core->num, input + 3);
if (ptr[1]=='.') {
to = r_num_tail (core->num, core->offset, ptr+2);
} else {
to = r_num_math (core->num, ptr+1);
}
dcu_range = true;
} else {
Major rework to the native debugger (esp on Linux) (#5185) The major contribution here is completely re-worked breakpoint hit/recoil handling. This work fixes #4907 and lays the ground work for future native debugger improvements (multi-threading, etc). * Give a human friendly type to enums * Change many wait functions to return RDebugReasonType * Better return checking (from r_debug_reg_sync, r_bp_restore) * Optimized register synchronization * Lots of comments and whitespace changes * Improved inferior death detection Handle EXIT_PID events differently than DEAD process events * Move breakpoint/recoil handling to wait/cont/step Rather than handing breakpoint related things inside cmd_debug.c, do that inside the r_debug API functions. This seems like the most logical place for it to live since it should apply to just about any platform/architecture. This also centralizes calling into "cmd.bp" handling via the CoreBind callback. * Track how the caller wishes to continue It turns out that handling break point recoils is very complicated. The ptrace API on Linux returns SIGTRAP for just about every type of operation (not just breakpoints getting hit). Add the "recoil_mode" flag to indicate whether we are single-stepping or continuing and whether or not we are inside the recoil. * Proper handling for swstep=true Since r_debug_step_soft calls r_debug_continue, it's already hitting the recoil case there. Move the recoil handling from r_debug_step to r_debug_step_hard only. For the swstep=true case, special handling is required inside r_debug_recoil. By resetting all of the breakpoints except the one we just hit, we ensure we can step the original instruction and hit the new swstep breakpoint. Add a new bp function called r_bp_restore_except to do this. To make matters worse, we cannot use a BreakpointItem pointer because that leads to a use-after-free condition. Instead, we the breakpoint address instead. Now breakpoints should work regardless of the swtep setting. * Always call the recoil before continuing Some callers of r_debug_continue might not have ever inserted any breakpoints before. If we don't restore breakpoints before each call to the underlying continue we won't hit them. * Hide software step breakpoint events from the user When a breakpoint even happens due to a software-step, hide it from the user. They aren't really breakpoints as far as they are concerned. * Improve process exit handling on Linux There are three types of process exiting events on Linux: 1. PTRACE_EVENT_EXIT occurs just before a process exits. It's not possible to prevent it from exiting, but it can be used to inspect the pre-exit state. 2. The process can exit for a variety of reasons and we can notice when we call waitpid(2). 3. The process could die randomly on us :-/ On Windows, h->wait will return R_DEBUG_REASON_EXIT_PID, but it's more likely on Linux to find out the process is already dead. * Check more bits within waitpid status We can often make a decision about what happened strictly by looking at the status returned from waitpid. In other cases, we need to call r_debug_handle_signals. If we reach the end of this function without knowing what happened, consider it an error.
2016-06-22 08:34:45 +00:00
from = r_num_math (core->num, input + 3);
}
}
if (from == UT64_MAX) {
eprintf ("Cannot continue until address 0\n");
return false;
}
if (dcu_range) {
// TODO : handle ^C here
r_cons_break (NULL, NULL);
do {
if (r_cons_is_breaked ())
break;
r_debug_step (core->dbg, 1);
r_debug_reg_sync (core->dbg, R_REG_TYPE_GPR, false);
pc = r_debug_reg_get (core->dbg, "PC");
eprintf ("Continue 0x%08"PFMT64x" > 0x%08"PFMT64x" < 0x%08"PFMT64x"\n",
from, pc, to);
} while (pc < from || pc > to);
r_cons_break_end ();
} else {
ut64 addr = from;
2016-01-11 00:43:05 +00:00
eprintf ("Continue until 0x%08"PFMT64x" using %d bpsize\n", addr, core->dbg->bpsize);
r_reg_arena_swap (core->dbg->reg, true);
2016-01-11 00:43:05 +00:00
r_bp_add_sw (core->dbg->bp, addr, core->dbg->bpsize, R_BP_PROT_EXEC);
r_debug_continue (core->dbg);
r_bp_del (core->dbg->bp, addr);
}
return true;
}
static int cmd_debug_continue (RCore *core, const char *input) {
int pid, old_pid, signum;
2012-02-27 01:40:27 +00:00
char *ptr;
const char * help_message[] = {
"Usage: dc", "", "Execution continuation commands",
"dc", "", "Continue execution of all children",
"dc", " <pid>", "Continue execution of pid",
"dc", "[-pid]", "Stop execution of pid",
"dca", " [sym] [sym].", "Continue at every hit on any given symbol",
"dcc", "", "Continue until call (use step into)",
"dccu", "", "Continue until unknown call (call reg)",
"dcf", "", "Continue until fork (TODO)",
"dck", " <signal> <pid>", "Continue sending signal to process",
"dco", " <num>", "Step over <num> instructions",
"dcp", "", "Continue until program code (mapped io section)",
"dcr", "", "Continue until ret (uses step over)",
"dcs", " <num>", "Continue until syscall",
"dct", " <len>", "Traptrace from curseek to len, no argument to list",
"dcu", "[..end|addr] ([end])", "Continue until address (or range)",
/*"TODO: dcu/dcr needs dbg.untilover=true??",*/
/*"TODO: same for only user/libs side, to avoid steping into libs",*/
/*"TODO: support for threads?",*/
NULL
};
// TODO: we must use this for step 'ds' too maybe...
switch (input[1]) {
case 0: // "dc"
r_reg_arena_swap (core->dbg->reg, true);
r_debug_continue (core->dbg);
break;
2015-10-31 02:45:14 +00:00
case 'a': // "dca"
eprintf ("TODO: dca\n");
break;
2015-10-31 02:45:14 +00:00
case 'f': // "dcf"
eprintf ("[+] Running 'dcs vfork fork clone' behind the scenes...\n");
// we should stop in fork and vfork syscalls
//TODO: multiple syscalls not handled yet
// r_core_cmd0 (core, "dcs vfork fork");
r_core_cmd0 (core, "dcs vfork fork clone");
break;
2015-10-31 02:45:14 +00:00
case 'c': // "dcc"
2015-09-14 10:35:38 +00:00
r_reg_arena_swap (core->dbg->reg, true);
if (input[2] == 'u') {
r_debug_continue_until_optype (core->dbg, R_ANAL_OP_TYPE_UCALL, 0);
} else {
r_debug_continue_until_optype (core->dbg, R_ANAL_OP_TYPE_CALL, 0);
}
break;
case 'r':
2015-09-14 10:35:38 +00:00
r_reg_arena_swap (core->dbg->reg, true);
r_debug_continue_until_optype (core->dbg, R_ANAL_OP_TYPE_RET, 1);
break;
case 'k':
// select pid and r_debug_continue_kill (core->dbg,
2015-09-14 10:35:38 +00:00
r_reg_arena_swap (core->dbg->reg, true);
Major rework to the native debugger (esp on Linux) (#5185) The major contribution here is completely re-worked breakpoint hit/recoil handling. This work fixes #4907 and lays the ground work for future native debugger improvements (multi-threading, etc). * Give a human friendly type to enums * Change many wait functions to return RDebugReasonType * Better return checking (from r_debug_reg_sync, r_bp_restore) * Optimized register synchronization * Lots of comments and whitespace changes * Improved inferior death detection Handle EXIT_PID events differently than DEAD process events * Move breakpoint/recoil handling to wait/cont/step Rather than handing breakpoint related things inside cmd_debug.c, do that inside the r_debug API functions. This seems like the most logical place for it to live since it should apply to just about any platform/architecture. This also centralizes calling into "cmd.bp" handling via the CoreBind callback. * Track how the caller wishes to continue It turns out that handling break point recoils is very complicated. The ptrace API on Linux returns SIGTRAP for just about every type of operation (not just breakpoints getting hit). Add the "recoil_mode" flag to indicate whether we are single-stepping or continuing and whether or not we are inside the recoil. * Proper handling for swstep=true Since r_debug_step_soft calls r_debug_continue, it's already hitting the recoil case there. Move the recoil handling from r_debug_step to r_debug_step_hard only. For the swstep=true case, special handling is required inside r_debug_recoil. By resetting all of the breakpoints except the one we just hit, we ensure we can step the original instruction and hit the new swstep breakpoint. Add a new bp function called r_bp_restore_except to do this. To make matters worse, we cannot use a BreakpointItem pointer because that leads to a use-after-free condition. Instead, we the breakpoint address instead. Now breakpoints should work regardless of the swtep setting. * Always call the recoil before continuing Some callers of r_debug_continue might not have ever inserted any breakpoints before. If we don't restore breakpoints before each call to the underlying continue we won't hit them. * Hide software step breakpoint events from the user When a breakpoint even happens due to a software-step, hide it from the user. They aren't really breakpoints as far as they are concerned. * Improve process exit handling on Linux There are three types of process exiting events on Linux: 1. PTRACE_EVENT_EXIT occurs just before a process exits. It's not possible to prevent it from exiting, but it can be used to inspect the pre-exit state. 2. The process can exit for a variety of reasons and we can notice when we call waitpid(2). 3. The process could die randomly on us :-/ On Windows, h->wait will return R_DEBUG_REASON_EXIT_PID, but it's more likely on Linux to find out the process is already dead. * Check more bits within waitpid status We can often make a decision about what happened strictly by looking at the status returned from waitpid. In other cases, we need to call r_debug_handle_signals. If we reach the end of this function without knowing what happened, consider it an error.
2016-06-22 08:34:45 +00:00
signum = r_num_math (core->num, input + 2);
ptr = strchr (input + 3, ' ');
if (ptr) {
int old_pid = core->dbg->pid;
int old_tid = core->dbg->tid;
int pid = atoi (ptr+1);
int tid = pid; // XXX
*ptr = 0;
r_debug_select (core->dbg, pid, tid);
r_debug_continue_kill (core->dbg, signum);
r_debug_select (core->dbg, old_pid, old_tid);
} else {
r_debug_continue_kill (core->dbg, signum);
}
break;
case 's':
switch (input[2]) {
case '*':
cmd_debug_cont_syscall (core, "-1");
break;
case ' ':
Major rework to the native debugger (esp on Linux) (#5185) The major contribution here is completely re-worked breakpoint hit/recoil handling. This work fixes #4907 and lays the ground work for future native debugger improvements (multi-threading, etc). * Give a human friendly type to enums * Change many wait functions to return RDebugReasonType * Better return checking (from r_debug_reg_sync, r_bp_restore) * Optimized register synchronization * Lots of comments and whitespace changes * Improved inferior death detection Handle EXIT_PID events differently than DEAD process events * Move breakpoint/recoil handling to wait/cont/step Rather than handing breakpoint related things inside cmd_debug.c, do that inside the r_debug API functions. This seems like the most logical place for it to live since it should apply to just about any platform/architecture. This also centralizes calling into "cmd.bp" handling via the CoreBind callback. * Track how the caller wishes to continue It turns out that handling break point recoils is very complicated. The ptrace API on Linux returns SIGTRAP for just about every type of operation (not just breakpoints getting hit). Add the "recoil_mode" flag to indicate whether we are single-stepping or continuing and whether or not we are inside the recoil. * Proper handling for swstep=true Since r_debug_step_soft calls r_debug_continue, it's already hitting the recoil case there. Move the recoil handling from r_debug_step to r_debug_step_hard only. For the swstep=true case, special handling is required inside r_debug_recoil. By resetting all of the breakpoints except the one we just hit, we ensure we can step the original instruction and hit the new swstep breakpoint. Add a new bp function called r_bp_restore_except to do this. To make matters worse, we cannot use a BreakpointItem pointer because that leads to a use-after-free condition. Instead, we the breakpoint address instead. Now breakpoints should work regardless of the swtep setting. * Always call the recoil before continuing Some callers of r_debug_continue might not have ever inserted any breakpoints before. If we don't restore breakpoints before each call to the underlying continue we won't hit them. * Hide software step breakpoint events from the user When a breakpoint even happens due to a software-step, hide it from the user. They aren't really breakpoints as far as they are concerned. * Improve process exit handling on Linux There are three types of process exiting events on Linux: 1. PTRACE_EVENT_EXIT occurs just before a process exits. It's not possible to prevent it from exiting, but it can be used to inspect the pre-exit state. 2. The process can exit for a variety of reasons and we can notice when we call waitpid(2). 3. The process could die randomly on us :-/ On Windows, h->wait will return R_DEBUG_REASON_EXIT_PID, but it's more likely on Linux to find out the process is already dead. * Check more bits within waitpid status We can often make a decision about what happened strictly by looking at the status returned from waitpid. In other cases, we need to call r_debug_handle_signals. If we reach the end of this function without knowing what happened, consider it an error.
2016-06-22 08:34:45 +00:00
cmd_debug_cont_syscall (core, input + 3);
break;
case '\0':
cmd_debug_cont_syscall (core, NULL);
break;
default:
case '?':
eprintf ("|Usage: dcs [syscall-name-or-number]\n");
eprintf ("|dcs : continue until next syscall\n");
eprintf ("|dcs mmap : continue until next call to mmap\n");
eprintf ("|dcs* : trace all syscalls (strace)\n");
eprintf ("|dcs? : show this help\n");
break;
}
break;
case 'p':
{ // XXX: this is very slow
RIOSection *s;
ut64 pc;
int n = 0;
int t = core->dbg->trace->enabled;
core->dbg->trace->enabled = 0;
r_cons_break (static_debug_stop, core->dbg);
do {
r_debug_step (core->dbg, 1);
2015-09-14 10:35:38 +00:00
r_debug_reg_sync (core->dbg, R_REG_TYPE_GPR, false);
2015-10-31 00:57:52 +00:00
pc = r_debug_reg_get (core->dbg, "PC");
eprintf (" %d %"PFMT64x"\r", n++, pc);
s = r_io_section_vget (core->io, pc);
if (r_cons_singleton ()->breaked)
break;
} while (!s);
eprintf ("\n");
core->dbg->trace->enabled = t;
r_cons_break_end();
return 1;
}
case 'u':
cmd_dcu (core, input);
break;
case ' ':
old_pid = core->dbg->pid;
pid = atoi (input + 2);
2015-09-14 10:35:38 +00:00
r_reg_arena_swap (core->dbg->reg, true);
r_debug_select (core->dbg, pid, core->dbg->tid);
r_debug_continue (core->dbg);
r_debug_select (core->dbg, old_pid, core->dbg->tid);
break;
case 't':
cmd_debug_backtrace (core, input + 2);
break;
case '?': // "dc?"
default:
r_core_cmd_help (core, help_message);
return 0;
}
return 1;
}
2016-05-21 13:11:16 +00:00
static char *get_corefile_name (const char *raw_name, pid_t pid) {
2016-03-24 19:22:50 +00:00
return (!*raw_name)?
r_str_newf ("core.%u", pid) :
r_str_chop (strdup (raw_name));
}
static int cmd_debug_step (RCore *core, const char *input) {
ut64 addr;
ut8 buf[64];
RAnalOp aop;
2015-01-31 11:48:15 +00:00
int i, times = 1;
const char * help_message[] = {
"Usage: ds", "", "Step commands",
"ds", "", "Step one instruction",
"ds", " <num>", "Step <num> instructions",
"dsf", "", "Step until end of frame",
"dsi", " <cond>", "Continue until condition matches",
"dsl", "", "Step one source line",
"dsl", " <num>", "Step <num> source lines",
"dso", " <num>", "Step over <num> instructions",
"dsp", "", "Step into program (skip libs)",
"dss", " <num>", "Skip <num> step instructions",
"dsu", " <address>", "Step until address",
"dsui", " <instr>", "Step until an instruction that matches `instr`",
"dsue", " <esil>", "Step until esil expression matches",
"dsuf", " <flag>", "Step until pc == flag matching name",
NULL
};
if (strlen (input) > 2) {
times = atoi (input + 2);
}
if (times < 1) {
times = 1;
}
switch (input[1]) {
case 0:
r_reg_arena_swap (core->dbg->reg, true);
Major rework to the native debugger (esp on Linux) (#5185) The major contribution here is completely re-worked breakpoint hit/recoil handling. This work fixes #4907 and lays the ground work for future native debugger improvements (multi-threading, etc). * Give a human friendly type to enums * Change many wait functions to return RDebugReasonType * Better return checking (from r_debug_reg_sync, r_bp_restore) * Optimized register synchronization * Lots of comments and whitespace changes * Improved inferior death detection Handle EXIT_PID events differently than DEAD process events * Move breakpoint/recoil handling to wait/cont/step Rather than handing breakpoint related things inside cmd_debug.c, do that inside the r_debug API functions. This seems like the most logical place for it to live since it should apply to just about any platform/architecture. This also centralizes calling into "cmd.bp" handling via the CoreBind callback. * Track how the caller wishes to continue It turns out that handling break point recoils is very complicated. The ptrace API on Linux returns SIGTRAP for just about every type of operation (not just breakpoints getting hit). Add the "recoil_mode" flag to indicate whether we are single-stepping or continuing and whether or not we are inside the recoil. * Proper handling for swstep=true Since r_debug_step_soft calls r_debug_continue, it's already hitting the recoil case there. Move the recoil handling from r_debug_step to r_debug_step_hard only. For the swstep=true case, special handling is required inside r_debug_recoil. By resetting all of the breakpoints except the one we just hit, we ensure we can step the original instruction and hit the new swstep breakpoint. Add a new bp function called r_bp_restore_except to do this. To make matters worse, we cannot use a BreakpointItem pointer because that leads to a use-after-free condition. Instead, we the breakpoint address instead. Now breakpoints should work regardless of the swtep setting. * Always call the recoil before continuing Some callers of r_debug_continue might not have ever inserted any breakpoints before. If we don't restore breakpoints before each call to the underlying continue we won't hit them. * Hide software step breakpoint events from the user When a breakpoint even happens due to a software-step, hide it from the user. They aren't really breakpoints as far as they are concerned. * Improve process exit handling on Linux There are three types of process exiting events on Linux: 1. PTRACE_EVENT_EXIT occurs just before a process exits. It's not possible to prevent it from exiting, but it can be used to inspect the pre-exit state. 2. The process can exit for a variety of reasons and we can notice when we call waitpid(2). 3. The process could die randomly on us :-/ On Windows, h->wait will return R_DEBUG_REASON_EXIT_PID, but it's more likely on Linux to find out the process is already dead. * Check more bits within waitpid status We can often make a decision about what happened strictly by looking at the status returned from waitpid. In other cases, we need to call r_debug_handle_signals. If we reach the end of this function without knowing what happened, consider it an error.
2016-06-22 08:34:45 +00:00
// sync registers for BSD PT_STEP/PT_CONT
// XXX(jjd): is this necessary?
r_debug_reg_sync (core->dbg, R_REG_TYPE_GPR, false);
r_debug_step (core->dbg, times);
break;
case 'i':
if (input[2] == ' ') {
int n = 0;
r_cons_break (static_debug_stop, core->dbg);
do {
if (r_cons_singleton ()->breaked)
break;
r_debug_step (core->dbg, 1);
if (r_debug_is_dead (core->dbg))
break;
r_core_cmd0 (core, ".dr*");
n++;
Major rework to the native debugger (esp on Linux) (#5185) The major contribution here is completely re-worked breakpoint hit/recoil handling. This work fixes #4907 and lays the ground work for future native debugger improvements (multi-threading, etc). * Give a human friendly type to enums * Change many wait functions to return RDebugReasonType * Better return checking (from r_debug_reg_sync, r_bp_restore) * Optimized register synchronization * Lots of comments and whitespace changes * Improved inferior death detection Handle EXIT_PID events differently than DEAD process events * Move breakpoint/recoil handling to wait/cont/step Rather than handing breakpoint related things inside cmd_debug.c, do that inside the r_debug API functions. This seems like the most logical place for it to live since it should apply to just about any platform/architecture. This also centralizes calling into "cmd.bp" handling via the CoreBind callback. * Track how the caller wishes to continue It turns out that handling break point recoils is very complicated. The ptrace API on Linux returns SIGTRAP for just about every type of operation (not just breakpoints getting hit). Add the "recoil_mode" flag to indicate whether we are single-stepping or continuing and whether or not we are inside the recoil. * Proper handling for swstep=true Since r_debug_step_soft calls r_debug_continue, it's already hitting the recoil case there. Move the recoil handling from r_debug_step to r_debug_step_hard only. For the swstep=true case, special handling is required inside r_debug_recoil. By resetting all of the breakpoints except the one we just hit, we ensure we can step the original instruction and hit the new swstep breakpoint. Add a new bp function called r_bp_restore_except to do this. To make matters worse, we cannot use a BreakpointItem pointer because that leads to a use-after-free condition. Instead, we the breakpoint address instead. Now breakpoints should work regardless of the swtep setting. * Always call the recoil before continuing Some callers of r_debug_continue might not have ever inserted any breakpoints before. If we don't restore breakpoints before each call to the underlying continue we won't hit them. * Hide software step breakpoint events from the user When a breakpoint even happens due to a software-step, hide it from the user. They aren't really breakpoints as far as they are concerned. * Improve process exit handling on Linux There are three types of process exiting events on Linux: 1. PTRACE_EVENT_EXIT occurs just before a process exits. It's not possible to prevent it from exiting, but it can be used to inspect the pre-exit state. 2. The process can exit for a variety of reasons and we can notice when we call waitpid(2). 3. The process could die randomly on us :-/ On Windows, h->wait will return R_DEBUG_REASON_EXIT_PID, but it's more likely on Linux to find out the process is already dead. * Check more bits within waitpid status We can often make a decision about what happened strictly by looking at the status returned from waitpid. In other cases, we need to call r_debug_handle_signals. If we reach the end of this function without knowing what happened, consider it an error.
2016-06-22 08:34:45 +00:00
} while (!r_num_conditional (core->num, input + 3));
eprintf ("Stopped after %d instructions\n", n);
} else eprintf ("Missing argument\n");
break;
case 'f':
step_until_eof (core);
break;
case 'u':
switch (input[2]) {
case 'f':
Major rework to the native debugger (esp on Linux) (#5185) The major contribution here is completely re-worked breakpoint hit/recoil handling. This work fixes #4907 and lays the ground work for future native debugger improvements (multi-threading, etc). * Give a human friendly type to enums * Change many wait functions to return RDebugReasonType * Better return checking (from r_debug_reg_sync, r_bp_restore) * Optimized register synchronization * Lots of comments and whitespace changes * Improved inferior death detection Handle EXIT_PID events differently than DEAD process events * Move breakpoint/recoil handling to wait/cont/step Rather than handing breakpoint related things inside cmd_debug.c, do that inside the r_debug API functions. This seems like the most logical place for it to live since it should apply to just about any platform/architecture. This also centralizes calling into "cmd.bp" handling via the CoreBind callback. * Track how the caller wishes to continue It turns out that handling break point recoils is very complicated. The ptrace API on Linux returns SIGTRAP for just about every type of operation (not just breakpoints getting hit). Add the "recoil_mode" flag to indicate whether we are single-stepping or continuing and whether or not we are inside the recoil. * Proper handling for swstep=true Since r_debug_step_soft calls r_debug_continue, it's already hitting the recoil case there. Move the recoil handling from r_debug_step to r_debug_step_hard only. For the swstep=true case, special handling is required inside r_debug_recoil. By resetting all of the breakpoints except the one we just hit, we ensure we can step the original instruction and hit the new swstep breakpoint. Add a new bp function called r_bp_restore_except to do this. To make matters worse, we cannot use a BreakpointItem pointer because that leads to a use-after-free condition. Instead, we the breakpoint address instead. Now breakpoints should work regardless of the swtep setting. * Always call the recoil before continuing Some callers of r_debug_continue might not have ever inserted any breakpoints before. If we don't restore breakpoints before each call to the underlying continue we won't hit them. * Hide software step breakpoint events from the user When a breakpoint even happens due to a software-step, hide it from the user. They aren't really breakpoints as far as they are concerned. * Improve process exit handling on Linux There are three types of process exiting events on Linux: 1. PTRACE_EVENT_EXIT occurs just before a process exits. It's not possible to prevent it from exiting, but it can be used to inspect the pre-exit state. 2. The process can exit for a variety of reasons and we can notice when we call waitpid(2). 3. The process could die randomly on us :-/ On Windows, h->wait will return R_DEBUG_REASON_EXIT_PID, but it's more likely on Linux to find out the process is already dead. * Check more bits within waitpid status We can often make a decision about what happened strictly by looking at the status returned from waitpid. In other cases, we need to call r_debug_handle_signals. If we reach the end of this function without knowing what happened, consider it an error.
2016-06-22 08:34:45 +00:00
step_until_flag (core, input + 3);
break;
case 'i':
Major rework to the native debugger (esp on Linux) (#5185) The major contribution here is completely re-worked breakpoint hit/recoil handling. This work fixes #4907 and lays the ground work for future native debugger improvements (multi-threading, etc). * Give a human friendly type to enums * Change many wait functions to return RDebugReasonType * Better return checking (from r_debug_reg_sync, r_bp_restore) * Optimized register synchronization * Lots of comments and whitespace changes * Improved inferior death detection Handle EXIT_PID events differently than DEAD process events * Move breakpoint/recoil handling to wait/cont/step Rather than handing breakpoint related things inside cmd_debug.c, do that inside the r_debug API functions. This seems like the most logical place for it to live since it should apply to just about any platform/architecture. This also centralizes calling into "cmd.bp" handling via the CoreBind callback. * Track how the caller wishes to continue It turns out that handling break point recoils is very complicated. The ptrace API on Linux returns SIGTRAP for just about every type of operation (not just breakpoints getting hit). Add the "recoil_mode" flag to indicate whether we are single-stepping or continuing and whether or not we are inside the recoil. * Proper handling for swstep=true Since r_debug_step_soft calls r_debug_continue, it's already hitting the recoil case there. Move the recoil handling from r_debug_step to r_debug_step_hard only. For the swstep=true case, special handling is required inside r_debug_recoil. By resetting all of the breakpoints except the one we just hit, we ensure we can step the original instruction and hit the new swstep breakpoint. Add a new bp function called r_bp_restore_except to do this. To make matters worse, we cannot use a BreakpointItem pointer because that leads to a use-after-free condition. Instead, we the breakpoint address instead. Now breakpoints should work regardless of the swtep setting. * Always call the recoil before continuing Some callers of r_debug_continue might not have ever inserted any breakpoints before. If we don't restore breakpoints before each call to the underlying continue we won't hit them. * Hide software step breakpoint events from the user When a breakpoint even happens due to a software-step, hide it from the user. They aren't really breakpoints as far as they are concerned. * Improve process exit handling on Linux There are three types of process exiting events on Linux: 1. PTRACE_EVENT_EXIT occurs just before a process exits. It's not possible to prevent it from exiting, but it can be used to inspect the pre-exit state. 2. The process can exit for a variety of reasons and we can notice when we call waitpid(2). 3. The process could die randomly on us :-/ On Windows, h->wait will return R_DEBUG_REASON_EXIT_PID, but it's more likely on Linux to find out the process is already dead. * Check more bits within waitpid status We can often make a decision about what happened strictly by looking at the status returned from waitpid. In other cases, we need to call r_debug_handle_signals. If we reach the end of this function without knowing what happened, consider it an error.
2016-06-22 08:34:45 +00:00
step_until_inst (core, input + 3);
break;
case 'e':
Major rework to the native debugger (esp on Linux) (#5185) The major contribution here is completely re-worked breakpoint hit/recoil handling. This work fixes #4907 and lays the ground work for future native debugger improvements (multi-threading, etc). * Give a human friendly type to enums * Change many wait functions to return RDebugReasonType * Better return checking (from r_debug_reg_sync, r_bp_restore) * Optimized register synchronization * Lots of comments and whitespace changes * Improved inferior death detection Handle EXIT_PID events differently than DEAD process events * Move breakpoint/recoil handling to wait/cont/step Rather than handing breakpoint related things inside cmd_debug.c, do that inside the r_debug API functions. This seems like the most logical place for it to live since it should apply to just about any platform/architecture. This also centralizes calling into "cmd.bp" handling via the CoreBind callback. * Track how the caller wishes to continue It turns out that handling break point recoils is very complicated. The ptrace API on Linux returns SIGTRAP for just about every type of operation (not just breakpoints getting hit). Add the "recoil_mode" flag to indicate whether we are single-stepping or continuing and whether or not we are inside the recoil. * Proper handling for swstep=true Since r_debug_step_soft calls r_debug_continue, it's already hitting the recoil case there. Move the recoil handling from r_debug_step to r_debug_step_hard only. For the swstep=true case, special handling is required inside r_debug_recoil. By resetting all of the breakpoints except the one we just hit, we ensure we can step the original instruction and hit the new swstep breakpoint. Add a new bp function called r_bp_restore_except to do this. To make matters worse, we cannot use a BreakpointItem pointer because that leads to a use-after-free condition. Instead, we the breakpoint address instead. Now breakpoints should work regardless of the swtep setting. * Always call the recoil before continuing Some callers of r_debug_continue might not have ever inserted any breakpoints before. If we don't restore breakpoints before each call to the underlying continue we won't hit them. * Hide software step breakpoint events from the user When a breakpoint even happens due to a software-step, hide it from the user. They aren't really breakpoints as far as they are concerned. * Improve process exit handling on Linux There are three types of process exiting events on Linux: 1. PTRACE_EVENT_EXIT occurs just before a process exits. It's not possible to prevent it from exiting, but it can be used to inspect the pre-exit state. 2. The process can exit for a variety of reasons and we can notice when we call waitpid(2). 3. The process could die randomly on us :-/ On Windows, h->wait will return R_DEBUG_REASON_EXIT_PID, but it's more likely on Linux to find out the process is already dead. * Check more bits within waitpid status We can often make a decision about what happened strictly by looking at the status returned from waitpid. In other cases, we need to call r_debug_handle_signals. If we reach the end of this function without knowing what happened, consider it an error.
2016-06-22 08:34:45 +00:00
step_until_esil (core, input + 3);
break;
case ' ':
2015-09-14 10:35:38 +00:00
r_reg_arena_swap (core->dbg->reg, true);
Major rework to the native debugger (esp on Linux) (#5185) The major contribution here is completely re-worked breakpoint hit/recoil handling. This work fixes #4907 and lays the ground work for future native debugger improvements (multi-threading, etc). * Give a human friendly type to enums * Change many wait functions to return RDebugReasonType * Better return checking (from r_debug_reg_sync, r_bp_restore) * Optimized register synchronization * Lots of comments and whitespace changes * Improved inferior death detection Handle EXIT_PID events differently than DEAD process events * Move breakpoint/recoil handling to wait/cont/step Rather than handing breakpoint related things inside cmd_debug.c, do that inside the r_debug API functions. This seems like the most logical place for it to live since it should apply to just about any platform/architecture. This also centralizes calling into "cmd.bp" handling via the CoreBind callback. * Track how the caller wishes to continue It turns out that handling break point recoils is very complicated. The ptrace API on Linux returns SIGTRAP for just about every type of operation (not just breakpoints getting hit). Add the "recoil_mode" flag to indicate whether we are single-stepping or continuing and whether or not we are inside the recoil. * Proper handling for swstep=true Since r_debug_step_soft calls r_debug_continue, it's already hitting the recoil case there. Move the recoil handling from r_debug_step to r_debug_step_hard only. For the swstep=true case, special handling is required inside r_debug_recoil. By resetting all of the breakpoints except the one we just hit, we ensure we can step the original instruction and hit the new swstep breakpoint. Add a new bp function called r_bp_restore_except to do this. To make matters worse, we cannot use a BreakpointItem pointer because that leads to a use-after-free condition. Instead, we the breakpoint address instead. Now breakpoints should work regardless of the swtep setting. * Always call the recoil before continuing Some callers of r_debug_continue might not have ever inserted any breakpoints before. If we don't restore breakpoints before each call to the underlying continue we won't hit them. * Hide software step breakpoint events from the user When a breakpoint even happens due to a software-step, hide it from the user. They aren't really breakpoints as far as they are concerned. * Improve process exit handling on Linux There are three types of process exiting events on Linux: 1. PTRACE_EVENT_EXIT occurs just before a process exits. It's not possible to prevent it from exiting, but it can be used to inspect the pre-exit state. 2. The process can exit for a variety of reasons and we can notice when we call waitpid(2). 3. The process could die randomly on us :-/ On Windows, h->wait will return R_DEBUG_REASON_EXIT_PID, but it's more likely on Linux to find out the process is already dead. * Check more bits within waitpid status We can often make a decision about what happened strictly by looking at the status returned from waitpid. In other cases, we need to call r_debug_handle_signals. If we reach the end of this function without knowing what happened, consider it an error.
2016-06-22 08:34:45 +00:00
step_until (core, r_num_math (core->num, input + 2)); // XXX dupped by times
break;
default:
eprintf ("Usage: dsu[fei] [arg] . step until address ' ',"
" 'f'lag, 'e'sil or 'i'nstruction matching\n");
return 0;
}
break;
case 'p':
2015-09-14 10:35:38 +00:00
r_reg_arena_swap (core->dbg->reg, true);
for (i=0; i<times; i++) {
ut8 buf[64];
ut64 addr;
RAnalOp aop;
2015-09-14 10:35:38 +00:00
r_debug_reg_sync (core->dbg, R_REG_TYPE_GPR, false);
2015-10-31 00:57:52 +00:00
addr = r_debug_reg_get (core->dbg, "PC");
r_io_read_at (core->io, addr, buf, sizeof (buf));
r_anal_op (core->anal, &aop, addr, buf, sizeof (buf));
if (aop.type == R_ANAL_OP_TYPE_CALL) {
RIOSection *s = r_io_section_vget (core->io, aop.jump);
if (!s) {
r_debug_step_over (core->dbg, times);
continue;
}
}
r_debug_step (core->dbg, 1);
}
break;
case 's':
{
char delb[128] = {0};
2015-10-31 00:57:52 +00:00
addr = r_debug_reg_get (core->dbg, "PC");
RBreakpointItem *bpi = r_bp_get_at (core->dbg->bp, addr);
sprintf(delb, "db 0x%"PFMT64x"", addr);
r_reg_arena_swap (core->dbg->reg, true);
for (i = 0; i < times; i++) {
r_debug_reg_sync (core->dbg, R_REG_TYPE_GPR, false);
r_io_read_at (core->io, addr, buf, sizeof (buf));
r_anal_op (core->anal, &aop, addr, buf, sizeof (buf));
if (aop.jump != UT64_MAX && aop.fail != UT64_MAX) {
eprintf ("Don't know how to skip this instruction\n");
if (bpi) r_core_cmd0 (core, delb);
break;
}
addr += aop.size;
}
2015-10-31 00:57:52 +00:00
r_debug_reg_set (core->dbg, "PC", addr);
if (bpi) r_core_cmd0 (core, delb);
break;
}
case 'o':
{
char delb[128] = {0};
2015-10-31 00:57:52 +00:00
addr = r_debug_reg_get (core->dbg, "PC");
RBreakpointItem *bpi = r_bp_get_at (core->dbg->bp, addr);
sprintf(delb, "db 0x%"PFMT64x"", addr);
r_bp_del (core->dbg->bp, addr);
r_reg_arena_swap (core->dbg->reg, true);
r_debug_step_over (core->dbg, times);
if (bpi) r_core_cmd0 (core, delb);
break;
}
case 'l':
2015-09-14 10:35:38 +00:00
r_reg_arena_swap (core->dbg->reg, true);
step_line (core, times);
break;
case '?':
default:
r_core_cmd_help (core, help_message);
return 0;
}
return 1;
}
static int cmd_debug(void *data, const char *input) {
RCore *core = (RCore *)data;
int follow = 0;
2012-02-27 01:40:27 +00:00
if (r_sandbox_enable (0)) {
eprintf ("Debugger commands disabled in sandbox mode\n");
return 0;
}
if (!strncmp (input, "ate", 3)) {
char str[128];
str[0] = 0;
r_print_date_get_now (core->print, str);
r_cons_println (str);
return 0;
}
2012-02-27 01:40:27 +00:00
switch (input[0]) {
case 't':
// TODO: define ranges? to display only some traces, allow to scroll on this disasm? ~.. ?
2012-02-27 01:40:27 +00:00
switch (input[1]) {
case 'c': // "dtc"
if (input[2] == '?') {
eprintf ("Usage: dtc [addr] ([from] [to] [addr]) - trace calls in debugger\n");
} else {
debug_trace_calls (core, input + 2);
}
2012-02-27 01:40:27 +00:00
break;
case 'd':
// TODO: reimplement using the api
r_core_cmd0 (core, "pd 1 @@= `dt~[0]`");
break;
case 'g': // "dtg"
dot_trace_traverse (core, core->dbg->tree, input[2]);
2012-02-27 01:40:27 +00:00
break;
case '-':
r_tree_reset (core->dbg->tree);
2016-06-02 01:19:31 +00:00
r_debug_trace_free (core->dbg->trace);
r_debug_tracenodes_reset (core->dbg);
2012-02-27 01:40:27 +00:00
core->dbg->trace = r_debug_trace_new ();
break;
case '\0':
r_debug_trace_list (core->dbg, -1);
break;
case '?':
2012-02-27 01:40:27 +00:00
default:
{
const char * help_message[] = {
"Usage: dt", "", "Trace commands",
"dt", "", "List all traces ",
"dtd", "", "List all traced disassembled",
"dtc [addr]|([from] [to] [addr])", "", "Trace call/ret",
"dtg", "", "Graph call/ret trace",
"dtg*", "", "Graph in agn/age commands. use .dtg*;aggi for visual",
"dtgi", "", "Interactive debug trace",
"dt-", "", "Reset traces (instruction/calls)",
NULL
};
r_core_cmd_help (core, help_message);
}
2012-02-27 01:40:27 +00:00
break;
}
break;
case 'd':
switch (input[1]) {
case '\0':
r_debug_desc_list (core->dbg, 0);
break;
case '*':
r_debug_desc_list (core->dbg, 1);
break;
case 's':
2015-10-13 02:50:48 +00:00
{
ut64 off = UT64_MAX;
Major rework to the native debugger (esp on Linux) (#5185) The major contribution here is completely re-worked breakpoint hit/recoil handling. This work fixes #4907 and lays the ground work for future native debugger improvements (multi-threading, etc). * Give a human friendly type to enums * Change many wait functions to return RDebugReasonType * Better return checking (from r_debug_reg_sync, r_bp_restore) * Optimized register synchronization * Lots of comments and whitespace changes * Improved inferior death detection Handle EXIT_PID events differently than DEAD process events * Move breakpoint/recoil handling to wait/cont/step Rather than handing breakpoint related things inside cmd_debug.c, do that inside the r_debug API functions. This seems like the most logical place for it to live since it should apply to just about any platform/architecture. This also centralizes calling into "cmd.bp" handling via the CoreBind callback. * Track how the caller wishes to continue It turns out that handling break point recoils is very complicated. The ptrace API on Linux returns SIGTRAP for just about every type of operation (not just breakpoints getting hit). Add the "recoil_mode" flag to indicate whether we are single-stepping or continuing and whether or not we are inside the recoil. * Proper handling for swstep=true Since r_debug_step_soft calls r_debug_continue, it's already hitting the recoil case there. Move the recoil handling from r_debug_step to r_debug_step_hard only. For the swstep=true case, special handling is required inside r_debug_recoil. By resetting all of the breakpoints except the one we just hit, we ensure we can step the original instruction and hit the new swstep breakpoint. Add a new bp function called r_bp_restore_except to do this. To make matters worse, we cannot use a BreakpointItem pointer because that leads to a use-after-free condition. Instead, we the breakpoint address instead. Now breakpoints should work regardless of the swtep setting. * Always call the recoil before continuing Some callers of r_debug_continue might not have ever inserted any breakpoints before. If we don't restore breakpoints before each call to the underlying continue we won't hit them. * Hide software step breakpoint events from the user When a breakpoint even happens due to a software-step, hide it from the user. They aren't really breakpoints as far as they are concerned. * Improve process exit handling on Linux There are three types of process exiting events on Linux: 1. PTRACE_EVENT_EXIT occurs just before a process exits. It's not possible to prevent it from exiting, but it can be used to inspect the pre-exit state. 2. The process can exit for a variety of reasons and we can notice when we call waitpid(2). 3. The process could die randomly on us :-/ On Windows, h->wait will return R_DEBUG_REASON_EXIT_PID, but it's more likely on Linux to find out the process is already dead. * Check more bits within waitpid status We can often make a decision about what happened strictly by looking at the status returned from waitpid. In other cases, we need to call r_debug_handle_signals. If we reach the end of this function without knowing what happened, consider it an error.
2016-06-22 08:34:45 +00:00
int fd = atoi (input + 2);
char *str = strchr (input + 2, ' ');
2015-10-13 02:50:48 +00:00
if (str) off = r_num_math (core->num, str+1);
if (off == UT64_MAX || !r_debug_desc_seek (core->dbg, fd, off))
if (!r_core_syscallf (core, "lseek", "%d, 0x%"PFMT64x", %d", fd, off, 0))
eprintf ("Cannot seek\n");
}
2012-02-27 01:40:27 +00:00
break;
case 'd':
2015-10-13 02:50:48 +00:00
{
ut64 newfd = UT64_MAX;
Major rework to the native debugger (esp on Linux) (#5185) The major contribution here is completely re-worked breakpoint hit/recoil handling. This work fixes #4907 and lays the ground work for future native debugger improvements (multi-threading, etc). * Give a human friendly type to enums * Change many wait functions to return RDebugReasonType * Better return checking (from r_debug_reg_sync, r_bp_restore) * Optimized register synchronization * Lots of comments and whitespace changes * Improved inferior death detection Handle EXIT_PID events differently than DEAD process events * Move breakpoint/recoil handling to wait/cont/step Rather than handing breakpoint related things inside cmd_debug.c, do that inside the r_debug API functions. This seems like the most logical place for it to live since it should apply to just about any platform/architecture. This also centralizes calling into "cmd.bp" handling via the CoreBind callback. * Track how the caller wishes to continue It turns out that handling break point recoils is very complicated. The ptrace API on Linux returns SIGTRAP for just about every type of operation (not just breakpoints getting hit). Add the "recoil_mode" flag to indicate whether we are single-stepping or continuing and whether or not we are inside the recoil. * Proper handling for swstep=true Since r_debug_step_soft calls r_debug_continue, it's already hitting the recoil case there. Move the recoil handling from r_debug_step to r_debug_step_hard only. For the swstep=true case, special handling is required inside r_debug_recoil. By resetting all of the breakpoints except the one we just hit, we ensure we can step the original instruction and hit the new swstep breakpoint. Add a new bp function called r_bp_restore_except to do this. To make matters worse, we cannot use a BreakpointItem pointer because that leads to a use-after-free condition. Instead, we the breakpoint address instead. Now breakpoints should work regardless of the swtep setting. * Always call the recoil before continuing Some callers of r_debug_continue might not have ever inserted any breakpoints before. If we don't restore breakpoints before each call to the underlying continue we won't hit them. * Hide software step breakpoint events from the user When a breakpoint even happens due to a software-step, hide it from the user. They aren't really breakpoints as far as they are concerned. * Improve process exit handling on Linux There are three types of process exiting events on Linux: 1. PTRACE_EVENT_EXIT occurs just before a process exits. It's not possible to prevent it from exiting, but it can be used to inspect the pre-exit state. 2. The process can exit for a variety of reasons and we can notice when we call waitpid(2). 3. The process could die randomly on us :-/ On Windows, h->wait will return R_DEBUG_REASON_EXIT_PID, but it's more likely on Linux to find out the process is already dead. * Check more bits within waitpid status We can often make a decision about what happened strictly by looking at the status returned from waitpid. In other cases, we need to call r_debug_handle_signals. If we reach the end of this function without knowing what happened, consider it an error.
2016-06-22 08:34:45 +00:00
int fd = atoi (input + 2);
char *str = strchr (input + 2, ' ');
2015-10-13 02:50:48 +00:00
if (str) newfd = r_num_math (core->num, str+1);
if (newfd == UT64_MAX || !r_debug_desc_dup (core->dbg, fd, newfd))
if (!r_core_syscallf (core, "dup2", "%d, %d", fd, (int)newfd))
eprintf ("Cannot dup %d %d\n", fd, (int)newfd);
}
2012-02-27 01:40:27 +00:00
break;
case 'r':
2015-10-13 02:50:48 +00:00
{
ut64 off = UT64_MAX;
ut64 len = UT64_MAX;
Major rework to the native debugger (esp on Linux) (#5185) The major contribution here is completely re-worked breakpoint hit/recoil handling. This work fixes #4907 and lays the ground work for future native debugger improvements (multi-threading, etc). * Give a human friendly type to enums * Change many wait functions to return RDebugReasonType * Better return checking (from r_debug_reg_sync, r_bp_restore) * Optimized register synchronization * Lots of comments and whitespace changes * Improved inferior death detection Handle EXIT_PID events differently than DEAD process events * Move breakpoint/recoil handling to wait/cont/step Rather than handing breakpoint related things inside cmd_debug.c, do that inside the r_debug API functions. This seems like the most logical place for it to live since it should apply to just about any platform/architecture. This also centralizes calling into "cmd.bp" handling via the CoreBind callback. * Track how the caller wishes to continue It turns out that handling break point recoils is very complicated. The ptrace API on Linux returns SIGTRAP for just about every type of operation (not just breakpoints getting hit). Add the "recoil_mode" flag to indicate whether we are single-stepping or continuing and whether or not we are inside the recoil. * Proper handling for swstep=true Since r_debug_step_soft calls r_debug_continue, it's already hitting the recoil case there. Move the recoil handling from r_debug_step to r_debug_step_hard only. For the swstep=true case, special handling is required inside r_debug_recoil. By resetting all of the breakpoints except the one we just hit, we ensure we can step the original instruction and hit the new swstep breakpoint. Add a new bp function called r_bp_restore_except to do this. To make matters worse, we cannot use a BreakpointItem pointer because that leads to a use-after-free condition. Instead, we the breakpoint address instead. Now breakpoints should work regardless of the swtep setting. * Always call the recoil before continuing Some callers of r_debug_continue might not have ever inserted any breakpoints before. If we don't restore breakpoints before each call to the underlying continue we won't hit them. * Hide software step breakpoint events from the user When a breakpoint even happens due to a software-step, hide it from the user. They aren't really breakpoints as far as they are concerned. * Improve process exit handling on Linux There are three types of process exiting events on Linux: 1. PTRACE_EVENT_EXIT occurs just before a process exits. It's not possible to prevent it from exiting, but it can be used to inspect the pre-exit state. 2. The process can exit for a variety of reasons and we can notice when we call waitpid(2). 3. The process could die randomly on us :-/ On Windows, h->wait will return R_DEBUG_REASON_EXIT_PID, but it's more likely on Linux to find out the process is already dead. * Check more bits within waitpid status We can often make a decision about what happened strictly by looking at the status returned from waitpid. In other cases, we need to call r_debug_handle_signals. If we reach the end of this function without knowing what happened, consider it an error.
2016-06-22 08:34:45 +00:00
int fd = atoi (input + 2);
char *str = strchr (input + 2, ' ');
2015-10-13 02:50:48 +00:00
if (str) off = r_num_math (core->num, str+1);
2015-10-24 19:51:11 +00:00
if (str) str = strchr (str+1, ' ');
2015-10-13 02:50:48 +00:00
if (str) len = r_num_math (core->num, str+1);
if (len == UT64_MAX || off == UT64_MAX || \
!r_debug_desc_read (core->dbg, fd, off, len))
if (!r_core_syscallf (core, "read", "%d, 0x%"PFMT64x", %d",
fd, off, (int)len))
eprintf ("Cannot read\n");
}
2012-02-27 01:40:27 +00:00
break;
case 'w':
2015-10-13 02:50:48 +00:00
{
ut64 off = UT64_MAX;
ut64 len = UT64_MAX;
Major rework to the native debugger (esp on Linux) (#5185) The major contribution here is completely re-worked breakpoint hit/recoil handling. This work fixes #4907 and lays the ground work for future native debugger improvements (multi-threading, etc). * Give a human friendly type to enums * Change many wait functions to return RDebugReasonType * Better return checking (from r_debug_reg_sync, r_bp_restore) * Optimized register synchronization * Lots of comments and whitespace changes * Improved inferior death detection Handle EXIT_PID events differently than DEAD process events * Move breakpoint/recoil handling to wait/cont/step Rather than handing breakpoint related things inside cmd_debug.c, do that inside the r_debug API functions. This seems like the most logical place for it to live since it should apply to just about any platform/architecture. This also centralizes calling into "cmd.bp" handling via the CoreBind callback. * Track how the caller wishes to continue It turns out that handling break point recoils is very complicated. The ptrace API on Linux returns SIGTRAP for just about every type of operation (not just breakpoints getting hit). Add the "recoil_mode" flag to indicate whether we are single-stepping or continuing and whether or not we are inside the recoil. * Proper handling for swstep=true Since r_debug_step_soft calls r_debug_continue, it's already hitting the recoil case there. Move the recoil handling from r_debug_step to r_debug_step_hard only. For the swstep=true case, special handling is required inside r_debug_recoil. By resetting all of the breakpoints except the one we just hit, we ensure we can step the original instruction and hit the new swstep breakpoint. Add a new bp function called r_bp_restore_except to do this. To make matters worse, we cannot use a BreakpointItem pointer because that leads to a use-after-free condition. Instead, we the breakpoint address instead. Now breakpoints should work regardless of the swtep setting. * Always call the recoil before continuing Some callers of r_debug_continue might not have ever inserted any breakpoints before. If we don't restore breakpoints before each call to the underlying continue we won't hit them. * Hide software step breakpoint events from the user When a breakpoint even happens due to a software-step, hide it from the user. They aren't really breakpoints as far as they are concerned. * Improve process exit handling on Linux There are three types of process exiting events on Linux: 1. PTRACE_EVENT_EXIT occurs just before a process exits. It's not possible to prevent it from exiting, but it can be used to inspect the pre-exit state. 2. The process can exit for a variety of reasons and we can notice when we call waitpid(2). 3. The process could die randomly on us :-/ On Windows, h->wait will return R_DEBUG_REASON_EXIT_PID, but it's more likely on Linux to find out the process is already dead. * Check more bits within waitpid status We can often make a decision about what happened strictly by looking at the status returned from waitpid. In other cases, we need to call r_debug_handle_signals. If we reach the end of this function without knowing what happened, consider it an error.
2016-06-22 08:34:45 +00:00
int fd = atoi (input + 2);
char *str = strchr (input + 2, ' ');
2015-10-13 02:50:48 +00:00
if (str) off = r_num_math (core->num, str+1);
if (str) str = strchr (str+1, ' ');
2015-10-13 02:50:48 +00:00
if (str) len = r_num_math (core->num, str+1);
if (len == UT64_MAX || off == UT64_MAX || \
!r_debug_desc_write (core->dbg, fd, off, len))
if (!r_core_syscallf (core, "write", "%d, 0x%"PFMT64x", %d",
fd, off, (int)len))
eprintf ("Cannot write\n");
}
2012-02-27 01:40:27 +00:00
break;
case '-': // "dd-"
2012-02-27 01:40:27 +00:00
// close file
Major rework to the native debugger (esp on Linux) (#5185) The major contribution here is completely re-worked breakpoint hit/recoil handling. This work fixes #4907 and lays the ground work for future native debugger improvements (multi-threading, etc). * Give a human friendly type to enums * Change many wait functions to return RDebugReasonType * Better return checking (from r_debug_reg_sync, r_bp_restore) * Optimized register synchronization * Lots of comments and whitespace changes * Improved inferior death detection Handle EXIT_PID events differently than DEAD process events * Move breakpoint/recoil handling to wait/cont/step Rather than handing breakpoint related things inside cmd_debug.c, do that inside the r_debug API functions. This seems like the most logical place for it to live since it should apply to just about any platform/architecture. This also centralizes calling into "cmd.bp" handling via the CoreBind callback. * Track how the caller wishes to continue It turns out that handling break point recoils is very complicated. The ptrace API on Linux returns SIGTRAP for just about every type of operation (not just breakpoints getting hit). Add the "recoil_mode" flag to indicate whether we are single-stepping or continuing and whether or not we are inside the recoil. * Proper handling for swstep=true Since r_debug_step_soft calls r_debug_continue, it's already hitting the recoil case there. Move the recoil handling from r_debug_step to r_debug_step_hard only. For the swstep=true case, special handling is required inside r_debug_recoil. By resetting all of the breakpoints except the one we just hit, we ensure we can step the original instruction and hit the new swstep breakpoint. Add a new bp function called r_bp_restore_except to do this. To make matters worse, we cannot use a BreakpointItem pointer because that leads to a use-after-free condition. Instead, we the breakpoint address instead. Now breakpoints should work regardless of the swtep setting. * Always call the recoil before continuing Some callers of r_debug_continue might not have ever inserted any breakpoints before. If we don't restore breakpoints before each call to the underlying continue we won't hit them. * Hide software step breakpoint events from the user When a breakpoint even happens due to a software-step, hide it from the user. They aren't really breakpoints as far as they are concerned. * Improve process exit handling on Linux There are three types of process exiting events on Linux: 1. PTRACE_EVENT_EXIT occurs just before a process exits. It's not possible to prevent it from exiting, but it can be used to inspect the pre-exit state. 2. The process can exit for a variety of reasons and we can notice when we call waitpid(2). 3. The process could die randomly on us :-/ On Windows, h->wait will return R_DEBUG_REASON_EXIT_PID, but it's more likely on Linux to find out the process is already dead. * Check more bits within waitpid status We can often make a decision about what happened strictly by looking at the status returned from waitpid. In other cases, we need to call r_debug_handle_signals. If we reach the end of this function without knowing what happened, consider it an error.
2016-06-22 08:34:45 +00:00
//r_core_syscallf (core, "close", "%d", atoi (input + 2));
2015-10-13 02:50:48 +00:00
{
Major rework to the native debugger (esp on Linux) (#5185) The major contribution here is completely re-worked breakpoint hit/recoil handling. This work fixes #4907 and lays the ground work for future native debugger improvements (multi-threading, etc). * Give a human friendly type to enums * Change many wait functions to return RDebugReasonType * Better return checking (from r_debug_reg_sync, r_bp_restore) * Optimized register synchronization * Lots of comments and whitespace changes * Improved inferior death detection Handle EXIT_PID events differently than DEAD process events * Move breakpoint/recoil handling to wait/cont/step Rather than handing breakpoint related things inside cmd_debug.c, do that inside the r_debug API functions. This seems like the most logical place for it to live since it should apply to just about any platform/architecture. This also centralizes calling into "cmd.bp" handling via the CoreBind callback. * Track how the caller wishes to continue It turns out that handling break point recoils is very complicated. The ptrace API on Linux returns SIGTRAP for just about every type of operation (not just breakpoints getting hit). Add the "recoil_mode" flag to indicate whether we are single-stepping or continuing and whether or not we are inside the recoil. * Proper handling for swstep=true Since r_debug_step_soft calls r_debug_continue, it's already hitting the recoil case there. Move the recoil handling from r_debug_step to r_debug_step_hard only. For the swstep=true case, special handling is required inside r_debug_recoil. By resetting all of the breakpoints except the one we just hit, we ensure we can step the original instruction and hit the new swstep breakpoint. Add a new bp function called r_bp_restore_except to do this. To make matters worse, we cannot use a BreakpointItem pointer because that leads to a use-after-free condition. Instead, we the breakpoint address instead. Now breakpoints should work regardless of the swtep setting. * Always call the recoil before continuing Some callers of r_debug_continue might not have ever inserted any breakpoints before. If we don't restore breakpoints before each call to the underlying continue we won't hit them. * Hide software step breakpoint events from the user When a breakpoint even happens due to a software-step, hide it from the user. They aren't really breakpoints as far as they are concerned. * Improve process exit handling on Linux There are three types of process exiting events on Linux: 1. PTRACE_EVENT_EXIT occurs just before a process exits. It's not possible to prevent it from exiting, but it can be used to inspect the pre-exit state. 2. The process can exit for a variety of reasons and we can notice when we call waitpid(2). 3. The process could die randomly on us :-/ On Windows, h->wait will return R_DEBUG_REASON_EXIT_PID, but it's more likely on Linux to find out the process is already dead. * Check more bits within waitpid status We can often make a decision about what happened strictly by looking at the status returned from waitpid. In other cases, we need to call r_debug_handle_signals. If we reach the end of this function without knowing what happened, consider it an error.
2016-06-22 08:34:45 +00:00
int fd = atoi (input + 2);
//r_core_cmdf (core, "dxs close %d", (int)r_num_math ( core->num, input + 2));
2015-10-13 02:50:48 +00:00
r_core_syscallf (core, "close", "%d", fd);
}
2012-02-27 01:40:27 +00:00
break;
case ' ':
// TODO: handle read, readwrite, append
Major rework to the native debugger (esp on Linux) (#5185) The major contribution here is completely re-worked breakpoint hit/recoil handling. This work fixes #4907 and lays the ground work for future native debugger improvements (multi-threading, etc). * Give a human friendly type to enums * Change many wait functions to return RDebugReasonType * Better return checking (from r_debug_reg_sync, r_bp_restore) * Optimized register synchronization * Lots of comments and whitespace changes * Improved inferior death detection Handle EXIT_PID events differently than DEAD process events * Move breakpoint/recoil handling to wait/cont/step Rather than handing breakpoint related things inside cmd_debug.c, do that inside the r_debug API functions. This seems like the most logical place for it to live since it should apply to just about any platform/architecture. This also centralizes calling into "cmd.bp" handling via the CoreBind callback. * Track how the caller wishes to continue It turns out that handling break point recoils is very complicated. The ptrace API on Linux returns SIGTRAP for just about every type of operation (not just breakpoints getting hit). Add the "recoil_mode" flag to indicate whether we are single-stepping or continuing and whether or not we are inside the recoil. * Proper handling for swstep=true Since r_debug_step_soft calls r_debug_continue, it's already hitting the recoil case there. Move the recoil handling from r_debug_step to r_debug_step_hard only. For the swstep=true case, special handling is required inside r_debug_recoil. By resetting all of the breakpoints except the one we just hit, we ensure we can step the original instruction and hit the new swstep breakpoint. Add a new bp function called r_bp_restore_except to do this. To make matters worse, we cannot use a BreakpointItem pointer because that leads to a use-after-free condition. Instead, we the breakpoint address instead. Now breakpoints should work regardless of the swtep setting. * Always call the recoil before continuing Some callers of r_debug_continue might not have ever inserted any breakpoints before. If we don't restore breakpoints before each call to the underlying continue we won't hit them. * Hide software step breakpoint events from the user When a breakpoint even happens due to a software-step, hide it from the user. They aren't really breakpoints as far as they are concerned. * Improve process exit handling on Linux There are three types of process exiting events on Linux: 1. PTRACE_EVENT_EXIT occurs just before a process exits. It's not possible to prevent it from exiting, but it can be used to inspect the pre-exit state. 2. The process can exit for a variety of reasons and we can notice when we call waitpid(2). 3. The process could die randomly on us :-/ On Windows, h->wait will return R_DEBUG_REASON_EXIT_PID, but it's more likely on Linux to find out the process is already dead. * Check more bits within waitpid status We can often make a decision about what happened strictly by looking at the status returned from waitpid. In other cases, we need to call r_debug_handle_signals. If we reach the end of this function without knowing what happened, consider it an error.
2016-06-22 08:34:45 +00:00
r_core_syscallf (core, "open", "%s, %d, %d", input + 2, 2, 0644);
2012-02-27 01:40:27 +00:00
// open file
break;
case '?':
default:
{
const char * help_message[] = {
"Usage: dd", "", "Descriptors commands",
"dd", "", "List file descriptors",
"dd", " <file>", "Open and map that file into the UI",
"dd-", "<fd>", "Close stdout fd",
"dd*", "", "List file descriptors (in radare commands)",
NULL
};
r_core_cmd_help (core, help_message);
}
2012-02-27 01:40:27 +00:00
break;
}
break;
case 's':
if (cmd_debug_step (core, input)) {
follow = r_config_get_i (core->config, "dbg.follow");
}
2012-02-27 01:40:27 +00:00
break;
case 'b':
r_core_cmd_bp (core, input);
break;
case 'H':
eprintf ("TODO: transplant process\n");
break;
case 'c': // "dc"
2012-02-27 01:40:27 +00:00
r_cons_break (static_debug_stop, core->dbg);
(void)cmd_debug_continue (core, input);
2012-02-27 01:40:27 +00:00
follow = r_config_get_i (core->config, "dbg.follow");
r_cons_break_end ();
2012-02-27 01:40:27 +00:00
break;
case 'm': // "dm"
cmd_debug_map (core, input + 1);
2012-02-27 01:40:27 +00:00
break;
case 'r': // "dr"
if (core->io->debug || input[1] == '?') {
Major rework to the native debugger (esp on Linux) (#5185) The major contribution here is completely re-worked breakpoint hit/recoil handling. This work fixes #4907 and lays the ground work for future native debugger improvements (multi-threading, etc). * Give a human friendly type to enums * Change many wait functions to return RDebugReasonType * Better return checking (from r_debug_reg_sync, r_bp_restore) * Optimized register synchronization * Lots of comments and whitespace changes * Improved inferior death detection Handle EXIT_PID events differently than DEAD process events * Move breakpoint/recoil handling to wait/cont/step Rather than handing breakpoint related things inside cmd_debug.c, do that inside the r_debug API functions. This seems like the most logical place for it to live since it should apply to just about any platform/architecture. This also centralizes calling into "cmd.bp" handling via the CoreBind callback. * Track how the caller wishes to continue It turns out that handling break point recoils is very complicated. The ptrace API on Linux returns SIGTRAP for just about every type of operation (not just breakpoints getting hit). Add the "recoil_mode" flag to indicate whether we are single-stepping or continuing and whether or not we are inside the recoil. * Proper handling for swstep=true Since r_debug_step_soft calls r_debug_continue, it's already hitting the recoil case there. Move the recoil handling from r_debug_step to r_debug_step_hard only. For the swstep=true case, special handling is required inside r_debug_recoil. By resetting all of the breakpoints except the one we just hit, we ensure we can step the original instruction and hit the new swstep breakpoint. Add a new bp function called r_bp_restore_except to do this. To make matters worse, we cannot use a BreakpointItem pointer because that leads to a use-after-free condition. Instead, we the breakpoint address instead. Now breakpoints should work regardless of the swtep setting. * Always call the recoil before continuing Some callers of r_debug_continue might not have ever inserted any breakpoints before. If we don't restore breakpoints before each call to the underlying continue we won't hit them. * Hide software step breakpoint events from the user When a breakpoint even happens due to a software-step, hide it from the user. They aren't really breakpoints as far as they are concerned. * Improve process exit handling on Linux There are three types of process exiting events on Linux: 1. PTRACE_EVENT_EXIT occurs just before a process exits. It's not possible to prevent it from exiting, but it can be used to inspect the pre-exit state. 2. The process can exit for a variety of reasons and we can notice when we call waitpid(2). 3. The process could die randomly on us :-/ On Windows, h->wait will return R_DEBUG_REASON_EXIT_PID, but it's more likely on Linux to find out the process is already dead. * Check more bits within waitpid status We can often make a decision about what happened strictly by looking at the status returned from waitpid. In other cases, we need to call r_debug_handle_signals. If we reach the end of this function without knowing what happened, consider it an error.
2016-06-22 08:34:45 +00:00
cmd_debug_reg (core, input + 1);
} else {
void cmd_anal_reg(RCore *core, const char *str);
Major rework to the native debugger (esp on Linux) (#5185) The major contribution here is completely re-worked breakpoint hit/recoil handling. This work fixes #4907 and lays the ground work for future native debugger improvements (multi-threading, etc). * Give a human friendly type to enums * Change many wait functions to return RDebugReasonType * Better return checking (from r_debug_reg_sync, r_bp_restore) * Optimized register synchronization * Lots of comments and whitespace changes * Improved inferior death detection Handle EXIT_PID events differently than DEAD process events * Move breakpoint/recoil handling to wait/cont/step Rather than handing breakpoint related things inside cmd_debug.c, do that inside the r_debug API functions. This seems like the most logical place for it to live since it should apply to just about any platform/architecture. This also centralizes calling into "cmd.bp" handling via the CoreBind callback. * Track how the caller wishes to continue It turns out that handling break point recoils is very complicated. The ptrace API on Linux returns SIGTRAP for just about every type of operation (not just breakpoints getting hit). Add the "recoil_mode" flag to indicate whether we are single-stepping or continuing and whether or not we are inside the recoil. * Proper handling for swstep=true Since r_debug_step_soft calls r_debug_continue, it's already hitting the recoil case there. Move the recoil handling from r_debug_step to r_debug_step_hard only. For the swstep=true case, special handling is required inside r_debug_recoil. By resetting all of the breakpoints except the one we just hit, we ensure we can step the original instruction and hit the new swstep breakpoint. Add a new bp function called r_bp_restore_except to do this. To make matters worse, we cannot use a BreakpointItem pointer because that leads to a use-after-free condition. Instead, we the breakpoint address instead. Now breakpoints should work regardless of the swtep setting. * Always call the recoil before continuing Some callers of r_debug_continue might not have ever inserted any breakpoints before. If we don't restore breakpoints before each call to the underlying continue we won't hit them. * Hide software step breakpoint events from the user When a breakpoint even happens due to a software-step, hide it from the user. They aren't really breakpoints as far as they are concerned. * Improve process exit handling on Linux There are three types of process exiting events on Linux: 1. PTRACE_EVENT_EXIT occurs just before a process exits. It's not possible to prevent it from exiting, but it can be used to inspect the pre-exit state. 2. The process can exit for a variety of reasons and we can notice when we call waitpid(2). 3. The process could die randomly on us :-/ On Windows, h->wait will return R_DEBUG_REASON_EXIT_PID, but it's more likely on Linux to find out the process is already dead. * Check more bits within waitpid status We can often make a decision about what happened strictly by looking at the status returned from waitpid. In other cases, we need to call r_debug_handle_signals. If we reach the end of this function without knowing what happened, consider it an error.
2016-06-22 08:34:45 +00:00
cmd_anal_reg (core, input + 1);
}
2012-02-27 01:40:27 +00:00
//r_core_cmd (core, "|reg", 0);
break;
case 'p': // "dp"
2012-02-27 01:40:27 +00:00
cmd_debug_pid (core, input);
break;
case 'h': // "dh"
if (input[1]==' ') {
char *str = r_str_chop (strdup (input + 2));
r_config_set (core->config, "dbg.backend", str);
// implicit by config.set r_debug_use (core->dbg, str);
free (str);
} else r_debug_plugin_list (core->dbg);
2012-02-27 01:40:27 +00:00
break;
case 'i':
{
const char * help_message[] = {
"Usage: di", "", "Debugger target information",
"di", "", "Show debugger target information",
"dij", "", "Same as above, but in JSON format",
NULL
};
Major rework to the native debugger (esp on Linux) (#5185) The major contribution here is completely re-worked breakpoint hit/recoil handling. This work fixes #4907 and lays the ground work for future native debugger improvements (multi-threading, etc). * Give a human friendly type to enums * Change many wait functions to return RDebugReasonType * Better return checking (from r_debug_reg_sync, r_bp_restore) * Optimized register synchronization * Lots of comments and whitespace changes * Improved inferior death detection Handle EXIT_PID events differently than DEAD process events * Move breakpoint/recoil handling to wait/cont/step Rather than handing breakpoint related things inside cmd_debug.c, do that inside the r_debug API functions. This seems like the most logical place for it to live since it should apply to just about any platform/architecture. This also centralizes calling into "cmd.bp" handling via the CoreBind callback. * Track how the caller wishes to continue It turns out that handling break point recoils is very complicated. The ptrace API on Linux returns SIGTRAP for just about every type of operation (not just breakpoints getting hit). Add the "recoil_mode" flag to indicate whether we are single-stepping or continuing and whether or not we are inside the recoil. * Proper handling for swstep=true Since r_debug_step_soft calls r_debug_continue, it's already hitting the recoil case there. Move the recoil handling from r_debug_step to r_debug_step_hard only. For the swstep=true case, special handling is required inside r_debug_recoil. By resetting all of the breakpoints except the one we just hit, we ensure we can step the original instruction and hit the new swstep breakpoint. Add a new bp function called r_bp_restore_except to do this. To make matters worse, we cannot use a BreakpointItem pointer because that leads to a use-after-free condition. Instead, we the breakpoint address instead. Now breakpoints should work regardless of the swtep setting. * Always call the recoil before continuing Some callers of r_debug_continue might not have ever inserted any breakpoints before. If we don't restore breakpoints before each call to the underlying continue we won't hit them. * Hide software step breakpoint events from the user When a breakpoint even happens due to a software-step, hide it from the user. They aren't really breakpoints as far as they are concerned. * Improve process exit handling on Linux There are three types of process exiting events on Linux: 1. PTRACE_EVENT_EXIT occurs just before a process exits. It's not possible to prevent it from exiting, but it can be used to inspect the pre-exit state. 2. The process can exit for a variety of reasons and we can notice when we call waitpid(2). 3. The process could die randomly on us :-/ On Windows, h->wait will return R_DEBUG_REASON_EXIT_PID, but it's more likely on Linux to find out the process is already dead. * Check more bits within waitpid status We can often make a decision about what happened strictly by looking at the status returned from waitpid. In other cases, we need to call r_debug_handle_signals. If we reach the end of this function without knowing what happened, consider it an error.
2016-06-22 08:34:45 +00:00
RDebugInfo *rdi = r_debug_info (core->dbg, input + 2);
RDebugReasonType stop = r_debug_stop_reason (core->dbg);
char *escaped_str;
switch (input[1]) {
case '\0':
#define P r_cons_printf
#define PS(X, Y) {escaped_str = r_str_escape (Y);r_cons_printf(X, escaped_str);free(escaped_str);}
if (rdi) {
const char *s = r_debug_signal_resolve_i (core->dbg, core->dbg->reason.signum);
P ("type=%s\n", r_debug_reason_to_string (core->dbg->reason.type));
P ("signal=%s\n", s? s: "none");
P ("signum=%d\n", core->dbg->reason.signum);
P ("sigpid=%d\n", core->dbg->reason.tid);
P ("addr=0x%"PFMT64x"\n", core->dbg->reason.addr);
Major rework to the native debugger (esp on Linux) (#5185) The major contribution here is completely re-worked breakpoint hit/recoil handling. This work fixes #4907 and lays the ground work for future native debugger improvements (multi-threading, etc). * Give a human friendly type to enums * Change many wait functions to return RDebugReasonType * Better return checking (from r_debug_reg_sync, r_bp_restore) * Optimized register synchronization * Lots of comments and whitespace changes * Improved inferior death detection Handle EXIT_PID events differently than DEAD process events * Move breakpoint/recoil handling to wait/cont/step Rather than handing breakpoint related things inside cmd_debug.c, do that inside the r_debug API functions. This seems like the most logical place for it to live since it should apply to just about any platform/architecture. This also centralizes calling into "cmd.bp" handling via the CoreBind callback. * Track how the caller wishes to continue It turns out that handling break point recoils is very complicated. The ptrace API on Linux returns SIGTRAP for just about every type of operation (not just breakpoints getting hit). Add the "recoil_mode" flag to indicate whether we are single-stepping or continuing and whether or not we are inside the recoil. * Proper handling for swstep=true Since r_debug_step_soft calls r_debug_continue, it's already hitting the recoil case there. Move the recoil handling from r_debug_step to r_debug_step_hard only. For the swstep=true case, special handling is required inside r_debug_recoil. By resetting all of the breakpoints except the one we just hit, we ensure we can step the original instruction and hit the new swstep breakpoint. Add a new bp function called r_bp_restore_except to do this. To make matters worse, we cannot use a BreakpointItem pointer because that leads to a use-after-free condition. Instead, we the breakpoint address instead. Now breakpoints should work regardless of the swtep setting. * Always call the recoil before continuing Some callers of r_debug_continue might not have ever inserted any breakpoints before. If we don't restore breakpoints before each call to the underlying continue we won't hit them. * Hide software step breakpoint events from the user When a breakpoint even happens due to a software-step, hide it from the user. They aren't really breakpoints as far as they are concerned. * Improve process exit handling on Linux There are three types of process exiting events on Linux: 1. PTRACE_EVENT_EXIT occurs just before a process exits. It's not possible to prevent it from exiting, but it can be used to inspect the pre-exit state. 2. The process can exit for a variety of reasons and we can notice when we call waitpid(2). 3. The process could die randomly on us :-/ On Windows, h->wait will return R_DEBUG_REASON_EXIT_PID, but it's more likely on Linux to find out the process is already dead. * Check more bits within waitpid status We can often make a decision about what happened strictly by looking at the status returned from waitpid. In other cases, we need to call r_debug_handle_signals. If we reach the end of this function without knowing what happened, consider it an error.
2016-06-22 08:34:45 +00:00
P ("inbp=%s\n", r_str_bool (core->dbg->reason.bp_addr));
P ("pid=%d\n", rdi->pid);
P ("tid=%d\n", rdi->tid);
2016-03-24 19:22:50 +00:00
P ("uid=%d\n", rdi->uid);
P ("gid=%d\n", rdi->gid);
if (rdi->exe && *rdi->exe)
P ("exe=%s\n", rdi->exe);
if (rdi->cmdline && *rdi->cmdline)
P ("cmdline=%s\n", rdi->cmdline);
if (rdi->cwd && *rdi->cwd)
P ("cwd=%s\n", rdi->cwd);
}
if (stop != -1) P ("stopreason=%d\n", stop);
break;
case 'j':
P ("{");
if (rdi) {
const char *s = r_debug_signal_resolve_i (core->dbg, core->dbg->reason.signum);
P ("\"type\":\"%s\",", r_debug_reason_to_string (core->dbg->reason.type));
P ("\"signal\":\"%s\",", s? s: "none");
P ("\"signum\":%d,", core->dbg->reason.signum);
P ("\"sigpid\":%d,", core->dbg->reason.tid);
P ("\"addr\":%"PFMT64d",", core->dbg->reason.addr);
Major rework to the native debugger (esp on Linux) (#5185) The major contribution here is completely re-worked breakpoint hit/recoil handling. This work fixes #4907 and lays the ground work for future native debugger improvements (multi-threading, etc). * Give a human friendly type to enums * Change many wait functions to return RDebugReasonType * Better return checking (from r_debug_reg_sync, r_bp_restore) * Optimized register synchronization * Lots of comments and whitespace changes * Improved inferior death detection Handle EXIT_PID events differently than DEAD process events * Move breakpoint/recoil handling to wait/cont/step Rather than handing breakpoint related things inside cmd_debug.c, do that inside the r_debug API functions. This seems like the most logical place for it to live since it should apply to just about any platform/architecture. This also centralizes calling into "cmd.bp" handling via the CoreBind callback. * Track how the caller wishes to continue It turns out that handling break point recoils is very complicated. The ptrace API on Linux returns SIGTRAP for just about every type of operation (not just breakpoints getting hit). Add the "recoil_mode" flag to indicate whether we are single-stepping or continuing and whether or not we are inside the recoil. * Proper handling for swstep=true Since r_debug_step_soft calls r_debug_continue, it's already hitting the recoil case there. Move the recoil handling from r_debug_step to r_debug_step_hard only. For the swstep=true case, special handling is required inside r_debug_recoil. By resetting all of the breakpoints except the one we just hit, we ensure we can step the original instruction and hit the new swstep breakpoint. Add a new bp function called r_bp_restore_except to do this. To make matters worse, we cannot use a BreakpointItem pointer because that leads to a use-after-free condition. Instead, we the breakpoint address instead. Now breakpoints should work regardless of the swtep setting. * Always call the recoil before continuing Some callers of r_debug_continue might not have ever inserted any breakpoints before. If we don't restore breakpoints before each call to the underlying continue we won't hit them. * Hide software step breakpoint events from the user When a breakpoint even happens due to a software-step, hide it from the user. They aren't really breakpoints as far as they are concerned. * Improve process exit handling on Linux There are three types of process exiting events on Linux: 1. PTRACE_EVENT_EXIT occurs just before a process exits. It's not possible to prevent it from exiting, but it can be used to inspect the pre-exit state. 2. The process can exit for a variety of reasons and we can notice when we call waitpid(2). 3. The process could die randomly on us :-/ On Windows, h->wait will return R_DEBUG_REASON_EXIT_PID, but it's more likely on Linux to find out the process is already dead. * Check more bits within waitpid status We can often make a decision about what happened strictly by looking at the status returned from waitpid. In other cases, we need to call r_debug_handle_signals. If we reach the end of this function without knowing what happened, consider it an error.
2016-06-22 08:34:45 +00:00
P ("\"inbp\":%s,", r_str_bool (core->dbg->reason.bp_addr));
P ("\"pid\":%d,", rdi->pid);
P ("\"tid\":%d,", rdi->tid);
2016-03-24 19:22:50 +00:00
P ("\"uid\":%d,", rdi->uid);
P ("\"gid\":%d,", rdi->gid);
if (rdi->exe) PS("\"exe\":\"%s\",", rdi->exe)
if (rdi->cmdline) PS ("\"cmdline\":\"%s\",", rdi->cmdline);
if (rdi->cwd) PS ("\"cwd\":\"%s\",", rdi->cwd);
}
P ("\"stopreason\":%d}\n", stop);
break;
#undef P
#undef PS
case '?':
default:
r_core_cmd_help (core, help_message);
}
if (rdi)
r_debug_info_free (rdi);
}
2014-04-30 07:43:37 +00:00
break;
case 'x':
switch (input[1]) {
case 'a':
{
RAsmCode *acode;
r_asm_set_pc (core->assembler, core->offset);
Major rework to the native debugger (esp on Linux) (#5185) The major contribution here is completely re-worked breakpoint hit/recoil handling. This work fixes #4907 and lays the ground work for future native debugger improvements (multi-threading, etc). * Give a human friendly type to enums * Change many wait functions to return RDebugReasonType * Better return checking (from r_debug_reg_sync, r_bp_restore) * Optimized register synchronization * Lots of comments and whitespace changes * Improved inferior death detection Handle EXIT_PID events differently than DEAD process events * Move breakpoint/recoil handling to wait/cont/step Rather than handing breakpoint related things inside cmd_debug.c, do that inside the r_debug API functions. This seems like the most logical place for it to live since it should apply to just about any platform/architecture. This also centralizes calling into "cmd.bp" handling via the CoreBind callback. * Track how the caller wishes to continue It turns out that handling break point recoils is very complicated. The ptrace API on Linux returns SIGTRAP for just about every type of operation (not just breakpoints getting hit). Add the "recoil_mode" flag to indicate whether we are single-stepping or continuing and whether or not we are inside the recoil. * Proper handling for swstep=true Since r_debug_step_soft calls r_debug_continue, it's already hitting the recoil case there. Move the recoil handling from r_debug_step to r_debug_step_hard only. For the swstep=true case, special handling is required inside r_debug_recoil. By resetting all of the breakpoints except the one we just hit, we ensure we can step the original instruction and hit the new swstep breakpoint. Add a new bp function called r_bp_restore_except to do this. To make matters worse, we cannot use a BreakpointItem pointer because that leads to a use-after-free condition. Instead, we the breakpoint address instead. Now breakpoints should work regardless of the swtep setting. * Always call the recoil before continuing Some callers of r_debug_continue might not have ever inserted any breakpoints before. If we don't restore breakpoints before each call to the underlying continue we won't hit them. * Hide software step breakpoint events from the user When a breakpoint even happens due to a software-step, hide it from the user. They aren't really breakpoints as far as they are concerned. * Improve process exit handling on Linux There are three types of process exiting events on Linux: 1. PTRACE_EVENT_EXIT occurs just before a process exits. It's not possible to prevent it from exiting, but it can be used to inspect the pre-exit state. 2. The process can exit for a variety of reasons and we can notice when we call waitpid(2). 3. The process could die randomly on us :-/ On Windows, h->wait will return R_DEBUG_REASON_EXIT_PID, but it's more likely on Linux to find out the process is already dead. * Check more bits within waitpid status We can often make a decision about what happened strictly by looking at the status returned from waitpid. In other cases, we need to call r_debug_handle_signals. If we reach the end of this function without knowing what happened, consider it an error.
2016-06-22 08:34:45 +00:00
acode = r_asm_massemble (core->assembler, input + 2);
if (acode && *acode->buf_hex) {
r_reg_arena_push (core->dbg->reg);
r_debug_execute (core->dbg, acode->buf,
acode->len, 0);
r_reg_arena_pop (core->dbg->reg);
}
2014-08-18 01:22:16 +00:00
r_asm_code_free (acode);
}
break;
2015-10-01 16:26:31 +00:00
case 'e':
{
REgg *egg = core->egg;
RBuffer *b;
const char *asm_arch = r_config_get (core->config, "asm.arch");
int asm_bits = r_config_get_i (core->config, "asm.bits");
const char *asm_os = r_config_get (core->config, "asm.os");
r_egg_setup (egg, asm_arch, asm_bits, 0, asm_os);
r_egg_reset (egg);
Major rework to the native debugger (esp on Linux) (#5185) The major contribution here is completely re-worked breakpoint hit/recoil handling. This work fixes #4907 and lays the ground work for future native debugger improvements (multi-threading, etc). * Give a human friendly type to enums * Change many wait functions to return RDebugReasonType * Better return checking (from r_debug_reg_sync, r_bp_restore) * Optimized register synchronization * Lots of comments and whitespace changes * Improved inferior death detection Handle EXIT_PID events differently than DEAD process events * Move breakpoint/recoil handling to wait/cont/step Rather than handing breakpoint related things inside cmd_debug.c, do that inside the r_debug API functions. This seems like the most logical place for it to live since it should apply to just about any platform/architecture. This also centralizes calling into "cmd.bp" handling via the CoreBind callback. * Track how the caller wishes to continue It turns out that handling break point recoils is very complicated. The ptrace API on Linux returns SIGTRAP for just about every type of operation (not just breakpoints getting hit). Add the "recoil_mode" flag to indicate whether we are single-stepping or continuing and whether or not we are inside the recoil. * Proper handling for swstep=true Since r_debug_step_soft calls r_debug_continue, it's already hitting the recoil case there. Move the recoil handling from r_debug_step to r_debug_step_hard only. For the swstep=true case, special handling is required inside r_debug_recoil. By resetting all of the breakpoints except the one we just hit, we ensure we can step the original instruction and hit the new swstep breakpoint. Add a new bp function called r_bp_restore_except to do this. To make matters worse, we cannot use a BreakpointItem pointer because that leads to a use-after-free condition. Instead, we the breakpoint address instead. Now breakpoints should work regardless of the swtep setting. * Always call the recoil before continuing Some callers of r_debug_continue might not have ever inserted any breakpoints before. If we don't restore breakpoints before each call to the underlying continue we won't hit them. * Hide software step breakpoint events from the user When a breakpoint even happens due to a software-step, hide it from the user. They aren't really breakpoints as far as they are concerned. * Improve process exit handling on Linux There are three types of process exiting events on Linux: 1. PTRACE_EVENT_EXIT occurs just before a process exits. It's not possible to prevent it from exiting, but it can be used to inspect the pre-exit state. 2. The process can exit for a variety of reasons and we can notice when we call waitpid(2). 3. The process could die randomly on us :-/ On Windows, h->wait will return R_DEBUG_REASON_EXIT_PID, but it's more likely on Linux to find out the process is already dead. * Check more bits within waitpid status We can often make a decision about what happened strictly by looking at the status returned from waitpid. In other cases, we need to call r_debug_handle_signals. If we reach the end of this function without knowing what happened, consider it an error.
2016-06-22 08:34:45 +00:00
r_egg_load (egg, input + 1, 0);
2015-10-01 16:26:31 +00:00
r_egg_compile (egg);
b = r_egg_get_bin (egg);
r_asm_set_pc (core->assembler, core->offset);
r_reg_arena_push (core->dbg->reg);
r_debug_execute (core->dbg, b->buf, b->length, 0);
r_reg_arena_pop (core->dbg->reg);
}
break;
case 's':
2015-08-19 08:58:18 +00:00
if (input[2]) {
2015-10-31 02:45:14 +00:00
char *str;
r_cons_push ();
2015-10-31 02:45:14 +00:00
str = r_core_cmd_str (core, sdb_fmt (0, "gs %s", input + 2));
r_cons_pop ();
Major rework to the native debugger (esp on Linux) (#5185) The major contribution here is completely re-worked breakpoint hit/recoil handling. This work fixes #4907 and lays the ground work for future native debugger improvements (multi-threading, etc). * Give a human friendly type to enums * Change many wait functions to return RDebugReasonType * Better return checking (from r_debug_reg_sync, r_bp_restore) * Optimized register synchronization * Lots of comments and whitespace changes * Improved inferior death detection Handle EXIT_PID events differently than DEAD process events * Move breakpoint/recoil handling to wait/cont/step Rather than handing breakpoint related things inside cmd_debug.c, do that inside the r_debug API functions. This seems like the most logical place for it to live since it should apply to just about any platform/architecture. This also centralizes calling into "cmd.bp" handling via the CoreBind callback. * Track how the caller wishes to continue It turns out that handling break point recoils is very complicated. The ptrace API on Linux returns SIGTRAP for just about every type of operation (not just breakpoints getting hit). Add the "recoil_mode" flag to indicate whether we are single-stepping or continuing and whether or not we are inside the recoil. * Proper handling for swstep=true Since r_debug_step_soft calls r_debug_continue, it's already hitting the recoil case there. Move the recoil handling from r_debug_step to r_debug_step_hard only. For the swstep=true case, special handling is required inside r_debug_recoil. By resetting all of the breakpoints except the one we just hit, we ensure we can step the original instruction and hit the new swstep breakpoint. Add a new bp function called r_bp_restore_except to do this. To make matters worse, we cannot use a BreakpointItem pointer because that leads to a use-after-free condition. Instead, we the breakpoint address instead. Now breakpoints should work regardless of the swtep setting. * Always call the recoil before continuing Some callers of r_debug_continue might not have ever inserted any breakpoints before. If we don't restore breakpoints before each call to the underlying continue we won't hit them. * Hide software step breakpoint events from the user When a breakpoint even happens due to a software-step, hide it from the user. They aren't really breakpoints as far as they are concerned. * Improve process exit handling on Linux There are three types of process exiting events on Linux: 1. PTRACE_EVENT_EXIT occurs just before a process exits. It's not possible to prevent it from exiting, but it can be used to inspect the pre-exit state. 2. The process can exit for a variety of reasons and we can notice when we call waitpid(2). 3. The process could die randomly on us :-/ On Windows, h->wait will return R_DEBUG_REASON_EXIT_PID, but it's more likely on Linux to find out the process is already dead. * Check more bits within waitpid status We can often make a decision about what happened strictly by looking at the status returned from waitpid. In other cases, we need to call r_debug_handle_signals. If we reach the end of this function without knowing what happened, consider it an error.
2016-06-22 08:34:45 +00:00
r_core_cmdf (core, "dx %s", str); //`gs %s`", input + 2);
free (str);
2015-08-19 08:58:18 +00:00
} else {
eprintf ("Missing parameter used in gs by dxs\n");
}
break;
case 'r':
r_reg_arena_push (core->dbg->reg);
if (input[2] == ' ') {
ut8 bytes[4096];
if (strlen (input + 2) < 4096){
int bytes_len = r_hex_str2bin (input + 2,
bytes);
if (bytes_len > 0) {
r_debug_execute (core->dbg,
bytes, bytes_len,
0);
2015-07-31 18:53:34 +00:00
} else {
eprintf ("Invalid hexpairs\n");
}
} else eprintf ("Injection opcodes so long\n");
}
r_reg_arena_pop (core->dbg->reg);
break;
case ' ':
{
ut8 bytes[4096];
if (strlen (input + 2) < 4096){
int bytes_len = r_hex_str2bin (input + 2, bytes);
if (bytes_len>0) r_debug_execute (core->dbg,
bytes, bytes_len, 0);
2015-07-31 18:53:34 +00:00
else eprintf ("Invalid hexpairs\n");
} else eprintf ("Injection opcodes so long\n");
}
break;
case '?':
default:
{
const char* help_msg[] = {
"Usage: dx", "", " # Code injection commands",
"dx", " <opcode>...", "Inject opcodes",
"dxa", " nop", "Assemble code and inject",
"dxe", " egg-expr", "compile egg expression and inject it",
"dxr", " <opcode>...", "Inject opcodes and restore state",
"dxs", " write 1, 0x8048, 12", "Syscall injection (see gs)",
"\nExamples:", "", "",
"dx", " 9090", "Inject two x86 nop",
"\"dxa mov eax,6;mov ebx,0;int 0x80\"", "", "Inject and restore state",
NULL};
r_core_cmd_help (core, help_msg);
2014-06-20 12:18:18 +00:00
}
break;
}
break;
2012-02-27 01:40:27 +00:00
case 'o':
2016-03-21 16:20:15 +00:00
switch (input[1]) {
case 'o': //"doo" : reopen in debugger
r_core_file_reopen_debug (core, input + 2);
break;
case 0: // "do"
r_core_file_reopen (core, input[1] ? input + 2: NULL, 0, 1);
break;
case '?':
default:
{
2016-03-21 16:20:15 +00:00
const char* help_msg[] = {
"Usage:", "do", " # Debug commands",
"do", "", "Open process (reload, alias for 'oo')",
"doo", "[args]", "Reopen in debugger mode with args (alias for 'ood')",
NULL};
r_core_cmd_help (core, help_msg);
}
break;
}
2012-02-27 01:40:27 +00:00
break;
case 'w':
r_cons_break (static_debug_stop, core->dbg);
for (;!r_cons_singleton ()->breaked;) {
int pid = atoi (input + 1);
2012-12-07 15:00:36 +00:00
//int opid = core->dbg->pid = pid;
int res = r_debug_kill (core->dbg, pid, 0, 0);
if (!res) break;
r_sys_usleep (200);
}
r_cons_break_end ();
break;
case 'k':
r_core_debug_kill (core, input + 1);
break;
case 'e':
r_core_debug_esil (core, input + 1);
break;
2016-03-24 19:22:50 +00:00
case 'g': // "dg"
if (core->dbg->h && core->dbg->h->gcore) {
if (core->dbg->pid == -1) {
eprintf ("Not debugging, can't write core.\n");
break;
}
2016-05-21 13:11:16 +00:00
char *corefile = get_corefile_name (input + 1, core->dbg->pid);
eprintf ("Writing to file '%s'\n", corefile);
r_file_rm (corefile);
RBuffer *dst = r_buf_new ();
2016-06-02 01:19:31 +00:00
if (dst) {
if (!core->dbg->h->gcore (core->dbg, dst)) {
eprintf ("dg: coredump failed\n");
}
r_file_dump (corefile, dst->buf, dst->length, 1);
r_buf_free (dst);
} else {
perror ("r_buf_new_file");
2016-05-21 13:11:16 +00:00
}
2016-04-09 12:56:08 +00:00
free (corefile);
2016-03-24 19:22:50 +00:00
}
break;
case '?':
default:
{
2014-06-20 12:18:18 +00:00
const char* help_msg[] = {
"Usage:", "d", " # Debug commands",
"db", "[?]", "Breakpoints commands",
2015-08-22 12:19:33 +00:00
"dbt", "", "Display backtrace based on dbg.btdepth and dbg.btalgo",
"dc", "[?]", "Continue execution",
"dd", "[?]", "File descriptors (!fd in r1)",
"de", "[-sc] [rwx] [rm] [e]", "Debug with ESIL (see de?)",
2016-03-24 19:22:50 +00:00
"dg", " <file>", "Generate a core-file (WIP)",
"dh", " [handler]", "List or set debugger handler",
"dH", " [handler]", "Transplant process to a new handler",
"di", "", "Show debugger backend information (See dh)",
"dk", "[?]", "List, send, get, set, signal handlers of child",
"dm", "[?]", "Show memory maps",
"do", "", "Open process (reload, alias for 'oo')",
2016-03-21 16:20:15 +00:00
"doo", "[args]", "Reopen in debugger mode with args (alias for 'ood')",
"dp", "[?]", "List, attach to process or thread id",
"dr", "[?]", "Cpu registers",
"ds", "[?]", "Step, over, source line",
"dt", "[?]", "Display instruction traces (dtr=reset)",
"dw", " <pid>", "Block prompt until pid dies",
"dx", "[?]", "Inject and run code on target process (See gs)",
2014-06-20 12:18:18 +00:00
NULL};
r_core_cmd_help (core, help_msg);
}
2012-02-27 01:40:27 +00:00
break;
}
if (follow > 0) {
2015-10-31 00:57:52 +00:00
ut64 pc = r_debug_reg_get (core->dbg, "PC");
if ((pc < core->offset) || (pc > (core->offset + follow)))
2015-10-31 00:57:52 +00:00
r_core_cmd0 (core, "sr PC");
2012-02-27 01:40:27 +00:00
}
return 0;
}