This is the mail archive of the guile@cygnus.com mailing list for the guile project.


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]

Finding the top of the stack



I wrote a little program to see what ways there are to get the top of
the stack on a system. Here is my code so far (the #defines at the top
must be hacked by hand). Does anyone know of any other ways of
potentially getting something above the first stack frame? I recall
someone mentioning that glibc 2.x had a function like this, what is it called?

Once I get a lot of tests, I will package this up to be a completely
automated shell script (a configure script, really) and ship it out
for a lot of people to run on many different systems.

So far it seems like environ is the most promising candidate for
finding (close enough to) the top of the stack on many systems, this
works on sparc-sun-solaris, sparc-sun-sunos, and
i386-unknown-linux-gnulibc1, I'd expect it to work with anything that
uses glibc, and any BSD-derived or SVR4-derived system, actually. I
can specifically check on NetBSD/i386, Irix, HP-UX, AIX and Digital
Unix but not right now.

Anyway, if you have more start-of-stack ideas, send them my way.

------------------

#define HAVE_GETCONTEXT 1
#define HAVE_SIGSTACK   1
#define HAVE_ENVIRON    1

#include <stdlib.h>

#if HAVE_SIGSTACK
#include <signal.h>
#endif

#if HAVE_GETCONTEXT
#include <ucontext.h>
#endif

#include <errno.h>


#if HAVE_ENVIRON
extern char **environ;
#endif

static int 
stack_compare(void *addr1, void *addr2, int down_p)
{
  if (down_p) {
    return (unsigned long)addr1 > (unsigned long)addr2;
  } else {
    return (unsigned long)addr1 < (unsigned long)addr2;
  }
}

static unsigned long 
do_test(char **argv, char **envp, int *p_outer_var, void *gcp)
{
  int inner_var;
  int down_p;

#if HAVE_SIGSTACK
  struct sigstack oss;
#endif

#if HAVE_GETCONTEXT
  ucontext_t uc;
#endif

#if HAVE_SIGSTACK
  sigstack(NULL, &oss);
#endif

#if HAVE_GETCONTEXT
  getcontext(&uc);
#endif

  printf("Address of outer stack frame variable: 0x%x\n", p_outer_var);
  printf("Address of inner stack frame variable: 0x%x\n", &inner_var);
  printf("Address pointed to by argv:            0x%x\n", argv);
  printf("Address pointed to by envp:            0x%x\n", envp);

#if HAVE_ENVIRON
  printf("Address pointed to by environ:         0x%x\n", environ);
  printf("Address of environ:                    0x%x\n", &environ);
#endif

  printf("Address of errno:                      0x%x\n", &errno);

#if HAVE_SIGSTACK
  printf("Signal stack pointer from sigstack:    0x%x\n", oss.ss_sp);
#endif

#if HAVE_GETCONTEXT
  printf("Current stack pointer from getcontext: 0x%x\n", uc.uc_stack.ss_sp);
  printf("Stack pointer in main from getcontext: 0x%x\n", gcp);
#endif

  puts("");


#if HAVE_GETCONTEXT
  if (uc.uc_stack.ss_sp=gcp) {
    puts("getcontext returns constant stack pointerer.");
  }
#endif
  
  down_p=(unsigned long)p_outer_var > (unsigned long)(&inner_var);
  
  if (down_p) {
    puts("Stack grows down.");
  } else {
    puts("Stack grows up.");
  }
  
  if (stack_compare(argv, p_outer_var, down_p)) {
    puts("argv area is ahead of first stack frame.");
  }
  
  if (stack_compare(envp, p_outer_var, down_p)) {
    puts("envp area is ahead of first stack frame.");
  }
  
#if HAVE_ENVIRON
  if (stack_compare(environ, p_outer_var, down_p)) {
    puts("environ is ahead of first stack frame.");
  }

  if (stack_compare(&environ, p_outer_var, down_p)) {
    puts("address of environ is ahead of first stack frame.");
  }
#endif

  if (stack_compare(&errno, p_outer_var, down_p)) {
    puts("address of errno is ahead of first stack frame.");
  }

#if HAVE_SIGSTACK
  if (stack_compare(oss.ss_sp, p_outer_var, down_p)) {
    puts("sigstack stack pounsigned longer is ahead of first stack frame.");
  }
#endif
  
#if HAVE_GETCONTEXT
  if (stack_compare(uc.uc_stack.ss_sp, p_outer_var, down_p)) {
    puts("getcontext stack pounsigned longer is ahead of first stack frame.");
  }
#endif
}


int main (unsigned long argc, char **argv, char **envp)
{
  int outer_var;

#if HAVE_GETCONTEXT
  ucontext_t uc;

  getcontext(&uc);
#endif
  
  do_test(argv, envp, &outer_var, 
#if HAVE_GETCONTEXT
	  uc.uc_stack.ss_sp
#else
	  NULL
#endif
	  );


}