2012-09-03 52 views
4

我只是想知道如何報告分段故障。分段故障是如何報告的?

  • 該過程將會死亡,顯然它不能報告它。
  • shell不會肯定知道,除非進程傳遞了一個信號,這可能並非必然。
  • 操作系統可能能夠做些什麼,但我不知道如何。

哪一個報告分段錯誤(只是一個例子),以及如何?

回答

3

該進程將會死亡,顯然它不能報告它。

這其實是錯誤的。它可能安裝一個SIGSEGV處理程序來替換默認的處理程序,它只是轉儲核心和死亡。預加載庫可以這樣做來捕獲分段違例,並使用可用的有限設施來通知在系統上運行的另一個進程,以便退出之前發生的事情。

2

如果您看看函數wait() or waitpid(),您會發現退出狀態中的某個位表示核心轉儲。 POSIX規範提到WIFSIGNALED [原文如此]和WTERMSIG以獲得終止該過程的信號。 POSIX規範沒有提到它,但是在Mac OS X(10.7.4)中,例如,有一個WCOREDUMP()宏來測試是否創建了核心文件。

2

你可以有一些類似的代碼this將調用GDB命令轉儲呼叫跟蹤:

void BacktraceOnSegv() { 
    struct sigaction action = {}; 
    action.sa_handler = DumpBacktrace; 
    if (sigaction(SIGSEGV, &action, NULL) < 0) { 
    perror("sigaction(SEGV)"); 
    } 
} 

void DumpBacktrace(int) { 
    pid_t dying_pid = getpid(); 
    pid_t child_pid = fork(); 
    if (child_pid < 0) { 
    perror("fork() while collecting backtrace:"); 
    } else if (child_pid == 0) { 
    char buf[1024]; 
    sprintf(buf, "gdb -p %d -batch -ex bt 2>/dev/null | " 
      "sed '0,/<signal handler/d'", dying_pid); 
    const char* argv[] = {"sh", "-c", buf, NULL}; 
    execve("/bin/sh", (char**)argv, NULL); 
    _exit(1); 
    } else { 
    waitpid(child_pid, NULL, 0); 
    } 
    _exit(1); 
} 

Here是支持更多的平臺上實現。

1

好吧,首先,當CPU嘗試訪問進程無法訪問的地址時,會發生分段錯誤。在最低級別,內存映射的實現必須檢測到,通常會產生中斷。內核接收該中斷,並且具有其他代碼段的地址表,每個代碼段用於處理該中斷。

當內核接收到該中斷時,它會將其轉換爲特定值(由於硬件架構和內核實現的具體細節不同,因此我的含義很模糊)。通常將SIGSEGV定義爲具有值11,但確切值不重要;它在signal.h中定義。

此時,信號值被傳遞到內核中的另一個表格,其中包含「信號處理程序」的地址。其中一個處理程序位於由SIGSEGV表示的偏移處。除非你已經做了一些改變,否則這個地址通常是一個導致核心轉儲的例程,假設適當的限制允許,但你可以用你自己的例程地址替換它,它可以做你喜歡的任何事情。