From: Rhys Weatherley Date: Mon, 4 Oct 2004 02:26:41 +0000 (+0000) Subject: Clean up the breakpoint API and implement debug hooks for the interpreter. X-Git-Tag: r.0.0.6~37 X-Git-Url: https://git.unchartedbackwaters.co.uk/w/?a=commitdiff_plain;h=8196846bb1632cd3d5521029292a0c6cc96772a1;p=francis%2Flibjit.git Clean up the breakpoint API and implement debug hooks for the interpreter. --- diff --git a/ChangeLog b/ChangeLog index 53ce649..81ab682 100644 --- a/ChangeLog +++ b/ChangeLog @@ -9,6 +9,15 @@ add instructions and function API's for supporting debug line numbers and breakpoints. + * doc/Makefile.am, doc/libjit.texi, include/jit/jit-context.h, + include/jit/jit-insn.h, include/jit/jit-opcode.h, + include/jit/jit-plus.h, jit/Makefile.am, jit/jit-context.c, + jit/jit-debug.c, jit/jit-function.c, jit/jit-insn.c, + jit/jit-internal.h, jit/jit-interp.c, jit/jit-opcode.c, + jit/jit-rules-arm.sel, jit/jit-rules-interp.c, jit/jit-rules-x86.sel, + jitplus/jit-plus-function.cpp: clean up the breakpoint API and + implement debug hooks for the interpreter. + 2004-09-10 Rhys Weatherley * jit/jit-rules-x86.sel: pointer-relative loads and stores diff --git a/doc/Makefile.am b/doc/Makefile.am index d20680c..2afa8e9 100644 --- a/doc/Makefile.am +++ b/doc/Makefile.am @@ -8,6 +8,7 @@ libjit_TEXINFOS = \ $(srcdir)/libjitext-apply.texi \ $(srcdir)/libjitext-block.texi \ $(srcdir)/libjitext-context.texi \ + $(srcdir)/libjitext-debug.texi \ $(srcdir)/libjitext-dump.texi \ $(srcdir)/libjitext-dynlib.texi \ $(srcdir)/libjitext-elf-read.texi \ @@ -41,6 +42,9 @@ $(srcdir)/libjitext-block.texi: $(top_srcdir)/jit/jit-block.c $(srcdir)/libjitext-context.texi: $(top_srcdir)/jit/jit-context.c $(SHELL) $(srcdir)/extract-docs.sh $< >$@ +$(srcdir)/libjitext-debug.texi: $(top_srcdir)/jit/jit-debug.c + $(SHELL) $(srcdir)/extract-docs.sh $< >$@ + $(srcdir)/libjitext-dump.texi: $(top_srcdir)/jit/jit-dump.c $(SHELL) $(srcdir)/extract-docs.sh $< >$@ diff --git a/doc/libjit.texi b/doc/libjit.texi index 067affe..43c82b8 100644 --- a/doc/libjit.texi +++ b/doc/libjit.texi @@ -45,9 +45,10 @@ Copyright @copyright{} 2004 Southern Storm Software, Pty Ltd * Basic Blocks:: Working with basic blocks in the JIT * Intrinsics:: Intrinsic functions available to libjit users * Exceptions:: Handling exceptions +* Breakpoint Debugging:: Hooking a breakpoint debugger into libjit * ELF Binaries:: Manipulating ELF binaries * Utility Routines:: Miscellaneous utility routines -* Debugging Routines:: Debugging routines +* Diagnostic Routines:: Diagnostic routines * C++ Interface:: Using libjit from C++ * Porting:: Porting libjit to new architectures * Why GPL?:: Why we use GPL and not LGPL for libjit @@ -1014,7 +1015,7 @@ field with a @code{pointer to procedure/function} type. @c ----------------------------------------------------------------------- -@node Exceptions, ELF Binaries, Intrinsics, Top +@node Exceptions, Breakpoint Debugging, Intrinsics, Top @chapter Handling exceptions @cindex Handling exceptions @@ -1022,7 +1023,15 @@ field with a @code{pointer to procedure/function} type. @c ----------------------------------------------------------------------- -@node ELF Binaries, Utility Routines, Exceptions, Top +@node Breakpoint Debugging, ELF Binaries, Exceptions, Top +@chapter Hooking a breakpoint debugger into libjit +@cindex Breakpoint debugging + +@include libjitext-debug.texi + +@c ----------------------------------------------------------------------- + +@node ELF Binaries, Utility Routines, Breakpoint Debugging, Top @chapter Manipulating ELF binaries @cindex ELF binaries @@ -1030,7 +1039,7 @@ field with a @code{pointer to procedure/function} type. @c ----------------------------------------------------------------------- -@node Utility Routines, Debugging Routines, ELF Binaries, Top +@node Utility Routines, Diagnostic Routines, ELF Binaries, Top @chapter Miscellaneous utility routines @cindex Utility routines @cindex jit-util.h @@ -1049,15 +1058,15 @@ that it itself uses internally, but which may also be useful to front ends. @c ----------------------------------------------------------------------- -@node Debugging Routines, C++ Interface, Utility Routines, Top -@chapter Debugging routines -@cindex Debugging routines +@node Diagnostic Routines, C++ Interface, Utility Routines, Top +@chapter Diagnostic routines +@cindex Diagnostic routines @include libjitext-dump.texi @c ----------------------------------------------------------------------- -@node C++ Interface, C++ Contexts, Debugging Routines, Top +@node C++ Interface, C++ Contexts, Diagnostic Routines, Top @chapter Using libjit from C++ @cindex Using libjit from C++ diff --git a/include/jit/jit-context.h b/include/jit/jit-context.h index 33ff8ed..87b46b9 100644 --- a/include/jit/jit-context.h +++ b/include/jit/jit-context.h @@ -41,6 +41,9 @@ void *jit_context_get_meta(jit_context_t context, int type) JIT_NOTHROW; jit_nuint jit_context_get_meta_numeric (jit_context_t context, int type) JIT_NOTHROW; void jit_context_free_meta(jit_context_t context, int type) JIT_NOTHROW; +void jit_context_enable_all_breakpoints + (jit_context_t context, int flag) JIT_NOTHROW; +int jit_context_all_breakpoints_enabled(jit_context_t context) JIT_NOTHROW; /* * Standard meta values for builtin configurable options. @@ -49,6 +52,13 @@ void jit_context_free_meta(jit_context_t context, int type) JIT_NOTHROW; #define JIT_OPTION_CACHE_PAGE_SIZE 10001 #define JIT_OPTION_PRE_COMPILE 10002 #define JIT_OPTION_DONT_FOLD 10003 +#define JIT_OPTION_DEBUG_HOOK 10004 + +/* + * Prototype for debug hook functions. + */ +typedef void (*jit_debug_hook_func) + (jit_function_t func, jit_nint data1, jit_nint data2); #ifdef __cplusplus }; diff --git a/include/jit/jit-insn.h b/include/jit/jit-insn.h index 299ee79..f39ce8f 100644 --- a/include/jit/jit-insn.h +++ b/include/jit/jit-insn.h @@ -312,7 +312,7 @@ int jit_insn_move_blocks_to_start int jit_insn_mark_offset (jit_function_t func, jit_int offset) JIT_NOTHROW; -int jit_insn_mark_debug +int jit_insn_mark_breakpoint (jit_function_t func, jit_nint data1, jit_nint data2) JIT_NOTHROW; void jit_insn_iter_init(jit_insn_iter_t *iter, jit_block_t block) JIT_NOTHROW; diff --git a/include/jit/jit-opcode.h b/include/jit/jit-opcode.h index ec370a5..8bc88d7 100644 --- a/include/jit/jit-opcode.h +++ b/include/jit/jit-opcode.h @@ -515,7 +515,7 @@ extern "C" { * Debugging support. */ #define JIT_OP_MARK_OFFSET 0x01A0 -#define JIT_OP_MARK_DEBUG 0x01A1 +#define JIT_OP_MARK_BREAKPOINT 0x01A1 /* * The number of opcodes in the above list. diff --git a/include/jit/jit-plus.h b/include/jit/jit-plus.h index 6f118d5..90535bf 100644 --- a/include/jit/jit-plus.h +++ b/include/jit/jit-plus.h @@ -351,7 +351,7 @@ public: void insn_move_blocks_to_start (const jit_label& from_label, const jit_label& to_label); void insn_mark_offset(jit_int offset); - void insn_mark_debug(jit_nint data1, jit_nint data2); + void insn_mark_breakpoint(jit_nint data1, jit_nint data2); private: jit_function_t func; diff --git a/jit/Makefile.am b/jit/Makefile.am index 4bc7469..f87a2c8 100644 --- a/jit/Makefile.am +++ b/jit/Makefile.am @@ -14,6 +14,7 @@ libjit_la_SOURCES = \ jit-context.c \ jit-cpuid-x86.h \ jit-cpuid-x86.c \ + jit-debug.c \ jit-dump.c \ jit-elf-defs.h \ jit-elf-read.c \ diff --git a/jit/jit-context.c b/jit/jit-context.c index 4856d11..b077df6 100644 --- a/jit/jit-context.c +++ b/jit/jit-context.c @@ -170,6 +170,21 @@ void jit_context_build_end(jit_context_t context) * * If the @code{type} already has some metadata associated with it, then * the previous value will be freed. + * + * The following non-numeric options are currently defined: + * + * @table @code + * @vindex JIT_OPTION_DEBUG_HOOK + * @item JIT_OPTION_DEBUG_HOOK + * Address of a function that should be called whenever an active + * breakpoint is encountered. The prototype should be as follows: + * + * @example + * void hook(jit_function_t func, jit_nint data1, jit_nint data2); + * @end example + * + * @xref{Breakpoint Debugging}, for more information. + * @end table * @end deftypefun @*/ int jit_context_set_meta diff --git a/jit/jit-debug.c b/jit/jit-debug.c new file mode 100644 index 0000000..e9d488e --- /dev/null +++ b/jit/jit-debug.c @@ -0,0 +1,132 @@ +/* + * jit-debug.c - Debug support routines for the JIT. + * + * Copyright (C) 2004 Southern Storm Software, Pty Ltd. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#include "jit-internal.h" + +/*@ + +The @code{libjit} library provides a very simple breakpoint mechanism. +Upon reaching each breakpoint in a function, the global debug hook +is called. It is up to the debug hook to decide whether to stop execution +or to ignore the breakpoint. + +Typically, the debug hook will inspect a table to determine which +breakpoints were actually selected by the user in a debugger's user +interface. The debug hook may even evaluate a complicated expression, +taking the function, current thread, and the value of local variables +into account, to make the decision. + +The global debug hook is set using @code{jit_context_set_meta} with a +type argument of @code{JIT_OPTION_DEBUG_HOOK}. It must have the +following prototype: + +@example +void hook(jit_function_t func, jit_nint data1, jit_nint data2); +@end example + +The @code{func} argument indicates the function that the breakpoint +occurred within. The @code{data1} and @code{data2} arguments are +those supplied to @code{jit_insn_mark_breakpoint}. The debugger can use +these values to indicate information about the breakpoint's type +and location. + +If the hook decides to stop at the breakpoint, it can call the debugger +immediately. Or the hook can send a message to a separate debugger +thread and wait for an indication that it is time to continue. + +Debug hooks can be used for other purposes besides breakpoint debugging. +A program could be instrumented with hooks that tally up the number +of times that each function is called, or which profile the amount of +time spent in each function. + +@*/ + +/*@ + * @deftypefun int jit_insn_mark_breakpoint (jit_function_t func, jit_nint data1, jit_nint data2) + * Mark the current position in @code{func} as corresponding to a breakpoint + * location. When a break occurs, the global debug hook is called with + * @code{func}, @code{data1}, and @code{data2} as arguments. + * + * Some platforms may have a performance penalty for inserting breakpoint + * locations, even if the breakpoint is never enabled. Correctness is + * considered more important than performance where debugging is concerned. + * @end deftypefun +@*/ + +/*@ + * @deftypefun void jit_context_enable_all_breakpoints (jit_context_t context, int flag) + * Enable or disable all breakpoints in all functions within @code{context}. + * This is typically used to implement a "single step" facility. + * @end deftypefun +@*/ +void jit_context_enable_all_breakpoints(jit_context_t context, int flag) +{ + if(context) + { + context->breakpoints_enabled = flag; + } +} + +/*@ + * @deftypefun int jit_context_all_breakpoints_enabled (jit_context_t context) + * Determine if all breakpoints within @code{context} are enabled. + * @end deftypefun +@*/ +int jit_context_all_breakpoints_enabled(jit_context_t context) +{ + if(context) + { + return context->breakpoints_enabled; + } + else + { + return 0; + } +} + +/*@ + * @deftypefun void jit_function_enable_breakpoints (jit_function_t func) + * Enable or disable all breakpoints in the specified function. + * @end deftypefun +@*/ +void jit_function_enable_breakpoints(jit_function_t func, int flag) +{ + if(func) + { + func->breakpoints_enabled = flag; + } +} + +/*@ + * @deftypefun int jit_function_breakpoints_enabled (jit_function_t func) + * Determine if breakpoints are enabled on the specified function. + * @end deftypefun +@*/ +int jit_function_breakpoints_enabled(jit_function_t func) +{ + if(func) + { + return func->breakpoints_enabled; + } + else + { + return 0; + } +} diff --git a/jit/jit-function.c b/jit/jit-function.c index 6e7f3d3..dc1ab4c 100644 --- a/jit/jit-function.c +++ b/jit/jit-function.c @@ -1288,45 +1288,3 @@ unsigned int jit_function_get_max_optimization_level(void) /* TODO - implement more than basic optimization */ return 0; } - -/*@ - * @deftypefun void jit_function_enable_breakpoints (jit_function_t func) - * Enable or disable all breakpoints in the specified function. Breakpoints - * occur at locations marked by @code{jit_insn_mark_debug}. - * - * The @code{libjit} library provides a very simple breakpoint mechanism. - * Upon reaching each breakpoint in the function, the global debug hook - * is called. It is up to the debug hook to decide whether to stop execution - * or to ignore the breakpoint. - * - * Typically, the debug hook will inspect a table to determine which - * breakpoints were actually selected by the user in a debugger's user - * interface. The debug hook may even evaluate a complicated expression, - * taking the function, current thread, and the value of local variables - * into account, to make the decision. - * @end deftypefun -@*/ -void jit_function_enable_breakpoints(jit_function_t func, int flag) -{ - if(func) - { - func->breakpoints_enabled = flag; - } -} - -/*@ - * @deftypefun int jit_function_breakpoints_enabled (jit_function_t func) - * Determine if breakpoints are enabled on the specified function. - * @end deftypefun -@*/ -int jit_function_breakpoints_enabled(jit_function_t func) -{ - if(func) - { - return func->breakpoints_enabled; - } - else - { - return 0; - } -} diff --git a/jit/jit-insn.c b/jit/jit-insn.c index e334eef..75924b3 100644 --- a/jit/jit-insn.c +++ b/jit/jit-insn.c @@ -7694,23 +7694,15 @@ int jit_insn_mark_offset(jit_function_t func, jit_int offset) (func, jit_type_int, offset)); } -/*@ - * @deftypefun int jit_insn_mark_debug (jit_function_t func, jit_nint data1, jit_nint data2) - * Mark the current position in @code{func} as corresponding to a breakpoint - * location. When a break occurs, the global debug hook is called with - * @code{func}, @code{data1}, and @code{data2} as arguments. See the - * description for @code{jit_function_enable_breakpoints} for more - * information on breakpoint support. - * @end deftypefun -@*/ -int jit_insn_mark_debug +/* Documentation is in jit-debug.c */ +int jit_insn_mark_breakpoint (jit_function_t func, jit_nint data1, jit_nint data2) { if(!jit_insn_new_block(func)) { return 0; } - return create_note(func, JIT_OP_MARK_DEBUG, + return create_note(func, JIT_OP_MARK_BREAKPOINT, jit_value_create_nint_constant (func, jit_type_nint, data1), jit_value_create_nint_constant diff --git a/jit/jit-internal.h b/jit/jit-internal.h index 4afbe51..e1ec224 100644 --- a/jit/jit-internal.h +++ b/jit/jit-internal.h @@ -458,6 +458,9 @@ struct _jit_context /* Table of symbols that have been registered with this context */ jit_regsym_t *registered_symbols; int num_registered_symbols; + + /* Flag that is set if all breakpoints in the system are enabled */ + int volatile breakpoints_enabled; }; /* diff --git a/jit/jit-interp.c b/jit/jit-interp.c index 0de6402..8cf2b08 100644 --- a/jit/jit-interp.c +++ b/jit/jit-interp.c @@ -4460,10 +4460,21 @@ void _jit_run_function(jit_function_interp_t func, jit_item *args, * Debugging support. ******************************************************************/ - VMCASE(JIT_OP_MARK_DEBUG): + VMCASE(JIT_OP_MARK_BREAKPOINT): { /* Process a breakpoint within the current function */ - /* TODO */ + if(func->func->breakpoints_enabled || + func->func->context->breakpoints_enabled) + { + jit_debug_hook_func hook; + hook = (jit_debug_hook_func) + jit_context_get_meta(func->func->context, + JIT_OPTION_DEBUG_HOOK); + if(hook) + { + (*hook)(func->func, VM_NINT_ARG, VM_NINT_ARG2); + } + } VM_MODIFY_PC_AND_STACK(3, 0); } VMBREAK; diff --git a/jit/jit-opcode.c b/jit/jit-opcode.c index 0d2a992..b6c9806 100644 --- a/jit/jit-opcode.c +++ b/jit/jit-opcode.c @@ -530,8 +530,8 @@ jit_opcode_info_t const jit_opcodes[JIT_OP_NUM_OPCODES] = { /* * Debugging support. */ - {"mark_offset", F_(EMPTY, INT, EMPTY)}, - {"mark_debug", F_(EMPTY, PTR, PTR)}, + {"mark_offset", F_(EMPTY, INT, EMPTY)}, + {"mark_breakpoint", F_(EMPTY, PTR, PTR)}, }; diff --git a/jit/jit-rules-arm.sel b/jit/jit-rules-arm.sel index d41b761..e27304e 100644 --- a/jit/jit-rules-arm.sel +++ b/jit/jit-rules-arm.sel @@ -1404,7 +1404,7 @@ JIT_OP_ADD_RELATIVE: unary * Debugging support. */ -JIT_OP_MARK_DEBUG: manual +JIT_OP_MARK_BREAKPOINT: manual [] -> { /* TODO */ TODO(); diff --git a/jit/jit-rules-interp.c b/jit/jit-rules-interp.c index e8ceefc..27b7914 100644 --- a/jit/jit-rules-interp.c +++ b/jit/jit-rules-interp.c @@ -1631,7 +1631,7 @@ void _jit_gen_insn(jit_gencode_t gen, jit_function_t func, } break; - case JIT_OP_MARK_DEBUG: + case JIT_OP_MARK_BREAKPOINT: { /* Mark the current location as a potential breakpoint */ jit_cache_opcode(&(gen->posn), insn->opcode); diff --git a/jit/jit-rules-x86.sel b/jit/jit-rules-x86.sel index 2d7f612..c29d739 100644 --- a/jit/jit-rules-x86.sel +++ b/jit/jit-rules-x86.sel @@ -2805,7 +2805,7 @@ JIT_OP_ALLOCA: unary * Debugging support. */ -JIT_OP_MARK_DEBUG: manual +JIT_OP_MARK_BREAKPOINT: manual [] -> { /* TODO */ TODO(); diff --git a/jitplus/jit-plus-function.cpp b/jitplus/jit-plus-function.cpp index df486a7..4fcf3bf 100644 --- a/jitplus/jit-plus-function.cpp +++ b/jitplus/jit-plus-function.cpp @@ -673,7 +673,7 @@ jit_value jit_function::get_struct_pointer() * @deftypemethodx jit_function void insn_move_blocks_to_end ({const jit_label&} from_label, {const jit_label&} to_label) * @deftypemethodx jit_function void insn_move_blocks_to_start ({const jit_label&} from_label, {const jit_label&} to_label) * @deftypemethodx jit_function void insn_mark_offset (jit_int offset) - * @deftypemethodx jit_function void insn_mark_debug (jit_nint data1, jit_nint data2) + * @deftypemethodx jit_function void insn_mark_breakpoint (jit_nint data1, jit_nint data2) * Create instructions of various kinds. @xref{Instructions}, for more * information on the individual instructions and their arguments. * @end deftypemethod @@ -1436,9 +1436,9 @@ void jit_function::insn_mark_offset(jit_int offset) } } -void jit_function::insn_mark_debug(jit_nint data1, jit_nint data2) +void jit_function::insn_mark_breakpoint(jit_nint data1, jit_nint data2) { - if(!jit_insn_mark_debug(func, data1, data2)) + if(!jit_insn_mark_breakpoint(func, data1, data2)) { out_of_memory(); }