The kernel does not pass the memory address which caused a SIGSEGV signal to the signal handler. The si_addr field in the siginfo_t structure. The field is always zero. This mechanism is used inconjunction with mmap to detect reads/writes to regions of memory by a process. For example, the following program should print "hello world", but it exits in the signal handler because the kernel passes in the si_addr field, instead of the address which was returned by mmap() in main(). Tom Geocaris /////////////////////// code /////////////////////////////// #include <stdio.h> #include <stdlib.h> #include <unistd.h> #include <fcntl.h> #include <sys/types.h> #include <sys/mman.h> #include <signal.h> void segv_handler( int sig, siginfo_t *info, void *user_context ); void install_signal_handlers(); static struct sigaction old_sigsegv; void install_signal_handlers() { struct sigaction action; sigaction( SIGSEGV, NULL, &old_sigsegv ); action = old_sigsegv; action.sa_sigaction = segv_handler; sigemptyset( &action.sa_mask ); action.sa_flags |= SA_SIGINFO; sigaction( SIGSEGV, &action, NULL ); } void segv_handler( int sig, siginfo_t *info, void *user_context ) { printf("SEGV at %x with type %d\n", info->si_addr, info->si_code ); if ( info->si_addr ) mprotect( info->si_addr, 4096, PROT_WRITE ); else exit(1); } main() { int fd; install_signal_handlers(); fd = open( "/dev/zero", O_RDWR ); if ( fd <= 0 ) { printf("Cannot open zero\n"); exit(1); } caddr_t b; b = (caddr_t) mmap( 0, 8192, PROT_NONE, MAP_PRIVATE|MAP_NORESERVE|MAP_ANON, fd, 0 ); close(fd); if ( b == (void *) -1 ) { printf("Cannot create mapping \n" ); exit(1); } *b = 1; printf( "hello world\n"); }
This feature should be in the 2.4 kernel.