/* * %CopyrightBegin% * * Copyright Ericsson AB 2000-2010. All Rights Reserved. * * The contents of this file are subject to the Erlang Public License, * Version 1.1, (the "License"); you may not use this file except in * compliance with the License. You should have received a copy of the * Erlang Public License along with this software. If not, it can be * retrieved online at http://www.erlang.org/. * * Software distributed under the License is distributed on an "AS IS" * basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See * the License for the specific language governing rights and limitations * under the License. * * %CopyrightEnd% */ #ifndef _BEAM_BP_H #define _BEAM_BP_H #include "sys.h" #include "erl_vm.h" #include "global.h" /* A couple of gotchas: * * The breakpoint structure from BeamInstr, * In beam_emu where the instruction counter pointer, I (or pc), * points to the *current* instruction. At that time, if the instruction * is a breakpoint instruction the pc looks like the following, * * I[-5] | op_i_func_info_IaaI | scheduler specific entries * I[-4] | BpData** bpa | --> | BpData * bdas1 | ... | BpData * bdasN | * I[-3] | Tagged Module | | | * I[-2] | Tagged Function | V V * I[-1] | Arity | BpData -> BpData -> BpData -> BpData * I[0] | The bp instruction | ^ * the bp wheel * | * |------------------------------ * * Common struct to all bp_data_* * * 1) The type of bp_data structure in the ring is deduced from the * orig_instr field of the structure _before_ in the ring, except for * the first structure in the ring that has its instruction in * pc[0] of the code to execute. * This is valid as long as you don't search for the function while it is * being executed by something else. Or is in the middle of its rotation for * any other reason. * A key, the bp beam instruction, is included for this reason. * * 2) pc[-4][sched_id - 1] points to the _last_ structure in the ring before the * breakpoints are being executed. * * So, as an example, when a breakpointed function starts to execute, * the first instruction that is a breakpoint instruction at pc[0] finds * its data at ((BpData **) pc[-4][sched_id - 1])->next and has to cast that pointer * to the correct bp_data type. */ typedef struct bp_data { struct bp_data *next; /* Doubly linked ring pointers */ struct bp_data *prev; /* -"- */ BeamInstr orig_instr; /* The original instruction to execute */ BeamInstr this_instr; /* key */ } BpData; /* ** All the following bp_data_.. structs must begin the same way */ typedef struct bp_data_trace { struct bp_data *next; struct bp_data *prev; BeamInstr orig_instr; BeamInstr this_instr; /* key */ Binary *match_spec; Eterm tracer_pid; } BpDataTrace; typedef struct bp_data_debug { struct bp_data *next; struct bp_data *prev; BeamInstr orig_instr; BeamInstr this_instr; /* key */ } BpDataDebug; typedef struct bp_data_count { /* Call count */ struct bp_data *next; struct bp_data *prev; BeamInstr orig_instr; BeamInstr this_instr; /* key */ erts_smp_atomic_t acount; } BpDataCount; typedef struct { Eterm pid; Sint count; Uint s_time; Uint us_time; } bp_data_time_item_t; typedef struct { Uint n; Uint used; bp_data_time_item_t *item; } bp_time_hash_t; typedef struct bp_data_time { /* Call time */ struct bp_data *next; struct bp_data *prev; BeamInstr orig_instr; BeamInstr this_instr; /* key */ Uint pause; Uint n; bp_time_hash_t *hash; } BpDataTime; typedef struct { Uint ms; Uint s; Uint us; BeamInstr *pc; } process_breakpoint_time_t; /* used within psd */ extern erts_smp_spinlock_t erts_bp_lock; #define ERTS_BP_CALL_TIME_SCHEDULE_IN (0) #define ERTS_BP_CALL_TIME_SCHEDULE_OUT (1) #define ERTS_BP_CALL_TIME_SCHEDULE_EXITING (2) #define ERTS_BP_CALL_TIME_CALL (0) #define ERTS_BP_CALL_TIME_RETURN (1) #define ERTS_BP_CALL_TIME_TAIL_CALL (2) #ifdef ERTS_SMP #define ErtsSmpBPLock(BDC) erts_smp_spin_lock(&erts_bp_lock) #define ErtsSmpBPUnlock(BDC) erts_smp_spin_unlock(&erts_bp_lock) #else #define ErtsSmpBPLock(BDC) #define ErtsSmpBPUnlock(BDC) #endif ERTS_INLINE Uint bp_sched2ix(void); #ifdef ERTS_SMP #define bp_sched2ix_proc(p) ((p)->scheduler_data->no - 1) #else #define bp_sched2ix_proc(p) (0) #endif #define ErtsCountBreak(p, pc,instr_result) \ do { \ BpData **bds = (BpData **) (pc)[-4]; \ BpDataCount *bdc = NULL; \ Uint ix = bp_sched2ix_proc( (p) ); \ erts_aint_t count = 0; \ \ ASSERT((pc)[-5] == (BeamInstr) BeamOp(op_i_func_info_IaaI)); \ ASSERT(bds); \ bdc = (BpDataCount *) bds[ix]; \ bdc = (BpDataCount *) bdc->next; \ ASSERT(bdc); \ bds[ix] = (BpData *) bdc; \ count = erts_smp_atomic_read(&bdc->acount); \ if (count >= 0) erts_smp_atomic_inc(&bdc->acount); \ *(instr_result) = bdc->orig_instr; \ } while (0) #define ErtsBreakSkip(p, pc,instr_result) \ do { \ BpData **bds = (BpData **) (pc)[-4]; \ BpData *bd = NULL; \ Uint ix = bp_sched2ix_proc( (p) ); \ \ ASSERT((pc)[-5] == (BeamInstr) BeamOp(op_i_func_info_IaaI)); \ ASSERT(bds); \ bd = bds[ix]; \ ASSERT(bd); \ bd = bd->next; \ ASSERT(bd); \ bds[ix] = bd; \ *(instr_result) = bd->orig_instr; \ } while (0) enum erts_break_op{ erts_break_nop = 0, /* Must be false */ erts_break_set = !0, /* Must be true */ erts_break_reset, erts_break_stop }; /* ** Function interface exported from beam_bp.c */ void erts_bp_init(void); int erts_set_trace_break(Eterm mfa[3], int specified, Binary *match_spec, Eterm tracer_pid); int erts_clear_trace_break(Eterm mfa[3], int specified); int erts_set_mtrace_break(Eterm mfa[3], int specified, Binary *match_spec, Eterm tracer_pid); int erts_clear_mtrace_break(Eterm mfa[3], int specified); void erts_set_mtrace_bif(BeamInstr *pc, Binary *match_spec, Eterm tracer_pid); void erts_clear_mtrace_bif(BeamInstr *pc); int erts_set_debug_break(Eterm mfa[3], int specified); int erts_clear_debug_break(Eterm mfa[3], int specified); int erts_set_count_break(Eterm mfa[3], int specified, enum erts_break_op); int erts_clear_count_break(Eterm mfa[3], int specified); int erts_clear_break(Eterm mfa[3], int specified); int erts_clear_module_break(Module *modp); int erts_clear_function_break(Module *modp, BeamInstr *pc); BeamInstr erts_trace_break(Process *p, BeamInstr *pc, Eterm *args, Uint32 *ret_flags, Eterm *tracer_pid); Uint32 erts_bif_mtrace(Process *p, BeamInstr *pc, Eterm *args, int local, Eterm *tracer_pid); int erts_is_trace_break(BeamInstr *pc, Binary **match_spec_ret, Eterm *tracer_pid_ret); int erts_is_mtrace_break(BeamInstr *pc, Binary **match_spec_ret, Eterm *tracer_pid_rte); int erts_is_mtrace_bif(BeamInstr *pc, Binary **match_spec_ret, Eterm *tracer_pid_ret); int erts_is_native_break(BeamInstr *pc); int erts_is_count_break(BeamInstr *pc, Sint *count_ret); int erts_is_time_break(Process *p, BeamInstr *pc, Eterm *call_time); void erts_trace_time_break(Process *p, BeamInstr *pc, BpDataTime *bdt, Uint type); void erts_schedule_time_break(Process *p, Uint out); int erts_set_time_break(Eterm mfa[3], int specified, enum erts_break_op); int erts_clear_time_break(Eterm mfa[3], int specified); int erts_is_time_trace_bif(Process *p, BeamInstr *pc, Eterm *call_time); void erts_set_time_trace_bif(BeamInstr *pc, enum erts_break_op); void erts_clear_time_trace_bif(BeamInstr *pc); BpData *erts_get_time_break(Process *p, BeamInstr *pc); BeamInstr *erts_find_local_func(Eterm mfa[3]); #endif /* _BEAM_BP_H */