Not
Bu sayfaya erişim yetkilendirme gerektiriyor. Oturum açmayı veya dizinleri değiştirmeyi deneyebilirsiniz.
Bu sayfaya erişim yetkilendirme gerektiriyor. Dizinleri değiştirmeyi deneyebilirsiniz.
"Zaman yolculuğu hata ayıklama logosu, bir saat içerir
"
Bu laboratuvarda, kod kusuru olan küçük bir örnek program kullanan Time Travel Debugging (TTD) tanıtılır. TTD, sorunun hatalarını ayıklamak, tanımlamak ve sorunun kök nedenini belirlemek için kullanılır. Bu küçük programdaki sorunu bulmak kolay olsa da, genel yordam daha karmaşık kodlarda kullanılabilir. Bu genel yordam aşağıdaki gibi özetlenebilir.
- Başarısız programın zaman yolculuğu izini yakalayın.
- Kayıtta depolanan özel durum olayını bulmak için dx (Görüntü Hata Ayıklayıcısı Nesne Modeli İfadesi) komutunu kullanın.
- İzlemedeki özel durum olayının konumuna gitmek için !tt (zaman yolculuğu) komutunu kullanın.
- İzden o noktaya kadar adım adım geriye doğru izleyin ve söz konusu hatalı kod kapsamına girene kadar devam edin.
- Kapsam dahilindeki hatalı kodla, yerel değerlere bakın ve yanlış bir değer içerebilecek bir değişkene dair bir hipotez geliştirin.
- Değişkenin bellek adresini yanlış değerle belirleyin.
- ba ( Erişimde Kes ) komutunu kullanarak şüpheli değişkenin adresinde bir bellek erişimi (ba) kesme noktası ayarlayın.
- Şüpheli değişkenin bellek erişiminin son noktasına geri dönmek için g- kullanın.
- Bu konumun veya daha önce birkaç yönergenin kod kusurunun noktası olup olmadığını görün. Öyleyse, işiniz bitti. Yanlış değer başka bir değişkenden geldiyse, ikinci değişkende erişim kesme noktasında başka bir kesme ayarlayın.
- İkinci şüpheli değişkende bellek erişiminin son noktasına geri dönmek için g- kullanın. Bu konumun veya önceki birkaç yönergenin kod kusurunu içerip içermediğini görün. Öyleyse, işiniz bitti.
- Hataya neden olan yanlış değeri ayarlayan kod bulunana kadar bu işlemi tekrarlayın.
Bu yordamda açıklanan genel teknikler çok çeşitli kod sorunları için geçerli olsa da, benzersiz bir yaklaşım gerektirecek benzersiz kod sorunları vardır. Adım adım kılavuzda gösterilen teknikler, hata ayıklama araç kümenizi genişletmeye hizmet etmelidir ve TTD izlemesiyle nelerin mümkün olduğunu gösterecektir.
Laboratuvar hedefleri
Bu laboratuvarı tamamladıktan sonra, koddaki sorunları tespit etmek için zaman yolculuğu izleği ile genel prosedürü kullanabileceksiniz.
Laboratuvar kurulumu
Laboratuvarı tamamlayabilmeniz için aşağıdaki donanıma ihtiyacınız olacaktır.
- Windows 10 veya Windows 11 çalıştıran bir dizüstü veya masaüstü bilgisayar (konak)
Laboratuvarı tamamlamak için aşağıdaki yazılıma ihtiyacınız olacaktır.
- The WinDbg. WinDbg'yi yükleme hakkında bilgi için bkz. WinDbg - Yükleme
- Örnek C++ kodunu oluşturmak için Visual Studio.
Laboratuvarda aşağıdaki üç bölüm bulunur.
- Bölüm 1: Örnek kodu oluşturma
- Bölüm 2: "DisplayGreeting" örneğinin izlemesini kaydetmek
- Bölüm 3: Kod sorununu tanımlamak için izleme dosyası kaydını analiz etme
Bölüm 1: Örnek kodu oluşturma
Bölüm 1'de Visual Studio kullanarak örnek kodu oluşturacaksınız.
Visual Studio'da örnek uygulama oluşturma
Microsoft Visual Studio'da Dosya>Yeni>Proje/Çözüm... seçeneğine ve ardından Visual C++ şablonlarına tıklayın.
Win32 Konsol Uygulamasını seçin.
DisplayGreeting proje adını girin ve Tamam'a tıklayın.
Güvenlik Geliştirme Yaşam Döngüsü (SDL) kontrol işaretlerini kaldırın.
Son'a tıklayın.
Aşağıdaki metni Visual Studio'daki DisplayGreeting.cpp bölmesine yapıştırın.
// 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; }Visual Studio'da Project>DisplayGreeting özellikleri'ne tıklayın. Ardından C/C++ ve Kod Oluşturma'ya tıklayın.
Aşağıdaki özellikleri ayarlayın.
Ayarlar Değer Güvenlik Denetimi Güvenlik Denetimini Devre Dışı Bırak (/GS-) Temel Çalışma Zamanı Denetimleri Varsayılan Uyarı
Bu ayar önerilmiyor olsa da, birinin kodlamayı hızlandırmak veya belirli test ortamlarını kolaylaştırmak için bu ayarların kullanılmasını önereceği bir senaryo hayal etmek mümkündür.
Visual Studio'da Oluştur>Çözümü Derle'ye tıklayın.
Her şey yolunda giderse, derleme pencerelerinin derlemenin başarılı olduğunu belirten bir ileti görüntülemesi gerekir.
Yerleşik örnek uygulama dosyalarını bulma
Çözüm Gezgini'nde DisplayGreeting projesine sağ tıklayın ve Dosya gezgininde Klasör Aç'ı seçin.
Örnek için uyumlu exe ve sembol pdb dosyasını içeren Debug klasörüne gidin. Örneğin, projelerinizin depolandığı klasör buysa C:\Projects\DisplayGreeting\Debug konumuna gidebilirsiniz.
Kod kusuruyla örnek uygulamayı çalıştırma
Örnek uygulamayı çalıştırmak için exe dosyasına çift tıklayın.
Bu iletişim kutusu görüntülenirse Programı kapat'ı seçin
Rehberin bir sonraki bölümünde, bu özel durumun neden oluştuğunu tespit edebilir miyiz diye örnek uygulamanın yürütülmesinin kaydını yapacağız.
Bölüm 2: "DisplayGreeting" örneğinin bir izlemesini kaydetme
Bölüm 2'de hatalı davranan örnek "DisplayGreeting" uygulamasının bir izlemesini kaydedeceksiniz
Örnek uygulamayı başlatmak ve bir TTD izlemesi kaydetmek için aşağıdaki adımları izleyin. TTD izlerini kaydetme hakkında genel bilgi için bkz. Zaman Yolculuğu Hata Ayıklama - İz kaydetme
Zaman yolculuğu izlemelerini kaydedebilmek için WinDbg'yi Yönetici olarak çalıştırın.
WinDbg'de Dosya>Hata ayıklamayı başlat>Gelişmiş yürütülebilir dosyayı başlat seçin.
Kaydetmek istediğiniz kullanıcı modu yürütülebilir dosyasının yolunu girin veya yürütülebilir dosyayı bulmak için Gözat seçeneğini seçin. WinDbg'de yürütülebilir başlat menüsüyle çalışma hakkında bilgi için bkz. WinDbg - Kullanıcı modu oturumu başlatma.
Yürütülebilir dosya başlatıldığında bir izleme kaydetmek için Zaman Yolculuğu Hata Ayıklama ile Kaydet kutusunu işaretleyin.
Kaydı başlatmak için Yapılandır ve Kaydet'e tıklayın.
"Kaydı yapılandır" iletişim kutusu görüntülendiğinde, yürütülebilir dosyayı başlatmak ve kaydı başlatmak için Kaydet'e tıklayın.
İz kaydının yapıldığını belirten kayıt iletişim kutusu görüntülenir. Bundan kısa bir süre sonra uygulama çöker.
"DisplayGreeting çalışmayı durdurdu" iletişim kutusunu kapatmak için Programı Kapat'a tıklayın.
Program kilitlendiğinde, izleme dosyası kapatılacak ve diske yazılacaktır.
Hata ayıklayıcı, izleme dosyasını otomatik olarak açar ve dizine ekler. Dizin oluşturma, izleme dosyasının verimli bir şekilde hata ayıklamasını sağlayan bir işlemdir. Bu dizin oluşturma işlemi daha büyük izleme dosyaları için daha uzun sürer.
(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.
Uyarı
Anahtar kare, dizin oluşturmak için kullanılan izlemedeki bir konumdur. Ana kareler otomatik olarak oluşturulur. Daha büyük izler daha fazla ana kare içerir.
Bu noktada izleme dosyasının başındasınız ve zamanda ileri ve geri gitmeye hazırsınız.
Artık bir TTD izlemesi kaydettiğinize göre, izleme dosyasını yeniden yürütebilir veya izleme dosyasıyla çalışabilirsiniz, örneğin bir iş arkadaşı ile paylaşabilirsiniz. İzleme dosyalarıyla çalışma hakkında daha fazla bilgi için bkz. Zaman Yolculuğu Hata Ayıklama - İzleme Dosyalarıyla Çalışma
Bu laboratuvarın sonraki bölümünde, kodumuzla ilgili sorunu bulmak için izleme dosyasını analiz edeceğiz.
Bölüm 3: Kod sorununu tanımlamak için izleme dosyası kaydını analiz etme
Bölüm 3'te, kod sorununu tanımlamak için izleme dosyası kaydını analiz edeceksiniz.
WinDbg Ortamını Yapılandırma
Yerel simge konumunuzu sembol yoluna ekleyin ve aşağıdaki komutları yazarak simgeleri yeniden yükleyin.
.sympath+ C:\MyProjects\DisplayGreeting\Debug .reloadAşağıdaki komutu yazarak yerel kod konumunuzu kaynak yola ekleyin.
.srcpath+ C:\MyProjects\DisplayGreeting\DisplayGreetingYığının ve yerel değişkenlerin durumunu görüntüleyebilmek için WinDbg şeridinde Görünüm ve Yerel Ayarlar ile Görünüm ve Yığın'ı seçin. Pencereleri, kaynak kodu ve komut pencerelerini aynı anda görüntülemenizi sağlayacak şekilde düzenleyin.
WinDbg şeridinde Kaynak ve Açık Kaynak Dosyası'nı seçin. DisplayGreeting.cpp dosyasını bulun ve açın.
Özel durumu inceleme
İzleme dosyası yüklendiğinde, bir özel durumun oluştuğu bilgisini görüntüler.
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=00000000Kayıttaki tüm olayları listelemek için dx komutunu kullanın. Özel durum olayı, olaylarda listelenir.
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 ...Uyarı
Bu rehberde, gereksiz çıktıların kaldırıldığını belirtmek için üç nokta kullanılır.
Bu TTD olayıyla ilgili bilgileri görüntülemek için Özel Durum olayına tıklayın.
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Özel durum verilerinde daha fazla detaya gitmek için Özel Durum alanına tıklayın.
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Özel durum verileri bunun CPU tarafından oluşan bir Donanım hatası olduğunu gösterir. Ayrıca, bunun bir erişim ihlali olduğunu gösteren 0xc0000005 özel durum kodunu sağlar. Bu genellikle erişimimiz olmayan belleğe yazmaya çalıştığımızı gösterir.
İzlemedeki bu konuma gitmek için özel durum olayında [Zaman Yolculuğu] bağlantısına tıklayın.
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 ??Bu çıkışta, yığın ve temel işaretçinin iki çok farklı adrese işaret ettiğini unutmayın.
esp=00effe4c ebp=00520055Bu, yığın bozulmasını gösterebilir; büyük olasılıkla bir işlev döndürülür ve sonra yığını bozar. Bunu doğrulamak için CPU durumunun bozulmasından önce adresine geri dönmemiz ve yığın bozulmasının ne zaman gerçekleştiğini belirleyip belirleyemediğini görmemiz gerekir.
Yerel değişkenleri inceleme ve bir kod kesme noktası ayarlama
İzlemedeki hata noktasında, hata işleme kodundaki gerçek nedenden sonra birkaç adım olması yaygın bir durumdur. Zaman yolculuğuyla, gerçek kök nedeni bulmak için bir kerede bir yönergeye geri dönebiliriz.
Giriş şeridinden Geri Adım At komutunu kullanarak üç yönerge geri gidin. Bunu yaptığınız gibi yığın ve bellek pencerelerini incelemeye devam edin.
Komut penceresinde, üç yönerge geri adım attıkça zaman yolculuğu konumu ve yazmaçlar görüntülenir.
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:Uyarı
Bu kılavuzda komut çıktısı, komut satırı kullanım tercihi olan kullanıcıların komut satırı komutlarını kullanmasına izin vermek için KULLANıCı Arabirimi Menüsü seçenekleri yerine kullanılabilecek komutları gösterir.
İzlemenin bu noktasında yığınımız ve temel işaretçimiz daha anlamlı değerlere sahiptir, bu nedenle kodda bozulmanın oluştuğu noktaya yaklaştığımız görülüyor.
esp=00effd94 ebp=00effe44Ayrıca, yerel ayarlar penceresinin hedef uygulamamızdan değerler içermesi ve kaynak kod penceresinin izlemenin bu noktasında yürütülmeye hazır olan kod satırını vurgulaması da ilgi çekicidir.
Daha fazla araştırma yapmak için, 0x00effe44 temel işaretçi bellek adresinin yanındaki içeriği görüntülemek için bir bellek penceresi açabiliriz.
İlişkili ASCII karakterlerini görüntülemek için Bellek şeridinden Metin'i ve ardından ASCII'yi seçin.
Bir yönergeye işaret eden temel işaretçi yerine ileti metnimize işaret ediyor. Bu nedenle burada bir sorun var, bu, yığını bozdığımız noktaya yakın olabilir. Daha fazla araştırmak için bir kesme noktası ayarlayacağız.
Uyarı
Bu çok küçük örnekte yalnızca koda bakmak oldukça kolay olacaktır, ancak yüzlerce kod satırı ve onlarca alt yordam varsa, sorunu bulmak için gereken süreyi azaltmak için burada açıklanan teknikler kullanılabilir.
TTD ve kesme noktaları
Kesme noktalarını kullanmak, ilgi çekici bir durumda kod yürütmeyi duraklatmak için yaygın bir yaklaşımdır. TTD, izleme kaydedildikten sonra kesme noktasına ulaşılana kadar bir kesme noktası ayarlamanıza ve zamanda geri dönmenize olanak tanır. Bir sorun oluştuktan sonra işlem durumunu inceleyerek kesme noktasının en iyi konumunu belirleme olanağı, TTD'ye özgü ek hata ayıklama iş akışlarını etkinleştirir.
Bellek erişim kesme noktaları
Bellek konumuna erişildiğinde tetiklenen kesme noktaları ayarlayabilirsiniz. Aşağıdaki söz dizimiyle ba (erişimde kesme) komutunu kullanın.
ba <access> <size> <address> {options}
| Seçenek | Açıklama |
|---|---|
| e | yürüt (CPU bir yönergeyi adresten aldığında) |
| r | okuma/yazma (CPU adresi okuduğunda veya yazdığında) |
| w | yazma (CPU adrese yazdığında) |
Herhangi bir zamanda yalnızca dört veri kesme noktası ayarlayabileceğinizi unutmayın ve verilerinizi doğru hizalamazsanız kesme noktasını tetikleyemezsiniz (sözcüklerin 2 ile bölünebilen adreslerle bitmesi, dword'ların 4 ile bölünebilmesi ve kuad kelimelerin 8 ile bölünebilir olması gerekir).
Temel işaretçi için bellek erişim kesme noktasında kesmeyi ayarlama
İzlemenin bu noktasında, örneğimizde 00effe44 olan ebp temel işaretçisine yazma belleği erişimi için bir kesme noktası belirlemek istiyoruz. Bunu yapmak için izlemek istediğimiz adresi kullanarak ba komutunu kullanın. Dört baytlık yazmaları izlemek istediğimiz için w4 değerini belirteceğiz.
0:000> ba w4 00effe44Amaçlandığı gibi ayarlandıklarını onaylamak için Görünüm'ü ve ardından Kesme Noktaları'na tıklayın.
Giriş menüsünden, kesme noktasına isabet edene kadar zamanda geri gitmek için Geri Git'i seçin.
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=ccccccccGörünüm'ü ve ardından Yerel Ayarlar'ı seçin. Yerel ayarlar penceresinde hedef değişkenin iletinin yalnızca bir bölümüne sahip olduğunu, kaynakta ise metnin tamamının bulunduğunu görebiliriz. Bu bilgiler yığının bozuk olduğu fikrini destekler.
Bu noktada hangi kodun etkin olduğunu görmek için program yığınını inceleyebiliriz. Görünüm şeridinden Yığın'ı seçin.
Microsoft tarafından sağlanan wscpy_s() işlevinin bunun gibi bir kod hatasına sahip olması çok düşük bir olasılık olduğundan yığında daha fazla inceleme yaparız. Yığın, Greeting!main'in Greeting!GetCppConGreeting'i çağırdığını gösterir. Çok küçük kod örneğimizde kodu bu noktada açabilir ve büyük olasılıkla hatayı oldukça kolay bulabilirdik. Ancak daha büyük, daha karmaşık bir programla kullanılabilecek teknikleri göstermek için daha fazla araştırma yapmak için yeni bir kesme noktası ayarlayacağız.
GetCppConGreeting işlevi için erişim kesme noktasında kesmeyi ayarlama
Var olan kesme noktasına sağ tıklayıp Kaldır'ı seçerek var olan kesme noktasını temizlemek için kesme noktaları penceresini kullanın.
DisplayGreeting'in adresini belirleyin! dx komutunu kullanarak GetCppConGreeting işlevi.
0:000> dx &DisplayGreeting!GetCppConGreeting &DisplayGreeting!GetCppConGreeting : 0xb61720 [Type: void (__cdecl*)(wchar_t *,unsigned int)] [Type: void __cdecl(wchar_t *,unsigned int)]Bellek erişiminde kesme noktası ayarlamak için ba komutunu kullanın. İşlev yalnızca yürütme için bellekten okunacağından r - okuma kesme noktası ayarlamamız gerekir.
0:000> ba r4 b61720Kesme noktaları penceresinde Donanım Okuma kesme noktasının etkin olduğunu onaylayın.
Selamlama dizesinin boyutunu merak ettiğimiz için sizeof(selamlama) değerini görüntülemek için bir izleme penceresi ayarlayacağız. Görünüm şeridinden İzle'yi seçin ve sizeof(selamlama) verin. Eğer değer kapsamda değilse, sayaç penceresi - 'greeting' adı bağlanamıyor hatasını gösterir.
Zaman Yolculuğu menüsünde, başlangıca gitmek için zaman yolculuğunu kullanın veya izleme başlangıcına gitmek için
!tt 0komutunu kullanın.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=00000000Giriş menüsünde Git'i seçin veya komutu kullanarak
gkesme noktasına isabet edene kadar kodda ilerleyin.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,espAna menüde Adım Dışarı Çık'ı seçin veya
g-ukomutuyla bir adım geri dönün.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)Görünüşe göre kök nedeni bulduk. Bildirdiğimiz selamlama dizisi 50 karakter uzunluğundayken GetCppConGreeting'e geçirdiğimiz boyut(selamlama) 0x64, 100.
Boyut sorununa daha fazla baktığımızda, iletinin 75 karakter uzunluğunda olduğunu ve dize karakterinin sonu dahil edilirken 76 olduğunu da fark ediyoruz.
HELLO FROM THE WINDBG TEAM. GOOD LUCK IN ALL OF YOUR TIME TRAVEL DEBUGGING!Kodu düzeltmenin bir yolu, karakter dizisinin boyutunu 100'e genişletmektir.
std::array <wchar_t, 100> greeting{};Ayrıca bu kod satırında sizeof(greeting) boyutunu da size(greeting) olarak değiştirmemiz gerekir.
GetCppConGreeting(greeting.data(), size(greeting));Bu düzeltmeleri doğrulamak için kodu yeniden derleyip hatasız çalıştığını onaylayabiliriz.
Kaynak pencereyi kullanarak kesme noktası ayarlama
Bu araştırmayı gerçekleştirmenin alternatif bir yolu, herhangi bir kod satırına tıklayarak kesme noktası ayarlamaktır. Örneğin, kaynak pencerede std:array tanım satırının sağ tarafına tıklanması burada bir kesme noktası ayarlar.
Zaman Yolculuğu menüsünde, izlemenin başlangıcına gitmek için Başlangıca git komutunu kullanın.
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=00000000Giriş Şeridinde, kesme noktasına isabet edene kadar geri gitmek için Git'e tıklayın.
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
Selamlama değişkeni için erişim kesme noktasını ayarla
Bu araştırmayı gerçekleştirmenin bir diğer alternatif yolu da şüpheli değişkenler üzerinde bir kesme noktası ayarlamak ve hangi kodun bunları değiştirdiği incelemektir. Örneğin, GetCppConGreeting yöntemindeki selamlama değişkeni üzerinde bir kesme noktası ayarlamak için bu yordamı kullanın.
İzlenecek kılavuzun bu bölümü, önceki bölümdeki kesme noktasında yer almaya devam ettiğinizi varsayar.
Görünüm'den ve ardından YerelLer'den. Yerel penceresinde Selamlama geçerli bağlamda kullanılabilir, bu yüzden bellek yerini saptayabileceğiz.
Selamlama dizisini incelemek için dx komutunu kullanın.
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]Bu izde, greeting bellekte ddf800 konumunda bulunur.
Var olan kesme noktasına sağ tıklayıp Kaldır'ı seçerek var olan kesme noktalarını temizlemek için kesme noktaları penceresini kullanın.
Yazma erişimi için izlemek istediğimiz bellek adresini kullanarak ba komutuyla kesme noktasını ayarlayın.
ba w4 ddf800Zaman Yolculuğu menüsünde, izlemenin başlangıcına gitmek için Zaman yolculuğu komutunu başlatmak için kullanın.
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=00000000Giriş menüsünde, selamlama dizisinin ilk bellek erişimi noktasına gitmek için Git'i seçin.
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=ccccccccAlternatif olarak, izlemenin sonuna gidip dizi bellek konumunun yazıldığı son noktayı bulmak için kodda tersten çalışabilirdik.
Bellek erişimini görüntülemek için TTD.Memory nesnelerini kullanın
İzleme belleğindeki hangi noktalara erişildiğini belirlemenin başka bir yolu da TTD'yi kullanmaktır. Bellek nesneleri ve dx komutu.
Selamlama dizisini incelemek için dx komutunu kullanın.
0:000> dx &greeting &greeting : 0xddf800 [Type: std::array<wchar_t,50> *] [+0x000] _Elems : "꽘棶檙瞝???" [Type: wchar_t [50]]Bu izde selamlama, ddf800 konumunda bellekte bulunmaktadır.
Okuma yazma erişimiyle bu adresten başlayarak bellekteki dört bayta bakmak için dx komutunu kullanın.
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] ...Bellek erişiminin oluşumu hakkında daha fazla bilgi görüntülemek için oluşumlardan herhangi birine tıklayın.
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İzlemeyi belirli bir zaman noktasına konumlandırmak için [Time Travel] öğesine, ardından TimeStart'a tıklayın.
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İzlemedeki okuma/yazma bellek erişiminin son oluşumuyla ilgileniyorsak listedeki son öğeye tıklayabilir veya dx komutunun sonuna .Last() işlevini ekleyebiliriz.
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.859Daha sonra izlemedeki o konuma gitmek için [Zaman Yolculuğu] öğesine tıklayabilir ve bu laboratuvarın önceki bölümlerinde açıklanan teknikleri kullanarak bu noktadaki kod yürütmeye daha fazla göz atabiliriz.
TTD.Memory nesneleri hakkında daha fazla bilgi için TTD.Memory Object bölümüne bakın.
Özet
Bu çok küçük örnekte, sorun birkaç kod satırına bakılarak belirlenebilirdi, ancak daha büyük programlarda burada sunulan teknikler bir sorunu bulmak için gereken süreyi azaltmak için kullanılabilir.
İzleme kaydedildikten sonra izleme ve yeniden oluşturma adımları paylaşılabilir ve sorun herhangi bir bilgisayarda yeniden üretilebilir.
Ayrıca Bkz.
Zaman Yolculuğu Hata Giderme - Genel Bakış
Zaman Yolculuğu Hata Ayıklama - Kayıt