/* systest v0.2 */
/* do NOT link statically ! */
/* usage: ./systest 2>/dev/null >interesting-data */
/* Changelog:
 *   0.2        error messages, mmap() /bin/sh if mmap() /dev/zero fails */


#include <fcntl.h>
#include <setjmp.h>
#include <signal.h>
#include <stdio.h>
#include <stdlib.h>
#include <sys/types.h>
#include <sys/mman.h>
#include <unistd.h>
#include <errno.h>
#include <string.h>


int stack_increment;
unsigned int *stack_top;
void *sbrk_start;
void *mmap_start;


jmp_buf env;


void SIGSEGVBUS_handler() {
  longjmp(env,1);
}

void probe_stack_growth(unsigned int *foo) {
  if (foo<(unsigned int *)&foo) {
    /* stack grows upwards */
    stack_increment=-1;
  } else {
    /* stack grows downwards */
    stack_increment=1;
  }
}


int bss;
int data=42;
const char* fn[]={"/dev/zero","/bin/sh"};


int main() {
  unsigned int i;
  unsigned int reported_errors;
  int fd;
  char *rodata="foobar";

  reported_errors=0;

  /* determine stack data */
  probe_stack_growth(&i);
  if (signal(SIGSEGV,(void (*)())SIGSEGVBUS_handler)==(void (*)(int))-1) {
    stack_top=(void *)-1;
    if (!reported_errors) {
      printf("----------------- errors report -----------------\n"); 
      reported_errors=1;
    }
    printf("signal(SIGSEGV,SISEGVBUS_handler): %d %s\n",errno,strerror(errno));
  } else {
    if (signal(SIGBUS,(void (*)())SIGSEGVBUS_handler)==(void (*)(int))-1) {
      stack_top=(void *)-1;
      if (!reported_errors) {
        printf("----------------- errors report -----------------\n"); 
        reported_errors=1;
      }
      printf("signal(SIGBUS,SISEGVBUS_handler): %d %s\n",errno,strerror(errno));
    } else {
      if (!setjmp(env)) {
        for (stack_top=&i;;stack_top+=stack_increment) {
          fprintf(stderr,"%lx\t-> 0x%x\n",(unsigned long)stack_top,*stack_top);
        }
      }
    }
  }
  
  /* determine heap data */
  sbrk_start=sbrk(0);
  if (((long int)sbrk_start)==-1) {
    if (!reported_errors) {
      printf("----------------- errors report -----------------\n"); 
      reported_errors=1;
    }
    printf("sbrk(0): %d %s\n",errno,strerror(errno));
  }

  /* determine mmap data */
  for (i=0;i<2;i++) {
    fd=open(fn[i],O_RDONLY,0);
    if (fd<0) {
      mmap_start=(void *)-1;
      if (!reported_errors) {
        printf("----------------- errors report -----------------\n"); 
        reported_errors=1;
      }
      printf("open(\"%s\",O_RDONLY,0): %d %s\n",fn[i],errno,strerror(errno));
    } else {
      mmap_start=mmap(0,0x4212,PROT_READ,MAP_PRIVATE,fd,0);
      if (((long int)mmap_start)==-1) {
        if (!reported_errors) {
          printf("----------------- errors report -----------------\n"); 
          reported_errors=1;
        }
        printf("mmap(0,0x4212,PROT_READ,MAP_PRIVATE,%d,0): %d %s\n",fd,errno,
               strerror(errno));
      }
    }
  }

  /* display results */
  printf("----------------- interesting data starts here -----------------\n"); 
  printf("code around 0x%lx\n",(unsigned long)probe_stack_growth);
  printf("rodata around 0x%lx\n",(unsigned long)rodata);
  printf("data around 0x%lx\n",(unsigned long)&mmap_start);
  printf("bss around 0x%lx\n",(unsigned long)&bss);
  printf("sbrk start around 0x%lx\n",(unsigned long)sbrk_start);
  printf("stack grows %s from 0x%lx\n",
         (stack_increment>0)?"downwards":"upwards",
         (unsigned long)stack_top);
  printf("shared libraries mapped around 0x%lx\n",(unsigned long)&errno);
  printf("mmap start around 0x%lx\n",(unsigned long)mmap_start);
  printf("uname -a: ");
  fflush(stdout);
  system("uname -a");

  return 0;
}