A modularisation + refactoring commit.  vg_execontext.c has been split into
two halves: stacktrace.c, which deals with getting, traversing and printing
stack traces;  and execontext.c, which deals with storing stack traces
permanently in a way that avoids duplicates, and comparing them.

One nice outcome:  previously we were often creating ExeContexts, which live
forever, even when they were only needed temporarily.  Ie. this was a memory
leak, which has been removed.

As part of this, new headers have been created, carved off core.h and
tool.h.  Lots of function names have changed, too.

In Massif, I also changed a lot of "eip" names to "ip" to make them less
x86-specific.


git-svn-id: svn://svn.valgrind.org/valgrind/trunk@3429 a5019735-40e9-0310-863c-91ae7b9d1cf9
diff --git a/coregrind/Makefile.am b/coregrind/Makefile.am
index be3d5da..df822ac 100644
--- a/coregrind/Makefile.am
+++ b/coregrind/Makefile.am
@@ -27,6 +27,8 @@
 noinst_HEADERS = \
 	core.h			\
 	core_asm.h		\
+	pub_core_execontext.h	\
+	pub_core_stacktrace.h	\
 	ume.h			\
 	vg_symtab2.h		\
 	vg_symtypes.h		\
@@ -50,13 +52,14 @@
 valgrind_LDADD=
 
 stage2_SOURCES = \
+	execontext.c \
+	stacktrace.c \
 	ume.c \
 	\
 	vg_scheduler.c \
 	vg_default.c \
 	vg_demangle.c \
 	vg_errcontext.c \
-	vg_execontext.c \
 	vg_hashtable.c \
 	vg_instrument.c \
 	vg_main.c \
diff --git a/coregrind/core.h b/coregrind/core.h
index 25be871..481d4f7 100644
--- a/coregrind/core.h
+++ b/coregrind/core.h
@@ -93,6 +93,8 @@
                            //   eg. x86-linux/core_platform.h
 #include "core_os.h"       // OS-specific stuff,    eg. linux/core_os.h
 
+#include "pub_core_stacktrace.h"  // for type 'StackTrace'
+
 #include "valgrind.h"
 
 #undef TL_
@@ -809,7 +811,7 @@
 __attribute__ ((__noreturn__))
 extern void  VG_(core_panic)      ( Char* str );
 __attribute__ ((__noreturn__))
-extern void  VG_(core_panic_at)   ( Char* str, ExeContext *ec );
+extern void  VG_(core_panic_at)   ( Char* str, StackTrace ips );
 
 /* Tools use VG_(strdup)() which doesn't expose ArenaId */
 extern Char* VG_(arena_strdup) ( ArenaId aid, const Char* s);
@@ -867,31 +869,6 @@
                       Int      debugging_verbosity );
 
 /* ---------------------------------------------------------------------
-   Exports of vg_execontext.c.
-   ------------------------------------------------------------------ */
-
-/* Records the PC and a bit of the call chain.  The first 4 IP
-   values are used in comparisons do remove duplicate errors, and for
-   comparing against suppression specifications.  The rest are purely
-   informational (but often important). */
-
-struct _ExeContext {
-   struct _ExeContext * next;
-   /* Variable-length array.  The size is VG_(clo_backtrace_size); 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];
-};
-
-
-/* Print stats (informational only). */
-extern void VG_(print_ExeContext_stats) ( void );
-
-/* Like VG_(get_ExeContext), but with a slightly different type */
-extern ExeContext* VG_(get_ExeContext2) ( Addr ip, Addr fp,
-                                          Addr fp_min, Addr fp_max );
-
-/* ---------------------------------------------------------------------
    Exports of vg_errcontext.c.
    ------------------------------------------------------------------ */
 
diff --git a/coregrind/execontext.c b/coregrind/execontext.c
new file mode 100644
index 0000000..5de1dbe
--- /dev/null
+++ b/coregrind/execontext.c
@@ -0,0 +1,256 @@
+/*--------------------------------------------------------------------*/
+/*---                                                 execontext.c ---*/
+/*--------------------------------------------------------------------*/
+
+/*
+   This file is part of Valgrind, a dynamic binary instrumentation
+   framework.
+
+   Copyright (C) 2000-2005 Julian Seward 
+      jseward@acm.org
+
+   This program is free software; you can redistribute it and/or
+   modify it under the terms of the GNU General Public License as
+   published by the Free Software Foundation; either version 2 of the
+   License, or (at your option) any later version.
+
+   This program is distributed in the hope that it will be useful, but
+   WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+   General Public License for more details.
+
+   You should have received a copy of the GNU General Public License
+   along with this program; if not, write to the Free Software
+   Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+   02111-1307, USA.
+
+   The GNU General Public License is contained in the file COPYING.
+*/
+
+#include "core.h"
+#include "pub_core_execontext.h"
+
+/*------------------------------------------------------------*/
+/*--- Low-level ExeContext storage.                        ---*/
+/*------------------------------------------------------------*/
+
+/* The first 4 IP values are used in comparisons do remove duplicate errors,
+   and for comparing against suppression specifications.  The rest are
+   purely informational (but often important). */
+
+struct _ExeContext {
+   struct _ExeContext * next;
+   /* Variable-length array.  The size is VG_(clo_backtrace_size); 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];
+};
+
+/* Number of lists in which we keep track of ExeContexts.  Should be
+   prime. */
+#define N_EC_LISTS 4999 /* a prime number */
+
+/* The idea is only to ever store any one context once, so as to save
+   space and make exact comparisons faster. */
+
+static ExeContext* ec_list[N_EC_LISTS];
+
+/* Stats only: the number of times the system was searched to locate a
+   context. */
+static UInt ec_searchreqs;
+
+/* Stats only: the number of full context comparisons done. */
+static UInt ec_searchcmps;
+
+/* Stats only: total number of stored contexts. */
+static UInt ec_totstored;
+
+/* Number of 2, 4 and (fast) full cmps done. */
+static UInt ec_cmp2s;
+static UInt ec_cmp4s;
+static UInt ec_cmpAlls;
+
+
+/*------------------------------------------------------------*/
+/*--- Exported functions.                                  ---*/
+/*------------------------------------------------------------*/
+
+
+/* Initialise this subsystem. */
+static void init_ExeContext_storage ( void )
+{
+   Int i;
+   static Bool init_done = False;
+   if (init_done)
+      return;
+   ec_searchreqs = 0;
+   ec_searchcmps = 0;
+   ec_totstored = 0;
+   ec_cmp2s = 0;
+   ec_cmp4s = 0;
+   ec_cmpAlls = 0;
+   for (i = 0; i < N_EC_LISTS; i++)
+      ec_list[i] = NULL;
+   init_done = True;
+}
+
+
+/* Print stats. */
+void VG_(print_ExeContext_stats) ( void )
+{
+   init_ExeContext_storage();
+   VG_(message)(Vg_DebugMsg, 
+      "   exectx: %d lists, %d contexts (avg %d per list)",
+      N_EC_LISTS, ec_totstored, 
+      ec_totstored / N_EC_LISTS 
+   );
+   VG_(message)(Vg_DebugMsg, 
+      "   exectx: %d searches, %d full compares (%d per 1000)",
+      ec_searchreqs, ec_searchcmps, 
+      ec_searchreqs == 0 
+         ? 0 
+         : (UInt)( (((ULong)ec_searchcmps) * 1000) 
+           / ((ULong)ec_searchreqs )) 
+   );
+   VG_(message)(Vg_DebugMsg, 
+      "   exectx: %d cmp2, %d cmp4, %d cmpAll",
+      ec_cmp2s, ec_cmp4s, ec_cmpAlls 
+   );
+}
+
+
+/* Print an ExeContext. */
+void VG_(pp_ExeContext) ( ExeContext* ec )
+{
+   VG_(pp_StackTrace)( ec->ips, VG_(clo_backtrace_size) );
+}
+
+
+/* Compare two ExeContexts, comparing all callers. */
+Bool VG_(eq_ExeContext) ( VgRes res, ExeContext* e1, ExeContext* e2 )
+{
+   if (e1 == NULL || e2 == NULL) 
+      return False;
+   switch (res) {
+   case Vg_LowRes:
+      /* Just compare the top two callers. */
+      ec_cmp2s++;
+      if (e1->ips[0] != e2->ips[0]) return False;
+
+      if (VG_(clo_backtrace_size) < 2) return True;
+      if (e1->ips[1] != e2->ips[1]) return False;
+      return True;
+
+   case Vg_MedRes:
+      /* Just compare the top four callers. */
+      ec_cmp4s++;
+      if (e1->ips[0] != e2->ips[0]) return False;
+
+      if (VG_(clo_backtrace_size) < 2) return True;
+      if (e1->ips[1] != e2->ips[1]) return False;
+
+      if (VG_(clo_backtrace_size) < 3) return True;
+      if (e1->ips[2] != e2->ips[2]) return False;
+
+      if (VG_(clo_backtrace_size) < 4) return True;
+      if (e1->ips[3] != e2->ips[3]) return False;
+      return True;
+
+   case Vg_HighRes:
+      ec_cmpAlls++;
+      /* Compare them all -- just do pointer comparison. */
+      if (e1 != e2) return False;
+      return True;
+
+   default:
+      VG_(core_panic)("VG_(eq_ExeContext): unrecognised VgRes");
+   }
+}
+
+/* This guy is the head honcho here.  Take a snapshot of the client's
+   stack.  Search our collection of ExeContexts to see if we already
+   have it, and if not, allocate a new one.  Either way, return a
+   pointer to the context.  If there is a matching context we
+   guarantee to not allocate a new one.  Thus we never store
+   duplicates, and so exact equality can be quickly done as equality
+   on the returned ExeContext* values themselves.  Inspired by Hugs's
+   Text type.  
+*/
+ExeContext* VG_(record_ExeContext) ( ThreadId tid )
+{
+   Int         i;
+   Addr        ips[VG_DEEPEST_BACKTRACE];
+   Bool        same;
+   UWord       hash;
+   ExeContext* new_ec;
+   ExeContext* list;
+
+   VGP_PUSHCC(VgpExeContext);
+
+   init_ExeContext_storage();
+   vg_assert(VG_(clo_backtrace_size) >= 1 
+             && VG_(clo_backtrace_size) <= VG_DEEPEST_BACKTRACE);
+
+   VG_(get_StackTrace)( tid, ips, VG_(clo_backtrace_size) );
+
+   /* Now figure out if we've seen this one before.  First hash it so
+      as to determine the list number. */
+
+   hash = 0;
+   for (i = 0; i < VG_(clo_backtrace_size); i++) {
+      hash ^= ips[i];
+      hash = (hash << 29) | (hash >> 3);
+   }
+   hash = hash % N_EC_LISTS;
+
+   /* And (the expensive bit) look a matching entry in the list. */
+
+   ec_searchreqs++;
+
+   list = ec_list[hash];
+
+   while (True) {
+      if (list == NULL) break;
+      ec_searchcmps++;
+      same = True;
+      for (i = 0; i < VG_(clo_backtrace_size); i++) {
+         if (list->ips[i] != ips[i]) {
+            same = False;
+            break; 
+         }
+      }
+      if (same) break;
+      list = list->next;
+   }
+
+   if (list != NULL) {
+      /* Yay!  We found it.  */
+      VGP_POPCC(VgpExeContext);
+      return list;
+   }
+
+   /* Bummer.  We have to allocate a new context record. */
+   ec_totstored++;
+
+   new_ec = VG_(arena_malloc)( VG_AR_EXECTXT, 
+                               sizeof(struct _ExeContext *) 
+                               + VG_(clo_backtrace_size) * sizeof(Addr) );
+
+   for (i = 0; i < VG_(clo_backtrace_size); i++)
+      new_ec->ips[i] = ips[i];
+
+   new_ec->next = ec_list[hash];
+   ec_list[hash] = new_ec;
+
+   VGP_POPCC(VgpExeContext);
+   return new_ec;
+}
+
+StackTrace VG_(extract_StackTrace) ( ExeContext* e )
+{                                  
+   return e->ips;
+}  
+
+/*--------------------------------------------------------------------*/
+/*--- end                                                          ---*/
+/*--------------------------------------------------------------------*/
diff --git a/coregrind/pub_core_execontext.h b/coregrind/pub_core_execontext.h
new file mode 100644
index 0000000..119adb4
--- /dev/null
+++ b/coregrind/pub_core_execontext.h
@@ -0,0 +1,54 @@
+/*--------------------------------------------------------------------*/
+/*--- ExeContexts: long-lived, non-dup'd stack traces.             ---*/
+/*---                                        pub_core_execontext.h ---*/
+/*--------------------------------------------------------------------*/
+
+/*
+   This file is part of Valgrind, a dynamic binary instrumentation
+   framework.
+
+   Copyright (C) 2000-2005 Julian Seward
+      jseward@acm.org
+
+   This program is free software; you can redistribute it and/or
+   modify it under the terms of the GNU General Public License as
+   published by the Free Software Foundation; either version 2 of the
+   License, or (at your option) any later version.
+
+   This program is distributed in the hope that it will be useful, but
+   WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+   General Public License for more details.
+
+   You should have received a copy of the GNU General Public License
+   along with this program; if not, write to the Free Software
+   Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+   02111-1307, USA.
+
+   The GNU General Public License is contained in the file COPYING.
+*/
+
+#ifndef __PUB_CORE_EXECONTEXT_H
+#define __PUB_CORE_EXECONTEXT_H
+
+//--------------------------------------------------------------------
+// PURPOSE: This module provides an abstract data type, ExeContext,
+// which is a stack trace stored in such a way that duplicates are
+// avoided.  This also facilitates fast comparisons if necessary.
+//--------------------------------------------------------------------
+
+#include "pub_tool_execontext.h"
+
+#include "pub_core_stacktrace.h"
+
+// Print stats (informational only).
+extern void VG_(print_ExeContext_stats) ( void );
+
+// Extract the StackTrace from an ExeContext.
+extern StackTrace VG_(extract_StackTrace) ( ExeContext* e );
+
+#endif   // __PUB_CORE_EXECONTEXT_H
+
+/*--------------------------------------------------------------------*/
+/*--- end                                                          ---*/
+/*--------------------------------------------------------------------*/
diff --git a/coregrind/pub_core_stacktrace.h b/coregrind/pub_core_stacktrace.h
new file mode 100644
index 0000000..61c6e63
--- /dev/null
+++ b/coregrind/pub_core_stacktrace.h
@@ -0,0 +1,49 @@
+/*--------------------------------------------------------------------*/
+/*--- Stack traces: getting, traversing, printing.                 ---*/
+/*---                                        pub_core_stacktrace.h ---*/
+/*--------------------------------------------------------------------*/
+
+/*
+   This file is part of Valgrind, a dynamic binary instrumentation
+   framework.
+
+   Copyright (C) 2000-2005 Julian Seward
+      jseward@acm.org
+
+   This program is free software; you can redistribute it and/or
+   modify it under the terms of the GNU General Public License as
+   published by the Free Software Foundation; either version 2 of the
+   License, or (at your option) any later version.
+
+   This program is distributed in the hope that it will be useful, but
+   WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+   General Public License for more details.
+
+   You should have received a copy of the GNU General Public License
+   along with this program; if not, write to the Free Software
+   Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+   02111-1307, USA.
+
+   The GNU General Public License is contained in the file COPYING.
+*/
+
+#ifndef __PUB_CORE_STACKTRACE_H
+#define __PUB_CORE_STACKTRACE_H
+
+//--------------------------------------------------------------------
+// PURPOSE: This module deals with stack traces:  getting them, 
+// traversing them, and printing them.
+//--------------------------------------------------------------------
+
+#include "pub_tool_stacktrace.h"
+
+// Variant that gives a little more control over the stack-walking.
+extern UInt VG_(get_StackTrace2) ( StackTrace ips, UInt n_ips, Addr ip,
+                                   Addr fp, Addr fp_min, Addr fp_max );
+
+#endif   // __PUB_CORE_STACKTRACE_H
+
+/*--------------------------------------------------------------------*/
+/*--- end                                                          ---*/
+/*--------------------------------------------------------------------*/
diff --git a/coregrind/stacktrace.c b/coregrind/stacktrace.c
new file mode 100644
index 0000000..692a035
--- /dev/null
+++ b/coregrind/stacktrace.c
@@ -0,0 +1,204 @@
+/*--------------------------------------------------------------------*/
+/*---                                                 stacktrace.c ---*/
+/*--------------------------------------------------------------------*/
+
+/*
+   This file is part of Valgrind, a dynamic binary instrumentation
+   framework.
+
+   Copyright (C) 2000-2005 Julian Seward 
+      jseward@acm.org
+
+   This program is free software; you can redistribute it and/or
+   modify it under the terms of the GNU General Public License as
+   published by the Free Software Foundation; either version 2 of the
+   License, or (at your option) any later version.
+
+   This program is distributed in the hope that it will be useful, but
+   WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+   General Public License for more details.
+
+   You should have received a copy of the GNU General Public License
+   along with this program; if not, write to the Free Software
+   Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+   02111-1307, USA.
+
+   The GNU General Public License is contained in the file COPYING.
+*/
+
+#include "core.h"
+#include "pub_core_stacktrace.h"
+
+/*------------------------------------------------------------*/
+/*--- Exported functions.                                  ---*/
+/*------------------------------------------------------------*/
+
+/* Take a snapshot of the client's stack, putting the up to 'n_ips' IPs 
+   into 'ips'.  In order to be thread-safe, we pass in the thread's IP
+   and FP.  Returns number of IPs put in 'ips'.  */
+UInt VG_(get_StackTrace2) ( Addr* ips, UInt n_ips, Addr ip, Addr fp,
+                            Addr fp_min, Addr fp_max_orig )
+{
+   static const Bool debug = False;
+   Int         i;
+   Addr        fp_max;
+   UInt        n_found = 0;
+
+   VGP_PUSHCC(VgpExeContext);
+
+   /* First snaffle IPs from the client's stack into ips[0 .. n_ips-1], 
+      putting zeroes in when the trail goes cold, which we guess to be when
+      FP is not a reasonable stack location.  We also assert that FP
+      increases down the chain. */
+
+   // Gives shorter stack trace for tests/badjump.c
+   // JRS 2002-aug-16: I don't think this is a big deal; looks ok for
+   // most "normal" backtraces.
+   // NJN 2002-sep-05: traces for pthreaded programs are particularly bad.
+
+   // JRS 2002-sep-17: hack, to round up fp_max to the end of the
+   // current page, at least.  Dunno if it helps.
+   // NJN 2002-sep-17: seems to -- stack traces look like 1.0.X again
+   fp_max = (fp_max_orig + VKI_PAGE_SIZE - 1) & ~(VKI_PAGE_SIZE - 1);
+   fp_max -= sizeof(Addr);
+
+   if (debug)
+      VG_(printf)("n_ips=%d fp_min=%p fp_max_orig=%p, fp_max=%p ip=%p fp=%p\n",
+		  n_ips, fp_min, fp_max_orig, fp_max, ip, fp);
+
+   /* Assertion broken before main() is reached in pthreaded programs;  the
+    * offending stack traces only have one item.  --njn, 2002-aug-16 */
+   /* vg_assert(fp_min <= fp_max);*/
+
+   if (fp_min + 4000000 <= fp_max) {
+      /* If the stack is ridiculously big, don't poke around ... but
+         don't bomb out either.  Needed to make John Regehr's
+         user-space threads package work. JRS 20021001 */
+      ips[0] = ip;
+      i = 1;
+   } else {
+      /* Get whatever we safely can ... */
+      ips[0] = ip;
+      fp = FIRST_STACK_FRAME(fp);
+      for (i = 1; i < n_ips; i++) {
+         if (!(fp_min <= fp && fp <= fp_max)) {
+	    if (debug)
+	       VG_(printf)("... out of range %p\n", fp);
+            break; /* fp gone baaaad */
+         }
+         // NJN 2002-sep-17: monotonicity doesn't work -- gives wrong traces...
+         //     if (fp >= ((UInt*)fp)[0]) {
+         //   VG_(printf)("nonmonotonic\n");
+         //    break; /* fp gone nonmonotonic */
+         // }
+         ips[i] = STACK_FRAME_RET(fp);  /* ret addr */
+         fp     = STACK_FRAME_NEXT(fp);  /* old fp */
+	 if (debug)
+	    VG_(printf)("     ips[%d]=%08p\n", i, ips[i]);
+      }
+   }
+   n_found = i;
+
+   /* Put zeroes in the rest. */
+   for (;  i < n_ips; i++) {
+      ips[i] = 0;
+   }
+   VGP_POPCC(VgpExeContext);
+
+   return n_found;
+}
+
+UInt VG_(get_StackTrace) ( ThreadId tid, StackTrace ips, UInt n_ips )
+{
+   /* thread in thread table */
+   ThreadState* tst        = & VG_(threads)[ tid ];
+   Addr ip                 = INSTR_PTR(tst->arch);
+   Addr fp                 = FRAME_PTR(tst->arch);
+   Addr sp                 = STACK_PTR(tst->arch);
+   Addr stack_highest_word = tst->stack_highest_word;
+
+#ifdef __x86__
+   /* Nasty little hack to deal with sysinfo syscalls - if libc is
+      using the sysinfo page for syscalls (the TLS version does), then
+      ip will always appear to be in that page when doing a syscall,
+      not the actual libc function doing the syscall.  This check sees
+      if IP is within the syscall code, and pops the return address
+      off the stack so that ip is placed within the library function
+      calling the syscall.  This makes stack backtraces much more
+      useful.  */
+   if (ip >= VG_(client_trampoline_code)+VG_(tramp_syscall_offset) &&
+       ip < VG_(client_trampoline_code)+VG_(trampoline_code_length) &&
+       VG_(is_addressable)(sp, sizeof(Addr), VKI_PROT_READ)) {
+      ip = *(Addr *)sp;
+      sp += sizeof(Addr);
+   }
+#endif
+   if (0)
+      VG_(printf)("tid %d: stack_highest=%p ip=%p sp=%p fp=%p\n",
+		  tid, stack_highest_word, ip, sp, fp);
+
+   return VG_(get_StackTrace2)(ips, n_ips, ip, fp, sp, stack_highest_word);
+}
+
+static void printIpDesc(UInt n, Addr ip)
+{
+   static UChar buf[M_VG_ERRTXT];
+
+   VG_(describe_IP)(ip, buf, M_VG_ERRTXT);
+   VG_(message)(Vg_UserMsg, "   %s %s", ( n == 0 ? "at" : "by" ), buf);
+}
+
+/* Print a StackTrace. */
+void VG_(pp_StackTrace) ( StackTrace ips, UInt n_ips )
+{
+   vg_assert( n_ips > 0 );
+   VG_(apply_StackTrace)( printIpDesc, ips, n_ips );
+}
+
+/* Get and immediately print a StackTrace. */
+void VG_(get_and_pp_StackTrace) ( ThreadId tid, UInt n_ips )
+{
+   Addr ips[n_ips];
+   VG_(get_StackTrace)(tid, ips, n_ips);
+   VG_(pp_StackTrace) (     ips, n_ips);
+}
+
+
+void VG_(apply_StackTrace)( void(*action)(UInt n, Addr ip),
+                            StackTrace ips, UInt n_ips )
+{
+   #define MYBUF_LEN 10    // only needs to be long enough for "main"
+
+   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 -= MIN_INSTR_SIZE;     // point to calling line
+
+      // Stop after "main";  if main() is recursive, stop after last main().
+      if ( ! VG_(clo_show_below_main)) {
+         VG_(get_fnname_nodemangle)( ip, mybuf, MYBUF_LEN );
+         if ( VG_STREQ("main", mybuf) )
+            main_done = True;
+         else if (main_done)
+            break;
+      }
+
+      // Act on the ip
+      action(i, ip);
+
+      i++;
+   } while (i < n_ips && ips[i] != 0);
+
+   #undef MYBUF_LEN
+}
+
+
+/*--------------------------------------------------------------------*/
+/*--- end                                                          ---*/
+/*--------------------------------------------------------------------*/
diff --git a/coregrind/vg_errcontext.c b/coregrind/vg_errcontext.c
index ce55550..a28e34e 100644
--- a/coregrind/vg_errcontext.c
+++ b/coregrind/vg_errcontext.c
@@ -29,6 +29,7 @@
 */
 
 #include "core.h"
+#include "pub_core_execontext.h"
 
 /*------------------------------------------------------------*/
 /*--- Globals                                              ---*/
@@ -326,7 +327,7 @@
    err->count    = 1;
    err->tid      = tid;
    if (NULL == where)
-      err->where = VG_(get_ExeContext)( tid );
+      err->where = VG_(record_ExeContext)( tid );
    else
       err->where = where;
 
@@ -381,7 +382,7 @@
    }
 
    // Print stack trace elements
-   VG_(apply_ExeContext)(printSuppForIp, ec, stop_at);
+   VG_(apply_StackTrace)(printSuppForIp, VG_(extract_StackTrace)(ec), stop_at);
 
    VG_(printf)("}\n");
 }
@@ -675,9 +676,9 @@
       pp_Error( p_min, False );
 
       if ((i+1 == VG_(clo_dump_error))) {
+         StackTrace ips = VG_(extract_StackTrace)(p_min->where);
          VG_(translate) ( 0 /* dummy ThreadId; irrelevant due to debugging*/,
-                          p_min->where->ips[0], /*debugging*/True, 
-                          0xFE/*verbosity*/);
+                          ips[0], /*debugging*/True, 0xFE/*verbosity*/);
       }
 
       p_min->count = 1 << 30;
@@ -982,9 +983,10 @@
 {
    Int i;
    Char caller_name[M_VG_ERRTXT];
+   StackTrace ips = VG_(extract_StackTrace)(err->where);
 
    for (i = 0; i < su->n_callers; i++) {
-      Addr a = err->where->ips[i];
+      Addr a = ips[i];
       vg_assert(su->callers[i].name != NULL);
       switch (su->callers[i].ty) {
          case ObjName: 
diff --git a/coregrind/vg_execontext.c b/coregrind/vg_execontext.c
deleted file mode 100644
index 8683055..0000000
--- a/coregrind/vg_execontext.c
+++ /dev/null
@@ -1,411 +0,0 @@
-
-/*--------------------------------------------------------------------*/
-/*--- Storage, and equality on, execution contexts (backtraces).   ---*/
-/*---                                              vg_execontext.c ---*/
-/*--------------------------------------------------------------------*/
-
-/*
-   This file is part of Valgrind, a dynamic binary instrumentation
-   framework.
-
-   Copyright (C) 2000-2005 Julian Seward 
-      jseward@acm.org
-
-   This program is free software; you can redistribute it and/or
-   modify it under the terms of the GNU General Public License as
-   published by the Free Software Foundation; either version 2 of the
-   License, or (at your option) any later version.
-
-   This program is distributed in the hope that it will be useful, but
-   WITHOUT ANY WARRANTY; without even the implied warranty of
-   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
-   General Public License for more details.
-
-   You should have received a copy of the GNU General Public License
-   along with this program; if not, write to the Free Software
-   Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
-   02111-1307, USA.
-
-   The GNU General Public License is contained in the file COPYING.
-*/
-
-#include "core.h"
-
-
-/*------------------------------------------------------------*/
-/*--- Low-level ExeContext storage.                        ---*/
-/*------------------------------------------------------------*/
-
-/* Number of lists in which we keep track of ExeContexts.  Should be
-   prime. */
-#define N_EC_LISTS 4999 /* a prime number */
-
-/* The idea is only to ever store any one context once, so as to save
-   space and make exact comparisons faster. */
-
-static ExeContext* ec_list[N_EC_LISTS];
-
-/* Stats only: the number of times the system was searched to locate a
-   context. */
-static UInt ec_searchreqs;
-
-/* Stats only: the number of full context comparisons done. */
-static UInt ec_searchcmps;
-
-/* Stats only: total number of stored contexts. */
-static UInt ec_totstored;
-
-/* Number of 2, 4 and (fast) full cmps done. */
-static UInt ec_cmp2s;
-static UInt ec_cmp4s;
-static UInt ec_cmpAlls;
-
-
-/*------------------------------------------------------------*/
-/*--- Exported functions.                                  ---*/
-/*------------------------------------------------------------*/
-
-
-/* Initialise this subsystem. */
-static void init_ExeContext_storage ( void )
-{
-   Int i;
-   static Bool init_done = False;
-   if (init_done)
-      return;
-   ec_searchreqs = 0;
-   ec_searchcmps = 0;
-   ec_totstored = 0;
-   ec_cmp2s = 0;
-   ec_cmp4s = 0;
-   ec_cmpAlls = 0;
-   for (i = 0; i < N_EC_LISTS; i++)
-      ec_list[i] = NULL;
-   init_done = True;
-}
-
-
-/* Print stats. */
-void VG_(print_ExeContext_stats) ( void )
-{
-   init_ExeContext_storage();
-   VG_(message)(Vg_DebugMsg, 
-      "   exectx: %d lists, %d contexts (avg %d per list)",
-      N_EC_LISTS, ec_totstored, 
-      ec_totstored / N_EC_LISTS 
-   );
-   VG_(message)(Vg_DebugMsg, 
-      "   exectx: %d searches, %d full compares (%d per 1000)",
-      ec_searchreqs, ec_searchcmps, 
-      ec_searchreqs == 0 
-         ? 0 
-         : (UInt)( (((ULong)ec_searchcmps) * 1000) 
-           / ((ULong)ec_searchreqs )) 
-   );
-   VG_(message)(Vg_DebugMsg, 
-      "   exectx: %d cmp2, %d cmp4, %d cmpAll",
-      ec_cmp2s, ec_cmp4s, ec_cmpAlls 
-   );
-}
-
-
-static void printIpDesc(UInt n, Addr ip)
-{
-   static UChar buf[M_VG_ERRTXT];
-
-   VG_(describe_eip)(ip, buf, M_VG_ERRTXT);
-   VG_(message)(Vg_UserMsg, "   %s %s", ( n == 0 ? "at" : "by" ), buf);
-}
-
-/* Print an ExeContext. */
-void VG_(pp_ExeContext) ( ExeContext* ec )
-{
-   vg_assert( VG_(clo_backtrace_size) > 0 );
-   VG_(apply_ExeContext)( printIpDesc, ec, VG_(clo_backtrace_size) );
-}
-
-
-/* Compare two ExeContexts, comparing all callers. */
-Bool VG_(eq_ExeContext) ( VgRes res, ExeContext* e1, ExeContext* e2 )
-{
-   if (e1 == NULL || e2 == NULL) 
-      return False;
-   switch (res) {
-   case Vg_LowRes:
-      /* Just compare the top two callers. */
-      ec_cmp2s++;
-      if (e1->ips[0] != e2->ips[0]
-          || e1->ips[1] != e2->ips[1]) return False;
-      return True;
-
-   case Vg_MedRes:
-      /* Just compare the top four callers. */
-      ec_cmp4s++;
-      if (e1->ips[0] != e2->ips[0]) return False;
-
-      if (VG_(clo_backtrace_size) < 2) return True;
-      if (e1->ips[1] != e2->ips[1]) return False;
-
-      if (VG_(clo_backtrace_size) < 3) return True;
-      if (e1->ips[2] != e2->ips[2]) return False;
-
-      if (VG_(clo_backtrace_size) < 4) return True;
-      if (e1->ips[3] != e2->ips[3]) return False;
-      return True;
-
-   case Vg_HighRes:
-      ec_cmpAlls++;
-      /* Compare them all -- just do pointer comparison. */
-      if (e1 != e2) return False;
-      return True;
-
-   default:
-      VG_(core_panic)("VG_(eq_ExeContext): unrecognised VgRes");
-   }
-}
-
-
-void VG_(apply_ExeContext)( void(*action)(UInt n, Addr ip),
-                            ExeContext* ec, UInt n_ips )
-{
-   #define MYBUF_LEN 10    // only needs to be long enough for "main"
-
-   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 = ec->ips[i];
-      if (i > 0) 
-         ip -= MIN_INSTR_SIZE;     // point to calling line
-
-      // Stop after "main";  if main() is recursive, stop after last main().
-      if ( ! VG_(clo_show_below_main)) {
-         VG_(get_fnname_nodemangle)( ip, mybuf, MYBUF_LEN );
-         if ( VG_STREQ("main", mybuf) )
-            main_done = True;
-         else if (main_done)
-            break;
-      }
-
-      // Act on the ip
-      action(i, ip);
-
-      i++;
-   } while (i < n_ips && ec->ips[i] != 0);
-
-   #undef MYBUF_LEN
-}
-
-
-/* Take a snapshot of the client's stack, putting the up to 'n_ips' IPs 
-   into 'ips'.  In order to be thread-safe, we pass in the thread's IP
-   and FP.  Returns number of IPs put in 'ips'.  */
-static UInt stack_snapshot2 ( Addr* ips, UInt n_ips, Addr ip, Addr fp,
-                              Addr fp_min, Addr fp_max_orig )
-{
-   static const Bool debug = False;
-   Int         i;
-   Addr        fp_max;
-   UInt        n_found = 0;
-
-   VGP_PUSHCC(VgpExeContext);
-
-   /* First snaffle IPs from the client's stack into ips[0 .. n_ips-1], 
-      putting zeroes in when the trail goes cold, which we guess to be when
-      FP is not a reasonable stack location.  We also assert that FP
-      increases down the chain. */
-
-   // Gives shorter stack trace for tests/badjump.c
-   // JRS 2002-aug-16: I don't think this is a big deal; looks ok for
-   // most "normal" backtraces.
-   // NJN 2002-sep-05: traces for pthreaded programs are particularly bad.
-
-   // JRS 2002-sep-17: hack, to round up fp_max to the end of the
-   // current page, at least.  Dunno if it helps.
-   // NJN 2002-sep-17: seems to -- stack traces look like 1.0.X again
-   fp_max = (fp_max_orig + VKI_PAGE_SIZE - 1) & ~(VKI_PAGE_SIZE - 1);
-   fp_max -= sizeof(Addr);
-
-   if (debug)
-      VG_(printf)("n_ips=%d fp_min=%p fp_max_orig=%p, fp_max=%p ip=%p fp=%p\n",
-		  n_ips, fp_min, fp_max_orig, fp_max, ip, fp);
-
-   /* Assertion broken before main() is reached in pthreaded programs;  the
-    * offending stack traces only have one item.  --njn, 2002-aug-16 */
-   /* vg_assert(fp_min <= fp_max);*/
-
-   if (fp_min + 4000000 <= fp_max) {
-      /* If the stack is ridiculously big, don't poke around ... but
-         don't bomb out either.  Needed to make John Regehr's
-         user-space threads package work. JRS 20021001 */
-      ips[0] = ip;
-      i = 1;
-   } else {
-      /* Get whatever we safely can ... */
-      ips[0] = ip;
-      fp = FIRST_STACK_FRAME(fp);
-      for (i = 1; i < n_ips; i++) {
-         if (!(fp_min <= fp && fp <= fp_max)) {
-	    if (debug)
-	       VG_(printf)("... out of range %p\n", fp);
-            break; /* fp gone baaaad */
-         }
-         // NJN 2002-sep-17: monotonicity doesn't work -- gives wrong traces...
-         //     if (fp >= ((UInt*)fp)[0]) {
-         //   VG_(printf)("nonmonotonic\n");
-         //    break; /* fp gone nonmonotonic */
-         // }
-         ips[i] = STACK_FRAME_RET(fp);  /* ret addr */
-         fp     = STACK_FRAME_NEXT(fp);  /* old fp */
-	 if (debug)
-	    VG_(printf)("     ips[%d]=%08p\n", i, ips[i]);
-      }
-   }
-   n_found = i;
-
-   /* Put zeroes in the rest. */
-   for (;  i < n_ips; i++) {
-      ips[i] = 0;
-   }
-   VGP_POPCC(VgpExeContext);
-
-   return n_found;
-}
-
-/* This guy is the head honcho here.  Take a snapshot of the client's
-   stack.  Search our collection of ExeContexts to see if we already
-   have it, and if not, allocate a new one.  Either way, return a
-   pointer to the context.  If there is a matching context we
-   guarantee to not allocate a new one.  Thus we never store
-   duplicates, and so exact equality can be quickly done as equality
-   on the returned ExeContext* values themselves.  Inspired by Hugs's
-   Text type.  
-*/
-ExeContext* VG_(get_ExeContext2) ( Addr ip, Addr fp,
-                                   Addr fp_min, Addr fp_max_orig )
-{
-   Int         i;
-   Addr        ips[VG_DEEPEST_BACKTRACE];
-   Bool        same;
-   UWord       hash;
-   ExeContext* new_ec;
-   ExeContext* list;
-
-   VGP_PUSHCC(VgpExeContext);
-
-   init_ExeContext_storage();
-   vg_assert(VG_(clo_backtrace_size) >= 1 
-             && VG_(clo_backtrace_size) <= VG_DEEPEST_BACKTRACE);
-
-   stack_snapshot2( ips, VG_(clo_backtrace_size),
-                    ip, fp, fp_min, fp_max_orig );
-
-   /* Now figure out if we've seen this one before.  First hash it so
-      as to determine the list number. */
-
-   hash = 0;
-   for (i = 0; i < VG_(clo_backtrace_size); i++) {
-      hash ^= ips[i];
-      hash = (hash << 29) | (hash >> 3);
-   }
-   hash = hash % N_EC_LISTS;
-
-   /* And (the expensive bit) look a matching entry in the list. */
-
-   ec_searchreqs++;
-
-   list = ec_list[hash];
-
-   while (True) {
-      if (list == NULL) break;
-      ec_searchcmps++;
-      same = True;
-      for (i = 0; i < VG_(clo_backtrace_size); i++) {
-         if (list->ips[i] != ips[i]) {
-            same = False;
-            break; 
-         }
-      }
-      if (same) break;
-      list = list->next;
-   }
-
-   if (list != NULL) {
-      /* Yay!  We found it.  */
-      VGP_POPCC(VgpExeContext);
-      return list;
-   }
-
-   /* Bummer.  We have to allocate a new context record. */
-   ec_totstored++;
-
-   new_ec = VG_(arena_malloc)( VG_AR_EXECTXT, 
-                               sizeof(struct _ExeContext *) 
-                               + VG_(clo_backtrace_size) * sizeof(Addr) );
-
-   for (i = 0; i < VG_(clo_backtrace_size); i++)
-      new_ec->ips[i] = ips[i];
-
-   new_ec->next = ec_list[hash];
-   ec_list[hash] = new_ec;
-
-   VGP_POPCC(VgpExeContext);
-   return new_ec;
-}
-
-static
-void get_needed_regs(ThreadId tid, Addr* ip, Addr* fp, Addr* sp,
-                     Addr* stack_highest_word)
-{
-   /* thread in thread table */
-   ThreadState* tst = & VG_(threads)[ tid ];
-   *ip                 = INSTR_PTR(tst->arch);
-   *fp                 = FRAME_PTR(tst->arch);
-   *sp                 = STACK_PTR(tst->arch);
-   *stack_highest_word = tst->stack_highest_word;
-
-#ifdef __x86__
-   /* Nasty little hack to deal with sysinfo syscalls - if libc is
-      using the sysinfo page for syscalls (the TLS version does), then
-      ip will always appear to be in that page when doing a syscall,
-      not the actual libc function doing the syscall.  This check sees
-      if IP is within the syscall code, and pops the return address
-      off the stack so that ip is placed within the library function
-      calling the syscall.  This makes stack backtraces much more
-      useful.  */
-   if (*ip >= VG_(client_trampoline_code)+VG_(tramp_syscall_offset) &&
-       *ip < VG_(client_trampoline_code)+VG_(trampoline_code_length) &&
-       VG_(is_addressable)(*sp, sizeof(Addr), VKI_PROT_READ)) {
-      *ip = *(Addr *)*sp;
-      *sp += sizeof(Addr);
-   }
-#endif
-   if (0)
-      VG_(printf)("tid %d: stack_highest=%p ip=%p sp=%p fp=%p\n",
-		  tid, *stack_highest_word, *ip, *sp, *fp);
-}
-
-ExeContext* VG_(get_ExeContext) ( ThreadId tid )
-{
-   Addr ip, fp, sp, stack_highest_word;
-
-   get_needed_regs(tid, &ip, &fp, &sp, &stack_highest_word);
-   return VG_(get_ExeContext2)(ip, fp, sp, stack_highest_word);
-}
-
-/* Take a snapshot of the client's stack, putting the up to 'n_ips' 
-   instruction pointers into 'ips'.  In order to be thread-safe, we pass in
-   the thread's IP and FP.  Returns number of IPs put in 'ips'.  */
-UInt VG_(stack_snapshot) ( ThreadId tid, Addr* ips, UInt n_ips )
-{
-   Addr ip, fp, sp, stack_highest_word;
-
-   get_needed_regs(tid, &ip, &fp, &sp, &stack_highest_word);
-   return stack_snapshot2(ips, n_ips, ip, fp, sp, stack_highest_word);
-}
-
-/*--------------------------------------------------------------------*/
-/*--- end                                                          ---*/
-/*--------------------------------------------------------------------*/
diff --git a/coregrind/vg_main.c b/coregrind/vg_main.c
index eaef6d2..15962ce 100644
--- a/coregrind/vg_main.c
+++ b/coregrind/vg_main.c
@@ -32,6 +32,7 @@
 
 #include "core.h"
 #include "ume.h"
+#include "pub_core_execontext.h"
 
 #include <dirent.h>
 #include <dlfcn.h>
diff --git a/coregrind/vg_mylibc.c b/coregrind/vg_mylibc.c
index 4cd55f9..3f261fd 100644
--- a/coregrind/vg_mylibc.c
+++ b/coregrind/vg_mylibc.c
@@ -31,6 +31,7 @@
 */
 
 #include "core.h"
+#include "pub_core_stacktrace.h"
 
 /* ---------------------------------------------------------------------
    Wrappers around system calls, and other stuff, to do with signals.
@@ -1128,9 +1129,9 @@
    into the signal handler.  Also, it could be somewhat risky if we
    actully got the panic/exception within the execontext/stack
    dump/symtab code.  But it's better than nothing. */
-static inline ExeContext *get_real_execontext(Addr ret)
+static inline void get_and_pp_real_StackTrace(Addr ret)
 {
-   ExeContext *ec;
+   Addr ips[VG_DEEPEST_BACKTRACE];
    Addr sp, fp;
    Addr stacktop;
    ThreadId tid = VG_(get_lwp_tid)(VG_(gettid)());
@@ -1141,18 +1142,18 @@
 
    stacktop = (Addr)(tst->os_state.stack + tst->os_state.stacksize);
 
-   ec = VG_(get_ExeContext2)(ret, fp, sp, stacktop);
-
-   return ec;
+   VG_(get_StackTrace2)(ips, VG_(clo_backtrace_size),
+                        ret, fp, sp, stacktop);
+   VG_(pp_StackTrace)  (ips, VG_(clo_backtrace_size));
 }
 
 __attribute__ ((noreturn))
-static void report_and_quit ( const Char* report, ExeContext *ec )
+static void report_and_quit ( const Char* report, StackTrace ips )
 {
-   if (ec == NULL)
-      ec = get_real_execontext((Addr)__builtin_return_address(0));
-
-   VG_(pp_ExeContext)(ec);
+   if (ips == NULL)
+      get_and_pp_real_StackTrace((Addr)__builtin_return_address(0));
+   else
+      VG_(pp_StackTrace)(ips, VG_(clo_backtrace_size));
    
    VG_(pp_sched_status)();
    VG_(printf)("\n");
@@ -1191,11 +1192,11 @@
 }
 
 __attribute__ ((noreturn))
-static void panic ( Char* name, Char* report, Char* str, ExeContext *ec )
+static void panic ( Char* name, Char* report, Char* str, StackTrace ips )
 {
    VG_(printf)("\n%s: the `impossible' happened:\n   %s\n", name, str);
    VG_(printf)("Basic block ctr is approximately %llu\n", VG_(bbs_done) );
-   report_and_quit(report, ec);
+   report_and_quit(report, ips);
 }
 
 void VG_(core_panic) ( Char* str )
@@ -1203,9 +1204,9 @@
    panic("valgrind", VG_BUGS_TO, str, NULL);
 }
 
-void VG_(core_panic_at) ( Char* str, ExeContext *ec )
+void VG_(core_panic_at) ( Char* str, StackTrace ips )
 {
-   panic("valgrind", VG_BUGS_TO, str, ec);
+   panic("valgrind", VG_BUGS_TO, str, ips);
 }
 
 void VG_(tool_panic) ( Char* str )
diff --git a/coregrind/vg_scheduler.c b/coregrind/vg_scheduler.c
index e316eb4..66eba36 100644
--- a/coregrind/vg_scheduler.c
+++ b/coregrind/vg_scheduler.c
@@ -60,6 +60,8 @@
                              VG_USERREQ__DISCARD_TRANSLATIONS, and others */
 #include "core.h"
 
+#include "pub_core_stacktrace.h"
+
 
 /* ---------------------------------------------------------------------
    Types and globals for the scheduler.
@@ -168,7 +170,7 @@
    for (i = 1; i < VG_N_THREADS; i++) {
       if (VG_(threads)[i].status == VgTs_Empty) continue;
       VG_(printf)("\nThread %d: status = %s\n", i, name_of_thread_state(VG_(threads)[i].status));
-      VG_(pp_ExeContext)( VG_(get_ExeContext)( i ) );
+      VG_(get_and_pp_StackTrace)( i, VG_(clo_backtrace_size) );
    }
    VG_(printf)("\n");
 }
@@ -844,7 +846,7 @@
             VG_(message)( Vg_UserMsg,
                           "Emulation warning: unsupported action:");
             VG_(message)( Vg_UserMsg, "  %s", what);
-            VG_(pp_ExeContext) (  VG_(get_ExeContext) ( tid ) );
+            VG_(get_and_pp_StackTrace)( tid, VG_(clo_backtrace_size) );
          }
          break;
       }
@@ -1047,10 +1049,9 @@
          break; }
 
       case VG_USERREQ__PRINTF_BACKTRACE: {
-         ExeContext *e = VG_(get_ExeContext)( tid );
          int count =
             VG_(vmessage)( Vg_ClientMsg, (char *)arg[1], (void*)arg[2] );
-            VG_(pp_ExeContext)(e);
+            VG_(get_and_pp_StackTrace)( tid, VG_(clo_backtrace_size) );
             SET_CLREQ_RETVAL( tid, count );
          break; }
 
diff --git a/coregrind/vg_signals.c b/coregrind/vg_signals.c
index 6774b39..8e814d7 100644
--- a/coregrind/vg_signals.c
+++ b/coregrind/vg_signals.c
@@ -1373,8 +1373,7 @@
       }
 
       if (tid != VG_INVALID_THREADID) {
-	 ExeContext *ec = VG_(get_ExeContext)(tid);
-	 VG_(pp_ExeContext)(ec);
+         VG_(get_and_pp_StackTrace)(tid, VG_(clo_backtrace_size));
       }
    }
 
@@ -1879,6 +1878,7 @@
       from the client's code, then we can jump back into the scheduler
       and have it delivered.  Otherwise it's a Valgrind bug. */
    {   
+      Addr ips[ VG_(clo_backtrace_size) ];
       Addr context_ip;
       Char buf[1024];
       ThreadState *tst = VG_(get_ThreadState)(VG_(get_lwp_tid)(VG_(gettid)()));
@@ -1936,11 +1936,12 @@
       if (tid == 0)            /* could happen after everyone has exited */
         tid = VG_(master_tid);
       tst = VG_(get_ThreadState)(tid);
-      VG_(core_panic_at)("Killed by fatal signal",
-                         VG_(get_ExeContext2)(UCONTEXT_INSTR_PTR(uc),
-                                              UCONTEXT_FRAME_PTR(uc),
-                                              UCONTEXT_STACK_PTR(uc),
-                                              (Addr)(tst->os_state.stack + tst->os_state.stacksize)));
+      VG_(get_StackTrace2)(ips, VG_(clo_backtrace_size), 
+                           UCONTEXT_INSTR_PTR(uc),
+                           UCONTEXT_FRAME_PTR(uc),
+                           UCONTEXT_STACK_PTR(uc),
+                           (Addr)(tst->os_state.stack + tst->os_state.stacksize));
+      VG_(core_panic_at)("Killed by fatal signal", ips);
    }
 }
 
diff --git a/coregrind/vg_symtab2.c b/coregrind/vg_symtab2.c
index 9cb2a12..1ec15ae 100644
--- a/coregrind/vg_symtab2.c
+++ b/coregrind/vg_symtab2.c
@@ -2170,7 +2170,7 @@
 #endif /* TEST */
 
 /* Print into buf info on code address, function name and filename */
-Char* VG_(describe_eip)(Addr eip, Char* buf, Int n_buf)
+Char* VG_(describe_IP)(Addr eip, Char* buf, Int n_buf)
 {
 #define APPEND(str)                                         \
    { UChar* sss;                                            \
diff --git a/coregrind/vg_syscalls.c b/coregrind/vg_syscalls.c
index 14e4c97..b0b1c75 100644
--- a/coregrind/vg_syscalls.c
+++ b/coregrind/vg_syscalls.c
@@ -29,6 +29,7 @@
 */
 
 #include "core.h"
+#include "pub_core_stacktrace.h"
 
 /* All system calls are channelled through here, doing two things:
 
@@ -134,8 +135,7 @@
 		   syscallname, start, end);
 
       if (VG_(clo_verbosity) > 1) {
-	 ExeContext *ec = VG_(get_ExeContext)(tid);
-	 VG_(pp_ExeContext)(ec);
+         VG_(get_and_pp_StackTrace)(tid, VG_(clo_backtrace_size));
       }
    }
 
@@ -479,7 +479,7 @@
 
    i->fd = fd;
    i->pathname = pathname;
-   i->where = (tid == -1) ? NULL : VG_(get_ExeContext)(tid);
+   i->where = (tid == -1) ? NULL : VG_(record_ExeContext)(tid);
 }
 
 static
@@ -954,8 +954,7 @@
 	 VG_(message)(Vg_UserMsg, 
             "   Use --log-fd=<number> to select an alternative log fd.");
       if (VG_(clo_verbosity) > 1) {
-	 ExeContext *ec = VG_(get_ExeContext)(tid);
-	 VG_(pp_ExeContext)(ec);
+         VG_(get_and_pp_StackTrace)(tid, VG_(clo_backtrace_size));
       }
       return False;
    }
@@ -5907,8 +5906,7 @@
    VG_(message)
       (Vg_DebugMsg,"WARNING: unhandled syscall: %u", (UInt)SYSNO);
    if (VG_(clo_verbosity) > 1) {
-      ExeContext *ec = VG_(get_ExeContext)(tid);
-      VG_(pp_ExeContext)(ec);
+      VG_(get_and_pp_StackTrace)(tid, VG_(clo_backtrace_size));
    }
    VG_(message)
       (Vg_DebugMsg,"Do not panic.  You may be able to fix this easily.");
diff --git a/coregrind/vg_threadmodel.c b/coregrind/vg_threadmodel.c
index 37209b0..a1bec5d 100644
--- a/coregrind/vg_threadmodel.c
+++ b/coregrind/vg_threadmodel.c
@@ -180,7 +180,7 @@
 //::    if (th->state == state)
 //::       return;
 //:: 
-//::    ec = VG_(get_ExeContext)(th->tid);
+//::    ec = VG_(record_ExeContext)(th->tid);
 //:: 
 //::    switch(state) {
 //::    case TS_Alive:
@@ -607,7 +607,7 @@
 //:: 
 //:: static void mutex_setstate(ThreadId tid, struct mutex *mx, enum mutex_state st)
 //:: {
-//::    ExeContext *ec = VG_(get_ExeContext)(tid);
+//::    ExeContext *ec = VG_(record_ExeContext)(tid);
 //:: 
 //::    switch(st) {
 //::    case MX_Init:
diff --git a/helgrind/hg_main.c b/helgrind/hg_main.c
index bf9a9d4..3013aeb 100644
--- a/helgrind/hg_main.c
+++ b/helgrind/hg_main.c
@@ -1571,7 +1571,7 @@
       break;
    }
 
-   mutex->location = VG_(get_ExeContext)(tid);
+   mutex->location = VG_(record_ExeContext)(tid);
    mutex->state = state;
 }
 
@@ -1818,7 +1818,7 @@
    hc            = VG_(malloc)(sizeof(HG_Chunk));
    hc->data      = p;
    hc->size      = size;
-   hc->where     = VG_(get_ExeContext)(tid);
+   hc->where     = VG_(record_ExeContext)(tid);
    hc->tid       = tid;
 
    VG_(HT_add_node)( hg_malloc_list, (VgHashNode*)hc );
@@ -1894,7 +1894,7 @@
    *prev_chunks_next_ptr = hc->next;
 
    /* Record where freed */
-   hc->where = VG_(get_ExeContext) ( tid );
+   hc->where = VG_(record_ExeContext) ( tid );
 
    /* maintain a small window so that the error reporting machinery
       knows about this memory */
@@ -1961,13 +1961,13 @@
   
    if (hc->size == new_size) {
       /* size unchanged */
-      hc->where = VG_(get_ExeContext)(tid);
+      hc->where = VG_(record_ExeContext)(tid);
       return p;
       
    } else if (hc->size > new_size) {
       /* new size is smaller */
       hc->size = new_size;
-      hc->where = VG_(get_ExeContext)(tid);
+      hc->where = VG_(record_ExeContext)(tid);
       return p;
 
    } else {
@@ -3035,7 +3035,7 @@
       if (clo_execontext == EC_Some)
 	 ecip = IP(VG_(get_IP)(tid), prevstate, tls);
       else
-	 ecip = EC(VG_(get_ExeContext)(tid), prevstate, tls);
+	 ecip = EC(VG_(record_ExeContext)(tid), prevstate, tls);
       setExeContext(a, ecip);
    }
 }
@@ -3140,7 +3140,7 @@
       if (clo_execontext == EC_Some)
 	 ecip = IP(VG_(get_IP)(tid), prevstate, tls);
       else
-	 ecip = EC(VG_(get_ExeContext)(tid), prevstate, tls);
+	 ecip = EC(VG_(record_ExeContext)(tid), prevstate, tls);
       setExeContext(a, ecip);
    }
 }
diff --git a/include/Makefile.am b/include/Makefile.am
index e9bafff..d41672a 100644
--- a/include/Makefile.am
+++ b/include/Makefile.am
@@ -10,9 +10,11 @@
 incincdir = $(includedir)/valgrind
 
 incinc_HEADERS = \
-	basic_types.h \
-	tool.h \
-	tool_asm.h \
+	basic_types.h 		\
+	tool.h 			\
+	tool_asm.h 		\
+	pub_tool_stacktrace.h 	\
+	pub_tool_execontext.h 	\
 	valgrind.h
 
 BUILT_SOURCES = tool.h valgrind.h
diff --git a/include/basic_types.h b/include/basic_types.h
index cbf1594..728c367 100644
--- a/include/basic_types.h
+++ b/include/basic_types.h
@@ -32,7 +32,7 @@
 #define __BASIC_TYPES_H
 
 /* ---------------------------------------------------------------------
-   Basic types
+   builtin types
    ------------------------------------------------------------------ */
 
 #include "libvex_basictypes.h"
@@ -57,6 +57,14 @@
 
 typedef  Word                   OffT;     // 32             64
 
+/* ---------------------------------------------------------------------
+   non-builtin types
+   ------------------------------------------------------------------ */
+
+/* ThreadIds are simply indices into the VG_(threads)[] array. */
+typedef
+   UInt
+   ThreadId;
 
 /* ---------------------------------------------------------------------
    Where to send bug reports to.
diff --git a/include/pub_tool_execontext.h b/include/pub_tool_execontext.h
new file mode 100644
index 0000000..9e33869
--- /dev/null
+++ b/include/pub_tool_execontext.h
@@ -0,0 +1,76 @@
+/*--------------------------------------------------------------------*/
+/*--- ExeContexts: long-lived stack traces.  pub_tool_execontext.h ---*/
+/*--------------------------------------------------------------------*/
+
+/*
+   This file is part of Valgrind, a dynamic binary instrumentation
+   framework.
+
+   Copyright (C) 2000-2005 Julian Seward
+      jseward@acm.org
+
+   This program is free software; you can redistribute it and/or
+   modify it under the terms of the GNU General Public License as
+   published by the Free Software Foundation; either version 2 of the
+   License, or (at your option) any later version.
+
+   This program is distributed in the hope that it will be useful, but
+   WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+   General Public License for more details.
+
+   You should have received a copy of the GNU General Public License
+   along with this program; if not, write to the Free Software
+   Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+   02111-1307, USA.
+
+   The GNU General Public License is contained in the file COPYING.
+*/
+
+#ifndef __PUB_TOOL_EXECONTEXT_H
+#define __PUB_TOOL_EXECONTEXT_H
+
+// It's an abstract type.
+typedef
+   struct _ExeContext
+   ExeContext;
+
+// Resolution type used to decide how closely to compare two errors for
+// equality.
+typedef
+   enum { Vg_LowRes, Vg_MedRes, Vg_HighRes }
+   VgRes;
+
+// Take a snapshot of the client's stack.  Search our collection of
+// ExeContexts to see if we already have it, and if not, allocate a
+// new one.  Either way, return a pointer to the context.  Context size
+// controlled by --num-callers option.
+//
+// This should only be used for long-lived stack traces.  If you want a
+// short-lived stack trace, use VG_(get_StackTrace)().
+//
+// If called from generated code, use VG_(get_running_tid)() to get the
+// current ThreadId.  If called from non-generated code, the current
+// ThreadId should be passed in by the core.
+extern ExeContext* VG_(record_ExeContext) ( ThreadId tid );
+
+// Apply a function to every element in the ExeContext.  The parameter 'n'
+// gives the index of the passed ip.  Doesn't go below main() unless
+// --show-below-main=yes is set.
+extern void VG_(apply_ExeContext)( void(*action)(UInt n, Addr ip),
+                                   ExeContext* ec, UInt n_ips );
+
+// Compare two ExeContexts.  Number of callers considered depends on `res':
+//   Vg_LowRes:  2
+//   Vg_MedRes:  4
+//   Vg_HighRes: all
+extern Bool VG_(eq_ExeContext) ( VgRes res, ExeContext* e1, ExeContext* e2 );
+
+// Print an ExeContext.
+extern void VG_(pp_ExeContext) ( ExeContext* ec );
+
+#endif   // __PUB_TOOL_EXECONTEXT_H
+
+/*--------------------------------------------------------------------*/
+/*--- end                                                          ---*/
+/*--------------------------------------------------------------------*/
diff --git a/include/pub_tool_stacktrace.h b/include/pub_tool_stacktrace.h
new file mode 100644
index 0000000..f74a1b1
--- /dev/null
+++ b/include/pub_tool_stacktrace.h
@@ -0,0 +1,61 @@
+/*--------------------------------------------------------------------*/
+/*--- Stack traces: getting, traversing, printing.                 ---*/
+/*---                                            tool_stacktrace.h ---*/
+/*--------------------------------------------------------------------*/
+
+/*
+   This file is part of Valgrind, a dynamic binary instrumentation
+   framework.
+
+   Copyright (C) 2000-2005 Julian Seward
+      jseward@acm.org
+
+   This program is free software; you can redistribute it and/or
+   modify it under the terms of the GNU General Public License as
+   published by the Free Software Foundation; either version 2 of the
+   License, or (at your option) any later version.
+
+   This program is distributed in the hope that it will be useful, but
+   WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+   General Public License for more details.
+
+   You should have received a copy of the GNU General Public License
+   along with this program; if not, write to the Free Software
+   Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+   02111-1307, USA.
+
+   The GNU General Public License is contained in the file COPYING.
+*/
+
+#ifndef __PUB_TOOL_STACKTRACE_H
+#define __PUB_TOOL_STACKTRACE_H
+
+#include "basic_types.h"
+
+// The basic stack trace type:  just an array of code addresses.
+typedef Addr* StackTrace;
+
+// Walks the stack to get instruction pointers from the top stack frames for
+// thread 'tid'.  Maximum of 'n_ips' addresses put into 'ips';  0 is the top
+// of the stack, 1 is its caller, etc.
+extern UInt VG_(get_StackTrace) ( ThreadId tid, StackTrace ips, UInt n_ips );
+
+// Apply a function to every element in the StackTrace.  The parameter 'n'
+// gives the index of the passed ip.  Doesn't go below main() unless
+// --show-below-main=yes is set.
+extern void VG_(apply_StackTrace)( void(*action)(UInt n, Addr ip),
+                                   StackTrace ips, UInt n_ips );
+
+// Print a StackTrace.
+extern void VG_(pp_StackTrace) ( StackTrace ips, UInt n_ips );
+
+// 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 );
+
+#endif   // __PUB_TOOL_STACKTRACE_H
+
+/*--------------------------------------------------------------------*/
+/*--- end                                                          ---*/
+/*--------------------------------------------------------------------*/
diff --git a/include/tool.h.base b/include/tool.h.base
index 2ef0f8e..14d9fe6 100644
--- a/include/tool.h.base
+++ b/include/tool.h.base
@@ -1,6 +1,5 @@
 /*-*- c -*- ----------------------------------------------------------*/
-/*--- The only header your tool will ever need to #include...      ---*/
-/*---                                                       tool.h ---*/
+/*--- Header for lots of tool stuff.                        tool.h ---*/
 /*--------------------------------------------------------------------*/
 
 /*
@@ -38,6 +37,8 @@
 #include "tool_arch.h"          /* arch-specific tool stuff */
 #include "vki.h"
 
+#include "pub_tool_execontext.h"    // needed for type 'ExeContext'
+
 #include "libvex.h"
 #include "libvex_ir.h"
 
@@ -282,11 +283,6 @@
    pthread_mutex_t.__m_owner and pthread_cond_t.__c_waiting. */
 #define VG_INVALID_THREADID ((ThreadId)(0))
 
-/* ThreadIds are simply indices into the VG_(threads)[] array. */
-typedef
-   UInt
-   ThreadId;
-
 /* Get the TID of the thread which currently has the CPU. */
 extern ThreadId VG_(get_running_tid) ( void );
 
@@ -571,53 +567,6 @@
                          UInt *ecx_ret, UInt *edx_ret );
 
 /*====================================================================*/
-/*=== Execution contexts                                           ===*/
-/*====================================================================*/
-
-/* Generic resolution type used in a few different ways, such as deciding
-   how closely to compare two errors for equality. */
-typedef
-   enum { Vg_LowRes, Vg_MedRes, Vg_HighRes }
-   VgRes;
-
-typedef
-   struct _ExeContext
-   ExeContext;
-
-/* Compare two ExeContexts.  Number of callers considered depends on `res':
-     Vg_LowRes:  2
-     Vg_MedRes:  4
-     Vg_HighRes: all */
-extern Bool VG_(eq_ExeContext) ( VgRes res,
-                                 ExeContext* e1, ExeContext* e2 );
-
-/* Print an ExeContext. */
-extern void VG_(pp_ExeContext) ( ExeContext* );
-
-/* Take a snapshot of the client's stack.  Search our collection of
-   ExeContexts to see if we already have it, and if not, allocate a
-   new one.  Either way, return a pointer to the context.  Context size
-   controlled by --num-callers option.
-
-   If called from generated code, use VG_(get_VCPU_tid)() to get the
-   current ThreadId.  If called from non-generated code, the current
-   ThreadId should be passed in by the core.
-*/
-extern ExeContext* VG_(get_ExeContext) ( ThreadId tid );
-
-/* Apply a function to every element in the ExeContext.  The parameter 'n'
-   gives the index of the passed ip.  Doesn't go below main() unless
-   --show-below-main=yes is set. */
-extern void VG_(apply_ExeContext)( void(*action)(UInt n, Addr ip),
-                                   ExeContext* ec, UInt n_ips );
-
-/* For tools needing more control over stack traces:  walks the stack to get
-   instruction pointers from the top stack frames for thread 'tid'.  Maximum of
-   'n_ips' addresses put into 'ips';  0 is the top of the stack, 1 is its
-   caller, etc. */
-extern UInt VG_(stack_snapshot) ( ThreadId tid, Addr* ips, UInt n_ips );
-
-/*====================================================================*/
 /*=== Error reporting                                              ===*/
 /*====================================================================*/
 
@@ -686,7 +635,7 @@
    seen before.  If it has, the existing error record will have its count
    incremented.
 
-   'tid' can be found as for VG_(get_ExeContext)().  The `extra' field can
+   'tid' can be found as for VG_(record_ExeContext)().  The `extra' field can
    be stack-allocated;  it will be copied by the core if needed (but it
    won't be copied if it's NULL).
 
@@ -755,7 +704,7 @@
 
    'n_buf' gives length of 'buf'.  Returns 'buf'.
 */
-extern Char* VG_(describe_eip)(Addr eip, Char* buf, Int n_buf);
+extern Char* VG_(describe_IP)(Addr eip, Char* buf, Int n_buf);
 
 /* Returns a string containing an expression for the given
    address. String is malloced with VG_(malloc)() */
diff --git a/massif/ms_main.c b/massif/ms_main.c
index 1576b5f..019f4ae 100644
--- a/massif/ms_main.c
+++ b/massif/ms_main.c
@@ -35,6 +35,7 @@
 // structures below for more info on how things work.
 
 #include "tool.h"
+#include "pub_tool_stacktrace.h"
 //#include "vg_profile.c"
 
 #include "valgrind.h"           // For {MALLOC,FREE}LIKE_BLOCK
@@ -90,7 +91,7 @@
 typedef struct _XPt XPt;
 
 struct _XPt {
-   Addr  eip;              // code address
+   Addr  ip;              // code address
 
    // Bottom-XPts: space for the precise context.
    // Other XPts:  space of all the descendent bottom-XPts.
@@ -362,10 +363,10 @@
 
 
 
-static XPt* new_XPt(Addr eip, XPt* parent, Bool is_bottom)
+static XPt* new_XPt(Addr ip, XPt* parent, Bool is_bottom)
 {
    XPt* xpt          = perm_malloc(sizeof(XPt));
-   xpt->eip          = eip;
+   xpt->ip           = ip;
 
    xpt->curr_space    = 0;
    xpt->approx_ST     = 0;
@@ -396,11 +397,11 @@
    return xpt;
 }
 
-static Bool is_alloc_fn(Addr eip)
+static Bool is_alloc_fn(Addr ip)
 {
    Int i;
 
-   if ( VG_(get_fnname)(eip, buf, BUF_LEN) ) {
+   if ( VG_(get_fnname)(ip, buf, BUF_LEN) ) {
       for (i = 0; i < n_alloc_fns; i++) {
          if (VG_STREQ(buf, alloc_fns[i]))
             return True;
@@ -414,11 +415,11 @@
 // to ensure this in certain cases.  See comments below.
 static XPt* get_XCon( ThreadId tid, Bool custom_malloc )
 {
-   // Static to minimise stack size.  +1 for added ~0 %eip.
-   static Addr eips[MAX_DEPTH + MAX_ALLOC_FNS + 1];
+   // Static to minimise stack size.  +1 for added ~0 IP
+   static Addr ips[MAX_DEPTH + MAX_ALLOC_FNS + 1];
 
    XPt* xpt = alloc_xpt;
-   UInt n_eips, L, A, B, nC;
+   UInt n_ips, L, A, B, nC;
    UInt overestimate;
    Bool reached_bottom;
 
@@ -431,25 +432,25 @@
    // it is enough.
    overestimate = 2;
    while (True) {
-      n_eips = VG_(stack_snapshot)( tid, eips, clo_depth + overestimate );
+      n_ips = VG_(get_StackTrace)( tid, ips, clo_depth + overestimate );
 
-      // Now we add a dummy "unknown" %eip at the end.  This is only used if we
-      // run out of %eips before hitting clo_depth.  It's done to ensure the
+      // Now we add a dummy "unknown" IP at the end.  This is only used if we
+      // run out of IPs before hitting clo_depth.  It's done to ensure the
       // XPt we return is (now and forever) a bottom-XPt.  If the returned XPt
       // wasn't a bottom-XPt (now or later) it would cause problems later (eg.
       // the parent's approx_ST wouldn't be equal [or almost equal] to the
       // total of the childrens' approx_STs).  
-      eips[ n_eips++ ] = ~((Addr)0);
+      ips[ n_ips++ ] = ~((Addr)0);
 
-      // Skip over alloc functions in eips[]. 
-      for (L = 0; is_alloc_fn(eips[L]) && L < n_eips; L++) { }
+      // Skip over alloc functions in ips[]. 
+      for (L = 0; is_alloc_fn(ips[L]) && L < n_ips; L++) { }
 
       // Must be at least one alloc function, unless client used
       // MALLOCLIKE_BLOCK
       if (!custom_malloc) tl_assert(L > 0);    
 
       // Should be at least one non-alloc function.  If not, try again.
-      if (L == n_eips) {
+      if (L == n_ips) {
          overestimate += 2;
          if (overestimate > MAX_ALLOC_FNS)
             VG_(tool_panic)("No stk snapshot big enough to find non-alloc fns");
@@ -458,15 +459,15 @@
       }
    }
    A = L;
-   B = n_eips - 1;
+   B = n_ips - 1;
    reached_bottom = False;
 
-   // By this point, the eips we care about are in eips[A]..eips[B]
+   // By this point, the IPs we care about are in ips[A]..ips[B]
 
    // Now do the search/insertion of the XCon. 'L' is the loop counter,
-   // being the index into eips[].
+   // being the index into ips[].
    while (True) {
-      // Look for %eip in xpt's children.
+      // Look for IP in xpt's children.
       // XXX: linear search, ugh -- about 10% of time for konqueror startup
       // XXX: tried cacheing last result, only hit about 4% for konqueror
       // Nb:  this search hits about 98% of the time for konqueror
@@ -490,12 +491,12 @@
                                              xpt->max_children * sizeof(XPt*) );
                n_children_reallocs++;
             }
-            // Make new XPt for %eip, insert in list
+            // Make new XPt for IP, insert in list
             xpt->children[ xpt->n_children++ ] = 
-               new_XPt(eips[L], xpt, reached_bottom);
+               new_XPt(ips[L], xpt, reached_bottom);
             break;
          }
-         if (eips[L] == xpt->children[nC]->eip) break;   // found the %eip
+         if (ips[L] == xpt->children[nC]->ip) break;   // found the IP
          nC++;                                           // keep looking
       }
       VGP_POPCC(VgpGetXPtSearch);
@@ -1430,10 +1431,10 @@
          for (j = 0; NULL != census->xtree_snapshots[j]; j++) {
             // Grab the jth top-XPt
             XTreeSnapshot xtree_snapshot = & census->xtree_snapshots[j][0];
-            if ( ! VG_(get_fnname)(xtree_snapshot->xpt->eip, buf2, 16)) {
+            if ( ! VG_(get_fnname)(xtree_snapshot->xpt->ip, buf2, 16)) {
                VG_(sprintf)(buf2, "???");
             }
-            SPRINTF(buf, "x%x:%s %d\n", xtree_snapshot->xpt->eip,
+            SPRINTF(buf, "x%x:%s %d\n", xtree_snapshot->xpt->ip,
                          clean_fnname(buf3, buf2), xtree_snapshot->space);
          }
 
@@ -1512,11 +1513,11 @@
    return mbuf;
 }
 
-// Nb: passed in XPt is a lower-level XPt;  %eips are grabbed from
+// Nb: passed in XPt is a lower-level XPt;  IPs are grabbed from
 // bottom-to-top of XCon, and then printed in the reverse order.
 static UInt pp_XCon(Int fd, XPt* xpt)
 {
-   Addr  rev_eips[clo_depth+1];
+   Addr  rev_ips[clo_depth+1];
    Int   i = 0;
    Int   n = 0;
    Bool  is_HTML      = ( XHTML == clo_format );
@@ -1526,7 +1527,7 @@
    tl_assert(NULL != xpt);
 
    while (True) {
-      rev_eips[i] = xpt->eip;
+      rev_ips[i] = xpt->ip;
       n++;
       if (alloc_xpt == xpt->parent) break;
       i++;
@@ -1535,7 +1536,7 @@
 
    for (i = n-1; i >= 0; i--) {
       // -1 means point to calling line
-      VG_(describe_eip)(rev_eips[i]-1, buf2, BUF_LEN);
+      VG_(describe_IP)(rev_ips[i]-1, buf2, BUF_LEN);
       SPRINTF(buf, "  %s%s%s\n", maybe_indent, buf2, maybe_br);
    }
 
@@ -1543,7 +1544,7 @@
 }
 
 // Important point:  for HTML, each XPt must be identified uniquely for the
-// HTML links to all match up correctly.  Using xpt->eip is not
+// HTML links to all match up correctly.  Using xpt->ip is not
 // sufficient, because function pointers mean that you can call more than
 // one other function from a single code location.  So instead we use the
 // address of the xpt struct itself, which is guaranteed to be unique.
@@ -1558,7 +1559,7 @@
    UInt  c2  = 0;
    ULong sum = 0;
    UInt  n;
-   Char *eip_desc, *perc;
+   Char *ip_desc, *perc;
    Bool  is_HTML   = ( XHTML == clo_format );
    Char* maybe_br  = ( is_HTML ?  "<br>" : "" );
    Char* maybe_p   = ( is_HTML ?   "<p>" : "" );
@@ -1642,8 +1643,8 @@
          }
 
          // Remember: exact_ST_dbld is space.time *doubled*
-         perc     = make_perc(child->exact_ST_dbld / 2, total_spacetime);
-         eip_desc = VG_(describe_eip)(child->eip-1, buf2, BUF_LEN);
+         perc    = make_perc(child->exact_ST_dbld / 2, total_spacetime);
+         ip_desc = VG_(describe_IP)(child->ip-1, buf2, BUF_LEN);
          if (is_HTML) {
             SPRINTF(buf, "<li><a name=\"a%x\"></a>", child );
 
@@ -1652,9 +1653,9 @@
             } else {
                SPRINTF(buf, "%s", perc);
             }
-            SPRINTF(buf, ": %s\n", eip_desc);
+            SPRINTF(buf, ": %s\n", ip_desc);
          } else {
-            SPRINTF(buf, "  %6s: %s\n\n", perc, eip_desc);
+            SPRINTF(buf, "  %6s: %s\n\n", perc, ip_desc);
          }
 
          if (child->n_children > 0) {
diff --git a/memcheck/mac_malloc_wrappers.c b/memcheck/mac_malloc_wrappers.c
index 7250353..5510a06 100644
--- a/memcheck/mac_malloc_wrappers.c
+++ b/memcheck/mac_malloc_wrappers.c
@@ -141,7 +141,7 @@
    mc->data      = p;
    mc->size      = size;
    mc->allockind = kind;
-   mc->where     = VG_(get_ExeContext)(tid);
+   mc->where     = VG_(record_ExeContext)(tid);
 
    /* Paranoia ... ensure this area is off-limits to the client, so
       the mc->data field isn't visible to the leak checker.  If memory
@@ -290,7 +290,7 @@
    /* Put it out of harm's way for a while, if not from a client request */
    if (MAC_AllocCustom != mc->allockind) {
       /* Record where freed */
-      mc->where = VG_(get_ExeContext) ( tid );
+      mc->where = VG_(record_ExeContext) ( tid );
       add_to_freed_queue ( mc );
    } else
       VG_(free) ( mc );
@@ -376,7 +376,7 @@
 
    if (mc->size == new_size) {
       /* size unchanged */
-      mc->where = VG_(get_ExeContext)(tid);
+      mc->where = VG_(record_ExeContext)(tid);
       VGP_POPCC(VgpCliMalloc);
       return p;
       
@@ -384,7 +384,7 @@
       /* new size is smaller */
       MAC_(die_mem_heap)( mc->data+new_size, mc->size-new_size );
       mc->size = new_size;
-      mc->where = VG_(get_ExeContext)(tid);
+      mc->where = VG_(record_ExeContext)(tid);
       VGP_POPCC(VgpCliMalloc);
       return p;
 
diff --git a/memcheck/mc_main.c b/memcheck/mc_main.c
index f5d6c32..4654251 100644
--- a/memcheck/mc_main.c
+++ b/memcheck/mc_main.c
@@ -1808,7 +1808,7 @@
 	    vg_cgbs[i].start = arg[1];
 	    vg_cgbs[i].size  = arg[2];
 	    vg_cgbs[i].desc  = VG_(strdup)((Char *)arg[3]);
-	    vg_cgbs[i].where = VG_(get_ExeContext) ( tid );
+	    vg_cgbs[i].where = VG_(record_ExeContext) ( tid );
 
 	    *ret = i;
 	 } else