mirror of
https://github.com/radareorg/radare2.git
synced 2025-01-23 22:36:27 +00:00
* Initial implementation of r_debug_step_soft and _hard
- arm-darwin seems to not support stepping, mips follows - Delegate swstep responsability to r_debug api * Implement set registers in arm-darwin - write in memory is not yet working * Some fixes in memory regions list in arm-darwin
This commit is contained in:
parent
19c90096ff
commit
dacab5e4bf
@ -172,17 +172,43 @@ R_API int r_debug_wait(RDebug *dbg) {
|
||||
return ret;
|
||||
}
|
||||
|
||||
// XXX: very experimental
|
||||
R_API int r_debug_step_soft(RDebug *dbg) {
|
||||
ut8 buf[32];
|
||||
RAnalOp op;
|
||||
ut64 pc0, pc1, pc2;
|
||||
pc0 = r_debug_reg_get (dbg, dbg->reg->name[R_REG_NAME_PC]);
|
||||
int ret = r_anal_aop (dbg->anal, &op, pc0, buf, sizeof (buf));
|
||||
pc1 = pc0 + op.length;
|
||||
// XXX: Does not works for 'ret'
|
||||
pc2 = op.jump?op.jump:0;
|
||||
|
||||
r_bp_add_sw (dbg->bp, pc1, 4, R_BP_PROT_EXEC);
|
||||
if (pc2) r_bp_add_sw (dbg->bp, pc2, 4, R_BP_PROT_EXEC);
|
||||
r_debug_continue (dbg);
|
||||
r_debug_wait (dbg);
|
||||
r_bp_del (dbg->bp, pc1);
|
||||
if (pc2) r_bp_del (dbg->bp, pc2);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
R_API int r_debug_step_hard(RDebug *dbg) {
|
||||
if (!dbg->h->step (dbg, dbg->pid))
|
||||
return R_FALSE;
|
||||
return r_debug_wait (dbg);
|
||||
}
|
||||
|
||||
// TODO: count number of steps done to check if no error??
|
||||
R_API int r_debug_step(RDebug *dbg, int steps) {
|
||||
int i, ret = R_FALSE;
|
||||
if (dbg && dbg->h && dbg->h->step) {
|
||||
for (i=0;i<steps;i++) {
|
||||
if (!(ret = dbg->h->step (dbg, dbg->pid)))
|
||||
break;
|
||||
r_debug_wait (dbg);
|
||||
ret = (dbg->swstep)?r_debug_step_soft (dbg):r_debug_step_hard (dbg);
|
||||
// TODO: create wrapper for dbg_wait
|
||||
// TODO: check return value of wait and show error
|
||||
dbg->steps++;
|
||||
if (ret)
|
||||
dbg->steps++;
|
||||
}
|
||||
}
|
||||
return ret;
|
||||
|
@ -23,8 +23,10 @@ R_API void r_debug_map_list(struct r_debug_t *dbg, ut64 addr) {
|
||||
|
||||
R_API RDebugMap *r_debug_map_new (char *name, ut64 addr, ut64 addr_end, int perm, int user) {
|
||||
RDebugMap *map;
|
||||
if (name == NULL || addr >= addr_end)
|
||||
if (name == NULL || addr >= addr_end) {
|
||||
eprintf ("r_debug_map_new: error assert(%"PFMT64x">=%"PFMT64x")\n", addr, addr_end);
|
||||
return NULL;
|
||||
}
|
||||
map = R_NEW (RDebugMap);
|
||||
if (map) {
|
||||
map->name = strdup (name);
|
||||
|
@ -186,16 +186,22 @@ static int r_debug_native_step(RDebug *dbg, int pid) {
|
||||
r_debug_native_continue (pid, -1);
|
||||
#elif __APPLE__
|
||||
debug_arch_x86_trap_set (dbg, 1);
|
||||
// TODO: not supported in all platforms. need dbg.swstep=
|
||||
#if __arm__
|
||||
if (!dbg->swstep)
|
||||
eprintf ("XXX hardware stepping is not supported in arm. set e dbg.swstep=true\n");
|
||||
else eprintf ("XXX: software step is not implemented??\n");
|
||||
return R_FALSE;
|
||||
#endif
|
||||
//eprintf ("stepping from pc = %08x\n", (ut32)get_offset("eip"));
|
||||
//ret = ptrace (PT_STEP, ps.tid, (caddr_t)get_offset("eip"), SIGSTOP);
|
||||
ret = ptrace (PT_STEP, pid, (caddr_t)1, SIGTRAP); //SIGINT);
|
||||
if (ret != 0) {
|
||||
perror ("ptrace-step");
|
||||
eprintf ("mach-error: %d, %s\n", ret, MACH_ERROR_STRING (ret));
|
||||
/* DO NOT WAIT FOR EVENTS !!! */
|
||||
ret = R_FALSE;
|
||||
ret = R_FALSE; /* do not wait for events */
|
||||
} else ret = R_TRUE;
|
||||
#else // __APPLE__
|
||||
#else // linux
|
||||
ut32 addr = 0; /* should be eip */
|
||||
//ut32 data = 0;
|
||||
//printf("NATIVE STEP over PID=%d\n", pid);
|
||||
@ -204,7 +210,7 @@ static int r_debug_native_step(RDebug *dbg, int pid) {
|
||||
perror ("native-singlestep");
|
||||
ret = R_FALSE;
|
||||
} else ret = R_TRUE;
|
||||
#endif // __APPLE_
|
||||
#endif
|
||||
return ret;
|
||||
}
|
||||
|
||||
@ -795,10 +801,35 @@ static int r_debug_native_reg_write(int pid, int type, const ut8* buf, int size)
|
||||
if (sizeof (R_DEBUG_REG_T) < size)
|
||||
size = sizeof (R_DEBUG_REG_T);
|
||||
return (ret != 0) ? R_FALSE: R_TRUE;
|
||||
#elif __APPLE__
|
||||
int ret;
|
||||
thread_array_t inferior_threads = NULL;
|
||||
unsigned int inferior_thread_count = 0;
|
||||
R_DEBUG_REG_T *regs = (R_DEBUG_REG_T*)buf;
|
||||
unsigned int gp_count = sizeof (R_DEBUG_REG_T);
|
||||
|
||||
ret = task_threads (pid_to_task (pid), &inferior_threads, &inferior_thread_count);
|
||||
if (ret != KERN_SUCCESS) {
|
||||
eprintf ("debug_getregs\n");
|
||||
return R_FALSE;
|
||||
}
|
||||
|
||||
if (inferior_thread_count>0) {
|
||||
/* TODO: allow to choose the thread */
|
||||
gp_count = sizeof (R_DEBUG_REG_T)/sizeof(size_t);
|
||||
if (thread_set_state (inferior_threads[0], ARM_THREAD_STATE,
|
||||
(thread_state_t) regs, gp_count) != KERN_SUCCESS) {
|
||||
eprintf ("debug_getregs: Failed to get thread %d %d.error (%x). (%s)\n",
|
||||
(int)pid, pid_to_task (pid), (int)ret, MACH_ERROR_STRING (ret));
|
||||
perror ("thread_get_state");
|
||||
return R_FALSE;
|
||||
}
|
||||
} else eprintf ("There are no threads!\n");
|
||||
return sizeof (R_DEBUG_REG_T);
|
||||
#else
|
||||
#warning r_debug_native_reg_write not implemented
|
||||
#endif
|
||||
} else eprintf("TODO: reg_write_non-gpr (%d)\n", type);
|
||||
} else eprintf ("TODO: reg_write_non-gpr (%d)\n", type);
|
||||
return R_FALSE;
|
||||
}
|
||||
|
||||
@ -813,12 +844,13 @@ static const char * unparse_inheritance (vm_inherit_t i) {
|
||||
}
|
||||
|
||||
// TODO: move to p/native/darwin.c
|
||||
// TODO: this loop MUST be cleaned up
|
||||
static RList *darwin_dbg_maps (RDebug *dbg) {
|
||||
RDebugMap *mr;
|
||||
RList *list = r_list_new ();
|
||||
|
||||
char buf[128];
|
||||
int i;
|
||||
int i, print;
|
||||
kern_return_t kret;
|
||||
vm_region_basic_info_data_64_t info, prev_info;
|
||||
mach_vm_address_t prev_address;
|
||||
@ -829,8 +861,6 @@ static RList *darwin_dbg_maps (RDebug *dbg) {
|
||||
int num_printed = 0;
|
||||
// XXX: wrong for 64bits
|
||||
size_t address = 0;
|
||||
|
||||
int max = 100; // XXX
|
||||
task_t task = pid_to_task (dbg->pid);
|
||||
/*
|
||||
count = VM_REGION_BASIC_INFO_COUNT_64;
|
||||
@ -842,20 +872,22 @@ static RList *darwin_dbg_maps (RDebug *dbg) {
|
||||
}
|
||||
memcpy (&prev_info, &info, sizeof (vm_region_basic_info_data_64_t));
|
||||
*/
|
||||
size = 4096;
|
||||
memset (&prev_info, 0, sizeof (prev_info));
|
||||
prev_address = address;
|
||||
prev_size = size;
|
||||
nsubregions = 1;
|
||||
|
||||
for (i=0; ; i++) {
|
||||
int print = 0;
|
||||
int done = 0;
|
||||
|
||||
address = prev_address + prev_size;
|
||||
|
||||
if (prev_size==0)
|
||||
break;
|
||||
/* Check to see if address space has wrapped around. */
|
||||
if (address == 0)
|
||||
print = done = 1;
|
||||
done = 1;
|
||||
|
||||
if (!done) {
|
||||
count = VM_REGION_BASIC_INFO_COUNT_64;
|
||||
@ -877,33 +909,21 @@ static RList *darwin_dbg_maps (RDebug *dbg) {
|
||||
|| (info.shared != prev_info.reserved)
|
||||
|| (info.reserved != prev_info.reserved))
|
||||
print = 1;
|
||||
|
||||
#if 0
|
||||
mr = malloc(sizeof(MAP_REG));
|
||||
mr->ini = (ut32) prev_address;
|
||||
mr->end = (ut32) (prev_address+ prev_size);
|
||||
mr->size = (ut32) prev_size;
|
||||
|
||||
mr->bin = strdup(buf);
|
||||
mr->perms = darwin_prot_to_unix(prev_info.protection); // XXX is this ok?
|
||||
//mr->flags = // FLAG_NOPERM // FLAG_USERCODE ...
|
||||
//mr->perms = prev_info.max_protection;
|
||||
|
||||
add_regmap(mr);
|
||||
#endif
|
||||
sprintf(buf, "unk%d-%s-%s-%s", i,
|
||||
unparse_inheritance (prev_info.inheritance),
|
||||
prev_info.shared ? "shar" : "priv",
|
||||
prev_info.reserved ? "reserved" : "not-reserved");
|
||||
// TODO: MAPS can have min and max protection rules
|
||||
// :: prev_info.max_protection
|
||||
mr = r_debug_map_new (buf, prev_address, prev_address+prev_size, prev_info.protection, 0);
|
||||
if (mr == NULL) {
|
||||
eprintf ("Cannot create r_debug_map_new\n");
|
||||
break;
|
||||
if (print) {
|
||||
sprintf (buf, "%s %02x %s/%s/%s",
|
||||
r_str_rwx_i (prev_info.max_protection), i,
|
||||
unparse_inheritance (prev_info.inheritance),
|
||||
prev_info.shared ? "shar" : "priv",
|
||||
prev_info.reserved ? "reserved" : "not-reserved");
|
||||
// TODO: MAPS can have min and max protection rules
|
||||
// :: prev_info.max_protection
|
||||
mr = r_debug_map_new (buf, prev_address, prev_address+prev_size, prev_info.protection, 0);
|
||||
if (mr == NULL) {
|
||||
eprintf ("Cannot create r_debug_map_new\n");
|
||||
break;
|
||||
}
|
||||
r_list_append (list, mr);
|
||||
}
|
||||
r_list_append (list, mr);
|
||||
|
||||
#if 0
|
||||
if (1==0 && rest) { /* XXX never pritn this info here */
|
||||
addr = 0LL;
|
||||
@ -944,12 +964,6 @@ static RList *darwin_dbg_maps (RDebug *dbg) {
|
||||
num_printed++;
|
||||
#endif
|
||||
// }
|
||||
|
||||
if ((max > 0) && (num_printed >= max))
|
||||
done = 1;
|
||||
|
||||
if (done)
|
||||
break;
|
||||
}
|
||||
return list;
|
||||
}
|
||||
|
@ -75,23 +75,17 @@ static int __read(RIO *io, int pid, ut8 *buff, int len) {
|
||||
return (int)size;
|
||||
}
|
||||
|
||||
static int ptrace_write_at(int tid, const void *buff, int len, ut64 addr) {
|
||||
static int mach_write_at(int tid, const void *buff, int len, ut64 addr) {
|
||||
kern_return_t err;
|
||||
task_t task = pid_to_task (tid);
|
||||
// XXX SHOULD RESTORE PERMS LATER!!!
|
||||
err = vm_protect (pid_to_task (tid), addr+(addr%4096), 4096, 0,
|
||||
VM_PROT_READ | VM_PROT_WRITE);
|
||||
if (err != KERN_SUCCESS)
|
||||
eprintf ("cant change page perms to rw\n");
|
||||
|
||||
err = vm_write( pid_to_task(tid),
|
||||
(vm_address_t)(unsigned int)addr, // XXX not for 64 bits
|
||||
(pointer_t)buff, (mach_msg_type_number_t)len);
|
||||
if (err != KERN_SUCCESS)
|
||||
//err = vm_protect (task, addr+(addr%4096), 4096, 0, VM_PROT_READ | VM_PROT_WRITE);
|
||||
if (vm_protect (task, addr, len, 0, VM_PROT_READ | VM_PROT_WRITE) != KERN_SUCCESS)
|
||||
eprintf ("cant change page perms to rw at 0x%"PFMT64x"\n", addr);
|
||||
if (vm_write (task, (vm_address_t)(unsigned int)addr, // XXX not for 64 bits
|
||||
(pointer_t)buff, (mach_msg_type_number_t)len) != KERN_SUCCESS)
|
||||
eprintf ("cant write on memory\n");
|
||||
|
||||
vm_protect (pid_to_task (tid), addr+(addr%4096), 4096, 0,
|
||||
VM_PROT_READ | VM_PROT_EXECUTE);
|
||||
if (err != KERN_SUCCESS) {
|
||||
if (vm_protect (task, addr, len, 0, VM_PROT_READ | VM_PROT_EXECUTE) != KERN_SUCCESS) {
|
||||
eprintf ("Oops (0x%"PFMT64x") error (%s)\n", addr,
|
||||
MACH_ERROR_STRING (err));
|
||||
eprintf ("cant change page perms to rx\n");
|
||||
@ -100,7 +94,7 @@ static int ptrace_write_at(int tid, const void *buff, int len, ut64 addr) {
|
||||
}
|
||||
|
||||
static int __write(struct r_io_t *io, int pid, const ut8 *buf, int len) {
|
||||
return ptrace_write_at (pid, buf, len, io->off);
|
||||
return mach_write_at (pid, buf, len, io->off);
|
||||
}
|
||||
|
||||
static int __plugin_open(struct r_io_t *io, const char *file) {
|
||||
@ -117,7 +111,6 @@ static int debug_attach(int pid) {
|
||||
inferior_task = pid_to_task (pid);
|
||||
if (inferior_task == -1)
|
||||
return -1;
|
||||
|
||||
task = inferior_task; // ugly global asignation
|
||||
eprintf ("; pid = %d\ntask= %d\n", pid, inferior_task);
|
||||
#if 0
|
||||
@ -138,7 +131,7 @@ static int debug_attach(int pid) {
|
||||
#endif
|
||||
/* is this required for arm ? */
|
||||
#if EXCEPTION_PORT
|
||||
int exception_port;
|
||||
int exception_port;
|
||||
if (mach_port_allocate (mach_task_self(), MACH_PORT_RIGHT_RECEIVE,
|
||||
&exception_port) != KERN_SUCCESS) {
|
||||
eprintf ("Failed to create exception port.\n");
|
||||
@ -225,12 +218,10 @@ struct r_io_plugin_t r_io_plugin_mach = {
|
||||
};
|
||||
|
||||
#else
|
||||
|
||||
struct r_io_plugin_t r_io_plugin_mach = {
|
||||
.name = "io.mach ",
|
||||
.name = "io.mach",
|
||||
.desc = "mach debug io (unsupported in this platform)"
|
||||
};
|
||||
|
||||
#endif
|
||||
|
||||
#ifndef CORELIB
|
||||
|
Loading…
x
Reference in New Issue
Block a user