/* Add a breakpoint without using a script command */ int e2dbg_breakpoint_add(eresi_Addr addr) { int err; char buf[BUFSIZ]; char *name; elfsh_SAddr off; elfshobj_t *file; PROFILER_IN(__FILE__, __FUNCTION__, __LINE__); /* Resolve source file */ file = e2dbg_get_parent_object(addr); if (file == NULL) PROFILER_ERR(__FILE__, __FUNCTION__, __LINE__, "Cannot resolve parent file for bp", -1); /* Resolve breakpoint address */ name = revm_resolve(file, addr, &off); if (off) snprintf(buf, BUFSIZ, "<%s + " DFMT ">", name, off); else snprintf(buf, BUFSIZ, "<%s>", name); /* Really put the breakpoint */ err = elfsh_bp_add(&e2dbgworld.bp, file, buf, addr); if (err < 0) PROFILER_ERR(__FILE__, __FUNCTION__, __LINE__, "Cannot add breakpoint", -1); PROFILER_ROUT(__FILE__, __FUNCTION__, __LINE__, 0); }
/** * The Real routine that handles each thread-specific breakpoint state machine. * * breakpoint case: * * 0-1: restore old instr, enable step, set bp addr in ->past, reset pc to orig bp addr * 1-2: do nothing (just executed instr) * 2-3: reinstall, resetstep, thread_contall, curthread->was_step = 0, * stoppedthread->count = NONE; e2dbgworld.curbp = NULL; stoppedthread = RUNNING * * stepping case: * * 0-1: print current instr; reinstall * stoppedthread->state = BREAKING; thread_contall; * was_step = 0; count = NONE; curbp = NULL; stoppedthread->state = RUNNING */ void e2dbg_breakpoint_process() { char buf[32]; elfshbp_t *bp; int prot; char *name; elfsh_SAddr off; int ret; asm_instr ptr; char *s; eresi_Addr *pc; eresi_Addr savedpc; u_int bpsz; elfshsect_t *sect; elfshobj_t *parent; elfsh_Sym *sym; #if __DEBUG_BP__ fprintf(stderr, " [D] Entering breakpoint handler\n"); #endif /* Set all registers as variables and get PC */ e2dbg_user_hooks_install(); e2dbg_getregs(); pc = e2dbg_getpc(); parent = e2dbg_get_parent_object((eresi_Addr) *pc); bpsz = elfsh_get_breaksize(parent); /* Print variables and registers on breakpoints */ //if (!world.state.revm_quiet) //cmd_vlist(); /* Try to find the breakpoint at current instruction pointer */ #if __DEBUG_BP__ fprintf(stderr, " [D] At PC = %08X : Trying to find breakpoint at addr %08X (bpsize = %u)\n", *pc, *pc - bpsz, bpsz); #endif snprintf(buf, sizeof(buf), XFMT, *pc - bpsz); bp = hash_get(&e2dbgworld.bp, buf); #if __DEBUG_BP__ if (bp) fprintf(stderr, " [D] Saved instruction BYTE = %02X and PC-BPSZ BYTE = %02X \n", bp->savedinstr[0], *((u_char *) *pc - bpsz)); else fprintf(stderr, " [D] No BP found at %08X ! \n", *pc); #endif /* Case of processing breakpoint, or if we are single-stepping */ if (!bp || (bp->savedinstr[0] == *((u_char *) *pc - bpsz))) { /* We are single-stepping, display the instruction at $pc */ if (e2dbgworld.stoppedthread->step) { #if __DEBUG_BP__ fprintf(stderr, " [D] Single-stepping -IS- enabled \n"); #endif ret = asm_read_instr(&ptr, (u_char *) *pc, 16, world.curjob->proc); if (!ret) ret++; sect = elfsh_get_parent_section(parent, (eresi_Addr) *pc, NULL); name = revm_resolve(parent, (eresi_Addr) *pc, &off); off = 0; sym = elfsh_get_metasym_by_value(parent, (eresi_Addr) *pc, &off, ELFSH_LOWSYM); #if __DEBUG_BP__ fprintf(stderr, " [D] Found parent = %08X (%s) in step (name = %s, parentsect = %s) off = %u\n", (eresi_Addr) parent, parent->name, name, sect->name, off); #endif revm_instr_display(-1, *pc, 0, 20, name, off, (char *) *pc); e2dbg_display(e2dbgworld.displaycmd, e2dbgworld.displaynbr); if (!e2dbgworld.stoppedthread->trace) e2dbg_entry(NULL); else e2dbg_watch(); e2dbg_breakpoint_reinstall(); return; } #if __DEBUG_BP__ fprintf(stderr, " [D] Single-stepping is -NOT- enabled \n"); #endif /* Here starts the real stuff ** ** count == E2DBG_BREAK_EXEC -> execute restored instruction ** count == E2DBG_BREAK_FINISHED -> restore breakpoint ** count > E2DBG_BREAK_MAX -> e2dbg is getting debugged by a third party debugger */ e2dbgworld.stoppedthread->count++; #if __DEBUG_BP__ fprintf(stderr, " [C] Count %u -> %u for thread ID %u \n", e2dbgworld.stoppedthread->count - 1, e2dbgworld.stoppedthread->count, ((unsigned int) e2dbgworld.stoppedthread->tid)); #endif /* execute the previously restored instruction */ if (e2dbgworld.stoppedthread->count == E2DBG_BREAK_EXEC) { #if __DEBUG_BP__ printf(" [D] At PC = 0x%X : Debuggee executed restored instruction \n", *pc); #endif return; } /* Suggested by andrewg, useful when debugging valgrind */ if (e2dbgworld.stoppedthread->count > E2DBG_BREAK_MAX) { printf(".::- E2DBG WARNING -::.\n" "Breakpoint triggered at location " AFMT " which we don't know about.\n\n" "This may be an anti-debug trick or the program may be inside another\n" "debugger. Exiting (DEBUG: count = " UFMT ", step is off)\n\n", *pc - bpsz, e2dbgworld.stoppedthread->count); return; } e2dbg_breakpoint_reinstall(); /* remove trace flag */ #if __DEBUG_BP__ fprintf(stderr, " [D] At PC = " AFMT " Resetting STEP mode\n", *pc); #endif e2dbg_resetstep(); return; } /* Case of newly hit breakpoint */ else { name = revm_resolve(parent, (eresi_Addr) *pc - bpsz, &off); s = (e2dbg_is_watchpoint(bp) ? "Watch" : "Break"); #if __DEBUG_BP__ fprintf(stderr, " [C] Count set to 1 (HIT) for thread ID %u \n", (unsigned int) e2dbgworld.stoppedthread->tid); #endif if (off) printf(" [*] %spoint found at " XFMT " <%s + " DFMT "> in thread %u \n\n", s, *pc - bpsz, name, off, (unsigned int) e2dbgworld.stoppedthread->tid); else printf(" [*] %spoint found at " XFMT " <%s> in thread %u \n\n", s, *pc - bpsz, name, (unsigned int) e2dbgworld.stoppedthread->tid); revm_doswitch(parent->id); mjr_set_current_context(&world.mjr_session, parent->name); *pc -= bpsz; prot = elfsh_munprotect(bp->obj, *pc, bpsz); memcpy((u_char *) *pc, bp->savedinstr, bpsz); elfsh_mprotect(bp->obj, *pc, bpsz, prot); e2dbg_setstep(); #if __DEBUG_BP__ fprintf(stderr, " [D] Setting Step mode \n"); #endif e2dbgworld.stoppedthread->past = *pc; e2dbgworld.stoppedthread->count = E2DBG_BREAK_HIT; e2dbgworld.curbp = bp; bp->tid = (uint32_t) e2dbgworld.stoppedthread->tid; #if __DEBUG_BP__ fprintf(stderr, " [D] Reset break \n"); #endif if (bp->cmdnbr) e2dbg_display(bp->cmd, bp->cmdnbr); else e2dbg_display(e2dbgworld.displaycmd, e2dbgworld.displaynbr); #if __DEBUG_BP__ fprintf(stderr, " [D] After BP display \n"); #endif #if __DEBUG_BP__ fprintf(stderr, " [D] PC before entry is addr 0x%X \n", *pc); #endif savedpc = *pc; e2dbg_entry(NULL); *pc = savedpc; #if __DEBUG_BP__ fprintf(stderr, " [D] At PC = 0x%X : returned from BP handler with step enabled\n", *pc); #endif } }