summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--coregrind/m_clientstate.c6
-rw-r--r--coregrind/m_redir.c39
-rw-r--r--coregrind/m_signals.c4
-rw-r--r--coregrind/m_stacktrace.c31
-rw-r--r--coregrind/m_trampoline.S10
-rw-r--r--coregrind/pub_core_clientstate.h7
-rw-r--r--coregrind/pub_core_trampoline.h10
7 files changed, 74 insertions, 33 deletions
diff --git a/coregrind/m_clientstate.c b/coregrind/m_clientstate.c
index b4b16c2f..5da95d2c 100644
--- a/coregrind/m_clientstate.c
+++ b/coregrind/m_clientstate.c
@@ -91,6 +91,12 @@ Int VG_(fd_hard_limit) = -1;
/* Where is the __libc_freeres_wrapper routine we made? */
Addr VG_(client___libc_freeres_wrapper) = 0;
+/* x86-linux only: where is glibc's _dl_sysinfo_int80 function?
+ Finding it isn't essential, but knowing where it is does sometimes
+ help produce better back traces. See big comment in
+ VG_(get_StackTrace) in m_stacktrace.c for further info. */
+Addr VG_(client__dl_sysinfo_int80) = 0;
+
/*--------------------------------------------------------------------*/
/*--- end ---*/
diff --git a/coregrind/m_redir.c b/coregrind/m_redir.c
index 853ad662..adfa215d 100644
--- a/coregrind/m_redir.c
+++ b/coregrind/m_redir.c
@@ -273,7 +273,8 @@ static Bool is_plausible_guest_addr(Addr);
static void show_redir_state ( HChar* who );
static void show_active ( HChar* left, Active* act );
-static void handle_maybe_load_notifier( HChar* symbol, Addr addr );
+static void handle_maybe_load_notifier( const UChar* soname,
+ HChar* symbol, Addr addr );
/*------------------------------------------------------------*/
@@ -310,8 +311,11 @@ void VG_(redir_notify_new_SegInfo)( SegInfo* newsi )
HChar demangled_sopatt[N_DEMANGLED];
HChar demangled_fnpatt[N_DEMANGLED];
+ const UChar* newsi_soname;
+
vg_assert(newsi);
- vg_assert(VG_(seginfo_soname)(newsi) != NULL);
+ newsi_soname = VG_(seginfo_soname)(newsi);
+ vg_assert(newsi_soname != NULL);
/* stay sane: we don't already have this. */
for (ts = topSpecs; ts; ts = ts->next)
@@ -330,7 +334,7 @@ void VG_(redir_notify_new_SegInfo)( SegInfo* newsi )
if (!ok) {
/* It's not a full-scale redirect, but perhaps it is a load-notify
fn? Let the load-notify department see it. */
- handle_maybe_load_notifier( sym_name, sym_addr );
+ handle_maybe_load_notifier( newsi_soname, sym_name, sym_addr );
continue;
}
spec = symtab_alloc(sizeof(Spec));
@@ -726,13 +730,6 @@ void VG_(redir_initialise) ( void )
// The rest of this function just adds initial Specs.
# if defined(VGP_x86_linux)
- /* Redirect _dl_sysinfo_int80, which is glibc's default system call
- routine, to our copy so that the special sysinfo unwind hack in
- m_stacktrace.c will kick in. */
- add_hardwired_spec(
- "ld-linux.so.2", "_dl_sysinfo_int80",
- (Addr)&VG_(x86_linux_REDIR_FOR__dl_sysinfo_int80)
- );
/* If we're using memcheck, use this intercept right from the
start, otherwise ld.so (glibc-2.3.5) makes a lot of noise. */
if (0==VG_(strcmp)("Memcheck", VG_(details).name)) {
@@ -827,8 +824,25 @@ static Bool is_plausible_guest_addr(Addr a)
/*--- NOTIFY-ON-LOAD FUNCTIONS ---*/
/*------------------------------------------------------------*/
-static void handle_maybe_load_notifier( HChar* symbol, Addr addr )
+static
+void handle_maybe_load_notifier( const UChar* soname,
+ HChar* symbol, Addr addr )
{
+# if defined(VGP_x86_linux)
+ /* x86-linux only: if we see _dl_sysinfo_int80, note its address.
+ See comment on declaration of VG_(client__dl_sysinfo_int80) for
+ the reason. As far as I can tell, the relevant symbol is always
+ in object with soname "ld-linux.so.2". */
+ if (symbol && symbol[0] == '_'
+ && 0 == VG_(strcmp)(symbol, "_dl_sysinfo_int80")
+ && 0 == VG_(strcmp)(soname, "ld-linux.so.2")) {
+ if (VG_(client__dl_sysinfo_int80) == 0)
+ VG_(client__dl_sysinfo_int80) = addr;
+ }
+# endif
+
+ /* Normal load-notifier handling after here. First, ignore all
+ symbols lacking the right prefix. */
if (0 != VG_(strncmp)(symbol, VG_NOTIFY_ON_LOAD_PREFIX,
VG_NOTIFY_ON_LOAD_PREFIX_LEN))
/* Doesn't have the right prefix */
@@ -836,9 +850,6 @@ static void handle_maybe_load_notifier( HChar* symbol, Addr addr )
if (VG_(strcmp)(symbol, VG_STRINGIFY(VG_NOTIFY_ON_LOAD(freeres))) == 0)
VG_(client___libc_freeres_wrapper) = addr;
-// else
-// if (VG_(strcmp)(symbol, STR(VG_WRAPPER(pthread_startfunc_wrapper))) == 0)
-// VG_(pthread_startfunc_wrapper)((Addr)(si->offset + sym->st_value));
else
vg_assert2(0, "unrecognised load notification function: %s", symbol);
}
diff --git a/coregrind/m_signals.c b/coregrind/m_signals.c
index 05916223..53c2dc2d 100644
--- a/coregrind/m_signals.c
+++ b/coregrind/m_signals.c
@@ -905,9 +905,11 @@ void push_signal_frame ( ThreadId tid, const vki_siginfo_t *siginfo )
vg_assert(VG_(is_valid_tid)(tid));
tst = & VG_(threads)[tid];
- if (VG_(clo_trace_signals))
+ if (VG_(clo_trace_signals)) {
VG_(message)(Vg_DebugMsg,
"push_signal_frame (thread %d): signal %d", tid, sigNo);
+ VG_(get_and_pp_StackTrace)(tid, 10);
+ }
if (/* this signal asked to run on an alt stack */
(scss.scss_per_sig[sigNo].scss_flags & VKI_SA_ONSTACK )
diff --git a/coregrind/m_stacktrace.c b/coregrind/m_stacktrace.c
index 3d307fc4..be0fef7c 100644
--- a/coregrind/m_stacktrace.c
+++ b/coregrind/m_stacktrace.c
@@ -38,6 +38,7 @@
#include "pub_core_machine.h"
#include "pub_core_options.h"
#include "pub_core_stacktrace.h"
+#include "pub_core_clientstate.h" // VG_(client__dl_sysinfo_int80)
#include "pub_core_trampoline.h"
/*------------------------------------------------------------*/
@@ -344,16 +345,26 @@ UInt VG_(get_StackTrace) ( ThreadId tid, StackTrace ips, UInt n_ips )
Addr stack_highest_word = VG_(threads)[tid].client_stack_highest_word;
# if defined(VGP_x86_linux)
- /* 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 >= (Addr)&VG_(trampoline_stuff_start)
- && ip < (Addr)&VG_(trampoline_stuff_end)
+ /* Nasty little hack to deal with syscalls - if libc is using its
+ _dl_sysinfo_int80 function for syscalls (the TLS version does),
+ then ip will always appear to be in that function when doing a
+ syscall, not the actual libc function doing the syscall. This
+ check sees if IP is within that function, 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.
+
+ The function is assumed to look like this (from glibc-2.3.6 sources):
+ _dl_sysinfo_int80:
+ int $0x80
+ ret
+ That is 3 (2+1) bytes long. We could be more thorough and check
+ the 3 bytes of the function are as expected, but I can't be
+ bothered.
+ */
+ if (VG_(client__dl_sysinfo_int80) != 0 /* we know its address */
+ && ip >= VG_(client__dl_sysinfo_int80)
+ && ip < VG_(client__dl_sysinfo_int80)+3
&& VG_(am_is_valid_for_client)(sp, sizeof(Addr), VKI_PROT_READ)) {
ip = *(Addr *)sp;
sp += sizeof(Addr);
diff --git a/coregrind/m_trampoline.S b/coregrind/m_trampoline.S
index 3416eb4d..5965e871 100644
--- a/coregrind/m_trampoline.S
+++ b/coregrind/m_trampoline.S
@@ -55,7 +55,9 @@ VG_(trampoline_stuff_start):
.global VG_(x86_linux_SUBST_FOR_sigreturn)
VG_(x86_linux_SUBST_FOR_sigreturn):
/* This is a very specific sequence which GDB uses to
- recognize signal handler frames. */
+ recognize signal handler frames. Also gcc: see
+ x86_fallback_frame_state() in
+ gcc-4.1.0/gcc/config/i386/linux-unwind.h */
popl %eax
movl $__NR_sigreturn, %eax
int $0x80
@@ -68,12 +70,6 @@ VG_(x86_linux_SUBST_FOR_rt_sigreturn):
int $0x80
ud2
-.global VG_(x86_linux_REDIR_FOR__dl_sysinfo_int80)
-VG_(x86_linux_REDIR_FOR__dl_sysinfo_int80):
- /* We can point our sysinfo stuff here */
- int $0x80
- ret
-
/* There's no particular reason that this needs to be handwritten
assembly, but since that's what this file contains, here's a
simple index implementation (written in C and compiled by gcc.)
diff --git a/coregrind/pub_core_clientstate.h b/coregrind/pub_core_clientstate.h
index a526532a..e9740f23 100644
--- a/coregrind/pub_core_clientstate.h
+++ b/coregrind/pub_core_clientstate.h
@@ -82,6 +82,13 @@ extern Int VG_(fd_hard_limit);
/* Where is the __libc_freeres_wrapper routine we made? */
extern Addr VG_(client___libc_freeres_wrapper);
+/* x86-linux only: where is ld.so's _dl_sysinfo_int80 function?
+ Finding it isn't essential, but knowing where it is does sometimes
+ help produce better back traces. See big comment in
+ VG_(get_StackTrace) in m_stacktrace.c for further info. */
+extern Addr VG_(client__dl_sysinfo_int80);
+
+
#endif // __PUB_CORE_CLIENTSTATE_H
/*--------------------------------------------------------------------*/
diff --git a/coregrind/pub_core_trampoline.h b/coregrind/pub_core_trampoline.h
index 134a569d..9d2c5507 100644
--- a/coregrind/pub_core_trampoline.h
+++ b/coregrind/pub_core_trampoline.h
@@ -37,6 +37,15 @@
// stubs for signal returns. Note, all the code within runs on the
// simulated CPU. The vsyscall stubs are gotten to by use of the
// redirect mechanism.
+//
+// Note: generally, putting replacement functions in here is a bad
+// idea, since any Dwarf frame-unwind info attached to them will not
+// be seen by the unwinder in gcc's runtime support. This means
+// unwinding during exception handling by gcc tends to fail if it
+// encounters one of these replacement functions. A better place to
+// put them is in one of the .so's preloaded into the client, since
+// the client's ld.so will know about it and so gcc's unwinder
+// (somehow) is able to get hold of it.
//--------------------------------------------------------------------
/* These two delimit our handwritten assembly code, so we can tell
@@ -50,7 +59,6 @@ extern void VG_(trampoline_stuff_end);
#if defined(VGP_x86_linux)
extern void VG_(x86_linux_SUBST_FOR_sigreturn);
extern void VG_(x86_linux_SUBST_FOR_rt_sigreturn);
-extern void VG_(x86_linux_REDIR_FOR__dl_sysinfo_int80);
extern Char* VG_(x86_linux_REDIR_FOR_index) ( const Char*, Int );
#endif