A refactoring change; no functional effect.  struct _DebugInfo
contains a bunch of fields which are used as a very simple state
machine that observes mmap calls and decides when to read debuginfo
for the associated file.  This change moves these fields into their
own structure, struct _DebugInfoFSM, for cleanness, so as to make it
clear they have a common purpose.



git-svn-id: svn://svn.valgrind.org/valgrind/trunk@12041 a5019735-40e9-0310-863c-91ae7b9d1cf9
diff --git a/coregrind/m_debuginfo/debuginfo.c b/coregrind/m_debuginfo/debuginfo.c
index 3a4b621..6a9c177 100644
--- a/coregrind/m_debuginfo/debuginfo.c
+++ b/coregrind/m_debuginfo/debuginfo.c
@@ -176,8 +176,8 @@
    vg_assert(filename);
 
    di = ML_(dinfo_zalloc)("di.debuginfo.aDI.1", sizeof(DebugInfo));
-   di->handle    = handle_counter++;
-   di->filename  = ML_(dinfo_strdup)("di.debuginfo.aDI.2", filename);
+   di->handle       = handle_counter++;
+   di->fsm.filename = ML_(dinfo_strdup)("di.debuginfo.aDI.2", filename);
 
    /* Everything else -- pointers, sizes, arrays -- is zeroed by
       ML_(dinfo_zalloc).  Now set up the debugging-output flags. */
@@ -204,11 +204,11 @@
    GExpr* gexpr;
 
    vg_assert(di != NULL);
-   if (di->filename)   ML_(dinfo_free)(di->filename);
-   if (di->loctab)     ML_(dinfo_free)(di->loctab);
-   if (di->cfsi)       ML_(dinfo_free)(di->cfsi);
-   if (di->cfsi_exprs) VG_(deleteXA)(di->cfsi_exprs);
-   if (di->fpo)        ML_(dinfo_free)(di->fpo);
+   if (di->fsm.filename) ML_(dinfo_free)(di->fsm.filename);
+   if (di->loctab)       ML_(dinfo_free)(di->loctab);
+   if (di->cfsi)         ML_(dinfo_free)(di->cfsi);
+   if (di->cfsi_exprs)   VG_(deleteXA)(di->cfsi_exprs);
+   if (di->fpo)          ML_(dinfo_free)(di->fpo);
 
    if (di->symtab) {
       /* We have to visit all the entries so as to free up any
@@ -307,7 +307,8 @@
                          "Discarding syms at %#lx-%#lx in %s due to %s()\n",
                          di->text_avma, 
                          di->text_avma + di->text_size,
-                         curr->filename ? curr->filename : (UChar*)"???",
+                         curr->fsm.filename ? curr->fsm.filename
+                                            : (UChar*)"???",
                          reason);
          vg_assert(*prev_next_ptr == curr);
          *prev_next_ptr = curr->next;
@@ -390,24 +391,24 @@
    vg_assert(di1);
    vg_assert(di2);
 
-   if (di1->have_rx_map && di2->have_rx_map
-       && ranges_overlap(di1->rx_map_avma, di1->rx_map_size,
-                         di2->rx_map_avma, di2->rx_map_size))
+   if (di1->fsm.have_rx_map && di2->fsm.have_rx_map
+       && ranges_overlap(di1->fsm.rx_map_avma, di1->fsm.rx_map_size,
+                         di2->fsm.rx_map_avma, di2->fsm.rx_map_size))
       return True;
 
-   if (di1->have_rx_map && di2->have_rw_map
-       && ranges_overlap(di1->rx_map_avma, di1->rx_map_size,
-                         di2->rw_map_avma, di2->rw_map_size))
+   if (di1->fsm.have_rx_map && di2->fsm.have_rw_map
+       && ranges_overlap(di1->fsm.rx_map_avma, di1->fsm.rx_map_size,
+                         di2->fsm.rw_map_avma, di2->fsm.rw_map_size))
       return True;
 
-   if (di1->have_rw_map && di2->have_rx_map
-       && ranges_overlap(di1->rw_map_avma, di1->rw_map_size,
-                         di2->rx_map_avma, di2->rx_map_size))
+   if (di1->fsm.have_rw_map && di2->fsm.have_rx_map
+       && ranges_overlap(di1->fsm.rw_map_avma, di1->fsm.rw_map_size,
+                         di2->fsm.rx_map_avma, di2->fsm.rx_map_size))
       return True;
 
-   if (di1->have_rw_map && di2->have_rw_map
-       && ranges_overlap(di1->rw_map_avma, di1->rw_map_size,
-                         di2->rw_map_avma, di2->rw_map_size))
+   if (di1->fsm.have_rw_map && di2->fsm.have_rw_map
+       && ranges_overlap(di1->fsm.rw_map_avma, di1->fsm.rw_map_size,
+                         di2->fsm.rw_map_avma, di2->fsm.rw_map_size))
       return True;
 
    return False;
@@ -467,8 +468,8 @@
    DebugInfo* di;
    vg_assert(filename);
    for (di = debugInfo_list; di; di = di->next) {
-      vg_assert(di->filename);
-      if (0==VG_(strcmp)(di->filename, filename))
+      vg_assert(di->fsm.filename);
+      if (0==VG_(strcmp)(di->fsm.filename, filename))
          break;
    }
    if (!di) {
@@ -492,31 +493,33 @@
    /* This fn isn't called until after debuginfo for this object has
       been successfully read.  And that shouldn't happen until we have
       both a r-x and rw- mapping for the object.  Hence: */
-   vg_assert(di->have_rx_map);
-   vg_assert(di->have_rw_map);
+   vg_assert(di->fsm.have_rx_map);
+   vg_assert(di->fsm.have_rw_map);
    /* degenerate case: r-x section is empty */
-   if (di->rx_map_size == 0) {
+   if (di->fsm.rx_map_size == 0) {
       vg_assert(di->cfsi == NULL);
       return;
    }
    /* normal case: r-x section is nonempty */
    /* invariant (0) */
-   vg_assert(di->rx_map_size > 0);
+   vg_assert(di->fsm.rx_map_size > 0);
    /* invariant (1) */
    for (di2 = debugInfo_list; di2; di2 = di2->next) {
       if (di2 == di)
          continue;
-      if (di2->rx_map_size == 0)
+      if (di2->fsm.rx_map_size == 0)
          continue;
-      vg_assert(di->rx_map_avma + di->rx_map_size <= di2->rx_map_avma
-                || di2->rx_map_avma + di2->rx_map_size <= di->rx_map_avma);
+      vg_assert(
+         di->fsm.rx_map_avma + di->fsm.rx_map_size <= di2->fsm.rx_map_avma
+         || di2->fsm.rx_map_avma + di2->fsm.rx_map_size <= di->fsm.rx_map_avma
+      );
    }
    di2 = NULL;
    /* invariant (2) */
    if (di->cfsi) {
       vg_assert(di->cfsi_minavma <= di->cfsi_maxavma); /* duh! */
-      vg_assert(di->cfsi_minavma >= di->rx_map_avma);
-      vg_assert(di->cfsi_maxavma < di->rx_map_avma + di->rx_map_size);
+      vg_assert(di->cfsi_minavma >= di->fsm.rx_map_avma);
+      vg_assert(di->cfsi_maxavma < di->fsm.rx_map_avma + di->fsm.rx_map_size);
    }
    /* invariants (3) and (4) */
    if (di->cfsi) {
@@ -643,7 +646,7 @@
       Bool quiet = VG_(strstr)(filename, "/var/run/nscd/") != NULL;
       if (!quiet && VG_(clo_verbosity) > 1) {
          VG_(memset)(&fake_di, 0, sizeof(fake_di));
-         fake_di.filename = filename;
+         fake_di.fsm.filename = filename;
          ML_(symerr)(&fake_di, True, "failed to stat64/stat this file");
       }
       return 0;
@@ -737,7 +740,7 @@
       if (sr_Err(fd) != VKI_EACCES) {
          DebugInfo fake_di;
          VG_(memset)(&fake_di, 0, sizeof(fake_di));
-         fake_di.filename = filename;
+         fake_di.fsm.filename = filename;
          ML_(symerr)(&fake_di, True, "can't open file to inspect ELF header");
       }
       return 0;
@@ -750,7 +753,7 @@
    if (nread < 0) {
       DebugInfo fake_di;
       VG_(memset)(&fake_di, 0, sizeof(fake_di));
-      fake_di.filename = filename;
+      fake_di.fsm.filename = filename;
       ML_(symerr)(&fake_di, True, "can't read file to inspect ELF header");
       return 0;
    }
@@ -774,11 +777,11 @@
 
    if (is_rx_map) {
       /* We have a text-like mapping.  Note the details. */
-      if (!di->have_rx_map) {
-         di->have_rx_map = True;
-         di->rx_map_avma = a;
-         di->rx_map_size = seg->end + 1 - seg->start;
-         di->rx_map_foff = seg->offset;
+      if (!di->fsm.have_rx_map) {
+         di->fsm.have_rx_map = True;
+         di->fsm.rx_map_avma = a;
+         di->fsm.rx_map_size = seg->end + 1 - seg->start;
+         di->fsm.rx_map_foff = seg->offset;
       } else {
          /* FIXME: complain about a second text-like mapping */
       }
@@ -786,11 +789,11 @@
 
    if (is_rw_map) {
       /* We have a data-like mapping.  Note the details. */
-      if (!di->have_rw_map) {
-         di->have_rw_map = True;
-         di->rw_map_avma = a;
-         di->rw_map_size = seg->end + 1 - seg->start;
-         di->rw_map_foff = seg->offset;
+      if (!di->fsm.have_rw_map) {
+         di->fsm.have_rw_map = True;
+         di->fsm.rw_map_avma = a;
+         di->fsm.rw_map_size = seg->end + 1 - seg->start;
+         di->fsm.rw_map_foff = seg->offset;
       } else {
          /* FIXME: complain about a second data-like mapping */
       }
@@ -799,15 +802,15 @@
    /* If we don't have an rx and rw mapping, or if we already have
       debuginfo for this mapping for whatever reason, go no
       further. */
-   if ( ! (di->have_rx_map && di->have_rw_map && !di->have_dinfo) )
+   if ( ! (di->fsm.have_rx_map && di->fsm.have_rw_map && !di->have_dinfo) )
       return 0;
 
    /* Ok, so, finally, let's try to read the debuginfo. */
-   vg_assert(di->filename);
+   vg_assert(di->fsm.filename);
    TRACE_SYMTAB("\n");
    TRACE_SYMTAB("------ start ELF OBJECT "
                 "------------------------------\n");
-   TRACE_SYMTAB("------ name = %s\n", di->filename);
+   TRACE_SYMTAB("------ name = %s\n", di->fsm.filename);
    TRACE_SYMTAB("\n");
 
    /* We're going to read symbols and debug info for the avma
@@ -855,7 +858,7 @@
    }
 
    TRACE_SYMTAB("\n");
-   TRACE_SYMTAB("------ name = %s\n", di->filename);
+   TRACE_SYMTAB("------ name = %s\n", di->fsm.filename);
    TRACE_SYMTAB("------ end ELF OBJECT "
                 "------------------------------\n");
    TRACE_SYMTAB("\n");
@@ -1100,7 +1103,7 @@
    { DebugInfo* di = find_or_create_DebugInfo_for(exename);
 
      /* this di must be new, since we just nuked any old stuff in the range */
-     vg_assert(di && !di->have_rx_map && !di->have_rw_map);
+     vg_assert(di && !di->fsm.have_rx_map && !di->fsm.have_rw_map);
      vg_assert(!di->have_dinfo);
 
      /* don't set up any of the di-> fields; let
@@ -1172,10 +1175,10 @@
          /* Consider any symbol in the r-x mapped area to be text.
             See Comment_Regarding_Text_Range_Checks in storage.c for
             details. */
-         inRange = di->have_rx_map
-                   && di->rx_map_size > 0
-                   && di->rx_map_avma <= ptr
-                   && ptr < di->rx_map_avma + di->rx_map_size;
+         inRange = di->fsm.have_rx_map
+                   && di->fsm.rx_map_size > 0
+                   && di->fsm.rx_map_avma <= ptr
+                   && ptr < di->fsm.rx_map_avma + di->fsm.rx_map_size;
       } else {
          inRange = (di->data_present
                     && di->data_size > 0
@@ -1467,7 +1470,7 @@
           && di->text_size > 0
           && di->text_avma <= a 
           && a < di->text_avma + di->text_size) {
-         VG_(strncpy_safely)(buf, di->filename, nbuf);
+         VG_(strncpy_safely)(buf, di->fsm.filename, nbuf);
          buf[nbuf-1] = 0;
          return True;
       }
@@ -3602,7 +3605,7 @@
 
 const UChar* VG_(DebugInfo_get_filename)(const DebugInfo* di)
 {
-   return di->filename;
+   return di->fsm.filename;
 }
 
 PtrdiffT VG_(DebugInfo_get_text_bias)(const DebugInfo* di)
@@ -3674,7 +3677,7 @@
          VG_(printf)(
             "addr=%#lx di=%p %s got=%#lx,%ld plt=%#lx,%ld "
             "data=%#lx,%ld bss=%#lx,%ld\n",
-            a, di, di->filename,
+            a, di, di->fsm.filename,
             di->got_avma,  di->got_size,
             di->plt_avma,  di->plt_size,
             di->data_avma, di->data_size,
@@ -3744,9 +3747,9 @@
 
       vg_assert(n_name >= 8);
 
-      if (di && di->filename) {
+      if (di && di->fsm.filename) {
          Int i, j;
-         Int fnlen = VG_(strlen)(di->filename);
+         Int fnlen = VG_(strlen)(di->fsm.filename);
          Int start_at = 1 + fnlen - n_name;
          if (start_at < 0) start_at = 0;
          vg_assert(start_at < fnlen);
@@ -3754,8 +3757,8 @@
          while (True) {
             vg_assert(j >= 0 && j < n_name);
             vg_assert(i >= 0 && i <= fnlen);
-            name[j] = di->filename[i];
-            if (di->filename[i] == 0) break;
+            name[j] = di->fsm.filename[i];
+            if (di->fsm.filename[i] == 0) break;
             i++; j++;
          }
          vg_assert(i == fnlen);
diff --git a/coregrind/m_debuginfo/priv_storage.h b/coregrind/m_debuginfo/priv_storage.h
index 0cf8a72..fa57d99 100644
--- a/coregrind/m_debuginfo/priv_storage.h
+++ b/coregrind/m_debuginfo/priv_storage.h
@@ -394,14 +394,54 @@
    information pertaining to one mapped ELF object.  This type is
    exported only abstractly - in pub_tool_debuginfo.h. */
 
+/* First though, here's an auxiliary data structure.  It is only ever
+   used as part of a struct _DebugInfo.  We use it to record
+   observations about mappings and permission changes to the
+   associated file, so as to decide when to read debug info.  It's
+   essentially an ultra-trivial finite state machine which, when it
+   reaches an accept state, signals that we should now read debug info
+   from the object into the associated struct _DebugInfo.  The accept
+   state is arrived at when have_rx_map and have_rw_map both become
+   true.
+
+   This is all rather ad-hoc; for example it has no way to record more
+   than one rw or rx mapping for a given object, not because such
+   events have never been observed, but because we've never needed to
+   note more than the first one of any such in order when to decide to
+   read debug info.  It may be that in future we need to track more
+   state in order to make the decision, so this struct would then get
+   expanded.
+*/
+struct _DebugInfoFSM
+{
+   UChar* filename; /* in mallocville (VG_AR_DINFO) */
+
+   Bool  have_rx_map; /* did we see a r?x mapping yet for the file? */
+   Bool  have_rw_map; /* did we see a rw? mapping yet for the file? */
+
+   Addr  rx_map_avma; /* these fields record the file offset, length */
+   SizeT rx_map_size; /* and map address of the r?x mapping we believe */
+   OffT  rx_map_foff; /* is the .text segment mapping */
+
+   Addr  rw_map_avma; /* ditto, for the rw? mapping we believe is the */
+   SizeT rw_map_size; /* .data segment mapping */
+   OffT  rw_map_foff;
+};
+
+
+/* To do with the string table in struct _DebugInfo (::strchunks) */
 #define SEGINFO_STRCHUNKSIZE (64*1024)
 
+
 /* We may encounter more than one .eh_frame section in an object --
    unusual but apparently allowed by ELF.  See
    http://sourceware.org/bugzilla/show_bug.cgi?id=12675
 */
 #define N_EHFRAME_SECTS 2
 
+
+/* So, the main structure for holding debug info for one object. */
+
 struct _DebugInfo {
 
    /* Admin stuff */
@@ -431,28 +471,20 @@
    Bool ddump_line;   /* mimic /usr/bin/readelf --debug-dump=line */
    Bool ddump_frames; /* mimic /usr/bin/readelf --debug-dump=frames */
 
-   /* Fields that must be filled in before we can start reading
-      anything from the ELF file.  These fields are filled in by
-      VG_(di_notify_mmap) and its immediate helpers. */
+   /* The "decide when it is time to read debuginfo" state machine.
+      This structure must get filled in before we can start reading
+      anything from the ELF/MachO file.  This structure is filled in
+      by VG_(di_notify_mmap) and its immediate helpers. */
+   struct _DebugInfoFSM fsm;
 
-   UChar* filename; /* in mallocville (VG_AR_DINFO) */
-
-   Bool  have_rx_map; /* did we see a r?x mapping yet for the file? */
-   Bool  have_rw_map; /* did we see a rw? mapping yet for the file? */
-
-   Addr  rx_map_avma; /* these fields record the file offset, length */
-   SizeT rx_map_size; /* and map address of the r?x mapping we believe */
-   OffT  rx_map_foff; /* is the .text segment mapping */
-
-   Addr  rw_map_avma; /* ditto, for the rw? mapping we believe is the */
-   SizeT rw_map_size; /* .data segment mapping */
-   OffT  rw_map_foff;
-
-   /* Once both a rw? and r?x mapping for .filename have been
-      observed, we can go on to read the symbol tables and debug info.
-      .have_dinfo flags when that has happened. */
-   /* If have_dinfo is False, then all fields except "*rx_map*" and
-      "*rw_map*" are invalid and should not be consulted. */
+   /* Once the ::fsm has reached an accept state -- typically, when
+      both a rw? and r?x mapping for .filename have been observed --
+      we can go on to read the symbol tables and debug info.
+      .have_dinfo changes from False to True when the debug info has
+      been completely read in and postprocessed (canonicalised) and is
+      now suitable for querying. */
+   /* If have_dinfo is False, then all fields below this point are
+      invalid and should not be consulted. */
    Bool  have_dinfo; /* initially False */
 
    /* All the rest of the fields in this structure are filled in once
diff --git a/coregrind/m_debuginfo/readdwarf.c b/coregrind/m_debuginfo/readdwarf.c
index 870d77e..71a4e7b 100644
--- a/coregrind/m_debuginfo/readdwarf.c
+++ b/coregrind/m_debuginfo/readdwarf.c
@@ -3765,7 +3765,7 @@
       VG_(printf)("CFI info: szB %ld, _avma %#lx, _image %p\n",
                   frame_size, frame_avma, frame_image );
       VG_(printf)("CFI info: name %s\n",
-                  di->filename );
+                  di->fsm.filename );
    }
 
    /* Loop over CIEs/FDEs */
diff --git a/coregrind/m_debuginfo/readelf.c b/coregrind/m_debuginfo/readelf.c
index da38af3..08bb4f2 100644
--- a/coregrind/m_debuginfo/readelf.c
+++ b/coregrind/m_debuginfo/readelf.c
@@ -532,9 +532,10 @@
          "Comment_Regarding_Text_Range_Checks" in storage.c for
          background. */
       Bool in_rx;
-      vg_assert(di->have_rx_map);
-      in_rx = (!(*sym_avma_out + *sym_size_out <= di->rx_map_avma
-                 || *sym_avma_out >= di->rx_map_avma + di->rx_map_size));
+      vg_assert(di->fsm.have_rx_map);
+      in_rx = (!(*sym_avma_out + *sym_size_out <= di->fsm.rx_map_avma
+                 || *sym_avma_out >= di->fsm.rx_map_avma
+                                     + di->fsm.rx_map_size));
       if (in_text)
          vg_assert(in_rx);
       if (!in_rx) {
@@ -548,7 +549,8 @@
    } else {
      if (!(in_data || in_sdata || in_rodata || in_bss || in_sbss)) {
          TRACE_SYMTAB(
-            "ignore -- %#lx .. %#lx outside .data / .sdata / .rodata / .bss / .sbss svma ranges\n",
+            "ignore -- %#lx .. %#lx outside .data / .sdata / .rodata "
+            "/ .bss / .sbss svma ranges\n",
             *sym_avma_out, *sym_avma_out + *sym_size_out);
          return False;
       }
@@ -876,7 +878,8 @@
       Word i;
 
       for (i = 0; i < ehdr->e_phnum; i++) {
-         ElfXX_Phdr* phdr = (ElfXX_Phdr*)(image + ehdr->e_phoff + i * ehdr->e_phentsize);
+         ElfXX_Phdr* phdr
+            = (ElfXX_Phdr*)(image + ehdr->e_phoff + i * ehdr->e_phentsize);
 
          if (phdr->p_type == PT_NOTE) {
             ElfXX_Off offset =  phdr->p_offset;
@@ -889,10 +892,12 @@
 
                if (VG_(strcmp)(name, ELF_NOTE_GNU) == 0 &&
                    note->n_type == NT_GNU_BUILD_ID) {
-                  buildid = ML_(dinfo_zalloc)("di.fbi.1", note->n_descsz * 2 + 1);
+                  buildid = ML_(dinfo_zalloc)("di.fbi.1",
+                                              note->n_descsz * 2 + 1);
                   
                   for (j = 0; j < note->n_descsz; j++) {
-                     VG_(sprintf)(buildid + VG_(strlen)(buildid), "%02x", desc[j]);
+                     VG_(sprintf)(buildid + VG_(strlen)(buildid), 
+                                  "%02x", desc[j]);
                   }
                }
 
@@ -1018,7 +1023,8 @@
          vg_assert(!sr_isError(res));
          if (VG_(clo_verbosity) > 1)
             VG_(message)(Vg_DebugMsg, 
-               "  .. build-id mismatch (found %s wanted %s)\n", debug_buildid, buildid);
+               "  .. build-id mismatch (found %s wanted %s)\n", 
+               debug_buildid, buildid);
          ML_(dinfo_free)(debug_buildid);
          return 0;
       }
@@ -1211,12 +1217,12 @@
    Char* buildid = NULL;
 
    vg_assert(di);
-   vg_assert(di->have_rx_map == True);
-   vg_assert(di->have_rw_map == True);
-   vg_assert(di->rx_map_size > 0);
-   vg_assert(di->rw_map_size > 0);
+   vg_assert(di->fsm.have_rx_map == True);
+   vg_assert(di->fsm.have_rw_map == True);
+   vg_assert(di->fsm.rx_map_size > 0);
+   vg_assert(di->fsm.rw_map_size > 0);
    vg_assert(di->have_dinfo == False);
-   vg_assert(di->filename);
+   vg_assert(di->fsm.filename);
    vg_assert(!di->symtab);
    vg_assert(!di->loctab);
    vg_assert(!di->cfsi);
@@ -1227,8 +1233,8 @@
    /* If these don't hold true, it means that m_syswrap/m_aspacemgr
       managed to do a mapping where the start isn't page aligned.
       Which sounds pretty bogus to me. */
-   vg_assert(VG_IS_PAGE_ALIGNED(di->rx_map_avma));
-   vg_assert(VG_IS_PAGE_ALIGNED(di->rw_map_avma));
+   vg_assert(VG_IS_PAGE_ALIGNED(di->fsm.rx_map_avma));
+   vg_assert(VG_IS_PAGE_ALIGNED(di->fsm.rw_map_avma));
 
    /* ----------------------------------------------------------
       At this point, there is very little information in the
@@ -1247,13 +1253,13 @@
    oimage = (Addr)NULL;
    if (VG_(clo_verbosity) > 1 || VG_(clo_trace_redir))
       VG_(message)(Vg_DebugMsg, "Reading syms from %s (%#lx)\n",
-                                di->filename, di->rx_map_avma );
+                                di->fsm.filename, di->fsm.rx_map_avma );
 
    /* mmap the object image aboard, so that we can read symbols and
       line number info out of it.  It will be munmapped immediately
       thereafter; it is only aboard transiently. */
 
-   fd = VG_(open)(di->filename, VKI_O_RDONLY, 0);
+   fd = VG_(open)(di->fsm.filename, VKI_O_RDONLY, 0);
    if (sr_isError(fd)) {
       ML_(symerr)(di, True, "Can't open .so/.exe to read symbols?!");
       return False;
@@ -1274,7 +1280,8 @@
    VG_(close)(sr_Res(fd));
 
    if (sr_isError(sres)) {
-      VG_(message)(Vg_UserMsg, "warning: mmap failed on %s\n", di->filename );
+      VG_(message)(Vg_UserMsg, "warning: mmap failed on %s\n",
+                               di->fsm.filename );
       VG_(message)(Vg_UserMsg, "         no symbols or debug info loaded\n" );
       return False;
    }
@@ -1322,9 +1329,9 @@
    TRACE_SYMTAB("shdr:    img %p nent %ld ent_szB %ld\n",
                shdr_img, shdr_nent, shdr_ent_szB);
    TRACE_SYMTAB("rx_map:  avma %#lx  size %lu  foff %lu\n",
-                di->rx_map_avma, di->rx_map_size, di->rx_map_foff);
+                di->fsm.rx_map_avma, di->fsm.rx_map_size, di->fsm.rx_map_foff);
    TRACE_SYMTAB("rw_map:  avma %#lx  size %lu  foff %lu\n",
-                di->rw_map_avma, di->rw_map_size, di->rw_map_foff);
+                di->fsm.rw_map_avma, di->fsm.rw_map_size, di->fsm.rw_map_foff);
 
    if (phdr_nent == 0
        || !contained_within(
@@ -1394,35 +1401,39 @@
                goto out;
             }
             prev_svma = phdr->p_vaddr;
-            if (phdr->p_offset >= di->rx_map_foff
-                && phdr->p_offset < di->rx_map_foff + di->rx_map_size
-                && phdr->p_offset + phdr->p_filesz <= di->rx_map_foff + di->rx_map_size
+            if (phdr->p_offset >= di->fsm.rx_map_foff
+                && phdr->p_offset < di->fsm.rx_map_foff + di->fsm.rx_map_size
+                && phdr->p_offset + phdr->p_filesz
+                   <= di->fsm.rx_map_foff + di->fsm.rx_map_size
                 && (phdr->p_flags & (PF_R | PF_W | PF_X)) == (PF_R | PF_X)) {
                if (n_rx == N_RX_RW_AREAS) {
                   ML_(symerr)(di, True,
-                              "N_RX_RW_AREAS is too low; increase and recompile.");
+                              "N_RX_RW_AREAS is too low; "
+                              "increase and recompile.");
                   goto out;
                }
                rx[n_rx].svma_base  = phdr->p_vaddr;
                rx[n_rx].svma_limit = phdr->p_vaddr + phdr->p_memsz;
-               rx[n_rx].bias       = di->rx_map_avma - di->rx_map_foff
+               rx[n_rx].bias       = di->fsm.rx_map_avma - di->fsm.rx_map_foff
                                      + phdr->p_offset - phdr->p_vaddr;
                n_rx++;
                TRACE_SYMTAB("PT_LOAD[%ld]:   acquired as rx\n", i);
             }
             else
-            if (phdr->p_offset >= di->rw_map_foff
-                && phdr->p_offset < di->rw_map_foff + di->rw_map_size
-                && phdr->p_offset + phdr->p_filesz <= di->rw_map_foff + di->rw_map_size
+            if (phdr->p_offset >= di->fsm.rw_map_foff
+                && phdr->p_offset < di->fsm.rw_map_foff + di->fsm.rw_map_size
+                && phdr->p_offset + phdr->p_filesz 
+                   <= di->fsm.rw_map_foff + di->fsm.rw_map_size
                 && (phdr->p_flags & (PF_R | PF_W | PF_X)) == (PF_R | PF_W)) {
                if (n_rw == N_RX_RW_AREAS) {
                   ML_(symerr)(di, True,
-                              "N_RX_RW_AREAS is too low; increase and recompile.");
+                              "N_RX_RW_AREAS is too low; "
+                              "increase and recompile.");
                   goto out;
                }
                rw[n_rw].svma_base  = phdr->p_vaddr;
                rw[n_rw].svma_limit = phdr->p_vaddr + phdr->p_memsz;
-               rw[n_rw].bias       = di->rw_map_avma - di->rw_map_foff
+               rw[n_rw].bias       = di->fsm.rw_map_avma - di->fsm.rw_map_foff
                                      + phdr->p_offset - phdr->p_vaddr;
                n_rw++;
                TRACE_SYMTAB("PT_LOAD[%ld]:   acquired as rw\n", i);
@@ -1491,15 +1502,17 @@
    TRACE_SYMTAB("\n");
    TRACE_SYMTAB("------ Examining the section headers ------\n");
    TRACE_SYMTAB("rx: at %#lx are mapped foffsets %ld .. %ld\n",
-               di->rx_map_avma,
-               di->rx_map_foff, di->rx_map_foff + di->rx_map_size - 1 );
+                di->fsm.rx_map_avma,
+                di->fsm.rx_map_foff,
+                di->fsm.rx_map_foff + di->fsm.rx_map_size - 1 );
    for (i = 0; i < n_rx; i++) {
       TRACE_SYMTAB("rx[%ld]: contains svmas %#lx .. %#lx with bias %#lx\n",
                    i, rx[i].svma_base, rx[i].svma_limit - 1, rx[i].bias );
    }
    TRACE_SYMTAB("rw: at %#lx are mapped foffsets %ld .. %ld\n",
-               di->rw_map_avma,
-               di->rw_map_foff, di->rw_map_foff + di->rw_map_size - 1 );
+                di->fsm.rw_map_avma,
+                di->fsm.rw_map_foff, 
+                di->fsm.rw_map_foff + di->fsm.rw_map_size - 1 );
    for (i = 0; i < n_rw; i++) {
       TRACE_SYMTAB("rw[%ld]: contains svmas %#lx .. %#lx with bias %#lx\n",
                    i, rw[i].svma_base, rw[i].svma_limit - 1, rw[i].bias );
@@ -1724,8 +1737,8 @@
                VG_(message)(Vg_UserMsg,
                             "Warning: the following file's .bss is "
                             "mapped r-x only - ignoring .bss syms\n");
-               VG_(message)(Vg_UserMsg,   " %s\n", di->filename 
-                                                      ? di->filename
+               VG_(message)(Vg_UserMsg,   " %s\n", di->fsm.filename 
+                                                      ? di->fsm.filename
                                                       : (UChar*)"(null?!)" );
             }
          } else
@@ -2079,11 +2092,12 @@
             crc = *(UInt *)(debuglink_img + crc_offset);
 
             /* See if we can find a matching debug file */
-            dimage = find_debug_file( di, di->filename, buildid,
+            dimage = find_debug_file( di, di->fsm.filename, buildid,
                                       debuglink_img, crc, &n_dimage );
          } else {
             /* See if we can find a matching debug file */
-            dimage = find_debug_file( di, di->filename, buildid, NULL, 0, &n_dimage );
+            dimage = find_debug_file( di, di->fsm.filename, buildid,
+                                      NULL, 0, &n_dimage );
          }
 
          ML_(dinfo_free)(buildid);
@@ -2162,21 +2176,27 @@
                                           i, phdr_ent_szB );
                if (phdr->p_type == PT_LOAD) {
                   if (rx_dsvma_limit == 0
-                      && phdr->p_offset >= di->rx_map_foff
-                      && phdr->p_offset < di->rx_map_foff + di->rx_map_size
-                      && phdr->p_offset + phdr->p_filesz <= di->rx_map_foff + di->rx_map_size) {
+                      && phdr->p_offset >= di->fsm.rx_map_foff
+                      && phdr->p_offset
+                         < di->fsm.rx_map_foff + di->fsm.rx_map_size
+                      && phdr->p_offset + phdr->p_filesz
+                         <= di->fsm.rx_map_foff + di->fsm.rx_map_size) {
                      /* rx_dsvma_base = phdr->p_vaddr; */ /* UNUSED */
                      rx_dsvma_limit = phdr->p_vaddr + phdr->p_memsz;
-                     rx_dbias = di->rx_map_avma - di->rx_map_foff + phdr->p_offset - phdr->p_vaddr;
+                     rx_dbias = di->fsm.rx_map_avma - di->fsm.rx_map_foff 
+                                + phdr->p_offset - phdr->p_vaddr;
                   }
                   else
                   if (rw_dsvma_limit == 0
-                      && phdr->p_offset >= di->rw_map_foff
-                      && phdr->p_offset < di->rw_map_foff + di->rw_map_size
-                      && phdr->p_offset + phdr->p_filesz <= di->rw_map_foff + di->rw_map_size) {
+                      && phdr->p_offset >= di->fsm.rw_map_foff
+                      && phdr->p_offset
+                         < di->fsm.rw_map_foff + di->fsm.rw_map_size
+                      && phdr->p_offset + phdr->p_filesz
+                         <= di->fsm.rw_map_foff + di->fsm.rw_map_size) {
                      /* rw_dsvma_base = phdr->p_vaddr; */ /* UNUSED */
                      rw_dsvma_limit = phdr->p_vaddr + phdr->p_memsz;
-                     rw_dbias = di->rw_map_avma - di->rw_map_foff + phdr->p_offset - phdr->p_vaddr;
+                     rw_dbias = di->fsm.rw_map_avma - di->fsm.rw_map_foff
+                                + phdr->p_offset - phdr->p_vaddr;
                   }
                }
             }
@@ -2204,7 +2224,8 @@
                      di->sec##_debug_bias \
                         = di->sec##_bias + \
                           di->sec##_svma - di->sec##_debug_svma; \
-                     TRACE_SYMTAB("acquiring ." #sec " debug svma = %#lx .. %#lx\n", \
+                     TRACE_SYMTAB("acquiring ." #sec \
+                                  " debug svma = %#lx .. %#lx\n",       \
                                   di->sec##_debug_svma, \
                                   di->sec##_debug_svma + di->sec##_size - 1); \
                      TRACE_SYMTAB("acquiring ." #sec " debug bias = %#lx\n", \
@@ -2402,7 +2423,7 @@
          }
       }
       VG_(umsg)("VARINFO: %7lu vars   %7ld text_size   %s\n",
-                nVars, di->text_size, di->filename);
+                nVars, di->text_size, di->fsm.filename);
    }
 
   out: {
diff --git a/coregrind/m_debuginfo/readpdb.c b/coregrind/m_debuginfo/readpdb.c
index 71ad4b4..a720750 100644
--- a/coregrind/m_debuginfo/readpdb.c
+++ b/coregrind/m_debuginfo/readpdb.c
@@ -86,8 +86,8 @@
    doesn't make much sense.  Here, we use text_bias as empirically
    producing the most ranges that fall inside the text segments for a
    multi-dll program.  Of course, it could still be nonsense :-) */
-#define BIAS_FOR_SYMBOLS   (di->rx_map_avma)
-#define BIAS_FOR_LINETAB   (di->rx_map_avma)
+#define BIAS_FOR_SYMBOLS   (di->fsm.rx_map_avma)
+#define BIAS_FOR_LINETAB   (di->fsm.rx_map_avma)
 #define BIAS_FOR_LINETAB2  (di->text_bias)
 #define BIAS_FOR_FPO       (di->text_bias)
 /* Using di->text_bias for the FPOs causes 981 in range and 1 out of
@@ -2259,7 +2259,7 @@
         + OFFSET_OF(IMAGE_NT_HEADERS, OptionalHeader)
         + ntheaders_avma->FileHeader.SizeOfOptionalHeader;
 
-   di->rx_map_avma = (Addr)obj_avma;
+   di->fsm.rx_map_avma = (Addr)obj_avma;
 
    /* Iterate over PE(?) headers.  Try to establish the text_bias,
       that's all we really care about. */
@@ -2290,35 +2290,35 @@
             the real text section and valgrind will compute the wrong
             avma value and hence the wrong bias. */
          if (!(pe_sechdr_avma->Characteristics & IMAGE_SCN_CNT_UNINITIALIZED_DATA)) {
-            di->have_rx_map = True;
-            if (di->rx_map_avma == 0) {
-               di->rx_map_avma = mapped_avma;
+            di->fsm.have_rx_map = True;
+            if (di->fsm.rx_map_avma == 0) {
+               di->fsm.rx_map_avma = mapped_avma;
             }
-            if (di->rx_map_size==0) {
-               di->rx_map_foff = pe_sechdr_avma->PointerToRawData;
+            if (di->fsm.rx_map_size==0) {
+               di->fsm.rx_map_foff = pe_sechdr_avma->PointerToRawData;
             }
             di->text_present = True;
             if (di->text_avma==0) {
                di->text_avma = mapped_avma;
             }
             di->text_size   += pe_sechdr_avma->Misc.VirtualSize;
-            di->rx_map_size += pe_sechdr_avma->Misc.VirtualSize;
+            di->fsm.rx_map_size += pe_sechdr_avma->Misc.VirtualSize;
          }
       }
       else if (pe_sechdr_avma->Characteristics 
                & IMAGE_SCN_CNT_INITIALIZED_DATA) {
-         di->have_rw_map = True;
-         if (di->rw_map_avma == 0) {
-            di->rw_map_avma = mapped_avma;
+         di->fsm.have_rw_map = True;
+         if (di->fsm.rw_map_avma == 0) {
+            di->fsm.rw_map_avma = mapped_avma;
          }
-         if (di->rw_map_size==0) {
-            di->rw_map_foff = pe_sechdr_avma->PointerToRawData;
+         if (di->fsm.rw_map_size==0) {
+            di->fsm.rw_map_foff = pe_sechdr_avma->PointerToRawData;
          }
          di->data_present = True;
          if (di->data_avma==0) {
             di->data_avma = mapped_avma;
          }
-         di->rw_map_size += pe_sechdr_avma->Misc.VirtualSize;
+         di->fsm.rw_map_size += pe_sechdr_avma->Misc.VirtualSize;
          di->data_size   += pe_sechdr_avma->Misc.VirtualSize;
       }
       else if (pe_sechdr_avma->Characteristics
@@ -2331,29 +2331,29 @@
       mapped_avma     = VG_PGROUNDDN(mapped_avma);
       mapped_end_avma = VG_PGROUNDUP(mapped_end_avma);
 
-      /* Urr.  These tests are bogus; ->rx_map_avma is not necessarily
+      /* Urr.  These tests are bogus; ->fsm.rx_map_avma is not necessarily
          the start of the text section. */
       if ((1 /*VG_(needs).data_syms*/ 
            || (pe_sechdr_avma->Characteristics & IMAGE_SCN_CNT_CODE))
-          && mapped_avma >= di->rx_map_avma
-          && mapped_avma <= (di->rx_map_avma+di->text_size)
-          && mapped_end_avma > (di->rx_map_avma+di->text_size)) {
-         UInt newsz = mapped_end_avma - di->rx_map_avma;
+          && mapped_avma >= di->fsm.rx_map_avma
+          && mapped_avma <= (di->fsm.rx_map_avma+di->text_size)
+          && mapped_end_avma > (di->fsm.rx_map_avma+di->text_size)) {
+         UInt newsz = mapped_end_avma - di->fsm.rx_map_avma;
          if (newsz > di->text_size) {
             /* extending the mapping is always needed for PE files
                under WINE */
             di->text_size = newsz;
-            di->rx_map_size = newsz;
+            di->fsm.rx_map_size = newsz;
          }
       }
    }
 
-   if (di->have_rx_map && di->have_rw_map && !di->have_dinfo) {
-      vg_assert(di->filename);
+   if (di->fsm.have_rx_map && di->fsm.have_rw_map && !di->have_dinfo) {
+      vg_assert(di->fsm.filename);
       TRACE_SYMTAB("\n");
       TRACE_SYMTAB("------ start PE OBJECT with PDB INFO "
                    "---------------------\n");
-      TRACE_SYMTAB("------ name = %s\n", di->filename);
+      TRACE_SYMTAB("------ name = %s\n", di->fsm.filename);
       TRACE_SYMTAB("\n");
    }
 
@@ -2366,14 +2366,17 @@
    if (VG_(clo_verbosity) > 1) {
       VG_(message)(Vg_DebugMsg,
                    "rx_map: avma %#lx size %7lu foff %llu\n",
-                   di->rx_map_avma, di->rx_map_size, (Off64T)di->rx_map_foff);
+                   di->fsm.rx_map_avma, di->fsm.rx_map_size,
+                   (Off64T)di->fsm.rx_map_foff);
       VG_(message)(Vg_DebugMsg,
                    "rw_map: avma %#lx size %7lu foff %llu\n",
-                   di->rw_map_avma, di->rw_map_size, (Off64T)di->rw_map_foff);
+                   di->fsm.rw_map_avma, di->fsm.rw_map_size,
+                   (Off64T)di->fsm.rw_map_foff);
 
       VG_(message)(Vg_DebugMsg,
                    "  text: avma %#lx svma %#lx size %7lu bias %#lx\n",
-                   di->text_avma, di->text_svma, di->text_size, di->text_bias);
+                   di->text_avma, di->text_svma,
+                   di->text_size, di->text_bias);
    }
 
    /*
@@ -2429,7 +2432,7 @@
    }
 
    TRACE_SYMTAB("\n");
-   TRACE_SYMTAB("------ name = %s\n", di->filename);
+   TRACE_SYMTAB("------ name = %s\n", di->fsm.filename);
    TRACE_SYMTAB("------ end PE OBJECT with PDB INFO "
                 "--------------------\n");
    TRACE_SYMTAB("\n");
diff --git a/coregrind/m_debuginfo/storage.c b/coregrind/m_debuginfo/storage.c
index 4dbd3bb..6142cb0 100644
--- a/coregrind/m_debuginfo/storage.c
+++ b/coregrind/m_debuginfo/storage.c
@@ -74,7 +74,8 @@
             or below, since that won't already have been shown */
          VG_(message)(Vg_DebugMsg, 
                       "When reading debug info from %s:\n",
-                      (di && di->filename) ? di->filename : (UChar*)"???");
+                      (di && di->fsm.filename) ? di->fsm.filename
+                                               : (UChar*)"???");
       }
       VG_(message)(Vg_DebugMsg, "%s\n", msg);
 
@@ -396,9 +397,9 @@
    /* Rule out ones which are completely outside the r-x mapped area.
       See "Comment_Regarding_Text_Range_Checks" elsewhere in this file
       for background and rationale. */
-   vg_assert(di->have_rx_map && di->have_rw_map);
-   if (next-1 < di->rx_map_avma
-       || this >= di->rx_map_avma + di->rx_map_size ) {
+   vg_assert(di->fsm.have_rx_map && di->fsm.have_rw_map);
+   if (next-1 < di->fsm.rx_map_avma
+       || this >= di->fsm.rx_map_avma + di->fsm.rx_map_size ) {
        if (0)
           VG_(message)(Vg_DebugMsg, 
                        "warning: ignoring line info entry falling "
@@ -467,17 +468,17 @@
       would fall within a single procedure. */
    vg_assert(cfsi.len < 5000000);
 
-   vg_assert(di->have_rx_map && di->have_rw_map);
+   vg_assert(di->fsm.have_rx_map && di->fsm.have_rw_map);
    /* If we have an empty r-x mapping (is that possible?) then the
       DiCfSI can't possibly fall inside it.  In which case skip. */
-   if (di->rx_map_size == 0)
+   if (di->fsm.rx_map_size == 0)
       return;
 
    /* Rule out ones which are completely outside the r-x mapped area.
       See "Comment_Regarding_Text_Range_Checks" elsewhere in this file
       for background and rationale. */
-   if (cfsi.base + cfsi.len - 1 < di->rx_map_avma
-       || cfsi.base >= di->rx_map_avma + di->rx_map_size) {
+   if (cfsi.base + cfsi.len - 1 < di->fsm.rx_map_avma
+       || cfsi.base >= di->fsm.rx_map_avma + di->fsm.rx_map_size) {
       static Int complaints = 10;
       if (VG_(clo_trace_cfi) || complaints > 0) {
          complaints--;
@@ -505,25 +506,26 @@
       will fail.  See
       "Comment_on_IMPORTANT_CFSI_REPRESENTATIONAL_INVARIANTS" in
       priv_storage.h for background. */
-   if (cfsi.base < di->rx_map_avma) {
+   if (cfsi.base < di->fsm.rx_map_avma) {
       /* Lower end is outside the mapped area.  Hence upper end must
          be inside it. */
       if (0) VG_(printf)("XXX truncate lower\n");
-      vg_assert(cfsi.base + cfsi.len - 1 >= di->rx_map_avma);
-      delta = (SSizeT)(di->rx_map_avma - cfsi.base);
+      vg_assert(cfsi.base + cfsi.len - 1 >= di->fsm.rx_map_avma);
+      delta = (SSizeT)(di->fsm.rx_map_avma - cfsi.base);
       vg_assert(delta > 0);
       vg_assert(delta < (SSizeT)cfsi.len);
       cfsi.base += delta;
       cfsi.len -= delta;
    }
    else
-   if (cfsi.base + cfsi.len - 1 > di->rx_map_avma + di->rx_map_size - 1) {
+   if (cfsi.base + cfsi.len - 1 > di->fsm.rx_map_avma
+                                  + di->fsm.rx_map_size - 1) {
       /* Upper end is outside the mapped area.  Hence lower end must be
          inside it. */
       if (0) VG_(printf)("XXX truncate upper\n");
-      vg_assert(cfsi.base <= di->rx_map_avma + di->rx_map_size - 1);
+      vg_assert(cfsi.base <= di->fsm.rx_map_avma + di->fsm.rx_map_size - 1);
       delta = (SSizeT)( (cfsi.base + cfsi.len - 1) 
-                        - (di->rx_map_avma + di->rx_map_size - 1) );
+                        - (di->fsm.rx_map_avma + di->fsm.rx_map_size - 1) );
       vg_assert(delta > 0); vg_assert(delta < (SSizeT)cfsi.len);
       cfsi.len -= delta;
    }
@@ -537,9 +539,9 @@
    vg_assert(cfsi.len > 0);
 
    /* Similar logic applies for the next two assertions. */
-   vg_assert(cfsi.base >= di->rx_map_avma);
+   vg_assert(cfsi.base >= di->fsm.rx_map_avma);
    vg_assert(cfsi.base + cfsi.len - 1
-             <= di->rx_map_avma + di->rx_map_size - 1);
+             <= di->fsm.rx_map_avma + di->fsm.rx_map_size - 1);
 
    if (di->cfsi_used == di->cfsi_size) {
       new_sz = 2 * di->cfsi_size;
@@ -927,10 +929,10 @@
    /* This is assured us by top level steering logic in debuginfo.c,
       and it is re-checked at the start of
       ML_(read_elf_debug_info). */
-   vg_assert(di->have_rx_map && di->have_rw_map);
+   vg_assert(di->fsm.have_rx_map && di->fsm.have_rw_map);
    if (level > 0
-       && (aMax < di->rx_map_avma
-           || aMin >= di->rx_map_avma + di->rx_map_size)) {
+       && (aMax < di->fsm.rx_map_avma
+           || aMin >= di->fsm.rx_map_avma + di->fsm.rx_map_size)) {
       if (VG_(clo_verbosity) >= 0) {
          VG_(message)(Vg_DebugMsg, 
             "warning: addVar: in range %#lx .. %#lx outside "
@@ -1858,7 +1860,7 @@
 
 Word ML_(search_one_fpotab) ( struct _DebugInfo* di, Addr ptr )
 {
-   Addr const addr = ptr - di->rx_map_avma;
+   Addr const addr = ptr - di->fsm.rx_map_avma;
    Addr a_mid_lo, a_mid_hi;
    Word mid, size,
         lo = 0,