首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
您现在的位置: 程式碼之家 >> 編程語言 >  >> C語言 >> VC >> VC 教學

VC++ Release 版程式異常捕捉與定位完整指南

     編輯:VC 教學

前言

Release 版無調試資訊,定位崩潰比 Debug 版困難。本文介紹三種進階定位技術:MAP 檔案、自定義異常過濾器、COD 檔案混合分析。

一、使用 MAP 檔案定位錯誤行

1. 產生 MAP 檔

  • 專案屬性 -> C/C++ -> 一般 -> 偵錯資訊:僅行號 (/Zd) 或專案選項加 /Zd。
  • 連結器 -> 偵錯 -> 產生對應檔:是 (/MAP),並加 /MAPINFO:LINES。
  • 重新建置,輸出目錄產生 .map 檔。

2. MAP 檔結構與定位步驟

; 範例 MAP 片段
Preferred load address is 00400000  ; 基址

Address         Publics by Value              Rva+Base    Lib:Object
0001:00000000   ?_GetBaseMessageMap@CMyApp@@... 00401000   MyApp.obj

Line numbers for MyDlg.obj (MyDlg.cpp)
  24 0001:00003f90
  28 0001:00003fce
  29 0001:00003fd1

定位步驟:

  1. 取得崩潰位址 (如 0x00405FD1)。
  2. 在 Publics by Value 區找 最後一個 Rva+Base < 崩潰位址 的函數,即所在函數。
  3. 計算偏移:崩潰位址 - 函數 Rva+Base。
  4. 在對應 Line numbers for ... 區,找 最接近該偏移 的行號。

二、自定義未處理異常過濾器獲取詳細資訊

使用 SetUnhandledExceptionFilter 註冊回調,可在崩潰瞬間捕獲完整上下文。

關鍵結構

typedef struct _EXCEPTION_POINTERS {
    PEXCEPTION_RECORD ExceptionRecord; // 異常代碼、位址、參數
    PCONTEXT ContextRecord;            // 所有暫存器值 (EIP, ESP, EAX...)
} EXCEPTION_POINTERS;

常見異常代碼

代碼符號說明
0xC0000005EXCEPTION_ACCESS_VIOLATION記憶體讀寫違規
0xC0000094EXCEPTION_INT_DIVIDE_BY_ZERO整數除零
0xC00000FDEXCEPTION_STACK_OVERFLOW堆疊溢位
0x80000003EXCEPTION_BREAKPOINT硬體中斷點 (INT 3)

實作範例

LPTOP_LEVEL_EXCEPTION_FILTER g_prevFilter = NULL;

LONG WINAPI MyExceptionFilter(PEXCEPTION_POINTERS pExpInfo)
{
    // 1. 記錄詳細資訊到檔案
    WriteCrashLog(pExpInfo); 

    // 2. 交還系統預設處理 (彈出錯誤對話框)
    if (g_prevFilter) return g_prevFilter(pExpInfo);
    return EXCEPTION_CONTINUE_SEARCH;
}

// 程式啟動時安裝
g_prevFilter = SetUnhandledExceptionFilter(MyExceptionFilter);

EXCEPTION_RECORD.ExceptionInformation[0] 為 0 表讀取違規,1 表寫入違規;[1] 為違規記憶體位址。

三、使用 COD 檔案精確分析組合語言層面

1. 產生 COD 檔

專案屬性 -> C/C++ -> 輸出檔案 -> 清單檔類型:含機器碼的組合語言 (/FAcs)。產生 .cod 檔。

2. COD 檔結構與定位

?OnPaint@CMyDlg@@IAEXXZ PROC NEAR ; CMyDlg::OnPaint

; 81 : {
00000  83 ec 64     sub     esp, 100        ; 00000064H
00003  56           push    esi

; 82 :     if (IsIconic())
00004  e8 xx xx xx xx call    ?IsIconic@CWnd@@QAEHXZ

步驟:

  1. 同 MAP 定位函數與偏移。
  2. 在對應 .cod 檔找函數標籤 (如 ?OnPaint@CMyDlg@@IAEXXZ)。
  3. 對照左側偏移位址 (00000, 00003...) 找到崩潰指令。
  4. 結合右側原始碼行號註解 (; 82 :) 精確定位到 C++ 行。
  5. 利用異常過濾器取得的暫存器值 (EAX, ECX...)、呼叫堆疊 (ESP/EBP 鏈) 進行深度分析。

總結建議

  • MAP 檔:快速定位函數與大概行號,必備基礎。
  • 異常過濾器:自動記錄崩潰現場 (暫存器、記憶體、異常碼),生產環境必裝。
  • COD 檔:疑難雜症終極武器,需組合語言基礎。
  • 建議:Release 版也開啟 /Zd 與 /MAPINFO:LINES,體積增加微小但獲益巨大。
  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved