// This function throws an exception that can be caught by the debugger, // instead of allowing the default CRT behavior of invoking Watson to failfast. void __cdecl _SOS_invalid_parameter( const WCHAR * expression, const WCHAR * function, const WCHAR * file, unsigned int line, uintptr_t pReserved ) { ExtErr("\nSOS failure!\n"); throw "SOS failure"; }
extern "C" HRESULT ArchQuery(void) { ULONG targetArchitecture; IMachine* targetMachine = NULL; g_ExtControl->GetExecutingProcessorType(&targetArchitecture); #ifdef SOS_TARGET_AMD64 if(targetArchitecture == IMAGE_FILE_MACHINE_AMD64) { targetMachine = AMD64Machine::GetInstance(); } #endif // SOS_TARGET_AMD64 #ifdef SOS_TARGET_X86 if (targetArchitecture == IMAGE_FILE_MACHINE_I386) { targetMachine = X86Machine::GetInstance(); } #endif // SOS_TARGET_X86 #ifdef SOS_TARGET_ARM if (targetArchitecture == IMAGE_FILE_MACHINE_ARMNT) { targetMachine = ARMMachine::GetInstance(); } #endif // SOS_TARGET_ARM #ifdef SOS_TARGET_ARM64 if (targetArchitecture == IMAGE_FILE_MACHINE_ARM64) { targetMachine = ARM64Machine::GetInstance(); } #endif // SOS_TARGET_ARM64 if (targetMachine == NULL) { g_targetMachine = NULL; ExtErr("SOS does not support the current target architecture.\n"); return E_FAIL; } g_targetMachine = targetMachine; return S_OK; }
STDMETHODIMP EventCallbacks::Exception( THIS_ IN PEXCEPTION_RECORD64 Exception, IN ULONG FirstChance) { g_ResumeState = FALSE; if (Exception->ExceptionCode == STATUS_BREAKPOINT) { if (FirstChance) { DEBUG_VALUE Reg, Ecx, Edx; // Query EIP, EAX and ECX value. if (g_Registers->GetValue(g_EipIndex, &Reg) == S_OK && g_Registers->GetValue(g_EdxIndex, &Edx) == S_OK && g_Registers->GetValue(g_EcxIndex, &Ecx) == S_OK) { char szParam[MAX_PATH]; ULONG ReadedBytes = 0; // Read current instruction opcode value. ZeroMemory(szParam, sizeof(szParam)); HRESULT Hr = g_DataSpaces->ReadVirtual(RegPtrGet(&Reg), &szParam, 1, &ReadedBytes); if (Hr != S_OK) { ExtErr(__FUNCTION__"() ERROR: IDebugDataSpaces::ReadVirtual() fails: %lx\n", Hr); return DEBUG_STATUS_NO_CHANGE; } // Check for int 3 at EIP. if (szParam[0] != '\xCC') { return DEBUG_STATUS_NO_CHANGE; } // Check for the magic engine constnat in EDX. if (Edx.I32 != DBGCB_GET_SYMBOL && Edx.I32 != DBGCB_EXECUTE && Edx.I32 != DBGCB_FIELD_OFFSET) { return DEBUG_STATUS_NO_CHANGE; } g_ResumeState = TRUE; // Read ASCII string with command arguments. ZeroMemory(szParam, sizeof(szParam)); Hr = g_DataSpaces->ReadVirtual(RegPtrGet(&Ecx), &szParam, sizeof(szParam), &ReadedBytes); if (Hr != S_OK) { ExtErr(__FUNCTION__"() ERROR: IDebugDataSpaces::ReadVirtual() fails: %lx\n", Hr); return DEBUG_STATUS_NO_CHANGE; } switch (Edx.I32) { case DBGCB_GET_SYMBOL: { ExtOut("<col fg=\"srccmnt\">" __FUNCTION__"(): DBGCB_GET_SYMBOL \"%s\"</col>\n", szParam); RegPtrSet(&Reg, 0); g_Registers->SetValue(g_EaxIndex, &Reg); Hr = g_Control->Evaluate(szParam, g_RegPtrType, &Reg, NULL); if (Hr == S_OK) { // Return symbol address in EAX. g_Registers->SetValue(g_EaxIndex, &Reg); } else { ExtErr(__FUNCTION__"() WARNING: IDebugControl::Evaluate() fails: %lx\n", Hr); } break; } case DBGCB_EXECUTE: { ExtOut("<col fg=\"srccmnt\">" __FUNCTION__ "(): DBGCB_EXECUTE</col>\n"); // execute debugger command Hr = g_Control->Execute( DEBUG_OUTCTL_ALL_CLIENTS | DEBUG_OUTCTL_AMBIENT_DML, szParam, DEBUG_EXECUTE_DEFAULT ); if (Hr == S_OK) { // Return TRUE in EAX RegPtrSet(&Reg, 1); g_Registers->SetValue(g_EaxIndex, &Reg); } else { ExtErr(__FUNCTION__"() WARNING: IDebugControl::Execute() fails: %lx\n", Hr); } break; } case DBGCB_FIELD_OFFSET: { RegPtrSet(&Reg, (ULONG64)-1); char *lpszModule = szParam, *lpszStruct = NULL, *lpszField = NULL; ExtOut("<col fg=\"srccmnt\">" __FUNCTION__"(): DBGCB_FIELD_OFFSET \"%s\"</col>\n", szParam); // parse structure and field description string if (lpszStruct = strstr(lpszModule, "!")) { *lpszStruct = '\x00'; lpszStruct += 1; if (lpszField = strstr(lpszStruct, "::")) { *lpszField = '\x00'; lpszField += 2; } } if (lpszStruct && lpszField) { // enumerate fields for (ULONG i = 0; ;i++) { ULONG64 Module = 0; ULONG TypeId = 0; // get ID of this symbol Hr = g_Symbols->GetSymbolTypeId(lpszStruct, &TypeId, &Module); if (Hr == S_OK) { char szFieldName[MAX_PATH]; // query name of the filed HRESULT Hr = g_Symbols->GetFieldName(Module, TypeId, i, szFieldName, MAX_PATH, NULL); if (Hr == S_OK) { ULONG Offset = 0, FieldTypeId = 0; // query filed type and offset Hr = g_Symbols->GetFieldTypeAndOffset(Module, TypeId, szFieldName, &FieldTypeId, &Offset); if (Hr == S_OK) { if (!strcmp(szFieldName, lpszField)) { // Return symbol offset in EAX RegPtrSet(&Reg, (ULONG64)Offset); break; } } else { ExtErr(__FUNCTION__"() WARNING: IDebugSymbols3::GetFieldTypeAndOffset() fails: %lx\n", Hr); } } else if (Hr == E_INVALIDARG) { // All Fields done break; } else { ExtErr(__FUNCTION__"() WARNING: IDebugSymbols3::GetFieldName() fails: %lx\n", Hr); } } else { ExtErr(__FUNCTION__"() WARNING: IDebugSymbols3::GetSymbolTypeId() fails: %lx\n", Hr); } } } else { ExtErr(__FUNCTION__"() WARNING: Bad name format (must be <module>!<struct_name>::<field_name>)\n"); } g_Registers->SetValue(g_EaxIndex, &Reg); break; } default: return DEBUG_STATUS_NO_CHANGE; } // Skip current int 3 instruction and continue execution if (g_Registers->GetValue(g_EipIndex, &Reg) == S_OK && Reg.Type == DEBUG_VALUE_INT32) { if (g_bIs64) { Reg.I64 += 1; } else { Reg.I32 += 1; } g_Registers->SetValue(g_EipIndex, &Reg); } return DEBUG_STATUS_GO_HANDLED; } } } return DEBUG_STATUS_NO_CHANGE; }