I want to catch SIGSEGV
signal and write on stdout
in which line did it occur. I guess i should use SA_SIGINFO
flag for sigaction
structure and use sa_sigaction
instead of sa_handler
because i get more information about the sginal. When SIGSEGV
occur in siginfo_t
structure the field si_addr
is filled with the address of the fault. What does this mean? Is that address in memory of variable or function that triggered SIGSEGV
?
I am learning from the book "The linux programming interface" but there is nothing about sa_sigaction
(only about sa_handler
), instead i have read about this on man pages.
#define _GNU_SOURCE
#include<string.h>
#include<stdio.h>
#include<stdlib.h>
#include<signal.h>
#include<unistd.h>
#include<limits.h>
#include<errno.h>
#include<sys/wait.h>
#include<sys/types.h>
#define osErrorFatal(userMsg) osErrorFatalImpl((userMsg),__FILE__,__func__,__LINE__)
#define osAssert(expr,userMsg)\
do{ if(!(expr)) {osErrorFatal(userMsg);} }while(0);
#define MAX_ARGUMENTS 10
void osErrorFatalImpl(char *userMsg,const char *fileName,const char *funcName,const int lineNum)
{
perror(userMsg);
fprintf(stderr,"File name: %s\nFunc name: %s\nLine num: %d\n",fileName,funcName,lineNum);
exit(EXIT_FAILURE);
}
void signal_handler(int sig, siginfo_t *info, void *ucontext)
{
fprintf(stdout,"Caught signal '%s'\n",strsignal(sig));
//now i want to print in which line SIGSEGV occured in child process
}
int main(int argc, char **argv)
{
if(argc<2)
{
fprintf(stderr,"Error: usage ./a.out file_path\n");
exit(EXIT_FAILURE);
}
char *programPath = NULL;
osAssert((programPath = realpath(argv[1],programPath)) != NULL, "realpath failed");
char *programArguments[argc];
programArguments[0] = strdup(strrchr(programPath, '/'));
int i;
for(i=1;i<argc-1;i++)
programArguments[i] = strdup(argv[i+1]);
programArguments[i] = NULL;
int childPid;
switch((childPid = fork()))
{
case -1: //error
osAssert(0,"fork failed");
case 0: //child branch
execvp(programPath, programArguments);
_exit(127);
default: //parent branch
{
struct sigaction sa;
sa.sa_flags = SA_SIGINFO;
sa.sa_sigaction = signal_handler;
osAssert(sigemptyset(&sa.sa_mask) != -1,"sigemptyset failed");
osAssert(sigaction(SIGSEGV,&sa,NULL) != -1, "sigaction failed");
wait(NULL);
exit(EXIT_SUCCESS);
}
}
}
This is the program that is triggering SIGSEGV
:
#define _GNU_SOURCE
#include<string.h>
#include<stdio.h>
#include<stdlib.h>
#include<signal.h>
#include<unistd.h>
#include<limits.h>
#include<errno.h>
#include<sys/wait.h>
#include<sys/types.h>
#define osErrorFatal(userMsg) osErrorFatalImpl((userMsg),__FILE__,__func__,__LINE__)
#define osAssert(expr,userMsg)\
do{ if(!(expr)) {osErrorFatal(userMsg);} }while(0);
#define MAX_ARGUMENTS 10
void osErrorFatalImpl(char *userMsg,const char *fileName,const char *funcName,const int lineNum)
{
perror(userMsg);
fprintf(stderr,"File name: %s\nFunc name: %s\nLine num: %d\n",fileName,funcName,lineNum);
exit(EXIT_FAILURE);
}
void signal_handler_child(int sig)
{
osAssert( kill(getppid(), sig) != -1,"kill failed");
exit(EXIT_FAILURE);
}
int main(int argc, char **argv)
{
struct sigaction sa;
sa.sa_handler = signal_handler_child;
sa.sa_flags = 0;
osAssert( sigemptyset(&sa.sa_mask) != -1,"sigemptyset failed");
osAssert( sigaction(SIGSEGV,&sa,NULL) != -1,"sigaction failed");
char *s=NULL;
printf("%s\n",s);
exit(EXIT_SUCCESS);
}
I know i can use gdb but i don't want to. I want to make parent process that will look out for his children.