Commits

Anonymous committed 82db95f Merge

merge onering back to default, refs #1218 (spent 40)

This improves:

* general sparc support
* big endian bitfields
* recursive struct printing
* APIs for tracing modules
* success of DWARF CU, CIE, FDE resolution
* Solaris unwinding
* Performance (by two orders of magnitude, making it faster than gdb by
1 order of magnitude)

  • Participants
  • Parent commits d07f287, c1c3577

Comments (0)

Files changed (35)

 RLLDFLAGS = @RL_LDFLAGS@
 RLCFLAGS = @RL_CFLAGS@
 TRACELDFLAGS = @CORONER_LDFLAGS@
-bin_PROGRAMS = monitor glider wdb
+bin_PROGRAMS = monitor glider #wdb
 noinst_PROGRAMS = wedgie
 lib_LTLIBRARIES = libgimli.la libgimli_ana.la
 noinst_LTLIBRARIES = liblua.la
 
 libgimli_ana_la_SOURCES = \
 	trace.c linux.c elf.c hash.c elf-read.c dwarf-read.c dwarf-unwind.c \
-	dwarf-expr.c darwin.c solaris.c demangle.c freebsd.c
+	dwarf-expr.c darwin.c solaris.c demangle.c freebsd.c proc.c \
+	proc_service.c symbols.c types.c maps.c apiv2.c print.c slab.c \
+	apiv3.c module.c
 
 libgimli_la_SOURCES = \
   heartbeat.c
+/*
+ * Copyright (c) 2007-2012 Message Systems, Inc. All rights reserved
+ * For licensing information, see:
+ * https://bitbucket.org/wez/gimli/src/tip/LICENSE
+ */
+#include "impl.h"
+
+/* Implements GIMLI_ANA_API_VERSION <= 2 */
+
+static const struct gimli_proc_stat *v2_get_proc_stat(void)
+{
+  return &the_proc->proc_stat;
+}
+
+static int v2_get_source_info(void *addr, char *buf,
+  int buflen, int *lineno)
+{
+  uint64_t l;
+  int ret = gimli_determine_source_line_number(the_proc,
+      (gimli_addr_t)addr, buf, buflen, &l);
+  if (ret) {
+    *lineno = (int)l;
+  }
+  return ret;
+}
+
+static char *v2_get_string_symbol(const char *obj, const char *name)
+{
+  return gimli_get_string_symbol(the_proc, obj, name);
+}
+
+static int v2_copy_from_symbol(const char *obj, const char *name,
+  int deref, void *buf, uint32_t size)
+{
+  return gimli_copy_from_symbol(obj, name, deref, buf, size);
+}
+
+static struct gimli_symbol *v1_sym_lookup(
+    const char *obj, const char *name)
+{
+  return gimli_sym_lookup(the_proc, obj, name);
+}
+
+static const char *v1_pc_sym_name(void *addr,
+    char *buf, int buflen)
+{
+  return gimli_pc_sym_name(the_proc, (gimli_addr_t)addr, buf, buflen);
+}
+
+static int v1_read_mem(void *src, void *dest, int len)
+{
+  return gimli_read_mem(the_proc, (gimli_addr_t)src, dest, len);
+}
+
+static char *v1_read_string(void *src)
+{
+  return gimli_read_string(the_proc, (gimli_addr_t)src);
+}
+
+static int v2_get_parameter(void *context, const char *varname,
+  const char **datatypep, void **addrp, uint64_t *sizep)
+{
+  gimli_stack_frame_t frame = context;
+  gimli_addr_t addr;
+  gimli_type_t t;
+
+  if (!gimli_stack_frame_resolve_var(frame, GIMLI_WANT_PARAMS,
+        varname, &t, &addr)) {
+    return 0;
+  }
+
+  *addrp = (void*)addr;
+  *sizep = gimli_type_size(t);
+  *datatypep = gimli_type_declname(t);
+
+  return 1;
+}
+
+
+struct gimli_ana_api ana_api = {
+  GIMLI_ANA_API_VERSION,
+  v1_sym_lookup,
+  v1_pc_sym_name,
+  v1_read_mem,
+  v1_read_string,
+  v2_get_source_info,
+  v2_get_parameter,
+  v2_get_string_symbol,
+  v2_copy_from_symbol,
+  v2_get_proc_stat,
+};
+
+/* vim:ts=2:sw=2:et:
+ */
+/*
+ * Copyright (c) 2012 Message Systems, Inc. All rights reserved
+ * For licensing information, see:
+ * https://bitbucket.org/wez/gimli/src/tip/LICENSE
+ */
+#include "impl.h"
+
+int gimli_read_pointer(gimli_proc_t proc, gimli_addr_t addr, gimli_addr_t *val)
+{
+  uint64_t p64;
+  uint32_t p32;
+
+  *val = 0;
+  if (sizeof(void*) == 8) { // FIXME: data model aware
+    if (gimli_read_mem(proc, addr, &p64, sizeof(p64)) == sizeof(p64)) {
+      *val = p64;
+      return 1;
+    }
+    return 0;
+  }
+  /* 32-bit target */
+  if (gimli_read_mem(proc, addr, &p32, sizeof(p32)) == sizeof(p32)) {
+    *val = p32;
+    return 1;
+  }
+  return 0;
+}
+
+char *gimli_get_string_symbol(gimli_proc_t proc,
+    const char *obj, const char *name)
+{
+  struct gimli_symbol *sym;
+
+  sym = gimli_sym_lookup(proc, obj, name);
+  if (sym) {
+    gimli_addr_t addr;
+
+    if (gimli_read_pointer(proc, sym->addr, &addr)) {
+      return gimli_read_string(proc, addr);
+    }
+  }
+  return NULL;
+}
+
+int gimli_copy_from_symbol(const char *obj, const char *name,
+  int deref, void *buf, uint32_t size)
+{
+  struct gimli_symbol *sym;
+
+  sym = gimli_sym_lookup(the_proc, obj, name);
+  if (sym) {
+    gimli_addr_t addr = sym->addr;
+
+    while (deref--) {
+      if (!gimli_read_pointer(the_proc, addr, &addr)) {
+        return 0;
+      }
+    }
+
+    return gimli_read_mem(the_proc, addr, buf, size) == size;
+  }
+  return 0;
+}
+
+int gimli_module_register_tracer(gimli_tracer_f func, void *arg)
+{
+  return gimli_hook_register("tracer", func, arg);
+}
+
+static gimli_iter_status_t visit_tracer(gimli_hook_f func, void *farg, void *arg)
+{
+  gimli_proc_t proc = arg;
+  gimli_tracer_f tracer = (gimli_tracer_f)func;
+
+  tracer(proc, farg);
+
+  return GIMLI_ITER_CONT;
+}
+
+void gimli_module_call_tracers(gimli_proc_t proc)
+{
+  gimli_hook_visit("tracer", visit_tracer, proc);
+}
+
+int gimli_module_register_var_printer(gimli_var_printer_f func, void *arg)
+{
+  return gimli_hook_register("prettyprinter", (gimli_hook_f)func, arg);
+}
+
+struct prettyargs {
+  gimli_proc_t proc;
+  gimli_stack_frame_t frame;
+  const char *varname;
+  gimli_type_t t;
+  gimli_addr_t addr;
+  int depth;
+};
+
+static gimli_iter_status_t visit_pretty(gimli_hook_f func, void *farg, void *arg)
+{
+  struct prettyargs *args = arg;
+  gimli_var_printer_f pretty = (gimli_var_printer_f)func;
+
+  return pretty(args->proc, args->frame, args->varname,
+      args->t, args->addr, args->depth, farg);
+}
+
+gimli_iter_status_t gimli_module_call_var_printer(
+    gimli_proc_t proc, gimli_stack_frame_t frame,
+    const char *varname, gimli_type_t t,
+    gimli_addr_t addr, int depth)
+{
+  struct prettyargs pargs = { proc, frame, varname, t, addr, depth };
+
+  return gimli_hook_visit("prettyprinter", visit_pretty, &pargs);
+}
+
+struct printer_type {
+  gimli_var_printer_f func;
+  void *arg;
+  int ntypes;
+};
+static gimli_hash_t printer_by_type = NULL;
+
+static gimli_iter_status_t filter_printer_type(gimli_proc_t proc,
+    gimli_stack_frame_t frame,
+    const char *varname, gimli_type_t t, gimli_addr_t addr,
+    int depth, void *arg)
+{
+  struct printer_type *list;
+  const char *decl;
+
+  if (!t) return GIMLI_ITER_CONT;
+
+  decl = gimli_type_declname(t);
+  if (gimli_hash_find(printer_by_type, decl, (void**)&list)) {
+    return list->func(proc, frame, varname, t, addr, depth, list->arg);
+  }
+
+  return GIMLI_ITER_CONT;
+}
+
+static void free_printer(void *ptr)
+{
+  struct printer_type *list = ptr;
+
+  if (--list->ntypes) return;
+  free(list);
+}
+
+int gimli_module_register_var_printer_for_types(const char *typenames[],
+    int ntypes, gimli_var_printer_f func, void *arg)
+{
+  struct printer_type *list = calloc(1, sizeof(*list));
+  int i;
+
+  list->arg = arg;
+  list->func = func;
+  list->ntypes = ntypes;
+
+  if (!printer_by_type) {
+    printer_by_type = gimli_hash_new(free_printer);
+    gimli_module_register_var_printer(filter_printer_type, NULL);
+  }
+  for (i = 0; i < ntypes; i++) {
+    gimli_hash_insert(printer_by_type, typenames[i], list);
+  }
+
+  return 1;
+}
+
+/* vim:ts=2:sw=2:et:
+ */
+
   libtoolize --automake
 fi
 autoheader
-aclocal 
-automake --add-missing --foreign
+if test -z "$ACLOCAL" ; then
+  ACLOCAL=aclocal
+fi
+$ACLOCAL
+if test -z "$AUTOMAKE" ; then
+  AUTOMAKE=automake
+fi
+$AUTOMAKE --add-missing --foreign
 autoconf
 

File configure.ac

 AM_PROG_AS
 AC_PROG_LIBTOOL
 AC_C_INLINE
+AC_C_BIGENDIAN
 
 CFLAGS=`echo $CFLAGS | sed -e 's/-O2//;'`
 CFLAGS="-D_REENTRANT $CFLAGS"
+if test "$GCC" == "yes" ; then
+  CFLAGS="$CFLAGS -Wmissing-prototypes -Wformat"
+fi
 MODULE_SUFFIX=".so"
 SHLIB_SUFFIX=".so"
 DWARF_DEBUG_FLAGS="-gdwarf-2 -g3"
     MODULE_SUFFIX=".bundle"
     SHLIB_SUFFIX=".dylib"
     RLDPATH="-R"
-    DARWIN_DSYMUTIL="dsymutil -o .libs/wedgie.dSYM .libs/wedgie"
+    DARWIN_DSYMUTIL="dsymutil -o .libs/wedgie.dSYM .libs/wedgie ; dsymutil -o .libs/libgimli.0.dylib.dSYM .libs/libgimli.0.dylib"
     ;;
   *linux*)
     CORONER_LDFLAGS="-lthread_db -lpthread"
 #elif defined(__ppc__)
       CPU_TYPE_POWERPC
 #else
-# error don't know my own arch
+# error dont know my own arch
 #endif
       ;
 
 static int target_pid;
 static int got_task = 0;
 static task_t targetTask;
-static void *sigtramp = NULL;
+static gimli_addr_t sigtramp = 0;
+
+void gimli_object_file_destroy(gimli_object_file_t obj)
+{
+}
 
 /* Given a path to an image file, open it, find the correct architecture
  * portion for the header, populate rethdr with it and return the file
  * Attempt to load such a beast and process the dwarf info from
  * it.
  */
-static void find_dwarf_dSYM(struct gimli_object_file *of)
+static void find_dwarf_dSYM(gimli_mapped_object_t file)
 {
   char dsym[PATH_MAX];
   char *base;
   int fd;
   gimli_segment_command scmd;
   char sectname[16];
-  gimli_object_file_t *container;
+  gimli_object_file_t container;
   
-  strcpy(basepath, of->objname);
+  strcpy(basepath, file->objname);
   base = basename(basepath);
 
   snprintf(dsym, sizeof(dsym)-1,
-    "%s.dSYM/Contents/Resources/DWARF/%s", of->objname, base);
+    "%s.dSYM/Contents/Resources/DWARF/%s", file->objname, base);
 
   if (debug) {
     fprintf(stderr, "dsym: trying %s\n", dsym);
   if (fd == -1) return;
 
   container = calloc(1, sizeof(*container));
-  container->gobject = of;
+  container->gobject = file;
   container->objname = strdup(dsym);
   container->is_exec = 1;
 
-  of->aux_elf = container;
+  file->aux_elf = container;
 
   /* we're looking for an LC_SEGMENT with a segname of __DWARF */
   cmd_offset = hdr_offset + sizeof(hdr);
           s->name[0] = '.';
           s->addr = sec.addr;
           if (debug) {
-            fprintf(stderr, "%s %s s->addr=%p base_addr=%p\n",
-              of->objname, sectname, s->addr, of->base_addr);
+            fprintf(stderr, "%s %s s->addr=" PTRFMT " base_addr=" PTRFMT "\n",
+              file->objname, sectname, s->addr, file->base_addr);
           }
           s->size = sec.size;
           s->data = malloc(s->size);
           s->container = container;
           pread(fd, s->data, s->size, s->offset);
 
-          gimli_hash_insert(of->sections, s->name, s);
+          gimli_hash_insert(file->sections, s->name, s);
         }
       }
     }
 }
 
 struct gimli_section_data *gimli_get_section_by_name(
-  gimli_object_file_t *elf, const char *name)
+  gimli_object_file_t elf, const char *name)
 {
   struct gimli_section_data *s = NULL;
 
 static int add_symbol(gimli_mach_header *mhdr, void *context,
   const char *strtab, gimli_nlist *nsym)
 {
-  struct gimli_object_file *of = context;
+  gimli_mapped_object_t file = context;
 
   if (nsym->n_value != 0 && nsym->n_type != N_UNDF &&
       strtab[nsym->n_un.n_strx] != '\0') {
         case N_FNAME:
         case N_FUN: /* may have line numbers */
         case N_LSYM:
+        case N_STSYM:
           want_symbol = 1;
           break;
         default:
           want_symbol = 0;
-          //printf("        stab:%x\n", nsym->n_type);
+#if 0
+          printf("%02x %s sect=%d desc=%d val=%" PRIu64 "\n",
+              nsym->n_type,
+              strtab + nsym->n_un.n_strx,
+              nsym->n_sect, nsym->n_desc, nsym->n_value);
+#endif
+
       }
     } else if (nsym->n_type & N_PEXT) {
       want_symbol = 0;
 #endif
     }
     if (want_symbol) {
-      void *value = (void*)(intptr_t)nsym->n_value;
+      gimli_addr_t value = nsym->n_value + file->base_addr;
+//      printf("sym: %s " PTRFMT "\n", strtab + nsym->n_un.n_strx, value);
+      gimli_add_symbol(file, strtab + nsym->n_un.n_strx, value, 0);
 
-      if (mhdr->filetype != MH_EXECUTE) {
-        value += of->base_addr;
-      }
-      //          printf("sym: %s %p\n", strtab + nsym->n_un.n_strx, (char*)value);
-      gimli_add_symbol(of, strtab + nsym->n_un.n_strx, value, 0);
-
-      if (sigtramp == NULL &&
+      if (sigtramp == 0 &&
           !strcmp(strtab + nsym->n_un.n_strx, "__sigtramp")) {
         sigtramp = value;
       }
   return 1;
 }
 
-static void read_symtab(struct gimli_object_file *of,
+static void read_symtab(gimli_mapped_object_t file,
   int fd, uint32_t cmd_offset, uint32_t file_off,
   gimli_mach_header *mhdr)
 {
-  walk_symtab(of, add_symbol, fd, cmd_offset, file_off, mhdr);
+  walk_symtab(file, add_symbol, fd, cmd_offset, file_off, mhdr);
 }
 
 /* dyld bootstrap.
  * the nlist() library routine, so we need to manually grub around in dyld
  * to find the dyld symbols we need for discover_maps. */
 struct gimli_dyld_bootstrap {
-  void *info;
-  void *cache;
+  gimli_addr_t info;
+  gimli_addr_t cache;
 };
 
 static int find_dyld_symbols(gimli_mach_header *mhdr, void *context,
 
   if (!dyld->info) {
     if (!strcmp(name, "_dyld_all_image_infos")) {
-      dyld->info = (void*)nsym->n_value;
+      dyld->info = nsym->n_value;
       return 1;
     }
   }
   if (dyld->cache) {
     if (!strcmp(name, "_dyld_shared_region_ranges")) {
-      dyld->cache = (void*)nsym->n_value;
+      dyld->cache = nsym->n_value;
       return 1;
     }
   }
  * target (which should always be true) and read the info out of the target
  * from that address.  This interface is documented in <mach-o/dyld_images.h>
  */
-static void discover_maps(void)
+static void discover_maps(gimli_proc_t proc)
 {
   int i;
   char *symoff = NULL;
     /* adjust the cache information by the same slide that we observe
      * for the difference between the symbol for _dyld_all_image_infos
      * and the value we got from the task_info above */
-    dyld.cache -= (void*)tinfo.all_image_info_addr - dyld.info;
+    dyld.cache -= tinfo.all_image_info_addr - dyld.info;
   }
   dyld.info = tinfo.all_image_info_addr;
 
   if (dyld.info) {
-    if (gimli_read_mem(dyld.info, &infos, sizeof(infos)) != sizeof(infos)) {
-      fprintf(stderr, "DYLD: failed to read _dyld_all_image_infos from %p\n"
+    if (gimli_read_mem(proc, dyld.info, &infos, sizeof(infos)) != sizeof(infos)) {
+      fprintf(stderr, "DYLD: failed to read _dyld_all_image_infos from " PTRFMT "\n"
           "DYLD: no maps, symbols or DWARF info will be available\n",
           dyld.info);
       return;
    * addresses match against the shared cache, then we need to perform
    * an additional computation to obtain the relocated address in the target */
   have_shared_cache = 0;
-  if (dyld.cache && gimli_read_mem(dyld.cache, &shared_cache,
+  if (dyld.cache && gimli_read_mem(proc, dyld.cache, &shared_cache,
         sizeof(shared_cache)) == sizeof(shared_cache)) {
     have_shared_cache = 1;
   }
     struct dyld_image_info im;
     char name[PATH_MAX];
     char rname[PATH_MAX];
-    struct gimli_object_file *of = NULL;
+    gimli_mapped_object_t file = NULL;
     gimli_mach_header mhdr;
     int n, fd;
     char *addr = NULL;
     char sectname[16];
     uint32_t hdr_offset, cmd_offset;
 
-    gimli_read_mem((char*)infos.infoArray + (i * sizeof(im)),
+    gimli_read_mem(proc, (gimli_addr_t)infos.infoArray + (i * sizeof(im)),
         &im, sizeof(im));
 
     if (im.imageLoadAddress == 0) {
     }
 
     memset(name, 0, sizeof(name));
-    gimli_read_mem((void*)im.imageFilePath, name, sizeof(name));
+    gimli_read_mem(proc, (gimli_addr_t)im.imageFilePath, name, sizeof(name));
     if (!realpath(name, rname)) strcpy(rname, name);
 
     if (debug) {
           im.imageLoadAddress, im.imageFilePath, rname);
     }
 
-    of = gimli_add_object(rname, 0);
-    of->elf = calloc(1, sizeof(*of->elf));
-    of->elf->gobject = of;
-    of->elf->is_exec = 1;
-    of->elf->objname = of->objname;
+    file = gimli_add_object(proc, rname, 0);
+    file->elf = calloc(1, sizeof(*file->elf));
+    file->elf->gobject = file;
+    file->elf->is_exec = 1;
+    file->elf->objname = file->objname;
 
     /* now, from the mach header, find each segment and its
      * address range and record the mapping */
-    gimli_read_mem((void*)im.imageLoadAddress, &mhdr, sizeof(mhdr));
+    gimli_read_mem(proc, (gimli_addr_t)im.imageLoadAddress, &mhdr, sizeof(mhdr));
 
     in_shared_cache = 0;
     if (have_shared_cache) {
     for (n = 0; n < hdr.ncmds; n++, cmd_offset += seg.cmdsize) {
       pread(fd, &seg, sizeof(struct load_command), cmd_offset);
       if (seg.cmd == LC_SYMTAB) {
-        read_symtab(of, fd, cmd_offset, hdr_offset, &mhdr);
+        read_symtab(file, fd, cmd_offset, hdr_offset, &mhdr);
         continue;
       }
       if (seg.cmd != GIMLI_LC_SEGMENT) {
         /* ignore zero page mapping */
         continue;
       }
-      if (!strcmp(seg.segname, SEG_TEXT) && of->base_addr == 0) {
+      if (!strcmp(seg.segname, SEG_TEXT) && file->base_addr == 0) {
         /* compute the slide */
-        of->base_addr = (intptr_t)im.imageLoadAddress - seg.vmaddr;
+        file->base_addr = (intptr_t)im.imageLoadAddress - seg.vmaddr;
       }
-      gimli_add_mapping(of->objname,
-        (void*)(intptr_t)(seg.vmaddr + of->base_addr), seg.vmsize, seg.fileoff);
+      gimli_add_mapping(proc, file->objname,
+        (gimli_addr_t)(seg.vmaddr + file->base_addr), seg.vmsize, seg.fileoff);
 
       if (!strcmp(seg.segname, "__TEXT")) {
         /* look for an __eh_frame section */
             s->size = sec.size;
             s->data = malloc(s->size);
             s->offset = sec.offset + hdr_offset;
-            s->container = of->elf;
+            s->container = file->elf;
             pread(fd, s->data, s->size, s->offset);
 
-            gimli_hash_insert(of->sections, s->name, s);
+            gimli_hash_insert(file->sections, s->name, s);
           }
         }
       }
 
     }
-    find_dwarf_dSYM(of);
+    find_dwarf_dSYM(file);
   }
 }
 
   }
 }
 
-int gimli_attach(int pid)
+gimli_err_t gimli_attach(gimli_proc_t proc)
 {
   kern_return_t rc;
   mach_msg_type_number_t n;
-  struct gimli_thread_state *threads;
+  struct gimli_thread_state *thr;
   thread_act_port_array_t threadlist;
   int i;
 
    * See also taskgated(8)
    */
   make_authz_request();
-  target_pid = pid;
-  rc = task_for_pid(mach_task_self(), pid, &targetTask);
+  target_pid = proc->pid;
+  rc = task_for_pid(mach_task_self(), proc->pid, &targetTask);
   if (rc != KERN_SUCCESS) {
     /* this will usually fail unless you call this from the
      * parent of the faulting process, or have root */
 "http://sourceware.org/gdb/wiki/BuildingOnDarwin\n"
 "http://developer.apple.com/library/mac/#documentation/Security/Conceptual/CodeSigningGuide/Procedures/Procedures.html#//apple_ref/doc/uid/TP40005929-CH4-SW1\n"
 , rc);
-    return 0;
+    return GIMLI_ERR_PERM;
   }
   got_task = 1;
   task_suspend(targetTask);
 
-  discover_maps();
+  discover_maps(proc);
 
   rc = task_threads(targetTask, &threadlist, &n);
 
   if (rc == KERN_SUCCESS) {
-    threads = calloc(n, sizeof(*threads));
-
     for (i = 0; i < n; i++) {
 #ifdef __x86_64__
       x86_thread_state64_t ts;
       mach_msg_type_number_t count = x86_THREAD_STATE64_COUNT;
 
+      thr = gimli_proc_thread_by_lwpid(proc, i, 1);
       memset(&ts, 0, sizeof(ts));
       rc = thread_get_state(threadlist[i], x86_THREAD_STATE64,
           (thread_state_t)&ts, &count);
       if (rc == KERN_SUCCESS) {
-        memcpy(&threads[i].regs, &ts, sizeof(ts));
-        threads[i].pc = (void*)ts.GIMLI_DARWIN_REGNAME(rip);
-        threads[i].fp = (void*)ts.GIMLI_DARWIN_REGNAME(rbp);
-        threads[i].sp = (void*)ts.GIMLI_DARWIN_REGNAME(rsp);
+        memcpy(&thr->regs, &ts, sizeof(ts));
+        thr->pc = (void*)ts.GIMLI_DARWIN_REGNAME(rip);
+        thr->fp = (void*)ts.GIMLI_DARWIN_REGNAME(rbp);
+        thr->sp = (void*)ts.GIMLI_DARWIN_REGNAME(rsp);
       }
 #elif defined(__i386__)
       x86_thread_state32_t ts;
       mach_msg_type_number_t count = x86_THREAD_STATE32_COUNT;
 
+      thr = gimli_proc_thread_by_lwpid(proc, i, 1);
       memset(&ts, 0, sizeof(ts));
       rc = thread_get_state(threadlist[i], x86_THREAD_STATE32,
           (thread_state_t)&ts, &count);
       if (rc == KERN_SUCCESS) {
-        memcpy(&threads[i].regs, &ts, sizeof(ts));
-        threads[i].pc = (void*)ts.GIMLI_DARWIN_REGNAME(eip);
-        threads[i].fp = (void*)ts.GIMLI_DARWIN_REGNAME(ebp);
-        threads[i].sp = (void*)ts.GIMLI_DARWIN_REGNAME(esp);
+        memcpy(&thr->regs, &ts, sizeof(ts));
+        thr->pc = (void*)ts.GIMLI_DARWIN_REGNAME(eip);
+        thr->fp = (void*)ts.GIMLI_DARWIN_REGNAME(ebp);
+        thr->sp = (void*)ts.GIMLI_DARWIN_REGNAME(esp);
       }
 #else
 # error unknown architecture
 #endif
     }
-    gimli_nthreads = n;
-    gimli_threads = threads;
   }
-  return 1;
+  return GIMLI_ERR_OK;
 }
 
 int gimli_init_unwind(struct gimli_unwind_cursor *cur,
   } frame;
   struct gimli_unwind_cursor c;
 
-  if (gimli_is_signal_frame(cur)) {
+  if (0 && gimli_is_signal_frame(cur)) {
 #if defined(__x86_64__)
     _STRUCT_MCONTEXT64 mctx;
     
-    if (gimli_read_mem(cur->st.fp + GIMLI_KERNEL_MCTX64, &mctx,
+    if (gimli_read_mem(cur->proc, (gimli_addr_t)cur->st.fp + GIMLI_KERNEL_MCTX64, &mctx,
         sizeof(mctx)) != sizeof(mctx)) {
       fprintf(stderr, "unable to read old context\n");
       return 0;
     }
 #if 0
-#define SHOWREG(n) fprintf(stderr, #n ": %p\n", mctx.GIMLI_DARWIN_REGNAME(ss).GIMLI_DARWIN_REGNAME(n));
+#define SHOWREG(n) fprintf(stderr, #n ": " PTRFMT "\n", mctx.GIMLI_DARWIN_REGNAME(ss).GIMLI_DARWIN_REGNAME(n));
     SHOWREG(rax);
     SHOWREG(rbx);
     SHOWREG(rcx);
   }
 
   if (c.st.fp) {
-    if (gimli_read_mem(c.st.fp, &frame, sizeof(frame)) != sizeof(frame)) {
+    if (gimli_read_mem(cur->proc, (gimli_addr_t)c.st.fp,
+          &frame, sizeof(frame)) != sizeof(frame)) {
       memset(&frame, 0, sizeof(frame));
     }
     if (debug) {
   return 0;
 }
 
-int gimli_detach(void)
+gimli_err_t gimli_detach(gimli_proc_t proc)
 {
   if (got_task) {
     task_resume(targetTask);
   return 0;
 }
 
-int gimli_read_mem(void *src, void *dest, int len)
+int gimli_read_mem(gimli_proc_t proc, gimli_addr_t src, void *dest, int len)
 {
   kern_return_t rc;
   vm_size_t dataCnt = len;
     memset(&cur->si, 0, sizeof(cur->si));
     return 1;
   }
-  if (sigtramp && cur->st.pc >= sigtramp && cur->st.pc <= sigtramp + 0xff) {
+  if (sigtramp && (gimli_addr_t)cur->st.pc >= sigtramp &&
+      (gimli_addr_t)cur->st.pc <= sigtramp + 0xff) {
 #if defined(__x86_64__)
-    if (gimli_read_mem(cur->st.fp + GIMLI_KERNEL_SIGINFO64,
+    /* I can see the pointer in rsi when I used gdb on the target,
+     * but we don't have a valid register set here when we need it :-/ */
+    if (gimli_read_mem(cur->proc,
+        cur->st.regs.GIMLI_DARWIN_REGNAME(rsi),
         &cur->si, sizeof(cur->si)) != sizeof(cur->si)) {
       memset(&cur->si, 0, sizeof(cur->si));
     }
     return 1;
 #elif defined(__i386__)
     struct gimli_kernel_sigframe32 *f = cur->st.fp;
-    if (gimli_read_mem(&f->si, &cur->si, sizeof(cur->si)) != sizeof(cur->si)) {
+    if (gimli_read_mem(cur->proc, (gimli_addr_t)&f->si,
+          &cur->si, sizeof(cur->si)) != sizeof(cur->si)) {
       memset(&cur->si, 0, sizeof(cur->si));
     }
     return 1;
 int gimli_demangle(const char *mangled, char *out, int out_size)
 {
   State state;
+
+#ifdef __MACH__
+  /* skip leading '_' that is present on this platform */
+  mangled++;
+#endif
   InitState(&state, mangled, out, out_size);
   return (ParseMangledName(&state) &&
           state.overflowed == false &&

File dwarf-expr.c

     return 0;
   }
   e->stack[++e->top] = *v;
-  if (debug) printf("push: sp=%d %llx\n", e->top, e->stack[e->top].v.u64);
+  if (debug) printf("push: sp=%d %" PRIx64 "\n", e->top, e->stack[e->top].v.u64);
   return 1;
 }
 
     return 0;
   }
   *v = e->stack[e->top--];
-  if (debug) printf("pop: sp=%d %llx\n", e->top, v->v.u64);
+  if (debug) printf("pop: sp=%d %" PRIx64 "\n", e->top, v->v.u64);
   return 1;
 }
 
-static int deref(uint64_t addr, uint64_t *resp, uint8_t opsize)
+static int deref(gimli_proc_t proc, uint64_t ptr, uint64_t *resp, uint8_t opsize)
 {
   uint8_t u8;
   uint16_t u16;
   uint32_t u32;
   uint64_t u64;
   int res;
-  void *ptr = (void*)(intptr_t)addr;
 
   switch (opsize) {
     case 1:
-      res = gimli_read_mem(ptr, &u8, opsize);
+      res = gimli_read_mem(proc, ptr, &u8, opsize);
       u64 = u8;
       break;
     case 2:
-      res = gimli_read_mem(ptr, &u16, opsize);
+      res = gimli_read_mem(proc, ptr, &u16, opsize);
       u64 = u16;
       break;
     case 4:
-      res = gimli_read_mem(ptr, &u32, opsize);
+      res = gimli_read_mem(proc, ptr, &u32, opsize);
       u64 = u32;
       break;
     case 8:
-      res = gimli_read_mem(ptr, &u64, opsize);
+      res = gimli_read_mem(proc, ptr, &u64, opsize);
       break;
   }
   if (res != opsize) {
-    fprintf(stderr, "DWARF: expr: unable to deref %d bytes from %p\n",
+    fprintf(stderr, "DWARF: expr: unable to deref %d bytes from " PTRFMT "\n",
       opsize, ptr);
     return 0;
   }
-  if (debug) printf("deref: addr=%p opsize=%d res=%llx\n", ptr, opsize, res);
+  if (debug) printf("deref: addr=" PTRFMT " opsize=%d res=0x%x\n", ptr, opsize, res);
   *resp = res;
   return 1;
 }
       val.is_signed = 0;
       val.is_stack = 1;
       if (!get_reg(cur, op - DW_OP_breg0, &val.v.u64)) return 0;
-      if (debug) printf("OP_breg%d val=%llx\n", op - DW_OP_breg0, val.v.u64);
+      if (debug) printf("OP_breg%d val=%" PRIx64 "\n", op - DW_OP_breg0, val.v.u64);
       val.v.u64 += s64;
       if (!push(&e, &val)) return 0;
       continue;
       val.is_signed = 0;
       val.is_stack = 0;
       if (!get_reg(cur, op - DW_OP_reg0, &val.v.u64)) return 0;
-      if (debug) printf("OP_reg%d -> %llx\n", op - DW_OP_reg0, val.v.u64);
+      if (debug) printf("OP_reg%d -> %" PRIx64 "\n", op - DW_OP_reg0, val.v.u64);
       if (!push(&e, &val)) return 0;
       continue;
     }
           memcpy(&val.v.u64, e.ops, sizeof(val.v.u64));
           e.ops += sizeof(val.v.u64);
         }
-        if (debug) printf("OP_addr: %llx\n", val.v.u64);
+        if (debug) printf("OP_addr: %" PRIx64 "\n", val.v.u64);
         if (!push(&e, &val)) return 0;
         continue;
 
         val.is_signed = 0;
         val.is_stack = 1;
         val.v.u64 = u8;
-        if (debug) printf("OP_const1u: %llx\n", val.v.u64);
+        if (debug) printf("OP_const1u: %" PRIx64 "\n", val.v.u64);
         if (!push(&e, &val)) return 0;
         continue;
 
         val.is_signed = 1;
         val.is_stack = 1;
         val.v.s64 = s8;
-        if (debug) printf("OP_const1s: %llx\n", val.v.u64);
+        if (debug) printf("OP_const1s: %" PRIx64 "\n", val.v.u64);
         if (!push(&e, &val)) return 0;
         continue;
 
         val.is_signed = 0;
         val.is_stack = 1;
         val.v.u64 = u16;
-        if (debug) printf("OP_const2u: %llx\n", val.v.u64);
+        if (debug) printf("OP_const2u: %" PRIx64 "\n", val.v.u64);
         if (!push(&e, &val)) return 0;
         continue;
 
         val.is_signed = 1;
         val.is_stack = 1;
         val.v.s64 = s16;
-        if (debug) printf("OP_const2s: %llx\n", val.v.u64);
+        if (debug) printf("OP_const2s: %" PRIx64 "\n", val.v.u64);
         if (!push(&e, &val)) return 0;
         continue;
 
         val.is_signed = 0;
         val.is_stack = 1;
         val.v.u64 = u32;
-        if (debug) printf("OP_const4u: %llx\n", val.v.u64);
+        if (debug) printf("OP_const4u: %" PRIx64 "\n", val.v.u64);
         if (!push(&e, &val)) return 0;
         continue;
 
         val.is_signed = 1;
         val.is_stack = 1;
         val.v.s64 = s32;
-        if (debug) printf("OP_const4s: %llx\n", val.v.u64);
+        if (debug) printf("OP_const4s: %" PRIx64 "\n", val.v.u64);
         if (!push(&e, &val)) return 0;
         continue;
 
         memcpy(&val.v.u64, e.ops, sizeof(val.v.u64));
         val.is_signed = 0;
         val.is_stack = 1;
-        if (debug) printf("OP_const8u: %llx\n", val.v.u64);
+        if (debug) printf("OP_const8u: %" PRIx64 "\n", val.v.u64);
         if (!push(&e, &val)) return 0;
         continue;
 
         memcpy(&val.v.s64, e.ops, sizeof(val.v.s64));
         val.is_signed = 1;
         val.is_stack = 1;
-        if (debug) printf("OP_const8s: %llx\n", val.v.u64);
+        if (debug) printf("OP_const8s: %" PRIx64 "\n", val.v.u64);
         if (!push(&e, &val)) return 0;
         continue;
 
         val.v.u64 = dw_read_uleb128(&e.ops, e.end);
         val.is_signed = 0;
         val.is_stack = 1;
-        if (debug) printf("OP_constu: %llx\n", val.v.u64);
+        if (debug) printf("OP_constu: %" PRIx64 "\n", val.v.u64);
         if (!push(&e, &val)) return 0;
         continue;
 
         val.v.s64 = dw_read_leb128(&e.ops, e.end);
         val.is_signed = 1;
         val.is_stack = 1;
-        if (debug) printf("OP_consts: %llx\n", val.v.u64);
+        if (debug) printf("OP_consts: %" PRIx64 "\n", val.v.u64);
         if (!push(&e, &val)) return 0;
         continue;
 
         val.is_signed = 0;
         val.is_stack = 1;
         val.v.u64 = frame_base + s64;
-        if (debug) printf("OP_fbreg: %llx\n", val.v.u64);
+        if (debug) printf("OP_fbreg: %" PRIx64 "\n", val.v.u64);
         if (!push(&e, &val)) return 0;
         continue;
 
         val.is_stack = 1;
         if (!get_reg(cur, u64, &val.v.u64)) return 0;
         val.v.u64 += s64;
-        if (debug) printf("OP_breg%d: %llx\n", u64, val.v.u64);
+        if (debug) printf("OP_breg%" PRId64 ": %" PRIx64 "\n", u64, val.v.u64);
         if (!push(&e, &val)) return 0;
         continue;
 
         val.is_signed = 0;
         val.is_stack = 0;
         if (!get_reg(cur, u64, &val.v.u64)) return 0;
-        if (debug) printf("OP_reg%d\n", u64);
+        if (debug) printf("OP_reg%" PRId64 "\n", u64);
         if (!push(&e, &val)) return 0;
         continue;
-       
+
       case DW_OP_dup:
         val = e.stack[e.top];
         if (debug) printf("OP_dup\n");
       case DW_OP_pick:
         memcpy(&u8, e.ops, sizeof(u8));
         e.ops += sizeof(u8);
-        if (debug) printf("OP_pick %u\n", u8);
+        if (debug) printf("OP_pick %" PRIu8 "\n", u8);
         if (e.top - u8 < 0) {
-          fprintf(stderr, "DWARF:expr: DW_OP_pick(%d): stack underflow\n");
+          fprintf(stderr, "DWARF:expr: DW_OP_pick(%" PRIu8 "): stack underflow\n", u8);
           return 0;
         }
         val = e.stack[e.top - u8];
 
       case DW_OP_deref:
         if (!pop(&e, &val)) return 0;
-        if (!deref(val.v.u64, &u64, sizeof(void*))) return 0;
+        if (!deref(cur->proc, val.v.u64, &u64, sizeof(void*))) return 0;
         val.is_signed = 0;
         val.is_stack = 1;
         if (!push(&e, &val)) return 0;
       case DW_OP_deref_size:
         memcpy(&u8, e.ops, sizeof(u8));
         if (!pop(&e, &val)) return 0;
-        if (!deref(val.v.u64, &u64, u8)) return 0;
+        if (!deref(cur->proc, val.v.u64, &u64, u8)) return 0;
         val.is_signed = 0;
         val.is_stack = 1;
         if (!push(&e, &val)) return 0;
       case DW_OP_nop:
         continue;
 
+      case DW_OP_stack_value:
+        /* The DW_OP_stack_value operation specifies that the object does not
+         * exist in memory but its value is nonetheless known and is at the top
+         * of the DWARF expression stack. In this form of location description,
+         * the DWARF expression represents the actual value of the object,
+         * rather than its location. The DW_OP_stack_value operation terminates
+         * the expression.
+         *
+         * Unfortunately, we're focused around expressions returning
+         * addresses rather than values, so while it is simple to
+         * break here to obtain the desired value, we have no way to convey
+         * that result back to the caller at this time.
+         */
+        return 0;
+
+      case DW_OP_piece: /* similar reasoning to DW_OP_stack_value above */
       default:
-        fprintf(stderr, "DWARF: expr: unhandled op %02x\n", op);
+        fprintf(stderr, "DWARF: expr: unhandled op 0x%02x\n", op);
         return 0;
     }
   }
 
   if (is_stack) *is_stack = e.stack[e.top].is_stack;
   *result = e.stack[e.top].v.u64;
-  if (debug) printf("eval expr: result=%llx\n", *result);
+  if (debug) printf("eval expr: result=%" PRIx64 "\n", *result);
   return 1;
 }
 

File dwarf-read.c

 /*
- * Copyright (c) 2009-2010 Message Systems, Inc. All rights reserved
+ * Copyright (c) 2009-2012 Message Systems, Inc. All rights reserved
  * For licensing information, see:
  * https://bitbucket.org/wez/gimli/src/tip/LICENSE
  */
 #include "impl.h"
 #include "gimli_dwarf.h"
+static gimli_addr_t calc_reloc(gimli_mapped_object_t f);
 
 struct dw_die_arange {
   uint64_t addr;
   uint64_t di_offset;
 };
 
-/* when rendering parameters, remember what we've already done */
-static gimli_hash_t derefed_params = NULL;
-
-
-static void local_hexdump(void *addr, int p, int n);
-
 uint64_t dw_read_uleb128(const uint8_t **ptr, const uint8_t *end)
 {
   uint64_t res = 0;
   return res;
 }
 
-int dw_read_encptr(uint8_t enc, const uint8_t **ptr, const uint8_t *end,
+int dw_read_encptr(gimli_proc_t proc,
+  uint8_t enc, const uint8_t **ptr, const uint8_t *end,
   uint64_t pc, uint64_t *output)
 {
   const uint8_t *cur = *ptr;
     return 0;
 
     if (sizeof(void*) == 8) {
-      if (gimli_read_mem((void*)(intptr_t)res, &res, sizeof(res))
+      if (gimli_read_mem(proc, res, &res, sizeof(res))
           != sizeof(*output)) {
         return 0;
       }
     } else {
       uint32_t r;
-      if (gimli_read_mem((void*)(intptr_t)res, &r, sizeof(r)) != sizeof(r)) {
+      if (gimli_read_mem(proc, res, &r, sizeof(r)) != sizeof(r)) {
         return 0;
       }
       res = r;
       break;
     case DW_EH_PE_datarel:
     default:
-      fprintf(stderr, "DWARF: unhandled pointer application value: %02x at %p\n", enc & DW_EH_PE_APPL_MASK, pc);
+      fprintf(stderr, "DWARF: unhandled pointer application value: %02x at %p\n", enc & DW_EH_PE_APPL_MASK, (void*)pc);
       return 0;
   }
 
       }
       break;
     default:
-      fprintf(stderr, "DWARF: unhandled DW_EH_PE value: 0x%02x (masked to 0x%02x) at %p\n", enc, enc & 0x0f, pc);
+      fprintf(stderr, "DWARF: unhandled DW_EH_PE value: 0x%02x (masked to 0x%02x) at %p\n", enc, enc & 0x0f, (void*)pc);
       return 0;
   }
 
   return a->addr - b->addr;
 }
 
-static int search_compare_line(const void *pc, const void *L)
+static int search_compare_line(const void *addrp, const void *L)
 {
   struct gimli_line_info *line = (struct gimli_line_info*)L;
+  gimli_addr_t pc = *(gimli_addr_t*)addrp;
 
   if (pc < line->addr) {
     return -1;
   return 1;
 }
 
+static int process_line_numbers(gimli_mapped_object_t f);
+
 /* read dwarf info to determine the source/line information for a given
  * address */
-int dwarf_determine_source_line_number(void *pc, char *src, int srclen,
+int gimli_determine_source_line_number(gimli_proc_t proc,
+  gimli_addr_t pc, char *src, int srclen,
   uint64_t *lineno)
 {
   struct gimli_object_mapping *m;
-  struct gimli_object_file *f;
+  gimli_mapped_object_t f;
   struct gimli_line_info *linfo;
 
-  m = gimli_mapping_for_addr(pc);
-  if (!m) return 0;
+  m = gimli_mapping_for_addr(proc, pc);
+  if (!m) {
+    return 0;
+  }
   f = m->objfile;
 
   if (!f->elf) {
     /* can happen if the original file has been removed from disk */
     return 0;
   }
-
-  if (!gimli_object_is_executable(f->elf)) {
-    pc -= (intptr_t)m->base;
+  if (!f->lines) {
+    process_line_numbers(f);
+    if (!f->lines) {
+      return 0;
+    }
   }
 
-  linfo = bsearch(pc, f->lines, f->linecount, sizeof(*linfo),
+#ifdef __MACH__
+  pc -= f->base_addr;
+#else
+  if (!gimli_object_is_executable(f->elf)) {
+    pc -= calc_reloc(f);
+  }
+#endif
+
+  linfo = bsearch(&pc, f->lines, f->linecount, sizeof(*linfo),
       search_compare_line);
 
   if (linfo) {
 }
 
 
-static int process_line_numbers(struct gimli_object_file *f)
+static int process_line_numbers(gimli_mapped_object_t f)
 {
   struct gimli_section_data *s = NULL;
   struct {
   const char *filenames[1024];
   uint8_t op;
   struct gimli_line_info *linfo;
+  int debugline = debug && 0;
 
   if (f->aux_elf) {
     s = gimli_get_section_by_name(f->aux_elf, ".debug_line");
   if (!s) {
     return 0;
   }
-  if (debug) fprintf(stderr, "\nGot debug_line info\n");
+  if (debugline) fprintf(stderr, "\nGot debug_line info\n");
 
   end = data + s->size;
 
     memcpy(&ver, data, sizeof(ver));
     data += sizeof(ver);
 
-    if (debug) {
-      fprintf(stderr, "initlen is %llx (%d bit) ver=%u\n", 
+    if (debugline) {
+      fprintf(stderr, "initlen is 0x%" PRIx64 " (%d bit) ver=%u\n",
         len, is_64 ? 64 : 32, ver);
     }
 
     data += sizeof(hdr_1);
     regs.is_stmt = hdr_1.def_is_stmt;
 
-    if (debug) {
+    if (debugline) {
       fprintf(stderr,
-        "headerlen is %llu, min_insn_len=%u line_base=%d line_range=%u\n"
+        "headerlen is %" PRIu64 ", min_insn_len=%u line_base=%d line_range=%u\n"
         "opcode_base=%u\n",
         len, hdr_1.min_insn_len, hdr_1.line_base, hdr_1.line_range,
         hdr_1.opcode_base);
     opcode_lengths = calloc(hdr_1.opcode_base, sizeof(uint64_t));
     for (i = 1; i < hdr_1.opcode_base; i++) {
       opcode_lengths[i-1] = dw_read_uleb128(&data, cuend);
-      if (debug) {
-        fprintf(stderr, "op len [%d] = %llu\n", i, opcode_lengths[i-1]);
+      if (debugline) {
+        fprintf(stderr, "op len [%d] = %" PRIu64 "\n", i, opcode_lengths[i-1]);
       }
     }
     /* include_directories */
     while (*data && data < cuend) {
-      if (debug) fprintf(stderr, "inc_dir: %s\n", data);
+      if (debugline) fprintf(stderr, "inc_dir: %s\n", data);
       data += strlen((char*)data) + 1;
     }
     data++;
         fprintf(stderr, "DWARF: too many files for line number info reader\n");
         return 0;
       }
-      if (debug) fprintf(stderr, "file[%d] = %s\n", i, data);
+      if (debugline) fprintf(stderr, "file[%d] = %s\n", i, data);
       filenames[i] = (char*)data;
       data += strlen((char*)data) + 1;
       /* ignore additional data about the file */
             {
               void *addr;
               memcpy(&addr, data, sizeof(addr));
-              if (debug) fprintf(stderr, "set_address %p\n", addr);
+              if (debugline) fprintf(stderr, "set_address %p\n", addr);
               regs.address = addr;
               break;
             }
           case DW_LNE_end_sequence:
             {
-              if (debug) fprintf(stderr, "end_sequence\n");
+              if (debugline) fprintf(stderr, "end_sequence\n");
               memset(&regs, 0, sizeof(regs));
               regs.file = 1;
               regs.line = 1;
               data += strlen(fname)+1;
               fno = dw_read_uleb128(&data, cuend);
               filenames[fno] = fname;
-              if (debug) fprintf(stderr, "define_files[%d] = %s\n", fno, fname);
+              if (debugline) fprintf(stderr, "define_files[%" PRIu64 "] = %s\n", fno, fname);
               break;
             }
 
           default:
-            fprintf(stderr,
-              "DWARF: line nos.: unhandled extended op=%02x, len=%llu\n",
-              op, initlen);
+//            fprintf(stderr,
+//              "DWARF: line nos.: unhandled extended op=%02x, len=%" PRIu32 "\n",
+//              op, initlen);
             ;
         }
         data = next;
         /* standard opcode */
         switch (op) {
           case DW_LNS_copy:
-            if (debug) fprintf(stderr, "copy\n");
+            if (debugline) fprintf(stderr, "copy\n");
             regs.basic_block = 0;
             regs.prologue_end = 0;
             regs.epilogue_begin = 0;
           case DW_LNS_advance_line:
             {
               int64_t d = dw_read_leb128(&data, cuend);
-              if (debug) {
-                fprintf(stderr, "advance_line from %lld to %lld\n",
+              if (debugline) {
+                fprintf(stderr, "advance_line from %" PRId64 " to %" PRId64 "\n",
                   regs.line, regs.line + d);
               }
               regs.line += d;
             {
               uint64_t u = dw_read_uleb128(&data, cuend);
               regs.address += u * hdr_1.min_insn_len;
-              if (debug) {
-                fprintf(stderr, "advance_pc: addr=%llx\n", regs.address);
+              if (debugline) {
+                fprintf(stderr, "advance_pc: addr=0x%" PRIx64 "\n", (uintptr_t)regs.address);
               }
               break;
             }
           {
             uint64_t u = dw_read_uleb128(&data, cuend);
             regs.file = u;
-            if (debug) fprintf(stderr, "set_file: %llu\n", regs.file);
+            if (debugline) fprintf(stderr, "set_file: %" PRIu64 "\n", regs.file);
             break;
           }
           case DW_LNS_set_column:
           {
             uint64_t u = dw_read_uleb128(&data, cuend);
             regs.column = u;
-            if (debug) fprintf(stderr, "set_column: %llu\n", regs.column);
+            if (debugline) fprintf(stderr, "set_column: %" PRIu64 "\n", regs.column);
             break;
           }
           case DW_LNS_negate_stmt:
-            if (debug) fprintf(stderr, "negate_stmt\n");
+            if (debugline) fprintf(stderr, "negate_stmt\n");
             regs.is_stmt = !regs.is_stmt;
             break;
           case DW_LNS_set_basic_block:
-            if (debug) fprintf(stderr, "set_basic_block\n");
+            if (debugline) fprintf(stderr, "set_basic_block\n");
             regs.basic_block = 1;
             break;
           case DW_LNS_const_add_pc:
             regs.address += ((255 - hdr_1.opcode_base) /
                             hdr_1.line_range) * hdr_1.min_insn_len;
-            if (debug) {
-              fprintf(stderr, "const_add_pc: addr=%llx\n", regs.address);
+            if (debugline) {
+              fprintf(stderr, "const_add_pc: addr=0x%" PRIx64 "\n", (uintptr_t)regs.address);
             }
             break;
           case DW_LNS_fixed_advance_pc:
             memcpy(&u, data, sizeof(u));
             data += sizeof(u);
             regs.address += u;
-            if (debug) {
-              fprintf(stderr, "fixed_advance_pc: %llx\n", regs.address);
+            if (debugline) {
+              fprintf(stderr, "fixed_advance_pc: 0x%" PRIx64 "\n", (uintptr_t)regs.address);
             }
             break;
           }
           case DW_LNS_set_prologue_end:
-            if (debug) {
+            if (debugline) {
               fprintf(stderr, "set_prologue_end\n");
             }
             regs.prologue_end = 1;
             break;
           case DW_LNS_set_epilogue_begin:
-            if (debug) {
+            if (debugline) {
               fprintf(stderr, "set_epilogue_begin\n");
             }
             regs.epilogue_begin = 1;
             break;
           case DW_LNS_set_isa:
             regs.isa = dw_read_uleb128(&data, cuend);
-            if (debug) {
-              fprintf(stderr, "set_isa: %llx\n", regs.isa);
+            if (debugline) {
+              fprintf(stderr, "set_isa: 0x%" PRIx64 "\n", regs.isa);
             }
             break;
           default:
         /* special opcode */
         op -= hdr_1.opcode_base;
 
-        if (debug) {
-          fprintf(stderr, "special before: addr = %p, line = %lld\n",
+        if (debugline) {
+          fprintf(stderr, "special before: addr = %p, line = %" PRId64 "\n",
               regs.address, regs.line);
           fprintf(stderr, "line_base = %d, line_range = %d\n",
             hdr_1.line_base, hdr_1.line_range);
 
         regs.address += (op / hdr_1.line_range) * hdr_1.min_insn_len;
         regs.line += hdr_1.line_base + (op % hdr_1.line_range);
-        if (debug) {
-          fprintf(stderr, "special: addr = %p, line = %lld\n",
+        if (debugline) {
+          fprintf(stderr, "special: addr = %p, line = %" PRId64 "\n",
             regs.address, regs.line);
         }
       }
 
 
       if (regs.address && filenames[regs.file]) {
-        f->lines = realloc(f->lines, (f->linecount + 1) * sizeof(*linfo));
+        if (f->linecount + 1 >= f->linealloc) {
+          f->linealloc = f->linealloc ? f->linealloc * 2 : 1024;
+          f->lines = realloc(f->lines, f->linealloc * sizeof(*linfo));
+        }
         linfo = &f->lines[f->linecount++];
-        linfo->filename = (char*)filenames[regs.file];
+        linfo->filename = filenames[regs.file];
         linfo->lineno = regs.line;
-        linfo->addr = regs.address;
+        linfo->addr = (gimli_addr_t)regs.address;
       }
     }
   }
 
   qsort(f->lines, f->linecount, sizeof(struct gimli_line_info), sort_by_addr);
+//printf("sorting %d lines in %s\n", f->linecount, f->objname);
+
+  free(opcode_lengths);
 
   /* make a pass to fill in the end member to make it easier to find
    * an approx match */
-  for (i = 0; i < f->linecount - 1; i++) {
-    f->lines[i].end = f->lines[i+1].addr;
+  if (f->linecount) {
+    for (i = 0; i < f->linecount - 1; i++) {
+      f->lines[i].end = f->lines[i+1].addr;
+    }
   }
 
   return 0;
 }
 
-int gimli_process_dwarf(struct gimli_object_file *f)
-{
-  /* pull out additional information from dwarf debugging information.
-   * In particular, we can scan the .debug_info section to resolve
-   * function names into symbols for the back trace code */
-
-  if (f->elf) {
-    process_line_numbers(f);
-  }
-
-  return 1;
-}
-
-static void local_hexdump(void *addr, int p, int n)
-{
-  uint32_t data[4];
-  int i, j;
-  int x;
-  struct gimli_symbol *sym;
-  char buf[16];
-
-  addr = (char*)addr - (p * sizeof(data));
-
-  for (i = 0; i < n; i++) {
-    memcpy(data, addr, sizeof(data));
-    printf("%p:   ", addr);
-    for (j = 0; j < 4; j++) {
-      printf("     %08x", data[j]);
-    }
-    printf("\n");
-
-    addr += sizeof(data);
-  }
-}
-
-static int get_sect_data(struct gimli_object_file *f, const char *name,
-  const uint8_t **startptr, const uint8_t **endptr, gimli_object_file_t **elf)
+static int get_sect_data(gimli_mapped_object_t f, const char *name,
+  const uint8_t **startptr, const uint8_t **endptr, gimli_object_file_t *elf)
 {
   const uint8_t *data = NULL, *end = NULL;
   struct gimli_section_data *s;
 int dw_calc_location(struct gimli_unwind_cursor *cur,
   uint64_t compilation_unit_base_addr,
   struct gimli_object_mapping *m, uint64_t offset, uint64_t *res,
-  gimli_object_file_t *elf, int *is_stack)
+  gimli_object_file_t elf, int *is_stack)
 {
   const uint8_t *data, *end;
   void *rstart = NULL, *rend = NULL;
 
 //  printf("Using offset %d into .debug_loc\n", offset);
   data += offset;
-//  local_hexdump(data, 0, 20);
 
   while (data < end) {
 //    printf("populating rstart with %d bytes\n", sizeof(rstart));
 }
 
 
-static const uint8_t *find_abbr(const uint8_t *abbr, const uint8_t *end,
-  uint64_t fcode)
+static const uint8_t *find_abbr(gimli_mapped_object_t file,
+    uint64_t da_offset,
+    uint64_t fcode)
 {
   uint64_t code;
   uint64_t tag;
+  uint64_t key;
+  const uint8_t *abbr;
+  int slow_mode = 0;
 
-  while (abbr < end) {
-    code = dw_read_uleb128(&abbr, end);
+  if (!file->abbr.map) {
+    if (!get_sect_data(file, ".debug_abbrev",
+          &file->abbr.start, &file->abbr.end, &file->abbr.elf)) {
+      printf("could not get abbrev data for %s\n", file->objname);
+      return 0;
+    }
+
+    /* observed approx 11-13 per abbrev, err on the side of avoiding
+     * rebuckets */
+    file->abbr.map = gimli_hash_new_size(NULL, GIMLI_HASH_U64_KEYS,
+        (file->abbr.end - file->abbr.start) / 10);
+  }
+
+  /* NOTE: even though DWARF allows for 64-bit offsets, we're making the assumption
+   * that they are not practical or possible for the next few years.
+   * Doing so allows us to cheaply record both the da_offset and code
+   * into a u64 key.
+   * I've observed approx 17% collisions with a max chain length of 7
+   * in a collided bucket.  It's not perfect but it is effective.
+   * */
+  if (da_offset > UINT32_MAX || fcode > UINT32_MAX) {
+    // Allow correct, albeit slow, operation when we overflow this assumption
+    slow_mode = 1;
+  }
+  if (!slow_mode) {
+    key = (da_offset << 32) | (fcode & 0xffffffff);
+    if (gimli_hash_find_u64(file->abbr.map, key, (void**)&abbr)) {
+      return abbr;
+    }
+  }
+
+  abbr = file->abbr.start + da_offset;
+
+  while (abbr < file->abbr.end) {
+    code = dw_read_uleb128(&abbr, file->abbr.end);
     if (code == 0) continue;
 //    printf("find_abbr: %lld (looking for %lld)\n", code, fcode);
-    if (fcode == code) return abbr;
+    if (fcode == code) {
 
-    tag = dw_read_uleb128(&abbr, end);
+//printf("find_abbr: %" PRIx64 " -> %p\n", fcode, abbr);
+      if (!slow_mode &&
+          !gimli_hash_insert_u64(file->abbr.map, key, (void*)abbr)) {
+        void *ptr = NULL;
+        gimli_hash_find_u64(file->abbr.map, key, &ptr);
+        if (ptr != abbr) {
+          printf("find_abbr: %" PRIx64 " (key=%" PRIx64 ") collided with %p and %p\n",
+              fcode, key, abbr, ptr);
+        }
+      }
+      return abbr;
+    }
+
+    tag = dw_read_uleb128(&abbr, file->abbr.end);
     abbr += sizeof(uint8_t);
 
 
-    while (abbr < end) {
-      dw_read_uleb128(&abbr, end);
-      code = dw_read_uleb128(&abbr, end);
+    while (abbr < file->abbr.end) {
+      dw_read_uleb128(&abbr, file->abbr.end);
+      code = dw_read_uleb128(&abbr, file->abbr.end);
       if (code == 0) {
         break;
       }
 static uint64_t get_value(uint64_t form, uint64_t addr_size, int is_64,
   const uint8_t **datap, const uint8_t *end,
   uint64_t *vptr, const uint8_t **byteptr,
-  gimli_object_file_t *elf)
+  gimli_object_file_t elf)
 {
   uint64_t u64;
   int64_t s64;
       *vptr = strlen((char*)data);
       data += 1 + *vptr;
       break;
-    
+
     case DW_FORM_indirect:
       form = dw_read_uleb128(datap, end);
       if (form == DW_FORM_indirect) {
       return get_value(form, addr_size, is_64, datap, end, vptr, byteptr, elf);
 
     default:
-      printf("DWARF: unhandled FORM: 0x%llx\n", form);
+      printf("DWARF: unhandled FORM: 0x%" PRIx64 "\n", form);
       return 0;
   }
 
       form = DW_FORM_ref_udata;
       break;
   }
-  if (debug) {
-  printf("value normalized to form 0x%llx val=0x%llx bytep=%p %s\n",
+  if (debug && 0) {
+    printf("value normalized to form 0x%" PRIx64 " val=0x%" PRIx64 " bytep=%p %s\n",
        form, *vptr, *byteptr, form == DW_FORM_string ? (char*)*byteptr : "");
   }
 
   return form;
 }
 
-
 static struct gimli_dwarf_die *process_die(
-  uint64_t reloc, const uint8_t *datastart,
+  gimli_mapped_object_t file,
+  struct gimli_dwarf_cu *cu,
   const uint8_t *custart,
   const uint8_t **datap, const uint8_t *end,
-  const uint8_t *abbrstart, const uint8_t *abbrend,
-  int is_64, uint8_t addr_size,
-  gimli_object_file_t *elf,
-  gimli_hash_t diehash
+  uint64_t da_offset,
+  int is_64, uint8_t addr_size
 )
 {
   const uint8_t *data = *datap;
   struct gimli_dwarf_die *die = NULL, *kid = NULL;
   struct gimli_dwarf_attr *attr = NULL;
   uint64_t offset;
-  char diename[64];
 
-  offset = data - datastart;
+  offset = data - file->debug_info.start;
+
   abbr_code = dw_read_uleb128(&data, end);
   if (abbr_code == 0) {
     // Skip over NUL entry
-//    printf("found a NUL entry @ %llx\n", offset);
+//    printf("found a NUL entry @ 0x%" PRIx64 "\n", offset);
     *datap = data;
     return NULL;
   }
-  abbr = find_abbr(abbrstart, abbrend, abbr_code);
+  abbr = find_abbr(file, da_offset, abbr_code);
   if (!abbr) {
-    printf("Couldn't locate abbrev code %lld\n", abbr_code);
+    printf("Couldn't locate abbrev code %" PRId64 "\n", abbr_code);
     *datap = data;
     return NULL;
   }
 
   /* what kind of entry is this? */
-  tag = dw_read_uleb128(&abbr, abbrend);
+  tag = dw_read_uleb128(&abbr, file->abbr.end);
   memcpy(&has_children, abbr, sizeof(has_children));
   abbr += sizeof(has_children);
+  if (has_children != 0 && has_children != 1) {
+    printf("invalid value for has_children! %d\n", has_children);
+    abort();
+  }
 
-  die = calloc(1, sizeof(*die));
+  die = gimli_slab_alloc(&file->dieslab);
+  memset(die, 0, sizeof(*die));
   die->offset = offset;
   die->tag = tag;
-  snprintf(diename, sizeof(diename)-1, "%llx", offset);
-  gimli_hash_insert(diehash, diename, die);
-//  printf("die @ %s tag=%llx\n", diename, die->tag);
+  STAILQ_INIT(&die->kids);
 
-  while (data < end && abbr < abbrend) {
-    atype = dw_read_uleb128(&abbr, abbrend);
-    aform = dw_read_uleb128(&abbr, abbrend);
+  while (data < end && abbr < file->abbr.end) {
+    atype = dw_read_uleb128(&abbr, file->abbr.end);
+    aform = dw_read_uleb128(&abbr, file->abbr.end);
 
     if (atype == 0) {
       break;
     }
 
-    attr = calloc(1, sizeof(*attr));
+    attr = gimli_slab_alloc(&file->attrslab);
+    memset(attr, 0, sizeof(*attr));
     attr->attr = atype;
 
     attr->form = get_value(aform, addr_size, is_64, &data, end,
-        &attr->code, &attr->ptr, elf);
+        &attr->code, &attr->ptr, file->debug_info.elf);
 
     if (attr->form == 0) {
       printf("Failed to resolve value for attribute\n");
     }
 
     if (attr->form == DW_FORM_addr) {
-      attr->code += reloc;
+      attr->code += file->debug_info.reloc;
     } else if (attr->form == DW_FORM_ref_udata) {
       /* offset from start of its respective CU */
-      attr->code += (int64_t)(custart - datastart);
+//      printf("ref CU, code is %" PRIx64, attr->code);
+      attr->code += (int64_t)(custart - file->debug_info.start);
+//      printf(" fixed up to %" PRIx64 "\n", attr->code);
+      attr->ptr = (const uint8_t*)cu;
       attr->form = DW_FORM_data8;
     }
 
     /* go recursive and pull those in now.
      * The first child may be NULL and not indicate a terminator */
     while (1) {
-      kid = process_die(reloc, datastart, custart, &data, end, abbrstart,
-            abbrend, is_64, addr_size, elf, diehash);
+      kid = process_die(file, cu, custart, &data, end, da_offset,
+            is_64, addr_size);
       if (kid == NULL) {
-        if (die->last_kid) {
+        if (STAILQ_FIRST(&die->kids)) {
           break;
         }
         continue;
       }
-      if (!die->kids) {
-        die->kids = kid;
-      }
-      if (die->last_kid) {
-        die->last_kid->next = kid;
-      }
-      die->last_kid = kid;
+      STAILQ_INSERT_TAIL(&die->kids, kid, siblings);
       kid->parent = die;
     }
   }
 
-#if 0 /* we could collect type info here */
-  if (die->tag == DW_TAG_structure_type) {
-    struct gimli_dwarf_attr *name = gimli_dwarf_die_get_attr(die, DW_AT_name);
-    if (name) {
-      printf("struct %s\n", (char*)name->ptr);
-    }
-  }
+#if 0
+  printf("process_die stopping at offset %" PRIx64 "\n",
+      data - file->debug_info.start);
 #endif
-
   *datap = data;
   return die;
 }
 
-struct gimli_dwarf_die *gimli_dwarf_get_die(struct gimli_object_file *f,
-  uint64_t offset)
+/* Calculate the relocation slide value; it only applies
+ * to shared objects (not the main executable) and must
+ * be the value of the lowest load address of all the
+ * mappings for that object */
+static gimli_addr_t calc_reloc(gimli_mapped_object_t f)
 {
-  const uint8_t *data, *datastart, *end, *next;
-  const uint8_t *abbr, *abbrstart, *abbrend;
+  int i;
+  struct gimli_object_mapping *m;
+  gimli_addr_t smallest = 0;
+
+  if (gimli_object_is_executable(f->elf) || f->debug_info.reloc) {
+    return f->debug_info.reloc;
+  }
+
+  for (i = 0; i < the_proc->nmaps; i++) {
+    m = the_proc->mappings[i];
+
+    if (m->objfile == f) {
+      if (smallest) {
+        if (m->base < smallest) {
+          smallest = m->base;
+        }
+      } else {
+        smallest = m->base;
+      }
+    }
+    f->debug_info.reloc = smallest;
+  }
+#if 0
+  printf("Using reloc adjustment for %s: 0x%" PRIx64 "\n",
+      m->objfile->objname, f->debug_info.reloc);
+#endif
+  return f->debug_info.reloc;
+}
+
+static int init_debug_info(gimli_mapped_object_t f)
+{
+  if (f->debug_info.start) return 1;
+
+  if (!get_sect_data(f, ".debug_info", &f->debug_info.start,
+        &f->debug_info.end, &f->debug_info.elf)) {
+    printf("no debug info for %s\n", f->objname);
+    return 0;
+  }
+
+  calc_reloc(f);
+
+  return 1;
+}
+
+/* insert CU into the appropriate portion of the binary search tree
+ * pointed to by root */
+static void insert_cu(struct gimli_dwarf_cu **rootp, struct gimli_dwarf_cu *cu)
+{
+  struct gimli_dwarf_cu *root = *rootp;
+
+  if (!root) {
+    *rootp = cu;
+    return;
+  }
+  while (root) {
+    if (cu->offset >= root->offset && cu->offset < root->end) {
+      printf("CU list already contains %" PRIx64 "\n", cu->offset);
+      abort();
+    }
+    if (cu->offset < root->offset) {
+      if (root->left) {
+        root = root->left;
+        continue;
+      }
+      root->left = cu;
+      return;
+    }
+    /* must be on the right */
+    if (root->right) {
+      root = root->right;
+      continue;
+    }
+    root->right = cu;
+    return;
+  }
+}
+
+static struct gimli_dwarf_cu *load_cu(gimli_mapped_object_t f, uint64_t offset)
+{
+  const uint8_t *data, *next;
   const uint8_t *cuend, *custart;
-  gimli_object_file_t *elf = NULL;
+  gimli_object_file_t elf = NULL;
   uint64_t initlen;
   uint32_t len32;
   uint16_t ver;
   uint64_t da_offset;
   int is_64 = 0;
   uint8_t addr_size, seg_size;
-  uint64_t reloc = 0;
+  struct gimli_dwarf_cu *cu, *cuptr;
   struct gimli_dwarf_die *die = NULL;
-  struct gimli_dwarf_die *last_die = NULL;
-  char diename[64];
 
-  if (!f->dies) {
-    f->dies = gimli_hash_new(NULL);
+  if (!init_debug_info(f)) {
+    return 0;
+  }
+  data = f->debug_info.start + offset;
 
-    if (!get_sect_data(f, ".debug_info", &datastart, &end, &elf)) {
-      printf("no debug info for %s\n", f->objname);
-      return 0;
+#if 0
+  printf("Loading CU @ offset %" PRIx64 " from data of size %" PRIu64 "\n",
+      offset,
+      f->debug_info.end - f->debug_info.start);
+#endif
+
+  if (data >= f->debug_info.end) {
+    printf("CU offset %" PRIx64 " it out of bounds\n", offset);
+    return 0;
+  }
+
+  custart = data;
+  memcpy(&len32, data, sizeof(len32));
+  data += sizeof(len32);
+  if (len32 == 0xffffffff) {
+    is_64 = 1;
+    memcpy(&initlen, data, sizeof(initlen));
+    data += sizeof(initlen);
+  } else {
+    is_64 = 0;
+    initlen = len32;
+  }
+  cuend = data + initlen;
+
+  memcpy(&ver, data, sizeof(ver));
+  data += sizeof(ver);
+  if (ver < 2 || ver > 3) {
+    printf("%s: CU @ offset 0x%" PRIx64 " with dwarf version %d; ending processing\n",
+        f->objname, offset, ver);
+    abort();
+    return 0;
+  }
+
+  if (is_64) {
+    memcpy(&da_offset, data, sizeof(da_offset));
+    data += sizeof(da_offset);
+  } else {
+    memcpy(&len32, data, sizeof(len32));
+    data += sizeof(len32);
+    da_offset = len32;
+  }
+
+  memcpy(&addr_size, data, sizeof(addr_size));
+  data += sizeof(addr_size);
+
+  cu = calloc(1, sizeof(*cu));
+  cu->offset = offset;
+  cu->end = cuend - f->debug_info.start;
+  cu->da_offset = da_offset;
+  STAILQ_INIT(&cu->dies);
+
+  /* insert into the cu tree */
+  insert_cu(&f->debug_info.cus, cu);
+#if 0
+  printf("Recording CU %" PRIx64 " - %" PRIx64 " @ %p\n",
+      cu->offset, cu->end, cu);
+#endif
+
+  /* now we have a series of Debugging Information Entries (DIE) */
+  while (data < cuend) {
+    die = process_die(f, cu, custart, &data, cuend,
+        da_offset, is_64, addr_size);
+    if (!die) {
+      continue;
     }
-    data = datastart;
+    STAILQ_INSERT_TAIL(&cu->dies, die, siblings);
+  }
 
-    if (!gimli_object_is_executable(f->elf)) {
-      struct gimli_object_mapping *m;
+#if 0
+  printf("abbr.map is %d in size, data size %" PRIu64 " approx %" PRIu64 " per entry\n",
+      gimli_hash_size(f->abbr.map), f->abbr.end - f->abbr.start,
+      (f->abbr.end - f->abbr.start) / gimli_hash_size(f->abbr.map));
+  gimli_hash_diagnose(f->abbr.map);
+#endif
 
-      for (m = gimli_mappings; m; m = m->next) {
-        if (m->objfile == f) {
-          reloc = (uint64_t)(intptr_t)m->base;
-        }
+  return cu;
+}
+
+/* searches the CU binary search tree for the requested offset */
+static struct gimli_dwarf_cu *find_cu(
+  gimli_mapped_object_t f,
+  uint64_t offset)
+{
+  struct gimli_dwarf_die *die = NULL;
+  struct gimli_dwarf_cu *cu;
+
+  /* search binary tree */
+  cu = f->debug_info.cus;
+  while (cu) {
+    if (offset >= cu->offset && offset < cu->end) {
+      return cu;
+    }
+    if (offset < cu->offset) {
+      cu = cu->left;
+    } else {
+      cu = cu->right;
+    }
+  }
+  return NULL;
+}
+
+static struct gimli_dwarf_die *find_die_r(struct gimli_dwarf_die *die, uint64_t offset)
+{
+  struct gimli_dwarf_die *kid, *res;
+
+  if (die->offset == offset) {
+    return die;
+  }
+  STAILQ_FOREACH(kid, &die->kids, siblings) {
+    if (kid->offset == offset) {
+      return kid;
+    }
+  }
+  STAILQ_FOREACH(kid, &die->kids, siblings) {
+    res = find_die_r(kid, offset);
+    if (res) {
+      return res;
+    }
+  }
+  return NULL;
+}
+
+struct gimli_dwarf_die *gimli_dwarf_get_die(
+  gimli_mapped_object_t f,
+  uint64_t offset)
+{
+  struct gimli_dwarf_die *die = NULL, *res;
+  struct gimli_dwarf_cu *cu;
+
+  cu = find_cu(f, offset);
+  if (!cu) {
+    /* not found; will need to go out to disk to read it */
+    cu = load_cu(f, offset);
+  }
+
+  if (cu) {
+    STAILQ_FOREACH(die, &cu->dies, siblings) {
+      res = find_die_r(die, offset);
+      if (res) {
+        return res;
       }
-      //    printf("Using reloc adjustment for %s: 0x%llx\n", m->objfile->objname, reloc);
-    }
-
-    while (data < end) {
-      custart = data;
-      memcpy(&len32, data, sizeof(len32));
-      data += sizeof(len32);
-      if (len32 == 0xffffffff) {
-        is_64 = 1;
-        memcpy(&initlen, data, sizeof(initlen));
-        data += sizeof(initlen);
-      } else {
-        is_64 = 0;
-        initlen = len32;
-      }
-      cuend = data + initlen;
-
-      memcpy(&ver, data, sizeof(ver));
-      data += sizeof(ver);
-      if (ver < 2 || ver > 3) {
-        printf("Encountered a compilation unit with dwarf version %d; ending processing\n", ver);
-
-        break;
-      }
-
-      if (is_64) {
-        memcpy(&da_offset, data, sizeof(da_offset));
-        data += sizeof(da_offset);
-      } else {
-        memcpy(&len32, data, sizeof(len32));
-        data += sizeof(len32);
-        da_offset = len32;
-      }
-
-      memcpy(&addr_size, data, sizeof(addr_size));
-      data += sizeof(addr_size);
-
-      if (!get_sect_data(f, ".debug_abbrev",
-            &abbrstart, &abbrend, &elf)) {
-        printf("could not get abbrev data for %s\n", f->objname);
-        return 0;
-      }
-      abbrstart += da_offset;
-
-      /* now we have a series of Debugging Information Entries (DIE) */
-      while (data < cuend) {
-        die = process_die(reloc, datastart, custart, &data, cuend,
-                abbrstart, abbrend, is_64, addr_size, elf, f->dies);
-        if (!die) {
-          continue;
-        }
-        if (last_die) {
-          last_die->next = die;
-        }
-        if (!f->first_die) {
-          f->first_die = die;
-        }
-        last_die = die;
-      }
-      data = cuend;
     }
   }
 
-  snprintf(diename, sizeof(diename)-1, "%llx", offset);
-  if (gimli_hash_find(f->dies, diename, (void**)&die)) {
-    return die;
-  }
-
-  for (die = f->first_die; die; die = die->next) {
-    if (die->offset >= offset) {
-      return die;
-    }
-  }
-
-//  printf("Didn't find die at offset %s\n", diename);
+  printf("get_die: %" PRIx64 " MISSING cu=%p %" PRIx64 "-%" PRIx64 "\n",
+      offset, cu, cu->offset, cu->end);
   return NULL;
 }
 
-
-
 struct gimli_dwarf_attr *gimli_dwarf_die_get_attr(
   struct gimli_dwarf_die *die, uint64_t attrcode)
 {
   return NULL;
 }
 
-int gimli_dwarf_die_get_uint64_t_attr(
+static int gimli_dwarf_die_get_uint64_t_attr(
   struct gimli_dwarf_die *die, uint64_t attrcode, uint64_t *val)
 {
   struct gimli_dwarf_attr *attr;
 {
   struct gimli_section_data *s = NULL;
   const uint8_t *data, *end, *next;
-  gimli_object_file_t *elf = NULL;
+  gimli_object_file_t elf = NULL;
   uint64_t reloc = 0;
   uint32_t len32;
   int is_64 = 0;