* Integrate backtrace into the debugging backend

* Add 'dcs' command to continue until syscall
  - Need syscall analysis
* Some tips for future enhacements in r_search
This commit is contained in:
pancake 2010-03-02 11:18:49 +01:00
parent 1219a2ae40
commit a74926c6d0
10 changed files with 122 additions and 118 deletions

View File

@ -2076,6 +2076,7 @@ static int cmd_debug(void *data, const char *input) {
" dc? show this help\n"
" dc continue execution of all childs\n"
" dcu [addr] continue until address\n"
" dcs [num] continue until syscall\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"
@ -2093,6 +2094,12 @@ static int cmd_debug(void *data, const char *input) {
r_debug_select (&core->dbg, old_pid, old_pid);
} else r_debug_continue_kill (&core->dbg, atoi (input+2));
break;
case 's':
sig = r_num_math (&core->num, input+2);
eprintf ("Continue until syscall %d\n", sig);
r_debug_continue_syscall (&core->dbg, sig);
/* TODO : use r_syscall here, to retrieve syscall info */
break;
case 'u':
addr = r_num_math (&core->num, input+2);
eprintf ("Continue until 0x%08llx\n", addr);

View File

@ -1,80 +0,0 @@
#include <r_debug.h>
#define MAXBT 128
// TODO: r_reg typedef must be renamed to this shorter version
#define RReg RRegister
/* TODO: Can I use this as in a coroutine? */
static RList *backtrace_i386(RIOBind *bio, RReg *reg) {
ut32 i, esp, ebp2;
ut8 buf[4];
ut32 _esp = r_reg_get_value (reg, r_reg_get (reg, "esp", R_REG_TYPE_GPR));
RList *list = r_list_new ();
list->free = free;
// TODO: implement [stack] map uptrace method too
esp = _esp;
for (i=0; i<MAXBT; i++) {
bio->read_at (bio->io, esp, (void *)&ebp2, 4);
*buf = '\0';
bio->read_at (bio->io, (ebp2-5)-(ebp2-5)%4, (void *)&buf, 4);
// TODO: arch_is_call() here and this fun will be portable
if (buf[(ebp2-5)%4]==0xe8) {
RDebugFrame *frame = R_NEW (RDebugFrame);
frame->addr = ebp2;
frame->size = esp-_esp;
r_list_append (list, frame);
eprintf ("ADDR: 0x%08x, SIZE: 0x%x\n", ebp2, esp-_esp);
}
esp += 4;
}
return list;
}
// XXX: Do this work correctly?
static RList *backtrace_x86_64(RIOBind *bio, RReg *reg) {
int i;
ut8 buf[4];
ut64 ptr, ebp2;
ut64 _rip = r_reg_get_value (reg, r_reg_get (reg, "rip", R_REG_TYPE_GPR));
ut64 _rsp = r_reg_get_value (reg, r_reg_get (reg, "rsp", R_REG_TYPE_GPR));
ut64 _rbp = r_reg_get_value (reg, r_reg_get (reg, "rbp", R_REG_TYPE_GPR));
RList *list = r_list_new ();
list->free = free;
bio->read_at (bio->io, _rip, &buf, 4);
/*
%ebp points to the old ebp var
%ebp+4 points to ret
*/
/* Handle before function prelude: push %ebp ; mov %esp, %ebp */
if (!memcmp (buf, "\x55\x89\xe5", 3) || !memcmp (buf, "\x89\xe5\x57", 3)) {
if (bio->read_at (bio->io, _rsp, &ptr, 4) != 4) {
eprintf ("read error at 0x%08llx\n", _rsp);
return R_FALSE;
}
eprintf ("ADDR: 0x%08llx\n", ptr); // TODO: size!
_rbp = ptr;
}
for (i=1; i<MAXBT; i++) {
// TODO: make those two reads in a shot
bio->read_at (bio->io, _rbp, &ebp2, 4);
bio->read_at (bio->io, _rbp+4, &ptr, 4);
if (ptr == 0x0 || _rbp == 0x0)
break;
eprintf ("ADDR: 0x%08llx\n", ptr);
_rbp = ebp2;
}
return list;
}
R_API RList *r_debug_frames (RDebug *dbg) {
//if (dbg->bits == 64) {
// return backtrace_x86_64 (dbg->bio, dbg->reg) {
//} else {
return backtrace_i386 (&dbg->iob, dbg->reg);
//}
}

View File

@ -199,9 +199,9 @@ R_API int r_debug_continue_kill(struct r_debug_t *dbg, int sig) {
int ret = R_FALSE;
if (dbg && dbg->h && dbg->h->cont) {
r_bp_restore (dbg->bp, R_FALSE); // set sw breakpoints
ret = dbg->h->cont(dbg->pid, sig);
ret = dbg->h->cont (dbg->pid, sig);
if (dbg->h->wait)
ret = dbg->h->wait(dbg->pid);
ret = dbg->h->wait (dbg->pid);
r_bp_restore (dbg->bp, R_TRUE); // unset sw breakpoints
r_debug_recoil (dbg);
}
@ -241,10 +241,8 @@ R_API int r_debug_kill(struct r_debug_t *dbg, int sig) {
return ret;
}
// TODO: move into r_debug
// TODO: we need to know the arch backend, frame size,
// TODO: merge algorithms from r1 (do we need ebp?)
// TODO: must return a linked list or r_iter
R_API int r_anal_backtrace(struct r_anal_t *anal, const ut8 *buf, ut64 esp) {
return R_FALSE;
R_API RList *r_debug_frames (RDebug *dbg) {
if (dbg && dbg->h && dbg->h->frames)
return dbg->h->frames (dbg);
return NULL;
}

View File

@ -58,8 +58,7 @@ R_API int r_debug_map_sync(RDebug *dbg) {
return ret;
}
R_API int r_debug_map_alloc(RDebug *dbg, RDebugMap *map)
{
R_API int r_debug_map_alloc(RDebug *dbg, RDebugMap *map) {
int ret = R_FALSE;
if (dbg->h && dbg->h->map_alloc) {
if (dbg->h->map_alloc (dbg, map)) {
@ -70,8 +69,7 @@ R_API int r_debug_map_alloc(RDebug *dbg, RDebugMap *map)
return ret;
}
R_API int r_debug_map_dealloc(RDebug *dbg, RDebugMap *map)
{
R_API int r_debug_map_dealloc(RDebug *dbg, RDebugMap *map) {
int ret = R_FALSE;
ut64 addr = map->addr;
if (dbg->h && dbg->h->map_dealloc)
@ -82,6 +80,7 @@ R_API int r_debug_map_dealloc(RDebug *dbg, RDebugMap *map)
//r_debug_map_free (map);
return ret;
}
R_API RDebugMap *r_debug_map_get(RDebug *dbg, ut64 addr) {
RDebugMap *ret = NULL;
RListIter *iter = r_list_iterator (dbg->maps);
@ -95,22 +94,19 @@ R_API RDebugMap *r_debug_map_get(RDebug *dbg, ut64 addr) {
return ret;
}
R_API void r_debug_map_free(RDebugMap *map)
{
R_API void r_debug_map_free(RDebugMap *map) {
//r_list_unlink (dbg->maps_user, map);
free (map->name);
free (map);
}
R_API RList *r_debug_map_list_new()
{
R_API RList *r_debug_map_list_new() {
RList *list = r_list_new ();
list->free = r_debug_map_free;
return list;
}
R_API void r_debug_map_list_free(RList *maps)
{
R_API void r_debug_map_list_free(RList *maps) {
RListIter *iter = r_list_iterator (maps);
while (r_list_iter_next (iter)) {
RDebugMap *map = r_list_iter_get (iter);

View File

@ -8,6 +8,7 @@
#include <signal.h>
#define DEBUGGER 1
#define MAXBT 128
#if __WINDOWS__
#include <windows.h>
@ -570,9 +571,89 @@ static int r_debug_native_bp_read(int pid, ut64 addr, int hw, int rwx) {
return R_TRUE;
}
#endif
#if __i386__
/* TODO: Can I use this as in a coroutine? */
static RList *r_debug_native_frames(RDebug *dbg) {
RRegister *reg = dbg->reg;
ut32 i, _esp, esp, ebp2;
ut8 buf[4];
RList *list = r_list_new ();
RIOBind *bio = &dbg->iob;
static int r_debug_get_arch()
{
list->free = free;
_esp = r_reg_get_value (reg, r_reg_get (reg, "esp", R_REG_TYPE_GPR));
// TODO: implement [stack] map uptrace method too
esp = _esp;
for (i=0; i<MAXBT; i++) {
bio->read_at (bio->io, esp, (void *)&ebp2, 4);
*buf = '\0';
bio->read_at (bio->io, (ebp2-5)-(ebp2-5)%4, (void *)&buf, 4);
// TODO: arch_is_call() here and this fun will be portable
if (buf[(ebp2-5)%4]==0xe8) {
RDebugFrame *frame = R_NEW (RDebugFrame);
frame->addr = ebp2;
frame->size = esp-_esp;
r_list_append (list, frame);
}
esp += 4;
}
return list;
}
#elif __x86_64__
// XXX: Do this work correctly?
static RList *r_debug_native_frames(RDebug *dbg) {
int i;
ut8 buf[4];
ut64 ptr, ebp2;
ut64 _rip, _rsp, _rbp;
RList *list;
RRegister *reg = dbg->reg;
RIOBind *bio = &dbg->iob;
_rip = r_reg_get_value (reg, r_reg_get (reg, "rip", R_REG_TYPE_GPR));
_rsp = r_reg_get_value (reg, r_reg_get (reg, "rsp", R_REG_TYPE_GPR));
_rbp = r_reg_get_value (reg, r_reg_get (reg, "rbp", R_REG_TYPE_GPR));
list = r_list_new ();
list->free = free;
bio->read_at (bio->io, _rip, &buf, 4);
/* %rbp=old rbp, %rbp+4 points to ret */
/* Handle before function prelude: push %rbp ; mov %rsp, %rbp */
if (!memcmp (buf, "\x55\x89\xe5", 3) || !memcmp (buf, "\x89\xe5\x57", 3)) {
if (bio->read_at (bio->io, _rsp, &ptr, 4) != 4) {
eprintf ("read error at 0x%08llx\n", _rsp);
return R_FALSE;
}
RDebugFrame *frame = R_NEW (RDebugFrame);
frame->addr = ptr;
frame->size = 0; // TODO ?
r_list_append (list, frame);
_rbp = ptr;
}
for (i=1; i<MAXBT; i++) {
// TODO: make those two reads in a shot
bio->read_at (bio->io, _rbp, &ebp2, 4);
bio->read_at (bio->io, _rbp+4, &ptr, 4);
if (ptr == 0x0 || _rbp == 0x0)
break;
RDebugFrame *frame = R_NEW (RDebugFrame);
frame->addr = ptr;
frame->size = 0; // TODO ?
r_list_append (list, frame);
_rbp = ebp2;
}
return list;
}
#else
#warning Backtrace frames not implemented for this platform
#endif
static int r_debug_get_arch() {
#if __i386__ || __x86_64__
return R_ASM_ARCH_X86;
#elif __powerpc__ || __POWERPC__
@ -618,6 +699,7 @@ struct r_debug_handle_t r_debug_plugin_native = {
.detach = &r_debug_native_detach,
.wait = &r_debug_native_wait,
.kill = &r_debug_native_kill,
.frames = &r_debug_native_frames,
.get_arch = &r_debug_get_arch,
.reg_profile = (void *)&r_debug_native_reg_profile,
.reg_read = &r_debug_native_reg_read,

View File

@ -9,39 +9,33 @@ R_API int r_debug_pid_list(struct r_debug_t *dbg)
}
/* processes */
R_API int r_debug_pid_parent(RDebugPid *pid)
{
R_API int r_debug_pid_parent(RDebugPid *pid) {
// fork in child
return 0;
}
R_API int r_debug_pid_del(struct r_debug_t *dbg)
{
R_API int r_debug_pid_del(struct r_debug_t *dbg) {
// kill da child
return R_TRUE;
}
/* threads */
R_API int r_debug_pid_add_thread(struct r_debug_t *dbg)
{
R_API int r_debug_pid_add_thread(struct r_debug_t *dbg) {
// create a thread in process
return R_TRUE;
}
R_API int r_debug_pid_del_thread(struct r_debug_t *dbg)
{
R_API int r_debug_pid_del_thread(struct r_debug_t *dbg) {
// kill a thread in process
return R_TRUE;
}
/* status */
R_API int r_debug_pid_set_state(struct r_debug_t *dbg, int status)
{
R_API int r_debug_pid_set_state(struct r_debug_t *dbg, int status) {
return R_TRUE;
}
/* status */
R_API struct r_debug_pid_t *r_debug_pid_get_status(struct r_debug_t *dbg, int pid)
{
R_API struct r_debug_pid_t *r_debug_pid_get_status(struct r_debug_t *dbg, int pid) {
return NULL;
}

View File

@ -83,6 +83,7 @@ typedef struct r_debug_handle_t {
int (*wait)(int pid);
int (*kill)(RDebug *dbg, int sig);
int (*contsc)(int pid, int sc);
RList* (*frames)(RDebug *dbg);
/* registers */
RBreakpointCallback breakpoint;
int (*reg_read)(struct r_debug_t *dbg, int type, ut8 *buf, int size);
@ -165,6 +166,9 @@ R_API ut64 r_debug_reg_get(struct r_debug_t *dbg, const char *name);
R_API void r_debug_io_bind(RDebug *dbg, RIO *io);
R_API ut64 r_debug_execute(struct r_debug_t *dbg, ut8 *buf, int len);
R_API int r_debug_map_sync(RDebug *dbg);
/* backtrace */
R_API RList *r_debug_frames (RDebug *dbg);
#endif
#endif

View File

@ -87,6 +87,9 @@ R_API ut8* r_reg_get_bytes(struct r_reg_t *reg, int type, int *size);
R_API int r_reg_set_bytes(struct r_reg_t *reg, int type, const ut8* buf, int len);
R_API RRegisterArena *r_reg_arena_new (int size);
R_API int r_reg_fit_arena(struct r_reg_t *reg);
// TODO: r_reg typedef must be renamed to this shorter version
#define RReg RRegister
#endif
#endif

View File

@ -2,5 +2,7 @@
- We must think on a way to do it more algoritmically
* Add support for stepped searchs (skip N bytes after every read)
* Allow to enable/disable nested hits
* Define minimum distance between hits
* Enable/Disable chained hits
* Added support for negated searchs (find until no keyword matches)
- useful to find the end of a \xff block

View File

@ -12,8 +12,7 @@ static char *encodings[3] = { "ascii", "cp850", NULL };
//static int encoding = ENCODING_ASCII; // default
//encoding = resolve_encoding(config_get("cfg.encoding"));
R_API int r_search_get_encoding(const char *name)
{
R_API int r_search_get_encoding(const char *name) {
int i;
if (name != NULL)
for(i=0;encodings[i];i++)
@ -22,13 +21,12 @@ R_API int r_search_get_encoding(const char *name)
return ENCODING_ASCII;
}
static int is_encoded(int encoding, unsigned char c)
{
switch(encoding) {
static int is_encoded(int encoding, unsigned char c) {
switch (encoding) {
case ENCODING_ASCII:
break;
case ENCODING_CP850:
switch(c) {
switch (c) {
// CP850
case 128: // cedilla
case 133: // a grave