diff --git a/Makefile.am b/Makefile.am
index dec7db6add5f94c9268ee9177a4bb8b64197964b..b5d143b1ddb9d606061f4a4ae7760a75f6ab2185 100644
--- a/Makefile.am
+++ b/Makefile.am
@@ -67,7 +67,7 @@ nobase_include_HEADERS += capsule/capsule-shim.h \
 # Mostly just a demo program, but keep this hanging around as it's a useful PoC
 bin_PROGRAMS           += capsule-elf-dump
 
-capsule_elf_dump_SOURCES        = utils/elf-dump.c utils/utils.c
+capsule_elf_dump_SOURCES        = utils/elf-dump.c utils/dump.c utils/utils.c
 capsule_elf_dump_LDADD          = -ldl
 capsule_elf_dump_SOURCES       += utils/utils.h
 capsule_elf_dump_CFLAGS         = $(AM_CFLAGS)
diff --git a/utils/dump.c b/utils/dump.c
index 1eb9d8e5e6381eaf721d9a06f8d1c65c55dfe4e4..064d1f40be332c28d46c8247bbea69a351203dd9 100644
--- a/utils/dump.c
+++ b/utils/dump.c
@@ -491,13 +491,14 @@ dump_symtab (const char *indent,
         symbol_version( entry, x, strtab, versym, verdef, verdefnum,
                         &defversym, &version, &vs );
 
-        fprintf(stderr, "%s    // %02d [%-8s %-8s] size:%"FMT_SWORD" %s%s%s%s %04x %p\n",
+        fprintf(stderr, "%s    // %02d [%-8s %-8s] size:%2" FMT_WORD " (%d)%s%s%s%s %04x %p\n",
                 indent,
                 x,
                 st_type( ELFW_ST_TYPE(entry->st_info) ),
                 st_bind( ELFW_ST_BIND(entry->st_info) ),
                 // ELFW_ST_VISIBILITY(entry->st_other),
                 entry->st_size  ,
+                entry->st_shndx ,
                 strtab + entry->st_name ,
                 version   ? "@"     : "",
                 defversym ? "@"     : "",
@@ -517,7 +518,7 @@ dump_interp (const char *indent, void *start, size_t size, ElfW(Addr) base)
     strncpy( &interpreter[0], start + base, PATH_MAX );
 
     fprintf( stderr, "%s// %p %"FMT_SIZE" %p %s", indent, start, size, (void *)base,
-             &interpreter[0] );
+             interpreter );
     return;
 }
 
@@ -751,10 +752,11 @@ dump_verneed(const char *indent,
     {
         ElfW(Verneed) *entry = (ElfW(Verneed) *) vn;
 
-        fprintf( stderr, "%s    // %02d %-15s : %d entries %d aux\n",
+        fprintf( stderr, "%s    // %02d %-15s : %d entries (aux %d)\n",
                  indent, x,
                  strtab + entry->vn_file,
-                 entry->vn_cnt,
+                 entries,
+                 // entry->vn_cnt,
                  entry->vn_aux );
 
         const char *au = vn + entry->vn_aux;
@@ -786,8 +788,8 @@ dump_verdef(const char *indent,
     {
         ElfW(Verdef) *entry = (ElfW(Verdef) *) vd;
 
-        fprintf( stderr, "%s    // %02d [%d]; ndx: %0x; flags: %0x\n",
-                 indent, x,
+        fprintf( stderr, "%s    // %02d/%02d [%d]; ndx: %0x; flags: %0x\n",
+                 indent, x, entries,
                  entry->vd_cnt  ,
                  entry->vd_ndx  ,
                  entry->vd_flags);
@@ -815,7 +817,9 @@ dump_dynamic (const char *indent, void *start, size_t size, ElfW(Addr) base)
     const char *tag;
     ElfW(Dyn) *entry;
 
+    size_t strsiz  = -1;
     int relasz     = -1;
+    int relsz      = -1;
     int jmprelsz   = -1;
     int verneednum = -1;
     int verdefnum  = -1;
@@ -824,10 +828,21 @@ dump_dynamic (const char *indent, void *start, size_t size, ElfW(Addr) base)
     const void *symtab = NULL;
     const void *versym = NULL;
     const void *verdef = NULL;
-    const char *strtab = dynamic_section_find_strtab( start + base, (const void *) base, NULL );
+    const char *strtab = dynamic_section_find_strtab( start + base, (const void *) base, &strsiz );
     int tag_type = TTYPE_VAL;
 
     fprintf( stderr, "%s{\n", indent );
+
+    if( strtab )
+    {
+        fprintf( stderr, "%s    string table at %p, %zu bytes\n",
+                 indent, strtab, strsiz );
+    }
+    else
+    {
+        fprintf( stderr, "%s    no string table?!\n", indent );
+    }
+
     for( entry = start + base;
          (entry->d_tag != DT_NULL) && ((void *)entry < (start + base + size));
          entry++ )
@@ -897,6 +912,17 @@ dump_dynamic (const char *indent, void *start, size_t size, ElfW(Addr) base)
             relasz = entry->d_un.d_val;
             break;
 
+          case DT_RELSZ:
+            relsz = entry->d_un.d_val;
+            break;
+
+          case DT_REL:
+            if( relsz == -1 )
+                relsz = find_value( base, start, DT_RELSZ );
+            dump_rel( indent, (const void *) entry->d_un.d_ptr, relsz,
+                      strtab, symtab );
+            break;
+
           case DT_PLTREL:
             jmpreltype = entry->d_un.d_val;
             break;
@@ -936,7 +962,9 @@ dump_dynamic (const char *indent, void *start, size_t size, ElfW(Addr) base)
           case DT_VERNEED:
             if( verneednum == -1 )
                 verneednum = find_value( base, start, DT_VERNEEDNUM );
-            dump_verneed( indent, (const void *) entry->d_un.d_ptr, verneednum,
+            dump_verneed( indent,
+                          fix_addr( (const void *) base, entry->d_un.d_ptr ),
+                          verneednum,
                           strtab, base );
             break;
 
@@ -947,7 +975,7 @@ dump_dynamic (const char *indent, void *start, size_t size, ElfW(Addr) base)
           case DT_VERDEF:
             if( verdefnum == -1 )
                 verdefnum = find_value( base, start, DT_VERDEFNUM );
-            verdef = (const void *) entry->d_un.d_ptr;
+            verdef = fix_addr( (const void *) base, entry->d_un.d_ptr );
             dump_verdef( indent, verdef, verdefnum, strtab, base );
             break;
 
@@ -969,6 +997,9 @@ phdr_cb (struct dl_phdr_info *info, size_t size, void *data)
 {
     int j;
 
+    if( data != NULL && strstr( info->dlpi_name, (const char *)data ) == NULL )
+        return 0;
+
     fprintf(stderr, "\n\
 ===============================================================================\n\
 struct dl_phdr_info                  \n\
@@ -989,8 +1020,8 @@ struct dl_phdr_info                  \n\
         ElfW(Off)   p_offset;  %"FMT_OFF"\n\
         ElfW(Addr)  p_vaddr;   %p      \n\
         ElfW(Addr)  p_paddr;   %p      \n\
-        ElfW(Word)  p_filesz;  0x%"FMT_XADDR" \n\
-        ElfW(Word)  p_memsz;   0x%"FMT_XADDR" \n\
+        ElfW(Word)  p_filesz;  %"FMT_WORD" \n\
+        ElfW(Word)  p_memsz;   %"FMT_WORD" \n\
         ElfW(Word)  p_flags;   0x%x %s \n\
         ElfW(Word)  p_align;   %"FMT_WORD" \n",
                 j,
@@ -1030,9 +1061,10 @@ struct dl_phdr_info                  \n\
     return 0;
 }
 
-void dump_elf_data (void)
+void
+dump_elf_data (const char *basename)
 {
-    dl_iterate_phdr( phdr_cb, NULL );
+    dl_iterate_phdr( phdr_cb, (void *) basename );
 }
 
 static int
diff --git a/utils/dump.h b/utils/dump.h
index f72108b38f63bf71e90da5f13db7b59bb7be6139..8ba78334046d02f77f784a96cb689bb96d4504fe 100644
--- a/utils/dump.h
+++ b/utils/dump.h
@@ -17,6 +17,6 @@
 
 #pragma once
 
-void dump_elf_data (void);
+void dump_elf_data (const char *basename);
 
 void debug_link_maps (void);
diff --git a/utils/elf-dump.c b/utils/elf-dump.c
index 416666c5e6d7abc822d7142bfa979058a5d758ce..c7c5f954656e08cbdcd4a53d937765954b1b7e1c 100644
--- a/utils/elf-dump.c
+++ b/utils/elf-dump.c
@@ -16,1043 +16,12 @@
 // License along with libcapsule.  If not, see <http://www.gnu.org/licenses/>.
 
 #include <dlfcn.h>
-#include <stdlib.h>
+#include <errno.h>
 #include <stdio.h>
-
+#include <stdlib.h>
 #include <string.h>
 
-#include <sys/types.h>
-#include <sys/stat.h>
-#include <fcntl.h>
-#include <errno.h>
-#include <limits.h>
-
-#include <link.h>
-#include "utils.h"
-
-// this file is a home for the various ways of parsing the ELF layout
-// of a program or library from within the executable itself, ie
-// it allows the different parts of the in-memory ELF layout to be
-// extracted in some useful way. not all these sections are relevant
-// or useful for our eventual goals, but as this knowledge is hard
-// to come by it is [literally] codified here
-
-typedef enum
-{
-    TTYPE_VAL,
-    TTYPE_PTR,
-    TTYPE_STR,
-} ttype;
-
-static const char *
-pt_flags (int x)
-{
-    static char flags[80];
-
-    flags[sizeof(flags) - 1] = '\0';
-    snprintf( flags, sizeof(flags) - 1,
-              "%c%c%c [%x %x]",
-              (x & PF_R) ? 'R' : '-',
-              (x & PF_W) ? 'W' : '-',
-              (x & PF_X) ? 'X' : '-',
-              x & PF_MASKOS   ,
-              x & PF_MASKPROC );
-
-    return flags;
-}
-
-static const char *
-pt_type (int x)
-{
-    switch (x)
-    {
-      case PT_NULL:         return "NULL";
-      case PT_LOAD:         return "LOAD";
-      case PT_DYNAMIC:      return "DYNAMIC";
-      case PT_INTERP:       return "INTERP";
-      case PT_NOTE:         return "NOTE";
-      case PT_SHLIB:        return "SHLIB";
-      case PT_PHDR:         return "PHDR";
-      case PT_TLS:          return "TLS";
-      case PT_NUM:          return "NUM";
-      case PT_LOOS:         return "LOOS";
-      case PT_GNU_EH_FRAME: return "GNU_EH_FRAME";
-      case PT_GNU_STACK:    return "GNU_STACK";
-      case PT_GNU_RELRO:    return "GNU_RELRO";
-      case PT_SUNWBSS:      return "SUNWBSS";
-      case PT_SUNWSTACK:    return "SUNWSTACK";
-      case PT_HISUNW:       return "HISUNW";
-      case PT_LOPROC:       return "LOPROC";
-      case PT_HIPROC:       return "HIPROC";
-      default:              return "-unknown-";
-    };
-}
-
-static const char *
-d_tag (unsigned long tag, int *tag_type)
-{
-    static char label[80];
-    const char *rval = label;
-
-    label[0] = '\0';
-    *tag_type = TTYPE_VAL;
-
-    switch( tag )
-    {
-      case DT_NULL: // Marks end of dynamic section
-        rval = "NULL";
-        break;
-
-      case DT_NEEDED: // Name of needed library
-        *tag_type = TTYPE_STR;
-        rval = "NEEDED";
-        break;
-
-      case DT_PLTRELSZ:		// Size in bytes of PLT relocs
-        rval = "PLTRELSZ";
-        break;
-
-      case DT_PLTGOT:   // Processor defined value
-        *tag_type = TTYPE_PTR;
-        rval = "PLTGOT";
-        break;
-
-      case DT_HASH: // Address of symbol hash table
-        *tag_type = TTYPE_PTR;
-        rval = "HASH";
-        break;
-
-      case DT_STRTAB: // Address of string table
-        *tag_type = TTYPE_PTR;
-        rval = "STRTAB";
-        break;
-
-      case DT_SYMTAB: // Address of symbol table
-        *tag_type = TTYPE_PTR;
-        rval = "SYMTAB";
-        break;
-
-      case DT_RELA: // Address of Rela relocs
-        *tag_type = TTYPE_PTR;
-        rval = "RELA";
-        break;
-
-      case DT_RELASZ:		// Total size of Rela relocs
-        rval = "RELASZ";
-        break;
-
-      case DT_RELAENT: // Size of one Rela reloc
-        rval = "RELAENT";
-        break;
-
-      case DT_STRSZ: // Size of string table
-        rval = "STRSZ";
-        break;
-
-      case DT_SYMENT: // Size of one symbol table entry
-        rval = "SYMENT";
-        break;
-
-      case DT_INIT: // Address of init function
-        *tag_type = TTYPE_PTR;
-        rval = "INIT";
-        break;
-
-      case DT_FINI: // Address of termination function
-        *tag_type = TTYPE_PTR;
-        rval = "FINI";
-        break;
-
-      case DT_SONAME: // Name of shared object
-        *tag_type = TTYPE_STR;
-        rval = "SONAME";
-        break;
-
-      case DT_RPATH: // Library search path (deprecated)
-        *tag_type = TTYPE_STR;
-        rval = "RPATH (deprecated)";
-        break;
-
-      case DT_SYMBOLIC: // Start symbol search here
-        *tag_type = TTYPE_PTR;
-        rval = "SYMBOLIC";
-        break;
-
-      case DT_REL: // Address of Rel relocs
-        *tag_type = TTYPE_PTR;
-        rval = "REL";
-        break;
-
-      case DT_RELSZ: // Total size of Rel relocs
-        rval = "RELSZ";
-        break;
-
-      case DT_RELENT: // Size of one Rel reloc
-        rval = "RELENT";
-        break;
-
-      case DT_PLTREL: // Type of reloc in PLT
-        rval = "PLTREL";
-        break;
-
-      case DT_DEBUG: // For debugging; unspecified
-        rval = "DEBUG";
-        break;
-
-      case DT_TEXTREL: // Reloc might modify .text
-        rval = "TEXTREL";
-        break;
-
-      case DT_JMPREL: // Address of PLT relocs
-        *tag_type = TTYPE_PTR;
-        rval = "JMPREL";
-        break;
-
-      case DT_BIND_NOW: // Process relocations of object
-        rval = "BIND_NOW";
-        break;
-
-      case DT_INIT_ARRAY:			// Array with addresses of init fct
-        *tag_type = TTYPE_PTR;
-        rval = "INIT_ARRAY";
-        break;
-
-      case DT_FINI_ARRAY: // Array with addresses of fini fct
-        *tag_type = TTYPE_PTR;
-        rval = "FINI_ARRAY";
-        break;
-
-      case DT_INIT_ARRAYSZ: // Size in bytes of DT_INIT_ARRAY
-        rval = "INIT_ARRAYSZ";
-        break;
-
-      case DT_FINI_ARRAYSZ: // Size in bytes of DT_FINI_ARRAY
-        rval = "FINI_ARRAYSZ";
-        break;
-
-      case DT_RUNPATH: // Library search path
-        *tag_type = TTYPE_PTR;
-        rval = "RUNPATH";
-        break;
-
-      case DT_FLAGS: // Flags for the object being loaded
-        rval = "FLAGS";
-        break;
-
-      case DT_PREINIT_ARRAY:		// Array with addresses of preinit fct
-        *tag_type = TTYPE_PTR;
-        rval = "PREINIT_ARRAY";
-        break;
-
-      case DT_PREINIT_ARRAYSZ: // size in bytes of DT_PREINIT_ARRAY
-        rval = "PREINIT_ARRAYSZ";
-        break;
-
-      case DT_NUM:          // Number used
-        rval = "NUM";
-        break;
-
-      case DT_GNU_PRELINKED:
-        rval = "GNU_PRELINKED"; // Prelinking timestamp
-        break;
-
-      case DT_GNU_CONFLICTSZ:
-        rval = "GNU_CONFLICTSZ"; // Size of conflict section
-        break;
-
-      case DT_GNU_LIBLISTSZ:
-        rval = "GNU_LIBLISTSZ"; // Size of library list
-        break;
-
-      case DT_CHECKSUM:
-        rval = "CHECKSUM"; // Feature selection (DTF_*).
-        break;
-
-      case DT_POSFLAG_1:
-        rval = "POSFLAG_1"; // Flags for DT_* entries, effecting the following DT_* entry.
-        break;
-
-      case DT_SYMINSZ:
-        rval = "SYMINSZ"; // Size of syminfo table (in bytes)
-        break;
-
-      case DT_SYMINENT:
-        rval = "SYMINENT"; // Entry size of syminfo
-        break;
-
-      case DT_GNU_HASH:
-        rval = "GNU_HASH"; // GNU-style hash table.
-        break;
-
-      case DT_TLSDESC_PLT:
-        rval = "TLSDESC_PLT"; // Start of conflict section
-        break;
-
-      case DT_GNU_LIBLIST:
-        rval = "GNU_LIBLIST"; // Library list
-        break;
-
-      case DT_CONFIG:
-        rval = "CONFIG"; // Configuration information.
-        break;
-
-      case DT_DEPAUDIT:
-        rval = "DEPAUDIT"; // Dependency auditing.
-        break;
-
-      case DT_AUDIT:
-        rval = "AUDIT"; // Object auditing.
-        break;
-
-      case DT_PLTPAD:
-        rval = "PLTPAD"; // PLT padding.
-        break;
-
-      case DT_MOVETAB:
-        rval = "MOVETAB"; // Move table.
-        break;
-
-      case DT_SYMINFO:
-        rval = "SYMINFO";
-        break;
-
-      case DT_VERSYM:
-        rval = "DT_VERSYM";
-        *tag_type = TTYPE_PTR;
-        break;
-
-      case DT_RELACOUNT:
-          rval = "RELACOUNT";
-        break;
-
-      case DT_RELCOUNT:
-          rval = "DT_RELCOUNT";
-        break;
-
-      case DT_FLAGS_1:  /* State flags, see DF_1_* below.  */
-        rval = "DT_FLAGS_1";
-        break;
-
-      case DT_VERDEF:  /* Address of version definition table */
-        rval = "DT_VERDEF";
-        break;
-
-      case DT_VERDEFNUM:  /* Number of version definitions */
-        rval = "VERDEFNUM";
-        break;
-
-      case DT_VERNEED: /* Address of table with needed versions */
-        *tag_type = TTYPE_PTR;
-        rval = "DT_VERNEED";
-        break;
-
-      case DT_VERNEEDNUM:
-        rval = "DT_VERNEEDNUM";
-        break;
-
-      default:
-        label[sizeof(label) - 1] = '\0';
-        if( tag >= DT_LOOS && tag <= DT_HIOS )
-            snprintf( label, sizeof(label) - 1, "OS_SPECIFIC:%lx", tag );
-        else if ( tag >= DT_LOPROC && tag <= DT_HIPROC )
-            snprintf( label, sizeof(label) - 1, "PROC_SPECIFIC:%lx", tag );
-        else
-            snprintf( label, sizeof(label) - 1, "-unknown-:%lx", tag );
-        rval = &label[0];
-    }
-
-    if ( tag >= DT_ADDRRNGLO && tag <= DT_ADDRRNGHI )
-        *tag_type = TTYPE_PTR;
-
-    return rval;
-}
-
-static const char *
-st_bind(int bind)
-{
-    switch( bind )
-    {
-      case STB_LOCAL:      return "LOCAL"          ; // Local symbol
-      case STB_GLOBAL:     return "GLOBAL"         ; // Global symbol
-      case STB_WEAK:       return "WEAK"           ; // Weak symbol
-      case STB_NUM:        return "NUM"            ; // Number of defined types.
-      case STB_LOOS:       return "LOOS/GNU_UNIQUE"; // Start of OS-specific
-      case STB_HIOS:       return "HIOS"           ; // End of OS-specific
-      case STB_LOPROC:     return "LOPROC"         ; // Start of processor-specific
-      case STB_HIPROC:     return "HIPROC"         ; // End of processor-specific
-      default:             return "???";
-    }
-}
-
-static const char *
-st_type(int type)
-{
-    switch( type )
-    {
-      case STT_NOTYPE:    return "NOTYPE"   ; // Symbol type is unspecified
-      case STT_OBJECT:    return "OBJECT"   ; // Symbol is a data object
-      case STT_FUNC:      return "FUNC"     ; // Symbol is a code object
-      case STT_SECTION:   return "SECTION"  ; // associated with a section
-      case STT_FILE:      return "FILE"     ; // Symbol's name is file name
-      case STT_COMMON:    return "COMMON"   ; // common data object
-      case STT_TLS:       return "TLS"      ; // thread-local data object
-      case STT_NUM:       return "NUM"      ; // Number of defined types.
-      case STT_LOOS:      return "LOOS/GNU_IFUNC"; // Start of OS-specific
-      case STT_HIOS:      return "HIOS"     ; // End of OS-specific
-      case STT_LOPROC:    return "LOPROC"   ; // Start of processor-specific
-      case STT_HIPROC:    return "HIPROC"   ; // End of processor-specific
-      default:            return "???";
-   }
-}
-
-static void
-symbol_version ( ElfW(Sym) *symbol,
-                 int i,
-                 const char *strtab,
-                 const ElfW(Versym) *versym,
-                 const void *verdef,
-                 const int verdefnum,
-                 int *default_version,
-                 const char **version,
-                 ElfW(Versym) *vs)
-{
-    *default_version = 0;
-    *version = NULL;
-
-    if( versym == NULL )
-        return;
-
-    switch( symbol->st_shndx )
-    {
-      case SHN_UNDEF:
-      case SHN_ABS:
-      case SHN_COMMON:
-      case SHN_BEFORE:
-      case SHN_AFTER:
-      case SHN_XINDEX:
-        // none of these are handled (and we're very unlikely to need to)
-        break;
-
-      default:
-        if( symbol->st_shndx < SHN_LORESERVE )
-        {
-            const char  *vd = verdef;
-            *vs = *(versym + i);
-
-            for( int x = 0; x < verdefnum; x++ )
-            {
-                ElfW(Verdef) *entry = (ElfW(Verdef) *) vd;
-
-                if( entry->vd_ndx == (*vs & 0x7fff) )
-                {
-                    const char *au;
-
-                    if( entry->vd_flags & VER_FLG_BASE )
-                        break;
-
-                    au = vd + entry->vd_aux;
-                    ElfW(Verdaux) *aux = (ElfW(Verdaux) *) au;
-                    *version = strtab + aux->vda_name;
-                    *default_version = (*vs & 0x8000) ? 0 : 1;
-                }
-
-                vd = vd + entry->vd_next;
-            }
-        }
-    }
-}
-
-static void
-dump_symtab (const char *indent,
-             const void *start,
-             const char *strtab,
-             const ElfW(Versym) *versym,
-             const void *verdef,
-             const int verdefnum)
-{
-    int x = 0;
-    ElfW(Sym) *entry;
-
-    for( entry = (ElfW(Sym) *)start;
-         ( (ELFW_ST_TYPE(entry->st_info) < STT_NUM) &&
-           (ELFW_ST_BIND(entry->st_info) < STB_NUM) );
-         entry++ )
-    {
-        int defversym = 0;
-        const char *version = NULL;
-        ElfW(Versym) vs = 0;
-
-        symbol_version( entry, x, strtab, versym, verdef, verdefnum,
-                        &defversym, &version, &vs );
-
-        fprintf(stderr, "%s    // %02d [%-8s %-8s] size:%2"FMT_WORD" (%d)%s%s%s%s %04x %p\n",
-                indent,
-                x,
-                st_type( ELFW_ST_TYPE(entry->st_info) ),
-                st_bind( ELFW_ST_BIND(entry->st_info) ),
-                // ELFW_ST_VISIBILITY(entry->st_other),
-                entry->st_size  ,
-                entry->st_shndx ,
-                strtab + entry->st_name ,
-                version   ? "@"     : "",
-                defversym ? "@"     : "",
-                version   ? version : "",
-                vs,
-                (void *)entry->st_value );
-        x++;
-    }
-}
-
-static void
-dump_interp (const char *indent, void *start, size_t size, ElfW(Addr) base)
-{
-    char interpreter[PATH_MAX + 1] = "";
-    interpreter[PATH_MAX] = '\0';
-
-    strncpy( &interpreter[0], start + base, PATH_MAX );
-
-    fprintf( stderr, "%s// %p %"FMT_SIZE" %p %s", indent, start, size, (void *)base,
-             interpreter );
-    return;
-}
-
-static void *
-addr (ElfW(Addr) base, ElfW(Addr) ptr)
-{
-    if( ptr > base )
-        return (void *)ptr;
-    else
-        return (void *)(base + ptr);
-}
-
-static const char *
-reloc_type (int rtype)
-{
-    switch( __ELF_NATIVE_CLASS )
-    {
-      case 64:
-        switch( rtype )
-        {
-          case R_X86_64_NONE:      return "NONE";      // No reloc
-          case R_X86_64_64:        return "64";        // Direct 64 bit
-          case R_X86_64_PC32:      return "PC32";      // PC rel 32 bit signed
-          case R_X86_64_GOT32:     return "GOT32";     // 32 bit GOT entry
-          case R_X86_64_PLT32:     return "PLT32";     // 32 bit PLT address
-          case R_X86_64_COPY:      return "COPY";      // Copy symbol at runtime
-          case R_X86_64_GLOB_DAT:  return "GLOB_DAT";  // Create GOT entry
-          case R_X86_64_JUMP_SLOT: return "JUMP_SLOT"; // Create PLT entry
-          case R_X86_64_RELATIVE:  return "RELATIVE";  // Adjust by program base
-          case R_X86_64_GOTPCREL:  return "GOTPCREL";  // 32 bit GOT PC ofset
-          case R_X86_64_32:        return "32";        // Direct 32 bit zero
-          case R_X86_64_32S:       return "32S";       // Direct 32 bit sign
-          case R_X86_64_16:        return "16";        // Direct 16 bit zero
-          case R_X86_64_PC16:      return "PC16";      // 16 bit extended pc
-          case R_X86_64_8:         return "8";         // Direct 8 bit extended
-          case R_X86_64_PC8:       return "PC8";       // 8 bit sign extended pc relative
-          case R_X86_64_DTPMOD64:  return "DTPMOD64";  // ID of containing symbol module
-          case R_X86_64_DTPOFF64:  return "DTPOFF64";  // Offset in module's TLS
-          case R_X86_64_TPOFF64:   return "TPOFF64";   // Offset in initial TLS
-          case R_X86_64_TLSGD:     return "TLSGD";     // 32 bit PC relative offset to two GOT entries for GD symbol
-          case R_X86_64_TLSLD:     return "TLSLD";     // 32 bit PC relative offset to two GOT entries for LD symbol
-          case R_X86_64_DTPOFF32:  return "DTPOFF32";  // Offset in TLS block
-          case R_X86_64_GOTTPOFF:  return "GOTTPOFF";  // 32 bit PC relative offset to GOT entry for IE symbol
-          case R_X86_64_TPOFF32:   return "TPOFF32";   // Offset in initial TLS
-          default:                 break;
-        }
-        break;
-      case 32:
-        switch( rtype )
-        {
-          case R_386_NONE:         return "NONE";         // No reloc
-          case R_386_32:           return "32";           // Direct 32 bit
-          case R_386_PC32:         return "PC32";         // PC relative 32 bit
-          case R_386_GOT32:        return "GOT32";        // 32 bit GOT entry
-          case R_386_PLT32:        return "PLT32";        // 32 bit PLT address
-          case R_386_COPY:         return "COPY";         // Copy symbol at runtime
-          case R_386_GLOB_DAT:     return "GLOB_DAT";     // Create GOT entry
-          case R_386_JMP_SLOT:     return "JMP_SLOT";     // Create PLT entry
-          case R_386_RELATIVE:     return "RELATIVE";     // Adjust by program base
-          case R_386_GOTOFF:       return "GOTOFF";       // 32 bit offset to GOT
-          case R_386_GOTPC:        return "GOTPC";        // 32 bit PC relative offset to GOT
-          case R_386_32PLT:        return "32PLT";
-          case R_386_TLS_TPOFF:    return "TLS_TPOFF";    // Offset in static TLS block
-          case R_386_TLS_IE:       return "TLS_IE";       // Address of GOT entry for static TLS block offset
-          case R_386_TLS_GOTIE:    return "TLS_GOTIE";    // GOT entry for static TLS block offset
-          case R_386_TLS_LE:       return "TLS_LE";       // Offset relative to static TLS block
-          case R_386_TLS_GD:       return "TLS_GD";       // Direct 32 bit for GNU version of general dynamic thread local data
-          case R_386_TLS_LDM:      return "TLS_LDM";      // Direct 32 bit for GNU version of local dynamic thread local data in LE code
-          case R_386_16:           return "16";
-          case R_386_PC16:         return "PC16";
-          case R_386_8:            return "8";
-          case R_386_PC8:          return "PC8";
-          case R_386_TLS_GD_32:    return "TLS_GD_32";    // Direct 32 bit for general dynamic thread local data
-          case R_386_TLS_GD_PUSH:  return "TLS_GD_PUSH";  // Tag for pushl in GD TLS code
-          case R_386_TLS_GD_CALL:  return "TLS_GD_CALL";  // Relocation for call to __tls_get_addr()
-          case R_386_TLS_GD_POP:   return "TLS_GD_POP";   // Tag for popl in GD TLS code
-          case R_386_TLS_LDM_32:   return "TLS_LDM_32";   // Direct 32 bit for local dynamic thread local data in LE code
-          case R_386_TLS_LDM_PUSH: return "TLS_LDM_PUSH"; // Tag for pushl in LDM TLS code
-          case R_386_TLS_LDM_CALL: return "TLS_LDM_CALL"; // Relocation for call to __tls_get_addr() in LDM code
-          case R_386_TLS_LDM_POP:  return "TLS_LDM_POP";  // Tag for popl in LDM TLS code
-          case R_386_TLS_LDO_32:   return "TLS_LDO_32";   // Offset relative to TLS block
-          case R_386_TLS_IE_32:    return "TLS_IE_32";    // GOT entry for negated static TLS block offset
-          case R_386_TLS_LE_32:    return "TLS_LE_32";    // Negated offset relative to static TLS block
-          case R_386_TLS_DTPMOD32: return "TLS_DTPMOD32"; // ID of module containing symbol
-          case R_386_TLS_DTPOFF32: return "TLS_DTPOFF32"; // Offset in TLS block
-          case R_386_TLS_TPOFF32:  return "TLS_TPOFF32";  // Negated offset in static TLS block
-          default:                 break;
-        }
-        break;
-      default:
-        break;
-    }
-
-    return "???";
-}
-
-static void
-dump_rel (const char *indent,
-          const void *start,
-          int relsz,
-          const char *strtab,
-          const void *symtab)
-{
-    int x = 0;
-    ElfW(Rel) *entry;
-
-    for( entry = (ElfW(Rel) *)start;
-         entry < (ElfW(Rel) *)(start + relsz);
-         entry++ )
-    {
-        int sym;
-        int chr;
-        const char *name = NULL;
-
-        const ElfW(Sym) *symbol;
-
-#if __ELF_NATIVE_CLASS == 32
-        sym = ELF32_R_SYM (entry->r_info);
-        chr = ELF32_R_TYPE(entry->r_info);
-#elif __ELF_NATIVE_CLASS == 64
-        sym = ELF64_R_SYM (entry->r_info);
-        chr = ELF64_R_TYPE(entry->r_info);
-#else
-        fprintf( stderr,
-                 "__ELF_NATIVE_CLASS is NOT 32 or 64:"
-                 " What the actual hell\n" );
-        exit( 22 );
-#endif
-
-        symbol = find_symbol( sym, symtab, strtab, &name );
-        if( symbol )
-            fprintf( stderr, "%s    // [%03d] %16s off: %p; %s;\n",
-                     indent,
-                     x++,
-                     reloc_type(chr),
-                     (void *)entry->r_offset,
-                     name );
-        else
-            fprintf( stderr, "%s    // [%03d] %16s off: %p; sym[%d];\n",
-                     indent,
-                     x++,
-                     reloc_type(chr),
-                     (void *)entry->r_offset,
-                     sym );
-    }
-}
-
-static void
-dump_rela (const char *indent,
-           const void *start,
-           int relasz,
-           const char *strtab,
-           const void *symtab,
-           ElfW(Addr)  base)
-{
-    int x = 0;
-    ElfW(Rela) *entry;
-
-    for( entry = (ElfW(Rela) *)start;
-         entry < (ElfW(Rela) *)(start + relasz);
-         entry++ )
-    {
-        int sym;
-        int chr;
-        const char *name = NULL;
-
-        const ElfW(Sym) *symbol;
-
-#if __ELF_NATIVE_CLASS == 32
-        sym = ELF32_R_SYM (entry->r_info);
-        chr = ELF32_R_TYPE(entry->r_info);
-#elif __ELF_NATIVE_CLASS == 64
-        sym = ELF64_R_SYM (entry->r_info);
-        chr = ELF64_R_TYPE(entry->r_info);
-#else
-        fprintf( stderr,
-                 "__ELF_NATIVE_CLASS is NOT 32 or 64:"
-                 " What the actual hell\n" );
-        exit( 22 );
-#endif
-
-        symbol = find_symbol( sym, symtab, strtab, &name );
-        if( symbol )
-            fprintf( stderr, "%s    // [%03d] %16s off: %p; %s; add: %"FMT_SWORD"\n",
-                     indent,
-                     x++,
-                     reloc_type(chr),
-                     (void *)entry->r_offset,
-                     name,
-                     entry->r_addend );
-        else
-            fprintf( stderr, "%s    // [%03d] %16s off: %p; sym: %d; add: %"FMT_SWORD"\n",
-                     indent,
-                     x++,
-                     reloc_type(chr),
-                     (void *)entry->r_offset,
-                     sym,
-                     entry->r_addend );
-
-        switch( chr )
-        {
-            ElfW(Addr) *reloc_addr;
-          case R_X86_64_JUMP_SLOT:
-            reloc_addr = addr( base, entry->r_offset );
-            fprintf( stderr,
-                     "%s    // JUMP_SLOT relocation for %s is at %p "
-                     "and contains %p\n",
-                     indent,
-                     symbol ? name : "*unnamed*",
-                     reloc_addr,
-                     (void *)*((ElfW(Addr) *) reloc_addr) );
-            break;
-          default:
-            break;
-        }
-    }
-}
-
-static void
-dump_verneed(const char *indent,
-             const void *start,
-             int entries,
-             const char *strtab,
-             ElfW(Addr)  base)
-{
-    const char *vn = start;
-
-    for( int x = 0; x < entries; x++ )
-    {
-        ElfW(Verneed) *entry = (ElfW(Verneed) *) vn;
-
-        fprintf( stderr, "%s    // %02d %-15s : %d entries (aux %d)\n",
-                 indent, x,
-                 strtab + entry->vn_file,
-                 entries,
-                 // entry->vn_cnt,
-                 entry->vn_aux );
-
-        const char *au = vn + entry->vn_aux;
-
-        for( int y = 0; y < entry->vn_cnt; y++ )
-        {
-            ElfW(Vernaux) *aux = (ElfW(Vernaux) *) au;
-            fprintf( stderr, "%s    //    %s %s\n",
-                     indent,
-                     strtab + aux->vna_name,
-                     (aux->vna_flags & VER_FLG_WEAK) ? "(weak symbol)" : "" );
-            au = au + aux->vna_next;
-        }
-
-        vn = vn + entry->vn_next;
-    }
-}
-
-static void
-dump_verdef(const char *indent,
-            const void *start,
-            int entries,
-            const char *strtab,
-            ElfW(Addr)  base)
-{
-    const char *vd = start;
-
-    for( int x = 0; x < entries; x++ )
-    {
-        ElfW(Verdef) *entry = (ElfW(Verdef) *) vd;
-
-        fprintf( stderr, "%s    // %02d/%02d [%d]; ndx: %0x; flags: %0x\n",
-                 indent, x, entries,
-                 entry->vd_cnt  ,
-                 entry->vd_ndx  ,
-                 entry->vd_flags);
-
-        const char *au = vd + entry->vd_aux;
-
-        for( int y = 0; y < entry->vd_cnt; y++ )
-        {
-            ElfW(Verdaux) *aux = (ElfW(Verdaux) *) au;
-            fprintf( stderr, "%s    //    %s\n",
-                     indent,
-                     strtab + aux->vda_name );
-            au = au + aux->vda_next;
-        }
-
-        vd = vd + entry->vd_next;
-    }
-}
-
-
-static void
-dump_dynamic (const char *indent, void *start, size_t size, ElfW(Addr) base)
-{
-    int x = 0;
-    const char *tag;
-    ElfW(Dyn) *entry;
-
-    size_t strsiz  = -1;
-    int relasz     = -1;
-    int relsz      = -1;
-    int jmprelsz   = -1;
-    int verneednum = -1;
-    int verdefnum  = -1;
-    int jmpreltype = DT_NULL;
-
-    const void *symtab = NULL;
-    const void *versym = NULL;
-    const void *verdef = NULL;
-    const char *strtab = dynamic_section_find_strtab( start + base, (const void *) base, &strsiz );
-    int tag_type = TTYPE_VAL;
-
-    fprintf( stderr, "%s{\n", indent );
-
-    if( strtab )
-    {
-        fprintf( stderr, "%s    string table at %p, %zu bytes\n",
-                 indent, strtab, strsiz );
-    }
-    else
-    {
-        fprintf( stderr, "%s    no string table?!\n", indent );
-    }
-
-    for( entry = start + base;
-         (entry->d_tag != DT_NULL) && ((void *)entry < (start + base + size));
-         entry++ )
-    {
-        tag = d_tag( entry->d_tag, &tag_type );
-
-        switch( tag_type )
-        {
-          case TTYPE_VAL:
-            fprintf( stderr, "%s    { #%03d %20s(%"FMT_SWORD") = val:%"FMT_WORD" }\n",
-                     indent,
-                     x++,
-                     tag,
-                     entry->d_tag,
-                     entry->d_un.d_val );
-            break;
-          case TTYPE_PTR:
-            fprintf( stderr, "%s    { #%03d %20s(%"FMT_SWORD") = ptr:%p }\n",
-                     indent, x++,
-                     tag,
-                     entry->d_tag,
-                     (const void *) entry->d_un.d_ptr );
-            break;
-          case TTYPE_STR:
-            fprintf( stderr, "%s    { #%03d %20s(%"FMT_WORD") = str:%s }\n",
-                     indent,
-                     x++,
-                     tag,
-                     entry->d_tag,
-                     strtab + entry->d_un.d_ptr );
-            break;
-          default:
-            fprintf( stderr, "%s    { #%03d %20s(%"FMT_WORD") = ???:%p }\n",
-                     indent,
-                     x++,
-                     tag,
-                     entry->d_tag,
-                     (void *)entry->d_un.d_ptr );
-            break;
-        }
-
-        switch( entry->d_tag )
-        {
-          case DT_PLTRELSZ:
-            jmprelsz = entry->d_un.d_val;
-            break;
-
-          case DT_SYMTAB:
-            if( versym == NULL )
-                versym = (const void *) find_ptr( base, start, DT_VERSYM );
-            if( verdef == NULL )
-                verdef = (const void *) find_ptr( base, start, DT_VERDEF );
-            if( verdefnum == -1 )
-                verdefnum = find_value( base, start, DT_VERDEFNUM );
-            symtab = (const void *) entry->d_un.d_ptr;
-            dump_symtab( indent, symtab, strtab, versym, verdef, verdefnum );
-            break;
-
-          case DT_RELA:
-            if( relasz == -1 )
-                relasz = find_value( base, start, DT_RELASZ );
-            dump_rela( indent, (const void *) entry->d_un.d_ptr, relasz,
-                       strtab, symtab, base );
-            break;
-
-          case DT_RELASZ:
-            relasz = entry->d_un.d_val;
-            break;
-
-          case DT_RELSZ:
-            relsz = entry->d_un.d_val;
-            break;
-
-          case DT_REL:
-            if( relsz == -1 )
-                relsz = find_value( base, start, DT_RELSZ );
-            dump_rel( indent, (const void *) entry->d_un.d_ptr, relsz,
-                      strtab, symtab );
-            break;
-
-          case DT_PLTREL:
-            jmpreltype = entry->d_un.d_val;
-            break;
-
-          case DT_JMPREL:
-            if( jmprelsz == -1 )
-                jmprelsz = find_value( base, start, DT_PLTRELSZ );
-            if( jmpreltype == DT_NULL )
-                jmpreltype = find_value( base, start, DT_PLTREL );
-
-            switch( jmpreltype )
-            {
-                int unused;
-
-              case DT_REL:
-                dump_rel( indent, (const void *) entry->d_un.d_ptr, jmprelsz,
-                          strtab, symtab );
-                break;
-
-              case DT_RELA:
-                dump_rela( indent, (const void *) entry->d_un.d_ptr, jmprelsz,
-                           strtab, symtab, base );
-                break;
-
-              default:
-                fprintf( stderr, "%s    // unknown DT_PLTREL value: %d (%s)\n",
-                         indent, jmpreltype, d_tag( jmpreltype, &unused ) );
-                fprintf( stderr, "%s    // expected DT_REL or DT_RELA\n", indent );
-                break;
-            }
-            break;
-
-          case DT_VERNEEDNUM:
-            verneednum = entry->d_un.d_val;
-            break;
-
-          case DT_VERNEED:
-            if( verneednum == -1 )
-                verneednum = find_value( base, start, DT_VERNEEDNUM );
-            dump_verneed( indent,
-                          fix_addr( (const void *) base, entry->d_un.d_ptr ),
-                          verneednum,
-                          strtab, base );
-            break;
-
-          case DT_VERDEFNUM:
-            verdefnum = entry->d_un.d_val;
-            break;
-
-          case DT_VERDEF:
-            if( verdefnum == -1 )
-                verdefnum = find_value( base, start, DT_VERDEFNUM );
-            verdef = fix_addr( (const void *) base, entry->d_un.d_ptr );
-            dump_verdef( indent, verdef, verdefnum, strtab, base );
-            break;
-
-          case DT_VERSYM:
-            if( versym == NULL )
-                versym = (const void *) entry->d_un.d_ptr;
-            break;
-
-          default:
-            break;
-        }
-    }
-    fprintf(stderr, "%s}\n", indent);
-    return;
-}
-
-static int
-phdr_cb (struct dl_phdr_info *info, size_t size, void *data)
-{
-    int j;
-
-    if( strstr( info->dlpi_name, (const char *)data ) == NULL )
-        return 0;
-
-    fprintf(stderr, "\n\
-===============================================================================\n\
-struct dl_phdr_info                  \n\
-{                                    \n\
-    ElfW(Addr)        dlpi_addr;  %p \n\
-    const char       *dlpi_name; \"%s\" \n\
-    ElfW(Half)        dlpi_phnum; %d \n\
-    const ElfW(Phdr) *dlpi_phdr;  %p \n",
-            (void *)info->dlpi_addr  ,
-            info->dlpi_name  ,
-            info->dlpi_phnum ,
-            (void *)info->dlpi_phdr  );
-
-    for( j = 0; j < info->dlpi_phnum; j++ )
-    {
-        fprintf(stderr, "    { // #%03d @ ( %p + %p ) %p\n\
-        ElfW(Word)  p_type;    %d %s   \n\
-        ElfW(Off)   p_offset;  %"FMT_OFF" \n\
-        ElfW(Addr)  p_vaddr;   %p      \n\
-        ElfW(Addr)  p_paddr;   %p      \n\
-        ElfW(Word)  p_filesz;  %"FMT_WORD" \n\
-        ElfW(Word)  p_memsz;   %"FMT_WORD" \n\
-        ElfW(Word)  p_flags;   0x%x %s \n\
-        ElfW(Word)  p_align;   %"FMT_WORD" \n",
-                j,
-                (void *)info->dlpi_addr             ,
-                (void *)info->dlpi_phdr[j].p_vaddr  ,
-                (void *)( info->dlpi_addr + info->dlpi_phdr[j].p_vaddr ),
-                info->dlpi_phdr[j].p_type   ,
-                pt_type( info->dlpi_phdr[j].p_type ),
-                info->dlpi_phdr[j].p_offset ,
-                (void *)info->dlpi_phdr[j].p_vaddr  ,
-                (void *)info->dlpi_phdr[j].p_paddr  ,
-                info->dlpi_phdr[j].p_filesz ,
-                info->dlpi_phdr[j].p_memsz  ,
-                info->dlpi_phdr[j].p_flags  ,
-                pt_flags( info->dlpi_phdr[j].p_flags ),
-                info->dlpi_phdr[j].p_align  );
-
-        switch(info->dlpi_phdr[j].p_type)
-        {
-          case PT_DYNAMIC:
-            dump_dynamic("        ",
-                         (void *) info->dlpi_phdr[j].p_vaddr,
-                         info->dlpi_phdr[j].p_memsz,
-                         info->dlpi_addr);
-            break;
-          case PT_INTERP:
-            dump_interp("        ",
-                        (void *) info->dlpi_phdr[j].p_vaddr,
-                        info->dlpi_phdr[j].p_memsz,
-                        info->dlpi_addr);
-          default:
-            break;
-        }
-        fprintf(stderr, "\n    }\n");
-    }
-
-    fprintf(stderr, "};\n");
-    return 0;
-}
+#include "dump.h"
 
 int main (int argc, char **argv)
 {
@@ -1080,7 +49,7 @@ int main (int argc, char **argv)
     else
         libname = argv[1];
 
-    dl_iterate_phdr( phdr_cb, (void *)libname );
+    dump_elf_data( libname );
 
     return 0;
 }