2014-01-08 22:23:06 +00:00
|
|
|
/* radare - LGPL - Copyright 2009-2014 - pancake */
|
2012-06-07 01:41:21 +00:00
|
|
|
|
2012-02-27 01:40:27 +00:00
|
|
|
static void dot_r_graph_traverse(RCore *core, RGraph *t) {
|
|
|
|
RGraphNode *n, *n2;
|
|
|
|
RListIter *iter, *iter2;
|
|
|
|
const char *gfont = r_config_get (core->config, "graph.font");
|
2013-03-03 00:11:44 +00:00
|
|
|
r_cons_printf ("digraph code {\n"
|
|
|
|
"graph [bgcolor=white];\n"
|
|
|
|
" node [color=lightgray, style=filled"
|
|
|
|
" shape=box fontname=\"%s\" fontsize=\"8\"];\n", gfont);
|
2012-02-27 01:40:27 +00:00
|
|
|
r_list_foreach (t->nodes, iter, n) {
|
2013-03-03 00:11:44 +00:00
|
|
|
r_cons_printf ("\"0x%08"PFMT64x"\" [URL=\"0x%08"PFMT64x
|
|
|
|
"\" color=\"lightgray\" label=\"0x%08"PFMT64x
|
|
|
|
" (%d)\"]\n", n->addr, n->addr, n->addr, n->refs);
|
2012-02-27 01:40:27 +00:00
|
|
|
r_list_foreach (n->children, iter2, n2) {
|
2013-03-03 00:11:44 +00:00
|
|
|
r_cons_printf ("\"0x%08"PFMT64x"\" -> \"0x%08"PFMT64x
|
|
|
|
"\" [color=\"red\"];\n", n->addr, n2->addr);
|
2012-02-27 01:40:27 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
r_cons_printf ("}\n");
|
|
|
|
}
|
|
|
|
|
|
|
|
static int checkbpcallback(RCore *core) ;
|
|
|
|
static int step_until(RCore *core, ut64 addr) {
|
|
|
|
ut64 off = r_debug_reg_get (core->dbg, "pc");
|
|
|
|
if (off == 0LL) {
|
|
|
|
eprintf ("Cannot 'drn pc'\n");
|
|
|
|
return R_FALSE;
|
|
|
|
}
|
|
|
|
if (addr == 0LL) {
|
|
|
|
eprintf ("Cannot continue until address 0\n");
|
|
|
|
return R_FALSE;
|
|
|
|
}
|
|
|
|
do {
|
|
|
|
r_debug_step (core->dbg, 1);
|
|
|
|
if (checkbpcallback (core)) {
|
|
|
|
eprintf ("Interrupted by a breakpoint\n");
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
off = r_debug_reg_get (core->dbg, "pc");
|
|
|
|
// check breakpoint here
|
|
|
|
} while (off != addr);
|
|
|
|
return R_TRUE;
|
|
|
|
}
|
|
|
|
|
2012-11-13 03:38:26 +00:00
|
|
|
/* until end of frame */
|
|
|
|
static int step_until_eof(RCore *core) {
|
|
|
|
ut64 off, now = r_debug_reg_get (core->dbg, "sp");
|
|
|
|
do {
|
2014-02-18 02:06:13 +00:00
|
|
|
if (!r_debug_step (core->dbg, 1))
|
|
|
|
break;
|
2012-11-13 03:38:26 +00:00
|
|
|
if (checkbpcallback (core)) {
|
|
|
|
eprintf ("Interrupted by a breakpoint\n");
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
off = r_debug_reg_get (core->dbg, "sp");
|
|
|
|
// check breakpoint here
|
|
|
|
} while (off <= now);
|
|
|
|
return R_TRUE;
|
|
|
|
}
|
|
|
|
|
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;
|
|
|
|
ut64 off = r_debug_reg_get (core->dbg, "pc");
|
|
|
|
if (off == 0LL) {
|
|
|
|
eprintf ("Cannot 'drn pc'\n");
|
|
|
|
return R_FALSE;
|
|
|
|
}
|
|
|
|
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)) {
|
2012-02-27 01:40:27 +00:00
|
|
|
eprintf ("--> 0x%08"PFMT64x" %s : %d\n", off, file, line);
|
|
|
|
eprintf ("--> %s\n", r_file_slurp_line (file, line, 0));
|
|
|
|
find_meta = R_FALSE;
|
|
|
|
} else {
|
|
|
|
eprintf ("--> Stepping until dwarf line\n");
|
|
|
|
find_meta = R_TRUE;
|
|
|
|
}
|
|
|
|
do {
|
|
|
|
r_debug_step (core->dbg, 1);
|
|
|
|
if (checkbpcallback (core)) {
|
|
|
|
eprintf ("Interrupted by a breakpoint\n");
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
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);
|
|
|
|
return R_FALSE;
|
|
|
|
}
|
|
|
|
} while (!strcmp (file, file2) && line == line2);
|
|
|
|
eprintf ("--> 0x%08"PFMT64x" %s : %d\n", off, file2, line2);
|
|
|
|
eprintf ("--> %s\n", r_file_slurp_line (file2, line2, 0));
|
|
|
|
return R_TRUE;
|
|
|
|
}
|
|
|
|
|
|
|
|
static void cmd_debug_pid(RCore *core, const char *input) {
|
|
|
|
const char *ptr;
|
|
|
|
int pid, sig;
|
|
|
|
switch (input[1]) {
|
|
|
|
case 'k':
|
2013-09-06 22:39:08 +00:00
|
|
|
/* 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);
|
|
|
|
ptr = strchr (input, ' ');
|
|
|
|
sig = ptr? atoi (ptr+1): 0;
|
|
|
|
if (pid > 0) {
|
|
|
|
eprintf ("Sending signal '%d' to pid '%d'\n", sig, pid);
|
2012-12-07 11:03:53 +00:00
|
|
|
r_debug_kill (core->dbg, 0, R_FALSE, sig);
|
2012-12-06 02:11:40 +00:00
|
|
|
} else eprintf ("cmd_debug_pid: Invalid arguments (%s)\n", input);
|
2012-02-27 01:40:27 +00:00
|
|
|
break;
|
|
|
|
case 'n':
|
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;
|
|
|
|
case 't':
|
|
|
|
switch (input[2]) {
|
|
|
|
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 '=':
|
|
|
|
case ' ':
|
|
|
|
r_debug_select (core->dbg, core->dbg->pid,
|
|
|
|
(int) r_num_math (core->num, input+3));
|
|
|
|
break;
|
|
|
|
default:
|
|
|
|
r_debug_thread_list (core->dbg, core->dbg->pid);
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
case 'a':
|
2012-11-05 01:00:34 +00:00
|
|
|
if (input[2]) {
|
2013-03-03 00:11:44 +00:00
|
|
|
r_debug_attach (core->dbg, (int) r_num_math (
|
|
|
|
core->num, input+2));
|
|
|
|
} else r_debug_attach (core->dbg, core->file->fd->fd);
|
2012-02-27 01:40:27 +00:00
|
|
|
r_debug_select (core->dbg, core->dbg->pid, core->dbg->tid);
|
2012-07-05 16:02:12 +00:00
|
|
|
r_config_set_i (core->config, "dbg.swstep",
|
|
|
|
(core->dbg->h && !core->dbg->h->canstep));
|
2012-02-27 01:40:27 +00:00
|
|
|
break;
|
|
|
|
case 'f':
|
|
|
|
r_debug_select (core->dbg, core->file->fd->fd, core->dbg->tid);
|
|
|
|
break;
|
|
|
|
case '=':
|
|
|
|
r_debug_select (core->dbg,
|
|
|
|
(int) r_num_math (core->num, input+2), core->dbg->tid);
|
|
|
|
break;
|
|
|
|
case '*':
|
|
|
|
r_debug_pid_list (core->dbg, 0);
|
|
|
|
break;
|
2013-08-18 22:36:17 +00:00
|
|
|
case 'e':
|
|
|
|
{
|
|
|
|
int pid = (input[2] == ' ')? atoi(input+2): core->dbg->pid;
|
|
|
|
char *exe = r_sys_pid_to_path (pid);
|
|
|
|
if (exe) {
|
|
|
|
r_cons_printf ("%s\n", exe);
|
|
|
|
free (exe);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
break;
|
2012-02-27 01:40:27 +00:00
|
|
|
case ' ':
|
|
|
|
r_debug_pid_list (core->dbg,
|
|
|
|
(int) r_num_math (core->num, input+2));
|
|
|
|
break;
|
2012-10-31 15:37:19 +00:00
|
|
|
case '?':
|
2013-12-28 01:34:15 +00:00
|
|
|
r_cons_printf ("|Usage: dp[=][pid]\n"
|
|
|
|
"| dp list current pid and childrens\n"
|
|
|
|
"| dp 748 list children of pid\n"
|
|
|
|
"| dp* list all attachable pids\n"
|
|
|
|
"| dpe show path to executable\n"
|
|
|
|
"| dpa 377 attach and select this pid\n"
|
|
|
|
"| dp=748 select this pid\n"
|
|
|
|
"| dpf Attach to pid like file fd // HACK\n"
|
|
|
|
"| dpn Create new process (fork)\n"
|
|
|
|
"| dpnt Create new thread (clone)\n"
|
|
|
|
"| dpt List threads of current pid\n"
|
|
|
|
"| dpt 74 List threads of given process\n"
|
|
|
|
"| dpt=64 Attach to thread\n"
|
|
|
|
"| dpk P S send signal S to P process id\n");
|
2012-10-31 15:37:19 +00:00
|
|
|
break;
|
2012-02-27 01:40:27 +00:00
|
|
|
default:
|
|
|
|
eprintf ("selected: %d %d\n", core->dbg->pid, core->dbg->tid);
|
|
|
|
r_debug_pid_list (core->dbg, core->dbg->pid);
|
|
|
|
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;
|
2013-03-03 00:11:44 +00:00
|
|
|
eprintf ("Trap tracing 0x%08"PFMT64x"-0x%08"PFMT64x"\n",
|
|
|
|
core->offset, core->offset+len);
|
2012-02-27 01:40:27 +00:00
|
|
|
r_reg_arena_swap (core->dbg->reg, R_TRUE);
|
|
|
|
r_bp_traptrace_reset (core->dbg->bp, R_TRUE);
|
|
|
|
r_bp_traptrace_add (core->dbg->bp, core->offset, core->offset+len);
|
|
|
|
r_bp_traptrace_enable (core->dbg->bp, R_TRUE);
|
|
|
|
do {
|
|
|
|
ut8 buf[32];
|
|
|
|
r_debug_continue (core->dbg);
|
|
|
|
if (checkbpcallback (core)) {
|
|
|
|
eprintf ("Interrupted by breakpoint\n");
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
addr = r_debug_reg_get (core->dbg, "pc");
|
|
|
|
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));
|
2013-12-06 04:04:17 +00:00
|
|
|
} while (r_bp_traptrace_at (core->dbg->bp, addr, analop.size));
|
2012-02-27 01:40:27 +00:00
|
|
|
r_bp_traptrace_enable (core->dbg->bp, R_FALSE);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
static int cmd_debug_map(RCore *core, const char *input) {
|
|
|
|
char file[128];
|
|
|
|
RListIter *iter;
|
|
|
|
RDebugMap *map;
|
|
|
|
ut64 addr = core->offset;
|
|
|
|
|
|
|
|
switch (input[0]) {
|
|
|
|
case '?':
|
|
|
|
r_cons_printf (
|
2013-12-28 01:34:15 +00:00
|
|
|
"|Usage: dm [size]\n"
|
|
|
|
"| dm List memory maps of target process\n"
|
|
|
|
"| dmj List memmaps in JSON format\n"
|
|
|
|
"| dm* Same as above but in radare commands\n"
|
|
|
|
"| dm addr size Allocate size bytes at addr (anywhere if addr is -1) in child process\n"
|
|
|
|
"| dm-0x8048 Deallocate memory map of address 0x8048\n"
|
|
|
|
"| dmp A S rwx Change page at A with size S protection permissions\n"
|
|
|
|
"| dmd [file] Dump current debug map region to a file (from-to.dmp) (see Sd)\n"
|
|
|
|
"| dml file Load contents of file into the current map region (see Sl)\n"
|
|
|
|
"| dmi [addr|libname] [symname] List symbols of target lib\n"
|
|
|
|
"| dmi* [addr|libname] [symname] Same as above but in radare commands\n"
|
|
|
|
//"| dm rw- esp 9K set 9KB of the stack as read+write (no exec)\n"
|
|
|
|
"|TODO: map files in process memory. (dmf file @ [addr])\n");
|
2012-02-27 01:40:27 +00:00
|
|
|
break;
|
|
|
|
case 'p':
|
|
|
|
if (input[1] == ' ') {
|
|
|
|
int perms;
|
|
|
|
char *p, *q;
|
|
|
|
ut64 size, addr;
|
|
|
|
p = strchr (input+2, ' ');
|
|
|
|
if (p) {
|
|
|
|
*p++ = 0;
|
|
|
|
q = strchr (p, ' ');
|
|
|
|
if (q) {
|
|
|
|
*q++ = 0;
|
|
|
|
addr = r_num_math (core->num, input+2);
|
|
|
|
size = r_num_math (core->num, p);
|
|
|
|
perms = r_str_rwx (q);
|
|
|
|
eprintf ("(%s)(%s)(%s)\n", input+2, p, q);
|
|
|
|
eprintf ("0x%08"PFMT64x" %d %o\n", addr, (int) size, perms);
|
|
|
|
r_debug_map_protect (core->dbg, addr, size, perms);
|
|
|
|
} else eprintf ("See dm?\n");
|
|
|
|
} else eprintf ("See dm?\n");
|
|
|
|
} else eprintf ("See dm?\n");
|
|
|
|
break;
|
|
|
|
case 'd':
|
|
|
|
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) {
|
|
|
|
ut8 *buf = malloc (map->size);
|
|
|
|
#warning TODO: use mmap here. we need a portable implementation
|
|
|
|
if (!buf) {
|
|
|
|
eprintf ("Cannot allocate 0x%08"PFMT64x" bytes\n", map->size);
|
|
|
|
return R_FALSE;
|
|
|
|
}
|
|
|
|
r_io_read_at (core->io, map->addr, buf, map->size);
|
|
|
|
if (input[1]==' ' && input[2]) {
|
2014-04-22 23:39:17 +00:00
|
|
|
snprintf (file, sizeof (file), "%s", input+2);
|
2013-03-03 00:11:44 +00:00
|
|
|
} else snprintf (file, sizeof (file),
|
|
|
|
"0x%08"PFMT64x"-0x%08"PFMT64x"-%s.dmp",
|
2012-02-27 01:40:27 +00:00
|
|
|
map->addr, map->addr_end, r_str_rwx_i (map->perm));
|
|
|
|
if (!r_file_dump (file, buf, map->size)) {
|
|
|
|
eprintf ("Cannot write '%s'\n", file);
|
|
|
|
free (buf);
|
|
|
|
return R_FALSE;
|
|
|
|
}
|
|
|
|
eprintf ("Dumped %d bytes into %s\n", (int)map->size, file);
|
|
|
|
free (buf);
|
|
|
|
return R_TRUE;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
eprintf ("No debug region found here\n");
|
|
|
|
return R_FALSE;
|
|
|
|
case 'l':
|
|
|
|
if (input[1] != ' ') {
|
|
|
|
eprintf ("Usage: dml [file]\n");
|
|
|
|
return R_FALSE;
|
|
|
|
}
|
|
|
|
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;
|
|
|
|
char *buf = r_file_slurp (input+2, &sz);
|
|
|
|
#warning TODO: use mmap here. we need a portable implementation
|
|
|
|
if (!buf) {
|
|
|
|
eprintf ("Cannot allocate 0x%08"PFMT64x" bytes\n", map->size);
|
|
|
|
return R_FALSE;
|
|
|
|
}
|
|
|
|
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);
|
|
|
|
return R_TRUE;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
eprintf ("No debug region found here\n");
|
|
|
|
return R_FALSE;
|
|
|
|
case 'i':
|
|
|
|
{ // Move to a separate function
|
|
|
|
RCoreBinFilter filter;
|
|
|
|
const char *libname = NULL, *symname = NULL;
|
|
|
|
char *ptr = strdup (r_str_trim_head ((char*)input+2));
|
|
|
|
int i;
|
|
|
|
ut64 baddr;
|
|
|
|
|
|
|
|
addr = 0LL;
|
|
|
|
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);
|
|
|
|
}
|
|
|
|
r_debug_map_sync (core->dbg); // update process memory maps
|
|
|
|
r_list_foreach (core->dbg->maps, iter, map) {
|
|
|
|
if ((addr != -1 && (addr >= map->addr && addr < map->addr_end)) ||
|
|
|
|
(libname != NULL && (strstr (map->name, libname)))) {
|
2014-01-18 15:26:09 +00:00
|
|
|
RBinObject *o = core->bin->cur->o;
|
2012-02-27 01:40:27 +00:00
|
|
|
filter.offset = 0LL;
|
|
|
|
filter.name = (char *)symname;
|
2012-08-04 21:48:06 +00:00
|
|
|
baddr = o->baddr;
|
|
|
|
o->baddr = map->addr;
|
2012-02-27 01:40:27 +00:00
|
|
|
r_core_bin_info (core, R_CORE_BIN_ACC_SYMBOLS, (input[1]=='*'),
|
|
|
|
R_TRUE, &filter, 0);
|
2012-08-04 21:48:06 +00:00
|
|
|
o->baddr = baddr;
|
2012-02-27 01:40:27 +00:00
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
free (ptr);
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
case ' ':
|
2013-07-21 01:05:56 +00:00
|
|
|
{
|
|
|
|
char *p;
|
|
|
|
int size;
|
|
|
|
p = strchr (input+2, ' ');
|
|
|
|
if (p) {
|
|
|
|
*p++ = 0;
|
|
|
|
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");
|
|
|
|
return R_FALSE;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
case '-':
|
|
|
|
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);
|
|
|
|
return R_TRUE;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
eprintf ("The address doesn't match with any map.\n");
|
2013-10-15 01:56:01 +00:00
|
|
|
break;
|
|
|
|
case '\0':
|
|
|
|
case '*':
|
|
|
|
case 'j':
|
2012-02-27 01:40:27 +00:00
|
|
|
r_debug_map_sync (core->dbg); // update process memory maps
|
2013-10-06 13:04:19 +00:00
|
|
|
r_debug_map_list (core->dbg, core->offset, input[0]);
|
2012-02-27 01:40:27 +00:00
|
|
|
break;
|
|
|
|
}
|
|
|
|
return R_TRUE;
|
|
|
|
}
|
|
|
|
|
|
|
|
static void cmd_debug_reg(RCore *core, const char *str) {
|
2014-01-08 22:23:06 +00:00
|
|
|
int size, i, type = R_REG_TYPE_GPR;
|
|
|
|
int bits = (core->dbg->bits & R_SYS_BITS_64)? 64: 32;
|
2012-02-27 01:40:27 +00:00
|
|
|
struct r_reg_item_t *r;
|
|
|
|
const char *name;
|
|
|
|
char *arg;
|
|
|
|
switch (str[0]) {
|
|
|
|
case '?':
|
|
|
|
if (str[1]) {
|
|
|
|
ut64 off;
|
2014-01-28 03:38:02 +00:00
|
|
|
r_debug_reg_sync (core->dbg, -1, 0); //R_REG_TYPE_GPR, R_FALSE);
|
2012-02-27 01:40:27 +00:00
|
|
|
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);
|
2014-05-03 23:41:32 +00:00
|
|
|
r_cons_printf ("0x%08"PFMT64x"\n", off);
|
2012-02-27 01:40:27 +00:00
|
|
|
//r_reg_get_value (core->dbg->reg, r));
|
|
|
|
} else
|
2014-01-08 22:23:06 +00:00
|
|
|
r_cons_printf ("|Usage: dr[*] [type] [size] - get/set registers\n"
|
|
|
|
"| dr show 'gpr' registers\n"
|
|
|
|
"| dr all show all registers\n"
|
|
|
|
"| dr flg 1 show flag registers ('flg' is type, see drt)\n"
|
|
|
|
"| dr 16 show 16 bit registers\n"
|
|
|
|
"| dr 32 show 32 bit registers\n"
|
|
|
|
"| dr eax=33 set register value. eax = 33\n"
|
|
|
|
"| dr? display this help message\n"
|
|
|
|
"| drs? stack register states\n"
|
|
|
|
"| drt show all register types\n"
|
|
|
|
"| drn [pc] get regname for pc,sp,bp,a0-3,zf,cf,of,sg\n"
|
|
|
|
"| drc [name] related to conditional flag registers\n"
|
|
|
|
"| drd show only different registers\n"
|
|
|
|
"| dro show previous (old) values of registers\n"
|
|
|
|
"| dr= show registers in columns\n"
|
|
|
|
"| dr?eax show value of eax register\n"
|
|
|
|
"| .dr* include common register values in flags\n"
|
|
|
|
"| .dr- unflag all registers\n"
|
|
|
|
"| drp [file] load register metadata file\n"
|
|
|
|
"| drp display current register profile\n"
|
|
|
|
"| drb [type] display hexdump of gpr arena (WIP)\n");
|
2012-02-27 01:40:27 +00:00
|
|
|
// TODO: 'drs' to swap register arenas and display old register valuez
|
|
|
|
break;
|
|
|
|
case 'b':
|
|
|
|
{ // WORK IN PROGRESS // DEBUG COMMAND
|
|
|
|
int len;
|
|
|
|
const ut8 *buf = r_reg_get_bytes (core->dbg->reg, R_REG_TYPE_GPR, &len);
|
|
|
|
//r_print_hexdump (core->print, 0LL, buf, len, 16, 16);
|
|
|
|
r_print_hexdump (core->print, 0LL, buf, len, 32, 4);
|
|
|
|
}
|
|
|
|
break;
|
2014-01-08 22:23:06 +00:00
|
|
|
case 'c':
|
|
|
|
// 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_printf ("%s\n", 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;
|
2014-01-28 03:03:35 +00:00
|
|
|
case 'x':
|
|
|
|
switch (str[1]) {
|
|
|
|
case '-':
|
2014-01-28 03:38:02 +00:00
|
|
|
r_debug_reg_sync (core->dbg, R_REG_TYPE_DRX, R_FALSE);
|
2014-01-28 03:03:35 +00:00
|
|
|
r_debug_drx_unset (core->dbg, atoi (str+2));
|
2014-01-28 03:38:02 +00:00
|
|
|
r_debug_reg_sync (core->dbg, R_REG_TYPE_DRX, R_TRUE);
|
2014-01-28 03:03:35 +00:00
|
|
|
break;
|
|
|
|
case ' ': {
|
|
|
|
char *s = strdup (str+2);
|
2014-01-31 01:02:51 +00:00
|
|
|
char sl, n, rwx;
|
2014-01-28 03:03:35 +00:00
|
|
|
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) {
|
|
|
|
r_debug_reg_sync (core->dbg, R_REG_TYPE_DRX, R_FALSE);
|
|
|
|
r_debug_drx_set (core->dbg, n, 0, 0, 0, 0);
|
|
|
|
r_debug_reg_sync (core->dbg, R_REG_TYPE_DRX, R_TRUE);
|
|
|
|
} else {
|
|
|
|
r_debug_reg_sync (core->dbg, R_REG_TYPE_DRX, R_FALSE);
|
|
|
|
r_debug_drx_set (core->dbg, n, off, len, rwx, 0);
|
|
|
|
r_debug_reg_sync (core->dbg, R_REG_TYPE_DRX, R_TRUE);
|
|
|
|
}
|
|
|
|
} else eprintf ("|Usage: drx N [address] [length] [rwx]\n");
|
2014-01-28 03:03:35 +00:00
|
|
|
free (s);
|
|
|
|
} break;
|
|
|
|
case '\0':
|
2014-01-11 22:48:55 +00:00
|
|
|
r_debug_reg_sync (core->dbg, R_REG_TYPE_DRX, R_FALSE);
|
2014-01-28 03:03:35 +00:00
|
|
|
r_debug_drx_list (core->dbg);
|
|
|
|
break;
|
|
|
|
default:
|
|
|
|
r_cons_printf (
|
|
|
|
"|Usage: drx[-] [N A L RWX]\n"
|
|
|
|
"| drx list all (x86?) hardware breakpoints\n"
|
|
|
|
"| drx N A L RWX set drN to Address with Length and perms\n"
|
|
|
|
"| drx-N clear drN hw breakpoint\n");
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
break;
|
2013-08-29 14:59:24 +00:00
|
|
|
case 's':
|
|
|
|
switch (str[1]) {
|
|
|
|
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 '?':
|
|
|
|
r_cons_printf ("Usage: drs[+-]\n"
|
|
|
|
"drs+ push register state\n"
|
|
|
|
"drs- pop register state\n"
|
|
|
|
"drs list register stack\n");
|
|
|
|
break;
|
|
|
|
default:
|
2014-01-08 22:23:06 +00:00
|
|
|
r_cons_printf ("%d\n", r_list_length (
|
|
|
|
core->dbg->reg->regset[0].pool));
|
2013-08-29 14:59:24 +00:00
|
|
|
break;
|
|
|
|
}
|
|
|
|
break;
|
2012-02-27 01:40:27 +00:00
|
|
|
case 'p':
|
|
|
|
if (!str[1]) {
|
|
|
|
if (core->dbg->reg->reg_profile_str) {
|
|
|
|
//core->anal->reg = core->dbg->reg;
|
|
|
|
r_cons_printf ("%s\n", 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");
|
|
|
|
} else r_reg_set_profile (core->dbg->reg, str+2);
|
|
|
|
break;
|
|
|
|
case 't':
|
|
|
|
for (i=0; (name=r_reg_get_type (i)); i++)
|
|
|
|
r_cons_printf ("%s\n", name);
|
|
|
|
break;
|
|
|
|
case 'n':
|
|
|
|
name = r_reg_get_name (core->dbg->reg, r_reg_get_name_idx (str+2));
|
|
|
|
if (name && *name)
|
|
|
|
r_cons_printf ("%s\n", name);
|
2014-01-08 22:23:06 +00:00
|
|
|
else eprintf ("Oops. try drn [pc|sp|bp|a0|a1|a2|a3|zf|sf|nf|of]\n");
|
2012-02-27 01:40:27 +00:00
|
|
|
break;
|
|
|
|
case 'd':
|
2012-06-14 00:18:15 +00:00
|
|
|
r_debug_reg_list (core->dbg, R_REG_TYPE_GPR, bits, 3); // XXX detect which one is current usage
|
2012-02-27 01:40:27 +00:00
|
|
|
break;
|
|
|
|
case 'o':
|
|
|
|
r_reg_arena_swap (core->dbg->reg, R_FALSE);
|
2012-06-14 00:18:15 +00:00
|
|
|
r_debug_reg_list (core->dbg, R_REG_TYPE_GPR, bits, 0); // XXX detect which one is current usage
|
2012-02-27 01:40:27 +00:00
|
|
|
r_reg_arena_swap (core->dbg->reg, R_FALSE);
|
|
|
|
break;
|
|
|
|
case '=':
|
|
|
|
if (r_debug_reg_sync (core->dbg, R_REG_TYPE_GPR, R_FALSE)) {
|
2012-06-14 00:18:15 +00:00
|
|
|
r_debug_reg_list (core->dbg, R_REG_TYPE_GPR, bits, 2); // XXX detect which one is current usage
|
2012-02-27 01:40:27 +00:00
|
|
|
} //else eprintf ("Cannot retrieve registers from pid %d\n", core->dbg->pid);
|
|
|
|
break;
|
|
|
|
case '*':
|
2013-01-10 17:20:36 +00:00
|
|
|
if (r_debug_reg_sync (core->dbg, R_REG_TYPE_GPR, R_FALSE))
|
|
|
|
r_debug_reg_list (core->dbg, R_REG_TYPE_GPR, bits, '*');
|
2012-02-27 01:40:27 +00:00
|
|
|
break;
|
2012-12-23 17:34:30 +00:00
|
|
|
case 'j':
|
2012-02-27 01:40:27 +00:00
|
|
|
case '\0':
|
|
|
|
if (r_debug_reg_sync (core->dbg, R_REG_TYPE_GPR, R_FALSE)) {
|
2013-05-20 01:00:49 +00:00
|
|
|
r_debug_reg_list (core->dbg, R_REG_TYPE_GPR, bits, str[0]);
|
|
|
|
} 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) {
|
|
|
|
*arg = 0;
|
2014-01-12 03:31:04 +00:00
|
|
|
r = r_reg_get (core->dbg->reg, str+1, -1); //R_REG_TYPE_GPR);
|
2012-02-27 01:40:27 +00:00
|
|
|
if (r) {
|
|
|
|
r_cons_printf ("0x%08"PFMT64x" ->", str,
|
|
|
|
r_reg_get_value (core->dbg->reg, r));
|
|
|
|
r_reg_set_value (core->dbg->reg, r,
|
|
|
|
r_num_math (core->num, arg+1));
|
2014-01-12 03:31:04 +00:00
|
|
|
r_debug_reg_sync (core->dbg, -1, R_TRUE);
|
2012-02-27 01:40:27 +00:00
|
|
|
r_cons_printf ("0x%08"PFMT64x"\n",
|
|
|
|
r_reg_get_value (core->dbg->reg, r));
|
|
|
|
} else eprintf ("Unknown register '%s'\n", str+1);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
size = atoi (str+1);
|
|
|
|
if (size==0) {
|
|
|
|
arg = strchr (str+1, ' ');
|
|
|
|
if (arg && size==0) {
|
|
|
|
*arg='\0';
|
|
|
|
size = atoi (arg);
|
2013-10-14 20:23:05 +00:00
|
|
|
} else size = bits;
|
2012-02-27 01:40:27 +00:00
|
|
|
type = r_reg_type_by_name (str+1);
|
|
|
|
}
|
|
|
|
if (type != R_REG_TYPE_LAST) {
|
|
|
|
r_debug_reg_sync (core->dbg, type, R_FALSE);
|
|
|
|
r_debug_reg_list (core->dbg, type, size, str[0]=='*');
|
|
|
|
} else eprintf ("cmd_debug_reg: Unknown type\n");
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
static int checkbpcallback(RCore *core) {
|
|
|
|
ut64 pc = r_debug_reg_get (core->dbg, "pc");
|
|
|
|
RBreakpointItem *bpi = r_bp_get (core->dbg->bp, pc);
|
|
|
|
if (bpi) {
|
|
|
|
if (bpi->data)
|
|
|
|
r_core_cmd (core, bpi->data, 0);
|
|
|
|
return R_TRUE;
|
|
|
|
}
|
|
|
|
return R_FALSE;
|
|
|
|
}
|
|
|
|
|
|
|
|
static int bypassbp(RCore *core) {
|
|
|
|
RBreakpointItem *bpi;
|
|
|
|
ut64 addr;
|
|
|
|
r_debug_reg_sync (core->dbg, R_REG_TYPE_GPR, R_FALSE);
|
|
|
|
addr = r_debug_reg_get (core->dbg, "pc");
|
|
|
|
bpi = r_bp_get (core->dbg->bp, addr);
|
|
|
|
if (!bpi) return R_FALSE;
|
|
|
|
/* XXX 2 if libr/debug/debug.c:226 is enabled */
|
|
|
|
r_debug_step (core->dbg, 1);
|
|
|
|
return R_TRUE;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
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) {
|
2013-03-03 00:11:44 +00:00
|
|
|
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;
|
2012-02-27 01:40:27 +00:00
|
|
|
switch (input[1]) {
|
|
|
|
case 't':
|
2013-03-03 00:11:44 +00:00
|
|
|
addr = UT64_MAX;
|
2012-06-14 00:18:15 +00:00
|
|
|
if (input[2]==' ' && input[3])
|
2013-03-03 00:11:44 +00:00
|
|
|
addr = r_num_math (core->num, input+2);
|
|
|
|
i = 0;
|
|
|
|
list = r_debug_frames (core->dbg, addr);
|
2012-02-27 01:40:27 +00:00
|
|
|
r_list_foreach (list, iter, frame) {
|
|
|
|
r_cons_printf ("%d 0x%08"PFMT64x" %d\n",
|
|
|
|
i++, frame->addr, frame->size);
|
|
|
|
}
|
2014-05-02 14:54:27 +00:00
|
|
|
r_list_purge (list);
|
2012-02-27 01:40:27 +00:00
|
|
|
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;
|
2012-02-27 01:40:27 +00:00
|
|
|
case '-':
|
|
|
|
r_bp_del (core->dbg->bp, r_num_math (core->num, input+2));
|
|
|
|
break;
|
2013-03-03 00:11:44 +00:00
|
|
|
case 'c':
|
|
|
|
addr = r_num_math (core->num, input+2);
|
|
|
|
RBreakpointItem *bpi = r_bp_get (core->dbg->bp, addr);
|
|
|
|
if (bpi) {
|
|
|
|
char *arg = strchr (input+2, ' ');
|
|
|
|
if (arg)
|
|
|
|
arg = strchr (arg+1, ' ');
|
|
|
|
if (arg) {
|
|
|
|
free (bpi->data);
|
|
|
|
bpi->data = strdup (arg+1);
|
|
|
|
} else {
|
|
|
|
free (bpi->data);
|
|
|
|
bpi->data = NULL;
|
|
|
|
}
|
|
|
|
} else eprintf ("No breakpoint defined at 0x%08"PFMT64x"\n", addr);
|
2012-02-27 01:40:27 +00:00
|
|
|
break;
|
2012-07-16 09:39:43 +00:00
|
|
|
case 's':
|
2013-03-03 00:11:44 +00:00
|
|
|
addr = r_num_math (core->num, input+2);
|
|
|
|
RBreakpointItem *bp = r_bp_get (core->dbg->bp, addr);
|
2013-10-06 13:15:23 +00:00
|
|
|
if (bp) {
|
|
|
|
//bp->enabled = !bp->enabled;
|
|
|
|
r_bp_del (core->dbg->bp, addr);
|
|
|
|
} else {
|
2013-03-03 00:11:44 +00:00
|
|
|
if (hwbp) bp = r_bp_add_hw (core->dbg->bp, addr, 1, R_BP_PROT_EXEC);
|
|
|
|
else bp = r_bp_add_sw (core->dbg->bp, addr, 1, R_BP_PROT_EXEC);
|
|
|
|
if (!bp) eprintf ("Cannot set breakpoint (%s)\n", input+2);
|
2012-07-16 09:39:43 +00:00
|
|
|
}
|
|
|
|
r_bp_enable (core->dbg->bp, r_num_math (core->num, input+2), 0);
|
|
|
|
break;
|
2012-02-27 01:40:27 +00:00
|
|
|
case 'e':
|
|
|
|
r_bp_enable (core->dbg->bp, r_num_math (core->num, input+2), 1);
|
|
|
|
break;
|
|
|
|
case 'd':
|
|
|
|
r_bp_enable (core->dbg->bp, r_num_math (core->num, input+2), 0);
|
|
|
|
break;
|
|
|
|
case 'h':
|
|
|
|
if (input[2]==' ') {
|
|
|
|
if (!r_bp_use (core->dbg->bp, input+3))
|
|
|
|
eprintf ("Invalid name: '%s'.\n", input+3);
|
|
|
|
} else r_bp_plugin_list (core->dbg->bp);
|
|
|
|
break;
|
2013-06-20 07:54:42 +00:00
|
|
|
case ' ':
|
|
|
|
for (p=input+1; *p==' ';p++);
|
|
|
|
if (*p == '-') {
|
|
|
|
r_bp_del (core->dbg->bp, r_num_math (core->num, p+1));
|
|
|
|
} else {
|
|
|
|
addr = r_num_math (core->num, input+2);
|
|
|
|
if (hwbp) bp = r_bp_add_hw (core->dbg->bp, addr, 1, R_BP_PROT_EXEC);
|
|
|
|
else bp = r_bp_add_sw (core->dbg->bp, addr, 1, R_BP_PROT_EXEC);
|
|
|
|
if (!bp) eprintf ("Cannot set breakpoint (%s)\n", input+2);
|
|
|
|
}
|
|
|
|
break;
|
2012-02-27 01:40:27 +00:00
|
|
|
case '?':
|
2013-06-20 07:54:42 +00:00
|
|
|
default:
|
2012-02-27 01:40:27 +00:00
|
|
|
r_cons_printf (
|
|
|
|
"Usage: db[ecdht] [[-]addr] [len] [rwx] [condstring]\n"
|
2013-10-06 13:15:23 +00:00
|
|
|
"db list breakpoints\n"
|
|
|
|
"db sym.main add breakpoint into sym.main\n"
|
|
|
|
"db 0x804800 add breakpoint\n"
|
|
|
|
"db -0x804800 remove breakpoint\n"
|
2013-03-03 04:28:42 +00:00
|
|
|
// "dbi 0x848 ecx=3 ; stop execution when condition matches\n"
|
2013-10-06 13:15:23 +00:00
|
|
|
"dbs 0x8048000 toggle breakpoint on given address\n"
|
|
|
|
"dbe 0x8048000 enable breakpoint\n"
|
|
|
|
"dbc 0x8048000 cmd run command when breakpoint is hit\n"
|
|
|
|
"dbd 0x8048000 disable breakpoint\n"
|
|
|
|
"dbh x86 set/list breakpoint plugin handlers\n"
|
2012-02-27 01:40:27 +00:00
|
|
|
"Unrelated:\n"
|
2013-10-06 13:15:23 +00:00
|
|
|
"dbt [ebp] debug backtrace\n");
|
2012-02-27 01:40:27 +00:00
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2013-03-03 00:11:44 +00:00
|
|
|
static void r_core_debug_trace_calls (RCore *core) {
|
|
|
|
int n = 0, t = core->dbg->trace->enabled;
|
|
|
|
/*RGraphNode *gn;*/
|
|
|
|
core->dbg->trace->enabled = 0;
|
|
|
|
r_graph_plant (core->dbg->graph);
|
|
|
|
r_cons_break (static_debug_stop, core->dbg);
|
|
|
|
r_reg_arena_swap (core->dbg->reg, R_TRUE);
|
|
|
|
for (;;) {
|
|
|
|
ut8 buf[32];
|
|
|
|
ut64 addr;
|
|
|
|
RAnalOp aop;
|
|
|
|
if (r_cons_singleton ()->breaked)
|
|
|
|
break;
|
|
|
|
r_debug_step (core->dbg, 1);
|
|
|
|
r_debug_reg_sync (core->dbg, R_REG_TYPE_GPR, R_FALSE);
|
|
|
|
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));
|
|
|
|
eprintf (" %d %"PFMT64x"\r", n++, addr);
|
|
|
|
switch (aop.type) {
|
|
|
|
case R_ANAL_OP_TYPE_UCALL:
|
|
|
|
// store regs
|
|
|
|
// step into
|
|
|
|
// get pc
|
|
|
|
r_debug_step (core->dbg, 1);
|
|
|
|
r_debug_reg_sync (core->dbg, R_REG_TYPE_GPR, R_FALSE);
|
|
|
|
addr = r_debug_reg_get (core->dbg, "pc");
|
|
|
|
eprintf ("0x%08"PFMT64x" ucall. computation may fail\n", addr);
|
|
|
|
r_graph_push (core->dbg->graph, addr, NULL);
|
|
|
|
// TODO: push pc+aop.length into the call path stack
|
|
|
|
break;
|
|
|
|
case R_ANAL_OP_TYPE_CALL:
|
|
|
|
r_graph_push (core->dbg->graph, addr, NULL);
|
|
|
|
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 (core->dbg, 1);
|
|
|
|
r_debug_reg_sync (core->dbg, R_REG_TYPE_GPR, R_FALSE);
|
|
|
|
addr = r_debug_reg_get (core->dbg, "pc");
|
|
|
|
// TODO: step into and check return address if correct
|
|
|
|
// if not correct we are hijacking the control flow (exploit!)
|
|
|
|
#endif
|
|
|
|
/*gn =*/ r_graph_pop (core->dbg->graph);
|
|
|
|
#if 0
|
|
|
|
if (addr != gn->addr) {
|
|
|
|
eprintf ("Oops. invalid return address 0x%08"PFMT64x
|
|
|
|
"\n0x%08"PFMT64x"\n", addr, gn->addr);
|
|
|
|
}
|
|
|
|
#endif
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
if (checkbpcallback (core)) {
|
|
|
|
eprintf ("Interrupted by a breakpoint\n");
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
r_graph_traverse (core->dbg->graph);
|
|
|
|
core->dbg->trace->enabled = t;
|
|
|
|
r_cons_break_end();
|
|
|
|
}
|
|
|
|
|
2013-08-29 02:44:18 +00:00
|
|
|
static void r_core_debug_kill (RCore *core, const char *input) {
|
|
|
|
if (!input || *input=='?') {
|
2014-04-22 23:39:17 +00:00
|
|
|
if (input && input[1]) {
|
2013-09-18 00:11:23 +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_printf ("%s\n", signame);
|
|
|
|
} else {
|
|
|
|
signum = r_debug_signal_resolve (core->dbg, arg);
|
|
|
|
if (signum>0)
|
|
|
|
r_cons_printf ("%d\n", signum);
|
|
|
|
}
|
|
|
|
} else eprintf ("Usage: dk[o] [sig][=val]\n"
|
|
|
|
" dk?9 ; name/signum resolver\n"
|
|
|
|
" dk ; list all signal handlers of child process\n"
|
|
|
|
" dko 9 sc ; on SIGKILL Skip and CONT (default stop, always trace)\n"
|
|
|
|
" dk 9 ; send KILL signal to child\n"
|
|
|
|
" dk 9=1 ; set signal handler for KILL signal in child\n");
|
|
|
|
} else if (*input=='o') {
|
|
|
|
char *p, *name = strdup (input+2);
|
|
|
|
p = strchr (name, ' ');
|
|
|
|
if (p) {
|
|
|
|
int signum = atoi (name);
|
|
|
|
*p++ = 0;
|
|
|
|
// Actions:
|
|
|
|
// - pass
|
|
|
|
// - trace
|
|
|
|
// - stop
|
|
|
|
if (signum<1) signum = r_debug_signal_resolve (core->dbg, name);
|
2013-09-18 00:17:54 +00:00
|
|
|
if (signum>0) {
|
2013-09-18 00:11:23 +00:00
|
|
|
int sigopt = 0;
|
|
|
|
if (strchr (p, 's')) sigopt |= R_DBG_SIGNAL_SKIP;
|
|
|
|
if (strchr (p, 'c')) sigopt |= R_DBG_SIGNAL_CONT;
|
|
|
|
r_debug_signal_setup (core->dbg, signum, sigopt);
|
|
|
|
} else {
|
|
|
|
eprintf ("Invalid signal\n");
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
eprintf ("Usage: dko SIGNAL sc\n"
|
|
|
|
" 'SIGNAL' can be a number or a string that resolves with dk?..\n"
|
|
|
|
" 'sc' stands for SKIP and CONT\n");
|
|
|
|
}
|
|
|
|
free (name);
|
2013-08-29 02:44:18 +00:00
|
|
|
} else if (!*input) {
|
2013-09-18 00:11:23 +00:00
|
|
|
r_debug_signal_list (core->dbg);
|
|
|
|
#if 0
|
2013-08-29 02:44:18 +00:00
|
|
|
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);
|
2013-09-18 00:11:23 +00:00
|
|
|
#endif
|
2013-08-29 02:44:18 +00:00
|
|
|
} else {
|
|
|
|
int sig = atoi (input);
|
2013-09-18 00:11:23 +00:00
|
|
|
char *p = strchr (input, '=');
|
2013-08-29 02:44:18 +00:00
|
|
|
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);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2012-02-27 01:40:27 +00:00
|
|
|
static int cmd_debug(void *data, const char *input) {
|
|
|
|
RCore *core = (RCore *)data;
|
|
|
|
int i, times, sig, follow=0;
|
|
|
|
ut64 addr;
|
|
|
|
char *ptr;
|
|
|
|
|
|
|
|
switch (input[0]) {
|
|
|
|
case 't':
|
|
|
|
switch (input[1]) {
|
|
|
|
case '?':
|
2013-12-28 01:34:15 +00:00
|
|
|
r_cons_printf ("|Usage: dt[*] [tag]\n"
|
|
|
|
"| dtc - trace call/ret\n"
|
|
|
|
"| dtg - graph call/ret trace\n"
|
|
|
|
"| dtr - reset traces (instruction//cals)\n");
|
2012-02-27 01:40:27 +00:00
|
|
|
break;
|
|
|
|
case 'c':
|
2013-03-03 00:11:44 +00:00
|
|
|
if (r_debug_is_dead (core->dbg))
|
|
|
|
eprintf ("No process to debug.");
|
|
|
|
else r_core_debug_trace_calls (core);
|
2012-02-27 01:40:27 +00:00
|
|
|
break;
|
|
|
|
case 'g':
|
|
|
|
dot_r_graph_traverse (core, core->dbg->graph);
|
|
|
|
break;
|
|
|
|
case 'r':
|
|
|
|
r_graph_reset (core->dbg->graph);
|
|
|
|
r_debug_trace_free (core->dbg);
|
|
|
|
core->dbg->trace = r_debug_trace_new ();
|
|
|
|
break;
|
|
|
|
case '\0':
|
|
|
|
r_debug_trace_list (core->dbg, -1);
|
|
|
|
break;
|
|
|
|
default:
|
|
|
|
eprintf ("Wrong arg. See dt?\n");
|
|
|
|
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':
|
|
|
|
// r_debug_desc_seek()
|
|
|
|
break;
|
|
|
|
case 'd':
|
|
|
|
// r_debug_desc_dup()
|
|
|
|
break;
|
|
|
|
case 'r':
|
|
|
|
// r_debug_desc_read()
|
|
|
|
break;
|
|
|
|
case 'w':
|
|
|
|
// r_debug_desc_write()
|
|
|
|
break;
|
|
|
|
case '-':
|
|
|
|
// close file
|
2013-09-18 01:44:11 +00:00
|
|
|
//r_core_syscallf (core, "close", "%d", atoi (input+2));
|
|
|
|
r_core_cmdf (core, "dis close %d", atoi (input+2));
|
2013-09-15 00:24:23 +00:00
|
|
|
// TODO: run
|
2012-02-27 01:40:27 +00:00
|
|
|
break;
|
|
|
|
case ' ':
|
2013-09-15 00:24:23 +00:00
|
|
|
// TODO: handle read, readwrite, append
|
|
|
|
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:
|
2013-12-28 01:34:15 +00:00
|
|
|
r_cons_printf ("|Usage: dd[*sdrw-?]\n"
|
|
|
|
"| dd list filedescriptors\n"
|
|
|
|
"| dd* list filedescriptors (in radare commands)\n"
|
|
|
|
"| dd-1 close stdout fd\n"
|
|
|
|
"| dd file open and map that file into the UI\n"
|
|
|
|
"| dd? show this help\n");
|
2012-02-27 01:40:27 +00:00
|
|
|
break;
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
case 's':
|
|
|
|
times = atoi (input+2);
|
|
|
|
if (times<1) times = 1;
|
|
|
|
switch (input[1]) {
|
|
|
|
case '?':
|
2013-12-28 01:34:15 +00:00
|
|
|
r_cons_printf ("|Usage: ds[ol] [count]\n"
|
|
|
|
"| ds step one instruction\n"
|
|
|
|
"| ds 4 step 4 instructions\n"
|
|
|
|
"| dsf step until end of frame\n"
|
|
|
|
"| dsi [cond] continue until condition matches\n"
|
|
|
|
"| dsl step one source line\n"
|
|
|
|
"| dsl 40 step 40 source lines\n"
|
|
|
|
"| dso 3 step over 3 instructions\n"
|
|
|
|
"| dsp step into program (skip libs)\n"
|
|
|
|
"| dss 3 skip 3 step instructions\n"
|
|
|
|
"| dsu addr step until address\n"
|
2013-03-03 04:03:48 +00:00
|
|
|
);
|
|
|
|
break;
|
|
|
|
case 'i':
|
|
|
|
if (input[2] == ' ') {
|
|
|
|
int n = 0;
|
2013-03-03 04:28:42 +00:00
|
|
|
r_cons_break (static_debug_stop, core->dbg);
|
2013-03-03 04:03:48 +00:00
|
|
|
do {
|
2013-03-03 04:28:42 +00:00
|
|
|
if (r_cons_singleton ()->breaked)
|
|
|
|
break;
|
2013-03-03 04:03:48 +00:00
|
|
|
r_debug_step (core->dbg, 1);
|
2013-03-03 04:47:33 +00:00
|
|
|
if (r_debug_is_dead (core->dbg))
|
|
|
|
break;
|
2013-03-03 04:03:48 +00:00
|
|
|
if (checkbpcallback (core)) {
|
|
|
|
eprintf ("Interrupted by a breakpoint\n");
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
r_core_cmd0 (core, ".dr*");
|
|
|
|
n++;
|
|
|
|
} while (!r_num_conditional (core->num, input+3));
|
|
|
|
eprintf ("Stopped after %d instructions\n", n);
|
|
|
|
} else {
|
|
|
|
eprintf ("Missing argument\n");
|
|
|
|
}
|
2012-02-27 01:40:27 +00:00
|
|
|
break;
|
2012-11-13 03:38:26 +00:00
|
|
|
case 'f':
|
2013-09-26 23:38:49 +00:00
|
|
|
step_until_eof (core);
|
2012-11-13 03:38:26 +00:00
|
|
|
break;
|
2012-02-27 01:40:27 +00:00
|
|
|
case 'u':
|
|
|
|
r_reg_arena_swap (core->dbg->reg, R_TRUE);
|
|
|
|
step_until (core, r_num_math (core->num, input+2)); // XXX dupped by times
|
|
|
|
break;
|
|
|
|
case 'p':
|
|
|
|
r_reg_arena_swap (core->dbg->reg, R_TRUE);
|
|
|
|
for (i=0; i<times; i++) {
|
|
|
|
ut8 buf[64];
|
|
|
|
ut64 addr;
|
|
|
|
RAnalOp aop;
|
|
|
|
r_debug_reg_sync (core->dbg, R_REG_TYPE_GPR, R_FALSE);
|
|
|
|
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_get (core->io, aop.jump);
|
|
|
|
if (!s) {
|
|
|
|
r_debug_step_over (core->dbg, times);
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
r_debug_step (core->dbg, 1);
|
|
|
|
if (checkbpcallback (core)) {
|
|
|
|
eprintf ("Interrupted by a breakpoint\n");
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
break;
|
2012-10-25 13:21:47 +00:00
|
|
|
case 's':
|
|
|
|
{
|
2013-03-03 00:11:44 +00:00
|
|
|
ut64 addr = r_debug_reg_get (core->dbg, "pc");
|
2012-10-25 13:21:47 +00:00
|
|
|
r_reg_arena_swap (core->dbg->reg, R_TRUE);
|
|
|
|
for (i=0; i<times; i++) {
|
|
|
|
ut8 buf[64];
|
|
|
|
RAnalOp aop;
|
|
|
|
r_debug_reg_sync (core->dbg, R_REG_TYPE_GPR, R_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) {
|
2014-01-01 07:52:46 +00:00
|
|
|
eprintf ("Don't know how to skip this instruction\n");
|
2012-10-25 13:21:47 +00:00
|
|
|
break;
|
|
|
|
}
|
2013-12-06 04:04:17 +00:00
|
|
|
addr += aop.size;
|
2012-10-25 13:21:47 +00:00
|
|
|
}
|
2013-03-03 00:11:44 +00:00
|
|
|
r_debug_reg_set (core->dbg, "pc", addr);
|
2012-10-25 13:21:47 +00:00
|
|
|
}
|
|
|
|
break;
|
2012-02-27 01:40:27 +00:00
|
|
|
case 'o':
|
|
|
|
r_reg_arena_swap (core->dbg->reg, R_TRUE);
|
|
|
|
r_debug_step_over (core->dbg, times);
|
|
|
|
if (checkbpcallback (core)) {
|
|
|
|
eprintf ("Interrupted by a breakpoint\n");
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
case 'l':
|
|
|
|
r_reg_arena_swap (core->dbg->reg, R_TRUE);
|
|
|
|
step_line (core, times);
|
|
|
|
break;
|
|
|
|
default:
|
|
|
|
r_reg_arena_swap (core->dbg->reg, R_TRUE);
|
|
|
|
r_debug_reg_sync (core->dbg, R_REG_TYPE_GPR, R_FALSE);
|
|
|
|
r_debug_step (core->dbg, times);
|
|
|
|
if (checkbpcallback (core)) {
|
|
|
|
eprintf ("Interrupted by a breakpoint\n");
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
follow = r_config_get_i (core->config, "dbg.follow");
|
|
|
|
break;
|
|
|
|
case 'b':
|
|
|
|
r_core_cmd_bp (core, input);
|
|
|
|
break;
|
|
|
|
case 'H':
|
|
|
|
eprintf ("TODO: transplant process\n");
|
|
|
|
break;
|
|
|
|
case 'c':
|
|
|
|
// TODO: we must use this for step 'ds' too maybe...
|
|
|
|
r_cons_break (static_debug_stop, core->dbg);
|
|
|
|
switch (input[1]) {
|
|
|
|
case '?':
|
2013-12-28 01:34:15 +00:00
|
|
|
eprintf("|Usage: dc[?] -- continue execution\n"
|
|
|
|
"| dc? show this help\n"
|
|
|
|
"| dc continue execution of all children\n"
|
|
|
|
"| dcf continue until fork (TODO)\n"
|
|
|
|
"| dca [sym] [sym]. continue at every hit on any given symbol\n"
|
|
|
|
"| dct [len] traptrace from curseek to len, no argument to list\n"
|
|
|
|
"| dcu [addr] continue until address\n"
|
|
|
|
"| dcu [addr] [end] continue until given address range\n"
|
|
|
|
"| dco [num] step over N instructions\n"
|
|
|
|
"| dcp continue until program code (mapped io section)\n"
|
|
|
|
"| dcs [num] continue until syscall\n"
|
|
|
|
"| dcc continue until call (use step into)\n"
|
|
|
|
"| dcr continue until ret (uses step over)\n"
|
|
|
|
"| dck [sig] [pid] continue sending kill 9 to process\n"
|
|
|
|
"| dc [pid] continue execution of pid\n"
|
|
|
|
"| dc[-pid] stop execution of pid\n"
|
|
|
|
"|TODO: dcu/dcr needs dbg.untilover=true??\n"
|
|
|
|
"|TODO: same for only user/libs side, to avoid steping into libs\n"
|
|
|
|
"|TODO: support for threads?\n");
|
2012-02-27 01:40:27 +00:00
|
|
|
break;
|
|
|
|
case 'a':
|
|
|
|
eprintf ("TODO: dca\n");
|
|
|
|
break;
|
|
|
|
case 'c':
|
|
|
|
r_reg_arena_swap (core->dbg->reg, R_TRUE);
|
|
|
|
r_debug_continue_until_optype (core->dbg, R_ANAL_OP_TYPE_CALL, 0);
|
|
|
|
checkbpcallback (core);
|
|
|
|
break;
|
|
|
|
case 'r':
|
|
|
|
r_reg_arena_swap (core->dbg->reg, R_TRUE);
|
|
|
|
r_debug_continue_until_optype (core->dbg, R_ANAL_OP_TYPE_RET, 1);
|
|
|
|
checkbpcallback (core);
|
|
|
|
break;
|
|
|
|
case 'k':
|
|
|
|
// select pid and r_debug_continue_kill (core->dbg,
|
|
|
|
r_reg_arena_swap (core->dbg->reg, R_TRUE);
|
|
|
|
ptr = strchr (input+3, ' ');
|
|
|
|
if (ptr) {
|
|
|
|
bypassbp (core);
|
|
|
|
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, atoi (input+2));
|
|
|
|
r_debug_select (core->dbg, old_pid, old_tid);
|
|
|
|
} else r_debug_continue_kill (core->dbg, atoi (input+2));
|
|
|
|
checkbpcallback (core);
|
|
|
|
break;
|
|
|
|
case 's':
|
|
|
|
if (input[2]==' ') {
|
|
|
|
sig = r_num_math (core->num, input+3);
|
|
|
|
if (sig <= 0) {
|
|
|
|
sig = r_syscall_get_num (core->anal->syscall, input+3);
|
|
|
|
if (sig == -1) {
|
|
|
|
eprintf ("Unknown syscall number\n");
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
eprintf ("Running child until syscall %d\n", sig);
|
|
|
|
r_reg_arena_swap (core->dbg->reg, R_TRUE);
|
|
|
|
r_debug_continue_syscall (core->dbg, sig);
|
|
|
|
checkbpcallback (core);
|
|
|
|
} else eprintf ("Usage: dcs [syscall-name-or-number]\n");
|
|
|
|
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);
|
|
|
|
r_debug_reg_sync (core->dbg, R_REG_TYPE_GPR, R_FALSE);
|
|
|
|
pc = r_debug_reg_get (core->dbg, "pc");
|
|
|
|
eprintf (" %d %"PFMT64x"\r", n++, pc);
|
|
|
|
s = r_io_section_get (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':
|
2013-05-05 17:39:01 +00:00
|
|
|
if (input[2] != ' ') {
|
|
|
|
eprintf ("Usage: dcu [address]\n");
|
|
|
|
return 1;
|
|
|
|
}
|
2012-02-27 01:40:27 +00:00
|
|
|
ptr = strchr (input+3, ' ');
|
|
|
|
// TODO : handle ^C here
|
|
|
|
if (ptr) { // TODO: put '\0' in *ptr to avoid
|
|
|
|
ut64 from, to, pc;
|
|
|
|
from = r_num_math (core->num, input+3);
|
|
|
|
to = r_num_math (core->num, ptr+1);
|
|
|
|
do {
|
|
|
|
r_debug_step (core->dbg, 1);
|
|
|
|
r_debug_reg_sync (core->dbg, R_REG_TYPE_GPR, R_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);
|
|
|
|
return 1;
|
|
|
|
}
|
|
|
|
addr = r_num_math (core->num, input+2);
|
|
|
|
if (addr) {
|
|
|
|
eprintf ("Continue until 0x%08"PFMT64x"\n", addr);
|
|
|
|
bypassbp (core);
|
|
|
|
r_reg_arena_swap (core->dbg->reg, R_TRUE);
|
|
|
|
r_bp_add_sw (core->dbg->bp, addr, 1, R_BP_PROT_EXEC);
|
|
|
|
r_debug_continue (core->dbg);
|
|
|
|
checkbpcallback (core);
|
|
|
|
r_bp_del (core->dbg->bp, addr);
|
|
|
|
} else eprintf ("Cannot continue until address 0\n");
|
|
|
|
break;
|
|
|
|
case ' ':
|
|
|
|
{
|
|
|
|
int old_pid = core->dbg->pid;
|
|
|
|
int pid = atoi (input+2);
|
|
|
|
bypassbp (core);
|
|
|
|
r_reg_arena_swap (core->dbg->reg, R_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);
|
|
|
|
checkbpcallback (core);
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
case 't':
|
|
|
|
cmd_debug_backtrace (core, input+2);
|
|
|
|
break;
|
|
|
|
default:
|
|
|
|
bypassbp (core);
|
|
|
|
r_reg_arena_swap (core->dbg->reg, R_TRUE);
|
|
|
|
r_debug_continue (core->dbg);
|
|
|
|
checkbpcallback (core);
|
|
|
|
}
|
|
|
|
follow = r_config_get_i (core->config, "dbg.follow");
|
|
|
|
r_cons_break_end();
|
|
|
|
break;
|
|
|
|
case 'm':
|
|
|
|
cmd_debug_map (core, input+1);
|
|
|
|
break;
|
|
|
|
case 'r':
|
|
|
|
cmd_debug_reg (core, input+1);
|
|
|
|
//r_core_cmd (core, "|reg", 0);
|
|
|
|
break;
|
|
|
|
case 'p':
|
|
|
|
cmd_debug_pid (core, input);
|
|
|
|
break;
|
|
|
|
case 'h':
|
|
|
|
if (input[1]==' ')
|
|
|
|
r_debug_use (core->dbg, input+2);
|
|
|
|
else r_debug_plugin_list (core->dbg);
|
|
|
|
break;
|
2013-04-16 02:01:39 +00:00
|
|
|
case 'i':
|
2014-04-30 07:43:37 +00:00
|
|
|
eprintf ("TODO: info\n");
|
|
|
|
break;
|
|
|
|
case 'x':
|
2013-08-29 14:59:24 +00:00
|
|
|
switch (input[1]) {
|
2013-08-29 17:46:48 +00:00
|
|
|
case 'a':
|
|
|
|
{
|
|
|
|
RAsmCode *acode;
|
|
|
|
r_asm_set_pc (core->assembler, core->offset);
|
|
|
|
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);
|
|
|
|
r_asm_code_free (acode);
|
2014-05-03 23:41:32 +00:00
|
|
|
free (acode);
|
2013-08-29 17:46:48 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
break;
|
2013-08-29 14:59:24 +00:00
|
|
|
case 's':
|
2013-08-29 17:46:48 +00:00
|
|
|
// XXX: last byte fails (ret) should not be generated
|
|
|
|
r_core_cmdf (core, "dir `gs %s`", input+2);
|
2013-08-29 14:59:24 +00:00
|
|
|
break;
|
|
|
|
case 'r':
|
|
|
|
r_reg_arena_push (core->dbg->reg);
|
2013-08-29 17:46:48 +00:00
|
|
|
if (input[2]==' ') {
|
2013-08-29 14:59:24 +00:00
|
|
|
ut8 bytes[4096];
|
|
|
|
int bytes_len = r_hex_str2bin (input+2, bytes);
|
|
|
|
r_debug_execute (core->dbg, bytes, bytes_len, 0);
|
|
|
|
}
|
|
|
|
r_reg_arena_pop (core->dbg->reg);
|
|
|
|
break;
|
|
|
|
case ' ':
|
|
|
|
{
|
2013-04-18 07:39:37 +00:00
|
|
|
ut8 bytes[4096];
|
2013-04-16 02:01:39 +00:00
|
|
|
int bytes_len = r_hex_str2bin (input+2, bytes);
|
2014-01-18 22:02:53 +00:00
|
|
|
if (bytes_len>0)
|
|
|
|
r_debug_execute (core->dbg, bytes, bytes_len, 0);
|
2013-08-29 14:59:24 +00:00
|
|
|
}
|
|
|
|
break;
|
|
|
|
default:
|
2013-12-28 01:34:15 +00:00
|
|
|
r_cons_printf ("|Usage: di[asr] [arg| ...]\n"
|
2014-04-30 07:43:37 +00:00
|
|
|
"| dx 9090 ; inject two x86 nops\n"
|
2013-12-28 01:34:15 +00:00
|
|
|
"| \"dia mov eax,6;mov ebx,0;int 0x80\" ; inject and restore state\n"
|
2014-04-30 07:43:37 +00:00
|
|
|
"| dxr 9090 ; inject and restore state\n"
|
|
|
|
"| dxs write 1, 0x8048, 12 ; syscall injection (see gs)\n");
|
2013-08-29 14:59:24 +00:00
|
|
|
break;
|
2013-04-16 02:01:39 +00:00
|
|
|
}
|
|
|
|
break;
|
2012-02-27 01:40:27 +00:00
|
|
|
case 'o':
|
2012-10-22 08:12:13 +00:00
|
|
|
r_core_file_reopen (core, input[1]? input+2: NULL, 0);
|
2012-02-27 01:40:27 +00:00
|
|
|
break;
|
2012-12-07 11:03:53 +00:00
|
|
|
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;
|
2012-12-07 11:03:53 +00:00
|
|
|
int res = r_debug_kill (core->dbg, pid, 0, 0);
|
|
|
|
if (!res) break;
|
|
|
|
r_sys_usleep (200);
|
|
|
|
}
|
|
|
|
r_cons_break_end();
|
|
|
|
break;
|
2013-08-29 02:44:18 +00:00
|
|
|
case 'k':
|
|
|
|
r_core_debug_kill (core, input+1);
|
|
|
|
break;
|
2012-02-27 01:40:27 +00:00
|
|
|
default:
|
2013-12-28 01:34:15 +00:00
|
|
|
r_cons_printf ("|Usage: d[sbhcrbo] [arg]\n"
|
|
|
|
"| dh [handler] list or set debugger handler\n"
|
|
|
|
"| dH [handler] transplant process to a new handler\n"
|
|
|
|
"| dd file descriptors (!fd in r1)\n"
|
|
|
|
"| ds[ol] N step, over, source line\n"
|
|
|
|
"| do open process (reload, alias for 'oo')\n"
|
|
|
|
"| dk [sig][=act] list, send, get, set, signal handlers of child\n"
|
2014-04-30 07:43:37 +00:00
|
|
|
"| di show debugger backend information (See dh)\n"
|
|
|
|
"| dx[rs] [arg..] inject code on running process and execute it (See gs)\n"
|
2013-12-28 01:34:15 +00:00
|
|
|
"| dp[=*?t][pid] list, attach to process or thread id\n"
|
|
|
|
"| dc[?] continue execution. dc? for more\n"
|
|
|
|
"| dr[?] cpu registers, dr? for extended help\n"
|
|
|
|
"| db[?] breakpoints\n"
|
|
|
|
"| dbt display backtrace\n"
|
|
|
|
"| dt[?r] [tag] display instruction traces (dtr=reset)\n"
|
|
|
|
"| dm[?*] show memory maps\n"
|
|
|
|
"| dw [pid] block prompt until pid dies\n");
|
2012-02-27 01:40:27 +00:00
|
|
|
break;
|
|
|
|
}
|
|
|
|
if (follow>0) {
|
|
|
|
ut64 pc = r_debug_reg_get (core->dbg, "pc");
|
|
|
|
if ((pc<core->offset) || (pc > (core->offset+follow)))
|
|
|
|
r_core_cmd0 (core, "sr pc");
|
|
|
|
}
|
|
|
|
return 0;
|
|
|
|
}
|