windows-nt/Source/XPSP1/NT/sdktools/debuggers/imagehlp/symbols.c
2020-09-26 16:20:57 +08:00

4190 lines
99 KiB
C

/*++
Copyright (c) 1995 Microsoft Corporation
Module Name:
symbols.c
Abstract:
This function implements a generic simple symbol handler.
Author:
Wesley Witt (wesw) 1-Sep-1994
Environment:
User Mode
--*/
#include "private.h"
#include "symbols.h"
#include "globals.h"
#include <dbhpriv.h>
#include "fecache.hpp"
BOOL
IMAGEAPI
SympGetSymNextPrev(
IN HANDLE hProcess,
IN OUT PIMAGEHLP_SYMBOL64 Symbol,
IN int Direction
);
#ifndef _DBGHELP_USER_GENERATED_SYMBOLS_NOTSUPPORTED
PSYMBOL_ENTRY
IMAGEAPI
AllocSym(
IN PMODULE_ENTRY mi,
IN DWORD64 addr,
IN LPSTR name
);
VOID
CompleteSymbolTable(
IN PMODULE_ENTRY mi
);
#endif // !_DBGHELP_USER_GENERATED_SYMBOLS_NOTSUPPORTED
typedef struct _STORE_OLD_CB {
BOOL cb64;
union{
PSYM_ENUMSYMBOLS_CALLBACK UserCallBackRoutine;
PSYM_ENUMSYMBOLS_CALLBACK64 UserCallBackRoutine64;
};
PVOID UserContext;
} STORE_OLD_CB;
BOOL
ImgHlpDummyCB(
PSYMBOL_INFO pSymInfo,
ULONG SymbolSize,
PVOID UserContext
)
{
STORE_OLD_CB *pOld = (STORE_OLD_CB *) UserContext;
if (pSymInfo->Flags & SYMF_REGREL) {
LARGE_INTEGER li;
li.HighPart = pSymInfo->Register;
li.LowPart = (ULONG) pSymInfo->Address;
pSymInfo->Address = li.QuadPart;
}
if (pOld->cb64) {
return (*pOld->UserCallBackRoutine64) (
pSymInfo->Name,
pSymInfo->Address,
SymbolSize,
pOld->UserContext );
} else {
return (*pOld->UserCallBackRoutine) (
pSymInfo->Name,
(ULONG) pSymInfo->Address,
SymbolSize,
pOld->UserContext );
}
}
void
symcpy2(
PSYMBOL_INFO SymInfo,
PSYMBOL_ENTRY SymEntry
)
{
SymInfo->Address = SymEntry->Address;
SymInfo->Flags = SymEntry->Flags;
SymInfo->TypeIndex = SymEntry->TypeIndex;
SymInfo->ModBase = SymEntry->ModBase;
SymInfo->NameLen = SymEntry->NameLength;
SymInfo->Size = SymEntry->Size;
SymInfo->Register = SymEntry->Register;
if (SymEntry->Name &&
(strlen(SymEntry->Name) < SymInfo->MaxNameLen)) {
strcpy(SymInfo->Name, SymEntry->Name);
}
}
BOOL
TestOutputString(
PCHAR sz
)
{
CHAR c;
__try {
c = *sz;
} __except(EXCEPTION_EXECUTE_HANDLER) {
SetLastError(ERROR_INVALID_PARAMETER);
return FALSE;
}
return TRUE;
}
BOOL
InitOutputString(
PCHAR sz
)
{
BOOL rc;
rc = TestOutputString(sz);
if (rc)
*sz = 0;
return rc;
}
BOOL
DoEnumCallback(
PPROCESS_ENTRY pe,
PSYMBOL_INFO pSymInfo,
ULONG SymSize,
PROC EnumCallback,
PVOID UserContext,
BOOL Use64,
BOOL UsesUnicode
)
{
BOOL rc = FALSE;
if (pSymInfo)
{
if (Use64 || (!UsesUnicode))
{
rc = (*(PSYM_ENUMERATESYMBOLS_CALLBACK)EnumCallback) (
pSymInfo,
SymSize,
UserContext);
}
else
{
PWSTR pszTmp = AnsiToUnicode(pSymInfo->Name);
if (pszTmp)
{
strncpy(pSymInfo->Name, (LPSTR) pszTmp,
min(pSymInfo->MaxNameLen, wcslen(pszTmp)));
*((LPWSTR) &pSymInfo->Name[min(pSymInfo->MaxNameLen, wcslen(pszTmp)) - 1 ]) = 0;
rc = (*(PSYM_ENUMERATESYMBOLS_CALLBACK)EnumCallback) (
pSymInfo,
SymSize,
UserContext );
MemFree(pszTmp);
}
}
}
return rc;
}
BOOL
IMAGEAPI
SymInitialize(
IN HANDLE hProcess,
IN LPSTR UserSearchPath,
IN BOOL InvadeProcess
)
/*++
Routine Description:
This function initializes the symbol handler for
a process. The process is identified by the
process handle passed into this function.
Arguments:
hProcess - Process handle. If InvadeProcess is FALSE
then this can be any unique value that identifies
the process to the symbol handler.
UserSearchPath - Pointer to a string of paths separated by semicolons.
These paths are used to search for symbol files.
The value NULL is acceptable.
InvadeProcess - If this is set to TRUE then the process identified
by the process handle is "invaded" and it's loaded
module list is enumerated. Each module is added
to the symbol handler and symbols are attempted
to be loaded.
Return Value:
TRUE - The symbol handler was successfully initialized.
FALSE - The initialization failed. Call GetLastError to
discover the cause of the failure.
--*/
{
PPROCESS_ENTRY pe;
__try {
if (!g.SymInitialized) {
g.SymInitialized = TRUE;
g.cProcessList = 0;
InitializeListHead( &g.ProcessList );
}
*g.DebugToken = 0;
GetEnvironmentVariable(DEBUG_TOKEN, g.DebugToken, sizeof(g.DebugToken) / sizeof(g.DebugToken[0]));
_strlwr(g.DebugToken);
if (FindProcessEntry( hProcess )) {
SetLastError( ERROR_INVALID_HANDLE );
return TRUE;
}
pe = (PPROCESS_ENTRY) MemAlloc( sizeof(PROCESS_ENTRY) );
if (!pe) {
SetLastError( ERROR_NOT_ENOUGH_MEMORY );
return FALSE;
}
ZeroMemory( pe, sizeof(PROCESS_ENTRY) );
pe->hProcess = hProcess;
pe->pid = (int) GetPID(hProcess);
g.cProcessList++;
InitializeListHead( &pe->ModuleList );
InsertTailList( &g.ProcessList, &pe->ListEntry );
if (!SymSetSearchPath( hProcess, UserSearchPath )) {
//
// last error code was set by SymSetSearchPath, so just return
//
SymCleanup( hProcess );
return FALSE;
}
if (!diaInit()) {
SymCleanup( hProcess );
return FALSE;
}
if (InvadeProcess) {
DWORD DosError = GetProcessModules(hProcess, InternalGetModule, NULL);
if (DosError) {
SymCleanup( hProcess );
SetLastError( DosError );
return FALSE;
}
}
} __except (EXCEPTION_EXECUTE_HANDLER) {
ImagepSetLastErrorFromStatus( GetExceptionCode() );
return FALSE;
}
return TRUE;
}
BOOL
IMAGEAPI
SymCleanup(
HANDLE hProcess
)
/*++
Routine Description:
This function cleans up the symbol handler's data structures
for a previously initialized process.
Arguments:
hProcess - Process handle.
Return Value:
TRUE - The symbol handler was successfully cleaned up.
FALSE - The cleanup failed. Call GetLastError to
discover the cause of the failure.
--*/
{
PPROCESS_ENTRY pe;
PLIST_ENTRY next;
PMODULE_ENTRY mi;
BOOL rc = TRUE;
HeapDump("SymCleanup(before cleanup)\n");
__try {
pe = FindProcessEntry(hProcess);
if (!pe) {
SetLastError( ERROR_INVALID_HANDLE );
return FALSE;
}
next = pe->ModuleList.Flink;
if (next) {
while (next != &pe->ModuleList) {
mi = CONTAINING_RECORD(next, MODULE_ENTRY, ListEntry);
next = mi->ListEntry.Flink;
FreeModuleEntry(pe, mi);
}
}
CloseSymbolServer();
if (pe->SymbolSearchPath) {
MemFree(pe->SymbolSearchPath);
}
RemoveEntryList(&pe->ListEntry);
MemFree(pe);
g.cProcessList--;
// Assume that things are shutting down and
// dump all the function entry caches.
ClearFeCaches();
} __except (EXCEPTION_EXECUTE_HANDLER) {
ImagepSetLastErrorFromStatus(GetExceptionCode());
rc = FALSE;
}
HeapDump("SymCleanup(after cleanup)\n");
return rc;
}
DWORD
IMAGEAPI
SymSetOptions(
DWORD UserOptions
)
/*++
Routine Description:
This function changes the symbol handler's option mask.
Arguments:
UserOptions - The new options mask.
Return Value:
The new mask is returned.
--*/
{
g.SymOptions = UserOptions;
SetSymbolServerCallback(g.SymOptions & SYMOPT_DEBUG ? TRUE : FALSE);
DoCallback(NULL, CBA_SET_OPTIONS, &g.SymOptions);
return g.SymOptions;
}
DWORD
IMAGEAPI
SymGetOptions(
VOID
)
/*++
Routine Description:
This function queries the symbol handler's option mask.
Arguments:
None.
Return Value:
The current options mask is returned.
--*/
{
return g.SymOptions;
}
ULONG
IMAGEAPI
SymSetContext(
HANDLE hProcess,
PIMAGEHLP_STACK_FRAME StackFrame,
PIMAGEHLP_CONTEXT Context
)
{
PPROCESS_ENTRY pe;
pe = FindProcessEntry(hProcess);
if (pe) {
pe->pContext = Context;
pe->StackFrame = *StackFrame;
return diaSetModFromIP(pe);
}
return FALSE;
};
BOOL
SympEnumerateModules(
IN HANDLE hProcess,
IN PROC EnumModulesCallback,
IN PVOID UserContext,
IN BOOL Use64
)
/*++
Routine Description:
This is the worker function for the 32 and 64 bit versions.
Arguments:
hProcess - Process handle, must have been previously registered
with SymInitialize.
EnumModulesCallback - Callback pointer that is called once for each
module that is enumerated. If the enum callback
returns FALSE then the enumeration is terminated.
UserContext - This data is simply passed on to the callback function
and is completly user defined.
Use64 - Supplies flag which determines whether to use the 32 bit
or 64 bit callback prototype.
Return Value:
TRUE - The modules were successfully enumerated.
FALSE - The enumeration failed. Call GetLastError to
discover the cause of the failure.
--*/
{
PPROCESS_ENTRY pe;
PMODULE_ENTRY mi;
PLIST_ENTRY Next;
__try {
pe = FindProcessEntry( hProcess );
if (!pe) {
SetLastError( ERROR_INVALID_HANDLE );
return FALSE;
}
Next = pe->ModuleList.Flink;
if (Next) {
while (Next != &pe->ModuleList) {
mi = CONTAINING_RECORD( Next, MODULE_ENTRY, ListEntry );
Next = mi->ListEntry.Flink;
if (Use64) {
if ( !(*(PSYM_ENUMMODULES_CALLBACK64)EnumModulesCallback) (
mi->ModuleName,
mi->BaseOfDll,
UserContext
)) {
break;
}
} else {
if ( !(*(PSYM_ENUMMODULES_CALLBACK)EnumModulesCallback) (
mi->ModuleName,
(DWORD)mi->BaseOfDll,
UserContext
)) {
break;
}
}
}
}
} __except (EXCEPTION_EXECUTE_HANDLER) {
ImagepSetLastErrorFromStatus( GetExceptionCode() );
return FALSE;
}
return TRUE;
}
BOOL
dbhfnModSymInfo(
IN HANDLE hp,
IN OUT PDBH_MODSYMINFO p
)
{
PMODULE_ENTRY mi;
PPROCESS_ENTRY pe;
assert(p->function == dbhModSymInfo);
pe = FindProcessEntry(hp);
if (!pe) {
SetLastError( ERROR_INVALID_HANDLE );
return FALSE;
}
if (p->sizeofstruct != sizeof(DBH_MODSYMINFO)) {
SetLastError(ERROR_INVALID_PARAMETER);
return FALSE;
}
mi = GetModuleForPC(pe, p->addr, FALSE);
if (!mi) {
SetLastError(ERROR_MOD_NOT_FOUND);
return FALSE;
}
p->type = mi->SymType;
*p->file = 0;
switch (p->type)
{
case SymPdb:
case SymDia:
if (mi->LoadedPdbName)
strcpy(p->file, mi->LoadedPdbName);
break;
default:
if (mi->LoadedImageName)
strcpy(p->file, mi->LoadedImageName);
break;
}
return TRUE;
}
BOOL
dbhfnDiaVersion(
IN OUT PDBH_DIAVERSION p
)
{
PMODULE_ENTRY mi;
assert(p->function == dbhDiaVersion);
if (p->sizeofstruct != sizeof(DBH_DIAVERSION)) {
SetLastError(ERROR_INVALID_PARAMETER);
return FALSE;
}
p->ver = diaVersion();
return TRUE;
}
BOOL
IMAGEAPI
dbghelp(
IN HANDLE hp,
IN OUT PVOID data
)
{
DWORD *function;
if (!data) {
SetLastError(ERROR_INVALID_PARAMETER);
return FALSE;
}
__try {
function = (DWORD *)data;
switch (*function)
{
case dbhModSymInfo:
return dbhfnModSymInfo(hp, (PDBH_MODSYMINFO)data);
case dbhDiaVersion:
return dbhfnDiaVersion((PDBH_DIAVERSION)data);
default:
SetLastError(ERROR_INVALID_PARAMETER);
return FALSE;
}
} __except (EXCEPTION_EXECUTE_HANDLER) {
ImagepSetLastErrorFromStatus(GetExceptionCode());
return FALSE;
}
return FALSE;
}
BOOL
IMAGEAPI
SymEnumerateModules(
IN HANDLE hProcess,
IN PSYM_ENUMMODULES_CALLBACK EnumModulesCallback,
IN PVOID UserContext
)
/*++
Routine Description:
This function enumerates all of the modules that are currently
loaded into the symbol handler. This is the 32 bit wrapper.
Arguments:
hProcess - Process handle, must have been previously registered
with SymInitialize.
EnumModulesCallback - Callback pointer that is called once for each
module that is enumerated. If the enum callback
returns FALSE then the enumeration is terminated.
UserContext - This data is simply passed on to the callback function
and is completly user defined.
Return Value:
TRUE - The modules were successfully enumerated.
FALSE - The enumeration failed. Call GetLastError to
discover the cause of the failure.
--*/
{
return SympEnumerateModules(hProcess, (PROC)EnumModulesCallback, UserContext, FALSE);
}
BOOL
IMAGEAPI
SymEnumerateModules64(
IN HANDLE hProcess,
IN PSYM_ENUMMODULES_CALLBACK64 EnumModulesCallback,
IN PVOID UserContext
)
/*++
Routine Description:
This function enumerates all of the modules that are currently
loaded into the symbol handler. This is the 64 bit wrapper.
Arguments:
hProcess - Process handle, must have been previously registered
with SymInitialize.
EnumModulesCallback - Callback pointer that is called once for each
module that is enumerated. If the enum callback
returns FALSE then the enumeration is terminated.
UserContext - This data is simply passed on to the callback function
and is completly user defined.
Return Value:
TRUE - The modules were successfully enumerated.
FALSE - The enumeration failed. Call GetLastError to
discover the cause of the failure.
--*/
{
return SympEnumerateModules(hProcess, (PROC)EnumModulesCallback, UserContext, TRUE);
}
DWORD
CalcItemSize(
PDWORD64 pAddr,
PDWORD64 pAddrsBase,
UINT_PTR count
)
{
PDWORD64 p;
PDWORD64 pAddrEnd;
if (!pAddr)
return 0;
pAddrEnd = pAddrsBase + count;
for (p = pAddr + 1; p <= pAddrEnd; p++) {
if (*p != *pAddr)
return (DWORD)(*p - *pAddr);
}
return 0;
}
BOOL
MatchModuleName(
PMODULE_ENTRY mi,
LPSTR mask
)
{
if (!strcmpre(mi->AliasName, mask, FALSE))
return TRUE;
if (!strcmpre(mi->ModuleName, mask, FALSE))
return TRUE;
return FALSE;
}
BOOL
SympEnumerateSymbols(
IN HANDLE hProcess,
IN ULONG64 BaseOfDll,
IN LPSTR Mask,
IN PROC EnumSymbolsCallback,
IN PVOID UserContext,
IN BOOL Use64,
IN BOOL CallBackUsesUnicode
)
/*++
Routine Description:
This function enumerates all of the symbols contained the module
specified by the BaseOfDll argument.
Arguments:
hProcess - Process handle, must have been previously registered
with SymInitialize
BaseOfDll - Base address of the DLL that symbols are to be
enumerated for
EnumSymbolsCallback - User specified callback routine for enumeration
notification
UserContext - Pass thru variable, this is simply passed thru to the
callback function
Use64 - Supplies flag which determines whether to use the 32 bit
or 64 bit callback prototype.
Return Value:
TRUE - The symbols were successfully enumerated.
FALSE - The enumeration failed. Call GetLastError to
discover the cause of the failure.
--*/
{
PPROCESS_ENTRY pe;
PLIST_ENTRY Next;
PMODULE_ENTRY mi;
DWORD i;
PSYMBOL_ENTRY sym;
LPSTR szSymName;
SYMBOL_ENTRY SymEntry={0};
CHAR Buffer[2500];
LPSTR p;
CHAR modmask[200];
BOOL rc;
int pass;
BOOL fCase;
static DWORD flags[2] = {LS_JUST_TEST, LS_QUALIFIED | LS_FAIL_IF_LOADED};
__try {
pe = FindProcessEntry( hProcess );
if (!pe) {
SetLastError( ERROR_INVALID_HANDLE );
return FALSE;
}
p = 0;
modmask[0] = 0;
if (Mask)
p = strchr(Mask, '!');
if (p > Mask) {
memcpy(modmask, Mask, (int)(p - Mask));
modmask[p-Mask] = 0;
Mask = p + 1;
} else if (!BaseOfDll) {
rc = diaEnumerateSymbols(pe,
NULL,
Mask,
EnumSymbolsCallback,
UserContext,
Use64,
CallBackUsesUnicode);
if (!rc && pe->ipmi && pe->ipmi->code == ERROR_CANCELLED) {
pe->ipmi->code = 0;
return TRUE;
}
return rc;
}
for (pass = 0; pass < 2; pass++) {
Next = pe->ModuleList.Flink;
if (Next) {
while (Next != &pe->ModuleList) {
mi = CONTAINING_RECORD( Next, MODULE_ENTRY, ListEntry );
Next = mi->ListEntry.Flink;
if (BaseOfDll) {
if (mi->BaseOfDll != BaseOfDll)
continue;
} else if (!MatchModuleName(mi, modmask)) {
continue;
}
if (!LoadSymbols(hProcess, mi, flags[pass]))
continue;
if (mi->dia) {
rc = diaEnumerateSymbols(pe,
mi,
Mask,
EnumSymbolsCallback,
UserContext,
Use64,
CallBackUsesUnicode);
if (!rc) {
if (mi->code == ERROR_CANCELLED) {
mi->code = 0;
return TRUE;
}
return rc;
}
continue;
}
fCase = (g.SymOptions & SYMOPT_CASE_INSENSITIVE) ? FALSE : TRUE;
for (i = 0; i < mi->numsyms; i++) {
PSYMBOL_INFO SymInfo = (PSYMBOL_INFO) &Buffer[0];
sym = &mi->symbolTable[i];
if (Mask && *Mask && strcmpre(sym->Name, Mask, fCase))
continue;
mi->TmpSym.Name[0] = 0;
strncat( mi->TmpSym.Name, sym->Name, TMP_SYM_LEN );
SymEntry = *sym;
SymEntry.Name = mi->TmpSym.Name;
SymInfo->MaxNameLen = sizeof(Buffer) - sizeof(SYMBOL_INFO);
symcpy2(SymInfo, &SymEntry);
SymInfo->ModBase = mi->BaseOfDll;
if (!DoEnumCallback(
pe,
SymInfo,
sym->Size,
EnumSymbolsCallback,
UserContext,
Use64,
CallBackUsesUnicode)) {
break;
}
}
break;
}
}
}
} __except (EXCEPTION_EXECUTE_HANDLER) {
ImagepSetLastErrorFromStatus( GetExceptionCode() );
return FALSE;
}
return TRUE;
}
BOOL
IMAGEAPI
SymEnumerateSymbols(
IN HANDLE hProcess,
IN ULONG BaseOfDll,
IN PSYM_ENUMSYMBOLS_CALLBACK EnumSymbolsCallback,
IN PVOID UserContext
)
/*++
Routine Description:
This function enumerates all of the symbols contained the module
specified by the BaseOfDll argument.
Arguments:
hProcess - Process handle, must have been previously registered
with SymInitialize
BaseOfDll - Base address of the DLL that symbols are to be
enumerated for
EnumSymbolsCallback - User specified callback routine for enumeration
notification
UserContext - Pass thru variable, this is simply passed thru to the
callback function
Return Value:
TRUE - The symbols were successfully enumerated.
FALSE - The enumeration failed. Call GetLastError to
discover the cause of the failure.
--*/
{
STORE_OLD_CB OldCB;
OldCB.UserCallBackRoutine = EnumSymbolsCallback;
OldCB.UserContext = UserContext;
OldCB.cb64 = FALSE;
return SympEnumerateSymbols(hProcess,
BaseOfDll,
NULL,
(PROC) (EnumSymbolsCallback ? &ImgHlpDummyCB : NULL),
(PVOID) &OldCB,
FALSE,
FALSE);
}
BOOL
IMAGEAPI
SymEnumerateSymbolsW(
IN HANDLE hProcess,
IN ULONG BaseOfDll,
IN PSYM_ENUMSYMBOLS_CALLBACKW EnumSymbolsCallback,
IN PVOID UserContext
)
{
STORE_OLD_CB OldCB;
OldCB.UserCallBackRoutine = (PSYM_ENUMSYMBOLS_CALLBACK) EnumSymbolsCallback;
OldCB.UserContext = UserContext;
OldCB.cb64 = FALSE;
return SympEnumerateSymbols(hProcess,
BaseOfDll,
NULL,
(PROC) (EnumSymbolsCallback ? &ImgHlpDummyCB : NULL),
(PVOID) &OldCB,
FALSE,
FALSE);
}
BOOL
IMAGEAPI
SymEnumerateSymbols64(
IN HANDLE hProcess,
IN ULONG64 BaseOfDll,
IN PSYM_ENUMSYMBOLS_CALLBACK64 EnumSymbolsCallback,
IN PVOID UserContext
)
{
STORE_OLD_CB OldCB;
OldCB.UserCallBackRoutine64 = EnumSymbolsCallback;
OldCB.UserContext = UserContext;
OldCB.cb64 = TRUE;
return SympEnumerateSymbols(hProcess,
BaseOfDll,
NULL,
(PROC) (EnumSymbolsCallback ? &ImgHlpDummyCB : NULL),
(PVOID) &OldCB,
FALSE,
FALSE);
}
BOOL
IMAGEAPI
SymEnumerateSymbolsW64(
IN HANDLE hProcess,
IN ULONG64 BaseOfDll,
IN PSYM_ENUMSYMBOLS_CALLBACK64W EnumSymbolsCallback,
IN PVOID UserContext
)
{
STORE_OLD_CB OldCB;
OldCB.UserCallBackRoutine64 = (PSYM_ENUMSYMBOLS_CALLBACK64) EnumSymbolsCallback;
OldCB.UserContext = UserContext;
OldCB.cb64 = TRUE;
return SympEnumerateSymbols(hProcess,
BaseOfDll,
NULL,
(PROC) (EnumSymbolsCallback ? &ImgHlpDummyCB : NULL),
(PVOID) &OldCB,
FALSE,
FALSE);
}
BOOL
SympGetSymFromAddr(
IN HANDLE hProcess,
IN DWORD64 Address,
OUT PDWORD64 Displacement,
OUT PSYMBOL_ENTRY SymRet
)
/*++
Routine Description:
This function finds an entry in the symbol table based on an address.
This is the common worker function for the 32 and 64 bit API.
Arguments:
hProcess - Process handle, must have been previously registered
with SymInitialize.
Address - Address of the desired symbol.
Displacement - This value is set to the offset from the beginning
of the symbol.
sym - Returns the found symbol
Return Value:
TRUE - The symbol was located.
FALSE - The symbol was not found. Call GetLastError to
discover the cause of the failure.
--*/
{
PPROCESS_ENTRY pe;
PMODULE_ENTRY mi;
PSYMBOL_ENTRY psym;
__try {
pe = FindProcessEntry( hProcess );
if (!pe) {
SetLastError( ERROR_INVALID_HANDLE );
return FALSE;
}
mi = GetModuleForPC( pe, Address, FALSE );
if (mi == NULL) {
SetLastError( ERROR_MOD_NOT_FOUND );
return FALSE;
}
if (!LoadSymbols(hProcess, mi, 0)) {
SetLastError( ERROR_MOD_NOT_FOUND );
return FALSE;
}
psym = GetSymFromAddr( Address, Displacement, mi );
if (psym) {
*SymRet = *psym;
} else {
SetLastError( ERROR_INVALID_ADDRESS );
return FALSE;
}
} __except (EXCEPTION_EXECUTE_HANDLER) {
ImagepSetLastErrorFromStatus( GetExceptionCode() );
return FALSE;
}
return TRUE;
}
BOOL
IMAGEAPI
SymGetSymFromAddr64(
IN HANDLE hProcess,
IN DWORD64 Address,
OUT PDWORD64 Displacement,
OUT PIMAGEHLP_SYMBOL64 Symbol
)
/*++
Routine Description:
This function finds an entry in the symbol table based on an address.
Arguments:
hProcess - Process handle, must have been previously registered
with SymInitialize.
Address - Address of the desired symbol.
Displacement - This value is set to the offset from the beginning
of the symbol.
Symbol - Returns the found symbol
Return Value:
TRUE - The symbol was located.
FALSE - The symbol was not found. Call GetLastError to
discover the cause of the failure.
--*/
{
SYMBOL_ENTRY sym;
if (SympGetSymFromAddr(hProcess, Address, Displacement, &sym)) {
symcpy64(Symbol, &sym);
return TRUE;
} else {
return FALSE;
}
}
BOOL
IMAGEAPI
SymGetSymFromAddr(
IN HANDLE hProcess,
IN DWORD Address,
OUT PDWORD Displacement,
OUT PIMAGEHLP_SYMBOL Symbol
)
/*++
Routine Description:
This function finds an entry in the symbol table based on an address.
Arguments:
hProcess - Process handle, must have been previously registered
with SymInitialize.
Address - Address of the desired symbol.
Displacement - This value is set to the offset from the beginning
of the symbol.
Symbol - Returns the found symbol
Return Value:
TRUE - The symbol was located.
FALSE - The symbol was not found. Call GetLastError to
discover the cause of the failure.
--*/
{
SYMBOL_ENTRY sym;
DWORD64 qDisplacement;
if (SympGetSymFromAddr(hProcess, Address, &qDisplacement, &sym)) {
symcpy32(Symbol, &sym);
if (Displacement) {
*Displacement = (DWORD)qDisplacement;
}
return TRUE;
} else {
return FALSE;
}
}
#ifndef _DBGHELP_USER_GENERATED_SYMBOLS_NOTSUPPORTED
#if 0
VOID
DumpMiSymbolTable(
PMODULE_ENTRY mi
)
{
PSYMBOL_ENTRY sym;
if ( !mi )
return;
sym = mi->symbolTable;
for ( sym = mi->symbolTable; sym < &mi->symbolTable[mi->numsyms] ; sym++ ) {
dprint("sym: %40s 0x%I64x %ld\n", sym->Name, sym->Address, sym->Size );
}
return;
} // DumpMiSymbolTable()
#endif // 0
#ifdef __cplusplus
extern "C"
#endif
BOOL
SymSetSymWithAddr64(
IN HANDLE hProcess,
IN DWORD64 Address,
IN LPSTR SymString,
OUT PIMAGEHLP_SYMBOL64 Symbol
)
/*++
Routine Description:
This function allocates an entry in the symbol table based on an address.
Arguments:
hProcess - Process handle, must have been previously registered
with SymInitialize.
Address - Address of the desired symbol.
SymString - Symbol name.
Return Value:
TRUE - The symbol was allocated.
FALSE - The symbol was not allocated. all GetLastError to
discover the cause of the failure.
--*/
{
PPROCESS_ENTRY pe;
PMODULE_ENTRY mi;
PSYMBOL_ENTRY psym;
BOOL ret;
DWORD64 displacement;
if ( !SymString ) {
SetLastError( ERROR_INVALID_PARAMETER );
return FALSE;
}
ret = TRUE;
__try {
pe = FindProcessEntry( hProcess );
if (!pe) {
SetLastError( ERROR_INVALID_HANDLE ), ret = FALSE;
__leave;
}
mi = GetModuleForPC( pe, Address, FALSE );
if (mi == NULL) {
SetLastError( ERROR_MOD_NOT_FOUND ), ret = FALSE;
__leave;
}
if (!LoadSymbols(hProcess, mi, 0)) {
SetLastError( ERROR_MOD_NOT_FOUND ), ret = FALSE;
__leave;
}
//
// Let's verify that this address is not already used...
// If yes, returns FALSE. The caller could parse the LastError.
//
psym = GetSymFromAddr( Address, &displacement, mi );
if ( psym ) {
pprint(pe, "SymSetSymWithAddr64: symbol %s already exists at this address 0x%I64x\n", psym->Name, Address );
SetLastError( ERROR_ALREADY_EXISTS ), ret = FALSE;
__leave;
}
//
// Allocate a new entry.
// This allocation is under imagehlp rules.
// Meaning that if the symbols table has overflow,
// we will not allocate an entry. This implementation]
// does not use a specific bucket of entries.
//
psym = AllocSym( mi, Address, SymString );
if ( !psym ) {
SetLastError( ERROR_INVALID_ADDRESS ), ret = FALSE;
__leave;
}
psym->Flags |= SYMF_USER_GENERATED;
symcpy64(Symbol, psym);
CompleteSymbolTable( mi );
} __except (EXCEPTION_EXECUTE_HANDLER) {
ImagepSetLastErrorFromStatus( GetExceptionCode() );
ret = FALSE;
}
return ret;
} // SymSetSymWithAddr64()
#endif // !_DBGHELP_USER_GENERATED_SYMBOLS_NOTSUPPORTED
BOOL
SympGetSymFromName(
IN HANDLE hProcess,
IN LPSTR Name,
OUT PSYMBOL_ENTRY SymRet
)
/*++
Routine Description:
This function finds an entry in the symbol table based on a name.
Arguments:
hProcess - Process handle, must have been previously registered
with SymInitialize.
SymName - A string containing the symbol name.
sym - Returns the located symbol
Return Value:
TRUE - The symbol was located.
FALSE - The symbol was not found. Call GetLastError to
discover the cause of the failure.
--*/
{
LPSTR p;
PPROCESS_ENTRY pe;
PMODULE_ENTRY mi = NULL;
PLIST_ENTRY Next;
PSYMBOL_ENTRY psym;
IMAGEHLP_DEFERRED_SYMBOL_LOAD64 idsl64;
int pass;
static DWORD flags[2] = {LS_JUST_TEST, LS_QUALIFIED};
__try {
pe = FindProcessEntry( hProcess );
if (!pe) {
SetLastError( ERROR_INVALID_HANDLE );
return FALSE;
}
// first check for fully qualified symbol name I.E. mod!sym
p = strchr( Name, '!' );
if (p > Name) {
LPSTR ModName = (LPSTR)MemAlloc(p - Name + 1);
if (!ModName) {
SetLastError( ERROR_NOT_ENOUGH_MEMORY );
return FALSE;
}
memcpy(ModName, Name, (int)(p - Name));
ModName[p-Name] = 0;
//
// the caller wants to look in a specific module
//
mi = FindModule(hProcess, pe, ModName, TRUE);
MemFree(ModName);
if (mi != NULL) {
psym = FindSymbolByName( pe, mi, p+1 );
if (psym) {
*SymRet = *psym;
return TRUE;
}
}
SetLastError( ERROR_MOD_NOT_FOUND );
return FALSE;
}
// now check, using context information
psym = FindSymbolByName( pe, NULL, Name );
if (psym) {
*SymRet = *psym;
return TRUE;
}
// now just look in every module
for (pass = 0; pass < 2; pass++) {
Next = pe->ModuleList.Flink;
while (Next != &pe->ModuleList) {
mi = CONTAINING_RECORD( Next, MODULE_ENTRY, ListEntry );
Next = mi->ListEntry.Flink;
if (pass && DoSymbolCallback(pe,
CBA_DEFERRED_SYMBOL_LOAD_CANCEL,
mi,
&idsl64,
NULL))
{
break;
}
if (!LoadSymbols(hProcess, mi, flags[pass]))
continue;
psym = FindSymbolByName( pe, mi, Name );
if (psym) {
*SymRet = *psym;
return TRUE;
}
}
}
SetLastError( ERROR_MOD_NOT_FOUND );
return FALSE;
} __except (EXCEPTION_EXECUTE_HANDLER) {
ImagepSetLastErrorFromStatus( GetExceptionCode() );
return FALSE;
}
SetLastError( ERROR_INVALID_FUNCTION );
return FALSE;
}
BOOL
IMAGEAPI
SymGetSymFromName64(
IN HANDLE hProcess,
IN LPSTR Name,
OUT PIMAGEHLP_SYMBOL64 Symbol
)
/*++
Routine Description:
This function finds an entry in the symbol table based on a name.
Arguments:
hProcess - Process handle, must have been previously registered
with SymInitialize.
SymName - A string containing the symbol name.
Symbol - Returns found symbol
Return Value:
TRUE - The symbol was located.
FALSE - The symbol was not found. Call GetLastError to
discover the cause of the failure.
--*/
{
SYMBOL_ENTRY sym;
if (SympGetSymFromName(hProcess, Name, &sym)) {
symcpy64(Symbol, &sym);
return TRUE;
} else {
return FALSE;
}
}
BOOL
IMAGEAPI
SymGetSymFromName(
IN HANDLE hProcess,
IN LPSTR Name,
OUT PIMAGEHLP_SYMBOL Symbol
)
/*++
Routine Description:
This function finds an entry in the symbol table based on a name.
Arguments:
hProcess - Process handle, must have been previously registered
with SymInitialize.
SymName - A string containing the symbol name.
Symbol - Returns found symbol
Return Value:
TRUE - The symbol was located.
FALSE - The symbol was not found. Call GetLastError to
discover the cause of the failure.
--*/
{
SYMBOL_ENTRY sym;
if (SympGetSymFromName(hProcess, Name, &sym)) {
symcpy32(Symbol, &sym);
return TRUE;
} else {
return FALSE;
}
}
BOOL
IMAGEAPI
SymGetSymNext(
IN HANDLE hProcess,
IN OUT PIMAGEHLP_SYMBOL Symbol32
)
/*++
Routine Description:
This function finds the next symbol in the symbol table that falls
sequentially after the symbol passed in.
Arguments:
hProcess - Process handle, must have been previously registered
with SymInitialize.
Symbol - Starting symbol.
Return Value:
Non NULL pointer - The symbol was located.
NULL pointer - The symbol was not found. Call GetLastError to
discover the cause of the failure.
--*/
{
PIMAGEHLP_SYMBOL64 Symbol64;
BOOL r = FALSE;
Symbol64 = (PIMAGEHLP_SYMBOL64)MemAlloc(sizeof(IMAGEHLP_SYMBOL64) + Symbol32->MaxNameLength);
if (Symbol64) {
SympConvertSymbol32To64(Symbol32, Symbol64);
if (SympGetSymNextPrev(hProcess, Symbol64, 1)) {
SympConvertSymbol64To32(Symbol64, Symbol32);
r = TRUE;
}
MemFree(Symbol64);
}
return r;
}
BOOL
IMAGEAPI
SymGetSymNext64(
IN HANDLE hProcess,
IN OUT PIMAGEHLP_SYMBOL64 Symbol
)
/*++
Routine Description:
This function finds the next symbol in the symbol table that falls
sequentially after the symbol passed in.
Arguments:
hProcess - Process handle, must have been previously registered
with SymInitialize.
Symbol - Starting symbol.
Return Value:
Non NULL pointer - The symbol was located.
NULL pointer - The symbol was not found. Call GetLastError to
discover the cause of the failure.
--*/
{
return SympGetSymNextPrev(hProcess, Symbol, 1);
}
BOOL
IMAGEAPI
SymGetSymPrev(
IN HANDLE hProcess,
IN OUT PIMAGEHLP_SYMBOL Symbol32
)
/*++
Routine Description:
This function finds the next symbol in the symbol table that falls
sequentially after the symbol passed in.
Arguments:
hProcess - Process handle, must have been previously registered
with SymInitialize.
Symbol - Starting symbol.
Return Value:
Non NULL pointer - The symbol was located.
NULL pointer - The symbol was not found. Call GetLastError to
discover the cause of the failure.
--*/
{
PIMAGEHLP_SYMBOL64 Symbol64;
BOOL r = FALSE;
Symbol64 = (PIMAGEHLP_SYMBOL64)MemAlloc(sizeof(IMAGEHLP_SYMBOL64) + Symbol32->MaxNameLength);
if (Symbol64) {
SympConvertSymbol32To64(Symbol32, Symbol64);
if (SympGetSymNextPrev(hProcess, Symbol64, -1)) {
SympConvertSymbol64To32(Symbol64, Symbol32);
r = TRUE;
}
MemFree(Symbol64);
}
return r;
}
BOOL
IMAGEAPI
SymGetSymPrev64(
IN HANDLE hProcess,
IN OUT PIMAGEHLP_SYMBOL64 Symbol
)
/*++
Routine Description:
This function finds the next symbol in the symbol table that falls
sequentially after the symbol passed in.
Arguments:
hProcess - Process handle, must have been previously registered
with SymInitialize.
Symbol - Starting symbol.
Return Value:
Non NULL pointer - The symbol was located.
NULL pointer - The symbol was not found. Call GetLastError to
discover the cause of the failure.
--*/
{
return SympGetSymNextPrev(hProcess, Symbol, -1);
}
BOOL
SympGetSymNextPrev(
IN HANDLE hProcess,
IN OUT PIMAGEHLP_SYMBOL64 Symbol,
IN int Direction
)
/*++
Routine Description:
Common code for SymGetSymNext and SymGetSymPrev.
Arguments:
hProcess - Process handle, must have been previously registered
with SymInitialize.
Symbol - Starting symbol.
Dir - Supplies direction to search
Return Value:
Non NULL pointer - The symbol was located.
NULL pointer - The symbol was not found. Call GetLastError to
discover the cause of the failure.
--*/
{
PPROCESS_ENTRY pe;
PMODULE_ENTRY mi;
ULONG64 Displacement;
PSYMBOL_ENTRY sym;
SYMBOL_ENTRY SymEntry = {0};
__try {
pe = FindProcessEntry( hProcess );
if (!pe) {
SetLastError( ERROR_INVALID_HANDLE );
return FALSE;
}
mi = GetModuleForPC( pe, Symbol->Address, FALSE );
if (mi == NULL) {
SetLastError( ERROR_MOD_NOT_FOUND );
return FALSE;
}
if (!LoadSymbols(hProcess, mi, 0)) {
SetLastError( ERROR_MOD_NOT_FOUND );
return FALSE;
}
if (mi->dia) {
sym = diaGetSymNextPrev(mi, Symbol->Address, Direction);
if (!sym) {
SetLastError( ERROR_INVALID_ADDRESS );
return FALSE;
}
symcpy64(Symbol, sym);
} else {
sym = GetSymFromAddr( Symbol->Address, &Displacement, mi );
if (!sym) {
SetLastError( ERROR_INVALID_ADDRESS );
return FALSE;
}
if (Direction > 0 && sym+1 >= mi->symbolTable+mi->numsyms) {
SetLastError( ERROR_INVALID_ADDRESS );
return FALSE;
} else if (Direction < 0 && sym-1 < mi->symbolTable) {
SetLastError( ERROR_INVALID_ADDRESS );
return FALSE;
}
symcpy64( Symbol, sym + Direction);
}
return TRUE;
} __except (EXCEPTION_EXECUTE_HANDLER) {
ImagepSetLastErrorFromStatus( GetExceptionCode() );
return FALSE;
}
return FALSE;
}
BOOL
IMAGEAPI
SymGetLineFromAddr64(
IN HANDLE hProcess,
IN DWORD64 dwAddr,
OUT PDWORD pdwDisplacement,
OUT PIMAGEHLP_LINE64 Line
)
/*++
Routine Description:
This function finds a source file and line number entry for the
line closest to the given address.
Arguments:
hProcess - Process handle, must have been previously registered
with SymInitialize.
dwAddr - Supplies an address for which a line is to be
located.
pdwDisplacement - Returns the offset between the given address
and the first instruction of the line.
Line - Returns the line and file information.
Return Value:
TRUE - A line was located.
FALSE - The line was not found. Call GetLastError to
discover the cause of the failure.
--*/
{
PPROCESS_ENTRY pe;
PMODULE_ENTRY mi;
__try {
if (Line->SizeOfStruct != sizeof(IMAGEHLP_LINE64)) {
SetLastError(ERROR_INVALID_PARAMETER);
return FALSE;
}
pe = FindProcessEntry( hProcess );
if (!pe) {
SetLastError( ERROR_INVALID_HANDLE );
return FALSE;
}
mi = GetModuleForPC( pe, dwAddr, FALSE );
if (mi == NULL) {
SetLastError( ERROR_MOD_NOT_FOUND );
return FALSE;
}
if (!LoadSymbols(hProcess, mi, 0)) {
SetLastError( ERROR_MOD_NOT_FOUND );
return FALSE;
}
if (!GetLineFromAddr(mi, dwAddr, pdwDisplacement, Line)) {
SetLastError( ERROR_INVALID_ADDRESS );
return FALSE;
}
} __except (EXCEPTION_EXECUTE_HANDLER) {
ImagepSetLastErrorFromStatus( GetExceptionCode() );
return FALSE;
}
return TRUE;
}
BOOL
IMAGEAPI
SymGetLineFromAddr(
IN HANDLE hProcess,
IN DWORD dwAddr,
OUT PDWORD pdwDisplacement,
OUT PIMAGEHLP_LINE Line32
)
{
IMAGEHLP_LINE64 Line64;
Line64.SizeOfStruct = sizeof(Line64);
if (SymGetLineFromAddr64(hProcess, dwAddr, pdwDisplacement, &Line64)) {
SympConvertLine64To32(&Line64, Line32);
return TRUE;
} else {
return FALSE;
}
}
BOOL
IMAGEAPI
SymGetLineFromName64(
IN HANDLE hProcess,
IN LPSTR ModuleName,
IN LPSTR FileName,
IN DWORD dwLineNumber,
OUT PLONG plDisplacement,
IN OUT PIMAGEHLP_LINE64 Line
)
/*++
Routine Description:
This function finds an entry in the source file and line-number
information based on a particular filename and line number.
A module name can be given if the search is to be restricted to
a specific module.
The filename can be omitted if a pure line number search is desired,
in which case Line must be a previously filled out line number
struct. The module and file that Line->Address lies in is used
to look up the new line number. This cannot be used when a module
name is given.
Arguments:
hProcess - Process handle, must have been previously registered
with SymInitialize.
ModuleName - Module name or NULL.
FileName - File name or NULL.
dwLineNumber - Line number of interest.
plDisplacement - Difference between requested line number and
returned line number.
Line - Line information input and return.
Return Value:
TRUE - A line was located.
FALSE - A line was not found. Call GetLastError to
discover the cause of the failure.
--*/
{
PPROCESS_ENTRY pe;
PMODULE_ENTRY mi = NULL;
PLIST_ENTRY Next;
IMAGEHLP_DEFERRED_SYMBOL_LOAD64 idsl64;
int pass;
static DWORD flags[2] = {LS_JUST_TEST, LS_QUALIFIED | LS_LOAD_LINES};
__try {
if (Line->SizeOfStruct != sizeof(IMAGEHLP_LINE64)) {
SetLastError(ERROR_INVALID_PARAMETER);
return FALSE;
}
pe = FindProcessEntry( hProcess );
if (!pe) {
SetLastError( ERROR_INVALID_HANDLE );
return FALSE;
}
if (ModuleName != NULL) {
//
// The caller wants to look in a specific module.
// A filename must be given in this case because it doesn't
// make sense to do an address-driven search when a module
// is explicitly specified since the address also specifies
// a module.
//
if (FileName == NULL) {
SetLastError(ERROR_INVALID_PARAMETER);
return FALSE;
}
mi = FindModule(hProcess, pe, ModuleName, TRUE);
if (mi != NULL &&
FindLineByName( mi, FileName, dwLineNumber, plDisplacement, Line )) {
return TRUE;
}
SetLastError( ERROR_MOD_NOT_FOUND );
return FALSE;
}
if (FileName == NULL) {
// Only a line number has been given, implying that
// it's a line in the same file as the given line is currently in.
mi = GetModuleForPC( pe, Line->Address, FALSE );
if (mi == NULL) {
SetLastError( ERROR_MOD_NOT_FOUND );
return FALSE;
}
if (!LoadSymbols(hProcess, mi, LS_LOAD_LINES)) {
SetLastError( ERROR_MOD_NOT_FOUND );
return FALSE;
}
if (FindLineByName( mi, FileName, dwLineNumber,
plDisplacement, Line )) {
return TRUE;
}
SetLastError( ERROR_MOD_NOT_FOUND );
return FALSE;
}
Next = pe->ModuleList.Flink;
if (!Next) {
SetLastError( ERROR_MOD_NOT_FOUND );
return FALSE;
}
for (pass = 0; pass < 2; pass++) {
Next = pe->ModuleList.Flink;
while (Next != &pe->ModuleList) {
mi = CONTAINING_RECORD( Next, MODULE_ENTRY, ListEntry );
Next = mi->ListEntry.Flink;
if (pass && DoSymbolCallback(pe,
CBA_DEFERRED_SYMBOL_LOAD_CANCEL,
mi,
&idsl64,
NULL))
{
break;
}
if (!LoadSymbols(hProcess, mi, flags[pass]))
continue;
if (FindLineByName( mi, FileName, dwLineNumber, plDisplacement, Line ))
return TRUE;
}
}
SetLastError( ERROR_MOD_NOT_FOUND );
return FALSE;
} __except (EXCEPTION_EXECUTE_HANDLER) {
ImagepSetLastErrorFromStatus( GetExceptionCode() );
return FALSE;
}
SetLastError( ERROR_INVALID_FUNCTION );
return FALSE;
}
BOOL
IMAGEAPI
SymGetLineFromName(
IN HANDLE hProcess,
IN LPSTR ModuleName,
IN LPSTR FileName,
IN DWORD dwLineNumber,
OUT PLONG plDisplacement,
IN OUT PIMAGEHLP_LINE Line32
)
{
IMAGEHLP_LINE64 Line64;
Line64.SizeOfStruct = sizeof(Line64);
SympConvertLine32To64(Line32, &Line64);
if (SymGetLineFromName64(hProcess,
ModuleName,
FileName,
dwLineNumber,
plDisplacement,
&Line64)) {
return SympConvertLine64To32(&Line64, Line32);
} else {
return FALSE;
}
}
BOOL
IMAGEAPI
SymGetLineNext64(
IN HANDLE hProcess,
IN OUT PIMAGEHLP_LINE64 Line
)
/*++
Routine Description:
This function returns line address information for the line immediately
following the line given.
Arguments:
hProcess - Process handle, must have been previously registered
with SymInitialize.
Line - Supplies line number information for the line
prior to the one being located.
Return Value:
TRUE - A line was located. The Key, LineNumber and Address
of Line are updated.
FALSE - No such line exists. Call GetLastError to
discover the cause of the failure.
--*/
{
PPROCESS_ENTRY pe;
PMODULE_ENTRY mi;
PSOURCE_LINE SrcLine;
PSOURCE_ENTRY Src;
__try {
if (Line->SizeOfStruct != sizeof(IMAGEHLP_LINE64)) {
SetLastError(ERROR_INVALID_PARAMETER);
return FALSE;
}
pe = FindProcessEntry( hProcess );
if (!pe) {
SetLastError( ERROR_INVALID_HANDLE );
return FALSE;
}
mi = GetModuleForPC( pe, Line->Address, FALSE );
if (mi == NULL) {
SetLastError( ERROR_MOD_NOT_FOUND );
return FALSE;
}
if (!LoadSymbols(hProcess, mi, 0)) {
SetLastError( ERROR_MOD_NOT_FOUND );
return FALSE;
}
if (mi->dia)
return diaGetLineNext(mi, Line);
// Use existing information to look up module and then
// locate the file information. The key could be extended
// to make this unnecessary but it's done as a validation step
// more than as a way to save a DWORD.
SrcLine = (PSOURCE_LINE)Line->Key;
for (Src = mi->SourceFiles; Src != NULL; Src = Src->Next) {
if (SrcLine >= Src->LineInfo &&
SrcLine < Src->LineInfo+Src->Lines) {
break;
}
}
if (Src == NULL) {
SetLastError(ERROR_INVALID_PARAMETER);
return FALSE;
}
if (SrcLine == Src->LineInfo+Src->Lines-1) {
SetLastError(ERROR_NO_MORE_ITEMS);
return FALSE;
}
SrcLine++;
Line->Key = SrcLine;
Line->LineNumber = SrcLine->Line;
Line->Address = SrcLine->Addr;
} __except (EXCEPTION_EXECUTE_HANDLER) {
ImagepSetLastErrorFromStatus( GetExceptionCode() );
return FALSE;
}
return TRUE;
}
BOOL
IMAGEAPI
SymGetLineNext(
IN HANDLE hProcess,
IN OUT PIMAGEHLP_LINE Line32
)
{
IMAGEHLP_LINE64 Line64;
Line64.SizeOfStruct = sizeof(Line64);
SympConvertLine32To64(Line32, &Line64);
if (SymGetLineNext64(hProcess, &Line64)) {
return SympConvertLine64To32(&Line64, Line32);
} else {
return FALSE;
}
}
BOOL
IMAGEAPI
SymGetLinePrev64(
IN HANDLE hProcess,
IN OUT PIMAGEHLP_LINE64 Line
)
/*++
Routine Description:
This function returns line address information for the line immediately
before the line given.
Arguments:
hProcess - Process handle, must have been previously registered
with SymInitialize.
Line - Supplies line number information for the line
after the one being located.
Return Value:
TRUE - A line was located. The Key, LineNumber and Address
of Line are updated.
FALSE - No such line exists. Call GetLastError to
discover the cause of the failure.
--*/
{
PPROCESS_ENTRY pe;
PMODULE_ENTRY mi;
PSOURCE_LINE SrcLine;
PSOURCE_ENTRY Src;
__try {
if (Line->SizeOfStruct != sizeof(IMAGEHLP_LINE64)) {
SetLastError(ERROR_INVALID_PARAMETER);
return FALSE;
}
pe = FindProcessEntry( hProcess );
if (!pe) {
SetLastError( ERROR_INVALID_HANDLE );
return FALSE;
}
mi = GetModuleForPC( pe, Line->Address, FALSE );
if (mi == NULL) {
SetLastError( ERROR_MOD_NOT_FOUND );
return FALSE;
}
if (!LoadSymbols(hProcess, mi, 0)) {
SetLastError( ERROR_MOD_NOT_FOUND );
return FALSE;
}
if (mi->dia)
return diaGetLinePrev(mi, Line);
// Use existing information to look up module and then
// locate the file information. The key could be extended
// to make this unnecessary but it's done as a validation step
// more than as a way to save a DWORD.
SrcLine = (PSOURCE_LINE)Line->Key;
for (Src = mi->SourceFiles; Src != NULL; Src = Src->Next) {
if (SrcLine >= Src->LineInfo &&
SrcLine < Src->LineInfo+Src->Lines) {
break;
}
}
if (Src == NULL) {
SetLastError(ERROR_INVALID_PARAMETER);
return FALSE;
}
if (SrcLine == Src->LineInfo) {
SetLastError(ERROR_NO_MORE_ITEMS);
return FALSE;
}
SrcLine--;
Line->Key = SrcLine;
Line->LineNumber = SrcLine->Line;
Line->Address = SrcLine->Addr;
} __except (EXCEPTION_EXECUTE_HANDLER) {
ImagepSetLastErrorFromStatus( GetExceptionCode() );
return FALSE;
}
return TRUE;
}
BOOL
IMAGEAPI
SymGetLinePrev(
IN HANDLE hProcess,
IN OUT PIMAGEHLP_LINE Line32
)
{
IMAGEHLP_LINE64 Line64;
Line64.SizeOfStruct = sizeof(Line64);
SympConvertLine32To64(Line32, &Line64);
if (SymGetLinePrev64(hProcess, &Line64)) {
return SympConvertLine64To32(&Line64, Line32);
} else {
return FALSE;
}
}
BOOL
IMAGEAPI
SymMatchFileName(
IN LPSTR FileName,
IN LPSTR Match,
OUT LPSTR *FileNameStop,
OUT LPSTR *MatchStop
)
/*++
Routine Description:
This function attempts to match a string against a filename and path.
The match string is allowed to be a suffix of the complete filename,
so this function is useful for matching a plain filename against
a fully qualified filename.
Matching begins from the end of both strings and proceeds backwards.
Matching is case-insensitive and equates \ with /.
Arguments:
FileName - Filename to match against.
Match - String to match against filename.
FileNameStop - Returns pointer into FileName where matching stopped.
May be one before FileName for full matches.
May be NULL.
MatchStop - Returns pointer info Match where matching stopped.
May be one before Match for full matches.
May be NULL.
Return Value:
TRUE - Match is a matching suffix of FileName.
FALSE - Mismatch.
--*/
{
LPSTR pF, pM;
pF = FileName+strlen(FileName)-1;
pM = Match+strlen(Match)-1;
while (pF >= FileName && pM >= Match) {
int chF, chM;
chF = tolower(*pF);
chF = chF == '\\' ? '/' : chF;
chM = tolower(*pM);
chM = chM == '\\' ? '/' : chM;
if (chF != chM) {
break;
}
pF--;
pM--;
}
if (FileNameStop != NULL) {
*FileNameStop = pF;
}
if (MatchStop != NULL) {
*MatchStop = pM;
}
return pM < Match;
}
BOOL
IMAGEAPI
SymRegisterFunctionEntryCallback(
IN HANDLE hProcess,
IN PSYMBOL_FUNCENTRY_CALLBACK CallbackFunction,
IN PVOID UserContext
)
/*++
Routine Description:
Set the address of a callback routine to access extended function
table entries directly. This function is useful when debugging
Alpha processes where RUNTIME_FUNCTION_ENTRYs are available from
sources other than in the image. Two existing examples are:
1) Access to dynamic function tables for run-time code
2) Access to function tables for ROM images
Arguments:
hProcess - Process handle, must have been previously registered
with SymInitialize.
DirectFunctionTableRoutine - Address of direct function table callback routine.
On alpha this routine must return a pointer to the
RUNTIME_FUNCTION_ENTRY containing the specified address.
If no such entry is available, it must return NULL.
Return Value:
TRUE - The callback was successfully registered
FALSE - The initialization failed. Most likely failure is that
the hProcess parameter is invalid. Call GetLastError()
for specific error codes.
--*/
{
PPROCESS_ENTRY pe = NULL;
__try {
if (!CallbackFunction) {
SetLastError(ERROR_INVALID_PARAMETER);
return FALSE;
}
pe = FindProcessEntry( hProcess );
if (!pe) {
SetLastError(ERROR_INVALID_PARAMETER);
return FALSE;
}
pe->pFunctionEntryCallback32 = CallbackFunction;
pe->pFunctionEntryCallback64 = NULL;
pe->FunctionEntryUserContext = (ULONG64)UserContext;
} __except (EXCEPTION_EXECUTE_HANDLER) {
ImagepSetLastErrorFromStatus( GetExceptionCode() );
return FALSE;
}
return TRUE;
}
BOOL
IMAGEAPI
SymRegisterFunctionEntryCallback64(
IN HANDLE hProcess,
IN PSYMBOL_FUNCENTRY_CALLBACK64 CallbackFunction,
IN ULONG64 UserContext
)
/*++
Routine Description:
See SymRegisterFunctionEntryCallback64
--*/
{
PPROCESS_ENTRY pe = NULL;
__try {
if (!CallbackFunction) {
SetLastError(ERROR_INVALID_PARAMETER);
return FALSE;
}
pe = FindProcessEntry( hProcess );
if (!pe) {
SetLastError(ERROR_INVALID_PARAMETER);
return FALSE;
}
pe->pFunctionEntryCallback32 = NULL;
pe->pFunctionEntryCallback64 = CallbackFunction;
pe->FunctionEntryUserContext = (ULONG64)UserContext;
} __except (EXCEPTION_EXECUTE_HANDLER) {
ImagepSetLastErrorFromStatus( GetExceptionCode() );
return FALSE;
}
return TRUE;
}
LPVOID
IMAGEAPI
SymFunctionTableAccess(
HANDLE hProcess,
DWORD AddrBase
)
{
return SymFunctionTableAccess64(hProcess, EXTEND64(AddrBase));
}
LPVOID
IMAGEAPI
SymFunctionTableAccess64(
HANDLE hProcess,
DWORD64 AddrBase
)
/*++
Routine Description:
This function finds a function table entry or FPO record for an address.
Arguments:
hProcess - Process handle, must have been previously registered
with SymInitialize.
AddrBase - Supplies an address for which a function table entry
or FPO entry is to be located.
Return Value:
Non NULL pointer - The symbol was located.
NULL pointer - The symbol was not found. Call GetLastError to
discover the cause of the failure.
--*/
{
PPROCESS_ENTRY pe;
PMODULE_ENTRY mi;
PVOID rtf;
ULONG_PTR rva;
DWORD bias;
DWORD MachineType;
__try {
pe = FindProcessEntry( hProcess );
if (!pe) {
SetLastError( ERROR_INVALID_HANDLE );
return NULL;
}
// Dynamically generated function table entries
// may not be in a module, so failing to
// find a module is not a fatal error.
mi = GetModuleForPC( pe, AddrBase, FALSE );
if (mi != NULL) {
if (!LoadSymbols(hProcess, mi, 0)) {
SetLastError( ERROR_MOD_NOT_FOUND );
return NULL;
}
MachineType = mi->MachineType;
} else {
// We need to guess what kind of machine we
// should be working with. First see if ntdll
// is loaded and if so use its machine type.
mi = FindModule(hProcess, pe, "ntdll", TRUE);
if (mi != NULL) {
MachineType = mi->MachineType;
} else if (pe->ModuleList.Flink != NULL) {
// Try the first module's type.
mi = CONTAINING_RECORD( pe->ModuleList.Flink,
MODULE_ENTRY, ListEntry );
} else {
// Use the complation machine.
#if defined(_M_IX86)
MachineType = IMAGE_FILE_MACHINE_I386;
#elif defined(_M_IA64)
MachineType = IMAGE_FILE_MACHINE_IA64;
#elif defined(_M_AXP64)
MachineType = IMAGE_FILE_MACHINE_AXP64;
#elif defined(_M_ALPHA)
MachineType = IMAGE_FILE_MACHINE_ALPHA;
#elif defined(_M_AMD64)
MachineType = IMAGE_FILE_MACHINE_AMD64;
#else
#error( "unknown target machine" );
#endif
}
}
switch (MachineType) {
default:
rtf = NULL;
break;
case IMAGE_FILE_MACHINE_I386:
rtf = NULL;
if (mi == NULL) {
SetLastError( ERROR_MOD_NOT_FOUND );
break;
}
DWORD64 caddr;
if (!mi->pFpoData)
break;
caddr = ConvertOmapToSrc( mi, AddrBase, &bias, TRUE );
if (caddr)
AddrBase = caddr + bias;
rtf = SwSearchFpoData( (ULONG)(AddrBase - mi->BaseOfDll), mi->pFpoData, mi->dwEntries );
if (rtf && mi->cOmapFrom && mi->pFpoDataOmap) {
rva = (ULONG_PTR)rtf - (ULONG_PTR)mi->pFpoData;
rtf = (PBYTE)mi->pFpoDataOmap + rva;
}
break;
case IMAGE_FILE_MACHINE_ALPHA:
rtf = LookupFunctionEntryAxp32(hProcess, (DWORD)AddrBase);
break;
case IMAGE_FILE_MACHINE_IA64:
rtf = LookupFunctionEntryIa64(hProcess, AddrBase);
break;
case IMAGE_FILE_MACHINE_AXP64:
rtf = LookupFunctionEntryAxp64(hProcess, AddrBase);
break;
case IMAGE_FILE_MACHINE_AMD64:
rtf = LookupFunctionEntryAmd64(hProcess, AddrBase);
break;
}
if (!rtf) {
SetLastError( ERROR_INVALID_ADDRESS );
return NULL;
}
} __except (EXCEPTION_EXECUTE_HANDLER) {
ImagepSetLastErrorFromStatus( GetExceptionCode() );
return NULL;
}
return rtf;
}
BOOL
IMAGEAPI
SymGetModuleInfo64(
IN HANDLE hProcess,
IN DWORD64 dwAddr,
OUT PIMAGEHLP_MODULE64 ModuleInfo
)
{
PPROCESS_ENTRY pe;
PMODULE_ENTRY mi;
DWORD SizeOfStruct;
__try {
pe = FindProcessEntry( hProcess );
if (!pe) {
SetLastError( ERROR_INVALID_HANDLE );
return FALSE;
}
mi = GetModuleForPC( pe, dwAddr, FALSE );
if (mi == NULL) {
SetLastError( ERROR_MOD_NOT_FOUND );
return FALSE;
}
SizeOfStruct = ModuleInfo->SizeOfStruct;
if (SizeOfStruct > sizeof(IMAGEHLP_MODULE64)) {
SetLastError( ERROR_INVALID_PARAMETER );
return FALSE;
}
ZeroMemory( ModuleInfo, SizeOfStruct);
ModuleInfo->SizeOfStruct = SizeOfStruct;
ModuleInfo->BaseOfImage = mi->BaseOfDll;
ModuleInfo->ImageSize = mi->DllSize;
ModuleInfo->NumSyms = mi->numsyms;
ModuleInfo->CheckSum = mi->CheckSum;
ModuleInfo->TimeDateStamp = mi->TimeDateStamp;
ModuleInfo->SymType = mi->SymType;
ModuleInfo->ModuleName[0] = 0;
strncat( ModuleInfo->ModuleName, mi->ModuleName,
sizeof(ModuleInfo->ModuleName) - 1 );
if (mi->ImageName) {
strcpy( ModuleInfo->ImageName, mi->ImageName );
}
if (mi->LoadedImageName) {
strcpy( ModuleInfo->LoadedImageName, mi->LoadedImageName );
}
} __except (EXCEPTION_EXECUTE_HANDLER) {
ImagepSetLastErrorFromStatus( GetExceptionCode() );
return FALSE;
}
return TRUE;
}
BOOL
IMAGEAPI
SymGetModuleInfoW(
IN HANDLE hProcess,
IN DWORD dwAddr,
OUT PIMAGEHLP_MODULEW wModInfo
)
{
IMAGEHLP_MODULE aModInfo;
if (wModInfo->SizeOfStruct != sizeof(IMAGEHLP_MODULEW)) {
SetLastError(ERROR_INVALID_PARAMETER);
return FALSE;
}
ZeroMemory(wModInfo, sizeof(IMAGEHLP_MODULEW));
wModInfo->SizeOfStruct = sizeof(IMAGEHLP_MODULEW);
if (!SympConvertUnicodeModule32ToAnsiModule32(
wModInfo, &aModInfo))
{
SetLastError(ERROR_INVALID_PARAMETER);
return FALSE;
}
if (!SymGetModuleInfo(hProcess, dwAddr, &aModInfo)) {
return FALSE;
}
if (!SympConvertAnsiModule32ToUnicodeModule32(
&aModInfo, wModInfo)) {
return FALSE;
}
return TRUE;
}
BOOL
IMAGEAPI
SymGetModuleInfoW64(
IN HANDLE hProcess,
IN DWORD64 dwAddr,
OUT PIMAGEHLP_MODULEW64 wModInfo
)
{
IMAGEHLP_MODULE64 aModInfo;
if (!SympConvertUnicodeModule64ToAnsiModule64(
wModInfo, &aModInfo)) {
return FALSE;
}
if (!SymGetModuleInfo64(hProcess, dwAddr, &aModInfo)) {
return FALSE;
}
if (!SympConvertAnsiModule64ToUnicodeModule64(
&aModInfo, wModInfo)) {
return FALSE;
}
return TRUE;
}
BOOL
IMAGEAPI
SymGetModuleInfo(
IN HANDLE hProcess,
IN DWORD dwAddr,
OUT PIMAGEHLP_MODULE ModuleInfo
)
{
PPROCESS_ENTRY pe;
PMODULE_ENTRY mi;
DWORD SizeOfStruct;
__try {
pe = FindProcessEntry( hProcess );
if (!pe) {
SetLastError( ERROR_INVALID_HANDLE );
return FALSE;
}
mi = GetModuleForPC( pe,
dwAddr == (DWORD)-1 ? (DWORD64)-1 : dwAddr, FALSE );
if (mi == NULL) {
SetLastError( ERROR_MOD_NOT_FOUND );
return FALSE;
}
SizeOfStruct = ModuleInfo->SizeOfStruct;
if (SizeOfStruct > sizeof(IMAGEHLP_MODULE)) {
SetLastError( ERROR_INVALID_PARAMETER );
return FALSE;
}
ZeroMemory( ModuleInfo, SizeOfStruct);
ModuleInfo->SizeOfStruct = SizeOfStruct;
ModuleInfo->BaseOfImage = (DWORD)mi->BaseOfDll;
ModuleInfo->ImageSize = mi->DllSize;
ModuleInfo->NumSyms = mi->numsyms;
ModuleInfo->CheckSum = mi->CheckSum;
ModuleInfo->TimeDateStamp = mi->TimeDateStamp;
ModuleInfo->SymType = mi->SymType;
ModuleInfo->ModuleName[0] = 0;
strncat( ModuleInfo->ModuleName, mi->ModuleName,
sizeof(ModuleInfo->ModuleName) - 1 );
if (mi->ImageName) {
strcpy( ModuleInfo->ImageName, mi->ImageName );
}
if (mi->LoadedImageName) {
strcpy( ModuleInfo->LoadedImageName, mi->LoadedImageName );
}
} __except (EXCEPTION_EXECUTE_HANDLER) {
ImagepSetLastErrorFromStatus( GetExceptionCode() );
return FALSE;
}
return TRUE;
}
DWORD64
IMAGEAPI
SymGetModuleBase64(
IN HANDLE hProcess,
IN DWORD64 dwAddr
)
{
PPROCESS_ENTRY pe;
PMODULE_ENTRY mi;
__try {
pe = FindProcessEntry( hProcess );
if (!pe) {
return 0;
}
mi = GetModuleForPC( pe, dwAddr, FALSE );
if (mi == NULL) {
return 0;
}
} __except (EXCEPTION_EXECUTE_HANDLER) {
ImagepSetLastErrorFromStatus( GetExceptionCode() );
return FALSE;
}
return mi->BaseOfDll;
}
DWORD
IMAGEAPI
SymGetModuleBase(
IN HANDLE hProcess,
IN DWORD dwAddr
)
{
return (ULONG)SymGetModuleBase64(hProcess, dwAddr);
}
BOOL
IMAGEAPI
SymUnloadModule64(
IN HANDLE hProcess,
IN DWORD64 BaseOfDll
)
/*++
Routine Description:
Remove the symbols for an image from a process' symbol table.
Arguments:
hProcess - Supplies the token which refers to the process
BaseOfDll - Supplies the offset to the image as supplies by the
LOAD_DLL_DEBUG_EVENT and UNLOAD_DLL_DEBUG_EVENT.
Return Value:
Returns TRUE if the module's symbols were successfully unloaded.
Returns FALSE if the symbol handler does not recognize hProcess or
no image was loaded at the given offset.
--*/
{
PPROCESS_ENTRY pe;
PLIST_ENTRY next;
PMODULE_ENTRY mi;
__try {
pe = FindProcessEntry(hProcess);
if (!pe) {
return FALSE;
}
next = pe->ModuleList.Flink;
if (next) {
while (next != &pe->ModuleList) {
mi = CONTAINING_RECORD(next, MODULE_ENTRY, ListEntry);
if (mi->BaseOfDll == BaseOfDll) {
RemoveEntryList(next);
FreeModuleEntry(pe, mi);
ZeroMemory(pe->DiaCache, sizeof(pe->DiaCache));
ZeroMemory(pe->DiaLargeData, sizeof(pe->DiaLargeData));
return TRUE;
}
next = mi->ListEntry.Flink;
}
}
} __except (EXCEPTION_EXECUTE_HANDLER) {
ImagepSetLastErrorFromStatus(GetExceptionCode());
return FALSE;
}
return FALSE;
}
BOOL
IMAGEAPI
SymUnloadModule(
IN HANDLE hProcess,
IN DWORD BaseOfDll
)
{
return SymUnloadModule64(hProcess, BaseOfDll);
}
DWORD64
IMAGEAPI
SymLoadModuleEx(
IN HANDLE hProcess,
IN HANDLE hFile,
IN PSTR ImageName,
IN PSTR ModuleName,
IN DWORD64 BaseOfDll,
IN DWORD DllSize,
IN PMODLOAD_DATA Data,
IN DWORD Flags
)
/*++
Routine Description:
Loads the symbols for an image for use by the other Sym functions.
Arguments:
hProcess - Supplies unique process identifier.
hFile -
ImageName - Supplies the name of the image file.
ModuleName - ???? Supplies the module name that will be returned by
enumeration functions ????
BaseOfDll - Supplies loaded base address of image.
DllSize
Return Value:
--*/
{
__try {
return InternalLoadModule( hProcess, ImageName, ModuleName, BaseOfDll, DllSize, hFile, Data, Flags );
} __except (EXCEPTION_EXECUTE_HANDLER) {
ImagepSetLastErrorFromStatus( GetExceptionCode() );
return 0;
}
}
DWORD64
IMAGEAPI
SymLoadModule64(
IN HANDLE hProcess,
IN HANDLE hFile,
IN PSTR ImageName,
IN PSTR ModuleName,
IN DWORD64 BaseOfDll,
IN DWORD DllSize
)
{
return SymLoadModuleEx(hProcess, hFile, ImageName, ModuleName, BaseOfDll, DllSize, NULL, 0);
}
DWORD
IMAGEAPI
SymLoadModule(
IN HANDLE hProcess,
IN HANDLE hFile,
IN PSTR ImageName,
IN PSTR ModuleName,
IN DWORD BaseOfDll,
IN DWORD DllSize
)
{
return (DWORD)SymLoadModule64( hProcess, hFile, ImageName, ModuleName, BaseOfDll, DllSize );
}
BOOL
IMAGEAPI
SymUnDName(
IN PIMAGEHLP_SYMBOL sym,
OUT LPSTR UnDecName,
OUT DWORD UnDecNameLength
)
{
__try {
if (SymUnDNameInternal( UnDecName,
UnDecNameLength-1,
sym->Name,
strlen(sym->Name),
IMAGE_FILE_MACHINE_UNKNOWN,
TRUE )) {
return TRUE;
} else {
return FALSE;
}
} __except (EXCEPTION_EXECUTE_HANDLER) {
ImagepSetLastErrorFromStatus( GetExceptionCode() );
return FALSE;
}
}
BOOL
IMAGEAPI
SymUnDName64(
IN PIMAGEHLP_SYMBOL64 sym,
OUT LPSTR UnDecName,
OUT DWORD UnDecNameLength
)
{
__try {
if (SymUnDNameInternal( UnDecName,
UnDecNameLength-1,
sym->Name,
strlen(sym->Name),
IMAGE_FILE_MACHINE_UNKNOWN,
TRUE )) {
return TRUE;
} else {
return FALSE;
}
} __except (EXCEPTION_EXECUTE_HANDLER) {
ImagepSetLastErrorFromStatus( GetExceptionCode() );
return FALSE;
}
}
BOOL
IMAGEAPI
SymGetSearchPath(
IN HANDLE hProcess,
OUT LPSTR SearchPath,
IN DWORD SearchPathLength
)
/*++
Routine Description:
This function looks up the symbol search path associated with a process.
Arguments:
hProcess - Supplies the token associated with a process.
Return Value:
A pointer to the search path. Returns NULL if the process is not
know to the symbol handler.
--*/
{
PPROCESS_ENTRY pe;
__try {
pe = FindProcessEntry( hProcess );
if (!pe) {
return FALSE;
}
SearchPath[0] = 0;
strncat( SearchPath, pe->SymbolSearchPath, SearchPathLength );
} __except (EXCEPTION_EXECUTE_HANDLER) {
ImagepSetLastErrorFromStatus( GetExceptionCode() );
return FALSE;
}
return TRUE;
}
BOOL
IMAGEAPI
SymSetSearchPath(
HANDLE hProcess,
LPSTR UserSearchPath
)
/*++
Routine Description:
This functions sets the searh path to be used by the symbol loader
for the given process. If UserSearchPath is not supplied, a default
path will be used.
Arguments:
hProcess - Supplies the process token associated with a symbol table.
UserSearchPath - Supplies the new search path to associate with the
process. If this argument is NULL, the following path is generated:
.;%_NT_SYMBOL_PATH%;%_NT_ALTERNATE_SYMBOL_PATH%
It is ok if any or all of the environment variables is missing.
Return Value:
A pointer to the new search path. The user should not modify this string.
Returns NULL if the process is not known to the symbol handler.
--*/
{
PPROCESS_ENTRY pe;
LPSTR p;
DWORD cbSymPath;
DWORD cb;
char ExpandedSearchPath[MAX_PATH];
__try {
pe = FindProcessEntry( hProcess );
if (!pe) {
return FALSE;
}
if (pe->SymbolSearchPath) {
MemFree(pe->SymbolSearchPath);
}
if (UserSearchPath) {
cbSymPath = ExpandEnvironmentStrings(UserSearchPath,
ExpandedSearchPath,
sizeof(ExpandedSearchPath) / sizeof(ExpandedSearchPath[0]));
if (cbSymPath < sizeof(ExpandedSearchPath)/sizeof(ExpandedSearchPath[0])) {
pe->SymbolSearchPath = StringDup(ExpandedSearchPath);
} else {
pe->SymbolSearchPath = (LPSTR)MemAlloc( cbSymPath );
ExpandEnvironmentStrings(UserSearchPath,
pe->SymbolSearchPath,
cbSymPath );
}
} else {
//
// ".;%_NT_SYMBOL_PATH%;%_NT_ALTERNATE_SYMBOL_PATH%
//
cbSymPath = 3; // ".;" and ";" between env vars.
//
// GetEnvironmentVariable returns the size of the string
// INCLUDING the '\0' in this case.
//
cbSymPath += GetEnvironmentVariable( SYMBOL_PATH, NULL, 0 );
cbSymPath += GetEnvironmentVariable( ALTERNATE_SYMBOL_PATH, NULL, 0 );
p = pe->SymbolSearchPath = (LPSTR) MemAlloc( cbSymPath );
if (!p) {
return FALSE;
}
*p++ = '.';
--cbSymPath;
cb = GetEnvironmentVariable(SYMBOL_PATH, p+1, cbSymPath-1);
if (cb) {
*p = ';';
p += cb+1;
cbSymPath -= cb+1;
}
cb = GetEnvironmentVariable(ALTERNATE_SYMBOL_PATH,
p+1, cbSymPath-1);
if (cb) {
*p = ';';
p += cb+1;
}
*p = 0;
}
} __except (EXCEPTION_EXECUTE_HANDLER) {
ImagepSetLastErrorFromStatus( GetExceptionCode() );
return FALSE;
}
CloseSymbolServer();
return TRUE;
}
BOOL
IMAGEAPI
EnumerateLoadedModules(
IN HANDLE hProcess,
IN PENUMLOADED_MODULES_CALLBACK EnumLoadedModulesCallback,
IN PVOID UserContext
)
{
LOADED_MODULE lm;
DWORD status = NO_ERROR;
__try {
lm.EnumLoadedModulesCallback32 = EnumLoadedModulesCallback;
lm.EnumLoadedModulesCallback64 = NULL;
lm.Context = UserContext;
status = GetProcessModules( hProcess, (PINTERNAL_GET_MODULE)LoadedModuleEnumerator, (PVOID)&lm );
} __except (EXCEPTION_EXECUTE_HANDLER) {
ImagepSetLastErrorFromStatus( GetExceptionCode() );
return FALSE;
}
return (status == NO_ERROR);
}
BOOL
IMAGEAPI
EnumerateLoadedModules64(
IN HANDLE hProcess,
IN PENUMLOADED_MODULES_CALLBACK64 EnumLoadedModulesCallback,
IN PVOID UserContext
)
{
LOADED_MODULE lm;
DWORD status = NO_ERROR;
__try {
lm.EnumLoadedModulesCallback64 = EnumLoadedModulesCallback;
lm.EnumLoadedModulesCallback32 = NULL;
lm.Context = UserContext;
status = GetProcessModules(hProcess,
(PINTERNAL_GET_MODULE)LoadedModuleEnumerator,
(PVOID)&lm );
} __except (EXCEPTION_EXECUTE_HANDLER) {
ImagepSetLastErrorFromStatus( GetExceptionCode() );
return FALSE;
}
return (status == NO_ERROR);
}
BOOL
IMAGEAPI
SymRegisterCallback(
IN HANDLE hProcess,
IN PSYMBOL_REGISTERED_CALLBACK CallbackFunction,
IN PVOID UserContext
)
{
PPROCESS_ENTRY pe = NULL;
__try {
if (!CallbackFunction) {
SetLastError(ERROR_INVALID_PARAMETER);
return FALSE;
}
pe = FindProcessEntry( hProcess );
if (!pe) {
SetLastError(ERROR_INVALID_PARAMETER);
return FALSE;
}
pe->pCallbackFunction32 = CallbackFunction;
pe->pCallbackFunction64 = NULL;
pe->CallbackUserContext = (ULONG64)UserContext;
} __except (EXCEPTION_EXECUTE_HANDLER) {
ImagepSetLastErrorFromStatus( GetExceptionCode() );
return FALSE;
}
return TRUE;
}
BOOL
IMAGEAPI
SymRegisterCallback64(
IN HANDLE hProcess,
IN PSYMBOL_REGISTERED_CALLBACK64 CallbackFunction,
IN ULONG64 UserContext
)
{
PPROCESS_ENTRY pe = NULL;
__try {
if (!CallbackFunction) {
SetLastError(ERROR_INVALID_PARAMETER);
return FALSE;
}
pe = FindProcessEntry( hProcess );
if (!pe) {
SetLastError(ERROR_INVALID_PARAMETER);
return FALSE;
}
pe->pCallbackFunction32 = NULL;
pe->pCallbackFunction64 = CallbackFunction;
pe->CallbackUserContext = UserContext;
} __except (EXCEPTION_EXECUTE_HANDLER) {
ImagepSetLastErrorFromStatus( GetExceptionCode() );
return FALSE;
}
return TRUE;
}
void
InitModuleEntry(
PMODULE_ENTRY mi
)
{
ZeroMemory(mi, sizeof(MODULE_ENTRY));
mi->si.MaxNameLen = 2048;
}
BOOL
SympConvertAnsiModule32ToUnicodeModule32(
PIMAGEHLP_MODULE aMod32,
PIMAGEHLP_MODULEW wMod32
)
{
ZeroMemory(wMod32, sizeof(*wMod32));
wMod32->SizeOfStruct = sizeof(*wMod32);
wMod32->BaseOfImage = aMod32->BaseOfImage;
wMod32->ImageSize = aMod32->ImageSize;
wMod32->TimeDateStamp = aMod32->TimeDateStamp;
wMod32->CheckSum = aMod32->CheckSum;
wMod32->NumSyms = aMod32->NumSyms;
wMod32->SymType = aMod32->SymType;
if (!ansi2wcs(aMod32->ModuleName, wMod32->ModuleName, 256))
return FALSE;
if (!ansi2wcs(aMod32->ImageName, wMod32->ImageName, 256))
return FALSE;
if (!ansi2wcs(aMod32->LoadedImageName, wMod32->LoadedImageName, 256))
return FALSE;
return TRUE;
}
BOOL
SympConvertUnicodeModule32ToAnsiModule32(
PIMAGEHLP_MODULEW wMod32,
PIMAGEHLP_MODULE aMod32
)
{
ZeroMemory(aMod32, sizeof(*aMod32));
aMod32->SizeOfStruct = sizeof(*aMod32);
aMod32->BaseOfImage = wMod32->BaseOfImage;
aMod32->ImageSize = wMod32->ImageSize;
aMod32->TimeDateStamp = wMod32->TimeDateStamp;
aMod32->CheckSum = wMod32->CheckSum;
aMod32->NumSyms = wMod32->NumSyms;
aMod32->SymType = wMod32->SymType;
if (!wcs2ansi(wMod32->ModuleName, aMod32->ModuleName, lengthof(wMod32->ModuleName)))
return FALSE;
if (!wcs2ansi(wMod32->ImageName, aMod32->ImageName, lengthof(wMod32->ImageName)))
return FALSE;
if (!wcs2ansi(wMod32->LoadedImageName, aMod32->LoadedImageName, lengthof(wMod32->LoadedImageName)))
return FALSE;
return TRUE;
}
BOOL
SympConvertAnsiModule64ToUnicodeModule64(
PIMAGEHLP_MODULE64 aMod64,
PIMAGEHLP_MODULEW64 wMod64
)
{
ZeroMemory(wMod64, sizeof(*wMod64));
wMod64->SizeOfStruct = sizeof(*wMod64);
wMod64->BaseOfImage = aMod64->BaseOfImage;
wMod64->ImageSize = aMod64->ImageSize;
wMod64->TimeDateStamp = aMod64->TimeDateStamp;
wMod64->CheckSum = aMod64->CheckSum;
wMod64->NumSyms = aMod64->NumSyms;
wMod64->SymType = aMod64->SymType;
if (!ansi2wcs(aMod64->ModuleName, wMod64->ModuleName, 256))
return FALSE;
if (!ansi2wcs(aMod64->ImageName, wMod64->ImageName, 256))
return FALSE;
if (!ansi2wcs(aMod64->LoadedImageName, wMod64->LoadedImageName, 256))
return FALSE;
return TRUE;
}
BOOL
SympConvertUnicodeModule64ToAnsiModule64(
PIMAGEHLP_MODULEW64 wMod64,
PIMAGEHLP_MODULE64 aMod64
)
{
ZeroMemory(aMod64, sizeof(*aMod64));
aMod64->SizeOfStruct = sizeof(*aMod64);
aMod64->BaseOfImage = wMod64->BaseOfImage;
aMod64->ImageSize = wMod64->ImageSize;
aMod64->TimeDateStamp = wMod64->TimeDateStamp;
aMod64->CheckSum = wMod64->CheckSum;
aMod64->NumSyms = wMod64->NumSyms;
aMod64->SymType = wMod64->SymType;
if (!wcs2ansi(wMod64->ModuleName, aMod64->ModuleName, lengthof(wMod64->ModuleName)))
return FALSE;
if (!wcs2ansi(wMod64->ImageName, aMod64->ImageName, lengthof(wMod64->ImageName)))
return FALSE;
if (!wcs2ansi(wMod64->LoadedImageName, aMod64->LoadedImageName, lengthof(wMod64->LoadedImageName)))
return FALSE;
return TRUE;
}
BOOL
CopySymbolEntryFromSymbolInfo(
PSYMBOL_ENTRY se,
PSYMBOL_INFO si
)
{
se->Size = si->SizeOfStruct;
se->Flags = si->Flags;
se->Address = si->Address;
if (si->Name && se->Name)
strcpy(se->Name, si->Name);
se->NameLength = si->NameLen;
// segment is not used
// offset is not used
se->TypeIndex = si->TypeIndex;
se->ModBase = si->ModBase;
se->Register = si->Register;
if (si->Register) {
((LARGE_INTEGER *) &se->Address)->HighPart = si->Register;
}
return TRUE;
}
BOOL
IMAGEAPI
SymFromAddr(
IN HANDLE hProcess,
IN DWORD64 Address,
OUT PDWORD64 Displacement,
IN OUT PSYMBOL_INFO Symbol
)
{
SYMBOL_ENTRY SymEntry={0};
if (SympGetSymFromAddr(hProcess, Address, Displacement, &SymEntry)) {
symcpy2(Symbol, &SymEntry);
return TRUE;
} else {
return FALSE;
}
}
BOOL
IMAGEAPI
SymFromName(
IN HANDLE hProcess,
IN LPSTR Name,
OUT PSYMBOL_INFO Symbol
)
{
SYMBOL_ENTRY sym;
if (SympGetSymFromName(hProcess, Name, &sym)) {
symcpy2(Symbol, &sym);
return TRUE;
} else {
return FALSE;
}
}
BOOL
IMAGEAPI
SymEnumSymbols(
IN HANDLE hProcess,
IN ULONG64 BaseOfDll,
IN PCSTR Mask,
IN PSYM_ENUMERATESYMBOLS_CALLBACK EnumSymbolsCallback,
IN PVOID UserContext
)
{
return SympEnumerateSymbols(hProcess,
BaseOfDll,
(LPSTR)Mask,
(PROC) EnumSymbolsCallback,
UserContext,
FALSE,
FALSE);
}
BOOL
IMAGEAPI
SymEnumSym(
IN HANDLE hProcess,
IN ULONG64 BaseOfDll,
IN PSYM_ENUMERATESYMBOLS_CALLBACK EnumSymbolsCallback,
IN PVOID UserContext
)
{
return SymEnumSymbols(hProcess,
BaseOfDll,
NULL,
EnumSymbolsCallback,
UserContext);
}
BOOL
IMAGEAPI
SymEnumTypes(
IN HANDLE hProcess,
IN ULONG64 BaseOfDll,
IN PSYM_ENUMERATESYMBOLS_CALLBACK EnumSymbolsCallback,
IN PVOID UserContext
)
{
PPROCESS_ENTRY pe;
PLIST_ENTRY Next;
PMODULE_ENTRY mi;
pe = FindProcessEntry( hProcess );
if (!pe) {
SetLastError( ERROR_INVALID_HANDLE );
return FALSE;
}
mi = NULL;
Next = pe->ModuleList.Flink;
if (Next) {
while (Next != &pe->ModuleList) {
mi = CONTAINING_RECORD( Next, MODULE_ENTRY, ListEntry );
if (!mi)
break;
Next = mi->ListEntry.Flink;
if (mi->BaseOfDll == BaseOfDll)
break;
}
}
if (!mi) {
return FALSE;
}
return diaEnumUDT(mi, "", EnumSymbolsCallback, UserContext);
}
BOOL
IMAGEAPI
SymGetTypeFromName(
IN HANDLE hProcess,
IN ULONG64 BaseOfDll,
IN LPSTR Name,
OUT PSYMBOL_INFO Symbol
)
{
PPROCESS_ENTRY pe;
PLIST_ENTRY Next;
PMODULE_ENTRY mi;
pe = FindProcessEntry( hProcess );
if (!pe) {
SetLastError( ERROR_INVALID_HANDLE );
return FALSE;
}
mi = NULL;
Next = pe->ModuleList.Flink;
if (Next) {
while (Next != &pe->ModuleList) {
mi = CONTAINING_RECORD( Next, MODULE_ENTRY, ListEntry );
if (!mi)
break;
Next = mi->ListEntry.Flink;
if (mi->BaseOfDll == BaseOfDll)
break;
}
}
if (!mi || mi->BaseOfDll != BaseOfDll) {
LPSTR p;
// first check for fully qualified symbol name I.E. mod!sym
p = strchr( Name, '!' );
if (p > Name) {
LPSTR ModName = (LPSTR)MemAlloc(p - Name + 1);
if (!ModName) {
SetLastError( ERROR_NOT_ENOUGH_MEMORY );
return FALSE;
}
memcpy(ModName, Name, (int)(p - Name));
ModName[p-Name] = 0;
//
// the caller wants to look in a specific module
//
mi = FindModule(hProcess, pe, ModName, TRUE);
MemFree(ModName);
if (mi == NULL) {
return FALSE;
}
Name = p+1;
}
}
if (diaGetTiForUDT(mi, Name, Symbol)) {
return TRUE;
} else {
return FALSE;
}
return FALSE;
}
BOOL
strcmpre(
LPSTR pStr,
LPSTR pRE,
BOOL fCase
)
{
DWORD rc;
CHAR sz[MAX_SYM_NAME + 2];
PWSTR wStr = NULL;
PWSTR wRE = NULL;
rc = TRUE;
wStr = AnsiToUnicode(pStr);
if (!wStr)
goto exit;;
wRE = AnsiToUnicode(pRE);
if (!wRE)
goto exit;
rc = CompareRE(wStr, wRE, fCase);
if (rc == S_OK)
rc = FALSE;
else
rc = TRUE;
exit:
if (wStr) MemFree(wStr);
if (wRE) MemFree(wRE);
return (BOOL)rc;
}
BOOL
IMAGEAPI
SymMatchString(
IN LPSTR string,
IN LPSTR expression,
IN BOOL fCase
)
{
return !strcmpre(string, expression, fCase);
}
BOOL
SymEnumSourceFiles(
IN HANDLE hProcess,
IN ULONG64 ModBase,
IN LPSTR Mask,
IN PSYM_ENUMSOURCFILES_CALLBACK cbSrcFiles,
IN PVOID UserContext
)
{
PPROCESS_ENTRY pe;
PLIST_ENTRY Next;
PMODULE_ENTRY mi;
DWORD i;
PSYMBOL_ENTRY sym;
LPSTR szSymName;
SYMBOL_ENTRY SymEntry={0};
CHAR Buffer[2500];
LPSTR p;
CHAR modmask[200];
BOOL rc;
int pass;
BOOL fCase;
static DWORD flags[2] = {LS_JUST_TEST, LS_QUALIFIED | LS_FAIL_IF_LOADED};
if (!cbSrcFiles) {
SetLastError(ERROR_INVALID_PARAMETER);
return FALSE;
}
__try {
pe = FindProcessEntry(hProcess);
if (!pe) {
SetLastError( ERROR_INVALID_HANDLE );
return FALSE;
}
p = 0;
modmask[0] = 0;
if (Mask)
p = strchr(Mask, '!');
if (p > Mask) {
memcpy(modmask, Mask, (int)(p - Mask));
modmask[p-Mask] = 0;
Mask = p + 1;
}
for (pass = 0; pass < 2; pass++) {
Next = pe->ModuleList.Flink;
if (Next) {
while (Next != &pe->ModuleList) {
mi = CONTAINING_RECORD( Next, MODULE_ENTRY, ListEntry );
Next = mi->ListEntry.Flink;
if (ModBase) {
if (mi->BaseOfDll != ModBase)
continue;
} else if (!MatchModuleName(mi, modmask)) {
continue;
}
if (!LoadSymbols(hProcess, mi, flags[pass]))
continue;
if (mi->dia) {
rc = diaEnumSourceFiles(mi, Mask, cbSrcFiles, UserContext);
if (!rc) {
if (mi->code == ERROR_CANCELLED) {
mi->code = 0;
return TRUE;
}
return rc;
}
continue;
}
#if 0
fCase = (g.SymOptions & SYMOPT_CASE_INSENSITIVE) ? FALSE : TRUE;
for (i = 0; i < mi->numsyms; i++) {
PSYMBOL_INFO SymInfo = (PSYMBOL_INFO) &Buffer[0];
sym = &mi->symbolTable[i];
if (Mask && *Mask && strcmpre(sym->Name, Mask, fCase))
continue;
}
#endif
}
}
}
} __except (EXCEPTION_EXECUTE_HANDLER) {
ImagepSetLastErrorFromStatus( GetExceptionCode() );
return FALSE;
}
return TRUE;
}
PWSTR
AnsiToUnicode(
PSTR pszAnsi
)
{
UINT uSizeUnicode;
PWSTR pwszUnicode;
if (!pszAnsi) {
return NULL;
}
uSizeUnicode = (strlen(pszAnsi) + 1) * sizeof(wchar_t);
pwszUnicode = (PWSTR)MemAlloc(uSizeUnicode);
if (*pszAnsi && pwszUnicode) {
ZeroMemory(pwszUnicode, uSizeUnicode);
if (!MultiByteToWideChar(CP_ACP, MB_COMPOSITE,
pszAnsi, strlen(pszAnsi),
pwszUnicode, uSizeUnicode)) {
// Error. Free the string, return NULL.
MemFree(pwszUnicode);
pwszUnicode = NULL;
}
}
return pwszUnicode;
}
BOOL
wcs2ansi(
PWSTR pwsz,
PSTR psz,
DWORD pszlen
)
{
BOOL rc;
int len;
assert(psz && pwsz);
len = wcslen(pwsz);
if (!len) {
*psz = 0;
return TRUE;
}
rc = WideCharToMultiByte(CP_ACP,
WC_SEPCHARS | WC_COMPOSITECHECK,
pwsz,
len,
psz,
pszlen,
NULL,
NULL);
if (!rc)
return FALSE;
psz[len] = 0;
return TRUE;
}
BOOL
ansi2wcs(
PSTR psz,
PWSTR pwsz,
DWORD pwszlen
)
{
BOOL rc;
int len;
assert(psz && pwsz);
len = strlen(psz);
if (!len) {
*pwsz = 0L;
return TRUE;
}
rc = MultiByteToWideChar(CP_ACP,
MB_COMPOSITE,
psz,
len,
pwsz,
pwszlen);
if (!rc)
return FALSE;
pwsz[len] = 0;
return TRUE;
}
PSTR
UnicodeToAnsi(
PWSTR pwszUnicode
)
{
UINT uSizeAnsi;
PSTR pszAnsi;
if (!pwszUnicode) {
return NULL;
}
uSizeAnsi = wcslen(pwszUnicode) + 1;
pszAnsi = (PSTR)MemAlloc(uSizeAnsi);
if (*pwszUnicode && pszAnsi) {
ZeroMemory(pszAnsi, uSizeAnsi);
if (!WideCharToMultiByte(CP_ACP, WC_SEPCHARS | WC_COMPOSITECHECK,
pwszUnicode, wcslen(pwszUnicode),
pszAnsi, uSizeAnsi, NULL, NULL)) {
// Error. Free the string, return NULL.
free(pszAnsi);
pszAnsi = NULL;
}
}
return pszAnsi;
}
#if 0
BOOL
CopyAnsiToUnicode(
PWSTR pszDest,
PSTR pszSrc,
DWORD dwCharCountSizeOfDest
)
{
PWSTR pszTmp = AnsiToUnicode(pszSrc);
if (!pszTmp) {
return FALSE;
} else {
wcsncpy(pszDest, pszTmp, dwCharCountSizeOfDest);
return TRUE;
}
}
BOOL
CopyUnicodeToAnsi(
PSTR pszDest,
PWSTR pszSrc,
DWORD dwCharCountSizeOfDest
)
{
PSTR pszTmp = UnicodeToAnsi(pszSrc);
if (!pszTmp) {
return FALSE;
} else {
strncpy(pszDest, pszTmp, dwCharCountSizeOfDest);
return TRUE;
}
}
#endif
BOOL
IMAGEAPI
SymGetTypeInfo(
IN HANDLE hProcess,
IN DWORD64 ModBase,
IN ULONG TypeId,
IN IMAGEHLP_SYMBOL_TYPE_INFO GetType,
OUT PVOID pInfo
)
{
HRESULT err;
err = diaGetSymbolInfo(hProcess, ModBase, TypeId, GetType, pInfo);
SetLastError((ULONG) err);
return (err==S_OK);
}
//#ifdef _WIN64
#if 0
BOOL __cdecl PDBOpenTpi(PDB* ppdb, const char* szMode, TPI** pptpi) {return FALSE;}
BOOL __cdecl PDBCopyTo(PDB* ppdb, const char* szTargetPdb, DWORD dwCopyFilter, DWORD dwReserved){return FALSE;}
BOOL __cdecl PDBClose(PDB* ppdb) {return FALSE;}
BOOL __cdecl ModQueryImod(Mod* pmod, USHORT* pimod) {return FALSE;}
BOOL __cdecl ModQueryLines(Mod* pmod, BYTE* pbLines, long* pcb) {return FALSE;}
BOOL __cdecl DBIQueryModFromAddr(DBI* pdbi, USHORT isect, long off, Mod** ppmod, USHORT* pisect, long* poff, long* pcb){return FALSE;}
BOOL __cdecl ModClose(Mod* pmod){return FALSE;}
BOOL __cdecl DBIQueryNextMod(DBI* pdbi, Mod* pmod, Mod** ppmodNext) {return FALSE;}
BYTE* __cdecl GSINextSym (GSI* pgsi, BYTE* pbSym) {return NULL;}
BOOL __cdecl PDBOpen(char* szPDB,char* szMode,SIG sigInitial,EC* pec,char szError[cbErrMax],PDB** pppdb) {return FALSE;}
BOOL __cdecl TypesClose(TPI* ptpi){return FALSE;}
BOOL __cdecl GSIClose(GSI* pgsi){return FALSE;}
BOOL __cdecl DBIClose(DBI* pdbi){return FALSE;}
BYTE* __cdecl GSINearestSym (GSI* pgsi, USHORT isect, long off, long* pdisp){return NULL;}
BOOL __cdecl PDBOpenValidate(char* szPDB,char* szPath,char* szMode,SIG sig,AGE age,EC* pec,char szError[cbErrMax],PDB** pppdb){return FALSE;}
BOOL __cdecl PDBOpenDBI(PDB* ppdb, const char* szMode, const char* szTarget, DBI** ppdbi){return FALSE;}
BOOL __cdecl DBIOpenPublics(DBI* pdbi, GSI **ppgsi){return FALSE;}
BOOL __cdecl DBIQuerySecMap(DBI* pdbi, BYTE* pb, long* pcb){return FALSE;}
#endif