/* * SMP NOTE: Process p may have become exiting on return! */ BeamInstr erts_trace_break(Process *p, BeamInstr *pc, Eterm *args, Uint32 *ret_flags, Eterm *tracer_pid) { Eterm tpid1, tpid2; BpData **bds = (BpData **) (pc)[-4]; BpDataTrace *bdt = NULL; ASSERT(bds); ASSERT(pc[-5] == (BeamInstr) BeamOp(op_i_func_info_IaaI)); bdt = (BpDataTrace *) bds[bp_sched2ix_proc(p)]; ASSERT(bdt); bdt = (BpDataTrace *) bdt->next; ASSERT(bdt); ASSERT(ret_flags); ASSERT(tracer_pid); ErtsSmpBPLock(bdt); tpid1 = tpid2 = bdt->tracer_pid; ErtsSmpBPUnlock(bdt); *ret_flags = erts_call_trace(p, pc-3/*mfa*/, bdt->match_spec, args, 1, &tpid2); *tracer_pid = tpid2; if (tpid1 != tpid2) { ErtsSmpBPLock(bdt); bdt->tracer_pid = tpid2; ErtsSmpBPUnlock(bdt); } bds[bp_sched2ix_proc(p)] = (BpData *) bdt; return bdt->orig_instr; }
/* * SMP NOTE: Process p may have become exiting on return! */ Uint32 erts_bif_mtrace(Process *p, BeamInstr *pc, Eterm *args, int local, Eterm *tracer_pid) { BpData **bds = (BpData **) (pc)[-4]; BpDataTrace *bdt = NULL; ASSERT(tracer_pid); if (bds) { Eterm tpid1, tpid2; Uint32 flags; bdt = (BpDataTrace *)bds[bp_sched2ix_proc(p)]; ErtsSmpBPLock(bdt); tpid1 = tpid2 = bdt->tracer_pid; ErtsSmpBPUnlock(bdt); flags = erts_call_trace(p, pc-3/*mfa*/, bdt->match_spec, args, local, &tpid2); *tracer_pid = tpid2; if (tpid1 != tpid2) { ErtsSmpBPLock(bdt); bdt->tracer_pid = tpid2; ErtsSmpBPUnlock(bdt); } return flags; } *tracer_pid = NIL; return 0; }
/* * SMP NOTE: Process p may have become exiting on return! */ Uint32 erts_bif_mtrace(Process *p, Uint *pc, Eterm *args, int local, Eterm *tracer_pid) { BpDataTrace *bdt = (BpDataTrace *) pc[-4]; ASSERT(tracer_pid); if (bdt) { Eterm tpid1, tpid2; Uint32 flags; ErtsSmpBPLock(bdt); tpid1 = tpid2 = bdt->tracer_pid; ErtsSmpBPUnlock(bdt); flags = erts_call_trace(p, pc-3/*mfa*/, bdt->match_spec, args, local, &tpid2); *tracer_pid = tpid2; if (tpid1 != tpid2) { ErtsSmpBPLock(bdt); bdt->tracer_pid = tpid2; ErtsSmpBPUnlock(bdt); } return flags; } *tracer_pid = NIL; return 0; }
/* * SMP NOTE: Process p may have become exiting on return! */ Uint erts_trace_break(Process *p, Uint *pc, Eterm *args, Uint32 *ret_flags, Eterm *tracer_pid) { Eterm tpid1, tpid2; BpDataTrace *bdt = (BpDataTrace *) pc[-4]; ASSERT(pc[-5] == (Uint) BeamOp(op_i_func_info_IaaI)); ASSERT(bdt); bdt = (BpDataTrace *) bdt->next; ASSERT(bdt); ASSERT(ret_flags); ASSERT(tracer_pid); ErtsSmpBPLock(bdt); tpid1 = tpid2 = bdt->tracer_pid; ErtsSmpBPUnlock(bdt); *ret_flags = erts_call_trace(p, pc-3/*mfa*/, bdt->match_spec, args, 1, &tpid2); *tracer_pid = tpid2; if (tpid1 != tpid2) { ErtsSmpBPLock(bdt); bdt->tracer_pid = tpid2; ErtsSmpBPUnlock(bdt); } pc[-4] = (Uint) bdt; return bdt->orig_instr; }
int erts_is_count_break(Uint *pc, Sint *count_ret) { BpDataCount *bdc = (BpDataCount *) is_break(pc, (Uint) BeamOp(op_i_count_breakpoint)); if (bdc) { if (count_ret) { ErtsSmpBPLock(bdc); *count_ret = bdc->count; ErtsSmpBPUnlock(bdc); } return !0; } return 0; }
int erts_is_mtrace_bif(Uint *pc, Binary **match_spec_ret, Eterm *tracer_pid_ret) { BpDataTrace *bdt = (BpDataTrace *) pc[-4]; if (bdt) { if (match_spec_ret) { *match_spec_ret = bdt->match_spec; } if (tracer_pid_ret) { ErtsSmpBPLock(bdt); *tracer_pid_ret = bdt->tracer_pid; ErtsSmpBPUnlock(bdt); } return !0; } return 0; }
int erts_is_mtrace_break(BeamInstr *pc, Binary **match_spec_ret, Eterm *tracer_pid_ret) { BpDataTrace *bdt = (BpDataTrace *) is_break(pc, (BeamInstr) BeamOp(op_i_mtrace_breakpoint)); if (bdt) { if (match_spec_ret) { *match_spec_ret = bdt->match_spec; } if (tracer_pid_ret) { ErtsSmpBPLock(bdt); *tracer_pid_ret = bdt->tracer_pid; ErtsSmpBPUnlock(bdt); } return !0; } return 0; }
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; }