Time Travel Debugging – Példaalkalmazás-bemutató

Time Travel hibakeresési emblémája, amely egy órát tartalmaz.

Ez a laboratórium bemutatja az Időutazó Hibakeresést (TTD) egy kódhibával rendelkező kis mintaprogram segítségével. A TTD a probléma hibakeresésére, azonosítására és kiváltó okára szolgál. Bár ebben a kis programban könnyen megtalálható a probléma, az általános eljárás összetettebb kódon is használható. Ez az általános eljárás az alábbiak szerint foglalható össze.

  1. Rögzítse a sikertelen program időutazási nyomkövetését.
  2. A dx (Display Debugger Object Model Expression) paranccsal keresse meg a felvételben tárolt kivételeseményt.
  3. A !tt (időutazás) paranccsal a nyomkövetésben lévő kivételesemény helyére utazhat.
  4. Ettől a ponttól kezdve a nyomkövetés egyetlen lépésben hátrafelé halad, amíg a kérdéses hibás kód a hatókörbe nem kerül.
  5. A hibás kód hatókörében vizsgálja meg a helyi értékeket, és dolgozzon ki egy olyan változó hipotézisét, amely helytelen értéket tartalmazhat.
  6. Határozza meg annak a változónak a memóriacímét, amely helytelen értékkel rendelkezik.
  7. Állítson be egy memóriaelérési (ba) töréspontot a gyanús változó címére a ba (Break on Access) paranccsal.
  8. A g- használatával futtassa vissza a gyanús változó utolsó memóriahozzáférésének pontjára.
  9. Ellenőrizze, hogy ez a hely vagy néhány korábbi utasítás a kódhibának a pontja-e. Ha igen, akkor elkészült. Ha a helytelen érték más változóból származik, állítson be egy újabb törést a hozzáférési törésponton a második változón.
  10. Használja a g- parancsot, hogy visszafusson a második gyanús változó memóriához való utolsó hozzáférési pontjához. Ellenőrizze, hogy ez a hely vagy néhány utasítás tartalmazza-e a kódhibát. Ezzel készen van.
  11. Addig ismételje meg ezt a folyamatot, amíg visszafelé haladva meg nem találja azt a kódot, amely beállította a hibát okozó helytelen értéket.

Bár az eljárásban ismertetett általános technikák a kódproblémák széles körére vonatkoznak, vannak egyedi kódproblémák, amelyek egyedi megközelítést igényelnek. Az útmutatóban bemutatott technikáknak a hibakereső eszközkészlet bővítését kell szolgálniuk, és TTD-nyomkövetéssel szemléltetik a lehetséges lehetőségek egy részét.

Laborcélok

A labor elvégzése után az általános eljárást időutazási nyomkövetéssel használhatja a kódban található problémák megkereséséhez.

Tesztkörnyezet beállítása

A tesztkörnyezet befejezéséhez a következő hardverre lesz szüksége.

  • Windows 10 vagy Windows 11 rendszerű laptop vagy asztali számítógép (gazdagép)

A laboratórium elvégzéséhez a következő szoftverre lesz szüksége.

  • A WinDbg. A WinDbg telepítésével kapcsolatos információkért lásd: WinDbg – Telepítés
  • A Visual Studio a C++ mintakód létrehozásához.

A labor három szakaszból áll.

1. szakasz: A mintakód létrehozása

Az 1. szakaszban a mintakódot a Visual Studióval fogja létrehozni.

Mintaalkalmazás létrehozása a Visual Studióban

  1. A Microsoft Visual Studióban kattintson a Fájl>új>projekt/megoldás... elemre, és kattintson a Visual C++ sablonokra.

    Válassza ki a Win32 konzolalkalmazást.

    Adja meg a DisplayGreeting projektnevét , és kattintson az OK gombra.

  2. Törölje a biztonsági fejlesztési életciklus (SDL) ellenőrzésének jelölését.

    A Win32 alkalmazásvarázsló beállításai a Visual Studióban.

  3. Kattintson a Befejezés gombra.

  4. Illessze be a következő szöveget a Visual Studio DisplayGreeting.cpp ablakába.

    // DisplayGreeting.cpp : Defines the entry point for the console application.
    //
    
    #include "stdafx.h"
    #include <array>
    #include <stdio.h>
    #include <string.h>
    
    void GetCppConGreeting(wchar_t* buffer, size_t size)
    {
        wchar_t const* const message = L"HELLO FROM THE WINDBG TEAM. GOOD LUCK IN ALL OF YOUR TIME TRAVEL DEBUGGING!";
    
        wcscpy_s(buffer, size, message);
    }
    
    int main()
    {
         std::array <wchar_t, 50> greeting{};
         GetCppConGreeting(greeting.data(), sizeof(greeting));
    
         wprintf(L"%ls\n", greeting.data());
    
         return 0;
    }
    
  5. A Visual Studióban kattintson a Project>DisplayGreeting tulajdonságai elemre. Ezután kattintson a C/C++ és a Kódgenerálás elemre.

    Adja meg a következő tulajdonságokat.

    Beállítás Érték
    Biztonsági ellenőrzés Biztonsági ellenőrzés letiltása (/GS-)
    Alapszintű futásidejű ellenőrzések Alapértelmezett

    Megjegyzés:

    Bár ezek a beállítások nem ajánlottak, el lehet képzelni egy olyan forgatókönyvet, amelyben valaki azt tanácsolja, hogy használja ezeket a beállításokat a kódolás felgyorsítása vagy bizonyos tesztelési környezetek megkönnyítése érdekében.

  6. A Visual Studióban kattintson a Build>Build Solution elemre.

    Ha minden jól megy, a buildablakokban egy üzenetnek kell megjelennie, amely jelzi, hogy a build sikeres volt.

  7. A beépített mintaalkalmazás-fájlok megkeresése

    A Megoldáskezelőben kattintson a jobb gombbal a DisplayGreeting projektre , és válassza a Mappa megnyitása a Fájlkezelőben lehetőséget.

    Lépjen a Debug mappába, amely tartalmazza a minta lefordított exe- és szimbólum pdb fájlját. Például a C:\Projects\DisplayGreeting\Debug mappába navigálhat, ha a projektek ebben a mappában vannak tárolva.

  8. A mintaalkalmazás futtatása a kódhibával

    Kattintson duplán az exe fájlra a mintaalkalmazás futtatásához.

    Képernyőkép a DisplayGreeting.exe fájlt futtató konzolról.

    Ha megjelenik ez a párbeszédpanel, válassza a Program bezárása lehetőséget

    Képernyőkép a

    Az útmutató következő szakaszában rögzítjük a mintaalkalmazás végrehajtását, hogy megállapíthassuk, miért történik ez a kivétel.

2. szakasz: A "DisplayGreeting" minta nyomkövetésének rögzítése

A 2. szakaszban a "DisplayGreeting" alkalmazás helytelen viselkedésének nyomkövetését fogja rögzíteni

A mintaalkalmazás elindításához és egy TTD-nyomkövetés rögzítéséhez kövesse az alábbi lépéseket. A TTD-nyomkövetések rögzítésével kapcsolatos általános információkért lásd: Time Travel Hibakeresés – Nyomkövetés rögzítése

  1. Futtassa a WinDbg-et rendszergazdaként, hogy rögzíthesse az időutazási nyomkövetéseket.

  2. A WinDbg-ben válassza a Fájl>Hibakeresés indítása>Végrehajtható indítása (speciális).

  3. Adja meg annak a felhasználói módnak az elérési útját, amelyet rögzíteni szeretne, vagy válassza a Tallózás lehetőséget a végrehajtható fájlra való navigáláshoz. A WinDbg indítási végrehajtható menüjének használatával kapcsolatos további információkért lásd: WinDbg – Felhasználói módú munkamenet indítása.

    Képernyőkép a WinDbg-ről a

  4. Jelölje be a Rekord és a Time Travel hibakeresési jelölőnégyzetet, ha nyomkövetést szeretne rögzíteni a végrehajtható fájl elindításakor.

  5. A felvétel indításához kattintson a Konfigurálás és rögzítés gombra.

  6. Amikor megjelenik a "Felvétel konfigurálása" párbeszédpanel, kattintson a Rekord gombra a végrehajtható fájl elindításához és a felvétel elindításához.

    Képernyőkép a WinDbg-ről, amely megjeleníti a

  7. Megjelenik a rögzítési párbeszédpanel, amely azt jelzi, hogy a nyomkövetés rögzítve van. Röviddel ezután az alkalmazás összeomlik.

  8. Kattintson a Program bezárása gombra a "DisplayGreeting leállt" párbeszédpanel bezárásához.

    A DisplayGreeting alkalmazást megjelenítő párbeszédpanel működése leállt.

  9. Amikor a program összeomlik, a nyomkövetési fájl le lesz zárva, és lemezre lesz írva.

    Képernyőkép az indexelt 1/1 kulcskereteket megjelenítő WinDbg-kimenetről.

  10. A hibakereső automatikusan megnyitja és indexeli a nyomkövetési fájlt. Az indexelés olyan folyamat, amely lehetővé teszi a nyomkövetési fájl hatékony hibakeresését. Ez az indexelési folyamat hosszabb időt vesz igénybe a nagyobb nyomkövetési fájlok esetében.

    (5120.2540): Break instruction exception - code 80000003 (first/second chance not available)
    Time Travel Position: D:0 [Unindexed] Index
    !index
    Indexed 10/22 keyframes
    Indexed 20/22 keyframes
    Indexed 22/22 keyframes
    Successfully created the index in 755ms.
    

Megjegyzés:

A kulcskeret egy hely a nyomvonalban, amelyet indexelésre használnak. A rendszer automatikusan létrehozza a kulcskereteket. A nagyobb nyomok több kulcsfontosságú képkockát tartalmaznak.

  1. Jelenleg a nyomkövetési fájl elején jár, és készen áll arra, hogy előre és hátra mozogjon az időben.

    Most, hogy rögzített egy TTD-nyomkövetést, visszajátszhatja a nyomkövetést, vagy dolgozhat a nyomkövetési fájllal, például megoszthatja azt egy munkatárssal. A nyomkövetési fájlok használatával kapcsolatos további információkért lásd: Time Travel Hibakeresés – Nyomkövetési fájlok használata

A tesztkörnyezet következő szakaszában elemezzük a nyomkövetési fájlt a kóddal kapcsolatos probléma megkereséséhez.

3. szakasz: A nyomkövetési fájl felvételének elemzése a kódproblémák azonosításához

A 3. szakaszban elemezni fogja a nyomkövetési fájl rögzítését a kódproblémák azonosításához.

A WinDbg-környezet konfigurálása

  1. Adja hozzá a helyi szimbólum helyét a szimbólum elérési útjához, és töltse be újra a szimbólumokat az alábbi parancsok beírásával.

    .sympath+ C:\MyProjects\DisplayGreeting\Debug
    .reload
    
  2. Adja hozzá a helyi kód helyét a forrásútvonalhoz az alábbi parancs beírásával.

    .srcpath+ C:\MyProjects\DisplayGreeting\DisplayGreeting
    
  3. A verem és a helyi változók állapotának megtekintéséhez a WinDbg menüszalagján válassza a Nézet, a Helyi változók lehetőséget és a Nézet és a Verem lehetőséget. Rendszerezze az ablakokat, hogy egyszerre tekinthesse meg őket, a forráskódot és a parancsablakokat.

  4. A WinDbg menüszalagján válassza a Forrást és a Forrásfájl megnyitását. Keresse meg a DisplayGreeting.cpp fájlt, és nyissa meg.

A kivétel vizsgálata

  1. A nyomkövetési fájl betöltésekor megjelenik egy kivételről tájékoztató információ.

    2fa8.1fdc): Break instruction exception - code 80000003 (first/second chance not available)
    Time Travel Position: 15:0
    eax=68ef8100 ebx=00000000 ecx=77a266ac edx=69614afc esi=6961137c edi=004da000
    eip=77a266ac esp=0023f9b4 ebp=0023fc04 iopl=0         nv up ei pl nz na pe nc
    cs=0023  ss=002b  ds=002b  es=002b  fs=0053  gs=002b             efl=00000206
    ntdll!LdrpInitializeProcess+0x1d1c:
    77a266ac 83bdbcfeffff00  cmp     dword ptr [ebp-144h],0 ss:002b:0023fac0=00000000
    
  2. A dx paranccsal listázhatja a felvétel összes eseményét. A kivételesemény szerepel az események között.

    0:000> dx -r1 @$curprocess.TTD.Events
    ...
    [0x2c]           : Module Loaded at position: 9967:0
    [0x2d]           : Exception at 9BDC:0
    [0x2e]           : Thread terminated at 9C43:0
    ...
    
    

    Megjegyzés:

    Ebben a lépésenkénti útmutatóban három pont használatos annak jelzésére, hogy a felesleges kimenetet eltávolították.

  3. A Kivétel eseményre kattintva megjelenítheti az adott TTD-esemény adatait.

    0:000> dx -r1 @$curprocess.TTD.Events[17]
    @$curprocess.TTD.Events[17]                 : Exception at 68:0
        Type             : Exception
        Position         : 68:0 [Time Travel]
        Exception        : Exception of type Hardware at PC: 0X540020
    
  4. Kattintson a Kivétel mezőre a kivételadatok további részletezéséhez.

    0:000> dx -r1 @$curprocess.TTD.Events[17].Exception
    @$curprocess.TTD.Events[17].Exception                 : Exception of type Hardware at PC: 0X540020
        Position         : 68:0 [Time Travel]
        Type             : Hardware
        ProgramCounter   : 0x540020
        Code             : 0xc0000005
        Flags            : 0x0
        RecordAddress    : 0x0
    

    A kivételadatok azt jelzik, hogy ez a processzor által okozott hardverhiba. Emellett a 0xc0000005 kivételkódját is tartalmazza, amely azt jelzi, hogy ez hozzáférés-megsértés. Ez általában azt jelzi, hogy olyan memóriába próbáltunk írni, amelyhez nincs hozzáférésünk.

  5. A kivételeseményben kattintson az [Időutazás] hivatkozásra, hogy a nyomkövetés adott pozíciójára ugorjon.

    0:000> dx @$curprocess.TTD.Events[17].Exception.Position.SeekTo()
    Setting position: 68:0
    
    @$curprocess.TTD.Events[17].Exception.Position.SeekTo()
    (16c8.1f28): Break instruction exception - code 80000003 (first/second chance not available)
    Time Travel Position: 68:0
    eax=00000000 ebx=00cf8000 ecx=99da9203 edx=69cf1a6c esi=00191046 edi=00191046
    eip=00540020 esp=00effe4c ebp=00520055 iopl=0         nv up ei pl zr na pe nc
    cs=0023  ss=002b  ds=002b  es=002b  fs=0053  gs=002b             efl=00000246
    00540020 ??
    

    Fontos megjegyezni ebben a kimenetben, hogy a veremmutató és az alapmutató két nagyon különböző címre mutat.

    esp=00effe4c ebp=00520055
    

    Ez azt jelezheti, hogy a verem sérülése – valószínűleg egy függvényt adott vissza, majd sérült a verem. Ennek ellenőrzéséhez vissza kell utaznunk a CPU-állapot sérülése előtt, és meg kell állapítanunk, hogy mikor történt a verem sérülése.

A helyi változók vizsgálata és kódtörési pont beállítása

A nyomkövetési hiba helyén gyakran előfordul, hogy a hibakezelési kód miatt néhány lépéssel túlhaladunk a valódi okon. Az időutazással egy időben visszatérhetünk egy utasításhoz, hogy megtaláljuk a valódi kiváltó okot.

  1. A Kezdőlap menüszalagjáról a Step Into Back paranccsal léptethet vissza három utasítást. Ennek során folytassa a verem és a memóriaablakok vizsgálatát.

    A parancsablakban megjelenik az időutazás pozíciója és a regiszterek, miközben három utasítást lép vissza.

    0:000> t-
    Time Travel Position: 67:40
    eax=00000000 ebx=00cf8000 ecx=99da9203 edx=69cf1a6c esi=00191046 edi=00191046
    eip=00540020 esp=00effe4c ebp=00520055 iopl=0         nv up ei pl zr na pe nc
    cs=0023  ss=002b  ds=002b  es=002b  fs=0053  gs=002b             efl=00000246
    00540020 ??              ???
    
    0:000> t-
    Time Travel Position: 67:3F
    eax=00000000 ebx=00cf8000 ecx=99da9203 edx=69cf1a6c esi=00191046 edi=00191046
    eip=0019193d esp=00effe48 ebp=00520055 iopl=0         nv up ei pl zr na pe nc
    cs=0023  ss=002b  ds=002b  es=002b  fs=0053  gs=002b             efl=00000246
    DisplayGreeting!main+0x4d:
    0019193d c3
    
    0:000> t-
    Time Travel Position: 67:39
    eax=0000004c ebx=00cf8000 ecx=99da9203 edx=69cf1a6c esi=00191046 edi=00191046
    eip=00191935 esp=00effd94 ebp=00effe44 iopl=0         nv up ei pl nz ac po nc
    cs=0023  ss=002b  ds=002b  es=002b  fs=0053  gs=002b             efl=00000212
    DisplayGreeting!main+0x45:
    

    Megjegyzés:

    Ebben az útmutatóban a parancskimenet azokat a parancsokat jeleníti meg, amelyek a felhasználói felület menübeállításai helyett használhatók, hogy a parancssori használati beállításokat használó felhasználók parancssori parancsokat használhassanak.

  2. A nyomkövetés ezen pontján a verem és az alapmutató értelmesebb értékekkel bír, ezért úgy tűnik, hogy egyre közelebb jutottunk a kód azon pontjához, ahol a sérülés történt.

    esp=00effd94 ebp=00effe44
    

    Az is érdekes, hogy a helyiek ablak a célalkalmazás értékeit tartalmazza, a forráskódablak pedig a nyomkövetés ezen pontján végrehajtandó kódsort emeli ki.

  3. A további vizsgálathoz megnyithatunk egy memóriaablakot, amely a 0x00effe44 alapmutató memóriacíme közelében jeleníti meg a tartalmat.

  4. A társított ASCII-karakterek megjelenítéséhez a Memória menüszalagon válassza a Szöveg , majd az ASCII lehetőséget.

    Képernyőkép a WinDbg előzetes verziójáról, amelyen a memória ASCII-kimenete és a Forráskód ablak látható.

  5. Ahelyett, hogy az alapmutató egy utasításra mutat, az üzenet szövegére mutat. Tehát valami nincs rendben, ez lehet az az időpont, amikor megrongáltuk a veremet. A további vizsgálathoz töréspontot állítunk be.

Megjegyzés:

Ebben a nagyon kicsi mintában elég könnyű lenne csak a kódban keresni, de ha több száz sornyi kód és több tucat alrutin található, az itt leírt technikák segítségével csökkenthető a probléma megkereséséhez szükséges idő.

TTD és töréspontok

A töréspontok használata gyakori módszer a kódvégrehajtás szüneteltetésére valamilyen fontos eseménynél. A TTD lehetővé teszi, hogy töréspontot állítson be, és visszautazzon az időben, amíg el nem éri a töréspontot a nyomkövetés rögzítése után. A probléma bekövetkezése után a folyamat állapotának vizsgálatával, a töréspontok legjobb helyének meghatározásával további, a TTD-ben egyedi hibakeresési munkafolyamatokat is lehetővé tesz.

Memóriaelérési töréspontok

Beállíthat olyan töréspontokat, amelyek memóriahely elérésekor aktiválhatók. Használja a ba (hozzáférés-megszakítás) parancsot az alábbi szintaxissal.

ba <access> <size> <address> {options}
Lehetőség Leírás
e végrehajtás (amikor a CPU lekéri az utasítást a címről)
r olvasás/írás (amikor a CPU beolvassa vagy a címre ír)
w írás (amikor a CPU a címre ír)

Vegye figyelembe, hogy egy adott időpontban csak négy adattörési pontot állíthat be, és Önnek kell gondoskodnia arról, hogy megfelelően igazítsa az adatokat, vagy hogy ne aktiválja a töréspontot (a szavaknak 2-gyel osztható címekben kell végződniük, a dwords-nek 4-gyel, a quadwordsnek pedig 0-tal vagy 8-tal kell oszthatónak lennie).

A memóriahozzáférés töréspontjának beállítása az alapmutatóhoz

  1. A nyomkövetés ezen pontján szeretnénk beállítani egy megszakítási pontot az alapmutató (ebp) írási memória-hozzáférésére, ami a példánkban 00effe44. Ehhez használja a ba parancsot a figyelni kívánt címmel. Szeretnénk figyelni az írási műveleteket négy bájton, ezért megadjuk a w4-et.

    0:000> ba w4 00effe44
    
  2. Válassza a Nézet lehetőséget, majd kattintson a Töréspontok-ra, hogy meggyőződjön arról, hogy megfelelően vannak beállítva.

    Képernyőkép a WinDbg töréspontok ablakáról, amely egyetlen töréspontot jelenít meg.

  3. A Kezdőlap menü Vissza gombra kattintva visszatérhet az időben, amíg el nem éri a töréspontot.

    0:000> g-
    Breakpoint 0 hit
    Time Travel Position: 5B:92
    eax=0000000f ebx=003db000 ecx=00000000 edx=00cc1a6c esi=00d41046 edi=0053fde8
    eip=00d4174a esp=0053fcf8 ebp=0053fde8 iopl=0         nv up ei pl nz ac pe nc
    cs=0023  ss=002b  ds=002b  es=002b  fs=0053  gs=002b             efl=00000216
    DisplayGreeting!DisplayGreeting+0x3a:
    00d4174a c745e000000000  mov     dword ptr [ebp-20h],0 ss:002b:0053fdc8=cccccccc
    
  4. Válassza a Nézet , majd a Helyiek lehetőséget. A helyi ablakban látható, hogy a célváltozó csak az üzenet egy részét tartalmazza, míg a forrás az összes szöveget tartalmazza. Ez az információ azt az elképzelést támogatja, hogy a verem megsérült.

    Képernyőkép a WinDbg-ről, amely a Helyiek ablakot jeleníti meg.

  5. Ezen a ponton megvizsgálhatjuk a program vermet, hogy lássuk, melyik kód aktív. A Nézet menüszalagon válassza a Stack lehetőséget.

    Képernyőkép a Stack ablakát megjelenítő WinDbg-ről.

Mivel nagyon valószínűtlen, hogy a Microsoft által biztosított wscpy_s() függvény ilyen kódhibát tartalmazna, részletesebben megvizsgáljuk a veremet. A verem azt mutatja, hogy a Greeting!main hívja a Greeting!GetCppConGreeting-et. A nagyon kis kódmintánkban ezen a ponton egyszerűen megnyithatjuk a kódot, és valószínűleg elég könnyen megtalálhatjuk a hibát. De a nagyobb, összetettebb programokkal használható technikák szemléltetéséhez egy új töréspontot állítunk be a további vizsgálathoz.

A GetCppConGreeting függvény hozzáférési töréspontjának beállítása

  1. A töréspontok ablakával törölje a meglévő töréspontot a jobb gombbal a meglévő töréspontra kattintva, és válassza az Eltávolítás lehetőséget.

  2. Határozza meg a DisplayGreeting!GetCppConGreeting függvény címét a dx paranccsal.

    0:000> dx &DisplayGreeting!GetCppConGreeting
    &DisplayGreeting!GetCppConGreeting                 : 0xb61720 [Type: void (__cdecl*)(wchar_t *,unsigned int)]
        [Type: void __cdecl(wchar_t *,unsigned int)]
    
  3. A ba paranccsal állítson be töréspontot a memória-hozzáféréshez. Mivel a függvény csak a memóriából lesz beolvasva a végrehajtáshoz, be kell állítanunk egy r - olvasási töréspontot.

    0:000> ba r4 b61720
    
  4. Ellenőrizze, hogy a hardver olvasási töréspontja aktív-e a töréspontok ablakban.

    Képernyőkép a WinDbg Töréspontok ablakról, amely egyetlen hardveres olvasási töréspontot jelenít meg.

  5. Mivel kíváncsiak vagyunk a köszönési karakterlánc méretére, be fogunk állítani egy óraablakot, hogy megjelenítse a sizeof(greeting) értékét. A Nézet menüszalagon válassza a Figyelés lehetőséget, és adja meg a sizeof(greeting) értékét. Ha az érték nem szerepel a hatókörben, a vizsgálati ablak ezt jeleníti meg: Nem sikerült a 'greeting' név hozzárendelése.

    Képernyőkép a WinDbg-ről, amely a Helyiek megtekintése ablakot jeleníti meg.

  6. Az Időutazás menüben használja az Időutazás indítása parancsot, vagy használja a !tt 0 parancsot a nyomkövetés elejére lépéshez.

    0:000> !tt 0
    Setting position to the beginning of the trace
    Setting position: 15:0
    (1e5c.710): Break instruction exception - code 80000003 (first/second chance not available)
    Time Travel Position: 15:0
    eax=68e28100 ebx=00000000 ecx=77a266ac edx=69e34afc esi=69e3137c edi=00fa2000
    eip=77a266ac esp=00ddf3b8 ebp=00ddf608 iopl=0         nv up ei pl nz na pe nc
    cs=0023  ss=002b  ds=002b  es=002b  fs=0053  gs=002b             efl=00000206
    ntdll!LdrpInitializeProcess+0x1d1c:
    77a266ac 83bdbcfeffff00  cmp     dword ptr [ebp-144h],0 ss:002b:00ddf4c4=00000000
    
  7. A Kezdőlap menüBen válassza az Ugrás lehetőséget, vagy használja a g parancsot, hogy továbblépjen a kódban, amíg el nem éri a töréspontot.

    0:000> g
    Breakpoint 2 hit
    Time Travel Position: 4B:1AD
    eax=00ddf800 ebx=00fa2000 ecx=00ddf800 edx=00b61046 esi=00b61046 edi=00b61046
    eip=00b61721 esp=00ddf7a4 ebp=00ddf864 iopl=0         nv up ei pl nz na po nc
    cs=0023  ss=002b  ds=002b  es=002b  fs=0053  gs=002b             efl=00000202
    DisplayGreeting!GetCppConGreeting+0x1:
    00b61721 8bec            mov     ebp,esp
    
  8. A Kezdőlap menüben válassza a Visszalépés lehetőséget, vagy használja a g-u parancsot egy lépés visszalépéséhez.

    0:000> g-u
    Time Travel Position: 4B:1AA
    eax=00ddf800 ebx=00fa2000 ecx=00ddf800 edx=00b61046 esi=00b61046 edi=00b61046
    eip=00b61917 esp=00ddf7ac ebp=00ddf864 iopl=0         nv up ei pl nz na po nc
    cs=0023  ss=002b  ds=002b  es=002b  fs=0053  gs=002b             efl=00000202
    DisplayGreeting!main+0x27:
    00b61917 e8def7ffff      call    DisplayGreeting!ILT+245(?GetCppConGreetingYAXPA_WIZ) (00b610fa)
    
  9. Úgy tűnik, megtaláltuk a kiváltó okot. A deklarált üdvözlőtömb hossza 50 karakter, míg a GetCppConGreetingbe átadott méret (üdvözlés) 0x64, 100.

    Képernyőkép a WinDbg-ről, amely a DisplayGreeting kódot jeleníti meg a Helyiek figyelése ablakkal, amelyen 0x64 látható.

    A méretproblémát tovább vizsgálva azt is észrevehetjük, hogy az üzenet 75 karakter hosszú, és 76 karakter, ha a string végét jelző karaktert is beleszámítjuk.

    HELLO FROM THE WINDBG TEAM. GOOD LUCK IN ALL OF YOUR TIME TRAVEL DEBUGGING!
    
  10. A kód kijavításának egyik módja, ha a karaktertömb méretét 100-ra bővíti.

    std::array <wchar_t, 100> greeting{};
    

    És ebben a kódsorban a sizeof(greeting)-et size(greeting)-re kell módosítanunk.

     GetCppConGreeting(greeting.data(), size(greeting));
    
  11. A javítások ellenőrzéséhez újrafordíthatjuk a kódot, és ellenőrizhetjük, hogy hiba nélkül fut-e.

Töréspont beállítása a forrásablak használatával

  1. A vizsgálat elvégzésének másik módja egy töréspont beállítása bármely kódsorra kattintva. Ha például a forrásablakban az std:tömbdefiníciós sor jobb oldalára kattint, ott beállít egy töréspontot.

    Képernyőkép a WinDbg Forrás ablakáról egy std::array törésponttal.

  2. Az Időutazás menü Időutazás parancsával lépjen a nyomkövetés elejére.

    0:000> !tt 0
    Setting position to the beginning of the trace
    Setting position: 15:0
    (1e5c.710): Break instruction exception - code 80000003 (first/second chance not available)
    Time Travel Position: 15:0
    eax=68e28100 ebx=00000000 ecx=77a266ac edx=69e34afc esi=69e3137c edi=00fa2000
    eip=77a266ac esp=00ddf3b8 ebp=00ddf608 iopl=0         nv up ei pl nz na pe nc
    cs=0023  ss=002b  ds=002b  es=002b  fs=0053  gs=002b             efl=00000206
    ntdll!LdrpInitializeProcess+0x1d1c:
    77a266ac 83bdbcfeffff00  cmp     dword ptr [ebp-144h],0 ss:002b:00ddf4c4=00000000
    
  3. A Kezdőlap menüszalagján kattintson az Ugrás gombra, és térjen vissza a töréspontig.

    Breakpoint 0 hit
    Time Travel Position: 5B:AF
    eax=0000000f ebx=00c20000 ecx=00000000 edx=00000000 esi=013a1046 edi=00effa60
    eip=013a17c1 esp=00eff970 ebp=00effa60 iopl=0         nv up ei pl nz na po nc
    cs=0023  ss=002b  ds=002b  es=002b  fs=0053  gs=002b             efl=00000202
    DisplayGreeting!DisplayGreeting+0x41:
    013a17c1 8bf4            mov     esi,esp
    

A megszólítási változó hozzáférési töréspontjának beállítása

A vizsgálat másik alternatív módja, ha töréspontot állít be a gyanús változókhoz, és megvizsgálja, hogy milyen kód módosítja őket. Ha például töréspontot szeretne beállítani a GetCppConGreeting metódus üdvözlő változóján, használja ezt az eljárást.

Az útmutató ezen része feltételezi, hogy továbbra is az előző szakasz töréspontján tartózkodik.

  1. Menj a Nézet menüpontra, majd válaszd a Helyiek lehetőséget. A helyi ablakban az üdvözlés az aktuális környezetben érhető el, így meg tudjuk határozni a memória helyét.

  2. A dx paranccsal vizsgálja meg az üdvözlőtömböt .

    0:000> dx &greeting
    &greeting                 : ddf800 : { size=50 } [Type: std::array<wchar_t,50> *]
       [<Raw View>]     [Type: std::array<wchar_t,50>]
       [0]              : 3 [Type: wchar_t]
       [1]              : 0 [Type: wchar_t]
    

    Ebben a nyomkövetésben az üdvözlés a ddf800 memóriájában található.

  3. A töréspontok ablakával törölheti a meglévő töréspontot. Ehhez kattintson a jobb gombbal a meglévő töréspontra, és válassza az Eltávolítás lehetőséget.

  4. Állítsa be a töréspontot a ba paranccsal a figyelendő memóriacím használatával az írási hozzáférés figyeléséhez.

    ba w4 ddf800
    
  5. Az Időutazás menü Időutazás parancsával lépjen a nyomkövetés elejére.

    0:000> !tt 0
    Setting position to the beginning of the trace
    Setting position: 15:0
    (1e5c.710): Break instruction exception - code 80000003 (first/second chance not available)
    Time Travel Position: 15:0
    eax=68e28100 ebx=00000000 ecx=77a266ac edx=69e34afc esi=69e3137c edi=00fa2000
    eip=77a266ac esp=00ddf3b8 ebp=00ddf608 iopl=0         nv up ei pl nz na pe nc
    cs=0023  ss=002b  ds=002b  es=002b  fs=0053  gs=002b             efl=00000206
    ntdll!LdrpInitializeProcess+0x1d1c:
    77a266ac 83bdbcfeffff00  cmp     dword ptr [ebp-144h],0 ss:002b:00ddf4c4=00000000
    
  6. A Kezdőlap menüben válassza az Ugrás lehetőséget, hogy előre lépjen az üdvözlő tömb első memóriaelérési pontjához.

    0:000> g-
    Breakpoint 0 hit
    Time Travel Position: 5B:9C
    eax=cccccccc ebx=002b1000 ecx=00000000 edx=68d51a6c esi=013a1046 edi=001bf7d8
    eip=013a1735 esp=001bf6b8 ebp=001bf7d8 iopl=0         nv up ei pl nz na po nc
    cs=0023  ss=002b  ds=002b  es=002b  fs=0053  gs=002b             efl=00000202
    DisplayGreeting!GetCppConGreeting+0x25:
    013a1735 c745ec04000000  mov     dword ptr [ebp-14h],4 ss:002b:001bf7c4=cccccccc
    

    Alternatív megoldásként elutazhattunk volna a nyomkövetés végére, és visszafelé dolgozva a kóddal, megtalálhattuk volna azt az utolsó nyomkövetési pontot, ahová a tömb memóriahelyét írták.

Használja a TTD.Memory objektumokat a memóriahozzáférés megtekintéséhez

Egy másik módja annak, hogy meghatározzuk, milyen pontokon történt a nyomkövetési memória elérése, a TTD.Memory objektumok és a dx parancs használata.

  1. A dx paranccsal vizsgálja meg az üdvözlőtömböt .

    0:000> dx &greeting
    &greeting                 : 0xddf800 [Type: std::array<wchar_t,50> *]
       [+0x000] _Elems           : "꽘棶檙瞝???" [Type: wchar_t [50]]
    

    Ebben a nyomkövetésben az üdvözlés a ddf800 memóriájában található.

  2. A dx paranccsal megtekintheti a memóriában lévő négy bájtot az adott címtől kezdve az olvasási írási hozzáféréssel.

    0:000> dx -r1 @$cursession.TTD.Memory(0xddf800,0xddf804, "rw")
    @$cursession.TTD.Memory(0x1bf7d0,0x1bf7d4, "rw")                
        [0x0]           
        [0x1]           
        [0x2]           
        [0x3]           
        [0x4]           
        [0x5]           
        [0x6]           
        [0x7]           
        [0x8]           
        [0x9]           
        [0xa]           
        ...         
    
  3. Az előfordulásokra kattintva további információt jeleníthet meg a memóriahozzáférés előfordulásáról.

    0:000> dx -r1 @$cursession.TTD.Memory(0xddf800,0xddf804, "rw")[5]
    @$cursession.TTD.Memory(0xddf800,0xddf804, "rw")[5]                
        EventType        : MemoryAccess
        ThreadId         : 0x710
        UniqueThreadId   : 0x2
        TimeStart        : 27:3C1 [Time Travel]
        TimeEnd          : 27:3C1 [Time Travel]
        AccessType       : Write
        IP               : 0x6900432f
        Address          : 0xddf800
        Size             : 0x4
        Value            : 0xddf818
        OverwrittenValue : 0x0
        SystemTimeStart  : Monday, November 18, 2024 23:01:43.400
        SystemTimeEnd    : Monday, November 18, 2024 23:01:43.400
    
  4. Kattintson a [Time Travel] (Időutazás) elemre a TimeStartban, hogy a nyomkövetést az adott időpontban helyezze el.

    0:000> dx @$cursession.TTD.Memory(0xddf800,0xddf804, "rw")[5].TimeStart.SeekTo()
    @$cursession.TTD.Memory(0xddf800,0xddf804, "rw")[5].TimeStart.SeekTo()
    (1e5c.710): Break instruction exception - code 80000003 (first/second chance not available)
    Time Travel Position: 27:3C1
    eax=00ddf81c ebx=00fa2000 ecx=00ddf818 edx=ffffffff esi=00000000 edi=00b61046
    eip=6900432f esp=00ddf804 ebp=00ddf810 iopl=0         nv up ei pl nz ac po nc
    cs=0023  ss=002b  ds=002b  es=002b  fs=0053  gs=002b             efl=00000212
    ucrtbased!_register_onexit_function+0xf:
    6900432f 51              push    ecx
    
  5. Ha érdekli az olvasási/írási memóriahozzáférés utolsó előfordulása a nyomkövetésben, kattintson a lista utolsó elemére, vagy fűzze hozzá a . Last() függvény a dx parancs végéig.

    0:000> dx -r1 @$cursession.TTD.Memory(0xddf800,0xddf804, "rw").Last()
    @$cursession.TTD.Memory(0xddf800,0xddf804, "rw").Last()                
        EventType        : MemoryAccess
        ThreadId         : 0x710
        UniqueThreadId   : 0x2
        TimeStart        : 53:100E [Time Travel]
        TimeEnd          : 53:100E [Time Travel]
        AccessType       : Read
        IP               : 0x690338e4
        Address          : 0xddf802
        Size             : 0x2
        Value            : 0x45
        SystemTimeStart  : Monday, November 18, 2024 23:01:43.859
        SystemTimeEnd    : Monday, November 18, 2024 23:01:43.859
    
  6. Ezután a [Time Travel] gombra kattintva továbbléphetünk a nyomkövetési pozícióra, és részletesebben megvizsgálhatjuk a kódvégrehajtást ezen a ponton, a laborban korábban ismertetett technikák használatával.

További információ a TTD.Memory objektumokról, lásd: TTD.Memory Objektum.

Összefoglalás

Ebben a nagyon kis mintában a problémát a kód néhány sorának megtekintésével lehetett volna meghatározni, de nagyobb programokban az itt bemutatott technikák segítségével csökkenthető a probléma megkereséséhez szükséges idő.

A nyomkövetés rögzítése után a nyomkövetési és a visszaállítási lépések megoszthatóak, és a probléma bármely pc-n reprodukálható lesz.

Lásd még:

Time Travel Hibakeresés – Áttekintés

Time Travel Hibakeresés – Felvétel

Időutazásos hibakeresés - Egy nyomkövetés újrajátszása

Time Travel Hibakeresés – Nyomkövetési fájlok használata