singrdk/base/Windows/singx86/singx86.cpp

600 lines
15 KiB
C++

/////////////////////////////////////////////////////////////////////////////
//
// singx86.cpp - Singularity Debugger Extension.
//
// Copyright (c) Microsoft Corporation. All rights reserved.
//
// For more information, see http://ddkslingshot/webs/debugexw/
//
#include "singx86.h"
#include <strsafe.h>
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.