LinuxQuestions.org
Download your favorite Linux distribution at LQ ISO.
Home Forums Tutorials Articles Register
Go Back   LinuxQuestions.org > Forums > Non-*NIX Forums > Programming
User Name
Password
Programming This forum is for all programming questions.
The question does not have to be directly related to Linux and any language is fair game.

Notices


Reply
  Search this Thread
Old 06-02-2008, 04:51 AM   #1
telg
LQ Newbie
 
Registered: Dec 2007
Location: Australia
Posts: 13

Rep: Reputation: 0
Catching SIGSEGV - handelling segmentation faults


I have been messing around with signals lately and i was wondering if there is a nice simple way to pass arguments into a signal handler.

This is so it can tell you information about how the program died - almost throwing and catching exceptions in java. However, I can't find how the signal handeller will be able to take arguments from the location where the program crashed.
Code:
#include<signal.h>
#include<stdio.h>
void print(void)
{
        printf("%d\n",__LINE__);
        exit(-1);
}
int main(){
        signal(SIGSEGV,print);
        int x[2];
        x[1000000]=2;
}
but i want __LINE__ to be passed into print from where the program crashes

Does anyone know a method of doing this? Does one exist? If so, it could be very helpful for many...

Last edited by telg; 06-02-2008 at 04:53 AM.
 
Old 06-02-2008, 06:14 AM   #2
pinniped
Senior Member
 
Registered: May 2008
Location: planet earth
Distribution: Debian
Posts: 1,732

Rep: Reputation: 50
That's what a core file and debugger are for. You usually have to unwind the stack a bit (if the stack wasn't damaged) before you find the line in your program which was the initial cause of the problem (usually you pass a bad pointer to a library function).

What you want to do can be accomplished by changing a global variable, but it is cumbersome, ugly, and not very useful. Learning to use a debugger is far more useful and doesn't make your beautiful code look like Jabba the Hutt's mother.
 
Old 06-02-2008, 10:43 AM   #3
telg
LQ Newbie
 
Registered: Dec 2007
Location: Australia
Posts: 13

Original Poster
Rep: Reputation: 0
i see.
so the signal handler can only take in parameters of int and void but nothing else. hmm, i guess that answers no to any simple mechanism.
 
Old 06-02-2008, 04:33 PM   #4
osor
HCL Maintainer
 
Registered: Jan 2006
Distribution: (H)LFS, Gentoo
Posts: 2,450

Rep: Reputation: 78
Quote:
Originally Posted by telg View Post
i see.
so the signal handler can only take in parameters of int and void but nothing else. hmm, i guess that answers no to any simple mechanism.
Well, yes and no. First, a process cannot catch its own SIGSEGV AFAIK. For this, you need to be tracing the process (in e.g., a debugger).

If you use the newer signal functions (e.g, sigaction() rather than plain-old signal()), however, you can get a little more information passed to your handler besides the signal number itself. In particular, if you set the flag SA_SIGINFO, your signal catching function will need to have signature:
Code:
void func(int signo, siginfo_t *info, ucontext_t *context);
The siginfo_t structure contains information such as who (what PID) sent the signal and the address of the faulting instruction. The ucontext_t contains the context in which the process was before the signal was caught (this includes stack state and architecture-specific values).
 
Old 06-02-2008, 07:12 PM   #5
telg
LQ Newbie
 
Registered: Dec 2007
Location: Australia
Posts: 13

Original Poster
Rep: Reputation: 0
ok,

i gave this a try like this

Code:
#include<signal.h>
#include<stdio.h>
#include<string.h>
#include<ucontext.h>
void print(int sig, siginfo_t *info, ucontext_t *context)
{
        printf("%d\n",__LINE__);
        printf("%d %d %d\n",info->si_pid, info->si_addr, context->uc_stack);
        exit(-1);
}
int main(){
        struct sigaction sa;
        //sa.sa_handler=print;
        sa.sa_sigaction=print;// warning here: assignment from incompatible pointer type
        sa.sa_flags=SA_SIGINFO;
        sigaction(SIGSEGV,&sa,NULL);
        int x[2];
        x[10000000]=2;
}
gives output of

Code:
7
-1033747112 -1033747112 0
but i'm pretty sure that's not right.
Is this the correct usage of the handler and the related structures?
 
Old 06-02-2008, 08:17 PM   #6
pinniped
Senior Member
 
Registered: May 2008
Location: planet earth
Distribution: Debian
Posts: 1,732

Rep: Reputation: 50
As I said before, the simplest way to get the line number is to have extensive assignments to a global variable, so you can forget about which of your lines resulted in the fault. Plus, (as I've also said), the fault is very likely to be generated from within a call to a library, in which case you have no line number to refer to (unless you compiled yourself or used a version with the debug info not stripped + you have the source on hand).

Although sigaction does give you a lot more info, you have to build in some debugger features simply to display the info you want. The big question is: WHY? There is absolutely no advantage over a core file + debugger, or a debugger attached to a process. People have spent many years building features into debuggers, so use them. The only advantage I can think of is to give a partial stack trace which developers might hope to recover some useful information from, such as the case with Microsoft. But if you do that, be prepared to be inundated with useless bug reports.
 
Old 06-02-2008, 08:45 PM   #7
osor
HCL Maintainer
 
Registered: Jan 2006
Distribution: (H)LFS, Gentoo
Posts: 2,450

Rep: Reputation: 78
Quote:
Originally Posted by telg View Post
but i'm pretty sure that's not right.
Is this the correct usage of the handler and the related structures?
You haven’t addressed the point pinniped made (in particular, why not use a debugger). As for the correctness of the information, you are not guaranteed meaningful values for all struct members, and, additionally, you have to be able to interpret properly.

The statement:
Code:
printf("%d\n",__LINE__);
Will always print a 7, since __LINE__ is seven in that file. I am not sure how that was supposed to help you debug. The other information (such as pid is useless, since this signal was not generated by a kill() call).

When you use gdb (and compile with the greatest number of debugging symbols available), not only will it give you a stack trace, it will show the exact line number (and moreover, the exact assembly instruction) where the problem occurs.
 
Old 06-02-2008, 08:57 PM   #8
osor
HCL Maintainer
 
Registered: Jan 2006
Distribution: (H)LFS, Gentoo
Posts: 2,450

Rep: Reputation: 78
Btw, just for fun, here is a program which outputs the maximum possible amount of information which may be gleaned through siginfo (with the exception of the largely irrelevant floating-point state). It is targeted toward the i386 arch.
Code:
#include <signal.h>
#include <stdio.h>
#include <stdlib.h>
#include <ucontext.h>

static const char *gregs[] = {
	"GS",
	"FS",
	"ES",
	"DS",
	"EDI",
	"ESI",
	"EBP",
	"ESP",
	"EBX",
	"EDX",
	"ECX",
	"EAX",
	"TRAPNO",
	"ERR",
	"EIP",
	"CS",
	"EFL",
	"UESP",
	"SS"
};

void print(int sig, siginfo_t *info, void *c)
{
	ucontext_t *context = c;

	fprintf(stderr,
		"si_signo:  %d\n"
		"si_code:   %s\n"
		"si_errno:  %d\n"
		"si_pid:    %d\n"
		"si_uid:    %d\n"
		"si_addr:   %p\n"
		"si_status: %d\n"
		"si_band:   %ld\n",
		info->si_signo,
		(info->si_code == SEGV_MAPERR) ? "SEGV_MAPERR" : "SEGV_ACCERR",
		info->si_errno, info->si_pid, info->si_uid, info->si_addr,
		info->si_status, info->si_band
	);

	fprintf(stderr,
		"uc_flags:  0x%x\n"
		"ss_sp:     %p\n"
		"ss_size:   %d\n"
		"ss_flags:  0x%X\n",
		context->uc_flags,
		context->uc_stack.ss_sp,
		context->uc_stack.ss_size,
		context->uc_stack.ss_flags
	);

	fprintf(stderr, "General Registers:\n");
	for(int i = 0; i < 19; i++)
		fprintf(stderr, "\t%7s: 0x%x\n", gregs[i], context->uc_mcontext.gregs[i]);
	fprintf(stderr, "\tOLDMASK: 0x%x\n", context->uc_mcontext.oldmask);
	fprintf(stderr, "\t    CR2: 0x%x\n", context->uc_mcontext.cr2);

	exit(-1);
}

int main()
{
	struct sigaction sa;
	sigemptyset (&sa.sa_mask);
	sa.sa_flags = SA_SIGINFO;
	sa.sa_sigaction = print;

	sigaction(SIGSEGV, &sa, NULL);

	int x[2];
	x[10000000]=2;

	return 0;
}
I haven’t checked for complete correctness, but it passes the “works for me” test.

Last edited by osor; 06-02-2008 at 08:58 PM.
 
  


Reply



Posting Rules
You may not post new threads
You may not post replies
You may not post attachments
You may not edit your posts

BB code is On
Smilies are On
[IMG] code is Off
HTML code is Off



Similar Threads
Thread Thread Starter Forum Replies Last Post
Need help in catching and handling SIGSEGV signal janardhan@eilabs.com Programming 2 02-27-2008 05:08 AM
Help regarding SIGSEGV signal catching and handling it. janardhan@eilabs.com Linux - Software 1 02-27-2008 05:06 AM
Sigsegv - segmentation faul binda Linux - Hardware 1 03-31-2005 09:19 AM
SIGSEGV- segmentation fault during execution ashwinipahuja Programming 5 05-02-2004 10:02 PM

LinuxQuestions.org > Forums > Non-*NIX Forums > Programming

All times are GMT -5. The time now is 06:24 AM.

Main Menu
Advertisement
My LQ
Write for LQ
LinuxQuestions.org is looking for people interested in writing Editorials, Articles, Reviews, and more. If you'd like to contribute content, let us know.
Main Menu
Syndicate
RSS1  Latest Threads
RSS1  LQ News
Twitter: @linuxquestions
Open Source Consulting | Domain Registration