diff --git a/coregrind/Makefile.am b/coregrind/Makefile.am index be3d5da25..df822acb5 100644 --- a/coregrind/Makefile.am +++ b/coregrind/Makefile.am @@ -27,6 +27,8 @@ noinst_LIBRARIES = lib_replace_malloc.a 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_LDFLAGS=-static -g 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 25be87101..481d4f7cd 100644 --- a/coregrind/core.h +++ b/coregrind/core.h @@ -93,6 +93,8 @@ typedef struct _ThreadState ThreadState; // 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 @@ extern void VG_(core_assert_fail) ( const Char* expr, const Char* file, __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); @@ -866,31 +868,6 @@ Bool VG_(translate) ( ThreadId tid, Bool debugging_translation, 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/vg_execontext.c b/coregrind/execontext.c similarity index 50% rename from coregrind/vg_execontext.c rename to coregrind/execontext.c index 8683055e0..5de1dbe92 100644 --- a/coregrind/vg_execontext.c +++ b/coregrind/execontext.c @@ -1,7 +1,5 @@ - /*--------------------------------------------------------------------*/ -/*--- Storage, and equality on, execution contexts (backtraces). ---*/ -/*--- vg_execontext.c ---*/ +/*--- execontext.c ---*/ /*--------------------------------------------------------------------*/ /* @@ -30,12 +28,24 @@ */ #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 */ @@ -109,19 +119,10 @@ void VG_(print_ExeContext_stats) ( void ) } -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) ); + VG_(pp_StackTrace)( ec->ips, VG_(clo_backtrace_size) ); } @@ -134,8 +135,10 @@ Bool VG_(eq_ExeContext) ( VgRes res, ExeContext* e1, ExeContext* e2 ) 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; + 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: @@ -164,116 +167,6 @@ Bool VG_(eq_ExeContext) ( VgRes res, ExeContext* e1, ExeContext* e2 ) } } - -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 @@ -283,8 +176,7 @@ static UInt stack_snapshot2 ( Addr* ips, UInt n_ips, Addr ip, Addr fp, 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 ) +ExeContext* VG_(record_ExeContext) ( ThreadId tid ) { Int i; Addr ips[VG_DEEPEST_BACKTRACE]; @@ -299,8 +191,7 @@ ExeContext* VG_(get_ExeContext2) ( Addr ip, Addr fp, 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 ); + 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. */ @@ -355,56 +246,10 @@ ExeContext* VG_(get_ExeContext2) ( Addr ip, Addr fp, 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); -} +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 000000000..119adb41e --- /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 000000000..61c6e632e --- /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 000000000..692a035d9 --- /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 ce555500a..a28e34ed2 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 @@ void construct_error ( Error* err, ThreadId tid, ErrorKind ekind, Addr a, 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 @@ static void gen_suppression(Error* err) } // 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 @@ void VG_(show_all_errors) ( void ) 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 @@ Bool supp_matches_callers(Error* err, Supp* su) { 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_main.c b/coregrind/vg_main.c index eaef6d2b7..15962ceaf 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 #include diff --git a/coregrind/vg_mylibc.c b/coregrind/vg_mylibc.c index 4cd55f93b..3f261fd81 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 @@ Bool VG_(string_match) ( const Char* pat, const Char* str ) 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 @@ static inline ExeContext *get_real_execontext(Addr ret) 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 @@ void VG_(core_assert_fail) ( const Char* expr, const Char* file, Int line, const } __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 @@ void VG_(core_panic) ( Char* str ) 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 e316eb4cc..66eba3665 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 @@ void VG_(pp_sched_status) ( void ) 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 @@ VgSchedReturnCode VG_(scheduler) ( ThreadId tid ) 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 @@ void do_client_request ( ThreadId tid ) 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 6774b399f..8e814d735 100644 --- a/coregrind/vg_signals.c +++ b/coregrind/vg_signals.c @@ -1373,8 +1373,7 @@ static void vg_default_action(const vki_siginfo_t *info, ThreadId tid) } 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 @@ void vg_sync_signalhandler ( Int sigNo, vki_siginfo_t *info, struct vki_ucontext 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 @@ void vg_sync_signalhandler ( Int sigNo, vki_siginfo_t *info, struct vki_ucontext 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 9cb2a123a..1ec15ae01 100644 --- a/coregrind/vg_symtab2.c +++ b/coregrind/vg_symtab2.c @@ -2170,7 +2170,7 @@ Variable *VG_(get_scope_variables)(ThreadId tid) #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 14e4c9700..b0b1c756d 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 @@ Bool VG_(valid_client_addr)(Addr start, SizeT size, ThreadId tid, 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 @@ void VG_(record_fd_open)(ThreadId tid, Int fd, char *pathname) 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 @@ Bool VG_(fd_allowed)(Int fd, const Char *syscallname, ThreadId tid, Bool soft) VG_(message)(Vg_UserMsg, " Use --log-fd= 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 @@ static void bad_before(ThreadId tid, ThreadState *tst) 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 37209b03e..a1bec5d83 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 bf9a9d479..3013aeb17 100644 --- a/helgrind/hg_main.c +++ b/helgrind/hg_main.c @@ -1571,7 +1571,7 @@ static void set_mutex_state(Mutex *mutex, MutexState state, ThreadId tid) break; } - mutex->location = VG_(get_ExeContext)(tid); + mutex->location = VG_(record_ExeContext)(tid); mutex->state = state; } @@ -1818,7 +1818,7 @@ static void add_HG_Chunk ( ThreadId tid, Addr p, SizeT size ) 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 @@ void die_and_free_mem ( ThreadId tid, HG_Chunk* hc, *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 @@ void* TL_(realloc) ( ThreadId tid, void* p, SizeT new_size ) 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 @@ static void eraser_mem_read_word(Addr a, ThreadId tid) 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 @@ static void eraser_mem_write_word(Addr a, ThreadId tid) 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 e9bafffd2..d41672a12 100644 --- a/include/Makefile.am +++ b/include/Makefile.am @@ -10,9 +10,11 @@ EXTRA_DIST = \ 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 cbf15941d..728c36763 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 SSizeT; // 32 64 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 000000000..9e3386950 --- /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 000000000..f74a1b109 --- /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 2ef0f8e3e..14d9fe61e 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 @@ extern ULong VG_(bbs_done); 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 ); @@ -570,53 +566,6 @@ extern void VG_(cpuid) ( UInt eax, UInt *eax_ret, UInt *ebx_ret, 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 @@ void* VG_(get_error_extra) ( Error* err ); 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 @@ extern Bool VG_(get_objname) ( Addr a, Char* objname, Int n_objname ); '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 1576b5fe6..019f4ae38 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 void* perm_malloc(SizeT n_bytes) -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 @@ static XPt* new_XPt(Addr eip, XPt* parent, Bool is_bottom) 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 @@ static Bool is_alloc_fn(Addr eip) // 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 @@ static XPt* get_XCon( ThreadId tid, Bool custom_malloc ) // 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 @@ static XPt* get_XCon( ThreadId tid, Bool custom_malloc ) } } 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 @@ static XPt* get_XCon( ThreadId tid, Bool custom_malloc ) 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 @@ static void write_hp_file(void) 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 @@ static Char* make_perc(ULong spacetime, ULong total_spacetime) 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 @@ static UInt pp_XCon(Int fd, XPt* xpt) 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 @@ static UInt pp_XCon(Int fd, XPt* xpt) 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 @@ static UInt pp_XCon(Int fd, XPt* xpt) } // 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 @@ static void pp_all_XPts2(Int fd, Queue* q, ULong heap_spacetime, 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 ? "
" : "" ); Char* maybe_p = ( is_HTML ? "

" : "" ); @@ -1642,8 +1643,8 @@ static void pp_all_XPts2(Int fd, Queue* q, ULong heap_spacetime, } // 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, "

  • ", child ); @@ -1652,9 +1653,9 @@ static void pp_all_XPts2(Int fd, Queue* q, ULong heap_spacetime, } 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 725035394..5510a06ff 100644 --- a/memcheck/mac_malloc_wrappers.c +++ b/memcheck/mac_malloc_wrappers.c @@ -141,7 +141,7 @@ void add_MAC_Chunk ( ThreadId tid, 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 @@ void die_and_free_mem ( ThreadId tid, /* 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 @@ void* TL_(realloc) ( ThreadId tid, void* p, SizeT new_size ) 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 @@ void* TL_(realloc) ( ThreadId tid, void* p, SizeT new_size ) /* 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 f5d6c3239..465425101 100644 --- a/memcheck/mc_main.c +++ b/memcheck/mc_main.c @@ -1808,7 +1808,7 @@ Bool TL_(handle_client_request) ( ThreadId tid, UWord* arg, UWord* ret ) 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