]> git.unchartedbackwaters.co.uk Git - francis/libjit.git/commitdiff
Redesign the debugger API so that it contains functions
authorRhys Weatherley <rweather@southern-storm.com.au>
Wed, 6 Oct 2004 05:43:15 +0000 (05:43 +0000)
committerRhys Weatherley <rweather@southern-storm.com.au>
Wed, 6 Oct 2004 05:43:15 +0000 (05:43 +0000)
like "add breakpoint", "run", "step", etc that more closely resemble
what a front end debugger will want to have, shifting the
implementation burden off the front end.

17 files changed:
ChangeLog
doc/Makefile.am
doc/libjit.texi
include/jit/Makefile.am
include/jit/jit-common.h
include/jit/jit-context.h
include/jit/jit-debugger.h [new file with mode: 0644]
include/jit/jit-except.h
include/jit/jit-function.h
include/jit/jit.h
jit/Makefile.am
jit/jit-context.c
jit/jit-debug.c [deleted file]
jit/jit-debugger.c [new file with mode: 0644]
jit/jit-insn.c
jit/jit-internal.h
jit/jit-interp.c

index 463fe60f467acba695bc5ff71e174b24f253e67a..855e8b5b2adc33896bdf85258efb2c2ab90ca010 100644 (file)
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,4 +1,17 @@
 
+2004-10-06  Rhys Weatherley  <rweather@southern-storm.com.au>
+
+       * doc/Makefile.am, doc/libjit.texi, include/jit/Makefile.am,
+       include/jit/jit-common.h, include/jit/jit-context.h,
+       include/jit/jit-debugger.h, include/jit/jit-except.h,
+       include/jit/jit-function.h, include/jit/jit.h, jit/Makefile.am,
+       jit/jit-context.c, jit/jit-debug.c, jit/jit-debugger.c,
+       jit/jit-insn.c, jit/jit-internal.h, jit/jit-interp.c:
+       redesign the debugger API so that it contains functions
+       like "add breakpoint", "run", "step", etc that more closely resemble
+       what a front end debugger will want to have, shifting the
+       implementation burden off the front end.
+
 2004-10-04  Rhys Weatherley  <rweather@southern-storm.com.au>
 
        * include/jit/jit-function.h, include/jit/jit-insn.h,
index 2afa8e9a707e647e28dfffa23175d8ac4c3c3303..5d3ee6835f32d0f9b21debd461931807c322a80f 100644 (file)
@@ -8,7 +8,7 @@ libjit_TEXINFOS = \
        $(srcdir)/libjitext-apply.texi \
        $(srcdir)/libjitext-block.texi \
        $(srcdir)/libjitext-context.texi \
-       $(srcdir)/libjitext-debug.texi \
+       $(srcdir)/libjitext-debugger.texi \
        $(srcdir)/libjitext-dump.texi \
        $(srcdir)/libjitext-dynlib.texi \
        $(srcdir)/libjitext-elf-read.texi \
@@ -42,7 +42,7 @@ $(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
+$(srcdir)/libjitext-debugger.texi: $(top_srcdir)/jit/jit-debugger.c
        $(SHELL) $(srcdir)/extract-docs.sh $< >$@
 
 $(srcdir)/libjitext-dump.texi: $(top_srcdir)/jit/jit-dump.c
index 43c82b8dc40348c16bedb2230aaae496886a470b..e49f773d27dac3c2d53ac547162968ba617d08c8 100644 (file)
@@ -1027,7 +1027,7 @@ field with a @code{pointer to procedure/function} type.
 @chapter Hooking a breakpoint debugger into libjit
 @cindex Breakpoint debugging
 
-@include libjitext-debug.texi
+@include libjitext-debugger.texi
 
 @c -----------------------------------------------------------------------
 
index 8490e446ba76a086a07bd1dafd286c54d423503f..8ed359b4cb8cb01ea45ce4312d8ca141316a71fe 100644 (file)
@@ -5,6 +5,7 @@ libjitinclude_HEADERS = jit.h \
                                                jit-block.h \
                                                jit-common.h \
                                                jit-context.h \
+                                               jit-debugger.h \
                                                jit-defs.h \
                                                jit-dump.h \
                                                jit-dynamic.h \
index 2b182d631c5deaac6330e7396858ee3f5dadef68..bb03f7be63743461b0d07f470205490b0f25c974 100644 (file)
@@ -62,6 +62,11 @@ typedef struct _jit_value *jit_value_t;
  */
 typedef struct _jit_type *jit_type_t;
 
+/*
+ * Opaque type that represents an exception stack trace.
+ */
+typedef struct jit_stack_trace *jit_stack_trace_t;
+
 /*
  * Block label identifier.
  */
index 87b46b9ae9ea481c3dfdd0711cea5e9d70f3c2d3..33ff8ed125c8f98ab6ed8cb11a6bf42075b42e7a 100644 (file)
@@ -41,9 +41,6 @@ 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.
@@ -52,13 +49,6 @@ int jit_context_all_breakpoints_enabled(jit_context_t context) 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-debugger.h b/include/jit/jit-debugger.h
new file mode 100644 (file)
index 0000000..e41b76f
--- /dev/null
@@ -0,0 +1,132 @@
+/*
+ * jit-debugger.h - Helper routines for single-step debugging of programs.
+ *
+ * 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
+ */
+
+#ifndef        _JIT_DEBUGGER_H
+#define        _JIT_DEBUGGER_H
+
+#include <jit/jit-common.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+typedef struct jit_debugger *jit_debugger_t;
+typedef jit_nint jit_debugger_thread_id_t;
+typedef jit_nint jit_debugger_breakpoint_id_t;
+
+typedef struct jit_debugger_event
+{
+       int                                                             type;
+       jit_debugger_thread_id_t                thread;
+       jit_function_t                                  function;
+       jit_nint                                                data1;
+       jit_nint                                                data2;
+       jit_debugger_breakpoint_id_t    id;
+       jit_stack_trace_t                               trace;
+
+} jit_debugger_event_t;
+
+#define        JIT_DEBUGGER_TYPE_QUIT                          0
+#define        JIT_DEBUGGER_TYPE_HARD_BREAKPOINT       1
+#define        JIT_DEBUGGER_TYPE_SOFT_BREAKPOINT       2
+#define        JIT_DEBUGGER_TYPE_USER_BREAKPOINT       3
+#define        JIT_DEBUGGER_TYPE_ATTACH_THREAD         4
+#define        JIT_DEBUGGER_TYPE_DETACH_THREAD         5
+
+typedef struct jit_debugger_breakpoint_info
+{
+       int                                                             flags;
+       jit_debugger_thread_id_t                thread;
+       jit_function_t                                  function;
+       jit_nint                                                data1;
+       jit_nint                                                data2;
+
+} *jit_debugger_breakpoint_info_t;
+
+#define        JIT_DEBUGGER_FLAG_THREAD                (1 << 0)
+#define        JIT_DEBUGGER_FLAG_FUNCTION              (1 << 1)
+#define        JIT_DEBUGGER_FLAG_DATA1                 (1 << 2)
+#define        JIT_DEBUGGER_FLAG_DATA2                 (1 << 3)
+
+#define        JIT_DEBUGGER_DATA1_FIRST                10000
+#define        JIT_DEBUGGER_DATA1_LINE                 10000
+#define        JIT_DEBUGGER_DATA1_ENTER                10001
+#define        JIT_DEBUGGER_DATA1_LEAVE                10002
+#define        JIT_DEBUGGER_DATA1_THROW                10003
+
+typedef void (*jit_debugger_hook_func)
+       (jit_function_t func, jit_nint data1, jit_nint data2);
+
+int jit_debugging_possible(void) JIT_NOTHROW;
+
+jit_debugger_t jit_debugger_create(jit_context_t context) JIT_NOTHROW;
+void jit_debugger_destroy(jit_debugger_t dbg) JIT_NOTHROW;
+
+jit_context_t jit_debugger_get_context(jit_debugger_t dbg) JIT_NOTHROW;
+jit_debugger_t jit_debugger_from_context(jit_context_t context) JIT_NOTHROW;
+
+jit_debugger_thread_id_t jit_debugger_get_self(jit_debugger_t dbg) JIT_NOTHROW;
+jit_debugger_thread_id_t jit_debugger_get_thread
+               (jit_debugger_t dbg, const void *native_thread) JIT_NOTHROW;
+int jit_debugger_get_native_thread
+               (jit_debugger_t dbg, jit_debugger_thread_id_t thread,
+                void *native_thread) JIT_NOTHROW;
+void jit_debugger_set_breakable
+               (jit_debugger_t dbg, const void *native_thread, int flag) JIT_NOTHROW;
+
+void jit_debugger_attach_self
+               (jit_debugger_t dbg, int stop_immediately) JIT_NOTHROW;
+void jit_debugger_detach_self(jit_debugger_t dbg) JIT_NOTHROW;
+
+int jit_debugger_wait_event
+               (jit_debugger_t dbg, jit_debugger_event_t *event,
+                jit_int timeout) JIT_NOTHROW;
+
+jit_debugger_breakpoint_id_t jit_debugger_add_breakpoint
+               (jit_debugger_t dbg, jit_debugger_breakpoint_info_t info) JIT_NOTHROW;
+void jit_debugger_remove_breakpoint
+               (jit_debugger_t dbg, jit_debugger_breakpoint_id_t id) JIT_NOTHROW;
+void jit_debugger_remove_all_breakpoints(jit_debugger_t dbg) JIT_NOTHROW;
+
+int jit_debugger_is_alive
+               (jit_debugger_t dbg, jit_debugger_thread_id_t thread) JIT_NOTHROW;
+int jit_debugger_is_running
+               (jit_debugger_t dbg, jit_debugger_thread_id_t thread) JIT_NOTHROW;
+void jit_debugger_run
+               (jit_debugger_t dbg, jit_debugger_thread_id_t thread) JIT_NOTHROW;
+void jit_debugger_step
+               (jit_debugger_t dbg, jit_debugger_thread_id_t thread) JIT_NOTHROW;
+void jit_debugger_next
+               (jit_debugger_t dbg, jit_debugger_thread_id_t thread) JIT_NOTHROW;
+void jit_debugger_finish
+               (jit_debugger_t dbg, jit_debugger_thread_id_t thread) JIT_NOTHROW;
+
+void jit_debugger_break(jit_debugger_t dbg) JIT_NOTHROW;
+
+void jit_debugger_quit(jit_debugger_t dbg) JIT_NOTHROW;
+
+jit_debugger_hook_func jit_debugger_set_hook
+               (jit_context_t context, jit_debugger_hook_func hook);
+
+#ifdef __cplusplus
+};
+#endif
+
+#endif /* _JIT_DEBUGGER_H */
index 6d1be10227d445545a4c1193c3b283cc3bb9ae49..0f1cb22126dd14cfe08a6b5d5e4c378b24efe026 100644 (file)
@@ -45,11 +45,6 @@ extern       "C" {
  */
 typedef void *(*jit_exception_func)(int exception_type);
 
-/*
- * Opaque type that represents an exception stack trace.
- */
-typedef struct jit_stack_trace *jit_stack_trace_t;
-
 /*
  * External function declarations.
  */
index c376d7f10939fb556776a47dab0ac00906f53501..cd5e5d614378ebd40904dec67b51a698a249a603 100644 (file)
@@ -70,8 +70,6 @@ void jit_function_set_optimization_level
 unsigned int jit_function_get_optimization_level
        (jit_function_t func) JIT_NOTHROW;
 unsigned int jit_function_get_max_optimization_level(void) JIT_NOTHROW;
-void jit_function_enable_breakpoints(jit_function_t func, int flag) JIT_NOTHROW;
-int jit_function_breakpoints_enabled(jit_function_t func) JIT_NOTHROW;
 
 #ifdef __cplusplus
 };
index 45220bdd85d4a02d85932467ca033a4f7c4d5f64..ecb9547dd831a07018f3475ab203fa266953b681 100644 (file)
@@ -30,6 +30,7 @@ extern        "C" {
 #include <jit/jit-context.h>
 #include <jit/jit-apply.h>
 #include <jit/jit-block.h>
+#include <jit/jit-debugger.h>
 #include <jit/jit-elf.h>
 #include <jit/jit-except.h>
 #include <jit/jit-function.h>
index f87a2c8dbab40b070d7f0b23738c047b91be4814..4706e0f14446b9c35f9e05fbf518a46b4fcf9a03 100644 (file)
@@ -14,7 +14,7 @@ libjit_la_SOURCES = \
                jit-context.c \
                jit-cpuid-x86.h \
                jit-cpuid-x86.c \
-               jit-debug.c \
+               jit-debugger.c \
                jit-dump.c \
                jit-elf-defs.h \
                jit-elf-read.c \
index b077df674f7f56baec95981fa884009efc5be1e8..4856d11e8bb0634580791ec13bbc2820ed2a0c01 100644 (file)
@@ -170,21 +170,6 @@ 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
deleted file mode 100644 (file)
index e9d488e..0000000
+++ /dev/null
@@ -1,132 +0,0 @@
-/*
- * 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-debugger.c b/jit/jit-debugger.c
new file mode 100644 (file)
index 0000000..b677290
--- /dev/null
@@ -0,0 +1,878 @@
+/*
+ * jit-debugger.c - Helper routines for single-step debugging of programs.
+ *
+ * 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"
+
+/*@
+
+@cindex jit-debugger.h
+
+The @code{libjit} library provides support routines for breakpoint-based
+single-step debugging.  It isn't a full debugger, but provides the
+infrastructure necessary to support one.
+
+The front end virtual machine is responsible for inserting "potential
+breakpoints" into the code when functions are built and compiled.  This
+is performed using @code{jit_insn_mark_breakpoint}:
+
+@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 debugging routines are passed
+@code{func}, @code{data1}, and @code{data2} as arguments.  By convention,
+@code{data1} is the type of breakpoint (source line, function entry,
+function exit, etc).
+@end deftypefun
+
+There are two ways for a front end to receive notification about breakpoints.
+The bulk of this chapter describes the @code{jit_debugger_t} interface,
+which handles most of the ugly details.  In addition, a low-level "debug hook
+mechanism" is provided for front ends that wish more control over the
+process.  The debug hook mechanism is described below, under the
+@code{jit_debugger_set_hook} function.
+
+This debugger implementation requires a threading system to work
+successfully.  At least two threads are required, in addition to those of
+the program being debugged:
+
+@enumerate
+@item
+Event thread which calls @code{jit_debugger_wait_event} to receive
+notifications of breakpoints and other interesting events.
+
+@item
+User interface thread which calls functions like @code{jit_debugger_run},
+@code{jit_debugger_step}, etc, to control the debug process.
+@end enumerate
+
+These two threads should be set to "unbreakable" with a call to
+@code{jit_debugger_set_breakable}.  This prevents them from accidentally
+stopping at a breakpoint, which would cause a system deadlock.
+Other housekeeping threads, such as a finalization thread, should
+also be set to "unbreakable" for the same reason.
+
+@noindent
+Events have the following members:
+
+@table @code
+@item type
+The type of event (see the next table for details).
+
+@item thread
+The thread that the event occurred on.
+
+@item function
+The function that the breakpoint occurred within.
+
+@item data1
+@itemx data2
+The data values at the breakpoint.  These values are inserted into
+the function's code with @code{jit_insn_mark_breakpoint}.
+
+@item id
+The identifier for the breakpoint.
+
+@item trace
+The stack trace corresponding to the location where the breakpoint
+occurred.  This value is automatically freed upon the next call
+to @code{jit_debugger_wait_event}.  If you wish to preserve the
+value, then you must call @code{jit_stack_trace_copy}.
+@end table
+
+@noindent
+The following event types are currently supported:
+
+@table @code
+@item JIT_DEBUGGER_TYPE_QUIT
+A thread called @code{jit_debugger_quit}, indicating that it wanted the
+event thread to terminate.
+
+@item JIT_DEBUGGER_TYPE_HARD_BREAKPOINT
+A thread stopped at a hard breakpoint.  That is, a breakpoint defined
+by a call to @code{jit_debugger_add_breakpoint}.
+
+@item JIT_DEBUGGER_TYPE_SOFT_BREAKPOINT
+A thread stopped at a breakpoint that wasn't explicitly defined by
+a call to @code{jit_debugger_add_breakpoint}.  This typicaly results
+from a call to a "step" function like @code{jit_debugger_step}, where
+execution stopped at the next line but there isn't an explicit breakpoint
+on that line.
+
+@item JIT_DEBUGGER_TYPE_USER_BREAKPOINT
+A thread stopped because of a call to @code{jit_debugger_break}.
+
+@item JIT_DEBUGGER_TYPE_ATTACH_THREAD
+A thread called @code{jit_debugger_attach_self}.  The @code{data1} field
+of the event is set to the value of @code{stop_immediately} for the call.
+
+@item JIT_DEBUGGER_TYPE_DETACH_THREAD
+A thread called @code{jit_debugger_detach_self}.
+@end table
+
+@*/
+
+/*
+ * Linked event, for the debugger event queue.
+ */
+typedef struct jit_debugger_linked_event
+{
+       jit_debugger_event_t                            event;
+       struct jit_debugger_linked_event   *next;
+
+} jit_debugger_linked_event_t;
+
+/*
+ * Run types.
+ */
+#define        JIT_RUN_TYPE_STOPPED            0
+#define        JIT_RUN_TYPE_CONTINUE           1
+#define        JIT_RUN_TYPE_STEP                       2
+#define        JIT_RUN_TYPE_NEXT                       3
+#define        JIT_RUN_TYPE_FINISH                     4
+#define        JIT_RUN_TYPE_DETACHED           5
+
+/*
+ * Information about a thread that is under the control of the debugger.
+ */
+typedef struct jit_debugger_thread
+{
+       struct jit_debugger_thread *next;
+       jit_debugger_thread_id_t        id;
+       int                                volatile     run_type;
+       jit_function_t                          find_func;
+       jit_nint                                        last_data1;
+       jit_nint                                        last_func_data1;
+       int                                                     breakable;
+
+} *jit_debugger_thread_t;
+
+/*
+ * Structure of a debugger instance.
+ */
+struct jit_debugger
+{
+       jit_context_t                             context;
+       jit_debugger_linked_event_t * volatile events;
+       jit_debugger_linked_event_t * volatile last_event;
+};
+
+/*
+ * Lock the debugger object.
+ */
+static void lock_debugger(jit_debugger_t dbg)
+{
+       /* TODO */
+}
+
+/*
+ * Unlock the debugger object.
+ */
+static void unlock_debugger(jit_debugger_t dbg)
+{
+       /* TODO */
+}
+
+/*
+ * Suspend the current thread until it is marked as running again.
+ * It is assumed that the debugger's monitor lock has been acquired.
+ */
+static void suspend_thread(jit_debugger_t dbg, jit_debugger_thread_t thread)
+{
+       /* TODO */
+}
+
+/*
+ * Wake all threads that are waiting on the debugger's monitor.
+ */
+static void wakeup_all(jit_debugger_t dbg)
+{
+       /* TODO */
+}
+
+/*
+ * Get the information block for the current thread.
+ */
+static jit_debugger_thread_t get_current_thread(jit_debugger_t dbg)
+{
+       /* TODO */
+       return 0;
+}
+
+/*
+ * Get the information block for a specific thread.
+ */
+static jit_debugger_thread_t get_specific_thread
+               (jit_debugger_t dbg, jit_debugger_thread_id_t thread)
+{
+       /* TODO */
+       return 0;
+}
+
+/*
+ * Allocate space for a new event on the event queue.
+ */
+#define        alloc_event()           \
+               ((jit_debugger_event_t *)jit_cnew(jit_debugger_linked_event_t))
+
+/*
+ * Add an event that was previously allocated with "alloc_event"
+ * to a debugger's event queue.
+ */
+static void add_event(jit_debugger_t dbg, jit_debugger_event_t *_event)
+{
+       jit_debugger_linked_event_t *event = (jit_debugger_linked_event_t *)_event;
+       event->next = 0;
+       if(dbg->last_event)
+       {
+               dbg->last_event->next = event;
+       }
+       else
+       {
+               dbg->events = event;
+       }
+       dbg->last_event = event;
+       wakeup_all(dbg);
+}
+
+/*@
+ * @deftypefun int jit_debugging_possible (void)
+ * Determine if debugging is possible.  i.e. that threading is available
+ * and compatible with the debugger's requirements.
+ * @end deftypefun
+@*/
+int jit_debugging_possible(void)
+{
+       /* TODO */
+       return 1;
+}
+
+/*@
+ * @deftypefun jit_debugger_t jit_debugger_create (jit_context_t context)
+ * Create a new debugger instance and attach it to a JIT @code{context}.
+ * If the context already has a debugger associated with it, then this
+ * function will return the previous debugger.
+ * @end deftypefun
+@*/
+jit_debugger_t jit_debugger_create(jit_context_t context)
+{
+       jit_debugger_t dbg;
+       if(context)
+       {
+               if(context->debugger)
+               {
+                       return context->debugger;
+               }
+               dbg = jit_cnew(struct jit_debugger);
+               if(!dbg)
+               {
+                       return 0;
+               }
+               dbg->context = context;
+               context->debugger = dbg;
+               return dbg;
+       }
+       else
+       {
+               return 0;
+       }
+}
+
+/*@
+ * @deftypefun void jit_debugger_destroy (jit_debugger_t dbg)
+ * Destroy a debugger instance.
+ * @end deftypefun
+@*/
+void jit_debugger_destroy(jit_debugger_t dbg)
+{
+       /* TODO */
+}
+
+/*@
+ * @deftypefun jit_context_t jit_debugger_get_context (jit_debugger_t dbg)
+ * Get the JIT context that is associated with a debugger instance.
+ * @end deftypefun
+@*/
+jit_context_t jit_debugger_get_context(jit_debugger_t dbg)
+{
+       if(dbg)
+       {
+               return dbg->context;
+       }
+       else
+       {
+               return 0;
+       }
+}
+
+/*@
+ * @deftypefun jit_debugger_t jit_debugger_from_context (jit_context_t context)
+ * Get the debugger that is currently associated with a JIT context,
+ * or NULL if there is no debugger associated with the context.
+ * @end deftypefun
+@*/
+jit_debugger_t jit_debugger_from_context(jit_context_t context)
+{
+       if(context)
+       {
+               return context->debugger;
+       }
+       else
+       {
+               return 0;
+       }
+}
+
+/*@
+ * @deftypefun jit_debugger_thread_id_t jit_debugger_get_self (jit_debugger_t dbg)
+ * Get the thread identifier associated with the current thread.
+ * The return values are normally values like 1, 2, 3, etc, allowing
+ * the user interface to report messages like "thread 3 has stopped
+ * at a breakpoint".
+ * @end deftypefun
+@*/
+jit_debugger_thread_id_t jit_debugger_get_self(jit_debugger_t dbg)
+{
+       /* TODO */
+       return 0;
+}
+
+/*@
+ * @deftypefun jit_debugger_thread_id_t jit_debugger_get_thread (jit_debugger_t dbg, {const void *} native_thread)
+ * Get the thread identifier for a specific native thread.  The
+ * @code{native_thread} pointer is assumed to point at a block
+ * of memory containing a native thread handle.  This would be a
+ * @code{pthread_t} on Pthreads platforms or a @code{HANDLE}
+ * on Win32 platforms.  If the native thread has not been seen
+ * previously, then a new thread identifier is allocated.
+ * @end deftypefun
+@*/
+jit_debugger_thread_id_t jit_debugger_get_thread
+               (jit_debugger_t dbg, const void *native_thread)
+{
+       /* TODO */
+       return 0;
+}
+
+/*@
+ * @deftypefun int jit_debugger_get_native_thread (jit_debugger_t dbg, jit_debugger_thread_id_t thread, {void *} native_thread)
+ * Get the native thread handle associated with a debugger thread identifier.
+ * Returns non-zero if OK, or zero if the debugger thread identifier is not
+ * yet associated with a native thread handle.
+ * @end deftypefun
+@*/
+int jit_debugger_get_native_thread
+               (jit_debugger_t dbg, jit_debugger_thread_id_t thread,
+                void *native_thread)
+{
+       /* TODO */
+       return 0;
+}
+
+/*@
+ * @deftypefun void jit_debugger_set_breakable (jit_debugger_t dbg, {const void *} native_thread, int flag)
+ * Set a flag that indicates if a native thread can stop at breakpoints.
+ * If set to 1 (the default), breakpoints will be active on the thread.
+ * If set to 0, breakpoints will be ignored on the thread.  Typically
+ * this is used to mark threads associated with the debugger's user
+ * interface, or the virtual machine's finalization thread, so that they
+ * aren't accidentally suspended by the debugger (which might cause a
+ * deadlock).
+ * @end deftypefun
+@*/
+void jit_debugger_set_breakable
+               (jit_debugger_t dbg, const void *native_thread, int flag)
+{
+       /* TODO */
+}
+
+/*@
+ * @deftypefun void jit_debugger_attach_self (jit_debugger_t dbg, int stop_immediately)
+ * Attach the current thread to a debugger.  If @code{stop_immediately}
+ * is non-zero, then the current thread immediately suspends, waiting for
+ * the user to start it with @code{jit_debugger_run}.  This function is
+ * typically called in a thread's startup code just before any "real work"
+ * is performed.
+ * @end deftypefun
+@*/
+void jit_debugger_attach_self(jit_debugger_t dbg, int stop_immediately)
+{
+       jit_debugger_event_t *event;
+       jit_debugger_thread_t th;
+       lock_debugger(dbg);
+       th = get_current_thread(dbg);
+       if(th)
+       {
+               event = alloc_event();
+               if(event)
+               {
+                       event->type = JIT_DEBUGGER_TYPE_ATTACH_THREAD;
+                       event->thread = th->id;
+                       event->data1 = (jit_nint)stop_immediately;
+                       add_event(dbg, event);
+                       th->find_func = 0;
+                       th->last_data1 = 0;
+                       th->last_func_data1 = 0;
+                       if(stop_immediately)
+                       {
+                               th->run_type = JIT_RUN_TYPE_STOPPED;
+                               suspend_thread(dbg, th);
+                       }
+                       else
+                       {
+                               th->run_type = JIT_RUN_TYPE_CONTINUE;
+                       }
+               }
+       }
+       unlock_debugger(dbg);
+}
+
+/*@
+ * @deftypefun void jit_debugger_detach_self (jit_debugger_t dbg)
+ * Detach the current thread from the debugger.  This is typically
+ * called just before the thread exits.
+ * @end deftypefun
+@*/
+void jit_debugger_detach_self(jit_debugger_t dbg)
+{
+       jit_debugger_event_t *event;
+       jit_debugger_thread_t th;
+       lock_debugger(dbg);
+       th = get_current_thread(dbg);
+       if(th)
+       {
+               event = alloc_event();
+               if(event)
+               {
+                       event->type = JIT_DEBUGGER_TYPE_DETACH_THREAD;
+                       event->thread = th->id;
+                       add_event(dbg, event);
+                       th->run_type = JIT_RUN_TYPE_DETACHED;
+               }
+       }
+       unlock_debugger(dbg);
+}
+
+/*@
+ * @deftypefun int jit_debugger_wait_event (jit_debugger_t dbg, {jit_debugger_event_t *} event, jit_nint timeout)
+ * Wait for the next debugger event to arrive.  Debugger events typically
+ * indicate breakpoints that have occurred.  The @code{timeout} is in
+ * milliseconds, or -1 for an infinite timeout period.  Returns non-zero
+ * if an event has arrived, or zero on timeout.
+ * @end deftypefun
+@*/
+int jit_debugger_wait_event
+               (jit_debugger_t dbg, jit_debugger_event_t *event, jit_int timeout)
+{
+       /* TODO */
+       return 0;
+}
+
+/*@
+ * @deftypefun jit_debugger_breakpoint_id_t jit_debugger_add_breakpoint (jit_debugger_t dbg, jit_debugger_breakpoint_info_t info)
+ * Add a hard breakpoint to a debugger instance.  The @code{info} structure
+ * defines the conditions under which the breakpoint should fire.
+ * The fields of @code{info} are as follows:
+ *
+ * @table @code
+ * @item flags
+ * Flags that indicate which of the following fields should be matched.
+ * If a flag is not present, then all possible values of the field will match.
+ * Valid flags are @code{JIT_DEBUGGER_FLAG_THREAD},
+ * @code{JIT_DEBUGGER_FLAG_FUNCTION}, @code{JIT_DEBUGGER_FLAG_DATA1},
+ * and @code{JIT_DEBUGGER_FLAG_DATA2}.
+ *
+ * @item thread
+ * The thread to match against, if @code{JIT_DEBUGGER_FLAG_THREAD} is set.
+ *
+ * @item function
+ * The function to match against, if @code{JIT_DEBUGGER_FLAG_FUNCTION} is set.
+ *
+ * @item data1
+ * The @code{data1} value to match against, if @code{JIT_DEBUGGER_FLAG_DATA1}
+ * is set.
+ *
+ * @item data2
+ * The @code{data2} value to match against, if @code{JIT_DEBUGGER_FLAG_DATA2}
+ * is set.
+ * @end table
+ *
+ * The following special values for @code{data1} are recommended for marking
+ * breakpoint locations with @code{jit_insn_mark_breakpoint}:
+ *
+ * @table @code
+ * @item JIT_DEBUGGER_DATA1_LINE
+ * Breakpoint location that corresponds to a source line.  This is used
+ * to determine where to continue to upon a "step".
+ *
+ * @item JIT_DEBUGGER_DATA1_ENTER
+ * Breakpoint location that corresponds to the start of a function.
+ *
+ * @item JIT_DEBUGGER_DATA1_LEAVE
+ * Breakpoint location that corresponds to the end of a function, just
+ * prior to a @code{return} statement.  This is used to determine where
+ * to continue to upon a "finish".
+ *
+ * @item JIT_DEBUGGER_DATA1_THROW
+ * Breakpoint location that corresponds to an exception throw.
+ * @end table
+ * @end deftypefun
+@*/
+jit_debugger_breakpoint_id_t jit_debugger_add_breakpoint
+               (jit_debugger_t dbg, jit_debugger_breakpoint_info_t info)
+{
+       /* TODO */
+       return 0;
+}
+
+/*@
+ * @deftypefun void jit_debugger_remove_breakpoint (jit_debugger_t dbg, jit_debugger_breakpoint_id_t id)
+ * Remove a previously defined breakpoint from a debugger instance.
+ * @end deftypefun
+@*/
+void jit_debugger_remove_breakpoint
+               (jit_debugger_t dbg, jit_debugger_breakpoint_id_t id)
+{
+       /* TODO */
+}
+
+/*@
+ * @deftypefun void jit_debugger_remove_all_breakpoints (jit_debugger_t dbg)
+ * Remove all breakpoints from a debugger instance.
+ * @end deftypefun
+@*/
+void jit_debugger_remove_all_breakpoints(jit_debugger_t dbg)
+{
+       /* TODO */
+}
+
+/*@
+ * @deftypefun int jit_debugger_is_alive (jit_debugger_t dbg, jit_debugger_thread_id_t thread)
+ * Determine if a particular thread is still alive.
+ * @end deftypefun
+@*/
+int jit_debugger_is_alive(jit_debugger_t dbg, jit_debugger_thread_id_t thread)
+{
+       /* TODO */
+       return 1;
+}
+
+/*@
+ * @deftypefun int jit_debugger_is_running (jit_debugger_t dbg, jit_debugger_thread_id_t thread)
+ * Determine if a particular thread is currently running (non-zero) or
+ * stopped (zero).
+ * @end deftypefun
+@*/
+int jit_debugger_is_running(jit_debugger_t dbg, jit_debugger_thread_id_t thread)
+{
+       jit_debugger_thread_t th;
+       int flag = 0;
+       lock_debugger(dbg);
+       th = get_specific_thread(dbg, thread);
+       if(th)
+       {
+               flag = (th->run_type != JIT_RUN_TYPE_STOPPED);
+       }
+       unlock_debugger(dbg);
+       return flag;
+}
+
+/*@
+ * @deftypefun void jit_debugger_run (jit_debugger_t dbg, jit_debugger_thread_id_t thread)
+ * Start the specified thread running, or continue from the last breakpoint.
+ *
+ * This function, and the others that follow, sends a request to the specified
+ * thread and then returns to the caller immediately.
+ * @end deftypefun
+@*/
+void jit_debugger_run(jit_debugger_t dbg, jit_debugger_thread_id_t thread)
+{
+       jit_debugger_thread_t th;
+       lock_debugger(dbg);
+       th = get_specific_thread(dbg, thread);
+       if(th && th->run_type == JIT_RUN_TYPE_STOPPED)
+       {
+               th->run_type = JIT_RUN_TYPE_CONTINUE;
+               wakeup_all(dbg);
+       }
+       unlock_debugger(dbg);
+}
+
+/*@
+ * @deftypefun void jit_debugger_step (jit_debugger_t dbg, jit_debugger_thread_id_t thread)
+ * Step over a single line of code.  If the line performs a method call,
+ * then this will step into the call.  The request will be ignored if
+ * the thread is currently running.
+ * @end deftypefun
+@*/
+void jit_debugger_step(jit_debugger_t dbg, jit_debugger_thread_id_t thread)
+{
+       jit_debugger_thread_t th;
+       lock_debugger(dbg);
+       th = get_specific_thread(dbg, thread);
+       if(th && th->run_type == JIT_RUN_TYPE_STOPPED)
+       {
+               th->run_type = JIT_RUN_TYPE_STEP;
+               wakeup_all(dbg);
+       }
+       unlock_debugger(dbg);
+}
+
+/*@
+ * @deftypefun void jit_debugger_next (jit_debugger_t dbg, jit_debugger_thread_id_t thread)
+ * Step over a single line of code but do not step into method calls.
+ * The request will be ignored if the thread is currently running.
+ * @end deftypefun
+@*/
+void jit_debugger_next(jit_debugger_t dbg, jit_debugger_thread_id_t thread)
+{
+       jit_debugger_thread_t th;
+       lock_debugger(dbg);
+       th = get_specific_thread(dbg, thread);
+       if(th && th->run_type == JIT_RUN_TYPE_STOPPED)
+       {
+               th->run_type = JIT_RUN_TYPE_NEXT;
+               wakeup_all(dbg);
+       }
+       unlock_debugger(dbg);
+}
+
+/*@
+ * @deftypefun void jit_debugger_finish (jit_debugger_t dbg, jit_debugger_thread_id_t thread)
+ * Keep running until the end of the current function.  The request will
+ * be ignored if the thread is currently running.
+ * @end deftypefun
+@*/
+void jit_debugger_finish(jit_debugger_t dbg, jit_debugger_thread_id_t thread)
+{
+       jit_debugger_thread_t th;
+       lock_debugger(dbg);
+       th = get_specific_thread(dbg, thread);
+       if(th && th->run_type == JIT_RUN_TYPE_STOPPED)
+       {
+               th->run_type = JIT_RUN_TYPE_FINISH;
+               wakeup_all(dbg);
+       }
+       unlock_debugger(dbg);
+}
+
+/*@
+ * @deftypefun void jit_debugger_break (jit_debugger_t dbg)
+ * Force an explicit user breakpoint at the current location within the
+ * current thread.  Control returns to the caller when the debugger
+ * calls one of the above "run" or "step" functions in another thread.
+ * @end deftypefun
+@*/
+void jit_debugger_break(jit_debugger_t dbg)
+{
+       jit_debugger_event_t *event;
+       jit_debugger_thread_t th;
+       lock_debugger(dbg);
+       th = get_current_thread(dbg);
+       if(th && th->breakable)
+       {
+               event = alloc_event();
+               if(event)
+               {
+                       th->run_type = JIT_RUN_TYPE_STOPPED;
+                       th->find_func = 0;
+                       th->last_data1 = 0;
+                       th->last_func_data1 = 0;
+                       event->type = JIT_DEBUGGER_TYPE_USER_BREAKPOINT;
+                       event->thread = th->id;
+                       event->trace = jit_exception_get_stack_trace();
+                       add_event(dbg, event);
+                       suspend_thread(dbg, th);
+               }
+       }
+       unlock_debugger(dbg);
+}
+
+/*@
+ * @deftypefun void jit_debugger_quit (jit_debugger_t dbg)
+ * Sends a request to the thread that called @code{jit_debugger_wait_event}
+ * indicating that the debugger should quit.
+ * @end deftypefun
+@*/
+void jit_debugger_quit(jit_debugger_t dbg)
+{
+       jit_debugger_event_t *event;
+       lock_debugger(dbg);
+       event = alloc_event();
+       if(event)
+       {
+               event->type = JIT_DEBUGGER_TYPE_QUIT;
+               add_event(dbg, event);
+       }
+       unlock_debugger(dbg);
+}
+
+/*@
+ * @deftypefun jit_debugger_hook_func jit_debugger_set_hook (jit_context_t context, jit_debugger_hook_func hook)
+ * Set a debugger hook on a JIT context.  Returns the previous hook.
+ *
+ * Debug hooks are a very low-level breakpoint mechanism.  Upon reaching each
+ * breakpoint in a function, a user-supplied hook function is called.
+ * It is up to the hook function to decide whether to stop execution
+ * or to ignore the breakpoint.  The hook function has 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.
+ *
+ * Hook functions can be used for other purposes besides breakpoint
+ * debugging.  For example, 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.
+ *
+ * By convention, @code{data1} values less than 10000 are intended for
+ * use by user-defined hook functions.  Values of 10000 and greater are
+ * reserved for the full-blown debugger system described earlier.
+ * @end deftypefun
+@*/
+jit_debugger_hook_func jit_debugger_set_hook
+               (jit_context_t context, jit_debugger_hook_func hook)
+{
+       jit_debugger_hook_func prev;
+       if(context)
+       {
+               prev = context->debug_hook;
+               context->debug_hook = hook;
+               return prev;
+       }
+       else
+       {
+               return 0;
+       }
+}
+
+void _jit_debugger_hook(jit_function_t func, jit_nint data1, jit_nint data2)
+{
+       jit_context_t context;
+       jit_debugger_t dbg;
+       jit_debugger_thread_t th;
+       jit_debugger_event_t *event;
+       int stop;
+
+       /* Find the context and look for a user-supplied debug hook */
+       context = func->context;
+       if(context->debug_hook)
+       {
+               (*(context->debug_hook))(func, data1, data2);
+       }
+
+       /* Ignore breakpoints with data1 values less than 10000.  These are
+          presumed to be handled by a user-supplied debug hook instead */
+       if(data1 < JIT_DEBUGGER_DATA1_FIRST)
+       {
+               return;
+       }
+
+       /* Determine if there is a debugger attached to the context */
+       dbg = context->debugger;
+       if(!dbg)
+       {
+               return;
+       }
+
+       /* Lock down the debugger while we do this */
+       lock_debugger(dbg);
+
+       /* Get the current thread's information block */
+       th = get_current_thread(dbg);
+       if(!th || !(th->breakable))
+       {
+               unlock_debugger(dbg);
+               return;
+       }
+
+       /* Determine if there is a hard breakpoint at this location */
+       /* TODO */
+
+       /* Determine if we are looking for a soft breakpoint */
+       stop = 0;
+       switch(th->run_type)
+       {
+               case JIT_RUN_TYPE_STEP:
+               {
+                       /* Stop at all breakpoints */
+                       stop = 1;
+               }
+               break;
+
+               case JIT_RUN_TYPE_NEXT:
+               {
+                       /* Stop only if we are in the same function as the last stopping
+                          point, or if we might have already left the function */
+                       if(func == th->find_func || th->find_func == 0 ||
+                          th->last_func_data1 == JIT_DEBUGGER_DATA1_LEAVE ||
+                          th->last_data1 == JIT_DEBUGGER_DATA1_THROW)
+                       {
+                               stop = 1;
+                       }
+                       if(func == th->find_func)
+                       {
+                               th->last_func_data1 = data1;
+                       }
+               }
+               break;
+
+               case JIT_RUN_TYPE_FINISH:
+               {
+                       /* Stop if we are at a leave point, or we saw an exception */
+                       if((func == th->find_func && data1 == JIT_DEBUGGER_DATA1_LEAVE) ||
+                          th->last_data1 == JIT_DEBUGGER_DATA1_THROW ||
+                          th->find_func == 0)
+                       {
+                               stop = 1;
+                       }
+               }
+               break;
+       }
+       th->last_data1 = data1;
+
+       /* Do we need to stop the thread at this breakpoint? */
+       if(stop)
+       {
+               event = alloc_event();
+               if(event)
+               {
+                       th->run_type = JIT_RUN_TYPE_STOPPED;
+                       th->find_func = func;
+                       th->last_func_data1 = data1;
+                       event->type = JIT_DEBUGGER_TYPE_SOFT_BREAKPOINT;
+                       event->thread = th->id;
+                       event->function = func;
+                       event->data1 = data1;
+                       event->data2 = data2;
+                       event->trace = jit_exception_get_stack_trace();
+                       add_event(dbg, event);
+                       suspend_thread(dbg, th);
+               }
+       }
+
+       /* Unlock and exit */
+       unlock_debugger(dbg);
+}
index b0b7a9c8942ac650e1146f5eeceaea688ae79ddd..968487a94955a5044c808d918116269892217ff9 100644 (file)
@@ -7694,27 +7694,6 @@ int jit_insn_mark_offset(jit_function_t func, jit_int offset)
                                                                (func, jit_type_int, offset));
 }
 
-#if !defined(JIT_BACKEND_INTERP)
-
-/*
- * Perform first-level debug hook testing.
- */
-void _jit_hook_test(jit_function_t func, jit_nint data1, jit_nint data2)
-{
-       if(func->breakpoints_enabled || func->context->breakpoints_enabled)
-       {
-               jit_debug_hook_func hook;
-               hook = (jit_debug_hook_func)
-                       jit_context_get_meta(func->context, JIT_OPTION_DEBUG_HOOK);
-               if(hook)
-               {
-                       (*hook)(func, data1, data2);
-               }
-       }
-}
-
-#endif /* !JIT_BACKEND_INTERP */
-
 /* Documentation is in jit-debug.c */
 int jit_insn_mark_breakpoint
        (jit_function_t func, jit_nint data1, jit_nint data2)
@@ -7731,7 +7710,7 @@ int jit_insn_mark_breakpoint
                                       jit_value_create_nint_constant
                                                        (func, jit_type_nint, data2));
 #else
-       /* Insert a call to "_jit_hook_test" on native platforms */
+       /* Insert a call to "_jit_debugger_hook" on native platforms */
        jit_type_t params[3];
        jit_type_t signature;
        jit_value_t values[3];
@@ -7762,7 +7741,7 @@ int jit_insn_mark_breakpoint
                jit_type_free(signature);
                return 0;
        }
-       jit_insn_call_native(func, "_jit_hook_test", (void *)_jit_hook_test,
+       jit_insn_call_native(func, "_jit_debugger_hook", (void *)_jit_debugger_hook,
                                                 signature, values, 3, JIT_CALL_NOTHROW);
        jit_type_free(signature);
        return 1;
index e1ec2246b402b810a5c4da97366c78872d5c050e..e2255aa92290dd2785ff1e3f28abe1945ba79533 100644 (file)
@@ -377,7 +377,6 @@ struct _jit_function
        int                                     has_try : 1;
        int                                     optimization_level : 8;
        int volatile            is_compiled;
-       int volatile            breakpoints_enabled;
 
        /* The entry point for the function's compiled code */
        void * volatile         entry_point;
@@ -459,8 +458,9 @@ struct _jit_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;
+       /* Debugger support */
+       jit_debugger_hook_func debug_hook;
+       jit_debugger_t          debugger;
 };
 
 /*
@@ -575,6 +575,11 @@ int _jit_load_opcode(int base_opcode, jit_type_t type,
  */
 int _jit_store_opcode(int base_opcode, int small_base, jit_type_t type);
 
+/*
+ * Function that is called upon each breakpoint location.
+ */
+void _jit_debugger_hook(jit_function_t func, jit_nint data1, jit_nint data2);
+
 /*
  * Internal structure of a type descriptor.
  */
index 8cf2b082b808578b895ded45c45ea816f5441323..b035d5040746f745849d80053cc6319331a88a2c 100644 (file)
@@ -4462,20 +4462,14 @@ void _jit_run_function(jit_function_interp_t func, jit_item *args,
 
                VMCASE(JIT_OP_MARK_BREAKPOINT):
                {
-                       /* Process a breakpoint within the current function */
-                       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);
-                               }
-                       }
+                       /* Process a marked breakpoint within the current function */
+                       tempptr = (void *)VM_NINT_ARG;
+                       tempptr2 = (void *)VM_NINT_ARG2;
                        VM_MODIFY_PC_AND_STACK(3, 0);
+                       _jit_backtrace_push(&call_trace, pc);
+                       _jit_debugger_hook
+                               (func->func, (jit_nint)tempptr, (jit_nint)tempptr2);
+                       _jit_backtrace_pop();
                }
                VMBREAK;