Unix/Linux C 异常处理的问题=============================================
来自网络的文章 --> 不断增加中, 如果文章作者不同意引用,请联系我: cj_9379@163.com
我会马上删除。
--------------------------------------------
19。
--------------------------------------------
18。
--------------------------------------------
17。
--------------------------------------------
16。
--------------------------------------------
15。
--------------------------------------------
14。
--------------------------------------------
13。
--------------------------------------------
12。
--------------------------------------------
11。
--------------------------------------------
10。
--------------------------------------------
9。
--------------------------------------------
8。
--------------------------------------------
7。
--------------------------------------------
6。
--------------------------------------------
5。
--------------------------------------------
4。
--------------------------------------------
3。
--------------------------------------------
2。 来源:
Linux下C++异常处理技巧-实例讲解
保留异常来源信息
在C++中,无论何时在处理程序内捕获一个异常,关于该异常来源的信息都是不为人知的。异常的具体来源可以提供许多更好地处理该异常的重要信息,或者提供一些可以附加到错误日志的信息,以便以后进行分析。
为了解决这一问题,可以在抛出异常语句期间,在异常对象的构造函数中生成一个堆栈跟踪。ExceptionTracer是示范这种行为的一个类。
清单 1. 在异常对象构造函数中生成一个堆栈跟踪
// Sample Program:
// Compiler: gcc
3.2.3 20030502
// Linux: Red Hat
#include
#include
#include
#include
using namespace
std;
/////////////////////////////////////////////
class
ExceptionTracer
{
public:
ExceptionTracer()
{
void *
array[25];
int nSize = backtrace(array, 25);
char ** symbols =
backtrace_symbols(array, nSize);
for (int i = 0; i < nSize;
i++)
{
cout << symbols[i] << endl;
}
free(symbols);
}
};
管理信号
每当进程执行一个令人讨厌的动作,以致于Linux?内核发出一个信号时,该信号都必须被处理。信号处理程序通常会释放一些重要资源并终止应用程序。在这种情况下,堆栈上的所有对象实例都处于未破坏状态。另一方面,如果这些信号被转换成
C++ 异常,那么您可以优雅地调用其构造函数,并安排多层 catch 块,以便更好地处理这些信号。
清单2中定义的SignalExceptionClass,提供了表示内核可能发出信号的C++异常的抽象。SignalTranslator 是一个基于
SignalExceptionClass 的模板类,它通常用来实现到
C++异常的转换。在任何瞬间,只能有一个信号处理程序处理一个活动进程的一个信号。因此,SignalTranslator 采用了 singleton
设计模式。整体概念通过用于 SIGSEGV 的 SegmentationFault 类和用于 SIGFPE 的 FloatingPointException
类得到了展示。
清单 2. 将信号转换成异常
template class
SignalTranslator
{
private:
class SingleTonTranslator
{
public:
SingleTonTranslator()
{
signal(SignalExceptionClass::GetSignalNumber(), SignalHandler);
}
static void SignalHandler(int)
{
throw
SignalExceptionClass();
}
};
public:
SignalTranslator()
{
static SingleTonTranslator
s_objTranslator;
}
};
// An example for SIGSEGV
class
SegmentationFault : public ExceptionTracer, public
exception
{
public:
static int GetSignalNumber() {return
SIGSEGV;}
};
SignalTranslator
g_objSegmentationFaultTranslator;
// An example for SIGFPE
class
FloatingPointException : public ExceptionTracer, public
exception
{
public:
static int GetSignalNumber() {return
SIGFPE;}
};
SignalTranslator
g_objFloatingPointExceptionTranslator;
管理构造函数和析构函数中的异常
: XML WebService完全实例详细解析
本文章共:3页
[1]
views:(0) | Comments:(0) | |
相关内容:
Linux下C++异常处理技巧-实例讲解
在全局(静态全局)变量的构造和析构期间,每个ANSI C++ 都捕获到异常是不可能的。因此,ANSI C++
不建议在那些其实例可能被定义为全局实例(静态全局实例)的类的构造函数和析构函数中抛出异常。换一种说法就是永远都不要为那些其构造函数和析构函数可能抛出异常的类定义全局(静态全局)实例。不过,如果假定有一个特定编译器和一个特定系统,那么可能可以这样做,幸运的是,对于
Linux 上的 GCC,恰好是这种情况。
使用ExceptionHandler类可以展示这一点,该类也采用了singleton设计模式。其构造函数注册了一个未捕获的处理程序。因为每次只能有一个未捕获的处理程序处理一个活动进程,构造函数应该只被调用一次,因此要采用singleton模式。应该在定义有问题的实际全局(静态全局)变量之前定义ExceptionHandler
的全局(静态全局)实例。
清单 3. 处理构造函数中的异常
class ExceptionHandler
{
private:
class
SingleTonHandler
{
public:
SingleTonHandler()
{
set_terminate(Handler);
}
static
void Handler()
{
// Exception from construction/destruction of global
variables
try
{
// re-throw
throw;
}
catch (SegmentationFault
&)
{
cout << "SegmentationFault" << endl;
}
catch
(FloatingPointException &)
{
cout << "FloatingPointException"
<< endl;
}
catch (...)
{
cout << "Unknown Exception"
<< endl;
}
//if this is a thread performing some core
activity
abort();
// else if this is a thread used to service
requests
//
pthread_exit();
}
};
public:
ExceptionHandler()
{
static
SingleTonHandler
s_objHandler;
}
};
//////////////////////////////////////////////////////////////////////////
class
A
{
public:
A()
{
//int i = 0, j = 1/i;
*(int *)0 =
0;
}
};
// Before defining any global variable, we define a dummy
instance
// of ExceptionHandler object to make sure that
//
ExceptionHandler::SingleTonHandler::SingleTonHandler() is
invoked
ExceptionHandler g_objExceptionHandler;
A
g_a;
//////////////////////////////////////////////////////////////////////////
int
main(int argc, char* argv[])
{
return 0;
}
处理多线程程序中的异常
: 网友原创:从N层到.NET详细剖析原理
本文章共:3页
[2]
views:(0) | Comments:(0) | |
相关内容:
Linux下C++异常处理技巧-实例讲解
有时一些异常没有被捕获,这将造成进程异常中止。不过很多时候,进程包含多个线程,其中少数线程执行核心应用程序逻辑,同时,其余线程为外部请求提供服务。如果服务线程因编程错误而没有处理某个异常,则会造成整个应用程序崩溃。这一点可能是不受人们欢迎的,因为它会通过向应用程序传送不合法的请求而助长拒绝服务攻击。为了避免这一点,未捕获处理程序可以决定是请求异常中止调用,还是请求线程退出调用。清单
3 中 ExceptionHandler::SingleTonHandler::Handler() 函数的末尾处展示了该处理程序。
结束语
我简单地讨论了少许 C++ 编程设计模式,以便更好地执行以下任务:
在抛出异常的时候追踪异常的来源。
将信号从内核程序转换成 C++ 异常。
捕获构造和/或析构全局变量期间抛出的异常。
多线程进程中的异常处理。
我希望您能采用这些技巧中的一些来开发无忧代码。
--------------------------------------------
1。 来源: http://www.xfocus.net/releases/200308/a589.html
内核处理信号对应用层堆栈的影响
创建时间:2003-08-13
文章属性:原创
文章提交:alert7
(sztcww_at_sina.com)
内核处理信号对应用层堆栈的影响
by alert7 <
alert7@xfocus.org >
主页:
http://www.xfocus.org/
时间:2003年8月1日
好久没有为组织做点贡献了,真有点过意不去:(
本文着重点在内核信号处理对应用层堆栈的影响上,其他的一些在处理信号细节上被忽略。
至于本文是否跟安全相关,那就是仁者见仁智者见智了。
1
发送信号过程:
发送信号的过程比接收信号的过程简单的多。当应用层用KILL命令向某个进程发送进程的时候,
内核只在进程task_struct的sigpending结构中安排一个信号位。
2
接收信号过程
信号处理的时机。
当某个进程有悬而未决的信号的时候,内核就会调用do_signal函数
do_signal做一些其他功能上的事情,真正递送一个信号是在handle_signal函数。于是在最后
do_signal函数调用了handle_signal真正递送一个信号。当然要想到达这一步需要一些条件。比如说
应用层已经声明要处理该信号,信号不是些不可捕获的信号等等...
重点中的重点,我们来看看handle_signal函数
/*
*
OK, we're invoking a handler
*/
static
void
handle_signal(unsigned long sig, struct k_sigaction
*ka,
siginfo_t *info, sigset_t *oldset, struct pt_regs *
regs)
{
....
/* Set up the stack frame */
if
(ka->sa.sa_flags & SA_SIGINFO)
setup_rt_frame(sig, ka, info,
oldset, regs);
else
setup_frame(sig, ka, oldset,
regs);
.....
}
去掉一些我们不想关心的东西,代码就剩下上面这些。
以上函数setup_rt_frame和setup_frame就是内核在应用层的堆栈上安排信号堆栈帧的过程,就是我们所
要关注的。setup_rt_frame和setup_frame雷同,我们就来分析下setup_frame函数。
static
void setup_frame(int sig, struct k_sigaction *ka,
sigset_t *set,
struct pt_regs * regs)
{
struct sigframe *frame;
int err =
0;
frame = get_sigframe(ka, regs, sizeof(*frame));
//决定要使用应用层堆栈的地址
if (!access_ok(VERIFY_WRITE, frame, sizeof(*frame)))
//判断是否可写
goto give_sigsegv;
err |=
__put_user((current->exec_domain
&&
current->exec_domain->signal_invmap
&& sig
< 32
?
current->exec_domain->signal_invmap[sig]
:
sig),
&frame->sig);
if (err)
goto
give_sigsegv;
/*保存寄存器信号到&frame->sc和&frame->fpstate中*/
err
|= setup_sigcontext(&frame->sc, &frame->fpstate, regs,
set->sig[0]);
if (err)
goto give_sigsegv;
if
(_NSIG_WORDS > 1) {
err |= __copy_to_user(frame->extramask,
&set->sig[1],
sizeof(frame->extramask));
}
if
(err)
goto give_sigsegv;
/* Set up to return from
userspace. If provided, use a stub
already in
userspace. */
if (ka->sa.sa_flags & SA_RESTORER) {
err
|= __put_user(ka->sa.sa_restorer, &frame->pretcode);
} else
{
/*把frame->retcod的地址放到&frame->pretcode中,这样当信号处理函数返回时候就会*/
/*跳到frame->retcode地址去执行代码了*/
err
|= __put_user(frame->retcode, &frame->pretcode);
/* This is
popl %eax ; movl $,%eax ; int $0x80 */
err |= __put_user(0xb858,
(short *)(frame->retcode+0));
err |= __put_user(__NR_sigreturn,
(int *)(frame->retcode+2));
err |= __put_user(0x80cd, (short
*)(frame->retcode+6));
/*以上在frame->retcode上安排了popl %eax ; movl
$,%eax ; int $0x80指令*/
}
if (err)
goto
give_sigsegv;
/* Set up registers for signal handler
*/
regs->esp = (unsigned long) frame;
//让应用层的esp指向frame;
regs->eip = (unsigned long)
ka->sa.sa_handler;//EIP为信号处理函数
set_fs(USER_DS);
regs->xds
= __USER_DS;
regs->xes = __USER_DS;
regs->xss =
__USER_DS;
regs->xcs = __USER_CS;
regs->eflags &=
~TF_MASK;
#if DEBUG_SIG
printk("SIG deliver (%s:%d): sp=%p pc=%p
ra=%p\n",
current->comm, current->pid, frame, regs->eip,
frame->pretcode);
#endif
return;
give_sigsegv:
if
(sig == SIGSEGV)
ka->sa.sa_handler =
SIG_DFL;
force_sig(SIGSEGV,
current);
}
到此,内核在应用层的堆栈上就安排了一个帧,我们来看一下一个实际的例子。
[alert7@redhat73
sigal]$ cat test.c
test
()
{
printf("test");
return;
}
int
main(int argv,char **argc) {
char
buf[256];
signal(10,test);
while(1);
}
[alert7@redhat73]
(gdb)
b main
Breakpoint 1 at 0x8048501
(gdb) r dd dd
Starting program:
/home/alert7/sigal/test dd dd
Breakpoint 1, 0x08048501 in main
()
(gdb)
Breakpoint 2 at 0x42029098
(gdb)
c
Continuing.
(gdb) x/5i 0x42029098
0x42029098 <__restore>:
pop %eax
0x42029099 <__restore+1>:
mov $0x77,%eax
0x4202909e <__restore+6>:
int $0x80
0x420290a0 <__restore+8>:
mov (%esp,1),%ebx
0x420290a3 <__restore+11>: ret
(gdb) i reg
esp ebp eip
esp 0xbffff748
0xbffff748
ebp 0xbffffb38
0xbffffb38
eip 0x4202909e 0x4202909e
(gdb) x/50x $esp-8
//$esp-8就是内核构造的一个信号帧
0xbffff740:
0x42029098 0x0000000a 0x00000000 0x00000000
0xbffff750:
0x0000002b 0x0000002b 0xbffffba4 0x40013020
0xbffff760:
0xbffffb38 0xbffffa20 0x4213030c 0xbffffc00
0xbffff770:
0x08049752 0xbffffb2c 0x00000001 0x00000000
0xbffff780:
0x08048570 0x00000023 0x00000346 0xbffffa20
0xbffff790:
0x0000002b 0x00000000 0x00000000 0x00000000
0xbffff7a0:
0x4000083e 0x400005b8 0x40000218 0x400131e8
0xbffff7b0:
0x00000003 0x40013e48 0x00000003 0x42009e38
0xbffff7c0:
0x40013d68 0x0d1fc7ae 0x0d1fc7ae 0xbffff890
0xbffff7d0:
0x40013bc8 0x4200f624 0x00000000 0x00000000
0xbffff7e0:
0x42009e38 0x40013bc8 0x00000000 0x00000000
0xbffff7f0:
0x00000000 0x00000000 0x00000000 0x00000000
0xbffff800:
0x00000000 0x00000000
struct sigframe
{
char
*pretcode; //这里为0x42029098,在该程序中,ka->sa.sa_flags 有
SA_RESTORER标志,
//所以没有在堆栈中安排指令,而是使用了一个现成的地址
int
sig; //信号为10
struct sigcontext sc;
struct _fpstate
fpstate;
unsigned long extramask[_NSIG_WORDS-1];
char
retcode[8];
};
struct sigcontext {
unsigned short gs,
__gsh;//0,0
unsigned short fs, __fsh;//0,0
unsigned short es,
__esh;//0x2b,0
unsigned short ds, __dsh;//0x2b,0
unsigned long
edi; //0xbffffba4
unsigned long
esi; //0x40013020
unsigned long
ebp; //0xbffffb38
unsigned long
esp; //0xbffffa20
unsigned long
ebx; //0x4213030c
unsigned long
edx; //0xbffffc00
unsigned long
ecx; //0x08049752
unsigned long
eax; //0xbffffb2c
unsigned long
trapno; //0x00000001
unsigned long
err; //0x00000000
unsigned long
eip; //0x08048570
unsigned short cs,
__csh; //0x23,0
unsigned long
eflags; //0x00000346
unsigned long
esp_at_signal; //0xbffffa20
unsigned short ss,
__ssh; //0x2b,0
struct _fpstate *
fpstate; //0x00000000
unsigned long
oldmask; //0x00000000
unsigned long
cr2; //0x00000000
};
内核在应用层的堆栈上安了一个帧后,当一返回到应用态的时候就跳到信号处理函数test去执行了。
此时图一
①,应用层的堆栈多了一个帧,如下:
**********************************************************************************
图一
(内存高址)
+--------------------------------------+
|
... |
+--------------------------------------+
|
char retcode[8] | 8个字节
+--------------------------------------+
| long
extramask[_NSIG_WORDS-1];
|
+--------------------------------------+
| struct
_fpstate fpstate;
|
+--------------------------------------+
| struct
sigcontext sc;
|
+--------------------------------------+ <---------esp指向这里
③
| int sig;
|
+--------------------------------------+ <---------esp指向这里
②
| char *pretcode;
|
+--------------------------------------+ <---------esp指向这里
①
| ... |
+--------------------------------------+
(内存低址)
**********************************************************************************
由于内核是让应用程序跳到信号处理函数的,所以不象一般的调用会把当前的EIP压入堆栈,所以现在
esp指向的pretcode的值将来信号处理完就返回到那里去了。此时ESP情况如图一
②
的情况
当test信号处理函数完成时候,将返回到frame->pretcode也就是0x42029098的地址去执行,在这里0x42029098地址代码如下:
0x42029098
<__restore>: pop %eax //弹出frame->sig,这里为10
0x42029099
<__restore+1>: mov $0x77,%eax
0x4202909e
<__restore+6>:
int $0x80 //请求sys_sigreturn系统调用
当执行完以上三条指令的时候,应用层的堆栈就变成了 ③
的情况了。
忽略切入内核的细节,sys_sigreturn系统调用被调用。下面是该函数的实现细节。
asmlinkage int
sys_sigreturn(unsigned long __unused)
{
struct pt_regs *regs = (struct
pt_regs *) &__unused;
struct sigframe *frame = (struct sigframe
*)(regs->esp -
8);//取得frame地址,-8是为了补上ret和pop
//这两个指令分别弹出的pretcode和sig
//看看上面的图会更清楚
sigset_t
set;
int eax;
if (verify_area(VERIFY_READ, frame,
sizeof(*frame)))
goto badframe;
if (__get_user(set.sig[0],
&frame->sc.oldmask)
|| (_NSIG_WORDS >
1
&& __copy_from_user(&set.sig[1],
&frame->extramask,
sizeof(frame->extramask))))
goto
badframe;
sigdelsetmask(&set,
~_BLOCKABLE);
spin_lock_irq(¤t->sigmask_lock);
current->blocked
=
set;
recalc_sigpending(current);
spin_unlock_irq(¤t->sigmask_lock);
/*把frame保存的一些信息恢复出来,修改regs一些寄存器*/
if
(restore_sigcontext(regs, &frame->sc, &eax))
goto
badframe;
return eax;
badframe:
force_sig(SIGSEGV,
current);
return
0;
}
restore_sigcontext函数好象也没有什么好说的,等到sys_sigreturn函数返回,regs的一些寄存器又恢复到信号来之前的值了。
所以等到内核态在返回到应用态的时候,又恢复到原来的地址去执行了。
参考资料:
linux
2.4.18 kernel src
-------the end--------
--------------------------------------------
0。 来源: http://blog.chinaunix.net/u1/44989/showart_355920.html
修改信号处理函数 -- sigaction
|
|
|
程序在运行的时候经常会收到系统或其他进程发过来的信号,有时候我们希望改变对信号的缺省处理,这时候就需要使用信号处理程序了。
#include <signal.h> int sigaction(int
signum, const struct sigaction *act, struct sigaction *oldact);
struct sigaction { void (*sa_handler)(int); void (*sa_sigaction)(int,
siginfo_t *, void *); sigset_t sa_mask; int sa_flags; void (*sa_restorer)(void); }
|
man手册上说sa_handler和sa_sigaction在某些系统是作为union实现的,不能一起使用。
不过对我们来说只需要其中一个,信号处理函数或者定义成sa_handler形式或者sa_sigaction形式,完全根据我们程序的需要来定。按照POSIX的说法,sa_sigaction的第三个参数可以被转换成类型为 ucontext_t并指向信号发送时线程执行的上下文。而 中另外定义了对ucontext的处理函数getcontext(),
setcontext(), makecontext() 以及 swapcontext().
man手册上说sa_restorer属于一个被废弃的域。
sa_handler可以接受SIG_DFL(缺省处理)或者SIG_IGN(忽略该信号)。
sa_mask
定义了在此信号处理程序执行时,哪些信号可以被阻塞住。
sa_flags指定了一系列信号处理程序的选项: SA_NOCLDSTOP
不处理信号SIGCHLD.
SA_ONESHOT 或
SA_RESETHAND 信号处理程序只使用一次。
SA_ONSTACK
只在特定的调用栈中使用此处理程序,该调用栈由sigaltstack()指定。
SA_RESTART 为了兼容BSD信号的语义
SA_NOMASK
or SA_NODEFER
缺省情况下触发信号处理程序的信号在处理期间会被阻塞,如果在sa_flags定义了SA_NODEFER或者SA_NOMASK就不再阻塞。
SA_SIGINFO 信号处理程序时使用3各参数,见sa_sigaction(after Linux
2.1.86).
下面是结构siginfo_t的定义:
siginfo_t { int si_signo; /* for
all signals. Signal number */ int si_errno; /* for
all signals. An errno value */ nt si_code; /* for
all signals. why this signal occur */ pid_t si_pid; /*
Sending process ID */ uid_t si_uid; /* Real
user ID of sending process */ int si_status; /* Exit
value or signal */ lock_t si_utime; /* User
time consumed */ clock_t
si_stime; /* System time consumed */ sigval_t
si_value; /* Signal value */ int si_int; /*
POSIX.1b signal */ void
* si_ptr; /*
POSIX.1b signal */ void
* si_addr; /*
Memory location which caused fault */ int si_band; /* Band
event */ int si_fd; /* File
descriptor */ }
|
下面是使用sigaction处理SIGUSR1并且打印当前调用栈的代码。要注意的就是如果要在你的程序里引用sigsegv.h、sigsegv.c得到堆栈信息的话记得加上-rdynamic
-ldl参数
sigsegv.h
#ifndef __sigsegv_h__ #define __sigsegv_h__
#ifdef __cplusplus extern "C" { #endif
int setup_sigsegv();
#ifdef __cplusplus } #endif
#endif /*
__sigsegv_h__
*/
|
sigsegv.c
#define _GNU_SOURCE #include <memory.h> #include <stdlib.h> #include <stdio.h> #include <signal.h> #include <ucontext.h> #include <dlfcn.h> #include <execinfo.h> #ifndef NO_CPP_DEMANGLE #include <cxxabi.h> #endif
#if
defined(REG_RIP) # define SIGSEGV_STACK_IA64 # define REGFORMAT "%016lx" #elif defined(REG_EIP) # define SIGSEGV_STACK_X86 # define REGFORMAT "%08x" #else # define SIGSEGV_STACK_GENERIC # define REGFORMAT "%x" #endif
static void signal_segv(int
signum, siginfo_t* info, void*ptr) { static const char *si_codes[3]
= {"", "SEGV_MAPERR", "SEGV_ACCERR"};
size_t i; ucontext_t *ucontext = (ucontext_t*)ptr;
#if
defined(SIGSEGV_STACK_X86) ||
defined(SIGSEGV_STACK_IA64) int f = 0; Dl_info dlinfo; void **bp
= 0; void *ip = 0; #else void *bt[20]; char **strings; size_t sz; #endif
fprintf(stderr, "Segmentation Fault!\n"); fprintf(stderr, "info.si_signo = %d\n", signum); fprintf(stderr, "info.si_errno = %d\n", info->si_errno); fprintf(stderr, "info.si_code = %d (%s)\n", info->si_code, si_codes[info->si_code]); fprintf(stderr, "info.si_addr = %p\n", info->si_addr); for(i =
0; i <
NGREG; i++) fprintf(stderr, "reg[%02d] = 0x" REGFORMAT "\n", i,
ucontext->uc_mcontext.gregs[i]);
#if
defined(SIGSEGV_STACK_X86) ||
defined(SIGSEGV_STACK_IA64) # if
defined(SIGSEGV_STACK_IA64) ip = (void*)ucontext->uc_mcontext.gregs[REG_RIP]; bp = (void**)ucontext->uc_mcontext.gregs[REG_RBP]; # elif defined(SIGSEGV_STACK_X86) ip = (void*)ucontext->uc_mcontext.gregs[REG_EIP]; bp = (void**)ucontext->uc_mcontext.gregs[REG_EBP]; # endif
fprintf(stderr, "Stack
trace:\n"); while(bp &&
ip) { if(!dladdr(ip,
&dlinfo)) break;
const char *symname = dlinfo.dli_sname; #ifndef NO_CPP_DEMANGLE int status; char *tmp = __cxa_demangle(symname, NULL, 0,
&status);
if(status == 0
&&
tmp) symname = tmp; #endif
fprintf(stderr, "% 2d:
%p <%s+%u> (%s)\n", ++f, ip, symname, (unsigned)(ip
- dlinfo.dli_saddr), dlinfo.dli_fname);
#ifndef NO_CPP_DEMANGLE if(tmp) free(tmp); #endif
if(dlinfo.dli_sname &&
!strcmp(dlinfo.dli_sname, "main")) break;
ip = bp[1]; bp = (void**)bp[0]; } #else fprintf(stderr, "Stack
trace (non-dedicated):\n"); sz = backtrace(bt,
20); strings = backtrace_symbols(bt,
sz);
for(i =
0; i < sz; ++i) fprintf(stderr, "%s\n", strings[i]); #endif fprintf(stderr, "End of
stack trace\n"); exit (-1); }
int setup_sigsegv()
{ struct sigaction action; memset(&action, 0,
sizeof(action)); action.sa_sigaction = signal_segv; action.sa_flags = SA_SIGINFO; if(sigaction(SIGSEGV, &action, NULL) < 0)
{ perror("sigaction"); return 0; }
return 1; }
#ifndef SIGSEGV_NO_AUTO_INIT static void __attribute((constructor))
init(void) { setup_sigsegv(); } #endif
|
#include "sigsegv.h" #include <string.h>
int die()
{ char *err = NULL; strcpy(err, "gonner"); return 0; }
int main()
{ return die(); }
|
其中,dladdr()是Glibc的扩展函数,在POSIX中并没有定义。
#define _GNU_SOURCE
#include <dlfcn.h> int dladdr(void *addr, Dl_info *info); void *dlvsym(void *handle, char *symbol, char *version);
typedef struct { const char *dli_fname;/*
Filename of defining object */ void *dli_fbase; /* Load
address of that object */ const char *dli_sname;/* Name
of nearest lower symbol */ void *dli_saddr; /*
Exact value of nearest symbol */
} Dl_info;
| reference: http://blog.chinaunix.net/u/3425/showart_263408.html
| |