Dostlar selam, bugün farklı bir yazı ile birlikteyiz.
Windows işletim sistemi için (ve muhtemelen diğer işletim sistemleri) yazılım geliştiren bir çoğumuz, yazılımları konuşlandırdıktan sonra çıkan ve yazılımların göçmesi ile sonuçlanan hatalar ile karşılaşıyoruzdur. Genelde de bu yazılımların bir çoğu da kendi makinelerimizde çalışıyor oluyorlar 🙂 Bunları eğer tekrarlayabiliyorsanız ne ala. Ama eğer oluşturamıyorsanız büyük sıkıntı. Bir de tabi mavi ekranlar var aşağıdaki gibi 🙂 Peki bu durumda ne yapacağız? Elbette, çeşitli kayıt çıktıları veya uygulamanın davranışından bazı çıkarımlarda bulunabilirsiniz. Peki ya bulunamazsanız ne olacak?
İşte bu yazımızda, bu duruma düşdüğünüz durumda, izleyebileceğiniz yöntemlerden birine değineceğim (ki ben de bunu böyle bir durum düştükten sonra öğrenerek uyguladım ve problemin kaynağını çözmemde yardımcı oldu). Bu yöntem bellek dökümlerinin incelenmesine dayanıyor. Elbette, bunları belirli araçları kullanarak ve yaklaşımları izleyerek yapıyor olacağız.
Temelde, bellek döküm dosyaları, bellekte çalışan ve yüklü olan uygulamalara, kullanılan verilere ve diğer ilintili hususlara ilişkin verileri içeren dosyadır. Bir uygulama çöktüğü zaman, uygulama tamamen kapatılmadan önce, “registery” içerisinde döküm alınmasına ilişkin bir ayar var mı diye kontrol edilir ve eğer var ise ilgili döküm dosyası oluşturulur.
Öncelikle şunu ifade etmekte fayda var ki, bu yöntem windows üzerinde çalışacak olan uygulamalar için geçerli, açıkçası benzer araçlar diğer işletim sistemleri nasıl kullanılıyor bilmiyorum ama olduğuna eminim.
Şimdi gelelim bu yaklaşımı nasıl uygulayacağımıza. Burada, önce sizlere izlemeniz gereken adımları aktarmaya çalışacağım daha sonra bu adımlarda yaptığımız eylemlerin, alanların ne anlama geldiklerini aktarmaya çalışacağım. Son olarak da, elde ettiğimiz kayıtları nasıl anlamlandıracağımıza bakıyor olacağız.
Gerekli Ayarlar
Bu şekilde, hata kayıt dökümlerine almaya yönelik ayar ne yazık ki windows ile ayarlı gelmiyor ve bu kabiliyeti kullanabilmek için registery’de bir takım ayarlar yapmamız gerekiyor ki, bu sebeple bir yedek almanızda fayda var. Şimdi adım adım ne yapacağımıza bakalım:
- “Registry Editor” ‘ nü açalım:
- Win + R kısayolunu kullanarak Çalıştır kutucuğunu açalım
- Buraya “regedit” yazarak ilgili editörü açalım
- Bundan önce eğer bir Pop-Up penceresi görünür ise evet düğmesine basmanız gerekiyor.
- Açılan editör içerisinde “HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows\Windows Error Reporting” dizinine gidiyoruz
- Bu kısmı değiştireceğimizden, yedek almak için aşağıdaki adımları izleyelim:
- “Windows Error Reporting” ‘i seçip sağ tıklayalım,
- Gelen menüden “Ver” komutunu seçerek ilgili alanları .reg uzantılı bir dosyaya kaydedelim,
- Kuvvetle muhtemel, eğer daha önce bir uygulama veya sizin tarafınızdan oluşturulmadı ise “”Windows Error Reporting” altında “LocalDumps” anahtarı sizlerde bulunmuyor olabilir. Eğer bu anahtar yok ise bunu oluşturacağız:
- “Windows Error Reporting” seçip sağ tıklıyoruz,
- Gelen menüden “Yeni” ve sonrasında ise “Anahtar”‘ı seçiyoruz,
- Ve bu anahtarın ismini “LocalDumps” olarak belirliyoruz,
- Yeni oluşturduğumuz “LocalDumps” anahtarı içerisinde gerekli kayıt değerlerini oluşturacağız. Bunun içinde aşağıda sizlere aktardığım alanları kullanıyor olacağız:
-
Kullanıcı Çökme Dökümü Alma Ayarları Alt Alan İsmi Açıklama Alan Tipi Varsayılan Değer DumpFolder Döküm dosyalarının depolanacağı dizin. Eğer varsayılan dizini kullanmayacaksanız, bu dizinin gerekli yazma haklarına sahip olduğundan emin olunuz. Çökmelere ilişkin dökümler bu dizine saklanıyor olacaklar. Ör. D:\CrashDumps REG_EXPAND_SZ %LOCALAPPDATA%\CrashDumps DumpCount Döküm dizini içerisinde tutulacak maksimum dosya adeti. İlgili adet dolunca en eski kayıt/dosya silinir. REG_DWORD 10 DumpType Döküm tipini belirler: - 0: Özelleşmiş döküm (sonraki satır 😉
- 1: Mini döküm
- 2: Tam döküm
* Bu tiplere ilişkin aşağıya ek bilgiler ekliyorum.
REG_DWORD 1 CustomDumpFlags Burada ilgili döküme ilişkin özelleşmiş ayarları kombine ederek kullanabilirsiniz. Buradaki değerler bir önceli alanın 0 olması durumunda sadece kullanılıyor. REG_DWORD MiniDumpWithDataSegs | MiniDumpWithUnloadedModules | MiniDumpWithProcessThreadData.
- Yukarıdaki tabloda döküm tiplerinin davranışları şu şekilde:
-
- Yukarıdaki ayarları eğer doğru yaptıysanız, bundan sonra windows üzerinde gerçekleşen herhangi bir (ki buna bütün uygulamalar dahil, bunu nasıl sınırlayabileceğinize de bakacağız) göçmede, bu dizin altında ilgili döküm kayıtları oluşturulacaktır.
- Peki, bilgisayarınızda çalışan bütün uygulamalar değil de, sadece belirli bir uygulamaya ilişkin döküm almak isterseniz ne yapacaksınız? Bunun için, döküm almak istediğini uygulamanın ismini içeren bir anahtarı “LocalDumps” dizini altına açıyorsunuz. Ör. OrnekUygulama.exe için:
- HKEY_LOCAL_MACHINE\Software\Microsoft\Windows\Windows Error Reporting\LocalDumps\OrnekUygulama.exe anahtarı ekleyip içerisine de yukarıda belirttiğimiz kayıt alanları istediğiniz şekilde düzenleyerek ekleyebilirsiniz.
Gerekli Araçlar
Elde ettiğiniz döküm dosyalarını anlamlandırabilmek için bir takım araçlar kullanmanız gerekmekte ve bunların en önemlisi de WinDbg aracıdır. Bu araç ile birlikte, kernel ve user mode uygulamalarınızı/kodlarınıza ilişkin hata ayıklama, dökümleri inceleme ve işlemci register’larına göz atabiliriniz. Microsoft’un buna ilişkin çok güzel kılavuzları da mevcut. Ör. https://docs.microsoft.com/tr-tr/windows-hardware/drivers/debugger/getting-started-with-windows-debugging
Öncelikle bu araçla inceleyebileceğimiz bir döküm dosyası oluşturalım nasıl mı? En kolayınızdaki bir C ya da C++ derleyecisi ile aşağıdaki kod parçasından oluşan bir uygulama oluşturun ve çalıştırın.
1 2 3 4 5 6 7 8 |
#include <iostream> int main() { std::cout << "Gocmeye hazir miyiz?\n"; int* deneme = 0; *deneme = 0; } |
Eğer, bir önceki başlık altındaki ayarlarımızı düzgün yaptıysak. D:\CrashDumps dizini altında (siz hangi dizini ayarladıysanız), aşağıdaki dosyanın oluşmuş olduğunu göreceksiniz:
Şimdi, WinDbg aracı ile bu dökümü inceleyelim:
- Öncelikle WinDbg Preview aracını indirerek kurmanız gerekiyor, ilgili bağlantıyı izlediğinizde sizi microsoft store’a yönlendiriyor olacak ve orada ilgili uygulamayı indirebilirsiniz,
-
Daha sonra bu uygulamayı yönetici hakları ile başlatmanız gerekiyor,
- Uygulamayı çalıştırdıktan sonra, Dosya -> Start Debugging -> Open dump file’ı seçmeniz gerekiyor. Daha sonra çıkan pencereden az önce gördüğümüz döküm dosyasını seçiyoruz,
- Dosyayı açtıktan sonra, uygulama ilgili .exe’iy analiz etmek için gerekli dosyaları yüklüyor (durum çubuğundan görebilirsiniz):
- Bu aşamadan sonra 0:000>’ın yanındaki komut alanına “!analyze -v” yazmanız yeterli. Bu komut da, oluşturulan döküm dosyasını analiz edip, ilgili çıktıları “Command” sekmesine basıyor olacak, hemen bakalım:
- Evet, bu analiz sonucunda sekmeye basılan bilgileri aşağıya ekliyorum. Eğer, uygulamanız, benim örneğimde olduğu gibi “Debug” bilgileri ile derlendiyse, ilgili hatanın/göçmenin kod içerisindeki satırına kadar bilgiyi görebilirsiniz. Burada önemli olan satırlar (PROCESS NAME, STACK_TEXT, FAULTING_SOURCE_LINE, FAULTING_SOURCE_LINE_NUMBER, MODULE_NAME ve tabi ki FAILURE_BUCKET_ID):
-
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133******************************************************************************** ** Exception Analysis ** ********************************************************************************KEY_VALUES_STRING: 1Key : AV.DereferenceValue: NullPtrKey : AV.FaultValue: WriteKey : Analysis.CPU.mSecValue: 1234Key : Analysis.DebugAnalysisManagerValue: CreateKey : Analysis.Elapsed.mSecValue: 1243Key : Analysis.Init.CPU.mSecValue: 718Key : Analysis.Init.Elapsed.mSecValue: 209914Key : Analysis.Memory.CommitPeak.MbValue: 70Key : Timeline.Process.Start.DeltaSecValue: 2Key : WER.OS.BranchValue: vb_releaseKey : WER.OS.TimestampValue: 2019-12-06T14:06:00ZKey : WER.OS.VersionValue: 10.0.19041.1NTGLOBALFLAG: 0APPLICATION_VERIFIER_FLAGS: 0CONTEXT: (.ecxr)eax=00000000 ebx=0081a000 ecx=6f194fbb edx=7a475a78 esi=00a61023 edi=00b7fc84eip=00a624b5 esp=00b7fbac ebp=00b7fc84 iopl=0 nv up ei pl nz na pe nccs=0023 ss=002b ds=002b es=002b fs=0053 gs=002b efl=00010206AppToCrash!main+0x45:00a624b5 c70000000000 mov dword ptr [eax],0 ds:002b:00000000=????????Resetting default scopeEXCEPTION_RECORD: (.exr -1)ExceptionAddress: 00a624b5 (AppToCrash!main+0x00000045)ExceptionCode: c0000005 (Access violation)ExceptionFlags: 00000000NumberParameters: 2Parameter[0]: 00000001Parameter[1]: 00000000Attempt to write to address 00000000PROCESS_NAME: AppToCrash.exeWRITE_ADDRESS: 00000000ERROR_CODE: (NTSTATUS) 0xc0000005 - 0x%p adresindeki y nerge 0x%p adresindeki belle e ba vurdu. Bellek u olamaz %s.EXCEPTION_CODE_STR: c0000005EXCEPTION_PARAMETER1: 00000001EXCEPTION_PARAMETER2: 00000000FAULTING_LOCAL_VARIABLE_NAME: denemeSTACK_TEXT:00b7fc84 00a62c63 00000001 00d4c3d8 00d51700 AppToCrash!main+0x4500b7fca4 00a62ab7 6faeb2bb 00a61023 00a61023 AppToCrash!invoke_main+0x3300b7fd00 00a6294d 00b7fd10 00a62ce8 00b7fd20 AppToCrash!__scrt_common_main_seh+0x15700b7fd08 00a62ce8 00b7fd20 76a1fa29 0081a000 AppToCrash!__scrt_common_main+0xd00b7fd10 76a1fa29 0081a000 76a1fa10 00b7fd7c AppToCrash!mainCRTStartup+0x800b7fd20 77057a7e 0081a000 5fa1404f 00000000 kernel32!BaseThreadInitThunk+0x1900b7fd7c 77057a4e ffffffff 77078a24 00000000 ntdll!__RtlUserThreadStart+0x2f00b7fd8c 00000000 00a61023 0081a000 00000000 ntdll!_RtlUserThreadStart+0x1bFAULTING_SOURCE_LINE: C:\Users\fatih\source\repos\AppToCrash\AppToCrash.cppFAULTING_SOURCE_FILE: C:\Users\fatih\source\repos\AppToCrash\AppToCrash.cppFAULTING_SOURCE_LINE_NUMBER: 10FAULTING_SOURCE_CODE:6: int main()7: {8: std::cout << "Gocmeye hazir miyiz?\n";9: int* deneme = 0;> 10: *deneme = 0;11: }12:13: // Run program: Ctrl + F5 or Debug > Start Without Debugging menu14: // Debug program: F5 or Debug > Start Debugging menu15:SYMBOL_NAME: AppToCrash!main+45MODULE_NAME: AppToCrashIMAGE_NAME: AppToCrash.exeSTACK_COMMAND: ~0s ; .ecxr ; kbFAILURE_BUCKET_ID: NULL_POINTER_WRITE_c0000005_AppToCrash.exe!mainOS_VERSION: 10.0.19041.1BUILDLAB_STR: vb_releaseOSPLATFORM_TYPE: x86OSNAME: Windows 10FAILURE_ID_HASH: {4772375e-2b86-9361-1fdb-daa2edb4f5a8}Followup: MachineOwner---------
-
- Buradaki alanlar, hata kodları ve daha bir çok bilgi için https://docs.microsoft.com/en-us/windows-hardware/drivers/debugger/bug-check-code-reference2 sayfasına muhakkak göz atın.
Evet arkadaşlar bu yazım ile birlikte, sinir bozucu göçme hatalarını çözmede kullanabileceğiniz bir yaklaşıma da göz atmış olduk.
Biraz internette dolaştığımda, bu tarz göçme durumlarını uygulama içerisinde yakalamaya yönelik bir takım kütüphanelere de rast geldim. Açıkçası çok incelemesemde, ihtiyaç duyan arkadaşlar yardımcı olabilir. Bunlardan birisi de “crashrpt” kütüphanesi. Her ne kadar yeni bir kütüphane olmasa da, benzerleri için bir fikir verebilir veya kendi kütüphanenizi oluşturmak için faydalı olabilir. Bu konuda ayrıca https://www.wikiwand.com/en/Crash_reporter sayfasında da, güzel bilgilere ulaşabilirsiniz.
Bir sonraki yazımda görüşmek dileğiyle sevgili yazılımperver dostlarım, bol kodlu ve sağlıklı günler diliyorum 🙂
Kaynaklar
- https://docs.microsoft.com/tr-tr/windows/win32/wer/collecting-user-mode-dumps?redirectedfrom=MSDN
- https://docs.microsoft.com/tr-tr/windows-hardware/drivers/debugger/debugger-download-tools
- https://docs.microsoft.com/en-us/windows-hardware/drivers/debugger/bug-check-code-reference2
- https://www.wikiwand.com/en/Crash_reporter
- http://crashrpt.sourceforge.net/