From d6dfb791614d34f1919f276b668b79c5eb278044 Mon Sep 17 00:00:00 2001 From: Sanjoy Das Date: Thu, 30 Jun 2011 16:57:46 +0530 Subject: [PATCH 2/3] Symbol handling code. Implements * Plugin loading code. * Symbol table creation callbacks. --- gdb/jit.c | 506 +++++++++++++++++++++++++++++++++++++++++++++++++++++++------ 1 files changed, 460 insertions(+), 46 deletions(-) diff --git a/gdb/jit.c b/gdb/jit.c index 4ce5814..d259e04 100644 --- a/gdb/jit.c +++ b/gdb/jit.c @@ -21,8 +21,10 @@ #include "jit.h" #include "jit-reader.h" +#include "block.h" #include "breakpoint.h" #include "command.h" +#include "dictionary.h" #include "gdbcmd.h" #include "gdbcore.h" #include "inferior.h" @@ -31,8 +33,11 @@ #include "symfile.h" #include "symtab.h" #include "target.h" +#include "gdb_dirent.h" #include "gdb_stat.h" +#include + static const struct objfile_data *jit_objfile_data; static const char *const jit_break_name = "__jit_debug_register_code"; @@ -45,6 +50,114 @@ static const struct inferior_data *jit_inferior_data = NULL; static int jit_debug = 0; +/* The environment variable we poke at to get the file name of the shared object + to load. */ + +static const char *jit_dbg_reader_so_name_env = "JIT_DEBUG_READER"; + +/* Symbols (and the corresponding types) to be loaded from the shared object + supposed to do the debug-info parsing. */ +typedef int (jit_init_reader_fn) (void **); +static const char *jit_init_reader_sym = "gdbjit_init_reader"; + +typedef int (jit_read_debug_info_fn) (void *, struct gdbjit_symtab_callbacks *, + void *mem, long sz); +static const char *jit_read_debug_info_sym = "gdbjit_read_debug_info"; + +typedef int (jit_unwind_frame_fn) (void *, struct gdbjit_unwind_callbacks *); +static const char *jit_unwind_frame_sym = "gdbjit_unwind_frame"; + +typedef void (jit_destroy_reader_fn) (void *); +static const char *jit_destroy_reader_sym = "gdbjit_destroy_reader"; + +typedef struct gdbjit_frame_id (jit_get_frame_id_fn) (void *, struct + gdbjit_unwind_callbacks *); +static const char *jit_get_frame_id_sym = "gdbjit_get_frame_id"; + +static const char *jit_so_api_version_sym = "__gdbjit_so_api_version"; + +struct jit_dbg_reader { + jit_init_reader_fn *init; + jit_read_debug_info_fn *read; + jit_unwind_frame_fn *unwind; + jit_get_frame_id_fn *get_frame_id; + jit_destroy_reader_fn *destroy; + + void *handle, *private_data; +}; + +static struct jit_dbg_reader * +jit_dbg_reader_load (void) +{ + /* Check if a reader has been provided. */ + const char *file_name = getenv (jit_dbg_reader_so_name_env); + void *handle = NULL; + int (*jit_reader_so_api_version) (void) = NULL; + struct jit_dbg_reader *reader = NULL; + + if (file_name == NULL) + return NULL; + + handle = dlopen (file_name, RTLD_NOW); + if (!handle) + goto cleanup; + + reader = XZALLOC (struct jit_dbg_reader); + reader->init = dlsym (handle, jit_init_reader_sym); + reader->handle = handle; + + if (!reader->init) + goto cleanup; + + reader->read = dlsym (handle, jit_read_debug_info_sym); + if (!reader->read) + goto cleanup; + + reader->unwind = dlsym (handle, jit_unwind_frame_sym); + if (!reader->unwind) + goto cleanup; + + reader->get_frame_id = dlsym (handle, jit_get_frame_id_sym); + if (!reader->get_frame_id) + goto cleanup; + + reader->destroy = dlsym (handle, jit_destroy_reader_sym); + if (!reader->destroy) + goto cleanup; + + jit_reader_so_api_version = dlsym (handle, jit_so_api_version_sym); + if (!jit_reader_so_api_version || + jit_reader_so_api_version () != GDB_JIT_INTERFACE_VERSION) + { + goto cleanup; + } + + if (reader->init (&reader->private_data) != GDB_JIT_SUCCESS) + goto cleanup; + + return reader; + + cleanup: + xfree (reader); + if (handle) + { + dlclose (handle); + fprintf (stderr, "Could not load reader object %s\n", file_name); + } + else /* also report why the shared object could not be loaded */ + fprintf (stderr, "Could not load reader object %s (%s)\n", file_name, + dlerror()); + return NULL; +} + +static void +jit_dbg_reader_destroy (struct jit_dbg_reader *reader) +{ + if (reader) + reader->destroy (reader->private_data); + xfree (reader); +} + static void show_jit_debug (struct ui_file *file, int from_tty, struct cmd_list_element *c, const char *value) @@ -135,6 +248,9 @@ struct jit_inferior_data { CORE_ADDR breakpoint_addr; /* &__jit_debug_register_code() */ CORE_ADDR descriptor_addr; /* &__jit_debug_descriptor */ + struct jit_dbg_reader *reader; /* If a debug info reader was found. */ + struct objfile *jit_objfile; /* The object file where all the JIT symbols + will be added. */ }; /* Return jit_inferior_data for current inferior. Allocate if not already @@ -233,6 +349,282 @@ jit_read_code_entry (struct gdbarch *gdbarch, extract_unsigned_integer (&entry_buf[3 * ptr_size], 8, byte_order); } +struct gdbjit_block +{ + struct gdbjit_block *next, *parent; + struct block *real_block; + + void *begin, *end; + const char *name; +}; + +struct gdbjit_symtab +{ + struct gdbjit_block *blocks; + struct linetable *linetable; + int nblocks; + + const char *file_name; +}; + +struct jit_dbg_reader_data +{ + struct objfile **objf; +}; + +static int +jit_target_read_impl (void *target_mem, void *gdb_buf, int len) +{ + return target_read_memory ((CORE_ADDR) target_mem, gdb_buf, len); +} + +static struct gdbjit_symtab * +jit_symtab_open_impl (struct gdbjit_symtab_callbacks *cb, const char *file_name) +{ + struct gdbjit_symtab *ret = XZALLOC (struct gdbjit_symtab); + ret->file_name = xstrdup (file_name); + return ret; +} + +/* Returns true if the block corrensponding to old should be placed before the + block corrensponding to new in the final blockvector. */ +static int +compare_block (struct gdbjit_block *old, struct gdbjit_block *new) +{ + if (old == NULL) + return 1; + if (old->begin < new->begin) + return 1; + else if (old->begin == new->begin) + { + if (old->end > new->end) + return 1; + else + return 0; + } + else + return 0; +} + +static struct gdbjit_block * +jit_new_block_impl (struct gdbjit_symtab_callbacks *cb, + struct gdbjit_symtab *symtab, + struct gdbjit_block *parent, + void *begin, void *end, const char *name) +{ + struct gdbjit_block *block = XZALLOC (struct gdbjit_block); + + (void) cb; + + block->next = symtab->blocks; + block->begin = begin; + block->end = end; + block->name = name ? xstrdup (name) : NULL; + block->parent = parent; + + /* Ensure that the blocks are inserted in the correct (reverse of the order + expected by blockvector). */ + if (compare_block (symtab->blocks, block)) + { + symtab->blocks = block; + } + else + { + struct gdbjit_block *i = symtab->blocks; + for (;; i = i->next) + { + /* Guranteed to terminate, since compare_block (NULL, _) returns 1 */ + if (compare_block (i->next, block)) + { + block->next = i->next; + i->next = block; + break; + } + } + } + symtab->nblocks++; + + return block; +} + +static void +jit_symtab_add_line_mapping_impl (struct gdbjit_symtab_callbacks *cb, + struct gdbjit_symtab *stab, + int nlines, + struct gdbjit_line_mapping *map) +{ + int i; + /* Must copy */ + if (!nlines) + return; + + stab->linetable = xmalloc (sizeof (struct linetable) + (nlines - 1) * + sizeof (struct linetable_entry)); + stab->linetable->nitems = nlines; + for (i = 0; i < nlines; i++) + { + stab->linetable->item [i].pc = (CORE_ADDR) map[i].pc; + stab->linetable->item [i].line = map[i].line; + } +} + +static void +jit_symtab_close_impl (struct gdbjit_symtab_callbacks *cb, + struct gdbjit_symtab *stab) +{ + struct jit_dbg_reader_data *dat = cb->private; + struct symtab *symtab; + struct gdbjit_block *blck_iter, *blck_iter_tmp; + struct block *block_iter; + struct objfile *objfile; + int actual_nblocks = FIRST_LOCAL_BLOCK + stab->nblocks, i; + CORE_ADDR begin, end; + + if (*dat->objf == NULL) + { + objfile = allocate_objfile (NULL, 0); + *dat->objf = objfile; + objfile->gdbarch = target_gdbarch; + objfile->msymbols = obstack_alloc (&objfile->objfile_obstack, + sizeof (struct minimal_symbol)); + objfile->msymbols[0].ginfo.name = NULL; + objfile->msymbols[0].ginfo.value.address = 0; + objfile->name = xstrdup ("JIT"); + } + else + objfile = *dat->objf; + + symtab = allocate_symtab (stab->file_name, objfile); + symtab->dirname = NULL; /* JIT compilers compile in memory */ + + if (stab->linetable) { + int size = (stab->linetable->nitems - 1) * sizeof (struct linetable_entry) + + sizeof (struct linetable); + LINETABLE (symtab) = obstack_alloc (&objfile->objfile_obstack, size); + memcpy (LINETABLE (symtab), stab->linetable, size); + } else { + LINETABLE (symtab) = NULL; + } + + symtab->blockvector = obstack_alloc (&objfile->objfile_obstack, + (sizeof (struct blockvector) + + (actual_nblocks - 1) * + sizeof (struct block *))); + + /* (begin, end) will contain the PC range this entire blockvector spans. */ + symtab->primary = 1; + BLOCKVECTOR_MAP (symtab->blockvector) = NULL; + begin = (CORE_ADDR) stab->blocks->begin; + end = (CORE_ADDR) stab->blocks->end; + BLOCKVECTOR_NBLOCKS (symtab->blockvector) = actual_nblocks; + + for (i = (actual_nblocks - 1), blck_iter = stab->blocks; + i >= FIRST_LOCAL_BLOCK; i--) + { + struct block *bl = allocate_block (&objfile->objfile_obstack); + struct symbol *block_name = obstack_alloc (&objfile->objfile_obstack, + sizeof (struct symbol)); + + BLOCK_DICT (bl) = dict_create_linear (&objfile->objfile_obstack, NULL); + BLOCK_START (bl) = (CORE_ADDR) blck_iter->begin; + BLOCK_END (bl) = (CORE_ADDR) blck_iter->end; + BLOCK_FUNCTION (bl) = block_name; + + memset (block_name, 0, sizeof (struct symbol)); + SYMBOL_DOMAIN (block_name) = VAR_DOMAIN; + SYMBOL_CLASS (block_name) = LOC_BLOCK; + block_name->symtab = symtab; + SYMBOL_BLOCK_VALUE (block_name) = bl; + + block_name->ginfo.name = obstack_alloc (&objfile->objfile_obstack, + 1 + strlen (blck_iter->name)); + strcpy (block_name->ginfo.name, blck_iter->name); + BLOCK_FUNCTION (bl) = block_name; + + BLOCKVECTOR_BLOCK (symtab->blockvector, i) = bl; + if (begin < (long) blck_iter->begin) + begin = (long) blck_iter->begin; + if (end > (long) blck_iter->end) + end = (long) blck_iter->end; + } + + blck_iter = blck_iter->next; + + /* Now add the special blocks. */ + block_iter = NULL; + for (i = 0; i < FIRST_LOCAL_BLOCK; i++) + { + struct block *bl = allocate_block (&objfile->objfile_obstack); + BLOCK_DICT (bl) = dict_create_linear (&objfile->objfile_obstack, NULL); + BLOCK_SUPERBLOCK (bl) = block_iter; + block_iter = bl; + + BLOCK_START (bl) = (CORE_ADDR) begin; + BLOCK_END (bl) = (CORE_ADDR) end; + + BLOCKVECTOR_BLOCK (symtab->blockvector, i) = bl; + } + + /* Fill up the superblock fields. */ + for (blck_iter = stab->blocks; blck_iter; blck_iter = blck_iter->next) + { + if (blck_iter->parent != NULL) + BLOCK_SUPERBLOCK (blck_iter->real_block) = + blck_iter->parent->real_block; + } + + /* Free memory. */ + blck_iter = stab->blocks; + for (blck_iter = stab->blocks, blck_iter_tmp = blck_iter->next; + blck_iter; blck_iter = blck_iter_tmp) + { + xfree (blck_iter); + } +} + +static int +jit_try_read_symtab (struct jit_inferior_data *inf_data, + CORE_ADDR target_mem, long sz) +{ + void *gdb_mem; + int status = 0; + struct jit_dbg_reader *i; + struct jit_dbg_reader_data priv_data; + struct gdbjit_symtab_callbacks callbacks = + { + jit_symtab_open_impl, + jit_new_block_impl, + jit_symtab_add_line_mapping_impl, + jit_target_read_impl, + jit_symtab_close_impl, + + &priv_data + }; + + if (!inf_data->reader) + return 0; + + priv_data.objf = &inf_data->jit_objfile; + + gdb_mem = xmalloc (sz); + if (target_read_memory (target_mem, gdb_mem, sz)) + { + status = 0; + goto cleanup; + } + + if (inf_data->reader->read (inf_data->reader->private_data, &callbacks, + gdb_mem, sz) == GDB_JIT_SUCCESS) + { + status = 1; + goto cleanup; + } + + cleanup: + xfree (gdb_mem); + return status; +} + /* This function registers code associated with a JIT code entry. It uses the pointer and size pair in the entry to read the symbol file from the remote and then calls symbol_file_add_from_local_memory to add it as though it were @@ -246,10 +638,10 @@ jit_register_code (struct gdbarch *gdbarch, struct section_addr_info *sai; struct bfd_section *sec; struct objfile *objfile; - struct cleanup *old_cleanups, *my_cleanups; - int i; + int i, success; const struct bfd_arch_info *b; CORE_ADDR *entry_addr_ptr; + struct jit_inferior_data *inf_data = get_jit_inferior_data (); if (jit_debug) fprintf_unfiltered (gdb_stdlog, @@ -258,53 +650,62 @@ jit_register_code (struct gdbarch *gdbarch, paddress (gdbarch, code_entry->symfile_addr), pulongest (code_entry->symfile_size)); - nbfd = bfd_open_from_target_memory (code_entry->symfile_addr, - code_entry->symfile_size, gnutarget); - old_cleanups = make_cleanup_bfd_close (nbfd); - - /* Check the format. NOTE: This initializes important data that GDB uses! - We would segfault later without this line. */ - if (!bfd_check_format (nbfd, bfd_object)) + if (jit_try_read_symtab (inf_data, code_entry->symfile_addr, + code_entry->symfile_size)) { - printf_unfiltered (_("\ + objfile = inf_data->jit_objfile; + } + else + { + struct cleanup *old_cleanups; + nbfd = bfd_open_from_target_memory (code_entry->symfile_addr, + code_entry->symfile_size, gnutarget); + old_cleanups = make_cleanup_bfd_close (nbfd); + + /* Check the format. NOTE: This initializes important data that GDB uses! + We would segfault later without this line. */ + if (!bfd_check_format (nbfd, bfd_object)) + { + printf_unfiltered (_("\ JITed symbol file is not an object file, ignoring it.\n")); - do_cleanups (old_cleanups); - return; + do_cleanups (old_cleanups); + return; + } + + /* Check bfd arch. */ + b = gdbarch_bfd_arch_info (gdbarch); + if (b->compatible (b, bfd_get_arch_info (nbfd)) != b) + warning (_("JITed object file architecture %s is not compatible " + "with target architecture %s."), bfd_get_arch_info + (nbfd)->printable_name, b->printable_name); + + /* Read the section address information out of the symbol file. Since the + file is generated by the JIT at runtime, it should all of the absolute + addresses that we care about. */ + sai = alloc_section_addr_info (bfd_count_sections (nbfd)); + make_cleanup_free_section_addr_info (sai); + i = 0; + for (sec = nbfd->sections; sec != NULL; sec = sec->next) + if ((bfd_get_section_flags (nbfd, sec) & (SEC_ALLOC|SEC_LOAD)) != 0) + { + /* We assume that these virtual addresses are absolute, and do not + treat them as offsets. */ + sai->other[i].addr = bfd_get_section_vma (nbfd, sec); + sai->other[i].name = xstrdup (bfd_get_section_name (nbfd, sec)); + sai->other[i].sectindex = sec->index; + ++i; + } + + /* This call takes ownership of sai. */ + objfile = symbol_file_add_from_bfd (nbfd, 0, sai, OBJF_SHARED, NULL); + + /* Remember a mapping from entry_addr to objfile. */ + entry_addr_ptr = xmalloc (sizeof (CORE_ADDR)); + *entry_addr_ptr = entry_addr; + set_objfile_data (objfile, jit_objfile_data, entry_addr_ptr); + + discard_cleanups (old_cleanups); } - - /* Check bfd arch. */ - b = gdbarch_bfd_arch_info (gdbarch); - if (b->compatible (b, bfd_get_arch_info (nbfd)) != b) - warning (_("JITed object file architecture %s is not compatible " - "with target architecture %s."), bfd_get_arch_info - (nbfd)->printable_name, b->printable_name); - - /* Read the section address information out of the symbol file. Since the - file is generated by the JIT at runtime, it should all of the absolute - addresses that we care about. */ - sai = alloc_section_addr_info (bfd_count_sections (nbfd)); - make_cleanup_free_section_addr_info (sai); - i = 0; - for (sec = nbfd->sections; sec != NULL; sec = sec->next) - if ((bfd_get_section_flags (nbfd, sec) & (SEC_ALLOC|SEC_LOAD)) != 0) - { - /* We assume that these virtual addresses are absolute, and do not - treat them as offsets. */ - sai->other[i].addr = bfd_get_section_vma (nbfd, sec); - sai->other[i].name = xstrdup (bfd_get_section_name (nbfd, sec)); - sai->other[i].sectindex = sec->index; - ++i; - } - - /* This call takes ownership of sai. */ - objfile = symbol_file_add_from_bfd (nbfd, 0, sai, OBJF_SHARED, NULL); - - /* Remember a mapping from entry_addr to objfile. */ - entry_addr_ptr = xmalloc (sizeof (CORE_ADDR)); - *entry_addr_ptr = entry_addr; - set_objfile_data (objfile, jit_objfile_data, entry_addr_ptr); - - discard_cleanups (old_cleanups); } /* This function unregisters JITed code and frees the corresponding @@ -385,6 +786,8 @@ jit_inferior_init (struct gdbarch *gdbarch) if (jit_breakpoint_re_set_internal (gdbarch, inf_data) != 0) return; + inf_data->reader = jit_dbg_reader_load (); + if (inf_data->descriptor_addr == 0) { struct minimal_symbol *desc_symbol; @@ -464,6 +867,11 @@ jit_reset_inferior_data_and_breakpoints (void) /* Remove any existing JIT breakpoint(s). */ remove_jit_event_breakpoints (); + /* Destroy JIT reader objects. */ + jit_dbg_reader_destroy (inf_data->reader); + if (inf_data->jit_objfile) + free_objfile (inf_data->jit_objfile); + jit_inferior_init (target_gdbarch); } @@ -484,6 +892,12 @@ jit_inferior_exit_hook (struct inferior *inf) { struct objfile *objf; struct objfile *temp; + struct jit_inferior_data *inf_data; + + inf_data = inferior_data (inf, jit_inferior_data); + jit_dbg_reader_destroy (inf_data->reader); + if (inf_data->jit_objfile) + free_objfile (inf_data->jit_objfile); ALL_OBJFILES_SAFE (objf, temp) if (objfile_data (objf, jit_objfile_data) != NULL) -- 1.7.5.3