/*++ Copyright (c) 2000 Microsoft Corporation Module Name: exts.c Abstract: This file contains the generic routines and initialization code for the kernel debugger extensions dll. Environment: User Mode --*/ #include "precomp.h" #pragma hdrstop #include // // Valid for the lifetime of the debug session. // WINDBG_EXTENSION_APIS ExtensionApis; ULONG TargetMachine; BOOL Connected; ULONG g_TargetClass, g_TargetQual; // // Valid only during an extension API call // PDEBUG_ADVANCED g_ExtAdvanced; PDEBUG_CLIENT g_ExtClient; PDEBUG_CONTROL g_ExtControl; PDEBUG_DATA_SPACES g_ExtData; PDEBUG_REGISTERS g_ExtRegisters; PDEBUG_SYMBOLS2 g_ExtSymbols; PDEBUG_SYSTEM_OBJECTS g_ExtSystem; // Queries for all debugger interfaces. extern "C" HRESULT ExtQuery(PDEBUG_CLIENT Client) { HRESULT Status; if ((Status = Client->QueryInterface(__uuidof(IDebugAdvanced), (void **)&g_ExtAdvanced)) != S_OK) { goto Fail; } if ((Status = Client->QueryInterface(__uuidof(IDebugControl), (void **)&g_ExtControl)) != S_OK) { goto Fail; } if ((Status = Client->QueryInterface(__uuidof(IDebugDataSpaces), (void **)&g_ExtData)) != S_OK) { goto Fail; } if ((Status = Client->QueryInterface(__uuidof(IDebugRegisters), (void **)&g_ExtRegisters)) != S_OK) { goto Fail; } if ((Status = Client->QueryInterface(__uuidof(IDebugSymbols), (void **)&g_ExtSymbols)) != S_OK) { goto Fail; } if ((Status = Client->QueryInterface(__uuidof(IDebugSystemObjects), (void **)&g_ExtSystem)) != S_OK) { goto Fail; } g_ExtClient = Client; return S_OK; Fail: ExtRelease(); return Status; } // Cleans up all debugger interfaces. void ExtRelease(void) { g_ExtClient = NULL; EXT_RELEASE(g_ExtAdvanced); EXT_RELEASE(g_ExtControl); EXT_RELEASE(g_ExtData); EXT_RELEASE(g_ExtRegisters); EXT_RELEASE(g_ExtSymbols); EXT_RELEASE(g_ExtSystem); } // Normal output. void __cdecl ExtOut(PCSTR Format, ...) { va_list Args; va_start(Args, Format); g_ExtControl->OutputVaList(DEBUG_OUTPUT_NORMAL, Format, Args); va_end(Args); } // Error output. void __cdecl ExtErr(PCSTR Format, ...) { va_list Args; va_start(Args, Format); g_ExtControl->OutputVaList(DEBUG_OUTPUT_ERROR, Format, Args); va_end(Args); } // Warning output. void __cdecl ExtWarn(PCSTR Format, ...) { va_list Args; va_start(Args, Format); g_ExtControl->OutputVaList(DEBUG_OUTPUT_WARNING, Format, Args); va_end(Args); } // Verbose output. void __cdecl ExtVerb(PCSTR Format, ...) { va_list Args; va_start(Args, Format); g_ExtControl->OutputVaList(DEBUG_OUTPUT_VERBOSE, Format, Args); va_end(Args); } extern "C" HRESULT CALLBACK DebugExtensionInitialize(PULONG Version, PULONG Flags) { IDebugClient *DebugClient; PDEBUG_CONTROL DebugControl; HRESULT Hr; *Version = DEBUG_EXTENSION_VERSION(1, 0); *Flags = 0; if ((Hr = DebugCreate(__uuidof(IDebugClient), (void **)&DebugClient)) != S_OK) { return Hr; } if ((Hr = DebugClient->QueryInterface(__uuidof(IDebugControl), (void **)&DebugControl)) != S_OK) { return Hr; } ExtensionApis.nSize = sizeof (ExtensionApis); if ((Hr = DebugControl->GetWindbgExtensionApis64(&ExtensionApis)) != S_OK) { return Hr; } DebugControl->Release(); DebugClient->Release(); return S_OK; } extern "C" void CALLBACK DebugExtensionNotify(ULONG Notify, ULONG64 Argument) { // // The first time we actually connect to a target, get the page size // if ((Notify == DEBUG_NOTIFY_SESSION_ACCESSIBLE) && (!Connected)) { IDebugClient *DebugClient; PDEBUG_DATA_SPACES DebugDataSpaces; PDEBUG_CONTROL DebugControl; HRESULT Hr; ULONG64 Page; if ((Hr = DebugCreate(__uuidof(IDebugClient), (void **)&DebugClient)) == S_OK) { // // Get the architecture type. // if ((Hr = DebugClient->QueryInterface(__uuidof(IDebugControl), (void **)&DebugControl)) == S_OK) { if ((Hr = DebugControl->GetActualProcessorType( &TargetMachine)) == S_OK) { Connected = TRUE; } ULONG Qualifier; if ((Hr = DebugControl->GetDebuggeeType(&g_TargetClass, &g_TargetQual)) == S_OK) { } DebugControl->Release(); } DebugClient->Release(); } } if (Notify == DEBUG_NOTIFY_SESSION_INACTIVE) { Connected = FALSE; TargetMachine = 0; } return; } extern "C" void CALLBACK DebugExtensionUninitialize(void) { return; } DllInit( HANDLE hModule, DWORD dwReason, DWORD dwReserved ) { switch (dwReason) { case DLL_THREAD_ATTACH: break; case DLL_THREAD_DETACH: break; case DLL_PROCESS_DETACH: break; case DLL_PROCESS_ATTACH: break; } return TRUE; } DECLARE_API ( time ) { dprintf("*** !time is obsolete: Use '.time'\n"); return S_OK; } HRESULT PrintString( BOOL Unicode, PDEBUG_CLIENT Client, LPCSTR args ) { ULONG64 AddrString; ULONG64 Displacement; STRING32 String; UNICODE_STRING UnicodeString; ULONG64 AddrBuffer; CHAR Symbol[1024]; LPSTR StringData; HRESULT hResult; BOOL b; AddrString = GetExpression(args); if (!AddrString) { return E_FAIL; } // // Get the symbolic name of the string // GetSymbol(AddrString, Symbol, &Displacement); // // Read the string from the debuggees address space into our // own. b = ReadMemory(AddrString, &String, sizeof(String), NULL); if ( !b ) { return E_FAIL; } INIT_API(); if (IsPtr64()) { hResult = g_ExtData->ReadPointersVirtual(1, AddrString + FIELD_OFFSET(STRING64, Buffer), &AddrBuffer); } else { hResult = g_ExtData->ReadPointersVirtual(1, AddrString + FIELD_OFFSET(STRING32, Buffer), &AddrBuffer); } EXIT_API(); if (hResult != S_OK) { return E_FAIL; } StringData = (LPSTR) LocalAlloc(LMEM_ZEROINIT, String.Length + sizeof(UNICODE_NULL)); if (!StringData) { return E_FAIL; } dprintf("String(%d,%d)", String.Length, String.MaximumLength); if (Symbol[0]) { dprintf(" %s+%p", Symbol, Displacement); } b = ReadMemory(AddrBuffer, StringData, String.Length, NULL); if ( b ) { if (Unicode) { ANSI_STRING AnsiString; UnicodeString.Buffer = (PWSTR)StringData; UnicodeString.Length = String.Length; UnicodeString.MaximumLength = String.Length+sizeof(UNICODE_NULL); RtlUnicodeStringToAnsiString(&AnsiString, &UnicodeString,TRUE); dprintf(" at %p: %s\n", AddrString, AnsiString.Buffer); RtlFreeAnsiString(&AnsiString); } else { dprintf(" at %p: %s\n", AddrString, StringData); } LocalFree(StringData); return S_OK; } else { LocalFree(StringData); return E_FAIL; } } DECLARE_API( str ) /*++ Routine Description: This function is called to format and dump counted (ansi) string. Arguments: args - Address Return Value: None. --*/ { return PrintString(FALSE, Client, args); } DECLARE_API( ustr ) /*++ Routine Description: This function is called to format and dump counted (unicode) string. Arguments: args - Address Return Value: None. --*/ { return PrintString(TRUE, Client, args); } DECLARE_API( obja ) /*++ Routine Description: This function is called to format and dump an object attributes structure. Arguments: args - Address Return Value: None. --*/ { ULONG64 AddrObja; ULONG64 Displacement; ULONG64 AddrString; STRING32 String; ULONG64 StrAddr = NULL; CHAR Symbol[1024]; LPSTR StringData; BOOL b; ULONG Attr; HRESULT hResult; ULONG ObjectNameOffset; ULONG AttrOffset; ULONG StringOffset; if (IsPtr64()) { ObjectNameOffset = FIELD_OFFSET(OBJECT_ATTRIBUTES64, ObjectName); AttrOffset = FIELD_OFFSET(OBJECT_ATTRIBUTES64, Attributes); StringOffset = FIELD_OFFSET(STRING64, Buffer); } else { ObjectNameOffset = FIELD_OFFSET(OBJECT_ATTRIBUTES32, ObjectName); AttrOffset = FIELD_OFFSET(OBJECT_ATTRIBUTES32, Attributes); StringOffset = FIELD_OFFSET(STRING32, Buffer); } AddrObja = GetExpression(args); if (!AddrObja) { return E_FAIL; } // // Get the symbolic name of the Obja // GetSymbol(AddrObja, Symbol, &Displacement); dprintf("Obja %s+%p at %p:\n", Symbol, Displacement, AddrObja); INIT_API(); hResult = g_ExtData->ReadPointersVirtual(1, AddrObja + ObjectNameOffset, &AddrString); if (hResult != S_OK) { return E_FAIL; } if (AddrString) { b = ReadMemory(AddrString, &String, sizeof(String), NULL); hResult = g_ExtData->ReadPointersVirtual(1, AddrString + StringOffset, &StrAddr); } EXIT_API(); if (StrAddr) { StringData = (LPSTR)LocalAlloc(LMEM_ZEROINIT, String.Length+sizeof(UNICODE_NULL)); if (StringData) { b = ReadMemory(StrAddr, StringData, String.Length, NULL); if (b) { dprintf("\tName is %ws\n", StringData); } LocalFree(StringData); } } b = ReadMemory(AddrObja + AttrOffset, &Attr, sizeof(Attr), NULL); if (!b) { return E_FAIL; } if (Attr & OBJ_INHERIT ) { dprintf("\tOBJ_INHERIT\n"); } if (Attr & OBJ_PERMANENT ) { dprintf("\tOBJ_PERMANENT\n"); } if (Attr & OBJ_EXCLUSIVE ) { dprintf("\tOBJ_EXCLUSIVE\n"); } if (Attr & OBJ_CASE_INSENSITIVE ) { dprintf("\tOBJ_CASE_INSENSITIVE\n"); } if (Attr & OBJ_OPENIF ) { dprintf("\tOBJ_OPENIF\n"); } return S_OK; } DECLARE_API( help ) { dprintf("analyzebugcheck - Perform bugcheck analysis\n"); dprintf("ecb - Edit PCI ConfigSpace byte\n"); dprintf("ecd - Edit PCI ConfigSpace dword\n"); dprintf("ecw - Edit PCI ConfigSpace word\n"); dprintf("exca . - Dump ExCA registers\n"); dprintf("help - Show this help\n"); dprintf("pci [flag] [bus] [device] [function] [rawdump:minaddr] [maxaddr] - Dumps pci type1 config\n"); dprintf(" flag: 0x01 - verbose\n"); dprintf(" 0x02 - from bus 0 to 'bus'\n"); dprintf(" 0x04 - dump raw bytes\n"); dprintf(" 0x08 - dump raw dwords\n"); dprintf(" 0x10 - do not skip invalid devices\n"); dprintf(" 0x20 - do not skip invalid functions\n"); dprintf(" 0x40 - dump Capabilities if found\n"); dprintf(" 0x80 - dump device specific on VendorID:8086\n"); dprintf(" 0x100 - dump config space\n"); return S_OK; }