diff options
Diffstat (limited to 'erts/emulator/beam/beam_bp.c')
-rw-r--r-- | erts/emulator/beam/beam_bp.c | 325 |
1 files changed, 210 insertions, 115 deletions
diff --git a/erts/emulator/beam/beam_bp.c b/erts/emulator/beam/beam_bp.c index 2142830ae8..7f105ce7c4 100644 --- a/erts/emulator/beam/beam_bp.c +++ b/erts/emulator/beam/beam_bp.c @@ -1,7 +1,7 @@ /* * %CopyrightBegin% * - * Copyright Ericsson AB 2000-2020. All Rights Reserved. + * Copyright Ericsson AB 2000-2023. All Rights Reserved. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -123,7 +123,8 @@ static void bp_meta_unref(BpMetaTracer *bmt); static void bp_count_unref(BpCount *bcp); static void bp_time_unref(BpDataTime *bdt); static void consolidate_bp_data(Module *modp, ErtsCodeInfo *ci, int local); -static void uninstall_breakpoint(ErtsCodeInfo *ci); +static void uninstall_breakpoint(ErtsCodeInfo *ci_rw, + const ErtsCodeInfo *ci_exec); /* bp_hash */ #define BP_TIME_ADD(pi0, pi1) \ @@ -188,31 +189,33 @@ erts_bp_match_functions(BpFunctions* f, ErtsCodeMFA *mfa, int specified) } for (fi = 0; fi < num_functions; fi++) { - ErtsCodeInfo* ci; + const ErtsCodeInfo* ci_exec; + ErtsCodeInfo* ci_rw; void *w_ptr; - w_ptr = erts_writable_code_ptr(&module[current]->curr, - code_hdr->functions[fi]); - ci = (ErtsCodeInfo*)w_ptr; + ci_exec = code_hdr->functions[fi]; + w_ptr = erts_writable_code_ptr(&module[current]->curr, ci_exec); + ci_rw = (ErtsCodeInfo*)w_ptr; #ifndef BEAMASM - ASSERT(BeamIsOpCode(ci->op, op_i_func_info_IaaI)); + ASSERT(BeamIsOpCode(ci_rw->u.op, op_i_func_info_IaaI)); #endif switch (specified) { case 3: - if (ci->mfa.arity != mfa->arity) + if (ci_rw->mfa.arity != mfa->arity) continue; case 2: - if (ci->mfa.function != mfa->function) + if (ci_rw->mfa.function != mfa->function) continue; case 1: - if (ci->mfa.module != mfa->module) + if (ci_rw->mfa.module != mfa->module) continue; case 0: break; } /* Store match */ - f->matching[i].ci = ci; + f->matching[i].ci_exec = ci_exec; + f->matching[i].ci_rw = ci_rw; f->matching[i].mod = module[current]; i++; } @@ -260,12 +263,13 @@ erts_bp_match_export(BpFunctions* f, ErtsCodeMFA *mfa, int specified) ASSERT(BeamIsOpCode(ep->trampoline.common.op, op_i_generic_breakpoint)); } - f->matching[ne].ci = &ep->info; - f->matching[ne].mod = erts_get_module(ep->info.mfa.module, code_ix); - - ne++; + f->matching[ne].ci_exec = &ep->info; + f->matching[ne].ci_rw = &ep->info; + f->matching[ne].mod = erts_get_module(ep->info.mfa.module, code_ix); + ne++; } + f->matched = ne; } @@ -288,14 +292,14 @@ erts_consolidate_bp_data(BpFunctions* f, int local) ERTS_LC_ASSERT(erts_has_code_write_permission()); for (i = 0; i < n; i++) { - consolidate_bp_data(fs[i].mod, fs[i].ci, local); + consolidate_bp_data(fs[i].mod, fs[i].ci_rw, local); } } static void -consolidate_bp_data(Module* modp, ErtsCodeInfo *ci, int local) +consolidate_bp_data(Module* modp, ErtsCodeInfo *ci_rw, int local) { - GenericBp* g = ci->u.gen_bp; + GenericBp* g = ci_rw->gen_bp; GenericBpData* src; GenericBpData* dst; Uint flags; @@ -343,14 +347,15 @@ consolidate_bp_data(Module* modp, ErtsCodeInfo *ci, int local) ASSERT(modp->curr.num_traced_exports >= 0); #if !defined(BEAMASM) && defined(DEBUG) { - BeamInstr instr = *(const BeamInstr*)erts_codeinfo_to_code(ci); + BeamInstr instr = *(const BeamInstr*)erts_codeinfo_to_code(ci_rw); ASSERT(!BeamIsOpCode(instr, op_i_generic_breakpoint)); } #endif - } - ci->u.gen_bp = NULL; - Free(g); - return; + } + + ci_rw->gen_bp = NULL; + Free(g); + return; } /* @@ -396,11 +401,12 @@ erts_install_breakpoints(BpFunctions* f) Uint n = f->matched; for (i = 0; i < n; i++) { - ErtsCodeInfo* ci = f->matching[i].ci; - GenericBp* g = ci->u.gen_bp; - Module* modp = f->matching[i].mod; + const ErtsCodeInfo *ci_exec = f->matching[i].ci_exec; + ErtsCodeInfo *ci_rw = f->matching[i].ci_rw; + GenericBp *g = ci_rw->gen_bp; + Module *modp = f->matching[i].mod; #ifdef BEAMASM - if ((erts_asm_bp_get_flags(ci) & ERTS_ASM_BP_FLAG_BP) == 0 && g) { + if ((erts_asm_bp_get_flags(ci_exec) & ERTS_ASM_BP_FLAG_BP) == 0 && g) { /* * The breakpoint must be disabled in the active data * (it will enabled later by switching bp indices), @@ -409,12 +415,16 @@ erts_install_breakpoints(BpFunctions* f) ASSERT(g->data[erts_active_bp_ix()].flags == 0); ASSERT(g->data[erts_staging_bp_ix()].flags != 0); - erts_asm_bp_set_flag(ci, ERTS_ASM_BP_FLAG_BP); + erts_asm_bp_set_flag(ci_rw, ci_exec, ERTS_ASM_BP_FLAG_BP); modp->curr.num_breakpoints++; } #else - BeamInstr volatile *pc = (BeamInstr*)erts_codeinfo_to_code(ci); + BeamInstr volatile *pc = (BeamInstr*)erts_codeinfo_to_code(ci_rw); BeamInstr instr = *pc; + + ASSERT(ci_exec == ci_rw); + (void)ci_exec; + if (!BeamIsOpCode(instr, op_i_generic_breakpoint) && g) { BeamInstr br = BeamOpCodeAddr(op_i_generic_breakpoint); @@ -452,30 +462,33 @@ erts_uninstall_breakpoints(BpFunctions* f) Uint n = f->matched; for (i = 0; i < n; i++) { - uninstall_breakpoint(f->matching[i].ci); + uninstall_breakpoint(f->matching[i].ci_rw, f->matching[i].ci_exec); } } #ifdef BEAMASM static void -uninstall_breakpoint(ErtsCodeInfo *ci) +uninstall_breakpoint(ErtsCodeInfo *ci_rw, const ErtsCodeInfo *ci_exec) { - if (erts_asm_bp_get_flags(ci) & ERTS_ASM_BP_FLAG_BP) { - GenericBp* g = ci->u.gen_bp; + if (erts_asm_bp_get_flags(ci_rw) & ERTS_ASM_BP_FLAG_BP) { + GenericBp* g = ci_rw->gen_bp; if (g->data[erts_active_bp_ix()].flags == 0) { - erts_asm_bp_unset_flag(ci, ERTS_ASM_BP_FLAG_BP); + erts_asm_bp_unset_flag(ci_rw, ci_exec, ERTS_ASM_BP_FLAG_BP); } } } #else static void -uninstall_breakpoint(ErtsCodeInfo *ci) +uninstall_breakpoint(ErtsCodeInfo *ci_rw, const ErtsCodeInfo *ci_exec) { - BeamInstr *pc = (BeamInstr*)erts_codeinfo_to_code(ci); + BeamInstr *pc = (BeamInstr*)erts_codeinfo_to_code(ci_rw); + + ASSERT(ci_rw == ci_exec); + (void)ci_exec; if (BeamIsOpCode(*pc, op_i_generic_breakpoint)) { - GenericBp* g = ci->u.gen_bp; + GenericBp* g = ci_rw->gen_bp; if (g->data[erts_active_bp_ix()].flags == 0) { /* @@ -539,7 +552,7 @@ erts_clear_trace_break(BpFunctions* f) void erts_clear_export_trace(ErtsCodeInfo *ci, int local) { - GenericBp* g = ci->u.gen_bp; + GenericBp* g = ci->gen_bp; if (g) { Uint flags = local ? ERTS_BPF_LOCAL_TRACE : ERTS_BPF_GLOBAL_TRACE; @@ -574,7 +587,7 @@ erts_clear_time_break(BpFunctions* f) { clear_break(f, ERTS_BPF_TIME_TRACE|ERTS_BPF_TIME_TRACE_ACTIVE); } - + void erts_clear_all_breaks(BpFunctions* f) { @@ -605,16 +618,18 @@ erts_clear_module_break(Module *modp) { erts_commit_staged_bp(); for (i = 0; i < n; ++i) { - ErtsCodeInfo* ci; + const ErtsCodeInfo *ci_exec; + ErtsCodeInfo *ci_rw; void *w_ptr; - w_ptr = erts_writable_code_ptr(&modp->curr, - code_hdr->functions[i]); - ci = (ErtsCodeInfo*)w_ptr; + ci_exec = code_hdr->functions[i]; + w_ptr = erts_writable_code_ptr(&modp->curr, ci_exec); + ci_rw = (ErtsCodeInfo*)w_ptr; + + uninstall_breakpoint(ci_rw, ci_exec); + consolidate_bp_data(modp, ci_rw, 1); - uninstall_breakpoint(ci); - consolidate_bp_data(modp, ci, 1); - ASSERT(ci->u.gen_bp == NULL); + ASSERT(ci_rw->gen_bp == NULL); } return n; @@ -639,7 +654,7 @@ erts_clear_export_break(Module* modp, Export *ep) erts_commit_staged_bp(); consolidate_bp_data(modp, ci, 0); - ASSERT(ci->u.gen_bp == NULL); + ASSERT(ci->gen_bp == NULL); } /* @@ -653,25 +668,53 @@ erts_clear_export_break(Module* modp, Export *ep) * being the function which is the caller, but rather the function * which we are about to return to. */ -static void fixup_cp_before_trace(Process *c_p, int *return_to_trace) +static void fixup_cp_before_trace(Process *c_p, + Eterm cp_save[2], + int *return_to_trace) { + const ErtsFrameLayout frame_layout = erts_frame_layout; Eterm *cpp = c_p->stop; + if (frame_layout == ERTS_FRAME_LAYOUT_FP_RA) { + ASSERT(is_CP(cpp[1])); + cp_save[1] = cpp[1]; + } + + ASSERT(is_CP(cpp[0])); + cp_save[0] = cpp[0]; + for (;;) { - ErtsCodePtr w = cp_val(*cpp); + ErtsCodePtr w; + + erts_inspect_frame(cpp, &w); + if (BeamIsReturnTrace(w)) { - cpp += 3; + cpp += CP_SIZE + 2; + } else if (BeamIsReturnTimeTrace(w)) { + cpp += CP_SIZE + 1; } else if (BeamIsReturnToTrace(w)) { *return_to_trace = 1; - cpp += 1; - } else if (BeamIsReturnTimeTrace(w)) { - cpp += 2; + cpp += CP_SIZE; } else { - break; + if (frame_layout == ERTS_FRAME_LAYOUT_FP_RA) { + ASSERT(is_CP(cpp[1])); + c_p->stop[1] = cpp[1]; + } + + ASSERT(is_CP(cpp[0])); + c_p->stop[0] = cpp[0]; + + return; } } - c_p->stop[0] = (Eterm) cp_val(*cpp); - ASSERT(is_CP(*cpp)); +} + +static void restore_cp_after_trace(Process *c_p, const Eterm cp_save[2]) { + if (erts_frame_layout == ERTS_FRAME_LAYOUT_FP_RA) { + c_p->stop[1] = cp_save[1]; + } + + c_p->stop[0] = cp_save[0]; } BeamInstr @@ -683,10 +726,10 @@ erts_generic_breakpoint(Process* c_p, ErtsCodeInfo *info, Eterm* reg) ErtsBpIndex ix = erts_active_bp_ix(); #ifndef BEAMASM - ASSERT(BeamIsOpCode(info->op, op_i_func_info_IaaI)); + ASSERT(BeamIsOpCode(info->u.op, op_i_func_info_IaaI)); #endif - g = info->u.gen_bp; + g = info->gen_bp; bp = &g->data[ix]; bp_flags = bp->flags; ASSERT((bp_flags & ~ERTS_BPF_ALL) == 0); @@ -738,24 +781,41 @@ erts_generic_breakpoint(Process* c_p, ErtsCodeInfo *info, Eterm* reg) ErtsCodePtr w; Eterm* E; - prev_info= erts_trace_time_call(c_p, info, bp->time); + prev_info = erts_trace_time_call(c_p, info, bp->time); + E = c_p->stop; - w = (ErtsCodePtr) E[0]; - if (!(BeamIsReturnTrace(w) || BeamIsReturnToTrace(w) || BeamIsReturnTimeTrace(w))) { - ASSERT(c_p->htop <= E && E <= c_p->hend); - if (HeapWordsLeft(c_p) < 2) { - (void) erts_garbage_collect(c_p, 2, reg, info->mfa.arity); - ERTS_VERIFY_UNUSED_TEMP_ALLOC(c_p); - } - E = c_p->stop; - ASSERT(c_p->htop <= E && E <= c_p->hend); + erts_inspect_frame(E, &w); - E -= 2; - E[1] = prev_info ? make_cp(erts_codeinfo_to_code(prev_info)) : NIL; - E[0] = (Eterm) beam_return_time_trace; - c_p->stop = E; - } + if (!(BeamIsReturnTrace(w) || + BeamIsReturnToTrace(w) || + BeamIsReturnTimeTrace(w))) { + int need = CP_SIZE + 1; + + ASSERT(c_p->htop <= E && E <= c_p->hend); + + if (HeapWordsLeft(c_p) < need) { + (void) erts_garbage_collect(c_p, need, + reg, info->mfa.arity); + ERTS_VERIFY_UNUSED_TEMP_ALLOC(c_p); + } + + E = c_p->stop; + + ASSERT(c_p->htop <= E && E <= c_p->hend); + + E -= 2; + E[1] = prev_info ? make_cp(erts_codeinfo_to_code(prev_info)) : NIL; + E[0] = make_cp(beam_return_time_trace); + + if (erts_frame_layout == ERTS_FRAME_LAYOUT_FP_RA) { + E -= 1; + E[0] = make_cp(FRAME_POINTER(c_p)); + FRAME_POINTER(c_p) = E; + } + + c_p->stop = E; + } } if (bp_flags & ERTS_BPF_DEBUG) { @@ -769,56 +829,91 @@ static ErtsTracer do_call_trace(Process* c_p, ErtsCodeInfo* info, Eterm* reg, int local, Binary* ms, ErtsTracer tracer) { + Eterm cp_save[2] = {0, 0}; int return_to_trace = 0; Uint32 flags; Uint need = 0; - Eterm cp_save; - Eterm* E = c_p->stop; + Eterm* E; - cp_save = E[0]; + fixup_cp_before_trace(c_p, cp_save, &return_to_trace); - fixup_cp_before_trace(c_p, &return_to_trace); ERTS_UNREQ_PROC_MAIN_LOCK(c_p); flags = erts_call_trace(c_p, info, ms, reg, local, &tracer); ERTS_REQ_PROC_MAIN_LOCK(c_p); - E[0] = cp_save; + restore_cp_after_trace(c_p, cp_save); + + E = c_p->stop; ASSERT(!ERTS_PROC_IS_EXITING(c_p)); + if ((flags & MATCH_SET_RETURN_TO_TRACE) && !return_to_trace) { - need += 1; + need += CP_SIZE; } + if (flags & MATCH_SET_RX_TRACE) { - need += 3 + size_object(tracer); + need += CP_SIZE + 2 + size_object(tracer); } + if (need) { - ASSERT(c_p->htop <= E && E <= c_p->hend); - if (HeapWordsLeft(c_p) < need) { - (void) erts_garbage_collect(c_p, need, reg, info->mfa.arity); - ERTS_VERIFY_UNUSED_TEMP_ALLOC(c_p); - E = c_p->stop; - } - } - if (flags & MATCH_SET_RETURN_TO_TRACE && !return_to_trace) { - E -= 1; - ASSERT(c_p->htop <= E && E <= c_p->hend); - E[0] = (Eterm) beam_return_to_trace; - c_p->stop = E; - } - if (flags & MATCH_SET_RX_TRACE) { - E -= 3; - c_p->stop = E; - ASSERT(c_p->htop <= E && E <= c_p->hend); - ASSERT(is_CP((Eterm) (UWord) (&info->mfa.module))); - ASSERT(IS_TRACER_VALID(tracer)); - E[2] = copy_object(tracer, c_p); - E[1] = make_cp(&info->mfa.module); - E[0] = (Eterm) ((flags & MATCH_SET_EXCEPTION_TRACE) ? - beam_exception_trace : beam_return_trace); - erts_proc_lock(c_p, ERTS_PROC_LOCKS_ALL_MINOR); - ERTS_TRACE_FLAGS(c_p) |= F_EXCEPTION_TRACE; - erts_proc_unlock(c_p, ERTS_PROC_LOCKS_ALL_MINOR); + ASSERT(c_p->htop <= E && E <= c_p->hend); + + if (HeapWordsLeft(c_p) < need) { + (void) erts_garbage_collect(c_p, need, reg, info->mfa.arity); + ERTS_VERIFY_UNUSED_TEMP_ALLOC(c_p); + E = c_p->stop; + } + + if ((flags & MATCH_SET_RETURN_TO_TRACE) && !return_to_trace) { + E -= CP_SIZE; + + if (erts_frame_layout == ERTS_FRAME_LAYOUT_RA) { + E[0] = make_cp(beam_return_to_trace); + } else { + E[1] = make_cp(beam_return_to_trace); + E[0] = make_cp(FRAME_POINTER(c_p)); + FRAME_POINTER(c_p) = E; + } + + ASSERT(c_p->htop <= E && E <= c_p->hend); + + c_p->stop = E; + } + + if (flags & MATCH_SET_RX_TRACE) { + ErtsCodePtr trace_cp; + + if (flags & MATCH_SET_EXCEPTION_TRACE) { + trace_cp = beam_exception_trace; + } else { + trace_cp = beam_return_trace; + } + + E -= 2; + E[1] = copy_object(tracer, c_p); + E[0] = make_cp(&info->mfa.module); + + E -= CP_SIZE; + if (erts_frame_layout == ERTS_FRAME_LAYOUT_RA) { + E[0] = make_cp(trace_cp); + } else { + E[1] = make_cp(trace_cp); + E[0] = make_cp(FRAME_POINTER(c_p)); + FRAME_POINTER(c_p) = E; + } + + ASSERT(c_p->htop <= E && E <= c_p->hend); + ASSERT(is_CP((Eterm)(&info->mfa.module))); + ASSERT(IS_TRACER_VALID(tracer)); + + c_p->stop = E; + + erts_proc_lock(c_p, ERTS_PROC_LOCKS_ALL_MINOR); + ERTS_TRACE_FLAGS(c_p) |= F_EXCEPTION_TRACE; + erts_proc_unlock(c_p, ERTS_PROC_LOCKS_ALL_MINOR); + } } + return tracer; } @@ -1097,7 +1192,7 @@ erts_find_local_func(const ErtsCodeMFA *mfa) { for (i = 0; i < n; ++i) { ci = code_hdr->functions[i]; #ifndef BEAMASM - ASSERT(BeamIsOpCode(ci->op, op_i_func_info_IaaI)); + ASSERT(BeamIsOpCode(ci->u.op, op_i_func_info_IaaI)); #endif ASSERT(mfa->module == ci->mfa.module || is_nil(ci->mfa.module)); if (mfa->function == ci->mfa.function && @@ -1287,9 +1382,9 @@ set_break(BpFunctions* f, Binary *match_spec, Uint break_flags, n = f->matched; for (i = 0; i < n; i++) { - set_function_break(f->matching[i].ci, + set_function_break(f->matching[i].ci_rw, match_spec, break_flags, - count_op, tracer); + count_op, tracer); } } @@ -1303,7 +1398,7 @@ set_function_break(ErtsCodeInfo *ci, Binary *match_spec, Uint break_flags, ErtsBpIndex ix = erts_staging_bp_ix(); ERTS_LC_ASSERT(erts_has_code_write_permission()); - g = ci->u.gen_bp; + g = ci->gen_bp; if (g == 0) { int i; if (count_op == ERTS_BREAK_RESTART || count_op == ERTS_BREAK_PAUSE) { @@ -1331,7 +1426,7 @@ set_function_break(ErtsCodeInfo *ci, Binary *match_spec, Uint break_flags, for (i = 0; i < ERTS_NUM_BP_IX; i++) { g->data[i].flags = 0; } - ci->u.gen_bp = g; + ci->gen_bp = g; } bp = &g->data[ix]; @@ -1423,7 +1518,7 @@ clear_break(BpFunctions* f, Uint break_flags) n = f->matched; for (i = 0; i < n; i++) { - clear_function_break(f->matching[i].ci, break_flags); + clear_function_break(f->matching[i].ci_exec, break_flags); } } @@ -1437,7 +1532,7 @@ clear_function_break(const ErtsCodeInfo *ci, Uint break_flags) ERTS_LC_ASSERT(erts_has_code_write_permission()); - if ((g = ci->u.gen_bp) == NULL) { + if ((g = ci->gen_bp) == NULL) { return 1; } @@ -1507,10 +1602,10 @@ get_time_break(const ErtsCodeInfo *ci) static GenericBpData* check_break(const ErtsCodeInfo *ci, Uint break_flags) { - GenericBp* g = ci->u.gen_bp; + GenericBp* g = ci->gen_bp; #ifndef BEAMASM - ASSERT(BeamIsOpCode(ci->op, op_i_func_info_IaaI)); + ASSERT(BeamIsOpCode(ci->u.op, op_i_func_info_IaaI)); #endif if (g) { |