Warning: file_get_contents(/data/phpspider/zhask/data//catemap/6/cplusplus/159.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181

Warning: file_get_contents(/data/phpspider/zhask/data//catemap/4/unix/3.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C++ 获取生成UNIX信号的故障地址_C++_Unix_Signals - Fatal编程技术网

C++ 获取生成UNIX信号的故障地址

C++ 获取生成UNIX信号的故障地址,c++,unix,signals,C++,Unix,Signals,我感兴趣的是一个信号处理器,它可以识别导致问题的指令的地址 我知道siginfo\u t和\u内置返回地址,这两种方法似乎都不起作用: #include <iostream> #include <signal.h> void handler (int, siginfo_t *, void *); int main () { begin: std :: cerr << &&begin << " ~ " << &

我感兴趣的是一个信号处理器,它可以识别导致问题的指令的地址


我知道
siginfo\u t
\u内置返回地址
,这两种方法似乎都不起作用:

#include <iostream>
#include <signal.h>

void handler (int, siginfo_t *, void *);

int main ()
{
begin:
    std :: cerr << &&begin << " ~ " << &&before << " ~ " << &&after << "\n";

    struct sigaction s;
    s .sa_flags = SA_SIGINFO;
    sigemptyset (& s .sa_mask);
    s .sa_sigaction = handler;
    sigaction (SIGSEGV, &s, NULL);

    int * i = NULL;
before:
    *i = 0;
after:
    std :: cout << "End.\n";
}

void handler (int, siginfo_t *si, void *)
{
    std :: cerr << "si:" << si -> si_addr << "\n";
    std :: cerr << "At: " << __builtin_return_address (0) << "\n";
    std :: cerr << "At: " << __builtin_return_address (1) << "\n";
    std :: cerr << "At: " << __builtin_return_address (2) << "\n";
    std :: cerr << "At: " << __builtin_return_address (3) << "\n";
    std :: cerr << "At: " << __builtin_return_address (4) << "\n";
    std :: cerr << "At: " << __builtin_return_address (5) << "\n";
}

因此,
siginfo\u t
为空,
\u内置\u返回\u地址
在命名标签之间的某处生成值

我希望这两个函数都返回
&&before
的值。我是否正确使用了这些函数


在Linux 2.6.9-89.0.9.Elsmp和SunOS上测试。

siginfo\u t将无法工作,因为不是执行该操作的指令的地址


现在,
\uuuuuu内置返回地址
很有趣。在我的机器上,它返回一些废话:

0x40089f ~ 0x400935 ~ 0x40093f
si:0
At: 0x7fe22916fc20
At: 0x7fe22915ad8e
我不知道为什么。但随后我检查了堆芯转储:

(gdb) bt
#0  0x00000000004009ff in handler(int, siginfo*, void*) ()
#1  <signal handler called>
#2  0x0000000000400939 in main ()
(gdb)bt
#处理程序中的0 0x00000000004009ff(int,siginfo*,void*)()
#1  
#2 0x0000000000400939位于主()
正如您所看到的,就像您的情况一样,违规地址位于标签位置之间的某个位置。不过,这很容易解释。只需查看main()的分解:

(gdb)disas
主功能的汇编程序代码转储:
...
; 标签如下:
0x00000000000400935:mov-0x8(%rbp),%rax
=>0x000000000040939:movl$0x0,(%rax)
0x0000000000040093F:mov$0x400c32,%esi

带标签的语句由几个指令组成。第一个将地址加载到RAX寄存器中。它成功地完成了,因为它没有任何问题。它是第二个访问地址并中断的。这解释了为什么跟踪中的地址与标签的地址略有不同,尽管代码可能与我的示例不同。不过,这并不能解释为什么在我的例子中,
\u内置返回地址
毫无意义。

安装了
SA\u SIGINFO
(声明为
void*
)的处理程序的第三个参数是指向
ucontext\u t
结构的指针。此结构的内容是特定于体系结构和操作系统的,不是任何标准的一部分,但它们包含您需要的信息。下面是一个适合使用它的程序版本(特定于Linux/x86-64;对于每个感兴趣的体系结构和操作系统,您都需要
#ifdef
s):


查看优化版本中所有标签如何位于同一地址?这将使任何尝试都失败,比如说,通过调整PC从故障中恢复。IIRC有一种方法可以使GCC不这样做,但我不知道它是什么,也无法在手册中找到它。

\uuuu内置返回地址
,当使用任何非零参数调用时,假设存在帧指针链。这不是x86-64所要求的,即使您强制编译器生成一个,内核生成的特殊“信号处理程序调用方”框架也会打破这个链条。这可能是有用的。请记住,另一个进程可以向这个进程发送信号,因此“错误地址”可能不会告诉您任何重要的信息。OTOH,这是一个不太可能发生的事件。@Jonathan:对于实时信号(
sigaction
with
SA_SIGINFO
SIGINFO_t
),内核需要防止欺骗。
siginfo\u t
中有一个字段告诉信号源,
sigqueue
不能将信号源冒充为内核。试图通过调整PC从故障中恢复将进入危险的未定义行为区。你可以尝试
longjmp
找出一段已知的代码,但即使这样也可能充满危险;最好的选择是转储核心并死亡。@Adam:您可以
mmap
在失败访问的地址上方添加新的内容,然后返回。这可能是一个可行的解决方案,可以从截断的MMAP文件、过度提交等方面解决
SIGSEGV
SIGBUS
问题。确实如此,但同时,这也是人们真正需要做的事情,并且通常可以根据自己的目的可靠地工作。例如,持久对象数据库和GC写入障碍通常会导致这些问题。(不过,我不知道有谁会依赖标签扩展的GCC地址。)@R你不需要为此调整电脑(我同意它的危险性较小)
(gdb) bt
#0  0x00000000004009ff in handler(int, siginfo*, void*) ()
#1  <signal handler called>
#2  0x0000000000400939 in main ()
(gdb) disas
Dump of assembler code for function main:
   ...
   ; the label is here:
   0x0000000000400935 <+161>:   mov    -0x8(%rbp),%rax
=> 0x0000000000400939 <+165>:   movl   $0x0,(%rax)
   0x000000000040093f <+171>:   mov    $0x400c32,%esi
#define _GNU_SOURCE 1
#include <iostream>
#include <iomanip>
#include <signal.h>
#include <ucontext.h>

using std::cout;

static volatile int *causecrash;

static void handler(int, siginfo_t *si, void *ptr)
{
   ucontext_t *uc = (ucontext_t *)ptr;

   cout << "si:" << si->si_addr << '\n';
   cout << "ip:" << std::hex << uc->uc_mcontext.gregs[REG_RIP] << '\n';
}

int main()
{
begin:
    cout.setf(std::ios::unitbuf);
    cout << &&begin << " ~ " << &&before << " ~ " << &&after << '\n';

    struct sigaction s;
    s.sa_flags = SA_SIGINFO|SA_RESETHAND;
    s.sa_sigaction = handler;
    sigemptyset(&s.sa_mask);
    sigaction(SIGSEGV, &s, 0);

before:
    *causecrash = 0;
after:
    cout << "End.\n";
}
$ g++ -O0 -W -Wall test.cc && ./a.out 
0x400a30 ~ 0x400acd ~ 0x400ada
si:0
ip:400ad4
Segmentation fault
$ g++ -O2 -W -Wall test.cc && ./a.out 
0x4009f0 ~ 0x4009f0 ~ 0x4009f0
si:0
ip:400ab4
Segmentation fault