WinDbg: Časové osy

logo WinDbg s lupou, která kontroluje bity.

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.

Snímek obrazovky s časovými osami v debuggeru zobrazující výjimky, přístup k paměti, zarážky a volání funkcí.

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.

Snímek obrazovky časové osy v ladicím programu zobrazující výjimky s informacemi o konkrétním kódu výjimky

Pomocí volitelného pole Kód výjimky můžete dále filtrovat konkrétní kód výjimky.

Snímek obrazovky s dialogovým oknem výjimky ladicího nástroje časové osy, kde je typ časové osy nastaven na Výjimky, a kód výjimky nastaven na 0xC0000004.

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.

Snímek obrazovky časové osy v ladicím programu, který zobrazuje přibližně 30 indikátorů bodů přerušení

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

Snímek obrazovky znázorňuje přidání časové osy v ladicím programu se zadaným názvem volání funkce

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.

Snímek obrazovky časové osy v ladicím programu zobrazující volání funkcí a okno registrů.

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.

Snímek obrazovky s přidáním dialogového okna Přístup k paměti s vybranou možností Zápis

Když najedete myší na položku přístupu k paměti, zobrazí se hodnota a ukazatel instrukce.

Snímek obrazovky zobrazuje časovou osu v ladicím programu, která ukazuje události přístupu k paměti.

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.

Snímek obrazovky s časovou osou v ladicím programu zobrazující horní oblast použitou k výběru aktivního zobrazení

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

Snímek obrazovky s časovou osou v ladicím programu zobrazující ukázkovou výjimku testovacího prostředí a okno Registry

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.

Snímek obrazovky ladicího programu zobrazujícího okna Registry, Zásobník a Paměť

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

Snímek obrazovky s přidáním dialogového okna pro přístup k paměti časové osy s vybranou možností Zápis a počáteční hodnotou 003cf7c8

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

Snímek obrazovky časové osy přístupu k paměti a okna Místní hodnoty zobrazující místní hodnoty s odlišnými zdrojovými a cílovými hodnotami

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

Snímek obrazovky s časovou osou v ladicím programu zobrazující časové osy přístupu k paměti a okna Stack

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

Snímek obrazovky z aplikace, který zobrazuje dialogové okno přidání nové časové osy ukazující přidání časové osy Volání funkcí s vyhledávacím řetězcem DisplayGreeting!GetCppConGreeting.

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.

Snímek obrazovky časové osy v ladicím programu zobrazující časovou osu přístupu k paměti a okno Místní hodnoty se zprávou a vyrovnávací pamětí obsahujícími různé řetězcové hodnoty

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

Snímek obrazovky s časovou osou v ladicím programu zobrazující časovou osu přístupů k paměti a okno místních proměnných.

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.

Snímek obrazovky s dialogovým oknem Nová záložka zobrazující příklad názvu prvního volání rozhraní API v aplikaci Zobrazit pozdrav

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.

Snímek obrazovky časové osy zobrazující tři záložky, přičemž kurzor najede na jednu záložku, aby se zobrazil její název.

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.

Snímek obrazovky s místní nabídkou záložek, na které se zobrazují možnosti pro umístění, úpravy a odebrání, klikněte pravým tlačítkem myši.

Poznámka:

Funkce záložky není k dispozici ve verzi 1.2402.24001.0 WinDbg.