4190 lines
99 KiB
C
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
|