* [PATCH 1/4] jit-reader.h: describe interface implemented by the JIT readers.
@ 2011-07-13 20:24 Sanjoy Das
2011-07-13 20:24 ` [PATCH 4/4] Activate JIT code unwinder for i386 Sanjoy Das
` (2 more replies)
0 siblings, 3 replies; 8+ messages in thread
From: Sanjoy Das @ 2011-07-13 20:24 UTC (permalink / raw)
To: gdb-patches; +Cc: Sanjoy Das
Generating ELF files in memory is usually too much work for JIT
compilers, since they usually don't have the related routines (as
opposed to a regular static compiler). One way to simplify this is to
have the JIT vendor themselves provide a shared object which is loaded
and used to parse the debug information. This patch exposes a
simplified interface for the debug info parser.
The interface is _simplified_ in the sense that it does not expose all
of GDB's functionality. The idea is that if the user wishes to use GDB
for full-on debugging of generated code, it will probably be simpler
to generate the full DWARF info.
The interface does not expose more than the minimum amount of GDB
internals; both to prevent versioning problems, and to keep writing
the debug-info reader simple.
This patch adds a header file (`jit-reader.h') which can be included
and implemented in a shared object to build a working JIT
debug-reader.
gdb/ChangeLog:
* jit-reader.h: Add (new) JIT reader interface.
* jit.c: Include jit-reader.h in source file
* Makefile.in: Add jit-reader.h to HFILES_NO_SRCDIR.
---
gdb/ChangeLog | 6 ++
gdb/Makefile.in | 2 +-
gdb/jit-reader.h | 189 ++++++++++++++++++++++++++++++++++++++++++++++++++++++
gdb/jit.c | 4 +
4 files changed, 200 insertions(+), 1 deletions(-)
create mode 100644 gdb/jit-reader.h
diff --git a/gdb/ChangeLog b/gdb/ChangeLog
index 8ed7eaf..e067f04 100644
--- a/gdb/ChangeLog
+++ b/gdb/ChangeLog
@@ -1,3 +1,9 @@
+2011-07-13 Sanjoy Das <sanjoy@playingwithpointers.com>
+
+ * jit-reader.h: Add (new) JIT reader interface.
+ * jit.c: Include jit-reader.h in source file
+ * Makefile.in: Add jit-reader.h to HFILES_NO_SRCDIR.
+
2011-07-12 Jan Kratochvil <jan.kratochvil@redhat.com>
Code cleanup making also optimized out values lazy.
diff --git a/gdb/Makefile.in b/gdb/Makefile.in
index 494f24f..ca2cbcb 100644
--- a/gdb/Makefile.in
+++ b/gdb/Makefile.in
@@ -816,7 +816,7 @@ osdata.h procfs.h python/py-event.h python/py-events.h python/py-stopevent.h \
python/python-internal.h python/python.h ravenscar-thread.h record.h \
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
+gnulib/stddef.in.h inline-frame.h jit-reader.h
# Header files that already have srcdir in them, or which are in objdir.
diff --git a/gdb/jit-reader.h b/gdb/jit-reader.h
new file mode 100644
index 0000000..15980bd
--- /dev/null
+++ b/gdb/jit-reader.h
@@ -0,0 +1,189 @@
+/* Interface for JIT debug-info readers.
+
+ 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
+
+/* Versioning: for the SO to be correctly recognized and loaded, put the macro
+ GDB_JIT_DECLARE_API_VERSION in a source file. */
+
+#define GDB_JIT_INTERFACE_VERSION 1
+#define GDB_JIT_DECLARE_API_VERSION \
+ extern int __gdbjit_so_api_version (void) \
+ { \
+ return GDB_JIT_INTERFACE_VERSION; \
+ }
+
+#define GDB_JIT_SUCCESS 1
+#define GDB_JIT_FAIL 0
+#define GDBJIT_MAX_REGISTER_SIZE 64 /* Mirrors the internal GDB definition. */
+
+struct gdbjit_symtab;
+struct gdbjit_block;
+struct gdbjit_symbol;
+struct gdbjit_symtab_callbacks;
+
+#ifndef __GDB__INTERNAL /* Only defined when being compiled in GDB. */
+typedef long long CORE_ADDR;
+#endif
+
+struct gdbjit_line_mapping
+{
+ int line;
+ CORE_ADDR pc;
+};
+
+typedef struct gdbjit_symtab *(gdbjit_symtab_open)
+ (struct gdbjit_symtab_callbacks *callbacks,
+ const char *file_name);
+
+typedef struct gdbjit_block *(gdbjit_new_block)
+ (struct gdbjit_symtab_callbacks *callbacks, struct gdbjit_symtab *symtab,
+ struct gdbjit_block *parent, CORE_ADDR begin_addr, CORE_ADDR end_addr,
+ const char *name);
+
+typedef void (gdbjit_symtab_close) (struct gdbjit_symtab_callbacks *callbacks,
+ struct gdbjit_symtab *symtab);
+
+typedef void (gdbjit_symtab_add_line_mapping)
+(struct gdbjit_symtab_callbacks * callbacks, struct gdbjit_symtab *symtab,
+ int nlines, struct gdbjit_line_mapping *lines);
+
+typedef int (gdbjit_target_read) (CORE_ADDR target_mem, void *gdb_buf, int len);
+
+struct gdbjit_symtab_callbacks {
+ /* Create a new symbol table. A symbol table consists of a forest of block
+ hierachies. Blocks are added by a call to new_block. This needs to be
+ paired with a call to symtab_close.
+
+ An optional FILE_NAME can be passed, which will be associated with the
+ symbol table as the source file from which this code was compiled.
+
+ Returns a new struct gdbjit_symtab which can be further passed to
+ new_block and symtab_close. */
+ gdbjit_symtab_open *symtab_open;
+
+ /* Creates a new block. A block is an optionally named contiguous block of
+ code in memory. Creating a new block automatically adds it to the symbol
+ table in which it is created.
+
+ SYMTAB is the symbol table this block is added to. Each block may have an
+ optionally non-NULL PARENT. BEGIN_ADDR and END_ADDR are the first and last
+ addresses spanned by this piece of compiled code. This block may have an
+ optional NAME, in case it corresponds to a function.
+
+ Returns a gdbjit_block instance, which, at this point, is useless. */
+ gdbjit_new_block *new_block;
+
+ /* Adds PC <-> line number mapping for the symbol table SYMTAB. Pass an array
+ of NLINES gdbjit_line_mapping s in LINES. */
+ gdbjit_symtab_add_line_mapping *add_line_mapping;
+
+ /* Reads LEN bytes of memory from the target's address space, beginning from
+ TARGET_MEM into the buffer GDB_BUF points to. */
+ gdbjit_target_read *target_read;
+
+ /* Closes the symbol table SYMTAB, and add it to the internal GDB list. */
+ gdbjit_symtab_close *symtab_close;
+
+ /* For internal use. */
+ void *private;
+};
+
+/* Denotes a register value. */
+struct gdbjit_reg_value
+{
+ /* Set to non-zero if this register has a valid value. Otherwise 0. */
+ int defined;
+ /* The actual value of the register (this is considered valid only if defined
+ is non-zero). */
+ unsigned char value[GDBJIT_MAX_REGISTER_SIZE];
+};
+
+/* Unique frame identifier. This should remain constant throughout the lifetime
+ of the frame concerned. */
+struct gdbjit_frame_id
+{
+ CORE_ADDR code_address;
+ CORE_ADDR stack_address;
+};
+
+struct gdbjit_unwind_callbacks;
+
+typedef struct gdbjit_reg_value (gdbjit_unwind_reg_get)
+ (struct gdbjit_unwind_callbacks *callback, int regnum);
+
+typedef void (gdbjit_unwind_reg_set) (struct gdbjit_unwind_callbacks *callback,
+ int regnum, struct gdbjit_reg_value val);
+
+struct gdbjit_unwind_callbacks
+{
+ /* Gets the current value for the register REGNUM (DWARF numbering). */
+ gdbjit_unwind_reg_get *reg_get;
+
+ /* Sets the previous value of the REGNUM register (i.e. its value in the
+ previous frame) to VAL. */
+ gdbjit_unwind_reg_set *reg_set;
+
+ /* Function to read memory off the inferior process being debugged, as
+ documented in gdbjit_symtab_callbacks. */
+ gdbjit_target_read *target_read;
+
+ /* For internal use. */
+ void *private;
+};
+
+/* Called once for each new inferior program. It should also initialize the
+ private pointer (to which a pointer is passed here) if the it needs one.
+
+ return: GDB_SUCCESS on success, or GDB_JIT_FAIL on error,
+ in which this plugin will be discarded (gdbjit_destroy_reader will not be
+ called in such a case). */
+extern int gdbjit_init_reader (void **private);
+
+/* Called to have the reader try to read a block of memory. PRIVATE is the
+ private pointer, (possibly) initialized by gdbjit_init_reader.
+
+ The function is expected to use CALLBACKS (documented above) to build a
+ symbol table for this particular block of memory (pointed to by MEMORY,
+ already copied from the target address space to GDB's address space).
+ MEMORY_SZ is the size of the block of memory.
+
+ Should return GDB_JIT_SUCESS on success and GDB_JIT_FAIL on error. */
+extern int gdbjit_read_debug_info (void *private,
+ struct gdbjit_symtab_callbacks *callbacks,
+ CORE_ADDR memory, long memory_sz);
+
+/* Called to unwind one frame. PRIVATE is the private pointer. Expected to use
+ CALLBACKS to unwind the registers to the older frame.
+
+ Should return GDB_JIT_SUCESS for success, GDB_JIT_FAIL for fail. */
+extern int gdbjit_unwind_frame (void *private,
+ struct gdbjit_unwind_callbacks *callbacks);
+
+/* Called to get a unique identifier for the current stack frame (as reported by
+ callbacks). */
+struct gdbjit_frame_id gdbjit_get_frame_id (void *private, struct
+ gdbjit_unwind_callbacks *callbacks);
+
+/* Called once the inferior process exits. */
+extern void gdbjit_destroy_reader (void *private);
+
+#endif
diff --git a/gdb/jit.c b/gdb/jit.c
index eb1bcc7..6c07a57 100644
--- a/gdb/jit.c
+++ b/gdb/jit.c
@@ -19,7 +19,11 @@
#include "defs.h"
+/* To stop jit-reader.h from re-defining CORE_ADDR */
+#define __GDB__INTERNAL
+
#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] 8+ messages in thread* [PATCH 4/4] Activate JIT code unwinder for i386. 2011-07-13 20:24 [PATCH 1/4] jit-reader.h: describe interface implemented by the JIT readers Sanjoy Das @ 2011-07-13 20:24 ` Sanjoy Das 2011-07-14 17:55 ` Tom Tromey 2011-07-13 20:52 ` [PATCH 2/4] Add symbol-handling callbacks to the jit-reader interface Sanjoy Das 2011-07-14 1:39 ` [PATCH 3/4] Add an unwinder for JIT compiled code Sanjoy Das 2 siblings, 1 reply; 8+ messages in thread From: Sanjoy Das @ 2011-07-13 20:24 UTC (permalink / raw) To: gdb-patches; +Cc: Sanjoy Das Registers the (pseudo) unwinder for JIT code for i386. This can probably be extended to other architectures after some testing and review. gdb/ChangeLog: * i386-tdep.c: Activate JIT unwinder for i386. --- gdb/ChangeLog | 4 ++++ gdb/i386-tdep.c | 4 ++++ 2 files changed, 8 insertions(+), 0 deletions(-) diff --git a/gdb/ChangeLog b/gdb/ChangeLog index 8485b05..51c0727 100644 --- a/gdb/ChangeLog +++ b/gdb/ChangeLog @@ -1,5 +1,9 @@ 2011-07-13 Sanjoy Das <sanjoy@playingwithpointers.com> + * i386-tdep.c: Activate JIT unwinder for i386. + +2011-07-13 Sanjoy Das <sanjoy@playingwithpointers.com> + * jit.c: Add JIT frame unwinding code. * jit-reader.h: Added jit_prepend_unwinder. diff --git a/gdb/i386-tdep.c b/gdb/i386-tdep.c index 366d0fa..66626ab 100644 --- a/gdb/i386-tdep.c +++ b/gdb/i386-tdep.c @@ -30,6 +30,7 @@ #include "frame-base.h" #include "frame-unwind.h" #include "inferior.h" +#include "jit.h" #include "gdbcmd.h" #include "gdbcore.h" #include "gdbtypes.h" @@ -7330,6 +7331,9 @@ i386_gdbarch_init (struct gdbarch_info info, struct gdbarch_list *arches) CFI info will be used if it is available. */ dwarf2_append_unwinders (gdbarch); + /* JIT reader pseudo-unwinder. */ + jit_prepend_unwinder (gdbarch); + frame_base_set_default (gdbarch, &i386_frame_base); /* Pseudo registers may be changed by amd64_init_abi. */ -- 1.7.5.4 ^ permalink raw reply [flat|nested] 8+ messages in thread
* Re: [PATCH 4/4] Activate JIT code unwinder for i386. 2011-07-13 20:24 ` [PATCH 4/4] Activate JIT code unwinder for i386 Sanjoy Das @ 2011-07-14 17:55 ` Tom Tromey 2011-07-14 17:58 ` Sanjoy Das 0 siblings, 1 reply; 8+ messages in thread From: Tom Tromey @ 2011-07-14 17:55 UTC (permalink / raw) To: Sanjoy Das; +Cc: gdb-patches >>>>> "Sanjoy" == Sanjoy Das <sanjoy@playingwithpointers.com> writes: Sanjoy> Registers the (pseudo) unwinder for JIT code for i386. This can Sanjoy> probably be extended to other architectures after some testing Sanjoy> and review. This doesn't seem to be different from the earlier version of this patch; which Mark K. said should probably be changed to put the JIT unwinders after the DWARF ones. Tom ^ permalink raw reply [flat|nested] 8+ messages in thread
* Re: [PATCH 4/4] Activate JIT code unwinder for i386. 2011-07-14 17:55 ` Tom Tromey @ 2011-07-14 17:58 ` Sanjoy Das 0 siblings, 0 replies; 8+ messages in thread From: Sanjoy Das @ 2011-07-14 17:58 UTC (permalink / raw) To: Tom Tromey; +Cc: gdb-patches Hi! Thanks for the feedback; I'll get started on fixing the problems. And no, I have not done anything regarding copyright assignment. -- Sanjoy Das http://playingwithpointers.com ^ permalink raw reply [flat|nested] 8+ messages in thread
* [PATCH 2/4] Add symbol-handling callbacks to the jit-reader interface. 2011-07-13 20:24 [PATCH 1/4] jit-reader.h: describe interface implemented by the JIT readers Sanjoy Das 2011-07-13 20:24 ` [PATCH 4/4] Activate JIT code unwinder for i386 Sanjoy Das @ 2011-07-13 20:52 ` Sanjoy Das 2011-07-14 1:39 ` [PATCH 3/4] Add an unwinder for JIT compiled code Sanjoy Das 2 siblings, 0 replies; 8+ messages in thread From: Sanjoy Das @ 2011-07-13 20:52 UTC (permalink / raw) To: gdb-patches; +Cc: Sanjoy Das Implements the callbacks in `struct gdbjit_symtab_callbacks'. This will allow the JIT debug info reader to be able to parse the debug info and actually push the symbols into GDB. gdb/ChangeLog: * jit.c: Add symbol handling callbacks for the JIT reader interface. --- gdb/ChangeLog | 4 + gdb/jit.c | 518 +++++++++++++++++++++++++++++++++++++++++++++++++++------ 2 files changed, 471 insertions(+), 51 deletions(-) diff --git a/gdb/ChangeLog b/gdb/ChangeLog index e067f04..ac207d1 100644 --- a/gdb/ChangeLog +++ b/gdb/ChangeLog @@ -1,5 +1,9 @@ 2011-07-13 Sanjoy Das <sanjoy@playingwithpointers.com> + * jit.c: Add symbol handling callbacks for the JIT reader interface. + +2011-07-13 Sanjoy Das <sanjoy@playingwithpointers.com> + * jit-reader.h: Add (new) JIT reader interface. * jit.c: Include jit-reader.h in source file * Makefile.in: Add jit-reader.h to HFILES_NO_SRCDIR. diff --git a/gdb/jit.c b/gdb/jit.c index 6c07a57..2899469 100644 --- a/gdb/jit.c +++ b/gdb/jit.c @@ -24,8 +24,10 @@ #include "jit.h" #include "jit-reader.h" +#include "block.h" #include "breakpoint.h" #include "command.h" +#include "dictionary.h" #include "gdbcmd.h" #include "gdbcore.h" #include "inferior.h" @@ -34,8 +36,11 @@ #include "symfile.h" #include "symtab.h" #include "target.h" +#include "gdb_dirent.h" #include "gdb_stat.h" +#include <dlfcn.h> + static const struct objfile_data *jit_objfile_data; static const char *const jit_break_name = "__jit_debug_register_code"; @@ -50,6 +55,115 @@ static void jit_inferior_init (struct gdbarch *gdbarch); static int jit_debug = 0; +/* The environment variable we poke at to get the file name of the shared object + to load. */ + +static const char *jit_dbg_reader_so_name_env = "JIT_DEBUG_READER"; + +/* Symbols (and the corresponding types) to be loaded from the shared object + supposed to do the debug-info parsing. */ +typedef int (jit_init_reader_fn) (void **); +static const char *jit_init_reader_sym = "gdbjit_init_reader"; + +typedef int (jit_read_debug_info_fn) (void *, struct gdbjit_symtab_callbacks *, + void *mem, long sz); +static const char *jit_read_debug_info_sym = "gdbjit_read_debug_info"; + +typedef int (jit_unwind_frame_fn) (void *, struct gdbjit_unwind_callbacks *); +static const char *jit_unwind_frame_sym = "gdbjit_unwind_frame"; + +typedef void (jit_destroy_reader_fn) (void *); +static const char *jit_destroy_reader_sym = "gdbjit_destroy_reader"; + +typedef struct gdbjit_frame_id (jit_get_frame_id_fn) (void *, struct + gdbjit_unwind_callbacks *); +static const char *jit_get_frame_id_sym = "gdbjit_get_frame_id"; + +static const char *jit_so_api_version_sym = "__gdbjit_so_api_version"; + +struct jit_dbg_reader +{ + jit_init_reader_fn *init; + jit_read_debug_info_fn *read; + jit_unwind_frame_fn *unwind; + jit_get_frame_id_fn *get_frame_id; + jit_destroy_reader_fn *destroy; + + void *handle, *private_data; +}; + +static struct jit_dbg_reader * +jit_dbg_reader_load (void) +{ + /* Check if a reader has been provided. */ + const char *file_name = getenv (jit_dbg_reader_so_name_env); + void *handle = NULL; + int (*jit_reader_so_api_version) (void) = NULL; + struct jit_dbg_reader *reader = NULL; + + if (file_name == NULL) + return NULL; + + handle = dlopen (file_name, RTLD_NOW); + if (!handle) + goto cleanup; + + reader = XZALLOC (struct jit_dbg_reader); + reader->init = dlsym (handle, jit_init_reader_sym); + reader->handle = handle; + + if (!reader->init) + goto cleanup; + + reader->read = dlsym (handle, jit_read_debug_info_sym); + if (!reader->read) + goto cleanup; + + reader->unwind = dlsym (handle, jit_unwind_frame_sym); + if (!reader->unwind) + goto cleanup; + + reader->get_frame_id = dlsym (handle, jit_get_frame_id_sym); + if (!reader->get_frame_id) + goto cleanup; + + reader->destroy = dlsym (handle, jit_destroy_reader_sym); + if (!reader->destroy) + goto cleanup; + + jit_reader_so_api_version = dlsym (handle, jit_so_api_version_sym); + if (!jit_reader_so_api_version || + jit_reader_so_api_version () != GDB_JIT_INTERFACE_VERSION) + { + goto cleanup; + } + + if (reader->init (&reader->private_data) != GDB_JIT_SUCCESS) + goto cleanup; + + return reader; + + cleanup: + xfree (reader); + if (handle) + { + dlclose (handle); + fprintf (stderr, "Could not load reader object %s\n", file_name); + } + else /* also report why the shared object could not be loaded */ + fprintf (stderr, "Could not load reader object %s (%s)\n", file_name, + dlerror()); + return NULL; +} + +static void +jit_dbg_reader_destroy (struct jit_dbg_reader *reader) +{ + if (reader) + reader->destroy (reader->private_data); + xfree (reader); +} + static void show_jit_debug (struct ui_file *file, int from_tty, struct cmd_list_element *c, const char *value) @@ -140,6 +254,9 @@ struct jit_inferior_data { CORE_ADDR breakpoint_addr; /* &__jit_debug_register_code() */ CORE_ADDR descriptor_addr; /* &__jit_debug_descriptor */ + struct jit_dbg_reader *reader; /* If a debug info reader was found. */ + struct objfile *jit_objfile; /* The object file where all the JIT symbols + will be added. */ }; /* Return jit_inferior_data for current inferior. Allocate if not already @@ -238,6 +355,282 @@ jit_read_code_entry (struct gdbarch *gdbarch, extract_unsigned_integer (&entry_buf[3 * ptr_size], 8, byte_order); } +struct gdbjit_block +{ + struct gdbjit_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; +}; + +struct gdbjit_symtab +{ + struct gdbjit_block *blocks; + struct linetable *linetable; + int nblocks; + + const char *file_name; +}; + +struct jit_dbg_reader_data +{ + struct objfile **objf; +}; + +static int +jit_target_read_impl (CORE_ADDR target_mem, void *gdb_buf, int len) +{ + return target_read_memory (target_mem, gdb_buf, len); +} + +static struct gdbjit_symtab * +jit_symtab_open_impl (struct gdbjit_symtab_callbacks *cb, const char *file_name) +{ + struct gdbjit_symtab *ret = XZALLOC (struct gdbjit_symtab); + ret->file_name = xstrdup (file_name); + return ret; +} + +/* Returns true if the block corrensponding to old should be placed before the + block corrensponding to new in the final blockvector. */ +static int +compare_block (struct gdbjit_block *old, struct gdbjit_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; +} + +static struct gdbjit_block * +jit_new_block_impl (struct gdbjit_symtab_callbacks *cb, + struct gdbjit_symtab *symtab, + struct gdbjit_block *parent, + CORE_ADDR begin, CORE_ADDR end, const char *name) +{ + struct gdbjit_block *block = XZALLOC (struct gdbjit_block); + + (void) cb; + + block->next = symtab->blocks; + block->begin = begin; + block->end = 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 gdbjit_block *i = symtab->blocks; + + for (;; i = i->next) + { + /* Guranteed 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; +} + +static void +jit_symtab_add_line_mapping_impl (struct gdbjit_symtab_callbacks *cb, + struct gdbjit_symtab *stab, + int nlines, + struct gdbjit_line_mapping *map) +{ + int i; + /* Must copy */ + if (!nlines) + 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 = map[i].pc; + stab->linetable->item [i].line = map[i].line; + } +} + +static void +jit_symtab_close_impl (struct gdbjit_symtab_callbacks *cb, + struct gdbjit_symtab *stab) +{ + struct jit_dbg_reader_data *dat = cb->private; + struct symtab *symtab; + struct gdbjit_block *blck_iter, *blck_iter_tmp; + struct block *block_iter; + struct objfile *objfile; + int actual_nblocks = FIRST_LOCAL_BLOCK + stab->nblocks, i; + CORE_ADDR begin, end; + + if (*dat->objf == NULL) + { + objfile = allocate_objfile (NULL, 0); + *dat->objf = objfile; + 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; + objfile->name = xstrdup ("JIT"); + } + else + objfile = *dat->objf; + + symtab = allocate_symtab (stab->file_name, objfile); + symtab->dirname = NULL; /* JIT compilers compile in memory */ + + 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; + } + + symtab->blockvector = obstack_alloc (&objfile->objfile_obstack, + (sizeof (struct blockvector) + + (actual_nblocks - 1) * + sizeof (struct block *))); + + /* (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; + + for (i = (actual_nblocks - 1), blck_iter = stab->blocks; + i >= FIRST_LOCAL_BLOCK; i--) + { + struct block *bl = allocate_block (&objfile->objfile_obstack); + struct symbol *block_name = obstack_alloc (&objfile->objfile_obstack, + sizeof (struct symbol)); + + BLOCK_DICT (bl) = dict_create_linear (&objfile->objfile_obstack, NULL); + BLOCK_START (bl) = blck_iter->begin; + BLOCK_END (bl) = blck_iter->end; + BLOCK_FUNCTION (bl) = block_name; + + memset (block_name, 0, sizeof (struct symbol)); + SYMBOL_DOMAIN (block_name) = VAR_DOMAIN; + SYMBOL_CLASS (block_name) = LOC_BLOCK; + block_name->symtab = symtab; + SYMBOL_BLOCK_VALUE (block_name) = bl; + + block_name->ginfo.name = obstack_alloc (&objfile->objfile_obstack, + 1 + strlen (blck_iter->name)); + strcpy (block_name->ginfo.name, blck_iter->name); + BLOCK_FUNCTION (bl) = block_name; + + BLOCKVECTOR_BLOCK (symtab->blockvector, i) = bl; + if (begin < (long) blck_iter->begin) + begin = (long) blck_iter->begin; + if (end > (long) blck_iter->end) + end = (long) blck_iter->end; + } + + blck_iter = blck_iter->next; + + /* Now add the special blocks. */ + block_iter = NULL; + for (i = 0; i < FIRST_LOCAL_BLOCK; i++) + { + struct block *bl = allocate_block (&objfile->objfile_obstack); + BLOCK_DICT (bl) = dict_create_linear (&objfile->objfile_obstack, NULL); + BLOCK_SUPERBLOCK (bl) = block_iter; + block_iter = bl; + + BLOCK_START (bl) = begin; + BLOCK_END (bl) = end; + + BLOCKVECTOR_BLOCK (symtab->blockvector, i) = bl; + } + + /* Fill up the superblock fields. */ + for (blck_iter = stab->blocks; blck_iter; blck_iter = blck_iter->next) + { + if (blck_iter->parent != NULL) + BLOCK_SUPERBLOCK (blck_iter->real_block) = + blck_iter->parent->real_block; + } + + /* Free memory. */ + blck_iter = stab->blocks; + for (blck_iter = stab->blocks, blck_iter_tmp = blck_iter->next; + blck_iter; blck_iter = blck_iter_tmp) + { + xfree (blck_iter); + } +} + +static int +jit_try_read_symtab (struct jit_inferior_data *inf_data, + CORE_ADDR target_mem, long sz) +{ + void *gdb_mem; + int status = 0; + struct jit_dbg_reader *i; + struct jit_dbg_reader_data priv_data; + struct gdbjit_symtab_callbacks callbacks = + { + jit_symtab_open_impl, + jit_new_block_impl, + jit_symtab_add_line_mapping_impl, + jit_target_read_impl, + jit_symtab_close_impl, + + &priv_data + }; + + if (!inf_data->reader) + return 0; + + priv_data.objf = &inf_data->jit_objfile; + + gdb_mem = xmalloc (sz); + if (target_read_memory (target_mem, gdb_mem, sz)) + { + status = 0; + goto cleanup; + } + + status = inf_data->reader->read (inf_data->reader->private_data, &callbacks, + gdb_mem, sz) == GDB_JIT_SUCCESS; + + cleanup: + xfree (gdb_mem); + return status; +} + /* 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 @@ -247,14 +640,9 @@ static void jit_register_code (struct gdbarch *gdbarch, CORE_ADDR entry_addr, struct jit_code_entry *code_entry) { - 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; + int i, success; + struct jit_inferior_data *inf_data = get_jit_inferior_data (); if (jit_debug) fprintf_unfiltered (gdb_stdlog, @@ -263,53 +651,68 @@ jit_register_code (struct gdbarch *gdbarch, paddress (gdbarch, code_entry->symfile_addr), pulongest (code_entry->symfile_size)); - 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. */ - if (!bfd_check_format (nbfd, bfd_object)) + if (jit_try_read_symtab (inf_data, code_entry->symfile_addr, + code_entry->symfile_size)) { - printf_unfiltered (_("\ + objfile = inf_data->jit_objfile; + } + else + { + struct cleanup *old_cleanups; + bfd *nbfd; + struct section_addr_info *sai; + struct bfd_section *sec; + const struct bfd_arch_info *b; + CORE_ADDR *entry_addr_ptr; + + 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. */ + if (!bfd_check_format (nbfd, bfd_object)) + { + printf_unfiltered (_("\ JITed symbol file is not an object file, ignoring it.\n")); - do_cleanups (old_cleanups); - return; + do_cleanups (old_cleanups); + return; + } + + /* Check bfd arch. */ + b = gdbarch_bfd_arch_info (gdbarch); + if (b->compatible (b, bfd_get_arch_info (nbfd)) != b) + warning (_("JITed object file architecture %s is not compatible " + "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. */ + 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. */ + 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; + ++i; + } + + /* 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); } - - /* Check bfd arch. */ - b = gdbarch_bfd_arch_info (gdbarch); - if (b->compatible (b, bfd_get_arch_info (nbfd)) != b) - warning (_("JITed object file architecture %s is not compatible " - "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. */ - 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. */ - 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; - ++i; - } - - /* 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); } /* This function unregisters JITed code and frees the corresponding @@ -395,6 +798,8 @@ jit_inferior_init (struct gdbarch *gdbarch) if (jit_breakpoint_re_set_internal (gdbarch, inf_data) != 0) return; + inf_data->reader = jit_dbg_reader_load (); + if (inf_data->descriptor_addr == 0) { struct minimal_symbol *desc_symbol; @@ -474,6 +879,11 @@ jit_reset_inferior_data_and_breakpoints (void) /* Remove any existing JIT breakpoint(s). */ remove_jit_event_breakpoints (); + /* Destroy JIT reader objects. */ + jit_dbg_reader_destroy (inf_data->reader); + if (inf_data->jit_objfile) + free_objfile (inf_data->jit_objfile); + jit_inferior_init (target_gdbarch); } @@ -494,6 +904,12 @@ jit_inferior_exit_hook (struct inferior *inf) { struct objfile *objf; struct objfile *temp; + struct jit_inferior_data *inf_data; + + inf_data = inferior_data (inf, jit_inferior_data); + jit_dbg_reader_destroy (inf_data->reader); + if (inf_data->jit_objfile) + free_objfile (inf_data->jit_objfile); ALL_OBJFILES_SAFE (objf, temp) if (objfile_data (objf, jit_objfile_data) != NULL) -- 1.7.5.4 ^ permalink raw reply [flat|nested] 8+ messages in thread
* [PATCH 3/4] Add an unwinder for JIT compiled code. 2011-07-13 20:24 [PATCH 1/4] jit-reader.h: describe interface implemented by the JIT readers Sanjoy Das 2011-07-13 20:24 ` [PATCH 4/4] Activate JIT code unwinder for i386 Sanjoy Das 2011-07-13 20:52 ` [PATCH 2/4] Add symbol-handling callbacks to the jit-reader interface Sanjoy Das @ 2011-07-14 1:39 ` Sanjoy Das 2011-07-14 21:05 ` Tom Tromey 2 siblings, 1 reply; 8+ messages in thread From: Sanjoy Das @ 2011-07-14 1:39 UTC (permalink / raw) To: gdb-patches; +Cc: Sanjoy Das Add a (pseudo) unwinder which proxies back everything to the unwinder registered by the JIT debug info reader. gdb/ChangeLog: * jit.c: Add JIT frame unwinding code. * jit-reader.h: Added jit_prepend_unwinder. --- gdb/ChangeLog | 5 ++ gdb/jit.c | 150 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++ gdb/jit.h | 2 + 3 files changed, 157 insertions(+), 0 deletions(-) diff --git a/gdb/ChangeLog b/gdb/ChangeLog index ac207d1..8485b05 100644 --- a/gdb/ChangeLog +++ b/gdb/ChangeLog @@ -1,5 +1,10 @@ 2011-07-13 Sanjoy Das <sanjoy@playingwithpointers.com> + * jit.c: Add JIT frame unwinding code. + * jit-reader.h: Added jit_prepend_unwinder. + +2011-07-13 Sanjoy Das <sanjoy@playingwithpointers.com> + * jit.c: Add symbol handling callbacks for the JIT reader interface. 2011-07-13 Sanjoy Das <sanjoy@playingwithpointers.com> diff --git a/gdb/jit.c b/gdb/jit.c index 2899469..03a3d0b 100644 --- a/gdb/jit.c +++ b/gdb/jit.c @@ -28,6 +28,7 @@ #include "breakpoint.h" #include "command.h" #include "dictionary.h" +#include "frame-unwind.h" #include "gdbcmd.h" #include "gdbcore.h" #include "inferior.h" @@ -781,6 +782,149 @@ jit_breakpoint_re_set_internal (struct gdbarch *gdbarch, return 0; } +struct jit_unwind_private { + struct gdbjit_reg_value *registers; + struct frame_info *this_frame; +}; + +static void +jit_unwind_reg_set_impl (struct gdbjit_unwind_callbacks *cb, int regnum, + struct gdbjit_reg_value value) +{ + struct jit_unwind_private *priv = cb->private; + int gdb_reg = gdbarch_dwarf2_reg_to_regnum (target_gdbarch, regnum); + priv->registers[gdb_reg] = value; +} + +static struct gdbjit_reg_value +jit_unwind_reg_get_impl (struct gdbjit_unwind_callbacks *cb, int regnum) +{ + struct jit_unwind_private *priv = cb->private; + struct gdbjit_reg_value val; + int gdb_reg = gdbarch_dwarf2_reg_to_regnum (target_gdbarch, regnum); + val.defined = frame_register_read (priv->this_frame, gdb_reg, val.value); + return val; +} + +static int +jit_frame_sniffer (const struct frame_unwind *self, + struct frame_info *this_frame, void **cache) +{ + /* First look up the PC, and check if the code address has been registered or + not. */ + CORE_ADDR pc = get_frame_pc (this_frame); + struct jit_inferior_data *inf_data = get_jit_inferior_data (); + struct jit_unwind_private *priv_data; + struct jit_dbg_reader *iter; + struct gdbjit_unwind_callbacks callbacks = + { + jit_unwind_reg_get_impl, + jit_unwind_reg_set_impl, + jit_target_read_impl + }; + + if (inf_data->reader == NULL) + return 0; + + /* All the unwinding happens here, and the unwound registers are written to + this block of memory, which we then sneakily read back in + jit_frame_prev_register. */ + if (!*cache) + { + *cache = XZALLOC (struct jit_unwind_private); + priv_data = *cache; + priv_data->registers = XCALLOC (gdbarch_num_regs (target_gdbarch), + struct gdbjit_reg_value); + priv_data->this_frame = this_frame; + } + else + { + priv_data = *cache; + priv_data->this_frame = this_frame; + } + + callbacks.private = priv_data; + + /* Try to coax the provided unwinder to unwind the stack, and hope it + succeeds. */ + if (inf_data->reader->unwind (inf_data->reader->private_data, &callbacks) + == GDB_JIT_SUCCESS) + return 1; + xfree (priv_data->registers); + xfree (priv_data); + *cache = NULL; + + return 0; +} + +static enum unwind_stop_reason +jit_frame_unwind_stop_reason (struct frame_info *this_frame, void **cache) +{ + return UNWIND_NO_REASON; +} + +static void +jit_frame_this_id (struct frame_info *this_frame, void **cache, + struct frame_id *this_id) +{ + struct jit_inferior_data *inf_data = get_jit_inferior_data (); + struct jit_unwind_private private = + { + NULL, + this_frame + }; + struct gdbjit_frame_id frame_id; + struct gdbjit_unwind_callbacks callbacks = + { + jit_unwind_reg_get_impl, + NULL, + jit_target_read_impl, + + &private + }; + + frame_id = inf_data->reader->get_frame_id (inf_data->reader->private_data, + &callbacks); + *this_id = frame_id_build (frame_id.stack_address, frame_id.code_address); +} + +static struct value * +jit_frame_prev_register (struct frame_info *this_frame, void **cache, int reg) +{ + struct jit_unwind_private *priv = *cache; + struct gdbjit_reg_value value; + + if (priv == NULL) + return frame_unwind_got_optimized (this_frame, reg); + + value = priv->registers[reg]; + if (value.defined) + return frame_unwind_got_bytes (this_frame, reg, value.value); + else + return frame_unwind_got_optimized (this_frame, reg); +} + +static void +jit_dealloc_cache (struct frame_info *this_frame, void *cache) +{ + (void) this_frame; + + xfree (cache); +} + +/* Simply relays 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 +}; + /* Register any already created translations. */ static void @@ -960,6 +1104,12 @@ jit_event_handler (struct gdbarch *gdbarch) } } +void +jit_prepend_unwinder (struct gdbarch *gdbarch) +{ + frame_unwind_prepend_unwinder (gdbarch, &jit_frame_unwind); +} + /* Provide a prototype to silence -Wmissing-prototypes. */ extern void _initialize_jit (void); diff --git a/gdb/jit.h b/gdb/jit.h index 73a1414..9dd8f5a 100644 --- a/gdb/jit.h +++ b/gdb/jit.h @@ -80,4 +80,6 @@ extern void jit_breakpoint_re_set (void); extern void jit_event_handler (struct gdbarch *gdbarch); +extern void jit_prepend_unwinder (struct gdbarch *gdbarch); + #endif /* JIT_H */ -- 1.7.5.4 ^ permalink raw reply [flat|nested] 8+ messages in thread
* Re: [PATCH 3/4] Add an unwinder for JIT compiled code. 2011-07-14 1:39 ` [PATCH 3/4] Add an unwinder for JIT compiled code Sanjoy Das @ 2011-07-14 21:05 ` Tom Tromey 0 siblings, 0 replies; 8+ messages in thread From: Tom Tromey @ 2011-07-14 21:05 UTC (permalink / raw) To: Sanjoy Das; +Cc: gdb-patches >>>>> "Sanjoy" == Sanjoy Das <sanjoy@playingwithpointers.com> writes: Sanjoy> * jit-reader.h: Added jit_prepend_unwinder. This mentions the wrong file. Otherwise this one seems pretty good, though again, I would appreciate further reviews by others. Tom ^ permalink raw reply [flat|nested] 8+ messages in thread
* [PATCH 1/4] jit-reader.h: describe interface implemented by the JIT readers. @ 2011-07-05 6:27 Sanjoy Das 2011-07-05 6:27 ` [PATCH 2/4] Add symbol-handling callbacks to the jit-reader interface Sanjoy Das 0 siblings, 1 reply; 8+ messages in thread From: Sanjoy Das @ 2011-07-05 6:27 UTC (permalink / raw) To: gdb-patches; +Cc: Sanjoy Das Generating ELF files in memory is usually too much work for JIT compilers, since they usually don't have the related routines (as opposed to a regular static compiler). One way to simplify this is to have the JIT vendor themselves provide a shared object which is loaded and used to parse the debug information. This patch exposes a simplified interface for the debug info parser. The interface is _simplified_ in the sense that it does not expose all of GDB's functionality. The idea is that if the user wishes to use GDB for full-on debugging of generated code, it will probably be simpler to generate the full DWARF info. The interface does not expose more than the minimum amount of GDB internals; both to prevent versioning problems, and to keep writing the debug-info reader simple. For the same reason, GDB specific typedefs (like CORE_ADDR) have been kept out of `jit-reader.h'. This patch adds a header file (`jit-reader.h') which can be included and implemented in a shared object to build a working JIT debug-reader. gdb/ChangeLog: * jit-reader.h: Add (new) JIT reader interface. * jit.c: Include jit-reader.h in source file * Makefile.in: Add jit-reader.h to HFILES_NO_SRCDIR. --- gdb/ChangeLog | 6 ++ gdb/Makefile.in | 2 +- gdb/jit-reader.h | 185 ++++++++++++++++++++++++++++++++++++++++++++++++++++++ gdb/jit.c | 1 + 4 files changed, 193 insertions(+), 1 deletions(-) create mode 100644 gdb/jit-reader.h diff --git a/gdb/ChangeLog b/gdb/ChangeLog index 8d1fc9a..3ad44e8 100644 --- a/gdb/ChangeLog +++ b/gdb/ChangeLog @@ -1,3 +1,9 @@ +2011-07-04 Sanjoy Das <sanjoy@playingwithpointers.com> + + * jit-reader.h: Add (new) JIT reader interface. + * jit.c: Include jit-reader.h in source file + * Makefile.in: Add jit-reader.h to HFILES_NO_SRCDIR. + 2011-07-04 Joel Brobecker <brobecker@adacore.com> * osabi.c (generic_elf_osabi_sniffer): Minor comment reformatting. diff --git a/gdb/Makefile.in b/gdb/Makefile.in index 494f24f..ca2cbcb 100644 --- a/gdb/Makefile.in +++ b/gdb/Makefile.in @@ -816,7 +816,7 @@ osdata.h procfs.h python/py-event.h python/py-events.h python/py-stopevent.h \ python/python-internal.h python/python.h ravenscar-thread.h record.h \ 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 +gnulib/stddef.in.h inline-frame.h jit-reader.h # Header files that already have srcdir in them, or which are in objdir. diff --git a/gdb/jit-reader.h b/gdb/jit-reader.h new file mode 100644 index 0000000..d143714 --- /dev/null +++ b/gdb/jit-reader.h @@ -0,0 +1,185 @@ +/* Interface for JIT debug-info readers. + + Copyright (C) 2003, 2005, 2007, 2008, 2009, 2010, 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 + +/* Versioning: for the SO to be correctly recognized and loaded, put the macro + GDB_JIT_DECLARE_API_VERSION in a source file. */ + +#define GDB_JIT_INTERFACE_VERSION 1 +#define GDB_JIT_DECLARE_API_VERSION \ + extern int __gdbjit_so_api_version (void) \ + { \ + return GDB_JIT_INTERFACE_VERSION; \ + } + +#define GDB_JIT_SUCCESS 1 +#define GDB_JIT_FAIL 0 +#define GDBJIT_MAX_REGISTER_SIZE 64 /* Mirrors the internal GDB definition. */ + +struct gdbjit_symtab; +struct gdbjit_block; +struct gdbjit_symbol; +struct gdbjit_symtab_callbacks; + +struct gdbjit_line_mapping +{ + int line; + void *pc; +}; + +typedef struct gdbjit_symtab *(gdbjit_symtab_open) + (struct gdbjit_symtab_callbacks *callbacks, + const char *file_name); + +typedef struct gdbjit_block *(gdbjit_new_block) + (struct gdbjit_symtab_callbacks *callbacks, struct gdbjit_symtab *symtab, + struct gdbjit_block *parent, void *begin_addr, void *end_addr, + const char *name); + +typedef void (gdbjit_symtab_close) (struct gdbjit_symtab_callbacks *callbacks, + struct gdbjit_symtab *symtab); + +typedef void (gdbjit_symtab_add_line_mapping) +(struct gdbjit_symtab_callbacks * callbacks, struct gdbjit_symtab *symtab, + int nlines, struct gdbjit_line_mapping *lines); + +typedef int (gdbjit_target_read) (void *target_mem, void *gdb_buf, int len); + +struct gdbjit_symtab_callbacks { + /* Create a new symbol table. A symbol table consists of a forest of block + hierachies. Blocks are added by a call to new_block. This needs to be + paired with a call to symtab_close. + + An optional FILE_NAME can be passed, which will be associated with the + symbol table as the source file from which this code was compiled. + + Returns a new struct gdbjit_symtab which can be further passed to + new_block and symtab_close. */ + gdbjit_symtab_open *symtab_open; + + /* Creates a new block. A block is an optionally named contiguous block of + code in memory. Creating a new block automatically adds it to the symbol + table in which it is created. + + SYMTAB is the symbol table this block is added to. Each block may have an + optionally non-NULL PARENT. BEGIN_ADDR and END_ADDR are the first and last + addresses spanned by this piece of compiled code. This block may have an + optional NAME, in case it corresponds to a function. + + Returns a gdbjit_block instance, which, at this point, is useless. */ + gdbjit_new_block *new_block; + + /* Adds PC <-> line number mapping for the symbol table SYMTAB. Pass an array + of NLINES gdbjit_line_mapping s in LINES. */ + gdbjit_symtab_add_line_mapping *add_line_mapping; + + /* Reads LEN bytes of memory from the target's address space, beginning from + TARGET_MEM into the buffer GDB_BUF points to. */ + gdbjit_target_read *target_read; + + /* Closes the symbol table SYMTAB, and add it to the internal GDB list. */ + gdbjit_symtab_close *symtab_close; + + /* For internal use. */ + void *private; +}; + +/* Denotes a register value. */ +struct gdbjit_reg_value +{ + /* Set to non-zero if this register has a valid value. Otherwise 0. */ + int defined; + /* The actual value of the register (this is considered valid only if defined + is non-zero). */ + unsigned char value[GDBJIT_MAX_REGISTER_SIZE]; +}; + +/* Unique frame identifier. This should remain constant throughout the lifetime + of the frame concerned. */ +struct gdbjit_frame_id +{ + void *code_address; + void *stack_address; +}; + +struct gdbjit_unwind_callbacks; + +typedef struct gdbjit_reg_value (gdbjit_unwind_reg_get) + (struct gdbjit_unwind_callbacks *callback, int regnum); + +typedef void (gdbjit_unwind_reg_set) (struct gdbjit_unwind_callbacks *callback, + int regnum, struct gdbjit_reg_value val); + +struct gdbjit_unwind_callbacks +{ + /* Gets the current value for the register REGNUM (DWARF numbering). */ + gdbjit_unwind_reg_get *reg_get; + + /* Sets the previous value of the REGNUM register (i.e. its value in the + previous frame) to VAL. */ + gdbjit_unwind_reg_set *reg_set; + + /* Function to read memory off the inferior process being debugged, as + documented in gdbjit_symtab_callbacks. */ + gdbjit_target_read *target_read; + + /* For internal use. */ + void *private; +}; + +/* Called once for each new inferior program. It should also initialize the + private pointer (to which a pointer is passed here) if the it needs one. + + return: GDB_SUCCESS on success, or GDB_JIT_FAIL on error, + in which this plugin will be discarded (gdbjit_destroy_reader will not be + called in such a case). */ +extern int gdbjit_init_reader (void **private); + +/* Called to have the reader try to read a block of memory. PRIVATE is the + private pointer, (possibly) initialized by gdbjit_init_reader. + + The function is expected to use CALLBACKS (documented above) to build a + symbol table for this particular block of memory (pointed to by MEMORY, + already copied from the target address space to GDB's address space). + MEMORY_SZ is the size of the block of memory. + + Should return GDB_JIT_SUCESS on success and GDB_JIT_FAIL on error. */ +extern int gdbjit_read_debug_info (void *private, + struct gdbjit_symtab_callbacks *callbacks, + void *memory, long memory_sz); + +/* Called to unwind one frame. PRIVATE is the private pointer. Expected to use + CALLBACKS to unwind the registers to the older frame. + + Should return GDB_JIT_SUCESS for success, GDB_JIT_FAIL for fail. */ +extern int gdbjit_unwind_frame (void *private, + struct gdbjit_unwind_callbacks *callbacks); + +/* Called to get a unique identifier for the current stack frame (as reported by + callbacks). */ +struct gdbjit_frame_id gdbjit_get_frame_id (void *private, struct + gdbjit_unwind_callbacks *callbacks); + +/* Called once the inferior process exits. */ +extern void gdbjit_destroy_reader (void *private); + +#endif diff --git a/gdb/jit.c b/gdb/jit.c index be123a5..4ce5814 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.3 ^ permalink raw reply [flat|nested] 8+ messages in thread
* [PATCH 2/4] Add symbol-handling callbacks to the jit-reader interface. 2011-07-05 6:27 [PATCH 1/4] jit-reader.h: describe interface implemented by the JIT readers Sanjoy Das @ 2011-07-05 6:27 ` Sanjoy Das 0 siblings, 0 replies; 8+ messages in thread From: Sanjoy Das @ 2011-07-05 6:27 UTC (permalink / raw) To: gdb-patches; +Cc: Sanjoy Das Implements the callbacks in `struct gdbjit_symtab_callbacks'. This will allow the JIT debug info reader to be able to parse the debug info and actually push the symbols into GDB. gdb/ChangeLog: * jit.c: Add symbol handling callbacks for the JIT reader interface. --- gdb/ChangeLog | 4 + gdb/jit.c | 522 +++++++++++++++++++++++++++++++++++++++++++++++++++------ 2 files changed, 475 insertions(+), 51 deletions(-) diff --git a/gdb/ChangeLog b/gdb/ChangeLog index 3ad44e8..38b83f1 100644 --- a/gdb/ChangeLog +++ b/gdb/ChangeLog @@ -1,5 +1,9 @@ 2011-07-04 Sanjoy Das <sanjoy@playingwithpointers.com> + * jit.c: Add symbol handling callbacks for the JIT reader interface. + +2011-07-04 Sanjoy Das <sanjoy@playingwithpointers.com> + * jit-reader.h: Add (new) JIT reader interface. * jit.c: Include jit-reader.h in source file * Makefile.in: Add jit-reader.h to HFILES_NO_SRCDIR. diff --git a/gdb/jit.c b/gdb/jit.c index 4ce5814..f8810a8 100644 --- a/gdb/jit.c +++ b/gdb/jit.c @@ -21,8 +21,10 @@ #include "jit.h" #include "jit-reader.h" +#include "block.h" #include "breakpoint.h" #include "command.h" +#include "dictionary.h" #include "gdbcmd.h" #include "gdbcore.h" #include "inferior.h" @@ -31,8 +33,11 @@ #include "symfile.h" #include "symtab.h" #include "target.h" +#include "gdb_dirent.h" #include "gdb_stat.h" +#include <dlfcn.h> + static const struct objfile_data *jit_objfile_data; static const char *const jit_break_name = "__jit_debug_register_code"; @@ -45,6 +50,115 @@ static const struct inferior_data *jit_inferior_data = NULL; static int jit_debug = 0; +/* The environment variable we poke at to get the file name of the shared object + to load. */ + +static const char *jit_dbg_reader_so_name_env = "JIT_DEBUG_READER"; + +/* Symbols (and the corresponding types) to be loaded from the shared object + supposed to do the debug-info parsing. */ +typedef int (jit_init_reader_fn) (void **); +static const char *jit_init_reader_sym = "gdbjit_init_reader"; + +typedef int (jit_read_debug_info_fn) (void *, struct gdbjit_symtab_callbacks *, + void *mem, long sz); +static const char *jit_read_debug_info_sym = "gdbjit_read_debug_info"; + +typedef int (jit_unwind_frame_fn) (void *, struct gdbjit_unwind_callbacks *); +static const char *jit_unwind_frame_sym = "gdbjit_unwind_frame"; + +typedef void (jit_destroy_reader_fn) (void *); +static const char *jit_destroy_reader_sym = "gdbjit_destroy_reader"; + +typedef struct gdbjit_frame_id (jit_get_frame_id_fn) (void *, struct + gdbjit_unwind_callbacks *); +static const char *jit_get_frame_id_sym = "gdbjit_get_frame_id"; + +static const char *jit_so_api_version_sym = "__gdbjit_so_api_version"; + +struct jit_dbg_reader +{ + jit_init_reader_fn *init; + jit_read_debug_info_fn *read; + jit_unwind_frame_fn *unwind; + jit_get_frame_id_fn *get_frame_id; + jit_destroy_reader_fn *destroy; + + void *handle, *private_data; +}; + +static struct jit_dbg_reader * +jit_dbg_reader_load (void) +{ + /* Check if a reader has been provided. */ + const char *file_name = getenv (jit_dbg_reader_so_name_env); + void *handle = NULL; + int (*jit_reader_so_api_version) (void) = NULL; + struct jit_dbg_reader *reader = NULL; + + if (file_name == NULL) + return NULL; + + handle = dlopen (file_name, RTLD_NOW); + if (!handle) + goto cleanup; + + reader = XZALLOC (struct jit_dbg_reader); + reader->init = dlsym (handle, jit_init_reader_sym); + reader->handle = handle; + + if (!reader->init) + goto cleanup; + + reader->read = dlsym (handle, jit_read_debug_info_sym); + if (!reader->read) + goto cleanup; + + reader->unwind = dlsym (handle, jit_unwind_frame_sym); + if (!reader->unwind) + goto cleanup; + + reader->get_frame_id = dlsym (handle, jit_get_frame_id_sym); + if (!reader->get_frame_id) + goto cleanup; + + reader->destroy = dlsym (handle, jit_destroy_reader_sym); + if (!reader->destroy) + goto cleanup; + + jit_reader_so_api_version = dlsym (handle, jit_so_api_version_sym); + if (!jit_reader_so_api_version || + jit_reader_so_api_version () != GDB_JIT_INTERFACE_VERSION) + { + goto cleanup; + } + + if (reader->init (&reader->private_data) != GDB_JIT_SUCCESS) + goto cleanup; + + return reader; + + cleanup: + xfree (reader); + if (handle) + { + dlclose (handle); + fprintf (stderr, "Could not load reader object %s\n", file_name); + } + else /* also report why the shared object could not be loaded */ + fprintf (stderr, "Could not load reader object %s (%s)\n", file_name, + dlerror()); + return NULL; +} + +static void +jit_dbg_reader_destroy (struct jit_dbg_reader *reader) +{ + if (reader) + reader->destroy (reader->private_data); + xfree (reader); +} + static void show_jit_debug (struct ui_file *file, int from_tty, struct cmd_list_element *c, const char *value) @@ -135,6 +249,9 @@ struct jit_inferior_data { CORE_ADDR breakpoint_addr; /* &__jit_debug_register_code() */ CORE_ADDR descriptor_addr; /* &__jit_debug_descriptor */ + struct jit_dbg_reader *reader; /* If a debug info reader was found. */ + struct objfile *jit_objfile; /* The object file where all the JIT symbols + will be added. */ }; /* Return jit_inferior_data for current inferior. Allocate if not already @@ -233,6 +350,286 @@ jit_read_code_entry (struct gdbarch *gdbarch, extract_unsigned_integer (&entry_buf[3 * ptr_size], 8, byte_order); } +struct gdbjit_block +{ + struct gdbjit_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; +}; + +struct gdbjit_symtab +{ + struct gdbjit_block *blocks; + struct linetable *linetable; + int nblocks; + + const char *file_name; +}; + +struct jit_dbg_reader_data +{ + struct objfile **objf; +}; + +static int +jit_target_read_impl (void *target_mem, void *gdb_buf, int len) +{ + return target_read_memory ((CORE_ADDR) target_mem, gdb_buf, len); +} + +static struct gdbjit_symtab * +jit_symtab_open_impl (struct gdbjit_symtab_callbacks *cb, const char *file_name) +{ + struct gdbjit_symtab *ret = XZALLOC (struct gdbjit_symtab); + ret->file_name = xstrdup (file_name); + return ret; +} + +/* Returns true if the block corrensponding to old should be placed before the + block corrensponding to new in the final blockvector. */ +static int +compare_block (struct gdbjit_block *old, struct gdbjit_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; +} + +static struct gdbjit_block * +jit_new_block_impl (struct gdbjit_symtab_callbacks *cb, + struct gdbjit_symtab *symtab, + struct gdbjit_block *parent, + void *begin, void *end, const char *name) +{ + struct gdbjit_block *block = XZALLOC (struct gdbjit_block); + + (void) cb; + + 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 gdbjit_block *i = symtab->blocks; + + for (;; i = i->next) + { + /* Guranteed 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; +} + +static void +jit_symtab_add_line_mapping_impl (struct gdbjit_symtab_callbacks *cb, + struct gdbjit_symtab *stab, + int nlines, + struct gdbjit_line_mapping *map) +{ + int i; + /* Must copy */ + if (!nlines) + 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; + } +} + +static void +jit_symtab_close_impl (struct gdbjit_symtab_callbacks *cb, + struct gdbjit_symtab *stab) +{ + struct jit_dbg_reader_data *dat = cb->private; + struct symtab *symtab; + struct gdbjit_block *blck_iter, *blck_iter_tmp; + struct block *block_iter; + struct objfile *objfile; + int actual_nblocks = FIRST_LOCAL_BLOCK + stab->nblocks, i; + CORE_ADDR begin, end; + + if (*dat->objf == NULL) + { + objfile = allocate_objfile (NULL, 0); + *dat->objf = objfile; + 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; + objfile->name = xstrdup ("JIT"); + } + else + objfile = *dat->objf; + + symtab = allocate_symtab (stab->file_name, objfile); + symtab->dirname = NULL; /* JIT compilers compile in memory */ + + 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; + } + + symtab->blockvector = obstack_alloc (&objfile->objfile_obstack, + (sizeof (struct blockvector) + + (actual_nblocks - 1) * + sizeof (struct block *))); + + /* (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; + + for (i = (actual_nblocks - 1), blck_iter = stab->blocks; + i >= FIRST_LOCAL_BLOCK; i--) + { + struct block *bl = allocate_block (&objfile->objfile_obstack); + struct symbol *block_name = obstack_alloc (&objfile->objfile_obstack, + sizeof (struct symbol)); + + BLOCK_DICT (bl) = dict_create_linear (&objfile->objfile_obstack, NULL); + BLOCK_START (bl) = (CORE_ADDR) blck_iter->begin; + BLOCK_END (bl) = (CORE_ADDR) blck_iter->end; + BLOCK_FUNCTION (bl) = block_name; + + memset (block_name, 0, sizeof (struct symbol)); + SYMBOL_DOMAIN (block_name) = VAR_DOMAIN; + SYMBOL_CLASS (block_name) = LOC_BLOCK; + block_name->symtab = symtab; + SYMBOL_BLOCK_VALUE (block_name) = bl; + + block_name->ginfo.name = obstack_alloc (&objfile->objfile_obstack, + 1 + strlen (blck_iter->name)); + strcpy (block_name->ginfo.name, blck_iter->name); + BLOCK_FUNCTION (bl) = block_name; + + BLOCKVECTOR_BLOCK (symtab->blockvector, i) = bl; + if (begin < (long) blck_iter->begin) + begin = (long) blck_iter->begin; + if (end > (long) blck_iter->end) + end = (long) blck_iter->end; + } + + blck_iter = blck_iter->next; + + /* Now add the special blocks. */ + block_iter = NULL; + for (i = 0; i < FIRST_LOCAL_BLOCK; i++) + { + struct block *bl = allocate_block (&objfile->objfile_obstack); + BLOCK_DICT (bl) = dict_create_linear (&objfile->objfile_obstack, NULL); + BLOCK_SUPERBLOCK (bl) = block_iter; + block_iter = bl; + + BLOCK_START (bl) = (CORE_ADDR) begin; + BLOCK_END (bl) = (CORE_ADDR) end; + + BLOCKVECTOR_BLOCK (symtab->blockvector, i) = bl; + } + + /* Fill up the superblock fields. */ + for (blck_iter = stab->blocks; blck_iter; blck_iter = blck_iter->next) + { + if (blck_iter->parent != NULL) + BLOCK_SUPERBLOCK (blck_iter->real_block) = + blck_iter->parent->real_block; + } + + /* Free memory. */ + blck_iter = stab->blocks; + for (blck_iter = stab->blocks, blck_iter_tmp = blck_iter->next; + blck_iter; blck_iter = blck_iter_tmp) + { + xfree (blck_iter); + } +} + +static int +jit_try_read_symtab (struct jit_inferior_data *inf_data, + CORE_ADDR target_mem, long sz) +{ + void *gdb_mem; + int status = 0; + struct jit_dbg_reader *i; + struct jit_dbg_reader_data priv_data; + struct gdbjit_symtab_callbacks callbacks = + { + jit_symtab_open_impl, + jit_new_block_impl, + jit_symtab_add_line_mapping_impl, + jit_target_read_impl, + jit_symtab_close_impl, + + &priv_data + }; + + if (!inf_data->reader) + return 0; + + priv_data.objf = &inf_data->jit_objfile; + + gdb_mem = xmalloc (sz); + if (target_read_memory (target_mem, gdb_mem, sz)) + { + status = 0; + goto cleanup; + } + + if (inf_data->reader->read (inf_data->reader->private_data, &callbacks, + gdb_mem, sz) == GDB_JIT_SUCCESS) + { + status = 1; + goto cleanup; + } + + cleanup: + xfree (gdb_mem); + return status; +} + /* 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 @@ -242,14 +639,9 @@ static void jit_register_code (struct gdbarch *gdbarch, CORE_ADDR entry_addr, struct jit_code_entry *code_entry) { - 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; + int i, success; + struct jit_inferior_data *inf_data = get_jit_inferior_data (); if (jit_debug) fprintf_unfiltered (gdb_stdlog, @@ -258,53 +650,68 @@ jit_register_code (struct gdbarch *gdbarch, paddress (gdbarch, code_entry->symfile_addr), pulongest (code_entry->symfile_size)); - 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. */ - if (!bfd_check_format (nbfd, bfd_object)) + if (jit_try_read_symtab (inf_data, code_entry->symfile_addr, + code_entry->symfile_size)) { - printf_unfiltered (_("\ + objfile = inf_data->jit_objfile; + } + else + { + struct cleanup *old_cleanups; + bfd *nbfd; + struct section_addr_info *sai; + struct bfd_section *sec; + const struct bfd_arch_info *b; + CORE_ADDR *entry_addr_ptr; + + 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. */ + if (!bfd_check_format (nbfd, bfd_object)) + { + printf_unfiltered (_("\ JITed symbol file is not an object file, ignoring it.\n")); - do_cleanups (old_cleanups); - return; + do_cleanups (old_cleanups); + return; + } + + /* Check bfd arch. */ + b = gdbarch_bfd_arch_info (gdbarch); + if (b->compatible (b, bfd_get_arch_info (nbfd)) != b) + warning (_("JITed object file architecture %s is not compatible " + "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. */ + 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. */ + 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; + ++i; + } + + /* 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); } - - /* Check bfd arch. */ - b = gdbarch_bfd_arch_info (gdbarch); - if (b->compatible (b, bfd_get_arch_info (nbfd)) != b) - warning (_("JITed object file architecture %s is not compatible " - "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. */ - 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. */ - 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; - ++i; - } - - /* 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); } /* This function unregisters JITed code and frees the corresponding @@ -385,6 +792,8 @@ jit_inferior_init (struct gdbarch *gdbarch) if (jit_breakpoint_re_set_internal (gdbarch, inf_data) != 0) return; + inf_data->reader = jit_dbg_reader_load (); + if (inf_data->descriptor_addr == 0) { struct minimal_symbol *desc_symbol; @@ -464,6 +873,11 @@ jit_reset_inferior_data_and_breakpoints (void) /* Remove any existing JIT breakpoint(s). */ remove_jit_event_breakpoints (); + /* Destroy JIT reader objects. */ + jit_dbg_reader_destroy (inf_data->reader); + if (inf_data->jit_objfile) + free_objfile (inf_data->jit_objfile); + jit_inferior_init (target_gdbarch); } @@ -484,6 +898,12 @@ jit_inferior_exit_hook (struct inferior *inf) { struct objfile *objf; struct objfile *temp; + struct jit_inferior_data *inf_data; + + inf_data = inferior_data (inf, jit_inferior_data); + jit_dbg_reader_destroy (inf_data->reader); + if (inf_data->jit_objfile) + free_objfile (inf_data->jit_objfile); ALL_OBJFILES_SAFE (objf, temp) if (objfile_data (objf, jit_objfile_data) != NULL) -- 1.7.5.3 ^ permalink raw reply [flat|nested] 8+ messages in thread
end of thread, other threads:[~2011-07-14 17:55 UTC | newest] Thread overview: 8+ messages (download: mbox.gz / follow: Atom feed) -- links below jump to the message on this page -- 2011-07-13 20:24 [PATCH 1/4] jit-reader.h: describe interface implemented by the JIT readers Sanjoy Das 2011-07-13 20:24 ` [PATCH 4/4] Activate JIT code unwinder for i386 Sanjoy Das 2011-07-14 17:55 ` Tom Tromey 2011-07-14 17:58 ` Sanjoy Das 2011-07-13 20:52 ` [PATCH 2/4] Add symbol-handling callbacks to the jit-reader interface Sanjoy Das 2011-07-14 1:39 ` [PATCH 3/4] Add an unwinder for JIT compiled code Sanjoy Das 2011-07-14 21:05 ` Tom Tromey -- strict thread matches above, loose matches on Subject: below -- 2011-07-05 6:27 [PATCH 1/4] jit-reader.h: describe interface implemented by the JIT readers Sanjoy Das 2011-07-05 6:27 ` [PATCH 2/4] Add symbol-handling callbacks to the jit-reader interface Sanjoy Das
This is a public inbox, see mirroring instructions for how to clone and mirror all data and code used for this inbox