void erts_clear_mtrace_bif(Uint *pc) { BpDataTrace *bdt; ERTS_SMP_LC_ASSERT(erts_smp_is_system_blocked(0)); bdt = (BpDataTrace *) pc[-4]; if (bdt) { if (bdt->match_spec) { MatchSetUnref(bdt->match_spec); } Free(bdt); } pc[-4] = (Uint) NULL; }
void erts_set_mtrace_bif(Uint *pc, Binary *match_spec, Eterm tracer_pid) { BpDataTrace *bdt; ERTS_SMP_LC_ASSERT(erts_smp_is_system_blocked(0)); bdt = (BpDataTrace *) pc[-4]; if (bdt) { MatchSetUnref(bdt->match_spec); MatchSetRef(match_spec); bdt->match_spec = match_spec; bdt->tracer_pid = tracer_pid; } else { bdt = Alloc(sizeof(BpDataTrace)); BpInit((BpData *) bdt, 0); MatchSetRef(match_spec); bdt->match_spec = match_spec; bdt->tracer_pid = tracer_pid; pc[-4] = (Uint) bdt; } }
static void delete_export_references(Eterm module) { int i; ASSERT(is_atom(module)); for (i = 0; i < export_list_size(); i++) { Export *ep = export_list(i); if (ep != NULL && (ep->code[0] == module)) { if (ep->address == ep->code+3 && (ep->code[3] == (Eterm) em_apply_bif)) { continue; } ep->address = ep->code+3; ep->code[3] = (Uint) em_call_error_handler; ep->code[4] = 0; MatchSetUnref(ep->match_prog_set); ep->match_prog_set = NULL; } } }
static void delete_code(Module* modp) { ErtsCodeIndex code_ix = erts_staging_code_ix(); Eterm module = make_atom(modp->module); int i; for (i = 0; i < export_list_size(code_ix); i++) { Export *ep = export_list(i, code_ix); if (ep != NULL && (ep->code[0] == module)) { if (ep->addressv[code_ix] == ep->code+3) { if (ep->code[3] == (BeamInstr) em_apply_bif) { continue; } else if (ep->code[3] == (BeamInstr) em_call_traced_function) { ERTS_SMP_LC_ASSERT(erts_smp_thr_progress_is_blocking()); ASSERT(modp->curr.num_traced_exports > 0); --modp->curr.num_traced_exports; MatchSetUnref(ep->match_prog_set); ep->match_prog_set = NULL; } else ASSERT(ep->code[3] == (BeamInstr) em_call_error_handler || !erts_initialized); } ep->addressv[code_ix] = ep->code+3; ep->code[3] = (BeamInstr) em_call_error_handler; ep->code[4] = 0; ASSERT(ep->match_prog_set == NULL); } } ASSERT(modp->curr.num_breakpoints == 0); ASSERT(modp->curr.num_traced_exports == 0); modp->old = modp->curr; modp->curr.code = NULL; modp->curr.code_length = 0; modp->curr.catches = BEAM_CATCHES_NIL; modp->curr.nif = NULL; }
static void consolidate_bp_data(Module* modp, BeamInstr* pc, int local) { GenericBp* g = (GenericBp *) pc[-4]; GenericBpData* src; GenericBpData* dst; Uint flags; if (g == 0) { return; } src = &g->data[erts_active_bp_ix()]; dst = &g->data[erts_staging_bp_ix()]; /* * The contents of the staging area may be out of date. * Decrement all reference pointers. */ flags = dst->flags; if (flags & (ERTS_BPF_LOCAL_TRACE|ERTS_BPF_GLOBAL_TRACE)) { MatchSetUnref(dst->local_ms); } if (flags & ERTS_BPF_META_TRACE) { bp_meta_unref(dst->meta_tracer); MatchSetUnref(dst->meta_ms); } if (flags & ERTS_BPF_COUNT) { bp_count_unref(dst->count); } if (flags & ERTS_BPF_TIME_TRACE) { bp_time_unref(dst->time); } /* * If all flags are zero, deallocate all breakpoint data. */ flags = dst->flags = src->flags; if (flags == 0) { if (modp) { if (local) { modp->curr.num_breakpoints--; } else { modp->curr.num_traced_exports--; } ASSERT(modp->curr.num_breakpoints >= 0); ASSERT(modp->curr.num_traced_exports >= 0); ASSERT(*pc != (BeamInstr) BeamOp(op_i_generic_breakpoint)); } pc[-4] = 0; Free(g); return; } /* * Copy the active data to the staging area (making it ready * for the next time it will be used). */ if (flags & (ERTS_BPF_LOCAL_TRACE|ERTS_BPF_GLOBAL_TRACE)) { dst->local_ms = src->local_ms; MatchSetRef(dst->local_ms); } if (flags & ERTS_BPF_META_TRACE) { dst->meta_tracer = src->meta_tracer; erts_refc_inc(&dst->meta_tracer->refc, 1); dst->meta_ms = src->meta_ms; MatchSetRef(dst->meta_ms); } if (flags & ERTS_BPF_COUNT) { dst->count = src->count; erts_refc_inc(&dst->count->refc, 1); } if (flags & ERTS_BPF_TIME_TRACE) { dst->time = src->time; erts_refc_inc(&dst->time->refc, 1); ASSERT(dst->time->hash); } }
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; }