* [PATCH 1/6] Introduce header (jit-reader.in) and modify build system.
2011-08-20 6:26 JIT Reader (re-roll) Sanjoy Das
@ 2011-08-20 6:26 ` Sanjoy Das
2011-08-20 18:04 ` Jan Kratochvil
2011-08-20 6:27 ` [PATCH 5/6] New JIT unwinder Sanjoy Das
` (4 subsequent siblings)
5 siblings, 1 reply; 16+ messages in thread
From: Sanjoy Das @ 2011-08-20 6:26 UTC (permalink / raw)
To: gdb-patches; +Cc: Sanjoy Das
jit-reader.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 produce `jit.reader.h'; so that GDB_CORE_ADDR is defined correctly.
This commit arranges for `jit-reader.h' to be installed in the global
include directory.
It also adds libdir as a define (to GDB_CFLAGS) since the value is
needed to determine the location from where the shared objects
(readers) are to be lifted.
gdb/ChangeLog:
* Makefile.in: Add jit-reader.in to HFILES_WITH_SRCDIR,
generated_files and install-only. Add -DLIBDIR to GDB_CFLAGS.
* config.in: Add HAVE_LIBDL.
* configure.ac: Add TARGET_PTR, check for libdl and add
jit-reader.h.in.
* configure: (Autogenerated)
* jit-reader.in: New
* jit.c: Include jit-reader.h.
---
gdb/ChangeLog | 11 ++
gdb/Makefile.in | 15 ++-
gdb/config.in | 3 +
gdb/configure | 169 ++++++++++++++++++++++++++
gdb/configure.ac | 23 ++++
gdb/jit-reader.in | 349 +++++++++++++++++++++++++++++++++++++++++++++++++++++
gdb/jit.c | 1 +
7 files changed, 566 insertions(+), 5 deletions(-)
create mode 100644 gdb/jit-reader.in
diff --git a/gdb/ChangeLog b/gdb/ChangeLog
index f6d8a17..369cc35 100644
--- a/gdb/ChangeLog
+++ b/gdb/ChangeLog
@@ -1,3 +1,14 @@
+2011-08-20 Sanjoy Das <sdas@igalia.com>
+
+ * Makefile.in: Add jit-reader.in to HFILES_WITH_SRCDIR,
+ generated_files and install-only. Add -DLIBDIR to GDB_CFLAGS.
+ * config.in: Add HAVE_LIBDL.
+ * configure.ac: Add TARGET_PTR, check for libdl and add
+ jit-reader.h.in.
+ * configure: (Autogenerated)
+ * jit-reader.in: New
+ * jit.c: Include jit-reader.h.
+
2011-08-18 Keith Seitz <keiths@redhat.com>
PR c++/12266
diff --git a/gdb/Makefile.in b/gdb/Makefile.in
index bd00644..2e24dfa 100644
--- a/gdb/Makefile.in
+++ b/gdb/Makefile.in
@@ -419,7 +419,7 @@ CONFIG_UNINSTALL = @CONFIG_UNINSTALL@
# should be according to Posix).
DEFS = @DEFS@
GDB_CFLAGS = -I. -I$(srcdir) -I$(srcdir)/common -I$(srcdir)/config \
- -DLOCALEDIR="\"$(localedir)\"" $(DEFS)
+ -DLOCALEDIR="\"$(localedir)\"" $(DEFS) -DLIBDIR="\"@libdir@\""
# MH_CFLAGS, if defined, has host-dependent CFLAGS from the config directory.
GLOBAL_CFLAGS = $(MH_CFLAGS)
@@ -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.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..8b3f0cf 100644
--- a/gdb/config.in
+++ b/gdb/config.in
@@ -982,3 +982,6 @@
/* Define as `fork' if `vfork' does not work. */
#undef vfork
+
+/* Define if -ldl will work. */
+#undef HAVE_LIBDL
diff --git a/gdb/configure b/gdb/configure
index ac143e4..3c99bd5 100755
--- a/gdb/configure
+++ b/gdb/configure
@@ -666,6 +666,7 @@ python_prog_path
LTLIBEXPAT
LIBEXPAT
HAVE_LIBEXPAT
+TARGET_PTR
READLINE_TEXI_INCFLAG
READLINE_CFLAGS
READLINE_DEPS
@@ -9807,6 +9808,173 @@ fi
+# Generate jit-reader.h
+
+# This is typedeffed to GDB_CORE_ADDR in jit-reader.h
+TARGET_PTR=
+
+# 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
+ TARGET_PTR="unsigned long"
+elif test "x${ac_cv_sizeof_unsigned_long_long}" = "x8"; then
+ TARGET_PTR="unsigned long long"
+elif test "x${ac_cv_sizeof_unsigned___int128}" = "x16"; then
+ TARGET_PTR="unsigned __int128"
+else
+ TARGET_PTR="unsigned long"
+fi
+
+
+{ $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.in"
+
+
# Check whether --with-expat was given.
if test "${with_expat+set}" = set; then :
@@ -16717,6 +16885,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.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..e0882d9 100644
--- a/gdb/configure.ac
+++ b/gdb/configure.ac
@@ -573,6 +573,29 @@ 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
+TARGET_PTR=
+
+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
+ TARGET_PTR="unsigned long"
+elif test "x${ac_cv_sizeof_unsigned_long_long}" = "x8"; then
+ TARGET_PTR="unsigned long long"
+elif test "x${ac_cv_sizeof_unsigned___int128}" = "x16"; then
+ TARGET_PTR="unsigned __int128"
+else
+ TARGET_PTR="unsigned long"
+fi
+
+AC_SUBST(TARGET_PTR)
+AC_CHECK_LIB([dl], [dlopen], [], [], [])
+AC_CONFIG_FILES([jit-reader.h:jit-reader.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.in b/gdb/jit-reader.in
new file mode 100644
index 0000000..b7a2d3c
--- /dev/null
+++ b/gdb/jit-reader.in
@@ -0,0 +1,349 @@
+/* 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
+
+/* Versioning information. See gdb_reader_funcs */
+
+#define GDB_READER_INTERFACE_VERSION 1
+
+/* 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. */
+
+#ifdef __cplusplus
+#define GDB_DECLARE_GPL_COMPATIBLE_READER \
+ extern "C" { \
+ extern int plugin_is_GPL_compatible (void) \
+ { \
+ return 0; \
+ } \
+ }
+
+#else
+
+#define GDB_DECLARE_GPL_COMPATIBLE_READER
+ extern int plugin_is_GPL_compatible (void) \
+ { \
+ return 0; \
+ }
+
+#endif
+
+/* Represents an address on the target system. */
+
+typedef @TARGET_PTR@ GDB_CORE_ADDR;
+
+/* Return status codes. */
+
+enum gdb_status {
+ GDB_FAIL = 0,
+ GDB_SUCCESS = 1
+};
+
+struct gdb_object;
+struct gdb_symtab;
+struct gdb_block;
+struct gdb_symbol_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;
+};
+
+/* Create a new GDB code object. Each code object can have one or more
+ symbol tables, each representing a compiled source file. */
+
+typedef struct gdb_object *(gdb_object_open) (struct gdb_symbol_callbacks *cb);
+
+/* The callback used to create new symbol table. CB is the
+ gdb_symbol_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_open) (struct gdb_symbol_callbacks *cb,
+ struct gdb_object *obj,
+ 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_open) (struct gdb_symbol_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_symbol_callbacks *cb,
+ struct gdb_symtab *symtab,
+ int nlines,
+ struct gdb_line_mapping *lines);
+
+/* Close the symtab SYMTAB. This signals to GDB that no more blocks
+ will be opened on this symtab. */
+
+typedef void (gdb_symtab_close) (struct gdb_symbol_callbacks *cb,
+ struct gdb_symtab *symtab);
+
+
+/* Closes the gdb_object OBJ and adds the emitted information into
+ GDB's internal structures. Once this is done, the debug information
+ will be picked up and used; this will usually be the last operation
+ in gdb_read_debug_info. */
+
+typedef void (gdb_object_close) (struct gdb_symbol_callbacks *cb,
+ struct gdb_object *obj);
+
+/* 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 enum gdb_status (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_symbol_callbacks
+{
+ gdb_object_open *object_open;
+ gdb_symtab_open *symtab_open;
+ gdb_block_open *block_open;
+ gdb_symtab_close *symtab_close;
+ gdb_object_close *object_close;
+
+ gdb_symtab_add_line_mapping *line_mapping_add;
+ gdb_target_read *target_read;
+
+ /* For internal use by GDB. */
+
+ void *priv_data;
+};
+
+/* Forward declaration. */
+
+struct gdb_reg_value;
+
+/* A function of this type is used to free a gdb_reg_value. See the
+ comment on `free' in struct gdb_reg_value. */
+
+typedef void (gdb_reg_value_free) (struct gdb_reg_value *);
+
+/* Denotes the value of a register. */
+
+struct gdb_reg_value
+{
+ /* The size of the register in bytes. The reader need not set this
+ field. This will be set for (defined) register values being read
+ from GDB using reg_get. */
+
+ int size;
+
+ /* Set to non-zero if the value for the register is known. The
+ registers for which the reader does not call reg_set are also
+ assumed to be undefined */
+
+ int defined;
+
+ /* Since gdb_reg_value is a variable sized structure, it will
+ usually be allocated on the heap. This function is expected to
+ contain the corresponding "free" function.
+
+ When a pointer to gdb_reg_value is being sent from GDB to the
+ reader (via gdb_unwind_reg_get), the reader is expected to call
+ this function (with the same gdb_reg_value as argument) once it
+ is done with the value.
+
+ When the function sends the a gdb_reg_value to GDB (via
+ gdb_unwind_reg_set), it is expected to set this field to point to
+ an appropriate cleanup routine (or to NULL if no cleanup is
+ required). */
+
+ gdb_reg_value_free *free;
+
+ /* The value of the register. */
+
+ unsigned char value[1];
+};
+
+/* get_frame_id in gdb_reader_funcs is to return a gdb_frame_id
+ corresponding to the current frame. The registers corresponding to
+ the current frame can be read using reg_get. Calling get_frame_id
+ on a particular frame should return the same gdb_frame_id
+ throughout its lifetime (i.e. till before it gets unwound). One way
+ to do this is 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. 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 the
+ (DWARF) register number whose value is to be set. VAL is the value
+ the register is to be set to.
+
+ VAL is *not* copied, so the memory allocated to it cannot be
+ reused. Once GDB no longer needs the value, it is deallocated using
+ the FREE function (see gdb_reg_value).
+
+ 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 by GDB. */
+
+ void *priv_data;
+};
+
+/* Forward declaration. */
+
+struct gdb_reader_funcs;
+
+/* 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.
+ The implementation has to use the functions in CB to actually emit
+ the parsed data into GDB. SELF is the same structure returned by
+ gdb_init_reader.
+
+ Return GDB_FAIL on failure and GDB_SUCCESS on success. */
+
+typedef enum gdb_status (gdb_read_debug_info) (struct gdb_reader_funcs *self,
+ struct gdb_symbol_callbacks *cb,
+ void *memory, long memory_sz);
+
+/* Unwind the current frame, CB is the set of unwind callbacks that
+ are to be used to do this.
+
+ Return GDB_FAIL on failure and GDB_SUCCESS on success. */
+
+typedef enum gdb_status (gdb_unwind_frame) (struct gdb_reader_funcs *self,
+ struct gdb_unwind_callbacks *cb);
+
+/* Return 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, if required. */
+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. 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
+{
+ /* Must be set to GDB_READER_INTERFACE_VERSION */
+
+ int reader_version;
+
+ /* For use by the reader. */
+
+ void *priv_data;
+
+ gdb_read_debug_info *read;
+ gdb_unwind_frame *unwind;
+ gdb_get_frame_id *get_frame_id;
+ gdb_destroy_reader *destroy;
+};
+
+#ifdef __cplusplus
+} /* extern "C" */
+#endif
+
+#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] 16+ messages in thread* Re: [PATCH 1/6] Introduce header (jit-reader.in) and modify build system.
2011-08-20 6:26 ` [PATCH 1/6] Introduce header (jit-reader.in) and modify build system Sanjoy Das
@ 2011-08-20 18:04 ` Jan Kratochvil
2011-08-20 18:18 ` Sanjoy Das
0 siblings, 1 reply; 16+ messages in thread
From: Jan Kratochvil @ 2011-08-20 18:04 UTC (permalink / raw)
To: Sanjoy Das; +Cc: gdb-patches
On Sat, 20 Aug 2011 08:27:10 +0200, Sanjoy Das wrote:
> --- /dev/null
> +++ b/gdb/jit-reader.in
> @@ -0,0 +1,349 @@
[...]
> +/* Called when the reader is loaded. Must either return a properly
> + populated gdb_reader_funcs or NULL. 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);
I think it should be:
extern const struct gdb_reader_funcs *gdb_init_reader (void);
as GDB should never modify it.
Thanks,
Jan
^ permalink raw reply [flat|nested] 16+ messages in thread
* [PATCH 5/6] New JIT unwinder.
2011-08-20 6:26 JIT Reader (re-roll) Sanjoy Das
2011-08-20 6:26 ` [PATCH 1/6] Introduce header (jit-reader.in) and modify build system Sanjoy Das
@ 2011-08-20 6:27 ` Sanjoy Das
2011-08-20 17:59 ` Jan Kratochvil
2011-08-20 6:27 ` [PATCH 3/6] New commands for loading and unloading a reader Sanjoy Das
` (3 subsequent siblings)
5 siblings, 1 reply; 16+ messages in thread
From: Sanjoy Das @ 2011-08-20 6:27 UTC (permalink / raw)
To: gdb-patches; +Cc: Sanjoy Das
Introduce a "proxy unwinder", whcih will pass down all calls to the
functions the JIT reader provides.
gdb/ChangeLog
* jit.c (jut_unwind_reg_set_impl, free_reg_value_impl)
(jit_unwind_reg_get_impl, jit_frame_sniffer)
(jit_frame_unwind_stop_reason, jit_frame_this_id)
(jit_frame_prev_register, jit_dealloc_cache)
(jit_gdbarch_data_init): New functions
(_initialize_jit): Register new gdbarch data slot
jit_gdbarch_data.
---
gdb/ChangeLog | 10 ++
gdb/jit.c | 260 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++
2 files changed, 270 insertions(+), 0 deletions(-)
diff --git a/gdb/ChangeLog b/gdb/ChangeLog
index 70c280e..92d645b 100644
--- a/gdb/ChangeLog
+++ b/gdb/ChangeLog
@@ -1,5 +1,15 @@
2011-08-20 Sanjoy Das <sdas@igalia.com>
+ * jit.c (jut_unwind_reg_set_impl, free_reg_value_impl)
+ (jit_unwind_reg_get_impl, jit_frame_sniffer)
+ (jit_frame_unwind_stop_reason, jit_frame_this_id)
+ (jit_frame_prev_register, jit_dealloc_cache)
+ (jit_gdbarch_data_init): New functions
+ (_initialize_jit): Register new gdbarch data slot
+ jit_gdbarch_data.
+
+2011-08-20 Sanjoy Das <sdas@igalia.com>
+
* jit.c (add_objfile_entry, jit_target_read_impl)
(jit_object_open_impl, jit_symtab_open_impl, compare_block)
(jit_block_open_impl, jit_block_open_impl)
diff --git a/gdb/jit.c b/gdb/jit.c
index d4d7ddb..da39525 100644
--- a/gdb/jit.c
+++ b/gdb/jit.c
@@ -31,6 +31,7 @@
#include "inferior.h"
#include "observer.h"
#include "objfiles.h"
+#include "regcache.h"
#include "symfile.h"
#include "symtab.h"
#include "target.h"
@@ -49,6 +50,12 @@ static const struct inferior_data *jit_inferior_data = NULL;
static void jit_inferior_init (struct gdbarch *gdbarch);
+/* An unwinder is registered for every gdbarch. This key is used to
+ remember if the unwinder has been registered for a particular
+ gdbarch. */
+
+static struct gdbarch_data *jit_gdbarch_data;
+
/* Non-zero if we want to see trace of jit level stuff. */
static int jit_debug = 0;
@@ -907,6 +914,244 @@ jit_breakpoint_re_set_internal (struct gdbarch *gdbarch,
return 0;
}
+/* The private data passed around in the frame unwind callback
+ functions. */
+
+struct jit_unwind_private
+{
+ /* Cached register values. See jit_frame_sniffer to see how this
+ works. */
+
+ struct gdb_reg_value **registers;
+
+ /* The frame being unwound. */
+
+ struct frame_info *this_frame;
+};
+
+/* Sets the value of a particular register in this frame. */
+
+static void
+jit_unwind_reg_set_impl (struct gdb_unwind_callbacks *cb, int regnum,
+ struct gdb_reg_value *value)
+{
+ struct jit_unwind_private *priv;
+ int gdb_reg;
+
+ gdb_reg = gdbarch_dwarf2_reg_to_regnum (target_gdbarch, regnum);
+ priv = cb->priv_data;
+ gdb_assert (priv->registers);
+ priv->registers[gdb_reg] = value;
+}
+
+/* Passed in the `free' field of a gdb_reg_value. */
+
+static void
+free_reg_value_impl (struct gdb_reg_value *reg_value)
+{
+ xfree (reg_value);
+}
+
+/* Get the value of register REGNUM in the previous frame. */
+
+static struct gdb_reg_value *
+jit_unwind_reg_get_impl (struct gdb_unwind_callbacks *cb, int regnum)
+{
+ struct jit_unwind_private *priv;
+ struct gdb_reg_value *value;
+ int gdb_reg, size;
+
+ priv = cb->priv_data;
+ gdb_reg = gdbarch_dwarf2_reg_to_regnum (target_gdbarch, regnum);
+ size = register_size (target_gdbarch, gdb_reg);
+ value = xmalloc (sizeof (struct gdb_reg_value) + size - 1);
+ value->defined = frame_register_read (priv->this_frame, gdb_reg,
+ value->value);
+ value->size = size;
+ value->free = free_reg_value_impl;
+ return value;
+}
+
+/* The frame sniffer for the pseudo unwinder.
+
+ While this is nominally a frame sniffer, in the case where the JIT
+ reader actually recognizes the frame, it does a lot more work -- it
+ unwinds the frame and saves the corresponding register values in
+ the cache. jit_frame_prev_register simply returns the saved
+ register values. */
+
+static int
+jit_frame_sniffer (const struct frame_unwind *self,
+ struct frame_info *this_frame, void **cache)
+{
+ struct jit_inferior_data *inf_data;
+ struct jit_unwind_private *priv_data;
+ struct jit_dbg_reader *iter;
+ struct gdb_unwind_callbacks callbacks;
+ struct gdb_reader_funcs *funcs;
+
+ inf_data = get_jit_inferior_data ();
+
+ callbacks.reg_get = jit_unwind_reg_get_impl;
+ callbacks.reg_set = jit_unwind_reg_set_impl;
+ callbacks.target_read = jit_target_read_impl;
+
+ if (loaded_jit_reader == NULL)
+ return 0;
+
+ funcs = loaded_jit_reader->functions;
+
+ if (!*cache)
+ {
+ *cache = XZALLOC (struct jit_unwind_private);
+ priv_data = *cache;
+ priv_data->registers = XCALLOC (gdbarch_num_regs (target_gdbarch),
+ struct gdb_reg_value *);
+ priv_data->this_frame = this_frame;
+ }
+ else
+ {
+ priv_data = *cache;
+ priv_data->this_frame = this_frame;
+ }
+
+ callbacks.priv_data = priv_data;
+
+ /* Try to coax the provided unwinder to unwind the stack */
+ if (funcs->unwind (funcs, &callbacks) == GDB_SUCCESS)
+ {
+ if (jit_debug)
+ fprintf_unfiltered (gdb_stdlog, "Successfully unwound frame using "
+ "JIT reader.\n");
+ return 1;
+ }
+ if (jit_debug)
+ fprintf_unfiltered (gdb_stdlog, "Could not unwind frame using "
+ "JIT reader.\n");
+
+ xfree (priv_data->registers);
+ xfree (priv_data);
+ *cache = NULL;
+
+ return 0;
+}
+
+/* Also for the pseudo unwinder. */
+
+static enum unwind_stop_reason
+jit_frame_unwind_stop_reason (struct frame_info *this_frame, void **cache)
+{
+ return UNWIND_NO_REASON;
+}
+
+/* The frame_id function for the pseudo unwinder. Relays the call to
+ the loaded plugin. */
+
+static void
+jit_frame_this_id (struct frame_info *this_frame, void **cache,
+ struct frame_id *this_id)
+{
+ struct jit_unwind_private private;
+ struct gdb_frame_id frame_id;
+ struct gdb_reader_funcs *funcs;
+ struct gdb_unwind_callbacks callbacks;
+
+ private.registers = NULL;
+ private.this_frame = this_frame;
+
+ /* We don't expect the frame_id function to set any registers, so we
+ set reg_set to NULL. */
+ callbacks.reg_get = jit_unwind_reg_get_impl;
+ callbacks.reg_set = NULL;
+ callbacks.target_read = jit_target_read_impl;
+ callbacks.priv_data = &private;
+
+ gdb_assert (loaded_jit_reader);
+ funcs = loaded_jit_reader->functions;
+
+ frame_id = funcs->get_frame_id (funcs, &callbacks);
+ *this_id = frame_id_build (frame_id.stack_address, frame_id.code_address);
+}
+
+/* Pseudo unwinder function. Reads the previously fetched value for
+ the register from the cache. */
+
+static struct value *
+jit_frame_prev_register (struct frame_info *this_frame, void **cache, int reg)
+{
+ struct jit_unwind_private *priv = *cache;
+ struct gdb_reg_value *value;
+
+ if (priv == NULL)
+ return frame_unwind_got_optimized (this_frame, reg);
+
+ gdb_assert (priv->registers);
+ value = priv->registers[reg];
+ if (value && value->defined)
+ return frame_unwind_got_bytes (this_frame, reg, value->value);
+ else
+ return frame_unwind_got_optimized (this_frame, reg);
+}
+
+/* gdb_reg_value has a free function, which must be called on each
+ saved register value. */
+
+static void
+jit_dealloc_cache (struct frame_info *this_frame, void *cache)
+{
+ struct jit_unwind_private *priv_data = cache;
+ int i;
+
+ gdb_assert (priv_data->registers);
+
+ for (i = 0; i < gdbarch_num_regs (target_gdbarch); i++)
+ if (priv_data->registers[i] && priv_data->registers[i]->free)
+ priv_data->registers[i]->free (priv_data->registers[i]);
+
+ xfree (priv_data->registers);
+ xfree (priv_data);
+}
+
+/* Relay everything back to the unwinder registered by the JIT debug
+ info reader.*/
+
+static const struct frame_unwind jit_frame_unwind =
+{
+ NORMAL_FRAME,
+ jit_frame_unwind_stop_reason,
+ jit_frame_this_id,
+ jit_frame_prev_register,
+ NULL,
+ jit_frame_sniffer,
+ jit_dealloc_cache
+};
+
+
+/* This is the information that is stored at jit_gdbarch_data for each
+ architecture. */
+
+struct jit_gdbarch_data_type {
+
+ /* Has the (pseudo) unwinder been prepended? */
+
+ int unwinder_registered;
+};
+
+/* Check GDBARCH and prepend the pseudo JIT unwinder if needed. */
+
+static void
+jit_prepend_unwinder (struct gdbarch *gdbarch)
+{
+ struct jit_gdbarch_data_type *data;
+
+ data = gdbarch_data (gdbarch, jit_gdbarch_data);
+ if (!data->unwinder_registered)
+ {
+ frame_unwind_prepend_unwinder (gdbarch, &jit_frame_unwind);
+ data->unwinder_registered = 1;
+ }
+}
+
/* Register any already created translations. */
static void
@@ -920,6 +1165,8 @@ jit_inferior_init (struct gdbarch *gdbarch)
if (jit_debug)
fprintf_unfiltered (gdb_stdlog, "jit_inferior_init\n");
+ jit_prepend_unwinder (gdbarch);
+
inf_data = get_jit_inferior_data ();
if (jit_breakpoint_re_set_internal (gdbarch, inf_data) != 0)
return;
@@ -1082,6 +1329,18 @@ free_objfile_data (struct objfile *objfile, void *data)
xfree (data);
}
+/* Initialize the jit_gdbarch_data slot with an instance of struct
+ jit_gdbarch_data_type */
+
+static void *
+jit_gdbarch_data_init (struct obstack *obstack)
+{
+ struct jit_gdbarch_data_type *data =
+ obstack_alloc (obstack, sizeof (struct jit_gdbarch_data_type));
+ data->unwinder_registered = 0;
+ return data;
+}
+
/* Provide a prototype to silence -Wmissing-prototypes. */
extern void _initialize_jit (void);
@@ -1104,6 +1363,7 @@ _initialize_jit (void)
register_objfile_data_with_cleanup (NULL,free_objfile_data);
jit_inferior_data =
register_inferior_data_with_cleanup (jit_inferior_data_cleanup);
+ jit_gdbarch_data = gdbarch_data_register_pre_init (jit_gdbarch_data_init);
add_com ("load-jit-reader", no_class, load_jit_reader_command, _("\
Try to load file FILE as a debug info reader (and unwinder) for\n\
JIT compiled code from " LIBDIR "/gdb\n\
--
1.7.5.4
^ permalink raw reply [flat|nested] 16+ messages in thread* Re: [PATCH 5/6] New JIT unwinder.
2011-08-20 6:27 ` [PATCH 5/6] New JIT unwinder Sanjoy Das
@ 2011-08-20 17:59 ` Jan Kratochvil
2011-08-20 18:30 ` Mark Kettenis
0 siblings, 1 reply; 16+ messages in thread
From: Jan Kratochvil @ 2011-08-20 17:59 UTC (permalink / raw)
To: Sanjoy Das; +Cc: gdb-patches
On Sat, 20 Aug 2011 08:27:14 +0200, Sanjoy Das wrote:
> Introduce a "proxy unwinder", whcih will pass down all calls to the
> functions the JIT reader provides.
>
> gdb/ChangeLog
>
> * jit.c (jut_unwind_reg_set_impl, free_reg_value_impl)
> (jit_unwind_reg_get_impl, jit_frame_sniffer)
> (jit_frame_unwind_stop_reason, jit_frame_this_id)
> (jit_frame_prev_register, jit_dealloc_cache)
> (jit_gdbarch_data_init): New functions
> (_initialize_jit): Register new gdbarch data slot
> jit_gdbarch_data.
> ---
> gdb/ChangeLog | 10 ++
> gdb/jit.c | 260 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++
> 2 files changed, 270 insertions(+), 0 deletions(-)
>
> diff --git a/gdb/ChangeLog b/gdb/ChangeLog
> index 70c280e..92d645b 100644
> --- a/gdb/ChangeLog
> +++ b/gdb/ChangeLog
> @@ -1,5 +1,15 @@
> 2011-08-20 Sanjoy Das <sdas@igalia.com>
>
> + * jit.c (jut_unwind_reg_set_impl, free_reg_value_impl)
> + (jit_unwind_reg_get_impl, jit_frame_sniffer)
> + (jit_frame_unwind_stop_reason, jit_frame_this_id)
> + (jit_frame_prev_register, jit_dealloc_cache)
> + (jit_gdbarch_data_init): New functions
> + (_initialize_jit): Register new gdbarch data slot
> + jit_gdbarch_data.
> +
> +2011-08-20 Sanjoy Das <sdas@igalia.com>
> +
> * jit.c (add_objfile_entry, jit_target_read_impl)
> (jit_object_open_impl, jit_symtab_open_impl, compare_block)
> (jit_block_open_impl, jit_block_open_impl)
> diff --git a/gdb/jit.c b/gdb/jit.c
> index d4d7ddb..da39525 100644
> --- a/gdb/jit.c
> +++ b/gdb/jit.c
> @@ -31,6 +31,7 @@
> #include "inferior.h"
> #include "observer.h"
> #include "objfiles.h"
> +#include "regcache.h"
> #include "symfile.h"
> #include "symtab.h"
> #include "target.h"
> @@ -49,6 +50,12 @@ static const struct inferior_data *jit_inferior_data = NULL;
>
> static void jit_inferior_init (struct gdbarch *gdbarch);
>
> +/* An unwinder is registered for every gdbarch. This key is used to
> + remember if the unwinder has been registered for a particular
> + gdbarch. */
> +
> +static struct gdbarch_data *jit_gdbarch_data;
> +
> /* Non-zero if we want to see trace of jit level stuff. */
>
> static int jit_debug = 0;
> @@ -907,6 +914,244 @@ jit_breakpoint_re_set_internal (struct gdbarch *gdbarch,
> return 0;
> }
>
> +/* The private data passed around in the frame unwind callback
> + functions. */
> +
> +struct jit_unwind_private
> +{
> + /* Cached register values. See jit_frame_sniffer to see how this
> + works. */
> +
> + struct gdb_reg_value **registers;
> +
> + /* The frame being unwound. */
> +
> + struct frame_info *this_frame;
> +};
> +
> +/* Sets the value of a particular register in this frame. */
> +
> +static void
> +jit_unwind_reg_set_impl (struct gdb_unwind_callbacks *cb, int regnum,
> + struct gdb_reg_value *value)
Please rename / comment REGNUM it is DWARF register.
> +{
> + struct jit_unwind_private *priv;
> + int gdb_reg;
> +
> + gdb_reg = gdbarch_dwarf2_reg_to_regnum (target_gdbarch, regnum);
gdb_assert (gdb_reg != -1);
but maybe it should be rather some non-fatal error.
> + priv = cb->priv_data;
> + gdb_assert (priv->registers);
> + priv->registers[gdb_reg] = value;
> +}
> +
> +/* Passed in the `free' field of a gdb_reg_value. */
> +
> +static void
> +free_reg_value_impl (struct gdb_reg_value *reg_value)
> +{
> + xfree (reg_value);
> +}
> +
> +/* Get the value of register REGNUM in the previous frame. */
> +
> +static struct gdb_reg_value *
> +jit_unwind_reg_get_impl (struct gdb_unwind_callbacks *cb, int regnum)
> +{
> + struct jit_unwind_private *priv;
> + struct gdb_reg_value *value;
> + int gdb_reg, size;
> +
> + priv = cb->priv_data;
> + gdb_reg = gdbarch_dwarf2_reg_to_regnum (target_gdbarch, regnum);
> + size = register_size (target_gdbarch, gdb_reg);
> + value = xmalloc (sizeof (struct gdb_reg_value) + size - 1);
> + value->defined = frame_register_read (priv->this_frame, gdb_reg,
> + value->value);
> + value->size = size;
> + value->free = free_reg_value_impl;
> + return value;
> +}
> +
> +/* The frame sniffer for the pseudo unwinder.
> +
> + While this is nominally a frame sniffer, in the case where the JIT
> + reader actually recognizes the frame, it does a lot more work -- it
> + unwinds the frame and saves the corresponding register values in
> + the cache. jit_frame_prev_register simply returns the saved
> + register values. */
> +
> +static int
> +jit_frame_sniffer (const struct frame_unwind *self,
> + struct frame_info *this_frame, void **cache)
> +{
> + struct jit_inferior_data *inf_data;
> + struct jit_unwind_private *priv_data;
> + struct jit_dbg_reader *iter;
> + struct gdb_unwind_callbacks callbacks;
> + struct gdb_reader_funcs *funcs;
const struct gdb_reader_funcs *funcs;
> +
> + inf_data = get_jit_inferior_data ();
> +
> + callbacks.reg_get = jit_unwind_reg_get_impl;
> + callbacks.reg_set = jit_unwind_reg_set_impl;
> + callbacks.target_read = jit_target_read_impl;
Couldn't GDB just export these functions to the plugin without having to use
the callbacks vector? Python does so, libthread_db does so (see
proc-service.list).
> +
> + if (loaded_jit_reader == NULL)
> + return 0;
> +
> + funcs = loaded_jit_reader->functions;
> +
> + if (!*cache)
> + {
> + *cache = XZALLOC (struct jit_unwind_private);
> + priv_data = *cache;
> + priv_data->registers = XCALLOC (gdbarch_num_regs (target_gdbarch),
> + struct gdb_reg_value *);
Registers for this frame can be different from target_gdbarch, you should use
get_frame_arch. Please read:
Re: [00/03] per-aspace target_gdbarch (+local gdbarch obsoletion?)
http://sourceware.org/ml/gdb-patches/2010-01/msg00497.html
> + priv_data->this_frame = this_frame;
> + }
> + else
When can be *cache != NULL? IMO never. Otherwise I think there would be some
reference counting problems or so.
> + {
> + priv_data = *cache;
> + priv_data->this_frame = this_frame;
> + }
> +
> + callbacks.priv_data = priv_data;
> +
> + /* Try to coax the provided unwinder to unwind the stack */
> + if (funcs->unwind (funcs, &callbacks) == GDB_SUCCESS)
> + {
> + if (jit_debug)
> + fprintf_unfiltered (gdb_stdlog, "Successfully unwound frame using "
> + "JIT reader.\n");
Missing _(...) localization.
> + return 1;
> + }
> + if (jit_debug)
> + fprintf_unfiltered (gdb_stdlog, "Could not unwind frame using "
> + "JIT reader.\n");
Missing _(...) localization.
> +
> + xfree (priv_data->registers);
> + xfree (priv_data);
Could you reuse jit_dealloc_cache instead?
> + *cache = NULL;
> +
> + return 0;
> +}
> +
> +/* Also for the pseudo unwinder. */
> +
> +static enum unwind_stop_reason
> +jit_frame_unwind_stop_reason (struct frame_info *this_frame, void **cache)
> +{
> + return UNWIND_NO_REASON;
> +}
Just use default_frame_unwind_stop_reason.
> +
> +/* The frame_id function for the pseudo unwinder. Relays the call to
> + the loaded plugin. */
> +
> +static void
> +jit_frame_this_id (struct frame_info *this_frame, void **cache,
> + struct frame_id *this_id)
> +{
> + struct jit_unwind_private private;
> + struct gdb_frame_id frame_id;
> + struct gdb_reader_funcs *funcs;
> + struct gdb_unwind_callbacks callbacks;
> +
> + private.registers = NULL;
> + private.this_frame = this_frame;
> +
> + /* We don't expect the frame_id function to set any registers, so we
> + set reg_set to NULL. */
> + callbacks.reg_get = jit_unwind_reg_get_impl;
> + callbacks.reg_set = NULL;
> + callbacks.target_read = jit_target_read_impl;
> + callbacks.priv_data = &private;
> +
> + gdb_assert (loaded_jit_reader);
> + funcs = loaded_jit_reader->functions;
> +
> + frame_id = funcs->get_frame_id (funcs, &callbacks);
> + *this_id = frame_id_build (frame_id.stack_address, frame_id.code_address);
Why to call frame_id_build at all and not just to use frame_id?
> +}
> +
> +/* Pseudo unwinder function. Reads the previously fetched value for
> + the register from the cache. */
> +
> +static struct value *
> +jit_frame_prev_register (struct frame_info *this_frame, void **cache, int reg)
> +{
> + struct jit_unwind_private *priv = *cache;
> + struct gdb_reg_value *value;
> +
> + if (priv == NULL)
> + return frame_unwind_got_optimized (this_frame, reg);
> +
> + gdb_assert (priv->registers);
> + value = priv->registers[reg];
> + if (value && value->defined)
> + return frame_unwind_got_bytes (this_frame, reg, value->value);
> + else
> + return frame_unwind_got_optimized (this_frame, reg);
> +}
> +
> +/* gdb_reg_value has a free function, which must be called on each
> + saved register value. */
> +
> +static void
> +jit_dealloc_cache (struct frame_info *this_frame, void *cache)
> +{
> + struct jit_unwind_private *priv_data = cache;
> + int i;
> +
> + gdb_assert (priv_data->registers);
> +
> + for (i = 0; i < gdbarch_num_regs (target_gdbarch); i++)
> + if (priv_data->registers[i] && priv_data->registers[i]->free)
> + priv_data->registers[i]->free (priv_data->registers[i]);
> +
> + xfree (priv_data->registers);
> + xfree (priv_data);
> +}
> +
> +/* Relay everything back to the unwinder registered by the JIT debug
> + info reader.*/
> +
> +static const struct frame_unwind jit_frame_unwind =
> +{
> + NORMAL_FRAME,
> + jit_frame_unwind_stop_reason,
> + jit_frame_this_id,
> + jit_frame_prev_register,
> + NULL,
> + jit_frame_sniffer,
> + jit_dealloc_cache
> +};
> +
> +
> +/* This is the information that is stored at jit_gdbarch_data for each
> + architecture. */
> +
> +struct jit_gdbarch_data_type {
struct jit_gdbarch_data_type
{
> +
> + /* Has the (pseudo) unwinder been prepended? */
> +
> + int unwinder_registered;
> +};
> +
> +/* Check GDBARCH and prepend the pseudo JIT unwinder if needed. */
> +
> +static void
> +jit_prepend_unwinder (struct gdbarch *gdbarch)
> +{
> + struct jit_gdbarch_data_type *data;
> +
> + data = gdbarch_data (gdbarch, jit_gdbarch_data);
> + if (!data->unwinder_registered)
> + {
> + frame_unwind_prepend_unwinder (gdbarch, &jit_frame_unwind);
> + data->unwinder_registered = 1;
> + }
> +}
> +
> /* Register any already created translations. */
>
> static void
> @@ -920,6 +1165,8 @@ jit_inferior_init (struct gdbarch *gdbarch)
> if (jit_debug)
> fprintf_unfiltered (gdb_stdlog, "jit_inferior_init\n");
>
> + jit_prepend_unwinder (gdbarch);
> +
> inf_data = get_jit_inferior_data ();
> if (jit_breakpoint_re_set_internal (gdbarch, inf_data) != 0)
> return;
> @@ -1082,6 +1329,18 @@ free_objfile_data (struct objfile *objfile, void *data)
> xfree (data);
> }
>
> +/* Initialize the jit_gdbarch_data slot with an instance of struct
> + jit_gdbarch_data_type */
> +
> +static void *
> +jit_gdbarch_data_init (struct obstack *obstack)
> +{
> + struct jit_gdbarch_data_type *data =
> + obstack_alloc (obstack, sizeof (struct jit_gdbarch_data_type));
Empty line from declarations.
> + data->unwinder_registered = 0;
> + return data;
> +}
> +
> /* Provide a prototype to silence -Wmissing-prototypes. */
>
> extern void _initialize_jit (void);
> @@ -1104,6 +1363,7 @@ _initialize_jit (void)
> register_objfile_data_with_cleanup (NULL,free_objfile_data);
> jit_inferior_data =
> register_inferior_data_with_cleanup (jit_inferior_data_cleanup);
> + jit_gdbarch_data = gdbarch_data_register_pre_init (jit_gdbarch_data_init);
> add_com ("load-jit-reader", no_class, load_jit_reader_command, _("\
> Try to load file FILE as a debug info reader (and unwinder) for\n\
> JIT compiled code from " LIBDIR "/gdb\n\
> --
> 1.7.5.4
Thanks,
Jan
^ permalink raw reply [flat|nested] 16+ messages in thread* Re: [PATCH 5/6] New JIT unwinder.
2011-08-20 17:59 ` Jan Kratochvil
@ 2011-08-20 18:30 ` Mark Kettenis
2011-08-20 19:45 ` Jan Kratochvil
0 siblings, 1 reply; 16+ messages in thread
From: Mark Kettenis @ 2011-08-20 18:30 UTC (permalink / raw)
To: jan.kratochvil; +Cc: sanjoy, gdb-patches
> Date: Sat, 20 Aug 2011 19:58:38 +0200
> From: Jan Kratochvil <jan.kratochvil@redhat.com>
>
> > +
> > + inf_data = get_jit_inferior_data ();
> > +
> > + callbacks.reg_get = jit_unwind_reg_get_impl;
> > + callbacks.reg_set = jit_unwind_reg_set_impl;
> > + callbacks.target_read = jit_target_read_impl;
>
> Couldn't GDB just export these functions to the plugin without having to use
> the callbacks vector? Python does so, libthread_db does so (see
> proc-service.list).
I'd say that's a bad idea. The --dynamic-list linker option isn't
uniformly available, and even -rdynamic may not work everywehere.
^ permalink raw reply [flat|nested] 16+ messages in thread
* Re: [PATCH 5/6] New JIT unwinder.
2011-08-20 18:30 ` Mark Kettenis
@ 2011-08-20 19:45 ` Jan Kratochvil
2011-08-30 17:53 ` Tom Tromey
0 siblings, 1 reply; 16+ messages in thread
From: Jan Kratochvil @ 2011-08-20 19:45 UTC (permalink / raw)
To: Mark Kettenis; +Cc: sanjoy, gdb-patches
On Sat, 20 Aug 2011 20:29:52 +0200, Mark Kettenis wrote:
> > Couldn't GDB just export these functions to the plugin without having to use
> > the callbacks vector? Python does so, libthread_db does so (see
> > proc-service.list).
>
> I'd say that's a bad idea. The --dynamic-list linker option isn't
> uniformly available, and even -rdynamic may not work everywehere.
But neither glibc libthread_db nor Python works there. But it is true I heard
some platforms have problems creating libraries with referenced unresolved by
any other library.
Jan
^ permalink raw reply [flat|nested] 16+ messages in thread
* Re: [PATCH 5/6] New JIT unwinder.
2011-08-20 19:45 ` Jan Kratochvil
@ 2011-08-30 17:53 ` Tom Tromey
0 siblings, 0 replies; 16+ messages in thread
From: Tom Tromey @ 2011-08-30 17:53 UTC (permalink / raw)
To: Jan Kratochvil; +Cc: Mark Kettenis, sanjoy, gdb-patches
>>>>> "Jan" == Jan Kratochvil <jan.kratochvil@redhat.com> writes:
Jan> Couldn't GDB just export these functions to the plugin without
Jan> having to use the callbacks vector? Python does so, libthread_db
Jan> does so (see proc-service.list).
Mark> I'd say that's a bad idea. The --dynamic-list linker option isn't
Mark> uniformly available, and even -rdynamic may not work everywehere.
Jan> But neither glibc libthread_db nor Python works there. But it is
Jan> true I heard some platforms have problems creating libraries with
Jan> referenced unresolved by any other library.
I think the proposed approach is more flexible, since it lets us more
easily mess with renames and API version changes while keeping
compatibility; while I don't think there are definite advantages to the
libthread_db approach.
Tom
^ permalink raw reply [flat|nested] 16+ messages in thread
* [PATCH 3/6] New commands for loading and unloading a reader.
2011-08-20 6:26 JIT Reader (re-roll) Sanjoy Das
2011-08-20 6:26 ` [PATCH 1/6] Introduce header (jit-reader.in) and modify build system Sanjoy Das
2011-08-20 6:27 ` [PATCH 5/6] New JIT unwinder Sanjoy Das
@ 2011-08-20 6:27 ` Sanjoy Das
2011-08-20 8:24 ` Eli Zaretskii
2011-08-20 17:31 ` Jan Kratochvil
2011-08-20 6:27 ` [PATCH 2/6] Platform agnostic dynamic loading code Sanjoy Das
` (2 subsequent siblings)
5 siblings, 2 replies; 16+ messages in thread
From: Sanjoy Das @ 2011-08-20 6:27 UTC (permalink / raw)
To: gdb-patches; +Cc: Sanjoy Das
Introduces two new GDB commands - `load-jit-reader' and
`unload-jit-reader'.
gdb/ChangeLog
* jit.c (_initialize_jit): Add commands load-jit-reader and
unload-jit-reader.
(jit_reader_load): New function.
---
gdb/ChangeLog | 6 +++
gdb/jit.c | 136 ++++++++++++++++++++++++++++++++++++++++++++++++++++-----
2 files changed, 131 insertions(+), 11 deletions(-)
diff --git a/gdb/ChangeLog b/gdb/ChangeLog
index a5b34dd..dda4a31 100644
--- a/gdb/ChangeLog
+++ b/gdb/ChangeLog
@@ -1,5 +1,11 @@
2011-08-20 Sanjoy Das <sdas@igalia.com>
+ * jit.c (_initialize_jit): Add commands load-jit-reader and
+ unload-jit-reader.
+ (jit_reader_load): New function.
+
+2011-08-20 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.
diff --git a/gdb/jit.c b/gdb/jit.c
index e3bb81a..8cf1109 100644
--- a/gdb/jit.c
+++ b/gdb/jit.c
@@ -31,8 +31,11 @@
#include "symfile.h"
#include "symtab.h"
#include "target.h"
+#include "gdb-dlfcn.h"
#include "gdb_stat.h"
+#define GDB_READER_DIR (LIBDIR "/gdb/")
+
static const struct objfile_data *jit_objfile_data;
static const char *const jit_break_name = "__jit_debug_register_code";
@@ -113,6 +116,109 @@ mem_bfd_iovec_stat (struct bfd *abfd, void *stream, struct stat *sb)
return 0;
}
+/* One reader that has been loaded successfully, and can potentially be used to
+ parse debug info. */
+struct jit_reader
+{
+ struct gdb_reader_funcs *functions;
+} *loaded_jit_reader = NULL;
+
+typedef struct gdb_reader_funcs * (reader_init_fn_type) (void);
+const char *reader_init_fn_sym = "gdb_init_reader";
+
+/* Try to load FILE_NAME as a JIT debug info reader. Set ERROR_STRING
+ in case of an error (and return NULL), else return a correcly
+ formed struct jit_reader. */
+static struct jit_reader *
+jit_reader_load (const char *file_name, char **error_string)
+{
+ void *so;
+ reader_init_fn_type *init_fn;
+ struct jit_reader *new_reader = NULL;
+ struct gdb_reader_funcs *funcs = NULL;
+
+ if (jit_debug)
+ fprintf_unfiltered (gdb_stdlog, "Opening shared object %s.\n", file_name);
+ so = gdb_dlopen (file_name);
+
+ if (!so)
+ {
+ *error_string = _("could not open reader file");
+ return NULL;
+ }
+
+ init_fn = gdb_dlsym (so, reader_init_fn_sym);
+ if (!init_fn)
+ {
+ *error_string = _("could not locate initialization routine");
+ goto error;
+ }
+
+ if (gdb_dlsym (so, "plugin_is_GPL_compatible") == NULL)
+ {
+ *error_string = _("reader not GPL compatible");
+ goto error;
+ }
+
+ funcs = init_fn ();
+ if (funcs->reader_version != GDB_READER_INTERFACE_VERSION)
+ {
+ *error_string = _("incorrect module version");
+ goto error;
+ }
+
+ new_reader = XZALLOC (struct jit_reader);
+ new_reader->functions = funcs;
+ return new_reader;
+
+ error:
+ if (so)
+ gdb_dlclose(so);
+ return NULL;
+}
+
+/* Provides the load-jit-reader command. */
+
+static void
+load_jit_reader_command (char *args, int from_tty)
+{
+ char so_name[PATH_MAX] = GDB_READER_DIR;
+ char *error_string;
+
+ if (args == NULL)
+ {
+ error (_("No reader name provided."));
+ return;
+ }
+
+ if (loaded_jit_reader != NULL)
+ {
+ error (_("JIT reader already loaded. Run unload-jit-reader first."));
+ return;
+ }
+
+ strncat (so_name, args, PATH_MAX - sizeof(GDB_READER_DIR));
+
+ loaded_jit_reader = jit_reader_load (so_name, &error_string);
+ if (loaded_jit_reader == NULL)
+ error(_("Unable to load reader: %s."), error_string);
+}
+
+/* Provides the unload-jit-reader command. */
+
+static void
+unload_jit_reader_command (char *args, int from_tty)
+{
+ if (!loaded_jit_reader)
+ {
+ error(_("No JIT reader loaded."));
+ return;
+ }
+ loaded_jit_reader->functions->destroy (loaded_jit_reader->functions);
+ free (loaded_jit_reader);
+ loaded_jit_reader = NULL;
+}
+
/* Open a BFD from the target's memory. */
static struct bfd *
@@ -510,10 +616,10 @@ jit_event_handler (struct gdbarch *gdbarch)
struct jit_code_entry code_entry;
CORE_ADDR entry_addr;
struct objfile *objf;
+ struct jit_inferior_data *inf_data = get_jit_inferior_data ();
/* Read the descriptor from remote memory. */
- jit_read_descriptor (gdbarch, &descriptor,
- get_jit_inferior_data ()->descriptor_addr);
+ jit_read_descriptor (gdbarch, &descriptor, inf_data->descriptor_addr);
entry_addr = descriptor.relevant_entry;
/* Do the corresponding action. */
@@ -526,15 +632,16 @@ jit_event_handler (struct gdbarch *gdbarch)
jit_register_code (gdbarch, entry_addr, &code_entry);
break;
case JIT_UNREGISTER:
- objf = jit_find_objf_with_entry_addr (entry_addr);
- if (objf == NULL)
- printf_unfiltered (_("Unable to find JITed code "
- "entry at address: %s\n"),
- paddress (gdbarch, entry_addr));
- else
- jit_unregister_code (objf);
-
- break;
+ {
+ objf = jit_find_objf_with_entry_addr (entry_addr);
+ if (objf == NULL)
+ printf_unfiltered (_("Unable to find JITed code "
+ "entry at address: %s\n"),
+ paddress (gdbarch, entry_addr));
+ else
+ jit_unregister_code (objf);
+ break;
+ }
default:
error (_("Unknown action_flag value in JIT descriptor!"));
break;
@@ -562,4 +669,11 @@ _initialize_jit (void)
jit_objfile_data = register_objfile_data ();
jit_inferior_data =
register_inferior_data_with_cleanup (jit_inferior_data_cleanup);
+ add_com ("load-jit-reader", no_class, load_jit_reader_command, _("\
+Try to load file FILE as a debug info reader (and unwinder) for\n\
+JIT compiled code from " LIBDIR "/gdb\n\
+Usage is `load-jit-reader FILE`."));
+ add_com ("unload-jit-reader", no_class, unload_jit_reader_command, _("\
+Unload the currently loaded JIT reader (loaded using load-jit-reader)\n\
+Usage is `unload-jit-reader`."));
}
--
1.7.5.4
^ permalink raw reply [flat|nested] 16+ messages in thread* Re: [PATCH 3/6] New commands for loading and unloading a reader.
2011-08-20 6:27 ` [PATCH 3/6] New commands for loading and unloading a reader Sanjoy Das
@ 2011-08-20 8:24 ` Eli Zaretskii
2011-08-20 17:31 ` Jan Kratochvil
1 sibling, 0 replies; 16+ messages in thread
From: Eli Zaretskii @ 2011-08-20 8:24 UTC (permalink / raw)
To: Sanjoy Das; +Cc: gdb-patches
> From: Sanjoy Das <sanjoy@playingwithpointers.com>
> Cc: Sanjoy Das <sanjoy@playingwithpointers.com>
> Date: Sat, 20 Aug 2011 11:57:12 +0530
>
> + add_com ("load-jit-reader", no_class, load_jit_reader_command, _("\
> +Try to load file FILE as a debug info reader (and unwinder) for\n\
> +JIT compiled code from " LIBDIR "/gdb\n\
> +Usage is `load-jit-reader FILE`."));
The first line of a doc string should be a complete sentence, because
it is displayed by help commands such as apropos. I suggest
Load FILE as debug info reader and unwinder for JIT compiled code.
Then you can have the more detailed information in the rest of the doc
string.
> + add_com ("unload-jit-reader", no_class, unload_jit_reader_command, _("\
> +Unload the currently loaded JIT reader (loaded using load-jit-reader)\n\
> +Usage is `unload-jit-reader`."));
The reference to load-jit-reader in the first line looks redundant.
And the usage is trivial. How about this instead?
Unload the currently loaded JIT debug info reader.
See load-jit-reader for how to load JIT debug readers.
Thanks.
^ permalink raw reply [flat|nested] 16+ messages in thread* Re: [PATCH 3/6] New commands for loading and unloading a reader.
2011-08-20 6:27 ` [PATCH 3/6] New commands for loading and unloading a reader Sanjoy Das
2011-08-20 8:24 ` Eli Zaretskii
@ 2011-08-20 17:31 ` Jan Kratochvil
1 sibling, 0 replies; 16+ messages in thread
From: Jan Kratochvil @ 2011-08-20 17:31 UTC (permalink / raw)
To: Sanjoy Das; +Cc: gdb-patches
On Sat, 20 Aug 2011 08:27:12 +0200, Sanjoy Das wrote:
> + {
> + error (_("No reader name provided."));
> + return;
> + }
error is terminal call, no return is needed. (present multiple times)
Jan
^ permalink raw reply [flat|nested] 16+ messages in thread
* [PATCH 2/6] Platform agnostic dynamic loading code.
2011-08-20 6:26 JIT Reader (re-roll) Sanjoy Das
` (2 preceding siblings ...)
2011-08-20 6:27 ` [PATCH 3/6] New commands for loading and unloading a reader Sanjoy Das
@ 2011-08-20 6:27 ` Sanjoy Das
2011-08-20 6:33 ` [PATCH 4/6] Use the loaded reader Sanjoy Das
2011-08-20 6:33 ` [PATCH 6/6] Documentation Sanjoy Das
5 siblings, 0 replies; 16+ messages in thread
From: Sanjoy Das @ 2011-08-20 6:27 UTC (permalink / raw)
To: gdb-patches; +Cc: Sanjoy Das
gdb-dlfcn.h and gdb-dlfcn.c are added, which implement the (cross
platform) functions gdb_dlopen, gdb_dlsym and gdb_dlclose. They should
work correctly on POSIX and windows systems.
gdb/ChangeLog
* gdb-dlfcn.h, gdb-dlfcn.c: New.
* Makefile.in: Add gdb_dlcfn.c and gdb_dlcfn.h to the build
system.
---
gdb/ChangeLog | 6 +++++
gdb/Makefile.in | 6 ++--
gdb/gdb-dlfcn.c | 61 +++++++++++++++++++++++++++++++++++++++++++++++++++++++
gdb/gdb-dlfcn.h | 37 +++++++++++++++++++++++++++++++++
4 files changed, 107 insertions(+), 3 deletions(-)
create mode 100644 gdb/gdb-dlfcn.c
create mode 100644 gdb/gdb-dlfcn.h
diff --git a/gdb/ChangeLog b/gdb/ChangeLog
index 369cc35..a5b34dd 100644
--- a/gdb/ChangeLog
+++ b/gdb/ChangeLog
@@ -1,3 +1,9 @@
+2011-08-20 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.
+
2011-08-20 Sanjoy Das <sdas@igalia.com>
* Makefile.in: Add jit-reader.in to HFILES_WITH_SRCDIR,
diff --git a/gdb/Makefile.in b/gdb/Makefile.in
index 2e24dfa..29a686b 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/gdb-dlfcn.c b/gdb/gdb-dlfcn.c
new file mode 100644
index 0000000..8a9d7a3
--- /dev/null
+++ b/gdb/gdb-dlfcn.c
@@ -0,0 +1,61 @@
+/* Platform independent shared object routines for GDB.
+
+ 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/>. */
+
+#include "gdb-dlfcn.h"
+
+#include "defs.h"
+
+#ifdef HAVE_LIBDL
+#include <dlfcn.h>
+#elif __MINGW32__
+#include <windows.h>
+#else
+/* Unsupported configuration. See Eg. gdb_dlopen for details. */
+#error API to load shared library missing (Eg. libdl)
+#endif
+
+void *
+gdb_dlopen (const char *filename)
+{
+#ifdef HAVE_LIBDL
+ return dlopen (filename, RTLD_NOW);
+#elif __MINGW32__
+ return (void *) LoadLibrary (filename);
+#endif
+}
+
+void *
+gdb_dlsym (void *handle, const char *symbol)
+{
+#ifdef HAVE_LIBDL
+ return dlsym (handle, symbol);
+#elif __MINGW32__
+ return (void *) GetProcAddress (handle, symbol);
+#endif
+}
+
+int
+gdb_dlclose (void *handle)
+{
+#ifdef HAVE_LIBDL
+ return dlclose (handle);
+#elif __MINGW32__
+ return !((int) FreeLibrary (handle));
+#endif
+}
diff --git a/gdb/gdb-dlfcn.h b/gdb/gdb-dlfcn.h
new file mode 100644
index 0000000..69cb032
--- /dev/null
+++ b/gdb/gdb-dlfcn.h
@@ -0,0 +1,37 @@
+/* Platform independent shared object routines for GDB.
+
+ 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_DLFCN_H
+#define GDB_DLFCN_H
+
+/* Load the dynamic library file named FILENAME, and return a handle
+ for that dynamic library. Return NULL if the loading fails for any
+ reason. */
+void *gdb_dlopen (const char *filename);
+
+/* Return the address of the symbol named SYMBOL inside the shared
+ library whose handle is HANDLE. Return NULL when the symbol could
+ not be found. */
+void *gdb_dlsym (void *handle, const char *symbol);
+
+/* Cleanup the shared object pointed to by HANDLE. Return 0 on success
+ and nonzero on failure. */
+int gdb_dlclose (void *handle);
+
+#endif /* GDB_DLFCN_H */
--
1.7.5.4
^ permalink raw reply [flat|nested] 16+ messages in thread* [PATCH 4/6] Use the loaded reader.
2011-08-20 6:26 JIT Reader (re-roll) Sanjoy Das
` (3 preceding siblings ...)
2011-08-20 6:27 ` [PATCH 2/6] Platform agnostic dynamic loading code Sanjoy Das
@ 2011-08-20 6:33 ` Sanjoy Das
2011-08-20 6:33 ` [PATCH 6/6] Documentation Sanjoy Das
5 siblings, 0 replies; 16+ messages in thread
From: Sanjoy Das @ 2011-08-20 6:33 UTC (permalink / raw)
To: gdb-patches; +Cc: Sanjoy Das
Invoke the loaded JIT debug info reader to parse the registered symbol
files.
gdb/ChangeLog
* jit.c (add_objfile_entry, jit_target_read_impl)
(jit_object_open_impl, jit_symtab_open_impl, compare_block)
(jit_block_open_impl, jit_block_open_impl)
(jit_symtab_line_mapping_impl, jit_symtab_close_impl)
(finalize_symtab, jit_object_close_impl)
(jit_reader_try_read_symtab, jit_bfd_try_read_symtab): New
functions.
(jit_register_code): Try using the loaded jit reader before
resorting to BFD.
---
gdb/ChangeLog | 12 ++
gdb/jit.c | 495 +++++++++++++++++++++++++++++++++++++++++++++++++++++----
2 files changed, 477 insertions(+), 30 deletions(-)
diff --git a/gdb/ChangeLog b/gdb/ChangeLog
index dda4a31..70c280e 100644
--- a/gdb/ChangeLog
+++ b/gdb/ChangeLog
@@ -1,5 +1,17 @@
2011-08-20 Sanjoy Das <sdas@igalia.com>
+ * jit.c (add_objfile_entry, jit_target_read_impl)
+ (jit_object_open_impl, jit_symtab_open_impl, compare_block)
+ (jit_block_open_impl, jit_block_open_impl)
+ (jit_symtab_line_mapping_impl, jit_symtab_close_impl)
+ (finalize_symtab, jit_object_close_impl)
+ (jit_reader_try_read_symtab, jit_bfd_try_read_symtab): New
+ functions.
+ (jit_register_code): Try using the loaded jit reader before
+ resorting to BFD.
+
+2011-08-20 Sanjoy Das <sdas@igalia.com>
+
* jit.c (_initialize_jit): Add commands load-jit-reader and
unload-jit-reader.
(jit_reader_load): New function.
diff --git a/gdb/jit.c b/gdb/jit.c
index 8cf1109..d4d7ddb 100644
--- a/gdb/jit.c
+++ b/gdb/jit.c
@@ -21,8 +21,11 @@
#include "jit.h"
#include "jit-reader.h"
+#include "block.h"
#include "breakpoint.h"
#include "command.h"
+#include "dictionary.h"
+#include "frame-unwind.h"
#include "gdbcmd.h"
#include "gdbcore.h"
#include "inferior.h"
@@ -118,6 +121,7 @@ mem_bfd_iovec_stat (struct bfd *abfd, void *stream, struct stat *sb)
/* One reader that has been loaded successfully, and can potentially be used to
parse debug info. */
+
struct jit_reader
{
struct gdb_reader_funcs *functions;
@@ -129,6 +133,7 @@ const char *reader_init_fn_sym = "gdb_init_reader";
/* Try to load FILE_NAME as a JIT debug info reader. Set ERROR_STRING
in case of an error (and return NULL), else return a correcly
formed struct jit_reader. */
+
static struct jit_reader *
jit_reader_load (const char *file_name, char **error_string)
{
@@ -245,6 +250,18 @@ struct jit_inferior_data
CORE_ADDR descriptor_addr; /* &__jit_debug_descriptor */
};
+/* Remember a mapping from entry_addr to objfile. */
+
+static void
+add_objfile_entry (struct objfile *objfile, CORE_ADDR entry)
+{
+ CORE_ADDR *entry_addr_ptr;
+
+ entry_addr_ptr = xmalloc (sizeof (CORE_ADDR));
+ *entry_addr_ptr = entry;
+ set_objfile_data (objfile, jit_objfile_data, entry_addr_ptr);
+}
+
/* Return jit_inferior_data for current inferior. Allocate if not already
present. */
@@ -341,37 +358,424 @@ jit_read_code_entry (struct gdbarch *gdbarch,
extract_unsigned_integer (&entry_buf[3 * ptr_size], 8, byte_order);
}
-/* This function registers code associated with a JIT code entry. It uses the
- pointer and size pair in the entry to read the symbol file from the remote
- and then calls symbol_file_add_from_local_memory to add it as though it were
- a symbol file added by the user. */
+/* Proxy object for building a block. */
+
+struct gdb_block
+{
+ /* gdb_blocks are linked into a tree structure. Next points to the
+ next node at the same depth as this block and parent to the
+ parent gdb_block. */
+
+ struct gdb_block *next, *parent;
+ struct block *real_block;
+
+ /* The first and last code address corresponding to this block */
+
+ CORE_ADDR begin, end;
+
+ /* The name of this block (if any). If this is non-NULL, the
+ FUNCTION symbol symbol is set to this value. */
+
+ const char *name;
+};
+
+/* Proxy object for building a symtab. */
+
+struct gdb_symtab
+{
+ /* The list of blocks in this symtab. These will eventually be
+ converted to real blocks. */
+
+ struct gdb_block *blocks;
+
+ /* The number of blocks inserted. */
+
+ int nblocks;
+
+ /* A mapping between line numbers to PC. */
+
+ struct linetable *linetable;
+
+ /* The source file for this symtab. */
+
+ const char *file_name;
+ struct gdb_symtab *next;
+};
+
+/* Proxy object for building an object. */
+
+struct gdb_object
+{
+ struct gdb_symtab *symtabs;
+};
+
+/* The type of the `private' data passed around by the callback
+ functions. */
+
+struct jit_dbg_reader_data
+{
+ CORE_ADDR entry_address;
+};
+
+/* The reader calls into this function to read data off the targets
+ address space. */
+
+static enum gdb_status
+jit_target_read_impl (GDB_CORE_ADDR target_mem, void *gdb_buf, int len)
+{
+ int result = target_read_memory ((CORE_ADDR) target_mem, gdb_buf, len);
+ if (result == 0)
+ return GDB_SUCCESS;
+ else
+ return GDB_FAIL;
+}
+
+/* The reader calls into this function to create a new gdb_object
+ which it can then pass around to the other callbacks. Right now,
+ all that is required is allocating the memory. */
+
+static struct gdb_object *
+jit_object_open_impl (struct gdb_symbol_callbacks *cb)
+{
+ return XZALLOC (struct gdb_object);
+}
+
+/* Readers call into this function to open a new gdb_symtab, which,
+ again, is passed around to other callbacks. */
+
+static struct gdb_symtab *
+jit_symtab_open_impl (struct gdb_symbol_callbacks *cb,
+ struct gdb_object *object,
+ const char *file_name)
+{
+ struct gdb_symtab *ret;
+
+ ret = XZALLOC (struct gdb_symtab);
+ ret->file_name = file_name ? xstrdup (file_name) : xstrdup ("");
+ ret->next = object->symtabs;
+ object->symtabs = ret;
+ return ret;
+}
+
+/* Returns true if the block corresponding to old should be placed
+ before the block corresponding to new in the final blockvector. */
+
+static int
+compare_block (struct gdb_block *old, struct gdb_block *new)
+{
+ if (old == NULL)
+ return 1;
+ if (old->begin < new->begin)
+ return 1;
+ else if (old->begin == new->begin)
+ {
+ if (old->end > new->end)
+ return 1;
+ else
+ return 0;
+ }
+ else
+ return 0;
+}
+
+/* Called by readers to open a new gdb_block. This function also
+ inserts the new gdb_block in the correct place in the corresponding
+ gdb_symtab. */
+
+static struct gdb_block *
+jit_block_open_impl (struct gdb_symbol_callbacks *cb,
+ struct gdb_symtab *symtab, struct gdb_block *parent,
+ GDB_CORE_ADDR begin, GDB_CORE_ADDR end, const char *name)
+{
+ struct gdb_block *block = XZALLOC (struct gdb_block);
+
+ block->next = symtab->blocks;
+ block->begin = (CORE_ADDR) begin;
+ block->end = (CORE_ADDR) end;
+ block->name = name ? xstrdup (name) : NULL;
+ block->parent = parent;
+
+ /* Ensure that the blocks are inserted in the correct (reverse of
+ the order expected by blockvector). */
+ if (compare_block (symtab->blocks, block))
+ {
+ symtab->blocks = block;
+ }
+ else
+ {
+ struct gdb_block *i = symtab->blocks;
+
+ for (;; i = i->next)
+ {
+ /* Guaranteed to terminate, since compare_block (NULL, _)
+ returns 1 */
+ if (compare_block (i->next, block))
+ {
+ block->next = i->next;
+ i->next = block;
+ break;
+ }
+ }
+ }
+ symtab->nblocks++;
+
+ return block;
+}
+
+/* Readers call this to add a line mapping (from PC to line number) to
+ a gdb_symtab. */
static void
-jit_register_code (struct gdbarch *gdbarch,
- CORE_ADDR entry_addr, struct jit_code_entry *code_entry)
+jit_symtab_line_mapping_add_impl (struct gdb_symbol_callbacks *cb,
+ struct gdb_symtab *stab, int nlines,
+ struct gdb_line_mapping *map)
{
+ int i;
+
+ if (nlines < 1)
+ return;
+
+ stab->linetable = xmalloc (sizeof (struct linetable)
+ + (nlines - 1) * sizeof (struct linetable_entry));
+ stab->linetable->nitems = nlines;
+ for (i = 0; i < nlines; i++)
+ {
+ stab->linetable->item [i].pc = (CORE_ADDR) map[i].pc;
+ stab->linetable->item [i].line = map[i].line;
+ }
+}
+
+/* Called by readers to close a gdb_symtab. Does not need to do
+ anything as of now. */
+
+static void
+jit_symtab_close_impl (struct gdb_symbol_callbacks *cb,
+ struct gdb_symtab *stab)
+{
+}
+
+/* Transform STAB to a proper symtab, and add it it OBJFILE. */
+
+static void
+finalize_symtab (struct gdb_symtab *stab, struct objfile *objfile)
+{
+ struct symtab *symtab;
+ struct gdb_block *gdb_block_iter, *gdb_block_iter_tmp;
+ struct block *block_iter;
+ int actual_nblocks, i, blockvector_size;
+ CORE_ADDR begin, end;
+
+ actual_nblocks = FIRST_LOCAL_BLOCK + stab->nblocks;
+
+ symtab = allocate_symtab (stab->file_name, objfile);
+ symtab->dirname = NULL; /* JIT compilers compile in memory */
+
+ /* Copy over the linetable entry if one was provided. */
+ if (stab->linetable)
+ {
+ int size = ((stab->linetable->nitems - 1)
+ * sizeof (struct linetable_entry)
+ + sizeof (struct linetable));
+ LINETABLE (symtab) = obstack_alloc (&objfile->objfile_obstack, size);
+ memcpy (LINETABLE (symtab), stab->linetable, size);
+ }
+ else
+ {
+ LINETABLE (symtab) = NULL;
+ }
+
+ blockvector_size = (sizeof (struct blockvector)
+ + (actual_nblocks - 1) * sizeof (struct block *));
+ symtab->blockvector = obstack_alloc (&objfile->objfile_obstack,
+ blockvector_size);
+
+ /* (begin, end) will contain the PC range this entire blockvector spans. */
+ symtab->primary = 1;
+ BLOCKVECTOR_MAP (symtab->blockvector) = NULL;
+ begin = stab->blocks->begin;
+ end = stab->blocks->end;
+ BLOCKVECTOR_NBLOCKS (symtab->blockvector) = actual_nblocks;
+
+ /* First run over all the gdb_block objects, creating a real block
+ object for each. Simultaneously, keep setting the real_block
+ fields. */
+ for (i = (actual_nblocks - 1), gdb_block_iter = stab->blocks;
+ i >= FIRST_LOCAL_BLOCK; i--, gdb_block_iter = gdb_block_iter->next)
+ {
+ struct block *new_block = allocate_block (&objfile->objfile_obstack);
+ struct symbol *block_name = obstack_alloc (&objfile->objfile_obstack,
+ sizeof (struct symbol));
+
+ BLOCK_DICT (new_block) = dict_create_linear (&objfile->objfile_obstack,
+ NULL);
+ /* The address range. */
+ BLOCK_START (new_block) = (CORE_ADDR) gdb_block_iter->begin;
+ BLOCK_END (new_block) = (CORE_ADDR) gdb_block_iter->end;
+
+ /* The name. */
+ memset (block_name, 0, sizeof (struct symbol));
+ SYMBOL_DOMAIN (block_name) = VAR_DOMAIN;
+ SYMBOL_CLASS (block_name) = LOC_BLOCK;
+ SYMBOL_SYMTAB (block_name) = symtab;
+ SYMBOL_BLOCK_VALUE (block_name) = new_block;
+
+ block_name->ginfo.name = obsavestring (gdb_block_iter->name,
+ strlen (gdb_block_iter->name),
+ &objfile->objfile_obstack);
+
+ BLOCK_FUNCTION (new_block) = block_name;
+
+ BLOCKVECTOR_BLOCK (symtab->blockvector, i) = new_block;
+ if (begin > BLOCK_START (new_block))
+ begin = BLOCK_START (new_block);
+ if (end < BLOCK_END (new_block))
+ end = BLOCK_END (new_block);
+
+ gdb_block_iter->real_block = new_block;
+ }
+
+ /* Now add the special blocks. */
+ block_iter = NULL;
+ for (i = 0; i < FIRST_LOCAL_BLOCK; i++)
+ {
+ struct block *new_block = allocate_block (&objfile->objfile_obstack);
+ BLOCK_DICT (new_block) = dict_create_linear (&objfile->objfile_obstack,
+ NULL);
+ BLOCK_SUPERBLOCK (new_block) = block_iter;
+ block_iter = new_block;
+
+ BLOCK_START (new_block) = (CORE_ADDR) begin;
+ BLOCK_END (new_block) = (CORE_ADDR) end;
+
+ BLOCKVECTOR_BLOCK (symtab->blockvector, i) = new_block;
+ }
+
+ /* Fill up the superblock fields for the real blocks, using the
+ real_block fields populated earlier. */
+ for (gdb_block_iter = stab->blocks; gdb_block_iter;
+ gdb_block_iter = gdb_block_iter->next)
+ {
+ if (gdb_block_iter->parent != NULL)
+ BLOCK_SUPERBLOCK (gdb_block_iter->real_block) =
+ gdb_block_iter->parent->real_block;
+ }
+
+ /* Free memory. */
+ gdb_block_iter = stab->blocks;
+
+ for (gdb_block_iter = stab->blocks, gdb_block_iter_tmp = gdb_block_iter->next;
+ gdb_block_iter; gdb_block_iter = gdb_block_iter_tmp)
+ {
+ xfree ((void *) gdb_block_iter->name);
+ xfree (gdb_block_iter);
+ }
+ xfree (stab->linetable);
+ xfree ((char *) stab->file_name);
+ xfree (stab);
+}
+
+/* Called when closing a gdb_objfile. Converts OBJ to a proper objfile. */
+
+static void
+jit_object_close_impl (struct gdb_symbol_callbacks *cb,
+ struct gdb_object *obj)
+{
+ struct gdb_symtab *i, *j;
+ struct objfile *objfile;
+ struct jit_dbg_reader_data *priv_data;
+
+ priv_data = cb->priv_data;
+
+ objfile = allocate_objfile (NULL, 0);
+ objfile->gdbarch = target_gdbarch;
+ objfile->msymbols = obstack_alloc (&objfile->objfile_obstack,
+ sizeof (struct minimal_symbol));
+ objfile->msymbols[0].ginfo.name = NULL;
+ objfile->msymbols[0].ginfo.value.address = 0;
+
+ xfree (objfile->name);
+ objfile->name = xstrdup ("<< JIT compiled code >>");
+
+ j = NULL;
+ for (i = obj->symtabs; i; i = j)
+ {
+ j = i->next;
+ finalize_symtab (i, objfile);
+ }
+ add_objfile_entry (objfile, priv_data->entry_address);
+ xfree (obj);
+}
+
+/* Try to read CODE_ENTRY using the loaded jit reader (if any). */
+
+static int
+jit_reader_try_read_symtab (struct jit_code_entry *code_entry)
+{
+ void *gdb_mem;
+ int status = 0;
+ struct jit_dbg_reader *i;
+ struct jit_dbg_reader_data priv_data;
+ struct gdb_reader_funcs *funcs;
+ struct gdb_symbol_callbacks callbacks =
+ {
+ jit_object_open_impl,
+ jit_symtab_open_impl,
+ jit_block_open_impl,
+ jit_symtab_close_impl,
+ jit_object_close_impl,
+
+ jit_symtab_line_mapping_add_impl,
+ jit_target_read_impl,
+
+ &priv_data
+ };
+
+ priv_data.entry_address = code_entry->symfile_addr;
+
+ if (!loaded_jit_reader)
+ return 0;
+
+ gdb_mem = xmalloc (code_entry->symfile_size);
+ if (target_read_memory (code_entry->symfile_addr, gdb_mem,
+ code_entry->symfile_size))
+ {
+ status = 0;
+ goto cleanup;
+ }
+
+ funcs = loaded_jit_reader->functions;
+ if (funcs->read (funcs, &callbacks, gdb_mem, code_entry->symfile_size)
+ == GDB_SUCCESS)
+ {
+ status = 1;
+ goto cleanup;
+ }
+
+ cleanup:
+ xfree (gdb_mem);
+ return status;
+}
+
+/* Try to read CODE_ENTRY using BFD. */
+
+static void
+jit_bfd_try_read_symtab (struct jit_code_entry *code_entry,
+ struct gdbarch *gdbarch)
+{
+ struct cleanup *old_cleanups;
+ struct objfile *objfile;
bfd *nbfd;
struct section_addr_info *sai;
struct bfd_section *sec;
- struct objfile *objfile;
- struct cleanup *old_cleanups, *my_cleanups;
- int i;
const struct bfd_arch_info *b;
- CORE_ADDR *entry_addr_ptr;
-
- if (jit_debug)
- fprintf_unfiltered (gdb_stdlog,
- "jit_register_code, symfile_addr = %s, "
- "symfile_size = %s\n",
- paddress (gdbarch, code_entry->symfile_addr),
- pulongest (code_entry->symfile_size));
+ int i;
nbfd = bfd_open_from_target_memory (code_entry->symfile_addr,
code_entry->symfile_size, gnutarget);
old_cleanups = make_cleanup_bfd_close (nbfd);
- /* Check the format. NOTE: This initializes important data that GDB uses!
- We would segfault later without this line. */
+ /* Check the format. NOTE: This initializes important data that GDB
+ uses! We would segfault later without this line. */
if (!bfd_check_format (nbfd, bfd_object))
{
printf_unfiltered (_("\
@@ -387,17 +791,17 @@ JITed symbol file is not an object file, ignoring it.\n"));
"with target architecture %s."), bfd_get_arch_info
(nbfd)->printable_name, b->printable_name);
- /* Read the section address information out of the symbol file. Since the
- file is generated by the JIT at runtime, it should all of the absolute
- addresses that we care about. */
+ /* Read the section address information out of the symbol file.
+ Since the file is generated by the JIT at runtime, it should all
+ of the absolute addresses that we care about. */
sai = alloc_section_addr_info (bfd_count_sections (nbfd));
make_cleanup_free_section_addr_info (sai);
i = 0;
for (sec = nbfd->sections; sec != NULL; sec = sec->next)
if ((bfd_get_section_flags (nbfd, sec) & (SEC_ALLOC|SEC_LOAD)) != 0)
{
- /* We assume that these virtual addresses are absolute, and do not
- treat them as offsets. */
+ /* We assume that these virtual addresses are absolute, and do
+ not treat them as offsets. */
sai->other[i].addr = bfd_get_section_vma (nbfd, sec);
sai->other[i].name = xstrdup (bfd_get_section_name (nbfd, sec));
sai->other[i].sectindex = sec->index;
@@ -407,12 +811,34 @@ JITed symbol file is not an object file, ignoring it.\n"));
/* This call takes ownership of sai. */
objfile = symbol_file_add_from_bfd (nbfd, 0, sai, OBJF_SHARED, NULL);
- /* Remember a mapping from entry_addr to objfile. */
- entry_addr_ptr = xmalloc (sizeof (CORE_ADDR));
- *entry_addr_ptr = entry_addr;
- set_objfile_data (objfile, jit_objfile_data, entry_addr_ptr);
-
discard_cleanups (old_cleanups);
+ add_objfile_entry (objfile, code_entry->symfile_addr);
+}
+
+/* This function registers code associated with a JIT code entry. It uses the
+ pointer and size pair in the entry to read the symbol file from the remote
+ and then calls symbol_file_add_from_local_memory to add it as though it were
+ a symbol file added by the user. */
+
+static void
+jit_register_code (struct gdbarch *gdbarch,
+ CORE_ADDR entry_addr, struct jit_code_entry *code_entry)
+{
+ int i, success;
+ const struct bfd_arch_info *b;
+ struct jit_inferior_data *inf_data = get_jit_inferior_data ();
+
+ if (jit_debug)
+ fprintf_unfiltered (gdb_stdlog,
+ "jit_register_code, symfile_addr = %s, "
+ "symfile_size = %s\n",
+ paddress (gdbarch, code_entry->symfile_addr),
+ pulongest (code_entry->symfile_size));
+
+ success = jit_reader_try_read_symtab (code_entry);
+
+ if (!success)
+ jit_bfd_try_read_symtab (code_entry, gdbarch);
}
/* This function unregisters JITed code and frees the corresponding
@@ -648,6 +1074,14 @@ jit_event_handler (struct gdbarch *gdbarch)
}
}
+/* Called to free the data allocated to the jit_inferior_data slot. */
+
+static void
+free_objfile_data (struct objfile *objfile, void *data)
+{
+ xfree (data);
+}
+
/* Provide a prototype to silence -Wmissing-prototypes. */
extern void _initialize_jit (void);
@@ -666,7 +1100,8 @@ _initialize_jit (void)
observer_attach_inferior_created (jit_inferior_created_observer);
observer_attach_inferior_exit (jit_inferior_exit_hook);
observer_attach_executable_changed (jit_executable_changed_observer);
- jit_objfile_data = register_objfile_data ();
+ jit_objfile_data =
+ register_objfile_data_with_cleanup (NULL,free_objfile_data);
jit_inferior_data =
register_inferior_data_with_cleanup (jit_inferior_data_cleanup);
add_com ("load-jit-reader", no_class, load_jit_reader_command, _("\
--
1.7.5.4
^ permalink raw reply [flat|nested] 16+ messages in thread* [PATCH 6/6] Documentation.
2011-08-20 6:26 JIT Reader (re-roll) Sanjoy Das
` (4 preceding siblings ...)
2011-08-20 6:33 ` [PATCH 4/6] Use the loaded reader Sanjoy Das
@ 2011-08-20 6:33 ` Sanjoy Das
2011-08-20 8:34 ` Eli Zaretskii
5 siblings, 1 reply; 16+ messages in thread
From: Sanjoy Das @ 2011-08-20 6:33 UTC (permalink / raw)
To: gdb-patches; +Cc: Sanjoy Das
Add some basic documentation to gdb.texinfo about the new JIT reader
functionality. Most of the actual documentation is still in
jit-reader.h.
gdb/ChangeLog
* doc/gdb.texinfo (JIT Interface): Added node `Custom Debug Info'.
(Custom Debug Info, Using Readers, Writing Readers): New nodes.
---
gdb/ChangeLog | 5 ++
gdb/doc/gdb.texinfo | 119 +++++++++++++++++++++++++++++++++++++++++++++++++++
2 files changed, 124 insertions(+), 0 deletions(-)
diff --git a/gdb/ChangeLog b/gdb/ChangeLog
index 92d645b..a2f6794 100644
--- a/gdb/ChangeLog
+++ b/gdb/ChangeLog
@@ -1,5 +1,10 @@
2011-08-20 Sanjoy Das <sdas@igalia.com>
+ * doc/gdb.texinfo (JIT Interface): Added node `Custom Debug Info'.
+ (Custom Debug Info, Using Readers, Writing Readers): New nodes.
+
+2011-08-20 Sanjoy Das <sdas@igalia.com>
+
* jit.c (jut_unwind_reg_set_impl, free_reg_value_impl)
(jit_unwind_reg_get_impl, jit_frame_sniffer)
(jit_frame_unwind_stop_reason, jit_frame_this_id)
diff --git a/gdb/doc/gdb.texinfo b/gdb/doc/gdb.texinfo
index 6e7bf52..f6103aa 100644
--- a/gdb/doc/gdb.texinfo
+++ b/gdb/doc/gdb.texinfo
@@ -30950,6 +30950,7 @@ out about additional code.
* Declarations:: Relevant C struct declarations
* Registering Code:: Steps to register code
* Unregistering Code:: Steps to unregister code
+* Custom Debug Info:: Emit debug information in a custom format
@end menu
@node Declarations
@@ -31046,6 +31047,124 @@ 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 Debug Info
+@section Custom Debug Info
+@cindex custom JIT debug info
+@cindex JIT debug info reader
+
+Generating debug information in platform-native file formats (like ELF
+or COFF) may be an overkill for JIT compilers; especially if all the
+debug info is used for is displaying a meaningful backtrace. The
+issue can be resolved by having the JIT writers decide on a debug info
+format and also provide a reader that parses the debug info generated
+by the JIT compiler. This section gives a brief overview on writing
+such a parser. More specific details can be found in the file
+@file{gdb/jit-reader.h.in}.
+
+The reader is implemented as a shared object. Two new @value{GDBN}
+commands, @code{load-jit-reader} and @code{unload-jit-reader} are
+added, to be used to load and unload the readers from a preconfigured
+directory. Once loaded, the shared object is used the parse the debug
+information emitted by the JIT compiler.
+
+@menu
+* Using Readers:: How to use supplied readers correctly
+* Writing Readers:: Creating a debug-info reader
+@end menu
+
+@node Using Readers
+@subsection Using Readers
+@kindex load-jit-reader
+@kindex unload-jit-reader
+
+Readers can be loaded and unloaded using the @code{load-jit-reader}
+and @code{unload-jit-reader} commands.
+
+@table @code
+@kindex load-jit-reader
+@item load-jit-reader @var{reader-name}
+
+Load the JIT reader named @var{reader-name}. On a UNIX system, this
+will usually result load @file{@var{libdir}/gdb/@var{reader-name}},
+where @var{libdir} is the system library directory, usually
+@file{/usr/local/lib}. Only one reader can be active at a time;
+trying to load a second reader when one is already loaded will result
+in @value{GDBN} reporting an error. A new JIT reader can be loaded by
+first unloading the current one using @code{unload-jit-reader} and
+then running @code{load-jit-reader}.
+
+@kindex unload-jit-reader
+@item unload-jit-reader
+
+Unload the currently loaded JIT reader.
+
+@end table
+
+@node Writing Readers
+@subsection Writing Readers
+
+As mentioned, a reader is essentially a shared object conforming to a
+certain ABI. This ABI is described in @file{jit-reader.h}.
+
+@file{jit-reader.h} defines the structures, macros and functions
+required to write a reader. It is installed (along with
+@value{GDBN}), in @file{@var{includedir}/gdb} where @var{includedir} is
+the system include directory.
+
+Readers need to be released under a GPL compatible license. A reader
+can be declared as released under such a license by placing the macro
+@code{GDB_DECLARE_GPL_COMPATIBLE_READER} in a source file.
+
+The entry point for readers is the symbol @code{gdb_init_reader},
+which is expected to be a function with the prototype
+
+@findex gdb_init_reader
+
+@smallexample
+extern struct gdb_reader_funcs *gdb_init_reader (void);
+@end smallexample
+
+@cindex @code{struct gdb_reader_funcs}
+
+@code{struct gdb_reader_funcs} contains a set of pointers to callback
+functions. These functions are executed to read the debug info
+generated by the JIT compiler (@code{read}), to unwind stack frames
+(@code{unwind}) and to create canonical frame IDs
+(@code{get_Frame_id}). It also has a callback that is called when the
+reader is being unloaded (@code{destroy}). The struct looks like this
+
+@smallexample
+struct gdb_reader_funcs
+@{
+ /* Must be set to GDB_READER_INTERFACE_VERSION */
+
+ int reader_version;
+
+ /* For use by the reader. */
+
+ void *priv_data;
+
+ gdb_read_debug_info *read;
+ gdb_unwind_frame *unwind;
+ gdb_get_frame_id *get_frame_id;
+ gdb_destroy_reader *destroy;
+@};
+@end smallexample
+
+@cindex @code{struct gdb_symbol_callbacks}
+@cindex @code{struct gdb_unwind_callbacks}
+
+The callbacks are provided with another set of callbacks by
+@value{GDBN} to do their job. For @code{read}, these callbacks are
+passed in a @code{struct gdb_symbol_callbacks} and for @code{unwind}
+and @code{get_frame_id}, in a @code{struct gdb_unwind_callbacks}.
+@code{struct gdb_symbol_callbacks} has callbacks to create new object
+files and new symbol tables inside those object files. @code{struct
+gdb_unwind_callbacks} has callbacks to read registers off the current
+frame and to write out the values of the registers in the previous
+frame. Both have a callback (@code{target_read}) to read bytes off the
+target's address space.
+
@node GDB Bugs
@chapter Reporting Bugs in @value{GDBN}
@cindex bugs in @value{GDBN}
--
1.7.5.4
^ permalink raw reply [flat|nested] 16+ messages in thread* Re: [PATCH 6/6] Documentation.
2011-08-20 6:33 ` [PATCH 6/6] Documentation Sanjoy Das
@ 2011-08-20 8:34 ` Eli Zaretskii
0 siblings, 0 replies; 16+ messages in thread
From: Eli Zaretskii @ 2011-08-20 8:34 UTC (permalink / raw)
To: Sanjoy Das; +Cc: gdb-patches
> From: Sanjoy Das <sanjoy@playingwithpointers.com>
> Cc: Sanjoy Das <sanjoy@playingwithpointers.com>
> Date: Sat, 20 Aug 2011 11:57:15 +0530
>
> +such a parser. More specific details can be found in the file
> +@file{gdb/jit-reader.h.in}.
The file name needs an update, I think.
> +The reader is implemented as a shared object. Two new @value{GDBN}
> +commands, @code{load-jit-reader} and @code{unload-jit-reader} are
> +added, to be used to load and unload the readers from a preconfigured
^^^^^
"provided" is better, especially if the manual is read a year from now ;-)
> +@node Using Readers
> +@subsection Using Readers
> +@kindex load-jit-reader
> +@kindex unload-jit-reader
> +
> +Readers can be loaded and unloaded using the @code{load-jit-reader}
> +and @code{unload-jit-reader} commands.
> +
> +@table @code
> +@kindex load-jit-reader
> +@item load-jit-reader @var{reader-name}
Please leave only one @kindex, the one that's immediately before the
command description.
In general, it is not useful to have identical or very similar index
entries that point to the same page in the document. They just
inflate the index without adding any benefits for the reader who uses
the index to quickly find the information she is after.
> +in @value{GDBN} reporting an error. A new JIT reader can be loaded by
> +first unloading the current one using @code{unload-jit-reader} and
> +then running @code{load-jit-reader}.
^^^^^^^
"invoking" is better here.
> +@node Writing Readers
> +@subsection Writing Readers
Suggest a less general name like "Writing JIT Readers".
> +@findex gdb_init_reader
> +
> +@smallexample
Please don't leave an empty line between the index entries and the
text they index.
> +@cindex @code{struct gdb_reader_funcs}
> +
> +@code{struct gdb_reader_funcs} contains a set of pointers to callback
Same here.
> +reader is being unloaded (@code{destroy}). The struct looks like this
^^
Need two spaces here.
Okay with those changes.
Thanks.
^ permalink raw reply [flat|nested] 16+ messages in thread