Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Is there a way to return the address which caused SIGSEGV in C?

I am a C dummy and working on a C project which asked me to write a signal handler to catch SIGSEGV signal and perform some operations.

Basically, the main program will try to access a memory chunk that is neither readable or writable. When the main program access this chunk of memory it will raise a SIGSEGV signal, and in my signal handler function I will catch the signal and use mprotect() to convert that memory chunk into readable & writable.

But I don't know is there any way to get the address which caused SIGSEGV when signal is catched by my signal handler. I cannot do anything if I don't have the actual address which caused SIGSEGV. And I am not allowed to grab address from main into my signal handler.

can someone help me? Thanks!

like image 754
Zirui Bai Avatar asked Oct 16 '22 10:10

Zirui Bai


1 Answers

At least on Linux the answer is yes.

You use sigaction to register your signal handler, and you set the SA_SIGINFO flag and set a sa_sigaction handler.

This gives you access to a siginfo_t (second argument to your signal handler), which (among other things) contains a void *si_addr; field that (for SIGSEGV) contains the faulting address.

#define _POSIX_C_SOURCE 199309L
#include <signal.h>

void my_handler(int sig, siginfo_t *info, void *ucontext) {
    ... info->si_addr ...
}

...
struct sigaction act = {0};
act.sa_sigaction = my_handler;
act.sa_flags = SA_SIGINFO;
sigaction(SIGSEGV, &act, NULL);

See man 2 sigaction for details.

like image 165
melpomene Avatar answered Oct 21 '22 01:10

melpomene