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/vg_main.c b/vg_main.c
index 6df3e92..330068d 100644
--- a/vg_main.c
+++ b/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. */