/* ** Searches (linear forward) the breakpoint ring for a specified opcode ** and returns a pointer to the breakpoint data structure or NULL if ** not found. If the specified opcode is 0, the last breakpoint is ** returned. The program counter must point to the first executable ** (breakpoint) instruction of the function. */ static BpData *is_break(Uint *pc, Uint break_op) { ASSERT(pc[-5] == (Uint) BeamOp(op_i_func_info_IaaI)); if (! erts_is_native_break(pc)) { BpData *bd = (BpData *) pc[-4]; if (break_op == 0) { return bd; } if (*pc == break_op) { ASSERT(bd); return bd->next; } if (! bd){ return NULL; } bd = bd->next; while (bd != (BpData *) pc[-4]) { ASSERT(bd); if (bd->orig_instr == break_op) { bd = bd->next; ASSERT(bd); return bd; } else { bd = bd->next; } } } return NULL; }
int erts_clear_module_break(Module *modp) { BeamCodeHeader* code_hdr; Uint n; Uint i; ERTS_SMP_LC_ASSERT(erts_smp_thr_progress_is_blocking()); ASSERT(modp); code_hdr = modp->curr.code_hdr; if (!code_hdr) { return 0; } n = (Uint)(UWord) code_hdr->num_functions; for (i = 0; i < n; ++i) { BeamInstr* pc; pc = code_hdr->functions[i] + 5; if (erts_is_native_break(pc)) { continue; } clear_function_break(pc, ERTS_BPF_ALL); } erts_commit_staged_bp(); for (i = 0; i < n; ++i) { BeamInstr* pc; pc = code_hdr->functions[i] + 5; if (erts_is_native_break(pc)) { continue; } uninstall_breakpoint(pc); consolidate_bp_data(modp, pc, 1); ASSERT(pc[-4] == 0); } return n; }
int erts_clear_module_break(Module *modp) { BeamInstr** code_base; Uint n; Uint i; ERTS_SMP_LC_ASSERT(erts_smp_thr_progress_is_blocking()); ASSERT(modp); code_base = (BeamInstr **) modp->curr.code; if (code_base == NULL) { return 0; } n = (Uint)(UWord) code_base[MI_NUM_FUNCTIONS]; for (i = 0; i < n; ++i) { BeamInstr* pc; pc = code_base[MI_FUNCTIONS+i] + 5; if (erts_is_native_break(pc)) { continue; } clear_function_break(pc, ERTS_BPF_ALL); } erts_commit_staged_bp(); for (i = 0; i < n; ++i) { BeamInstr* pc; pc = code_base[MI_FUNCTIONS+i] + 5; if (erts_is_native_break(pc)) { continue; } uninstall_breakpoint(pc); consolidate_bp_data(modp, pc, 1); ASSERT(pc[-4] == 0); } return n; }
void erts_bp_match_export(BpFunctions* f, Eterm mfa[3], int specified) { ErtsCodeIndex code_ix = erts_active_code_ix(); int i; int num_exps = export_list_size(code_ix); int ne; f->matching = (BpFunction *) Alloc(num_exps*sizeof(BpFunction)); ne = 0; for (i = 0; i < num_exps; i++) { Export* ep = export_list(i, code_ix); BeamInstr* pc; int j; for (j = 0; j < specified && mfa[j] == ep->code[j]; j++) { /* Empty loop body */ } if (j < specified) { continue; } pc = ep->code+3; if (ep->addressv[code_ix] == pc) { if ((*pc == (BeamInstr) em_apply_bif || *pc == (BeamInstr) em_call_error_handler)) { continue; } ASSERT(*pc == (BeamInstr) BeamOp(op_i_generic_breakpoint)); } else if (erts_is_native_break(ep->addressv[code_ix])) { continue; } f->matching[ne].pc = pc; f->matching[ne].mod = erts_get_module(ep->code[0], code_ix); ne++; } f->matched = ne; }
void erts_bp_match_functions(BpFunctions* f, Eterm mfa[3], int specified) { ErtsCodeIndex code_ix = erts_active_code_ix(); Uint max_funcs = 0; int current; int max_modules = module_code_size(code_ix); int num_modules = 0; Module* modp; Module** module; Uint i; module = (Module **) Alloc(max_modules*sizeof(Module *)); num_modules = 0; for (current = 0; current < max_modules; current++) { modp = module_code(current, code_ix); if (modp->curr.code_hdr) { max_funcs += modp->curr.code_hdr->num_functions; module[num_modules++] = modp; } } f->matching = (BpFunction *) Alloc(max_funcs*sizeof(BpFunction)); i = 0; for (current = 0; current < num_modules; current++) { BeamCodeHeader* code_hdr = module[current]->curr.code_hdr; BeamInstr* code; Uint num_functions = (Uint)(UWord) code_hdr->num_functions; Uint fi; if (specified > 0) { if (mfa[0] != make_atom(module[current]->module)) { /* Wrong module name */ continue; } } for (fi = 0; fi < num_functions; fi++) { BeamInstr* pc; int wi; code = code_hdr->functions[fi]; ASSERT(code[0] == (BeamInstr) BeamOp(op_i_func_info_IaaI)); pc = code+5; if (erts_is_native_break(pc)) { continue; } if (is_nil(code[3])) { /* Ignore BIF stub */ continue; } for (wi = 0; wi < specified && (Eterm) code[2+wi] == mfa[wi]; wi++) { /* Empty loop body */ } if (wi == specified) { /* Store match */ f->matching[i].pc = pc; f->matching[i].mod = module[current]; i++; } } } f->matched = i; Free(module); }
static int clear_function_break(Module *m, Uint *pc, Uint break_op) { BpData *bd; Uint **code_base = (Uint **)m->code; ASSERT(code_base); ASSERT(code_base <= (Uint **)pc); ASSERT((Uint **)pc < code_base + (m->code_length/sizeof(Uint *))); /* * Currently no trace support for native code. */ if (erts_is_native_break(pc)) { return 0; } while ( (bd = is_break(pc, break_op))) { /* Remove all breakpoints of this type. * There should be only one of each type, * but break_op may be 0 which matches any type. */ Uint op; BpData **r = (BpData **) (pc-4); ASSERT(*r); /* Find opcode for this breakpoint */ if (break_op) { op = break_op; } else { if (bd == (*r)->next) { /* First breakpoint in ring */ op = *pc; } else { op = bd->prev->orig_instr; } } if (BpSingleton(bd)) { ASSERT(*r == bd); /* Only one breakpoint to remove */ *r = NULL; *pc = bd->orig_instr; } else { BpData *bd_prev = bd->prev; BpSpliceNext(bd, bd_prev); ASSERT(BpSingleton(bd)); if (bd == *r) { /* We removed the last breakpoint in the ring */ *r = bd_prev; bd_prev->orig_instr = bd->orig_instr; } else if (bd_prev == *r) { /* We removed the first breakpoint in the ring */ *pc = bd->orig_instr; } else { bd_prev->orig_instr = bd->orig_instr; } } if (op == (Uint) BeamOp(op_i_trace_breakpoint) || op == (Uint) BeamOp(op_i_mtrace_breakpoint)) { BpDataTrace *bdt = (BpDataTrace *) bd; MatchSetUnref(bdt->match_spec); } Free(bd); ASSERT(((Uint) code_base[MI_NUM_BREAKPOINTS]) > 0); --(*(Uint*)&code_base[MI_NUM_BREAKPOINTS]); } return 1; }
static int set_function_break(Module *modp, Uint *pc, Binary *match_spec, Uint break_op, enum erts_break_op count_op, Eterm tracer_pid) { BpData *bd, **r; size_t size; Uint **code_base = (Uint **)modp->code; ASSERT(code_base); ASSERT(code_base <= (Uint **)pc); ASSERT((Uint **)pc < code_base + (modp->code_length/sizeof(Uint *))); /* * Currently no trace support for native code. */ if (erts_is_native_break(pc)) { return 0; } /* Do not allow two breakpoints of the same kind */ if ( (bd = is_break(pc, break_op))) { if (break_op == (Uint) BeamOp(op_i_trace_breakpoint) || break_op == (Uint) BeamOp(op_i_mtrace_breakpoint)) { BpDataTrace *bdt = (BpDataTrace *) bd; Binary *old_match_spec; /* Update match spec and tracer */ MatchSetRef(match_spec); ErtsSmpBPLock(bdt); old_match_spec = bdt->match_spec; bdt->match_spec = match_spec; bdt->tracer_pid = tracer_pid; ErtsSmpBPUnlock(bdt); MatchSetUnref(old_match_spec); } else { ASSERT(! match_spec); ASSERT(is_nil(tracer_pid)); if (break_op == (Uint) BeamOp(op_i_count_breakpoint)) { BpDataCount *bdc = (BpDataCount *) bd; ErtsSmpBPLock(bdc); if (count_op == erts_break_stop) { if (bdc->count >= 0) { bdc->count = -bdc->count-1; /* Stop call counter */ } } else { bdc->count = 0; /* Reset call counter */ } ErtsSmpBPUnlock(bdc); } else { ASSERT (! count_op); } } return 1; } if (break_op == (Uint) BeamOp(op_i_trace_breakpoint) || break_op == (Uint) BeamOp(op_i_mtrace_breakpoint)) { size = sizeof(BpDataTrace); } else { ASSERT(! match_spec); ASSERT(is_nil(tracer_pid)); if (break_op == (Uint) BeamOp(op_i_count_breakpoint)) { if (count_op == erts_break_reset || count_op == erts_break_stop) { /* Do not insert a new breakpoint */ return 1; } size = sizeof(BpDataCount); } else { ASSERT(! count_op); ASSERT(break_op == (Uint) BeamOp(op_i_debug_breakpoint)); size = sizeof(BpDataDebug); } } r = (BpData **) (pc-4); if (! *r) { ASSERT(*pc != (Uint) BeamOp(op_i_trace_breakpoint)); ASSERT(*pc != (Uint) BeamOp(op_i_mtrace_breakpoint)); ASSERT(*pc != (Uint) BeamOp(op_i_debug_breakpoint)); ASSERT(*pc != (Uint) BeamOp(op_i_count_breakpoint)); /* First breakpoint; create singleton ring */ bd = Alloc(size); BpInit(bd, *pc); *pc = break_op; *r = bd; } else { ASSERT(*pc == (Uint) BeamOp(op_i_trace_breakpoint) || *pc == (Uint) BeamOp(op_i_mtrace_breakpoint) || *pc == (Uint) BeamOp(op_i_debug_breakpoint) || *pc == (Uint) BeamOp(op_i_count_breakpoint)); if (*pc == (Uint) BeamOp(op_i_debug_breakpoint)) { /* Debug bp must be last, so if it is also first; * it must be singleton. */ ASSERT(BpSingleton(*r)); /* Insert new bp first in the ring, i.e second to last. */ bd = Alloc(size); BpInitAndSpliceNext(bd, *pc, *r); *pc = break_op; } else if ((*r)->prev->orig_instr == (Uint) BeamOp(op_i_debug_breakpoint)) { /* Debug bp last in the ring; insert new second to last. */ bd = Alloc(size); BpInitAndSplicePrev(bd, (*r)->prev->orig_instr, *r); (*r)->prev->orig_instr = break_op; } else { /* Just insert last in the ring */ bd = Alloc(size); BpInitAndSpliceNext(bd, (*r)->orig_instr, *r); (*r)->orig_instr = break_op; *r = bd; } } /* Init the bp type specific data */ if (break_op == (Uint) BeamOp(op_i_trace_breakpoint) || break_op == (Uint) BeamOp(op_i_mtrace_breakpoint)) { BpDataTrace *bdt = (BpDataTrace *) bd; MatchSetRef(match_spec); bdt->match_spec = match_spec; bdt->tracer_pid = tracer_pid; } else if (break_op == (Uint) BeamOp(op_i_count_breakpoint)) { BpDataCount *bdc = (BpDataCount *) bd; bdc->count = 0; } ++(*(Uint*)&code_base[MI_NUM_BREAKPOINTS]); return 1; }