Essentially non-functional tidyings and improvements to debuginfo
reading.  Two sets of changes:

* New flags for debugging the readers.  
  --debug-dump=syms
  --debug-dump=line
  --debug-dump=frames

  These (currently accepted but nonfunctional) are intended to
  create output in the style of (that is, identical to)
    /usr/bin/readelf --syms
    /usr/bin/readelf --debug-dump=line
    /usr/bin/readelf --debug-dump=frames
  respectively.  The plan is that flaws in these readers can then
  be easily found by diff-ing the output against that from readelf.

  Also, a new flag --trace-symtab-patt=<object filename pattern>
  which is used to limit all debuginfo-related debug info to the
  set of shared object names matching the given pattern.  This
  facilitates extracting the debuginfo details of one specific
  shared object, which is usually what is required, rather than
  having to wade through megabytes of junk from every object in
  the process.

* Propagate the avma/svma/image address-naming scheme
  (as described at the top of debuginfo.c) through large parts of
  readelf.c and readdwarf.c.



git-svn-id: svn://svn.valgrind.org/valgrind/trunk@6588 a5019735-40e9-0310-863c-91ae7b9d1cf9
diff --git a/coregrind/m_debuginfo/debuginfo.c b/coregrind/m_debuginfo/debuginfo.c
index f651720..1477efc 100644
--- a/coregrind/m_debuginfo/debuginfo.c
+++ b/coregrind/m_debuginfo/debuginfo.c
@@ -85,7 +85,8 @@
    This terminology is not used consistently, but a start has been
    made.  readelf.c and the call-frame info reader in readdwarf.c now
    use it.  Specifically, various variables and structure fields have
-   been annotated with _avma / _svma / _image / _bias.
+   been annotated with _avma / _svma / _image / _bias.  In places _img
+   is used instead of _image for the sake of brevity.
 */
 
 
@@ -112,8 +113,12 @@
                        const UChar* filename,
                        const UChar* memname)
 {
-   SegInfo* si = VG_(arena_calloc)(VG_AR_SYMTAB, 1, sizeof(SegInfo));
+   Bool     traceme;
+   SegInfo* si;
 
+   vg_assert(filename);
+
+   si = VG_(arena_calloc)(VG_AR_SYMTAB, 1, sizeof(SegInfo));
    si->text_start_avma = start;
    si->text_size       = size;
    si->foffset         = foffset;
@@ -122,7 +127,23 @@
                            ?  VG_(arena_strdup)(VG_AR_SYMTAB, memname)
                            :  NULL;
 
-   // Everything else -- pointers, sizes, arrays -- is zeroed by calloc.
+   /* Everything else -- pointers, sizes, arrays -- is zeroed by calloc.
+      Now set up the debugging-output flags. */
+   traceme 
+      = VG_(string_match)( VG_(clo_trace_symtab_patt), filename )
+        || (memname && VG_(string_match)( VG_(clo_trace_symtab_patt), 
+                                          memname ));
+   if (traceme) {
+      si->trace_symtab = VG_(clo_trace_symtab);
+      si->trace_cfi    = VG_(clo_trace_cfi);
+#if 0
+      si->ddump_syms   = VG_(clo_ddump_syms);
+      si->ddump_line   = VG_(clo_ddump_line);
+      si->ddump_frames = VG_(clo_ddump_frames);
+#endif
+   }
+
+
    return si;
 }
 
diff --git a/coregrind/m_debuginfo/priv_storage.h b/coregrind/m_debuginfo/priv_storage.h
index c0618dc..dcd4887 100644
--- a/coregrind/m_debuginfo/priv_storage.h
+++ b/coregrind/m_debuginfo/priv_storage.h
@@ -194,6 +194,16 @@
    UInt   data_size;
    Addr   bss_start_avma;
    UInt   bss_size;
+
+   /* Used for debugging only - indicate what stuff to dump whilst
+      reading stuff into the seginfo.  Are computed as early in the
+      lifetime of the SegInfo as possible.  Use these when deciding
+      what to spew out; do not use the global VG_(clo_blah) flags. */
+   Bool trace_symtab; /* symbols, our style */
+   Bool trace_cfi;    /* dwarf frame unwind, our style */
+   Bool ddump_syms;   /* mimic /usr/bin/readelf --syms */
+   Bool ddump_line;   /* mimic /usr/bin/readelf --debug-dump=line */
+   Bool ddump_frames; /* mimic /usr/bin/readelf --debug-dump=frames */
 };
 
 /* --------------------- functions --------------------- */
@@ -250,7 +260,7 @@
 
 
 #define TRACE_SYMTAB(format, args...) \
-   if (VG_(clo_trace_symtab)) { VG_(printf)(format, ## args); }
+   if (si->trace_symtab) { VG_(printf)(format, ## args); }
 
 
 #endif /* ndef __PRIV_STORAGE_H */
diff --git a/coregrind/m_debuginfo/readdwarf.c b/coregrind/m_debuginfo/readdwarf.c
index 9288df0..58ec665 100644
--- a/coregrind/m_debuginfo/readdwarf.c
+++ b/coregrind/m_debuginfo/readdwarf.c
@@ -253,12 +253,12 @@
    Read 32-bit value from p.  If it is 0xFFFFFFFF, instead read a
    64-bit bit value from p+4.  This is used in 64-bit dwarf to encode
    some table lengths. */
-static ULong read_initial_length_field ( UChar* p, /*OUT*/Bool* is64 )
+static ULong read_initial_length_field ( UChar* p_img, /*OUT*/Bool* is64 )
 {
-   UInt w32 = *((UInt*)p);
+   UInt w32 = *((UInt*)p_img);
    if (w32 == 0xFFFFFFFF) {
       *is64 = True;
-      return *((ULong*)(p+4));
+      return *((ULong*)(p_img+4));
    } else {
       *is64 = False;
       return (ULong)w32;
@@ -390,7 +390,7 @@
 static 
 void read_dwarf2_lineblock ( struct _SegInfo*  si, OffT debug_offset,
                              UnitInfo* ui, 
-                             UChar*    theBlock, 
+                             UChar*    theBlock, /* IMAGE */
                              Int       noLargerThan )
 {
    DebugLineInfo  info;
@@ -786,9 +786,9 @@
  */
 static 
 void read_unitinfo_dwarf2( /*OUT*/UnitInfo* ui,
-                                  UChar*    unitblock,
-                                  UChar*    debugabbrev,
-                                  UChar*    debugstr )
+                                  UChar*    unitblock_img,
+                                  UChar*    debugabbrev_img,
+                                  UChar*    debugstr_img )
 {
    UInt   acode, abcode;
    ULong  atoffs, blklen;
@@ -796,9 +796,9 @@
    UShort ver;
 
    UChar addr_size;
-   UChar* p = unitblock;
-   UChar* end;
-   UChar* abbrev;
+   UChar* p = unitblock_img;
+   UChar* end_img;
+   UChar* abbrev_img;
 
    VG_(memset)( ui, 0, sizeof( UnitInfo ) );
    ui->stmt_list = -1LL;
@@ -821,12 +821,14 @@
    addr_size = *p;
    p += 1;
 
-   end    = unitblock + blklen + (ui->dw64 ? 12 : 4); /* End of this block */
-   level  = 0;                      /* Level in the abbrev tree */
-   abbrev = debugabbrev + atoffs;   /* Abbreviation data for this block */
+   end_img     = unitblock_img 
+                 + blklen + (ui->dw64 ? 12 : 4); /* End of this block */
+   level       = 0;                        /* Level in the abbrev tree */
+   abbrev_img  = debugabbrev_img 
+                 + atoffs; /* Abbreviation data for this block */
    
    /* Read the compilation unit entries */
-   while ( p < end ) {
+   while ( p < end_img ) {
       Bool has_child;
       UInt tag;
 
@@ -839,18 +841,18 @@
       }
       
       /* Read abbreviation header */
-      abcode = read_leb128U( &abbrev ); /* abbreviation code */
+      abcode = read_leb128U( &abbrev_img ); /* abbreviation code */
       if ( acode != abcode ) {
          /* We are in in children list, and must rewind to a
           * previously declared abbrev code.  This code works but is
           * not triggered since we shortcut the parsing once we have
           * read the compile_unit block.  This should only occur when
           * level > 0 */
-         abbrev = lookup_abbrev( debugabbrev + atoffs, acode );
+         abbrev_img = lookup_abbrev( debugabbrev_img + atoffs, acode );
       }
 
-      tag = read_leb128U( &abbrev );
-      has_child = *(abbrev++) == 1; /* DW_CHILDREN_yes */
+      tag = read_leb128U( &abbrev_img );
+      has_child = *(abbrev_img++) == 1; /* DW_CHILDREN_yes */
 
       if ( has_child )
          level++;
@@ -861,8 +863,8 @@
          UInt  name, form;
          ULong cval = -1LL;  /* Constant value read */
          Char  *sval = NULL; /* String value read */
-         name = read_leb128U( &abbrev );
-         form = read_leb128U( &abbrev );
+         name = read_leb128U( &abbrev_img );
+         form = read_leb128U( &abbrev_img );
          if ( name == 0 )
             break;
        
@@ -885,10 +887,10 @@
                        /* 2006-01-01: only generate a value if
                           debugstr is non-NULL (which means that a
                           debug_str section was found) */
-                                            if (debugstr && !ui->dw64)
-                                               sval = debugstr + *((UInt*)p); 
-                                            if (debugstr && ui->dw64)
-                                               sval = debugstr + *((ULong*)p); 
+                                            if (debugstr_img && !ui->dw64)
+                                               sval = debugstr_img + *((UInt*)p); 
+                                            if (debugstr_img && ui->dw64)
+                                               sval = debugstr_img + *((ULong*)p); 
                                             p += ui->dw64 ? 8 : 4; 
                                             break;
             case 0x08: /* FORM_string */    sval = (Char*)p; 
@@ -951,15 +953,15 @@
  */
 void ML_(read_debuginfo_dwarf2) 
         ( struct _SegInfo* si, OffT debug_offset,
-          UChar* debuginfo,   Int debug_info_sz,  /* .debug_info */
-          UChar* debugabbrev,                     /* .debug_abbrev */
-          UChar* debugline,   Int debug_line_sz,  /* .debug_line */
-          UChar* debugstr )                       /* .debug_str */
+          UChar* debuginfo_img,   Int debug_info_sz, /* .debug_info */
+          UChar* debugabbrev_img,                    /* .debug_abbrev */
+          UChar* debugline_img,   Int debug_line_sz, /* .debug_line */
+          UChar* debugstr_img )                      /* .debug_str */
 {
    UnitInfo ui;
    UShort   ver;
-   UChar*   block;
-   UChar*   end = debuginfo + debug_info_sz;
+   UChar*   block_img;
+   UChar*   end_img = debuginfo_img + debug_info_sz;
    ULong    blklen;
    Bool     blklen_is_64;
    Int      blklen_len = 0;
@@ -971,20 +973,21 @@
    }
 
    /* Iterate on all the blocks we find in .debug_info */
-   for ( block = debuginfo; block < end - 4; block += blklen + blklen_len ) {
+   for ( block_img = debuginfo_img; block_img < end_img - 4; 
+                                    block_img += blklen + blklen_len ) {
 
       /* Read the compilation unit header in .debug_info section - See
          p 70 */
       /* This block length */
-      blklen     = read_initial_length_field( block, &blklen_is_64 );
+      blklen     = read_initial_length_field( block_img, &blklen_is_64 );
       blklen_len = blklen_is_64 ? 12 : 4;
-      if ( block + blklen + blklen_len > end ) {
+      if ( block_img + blklen + blklen_len > end_img ) {
          ML_(symerr)( "Last block truncated in .debug_info; ignoring" );
          return;
       }
 
       /* version should be 2 */
-      ver = *((UShort*)( block + blklen_len ));
+      ver = *((UShort*)( block_img + blklen_len ));
       if ( ver != 2 ) {
          ML_(symerr)( "Ignoring non-dwarf2 block in .debug_info" );
          continue;
@@ -992,8 +995,9 @@
       
       /* Fill ui with offset in .debug_line and compdir */
       if (0)
-         VG_(printf)( "Reading UnitInfo at 0x%x.....\n", block - debuginfo );
-      read_unitinfo_dwarf2( &ui, block, debugabbrev, debugstr );
+         VG_(printf)( "Reading UnitInfo at 0x%x.....\n", 
+                      block_img - debuginfo_img );
+      read_unitinfo_dwarf2( &ui, block_img, debugabbrev_img, debugstr_img );
       if (0)
          VG_(printf)( "   => LINES=0x%llx    NAME=%s     DIR=%s\n", 
                       ui.stmt_list, ui.name, ui.compdir );
@@ -1006,8 +1010,9 @@
          VG_(printf)("debug_line_sz %d, ui.stmt_list %lld  %s\n", 
                      debug_line_sz, ui.stmt_list, ui.name );
       /* Read the .debug_line block for this compile unit */
-      read_dwarf2_lineblock( si, debug_offset, &ui, debugline + ui.stmt_list, 
-                                      debug_line_sz - ui.stmt_list );
+      read_dwarf2_lineblock( 
+         si, debug_offset, &ui, debugline_img + ui.stmt_list, 
+                                debug_line_sz - ui.stmt_list );
    }
 }
 
@@ -1759,7 +1764,8 @@
 */
 static Bool summarise_context( /*OUT*/DiCfSI* si,
                                Addr loc_start,
-	                       UnwindContext* ctx )
+	                       UnwindContext* ctx,
+                               struct _SegInfo* seginfo )
 {
    Int why = 0;
    initCfiSI(si);
@@ -1824,7 +1830,7 @@
    return True;
 
   failed:
-   if (VG_(clo_verbosity) > 2 || VG_(clo_trace_cfi)) {
+   if (VG_(clo_verbosity) > 2 || seginfo->trace_cfi) {
       VG_(message)(Vg_DebugMsg,
                   "summarise_context(loc_start = %p)"
                   ": cannot summarise(why=%d):   ", loc_start, why);
@@ -2042,7 +2048,8 @@
 static Int run_CF_instruction ( /*MOD*/UnwindContext* ctx, 
                                 UChar* instr,
                                 UnwindContext* restore_ctx,
-                                AddressDecodingInfo* adi )
+                                AddressDecodingInfo* adi,
+                                struct _SegInfo* si )
 {
    Int   off, reg, reg2, nleb, len;
    UInt  delta;
@@ -2244,7 +2251,7 @@
       case DW_CFA_expression:
          /* Too difficult to really handle; just skip over it and say
             that we don't know what do to with the register. */
-         if (VG_(clo_trace_cfi))
+         if (si->trace_cfi)
             VG_(printf)("DWARF2 CFI reader: "
                         "ignoring DW_CFA_expression\n");
          reg = read_leb128( &instr[i], &nleb, 0 );
@@ -2260,7 +2267,7 @@
       case DW_CFA_val_expression:
          /* Too difficult to really handle; just skip over it and say
             that we don't know what do to with the register. */
-         if (VG_(clo_trace_cfi))
+         if (si->trace_cfi)
             VG_(printf)("DWARF2 CFI reader: "
                         "ignoring DW_CFA_val_expression\n");
          reg = read_leb128( &instr[i], &nleb, 0 );
@@ -2274,7 +2281,7 @@
          break;
 
       case DW_CFA_def_cfa_expression:
-         if (VG_(clo_trace_cfi))
+         if (si->trace_cfi)
             VG_(printf)("DWARF2 CFI reader: "
                         "ignoring DW_CFA_def_cfa_expression\n");
          len = read_leb128( &instr[i], &nleb, 0 );
@@ -2558,7 +2565,7 @@
 
       /* Oh, well, let's kludge it into the text segment, then. */
       /* First, though, complain: */
-      if (VG_(clo_trace_cfi) || complaints > 0) {
+      if (si->trace_cfi || complaints > 0) {
          complaints--;
          if (VG_(clo_verbosity) > 1) {
             VG_(message)(
@@ -2570,7 +2577,7 @@
                si->text_bias + cfsi->base + cfsi->len - 1
             );
          }
-         if (VG_(clo_trace_cfi)) 
+         if (si->trace_cfi) 
             ML_(ppDiCfSI)(cfsi);
       }
 
@@ -2605,16 +2612,16 @@
       loc_prev = ctx->loc;
       if (i >= ilen) break;
       if (0) (void)show_CF_instruction( &instrs[i], adi );
-      j = run_CF_instruction( ctx, &instrs[i], restore_ctx, adi );
+      j = run_CF_instruction( ctx, &instrs[i], restore_ctx, adi, si );
       if (j == 0)
          return False; /* execution failed */
       i += j;
       if (0) ppUnwindContext(ctx);
       if (loc_prev != ctx->loc && si) {
-         summ_ok = summarise_context ( &cfsi, loc_prev, ctx );
+         summ_ok = summarise_context ( &cfsi, loc_prev, ctx, si );
          if (summ_ok) {
             kludge_then_addDiCfSI(si, &cfsi);
-            if (VG_(clo_trace_cfi))
+            if (si->trace_cfi)
                ML_(ppDiCfSI)(&cfsi);
          }
       }
@@ -2623,10 +2630,10 @@
       loc_prev = ctx->loc;
       ctx->loc = fde_arange;
       if (si) {
-         summ_ok = summarise_context ( &cfsi, loc_prev, ctx );
+         summ_ok = summarise_context ( &cfsi, loc_prev, ctx, si );
          if (summ_ok) {
             kludge_then_addDiCfSI(si, &cfsi);
-            if (VG_(clo_trace_cfi))
+            if (si->trace_cfi)
                ML_(ppDiCfSI)(&cfsi);
          }
       }
@@ -2686,7 +2693,7 @@
    return;
 #  endif
 
-   if (VG_(clo_trace_cfi)) {
+   if (si->trace_cfi) {
       VG_(printf)("\n-----------------------------------------------\n");
       VG_(printf)("CFI info: szB %d, _avma %p, _image %p\n",
 	          ehframe_sz, (void*)ehframe_avma, (void*)ehframe_image );
@@ -2734,12 +2741,12 @@
          Figure out which it is. */
 
       ciefde_start = data;
-      if (VG_(clo_trace_cfi)) 
+      if (si->trace_cfi) 
          VG_(printf)("\ncie/fde.start   = %p (ehframe_image + 0x%x)\n", 
                      ciefde_start, ciefde_start - ehframe_image);
 
       ciefde_len = read_UInt(data); data += sizeof(UInt);
-      if (VG_(clo_trace_cfi)) 
+      if (si->trace_cfi) 
          VG_(printf)("cie/fde.length  = %d\n", ciefde_len);
 
       /* Apparently, if the .length field is zero, we are at the end
@@ -2754,7 +2761,7 @@
 
       cie_pointer = read_UInt(data); 
       data += sizeof(UInt); /* XXX see XXX below */
-      if (VG_(clo_trace_cfi)) 
+      if (si->trace_cfi) 
          VG_(printf)("cie.pointer     = %d\n", cie_pointer);
 
       /* If cie_pointer is zero, we've got a CIE; else it's an FDE. */
@@ -2765,7 +2772,7 @@
          UChar* cie_augmentation;
 
          /* --------- CIE --------- */
-	 if (VG_(clo_trace_cfi)) 
+	 if (si->trace_cfi) 
             VG_(printf)("------ new CIE (#%d of 0 .. %d) ------\n", 
                         n_CIEs, N_CIEs - 1);
 
@@ -2785,7 +2792,7 @@
          the_CIEs[this_CIE].offset = ciefde_start - ehframe_image;
 
          cie_version = read_UChar(data); data += sizeof(UChar);
-         if (VG_(clo_trace_cfi))
+         if (si->trace_cfi)
             VG_(printf)("cie.version     = %d\n", (Int)cie_version);
          if (cie_version != 1) {
             how = "unexpected CIE version (not 1)";
@@ -2794,7 +2801,7 @@
 
          cie_augmentation = data;
          data += 1 + VG_(strlen)(cie_augmentation);
-         if (VG_(clo_trace_cfi)) 
+         if (si->trace_cfi) 
             VG_(printf)("cie.augment     = \"%s\"\n", cie_augmentation);
 
          if (cie_augmentation[0] == 'e' && cie_augmentation[1] == 'h') {
@@ -2804,19 +2811,19 @@
 
          the_CIEs[this_CIE].code_a_f = read_leb128( data, &nbytes, 0);
          data += nbytes;
-         if (VG_(clo_trace_cfi)) 
+         if (si->trace_cfi) 
             VG_(printf)("cie.code_af     = %d\n", 
                         the_CIEs[this_CIE].code_a_f);
 
          the_CIEs[this_CIE].data_a_f = read_leb128( data, &nbytes, 1);
          data += nbytes;
-         if (VG_(clo_trace_cfi)) 
+         if (si->trace_cfi) 
             VG_(printf)("cie.data_af     = %d\n",
                         the_CIEs[this_CIE].data_a_f);
 
          the_CIEs[this_CIE].ra_reg = (Int)read_UChar(data); 
          data += sizeof(UChar);
-         if (VG_(clo_trace_cfi)) 
+         if (si->trace_cfi) 
             VG_(printf)("cie.ra_reg      = %d\n", 
                         the_CIEs[this_CIE].ra_reg);
          if (the_CIEs[this_CIE].ra_reg < 0 
@@ -2869,14 +2876,14 @@
 
         done_augmentation:
 
-         if (VG_(clo_trace_cfi)) 
+         if (si->trace_cfi) 
             VG_(printf)("cie.encoding    = 0x%x\n", 
                         the_CIEs[this_CIE].address_encoding);
 
          the_CIEs[this_CIE].instrs = data;
          the_CIEs[this_CIE].ilen
             = ciefde_start + ciefde_len + sizeof(UInt) - data;
-         if (VG_(clo_trace_cfi)) {
+         if (si->trace_cfi) {
             VG_(printf)("cie.instrs      = %p\n", the_CIEs[this_CIE].instrs);
             VG_(printf)("cie.ilen        = %d\n", the_CIEs[this_CIE].ilen);
 	 }
@@ -2889,7 +2896,7 @@
 
          data += the_CIEs[this_CIE].ilen;
 
-         if (VG_(clo_trace_cfi)) {
+         if (si->trace_cfi) {
             AddressDecodingInfo adi;
             adi.encoding      = the_CIEs[this_CIE].address_encoding;
             adi.ehframe_image = ehframe_image;
@@ -2936,7 +2943,7 @@
          adi.ehframe_avma  = ehframe_avma;
          fde_initloc = read_encoded_Addr(&nbytes, &adi, data);
          data += nbytes;
-         if (VG_(clo_trace_cfi)) 
+         if (si->trace_cfi) 
             VG_(printf)("fde.initloc     = %p\n", (void*)fde_initloc);
 
          adi.encoding      = the_CIEs[cie].address_encoding & 0xf;
@@ -2944,7 +2951,7 @@
          adi.ehframe_avma  = ehframe_avma;
          fde_arange = read_encoded_Addr(&nbytes, &adi, data);
          data += nbytes;
-         if (VG_(clo_trace_cfi)) 
+         if (si->trace_cfi) 
             VG_(printf)("fde.arangec     = %p\n", (void*)fde_arange);
 
          if (the_CIEs[cie].saw_z_augmentation) {
@@ -2954,7 +2961,7 @@
 
          fde_instrs = data;
          fde_ilen   = ciefde_start + ciefde_len + sizeof(UInt) - data;
-         if (VG_(clo_trace_cfi)) {
+         if (si->trace_cfi) {
             VG_(printf)("fde.instrs      = %p\n", fde_instrs);
             VG_(printf)("fde.ilen        = %d\n", (Int)fde_ilen);
 	 }
@@ -2970,7 +2977,7 @@
          adi.ehframe_image = ehframe_image;
          adi.ehframe_avma  = ehframe_avma;
 
-         if (VG_(clo_trace_cfi))
+         if (si->trace_cfi)
             show_CF_instructions(fde_instrs, fde_ilen, &adi);
 
 	 initUnwindContext(&ctx);
diff --git a/coregrind/m_debuginfo/readelf.c b/coregrind/m_debuginfo/readelf.c
index 701936d..b540620 100644
--- a/coregrind/m_debuginfo/readelf.c
+++ b/coregrind/m_debuginfo/readelf.c
@@ -419,7 +419,7 @@
       sym_name = (Char*)(o_strtab + sym->st_name);
       sym_addr = o_symtab_offset + sym->st_value;
 
-      if (VG_(clo_trace_symtab))
+      if (si->trace_symtab)
          show_raw_elf_symbol(i, sym, sym_name, sym_addr, False);
 
       if (get_elf_symbol_info(si, sym, sym_name, sym_addr,
@@ -438,7 +438,7 @@
          vg_assert(risym.tocptr == 0); /* has no role except on ppc64-linux */
          ML_(addSym) ( si, &risym );
 
-         if (VG_(clo_trace_symtab)) {
+         if (si->trace_symtab) {
             VG_(printf)("    record [%4d]:          "
                         " val %010p, sz %4d  %s\n",
                         i, (void*)risym.addr, (Int)risym.size, 
@@ -527,7 +527,7 @@
       sym_name = (Char*)(o_strtab + sym->st_name);
       sym_addr = o_symtab_offset + sym->st_value;
 
-      if (VG_(clo_trace_symtab))
+      if (si->trace_symtab)
          show_raw_elf_symbol(i, sym, sym_name, sym_addr, True);
 
       if (get_elf_symbol_info(si, sym, sym_name, sym_addr,
@@ -580,7 +580,7 @@
             /* Only one or the other is possible (I think) */
 	    vg_assert(!(modify_size && modify_tocptr));
 
-            if (modify_size && VG_(clo_trace_symtab)) {
+            if (modify_size && si->trace_symtab) {
                VG_(printf)("    modify (old sz %4d)    "
                            " val %010p, toc %010p, sz %4d  %s\n",
                            old_size,
@@ -590,7 +590,7 @@
                            (HChar*)prev->key.name
                );
             }
-            if (modify_tocptr && VG_(clo_trace_symtab)) {
+            if (modify_tocptr && si->trace_symtab) {
                VG_(printf)("    modify (upd tocptr)     "
                            " val %010p, toc %010p, sz %4d  %s\n",
                             (void*) prev->key.addr, 
@@ -610,7 +610,7 @@
             elem->size     = sym_size;
             elem->from_opd = from_opd;
             VG_(OSet_Insert)(oset, elem);
-            if (VG_(clo_trace_symtab)) {
+            if (si->trace_symtab) {
                VG_(printf)("   to-oset [%4d]:          "
                            " val %010p, toc %010p, sz %4d  %s\n",
                            i, (void*) elem->key.addr,
@@ -638,7 +638,7 @@
       vg_assert(risym.name != NULL);
 
       ML_(addSym) ( si, &risym );
-      if (VG_(clo_trace_symtab)) {
+      if (si->trace_symtab) {
          VG_(printf)("    record [%4d]:          "
                      " val %010p, toc %010p, sz %4d  %s\n",
                      i, (void*) risym.addr,
@@ -1013,35 +1013,35 @@
    /* Find interesting sections, read the symbol table(s), read any debug
       information */
    {
-      /* Pointers to start of sections (in the oimage, not in the
-	 running image) -- image addresses */
-      UChar*     o_strtab     = NULL; /* .strtab */
-      ElfXX_Sym* o_symtab     = NULL; /* .symtab */
-      UChar*     o_dynstr     = NULL; /* .dynstr */
-      ElfXX_Sym* o_dynsym     = NULL; /* .dynsym */
-      Char*      debuglink    = NULL; /* .gnu_debuglink */
-      UChar*     stab         = NULL; /* .stab         (stabs)  */
-      UChar*     stabstr      = NULL; /* .stabstr      (stabs)  */
-      UChar*     debug_line   = NULL; /* .debug_line   (dwarf2) */
-      UChar*     debug_info   = NULL; /* .debug_info   (dwarf2) */
-      UChar*     debug_abbv   = NULL; /* .debug_abbrev (dwarf2) */
-      UChar*     debug_str    = NULL; /* .debug_str    (dwarf2) */
-      UChar*     dwarf1d      = NULL; /* .debug        (dwarf1) */
-      UChar*     dwarf1l      = NULL; /* .line         (dwarf1) */
-      UChar*     ehframe      = NULL; /* .eh_frame     (dwarf2) */
-      UChar*     opd_filea    = NULL; /* .opd          (dwarf2, ppc64-linux) */
-      UChar*     dummy_filea  = NULL;
+      /* IMAGE addresses: pointers to start of sections (in the
+         oimage, not in the running image) -- image addresses */
+      UChar*     strtab_img      = NULL; /* .strtab */
+      ElfXX_Sym* symtab_img      = NULL; /* .symtab */
+      UChar*     dynstr_img      = NULL; /* .dynstr */
+      ElfXX_Sym* dynsym_img      = NULL; /* .dynsym */
+      Char*      debuglink_img   = NULL; /* .gnu_debuglink */
+      UChar*     stab_img        = NULL; /* .stab         (stabs)  */
+      UChar*     stabstr_img     = NULL; /* .stabstr      (stabs)  */
+      UChar*     debug_line_img  = NULL; /* .debug_line   (dwarf2) */
+      UChar*     debug_info_img  = NULL; /* .debug_info   (dwarf2) */
+      UChar*     debug_abbv_img  = NULL; /* .debug_abbrev (dwarf2) */
+      UChar*     debug_str_img   = NULL; /* .debug_str    (dwarf2) */
+      UChar*     dwarf1d_img     = NULL; /* .debug        (dwarf1) */
+      UChar*     dwarf1l_img     = NULL; /* .line         (dwarf1) */
+      UChar*     ehframe_img     = NULL; /* .eh_frame     (dwarf2) */
+      UChar*     opd_filea_img   = NULL; /* .opd          (dwarf2, ppc64-linux) */
+      UChar*     dummy_filea_img = NULL;
 
-      OffT       o_symtab_offset = offset_oimage;
-      OffT       o_dynsym_offset = offset_oimage;
+      OffT       symtab_offset   = offset_oimage;
+      OffT       dynsym_offset   = offset_oimage;
       OffT       debug_offset    = offset_oimage;
       OffT       opd_offset      = offset_oimage;
 
       /* Section sizes, in bytes */
-      UInt       o_strtab_sz     = 0;
-      UInt       o_symtab_sz     = 0;
-      UInt       o_dynstr_sz     = 0;
-      UInt       o_dynsym_sz     = 0;
+      UInt       strtab_sz       = 0;
+      UInt       symtab_sz       = 0;
+      UInt       dynstr_sz       = 0;
+      UInt       dynsym_sz       = 0;
       UInt       debuglink_sz    = 0;
       UInt       stab_sz         = 0;
       UInt       stabstr_sz      = 0;
@@ -1093,45 +1093,46 @@
 
          /* Nb: must find where .got and .plt sections will be in the
           * executable image, not in the object image transiently loaded. */
-         /*   NAME              SIZE          ADDR_IN_OIMAGE  ADDR_WHEN_MAPPED */
-         FIND(".dynsym",        o_dynsym_sz,   o_dynsym,      dummy_avma)
-         FIND(".dynstr",        o_dynstr_sz,   o_dynstr,      dummy_avma)
-         FIND(".symtab",        o_symtab_sz,   o_symtab,      dummy_avma)
-         FIND(".strtab",        o_strtab_sz,   o_strtab,      dummy_avma)
+         /*   NAME              SIZE           IMAGE addr       AVMA */
+         FIND(".dynsym",        dynsym_sz,     dynsym_img,      dummy_avma)
+         FIND(".dynstr",        dynstr_sz,     dynstr_img,      dummy_avma)
+         FIND(".symtab",        symtab_sz,     symtab_img,      dummy_avma)
+         FIND(".strtab",        strtab_sz,     strtab_img,      dummy_avma)
 
-         FIND(".gnu_debuglink", debuglink_sz,  debuglink,     dummy_avma)
+         FIND(".gnu_debuglink", debuglink_sz,  debuglink_img,   dummy_avma)
 
-         FIND(".stab",          stab_sz,       stab,          dummy_avma)
-         FIND(".stabstr",       stabstr_sz,    stabstr,       dummy_avma)
+         FIND(".stab",          stab_sz,       stab_img,        dummy_avma)
+         FIND(".stabstr",       stabstr_sz,    stabstr_img,     dummy_avma)
 
-         FIND(".debug_line",    debug_line_sz, debug_line,    dummy_avma)
-         FIND(".debug_info",    debug_info_sz, debug_info,    dummy_avma)
-         FIND(".debug_abbrev",  debug_abbv_sz, debug_abbv,    dummy_avma)
-         FIND(".debug_str",     debug_str_sz,  debug_str,     dummy_avma)
+         FIND(".debug_line",    debug_line_sz, debug_line_img,  dummy_avma)
+         FIND(".debug_info",    debug_info_sz, debug_info_img,  dummy_avma)
+         FIND(".debug_abbrev",  debug_abbv_sz, debug_abbv_img,  dummy_avma)
+         FIND(".debug_str",     debug_str_sz,  debug_str_img,   dummy_avma)
 
-         FIND(".debug",         dwarf1d_sz,    dwarf1d,       dummy_avma)
-         FIND(".line",          dwarf1l_sz,    dwarf1l,       dummy_avma)
-         FIND(".eh_frame",      ehframe_sz,    ehframe,       ehframe_avma)
+         FIND(".debug",         dwarf1d_sz,    dwarf1d_img,     dummy_avma)
+         FIND(".line",          dwarf1l_sz,    dwarf1l_img,     dummy_avma)
+         FIND(".eh_frame",      ehframe_sz,    ehframe_img,     ehframe_avma)
 
-         FIND(".got",           si->got_size,  dummy_filea,   si->got_start_avma)
-         FIND(".plt",           si->plt_size,  dummy_filea,   si->plt_start_avma)
-         FIND(".opd",           si->opd_size,  opd_filea,     si->opd_start_avma)
+         FIND(".got",           si->got_size,  dummy_filea_img, si->got_start_avma)
+         FIND(".plt",           si->plt_size,  dummy_filea_img, si->plt_start_avma)
+         FIND(".opd",           si->opd_size,  opd_filea_img,   si->opd_start_avma)
 
 #        undef FIND
       }
          
       /* Did we find a debuglink section? */
-      if (debuglink != NULL) {
-         UInt crc_offset = VG_ROUNDUP(VG_(strlen)(debuglink)+1, 4);
+      if (debuglink_img != NULL) {
+         UInt crc_offset = VG_ROUNDUP(VG_(strlen)(debuglink_img)+1, 4);
          UInt crc;
 
          vg_assert(crc_offset + sizeof(UInt) <= debuglink_sz);
 
          /* Extract the CRC from the debuglink section */
-         crc = *(UInt *)(debuglink + crc_offset);
+         crc = *(UInt *)(debuglink_img + crc_offset);
 
          /* See if we can find a matching debug file */
-         if ((dimage = find_debug_file(si->filename, debuglink, crc, &n_dimage)) != 0) {
+         dimage = find_debug_file(si->filename, debuglink_img, crc, &n_dimage);
+         if (dimage != 0) {
             ehdr = (ElfXX_Ehdr*)dimage;
 
             if (n_dimage >= sizeof(ElfXX_Ehdr) 
@@ -1139,7 +1140,7 @@
                 && ehdr->e_phoff + ehdr->e_phnum*sizeof(ElfXX_Phdr) <= n_dimage
                 && ehdr->e_shoff + ehdr->e_shnum*sizeof(ElfXX_Shdr) <= n_dimage)
             {
-               Bool need_symtab = (NULL == o_symtab);
+               Bool need_symtab = (NULL == symtab_img);
 
                for (i = 0; i < ehdr->e_phnum; i++) {
                   ElfXX_Phdr *o_phdr = &((ElfXX_Phdr *)(dimage + ehdr->e_phoff))[i];
@@ -1151,7 +1152,7 @@
 
                debug_offset = offset_dimage;
                if (need_symtab)
-                  o_symtab_offset = offset_dimage;
+                  symtab_offset = offset_dimage;
 
                shdr = (ElfXX_Shdr*)(dimage + ehdr->e_shoff);
                sh_strtab = (UChar*)(dimage + shdr[ehdr->e_shstrndx].sh_offset);
@@ -1181,17 +1182,17 @@
                      } \
                   }
 
-                  /*   ??           NAME             SIZE         ADDR_IN_OIMAGE */
-                  FIND(need_symtab, ".symtab",       o_symtab_sz,   o_symtab)
-                  FIND(need_symtab, ".strtab",       o_strtab_sz,   o_strtab)
-                  FIND(1,           ".stab",         stab_sz,       stab)
-                  FIND(1,           ".stabstr",      stabstr_sz,    stabstr)
-                  FIND(1,           ".debug_line",   debug_line_sz, debug_line)
-                  FIND(1,           ".debug_info",   debug_info_sz, debug_info)
-                  FIND(1,           ".debug_abbrev", debug_abbv_sz, debug_abbv)
-                  FIND(1,           ".debug_str",    debug_str_sz,  debug_str)
-                  FIND(1,           ".debug",        dwarf1d_sz,    dwarf1d)
-                  FIND(1,           ".line",         dwarf1l_sz,    dwarf1l)
+                  /*   ??           NAME             SIZE           IMAGE addr */
+                  FIND(need_symtab, ".symtab",       symtab_sz,     symtab_img)
+                  FIND(need_symtab, ".strtab",       strtab_sz,     strtab_img)
+                  FIND(1,           ".stab",         stab_sz,       stab_img)
+                  FIND(1,           ".stabstr",      stabstr_sz,    stabstr_img)
+                  FIND(1,           ".debug_line",   debug_line_sz, debug_line_img)
+                  FIND(1,           ".debug_info",   debug_info_sz, debug_info_img)
+                  FIND(1,           ".debug_abbrev", debug_abbv_sz, debug_abbv_img)
+                  FIND(1,           ".debug_str",    debug_str_sz,  debug_str_img)
+                  FIND(1,           ".debug",        dwarf1d_sz,    dwarf1d_img)
+                  FIND(1,           ".line",         dwarf1l_sz,    dwarf1l_img)
 
 #                 undef FIND
                }
@@ -1200,8 +1201,8 @@
       }
 
       /* Check some sizes */
-      vg_assert((o_dynsym_sz % sizeof(ElfXX_Sym)) == 0);
-      vg_assert((o_symtab_sz % sizeof(ElfXX_Sym)) == 0);
+      vg_assert((dynsym_sz % sizeof(ElfXX_Sym)) == 0);
+      vg_assert((symtab_sz % sizeof(ElfXX_Sym)) == 0);
 
       /* Read symbols */
       {
@@ -1213,27 +1214,29 @@
          read_elf_symtab = read_elf_symtab__normal;
 #        endif
          read_elf_symtab(si, "symbol table",
-                         o_symtab, o_symtab_sz, o_symtab_offset,
-                         o_strtab, o_strtab_sz, opd_filea, opd_offset);
+                         symtab_img, symtab_sz, symtab_offset,
+                         strtab_img, strtab_sz, 
+                         opd_filea_img, opd_offset);
 
          read_elf_symtab(si, "dynamic symbol table",
-                         o_dynsym, o_dynsym_sz, o_dynsym_offset,
-                         o_dynstr, o_dynstr_sz, opd_filea, opd_offset);
+                         dynsym_img, dynsym_sz, dynsym_offset,
+                         dynstr_img, dynstr_sz, 
+                         opd_filea_img, opd_offset);
       }
 
       /* Read .eh_frame (call-frame-info) if any */
-      if (ehframe) {
+      if (ehframe_img) {
          ML_(read_callframe_info_dwarf2)
-            ( si, ehframe/*image*/, ehframe_sz, ehframe_avma );
+            ( si, ehframe_img, ehframe_sz, ehframe_avma );
       }
 
       /* Read the stabs and/or dwarf2 debug information, if any.  It
          appears reading stabs stuff on amd64-linux doesn't work, so
          we ignore it. */
 #     if !defined(VGP_amd64_linux)
-      if (stab && stabstr) {
-         ML_(read_debuginfo_stabs) ( si, debug_offset, stab, stab_sz, 
-                                         stabstr, stabstr_sz );
+      if (stab_img && stabstr_img) {
+         ML_(read_debuginfo_stabs) ( si, debug_offset, stab_img, stab_sz, 
+                                         stabstr_img, stabstr_sz );
       }
 #     endif
       /* jrs 2006-01-01: icc-8.1 has been observed to generate
@@ -1241,16 +1244,17 @@
          debuginfo reading for that reason, but, in
          read_unitinfo_dwarf2, do check that debugstr is non-NULL
          before using it. */
-      if (debug_info && debug_abbv && debug_line /* && debug_str */) {
+      if (debug_info_img && debug_abbv_img && debug_line_img
+                                           /* && debug_str_img */) {
          ML_(read_debuginfo_dwarf2) ( si, debug_offset, 
-                                      debug_info,   debug_info_sz,
-                                      debug_abbv,
-                                      debug_line,   debug_line_sz,
-                                      debug_str );
+                                      debug_info_img,   debug_info_sz,
+                                      debug_abbv_img,
+                                      debug_line_img,   debug_line_sz,
+                                      debug_str_img );
       }
-      if (dwarf1d && dwarf1l) {
-         ML_(read_debuginfo_dwarf1) ( si, dwarf1d, dwarf1d_sz, 
-                                          dwarf1l, dwarf1l_sz );
+      if (dwarf1d_img && dwarf1l_img) {
+         ML_(read_debuginfo_dwarf1) ( si, dwarf1d_img, dwarf1d_sz, 
+                                          dwarf1l_img, dwarf1l_sz );
       }
    }
    res = True;
diff --git a/coregrind/m_debuginfo/storage.c b/coregrind/m_debuginfo/storage.c
index aef37f4..4f3095f 100644
--- a/coregrind/m_debuginfo/storage.c
+++ b/coregrind/m_debuginfo/storage.c
@@ -397,7 +397,7 @@
    so we can misdescribe memcmp() as bcmp()).  This is hard to avoid.
    It's mentioned in the FAQ file.
  */
-static DiSym* prefersym ( DiSym* a, DiSym* b )
+static DiSym* prefersym ( struct _SegInfo* si, DiSym* a, DiSym* b )
 {
    Int lena, lenb;		/* full length */
    Int vlena, vlenb;		/* length without version */
@@ -476,7 +476,7 @@
             n_merged++;
             /* merge the two into one */
 	    si->symtab[si->symtab_used++] 
-               = *prefersym(&si->symtab[i], &si->symtab[i+1]);
+               = *prefersym(si, &si->symtab[i], &si->symtab[i+1]);
             i++;
          } else {
             si->symtab[si->symtab_used++] = si->symtab[i];
@@ -499,7 +499,7 @@
          continue;
 
       /* There's an overlap.  Truncate one or the other. */
-      if (VG_(clo_trace_symtab)) {
+      if (si->trace_symtab) {
          VG_(printf)("overlapping address ranges in symbol table\n\t");
          ML_(ppSym)( i, &si->symtab[i] );
          VG_(printf)("\t");
@@ -683,7 +683,7 @@
          si->cfsi_maxaddr = here_max;
    }
 
-   if (VG_(clo_trace_cfi))
+   if (si->trace_cfi)
       VG_(printf)("canonicaliseCfiSI: %d entries, %p .. %p\n", 
                   si->cfsi_used,
 	          si->cfsi_minaddr, si->cfsi_maxaddr);
diff --git a/coregrind/m_main.c b/coregrind/m_main.c
index 8e38b9b..5c5c564 100644
--- a/coregrind/m_main.c
+++ b/coregrind/m_main.c
@@ -159,7 +159,11 @@
 "    --trace-syscalls=no|yes   show all system calls? [no]\n"
 "    --trace-signals=no|yes    show signal handling details? [no]\n"
 "    --trace-symtab=no|yes     show symbol table details? [no]\n"
+"    --trace-symtab-patt=<patt> limit debuginfo tracing to obj name <patt>\n"
 "    --trace-cfi=no|yes        show call-frame-info details? [no]\n"
+"    --debug-dump=syms         mimic /usr/bin/readelf --syms\n"
+"    --debug-dump=line         mimic /usr/bin/readelf --debug-dump=line\n"
+"    --debug-dump=frames       mimic /usr/bin/readelf --debug-dump=frames\n"
 "    --trace-redir=no|yes      show redirection details? [no]\n"
 "    --trace-sched=no|yes      show thread scheduler details? [no]\n"
 "    --wait-for-gdb=yes|no     pause on startup to wait for gdb attach\n"
@@ -352,12 +356,16 @@
       else VG_BOOL_CLO(arg, "--trace-sched",      VG_(clo_trace_sched))
       else VG_BOOL_CLO(arg, "--trace-signals",    VG_(clo_trace_signals))
       else VG_BOOL_CLO(arg, "--trace-symtab",     VG_(clo_trace_symtab))
+      else VG_STR_CLO (arg, "--trace-symtab-patt", VG_(clo_trace_symtab_patt))
       else VG_BOOL_CLO(arg, "--trace-cfi",        VG_(clo_trace_cfi))
+      else VG_XACT_CLO(arg, "--debug-dump=syms",  VG_(clo_debug_dump_syms))
+      else VG_XACT_CLO(arg, "--debug-dump=line",  VG_(clo_debug_dump_line))
+      else VG_XACT_CLO(arg, "--debug-dump=frames", VG_(clo_debug_dump_frames))
       else VG_BOOL_CLO(arg, "--trace-redir",      VG_(clo_trace_redir))
+
       else VG_BOOL_CLO(arg, "--trace-syscalls",   VG_(clo_trace_syscalls))
       else VG_BOOL_CLO(arg, "--trace-pthreads",   VG_(clo_trace_pthreads))
       else VG_BOOL_CLO(arg, "--wait-for-gdb",     VG_(clo_wait_for_gdb))
-
       else VG_STR_CLO (arg, "--db-command",       VG_(clo_db_command))
       else VG_STR_CLO (arg, "--sim-hints",        VG_(clo_sim_hints))
       else VG_BOOL_CLO(arg, "--sym-offsets",      VG_(clo_sym_offsets))
diff --git a/coregrind/m_options.c b/coregrind/m_options.c
index 3ec68d5..030f78c 100644
--- a/coregrind/m_options.c
+++ b/coregrind/m_options.c
@@ -63,7 +63,11 @@
 Bool   VG_(clo_trace_syscalls) = False;
 Bool   VG_(clo_trace_signals)  = False;
 Bool   VG_(clo_trace_symtab)   = False;
+HChar* VG_(clo_trace_symtab_patt) = "*";
 Bool   VG_(clo_trace_cfi)      = False;
+Bool   VG_(clo_debug_dump_syms) = False;
+Bool   VG_(clo_debug_dump_line) = False;
+Bool   VG_(clo_debug_dump_frames) = False;
 Bool   VG_(clo_trace_redir)    = False;
 Bool   VG_(clo_trace_sched)    = False;
 Bool   VG_(clo_trace_pthreads) = False;
diff --git a/coregrind/pub_core_options.h b/coregrind/pub_core_options.h
index 60bd58c..0d0cb5a 100644
--- a/coregrind/pub_core_options.h
+++ b/coregrind/pub_core_options.h
@@ -112,8 +112,16 @@
 extern Bool  VG_(clo_trace_signals);
 /* DEBUG: print symtab details?  default: NO */
 extern Bool  VG_(clo_trace_symtab);
+/* DEBUG: restrict symtab etc details to object name pattern.  Default: "*" */
+extern HChar* VG_(clo_trace_symtab_patt);
 /* DEBUG: print call-frame-info details?  default: NO */
 extern Bool  VG_(clo_trace_cfi);
+/* DEBUG:  mimic /usr/bin/readelf --syms?  default: NO */
+extern Bool  VG_(clo_debug_dump_syms);
+/* DEBUG: mimic /usr/bin/readelf --debug-dump=line?  default: NO */
+extern Bool  VG_(clo_debug_dump_line);
+/* DEBUG: mimic  /usr/bin/readelf --debug-dump=frames?  default: NO */
+extern Bool  VG_(clo_debug_dump_frames);
 /* DEBUG: print redirection details?  default: NO */
 extern Bool  VG_(clo_trace_redir);
 /* DEBUG: print thread scheduling events?  default: NO */
diff --git a/include/pub_tool_options.h b/include/pub_tool_options.h
index cbd97c0..00c7bcb 100644
--- a/include/pub_tool_options.h
+++ b/include/pub_tool_options.h
@@ -63,6 +63,12 @@
       if ((qq_var) > (qq_hi)) (qq_var) = (qq_hi); \
    }
 
+/* Bool arg whose value is denoted by the exact presence of the given string. */
+#define VG_XACT_CLO(qq_arg, qq_option, qq_var) \
+   if (VG_CLO_STREQ(qq_arg, qq_option)) { \
+      (qq_var) = True; \
+   } /* else leave it alone */
+
 /* Verbosity level: 0 = silent, 1 (default), > 1 = more verbose. */
 extern Int  VG_(clo_verbosity);