This patch decreases significantly the memory needed to store the lineloc info.

On a big executable, the trunk needs:
dinfo: 134873088/71438336  max/curr mmap'd, 134607808/66717872 max/curr

With the patch, we have:
dinfo: 99065856/56836096  max/curr mmap'd,   97883776/51663656 max/curr

So, peak dinfo memory decreases by about 36Mb, and final by 15Mb.

(for info, valgrind 3.9.0 uses
dinfo: 158941184/109666304  max/curr mmap'd, 156775944/107590656 max/curr
So, compared to 3.9.0, dinfo peak decreases by about 40%, and the final
memory is divided by more than 2).

The memory decrease is obtained by:

* using a dedup pool to store filename/dirname pair for the loctab source/line
  information.
  As typically, there is not a lot of such pairs, typically a UShort is
  good enough to identify a fn/dn pair in a dedup pool.
  To avoid losing memory due to alignment, the fndn indexes are stored
  in a "parallel" array to the DiLoc loctab array, with entries having
  1, or 2 or 4 bytes according to the nr of fn/dn pairs in the dedup pool.
  See priv_storage.h comments for details.

  (there was a extensible WordArray local implementation in readdwarf.c.
   As with this change, we use an xarray, the local implementation was
   removed).

* the memory needed for --read-inline-info is slightly decreased (-2Mb)
  by removing the (unused) dirname from the DiInlLoc struct.
  Handling dirname for inlined function caller implies to rework
  the dwarf3 parser read_filename_table common to the var and inlinfo parser.
  Waiting for this to be done, the dirname component is removed from DiInlLoc.

* the stabs reader (readstabs.c) is broken since 3.9.0. 
  For this change, the code has been updated to make it compile with the new
  DiLoc/FnDn dedup pool. As the code is completely broken, a vg_assert(0)
  has been put at the begin of the stabs reader.

* the pdb reader (readpdb.c) has been trivially updated and should still work.
  It has not been tested (how do we test this ?).
  A follow-up patch will be done to avoid doing too many calls to
  ML_(addFnDn) : instead of having one call per ML_(addLineInfo), one
  should have a single call done when reading the filename table.

This has also be tested in an outer/inner setup, to verify no
memory leak/bugs.




git-svn-id: svn://svn.valgrind.org/valgrind/trunk@14158 a5019735-40e9-0310-863c-91ae7b9d1cf9
diff --git a/NEWS b/NEWS
index b8f48ce..1c85728 100644
--- a/NEWS
+++ b/NEWS
@@ -74,6 +74,8 @@
 * Error messages about fishy arguments (formerly known as silly arguments)
   now include a back-trace to aid debugging.
 
+* Reduction of memory used by Valgrind to read and store the debug information.
+
 * ==================== FIXED BUGS ====================
 
 The following bugs have been fixed or resolved.  Note that "n-i-bz"
diff --git a/coregrind/m_debuginfo/debuginfo.c b/coregrind/m_debuginfo/debuginfo.c
index 13d27f0..85d3ca8 100644
--- a/coregrind/m_debuginfo/debuginfo.c
+++ b/coregrind/m_debuginfo/debuginfo.c
@@ -217,6 +217,7 @@
    if (di->fsm.filename) ML_(dinfo_free)(di->fsm.filename);
    if (di->soname)       ML_(dinfo_free)(di->soname);
    if (di->loctab)       ML_(dinfo_free)(di->loctab);
+   if (di->loctab_fndn_ix) ML_(dinfo_free)(di->loctab_fndn_ix);
    if (di->inltab)       ML_(dinfo_free)(di->inltab);
    if (di->cfsi_base)    ML_(dinfo_free)(di->cfsi_base);
    if (di->cfsi_m_ix)    ML_(dinfo_free)(di->cfsi_m_ix);
@@ -240,6 +241,8 @@
 
    if (di->strpool)
       VG_(deleteDedupPA) (di->strpool);
+   if (di->fndnpool)
+      VG_(deleteDedupPA) (di->fndnpool);
 
    /* Delete the two admin arrays.  These lists exist primarily so
       that we can visit each object exactly once when we need to
@@ -1909,10 +1912,19 @@
 {
    DebugInfo* si;
    Word       locno;
+   UInt       fndn_ix;
+   FnDn*      fndn;
+
    search_all_loctabs ( a, &si, &locno );
    if (si == NULL) 
       return False;
-   VG_(strncpy_safely)(filename, si->loctab[locno].filename, n_filename);
+   fndn_ix = ML_(fndn_ix) (si, locno);
+   if (fndn_ix == 0)
+      VG_(strncpy_safely)(filename, "???", n_filename);
+   else {
+      fndn = VG_(indexEltNumber) (si->fndnpool, fndn_ix);
+      VG_(strncpy_safely)(filename, fndn->filename, n_filename);
+   }
    return True;
 }
 
@@ -1940,6 +1952,8 @@
 {
    DebugInfo* si;
    Word       locno;
+   UInt       fndn_ix;
+   FnDn*      fndn = NULL;
 
    vg_assert( (dirname == NULL && dirname_available == NULL)
               ||
@@ -1954,17 +1968,22 @@
       return False;
    }
 
-   VG_(strncpy_safely)(filename, si->loctab[locno].filename, n_filename);
+   fndn_ix = ML_(fndn_ix)(si, locno);
+   if (fndn_ix == 0)
+      VG_(strncpy_safely)(filename, "???", n_filename);
+   else {
+      fndn = VG_(indexEltNumber) (si->fndnpool, fndn_ix);
+      VG_(strncpy_safely)(filename, fndn->filename, n_filename);
+   }
    *lineno = si->loctab[locno].lineno;
 
    if (dirname) {
       /* caller wants directory info too .. */
       vg_assert(n_dirname > 0);
-      if (si->loctab[locno].dirname) {
+      if (fndn_ix != 0 && fndn->dirname) {
          /* .. and we have some */
          *dirname_available = True;
-         VG_(strncpy_safely)(dirname, si->loctab[locno].dirname,
-                                      n_dirname);
+         VG_(strncpy_safely)(dirname, fndn->dirname, n_dirname);
       } else {
          /* .. but we don't have any */
          *dirname_available = False;
@@ -2156,8 +2175,7 @@
       VG_(snprintf) (buf_srcloc, BUF_LEN, "%s", cur_inl->filename);
       lineno = cur_inl->lineno;
 
-      know_dirinfo = False; //INLINED TBD
-
+      know_dirinfo = False;
       know_srcloc = True;
    }
          
diff --git a/coregrind/m_debuginfo/priv_storage.h b/coregrind/m_debuginfo/priv_storage.h
index 000d5f1..817efae 100644
--- a/coregrind/m_debuginfo/priv_storage.h
+++ b/coregrind/m_debuginfo/priv_storage.h
@@ -103,6 +103,15 @@
  */
 #define OVERFLOW_DIFFERENCE     (LINENO_OVERFLOW - 5000)
 
+/* Filename and Dirname pair. FnDn are stored in di->fndnpool
+   and are allocated using VG_(allocFixedEltDedupPA).
+   The filename/dirname strings are themselves stored in di->strpool. */
+typedef
+   struct {
+      const HChar* filename;     /* source filename */
+      const HChar* dirname;      /* source directory name */
+   } FnDn;
+
 /* A structure to hold addr-to-source info for a single line.  There
   can be a lot of these, hence the dense packing. */
 typedef
@@ -112,10 +121,6 @@
       /* Word 2 */
       UShort size:LOC_SIZE_BITS; /* # bytes; we catch overflows of this */
       UInt   lineno:LINENO_BITS; /* source line number, or zero */
-      /* Word 3 */
-      const HChar* filename;     /* source filename */
-      /* Word 4 */
-      const HChar* dirname;      /* source directory name */
    }
    DiLoc;
 
@@ -123,7 +128,10 @@
 #define MAX_LEVEL     ((1 << LEVEL_BITS) - 1)
 
 /* A structure to hold addr-to-inlined fn info.  There
-  can be a lot of these, hence the dense packing. */
+   can be a lot of these, hence the dense packing.
+   Only caller source filename and lineno are stored.
+   Handling dirname should be done using fndn_ix technique
+   similar to  ML_(addLineInfo). */
 typedef
    struct {
       /* Word 1 */
@@ -135,8 +143,6 @@
       /* Word 4 */
       const HChar* filename;     /* caller source filename */
       /* Word 5 */
-      const HChar* dirname;      /* caller source directory name */
-      /* Word 6 */
       UInt   lineno:LINENO_BITS; /* caller line number */
       UShort level:LEVEL_BITS;   /* level of inlining */
    }
@@ -812,8 +818,14 @@
    DiSym*  symtab;
    UWord   symtab_used;
    UWord   symtab_size;
-   /* An expandable array of locations. */
+   /* Two expandable arrays, storing locations and their filename/dirname. */
    DiLoc*  loctab;
+   UInt    sizeof_fndn_ix;  /* Similar use as sizeof_cfsi_m_ix below. */
+   void*   loctab_fndn_ix;  /* loctab[i] filename/dirname is identified by
+                               loctab_fnindex_ix[i] (an index in di->fndnpool)
+                               0 means filename/dirname unknown.
+                               The void* is an UChar* or UShort* or UInt*
+                               depending on sizeof_fndn_ix. */
    UWord   loctab_used;
    UWord   loctab_size;
    /* An expandable array of inlined fn info.
@@ -838,16 +850,16 @@
 
       For each base in cfsi_base, an index into cfsi_m_pool is stored
       in cfsi_m_ix array. The size of cfsi_m_ix is equal to
-      cfsi_size*sizeof_ix. The used portion of cfsi_m_ix is
-      cfsi_m_ix[0] till cfsi_m_ix[(cfsi_used-1)*sizeof_ix].
+      cfsi_size*sizeof_cfsi_m_ix. The used portion of cfsi_m_ix is
+      cfsi_m_ix[0] till cfsi_m_ix[(cfsi_used-1)*sizeof_cfsi_m_ix].
 
       cfsi_base[i] gives the base address of a code range covered by
       some CF Info. The corresponding CF Info is identified by an index
       in cfsi_m_pool. The DiCfSI_m index in cfsi_m_pool corresponding to
       cfsi_base[i] is given
-        by ((UChar*) cfsi_m_ix)[i] if sizeof_ix == 1
-        by ((UShort*)cfsi_m_ix)[i] if sizeof_ix == 2
-        by ((UInt*)  cfsi_m_ix)[i] if sizeof_ix == 4.
+        by ((UChar*) cfsi_m_ix)[i] if sizeof_cfsi_m_ix == 1
+        by ((UShort*)cfsi_m_ix)[i] if sizeof_cfsi_m_ix == 2
+        by ((UInt*)  cfsi_m_ix)[i] if sizeof_cfsi_m_ix == 4.
 
       The end of the code range starting at cfsi_base[i] is given by
       cfsi_base[i+1]-1 (or cfsi_maxavma for  cfsi_base[cfsi_used-1]).
@@ -875,8 +887,8 @@
       records require any expression nodes, they are stored in
       cfsi_exprs. */
    Addr* cfsi_base;
-   UInt  sizeof_ix; /* size in byte of the indexes stored in cfsi_m_ix. */
-   void* cfsi_m_ix; /* Each index occupies sizeof_ix bytes. */
+   UInt  sizeof_cfsi_m_ix; /* size in byte of indexes stored in cfsi_m_ix. */
+   UInt* cfsi_m_ix; /* Each index occupies sizeof_cfsi_m_ix bytes. */
 
    DiCfSI* cfsi_rd; /* Only used during reading, NULL once info is read. */
                                    
@@ -900,6 +912,10 @@
       into this are stable (the memory is not reallocated). */
    DedupPoolAlloc *strpool;
 
+   /* Pool of FnDn -- filename and dirname.
+      Elements in the pool are allocated using VG_(allocFixedEltDedupPA). */
+   DedupPoolAlloc *fndnpool;
+
    /* Variable scope information, as harvested from Dwarf3 files.
 
       In short it's an
@@ -953,18 +969,30 @@
    to ensure that's OK. */
 extern void ML_(addSym) ( struct _DebugInfo* di, DiSym* sym );
 
-/* Add a line-number record to a DebugInfo. */
+/* Add a filename/dirname pair to a DebugInfo and returns the index
+   in the fndnpool fixed pool. */
+extern UInt ML_(addFnDn) (struct _DebugInfo* di,
+                          const HChar* filename, 
+                          const HChar* dirname);  /* NULL is allowable */
+
+/* Returns the fndn_ix for the LineInfo locno in di->loctab.
+   0 if filename/dirname are unknown. */
+extern UInt ML_(fndn_ix) (struct _DebugInfo* di, Word locno);
+
+/* Add a line-number record to a DebugInfo.
+   fndn_ix is an index in di->fndnpool, allocated using  ML_(addFnDn).
+   Give a 0 index for a unknown filename/dirname pair. */
 extern
 void ML_(addLineInfo) ( struct _DebugInfo* di, 
-                        const HChar* filename, 
-                        const HChar* dirname,  /* NULL is allowable */
+                        UInt fndn_ix,
                         Addr this, Addr next, Int lineno, Int entry);
 
 /* Add a call inlined record to a DebugInfo.
    A call to the below means that inlinedfn code has been
    inlined, resulting in code from [addr_lo, addr_hi[.
    Note that addr_hi is excluded, i.e. is not part of the inlined code.
-   The call that caused this inlining is in filename/dirname/lineno
+   The call that caused this inlining is in filename/lineno (dirname
+   is not recorded).
    In case of nested inlining, a small level indicates the call
    is closer to main that a call with a higher level. */
 extern
@@ -972,7 +1000,6 @@
                        Addr addr_lo, Addr addr_hi,
                        const HChar* inlinedfn,
                        const HChar* filename, 
-                       const HChar* dirname,  /* NULL is allowable */
                        Int lineno, UShort level);
 
 /* Add a CFI summary record.  The supplied DiCfSI_m is copied. */
diff --git a/coregrind/m_debuginfo/readdwarf.c b/coregrind/m_debuginfo/readdwarf.c
index c6e9ebe..91c1493 100644
--- a/coregrind/m_debuginfo/readdwarf.c
+++ b/coregrind/m_debuginfo/readdwarf.c
@@ -54,81 +54,30 @@
 /*---                                                      ---*/
 /*------------------------------------------------------------*/
 
-/*------------------------------------------------------------*/
-/*--- Expanding arrays of words, for holding file name and ---*/
-/*--- directory name arrays.                               ---*/
-/*------------------------------------------------------------*/
+/* The below "safe_*ix" functions allow to resist to malformed dwarf info:
+   if dwarf info contains wrong file or dirname indexes, these are (silently!)
+   ignored. */
 
-typedef
-   struct {
-      Word* tab;
-      UInt  tab_size;
-      UInt  tab_used;
-   }
-   WordArray;
-
-static void init_WordArray ( WordArray* wa )
+/* if xa_ix is a valid index in fndn_ix_xa,
+    return the element (i.e. the UInt indexing in fndnpool).
+   If xa_ix is invalid, return 0 (i.e. the "null" element in fndnpool). */
+static UInt safe_fndn_ix (XArray* fndn_ix_xa, Int xa_ix)
 {
-   wa->tab      = NULL;
-   wa->tab_size = 0;
-   wa->tab_used = 0;
+   if (xa_ix < 0) return 0;
+   if (xa_ix >= VG_(sizeXA) (fndn_ix_xa)) return 0;
+   return *(UInt*)VG_(indexXA) ( fndn_ix_xa, xa_ix );
 }
 
-static void free_WordArray ( WordArray* wa )
+/* if xa_ix is a valid index in dirname_xa,
+    return the element (i.e. the HChar*).
+   If xa_ix is invalid, return NULL. */
+static HChar* safe_dirname_ix (XArray* dirname_xa, Int xa_ix)
 {
-   if (wa->tab) {
-      vg_assert(wa->tab_size > 0);
-      ML_(dinfo_free)(wa->tab);
-   }
-   init_WordArray(wa);
+   if (xa_ix < 0) return NULL;
+   if (xa_ix >= VG_(sizeXA) (dirname_xa)) return NULL;
+   return *(HChar**)VG_(indexXA) ( dirname_xa, xa_ix );
 }
 
-static void addto_WordArray ( WordArray* wa, Word w )
-{
-   UInt  new_size, i;
-   Word* new_tab;
-
-   if (0) VG_(printf)("<<ADD %p (new sz = %d) >>\n", 
-                      (HChar*)w, wa->tab_used+1);
-
-   if (wa->tab_used < wa->tab_size) {
-      /* fine */
-   } else {
-      /* expand array */
-      if (0) VG_(printf)("EXPAND ARRAY from %d\n", wa->tab_size);
-      vg_assert(wa->tab_used == wa->tab_size);
-      vg_assert( (wa->tab_size == 0 && wa->tab == NULL)
-                 || (wa->tab_size != 0 && wa->tab != NULL) );
-      new_size = wa->tab_size == 0 ? 8 : 2 * wa->tab_size;
-      new_tab  = ML_(dinfo_zalloc)("di.aWA.1", new_size * sizeof(Word));
-      vg_assert(new_tab != NULL);
-      for (i = 0; i < wa->tab_used; i++)
-         new_tab[i] = wa->tab[i];
-      wa->tab_size = new_size;
-      if (wa->tab)
-         ML_(dinfo_free)(wa->tab);
-      wa->tab = new_tab;
-   }
-
-   vg_assert(wa->tab_used < wa->tab_size);
-   vg_assert(wa->tab_size > 0);
-   wa->tab[wa->tab_used] = w;
-   wa->tab_used++;
-}
-
-static Word index_WordArray ( /*OUT*/Bool* inRange, WordArray* wa, Int i )
-{
-   vg_assert(inRange);
-   if (i >= 0 && i < wa->tab_used) {
-      *inRange = True;
-      return wa->tab[i];
-   } else {
-      *inRange = False;
-      return 0;
-   }
-}
-
-
 /*------------------------------------------------------------*/
 /*--- Read DWARF2 format line number info.                 ---*/
 /*------------------------------------------------------------*/
@@ -296,26 +245,6 @@
    state_machine_regs.end_sequence = 0;
 }
 
-/* Look up a directory name, or return NULL if unknown. */
-static
-HChar* lookupDir ( Int filename_index,
-                   WordArray* fnidx2dir,
-                   WordArray* dirnames )
-{
-   Bool inRange;
-   Word diridx, dirname;
-
-   diridx = index_WordArray( &inRange, fnidx2dir, filename_index );
-   if (!inRange) goto bad;
-
-   dirname = index_WordArray( &inRange, dirnames, (Int)diridx );
-   if (!inRange) goto bad;
-
-   return (HChar*)dirname;
-  bad:
-   return NULL;
-}
-
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
 
@@ -323,9 +252,7 @@
    accordingly. */
 static 
 void process_extended_line_op( struct _DebugInfo* di,
-                               WordArray* filenames, 
-                               WordArray* dirnames, 
-                               WordArray* fnidx2dir, 
+                               XArray* fndn_ix_xa,
                                DiCursor* data, Int is_stmt)
 {
    UInt len = step_leb128U(data);
@@ -349,17 +276,10 @@
 
          if (state_machine_regs.is_stmt) {
             if (state_machine_regs.last_address) {
-               Bool inRange = False;
-               const HChar* filename
-                  = (HChar*)index_WordArray( &inRange, filenames, 
-                                             state_machine_regs.last_file);
-               if (!inRange || !filename)
-                  filename = "???";
                ML_(addLineInfo) (
-                  di, 
-                  filename, 
-                  lookupDir( state_machine_regs.last_file,
-                             fnidx2dir, dirnames ),
+                  di,
+                  safe_fndn_ix (fndn_ix_xa,
+                                state_machine_regs.last_file),
                   di->text_debug_bias + state_machine_regs.last_address, 
                   di->text_debug_bias + state_machine_regs.address, 
                   state_machine_regs.last_line, 0
@@ -383,7 +303,8 @@
 
       case DW_LNE_define_file: {
          HChar* name = ML_(cur_step_strdup)(data, "di.pelo.1");
-         addto_WordArray( filenames, (Word)ML_(addStr)(di,name,-1) );
+         UInt fndn_ix = ML_(addFnDn) (di, name, NULL);
+         VG_(addToXA) (fndn_ix_xa, &fndn_ix);
          ML_(dinfo_free)(name);
          (void)step_leb128U(data); // ignored: dir index
          (void)step_leb128U(data); // ignored: mod time
@@ -425,55 +346,48 @@
    Int            i;
    DebugLineInfo  info;
    Bool           is64;
-   WordArray      filenames;
-   WordArray      dirnames;
-   WordArray      fnidx2dir;
+   XArray*        fndn_ix_xa; /* xarray of UInt fndn_ix */
+   UInt           fndn_ix;
+   XArray*        dirname_xa;   /* xarray of HChar* dirname */
+   HChar*         dirname;
 
    DiCursor       external = theBlock;
    DiCursor       data = theBlock;
 
-   /* filenames is an array of file names harvested from the DWARF2
-      info.  Entry [0] is NULL and is never referred to by the state
-      machine.
+   /* fndn_ix_xa is an xarray of fndn_ix (indexes in di->fndnpool) which
+      are build from file names harvested from the DWARF2
+      info.  Entry [0] is the "null" pool index and is never referred to
+      by the state machine.
 
-      Similarly, dirnames is an array of directory names.  Entry [0]
+      Similarly, dirname_xa is an xarray of directory names.  Entry [0]
       is also NULL and denotes "we don't know what the path is", since
       that is different from "the path is the empty string".  Unlike
-      the file name table, the state machine does refer to entry [0],
+      the fndn_ix_xa table, the state machine does refer to entry [0],
       which basically means "." ("the current directory of the
       compilation", whatever that means, according to the DWARF3
       spec.)
-
-      fnidx2dir is an array of indexes into the dirnames table.
-      (confused yet?)  filenames[] and fnidx2dir[] are indexed
-      together.  That is, for some index i in the filename table, then
-
-         the filename  is filenames[i]
-         the directory is dirnames[ fnidx2dir[i] ] */
+   */
 
    /* Fails due to gcc padding ...
    vg_assert(sizeof(DWARF2_External_LineInfo)
              == sizeof(DWARF2_Internal_LineInfo));
    */
 
-   init_WordArray(&filenames);
-   init_WordArray(&dirnames);
-   init_WordArray(&fnidx2dir);
+   dirname_xa = VG_(newXA) (ML_(dinfo_zalloc), "di.rd2l.1", ML_(dinfo_free),
+                            sizeof(HChar*) );
+   fndn_ix_xa = VG_(newXA) (ML_(dinfo_zalloc), "di.rd2l.2", ML_(dinfo_free),
+                            sizeof(UInt) );
 
    /* DWARF2 starts numbering filename entries at 1, so we need to
-      add a dummy zeroth entry to the table.  The zeroth dirnames
-      entry denotes 'current directory of compilation' so we might
-      as well make the fnidx2dir zeroth entry denote that. 
-   */
-   addto_WordArray( &filenames, (Word)NULL );
+      add a dummy zeroth entry to the table. */
+   fndn_ix = 0; // 0 is the "null" index in a fixed pool.
+   VG_(addToXA) (fndn_ix_xa, &fndn_ix);
 
    if (ML_(cur_is_valid)(ui->compdir))
-      addto_WordArray( &dirnames,
-                       (Word)ML_(addStrFromCursor)(di, ui->compdir) );
+      dirname = ML_(addStrFromCursor)(di, ui->compdir);
    else
-      addto_WordArray( &dirnames, (Word)ML_(addStr)(di, ".", -1) );
-
-   addto_WordArray( &fnidx2dir, (Word)0 );  /* compilation dir */
+      dirname = ML_(addStr)(di, ".", -1);
+   VG_(addToXA) (dirname_xa, &dirname);
 
    info.li_length = step_initial_length_field( &external, &is64 );
    if (di->ddump_line)
@@ -629,12 +543,14 @@
          VG_(strcat)(buf, "/");
          VG_(strcat)(buf, data_str);
          vg_assert(VG_(strlen)(buf) < NBUF);
-         addto_WordArray( &dirnames, (Word)ML_(addStr)(di,buf,-1) );
+         dirname = ML_(addStr)(di,buf,-1);
+         VG_(addToXA) (dirname_xa, &dirname);
          if (0) VG_(printf)("rel path  %s\n", buf);
          ML_(dinfo_free)(compdir_str);
       } else {
          /* just use 'data'. */
-         addto_WordArray( &dirnames, (Word)ML_(addStr)(di,data_str,-1) );
+         dirname = ML_(addStr)(di,data_str,-1);
+         VG_(addToXA) (dirname_xa, &dirname);
          if (0) VG_(printf)("abs path  %s\n", data_str);
       }
 
@@ -655,8 +571,7 @@
    data = ML_(cur_plus)(data, 1);
 
    /* Read the contents of the File Name table.  This produces a bunch
-      of file names, and for each, an index to the corresponding
-      directory name entry. */
+      of fndn_ix in fndn_ix_xa. */
    if (di->ddump_line) {
       VG_(printf)(" The File Name Table:\n");
       VG_(printf)("  Entry	Dir	Time	Size	Name\n");
@@ -668,8 +583,10 @@
       Int    diridx  = step_leb128U(&data);
       Int    uu_time = step_leb128U(&data); /* unused */
       Int    uu_size = step_leb128U(&data); /* unused */
-      addto_WordArray( &filenames, (Word)ML_(addStr)(di,name,-1) );
-      addto_WordArray( &fnidx2dir, (Word)diridx );
+
+      dirname = safe_dirname_ix( dirname_xa, diridx );
+      fndn_ix = ML_(addFnDn) (di, name, dirname);
+      VG_(addToXA) (fndn_ix_xa, &fndn_ix);
       if (0) VG_(printf)("file %s diridx %d\n", name, diridx );
       if (di->ddump_line)
          VG_(printf)("  %d\t%d\t%d\t%d\t%s\n", 
@@ -720,17 +637,10 @@
          if (state_machine_regs.is_stmt) {
             /* only add a statement if there was a previous boundary */
             if (state_machine_regs.last_address) {
-               Bool inRange = False;
-               const HChar* filename
-                  = (HChar*)index_WordArray( &inRange, &filenames, 
-                                             state_machine_regs.last_file);
-               if (!inRange || !filename)
-                  filename = "???";
                ML_(addLineInfo)(
-                  di, 
-                  filename,
-                  lookupDir( state_machine_regs.last_file,
-                             &fnidx2dir, &dirnames ),
+                  di,
+                  safe_fndn_ix (fndn_ix_xa,
+                                state_machine_regs.last_file),
                   di->text_debug_bias + state_machine_regs.last_address, 
                   di->text_debug_bias + state_machine_regs.address, 
                   state_machine_regs.last_line, 
@@ -748,7 +658,7 @@
       switch (op_code) {
          case DW_LNS_extended_op:
             process_extended_line_op (
-                       di, &filenames, &dirnames, &fnidx2dir,
+                       di, fndn_ix_xa,
                        &data, info.li_default_is_stmt);
             break;
 
@@ -758,17 +668,10 @@
             if (state_machine_regs.is_stmt) {
                /* only add a statement if there was a previous boundary */
                if (state_machine_regs.last_address) {
-                  Bool inRange = False;
-                  const HChar* filename
-                     = (HChar*)index_WordArray( &inRange, &filenames,
-                                                state_machine_regs.last_file );
-                  if (!inRange || !filename)
-                     filename = "???";
                   ML_(addLineInfo)(
-                     di, 
-                     filename,
-                     lookupDir( state_machine_regs.last_file,
-                                &fnidx2dir, &dirnames ),
+                     di,
+                     safe_fndn_ix (fndn_ix_xa,
+                                   state_machine_regs.last_file), 
                      di->text_debug_bias + state_machine_regs.last_address, 
                      di->text_debug_bias + state_machine_regs.address,
                      state_machine_regs.last_line, 
@@ -887,9 +790,8 @@
       VG_(printf)("\n");
 
   out:
-   free_WordArray(&filenames);
-   free_WordArray(&dirnames);
-   free_WordArray(&fnidx2dir);
+   VG_(deleteXA)(dirname_xa);
+   VG_(deleteXA)(fndn_ix_xa);
 }
 
 ////////////////////////////////////////////////////////////////////
diff --git a/coregrind/m_debuginfo/readdwarf3.c b/coregrind/m_debuginfo/readdwarf3.c
index a3c0a0f..0dd49df 100644
--- a/coregrind/m_debuginfo/readdwarf3.c
+++ b/coregrind/m_debuginfo/readdwarf3.c
@@ -2600,7 +2600,6 @@
                              ip_lo, ip_hi1, 
                              get_inlFnName (inlinedfn_abstract_origin, cc, td3),
                              caller_filename,
-                             NULL, // INLINED TBD dirname ?????
                              caller_lineno, level);
          }
       } else if (have_range) {
@@ -2622,7 +2621,6 @@
                              // included.
                              inlfnname,
                              caller_filename,
-                             NULL, // INLINED TBD dirname ?????
                              caller_lineno, level);
          }
          VG_(deleteXA)( ranges );
diff --git a/coregrind/m_debuginfo/readelf.c b/coregrind/m_debuginfo/readelf.c
index c57ac22..9c69750 100644
--- a/coregrind/m_debuginfo/readelf.c
+++ b/coregrind/m_debuginfo/readelf.c
@@ -1453,6 +1453,7 @@
    vg_assert(!di->cfsi_rd);
    vg_assert(!di->cfsi_exprs);
    vg_assert(!di->strpool);
+   vg_assert(!di->fndnpool);
    vg_assert(!di->soname);
 
    {
diff --git a/coregrind/m_debuginfo/readpdb.c b/coregrind/m_debuginfo/readpdb.c
index 3824a33..6d2ccd1 100644
--- a/coregrind/m_debuginfo/readpdb.c
+++ b/coregrind/m_debuginfo/readpdb.c
@@ -1630,7 +1630,11 @@
                         ((const unsigned short *)(pnt2.ui + linecount))[j],
                         startaddr, endaddr );
                   ML_(addLineInfo)(
-                     di, fnmstr, dirstr, startaddr, endaddr,
+                     di, 
+                     ML_(addFnDn) (di, // fndnTBD
+                                   fnmstr,
+                                   dirstr), 
+                     startaddr, endaddr,
                      ((const unsigned short *)(pnt2.ui + linecount))[j], j );
                   n_lines_read++;
                }
@@ -1767,7 +1771,10 @@
             if (debug)
                VG_(printf)("%s  line %d: %08lx to %08lx\n",
                            pfx, lbh->l[i].lineno ^ 0x80000000, svma_s, svma_e);
-            ML_(addLineInfo)( di, filename, dirname,
+            ML_(addLineInfo)( di, 
+                              ML_(addFnDn) (di, // fndnTBD
+                                            filename,
+                                            dirname),
                               bias + svma_s,
                               bias + svma_e + 1,
                               lbh->l[i].lineno ^ 0x80000000, 0 );
@@ -1781,7 +1788,10 @@
             VG_(printf)("%s  line %d: %08lx to %08lx\n",
                         pfx, lbh->l[ lbh->nlines-1  ].lineno ^ 0x80000000,
                         svma_s, svma_e);
-          ML_(addLineInfo)( di, filename, dirname,
+          ML_(addLineInfo)( di, 
+                            ML_(addFnDn) (di, // fndnTBD
+                                          filename,
+                                          dirname),
                             bias + svma_s,
                             bias + svma_e + 1,
                             lbh->l[lbh->nlines-1].lineno ^ 0x80000000, 0 );
diff --git a/coregrind/m_debuginfo/readstabs.c b/coregrind/m_debuginfo/readstabs.c
index 736ae82..e9892dc 100644
--- a/coregrind/m_debuginfo/readstabs.c
+++ b/coregrind/m_debuginfo/readstabs.c
@@ -124,6 +124,12 @@
       Bool     first;         /* first line in function */
    } line = { 0, 0, 0, 0, False };
 
+   vg_assert (0);
+   /* Stab reader broken since debuginfo server (revision 13440)
+      See #if 0 for call to  ML_(read_debuginfo_stabs) in readelf.c.
+      If ever it is repaired, file.name above should be replaced by a fndn_ix
+      for performance reasons. */
+
    /* Ok.  It all looks plausible.  Go on and read debug data. 
          stab kinds: 100   N_SO     a source file name
                       68   N_SLINE  a source line number
@@ -270,7 +276,11 @@
 
             if (line.addr != 0) {
                /* finish off previous line */
-               ML_(addLineInfo)(di, file.name, NULL, line.addr,
+               ML_(addLineInfo)(di, 
+                                ML_(addFnDn) (di,
+                                              file.name,
+                                              NULL),
+                                line.addr,
                                 addr, line.no + line.ovf * LINENO_OVERFLOW, i);
             }
 
@@ -294,7 +304,11 @@
 
             if (line.addr != 0) {
                /* there was a previous */
-               ML_(addLineInfo)(di, file.name, NULL, line.addr,
+               ML_(addLineInfo)(di, 
+                                ML_(addFnDn)(di,
+                                             file.name,
+                                             NULL), 
+                                line.addr,
                                 addr, line.no + line.ovf * LINENO_OVERFLOW, i);
             }
 
@@ -353,7 +367,11 @@
             }
 
             if (line.addr) {
-               ML_(addLineInfo)(di, file.name, NULL, line.addr,
+               ML_(addLineInfo)(di, 
+                                ML_(addFnDn) (di,
+                                              file.name,
+                                              NULL),
+                                line.addr,
                                 addr, line.no + line.ovf * LINENO_OVERFLOW, i);
                line.addr = 0;
             }
diff --git a/coregrind/m_debuginfo/storage.c b/coregrind/m_debuginfo/storage.c
index 78bcdf6..c2bbe82 100644
--- a/coregrind/m_debuginfo/storage.c
+++ b/coregrind/m_debuginfo/storage.c
@@ -252,6 +252,24 @@
    return p;
 }
 
+UInt ML_(addFnDn) (struct _DebugInfo* di,
+                   const HChar* filename, 
+                   const HChar* dirname)
+{
+   FnDn fndn;
+   UInt fndn_ix;
+
+   if (UNLIKELY(di->fndnpool == NULL))
+      di->fndnpool = VG_(newDedupPA)(500,
+                                     vg_alignof(FnDn),
+                                     ML_(dinfo_zalloc),
+                                     "di.storage.addFnDn.1",
+                                     ML_(dinfo_free));
+   fndn.filename = ML_(addStr)(di, filename, -1);
+   fndn.dirname = dirname ? ML_(addStr)(di, dirname, -1) : NULL;
+   fndn_ix = VG_(allocFixedEltDedupPA) (di->fndnpool, sizeof(FnDn), &fndn);
+   return fndn_ix;
+}
 
 /* Add a string to the string table of a DebugInfo, by copying the
    string from the given DiCursor.  Measures the length of the string
@@ -301,32 +319,101 @@
    vg_assert(di->symtab_used <= di->symtab_size);
 }
 
+UInt ML_(fndn_ix) (struct _DebugInfo* di, Word locno)
+{
+   UInt fndn_ix;
+
+   switch(di->sizeof_fndn_ix) {
+      case 1: fndn_ix = ((UChar*)  di->loctab_fndn_ix)[locno]; break;
+      case 2: fndn_ix = ((UShort*) di->loctab_fndn_ix)[locno]; break;
+      case 4: fndn_ix = ((UInt*)   di->loctab_fndn_ix)[locno]; break;
+      default: vg_assert(0);
+   }
+   return fndn_ix;
+}
+
+static inline void set_fndn_ix (struct _DebugInfo* di, Word locno, UInt fndn_ix)
+{
+   Word i;
+
+   switch(di->sizeof_fndn_ix) {
+      case 1: 
+         if (LIKELY (fndn_ix <= 255)) {
+            ((UChar*) di->loctab_fndn_ix)[locno] = fndn_ix;
+            return;
+         }
+         {
+            UChar* old = (UChar*) di->loctab_fndn_ix;
+            UShort* new = ML_(dinfo_zalloc)( "di.storage.sfix.1",
+                                             di->loctab_size * 2 );
+            for (i = 0; i < di->loctab_used; i++)
+               new[i] = old[i];
+            ML_(dinfo_free)(old);
+            di->sizeof_fndn_ix = 2;
+            di->loctab_fndn_ix = new;
+         }
+         // Fallthrough
+
+      case 2:
+         if (LIKELY (fndn_ix <= 65535)) {
+            ((UShort*) di->loctab_fndn_ix)[locno] = fndn_ix;
+            return;
+         }
+         {
+            UShort* old = (UShort*) di->loctab_fndn_ix;
+            UInt* new = ML_(dinfo_zalloc)( "di.storage.sfix.2",
+                                           di->loctab_size * 4 );
+            for (i = 0; i < di->loctab_used; i++)
+               new[i] = old[i];
+            ML_(dinfo_free)(old);
+            di->sizeof_fndn_ix = 4;
+            di->loctab_fndn_ix = new;
+         }
+         // Fallthrough
+
+      case 4:
+         ((UInt*) di->loctab_fndn_ix)[locno] = fndn_ix;
+         return;
+
+      default: vg_assert(0);
+   }
+}
 
 /* Add a location to the location table. 
 */
-static void addLoc ( struct _DebugInfo* di, DiLoc* loc )
+static void addLoc ( struct _DebugInfo* di, DiLoc* loc, UInt fndn_ix )
 {
-   UInt   new_sz, i;
-   DiLoc* new_tab;
-
    /* Zero-sized locs should have been ignored earlier */
    vg_assert(loc->size > 0);
 
    if (di->loctab_used == di->loctab_size) {
+      UInt   new_sz;
+      DiLoc* new_loctab;
+      void*  new_loctab_fndn_ix;
+
       new_sz = 2 * di->loctab_size;
       if (new_sz == 0) new_sz = 500;
-      new_tab = ML_(dinfo_zalloc)( "di.storage.addLoc.1",
-                                   new_sz * sizeof(DiLoc) );
+      new_loctab = ML_(dinfo_zalloc)( "di.storage.addLoc.1",
+                                      new_sz * sizeof(DiLoc) );
+      if (di->sizeof_fndn_ix == 0)
+         di->sizeof_fndn_ix = 1; // To start with.
+      new_loctab_fndn_ix = ML_(dinfo_zalloc)( "di.storage.addLoc.2",
+                                              new_sz * di->sizeof_fndn_ix );
       if (di->loctab != NULL) {
-         for (i = 0; i < di->loctab_used; i++)
-            new_tab[i] = di->loctab[i];
+         VG_(memcpy)(new_loctab, di->loctab,
+                     di->loctab_used * sizeof(DiLoc));
+         VG_(memcpy)(new_loctab_fndn_ix, di->loctab_fndn_ix,
+                     di->loctab_used * di->sizeof_fndn_ix);
          ML_(dinfo_free)(di->loctab);
+         ML_(dinfo_free)(di->loctab_fndn_ix);
       }
-      di->loctab = new_tab;
+      di->loctab = new_loctab;
+      di->loctab_fndn_ix = new_loctab_fndn_ix;
       di->loctab_size = new_sz;
    }
 
    di->loctab[di->loctab_used] = *loc;
+   set_fndn_ix (di, di->loctab_used, fndn_ix);
    di->loctab_used++;
    vg_assert(di->loctab_used <= di->loctab_size);
 }
@@ -341,6 +428,7 @@
    if (new_sz == di->loctab_size) return;
    vg_assert(new_sz < di->loctab_size);
    ML_(dinfo_shrink_block)( di->loctab, new_sz * sizeof(DiLoc));
+   ML_(dinfo_shrink_block)( di->loctab_fndn_ix, new_sz * di->sizeof_fndn_ix);
    di->loctab_size = new_sz;
 }
 
@@ -348,8 +436,7 @@
 /* Top-level place to call to add a source-location mapping entry.
 */
 void ML_(addLineInfo) ( struct _DebugInfo* di,
-                        const HChar* filename,
-                        const HChar* dirname, /* NULL == directory is unknown */
+                        UInt     fndn_ix,
                         Addr     this,
                         Addr     next,
                         Int      lineno,
@@ -363,10 +450,13 @@
    /* Ignore zero-sized locs */
    if (this == next) return;
 
-   if (debug)
-      VG_(printf)( "  src %s %s line %d %#lx-%#lx\n",
-                   dirname ? dirname : "(unknown)",
-                   filename, lineno, this, next );
+   if (debug) {
+      FnDn *fndn = VG_(indexEltNumber) (di->fndnpool, fndn_ix);
+      VG_(printf)( "  src ix %u %s %s line %d %#lx-%#lx\n",
+                   fndn_ix, 
+                   fndn->dirname ? fndn->dirname : "(unknown)",
+                   fndn->filename, lineno, this, next );
+   }
 
    /* Maximum sanity checking.  Some versions of GNU as do a shabby
     * job with stabs entries; if anything looks suspicious, revert to
@@ -435,14 +525,12 @@
    loc.addr      = this;
    loc.size      = (UShort)size;
    loc.lineno    = lineno;
-   loc.filename  = filename;
-   loc.dirname   = dirname;
 
    if (0) VG_(message)(Vg_DebugMsg, 
-		       "addLoc: addr %#lx, size %lu, line %d, file %s\n",
-		       this,size,lineno,filename);
+		       "addLoc: addr %#lx, size %lu, line %d, fndn_ix %u\n",
+		       this,size,lineno,fndn_ix);
 
-   addLoc ( di, &loc );
+   addLoc ( di, &loc, fndn_ix );
 }
 
 /* Add an inlined call info to the inlined call table. 
@@ -494,7 +582,6 @@
                        Addr addr_lo, Addr addr_hi,
                        const HChar* inlinedfn,
                        const HChar* filename, 
-                       const HChar* dirname,  /* NULL is allowable */
                        Int lineno, UShort level)
 {
    DiInlLoc inl;
@@ -532,16 +619,14 @@
    inl.inlinedfn = inlinedfn;
    // caller:
    inl.filename  = filename;
-   inl.dirname   = dirname;
    inl.lineno    = lineno;
    inl.level     = level;
 
    if (0) VG_(message)
              (Vg_DebugMsg, 
               "addInlInfo: fn %s inlined as addr_lo %#lx,addr_hi %#lx,"
-              "caller %s:%d (dir %s)\n",
-              inlinedfn, addr_lo, addr_hi, filename, lineno, 
-              dirname ? dirname : "???");
+              "caller %s:%d\n",
+              inlinedfn, addr_lo, addr_hi, filename, lineno);
 
    addInl ( di, &inl );
 }
@@ -551,7 +636,7 @@
    UInt cfsi_m_ix;
 
    vg_assert(pos >= 0 && pos < di->cfsi_used);
-   switch (di->sizeof_ix) {
+   switch (di->sizeof_cfsi_m_ix) {
       case 1: cfsi_m_ix = ((UChar*)  di->cfsi_m_ix)[pos]; break;
       case 2: cfsi_m_ix = ((UShort*) di->cfsi_m_ix)[pos]; break;
       case 4: cfsi_m_ix = ((UInt*)   di->cfsi_m_ix)[pos]; break;
@@ -1743,33 +1828,72 @@
 }
 
 
+static DiLoc* sorting_loctab = NULL;
+static Int compare_DiLoc_via_ix ( const void* va, const void* vb ) 
+{
+   const DiLoc* a = &sorting_loctab[*(UInt*)va];
+   const DiLoc* b = &sorting_loctab[*(UInt*)vb];
+   if (a->addr < b->addr) return -1;
+   if (a->addr > b->addr) return  1;
+   return 0;
+}
+static void sort_loctab_and_loctab_fndn_ix (struct _DebugInfo* di )
+{
+   /* We have to sort the array loctab by addr
+      together with its "parallel" array loctab_fndn_ix.
+      We first build sort_ix : an array of indexes in loctab,
+      that we sort by loctab address. Then we can reorder both
+      arrays according to sort_ix. */
+   UInt *sort_ix = ML_(dinfo_zalloc)("di.storage.six",
+                                     di->loctab_used*sizeof(UInt));
+   Word i, j, k;
+
+   for (i = 0; i < di->loctab_used; i++) sort_ix[i] = i;
+   sorting_loctab = di->loctab;
+   VG_(ssort)(sort_ix, di->loctab_used, 
+              sizeof(*sort_ix), compare_DiLoc_via_ix);
+   sorting_loctab = NULL;
+
+   // Permute in place, using the sort_ix.
+   for (i=0; i < di->loctab_used; i++) {
+      DiLoc tmp_diloc;
+      UInt  tmp_fndn_ix;
+
+      if (i == sort_ix[i])
+         continue; // i already at the good place
+
+      tmp_diloc = di->loctab[i];
+      tmp_fndn_ix = ML_(fndn_ix)(di, i);
+      j = i;
+      for (;;) {
+         k = sort_ix[j];
+         sort_ix[j] = j;
+         if (k == i)
+            break;
+         di->loctab[j] = di->loctab[k];
+         set_fndn_ix (di, j, ML_(fndn_ix)(di, k));
+         j = k;
+      }
+      di->loctab[j] = tmp_diloc;
+      set_fndn_ix (di, j, tmp_fndn_ix);
+   }
+   ML_(dinfo_free)(sort_ix);
+}
+
 /* Sort the location table by starting address.  Mash the table around
    so as to establish the property that addresses are in order and the
    ranges do not overlap.  This facilitates using binary search to map
    addresses to locations when we come to query the table.
 */
-static Int compare_DiLoc ( const void* va, const void* vb ) 
-{
-   const DiLoc* a = va;
-   const DiLoc* b = vb;
-   if (a->addr < b->addr) return -1;
-   if (a->addr > b->addr) return  1;
-   return 0;
-}
-
 static void canonicaliseLoctab ( struct _DebugInfo* di )
 {
    Word i, j;
 
-#  define SWAP(ty,aa,bb) \
-      do { ty tt = (aa); (aa) = (bb); (bb) = tt; } while (0);
-
    if (di->loctab_used == 0)
       return;
 
-   /* Sort by start address. */
-   VG_(ssort)(di->loctab, di->loctab_used, 
-                          sizeof(*di->loctab), compare_DiLoc);
+   /* sort loctab and loctab_fndn_ix by addr. */
+   sort_loctab_and_loctab_fndn_ix (di);
 
    /* If two adjacent entries overlap, truncate the first. */
    for (i = 0; i < ((Word)di->loctab_used)-1; i++) {
@@ -1794,8 +1918,10 @@
    j = 0;
    for (i = 0; i < (Word)di->loctab_used; i++) {
       if (di->loctab[i].size > 0) {
-         if (j != i)
+         if (j != i) {
             di->loctab[j] = di->loctab[i];
+            set_fndn_ix(di, j, ML_(fndn_ix)(di, i));
+         }
          j++;
       }
    }
@@ -1803,11 +1929,15 @@
 
    /* Ensure relevant postconditions hold. */
    for (i = 0; i < ((Word)di->loctab_used)-1; i++) {
-      /* 
-      VG_(printf)("%d   (%d) %d 0x%x\n", 
-                   i, di->loctab[i+1].confident, 
-                   di->loctab[i+1].size, di->loctab[i+1].addr );
-      */
+      if (0)
+         VG_(printf)("%lu  0x%p  lno:%d sz:%d fndn_ix:%d  i+1 0x%p\n", 
+                     i,
+                     (void*)di->loctab[i].addr,
+                     di->loctab[i].lineno, 
+                     di->loctab[i].size,
+                     ML_(fndn_ix)(di, i),
+                     (void*)di->loctab[i+1].addr);
+      
       /* No zero-sized symbols. */
       vg_assert(di->loctab[i].size > 0);
       /* In order. */
@@ -1816,7 +1946,6 @@
       vg_assert(di->loctab[i].addr + di->loctab[i].size - 1
                 < di->loctab[i+1].addr);
    }
-#  undef SWAP
 
    /* Free up unused space at the end of the table. */
    shrinkLocTab(di);
@@ -2024,16 +2153,16 @@
    sz_cfsi_m_pool = VG_(sizeDedupPA)(di->cfsi_m_pool);
    vg_assert (sz_cfsi_m_pool > 0);
    if (sz_cfsi_m_pool <= 255)
-      di->sizeof_ix = 1;
+      di->sizeof_cfsi_m_ix = 1;
    else if (sz_cfsi_m_pool <= 65535)
-      di->sizeof_ix = 2;
+      di->sizeof_cfsi_m_ix = 2;
    else
-      di->sizeof_ix = 4;
+      di->sizeof_cfsi_m_ix = 4;
 
    di->cfsi_base = ML_(dinfo_zalloc)( "di.storage.finCfSI.1",
                                        new_used * sizeof(Addr) );
    di->cfsi_m_ix = ML_(dinfo_zalloc)( "di.storage.finCfSI.2",
-                                      new_used * sizeof(UChar)*di->sizeof_ix);
+                                      new_used * sizeof(UChar)*di->sizeof_cfsi_m_ix);
 
    pos = 0;
    f_mergeables = 0;
@@ -2055,7 +2184,7 @@
          if (sep > 1) {
             f_holes++;
             di->cfsi_base[pos] = prev_max + 1;
-            switch (di->sizeof_ix) {
+            switch (di->sizeof_cfsi_m_ix) {
                case 1: ((UChar*) di->cfsi_m_ix)[pos] = 0; break;
                case 2: ((UShort*)di->cfsi_m_ix)[pos] = 0; break;
                case 4: ((UInt*)  di->cfsi_m_ix)[pos] = 0; break;
@@ -2067,7 +2196,7 @@
 
       // Insert the cfsi entry i.
       di->cfsi_base[pos] = di->cfsi_rd[i].base;
-      switch (di->sizeof_ix) {
+      switch (di->sizeof_cfsi_m_ix) {
          case 1: ((UChar*) di->cfsi_m_ix)[pos] = di->cfsi_rd[i].cfsi_m_ix; break;
          case 2: ((UShort*)di->cfsi_m_ix)[pos] = di->cfsi_rd[i].cfsi_m_ix; break;
          case 4: ((UInt*)  di->cfsi_m_ix)[pos] = di->cfsi_rd[i].cfsi_m_ix; break;
@@ -2097,10 +2226,11 @@
    ML_(canonicaliseCFI) ( di );
    if (di->cfsi_m_pool)
       VG_(freezeDedupPA) (di->cfsi_m_pool, ML_(dinfo_shrink_block));
-   /// TBD prepare cfsi_base and cfsi_m_ix
    canonicaliseVarInfo ( di );
    if (di->strpool)
       VG_(freezeDedupPA) (di->strpool, ML_(dinfo_shrink_block));
+   if (di->fndnpool)
+      VG_(freezeDedupPA) (di->fndnpool, ML_(dinfo_shrink_block));
 }