Menambahkan Pelacakan Peristiwa ke Driver Mode Kernel
Bagian ini menjelaskan cara menggunakan API mode kernel Pelacakan Peristiwa untuk Windows (ETW) untuk menambahkan pelacakan peristiwa ke driver mode kernel. API mode kernel ETW diperkenalkan dengan Windows Vista dan tidak didukung di sistem operasi sebelumnya. Gunakan Pelacakan Perangkat Lunak WPP atau Pelacakan Peristiwa WMI jika driver Anda perlu mendukung kemampuan pelacakan di Windows 2000 dan yang lebih baru.
Tip
Untuk melihat kode sampel yang menunjukkan cara menerapkan ETW menggunakan Windows Driver Kit (WDK) dan Visual Studio, lihat sampel Eventdrv.
Di bagian ini:
Alur Kerja - Menambahkan Pelacakan Peristiwa ke Driver Mode Kernel
1. Tentukan jenis peristiwa yang akan dinaikkan dan tempat menerbitkannya
2. Buat manifes instrumentasi yang mendefinisikan penyedia, peristiwa, dan saluran
3. Kompilasi manifes instrumentasi dengan menggunakan pengkompilasi pesan (Mc.exe)
7. Uji driver untuk memverifikasi dukungan ETW
Alur Kerja - Menambahkan Pelacakan Peristiwa ke Driver Mode Kernel
1. Tentukan jenis peristiwa yang akan dinaikkan dan tempat menerbitkannya
Sebelum mulai mengoding, Anda harus memutuskan jenis peristiwa apa yang Anda inginkan untuk dicatat driver melalui Pelacakan Peristiwa untuk Windows (ETW). Misalnya, Anda mungkin ingin mencatat peristiwa yang dapat membantu Anda mendiagnosis masalah setelah driver didistribusikan, atau peristiwa yang mungkin membantu Anda saat mengembangkan driver Anda. Untuk informasi, lihat Referensi Log Peristiwa Windows.
Jenis peristiwa diidentifikasi dengan saluran. Saluran adalah aliran bernama peristiwa jenis Admin, Operasional, Analitik, atau Debug yang diarahkan ke audiens tertentu, mirip dengan saluran televisi. Saluran mengirimkan peristiwa dari penyedia peristiwa ke log peristiwa dan konsumen peristiwa. Untuk informasi, lihat Menentukan Saluran.
Selama pengembangan, Anda kemungkinan besar tertarik untuk melacak peristiwa yang membantu Anda men-debug kode Anda. Saluran yang sama ini dapat digunakan dalam kode produksi untuk membantu memecahkan masalah yang mungkin muncul setelah driver disebarkan. Anda mungkin juga ingin melacak peristiwa yang dapat digunakan untuk mengukur performa; peristiwa ini dapat membantu profesional TI menyempurnakan performa server dan dapat membantu mengidentifikasi penyempitan jaringan.
2. Buat manifes instrumentasi yang mendefinisikan penyedia, peristiwa, dan saluran
Manifes instrumentasi adalah file XML yang memberikan deskripsi formal tentang peristiwa yang akan dimunculkan penyedia. Manifes instrumentasi mengidentifikasi penyedia peristiwa, menentukan saluran atau saluran (hingga delapan), dan menjelaskan peristiwa, dan templat yang digunakan peristiwa. Selain itu, manifes instrumentasi memungkinkan pelokalan string, sehingga Anda dapat melokalisasi pesan jejak. Sistem peristiwa dan konsumen peristiwa dapat menggunakan data XML terstruktur yang disediakan dalam manifes untuk melakukan kueri dan analisis.
Untuk informasi tentang manifes instrumentasi, lihat Menulis Manifes Instrumentasi (Windows), Skema EventManifest (Windows) dan Menggunakan Log Peristiwa Windows (Windows).
Manifes instrumentasi berikut menunjukkan penyedia peristiwa yang menggunakan nama "Driver Sampel." Perhatikan bahwa nama ini tidak harus sama dengan nama biner driver. Manifes juga menentukan GUID untuk penyedia dan jalur ke file pesan dan sumber daya. File pesan dan sumber daya memberi tahu ETW di mana menemukan sumber daya yang diperlukan untuk mendekode dan melaporkan peristiwa. Jalur ini menunjuk ke lokasi file driver (.sys). Pengandar harus diinstal dalam direktori yang ditentukan pada komputer target.
Contohnya menggunakan Sistem saluran bernama, saluran untuk peristiwa jenis Admin. Saluran ini didefinisikan dalam file Winmeta.xml yang disediakan dengan Windows Driver Kit (WDK) di direktori%WindowsSdkDir%\include\um. Saluran Sistem diamankan ke aplikasi yang berjalan di bawah akun layanan sistem. Manifes mencakup templat peristiwa yang menjelaskan jenis data yang disediakan dengan peristiwa saat diterbitkan, bersama dengan konten statis dan dinamisnya. Contoh manifes ini mendefinisikan tiga peristiwa: StartEvent
, SampleEventA
, dan UnloadEvent
.
Selain saluran, Anda dapat mengaitkan peristiwa dengan tingkat dan kata kunci. Kata kunci dan tingkat menyediakan cara untuk mengaktifkan peristiwa dan menyediakan mekanisme untuk memfilter peristiwa saat dipublikasikan. Kata kunci dapat digunakan untuk mengelompokkan peristiwa terkait logis bersama-sama. Tingkat dapat digunakan untuk menunjukkan tingkat keparahan atau verbositas peristiwa, misalnya, kritis, kesalahan, peringatan, atau informasi. File Winmeta.xml berisi nilai yang telah ditentukan sebelumnya untuk atribut peristiwa.
Saat Anda membuat templat untuk payload peristiwa (pesan peristiwa, dan data), Anda harus menentukan jenis input dan output. Jenis yang didukung dijelaskan di bagian Keterangan dari Jenis Kompleks InputType (Windows).
<?xml version='1.0' encoding='utf-8' standalone='yes'?>
<instrumentationManifest
xmlns="http://schemas.microsoft.com/win/2004/08/events"
xmlns:win="http://manifests.microsoft.com/win/2004/08/windows/events"
xmlns:xs="http://www.w3.org/2001/XMLSchema"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://schemas.microsoft.com/win/2004/08/events eventman.xsd"
>
<instrumentation>
<events>
<provider
guid="{b5a0bda9-50fe-4d0e-a83d-bae3f58c94d6}"
messageFileName="%SystemDrive%\ETWDriverSample\Eventdrv.sys"
name="Sample Driver"
resourceFileName="%SystemDrive%\ETWDriverSample\Eventdrv.sys"
symbol="DriverControlGuid"
>
<channels>
<importChannel
chid="SYSTEM"
name="System"
/>
</channels>
<templates>
<template tid="tid_load_template">
<data
inType="win:UInt16"
name="DeviceNameLength"
outType="xs:unsignedShort"
/>
<data
inType="win:UnicodeString"
name="name"
outType="xs:string"
/>
<data
inType="win:UInt32"
name="Status"
outType="xs:unsignedInt"
/>
</template>
<template tid="tid_unload_template">
<data
inType="win:Pointer"
name="DeviceObjPtr"
outType="win:HexInt64"
/>
</template>
</templates>
<events>
<event
channel="SYSTEM"
level="win:Informational"
message="$(string.StartEvent.EventMessage)"
opcode="win:Start"
symbol="StartEvent"
template="tid_load_template"
value="1"
/>
<event
channel="SYSTEM"
level="win:Informational"
message="$(string.SampleEventA.EventMessage)"
opcode="win:Info"
symbol="SampleEventA"
value="2"
/>
<event
channel="SYSTEM"
level="win:Informational"
message="$(string.UnloadEvent.EventMessage)"
opcode="win:Stop"
symbol="UnloadEvent"
template="tid_unload_template"
value="3"
/>
</events>
</provider>
</events>
</instrumentation>
<localization xmlns="http://schemas.microsoft.com/win/2004/08/events">
<resources culture="en-US">
<stringTable>
<string
id="StartEvent.EventMessage"
value="Driver Loaded"
/>
<string
id="SampleEventA.EventMessage"
value="IRP A Occurred"
/>
<string
id="UnloadEvent.EventMessage"
value="Driver Unloaded"
/>
</stringTable>
</resources>
</localization>
</instrumentationManifest>
3. Kompilasi manifes instrumentasi dengan menggunakan pengkompilasi pesan (Mc.exe)
Pengkompilasi pesan (Mc.exe) harus dijalankan sebelum Anda mengkompilasi kode sumber Anda. Pengkompilasi pesan disertakan dalam Windows Driver Kit (WDK). Pengkompilasi pesan membuat file header yang berisi definisi untuk penyedia peristiwa, atribut peristiwa, saluran, dan peristiwa. Anda harus menyertakan file header ini dalam kode sumber Anda. Pengkompilasi pesan juga menempatkan skrip pengkompilasi sumber daya yang dihasilkan (*.rc) dan file .bin yang dihasilkan (sumber daya biner) yang disertakan oleh skrip pengkompilasi sumber daya.
Anda dapat menyertakan langkah ini sebagai bagian dari proses build Anda dalam beberapa cara:
Menambahkan tugas pengkompilasi pesan ke file proyek driver (seperti yang ditunjukkan dalam sampel Eventdrv).
Menggunakan Visual Studio untuk menambahkan manifes instrumentasi dan untuk mengonfigurasi properti Pengkompilasi Pesan.
Menambahkan tugas pengkompilasi pesan ke file proyek Untuk contoh bagaimana Anda dapat menyertakan pengkompilasi pesan dalam proses build, lihat file proyek untuk sampel Eventdrv. Dalam file Eventdrv.vcxproj, ada <bagian MessageCompile> yang memanggil pengkompilasi pesan. Pengkompilasi pesan menggunakan file manifes (evntdrv.xml) sebagai input untuk menghasilkan file header evntdrvEvents.h. Bagian ini juga menentukan jalur untuk file RC yang dihasilkan dan mengaktifkan makro pengelogan mode kernel. Anda dapat menyalin bagian ini dan menambahkannya ke file proyek driver Anda (.vcxproj).
<MessageCompile Include="evntdrv.xml">
<GenerateKernelModeLoggingMacros>true</GenerateKernelModeLoggingMacros>
<HeaderFilePath>.\$(IntDir)</HeaderFilePath>
<GeneratedHeaderPath>true</GeneratedHeaderPath>
<WinmetaPath>"$(SDK_INC_PATH)\winmeta.xml"</WinmetaPath>
<RCFilePath>.\$(IntDir)</RCFilePath>
<GeneratedRCAndMessagesPath>true</GeneratedRCAndMessagesPath>
<GeneratedFilesBaseName>evntdrvEvents</GeneratedFilesBaseName>
<UseBaseNameOfInput>true</UseBaseNameOfInput>
</MessageCompile>
Saat Anda membuat sampel Eventdrv.sys, Visual Studio membuat file yang diperlukan untuk pelacakan peristiwa. Ini juga menambahkan manifes evntdrv.xml ke daftar File Sumber Daya untuk proyek driver. Anda dapat memilih dan menahan (atau mengklik kanan) manifes untuk melihat halaman properti Pengkompilasi Pesan.
Menggunakan Visual Studio untuk menambahkan manifes instrumentasi
Anda dapat menambahkan manifes instrumentasi ke proyek driver lalu mengonfigurasi properti pengkompilasi pesan untuk membangun file sumber daya dan header yang diperlukan.
Untuk menambahkan manifes instrumentasi ke proyek menggunakan Visual Studio
Di Penjelajah Solusi, tambahkan file manifes ke proyek driver. Pilih dan tahan (atau klik kanan) File > Sumber Daya Tambahkan > Item yang Ada (misalnya, evntdrv.xml atau mydriver.man).
Pilih dan tahan (atau klik kanan) file yang baru saja Anda tambahkan dan gunakan halaman properti untuk mengubah jenis item menjadi MessageCompile dan pilih Terapkan.
Properti Pengkompilasi Pesan muncul. Di bawah Pengaturan umum , atur opsi berikut lalu pilih Terapkan.
Umum Pengaturan Hasilkan Makro Pengelogan Mode Kernel Ya (-km) Gunakan Nama Dasar Input Ya (-b) Di bawah Opsi File, atur opsi berikut lalu pilih Terapkan.
Opsi File Pengaturan Membuat file header untuk penghitung yang berisi Ya Jalur File Header $(IntDir) Jalur File Pesan RC dan Biner yang Dihasilkan Ya Jalur File RC $(IntDir) Nama Dasar File yang Dihasilkan $(Nama file)
Secara default, pengkompilasi pesan menggunakan nama dasar file input sebagai nama dasar file yang dihasilkannya. Untuk menentukan nama dasar, atur bidang Nama Dasar File yang Dihasilkan (-z). Dalam sampel Eventdr.sys, nama dasar diatur ke evntdrvEvents sehingga cocok dengan nama file header evntdrvEvents.h, yang disertakan dalam evntdrv.c.
Catatan
Jika Anda tidak menyertakan file .rc yang dihasilkan dalam proyek Visual Studio, Anda mungkin mendapatkan pesan kesalahan tentang sumber daya yang tidak ditemukan saat menginstal file manifes.
4. Tambahkan kode yang dihasilkan untuk menaikkan (menerbitkan) peristiwa (daftar, membatalkan pendaftaran, dan menulis peristiwa)
Dalam manifes instrumentasi, Anda menentukan nama penyedia peristiwa dan deskriptor peristiwa. Saat Anda mengkompilasi manifes instrumentasi dengan pengkompilasi pesan, pengkompilasi pesan menghasilkan file header yang menjelaskan sumber daya dan juga menentukan makro untuk peristiwa tersebut. Sekarang, Anda harus menambahkan kode yang dihasilkan ke driver Anda untuk menaikkan peristiwa ini.
Dalam file sumber Anda, sertakan file header peristiwa yang dihasilkan oleh pengkompilasi pesan (MC.exe). Misalnya, dalam sampel Eventdrv, file sumber Evntdrv.c menyertakan file header (evntdrvEvents.h) yang dihasilkan pada langkah sebelumnya:
#include "evntdrvEvents.h"
Tambahkan makro yang mendaftar dan membatalkan pendaftaran driver sebagai penyedia peristiwa. Misalnya, dalam file header untuk sampel Eventdrv (evntdrvEvents.h), pengkompilasi pesan membuat makro berdasarkan nama penyedia. Dalam manifes, sampel Eventdrv menggunakan nama "Driver Sampel" sebagai nama penyedia. Pengompilasi pesan menggabungkan nama penyedia dengan makro peristiwa untuk mendaftarkan penyedia, dalam hal ini, EventRegisterSample_Driver.
// This is the generated header file envtdrvEvents.h // // ... // // // Register with ETW Vista + // #ifndef EventRegisterSample_Driver #define EventRegisterSample_Driver() McGenEventRegister(&DriverControlGuid, McGenControlCallbackV2, &DriverControlGuid_Context, &Sample_DriverHandle) #endif
Tambahkan makro penyedia> EventRegister<ke fungsi DriverEntry Anda. Tambahkan fungsi ini setelah kode yang membuat dan menginisialisasi objek perangkat. Perhatikan bahwa Anda harus mencocokkan panggilan ke fungsi penyedia> EventRegister<dengan panggilan ke penyedia> EventUnregister.< Anda dapat membatalkan pendaftaran driver dalam rutinitas Bongkar* driver Anda.
// DriverEntry function // ... // Register with ETW // EventRegisterSample_Driver();
Tambahkan kode yang dihasilkan ke file sumber driver Anda untuk menulis (menaikkan) peristiwa yang Anda tentukan dalam manifes. File header yang Anda kompilasi dari manifes berisi kode yang dihasilkan untuk driver. Gunakan fungsi peristiwa> EventWrite<yang ditentukan dalam file header untuk menerbitkan pesan pelacakan ke ETW. Misalnya, kode berikut menunjukkan makro untuk peristiwa yang ditentukan dalam evntdrvEvents.h untuk sampel Eventdrv.
Makro untuk menulis peristiwa ini disebut:
EventWriteStartEvent
, ,EventWriteSampleEventA
danEventWriteUnloadEvent
. Seperti yang Anda lihat dalam definisi makro ini, definisi makro secara otomatis menyertakan makro peristiwa> EventEnabled<yang memeriksa apakah peristiwa diaktifkan. Pemeriksaan menghilangkan kebutuhan untuk membangun payload jika peristiwa tidak diaktifkan./// // This is the generated header file envtdrvEvents.h // // ... // // Enablement check macro for StartEvent // #define EventEnabledStartEvent() ((Sample_DriverEnableBits[0] & 0x00000001) != 0) // // Event Macro for StartEvent // #define EventWriteStartEvent(Activity, DeviceNameLength, name, Status)\ EventEnabledStartEvent() ?\ Template_hzq(Sample_DriverHandle, &StartEvent, Activity, DeviceNameLength, name, Status)\ : STATUS_SUCCESS\ // // Enablement check macro for SampleEventA // #define EventEnabledSampleEventA() ((Sample_DriverEnableBits[0] & 0x00000001) != 0) // // Event Macro for SampleEventA // #define EventWriteSampleEventA(Activity)\ EventEnabledSampleEventA() ?\ TemplateEventDescriptor(Sample_DriverHandle, &SampleEventA, Activity)\ : STATUS_SUCCESS\ // // Enablement check macro for UnloadEvent // #define EventEnabledUnloadEvent() ((Sample_DriverEnableBits[0] & 0x00000001) != 0) // // Event Macro for UnloadEvent // #define EventWriteUnloadEvent(Activity, DeviceObjPtr)\ EventEnabledUnloadEvent() ?\ Template_p(Sample_DriverHandle, &UnloadEvent, Activity, DeviceObjPtr)\ : STATUS_SUCCESS\
Tambahkan makro peristiwa> EventWrite<ke dalam kode sumber Anda untuk peristiwa yang Anda ajukan. Misalnya, cuplikan kode berikut menunjukkan rutinitas DriverEntry dari sampel Eventdrv. DriverEntry menyertakan makro untuk mendaftarkan driver dengan ETW (EventRegisterSample_Driver) dan makro untuk menulis peristiwa driver ke ETW (EventWriteStartEvent).
NTSTATUS DriverEntry( IN PDRIVER_OBJECT DriverObject, IN PUNICODE_STRING RegistryPath ) /*++ Routine Description: Installable driver initialization entry point. This entry point is called directly by the I/O system. Arguments: DriverObject - pointer to the driver object RegistryPath - pointer to a unicode string representing the path to driver-specific key in the registry Return Value: STATUS_SUCCESS if successful STATUS_UNSUCCESSFUL otherwise --*/ { NTSTATUS Status = STATUS_SUCCESS; UNICODE_STRING DeviceName; UNICODE_STRING LinkName; PDEVICE_OBJECT EventDrvDeviceObject; WCHAR DeviceNameString[128]; ULONG LengthToCopy = 128 * sizeof(WCHAR); UNREFERENCED_PARAMETER (RegistryPath); KdPrint(("EventDrv: DriverEntry\n")); // // Create Dispatch Entry Points. // DriverObject->DriverUnload = EventDrvDriverUnload; DriverObject->MajorFunction[ IRP_MJ_CREATE ] = EventDrvDispatchOpenClose; DriverObject->MajorFunction[ IRP_MJ_CLOSE ] = EventDrvDispatchOpenClose; DriverObject->MajorFunction[ IRP_MJ_DEVICE_CONTROL ] = EventDrvDispatchDeviceControl; RtlInitUnicodeString( &DeviceName, EventDrv_NT_DEVICE_NAME ); // // Create the Device object // Status = IoCreateDevice( DriverObject, 0, &DeviceName, FILE_DEVICE_UNKNOWN, 0, FALSE, &EventDrvDeviceObject); if (!NT_SUCCESS(Status)) { return Status; } RtlInitUnicodeString( &LinkName, EventDrv_WIN32_DEVICE_NAME ); Status = IoCreateSymbolicLink( &LinkName, &DeviceName ); if ( !NT_SUCCESS( Status )) { IoDeleteDevice( EventDrvDeviceObject ); return Status; } // // Choose a buffering mechanism // EventDrvDeviceObject->Flags |= DO_BUFFERED_IO; // // Register with ETW // EventRegisterSample_Driver(); // // Log an Event with : DeviceNameLength // DeviceName // Status // // Copy the device name into the WCHAR local buffer in order // to place a NULL character at the end, since this field is // defined in the manifest as a NULL-terminated string if (DeviceName.Length <= 128 * sizeof(WCHAR)) { LengthToCopy = DeviceName.Length; } RtlCopyMemory(DeviceNameString, DeviceName.Buffer, LengthToCopy); DeviceNameString[LengthToCopy/sizeof(WCHAR)] = L'\0'; EventWriteStartEvent(NULL, DeviceName.Length, DeviceNameString, Status); return STATUS_SUCCESS; }
Tambahkan semua makro peristiwa> EventWrite<ke dalam kode sumber Anda untuk peristiwa yang Anda tingkatkan. Anda dapat memeriksa sampel Eventdrv untuk melihat bagaimana dua makro lainnya dipanggil untuk peristiwa dalam kode sumber driver.
Batalkan pendaftaran driver sebagai penyedia peristiwa menggunakan makro penyedia> EventUnregister<dari file header yang dihasilkan.
Lakukan panggilan fungsi ini dalam rutinitas pembongkaran driver Anda. Tidak ada panggilan pelacakan yang harus dilakukan setelah makro penyedia> EventUnregister<dipanggil. Kegagalan untuk membatalkan pendaftaran penyedia peristiwa dapat menyebabkan kesalahan ketika proses dibongkar karena fungsi panggilan balik apa pun yang terkait dengan proses tidak lagi valid.
// DriverUnload function // ... // // Unregister the driver as an ETW provider // EventUnregisterSample_Driver();
5. Bangun driver
Jika Anda telah menambahkan manifes instrumen ke proyek dan telah mengonfigurasi properti pengkompilasi pesan (MC.exe), Anda dapat membangun proyek atau solusi driver menggunakan Visual Studio dan MSBuild.
Buka solusi driver di Visual Studio.
Buat sampel dari menu Build dengan memilih Build Solution. Untuk informasi selengkapnya tentang membangun solusi, lihat Membangun Driver.
6. Instal manifes
Anda harus menginstal manifes pada sistem target sehingga konsumen peristiwa (misalnya, Log Peristiwa) dapat menemukan lokasi biner yang berisi metadata peristiwa. Jika Anda menambahkan tugas pengkompilasi pesan ke proyek driver di Langkah 3, manifes instrumentasi dikompilasi dan file sumber daya dibuat saat Anda membuat driver. Gunakan Utilitas Baris Perintah Peristiwa Windows (Wevtutil.exe) untuk menginstal manifes. Sintaks untuk menginstal manifes adalah sebagai berikut:
wevtutil.exe im drivermanifest
Misalnya, untuk menginstal manifes untuk driver sampel Evntdrv.sys, buka jendela Prompt Perintah dengan hak istimewa yang ditinggikan (Jalankan sebagai administrator) navigasikan ke direktori tempat file evntdrv.xml berada dan masukkan perintah berikut:
Wevtutil.exe im evntdrv.xml
Saat sesi pelacakan Anda selesai, hapus instalan manifes menggunakan sintaks berikut.
wevtutil.exe umm drivermanifest
Misalnya, untuk menghapus instalan manifes untuk sampel Eventdrv:
Wevtutil.exe um evntdrv.xml
7. Uji driver untuk memverifikasi dukungan ETW
Pasang driver. Latihan driver untuk menghasilkan aktivitas pelacakan. Lihat hasilnya di Pemantau Peristiwa. Anda juga dapat menjalankan Tracelog, lalu menjalankan Tracerpt, alat untuk memproses log jejak peristiwa, untuk mengontrol, mengumpulkan, dan melihat log jejak peristiwa.