New and hopefully more reliable method for finding argc/argv/envp at

startup, by looking for the ELF frame created on the process' stack
at startup.  This avoids having to deal with problems caused by glibc
magic offsets.

WARNING: only works for 2.2 kernels right now.  2.4 is broken.


git-svn-id: svn://svn.valgrind.org/valgrind/trunk@258
This commit is contained in:
Julian Seward
2002-05-10 21:07:22 +00:00
parent 67b0b0e404
commit 06e9ee22df
2 changed files with 122 additions and 4 deletions

View File

@@ -531,18 +531,76 @@ static void process_cmd_line_options ( void )
to failures in initialisation. */
VG_(startup_logging)();
/* 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;
/* locate the top of the stack */
sp = (unsigned long *)(((unsigned long)VG_(esp_at_startup) &
0xF0000000) + 0x10000000);
/* 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); */
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");
sp -= 6;
}
sp--;
vg_assert(*sp == 0);
/* sp now points to NULL at the end of env[] */
while (True) {
sp --;
if (*sp == 0) break;
}
/* sp now points to NULL at the end of argv[] */
VG_(client_envp) = sp+1;
VG_(client_argc) = 0;
while (True) {
sp--;
if (*sp == VG_(client_argc))
break;
VG_(client_argc)++;
}
VG_(client_argv) = 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 0
# 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 = 0; i < 10; i++) {
for (i = -10; i < 20; i++) {
Char* p = ((Char**)VG_(esp_at_startup))[i];
VG_(printf)("%d: %p\n", i, p);
}
@@ -627,6 +685,7 @@ static void process_cmd_line_options ( void )
/* 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

View File

@@ -531,18 +531,76 @@ static void process_cmd_line_options ( void )
to failures in initialisation. */
VG_(startup_logging)();
/* 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;
/* locate the top of the stack */
sp = (unsigned long *)(((unsigned long)VG_(esp_at_startup) &
0xF0000000) + 0x10000000);
/* 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); */
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");
sp -= 6;
}
sp--;
vg_assert(*sp == 0);
/* sp now points to NULL at the end of env[] */
while (True) {
sp --;
if (*sp == 0) break;
}
/* sp now points to NULL at the end of argv[] */
VG_(client_envp) = sp+1;
VG_(client_argc) = 0;
while (True) {
sp--;
if (*sp == VG_(client_argc))
break;
VG_(client_argc)++;
}
VG_(client_argv) = 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 0
# 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 = 0; i < 10; i++) {
for (i = -10; i < 20; i++) {
Char* p = ((Char**)VG_(esp_at_startup))[i];
VG_(printf)("%d: %p\n", i, p);
}
@@ -627,6 +685,7 @@ static void process_cmd_line_options ( void )
/* 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