Membaca Data Panggilan Balik Pemeriksaan Bug

Banyak driver menyediakan rutinitas panggilan balik pemeriksaan bug. Ketika Windows mengeluarkan pemeriksaan bug, windows memanggil rutinitas ini sebelum mematikan sistem. Rutinitas ini dapat menentukan dan menulis ke area memori yang dikenal sebagai data panggilan balik dan data panggilan balik sekunder.

BugCheckCallback menggunakan KBUGCHECK_CALLBACK_ROUTINE
Data yang ditulis oleh rutinitas ini menjadi bagian dari data panggilan balik. Data tidak disertakan dalam file crash dump.

BugCheckSecondaryDumpDataCallback menggunakan KBUGCHECK_REASON_CALLBACK_ROUTINE
Data yang ditulis oleh rutinitas ini menjadi bagian dari data panggilan balik sekunder. Data disertakan dalam file crash dump.

BugCheckAddPagesCallback menggunakan KBUGCHECK_REASON_CALLBACK_ROUTINE
Halaman yang ditentukan oleh rutinitas ini menjadi bagian dari data panggilan balik. Data di halaman tersebut disertakan dalam file crash dump.

Jumlah data panggilan balik dan panggilan balik sekunder yang tersedia untuk debugger tergantung pada beberapa faktor:

  • Jika Anda melakukan penelusuran kesalahan langsung sistem yang mengalami crash, data panggilan balik yang telah ditulis oleh BugCheckCallback atau ditentukan oleh BugCheckAddPagesCallback akan tersedia. Data panggilan balik sekunder tidak akan tersedia, karena tidak disimpan di lokasi memori tetap.

  • Jika Anda men-debug Cadangan Memori Lengkap atau Cadangan Memori Kernel, data panggilan balik yang ditentukan oleh BugCheckAddPagesCallback dan data panggilan balik sekunder yang ditulis oleh BugCheckSecondaryDumpDataCallback akan tersedia. Data panggilan balik yang ditulis oleh BugCheckCallback tidak akan tersedia.

  • Jika Anda men-debug Cadangan Memori Kecil, data panggilan balik tidak akan tersedia. Data panggilan balik sekunder akan tersedia.

Lihat Varietas file cadangan Kernel-Mode untuk detail selengkapnya tentang ukuran file cadangan yang berbeda ini.

Menampilkan Data Panggilan Balik

Untuk menampilkan data panggilan balik pemeriksaan bug, Anda dapat menggunakan ekstensi !bugdump .

Tanpa parameter apa pun, !bugdump akan menampilkan data untuk semua panggilan balik.

Untuk melihat data untuk satu rutinitas panggilan balik tertentu, gunakan Komponen !bugdump, di mana Komponen adalah parameter yang sama yang diteruskan ke KeRegisterBugCheckCallback ketika rutinitas tersebut didaftarkan.

Menampilkan Data Panggilan Balik Sekunder

Ada dua metode untuk menampilkan data panggilan balik sekunder. Anda dapat menggunakan perintah .enumtag atau Anda dapat menulis ekstensi debugger Anda sendiri.

Setiap blok data panggilan balik sekunder diidentifikasi oleh tag GUID. Tag ini ditentukan oleh bidang Guid dari parameter (KBUGCHECK_SECONDARY_DUMP_DATA)ReasonSpecificData yang diteruskan ke BugCheckSecondaryDumpDataCallback.

Perintah .enumtag (Enumerate Secondary Callback Data) bukanlah instrumen yang sangat tepat. Ini menampilkan setiap blok data sekunder, memperlihatkan tag lalu memperlihatkan data dalam format heksadesimal dan ASCII. Umumnya hanya berguna untuk menentukan tag apa yang sebenarnya digunakan untuk blok data sekunder.

Untuk menggunakan data ini dengan cara yang lebih praktis, disarankan agar Anda menulis ekstensi debugger Anda sendiri. Ekstensi ini harus memanggil metode dalam file header dbgeng.h. Untuk detailnya, lihat Menulis Ekstensi Debugger Baru.

Jika Anda mengetahui tag GUID blok data sekunder, ekstensi Anda harus menggunakan metode IDebugDataSpaces3::ReadTagged untuk mengakses data. Prototipenya adalah sebagai berikut:

STDMETHOD(ReadTagged)(
    THIS_
    IN LPGUID Tag,
    IN ULONG Offset,
    OUT OPTIONAL PVOID Buffer,
    IN ULONG BufferSize,
    OUT OPTIONAL PULONG TotalSize
    ) PURE; 

Berikut adalah contoh cara menggunakan metode ini:

UCHAR RawData[MY_DATA_SIZE];
GUID MyGuid = .... ;

Success = DataSpaces->ReadTagged(  &MyGuid,  0,  RawData,
                                   sizeof(RawData),  NULL); 

Jika Anda menyediakan BufferSize yang terlalu kecil, ReadTagged akan berhasil tetapi hanya akan menulis jumlah byte yang diminta ke Buffer. Jika Anda menentukan BufferSize yang terlalu besar, ReadTagged akan berhasil tetapi hanya akan menulis ukuran blok aktual ke Buffer. Jika Anda menyediakan pointer untuk TotalSize, ReadTagged akan menggunakannya untuk mengembalikan ukuran blok aktual. Jika blok tidak dapat diakses, ReadTagged akan mengembalikan kode status kegagalan.

Jika dua blok memiliki tag GUID yang identik, blok pencocokan pertama akan dikembalikan, dan blok kedua tidak akan dapat diakses.

Jika Anda tidak yakin dengan tag GUID blok Anda, Anda dapat menggunakan metode IDebugDataSpaces3::StartEnumTagged, IDebugDataSpaces3::GetNextTagged, dan IDebugDataSpaces3::EndEnumTagged untuk menghitung blok yang ditandai. Prototipe mereka adalah sebagai berikut:

STDMETHOD(StartEnumTagged)(
    THIS_
    OUT PULONG64 Handle
    ) PURE;

STDMETHOD(GetNextTagged)(
    THIS_
    IN ULONG64 Handle,
    OUT LPGUID Tag,
    OUT PULONG Size
    ) PURE;

STDMETHOD(EndEnumTagged)(
    THIS_
    IN ULONG64 Handle
    ) PURE;

Men-debug Rutinitas Panggilan Balik

Dimungkinkan juga untuk men-debug rutinitas panggilan balik itu sendiri. Titik henti dalam rutinitas panggilan balik berfungsi sama seperti titik henti lainnya.

Jika rutinitas panggilan balik menyebabkan pemeriksaan bug kedua, pemeriksaan bug baru ini akan diproses terlebih dahulu. Namun, Windows tidak akan mengulangi bagian tertentu dari proses Hentikan—misalnya, windows tidak akan menulis file crash dump kedua. Kode Berhenti yang ditampilkan pada layar biru akan menjadi kode pemeriksaan bug kedua. Jika debugger kernel dilampirkan, pesan tentang kedua pemeriksaan bug biasanya akan muncul.