Programové zjištění místa vyjímky

Díky strukturované obsluze vyjímky, která je podporována od nástupu 32-bitových Windows, máme možnost programově ošetřit vyjímky jako např. chybný přístup do paměti nebo dělení nulou. Při zpracování vyjímky je možné zjistit adresu, na které vyjímka nastala. Díky dokumentovanému ladicímu rozhraní (knihovna Dbghelp.dll) je možné s pomocí ladicích informací zjistit také zdrojový soubor a číslo řádku, kde vyjímka nastala.

Zachycení vyjímky

K zachycení vyjímky je nutné použít konstrukci try-except, která (na rozdíl or try-catch) zachytí i vyjímky jádra, jako EXCEPTION_ACCESS_VIOLATION, EXCEPTION_BREAKPOINT, nebo EXCEPTION_INT_DIVIDE_BY_ZERO. Konstrukce try-except vypadá takto:

    // Start the frame for an exception.
    __try
    {
        // Access violation
        *((DWORD *)0) = 0;
    }

    // Exception handler
    __except(EXCEPTION_EXECUTE_HANDLER)
    {
        printf("Nastala vyjímka !!!\n");
    }

Jestliže je hodnota výrazu v obsluze vyjímky rovna konstantě EXCEPTION_EXECUTE_HANDLER, bude spuštěna obsluha vyjímky, tedy kód ve složených závorkách za __except.

Na které adrese ?

Adresa, na které nastala vyjímka, je uložena v informacích o vyjímce (struktura EXCEPTION_POINTERS). Tato struktura obsahuje kód vyjímky, adresu vyjímky, stav registrů procesoru a další. Ukazatel na strukturu vrací funkce GetExceptionInformation(). Následující kód vypíše kód vyjímky a adresu, na které nastala:

    EXCEPTION_POINTERS * ep;

    // Start the frame for an exception.
    __try
    {
        // Access violation
        *((DWORD *)0) = 0;
    }
    __except(ep = GetExceptionInformation(), EXCEPTION_EXECUTE_HANDLER)
    {
        printf("Nastala vyjímka %08lX na adrese %p\n",
                ep->ExceptionRecord->ExceptionCode, ep->ExceptionRecord->ExceptionAddress);
    }

Kde v kódu ?

Pomocí funkcí exportovaných knihovnou Dbghelp.dll je možné z adresy zjistit místo ve zdrojovém kódu. Postup pro zjištění je následující:

  1. Inicializovat knihovnu pomocí volání funkce SymInitialize()
  2. Nakonfigurovat knihovnu pro načtení čísel řádků zdrojového kódu pomocí volání SymSetOptions(SYMOPT_LOAD_LINES)
  3. Použít funkci SymGetLineFromAddr pro zjištění jména zdrojového souboru a čísla řádku, kde nastala vyjímka.

Vzorový příklad

Podrobný komentovaný zdrojový text, který využívá knihovny Dbghelp.dll ke zjištění jména souboru a čísla řádku, obsahuje projekt EHandler. Tento testprogram vygeneruje vyjímku EXCEPTION_ACCESS_VIOLATION. Vyjímka je zachycena v bloku __except a informace o vyjímce jsou předány funkci ShowExceptionInfo(). Tato funkce zjistí, kde vyjímka nastala a zobrazí hlášení (viz. obr.)

Hlášení o vyjímce