Mirror of the gdb-patches mailing list
 help / color / mirror / Atom feed
* [PATCH 5/7] Use the loaded reader.
  2011-08-27 13:08 JIT Debug Info Reader Sanjoy Das
@ 2011-08-27 13:08 ` Sanjoy Das
  2011-08-27 13:47   ` Abhijit Halder
  2011-08-27 13:08 ` [PATCH 2/7] Relocatable directory for loading JIT readers Sanjoy Das
                   ` (5 subsequent siblings)
  6 siblings, 1 reply; 29+ messages in thread
From: Sanjoy Das @ 2011-08-27 13:08 UTC (permalink / raw)
  To: gdb-patches; +Cc: Sanjoy Das

Invoke the loaded JIT debug info reader to parse the registered symbol
files.

gdb/ChangeLog:
	* gdb/jit.c: Include block.h, dictionary.h and frame-unwind.h.
	(add_objfile_entry, jit_target_read_impl, jit_object_open_impl)
	(jit_symtab_open_impl, compare_block, jit_block_open_impl)
	(jit_symtab_line_mapping_add_impl, jit_symtab_close_impl)
	(finalize_symtab, jit_object_close_impl)
	(jit_reader_try_read_symtab, jit_bfd_try_read_symtab)
	(free_objfile_data): New functions.
	(_initialize_jit): Register jit_objfile_data with a proper cleanup
	function.
---
 gdb/ChangeLog |   12 ++
 gdb/jit.c     |  479 ++++++++++++++++++++++++++++++++++++++++++++++++++++++---
 2 files changed, 468 insertions(+), 23 deletions(-)

diff --git a/gdb/ChangeLog b/gdb/ChangeLog
index 78076ef..7cdde7b 100644
--- a/gdb/ChangeLog
+++ b/gdb/ChangeLog
@@ -1,5 +1,17 @@
 2011-08-27  Sanjoy Das  <sdas@igalia.com>
 
+	* gdb/jit.c: Include block.h, dictionary.h and frame-unwind.h.
+	(add_objfile_entry, jit_target_read_impl, jit_object_open_impl)
+	(jit_symtab_open_impl, compare_block, jit_block_open_impl)
+	(jit_symtab_line_mapping_add_impl, jit_symtab_close_impl)
+	(finalize_symtab, jit_object_close_impl)
+	(jit_reader_try_read_symtab, jit_bfd_try_read_symtab)
+	(free_objfile_data): New functions.
+	(_initialize_jit): Register jit_objfile_data with a proper cleanup
+	function.
+
+2011-08-27  Sanjoy Das  <sdas@igalia.com>
+
 	* gdb/jit.c: Include gdb-dlfcn.h.
 	(loaded_jit_reader, reader_init_fn_sym): New static variables.
 	(jit_reader_load, jit_reader_load_command)
diff --git a/gdb/jit.c b/gdb/jit.c
index 4fc5819..3be8c4d 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"
@@ -233,6 +236,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.  */
 
@@ -329,30 +344,417 @@ 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);
@@ -395,12 +797,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
@@ -635,6 +1059,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);
@@ -655,7 +1087,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 ("jit-reader-load", no_class, jit_reader_load_command, _("\
-- 
1.7.5.4


^ permalink raw reply	[flat|nested] 29+ messages in thread

* JIT Debug Info Reader
@ 2011-08-27 13:08 Sanjoy Das
  2011-08-27 13:08 ` [PATCH 5/7] Use the loaded reader Sanjoy Das
                   ` (6 more replies)
  0 siblings, 7 replies; 29+ messages in thread
From: Sanjoy Das @ 2011-08-27 13:08 UTC (permalink / raw)
  To: gdb-patches

Hi!

This (seven part) series should hopefully address all the previous
mistakes.

Thanks!


^ permalink raw reply	[flat|nested] 29+ messages in thread

* [PATCH 1/7] Introduce jit-reader.in and modify build system.
  2011-08-27 13:08 JIT Debug Info Reader Sanjoy Das
                   ` (5 preceding siblings ...)
  2011-08-27 13:08 ` [PATCH 7/7] Documentation Sanjoy Das
@ 2011-08-27 13:08 ` Sanjoy Das
  6 siblings, 0 replies; 29+ messages in thread
From: Sanjoy Das @ 2011-08-27 13:08 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.

gdb/ChangeLog:
	* gdb/Makefile.in: Add jit-reader.h as a header.  Have it
	installed in $(includedir)/gdb.
	* gdb/configure.ac: Genereate a correct value for TARGET_PTR for
	jit-reader.h.  Tell configure to generate jit-reader.h from
	jit-reader.in.
	* gdb/configure: Re-generated by autoconf.
	* gdb/jit-reader.in: New file.
	* gdb/jit.c: Include jit-reader.h.
---
 gdb/ChangeLog     |   11 ++
 gdb/Makefile.in   |   13 ++-
 gdb/configure     |  124 +++++++++++++++++++
 gdb/configure.ac  |   22 ++++
 gdb/jit-reader.in |  350 +++++++++++++++++++++++++++++++++++++++++++++++++++++
 gdb/jit.c         |    1 +
 6 files changed, 517 insertions(+), 4 deletions(-)
 create mode 100644 gdb/jit-reader.in

diff --git a/gdb/ChangeLog b/gdb/ChangeLog
index e2bd6f6..ff9b8af 100644
--- a/gdb/ChangeLog
+++ b/gdb/ChangeLog
@@ -1,3 +1,14 @@
+2011-08-27  Sanjoy Das  <sdas@igalia.com>
+
+	* gdb/Makefile.in: Add jit-reader.h as a header.  Have it
+	installed in $(includedir)/gdb.
+	* gdb/configure.ac: Genereate a correct value for TARGET_PTR for
+	jit-reader.h.  Tell configure to generate jit-reader.h from
+	jit-reader.in.
+	* gdb/configure: Re-generated by autoconf.
+	* gdb/jit-reader.in: New file.
+	* gdb/jit.c: Include jit-reader.h.
+
 2011-08-26  Jan Kratochvil  <jan.kratochvil@redhat.com>
 
 	* inf-loop.c (inferior_event_handler): Add exception_print in
diff --git a/gdb/Makefile.in b/gdb/Makefile.in
index a3bd1f9..b277597 100644
--- a/gdb/Makefile.in
+++ b/gdb/Makefile.in
@@ -824,7 +824,7 @@ common/linux-osdata.h
 
 # Header files that already have srcdir in them, or which are in objdir.
 
-HFILES_WITH_SRCDIR = ../bfd/bfd.h
+HFILES_WITH_SRCDIR = ../bfd/bfd.h jit-reader.h
 
 
 # GDB "info" files, which should be included in their entirety
@@ -941,7 +941,7 @@ DISTSTUFF = $(YYFILES)
 
 
 # All generated files which can be included by another file.
-generated_files = config.h observer.h observer.inc ada-lex.c \
+generated_files = config.h observer.h observer.inc ada-lex.c jit-reader.h \
 	$(GNULIB_H) $(NAT_GENERATED_FILES)
 
 .c.o:
@@ -1026,7 +1026,9 @@ install-only: $(CONFIG_INSTALL)
 		$(SHELL) $(srcdir)/../mkinstalldirs \
 			$(DESTDIR)$(man1dir) ; \
 		$(INSTALL_DATA) $(srcdir)/gdb.1 \
-			$(DESTDIR)$(man1dir)/$$transformed_name.1
+			$(DESTDIR)$(man1dir)/$$transformed_name.1 ; \
+		$(SHELL) $(srcdir)/../mkinstalldirs $(includedir)/gdb ; \
+		$(INSTALL_DATA) jit-reader.h $(includedir)/gdb/jit-reader.h
 	@$(MAKE) DO=install "DODIRS=$(SUBDIRS)" $(FLAGS_TO_PASS) subdir_do
 .PHONY: install-tui
 install-tui:
@@ -1254,7 +1256,7 @@ distclean: clean
 	rm -f gdbserver/config.status gdbserver/config.log
 	rm -f gdbserver/tm.h gdbserver/xm.h gdbserver/nm.h
 	rm -f gdbserver/Makefile gdbserver/config.cache
-	rm -f nm.h config.status config.h stamp-h .gdbinit
+	rm -f nm.h config.status config.h stamp-h .gdbinit jit-reader.h
 	rm -f y.output yacc.acts yacc.tmp y.tab.h
 	rm -f config.log config.cache
 	rm -f Makefile
@@ -1320,6 +1322,9 @@ data-directory/Makefile: data-directory/Makefile.in config.status @frags@
 	  CONFIG_LINKS= \
 	  $(SHELL) config.status
 
+jit-reader.h: $(srcdir)/jit-reader.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/configure b/gdb/configure
index ac143e4..31469f2 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,128 @@ 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
+
+
+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 +16840,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..abeb251 100644
--- a/gdb/configure.ac
+++ b/gdb/configure.ac
@@ -573,6 +573,28 @@ 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_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..f9af324
--- /dev/null
+++ b/gdb/jit-reader.in
@@ -0,0 +1,350 @@
+/* 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] 29+ messages in thread

* [PATCH 7/7] Documentation.
  2011-08-27 13:08 JIT Debug Info Reader Sanjoy Das
                   ` (4 preceding siblings ...)
  2011-08-27 13:08 ` [PATCH 4/7] New commands for loading and unloading a reader Sanjoy Das
@ 2011-08-27 13:08 ` Sanjoy Das
  2011-08-27 13:08 ` [PATCH 1/7] Introduce jit-reader.in and modify build system Sanjoy Das
  6 siblings, 0 replies; 29+ messages in thread
From: Sanjoy Das @ 2011-08-27 13:08 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/doc/ChangeLog:
	* gdb.texinfo (JIT Interface): Add documentation on writing and
	usind JIT debug info readers.
	(Custom Debug Info, Using JIT Debug Info Readers, Writing JIT
	Debug Info Readers): New nodes.
---
 gdb/doc/ChangeLog   |    7 +++
 gdb/doc/gdb.texinfo |  117 +++++++++++++++++++++++++++++++++++++++++++++++++++
 2 files changed, 124 insertions(+), 0 deletions(-)

diff --git a/gdb/doc/ChangeLog b/gdb/doc/ChangeLog
index 80038f1..190ff75 100644
--- a/gdb/doc/ChangeLog
+++ b/gdb/doc/ChangeLog
@@ -1,3 +1,10 @@
+2011-08-27  Sanjoy Das  <sdas@igalia.com>
+
+	* gdb.texinfo (JIT Interface): Add documentation on writing and
+	usind JIT debug info readers.
+	(Custom Debug Info, Using JIT Debug Info Readers, Writing JIT
+	Debug Info Readers): New nodes.
+
 2011-08-25  Andrew Oakley  <andrew@ado.is-a-geek.net>
 
 	* gdb.texinfo (Types In Python): Document 'bitpos' for enums.
diff --git a/gdb/doc/gdb.texinfo b/gdb/doc/gdb.texinfo
index 23b2a98..8168952 100644
--- a/gdb/doc/gdb.texinfo
+++ b/gdb/doc/gdb.texinfo
@@ -30951,6 +30951,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
@@ -31047,6 +31048,122 @@ 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 source file
+@file{gdb/jit-reader.in}, which is also installed as a header at
+@file{@var{includedir}/gdb/jit-reader.h} for easy inclusion.
+
+The reader is implemented as a shared object.  Two new @value{GDBN}
+commands, @code{load-jit-reader} and @code{unload-jit-reader} are
+provided, 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 JIT Debug Info Readers::       How to use supplied readers correctly
+* Writing JIT Debug Info Readers::     Creating a debug-info reader
+@end menu
+
+@node Using JIT Debug Info Readers
+@subsection Using JIT Debug Info 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
+@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 invoking @code{load-jit-reader}.
+
+@item unload-jit-reader
+
+Unload the currently loaded JIT reader.
+
+@end table
+
+@node Writing JIT Debug Info Readers
+@subsection Writing JIT Debug Info 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] 29+ messages in thread

* [PATCH 6/7] New JIT unwinder.
  2011-08-27 13:08 JIT Debug Info Reader Sanjoy Das
                   ` (2 preceding siblings ...)
  2011-08-27 13:08 ` [PATCH 3/7] Platform agnostic dynamic loading code Sanjoy Das
@ 2011-08-27 13:08 ` Sanjoy Das
  2011-08-28  2:17   ` Sergio Durigan Junior
       [not found]   ` <1314518609-10204-1-git-send-email-sanjoy@playingwithpointers.com>
  2011-08-27 13:08 ` [PATCH 4/7] New commands for loading and unloading a reader Sanjoy Das
                   ` (2 subsequent siblings)
  6 siblings, 2 replies; 29+ messages in thread
From: Sanjoy Das @ 2011-08-27 13:08 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:
	* gdb/jit.c: Include regcache.h.
	(jit_gdbarch_data, jit_frame_unwind): New static variables.
	(jit_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_prepend_unwinder, jit_gdbarch_data_init): New functions.
	(jit_inferior_init): Prepend (new) pseudo unwinder by calling
	jit_prepend_unwinder.
	(_initialize_jit): Register new gdbarch data jit_gdbarch_data.
---
 gdb/ChangeLog |   13 +++
 gdb/jit.c     |  271 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++
 2 files changed, 284 insertions(+), 0 deletions(-)

diff --git a/gdb/ChangeLog b/gdb/ChangeLog
index 7cdde7b..cb000aa 100644
--- a/gdb/ChangeLog
+++ b/gdb/ChangeLog
@@ -1,5 +1,18 @@
 2011-08-27  Sanjoy Das  <sdas@igalia.com>
 
+	* gdb/jit.c: Include regcache.h.
+	(jit_gdbarch_data, jit_frame_unwind): New static variables.
+	(jit_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_prepend_unwinder, jit_gdbarch_data_init): New functions.
+	(jit_inferior_init): Prepend (new) pseudo unwinder by calling
+	jit_prepend_unwinder.
+	(_initialize_jit): Register new gdbarch data jit_gdbarch_data.
+
+2011-08-27  Sanjoy Das  <sdas@igalia.com>
+
 	* gdb/jit.c: Include block.h, dictionary.h and frame-unwind.h.
 	(add_objfile_entry, jit_target_read_impl, jit_object_open_impl)
 	(jit_symtab_open_impl, compare_block, jit_block_open_impl)
diff --git a/gdb/jit.c b/gdb/jit.c
index 3be8c4d..fa25908 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;
@@ -893,6 +900,254 @@ 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 dwarf_regnum,
+                         struct gdb_reg_value *value)
+{
+  struct jit_unwind_private *priv;
+  int gdb_reg;
+
+  priv = cb->priv_data;
+
+  gdb_reg = gdbarch_dwarf2_reg_to_regnum (get_frame_arch (priv->this_frame),
+                                          dwarf_regnum);
+  if (gdb_reg == -1)
+    {
+      if (jit_debug)
+        fprintf_unfiltered (gdb_stdlog,
+                            _("Could not recognize DWARF regnum %d"),
+                            dwarf_regnum);
+      return;
+    }
+
+  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;
+  struct gdbarch *frame_arch;
+
+  priv = cb->priv_data;
+  frame_arch = get_frame_arch (priv->this_frame);
+
+  gdb_reg = gdbarch_dwarf2_reg_to_regnum (frame_arch, regnum);
+  size = register_size (frame_arch, 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;
+}
+
+/* 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;
+  struct gdbarch *frame_arch;
+  int i;
+
+  gdb_assert (priv_data->registers);
+  frame_arch = get_frame_arch (priv_data->this_frame);
+
+  for (i = 0; i < gdbarch_num_regs (frame_arch); 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);
+}
+
+/* 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;
+
+  gdb_assert (!*cache);
+
+  *cache = XZALLOC (struct jit_unwind_private);
+  priv_data = *cache;
+  priv_data->registers =
+    XCALLOC (gdbarch_num_regs (get_frame_arch (this_frame)),
+             struct gdb_reg_value *);
+  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"));
+
+  jit_dealloc_cache (this_frame, cache);
+  *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 default_frame_unwind_stop_reason (this_frame, cache);
+}
+
+/* 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);
+}
+
+/* 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
@@ -906,6 +1161,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;
@@ -1067,6 +1324,19 @@ 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;
+
+  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);
@@ -1091,6 +1361,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 ("jit-reader-load", no_class, jit_reader_load_command, _("\
 Load FILE as debug info reader and unwinder for JIT compiled code.\n\
 Try to load file FILE as a debug info reader (and unwinder) for\n\
-- 
1.7.5.4


^ permalink raw reply	[flat|nested] 29+ messages in thread

* [PATCH 3/7] Platform agnostic dynamic loading code.
  2011-08-27 13:08 JIT Debug Info Reader Sanjoy Das
  2011-08-27 13:08 ` [PATCH 5/7] Use the loaded reader Sanjoy Das
  2011-08-27 13:08 ` [PATCH 2/7] Relocatable directory for loading JIT readers Sanjoy Das
@ 2011-08-27 13:08 ` Sanjoy Das
  2011-08-27 13:08 ` [PATCH 6/7] New JIT unwinder Sanjoy Das
                   ` (3 subsequent siblings)
  6 siblings, 0 replies; 29+ messages in thread
From: Sanjoy Das @ 2011-08-27 13:08 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/Makefile.in: Add gdb-dlfcn.c and gdb-dlfcn.h to build
	system.
	* gdb/config.in: Add new #define HAVE_LIBDL.
	* gdb/configure.ac: Add check for -ldl.
	* gdb/configure: Re-generated by autoconf.
---
 gdb/ChangeLog    |    8 ++++
 gdb/Makefile.in  |    6 ++--
 gdb/config.in    |    3 ++
 gdb/configure    |   46 ++++++++++++++++++++++++++
 gdb/configure.ac |    2 +
 gdb/gdb-dlfcn.c  |   95 ++++++++++++++++++++++++++++++++++++++++++++++++++++++
 gdb/gdb-dlfcn.h  |   46 ++++++++++++++++++++++++++
 7 files changed, 203 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 3196016..3536807 100644
--- a/gdb/ChangeLog
+++ b/gdb/ChangeLog
@@ -1,5 +1,13 @@
 2011-08-27  Sanjoy Das  <sdas@igalia.com>
 
+	* gdb/Makefile.in: Add gdb-dlfcn.c and gdb-dlfcn.h to build
+	system.
+	* gdb/config.in: Add new #define HAVE_LIBDL.
+	* gdb/configure.ac: Add check for -ldl.
+	* gdb/configure: Re-generated by autoconf.
+
+2011-08-27  Sanjoy Das  <sdas@igalia.com>
+
 	* gdb/config.in: Add new #defines: JIT_READER_DIR and
 	JIT_READER_DIR_RELOCATABLE.
 	* gdb/configure.ac: New GDB directory entry for jit-reader-dir.
diff --git a/gdb/Makefile.in b/gdb/Makefile.in
index b277597..732b8f0 100644
--- a/gdb/Makefile.in
+++ b/gdb/Makefile.in
@@ -739,7 +739,7 @@ SFILES = ada-exp.y ada-lang.c ada-typeprint.c ada-valprint.c ada-tasks.c \
 	annotate.c common/signals.c copying.c dfp.c gdb.c inf-child.c \
 	regset.c sol-thread.c windows-termcap.c \
 	common/common-utils.c common/xml-utils.c \
-	common/ptid.c common/buffer.c
+	common/ptid.c common/buffer.c gdb-dlfcn.c
 
 LINTFILES = $(SFILES) $(YYFILES) $(CONFIG_SRCS) init.c
 
@@ -820,7 +820,7 @@ solib-darwin.h solib-ia64-hpux.h solib-spu.h windows-nat.h xcoffread.h \
 gnulib/extra/arg-nonnull.h gnulib/extra/c++defs.h gnulib/extra/warn-on-use.h \
 gnulib/stddef.in.h inline-frame.h \
 common/common-utils.h common/xml-utils.h common/buffer.h common/ptid.h \
-common/linux-osdata.h
+common/linux-osdata.h gdb-dlfcn.h
 
 # Header files that already have srcdir in them, or which are in objdir.
 
@@ -907,7 +907,7 @@ COMMON_OBS = $(DEPFILES) $(CONFIG_OBS) $(YYOBJ) \
 	target-descriptions.o target-memory.o xml-tdesc.o xml-builtin.o \
 	inferior.o osdata.o gdb_usleep.o record.o gcore.o \
 	jit.o progspace.o \
-	common-utils.o buffer.o ptid.o
+	common-utils.o buffer.o ptid.o gdb-dlfcn.o
 
 TSOBS = inflow.o
 
diff --git a/gdb/config.in b/gdb/config.in
index b1aef82..89c0eb4 100644
--- a/gdb/config.in
+++ b/gdb/config.in
@@ -988,3 +988,6 @@
 
 /* Define if JIT_READER_DIR should be relocated when GDB is moved. */
 #undef JIT_READER_DIR_RELOCATABLE
+
+/* Define if -ldl will work. */
+#undef HAVE_LIBDL
diff --git a/gdb/configure b/gdb/configure
index c6dfbf7..b7753bf 100755
--- a/gdb/configure
+++ b/gdb/configure
@@ -9934,6 +9934,52 @@ fi
 ac_config_files="$ac_config_files jit-reader.h:jit-reader.in"
 
 
+{ $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
+
+
 
 
 # Check whether --with-jit-reader-dir was given.
diff --git a/gdb/configure.ac b/gdb/configure.ac
index ee73e9b..0ce5ac0 100644
--- a/gdb/configure.ac
+++ b/gdb/configure.ac
@@ -595,6 +595,8 @@ fi
 AC_SUBST(TARGET_PTR)
 AC_CONFIG_FILES([jit-reader.h:jit-reader.in])
 
+AC_CHECK_LIB([dl], [dlopen], [], [], [])
+
 GDB_AC_WITH_DIR([JIT_READER_DIR], [jit-reader-dir],
                 [directory to load the JIT readers from],
                 [${libdir}/gdb])
diff --git a/gdb/gdb-dlfcn.c b/gdb/gdb-dlfcn.c
new file mode 100644
index 0000000..34c58d7
--- /dev/null
+++ b/gdb/gdb-dlfcn.c
@@ -0,0 +1,95 @@
+/* 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)
+{
+  void *result;
+#ifdef HAVE_LIBDL
+  result = dlopen (filename, RTLD_NOW);
+#elif __MINGW32__
+  result = (void *) LoadLibrary (filename);
+#endif
+  if (result != NULL)
+    return result;
+
+#ifdef HAVE_LIBDL
+  error (_("Could not load %s: %s"), filename, dlerror());
+#else
+  {
+    LPVOID buffer;
+    DWORD dw;
+
+    dw = GetLastError();
+
+    FormatMessage (FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM |
+                   FORMAT_MESSAGE_IGNORE_INSERTS,
+                   NULL, dw, MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT),
+                   (LPTSTR) &buffer
+                   0, NULL);
+
+    error (_("Could not load %s: %s"), filename, (char *) buffer);
+  }
+#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
+}
+
+static void
+do_dlclose_cleanup (void *handle)
+{
+  gdb_dlclose (handle);
+}
+
+struct cleanup *
+make_cleanup_dlclose (void *handle)
+{
+  return make_cleanup (do_dlclose_cleanup, handle);
+}
diff --git a/gdb/gdb-dlfcn.h b/gdb/gdb-dlfcn.h
new file mode 100644
index 0000000..df6c05c
--- /dev/null
+++ b/gdb/gdb-dlfcn.h
@@ -0,0 +1,46 @@
+/* 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
+
+#include "defs.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);
+
+/* Install a cleanup routine which closes the handle HANDLE. */
+
+struct cleanup *make_cleanup_dlclose (void *handle);
+
+/* 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] 29+ messages in thread

* [PATCH 4/7] New commands for loading and unloading a reader.
  2011-08-27 13:08 JIT Debug Info Reader Sanjoy Das
                   ` (3 preceding siblings ...)
  2011-08-27 13:08 ` [PATCH 6/7] New JIT unwinder Sanjoy Das
@ 2011-08-27 13:08 ` Sanjoy Das
  2011-08-27 14:51   ` Abhijit Halder
  2011-08-27 13:08 ` [PATCH 7/7] Documentation Sanjoy Das
  2011-08-27 13:08 ` [PATCH 1/7] Introduce jit-reader.in and modify build system Sanjoy Das
  6 siblings, 1 reply; 29+ messages in thread
From: Sanjoy Das @ 2011-08-27 13:08 UTC (permalink / raw)
  To: gdb-patches; +Cc: Sanjoy Das

Introduces two new GDB commands - `load-jit-reader' and
`unload-jit-reader'.

gdb/ChangeLog:
	* gdb/jit.c: Include gdb-dlfcn.h.
	(loaded_jit_reader, reader_init_fn_sym): New static variables.
	(jit_reader_load, jit_reader_load_command)
	(jit_reader_unload_command): New functions.
	(_initialize_jit): Add commands "jit-reader-load" and
	"jit-reader-unload".
---
 gdb/ChangeLog |    9 +++++
 gdb/jit.c     |  103 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++
 2 files changed, 112 insertions(+), 0 deletions(-)

diff --git a/gdb/ChangeLog b/gdb/ChangeLog
index 3536807..78076ef 100644
--- a/gdb/ChangeLog
+++ b/gdb/ChangeLog
@@ -1,5 +1,14 @@
 2011-08-27  Sanjoy Das  <sdas@igalia.com>
 
+	* gdb/jit.c: Include gdb-dlfcn.h.
+	(loaded_jit_reader, reader_init_fn_sym): New static variables.
+	(jit_reader_load, jit_reader_load_command)
+	(jit_reader_unload_command): New functions.
+	(_initialize_jit): Add commands "jit-reader-load" and
+	"jit-reader-unload".
+
+2011-08-27  Sanjoy Das  <sdas@igalia.com>
+
 	* gdb/Makefile.in: Add gdb-dlfcn.c and gdb-dlfcn.h to build
 	system.
 	* gdb/config.in: Add new #define HAVE_LIBDL.
diff --git a/gdb/jit.c b/gdb/jit.c
index cab27a9..4fc5819 100644
--- a/gdb/jit.c
+++ b/gdb/jit.c
@@ -31,6 +31,7 @@
 #include "symfile.h"
 #include "symtab.h"
 #include "target.h"
+#include "gdb-dlfcn.h"
 #include "gdb_stat.h"
 
 static const char *jit_reader_dir = NULL;
@@ -115,6 +116,97 @@ 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. */
+
+static struct jit_reader
+{
+  struct gdb_reader_funcs *functions;
+} *loaded_jit_reader = NULL;
+
+typedef struct gdb_reader_funcs * (reader_init_fn_type) (void);
+static const char *reader_init_fn_sym = "gdb_init_reader";
+
+/* Try to load FILE_NAME as a JIT debug info reader. */
+
+static struct jit_reader *
+jit_reader_load (const char *file_name)
+{
+  void *so;
+  reader_init_fn_type *init_fn;
+  struct jit_reader *new_reader = NULL;
+  struct gdb_reader_funcs *funcs = NULL;
+  struct cleanup *old_cleanups;
+
+  if (jit_debug)
+    fprintf_unfiltered (gdb_stdlog, _("Opening shared object %s.\n"),
+                        file_name);
+  so = gdb_dlopen (file_name);
+  old_cleanups = make_cleanup_dlclose (so);
+
+  init_fn = gdb_dlsym (so, reader_init_fn_sym);
+  if (!init_fn)
+    error(_("Could not locate initialization function: %s."),
+          reader_init_fn_sym);
+
+  if (gdb_dlsym (so, "plugin_is_GPL_compatible") == NULL)
+    error(_("Reader not GPL compatible."));
+
+  funcs = init_fn ();
+  if (funcs->reader_version != GDB_READER_INTERFACE_VERSION)
+    error(_("Reader version does not match GDB version."));
+
+  new_reader = XZALLOC (struct jit_reader);
+  new_reader->functions = funcs;
+
+  discard_cleanups (old_cleanups);
+  return new_reader;
+}
+
+/* Provides the jit-reader-load command. */
+
+static void
+jit_reader_load_command (char *args, int from_tty)
+{
+  char so_name[PATH_MAX];
+  int len;
+
+  if (args == NULL)
+    {
+      error (_("No reader name provided."));
+      return;
+    }
+
+  if (loaded_jit_reader != NULL)
+    {
+      error (_("JIT reader already loaded.  Run jit-reader-unload first."));
+      return;
+    }
+
+  len = strlen (jit_reader_dir);
+  strcpy(so_name, jit_reader_dir);
+  so_name[len] = '/';
+  so_name[len + 1] = 0;
+
+  strncat (so_name, args, PATH_MAX - (len + 1));
+  loaded_jit_reader = jit_reader_load (so_name);
+}
+
+/* Provides the jit-reader-unload command. */
+
+static void
+jit_reader_unload_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 *
@@ -566,4 +658,15 @@ _initialize_jit (void)
   jit_objfile_data = register_objfile_data ();
   jit_inferior_data =
     register_inferior_data_with_cleanup (jit_inferior_data_cleanup);
+  add_com ("jit-reader-load", no_class, jit_reader_load_command, _("\
+Load FILE as debug info reader and unwinder for JIT compiled code.\n\
+Try to load file FILE as a debug info reader (and unwinder) for\n\
+JIT compiled code. The file is loaded from\n\
+" JIT_READER_DIR ", relocated \n\
+relative to the GDB executable if required.\n\
+Usage is `jit-reader-load FILE`."));
+  add_com ("jit-reader-unload", no_class, jit_reader_unload_command, _("\
+Unload the currently loaded JIT debug info reader.\n\
+See jit-reader-load for how to load JIT debug readers.\n\
+"));
 }
-- 
1.7.5.4


^ permalink raw reply	[flat|nested] 29+ messages in thread

* [PATCH 2/7] Relocatable directory for loading JIT readers.
  2011-08-27 13:08 JIT Debug Info Reader Sanjoy Das
  2011-08-27 13:08 ` [PATCH 5/7] Use the loaded reader Sanjoy Das
@ 2011-08-27 13:08 ` Sanjoy Das
  2011-08-27 13:08 ` [PATCH 3/7] Platform agnostic dynamic loading code Sanjoy Das
                   ` (4 subsequent siblings)
  6 siblings, 0 replies; 29+ messages in thread
From: Sanjoy Das @ 2011-08-27 13:08 UTC (permalink / raw)
  To: gdb-patches; +Cc: Sanjoy Das

Add a new directory `jit_reader_dir' to jit.c, which is relocated
during initialization.  The value of the directory can be set by using
--with-jit-reader-dir on configure and defaults to `${libdir}/gdb'.

gdb/ChangeLog:
	* gdb/config.in: Add new #defines: JIT_READER_DIR and
	JIT_READER_DIR_RELOCATABLE.
	* gdb/configure.ac: New GDB directory entry for jit-reader-dir.
	* gdb/configure: Re-generated by autoconf.
	* gdb/jit.c: New static variable: const char *jit_reader_dir.
	(_initialize_jit): Relocate jit_reader_dir.
---
 gdb/ChangeLog    |    9 +++++++++
 gdb/config.in    |    6 ++++++
 gdb/configure    |   51 +++++++++++++++++++++++++++++++++++++++++++++++++++
 gdb/configure.ac |    4 ++++
 gdb/jit.c        |    4 ++++
 5 files changed, 74 insertions(+), 0 deletions(-)

diff --git a/gdb/ChangeLog b/gdb/ChangeLog
index ff9b8af..3196016 100644
--- a/gdb/ChangeLog
+++ b/gdb/ChangeLog
@@ -1,5 +1,14 @@
 2011-08-27  Sanjoy Das  <sdas@igalia.com>
 
+	* gdb/config.in: Add new #defines: JIT_READER_DIR and
+	JIT_READER_DIR_RELOCATABLE.
+	* gdb/configure.ac: New GDB directory entry for jit-reader-dir.
+	* gdb/configure: Re-generated by autoconf.
+	* gdb/jit.c: New static variable: const char *jit_reader_dir.
+	(_initialize_jit): Relocate jit_reader_dir.
+
+2011-08-27  Sanjoy Das  <sdas@igalia.com>
+
 	* gdb/Makefile.in: Add jit-reader.h as a header.  Have it
 	installed in $(includedir)/gdb.
 	* gdb/configure.ac: Genereate a correct value for TARGET_PTR for
diff --git a/gdb/config.in b/gdb/config.in
index c1d7c68..b1aef82 100644
--- a/gdb/config.in
+++ b/gdb/config.in
@@ -982,3 +982,9 @@
 
 /* Define as `fork' if `vfork' does not work. */
 #undef vfork
+
+/* The directory from which JIT readers should be loaded. */
+#undef JIT_READER_DIR
+
+/* Define if JIT_READER_DIR should be relocated when GDB is moved. */
+#undef JIT_READER_DIR_RELOCATABLE
diff --git a/gdb/configure b/gdb/configure
index 31469f2..c6dfbf7 100755
--- a/gdb/configure
+++ b/gdb/configure
@@ -666,6 +666,7 @@ python_prog_path
 LTLIBEXPAT
 LIBEXPAT
 HAVE_LIBEXPAT
+JIT_READER_DIR
 TARGET_PTR
 READLINE_TEXI_INCFLAG
 READLINE_CFLAGS
@@ -964,6 +965,7 @@ with_zlib
 with_libiconv_prefix
 with_iconv_bin
 with_system_readline
+with_jit_reader_dir
 with_expat
 with_gnu_ld
 enable_rpath
@@ -1664,6 +1666,8 @@ Optional Packages:
                           search for libiconv in DIR/include and DIR/lib
   --with-iconv-bin=PATH   specify where to find the iconv program
   --with-system-readline  use installed readline library
+  --with-jit-reader-dir=PATH
+                          directory to load the JIT readers from
   --with-expat            include expat support (auto/yes/no)
   --with-gnu-ld           assume the C compiler uses GNU ld default=no
   --with-libexpat-prefix[=DIR]  search for libexpat in DIR/include and DIR/lib
@@ -9931,6 +9935,53 @@ ac_config_files="$ac_config_files jit-reader.h:jit-reader.in"
 
 
 
+
+# Check whether --with-jit-reader-dir was given.
+if test "${with_jit_reader_dir+set}" = set; then :
+  withval=$with_jit_reader_dir;
+    JIT_READER_DIR=$withval
+else
+  JIT_READER_DIR=${libdir}/gdb
+fi
+
+
+  test "x$prefix" = xNONE && prefix="$ac_default_prefix"
+  test "x$exec_prefix" = xNONE && exec_prefix='${prefix}'
+  ac_define_dir=`eval echo $JIT_READER_DIR`
+  ac_define_dir=`eval echo $ac_define_dir`
+
+cat >>confdefs.h <<_ACEOF
+#define JIT_READER_DIR "$ac_define_dir"
+_ACEOF
+
+
+
+
+  if test "x$exec_prefix" = xNONE || test "x$exec_prefix" = 'x${prefix}'; then
+     if test "x$prefix" = xNONE; then
+     	test_prefix=/usr/local
+     else
+	test_prefix=$prefix
+     fi
+  else
+     test_prefix=$exec_prefix
+  fi
+  value=0
+  case ${ac_define_dir} in
+     "${test_prefix}"|"${test_prefix}/"*|\
+	'${exec_prefix}'|'${exec_prefix}/'*)
+     value=1
+     ;;
+  esac
+
+cat >>confdefs.h <<_ACEOF
+#define JIT_READER_DIR_RELOCATABLE $value
+_ACEOF
+
+
+
+
+
 # Check whether --with-expat was given.
 if test "${with_expat+set}" = set; then :
   withval=$with_expat;
diff --git a/gdb/configure.ac b/gdb/configure.ac
index abeb251..ee73e9b 100644
--- a/gdb/configure.ac
+++ b/gdb/configure.ac
@@ -595,6 +595,10 @@ fi
 AC_SUBST(TARGET_PTR)
 AC_CONFIG_FILES([jit-reader.h:jit-reader.in])
 
+GDB_AC_WITH_DIR([JIT_READER_DIR], [jit-reader-dir],
+                [directory to load the JIT readers from],
+                [${libdir}/gdb])
+
 AC_ARG_WITH(expat,
   AS_HELP_STRING([--with-expat], [include expat support (auto/yes/no)]),
   [], [with_expat=auto])
diff --git a/gdb/jit.c b/gdb/jit.c
index e3bb81a..cab27a9 100644
--- a/gdb/jit.c
+++ b/gdb/jit.c
@@ -33,6 +33,8 @@
 #include "target.h"
 #include "gdb_stat.h"
 
+static const char *jit_reader_dir = NULL;
+
 static const struct objfile_data *jit_objfile_data;
 
 static const char *const jit_break_name = "__jit_debug_register_code";
@@ -548,6 +550,8 @@ extern void _initialize_jit (void);
 void
 _initialize_jit (void)
 {
+  jit_reader_dir = relocate_gdb_directory (JIT_READER_DIR,
+                                           JIT_READER_DIR_RELOCATABLE);
   add_setshow_zinteger_cmd ("jit", class_maintenance, &jit_debug,
 			    _("Set JIT debugging."),
 			    _("Show JIT debugging."),
-- 
1.7.5.4


^ permalink raw reply	[flat|nested] 29+ messages in thread

* Re: [PATCH 5/7] Use the loaded reader.
  2011-08-27 13:08 ` [PATCH 5/7] Use the loaded reader Sanjoy Das
@ 2011-08-27 13:47   ` Abhijit Halder
  2011-08-27 14:18     ` Abhijit Halder
  0 siblings, 1 reply; 29+ messages in thread
From: Abhijit Halder @ 2011-08-27 13:47 UTC (permalink / raw)
  To: Sanjoy Das; +Cc: gdb-patches

On Sat, Aug 27, 2011 at 6:42 PM, Sanjoy Das
<sanjoy@playingwithpointers.com> wrote:
> Invoke the loaded JIT debug info reader to parse the registered symbol
> files.
>
> gdb/ChangeLog:
>        * gdb/jit.c: Include block.h, dictionary.h and frame-unwind.h.
>        (add_objfile_entry, jit_target_read_impl, jit_object_open_impl)
>        (jit_symtab_open_impl, compare_block, jit_block_open_impl)
>        (jit_symtab_line_mapping_add_impl, jit_symtab_close_impl)
>        (finalize_symtab, jit_object_close_impl)
>        (jit_reader_try_read_symtab, jit_bfd_try_read_symtab)
>        (free_objfile_data): New functions.
>        (_initialize_jit): Register jit_objfile_data with a proper cleanup
>        function.
> ---
>  gdb/ChangeLog |   12 ++
>  gdb/jit.c     |  479 ++++++++++++++++++++++++++++++++++++++++++++++++++++++---
>  2 files changed, 468 insertions(+), 23 deletions(-)
>
> diff --git a/gdb/ChangeLog b/gdb/ChangeLog
> index 78076ef..7cdde7b 100644
> --- a/gdb/ChangeLog
> +++ b/gdb/ChangeLog
> @@ -1,5 +1,17 @@
>  2011-08-27  Sanjoy Das  <sdas@igalia.com>
>
> +       * gdb/jit.c: Include block.h, dictionary.h and frame-unwind.h.
> +       (add_objfile_entry, jit_target_read_impl, jit_object_open_impl)
> +       (jit_symtab_open_impl, compare_block, jit_block_open_impl)
> +       (jit_symtab_line_mapping_add_impl, jit_symtab_close_impl)
> +       (finalize_symtab, jit_object_close_impl)
> +       (jit_reader_try_read_symtab, jit_bfd_try_read_symtab)
> +       (free_objfile_data): New functions.
> +       (_initialize_jit): Register jit_objfile_data with a proper cleanup
> +       function.
> +
> +2011-08-27  Sanjoy Das  <sdas@igalia.com>
> +
>        * gdb/jit.c: Include gdb-dlfcn.h.
>        (loaded_jit_reader, reader_init_fn_sym): New static variables.
>        (jit_reader_load, jit_reader_load_command)
> diff --git a/gdb/jit.c b/gdb/jit.c
> index 4fc5819..3be8c4d 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"
> @@ -233,6 +236,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.  */
>
> @@ -329,30 +344,417 @@ 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. */
Should be two spaces after period. I am not sure but I think inside
structure there should not be any empty new-line between the comment
and the definition of member variable. Please correct me if I am
wrong.

> +
> +  struct gdb_block *next, *parent;
Please put a comment here.
> +  struct block *real_block;
> +
> +  /* The first and last code address corresponding to this block */
Missing trailing period and there should be two spaces after the period.

> +
> +  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;
> +};
Is there any reason not making it a typedef (also the above one)? I
mean to say something like this:
typedef CORE_ADDR jit_dbg_reader_data;
typedef struct gdb_symtab *gdb_object;
The advantage we may achieve is in saving two level of indirection.

> +
> +/* 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);
> @@ -395,12 +797,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
> @@ -635,6 +1059,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);
> @@ -655,7 +1087,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 ("jit-reader-load", no_class, jit_reader_load_command, _("\
> --
> 1.7.5.4
>
>


^ permalink raw reply	[flat|nested] 29+ messages in thread

* Re: [PATCH 5/7] Use the loaded reader.
  2011-08-27 13:47   ` Abhijit Halder
@ 2011-08-27 14:18     ` Abhijit Halder
  0 siblings, 0 replies; 29+ messages in thread
From: Abhijit Halder @ 2011-08-27 14:18 UTC (permalink / raw)
  To: Sanjoy Das; +Cc: gdb-patches

On Sat, Aug 27, 2011 at 7:17 PM, Abhijit Halder
<abhijit.k.halder@gmail.com> wrote:
> On Sat, Aug 27, 2011 at 6:42 PM, Sanjoy Das
> <sanjoy@playingwithpointers.com> wrote:
>> Invoke the loaded JIT debug info reader to parse the registered symbol
>> files.
>>
>> gdb/ChangeLog:
>>        * gdb/jit.c: Include block.h, dictionary.h and frame-unwind.h.
>>        (add_objfile_entry, jit_target_read_impl, jit_object_open_impl)
>>        (jit_symtab_open_impl, compare_block, jit_block_open_impl)
>>        (jit_symtab_line_mapping_add_impl, jit_symtab_close_impl)
>>        (finalize_symtab, jit_object_close_impl)
>>        (jit_reader_try_read_symtab, jit_bfd_try_read_symtab)
>>        (free_objfile_data): New functions.
>>        (_initialize_jit): Register jit_objfile_data with a proper cleanup
>>        function.
>> ---
>>  gdb/ChangeLog |   12 ++
>>  gdb/jit.c     |  479 ++++++++++++++++++++++++++++++++++++++++++++++++++++++---
>>  2 files changed, 468 insertions(+), 23 deletions(-)
>>
>> diff --git a/gdb/ChangeLog b/gdb/ChangeLog
>> index 78076ef..7cdde7b 100644
>> --- a/gdb/ChangeLog
>> +++ b/gdb/ChangeLog
>> @@ -1,5 +1,17 @@
>>  2011-08-27  Sanjoy Das  <sdas@igalia.com>
>>
>> +       * gdb/jit.c: Include block.h, dictionary.h and frame-unwind.h.
>> +       (add_objfile_entry, jit_target_read_impl, jit_object_open_impl)
>> +       (jit_symtab_open_impl, compare_block, jit_block_open_impl)
>> +       (jit_symtab_line_mapping_add_impl, jit_symtab_close_impl)
>> +       (finalize_symtab, jit_object_close_impl)
>> +       (jit_reader_try_read_symtab, jit_bfd_try_read_symtab)
>> +       (free_objfile_data): New functions.
>> +       (_initialize_jit): Register jit_objfile_data with a proper cleanup
>> +       function.
>> +
>> +2011-08-27  Sanjoy Das  <sdas@igalia.com>
>> +
>>        * gdb/jit.c: Include gdb-dlfcn.h.
>>        (loaded_jit_reader, reader_init_fn_sym): New static variables.
>>        (jit_reader_load, jit_reader_load_command)
>> diff --git a/gdb/jit.c b/gdb/jit.c
>> index 4fc5819..3be8c4d 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"
>> @@ -233,6 +236,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.  */
>>
>> @@ -329,30 +344,417 @@ 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. */
> Should be two spaces after period. I am not sure but I think inside
> structure there should not be any empty new-line between the comment
> and the definition of member variable. Please correct me if I am
> wrong.
>
>> +
>> +  struct gdb_block *next, *parent;
> Please put a comment here.
>> +  struct block *real_block;
>> +
>> +  /* The first and last code address corresponding to this block */
> Missing trailing period and there should be two spaces after the period.
>
>> +
>> +  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;
>> +};
> Is there any reason not making it a typedef (also the above one)? I
> mean to say something like this:
> typedef CORE_ADDR jit_dbg_reader_data;
> typedef struct gdb_symtab *gdb_object;
> The advantage we may achieve is in saving two level of indirection.
>
>> +
>> +/* 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)
I am not clear on why we are passing struct gdb_symbol_callbacks * as
an argument even when we are not using it inside function.

>> +{
>> +  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)
I am not able to see the use of struct gdb_symbol_callbacks *cb inside
the function.

>> +{
>> +  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)
I think this should be
+static int
+compare_block (const struct gdb_block *const old, const struct
gdb_block *const 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)
>> +{
>> +}
Do we need at all this definition?

>> +
>> +/* 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 */
I am not sure whether this way of putting comment is allowed under GNU style.

>> +
>> +  /* 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);
>> @@ -395,12 +797,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
>> @@ -635,6 +1059,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);
>> @@ -655,7 +1087,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 ("jit-reader-load", no_class, jit_reader_load_command, _("\
>> --
>> 1.7.5.4
>>
>>
>


^ permalink raw reply	[flat|nested] 29+ messages in thread

* Re: [PATCH 4/7] New commands for loading and unloading a reader.
  2011-08-27 13:08 ` [PATCH 4/7] New commands for loading and unloading a reader Sanjoy Das
@ 2011-08-27 14:51   ` Abhijit Halder
  0 siblings, 0 replies; 29+ messages in thread
From: Abhijit Halder @ 2011-08-27 14:51 UTC (permalink / raw)
  To: Sanjoy Das; +Cc: gdb-patches

On Sat, Aug 27, 2011 at 6:42 PM, Sanjoy Das
<sanjoy@playingwithpointers.com> wrote:
> Introduces two new GDB commands - `load-jit-reader' and
> `unload-jit-reader'.
>
> gdb/ChangeLog:
>        * gdb/jit.c: Include gdb-dlfcn.h.
>        (loaded_jit_reader, reader_init_fn_sym): New static variables.
>        (jit_reader_load, jit_reader_load_command)
>        (jit_reader_unload_command): New functions.
>        (_initialize_jit): Add commands "jit-reader-load" and
>        "jit-reader-unload".
> ---
>  gdb/ChangeLog |    9 +++++
>  gdb/jit.c     |  103 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++
>  2 files changed, 112 insertions(+), 0 deletions(-)
>
> diff --git a/gdb/ChangeLog b/gdb/ChangeLog
> index 3536807..78076ef 100644
> --- a/gdb/ChangeLog
> +++ b/gdb/ChangeLog
> @@ -1,5 +1,14 @@
>  2011-08-27  Sanjoy Das  <sdas@igalia.com>
>
> +       * gdb/jit.c: Include gdb-dlfcn.h.
> +       (loaded_jit_reader, reader_init_fn_sym): New static variables.
> +       (jit_reader_load, jit_reader_load_command)
> +       (jit_reader_unload_command): New functions.
> +       (_initialize_jit): Add commands "jit-reader-load" and
> +       "jit-reader-unload".
> +
> +2011-08-27  Sanjoy Das  <sdas@igalia.com>
> +
>        * gdb/Makefile.in: Add gdb-dlfcn.c and gdb-dlfcn.h to build
>        system.
>        * gdb/config.in: Add new #define HAVE_LIBDL.
> diff --git a/gdb/jit.c b/gdb/jit.c
> index cab27a9..4fc5819 100644
> --- a/gdb/jit.c
> +++ b/gdb/jit.c
> @@ -31,6 +31,7 @@
>  #include "symfile.h"
>  #include "symtab.h"
>  #include "target.h"
> +#include "gdb-dlfcn.h"
>  #include "gdb_stat.h"
>
>  static const char *jit_reader_dir = NULL;
> @@ -115,6 +116,97 @@ 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. */
> +
> +static struct jit_reader
> +{
> +  struct gdb_reader_funcs *functions;
> +} *loaded_jit_reader = NULL;
> +
> +typedef struct gdb_reader_funcs * (reader_init_fn_type) (void);
> +static const char *reader_init_fn_sym = "gdb_init_reader";
> +
> +/* Try to load FILE_NAME as a JIT debug info reader. */
> +
> +static struct jit_reader *
> +jit_reader_load (const char *file_name)
> +{
> +  void *so;
> +  reader_init_fn_type *init_fn;
> +  struct jit_reader *new_reader = NULL;
> +  struct gdb_reader_funcs *funcs = NULL;
> +  struct cleanup *old_cleanups;
> +
> +  if (jit_debug)
> +    fprintf_unfiltered (gdb_stdlog, _("Opening shared object %s.\n"),
> +                        file_name);
> +  so = gdb_dlopen (file_name);
> +  old_cleanups = make_cleanup_dlclose (so);
> +
> +  init_fn = gdb_dlsym (so, reader_init_fn_sym);
> +  if (!init_fn)
> +    error(_("Could not locate initialization function: %s."),
> +          reader_init_fn_sym);
> +
> +  if (gdb_dlsym (so, "plugin_is_GPL_compatible") == NULL)
> +    error(_("Reader not GPL compatible."));
> +
> +  funcs = init_fn ();
> +  if (funcs->reader_version != GDB_READER_INTERFACE_VERSION)
> +    error(_("Reader version does not match GDB version."));
> +
> +  new_reader = XZALLOC (struct jit_reader);
> +  new_reader->functions = funcs;
> +
> +  discard_cleanups (old_cleanups);
> +  return new_reader;
> +}
> +
> +/* Provides the jit-reader-load command. */
> +
> +static void
> +jit_reader_load_command (char *args, int from_tty)
> +{
> +  char so_name[PATH_MAX];
> +  int len;
> +
> +  if (args == NULL)
> +    {
> +      error (_("No reader name provided."));
> +      return;
This return statement is of no use.

> +    }
> +
> +  if (loaded_jit_reader != NULL)
> +    {
> +      error (_("JIT reader already loaded.  Run jit-reader-unload first."));
> +      return;
Same here.

> +    }
> +
> +  len = strlen (jit_reader_dir);
> +  strcpy(so_name, jit_reader_dir);
> +  so_name[len] = '/';
> +  so_name[len + 1] = 0;
> +
> +  strncat (so_name, args, PATH_MAX - (len + 1));
Why can't you use snprintf instead of all the above functions as below?
snprintf (so_name, sizeof (so_name), "%s/%s", jit_reader_dir, args);

> +  loaded_jit_reader = jit_reader_load (so_name);
> +}
> +
> +/* Provides the jit-reader-unload command. */
> +
> +static void
> +jit_reader_unload_command (char *args, int from_tty)
> +{
> +  if (!loaded_jit_reader)
> +    {
> +      error(_("No JIT reader loaded."));
> +      return;
return statement of no use.

> +    }
> +  loaded_jit_reader->functions->destroy (loaded_jit_reader->functions);
> +  free (loaded_jit_reader);
Should be xfree instead of free.

> +  loaded_jit_reader = NULL;
> +}
> +
>  /* Open a BFD from the target's memory.  */
>
>  static struct bfd *
> @@ -566,4 +658,15 @@ _initialize_jit (void)
>   jit_objfile_data = register_objfile_data ();
>   jit_inferior_data =
>     register_inferior_data_with_cleanup (jit_inferior_data_cleanup);
> +  add_com ("jit-reader-load", no_class, jit_reader_load_command, _("\
> +Load FILE as debug info reader and unwinder for JIT compiled code.\n\
> +Try to load file FILE as a debug info reader (and unwinder) for\n\
> +JIT compiled code. The file is loaded from\n\
> +" JIT_READER_DIR ", relocated \n\
> +relative to the GDB executable if required.\n\
> +Usage is `jit-reader-load FILE`."));
> +  add_com ("jit-reader-unload", no_class, jit_reader_unload_command, _("\
> +Unload the currently loaded JIT debug info reader.\n\
> +See jit-reader-load for how to load JIT debug readers.\n\
> +"));
>  }
> --
> 1.7.5.4
>
>


^ permalink raw reply	[flat|nested] 29+ messages in thread

* Re: [PATCH 6/7] New JIT unwinder.
  2011-08-27 13:08 ` [PATCH 6/7] New JIT unwinder Sanjoy Das
@ 2011-08-28  2:17   ` Sergio Durigan Junior
       [not found]   ` <1314518609-10204-1-git-send-email-sanjoy@playingwithpointers.com>
  1 sibling, 0 replies; 29+ messages in thread
From: Sergio Durigan Junior @ 2011-08-28  2:17 UTC (permalink / raw)
  To: Sanjoy Das; +Cc: gdb-patches

Hi Sanjoy,

Thanks for the work.  There are a few nits.

Sanjoy Das <sanjoy@playingwithpointers.com> writes:

> diff --git a/gdb/jit.c b/gdb/jit.c
> index 3be8c4d..fa25908 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. */

All over the code, you should put two spaces after a dot or a period.
Please fix that.

> +/* 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);
> +}

Sorry, I don't think this function is needed.  All it does is to call
`xfree'.  You should be able to call `xfree' directly when needed.

Thanks,

Sergio.


^ permalink raw reply	[flat|nested] 29+ messages in thread

* [PATCH 4/7] New commands for loading and unloading a reader.
       [not found]   ` <1314518609-10204-1-git-send-email-sanjoy@playingwithpointers.com>
                       ` (2 preceding siblings ...)
  2011-08-28  8:04     ` [PATCH 3/7] Platform agnostic dynamic loading code Sanjoy Das
@ 2011-08-28  8:04     ` Sanjoy Das
  2011-08-30 18:52       ` Tom Tromey
  2011-08-28  8:04     ` [PATCH 6/7] New JIT unwinder Sanjoy Das
                       ` (2 subsequent siblings)
  6 siblings, 1 reply; 29+ messages in thread
From: Sanjoy Das @ 2011-08-28  8:04 UTC (permalink / raw)
  To: gdb-patches; +Cc: Sanjoy Das

Introduces two new GDB commands - `load-jit-reader' and
`unload-jit-reader'.

gdb/ChangeLog:
	* gdb/jit.c: Include gdb-dlfcn.h.
	(loaded_jit_reader, reader_init_fn_sym): New static variables.
	(jit_reader_load, jit_reader_load_command)
	(jit_reader_unload_command): New functions.
	(_initialize_jit): Add commands "jit-reader-load" and
	"jit-reader-unload".
---
 gdb/ChangeLog |    9 ++++++
 gdb/jit.c     |   90 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++
 2 files changed, 99 insertions(+), 0 deletions(-)

diff --git a/gdb/ChangeLog b/gdb/ChangeLog
index 3536807..78076ef 100644
--- a/gdb/ChangeLog
+++ b/gdb/ChangeLog
@@ -1,5 +1,14 @@
 2011-08-27  Sanjoy Das  <sdas@igalia.com>
 
+	* gdb/jit.c: Include gdb-dlfcn.h.
+	(loaded_jit_reader, reader_init_fn_sym): New static variables.
+	(jit_reader_load, jit_reader_load_command)
+	(jit_reader_unload_command): New functions.
+	(_initialize_jit): Add commands "jit-reader-load" and
+	"jit-reader-unload".
+
+2011-08-27  Sanjoy Das  <sdas@igalia.com>
+
 	* gdb/Makefile.in: Add gdb-dlfcn.c and gdb-dlfcn.h to build
 	system.
 	* gdb/config.in: Add new #define HAVE_LIBDL.
diff --git a/gdb/jit.c b/gdb/jit.c
index cab27a9..a180621 100644
--- a/gdb/jit.c
+++ b/gdb/jit.c
@@ -31,6 +31,7 @@
 #include "symfile.h"
 #include "symtab.h"
 #include "target.h"
+#include "gdb-dlfcn.h"
 #include "gdb_stat.h"
 
 static const char *jit_reader_dir = NULL;
@@ -115,6 +116,84 @@ 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.  */
+
+static struct jit_reader
+{
+  struct gdb_reader_funcs *functions;
+} *loaded_jit_reader = NULL;
+
+typedef struct gdb_reader_funcs * (reader_init_fn_type) (void);
+static const char *reader_init_fn_sym = "gdb_init_reader";
+
+/* Try to load FILE_NAME as a JIT debug info reader.  */
+
+static struct jit_reader *
+jit_reader_load (const char *file_name)
+{
+  void *so;
+  reader_init_fn_type *init_fn;
+  struct jit_reader *new_reader = NULL;
+  struct gdb_reader_funcs *funcs = NULL;
+  struct cleanup *old_cleanups;
+
+  if (jit_debug)
+    fprintf_unfiltered (gdb_stdlog, _("Opening shared object %s.\n"),
+                        file_name);
+  so = gdb_dlopen (file_name);
+  old_cleanups = make_cleanup_dlclose (so);
+
+  init_fn = gdb_dlsym (so, reader_init_fn_sym);
+  if (!init_fn)
+    error (_("Could not locate initialization function: %s."),
+          reader_init_fn_sym);
+
+  if (gdb_dlsym (so, "plugin_is_GPL_compatible") == NULL)
+    error (_("Reader not GPL compatible."));
+
+  funcs = init_fn ();
+  if (funcs->reader_version != GDB_READER_INTERFACE_VERSION)
+    error (_("Reader version does not match GDB version."));
+
+  new_reader = XZALLOC (struct jit_reader);
+  new_reader->functions = funcs;
+
+  discard_cleanups (old_cleanups);
+  return new_reader;
+}
+
+/* Provides the jit-reader-load command.  */
+
+static void
+jit_reader_load_command (char *args, int from_tty)
+{
+  char so_name[PATH_MAX];
+  int len;
+
+  if (args == NULL)
+    error (_("No reader name provided."));
+
+  if (loaded_jit_reader != NULL)
+    error (_("JIT reader already loaded.  Run jit-reader-unload first."));
+
+  snprintf (so_name, PATH_MAX, "%s/%s", jit_reader_dir, args);
+  loaded_jit_reader = jit_reader_load (so_name);
+}
+
+/* Provides the jit-reader-unload command.  */
+
+static void
+jit_reader_unload_command (char *args, int from_tty)
+{
+  if (!loaded_jit_reader)
+    error (_("No JIT reader loaded."));
+
+  loaded_jit_reader->functions->destroy (loaded_jit_reader->functions);
+  xfree (loaded_jit_reader);
+  loaded_jit_reader = NULL;
+}
+
 /* Open a BFD from the target's memory.  */
 
 static struct bfd *
@@ -566,4 +645,15 @@ _initialize_jit (void)
   jit_objfile_data = register_objfile_data ();
   jit_inferior_data =
     register_inferior_data_with_cleanup (jit_inferior_data_cleanup);
+  add_com ("jit-reader-load", no_class, jit_reader_load_command, _("\
+Load FILE as debug info reader and unwinder for JIT compiled code.\n\
+Try to load file FILE as a debug info reader (and unwinder) for\n\
+JIT compiled code.  The file is loaded from\n\
+" JIT_READER_DIR ", relocated \n\
+relative to the GDB executable if required.\n\
+Usage is `jit-reader-load FILE`."));
+  add_com ("jit-reader-unload", no_class, jit_reader_unload_command, _("\
+Unload the currently loaded JIT debug info reader.\n\
+See jit-reader-load for how to load JIT debug readers.\n\
+"));
 }
-- 
1.7.5.4


^ permalink raw reply	[flat|nested] 29+ messages in thread

* [PATCH 5/7] Use the loaded reader.
       [not found]   ` <1314518609-10204-1-git-send-email-sanjoy@playingwithpointers.com>
@ 2011-08-28  8:04     ` Sanjoy Das
  2011-08-30 19:18       ` Tom Tromey
  2011-08-28  8:04     ` [PATCH 7/7] Documentation Sanjoy Das
                       ` (5 subsequent siblings)
  6 siblings, 1 reply; 29+ messages in thread
From: Sanjoy Das @ 2011-08-28  8:04 UTC (permalink / raw)
  To: gdb-patches; +Cc: Sanjoy Das

Invoke the loaded JIT debug info reader to parse the registered symbol
files.

gdb/ChangeLog:
	* gdb/jit.c: Include block.h, dictionary.h and frame-unwind.h.
	(add_objfile_entry, jit_target_read_impl, jit_object_open_impl)
	(jit_symtab_open_impl, compare_block, jit_block_open_impl)
	(jit_symtab_line_mapping_add_impl, jit_symtab_close_impl)
	(finalize_symtab, jit_object_close_impl)
	(jit_reader_try_read_symtab, jit_bfd_try_read_symtab)
	(free_objfile_data): New functions.
	(_initialize_jit): Register jit_objfile_data with a proper cleanup
	function.
---
 gdb/ChangeLog |   12 ++
 gdb/jit.c     |  485 ++++++++++++++++++++++++++++++++++++++++++++++++++++++---
 2 files changed, 474 insertions(+), 23 deletions(-)

diff --git a/gdb/ChangeLog b/gdb/ChangeLog
index 78076ef..7cdde7b 100644
--- a/gdb/ChangeLog
+++ b/gdb/ChangeLog
@@ -1,5 +1,17 @@
 2011-08-27  Sanjoy Das  <sdas@igalia.com>
 
+	* gdb/jit.c: Include block.h, dictionary.h and frame-unwind.h.
+	(add_objfile_entry, jit_target_read_impl, jit_object_open_impl)
+	(jit_symtab_open_impl, compare_block, jit_block_open_impl)
+	(jit_symtab_line_mapping_add_impl, jit_symtab_close_impl)
+	(finalize_symtab, jit_object_close_impl)
+	(jit_reader_try_read_symtab, jit_bfd_try_read_symtab)
+	(free_objfile_data): New functions.
+	(_initialize_jit): Register jit_objfile_data with a proper cleanup
+	function.
+
+2011-08-27  Sanjoy Das  <sdas@igalia.com>
+
 	* gdb/jit.c: Include gdb-dlfcn.h.
 	(loaded_jit_reader, reader_init_fn_sym): New static variables.
 	(jit_reader_load, jit_reader_load_command)
diff --git a/gdb/jit.c b/gdb/jit.c
index a180621..846d0b8 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"
@@ -220,6 +223,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.  */
 
@@ -316,30 +331,423 @@ 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;
+
+  /* Points to the "real" block that is being built out of this
+     instance.  This block will be added to a blockvector, which will
+     then be added to a symtab.  */
+  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.  */
+
+typedef CORE_ADDR jit_dbg_reader_data;
+
+/* 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)
+{
+  /* CB is not required right now, but sometime in the future we might
+     need a handle to it, and we'd like to do that without breaking
+     the ABI.  */
+  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;
+
+  /* CB stays unused.  See comment in jit_object_open_impl.  */
+
+  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 (const struct gdb_block *const old,
+               const struct gdb_block *const 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)
+{
+  /* Right now nothing needs to be done here.  We may need to do some
+     cleanup here in the future (again, without breaking the plugin
+     ABI).  */
+}
+
+/* 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);
+  /* JIT compilers compile in memory.  */
+  symtab->dirname = NULL;
+
+  /* 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;
+  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);
+  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;
+  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 = 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);
@@ -382,12 +790,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
@@ -622,6 +1052,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);
@@ -642,7 +1080,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 ("jit-reader-load", no_class, jit_reader_load_command, _("\
-- 
1.7.5.4


^ permalink raw reply	[flat|nested] 29+ messages in thread

* [PATCH 7/7] Documentation.
       [not found]   ` <1314518609-10204-1-git-send-email-sanjoy@playingwithpointers.com>
  2011-08-28  8:04     ` [PATCH 5/7] Use the loaded reader Sanjoy Das
@ 2011-08-28  8:04     ` Sanjoy Das
  2011-08-30 19:43       ` Tom Tromey
  2011-08-28  8:04     ` [PATCH 3/7] Platform agnostic dynamic loading code Sanjoy Das
                       ` (4 subsequent siblings)
  6 siblings, 1 reply; 29+ messages in thread
From: Sanjoy Das @ 2011-08-28  8:04 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/doc/ChangeLog:
	* gdb.texinfo (JIT Interface): Add documentation on writing and
	usind JIT debug info readers.
	(Custom Debug Info, Using JIT Debug Info Readers, Writing JIT
	Debug Info Readers): New nodes.
---
 gdb/doc/ChangeLog   |    7 +++
 gdb/doc/gdb.texinfo |  115 +++++++++++++++++++++++++++++++++++++++++++++++++++
 2 files changed, 122 insertions(+), 0 deletions(-)

diff --git a/gdb/doc/ChangeLog b/gdb/doc/ChangeLog
index 80038f1..190ff75 100644
--- a/gdb/doc/ChangeLog
+++ b/gdb/doc/ChangeLog
@@ -1,3 +1,10 @@
+2011-08-27  Sanjoy Das  <sdas@igalia.com>
+
+	* gdb.texinfo (JIT Interface): Add documentation on writing and
+	usind JIT debug info readers.
+	(Custom Debug Info, Using JIT Debug Info Readers, Writing JIT
+	Debug Info Readers): New nodes.
+
 2011-08-25  Andrew Oakley  <andrew@ado.is-a-geek.net>
 
 	* gdb.texinfo (Types In Python): Document 'bitpos' for enums.
diff --git a/gdb/doc/gdb.texinfo b/gdb/doc/gdb.texinfo
index 23b2a98..0ce01e5 100644
--- a/gdb/doc/gdb.texinfo
+++ b/gdb/doc/gdb.texinfo
@@ -30951,6 +30951,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
@@ -31047,6 +31048,120 @@ 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 source file
+@file{gdb/jit-reader.in}, which is also installed as a header at
+@file{@var{includedir}/gdb/jit-reader.h} for easy inclusion.
+
+The reader is implemented as a shared object.  Two new @value{GDBN}
+commands, @code{load-jit-reader} and @code{unload-jit-reader} are
+provided, 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 JIT Debug Info Readers::       How to use supplied readers correctly
+* Writing JIT Debug Info Readers::     Creating a debug-info reader
+@end menu
+
+@node Using JIT Debug Info Readers
+@subsection Using JIT Debug Info 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
+@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 invoking @code{load-jit-reader}.
+
+@item unload-jit-reader
+
+Unload the currently loaded JIT reader.
+
+@end table
+
+@node Writing JIT Debug Info Readers
+@subsection Writing JIT Debug Info 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] 29+ messages in thread

* [PATCH 6/7] New JIT unwinder.
       [not found]   ` <1314518609-10204-1-git-send-email-sanjoy@playingwithpointers.com>
                       ` (3 preceding siblings ...)
  2011-08-28  8:04     ` [PATCH 4/7] New commands for loading and unloading a reader Sanjoy Das
@ 2011-08-28  8:04     ` Sanjoy Das
  2011-08-30 19:28       ` Tom Tromey
  2011-08-28  8:05     ` [PATCH 2/7] Relocatable directory for loading JIT readers Sanjoy Das
  2011-08-28  8:07     ` [PATCH 1/7] Introduce jit-reader.in and modify build system Sanjoy Das
  6 siblings, 1 reply; 29+ messages in thread
From: Sanjoy Das @ 2011-08-28  8:04 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:
	* gdb/jit.c: Include regcache.h.
	(jit_gdbarch_data, jit_frame_unwind): New static variables.
	(jit_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_prepend_unwinder, jit_gdbarch_data_init): New functions.
	(jit_inferior_init): Prepend (new) pseudo unwinder by calling
	jit_prepend_unwinder.
	(_initialize_jit): Register new gdbarch data jit_gdbarch_data.
---
 gdb/ChangeLog |   13 +++
 gdb/jit.c     |  260 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++
 2 files changed, 273 insertions(+), 0 deletions(-)

diff --git a/gdb/ChangeLog b/gdb/ChangeLog
index 7cdde7b..cb000aa 100644
--- a/gdb/ChangeLog
+++ b/gdb/ChangeLog
@@ -1,5 +1,18 @@
 2011-08-27  Sanjoy Das  <sdas@igalia.com>
 
+	* gdb/jit.c: Include regcache.h.
+	(jit_gdbarch_data, jit_frame_unwind): New static variables.
+	(jit_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_prepend_unwinder, jit_gdbarch_data_init): New functions.
+	(jit_inferior_init): Prepend (new) pseudo unwinder by calling
+	jit_prepend_unwinder.
+	(_initialize_jit): Register new gdbarch data jit_gdbarch_data.
+
+2011-08-27  Sanjoy Das  <sdas@igalia.com>
+
 	* gdb/jit.c: Include block.h, dictionary.h and frame-unwind.h.
 	(add_objfile_entry, jit_target_read_impl, jit_object_open_impl)
 	(jit_symtab_open_impl, compare_block, jit_block_open_impl)
diff --git a/gdb/jit.c b/gdb/jit.c
index 846d0b8..727cd55 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;
@@ -886,6 +893,243 @@ 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 dwarf_regnum,
+                         struct gdb_reg_value *value)
+{
+  struct jit_unwind_private *priv;
+  int gdb_reg;
+
+  priv = cb->priv_data;
+
+  gdb_reg = gdbarch_dwarf2_reg_to_regnum (get_frame_arch (priv->this_frame),
+                                          dwarf_regnum);
+  if (gdb_reg == -1)
+    {
+      if (jit_debug)
+        fprintf_unfiltered (gdb_stdlog,
+                            _("Could not recognize DWARF regnum %d"),
+                            dwarf_regnum);
+      return;
+    }
+
+  gdb_assert (priv->registers);
+  priv->registers[gdb_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;
+  struct gdbarch *frame_arch;
+
+  priv = cb->priv_data;
+  frame_arch = get_frame_arch (priv->this_frame);
+
+  gdb_reg = gdbarch_dwarf2_reg_to_regnum (frame_arch, regnum);
+  size = register_size (frame_arch, 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 = (void (*) (struct gdb_reg_value *)) xfree;
+  return value;
+}
+
+/* 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;
+  struct gdbarch *frame_arch;
+  int i;
+
+  gdb_assert (priv_data->registers);
+  frame_arch = get_frame_arch (priv_data->this_frame);
+
+  for (i = 0; i < gdbarch_num_regs (frame_arch); 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);
+}
+
+/* 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;
+
+  gdb_assert (!*cache);
+
+  *cache = XZALLOC (struct jit_unwind_private);
+  priv_data = *cache;
+  priv_data->registers =
+    XCALLOC (gdbarch_num_regs (get_frame_arch (this_frame)),
+             struct gdb_reg_value *);
+  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"));
+
+  jit_dealloc_cache (this_frame, *cache);
+  *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 default_frame_unwind_stop_reason (this_frame, cache);
+}
+
+/* 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);
+}
+
+/* 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
@@ -899,6 +1143,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;
@@ -1060,6 +1306,19 @@ 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;
+
+  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);
@@ -1084,6 +1343,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 ("jit-reader-load", no_class, jit_reader_load_command, _("\
 Load FILE as debug info reader and unwinder for JIT compiled code.\n\
 Try to load file FILE as a debug info reader (and unwinder) for\n\
-- 
1.7.5.4


^ permalink raw reply	[flat|nested] 29+ messages in thread

* [PATCH 3/7] Platform agnostic dynamic loading code.
       [not found]   ` <1314518609-10204-1-git-send-email-sanjoy@playingwithpointers.com>
  2011-08-28  8:04     ` [PATCH 5/7] Use the loaded reader Sanjoy Das
  2011-08-28  8:04     ` [PATCH 7/7] Documentation Sanjoy Das
@ 2011-08-28  8:04     ` Sanjoy Das
  2011-08-28  8:04     ` [PATCH 4/7] New commands for loading and unloading a reader Sanjoy Das
                       ` (3 subsequent siblings)
  6 siblings, 0 replies; 29+ messages in thread
From: Sanjoy Das @ 2011-08-28  8:04 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/Makefile.in: Add gdb-dlfcn.c and gdb-dlfcn.h to build
	system.
	* gdb/config.in: Add new #define HAVE_LIBDL.
	* gdb/configure.ac: Add check for -ldl.
	* gdb/configure: Re-generated by autoconf.
---
 gdb/ChangeLog    |    8 ++++
 gdb/Makefile.in  |    6 ++--
 gdb/config.in    |    3 ++
 gdb/configure    |   46 ++++++++++++++++++++++++++
 gdb/configure.ac |    2 +
 gdb/gdb-dlfcn.c  |   95 ++++++++++++++++++++++++++++++++++++++++++++++++++++++
 gdb/gdb-dlfcn.h  |   46 ++++++++++++++++++++++++++
 7 files changed, 203 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 3196016..3536807 100644
--- a/gdb/ChangeLog
+++ b/gdb/ChangeLog
@@ -1,5 +1,13 @@
 2011-08-27  Sanjoy Das  <sdas@igalia.com>
 
+	* gdb/Makefile.in: Add gdb-dlfcn.c and gdb-dlfcn.h to build
+	system.
+	* gdb/config.in: Add new #define HAVE_LIBDL.
+	* gdb/configure.ac: Add check for -ldl.
+	* gdb/configure: Re-generated by autoconf.
+
+2011-08-27  Sanjoy Das  <sdas@igalia.com>
+
 	* gdb/config.in: Add new #defines: JIT_READER_DIR and
 	JIT_READER_DIR_RELOCATABLE.
 	* gdb/configure.ac: New GDB directory entry for jit-reader-dir.
diff --git a/gdb/Makefile.in b/gdb/Makefile.in
index b277597..732b8f0 100644
--- a/gdb/Makefile.in
+++ b/gdb/Makefile.in
@@ -739,7 +739,7 @@ SFILES = ada-exp.y ada-lang.c ada-typeprint.c ada-valprint.c ada-tasks.c \
 	annotate.c common/signals.c copying.c dfp.c gdb.c inf-child.c \
 	regset.c sol-thread.c windows-termcap.c \
 	common/common-utils.c common/xml-utils.c \
-	common/ptid.c common/buffer.c
+	common/ptid.c common/buffer.c gdb-dlfcn.c
 
 LINTFILES = $(SFILES) $(YYFILES) $(CONFIG_SRCS) init.c
 
@@ -820,7 +820,7 @@ solib-darwin.h solib-ia64-hpux.h solib-spu.h windows-nat.h xcoffread.h \
 gnulib/extra/arg-nonnull.h gnulib/extra/c++defs.h gnulib/extra/warn-on-use.h \
 gnulib/stddef.in.h inline-frame.h \
 common/common-utils.h common/xml-utils.h common/buffer.h common/ptid.h \
-common/linux-osdata.h
+common/linux-osdata.h gdb-dlfcn.h
 
 # Header files that already have srcdir in them, or which are in objdir.
 
@@ -907,7 +907,7 @@ COMMON_OBS = $(DEPFILES) $(CONFIG_OBS) $(YYOBJ) \
 	target-descriptions.o target-memory.o xml-tdesc.o xml-builtin.o \
 	inferior.o osdata.o gdb_usleep.o record.o gcore.o \
 	jit.o progspace.o \
-	common-utils.o buffer.o ptid.o
+	common-utils.o buffer.o ptid.o gdb-dlfcn.o
 
 TSOBS = inflow.o
 
diff --git a/gdb/config.in b/gdb/config.in
index 27a4e2c..65945cb 100644
--- a/gdb/config.in
+++ b/gdb/config.in
@@ -988,3 +988,6 @@
 
 /* Define if JIT_READER_DIR should be relocated when GDB is moved.  */
 #undef JIT_READER_DIR_RELOCATABLE
+
+/* Define if -ldl will work.  */
+#undef HAVE_LIBDL
diff --git a/gdb/configure b/gdb/configure
index c6dfbf7..b7753bf 100755
--- a/gdb/configure
+++ b/gdb/configure
@@ -9934,6 +9934,52 @@ fi
 ac_config_files="$ac_config_files jit-reader.h:jit-reader.in"
 
 
+{ $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
+
+
 
 
 # Check whether --with-jit-reader-dir was given.
diff --git a/gdb/configure.ac b/gdb/configure.ac
index ee73e9b..0ce5ac0 100644
--- a/gdb/configure.ac
+++ b/gdb/configure.ac
@@ -595,6 +595,8 @@ fi
 AC_SUBST(TARGET_PTR)
 AC_CONFIG_FILES([jit-reader.h:jit-reader.in])
 
+AC_CHECK_LIB([dl], [dlopen], [], [], [])
+
 GDB_AC_WITH_DIR([JIT_READER_DIR], [jit-reader-dir],
                 [directory to load the JIT readers from],
                 [${libdir}/gdb])
diff --git a/gdb/gdb-dlfcn.c b/gdb/gdb-dlfcn.c
new file mode 100644
index 0000000..34c58d7
--- /dev/null
+++ b/gdb/gdb-dlfcn.c
@@ -0,0 +1,95 @@
+/* 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)
+{
+  void *result;
+#ifdef HAVE_LIBDL
+  result = dlopen (filename, RTLD_NOW);
+#elif __MINGW32__
+  result = (void *) LoadLibrary (filename);
+#endif
+  if (result != NULL)
+    return result;
+
+#ifdef HAVE_LIBDL
+  error (_("Could not load %s: %s"), filename, dlerror());
+#else
+  {
+    LPVOID buffer;
+    DWORD dw;
+
+    dw = GetLastError();
+
+    FormatMessage (FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM |
+                   FORMAT_MESSAGE_IGNORE_INSERTS,
+                   NULL, dw, MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT),
+                   (LPTSTR) &buffer
+                   0, NULL);
+
+    error (_("Could not load %s: %s"), filename, (char *) buffer);
+  }
+#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
+}
+
+static void
+do_dlclose_cleanup (void *handle)
+{
+  gdb_dlclose (handle);
+}
+
+struct cleanup *
+make_cleanup_dlclose (void *handle)
+{
+  return make_cleanup (do_dlclose_cleanup, handle);
+}
diff --git a/gdb/gdb-dlfcn.h b/gdb/gdb-dlfcn.h
new file mode 100644
index 0000000..e87672a
--- /dev/null
+++ b/gdb/gdb-dlfcn.h
@@ -0,0 +1,46 @@
+/* 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
+
+#include "defs.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);
+
+/* Install a cleanup routine which closes the handle HANDLE.  */
+
+struct cleanup *make_cleanup_dlclose (void *handle);
+
+/* 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] 29+ messages in thread

* [PATCH 2/7] Relocatable directory for loading JIT readers.
       [not found]   ` <1314518609-10204-1-git-send-email-sanjoy@playingwithpointers.com>
                       ` (4 preceding siblings ...)
  2011-08-28  8:04     ` [PATCH 6/7] New JIT unwinder Sanjoy Das
@ 2011-08-28  8:05     ` Sanjoy Das
  2011-08-30 18:32       ` Tom Tromey
  2011-08-28  8:07     ` [PATCH 1/7] Introduce jit-reader.in and modify build system Sanjoy Das
  6 siblings, 1 reply; 29+ messages in thread
From: Sanjoy Das @ 2011-08-28  8:05 UTC (permalink / raw)
  To: gdb-patches; +Cc: Sanjoy Das

Add a new directory `jit_reader_dir' to jit.c, which is relocated
during initialization.  The value of the directory can be set by using
--with-jit-reader-dir on configure and defaults to `${libdir}/gdb'.

gdb/ChangeLog:
	* gdb/config.in: Add new #defines: JIT_READER_DIR and
	JIT_READER_DIR_RELOCATABLE.
	* gdb/configure.ac: New GDB directory entry for jit-reader-dir.
	* gdb/configure: Re-generated by autoconf.
	* gdb/jit.c: New static variable: const char *jit_reader_dir.
	(_initialize_jit): Relocate jit_reader_dir.
---
 gdb/ChangeLog    |    9 +++++++++
 gdb/config.in    |    6 ++++++
 gdb/configure    |   51 +++++++++++++++++++++++++++++++++++++++++++++++++++
 gdb/configure.ac |    4 ++++
 gdb/jit.c        |    4 ++++
 5 files changed, 74 insertions(+), 0 deletions(-)

diff --git a/gdb/ChangeLog b/gdb/ChangeLog
index ff9b8af..3196016 100644
--- a/gdb/ChangeLog
+++ b/gdb/ChangeLog
@@ -1,5 +1,14 @@
 2011-08-27  Sanjoy Das  <sdas@igalia.com>
 
+	* gdb/config.in: Add new #defines: JIT_READER_DIR and
+	JIT_READER_DIR_RELOCATABLE.
+	* gdb/configure.ac: New GDB directory entry for jit-reader-dir.
+	* gdb/configure: Re-generated by autoconf.
+	* gdb/jit.c: New static variable: const char *jit_reader_dir.
+	(_initialize_jit): Relocate jit_reader_dir.
+
+2011-08-27  Sanjoy Das  <sdas@igalia.com>
+
 	* gdb/Makefile.in: Add jit-reader.h as a header.  Have it
 	installed in $(includedir)/gdb.
 	* gdb/configure.ac: Genereate a correct value for TARGET_PTR for
diff --git a/gdb/config.in b/gdb/config.in
index c1d7c68..27a4e2c 100644
--- a/gdb/config.in
+++ b/gdb/config.in
@@ -982,3 +982,9 @@
 
 /* Define as `fork' if `vfork' does not work. */
 #undef vfork
+
+/* The directory from which JIT readers should be loaded.  */
+#undef JIT_READER_DIR
+
+/* Define if JIT_READER_DIR should be relocated when GDB is moved.  */
+#undef JIT_READER_DIR_RELOCATABLE
diff --git a/gdb/configure b/gdb/configure
index 31469f2..c6dfbf7 100755
--- a/gdb/configure
+++ b/gdb/configure
@@ -666,6 +666,7 @@ python_prog_path
 LTLIBEXPAT
 LIBEXPAT
 HAVE_LIBEXPAT
+JIT_READER_DIR
 TARGET_PTR
 READLINE_TEXI_INCFLAG
 READLINE_CFLAGS
@@ -964,6 +965,7 @@ with_zlib
 with_libiconv_prefix
 with_iconv_bin
 with_system_readline
+with_jit_reader_dir
 with_expat
 with_gnu_ld
 enable_rpath
@@ -1664,6 +1666,8 @@ Optional Packages:
                           search for libiconv in DIR/include and DIR/lib
   --with-iconv-bin=PATH   specify where to find the iconv program
   --with-system-readline  use installed readline library
+  --with-jit-reader-dir=PATH
+                          directory to load the JIT readers from
   --with-expat            include expat support (auto/yes/no)
   --with-gnu-ld           assume the C compiler uses GNU ld default=no
   --with-libexpat-prefix[=DIR]  search for libexpat in DIR/include and DIR/lib
@@ -9931,6 +9935,53 @@ ac_config_files="$ac_config_files jit-reader.h:jit-reader.in"
 
 
 
+
+# Check whether --with-jit-reader-dir was given.
+if test "${with_jit_reader_dir+set}" = set; then :
+  withval=$with_jit_reader_dir;
+    JIT_READER_DIR=$withval
+else
+  JIT_READER_DIR=${libdir}/gdb
+fi
+
+
+  test "x$prefix" = xNONE && prefix="$ac_default_prefix"
+  test "x$exec_prefix" = xNONE && exec_prefix='${prefix}'
+  ac_define_dir=`eval echo $JIT_READER_DIR`
+  ac_define_dir=`eval echo $ac_define_dir`
+
+cat >>confdefs.h <<_ACEOF
+#define JIT_READER_DIR "$ac_define_dir"
+_ACEOF
+
+
+
+
+  if test "x$exec_prefix" = xNONE || test "x$exec_prefix" = 'x${prefix}'; then
+     if test "x$prefix" = xNONE; then
+     	test_prefix=/usr/local
+     else
+	test_prefix=$prefix
+     fi
+  else
+     test_prefix=$exec_prefix
+  fi
+  value=0
+  case ${ac_define_dir} in
+     "${test_prefix}"|"${test_prefix}/"*|\
+	'${exec_prefix}'|'${exec_prefix}/'*)
+     value=1
+     ;;
+  esac
+
+cat >>confdefs.h <<_ACEOF
+#define JIT_READER_DIR_RELOCATABLE $value
+_ACEOF
+
+
+
+
+
 # Check whether --with-expat was given.
 if test "${with_expat+set}" = set; then :
   withval=$with_expat;
diff --git a/gdb/configure.ac b/gdb/configure.ac
index abeb251..ee73e9b 100644
--- a/gdb/configure.ac
+++ b/gdb/configure.ac
@@ -595,6 +595,10 @@ fi
 AC_SUBST(TARGET_PTR)
 AC_CONFIG_FILES([jit-reader.h:jit-reader.in])
 
+GDB_AC_WITH_DIR([JIT_READER_DIR], [jit-reader-dir],
+                [directory to load the JIT readers from],
+                [${libdir}/gdb])
+
 AC_ARG_WITH(expat,
   AS_HELP_STRING([--with-expat], [include expat support (auto/yes/no)]),
   [], [with_expat=auto])
diff --git a/gdb/jit.c b/gdb/jit.c
index e3bb81a..cab27a9 100644
--- a/gdb/jit.c
+++ b/gdb/jit.c
@@ -33,6 +33,8 @@
 #include "target.h"
 #include "gdb_stat.h"
 
+static const char *jit_reader_dir = NULL;
+
 static const struct objfile_data *jit_objfile_data;
 
 static const char *const jit_break_name = "__jit_debug_register_code";
@@ -548,6 +550,8 @@ extern void _initialize_jit (void);
 void
 _initialize_jit (void)
 {
+  jit_reader_dir = relocate_gdb_directory (JIT_READER_DIR,
+                                           JIT_READER_DIR_RELOCATABLE);
   add_setshow_zinteger_cmd ("jit", class_maintenance, &jit_debug,
 			    _("Set JIT debugging."),
 			    _("Show JIT debugging."),
-- 
1.7.5.4


^ permalink raw reply	[flat|nested] 29+ messages in thread

* [PATCH 1/7] Introduce jit-reader.in and modify build system.
       [not found]   ` <1314518609-10204-1-git-send-email-sanjoy@playingwithpointers.com>
                       ` (5 preceding siblings ...)
  2011-08-28  8:05     ` [PATCH 2/7] Relocatable directory for loading JIT readers Sanjoy Das
@ 2011-08-28  8:07     ` Sanjoy Das
  2011-08-30 18:30       ` Tom Tromey
  6 siblings, 1 reply; 29+ messages in thread
From: Sanjoy Das @ 2011-08-28  8:07 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.

gdb/ChangeLog:
	* gdb/Makefile.in: Add jit-reader.h as a header.  Have it
	installed in $(includedir)/gdb.
	* gdb/configure.ac: Genereate a correct value for TARGET_PTR for
	jit-reader.h.  Tell configure to generate jit-reader.h from
	jit-reader.in.
	* gdb/configure: Re-generated by autoconf.
	* gdb/jit-reader.in: New file.
	* gdb/jit.c: Include jit-reader.h.
---
 gdb/ChangeLog     |   11 ++
 gdb/Makefile.in   |   13 ++-
 gdb/configure     |  124 +++++++++++++++++++
 gdb/configure.ac  |   22 ++++
 gdb/jit-reader.in |  344 +++++++++++++++++++++++++++++++++++++++++++++++++++++
 gdb/jit.c         |    1 +
 6 files changed, 511 insertions(+), 4 deletions(-)
 create mode 100644 gdb/jit-reader.in

diff --git a/gdb/ChangeLog b/gdb/ChangeLog
index e2bd6f6..ff9b8af 100644
--- a/gdb/ChangeLog
+++ b/gdb/ChangeLog
@@ -1,3 +1,14 @@
+2011-08-27  Sanjoy Das  <sdas@igalia.com>
+
+	* gdb/Makefile.in: Add jit-reader.h as a header.  Have it
+	installed in $(includedir)/gdb.
+	* gdb/configure.ac: Genereate a correct value for TARGET_PTR for
+	jit-reader.h.  Tell configure to generate jit-reader.h from
+	jit-reader.in.
+	* gdb/configure: Re-generated by autoconf.
+	* gdb/jit-reader.in: New file.
+	* gdb/jit.c: Include jit-reader.h.
+
 2011-08-26  Jan Kratochvil  <jan.kratochvil@redhat.com>
 
 	* inf-loop.c (inferior_event_handler): Add exception_print in
diff --git a/gdb/Makefile.in b/gdb/Makefile.in
index a3bd1f9..b277597 100644
--- a/gdb/Makefile.in
+++ b/gdb/Makefile.in
@@ -824,7 +824,7 @@ common/linux-osdata.h
 
 # Header files that already have srcdir in them, or which are in objdir.
 
-HFILES_WITH_SRCDIR = ../bfd/bfd.h
+HFILES_WITH_SRCDIR = ../bfd/bfd.h jit-reader.h
 
 
 # GDB "info" files, which should be included in their entirety
@@ -941,7 +941,7 @@ DISTSTUFF = $(YYFILES)
 
 
 # All generated files which can be included by another file.
-generated_files = config.h observer.h observer.inc ada-lex.c \
+generated_files = config.h observer.h observer.inc ada-lex.c jit-reader.h \
 	$(GNULIB_H) $(NAT_GENERATED_FILES)
 
 .c.o:
@@ -1026,7 +1026,9 @@ install-only: $(CONFIG_INSTALL)
 		$(SHELL) $(srcdir)/../mkinstalldirs \
 			$(DESTDIR)$(man1dir) ; \
 		$(INSTALL_DATA) $(srcdir)/gdb.1 \
-			$(DESTDIR)$(man1dir)/$$transformed_name.1
+			$(DESTDIR)$(man1dir)/$$transformed_name.1 ; \
+		$(SHELL) $(srcdir)/../mkinstalldirs $(includedir)/gdb ; \
+		$(INSTALL_DATA) jit-reader.h $(includedir)/gdb/jit-reader.h
 	@$(MAKE) DO=install "DODIRS=$(SUBDIRS)" $(FLAGS_TO_PASS) subdir_do
 .PHONY: install-tui
 install-tui:
@@ -1254,7 +1256,7 @@ distclean: clean
 	rm -f gdbserver/config.status gdbserver/config.log
 	rm -f gdbserver/tm.h gdbserver/xm.h gdbserver/nm.h
 	rm -f gdbserver/Makefile gdbserver/config.cache
-	rm -f nm.h config.status config.h stamp-h .gdbinit
+	rm -f nm.h config.status config.h stamp-h .gdbinit jit-reader.h
 	rm -f y.output yacc.acts yacc.tmp y.tab.h
 	rm -f config.log config.cache
 	rm -f Makefile
@@ -1320,6 +1322,9 @@ data-directory/Makefile: data-directory/Makefile.in config.status @frags@
 	  CONFIG_LINKS= \
 	  $(SHELL) config.status
 
+jit-reader.h: $(srcdir)/jit-reader.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/configure b/gdb/configure
index ac143e4..31469f2 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,128 @@ 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
+
+
+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 +16840,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..abeb251 100644
--- a/gdb/configure.ac
+++ b/gdb/configure.ac
@@ -573,6 +573,28 @@ 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_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..3efe722
--- /dev/null
+++ b/gdb/jit-reader.in
@@ -0,0 +1,344 @@
+/* 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] 29+ messages in thread

* Re: [PATCH 1/7] Introduce jit-reader.in and modify build system.
  2011-08-28  8:07     ` [PATCH 1/7] Introduce jit-reader.in and modify build system Sanjoy Das
@ 2011-08-30 18:30       ` Tom Tromey
  2011-08-31  3:16         ` Sanjoy Das
  0 siblings, 1 reply; 29+ messages in thread
From: Tom Tromey @ 2011-08-30 18:30 UTC (permalink / raw)
  To: Sanjoy Das; +Cc: gdb-patches

>>>>> "Sanjoy" == Sanjoy Das <sanjoy@playingwithpointers.com> writes:

Sanjoy> jit-reader.in will host the interface to be implemented and the API to
Sanjoy> be used by the reader.  The file needs to be processed by ./configure
Sanjoy> to produce `jit.reader.h'; so that GDB_CORE_ADDR is defined correctly.

Thanks for persevering with this patch series.
I think it is an important addition to gdb.

Sanjoy> gdb/ChangeLog:
Sanjoy> 	* gdb/Makefile.in: Add jit-reader.h as a header.  Have it
Sanjoy> 	installed in $(includedir)/gdb.
Sanjoy> 	* gdb/configure.ac: Genereate a correct value for TARGET_PTR for
Sanjoy> 	jit-reader.h.  Tell configure to generate jit-reader.h from
Sanjoy> 	jit-reader.in.
Sanjoy> 	* gdb/configure: Re-generated by autoconf.
Sanjoy> 	* gdb/jit-reader.in: New file.
Sanjoy> 	* gdb/jit.c: Include jit-reader.h.

One final nit from me on this patch.

Sanjoy> +		$(SHELL) $(srcdir)/../mkinstalldirs $(includedir)/gdb ; \
Sanjoy> +		$(INSTALL_DATA) jit-reader.h $(includedir)/gdb/jit-reader.h

This should have $(DESTDIR) in it, see the rest of this rule.

This patch is ok with this change.

I haven't been keeping track of your assignment status.
Has everything gone through?

Tom


^ permalink raw reply	[flat|nested] 29+ messages in thread

* Re: [PATCH 2/7] Relocatable directory for loading JIT readers.
  2011-08-28  8:05     ` [PATCH 2/7] Relocatable directory for loading JIT readers Sanjoy Das
@ 2011-08-30 18:32       ` Tom Tromey
  0 siblings, 0 replies; 29+ messages in thread
From: Tom Tromey @ 2011-08-30 18:32 UTC (permalink / raw)
  To: Sanjoy Das; +Cc: gdb-patches

>>>>> "Sanjoy" == Sanjoy Das <sanjoy@playingwithpointers.com> writes:

Sanjoy> 	* gdb/config.in: Add new #defines: JIT_READER_DIR and
Sanjoy> 	JIT_READER_DIR_RELOCATABLE.
Sanjoy> 	* gdb/configure.ac: New GDB directory entry for jit-reader-dir.
Sanjoy> 	* gdb/configure: Re-generated by autoconf.
Sanjoy> 	* gdb/jit.c: New static variable: const char *jit_reader_dir.
Sanjoy> 	(_initialize_jit): Relocate jit_reader_dir.

Ok.

Tom


^ permalink raw reply	[flat|nested] 29+ messages in thread

* Re: [PATCH 4/7] New commands for loading and unloading a reader.
  2011-08-28  8:04     ` [PATCH 4/7] New commands for loading and unloading a reader Sanjoy Das
@ 2011-08-30 18:52       ` Tom Tromey
  0 siblings, 0 replies; 29+ messages in thread
From: Tom Tromey @ 2011-08-30 18:52 UTC (permalink / raw)
  To: Sanjoy Das; +Cc: gdb-patches

>>>>> "Sanjoy" == Sanjoy Das <sanjoy@playingwithpointers.com> writes:

This patch looks pretty good.

Sanjoy> +static struct jit_reader
Sanjoy> +{
Sanjoy> +  struct gdb_reader_funcs *functions;
Sanjoy> +} *loaded_jit_reader = NULL;

I think this should also have the gdb_dlopen result in it.
In the current patch, jit-reader-unload never calls dlclose, but it
seems to me that it should.

Sanjoy> +  char so_name[PATH_MAX];

Don't use PATH_MAX.

Sanjoy> +  snprintf (so_name, PATH_MAX, "%s/%s", jit_reader_dir, args);

You can use xstrprintf here instead; then make a cleanup to xfree it.

Sanjoy> +  add_com ("jit-reader-load", no_class, jit_reader_load_command, _("\

I think class_obscure is maybe a better fit than no_class.  Though
truthfully I can't claim to understand the class_* breakdown very well.

Tom


^ permalink raw reply	[flat|nested] 29+ messages in thread

* Re: [PATCH 5/7] Use the loaded reader.
  2011-08-28  8:04     ` [PATCH 5/7] Use the loaded reader Sanjoy Das
@ 2011-08-30 19:18       ` Tom Tromey
  0 siblings, 0 replies; 29+ messages in thread
From: Tom Tromey @ 2011-08-30 19:18 UTC (permalink / raw)
  To: Sanjoy Das; +Cc: gdb-patches

>>>>> "Sanjoy" == Sanjoy Das <sanjoy@playingwithpointers.com> writes:

Sanjoy> 	* gdb/jit.c: Include block.h, dictionary.h and frame-unwind.h.
Sanjoy> 	(add_objfile_entry, jit_target_read_impl, jit_object_open_impl)
Sanjoy> 	(jit_symtab_open_impl, compare_block, jit_block_open_impl)
Sanjoy> 	(jit_symtab_line_mapping_add_impl, jit_symtab_close_impl)
Sanjoy> 	(finalize_symtab, jit_object_close_impl)
Sanjoy> 	(jit_reader_try_read_symtab, jit_bfd_try_read_symtab)
Sanjoy> 	(free_objfile_data): New functions.
Sanjoy> 	(_initialize_jit): Register jit_objfile_data with a proper cleanup
Sanjoy> 	function.

Just some minor nits on this one.

Sanjoy> +  for (i = 0; i < nlines; i++)
Sanjoy> +    {
Sanjoy> +      stab->linetable->item [i].pc = (CORE_ADDR) map[i].pc;
Sanjoy> +      stab->linetable->item [i].line = map[i].line;
Sanjoy> +    }

No space before the "[" on those two lines.

Sanjoy> +  for (i = (actual_nblocks - 1), gdb_block_iter = stab->blocks;
Sanjoy> +       i >= FIRST_LOCAL_BLOCK; i--, gdb_block_iter = gdb_block_iter->next)

Once a 'for' header goes to a second line, I like to put each clause on
its own line, since I think that is easier to read.  So, add a newline
after the second ";".

Sanjoy> +  /* Fill up the superblock fields for the real blocks, using the
Sanjoy> +     real_block fields populated earlier.  */
Sanjoy> +  for (gdb_block_iter = stab->blocks; gdb_block_iter;
Sanjoy> +       gdb_block_iter = gdb_block_iter->next)

Likewise.

Sanjoy> +  for (gdb_block_iter = stab->blocks, gdb_block_iter_tmp = gdb_block_iter->next;
Sanjoy> +       gdb_block_iter; gdb_block_iter = gdb_block_iter_tmp)

Likewise.

Sanjoy> +  objfile->msymbols[0].ginfo.name = NULL;
Sanjoy> +  objfile->msymbols[0].ginfo.value.address = 0;

I think it is slightly better to use memset here.

Sanjoy> -  jit_objfile_data = register_objfile_data ();
Sanjoy> +  jit_objfile_data =
Sanjoy> +    register_objfile_data_with_cleanup (NULL,free_objfile_data);

Missing space after the ",".

This is ok with these things fixed.

Tom


^ permalink raw reply	[flat|nested] 29+ messages in thread

* Re: [PATCH 6/7] New JIT unwinder.
  2011-08-28  8:04     ` [PATCH 6/7] New JIT unwinder Sanjoy Das
@ 2011-08-30 19:28       ` Tom Tromey
  0 siblings, 0 replies; 29+ messages in thread
From: Tom Tromey @ 2011-08-30 19:28 UTC (permalink / raw)
  To: Sanjoy Das; +Cc: gdb-patches

>>>>> "Sanjoy" == Sanjoy Das <sanjoy@playingwithpointers.com> writes:

Sanjoy> Introduce a "proxy unwinder", whcih will pass down all calls to the
Sanjoy> functions the JIT reader provides.

Sanjoy> +  value->free = (void (*) (struct gdb_reg_value *)) xfree;

I think either the free function's type should be changed, or you should
go back to the previous version here.  Function casts are bad, we should
avoid them as much as possible.  My preference is for the previous patch
as I think the earlier critique was mistaken, but I am ok with either
approach.

Sanjoy> +static enum unwind_stop_reason
Sanjoy> +jit_frame_unwind_stop_reason (struct frame_info *this_frame, void **cache)
Sanjoy> +{
Sanjoy> +  return default_frame_unwind_stop_reason (this_frame, cache);
Sanjoy> +}

I think you can just delete this function and put
default_frame_unwind_stop_reason directly into jit_frame_unwind.

Otherwise this looks good to me.

Tom


^ permalink raw reply	[flat|nested] 29+ messages in thread

* Re: [PATCH 7/7] Documentation.
  2011-08-28  8:04     ` [PATCH 7/7] Documentation Sanjoy Das
@ 2011-08-30 19:43       ` Tom Tromey
  0 siblings, 0 replies; 29+ messages in thread
From: Tom Tromey @ 2011-08-30 19:43 UTC (permalink / raw)
  To: Sanjoy Das; +Cc: gdb-patches

>>>>> "Sanjoy" == Sanjoy Das <sanjoy@playingwithpointers.com> writes:

Sanjoy> Add some basic documentation to gdb.texinfo about the new JIT reader
Sanjoy> functionality. Most of the actual documentation is still in
Sanjoy> jit-reader.h.

I think Eli already approved the docs; so no need to repost in that
situation.

However...

Sanjoy> +The reader is implemented as a shared object.  Two new @value{GDBN}
Sanjoy> +commands, @code{load-jit-reader} and @code{unload-jit-reader} are

The commands are actually jit-reader-load and jit-reader-unload.
This affects a good chunk of the patch.

Tom


^ permalink raw reply	[flat|nested] 29+ messages in thread

* Re: [PATCH 1/7] Introduce jit-reader.in and modify build system.
  2011-08-30 18:30       ` Tom Tromey
@ 2011-08-31  3:16         ` Sanjoy Das
  2011-08-31 17:44           ` Tom Tromey
  0 siblings, 1 reply; 29+ messages in thread
From: Sanjoy Das @ 2011-08-31  3:16 UTC (permalink / raw)
  To: Tom Tromey; +Cc: gdb-patches

Hi Tom!

> I haven't been keeping track of your assignment status.
> Has everything gone through?

I'm doing this as a part of an internship, so I'll have to check with
my employers and let you know.

Thanks!
-- 
Sanjoy Das
http://playingwithpointers.com


^ permalink raw reply	[flat|nested] 29+ messages in thread

* Re: [PATCH 1/7] Introduce jit-reader.in and modify build system.
  2011-08-31  3:16         ` Sanjoy Das
@ 2011-08-31 17:44           ` Tom Tromey
  0 siblings, 0 replies; 29+ messages in thread
From: Tom Tromey @ 2011-08-31 17:44 UTC (permalink / raw)
  To: Sanjoy Das; +Cc: gdb-patches

>>>>> "Sanjoy" == Sanjoy Das <sanjoy@playingwithpointers.com> writes:

Tom> I haven't been keeping track of your assignment status.
Tom> Has everything gone through?

Sanjoy> I'm doing this as a part of an internship, so I'll have to check with
Sanjoy> my employers and let you know.

Ok.  We can't put in any of your patches until this is resolved.

Tom


^ permalink raw reply	[flat|nested] 29+ messages in thread

* [PATCH 4/7] New commands for loading and unloading a reader.
  2011-08-31  3:31 JIT Reader (re-roll) Sanjoy Das
@ 2011-08-31  3:32 ` Sanjoy Das
  0 siblings, 0 replies; 29+ messages in thread
From: Sanjoy Das @ 2011-08-31  3:32 UTC (permalink / raw)
  To: gdb-patches; +Cc: Sanjoy Das

Introduces two new GDB commands - `load-jit-reader' and
`unload-jit-reader'.

gdb/ChangeLog:
	* gdb/jit.c: Include gdb-dlfcn.h.
	(loaded_jit_reader, reader_init_fn_sym): New static variables.
	(jit_reader_load, jit_reader_load_command)
	(jit_reader_unload_command): New functions.
	(_initialize_jit): Add commands "jit-reader-load" and
	"jit-reader-unload".
---
 gdb/ChangeLog |    9 +++++
 gdb/jit.c     |   98 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++
 2 files changed, 107 insertions(+), 0 deletions(-)

diff --git a/gdb/ChangeLog b/gdb/ChangeLog
index 995599c..311d5ea 100644
--- a/gdb/ChangeLog
+++ b/gdb/ChangeLog
@@ -1,5 +1,14 @@
 2011-08-27  Sanjoy Das  <sdas@igalia.com>
 
+	* gdb/jit.c: Include gdb-dlfcn.h.
+	(loaded_jit_reader, reader_init_fn_sym): New static variables.
+	(jit_reader_load, jit_reader_load_command)
+	(jit_reader_unload_command): New functions.
+	(_initialize_jit): Add commands "jit-reader-load" and
+	"jit-reader-unload".
+
+2011-08-27  Sanjoy Das  <sdas@igalia.com>
+
     	* gdb/Makefile.in: Add gdb-dlfcn.c and gdb-dlfcn.h to build
     	system.
     	* gdb/config.in: Add new #define HAVE_DLFCN_H.
diff --git a/gdb/jit.c b/gdb/jit.c
index cab27a9..10ea086 100644
--- a/gdb/jit.c
+++ b/gdb/jit.c
@@ -31,6 +31,7 @@
 #include "symfile.h"
 #include "symtab.h"
 #include "target.h"
+#include "gdb-dlfcn.h"
 #include "gdb_stat.h"
 
 static const char *jit_reader_dir = NULL;
@@ -115,6 +116,92 @@ 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.  */
+
+static struct jit_reader
+{
+  struct gdb_reader_funcs *functions;
+  void *handle;
+} *loaded_jit_reader = NULL;
+
+typedef struct gdb_reader_funcs * (reader_init_fn_type) (void);
+static const char *reader_init_fn_sym = "gdb_init_reader";
+
+/* Try to load FILE_NAME as a JIT debug info reader.  */
+
+static struct jit_reader *
+jit_reader_load (const char *file_name)
+{
+  void *so;
+  reader_init_fn_type *init_fn;
+  struct jit_reader *new_reader = NULL;
+  struct gdb_reader_funcs *funcs = NULL;
+  struct cleanup *old_cleanups;
+
+  if (jit_debug)
+    fprintf_unfiltered (gdb_stdlog, _("Opening shared object %s.\n"),
+                        file_name);
+  so = gdb_dlopen (file_name);
+  old_cleanups = make_cleanup_dlclose (so);
+
+  init_fn = gdb_dlsym (so, reader_init_fn_sym);
+  if (!init_fn)
+    error (_("Could not locate initialization function: %s."),
+          reader_init_fn_sym);
+
+  if (gdb_dlsym (so, "plugin_is_GPL_compatible") == NULL)
+    error (_("Reader not GPL compatible."));
+
+  funcs = init_fn ();
+  if (funcs->reader_version != GDB_READER_INTERFACE_VERSION)
+    error (_("Reader version does not match GDB version."));
+
+  new_reader = XZALLOC (struct jit_reader);
+  new_reader->functions = funcs;
+  new_reader->handle = so;
+
+  discard_cleanups (old_cleanups);
+  return new_reader;
+}
+
+/* Provides the jit-reader-load command.  */
+
+static void
+jit_reader_load_command (char *args, int from_tty)
+{
+  char *so_name;
+  int len;
+  struct cleanup *prev_cleanup;
+
+  if (args == NULL)
+    error (_("No reader name provided."));
+
+  if (loaded_jit_reader != NULL)
+    error (_("JIT reader already loaded.  Run jit-reader-unload first."));
+
+  so_name = xstrprintf ("%s/%s", jit_reader_dir, args);
+  prev_cleanup = make_cleanup (xfree, so_name);
+
+  loaded_jit_reader = jit_reader_load (so_name);
+  do_cleanups (prev_cleanup);
+}
+
+/* Provides the jit-reader-unload command.  */
+
+static void
+jit_reader_unload_command (char *args, int from_tty)
+{
+  if (!loaded_jit_reader)
+    error (_("No JIT reader loaded."));
+
+  loaded_jit_reader->functions->destroy (loaded_jit_reader->functions);
+
+  gdb_dlclose (loaded_jit_reader->handle);
+  xfree (loaded_jit_reader);
+  loaded_jit_reader = NULL;
+}
+
 /* Open a BFD from the target's memory.  */
 
 static struct bfd *
@@ -566,4 +653,15 @@ _initialize_jit (void)
   jit_objfile_data = register_objfile_data ();
   jit_inferior_data =
     register_inferior_data_with_cleanup (jit_inferior_data_cleanup);
+  add_com ("jit-reader-load", no_class, jit_reader_load_command, _("\
+Load FILE as debug info reader and unwinder for JIT compiled code.\n\
+Try to load file FILE as a debug info reader (and unwinder) for\n\
+JIT compiled code.  The file is loaded from\n\
+" JIT_READER_DIR ", relocated \n\
+relative to the GDB executable if required.\n\
+Usage is `jit-reader-load FILE`."));
+  add_com ("jit-reader-unload", no_class, jit_reader_unload_command, _("\
+Unload the currently loaded JIT debug info reader.\n\
+See jit-reader-load for how to load JIT debug readers.\n\
+"));
 }
-- 
1.7.5.4


^ permalink raw reply	[flat|nested] 29+ messages in thread

* [PATCH 4/7] New commands for loading and unloading a reader.
  2011-08-24 18:57 JIT Debug Info Reader (re-roll) Sanjoy Das
@ 2011-08-24 18:57 ` Sanjoy Das
  0 siblings, 0 replies; 29+ messages in thread
From: Sanjoy Das @ 2011-08-24 18:57 UTC (permalink / raw)
  To: gdb-patches; +Cc: Sanjoy Das

Introduces two new GDB commands - `load-jit-reader' and
`unload-jit-reader'.
---
 gdb/jit.c |  103 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++-
 1 files changed, 102 insertions(+), 1 deletions(-)

diff --git a/gdb/jit.c b/gdb/jit.c
index cab27a9..f813625 100644
--- a/gdb/jit.c
+++ b/gdb/jit.c
@@ -31,6 +31,7 @@
 #include "symfile.h"
 #include "symtab.h"
 #include "target.h"
+#include "gdb-dlfcn.h"
 #include "gdb_stat.h"
 
 static const char *jit_reader_dir = NULL;
@@ -115,6 +116,96 @@ 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. */
+static struct jit_reader
+{
+  struct gdb_reader_funcs *functions;
+} *loaded_jit_reader = NULL;
+
+typedef struct gdb_reader_funcs * (reader_init_fn_type) (void);
+static const char *reader_init_fn_sym = "gdb_init_reader";
+
+/* Try to load FILE_NAME as a JIT debug info reader. */
+
+static struct jit_reader *
+jit_reader_load (const char *file_name)
+{
+  void *so;
+  reader_init_fn_type *init_fn;
+  struct jit_reader *new_reader = NULL;
+  struct gdb_reader_funcs *funcs = NULL;
+  struct cleanup *old_cleanups;
+
+  if (jit_debug)
+    fprintf_unfiltered (gdb_stdlog, _("Opening shared object %s.\n"),
+                        file_name);
+  so = gdb_dlopen (file_name);
+  old_cleanups = make_cleanup_dlclose (so);
+
+  init_fn = gdb_dlsym (so, reader_init_fn_sym);
+  if (!init_fn)
+    error(_("Could not locate initialization function: %s."),
+          reader_init_fn_sym);
+
+  if (gdb_dlsym (so, "plugin_is_GPL_compatible") == NULL)
+    error(_("Reader not GPL compatible."));
+
+  funcs = init_fn ();
+  if (funcs->reader_version != GDB_READER_INTERFACE_VERSION)
+    error(_("Reader version does not match GDB version."));
+
+  new_reader = XZALLOC (struct jit_reader);
+  new_reader->functions = funcs;
+
+  discard_cleanups (old_cleanups);
+  return new_reader;
+}
+
+/* Provides the jit-reader-load command. */
+
+static void
+jit_reader_load_command (char *args, int from_tty)
+{
+  char so_name[PATH_MAX];
+  int len;
+
+  if (args == NULL)
+    {
+      error (_("No reader name provided."));
+      return;
+    }
+
+  if (loaded_jit_reader != NULL)
+    {
+      error (_("JIT reader already loaded.  Run jit-reader-unload first."));
+      return;
+    }
+
+  len = strlen (jit_reader_dir);
+  strcpy(so_name, jit_reader_dir);
+  so_name[len] = '/';
+  so_name[len + 1] = 0;
+
+  strncat (so_name, args, PATH_MAX - (len + 1));
+  loaded_jit_reader = jit_reader_load (so_name);
+}
+
+/* Provides the jit-reader-unload command. */
+
+static void
+jit_reader_unload_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 *
@@ -535,7 +626,6 @@ jit_event_handler (struct gdbarch *gdbarch)
 			   paddress (gdbarch, entry_addr));
       else
         jit_unregister_code (objf);
-
       break;
     default:
       error (_("Unknown action_flag value in JIT descriptor!"));
@@ -566,4 +656,15 @@ _initialize_jit (void)
   jit_objfile_data = register_objfile_data ();
   jit_inferior_data =
     register_inferior_data_with_cleanup (jit_inferior_data_cleanup);
+  add_com ("jit-reader-load", no_class, jit_reader_load_command, _("\
+Load FILE as debug info reader and unwinder for JIT compiled code.\n\
+Try to load file FILE as a debug info reader (and unwinder) for\n\
+JIT compiled code. The file is loaded from\n\
+" JIT_READER_DIR ", relocated \n\
+relative to the GDB executable if required.\n\
+Usage is `jit-reader-load FILE`."));
+  add_com ("jit-reader-unload", no_class, jit_reader_unload_command, _("\
+Unload the currently loaded JIT debug info reader.\n\
+See jit-reader-load for how to load JIT debug readers.\n\
+"));
 }
-- 
1.7.5.4


^ permalink raw reply	[flat|nested] 29+ messages in thread

end of thread, other threads:[~2011-08-31 17:44 UTC | newest]

Thread overview: 29+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2011-08-27 13:08 JIT Debug Info Reader Sanjoy Das
2011-08-27 13:08 ` [PATCH 5/7] Use the loaded reader Sanjoy Das
2011-08-27 13:47   ` Abhijit Halder
2011-08-27 14:18     ` Abhijit Halder
2011-08-27 13:08 ` [PATCH 2/7] Relocatable directory for loading JIT readers Sanjoy Das
2011-08-27 13:08 ` [PATCH 3/7] Platform agnostic dynamic loading code Sanjoy Das
2011-08-27 13:08 ` [PATCH 6/7] New JIT unwinder Sanjoy Das
2011-08-28  2:17   ` Sergio Durigan Junior
     [not found]   ` <1314518609-10204-1-git-send-email-sanjoy@playingwithpointers.com>
2011-08-28  8:04     ` [PATCH 5/7] Use the loaded reader Sanjoy Das
2011-08-30 19:18       ` Tom Tromey
2011-08-28  8:04     ` [PATCH 7/7] Documentation Sanjoy Das
2011-08-30 19:43       ` Tom Tromey
2011-08-28  8:04     ` [PATCH 3/7] Platform agnostic dynamic loading code Sanjoy Das
2011-08-28  8:04     ` [PATCH 4/7] New commands for loading and unloading a reader Sanjoy Das
2011-08-30 18:52       ` Tom Tromey
2011-08-28  8:04     ` [PATCH 6/7] New JIT unwinder Sanjoy Das
2011-08-30 19:28       ` Tom Tromey
2011-08-28  8:05     ` [PATCH 2/7] Relocatable directory for loading JIT readers Sanjoy Das
2011-08-30 18:32       ` Tom Tromey
2011-08-28  8:07     ` [PATCH 1/7] Introduce jit-reader.in and modify build system Sanjoy Das
2011-08-30 18:30       ` Tom Tromey
2011-08-31  3:16         ` Sanjoy Das
2011-08-31 17:44           ` Tom Tromey
2011-08-27 13:08 ` [PATCH 4/7] New commands for loading and unloading a reader Sanjoy Das
2011-08-27 14:51   ` Abhijit Halder
2011-08-27 13:08 ` [PATCH 7/7] Documentation Sanjoy Das
2011-08-27 13:08 ` [PATCH 1/7] Introduce jit-reader.in and modify build system Sanjoy Das
  -- strict thread matches above, loose matches on Subject: below --
2011-08-31  3:31 JIT Reader (re-roll) Sanjoy Das
2011-08-31  3:32 ` [PATCH 4/7] New commands for loading and unloading a reader Sanjoy Das
2011-08-24 18:57 JIT Debug Info Reader (re-roll) Sanjoy Das
2011-08-24 18:57 ` [PATCH 4/7] New commands for loading and unloading a reader Sanjoy Das

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox