radare2/libr/core/cmd_debug.c

1345 lines
40 KiB
C
Raw Normal View History

/* radare - LGPL - Copyright 2009-2014 - pancake */
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");
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) {
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) {
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':
/* 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);
r_debug_kill (core->dbg, 0, R_FALSE, sig);
} 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':
if (input[2]) {
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);
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;
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;
case '?':
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");
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;
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));
} 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 (
"|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]) {
snprintf (file, sizeof (file), "%s", input+2);
} 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)))) {
RBinObject *o = core->bin->cur->o;
2012-02-27 01:40:27 +00:00
filter.offset = 0LL;
filter.name = (char *)symname;
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);
o->baddr = baddr;
2012-02-27 01:40:27 +00:00
break;
}
}
free (ptr);
}
break;
case ' ':
{
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");
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;
}
return R_TRUE;
}
static void cmd_debug_reg(RCore *core, const char *str) {
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;
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
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;
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;
case 'x':
switch (str[1]) {
case '-':
r_debug_reg_sync (core->dbg, R_REG_TYPE_DRX, R_FALSE);
r_debug_drx_unset (core->dbg, atoi (str+2));
r_debug_reg_sync (core->dbg, R_REG_TYPE_DRX, R_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) {
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");
free (s);
} break;
case '\0':
r_debug_reg_sync (core->dbg, R_REG_TYPE_DRX, R_FALSE);
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;
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:
r_cons_printf ("%d\n", r_list_length (
core->dbg->reg->regset[0].pool));
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);
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':
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);
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)) {
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)) {
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) {
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':
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);
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);
}
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;
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;
case 's':
addr = r_num_math (core->num, input+2);
RBreakpointItem *bp = r_bp_get (core->dbg->bp, addr);
if (bp) {
//bp->enabled = !bp->enabled;
r_bp_del (core->dbg->bp, addr);
} else {
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);
}
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"
"db list breakpoints\n"
"db sym.main add breakpoint into sym.main\n"
"db 0x804800 add breakpoint\n"
"db -0x804800 remove breakpoint\n"
// "dbi 0x848 ecx=3 ; stop execution when condition matches\n"
"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"
"dbt [ebp] debug backtrace\n");
2012-02-27 01:40:27 +00:00
break;
}
}
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();
}
static void r_core_debug_kill (RCore *core, const char *input) {
if (!input || *input=='?') {
if (input && input[1]) {
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) {
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);
} else if (!*input) {
r_debug_signal_list (core->dbg);
#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);
}
}
}
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 '?':
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':
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));
// TODO: run
2012-02-27 01:40:27 +00:00
break;
case ' ':
// 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:
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 '?':
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"
);
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);
2013-03-03 04:47:33 +00:00
if (r_debug_is_dead (core->dbg))
break;
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':
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;
case 's':
{
ut64 addr = r_debug_reg_get (core->dbg, "pc");
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) {
eprintf ("Don't know how to skip this instruction\n");
break;
}
addr += aop.size;
}
r_debug_reg_set (core->dbg, "pc", addr);
}
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 '?':
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':
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;
case 'i':
2014-04-30 07:43:37 +00:00
eprintf ("TODO: info\n");
break;
case 'x':
switch (input[1]) {
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);
}
}
break;
case 's':
// XXX: last byte fails (ret) should not be generated
r_core_cmdf (core, "dir `gs %s`", input+2);
break;
case 'r':
r_reg_arena_push (core->dbg->reg);
if (input[2]==' ') {
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 ' ':
{
ut8 bytes[4096];
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);
}
break;
default:
r_cons_printf ("|Usage: di[asr] [arg| ...]\n"
2014-04-30 07:43:37 +00:00
"| dx 9090 ; inject two x86 nops\n"
"| \"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");
break;
}
break;
2012-02-27 01:40:27 +00:00
case 'o':
r_core_file_reopen (core, input[1]? input+2: NULL, 0);
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;
2012-02-27 01:40:27 +00:00
default:
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"
"| 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;
}