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 <rweather@southern-storm.com.au>
* jit/jit-rules-x86.sel: pointer-relative loads and stores
$(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 \
$(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 $< >$@
* 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
@c -----------------------------------------------------------------------
-@node Exceptions, ELF Binaries, Intrinsics, Top
+@node Exceptions, Breakpoint Debugging, Intrinsics, Top
@chapter Handling exceptions
@cindex Handling exceptions
@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
@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
@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++
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.
#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
};
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;
* 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.
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;
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 \
*
* 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
--- /dev/null
+/*
+ * 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;
+ }
+}
/* 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;
- }
-}
(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
/* 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;
};
/*
* 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;
/*
* 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)},
};
* Debugging support.
*/
-JIT_OP_MARK_DEBUG: manual
+JIT_OP_MARK_BREAKPOINT: manual
[] -> {
/* TODO */
TODO();
}
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);
* Debugging support.
*/
-JIT_OP_MARK_DEBUG: manual
+JIT_OP_MARK_BREAKPOINT: manual
[] -> {
/* TODO */
TODO();
* @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
}
}
-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();
}