利用linux訊號機制調試段錯誤(Segment fault)

來源:互聯網
上載者:User

        在實際開發過程中,大家可能會遇到段錯誤的問題,雖然是個老問題,但是其帶來的隱患是極大的,只要出現一次,程式立即崩潰中止。如果程式運行在PC中,segment fault的調試相對比較方便,因為可以通過串口、顯示器可以查看訊息,只要程式運行,通過GDB調試工具即可捕捉產生segment fault的具體原因。但是不知大家有沒有想法,當程式運行在嵌入式裝置上時,你所面臨資源的缺乏,你沒有串口列印資訊,沒有顯示器可查看,你不知道程式啟動並執行狀態,如果程式的產生segment falut這種bug發生的周期1年之內只發生過三四次,時間又不確定,你又如何調試知道程式發生錯誤的具體位置呢?等等問題實在令人糾結。

        解決此問題的方式方法有如下幾種:

       1 在產品發布之前,盡量將所有segment fault產生原因找出,全部消除(最理想情況下)

       2 在程式中的關鍵位置增加列印資訊,設定列印層級,通過打信的資訊縮小查bug的範圍,如果是嵌入式裝置,需要將這些資訊寫入檔案,儲存在flash中。

       3 利用看門狗喂狗,如果程式中止或長期陷入死迴圈,將重新載入程式

       4 利用linux訊號機制來解決段錯誤問題(有點類似於軟看門狗)

 

 

       下面我著重講解第4要點的解決方式:

        首先,我先敘述下我的總體思路,假設我的程式在某處調用一函數dummy_func(),這個函數有個segment fault段錯誤,如果你程式沒對其進行處理,不用懷疑,你的程式馬上掛掉,如果是嵌入式裝置裡的程式,你可能不知道產生segment fault的具體原因和具體位置,只能看log日誌慢慢分析。我們知道,在linux的訊號機制中,當產生segment fault錯誤時,程式會產生SIGSEGV訊號,於是我們試想,如果我們在程式中能夠及時捕捉到此訊號,然後在此訊號處理函數中重新載入此應用程式,就可以實作類別似看門狗的功能,暫且將這種方法稱之為軟體看門狗吧。但是此方法只是權宜之計,它可以讓你的產品在客戶面前保持良好印象(因為如果程式掛掉後又重新載入了,而客戶不知道),而不至於長期很頻繁的去現場解決此問題,這種方式適用於產生段錯誤的周期具有不確定性,其實我們都知道遇到segment fault我們還得解決此問題產生的具體原因,這才是正確的解決方式。

        下面我列出完整的程式源碼,雖然簡單,但是非常有用:

 

/******************************程式開始


**********************************/

 

#include <stdio.h>
#include <signal.h>
#include <string.h>
#include <stdlib.h>

char main_status = 0;

/***********************
 * 此函數產生一個段錯誤
 * *********************/
void dummy_func(void)
{
    printf("hello world/n");
    char *p = NULL;     //0地址
    *p = 0x1a;             //對0地址寫入資料,出現段錯誤
    return;
}

/************************
 * 此函數用於重新載入程式
 ************************/
void deal(void)
{
   char buffer[255];
   memset(buffer, 0, sizeof(buffer));
   sprintf(buffer, "cd ~/test");
   system(buffer);

   /*
    *此延時很重要,如果不加延時,ctrl+c的訊號無法及時處理(即ctrl+c失效),程式將迴圈載入   
    * 如果不加延時,程式又重新執行後面./test1語句將重新載入應用程式了
     */
     sleep(5); 

   memset(buffer, 0, sizeof(buffer));
   sprintf(buffer, "./test1");
   system(buffer);
   printf ("xxxxxxxxxxxxxxx/n");
   
   if( 1 == main_status )
        exit(0);
}

/**************************
 * 捕捉到ctrl+c訊號的處理函數
 **************************/
void ctrl_c_func(int signo)
{
    printf("stop the demo/n");
    main_status = 1;  //置標誌位
    exit(0);
}

int ctrl_c_func_init(void)
{
    int ret = 0;
    struct sigaction act;

    act.sa_handler = ctrl_c_func;
    sigemptyset(&act.sa_mask);
    act.sa_flags = 0;

    ret = sigaction(SIGINT, &act, NULL);
}

/****************************
 * main主程式
 ****************************/
int main(int argc, char **argv)
{
    signal(SIGSEGV, &deal);   //捕捉SIGSEGV訊號
    signal(SIGINT, &ctrl_c_func);  //捕捉SIGINT訊號
//    ctrl_c_func_init();  //如果不用上面捕捉,調用這個函數也行

    while(1)
    {
        if( 1 == main_status )  //如果接收到標誌位,則退出
        {
             exit(0);
        }
        dummy_func();  //調用產生segment fault函數
    }
    return 0;
}
/******************************程式結束


**********************************/

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.