* [PATCH 1/4] Adds a new header file, jit-reader.h.in.
2011-07-24 16:00 JIT debug info parser Sanjoy Das
@ 2011-07-24 16:00 ` Sanjoy Das
2011-07-28 16:39 ` Tom Tromey
2011-07-24 16:00 ` [PATCH 3/4] Adds documentation Sanjoy Das
` (2 subsequent siblings)
3 siblings, 1 reply; 9+ messages in thread
From: Sanjoy Das @ 2011-07-24 16:00 UTC (permalink / raw)
To: gdb-patches; +Cc: Sanjoy Das
jit-reader.h.in will host the interface to be implemented and the API to be used by the reader. The file needs to be processed by ./configure to get the correct typedef for GDB_CORE_ADDR.
This commit also adds a #define to config.in - GDB_JIT_READER_PATH. This is the default location in the filesystem from which the readers are loaded. The configure script is also modified to replace HOST_U_64_BIT with a correct data-type in jit-reader.h.in.
gdb/ChangeLog
* jit-reader.h.in: New header.
* config.in: Add GDB_JIT_READER_PATH.
* configure.ac: Compute HOST_U_64_BIT (jit-reader.h.in) and GDB_JIT_READER_PATH.
---
gdb/ChangeLog | 6 ++
gdb/Makefile.in | 13 ++++--
gdb/config.in | 3 +
gdb/configure | 132 +++++++++++++++++++++++++++++++++++++++++++++++++++
gdb/configure.ac | 27 ++++++++++
gdb/jit-reader.h.in | 53 ++++++++++++++++++++
6 files changed, 230 insertions(+), 4 deletions(-)
create mode 100644 gdb/jit-reader.h.in
diff --git a/gdb/ChangeLog b/gdb/ChangeLog
index 3ba870b..2cc82bc 100644
--- a/gdb/ChangeLog
+++ b/gdb/ChangeLog
@@ -1,3 +1,9 @@
+2011-07-24 Sanjoy Das <sdas@igalia.com>
+
+ * jit-reader.h.in: New header.
+ * config.in: Add HAVE_LIBDL and GDB_JIT_READER_PATH.
+ * configure.ac: Check for libdl. Compute HOST_U_64_BIT (jit-reader.h.in) and GDB_JIT_READER_PATH.
+
2011-07-23 Paul Pluzhnikov <ppluzhnikov@google.com>
* elfread.c (elf_rel_plt_read): Fix off-by-one bug.
diff --git a/gdb/Makefile.in b/gdb/Makefile.in
index 46593e3..7ed6136 100644
--- a/gdb/Makefile.in
+++ b/gdb/Makefile.in
@@ -824,7 +824,7 @@ common/linux-osdata.h
# Header files that already have srcdir in them, or which are in objdir.
-HFILES_WITH_SRCDIR = ../bfd/bfd.h
+HFILES_WITH_SRCDIR = ../bfd/bfd.h jit-reader.h
# GDB "info" files, which should be included in their entirety
@@ -941,7 +941,7 @@ DISTSTUFF = $(YYFILES)
# All generated files which can be included by another file.
-generated_files = config.h observer.h observer.inc ada-lex.c \
+generated_files = config.h observer.h observer.inc ada-lex.c jit-reader.h \
$(GNULIB_H) $(NAT_GENERATED_FILES)
.c.o:
@@ -1026,7 +1026,9 @@ install-only: $(CONFIG_INSTALL)
$(SHELL) $(srcdir)/../mkinstalldirs \
$(DESTDIR)$(man1dir) ; \
$(INSTALL_DATA) $(srcdir)/gdb.1 \
- $(DESTDIR)$(man1dir)/$$transformed_name.1
+ $(DESTDIR)$(man1dir)/$$transformed_name.1 ; \
+ $(SHELL) $(srcdir)/../mkinstalldirs $(includedir)/gdb ; \
+ $(INSTALL_DATA) jit-reader.h $(includedir)/gdb/jit-reader.h
@$(MAKE) DO=install "DODIRS=$(SUBDIRS)" $(FLAGS_TO_PASS) subdir_do
.PHONY: install-tui
install-tui:
@@ -1254,7 +1256,7 @@ distclean: clean
rm -f gdbserver/config.status gdbserver/config.log
rm -f gdbserver/tm.h gdbserver/xm.h gdbserver/nm.h
rm -f gdbserver/Makefile gdbserver/config.cache
- rm -f nm.h config.status config.h stamp-h .gdbinit
+ rm -f nm.h config.status config.h stamp-h .gdbinit jit-reader.h
rm -f y.output yacc.acts yacc.tmp y.tab.h
rm -f config.log config.cache
rm -f Makefile
@@ -1320,6 +1322,9 @@ data-directory/Makefile: data-directory/Makefile.in config.status @frags@
CONFIG_LINKS= \
$(SHELL) config.status
+jit-reader.h: $(srcdir)/jit-reader.h.in
+ $(SHELL) config.status $@
+
config.h: stamp-h ; @true
stamp-h: $(srcdir)/config.in config.status
CONFIG_HEADERS=config.h:config.in \
diff --git a/gdb/config.in b/gdb/config.in
index c1d7c68..8862144 100644
--- a/gdb/config.in
+++ b/gdb/config.in
@@ -982,3 +982,6 @@
/* Define as `fork' if `vfork' does not work. */
#undef vfork
+
+/* The directory to search for JIT debug info reader plugins. */
+#undef GDB_JIT_READER_PATH
diff --git a/gdb/configure b/gdb/configure
index ac143e4..3d984c7 100755
--- a/gdb/configure
+++ b/gdb/configure
@@ -666,6 +666,7 @@ python_prog_path
LTLIBEXPAT
LIBEXPAT
HAVE_LIBEXPAT
+HOST_U_64_BIT
READLINE_TEXI_INCFLAG
READLINE_CFLAGS
READLINE_DEPS
@@ -9807,6 +9808,136 @@ fi
+# Generate jit-reader.h
+
+# This is typedeffed to GDB_CORE_ADDR in jit-reader.h
+HOST_U_64_BIT=
+
+# The cast to long int works around a bug in the HP C Compiler
+# version HP92453-01 B.11.11.23709.GP, which incorrectly rejects
+# declarations like `int a3[[(sizeof (unsigned char)) >= 0]];'.
+# This bug is HP SR number 8606223364.
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking size of unsigned long long" >&5
+$as_echo_n "checking size of unsigned long long... " >&6; }
+if test "${ac_cv_sizeof_unsigned_long_long+set}" = set; then :
+ $as_echo_n "(cached) " >&6
+else
+ if ac_fn_c_compute_int "$LINENO" "(long int) (sizeof (unsigned long long))" "ac_cv_sizeof_unsigned_long_long" "$ac_includes_default"; then :
+
+else
+ if test "$ac_cv_type_unsigned_long_long" = yes; then
+ { { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5
+$as_echo "$as_me: error: in \`$ac_pwd':" >&2;}
+{ as_fn_set_status 77
+as_fn_error "cannot compute sizeof (unsigned long long)
+See \`config.log' for more details." "$LINENO" 5; }; }
+ else
+ ac_cv_sizeof_unsigned_long_long=0
+ fi
+fi
+
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_sizeof_unsigned_long_long" >&5
+$as_echo "$ac_cv_sizeof_unsigned_long_long" >&6; }
+
+
+
+cat >>confdefs.h <<_ACEOF
+#define SIZEOF_UNSIGNED_LONG_LONG $ac_cv_sizeof_unsigned_long_long
+_ACEOF
+
+
+# The cast to long int works around a bug in the HP C Compiler
+# version HP92453-01 B.11.11.23709.GP, which incorrectly rejects
+# declarations like `int a3[[(sizeof (unsigned char)) >= 0]];'.
+# This bug is HP SR number 8606223364.
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking size of unsigned long" >&5
+$as_echo_n "checking size of unsigned long... " >&6; }
+if test "${ac_cv_sizeof_unsigned_long+set}" = set; then :
+ $as_echo_n "(cached) " >&6
+else
+ if ac_fn_c_compute_int "$LINENO" "(long int) (sizeof (unsigned long))" "ac_cv_sizeof_unsigned_long" "$ac_includes_default"; then :
+
+else
+ if test "$ac_cv_type_unsigned_long" = yes; then
+ { { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5
+$as_echo "$as_me: error: in \`$ac_pwd':" >&2;}
+{ as_fn_set_status 77
+as_fn_error "cannot compute sizeof (unsigned long)
+See \`config.log' for more details." "$LINENO" 5; }; }
+ else
+ ac_cv_sizeof_unsigned_long=0
+ fi
+fi
+
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_sizeof_unsigned_long" >&5
+$as_echo "$ac_cv_sizeof_unsigned_long" >&6; }
+
+
+
+cat >>confdefs.h <<_ACEOF
+#define SIZEOF_UNSIGNED_LONG $ac_cv_sizeof_unsigned_long
+_ACEOF
+
+
+# The cast to long int works around a bug in the HP C Compiler
+# version HP92453-01 B.11.11.23709.GP, which incorrectly rejects
+# declarations like `int a3[[(sizeof (unsigned char)) >= 0]];'.
+# This bug is HP SR number 8606223364.
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking size of unsigned __int128" >&5
+$as_echo_n "checking size of unsigned __int128... " >&6; }
+if test "${ac_cv_sizeof_unsigned___int128+set}" = set; then :
+ $as_echo_n "(cached) " >&6
+else
+ if ac_fn_c_compute_int "$LINENO" "(long int) (sizeof (unsigned __int128))" "ac_cv_sizeof_unsigned___int128" "$ac_includes_default"; then :
+
+else
+ if test "$ac_cv_type_unsigned___int128" = yes; then
+ { { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5
+$as_echo "$as_me: error: in \`$ac_pwd':" >&2;}
+{ as_fn_set_status 77
+as_fn_error "cannot compute sizeof (unsigned __int128)
+See \`config.log' for more details." "$LINENO" 5; }; }
+ else
+ ac_cv_sizeof_unsigned___int128=0
+ fi
+fi
+
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_sizeof_unsigned___int128" >&5
+$as_echo "$ac_cv_sizeof_unsigned___int128" >&6; }
+
+
+
+cat >>confdefs.h <<_ACEOF
+#define SIZEOF_UNSIGNED___INT128 $ac_cv_sizeof_unsigned___int128
+_ACEOF
+
+
+
+if test "x${ac_cv_sizeof_unsigned_long}" = "x8"; then
+ HOST_U_64_BIT="unsigned long"
+elif test "x${ac_cv_sizeof_unsigned_long_long}" = "x8"; then
+ HOST_U_64_BIT="unsigned long long"
+elif test "x${ac_cv_sizeof_unsigned___int128}" = "x16"; then
+ HOST_U_64_BIT="unsigned __int128"
+else
+ as_fn_error "could not find a 64 bit integer type" "$LINENO" 5
+fi
+
+# The default path from which to load readers
+GDB_JIT_READER_PATH="${prefix}/lib/gdb"
+
+cat >>confdefs.h <<_ACEOF
+#define GDB_JIT_READER_PATH "$GDB_JIT_READER_PATH"
+_ACEOF
+
+
+
+ac_config_files="$ac_config_files jit-reader.h:jit-reader.h.in"
+
+
# Check whether --with-expat was given.
if test "${with_expat+set}" = set; then :
@@ -16717,6 +16848,7 @@ do
"config.h") CONFIG_HEADERS="$CONFIG_HEADERS config.h:config.in" ;;
"depdir") CONFIG_COMMANDS="$CONFIG_COMMANDS depdir" ;;
"depfiles") CONFIG_COMMANDS="$CONFIG_COMMANDS depfiles" ;;
+ "jit-reader.h") CONFIG_FILES="$CONFIG_FILES jit-reader.h:jit-reader.h.in" ;;
"$ac_config_links_1") CONFIG_LINKS="$CONFIG_LINKS $ac_config_links_1" ;;
"Makefile") CONFIG_FILES="$CONFIG_FILES Makefile" ;;
".gdbinit") CONFIG_FILES="$CONFIG_FILES .gdbinit:gdbinit.in" ;;
diff --git a/gdb/configure.ac b/gdb/configure.ac
index 8c12a44..19263c1 100644
--- a/gdb/configure.ac
+++ b/gdb/configure.ac
@@ -573,6 +573,33 @@ AC_SUBST(READLINE_DEPS)
AC_SUBST(READLINE_CFLAGS)
AC_SUBST(READLINE_TEXI_INCFLAG)
+# Generate jit-reader.h
+
+# This is typedeffed to GDB_CORE_ADDR in jit-reader.h
+HOST_U_64_BIT=
+
+AC_CHECK_SIZEOF(unsigned long long)
+AC_CHECK_SIZEOF(unsigned long)
+AC_CHECK_SIZEOF(unsigned __int128)
+
+if test "x${ac_cv_sizeof_unsigned_long}" = "x8"; then
+ HOST_U_64_BIT="unsigned long"
+elif test "x${ac_cv_sizeof_unsigned_long_long}" = "x8"; then
+ HOST_U_64_BIT="unsigned long long"
+elif test "x${ac_cv_sizeof_unsigned___int128}" = "x16"; then
+ HOST_U_64_BIT="unsigned __int128"
+else
+ AC_MSG_ERROR([could not find a 64 bit integer type])
+fi
+
+# The default path from which to load readers
+GDB_JIT_READER_PATH="${prefix}/lib/gdb"
+AC_DEFINE_UNQUOTED(GDB_JIT_READER_PATH, "$GDB_JIT_READER_PATH",
+ [The directory to look for JIT debug info readers])
+
+AC_SUBST(HOST_U_64_BIT)
+AC_CONFIG_FILES([jit-reader.h:jit-reader.h.in])
+
AC_ARG_WITH(expat,
AS_HELP_STRING([--with-expat], [include expat support (auto/yes/no)]),
[], [with_expat=auto])
diff --git a/gdb/jit-reader.h.in b/gdb/jit-reader.h.in
new file mode 100644
index 0000000..94f9a95
--- /dev/null
+++ b/gdb/jit-reader.h.in
@@ -0,0 +1,53 @@
+/* JIT declarations for GDB, the GNU Debugger.
+
+ Copyright (C) 2011 Free Software Foundation, Inc.
+
+ This file is part of GDB.
+
+ 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 3 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, see <http://www.gnu.org/licenses/>. */
+
+#ifndef GDB_JIT_READER_H
+#define GDB_JIT_READER_H
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/* For the reader to be correctly loaded and used, some versioning information
+ needs to be added to the shared object. This is done by invoking the macro
+ GDB_DECLARE_READER_INTERFACE_VERSION in a source file. */
+#define GDB_READER_INTERFACE_VERSION 1
+#define GDB_DECLARE_READER_INTERFACE_VERSION \
+ extern int __gdb_reader_interface_version (void) \
+ { \
+ return GDBJIT_INTERFACE_VERSION; \
+ }
+
+/* Readers must be released under a GPL compatible license. To declare that the
+ reader is indeed released under a GPL compatible license, invoke the macro
+ GDB_DECLARE_GPL_COMPATIBLE in a source file. */
+#define GDB_DECLARE_GPL_COMPATIBLE_READER \
+ extern int plugin_is_GPL_compatible (void) \
+ { \
+ return 0; \
+ } \
+
+/* Represents an address on the target system. */
+typedef @HOST_U_64_BIT@ GDB_CORE_ADDR;
+
+#ifdef __cplusplus
+} /* extern "C" */
+#endif
+
+#endif
--
1.7.5.4
^ permalink raw reply [flat|nested] 9+ messages in thread* Re: [PATCH 1/4] Adds a new header file, jit-reader.h.in.
2011-07-24 16:00 ` [PATCH 1/4] Adds a new header file, jit-reader.h.in Sanjoy Das
@ 2011-07-28 16:39 ` Tom Tromey
0 siblings, 0 replies; 9+ messages in thread
From: Tom Tromey @ 2011-07-28 16:39 UTC (permalink / raw)
To: Sanjoy Das; +Cc: gdb-patches
>>>>> "Sanjoy" == Sanjoy Das <sanjoy@playingwithpointers.com> writes:
Sanjoy> jit-reader.h.in will host the interface to be implemented and
Sanjoy> the API to be used by the reader. The file needs to be processed
Sanjoy> by ./configure to get the correct typedef for GDB_CORE_ADDR.
Sanjoy> +AC_CHECK_SIZEOF(unsigned long long)
Sanjoy> +AC_CHECK_SIZEOF(unsigned long)
Sanjoy> +AC_CHECK_SIZEOF(unsigned __int128)
Sanjoy> +
Sanjoy> +if test "x${ac_cv_sizeof_unsigned_long}" = "x8"; then
Sanjoy> + HOST_U_64_BIT="unsigned long"
Sanjoy> +elif test "x${ac_cv_sizeof_unsigned_long_long}" = "x8"; then
Sanjoy> + HOST_U_64_BIT="unsigned long long"
Sanjoy> +elif test "x${ac_cv_sizeof_unsigned___int128}" = "x16"; then
Sanjoy> + HOST_U_64_BIT="unsigned __int128"
Sanjoy> +else
Sanjoy> + AC_MSG_ERROR([could not find a 64 bit integer type])
It should not be a fatal error if a 64-bit type cannot be found. It is
possible to build GDB on a 32-bit host that does not have a 64-bit type.
Nothing prevents this; you just won't be able to debug 64-bit processes.
Sanjoy> +# The default path from which to load readers
Sanjoy> +GDB_JIT_READER_PATH="${prefix}/lib/gdb"
It is more normal to use libdir here, but then you get into problems
with how configure represents these variables. There may be some
helpful macros in config/, not sure.
Sanjoy> + extern int __gdb_reader_interface_version (void) \
No need for the leading "__".
Tom
^ permalink raw reply [flat|nested] 9+ messages in thread
* [PATCH 3/4] Adds documentation.
2011-07-24 16:00 JIT debug info parser Sanjoy Das
2011-07-24 16:00 ` [PATCH 1/4] Adds a new header file, jit-reader.h.in Sanjoy Das
@ 2011-07-24 16:00 ` Sanjoy Das
2011-07-24 17:51 ` Eli Zaretskii
2011-07-24 17:26 ` [PATCH 2/4] Populates jit-reader.h.in Sanjoy Das
2011-07-24 17:41 ` [PATCH 4/4] Adds platform agnostic dynamic loading code Sanjoy Das
3 siblings, 1 reply; 9+ messages in thread
From: Sanjoy Das @ 2011-07-24 16:00 UTC (permalink / raw)
To: gdb-patches; +Cc: Sanjoy Das
Adds some basic documentation to gdb.texinfo about the new JIT reader functionality. This should be a good entry point for developers writing parsers for the debug info their JIT compiler generates.
gdb/ChangeLog
* gdb.texinfo: Some documentation about the new JIT debug info reader functionality.
---
gdb/ChangeLog | 4 +++
gdb/doc/gdb.texinfo | 66 +++++++++++++++++++++++++++++++++++++++++++++++++++
2 files changed, 70 insertions(+), 0 deletions(-)
diff --git a/gdb/ChangeLog b/gdb/ChangeLog
index 25281f4..656a42d 100644
--- a/gdb/ChangeLog
+++ b/gdb/ChangeLog
@@ -1,4 +1,8 @@
2011-07-24 Sanjoy Das <sdas@igalia.com>
+
+ * gdb.texinfo: Some documentation about the new JIT debug info reader functionality.
+
+2011-07-24 Sanjoy Das <sdas@igalia.com>
* jit-reader.h.in: Add API and interface.
* jit.c: Include jit-reader.h.
diff --git a/gdb/doc/gdb.texinfo b/gdb/doc/gdb.texinfo
index 16bb6bc..3968861 100644
--- a/gdb/doc/gdb.texinfo
+++ b/gdb/doc/gdb.texinfo
@@ -30870,6 +30870,72 @@ Set @code{action_flag} to @code{JIT_UNREGISTER} and call
If the JIT frees or recompiles code without unregistering it, then @value{GDBN}
and the JIT will leak the memory used for the associated symbol files.
+@node Custom Object File Format
+@section Custom Object File Format
+
+Generating debug information in native file formats (like ELF or COFF) can become an overkill for JIT compilers; especially if all the debug info is used for displaying a meaningful backtrace. The issue can be resolved by having the JIT writers decide on a debug info format and provide a third-party reader that parses the debug info generated by the JIT compiler. This section gives an overview on writing such a parser. More details can be found in the file @code{gdb/jit-reader.h.in}.
+
+The reader is implemented as a shared object. GDB, when trying to read the debug information generated by a JIT compiler, looks for such shared objects in a special, pre-configured, directory. If such a (conforming) shared object is found, it is dynamically loaded and used to parse the debug info.
+
+@node Writing A Parser
+@subsection Writing A Parser
+
+The parser needs to include @code{jit-reader.h}, which defines the required structures, macros and functions.
+
+@node Elements Of @code{jit-reader.h}
+@subsubsection Elements Of @code{jit-reader.h}
+
+The two macros declared in @code{jit-reader.h} are @code{GDB_DECLARE_READER_INTERFACE_VERSION} and @code{GDB_DECLARE_GPL_COMPATIBLE_READER}. Both of them need to be placed in a source file that will eventually be compiled and linked into the shared object.
+
+@code{GDB_DECLARE_READER_INTERFACE_VERSION} adds code that allows GDB to verify the version of the plugin. @code{GDB_DECLARE_GPL_COMPATIBLE_READER} declares the plugin to be released under a GPL compatible license.
+
+After the plugin is loaded, GDB looks for the function @code{gdb_init_reader}. The prototype of the function (also included in @code{jit-reader.h}) is:
+
+@smallexample
+extern struct gdb_reader_funcs *gdb_init_reader (void);
+@end smallexample
+
+As evident, the function is supposed to return a @code{struct gdb_reader_funcs *} (or @code{NULL}, in case of an error), which contains a set of functions later used to parse the debug info. It is declared thus:
+
+@smallexample
+struct gdb_reader_funcs
+@{
+ gdb_read_debug_info *read;
+ gdb_unwind_frame *unwind;
+ gdb_get_frame_id *get_frame_id;
+ gdb_destroy_reader *destroy;
+
+ void *private;
+@};
+@end smallexample
+
+@code{read} is called to read the debug info, @code{unwind} is called to unwind a frame corresponding to a JITted function, @code{get_frame_id} is supposed to return an unique frame id for a frame and @code{destroy} is called when the plugin is unloaded.
+
+@node The API
+@subsubsection The API
+
+The plugin provides an API for creating symbol files (which GDB will use to, for instance, display function names in the backtrace) and implementing a frame unwinder.
+
+@strong{Symbol Reading}
+
+The @code{read} function in @code{struct gdb_reader_funcs} is called to read in the debug info emitted by the JIT compiler and create the appropriate symbol tables. To keep the API clean and stable, GDB's internal structures are not exposed. Instead, a @code{struct} full of function pointers are passed to @code{read} which it is supposed to use to construct the symbol table.
+
+@strong{Frame Unwinding}
+
+@code{unwind} is called to unwind the current frame into the previous (earlier, outer) frame. The prototype for the @code{unwind} function is:
+
+@smallexample
+int unwind (struct gdb_reader_funcs *self, struct gdb_unwind_callbacks *cb);
+@end smallexample
+
+The first argument is the same @code{struct} that was returned by @code{gdb_init_reader} (so that the reader can persist some data). The second argument, @code{cb} is used to unwind the frame.
+
+Unwinding a frame involves computing the values of the registers in the earlier frame given the values in the current frame. @code{struct gdb_unwind_callbacks} provides the function @code{reg_get} which returns the value of a particular register in the @emph{current} frame. So the @emph{current} frame is, in a way, the frame defined by the register values returned by @code{reg_get}.
+
+The plugin is to use @code{reg_set} to save the predicted values of registers in the outer (earlier) frame. @code{struct gdb_unwind_callbacks} also provides a third function, @code{target_read}, which reads a block of memory from the target's virtual memory.
+
+An example can be made of a JIT compiler whose code maintains the frame pointers: assuming the program counter, the previous frame pointer and the previous stack pointer are all saved at known constant offsets from the frame pointer, we can have a simple unwinder which reads the value of the frame pointer using @code{reg_get}, reads the memory at the known offsets using @code{target_read} and then calls @code{reg_set} on the program counter, frame pointer and stack pointer with the new (now discovered) values. This is usually enough for GDB to generate a meaningful stacktrace.
+
@node GDB Bugs
@chapter Reporting Bugs in @value{GDBN}
@cindex bugs in @value{GDBN}
--
1.7.5.4
^ permalink raw reply [flat|nested] 9+ messages in thread* Re: [PATCH 3/4] Adds documentation.
2011-07-24 16:00 ` [PATCH 3/4] Adds documentation Sanjoy Das
@ 2011-07-24 17:51 ` Eli Zaretskii
0 siblings, 0 replies; 9+ messages in thread
From: Eli Zaretskii @ 2011-07-24 17:51 UTC (permalink / raw)
To: Sanjoy Das; +Cc: gdb-patches
> From: Sanjoy Das <sanjoy@playingwithpointers.com>
> Cc: Sanjoy Das <sanjoy@playingwithpointers.com>
> Date: Sun, 24 Jul 2011 21:33:46 +0530
>
> Adds some basic documentation to gdb.texinfo about the new JIT reader functionality. This should be a good entry point for developers writing parsers for the debug info their JIT compiler generates.
Thanks.
> gdb/ChangeLog
> * gdb.texinfo: Some documentation about the new JIT debug info reader functionality.
This should state the name(s) of the new node(s), in the same format
as gdb/ChangeLog documents functions, as if each node were a function.
> +@node Custom Object File Format
You cannot add a node without also adding it to the menu in its parent
(which happens to be "JIT Interface" in this case). I guess you
didn't actually say "make info", because I don't think it would have
worked for you.
> +@section Custom Object File Format
As a general rule, each @section should have a @cindex entry whose
text is identical to the section name, but with all lower-case
letters.
> +Generating debug information in native file formats (like ELF or COFF) can become an overkill for JIT compilers; especially if all the debug info is used for displaying a meaningful backtrace. The issue can be resolved by having the JIT writers decide on a debug info format and provide a third-party reader that parses the debug info generated by the JIT compiler. This section gives an overview on writing such a parser. More details can be found in the file @code{gdb/jit-reader.h.in}.
First, please don't make such long lines, they make reading harder.
Second, please leave 2 spaces after a period that ends a sentence.
And third, "gdb/jit-reader.h.in" is a file, so it should have the
@file markup, not @code.
> +The reader is implemented as a shared object. GDB, when trying to read the debug information generated by a JIT compiler, looks for such shared objects in a special, pre-configured, directory. If such a (conforming) shared object is found, it is dynamically loaded and used to parse the debug info.
Please use "@value{GDBN}" instead of a literal "GDB". That allows to
change the name in only one place, if someone wants to produce a
manual for a customized GDB that has a different name.
> +@node Writing A Parser
> +@subsection Writing A Parser
There should be a @menu in the previous node before you can use a
@subsection here.
Please add an index entry here, something like
@cindex JIT parser
@cindex writing JIT parsers
> +The parser needs to include @code{jit-reader.h}, which defines the required structures, macros and functions.
^^^^^
@file
> +@node Elements Of @code{jit-reader.h}
A @node cannot use @-commands. So just "Elements of jit-reader.h"
Also, this node has to appear in a menu, see above.
> +@subsubsection Elements Of @code{jit-reader.h}
^^^^^
@file
> +After the plugin is loaded, GDB looks for the function @code{gdb_init_reader}. The prototype of the function (also included in @code{jit-reader.h}) is:
^^^^^
@file
> +@node The API
Should be in a menu.
> +The plugin provides an API for creating symbol files (which GDB will use to, for instance, display function names in the backtrace) and implementing a frame unwinder.
^^^
@value{GDBN}
> +@strong{Symbol Reading}
If this is supposed to be a heading, please use @heading.
> +The @code{read} function in @code{struct gdb_reader_funcs} is called to read in the debug info emitted by the JIT compiler and create the appropriate symbol tables. To keep the API clean and stable, GDB's internal structures are not exposed. Instead, a @code{struct} full of function pointers are passed to @code{read} which it is supposed to use to construct the symbol table.
Again, @value{GDBN}.
^ permalink raw reply [flat|nested] 9+ messages in thread
* [PATCH 2/4] Populates jit-reader.h.in
2011-07-24 16:00 JIT debug info parser Sanjoy Das
2011-07-24 16:00 ` [PATCH 1/4] Adds a new header file, jit-reader.h.in Sanjoy Das
2011-07-24 16:00 ` [PATCH 3/4] Adds documentation Sanjoy Das
@ 2011-07-24 17:26 ` Sanjoy Das
2011-07-28 16:40 ` Tom Tromey
2011-07-24 17:41 ` [PATCH 4/4] Adds platform agnostic dynamic loading code Sanjoy Das
3 siblings, 1 reply; 9+ messages in thread
From: Sanjoy Das @ 2011-07-24 17:26 UTC (permalink / raw)
To: gdb-patches; +Cc: Sanjoy Das
Adds the interface to be implemented by the JIT debug-info readers and the API they can use to jit-reader.h.in.
gdb/ChangeLog
* jit-reader.h.in: Add API and interface.
* jit.c: Include jit-reader.h.
---
gdb/ChangeLog | 4 +
gdb/jit-reader.h.in | 196 +++++++++++++++++++++++++++++++++++++++++++++++++++
gdb/jit.c | 1 +
3 files changed, 201 insertions(+), 0 deletions(-)
diff --git a/gdb/ChangeLog b/gdb/ChangeLog
index 2cc82bc..25281f4 100644
--- a/gdb/ChangeLog
+++ b/gdb/ChangeLog
@@ -1,4 +1,8 @@
2011-07-24 Sanjoy Das <sdas@igalia.com>
+ * jit-reader.h.in: Add API and interface.
+ * jit.c: Include jit-reader.h.
+
+2011-07-24 Sanjoy Das <sdas@igalia.com>
* jit-reader.h.in: New header.
* config.in: Add HAVE_LIBDL and GDB_JIT_READER_PATH.
diff --git a/gdb/jit-reader.h.in b/gdb/jit-reader.h.in
index 94f9a95..a525ec8 100644
--- a/gdb/jit-reader.h.in
+++ b/gdb/jit-reader.h.in
@@ -46,6 +46,202 @@ extern "C" {
/* Represents an address on the target system. */
typedef @HOST_U_64_BIT@ GDB_CORE_ADDR;
+/* Return status codes. */
+enum {
+ GDB_FAIL = 0,
+ GDB_SUCCESS = 1
+};
+
+#define GDB_MAX_REGISTER_SIZE 64 /* Mirrors the internal GDB definition. */
+
+struct gdb_symtab;
+struct gdb_block;
+struct gdb_symbol;
+struct gdb_symtab_callbacks;
+
+/* An array of these are used to represent a map from code addresses to line
+ numbers in the source file. */
+struct gdb_line_mapping
+{
+ int line;
+ GDB_CORE_ADDR pc;
+};
+
+/* The callback used to create new symbol table.
+ CB is the gdb_symtab_callbacks which the structure is part of.
+ FILE_NAME is an (optionally NULL) file name to associate with this new symbol
+ table.
+
+ Returns a new instance to gdb_symtab that can later be passed to
+ gdb_block_new, gdb_symtab_add_line_mapping and gdb_symtab_close.
+*/
+typedef struct gdb_symtab *(gdb_symtab_new) (struct gdb_symtab_callbacks *cb,
+ const char *file_name);
+
+/* Creates a new block in a given symbol table. A symbol table is a forest of
+ blocks, each block representing an code address range and a corresponding
+ (optionally NULL) NAME. In case the block corresponds to a function, the NAME
+ passed should be the name of the function.
+
+ If the new block to be created is a child of (i.e. is nested in) another
+ block, the parent block can be passed in PARENT. SYMTAB is the symbol table
+ the new block is to belong in. BEGIN, END is the code address range the block
+ corresponds to.
+
+ Returns a new instance of gdb_block, which, as of now, has no use. Note that
+ the gdb_block returned must not be freed by the caller. */
+typedef struct gdb_block *(gdb_block_new) (struct gdb_symtab_callbacks *cb,
+ struct gdb_symtab *symtab,
+ struct gdb_block *parent,
+ GDB_CORE_ADDR begin,
+ GDB_CORE_ADDR end,
+ const char *name);
+
+/* Adds a PC to line number mapping for the symbol table SYMTAB. NLINES is the
+ number of elements in LINES, each element corresponding to one (PC, line)
+ pair. */
+typedef void (gdb_symtab_add_line_mapping) (struct gdb_symtab_callbacks *cb,
+ struct gdb_symtab *symtab,
+ int nlines,
+ struct gdb_line_mapping *lines);
+
+/* Frees the symbol table SYMTAB, after adding it to GDB's internal structures.
+ Every gdb_symtab_new must be paired with a gdb_symtab_free. */
+typedef void (gdb_symtab_free) (struct gdb_symtab_callbacks *cb,
+ struct gdb_symtab *symtab);
+
+/* Reads LEN bytes from TARGET_MEM in the target's virtual address space into
+ GDB_BUF.
+
+ Returns GDB_FAIL on failure, and GDB_SUCCESS on success. */
+typedef int (gdb_target_read) (GDB_CORE_ADDR target_mem, void *gdb_buf,
+ int len);
+
+/* The list of callbacks that are passed to read. These callbacks are to be used
+ to construct the symbol table. The functions have been described above. */
+struct gdb_symtab_callbacks
+{
+ gdb_symtab_new *symtab_open;
+ gdb_block_new *new_block;
+ gdb_symtab_add_line_mapping *add_line_mapping;
+ gdb_target_read *target_read;
+ gdb_symtab_free *symtab_close;
+
+ /* For internal use. */
+ void *private;
+};
+
+/* Denotes the value of a register. The value is valid only if defined is set to
+ non-zero. */
+struct gdb_reg_value
+{
+ int defined;
+ unsigned char value[GDB_MAX_REGISTER_SIZE];
+};
+
+/* get_frame_id in gdb_reader_funcs is required to return a gdb_frame_id
+ corresponding to the current frame. The registers corresponding to the
+ current frame can be read using reg_get. A frame should correspond to the
+ same gdb_frame_id throughout its lifetime (i.e. before it gets unwound). This
+ can usually be accomplished by having the CODE_ADDRESS point to the
+ function's first instruction and STACK_ADDRESS point to the value of the
+ stack pointer when entering the function. */
+struct gdb_frame_id
+{
+ GDB_CORE_ADDR code_address;
+ GDB_CORE_ADDR stack_address;
+};
+
+/* Forward declaration. */
+struct gdb_unwind_callbacks;
+
+/* Returns the value of a particular register in the current frame. The current
+ frame is the frame that needs to be unwound into the outer (earlier) frame.
+
+ CB is the struct gdb_unwind_callbacks * the callback belongs to. REGNUM is
+ the DWARF register number of the register that needs to be unwound.
+
+ Returns the gdb_reg_value corresponding to the register requested. Note that
+ in case the value of the register has been optimized away or otherwise
+ unavailable, the defined flag in the returned gdb_reg_value will be zero. */
+typedef struct gdb_reg_value (gdb_unwind_reg_get) (struct gdb_unwind_callbacks *
+ cb, int regnum);
+
+/* Sets the previous value of a particular register. REGNUM is (DWARF) register
+ number whose value is to be set. VAL is the value the register is to be set
+ to.
+
+ Note that a register can also be "set" to an undefined value by setting the
+ defined in VAL to zero. */
+typedef void (gdb_unwind_reg_set) (struct gdb_unwind_callbacks *cb, int regnum,
+ struct gdb_reg_value val);
+
+/* This struct is passed to unwind in gdb_reader_funcs, and is to be used to
+ unwind the current frame (current being the frame whose registers can be read
+ using reg_get) into the earlier frame. The functions have been described
+ above. */
+struct gdb_unwind_callbacks
+{
+ gdb_unwind_reg_get *reg_get;
+ gdb_unwind_reg_set *reg_set;
+ gdb_target_read *target_read;
+
+ /* For internal use. */
+ void *private;
+};
+
+/* Forward declaration. */
+struct gdb_reader_funcs;
+
+/* Tries to parse the debug info off a block of memory, pointed to by MEMORY
+ (already copied to GDB's address space) and MEMORY_SZ bytes long.
+ As mentioned, gdb_read_debug_info is expected to use the functions in
+ CB to actually emit the parsed data into GDB. SELF is the same structure
+ returned by gdb_init_reader.
+
+ Returns GDB_FAIL on failure and GDB_SUCCESS on success. */
+typedef int (gdb_read_debug_info) (struct gdb_reader_funcs *self,
+ struct gdb_symtab_callbacks *cb,
+ void *memory, long memory_sz);
+
+/* Tries to unwind the current frame, CB is the set of unwind callbacks that are
+ to be used to do this.
+
+ Returns GDB_FAIL on failure and GDB_SUCCESS on success. */
+typedef int (gdb_unwind_frame) (struct gdb_reader_funcs *self,
+ struct gdb_unwind_callbacks *cb);
+
+/* Returns the frame ID corresponding to the current frame, using C to read
+ the current register values. See the comment on struct gdb_frame_id. */
+typedef struct gdb_frame_id (gdb_get_frame_id) (struct gdb_reader_funcs *self,
+ struct gdb_unwind_callbacks *c);
+
+/* Called when a reader is being unloaded. This function should also free SELF,
+ in case it was malloced. */
+typedef void (gdb_destroy_reader) (struct gdb_reader_funcs *self);
+
+/* Called when the reader is loaded. Must either return a properly populated
+ gdb_reader_funcs or NULL (indicating an error). The memory allocated for
+ the gdb_reader_funcs is to be managed by the reader itself (i.e. if it is
+ allocated from the heap, it must also be freed in gdb_destroy_reader).
+*/
+extern struct gdb_reader_funcs *gdb_init_reader (void);
+
+/* Pointer to the functions which implement the reader's functionality.
+ The individual functions have been documented above.
+
+ None of the fields are optional. */
+struct gdb_reader_funcs
+{
+ gdb_read_debug_info *read;
+ gdb_unwind_frame *unwind;
+ gdb_get_frame_id *get_frame_id;
+ gdb_destroy_reader *destroy;
+
+ /* For use by the reader. */
+ void *private;
+};
+
#ifdef __cplusplus
} /* extern "C" */
#endif
diff --git a/gdb/jit.c b/gdb/jit.c
index eb1bcc7..e3bb81a 100644
--- a/gdb/jit.c
+++ b/gdb/jit.c
@@ -20,6 +20,7 @@
#include "defs.h"
#include "jit.h"
+#include "jit-reader.h"
#include "breakpoint.h"
#include "command.h"
#include "gdbcmd.h"
--
1.7.5.4
^ permalink raw reply [flat|nested] 9+ messages in thread* Re: [PATCH 2/4] Populates jit-reader.h.in
2011-07-24 17:26 ` [PATCH 2/4] Populates jit-reader.h.in Sanjoy Das
@ 2011-07-28 16:40 ` Tom Tromey
0 siblings, 0 replies; 9+ messages in thread
From: Tom Tromey @ 2011-07-28 16:40 UTC (permalink / raw)
To: Sanjoy Das; +Cc: gdb-patches
>>>>> "Sanjoy" == Sanjoy Das <sanjoy@playingwithpointers.com> writes:
Sanjoy> Adds the interface to be implemented by the JIT debug-info
Sanjoy> readers and the API they can use to jit-reader.h.in.
This looks pretty good.
I like the comments quite a bit, thanks for making the extra effort
here.
Sanjoy> +/* Return status codes. */
Sanjoy> +enum {
Sanjoy> + GDB_FAIL = 0,
Sanjoy> + GDB_SUCCESS = 1
Sanjoy> +};
Give this enum a tag and then use it as the return type in those
functions currently documented as returning GDB_FAIL or GDB_SUCCESS.
Sanjoy> +#define GDB_MAX_REGISTER_SIZE 64 /* Mirrors the internal GDB definition. */
A concern I have is that we may bump this value in future versions of
GDB. (IIUC, internally it is really just a convenience so we can
allocate temporary arrays of the right size on the stack.)
I think it would be good to try to address this problem before it bites.
One way to do that would be to put the register size into one of the
structures, rather than having a constant. E.g., there could be another
field in gdb_reg_value; or maybe some other way.
Sanjoy> + /* For internal use. */
Sanjoy> + void *private;
It isn't clear whose internal use these fields are for -- gdb or the jit
plugin? I suggest changing each one to read "For use by GDB" or "For
use by the plugin" as appropriate.
I didn't see anything in the patch series to actually wire up the JIT
code, so it is hard to fully review this patch. (I vaguely recall
seeing this in the earlier series -- but a resubmit should ideally be
complete.)
Sanjoy> +extern struct gdb_reader_funcs *gdb_init_reader (void);
It seems to me that we could put the API version into the returned
gdb_reader_funcs, to be checked by GDB. Then we don't need a special
#define as in patch #1, just an ordinary version number.
Tom
^ permalink raw reply [flat|nested] 9+ messages in thread
* [PATCH 4/4] Adds platform agnostic dynamic loading code.
2011-07-24 16:00 JIT debug info parser Sanjoy Das
` (2 preceding siblings ...)
2011-07-24 17:26 ` [PATCH 2/4] Populates jit-reader.h.in Sanjoy Das
@ 2011-07-24 17:41 ` Sanjoy Das
2011-07-28 17:33 ` Tom Tromey
3 siblings, 1 reply; 9+ messages in thread
From: Sanjoy Das @ 2011-07-24 17:41 UTC (permalink / raw)
To: gdb-patches; +Cc: Sanjoy Das
Adds gdb-dlfcn.h and gdb-dlfcn.c which implement gdb_dlopen, gdb_dlsym and gdb_dlclose for POSIX and windows systems differently. This provides a compatibility layer between the platforms.
gdb/ChangeLog
* gdb-dlfcn.h, gdb-dlfcn.c: New.
* Makefile.in: Add gdb_dlcfn.c and gdb_dlcfn.h to the build system.
* configure.ac, config.in: Check for -ldl and accordingly define HAVE_LIBDL.
---
gdb/ChangeLog | 6 ++++++
gdb/Makefile.in | 6 +++---
gdb/config.in | 3 +++
gdb/configure | 45 +++++++++++++++++++++++++++++++++++++++++++++
gdb/configure.ac | 1 +
5 files changed, 58 insertions(+), 3 deletions(-)
diff --git a/gdb/ChangeLog b/gdb/ChangeLog
index 656a42d..a0ddab4 100644
--- a/gdb/ChangeLog
+++ b/gdb/ChangeLog
@@ -1,5 +1,11 @@
2011-07-24 Sanjoy Das <sdas@igalia.com>
+ * gdb-dlfcn.h, gdb-dlfcn.c: New.
+ * Makefile.in: Add gdb_dlcfn.c and gdb_dlcfn.h to the build system.
+ * configure.ac, config.in: Check for -ldl and accordingly define HAVE_LIBDL.
+
+2011-07-24 Sanjoy Das <sdas@igalia.com>
+
* gdb.texinfo: Some documentation about the new JIT debug info reader functionality.
2011-07-24 Sanjoy Das <sdas@igalia.com>
diff --git a/gdb/Makefile.in b/gdb/Makefile.in
index 7ed6136..edbf0bc 100644
--- a/gdb/Makefile.in
+++ b/gdb/Makefile.in
@@ -739,7 +739,7 @@ SFILES = ada-exp.y ada-lang.c ada-typeprint.c ada-valprint.c ada-tasks.c \
annotate.c common/signals.c copying.c dfp.c gdb.c inf-child.c \
regset.c sol-thread.c windows-termcap.c \
common/common-utils.c common/xml-utils.c \
- common/ptid.c common/buffer.c
+ common/ptid.c common/buffer.c gdb-dlfcn.c
LINTFILES = $(SFILES) $(YYFILES) $(CONFIG_SRCS) init.c
@@ -820,7 +820,7 @@ solib-darwin.h solib-ia64-hpux.h solib-spu.h windows-nat.h xcoffread.h \
gnulib/extra/arg-nonnull.h gnulib/extra/c++defs.h gnulib/extra/warn-on-use.h \
gnulib/stddef.in.h inline-frame.h \
common/common-utils.h common/xml-utils.h common/buffer.h common/ptid.h \
-common/linux-osdata.h
+common/linux-osdata.h gdb-dlfcn.h
# Header files that already have srcdir in them, or which are in objdir.
@@ -907,7 +907,7 @@ COMMON_OBS = $(DEPFILES) $(CONFIG_OBS) $(YYOBJ) \
target-descriptions.o target-memory.o xml-tdesc.o xml-builtin.o \
inferior.o osdata.o gdb_usleep.o record.o gcore.o \
jit.o progspace.o \
- common-utils.o buffer.o ptid.o
+ common-utils.o buffer.o ptid.o gdb-dlfcn.o
TSOBS = inflow.o
diff --git a/gdb/config.in b/gdb/config.in
index 8862144..92dbb15 100644
--- a/gdb/config.in
+++ b/gdb/config.in
@@ -985,3 +985,6 @@
/* The directory to search for JIT debug info reader plugins. */
#undef GDB_JIT_READER_PATH
+
+/* Define if -ldl will work. */
+#undef HAVE_LIBDL
diff --git a/gdb/configure b/gdb/configure
index 3d984c7..ea84519 100755
--- a/gdb/configure
+++ b/gdb/configure
@@ -9935,6 +9935,51 @@ _ACEOF
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for dlopen in -ldl" >&5
+$as_echo_n "checking for dlopen in -ldl... " >&6; }
+if test "${ac_cv_lib_dl_dlopen+set}" = set; then :
+ $as_echo_n "(cached) " >&6
+else
+ ac_check_lib_save_LIBS=$LIBS
+LIBS="-ldl $LIBS"
+cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+
+/* Override any GCC internal prototype to avoid an error.
+ Use char because int might match the return type of a GCC
+ builtin and then its argument prototype would still apply. */
+#ifdef __cplusplus
+extern "C"
+#endif
+char dlopen ();
+int
+main ()
+{
+return dlopen ();
+ ;
+ return 0;
+}
+_ACEOF
+if ac_fn_c_try_link "$LINENO"; then :
+ ac_cv_lib_dl_dlopen=yes
+else
+ ac_cv_lib_dl_dlopen=no
+fi
+rm -f core conftest.err conftest.$ac_objext \
+ conftest$ac_exeext conftest.$ac_ext
+LIBS=$ac_check_lib_save_LIBS
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_dl_dlopen" >&5
+$as_echo "$ac_cv_lib_dl_dlopen" >&6; }
+if test "x$ac_cv_lib_dl_dlopen" = x""yes; then :
+ cat >>confdefs.h <<_ACEOF
+#define HAVE_LIBDL 1
+_ACEOF
+
+ LIBS="-ldl $LIBS"
+
+fi
+
ac_config_files="$ac_config_files jit-reader.h:jit-reader.h.in"
diff --git a/gdb/configure.ac b/gdb/configure.ac
index 19263c1..8e13cfe 100644
--- a/gdb/configure.ac
+++ b/gdb/configure.ac
@@ -598,6 +598,7 @@ AC_DEFINE_UNQUOTED(GDB_JIT_READER_PATH, "$GDB_JIT_READER_PATH",
[The directory to look for JIT debug info readers])
AC_SUBST(HOST_U_64_BIT)
+AC_CHECK_LIB([dl], [dlopen], [], [], [])
AC_CONFIG_FILES([jit-reader.h:jit-reader.h.in])
AC_ARG_WITH(expat,
--
1.7.5.4
^ permalink raw reply [flat|nested] 9+ messages in thread