linux: use /proc/self/maps to find precise stack base

This commit is contained in:
Matthew Flatt 2011-05-29 09:41:07 -06:00
parent 060b4e9b32
commit 5dfd17d0b9
4 changed files with 66 additions and 4 deletions

View File

@ -203,6 +203,7 @@
# define SIGSET_IS_SIGNAL
# define SIGSET_NEEDS_REINSTALL
# define LINUX_FIND_STACK_BASE
# define USE_DYNAMIC_FDSET_SIZE
# define USE_TIMEZONE_VAR_W_DLS
@ -1307,6 +1308,9 @@
WINDOWS_FIND_STACK_BOUNDS figures out the maximum stack position
under Windows (uses GC_find_stack_base())
MACOS_FIND_STACK_BOUNDS figures out the stack limit on the Mac.
LINUX_FIND_STACK_BASE figures out the stack base under Linux
by reading from /proc/self/maps and looking for "[stack]"
line.
ASSUME_FIXED_STACK_SIZE assumes that the main stack size is
always FIXED_STACK_SIZE.
Use only one of these if DO_STACK_CHECK is used, or none otherwise. */

View File

@ -426,6 +426,54 @@ scheme_handle_stack_overflow(Scheme_Object *(*k)(void))
return NULL; /* never gets here */
}
#ifdef LINUX_FIND_STACK_BASE
uintptr_t adjust_stack_base(uintptr_t bnd) {
if (bnd == scheme_get_primordial_thread_stack_base()) {
/* The address `base' might be far from the actual stack base
if Exec Sheild is enabled. Use "/proc/self/maps" to get
exacty the stack base. */
FILE *f;
char *buf;
f = fopen("/proc/self/maps", "r");
if (f) {
buf = malloc(256);
while (fgets(buf, 256, f)) {
int len;
len = strlen(buf);
if ((len > 8) && !strcmp("[stack]\n", buf + len - 8)) {
uintptr_t p = 0;
int i;
/* find separator: */
for (i = 0; buf[i]; i++) {
if (buf[i] == '-') {
i++;
break;
}
}
/* parse number after separator: */
for (; buf[i]; i++) {
if ((buf[i] >= '0') && (buf[i] <= '9')) {
p = (p << 4) | (buf[i] - '0');
} else if ((buf[i] >= 'a') && (buf[i] <= 'f')) {
p = (p << 4) | (buf[i] - 'a' + 10);
} else if ((buf[i] >= 'A') && (buf[i] <= 'F')) {
p = (p << 4) | (buf[i] - 'A' + 10);
} else
break;
}
/* printf("%p vs. %p: %d\n", (void*)bnd, (void*)p, p - bnd); */
return p;
}
}
free(buf);
fclose(f);
}
}
return bnd;
}
#endif
void scheme_init_stack_check()
/* Finds the C stack limit --- platform-specific. */
{
@ -503,6 +551,10 @@ void scheme_init_stack_check()
uintptr_t bnd, lim;
bnd = (uintptr_t)scheme_get_current_os_thread_stack_base();
# ifdef LINUX_FIND_STACK_BASE
bnd = adjust_stack_base(bnd);
# endif
lim = (uintptr_t)rl.rlim_cur;
# ifdef UNIX_STACK_MAXIMUM
if (lim > UNIX_STACK_MAXIMUM)

View File

@ -74,7 +74,7 @@ int scheme_thread_local_offset = 0;
#endif
extern int scheme_num_copied_stacks;
SHARED_OK static uintptr_t scheme_primordial_os_thread_stack_base;
SHARED_OK static uintptr_t primordial_os_thread_stack_base;
THREAD_LOCAL_DECL(static uintptr_t scheme_os_thread_stack_base);
#ifdef USE_THREAD_LOCAL
SHARED_OK Thread_Local_Variables *scheme_vars; /* for debugging */
@ -118,7 +118,7 @@ void scheme_set_stack_base(void *base, int no_auto_statics) XFORM_SKIP_PROC
scheme_register_traversers();
#endif
scheme_primordial_os_thread_stack_base = (uintptr_t) base;
primordial_os_thread_stack_base = (uintptr_t) base;
scheme_os_thread_stack_base = (uintptr_t) base;
#if defined(MZ_PRECISE_GC) || defined(USE_SENORA_GC)
@ -152,6 +152,11 @@ uintptr_t scheme_get_current_os_thread_stack_base()
return scheme_os_thread_stack_base;
}
uintptr_t scheme_get_primordial_thread_stack_base()
{
return primordial_os_thread_stack_base;
}
typedef struct {
Scheme_Env_Main _main;
int argc;

View File

@ -130,7 +130,8 @@ int scheme_num_types(void);
void scheme_reset_finalizations(void);
extern uintptr_t scheme_get_current_os_thread_stack_base(void);
uintptr_t scheme_get_primordial_thread_stack_base(void);
uintptr_t scheme_get_current_os_thread_stack_base(void);
void scheme_set_current_os_thread_stack_base(void *base);
int scheme_propagate_ephemeron_marks(void);