Poznámka:
Přístup k této stránce vyžaduje autorizaci. Můžete se zkusit přihlásit nebo změnit adresáře.
Přístup k této stránce vyžaduje autorizaci. Můžete zkusit změnit adresáře.
Ladění TTD (Time Travel Debugging) umožňuje uživatelům zaznamenávat stopy, což jsou záznamy provádění programu. Časové osy představují vizuální znázornění událostí, ke kterým dochází během provádění. Tyto události můžou zahrnovat například umístění zarážek, čtení a zápisy paměti, volání funkcí a návraty a výjimky.
Pomocí okna Časové osy můžete zobrazit důležité události, porozumět jejich relativní pozici a snadno přejít na jejich umístění v trasovacím souboru TTD. Pomocí více časových os můžete vizuálně zkoumat události v trasování časového cestování a zjišťovat korelaci událostí.
Když otevřete trasovací soubor TTD, zobrazí se okno Časové osy . Zobrazuje klíčové události, aniž byste museli ručně vytvářet dotazy datového modelu. Současně jsou k dispozici všechny objekty časové osy, které umožňují složitější dotazy na data.
Další informace o tom, jak vytvořit a pracovat se soubory tras časového cestování, naleznete v tématu Ladění časového cestování: Přehled.
Typy časových os
Okno Časové osy zobrazuje události na následujících časových osách:
- Výjimky: Můžete filtrovat podle konkrétního kódu výjimky.
- Zarážky: Uvidíte, kdy se zarážky na časové ose objeví.
- Přístupy k paměti: Můžete číst, zapisovat a spouštět mezi dvěma adresami paměti.
-
Volání funkcí: Můžete hledat ve formě
module!function.
Najeďte myší na každou událost, abyste získali další informace prostřednictvím popisu. Když vyberete událost, spustí se dotaz na událost a zobrazí se další informace. Poklikáním na událost přeskočíte do daného umístění v trasovacím souboru TTD.
Výjimky
Když načtete trasovací soubor a časová osa je aktivní, automaticky se v záznamu zobrazí všechny výjimky.
Když najedete myší na zarážku, zobrazí se informace, jako je typ výjimky a kód výjimky.
Pomocí volitelného pole Kód výjimky můžete dále filtrovat konkrétní kód výjimky.
Můžete také přidat novou časovou osu pro konkrétní typ výjimky.
Zarážky
Po přidání přerušení vám pozice na časové ose ukázují, kdy dojde k tomuto přerušení. Můžete například použít příkaz bp Set Breakpoint. Když na zarážku najedete myší, zobrazí se adresa a ukazatel instrukce přidružené k zarážce.
Když se přerušovací bod vymaže, přidružená časová osa přerušovacího bodu se automaticky odebere.
Volání funkcí
Pozice volání funkcí můžete zobrazit na časové ose. Chcete-li provést tento krok, zadejte hledání ve formě module!function. Příklad: TimelineTestCode!multiplyTwo. Můžete také zadat zástupné znaky, například TimelineTestCode!m*.
Když na volání funkce najedete myší, zobrazí se název funkce, vstupní parametry, jejich hodnoty a vrácená hodnota. Tento příklad ukazuje vyrovnávací paměť a velikost, jelikož se jedná o parametry pro DisplayGreeting!GetCppConGreeting.
Přístup k paměti
Časová osa Přístup k paměti umožňuje zjistit, kdy byl určitý rozsah paměti přečtený nebo zapsaný nebo kde proběhlo spuštění kódu. Počáteční a zastavové adresy slouží k definování rozsahu mezi dvěma adresami paměti.
Když najedete myší na položku přístupu k paměti, zobrazí se hodnota a ukazatel instrukce.
Práce s časovými osami
Svislá šedá čára následuje kurzor, když přejedete myší přes časovou osu. Svislá modrá čára označuje aktuální pozici v trasování.
Vyberte ikony lupy, které chcete přiblížit a oddálit na časové ose.
V horní oblasti ovládacího prvku časové osy použijte obdélník k posouvání zobrazení časové osy. Přetažením vnějších oddělovačů obdélníku změňte velikost aktuálního zobrazení časové osy.
Pohyby myši
Pokud chcete zobrazení přiblížit nebo oddálit, vyberte Ctrl a použijte kolečko.
Pokud chcete posouvat ze strany na stranu, vyberte Shift a použijte kolečko.
Techniky ladění časové osy
Abychom si ukázali techniky ladění časové osy, je zde znovu použit procházení ladění s cestováním v čase. Tato ukázka předpokládá, že jste dokončili první dva kroky k sestavení ukázkového kódu a vytvoření záznamu TTD pomocí prvních dvou kroků popsaných v tomto příkladu.
V tomto scénáři je prvním krokem nalezení výjimky v záznamu časového cestování. Poklikejte na jedinou výjimku, kterou vidíte na časové ose.
V příkazovém okně vidíte, že při výběru výjimky byl vydán následující příkaz.
(2dcc.6600): Break instruction exception - code 80000003 (first/second chance not available)
Time Travel Position: CC:0
@$curprocess.TTD.Events.Where(t => t.Type == "Exception")[0x0].Position.SeekTo()
Vyberte Zobrazit>registr abyste zobrazili registry v tomto okamžiku na časové ose a zahájili šetření.
Ve výstupu příkazu zásobník (esp) a základní ukazatel (ebp) odkazují na různé adresy. Tato nesrovnalost může značit poškození zásobníku. Pravděpodobně se funkce vrátila a pak byl poškozen zásobník. Pokud chcete tento problém ověřit, vraťte se do doby před poškozením stavu CPU a zjistěte, kdy došlo k poškození zásobníku.
Během tohoto procesu prozkoumejte hodnoty místních proměnných a zásobníku:
- Výběrem možnosti Zobrazit>místní hodnoty zobrazíte místní hodnoty.
- Zvolte Zobrazit>Zásobník pro zobrazení zásobníku spouštění kódu.
V okamžiku selhání je v trasování běžné skončit několik kroků po skutečné příčině v kódu pro zpracování chyb. S časovým cestováním se můžete kdykoli vrátit k jedné instrukci, abyste našli skutečnou původní příčinu.
Na pásu karet Domů použijte příkaz Vstoupit zpět, abyste se posunuli zpět o tři instrukce. Během tohoto procesu pokračujte v prozkoumání oken Stack, Locals a Registers .
V příkazovém okně se zobrazí pozice časové osy a registry, jakmile přejdete o tři instrukce zpět.
0:000> t-
Time Travel Position: CB:41
eax=00000000 ebx=00564000 ecx=c0d21d62 edx=7a1e4a6c esi=00061299 edi=00061299
eip=00540020 esp=003cf7d0 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: CB:40
eax=00000000 ebx=00564000 ecx=c0d21d62 edx=7a1e4a6c esi=00061299 edi=00061299
eip=00061767 esp=003cf7cc 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+0x57:
00061767 c3 ret
0:000> t-
Time Travel Position: CB:3A
eax=0000004c ebx=00564000 ecx=c0d21d62 edx=7a1e4a6c esi=00061299 edi=00061299
eip=0006175f esp=003cf718 ebp=003cf7c8 iopl=0 nv up ei pl nz na pe nc
cs=0023 ss=002b ds=002b es=002b fs=0053 gs=002b efl=00000206
DisplayGreeting!main+0x4f:
0006175f 33c0 xor eax,eax
V tomto okamžiku ve sledu mají váš zásobník a základní ukazatel hodnoty, které dávají větší smysl. Zdá se, že se blížíte bodu v kódu, ve kterém došlo k poškození.
esp=003cf718 ebp=003cf7c8
Okno Místní hodnoty obsahuje hodnoty z cílové aplikace. Okno Zdroj zvýrazní řádek kódu, který je připraven ke spuštění ve vašem zdrojovém kódu při aktuálním sledování.
Pokud chcete provést další šetření, otevřete okno Paměť a zobrazte obsah v blízkosti adresy paměti ukazatele zásobníku (esp). V tomto příkladu má hodnotu 003cf7c8. Vyberte Paměť>Text>ASCII a zobrazí se ASCII text uložený na této adrese.
Časová osa přístupu k paměti
Po zjištění umístění paměti, které je zajímavé, použijte tuto hodnotu k přidání časové osy přístupu k paměti. Vyberte + Přidat časovou osu a vyplňte počáteční adresu. Podívejte se na 4 bajty, takže když je přidáte do počáteční adresy hodnoty 003cf7c8, máte koncovou adresu hodnotu 003cf7cb. Výchozí nastavení je podívat se na všechny zápisy do paměti, ale můžete se také podívat pouze na zápisy nebo spuštění kódu na této adrese.
Teď můžete zpětně prozkoumávat časovou osu, abyste zjistili, v jakém okamžiku v trase časové cesty bylo toto umístění paměti zapsáno, a zjistit, co můžete objevit. Když tuto pozici vyberete na časové ose, uvidíte, že místní hodnoty mají pro zkopírovaný řetězec jinou hodnotu. Zdá se, že cílová hodnota není úplná, jako kdyby délka vašeho řetězce nebyla správná.
Časová osa bodu přerušení
Použití zarážek je běžný přístup k pozastavení provádění kódu v určitém případě zájmu. Pomocí funkce TTD můžete nastavit bod přerušení a cestovat zpět v čase, dokud není bod přerušení dosažen po zaznamenání trasování. Schopnost prozkoumat stav procesu po výskytu problému a určit nejlepší umístění pro bod přerušení umožňuje více ladicích pracovních postupů jedinečných pro TTD.
Pokud chcete prozkoumat alternativní techniku ladění časové osy, vyberte výjimku na časové ose a znovu přejděte třemi kroky zpět pomocí příkazu Zpětný krok na kartě Domů.
V této malé ukázce je snadné se podívat do kódu. Pokud máte stovky řádků kódu a desítek podprogramů, pomocí technik popsaných zde snižte dobu potřebnou k vyhledání problému.
Jak už bylo zmíněno dříve, základní ukazatel (esp) odkazuje na text zprávy místo na instrukci.
ba Pomocí příkazu nastavte zarážku pro přístup k paměti. Nastavíte zarážku zápisu, w - abyste viděli, kdy se do této oblasti paměti zapisuje.
0:000> ba w4 003cf7c8
I když používáte jednoduchou zarážku přístupu k paměti, můžete vytvořit zarážky tak, aby byly složitější podmíněné příkazy. Další informace naleznete v tématu bp, bu, bm (Set Breakpoint).
V nabídce Domů vyberte Přejít zpět a vraťte se v čase, dokud nenarazíte na zarážku.
V tomto okamžiku můžete prozkoumat zásobník programu a zjistit, jaký kód je aktivní.
Vzhledem k tomu, že je nepravděpodobné, že by funkce poskytovaná wscpy_s() Microsoftem mohla mít takovou chybu kódu, podívejte se dále do zásobníku. Zásobník ukazuje, že Greeting!main volá Greeting!GetCppConGreeting. V malé ukázce kódu byste mohli kód otevřít v tomto okamžiku a pravděpodobně chybu snadno najít. Abyste ale mohli znázornit techniky, které můžete použít s větším, složitějším programem, přidáte časovou osu volání funkce.
Časová osa volání funkce
Vyberte + Přidat časovou osu a vyplňte DisplayGreeting!GetCppConGreeting hledaný řetězec funkce.
Zaškrtávací políčka Počáteční umístění a Koncové umístění označují začátek a konec volání funkce v trasování.
Pomocí příkazu můžete dx zobrazit objekt volání funkce a zobrazit přidružená TimeStart pole a TimeEnd pole odpovídající počátečnímu umístění a koncovému umístění volání funkce.
dx @$cursession.TTD.Calls("DisplayGreeting!GetCppConGreeting")[0x0]
EventType : 0x0
ThreadId : 0x6600
UniqueThreadId : 0x2
TimeStart : 6D:BD [Time Travel]
SystemTimeStart : Thursday, October 31, 2019 23:36:05
TimeEnd : 6D:742 [Time Travel]
SystemTimeEnd : Thursday, October 31, 2019 23:36:05
Function : DisplayGreeting!GetCppConGreeting
FunctionAddress : 0x615a0
ReturnAddress : 0x61746
Parameters
Musí být zaškrtnuto jedno z políček Počáteční umístění nebo Koncové umístění nebo obě políčka Počáteční umístění a Koncové umístění .
Váš kód není rekurzivní ani znovuvstupný, takže je snadné najít na časové ose, kdy je metoda GetCppConGreeting volána. Volání GetCppConGreeting se také vyskytuje ve stejný čas jako vaše zarážka a událost přístupu k paměti, kterou jste definovali. Vypadá to, že jste se zúžili na oblast kódu, abyste se pečlivě podívali na původní příčinu chybového ukončení aplikace.
Prozkoumání provádění kódu zobrazením několika časových os
I když je náš vzorový kód malý, technika použití více časových os umožňuje vizuální zkoumání trasování času. Při prohlížení trasovacího souboru můžete pokládat otázky jako například: "Kdy je oblast paměti přistupována předtím, než je dosažena zarážka?"
Možnost zobrazit více korelací a najít neočekávané věci odlišuje nástroj časové osy od interakce s trasováním cesty času pomocí příkazů příkazového řádku.
Záložky na časové ose
Vytvořte záložku důležitých pozic pro cestování času ve WinDbg místo ručního kopírování a vkládání pozice do Poznámkového bloku. Záložky usnadňují přehledné prohlížení pozic ve sledování vzhledem k jiným událostem a jejich anotaci.
Můžete zadat popisný název záložek.
Výběrem Zobrazit>časovou osu otevřete okno Časové osy, abyste měli přístup k časové ose Záložek. Když na záložku najedete myší, zobrazí se název záložky.
Klikněte pravým tlačítkem myši na záložku a přejděte na pozici záložky, přejmenujte ji nebo ji odstraňte.
Poznámka:
Funkce záložky není k dispozici ve verzi 1.2402.24001.0 WinDbg.