|
|
//----------------------------------------------------------------------------
//
// 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; }
|