///////////////////////////////////////////////////////////////////////////// // // singx86.cpp - Singularity Debugger Extension. // // Copyright (c) Microsoft Corporation. All rights reserved. // // For more information, see http://ddkslingshot/webs/debugexw/ // #include "singx86.h" #include extern bool fCachedLogStateValid; ULONG TargetMachine; BOOL Connected; PDEBUG_ADVANCED g_ExtAdvanced; PDEBUG_CLIENT g_ExtClient; PDEBUG_CONTROL4 g_ExtControl; PDEBUG_DATA_SPACES4 g_ExtData; PDEBUG_REGISTERS2 g_ExtRegisters; PDEBUG_SYMBOLS g_ExtSymbols = NULL; PDEBUG_SYSTEM_OBJECTS g_ExtSystem; // Queries for all debugger interfaces. HRESULT ExtQuery(PDEBUG_CLIENT Client) { HRESULT status; // // Required interfaces. // if ((status = Client->QueryInterface(__uuidof(IDebugAdvanced), (void **)&g_ExtAdvanced)) != S_OK) { goto Fail; } if ((status = Client->QueryInterface(__uuidof(IDebugControl4), (void **)&g_ExtControl)) != S_OK) { goto Fail; } if ((status = Client->QueryInterface(__uuidof(IDebugDataSpaces4), (void **)&g_ExtData)) != S_OK) { goto Fail; } if ((status = Client->QueryInterface(__uuidof(IDebugRegisters2), (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); } HRESULT ExtEvalU64(PCSTR* Str, PULONG64 Val) { HRESULT status; DEBUG_VALUE FullVal; ULONG EndIdx; if ((status = g_ExtControl-> Evaluate(*Str, DEBUG_VALUE_INT64, &FullVal, &EndIdx)) != S_OK) { return status; } *Val = FullVal.I64; (*Str) += EndIdx; while (**Str == ' ' || **Str == '\t' || **Str == '\n' || **Str == '\r') { (*Str)++; } return S_OK; } HRESULT ExtDefPointer(ULONG64 address, PULONG64 val) { *val = 0; return g_ExtData->ReadPointersVirtual(1, address, val); } ////////////////////////////////////////////////////////////////////////////// // class MyEventCallbacks : public DebugBaseEventCallbacks { ULONG count; public: MyEventCallbacks() { count = 1; } STDMETHOD_(ULONG, AddRef)(THIS) { count++; return count; } STDMETHOD_(ULONG, Release)(THIS) { count--; return count; } STDMETHOD(GetInterestMask)( THIS_ __out PULONG Mask) { *Mask = DEBUG_EVENT_CHANGE_DEBUGGEE_STATE; return S_OK; } STDMETHOD(ChangeDebuggeeState)( THIS_ __in ULONG Flags, __in ULONG64 Argument ) { UNREFERENCED_PARAMETER(Flags); UNREFERENCED_PARAMETER(Argument); PDEBUG_CLIENT DebugClient; PDEBUG_CONTROL DebugControl; HRESULT Hr; if ((Hr = DebugCreate(__uuidof(IDebugClient), (void **)&DebugClient)) != S_OK) { return Hr; } if ((Hr = DebugClient->QueryInterface(__uuidof(IDebugControl), (void **)&DebugControl)) == S_OK) { return Hr; } fCachedLogStateValid = false; EXT_RELEASE(DebugControl); EXT_RELEASE(DebugClient); return S_OK; } }; static MyEventCallbacks g_Callback; ////////////////////////////////////////////////////////////////////////////// // extern "C" HRESULT CALLBACK DebugExtensionInitialize(PULONG Version, PULONG Flags) { PDEBUG_CLIENT DebugClient; PDEBUG_CONTROL DebugControl; HRESULT Hr; *Version = DEBUG_EXTENSION_VERSION(1, 0); *Flags = 0; Hr = S_OK; if ((Hr = DebugCreate(__uuidof(IDebugClient), (void **)&DebugClient)) != S_OK) { return Hr; } if ((Hr = DebugClient->QueryInterface(__uuidof(IDebugControl), (void **)&DebugControl)) == S_OK) { } Hr = DebugClient->SetEventCallbacks(&g_Callback); ULONG execStatus = 0; if ((Hr = DebugControl->GetExecutionStatus(&execStatus)) == S_OK) { // #define DEBUG_STATUS_NO_CHANGE 0 // #define DEBUG_STATUS_GO 1 // #define DEBUG_STATUS_GO_HANDLED 2 // #define DEBUG_STATUS_GO_NOT_HANDLED 3 // #define DEBUG_STATUS_STEP_OVER 4 // #define DEBUG_STATUS_STEP_INTO 5 // #define DEBUG_STATUS_BREAK 6 // #define DEBUG_STATUS_NO_DEBUGGEE 7 // #define DEBUG_STATUS_STEP_BRANCH 8 // #define DEBUG_STATUS_IGNORE_EVENT 9 // #define DEBUG_STATUS_RESTART_REQUESTED 10 } EXT_RELEASE(DebugControl); EXT_RELEASE(DebugClient); return Hr; } extern "C" void CALLBACK DebugExtensionNotify(ULONG Notify, ULONG64 Argument) { UNREFERENCED_PARAMETER(Argument); // // The first time we actually connect to a target // if ((Notify == DEBUG_NOTIFY_SESSION_ACCESSIBLE) && (!Connected)) { IDebugClient *DebugClient; HRESULT Hr; PDEBUG_CONTROL DebugControl; 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; } OnTargetAccessible(DebugClient); DebugControl->Release(); } DebugClient->Release(); } } if (Notify == DEBUG_NOTIFY_SESSION_INACTIVE) { Connected = FALSE; TargetMachine = 0; } } ////////////////////////////////////////////////////////////////////////////// /* This gets called (by DebugExtensionNotify when target is halted and is accessible */ HRESULT OnTargetAccessible(PDEBUG_CLIENT client) { EXT_ENTER(); // Defines: HRESULT status = S_OK; ExtOut("**** SingX86.dll [" __DATE__ " " __TIME__ "] detected a break"); if (Connected) { ExtOut(" connected to "); switch (TargetMachine) { case IMAGE_FILE_MACHINE_I386: ExtOut("X86"); break; case IMAGE_FILE_MACHINE_IA64: ExtOut("IA64"); break; default: ExtOut("Other"); break; } } ExtOut(" ****\n"); EXT_CHECK(StructType::InitializeRegistered()); EXT_LEAVE(); // Macro includes: return status; } extern "C" void CALLBACK DebugExtensionUninitialize(void) { PDEBUG_CLIENT DebugClient; HRESULT Hr; if ((Hr = DebugCreate(__uuidof(IDebugClient), (void **)&DebugClient)) != S_OK) { return; } Hr = DebugClient->SetEventCallbacks(NULL); EXT_RELEASE(DebugClient); } extern "C" HRESULT CALLBACK KnownStructOutput( ULONG Flag, ULONG64 Address, PSTR StructName, PSTR Buffer, PULONG BufferSize ) { IDebugClient *Client; HRESULT status; if ((status = DebugCreate(__uuidof(IDebugClient), (void **)&Client)) == S_OK) { switch (Flag) { case DEBUG_KNOWN_STRUCT_GET_NAMES: status = OnGetKnownStructNames(Client, Buffer, BufferSize); break; case DEBUG_KNOWN_STRUCT_GET_SINGLE_LINE_OUTPUT: status = OnGetSingleLineOutput(Client, Address, StructName, Buffer, BufferSize); break; case DEBUG_KNOWN_STRUCT_SUPPRESS_TYPE_NAME: status = OnGetSuppressTypeName(Client, StructName); break; default: status = E_INVALIDARG; break; } } EXT_RELEASE(Client); return status; } ULONG64 GetStaticPointer(PCSTR name) { HRESULT status = S_OK; ULONG64 address; ULONG64 value = 0; EXT_CHECK(g_ExtSymbols->GetOffsetByName(name, &address)); EXT_CHECK(g_ExtData->ReadPointersVirtual(1, address, &value)); Exit: return value; } ///////////////////////////////////// Remote to Local conversions for structs. // StructType * StructType::registered = NULL; StructType::StructType(PCSTR name, ULONG localSize, struct FieldType *fields) { this->next = registered; registered = this; this->name = name; this->localSize = localSize; this->fields = fields; this->fieldCount = 0; this->module = 0; this->type = 0; this->size = 0; this->temp = NULL; } HRESULT StructType::InitializeRegistered() { for (StructType *next = registered; next != NULL; next = next->next) { next->Initialize(); } return S_OK; } HRESULT StructType::Initialize() { HRESULT status = S_OK; ExtVerb("Initializing: %s [%p]\n", name, fields); EXT_CHECK(g_ExtSymbols->GetSymbolTypeId(name, &type, &module)); EXT_CHECK(g_ExtSymbols->GetTypeSize(module, type, &size)); ExtVerb("Initializing: %s [size=%d]\n", name, size); if (temp != NULL) { delete[] temp; } temp = new BYTE [size]; ZeroMemory(temp, size); fieldCount = 0; for (FieldType *field = fields; field->name != NULL; field++) { CHAR fieldName[512]; EXT_CHECK(StringCbPrintf(fieldName, sizeof(fieldName), "%s.%s", name, field->name)); status = g_ExtSymbols->GetSymbolTypeId(fieldName, &field->type, &field->module); if (status == S_OK) { EXT_CHECK(g_ExtSymbols->GetTypeSize(field->module, field->type, &field->size)); EXT_CHECK(g_ExtSymbols->GetFieldOffset(module, type, field->name, &field->offset)); ExtVerb("Initializing: %s [offset=%d,size=%d]\n", fieldName, field->offset, field->size); } else { ExtErr("Can't find: %s\n", fieldName); field->size = 0; field->offset = 0; } field->parent = this; fieldCount++; } Exit: ExtVerb("** Exited with %08x\n", status); return status; } HRESULT StructType::RemoteOffsetFromLocal(ULONG localOffset, ULONG *remoteOffset) { for (ULONG f = 0; f < fieldCount; f++) { FieldType *field = &fields[f]; if (field->localOffset == localOffset) { if (remoteOffset != NULL) { *remoteOffset = field->offset; return S_OK; } return S_FALSE; } } return E_FAIL; } HRESULT StructType::RawAccess(ULONG remoteOffset, PVOID *raw) { *raw = temp + remoteOffset; return S_OK; } HRESULT StructType::Read(ULONG64 address, PVOID local) { HRESULT status = S_OK; ZeroMemory(temp, size); ZeroMemory(local, localSize); EXT_CHECK(g_ExtData->ReadVirtual(address, temp, size, NULL)); for (ULONG f = 0; f < fieldCount; f++) { FieldType *field = &fields[f]; PBYTE pbLocal = ((PBYTE)local) + field->localOffset; PBYTE pbTemp = &temp[field->offset]; switch (field->size) { case 1: *(ULONG64 *)pbLocal = *(BYTE *)pbTemp; break; case 2: *(ULONG64 *)pbLocal = *(USHORT *)pbTemp; break; case 4: *(ULONG64 *)pbLocal = *(ULONG *)pbTemp; break; case 8: *(ULONG64 *)pbLocal = *(ULONG64 *)pbTemp; break; default: #if 0 // We allow bigger sizes, for raw access only. ExtOut("Unknown size: %d, in field %s\n", field->size, field->name); #endif break; } } Exit: return status; } HRESULT StructType::Clear() { HRESULT status = S_OK; ZeroMemory(temp, size); return status; } HRESULT StructType::Update(PVOID local) { HRESULT status = S_OK; for (ULONG f = 0; f < fieldCount; f++) { FieldType *field = &fields[f]; PBYTE pbLocal = ((PBYTE)local) + field->localOffset; PBYTE pbTemp = &temp[field->offset]; switch (field->size) { case 1: *(BYTE *)pbTemp = (BYTE)*(ULONG64 *)pbLocal; break; case 2: *(USHORT *)pbTemp = (USHORT)*(ULONG64 *)pbLocal; break; case 4: *(ULONG *)pbTemp = (ULONG)*(ULONG64 *)pbLocal; break; case 8: *(ULONG64 *)pbTemp = *(ULONG64 *)pbLocal; break; } } return status; } HRESULT StructType::Flush(ULONG64 address) { HRESULT status = S_OK; EXT_CHECK(g_ExtData->WriteVirtual(address, temp, size, NULL)); Exit: return status; } // ///////////////////////////////////////////////////////////////// End of File.