/* Returns PID */ R_API int r_debug_wait(RDebug *dbg) { int ret = 0; if (r_debug_is_dead (dbg)) return R_FALSE; if (dbg && dbg->h && dbg->h->wait) { dbg->reason = R_DBG_REASON_UNKNOWN; ret = dbg->h->wait (dbg, dbg->pid); dbg->reason = ret; dbg->newstate = 1; if (ret == -1) { eprintf ("\n==> Process finished\n\n"); r_debug_select (dbg, -1, -1); } //eprintf ("wait = %d\n", ret); if (dbg->trace->enabled) r_debug_trace_pc (dbg); if (ret == R_DBG_REASON_SIGNAL && dbg->signum != -1) { /* handle signal on continuations here */ int what = r_debug_signal_what (dbg, dbg->signum); const char *name = r_debug_signal_resolve_i (dbg, dbg->signum); if (strcmp ("SIGTRAP", name)) r_cons_printf ("[+] signal %d aka %s received\n", dbg->signum, name); if (what & R_DBG_SIGNAL_SKIP) { dbg->signum = 0; // TODO: use ptrace-setsiginfo to ignore signal } if (what & R_DBG_SIGNAL_CONT) { // XXX: support step, steptrace, continue_until_foo, etc.. r_debug_continue (dbg); } } } return ret; }
/* Returns PID */ R_API int r_debug_wait(RDebug *dbg) { int ret = 0; if (!dbg) return R_FALSE; dbg->reason.type = R_DEBUG_REASON_UNKNOWN; if (r_debug_is_dead (dbg)) { return dbg->reason.type = R_DEBUG_REASON_DEAD; } if (dbg->h && dbg->h->wait) { dbg->reason.type = R_DEBUG_REASON_UNKNOWN; ret = dbg->h->wait (dbg, dbg->pid); dbg->newstate = 1; if (ret == -1) { eprintf ("\n==> Process finished\n\n"); r_debug_select (dbg, -1, -1); } //eprintf ("wait = %d\n", ret); if (dbg->trace->enabled) r_debug_trace_pc (dbg); if (ret == R_DEBUG_REASON_SIGNAL && dbg->reason.signum != -1) { /* handle signal on continuations here */ int what = r_debug_signal_what (dbg, dbg->reason.signum); const char *name = r_debug_signal_resolve_i (dbg, dbg->reason.signum); if (name && strcmp ("SIGTRAP", name)) r_cons_printf ("[+] signal %d aka %s received %d\n", dbg->reason.signum, name, what); } } return ret; }
R_API int r_debug_attach(RDebug *dbg, int pid) { int ret = false; if (dbg && dbg->h && dbg->h->attach) { ret = dbg->h->attach (dbg, pid); if (ret != -1) { //eprintf ("Attached debugger to pid = %d, tid = %d\n", pid, ret); r_debug_select (dbg, pid, ret); //dbg->pid, dbg->tid); } } return ret; }
static int config_cfgdebug_callback(void *user, void *data) { RCore *core = (RCore*) user; RConfigNode *node = (RConfigNode*) data; if (!core) return R_FALSE; if (core->io) core->io->debug = node->i_value; if (core->dbg && node->i_value) { const char *dbgbackend = r_config_get (core->config, "dbg.backend"); r_debug_use (core->dbg, dbgbackend); if (!strcmp (dbgbackend, "bf")) r_config_set (core->config, "asm.arch", "bf"); if (core->file) { r_debug_select (core->dbg, core->file->fd->fd, core->file->fd->fd); } } else r_debug_use (core->dbg, NULL); return R_TRUE; }
R_API int r_debug_attach(RDebug *dbg, int pid) { int ret = R_FALSE; if (dbg && dbg->h && dbg->h->attach) { ret = dbg->h->attach (dbg, pid); if (ret != -1) { eprintf ("Attached debugger to pid = %d, tid = %d\n", pid, ret); // TODO: get arch and set io pid //int arch = dbg->h->arch; //r_reg_set(dbg->reg->nregs, arch); //R_DBG_ARCH_X86); // dbg->bp->iob->system("pid %d", pid); //dbg->pid = pid; //dbg->tid = ret; r_debug_select (dbg, pid, ret); //dbg->pid, dbg->tid); }// else if (pid != -1) // eprintf ("Cannot attach to this pid %d\n", pid); }// else eprintf ("dbg->attach = NULL\n"); return ret; }
/* Returns PID */ R_API int r_debug_wait(RDebug *dbg) { int ret = 0; if (r_debug_is_dead (dbg)) return R_FALSE; if (dbg && dbg->h && dbg->h->wait) { dbg->reason = R_DBG_REASON_UNKNOWN; ret = dbg->h->wait (dbg, dbg->pid); dbg->reason = ret; dbg->newstate = 1; if (ret == -1) { eprintf ("\n==> Process finished\n\n"); r_debug_select (dbg, -1, -1); //dbg->pid = -1; } //eprintf ("wait = %d\n", ret); if (dbg->trace->enabled) r_debug_trace_pc (dbg); } return ret; }
R_API int r_debug_continue_kill(RDebug *dbg, int sig) { int ret = R_FALSE; if (r_debug_is_dead (dbg)) return R_FALSE; if (dbg && dbg->h && dbg->h->cont) { r_bp_restore (dbg->bp, R_FALSE); // set sw breakpoints ret = dbg->h->cont (dbg, dbg->pid, dbg->tid, sig); r_debug_wait (dbg); r_bp_restore (dbg->bp, R_TRUE); // unset sw breakpoints r_debug_recoil (dbg); #if 0 #if __UNIX__ /* XXX Uh? */ if (dbg->stop_all_threads && dbg->pid>0) r_sandbox_kill (dbg->pid, SIGSTOP); #endif #endif r_debug_select (dbg, dbg->pid, ret); } return ret; }
R_API int r_debug_continue_kill(RDebug *dbg, int sig) { ut64 pc; int retwait, ret = R_FALSE; if (!dbg) return R_FALSE; #if __WINDOWS__ r_cons_break(w32_break_process, dbg); #endif repeat: if (r_debug_is_dead (dbg)) return R_FALSE; if (dbg->h && dbg->h->cont) { r_bp_restore (dbg->bp, R_TRUE); // set sw breakpoints ret = dbg->h->cont (dbg, dbg->pid, dbg->tid, sig); dbg->reason.signum = 0; retwait = r_debug_wait (dbg); #if __WINDOWS__ if (retwait != R_DEBUG_REASON_DEAD) { ret = dbg->tid; } #endif r_bp_restore (dbg->bp, R_FALSE); // unset sw breakpoints //r_debug_recoil (dbg); if (r_debug_recoil (dbg) || (dbg->reason.type == R_DEBUG_REASON_BREAKPOINT)) { /* check if cur bp demands tracing or not */ pc = r_debug_reg_get (dbg, dbg->reg->name[R_REG_NAME_PC]); RBreakpointItem *b = r_bp_get_at (dbg->bp, pc); if (b) { /* check if cur bp demands tracing or not */ if (b->trace) { eprintf("hit tracepoit at: %"PFMT64x"\n",pc); } else { eprintf("hit breakpoint at: %"PFMT64x"\n",pc); } if (dbg->trace->enabled) r_debug_trace_pc (dbg); // TODO: delegate this to RCore.bphit(RCore, RBreakopintItem) if (dbg->corebind.core && dbg->corebind.bphit) { dbg->corebind.bphit (dbg->corebind.core, b); } if (b->trace) { r_debug_step (dbg, 1); goto repeat; } } } #if 0 #if __UNIX__ /* XXX Uh? */ if (dbg->stop_all_threads && dbg->pid>0) r_sandbox_kill (dbg->pid, SIGSTOP); #endif #endif r_debug_select (dbg, dbg->pid, ret); sig = 0; // clear continuation after signal if needed if (retwait == R_DEBUG_REASON_SIGNAL && dbg->reason.signum != -1) { int what = r_debug_signal_what (dbg, dbg->reason.signum); if (what & R_DBG_SIGNAL_CONT) { sig = dbg->reason.signum; eprintf ("Continue into the signal %d handler\n", sig); goto repeat; } else if (what & R_DBG_SIGNAL_SKIP) { // skip signal. requires skipping one instruction ut8 buf[64]; RAnalOp op = {0}; ut64 pc = r_debug_reg_get (dbg, "pc"); dbg->iob.read_at (dbg->iob.io, pc, buf, sizeof (buf)); r_anal_op (dbg->anal, &op, pc, buf, sizeof (buf)); if (op.size>0) { const char *signame = r_debug_signal_resolve_i (dbg, dbg->reason.signum); r_debug_reg_set (dbg, "pc", pc+op.size); eprintf ("Skip signal %d handler %s\n", dbg->reason.signum, signame); goto repeat; } else { ut64 pc = r_debug_reg_get (dbg, "pc"); eprintf ("Stalled with an exception at 0x%08"PFMT64x"\n", pc); } } } } return ret; }
/* * wait for an event and start trying to figure out what to do with it. * * Returns R_DEBUG_REASON_* */ static RDebugReasonType r_debug_native_wait (RDebug *dbg, int pid) { int status = -1; RDebugReasonType reason = R_DEBUG_REASON_UNKNOWN; #if __WINDOWS__ && !__CYGWIN__ int mode = 0; reason = w32_dbg_wait (dbg, pid); if (reason == R_DEBUG_REASON_NEW_LIB) { mode = 'l'; } else if (reason == R_DEBUG_REASON_EXIT_LIB) { mode = 'u'; } else { mode = 0; } if (mode) { RDebugInfo *r = r_debug_native_info (dbg, ""); if (r && r->lib) { if (tracelib (dbg, mode=='l'? "load":"unload", r->lib)) reason = R_DEBUG_REASON_TRAP; } else { eprintf ("%soading unknown library.\n", mode?"L":"Unl"); } r_debug_info_free (r); } #else if (pid == -1) { eprintf ("r_debug_native_wait called with -1 pid!\n"); return R_DEBUG_REASON_ERROR; } #if __APPLE__ // eprintf ("No waitpid here :D\n"); reason = xnu_wait (dbg, pid); status = reason? 1: 0; #else // XXX: this is blocking, ^C will be ignored #ifdef WAIT_ON_ALL_CHILDREN //eprintf ("waiting on all children ...\n"); int ret = waitpid (-1, &status, WAITPID_FLAGS); #else //eprintf ("waiting on pid %d ...\n", pid); int ret = waitpid (pid, &status, WAITPID_FLAGS); #endif // WAIT_ON_ALL_CHILDREN if (ret == -1) { r_sys_perror ("waitpid"); return R_DEBUG_REASON_ERROR; } //eprintf ("r_debug_native_wait: status=%d (0x%x) (return=%d)\n", status, status, ret); #ifdef WAIT_ON_ALL_CHILDREN if (ret != pid) { reason = R_DEBUG_REASON_NEW_PID; eprintf ("switching to pid %d\n", ret); r_debug_select(dbg, ret, ret); } #endif // WAIT_ON_ALL_CHILDREN // TODO: switch status and handle reasons here #if __linux__ && defined(PT_GETEVENTMSG) reason = linux_ptrace_event (dbg, pid, status); #endif // __linux__ /* propagate errors */ if (reason == R_DEBUG_REASON_ERROR) { return reason; } /* we don't know what to do yet, let's try harder to figure it out. */ if (reason == R_DEBUG_REASON_UNKNOWN) { if (WIFEXITED (status)) { eprintf ("child exited with status %d\n", WEXITSTATUS (status)); reason = R_DEBUG_REASON_DEAD; } else if (WIFSIGNALED (status)) { eprintf ("child received signal %d\n", WTERMSIG (status)); reason = R_DEBUG_REASON_SIGNAL; } else if (WIFSTOPPED (status)) { if (WSTOPSIG (status) != SIGTRAP) { eprintf ("child stopped with signal %d\n", WSTOPSIG (status)); } /* this one might be good enough... */ dbg->reason.signum = WSTOPSIG (status); /* the ptrace documentation says GETSIGINFO is only necessary for * differentiating the various stops. * * this might modify dbg->reason.signum */ if (!r_debug_handle_signals (dbg)) return R_DEBUG_REASON_ERROR; reason = dbg->reason.type; } else if (WIFCONTINUED (status)) { eprintf ("child continued...\n"); reason = R_DEBUG_REASON_NONE; } else if (status == 1) { /* XXX(jjd): does this actually happen? */ eprintf ("EEK DEAD DEBUGEE!\n"); reason = R_DEBUG_REASON_DEAD; } else if (status == 0) { /* XXX(jjd): does this actually happen? */ eprintf ("STATUS=0?!?!?!?\n"); reason = R_DEBUG_REASON_DEAD; } else { if (ret != pid) { reason = R_DEBUG_REASON_NEW_PID; } else { /* ugh. still don't know :-/ */ eprintf ("CRAP. returning from wait without knowing why...\n"); } } } /* if we still don't know what to do, we have a problem... */ if (reason == R_DEBUG_REASON_UNKNOWN) { eprintf ("%s: no idea what happened... wtf?!?!\n", __func__); reason = R_DEBUG_REASON_ERROR; } #endif // __APPLE__ #endif // __WINDOWS__ && !__CYGWIN__ dbg->reason.tid = pid; dbg->reason.type = reason; return reason; }
R_API int r_core_file_reopen(RCore *core, const char *args, int perm, int loadbin) { int isdebug = r_config_get_i (core->config, "cfg.debug"); char *path; ut64 laddr = r_config_get_i (core->config, "bin.laddr"); RCoreFile *file = NULL; RCoreFile *ofile = core->file; RBinFile *bf = ofile ? r_bin_file_find_by_fd (core->bin, ofile->fd) : NULL; RIODesc *odesc = (core->io && ofile) ? r_io_desc_get (core->io, ofile->fd) : NULL; char *ofilepath = NULL, *obinfilepath = (bf && bf->file)? strdup (bf->file): NULL; int ret = false; ut64 origoff = core->offset; if (odesc) { if (odesc->referer) { ofilepath = odesc->referer; } else if (odesc->uri) { ofilepath = odesc->uri; } } if (r_sandbox_enable (0)) { eprintf ("Cannot reopen in sandbox\n"); free (obinfilepath); return false; } if (!core->file) { eprintf ("No file opened to reopen\n"); free (ofilepath); free (obinfilepath); return false; } int newpid = odesc? odesc->fd: -1; if (isdebug) { r_debug_kill (core->dbg, core->dbg->pid, core->dbg->tid, 9); // KILL perm = 7; } else { if (!perm) { perm = 4; //R_IO_READ; } } if (!ofilepath) { eprintf ("Unknown file path"); free (obinfilepath); return false; } // HACK: move last mapped address to higher place // XXX - why does this hack work? // when the new memory maps are created. path = strdup (ofilepath); free (obinfilepath); obinfilepath = strdup (ofilepath); // r_str_trim (path); file = r_core_file_open (core, path, perm, laddr); if (file) { bool had_rbin_info = false; if (ofile) { if (r_bin_file_delete (core->bin, ofile->fd)) { had_rbin_info = true; } } r_core_file_close (core, ofile); r_core_file_set_by_file (core, file); ofile = NULL; odesc = NULL; // core->file = file; eprintf ("File %s reopened in %s mode\n", path, (perm & R_IO_WRITE)? "read-write": "read-only"); if (loadbin && (loadbin == 2 || had_rbin_info)) { ut64 baddr = r_config_get_i (core->config, "bin.baddr"); ret = r_core_bin_load (core, obinfilepath, baddr); r_core_bin_update_arch_bits (core); if (!ret) { eprintf ("Error: Failed to reload rbin for: %s", path); } } if (core->bin->cur && core->io && r_io_desc_get (core->io, file->fd) && !loadbin) { //force here NULL because is causing uaf look this better in future XXX @alvarofe core->bin->cur = NULL; } // close old file } else if (ofile) { eprintf ("r_core_file_reopen: Cannot reopen file: %s with perms 0x%04x," " attempting to open read-only.\n", path, perm); // lower it down back //ofile = r_core_file_open (core, path, R_IO_READ, addr); r_core_file_set_by_file (core, ofile); } else { eprintf ("Cannot reopen\n"); } if (isdebug) { int newtid = newpid; // XXX - select the right backend if (core->file) { newpid = r_io_fd_get_pid (core->io, core->file->fd); newtid = r_io_fd_get_tid (core->io, core->file->fd); #if __linux__ core->dbg->main_pid = newpid; newtid = newpid; #endif #pragma message ("fix debugger-concept in core") #if __WINDOWS__ r_debug_select (core->dbg, newpid, newtid); core->dbg->reason.type = R_DEBUG_REASON_NONE; #endif } //reopen and attach r_core_setup_debugger (core, "native", true); r_debug_select (core->dbg, newpid, newtid); } if (core->file) { r_io_use_fd (core->io, core->file->fd); core->switch_file_view = 1; r_core_block_read (core); #if 0 else {