Win32 Debugger Yapıyoruz – 1

  Hata ayıklama konusunda şimdiye kadar ki paylaşımlarımda sizlerle birlikte nasıl minidump alabileceğimizi ve ADPlus uygulamasını nasıl kullanabileceğimizi incelemiş, size birinci ve ikinci şans hatalardan bahsetmiştim. Yazılarımın devamında artık daha zevkli, daha faydalı olacağına inandığım konulara değinmeyi planlıyorum. Hem ilerleyen makalelere bir zemim oluşturması, hem de Windows’un hata ayıklama konusunda bize sunduklarını daha yakından görebilmek adına bu makalemde birlikte en basit şekliyle bir debugger uygulamasının nasıl yazılabileceğini anlatacağım.

   Makalemde sizlerle paylaşacağım debugger uygulaması temelde Windows’un bize sunduğu ve detayları MSDN Debugging Functions sayfasından bulunan Win32 Debug API’lerini kullanacaktır. Adım adım ilerlemek adına, birlikte geliştireceğimiz ilk debugger’ımız sadece unmanaged debug olay bildirimlerini takip edecek; fakat üzülmeyin bunları kullanarak bile oldukça güzel uygulamalar geliştirmemiz mümkün.

    Debugger uygulamaları, temelde Windows üzerinden çalışan bir/bir kaç işlemi/uygulamayı izleyerek bu işlemlerde meydana gelen hata, işlem oluşması/sonlanması, iş parçacığı oluşması/sonlanması, dll yüklenmesi/kaldırılması v.b. olay bildirimlerine göre kullanıcıyı bilgilendirerek hata ayıklanmasını sağlayan uygulamalardır. Windows hata ayıklama API’leri debugger geliştiricilerine bir uygulamadaki hataları ayırmak için iki seçenek sunmuştur. Bu seçeneklerden ilkinde debugger çalışan bir işlemi izlemeye başlayabilirken diğerinde ise uygulama debugger tarafından hata ayıklama modunda başlatılabilir. Kullanıcı hata ayıklamak istediği noktaya (örneğin; uygulamanın hemen başlangıcında ya da belirli bir girdi toplandıktan sonra..) göre bu iki yöntemden uygun olanı seçmelidir. Her iki yöntemde de debugger’ımız ve takip ettiğimiz uygulama iki farklı işlem olarak çalışacak; fakat debugger, takip edilen uygulamanın parent’ı olarak ayarlanacaktır. Bu sayede debugger’ımız takip ettiği uygulamada oluşan olaylardan haberdar olabilirken olası hatalarından da etkilenmeyecektir. Bu konuda düşülmesi gereken önemli bir not; bir işlem aynı anda sadece tek bir debugger uygulamasınca takip edilebildiğidir. Bunun nedeni, sizin de tahmin edebileceğiniz gibi, bir işleme aynı anda tek bir parent atanabiliyor olmasıdır. Debugger açısından bakıldığında ise; bir uygulamanın aynı anda pek çok alt işlemi olabilmesi nedeniyle herhangi bir sıkıntı bulunmayıp, debugger istediği kadar uygulamaya bağlanarak takip edebilmektedir.

    Eğer geliştirdiğimiz debugger ile çalışan bir işlemi takip etmek istersek, kernel32.dll içerisinde yer alan DebugActiveProcess Win32 debug API fonksiyonunu kullanarak takip edilecek işleme bağlanmalıyız. Kullanımı hakkındaki detaylı bilgiyi MSDN sitesinde bulabileceğiniz DebugActiveProcess fonksiyonunu aşağıdaki basit tanımlama ardından C# uygulamanızda aynı bir normal fonksiyon gibi kullanmanız mümkün;

[DllImport("kernel32")]
[return: MarshalAs(UnmanagedType.Bool)]
static extern bool DebugActiveProcess(uint dwProcessId);

    Oldukça basit bir arayüze sahip olan bu fonksiyon, parametre olarak sadece takip edilecek olan işlemin id’sini beklemektedir. Fonksiyonun çağırılması sonucunda, belirtilen işleme başarılı bir şekilde bağlanılması durumunda true, aksi durumlarda ise false yanıtı alınacaktır.

   Eğer debuggerımızın takip etmek istediğimiz bir uygulamayı en başından itibaren izlemesini istiyorsak, yapmamız gereken Win32 API’leri vasıtasıyla debug yapılacağını bildirerek yeni bir işlem başlatmak olmalıdır. Windows yeni bir işlem başlatmak için bizlere kernel32.dll içerisinde CreateProcess Win32 API fonksiyonunu sunmuştur. DebugActiveProcess fonksiyonunda olduğu gibi aşağıdaki tanımlama ardından bu fonksiyonu da C# uygulamamız içerisinde kullanmamız mümkün olacaktır;

[DllImport("kernel32")]
public static extern bool CreateProcess(string lpApplicationName, 
                                        string lpCommandLine, 
                                        IntPtr lpProcessAttributes, 
                                        IntPtr lpThreadAttributes, 
                                        bool bInheritHandles, 
                                        ProcessCreationFlags dwCreationFlags, 
                                        IntPtr lpEnvironment, 
                                        string lpCurrentDirectory, 
                                        ref STARTUPINFO lpStartupInfo, 
                                        out PROCESS_INFORMATION lpProcessInformation);

   MSDN web sitesinde dokümantasyonunu bulabileceğiniz CreateProcess fonksiyonunda dwCreationFlags parametresi yardımıyla Windows’a başlatılacak olan işlemin debugger tarafından hata ayıklama işlemine tabi olacağını belirtebilirsiniz. Bu amaçla dwCreationFlags parametresinden; sadece bu işlemde hata ayıkla (DEBUG_ONLY_THIS_PROCESS) veya bu işlem ve tüm alt işlemlerinde hata ayıkla (DEBUG_PROCESS) denilmesi mümkündür. Bu fonksiyonun çalıştırılması sonrasında işlemin başarılı olması halinde true; aksi hallerde false değeri dönecektir. Başarılı bir işlem başlatılması sonrasında; başlatılan bu işlem hakkındaki bilgiler lpProcessInformation parametresi ile uygulamaya geri gönderiliyor olacaktır. Aşağıda örnek bir işlem başlatma kodunu ve  kullanılan STARTUPINFO ile PROCESS_INFORMATION struct’larını bulabilirsiniz;

[DllImport("kernel32")]
public static extern bool CreateProcess(string lpApplicationName, 
                                        string lpCommandLine, 
                                        IntPtr lpProcessAttributes, 
                                        IntPtr lpThreadAttributes, 
                                        bool bInheritHandles, 
                                        ProcessCreationFlags dwCreationFlags, 
                                        IntPtr lpEnvironment, 
                                        string lpCurrentDirectory, 
                                        ref STARTUPINFO lpStartupInfo, 
                                        out PROCESS_INFORMATION lpProcessInformation);

public enum ProcessCreationFlags : uint {
    CREATE_BREAKAWAY_FROM_JOB = 0x01000000,
    CREATE_DEFAULT_ERROR_MODE = 0x04000000,
    CREATE_NEW_CONSOLE = 0x00000010,
    CREATE_NEW_PROCESS_GROUP = 0x00000200,
    CREATE_NO_WINDOW = 0x08000000,
    CREATE_PROTECTED_PROCESS = 0x00040000,
    CREATE_PRESERVE_CODE_AUTHZ_LEVEL = 0x02000000,
    CREATE_SEPARATE_WOW_VDM = 0x00000800,
    CREATE_SHARED_WOW_VDM = 0x00001000,
    CREATE_SUSPENDED = 0x00000004,
    CREATE_UNICODE_ENVIRONMENT = 0x00000400,
    DEBUG_ONLY_THIS_PROCESS = 0x00000002,
    DEBUG_PROCESS = 0x00000001,
    DETACHED_PROCESS = 0x00000008,
    EXTENDED_STARTUPINFO_PRESENT = 0x00080000,
    INHERIT_PARENT_AFFINITY = 0x00010000
}

[StructLayout(LayoutKind.Sequential, CharSet = CharSet.Unicode)]
public struct STARTUPINFO {
    public uint cb;
    public string lpReserved;
    public string lpDesktop;
    public string lpTitle;
    public uint dwX;
    public uint dwY;
    public uint dwXSize;
    public uint dwYSize;
    public uint dwXCountChars;
    public uint dwYCountChars;
    public uint dwFillAttribute;
    public uint dwFlags;
    public short wShowWindow;
    public short cbReserved2;
    public IntPtr lpReserved2;
    public IntPtr hStdInput;
    public IntPtr hStdOutput;
    public IntPtr hStdError;
}

[StructLayout(LayoutKind.Sequential)]
public struct PROCESS_INFORMATION {
    public IntPtr hProcess;
    public IntPtr hThread;
    public uint dwProcessId;
    public uint dwThreadId;
}

//...
//--------------------------------------
//  İşlemin Debug moduyla başlatılması
//--------------------------------------
//...

var startupInfo = new STARTUPINFO();
var processInformation = new PROCESS_INFORMATION();

startupInfo.cb = (uint)Marshal.SizeOf(startupInfo);

CreateProcess("C:\hataliUygulama.exe", 
              null, 
              IntPtr.Zero, 
              IntPtr.Zero, 
              false, 
              ProcessCreationFlags.CREATE_NEW_CONSOLE | ProcessCreationFlags.DEBUG_ONLY_THIS_PROCESS, 
              IntPtr.Zero, 
              null, 
              ref startupInfo, 
              out processInformation);

   Yukarıdaki kodun işletilmesi sonrasında processInformation.hProcess  değeri bize başlatılan işlemin handle’ını verecektir. İsterseniz bu handle’ı kullanarak kernel32.dll’i içerisindeki GetProcessId fonksiyonu yardımıyla da process’in id’sine erişebilir ve bu id’yi kullanarak System.Diagnostics.Process içerisindeki static GetProcessById fonksiyonu yardımıyla da tüm işlem bilgilerine ulaşabilirsiniz. Bu işleme dair örnek bir kullanımı aşağıda bulabilirsiniz;

[DllImport("kernel32")]
public static extern int GetProcessId(IntPtr hProcess);

//--------------------------------------

var processId = GetProcessId(processInformation.hProcess);

islem = System.Diagnostics.Process.GetProcessById(processId);

   Tüm bu işlemler ardından herhangi bir sıkıntı yaşanmaması adına processInformation.hProcess ve processInformation.hThread  handle’larını aşağıdaki şekilde kapatmanız önemlidir;

[DllImport("kernel32")]
public static extern IntPtr CloseHandle(IntPtr handle);

//--------------------------------------

//...

CloseHandle(processInformation.hProcess);
CloseHandle(processInformation.hThread);

   Yukarıdaki bilgiler ışığında, şimdiye kadar geldiğimiz noktada mevcutta çalışan bir işleme hata ayıklama amaçlı olarak bağlanabilir ya da yeni bir işlem başlatabiliriz. Hangi yöntem seçilmiş olursa olsun, debugger’ımızın bundan sonraki kodları ortak olacaktır.

   Hata ayıklaması yapılacak olan işlemi başlattıktan/bağlandıktan sonra debuggerımız artık olay bildirimlerini alacak ve yönetecek olduğu debug döngüsüne girmelidir. Debug döngüsü, uygulamanın kendisinin ya da debugger’ın işlemi bir şekilde sonlandırmasına kadar debugger’ın işlem bildirimlerini dinlediği ve gelen bu bildirimler doğrultusunda da (kimi zaman) kullanıcıyla etkileşerek işlemler geçekleştirdiği döngüdür. Debugger, temelde bu döngünün başında işlem olaylarını dinlemeli, devamında kendi iş mantıklarını işletmeli ve son olarak da bir sonraki olay bildirimini dinlemek üzere bağlandığı işlemin işleyişine devam etmesini sağlamalıdır.

Debug Döngüsü 

    Bu noktada debug döngüsünün en önemli bileşenleri olan olay dinleme ve işleyişe devam etmek için kernel32.dll’i içerisinde bulunan WaitForDebugEvent ve ContinueDebugEvent fonksiyonları kullanılmalıdır. WaitForDebugEvent fonksiyon çağrısıyla bir olay bildirilmesi sırasında işletim sistemi debugger tarafından bağlanılmış olan işlem ve tüm alt iş parçacıklarını tamamen durdurarak debugger’ın iş mantıklarını çalıştırmasına olanak sağlamıştır. Bu şekilde durdurulmuş olan bir işlemin işleyişine devam etmesi için debugger tarafından ContinueDebugEvent fonksiyon çağrısı yapılarak işleyişe hangi durum bilgisi ile devam edileceği bildirilmelidir. Bir hata olay bildirimini ele alacak olursak pek çok hata ilk bildiriminde göz ardı edilerek uygulama tarafından gerekli kontroller yapılabilmekte (Birinci ve ikinci şans hatalar hakkında bu makalemde detaylı bilgi bulabilirsiniz), bu durumda verilmesi gereken durum bilgisi DBG_EXCEPTION_NOT_HANDLED olmalıdır. Aşağıda, her iki Win32 API fonksiyonunu da C# uygulamamızda kullanabilmemiz için gerekli olan tanımlamaları bulabilirsiniz;

[DllImport("kernel32")]
[return: MarshalAs(UnmanagedType.Bool)]
public static extern bool WaitForDebugEvent(ref DebugEvent pDebugEvent, int dwMilliseconds);

[DllImport("kernel32")]
[return: MarshalAs(UnmanagedType.Bool)]
public static extern bool ContinueDebugEvent(uint dwProcessId, uint dwThreadId, ContinueStatus dwContinueStatus);

    WaitForDebugEvent fonksiyonu dwMilliseconds parametresi ile belirtilen süre kadar bekleyerek olası Debug olay bildirimlerini yakalayacak ve bildirime ait verileri pDebugEvent parametresi ile uygulamamıza iletecektir. Fonksiyonun sonsuz bir bekleme durumunda kalması isteniyorsa, dwMilliseconds parametresine 0xffff değeri verilebilir. Belirtilen süre sonunda, henüz bir bildirim olmaması durumunda fonksiyon false değerini dönerken, bildirim gelmesi durumunda true değeri alınacaktır. Debugger’ımız gelen bu değere göre kendi iş mantığında yapılması gerekene karar verecektir.

   WaitForDebugEvent ile ilgili bilinmesi gereken önemli bir nokta da bu fonksiyonun belirtilen zaman aşımına ulaşıncaya ya da debug olay bildirimi alınıncaya kadar bir değer dönmeyerek içinde bulunduğu iş parçacığını kilitliyor olmasıdır. Bu durumda, debugger’ınız bir forms uygulaması ise debug döngüsünün arayüz iş parçacığından ayrı, ikinci bir iş parçacığında çalışıyor olması önemlidir. Aksi takdirde debuggerı uygulamamız işletim sistemi bildirimlerini alıp işleyemeyeceğinden dolayı arayüzünde donmalar/kilitlenmeler görülecektir. Bu bilgilendirme ardından debug döngüsünü ayrı bir iş parçacığında çalıştıracağınızı düşünerek yine belirtmem gereken önemli bir diğer noktada hata ayıklanacak olan  işleme bağlanma kodu ile debug döngüsü kodunun aynı iş parçacığı içerisinde çalışması gerektiğidir.

   Hata ayıklama işlemi sırasında debugger’ımız hata bilgisi, iş parçacığı oluşturulması/kaldırılması, işlem oluşturulması/kaldırılması, debug mesajı gönderilmesi, dll yüklenmesi/kaldırılması, işlemin ölü duruma gelmesi  gibi pek çok değişik olay bildirimini alacaktır. MSDN üzerinden dokümantasyonunu bulabileceğiniz DebugEvent struct’ı aşağıdaki yapıya sahiptir;

typedef struct _DEBUG_EVENT {
  DWORD dwDebugEventCode;
  DWORD dwProcessId;
  DWORD dwThreadId;
  union {
    EXCEPTION_DEBUG_INFO      Exception;
    CREATE_THREAD_DEBUG_INFO  CreateThread;
    CREATE_PROCESS_DEBUG_INFO CreateProcessInfo;
    EXIT_THREAD_DEBUG_INFO    ExitThread;
    EXIT_PROCESS_DEBUG_INFO   ExitProcess;
    LOAD_DLL_DEBUG_INFO       LoadDll;
    UNLOAD_DLL_DEBUG_INFO     UnloadDll;
    OUTPUT_DEBUG_STRING_INFO  DebugString;
    RIP_INFO                  RipInfo;
  } u;
} DEBUG_EVENT, *LPDEBUG_EVENT;

   DebugEvent’in ilk üç alanı sabit iken, makalemin devamında detaylarına değineceğim union içerisinde yer alan struct’lar ilgili olay bildirimine has bilgiler içermekte ve sadece bu bildirimlerde gelmektedirler. Yukarıdaki yapının C# içerisine aktarılmış hali ise aşağıda bulunabilir;

[StructLayout(LayoutKind.Explicit)]
public struct DebugEvent {
    [FieldOffset(0)]
    public DebugEventHeader header;

    [FieldOffset(12)]
    public DebugEventUnion union;
}

[StructLayout(LayoutKind.Sequential)]
public struct DebugEventHeader {
    public DebugEventCodes dwDebugEventCode;
    public UInt32 dwProcessId;
    public UInt32 dwThreadId;
};

[StructLayout(LayoutKind.Explicit)]
public struct DebugEventUnion {
    [FieldOffset(0)]
    public CREATE_PROCESS_DEBUG_INFO CreateProcess;

    [FieldOffset(0)]
    public EXCEPTION_DEBUG_INFO Exception;

    [FieldOffset(0)]
    public CREATE_THREAD_DEBUG_INFO CreateThread;

    [FieldOffset(0)]
    public EXIT_THREAD_DEBUG_INFO ExitThread;

    [FieldOffset(0)]
    public EXIT_PROCESS_DEBUG_INFO ExitProcess;

    [FieldOffset(0)]
    public LOAD_DLL_DEBUG_INFO LoadDll;

    [FieldOffset(0)]
    public UNLOAD_DLL_DEBUG_INFO UnloadDll;

    [FieldOffset(0)]
    public OUTPUT_DEBUG_STRING_INFO OutputDebugString;
}

public enum DebugEventCodes {
    None = 0,
    EXCEPTION_DEBUG_EVENT = 1,
    CREATE_THREAD_DEBUG_EVENT = 2,
    CREATE_PROCESS_DEBUG_EVENT = 3,
    EXIT_THREAD_DEBUG_EVENT = 4,
    EXIT_PROCESS_DEBUG_EVENT = 5,
    LOAD_DLL_DEBUG_EVENT = 6,
    UNLOAD_DLL_DEBUG_EVENT = 7,
    OUTPUT_DEBUG_STRING_EVENT = 8,
    RIP_EVENT = 9,
}

    Yukarıdaki yapıda DebugEvent struct’ı 32bit ve 64bitlik sistemlerde farklı offset’lerden başlamaktadır. Bu sebeple debugger uygulamamızın hem x86 hem de x64 sistemlerde çalışmasını istiyorsak bu ufak farklılığı göz önüne alarak aşağıdaki şekilde aynı içerik, fakat farklı offset adresine olan iki sınıf oluşturmalıyız;

[StructLayout(LayoutKind.Explicit)]
public struct DebugEvent32 {
    [FieldOffset(0)]
    public DebugEventHeader header;

    [FieldOffset(12)]
    public DebugEventUnion union;
}

[StructLayout(LayoutKind.Explicit)]
public struct DebugEvent64 {
    [FieldOffset(0)]
    public DebugEventHeader header;

    [FieldOffset(16)]
    public DebugEventUnion union;
}

Debugger’ımız aldığı bildirimin türünü dwDebugEventCode parametresi yardımıyla algılayabilir ve yine bu bilgiden yararlanarak kendi iş mantığını oluşturabilir. Aşağıda, en basit haliyle bir debug döngüsü kod parçacığını bulabilirsiniz;

while (izle) {
    var debugEvent = new DebugEvent();
    
    var olayBildirildi = WaitForDebugEvent(ref debugEvent, SONSUZ_BEKLEME);
    if (!olayBildirildi) { continue; }

    var continueStatus = ContinueStatus.DBG_CONTINUE;

    switch (debugEvent.header.dwDebugEventCode) {
        case DebugEventCodes.EXCEPTION_DEBUG_EVENT:
            // Hata bildirim iş mantığı kodu
            continueStatus = HataOlustuIsle(debugEvent);
            break;
        case DebugEventCodes.CREATE_THREAD_DEBUG_EVENT:
            // İş parçacığı oluştu iş mantığı kodu
            continueStatus = IslemParcacigiOlustuIsle(debugEvent);
            break;
        case DebugEventCodes.CREATE_PROCESS_DEBUG_EVENT:
            // işlem oluştu iş mantığı kodu
            continueStatus = IslemOlustuIsle(debugEvent);
            break;
        case DebugEventCodes.EXIT_THREAD_DEBUG_EVENT:
            // iş mantığı kodu
            continueStatus = IsParcacigiSonlandiIsle(debugEvent);
            break;
        case DebugEventCodes.EXIT_PROCESS_DEBUG_EVENT:
            // işlem sonlandı iş mantığı kodu
            continueStatus = IslemSonlandiIsle(debugEvent);
            break;
        case DebugEventCodes.LOAD_DLL_DEBUG_EVENT:
            // dll yüklendi iş mantığı kodu
            continueStatus = DllYuklendiIsle(debugEvent);
            break;
        case DebugEventCodes.UNLOAD_DLL_DEBUG_EVENT:
            // dll kaldırıldı iş mantığı kodu
            continueStatus = DllKaldirildiIsle(debugEvent);
            break;
        case DebugEventCodes.OUTPUT_DEBUG_STRING_EVENT:
            // debug çıktısı alındı iş mantığı kodu
            continueStatus = DebugMesajiIsle(debugEvent);
            break;
        case DebugEventCodes.RIP_EVENT:
            // uygulama beklenmedik şekilde
            // sonlandı iş mantığı kodu
            continueStatus = RIPIsle(debugEvent);
            break;
    }

    ContinueDebugEvent(debugEvent.header.dwProcessId, debugEvent.header.dwThreadId, continueStatus);
}

   Aşağıda, DebugEventCodes enum’u içerisinde yer alan ve bir debug olay bildirimi ile gelebilecek kodları ve açıklamalarını aşağıda bulabilirsiniz;

Enum Değer Açıklama
EXCEPTION_DEBUG_EVENT 1 Takip edilen işlem içerisinde oluşan bir hatayı bildirmektedir. Hata bilgisi EXCEPTION_DEBUG_INFO struct’ı ile iletilmektedir.
CREATE_THREAD_DEBUG_EVENT 2 Takip edilen işlemde yeni bir iş parçacığının oluştuğunu bildirmektedir. Oluşturulan iş parçacığına ait bilgiler ise CREATE_THREAD_DEBUG_INFO struct’ı ile iletilmektedir.
CREATE_PROCESS_DEBUG_EVENT 3 Takip edilen işlemde yeni bir işlem oluştuğunu bildirmektedir. Oluşturulan işleme ait bilgiler ise CREATE_PROCESS_DEBUG_INFO struct’ı ile iletilmektedir.
EXIT_THREAD_DEBUG_EVENT 4 Takip edilen işlemde bir iş parçacığının sonlandığı bildirilmektedir. Sonlanan iş parçacığına ait bilgiler ise EXIT_THREAD_DEBUG_INFO struct’ı ile iletilmektedir.
EXIT_PROCESS_DEBUG_EVENT 5 Takip edilen işlemde bir işlemin sonlandığı bildirilmektedir. Sonlanan işleme ait bilgiler ise EXIT_PROCESS_DEBUG_INFO struct’ı ile iletilmektedir.
LOAD_DLL_DEBUG_EVENT 6 Takip edilen işlemin yeni bir dll’i yüklediği bildirilmektedir. Yüklenen dll’e ait bilgiler ise LOAD_DLL_DEBUG_INFO struct’ı ile iletilmektedir.
UNLOAD_DLL_DEBUG_EVENT 7 Takip edilen işlemin mevcut bir dll’i kaldırdığı bildirilmektedir. Kaldırılan dll’e ait bilgiler ise UNLOAD_DLL_DEBUG_INFO struct’ı ile iletilmektedir.
OUTPUT_DEBUG_STRING_EVENT 8 Takip edilen işlem içerisinden bir debug mesajının gönderildiği bildirilmektedir. Gönderilen debug mesajına ait bilgiler ise OUTPUT_DEBUG_STRING_INFO struct’ı ile iletilmektedir.
RIP_EVENT 9 İşlemin takibi sırasında bir sistem hata ayıklama hatası (system debugging error, RIP) oluştuğu bildirilmektedir. Oluşan bu duruma ait bilgiler ise RIP_INFO struct’ı ile iletilmektedir.

    Debugger’ın en önemli parçalarından birisi olan debug döngüsünün mimarisini yukarıdaki adımların ardında tamamlamış oluyoruz. Tek makale ile anlatılması zor olan debugger yazılımı konusunda, devam makalelerinde gelen olay bildirimlerinde yer alan bilgileri kullanarak yüklenen dll’i adının nasıl bulunabildiğini, debug mesajı nasıl gösterebileceğimizi ya da hata mesajlarının neler olduğunu anlatıyor olacağım.

    Yukarıdaki süreçlerin kodlanması ardından hata ayıklamak için bir işleme bağlanıldığında işletim sistemi otomatik olarak bir CREATE_PROCESS_DEBUG_EVENT olay bildirimi yapacaktır. Yapılan bu olay bildirimi içerisinde takip edilen uygulama hakkında bilgiler bulunmaktadır.

    Önceki paragrafta bahsettiğime benzer olarak işletim sistemince bir de hata olay bildirimi yapılacak ve kodumuzun 10. satırına düşmesine neden olacaktır. Bunun nedeni, işletim sistemi açısından break point’lerinde bir hata olarak yorumlanması ve debuggerın bir işleme bağlanması durumunda işlemin işleyişinin işletim sistemince değiştirilerek bir break point eklenmesidir. Bu sebeple bir debugger hata ayıklama amacıyla bağlandığı işlemden gelen ilk hata mesajını (STATUS_BREAKPOINT, 0x80000003) es geçmelidir.

Fatih Boy

Ankara'da yaşayan Fatih, bir kamu kurumunda danışman olarak çalışmaktadır. ALM süreçleri, kurumsal veri yolu sistemleri, kurumsal altyapı ve yazılım geliştirme konularında destek vermektedir. Boş zamanlarında açık kaynak kodlu projeler geliştirmeyi ve bilgisini yazdığı makalelerle paylaşmayı seven Fatih, aynı zamanda Visual C# ve Visual Studio teknolojileri konusundan Microsoft tarafından altı yıl üst üste MVP (En Değerli Profesyonel) ödülüne layık görülmüştür. İş hayatı boyunca masaüstü uygulamaları, web teknolojileri, akıllı istemciler gibi konularda Asp.Net, Php, C#, Java programlama dilleri ve MySql, MsSql ve Oracle gibi veritabanı yönetim yazılımları ile çalışmıştır. İngilizce ve Türkçe olarak yayınlanan makalelerini gerek İngilizce bloğunda, gerekse de Türkçe bloğunda bulabileceğiniz gibi web sitesinden de açık kaynak kodlu geliştirdiği yazılımlarına ulaşabilirsiniz. vCard - Twitter - Facebook - Google+

1 Yorum

  1. Pingback: Tweets that mention Win32 Debugger Yapıyoruz – 1 | Fatih'in Notları -- Topsy.com

Bir Cevap Yazın

E-posta hesabınız yayımlanmayacak. Gerekli alanlar * ile işaretlenmişlerdir