Dela via


Felsökning av tidsresor – Genomgång av exempelapp

#B0 #A1 #A2 Logotyp för felsökning av tidsresor med en klocka. #A3 #A4 #C5

Det här labbet introducerar TTD (Time Travel Debugging) med hjälp av ett litet exempelprogram med ett kodfel. TTD används för att felsöka, identifiera och fastställa grundorsaken till problemet. Även om problemet i det här lilla programmet är lätt att hitta kan den allmänna proceduren användas för mer komplex kod. Den här allmänna proceduren kan sammanfattas på följande sätt.

  1. Samla in en spårning av tidsresan för det misslyckade programmet.
  2. Använd kommandot dx (Display Debugger Object Model Expression) för att hitta undantagshändelsen som lagras i inspelningen.
  3. Använd kommandot !tt (tidsresa) för att resa till platsen för undantagshändelsen i spårningen.
  4. Från den punkten, spåra steg för steg bakåt tills den felaktiga koden i fråga kommer i fokus.
  5. Med felkoden i omfånget kan du titta på de lokala värdena och utveckla en hypotes för en variabel som kan innehålla ett felaktigt värde.
  6. Fastställ minnesadressen för variabeln med det felaktiga värdet.
  7. Ange en brytpunkt för minnesåtkomst (ba) på adressen till den misstänkta variabeln med hjälp av kommandot ba (Break on Access).
  8. Använd g – för att köra tillbaka till den sista minnesåtkomstpunkten för den misstänkta variabeln.
  9. Se om den platsen, eller några instruktioner tidigare, är punkten där kodfelet uppstår. I så fall är du klar. Om det felaktiga värdet kom från någon annan variabel anger du ytterligare en brytpunkt för åtkomstbrytpunkten för den andra variabeln.
  10. Använd g – för att köra tillbaka till den sista minnesåtkomstpunkten på den andra misstänkta variabeln. Se om platsen eller några instruktioner innan innehåller kodfelet. I så fall är du klar.
  11. Upprepa den här processen när du går tillbaka tills koden som anger det felaktiga värdet som orsakade felet finns.

Även om de allmänna tekniker som beskrivs i den här proceduren gäller för en bred uppsättning kodproblem, finns det unika kodproblem som kräver en unik metod. De tekniker som illustreras i genomgången bör användas för att utöka din felsökningsverktygsuppsättning och illustrerar en del av vad som är möjligt med en TTD-spårning.

Labbmål

När du har slutfört den här labbuppgiften kan du använda den allmänna proceduren med en spårning av tidsresor för att hitta problem i koden.

Labbkonfiguration

Du behöver följande maskinvara för att kunna slutföra labbet.

  • En bärbar dator eller stationär dator (värd) som kör Windows 10 eller Windows 11

Du behöver följande programvara för att kunna slutföra labbet.

  • The WinDbg. Information om hur du installerar WinDbg finns i WinDbg – Installation
  • Visual Studio för att skapa C++-exempelkoden.

Labbet har följande tre avsnitt.

Avsnitt 1: Skapa exempelkoden

I avsnitt 1 skapar du exempelkoden med hjälp av Visual Studio.

Skapa exempelappen i Visual Studio

  1. I Microsoft Visual Studio klickar du på Arkiv>Nytt>projekt/lösning... och klickar på Visual C++ -mallarna.

    Välj Win32-konsolprogrammet.

    Ange ett projektnamn för DisplayGreeting och klicka på OK.

  2. Avmarkera SDL-kontrollerna (Security Development Lifecycle).

    Inställningar för Win32-programguiden i Visual Studio.

  3. Klicka på Slutför.

  4. Klistra in följande text i fönstret DisplayGreeting.cpp i Visual Studio.

    // 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. I Visual Studio klickar du på Project>DisplayGreeting-egenskaper. Klicka sedan på C/C++ och Kodgenerering.

    Ange följande egenskaper.

    Inställning Värde
    Säkerhetskontroll Inaktivera säkerhetskontroll (/GS-)
    Grundläggande körningskontroller Standardinställning

    Anmärkning

    Även om den här inställningen inte rekommenderas är det möjligt att föreställa sig ett scenario där någon rekommenderar att du använder de här inställningarna för att påskynda kodningen eller för att underlätta vissa testmiljöer.

  6. I Visual Studio klickar du på Skapa>bygglösning.

    Om allt går bra bör byggfönstren visa ett meddelande som anger att bygget lyckades.

  7. Leta upp de skapade exempelappfilerna

    I Solution Explorer högerklickar du på projektet DisplayGreeting och väljer Öppna mapp i Utforskaren.

    Navigera till mappen Debug som innehåller det kompilerade exe-filen och symbol-pdb-filen för exemplet. Du kan till exempel navigera till C:\Projects\DisplayGreeting\Debug, om det är mappen som dina projekt lagras i.

  8. Kör exempelappen med kodfelet

    Dubbelklicka på exe-filen för att köra exempelappen.

    Skärmbild av konsolen som kör DisplayGreeting.exe-filen.

    Om den här dialogrutan visas väljer du Stäng program

    Skärmbild av dialogrutan medDisplayGreeting.exe har slutat fungera.

    I nästa avsnitt av genomgången registrerar vi körningen av exempelappen för att se om vi kan avgöra varför det här undantaget inträffar.

Avsnitt 2: Registrera en spårning av exemplet "DisplayGreeting"

I avsnitt 2 registrerar du en spårning av den felaktiga exempelappen "DisplayGreeting"

Följ dessa steg för att starta exempelappen och registrera en TTD-spårning. Allmän information om hur du registrerar TTD-spårningar finns i Felsökning av tidsresor – Registrera en spårning

  1. Kör WinDbg som administratör för att kunna registrera spårningar av tidsresor.

  2. I WinDbg väljer du Fil>Starta felsökning>Starta körbar fil (avancerat).

  3. Ange sökvägen till den användarmodus körbara filen som du vill registrera eller välj Bläddra för att navigera till den körbara filen. Information om hur du arbetar med den körbara startmenyn i WinDbg finns i WinDbg – Starta en session i användarläge.

    Skärmbild av WinDbg med kryssrutan

  4. Markera kryssrutan Record with Time Travel Debugging för att registrera en spårning när den körbara filen startas.

  5. Klicka på Konfigurera och spela in för att starta inspelningen.

  6. När dialogrutan "Konfigurera inspelning" visas, klickar du på Spela in för att starta den körbara filen och börja inspelningen.

    Skärmbild av WinDbg som visar dialogrutan Konfigurera inspelning med sökvägen inställd på c: temp.

  7. Inspelningsdialogrutan visas som anger att spårningen registreras. Kort därefter kraschar programmet.

  8. Klicka på Stäng program för att stänga dialogrutan "DisplayGreeting har slutat fungera".

    Dialogrutan som visar att Appen DisplayGreeting har slutat fungera.

  9. När programmet kraschar stängs spårningsfilen och skrivs ut till disken.

    Skärmbild av WinDbg-utdata som visar att 1/1 nyckelramar har indexerats.

  10. Felsökningsprogrammet öppnar automatiskt spårningsfilen och indexerar den. Indexering är en process som möjliggör effektiv felsökning av spårningsfilen. Den här indexeringsprocessen tar längre tid för större spårningsfiler.

    (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.
    

Anmärkning

En nyckelram är en plats i en spårning som används för indexering. Nyckelrutor genereras automatiskt. Större spårningar innehåller fler nyckelramar.

  1. Nu är du i början av spårningsfilen och är redo att färdas framåt och bakåt i tiden.

    Nu när du har registrerat en TTD-spårning kan du spela upp spårningen igen eller arbeta med spårningsfilen, till exempel dela den med en medarbetare. Mer information om hur du arbetar med spårningsfiler finns i Felsökning av tidsresor – Arbeta med spårningsfiler

I nästa avsnitt av den här labbuppgiften analyserar vi spårningsfilen för att hitta problemet med vår kod.

Avsnitt 3: Analysera spårningsfilinspelningen för att identifiera kodproblemet

I avsnitt 3 analyserar du spårningsfilens inspelning för att identifiera kodproblemet.

Konfigurera WinDbg-miljön

  1. Lägg till platsen för dina lokala symboler i sökvägen till symbolerna och ladda om symbolerna genom att skriva följande kommandon.

    .sympath+ C:\MyProjects\DisplayGreeting\Debug
    .reload
    
  2. Lägg till din lokala kodplats i källsökvägen genom att skriva följande kommando.

    .srcpath+ C:\MyProjects\DisplayGreeting\DisplayGreeting
    
  3. För att kunna visa tillståndet för stacken och lokala variabler går du till menyfliksområdet WinDbg och väljer Visa och Lokala och Visa och Stack. Ordna fönstren så att du kan visa dem, källkoden och kommandofönstren samtidigt.

  4. I menyfliksområdet WinDbg väljer du Källa och Fil med öppen källkod. Leta upp filen DisplayGreeting.cpp och öppna den.

Granska undantaget

  1. När spårningsfilen lästes in visas information om att ett undantag inträffade.

    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. Använd dx-kommandot för att visa en lista över alla händelser i inspelningen. Undantagshändelsen visas i händelserna.

    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
    ...
    
    

    Anmärkning

    I den här genomgången används tre perioder för att indikera att överflödiga utdata har tagits bort.

  3. Klicka på undantagshändelsen för att visa information om TTD-händelsen.

    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. Klicka på fältet Undantag för att ytterligare öka detaljnivån för undantagsdata.

    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
    

    Undantagsdata anger att detta är ett maskinvarufel som genereras av processorn. Den innehåller också undantagskoden för 0xc0000005 som anger att detta är en åtkomstöverträdelse. Detta indikerar vanligtvis att vi försökte skriva till minnet som vi inte har åtkomst till.

  5. Klicka på länken [Tidsresa] i undantagshändelsen för att flytta till den positionen i spårningen.

    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 ??
    

    Observera i det här utdata att stacken och baspekaren pekar på två mycket olika adresser.

    esp=00effe4c ebp=00520055
    

    Detta kan tyda på stackkorruption – möjligen att en funktion returnerades och sedan skadade stacken. För att verifiera detta måste vi gå tillbaka till innan cpu-tillståndet skadades och se om vi kan avgöra när stacken skadades.

Granska de lokala variablerna och ange en kodbrytningspunkt

Vid tidpunkten för spårningsfel är det vanligt att sluta med några steg efter den verkliga orsaken till felhanteringskoden. Med tidsresor kan vi gå tillbaka en instruktion i taget för att hitta den verkliga orsaken.

  1. I menyfliksområdet Start använder du kommandot Step Into Back för att gå tillbaka tre instruktioner. När du gör detta fortsätter du att undersöka stack- och minnesfönstren.

    Kommandofönstret visar tidsresepositionen och registreringarna när du går tillbaka tre instruktioner.

    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:
    

    Anmärkning

    I den här genomgången visar kommandoutdata de kommandon som kan användas i stället för menyalternativen för användargränssnittet så att användare med en kommandoradsanvändningsinställning kan använda kommandoradskommandon.

  2. Vid den här tidpunkten i spårningen har vår stack och baspekare värden som är mer meningsfulla, så det verkar som om vi har kommit närmare punkten i koden där skadan inträffade.

    esp=00effd94 ebp=00effe44
    

    Det är också intressant att det lokala fönstret innehåller värden från vår målapp och att källkodsfönstret markerar den kodrad som är redo att köras nu i spårningen.

  3. För ytterligare undersökning kan vi öppna ett minnesfönster för att visa innehållet nära minnesadressen för baspekaren för 0x00effe44.

  4. Om du vill visa de associerade ASCII-tecknen går du till menyfliksområdet Minne och väljer Text och sedan ASCII.

    Skärmbild av WinDbg Preview som visar minnes-ASCII-utdata och källkodsfönster.

  5. I stället för att baspekaren pekar på en instruktion pekar den på vår meddelandetext. Så något är fel här, detta kan vara nära den tidpunkt då vi kan ha skadat stacken. För ytterligare undersökning anger vi en brytpunkt.

Anmärkning

I det här mycket lilla exemplet skulle det vara ganska enkelt att bara titta i koden, men om det finns hundratals rader med kod och dussintals subrutiner kan de tekniker som beskrivs här användas för att minska den tid som krävs för att hitta problemet.

TTD och brytpunkter

Att använda brytpunkter är en vanlig metod för att pausa kodexekvering vid någon händelse av intresse. Med TTD kan du ange en brytpunkt och resa tillbaka i tiden tills brytpunkten nås efter att spårningen har registrerats. Möjligheten att undersöka processtillståndet när ett problem har inträffat, för att fastställa den bästa platsen för en brytpunkt, möjliggör ytterligare felsökningsarbetsflöden som är unika för TTD.

Brytpunkter för minnesåtkomst

Du kan ange brytpunkter som utlöses när en minnesplats används. Använd kommandot ba (break on access) med följande syntax.

ba <access> <size> <address> {options}
Alternativ Beskrivning
e execute (när CPU hämtar en instruktion från adressen)
r läs/skriv (när en CPU läser eller skriver till adressen)
w skriv (när processorn skriver till adressen)

Observera att du bara kan ange fyra data brytpunkter vid en viss tidpunkt och det är upp till dig att se till att du justerar dina data korrekt eller att du inte utlöser brytpunkten (ord måste sluta i adresser som är delbara med 2, dwords måste vara delbara med 4 och fyrord med 0 eller 8).

Ange brytpunkten för minnesåtkomst för baspekaren

  1. Nu i spårningen vill vi ange en brytpunkt för skrivminnesåtkomst till baspekaren – ebp som i vårt exempel är 00effe44. För att göra detta använder du ba-kommandot med den adress som vi vill övervaka. Vi vill övervaka skrivoperationer för fyra byte, så vi specificerar w4.

    0:000> ba w4 00effe44
    
  2. Välj Visa och sedan Brytpunkter för att bekräfta att de har angetts som avsedda.

    Skärmbild av fönstret WinDbg Breakpoints som visar en enda brytpunkt.

  3. På menyn Start väljer du Gå tillbaka för att resa tillbaka i tiden tills brytpunkten har nåtts.

    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älj Visa och sedan Lokal. I det lokala fönstret kan vi se att målvariabeln bara har en del av meddelandet, medan källan innehåller all text. Den här informationen stöder idén att stacken har blivit skadad.

    Skärmbild av WinDbg som visar fönstret Lokaler.

  5. Nu kan vi undersöka programstacken för att se vilken kod som är aktiv. Välj Stack i menyfliksområdet Visa.

    Skärmbild av WinDbg som visar Stack-fönstret.

Eftersom det är mycket osannolikt att funktionen wscpy_s() som tillhandahålls av Microsoft skulle ha ett kodfel som detta, undersöker vi stacken närmare. Stacken visar att Greeting!main anropar Greeting!GetCppConGreeting. I vårt mycket lilla kodexempel kan vi bara öppna koden just nu och förmodligen hitta felet ganska enkelt. Men för att illustrera de tekniker som kan användas med större, mer komplexa program, kommer vi att ange en ny brytpunkt för att undersöka ytterligare.

Ställ in en åtkomstbrytpunkt för funktionen GetCppConGreeting

  1. Använd brytpunktsfönstret för att rensa den befintliga brytpunkten genom att högerklicka på den befintliga brytpunkten och välja Ta bort.

  2. Fastställa adressen till DisplayGreeting!GetCppConGreeting-funktionen med hjälp av dx-kommandot.

    0:000> dx &DisplayGreeting!GetCppConGreeting
    &DisplayGreeting!GetCppConGreeting                 : 0xb61720 [Type: void (__cdecl*)(wchar_t *,unsigned int)]
        [Type: void __cdecl(wchar_t *,unsigned int)]
    
  3. Använd ba-kommandot för att ange en brytpunkt för minnesåtkomst. Eftersom funktionen bara kommer att läsas från minnet för körning måste vi ange en r - läs brytpunkt.

    0:000> ba r4 b61720
    
  4. Bekräfta att en brytpunkt för maskinvaruläsning är aktiv i brytpunktsfönstret.

    Skärmbild av fönstret WinDbg Breakpoints som visar en enda läsbrytningspunkt för maskinvara.

  5. Eftersom vi undrar över storleken på hälsningssträngen ställer vi in ett klockfönster för att visa värdet för sizeof(greeting). I menyfliksområdet Visa väljer du Titta och anger storlek(hälsning). Om värdet inte finns i omfånget visas övervakningsfönstret – Det går inte att binda namnet "hälsning".

    Skärmbild av WinDbg som visar ett visningsfönster för Lokal visning.

  6. På menyn Tidsresa använder du Tidsresa för att starta eller använd !tt 0kommandot för att gå till början av spåret.

    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. På startmenyn väljer du eller använder g kommandot för att gå vidare i koden tills brytpunkten har nåtts.

    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. På startmenyn väljer du Stega tillbaka eller använder g-u kommandot för att backa upp ett steg.

    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. Det verkar som om vi har hittat grundorsaken. Hälsningsmatrisen som vi deklarerade är 50 tecken lång, medan storleken på (hälsningen) som vi skickar till GetCppConGreeting är 0x64, 100.

    Skärmbild av WinDbg som visar DisplayGreeting-kod med ett Watch Locals-fönster som visar 0x64.

    När vi tittar närmare på storleksproblemet ser vi också att meddelandet är 75 tecken långt och är 76 när du inkluderar slutet av strängtecknet.

    HELLO FROM THE WINDBG TEAM. GOOD LUCK IN ALL OF YOUR TIME TRAVEL DEBUGGING!
    
  10. Ett sätt att åtgärda koden är att utöka storleken på teckenmatrisen till 100.

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

    Och vi måste också ändra sizeof(greeting) till size(greeting) i den här kodraden.

     GetCppConGreeting(greeting.data(), size(greeting));
    
  11. För att verifiera dessa korrigeringar kan vi kompilera om koden och bekräfta att den körs utan fel.

Ange en brytpunkt med hjälp av källfönstret

  1. Ett annat sätt att utföra den här undersökningen är att ange en brytpunkt genom att klicka på valfri kodrad. Om du till exempel klickar på höger sida av definitionsraden std:array i källfönstret anges en brytpunkt där.

    Skärmbild av källfönstret i WinDbg med en brytpunkt inställd på std::array.

  2. På menyn Tidsresa använder du kommandot Tidsresa för att starta för att gå till början av spårningen.

    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. I menyfliksområdet Start klickar du på för att gå tillbaka tills du når brytpunkten.

    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
    

Ange brytpunkten för åtkomstbrytpunkten för hälsningsvariabeln

Ett annat alternativt sätt att utföra den här undersökningen är att ange en brytpunkt för misstänkta variabler och undersöka vilken kod som ändrar dem. Om du till exempel vill ange en brytpunkt för hälsningsvariabeln i metoden GetCppConGreeting använder du den här proceduren.

Den här delen av genomgången förutsätter att du fortfarande finns vid brytpunkten från föregående avsnitt.

  1. Från Visa och sedan Lokaler. I det lokala fönstret är hälsning tillgänglig i den aktuella kontexten, så vi kommer att kunna fastställa dess minnesplats.

  2. Använd dx-kommandot för att undersöka hälsningsmatrisen.

    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]
    

    I den här spårningen är hälsning placerad i minnet på ddf800.

  3. Använd brytpunktsfönstret för att rensa alla befintliga brytpunkter genom att högerklicka på den befintliga brytpunkten och välja Ta bort.

  4. Ange brytpunkten med ba-kommandot med den minnesadress som vi vill övervaka för skrivåtkomst.

    ba w4 ddf800
    
  5. På menyn Tidsresa använder du kommandot Tidsresa för att starta för att gå till början av spårningen.

    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. På startmenyn väljer du för att gå vidare till den första minnesåtkomstpunkten för hälsningsmatrisen.

    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
    

    Alternativt kunde vi ha rest till slutet av spåret och arbetat baklänges genom koden för att hitta den sista punkten i spåret som minnesplatsen för arrayen skrevs till.

Använd TTD. Minnesobjekt för att visa minnesåtkomst

Ett annat sätt att avgöra vid vilka punkter i spårningsminnet som har använts är att använda TTD.Memory-objekt och dx-kommandot.

  1. Använd dx-kommandot för att undersöka hälsningsmatrisen.

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

    I det här spåret finns hälsningen i minnet på ddf800.

  2. Använd dx-kommandot för att titta på de fyra byte i minnet som börjar på den adressen med läsbehörighet.

    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. Klicka på någon av förekomsterna för att visa mer information om den förekomsten av minnesåtkomst.

    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. Klicka på [Tidsresa] så att TimeStart kan placera spåret vid tidpunkten.

    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. Om vi är intresserade av den senaste förekomsten av minnesåtkomst för läsning/skrivning i spårningen kan vi klicka på det sista objektet i listan eller lägga till . Funktionen Last() till slutet av dx-kommandot.

    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. Vi skulle kunna klicka på [Tidsresa] för att flytta till den positionen i spårningen och granska kodkörningen närmare vid den tidpunkten, med hjälp av de tekniker som beskrivs tidigare i den här övningen.

Mer information om TTD. Minnesobjekt, se TTD. Minnesobjekt.

Sammanfattning

I det här mycket lilla exemplet kunde problemet ha fastställts genom att titta på de få kodraderna, men i större program kan de tekniker som presenteras här användas för att minska den tid som krävs för att hitta ett problem.

När en spårning har registrerats kan spårnings- och återgivningsstegen delas och problemet kan återskapas på valfri dator.

Se även

Felsökning av tidsresande – Översikt

Felsökning av tidsresor – inspelning

Felsökning av tidsresor – Spela upp en spårfil

Felsökning av tidsresor – Arbeta med spårningsfiler