* Add XML to ldid r2 debugger for iOS

* Fix build of the r2 debugger on darwin-arm
* Implement list of threads and memory regions on darwin-arm
  - just a draft, needs more work
* Add attach:// IO handler to mach plugin
* darwin does not needs -ldl
This commit is contained in:
pancake 2010-11-11 01:09:27 +01:00
parent 1c779dfd3c
commit cfa24e1879
10 changed files with 296 additions and 35 deletions

View File

@ -5,6 +5,9 @@ BINDEPS+=r_sign r_print r_lang r_asm r_syscall r_hash r_line r_socket r_flags r_
include ../binr.mk
sign:
ldid -Sradare2.xml radare2
ifeq ($(WITHNONPIC),1)
LDFLAGS+=${DL_LIBS} -lm -lpthread
ifeq ($(HAVE_LIB_GMP),1)

17
binr/radare2/radare2.xml Normal file
View File

@ -0,0 +1,17 @@
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>app-identifier</key>
<true/>
<key>get-task-allow</key>
<true/>
<key>task_for_pid-allow</key>
<true/>
</dict>
</plist>
<!--
This file must be used to 'sign' the 'radare' binary
after compiling to permit debugging on the iphone-os
$ ldid -Sradare2.xml radare2
-->

View File

@ -21,7 +21,10 @@ VERSION=@VERSION@
# ./configure --with-ostype=[linux,osx,solaris,windows] # TODO: rename to w32, w64?
OSTYPE=@USEROSTYPE@
HOST_OS=@HOST_OS@
# hack: must be fixed in acr
ifneq($(OSTYPE),darwin)
DL_LIBS=@DL_LIBS@
endif
WITHPIC=@WITHPIC@
WITHNONPIC=@WITHNONPIC@

View File

@ -61,7 +61,11 @@ static HANDLE tid2handler(int tid) {
#include <mach/exception_types.h>
#include <mach/mach_init.h>
#include <mach/mach_port.h>
#include <mach/mach_interface.h>
#include <mach/mach_traps.h>
#include <mach/mach_types.h>
#include <mach/mach_vm.h>
#include <mach/mach_error.h>
#include <mach/task.h>
#include <mach/task_info.h>
#include <mach/thread_act.h>
@ -136,7 +140,7 @@ task_t pid_to_task(int pid) {
if (old_task!= -1) //old_pid != -1 && old_pid == pid)
return old_task;
err = task_for_pid(mach_task_self(), (pid_t)pid, &task);
err = task_for_pid (mach_task_self(), (pid_t)pid, &task);
if ((err != KERN_SUCCESS) || !MACH_PORT_VALID(task)) {
eprintf ("Failed to get task %d for pid %d.\n", (int)task, (int)pid);
eprintf ("Reason: 0x%x: %s\n", err, (char *)MACH_ERROR_STRING (err));
@ -225,7 +229,7 @@ static int r_debug_native_detach(int pid) {
#if __WINDOWS__
return w32_detach (pid)? 0 : -1;
#elif __APPLE__
return ptrace (PT_DETACH, pid, NULL, NULL);
return ptrace (PT_DETACH, pid, NULL, 0);
#else
return ptrace (PTRACE_DETACH, pid, NULL, NULL);
#endif
@ -561,7 +565,7 @@ static RList *r_debug_native_pids(int pid) {
continue;
read (fd, cmdline, 1024);
cmdline[1023] = '\0';
r_list_append (list, r_debug_pid_new (cmdline, i, 's'));
r_list_append (list, r_debug_pid_new (cmdline, i, 's', 0));
}
close (fd);
}
@ -578,7 +582,7 @@ static RList *r_debug_native_pids(int pid) {
read (fd, cmdline, sizeof (cmdline));
cmdline[sizeof (cmdline)-1] = '\0';
close (fd);
r_list_append (list, r_debug_pid_new (cmdline, i, 's'));
r_list_append (list, r_debug_pid_new (cmdline, i, 's', 0));
}
}
#endif
@ -591,7 +595,35 @@ static RList *r_debug_native_threads(int pid) {
#if __WINDOWS__
eprintf ("pids: TODO\n");
#elif __APPLE__
eprintf ("pids: TODO\n");
#if __arm__
#define OSX_PC state.r15
#undef THREAD_STATE
#define THREAD_STATE ARM_THREAD_STATE
#elif __POWERPC__
#define OSX_PC state.srr0
#else
#define OSX_PC state.__eip
#endif
int i, tid, err;
unsigned int gp_count;
static thread_array_t inferior_threads = NULL;
static unsigned int inferior_thread_count = 0;
R_DEBUG_REG_T state;
if (task_threads (pid_to_task (pid), &inferior_threads,
&inferior_thread_count) != KERN_SUCCESS) {
eprintf ("Failed to get list of task's threads.\n");
return list;
}
for (i = 0; i < inferior_thread_count; i++) {
tid = inferior_threads[i];
if ((err = thread_get_state (tid, ARM_THREAD_STATE,
(thread_state_t) &state, &gp_count)) != KERN_SUCCESS) {
// eprintf ("debug_list_threads: %s\n", MACH_ERROR_STRING(err));
OSX_PC = 0;
}
r_list_append (list, r_debug_pid_new ("???", i, 's', OSX_PC));
}
#elif __linux__
int i, fd, thid = 0;
char *ptr, cmdline[1024];
@ -650,9 +682,6 @@ static int r_debug_native_reg_read(RDebug *dbg, int type, ut8 *buf, int size) {
R_DEBUG_REG_T *regs = (R_DEBUG_REG_T *)buf;
unsigned int gp_count = sizeof (R_DEBUG_REG_T);
//thread_act_port_array_t thread_list;
//mach_msg_type_number_t thread_count;
ret = task_threads (pid_to_task (pid), &inferior_threads, &inferior_thread_count);
if (ret != KERN_SUCCESS) {
eprintf ("debug_getregs\n");
@ -661,8 +690,8 @@ static int r_debug_native_reg_read(RDebug *dbg, int type, ut8 *buf, int size) {
if (inferior_thread_count>0) {
/* TODO: allow to choose the thread */
if ((ret = thread_get_state (inferior_threads[0], R_DEBUG_STATE_T,
(thread_state_t) regs, &gp_count)) != KERN_SUCCESS) {
if (thread_get_state (inferior_threads[0], R_DEBUG_STATE_T,
(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");
@ -670,7 +699,6 @@ static int r_debug_native_reg_read(RDebug *dbg, int type, ut8 *buf, int size) {
}
} else eprintf ("There are no threads!\n");
return R_TRUE; //gp_count;
#elif __linux__ || __sun || __NetBSD__ || __FreeBSD__ || __OpenBSD__
int ret;
switch (type) {
@ -706,10 +734,8 @@ static int r_debug_native_reg_read(RDebug *dbg, int type, ut8 *buf, int size) {
R_DEBUG_REG_T regs;
memset (&regs, 0, sizeof (regs));
memset (buf, 0, size);
#if __NetBSD__ || __FreeBSD__ || __OpenBSD__
ret = ptrace (PTRACE_GETREGS, pid, &regs, sizeof (regs));
#elif __linux__ && __powerpc__
ret = ptrace (PTRACE_GETREGS, pid, &regs, NULL);
#else
@ -770,15 +796,168 @@ static int r_debug_native_reg_write(int pid, int type, const ut8* buf, int size)
return R_FALSE;
}
#if __APPLE__
static const char * unparse_inheritance (vm_inherit_t i) {
switch (i) {
case VM_INHERIT_SHARE: return "share";
case VM_INHERIT_COPY: return "copy";
case VM_INHERIT_NONE: return "none";
default: return "???";
}
}
// TODO: move to p/native/darwin.c
static RList *darwin_dbg_maps (RDebug *dbg) {
RDebugMap *mr;
RList *list = r_list_new ();
char buf[128];
int i;
kern_return_t kret;
vm_region_basic_info_data_64_t info, prev_info;
mach_vm_address_t prev_address;
mach_vm_size_t size, prev_size;
mach_port_t object_name;
mach_msg_type_number_t count;
int nsubregions = 0;
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;
kret = mach_vm_region (pid_to_task (dbg->pid), &address, &size, VM_REGION_BASIC_INFO_64,
(vm_region_info_t) &info, &count, &object_name);
if (kret != KERN_SUCCESS) {
printf("No memory regions.\n");
return;
}
memcpy (&prev_info, &info, sizeof (vm_region_basic_info_data_64_t));
*/
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;
/* Check to see if address space has wrapped around. */
if (address == 0)
print = done = 1;
if (!done) {
count = VM_REGION_BASIC_INFO_COUNT_64;
kret = mach_vm_region (task, (mach_vm_address_t *)&address,
&size, VM_REGION_BASIC_INFO_64,
(vm_region_info_t) &info, &count, &object_name);
if (kret != KERN_SUCCESS) {
size = 0;
print = done = 1;
}
}
if (address != prev_address + prev_size)
print = 1;
if ((info.protection != prev_info.protection)
|| (info.max_protection != prev_info.max_protection)
|| (info.inheritance != prev_info.inheritance)
|| (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;
}
r_list_append (list, mr);
#if 0
if (1==0 && rest) { /* XXX never pritn this info here */
addr = 0LL;
addr = (ut64) (ut32) prev_address;
if (num_printed == 0)
fprintf(stderr, "Region ");
else fprintf(stderr, " ... ");
fprintf(stderr, " 0x%08llx - 0x%08llx %s (%s) %s, %s, %s",
addr, addr + prev_size,
unparse_protection (prev_info.protection),
unparse_protection (prev_info.max_protection),
unparse_inheritance (prev_info.inheritance),
prev_info.shared ? "shared" : " private",
prev_info.reserved ? "reserved" : "not-reserved");
if (nsubregions > 1)
fprintf(stderr, " (%d sub-regions)", nsubregions);
fprintf(stderr, "\n");
prev_address = address;
prev_size = size;
memcpy (&prev_info, &info, sizeof (vm_region_basic_info_data_64_t));
nsubregions = 1;
num_printed++;
} else {
#endif
#if 0
prev_size += size;
nsubregions++;
#else
prev_address = address;
prev_size = size;
memcpy (&prev_info, &info, sizeof (vm_region_basic_info_data_64_t));
nsubregions = 1;
num_printed++;
#endif
// }
if ((max > 0) && (num_printed >= max))
done = 1;
if (done)
break;
}
return list;
}
#endif
static RList *r_debug_native_map_get(RDebug *dbg) {
char path[1024];
RList *list = NULL;
#if __WINDOWS__
list = w32_dbg_maps ();
// TODO
#if __APPLE__
list = darwin_dbg_maps (dbg);
#elif __WINDOWS__
list = w32_dbg_maps (); // TODO: moar?
#else
#if __sun
char path[1024];
/* TODO: On solaris parse /proc/%d/map */
sprintf (path, "pmap %d > /dev/stderr", ps.tid);
system (path);
@ -786,8 +965,8 @@ static RList *r_debug_native_map_get(RDebug *dbg) {
RDebugMap *map;
int i, perm, unk = 0;
char *pos_c;
char path[1024], line[1024];
char region[100], region2[100], perms[5], null[16];
char line[1024];
FILE *fd;
#if __FreeBSD__
sprintf (path, "/proc/%d/map", dbg->pid);
@ -796,7 +975,7 @@ static RList *r_debug_native_map_get(RDebug *dbg) {
#endif
fd = fopen (path, "r");
if (!fd) {
perror ("debug_init_maps");
perror ("debug_init_maps: /proc");
return NULL;
}
@ -1018,8 +1197,8 @@ int drx_del(RDebug *dbg, ut64 addr, int rwx) {
#endif
static int r_debug_native_bp(void *user, int add, ut64 addr, int hw, int rwx) {
RDebug *dbg = user;
#if __i386__ || __x86_64__
RDebug *dbg = user;
if (hw) {
if (add) return drx_add (dbg, addr, rwx);
return drx_del (dbg, addr, rwx);

View File

@ -1,5 +1,5 @@
include ../../config.mk
BINDEPS=r_reg r_bp r_util r_io
BINDEPS=r_reg r_bp r_util r_io r_anal
CFLAGS+=-Ilibgdbwrap/include
ifeq (${OSTYPE},windows)

View File

@ -0,0 +1,57 @@
#include <stdio.h>
int pids_cmdline(int pid, char *cmdline) {
int fd;
sprintf(cmdline, "/proc/%d/cmdline", pid);
fd = open(cmdline, O_RDONLY);
cmdline[0] = '\0';
if (fd != -1) {
read(fd, cmdline, 1024);
cmdline[1024] = '\0';
close(fd);
}
return 0;
}
// XXX
int pids_sons_of_r(int pid, int recursive, int limit) {
int p;
int n = 0;
int mola;
char buf[128];
int tmp;
char tmp2[1024];
char tmp3[8];
struct dirent *file;
FILE *fd;
DIR *dh = opendir("/proc/");
if (pid == 0 || dh == NULL)
return 0;
while((file=(struct dirent *)readdir(dh)) ) {
p = atoi(file->d_name);
if (p) {
sprintf(buf,"/proc/%s/stat", file->d_name);
fd = fopen(buf, "r");
if (fd) {
mola = 0;
fscanf(fd,"%d %s %s %d",
&tmp, tmp2, tmp3, &mola);
if (mola == pid) {
pids_cmdline(p, tmp2);
//for(i=0; i<recursive*2;i++)
// printf(" ");
cons_printf(" `- %d : %s (%s)\n", p, tmp2, (tmp3[0]=='S')?"sleeping":(tmp3[0]=='T')?"stopped":"running");
n++;
if (recursive<limit)
n+=pids_sons_of_r(p, recursive+1, limit);
}
}
fclose(fd);
}
}
return n;
}

View File

@ -14,7 +14,9 @@ enum {
R_DBG_PROC_STOP = 's',
R_DBG_PROC_RUN = 'r',
R_DBG_PROC_SLEEP = 'S',
R_DBG_PROC_ZOMBIE = 'z'
R_DBG_PROC_ZOMBIE = 'z',
R_DBG_PROC_DEAD = 'd',
R_DBG_PROC_RAISED = 'R' // has produced a signal, breakpoint, etc..
};
// signal handling must support application and debugger level options
@ -152,9 +154,7 @@ typedef struct r_debug_pid_t {
char status; /* stopped, running, zombie, sleeping ,... */
int runnable; /* when using 'run', 'continue', .. this proc will be runnable */
const char *path;
//struct list_head threads;
//struct list_head childs;
//struct r_debug_pid_t *parent;
ut64 pc;
} RDebugPid;
#ifdef R_API
@ -174,7 +174,7 @@ R_API int r_debug_continue_syscall(struct r_debug_t *dbg, int sc);
//R_API int r_debug_pid_del(struct r_debug_t *dbg);
//R_API int r_debug_pid_del_thread(struct r_debug_t *dbg);
R_API int r_debug_pid_list(RDebug *dbg, int pid);
R_API RDebugPid *r_debug_pid_new(char *path, int pid, char status);
R_API RDebugPid *r_debug_pid_new(char *path, int pid, char status, ut64 pc);
R_API RDebugPid *r_debug_pid_free(RDebugPid *pid);
R_API int r_debug_use(struct r_debug_t *dbg, const char *str);

View File

@ -18,6 +18,7 @@
#include <mach/mach_init.h>
#include <mach/mach_port.h>
#include <mach/mach_traps.h>
#include <mach/mach_error.h>
#include <mach/task.h>
#include <mach/task_info.h>
#include <mach/thread_act.h>
@ -48,10 +49,10 @@ static task_t pid_to_task(int pid) {
if (old_task!= -1) //old_pid != -1 && old_pid == pid)
return old_task;
err = task_for_pid(mach_task_self(), (pid_t)pid, &task);
err = task_for_pid (mach_task_self (), (pid_t)pid, &task);
if ((err != KERN_SUCCESS) || !MACH_PORT_VALID(task)) {
fprintf(stderr, "Failed to get task %d for pid %d.\n", (int)task, (int)pid);
eprintf ("Reason: 0x%x: %s\n", err, MACH_ERROR_STRING(err));
eprintf ("Reason: 0x%x: %s\n", err, MACH_ERROR_STRING (err));
eprintf ("You probably need to add user to procmod group.\n"
" Or chmod g+s radare && chown root:procmod radare\n");
fprintf(stderr, "FMI: http://developer.apple.com/documentation/Darwin/Reference/ManPages/man8/taskgated.8.html\n");
@ -63,7 +64,7 @@ static task_t pid_to_task(int pid) {
return task;
}
static int __read(RIO *io, int pid, void *buff, int len) {
static int __read(RIO *io, int pid, ut8 *buff, int len) {
unsigned int size = 0;
int err = vm_read_overwrite (pid_to_task (pid),
(unsigned int)io->off, len, (pointer_t)buff, &size);
@ -103,7 +104,7 @@ static int __write(struct r_io_t *io, int pid, const ut8 *buf, int len) {
}
static int __plugin_open(struct r_io_t *io, const char *file) {
if (!memcmp (file, "mach://", 7))
if (!memcmp (file, "attach://", 9) || !memcmp (file, "mach://", 7))
return R_TRUE;
return R_FALSE;
}
@ -159,7 +160,7 @@ static int debug_attach(int pid) {
static int __open(struct r_io_t *io, const char *file, int rw, int mode) {
int ret = -1;
if (__plugin_open (io, file)) {
int pid = atoi(file+7);
int pid = atoi(file+(file[0]=='a'?9:7));
if (pid>0) {
ret = debug_attach (pid);
if (ret == -1) {
@ -225,8 +226,8 @@ struct r_io_plugin_t r_io_plugin_mach = {
#else
struct r_io_plugin_t r_io_plugin_mach = {
.name = "io.ptrace",
.desc = "ptrace io (NOT SUPPORTED FOR THIS PLATFORM)",
.name = "io.mach ",
.desc = "mach debug io (unsupported in this platform)"
};
#endif

View File

@ -24,7 +24,7 @@ R_API RIOSection *r_io_section_get_i(RIO *io, int idx) {
int i = 0;
struct list_head *pos;
list_for_each_prev (pos, &io->sections) {
RIOSection *s = (RIOSection *)list_entry(pos, RIOSection, list);
RIOSection *s = (RIOSection *)list_entry (pos, RIOSection, list);
if (i == idx)
return s;
i++;

View File

@ -93,6 +93,7 @@ public class Radare.RDebug {
RUN,
SLEEP,
ZOMBIE,
DEAD
}
[CCode (cprefix="R_DBG_REASON_", cname="int")]