Kernel 2.4 / glibc 2.2.X build fixes for recent startup changes.
git-svn-id: svn://svn.valgrind.org/valgrind/trunk@259 a5019735-40e9-0310-863c-91ae7b9d1cf9
diff --git a/coregrind/arch/x86-linux/vg_libpthread.c b/coregrind/arch/x86-linux/vg_libpthread.c
index 015b9f7..df89517 100644
--- a/coregrind/arch/x86-linux/vg_libpthread.c
+++ b/coregrind/arch/x86-linux/vg_libpthread.c
@@ -104,8 +104,6 @@
static __inline__
void ensure_valgrind ( char* caller )
{
- char* str;
- int is_valgrind;
VG_(startup)();
}
@@ -333,7 +331,9 @@
case PTHREAD_MUTEX_TIMED_NP:
case PTHREAD_MUTEX_ADAPTIVE_NP:
# endif
+# ifdef GLIBC_2_1
case PTHREAD_MUTEX_FAST_NP:
+# endif
case PTHREAD_MUTEX_RECURSIVE_NP:
case PTHREAD_MUTEX_ERRORCHECK_NP:
attr->__mutexkind = type;
diff --git a/coregrind/vg_include.h b/coregrind/vg_include.h
index f280ef8..d4622b2 100644
--- a/coregrind/vg_include.h
+++ b/coregrind/vg_include.h
@@ -627,10 +627,22 @@
extern Int VG_(longjmpd_on_signal);
-/* We check that the initial stack, which we can't move, is allocated
- here. VG_(scheduler_init) checks this.
+/* Possible places where the main stack might be based. We check that
+ the initial stack, which we can't move, is allocated here.
+ VG_(scheduler_init) checks this. Andrea Archelangi's 2.4 kernels
+ have been rumoured to start stacks at 0x80000000, so that too is
+ considered.
*/
-#define VG_STARTUP_STACK_MASK (Addr)0xBFF80000
+#define VG_STARTUP_STACK_BASE_1 (Addr)0xC0000000
+#define VG_STARTUP_STACK_BASE_2 (Addr)0x80000000
+#define VG_STARTUP_STACK_SMALLERTHAN 0x100000 /* 1024k */
+
+#define VG_STACK_MATCHES_BASE(zzstack, zzbase) \
+ ( \
+ ((zzstack) & ((zzbase) - VG_STARTUP_STACK_SMALLERTHAN)) \
+ == \
+ ((zzbase) - VG_STARTUP_STACK_SMALLERTHAN) \
+ )
/* The red-zone size which we put at the bottom (highest address) of
diff --git a/coregrind/vg_kerneliface.h b/coregrind/vg_kerneliface.h
index 362a553..a7690dd 100644
--- a/coregrind/vg_kerneliface.h
+++ b/coregrind/vg_kerneliface.h
@@ -297,6 +297,24 @@
};
+/* To do with the ELF constructed by the kernel on a process' stack
+ just before it transfers control to the program's interpreter
+ (to use the ELF parlance).
+ Constants from /usr/src/linux-2.4.9-31/include/linux/elf.h
+ Logic from /usr/src/linux-2.4.9-31/fs/binfmt_elf.c
+ and its counterpart in the 2.2.14 kernel sources
+ in Red Hat 6.2.
+*/
+#define VKI_AT_CLKTCK 17 /* frequency at which times() increments */
+#define VKI_AT_HWCAP 16 /* arch dependent hints at CPU capabilities */
+#define VKI_AT_BASE 7 /* base address of interpreter */
+#define VKI_AT_PAGESZ 6 /* system page size */
+#define VKI_AT_PHNUM 5 /* number of program headers */
+#define VKI_AT_PHENT 4 /* size of program header entry */
+#define VKI_AT_PHDR 3 /* program headers for program */
+
+
+
#endif /* ndef __VG_KERNELIFACE_H */
/*--------------------------------------------------------------------*/
diff --git a/coregrind/vg_libpthread.c b/coregrind/vg_libpthread.c
index 015b9f7..df89517 100644
--- a/coregrind/vg_libpthread.c
+++ b/coregrind/vg_libpthread.c
@@ -104,8 +104,6 @@
static __inline__
void ensure_valgrind ( char* caller )
{
- char* str;
- int is_valgrind;
VG_(startup)();
}
@@ -333,7 +331,9 @@
case PTHREAD_MUTEX_TIMED_NP:
case PTHREAD_MUTEX_ADAPTIVE_NP:
# endif
+# ifdef GLIBC_2_1
case PTHREAD_MUTEX_FAST_NP:
+# endif
case PTHREAD_MUTEX_RECURSIVE_NP:
case PTHREAD_MUTEX_ERRORCHECK_NP:
attr->__mutexkind = type;
diff --git a/coregrind/vg_main.c b/coregrind/vg_main.c
index 6df3e92..330068d 100644
--- a/coregrind/vg_main.c
+++ b/coregrind/vg_main.c
@@ -481,6 +481,15 @@
VG_(exit)(1);
}
+static void args_grok_error ( Char* msg )
+{
+ VG_(shutdown_logging)();
+ VG_(clo_logfile_fd) = 2; /* stderr */
+ VG_(printf)("valgrind.so: When searching for "
+ "client's argc/argc/envp:\n\t%s\n", msg);
+ config_error("couldn't find client's argc/argc/envp");
+}
+
static void process_cmd_line_options ( void )
{
@@ -488,7 +497,7 @@
UInt argc;
UChar* p;
UChar* str;
- Int i, eventually_logfile_fd;
+ Int i, eventually_logfile_fd, ctr;
# define ISSPACE(cc) ((cc) == ' ' || (cc) == '\t' || (cc) == '\n')
# define STREQ(s1,s2) (0==VG_(strcmp_ws)((s1),(s2)))
@@ -532,161 +541,89 @@
VG_(startup_logging)();
- /* We look for the Linux ELF table and go down until we find the
+ /* (Suggested by Fabrice Bellard ... )
+ We look for the Linux ELF table and go down until we find the
envc & envp. It is not full proof, but these structures should
change less often than the libc ones. */
{
- unsigned long *sp;
- int i;
+ UInt* sp = 0; /* bogus init to keep gcc -O happy */
+
/* locate the top of the stack */
- sp = (unsigned long *)(((unsigned long)VG_(esp_at_startup) &
- 0xF0000000) + 0x10000000);
+ if (VG_STACK_MATCHES_BASE( VG_(esp_at_startup),
+ VG_STARTUP_STACK_BASE_1 )) {
+ sp = (UInt*)VG_STARTUP_STACK_BASE_1;
+ } else
+ if (VG_STACK_MATCHES_BASE( VG_(esp_at_startup),
+ VG_STARTUP_STACK_BASE_2 )) {
+ sp = (UInt*)VG_STARTUP_STACK_BASE_2;
+ } else {
+ args_grok_error(
+ "startup %esp is not near any VG_STARTUP_STACK_BASE_*\n "
+ "constants defined in vg_include.h. You should investigate."
+ );
+ }
+
/* we locate: NEW_AUX_ENT(1, AT_PAGESZ, ELF_EXEC_PAGESIZE) in
the elf interpreter table */
sp -= 2;
-
-#define VKI_AT_PAGESZ 6
-
while (sp[0] != VKI_AT_PAGESZ || sp[1] != 4096) {
- /* VG_(printf)("trying %p\n", sp); */
+ /* VG_(printf)("trying %p\n", sp); */
sp--;
}
-#define VKI_AT_BASE 7 /* base address of interpreter */
-#define VKI_AT_PAGESZ 6 /* system page size */
-#define VKI_AT_PHNUM 5 /* number of program headers */
-#define VKI_AT_PHENT 4 /* size of program header entry */
-#define VKI_AT_PHDR 3 /* program headers for program */
if (sp[2] == VKI_AT_BASE
&& sp[0] == VKI_AT_PAGESZ
&& sp[-2] == VKI_AT_PHNUM
&& sp[-4] == VKI_AT_PHENT
&& sp[-6] == VKI_AT_PHDR) {
- VG_(printf)("Looks like you've got a 2.2.X kernel here.\n");
+ if (0)
+ VG_(printf)("Looks like you've got a 2.2.X kernel here.\n");
sp -= 6;
- }
+ } else
+ if (sp[2] == VKI_AT_CLKTCK
+ && sp[0] == VKI_AT_PAGESZ
+ && sp[-2] == VKI_AT_HWCAP) {
+ if (0)
+ VG_(printf)("Looks like you've got a 2.4.X kernel here.\n");
+ sp -= 2;
+ } else
+ args_grok_error(
+ "ELF frame does not look like 2.2.X or 2.4.X.\n "
+ "See kernel sources linux/fs/binfmt_elf.c to make sense of this."
+ );
sp--;
- vg_assert(*sp == 0);
+ if (*sp != 0)
+ args_grok_error("can't find NULL at end of env[]");
+
/* sp now points to NULL at the end of env[] */
+ ctr = 0;
while (True) {
sp --;
if (*sp == 0) break;
+ if (++ctr >= 1000)
+ args_grok_error(
+ "suspiciously many (1000) env[] entries; giving up");
+
}
/* sp now points to NULL at the end of argv[] */
- VG_(client_envp) = sp+1;
+ VG_(client_envp) = (Char**)(sp+1);
+ ctr = 0;
VG_(client_argc) = 0;
while (True) {
sp--;
if (*sp == VG_(client_argc))
break;
VG_(client_argc)++;
+ if (++ctr >= 1000)
+ args_grok_error(
+ "suspiciously many (1000) argv[] entries; giving up");
}
- VG_(client_argv) = sp+1;
+ VG_(client_argv) = (Char**)(sp+1);
}
-
-#if 0
- /* Magically find the client's argc/argv/envp. This kludge is
- entirely dependent on the stack layout imposed by libc at
- startup. Hence the magic offsets. Then check (heuristically)
- that the results are plausible. There must be a better way to
- do this ... */
-
-# if 1
- /* Use this to search for the correct offsets if the tests below
- barf. */
- { Int i;
- VG_(printf)("startup %%esp is %p\n", VG_(esp_at_startup) );
- for (i = -10; i < 20; i++) {
- Char* p = ((Char**)VG_(esp_at_startup))[i];
- VG_(printf)("%d: %p\n", i, p);
- }
- }
-# endif
-
-# if defined(GLIBC_2_2)
- /* These offsets (5,6,7) are right for my RedHat 7.2 (glibc-2.2.4)
- box. */
-
- VG_(client_argc) = (Int) ( ((void**)VG_(esp_at_startup)) [5] );
- VG_(client_argv) = (Char**)( ((void**)VG_(esp_at_startup)) [6] );
- VG_(client_envp) = (Char**)( ((void**)VG_(esp_at_startup)) [7] );
-
- if ( ((UInt)VG_(client_argc)) > 0 &&
- ((UInt)VG_(client_argc)) < 10000 &&
- (Addr)VG_(client_argv) >= 0x8000000 &&
- (Addr)VG_(client_envp) >= 0x8000000)
- goto argc_argv_envp_OK;
-
- /* If that's no good, try some other offsets discovered by KDE
- folks on 8 Feb 02:
- For glibc > 2.2.4 the offset 9/10/11 did the trick. Coolo found
- out those, on I think a Caldera 3.1 with glibc 2.2.4 -- the same
- offsets worked for on a debian sid with glibc 2.2.5. */
-
- VG_(client_argc) = (Int) ( ((void**)VG_(esp_at_startup)) [9] );
- VG_(client_argv) = (Char**)( ((void**)VG_(esp_at_startup)) [10] );
- VG_(client_envp) = (Char**)( ((void**)VG_(esp_at_startup)) [11] );
-
- if ( ((UInt)VG_(client_argc)) > 0 &&
- ((UInt)VG_(client_argc)) < 10000 &&
- (Addr)VG_(client_argv) >= 0x8000000 &&
- (Addr)VG_(client_envp) >= 0x8000000)
- goto argc_argv_envp_OK;
-
-# endif /* defined(GLIBC_2_2) */
-
-# if defined(GLIBC_2_1)
- /* Doesn't look promising. Try offsets for RedHat 6.2
- (glibc-2.1.3) instead. In this case, the argv and envp vectors
- are actually on the stack (bizarrely). */
-
- VG_(client_argc) = (Int) ( ((void**)VG_(esp_at_startup)) [4] );
- VG_(client_argv) = (Char**) & ( ((void**)VG_(esp_at_startup)) [5] );
- VG_(client_envp)
- = (Char**) & ( ((void**)VG_(esp_at_startup)) [6 + VG_(client_argc)] );
-
- if ( ((UInt)VG_(client_argc)) > 0 &&
- ((UInt)VG_(client_argc)) < 10000 &&
- (Addr)VG_(client_argv) >= 0x8000000 &&
- (Addr)VG_(client_envp) >= 0x8000000)
- goto argc_argv_envp_OK;
-
- /* Here's yet another variant, from <hansen> (irc.kde.org). */
-
- VG_(client_argc) = (Int) ( ((void**)VG_(esp_at_startup)) [9] );
- VG_(client_argv) = (Char**) & ( ((void**)VG_(esp_at_startup)) [10] );
- VG_(client_envp)
- = (Char**) & ( ((void**)VG_(esp_at_startup)) [11 + VG_(client_argc)] );
-
- if ( ((UInt)VG_(client_argc)) > 0 &&
- ((UInt)VG_(client_argc)) < 10000 &&
- (Addr)VG_(client_argv) >= 0x8000000 &&
- (Addr)VG_(client_envp) >= 0x8000000)
- goto argc_argv_envp_OK;
-# endif /* defined(GLIBC_2_1) */
-
-# if !defined(GLIBC_2_2) && !defined(GLIBC_2_1)
- config_error("autoconf/configure detected neither glibc 2.1.X nor 2.2.X");
-# endif
-
- /* VG_(printf)("%d %p %p\n", VG_(client_argc), VG_(client_argv),
- VG_(client_envp));
- */
- /* We're hosed. Give up :-( */
- config_error(
- "Can't get plausible values for client's argc/argv/envp.\n\t"
- "You may be able to fix this; see process_cmd_line_options()\n\t"
- "in vg_main.c"
- );
- /* NOTREACHED */
-
- argc_argv_envp_OK:
-#endif
-
/* Now that VG_(client_envp) has been set, we can extract the args
for Valgrind itself. Copy into global var so that we don't have to
write zeroes to the getenv'd value itself. */
diff --git a/coregrind/vg_scheduler.c b/coregrind/vg_scheduler.c
index 54dc30b..79056e7 100644
--- a/coregrind/vg_scheduler.c
+++ b/coregrind/vg_scheduler.c
@@ -524,9 +524,15 @@
ThreadId tid_main;
startup_esp = VG_(baseBlock)[VGOFF_(m_esp)];
- if ((startup_esp & VG_STARTUP_STACK_MASK) != VG_STARTUP_STACK_MASK) {
- VG_(printf)("%%esp at startup = %p is not near %p; aborting\n",
- (void*)startup_esp, (void*)VG_STARTUP_STACK_MASK);
+
+ if (VG_STACK_MATCHES_BASE(startup_esp, VG_STARTUP_STACK_BASE_1)
+ || VG_STACK_MATCHES_BASE(startup_esp, VG_STARTUP_STACK_BASE_2)) {
+ /* Jolly good! */
+ } else {
+ VG_(printf)("%%esp at startup = %p is not near %p or %p; aborting\n",
+ (void*)startup_esp,
+ (void*)VG_STARTUP_STACK_BASE_1,
+ (void*)VG_STARTUP_STACK_BASE_2 );
VG_(panic)("unexpected %esp at startup");
}
@@ -1922,7 +1928,9 @@
case PTHREAD_MUTEX_TIMED_NP:
case PTHREAD_MUTEX_ADAPTIVE_NP:
# endif
+# ifdef GLIBC_2_1
case PTHREAD_MUTEX_FAST_NP:
+# endif
case PTHREAD_MUTEX_RECURSIVE_NP:
case PTHREAD_MUTEX_ERRORCHECK_NP:
if (mutex->__m_count >= 0) break;
@@ -2016,7 +2024,9 @@
case PTHREAD_MUTEX_TIMED_NP:
case PTHREAD_MUTEX_ADAPTIVE_NP:
# endif
+# ifdef GLIBC_2_1
case PTHREAD_MUTEX_FAST_NP:
+# endif
case PTHREAD_MUTEX_RECURSIVE_NP:
case PTHREAD_MUTEX_ERRORCHECK_NP:
if (mutex->__m_count >= 0) break;
@@ -2234,7 +2244,9 @@
case PTHREAD_MUTEX_TIMED_NP:
case PTHREAD_MUTEX_ADAPTIVE_NP:
# endif
+# ifdef GLIBC_2_1
case PTHREAD_MUTEX_FAST_NP:
+# endif
case PTHREAD_MUTEX_RECURSIVE_NP:
case PTHREAD_MUTEX_ERRORCHECK_NP:
if (mutex->__m_count >= 0) break;