You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
5176 lines
129 KiB
5176 lines
129 KiB
/*++
|
|
|
|
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
|
|
|
|
--*/
|
|
|
|
#if (_WIN32_IE < 0x0400)
|
|
#undef _WIN32_IE
|
|
#define _WIN32_IE 0x0400
|
|
#endif
|
|
|
|
#include "private.h"
|
|
#include "symbols.h"
|
|
#include "globals.h"
|
|
#include <shlobj.h>
|
|
#include <dbhpriv.h>
|
|
#include "fecache.hpp"
|
|
|
|
// common conversion routines
|
|
|
|
PSYMBOL_ENTRY
|
|
si2se(
|
|
PSYMBOL_INFO si,
|
|
PSYMBOL_ENTRY se
|
|
)
|
|
{
|
|
se->Size = si->SizeOfStruct;
|
|
se->Flags = si->Flags;
|
|
se->Address = si->Address;
|
|
se->Size = si->Size;
|
|
if (si->Name)
|
|
if (se->Name)
|
|
strcpy(se->Name, si->Name); // SECURITY: Don't know size of target buffer.
|
|
else
|
|
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 se;
|
|
}
|
|
|
|
PSYMBOL_INFO
|
|
se2si(
|
|
PSYMBOL_ENTRY se,
|
|
PSYMBOL_INFO si
|
|
)
|
|
{
|
|
si->Address = se->Address;
|
|
si->Flags = se->Flags;
|
|
si->TypeIndex = se->TypeIndex;
|
|
si->ModBase = se->ModBase;
|
|
si->NameLen = se->NameLength;
|
|
si->Size = se->Size;
|
|
si->Register = se->Register;
|
|
if (se->Name && (strlen(se->Name) < si->MaxNameLen))
|
|
CopyString(si->Name, se->Name, si->MaxNameLen);
|
|
|
|
return si;
|
|
}
|
|
|
|
|
|
PIMAGEHLP_SYMBOL
|
|
se2sym(
|
|
PSYMBOL_ENTRY se,
|
|
PIMAGEHLP_SYMBOL sym
|
|
)
|
|
{
|
|
assert(sym);
|
|
|
|
sym->Address = 0;
|
|
*sym->Name = 0;
|
|
|
|
if (!se)
|
|
return sym;
|
|
|
|
sym->Address = (ULONG)se->Address;
|
|
sym->Size = se->Size;
|
|
sym->Flags = se->Flags;
|
|
CatString(sym->Name, se->Name, sym->MaxNameLength);
|
|
|
|
return sym;
|
|
}
|
|
|
|
|
|
PIMAGEHLP_SYMBOL64
|
|
se2lsym(
|
|
PSYMBOL_ENTRY se,
|
|
PIMAGEHLP_SYMBOL64 lsym
|
|
)
|
|
{
|
|
assert(lsym);
|
|
|
|
lsym->Address = 0;
|
|
*lsym->Name = 0;
|
|
|
|
if (!se)
|
|
return lsym;
|
|
|
|
lsym->Address = se->Address;
|
|
lsym->Size = se->Size;
|
|
lsym->Flags = se->Flags;
|
|
CatString(lsym->Name, se->Name, lsym->MaxNameLength);
|
|
|
|
return lsym;
|
|
}
|
|
|
|
|
|
PIMAGEHLP_SYMBOL
|
|
si2sym(
|
|
PSYMBOL_INFO si,
|
|
PIMAGEHLP_SYMBOL sym
|
|
)
|
|
{
|
|
assert(sym);
|
|
|
|
sym->Address = 0;
|
|
*sym->Name = 0;
|
|
|
|
if (!si)
|
|
return sym;
|
|
|
|
sym->Address = (ULONG)si->Address;
|
|
sym->Size = si->Size;
|
|
sym->Flags = si->Flags;
|
|
sym->Flags ^= 0x7; // filter out bad flags
|
|
CatString(sym->Name, si->Name, sym->MaxNameLength);
|
|
|
|
return ((si->Address >> 32) == 0) ? sym : NULL;
|
|
}
|
|
|
|
|
|
PIMAGEHLP_SYMBOL64
|
|
si2lsym(
|
|
PSYMBOL_INFO si,
|
|
PIMAGEHLP_SYMBOL64 lsym
|
|
)
|
|
{
|
|
assert(lsym);
|
|
|
|
lsym->Address = 0;
|
|
*lsym->Name = 0;
|
|
|
|
if (!si)
|
|
return lsym;
|
|
|
|
lsym->Address = si->Address;
|
|
lsym->Size = si->Size;
|
|
lsym->Flags = si->Flags;
|
|
CatString(lsym->Name, si->Name, lsym->MaxNameLength);
|
|
|
|
return lsym;
|
|
}
|
|
|
|
|
|
PSYMBOL_INFO
|
|
si2si(
|
|
PSYMBOL_INFO trg,
|
|
PSYMBOL_INFO src
|
|
)
|
|
{
|
|
ULONG len = trg->MaxNameLen;
|
|
|
|
if (src->Name && (strlen(src->Name) < len))
|
|
memcpy(trg->Name, src->Name, len * sizeof(trg->Name[0]));
|
|
|
|
*trg = *src;
|
|
trg->MaxNameLen = len;
|
|
|
|
return trg;
|
|
}
|
|
|
|
|
|
PIMAGEHLP_SYMBOL
|
|
lsym2sym(
|
|
PIMAGEHLP_SYMBOL64 lsym,
|
|
PIMAGEHLP_SYMBOL sym
|
|
)
|
|
{
|
|
sym->Address = (DWORD)lsym->Address;
|
|
sym->Size = lsym->Size;
|
|
sym->Flags = lsym->Flags;
|
|
sym->MaxNameLength = lsym->MaxNameLength;
|
|
*sym->Name = 0;
|
|
CatString(sym->Name, lsym->Name, sym->MaxNameLength);
|
|
|
|
return ((lsym->Address >> 32) == 0) ? sym : NULL;
|
|
}
|
|
|
|
|
|
PIMAGEHLP_SYMBOL64
|
|
sym2lsym(
|
|
PIMAGEHLP_SYMBOL sym,
|
|
PIMAGEHLP_SYMBOL64 lsym
|
|
)
|
|
{
|
|
lsym->Address = sym->Address;
|
|
lsym->Size = sym->Size;
|
|
lsym->Flags = sym->Flags;
|
|
lsym->MaxNameLength = sym->MaxNameLength;
|
|
lsym->Name[0] = 0;
|
|
CatString(lsym->Name, sym->Name, lsym->MaxNameLength);
|
|
|
|
return lsym;
|
|
}
|
|
|
|
|
|
PIMAGEHLP_LINE
|
|
lline2line( // SympConvertLine64To32(
|
|
PIMAGEHLP_LINE64 lline,
|
|
PIMAGEHLP_LINE line
|
|
)
|
|
{
|
|
line->Key = lline->Key;
|
|
line->LineNumber = lline->LineNumber;
|
|
line->FileName = lline->FileName;
|
|
line->Address = (DWORD)lline->Address;
|
|
|
|
return ((lline->Address >> 32) == 0) ? line : NULL;
|
|
}
|
|
|
|
|
|
PIMAGEHLP_LINE64
|
|
line2lline( // SympConvertLine32To64(
|
|
PIMAGEHLP_LINE line,
|
|
PIMAGEHLP_LINE64 lline
|
|
)
|
|
{
|
|
lline->Key = line->Key;
|
|
lline->LineNumber = line->LineNumber;
|
|
lline->FileName = line->FileName;
|
|
lline->Address = line->Address;
|
|
|
|
return lline;
|
|
}
|
|
|
|
|
|
// other utility routines
|
|
|
|
BOOL
|
|
GetSymNextPrev(
|
|
IN HANDLE hProcess,
|
|
IN OUT PIMAGEHLP_SYMBOL64 Symbol,
|
|
IN int Direction
|
|
);
|
|
|
|
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 & SYMFLAG_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 );
|
|
}
|
|
}
|
|
|
|
|
|
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;
|
|
}
|
|
|
|
|
|
char *
|
|
TokenFromSymbolPath(
|
|
char *path,
|
|
char *token,
|
|
int size
|
|
)
|
|
{
|
|
char *next;
|
|
|
|
*token = 0;
|
|
|
|
if (!path)
|
|
return NULL;
|
|
|
|
next = strchr(path, ';');
|
|
|
|
if (!next)
|
|
CopyString(token, path, size);
|
|
else
|
|
CopyNString(token, path, (ULONG)(next - path), size);
|
|
trim(token);
|
|
|
|
if (next && !*++next)
|
|
next = NULL;
|
|
|
|
return next;
|
|
}
|
|
|
|
|
|
BOOL
|
|
CreateSymbolPath(
|
|
int pass,
|
|
char *base,
|
|
char *iext,
|
|
char *node,
|
|
char *ext,
|
|
char *path,
|
|
size_t size
|
|
)
|
|
{
|
|
if (!path || !base || !*base || !node || !*node || !ext || !*ext)
|
|
return false;
|
|
|
|
CopyString(path, base, size);
|
|
EnsureTrailingBackslash(path);
|
|
|
|
switch (pass)
|
|
{
|
|
case 1:
|
|
// add the "symbols" directory
|
|
CatString(path, "symbols", size);
|
|
EnsureTrailingBackslash(path);
|
|
// pass through
|
|
case 2:
|
|
// add the image extension
|
|
CatString(path, iext, size);
|
|
// pass through
|
|
case 0:
|
|
EnsureTrailingBackslash(path);
|
|
break;
|
|
default:
|
|
return false;
|
|
}
|
|
|
|
CatString(path, node, size);
|
|
CatString(path, ext, size);
|
|
|
|
return true;
|
|
}
|
|
|
|
|
|
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, // SECURITY: Don't know size of output buffer.
|
|
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;
|
|
}
|
|
|
|
|
|
|
|
void OpenLogFile(char *file)
|
|
{
|
|
time_t stTime;
|
|
char *szTime;
|
|
|
|
if (g.hLog)
|
|
return;
|
|
|
|
g.hLog = _open(file, O_APPEND | O_CREAT | O_RDWR, S_IREAD | S_IWRITE);
|
|
if (g.hLog == -1)
|
|
g.hLog = 0;
|
|
|
|
time(&stTime);
|
|
szTime = ctime(&stTime);
|
|
|
|
eprint("\n");
|
|
dprint(szTime ? "new session: %s" : "new session:\n", szTime);
|
|
}
|
|
|
|
|
|
void CloseLogFile()
|
|
{
|
|
time_t stTime;
|
|
char *szTime;
|
|
|
|
if (!g.hLog)
|
|
return;
|
|
|
|
time(&stTime);
|
|
szTime = ctime(&stTime);
|
|
|
|
dprint(szTime ? "closing session: %s" : "closing session:\n", szTime);
|
|
|
|
_close(g.hLog);
|
|
g.hLog = 0;
|
|
}
|
|
|
|
|
|
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;
|
|
char log[MAX_PATH];
|
|
|
|
__try {
|
|
|
|
if (!g.SymInitialized) {
|
|
g.SymInitialized = true;
|
|
g.cProcessList = 0;
|
|
InitializeListHead( &g.ProcessList );
|
|
}
|
|
|
|
*g.DebugToken = 0;
|
|
GetEnvironmentVariable(DBGHELP_TOKEN, g.DebugToken, sizeof(g.DebugToken) / sizeof(g.DebugToken[0]));
|
|
_strlwr(g.DebugToken);
|
|
|
|
if (GetEnvironmentVariable("DBGHELP_LOG", log, MAX_PATH))
|
|
OpenLogFile(log);
|
|
|
|
if (GetEnvironmentVariable("DBGHELP_DBGOUT", log, MAX_PATH))
|
|
g.fdbgout = true;
|
|
|
|
if (pe = FindProcessEntry( hProcess )) {
|
|
pe->cRefs++;
|
|
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->NextModule = NULL;
|
|
pe->hProcess = hProcess;
|
|
pe->pid = (int) GetPID(hProcess);
|
|
pe->cRefs = 1;
|
|
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, GetModule, NULL);
|
|
if (DosError) {
|
|
SymCleanup( hProcess );
|
|
SetLastError( DosError );
|
|
return false;
|
|
}
|
|
}
|
|
|
|
srcsrvInit(hProcess);
|
|
|
|
|
|
} __except (EXCEPTION_EXECUTE_HANDLER) {
|
|
|
|
ImagepSetLastErrorFromStatus( GetExceptionCode() );
|
|
return false;
|
|
|
|
}
|
|
|
|
return true;
|
|
}
|
|
|
|
|
|
BOOL
|
|
IMAGEAPI
|
|
lSymCleanup(
|
|
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;
|
|
PSOURCE_HINT sh;
|
|
PSOURCE_HINT shnext;
|
|
BOOL rc = true;
|
|
|
|
HeapDump("SymCleanup(before cleanup)\n");
|
|
|
|
__try {
|
|
|
|
pe = FindProcessEntry(hProcess);
|
|
if (!pe) {
|
|
SetLastError( ERROR_INVALID_HANDLE );
|
|
return false;
|
|
}
|
|
|
|
if (--pe->cRefs)
|
|
return true;
|
|
|
|
next = pe->ModuleList.Flink;
|
|
if (next) {
|
|
while (next != &pe->ModuleList) {
|
|
mi = CONTAINING_RECORD(next, MODULE_ENTRY, ListEntry);
|
|
next = mi->ListEntry.Flink;
|
|
FreeModuleEntry(pe, mi);
|
|
}
|
|
}
|
|
|
|
for (sh = pe->SourceHints; sh; sh = shnext) {
|
|
shnext = sh->next;
|
|
MemFree(sh->filename);
|
|
MemFree(sh);
|
|
}
|
|
|
|
symsrvClose();
|
|
|
|
MemFree(pe->SymbolSearchPath);
|
|
|
|
RemoveEntryList(&pe->ListEntry);
|
|
MemFree(pe);
|
|
g.cProcessList--;
|
|
|
|
diaCleanup();
|
|
|
|
// 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");
|
|
gfnSrcSrvCleanup(hProcess);
|
|
CloseLogFile();
|
|
|
|
return rc;
|
|
}
|
|
|
|
|
|
BOOL
|
|
IMAGEAPI
|
|
SymCleanup(
|
|
HANDLE hProcess
|
|
)
|
|
{
|
|
BOOL rc = false;
|
|
|
|
__try {
|
|
|
|
EnterCriticalSection(&g.threadlock);
|
|
rc = lSymCleanup(hProcess);
|
|
|
|
} __finally {
|
|
|
|
LeaveCriticalSection(&g.threadlock);
|
|
}
|
|
|
|
return rc;
|
|
}
|
|
|
|
|
|
BOOL
|
|
IMAGEAPI
|
|
SymSetParentWindow(
|
|
HWND hwnd
|
|
)
|
|
{
|
|
g.hwndParent = hwnd;
|
|
symsrvSetPrompts();
|
|
|
|
return true;
|
|
}
|
|
|
|
|
|
BOOL IsDirectoryWritable(char *dir)
|
|
{
|
|
char fname[MAX_PATH + 1];
|
|
|
|
if (!GetTempFileName(dir, "DBG", 0, fname))
|
|
return false;
|
|
|
|
DeleteFile(fname);
|
|
return true;
|
|
}
|
|
|
|
typedef BOOL (*SHGETSPECIALFOLDERPATHA)(HWND, LPSTR, int, BOOL);
|
|
|
|
BOOL GetCommonAppDataDirectory(char *dir)
|
|
{
|
|
char path[MAX_PATH + 1];
|
|
static HMODULE hShell32 = 0;
|
|
static SHGETSPECIALFOLDERPATHA fnSHGetSpecialFolderPathA = NULL;
|
|
|
|
assert(dir);
|
|
|
|
if (!hShell32) {
|
|
hShell32 = LoadLibrary("shell32.dll");
|
|
if (hShell32)
|
|
fnSHGetSpecialFolderPathA = (SHGETSPECIALFOLDERPATHA)GetProcAddress(hShell32, "SHGetSpecialFolderPathA");
|
|
else
|
|
hShell32 = (HMODULE)INVALID_HANDLE_VALUE;
|
|
}
|
|
|
|
if (hShell32 == (HMODULE)INVALID_HANDLE_VALUE)
|
|
return false;
|
|
if (!fnSHGetSpecialFolderPathA)
|
|
return false;
|
|
|
|
if (!fnSHGetSpecialFolderPathA(NULL, path, CSIDL_COMMON_APPDATA, false))
|
|
return false;
|
|
|
|
CopyString(dir, path, MAX_PATH + 1);
|
|
EnsureTrailingBackslash(dir);
|
|
CatString(dir, "dbg", MAX_PATH + 1);
|
|
|
|
if (!CreateDirectory(dir, NULL)) {
|
|
if( GetLastError() != ERROR_ALREADY_EXISTS )
|
|
return false;
|
|
}
|
|
|
|
return true;
|
|
}
|
|
|
|
|
|
PCHAR IMAGEAPI SymSetHomeDirectory(PCSTR dir)
|
|
{
|
|
char dstore[MAX_PATH + 1] = "";
|
|
static char homedir[MAX_PATH + 1] = "";
|
|
|
|
// If a valid new directory is passed, use it.
|
|
// Otherwise, if the home directory has not
|
|
// been initialized, do so.
|
|
|
|
*homedir = 0;
|
|
if (dir && *dir)
|
|
{
|
|
CopyStrArray(homedir, dir);
|
|
}
|
|
else if (!*g.HomeDir)
|
|
{
|
|
char path[MAX_PATH + 1];
|
|
char drive[_MAX_DRIVE + 1];
|
|
char dir[_MAX_DIR + 1];
|
|
if (GetModuleFileName(NULL, path, DIMA(path))) {
|
|
_splitpath(path, drive, dir, NULL, NULL);
|
|
CopyStrArray(path, drive);
|
|
CatStrArray(path, dir);
|
|
RemoveTrailingBackslash(path);
|
|
CopyStrArray(homedir, path);
|
|
}
|
|
}
|
|
|
|
// If the home directory was changed, set it
|
|
// and the new default downstream store.
|
|
|
|
if (*homedir)
|
|
{
|
|
if (!IsDirectoryWritable(homedir)) {
|
|
if(!GetCommonAppDataDirectory(homedir)) {
|
|
CopyStrArray(homedir, g.HomeDir);
|
|
return homedir;
|
|
}
|
|
}
|
|
|
|
CopyStrArray(g.HomeDir, homedir);
|
|
|
|
CopyStrArray(g.SymDir, homedir);
|
|
EnsureTrailingBackslash(g.SymDir);
|
|
CatStrArray(g.SymDir, "sym");
|
|
symsrvSetDownstreamStore(g.SymDir);
|
|
} else
|
|
CopyStrArray(homedir, g.HomeDir);
|
|
|
|
// Return the current home directory.
|
|
|
|
return homedir;
|
|
}
|
|
|
|
|
|
PCHAR
|
|
IMAGEAPI
|
|
SymGetHomeDirectory(
|
|
DWORD type,
|
|
PSTR dir,
|
|
size_t size
|
|
)
|
|
{
|
|
char *tdir;
|
|
static char sz[MAX_PATH + 1];
|
|
|
|
if (!dir || type >= hdMax) {
|
|
SetLastError(ERROR_INVALID_PARAMETER);
|
|
return NULL;
|
|
}
|
|
|
|
switch(type)
|
|
{
|
|
case hdBase:
|
|
tdir = g.HomeDir;
|
|
break;
|
|
case hdSym:
|
|
tdir = g.SymDir;
|
|
break;
|
|
case hdSrc:
|
|
tdir = g.SrcDir;
|
|
break;
|
|
}
|
|
|
|
if (strlen(tdir) >= size) {
|
|
SetLastError(ERROR_INSUFFICIENT_BUFFER);
|
|
return NULL;
|
|
}
|
|
|
|
CopyString(dir, tdir, size);
|
|
|
|
return dir;
|
|
}
|
|
|
|
|
|
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.
|
|
|
|
--*/
|
|
|
|
{
|
|
BOOL symsdebug;
|
|
DWORD srcsopts;
|
|
BOOL secure;
|
|
|
|
secure = option(SYMOPT_SECURE);
|
|
g.SymOptions = UserOptions;
|
|
|
|
srcsopts = (g.fnSrcSrvGetOptions) ? gfnSrcSrvGetOptions() : 0;
|
|
if (option(SYMOPT_DEBUG)) {
|
|
srcsopts |= SRCSRVOPT_DEBUG;
|
|
symsdebug = true;
|
|
} else {
|
|
srcsopts &= ~SRCSRVOPT_DEBUG;
|
|
symsdebug = false;
|
|
}
|
|
gfnSrcSrvSetOptions(srcsopts);
|
|
|
|
symsrvSetCallback((symsdebug || g.hLog) ? true : false);
|
|
|
|
if (!secure) {
|
|
if (option(SYMOPT_SECURE))
|
|
symsrvSetOptions(SSRVOPT_SECURE, 1);
|
|
} else if (!option(SYMOPT_SECURE))
|
|
g.SymOptions |= SYMOPT_SECURE;
|
|
|
|
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;
|
|
}
|
|
|
|
|
|
BOOL
|
|
IMAGEAPI
|
|
SymSetContext(
|
|
HANDLE hProcess,
|
|
PIMAGEHLP_STACK_FRAME StackFrame,
|
|
PIMAGEHLP_CONTEXT Context
|
|
)
|
|
{
|
|
PPROCESS_ENTRY pe;
|
|
|
|
pe = FindProcessEntry(hProcess);
|
|
if (!pe)
|
|
return false;
|
|
|
|
pe->pContext = Context;
|
|
pe->StackFrame = *StackFrame;
|
|
|
|
return diaSetModFromIP(pe);
|
|
};
|
|
|
|
|
|
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)
|
|
CopyStrArray(p->file, mi->LoadedPdbName);
|
|
break;
|
|
default:
|
|
if (mi->LoadedImageName)
|
|
CopyStrArray(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
|
|
dbhfnLoadPdb(
|
|
IN OUT PDBH_LOADPDB p
|
|
)
|
|
{
|
|
PIMGHLP_DEBUG_DATA idd;
|
|
MODLOAD_DATA mld;
|
|
int i;
|
|
|
|
idd = InitIDD(
|
|
(HANDLE)6969,
|
|
0,
|
|
p->pdb,
|
|
NULL,
|
|
100000,
|
|
0,
|
|
&mld,
|
|
0,
|
|
0);
|
|
|
|
if (!idd)
|
|
return false;
|
|
|
|
CopyString(idd->PdbFileName, p->pdb, MAX_PATH + 1);
|
|
|
|
for (i = 0; i < 1000; i++) {
|
|
dtrace("%d ", i);
|
|
diaGetPdb(idd);
|
|
if (idd->dia)
|
|
diaRelease(idd->dia);
|
|
idd->dia = NULL;
|
|
}
|
|
|
|
ReleaseDebugData(idd, IMGHLP_FREE_STANDARD);
|
|
|
|
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);
|
|
|
|
case dbhLoadPdb:
|
|
return dbhfnLoadPdb((PDBH_LOADPDB)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;
|
|
char buf[2500];
|
|
LPSTR p;
|
|
CHAR modmask[200];
|
|
BOOL rc;
|
|
int pass;
|
|
BOOL fCase;
|
|
PSYMBOL_INFO si;
|
|
char match[MAX_SYM_NAME + 100];
|
|
|
|
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) {
|
|
// search is scoped to current scope
|
|
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;
|
|
}
|
|
|
|
if (Mask && *Mask)
|
|
PrepRE4Srch(Mask, match);
|
|
else
|
|
*match = 0;
|
|
|
|
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])) {
|
|
if (GetLastError() == ERROR_CANCELLED)
|
|
return false;
|
|
continue;
|
|
}
|
|
|
|
if (mi->dia) {
|
|
rc = diaEnumerateSymbols(pe,
|
|
mi,
|
|
Mask,
|
|
EnumSymbolsCallback,
|
|
UserContext,
|
|
Use64,
|
|
CallBackUsesUnicode);
|
|
}
|
|
|
|
if (mi->numsyms) {
|
|
fCase = option(SYMOPT_CASE_INSENSITIVE) ? false : true;
|
|
|
|
si = (PSYMBOL_INFO)buf;
|
|
ZeroMemory(buf, sizeof(buf));
|
|
si->MaxNameLen = sizeof(buf) - sizeof(SYMBOL_INFO);
|
|
|
|
for (i = 0; i < mi->numsyms; i++) {
|
|
sym = &mi->symbolTable[i];
|
|
if (*match && strcmpre(sym->Name, match, fCase))
|
|
continue;
|
|
se2si(sym, si);
|
|
si->ModBase = mi->BaseOfDll;
|
|
if (!DoEnumCallback(
|
|
pe,
|
|
si,
|
|
si->Size,
|
|
EnumSymbolsCallback,
|
|
UserContext,
|
|
Use64,
|
|
CallBackUsesUnicode)) {
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
rc = vsEnumSymbols(pe,
|
|
mi,
|
|
Mask,
|
|
EnumSymbolsCallback,
|
|
UserContext,
|
|
Use64,
|
|
CallBackUsesUnicode);
|
|
if (!rc) {
|
|
if (mi->code == ERROR_CANCELLED) {
|
|
mi->code = 0;
|
|
return true;
|
|
}
|
|
return rc;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
} __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);
|
|
|
|
}
|
|
|
|
PSYMBOL_INFO
|
|
SympGetSymFromAddr(
|
|
IN HANDLE hProcess,
|
|
IN DWORD64 Address,
|
|
OUT PDWORD64 Displacement
|
|
)
|
|
|
|
/*++
|
|
|
|
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.
|
|
|
|
Return Value:
|
|
|
|
PSYMBOL_INFO - relevent symbol information
|
|
|
|
--*/
|
|
|
|
{
|
|
PPROCESS_ENTRY pe;
|
|
PMODULE_ENTRY mi;
|
|
PSYMBOL_INFO si;
|
|
|
|
BOOL rc;
|
|
|
|
__try {
|
|
|
|
pe = FindProcessEntry(hProcess);
|
|
if (!pe)
|
|
return (PSYMBOL_INFO)(ULONG_PTR)error(ERROR_INVALID_HANDLE);
|
|
|
|
mi = GetModuleForPC(pe, Address, false);
|
|
if (!mi)
|
|
return (PSYMBOL_INFO)(ULONG_PTR)error(ERROR_MOD_NOT_FOUND);
|
|
|
|
if (!LoadSymbols(hProcess, mi, 0))
|
|
return (PSYMBOL_INFO)(ULONG_PTR)error(ERROR_MOD_NOT_FOUND);
|
|
|
|
#ifdef DEBUGSYMTAG
|
|
si = GetSymFromAddrByTag( Address, SymTagAnnotation, Displacement, mi );
|
|
if (si)
|
|
dprint("ANNOTATION: %xI64x %s %x\n", si->Address, si->Name, Displacement);
|
|
#endif
|
|
|
|
si = GetSymFromAddr( Address, Displacement, mi );
|
|
if (!si)
|
|
return (PSYMBOL_INFO)(ULONG_PTR)error(ERROR_INVALID_ADDRESS);
|
|
|
|
} __except (EXCEPTION_EXECUTE_HANDLER) {
|
|
|
|
ImagepSetLastErrorFromStatus(GetExceptionCode());
|
|
return NULL;
|
|
|
|
}
|
|
|
|
#if 0
|
|
if (_stricmp(mi->ModuleName, "symstore"))
|
|
return si;
|
|
char sz[MAX_PATH + 1];
|
|
SymGetSourceFile(hProcess, Address, "d:\\db\\symsrv\\symstore\\symstore.cpp", sz);
|
|
#endif
|
|
return si;
|
|
}
|
|
|
|
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.
|
|
|
|
--*/
|
|
{
|
|
PSYMBOL_INFO si;
|
|
|
|
si = SympGetSymFromAddr(hProcess, Address, Displacement);
|
|
if (!si)
|
|
return false;
|
|
|
|
si2lsym(si, Symbol);
|
|
|
|
return true;
|
|
}
|
|
|
|
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.
|
|
|
|
--*/
|
|
{
|
|
PSYMBOL_INFO si;
|
|
DWORD64 qDisplacement;
|
|
|
|
si = SympGetSymFromAddr(hProcess, Address, &qDisplacement);
|
|
if (!si)
|
|
return false;
|
|
|
|
si2sym(si, Symbol);
|
|
if (Displacement)
|
|
*Displacement = (DWORD)qDisplacement;
|
|
|
|
return true;
|
|
}
|
|
|
|
|
|
PSYMBOL_INFO
|
|
SympGetSymFromName(
|
|
IN HANDLE hProcess,
|
|
IN LPSTR Name
|
|
)
|
|
|
|
/*++
|
|
|
|
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;
|
|
IMAGEHLP_DEFERRED_SYMBOL_LOAD64 idsl64;
|
|
int pass;
|
|
PSYMBOL_INFO si;
|
|
|
|
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) {
|
|
si = FindSymbolByName( pe, mi, p+1 );
|
|
if (si)
|
|
return si;
|
|
}
|
|
|
|
SetLastError( ERROR_MOD_NOT_FOUND );
|
|
return false;
|
|
}
|
|
|
|
// now check, using context information
|
|
|
|
si = FindSymbolByName( pe, NULL, Name );
|
|
if (si)
|
|
return si;
|
|
|
|
// 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 (!LoadSymbols(hProcess, mi, flags[pass])) {
|
|
if (GetLastError() == ERROR_CANCELLED)
|
|
return false;
|
|
continue;
|
|
}
|
|
|
|
si = FindSymbolByName( pe, mi, Name );
|
|
if (si)
|
|
return si;
|
|
}
|
|
}
|
|
|
|
SetLastError( ERROR_MOD_NOT_FOUND );
|
|
return false;
|
|
|
|
} __except (EXCEPTION_EXECUTE_HANDLER) {
|
|
|
|
ImagepSetLastErrorFromStatus( GetExceptionCode() );
|
|
return false;
|
|
|
|
}
|
|
|
|
SetLastError( ERROR_INVALID_FUNCTION );
|
|
return NULL;
|
|
}
|
|
|
|
|
|
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.
|
|
|
|
--*/
|
|
{
|
|
PSYMBOL_INFO si;
|
|
|
|
si = SympGetSymFromName(hProcess, Name);
|
|
if (!si)
|
|
return false;
|
|
|
|
si2lsym(si, Symbol);
|
|
|
|
return true;
|
|
}
|
|
|
|
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.
|
|
|
|
--*/
|
|
{
|
|
PSYMBOL_INFO si;
|
|
|
|
si = SympGetSymFromName(hProcess, Name);
|
|
if (!si)
|
|
return false;
|
|
|
|
si2sym(si,Symbol);
|
|
|
|
return true;
|
|
}
|
|
|
|
|
|
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 rc = false;
|
|
|
|
Symbol64 = (PIMAGEHLP_SYMBOL64)MemAlloc(sizeof(IMAGEHLP_SYMBOL64) + Symbol32->MaxNameLength);
|
|
|
|
if (Symbol64) {
|
|
sym2lsym(Symbol32, Symbol64);
|
|
if (SymGetSymNext64(hProcess, Symbol64)) {
|
|
lsym2sym(Symbol64, Symbol32);
|
|
rc = true;
|
|
}
|
|
|
|
MemFree(Symbol64);
|
|
}
|
|
return rc;
|
|
}
|
|
|
|
|
|
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 GetSymNextPrev(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 rc = false;
|
|
|
|
Symbol64 = (PIMAGEHLP_SYMBOL64)MemAlloc(sizeof(IMAGEHLP_SYMBOL64) + Symbol32->MaxNameLength);
|
|
|
|
if (Symbol64) {
|
|
sym2lsym(Symbol32, Symbol64);
|
|
if (SymGetSymPrev64(hProcess, Symbol64)) {
|
|
lsym2sym(Symbol64, Symbol32);
|
|
rc = true;
|
|
}
|
|
MemFree(Symbol64);
|
|
}
|
|
return rc;
|
|
}
|
|
|
|
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 GetSymNextPrev(hProcess, Symbol, -1);
|
|
}
|
|
|
|
|
|
BOOL
|
|
GetSymNextPrev(
|
|
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 disp;
|
|
ULONG64 addr;
|
|
PSYMBOL_INFO si;
|
|
PSYMBOL_INFO vssi;
|
|
PSYMBOL_ENTRY se;
|
|
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;
|
|
}
|
|
|
|
addr = Symbol->Address;
|
|
|
|
if (mi->dia) {
|
|
|
|
si = diaGetSymNextPrev(mi, addr, Direction);
|
|
vssi = vsGetSymNextPrev(mi, addr, Direction);
|
|
si2lsym(si, Symbol);
|
|
|
|
} else {
|
|
|
|
se = cvGetSymFromAddr(addr, &disp, mi);
|
|
if (se) {
|
|
if (Direction > 0 && se+1 >= mi->symbolTable+mi->numsyms) {
|
|
se = NULL;
|
|
} else if (Direction < 0 && se-1 < mi->symbolTable) {
|
|
se = NULL;
|
|
}
|
|
se += Direction;
|
|
}
|
|
se2lsym(se, Symbol);
|
|
}
|
|
|
|
vssi = vsGetSymNextPrev(mi, addr, Direction);
|
|
if (vssi) {
|
|
if (Symbol->Address) {
|
|
if (Direction > 0) {
|
|
if (vssi->Address < Symbol->Address)
|
|
si2lsym(vssi, Symbol);
|
|
} else if (Symbol->Address < vssi->Address) {
|
|
si2lsym(vssi, Symbol);
|
|
}
|
|
} else {
|
|
si2lsym(vssi, Symbol);
|
|
}
|
|
}
|
|
|
|
if (!Symbol->Address) {
|
|
SetLastError(ERROR_INVALID_ADDRESS);
|
|
return false;
|
|
}
|
|
|
|
return true;
|
|
|
|
} __except (EXCEPTION_EXECUTE_HANDLER) {
|
|
|
|
ImagepSetLastErrorFromStatus( GetExceptionCode() );
|
|
return false;
|
|
|
|
}
|
|
|
|
return false;
|
|
}
|
|
|
|
|
|
BOOL
|
|
IMAGEAPI
|
|
SymGetSourceFile(
|
|
IN HANDLE hProcess,
|
|
IN ULONG64 Base,
|
|
IN LPCSTR FileSpec,
|
|
OUT LPSTR FilePath
|
|
)
|
|
{
|
|
PPROCESS_ENTRY pe;
|
|
PMODULE_ENTRY mi;
|
|
PBYTE stream;
|
|
|
|
if (!FileSpec || !*FileSpec || !FilePath)
|
|
return error(ERROR_INVALID_PARAMETER);
|
|
|
|
if (!g.fnSrcSrvInit)
|
|
return false;
|
|
|
|
pe = FindProcessEntry(hProcess);
|
|
if (!pe)
|
|
return error(ERROR_INVALID_HANDLE);
|
|
|
|
mi = GetModuleForPC(pe, Base, false);
|
|
if (!mi)
|
|
return error(ERROR_MOD_NOT_FOUND);
|
|
|
|
if (!LoadSymbols(hProcess, mi, 0))
|
|
return error(ERROR_MOD_NOT_FOUND);
|
|
|
|
if (mi->cbSrcSrv == -1)
|
|
return error(ERROR_NOT_SUPPORTED);
|
|
|
|
if (!mi->cbSrcSrv) {
|
|
diaReadStream(mi, "srcsrv", &stream, &mi->cbSrcSrv);
|
|
if (mi->cbSrcSrv)
|
|
gfnSrcSrvLoadModule(pe->hProcess,
|
|
(*mi->AliasName) ? mi->AliasName : mi->ModuleName,
|
|
mi->BaseOfDll,
|
|
stream,
|
|
mi->cbSrcSrv);
|
|
MemFree(stream);
|
|
}
|
|
if (!mi->cbSrcSrv) {
|
|
mi->cbSrcSrv = -1;
|
|
return error(ERROR_NOT_SUPPORTED);
|
|
}
|
|
|
|
return gfnSrcSrvGetFile(pe->hProcess, mi->BaseOfDll, FileSpec, FilePath);
|
|
}
|
|
|
|
|
|
BOOL
|
|
IMAGEAPI
|
|
SymEnumLines(
|
|
IN HANDLE hProcess,
|
|
IN ULONG64 Base,
|
|
IN PCSTR Obj,
|
|
IN PCSTR File,
|
|
IN PSYM_ENUMLINES_CALLBACK EnumLinesCallback,
|
|
IN PVOID UserContext
|
|
)
|
|
{
|
|
PPROCESS_ENTRY pe;
|
|
PMODULE_ENTRY mi;
|
|
|
|
__try {
|
|
pe = FindProcessEntry(hProcess);
|
|
if (!pe)
|
|
return error(ERROR_INVALID_HANDLE);
|
|
|
|
mi = GetModuleForPC(pe, Base, false);
|
|
if (!mi)
|
|
return error(ERROR_MOD_NOT_FOUND);
|
|
|
|
if (!LoadSymbols(hProcess, mi, 0))
|
|
return error(ERROR_MOD_NOT_FOUND);
|
|
|
|
if (!mi->dia)
|
|
return error(ERROR_NOT_SUPPORTED);
|
|
|
|
return diaEnumLines(pe, mi, Obj, File, EnumLinesCallback, UserContext);
|
|
|
|
} __except (EXCEPTION_EXECUTE_HANDLER) {
|
|
|
|
ImagepSetLastErrorFromStatus(GetExceptionCode());
|
|
return false;
|
|
}
|
|
|
|
return true;
|
|
}
|
|
|
|
|
|
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;
|
|
SRCCODEINFO sci;
|
|
|
|
sciInit(&sci);
|
|
|
|
__try {
|
|
if (Line->SizeOfStruct != sizeof(IMAGEHLP_LINE64))
|
|
return error(ERROR_INVALID_PARAMETER);
|
|
|
|
pe = FindProcessEntry( hProcess );
|
|
if (!pe)
|
|
return error( ERROR_INVALID_HANDLE );
|
|
|
|
mi = GetModuleForPC( pe, dwAddr, false );
|
|
if (!mi)
|
|
return error( ERROR_MOD_NOT_FOUND );
|
|
|
|
if (!LoadSymbols(hProcess, mi, 0))
|
|
return error( ERROR_MOD_NOT_FOUND );
|
|
|
|
if (!GetLineFromAddr(pe, mi, dwAddr, pdwDisplacement, &sci))
|
|
return error( ERROR_INVALID_ADDRESS );
|
|
|
|
sci2lline(mi, &sci, Line);
|
|
|
|
} __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)) {
|
|
lline2line(&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 Line64
|
|
)
|
|
|
|
/*++
|
|
|
|
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 i;
|
|
PSOURCE_HINT sh;
|
|
char fname[MAX_PATH + 1];
|
|
SRCCODEINFO sci;
|
|
SRCCODEINFO tsci;
|
|
|
|
static DWORD flags[3] = {LS_JUST_TEST, LS_QUALIFIED | LS_LOAD_LINES, LS_QUALIFIED | LS_LOAD_LINES};
|
|
static DWORD method[3] = {mFullPath, mFullPath, mName};
|
|
|
|
sciInit(&sci);
|
|
sciInit(&tsci);
|
|
|
|
__try {
|
|
if (Line64->SizeOfStruct != sizeof(IMAGEHLP_LINE64))
|
|
return error(ERROR_INVALID_PARAMETER);
|
|
|
|
// If no file was given then it's assumed that the file
|
|
// is the same as for the line information passed in.
|
|
|
|
if (FileName)
|
|
CopyStrArray(fname, FileName);
|
|
else
|
|
CopyStrArray(fname, Line64->FileName ? Line64->FileName : "");
|
|
|
|
// get the process
|
|
|
|
pe = FindProcessEntry( hProcess );
|
|
if (!pe)
|
|
return error( ERROR_INVALID_HANDLE );
|
|
|
|
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 (!*fname)
|
|
return error(ERROR_INVALID_PARAMETER);
|
|
|
|
mi = FindModule(hProcess, pe, ModuleName, true);
|
|
if (mi) {
|
|
if (GetLineFromName(pe, mi, fname, dwLineNumber, plDisplacement, &sci, mFullPath))
|
|
return sci2lline(mi, &sci, Line64);
|
|
if (GetLineFromName(pe, mi, fname, dwLineNumber, plDisplacement, &sci, mName))
|
|
return sci2lline(mi, &sci, Line64);
|
|
return error(ERROR_NOT_FOUND);
|
|
}
|
|
|
|
return error( ERROR_MOD_NOT_FOUND );
|
|
}
|
|
|
|
if (!*fname) {
|
|
// 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, Line64->Address, false );
|
|
if (!mi)
|
|
return error( ERROR_MOD_NOT_FOUND );
|
|
|
|
if (!LoadSymbols(hProcess, mi, LS_LOAD_LINES))
|
|
return error( ERROR_MOD_NOT_FOUND );
|
|
|
|
if (GetLineFromName(pe, mi, fname, dwLineNumber, plDisplacement, &sci, mFullPath))
|
|
return sci2lline(mi, &sci, Line64);
|
|
if (GetLineFromName(pe, mi, fname, dwLineNumber, plDisplacement, &sci, mName))
|
|
return sci2lline(mi, &sci, Line64);
|
|
|
|
return error(ERROR_NOT_FOUND);
|
|
}
|
|
|
|
sh = FindSourceFileInHintList(pe, fname);
|
|
if (sh) {
|
|
if (GetLineFromName(pe, sh->mi, fname, dwLineNumber, plDisplacement, &sci, mFullPath))
|
|
return sci2lline(sh->mi, &sci, Line64);
|
|
}
|
|
|
|
Next = pe->ModuleList.Flink;
|
|
if (!Next)
|
|
return error( ERROR_MOD_NOT_FOUND );
|
|
|
|
ClearModuleFlags(pe);
|
|
ZeroMemory(&sci, sizeof(sci));
|
|
|
|
// Search for lines in 3 passes.
|
|
//
|
|
// 0. Look for exact match of full path name. Check only modules with symbols loaded.
|
|
// 1. Look for exact match of full path name. Load all unloaded modules.
|
|
// 2. Look for best match of path name. All modules are already loaded.
|
|
|
|
for (i = 0; i < 3; i++) {
|
|
Next = pe->ModuleList.Flink;
|
|
while (Next != &pe->ModuleList) {
|
|
mi = CONTAINING_RECORD( Next, MODULE_ENTRY, ListEntry );
|
|
Next = mi->ListEntry.Flink;
|
|
#ifdef DEBUG
|
|
if (traceSubName(mi->ModuleName)) // for setting debug breakpoints from DBGHELP_TOKEN
|
|
dtrace("debug(%s)\n", mi->ModuleName);
|
|
#endif
|
|
if (mi->processed && (method[i] == mFullPath))
|
|
continue;
|
|
if (!LoadSymbols(hProcess, mi, flags[i])) {
|
|
if (GetLastError() == ERROR_CANCELLED)
|
|
return false;
|
|
continue;
|
|
}
|
|
mi->processed = true;
|
|
|
|
if (GetLineFromName(pe, mi, fname, dwLineNumber, plDisplacement, &tsci, method[i])) {
|
|
if (UpdateBestSrc(fname, sci.FileName, tsci.FileName))
|
|
memcpy(&sci, &tsci, sizeof(SRCCODEINFO));
|
|
}
|
|
}
|
|
|
|
if (*sci.FileName)
|
|
return sci2lline(mi, &sci, Line64);
|
|
|
|
// Only the 1st pass works with loaded symbols. The next pass will try
|
|
// to load the rest. Might as well quit now if the options don't allow it.
|
|
|
|
if (option(SYMOPT_NO_UNQUALIFIED_LOADS))
|
|
return error(ERROR_NOT_FOUND);
|
|
}
|
|
|
|
return error(ERROR_NOT_FOUND);
|
|
|
|
} __except (EXCEPTION_EXECUTE_HANDLER) {
|
|
|
|
ImagepSetLastErrorFromStatus( GetExceptionCode() );
|
|
return false;
|
|
|
|
}
|
|
|
|
return error( ERROR_INVALID_FUNCTION );
|
|
}
|
|
|
|
|
|
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);
|
|
line2lline(Line32, &Line64);
|
|
if (SymGetLineFromName64(hProcess,
|
|
ModuleName,
|
|
FileName,
|
|
dwLineNumber,
|
|
plDisplacement,
|
|
&Line64)) {
|
|
return lline2line(&Line64, Line32) ? true : false;
|
|
} 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))
|
|
return error(ERROR_INVALID_PARAMETER);
|
|
|
|
pe = FindProcessEntry( hProcess );
|
|
if (!pe)
|
|
return error( ERROR_INVALID_HANDLE );
|
|
|
|
mi = GetModuleForPC( pe, Line->Address, false );
|
|
if (!mi)
|
|
return error( ERROR_MOD_NOT_FOUND );
|
|
|
|
if (!LoadSymbols(hProcess, mi, 0))
|
|
return error( ERROR_MOD_NOT_FOUND );
|
|
|
|
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)
|
|
return error(ERROR_INVALID_PARAMETER);
|
|
|
|
if (SrcLine == Src->LineInfo+Src->Lines-1)
|
|
return error(ERROR_NO_MORE_ITEMS);
|
|
|
|
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);
|
|
line2lline(Line32, &Line64);
|
|
if (SymGetLineNext64(hProcess, &Line64)) {
|
|
return lline2line(&Line64, Line32) ? true : false;
|
|
} 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))
|
|
return error(ERROR_INVALID_PARAMETER);
|
|
|
|
pe = FindProcessEntry( hProcess );
|
|
if (!pe)
|
|
return error( ERROR_INVALID_HANDLE );
|
|
|
|
mi = GetModuleForPC( pe, Line->Address, false );
|
|
if (!mi)
|
|
return error( ERROR_MOD_NOT_FOUND );
|
|
|
|
if (!LoadSymbols(hProcess, mi, 0))
|
|
return error( ERROR_MOD_NOT_FOUND );
|
|
|
|
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)
|
|
return error(ERROR_INVALID_PARAMETER);
|
|
|
|
if (SrcLine == Src->LineInfo)
|
|
return error(ERROR_NO_MORE_ITEMS);
|
|
|
|
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);
|
|
line2lline(Line32, &Line64);
|
|
if (SymGetLinePrev64(hProcess, &Line64)) {
|
|
return lline2line(&Line64, Line32) ? true : false;
|
|
} 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)
|
|
return error(ERROR_INVALID_PARAMETER);
|
|
|
|
pe = FindProcessEntry( hProcess );
|
|
if (!pe)
|
|
return error(ERROR_INVALID_PARAMETER);
|
|
|
|
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)
|
|
return error(ERROR_INVALID_PARAMETER);
|
|
|
|
pe = FindProcessEntry( hProcess );
|
|
if (!pe)
|
|
return error(ERROR_INVALID_PARAMETER);
|
|
|
|
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_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_IA64:
|
|
rtf = LookupFunctionEntryIa64(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;
|
|
|
|
DWORD dw = sizeof(CVDD);
|
|
|
|
__try {
|
|
|
|
pe = FindProcessEntry( hProcess );
|
|
if (!pe)
|
|
return error( ERROR_INVALID_HANDLE );
|
|
|
|
mi = GetModuleForPC( pe, dwAddr, false );
|
|
if (!mi)
|
|
return error( ERROR_MOD_NOT_FOUND );
|
|
|
|
SizeOfStruct = ModuleInfo->SizeOfStruct;
|
|
if (SizeOfStruct > sizeof(IMAGEHLP_MODULE64))
|
|
return error( ERROR_INVALID_PARAMETER );
|
|
|
|
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;
|
|
CatString( ModuleInfo->ModuleName, mi->ModuleName, sizeof(ModuleInfo->ModuleName));
|
|
ModuleInfo->ImageName[0] = 0;
|
|
if (mi->ImageName)
|
|
CopyStrArray(ModuleInfo->ImageName, mi->ImageName);
|
|
ModuleInfo->LoadedImageName[0] = 0;
|
|
if (mi->LoadedImageName)
|
|
CopyStrArray(ModuleInfo->LoadedImageName, mi->LoadedImageName);
|
|
|
|
// if (ModuleInfo->SizeofStruct == 0x248) // the original size
|
|
// return true
|
|
|
|
// the following code supports the expanded structure
|
|
|
|
if (ModuleInfo->SizeOfStruct < sizeof(IMAGEHLP_MODULE64))
|
|
return true;
|
|
|
|
ModuleInfo->LoadedPdbName[0] = 0;
|
|
if (mi->LoadedPdbName)
|
|
CopyStrArray(ModuleInfo->LoadedPdbName, mi->LoadedPdbName);
|
|
ModuleInfo->CVSig = mi->cvSig;
|
|
ModuleInfo->PdbSig = mi->pdbdataSig;
|
|
memcpy(&ModuleInfo->PdbSig70, &mi->pdbdataGuid, sizeof(GUID));
|
|
ModuleInfo->PdbAge = mi->pdbdataAge;
|
|
ModuleInfo->PdbUnmatched = mi->fPdbUnmatched;
|
|
ModuleInfo->DbgUnmatched = mi->fDbgUnmatched;
|
|
ModuleInfo->LineNumbers = mi->fLines;
|
|
ModuleInfo->GlobalSymbols = mi->fSymbols;
|
|
ModuleInfo->TypeInfo = mi->fTypes;
|
|
switch (mi->CVRec.dwSig)
|
|
{
|
|
case '01BN':
|
|
CopyString(ModuleInfo->CVData, mi->CVRec.nb10i.szPdb, MAX_PATH * 3);
|
|
break;
|
|
case 'SDSR':
|
|
CopyString(ModuleInfo->CVData, mi->CVRec.rsdsi.szPdb, MAX_PATH * 3);
|
|
break;
|
|
}
|
|
} __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))
|
|
return error(ERROR_INVALID_PARAMETER);
|
|
|
|
ZeroMemory(wModInfo, sizeof(IMAGEHLP_MODULEW));
|
|
wModInfo->SizeOfStruct = sizeof(IMAGEHLP_MODULEW);
|
|
|
|
if (!SympConvertUnicodeModule32ToAnsiModule32(
|
|
wModInfo, &aModInfo))
|
|
{
|
|
return error(ERROR_INVALID_PARAMETER);
|
|
}
|
|
|
|
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)
|
|
return error( ERROR_INVALID_HANDLE );
|
|
|
|
mi = GetModuleForPC( pe,
|
|
dwAddr == (DWORD)-1 ? (DWORD64)-1 : dwAddr, false );
|
|
if (!mi)
|
|
return error( ERROR_MOD_NOT_FOUND );
|
|
|
|
SizeOfStruct = ModuleInfo->SizeOfStruct;
|
|
if (SizeOfStruct > sizeof(IMAGEHLP_MODULE))
|
|
return error( ERROR_INVALID_PARAMETER );
|
|
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;
|
|
CatString( ModuleInfo->ModuleName, mi->ModuleName, sizeof(ModuleInfo->ModuleName));
|
|
if (mi->ImageName)
|
|
CopyStrArray(ModuleInfo->ImageName, mi->ImageName);
|
|
if (mi->LoadedImageName)
|
|
CopyStrArray(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);
|
|
gfnSrcSrvUnloadModule(hProcess, mi->BaseOfDll);
|
|
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 LoadModule( 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;
|
|
CatString( 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.
|
|
//
|
|
if (!option(SYMOPT_IGNORE_NT_SYMPATH)) {
|
|
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;
|
|
|
|
if (!option(SYMOPT_IGNORE_NT_SYMPATH)) {
|
|
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;
|
|
|
|
}
|
|
|
|
symsrvClose();
|
|
|
|
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, (PGET_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,
|
|
(PGET_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)
|
|
return error(ERROR_INVALID_PARAMETER);
|
|
|
|
pe = FindProcessEntry( hProcess );
|
|
if (!pe)
|
|
return error(ERROR_INVALID_PARAMETER);
|
|
|
|
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)
|
|
return error(ERROR_INVALID_PARAMETER);
|
|
|
|
pe = FindProcessEntry( hProcess );
|
|
if (!pe)
|
|
return error(ERROR_INVALID_PARAMETER);
|
|
|
|
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;
|
|
mi->vssi.MaxNameLen = 2048;
|
|
mi->cGlobals = -1;
|
|
mi->SymType = SymDeferred;
|
|
}
|
|
|
|
|
|
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, DIMA(wMod32->ModuleName)))
|
|
return false;
|
|
|
|
if (!wcs2ansi(wMod32->ImageName, aMod32->ImageName, DIMA(wMod32->ImageName)))
|
|
return false;
|
|
|
|
if (!wcs2ansi(wMod32->LoadedImageName, aMod32->LoadedImageName, DIMA(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;
|
|
|
|
if (aMod64->SizeOfStruct < sizeof(IMAGEHLP_MODULE64))
|
|
return true;
|
|
|
|
if (!ansi2wcs(aMod64->LoadedPdbName, wMod64->LoadedPdbName, 256))
|
|
return false;
|
|
|
|
wMod64->CVSig = aMod64->CVSig;
|
|
|
|
if (!ansi2wcs(aMod64->CVData, wMod64->CVData, MAX_PATH * 3))
|
|
return false;
|
|
|
|
wMod64->PdbSig = aMod64->PdbSig;
|
|
memcpy(&wMod64->PdbSig70, &aMod64->PdbSig70, sizeof(GUID));
|
|
wMod64->PdbAge = aMod64->PdbAge;
|
|
wMod64->PdbUnmatched = aMod64->PdbUnmatched;
|
|
wMod64->DbgUnmatched = aMod64->DbgUnmatched;
|
|
wMod64->LineNumbers = aMod64->LineNumbers;
|
|
wMod64->GlobalSymbols = aMod64->GlobalSymbols;
|
|
wMod64->TypeInfo = aMod64->TypeInfo;
|
|
|
|
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, DIMA(wMod64->ModuleName)))
|
|
return false;
|
|
|
|
if (!wcs2ansi(wMod64->ImageName, aMod64->ImageName, DIMA(wMod64->ImageName)))
|
|
return false;
|
|
|
|
if (!wcs2ansi(wMod64->LoadedImageName, aMod64->LoadedImageName, DIMA(wMod64->LoadedImageName)))
|
|
return false;
|
|
|
|
return true;
|
|
}
|
|
|
|
BOOL
|
|
IMAGEAPI
|
|
SymAddSymbol(
|
|
IN HANDLE hProcess,
|
|
IN ULONG64 BaseOfDll,
|
|
IN PCSTR Name,
|
|
IN DWORD64 Address,
|
|
IN DWORD Size,
|
|
IN DWORD Flags
|
|
)
|
|
{
|
|
PPROCESS_ENTRY pe;
|
|
PMODULE_ENTRY mi;
|
|
PSYMBOL_ENTRY psym;
|
|
|
|
if (!Name || !*Name || !Address)
|
|
return error(ERROR_INVALID_PARAMETER);
|
|
|
|
__try {
|
|
|
|
pe = FindProcessEntry(hProcess);
|
|
if (!pe)
|
|
return error(ERROR_INVALID_HANDLE);
|
|
|
|
mi = GetModuleForPC(pe, Address, false);
|
|
if (!mi)
|
|
return error(ERROR_MOD_NOT_FOUND);
|
|
|
|
if (!LoadSymbols(hProcess, mi, 0))
|
|
return error(ERROR_MOD_NOT_FOUND);
|
|
|
|
return vsAddSymbol(mi, Name, Address, Size);
|
|
|
|
} __except (EXCEPTION_EXECUTE_HANDLER) {
|
|
|
|
ImagepSetLastErrorFromStatus(GetExceptionCode());
|
|
return false;
|
|
}
|
|
|
|
return true;
|
|
}
|
|
|
|
|
|
BOOL
|
|
IMAGEAPI
|
|
SymDeleteSymbol(
|
|
IN HANDLE hProcess,
|
|
IN ULONG64 BaseOfDll,
|
|
IN PCSTR Name,
|
|
IN DWORD64 Address,
|
|
IN DWORD Flags
|
|
)
|
|
{
|
|
PPROCESS_ENTRY pe;
|
|
PMODULE_ENTRY mi;
|
|
PSYMBOL_ENTRY psym;
|
|
|
|
__try {
|
|
|
|
pe = FindProcessEntry(hProcess);
|
|
if (!pe)
|
|
return error(ERROR_INVALID_HANDLE);
|
|
|
|
mi = GetModuleForPC(pe, Address, false);
|
|
if (!mi)
|
|
return error(ERROR_MOD_NOT_FOUND);
|
|
|
|
if (!LoadSymbols(hProcess, mi, LS_JUST_TEST))
|
|
return error(ERROR_MOD_NOT_FOUND);
|
|
|
|
return vsDeleteSymbol(mi, Name, Address);
|
|
|
|
} __except (EXCEPTION_EXECUTE_HANDLER) {
|
|
|
|
ImagepSetLastErrorFromStatus(GetExceptionCode());
|
|
return false;
|
|
}
|
|
|
|
return true;
|
|
}
|
|
|
|
|
|
BOOL
|
|
IMAGEAPI
|
|
SymFromAddr(
|
|
IN HANDLE hProcess,
|
|
IN DWORD64 Address,
|
|
OUT PDWORD64 Displacement,
|
|
IN OUT PSYMBOL_INFO Symbol
|
|
)
|
|
{
|
|
PSYMBOL_INFO si;
|
|
|
|
si = SympGetSymFromAddr(hProcess, Address, Displacement);
|
|
if (!si)
|
|
return false;
|
|
|
|
si2si(Symbol, si);
|
|
|
|
return true;
|
|
}
|
|
|
|
|
|
BOOL
|
|
IMAGEAPI
|
|
SymFromAddrByTag(
|
|
IN HANDLE hProcess,
|
|
IN DWORD64 Address,
|
|
IN DWORD SymTag,
|
|
OUT PDWORD64 Displacement,
|
|
IN OUT PSYMBOL_INFO Symbol
|
|
)
|
|
{
|
|
PPROCESS_ENTRY pe;
|
|
PMODULE_ENTRY mi;
|
|
PSYMBOL_INFO si;
|
|
|
|
__try {
|
|
|
|
pe = FindProcessEntry(hProcess);
|
|
if (!pe)
|
|
return error(ERROR_INVALID_HANDLE);
|
|
|
|
mi = GetModuleForPC(pe, Address, false);
|
|
if (!mi)
|
|
return error(ERROR_MOD_NOT_FOUND);
|
|
|
|
if (!LoadSymbols(hProcess, mi, 0))
|
|
return error(ERROR_MOD_NOT_FOUND);
|
|
|
|
si = GetSymFromAddrByTag(Address, SymTag, Displacement, mi);
|
|
if (!si)
|
|
return error(ERROR_INVALID_ADDRESS);
|
|
|
|
} __except (EXCEPTION_EXECUTE_HANDLER) {
|
|
|
|
ImagepSetLastErrorFromStatus(GetExceptionCode());
|
|
return false;
|
|
|
|
}
|
|
|
|
si2si(Symbol, si);
|
|
|
|
return true;
|
|
}
|
|
|
|
|
|
BOOL
|
|
IMAGEAPI
|
|
SymFromToken(
|
|
IN HANDLE hProcess,
|
|
IN DWORD64 Base,
|
|
IN DWORD Token,
|
|
IN OUT PSYMBOL_INFO Symbol
|
|
)
|
|
{
|
|
PPROCESS_ENTRY pe;
|
|
PMODULE_ENTRY mi;
|
|
PSYMBOL_INFO si;
|
|
|
|
__try {
|
|
|
|
pe = FindProcessEntry(hProcess);
|
|
if (!pe)
|
|
return error(ERROR_INVALID_HANDLE);
|
|
|
|
mi = GetModuleForPC(pe, Base, false);
|
|
if (!mi)
|
|
return error(ERROR_MOD_NOT_FOUND);
|
|
|
|
if (!LoadSymbols(hProcess, mi, 0))
|
|
return error(ERROR_MOD_NOT_FOUND);
|
|
|
|
si = GetSymFromToken(mi, Token);
|
|
if (!si)
|
|
return error(ERROR_INVALID_ADDRESS);
|
|
|
|
} __except (EXCEPTION_EXECUTE_HANDLER) {
|
|
|
|
ImagepSetLastErrorFromStatus(GetExceptionCode());
|
|
return false;
|
|
|
|
}
|
|
|
|
si2si(Symbol, si);
|
|
|
|
return true;
|
|
}
|
|
|
|
|
|
BOOL
|
|
IMAGEAPI
|
|
SymFromName(
|
|
IN HANDLE hProcess,
|
|
IN LPSTR Name,
|
|
OUT PSYMBOL_INFO Symbol
|
|
)
|
|
{
|
|
SYMBOL_ENTRY sym;
|
|
PSYMBOL_INFO si;
|
|
|
|
si = SympGetSymFromName(hProcess, Name);
|
|
if (!si)
|
|
return false;
|
|
|
|
si2si(Symbol, si);
|
|
|
|
return true;
|
|
}
|
|
|
|
|
|
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
|
|
SymEnumSymbolsByTag(
|
|
IN HANDLE hProcess,
|
|
IN ULONG64 BaseOfDll,
|
|
IN DWORD SymTag,
|
|
IN PCSTR Mask,
|
|
IN DWORD Options,
|
|
IN PSYM_ENUMERATESYMBOLS_CALLBACK EnumSymbolsCallback,
|
|
IN PVOID UserContext
|
|
)
|
|
{
|
|
PPROCESS_ENTRY pe;
|
|
PLIST_ENTRY Next;
|
|
PMODULE_ENTRY mi;
|
|
DWORD i;
|
|
PSYMBOL_ENTRY sym;
|
|
char buf[2500];
|
|
LPSTR p;
|
|
CHAR modmask[200];
|
|
BOOL rc;
|
|
int pass;
|
|
BOOL fCase;
|
|
PSYMBOL_INFO si;
|
|
char match[MAX_SYM_NAME + 100];
|
|
|
|
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) {
|
|
// search is scoped to current scope
|
|
rc = diaGetSymbolsByTag(pe,
|
|
NULL,
|
|
Mask,
|
|
0,
|
|
SymTag,
|
|
(PROC)EnumSymbolsCallback,
|
|
UserContext,
|
|
false,
|
|
false,
|
|
Options);
|
|
if (!rc && pe->ipmi && pe->ipmi->code == ERROR_CANCELLED) {
|
|
pe->ipmi->code = 0;
|
|
return true;
|
|
}
|
|
return rc;
|
|
}
|
|
|
|
if (Mask && *Mask)
|
|
PrepRE4Srch(Mask, match);
|
|
else
|
|
*match = 0;
|
|
|
|
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])) {
|
|
if (GetLastError() == ERROR_CANCELLED)
|
|
return false;
|
|
continue;
|
|
}
|
|
|
|
if (mi->dia) {
|
|
rc = diaGetSymbolsByTag(pe,
|
|
mi,
|
|
Mask,
|
|
0,
|
|
SymTag,
|
|
(PROC)EnumSymbolsCallback,
|
|
UserContext,
|
|
false,
|
|
false,
|
|
Options);
|
|
}
|
|
|
|
if (mi->numsyms) {
|
|
fCase = option(SYMOPT_CASE_INSENSITIVE) ? false : true;
|
|
|
|
si = (PSYMBOL_INFO)buf;
|
|
ZeroMemory(buf, sizeof(buf));
|
|
si->MaxNameLen = sizeof(buf) - sizeof(SYMBOL_INFO);
|
|
|
|
for (i = 0; i < mi->numsyms; i++) {
|
|
sym = &mi->symbolTable[i];
|
|
if (*match && strcmpre(sym->Name, match, fCase))
|
|
continue;
|
|
se2si(sym, si);
|
|
si->ModBase = mi->BaseOfDll;
|
|
if (!DoEnumCallback(
|
|
pe,
|
|
si,
|
|
si->Size,
|
|
(PROC)EnumSymbolsCallback,
|
|
UserContext,
|
|
false,
|
|
false)) {
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
rc = vsEnumSymbols(pe,
|
|
mi,
|
|
Mask,
|
|
(PROC)EnumSymbolsCallback,
|
|
UserContext,
|
|
false,
|
|
false);
|
|
if (!rc) {
|
|
if (mi->code == ERROR_CANCELLED) {
|
|
mi->code = 0;
|
|
return true;
|
|
}
|
|
return rc;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
} __except (EXCEPTION_EXECUTE_HANDLER) {
|
|
|
|
ImagepSetLastErrorFromStatus( GetExceptionCode() );
|
|
return false;
|
|
|
|
}
|
|
|
|
return true;
|
|
}
|
|
|
|
|
|
BOOL
|
|
IMAGEAPI
|
|
SymEnumObjs(
|
|
IN HANDLE hProcess,
|
|
IN ULONG64 BaseOfDll,
|
|
IN PCSTR Mask,
|
|
IN PSYM_ENUMERATESYMBOLS_CALLBACK EnumSymbolsCallback,
|
|
IN PVOID UserContext
|
|
)
|
|
{
|
|
return SymEnumSymbolsByTag(hProcess, BaseOfDll, SymTagCompiland, Mask, 0, EnumSymbolsCallback, UserContext);
|
|
}
|
|
|
|
|
|
BOOL
|
|
EnumSymForAddr(
|
|
IN PPROCESS_ENTRY pe,
|
|
IN PMODULE_ENTRY mi,
|
|
IN DWORD64 Address,
|
|
IN PROC EnumSymbolsCallback,
|
|
IN PVOID UserContext,
|
|
IN BOOL Use64,
|
|
IN BOOL CallBackUsesUnicode
|
|
)
|
|
{
|
|
PLIST_ENTRY Next;
|
|
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 {
|
|
|
|
if (mi->dia) {
|
|
rc = diaEnumSymForAddr(pe,
|
|
mi,
|
|
Address,
|
|
EnumSymbolsCallback,
|
|
UserContext,
|
|
Use64,
|
|
CallBackUsesUnicode);
|
|
if (rc)
|
|
rc = vsEnumSymbolsForAddr(pe,
|
|
mi,
|
|
Address,
|
|
EnumSymbolsCallback,
|
|
UserContext,
|
|
Use64,
|
|
CallBackUsesUnicode);
|
|
if (!rc) {
|
|
if (mi->code == ERROR_CANCELLED) {
|
|
mi->code = 0;
|
|
return true;
|
|
}
|
|
return rc;
|
|
}
|
|
return rc;
|
|
}
|
|
|
|
fCase = option(SYMOPT_CASE_INSENSITIVE) ? false : true;
|
|
|
|
for (i = 0; i < mi->numsyms; i++) {
|
|
PSYMBOL_INFO SymInfo = (PSYMBOL_INFO) &Buffer[0];
|
|
|
|
sym = &mi->symbolTable[i];
|
|
|
|
if (sym->Address != Address)
|
|
continue;
|
|
|
|
mi->TmpSym.Name[0] = 0;
|
|
CatString( mi->TmpSym.Name, sym->Name, TMP_SYM_LEN );
|
|
SymEntry = *sym;
|
|
SymEntry.Name = mi->TmpSym.Name;
|
|
|
|
SymInfo->MaxNameLen = sizeof(Buffer) - sizeof(SYMBOL_INFO);
|
|
|
|
se2si(&SymEntry, SymInfo);
|
|
SymInfo->ModBase = mi->BaseOfDll;
|
|
|
|
if (!DoEnumCallback(
|
|
pe,
|
|
SymInfo,
|
|
sym->Size,
|
|
EnumSymbolsCallback,
|
|
UserContext,
|
|
Use64,
|
|
CallBackUsesUnicode)) {
|
|
return true;
|
|
}
|
|
}
|
|
|
|
rc = vsEnumSymbolsForAddr(pe,
|
|
mi,
|
|
Address,
|
|
EnumSymbolsCallback,
|
|
UserContext,
|
|
Use64,
|
|
CallBackUsesUnicode);
|
|
if (!rc) {
|
|
if (mi->code == ERROR_CANCELLED) {
|
|
mi->code = 0;
|
|
return true;
|
|
}
|
|
return rc;
|
|
}
|
|
|
|
return true;
|
|
|
|
} __except (EXCEPTION_EXECUTE_HANDLER) {
|
|
|
|
ImagepSetLastErrorFromStatus( GetExceptionCode() );
|
|
return false;
|
|
|
|
}
|
|
|
|
return true;
|
|
}
|
|
|
|
BOOL
|
|
IMAGEAPI
|
|
SymEnumSymbolsForAddr(
|
|
IN HANDLE hProcess,
|
|
IN DWORD64 Address,
|
|
IN PSYM_ENUMERATESYMBOLS_CALLBACK EnumSymbolsCallback,
|
|
IN PVOID UserContext
|
|
)
|
|
{
|
|
PPROCESS_ENTRY pe;
|
|
PMODULE_ENTRY mi;
|
|
|
|
__try {
|
|
|
|
pe = FindProcessEntry( hProcess );
|
|
if (!pe)
|
|
return error( ERROR_INVALID_HANDLE );
|
|
|
|
mi = GetModuleForPC( pe, Address, false );
|
|
if (!mi)
|
|
return error( ERROR_MOD_NOT_FOUND );
|
|
|
|
if (!LoadSymbols(hProcess, mi, 0))
|
|
return error( ERROR_MOD_NOT_FOUND );
|
|
|
|
return EnumSymForAddr(pe,
|
|
mi,
|
|
Address,
|
|
(PROC) EnumSymbolsCallback,
|
|
UserContext,
|
|
false,
|
|
false);
|
|
|
|
} __except (EXCEPTION_EXECUTE_HANDLER) {
|
|
|
|
ImagepSetLastErrorFromStatus( GetExceptionCode() );
|
|
return false;
|
|
|
|
}
|
|
|
|
return true;
|
|
}
|
|
|
|
|
|
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)
|
|
return error( ERROR_INVALID_HANDLE );
|
|
|
|
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;
|
|
}
|
|
|
|
if (!LoadSymbols(hProcess, mi, 0))
|
|
return error(ERROR_MOD_NOT_FOUND);
|
|
|
|
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)
|
|
return error( ERROR_INVALID_HANDLE );
|
|
|
|
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)
|
|
return error( ERROR_NOT_ENOUGH_MEMORY );
|
|
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;
|
|
} else {
|
|
return false;
|
|
}
|
|
}
|
|
|
|
if (!LoadSymbols(hProcess, mi, 0))
|
|
return error(ERROR_MOD_NOT_FOUND);
|
|
|
|
if (diaGetTiForUDT(mi, Name, Symbol)) {
|
|
return true;
|
|
} else {
|
|
return false;
|
|
}
|
|
|
|
return false;
|
|
}
|
|
|
|
BOOL
|
|
strcmpre(
|
|
PCSTR pStr,
|
|
PCSTR pRE,
|
|
BOOL fCase
|
|
)
|
|
{
|
|
DWORD rc;
|
|
WCHAR wstr[MAX_SYM_NAME + 2];
|
|
WCHAR wre[MAX_SYM_NAME + 100];
|
|
|
|
ansi2wcs(pStr, wstr, MAX_SYM_NAME + 2);
|
|
ansi2wcs(pRE, wre, MAX_SYM_NAME + 100);
|
|
|
|
rc = CompareRE(wstr, wre, fCase);
|
|
if (rc == S_OK)
|
|
return false;
|
|
|
|
return true;
|
|
}
|
|
|
|
|
|
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)
|
|
return error(ERROR_INVALID_PARAMETER);
|
|
|
|
__try {
|
|
|
|
pe = FindProcessEntry(hProcess);
|
|
if (!pe)
|
|
return error( ERROR_INVALID_HANDLE );
|
|
|
|
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])) {
|
|
if (GetLastError() == ERROR_CANCELLED)
|
|
return false;
|
|
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 = option(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(
|
|
PCSTR 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;
|
|
}
|
|
|
|
|
|
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
|