void VG_(pp_ExeContext) ( ExeContext* e )
{
init_ExeContext_storage();
- VG_(mini_stack_dump) ( e );
+ VG_(mini_stack_dump) ( e->eips, VG_(clo_backtrace_size) );
}
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;
}
-/* 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
} 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 */
//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. */
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 )
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,
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];
};
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
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;
}
*/
static SegInfo* segInfo = NULL;
-
void VG_(read_symtab_callback) (
Addr start, UInt size,
Char rr, Char ww, Char xx,
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. ---*/
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. */
(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));
/* 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
*/
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 ===*/
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;