Leaked source code of windows server 2003
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.
 
 
 
 
 
 

2358 lines
64 KiB

//----------------------------------------------------------------------------
//
// Symbol-handling routines.
//
// Copyright (C) Microsoft Corporation, 1997-2002.
//
//----------------------------------------------------------------------------
#include "ntsdp.hpp"
#include <stddef.h>
#include <cvconst.h>
PCSTR g_CallConv[] =
{
// Ignore near/far distinctions.
"cdecl", "cdecl", "pascal", "pascal", "fastcall", "fastcall",
"<skipped>", "stdcall", "stdcall", "syscall", "syscall",
"thiscall", "MIPS", "generic", "Alpha", "PPC", "SuperH 4",
"ARM", "AM33", "TriCore", "SuperH 5", "M32R",
};
typedef struct _OUTPUT_SYMBOL_CALLBACK
{
PSTR Prefix;
ULONG Verbose:1;
ULONG ShowAddress:1;
} OUTPUT_SYMBOL_CALLBACK, *POUTPUT_SYMBOL_CALLBACK;
LPSTR g_SymbolSearchPath;
LPSTR g_ExecutableImageSearchPath;
// Symbol options that require symbol reloading to take effect.
#define RELOAD_SYM_OPTIONS \
(SYMOPT_UNDNAME | SYMOPT_NO_CPP | SYMOPT_DEFERRED_LOADS | \
SYMOPT_LOAD_LINES | SYMOPT_IGNORE_CVREC | SYMOPT_LOAD_ANYTHING | \
SYMOPT_EXACT_SYMBOLS | SYMOPT_ALLOW_ABSOLUTE_SYMBOLS | \
SYMOPT_IGNORE_NT_SYMPATH | SYMOPT_INCLUDE_32BIT_MODULES | \
SYMOPT_PUBLICS_ONLY | SYMOPT_NO_PUBLICS | SYMOPT_AUTO_PUBLICS |\
SYMOPT_NO_IMAGE_SEARCH)
ULONG g_SymOptions = SYMOPT_CASE_INSENSITIVE | SYMOPT_UNDNAME |
SYMOPT_OMAP_FIND_NEAREST | SYMOPT_DEFERRED_LOADS |
SYMOPT_AUTO_PUBLICS | SYMOPT_NO_IMAGE_SEARCH |
SYMOPT_FAIL_CRITICAL_ERRORS;
#define SYM_BUFFER_SIZE (sizeof(IMAGEHLP_SYMBOL64) + MAX_SYMBOL_LEN)
ULONG64 g_SymBuffer[(SYM_BUFFER_SIZE + sizeof(ULONG64) - 1) / sizeof(ULONG64)];
PIMAGEHLP_SYMBOL64 g_Sym = (PIMAGEHLP_SYMBOL64) g_SymBuffer;
SYMBOL_INFO_AND_NAME g_TmpSymInfo;
PSTR g_DmtNameDescs[DMT_NAME_COUNT] =
{
"Loaded symbol image file", "Symbol file", "Mapped memory image file",
"Image path",
};
DEBUG_SCOPE g_ScopeBuffer;
void
RefreshAllModules(BOOL EnsureLines)
{
TargetInfo* Target;
ProcessInfo* Process;
ForAllLayersToProcess()
{
ImageInfo* Image;
for (Image = Process->m_ImageHead; Image; Image = Image->m_Next)
{
if (EnsureLines)
{
IMAGEHLP_MODULE64 ModInfo;
ModInfo.SizeOfStruct = sizeof(ModInfo);
if (SymGetModuleInfo64(g_Process->m_SymHandle,
Image->m_BaseOfImage, &ModInfo) &&
ModInfo.LineNumbers)
{
// Line number information is already loaded,
// so there's no need to reload this image.
continue;
}
}
Image->ReloadSymbols();
}
}
}
HRESULT
SetSymOptions(ULONG Options)
{
ULONG OldOptions = g_SymOptions;
//
// If we're enabling untrusted user mode we can't
// already be in a dangerous state.
//
if ((Options & SYMOPT_SECURE) &&
!(OldOptions & SYMOPT_SECURE))
{
ULONG Id;
char Desc[2 * MAX_PARAM_VALUE];
// If there are any active targets we
// can't be sure they're safe.
// If we have RPC servers there may be ways
// to attack through those so disallow that.
if (g_TargetHead ||
DbgRpcEnumActiveServers(NULL, &Id, Desc, sizeof(Desc)))
{
return HRESULT_FROM_WIN32(ERROR_ACCESS_DENIED);
}
}
SymSetOptions(Options);
g_SymOptions = SymGetOptions();
if (g_SymOptions != Options)
{
// dbghelp denied the request to set options.
return E_INVALIDARG;
}
NotifyChangeSymbolState(DEBUG_CSS_SYMBOL_OPTIONS, g_SymOptions, NULL);
if ((OldOptions ^ g_SymOptions) & RELOAD_SYM_OPTIONS)
{
BOOL EnsureLines = FALSE;
// If the only change was to turn on line loading
// there's no need to reload modules which already
// have lines loaded. This is usually the case for
// PDBs, so this optimization effectively avoids all
// PDB reloading when turning on .lines.
if ((OldOptions & ~SYMOPT_LOAD_LINES) ==
(g_SymOptions & ~SYMOPT_LOAD_LINES) &&
(g_SymOptions & SYMOPT_LOAD_LINES))
{
EnsureLines = TRUE;
}
RefreshAllModules(EnsureLines);
}
return S_OK;
}
/*
* TranslateAddress
* Flags Flags returned by dbghelp
* Address IN Address returned by dbghelp
* OUT Address of symbol
* Value Value of the symbol if its in register
*
*/
BOOL
TranslateAddress(
IN ULONG64 ModBase,
IN ULONG Flags,
IN ULONG RegId,
IN OUT PULONG64 Address,
OUT PULONG64 Value
)
{
BOOL Status;
ContextSave* Push;
PCROSS_PLATFORM_CONTEXT ScopeContext = GetCurrentScopeContext();
if (ScopeContext)
{
Push = g_Machine->PushContext(ScopeContext);
}
if (Flags & SYMFLAG_REGREL)
{
ULONG64 RegContent;
if (RegId || (Value && (RegId = (ULONG)*Value)))
{
if (g_Machine->
GetScopeFrameRegister(RegId, &GetCurrentScope()->Frame,
&RegContent) != S_OK)
{
Status = FALSE;
goto Exit;
}
}
else
{
DBG_ASSERT(FALSE);
Status = FALSE;
goto Exit;
}
*Address = RegContent + ((LONG64) (LONG) (ULONG) *Address);
}
else if (Flags & SYMFLAG_REGISTER)
{
if (Value)
{
if (RegId || (RegId = (ULONG)*Address))
{
if (g_Machine->
GetScopeFrameRegister(RegId, &GetCurrentScope()->Frame,
Value) != S_OK)
{
Status = FALSE;
goto Exit;
}
}
else
{
DBG_ASSERT(FALSE);
Status = FALSE;
goto Exit;
}
}
}
else if (Flags & SYMFLAG_FRAMEREL)
{
PDEBUG_SCOPE Scope = GetCurrentScope();
if (Scope->Frame.FrameOffset)
{
*Address += Scope->Frame.FrameOffset;
PFPO_DATA pFpoData = (PFPO_DATA)Scope->Frame.FuncTableEntry;
if (g_Machine->m_ExecTypes[0] == IMAGE_FILE_MACHINE_I386 &&
pFpoData &&
(pFpoData->cbFrame == FRAME_FPO ||
pFpoData->cbFrame == FRAME_TRAP))
{
// Compensate for FPO's not having ebp
*Address += sizeof(DWORD);
}
}
else
{
ADDR FP;
g_Machine->GetFP(&FP);
FP.flat = (LONG64) FP.flat + *Address;
*Address = FP.flat;
}
}
else if (Flags & SYMFLAG_TLSREL)
{
ULONG64 TlsAddr;
ImageInfo* Image = g_Process->FindImageByOffset(ModBase, FALSE);
if (!Image ||
Image->GetTlsIndex() != S_OK)
{
Status = FALSE;
goto Exit;
}
if (g_Process->GetImplicitThreadDataTeb(g_Thread, &TlsAddr) != S_OK ||
g_Target->ReadPointer(g_Process, g_Machine,
TlsAddr + 11 * (g_Machine->m_Ptr64 ? 8 : 4),
&TlsAddr) != S_OK ||
g_Target->ReadPointer(g_Process, g_Machine,
TlsAddr + Image->m_TlsIndex *
(g_Machine->m_Ptr64 ? 8 : 4),
&TlsAddr) != S_OK)
{
return MEMORY;
}
(*Address) += TlsAddr;
}
Status = TRUE;
Exit:
if (ScopeContext)
{
g_Machine->PopContext(Push);
}
return Status;
}
void
FillCorSymbolInfo(PSYMBOL_INFO SymInfo)
{
// XXX drewb - Not clear what to do here.
// Assumes the SYM_INFO was already zero-filled,
// so just leave it zeroed.
}
BOOL
FormatSymbolName(ImageInfo* Image,
ULONG64 Offset,
PCSTR Name,
PULONG64 Displacement,
PSTR Buffer,
ULONG BufferLen)
{
DBG_ASSERT(BufferLen > 0);
if (!Image)
{
*Buffer = 0;
*Displacement = Offset;
return FALSE;
}
if (Name)
{
if (*Displacement == (ULONG64)-1)
{
// In some BBT cases dbghelp can tell that an offset
// is associated with a particular symbol but it
// doesn't have a valid offset. Present the symbol
// but in a way that makes it clear that it's
// this special case.
PrintString(Buffer, BufferLen,
"%s!%s <PERF> (%s+0x%I64x)",
Image->m_ModuleName, Name,
Image->m_ModuleName,
(Offset - Image->m_BaseOfImage));
*Displacement = 0;
}
else
{
PrintString(Buffer, BufferLen,
"%s!%s", Image->m_ModuleName, Name);
}
}
else
{
CopyString(Buffer, Image->m_ModuleName, BufferLen);
*Displacement = Offset - Image->m_BaseOfImage;
}
return TRUE;
}
BOOL
GetSymbolInfo(ULONG64 Offset,
PCHAR Buffer,
ULONG BufferLen,
PSYMBOL_INFO SymInfo,
PULONG64 Displacement)
{
ImageInfo* Image;
PCSTR Name = NULL;
PSYMBOL_INFO TmpInfo = g_TmpSymInfo.Init();
if ((Image = g_Process->FindImageByOffset(Offset, TRUE)) &&
!Image->m_CorImage)
{
if (SymFromAddr(g_Process->m_SymHandle, Offset,
Displacement, TmpInfo))
{
Name = TmpInfo->Name;
}
}
else if (g_Process->m_CorImage)
{
ULONG64 IlModBase;
ULONG32 MethodToken;
ULONG32 MethodOffs;
// The offset is not in any known module.
// The managed runtime is loaded in this process,
// so possibly the offset is in some JIT code.
// See if the runtime knows about it.
if (g_Process->
ConvertNativeToIlOffset(Offset, &IlModBase,
&MethodToken, &MethodOffs) == S_OK &&
(Image = g_Process->FindImageByOffset(IlModBase, TRUE)) &&
g_Process->
GetCorSymbol(Offset, TmpInfo->Name, TmpInfo->MaxNameLen,
Displacement) == S_OK)
{
Name = TmpInfo->Name;
FillCorSymbolInfo(TmpInfo);
}
}
if (SymInfo)
{
memcpy(SymInfo, TmpInfo, FIELD_OFFSET(SYMBOL_INFO, MaxNameLen));
Buffer = SymInfo->Name;
BufferLen = SymInfo->MaxNameLen;
}
return FormatSymbolName(Image, Offset, Name, Displacement,
Buffer, BufferLen);
}
BOOL
GetNearSymbol(ULONG64 Offset,
PSTR Buffer,
ULONG BufferLen,
PULONG64 Displacement,
LONG Delta)
{
ImageInfo* Image;
if (Delta == 0)
{
return GetSymbol(Offset, Buffer, BufferLen, Displacement);
}
if (!(Image = g_Process->FindImageByOffset(Offset, TRUE)) ||
!SymGetSymFromAddr64(g_Process->m_SymHandle, Offset,
Displacement, g_Sym))
{
return FALSE;
}
if (Delta < 0)
{
while (Delta++ < 0)
{
if (!SymGetSymPrev(g_Process->m_SymHandle, g_Sym))
{
return FALSE;
}
}
if (Displacement != NULL)
{
*Displacement = Offset - g_Sym->Address;
}
}
else if (Delta > 0)
{
while (Delta-- > 0)
{
if (!SymGetSymNext(g_Process->m_SymHandle, g_Sym))
{
return FALSE;
}
}
if (Displacement != NULL)
{
*Displacement = g_Sym->Address - Offset;
}
}
PrintString(Buffer, BufferLen,
"%s!%s", Image->m_ModuleName, g_Sym->Name);
return TRUE;
}
BOOL
GetLineFromAddr(ProcessInfo* Process,
ULONG64 Offset,
PIMAGEHLP_LINE64 Line,
PULONG Displacement)
{
ImageInfo* Image;
Line->SizeOfStruct = sizeof(*Line);
if (!(Image = Process->FindImageByOffset(Offset, FALSE)) ||
Image->m_CorImage)
{
ULONG32 MethodToken;
ULONG32 MethodOffs;
SYMBOL_INFO SymInfo = {0};
// The offset is not in any known module.
// The managed runtime is loaded in this process,
// so possibly the offset is in some JIT code.
// See if the runtime knows about it.
if (Process->
ConvertNativeToIlOffset(Offset, &Offset,
&MethodToken, &MethodOffs) != S_OK)
{
return FALSE;
}
// Need to look up the fake method RVA by
// the method token, then add the method offset
// to that and search by that offset for the line.
if (!SymFromToken(Process->m_SymHandle, Offset, MethodToken, &SymInfo))
{
return FALSE;
}
Offset = SymInfo.Address + MethodOffs;
}
return SymGetLineFromAddr64(Process->m_SymHandle, Offset,
Displacement, Line);
}
void
OutputSymbolAndInfo(ULONG64 Addr)
{
SYMBOL_INFO_AND_NAME SymInfo;
ULONG64 Disp;
if (GetSymbolInfo(Addr, NULL, 0, SymInfo, &Disp))
{
dprintf("%s", SymInfo->Name);
ShowSymbolInfo(SymInfo);
}
}
#define IMAGE_IS_PATTERN ((ImageInfo*)-1)
ImageInfo*
ParseModuleName(PBOOL ModSpecified)
{
PSTR CmdSaved = g_CurCmd;
CHAR Name[MAX_MODULE];
PSTR Dst = Name;
CHAR ch;
BOOL HasWild = FALSE;
// first, parse out a possible module name, either a '*' or
// a string of 'A'-'Z', 'a'-'z', '0'-'9', '_', '~' (or null)
ch = PeekChar();
g_CurCmd++;
while ((ch >= 'A' && ch <= 'Z') ||
(ch >= 'a' && ch <= 'z') ||
(ch >= '0' && ch <= '9') ||
ch == '_' || ch == '~' || ch == '*' || ch == '?')
{
if (ch == '*' || ch == '?')
{
HasWild = TRUE;
}
*Dst++ = ch;
ch = *g_CurCmd++;
}
*Dst = '\0';
g_CurCmd--;
// if no '!' after name and white space, then no module specified
// restore text pointer and treat as null module (PC current)
if (PeekChar() == '!')
{
g_CurCmd++;
}
else
{
g_CurCmd = CmdSaved;
Name[0] = '\0';
}
// Name either has: '*' for all modules,
// '\0' for current module,
// nonnull string for module name.
*ModSpecified = Name[0] != 0;
if (HasWild)
{
return IMAGE_IS_PATTERN;
}
else if (Name[0])
{
return g_Process->FindImageByName(Name, 0, INAME_MODULE, TRUE);
}
else
{
return NULL;
}
}
BOOL CALLBACK
OutputSymbolInfoCallback(
PSYMBOL_INFO SymInfo,
ULONG Size,
PVOID Arg
)
{
POUTPUT_SYMBOL_CALLBACK OutSym = (POUTPUT_SYMBOL_CALLBACK)Arg;
ULONG64 Address = SymInfo->Address;
ULONG64 Value = 0;
ImageInfo* Image;
if (OutSym->Prefix)
{
dprintf("%s", OutSym->Prefix);
}
if (SymInfo->Flags & (SYMFLAG_REGISTER |
SYMFLAG_REGREL |
SYMFLAG_FRAMEREL |
SYMFLAG_TLSREL))
{
TranslateAddress(SymInfo->ModBase, SymInfo->Flags,
g_Machine->
CvRegToMachine((CV_HREG_e)SymInfo->Register),
&Address, &Value);
}
if (OutSym->ShowAddress)
{
dprintf("%s ", FormatAddr64(Address));
}
Image = g_Process->FindImageByOffset(SymInfo->ModBase, TRUE);
if (Image && ((SymInfo->Flags & SYMFLAG_LOCAL) == 0))
{
dprintf("%s!%s", Image->m_ModuleName, SymInfo->Name);
}
else
{
dprintf("%s", SymInfo->Name);
}
if (OutSym->Verbose)
{
dprintf(" ");
ShowSymbolInfo(SymInfo);
}
dprintf("\n");
return !CheckUserInterrupt();
}
/*** ParseExamine - parse and execute examine command
*
* Purpose:
* Parse the current command string and examine the symbol
* table to display the appropriate entries. The entries
* are displayed in increasing string order. This function
* accepts underscores, alphabetic, and numeric characters
* to match as well as the special characters '?', '*', '['-']'.
*
* Input:
* g_CurCmd - pointer to current command string
*
* Output:
* offset and string name of symbols displayed
*
*************************************************************************/
void
ParseExamine(void)
{
CHAR StringBuf[MAX_SYMBOL_LEN];
UCHAR ch;
PSTR String = StringBuf;
PSTR Start;
PSTR ModEnd;
BOOL ModSpecified;
ULONG64 Base = 0;
ImageInfo* Image;
OUTPUT_SYMBOL_CALLBACK OutSymInfo;
// Get module pointer from name in command line (<string>!).
PeekChar();
Start = g_CurCmd;
Image = ParseModuleName(&ModSpecified);
ModEnd = g_CurCmd;
ch = PeekChar();
// Special case the command "x <pattern>!" to dump out the module table.
if (Image == IMAGE_IS_PATTERN &&
(ch == ';' || ch == '\0'))
{
*(ModEnd - 1) = 0;
_strupr(Start);
DumpModuleTable(DMT_STANDARD, Start);
return;
}
if (ModSpecified)
{
if (Image == NULL)
{
// The user specified a module that doesn't exist.
error(VARDEF);
}
else if (Image == IMAGE_IS_PATTERN)
{
// The user gave a pattern string for the module
// so we need to pass it on for dbghelp to scan with.
memcpy(String, Start, (ModEnd - Start));
String += ModEnd - Start;
}
else
{
// A specific image was given and found so
// confine the search to that one image.
Base = Image->m_BaseOfImage;
}
}
g_CurCmd++;
// Condense leading underscores into a "_#"
// that will match zero or more underscores. This causes all
// underscore-prefixed symbols to match the base symbol name
// when the pattern is prefixed by an underscore.
if (ch == '_')
{
*String++ = '_';
*String++ = '#';
do
{
ch = *g_CurCmd++;
} while (ch == '_');
}
ch = (UCHAR)toupper(ch);
while (ch && ch != ';' && ch != ' ')
{
*String++ = ch;
ch = (CHAR)toupper(*g_CurCmd);
g_CurCmd++;
}
*String = '\0';
g_CurCmd--;
ZeroMemory(&OutSymInfo, sizeof(OutSymInfo));
OutSymInfo.Verbose = TRUE;
OutSymInfo.ShowAddress = TRUE;
// We nee the scope for all cases since param values are displayed for
// function in scope
RequireCurrentScope();
SymEnumSymbols(g_Process->m_SymHandle,
Base,
StringBuf,
OutputSymbolInfoCallback,
&OutSymInfo);
}
void
ListNearSymbols(ULONG64 AddrStart)
{
ULONG64 Displacement;
ImageInfo* Image;
if (g_SrcOptions & SRCOPT_LIST_LINE)
{
OutputLineAddr(AddrStart, "%s(%d)%s\n");
}
if ((Image = g_Process->FindImageByOffset(AddrStart, TRUE)) &&
!Image->m_CorImage)
{
if (!SymGetSymFromAddr64(g_Process->m_SymHandle, AddrStart,
&Displacement, g_Sym))
{
return;
}
dprintf("(%s) %s!%s",
FormatAddr64(g_Sym->Address),
Image->m_ModuleName,
g_Sym->Name);
if (Displacement)
{
dprintf("+0x%s ", FormatDisp64(Displacement));
}
else
{
dprintf(" ");
}
if (SymGetSymNext64(g_Process->m_SymHandle, g_Sym))
{
dprintf("| (%s) %s!%s",
FormatAddr64(g_Sym->Address),
Image->m_ModuleName,
g_Sym->Name);
}
dprintf("\n");
if (Displacement == 0)
{
OUTPUT_SYMBOL_CALLBACK OutSymInfo;
dprintf("Exact matches:\n");
FlushCallbacks();
ZeroMemory(&OutSymInfo, sizeof(OutSymInfo));
OutSymInfo.Prefix = " ";
OutSymInfo.Verbose = TRUE;
SymEnumSymbolsForAddr(g_Process->m_SymHandle, AddrStart,
OutputSymbolInfoCallback, &OutSymInfo);
}
}
else
{
SYMBOL_INFO_AND_NAME SymInfo;
// We couldn't find a true symbol but it may be
// possible to find a managed symbol.
if (GetSymbolInfo(AddrStart, NULL, 0, SymInfo, &Displacement))
{
dprintf("(%s) %s", FormatAddr64(AddrStart), SymInfo->Name);
if (Displacement)
{
dprintf("+0x%s", FormatDisp64(Displacement));
}
dprintf("\n");
}
}
}
void
DumpModuleTable(ULONG Flags, PSTR Pattern)
{
ImageInfo* Image;
IMAGEHLP_MODULE64 ModInfo;
ULONG i;
if (g_Target->m_Machine->m_Ptr64)
{
dprintf("start end module name\n");
}
else
{
dprintf("start end module name\n");
}
Image = g_Process->m_ImageHead;
while (Image)
{
ULONG PrimaryName;
PSTR Names[DMT_NAME_COUNT];
if (Pattern != NULL &&
!MatchPattern(Image->m_ModuleName, Pattern))
{
Image = Image->m_Next;
continue;
}
ModInfo.SizeOfStruct = sizeof(ModInfo);
if (!SymGetModuleInfo64(g_Process->m_SymHandle,
Image->m_BaseOfImage, &ModInfo))
{
ModInfo.SymType = SymNone;
}
Names[DMT_NAME_SYM_IMAGE] = ModInfo.LoadedImageName;
Names[DMT_NAME_SYM_FILE] = ModInfoSymFile(&ModInfo);
Names[DMT_NAME_MAPPED_IMAGE] = Image->m_MappedImagePath;
Names[DMT_NAME_IMAGE_PATH] = Image->m_ImagePath;
if (Flags & DMT_SYM_FILE_NAME)
{
PrimaryName = DMT_NAME_SYM_FILE;
}
else if (Flags & DMT_MAPPED_IMAGE_NAME)
{
PrimaryName = DMT_NAME_MAPPED_IMAGE;
}
else if (Flags & DMT_IMAGE_PATH_NAME)
{
PrimaryName = DMT_NAME_IMAGE_PATH;
}
else
{
PrimaryName = DMT_NAME_SYM_IMAGE;
}
//
// Skip modules filtered by flags
//
if ((Flags & DMT_ONLY_LOADED_SYMBOLS) &&
(ModInfo.SymType == SymDeferred))
{
Image = Image->m_Next;
continue;
}
if (IS_KERNEL_TARGET(g_Target))
{
if ((Flags & DMT_ONLY_USER_SYMBOLS) &&
(Image->m_BaseOfImage >= g_Target->m_SystemRangeStart))
{
Image = Image->m_Next;
continue;
}
if ((Flags & DMT_ONLY_KERNEL_SYMBOLS) &&
(Image->m_BaseOfImage <= g_Target->m_SystemRangeStart))
{
Image = Image->m_Next;
continue;
}
}
dprintf("%s %s %-8s ",
FormatAddr64(Image->m_BaseOfImage),
FormatAddr64(Image->m_BaseOfImage + Image->m_SizeOfImage),
Image->m_ModuleName);
if (Flags & DMT_NO_SYMBOL_OUTPUT)
{
goto SkipSymbolOutput;
}
if (PrimaryName == DMT_NAME_MAPPED_IMAGE ||
PrimaryName == DMT_NAME_IMAGE_PATH)
{
dprintf(" %s\n",
*Names[PrimaryName] ? Names[PrimaryName] : "<none>");
goto SkipSymbolOutput;
}
switch(Image->m_SymState)
{
case ISS_MATCHED:
dprintf( " " );
break;
case ISS_MISMATCHED_SYMBOLS:
dprintf( "M " );
break;
case ISS_UNKNOWN_TIMESTAMP:
dprintf( "T " );
break;
case ISS_UNKNOWN_CHECKSUM:
dprintf( "C " );
break;
case ISS_BAD_CHECKSUM:
dprintf( "# " );
break;
}
if (ModInfo.SymType == SymDeferred)
{
dprintf("(deferred) ");
}
else if (ModInfo.SymType == SymNone)
{
dprintf("(no symbolic information) ");
}
else
{
switch(ModInfo.SymType)
{
case SymCoff:
dprintf("(coff symbols) ");
break;
case SymCv:
dprintf("(codeview symbols) ");
break;
case SymPdb:
dprintf("(pdb symbols) ");
break;
case SymExport:
dprintf("(export symbols) ");
break;
}
dprintf("%s", *Names[PrimaryName] ? Names[PrimaryName] : "<none>");
}
dprintf("\n");
SkipSymbolOutput:
if (Flags & DMT_VERBOSE)
{
for (i = 0; i < DMT_NAME_COUNT; i++)
{
if (i != PrimaryName && *Names[i])
{
dprintf(" %s: %s\n", g_DmtNameDescs[i], Names[i]);
}
}
}
if (Flags & (DMT_VERBOSE | DMT_IMAGE_TIMESTAMP))
{
LPSTR TimeDateStr = TimeToStr(Image->m_TimeDateStamp);
dprintf(" Checksum: %08X Timestamp: %s (%08X)\n",
Image->m_CheckSum, TimeDateStr, Image->m_TimeDateStamp);
}
if (Flags & DMT_VERBOSE)
{
Image->OutputVersionInformation();
}
if (CheckUserInterrupt())
{
break;
}
Image = Image->m_Next;
}
if ((Flags & (DMT_ONLY_LOADED_SYMBOLS | DMT_ONLY_USER_SYMBOLS)) == 0)
{
ULONG LumFlags = LUM_OUTPUT;
LumFlags |= ((Flags & DMT_VERBOSE) ? LUM_OUTPUT_VERBOSE : 0);
LumFlags |= ((Flags & DMT_IMAGE_TIMESTAMP) ?
LUM_OUTPUT_IMAGE_INFO : 0);
dprintf("\n");
ListUnloadedModules(LumFlags, Pattern);
}
}
void
ParseDumpModuleTable(void)
{
ULONG Flags = DMT_STANDARD;
char Pattern[MAX_MODULE];
PSTR Pat = NULL;
if (!IS_CUR_MACHINE_ACCESSIBLE())
{
error(BADTHREAD);
}
g_CurCmd++;
for (;;)
{
// skip white space
while (isspace(*g_CurCmd))
{
g_CurCmd++;
}
if (*g_CurCmd == 'f')
{
Flags = (Flags & ~DMT_NAME_FLAGS) | DMT_IMAGE_PATH_NAME;
g_CurCmd++;
}
else if (*g_CurCmd == 'i')
{
Flags = (Flags & ~DMT_NAME_FLAGS) | DMT_SYM_IMAGE_FILE_NAME;
g_CurCmd++;
}
else if (*g_CurCmd == 'l')
{
Flags |= DMT_ONLY_LOADED_SYMBOLS;
g_CurCmd++;
}
else if (*g_CurCmd == 'm')
{
g_CurCmd++;
// skip white space
while (isspace(*g_CurCmd))
{
g_CurCmd++;
}
Pat = Pattern;
while (*g_CurCmd && !isspace(*g_CurCmd))
{
if ((Pat - Pattern) < sizeof(Pattern) - 1)
{
*Pat++ = *g_CurCmd;
}
g_CurCmd++;
}
*Pat = 0;
Pat = Pattern;
_strupr(Pat);
}
else if (*g_CurCmd == 'p')
{
Flags = (Flags & ~DMT_NAME_FLAGS) | DMT_MAPPED_IMAGE_NAME;
g_CurCmd++;
}
else if (*g_CurCmd == 't')
{
Flags = (Flags & ~(DMT_NAME_FLAGS)) |
DMT_NAME_SYM_IMAGE | DMT_IMAGE_TIMESTAMP |
DMT_NO_SYMBOL_OUTPUT;
g_CurCmd++;
}
else if (*g_CurCmd == 'v')
{
Flags |= DMT_VERBOSE;
g_CurCmd++;
}
else if (IS_KERNEL_TARGET(g_Target))
{
if (*g_CurCmd == 'u')
{
Flags |= DMT_ONLY_USER_SYMBOLS;
g_CurCmd++;
}
else if (*g_CurCmd == 'k')
{
Flags |= DMT_ONLY_KERNEL_SYMBOLS;
g_CurCmd++;
}
else
{
break;
}
}
else
{
break;
}
}
DumpModuleTable(Flags, Pat);
}
void
GetCurrentMemoryOffsets(PULONG64 MemoryLow,
PULONG64 MemoryHigh)
{
// Default value for no source.
*MemoryLow = (ULONG64)(LONG64)-1;
}
PCSTR
PrependPrefixToSymbol(char PrefixedString[],
PCSTR pString,
PCSTR *RegString)
{
if ( RegString )
{
*RegString = NULL;
}
PCSTR bangPtr;
int bang = '!';
PCSTR Tail;
bangPtr = strchr( pString, bang );
if ( bangPtr )
{
Tail = bangPtr + 1;
}
else
{
Tail = pString;
}
if ( strncmp( Tail, g_Machine->m_SymPrefix, g_Machine->m_SymPrefixLen ) )
{
ULONG Loc = (ULONG)(Tail - pString);
if (Loc > 0)
{
memcpy( PrefixedString, pString, Loc );
}
memcpy( PrefixedString + Loc, g_Machine->m_SymPrefix,
g_Machine->m_SymPrefixLen );
if ( RegString )
{
*RegString = &PrefixedString[Loc];
}
Loc += g_Machine->m_SymPrefixLen;
strcpy( &PrefixedString[Loc], Tail );
return PrefixedString;
}
else
{
return pString;
}
}
BOOL
ForceSymbolCodeAddress(ProcessInfo* Process,
PSYMBOL_INFO Symbol, MachineInfo* Machine)
{
ULONG64 Code = Symbol->Address;
if (Symbol->Flags & SYMFLAG_FORWARDER)
{
char Fwd[2 * MAX_PATH];
ULONG Read;
PSTR Sep;
// The address of a forwarder entry points to the
// string name of the function that things are forwarded
// to. Look up that name and try to get the address
// from it.
if (g_Target->ReadVirtual(Process, Symbol->Address, Fwd, sizeof(Fwd),
&Read) != S_OK ||
Read < 2)
{
ErrOut("Unable to read forwarder string\n");
return FALSE;
}
Fwd[sizeof(Fwd) - 1] = 0;
if (!(Sep = strchr(Fwd, '.')))
{
ErrOut("Unable to read forwarder string\n");
return FALSE;
}
*Sep = '!';
if (GetOffsetFromSym(Process, Fwd, &Code, NULL) != 1)
{
ErrOut("Unable to get address of forwarder '%s'\n", Fwd);
return FALSE;
}
}
else if (Machine &&
Machine->m_ExecTypes[0] == IMAGE_FILE_MACHINE_IA64 &&
(Symbol->Flags & SYMFLAG_EXPORT))
{
// On IA64 the export entries contain the address
// of the plabel. We want the actual code address
// so resolve the plabel to its code.
if (!Machine->GetPrefixedSymbolOffset(Process, Symbol->Address,
GETPREF_VERBOSE,
&Code))
{
return FALSE;
}
}
Symbol->Address = Code;
return TRUE;
}
BOOL
GetOffsetFromBreakpoint(PCSTR String, PULONG64 Offset)
{
ULONG Id;
Breakpoint* Bp;
//
// The string must be of the form "$bp[digits]".
//
if (strlen(String) < 4 || _memicmp(String, "$bp", 3) != 0)
{
return FALSE;
}
String += 3;
Id = 0;
while (*String)
{
if (*String < '0' || *String > '9')
{
return FALSE;
}
Id = Id * 10 + (int)(*String - '0');
String++;
}
Bp = GetBreakpointById(NULL, Id);
if (Bp == NULL ||
(Bp->m_Flags & DEBUG_BREAKPOINT_DEFERRED))
{
return FALSE;
}
*Offset = Flat(*Bp->GetAddr());
return TRUE;
}
BOOL
IgnoreEnumeratedSymbol(ProcessInfo* Process,
PSTR MatchString,
MachineInfo* Machine,
PSYMBOL_INFO SymInfo)
{
ULONG64 Func;
//
// The compiler and linker can generate thunks for
// a variety of reasons. For example, a "this" adjustor
// thunk can be generated to adjust a this pointer before
// calling into a method to account for differences between
// derived/container classes and the base/containee classes.
// Assume that the user doesn't care about thunks as they're
// automatically emitted.
//
if (SymInfo->Tag == SymTagThunk &&
!_stricmp(MatchString, SymInfo->Name))
{
// We hit a thunk for the function we're looking
// for, just ignore it.
return TRUE;
}
//
// IA64 plabels are publics with the same name
// as the function they refer to. This causes
// ambiguity problems as we end up with two
// hits. The plabel is rarely interesting, though,
// so just filter them out here so that expressions
// always evaluate to the function itself.
//
if ((Machine->m_ExecTypes[0] != IMAGE_FILE_MACHINE_IA64) ||
(SymInfo->Scope != SymTagPublicSymbol) ||
(SymInfo->Flags & SYMFLAG_FUNCTION) ||
!Machine->GetPrefixedSymbolOffset(Process, SymInfo->Address,
0, &Func))
{
return FALSE;
}
if (Func == SymInfo->Address)
{
// The symbol is probably a global pointing to itself
return FALSE;
}
PSYMBOL_INFO FuncSymInfo;
PSTR FuncSym;
__try
{
FuncSymInfo = (PSYMBOL_INFO)
alloca(sizeof(*FuncSymInfo) + MAX_SYMBOL_LEN * 2);
}
__except(EXCEPTION_EXECUTE_HANDLER)
{
FuncSymInfo = NULL;
}
if (FuncSymInfo == NULL)
{
return FALSE;
}
FuncSym = FuncSymInfo->Name;
SYMBOL_INFO LocalSymInfo;
// We have to save and restore the original data as
// dbghelp always uses a single buffer to store all
// symbol information. The incoming symbol info
// is going to be wiped out when we look up another symbol.
LocalSymInfo = *SymInfo;
strcpy(FuncSym + MAX_SYMBOL_LEN, SymInfo->Name);
ULONG64 FuncSymDisp;
ZeroMemory(FuncSymInfo, sizeof(*FuncSymInfo));
FuncSymInfo->SizeOfStruct = sizeof(*FuncSymInfo);
FuncSymInfo->MaxNameLen = MAX_SYMBOL_LEN;
FuncSym[0] = 0;
if (!SymFromAddr(Process->m_SymHandle, Func, &FuncSymDisp, FuncSymInfo))
{
FuncSymDisp = 1;
}
else
{
// Incremental linking produces intermediate thunks
// that entry points refer to. The thunks call on
// to the real code. The extra layer of code prevents
// direct filtering; we have to chain through thunks
// to see if the final code is the function code.
while (FuncSymDisp == 0 &&
FuncSymInfo->Tag == SymTagThunk &&
strstr(FuncSym, FuncSym + MAX_SYMBOL_LEN) == NULL)
{
FuncSym[0] = 0;
if (!SymFromAddr(Process->m_SymHandle, FuncSymInfo->Value,
&FuncSymDisp, FuncSymInfo))
{
FuncSymDisp = 1;
break;
}
}
}
*SymInfo = LocalSymInfo;
strcpy(SymInfo->Name, FuncSym + MAX_SYMBOL_LEN);
return FuncSymDisp == 0 && strstr(FuncSym, SymInfo->Name);
}
struct COUNT_SYMBOL_MATCHES
{
PSTR MatchString;
ProcessInfo* Process;
MachineInfo* Machine;
SYMBOL_INFO ReturnSymInfo;
CHAR SymbolNameOverflowBuffer[MAX_SYMBOL_LEN];
ULONG Matches;
};
BOOL CALLBACK
CountSymbolMatches(
PSYMBOL_INFO SymInfo,
ULONG Size,
PVOID UserContext
)
{
COUNT_SYMBOL_MATCHES* Context =
(COUNT_SYMBOL_MATCHES*)UserContext;
if (IgnoreEnumeratedSymbol(Context->Process, Context->MatchString,
Context->Machine, SymInfo))
{
return TRUE;
}
if (Context->Matches == 1)
{
// We already have one match, check if we got a duplicate.
if ((SymInfo->Address == Context->ReturnSymInfo.Address) &&
!strcmp(SymInfo->Name, Context->ReturnSymInfo.Name))
{
// Looks like the same symbol, ignore it.
return TRUE;
}
}
Context->ReturnSymInfo = *SymInfo;
if (SymInfo->NameLen < MAX_SYMBOL_LEN)
{
strcpy(Context->ReturnSymInfo.Name, SymInfo->Name);
}
Context->Matches++;
return TRUE;
}
ULONG
MultiSymFromName(IN ProcessInfo* Process,
IN LPSTR Name,
IN ImageInfo* Image,
IN MachineInfo* Machine,
OUT PSYMBOL_INFO Symbol)
{
ULONG Matches;
RequireCurrentScope();
if (!Image)
{
if (!SymFromName(Process->m_SymHandle, Name, Symbol))
{
return 0;
}
Matches = 1;
}
else
{
COUNT_SYMBOL_MATCHES Context;
ULONG MaxName = Symbol->MaxNameLen;
PSTR Bang;
Bang = strchr(Name, '!');
if (Bang &&
!_strnicmp(Image->m_ModuleName, Name,
Bang - Name))
{
Context.MatchString = Bang + 1;
}
else
{
Context.MatchString = Name;
}
Context.Process = Process;
Context.Machine = Machine;
Context.ReturnSymInfo = *Symbol;
if (Symbol->NameLen < MAX_SYMBOL_LEN)
{
strcpy(Context.ReturnSymInfo.Name, Symbol->Name);
}
Context.Matches = 0;
SymEnumSymbols(Process->m_SymHandle, Image->m_BaseOfImage, Name,
CountSymbolMatches, &Context);
*Symbol = Context.ReturnSymInfo;
Symbol->MaxNameLen = MaxName;
if (Symbol->MaxNameLen > Context.ReturnSymInfo.NameLen)
{
strcpy(Symbol->Name, Context.ReturnSymInfo.Name);
}
Matches = Context.Matches;
}
if (Matches == 1 &&
!ForceSymbolCodeAddress(Process, Symbol, Machine))
{
return 0;
}
return Matches;
}
ULONG
GetOffsetFromSym(ProcessInfo* Process,
PCSTR String,
PULONG64 Offset,
ImageInfo** Image)
{
CHAR ModifiedString[MAX_SYMBOL_LEN + 64];
CHAR Suffix[2];
SYMBOL_INFO SymInfo = {0};
ULONG Count;
if (Image != NULL)
{
*Image = NULL;
}
if (strlen(String) >= MAX_SYMBOL_LEN)
{
return 0;
}
//
// We can't do anything without a current process.
//
if (Process == NULL)
{
return 0;
}
if ( strlen(String) == 0 )
{
return 0;
}
if (Process->GetOffsetFromMod(String, Offset) ||
GetOffsetFromBreakpoint(String, Offset))
{
return 1;
}
//
// If a module name was given look up the module
// and determine the processor type so that the
// appropriate machine is used for the following
// machine-specific operations.
//
ImageInfo* StrImage;
PCSTR ModSep = strchr(String, '!');
if (ModSep != NULL)
{
StrImage = Process->
FindImageByName(String, (ULONG)(ModSep - String),
INAME_MODULE, TRUE);
if (Image != NULL)
{
*Image = StrImage;
}
}
else
{
StrImage = NULL;
}
MachineInfo* Machine = Process->m_Target->m_EffMachine;
if (StrImage != NULL)
{
Machine = MachineTypeInfo(Process->m_Target,
StrImage->GetMachineType());
if (Machine == NULL)
{
Machine = Process->m_Target->m_EffMachine;
}
}
if ( g_PrefixSymbols && Machine->m_SymPrefix != NULL )
{
PCSTR PreString;
PCSTR RegString;
PreString = PrependPrefixToSymbol( ModifiedString, String,
&RegString );
if ( Count =
MultiSymFromName( Process, (PSTR)PreString,
StrImage, Machine, &SymInfo ) )
{
*Offset = SymInfo.Address;
goto GotOffsetSuccess;
}
if ( (PreString != String) &&
(Count =
MultiSymFromName( Process, (PSTR)String,
StrImage, Machine, &SymInfo ) ) )
{
// Ambiguous plabels shouldn't be further resolved,
// so just return the information for the plabel.
if (Count > 1)
{
*Offset = SymInfo.Address;
goto GotOffsetSuccess;
}
if (!Machine->GetPrefixedSymbolOffset(Process, SymInfo.Address,
GETPREF_VERBOSE,
Offset))
{
// This symbol doesn't appear to actually
// be a plabel so just use the symbol address.
*Offset = SymInfo.Address;
}
goto GotOffsetSuccess;
}
}
else if (Count =
MultiSymFromName( Process, (PSTR)String,
StrImage, Machine, &SymInfo ))
{
*Offset = SymInfo.Address;
goto GotOffsetSuccess;
}
if (g_SymbolSuffix != 'n')
{
strcpy( ModifiedString, String );
Suffix[0] = g_SymbolSuffix;
Suffix[1] = '\0';
strcat( ModifiedString, Suffix );
if (Count =
MultiSymFromName( Process, ModifiedString,
StrImage, Machine, &SymInfo ))
{
*Offset = SymInfo.Address;
goto GotOffsetSuccess;
}
}
return 0;
GotOffsetSuccess:
TranslateAddress(SymInfo.ModBase, SymInfo.Flags,
Machine->CvRegToMachine((CV_HREG_e)SymInfo.Register),
Offset, &SymInfo.Value);
if (SymInfo.Flags & SYMFLAG_REGISTER)
{
*Offset = SymInfo.Value;
}
return Count;
}
void
CreateModuleNameFromPath(LPSTR ImagePath, LPSTR ModuleName)
{
PSTR Scan;
CopyString( ModuleName, PathTail(ImagePath), MAX_MODULE );
Scan = strrchr( ModuleName, '.' );
if (Scan != NULL)
{
*Scan = '\0';
}
}
void
GetAdjacentSymOffsets(ULONG64 AddrStart,
PULONG64 PrevOffset,
PULONG64 NextOffset)
{
DWORD64 Displacement;
//
// assume failure
//
*PrevOffset = 0;
*NextOffset = (ULONG64) -1;
//
// get the symbol for the initial address
//
if (!SymGetSymFromAddr64(g_Process->m_SymHandle, AddrStart, &Displacement,
g_Sym))
{
return;
}
*PrevOffset = g_Sym->Address;
if (SymGetSymNext64(g_Process->m_SymHandle, g_Sym))
{
*NextOffset = g_Sym->Address;
}
}
BOOL
SymbolCallbackFunction(HANDLE ProcessSymHandle,
ULONG ActionCode,
ULONG64 CallbackData,
ULONG64 UserContext)
{
PIMAGEHLP_DEFERRED_SYMBOL_LOAD64 DefLoad;
PIMAGEHLP_CBA_READ_MEMORY ReadMem;
PIMAGEHLP_CBA_EVENT Event;
ImageInfo* Image;
ULONG i;
ULONG OldSymOptions;
PVOID Mapping;
ProcessInfo* Process =
(ProcessInfo*)(ULONG_PTR)UserContext;
DefLoad = (PIMAGEHLP_DEFERRED_SYMBOL_LOAD64) CallbackData;
switch(ActionCode)
{
case CBA_DEBUG_INFO:
DBG_ASSERT(CallbackData && *(LPSTR)CallbackData);
CompletePartialLine(DEBUG_OUTPUT_SYMBOLS);
MaskOut(DEBUG_OUTPUT_SYMBOLS, "%s", (LPSTR)CallbackData);
return TRUE;
case CBA_EVENT:
Event = (PIMAGEHLP_CBA_EVENT)CallbackData;
DBG_ASSERT(Event);
if (Event->desc && *Event->desc)
{
dprintf("%s", Event->desc);
if (Event->severity >= sevProblem)
{
FlushCallbacks();
}
}
return TRUE;
case CBA_DEFERRED_SYMBOL_LOAD_CANCEL:
return PollUserInterrupt(TRUE);
case CBA_DEFERRED_SYMBOL_LOAD_START:
Image = Process->FindImageByOffset(DefLoad->BaseOfImage, FALSE);
if (Image)
{
// Try to load the image memory right away in this
// case to catch incomplete-information errors.
if (!Image->DemandLoadImageMemory(TRUE, TRUE))
{
return FALSE;
}
// Update dbghelp with the latest image file handle
// as loading image memory may have given us one.
DefLoad->hFile = Image->m_File;
VerbOut("Loading symbols for %s %16s -> ",
FormatAddr64(DefLoad->BaseOfImage),
DefLoad->FileName);
return TRUE;
}
break;
case CBA_DEFERRED_SYMBOL_LOAD_PARTIAL:
//
// dbghelp wasn't able to get complete
// information about an image and so had
// to do some guessing when loading symbols.
// Returning FALSE means do the best that
// dbghelp can. Returning TRUE means try
// again with any updated data we provide here.
// We use this as an opportunity to go out
// and attempt to load image files to get
// image information that may not be present in
// the debuggee and thus we are creating information
// that's not really present. Hopefully we'll find
// the right image and not come up with incorrect information.
//
// Don't do this if the user has asked for exact
// symbols as the in-memory image may not exactly
// match what's on disk even if the headers are similar.
if (g_SymOptions & SYMOPT_EXACT_SYMBOLS)
{
return FALSE;
}
Image = Process->FindImageByOffset(DefLoad->BaseOfImage, FALSE);
if (!Image ||
Image->m_File ||
Image->m_MapAlreadyFailed ||
!(Mapping =
FindImageFile(Process, Image->m_ImagePath, Image->m_SizeOfImage,
Image->m_CheckSum, Image->m_TimeDateStamp,
&Image->m_File, Image->m_MappedImagePath)))
{
return FALSE;
}
// This file handle is only good as long as the
// image information doesn't change.
Image->m_FileIsDemandMapped = TRUE;
// We don't need the actual file mapping, just
// the file handle.
UnmapViewOfFile(Mapping);
// Update dbghelp with the latest image file handle
// as loading the image has given us one.
DefLoad->Reparse = TRUE;
DefLoad->hFile = Image->m_File;
if (g_SymOptions & SYMOPT_DEBUG)
{
CompletePartialLine(DEBUG_OUTPUT_SYMBOLS);
MaskOut(DEBUG_OUTPUT_SYMBOLS,
"DBGENG: Partial symbol load found image %s.\n",
Image->m_MappedImagePath);
}
return TRUE;
case CBA_DEFERRED_SYMBOL_LOAD_FAILURE:
if (IS_KERNEL_TARGET(Process->m_Target) &&
DefLoad->SizeOfStruct >=
FIELD_OFFSET(IMAGEHLP_DEFERRED_SYMBOL_LOAD, Reparse))
{
i = 0;
if (strncmp(DefLoad->FileName, "dump_", sizeof("dump_")-1) == 0)
{
i = sizeof("dump_")-1;
}
if (strncmp(DefLoad->FileName, "hiber_", sizeof("hiber_")-1) == 0)
{
i = sizeof("hiber_")-1;
}
if (i)
{
if (_stricmp (DefLoad->FileName+i, "scsiport.sys") == 0)
{
strcpy (DefLoad->FileName, "diskdump.sys");
}
else
{
strcpy(DefLoad->FileName, DefLoad->FileName+i);
}
DefLoad->Reparse = TRUE;
return TRUE;
}
}
if (DefLoad->FileName && *DefLoad->FileName)
{
VerbOut("*** Error: could not load symbols for %s\n",
DefLoad->FileName);
}
else
{
VerbOut("*** Error: could not load symbols [MODNAME UNKNOWN]\n");
}
break;
case CBA_DEFERRED_SYMBOL_LOAD_COMPLETE:
Image = Process->FindImageByOffset(DefLoad->BaseOfImage, FALSE);
if (!Image)
{
VerbOut("\n");
break;
}
// Do not load unqualified symbols in this callback since this
// could result in stack overflow.
OldSymOptions = SymGetOptions();
SymSetOptions(OldSymOptions | SYMOPT_NO_UNQUALIFIED_LOADS);
VerbOut("%s\n", DefLoad->FileName);
Image->ValidateSymbolLoad(DefLoad);
NotifyChangeSymbolState(DEBUG_CSS_LOADS,
DefLoad->BaseOfImage, Process);
SymSetOptions(OldSymOptions);
return TRUE;
case CBA_SYMBOLS_UNLOADED:
VerbOut("Symbols unloaded for %s %s\n",
FormatAddr64(DefLoad->BaseOfImage),
DefLoad->FileName);
break;
case CBA_READ_MEMORY:
ReadMem = (PIMAGEHLP_CBA_READ_MEMORY)CallbackData;
return Process->m_Target->
ReadVirtual(Process,
ReadMem->addr,
ReadMem->buf,
ReadMem->bytes,
ReadMem->bytesread) == S_OK;
case CBA_SET_OPTIONS:
// Symbol options are set through the interface
// so the debugger generally knows about them
// already. The only flags that we want to check
// here are internal flags that can be changed through
// !sym or other dbghelp extension commands.
// There is no need to notify here for internal flag
// changes.
#define DBGHELP_CHANGE_SYMOPT \
(SYMOPT_NO_PROMPTS | \
SYMOPT_DEBUG)
g_SymOptions = (g_SymOptions & ~DBGHELP_CHANGE_SYMOPT) |
(*(PULONG)CallbackData & DBGHELP_CHANGE_SYMOPT);
break;
default:
return FALSE;
}
return FALSE;
}
BOOL
ValidatePathComponent(PCSTR Part)
{
if (strlen(Part) == 0)
{
return FALSE;
}
else if (!_strnicmp(Part, "SYMSRV*", 7) ||
!_strnicmp(Part, "SRV*", 4) ||
IsUrlPathComponent(Part))
{
// No easy way to validate symbol server or URL paths.
// They're virtually always network references,
// so just disallow all such usage when net
// access isn't allowed.
if (g_EngOptions & DEBUG_ENGOPT_DISALLOW_NETWORK_PATHS)
{
return FALSE;
}
return TRUE;
}
else
{
DWORD Attrs;
DWORD OldMode;
char Expand[MAX_PATH];
// Otherwise make sure this is a valid directory.
if (!ExpandEnvironmentStrings(Part, Expand, sizeof(Expand)))
{
return FALSE;
}
if (g_EngOptions & DEBUG_ENGOPT_DISALLOW_NETWORK_PATHS)
{
// Don't call GetFileAttributes when network paths
// are disabled as net operations may cause deadlocks.
if (NetworkPathCheck(Expand) != ERROR_SUCCESS)
{
return FALSE;
}
}
// We can still get to this point when debugging CSR
// if the user has explicitly allowed net paths.
// This check isn't important enough to risk a hang.
if (AnySystemProcesses(TRUE))
{
return TRUE;
}
OldMode = SetErrorMode(SEM_FAILCRITICALERRORS);
Attrs = GetFileAttributes(Expand);
SetErrorMode(OldMode);
return Attrs != 0xffffffff && (Attrs & FILE_ATTRIBUTE_DIRECTORY);
}
}
void
SetSymbolSearchPath(ProcessInfo* Process)
{
LPSTR lpExePathEnv;
size_t cbExePath;
LPSTR lpSymPathEnv;
LPSTR lpAltSymPathEnv;
size_t cbSymPath;
LPSTR NewMem;
//
// Load the Binary path (needed for triage dumps)
//
// No clue why this or the next is 18 ...
cbExePath = 18;
if (g_ExecutableImageSearchPath)
{
cbExePath += strlen(g_ExecutableImageSearchPath) + 1;
}
lpExePathEnv = NULL;
if ((g_SymOptions & SYMOPT_IGNORE_NT_SYMPATH) == 0 &&
(lpExePathEnv = getenv("_NT_EXECUTABLE_IMAGE_PATH")))
{
cbExePath += strlen(lpExePathEnv) + 1;
}
NewMem = (char*)realloc(g_ExecutableImageSearchPath, cbExePath);
if (!NewMem)
{
ErrOut("Not enough memory to allocate/initialize "
"ExecutableImageSearchPath");
return;
}
if (!g_ExecutableImageSearchPath)
{
*NewMem = 0;
}
g_ExecutableImageSearchPath = NewMem;
if ((g_SymOptions & SYMOPT_IGNORE_NT_SYMPATH) == 0)
{
AppendComponentsToPath(g_ExecutableImageSearchPath, lpExePathEnv,
TRUE);
}
//
// Load symbol Path
//
cbSymPath = 18;
if (g_SymbolSearchPath)
{
cbSymPath += strlen(g_SymbolSearchPath) + 1;
}
if ((g_SymOptions & SYMOPT_IGNORE_NT_SYMPATH) == 0 &&
(lpSymPathEnv = getenv("_NT_SYMBOL_PATH")))
{
cbSymPath += strlen(lpSymPathEnv) + 1;
}
if ((g_SymOptions & SYMOPT_IGNORE_NT_SYMPATH) == 0 &&
(lpAltSymPathEnv = getenv("_NT_ALT_SYMBOL_PATH")))
{
cbSymPath += strlen(lpAltSymPathEnv) + 1;
}
NewMem = (char*)realloc(g_SymbolSearchPath, cbSymPath);
if (!NewMem)
{
ErrOut("Not enough memory to allocate/initialize "
"SymbolSearchPath");
return;
}
if (!g_SymbolSearchPath)
{
*NewMem = 0;
}
g_SymbolSearchPath = NewMem;
if ((g_SymOptions & SYMOPT_IGNORE_NT_SYMPATH) == 0)
{
AppendComponentsToPath(g_SymbolSearchPath, lpAltSymPathEnv, TRUE);
AppendComponentsToPath(g_SymbolSearchPath, lpSymPathEnv, TRUE);
}
SymSetSearchPath( Process->m_SymHandle, g_SymbolSearchPath );
dprintf("Symbol search path is: %s\n",
*g_SymbolSearchPath ?
g_SymbolSearchPath :
"*** Invalid *** : Verify _NT_SYMBOL_PATH setting" );
if (g_ExecutableImageSearchPath)
{
dprintf("Executable search path is: %s\n",
g_ExecutableImageSearchPath);
}
}
BOOL
SetCurrentScope(
IN PDEBUG_STACK_FRAME ScopeFrame,
IN OPTIONAL PVOID ScopeContext,
IN ULONG ScopeContextSize
)
{
BOOL ScopeChanged;
PDEBUG_SCOPE Scope = &g_ScopeBuffer;
if (Scope->State == ScopeDefaultLazy)
{
// It's not a lazy scope now.
Scope->State = ScopeDefault;
}
if (ScopeFrame->FrameNumber != 0)
{
// Backup 1 byte to get correct scoped locals
ScopeFrame->InstructionOffset--;
}
Scope->Process = g_Process;
Scope->CheckedForThis = FALSE;
ZeroMemory(&Scope->ThisData, sizeof(Scope->ThisData));
ScopeChanged = g_Process &&
SymSetContext(g_Process->m_SymHandle,
(PIMAGEHLP_STACK_FRAME) ScopeFrame,
ScopeContext);
if (ScopeFrame->FrameNumber != 0)
{
// restore backed up byte
ScopeFrame->InstructionOffset++;
}
if (ScopeContext && (sizeof(Scope->Context) >= ScopeContextSize))
{
memcpy(&Scope->Context, ScopeContext, ScopeContextSize);
Scope->ContextState = MCTX_FULL;
Scope->State = ScopeFromContext;
NotifyChangeDebuggeeState(DEBUG_CDS_REGISTERS, DEBUG_ANY_ID);
}
if (ScopeChanged ||
(ScopeFrame->FrameOffset != Scope->Frame.FrameOffset))
{
Scope->Frame = *ScopeFrame;
if (ScopeFrame->FuncTableEntry)
{
// Cache the FPO data since the pointer is only temporary
Scope->CachedFpo =
*((PFPO_DATA) ScopeFrame->FuncTableEntry);
Scope->Frame.FuncTableEntry =
(ULONG64) &Scope->CachedFpo;
}
NotifyChangeSymbolState(DEBUG_CSS_SCOPE, 0, g_Process);
}
else
{
Scope->Frame = *ScopeFrame;
if (ScopeFrame->FuncTableEntry)
{
// Cache the FPO data since the pointer is only temporary
Scope->CachedFpo =
*((PFPO_DATA) ScopeFrame->FuncTableEntry);
Scope->Frame.FuncTableEntry =
(ULONG64) &Scope->CachedFpo;
}
}
return ScopeChanged;
}
BOOL
ResetCurrentScopeLazy(void)
{
PDEBUG_SCOPE Scope = &g_ScopeBuffer;
if (Scope->State == ScopeFromContext)
{
NotifyChangeDebuggeeState(DEBUG_CDS_REGISTERS, DEBUG_ANY_ID);
}
Scope->State = ScopeDefaultLazy;
return TRUE;
}
BOOL
ResetCurrentScope(void)
{
DEBUG_STACK_FRAME LocalFrame;
PDEBUG_SCOPE Scope = &g_ScopeBuffer;
if (Scope->State == ScopeFromContext)
{
NotifyChangeDebuggeeState(DEBUG_CDS_REGISTERS, DEBUG_ANY_ID);
}
Scope->State = ScopeDefault;
ZeroMemory(&LocalFrame, sizeof(LocalFrame));
// At the initial kernel load the system is only partially
// initialized and is very sensitive to bad memory reads.
// Stack traces can cause reads through unusual memory areas
// so it's best to avoid them at this time. This isn't
// much of a problem since users don't usually expect a locals
// context at this point.
if ((IS_USER_TARGET(g_Target) ||
(g_EngStatus & ENG_STATUS_AT_INITIAL_MODULE_LOAD) == 0) &&
IS_CUR_CONTEXT_ACCESSIBLE())
{
if (!StackTrace(NULL, 0, 0, 0, STACK_ALL_DEFAULT,
&LocalFrame, 1, 0, 0, TRUE))
{
ADDR Addr;
g_Machine->GetPC(&Addr);
LocalFrame.InstructionOffset = Addr.off;
}
}
return SetCurrentScope(&LocalFrame, NULL, 0);
}
ULONG
GetCurrentScopeThisData(TypedData* Data)
{
PDEBUG_SCOPE Scope = GetCurrentScope();
if (!Scope->CheckedForThis)
{
ULONG Tag;
if (Scope->ThisData.FindSymbol(Scope->Process,
"this",
TDACC_REQUIRE,
g_Machine->m_Ptr64 ? 8 : 4) ||
!Scope->ThisData.m_Image ||
!Scope->ThisData.IsPointer() ||
Scope->ThisData.GetTypeTag(Scope->ThisData.m_NextType, &Tag) ||
Tag != SymTagUDT)
{
ZeroMemory(&Scope->ThisData, sizeof(Scope->ThisData));
}
Scope->CheckedForThis = TRUE;
}
if (!Scope->ThisData.m_Image)
{
return VARDEF;
}
*Data = Scope->ThisData;
return NO_ERROR;
}
void
ListUnloadedModules(ULONG Flags, PSTR Pattern)
{
UnloadedModuleInfo* Unl;
g_Process->m_NumUnloadedModules = 0;
Unl = g_Target->GetUnloadedModuleInfo();
if (Unl == NULL || Unl->Initialize(g_Thread) != S_OK)
{
// User-mode only has an unloaded module list
// for .NET Server, so don't show any errors
// if there isn't one.
if (IS_KERNEL_TARGET(g_Target))
{
ErrOut("No unloaded module list present\n");
}
return;
}
char UnlName[MAX_INFO_UNLOADED_NAME];
DEBUG_MODULE_PARAMETERS Params;
if (Flags & LUM_OUTPUT)
{
dprintf("Unloaded modules:\n");
}
while (Unl->GetEntry(UnlName, &Params) == S_OK)
{
g_Process->m_NumUnloadedModules++;
if (Pattern != NULL &&
!MatchPattern(UnlName, Pattern))
{
continue;
}
if (Flags & LUM_OUTPUT_TERSE)
{
dprintf(".");
continue;
}
if (Flags & LUM_OUTPUT)
{
dprintf("%s %s %-8s\n",
FormatAddr64(Params.Base),
FormatAddr64(Params.Base + Params.Size),
UnlName);
}
if (Flags & ( LUM_OUTPUT_VERBOSE | LUM_OUTPUT_IMAGE_INFO))
{
PSTR TimeDateStr = TimeToStr(Params.TimeDateStamp);
dprintf(" Timestamp: %s (%08X)\n",
TimeDateStr, Params.TimeDateStamp);
dprintf(" Checksum: %08X\n", Params.Checksum);
}
}
dprintf("\n");
}
ULONG
ModuleMachineType(ProcessInfo* Process, ULONG64 Offset)
{
ImageInfo* Image = Process->FindImageByOffset(Offset, FALSE);
return Image ? Image->GetMachineType() : IMAGE_FILE_MACHINE_UNKNOWN;
}
ULONG
IsInFastSyscall(ULONG64 Addr, PULONG64 Base)
{
if (Addr >= g_Target->m_TypeInfo.UmSharedSysCallOffset &&
Addr < g_Target->m_TypeInfo.UmSharedSysCallOffset +
g_Target->m_TypeInfo.UmSharedSysCallSize)
{
*Base = g_Target->m_TypeInfo.UmSharedSysCallOffset;
return FSC_FOUND;
}
return FSC_NONE;
}
BOOL
ShowFunctionParameters(PDEBUG_STACK_FRAME StackFrame)
{
SYM_DUMP_PARAM_EX SymFunction = {0};
ULONG Status = 0;
PDEBUG_SCOPE Scope = GetCurrentScope();
DEBUG_SCOPE SavScope = *Scope;
SymFunction.size = sizeof(SYM_DUMP_PARAM_EX);
SymFunction.addr = StackFrame->InstructionOffset;
SymFunction.Options = DBG_DUMP_COMPACT_OUT | DBG_DUMP_FUNCTION_FORMAT;
// SetCurrentScope to this function
SymSetContext(g_Process->m_SymHandle,
(PIMAGEHLP_STACK_FRAME) StackFrame, NULL);
Scope->Frame = *StackFrame;
if (StackFrame->FuncTableEntry)
{
// Cache the FPO data since the pointer is only temporary
Scope->CachedFpo = *((PFPO_DATA) StackFrame->FuncTableEntry);
Scope->Frame.FuncTableEntry =
(ULONG64) &Scope->CachedFpo;
}
if (!SymbolTypeDumpNew(&SymFunction, &Status) &&
!Status)
{
Status = TRUE;
}
g_ScopeBuffer = SavScope;
SymSetContext(g_Process->m_SymHandle,
(PIMAGEHLP_STACK_FRAME) &Scope->Frame, NULL);
return !Status;
}