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/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                                                          ---*/
+/*--------------------------------------------------------------------*/