//-------------------------------------------------------------------------- // returns true-lowcnd was false, resumed the application // nb: recursive calls to this function are not handled in any special way! bool debmod_t::handle_lowcnd(lowcnd_t *lc, debug_event_t *event, int elc_flags) { if ( (debugger_flags & DBG_FLAG_CAN_CONT_BPT) == 0 ) { // difficult case: we have to reset pc, remove the bpt, single step, and resume the app QASSERT(616, !handling_lowcnds.has(lc->ea)); handling_lowcnds.push_back(lc->ea); int code; if ( (elc_flags & ELC_KEEP_EIP) == 0 ) { regval_t rv; rv._set_int(lc->ea); code = dbg_write_register(event->tid, pc_idx, &rv); if ( code <= 0 ) { handling_lowcnds.del(lc->ea); return false; } } code = dbg_freeze_threads_except(event->tid); if ( code > 0 ) { int bptlen = lc->type == BPT_SOFT ? lc->orgbytes.size() : lc->size; code = dbg_del_bpt(lc->type, lc->ea, lc->orgbytes.begin(), bptlen); if ( code > 0 ) { code = dbg_perform_single_step(event, lc->cmd); if ( code <= 0 ) dmsg("%a: failed to single step\n", event->ea); // may happen if ( dbg_add_bpt(lc->type, lc->ea, bptlen) <= 0 ) { // if this fails, it may be because the breakpoint is invalid // at this time so we should notify IDA it isn't available // any more code = 0; dwarning("%a: could not restore deleted bpt\n", lc->ea); // odd } } if ( dbg_thaw_threads_except(event->tid) <= 0 ) { dwarning("%d: could not resume suspended threads\n", event->tid); // odd code = 0; } } handling_lowcnds.del(lc->ea); if ( code <= 0 || event->eid != STEP ) return false; // did not resume } if ( (elc_flags & ELC_KEEP_SUSP) != 0 ) return true; return dbg_continue_after_event(event) > 0; }
//-------------------------------------------------------------------------- // returns true-lowcnd was false, resumed the application // nb: recursive calls to this function are not handled in any special way! bool debmod_t::handle_lowcnd(lowcnd_t *lc, debug_event_t *event) { if ( (debugger_flags & DBG_FLAG_CAN_CONT_BPT) == 0 ) { // difficult case: we have to reset pc, remove the bpt, single step, and resume the app handling_lowcnd = true; regval_t rv; rv._set_int(lc->ea); int code = dbg_write_register(event->tid, pc_idx, &rv); if ( code <= 0 ) { handling_lowcnd = false; return false; } code = dbg_freeze_threads_except(event->tid); if ( code > 0 ) { code = dbg_del_bpt(lc->type, lc->ea, lc->orgbytes.begin(), lc->orgbytes.size()); if ( code > 0 ) { code = dbg_perform_single_step(event, lc->cmd); if ( code <= 0 ) dmsg("%a: failed to single step\n", event->ea); // may happen if ( dbg_add_bpt(lc->type, lc->ea, lc->orgbytes.size()) <= 0 ) { code = 0; dwarning("%a: could not restore deleted bpt\n", lc->cmd.ea); // odd } } if ( dbg_thaw_threads_except(event->tid) <= 0 ) { dwarning("%d: could not resume suspended threads\n", event->tid); // odd code = 0; } } handling_lowcnd = false; if ( code <= 0 || event->eid != STEP ) return false; // did not resume } return dbg_continue_after_event(event); }
//-------------------------------------------------------------------------- // Cleanup after appcall() // The debugger module must keep the stack blob in the memory until this function // is called. It will be called by the kernel for each successful call_app_func() int idaapi debmod_t::dbg_cleanup_appcall(thid_t tid) { call_contexts_t &calls = appcalls[tid]; if ( calls.empty() ) return 0; // remove the return breakpoint call_context_t &ctx = calls.back(); if ( !preprocess_appcall_cleanup(tid, ctx) ) return 0; dbg_del_bpt(BPT_SOFT, ctx.ctrl_ea, bpt_code.begin(), bpt_code.size()); if ( ctx.regs_spoiled ) { if ( !write_registers(tid, 0, ctx.saved_regs.size(), ctx.saved_regs.begin()) ) { dmsg("Failed to restore registers!\n"); return 0; } } calls.pop(); return events.empty() ? 1 : 2; }
//-------------------------------------------------------------------------- int idaapi debmod_t::dbg_update_bpts( update_bpt_info_t *bpts, int nadd, int ndel) { // Write breakpoints to the process int cnt = 0; update_bpt_info_t *b; update_bpt_info_t *end = bpts + nadd; for ( b=bpts; b != end; b++ ) { int code = b->code; if ( code != BPT_OK ) continue; uchar len; char buf[32]; int nread = 0; ea_t ea = b->ea; if ( b->type == BPT_SOFT ) { len = bpt_code.size(); #ifdef __ARM__ if ( (ea & 1) != 0 ) // T bit is set, use a thumb breakpoint { ea--; len = 2; } #endif nread = len; if ( (debugger_flags & DBG_FLAG_CAN_CONT_BPT) == 0 ) { // we must save the original bytes before adding the bpt QASSERT(30017, sizeof(buf) >= len); if ( dbg_read_memory(ea, buf, len) <= 0 ) code = BPT_READ_ERROR; } } else { len = b->size; } if ( code == BPT_OK ) code = dbg_add_bpt(b->type, ea, len) ? BPT_OK : BPT_WRITE_ERROR; b->code = code; if ( code == BPT_OK ) { cnt++; if ( nread > 0 ) b->orgbytes = bytevec_t(buf, nread); } } // Delete breakpoints from the process. end += ndel; for ( ; b != end; b++ ) { b->code = BPT_OK; int len = b->type == BPT_SOFT ? b->orgbytes.size() : b->size; if ( dbg_del_bpt(b->type, b->ea, b->orgbytes.begin(), len) > 0 ) cnt++; else b->code = BPT_WRITE_ERROR; } return cnt; }
//-------------------------------------------------------------------------- int idaapi debmod_t::dbg_update_bpts( update_bpt_info_t *ubpts, int nadd, int ndel) { // Write breakpoints to the process int cnt = 0; update_bpt_info_t *b; update_bpt_info_t *end = ubpts + nadd; for ( b=ubpts; b != end; b++ ) { int code = b->code; if ( code != BPT_OK ) continue; // should be BPT_SKIP int len; uchar buf[32]; memset(buf, 0, sizeof(buf)); int nread = 0; ea_t ea = b->ea; if ( b->type == BPT_SOFT ) { len = bpt_code.size(); nread = read_bpt_orgbytes(&ea, &len, buf, sizeof(buf)); if ( nread < 0 ) code = BPT_READ_ERROR; } else { len = b->size; } if ( code == BPT_OK ) { switch ( dbg_add_bpt(b->type, ea, len) ) { case 2: code = BPT_PAGE_OK; break; case 1: code = BPT_OK; break; default: code = BPT_WRITE_ERROR; break; } } b->code = code; if ( code == BPT_OK ) { cnt++; if ( nread > 0 ) b->orgbytes = bytevec_t(buf, nread); } } // Delete breakpoints from the process. end += ndel; for ( ; b != end; b++ ) { b->code = BPT_OK; int len = b->type == BPT_SOFT ? b->orgbytes.size() : b->size; if ( dbg_del_bpt(b->type, b->ea, b->orgbytes.begin(), len) > 0 ) cnt++; else b->code = BPT_WRITE_ERROR; } return cnt; }