Files
sigmaker-ida/idasdk76/plugins/pdb/old.cpp
2021-10-31 21:20:46 +02:00

203 lines
6.0 KiB
C++

// Old interface to PDB files
// It is used as a fallback method if DIA interface fails
#include <windows.h>
#pragma pack(push, 8)
#include "cvconst.h"
#include "dbghelp.h"
#pragma pack(pop)
#include <ida.hpp>
#include <idp.hpp>
#include <err.h>
#include "oldpdb.h"
//----------------------------------------------------------------------
typedef DWORD IMAGEAPI SymSetOptions_t(IN DWORD SymOptions);
typedef BOOL IMAGEAPI SymInitialize_t(IN HANDLE hProcess, IN LPCSTR UserSearchPath, IN BOOL fInvadeProcess);
typedef DWORD64 IMAGEAPI SymLoadModule64_t(IN HANDLE hProcess, IN HANDLE hFile, IN PSTR ImageName, IN PSTR ModuleName, IN DWORD64 BaseOfDll, IN DWORD SizeOfDll);
typedef BOOL IMAGEAPI SymEnumSymbols_t(IN HANDLE hProcess, IN ULONG64 BaseOfDll, IN PCSTR Mask, IN PSYM_ENUMERATESYMBOLS_CALLBACK EnumSymbolsCallback, IN PVOID UserContext);
typedef BOOL IMAGEAPI SymUnloadModule64_t(IN HANDLE hProcess, IN DWORD64 BaseOfDll);
typedef BOOL IMAGEAPI SymCleanup_t(IN HANDLE hProcess);
static HINSTANCE dbghelp = NULL;
static SymSetOptions_t *pSymSetOptions = NULL;
static SymInitialize_t *pSymInitialize = NULL;
static SymLoadModule64_t *pSymLoadModule64 = NULL;
static SymEnumSymbols_t *pSymEnumSymbols = NULL;
static SymUnloadModule64_t *pSymUnloadModule64 = NULL;
static SymCleanup_t *pSymCleanup = NULL;
static int symbols_found = 0;
//----------------------------------------------------------------------
// Dynamically load and link to DBGHELP or IMAGEHLP libraries
// Return: success
static bool setup_pointers(bool *must_free)
{
char dll[QMAXPATH];
// check if it's already loaded
dbghelp = GetModuleHandle("dbghelp.dll");
*must_free = false;
if ( dbghelp == NULL )
{
// nope, load it
// use search_path to avoid dll current directory attacks
if ( !search_path(dll, sizeof(dll), "dbghelp.dll", false) )
return false;
dbghelp = LoadLibrary(dll);
*must_free = true;
}
if ( dbghelp == NULL )
{
deb(IDA_DEBUG_DBGINFO, "PDB plugin: failed to load DBGHELP.DLL");
}
else
{
*(FARPROC*)&pSymSetOptions = GetProcAddress(dbghelp, "SymSetOptions");
*(FARPROC*)&pSymInitialize = GetProcAddress(dbghelp, "SymInitialize");
*(FARPROC*)&pSymLoadModule64 = GetProcAddress(dbghelp, "SymLoadModule64");
*(FARPROC*)&pSymEnumSymbols = GetProcAddress(dbghelp, "SymEnumSymbols");
*(FARPROC*)&pSymUnloadModule64 = GetProcAddress(dbghelp, "SymUnloadModule64");
*(FARPROC*)&pSymCleanup = GetProcAddress(dbghelp, "SymCleanup");
if ( pSymSetOptions != NULL
&& pSymInitialize != NULL
&& pSymLoadModule64 != NULL
&& pSymUnloadModule64 != NULL
&& pSymCleanup != NULL
&& pSymEnumSymbols != NULL ) // required XP or higher
{
return true;
}
}
deb(IDA_DEBUG_DBGINFO, "PDB plugin: Essential DBGHELP.DLL functions are missing\n");
if ( dbghelp != NULL )
{
FreeLibrary(dbghelp);
dbghelp = NULL;
}
return false;
}
//----------------------------------------------------------------------
// New method: symbol enumeration callback
//lint -e{818} could be declared as pointing to const
static BOOL CALLBACK EnumerateSymbolsProc(
PSYMBOL_INFO psym,
ULONG /*SymbolSize*/,
PVOID delta)
{
symbols_found++;
ea_t ea = (ea_t)(psym->Address + *(adiff_t*)delta);
const char *name = psym->Name;
int maybe_func = 0; // maybe
switch ( psym->Tag )
{
case SymTagFunction:
case SymTagThunk:
maybe_func = 1;
break;
case SymTagNull:
case SymTagExe:
case SymTagCompiland:
case SymTagCompilandDetails:
case SymTagCompilandEnv:
case SymTagData:
case SymTagAnnotation:
case SymTagUDT:
case SymTagEnum:
case SymTagFunctionType:
case SymTagPointerType:
case SymTagArrayType:
case SymTagBaseType:
case SymTagTypedef:
case SymTagBaseClass:
case SymTagFunctionArgType:
case SymTagUsingNamespace:
case SymTagVTableShape:
case SymTagVTable:
case SymTagCustom:
case SymTagCustomType:
case SymTagManagedType:
case SymTagDimension:
maybe_func = -1;
break;
case SymTagBlock:
case SymTagLabel:
case SymTagFuncDebugStart:
case SymTagFuncDebugEnd:
maybe_func = 2;
break;
case SymTagPublicSymbol:
case SymTagFriend:
default:
break;
}
bool ok = apply_name(ea, name, maybe_func);
// New dbghelp.dll/symsrv.dll files return names without the terminating zero.
// So, as soon as we have a long name, shorter names will have garbage at the end.
// Clean up the name to avoid problems.
size_t len = strlen(name);
memset((void*)name, '\0', len);
return ok;
}
//----------------------------------------------------------------------
// Display a system error message
static void error_msg(const char *name)
{
int code = GetLastError();
if ( code != 0 )
msg("%s: %s\n", name, winerr(code));
}
//----------------------------------------------------------------------
// Try old method of loading symbols
bool old_pdb_plugin(ea_t loaded_base, const char *input, const char *spath)
{
bool ok = false;
bool must_free;
if ( setup_pointers(&must_free) )
{
pSymSetOptions(SYMOPT_LOAD_LINES|SYMOPT_FAVOR_COMPRESSED|SYMOPT_NO_PROMPTS);
void *fake_proc = (void *)(uintptr_t)0xBEEFFEED;
if ( !pSymInitialize(fake_proc, spath, FALSE) )
{
error_msg("SymInitialize");
}
else
{
DWORD64 symbase = pSymLoadModule64(fake_proc, 0, (char*)input, NULL, loaded_base, 0);
if ( symbase != 0 )
{
load_vc_til();
symbols_found = 0;
adiff_t delta = adiff_t(loaded_base - symbase);
ok = pSymEnumSymbols(fake_proc, symbase, NULL, EnumerateSymbolsProc, &delta)
&& symbols_found > 0;
if ( !ok )
error_msg("EnumSymbols");
if ( !pSymUnloadModule64(fake_proc, symbase) )
error_msg("SymUnloadModule64");
}
if ( !pSymCleanup(fake_proc) )
error_msg("SymCleanup");
}
if ( must_free )
{
FreeLibrary(dbghelp);
dbghelp = NULL;
}
}
return ok;
}