mirror of https://github.com/tongzx/nt5src
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.
5306 lines
128 KiB
5306 lines
128 KiB
//----------------------------------------------------------------------------
|
|
//
|
|
// IDebugSymbols implementation.
|
|
//
|
|
// Copyright (C) Microsoft Corporation, 1999-2001.
|
|
//
|
|
//----------------------------------------------------------------------------
|
|
|
|
#include "ntsdp.hpp"
|
|
|
|
// Special type status value that maps to E_UNEXPECTED.
|
|
#define TYPE_E_UNEXPECTED 0xfefefefe
|
|
|
|
BOOL
|
|
GetModuleName(
|
|
ULONG64 Base,
|
|
PCHAR Name,
|
|
ULONG SizeOfName
|
|
);
|
|
|
|
//#define DBG_SYMGROUP_ENABLED 1
|
|
|
|
HRESULT
|
|
ResultFromTypeStatus(ULONG Status)
|
|
{
|
|
switch(Status)
|
|
{
|
|
case NO_ERROR:
|
|
return S_OK;
|
|
|
|
case MEMORY_READ_ERROR:
|
|
case EXIT_ON_CONTROLC:
|
|
return E_FAIL;
|
|
|
|
case SYMBOL_TYPE_INDEX_NOT_FOUND:
|
|
case SYMBOL_TYPE_INFO_NOT_FOUND:
|
|
return E_NOINTERFACE;
|
|
|
|
case FIELDS_DID_NOT_MATCH:
|
|
case NULL_SYM_DUMP_PARAM:
|
|
case NULL_FIELD_NAME:
|
|
case INCORRECT_VERSION_INFO:
|
|
return E_INVALIDARG;
|
|
|
|
case CANNOT_ALLOCATE_MEMORY:
|
|
case INSUFFICIENT_SPACE_TO_COPY:
|
|
return E_OUTOFMEMORY;
|
|
|
|
case TYPE_E_UNEXPECTED:
|
|
return E_UNEXPECTED;
|
|
}
|
|
|
|
return E_FAIL;
|
|
}
|
|
|
|
STDMETHODIMP
|
|
DebugClient::GetSymbolOptions(
|
|
THIS_
|
|
OUT PULONG Options
|
|
)
|
|
{
|
|
ENTER_ENGINE();
|
|
|
|
*Options = g_SymOptions;
|
|
|
|
LEAVE_ENGINE();
|
|
return S_OK;
|
|
}
|
|
|
|
#define ALL_SYMBOL_OPTIONS \
|
|
(SYMOPT_CASE_INSENSITIVE | \
|
|
SYMOPT_UNDNAME | \
|
|
SYMOPT_DEFERRED_LOADS | \
|
|
SYMOPT_NO_CPP | \
|
|
SYMOPT_LOAD_LINES | \
|
|
SYMOPT_OMAP_FIND_NEAREST | \
|
|
SYMOPT_LOAD_ANYTHING | \
|
|
SYMOPT_IGNORE_CVREC | \
|
|
SYMOPT_NO_UNQUALIFIED_LOADS | \
|
|
SYMOPT_FAIL_CRITICAL_ERRORS | \
|
|
SYMOPT_EXACT_SYMBOLS | \
|
|
SYMOPT_DEBUG)
|
|
|
|
STDMETHODIMP
|
|
DebugClient::AddSymbolOptions(
|
|
THIS_
|
|
IN ULONG Options
|
|
)
|
|
{
|
|
if (Options & ~ALL_SYMBOL_OPTIONS)
|
|
{
|
|
return E_INVALIDARG;
|
|
}
|
|
|
|
ENTER_ENGINE();
|
|
|
|
SetSymOptions(g_SymOptions | Options);
|
|
|
|
LEAVE_ENGINE();
|
|
return S_OK;
|
|
}
|
|
|
|
STDMETHODIMP
|
|
DebugClient::RemoveSymbolOptions(
|
|
THIS_
|
|
IN ULONG Options
|
|
)
|
|
{
|
|
if (Options & ~ALL_SYMBOL_OPTIONS)
|
|
{
|
|
return E_INVALIDARG;
|
|
}
|
|
|
|
ENTER_ENGINE();
|
|
|
|
SetSymOptions(g_SymOptions & ~Options);
|
|
|
|
LEAVE_ENGINE();
|
|
return S_OK;
|
|
}
|
|
|
|
STDMETHODIMP
|
|
DebugClient::SetSymbolOptions(
|
|
THIS_
|
|
IN ULONG Options
|
|
)
|
|
{
|
|
if (Options & ~ALL_SYMBOL_OPTIONS)
|
|
{
|
|
return E_INVALIDARG;
|
|
}
|
|
|
|
ENTER_ENGINE();
|
|
|
|
SetSymOptions(Options);
|
|
|
|
LEAVE_ENGINE();
|
|
return S_OK;
|
|
}
|
|
|
|
STDMETHODIMP
|
|
DebugClient::GetNameByOffset(
|
|
THIS_
|
|
IN ULONG64 Offset,
|
|
OUT OPTIONAL PSTR NameBuffer,
|
|
IN ULONG NameBufferSize,
|
|
OUT OPTIONAL PULONG NameSize,
|
|
OUT OPTIONAL PULONG64 Displacement
|
|
)
|
|
{
|
|
HRESULT Status;
|
|
|
|
ENTER_ENGINE();
|
|
|
|
if (!IS_MACHINE_ACCESSIBLE())
|
|
{
|
|
Status = E_UNEXPECTED;
|
|
}
|
|
else
|
|
{
|
|
char Sym[MAX_SYMBOL_LEN];
|
|
|
|
if (GetNearSymbol(Offset, Sym, sizeof(Sym), Displacement, 0))
|
|
{
|
|
Status = FillStringBuffer(Sym, 0, NameBuffer, NameBufferSize,
|
|
NameSize);
|
|
}
|
|
else
|
|
{
|
|
Status = E_FAIL;
|
|
}
|
|
}
|
|
|
|
LEAVE_ENGINE();
|
|
return Status;
|
|
}
|
|
|
|
STDMETHODIMP
|
|
DebugClient::GetOffsetByName(
|
|
THIS_
|
|
IN PCSTR Symbol,
|
|
OUT PULONG64 Offset
|
|
)
|
|
{
|
|
HRESULT Status;
|
|
|
|
ENTER_ENGINE();
|
|
|
|
ULONG Count;
|
|
|
|
if (!IS_MACHINE_ACCESSIBLE())
|
|
{
|
|
Status = E_UNEXPECTED;
|
|
}
|
|
else if (Count = GetOffsetFromSym(Symbol, Offset, NULL))
|
|
{
|
|
Status = Count > 1 ? S_FALSE : S_OK;
|
|
}
|
|
else
|
|
{
|
|
Status = E_FAIL;
|
|
}
|
|
|
|
LEAVE_ENGINE();
|
|
return Status;
|
|
}
|
|
|
|
STDMETHODIMP
|
|
DebugClient::GetNearNameByOffset(
|
|
THIS_
|
|
IN ULONG64 Offset,
|
|
IN LONG Delta,
|
|
OUT OPTIONAL PSTR NameBuffer,
|
|
IN ULONG NameBufferSize,
|
|
OUT OPTIONAL PULONG NameSize,
|
|
OUT OPTIONAL PULONG64 Displacement
|
|
)
|
|
{
|
|
HRESULT Status;
|
|
|
|
ENTER_ENGINE();
|
|
|
|
if (!IS_MACHINE_ACCESSIBLE())
|
|
{
|
|
Status = E_UNEXPECTED;
|
|
}
|
|
else
|
|
{
|
|
char Sym[MAX_SYMBOL_LEN];
|
|
|
|
if (GetNearSymbol(Offset, Sym, sizeof(Sym), Displacement, Delta))
|
|
{
|
|
Status = FillStringBuffer(Sym, 0, NameBuffer, NameBufferSize,
|
|
NameSize);
|
|
}
|
|
else
|
|
{
|
|
Status = E_NOINTERFACE;
|
|
}
|
|
}
|
|
|
|
LEAVE_ENGINE();
|
|
return Status;
|
|
}
|
|
|
|
STDMETHODIMP
|
|
DebugClient::GetLineByOffset(
|
|
THIS_
|
|
IN ULONG64 Offset,
|
|
OUT OPTIONAL PULONG Line,
|
|
OUT OPTIONAL PSTR FileBuffer,
|
|
IN ULONG FileBufferSize,
|
|
OUT OPTIONAL PULONG FileSize,
|
|
OUT OPTIONAL PULONG64 Displacement
|
|
)
|
|
{
|
|
HRESULT Status;
|
|
|
|
ENTER_ENGINE();
|
|
|
|
if (!IS_MACHINE_ACCESSIBLE())
|
|
{
|
|
Status = E_UNEXPECTED;
|
|
}
|
|
else
|
|
{
|
|
IMAGEHLP_LINE64 DbgLine;
|
|
ULONG Disp;
|
|
|
|
DbgLine.SizeOfStruct = sizeof(DbgLine);
|
|
if (SymGetLineFromAddr64(g_CurrentProcess->Handle, Offset,
|
|
&Disp, &DbgLine))
|
|
{
|
|
if (Line != NULL)
|
|
{
|
|
*Line = DbgLine.LineNumber;
|
|
}
|
|
Status = FillStringBuffer(DbgLine.FileName, 0,
|
|
FileBuffer, FileBufferSize, FileSize);
|
|
if (Displacement != NULL)
|
|
{
|
|
*Displacement = Disp;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
Status = E_FAIL;
|
|
}
|
|
}
|
|
|
|
LEAVE_ENGINE();
|
|
return Status;
|
|
}
|
|
|
|
STDMETHODIMP
|
|
DebugClient::GetOffsetByLine(
|
|
THIS_
|
|
IN ULONG Line,
|
|
IN PCSTR File,
|
|
OUT PULONG64 Offset
|
|
)
|
|
{
|
|
HRESULT Status;
|
|
|
|
ENTER_ENGINE();
|
|
|
|
if (!IS_MACHINE_ACCESSIBLE())
|
|
{
|
|
Status = E_UNEXPECTED;
|
|
}
|
|
else
|
|
{
|
|
IMAGEHLP_LINE64 DbgLine;
|
|
LONG Disp;
|
|
|
|
DbgLine.SizeOfStruct = sizeof(DbgLine);
|
|
if (SymGetLineFromName64(g_CurrentProcess->Handle, NULL, (PSTR)File,
|
|
Line, &Disp, &DbgLine))
|
|
{
|
|
*Offset = DbgLine.Address;
|
|
Status = S_OK;
|
|
}
|
|
else
|
|
{
|
|
Status = E_FAIL;
|
|
}
|
|
}
|
|
|
|
LEAVE_ENGINE();
|
|
return Status;
|
|
}
|
|
|
|
STDMETHODIMP
|
|
DebugClient::GetNumberModules(
|
|
THIS_
|
|
OUT PULONG Loaded,
|
|
OUT PULONG Unloaded
|
|
)
|
|
{
|
|
HRESULT Status;
|
|
|
|
ENTER_ENGINE();
|
|
|
|
if (g_CurrentProcess == NULL)
|
|
{
|
|
Status = E_UNEXPECTED;
|
|
}
|
|
else
|
|
{
|
|
*Loaded = g_CurrentProcess->NumberImages;
|
|
*Unloaded = g_NumUnloadedModules;
|
|
Status = S_OK;
|
|
}
|
|
|
|
LEAVE_ENGINE();
|
|
return Status;
|
|
}
|
|
|
|
HRESULT
|
|
GetUnloadedModuleByIndex(ULONG Index, UnloadedModuleInfo** IterRet,
|
|
PSTR Name, PDEBUG_MODULE_PARAMETERS Params)
|
|
{
|
|
HRESULT Status;
|
|
UnloadedModuleInfo* Iter;
|
|
|
|
if ((Iter = g_Target->GetUnloadedModuleInfo()) == NULL)
|
|
{
|
|
return E_FAIL;
|
|
}
|
|
|
|
if ((Status = Iter->Initialize()) != S_OK)
|
|
{
|
|
return Status;
|
|
}
|
|
|
|
do
|
|
{
|
|
if ((Status = Iter->GetEntry(Name, Params)) != S_OK)
|
|
{
|
|
if (Status == S_FALSE)
|
|
{
|
|
return E_INVALIDARG;
|
|
}
|
|
|
|
return Status;
|
|
}
|
|
} while (Index-- > 0);
|
|
|
|
if (IterRet != NULL)
|
|
{
|
|
*IterRet = Iter;
|
|
}
|
|
return S_OK;
|
|
}
|
|
|
|
STDMETHODIMP
|
|
DebugClient::GetModuleByIndex(
|
|
THIS_
|
|
IN ULONG Index,
|
|
OUT PULONG64 Base
|
|
)
|
|
{
|
|
HRESULT Status;
|
|
|
|
ENTER_ENGINE();
|
|
|
|
if (g_CurrentProcess == NULL)
|
|
{
|
|
Status = E_UNEXPECTED;
|
|
}
|
|
else if (Index >= g_CurrentProcess->NumberImages)
|
|
{
|
|
DEBUG_MODULE_PARAMETERS Params;
|
|
|
|
if ((Status = GetUnloadedModuleByIndex
|
|
(Index - g_CurrentProcess->NumberImages,
|
|
NULL, NULL, &Params)) == S_OK)
|
|
{
|
|
*Base = Params.Base;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
*Base = GetImageByIndex(g_CurrentProcess, Index)->BaseOfImage;
|
|
Status = S_OK;
|
|
}
|
|
|
|
LEAVE_ENGINE();
|
|
return Status;
|
|
}
|
|
|
|
STDMETHODIMP
|
|
DebugClient::GetModuleByModuleName(
|
|
THIS_
|
|
IN PCSTR Name,
|
|
IN ULONG StartIndex,
|
|
OUT OPTIONAL PULONG Index,
|
|
OUT OPTIONAL PULONG64 Base
|
|
)
|
|
{
|
|
HRESULT Status;
|
|
|
|
ENTER_ENGINE();
|
|
|
|
if (g_CurrentProcess == NULL)
|
|
{
|
|
Status = E_UNEXPECTED;
|
|
}
|
|
else
|
|
{
|
|
ULONG Idx = 0;
|
|
|
|
Status = E_NOINTERFACE;
|
|
|
|
PDEBUG_IMAGE_INFO Image = g_CurrentProcess->ImageHead;
|
|
while (Image != NULL)
|
|
{
|
|
if (StartIndex == 0 &&
|
|
!_strcmpi(Name, Image->ModuleName))
|
|
{
|
|
if (Index != NULL)
|
|
{
|
|
*Index = Idx;
|
|
}
|
|
if (Base != NULL)
|
|
{
|
|
*Base = Image->BaseOfImage;
|
|
}
|
|
Status = S_OK;
|
|
break;
|
|
}
|
|
|
|
Image = Image->Next;
|
|
Idx++;
|
|
if (StartIndex > 0)
|
|
{
|
|
StartIndex--;
|
|
}
|
|
}
|
|
|
|
if (Image == NULL)
|
|
{
|
|
UnloadedModuleInfo* Iter;
|
|
char UnlName[MAX_UNLOADED_NAME_LENGTH / sizeof(WCHAR) + 1];
|
|
DEBUG_MODULE_PARAMETERS Params;
|
|
|
|
Status = GetUnloadedModuleByIndex(StartIndex, &Iter, UnlName,
|
|
&Params);
|
|
for (;;)
|
|
{
|
|
if (Status == S_FALSE || Status == E_INVALIDARG)
|
|
{
|
|
Status = E_NOINTERFACE;
|
|
break;
|
|
}
|
|
else if (Status != S_OK)
|
|
{
|
|
break;
|
|
}
|
|
|
|
if (!_strcmpi(Name, UnlName))
|
|
{
|
|
if (Index != NULL)
|
|
{
|
|
*Index = Idx;
|
|
}
|
|
if (Base != NULL)
|
|
{
|
|
*Base = Params.Base;
|
|
}
|
|
Status = S_OK;
|
|
break;
|
|
}
|
|
|
|
Status = Iter->GetEntry(UnlName, &Params);
|
|
Idx++;
|
|
}
|
|
}
|
|
}
|
|
|
|
LEAVE_ENGINE();
|
|
return Status;
|
|
}
|
|
|
|
STDMETHODIMP
|
|
DebugClient::GetModuleByOffset(
|
|
THIS_
|
|
IN ULONG64 Offset,
|
|
IN ULONG StartIndex,
|
|
OUT OPTIONAL PULONG Index,
|
|
OUT OPTIONAL PULONG64 Base
|
|
)
|
|
{
|
|
HRESULT Status;
|
|
|
|
ENTER_ENGINE();
|
|
|
|
if (g_CurrentProcess == NULL)
|
|
{
|
|
Status = E_UNEXPECTED;
|
|
}
|
|
else
|
|
{
|
|
ULONG Idx = 0;
|
|
|
|
Status = E_NOINTERFACE;
|
|
|
|
PDEBUG_IMAGE_INFO Image = g_CurrentProcess->ImageHead;
|
|
while (Image != NULL)
|
|
{
|
|
if (StartIndex == 0 &&
|
|
Offset >= Image->BaseOfImage &&
|
|
Offset < Image->BaseOfImage + Image->SizeOfImage)
|
|
{
|
|
if (Index != NULL)
|
|
{
|
|
*Index = Idx;
|
|
}
|
|
if (Base != NULL)
|
|
{
|
|
*Base = Image->BaseOfImage;
|
|
}
|
|
Status = S_OK;
|
|
break;
|
|
}
|
|
|
|
Image = Image->Next;
|
|
Idx++;
|
|
if (StartIndex > 0)
|
|
{
|
|
StartIndex--;
|
|
}
|
|
}
|
|
|
|
if (Image == NULL)
|
|
{
|
|
UnloadedModuleInfo* Iter;
|
|
DEBUG_MODULE_PARAMETERS Params;
|
|
|
|
Status = GetUnloadedModuleByIndex(StartIndex, &Iter, NULL,
|
|
&Params);
|
|
for (;;)
|
|
{
|
|
if (Status == S_FALSE || Status == E_INVALIDARG)
|
|
{
|
|
Status = E_NOINTERFACE;
|
|
break;
|
|
}
|
|
else if (Status != S_OK)
|
|
{
|
|
break;
|
|
}
|
|
|
|
if (Offset >= Params.Base &&
|
|
Offset < Params.Base + Params.Size)
|
|
{
|
|
if (Index != NULL)
|
|
{
|
|
*Index = Idx;
|
|
}
|
|
if (Base != NULL)
|
|
{
|
|
*Base = Params.Base;
|
|
}
|
|
Status = S_OK;
|
|
break;
|
|
}
|
|
|
|
Status = Iter->GetEntry(NULL, &Params);
|
|
Idx++;
|
|
}
|
|
}
|
|
}
|
|
|
|
LEAVE_ENGINE();
|
|
return Status;
|
|
}
|
|
|
|
STDMETHODIMP
|
|
DebugClient::GetModuleNames(
|
|
THIS_
|
|
IN ULONG Index,
|
|
IN ULONG64 Base,
|
|
OUT OPTIONAL PSTR ImageNameBuffer,
|
|
IN ULONG ImageNameBufferSize,
|
|
OUT OPTIONAL PULONG ImageNameSize,
|
|
OUT OPTIONAL PSTR ModuleNameBuffer,
|
|
IN ULONG ModuleNameBufferSize,
|
|
OUT OPTIONAL PULONG ModuleNameSize,
|
|
OUT OPTIONAL PSTR LoadedImageNameBuffer,
|
|
IN ULONG LoadedImageNameBufferSize,
|
|
OUT OPTIONAL PULONG LoadedImageNameSize
|
|
)
|
|
{
|
|
HRESULT Status;
|
|
|
|
ENTER_ENGINE();
|
|
|
|
if (g_CurrentProcess == NULL)
|
|
{
|
|
Status = E_UNEXPECTED;
|
|
}
|
|
else
|
|
{
|
|
ULONG Idx = 0;
|
|
|
|
Status = E_NOINTERFACE;
|
|
|
|
PDEBUG_IMAGE_INFO Image = g_CurrentProcess->ImageHead;
|
|
while (Image != NULL)
|
|
{
|
|
if ((Index != DEBUG_ANY_ID && Idx == Index) ||
|
|
(Index == DEBUG_ANY_ID && Base == Image->BaseOfImage))
|
|
{
|
|
IMAGEHLP_MODULE64 ModInfo;
|
|
|
|
ModInfo.SizeOfStruct = sizeof(ModInfo);
|
|
if (!SymGetModuleInfo64(g_CurrentProcess->Handle,
|
|
Image->BaseOfImage, &ModInfo))
|
|
{
|
|
Status = WIN32_LAST_STATUS();
|
|
break;
|
|
}
|
|
|
|
Status = FillStringBuffer(Image->ImagePath, 0,
|
|
ImageNameBuffer,
|
|
ImageNameBufferSize,
|
|
ImageNameSize);
|
|
if (FillStringBuffer(Image->ModuleName, 0,
|
|
ModuleNameBuffer,
|
|
ModuleNameBufferSize,
|
|
ModuleNameSize) == S_FALSE)
|
|
{
|
|
Status = S_FALSE;
|
|
}
|
|
if (FillStringBuffer(ModInfo.LoadedImageName, 0,
|
|
LoadedImageNameBuffer,
|
|
LoadedImageNameBufferSize,
|
|
LoadedImageNameSize) == S_FALSE)
|
|
{
|
|
Status = S_FALSE;
|
|
}
|
|
break;
|
|
}
|
|
|
|
Image = Image->Next;
|
|
Idx++;
|
|
}
|
|
|
|
if (Image == NULL)
|
|
{
|
|
UnloadedModuleInfo* Iter;
|
|
char UnlName[MAX_UNLOADED_NAME_LENGTH / sizeof(WCHAR) + 1];
|
|
DEBUG_MODULE_PARAMETERS Params;
|
|
ULONG StartIndex = 0;
|
|
|
|
if (Index != DEBUG_ANY_ID)
|
|
{
|
|
// If the index was already hit we
|
|
// shouldn't be here.
|
|
DBG_ASSERT(Index >= Idx);
|
|
StartIndex = Index - Idx;
|
|
}
|
|
|
|
Status = GetUnloadedModuleByIndex(StartIndex, &Iter, UnlName,
|
|
&Params);
|
|
Idx += StartIndex;
|
|
for (;;)
|
|
{
|
|
if (Status == S_FALSE || Status == E_INVALIDARG)
|
|
{
|
|
Status = E_NOINTERFACE;
|
|
break;
|
|
}
|
|
else if (Status != S_OK)
|
|
{
|
|
break;
|
|
}
|
|
|
|
if ((Index != DEBUG_ANY_ID && Idx == Index) ||
|
|
(Index == DEBUG_ANY_ID && Base == Params.Base))
|
|
{
|
|
Status = FillStringBuffer(UnlName, 0,
|
|
ImageNameBuffer,
|
|
ImageNameBufferSize,
|
|
ImageNameSize);
|
|
FillStringBuffer(NULL, 0,
|
|
ModuleNameBuffer,
|
|
ModuleNameBufferSize,
|
|
ModuleNameSize);
|
|
FillStringBuffer(NULL, 0,
|
|
LoadedImageNameBuffer,
|
|
LoadedImageNameBufferSize,
|
|
LoadedImageNameSize);
|
|
break;
|
|
}
|
|
|
|
Status = Iter->GetEntry(UnlName, &Params);
|
|
Idx++;
|
|
}
|
|
}
|
|
}
|
|
|
|
LEAVE_ENGINE();
|
|
return Status;
|
|
}
|
|
|
|
void
|
|
FillModuleParameters(PDEBUG_IMAGE_INFO Image, PDEBUG_MODULE_PARAMETERS Params)
|
|
{
|
|
Params->Base = Image->BaseOfImage;
|
|
Params->Size = Image->SizeOfImage;
|
|
Params->TimeDateStamp = Image->TimeDateStamp;
|
|
Params->Checksum = Image->CheckSum;
|
|
Params->Flags = 0;
|
|
Params->SymbolType = DEBUG_SYMTYPE_DEFERRED;
|
|
Params->ImageNameSize = strlen(Image->ImagePath) + 1;
|
|
Params->ModuleNameSize = strlen(Image->ModuleName) + 1;
|
|
Params->LoadedImageNameSize = 0;
|
|
ZeroMemory(Params->Reserved, sizeof(Params->Reserved));
|
|
|
|
IMAGEHLP_MODULE64 ModInfo;
|
|
|
|
ModInfo.SizeOfStruct = sizeof(ModInfo);
|
|
if (SymGetModuleInfo64(g_CurrentProcess->Handle,
|
|
Image->BaseOfImage, &ModInfo))
|
|
{
|
|
// DEBUG_SYMTYPE_* values match imagehlp's SYM_TYPE.
|
|
// Assert some key equivalences.
|
|
C_ASSERT(DEBUG_SYMTYPE_PDB == SymPdb &&
|
|
DEBUG_SYMTYPE_EXPORT == SymExport &&
|
|
DEBUG_SYMTYPE_DEFERRED == SymDeferred &&
|
|
DEBUG_SYMTYPE_DIA == SymDia);
|
|
|
|
Params->SymbolType = (ULONG)ModInfo.SymType;
|
|
Params->LoadedImageNameSize = strlen(ModInfo.LoadedImageName) + 1;
|
|
}
|
|
|
|
DBH_MODSYMINFO SymFile;
|
|
|
|
SymFile.function = dbhModSymInfo;
|
|
SymFile.sizeofstruct = sizeof(SymFile);
|
|
SymFile.addr = Image->BaseOfImage;
|
|
if (dbghelp(g_CurrentProcess->Handle, &SymFile))
|
|
{
|
|
Params->SymbolFileNameSize = strlen(SymFile.file) + 1;
|
|
}
|
|
|
|
Params->MappedImageNameSize = strlen(Image->MappedImagePath) + 1;
|
|
}
|
|
|
|
STDMETHODIMP
|
|
DebugClient::GetModuleParameters(
|
|
THIS_
|
|
IN ULONG Count,
|
|
IN OPTIONAL /* size_is(Count) */ PULONG64 Bases,
|
|
IN ULONG Start,
|
|
OUT /* size_is(Count) */ PDEBUG_MODULE_PARAMETERS Params
|
|
)
|
|
{
|
|
HRESULT Status;
|
|
|
|
ENTER_ENGINE();
|
|
|
|
UnloadedModuleInfo* Iter;
|
|
|
|
if (g_CurrentProcess == NULL)
|
|
{
|
|
Status = E_UNEXPECTED;
|
|
}
|
|
else if (Bases != NULL)
|
|
{
|
|
Status = S_OK;
|
|
while (Count-- > 0)
|
|
{
|
|
PDEBUG_IMAGE_INFO Image = g_CurrentProcess->ImageHead;
|
|
while (Image != NULL)
|
|
{
|
|
if (*Bases == Image->BaseOfImage)
|
|
{
|
|
FillModuleParameters(Image, Params);
|
|
break;
|
|
}
|
|
|
|
Image = Image->Next;
|
|
}
|
|
|
|
if (Image == NULL)
|
|
{
|
|
Status = E_NOINTERFACE;
|
|
|
|
Iter = g_Target->GetUnloadedModuleInfo();
|
|
if (Iter != NULL &&
|
|
Iter->Initialize() == S_OK)
|
|
{
|
|
while (Iter->GetEntry(NULL, Params) == S_OK)
|
|
{
|
|
if (*Bases == Params->Base)
|
|
{
|
|
Status = S_OK;
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
if (Status != S_OK)
|
|
{
|
|
ZeroMemory(Params, sizeof(*Params));
|
|
Params->Base = DEBUG_INVALID_OFFSET;
|
|
}
|
|
}
|
|
|
|
Bases++;
|
|
Params++;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
ULONG i, End;
|
|
HRESULT SingleStatus;
|
|
|
|
Status = S_OK;
|
|
i = Start;
|
|
End = Start + Count;
|
|
|
|
if (i < g_CurrentProcess->NumberImages)
|
|
{
|
|
PDEBUG_IMAGE_INFO Image = GetImageByIndex(g_CurrentProcess, i);
|
|
while (i < g_CurrentProcess->NumberImages && i < End)
|
|
{
|
|
FillModuleParameters(Image, Params);
|
|
Image = Image->Next;
|
|
Params++;
|
|
i++;
|
|
}
|
|
}
|
|
|
|
if (i < End)
|
|
{
|
|
DEBUG_MODULE_PARAMETERS Param;
|
|
|
|
SingleStatus = GetUnloadedModuleByIndex
|
|
(i - g_CurrentProcess->NumberImages,
|
|
&Iter, NULL, &Param);
|
|
if (SingleStatus != S_OK)
|
|
{
|
|
Iter = NULL;
|
|
}
|
|
while (i < End)
|
|
{
|
|
if (SingleStatus != S_OK)
|
|
{
|
|
ZeroMemory(Params, sizeof(*Params));
|
|
Params->Base = DEBUG_INVALID_OFFSET;
|
|
Status = SingleStatus;
|
|
}
|
|
else
|
|
{
|
|
*Params = Param;
|
|
}
|
|
Params++;
|
|
|
|
if (Iter != NULL)
|
|
{
|
|
SingleStatus = Iter->GetEntry(NULL, &Param);
|
|
if (SingleStatus == S_FALSE)
|
|
{
|
|
SingleStatus = E_INVALIDARG;
|
|
}
|
|
}
|
|
|
|
i++;
|
|
}
|
|
}
|
|
}
|
|
|
|
LEAVE_ENGINE();
|
|
return Status;
|
|
}
|
|
|
|
STDMETHODIMP
|
|
DebugClient::GetSymbolModule(
|
|
THIS_
|
|
IN PCSTR Symbol,
|
|
OUT PULONG64 Base
|
|
)
|
|
{
|
|
HRESULT Status;
|
|
|
|
ENTER_ENGINE();
|
|
|
|
if (g_CurrentProcess == NULL)
|
|
{
|
|
Status = E_UNEXPECTED;
|
|
}
|
|
else
|
|
{
|
|
PCSTR ModEnd;
|
|
ULONG Len;
|
|
|
|
ModEnd = strchr(Symbol, '!');
|
|
if (ModEnd == NULL)
|
|
{
|
|
Status = E_INVALIDARG;
|
|
}
|
|
else if (*(ModEnd+1) != '\0')
|
|
{
|
|
SYM_DUMP_PARAM_EX Param =
|
|
{
|
|
sizeof(Param), (PUCHAR)Symbol, DBG_DUMP_NO_PRINT, 0,
|
|
NULL, NULL, NULL, 0, NULL
|
|
};
|
|
ULONG TypeStatus;
|
|
TYPES_INFO TypeInfo;
|
|
|
|
ZeroMemory(&TypeInfo, sizeof(TypeInfo));
|
|
TypeStatus = TypeInfoFound(g_CurrentProcess->Handle,
|
|
g_CurrentProcess->ImageHead,
|
|
&Param, &TypeInfo);
|
|
if (TypeStatus == NO_ERROR)
|
|
{
|
|
*Base = TypeInfo.ModBaseAddress;
|
|
}
|
|
Status = ResultFromTypeStatus(TypeStatus);
|
|
}
|
|
else
|
|
{
|
|
PDEBUG_IMAGE_INFO Image;
|
|
|
|
Status = E_NOINTERFACE;
|
|
Len = (ULONG)(ModEnd - Symbol);
|
|
for (Image = g_CurrentProcess->ImageHead;
|
|
Image != NULL;
|
|
Image = Image->Next)
|
|
{
|
|
if (strlen(Image->ModuleName) == Len &&
|
|
!_memicmp(Symbol, Image->ModuleName, Len))
|
|
{
|
|
*Base = Image->BaseOfImage;
|
|
Status = S_OK;
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
LEAVE_ENGINE();
|
|
return Status;
|
|
}
|
|
|
|
STDMETHODIMP
|
|
DebugClient::GetTypeName(
|
|
THIS_
|
|
IN ULONG64 Module,
|
|
IN ULONG TypeId,
|
|
OUT OPTIONAL PSTR NameBuffer,
|
|
IN ULONG NameBufferSize,
|
|
OUT OPTIONAL PULONG NameSize
|
|
)
|
|
{
|
|
HRESULT Status;
|
|
|
|
ENTER_ENGINE();
|
|
|
|
if (!IS_MACHINE_ACCESSIBLE())
|
|
{
|
|
Status = E_UNEXPECTED;
|
|
}
|
|
else
|
|
{
|
|
TYPES_INFO TypeInfo;
|
|
ANSI_STRING TypeName;
|
|
char TypeString[MAX_NAME];
|
|
|
|
ZeroMemory(&TypeInfo, sizeof(TypeInfo));
|
|
TypeInfo.TypeIndex = TypeId;
|
|
TypeInfo.hProcess = g_CurrentProcess->Handle;
|
|
TypeInfo.ModBaseAddress = Module;
|
|
TypeName.Buffer = TypeString;
|
|
TypeName.Length = sizeof(TypeString);
|
|
TypeName.MaximumLength = sizeof(TypeString);
|
|
|
|
Status = ::GetTypeName(NULL, &TypeInfo, &TypeName);
|
|
if (Status == S_OK)
|
|
{
|
|
Status = FillStringBuffer(TypeName.Buffer, TypeName.Length,
|
|
NameBuffer, NameBufferSize, NameSize);
|
|
}
|
|
}
|
|
|
|
LEAVE_ENGINE();
|
|
return Status;
|
|
}
|
|
|
|
STDMETHODIMP
|
|
DebugClient::GetConstantName(
|
|
THIS_
|
|
IN ULONG64 Module,
|
|
IN ULONG TypeId,
|
|
IN ULONG64 Value,
|
|
OUT OPTIONAL PSTR NameBuffer,
|
|
IN ULONG NameBufferSize,
|
|
OUT OPTIONAL PULONG NameSize
|
|
)
|
|
{
|
|
HRESULT Status;
|
|
|
|
ENTER_ENGINE();
|
|
|
|
if (!IS_MACHINE_ACCESSIBLE())
|
|
{
|
|
Status = E_UNEXPECTED;
|
|
}
|
|
else
|
|
{
|
|
TYPES_INFO TypeInfo;
|
|
ANSI_STRING TypeName;
|
|
char TypeString[MAX_NAME];
|
|
|
|
ZeroMemory(&TypeInfo, sizeof(TypeInfo));
|
|
TypeInfo.TypeIndex = TypeId;
|
|
TypeInfo.hProcess = g_CurrentProcess->Handle;
|
|
TypeInfo.ModBaseAddress = Module;
|
|
TypeInfo.Flag = IMAGEHLP_SYMBOL_INFO_VALUEPRESENT;
|
|
TypeInfo.Value = Value;
|
|
TypeName.Buffer = TypeString;
|
|
TypeName.Length = sizeof(TypeString);
|
|
TypeName.MaximumLength = sizeof(TypeString);
|
|
|
|
Status = ::GetTypeName(NULL, &TypeInfo, &TypeName);
|
|
if (Status == S_OK)
|
|
{
|
|
Status = FillStringBuffer(TypeName.Buffer, TypeName.Length,
|
|
NameBuffer, NameBufferSize, NameSize);
|
|
}
|
|
}
|
|
|
|
LEAVE_ENGINE();
|
|
return Status;
|
|
}
|
|
|
|
typedef struct _COPY_FIELD_NAME_CONTEXT {
|
|
ULONG Called;
|
|
ULONG IndexToMatch;
|
|
PSTR NameBuffer;
|
|
ULONG NameBufferSize;
|
|
PULONG NameSize;
|
|
HRESULT Status;
|
|
} COPY_FIELD_NAME_CONTEXT;
|
|
|
|
ULONG
|
|
CopyFieldName(
|
|
PFIELD_INFO_EX pField,
|
|
PVOID Context
|
|
)
|
|
{
|
|
COPY_FIELD_NAME_CONTEXT* pInfo = (COPY_FIELD_NAME_CONTEXT *) Context;
|
|
|
|
if (pInfo->Called++ == pInfo->IndexToMatch)
|
|
{
|
|
pInfo->Status = FillStringBuffer((PSTR) pField->fName, strlen((PCHAR) pField->fName)+1,
|
|
pInfo->NameBuffer, pInfo->NameBufferSize, pInfo->NameSize);
|
|
return FALSE;
|
|
}
|
|
return TRUE;
|
|
}
|
|
|
|
STDMETHODIMP
|
|
DebugClient::GetFieldName(
|
|
THIS_
|
|
IN ULONG64 Module,
|
|
IN ULONG TypeId,
|
|
IN ULONG FieldIndex,
|
|
OUT OPTIONAL PSTR NameBuffer,
|
|
IN ULONG NameBufferSize,
|
|
OUT OPTIONAL PULONG NameSize
|
|
)
|
|
{
|
|
HRESULT Status;
|
|
|
|
ENTER_ENGINE();
|
|
|
|
if (!IS_MACHINE_ACCESSIBLE())
|
|
{
|
|
Status = E_UNEXPECTED;
|
|
}
|
|
else
|
|
{
|
|
ULONG TypeStatus;
|
|
COPY_FIELD_NAME_CONTEXT FieldInfo =
|
|
{
|
|
0, FieldIndex, NameBuffer, NameBufferSize,
|
|
NameSize, E_INVALIDARG
|
|
};
|
|
SYM_DUMP_PARAM_EX Param =
|
|
{
|
|
sizeof(Param), NULL, DBG_DUMP_NO_PRINT | DBG_DUMP_CALL_FOR_EACH, 0,
|
|
NULL, &FieldInfo, &CopyFieldName, 0, NULL
|
|
};
|
|
TYPES_INFO TypeInfo;
|
|
|
|
ZeroMemory(&TypeInfo, sizeof(TypeInfo));
|
|
TypeInfo.hProcess = g_CurrentProcess->Handle;
|
|
TypeInfo.ModBaseAddress = Module;
|
|
TypeInfo.TypeIndex = TypeId;
|
|
DumpType(&TypeInfo, &Param, &TypeStatus);
|
|
if (TypeStatus == NO_ERROR)
|
|
{
|
|
Status = FieldInfo.Status;
|
|
} else
|
|
{
|
|
Status = ResultFromTypeStatus(TypeStatus);
|
|
}
|
|
}
|
|
|
|
LEAVE_ENGINE();
|
|
return Status;
|
|
}
|
|
|
|
#define ALL_TYPE_OPTIONS DEBUG_TYPEOPTS_UNICODE_DISPLAY
|
|
|
|
STDMETHODIMP
|
|
DebugClient::GetTypeOptions(
|
|
THIS_
|
|
OUT PULONG Options
|
|
)
|
|
{
|
|
ENTER_ENGINE();
|
|
|
|
*Options = 0;
|
|
|
|
*Options |= g_EnableUnicode ? DEBUG_TYPEOPTS_UNICODE_DISPLAY : 0;
|
|
|
|
LEAVE_ENGINE();
|
|
return S_OK;
|
|
}
|
|
|
|
STDMETHODIMP
|
|
DebugClient::SetTypeOptions(
|
|
THIS_
|
|
IN ULONG Options
|
|
)
|
|
{
|
|
if (Options & ~ALL_TYPE_OPTIONS)
|
|
{
|
|
return E_INVALIDARG;
|
|
}
|
|
|
|
ENTER_ENGINE();
|
|
|
|
g_EnableUnicode = Options & DEBUG_TYPEOPTS_UNICODE_DISPLAY;
|
|
g_TypeOptions = Options;
|
|
|
|
NotifyChangeSymbolState(DEBUG_CSS_TYPE_OPTIONS, 0, NULL);
|
|
|
|
LEAVE_ENGINE();
|
|
return S_OK;
|
|
|
|
}
|
|
|
|
STDMETHODIMP
|
|
DebugClient::AddTypeOptions(
|
|
THIS_
|
|
IN ULONG Options
|
|
)
|
|
{
|
|
if (Options & ~ALL_TYPE_OPTIONS)
|
|
{
|
|
return E_INVALIDARG;
|
|
}
|
|
|
|
ENTER_ENGINE();
|
|
|
|
if (Options & DEBUG_TYPEOPTS_UNICODE_DISPLAY)
|
|
{
|
|
g_EnableUnicode = TRUE;
|
|
NotifyChangeSymbolState(DEBUG_CSS_TYPE_OPTIONS, 0, NULL);
|
|
}
|
|
g_TypeOptions |= Options;
|
|
|
|
LEAVE_ENGINE();
|
|
return S_OK;
|
|
}
|
|
|
|
STDMETHODIMP
|
|
DebugClient::RemoveTypeOptions(
|
|
THIS_
|
|
IN ULONG Options
|
|
)
|
|
{
|
|
if (Options & ~ALL_TYPE_OPTIONS)
|
|
{
|
|
return E_INVALIDARG;
|
|
}
|
|
|
|
ENTER_ENGINE();
|
|
|
|
if (Options & DEBUG_TYPEOPTS_UNICODE_DISPLAY)
|
|
{
|
|
g_EnableUnicode = FALSE;
|
|
NotifyChangeSymbolState(DEBUG_CSS_TYPE_OPTIONS, 0, NULL);
|
|
}
|
|
g_TypeOptions &= ~Options;
|
|
|
|
LEAVE_ENGINE();
|
|
return S_OK;
|
|
|
|
}
|
|
|
|
STDMETHODIMP
|
|
DebugClient::GetTypeId(
|
|
THIS_
|
|
IN ULONG64 Module,
|
|
IN PCSTR Name,
|
|
OUT PULONG TypeId
|
|
)
|
|
{
|
|
ULONG TypeStatus;
|
|
|
|
ENTER_ENGINE();
|
|
|
|
if (!IS_MACHINE_ACCESSIBLE())
|
|
{
|
|
TypeStatus = TYPE_E_UNEXPECTED;
|
|
}
|
|
else
|
|
{
|
|
SYM_DUMP_PARAM_EX Param =
|
|
{
|
|
sizeof(Param), (PUCHAR)Name, DBG_DUMP_NO_PRINT, 0,
|
|
NULL, NULL, NULL, 0, NULL
|
|
};
|
|
TYPES_INFO TypeInfo;
|
|
PCHAR QualName;
|
|
|
|
TypeStatus = CANNOT_ALLOCATE_MEMORY;
|
|
QualName = (PCHAR) malloc(strlen(Name) + 30);
|
|
if (QualName)
|
|
{
|
|
PCSTR ModEnd;
|
|
|
|
if (!strchr(Name, '!'))
|
|
{
|
|
if (GetModuleName(Module, QualName, 30))
|
|
{
|
|
strcat(QualName, "!");
|
|
}
|
|
} else // Already qualified name
|
|
{
|
|
*QualName = 0;
|
|
}
|
|
strcat(QualName, Name);
|
|
|
|
TypeStatus = SYMBOL_TYPE_INFO_NOT_FOUND;
|
|
Param.sName = (PUCHAR) QualName;
|
|
ZeroMemory(&TypeInfo, sizeof(TypeInfo));
|
|
TypeStatus = TypeInfoFound(g_CurrentProcess->Handle,
|
|
g_CurrentProcess->ImageHead,
|
|
&Param, &TypeInfo);
|
|
if (TypeStatus == NO_ERROR)
|
|
{
|
|
*TypeId = TypeInfo.TypeIndex;
|
|
}
|
|
}
|
|
}
|
|
|
|
LEAVE_ENGINE();
|
|
return ResultFromTypeStatus(TypeStatus);
|
|
}
|
|
|
|
STDMETHODIMP
|
|
DebugClient::GetTypeSize(
|
|
THIS_
|
|
IN ULONG64 Module,
|
|
IN ULONG TypeId,
|
|
OUT PULONG Size
|
|
)
|
|
{
|
|
ULONG TypeStatus;
|
|
|
|
ENTER_ENGINE();
|
|
|
|
if (!IS_MACHINE_ACCESSIBLE())
|
|
{
|
|
TypeStatus = TYPE_E_UNEXPECTED;
|
|
}
|
|
else
|
|
{
|
|
SYM_DUMP_PARAM_EX Param =
|
|
{
|
|
sizeof(Param), NULL,
|
|
DBG_DUMP_NO_PRINT | DBG_DUMP_GET_SIZE_ONLY, 0,
|
|
NULL, NULL, NULL, 0, NULL
|
|
};
|
|
TYPES_INFO TypeInfo;
|
|
|
|
ZeroMemory(&TypeInfo, sizeof(TypeInfo));
|
|
TypeInfo.hProcess = g_CurrentProcess->Handle;
|
|
TypeInfo.ModBaseAddress = Module;
|
|
TypeInfo.TypeIndex = TypeId;
|
|
*Size = DumpType(&TypeInfo, &Param, &TypeStatus);
|
|
}
|
|
|
|
LEAVE_ENGINE();
|
|
return ResultFromTypeStatus(TypeStatus);
|
|
}
|
|
|
|
STDMETHODIMP
|
|
DebugClient::GetFieldOffset(
|
|
THIS_
|
|
IN ULONG64 Module,
|
|
IN ULONG TypeId,
|
|
IN PCSTR Field,
|
|
OUT PULONG Offset
|
|
)
|
|
{
|
|
ULONG TypeStatus;
|
|
|
|
ENTER_ENGINE();
|
|
|
|
if (!IS_MACHINE_ACCESSIBLE())
|
|
{
|
|
TypeStatus = TYPE_E_UNEXPECTED;
|
|
}
|
|
else
|
|
{
|
|
FIELD_INFO_EX FieldInfo =
|
|
{
|
|
(PUCHAR)Field, NULL, 0, DBG_DUMP_FIELD_FULL_NAME, 0, NULL
|
|
};
|
|
SYM_DUMP_PARAM_EX Param =
|
|
{
|
|
sizeof(Param), NULL, DBG_DUMP_NO_PRINT, 0,
|
|
NULL, NULL, NULL, 1, &FieldInfo
|
|
};
|
|
TYPES_INFO TypeInfo;
|
|
|
|
ZeroMemory(&TypeInfo, sizeof(TypeInfo));
|
|
TypeInfo.hProcess = g_CurrentProcess->Handle;
|
|
TypeInfo.ModBaseAddress = Module;
|
|
TypeInfo.TypeIndex = TypeId;
|
|
DumpType(&TypeInfo, &Param, &TypeStatus);
|
|
if (TypeStatus == NO_ERROR)
|
|
{
|
|
*Offset = (ULONG)FieldInfo.address;
|
|
}
|
|
}
|
|
|
|
LEAVE_ENGINE();
|
|
return ResultFromTypeStatus(TypeStatus);
|
|
}
|
|
|
|
STDMETHODIMP
|
|
DebugClient::GetSymbolTypeId(
|
|
THIS_
|
|
IN PCSTR Symbol,
|
|
OUT PULONG TypeId,
|
|
OUT OPTIONAL PULONG64 Module
|
|
)
|
|
{
|
|
ULONG TypeStatus;
|
|
|
|
ENTER_ENGINE();
|
|
|
|
if (!IS_MACHINE_ACCESSIBLE())
|
|
{
|
|
TypeStatus = TYPE_E_UNEXPECTED;
|
|
}
|
|
else
|
|
{
|
|
TYPES_INFO_ALL TypeInfo;
|
|
|
|
ZeroMemory(&TypeInfo, sizeof(TypeInfo));
|
|
TypeStatus = !GetExpressionTypeInfo((PCHAR) Symbol, &TypeInfo);
|
|
if (TypeStatus == NO_ERROR)
|
|
{
|
|
*TypeId = TypeInfo.TypeIndex;
|
|
|
|
if (Module != NULL)
|
|
{
|
|
*Module = TypeInfo.Module;
|
|
}
|
|
}
|
|
}
|
|
|
|
LEAVE_ENGINE();
|
|
return ResultFromTypeStatus(TypeStatus);
|
|
}
|
|
|
|
STDMETHODIMP
|
|
DebugClient::GetOffsetTypeId(
|
|
THIS_
|
|
IN ULONG64 Offset,
|
|
OUT PULONG TypeId,
|
|
OUT OPTIONAL PULONG64 Module
|
|
)
|
|
{
|
|
HRESULT Status;
|
|
|
|
ENTER_ENGINE();
|
|
|
|
char Sym[MAX_SYMBOL_LEN];
|
|
|
|
if (!IS_MACHINE_ACCESSIBLE())
|
|
{
|
|
Status = E_UNEXPECTED;
|
|
}
|
|
else if (!GetNearSymbol(Offset, Sym, sizeof(Sym), NULL, 0))
|
|
{
|
|
Status = E_FAIL;
|
|
}
|
|
else
|
|
{
|
|
Status = GetSymbolTypeId(Sym, TypeId, Module);
|
|
}
|
|
|
|
LEAVE_ENGINE();
|
|
return Status;
|
|
}
|
|
|
|
STDMETHODIMP
|
|
DebugClient::ReadTypedDataVirtual(
|
|
THIS_
|
|
IN ULONG64 Offset,
|
|
IN ULONG64 Module,
|
|
IN ULONG TypeId,
|
|
OUT PVOID Buffer,
|
|
IN ULONG BufferSize,
|
|
OUT OPTIONAL PULONG BytesRead
|
|
)
|
|
{
|
|
HRESULT Status;
|
|
ULONG Size;
|
|
|
|
if ((Status = GetTypeSize(Module, TypeId, &Size)) != S_OK)
|
|
{
|
|
return Status;
|
|
}
|
|
if (Size < BufferSize)
|
|
{
|
|
BufferSize = Size;
|
|
}
|
|
if ((Status = ReadVirtual(Offset, Buffer, BufferSize,
|
|
BytesRead)) != S_OK)
|
|
{
|
|
return Status;
|
|
}
|
|
return Size > BufferSize ? S_FALSE : S_OK;
|
|
}
|
|
|
|
STDMETHODIMP
|
|
DebugClient::WriteTypedDataVirtual(
|
|
THIS_
|
|
IN ULONG64 Offset,
|
|
IN ULONG64 Module,
|
|
IN ULONG TypeId,
|
|
IN PVOID Buffer,
|
|
IN ULONG BufferSize,
|
|
OUT OPTIONAL PULONG BytesWritten
|
|
)
|
|
{
|
|
HRESULT Status;
|
|
ULONG Size;
|
|
|
|
if ((Status = GetTypeSize(Module, TypeId, &Size)) != S_OK)
|
|
{
|
|
return Status;
|
|
}
|
|
if (Size < BufferSize)
|
|
{
|
|
BufferSize = Size;
|
|
}
|
|
if ((Status = WriteVirtual(Offset, Buffer, BufferSize,
|
|
BytesWritten)) != S_OK)
|
|
{
|
|
return Status;
|
|
}
|
|
return Size > BufferSize ? S_FALSE : S_OK;
|
|
}
|
|
|
|
#define ALL_OUTPUT_TYPE_FLAGS \
|
|
(DEBUG_OUTTYPE_NO_INDENT | \
|
|
DEBUG_OUTTYPE_NO_OFFSET | \
|
|
DEBUG_OUTTYPE_VERBOSE | \
|
|
DEBUG_OUTTYPE_COMPACT_OUTPUT | \
|
|
DEBUG_OUTTYPE_RECURSION_LEVEL(0xf) | \
|
|
DEBUG_OUTTYPE_ADDRESS_OF_FIELD | \
|
|
DEBUG_OUTTYPE_ADDRESS_AT_END | \
|
|
DEBUG_OUTTYPE_BLOCK_RECURSE )
|
|
|
|
|
|
ULONG
|
|
OutputTypeFlagsToDumpOptions(ULONG Flags)
|
|
{
|
|
ULONG Options = 0;
|
|
|
|
if (Flags & DEBUG_OUTTYPE_NO_INDENT)
|
|
{
|
|
Options |= DBG_DUMP_NO_INDENT;
|
|
}
|
|
if (Flags & DEBUG_OUTTYPE_NO_OFFSET)
|
|
{
|
|
Options |= DBG_DUMP_NO_OFFSET;
|
|
}
|
|
if (Flags & DEBUG_OUTTYPE_VERBOSE)
|
|
{
|
|
Options |= DBG_DUMP_VERBOSE;
|
|
}
|
|
if (Flags & DEBUG_OUTTYPE_COMPACT_OUTPUT)
|
|
{
|
|
Options |= DBG_DUMP_COMPACT_OUT;
|
|
}
|
|
if (Flags & DEBUG_OUTTYPE_ADDRESS_AT_END)
|
|
{
|
|
Options |= DBG_DUMP_ADDRESS_AT_END;
|
|
}
|
|
if (Flags & DEBUG_OUTTYPE_ADDRESS_OF_FIELD)
|
|
{
|
|
Options |= DBG_DUMP_ADDRESS_OF_FIELD;
|
|
}
|
|
if (Flags & DEBUG_OUTTYPE_BLOCK_RECURSE)
|
|
{
|
|
Options |= DBG_DUMP_BLOCK_RECURSE;
|
|
}
|
|
|
|
Options |= DBG_DUMP_RECUR_LEVEL(((Flags >> 4) & 0xf));
|
|
|
|
return Options;
|
|
}
|
|
|
|
STDMETHODIMP
|
|
DebugClient::OutputTypedDataVirtual(
|
|
THIS_
|
|
IN ULONG OutputControl,
|
|
IN ULONG64 Offset,
|
|
IN ULONG64 Module,
|
|
IN ULONG TypeId,
|
|
IN ULONG Flags
|
|
)
|
|
{
|
|
if (Flags & ~ALL_OUTPUT_TYPE_FLAGS)
|
|
{
|
|
return E_INVALIDARG;
|
|
}
|
|
|
|
HRESULT Status;
|
|
|
|
ENTER_ENGINE();
|
|
|
|
OutCtlSave OldCtl;
|
|
|
|
if (!IS_MACHINE_ACCESSIBLE())
|
|
{
|
|
Status = E_UNEXPECTED;
|
|
}
|
|
else if (!PushOutCtl(OutputControl, this, &OldCtl))
|
|
{
|
|
Status = E_INVALIDARG;
|
|
}
|
|
else
|
|
{
|
|
SYM_DUMP_PARAM_EX Param =
|
|
{
|
|
sizeof(Param), NULL, OutputTypeFlagsToDumpOptions(Flags), Offset,
|
|
NULL, NULL, NULL, 0, NULL
|
|
};
|
|
ULONG TypeStatus;
|
|
TYPES_INFO TypeInfo;
|
|
|
|
ZeroMemory(&TypeInfo, sizeof(TypeInfo));
|
|
TypeInfo.hProcess = g_CurrentProcess->Handle;
|
|
TypeInfo.ModBaseAddress = Module;
|
|
TypeInfo.TypeIndex = TypeId;
|
|
DumpType(&TypeInfo, &Param, &TypeStatus);
|
|
Status = ResultFromTypeStatus(TypeStatus);
|
|
|
|
PopOutCtl(&OldCtl);
|
|
}
|
|
|
|
LEAVE_ENGINE();
|
|
return Status;
|
|
}
|
|
|
|
STDMETHODIMP
|
|
DebugClient::ReadTypedDataPhysical(
|
|
THIS_
|
|
IN ULONG64 Offset,
|
|
IN ULONG64 Module,
|
|
IN ULONG TypeId,
|
|
OUT PVOID Buffer,
|
|
IN ULONG BufferSize,
|
|
OUT OPTIONAL PULONG BytesRead
|
|
)
|
|
{
|
|
HRESULT Status;
|
|
ULONG Size;
|
|
|
|
if ((Status = GetTypeSize(Module, TypeId, &Size)) != S_OK)
|
|
{
|
|
return Status;
|
|
}
|
|
if (Size < BufferSize)
|
|
{
|
|
BufferSize = Size;
|
|
}
|
|
if ((Status = ReadPhysical(Offset, Buffer, BufferSize,
|
|
BytesRead)) != S_OK)
|
|
{
|
|
return Status;
|
|
}
|
|
return Size > BufferSize ? S_FALSE : S_OK;
|
|
}
|
|
|
|
STDMETHODIMP
|
|
DebugClient::WriteTypedDataPhysical(
|
|
THIS_
|
|
IN ULONG64 Offset,
|
|
IN ULONG64 Module,
|
|
IN ULONG TypeId,
|
|
IN PVOID Buffer,
|
|
IN ULONG BufferSize,
|
|
OUT OPTIONAL PULONG BytesWritten
|
|
)
|
|
{
|
|
HRESULT Status;
|
|
ULONG Size;
|
|
|
|
if ((Status = GetTypeSize(Module, TypeId, &Size)) != S_OK)
|
|
{
|
|
return Status;
|
|
}
|
|
if (Size < BufferSize)
|
|
{
|
|
BufferSize = Size;
|
|
}
|
|
if ((Status = WritePhysical(Offset, Buffer, BufferSize,
|
|
BytesWritten)) != S_OK)
|
|
{
|
|
return Status;
|
|
}
|
|
return Size > BufferSize ? S_FALSE : S_OK;
|
|
}
|
|
|
|
STDMETHODIMP
|
|
DebugClient::OutputTypedDataPhysical(
|
|
THIS_
|
|
IN ULONG OutputControl,
|
|
IN ULONG64 Offset,
|
|
IN ULONG64 Module,
|
|
IN ULONG TypeId,
|
|
IN ULONG Flags
|
|
)
|
|
{
|
|
if (Flags & ~ALL_OUTPUT_TYPE_FLAGS)
|
|
{
|
|
return E_INVALIDARG;
|
|
}
|
|
|
|
HRESULT Status;
|
|
|
|
ENTER_ENGINE();
|
|
|
|
OutCtlSave OldCtl;
|
|
|
|
if (!IS_MACHINE_ACCESSIBLE())
|
|
{
|
|
Status = E_UNEXPECTED;
|
|
}
|
|
else if (!PushOutCtl(OutputControl, this, &OldCtl))
|
|
{
|
|
Status = E_INVALIDARG;
|
|
}
|
|
else
|
|
{
|
|
SYM_DUMP_PARAM_EX Param =
|
|
{
|
|
sizeof(Param), NULL, OutputTypeFlagsToDumpOptions(Flags) |
|
|
DBG_DUMP_READ_PHYSICAL, Offset, NULL, NULL, NULL, 0, NULL
|
|
};
|
|
ULONG TypeStatus;
|
|
TYPES_INFO TypeInfo;
|
|
|
|
ZeroMemory(&TypeInfo, sizeof(TypeInfo));
|
|
TypeInfo.hProcess = g_CurrentProcess->Handle;
|
|
TypeInfo.ModBaseAddress = Module;
|
|
TypeInfo.TypeIndex = TypeId;
|
|
DumpType(&TypeInfo, &Param, &TypeStatus);
|
|
Status = ResultFromTypeStatus(TypeStatus);
|
|
|
|
PopOutCtl(&OldCtl);
|
|
}
|
|
|
|
LEAVE_ENGINE();
|
|
return Status;
|
|
}
|
|
|
|
STDMETHODIMP
|
|
DebugClient::GetScope(
|
|
THIS_
|
|
OUT OPTIONAL PULONG64 InstructionOffset,
|
|
OUT OPTIONAL PDEBUG_STACK_FRAME ScopeFrame,
|
|
OUT OPTIONAL PVOID ScopeContext,
|
|
IN ULONG ScopeContextSize
|
|
)
|
|
{
|
|
HRESULT Status;
|
|
|
|
ENTER_ENGINE();
|
|
|
|
if (!IS_MACHINE_ACCESSIBLE())
|
|
{
|
|
Status = E_UNEXPECTED;
|
|
goto Exit;
|
|
}
|
|
|
|
Status = S_OK;
|
|
|
|
PDEBUG_SCOPE Scope;
|
|
|
|
Scope = GetCurrentScope();
|
|
|
|
if (InstructionOffset)
|
|
{
|
|
*InstructionOffset = Scope->Frame.InstructionOffset;
|
|
}
|
|
|
|
if (ScopeFrame)
|
|
{
|
|
*ScopeFrame = Scope->Frame;
|
|
}
|
|
|
|
if (ScopeContext)
|
|
{
|
|
if (Scope->State == ScopeFromContext)
|
|
{
|
|
memcpy(ScopeContext, &Scope->Context,
|
|
min(sizeof(Scope->Context), ScopeContextSize));
|
|
}
|
|
else if (g_Machine->GetContextState(MCTX_FULL) == S_OK)
|
|
{
|
|
memcpy(ScopeContext, &g_Machine->m_Context,
|
|
min(sizeof(g_Machine->m_Context), ScopeContextSize));
|
|
}
|
|
}
|
|
|
|
Exit:
|
|
LEAVE_ENGINE();
|
|
return Status;
|
|
}
|
|
|
|
STDMETHODIMP
|
|
DebugClient::SetScope(
|
|
THIS_
|
|
IN ULONG64 InstructionOffset,
|
|
IN OPTIONAL PDEBUG_STACK_FRAME ScopeFrame,
|
|
IN OPTIONAL PVOID ScopeContext,
|
|
IN ULONG ScopeContextSize
|
|
)
|
|
{
|
|
HRESULT Status;
|
|
|
|
ENTER_ENGINE();
|
|
|
|
if (!IS_MACHINE_ACCESSIBLE())
|
|
{
|
|
Status = E_UNEXPECTED;
|
|
}
|
|
else
|
|
{
|
|
DEBUG_STACK_FRAME LocalFrame;
|
|
|
|
if (ScopeFrame)
|
|
{
|
|
LocalFrame = *ScopeFrame;
|
|
}
|
|
else
|
|
{
|
|
ZeroMemory(&LocalFrame, sizeof(LocalFrame));
|
|
LocalFrame.InstructionOffset = InstructionOffset;
|
|
}
|
|
|
|
Status = SetCurrentScope(&LocalFrame, ScopeContext, ScopeContextSize) ?
|
|
S_FALSE : S_OK;
|
|
}
|
|
|
|
LEAVE_ENGINE();
|
|
return Status;
|
|
}
|
|
|
|
STDMETHODIMP
|
|
DebugClient::ResetScope(
|
|
THIS
|
|
)
|
|
{
|
|
HRESULT Status;
|
|
|
|
ENTER_ENGINE();
|
|
|
|
if (!IS_MACHINE_ACCESSIBLE())
|
|
{
|
|
Status = E_UNEXPECTED;
|
|
}
|
|
else
|
|
{
|
|
ResetCurrentScope();
|
|
Status = S_OK;
|
|
}
|
|
|
|
LEAVE_ENGINE();
|
|
return Status;
|
|
}
|
|
|
|
STDMETHODIMP
|
|
DebugClient::GetScopeSymbolGroup(
|
|
THIS_
|
|
IN ULONG Flags,
|
|
IN OPTIONAL PDEBUG_SYMBOL_GROUP Update,
|
|
OUT PDEBUG_SYMBOL_GROUP* Symbols
|
|
)
|
|
{
|
|
HRESULT Status;
|
|
|
|
if (Flags == 0 ||
|
|
(Flags & ~DEBUG_SCOPE_GROUP_ALL))
|
|
{
|
|
return E_INVALIDARG;
|
|
}
|
|
|
|
ENTER_ENGINE();
|
|
|
|
if (Update)
|
|
{
|
|
ULONG Dummy;
|
|
|
|
if ((Status = Update->AddSymbol("*+", &Dummy)) == S_OK)
|
|
{
|
|
PDEBUG_SCOPE Scope;
|
|
|
|
if (IS_MACHINE_ACCESSIBLE())
|
|
{
|
|
Scope = GetCurrentScope();
|
|
Scope->LocalsChanged = FALSE;
|
|
}
|
|
*Symbols = Update;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
*Symbols = new DebugSymbolGroup(this, Flags);
|
|
if (*Symbols != NULL)
|
|
{
|
|
Status = S_OK;
|
|
}
|
|
else
|
|
{
|
|
Status = E_OUTOFMEMORY;
|
|
}
|
|
}
|
|
|
|
LEAVE_ENGINE();
|
|
return Status;
|
|
}
|
|
|
|
STDMETHODIMP
|
|
DebugClient::CreateSymbolGroup(
|
|
THIS_
|
|
OUT PDEBUG_SYMBOL_GROUP* Group
|
|
)
|
|
{
|
|
HRESULT Status;
|
|
|
|
ENTER_ENGINE();
|
|
|
|
*Group = new DebugSymbolGroup(this);
|
|
if (*Group == NULL)
|
|
{
|
|
Status = E_OUTOFMEMORY;
|
|
}
|
|
else
|
|
{
|
|
Status = S_OK;
|
|
}
|
|
|
|
LEAVE_ENGINE();
|
|
return Status;
|
|
}
|
|
|
|
struct SymbolMatch
|
|
{
|
|
PPROCESS_INFO Process;
|
|
BOOL SingleMod;
|
|
PDEBUG_IMAGE_INFO Mod;
|
|
PCHAR Storage, StorageEnd;
|
|
PCHAR Cur, End;
|
|
char Pattern[1];
|
|
};
|
|
|
|
STDMETHODIMP
|
|
DebugClient::StartSymbolMatch(
|
|
THIS_
|
|
IN PCSTR Pattern,
|
|
OUT PULONG64 Handle
|
|
)
|
|
{
|
|
HRESULT Status;
|
|
|
|
ENTER_ENGINE();
|
|
|
|
if (g_CurrentProcess == NULL)
|
|
{
|
|
Status = E_UNEXPECTED;
|
|
goto EH_Exit;
|
|
}
|
|
|
|
char Module[MAX_MODULE];
|
|
PDEBUG_IMAGE_INFO Mod;
|
|
PCSTR Sym;
|
|
|
|
// Check for a module qualifier.
|
|
Sym = strchr(Pattern, '!');
|
|
if (Sym != NULL)
|
|
{
|
|
size_t ModLen = Sym - Pattern;
|
|
|
|
DBG_ASSERT(ModLen < sizeof(Module));
|
|
|
|
if (ModLen == 0)
|
|
{
|
|
Status = E_INVALIDARG;
|
|
goto EH_Exit;
|
|
}
|
|
|
|
memcpy(Module, Pattern, ModLen);
|
|
Module[ModLen] = 0;
|
|
|
|
Mod = GetImageByName(g_CurrentProcess, Module, INAME_MODULE);
|
|
if (Mod == NULL)
|
|
{
|
|
Status = E_NOINTERFACE;
|
|
goto EH_Exit;
|
|
}
|
|
|
|
Sym++;
|
|
}
|
|
else
|
|
{
|
|
Sym = Pattern;
|
|
Mod = NULL;
|
|
}
|
|
|
|
ULONG SymLen;
|
|
SymLen = strlen(Sym);
|
|
SymbolMatch* Match;
|
|
Match = (SymbolMatch*)malloc(sizeof(SymbolMatch) + SymLen);
|
|
if (Match == NULL)
|
|
{
|
|
Status = E_OUTOFMEMORY;
|
|
goto EH_Exit;
|
|
}
|
|
|
|
if (Mod == NULL)
|
|
{
|
|
Match->Process = g_CurrentProcess;
|
|
Match->Mod = Match->Process->ImageHead;
|
|
Match->SingleMod = FALSE;
|
|
}
|
|
else
|
|
{
|
|
Match->Process = g_CurrentProcess;
|
|
Match->Mod = Mod;
|
|
Match->SingleMod = TRUE;
|
|
}
|
|
|
|
Match->Storage = NULL;
|
|
Match->StorageEnd = NULL;
|
|
Match->Cur = NULL;
|
|
strcpy(Match->Pattern, Sym);
|
|
_strupr(Match->Pattern);
|
|
|
|
*Handle = (ULONG64)Match;
|
|
|
|
EH_Exit:
|
|
LEAVE_ENGINE();
|
|
return Status;
|
|
}
|
|
|
|
#define STORAGE_INC 16384
|
|
|
|
BOOL CALLBACK
|
|
FillMatchStorageCb(PSTR Name, ULONG64 Offset, ULONG Size, PVOID Context)
|
|
{
|
|
SymbolMatch* Match = (SymbolMatch*)Context;
|
|
ULONG NameLen = strlen(Name) + 1;
|
|
ULONG RecordLen = NameLen + sizeof(ULONG64);
|
|
|
|
if (Match->Cur + RecordLen > Match->StorageEnd)
|
|
{
|
|
PCHAR NewStore;
|
|
size_t NewLen;
|
|
|
|
NewLen = (Match->StorageEnd - Match->Storage) + STORAGE_INC;
|
|
NewStore = (PCHAR)realloc(Match->Storage, NewLen);
|
|
if (NewStore == NULL)
|
|
{
|
|
// Terminate the enumeration since there's no more room.
|
|
// This produces a silent failure but it's not
|
|
// important enough to warrant a true failure.
|
|
return FALSE;
|
|
}
|
|
|
|
Match->Cur = NewStore + (Match->Cur - Match->Storage);
|
|
|
|
Match->Storage = NewStore;
|
|
Match->StorageEnd = NewStore + NewLen;
|
|
|
|
DBG_ASSERT(Match->Cur + RecordLen <= Match->StorageEnd);
|
|
}
|
|
|
|
strcpy(Match->Cur, Name);
|
|
Match->Cur += NameLen;
|
|
*(ULONG64 UNALIGNED *)Match->Cur = Offset;
|
|
Match->Cur += sizeof(Offset);
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
STDMETHODIMP
|
|
DebugClient::GetNextSymbolMatch(
|
|
THIS_
|
|
IN ULONG64 Handle,
|
|
OUT OPTIONAL PSTR Buffer,
|
|
IN ULONG BufferSize,
|
|
OUT OPTIONAL PULONG MatchSize,
|
|
OUT OPTIONAL PULONG64 Offset
|
|
)
|
|
{
|
|
ENTER_ENGINE();
|
|
|
|
SymbolMatch* Match = (SymbolMatch*)Handle;
|
|
ULONG64 Disp;
|
|
HRESULT Status = E_NOINTERFACE;
|
|
|
|
// Loop until a matching symbol is found.
|
|
for (;;)
|
|
{
|
|
if (Match->Mod == NULL)
|
|
{
|
|
// Nothing more to enumerate.
|
|
// Status is already set.
|
|
break;
|
|
}
|
|
|
|
if (Match->Cur == NULL)
|
|
{
|
|
// Enumerate all symbols and stash them away.
|
|
Match->Cur = Match->Storage;
|
|
|
|
if (!SymEnumerateSymbols64(Match->Process->Handle,
|
|
Match->Mod->BaseOfImage,
|
|
FillMatchStorageCb, Match))
|
|
{
|
|
Status = WIN32_LAST_STATUS();
|
|
break;
|
|
}
|
|
|
|
Match->End = Match->Cur;
|
|
Match->Cur = Match->Storage;
|
|
}
|
|
|
|
while (Match->Cur < Match->End)
|
|
{
|
|
PCHAR Name;
|
|
ULONG64 Addr;
|
|
|
|
Name = Match->Cur;
|
|
Match->Cur += strlen(Name) + 1;
|
|
Addr = *(ULONG64 UNALIGNED *)Match->Cur;
|
|
Match->Cur += sizeof(Addr);
|
|
|
|
// If this symbol matches remember it for return.
|
|
if (MatchPattern(Name, Match->Pattern))
|
|
{
|
|
char Sym[MAX_MODULE + MAX_SYMBOL_LEN + 1];
|
|
|
|
strcpy(Sym, Match->Mod->ModuleName);
|
|
strcat(Sym, "!");
|
|
strcat(Sym, Name);
|
|
|
|
Status = FillStringBuffer(Sym, 0, Buffer, BufferSize,
|
|
MatchSize);
|
|
|
|
if (Buffer == NULL)
|
|
{
|
|
// Do not advance the enumeration as this
|
|
// is just a size test.
|
|
Match->Cur = Name;
|
|
}
|
|
|
|
if (Offset != NULL)
|
|
{
|
|
*Offset = Addr;
|
|
}
|
|
|
|
break;
|
|
}
|
|
}
|
|
|
|
if (SUCCEEDED(Status))
|
|
{
|
|
break;
|
|
}
|
|
|
|
if (Match->SingleMod)
|
|
{
|
|
Match->Mod = NULL;
|
|
}
|
|
else
|
|
{
|
|
Match->Mod = Match->Mod->Next;
|
|
}
|
|
Match->Cur = NULL;
|
|
}
|
|
|
|
LEAVE_ENGINE();
|
|
return Status;
|
|
}
|
|
|
|
STDMETHODIMP
|
|
DebugClient::EndSymbolMatch(
|
|
THIS_
|
|
IN ULONG64 Handle
|
|
)
|
|
{
|
|
ENTER_ENGINE();
|
|
|
|
SymbolMatch* Match = (SymbolMatch*)Handle;
|
|
|
|
if (Match->Storage != NULL)
|
|
{
|
|
free(Match->Storage);
|
|
}
|
|
free(Match);
|
|
|
|
LEAVE_ENGINE();
|
|
return S_OK;
|
|
}
|
|
|
|
STDMETHODIMP
|
|
DebugClient::Reload(
|
|
THIS_
|
|
IN PCSTR Module
|
|
)
|
|
{
|
|
ENTER_ENGINE();
|
|
|
|
HRESULT Status = g_Target->Reload(Module);
|
|
|
|
LEAVE_ENGINE();
|
|
return Status;
|
|
}
|
|
|
|
STDMETHODIMP
|
|
DebugClient::GetSymbolPath(
|
|
THIS_
|
|
OUT OPTIONAL PSTR Buffer,
|
|
IN ULONG BufferSize,
|
|
OUT OPTIONAL PULONG PathSize
|
|
)
|
|
{
|
|
ENTER_ENGINE();
|
|
|
|
HRESULT Status =
|
|
FillStringBuffer(g_SymbolSearchPath, 0,
|
|
Buffer, BufferSize, PathSize);
|
|
|
|
LEAVE_ENGINE();
|
|
return Status;
|
|
}
|
|
|
|
STDMETHODIMP
|
|
DebugClient::SetSymbolPath(
|
|
THIS_
|
|
IN PCSTR Path
|
|
)
|
|
{
|
|
ENTER_ENGINE();
|
|
|
|
HRESULT Status;
|
|
|
|
Status = bangSymPath(Path, FALSE, NULL, 0) ?
|
|
S_OK : E_OUTOFMEMORY;
|
|
if (Status == S_OK)
|
|
{
|
|
CheckPath(g_SymbolSearchPath);
|
|
}
|
|
|
|
LEAVE_ENGINE();
|
|
return Status;
|
|
}
|
|
|
|
STDMETHODIMP
|
|
DebugClient::AppendSymbolPath(
|
|
THIS_
|
|
IN PCSTR Addition
|
|
)
|
|
{
|
|
ENTER_ENGINE();
|
|
|
|
HRESULT Status;
|
|
|
|
Status = bangSymPath(Addition, TRUE, NULL, 0) ?
|
|
S_OK : E_OUTOFMEMORY;
|
|
if (Status == S_OK)
|
|
{
|
|
CheckPath(g_SymbolSearchPath);
|
|
}
|
|
|
|
LEAVE_ENGINE();
|
|
return Status;
|
|
}
|
|
|
|
STDMETHODIMP
|
|
DebugClient::GetImagePath(
|
|
THIS_
|
|
OUT OPTIONAL PSTR Buffer,
|
|
IN ULONG BufferSize,
|
|
OUT OPTIONAL PULONG PathSize
|
|
)
|
|
{
|
|
ENTER_ENGINE();
|
|
|
|
HRESULT Status = FillStringBuffer(g_ExecutableImageSearchPath, 0,
|
|
Buffer, BufferSize, PathSize);
|
|
|
|
LEAVE_ENGINE();
|
|
return Status;
|
|
}
|
|
|
|
STDMETHODIMP
|
|
DebugClient::SetImagePath(
|
|
THIS_
|
|
IN PCSTR Path
|
|
)
|
|
{
|
|
ENTER_ENGINE();
|
|
|
|
HRESULT Status = ChangePath(&g_ExecutableImageSearchPath, Path, FALSE,
|
|
DEBUG_CSS_PATHS);
|
|
if (Status == S_OK)
|
|
{
|
|
CheckPath(g_ExecutableImageSearchPath);
|
|
}
|
|
|
|
LEAVE_ENGINE();
|
|
return Status;
|
|
}
|
|
|
|
STDMETHODIMP
|
|
DebugClient::AppendImagePath(
|
|
THIS_
|
|
IN PCSTR Addition
|
|
)
|
|
{
|
|
ENTER_ENGINE();
|
|
|
|
HRESULT Status = ChangePath(&g_ExecutableImageSearchPath, Addition, TRUE,
|
|
DEBUG_CSS_PATHS);
|
|
if (Status == S_OK)
|
|
{
|
|
CheckPath(g_ExecutableImageSearchPath);
|
|
}
|
|
|
|
LEAVE_ENGINE();
|
|
return Status;
|
|
}
|
|
|
|
STDMETHODIMP
|
|
DebugClient::GetSourcePath(
|
|
THIS_
|
|
OUT OPTIONAL PSTR Buffer,
|
|
IN ULONG BufferSize,
|
|
OUT OPTIONAL PULONG PathSize
|
|
)
|
|
{
|
|
ENTER_ENGINE();
|
|
|
|
HRESULT Status = FillStringBuffer(g_SrcPath, 0,
|
|
Buffer, BufferSize, PathSize);
|
|
|
|
LEAVE_ENGINE();
|
|
return Status;
|
|
}
|
|
|
|
STDMETHODIMP
|
|
DebugClient::GetSourcePathElement(
|
|
THIS_
|
|
IN ULONG Index,
|
|
OUT OPTIONAL PSTR Buffer,
|
|
IN ULONG BufferSize,
|
|
OUT OPTIONAL PULONG ElementSize
|
|
)
|
|
{
|
|
ENTER_ENGINE();
|
|
|
|
HRESULT Status;
|
|
PSTR Elt, EltEnd;
|
|
|
|
Elt = FindPathElement(g_SrcPath, Index, &EltEnd);
|
|
if (Elt == NULL)
|
|
{
|
|
Status = E_NOINTERFACE;
|
|
goto EH_Exit;
|
|
}
|
|
|
|
CHAR Save;
|
|
Save = *EltEnd;
|
|
*EltEnd = 0;
|
|
Status = FillStringBuffer(Elt, (ULONG)(EltEnd - Elt) + 1,
|
|
Buffer, BufferSize, ElementSize);
|
|
*EltEnd = Save;
|
|
|
|
EH_Exit:
|
|
LEAVE_ENGINE();
|
|
return Status;
|
|
}
|
|
|
|
STDMETHODIMP
|
|
DebugClient::SetSourcePath(
|
|
THIS_
|
|
IN PCSTR Path
|
|
)
|
|
{
|
|
ENTER_ENGINE();
|
|
|
|
HRESULT Status = ChangePath(&g_SrcPath, Path, FALSE, DEBUG_CSS_PATHS);
|
|
if (Status == S_OK)
|
|
{
|
|
CheckPath(g_SrcPath);
|
|
}
|
|
|
|
LEAVE_ENGINE();
|
|
return Status;
|
|
}
|
|
|
|
STDMETHODIMP
|
|
DebugClient::AppendSourcePath(
|
|
THIS_
|
|
IN PCSTR Addition
|
|
)
|
|
{
|
|
ENTER_ENGINE();
|
|
|
|
HRESULT Status = ChangePath(&g_SrcPath, Addition, TRUE, DEBUG_CSS_PATHS);
|
|
if (Status == S_OK)
|
|
{
|
|
CheckPath(g_SrcPath);
|
|
}
|
|
|
|
LEAVE_ENGINE();
|
|
return Status;
|
|
}
|
|
|
|
HRESULT
|
|
GetCanonicalPath(PCSTR Path, PSTR Canon)
|
|
{
|
|
// First make sure it's a full path.
|
|
// XXX drewb - Probably should also convert drive
|
|
// letters to unambiguous names.
|
|
if (!IS_SLASH(Path[0]) &&
|
|
!(((Path[0] >= 'a' && Path[0] <= 'z') ||
|
|
(Path[0] >= 'A' && Path[0] <= 'Z')) &&
|
|
Path[1] == ':') &&
|
|
!IsUrlPathComponent(Path))
|
|
{
|
|
DWORD FullLen;
|
|
PSTR FilePart;
|
|
|
|
FullLen = GetFullPathName(Path, MAX_SOURCE_PATH, Canon, &FilePart);
|
|
if (FullLen == 0 || FullLen >= MAX_SOURCE_PATH)
|
|
{
|
|
return WIN32_LAST_STATUS();
|
|
}
|
|
}
|
|
else
|
|
{
|
|
strcpy(Canon, Path);
|
|
}
|
|
|
|
// Now remove '.' and '..'. This is a full path with a filename
|
|
// at the end so all occurrences must be bracketed with
|
|
// path slashes.
|
|
PSTR Rd = Canon, Wr = Canon;
|
|
|
|
while (*Rd != 0)
|
|
{
|
|
if (IS_SLASH(*Rd))
|
|
{
|
|
if (Rd[1] == '.')
|
|
{
|
|
if (IS_SLASH(Rd[2]))
|
|
{
|
|
// Found /./, ignore leading /. and continue
|
|
// with /.
|
|
Rd += 2;
|
|
continue;
|
|
}
|
|
else if (Rd[2] == '.' && IS_SLASH(Rd[3]))
|
|
{
|
|
// Found /../ so back up one path component
|
|
// and continue with /.
|
|
do
|
|
{
|
|
Wr--;
|
|
}
|
|
while (Wr >= Canon && !IS_PATH_DELIM(*Wr));
|
|
DBG_ASSERT(Wr >= Canon);
|
|
|
|
Rd += 3;
|
|
continue;
|
|
}
|
|
}
|
|
}
|
|
|
|
*Wr++ = *Rd++;
|
|
}
|
|
*Wr = 0;
|
|
|
|
return S_OK;
|
|
}
|
|
|
|
STDMETHODIMP
|
|
DebugClient::FindSourceFile(
|
|
THIS_
|
|
IN ULONG StartElement,
|
|
IN PCSTR File,
|
|
IN ULONG Flags,
|
|
OUT OPTIONAL PULONG FoundElement,
|
|
OUT OPTIONAL PSTR Buffer,
|
|
IN ULONG BufferSize,
|
|
OUT OPTIONAL PULONG FoundSize
|
|
)
|
|
{
|
|
if (Flags & ~(DEBUG_FIND_SOURCE_DEFAULT |
|
|
DEBUG_FIND_SOURCE_FULL_PATH |
|
|
DEBUG_FIND_SOURCE_BEST_MATCH))
|
|
{
|
|
return E_INVALIDARG;
|
|
}
|
|
|
|
HRESULT Status;
|
|
char RwFile[MAX_SOURCE_PATH];
|
|
ULONG FileLen;
|
|
char Found[MAX_SOURCE_PATH];
|
|
PSTR MatchPart;
|
|
ULONG Elt;
|
|
|
|
// Make a read-write copy of the file as the searching
|
|
// modifies it.
|
|
FileLen = strlen(File) + 1;
|
|
if (FileLen > sizeof(RwFile))
|
|
{
|
|
return E_INVALIDARG;
|
|
}
|
|
memcpy(RwFile, File, FileLen);
|
|
|
|
ENTER_ENGINE();
|
|
|
|
if (FindSrcFileOnPath(StartElement, RwFile, Flags, Found,
|
|
&MatchPart, &Elt))
|
|
{
|
|
if (Flags & DEBUG_FIND_SOURCE_FULL_PATH)
|
|
{
|
|
Status = GetCanonicalPath(Found, RwFile);
|
|
if (Status != S_OK)
|
|
{
|
|
goto EH_Exit;
|
|
}
|
|
|
|
strcpy(Found, RwFile);
|
|
}
|
|
|
|
if (FoundElement != NULL)
|
|
{
|
|
*FoundElement = Elt;
|
|
}
|
|
Status = FillStringBuffer(Found, 0,
|
|
Buffer, BufferSize, FoundSize);
|
|
}
|
|
else
|
|
{
|
|
Status = E_NOINTERFACE;
|
|
}
|
|
|
|
EH_Exit:
|
|
LEAVE_ENGINE();
|
|
return Status;
|
|
}
|
|
|
|
// XXX drewb - This API is private for the moment due
|
|
// to uncertainty about what dbghelp's API is going to
|
|
// look like in the long term.
|
|
extern "C"
|
|
ULONG
|
|
IMAGEAPI
|
|
SymGetFileLineOffsets64(
|
|
IN HANDLE hProcess,
|
|
IN LPSTR ModuleName,
|
|
IN LPSTR FileName,
|
|
OUT PDWORD64 Buffer,
|
|
IN ULONG BufferLines
|
|
);
|
|
|
|
STDMETHODIMP
|
|
DebugClient::GetSourceFileLineOffsets(
|
|
THIS_
|
|
IN PCSTR File,
|
|
OUT OPTIONAL PULONG64 Buffer,
|
|
IN ULONG BufferLines,
|
|
OUT OPTIONAL PULONG FileLines
|
|
)
|
|
{
|
|
HRESULT Status;
|
|
ULONG Line;
|
|
|
|
if (Buffer != NULL)
|
|
{
|
|
// Initialize map to empty.
|
|
for (Line = 0; Line < BufferLines; Line++)
|
|
{
|
|
Buffer[Line] = DEBUG_INVALID_OFFSET;
|
|
}
|
|
}
|
|
|
|
ENTER_ENGINE();
|
|
|
|
if (g_CurrentProcess == NULL)
|
|
{
|
|
Status = E_UNEXPECTED;
|
|
goto EH_Exit;
|
|
}
|
|
|
|
PSTR FilePart;
|
|
ULONG HighestLine;
|
|
|
|
// Request the line information from dbghelp.
|
|
FilePart = (PSTR)File;
|
|
HighestLine =
|
|
SymGetFileLineOffsets64(g_CurrentProcess->Handle, NULL, FilePart,
|
|
Buffer, BufferLines);
|
|
if (HighestLine == 0xffffffff)
|
|
{
|
|
Status = WIN32_LAST_STATUS();
|
|
goto EH_Exit;
|
|
}
|
|
|
|
if (HighestLine == 0)
|
|
{
|
|
// Try again with just the filename because the path
|
|
// may be different than what's in the symbol information.
|
|
// XXX drewb - This can cause ambiguity problems.
|
|
FilePart = (PSTR)File + strlen(File) - 1;
|
|
while (FilePart >= File)
|
|
{
|
|
if (IS_PATH_DELIM(*FilePart))
|
|
{
|
|
break;
|
|
}
|
|
|
|
FilePart--;
|
|
}
|
|
FilePart++;
|
|
if (FilePart <= File)
|
|
{
|
|
// No path and no information was found for the
|
|
// given file so return not-found.
|
|
Status = E_NOINTERFACE;
|
|
goto EH_Exit;
|
|
}
|
|
|
|
HighestLine =
|
|
SymGetFileLineOffsets64(g_CurrentProcess->Handle, NULL, FilePart,
|
|
Buffer, BufferLines);
|
|
if (HighestLine == 0xffffffff)
|
|
{
|
|
Status = WIN32_LAST_STATUS();
|
|
goto EH_Exit;
|
|
}
|
|
else if (HighestLine == 0)
|
|
{
|
|
Status = E_NOINTERFACE;
|
|
goto EH_Exit;
|
|
}
|
|
}
|
|
|
|
if (FileLines != NULL)
|
|
{
|
|
*FileLines = HighestLine;
|
|
}
|
|
|
|
// Return S_FALSE if lines were missed because of
|
|
// insufficient buffer space.
|
|
Status = HighestLine > BufferLines ? S_FALSE : S_OK;
|
|
|
|
EH_Exit:
|
|
LEAVE_ENGINE();
|
|
return Status;
|
|
}
|
|
|
|
STDMETHODIMP
|
|
DebugClient::GetModuleVersionInformation(
|
|
THIS_
|
|
IN ULONG Index,
|
|
IN ULONG64 Base,
|
|
IN PCSTR Item,
|
|
OUT OPTIONAL PVOID Buffer,
|
|
IN ULONG BufferSize,
|
|
OUT OPTIONAL PULONG VerInfoSize
|
|
)
|
|
{
|
|
HRESULT Status;
|
|
|
|
ENTER_ENGINE();
|
|
|
|
if (g_CurrentProcess == NULL)
|
|
{
|
|
Status = E_UNEXPECTED;
|
|
}
|
|
else
|
|
{
|
|
PDEBUG_IMAGE_INFO Image;
|
|
|
|
if (Index == DEBUG_ANY_ID)
|
|
{
|
|
Image = GetImageByOffset(g_CurrentProcess, Base);
|
|
}
|
|
else
|
|
{
|
|
Image = GetImageByIndex(g_CurrentProcess, Index);
|
|
}
|
|
if (Image == NULL)
|
|
{
|
|
Status = E_NOINTERFACE;
|
|
}
|
|
else
|
|
{
|
|
Status = g_Target->
|
|
GetImageVersionInformation(Image->ImagePath,
|
|
Image->BaseOfImage, Item,
|
|
Buffer, BufferSize, VerInfoSize);
|
|
}
|
|
}
|
|
|
|
LEAVE_ENGINE();
|
|
return Status;
|
|
}
|
|
|
|
STDMETHODIMP
|
|
DebugClient::GetModuleNameString(
|
|
THIS_
|
|
IN ULONG Which,
|
|
IN ULONG Index,
|
|
IN ULONG64 Base,
|
|
OUT OPTIONAL PSTR Buffer,
|
|
IN ULONG BufferSize,
|
|
OUT OPTIONAL PULONG NameSize
|
|
)
|
|
{
|
|
HRESULT Status;
|
|
|
|
if (Which > DEBUG_MODNAME_MAPPED_IMAGE)
|
|
{
|
|
return E_INVALIDARG;
|
|
}
|
|
|
|
ENTER_ENGINE();
|
|
|
|
if (g_CurrentProcess == NULL)
|
|
{
|
|
Status = E_UNEXPECTED;
|
|
}
|
|
else
|
|
{
|
|
ULONG Idx = 0;
|
|
|
|
Status = E_NOINTERFACE;
|
|
|
|
PDEBUG_IMAGE_INFO Image = g_CurrentProcess->ImageHead;
|
|
while (Image != NULL)
|
|
{
|
|
if ((Index != DEBUG_ANY_ID && Idx == Index) ||
|
|
(Index == DEBUG_ANY_ID && Base == Image->BaseOfImage))
|
|
{
|
|
PSTR Str;
|
|
DBH_MODSYMINFO SymFile;
|
|
IMAGEHLP_MODULE64 ModInfo;
|
|
|
|
switch(Which)
|
|
{
|
|
case DEBUG_MODNAME_IMAGE:
|
|
Str = Image->ImagePath;
|
|
break;
|
|
case DEBUG_MODNAME_MODULE:
|
|
Str = Image->ModuleName;
|
|
break;
|
|
case DEBUG_MODNAME_LOADED_IMAGE:
|
|
ModInfo.SizeOfStruct = sizeof(ModInfo);
|
|
if (!SymGetModuleInfo64(g_CurrentProcess->Handle,
|
|
Image->BaseOfImage, &ModInfo))
|
|
{
|
|
Status = WIN32_LAST_STATUS();
|
|
goto Exit;
|
|
}
|
|
Str = ModInfo.LoadedImageName;
|
|
break;
|
|
case DEBUG_MODNAME_SYMBOL_FILE:
|
|
SymFile.function = dbhModSymInfo;
|
|
SymFile.sizeofstruct = sizeof(SymFile);
|
|
SymFile.addr = Image->BaseOfImage;
|
|
if (!dbghelp(g_CurrentProcess->Handle, &SymFile))
|
|
{
|
|
Status = WIN32_LAST_STATUS();
|
|
goto Exit;
|
|
}
|
|
Str = SymFile.file;
|
|
break;
|
|
case DEBUG_MODNAME_MAPPED_IMAGE:
|
|
Str = Image->MappedImagePath;
|
|
break;
|
|
}
|
|
|
|
Status = FillStringBuffer(Str, 0,
|
|
Buffer, BufferSize, NameSize);
|
|
break;
|
|
}
|
|
|
|
Image = Image->Next;
|
|
Idx++;
|
|
}
|
|
}
|
|
|
|
Exit:
|
|
LEAVE_ENGINE();
|
|
return Status;
|
|
}
|
|
|
|
//----------------------------------------------------------------------------
|
|
//
|
|
// Routines to make DebugSymbolGroup show Extension functions
|
|
//
|
|
//----------------------------------------------------------------------------
|
|
|
|
|
|
CHAR g_ExtensionOutputDataBuffer[MAX_NAME];
|
|
|
|
class ExtenOutputCallbacks : public IDebugOutputCallbacks
|
|
{
|
|
public:
|
|
// IUnknown.
|
|
STDMETHOD(QueryInterface)(
|
|
THIS_
|
|
IN REFIID InterfaceId,
|
|
OUT PVOID* Interface
|
|
);
|
|
STDMETHOD_(ULONG, AddRef)(
|
|
THIS
|
|
);
|
|
STDMETHOD_(ULONG, Release)(
|
|
THIS
|
|
);
|
|
// IDebugOutputCallbacks.
|
|
STDMETHOD(Output)(
|
|
THIS_
|
|
IN ULONG Mask,
|
|
IN PCSTR Text
|
|
);
|
|
};
|
|
|
|
STDMETHODIMP
|
|
ExtenOutputCallbacks::QueryInterface(
|
|
THIS_
|
|
IN REFIID InterfaceId,
|
|
OUT PVOID* Interface
|
|
)
|
|
{
|
|
*Interface = NULL;
|
|
|
|
if (IsEqualIID(InterfaceId, IID_IUnknown) ||
|
|
IsEqualIID(InterfaceId, IID_IDebugOutputCallbacks))
|
|
{
|
|
*Interface = (IDebugOutputCallbacks *)this;
|
|
AddRef();
|
|
return S_OK;
|
|
}
|
|
else
|
|
{
|
|
return E_NOINTERFACE;
|
|
}
|
|
}
|
|
|
|
STDMETHODIMP_(ULONG)
|
|
ExtenOutputCallbacks::AddRef(
|
|
THIS
|
|
)
|
|
{
|
|
// This class is designed to be static so
|
|
// there's no true refcount.
|
|
return 1;
|
|
}
|
|
|
|
STDMETHODIMP_(ULONG)
|
|
ExtenOutputCallbacks::Release(
|
|
THIS
|
|
)
|
|
{
|
|
// This class is designed to be static so
|
|
// there's no true refcount.
|
|
return 0;
|
|
}
|
|
|
|
STDMETHODIMP
|
|
ExtenOutputCallbacks::Output(
|
|
THIS_
|
|
IN ULONG Mask,
|
|
IN PCSTR Text
|
|
)
|
|
{
|
|
if ((strlen(Text) +strlen(g_ExtensionOutputDataBuffer)) < MAX_NAME)
|
|
{
|
|
strcat(g_ExtensionOutputDataBuffer, Text);
|
|
}
|
|
return S_OK;
|
|
}
|
|
|
|
ExtenOutputCallbacks g_ExtensionOutputCallback;
|
|
|
|
//
|
|
// Print out 'Line' in a multiline string MultiLine
|
|
//
|
|
BOOL
|
|
OutputBufferLine(
|
|
PSTR MultiLine,
|
|
ULONG Line
|
|
)
|
|
{
|
|
CHAR toPrint[200];
|
|
PSTR Start, End;
|
|
|
|
Start = MultiLine;
|
|
while (Line && Start)
|
|
{
|
|
Start = strchr(Start, '\n')+1;
|
|
--Line;
|
|
}
|
|
if (Start)
|
|
{
|
|
End = strchr(Start, '\n');
|
|
|
|
if (End)
|
|
{
|
|
ULONG len = (ULONG) ((ULONG64) End - (ULONG64) Start);
|
|
if ((len+1) >= sizeof(toPrint)) {
|
|
len = sizeof(toPrint)-2;
|
|
}
|
|
toPrint[0] = 0;
|
|
strncat(toPrint, Start, len);
|
|
dprintf(toPrint);
|
|
} else
|
|
{
|
|
dprintf(Start);
|
|
}
|
|
return TRUE;
|
|
}
|
|
return FALSE;
|
|
}
|
|
|
|
|
|
#include "extsfns.h"
|
|
//
|
|
// EFN Structs
|
|
//
|
|
#ifndef FIELD_SIZE
|
|
#define FIELD_SIZE(type, field) (sizeof(((type *)0)->field))
|
|
#endif
|
|
|
|
#define DIS_FIELD_ENTRY(Type, Field) \
|
|
{#Field, FIELD_OFFSET(Type, Field), FIELD_SIZE(Type, Field), DGS_FldDefault, 0, 0}
|
|
#define DIS_BITFIELD_ENTRY(Type, Name, Field, Mask, Shift) \
|
|
{#Name, FIELD_OFFSET(Type, Field), FIELD_SIZE(Type, Field), DGS_FldBit, Mask, Shift}
|
|
|
|
DBG_GENERATED_STRUCT_FIELDS FieldsOf_DEBUG_POOL_DATA[] = {
|
|
DIS_FIELD_ENTRY(DEBUG_POOL_DATA, PoolBlock),
|
|
DIS_FIELD_ENTRY(DEBUG_POOL_DATA, Pool),
|
|
DIS_FIELD_ENTRY(DEBUG_POOL_DATA, PreviousSize),
|
|
DIS_FIELD_ENTRY(DEBUG_POOL_DATA, Size),
|
|
DIS_FIELD_ENTRY(DEBUG_POOL_DATA, PoolTag),
|
|
DIS_FIELD_ENTRY(DEBUG_POOL_DATA, ProcessBilled),
|
|
DIS_BITFIELD_ENTRY(DEBUG_POOL_DATA, Free, AsUlong, 1, 0),
|
|
DIS_BITFIELD_ENTRY(DEBUG_POOL_DATA, LargePool, AsUlong, 1, 1),
|
|
DIS_BITFIELD_ENTRY(DEBUG_POOL_DATA, SpecialPool, AsUlong, 1, 2),
|
|
DIS_BITFIELD_ENTRY(DEBUG_POOL_DATA, Pageable, AsUlong, 1, 3),
|
|
DIS_BITFIELD_ENTRY(DEBUG_POOL_DATA, Protected, AsUlong, 1, 4),
|
|
DIS_BITFIELD_ENTRY(DEBUG_POOL_DATA, Allocated, AsUlong, 1, 5),
|
|
{NULL, 0, 0, DGS_FldBit},
|
|
};
|
|
|
|
DBG_GENERATED_STRUCT_INFO g_InternalStructsInfo[] = {
|
|
{ 1, "-Any Extension-", 0, DGS_Extension, 0, NULL},
|
|
{ 2, "_EFN_GetPoolData", sizeof(DEBUG_POOL_DATA), DGS_EFN,
|
|
sizeof(FieldsOf_DEBUG_POOL_DATA)/sizeof(DBG_GENERATED_STRUCT_FIELDS)-1,
|
|
&FieldsOf_DEBUG_POOL_DATA[0]
|
|
},
|
|
{ -1, NULL, 0, DGS_EFN, 0},
|
|
};
|
|
|
|
|
|
typedef HRESULT
|
|
(WINAPI * PEFN_GENERIC_CALLER)(
|
|
IN PDEBUG_CLIENT Client,
|
|
IN ULONG64 Address,
|
|
OUT PVOID Buffer
|
|
);
|
|
|
|
PDBG_GENERATED_STRUCT_INFO
|
|
GetGeneratedStructInfo(
|
|
ULONG Id,
|
|
ULONG64 Handle
|
|
)
|
|
{
|
|
if (Handle == -1)
|
|
{
|
|
// one of internal debugger structs
|
|
|
|
return &g_InternalStructsInfo[Id - 1];
|
|
}
|
|
|
|
|
|
// Default to "any extension" type
|
|
return &g_InternalStructsInfo[0];
|
|
}
|
|
|
|
BOOL
|
|
MatchAndCopyGeneratedStructInfo(
|
|
PCHAR Name,
|
|
PDBG_GENERATED_STRUCT_INFO pGenStrInfo,
|
|
PDEBUG_SYMBOL_PARAMETERS_INTERNAL pSymParam
|
|
)
|
|
{
|
|
HRESULT Status = E_FAIL;
|
|
ULONG find;
|
|
for (find=0; pGenStrInfo[find].Name != NULL; find++)
|
|
{
|
|
if (!_stricmp(pGenStrInfo[find].Name, Name+1) &&
|
|
(strlen(Name) < sizeof(pSymParam->TypeName)))
|
|
{
|
|
pSymParam->Flags |= SYMBOL_IS_EXTENSION | TYPE_NAME_CHANGED;
|
|
pSymParam->TypeIndex = find+1;
|
|
pSymParam->Size = pGenStrInfo[find].Size;
|
|
strcpy(pSymParam->TypeName, Name);
|
|
pSymParam->External.Module = -1;
|
|
pSymParam->External.SubElements = pGenStrInfo[find].NumFields;
|
|
pSymParam->External.Flags |= DEBUG_SYMBOL_READ_ONLY;
|
|
#ifdef DBG_SYMGROUP_ENABLED
|
|
dprintf("Added Internal struct %lx\n", pGenStrInfo[find].Id);
|
|
#endif
|
|
return TRUE;
|
|
}
|
|
}
|
|
|
|
return FALSE;
|
|
}
|
|
|
|
HRESULT
|
|
AddExtensionAsType(
|
|
PCHAR Extension,
|
|
PDEBUG_SYMBOL_PARAMETERS_INTERNAL pSymParam
|
|
)
|
|
{
|
|
HRESULT Status = E_FAIL;
|
|
ULONG find;
|
|
|
|
if (MatchAndCopyGeneratedStructInfo(Extension, &g_InternalStructsInfo[0], pSymParam))
|
|
{
|
|
Status = S_OK;
|
|
}
|
|
|
|
if (Status != S_OK)
|
|
{
|
|
// Nothing mached, default to generic extension type
|
|
find = 0;
|
|
pSymParam->Flags |= SYMBOL_IS_EXTENSION | TYPE_NAME_CHANGED;
|
|
pSymParam->TypeIndex = g_InternalStructsInfo[find].Id;
|
|
pSymParam->Size = g_InternalStructsInfo[find].Size;
|
|
strcpy(pSymParam->TypeName, Extension);
|
|
pSymParam->External.Module = -1;
|
|
pSymParam->External.SubElements = 0;
|
|
Status = S_OK;
|
|
|
|
}
|
|
|
|
return Status;
|
|
}
|
|
|
|
HRESULT
|
|
OutputExtensionForSymGrp(
|
|
PDEBUG_SYMBOL_PARAMETERS_INTERNAL pSymParam,
|
|
DebugClient *Client
|
|
)
|
|
{
|
|
HRESULT Status = E_FAIL;
|
|
|
|
if (!(pSymParam->Flags & SYMBOL_IS_EXTENSION))
|
|
{
|
|
return E_INVALIDARG;
|
|
}
|
|
|
|
PDBG_GENERATED_STRUCT_INFO pExtnInfo;
|
|
|
|
pExtnInfo = GetGeneratedStructInfo(pSymParam->TypeIndex, pSymParam->External.Module);
|
|
|
|
if (!pExtnInfo)
|
|
{
|
|
return E_INVALIDARG;
|
|
}
|
|
|
|
if (pExtnInfo->Type == DGS_Extension)
|
|
{
|
|
ULONG ShowLine = 0;
|
|
PVOID DataBuffer;
|
|
if (pSymParam->SymbolIndex == pSymParam->External.ParentSymbol)
|
|
{
|
|
DataBuffer = pSymParam->DataBuffer;
|
|
// dprintf("Tarpped %s", g_ExtensionOutputDataBuffer);
|
|
} else
|
|
{
|
|
ShowLine = (ULONG) pSymParam->Offset;
|
|
DataBuffer = pSymParam->Parent->DataBuffer;
|
|
}
|
|
OutputBufferLine((PSTR) DataBuffer, ShowLine);
|
|
} else if (pExtnInfo->Type = DGS_EFN)
|
|
{
|
|
if (pSymParam->SymbolIndex == pSymParam->External.ParentSymbol)
|
|
{
|
|
EXTDLL* Ext = g_ExtDlls;
|
|
while (Ext!=NULL)
|
|
{
|
|
if ((ULONG64) Ext == pSymParam->External.Module)
|
|
{
|
|
break;
|
|
}
|
|
Ext = Ext->Next;
|
|
}
|
|
if (Ext)
|
|
{
|
|
dprintf("%s.%s", Ext->Name, pExtnInfo->Name);
|
|
} else
|
|
{
|
|
dprintf("EFN not found");
|
|
}
|
|
|
|
} else
|
|
{
|
|
// print child value as recieved from parent buffer
|
|
PVOID Buffer;
|
|
|
|
if (Buffer = pSymParam->Parent->DataBuffer)
|
|
{
|
|
ULONG64 Value = 0;
|
|
|
|
memcpy(&Value, (PCHAR) Buffer + pSymParam->Offset,
|
|
min(sizeof(Value), pSymParam->Size));
|
|
|
|
if (pSymParam->Mask)
|
|
{
|
|
dprintf("%I64lx", (Value >> pSymParam->Shift) & pSymParam->Mask);
|
|
} else
|
|
{
|
|
dprintf("%I64lx", Value);
|
|
}
|
|
} else
|
|
{
|
|
dprintf("Error in retriving value");
|
|
}
|
|
}
|
|
}
|
|
return S_OK;
|
|
}
|
|
|
|
HRESULT
|
|
FindChildrenForExtensionSym(
|
|
PDEBUG_SYMBOL_PARAMETERS_INTERNAL pParentSym,
|
|
PDEBUG_SYMBOL_PARAMETERS_INTERNAL *pChildren,
|
|
PULONG pChildCount,
|
|
PCHAR *pChildNames
|
|
)
|
|
{
|
|
HRESULT Status = E_FAIL;
|
|
ULONG ChildCount=0;
|
|
|
|
if (!(pParentSym->Flags & SYMBOL_IS_EXTENSION) ||
|
|
(pParentSym->External.ParentSymbol != pParentSym->SymbolIndex) )
|
|
{
|
|
return E_INVALIDARG;
|
|
}
|
|
|
|
PDBG_GENERATED_STRUCT_INFO pParentInfo;
|
|
|
|
pParentInfo = GetGeneratedStructInfo(pParentSym->TypeIndex, pParentSym->External.Module);
|
|
|
|
if (!pParentInfo)
|
|
{
|
|
return E_INVALIDARG;
|
|
}
|
|
|
|
//
|
|
// Extensions
|
|
//
|
|
if (pParentInfo->Type == DGS_Extension)
|
|
{
|
|
ULONG nLines;
|
|
|
|
// Do we have any output buffer stored?
|
|
if (!pParentSym->DataBuffer)
|
|
{
|
|
*pChildCount = 0;
|
|
return E_FAIL;
|
|
}
|
|
|
|
// Number of children == number of newlines - 1
|
|
PCHAR scan = strchr((char *) pParentSym->DataBuffer, '\n');
|
|
nLines = 0;
|
|
while (scan)
|
|
{
|
|
++nLines; ++scan;
|
|
scan = strchr(scan, '\n');
|
|
}
|
|
|
|
if (!nLines)
|
|
{
|
|
*pChildCount = 0;
|
|
return E_FAIL;
|
|
}
|
|
|
|
*pChildNames = NULL;
|
|
*pChildren = (PDEBUG_SYMBOL_PARAMETERS_INTERNAL) malloc(
|
|
nLines * sizeof( DEBUG_SYMBOL_PARAMETERS_INTERNAL ));
|
|
if (*pChildren == NULL)
|
|
{
|
|
return E_OUTOFMEMORY;
|
|
}
|
|
|
|
pParentSym->External.SubElements = nLines;
|
|
ZeroMemory(*pChildren, nLines * sizeof( DEBUG_SYMBOL_PARAMETERS_INTERNAL ));
|
|
for (ULONG ChildCount = 0; ChildCount < nLines; ChildCount++)
|
|
{
|
|
(*pChildren)[ChildCount].External.ParentSymbol = pParentSym->SymbolIndex;
|
|
(*pChildren)[ChildCount].External.Flags = DEBUG_SYMBOL_READ_ONLY |
|
|
((UCHAR) pParentSym->External.Flags + 1);
|
|
(*pChildren)[ChildCount].External.Module = pParentSym->External.Module;
|
|
(*pChildren)[ChildCount].Parent = pParentSym;
|
|
(*pChildren)[ChildCount].Name.Buffer = " ";
|
|
(*pChildren)[ChildCount].Name.Length = (*pChildren)[ChildCount].Name.MaximumLength = 6;
|
|
(*pChildren)[ChildCount].Offset = ChildCount+1;
|
|
(*pChildren)[ChildCount].TypeIndex = pParentSym->TypeIndex;
|
|
(*pChildren)[ChildCount].Flags = SYMBOL_IS_EXTENSION;
|
|
}
|
|
return S_OK;
|
|
|
|
}
|
|
|
|
|
|
//
|
|
// EFN Structs
|
|
//
|
|
if (!pParentInfo->Fields)
|
|
{
|
|
return E_INVALIDARG;
|
|
}
|
|
assert(pParentSym->TypeIndex == pParentInfo->Id);
|
|
|
|
for (ChildCount=0; pParentInfo->Fields[ChildCount].Name != NULL; ChildCount++) ;
|
|
pParentSym->External.SubElements = ChildCount;
|
|
|
|
*pChildNames = NULL;
|
|
*pChildren = (PDEBUG_SYMBOL_PARAMETERS_INTERNAL) malloc(
|
|
ChildCount * sizeof( DEBUG_SYMBOL_PARAMETERS_INTERNAL ));
|
|
if (*pChildren == NULL)
|
|
{
|
|
return E_OUTOFMEMORY;
|
|
}
|
|
ZeroMemory(*pChildren, ChildCount * sizeof( DEBUG_SYMBOL_PARAMETERS_INTERNAL ));
|
|
for (ChildCount=0; pParentInfo->Fields[ChildCount].Name != NULL; ChildCount++)
|
|
{
|
|
(*pChildren)[ChildCount].External.ParentSymbol = pParentSym->SymbolIndex;
|
|
(*pChildren)[ChildCount].External.Flags = DEBUG_SYMBOL_READ_ONLY |
|
|
((UCHAR) pParentSym->External.Flags + 1);
|
|
(*pChildren)[ChildCount].External.Module = pParentSym->External.Module;
|
|
(*pChildren)[ChildCount].Parent = pParentSym;
|
|
(*pChildren)[ChildCount].Name.Buffer = pParentInfo->Fields[ChildCount].Name;
|
|
(*pChildren)[ChildCount].Name.Length = (*pChildren)[ChildCount].Name.MaximumLength =
|
|
strlen((*pChildren)[ChildCount].Name.Buffer)+1;
|
|
(*pChildren)[ChildCount].Offset = pParentInfo->Fields[ChildCount].Offset;
|
|
(*pChildren)[ChildCount].TypeIndex = pParentSym->TypeIndex;
|
|
(*pChildren)[ChildCount].Flags = SYMBOL_IS_EXTENSION;
|
|
(*pChildren)[ChildCount].Size = pParentInfo->Fields[ChildCount].Size;
|
|
(*pChildren)[ChildCount].Mask = pParentInfo->Fields[ChildCount].BitMask;
|
|
(*pChildren)[ChildCount].Shift = pParentInfo->Fields[ChildCount].BitShift;
|
|
}
|
|
|
|
return S_OK;
|
|
}
|
|
|
|
HRESULT
|
|
RefreshExtensionSymbolParemeter(
|
|
PDEBUG_SYMBOL_PARAMETERS_INTERNAL pSymParam,
|
|
DebugClient *Client
|
|
)
|
|
{
|
|
HRESULT Status = E_FAIL;
|
|
ULONG ChildCount=0;
|
|
|
|
if (!(pSymParam->Flags & SYMBOL_IS_EXTENSION))
|
|
{
|
|
return E_INVALIDARG;
|
|
}
|
|
PDBG_GENERATED_STRUCT_INFO pExtnInfo;
|
|
|
|
pExtnInfo = GetGeneratedStructInfo(pSymParam->TypeIndex, pSymParam->External.Module);
|
|
|
|
if (!pExtnInfo)
|
|
{
|
|
return E_INVALIDARG;
|
|
}
|
|
|
|
if (pExtnInfo->Type == DGS_Extension)
|
|
{
|
|
CHAR ExtArg[50];
|
|
PDEBUG_OUTPUT_CALLBACKS OutCbSave;
|
|
|
|
Client->FlushCallbacks();
|
|
OutCbSave = Client->m_OutputCb ;
|
|
|
|
OutCtlSave OldCtl;
|
|
|
|
if (PushOutCtl(DEBUG_OUTCTL_THIS_CLIENT | DEBUG_OUTCTL_OVERRIDE_MASK |DEBUG_OUTCTL_NOT_LOGGED,
|
|
Client, &OldCtl))
|
|
{
|
|
g_ExtensionOutputDataBuffer[0] = 0;
|
|
Client->m_OutputCb = &g_ExtensionOutputCallback;
|
|
|
|
sprintf(ExtArg, "%I64lx", pSymParam->Address);
|
|
|
|
CallAnyExtension(Client, NULL, pSymParam->TypeName+1, ExtArg, FALSE, FALSE, &Status);
|
|
|
|
PopOutCtl(&OldCtl);
|
|
|
|
}
|
|
Client->FlushCallbacks();
|
|
Client->m_OutputCb = OutCbSave;
|
|
|
|
if (pSymParam->DataBuffer)
|
|
{
|
|
free (pSymParam->DataBuffer);
|
|
}
|
|
pSymParam->DataBuffer = malloc(strlen(g_ExtensionOutputDataBuffer) + 1);
|
|
strcpy((char*)pSymParam->DataBuffer, g_ExtensionOutputDataBuffer);
|
|
if (!pSymParam->Expanded && strchr(g_ExtensionOutputDataBuffer, '\n'))
|
|
{
|
|
// Let caller know this can be expanded,
|
|
// number of che=ildren will be figured out by ExpandSymbol
|
|
pSymParam->External.SubElements = 1;
|
|
}
|
|
} else
|
|
{
|
|
|
|
if (pExtnInfo->Type = DGS_EFN)
|
|
{
|
|
PEFN_GENERIC_CALLER EfnRoutine;
|
|
EXTDLL* Ext;
|
|
Ext = g_ExtDlls;
|
|
|
|
if (pSymParam->SymbolIndex == pSymParam->External.ParentSymbol)
|
|
{
|
|
while (Ext!=NULL)
|
|
{
|
|
if (LoadExtensionDll(Ext))
|
|
{
|
|
EfnRoutine = (PEFN_GENERIC_CALLER) GetProcAddress(Ext->Dll, pExtnInfo->Name);
|
|
if (EfnRoutine != NULL)
|
|
{
|
|
Status = S_OK;
|
|
break;
|
|
}
|
|
}
|
|
|
|
Ext = Ext->Next;
|
|
|
|
}
|
|
pSymParam->External.Module = (ULONG64) Ext;
|
|
// Call EFN and get the value
|
|
PVOID Buffer = pSymParam->DataBuffer;
|
|
|
|
if (!Buffer)
|
|
{
|
|
Buffer = malloc(pExtnInfo->Size);
|
|
}
|
|
if (Buffer)
|
|
{
|
|
*((PULONG) Buffer) = pExtnInfo->Size;
|
|
|
|
if ((*EfnRoutine)((PDEBUG_CLIENT)Client, pSymParam->Address, Buffer) == S_OK)
|
|
{
|
|
pSymParam->DataBuffer = Buffer;
|
|
} else
|
|
{
|
|
free (Buffer);
|
|
}
|
|
}
|
|
} else
|
|
{
|
|
// nothing to do for EFN subelements, they always use
|
|
// parents databuffer
|
|
}
|
|
}
|
|
|
|
|
|
}
|
|
|
|
return S_OK;
|
|
}
|
|
//----------------------------------------------------------------------------
|
|
//
|
|
// DebugSymbolGroup helpers
|
|
//
|
|
//----------------------------------------------------------------------------
|
|
|
|
|
|
//
|
|
// Initialize DEBUG_SYMBOL_PARAMETERS_INTERNAL from TYPES_INFO_ALL
|
|
//
|
|
void
|
|
TypToParam(PTYPES_INFO_ALL pTyp, PDEBUG_SYMBOL_PARAMETERS_INTERNAL pParam)
|
|
{
|
|
pParam->Address = pTyp->Address;
|
|
pParam->Flags = pTyp->Flags;
|
|
pParam->ExpandTypeAddress = pTyp->SubAddr;
|
|
pParam->External.SubElements = pTyp->SubElements;
|
|
pParam->Size = pTyp->Size;
|
|
pParam->TypeIndex = pTyp->TypeIndex;
|
|
pParam->Register = pTyp->Register;
|
|
pParam->Offset = pTyp->Offset;
|
|
pParam->External.Module = pTyp->Module;
|
|
pParam->External.TypeId = pTyp->TypeIndex;
|
|
return;
|
|
}
|
|
|
|
//
|
|
// Show / compare corresponding values of TYPES_INFO_ALL and DEBUG_SYMBOL_PARAMETERS_INTERNAL
|
|
//
|
|
void
|
|
ShowDiff(PTYPES_INFO_ALL pTyp, PDEBUG_SYMBOL_PARAMETERS_INTERNAL pParam)
|
|
{
|
|
#ifdef DBG_SYMGROUP_ENABLED
|
|
dprintf("Address \t%8I64lx %8I64lx\n", pParam->Address ,pTyp->Address);
|
|
dprintf("Flags \t%8lx %8lx\n", pParam->Flags ,pTyp->Flags);
|
|
dprintf("ExpAddr \t%8I64lx %8I64lx\n", pParam->ExpandTypeAddress ,pTyp->SubAddr);
|
|
dprintf("Ext.SubEts\t%8lx %8lx\n", pParam->External.SubElements ,pTyp->SubElements);
|
|
dprintf("Size \t%8lx %8lx\n", pParam->Size ,pTyp->Size);
|
|
dprintf("TypeIndex \t%8lx %8lx\n", pParam->TypeIndex ,pTyp->TypeIndex);
|
|
dprintf("Register \t%8lx %8lx\n", pParam->Register ,pTyp->Register);
|
|
dprintf("Offset \t%8I64lx %8I64lx\n", pParam->Offset ,pTyp->Offset);
|
|
dprintf("ExtModule \t%8I64lx %8I64lx\n", pParam->External.Module ,pTyp->Module);
|
|
dprintf("ExtId \t%8lx %8lx\n", pParam->External.TypeId ,pTyp->TypeIndex);
|
|
#endif
|
|
return;
|
|
}
|
|
|
|
|
|
//
|
|
// Resolves the typecast vaulue and updates the symbol parameters
|
|
//
|
|
// Typecast : type string to resolve
|
|
//
|
|
// pSymParam : It has the appropriate values for given symbol as a result
|
|
// of typecast
|
|
//
|
|
HRESULT
|
|
ResolveTypecast(
|
|
PCHAR Typecast,
|
|
PDEBUG_SYMBOL_PARAMETERS_INTERNAL pSymParam
|
|
)
|
|
{
|
|
HRESULT Status;
|
|
ANSI_STRING TypeName;
|
|
TYPES_INFO typeInfo;
|
|
|
|
Status = E_INVALIDARG;
|
|
if (*Typecast == '!')
|
|
{
|
|
// Its an extension
|
|
Status = AddExtensionAsType(Typecast, pSymParam);
|
|
} else
|
|
{
|
|
SYM_DUMP_PARAM_EX Sym;
|
|
|
|
ZeroMemory(&typeInfo, sizeof(typeInfo));
|
|
ZeroMemory(&Sym, sizeof(Sym));
|
|
|
|
Sym.Options = NO_PRINT;
|
|
Sym.sName = (PUCHAR) Typecast;
|
|
Sym.size = sizeof(SYM_DUMP_PARAM_EX);
|
|
|
|
if (!TypeInfoFound(g_CurrentProcess->Handle,
|
|
g_CurrentProcess->ImageHead,
|
|
&Sym,
|
|
&typeInfo))
|
|
{
|
|
// We got a valid type name
|
|
|
|
if (strlen(Typecast) < sizeof(pSymParam->TypeName))
|
|
{
|
|
strcpy(pSymParam->TypeName, Typecast);
|
|
if ((pSymParam->TypeIndex != typeInfo.TypeIndex) ||
|
|
(pSymParam->External.Module != typeInfo.ModBaseAddress))
|
|
{
|
|
pSymParam->Flags |= TYPE_NAME_CHANGED;
|
|
}
|
|
|
|
Status = S_OK;
|
|
}
|
|
else
|
|
{
|
|
pSymParam->Flags &= ~TYPE_NAME_MASK;
|
|
}
|
|
|
|
pSymParam->TypeIndex = typeInfo.TypeIndex;
|
|
pSymParam->External.Module = typeInfo.ModBaseAddress;
|
|
}
|
|
|
|
|
|
}
|
|
return Status;
|
|
}
|
|
|
|
|
|
//
|
|
// Refresh paremeters for a symbol
|
|
//
|
|
HRESULT
|
|
RefreshSymbolParemeter(
|
|
PDEBUG_SYMBOL_PARAMETERS_INTERNAL pSymParam,
|
|
DebugClient * Client
|
|
)
|
|
{
|
|
CHAR TmpName[MAX_NAME], *pTmpName;
|
|
HRESULT Status = S_OK;
|
|
|
|
if (pSymParam->Flags & SYMBOL_IS_EXTENSION)
|
|
{
|
|
return RefreshExtensionSymbolParemeter(pSymParam, Client);
|
|
}
|
|
|
|
if (pSymParam &&
|
|
((!(pSymParam->External.Flags & DEBUG_SYMBOL_EXPANSION_LEVEL_MASK) ||
|
|
(pSymParam->Flags & TYPE_NAME_CHANGED))))
|
|
{
|
|
//
|
|
// Symbol's type might have changed
|
|
//
|
|
SYM_DUMP_PARAM_EX Sym = {0};
|
|
TYPES_INFO typeInfo = {0};
|
|
ULONG TypeStatus = 0;
|
|
|
|
Sym.size = sizeof(SYM_DUMP_PARAM_EX);
|
|
Sym.Options = DBG_RETURN_TYPE| DBG_RETURN_TYPE_VALUES | NO_PRINT ;
|
|
if (pSymParam->Flags & (TYPE_NAME_CHANGED | TYPE_NAME_USED))
|
|
{
|
|
Sym.sName = (PUCHAR) pSymParam->TypeName;
|
|
}
|
|
else
|
|
{
|
|
Sym.sName = (PUCHAR) pSymParam->Name.Buffer;
|
|
}
|
|
|
|
if (pSymParam->Flags & SYMBOL_IS_EXPRESSION) {
|
|
// The expression ight have changed
|
|
pSymParam->Address = ExtGetExpression(pSymParam->Name.Buffer);
|
|
}
|
|
|
|
if (pSymParam->External.Module &&
|
|
!strchr((PCHAR) Sym.sName, '!') && // We already have mod! in the name
|
|
!(*Sym.sName == '&' || *Sym.sName == '*') &&
|
|
!(pSymParam->Flags & SYMBOL_IS_EXPRESSION) // Do no display mod! if name entered was expression
|
|
)
|
|
{
|
|
pTmpName = &TmpName[0];
|
|
|
|
// If symbol runs out of scope, this causes lookup in all modules
|
|
// Search only in its last valid module to avoid slowing down debugger
|
|
if (GetModuleName(pSymParam->External.Module, pTmpName, sizeof(TmpName)))
|
|
{
|
|
strcat(pTmpName, "!");
|
|
strcat(pTmpName, (PCHAR) Sym.sName);
|
|
Sym.sName = (PUCHAR) &TmpName[0];
|
|
}
|
|
}
|
|
|
|
if (((pSymParam->Flags & (TYPE_NAME_CHANGED | TYPE_NAME_USED)) &&
|
|
!TypeInfoFound(g_CurrentProcess->Handle,
|
|
g_CurrentProcess->ImageHead,
|
|
&Sym,
|
|
&typeInfo)) &&
|
|
(typeInfo.SymAddress ||
|
|
Sym.addr ||
|
|
(pSymParam->Flags & (TYPE_NAME_CHANGED | TYPE_NAME_USED))))
|
|
{
|
|
|
|
if ((pSymParam->Flags & TYPE_NAME_USED) &&
|
|
!(pSymParam->Flags & TYPE_NAME_CHANGED))
|
|
{
|
|
//
|
|
// We'd typecast this, and types do not change with scope
|
|
//
|
|
}
|
|
else if (typeInfo.SymAddress != pSymParam->Address ||
|
|
typeInfo.TypeIndex != pSymParam->TypeIndex ||
|
|
typeInfo.ModBaseAddress != pSymParam->External.Module)
|
|
{
|
|
//
|
|
// The name refers to different symbol now
|
|
//
|
|
|
|
if (pSymParam->Flags & TYPE_NAME_CHANGED)
|
|
{
|
|
// Just a type cast, keep old address
|
|
typeInfo.SymAddress = pSymParam->Address;
|
|
typeInfo.Flag = pSymParam->Flags & ADDRESS_TRANSLATION_MASK;
|
|
typeInfo.Value = pSymParam->Register;
|
|
}
|
|
else
|
|
{
|
|
// Change address if not a typecast
|
|
pSymParam->Address = typeInfo.SymAddress;
|
|
pSymParam->Flags = typeInfo.Flag & ADDRESS_TRANSLATION_MASK;
|
|
}
|
|
|
|
pSymParam->TypeIndex = typeInfo.TypeIndex;
|
|
pSymParam->External.Module = typeInfo.ModBaseAddress;
|
|
pSymParam->External.TypeId = typeInfo.TypeIndex;
|
|
pSymParam->Register = (ULONG) typeInfo.Value;
|
|
|
|
DEBUG_SYMBOL_PARAMETERS SavedExt;
|
|
BOOL wasExpanded = FALSE;
|
|
if (pSymParam->External.Flags & DEBUG_SYMBOL_EXPANDED)
|
|
{
|
|
SavedExt = pSymParam->External;
|
|
wasExpanded = TRUE;
|
|
}
|
|
|
|
Sym.Options = DBG_RETURN_TYPE | NO_PRINT;
|
|
Sym.addr = pSymParam->Address;
|
|
|
|
FIND_TYPE_INFO Info;
|
|
Info.Flags = DBG_RETURN_TYPE ;
|
|
Info.InternalParams = pSymParam; Info.nParams = 1;
|
|
DumpTypeAndReturnInfo(&typeInfo, &Sym,
|
|
&TypeStatus, &Info);
|
|
if (wasExpanded)
|
|
{
|
|
pSymParam->External.Flags = SavedExt.Flags;
|
|
pSymParam->External.SubElements = SavedExt.SubElements;
|
|
}
|
|
if (TypeStatus)
|
|
{
|
|
Status = E_INVALIDARG;
|
|
}
|
|
if (pSymParam->Size && (pSymParam->Size <= sizeof(ULONG64)))
|
|
{
|
|
pSymParam->External.Flags &= ~DEBUG_SYMBOL_READ_ONLY;
|
|
}
|
|
else
|
|
{
|
|
pSymParam->External.Flags |= DEBUG_SYMBOL_READ_ONLY;
|
|
}
|
|
}
|
|
}
|
|
else
|
|
{
|
|
TYPES_INFO_ALL typ;
|
|
|
|
if (GetExpressionTypeInfo((PCHAR) Sym.sName, &typ))
|
|
{
|
|
DEBUG_SYMBOL_PARAMETERS SavedExt={0};
|
|
BOOL wasExpanded=FALSE;
|
|
if (pSymParam->External.Flags & DEBUG_SYMBOL_EXPANDED)
|
|
{
|
|
SavedExt = pSymParam->External;
|
|
wasExpanded = TRUE;
|
|
}
|
|
|
|
ShowDiff(&typ, pSymParam);
|
|
TypToParam(&typ, pSymParam);
|
|
|
|
if (wasExpanded)
|
|
{
|
|
pSymParam->External.Flags = SavedExt.Flags;
|
|
pSymParam->External.SubElements = SavedExt.SubElements;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
//
|
|
// Force error in output
|
|
//
|
|
pSymParam->TypeIndex = 0;
|
|
pSymParam->ExpandTypeAddress = 0;
|
|
|
|
// Remove children
|
|
if (pSymParam->External.Flags & DEBUG_SYMBOL_EXPANDED)
|
|
{
|
|
pSymParam->Expanded = FALSE;
|
|
pSymParam->External.Flags &= ~DEBUG_SYMBOL_EXPANDED;
|
|
pSymParam->External.SubElements = 0;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
if (pSymParam->Flags & TYPE_NAME_CHANGED)
|
|
{
|
|
pSymParam->Flags &= ~TYPE_NAME_CHANGED;
|
|
pSymParam->Flags |= TYPE_NAME_USED | TYPE_NAME_VALID;
|
|
}
|
|
|
|
|
|
return Status;
|
|
}
|
|
|
|
|
|
//
|
|
// Output value of the symbol
|
|
//
|
|
HRESULT
|
|
OutputDbgSymValue(
|
|
PDEBUG_SYMBOL_PARAMETERS_INTERNAL pSymParam,
|
|
DebugClient *Client
|
|
)
|
|
{
|
|
FIND_TYPE_INFO Info;
|
|
TYPE_DUMP_INTERNAL tdi;
|
|
SYM_DUMP_PARAM_EX Sym;
|
|
TYPES_INFO typeInfo;
|
|
ULONG SubTypes;
|
|
BOOL TypeChanged = FALSE, Expanded;
|
|
ULONG64 Value;
|
|
DEBUG_SYMBOL_PARAMETERS_INTERNAL TempSym;
|
|
|
|
if (pSymParam->Flags & SYMBOL_IS_EXTENSION)
|
|
{
|
|
return OutputExtensionForSymGrp(pSymParam, Client);
|
|
}
|
|
|
|
ZeroMemory(&Sym, sizeof(Sym));
|
|
ZeroMemory(&tdi, sizeof(tdi));
|
|
|
|
SubTypes = pSymParam->External.SubElements;
|
|
Expanded = pSymParam->External.Flags & DEBUG_SYMBOL_EXPANDED;
|
|
Sym.Options = tdi.TypeOptions = DBG_RETURN_TYPE| DBG_RETURN_TYPE_VALUES | NO_PRINT;
|
|
Sym.sName = (PUCHAR) pSymParam->Name.Buffer;
|
|
Sym.size = sizeof(SYM_DUMP_PARAM_EX);
|
|
|
|
if (pSymParam->Flags & TYPE_NAME_USED)
|
|
{
|
|
Sym.sName = (PUCHAR) &pSymParam->TypeName[0];
|
|
}
|
|
if (pSymParam->Parent)
|
|
{
|
|
pSymParam->Address = Sym.addr = pSymParam->Offset + pSymParam->Parent->ExpandTypeAddress;
|
|
}
|
|
else
|
|
{
|
|
Sym.addr = pSymParam->Address;
|
|
}
|
|
|
|
tdi.pSymParams = NULL;
|
|
tdi.level = 1;
|
|
tdi.NumSymParams = 1;
|
|
tdi.IsAVar = 1;
|
|
Value = pSymParam->Register;
|
|
typeInfo.hProcess = tdi.hProcess = g_CurrentProcess->Handle;
|
|
typeInfo.ModBaseAddress = tdi.modBaseAddr =
|
|
pSymParam->External.Module;
|
|
typeInfo.TypeIndex = pSymParam->TypeIndex;
|
|
typeInfo.SymAddress = pSymParam->Address;
|
|
typeInfo.Flag = pSymParam->Flags & ADDRESS_TRANSLATION_MASK;
|
|
typeInfo.Value = Value;
|
|
|
|
tdi.FieldOptions = pSymParam->Flags & STRING_DUMP_MASK;
|
|
|
|
if (pSymParam->TypeIndex)
|
|
{
|
|
Info.Flags = DBG_RETURN_TYPE ;
|
|
Info.InternalParams = &TempSym; Info.nParams = 1;
|
|
|
|
TempSym = *pSymParam;
|
|
DumpTypeAndReturnInfo(&typeInfo, &Sym, (PULONG) &tdi.ErrorStatus, &Info);
|
|
|
|
// Statements below corrupt the number of subelements and their address
|
|
// pSymParam->External.SubElements = Info.FullInfo.SubElements;
|
|
// pSymParam->ExpandTypeAddress = Info.ParentExpandAddress;
|
|
|
|
if (tdi.ErrorStatus)
|
|
{
|
|
// dprintf("Error : Cannot get value");
|
|
}
|
|
}
|
|
else if (pSymParam->Flags & SYMBOL_IS_EXPRESSION)
|
|
{
|
|
// We only have an address as symbol name, is hasn't
|
|
// been typecasted (correctly) yet
|
|
// Display what we have as address
|
|
dprintf("%p", pSymParam->Address);
|
|
}
|
|
else
|
|
{
|
|
dprintf("Error : Cannot get value");
|
|
}
|
|
if (Expanded)
|
|
{
|
|
//
|
|
// Keep the number of elements we expanded it with
|
|
//
|
|
pSymParam->External.SubElements = SubTypes;
|
|
pSymParam->Expanded = TRUE;
|
|
pSymParam->External.Flags |= DEBUG_SYMBOL_EXPANDED;
|
|
}
|
|
|
|
|
|
return S_OK;
|
|
}
|
|
|
|
|
|
//----------------------------------------------------------------------------
|
|
//
|
|
// IDebugSymbolGroup.
|
|
//
|
|
//----------------------------------------------------------------------------
|
|
|
|
#include "symtype.h"
|
|
|
|
DebugSymbolGroup::DebugSymbolGroup(
|
|
DebugClient *CreatedBy
|
|
)
|
|
{
|
|
m_Refs = 1;
|
|
m_pSymParams = NULL;
|
|
m_NumParams = 0;
|
|
m_pCreatedBy = CreatedBy;
|
|
m_Locals = FALSE;;
|
|
m_ScopeGroup = DEBUG_SCOPE_GROUP_ALL;
|
|
}
|
|
|
|
DebugSymbolGroup::DebugSymbolGroup(
|
|
DebugClient *CreatedBy,
|
|
ULONG ScopeGroup
|
|
)
|
|
{
|
|
m_Refs = 1;
|
|
m_pSymParams = NULL;
|
|
m_NumParams = 0;
|
|
m_pCreatedBy = CreatedBy;
|
|
m_Locals = ScopeGroup == DEBUG_SCOPE_GROUP_LOCALS;
|
|
m_ScopeGroup = ScopeGroup;
|
|
m_LastClassExpanded = TRUE;
|
|
m_thisAdjust = 0;
|
|
}
|
|
|
|
DebugSymbolGroup::~DebugSymbolGroup(void)
|
|
{
|
|
ENTER_ENGINE();
|
|
DeleteSymbolParam(0, m_NumParams);
|
|
LEAVE_ENGINE();
|
|
}
|
|
|
|
STDMETHODIMP
|
|
DebugSymbolGroup::QueryInterface(
|
|
THIS_
|
|
IN REFIID InterfaceId,
|
|
OUT PVOID* Interface
|
|
)
|
|
{
|
|
HRESULT Status;
|
|
|
|
*Interface = NULL;
|
|
Status = S_OK;
|
|
|
|
if (DbgIsEqualIID(InterfaceId, IID_IUnknown) ||
|
|
DbgIsEqualIID(InterfaceId, IID_IDebugSymbolGroup))
|
|
{
|
|
AddRef();
|
|
*Interface = (IDebugSymbolGroup *)this;
|
|
}
|
|
else
|
|
{
|
|
Status = E_NOINTERFACE;
|
|
}
|
|
|
|
return Status;
|
|
}
|
|
|
|
STDMETHODIMP_(ULONG)
|
|
DebugSymbolGroup::AddRef(
|
|
THIS
|
|
)
|
|
{
|
|
return InterlockedIncrement((PLONG)&m_Refs);
|
|
}
|
|
|
|
STDMETHODIMP_(ULONG)
|
|
DebugSymbolGroup::Release(
|
|
THIS
|
|
)
|
|
{
|
|
LONG Refs = InterlockedDecrement((PLONG)&m_Refs);
|
|
if (Refs == 0)
|
|
{
|
|
delete this;
|
|
}
|
|
return Refs;
|
|
}
|
|
|
|
// #define DBG 1
|
|
|
|
STDMETHODIMP
|
|
DebugSymbolGroup::GetNumberSymbols(
|
|
THIS_
|
|
OUT PULONG Number
|
|
)
|
|
{
|
|
*Number = m_NumParams;
|
|
return S_OK;
|
|
}
|
|
|
|
int __cdecl
|
|
CompareSymParamNames(
|
|
const void *Sym1,
|
|
const void *Sym2
|
|
)
|
|
{
|
|
PDEBUG_SYMBOL_PARAMETERS_INTERNAL S1 = *((PDEBUG_SYMBOL_PARAMETERS_INTERNAL *) Sym1);
|
|
PDEBUG_SYMBOL_PARAMETERS_INTERNAL S2 = *((PDEBUG_SYMBOL_PARAMETERS_INTERNAL *) Sym2);
|
|
|
|
#define IsArg(S) (S->External.Flags & DEBUG_SYMBOL_IS_ARGUMENT)
|
|
|
|
if (IsArg(S1) || IsArg(S2))
|
|
{
|
|
if (IsArg(S1) && IsArg(S2))
|
|
{
|
|
return (int) S1->Address - (int) S2->Address;
|
|
} else if (IsArg(S1))
|
|
{
|
|
return -1;
|
|
} else
|
|
{
|
|
return 1;
|
|
}
|
|
}
|
|
#undef IsArg
|
|
return _stricmp((*((PDEBUG_SYMBOL_PARAMETERS_INTERNAL *) Sym1))->Name.Buffer,
|
|
(*((PDEBUG_SYMBOL_PARAMETERS_INTERNAL *) Sym2))->Name.Buffer);
|
|
}
|
|
|
|
BOOL
|
|
GetModuleName(
|
|
ULONG64 Base,
|
|
PCHAR Name,
|
|
ULONG SizeOfName
|
|
)
|
|
{
|
|
PDEBUG_IMAGE_INFO Image = g_CurrentProcess->ImageHead;
|
|
while (Image != NULL)
|
|
{
|
|
if (Base == Image->BaseOfImage)
|
|
{
|
|
if (strlen(Image->ModuleName) < SizeOfName)
|
|
{
|
|
strcpy(Name, Image->ModuleName);
|
|
return TRUE;
|
|
}
|
|
}
|
|
|
|
Image = Image->Next;
|
|
}
|
|
|
|
IMAGEHLP_MODULE Mod;
|
|
|
|
Mod.SizeOfStruct = sizeof (IMAGEHLP_MODULE);
|
|
if (SymGetModuleInfo64(g_CurrentProcess->Handle, Base, &Mod))
|
|
{
|
|
if (strlen(Mod.ModuleName) < SizeOfName)
|
|
{
|
|
strcpy(Name, Mod.ModuleName);
|
|
return TRUE;
|
|
}
|
|
}
|
|
return FALSE;
|
|
}
|
|
|
|
STDMETHODIMP
|
|
DebugSymbolGroup::AddSymbol(
|
|
THIS_
|
|
IN PCSTR Name,
|
|
OUT PULONG Index
|
|
)
|
|
{
|
|
HRESULT Status;
|
|
|
|
ENTER_ENGINE();
|
|
|
|
if (!IS_MACHINE_ACCESSIBLE())
|
|
{
|
|
Status = E_UNEXPECTED;
|
|
}
|
|
else
|
|
{
|
|
Status = E_INVALIDARG;
|
|
|
|
if (m_Locals)
|
|
{
|
|
if (!strcmp(Name, "*"))
|
|
{
|
|
Status = AddCurrentLocals();
|
|
}
|
|
else if (!strcmp(Name, "*+"))
|
|
{
|
|
Status = AddCurrentLocals();
|
|
}
|
|
}
|
|
else
|
|
{
|
|
Status = AddOneSymbol(Name, NULL, Index);
|
|
}
|
|
}
|
|
|
|
LEAVE_ENGINE();
|
|
return Status;
|
|
}
|
|
|
|
STDMETHODIMP
|
|
DebugSymbolGroup::RemoveSymbolByName(
|
|
THIS_
|
|
IN PCSTR Name
|
|
)
|
|
{
|
|
return E_NOTIMPL;
|
|
}
|
|
|
|
STDMETHODIMP
|
|
DebugSymbolGroup::RemoveSymbolByIndex(
|
|
THIS_
|
|
IN ULONG Index
|
|
)
|
|
{
|
|
HRESULT Status = E_INVALIDARG;
|
|
|
|
ENTER_ENGINE();
|
|
|
|
if (IsRootSymbol(Index))
|
|
{
|
|
if (DeleteSymbolParam(Index, 1))
|
|
{
|
|
Status = S_OK;
|
|
}
|
|
}
|
|
|
|
#ifdef DBG_SYMGROUP_ENABLED
|
|
dprintf("Deleted %lx\n", Index);
|
|
ShowAll();
|
|
#endif
|
|
|
|
LEAVE_ENGINE();
|
|
return Status;
|
|
}
|
|
|
|
STDMETHODIMP
|
|
DebugSymbolGroup::GetSymbolName(
|
|
THIS_
|
|
IN ULONG Index,
|
|
OUT OPTIONAL PSTR Buffer,
|
|
IN ULONG BufferSize,
|
|
OUT OPTIONAL PULONG NameSize
|
|
)
|
|
{
|
|
HRESULT Status;
|
|
|
|
ENTER_ENGINE();
|
|
|
|
PDEBUG_SYMBOL_PARAMETERS_INTERNAL Sym;
|
|
|
|
Status = E_INVALIDARG;
|
|
|
|
Sym = LookupSymbolParameter(Index);
|
|
if (Sym)
|
|
{
|
|
if (NameSize)
|
|
{
|
|
*NameSize = Sym->Name.Length;
|
|
}
|
|
Status = FillStringBuffer(Sym->Name.Buffer, Sym->Name.Length, Buffer, BufferSize, NameSize);
|
|
}
|
|
|
|
LEAVE_ENGINE();
|
|
return Status;
|
|
}
|
|
|
|
STDMETHODIMP
|
|
DebugSymbolGroup::GetSymbolParameters(
|
|
THIS_
|
|
IN ULONG Start,
|
|
IN ULONG Count,
|
|
OUT /* size_is(Count) */ PDEBUG_SYMBOL_PARAMETERS Params
|
|
)
|
|
{
|
|
HRESULT Status;
|
|
|
|
ENTER_ENGINE();
|
|
|
|
if (!IS_MACHINE_ACCESSIBLE())
|
|
{
|
|
Status = E_UNEXPECTED;
|
|
goto Exit;
|
|
}
|
|
else if ((Start + Count) > m_NumParams)
|
|
{
|
|
Status = E_INVALIDARG;
|
|
goto Exit;
|
|
}
|
|
|
|
Status = S_OK;
|
|
|
|
PDEBUG_SYMBOL_PARAMETERS_INTERNAL StartSym;
|
|
|
|
ZeroMemory(Params, sizeof(DEBUG_SYMBOL_PARAMETERS) * Count);
|
|
StartSym = LookupSymbolParameter(Start);
|
|
|
|
#ifdef DBG_SYMGROUP_ENABLED
|
|
dprintf("GetSymbolParameters: will return %lx sym params\n", Count);
|
|
ShowAll();
|
|
#endif
|
|
|
|
while (Count && StartSym)
|
|
{
|
|
// Do not re-resolve locals if they aren't typecast
|
|
if (!m_Locals || (StartSym->Flags & (TYPE_NAME_CHANGED | TYPE_NAME_USED)))
|
|
{
|
|
Status = RefreshSymbolParemeter(StartSym, m_pCreatedBy);
|
|
if ((Status == S_OK) && StartSym->ExpandTypeAddress)
|
|
{
|
|
if (!strcmp(StartSym->Name.Buffer, "this"))
|
|
{
|
|
StartSym->ExpandTypeAddress -= m_thisAdjust;
|
|
StartSym->Offset = m_thisAdjust;
|
|
}
|
|
}
|
|
|
|
}
|
|
*Params = StartSym->External;
|
|
StartSym = StartSym->Next;
|
|
Count--;
|
|
Params++;
|
|
}
|
|
|
|
#ifdef DBG_SYMGROUP_ENABLED
|
|
dprintf("End GetSymbolParameters\n");
|
|
ShowAll();
|
|
#endif
|
|
|
|
Exit:
|
|
LEAVE_ENGINE();
|
|
return Status;
|
|
}
|
|
|
|
STDMETHODIMP
|
|
DebugSymbolGroup::ExpandSymbol(
|
|
THIS_
|
|
IN ULONG Index,
|
|
IN BOOL Expand
|
|
)
|
|
{
|
|
HRESULT Status;
|
|
|
|
ENTER_ENGINE();
|
|
|
|
if (!IS_MACHINE_ACCESSIBLE())
|
|
{
|
|
Status = E_UNEXPECTED;
|
|
}
|
|
else
|
|
{
|
|
Status = ExpandSymPri(Index, Expand);
|
|
}
|
|
|
|
LEAVE_ENGINE();
|
|
return Status;
|
|
}
|
|
|
|
STDMETHODIMP
|
|
DebugSymbolGroup::OutputSymbols(
|
|
THIS_
|
|
IN ULONG OutputControl,
|
|
IN ULONG Flags,
|
|
IN ULONG Start,
|
|
IN ULONG Count
|
|
)
|
|
{
|
|
HRESULT Status;
|
|
|
|
ENTER_ENGINE();
|
|
|
|
if (!IS_MACHINE_ACCESSIBLE())
|
|
{
|
|
Status = E_UNEXPECTED;
|
|
goto Exit;
|
|
}
|
|
|
|
#ifdef DBG_SYMGROUP_ENABLED
|
|
dprintf("Output\n");
|
|
ShowAll();
|
|
#endif
|
|
|
|
OutCtlSave OldCtl;
|
|
|
|
if (!PushOutCtl(OutputControl, m_pCreatedBy, &OldCtl))
|
|
{
|
|
Status = E_INVALIDARG;
|
|
goto Exit;
|
|
}
|
|
|
|
PDEBUG_SYMBOL_PARAMETERS_INTERNAL StartSym;
|
|
TYPES_INFO typeInfo;
|
|
|
|
ZeroMemory(&typeInfo, sizeof(typeInfo));
|
|
|
|
StartSym = LookupSymbolParameter(Start);
|
|
while (StartSym && Count)
|
|
{
|
|
|
|
dprintf("%s%s", StartSym->Name.Buffer, DEBUG_OUTPUT_NAME_END );
|
|
|
|
OutputDbgSymValue(StartSym, m_pCreatedBy);
|
|
|
|
dprintf(DEBUG_OUTPUT_VALUE_END);
|
|
|
|
if (!(Flags & DEBUG_OUTPUT_SYMBOLS_NO_OFFSETS))
|
|
{
|
|
dprintf("%03lx%s",(ULONG) StartSym->Offset, DEBUG_OUTPUT_OFFSET_END);
|
|
}
|
|
|
|
//
|
|
// Type Name Output
|
|
//
|
|
if (!(Flags & DEBUG_OUTPUT_SYMBOLS_NO_TYPES))
|
|
{
|
|
CHAR Name[1024];
|
|
ANSI_STRING TypeName = {sizeof(Name), sizeof(Name), (PCHAR)&Name};
|
|
|
|
typeInfo.hProcess = g_CurrentProcess->Handle;
|
|
typeInfo.ModBaseAddress = StartSym->External.Module;
|
|
typeInfo.TypeIndex = StartSym->TypeIndex;
|
|
|
|
if (StartSym->Flags & (TYPE_NAME_VALID | TYPE_NAME_USED))
|
|
{
|
|
//
|
|
// We already have a valid type name
|
|
//
|
|
strcpy(Name, StartSym->TypeName);
|
|
//dprintf("%s", StartSym->TypeName);
|
|
}
|
|
else if (StartSym->Flags & SYMBOL_IS_EXTENSION)
|
|
{
|
|
strcpy(Name, "<Extension>");
|
|
}
|
|
else if (GetTypeName(NULL, &typeInfo, &TypeName) == S_OK)
|
|
{
|
|
if (strlen(TypeName.Buffer) < sizeof(StartSym->TypeName))
|
|
{
|
|
strcpy(StartSym->TypeName, Name);
|
|
}
|
|
//dprintf("%s", Name);
|
|
}
|
|
else
|
|
{
|
|
strcpy(Name, "Enter new type");
|
|
}
|
|
if (Name[0] == '<')
|
|
{
|
|
// No name
|
|
dprintf("Enter new type");
|
|
StartSym->Flags &= ~TYPE_NAME_VALID;
|
|
}
|
|
else
|
|
{
|
|
StartSym->Flags |= TYPE_NAME_VALID;
|
|
dprintf("%s", Name);
|
|
}
|
|
dprintf(DEBUG_OUTPUT_TYPE_END);
|
|
}
|
|
|
|
StartSym = StartSym->Next;
|
|
}
|
|
|
|
PopOutCtl(&OldCtl);
|
|
Status = S_OK;
|
|
|
|
Exit:
|
|
LEAVE_ENGINE();
|
|
return Status;
|
|
}
|
|
|
|
STDMETHODIMP
|
|
DebugSymbolGroup::WriteSymbol(
|
|
THIS_
|
|
IN ULONG Index,
|
|
IN PCSTR Value
|
|
)
|
|
{
|
|
if (!Value)
|
|
{
|
|
return E_INVALIDARG;
|
|
}
|
|
|
|
HRESULT Status;
|
|
|
|
ENTER_ENGINE();
|
|
|
|
if (!IS_MACHINE_ACCESSIBLE())
|
|
{
|
|
Status = E_UNEXPECTED;
|
|
goto Exit;
|
|
}
|
|
|
|
|
|
if (!Value)
|
|
{
|
|
Status = E_INVALIDARG;
|
|
goto Exit;
|
|
}
|
|
|
|
PDEBUG_SYMBOL_PARAMETERS_INTERNAL SymInternal;
|
|
|
|
#ifdef DBG_SYMGROUP_ENABLED
|
|
dprintf("WriteSymbol %lx : %s\n", Index, Value);
|
|
#endif
|
|
|
|
SymInternal = LookupSymbolParameter(Index);
|
|
if (!SymInternal ||
|
|
!SymInternal->Size ||
|
|
SymInternal->Size > sizeof(ULONG64) ||
|
|
(SymInternal->External.Flags & DEBUG_SYMBOL_READ_ONLY))
|
|
{
|
|
Status = E_INVALIDARG;
|
|
goto Exit;
|
|
}
|
|
|
|
Status = E_FAIL;
|
|
|
|
ULONG64 ChangedValue = 0;
|
|
ULONG BytesWritten;
|
|
ULONG64 WriteAddress = SymInternal->Address;
|
|
|
|
if (SymInternal->External.Flags & DEBUG_SYMBOL_IS_FLOAT)
|
|
{
|
|
// read a float
|
|
float flt = 0;
|
|
if (sscanf(Value, "%g", &flt))
|
|
{
|
|
if (SymInternal->Size == sizeof (float))
|
|
{
|
|
*((float *) &ChangedValue) = flt;
|
|
Status = S_OK;
|
|
}
|
|
else if (SymInternal->Size == sizeof (double)) // its a double
|
|
{
|
|
*((double *) &ChangedValue) = flt;
|
|
Status = S_OK;
|
|
}
|
|
|
|
if (Status == S_OK)
|
|
{
|
|
// Only float nad double types get written out.
|
|
if (!(SymInternal->Flags & SYMF_REGISTER))
|
|
{
|
|
ULONG64 Reg = SymInternal->Register;
|
|
TranslateAddress(SymInternal->Flags & ADDRESS_TRANSLATION_MASK,
|
|
SymInternal->Register,
|
|
&WriteAddress,
|
|
&Reg);
|
|
Status = g_Target->WriteVirtual(WriteAddress,
|
|
(PVOID)&ChangedValue,
|
|
SymInternal->Size,
|
|
&BytesWritten);
|
|
} else
|
|
{
|
|
// We do not know register format for float values
|
|
Status = E_FAIL;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
else
|
|
{
|
|
CHAR Token[100];
|
|
PSTR SaveCurCmd = g_CurCmd;
|
|
__try
|
|
{
|
|
if (sscanf(Value, "%s", &Token[0]))
|
|
{
|
|
g_CurCmd = &Token[0];
|
|
g_TypedExpr = TRUE;
|
|
ChangedValue = GetExpression();
|
|
g_TypedExpr = FALSE;
|
|
g_CurCmd = SaveCurCmd;
|
|
}
|
|
|
|
if (SymInternal->Flags & SYMF_REGISTER)
|
|
{
|
|
g_Machine->SetReg64((ULONG) SymInternal->Register,
|
|
ChangedValue);
|
|
}
|
|
else if (SymInternal->Name.Buffer[0] == '&')
|
|
{
|
|
SymInternal->Address = ChangedValue;
|
|
}
|
|
else
|
|
{
|
|
ULONG64 Reg = SymInternal->Register, OrigValue;
|
|
TranslateAddress(SymInternal->Flags & ADDRESS_TRANSLATION_MASK,
|
|
SymInternal->Register,
|
|
&WriteAddress,
|
|
&Reg);
|
|
|
|
// Mask the value if its a bitfield
|
|
if (SymInternal->Mask)
|
|
{
|
|
Status = g_Target->ReadVirtual(WriteAddress,
|
|
(PVOID)&OrigValue,
|
|
SymInternal->Size, // size is byte aligned from writeaddress
|
|
&BytesWritten);
|
|
OrigValue &= ~(SymInternal->Mask << SymInternal->Shift);
|
|
ChangedValue = OrigValue | ((ChangedValue & SymInternal->Mask) << SymInternal->Shift);
|
|
|
|
}
|
|
|
|
Status = g_Target->WriteVirtual(WriteAddress,
|
|
(PVOID)&ChangedValue,
|
|
SymInternal->Size,
|
|
&BytesWritten);
|
|
}
|
|
}
|
|
__except(CommandExceptionFilter(GetExceptionInformation()))
|
|
{
|
|
Status = E_FAIL;
|
|
}
|
|
}
|
|
|
|
Exit:
|
|
LEAVE_ENGINE();
|
|
return Status;
|
|
}
|
|
|
|
STDMETHODIMP
|
|
DebugSymbolGroup::OutputAsType(
|
|
THIS_
|
|
IN ULONG Index,
|
|
IN PCSTR Type
|
|
)
|
|
{
|
|
HRESULT Status;
|
|
|
|
ENTER_ENGINE();
|
|
|
|
if (!IS_MACHINE_ACCESSIBLE())
|
|
{
|
|
Status = E_UNEXPECTED;
|
|
goto Exit;
|
|
}
|
|
|
|
Status = E_INVALIDARG;
|
|
|
|
PDEBUG_SYMBOL_PARAMETERS_INTERNAL SymInternal;
|
|
|
|
SymInternal = LookupSymbolParameter(Index);
|
|
if (SymInternal && Type)
|
|
{
|
|
Status = ResolveTypecast((PCHAR) Type, SymInternal);
|
|
}
|
|
Exit:
|
|
LEAVE_ENGINE();
|
|
return Status;
|
|
}
|
|
|
|
STDMETHODIMP
|
|
DebugSymbolGroup::ShowAll(
|
|
THIS
|
|
)
|
|
{
|
|
ULONG i;
|
|
PDEBUG_SYMBOL_PARAMETERS_INTERNAL loop = m_pSymParams;
|
|
|
|
ENTER_ENGINE();
|
|
dprintf("Total %d syms\n", m_NumParams);
|
|
dprintf("Idx Sub TI ExFlags Par ExpIdx ExpAddress Expdd Flag Address Off Name\n");
|
|
while (loop)
|
|
{
|
|
dprintf64("%2lx:%4lx %4lx%8lx %4lx %6lx %p %5lx %4lx %p %03I64lx %s\n",
|
|
loop->SymbolIndex,
|
|
loop->External.SubElements,
|
|
loop->TypeIndex,
|
|
loop->External.Flags,
|
|
loop->External.ParentSymbol,
|
|
loop->ExpandTypeIndex,
|
|
loop->ExpandTypeAddress,
|
|
loop->Expanded,
|
|
loop->Flags,
|
|
loop->Address,
|
|
loop->Offset,
|
|
loop->Name.Buffer
|
|
);
|
|
loop = loop->Next;
|
|
}
|
|
LEAVE_ENGINE();
|
|
return S_OK;
|
|
}
|
|
|
|
//
|
|
// Private DebugSymbolGroup methods
|
|
//
|
|
PDEBUG_SYMBOL_PARAMETERS_INTERNAL
|
|
DebugSymbolGroup::LookupSymbolParameter(
|
|
IN ULONG Index
|
|
)
|
|
{
|
|
PDEBUG_SYMBOL_PARAMETERS_INTERNAL list = m_pSymParams;
|
|
while (list != NULL)
|
|
{
|
|
if (list->SymbolIndex == Index)
|
|
{
|
|
return list;
|
|
}
|
|
list = list->Next;
|
|
}
|
|
return list;
|
|
}
|
|
|
|
PDEBUG_SYMBOL_PARAMETERS_INTERNAL
|
|
DebugSymbolGroup::LookupSymbolParameter(
|
|
IN PCSTR Name
|
|
)
|
|
{
|
|
PDEBUG_SYMBOL_PARAMETERS_INTERNAL list = m_pSymParams;
|
|
while (list != NULL)
|
|
{
|
|
if ((list->External.ParentSymbol == list->SymbolIndex) &&
|
|
!strcmp(list->Name.Buffer, Name))
|
|
{
|
|
return list;
|
|
}
|
|
list = list->Next;
|
|
}
|
|
return list;
|
|
}
|
|
|
|
|
|
HRESULT
|
|
DebugSymbolGroup::AddOneSymbol(
|
|
IN PCSTR Name,
|
|
IN PSYMBOL_INFO pSymInfo,
|
|
OUT PULONG Index
|
|
)
|
|
{
|
|
SYM_DUMP_PARAM_EX Sym={0};
|
|
TYPES_INFO typeInfo={0};
|
|
DEBUG_SYMBOL_PARAMETERS_INTERNAL SymParams={0};
|
|
CHAR MatchName[MAX_NAME]={0};
|
|
ULONG64 Addr=0;
|
|
PUCHAR savepch;
|
|
HRESULT Status=S_OK;
|
|
ULONG SymbolScope = 0;
|
|
BOOL NameIsExpression;
|
|
|
|
strcpy(MatchName, Name);
|
|
if (isdigit(MatchName[0]) ||
|
|
(MatchName[0] == '@') // Register
|
|
)
|
|
{
|
|
Addr = ExtGetExpression(Name);
|
|
NameIsExpression = TRUE;
|
|
} else
|
|
{
|
|
NameIsExpression = FALSE;
|
|
Sym.sName = (PUCHAR) Name;
|
|
Sym.addr = 0;
|
|
}
|
|
|
|
|
|
Sym.Options = NO_PRINT;
|
|
Sym.size = sizeof(SYM_DUMP_PARAM_EX);
|
|
typeInfo.Name.Length = typeInfo.Name.MaximumLength = MAX_NAME;
|
|
typeInfo.Name.Buffer = MatchName;
|
|
|
|
if (strlen(Name))
|
|
{
|
|
if (pSymInfo || Addr)
|
|
{
|
|
|
|
if (pSymInfo)
|
|
{
|
|
typeInfo.SymAddress = pSymInfo->Address;
|
|
typeInfo.hProcess = g_CurrentProcess->Handle;
|
|
typeInfo.Flag = pSymInfo->Flags;
|
|
typeInfo.TypeIndex = pSymInfo->TypeIndex;
|
|
typeInfo.Value = pSymInfo->Register;
|
|
typeInfo.ModBaseAddress = pSymInfo->ModBase;
|
|
} else if (strlen(Name) < MAX_NAME) {
|
|
strcpy(MatchName, Name);
|
|
SymParams.Name.Length = SymParams.Name.MaximumLength = strlen(MatchName) +1;
|
|
}
|
|
|
|
SymParams.Address = (Addr ? Addr : typeInfo.SymAddress);
|
|
|
|
SymParams.External.Module = typeInfo.ModBaseAddress;
|
|
SymParams.Name = typeInfo.Name;
|
|
SymParams.TypeIndex = typeInfo.TypeIndex;
|
|
SymParams.External.TypeId = typeInfo.TypeIndex;
|
|
SymParams.Flags = typeInfo.Flag & (ADDRESS_TRANSLATION_MASK | SYMBOL_SCOPE_MASK);
|
|
SymParams.Register = (ULONG) typeInfo.Value;
|
|
SymParams.Expanded = FALSE;
|
|
SymParams.External.Flags = DEBUG_SYMBOL_READ_ONLY;
|
|
SymParams.External.SubElements = 0;
|
|
|
|
Sym.Options = DBG_RETURN_TYPE | NO_PRINT ;
|
|
|
|
FIND_TYPE_INFO Info;
|
|
Info.Flags = DBG_RETURN_TYPE ;
|
|
Info.InternalParams = &SymParams; Info.nParams = 1;
|
|
|
|
DumpTypeAndReturnInfo(&typeInfo, &Sym, (PULONG) &Status, &Info);
|
|
if (Status)
|
|
{
|
|
SymParams.TypeIndex = 0;
|
|
Status = E_INVALIDARG;
|
|
}
|
|
if (SymParams.Size)
|
|
{
|
|
SymParams.External.Flags &= ~DEBUG_SYMBOL_READ_ONLY;
|
|
}
|
|
if (NameIsExpression) {
|
|
// Just an address value was given, display the error
|
|
// but remember that value was address only
|
|
SymParams.Flags |= SYMBOL_IS_EXPRESSION;
|
|
}
|
|
|
|
} else {
|
|
TYPES_INFO_ALL typ;
|
|
|
|
strcpy(MatchName, Name);
|
|
SymParams.Name.Buffer = (PCHAR) MatchName;
|
|
SymParams.Name.Length = SymParams.Name.MaximumLength = strlen(MatchName) +1;
|
|
|
|
if (Name && *Name && GetExpressionTypeInfo((PCHAR) Name, &typ))
|
|
{
|
|
TypToParam(&typ, &SymParams);
|
|
Status = E_FAIL;
|
|
} else
|
|
{
|
|
Status = E_INVALIDARG;
|
|
strcpy(MatchName, Name);
|
|
SymParams.Name.Buffer = (PCHAR) MatchName;
|
|
SymParams.Name.Length = SymParams.Name.MaximumLength = strlen(MatchName) +1;
|
|
}
|
|
}
|
|
if (*Index > m_NumParams) *Index = m_NumParams;
|
|
SymParams.External.ParentSymbol = *Index;
|
|
|
|
//
|
|
// Check if this symbol falls within the symbolgroup scope
|
|
//
|
|
if (m_ScopeGroup == DEBUG_SCOPE_GROUP_ARGUMENTS)
|
|
{
|
|
if (!(SymParams.Flags & SYMF_PARAMETER))
|
|
{
|
|
Status = E_INVALIDARG;
|
|
SymParams.TypeIndex = 0;
|
|
}
|
|
} else if (m_ScopeGroup == DEBUG_SCOPE_GROUP_LOCALS)
|
|
{
|
|
if (!(SymParams.Flags & SYMF_LOCAL))
|
|
{
|
|
Status = E_INVALIDARG;
|
|
SymParams.TypeIndex = 0;
|
|
}
|
|
}
|
|
|
|
if (SymParams.Flags & IMAGEHLP_SYMBOL_INFO_PARAMETER)
|
|
{
|
|
SymParams.Flags &= ~IMAGEHLP_SYMBOL_INFO_PARAMETER;
|
|
SymParams.External.Flags |= DEBUG_SYMBOL_IS_ARGUMENT;
|
|
}
|
|
|
|
if (SymParams.Flags & IMAGEHLP_SYMBOL_INFO_LOCAL)
|
|
{
|
|
SymParams.Flags &= ~IMAGEHLP_SYMBOL_INFO_LOCAL;
|
|
SymParams.External.Flags |= DEBUG_SYMBOL_IS_LOCAL;
|
|
}
|
|
|
|
if (!strcmp(Name, "this"))
|
|
{
|
|
GetThisAdjustForCurrentScope(&m_thisAdjust);
|
|
SymParams.ExpandTypeAddress -= m_thisAdjust;
|
|
}
|
|
AddSymbolParameters(*Index, 1, &SymParams);
|
|
} else
|
|
{
|
|
// Null, no need to add
|
|
|
|
Status = E_INVALIDARG;
|
|
}
|
|
#ifdef DBG_SYMGROUP_ENABLED
|
|
dprintf("Added %s at %lx\n", Name, *Index);
|
|
ShowAll();
|
|
#endif
|
|
return Status;
|
|
}
|
|
|
|
BOOL
|
|
DebugSymbolGroup::IsRootSymbol(
|
|
IN ULONG Index
|
|
)
|
|
{
|
|
PDEBUG_SYMBOL_PARAMETERS_INTERNAL Sym;
|
|
|
|
Sym = LookupSymbolParameter( Index );
|
|
if (Sym && (Sym->External.ParentSymbol == Index))
|
|
{
|
|
return TRUE;
|
|
}
|
|
return FALSE;
|
|
}
|
|
|
|
ULONG
|
|
DebugSymbolGroup::FindSortedIndex (
|
|
IN PCSTR Name,
|
|
IN BOOL IsArg,
|
|
IN ULONG64 Address
|
|
)
|
|
{
|
|
ULONG Index;
|
|
BOOL Found=FALSE;
|
|
PDEBUG_SYMBOL_PARAMETERS_INTERNAL Sym;
|
|
|
|
|
|
for (Index=0; Index<m_NumParams && !Found; Index++) {
|
|
|
|
if (!IsRootSymbol(Index)) {
|
|
continue;
|
|
}
|
|
Sym = LookupSymbolParameter( Index );
|
|
|
|
|
|
if ((Sym->External.Flags & DEBUG_SYMBOL_IS_ARGUMENT) || IsArg)
|
|
{
|
|
if ((Sym->External.Flags & DEBUG_SYMBOL_IS_ARGUMENT) && IsArg)
|
|
{
|
|
Found = ((LONG64) Sym->Address) > (LONG64) Address;
|
|
} else if (IsArg)
|
|
{
|
|
Found = TRUE;
|
|
}
|
|
} else {
|
|
Found = _stricmp(Sym->Name.Buffer, Name) > 0;
|
|
}
|
|
|
|
}
|
|
return Found ? (Index-1) : m_NumParams;
|
|
}
|
|
|
|
|
|
VOID
|
|
DebugSymbolGroup::ResetIndex(
|
|
IN PDEBUG_SYMBOL_PARAMETERS_INTERNAL Start,
|
|
IN ULONG StartIndex
|
|
)
|
|
{
|
|
ULONG OrigIndex;
|
|
LONG difference;
|
|
|
|
if (!Start) return;
|
|
OrigIndex = Start->SymbolIndex;
|
|
difference = (LONG) StartIndex - OrigIndex;
|
|
while (Start!=NULL)
|
|
{
|
|
if (Start->External.ParentSymbol >= OrigIndex)
|
|
{
|
|
Start->External.ParentSymbol = (ULONG) ((LONG) Start->External.ParentSymbol + difference);
|
|
}
|
|
Start->SymbolIndex = StartIndex++;
|
|
Start = Start->Next;
|
|
}
|
|
}
|
|
|
|
ULONG
|
|
DebugSymbolGroup::AddSymbolParameters(
|
|
IN ULONG Index,
|
|
IN ULONG Count,
|
|
IN PDEBUG_SYMBOL_PARAMETERS_INTERNAL SymbolParam
|
|
)
|
|
{
|
|
PDEBUG_SYMBOL_PARAMETERS_INTERNAL start, newSym, last;
|
|
PCHAR Name;
|
|
CHAR Module[MAX_MODULE];
|
|
|
|
if (!Index || !m_pSymParams)
|
|
{
|
|
// add at begining
|
|
last = m_pSymParams;
|
|
start = NULL;
|
|
} else
|
|
{
|
|
start = LookupSymbolParameter(Index-1);
|
|
if (!start)
|
|
{
|
|
return FALSE;
|
|
}
|
|
last = start->Next;
|
|
}
|
|
|
|
while (Count)
|
|
{
|
|
ULONG ModNameLen, NameLen;
|
|
|
|
if (GetModuleName(SymbolParam->External.Module, &Module[0], MAX_MODULE))
|
|
{
|
|
ModNameLen = strlen(Module) + 1; // For '!'
|
|
} else
|
|
{
|
|
ModNameLen = 0;
|
|
}
|
|
Module[ModNameLen] = '\0';
|
|
|
|
NameLen = strlen(SymbolParam->Name.Buffer);
|
|
if (!((newSym = (PDEBUG_SYMBOL_PARAMETERS_INTERNAL)
|
|
malloc(sizeof(DEBUG_SYMBOL_PARAMETERS_INTERNAL))) &&
|
|
(Name = (PCHAR) malloc(NameLen + ModNameLen + 1))))
|
|
{
|
|
if (newSym) {
|
|
free(newSym);
|
|
}
|
|
|
|
if (start)
|
|
{
|
|
start->Next = last;
|
|
}
|
|
ResetIndex(last, Index);
|
|
return FALSE;
|
|
}
|
|
|
|
if (start)
|
|
{
|
|
start->Next = newSym;
|
|
}
|
|
else
|
|
{
|
|
m_pSymParams = newSym;
|
|
}
|
|
|
|
*newSym = *SymbolParam;
|
|
*Name = 0;
|
|
if (ModNameLen && !strchr(SymbolParam->Name.Buffer, '!') &&
|
|
!m_Locals &&
|
|
!(SymbolParam->External.Flags & DEBUG_SYMBOL_EXPANSION_LEVEL_MASK) &&
|
|
!(SymbolParam->Flags & SYMBOL_IS_EXPRESSION))
|
|
{
|
|
// Unqualified symbol
|
|
strcpy(Name, Module);
|
|
strcat(Name, "!");
|
|
}
|
|
strncat(Name, SymbolParam->Name.Buffer, NameLen);
|
|
newSym->Name.Buffer = Name;
|
|
newSym->Name.Length = newSym->Name.MaximumLength =
|
|
(USHORT) (NameLen + ModNameLen);
|
|
newSym->SymbolIndex = Index++;
|
|
|
|
start = newSym;
|
|
SymbolParam++;
|
|
++m_NumParams;
|
|
Count--;
|
|
}
|
|
if (start)
|
|
{
|
|
start->Next = last;
|
|
}
|
|
ResetIndex(last, Index);
|
|
return TRUE;
|
|
}
|
|
|
|
|
|
ULONG
|
|
DebugSymbolGroup::DeleteSymbolParam(
|
|
IN ULONG Index,
|
|
IN ULONG Count
|
|
)
|
|
{
|
|
PDEBUG_SYMBOL_PARAMETERS_INTERNAL prev=NULL, delSym, next, freeSym;
|
|
PCHAR Name;
|
|
ULONG MaxDelIndex = Index + Count - 1;
|
|
BOOL HeadDeleted = FALSE;
|
|
BOOL DeleteChildren = Count == 0;
|
|
|
|
if (!m_pSymParams)
|
|
{
|
|
return TRUE;
|
|
}
|
|
#ifdef DBG_SYMGROUP_ENABLED
|
|
dprintf("DeleteSymbolParam(%lx, %lx) :\n", Index, Count);
|
|
ShowAll();
|
|
#endif
|
|
if (!DeleteChildren)
|
|
{
|
|
if (Index==0)
|
|
{
|
|
delSym = m_pSymParams;
|
|
next = LookupSymbolParameter(Index + Count);
|
|
HeadDeleted = TRUE;
|
|
} else
|
|
{
|
|
prev = LookupSymbolParameter(Index - 1);
|
|
next = LookupSymbolParameter(Index + Count);
|
|
if (!prev)
|
|
{
|
|
return FALSE;
|
|
}
|
|
delSym = LookupSymbolParameter(Index);
|
|
if (!delSym)
|
|
{
|
|
return FALSE;
|
|
}
|
|
}
|
|
|
|
if (delSym->SymbolIndex != Index)
|
|
{
|
|
return FALSE;
|
|
}
|
|
|
|
while (Count && delSym)
|
|
{
|
|
Name = delSym->Name.Buffer;
|
|
freeSym = delSym;
|
|
delSym = delSym->Next;
|
|
Count--;
|
|
assert(m_NumParams);
|
|
m_NumParams--;
|
|
#ifdef DBG_SYMGROUP_ENABLED
|
|
dprintf("Removed %s at %lx, %lx remaining.\n", Name, freeSym->SymbolIndex, m_NumParams);
|
|
#endif
|
|
if (freeSym->DataBuffer && (freeSym->Flags & SYMBOL_IS_EXTENSION))
|
|
{
|
|
free( freeSym->DataBuffer );
|
|
}
|
|
free(Name);
|
|
free(freeSym);
|
|
}
|
|
} else
|
|
{
|
|
prev = LookupSymbolParameter(Index);
|
|
next = LookupSymbolParameter(Index + 1);
|
|
MaxDelIndex = Index;
|
|
}
|
|
|
|
// clean up parent-less entries
|
|
while (next && (next->External.ParentSymbol >= Index) &&
|
|
next->External.ParentSymbol <= MaxDelIndex)
|
|
{
|
|
Name = next->Name.Buffer;
|
|
freeSym = next;
|
|
next = freeSym->Next;
|
|
MaxDelIndex++;
|
|
assert(m_NumParams);
|
|
m_NumParams--;
|
|
#ifdef DBG_SYMGROUP_ENABLED
|
|
dprintf("Removed child %s at %lx, %lx remaining.\n", Name, freeSym->SymbolIndex, m_NumParams);
|
|
#endif
|
|
if (freeSym->DataBuffer && (freeSym->Flags & SYMBOL_IS_EXTENSION))
|
|
{
|
|
free( freeSym->DataBuffer );
|
|
}
|
|
free(Name);
|
|
free(freeSym);
|
|
}
|
|
if (HeadDeleted)
|
|
{
|
|
m_pSymParams = next;
|
|
}
|
|
if (prev)
|
|
{
|
|
prev->Next = next;
|
|
}
|
|
ResetIndex(next, (DeleteChildren ? (Index+1) : Index));
|
|
return TRUE;
|
|
}
|
|
|
|
HRESULT
|
|
DebugSymbolGroup::AddCurrentLocals()
|
|
{
|
|
HRESULT Status = S_OK;
|
|
// Always return success since this reqiest is processed even if we didn't add anything
|
|
|
|
RequireCurrentScope();
|
|
|
|
GetThisAdjustForCurrentScope(&m_thisAdjust);
|
|
|
|
if (EnumerateLocals(AddLocals, (PVOID) this))
|
|
{
|
|
}
|
|
|
|
ULONG Index;
|
|
|
|
for (Index = 0; Index < m_NumParams; Index++)
|
|
{
|
|
if (IsRootSymbol(Index))
|
|
{
|
|
PDEBUG_SYMBOL_PARAMETERS_INTERNAL Sym;
|
|
|
|
Sym = LookupSymbolParameter(Index);
|
|
|
|
if (!Sym) // Or assert (Sym) ??
|
|
{
|
|
continue;
|
|
}
|
|
if (!(Sym->Flags & SYMBOL_IS_IN_SCOPE))
|
|
{
|
|
DeleteSymbolParam(Index,1);
|
|
--Index;
|
|
}
|
|
else
|
|
{
|
|
Sym->Flags &= ~SYMBOL_IS_IN_SCOPE;
|
|
}
|
|
|
|
}
|
|
}
|
|
|
|
KeepLastScopeClass(NULL, NULL, 0);
|
|
|
|
return Status;
|
|
}
|
|
|
|
HRESULT
|
|
DebugSymbolGroup::ResetCurrentLocals()
|
|
{
|
|
return S_OK;
|
|
}
|
|
|
|
void
|
|
DebugSymbolGroup::KeepLastScopeClass(
|
|
PDEBUG_SYMBOL_PARAMETERS_INTERNAL Sym_this,
|
|
PCHAR ExpansionState,
|
|
ULONG NumChilds
|
|
)
|
|
{
|
|
PDEBUG_SYMBOL_PARAMETERS_INTERNAL temp = LookupSymbolParameter("this");
|
|
|
|
if (temp)
|
|
{
|
|
ULONG thisIndex = temp->SymbolIndex;
|
|
|
|
if (m_LastClassExpanded)
|
|
{
|
|
ExpandSymPri(thisIndex, TRUE);
|
|
}
|
|
}
|
|
}
|
|
|
|
HRESULT
|
|
DebugSymbolGroup::ExpandSymPri(
|
|
THIS_
|
|
IN ULONG Index,
|
|
IN BOOL Expand
|
|
)
|
|
{
|
|
PDEBUG_SYMBOL_PARAMETERS_INTERNAL Parent;
|
|
HRESULT hr = S_OK;
|
|
|
|
Parent = LookupSymbolParameter(Index);
|
|
#ifdef DBG_SYMGROUP_ENABLED
|
|
dprintf("Enpanding %lx (%lx to be %s)\n", Parent->SymbolIndex, Parent->External.SubElements,
|
|
Expand ? "created" : "deleted");
|
|
ShowAll();
|
|
#endif
|
|
|
|
if (!Parent)
|
|
{
|
|
hr = E_INVALIDARG;
|
|
goto ExitExpandSymbol;
|
|
}
|
|
|
|
//
|
|
// Special case - check and store if "this" is expanded/collapsed
|
|
//
|
|
if (!strcmp(Parent->Name.Buffer, "this"))
|
|
{
|
|
m_LastClassExpanded = Expand;
|
|
}
|
|
|
|
if (!Expand && Parent->Expanded)
|
|
{
|
|
if (DeleteSymbolParam(Index, 0))
|
|
{
|
|
Parent->Expanded = FALSE;
|
|
Parent->External.Flags &= ~DEBUG_SYMBOL_EXPANDED;
|
|
hr = S_OK;
|
|
}
|
|
} else if (Expand)
|
|
{
|
|
PDEBUG_SYMBOL_PARAMETERS_INTERNAL SubTypes = NULL;
|
|
ULONG Count;
|
|
PCHAR Names = NULL;
|
|
|
|
if (Parent->Expanded || !Parent->External.SubElements)
|
|
{
|
|
hr = S_OK;
|
|
goto ExitExpandSymbol;
|
|
}
|
|
|
|
hr = FindChildren(Parent, &SubTypes, &Count, &Names);
|
|
|
|
if ((hr == S_OK) && Parent->External.SubElements)
|
|
{
|
|
AddSymbolParameters(Parent->SymbolIndex+1, Parent->External.SubElements, SubTypes);
|
|
Parent->External.Flags |= DEBUG_SYMBOL_EXPANDED;
|
|
Parent->Expanded = TRUE;
|
|
}
|
|
if (Names) free (Names);
|
|
if (SubTypes) free (SubTypes);
|
|
|
|
}
|
|
ExitExpandSymbol:
|
|
#ifdef DBG_SYMGROUP_ENABLED
|
|
dprintf("Enpanded %lx (%lx %s)\n", Parent->SymbolIndex, Parent->External.SubElements,
|
|
Parent->Expanded ? "new" : "deleted");
|
|
ShowAll();
|
|
#endif
|
|
return hr;
|
|
}
|
|
|
|
//
|
|
// Returns children of the given symbol
|
|
//
|
|
// pParentSym : Symbol whose chilren need to be looked up
|
|
//
|
|
// pChildren : Array in which info about children is returned
|
|
// Caller is responsible for freeig the memory pointed to by this
|
|
//
|
|
// pChildCount : Number of children returned
|
|
//
|
|
// pChildNames : Array of Char[MAX_NAME] containing the children names
|
|
// Caller is responsible for freeig the memory pointed to by this
|
|
//
|
|
HRESULT
|
|
DebugSymbolGroup::FindChildren(
|
|
PDEBUG_SYMBOL_PARAMETERS_INTERNAL pParentSym,
|
|
PDEBUG_SYMBOL_PARAMETERS_INTERNAL *pChildren,
|
|
PULONG pChildCount,
|
|
PCHAR *pChildNames
|
|
)
|
|
{
|
|
HRESULT Status = E_FAIL;
|
|
TYPE_DUMP_INTERNAL tdi={0};
|
|
TYPES_INFO ti = {0};
|
|
SYM_DUMP_PARAM_EX Sym={0};
|
|
PDEBUG_SYMBOL_PARAMETERS_INTERNAL SubTypes;
|
|
ULONG i;
|
|
PCHAR Names;
|
|
BOOL Success;
|
|
|
|
if (pParentSym->Flags & SYMBOL_IS_EXTENSION)
|
|
{
|
|
return FindChildrenForExtensionSym(pParentSym, pChildren, pChildCount, pChildNames);
|
|
}
|
|
do {
|
|
|
|
SubTypes = (PDEBUG_SYMBOL_PARAMETERS_INTERNAL) malloc(
|
|
pParentSym->External.SubElements * sizeof( DEBUG_SYMBOL_PARAMETERS_INTERNAL ));
|
|
Names = (PCHAR) malloc(pParentSym->External.SubElements * MAX_DISPLAY_NAME);
|
|
|
|
if (!SubTypes || !Names)
|
|
{
|
|
if (Names) free (Names);
|
|
if (SubTypes) free (SubTypes);
|
|
Status = E_OUTOFMEMORY;
|
|
break;
|
|
}
|
|
|
|
ZeroMemory(SubTypes, pParentSym->External.SubElements * sizeof( DEBUG_SYMBOL_PARAMETERS_INTERNAL));
|
|
|
|
for (i=0;i<pParentSym->External.SubElements; i++)
|
|
{
|
|
SubTypes[i].External.ParentSymbol = pParentSym->SymbolIndex;
|
|
SubTypes[i].External.Flags = DEBUG_SYMBOL_READ_ONLY |
|
|
((UCHAR) pParentSym->External.Flags + 1);
|
|
SubTypes[i].Expanded = FALSE;
|
|
SubTypes[i].External.Module = pParentSym->External.Module;
|
|
SubTypes[i].Parent = pParentSym;
|
|
SubTypes[i].Size = 0;
|
|
SubTypes[i].Name.Length = SubTypes[i].Name.MaximumLength = MAX_DISPLAY_NAME;
|
|
SubTypes[i].Name.Buffer = &Names[MAX_DISPLAY_NAME*i];
|
|
SubTypes[i].Flags = (pParentSym->Flags & DBG_DUMP_FIELD_STRING);
|
|
}
|
|
Sym.size = sizeof(SYM_DUMP_PARAM_EX);
|
|
Sym.Context = (PVOID) &SubTypes;
|
|
Sym.addr = 0;//pParentSym->ExpandTypeAddress;
|
|
if (pParentSym->Flags & TYPE_NAME_USED)
|
|
{
|
|
Sym.sName = (PUCHAR) &pParentSym->TypeName[0];
|
|
} else {
|
|
Sym.sName = (PUCHAR) pParentSym->Name.Buffer;
|
|
}
|
|
|
|
tdi.TypeOptions = Sym.Options = DBG_RETURN_SUBTYPES | NO_PRINT ;
|
|
Sym.Options = NO_PRINT ;
|
|
tdi.pSymParams = SubTypes;
|
|
tdi.NumSymParams = pParentSym->External.SubElements;
|
|
tdi.level = 0;
|
|
tdi.CopyName = 1;
|
|
tdi.CurrentSymParam = 0;
|
|
ti.hProcess = tdi.hProcess = g_CurrentProcess->Handle;
|
|
ti.ModBaseAddress = tdi.modBaseAddr = pParentSym->External.Module;
|
|
ti.TypeIndex = pParentSym->TypeIndex;
|
|
ti.Value = pParentSym->Register;
|
|
ti.Flag = pParentSym->Flags & ADDRESS_TRANSLATION_MASK;
|
|
ti.SymAddress = pParentSym->Address;
|
|
|
|
FIND_TYPE_INFO Info = {0};
|
|
Info.Flags = DBG_RETURN_SUBTYPES ;
|
|
Info.InternalParams = SubTypes; Info.nParams = pParentSym->External.SubElements;
|
|
|
|
DumpTypeAndReturnInfo(&ti, &Sym, (PULONG) &tdi.ErrorStatus, &Info);
|
|
|
|
Success = TRUE;
|
|
Status = S_OK;
|
|
|
|
if (Info.nParams <= pParentSym->External.SubElements)
|
|
{
|
|
pParentSym->External.SubElements = Info.nParams;
|
|
pParentSym->ExpandTypeAddress = Info.ParentExpandAddress;
|
|
} else {
|
|
// We are getting more subtypes than extected, try again
|
|
if (Names) free (Names);
|
|
if (SubTypes) free (SubTypes);
|
|
|
|
pParentSym->External.SubElements = Info.nParams;
|
|
Success = FALSE;
|
|
}
|
|
|
|
} while (!Success);
|
|
|
|
|
|
if (pParentSym->Name.Buffer && !strcmp(pParentSym->Name.Buffer, "this")) {
|
|
pParentSym->ExpandTypeAddress -= m_thisAdjust;
|
|
}
|
|
for (i=0;i<pParentSym->External.SubElements; i++)
|
|
{
|
|
if (SubTypes[i].Size)
|
|
{
|
|
SubTypes[i].External.Flags &= ~DEBUG_SYMBOL_READ_ONLY;
|
|
}
|
|
SubTypes[i].Offset = SubTypes[i].Address - pParentSym->ExpandTypeAddress;
|
|
}
|
|
|
|
*pChildNames = Names;
|
|
*pChildCount = pParentSym->External.SubElements;
|
|
*pChildren = SubTypes;
|
|
|
|
return Status;
|
|
}
|
|
|
|
BOOL
|
|
AreEquivAddress(
|
|
ULONG64 Addr1,
|
|
ULONG Addr1Flags,
|
|
ULONG Addr1Reg,
|
|
ULONG64 Addr2,
|
|
ULONG Addr2Flags,
|
|
ULONG Addr2Reg
|
|
)
|
|
{
|
|
ULONG64 Value1,Value2;
|
|
if (Addr1Flags & SYMF_REGISTER)
|
|
{
|
|
if (Addr2Flags & SYMF_REGISTER)
|
|
{
|
|
return (Addr1Reg == Addr2Reg);
|
|
}
|
|
|
|
return FALSE;
|
|
}
|
|
|
|
TranslateAddress(Addr1Flags, Addr1Reg, &Addr1, &Value1);
|
|
TranslateAddress(Addr2Flags, Addr2Reg, &Addr2, &Value2);
|
|
|
|
return (Addr1 == Addr2);
|
|
}
|
|
|
|
BOOL CALLBACK DebugSymbolGroup::AddLocals(
|
|
PSYMBOL_INFO pSymInfo,
|
|
ULONG Size,
|
|
PVOID Context
|
|
)
|
|
{
|
|
ULONG Index = -1;
|
|
DebugSymbolGroup *Caller = (DebugSymbolGroup *) Context;
|
|
|
|
if (Caller)
|
|
{
|
|
PDEBUG_SYMBOL_PARAMETERS_INTERNAL pSym;
|
|
|
|
pSym = Caller->LookupSymbolParameter(pSymInfo->Name);
|
|
|
|
if (pSym) {
|
|
if (((pSym->TypeIndex == pSymInfo->TypeIndex) || // Its same type
|
|
(pSym->Flags & TYPE_NAME_MASK)) && // Type may be different if it was a typecast
|
|
pSym->External.Module == pSymInfo->ModBase &&
|
|
AreEquivAddress(pSym->Address,
|
|
pSym->Flags & ADDRESS_TRANSLATION_MASK,
|
|
pSym->Register,
|
|
pSymInfo->Address,
|
|
pSymInfo->Flags & ADDRESS_TRANSLATION_MASK,
|
|
pSymInfo->Register)) {
|
|
|
|
// This is the same symbol
|
|
pSym->Flags |= SYMBOL_IS_IN_SCOPE;
|
|
return TRUE;
|
|
}
|
|
|
|
}
|
|
BOOL IsArg = FALSE;
|
|
|
|
if (pSymInfo->Flags & SYMF_PARAMETER)
|
|
{
|
|
IsArg = TRUE;
|
|
}
|
|
Index = Caller->FindSortedIndex(pSymInfo->Name, IsArg, pSymInfo->Address);
|
|
|
|
// dprintf("%lx : Adding %s %s \n", Index, IsArg ? "arg" : " ", pSymInfo->Name);
|
|
|
|
if (Caller->AddOneSymbol(pSymInfo->Name, pSymInfo, &Index) == S_OK)
|
|
{
|
|
pSym = Caller->LookupSymbolParameter(Index);
|
|
if (pSym) // should it be assert (pSym) ???
|
|
{
|
|
pSym->Flags |= SYMBOL_IS_IN_SCOPE;
|
|
pSym->External.Flags |= IsArg ? DEBUG_SYMBOL_IS_ARGUMENT : 0;
|
|
}
|
|
}
|
|
|
|
return TRUE;
|
|
}
|
|
return FALSE;
|
|
}
|