Aracılığıyla paylaş


Zaman Yolculuğu Hata Ayıklama - Örnek Uygulama Kılavuzu

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

  1. Başarısız programın zaman yolculuğu izini yakalayın.
  2. 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.
  3. İzlemedeki özel durum olayının konumuna gitmek için !tt (zaman yolculuğu) komutunu kullanın.
  4. İzden o noktaya kadar adım adım geriye doğru izleyin ve söz konusu hatalı kod kapsamına girene kadar devam edin.
  5. 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.
  6. Değişkenin bellek adresini yanlış değerle belirleyin.
  7. ba ( Erişimde Kes ) komutunu kullanarak şüpheli değişkenin adresinde bir bellek erişimi (ba) kesme noktası ayarlayın.
  8. Şüpheli değişkenin bellek erişiminin son noktasına geri dönmek için g- kullanın.
  9. 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.
  10. İ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.
  11. 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 1'de Visual Studio kullanarak örnek kodu oluşturacaksınız.

Visual Studio'da örnek uygulama oluşturma

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

  2. Güvenlik Geliştirme Yaşam Döngüsü (SDL) kontrol işaretlerini kaldırın.

    Visual Studio'da Win32 Uygulama Sihirbazı ayarları.

  3. Son'a tıklayın.

  4. 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;
    }
    
  5. 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.

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

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

  8. Kod kusuruyla örnek uygulamayı çalıştırma

    Örnek uygulamayı çalıştırmak için exe dosyasına çift tıklayın.

    DisplayGreeting.exe dosyasını çalıştıran konsolun ekran görüntüsü.

    Bu iletişim kutusu görüntülenirse Programı kapat'ı seçin

    'DisplayGreeting.exe çalışmayı durdurdu' ifadesini gösteren iletişim kutusunun ekran görüntüsü.

    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

  1. Zaman yolculuğu izlemelerini kaydedebilmek için WinDbg'yi Yönetici olarak çalıştırın.

  2. WinDbg'de Dosya>Hata ayıklamayı başlat>Gelişmiş yürütülebilir dosyayı başlat seçin.

  3. 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 Dosyayı Başlat (Gelişmiş) ekranında 'Zaman Yolculuğu Hata Ayıklama ile Kaydet' onay kutusunu içeren WinDbg'nin ekran görüntüsü.

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

  5. Kaydı başlatmak için Yapılandır ve Kaydet'e tıklayın.

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

    Yolu c: temp olarak ayarlanmış Kaydı Yapılandır iletişim kutusunu görüntüleyen WinDbg'nin ekran görüntüsü.

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

  8. "DisplayGreeting çalışmayı durdurdu" iletişim kutusunu kapatmak için Programı Kapat'a tıklayın.

    DisplayGreeting uygulamasının çalışmayı durdurduğunu gösteren iletişim kutusu.

  9. Program kilitlendiğinde, izleme dosyası kapatılacak ve diske yazılacaktır.

    WinDbg çıktısının, indekslenmiş 1/1 ana kareleri gösteren ekran görüntüsü.

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

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

  1. Yerel simge konumunuzu sembol yoluna ekleyin ve aşağıdaki komutları yazarak simgeleri yeniden yükleyin.

    .sympath+ C:\MyProjects\DisplayGreeting\Debug
    .reload
    
  2. Aşağıdaki komutu yazarak yerel kod konumunuzu kaynak yola ekleyin.

    .srcpath+ C:\MyProjects\DisplayGreeting\DisplayGreeting
    
  3. Yığı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.

  4. WinDbg şeridinde Kaynak ve Açık Kaynak Dosyası'nı seçin. DisplayGreeting.cpp dosyasını bulun ve açın.

Özel durumu inceleme

  1. İ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=00000000
    
  2. Kayı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.

  3. 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
    
  4. Ö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.

  5. İ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=00520055
    

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

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

  2. İ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=00effe44
    

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

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

  4. İlişkili ASCII karakterlerini görüntülemek için Bellek şeridinden Metin'i ve ardından ASCII'yi seçin.

    WinDbg Preview'in bellek ASCII çıktısını ve Kaynak Kodu penceresini gösteren ekran görüntüsü.

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

  1. İ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 00effe44
    
  2. Amaçlandığı gibi ayarlandıklarını onaylamak için Görünüm'ü ve ardından Kesme Noktaları'na tıklayın.

    Tek bir kesme noktasını gösteren WinDbg Kesme Noktaları penceresinin ekran görüntüsü.

  3. 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=cccccccc
    
  4. Gö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.

    Yerel Ayarlar penceresini görüntüleyen WinDbg'nin ekran görüntüsü.

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

    WinDbg'de Yığın penceresini gösteren ekran görüntüsü.

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

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

  2. 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)]
    
  3. 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 b61720
    
  4. Kesme noktaları penceresinde Donanım Okuma kesme noktasının etkin olduğunu onaylayın.

    Tek bir donanım okuma kesme noktasını gösteren WinDbg Kesme Noktaları penceresinin ekran görüntüsü.

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

    Yerel Ayarları İzle penceresini görüntüleyen WinDbg'nin ekran görüntüsü.

  6. 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 0 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=00000000
    
  7. Giriş menüsünde Git'i seçin veya komutu kullanarak g kesme 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,esp
    
  8. Ana menüde Adım Dışarı Çık'ı seçin veya g-u komutuyla 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)
    
  9. 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.

    WinDbg'nin DisplayGreeting kodunu ve 0x64 gösteren Yerelleri İzle penceresini içeren ekran görüntüsü.

    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!
    
  10. 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));
    
  11. Bu düzeltmeleri doğrulamak için kodu yeniden derleyip hatasız çalıştığını onaylayabiliriz.

Kaynak pencereyi kullanarak kesme noktası ayarlama

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

    WinDbg'de std::array üzerinde bir kesme noktası ayarlanmış Kaynak penceresinin ekran görüntüsü.

  2. 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=00000000
    
  3. Giriş Ş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.

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

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

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

  4. Yazma erişimi için izlemek istediğimiz bellek adresini kullanarak ba komutuyla kesme noktasını ayarlayın.

    ba w4 ddf800
    
  5. Zaman 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=00000000
    
  6. Giriş 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=cccccccc
    

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

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

  2. 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]           
        ...         
    
  3. 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
    
  4. İ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
    
  5. İ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.859
    
  6. Daha 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

Zaman Yolculuğu Hata Ayıklama - Bir izi yeniden oynatma

Zaman Yolculuğu Hata Ayıklama - İz dosyalarıyla çalışma