gpt4 book ai didi

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

转载 作者:可可西里 更新时间:2023-11-01 17:39:44 26 4
gpt4 key购买 nike

我对信号处理程序很感兴趣,它可以识别导致问题的指令的地址。

我知道 siginfo_t__builtin_return_address 但似乎都不起作用:

#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";
}

输出如下:

0x10978 ~ 0x10a4c ~ 0x10a54
si:0
At: 0xfb945364
At: 0xfb939e64
At: 0x10a40
At: 0x10740
At: 0
At: Segmentation Fault

因此 siginfo_t 为 NULL,__builtin_return_address 在指定标签之间的某处产生值。

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

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

最佳答案

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

#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";
}

顺便说一句,GCC 有这种讨厌的习惯,即移动地址已被占用但未在控制转移操作中使用的标签(据它所知)。比较:

$ 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

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

关于c++ - 获取生成 UNIX 信号的故障地址,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/5119288/

26 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com