]> git.ipfire.org Git - thirdparty/valgrind.git/commitdiff
Added some skin-visible functions that give skins a bit more control over
authorNicholas Nethercote <njn@valgrind.org>
Tue, 16 Sep 2003 07:41:43 +0000 (07:41 +0000)
committerNicholas Nethercote <njn@valgrind.org>
Tue, 16 Sep 2003 07:41:43 +0000 (07:41 +0000)
how stack snapshots are taken and printed;  they can be used in preference
to VG_(get_ExeContext)() and VG_(pp_ExeContext)().  These are used by
Massif, my heap profiling skin.

Changed --num-callers to allow a backtrace size of 1.

Added code so that when Valgrind fails to disassemble an instruction, the
instructions line/file and address are printed out, which makes it easier to
work out where and what it is.  Required the stack snapshot changes above.

MERGE TO STABLE?

git-svn-id: svn://svn.valgrind.org/valgrind/trunk@1819

coregrind/vg_execontext.c
coregrind/vg_include.h
coregrind/vg_main.c
coregrind/vg_symtab2.c
coregrind/vg_to_ucode.c
include/vg_skin.h

index 380ae5bd5d970927cee775278d2b1fb308fb7b69..e464e39e465861a8a6ef4881c73e0727b55b3250 100644 (file)
@@ -109,7 +109,7 @@ void VG_(show_ExeContext_stats) ( void )
 void VG_(pp_ExeContext) ( ExeContext* e )
 {
    init_ExeContext_storage();
-   VG_(mini_stack_dump) ( e );
+   VG_(mini_stack_dump) ( e->eips, VG_(clo_backtrace_size) );
 }
 
 
@@ -129,8 +129,10 @@ Bool VG_(eq_ExeContext) ( VgRes res, ExeContext* e1, ExeContext* e2 )
    case Vg_MedRes:
       /* Just compare the top four callers. */
       vg_ec_cmp4s++;
-      if (e1->eips[0] != e2->eips[0]
-          || e1->eips[1] != e2->eips[1]) return False;
+      if (e1->eips[0] != e2->eips[0]) return False;
+
+      if (VG_(clo_backtrace_size) < 2) return True;
+      if (e1->eips[1] != e2->eips[1]) return False;
 
       if (VG_(clo_backtrace_size) < 3) return True;
       if (e1->eips[2] != e2->eips[2]) return False;
@@ -151,38 +153,22 @@ Bool VG_(eq_ExeContext) ( VgRes res, ExeContext* e1, ExeContext* e2 )
 }
 
 
-/* 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.  
-
-   In order to be thread-safe, we pass in the thread's %EIP and %EBP.
-*/
-ExeContext* VG_(get_ExeContext2) ( Addr eip, Addr ebp,
-                                   Addr ebp_min, Addr ebp_max_orig )
+/* Take a snapshot of the client's stack, putting the up to 'n_eips' %eips
+   into 'eips'.  In order to be thread-safe, we pass in the thread's %EIP
+   and %EBP.  Returns number of %eips put in 'eips'.  */
+static UInt stack_snapshot2 ( Addr* eips, UInt n_eips, Addr eip, Addr ebp,
+                              Addr ebp_min, Addr ebp_max_orig )
 {
    Int         i;
-   Addr        eips[VG_DEEPEST_BACKTRACE];
    Addr        ebp_max;
-   Bool        same;
-   UInt        hash;
-   ExeContext* new_ec;
-   ExeContext* list;
+   UInt        n_found = 0;
 
    VGP_PUSHCC(VgpExeContext);
 
-   init_ExeContext_storage();
-   vg_assert(VG_(clo_backtrace_size) >= 2 
-             && VG_(clo_backtrace_size) <= VG_DEEPEST_BACKTRACE);
-
-   /* First snaffle %EIPs from the client's stack into eips[0
-      .. VG_(clo_backtrace_size)-1], putting zeroes in when the trail
-      goes cold, which we guess to be when %ebp is not a reasonable
-      stack location.  We also assert that %ebp increases down the chain. */
+   /* First snaffle %EIPs from the client's stack into eips[0 .. n_eips-1], 
+      putting zeroes in when the trail goes cold, which we guess to be when
+      %ebp is not a reasonable stack location.  We also assert that %ebp
+      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
@@ -209,7 +195,7 @@ ExeContext* VG_(get_ExeContext2) ( Addr eip, Addr ebp,
    } else {
       /* Get whatever we safely can ... */
       eips[0] = eip;
-      for (i = 1; i < VG_(clo_backtrace_size); i++) {
+      for (i = 1; i < n_eips; i++) {
          if (!(ebp_min <= ebp && ebp <= ebp_max)) {
             //VG_(printf)("... out of range %p\n", ebp);
             break; /* ebp gone baaaad */
@@ -224,11 +210,44 @@ ExeContext* VG_(get_ExeContext2) ( Addr eip, Addr ebp,
          //VG_(printf)("     %p\n", eips[i]);
       }
    }
+   n_found = i;
 
    /* Put zeroes in the rest. */
-   for (;  i < VG_(clo_backtrace_size); i++) {
+   for (;  i < n_eips; i++) {
       eips[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 eip, Addr ebp,
+                                   Addr ebp_min, Addr ebp_max_orig )
+{
+   Int         i;
+   Addr        eips[VG_DEEPEST_BACKTRACE];
+   Bool        same;
+   UInt        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( eips, VG_(clo_backtrace_size),
+                    eip, ebp, ebp_min, ebp_max_orig );
 
    /* Now figure out if we've seen this one before.  First hash it so
       as to determine the list number. */
@@ -283,23 +302,50 @@ ExeContext* VG_(get_ExeContext2) ( Addr eip, Addr ebp,
    return new_ec;
 }
 
-ExeContext* VG_(get_ExeContext) ( ThreadId tid )
+void get_needed_regs(ThreadId tid, Addr* eip, Addr* ebp, Addr* esp,
+                     Addr* stack_highest_word)
 {
-   ExeContext *ec;
-
    if (VG_(is_running_thread)(tid)) {
       /* thread currently in baseblock */
-      ec = VG_(get_ExeContext2)( VG_(baseBlock)[VGOFF_(m_eip)], 
-                                VG_(baseBlock)[VGOFF_(m_ebp)],
-                                VG_(baseBlock)[VGOFF_(m_esp)],
-                                VG_(threads)[tid].stack_highest_word);
+      *eip                = VG_(baseBlock)[VGOFF_(m_eip)];
+      *ebp                = VG_(baseBlock)[VGOFF_(m_ebp)];
+      *esp                = VG_(baseBlock)[VGOFF_(m_esp)];
+      *stack_highest_word = VG_(threads)[tid].stack_highest_word;
    } else {
       /* thread in thread table */
       ThreadState* tst = & VG_(threads)[ tid ];
-      ec = VG_(get_ExeContext2)( tst->m_eip, tst->m_ebp, tst->m_esp, 
-                                tst->stack_highest_word );
+      *eip                = tst->m_eip;
+      *ebp                = tst->m_ebp;
+      *esp                = tst->m_esp; 
+      *stack_highest_word = tst->stack_highest_word;
    }
-   return ec;
+}
+
+ExeContext* VG_(get_ExeContext) ( ThreadId tid )
+{
+   Addr eip, ebp, esp, stack_highest_word;
+
+   get_needed_regs(tid, &eip, &ebp, &esp, &stack_highest_word);
+   return VG_(get_ExeContext2)(eip, ebp, esp, stack_highest_word);
+}
+
+/* Take a snapshot of the client's stack, putting the up to 'n_eips' %eips
+   into 'eips'.  In order to be thread-safe, we pass in the thread's %EIP
+   and %EBP.  Returns number of %eips put in 'eips'.  */
+UInt VG_(stack_snapshot) ( ThreadId tid, Addr* eips, UInt n_eips )
+{
+   Addr eip, ebp, esp, stack_highest_word;
+
+   get_needed_regs(tid, &eip, &ebp, &esp, &stack_highest_word);
+   return stack_snapshot2(eips, n_eips, 
+                          eip, ebp, esp, stack_highest_word);
+}
+
+
+Addr VG_(get_EIP_from_ExeContext) ( ExeContext* e, UInt n )
+{
+   if (n > VG_(clo_backtrace_size)) return 0;
+   return e->eips[n];
 }
 
 Addr VG_(get_EIP) ( ThreadId tid )
index 5a88782bb722060bde94369464fbb0a1428e20e4..59cb97c83dcb7e2cce806b8d45a25ed25b69006a 100644 (file)
@@ -732,7 +732,7 @@ typedef
    void* /*pthread_cond_t* */ associated_cv;
 
    /* If VgTs_Sleeping, this is when we should wake up, measured in
-      milliseconds as supplied by VG_(read_millisecond_counter). 
+      milliseconds as supplied by VG_(read_millisecond_timer). 
 
       If VgTs_WaitCV, this indicates the time at which
       pthread_cond_timedwait should wake up.  If == 0xFFFFFFFF,
@@ -1145,7 +1145,7 @@ extern Bool  VG_(saneUCodeBlockCalls) ( UCodeBlock* cb );
 struct _ExeContext {
    struct _ExeContext * next;
    /* Variable-length array.  The size is VG_(clo_backtrace_size); at
-      least 2, at most VG_DEEPEST_BACKTRACE.  [0] is the current %eip,
+      least 1, at most VG_DEEPEST_BACKTRACE.  [0] is the current %eip,
       [1] is its caller, [2] is the caller of [1], etc. */
    Addr eips[0];
 };
@@ -1282,7 +1282,6 @@ extern void VG_(read_symtab_callback) ( Addr start, UInt size,
 extern void VG_(unload_symbols)       ( Addr start, UInt length );
 
 extern Bool VG_(get_fnname_nodemangle)( Addr a, Char* fnname, Int n_fnname );
-extern void VG_(mini_stack_dump)      ( ExeContext* ec );
 extern Int  VG_(setup_code_redirect_table) ( void );
 
 typedef
index a79f8bb1af5d870d3feaffa72ae5b49ec99d81db..ae48ed8a8104c8259ff655f89450f8d515598e7e 100644 (file)
@@ -1059,8 +1059,8 @@ static void process_cmd_line_options ( void )
       else if (VG_CLO_STREQN(14, argv[i], "--num-callers=")) {
          /* Make sure it's sane. */
         VG_(clo_backtrace_size) = (Int)VG_(atoll)(&argv[i][14]);
-         if (VG_(clo_backtrace_size) < 2)
-            VG_(clo_backtrace_size) = 2;
+         if (VG_(clo_backtrace_size) < 1)
+            VG_(clo_backtrace_size) = 1;
          if (VG_(clo_backtrace_size) >= VG_DEEPEST_BACKTRACE)
             VG_(clo_backtrace_size) = VG_DEEPEST_BACKTRACE;
       }
index 329434d70377645a07599f5437ea59766325db3e..e9ce97714555aa23b514c8db044c9fa94d8c595d 100644 (file)
@@ -1857,7 +1857,6 @@ Bool vg_read_lib_symbols ( SegInfo* si )
 */
 static SegInfo* segInfo = NULL;
 
-
 void VG_(read_symtab_callback) ( 
         Addr start, UInt size, 
         Char rr, Char ww, Char xx, 
@@ -2285,78 +2284,81 @@ Bool VG_(get_filename_linenum)( Addr a,
    return True;
 }
 
-
-/* Print a mini stack dump, showing the current location. */
-void VG_(mini_stack_dump) ( ExeContext* ec )
+/* Print into buf info on code address, function name and filename */
+Char* VG_(describe_eip)(Addr eip, Char* buf, Int n_buf)
 {
-
-#define APPEND(str)                                              \
-   { UChar* sss;                                                 \
-     for (sss = str; n < M_VG_ERRTXT-1 && *sss != 0; n++,sss++)  \
-        buf[n] = *sss;                                           \
-     buf[n] = 0;                                                 \
+#define APPEND(str)                                         \
+   { UChar* sss;                                            \
+     for (sss = str; n < n_buf-1 && *sss != 0; n++,sss++)   \
+        buf[n] = *sss;                                      \
+     buf[n] = '\0';                                         \
    }
-
    Bool   know_fnname;
    Bool   know_objname;
    Bool   know_srcloc;
-   UInt   lineno; 
-   UChar  ibuf[20];
-   UInt   i, n;
-
-   UChar  buf[M_VG_ERRTXT];
    UChar  buf_fn[M_VG_ERRTXT];
    UChar  buf_obj[M_VG_ERRTXT];
    UChar  buf_srcloc[M_VG_ERRTXT];
+   UInt   lineno; 
+   UChar  ibuf[20];
+   UInt   n = 0;
+
+   know_fnname  = VG_(get_fnname) (eip, buf_fn,  M_VG_ERRTXT);
+   know_objname = VG_(get_objname)(eip, buf_obj, M_VG_ERRTXT);
+   know_srcloc  = VG_(get_filename_linenum)(eip, buf_srcloc, M_VG_ERRTXT, 
+                                            &lineno);
+   VG_(sprintf)(ibuf,"0x%x: ", eip);
+   APPEND(ibuf);
+   if (know_fnname) { 
+      APPEND(buf_fn);
+      if (!know_srcloc && know_objname) {
+         APPEND(" (in ");
+         APPEND(buf_obj);
+         APPEND(")");
+      }
+   } else if (know_objname && !know_srcloc) {
+      APPEND("(within ");
+      APPEND(buf_obj);
+      APPEND(")");
+   } else {
+      APPEND("???");
+   }
+   if (know_srcloc) {
+      APPEND(" (");
+      APPEND(buf_srcloc);
+      APPEND(":");
+      VG_(sprintf)(ibuf,"%d",lineno);
+      APPEND(ibuf);
+      APPEND(")");
+   }
+   return buf;
 
-   Int stop_at = VG_(clo_backtrace_size);
+#undef APPEND
+}
+
+/* Print a mini stack dump, showing the current location. */
+void VG_(mini_stack_dump) ( Addr eips[], UInt n_eips )
+{
+   UInt  i;
+   UChar buf[M_VG_ERRTXT];
+   Char* how;
+
+   Int stop_at = n_eips;
 
    vg_assert(stop_at > 0);
 
    i = 0;
    do {
-      Addr eip = ec->eips[i];
-      n = 0;
-      if (i > 0)
-        eip--;                 /* point to calling line */
-      know_fnname  = VG_(get_fnname) (eip, buf_fn,  M_VG_ERRTXT);
-      know_objname = VG_(get_objname)(eip, buf_obj, M_VG_ERRTXT);
-      know_srcloc  = VG_(get_filename_linenum)(eip, buf_srcloc, M_VG_ERRTXT, 
-                                               &lineno);
-      if (i == 0) APPEND("   at ") else APPEND("   by ");
-      
-      VG_(sprintf)(ibuf,"0x%x: ", eip);
-      APPEND(ibuf);
-      if (know_fnname) { 
-         APPEND(buf_fn);
-         if (!know_srcloc && know_objname) {
-            APPEND(" (in ");
-            APPEND(buf_obj);
-            APPEND(")");
-         }
-      } else if (know_objname && !know_srcloc) {
-         APPEND("(within ");
-         APPEND(buf_obj);
-         APPEND(")");
-      } else {
-         APPEND("???");
-      }
-      if (know_srcloc) {
-         APPEND(" (");
-         APPEND(buf_srcloc);
-         APPEND(":");
-         VG_(sprintf)(ibuf,"%d",lineno);
-         APPEND(ibuf);
-         APPEND(")");
-      }
-      VG_(message)(Vg_UserMsg, "%s", buf);
+      Addr eip = eips[i];
+      if (i  > 0) eip--;            /* point to calling line */
+      if (i == 0) how = "at"; else how = "by";
+      VG_(describe_eip)(eip, buf, M_VG_ERRTXT);
+      VG_(message)(Vg_UserMsg, "   %s %s", how, buf);
       i++;
 
-   } while (i < (UInt)stop_at && ec->eips[i] != 0);
+   } while (i < (UInt)stop_at && eips[i] != 0);
 }
 
-#undef APPEND
-
 
 /*------------------------------------------------------------*/
 /*--- Find interesting glibc entry points.                 ---*/
index cbe76d25cfde45c0fddc0d6b913be6b9aed0fcb9..b814af49b03e33a75f5045d8295d9e6dd68c2208 100644 (file)
@@ -3578,6 +3578,7 @@ static Addr disInstr ( UCodeBlock* cb, Addr eip, Bool* isEnd )
    Int   t1, t2, t3, t4;
    UChar dis_buf[50];
    Int   am_sz, d_sz;
+   Char  loc_buf[M_VG_ERRTXT];
 
    /* Holds eip at the start of the insn, so that we can print
       consistent error messages for unimplemented insns. */
@@ -6266,6 +6267,10 @@ static Addr disInstr ( UCodeBlock* cb, Addr eip, Bool* isEnd )
                (Int)eip_start[2],
                (Int)eip_start[3] );
 
+   /* Print address of failing instruction. */
+   VG_(describe_eip)(eip, loc_buf, M_VG_ERRTXT);
+   VG_(printf)("          at %s\n", loc_buf);
+
    uInstr0(cb, CALLM_S, 0);
    uInstr1(cb, CALLM,   0, Lit16, 
                VGOFF_(helper_undefined_instruction));
index 2eb100a4bec11abaf30a235166cbd3aa0f5cb975..2dc221ace210b07b251723b19c969c7d7ffa85f3 100644 (file)
@@ -1253,7 +1253,8 @@ 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. 
+   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_current_tid)() to get the
    current ThreadId.  If called from non-generated code, the current
@@ -1261,12 +1262,27 @@ extern void VG_(pp_ExeContext) ( ExeContext* );
 */
 extern ExeContext* VG_(get_ExeContext) ( ThreadId tid );
 
+/* Get the nth EIP from the ExeContext.  0 is the EIP of the top function, 1
+   is its caller, etc.  Returns 0 if there isn't one, or if n is greater
+   than VG_(clo_backtrace_size), set by the --num-callers option. */
+extern Addr VG_(get_EIP_from_ExeContext) ( ExeContext* e, UInt n );
+
 /* Just grab the client's EIP, as a much smaller and cheaper
    indication of where they are.  Use is basically same as for
    VG_(get_ExeContext)() above. 
 */
 extern Addr VG_(get_EIP)( ThreadId tid );
 
+/* For skins needing more control over stack traces:  walks the stack to get
+   %eips from the top stack frames for thread 'tid'.  Maximum of 'n_eips'
+   addresses put into 'eips';  0 is the top of the stack, 1 is its caller,
+   etc. */
+extern UInt VG_(stack_snapshot) ( ThreadId tid, Addr* eips, UInt n_eips );
+
+/* Does the same thing as VG_(pp_ExeContext)(), just with slightly
+   different input. */
+extern void VG_(mini_stack_dump) ( Addr eips[], UInt n_eips );
+
 
 /*====================================================================*/
 /*=== Error reporting                                              ===*/
@@ -1399,6 +1415,15 @@ extern Bool VG_(get_fnname_if_entry) ( Addr a, Char* fnname, Int n_fnname );
    It doesn't matter if debug info is present or not. */
 extern Bool VG_(get_objname)  ( Addr a, Char* objname,  Int n_objname  );
 
+/* Puts into 'buf' info about the code address %eip:  the address, function
+   name (if known) and filename/line number (if known), like this:
+
+      0x4001BF05: realloc (vg_replace_malloc.c:339)
+
+   'n_buf' gives length of 'buf'.  Returns 'buf'.
+*/
+extern Char* VG_(describe_eip)(Addr eip, Char* buf, Int n_buf);
+
 /* A way to get information about what segments are mapped */
 typedef struct _SegInfo SegInfo;