342 lines
No EOL
8.2 KiB
C
342 lines
No EOL
8.2 KiB
C
// SPDX-FileCopyrightText: 2009-2019 pancake <pancake@nopcode.org>
|
|
// SPDX-License-Identifier: LGPL-3.0-only
|
|
|
|
#include <errno.h>
|
|
#include <sys/types.h>
|
|
#include <sys/ptrace.h>
|
|
#include <sys/wait.h>
|
|
#include <signal.h>
|
|
|
|
#include <sys/resource.h>
|
|
#include "xnu/xnu_debug.h"
|
|
#include "bt.c"
|
|
|
|
#ifdef __WALL
|
|
#define WAITPID_FLAGS __WALL
|
|
#else
|
|
#define WAITPID_FLAGS 0
|
|
#endif
|
|
|
|
#define PROC_NAME_SZ 1024
|
|
#define PROC_REGION_SZ 100
|
|
// PROC_REGION_SZ - 2 (used for `0x`). Due to how RZ_STR_DEF works this can't be
|
|
// computed.
|
|
#define PROC_REGION_LEFT_SZ 98
|
|
#define PROC_PERM_SZ 5
|
|
#define PROC_UNKSTR_SZ 128
|
|
|
|
static char *rz_debug_native_reg_profile(RzDebug *dbg) {
|
|
#include "reg/darwin-ppc.h"
|
|
}
|
|
|
|
static bool rz_debug_native_step(RzDebug *dbg) {
|
|
return xnu_step(dbg);
|
|
}
|
|
|
|
static int rz_debug_native_attach(RzDebug *dbg, int pid) {
|
|
return xnu_attach(dbg, pid);
|
|
}
|
|
|
|
static int rz_debug_native_detach(RzDebug *dbg, int pid) {
|
|
return xnu_detach(dbg, pid);
|
|
}
|
|
|
|
static int rz_debug_native_continue_syscall(RzDebug *dbg, int pid, int num) {
|
|
RZ_LOG_WARN("TODO: continue syscall not implemented yet\n");
|
|
return -1;
|
|
}
|
|
|
|
static int rz_debug_native_stop(RzDebug *dbg) {
|
|
return 0;
|
|
}
|
|
|
|
static int rz_debug_native_continue(RzDebug *dbg, int pid, int tid, int sig) {
|
|
bool ret = xnu_continue(dbg, pid, tid, sig);
|
|
if (!ret) {
|
|
return -1;
|
|
}
|
|
return tid;
|
|
}
|
|
|
|
static RzDebugInfo *rz_debug_native_info(RzDebug *dbg, const char *arg) {
|
|
return xnu_info(dbg, arg);
|
|
}
|
|
|
|
static RzDebugReasonType rz_debug_native_wait(RzDebug *dbg, int pid) {
|
|
RzDebugReasonType reason = RZ_DEBUG_REASON_UNKNOWN;
|
|
|
|
if (pid == -1) {
|
|
RZ_LOG_ERROR("rz_debug_native_wait called with pid -1\n");
|
|
return RZ_DEBUG_REASON_ERROR;
|
|
}
|
|
rz_cons_break_push(NULL, NULL);
|
|
do {
|
|
reason = xnu_wait(dbg, pid);
|
|
if (reason == RZ_DEBUG_REASON_MACH_RCV_INTERRUPTED) {
|
|
if (rz_cons_is_breaked()) {
|
|
// Perhaps check the inferior is still alive,
|
|
// otherwise xnu_stop will fail.
|
|
reason = xnu_stop(dbg, pid)
|
|
? RZ_DEBUG_REASON_USERSUSP
|
|
: RZ_DEBUG_REASON_UNKNOWN;
|
|
} else {
|
|
// Weird; we'll retry the wait.
|
|
continue;
|
|
}
|
|
}
|
|
break;
|
|
} while (true);
|
|
rz_cons_break_pop();
|
|
dbg->reason.tid = pid;
|
|
dbg->reason.type = reason;
|
|
return reason;
|
|
}
|
|
|
|
#undef MAXPID
|
|
#define MAXPID 99999
|
|
|
|
static RzList /*<RzDebugPid *>*/ *rz_debug_native_pids(RzDebug *dbg, int pid) {
|
|
RzList *list = rz_list_new();
|
|
if (!list) {
|
|
return NULL;
|
|
}
|
|
if (pid) {
|
|
RzDebugPid *p = xnu_get_pid(pid);
|
|
if (p) {
|
|
rz_list_append(list, p);
|
|
}
|
|
} else {
|
|
int i;
|
|
for (i = 1; i < MAXPID; i++) {
|
|
RzDebugPid *p = xnu_get_pid(i);
|
|
if (p) {
|
|
rz_list_append(list, p);
|
|
}
|
|
}
|
|
}
|
|
return list;
|
|
}
|
|
|
|
RZ_API RZ_OWN RzList /*<RzDebugPid *>*/ *rz_debug_native_threads(RzDebug *dbg, int pid) {
|
|
RzList *list = rz_list_new();
|
|
if (!list) {
|
|
RZ_LOG_ERROR("Cannot create list\n");
|
|
return NULL;
|
|
}
|
|
return xnu_thread_list(dbg, pid, list);
|
|
}
|
|
|
|
RZ_API ut64 rz_debug_get_tls(RZ_NONNULL RzDebug *dbg, int tid) {
|
|
rz_return_val_if_fail(dbg, 0);
|
|
return 0;
|
|
}
|
|
|
|
static int rz_debug_native_reg_read(RzDebug *dbg, int type, ut8 *buf, int size) {
|
|
if (size < 1) {
|
|
return false;
|
|
}
|
|
return xnu_reg_read(dbg, type, buf, size);
|
|
}
|
|
|
|
static int rz_debug_native_reg_write(RzDebug *dbg, int type, const ut8 *buf, int size) {
|
|
// XXX use switch or so
|
|
if (type == RZ_REG_TYPE_DRX) {
|
|
return false;
|
|
} else if (type == RZ_REG_TYPE_GPR) {
|
|
return xnu_reg_write(dbg, type, buf, size);
|
|
} else if (type == RZ_REG_TYPE_FPU) {
|
|
return false;
|
|
} else {
|
|
RZ_LOG_DEBUG("TODO: reg_write_non-gpr (%d)\n", type);
|
|
}
|
|
return false;
|
|
}
|
|
|
|
static RzDebugMap *rz_debug_native_map_alloc(RzDebug *dbg, ut64 addr, int size, bool thp) {
|
|
(void)thp;
|
|
return xnu_map_alloc(dbg, addr, size);
|
|
}
|
|
|
|
static int rz_debug_native_map_dealloc(RzDebug *dbg, ut64 addr, int size) {
|
|
return xnu_map_dealloc(dbg, addr, size);
|
|
}
|
|
|
|
static RzList /*<RzDebugMap *>*/ *rz_debug_native_map_get(RzDebug *dbg) {
|
|
RzList *list = NULL;
|
|
list = xnu_dbg_maps(dbg, 0);
|
|
return list;
|
|
}
|
|
|
|
static RzList /*<RzDebugMap *>*/ *rz_debug_native_modules_get(RzDebug *dbg) {
|
|
char *lastname = NULL;
|
|
RzDebugMap *map;
|
|
RzListIter *iter, *iter2;
|
|
RzList *list, *last;
|
|
bool must_delete;
|
|
list = xnu_dbg_maps(dbg, 1);
|
|
if (list && !rz_list_empty(list)) {
|
|
return list;
|
|
}
|
|
if (!(list = rz_debug_native_map_get(dbg))) {
|
|
return NULL;
|
|
}
|
|
if (!(last = rz_list_newf((RzListFree)rz_debug_map_free))) {
|
|
rz_list_free(list);
|
|
return NULL;
|
|
}
|
|
rz_list_foreach_safe (list, iter, iter2, map) {
|
|
const char *file = map->file;
|
|
if (!map->file) {
|
|
file = map->file = rz_str_dup(map->name);
|
|
}
|
|
must_delete = true;
|
|
if (file && *file == '/') {
|
|
if (!lastname || strcmp(lastname, file)) {
|
|
must_delete = false;
|
|
}
|
|
}
|
|
if (must_delete) {
|
|
rz_list_delete(list, iter);
|
|
} else {
|
|
rz_list_append(last, map);
|
|
free(lastname);
|
|
lastname = rz_str_dup(file);
|
|
}
|
|
}
|
|
list->free = NULL;
|
|
free(lastname);
|
|
rz_list_free(list);
|
|
return last;
|
|
}
|
|
|
|
static bool rz_debug_native_kill(RzDebug *dbg, int pid, int tid, int sig) {
|
|
bool ret = false;
|
|
if (pid == 0) {
|
|
pid = dbg->pid;
|
|
}
|
|
if (sig == SIGKILL && dbg->threads) {
|
|
rz_list_free(dbg->threads);
|
|
dbg->threads = NULL;
|
|
}
|
|
if ((rz_sys_kill(pid, sig) != -1)) {
|
|
ret = true;
|
|
}
|
|
if (errno == 1) {
|
|
ret = -true; // EPERM
|
|
}
|
|
return ret;
|
|
}
|
|
|
|
static int rz_debug_native_drx(RzDebug *dbg, int n, ut64 addr, int sz, int rwx, int g, int api_type) {
|
|
RZ_LOG_ERROR("drx: Unsupported platform\n");
|
|
return -1;
|
|
}
|
|
|
|
static int rz_debug_native_bp(RzBreakpoint *bp, RzBreakpointItem *b, bool set) {
|
|
return false;
|
|
}
|
|
|
|
static int getMaxFiles(void) {
|
|
struct rlimit limit;
|
|
if (getrlimit(RLIMIT_NOFILE, &limit) != 0) {
|
|
return 1024;
|
|
}
|
|
return limit.rlim_cur;
|
|
}
|
|
|
|
static RzList *xnu_desc_list(int pid) {
|
|
#if TARGET_OS_IPHONE || __POWERPC__
|
|
return NULL;
|
|
#else
|
|
#define xwrz_testwx(x) ((x & 1) << 2) | (x & 2) | ((x & 4) >> 2)
|
|
RzDebugDesc *desc;
|
|
RzList *ret = rz_list_new();
|
|
struct vnode_fdinfowithpath vi;
|
|
int i, nb, type = 0;
|
|
int maxfd = getMaxFiles();
|
|
|
|
for (i = 0; i < maxfd; i++) {
|
|
nb = proc_pidfdinfo(pid, i, PROC_PIDFDVNODEPATHINFO, &vi, sizeof(vi));
|
|
if (nb < 1) {
|
|
continue;
|
|
}
|
|
if (nb < sizeof(vi)) {
|
|
rz_sys_perror("too few bytes");
|
|
break;
|
|
}
|
|
// printf ("FD %d RWX %x ", i, vi.pfi.fi_openflags);
|
|
// printf ("PATH %s\n", vi.pvip.vip_path);
|
|
desc = rz_debug_desc_new(i,
|
|
vi.pvip.vip_path,
|
|
xwrz_testwx(vi.pfi.fi_openflags),
|
|
type, 0);
|
|
rz_list_append(ret, desc);
|
|
}
|
|
return ret;
|
|
#endif
|
|
}
|
|
|
|
static RzList /*<RzDebugDesc *>*/ *rz_debug_desc_native_list(int pid) {
|
|
return xnu_desc_list(pid);
|
|
}
|
|
|
|
static int rz_debug_native_map_protect(RzDebug *dbg, ut64 addr, int size, int perms) {
|
|
return xnu_map_protect(dbg, addr, size, perms);
|
|
}
|
|
|
|
static int rz_debug_desc_native_open(const char *path) {
|
|
return 0;
|
|
}
|
|
|
|
static bool rz_debug_gcore(RzDebug *dbg, char *path, RzBuffer *dest) {
|
|
(void)path;
|
|
return xnu_generate_corefile(dbg, dest);
|
|
}
|
|
|
|
struct rz_debug_desc_plugin_t rz_debug_desc_plugin_native = {
|
|
.open = rz_debug_desc_native_open,
|
|
.list = rz_debug_desc_native_list,
|
|
};
|
|
|
|
static bool rz_debug_native_init(RzDebug *dbg, void **user) {
|
|
dbg->cur->desc = rz_debug_desc_plugin_native;
|
|
return rz_xnu_debug_init(dbg, user);
|
|
}
|
|
|
|
static void rz_debug_native_fini(RzDebug *dbg, void *user) {
|
|
rz_xnu_debug_fini(dbg, user);
|
|
}
|
|
|
|
RzDebugPlugin rz_debug_plugin_native = {
|
|
.name = "native",
|
|
.license = "LGPL3",
|
|
.bits = RZ_SYS_BITS_32,
|
|
.arch = "ppc",
|
|
.canstep = 1,
|
|
.init = &rz_debug_native_init,
|
|
.fini = &rz_debug_native_fini,
|
|
.step = &rz_debug_native_step,
|
|
.cont = &rz_debug_native_continue,
|
|
.stop = &rz_debug_native_stop,
|
|
.contsc = &rz_debug_native_continue_syscall,
|
|
.attach = &rz_debug_native_attach,
|
|
.detach = &rz_debug_native_detach,
|
|
// TODO: add native select for other platforms?
|
|
.pids = &rz_debug_native_pids,
|
|
.threads = &rz_debug_native_threads,
|
|
.wait = &rz_debug_native_wait,
|
|
.kill = &rz_debug_native_kill,
|
|
.frames = &rz_debug_native_frames, // rename to backtrace ?
|
|
.reg_profile = rz_debug_native_reg_profile,
|
|
.reg_read = rz_debug_native_reg_read,
|
|
.info = rz_debug_native_info,
|
|
.reg_write = (void *)&rz_debug_native_reg_write,
|
|
.map_alloc = rz_debug_native_map_alloc,
|
|
.map_dealloc = rz_debug_native_map_dealloc,
|
|
.map_get = rz_debug_native_map_get,
|
|
.modules_get = rz_debug_native_modules_get,
|
|
.map_protect = rz_debug_native_map_protect,
|
|
.breakpoint = rz_debug_native_bp,
|
|
.drx = rz_debug_native_drx,
|
|
.gcore = rz_debug_gcore,
|
|
}; |