如何编写分段错误处理程序,以便不重启错误指令?(C和Linux)

kin*_*er1 2 c linux segmentation-fault

我编写了一个分段错误处理程序,但问题是,发生错误的指令在转到处理程序后重新启动,这导致处理程序进入无限循环.

我希望处理程序工作,使得在到达处理程序之后,应该执行错误指令之后的指令,使得它不会进入无限循环.有人可以帮我一些代码片段吗?

我正在使用C和Linux.

use*_*653 6

警告:我不建议这样做.听取评论告诉你找到一些其他方法来解决你的问题

我还想重复Henning Makholms的警告,它将极其特定于架构和非便携式.这将是维护地狱,你将不得不手动处理许多不同的指令,除非它是你正在寻找的一个特定指令序列(如下例所示).

如果您仍然希望这样做,可以通过以下方式完成:

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <stdint.h>
#include <time.h>

#define __USE_GNU
#include <signal.h>

void action(int sig, siginfo_t* siginfo, void* context)
{
    sig=sig; siginfo=siginfo;// ignore warning

    // get execution context
    mcontext_t* mcontext = &((ucontext_t*)context)->uc_mcontext;

    // find out what instruction faulted
#if defined(__x86_64)
    uint8_t* code = (uint8_t*)mcontext->gregs[REG_RIP];
    if (code[0] == 0x88 && code[1] == 0x10) { // mov %dl,(%rax)
        mcontext->gregs[REG_RIP] += 2; // skip it!
        return;
    }
#elif defined(__i386)
    uint8_t* code = (uint8_t*)mcontext->gregs[REG_EIP];
    if (code[0] == 0x88 && code[1] == 0x10) { // mov %dl,(%eax)
        mcontext->gregs[REG_EIP] += 2; // skip it!
        return;
    }
#else
#error "Unsupported system"
#endif
    // unknown/unhandled instruction failed...

    // only for debugging, shouldn't print stuff in a signal handler
    int i = 0; 
    for (i = 0; i < 16; i++) {
        fprintf(stderr, "%2.2X ", code[i]);
    }
    fprintf(stderr, "\n");
    exit(1);
}

int main(void)
{
    // install SIGSEGV handler
    struct sigaction act;
    memset(&act, 0, sizeof(act));
    act.sa_sigaction = action;
    act.sa_flags = SA_SIGINFO;
    if (sigaction(SIGSEGV, &act, NULL) < 0) {
        perror("sigaction");
        return 1;
    }

    // cause fault
    int i;
    for (i = 0; i < 10; i++) {
        ((unsigned char*)0)[i] = i;
    }
    return EXIT_SUCCESS;
}
Run Code Online (Sandbox Code Playgroud)

在这里,我只处理了x86 32位和64位的一个特定指令序列,尽管它应该是微不足道的(如果单调乏味)以支持更多的体系结构和指令.

更新:您(现在)提到您使用的是ARM计算机.这实际上应该更容易,因为如果我没有弄错的话,指令总是32位(拇指模式除外).我没有ARM机器来测试这个,所以你必须深入研究sys/ucontext.h以检查我的名字是否正确.当然,你也应该以类似的方式检查断层指令.我对ARM的最佳猜测如下(与其他#if defined(...)语句并列:

    #elif defined(__arm) // or use what your GCC defines, also check for 32-bit arm mode or whatever...
    uint8_t* code = (uint8_t*)mcontext->arm_pc;
    if (*(uint32_t*)code == /*some instruction*/) {
        mcontext->arm_pc += 4; // skip it!
        return;
    }
Run Code Online (Sandbox Code Playgroud)