Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Experimental debugger API #9604

Open
wants to merge 8 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion erts/emulator/Makefile.in
Original file line number Diff line number Diff line change
Expand Up @@ -1117,7 +1117,7 @@ RUN_OBJS += \
$(OBJDIR)/erl_trace.o $(OBJDIR)/copy.o \
$(OBJDIR)/utils.o $(OBJDIR)/bif.o \
$(OBJDIR)/io.o $(OBJDIR)/erl_printf_term.o\
$(OBJDIR)/erl_debug.o \
$(OBJDIR)/erl_debug.o $(OBJDIR)/erl_debugger.o \
$(OBJDIR)/erl_message.o $(OBJDIR)/erl_proc_sig_queue.o \
$(OBJDIR)/erl_process_dict.o $(OBJDIR)/erl_process_lock.o \
$(OBJDIR)/erl_port_task.o $(OBJDIR)/erl_arith.o \
Expand Down
4 changes: 4 additions & 0 deletions erts/emulator/beam/atom.names
Original file line number Diff line number Diff line change
Expand Up @@ -215,6 +215,7 @@ atom current_location
atom current_stacktrace
atom data
atom debug_flags
atom debugger_event
atom decentralized_counters
atom decimals
atom default
Expand Down Expand Up @@ -406,6 +407,7 @@ atom Le='=<'
atom legacy
atom lf
atom line
atom line_breakpoint
atom line_counters
atom line_delimiter
atom line_length
Expand Down Expand Up @@ -688,6 +690,7 @@ atom siginfo
atom silent
atom size
atom skip
atom slots
atom spawn_executable
atom spawn_driver
atom spawn_init
Expand Down Expand Up @@ -764,6 +767,7 @@ atom unloaded
atom unloaded_only
atom unload_cancelled
atom unsafe
atom unsupported
atom value
atom version
atom visible
Expand Down
127 changes: 127 additions & 0 deletions erts/emulator/beam/beam_bp.c
Original file line number Diff line number Diff line change
Expand Up @@ -1492,6 +1492,133 @@ int erts_is_call_break(Process *p, ErtsTraceSession *session, int is_time,
return 1;
}

void erts_install_line_breakpoint(struct erl_module_instance *mi, ErtsCodePtr cp_exec) {
ErtsCodePtr cp_rw;

erts_unseal_module(mi);
cp_rw = erts_writable_code_ptr(mi, cp_exec);

#ifdef BEAMASM
erts_asm_bp_enable(cp_rw);
#else
{
BeamInstr volatile *pc = (BeamInstr*)cp_rw;
BeamInstr instr = *pc;
BeamInstr br = BeamOpCodeAddr(op_i_enabled_line_breakpoint_t);

/* The following write is not protected by any lock.
* See note in erts_install_breakpoints().
*/
instr = BeamSetCodeAddr(instr, br);
*pc = instr;
}
#endif

erts_seal_module(mi);
}

void erts_uninstall_line_breakpoint(struct erl_module_instance *mi, ErtsCodePtr cp_exec) {
ErtsCodePtr cp_rw;

erts_unseal_module(mi);
cp_rw = erts_writable_code_ptr(mi, cp_exec);

#ifdef BEAMASM
erts_asm_bp_disable(cp_rw);
#else
{
BeamInstr volatile *pc = (BeamInstr*)cp_rw;
BeamInstr instr = *pc;
BeamInstr br = BeamOpCodeAddr(op_i_disabled_line_breakpoint_t);

/* The following write is not protected by any lock.
* See note in erts_install_breakpoints().
*/
instr = BeamSetCodeAddr(instr, br);
*pc = instr;
}
#endif

erts_seal_module(mi);
}

enum erts_is_line_breakpoint erts_is_line_breakpoint_code(ErtsCodePtr p) {
#ifdef BEAMASM
return beamasm_is_line_breakpoint_trampoline(p);
#else
const UWord instr = *(UWord *)p;
if (BeamIsOpCode(instr, op_i_disabled_line_breakpoint_t))
return IS_DISABLED_LINE_BP;
if (BeamIsOpCode(instr, op_i_enabled_line_breakpoint_t))
return IS_ENABLED_LINE_BP;
return IS_NOT_LINE_BP;
#endif
}

const Export *
erts_line_breakpoint_hit__prepare_call(Process* c_p, ErtsCodePtr pc, Uint live, Eterm *regs, UWord *stk) {
FunctionInfo fi;
const Export *ep;

ASSERT(live <= MAX_REG);

/*
* Search the error_handler module
*/
ep = erts_find_function(am_erts_internal, am_breakpoint, 4,
erts_active_code_ix());
if (ep == NULL) {
/* No error handler */
return NULL;
}

/*
* Find breakpoint location
*/
erts_lookup_function_info(&fi, pc, 1);
if (!fi.mfa) {
return NULL;
}

if (ep->info.mfa.module == fi.mfa->module
&& ep->info.mfa.function == fi.mfa->function
&& ep->info.mfa.arity == fi.mfa->arity) {
/* Cycle breaker */
return NULL;
}

/*
* Save live regs on the stack
*/
for(int i = 0; i < live; i++) {
*(stk++) = regs[i];
}

regs[0] = fi.mfa->module;
regs[1] = fi.mfa->function;
regs[2] = make_small(fi.mfa->arity);
regs[3] = make_small(LOC_LINE(fi.loc));

return ep;
}

Uint
erts_line_breakpoint_hit__cleanup(Eterm *regs, UWord *stk) {
int i = 0;

/*
* Restore X-registers
*/
while(is_not_CP(*stk)) {
regs[i++] = *(stk++);
}

/*
* Return number of registers restored
*/
return i;
}

const ErtsCodeInfo *
erts_find_local_func(const ErtsCodeMFA *mfa) {
const BeamCodeHeader *code_hdr;
Expand Down
17 changes: 17 additions & 0 deletions erts/emulator/beam/beam_bp.h
Original file line number Diff line number Diff line change
Expand Up @@ -116,6 +116,12 @@ typedef struct {
BpFunction* matching; /* Matching functions */
} BpFunctions;

enum erts_is_line_breakpoint {
IS_NOT_LINE_BP = 0,
IS_ENABLED_LINE_BP = 1,
IS_DISABLED_LINE_BP = 2,
};

/*
** Function interface exported from beam_bp.c
*/
Expand Down Expand Up @@ -187,6 +193,17 @@ void erts_clear_memory_break(BpFunctions *f);
Eterm erts_make_bp_session_list(ErtsHeapFactory*, const ErtsCodeInfo*,
Eterm tail);

void erts_install_line_breakpoint(struct erl_module_instance *, ErtsCodePtr);
void erts_uninstall_line_breakpoint(struct erl_module_instance *, ErtsCodePtr);
enum erts_is_line_breakpoint erts_is_line_breakpoint_code(ErtsCodePtr);

const Export *erts_line_breakpoint_hit__prepare_call(Process* c_p,
ErtsCodePtr pc,
Uint live,
Eterm *regs,
UWord *stk);
Uint erts_line_breakpoint_hit__cleanup(Eterm *regs, UWord *stk);

const ErtsCodeInfo *erts_find_local_func(const ErtsCodeMFA *mfa);

#if ERTS_GLB_INLINE_INCL_FUNC_DEF
Expand Down
5 changes: 5 additions & 0 deletions erts/emulator/beam/beam_code.h
Original file line number Diff line number Diff line change
Expand Up @@ -107,6 +107,11 @@ typedef struct beam_code_header {
const BeamDebugTab *debug;
#endif

/*
* Debugging instrumentation to use while loading the module
*/
Uint debugger_flags;

/*
* Pointer to the module MD5 sum (16 bytes)
*/
Expand Down
1 change: 1 addition & 0 deletions erts/emulator/beam/beam_common.h
Original file line number Diff line number Diff line change
Expand Up @@ -285,6 +285,7 @@ extern ErtsCodePtr beam_bif_export_trap;
extern ErtsCodePtr beam_export_trampoline;
extern ErtsCodePtr beam_continue_exit;
extern ErtsCodePtr beam_unloaded_fun;
extern ErtsCodePtr beam_i_line_breakpoint_cleanup;

extern ErtsCodePtr beam_return_to_trace; /* OpCode(i_return_to_trace) */
extern ErtsCodePtr beam_return_trace; /* OpCode(i_return_trace) */
Expand Down
50 changes: 50 additions & 0 deletions erts/emulator/beam/beam_ranges.c
Original file line number Diff line number Diff line change
Expand Up @@ -364,3 +364,53 @@ lookup_loc(FunctionInfo* fi, const void* pc,
}
}
}

ErtsCodePtr
erts_find_next_code_for_line(const BeamCodeHeader* code_hdr,
unsigned int line,
unsigned int *start_from)
{
const BeamCodeLineTab *lt = code_hdr->line_table;
const UWord num_functions = code_hdr->num_functions;
unsigned int line_index = -1;
unsigned int num_lines;

if (lt == NULL) {
return NULL;
}

num_lines = lt->func_tab[num_functions] - lt->func_tab[0];

/* NB. While at the moment lt->loc_tab is sorted (except at
* the edges, since module_info/0,1, etc have no line info),
* there's no strong guarantee this will be sorted in general,
* as the compiler could reorder functions, code with no
* dependencies, etc. So we do a linear-search here.
*/
if (lt->loc_size == 2) {
for(unsigned int i=*start_from; i<num_lines; i++) {
int curr_line = LOC_LINE(lt->loc_tab.p2[i]);
if (curr_line == line) {
line_index = i;
*start_from = i+1;
break;
}
}
} else {
for(unsigned int i=*start_from; i<num_lines; i++) {
int curr_line = LOC_LINE(lt->loc_tab.p4[i]);
if (curr_line == line) {
line_index = i;
*start_from = i+1;
break;
}
}
}

if (line_index == -1) {
*start_from = 0;
return NULL;
}

return lt->func_tab[0][line_index];
}
17 changes: 15 additions & 2 deletions erts/emulator/beam/bif.tab
Original file line number Diff line number Diff line change
Expand Up @@ -416,7 +416,7 @@ bif erl_ddll:monitor/2
bif erl_ddll:demonitor/1

#
# Bifs in the re module
# Bifs in the re module
#
bif re:version/0
bif re:compile/1
Expand Down Expand Up @@ -597,7 +597,7 @@ bif erlang:dt_get_tag_data/0
bif erlang:dt_spread_tag/1
bif erlang:dt_restore_tag/1

# These are dummies even with enabled dynamic trace unless vm probes are enabled.
# These are dummies even with enabled dynamic trace unless vm probes are enabled.
# They are also internal, for dtrace tags sent to the VM's own drivers (efile)
bif erlang:dt_prepend_vm_tag_data/1
bif erlang:dt_append_vm_tag_data/1
Expand Down Expand Up @@ -811,3 +811,16 @@ bif erts_internal:processes_next/1
bif code:get_debug_info/1
bif erlang:exit/3
bif erlang:link/2

bif erl_debugger:supported/0
bif erl_debugger:instrumentations/0
bif erl_debugger:toggle_instrumentations/1
bif erl_debugger:register/1
bif erl_debugger:unregister/2
bif erl_debugger:whereis/0
bif erl_debugger:breakpoint/3
bif erts_internal:notify_breakpoint_hit/3
bif erl_debugger:stack_frames/2
bif erl_debugger:peek_stack_frame_slot/4
bif erl_debugger:xregs_count/1
bif erl_debugger:peek_xreg/3
6 changes: 6 additions & 0 deletions erts/emulator/beam/emu/beam_emu.c
Original file line number Diff line number Diff line change
Expand Up @@ -119,6 +119,8 @@ ErtsCodePtr beam_exit;
static BeamInstr beam_continue_exit_[1];
ErtsCodePtr beam_continue_exit;

static BeamInstr beam_i_line_breakpoint_cleanup_[1];
ErtsCodePtr beam_i_line_breakpoint_cleanup;

/* NOTE These should be the only variables containing trace instructions.
** Sometimes tests are for the instruction value, and sometimes
Expand Down Expand Up @@ -580,6 +582,7 @@ void process_main(ErtsSchedulerData *esdp)
OpCase(label_L):
OpCase(on_load):
OpCase(line_I):
OpCase(i_debug_line_It):
OpCase(i_nif_padding):
erts_exit(ERTS_ERROR_EXIT, "meta op\n");

Expand Down Expand Up @@ -688,6 +691,9 @@ init_emulator_finish(void)
beam_continue_exit_[0] = BeamOpCodeAddr(op_continue_exit);
beam_continue_exit = (ErtsCodePtr)&beam_continue_exit_[0];

beam_i_line_breakpoint_cleanup_[0] = BeamOpCodeAddr(op_i_line_breakpoint_cleanup);
beam_i_line_breakpoint_cleanup = (ErtsCodePtr)&beam_i_line_breakpoint_cleanup_[0];

beam_return_to_trace_[0] = BeamOpCodeAddr(op_i_return_to_trace);
beam_return_to_trace = (ErtsCodePtr)&beam_return_to_trace_[0];

Expand Down
Loading
Loading