/* Orion Lawlor's Short UNIX Examples, olawlor@acm.org 2004/2/16

Shows how to use a signal handler with mprotect
to set and reset memory protection.  This is useful for
weird memory tricks like software distributed shared 
memory.
*/
#include <stdio.h>
#include <stdlib.h>
#include <sys/types.h>
#include <sys/mman.h>
#include <signal.h>
#include <unistd.h>
#ifdef SOLARIS /* needed with at least Solaris 8 */
#include <siginfo.h>
#endif

char mem[128*1024];
int pagesize;
char *where; /* pagesize-aligned pointer into "where" */

void handler(int cause, siginfo_t *HowCome, void *uap) {
        printf( "SIGSEGV raised at address %p\n", HowCome->si_addr);

        if (mprotect(where, pagesize, PROT_READ | PROT_WRITE)) {
                perror("mprotect");
                exit(1);
        }
}

int main(){ 
/* Install our signal handler */
        struct sigaction sa;

        sa.sa_sigaction = handler;
        sigemptyset( &sa.sa_mask );
        sa.sa_flags = SA_SIGINFO;
        if (sigaction (SIGSEGV, &sa, 0)) {
                perror("sigaction");
                exit(1);
        }

/* Find a page-aligned piece of memory */
        pagesize = sysconf(_SC_PAGESIZE);
        where = (char *)(((long) (mem + pagesize-1) / pagesize) * pagesize);
        *where = 'f';
        printf( "address %p contains '%c'\n", where, *where);
	
/* Make memory read-only */
        if (mprotect(where, pagesize, PROT_READ)) {
                perror("mprotect");
                exit(1);
        }

/* Perform a write to the memory, which should segfault.
   Our signal handler will make the memory read/write, which
   should let the write continue. 
*/
        printf( "About to write 'a'\n");
        *where = 'a';
        printf( "address %p contains '%c'\n", where, *where);

/* Now do another write-- we shouldn't get any segfault. */
        printf( "About to write 'b'\n");
        *where = 'b';
        printf( "address %p contains '%c'\n", where, *where);

        return(0);
}

/*<@>
<@> ******** Program output: ********
<@> address 0x602000 contains 'f'
<@> About to write 'a'
<@> SIGSEGV raised at address 0x602000
<@> address 0x602000 contains 'a'
<@> About to write 'b'
<@> address 0x602000 contains 'b'
<@> */
