#include <signal.h>
#include <stdio.h>

typedef long WamWord;


#if 0
void
SIGSEGV_Handler(int sig)
{
  /* LINUX: recovering the bad address...                       */
  /* There is no documented way to get the address that has     */
  /* caused SIGSEGV. I have looked at the sources of the kernel */
  /* (files from /usr/src/linux/arch/i386/)                     */
  /*                                                            */
  /* mm/fault.c:104:      current->tss.cr2 = address;           */
  /*    a bad address is found by the memory manager.           */
  /*                                                            */
  /* kernel/signal.c:203: put_user(current->tss.cr2, frame+23); */
  /*    a context pointed by 'frame' is created in the stack,   */
  /*    it contains the bad addess at +23.                      */
  /* Inside the handler SIGSEGV_Handler(int sig) the context    */
  /* (frame) can be found at &sig-1.                            */

  long *frame = (long *) &sig - 1;
  WamWord *addr = (WamWord *) (frame[+23]);

  printf("Segmentation Violation at: %lx\n", addr);
  exit(1);
}


#else

#include <asm/sigcontext.h>

#if 0
void
SIGSEGV_Handler(int sig, struct sigcontext_struct scp)
#else
void
SIGSEGV_Handler(int sig, struct sigcontext scp)
#endif
{
#if 1
  WamWord *addr = (WamWord *) scp.cr2;

  printf("Segmentation Violation at: %lx\n", addr);
#endif
  exit(1);
}

#endif


main()
{
  long *x;

  signal(SIGSEGV, (void (*)()) SIGSEGV_Handler);
  x = (long *) 0xffff040;
  *x = 12;

}
