Following my post on valgrind-users (subject "Dynamically loaded objects --
symbols dissapearing"):

I've created a basic alfa version of my patch (attached). It does not yet
support storing deltas of different symtab versions. Instead, it copies
a SegInfo struct every time discard_syms_in_range() is called. That leads 
to sometimes insane memory usage, unfortunately. When I ran it with some
custom freeradius modules of mine, it created about 220 versions of symtabs
which ate around 400MB of memory.

I'm planning to extend it further so that somehow magically only changes in 
SegInfos are stored.

The option can be enabled at runtime with --version-symtabs=yes command line 
argument.

I've assumed that a single valgrind (or should I say memcheck?) process is
single threaded, is that correct? In particular, I make use of globals (which
I saw were used previously), so any threading within the valgrind process
would break it totally.

You can also see that I extended the struct _ExeContext with one word that's
meant to store the version number. Are these extra 4 bytes acceptable in this
struct? I know there is plenty of them being allocated. If you think we should
try to minimize it, I could think of doing it somehow dynamically, maybe just
after this variable-length array that's at the end of it (depending on the
value of VG_(clo_version_symtabs)). This way, if someone doesn't want
versioned symtabs, we would not need those extra 4 bytes with every struct
_ExeContext. Tell me what you think about it.

This is not by any means a complete patch, I'm planning on removing repeated
code, adding more comments and hopefully making up a way to store deltas of
versions of symtabs. Don't apply this yet (but you probably wouldn't anyway).

Can I please get write access to SVN so that I can create a branch for my
development? I'm not sure if that's possible to do with SVN, but if you could
just give me access to one branch (not trunk that is), this would definitely 
suffice. 

Thanks
-- 
Robert Goliasz
Claranet Ltd.
Index: include/pub_tool_stacktrace.h
===================================================================
--- include/pub_tool_stacktrace.h       (revision 6955)
+++ include/pub_tool_stacktrace.h       (working copy)
@@ -49,6 +49,10 @@
 // Print a StackTrace.
 extern void VG_(pp_StackTrace) ( StackTrace ips, UInt n_ips );
 
+// Print a StackTrace at certain symbol version.
+extern void VG_(pp_StackTrace_with_symtab_ver) ( StackTrace ips, 
+               UInt n_ips, Word ver );
+
 // Gets and immediately prints a StackTrace.  Just a bit simpler than
 // calling VG_(get_StackTrace)() then VG_(pp_StackTrace)().
 extern void VG_(get_and_pp_StackTrace) ( ThreadId tid, UInt n_ips );
Index: include/pub_tool_xarray.h
===================================================================
--- include/pub_tool_xarray.h   (revision 6955)
+++ include/pub_tool_xarray.h   (working copy)
@@ -53,6 +53,8 @@
                             void(*free_fn)(void*),
                             Word elemSzB );
 
+extern XArray* VG_(copyXA)(XArray* what);
+
 /* Free all memory associated with an XArray. */
 extern void VG_(deleteXA) ( XArray* );
 
Index: coregrind/m_execontext.c
===================================================================
--- coregrind/m_execontext.c    (revision 6955)
+++ coregrind/m_execontext.c    (working copy)
@@ -36,6 +36,7 @@
 #include "pub_core_mallocfree.h"
 #include "pub_core_options.h"
 #include "pub_core_stacktrace.h"
+#include "pub_core_debuginfo.h"
 
 /*------------------------------------------------------------*/
 /*--- Low-level ExeContext storage.                        ---*/
@@ -73,10 +74,16 @@
 struct _ExeContext {
    struct _ExeContext* chain;
    UInt   n_ips;
+
+   /* Version number of the symbol table used */
+   Word symtab_ver;
+
    /* Variable-length array.  The size is 'n_ips'; at
       least 1, at most VG_DEEPEST_BACKTRACE.  [0] is the current IP,
       [1] is its caller, [2] is the caller of [1], etc. */
    Addr ips[0];
+
+   /* don't add elements here. it will break stuff. */
 };
 
 
@@ -157,7 +164,7 @@
 /* Print an ExeContext. */
 void VG_(pp_ExeContext) ( ExeContext* ec )
 {
-   VG_(pp_StackTrace)( ec->ips, ec->n_ips );
+   VG_(pp_StackTrace_with_symtab_ver)( ec->ips, ec->n_ips, ec->symtab_ver );
 }
 
 
@@ -365,6 +372,7 @@
 
    new_ec->n_ips = n_ips;
    new_ec->chain = ec_htab[hash];
+   new_ec->symtab_ver = segInfo_curr_ver;
    ec_htab[hash] = new_ec;
 
    /* Resize the hash table, maybe? */
Index: coregrind/m_debuginfo/debuginfo.c
===================================================================
--- coregrind/m_debuginfo/debuginfo.c   (revision 6955)
+++ coregrind/m_debuginfo/debuginfo.c   (working copy)
@@ -101,9 +101,81 @@
    address ranges, and as a result the SegInfos in this list describe
    disjoint address ranges.
 */
-static SegInfo* segInfo_list = NULL;
 
+static Bool segInfo_lists_initialised = False;
+static XArray* /* of SegInfo* lists */ segInfo_lists = NULL;
+Word segInfo_curr_ver = 0;
 
+/* Initialises the segInfo version table and creates a first segInfo_list
+   on it. */
+static
+void init_segInfo_lists(void)
+{
+   void *dummyp = NULL;
+
+   if(segInfo_lists_initialised == True)
+      return;
+
+   segInfo_lists = VG_(newXA)( VG_(malloc), VG_(free), sizeof(SegInfo*) );
+
+   // should always add in the first element of the array
+   vg_assert(0 == VG_(addToXA)(segInfo_lists, &dummyp));
+   segInfo_curr_ver = 0; // just to double-check
+
+   segInfo_lists_initialised = True;
+}
+
+static
+SegInfo** get_segInfo_list(Word which)
+{
+   return (SegInfo**)VG_(indexXA)(segInfo_lists, which);
+}
+
+static
+SegInfo** get_curr_segInfo_list(void)
+{
+   // temporary FIXME:
+   init_segInfo_lists();
+
+   return get_segInfo_list(segInfo_curr_ver);
+}
+
+static 
+SegInfo* copy_SegInfo(const SegInfo* what);
+
+static
+void create_newver_segInfo_list(void)
+{
+   // TODO FIXME: copy the struct for now
+   SegInfo** curSI;
+   SegInfo** newp;
+
+   curSI = get_curr_segInfo_list();
+
+   // FIXME: allocing and never freeing
+   newp = VG_(malloc)(sizeof(SegInfo*));
+   *newp = NULL;
+
+   // FIXME: this also doesn't get freed
+   if(*curSI)
+   {
+      SegInfo *iter;
+
+      for(iter = *curSI; iter != NULL; iter = iter->next)
+      {
+         SegInfo *swap_tmp = *newp;
+         *newp = copy_SegInfo(iter);
+         (*newp)->next = swap_tmp;
+      }
+   }
+   else
+      *newp = NULL;
+
+   segInfo_curr_ver = VG_(addToXA)(segInfo_lists, newp);
+
+   VG_(message)(Vg_DebugMsg, "Created symtab ver %d", segInfo_curr_ver);
+}
+
 /*------------------------------------------------------------*/
 /*--- Notification (acquire/discard) helpers               ---*/
 /*------------------------------------------------------------*/
@@ -145,7 +217,104 @@
    return si;
 }
 
+static 
+SegInfo* copy_SegInfo(const SegInfo* what)
+{
+   SegInfo *ret;
+   struct strchunk *tmp, *newch;
 
+   vg_assert(what);
+   vg_assert(what->filename);
+
+   ret = alloc_SegInfo(what->text_start_avma,
+         what->text_size,
+         what->foffset,
+         what->filename,
+         what->memname);
+
+   ret->soname = what->soname;
+
+   if(what->symtab != NULL)
+   {
+      ret->symtab = VG_(arena_malloc)(VG_AR_SYMTAB, what->symtab_size * 
+            sizeof(DiSym));
+      VG_(memcpy)(ret->symtab, what->symtab, what->symtab_used * 
sizeof(DiSym));
+   }
+   else
+      ret->symtab = NULL;
+
+   ret->symtab_used = what->symtab_used;
+   ret->symtab_size = what->symtab_size;
+
+   if(what->loctab != NULL)
+   {
+      ret->loctab = VG_(arena_malloc)(VG_AR_SYMTAB, what->loctab_size *
+            sizeof(DiLoc));
+      VG_(memcpy)(ret->loctab, what->loctab, what->loctab_used * 
sizeof(DiLoc));
+   }
+   else
+      ret->loctab = NULL;
+   ret->loctab_used = what->loctab_used;
+   ret->loctab_size = what->loctab_size;
+
+   if(what->cfsi != NULL)
+   {
+      ret->cfsi = VG_(arena_malloc)(VG_AR_SYMTAB, what->cfsi_size * 
+            sizeof(DiCfSI));
+      VG_(memcpy)(ret->cfsi, what->cfsi, what->cfsi_used * sizeof(DiCfSI));
+   }
+   else
+      ret->cfsi = NULL;
+   ret->cfsi_used = what->cfsi_used;
+   ret->cfsi_size = what->cfsi_size;
+   ret->cfsi_minaddr = what->cfsi_minaddr;
+   ret->cfsi_maxaddr = what->cfsi_maxaddr;
+
+   if(what->cfsi_exprs)
+      ret->cfsi_exprs = VG_(copyXA)(what->cfsi_exprs);
+   else
+      ret->cfsi_exprs = NULL;
+
+   // chunks
+   for(tmp = what->strchunks; tmp != NULL; tmp = tmp->next)
+   {
+      newch = VG_(arena_malloc)(VG_AR_SYMTAB, sizeof(struct strchunk));
+      
+      newch->strtab_used = tmp->strtab_used;
+      newch->next = ret->strchunks;
+      VG_(memcpy)(newch->strtab, tmp->strtab, tmp->strtab_used);
+
+      ret->strchunks = newch;
+   }
+   
+   ret->text_bias = what->text_bias;
+
+   ret->plt_start_avma = what->plt_start_avma;
+   ret->plt_size = what->plt_size;
+   ret->got_start_avma = what->got_start_avma;
+   ret->got_size = what->got_size;
+   ret->opd_start_avma = what->opd_start_avma;
+   ret->opd_size = what->opd_size;
+   ret->data_start_avma = what->data_start_avma;
+   ret->data_size = what->data_size;
+   ret->bss_start_avma = what->bss_start_avma;
+   ret->bss_size = what->bss_size;
+
+   ret->trace_symtab = what->trace_symtab;
+   ret->trace_cfi = what->trace_cfi;
+   ret->ddump_syms = what->ddump_syms;
+   ret->ddump_line = what->ddump_line;
+   ret->ddump_frames = what->ddump_frames;
+
+   // TODO: is this correct?
+   // notify redir the old one will be probably not in use
+   VG_(redir_notify_delete_SegInfo)(what);
+   // now, notify redir we've created a new one
+   VG_(redir_notify_new_SegInfo)(ret);
+
+   return ret;
+}
+
 /* Free a SegInfo, and also all the stuff hanging off it. */
 static void free_SegInfo ( SegInfo* si )
 {
@@ -179,8 +348,8 @@
    HChar* reason = "munmap";
 #  endif
 
-   SegInfo** prev_next_ptr = &segInfo_list;
-   SegInfo*  curr          =  segInfo_list;
+   SegInfo** prev_next_ptr =  get_curr_segInfo_list();
+   SegInfo*  curr          = *get_curr_segInfo_list();
 
    while (curr) {
       if (curr == si) {
@@ -215,10 +384,12 @@
    Bool found;
    SegInfo* curr;
 
+   create_newver_segInfo_list();
+
    while (True) {
       found = False;
 
-      curr = segInfo_list;
+      curr = *get_curr_segInfo_list();
       while (True) {
          if (curr == NULL)
             break;
@@ -263,6 +434,9 @@
 #    error Unknown OS
 #  endif
 
+   // FIXME: should be initialised in a better place
+   init_segInfo_lists();
+
    if (!ok) {
       // Something went wrong (eg. bad ELF file).
       free_SegInfo( si );
@@ -270,8 +444,8 @@
 
    } else {
       // Prepend si to segInfo_list
-      si->next = segInfo_list;
-      segInfo_list = si;
+      si->next = *get_curr_segInfo_list();
+      *get_curr_segInfo_list() = si;
 
       ML_(canonicaliseTables) ( si );
 
@@ -451,7 +625,7 @@
       /* Dump all the segInfos whose text segments intersect
          code_start/code_len. */
       while (True) {
-         for (si = segInfo_list; si; si = si->next) {
+         for (si = *get_curr_segInfo_list(); si; si = si->next) {
             if (code_start + code_len <= si->text_start_avma
                 || si->text_start_avma + si->text_size <= code_start)
                continue; /* no overlap */
@@ -492,7 +666,7 @@
    Int      sno;
    SegInfo* si;
 
-   for (si = segInfo_list; si != NULL; si = si->next) {
+   for (si = *get_curr_segInfo_list(); si != NULL; si = si->next) {
       if (si->text_start_avma <= ptr 
           && ptr < si->text_start_avma + si->text_size) {
          sno = ML_(search_one_symtab) ( si, ptr, match_anywhere_in_fun );
@@ -517,7 +691,7 @@
    Int      lno;
    SegInfo* si;
 
-   for (si = segInfo_list; si != NULL; si = si->next) {
+   for (si = *get_curr_segInfo_list(); si != NULL; si = si->next) {
       if (si->text_start_avma <= ptr 
           && ptr < si->text_start_avma + si->text_size) {
          lno = ML_(search_one_loctab) ( si, ptr );
@@ -661,7 +835,7 @@
    SegInfo* si;
 
    vg_assert(nbuf > 0);
-   for (si = segInfo_list; si != NULL; si = si->next) {
+   for (si = *get_curr_segInfo_list(); si != NULL; si = si->next) {
       if (si->text_start_avma <= a 
           && a < si->text_start_avma + si->text_size) {
          VG_(strncpy_safely)(buf, si->filename, nbuf);
@@ -689,7 +863,7 @@
 {
    SegInfo* si;
 
-   for (si = segInfo_list; si != NULL; si = si->next) {
+   for (si = *get_curr_segInfo_list(); si != NULL; si = si->next) {
       if (si->text_start_avma <= a 
           && a < si->text_start_avma + si->text_size) {
          return si;
@@ -786,7 +960,7 @@
 #  if defined(VG_PLAT_USES_PPCTOC)
    require_pToc = True;
 #  endif
-   for (si = segInfo_list; si; si = si->next) {
+   for (si = *get_curr_segInfo_list(); si; si = si->next) {
       if (debug)
          VG_(printf)("lookup_symbol_SLOW: considering %s\n", si->soname);
       if (!VG_(string_match)(sopatt, si->soname)) {
@@ -978,7 +1152,125 @@
 #  undef BUF_LEN
 }
 
+Char* VG_(describe_IP_with_symtab_ver)(Addr eip, Char* buf, Int n_buf, Word 
ver)
+{
+#  define APPEND(_str) \
+      n = putStr(n, n_buf, buf, _str)
+#  define APPEND_ESC(_count,_str) \
+      n = putStrEsc(n, n_buf, (_count), buf, (_str))
+#  define BUF_LEN    4096
 
+   UInt  lineno; 
+   UChar ibuf[50];
+   Int   n = 0;
+   static UChar buf_fn[BUF_LEN];
+   static UChar buf_obj[BUF_LEN];
+   static UChar buf_srcloc[BUF_LEN];
+   static UChar buf_dirname[BUF_LEN];
+   Bool  know_dirinfo = False;
+   Bool  know_fnname;
+   Bool  know_objname;
+   Bool  know_srcloc;
+   Word curr_ver;
+
+   curr_ver = segInfo_curr_ver;
+   segInfo_curr_ver = ver;
+   know_fnname = VG_(clo_sym_offsets)
+                        ? VG_(get_fnname_w_offset) (eip, buf_fn, BUF_LEN)
+                        : VG_(get_fnname) (eip, buf_fn, BUF_LEN);
+   know_objname = VG_(get_objname)(eip, buf_obj, BUF_LEN);
+   know_srcloc = VG_(get_filename_linenum)(
+                           eip, 
+                           buf_srcloc,  BUF_LEN, 
+                           buf_dirname, BUF_LEN, &know_dirinfo,
+                           &lineno 
+                        );
+   segInfo_curr_ver = curr_ver;
+
+   if (VG_(clo_xml)) {
+
+      Bool   human_readable = True;
+      HChar* maybe_newline  = human_readable ? "\n      " : "";
+      HChar* maybe_newline2 = human_readable ? "\n    "   : "";
+
+      /* Print in XML format, dumping in as much info as we know.
+         Ensure all tags are balanced even if the individual strings
+         are too long.  Allocate 1/10 of BUF_LEN to the object name,
+         6/10s to the function name, 1/10 to the directory name and
+         1/10 to the file name, leaving 1/10 for all the fixed-length
+         stuff. */
+      APPEND("<frame>");
+      VG_(sprintf)(ibuf,"<ip>0x%llX</ip>", (ULong)eip);
+      APPEND(maybe_newline);
+      APPEND(ibuf);
+      if (know_objname) {
+         APPEND(maybe_newline);
+         APPEND("<obj>");
+         APPEND_ESC(1*BUF_LEN/10, buf_obj);
+         APPEND("</obj>");
+      }
+      if (know_fnname) {
+         APPEND(maybe_newline);
+         APPEND("<fn>");
+         APPEND_ESC(6*BUF_LEN/10, buf_fn);
+         APPEND("</fn>");
+      }
+      if (know_srcloc) {
+         if (know_dirinfo) {
+            APPEND(maybe_newline);
+            APPEND("<dir>");
+            APPEND_ESC(1*BUF_LEN/10, buf_dirname);
+            APPEND("</dir>");
+         }
+         APPEND(maybe_newline);
+         APPEND("<file>");
+         APPEND_ESC(1*BUF_LEN/10, buf_srcloc);
+         APPEND("</file>");
+         APPEND(maybe_newline);
+         APPEND("<line>");
+         VG_(sprintf)(ibuf,"%d",lineno);
+         APPEND(ibuf);
+         APPEND("</line>");
+      }
+      APPEND(maybe_newline2);
+      APPEND("</frame>");
+
+   } else {
+
+      /* Print for humans to read */
+      VG_(sprintf)(ibuf,"0x%llX: ", (ULong)eip);
+      APPEND(ibuf);
+      if (know_fnname) { 
+         APPEND(buf_fn);
+         if (!know_srcloc && know_objname) {
+            APPEND(" (in ");
+            APPEND(buf_obj);
+            APPEND(")");
+         }
+      } else if (know_objname && !know_srcloc) {
+         APPEND("(within ");
+         APPEND(buf_obj);
+         APPEND(")");
+      } else {
+         APPEND("???");
+      }
+      if (know_srcloc) {
+         APPEND(" (");
+         APPEND(buf_srcloc);
+         APPEND(":");
+         VG_(sprintf)(ibuf,"%d",lineno);
+         APPEND(ibuf);
+         APPEND(")");
+      }
+
+   }
+   return buf;
+
+#  undef APPEND
+#  undef APPEND_ESC
+#  undef BUF_LEN
+}
+
 /*------------------------------------------------------------*/
 /*--- For unwinding the stack using                       --- */
 /*--- pre-summarised DWARF3 .eh_frame info                 ---*/
@@ -1080,7 +1372,7 @@
 
    if (0) VG_(printf)("search for %p\n", *ipP);
 
-   for (si = segInfo_list; si != NULL; si = si->next) {
+   for (si = *get_curr_segInfo_list(); si != NULL; si = si->next) {
       n_steps++;
 
       /* Use the per-SegInfo summary address ranges to skip
@@ -1112,7 +1404,7 @@
       find-the-right-SegInfo loop by more than a factor of 20. */
    if ((n_search & 0xF) == 0) {
       /* Move si one step closer to the start of the list. */
-      SegInfo* si0 = segInfo_list;
+      SegInfo* si0 = *get_curr_segInfo_list();
       SegInfo* si1 = NULL;
       SegInfo* si2 = NULL;
       SegInfo* tmp;
@@ -1232,7 +1524,7 @@
 const SegInfo* VG_(next_seginfo)(const SegInfo* si)
 {
    if (si == NULL)
-      return segInfo_list;
+      return *get_curr_segInfo_list();
    return si->next;
 }
 
@@ -1266,7 +1558,7 @@
    SegInfo* si;
    VgSectKind ret = Vg_SectUnknown;
 
-   for(si = segInfo_list; si != NULL; si = si->next) {
+   for(si = *get_curr_segInfo_list(); si != NULL; si = si->next) {
       if (a >= si->text_start_avma 
           && a < si->text_start_avma + si->text_size) {
 
Index: coregrind/pub_core_debuginfo.h
===================================================================
--- coregrind/pub_core_debuginfo.h      (revision 6955)
+++ coregrind/pub_core_debuginfo.h      (working copy)
@@ -103,6 +103,8 @@
 extern
 Bool VG_(lookup_symbol_SLOW)(UChar* sopatt, UChar* name, Addr* pEnt, Addr* 
pToc);
 
+extern Word segInfo_curr_ver;
+
 #endif   // __PUB_CORE_DEBUGINFO_H
 
 /*--------------------------------------------------------------------*/
Index: coregrind/m_stacktrace.c
===================================================================
--- coregrind/m_stacktrace.c    (revision 6955)
+++ coregrind/m_stacktrace.c    (working copy)
@@ -428,6 +428,21 @@
    }
 }
 
+static void printIpDesc_with_symtab_ver(UInt n, Addr ip, Word ver)
+{
+   #define BUF_LEN   4096
+   
+   static UChar buf[BUF_LEN];
+
+   VG_(describe_IP_with_symtab_ver)(ip, buf, BUF_LEN, ver);
+
+   if (VG_(clo_xml)) {
+      VG_(message)(Vg_UserMsg, "    %s", buf);
+   } else {
+      VG_(message)(Vg_UserMsg, "   %s %s", ( n == 0 ? "at" : "by" ), buf);
+   }
+}
+
 /* Print a StackTrace. */
 void VG_(pp_StackTrace) ( StackTrace ips, UInt n_ips )
 {
@@ -442,6 +457,21 @@
       VG_(message)(Vg_UserMsg, "  </stack>");
 }
 
+/* Print a StackTrace at certain symtab version. */
+void VG_(pp_StackTrace_with_symtab_ver) ( StackTrace ips, UInt n_ips, Word ver 
)
+{
+   vg_assert( n_ips > 0 );
+
+   if (VG_(clo_xml))
+      VG_(message)(Vg_UserMsg, "  <stack>");
+
+   VG_(apply_StackTrace_with_symtab_ver)( printIpDesc_with_symtab_ver, 
+         ips, n_ips, ver );
+
+   if (VG_(clo_xml))
+      VG_(message)(Vg_UserMsg, "  </stack>");
+}
+
 /* Get and immediately print a StackTrace. */
 void VG_(get_and_pp_StackTrace) ( ThreadId tid, UInt n_ips )
 {
@@ -491,7 +521,48 @@
    #undef MYBUF_LEN
 }
 
+void VG_(apply_StackTrace_with_symtab_ver)( void(*action)(UInt n, Addr ip, 
+                                            Word ver),
+                            StackTrace ips, UInt n_ips, Word ver )
+{
+   #define MYBUF_LEN 50  // only needs to be long enough for 
+                         // the names specially tested for
 
+   Bool main_done = False;
+   Char mybuf[MYBUF_LEN];     // ok to stack allocate mybuf[] -- it's tiny
+   Int i = 0;
+
+   vg_assert(n_ips > 0);
+   do {
+      Addr ip = ips[i];
+      if (i > 0) 
+         ip -= VG_MIN_INSTR_SZB;   // point to calling line
+
+      // Stop after the first appearance of "main" or one of the other names
+      // (the appearance of which is a pretty good sign that we've gone past
+      // main without seeing it, for whatever reason)
+      if ( ! VG_(clo_show_below_main)) {
+         VG_(get_fnname_nodemangle)( ip, mybuf, MYBUF_LEN );
+         mybuf[MYBUF_LEN-1] = 0; // paranoia
+         if ( VG_STREQ("main", mybuf)
+#             if defined(VGO_linux)
+              || VG_STREQ("__libc_start_main", mybuf)   // glibc glibness
+              || VG_STREQ("generic_start_main", mybuf)  // Yellow Dog 
doggedness
+#             endif
+            )
+            main_done = True;
+      }
+
+      // Act on the ip
+      action(i, ip, ver);
+
+      i++;
+   } while (i < n_ips && ips[i] != 0 && !main_done);
+
+   #undef MYBUF_LEN
+}
+
+
 /*--------------------------------------------------------------------*/
 /*--- end                                                          ---*/
 /*--------------------------------------------------------------------*/
Index: coregrind/m_main.c
===================================================================
--- coregrind/m_main.c  (revision 6955)
+++ coregrind/m_main.c  (working copy)
@@ -148,6 +148,7 @@
 "    --input-fd=<number>       file descriptor for input [0=stdin]\n"
 "    --max-stackframe=<number> assume stack switch for SP changes larger\n"
 "                              than <number> bytes [2000000]\n"
+"    --version-symtabs=yes|no  keep old versions of symbol table? [no]\n"
 "\n";
 
    Char* usage2 = 
@@ -402,6 +403,8 @@
 
       else VG_STR_CLO (arg, "--kernel-variant",   VG_(clo_kernel_variant))
 
+      else VG_BOOL_CLO(arg, "--version-symtabs",  VG_(clo_version_symtabs))
+
       else VG_BNUM_CLO(arg, "--vex-iropt-verbosity",
                        VG_(clo_vex_control).iropt_verbosity, 0, 10)
       else VG_BNUM_CLO(arg, "--vex-iropt-level",
Index: coregrind/m_options.c
===================================================================
--- coregrind/m_options.c       (revision 6955)
+++ coregrind/m_options.c       (working copy)
@@ -83,6 +83,7 @@
 Bool   VG_(clo_wait_for_gdb)   = False;
 VgSmc  VG_(clo_smc_check)      = Vg_SmcStack;
 HChar* VG_(clo_kernel_variant) = NULL;
+Bool   VG_(clo_version_symtabs) = False;
 
 
 /*====================================================================*/
Index: coregrind/pub_core_options.h
===================================================================
--- coregrind/pub_core_options.h        (revision 6955)
+++ coregrind/pub_core_options.h        (working copy)
@@ -181,6 +181,11 @@
    so they can be properly handled by m_syswrap. */
 extern HChar* VG_(clo_kernel_variant);
 
+/* Should we keep old versions of symbol table after dlclose()?
+   If we do, it will be possible to look up unloaded symbols later in 
+   stack traces. */
+extern Bool VG_(clo_version_symtabs);
+
 /* --------- Functions --------- */
 
 /* Call this if the executable is missing.  This function prints an
Index: coregrind/m_xarray.c
===================================================================
--- coregrind/m_xarray.c        (revision 6955)
+++ coregrind/m_xarray.c        (working copy)
@@ -48,7 +48,27 @@
    Bool  sorted;    /* is it sorted? */
 };
 
+XArray* VG_(copyXA)(XArray* what_)
+{
+   struct _XArray *ret, *what = (struct _XArray*)what_;
 
+   vg_assert(what);
+
+   ret = VG_(newXA)(what->alloc, what->free, what->elemSzB);
+
+   ret->cmpFn = what->cmpFn;
+   ret->arr = what->alloc(what->totsizeE * what->elemSzB);
+   vg_assert(ret->arr);
+   VG_(memcpy)(ret->arr, what->arr, what->usedsizeE * what->elemSzB);
+
+   ret->usedsizeE = what->usedsizeE;
+   ret->totsizeE = what->totsizeE;
+   ret->sorted = what->sorted;
+
+   return ret;
+}
+
+
 XArray* VG_(newXA) ( void*(*alloc_fn)(SizeT), 
                      void(*free_fn)(void*),
                      Word elemSzB )
-------------------------------------------------------------------------
This SF.net email is sponsored by: Splunk Inc.
Still grepping through log files to find problems?  Stop.
Now Search log events and configuration files using AJAX and a browser.
Download your FREE copy of Splunk now >> http://get.splunk.com/
_______________________________________________
Valgrind-developers mailing list
[email protected]
https://lists.sourceforge.net/lists/listinfo/valgrind-developers

Reply via email to