[PATCH 1/4] jit-reader.h: describe interface implemented by the JIT readers.

Sanjoy Das
2011-07-13T20:23:56Z

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