diff options
Diffstat (limited to 'semestr-5/so/lista2/so21_lista_2/demand.c')
-rw-r--r-- | semestr-5/so/lista2/so21_lista_2/demand.c | 83 |
1 files changed, 83 insertions, 0 deletions
diff --git a/semestr-5/so/lista2/so21_lista_2/demand.c b/semestr-5/so/lista2/so21_lista_2/demand.c new file mode 100644 index 0000000..d4ae715 --- /dev/null +++ b/semestr-5/so/lista2/so21_lista_2/demand.c @@ -0,0 +1,83 @@ +#include "csapp.h" + +/* First address of handled region. */ +#define ADDR_START ((void *)0x10000000) +/* Last address of handled region (not inclusive). */ +#define ADDR_END ((void *)0x10010000) + +static size_t pagesize; + +/* Maps anonymouse page with `prot` access permissions at `addr` address. */ +static void mmap_page(void *addr, int prot) { + Mmap(addr, pagesize, prot, MAP_ANONYMOUS | MAP_PRIVATE | MAP_FIXED, -1, 0); +} + +/* Changes protection bits to `prot` for page at `addr` address. */ +static void mprotect_page(void *addr, int prot) { + Mprotect(addr, pagesize, prot); +} + +static void sigsegv_handler(int signum, siginfo_t *info, void *data) { + ucontext_t *uc = data; + // intptr_t rip; + + /* TODO: You need to get value of instruction pointer register from `uc`. + * Print all useful data from `info` and quit in such a way that a shell + * reports program has been terminated with SIGSEGV. */ + + #define REG_RIP 16 + + intptr_t fault_instr = uc->uc_mcontext.gregs[REG_RIP]; + intptr_t fault_address = (intptr_t)info->si_addr; + intptr_t fault_page = fault_address / pagesize * pagesize; + + safe_printf("Fault at rip=%lx, accessing %lx! ", fault_instr, fault_address); + if ((void *)fault_address < ADDR_START || (void *)fault_address >= ADDR_END) { + safe_printf("Address not mapped - terminating!\n"); + _exit(128 + SIGSEGV); + } + + switch(info->si_code) { + case SEGV_MAPERR: + safe_printf("Map missing page at %lx.\n", fault_page); + mmap_page((void *)fault_page, PROT_READ); + break; + + case SEGV_ACCERR: + safe_printf("Make page at %lx writable.\n", fault_page); + mprotect_page((void *)fault_page, PROT_READ | PROT_WRITE); + break; + + default: + safe_printf("Uknkonw code: %d.\n", info->si_code); + _exit(128 + SIGSEGV); + } +} + +int main(int argc, char **argv) { + pagesize = sysconf(_SC_PAGESIZE); + + /* Register signal handler for SIGSEGV */ + struct sigaction action = {.sa_sigaction = sigsegv_handler, + .sa_flags = SA_SIGINFO}; + sigaction(SIGSEGV, &action, NULL); + + /* Initially all pages in the range are either not mapped or readonly! */ + for (void *addr = ADDR_START; addr < ADDR_END; addr += pagesize) + if (random() % 2) + mmap_page(addr, PROT_READ); + + /* Generate lots of writes to the region. */ + volatile long *array = ADDR_START; + long nelems = (ADDR_END - ADDR_START) / sizeof(long); + + for (long i = 0; i < nelems * 2; i++) { + long index = random() % nelems; + array[index] = (long)&array[index]; + } + + /* Perform off by one access - triggering a real fault! */ + array[nelems] = 0xDEADC0DE; + + return EXIT_SUCCESS; +} |