You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
1346 lines
32 KiB
1346 lines
32 KiB
#include <engexts.h>
|
|
|
|
//----------------------------------------------------------------------------
|
|
//
|
|
// StaticEventCallbacks.
|
|
//
|
|
//----------------------------------------------------------------------------
|
|
|
|
class StaticEventCallbacks : public DebugBaseEventCallbacks
|
|
{
|
|
public:
|
|
// IUnknown.
|
|
STDMETHOD_(ULONG, AddRef)(
|
|
THIS
|
|
);
|
|
STDMETHOD_(ULONG, Release)(
|
|
THIS
|
|
);
|
|
};
|
|
|
|
STDMETHODIMP_(ULONG)
|
|
StaticEventCallbacks::AddRef(
|
|
THIS
|
|
)
|
|
{
|
|
// This class is designed to be static so
|
|
// there's no true refcount.
|
|
return 1;
|
|
}
|
|
|
|
STDMETHODIMP_(ULONG)
|
|
StaticEventCallbacks::Release(
|
|
THIS
|
|
)
|
|
{
|
|
// This class is designed to be static so
|
|
// there's no true refcount.
|
|
return 0;
|
|
}
|
|
|
|
//----------------------------------------------------------------------------
|
|
//
|
|
// ExcepCallbacks.
|
|
//
|
|
//----------------------------------------------------------------------------
|
|
|
|
class ExcepCallbacks : public StaticEventCallbacks
|
|
{
|
|
public:
|
|
ExcepCallbacks(void)
|
|
{
|
|
m_Client = NULL;
|
|
m_Control = NULL;
|
|
}
|
|
|
|
// IDebugEventCallbacks.
|
|
STDMETHOD(GetInterestMask)(
|
|
THIS_
|
|
OUT PULONG Mask
|
|
);
|
|
|
|
STDMETHOD(Exception)(
|
|
THIS_
|
|
IN PEXCEPTION_RECORD64 Exception,
|
|
IN ULONG FirstChance
|
|
);
|
|
|
|
HRESULT Initialize(PDEBUG_CLIENT Client)
|
|
{
|
|
HRESULT Status;
|
|
|
|
m_Client = Client;
|
|
m_Client->AddRef();
|
|
|
|
if ((Status = m_Client->QueryInterface(__uuidof(IDebugControl),
|
|
(void**)&m_Control)) == S_OK)
|
|
{
|
|
// Turn off default breakin on breakpoint exceptions.
|
|
Status = m_Control->Execute(DEBUG_OUTCTL_ALL_CLIENTS,
|
|
"sxd bpe", DEBUG_EXECUTE_DEFAULT);
|
|
}
|
|
|
|
return Status;
|
|
}
|
|
void Uninitialize(void)
|
|
{
|
|
EXT_RELEASE(m_Control);
|
|
EXT_RELEASE(m_Client);
|
|
}
|
|
|
|
private:
|
|
PDEBUG_CLIENT m_Client;
|
|
PDEBUG_CONTROL m_Control;
|
|
};
|
|
|
|
STDMETHODIMP
|
|
ExcepCallbacks::GetInterestMask(
|
|
THIS_
|
|
OUT PULONG Mask
|
|
)
|
|
{
|
|
*Mask = DEBUG_EVENT_EXCEPTION;
|
|
return S_OK;
|
|
}
|
|
|
|
STDMETHODIMP
|
|
ExcepCallbacks::Exception(
|
|
THIS_
|
|
IN PEXCEPTION_RECORD64 Exception,
|
|
IN ULONG FirstChance
|
|
)
|
|
{
|
|
m_Control->Output(DEBUG_OUTPUT_NORMAL, "Exception %X at %p, chance %d\n",
|
|
Exception->ExceptionCode, Exception->ExceptionAddress,
|
|
FirstChance ? 1 : 2);
|
|
return DEBUG_STATUS_GO_HANDLED;
|
|
}
|
|
|
|
ExcepCallbacks g_ExcepCallbacks;
|
|
|
|
//----------------------------------------------------------------------------
|
|
//
|
|
// FnProfCallbacks.
|
|
//
|
|
//----------------------------------------------------------------------------
|
|
|
|
class FnProfCallbacks : public StaticEventCallbacks
|
|
{
|
|
public:
|
|
FnProfCallbacks(void)
|
|
{
|
|
m_Client = NULL;
|
|
m_Control = NULL;
|
|
}
|
|
|
|
// IDebugEventCallbacks.
|
|
STDMETHOD(GetInterestMask)(
|
|
THIS_
|
|
OUT PULONG Mask
|
|
);
|
|
|
|
STDMETHOD(Breakpoint)(
|
|
THIS_
|
|
IN PDEBUG_BREAKPOINT Bp
|
|
);
|
|
|
|
HRESULT Initialize(PDEBUG_CLIENT Client, PDEBUG_CONTROL Control)
|
|
{
|
|
m_Hits = 0;
|
|
|
|
m_Client = Client;
|
|
m_Client->AddRef();
|
|
m_Control = Control;
|
|
m_Control->AddRef();
|
|
|
|
return S_OK;
|
|
}
|
|
void Uninitialize(void)
|
|
{
|
|
EXT_RELEASE(m_Control);
|
|
EXT_RELEASE(m_Client);
|
|
}
|
|
|
|
ULONG GetHits(void)
|
|
{
|
|
return m_Hits;
|
|
}
|
|
PDEBUG_CONTROL GetControl(void)
|
|
{
|
|
return m_Control;
|
|
}
|
|
|
|
private:
|
|
PDEBUG_CLIENT m_Client;
|
|
PDEBUG_CONTROL m_Control;
|
|
ULONG m_Hits;
|
|
};
|
|
|
|
STDMETHODIMP
|
|
FnProfCallbacks::GetInterestMask(
|
|
THIS_
|
|
OUT PULONG Mask
|
|
)
|
|
{
|
|
*Mask = DEBUG_EVENT_BREAKPOINT;
|
|
return S_OK;
|
|
}
|
|
|
|
STDMETHODIMP
|
|
FnProfCallbacks::Breakpoint(
|
|
THIS_
|
|
IN PDEBUG_BREAKPOINT Bp
|
|
)
|
|
{
|
|
PDEBUG_CLIENT Client;
|
|
HRESULT Status = DEBUG_STATUS_NO_CHANGE;
|
|
|
|
// If this is one of our profiling breakpoints
|
|
// record the function hit and continue on.
|
|
if (Bp->GetAdder(&Client) == S_OK)
|
|
{
|
|
if (Client == m_Client)
|
|
{
|
|
m_Hits++;
|
|
Status = DEBUG_STATUS_GO;
|
|
}
|
|
|
|
Client->Release();
|
|
}
|
|
|
|
Bp->Release();
|
|
return Status;
|
|
}
|
|
|
|
FnProfCallbacks g_FnProfCallbacks;
|
|
|
|
//----------------------------------------------------------------------------
|
|
//
|
|
// Extension entry points.
|
|
//
|
|
//----------------------------------------------------------------------------
|
|
|
|
extern "C" HRESULT CALLBACK
|
|
DebugExtensionInitialize(PULONG Version, PULONG Flags)
|
|
{
|
|
*Version = DEBUG_EXTENSION_VERSION(1, 0);
|
|
*Flags = 0;
|
|
return S_OK;
|
|
}
|
|
|
|
extern "C" void CALLBACK
|
|
DebugExtensionUninitialize(void)
|
|
{
|
|
g_ExcepCallbacks.Uninitialize();
|
|
g_FnProfCallbacks.Uninitialize();
|
|
}
|
|
|
|
#if 0
|
|
extern "C" HRESULT CALLBACK
|
|
teb(PDEBUG_CLIENT Client, PCSTR Args)
|
|
{
|
|
HRESULT Status;
|
|
ULONG64 DataOffset;
|
|
|
|
if ((Status = ExtQuery(Client)) != S_OK)
|
|
{
|
|
return Status;
|
|
}
|
|
|
|
if (*Args)
|
|
{
|
|
sscanf(Args, "%I64x", &DataOffset);
|
|
}
|
|
else
|
|
{
|
|
g_ExtSystem->GetCurrentThreadDataOffset(&DataOffset);
|
|
}
|
|
|
|
ExtOut("TEB at %I64x\n", DataOffset);
|
|
|
|
TEB Teb;
|
|
|
|
Status = g_ExtData->ReadVirtual(DataOffset, &Teb, sizeof(Teb), NULL);
|
|
if (Status != S_OK)
|
|
{
|
|
ExtErr("* Unable to read TEB\n");
|
|
}
|
|
else
|
|
{
|
|
ExtOut(" ExceptionList: %x\n", Teb.NtTib.ExceptionList);
|
|
ExtOut(" Stack Base: %x\n", Teb.NtTib.StackBase);
|
|
ExtOut(" Stack Limit: %x\n", Teb.NtTib.StackLimit);
|
|
ExtOut(" SubSystemTib: %x\n", Teb.NtTib.SubSystemTib);
|
|
ExtOut(" FiberData: %x\n", Teb.NtTib.FiberData);
|
|
ExtOut(" ArbitraryUser: %x\n", Teb.NtTib.ArbitraryUserPointer);
|
|
ExtOut(" Self: %x\n", Teb.NtTib.Self);
|
|
ExtOut(" EnvironmentPtr: %x\n", Teb.EnvironmentPointer);
|
|
ExtOut(" ClientId: %x.%x\n",
|
|
Teb.ClientId.UniqueProcess, Teb.ClientId.UniqueThread);
|
|
if (Teb.ClientId.UniqueProcess != Teb.RealClientId.UniqueProcess ||
|
|
Teb.ClientId.UniqueThread != Teb.RealClientId.UniqueThread)
|
|
{
|
|
ExtOut(" Real ClientId: %x.%x\n",
|
|
Teb.RealClientId.UniqueProcess,
|
|
Teb.RealClientId.UniqueThread);
|
|
}
|
|
ExtOut(" Real ClientId: %x.%x\n",
|
|
Teb.RealClientId.UniqueProcess,
|
|
Teb.RealClientId.UniqueThread);
|
|
ExtOut(" RpcHandle: %x\n", Teb.ActiveRpcHandle);
|
|
ExtOut(" Tls Storage: %x\n", Teb.ThreadLocalStoragePointer);
|
|
ExtOut(" PEB Address: %x\n", Teb.ProcessEnvironmentBlock);
|
|
ExtOut(" LastErrorValue: %u\n", Teb.LastErrorValue);
|
|
ExtOut(" LastStatusValue: %x\n", Teb.LastStatusValue);
|
|
ExtOut(" Count Owned Locks:%u\n", Teb.CountOfOwnedCriticalSections);
|
|
ExtOut(" HardErrorMode: %u\n", Teb.HardErrorMode);
|
|
|
|
Status = S_OK;
|
|
}
|
|
|
|
ExtRelease();
|
|
return Status;
|
|
}
|
|
#endif
|
|
|
|
extern "C" HRESULT CALLBACK
|
|
outreg(PDEBUG_CLIENT Client, PCSTR Args)
|
|
{
|
|
HRESULT Status;
|
|
|
|
if ((Status = ExtQuery(Client)) != S_OK)
|
|
{
|
|
return Status;
|
|
}
|
|
|
|
g_ExtRegisters->OutputRegisters(DEBUG_OUTCTL_ALL_CLIENTS,
|
|
DEBUG_REGISTERS_ALL);
|
|
|
|
ExtRelease();
|
|
return Status;
|
|
}
|
|
|
|
extern "C" HRESULT CALLBACK
|
|
enumreg(PDEBUG_CLIENT Client, PCSTR Args)
|
|
{
|
|
HRESULT Status;
|
|
|
|
if ((Status = ExtQuery(Client)) != S_OK)
|
|
{
|
|
return Status;
|
|
}
|
|
|
|
ULONG Num;
|
|
|
|
g_ExtRegisters->GetNumberRegisters(&Num);
|
|
ExtOut("%d registers\n", Num);
|
|
|
|
ULONG i;
|
|
char Name[64];
|
|
DEBUG_REGISTER_DESCRIPTION Desc;
|
|
ULONG Reax, Rebx, Refl, Rsf, Rst0;
|
|
ULONG RegFound = 0;
|
|
|
|
for (i = 0; i < Num; i++)
|
|
{
|
|
g_ExtRegisters->GetDescription(i, Name, sizeof(Name), NULL, &Desc);
|
|
|
|
ExtOut(" %2d: \"%s\", type %d, flags %X\n",
|
|
i, Name, Desc.Type, Desc.Flags);
|
|
if (Desc.Flags & DEBUG_REGISTER_SUB_REGISTER)
|
|
{
|
|
ExtOut(" sub to %d, len %d, mask %I64X, shift %d\n",
|
|
Desc.SubregMaster, Desc.SubregLength,
|
|
Desc.SubregMask, Desc.SubregShift);
|
|
}
|
|
|
|
// XXX drewb - Hack for testing purposes.
|
|
if (!_strcmpi(Name, "eax"))
|
|
{
|
|
Reax = i;
|
|
RegFound++;
|
|
}
|
|
else if (!_strcmpi(Name, "ebx"))
|
|
{
|
|
Rebx = i;
|
|
RegFound++;
|
|
}
|
|
else if (!_strcmpi(Name, "efl"))
|
|
{
|
|
Refl = i;
|
|
RegFound++;
|
|
}
|
|
else if (!_strcmpi(Name, "sf"))
|
|
{
|
|
Rsf = i;
|
|
RegFound++;
|
|
}
|
|
else if (!_strcmpi(Name, "st0"))
|
|
{
|
|
Rst0 = i;
|
|
RegFound++;
|
|
}
|
|
}
|
|
|
|
ULONG ProcType;
|
|
|
|
g_ExtControl->GetExecutingProcessorType(&ProcType);
|
|
ExtOut("Processor type %d\n", ProcType);
|
|
|
|
if (ProcType == IMAGE_FILE_MACHINE_I386)
|
|
{
|
|
DEBUG_VALUE Val;
|
|
DEBUG_VALUE Coerce;
|
|
|
|
if (RegFound != 5)
|
|
{
|
|
ExtErr("** Only found %d registers\n", RegFound);
|
|
}
|
|
|
|
Val.Type = DEBUG_VALUE_INT32;
|
|
Val.I32 = 0x12345678;
|
|
g_ExtRegisters->SetValue(Reax, &Val);
|
|
Val.I32 = 12345678;
|
|
g_ExtRegisters->SetValue(Rst0, &Val);
|
|
g_ExtControl->Execute(DEBUG_OUTCTL_ALL_CLIENTS,
|
|
"r eax,st0", DEBUG_EXECUTE_NOT_LOGGED);
|
|
|
|
Val.Type = DEBUG_VALUE_FLOAT32;
|
|
Val.F32 = 1.2345f;
|
|
g_ExtRegisters->SetValue(Rst0, &Val);
|
|
g_ExtControl->Execute(DEBUG_OUTCTL_ALL_CLIENTS,
|
|
"r st0", DEBUG_EXECUTE_NOT_LOGGED);
|
|
g_ExtRegisters->GetValue(Rst0, &Val);
|
|
ExtOut("st0 type is %d\n", Val.Type);
|
|
|
|
g_ExtControl->CoerceValue(&Val, DEBUG_VALUE_FLOAT32, &Coerce);
|
|
Coerce.F32 *= 2.0f;
|
|
ExtOut("coerce type is %d, val*2 %hf\n", Coerce.Type, Coerce.F32);
|
|
|
|
g_ExtRegisters->SetValue(Reax, &Val);
|
|
g_ExtRegisters->SetValue(Rebx, &Coerce);
|
|
g_ExtControl->Execute(DEBUG_OUTCTL_ALL_CLIENTS,
|
|
"r eax,ebx", DEBUG_EXECUTE_NOT_LOGGED);
|
|
|
|
g_ExtControl->Execute(DEBUG_OUTCTL_ALL_CLIENTS,
|
|
"r efl", DEBUG_EXECUTE_NOT_LOGGED);
|
|
g_ExtRegisters->GetValue(Rsf, &Val);
|
|
ExtOut("sf type is %d, val %d\n", Val.Type, Val.I32);
|
|
Val.I32 ^= 1;
|
|
g_ExtRegisters->SetValue(Rsf, &Val);
|
|
g_ExtControl->Execute(DEBUG_OUTCTL_ALL_CLIENTS,
|
|
"r efl", DEBUG_EXECUTE_NOT_LOGGED);
|
|
g_ExtRegisters->GetValue(Rsf, &Val);
|
|
ExtOut("sf type is %d, val %d\n", Val.Type, Val.I32);
|
|
Val.I32 ^= 1;
|
|
g_ExtRegisters->SetValue(Rsf, &Val);
|
|
g_ExtControl->Execute(DEBUG_OUTCTL_ALL_CLIENTS,
|
|
"r efl", DEBUG_EXECUTE_NOT_LOGGED);
|
|
}
|
|
|
|
ExtRelease();
|
|
return Status;
|
|
}
|
|
|
|
extern "C" HRESULT CALLBACK
|
|
symnear(PDEBUG_CLIENT Client, PCSTR Args)
|
|
{
|
|
HRESULT Status;
|
|
|
|
if ((Status = ExtQuery(Client)) != S_OK)
|
|
{
|
|
return Status;
|
|
}
|
|
|
|
LONG Delta;
|
|
|
|
Delta = 0;
|
|
sscanf(Args, "%d", &Delta);
|
|
|
|
ULONG64 Instr;
|
|
char Name[128];
|
|
ULONG64 Disp;
|
|
|
|
g_ExtRegisters->GetInstructionOffset(&Instr);
|
|
if (g_ExtSymbols->GetNearNameByOffset(Instr, Delta,
|
|
Name, sizeof(Name), NULL,
|
|
&Disp) == S_OK)
|
|
{
|
|
ExtOut("Symbol %d away from %p is:\n %s + 0x%I64x\n",
|
|
Delta, Instr, Name, Disp);
|
|
|
|
if (g_ExtSymbols->GetOffsetByName(Name, &Instr) == S_OK)
|
|
{
|
|
ExtOut("Symbol %s has offset %p\n", Name, Instr);
|
|
}
|
|
else
|
|
{
|
|
ExtOut("Symbol %s has no offset\n", Name);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
ExtOut("No symbol %d away from %p\n", Delta, Instr);
|
|
}
|
|
|
|
ExtRelease();
|
|
return Status;
|
|
}
|
|
|
|
extern "C" HRESULT CALLBACK
|
|
symname(PDEBUG_CLIENT Client, PCSTR Args)
|
|
{
|
|
HRESULT Status;
|
|
|
|
if ((Status = ExtQuery(Client)) != S_OK)
|
|
{
|
|
return Status;
|
|
}
|
|
|
|
ULONG64 Offs;
|
|
|
|
if (g_ExtSymbols->GetOffsetByName(Args, &Offs) == S_OK)
|
|
{
|
|
ExtOut("Symbol %s has offset %I64x\n",
|
|
Args, Offs);
|
|
}
|
|
else
|
|
{
|
|
ExtOut("Symbol %s has no offset\n", Args);
|
|
}
|
|
|
|
ExtRelease();
|
|
return Status;
|
|
}
|
|
|
|
extern "C" HRESULT CALLBACK
|
|
line(PDEBUG_CLIENT Client, PCSTR Args)
|
|
{
|
|
HRESULT Status;
|
|
|
|
if ((Status = ExtQuery(Client)) != S_OK)
|
|
{
|
|
return Status;
|
|
}
|
|
|
|
ULONG64 Instr;
|
|
ULONG Line;
|
|
char File[128];
|
|
ULONG64 Disp;
|
|
|
|
g_ExtRegisters->GetInstructionOffset(&Instr);
|
|
if (g_ExtSymbols->GetLineByOffset(Instr, &Line,
|
|
File, sizeof(File), NULL, &Disp) == S_OK)
|
|
{
|
|
ExtOut("Line at %p is:\n %s(%d) + 0x%I64x\n",
|
|
Instr, File, Line, Disp);
|
|
|
|
if (g_ExtSymbols->GetOffsetByLine(Line, File, &Instr) == S_OK)
|
|
{
|
|
ExtOut("Line %s(%d) has offset %p\n", File, Line, Instr);
|
|
}
|
|
else
|
|
{
|
|
ExtOut("Line %s(%d) has no offset\n", File, Line);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
ExtOut("No line information for %p\n", Instr);
|
|
}
|
|
|
|
ExtRelease();
|
|
return Status;
|
|
}
|
|
|
|
extern "C" HRESULT CALLBACK
|
|
sympat(PDEBUG_CLIENT Client, PCSTR Args)
|
|
{
|
|
HRESULT Status;
|
|
|
|
if ((Status = ExtQuery(Client)) != S_OK)
|
|
{
|
|
return Status;
|
|
}
|
|
|
|
ULONG64 Match;
|
|
char Name[128];
|
|
ULONG64 Offset;
|
|
PCSTR Pattern;
|
|
|
|
while (*Args == ' ' || *Args == '\t')
|
|
{
|
|
Args++;
|
|
}
|
|
if (*Args)
|
|
{
|
|
Pattern = Args;
|
|
}
|
|
else
|
|
{
|
|
Pattern = "*";
|
|
}
|
|
|
|
Status = g_ExtSymbols->StartSymbolMatch(Pattern, &Match);
|
|
if (Status != S_OK)
|
|
{
|
|
ExtErr("Unable to match on '%s'\n", Pattern);
|
|
}
|
|
else
|
|
{
|
|
for (;;)
|
|
{
|
|
Status = g_ExtSymbols->
|
|
GetNextSymbolMatch(Match, Name, sizeof(Name), NULL, &Offset);
|
|
if (Status != S_OK)
|
|
{
|
|
break;
|
|
}
|
|
|
|
ExtOut("%p - %s\n", Offset, Name);
|
|
|
|
if (g_ExtControl->GetInterrupt() == S_OK)
|
|
{
|
|
ExtOut("** interrupt\n");
|
|
break;
|
|
}
|
|
}
|
|
|
|
g_ExtSymbols->EndSymbolMatch(Match);
|
|
}
|
|
|
|
ExtRelease();
|
|
return Status;
|
|
}
|
|
|
|
extern "C" HRESULT CALLBACK
|
|
stack(PDEBUG_CLIENT Client, PCSTR Args)
|
|
{
|
|
HRESULT Status;
|
|
|
|
if ((Status = ExtQuery(Client)) != S_OK)
|
|
{
|
|
return Status;
|
|
}
|
|
|
|
ULONG Flags;
|
|
|
|
while (*Args == ' ' || *Args == '\t')
|
|
{
|
|
Args++;
|
|
}
|
|
if (*Args)
|
|
{
|
|
sscanf(Args, "%d", &Flags);
|
|
}
|
|
else
|
|
{
|
|
Flags = 0;
|
|
}
|
|
|
|
DEBUG_STACK_FRAME Frames[4];
|
|
ULONG64 FrameOff, StackOff, InstrOff;
|
|
ULONG Filled;
|
|
|
|
g_ExtRegisters->GetFrameOffset(&FrameOff);
|
|
g_ExtRegisters->GetStackOffset(&StackOff);
|
|
g_ExtRegisters->GetInstructionOffset(&InstrOff);
|
|
|
|
if (g_ExtControl->GetStackTrace(FrameOff, StackOff, InstrOff,
|
|
Frames, sizeof(Frames) / sizeof(Frames[0]),
|
|
&Filled) != S_OK)
|
|
{
|
|
ExtErr("Unable to get stack trace\n");
|
|
}
|
|
else
|
|
{
|
|
ExtOut("Filled %d frames at %p\n", Filled, InstrOff);
|
|
g_ExtControl->OutputStackTrace(DEBUG_OUTCTL_ALL_CLIENTS,
|
|
Frames, Filled, Flags);
|
|
}
|
|
|
|
ExtOut("\nDirect:\n");
|
|
g_ExtControl->OutputStackTrace(DEBUG_OUTCTL_ALL_CLIENTS,
|
|
NULL, 20, Flags);
|
|
|
|
ExtRelease();
|
|
return Status;
|
|
}
|
|
|
|
extern "C" HRESULT CALLBACK
|
|
tyid(PDEBUG_CLIENT Client, PCSTR Args)
|
|
{
|
|
HRESULT Status;
|
|
|
|
if ((Status = ExtQuery(Client)) != S_OK)
|
|
{
|
|
return Status;
|
|
}
|
|
|
|
ULONG TypeId;
|
|
char Type[256];
|
|
ULONG TypeSize;
|
|
ULONG64 Module;
|
|
|
|
while (*Args == ' ' || *Args == '\t')
|
|
{
|
|
Args++;
|
|
}
|
|
if (*Args >= '0' && *Args <= '9')
|
|
{
|
|
DEBUG_VALUE IntVal;
|
|
|
|
g_ExtControl->Evaluate(Args, DEBUG_VALUE_INT64, &IntVal, NULL);
|
|
|
|
Status = g_ExtSymbols->GetOffsetTypeId(IntVal.I64, &TypeId, &Module);
|
|
}
|
|
else
|
|
{
|
|
Status = g_ExtSymbols->GetSymbolTypeId(Args, &TypeId, &Module);
|
|
}
|
|
|
|
if (Status == S_OK)
|
|
{
|
|
ExtOut("Type ID of '%s' is %d\n", Args, TypeId);
|
|
}
|
|
else
|
|
{
|
|
ExtErr("Unable to get type ID, %X\n", Status);
|
|
}
|
|
|
|
ExtRelease();
|
|
return Status;
|
|
}
|
|
|
|
extern "C" HRESULT CALLBACK
|
|
typeof(PDEBUG_CLIENT Client, PCSTR Args)
|
|
{
|
|
HRESULT Status;
|
|
|
|
if ((Status = ExtQuery(Client)) != S_OK)
|
|
{
|
|
return Status;
|
|
}
|
|
|
|
ULONG TypeId;
|
|
char Type[256];
|
|
ULONG TypeSize;
|
|
ULONG64 Module;
|
|
|
|
while (*Args == ' ' || *Args == '\t')
|
|
{
|
|
Args++;
|
|
}
|
|
if (*Args >= '0' && *Args <= '9')
|
|
{
|
|
DEBUG_VALUE IntVal;
|
|
|
|
g_ExtControl->Evaluate(Args, DEBUG_VALUE_INT64, &IntVal, NULL);
|
|
|
|
Status = g_ExtSymbols->GetOffsetTypeId(IntVal.I64, &TypeId, &Module);
|
|
}
|
|
else
|
|
{
|
|
Status = g_ExtSymbols->GetSymbolTypeId(Args, &TypeId, &Module);
|
|
}
|
|
if (Status == S_OK)
|
|
{
|
|
Status = g_ExtSymbols->GetTypeName(Module, TypeId, Type, sizeof(Type),
|
|
&TypeSize);
|
|
}
|
|
|
|
if (Status == S_OK)
|
|
{
|
|
ExtOut("Type of '%s' is '%s':%d (%d chars)\n",
|
|
Args, Type, TypeId, TypeSize);
|
|
}
|
|
else
|
|
{
|
|
ExtErr("Unable to get type, %X\n", Status);
|
|
}
|
|
|
|
ExtRelease();
|
|
return Status;
|
|
}
|
|
|
|
extern "C" HRESULT CALLBACK
|
|
tsizeof(PDEBUG_CLIENT Client, PCSTR Args)
|
|
{
|
|
HRESULT Status;
|
|
|
|
if ((Status = ExtQuery(Client)) != S_OK)
|
|
{
|
|
return Status;
|
|
}
|
|
|
|
PCSTR TypeName;
|
|
ULONG TypeId;
|
|
ULONG TypeSize;
|
|
|
|
while (*Args == ' ' || *Args == '\t')
|
|
{
|
|
Args++;
|
|
}
|
|
|
|
TypeName = strchr(Args, '!');
|
|
if (TypeName == NULL)
|
|
{
|
|
ExtErr("Must specify Module!Type\n");
|
|
Status = E_INVALIDARG;
|
|
}
|
|
else
|
|
{
|
|
ULONG64 Module;
|
|
|
|
Status = g_ExtSymbols->GetSymbolModule(Args, &Module);
|
|
if (Status == S_OK)
|
|
{
|
|
Status = g_ExtSymbols->GetTypeId(Module, TypeName, &TypeId);
|
|
}
|
|
if (Status == S_OK)
|
|
{
|
|
Status = g_ExtSymbols->GetTypeSize(Module, TypeId, &TypeSize);
|
|
}
|
|
|
|
if (Status == S_OK)
|
|
{
|
|
ExtOut("Type '%s':%d is %d bytes\n",
|
|
Args, TypeId, TypeSize);
|
|
}
|
|
else
|
|
{
|
|
ExtErr("Unable to get type size, %X\n", Status);
|
|
}
|
|
}
|
|
|
|
ExtRelease();
|
|
return Status;
|
|
}
|
|
|
|
extern "C" HRESULT CALLBACK
|
|
foff(PDEBUG_CLIENT Client, PCSTR Args)
|
|
{
|
|
HRESULT Status;
|
|
|
|
if ((Status = ExtQuery(Client)) != S_OK)
|
|
{
|
|
return Status;
|
|
}
|
|
|
|
ULONG TypeId;
|
|
char Type[256];
|
|
PCSTR Bang, Dot;
|
|
ULONG Offset;
|
|
|
|
while (*Args == ' ' || *Args == '\t')
|
|
{
|
|
Args++;
|
|
}
|
|
Bang = strchr(Args, '!');
|
|
if (Bang != NULL)
|
|
{
|
|
Dot = strchr(Bang + 1, '.');
|
|
}
|
|
if (Bang == NULL || Dot == NULL)
|
|
{
|
|
ExtErr("Syntax is Module!Type.Field\n");
|
|
Status = E_INVALIDARG;
|
|
}
|
|
else
|
|
{
|
|
ULONG64 Module;
|
|
|
|
memcpy(Type, Bang + 1, Dot - (Bang + 1));
|
|
Type[Dot - (Bang + 1)] = 0;
|
|
Dot++;
|
|
|
|
Status = g_ExtSymbols->GetSymbolModule(Args, &Module);
|
|
if (Status == S_OK)
|
|
{
|
|
Status = g_ExtSymbols->GetTypeId(Module, Type, &TypeId);
|
|
}
|
|
if (Status == S_OK)
|
|
{
|
|
Status = g_ExtSymbols->GetFieldOffset(Module, TypeId, Dot,
|
|
&Offset);
|
|
}
|
|
|
|
if (Status == S_OK)
|
|
{
|
|
ExtOut("Offset of %s is %d bytes\n",
|
|
Args, Offset);
|
|
}
|
|
else
|
|
{
|
|
ExtErr("Unable to get field offset, %X\n", Status);
|
|
}
|
|
}
|
|
|
|
ExtRelease();
|
|
return Status;
|
|
}
|
|
|
|
extern "C" HRESULT CALLBACK
|
|
otype(PDEBUG_CLIENT Client, PCSTR Args)
|
|
{
|
|
HRESULT Status;
|
|
|
|
if ((Status = ExtQuery(Client)) != S_OK)
|
|
{
|
|
return Status;
|
|
}
|
|
|
|
ULONG TypeId;
|
|
char Type[256];
|
|
PCSTR Bang, Space;
|
|
|
|
while (*Args == ' ' || *Args == '\t')
|
|
{
|
|
Args++;
|
|
}
|
|
Bang = strchr(Args, '!');
|
|
if (Bang != NULL)
|
|
{
|
|
Space = strchr(Bang + 1, ' ');
|
|
}
|
|
if (Bang == NULL || Space == NULL)
|
|
{
|
|
ExtErr("Syntax is Module!Type Address\n");
|
|
Status = E_INVALIDARG;
|
|
}
|
|
else
|
|
{
|
|
memcpy(Type, Bang + 1, Space - (Bang + 1));
|
|
Type[Space - (Bang + 1)] = 0;
|
|
Space++;
|
|
|
|
ULONG64 Module;
|
|
ULONG Flags = DEBUG_OUTTYPE_RECURSION_LEVEL(15);
|
|
DEBUG_VALUE IntVal;
|
|
|
|
g_ExtControl->Evaluate(Space, DEBUG_VALUE_INT64, &IntVal, NULL);
|
|
|
|
Status = g_ExtSymbols->GetSymbolModule(Args, &Module);
|
|
if (Status == S_OK)
|
|
{
|
|
Status = g_ExtSymbols->GetTypeId(Module, Type, &TypeId);
|
|
}
|
|
if (Status == S_OK)
|
|
{
|
|
Status = g_ExtSymbols->
|
|
OutputTypedDataVirtual(DEBUG_OUTCTL_ALL_CLIENTS,
|
|
IntVal.I64, Module, TypeId, Flags);
|
|
if (Status != S_OK)
|
|
{
|
|
ExtErr("Unable to output data, %X\n", Status);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
ExtErr("Unable to get type ID, %X\n", Status);
|
|
}
|
|
}
|
|
|
|
ExtRelease();
|
|
return Status;
|
|
}
|
|
|
|
extern "C" HRESULT CALLBACK
|
|
vsearch(PDEBUG_CLIENT Client, PCSTR Args)
|
|
{
|
|
HRESULT Status;
|
|
|
|
if ((Status = ExtQuery(Client)) != S_OK)
|
|
{
|
|
return Status;
|
|
}
|
|
|
|
ULONG Start = 0, Len = 0;
|
|
ULONG Chars;
|
|
|
|
sscanf(Args, "%x %x%n", &Start, &Len, &Chars);
|
|
if (Start == 0 || Len == 0)
|
|
{
|
|
ExtErr("Syntax is Start Len Byte+\n");
|
|
Status = E_INVALIDARG;
|
|
}
|
|
else
|
|
{
|
|
UCHAR Pattern[32];
|
|
ULONG PatLen;
|
|
|
|
Args += Chars;
|
|
PatLen = 0;
|
|
for (;;)
|
|
{
|
|
while (*Args == ' ' || *Args == '\t')
|
|
{
|
|
Args++;
|
|
}
|
|
|
|
if (*Args == 0)
|
|
{
|
|
break;
|
|
}
|
|
|
|
sscanf(Args, "%x", &Pattern[PatLen]);
|
|
PatLen++;
|
|
|
|
while (*Args != 0 && *Args != ' ' && *Args != '\t')
|
|
{
|
|
Args++;
|
|
}
|
|
}
|
|
|
|
ULONG64 Match;
|
|
|
|
Status = g_ExtData->SearchVirtual(Start, Len, Pattern, PatLen, 1,
|
|
&Match);
|
|
if (Status == S_OK)
|
|
{
|
|
ExtOut("Match at %p\n", Match);
|
|
}
|
|
else
|
|
{
|
|
ExtErr("Search failed, 0x%X\n", Status);
|
|
}
|
|
}
|
|
|
|
ExtRelease();
|
|
return Status;
|
|
}
|
|
|
|
extern "C" HRESULT CALLBACK
|
|
vread(PDEBUG_CLIENT Client, PCSTR Args)
|
|
{
|
|
HRESULT Status;
|
|
|
|
if ((Status = ExtQuery(Client)) != S_OK)
|
|
{
|
|
return Status;
|
|
}
|
|
|
|
ULONG Start = 0, Len = 0;
|
|
|
|
sscanf(Args, "%x %x", &Start, &Len);
|
|
if (Start == 0 || Len == 0)
|
|
{
|
|
ExtErr("Syntax is Start Len\n");
|
|
Status = E_INVALIDARG;
|
|
}
|
|
else
|
|
{
|
|
UCHAR Buffer[16384];
|
|
ULONG Read;
|
|
|
|
if (Len > sizeof(Buffer))
|
|
{
|
|
ExtWarn("Buffer is only %X bytes, clamping\n", sizeof(Buffer));
|
|
Len = sizeof(Buffer);
|
|
}
|
|
|
|
Status = g_ExtData->ReadVirtual(Start, Buffer, Len, &Read);
|
|
if (Status == S_OK)
|
|
{
|
|
ExtOut("Read %X bytes\n", Read);
|
|
}
|
|
else
|
|
{
|
|
ExtErr("Read failed, 0x%X\n", Status);
|
|
}
|
|
}
|
|
|
|
ExtRelease();
|
|
return Status;
|
|
}
|
|
|
|
extern "C" HRESULT CALLBACK
|
|
watch(PDEBUG_CLIENT Client, PCSTR Args)
|
|
{
|
|
HRESULT Status;
|
|
PDEBUG_CLIENT Watcher = NULL;
|
|
|
|
if ((Status = Client->CreateClient(&Watcher)) != S_OK)
|
|
{
|
|
goto Exit;
|
|
}
|
|
|
|
if ((Status = Watcher->SetEventCallbacks(&g_ExcepCallbacks)) != S_OK)
|
|
{
|
|
goto Exit;
|
|
}
|
|
|
|
g_ExcepCallbacks.Uninitialize();
|
|
Status = g_ExcepCallbacks.Initialize(Watcher);
|
|
|
|
Exit:
|
|
EXT_RELEASE(Watcher);
|
|
if (Status != S_OK)
|
|
{
|
|
ExtErr("Unable to watch, 0x%X\n", Status);
|
|
g_ExcepCallbacks.Uninitialize();
|
|
}
|
|
|
|
return Status;
|
|
}
|
|
|
|
extern "C" HRESULT CALLBACK
|
|
fnprof(PDEBUG_CLIENT Client, PCSTR Args)
|
|
{
|
|
HRESULT Status;
|
|
PDEBUG_CLIENT Profiler = NULL;
|
|
PDEBUG_CONTROL ProfCtrl = NULL;
|
|
PDEBUG_BREAKPOINT Bp = NULL;
|
|
static ULONG s_BpId = DEBUG_ANY_ID;
|
|
|
|
if ((Status = ExtQuery(Client)) != S_OK)
|
|
{
|
|
return Status;
|
|
}
|
|
|
|
while (*Args == ' ' || *Args == '\t')
|
|
{
|
|
Args++;
|
|
}
|
|
if (!*Args)
|
|
{
|
|
goto Exit;
|
|
}
|
|
|
|
if (!_strcmpi(Args, "-end"))
|
|
{
|
|
ULONG64 Offset;
|
|
char OffsetExpr[512];
|
|
|
|
if (s_BpId == DEBUG_ANY_ID)
|
|
{
|
|
Status = E_UNEXPECTED;
|
|
goto Exit;
|
|
}
|
|
|
|
if ((Status = g_FnProfCallbacks.GetControl()->
|
|
GetBreakpointById(s_BpId, &Bp)) != S_OK)
|
|
{
|
|
goto Exit;
|
|
}
|
|
|
|
if ((Status = Bp->GetOffset(&Offset)) != S_OK)
|
|
{
|
|
Offset = DEBUG_INVALID_OFFSET;
|
|
}
|
|
if ((Status = Bp->GetOffsetExpression(OffsetExpr,
|
|
sizeof(OffsetExpr),
|
|
NULL)) != S_OK)
|
|
{
|
|
goto Exit;
|
|
}
|
|
|
|
ExtOut("%s ", OffsetExpr);
|
|
if (Offset != DEBUG_INVALID_OFFSET)
|
|
{
|
|
ExtOut("(%p) ", Offset);
|
|
}
|
|
ExtOut("was hit %d times\n", g_FnProfCallbacks.GetHits());
|
|
|
|
g_FnProfCallbacks.GetControl()->RemoveBreakpoint(Bp);
|
|
Bp = NULL;
|
|
s_BpId = DEBUG_ANY_ID;
|
|
g_FnProfCallbacks.Uninitialize();
|
|
}
|
|
else
|
|
{
|
|
if (s_BpId != DEBUG_ANY_ID)
|
|
{
|
|
Status = E_UNEXPECTED;
|
|
goto Exit;
|
|
}
|
|
|
|
if ((Status = Client->CreateClient(&Profiler)) != S_OK)
|
|
{
|
|
goto Exit;
|
|
}
|
|
|
|
if ((Status = Profiler->SetEventCallbacks(&g_FnProfCallbacks)) != S_OK)
|
|
{
|
|
goto Exit;
|
|
}
|
|
|
|
if ((Status = Profiler->QueryInterface(__uuidof(IDebugControl),
|
|
(void **)&ProfCtrl)) != S_OK)
|
|
{
|
|
goto Exit;
|
|
}
|
|
|
|
if ((Status = ProfCtrl->AddBreakpoint(DEBUG_BREAKPOINT_CODE,
|
|
DEBUG_ANY_ID, &Bp)) != S_OK)
|
|
{
|
|
goto Exit;
|
|
}
|
|
|
|
if ((Status = Bp->SetOffsetExpression(Args)) != S_OK)
|
|
{
|
|
goto Exit;
|
|
}
|
|
|
|
if ((Status = Bp->AddFlags(DEBUG_BREAKPOINT_ADDER_ONLY |
|
|
DEBUG_BREAKPOINT_ENABLED)) != S_OK)
|
|
{
|
|
goto Exit;
|
|
}
|
|
|
|
if ((Status = Bp->GetId(&s_BpId)) != S_OK)
|
|
{
|
|
goto Exit;
|
|
}
|
|
|
|
g_FnProfCallbacks.Uninitialize();
|
|
if ((Status = g_FnProfCallbacks.Initialize(Profiler,
|
|
ProfCtrl)) != S_OK)
|
|
{
|
|
goto Exit;
|
|
}
|
|
|
|
ExtOut("Added breakpoint %d on %s\n", s_BpId, Args);
|
|
Bp = NULL;
|
|
}
|
|
|
|
Exit:
|
|
if (Bp != NULL)
|
|
{
|
|
if (ProfCtrl != NULL)
|
|
{
|
|
ProfCtrl->RemoveBreakpoint(Bp);
|
|
}
|
|
else
|
|
{
|
|
Bp->Release();
|
|
}
|
|
}
|
|
EXT_RELEASE(ProfCtrl);
|
|
EXT_RELEASE(Profiler);
|
|
if (Status != S_OK)
|
|
{
|
|
ExtErr("Unable to profile, 0x%X\n", Status);
|
|
g_FnProfCallbacks.Uninitialize();
|
|
}
|
|
|
|
ExtRelease();
|
|
return Status;
|
|
}
|
|
|
|
extern "C" HRESULT CALLBACK
|
|
vtrans(PDEBUG_CLIENT Client, PCSTR Args)
|
|
{
|
|
HRESULT Status;
|
|
|
|
if ((Status = ExtQuery(Client)) != S_OK)
|
|
{
|
|
return Status;
|
|
}
|
|
|
|
if (g_ExtData2 != NULL)
|
|
{
|
|
ULONG64 PhysOffs[8];
|
|
ULONG Levels;
|
|
DEBUG_VALUE Virt;
|
|
|
|
if ((Status = g_ExtControl->
|
|
Evaluate(Args, DEBUG_VALUE_INT64, &Virt, NULL)) == S_OK)
|
|
{
|
|
Status = g_ExtData2->
|
|
GetVirtualTranslationPhysicalOffsets(Virt.I64, PhysOffs,
|
|
sizeof(PhysOffs) /
|
|
sizeof(PhysOffs[0]),
|
|
&Levels);
|
|
if (SUCCEEDED(Status))
|
|
{
|
|
ULONG i;
|
|
|
|
ExtOut("%I64X translates in %d levels:\n",
|
|
Virt.I64, Levels);
|
|
for (i = 0; i < Levels; i++)
|
|
{
|
|
ExtOut(" %I64X\n", PhysOffs[i]);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
ExtErr("Unable to translate %I64X, 0x%X\n",
|
|
Virt.I64, Status);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
ExtErr("Unable to evaluate '%s', 0x%X\n", Args, Status);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
ExtErr("Debugger does not support IDebugDataSpaces2\n");
|
|
}
|
|
|
|
ExtRelease();
|
|
return Status;
|
|
}
|
|
|
|
extern "C" HRESULT CALLBACK
|
|
enummod(PDEBUG_CLIENT Client, PCSTR Args)
|
|
{
|
|
HRESULT Status;
|
|
|
|
if ((Status = ExtQuery(Client)) != S_OK)
|
|
{
|
|
return Status;
|
|
}
|
|
|
|
ULONG Num[2];
|
|
ULONG Type, i, Index;
|
|
DEBUG_MODULE_PARAMETERS Params;
|
|
|
|
if ((Status = g_ExtSymbols->GetNumberModules(&Num[0],
|
|
&Num[1])) != S_OK)
|
|
{
|
|
ExtErr("GetNumberModules failed, 0x%X\n", Status);
|
|
goto Exit;
|
|
}
|
|
|
|
ExtOut("%d modules, %d unloaded modules\n", Num[0], Num[1]);
|
|
|
|
Index = -1;
|
|
for (Type = 0; Type < 2; Type++)
|
|
{
|
|
if (!Num[Type])
|
|
{
|
|
continue;
|
|
}
|
|
|
|
switch(Type)
|
|
{
|
|
case 0:
|
|
ExtOut("Loaded:\n");
|
|
ExtOut("-------\n");
|
|
break;
|
|
case 1:
|
|
ExtOut("Unloaded:\n");
|
|
ExtOut("---------\n");
|
|
break;
|
|
}
|
|
|
|
for (i = 0; i < Num[Type]; i++)
|
|
{
|
|
if ((Status = g_ExtSymbols->
|
|
GetModuleParameters(1, NULL, ++Index, &Params)) != S_OK)
|
|
{
|
|
ExtErr(" GetModuleParameters failed, 0x%X\n", Status);
|
|
continue;
|
|
}
|
|
|
|
ExtOut(" Base %p, size %08x\n", Params.Base, Params.Size);
|
|
ExtOut(" Flags %08x\n", Params.Flags);
|
|
}
|
|
}
|
|
|
|
Exit:
|
|
ExtRelease();
|
|
return Status;
|
|
}
|