update to ida 7.6, add builds
This commit is contained in:
2546
idasdk76/plugins/pdb/common.cpp
Normal file
2546
idasdk76/plugins/pdb/common.cpp
Normal file
File diff suppressed because it is too large
Load Diff
3750
idasdk76/plugins/pdb/cvconst.h
Normal file
3750
idasdk76/plugins/pdb/cvconst.h
Normal file
File diff suppressed because it is too large
Load Diff
4458
idasdk76/plugins/pdb/dbghelp.h
Normal file
4458
idasdk76/plugins/pdb/dbghelp.h
Normal file
File diff suppressed because it is too large
Load Diff
7560
idasdk76/plugins/pdb/dia2.h
Normal file
7560
idasdk76/plugins/pdb/dia2.h
Normal file
File diff suppressed because it is too large
Load Diff
15
idasdk76/plugins/pdb/makefile
Normal file
15
idasdk76/plugins/pdb/makefile
Normal file
@@ -0,0 +1,15 @@
|
||||
PROC=pdb
|
||||
CONFIGS=pdb.cfg
|
||||
|
||||
ifdef __NT__
|
||||
O1=old
|
||||
STDLIBS += ole32.lib
|
||||
STDLIBS += oleaut32.lib
|
||||
else
|
||||
LIBS += $(L)network$(A)
|
||||
endif
|
||||
|
||||
include ../plugin.mak
|
||||
|
||||
$(F)pdb$(O): CC_WNO-$(call gte,$(GCC_VERSION),6.1) += -Wno-null-dereference
|
||||
|
||||
40
idasdk76/plugins/pdb/misc.cpp
Normal file
40
idasdk76/plugins/pdb/misc.cpp
Normal file
@@ -0,0 +1,40 @@
|
||||
|
||||
//----------------------------------------------------------------------
|
||||
static const char *symtag_to_string(uint32 tag)
|
||||
{
|
||||
static const char *const names[] =
|
||||
{
|
||||
"Null",
|
||||
"Exe",
|
||||
"Compiland",
|
||||
"CompilandDetails",
|
||||
"CompilandEnv",
|
||||
"Function",
|
||||
"Block",
|
||||
"Data",
|
||||
"Annotation",
|
||||
"Label",
|
||||
"PublicSymbol",
|
||||
"UDT",
|
||||
"Enum",
|
||||
"FunctionType",
|
||||
"PointerType",
|
||||
"ArrayType",
|
||||
"BaseType",
|
||||
"Typedef",
|
||||
"BaseClass",
|
||||
"Friend",
|
||||
"FunctionArgType",
|
||||
"FuncDebugStart",
|
||||
"FuncDebugEnd",
|
||||
"UsingNamespace",
|
||||
"VTableShape",
|
||||
"VTable",
|
||||
"Custom",
|
||||
"Thunk",
|
||||
"CustomType",
|
||||
"ManagedType",
|
||||
"Dimension"
|
||||
};
|
||||
return tag < qnumber(names) ? names[tag] : "???";
|
||||
}
|
||||
1150
idasdk76/plugins/pdb/msdia.cpp
Normal file
1150
idasdk76/plugins/pdb/msdia.cpp
Normal file
File diff suppressed because it is too large
Load Diff
81
idasdk76/plugins/pdb/msdia.hpp
Normal file
81
idasdk76/plugins/pdb/msdia.hpp
Normal file
@@ -0,0 +1,81 @@
|
||||
|
||||
#ifndef MSDIA_HPP
|
||||
#define MSDIA_HPP
|
||||
|
||||
#include "pdbaccess.hpp"
|
||||
#include "pdblocal.hpp"
|
||||
|
||||
//----------------------------------------------------------------------------
|
||||
struct pdb_session_t
|
||||
{
|
||||
HMODULE dia_hmod;
|
||||
int refcount;
|
||||
local_pdb_access_t *pdb_access;
|
||||
|
||||
pdb_session_t()
|
||||
: dia_hmod(NULL),
|
||||
refcount(1),
|
||||
pdb_access(NULL),
|
||||
pSource(NULL)
|
||||
{
|
||||
session_count++;
|
||||
}
|
||||
~pdb_session_t();
|
||||
|
||||
HRESULT open_session(const pdbargs_t &pdbargs);
|
||||
void close();
|
||||
const char *get_used_fname() const { return used_fname.begin(); }
|
||||
|
||||
private:
|
||||
DECLARE_UNCOPYABLE(pdb_session_t)
|
||||
HRESULT create_dia_source(int *dia_version);
|
||||
|
||||
IDiaDataSource *pSource;
|
||||
qwstring winput;
|
||||
qwstring wspath;
|
||||
enum load_data_type_t
|
||||
{
|
||||
EXE_LOCAL,
|
||||
MEM_LOCAL, // PDB_PLUGIN
|
||||
EXE_WIN32, // PDB_WIN32_SERVER
|
||||
MEM_WIN32, // PDB_WIN32_SERVER
|
||||
};
|
||||
HRESULT load_data_for_exe(const pdbargs_t &pdbargs, load_data_type_t type);
|
||||
HRESULT load_input_path(const pdbargs_t &pdbargs, const char *input_path);
|
||||
|
||||
// The total number of different PDB sessions; kept track of
|
||||
// in order to know when we can safely CoUninitialize().
|
||||
static int session_count;
|
||||
|
||||
// Whether COM is initialized in this thread.
|
||||
static bool co_initialized;
|
||||
#ifdef _DEBUG
|
||||
public:
|
||||
qstring _pdb_path;
|
||||
#endif
|
||||
qstring used_fname;
|
||||
};
|
||||
|
||||
|
||||
//----------------------------------------------------------------------------
|
||||
class pdb_session_ref_t
|
||||
{
|
||||
public:
|
||||
pdb_session_t *session; // refcounted object
|
||||
|
||||
pdb_session_ref_t(void) : session(NULL) {}
|
||||
pdb_session_ref_t(const pdb_session_ref_t &r);
|
||||
~pdb_session_ref_t();
|
||||
|
||||
pdb_session_ref_t &operator=(const pdb_session_ref_t &r);
|
||||
void create_session();
|
||||
void close();
|
||||
bool empty() const { return session == NULL; }
|
||||
bool opened() const { return !empty() && session->pdb_access != NULL; }
|
||||
HRESULT open_session(const pdbargs_t &args);
|
||||
};
|
||||
|
||||
//----------------------------------------------------------------------------
|
||||
const char *pdberr(int code);
|
||||
|
||||
#endif
|
||||
202
idasdk76/plugins/pdb/old.cpp
Normal file
202
idasdk76/plugins/pdb/old.cpp
Normal file
@@ -0,0 +1,202 @@
|
||||
|
||||
// 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;
|
||||
}
|
||||
9
idasdk76/plugins/pdb/oldpdb.h
Normal file
9
idasdk76/plugins/pdb/oldpdb.h
Normal file
@@ -0,0 +1,9 @@
|
||||
|
||||
// Common definitions for the old and new pdb plugins
|
||||
|
||||
// helper functions provided by the new pdb plugin
|
||||
bool apply_name(ea_t ea, const qstring &name, int maybe_func);
|
||||
void load_vc_til(void);
|
||||
|
||||
// entry point of the old pdb plugin
|
||||
bool old_pdb_plugin(ea_t loaded_base, const char *input, const char *spath);
|
||||
47
idasdk76/plugins/pdb/pdb.cfg
Normal file
47
idasdk76/plugins/pdb/pdb.cfg
Normal file
@@ -0,0 +1,47 @@
|
||||
// PDB plugin
|
||||
|
||||
// PDB information provider
|
||||
#define PDB_PROVIDER_MSDIA 1 // use MSDIA local/remote provider
|
||||
#define PDB_PROVIDER_PDBIDA 2 // use PDBIDA provider
|
||||
//PDB_PROVIDER = PDB_PROVIDER_PDBIDA
|
||||
|
||||
// it is possible to specify the desired provider in the command line:
|
||||
// ida -Opdb:off input_file
|
||||
// ida -Opdb:msdia input_file
|
||||
// ida -Opdb:pdbida input_file
|
||||
|
||||
// Symbol search path
|
||||
// The _NT_SYMBOL_PATH environment variable overrides this setting.
|
||||
// If none of these variables is set then the default value will be used:
|
||||
// "SRV*CACHEDIR*http://msdl.microsoft.com/download/symbols"
|
||||
// where
|
||||
// CACHEDIR=%TEMP%\ida for Windows
|
||||
// CACHEDIR=$TMPDIR/ida or $TMP/ida or /tmp/ida for non-Windows OSes
|
||||
//
|
||||
//_NT_SYMBOL_PATH = "SRV*c:\\symbols*http://symbols.mozilla.org/firefox;SRV*c:\\symbols*http://msdl.microsoft.com/download/symbols";
|
||||
|
||||
// Network communications while looking for PDB file can be restricted.
|
||||
// Valid only for PDBIDA provider.
|
||||
#define PDB_NETWORK_OFF 0 // local directories search only
|
||||
#define PDB_NETWORK_PE 1 // local directories search for COFF, full search for PE
|
||||
#define PDB_NETWORK_ON 2 // no restrictions
|
||||
//PDB_NETWORK = PDB_NETWORK_PE
|
||||
|
||||
// PDBIDA is able to load MSF 7.0 PDB files only.
|
||||
// MSDIA can load all PDB files, including old MSF 2.0 files.
|
||||
// If you set the following option to YES, IDA will automatically switch
|
||||
// to MSDIA for old files.
|
||||
// Please note that under Linux/macOS the MSDIA provider requires you to configure
|
||||
// the win32_remote.exe server because it can run only on Windows.
|
||||
// It is possible to specify the desired behavior in the command line:
|
||||
// ida -Opdb:fallback input_file
|
||||
// ida -Opdb:nofallback input_file
|
||||
PDB_MSDIA_FALLBACK = NO
|
||||
|
||||
// remote server where win32_remote.exe is running
|
||||
// used when loading PDB symbols on non-Windows platforms
|
||||
// NB: it will be used only if there is not already an existing debugging session started
|
||||
PDB_REMOTE_SERVER = "localhost";
|
||||
PDB_REMOTE_PORT = 23946
|
||||
// password for the remote server
|
||||
PDB_REMOTE_PASSWD = "";
|
||||
1414
idasdk76/plugins/pdb/pdb.cpp
Normal file
1414
idasdk76/plugins/pdb/pdb.cpp
Normal file
File diff suppressed because it is too large
Load Diff
217
idasdk76/plugins/pdb/pdb.hpp
Normal file
217
idasdk76/plugins/pdb/pdb.hpp
Normal file
@@ -0,0 +1,217 @@
|
||||
//
|
||||
// Copyright (c) 2005-2021 Hex-Rays SA <support@hex-rays.com>
|
||||
// ALL RIGHTS RESERVED.
|
||||
//
|
||||
#pragma once
|
||||
#include <idp.hpp>
|
||||
#include <idd.hpp>
|
||||
#include <typeinf.hpp>
|
||||
#include "../../ldr/pe/pe.h"
|
||||
|
||||
#define PDB_NODE_NAME "$ pdb"
|
||||
#define PDB_DLLBASE_NODE_IDX 0
|
||||
#define PDB_DLLNAME_NODE_IDX 0
|
||||
#define PDB_LOADING_WIN32_DBG 1
|
||||
#define PDB_TYPESONLY_NODE_IDX 2
|
||||
|
||||
enum pdb_callcode_t
|
||||
{
|
||||
// user invoked 'load pdb' command, load pdb for the input file.
|
||||
// after invocation, result (boolean) is stored in: netnode(PDB_NODE_NAME).altval(PDB_DLLBASE_NODE_IDX)
|
||||
PDB_CC_USER = 0,
|
||||
// ida decided to call the plugin itself
|
||||
PDB_CC_IDA = 1,
|
||||
// load additional pdb. This is semantically the same as
|
||||
// PDB_CC_USER (i.e., "File > Load file > PDB file..."), except
|
||||
// it won't ask the user for the data; rather it expects it in
|
||||
// netnode(PDB_NODE_NAME):
|
||||
// load_addr: netnode(PDB_NODE_NAME).altval(PDB_DLLBASE_NODE_IDX)
|
||||
// dll_name: netnode(PDB_NODE_NAME).supstr(PDB_DLLNAME_NODE_IDX)
|
||||
PDB_CC_USER_WITH_DATA = 3,
|
||||
// load debug info from the COFF file
|
||||
// ida decided to call the plugin itself
|
||||
// dbginfo_params_t: netnode(DBGINFO_PARAM_NODE_NAME).supval(DBGINFO_PARAMS_KEY)
|
||||
PDB_CC_IDA_COFF = 4,
|
||||
};
|
||||
|
||||
//----------------------------------------------------------------------
|
||||
struct pdb_signature_t
|
||||
{
|
||||
uint32 guid[4]; // if all zeroes, then consider as non-existing
|
||||
uint32 sig;
|
||||
uint32 age;
|
||||
pdb_signature_t(void) { memset(this, 0, sizeof(*this)); }
|
||||
};
|
||||
|
||||
//----------------------------------------------------------------------------
|
||||
struct pdbargs_t
|
||||
{
|
||||
qstring pdb_path; // Path to PDB file.
|
||||
qstring input_path; // Path to PE file with associated PDB.
|
||||
pdb_signature_t pdb_sign;
|
||||
qstring spath;
|
||||
ea_t loaded_base;
|
||||
void *user_data;
|
||||
uint32 flags;
|
||||
#define PDBFLG_DBG_MODULE 0x0001
|
||||
#define PDBFLG_ONLY_TYPES 0x0002
|
||||
#define PDBFLG_EFD 0x0004
|
||||
#define PDBFLG_COFF_FILE 0x0008
|
||||
#define PDBFLG_USE_HTTP 0x0100
|
||||
|
||||
pdbargs_t(void)
|
||||
: loaded_base(BADADDR),
|
||||
user_data(NULL),
|
||||
flags(0)
|
||||
{}
|
||||
|
||||
// If true, we are in a debugging session and the file specified by
|
||||
// input_path is an additional module that has been loaded by the
|
||||
// debugger itself.
|
||||
bool is_dbg_module(void) const
|
||||
{
|
||||
return (flags & PDBFLG_DBG_MODULE) != 0;
|
||||
}
|
||||
// PDB?
|
||||
bool is_pdbfile(void) const { return (flags & PDBFLG_COFF_FILE) == 0; }
|
||||
bool use_http() const { return (flags & PDBFLG_USE_HTTP) != 0; }
|
||||
|
||||
const char *fname(void) const
|
||||
{
|
||||
return !pdb_path.empty() ? pdb_path.begin() : input_path.c_str();
|
||||
}
|
||||
};
|
||||
|
||||
//----------------------------------------------------------------------------
|
||||
struct pdb_ctx_t : public plugmod_t, public event_listener_t
|
||||
{
|
||||
processor_t &ph;
|
||||
|
||||
// PDB search path (in _NT_SYMBOL_PATH format)
|
||||
qstring full_sympath;
|
||||
|
||||
peheader_t pe;
|
||||
|
||||
// config options
|
||||
int pdb_remote_port = DEBUGGER_PORT_NUMBER;
|
||||
int pdb_remote_port_64 = -1;
|
||||
qstring pdb_remote_server;
|
||||
qstring pdb_remote_passwd;
|
||||
#define PDB_PROVIDER_MSDIA 1
|
||||
uint pdb_provider = PDB_PROVIDER_MSDIA;
|
||||
#define PDB_NETWORK_OFF 0 // local directories search only
|
||||
#define PDB_NETWORK_PE 1 // local directories search for COFF, full search for PE
|
||||
#define PDB_NETWORK_ON 2 // no restrictions
|
||||
uint pdb_network = PDB_NETWORK_PE;
|
||||
bool use_http(bool is_pe) const
|
||||
{
|
||||
bool ok = pdb_network == PDB_NETWORK_PE && is_pe
|
||||
|| pdb_network == PDB_NETWORK_ON;
|
||||
deb(IDA_DEBUG_DBGINFO, ok ? "PDB: symbol servers will be used\n"
|
||||
: "PDB: local directories search only\n");
|
||||
return ok;
|
||||
}
|
||||
|
||||
// Plugin options
|
||||
uint opt_provider = 0;
|
||||
// -1 don't specified
|
||||
// 0 set PDB_FALLBACK to false
|
||||
// 1 set PDB_FALLBACK to true
|
||||
int opt_fallback = -1;
|
||||
|
||||
using namelist_t = std::map<ea_t, qstring>;
|
||||
namelist_t namelist;
|
||||
|
||||
// srcinfo provider
|
||||
class pdb_provider_t *pdb_srcinfo_provider = nullptr;
|
||||
|
||||
pdb_ctx_t();
|
||||
virtual ~pdb_ctx_t();
|
||||
virtual bool idaapi run(size_t arg) override;
|
||||
virtual ssize_t idaapi on_event(ssize_t code, va_list va) override;
|
||||
|
||||
void parse_options(bool *opt_skip);
|
||||
|
||||
void init_sympaths();
|
||||
void load_vc_til(void) const;
|
||||
|
||||
// maybe_func: -1:no, 0-maybe, 1-yes, 2:no,but iscode
|
||||
bool apply_name_in_idb(ea_t ea, const qstring &name, int maybe_func, uint32 the_machine_type);
|
||||
bool apply_debug_info(pdbargs_t &pdbargs);
|
||||
|
||||
// printable register name
|
||||
bool get_pdb_register_info(int *p_reg, uint64 *p_mask, int machine, int reg);
|
||||
|
||||
// Because we need to be able to call the 'old' pdb plugin
|
||||
// code, which knows nothing about the til_builder_t (and
|
||||
// thus its 'machine_type' field, and also because, at the
|
||||
// very time we call the old pdb code, our til_builder_t
|
||||
// instance will have been long forgotten and destroyed,
|
||||
// we must keep this machine type information somewhere.
|
||||
uint32 g_machine_type = 0; // will be set to CV_CFL_80386 in ctor
|
||||
|
||||
private:
|
||||
//-------------------------------------------------------------------------
|
||||
int utf16_encidx = -1;
|
||||
int get_utf16_encoding_idx();
|
||||
|
||||
bool checked_types = false;
|
||||
bool has_sid = false;
|
||||
bool check_for_ids(ea_t ea, const char *name, bool has_typeinfo);
|
||||
|
||||
void alloc_pdb_srcinfo_provider();
|
||||
void free_pdb_srcinfo_provider();
|
||||
|
||||
public:
|
||||
//-------------------------------------------------------------------------
|
||||
//#define CHECK_CREATED_TYPES
|
||||
#ifdef CHECK_CREATED_TYPES
|
||||
struct type_to_check_t
|
||||
{
|
||||
// one of the following 3 will be valid:
|
||||
ea_t ea;
|
||||
int id;
|
||||
qstring name;
|
||||
|
||||
// the type itself
|
||||
tinfo_t type;
|
||||
};
|
||||
|
||||
qvector<type_to_check_t> types_to_check;
|
||||
int check_n = 0;
|
||||
|
||||
void check_tinfo(ea_t ea, int id, const char *name, const tinfo_t &tif)
|
||||
{
|
||||
type_to_check_t &tc = types_to_check.push_back();
|
||||
tc.ea = ea;
|
||||
tc.id = id;
|
||||
tc.name = name;
|
||||
tc.type = tif;
|
||||
}
|
||||
|
||||
void check_added_types(void)
|
||||
{
|
||||
for ( const auto &tc : types_to_check )
|
||||
{
|
||||
if ( !tc.type.is_correct() )
|
||||
{
|
||||
msg("%d: INCORRECT TYPE ", check_n);
|
||||
if ( !tc.name.empty() )
|
||||
msg("%s", tc.name.begin());
|
||||
else if ( tc.ea != BADADDR )
|
||||
msg("%a", tc.ea);
|
||||
else
|
||||
msg("#%d", tc.id);
|
||||
qstring res;
|
||||
tc.type.print(&res);
|
||||
msg(": %s\n", res.c_str());
|
||||
check_n++;
|
||||
}
|
||||
}
|
||||
}
|
||||
#else
|
||||
inline void check_tinfo(ea_t,int,const char*,const tinfo_t &) {}
|
||||
inline void check_added_types(void) {}
|
||||
#endif
|
||||
};
|
||||
extern int data_id;
|
||||
661
idasdk76/plugins/pdb/pdbaccess.hpp
Normal file
661
idasdk76/plugins/pdb/pdbaccess.hpp
Normal file
@@ -0,0 +1,661 @@
|
||||
|
||||
|
||||
#ifndef PDBACCESS__H
|
||||
#define PDBACCESS__H
|
||||
|
||||
#include <pro.h>
|
||||
#include "cvconst.h"
|
||||
|
||||
#ifdef __NT__
|
||||
#include <windows.h>
|
||||
#include <oaidl.h>
|
||||
#include "dia2.h"
|
||||
#else
|
||||
// FIXME: It'd be good if those windows declarations for non-windows
|
||||
// systems were somewhere else than in the PE loader.
|
||||
#include "../../ldr/pe/mycor.h"
|
||||
#endif
|
||||
#include "pdb.hpp"
|
||||
|
||||
//----------------------------------------------------------------------------
|
||||
class pdb_access_t;
|
||||
class local_pdb_access_t;
|
||||
class remote_pdb_access_t;
|
||||
|
||||
struct pdb_exception_t
|
||||
{
|
||||
pdb_exception_t(const qstring &_what) : what(_what) {}
|
||||
qstring what;
|
||||
};
|
||||
|
||||
//----------------------------------------------------------------------------
|
||||
#ifdef __NT__
|
||||
enum sym_token_t : uint64
|
||||
#else
|
||||
enum sym_token_t
|
||||
#endif
|
||||
{
|
||||
t_start = 1 << 0,
|
||||
// bool
|
||||
t_bool_start = t_start,
|
||||
t_constType = t_bool_start,
|
||||
t_isStatic = 1 << 1,
|
||||
t_virtual = 1 << 2,
|
||||
t_volatileType = 1 << 3,
|
||||
t_code = 1 << 4,
|
||||
t_hasAssignmentOperator = 1 << 5,
|
||||
t_hasCastOperator = 1 << 6,
|
||||
t_function = 1 << 7, // FIXME!
|
||||
t_constructor = 1 << 8,
|
||||
t_isVirtualBaseClass = 1 << 9,
|
||||
t_bool_end = t_isVirtualBaseClass,
|
||||
|
||||
// dword
|
||||
t_dword_start = 1 << 10,
|
||||
t_backEndMajor = t_dword_start,
|
||||
t_baseType = 1 << 11,
|
||||
t_bitPosition = 1 << 12,
|
||||
t_callingConvention = 1 << 13,
|
||||
t_count = 1 << 14,
|
||||
t_dataKind = 1 << 15,
|
||||
t_locationType = 1 << 16,
|
||||
t_registerId = 1 << 17,
|
||||
t_relativeVirtualAddress = 1 << 18,
|
||||
t_symIndexId = 1 << 19,
|
||||
t_symTag = 1 << 20,
|
||||
t_udtKind = 1 << 21,
|
||||
t_virtualBaseOffset = 1 << 22,
|
||||
t_machineType = 1 << 23,
|
||||
t_classParentId = 1 << 24,
|
||||
t_typeId = 1 << 25,
|
||||
t_lexicalParentId = 1 << 26,
|
||||
t_dword_end = t_lexicalParentId,
|
||||
|
||||
// dword64
|
||||
t_dword64_start = 1 << 27,
|
||||
t_length = t_dword64_start,
|
||||
t_dword64_end = t_length,
|
||||
|
||||
// string
|
||||
t_string_start = 1 << 28,
|
||||
t_name = t_string_start,
|
||||
t_string_end = t_name,
|
||||
|
||||
// long
|
||||
t_long_start = 1 << 29,
|
||||
t_offset = t_long_start,
|
||||
t_long_end = t_offset,
|
||||
|
||||
// ulonglong
|
||||
t_ulonglong_start = 1 << 30,
|
||||
t_virtualAddress = t_ulonglong_start,
|
||||
t_ulonglong_end = t_virtualAddress,
|
||||
|
||||
// variant
|
||||
t_variant_start = 1ULL << 31,
|
||||
t_value = t_variant_start,
|
||||
t_variant_end = t_value,
|
||||
|
||||
t_end = 1ULL << 32,
|
||||
};
|
||||
CASSERT(sizeof(sym_token_t) == 8);
|
||||
|
||||
inline bool is_sym_token_bool(sym_token_t t) { return t >= t_bool_start && t <= t_bool_end; }
|
||||
inline bool is_sym_token_dword(sym_token_t t) { return t >= t_dword_start && t <= t_dword_end; }
|
||||
inline bool is_sym_token_dword64(sym_token_t t) { return t >= t_dword64_start && t <= t_dword64_end; }
|
||||
// inline bool is_sym_token_pdb_sym(sym_token_t t) { return t >= t_pdb_sym_start && t <= t_pdb_sym_end; }
|
||||
inline bool is_sym_token_string(sym_token_t t) { return t >= t_string_start && t <= t_string_end; }
|
||||
inline bool is_sym_token_long(sym_token_t t) { return t >= t_long_start && t <= t_long_end; }
|
||||
inline bool is_sym_token_ulonglong(sym_token_t t) { return t >= t_ulonglong_start && t <= t_ulonglong_end; }
|
||||
inline bool is_sym_token_variant(sym_token_t t) { return t >= t_variant_start && t <= t_variant_end; } //-V560 is always true
|
||||
|
||||
|
||||
typedef uint64 token_mask_t;
|
||||
#define TOKEN_MASK_FULL token_mask_t(-1)
|
||||
|
||||
//----------------------------------------------------------------------------
|
||||
// engine PDB symbol implementation identity
|
||||
enum pdb_sym_id_t
|
||||
{
|
||||
DIA_PDB_SYM,
|
||||
REMOTE_PDB_SYM,
|
||||
OWN_PDB_SYM,
|
||||
};
|
||||
|
||||
//----------------------------------------------------------------------------
|
||||
struct pdb_sym_t
|
||||
{
|
||||
virtual HRESULT get_backEndMajor(DWORD *out) = 0;
|
||||
virtual HRESULT get_baseType(DWORD *out) = 0;
|
||||
virtual HRESULT get_bitPosition(DWORD *out) = 0;
|
||||
virtual HRESULT get_callingConvention(DWORD *out) = 0;
|
||||
virtual HRESULT get_code(BOOL *out) = 0;
|
||||
virtual HRESULT get_constructor(BOOL *out) = 0;
|
||||
virtual HRESULT get_isVirtualBaseClass(BOOL *out) = 0;
|
||||
virtual HRESULT get_constType(BOOL *out) = 0;
|
||||
virtual HRESULT get_count(DWORD *out) = 0;
|
||||
virtual HRESULT get_dataKind(DWORD *out) = 0;
|
||||
virtual HRESULT get_function(BOOL *out) = 0;
|
||||
virtual HRESULT get_hasAssignmentOperator(BOOL *out) = 0;
|
||||
virtual HRESULT get_hasCastOperator(BOOL *out) = 0;
|
||||
virtual HRESULT get_isStatic(BOOL *out) = 0;
|
||||
virtual HRESULT get_length(DWORD64 *out) = 0;
|
||||
virtual HRESULT get_lexicalParent(pdb_sym_t *out) = 0;
|
||||
virtual HRESULT get_locationType(DWORD *out) = 0;
|
||||
virtual HRESULT get_machineType(DWORD *out) = 0;
|
||||
virtual HRESULT get_name(qstring *out) = 0;
|
||||
virtual HRESULT get_offset(LONG *out) = 0;
|
||||
virtual HRESULT get_registerId(DWORD *out) = 0;
|
||||
virtual HRESULT get_relativeVirtualAddress(DWORD *out) = 0;
|
||||
virtual HRESULT get_symIndexId(DWORD *out) = 0;
|
||||
virtual HRESULT get_symTag(DWORD *out) = 0;
|
||||
virtual HRESULT get_udtKind(DWORD *out) = 0;
|
||||
virtual HRESULT get_value(VARIANT *out) = 0;
|
||||
virtual HRESULT get_virtual(BOOL *out) = 0;
|
||||
virtual HRESULT get_virtualAddress(ULONGLONG *out) = 0;
|
||||
virtual HRESULT get_virtualBaseOffset(DWORD *out) = 0;
|
||||
virtual HRESULT get_volatileType(BOOL *out) = 0;
|
||||
// Be very, very careful to _not_ use classParent if you can avoid it:
|
||||
// In case the symbol was *not* resolved through get_type(), the link
|
||||
// to the parent might be lost, and a bug in the DIA SDK will
|
||||
// return S_FALSE.
|
||||
virtual HRESULT get_classParent(pdb_sym_t *out) = 0;
|
||||
virtual HRESULT get_type(pdb_sym_t *out) = 0;
|
||||
//------------------------------------------------------------
|
||||
virtual HRESULT get_ordinal(DWORD *pRetVal) = 0;
|
||||
|
||||
// careful with this!
|
||||
virtual void steal_data(pdb_sym_t &other) = 0;
|
||||
|
||||
virtual pdb_sym_id_t whoami(void) = 0;
|
||||
virtual bool empty(void) = 0;
|
||||
|
||||
virtual ~pdb_sym_t() {}
|
||||
|
||||
// Declare, but ***don't*** define: we don't want
|
||||
// that to happen, and thus we'll have a linker
|
||||
// error if that would happen in the code.
|
||||
DECLARE_UNCOPYABLE(pdb_sym_t);
|
||||
|
||||
protected:
|
||||
pdb_sym_t() {}
|
||||
};
|
||||
DECLARE_TYPE_AS_MOVABLE(pdb_sym_t);
|
||||
|
||||
typedef janitor_t<pdb_sym_t*> pdb_sym_janitor_t;
|
||||
template <> inline pdb_sym_janitor_t::~janitor_t()
|
||||
{
|
||||
delete resource;
|
||||
resource = NULL;
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------------
|
||||
enum packing_info_t
|
||||
{
|
||||
SYMDAT_PACKED = 1,
|
||||
SYMDAT_UNPACKED
|
||||
};
|
||||
|
||||
//----------------------------------------------------------------------------
|
||||
struct sym_data_t
|
||||
{
|
||||
sym_data_t(token_mask_t _tokens, const uchar *buf, size_t bufsize, packing_info_t _packing, bool *_warned);
|
||||
~sym_data_t();
|
||||
|
||||
DWORD get_id() const
|
||||
{
|
||||
DWORD id;
|
||||
if ( get_dword(t_symIndexId, &id) != S_OK )
|
||||
INTERR(30211);
|
||||
return id;
|
||||
}
|
||||
HRESULT get_bool(sym_token_t token, BOOL *out) const;
|
||||
HRESULT get_dword(sym_token_t token, DWORD *out) const;
|
||||
HRESULT get_dword64(sym_token_t token, DWORD64 *out) const;
|
||||
HRESULT get_pdb_sym(sym_token_t token, pdb_sym_t *out) const;
|
||||
HRESULT get_string(sym_token_t token, qstring *out) const;
|
||||
HRESULT get_dword(sym_token_t token, LONG *out) const;
|
||||
HRESULT get_ulonglong(sym_token_t token, ULONGLONG *out) const;
|
||||
HRESULT get_variant(sym_token_t token, VARIANT *out) const;
|
||||
|
||||
private:
|
||||
sym_data_t();
|
||||
|
||||
bool token_present(sym_token_t token) const
|
||||
{
|
||||
return (present & token) == token;
|
||||
}
|
||||
|
||||
void assert_token(sym_token_t token) const
|
||||
{
|
||||
if ( !token_present(token) )
|
||||
INTERR(30210);
|
||||
}
|
||||
|
||||
const BOOL *bool_ptr(sym_token_t token) const
|
||||
{
|
||||
return (const BOOL *)any_ptr(token, t_bool_start, t_bool_end);
|
||||
}
|
||||
|
||||
const DWORD *dword_ptr(sym_token_t token) const
|
||||
{
|
||||
return (const DWORD *)any_ptr(token, t_dword_start, t_dword_end);
|
||||
}
|
||||
|
||||
const DWORD64 *dword64_ptr(sym_token_t token) const
|
||||
{
|
||||
return (const DWORD64 *)any_ptr(token, t_dword64_start, t_dword64_end);
|
||||
}
|
||||
|
||||
const LONG *long_ptr(sym_token_t token) const
|
||||
{
|
||||
return (const LONG *)any_ptr(token, t_long_start, t_long_end);
|
||||
}
|
||||
|
||||
const ULONGLONG *uint64_ptr(sym_token_t token) const
|
||||
{
|
||||
return (const ULONGLONG *)any_ptr(token, t_ulonglong_start, t_ulonglong_end);
|
||||
}
|
||||
|
||||
const char **string_ptr(sym_token_t token) const
|
||||
{
|
||||
return (const char **)any_ptr(token, t_string_start, t_string_end);
|
||||
}
|
||||
|
||||
const VARIANT *variant_ptr(sym_token_t token) const
|
||||
{
|
||||
return (const VARIANT *)any_ptr(token, t_variant_start, t_variant_end);
|
||||
}
|
||||
|
||||
enum type_t
|
||||
{
|
||||
t_bool = 0,
|
||||
t_dword,
|
||||
t_dword64,
|
||||
t_string,
|
||||
t_long,
|
||||
t_ulonglong,
|
||||
t_variant,
|
||||
t_max
|
||||
};
|
||||
|
||||
static const uint32 sizes[];
|
||||
|
||||
const void *any_ptr(sym_token_t token, sym_token_t start, sym_token_t end) const;
|
||||
|
||||
token_mask_t present; // The tokens that are present in this instance.
|
||||
bytevec_t data;
|
||||
uint8 counters[t_max];
|
||||
|
||||
struct children_t
|
||||
{
|
||||
DWORD *ids;
|
||||
uint32 cnt;
|
||||
};
|
||||
children_t children_infos[SymTagMax];
|
||||
friend class remote_pdb_access_t; // accesses children_infos directly
|
||||
bool *warned;
|
||||
};
|
||||
|
||||
|
||||
//----------------------------------------------------------------------------
|
||||
#ifdef __NT__
|
||||
struct dia_pdb_sym_t : public pdb_sym_t
|
||||
{
|
||||
dia_pdb_sym_t(pdb_access_t *_pdb_access, IDiaSymbol *_data, bool _own_sym)
|
||||
: pdb_access(_pdb_access),
|
||||
data(_data),
|
||||
own_sym(_own_sym)
|
||||
{}
|
||||
|
||||
~dia_pdb_sym_t()
|
||||
{
|
||||
if ( data != NULL && own_sym )
|
||||
{
|
||||
data->Release();
|
||||
data = NULL;
|
||||
}
|
||||
pdb_access = NULL;
|
||||
}
|
||||
|
||||
pdb_access_t *pdb_access;
|
||||
IDiaSymbol *data;
|
||||
bool own_sym;
|
||||
|
||||
pdb_sym_id_t whoami(void) { return DIA_PDB_SYM; }
|
||||
void set_symbol_data(IDiaSymbol *s, bool own)
|
||||
{
|
||||
data = s;
|
||||
own_sym = own;
|
||||
}
|
||||
bool empty(void) { return data == NULL; }
|
||||
|
||||
HRESULT get_backEndMajor(DWORD *out) { return data->get_backEndMajor(out); }
|
||||
HRESULT get_baseType(DWORD *out) { return data->get_baseType(out); }
|
||||
HRESULT get_bitPosition(DWORD *out) { return data->get_bitPosition(out); }
|
||||
HRESULT get_callingConvention(DWORD *out) { return data->get_callingConvention(out); }
|
||||
HRESULT get_code(BOOL *out) { return data->get_code(out); }
|
||||
HRESULT get_constType(BOOL *out) { return data->get_constType(out); }
|
||||
HRESULT get_count(DWORD *out) { return data->get_count(out); }
|
||||
HRESULT get_constructor(BOOL *out) { return data->get_constructor(out); }
|
||||
HRESULT get_isVirtualBaseClass(BOOL *out) { return data->get_virtualBaseClass(out); }
|
||||
HRESULT get_dataKind(DWORD *out) { return data->get_dataKind(out); }
|
||||
HRESULT get_function(BOOL *out) { return data->get_function(out); }
|
||||
HRESULT get_hasAssignmentOperator(BOOL *out) { return data->get_hasAssignmentOperator(out); }
|
||||
HRESULT get_hasCastOperator(BOOL *out) { return data->get_hasCastOperator(out); }
|
||||
HRESULT get_isStatic(BOOL *out) { return data->get_isStatic(out); }
|
||||
HRESULT get_length(DWORD64 *out) { return data->get_length(out); }
|
||||
HRESULT get_lexicalParent(pdb_sym_t *out)
|
||||
{
|
||||
IDiaSymbol *t;
|
||||
HRESULT res = data->get_lexicalParent(&t);
|
||||
return handle_related_symbol(res, t, out);
|
||||
}
|
||||
HRESULT get_locationType(DWORD *out) { return data->get_locationType(out); }
|
||||
HRESULT get_machineType(DWORD *out) { return data->get_machineType(out); }
|
||||
HRESULT get_name(qstring *out)
|
||||
{
|
||||
BSTR name;
|
||||
HRESULT hr = data->get_name(&name);
|
||||
return maybe_convert_bstr(out, hr, &name);
|
||||
}
|
||||
HRESULT get_offset(LONG *out) { return data->get_offset(out); }
|
||||
HRESULT get_registerId(DWORD *out) { return data->get_registerId(out); }
|
||||
HRESULT get_relativeVirtualAddress(DWORD *out) { return data->get_relativeVirtualAddress(out); }
|
||||
HRESULT get_symIndexId(DWORD *out) { return data->get_symIndexId(out); }
|
||||
HRESULT get_symTag(DWORD *out) { return data->get_symTag(out); }
|
||||
HRESULT get_udtKind(DWORD *out) { return data->get_udtKind(out); }
|
||||
HRESULT get_value(VARIANT *out) { return data->get_value(out); }
|
||||
HRESULT get_virtual(BOOL *out) { return data->get_virtual(out); }
|
||||
HRESULT get_virtualAddress(ULONGLONG *out) { return data->get_virtualAddress(out); }
|
||||
HRESULT get_virtualBaseOffset(DWORD *out) { return data->get_virtualBaseOffset(out); }
|
||||
HRESULT get_volatileType(BOOL *out) { return data->get_volatileType(out); }
|
||||
HRESULT get_classParent(pdb_sym_t *out)
|
||||
{
|
||||
IDiaSymbol *t;
|
||||
HRESULT res = data->get_classParent(&t);
|
||||
return handle_related_symbol(res, t, out);
|
||||
}
|
||||
|
||||
HRESULT get_type(pdb_sym_t *out)
|
||||
{
|
||||
IDiaSymbol *t;
|
||||
HRESULT res = data->get_type(&t);
|
||||
return handle_related_symbol(res, t, out);
|
||||
}
|
||||
|
||||
//------------------------------------------------------------
|
||||
virtual HRESULT get_ordinal(DWORD *) override { return S_FALSE; }
|
||||
|
||||
HRESULT handle_related_symbol(HRESULT fetch_success, IDiaSymbol *t, pdb_sym_t *out)
|
||||
{
|
||||
if ( out == NULL )
|
||||
return S_FALSE;
|
||||
QASSERT(30545, out->whoami() == DIA_PDB_SYM);
|
||||
dia_pdb_sym_t *sym = (dia_pdb_sym_t *)out;
|
||||
sym->set_symbol_data(fetch_success == S_OK ? t : NULL, true);
|
||||
return fetch_success;
|
||||
}
|
||||
|
||||
// careful with this!
|
||||
void steal_data(pdb_sym_t &other)
|
||||
{
|
||||
QASSERT(30541, whoami() == other.whoami());
|
||||
dia_pdb_sym_t &other_dia = (dia_pdb_sym_t &)other;
|
||||
QASSERT(30503, other_dia.own_sym && other_dia.data != NULL && data == NULL);
|
||||
data = other_dia.data;
|
||||
own_sym = true;
|
||||
other_dia.own_sym = false;
|
||||
other_dia.data = NULL;
|
||||
}
|
||||
|
||||
private:
|
||||
dia_pdb_sym_t();
|
||||
|
||||
HRESULT maybe_convert_bstr(qstring *out, HRESULT hr, BSTR *s)
|
||||
{
|
||||
if ( hr == S_OK )
|
||||
{
|
||||
utf16_utf8(out, *s);
|
||||
SysFreeString(*s);
|
||||
}
|
||||
return hr;
|
||||
}
|
||||
};
|
||||
DECLARE_TYPE_AS_MOVABLE(dia_pdb_sym_t);
|
||||
|
||||
//----------------------------------------------------------------------------
|
||||
#else // __NT__
|
||||
struct remote_pdb_sym_t : public pdb_sym_t
|
||||
{
|
||||
remote_pdb_sym_t(pdb_access_t *_pdb_access, sym_data_t *_data)
|
||||
: pdb_access(_pdb_access),
|
||||
data(_data)
|
||||
{}
|
||||
|
||||
~remote_pdb_sym_t()
|
||||
{
|
||||
data = NULL;
|
||||
pdb_access = NULL;
|
||||
}
|
||||
|
||||
void set_symbol_data(sym_data_t *s) { data = s; }
|
||||
|
||||
HRESULT get_backEndMajor(DWORD *out) override { return data->get_dword(t_backEndMajor, out); }
|
||||
HRESULT get_baseType(DWORD *out) override { return data->get_dword(t_baseType, out); }
|
||||
HRESULT get_bitPosition(DWORD *out) override { return data->get_dword(t_bitPosition, out); }
|
||||
HRESULT get_callingConvention(DWORD *out) override { return data->get_dword(t_callingConvention, out); }
|
||||
HRESULT get_code(BOOL *out) override { return data->get_bool(t_code, out); }
|
||||
HRESULT get_constructor(BOOL *out) override { return data->get_bool(t_constructor, out); }
|
||||
HRESULT get_isVirtualBaseClass(BOOL *out) override { return data->get_bool(t_isVirtualBaseClass, out); }
|
||||
HRESULT get_constType(BOOL *out) override { return data->get_bool(t_constType, out); }
|
||||
HRESULT get_count(DWORD *out) override { return data->get_dword(t_count, out); }
|
||||
HRESULT get_dataKind(DWORD *out) override { return data->get_dword(t_dataKind, out); }
|
||||
HRESULT get_function(BOOL *out) override { return data->get_bool(t_function, out); }
|
||||
HRESULT get_hasAssignmentOperator(BOOL *out) override { return data->get_bool(t_hasAssignmentOperator, out); }
|
||||
HRESULT get_hasCastOperator(BOOL *out) override { return data->get_bool(t_hasCastOperator, out); }
|
||||
HRESULT get_isStatic(BOOL *out) override { return data->get_bool(t_isStatic, out); }
|
||||
HRESULT get_length(DWORD64 *out) override { return data->get_dword64(t_length, out); }
|
||||
HRESULT get_lexicalParent(pdb_sym_t *out) override;
|
||||
HRESULT get_locationType(DWORD *out) override { return data->get_dword(t_locationType, out); }
|
||||
HRESULT get_machineType(DWORD *out) override { return data->get_dword(t_machineType, out); }
|
||||
HRESULT get_name(qstring *out) override { return data->get_string(t_name, out); }
|
||||
HRESULT get_offset(LONG *out) override { return data->get_dword(t_offset, out); }
|
||||
HRESULT get_registerId(DWORD *out) override { return data->get_dword(t_registerId, out); }
|
||||
HRESULT get_relativeVirtualAddress(DWORD *out) override { return data->get_dword(t_relativeVirtualAddress, out); }
|
||||
HRESULT get_symIndexId(DWORD *out) override { return data->get_dword(t_symIndexId, out); }
|
||||
HRESULT get_symTag(DWORD *out) override { return data->get_dword(t_symTag, out); }
|
||||
HRESULT get_udtKind(DWORD *out) override { return data->get_dword(t_udtKind, out); }
|
||||
HRESULT get_value(VARIANT *out) override { return data->get_variant(t_value, out); }
|
||||
HRESULT get_virtual(BOOL *out) override { return data->get_bool(t_virtual, out); }
|
||||
HRESULT get_virtualAddress(ULONGLONG *out) override { return data->get_ulonglong(t_virtualAddress, out); }
|
||||
HRESULT get_virtualBaseOffset(DWORD *out) override { return data->get_dword(t_virtualBaseOffset, out); }
|
||||
HRESULT get_volatileType(BOOL *out) override { return data->get_bool(t_volatileType, out); }
|
||||
HRESULT get_classParent(pdb_sym_t *out) override;
|
||||
HRESULT get_type(pdb_sym_t *out) override;
|
||||
//------------------------------------------------------------
|
||||
virtual HRESULT get_ordinal(DWORD *) override { return S_FALSE; }
|
||||
|
||||
// careful with this!
|
||||
void steal_data(pdb_sym_t &other) override
|
||||
{
|
||||
QASSERT(30542, whoami() == other.whoami());
|
||||
remote_pdb_sym_t &other_rem = (remote_pdb_sym_t &)other;
|
||||
QASSERT(30492, other_rem.data != NULL && data == NULL);
|
||||
data = other_rem.data;
|
||||
// we don't want to set 'other.data = NULL', because in remote access,
|
||||
// the pdb_sym_t doesn't actually own the data anyway: it's part of
|
||||
// the cache.
|
||||
}
|
||||
|
||||
pdb_sym_id_t whoami(void) override { return REMOTE_PDB_SYM; }
|
||||
bool empty(void) override { return data == NULL; }
|
||||
|
||||
pdb_access_t *pdb_access;
|
||||
sym_data_t *data;
|
||||
|
||||
private:
|
||||
remote_pdb_sym_t();
|
||||
};
|
||||
DECLARE_TYPE_AS_MOVABLE(remote_pdb_sym_t);
|
||||
#endif // !__NT__
|
||||
|
||||
//----------------------------------------------------------------------------
|
||||
#define BAD_MACHINE_TYPE ((uint32) -1)
|
||||
|
||||
#define BADSYM ((uint32) -1)
|
||||
|
||||
//-------------------------------------------------------------------------
|
||||
struct pdb_lnnum_t
|
||||
{
|
||||
pdb_lnnum_t()
|
||||
: va(BADADDR), length(0),
|
||||
columnNumber(0), columnNumberEnd(0),
|
||||
lineNumber(0), lineNumberEnd(0),
|
||||
file_id(DWORD(-1)), statement(0) {}
|
||||
ULONGLONG va;
|
||||
DWORD length;
|
||||
DWORD columnNumber;
|
||||
DWORD columnNumberEnd;
|
||||
DWORD lineNumber;
|
||||
DWORD lineNumberEnd;
|
||||
DWORD file_id;
|
||||
BOOL statement;
|
||||
};
|
||||
|
||||
//--------------------------------------------------------------------------
|
||||
typedef qvector<pdb_lnnum_t> pdb_lnnum_vec_t;
|
||||
typedef std::map<int, pdb_lnnum_vec_t> lnmap_t;
|
||||
|
||||
//-------------------------------------------------------------------------
|
||||
struct pdb_lnnums_t : pdb_lnnum_vec_t
|
||||
{
|
||||
pdb_lnnums_t() : inited(false) {}
|
||||
|
||||
bool get_item_bounds(rangeset_t *set) const;
|
||||
int get_lnnum() const;
|
||||
int get_colnum() const;
|
||||
int get_end_lnnum() const;
|
||||
int get_end_colnum() const;
|
||||
|
||||
bool inited;
|
||||
};
|
||||
|
||||
//----------------------------------------------------------------------------
|
||||
class pdb_access_t
|
||||
{
|
||||
public:
|
||||
pdb_access_t(const pdbargs_t &args)
|
||||
: pdbargs(args),
|
||||
machine_type((uint32) -1),
|
||||
dia_version(0),
|
||||
base_address(BADADDR),
|
||||
global_sym_id(BADSYM)
|
||||
{
|
||||
}
|
||||
virtual ~pdb_access_t() {}
|
||||
|
||||
//----------------------------------------------------------------------
|
||||
struct children_visitor_t
|
||||
{
|
||||
children_visitor_t()
|
||||
: parent(NULL) {}
|
||||
|
||||
virtual HRESULT visit_child(pdb_sym_t &child) = 0;
|
||||
virtual ~children_visitor_t() {}
|
||||
|
||||
pdb_sym_t *parent;
|
||||
};
|
||||
|
||||
//-------------------------------------------------------------------------
|
||||
struct dummy_visitor_t : public children_visitor_t
|
||||
{
|
||||
virtual HRESULT visit_child(pdb_sym_t &) override { return S_OK; }
|
||||
};
|
||||
|
||||
//----------------------------------------------------------------------------
|
||||
HRESULT iterate_children(
|
||||
pdb_sym_t &sym,
|
||||
enum SymTagEnum type,
|
||||
children_visitor_t &visitor);
|
||||
|
||||
//----------------------------------------------------------------------------
|
||||
virtual HRESULT do_iterate_children(
|
||||
pdb_sym_t &sym,
|
||||
enum SymTagEnum type,
|
||||
children_visitor_t &visitor) = 0;
|
||||
virtual HRESULT iterate_subtags(
|
||||
pdb_sym_t &sym,
|
||||
enum SymTagEnum type,
|
||||
children_visitor_t &visitor);
|
||||
virtual HRESULT load(pdb_sym_t &sym, DWORD id) = 0;
|
||||
|
||||
// source-level debugging-specific
|
||||
virtual HRESULT sip_retrieve_lines_by_va(
|
||||
pdb_lnnums_t *out,
|
||||
ULONGLONG va,
|
||||
ULONGLONG length) = 0;
|
||||
virtual HRESULT sip_retrieve_lines_by_coords(
|
||||
pdb_lnnums_t *out,
|
||||
DWORD file_id,
|
||||
int lnnum,
|
||||
int colnum) = 0;
|
||||
virtual HRESULT sip_iterate_symbols_at_ea(
|
||||
ULONGLONG va,
|
||||
ULONGLONG size,
|
||||
enum SymTagEnum tag,
|
||||
children_visitor_t &visitor) = 0;
|
||||
virtual HRESULT sip_iterate_file_compilands(
|
||||
DWORD file_id,
|
||||
children_visitor_t &visitor) = 0;
|
||||
virtual HRESULT sip_retrieve_file_path(
|
||||
qstring *out,
|
||||
qstring *errbuf,
|
||||
DWORD file_id) = 0;
|
||||
virtual HRESULT sip_retrieve_symbol_files(
|
||||
qvector<DWORD> *out,
|
||||
pdb_sym_t &sym) = 0;
|
||||
virtual HRESULT sip_find_files(
|
||||
qvector<DWORD> *out,
|
||||
const char *filename) = 0; // case insensitive search
|
||||
// /source-level debugging-specific
|
||||
|
||||
//----------------------------------------------------------------------------
|
||||
virtual DWORD get_global_symbol_id() const { return global_sym_id; }
|
||||
virtual ea_t get_base_address() const { return base_address; }
|
||||
virtual uint32 get_machine_type() const { return machine_type; }
|
||||
virtual int get_dia_version() const { return dia_version; }
|
||||
|
||||
void set_global_symbol_id(DWORD _global_sym_id) { global_sym_id = _global_sym_id; }
|
||||
void set_machine_type(uint32 _machine_type) { machine_type = _machine_type; }
|
||||
void set_base_address(ea_t _base_address) { base_address = _base_address; }
|
||||
void set_dia_version(int _dia_version) { dia_version = _dia_version; }
|
||||
|
||||
//----------------------------------------------------------------------------
|
||||
virtual pdb_sym_t *create_sym(void *data=NULL, bool own=false) = 0;
|
||||
pdb_sym_t *create_sym(DWORD sym_id)
|
||||
{
|
||||
pdb_sym_t *sym = create_sym();
|
||||
if ( load(*sym, sym_id) != S_OK )
|
||||
{
|
||||
qstring err;
|
||||
err.sprnt("Failed loading symbol data for ID %u", sym_id);
|
||||
delete sym;
|
||||
throw pdb_exception_t(err.c_str());
|
||||
}
|
||||
return sym;
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------------
|
||||
const pdbargs_t &pdbargs;
|
||||
|
||||
private:
|
||||
uint32 machine_type;
|
||||
int dia_version;
|
||||
ea_t base_address;
|
||||
DWORD global_sym_id;
|
||||
DECLARE_UNCOPYABLE(pdb_access_t)
|
||||
};
|
||||
|
||||
|
||||
#endif // PDBACCESS__H
|
||||
399
idasdk76/plugins/pdb/pdblocal.cpp
Normal file
399
idasdk76/plugins/pdb/pdblocal.cpp
Normal file
@@ -0,0 +1,399 @@
|
||||
|
||||
//----------------------------------------------------------------------------
|
||||
template <typename T>
|
||||
struct dia_ptr_t
|
||||
{
|
||||
dia_ptr_t() : thing(NULL) {}
|
||||
|
||||
~dia_ptr_t()
|
||||
{
|
||||
if ( thing != NULL )
|
||||
thing->Release();
|
||||
}
|
||||
|
||||
T *thing;
|
||||
};
|
||||
|
||||
//----------------------------------------------------------------------------
|
||||
HRESULT local_pdb_access_t::_do_iterate_symbols_enumerator(
|
||||
IDiaEnumSymbols *sym_enum,
|
||||
children_visitor_t &visitor)
|
||||
{
|
||||
std::set<DWORD> seen;
|
||||
HRESULT hr = S_OK;
|
||||
while ( true )
|
||||
{
|
||||
ULONG celt = 0;
|
||||
IDiaSymbol *pChild = NULL;
|
||||
hr = sym_enum->Next(1, &pChild, &celt);
|
||||
if ( FAILED(hr) || celt != 1 )
|
||||
{
|
||||
hr = S_OK; // end of enumeration
|
||||
break;
|
||||
}
|
||||
pdb_sym_t *child = create_sym(pChild, true);
|
||||
pdb_sym_janitor_t janitor_pType(child);
|
||||
DWORD sym_id;
|
||||
hr = child->get_symIndexId(&sym_id);
|
||||
if ( hr != S_OK )
|
||||
break;
|
||||
// It seems we can, in some cases, iterate over the
|
||||
// same child more than once.
|
||||
// Fortunately, it appears to be the same symbol data;
|
||||
// and not another symbol w/ the same ID
|
||||
// See also: sip_iterate_symbols_at_ea()
|
||||
if ( seen.insert(sym_id).second )
|
||||
{
|
||||
hr = visitor.visit_child(*child);
|
||||
if ( FAILED(hr) )
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return hr;
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------------
|
||||
HRESULT local_pdb_access_t::safe_iterate_children(
|
||||
pdb_sym_t &sym,
|
||||
enum SymTagEnum type,
|
||||
children_visitor_t &visitor)
|
||||
{
|
||||
HRESULT hr = E_FAIL;
|
||||
IDiaEnumSymbols *pEnumSymbols;
|
||||
try
|
||||
{
|
||||
QASSERT(30536, sym.whoami() == DIA_PDB_SYM);
|
||||
dia_pdb_sym_t &diasym = (dia_pdb_sym_t &)sym;
|
||||
hr = dia_session->findChildren(diasym.data, type, NULL, nsNone, &pEnumSymbols);
|
||||
if ( hr == S_OK )
|
||||
{
|
||||
hr = _do_iterate_symbols_enumerator(pEnumSymbols, visitor);
|
||||
pEnumSymbols->Release();
|
||||
}
|
||||
}
|
||||
catch ( const std::bad_alloc & )
|
||||
{
|
||||
// try to free some memory before quitting (and saving the idb)
|
||||
delete this;
|
||||
nomem("pdb");
|
||||
}
|
||||
catch ( const std::exception &e )
|
||||
{
|
||||
error("Unhandled C++ exception: %s", e.what());
|
||||
}
|
||||
catch ( ... )
|
||||
{
|
||||
error("Unhandled C++ exception!");
|
||||
}
|
||||
return hr;
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------------
|
||||
HRESULT local_pdb_access_t::do_iterate_children(
|
||||
pdb_sym_t &sym,
|
||||
enum SymTagEnum type,
|
||||
children_visitor_t &visitor)
|
||||
{
|
||||
int code;
|
||||
HRESULT hr = E_FAIL;
|
||||
__try
|
||||
{
|
||||
hr = safe_iterate_children(sym, type, visitor);
|
||||
}
|
||||
__except ( code=GetExceptionCode(), EXCEPTION_EXECUTE_HANDLER )
|
||||
{
|
||||
// complain to the user
|
||||
ask_for_feedback(
|
||||
"%s: %s\n"
|
||||
"Is the corresponding PDB file valid?",
|
||||
pdbargs.input_path.c_str(),
|
||||
winerr(code));
|
||||
|
||||
// we may arrive here because we ran out of memory
|
||||
// try to free some memory before quitting (and saving the idb)
|
||||
delete this;
|
||||
error(NULL); // and die... this will save the idb
|
||||
}
|
||||
return hr;
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------------
|
||||
HRESULT local_pdb_access_t::load(pdb_sym_t &pdbsym, DWORD id)
|
||||
{
|
||||
IDiaSymbol *dia_sym;
|
||||
HRESULT hr = dia_session->symbolById(id, &dia_sym);
|
||||
if ( hr == S_OK )
|
||||
{
|
||||
QASSERT(30543, pdbsym.whoami() == DIA_PDB_SYM);
|
||||
dia_pdb_sym_t &sym = (dia_pdb_sym_t &)pdbsym;
|
||||
sym.set_symbol_data(dia_sym, true);
|
||||
}
|
||||
return hr;
|
||||
}
|
||||
|
||||
//-------------------------------------------------------------------------
|
||||
HRESULT local_pdb_access_t::_copy_line_numbers(
|
||||
pdb_lnnums_t *out,
|
||||
IDiaEnumLineNumbers *enumerator) const
|
||||
{
|
||||
LONG count = 0;
|
||||
HRESULT hr = enumerator->get_Count(&count);
|
||||
if ( hr == S_OK )
|
||||
{
|
||||
IDiaLineNumber *lines[64];
|
||||
ULONG got = 0;
|
||||
for ( LONG i=0; i < count; i += got )
|
||||
{
|
||||
// Fetch many line number information at once
|
||||
enumerator->Next(qnumber(lines), lines, &got);
|
||||
if ( got == 0 )
|
||||
break;
|
||||
|
||||
for ( ULONG j=0; j < got; j++ )
|
||||
{
|
||||
IDiaLineNumber *l = lines[j];
|
||||
pdb_lnnum_t &lo = out->push_back();
|
||||
l->get_virtualAddress(&lo.va);
|
||||
l->get_length(&lo.length);
|
||||
l->get_columnNumber(&lo.columnNumber);
|
||||
l->get_columnNumberEnd(&lo.columnNumberEnd);
|
||||
l->get_lineNumber(&lo.lineNumber);
|
||||
l->get_lineNumberEnd(&lo.lineNumberEnd);
|
||||
l->get_statement(&lo.statement);
|
||||
IDiaSourceFile *f = NULL;
|
||||
if ( l->get_sourceFile(&f) == S_OK )
|
||||
{
|
||||
f->get_uniqueId(&lo.file_id);
|
||||
f->Release();
|
||||
}
|
||||
lines[j]->Release();
|
||||
}
|
||||
}
|
||||
}
|
||||
return hr;
|
||||
}
|
||||
|
||||
//-------------------------------------------------------------------------
|
||||
HRESULT local_pdb_access_t::sip_retrieve_lines_by_va(
|
||||
pdb_lnnums_t *out,
|
||||
ULONGLONG va,
|
||||
ULONGLONG length)
|
||||
{
|
||||
dia_ptr_t<IDiaEnumLineNumbers> pEnumLineNumbers;
|
||||
HRESULT hr = dia_session->findLinesByVA(va, length, &pEnumLineNumbers.thing);
|
||||
if ( hr == S_OK )
|
||||
hr = _copy_line_numbers(out, pEnumLineNumbers.thing);
|
||||
return hr;
|
||||
}
|
||||
|
||||
//-------------------------------------------------------------------------
|
||||
HRESULT local_pdb_access_t::sip_retrieve_lines_by_coords(
|
||||
pdb_lnnums_t *out,
|
||||
DWORD file_id,
|
||||
int lnnum,
|
||||
int colnum)
|
||||
{
|
||||
dia_ptr_t<IDiaSourceFile> pFile;
|
||||
HRESULT hr = dia_session->findFileById(file_id, &pFile.thing);
|
||||
if ( FAILED(hr) )
|
||||
return hr;
|
||||
|
||||
dia_ptr_t<IDiaEnumSymbols> pEnumSymbols;
|
||||
hr = pFile.thing->get_compilands(&pEnumSymbols.thing);
|
||||
if ( FAILED(hr) )
|
||||
return hr;
|
||||
|
||||
while ( true )
|
||||
{
|
||||
ULONG got = 0;
|
||||
IDiaSymbol *compiland;
|
||||
pEnumSymbols.thing->Next(1, &compiland, &got);
|
||||
if ( got == 0 )
|
||||
break;
|
||||
|
||||
dia_ptr_t<IDiaEnumLineNumbers> pEnumLineNumbers;
|
||||
HRESULT hr2;
|
||||
if ( lnnum == 0 )
|
||||
hr2 = dia_session->findLines(
|
||||
compiland,
|
||||
pFile.thing,
|
||||
&pEnumLineNumbers.thing);
|
||||
else
|
||||
hr2 = dia_session->findLinesByLinenum(
|
||||
compiland,
|
||||
pFile.thing,
|
||||
lnnum,
|
||||
colnum,
|
||||
&pEnumLineNumbers.thing);
|
||||
compiland->Release();
|
||||
|
||||
if ( hr == S_OK )
|
||||
_copy_line_numbers(out, pEnumLineNumbers.thing);
|
||||
}
|
||||
return hr;
|
||||
}
|
||||
|
||||
//-------------------------------------------------------------------------
|
||||
HRESULT local_pdb_access_t::sip_iterate_symbols_at_ea(
|
||||
ULONGLONG va,
|
||||
ULONGLONG size,
|
||||
enum SymTagEnum tag,
|
||||
children_visitor_t &visitor)
|
||||
{
|
||||
// See also: _do_iterate_symbols_enumerator
|
||||
std::set<DWORD> seen;
|
||||
|
||||
ea_t cur = va;
|
||||
while ( true )
|
||||
{
|
||||
if ( cur >= va + size )
|
||||
break;
|
||||
|
||||
ea_t old = cur;
|
||||
qnotused(old);
|
||||
|
||||
LONG disp;
|
||||
IDiaSymbol *sym = NULL;
|
||||
HRESULT hr = dia_session->findSymbolByVAEx(cur, tag, &sym, &disp);
|
||||
if ( FAILED(hr) || sym == NULL )
|
||||
break;
|
||||
|
||||
// perform all get_*'s on 'sym' _before_ the visitor is called: it might
|
||||
// very well 'steal' the symbol & destroy it in case it's not needed.
|
||||
// (see source_items_vec_builder_t::visit_child())
|
||||
pdb_sym_t *psym = create_sym(sym, true);
|
||||
pdb_sym_janitor_t janitor_psym(psym);
|
||||
DWORD sym_id;
|
||||
hr = psym->get_symIndexId(&sym_id);
|
||||
if ( hr != S_OK )
|
||||
break;
|
||||
|
||||
ULONGLONG length = 0;
|
||||
sym->get_length(&length);
|
||||
|
||||
if ( seen.insert(sym_id).second )
|
||||
{
|
||||
hr = visitor.visit_child(*psym);
|
||||
if ( FAILED(hr) )
|
||||
break;
|
||||
}
|
||||
|
||||
cur -= disp;
|
||||
cur += length;
|
||||
|
||||
QASSERT(30169, cur > old); // to avoid endless loops - i do not know if they are possible
|
||||
}
|
||||
return S_OK;
|
||||
}
|
||||
|
||||
//-------------------------------------------------------------------------
|
||||
HRESULT local_pdb_access_t::sip_iterate_file_compilands(
|
||||
DWORD file_id,
|
||||
children_visitor_t &visitor)
|
||||
{
|
||||
dia_ptr_t<IDiaSourceFile> pFile;
|
||||
HRESULT hr = dia_session->findFileById(file_id, &pFile.thing);
|
||||
if ( FAILED(hr) )
|
||||
return hr;
|
||||
|
||||
dia_ptr_t<IDiaEnumSymbols> pEnumSymbols;
|
||||
hr = pFile.thing->get_compilands(&pEnumSymbols.thing);
|
||||
if ( hr == S_OK )
|
||||
hr = _do_iterate_symbols_enumerator(pEnumSymbols.thing, visitor);
|
||||
return hr;
|
||||
}
|
||||
|
||||
//-------------------------------------------------------------------------
|
||||
HRESULT local_pdb_access_t::sip_retrieve_file_path(
|
||||
qstring *out,
|
||||
qstring *errbuf,
|
||||
DWORD file_id)
|
||||
{
|
||||
dia_ptr_t<IDiaSourceFile> pFile;
|
||||
HRESULT hr = dia_session->findFileById(file_id, &pFile.thing);
|
||||
if ( hr == S_OK )
|
||||
{
|
||||
BSTR path;
|
||||
hr = pFile.thing->get_fileName(&path);
|
||||
if ( hr == S_OK )
|
||||
{
|
||||
utf16_utf8(out, path);
|
||||
SysFreeString(path);
|
||||
}
|
||||
}
|
||||
|
||||
if ( FAILED(hr) )
|
||||
{
|
||||
if ( errbuf != NULL )
|
||||
*errbuf = winerr(hr);
|
||||
}
|
||||
|
||||
return hr;
|
||||
}
|
||||
|
||||
//-------------------------------------------------------------------------
|
||||
HRESULT local_pdb_access_t::_copy_files_ids(
|
||||
qvector<DWORD> *out,
|
||||
IDiaEnumSourceFiles *enumerator) const
|
||||
{
|
||||
ULONG celt = 0;
|
||||
IDiaSourceFile *file = NULL;
|
||||
while ( enumerator->Next(1, &file, &celt) == S_OK && celt > 0 )
|
||||
{
|
||||
DWORD file_id;
|
||||
if ( file->get_uniqueId(&file_id) == S_OK )
|
||||
out->push_back(file_id);
|
||||
file->Release();
|
||||
}
|
||||
return S_OK;
|
||||
}
|
||||
|
||||
//-------------------------------------------------------------------------
|
||||
HRESULT local_pdb_access_t::sip_retrieve_symbol_files(
|
||||
qvector<DWORD> *out,
|
||||
pdb_sym_t &sym)
|
||||
{
|
||||
// Retrieve source file name associated with the current symbol
|
||||
QASSERT(30537, sym.whoami() == DIA_PDB_SYM);
|
||||
dia_pdb_sym_t &diasym = (dia_pdb_sym_t &)sym;
|
||||
BSTR path;
|
||||
HRESULT hr = diasym.data->get_sourceFileName(&path);
|
||||
if ( hr == S_OK ) // cannot use SUCCEEDED(hr) because S_OK means success
|
||||
{
|
||||
dia_ptr_t<IDiaEnumSourceFiles> pEnumSourceFiles;
|
||||
hr = dia_session->findFile(NULL, path, nsfFNameExt, &pEnumSourceFiles.thing);
|
||||
SysFreeString(path);
|
||||
|
||||
if ( hr == S_OK )
|
||||
_copy_files_ids(out, pEnumSourceFiles.thing);
|
||||
}
|
||||
return hr;
|
||||
}
|
||||
|
||||
//-------------------------------------------------------------------------
|
||||
HRESULT local_pdb_access_t::sip_find_files(
|
||||
qvector<DWORD> *out,
|
||||
const char *filename)
|
||||
{
|
||||
qwstring fnamebuf;
|
||||
wchar16_t *fname = NULL;
|
||||
if ( filename != NULL )
|
||||
{
|
||||
qstring fnametmp = filename;
|
||||
utf8_utf16(&fnamebuf, &fnametmp[0]);
|
||||
fname = fnamebuf.begin();
|
||||
}
|
||||
|
||||
dia_ptr_t<IDiaEnumSourceFiles> pEnumSourceFiles;
|
||||
HRESULT hr = dia_session->findFile(
|
||||
NULL,
|
||||
fname,
|
||||
nsfFNameExt | nsfCaseInsensitive,
|
||||
&pEnumSourceFiles.thing);
|
||||
|
||||
if ( hr == S_OK )
|
||||
_copy_files_ids(out, pEnumSourceFiles.thing);
|
||||
|
||||
return hr;
|
||||
}
|
||||
116
idasdk76/plugins/pdb/pdblocal.hpp
Normal file
116
idasdk76/plugins/pdb/pdblocal.hpp
Normal file
@@ -0,0 +1,116 @@
|
||||
|
||||
#ifndef PDBLOCAL_HPP
|
||||
#define PDBLOCAL_HPP
|
||||
|
||||
// The PDB related code that works on Windows and uses DIA
|
||||
|
||||
//----------------------------------------------------------------------------
|
||||
class local_pdb_access_t : public pdb_access_t
|
||||
{
|
||||
public:
|
||||
local_pdb_access_t(
|
||||
const pdbargs_t &args,
|
||||
IDiaDataSource *pSource,
|
||||
IDiaSession *pSession,
|
||||
IDiaSymbol *pGlobal)
|
||||
: pdb_access_t(args),
|
||||
dia_source(pSource),
|
||||
dia_session(pSession),
|
||||
dia_global(pGlobal)
|
||||
{
|
||||
}
|
||||
|
||||
virtual ~local_pdb_access_t()
|
||||
{
|
||||
#define RELEASE(thing) do { if ( thing != NULL ) { (thing)->Release(); thing = NULL; } } while ( false )
|
||||
RELEASE(dia_global);
|
||||
RELEASE(dia_session);
|
||||
RELEASE(dia_source);
|
||||
#undef RELEASE
|
||||
set_global_symbol_id(BADSYM);
|
||||
}
|
||||
|
||||
HRESULT init()
|
||||
{
|
||||
DWORD id;
|
||||
HRESULT hr = dia_global->get_symIndexId(&id);
|
||||
if ( hr != S_OK )
|
||||
return hr;
|
||||
set_global_symbol_id(id);
|
||||
|
||||
DWORD64 load_addr;
|
||||
hr = dia_session->get_loadAddress(&load_addr);
|
||||
if ( hr != S_OK )
|
||||
return hr;
|
||||
set_base_address(load_addr);
|
||||
|
||||
return S_OK;
|
||||
}
|
||||
|
||||
virtual HRESULT do_iterate_children(
|
||||
pdb_sym_t &sym,
|
||||
enum SymTagEnum type,
|
||||
children_visitor_t &visitor) override;
|
||||
virtual HRESULT load(pdb_sym_t &sym, DWORD id) override;
|
||||
|
||||
virtual HRESULT sip_retrieve_lines_by_va(
|
||||
pdb_lnnums_t *out,
|
||||
ULONGLONG va,
|
||||
ULONGLONG length) override;
|
||||
virtual HRESULT sip_retrieve_lines_by_coords(
|
||||
pdb_lnnums_t *out,
|
||||
DWORD file_id,
|
||||
int lnnum,
|
||||
int colnum) override;
|
||||
virtual HRESULT sip_iterate_symbols_at_ea(
|
||||
ULONGLONG va,
|
||||
ULONGLONG size,
|
||||
enum SymTagEnum tag,
|
||||
children_visitor_t &visitor) override;
|
||||
virtual HRESULT sip_iterate_file_compilands(
|
||||
DWORD file_id,
|
||||
children_visitor_t &visitor) override;
|
||||
virtual HRESULT sip_retrieve_file_path(
|
||||
qstring *out,
|
||||
qstring *errbuf,
|
||||
DWORD file_id) override;
|
||||
virtual HRESULT sip_retrieve_symbol_files(
|
||||
qvector<DWORD> *out,
|
||||
pdb_sym_t &sym) override;
|
||||
virtual HRESULT sip_find_files(
|
||||
qvector<DWORD> *out,
|
||||
const char *name) override;
|
||||
|
||||
virtual pdb_sym_t *create_sym(void *data, bool own) override
|
||||
{
|
||||
IDiaSymbol *sym = (IDiaSymbol *)data;
|
||||
return new dia_pdb_sym_t(this, sym, own);
|
||||
}
|
||||
pdb_sym_t *create_sym(DWORD sym_id) { return pdb_access_t::create_sym(sym_id); }
|
||||
|
||||
IDiaDataSource *dia_source;
|
||||
IDiaSession *dia_session;
|
||||
IDiaSymbol *dia_global;
|
||||
|
||||
private:
|
||||
HRESULT safe_iterate_children(
|
||||
pdb_sym_t &sym,
|
||||
enum SymTagEnum type,
|
||||
children_visitor_t &visitor);
|
||||
HRESULT _do_iterate_symbols_enumerator(
|
||||
IDiaEnumSymbols *sym_enum,
|
||||
children_visitor_t &visitor);
|
||||
|
||||
HRESULT _copy_line_numbers(
|
||||
pdb_lnnums_t *out,
|
||||
IDiaEnumLineNumbers *enumerator) const;
|
||||
|
||||
HRESULT _copy_files_ids(
|
||||
qvector<DWORD> *out,
|
||||
IDiaEnumSourceFiles *enumerator) const;
|
||||
|
||||
DECLARE_UNCOPYABLE(local_pdb_access_t)
|
||||
};
|
||||
|
||||
|
||||
#endif // PDBLOCAL_HPP
|
||||
898
idasdk76/plugins/pdb/pdbremote.cpp
Normal file
898
idasdk76/plugins/pdb/pdbremote.cpp
Normal file
@@ -0,0 +1,898 @@
|
||||
|
||||
#include <pro.h>
|
||||
|
||||
#include "pdbremote.hpp"
|
||||
#include "varser.hpp"
|
||||
|
||||
// Since we're using the win32 local stup debugger at the moment,
|
||||
// this is necessary.
|
||||
#include <dbg.hpp>
|
||||
|
||||
//-------------------------------------------------------------------------
|
||||
bool is_win32_remote_debugger_loaded()
|
||||
{
|
||||
return dbg != NULL && dbg->is_remote() && streq(dbg->name, "win32");
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------------
|
||||
HRESULT remote_pdb_sym_t::get_classParent(pdb_sym_t *out)
|
||||
{
|
||||
DWORD parent_id;
|
||||
HRESULT hr = data->get_dword(t_classParentId, &parent_id);
|
||||
if ( hr == S_OK )
|
||||
hr = pdb_access->load(*out, parent_id);
|
||||
return hr;
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------------
|
||||
HRESULT remote_pdb_sym_t::get_type(pdb_sym_t *out)
|
||||
{
|
||||
DWORD type_id;
|
||||
HRESULT hr = data->get_dword(t_typeId, &type_id);
|
||||
if ( hr == S_OK )
|
||||
hr = pdb_access->load(*out, type_id);
|
||||
return hr;
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------------
|
||||
HRESULT remote_pdb_sym_t::get_lexicalParent(pdb_sym_t *out)
|
||||
{
|
||||
DWORD lparent_id;
|
||||
HRESULT hr = data->get_dword(t_lexicalParentId, &lparent_id);
|
||||
if ( hr == S_OK )
|
||||
hr = pdb_access->load(*out, lparent_id);
|
||||
return hr;
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------------
|
||||
const uint32 sym_data_t::sizes[] =
|
||||
{
|
||||
sizeof(BOOL),
|
||||
sizeof(DWORD),
|
||||
sizeof(DWORD64),
|
||||
sizeof(char *),
|
||||
sizeof(LONG),
|
||||
sizeof(ULONGLONG),
|
||||
sizeof(VARIANT)
|
||||
};
|
||||
|
||||
//----------------------------------------------------------------------------
|
||||
sym_data_t::sym_data_t(
|
||||
token_mask_t _tokens,
|
||||
const uchar *buf,
|
||||
size_t bufsize,
|
||||
packing_info_t _packing,
|
||||
bool *_warned)
|
||||
: present(_tokens),
|
||||
warned(_warned)
|
||||
{
|
||||
memset(counters, 0, sizeof(counters));
|
||||
memset(children_infos, 0, sizeof(children_infos));
|
||||
|
||||
if ( _packing == SYMDAT_PACKED )
|
||||
{
|
||||
const uchar *ptr = buf;
|
||||
const uchar *const end = buf + bufsize;
|
||||
for ( uint64 bit = t_start; bit != t_end; bit <<= 1 )
|
||||
{
|
||||
sym_token_t token = sym_token_t(bit);
|
||||
if ( !token_present(token) )
|
||||
continue;
|
||||
|
||||
if ( is_sym_token_bool(token) )
|
||||
{
|
||||
counters[t_bool]++;
|
||||
uint8 tmp = unpack_db(&ptr, end);
|
||||
data.append(&tmp, sizeof(tmp));
|
||||
}
|
||||
else if ( is_sym_token_dword(token) )
|
||||
{
|
||||
counters[t_dword]++;
|
||||
uint32 tmp = unpack_dd(&ptr, end);
|
||||
data.append(&tmp, sizeof(tmp));
|
||||
}
|
||||
else if ( is_sym_token_dword64(token) )
|
||||
{
|
||||
counters[t_dword64]++;
|
||||
uint64 tmp = unpack_dq(&ptr, end);
|
||||
data.append(&tmp, sizeof(tmp));
|
||||
}
|
||||
else if ( is_sym_token_string(token) )
|
||||
{
|
||||
counters[t_string]++;
|
||||
char *tmp = qstrdup(unpack_str(&ptr, end));
|
||||
data.append(&tmp, sizeof(tmp));
|
||||
}
|
||||
else if ( is_sym_token_long(token) )
|
||||
{
|
||||
counters[t_long]++;
|
||||
LONG tmp = unpack_dd(&ptr, end);
|
||||
data.append(&tmp, sizeof(tmp));
|
||||
}
|
||||
else if ( is_sym_token_ulonglong(token) )
|
||||
{
|
||||
counters[t_ulonglong]++;
|
||||
ULONGLONG tmp = unpack_dq(&ptr, end);
|
||||
data.append(&tmp, sizeof(tmp));
|
||||
}
|
||||
else if ( is_sym_token_variant(token) )
|
||||
{
|
||||
counters[t_variant]++;
|
||||
VARIANT var;
|
||||
if ( varser_t::deserialize(var, &ptr, end) )
|
||||
{
|
||||
data.append(&var, sizeof(var));
|
||||
}
|
||||
else
|
||||
{
|
||||
if ( !*warned )
|
||||
{
|
||||
warning("The PDB file contains VARIANT items that cannot be deserialized.");
|
||||
*warned = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
INTERR(30200);
|
||||
}
|
||||
}
|
||||
|
||||
QASSERT(30201, data.size() == counters[t_bool] * sizes[t_bool]
|
||||
+ counters[t_dword] * sizes[t_dword]
|
||||
+ counters[t_dword64] * sizes[t_dword64]
|
||||
+ counters[t_string] * sizes[t_string]
|
||||
+ counters[t_long] * sizes[t_long]
|
||||
+ counters[t_ulonglong] * sizes[t_ulonglong]
|
||||
+ counters[t_variant] * sizes[t_variant]);
|
||||
QASSERT(30202, ptr == end);
|
||||
}
|
||||
else
|
||||
{
|
||||
data.append(buf, bufsize);
|
||||
// Not supported yet. All that's left to do
|
||||
// is count the types (counters[]), though.
|
||||
INTERR(30203);
|
||||
}
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------------
|
||||
sym_data_t::~sym_data_t()
|
||||
{
|
||||
for ( int i = 0; i < SymTagMax; i++ )
|
||||
{
|
||||
children_t &children = children_infos[i];
|
||||
if ( children.ids != NULL )
|
||||
{
|
||||
qfree(children.ids);
|
||||
children.ids = NULL;
|
||||
children.cnt = 0;
|
||||
}
|
||||
}
|
||||
|
||||
uint8 nstring = counters[t_string];
|
||||
if ( nstring > 0 )
|
||||
{
|
||||
char **cur_str_ptr = (char **)string_ptr(t_string_start);
|
||||
for ( uint8 i = 0; i < nstring; i++, cur_str_ptr++ )
|
||||
qfree(*cur_str_ptr);
|
||||
}
|
||||
|
||||
uint8 nvariant = counters[t_variant];
|
||||
if ( nvariant > 0 )
|
||||
{
|
||||
VARIANT *cur_variant_ptr = (VARIANT *)variant_ptr(t_variant_start);
|
||||
for ( uint8 i = 0; i < nvariant; i++, cur_variant_ptr++ )
|
||||
if ( cur_variant_ptr->vt == VT_LPSTR )
|
||||
qfree(cur_variant_ptr->punkVal);
|
||||
}
|
||||
|
||||
warned = nullptr;
|
||||
}
|
||||
|
||||
|
||||
#define READ_IF_FOUND(type, fun) \
|
||||
const type *ptr = fun##_ptr(token); \
|
||||
if ( ptr == NULL ) \
|
||||
{ \
|
||||
return S_FALSE; \
|
||||
} \
|
||||
else \
|
||||
{ \
|
||||
*out = *ptr; \
|
||||
return S_OK; \
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------------
|
||||
HRESULT sym_data_t::get_bool(sym_token_t token, BOOL *out) const
|
||||
{
|
||||
READ_IF_FOUND(BOOL, bool)
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------------
|
||||
HRESULT sym_data_t::get_dword(sym_token_t token, DWORD *out) const
|
||||
{
|
||||
READ_IF_FOUND(DWORD, dword)
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------------
|
||||
HRESULT sym_data_t::get_dword64(sym_token_t token, DWORD64 *out) const
|
||||
{
|
||||
READ_IF_FOUND(DWORD64, dword64)
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------------
|
||||
HRESULT sym_data_t::get_string(sym_token_t token, qstring *out) const
|
||||
{
|
||||
READ_IF_FOUND(char *, string)
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------------
|
||||
HRESULT sym_data_t::get_dword(sym_token_t token, LONG *out) const
|
||||
{
|
||||
READ_IF_FOUND(LONG, long)
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------------
|
||||
HRESULT sym_data_t::get_ulonglong(sym_token_t token, ULONGLONG *out) const
|
||||
{
|
||||
READ_IF_FOUND(ULONGLONG, uint64)
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------------
|
||||
HRESULT sym_data_t::get_variant(sym_token_t token, VARIANT *out) const
|
||||
{
|
||||
READ_IF_FOUND(VARIANT, variant)
|
||||
}
|
||||
|
||||
#undef READ_IF_FOUND
|
||||
|
||||
//----------------------------------------------------------------------------
|
||||
const void *sym_data_t::any_ptr(sym_token_t token, sym_token_t start, sym_token_t end) const
|
||||
{
|
||||
if ( !token_present(token) )
|
||||
return NULL;
|
||||
|
||||
static const sym_token_t ends[] =
|
||||
{
|
||||
t_bool_end,
|
||||
t_dword_end,
|
||||
t_dword64_end,
|
||||
t_string_end,
|
||||
t_long_end,
|
||||
t_ulonglong_end,
|
||||
t_variant_end,
|
||||
};
|
||||
CASSERT(qnumber(ends) == qnumber(counters));
|
||||
CASSERT(qnumber(sizes) == qnumber(counters));
|
||||
|
||||
// count how many bytes we have to skip and determine the type size
|
||||
uint32 type_size = 0;
|
||||
const uchar *ptr = data.begin();
|
||||
for ( int i=0; i < qnumber(ends); i++ )
|
||||
{
|
||||
if ( token <= ends[i] )
|
||||
{
|
||||
type_size = sizes[i];
|
||||
break;
|
||||
}
|
||||
ptr += counters[i] * sizes[i];
|
||||
}
|
||||
QASSERT(30204, type_size != 0);
|
||||
|
||||
// how many tokens of our type we have to skip?
|
||||
uint32 bit;
|
||||
for ( bit = start; bit <= end; bit <<= 1 )
|
||||
{
|
||||
sym_token_t t = sym_token_t(bit);
|
||||
if ( token_present(t) )
|
||||
{
|
||||
if ( t == token )
|
||||
return ptr;
|
||||
ptr += type_size;
|
||||
}
|
||||
}
|
||||
return NULL; // did not find the requested token
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------------
|
||||
remote_pdb_access_t::~remote_pdb_access_t()
|
||||
{
|
||||
typedef std::map<DWORD,sym_data_t*>::iterator iter;
|
||||
for ( iter it = cache.begin(), end = cache.end(); it != end; it++ )
|
||||
delete it->second;
|
||||
|
||||
close_connection();
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------------
|
||||
void remote_pdb_access_t::close_connection()
|
||||
{
|
||||
if ( remote_session_id > 0 )
|
||||
{
|
||||
bytevec_t dummy;
|
||||
perform_op(WIN32_IOCTL_PDB_CLOSE, dummy, NULL);
|
||||
remote_session_id = -1;
|
||||
}
|
||||
|
||||
if ( !was_connected && dbg != NULL )
|
||||
dbg->term_debugger();
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------
|
||||
// load and connect to a remote win32 debugger, if necessary
|
||||
bool remote_pdb_access_t::load_win32_debugger(void)
|
||||
{
|
||||
was_connected = false;
|
||||
if ( dbg != NULL && !is_win32_remote_debugger_loaded() )
|
||||
{
|
||||
// a debugger is loaded, but it's not a remote win32
|
||||
warning("Loading PDB symbols requires a remote win32 debugger. "
|
||||
"Please stop the current debugging session and try again.");
|
||||
return false;
|
||||
}
|
||||
if ( get_process_state() != DSTATE_NOTASK )
|
||||
{
|
||||
// the debugger is already connected
|
||||
was_connected = true;
|
||||
return true;
|
||||
}
|
||||
|
||||
netnode pdbnode(PDB_NODE_NAME);
|
||||
pdbnode.altset(PDB_LOADING_WIN32_DBG, true);
|
||||
bool win32_dbg_loaded = load_debugger("win32", true) && dbg != NULL;
|
||||
pdbnode.altdel(PDB_LOADING_WIN32_DBG);
|
||||
|
||||
if ( !win32_dbg_loaded )
|
||||
{
|
||||
warning("Could not load remote Win32 debugger.");
|
||||
return false;
|
||||
}
|
||||
|
||||
qstring server;
|
||||
server = host[0] != '\0' ? host : "localhost";
|
||||
|
||||
qstring pass;
|
||||
if ( pwd != NULL )
|
||||
pass = pwd;
|
||||
|
||||
qstring dbg_errbuf;
|
||||
while ( !dbg->init_debugger(server.c_str(), port, pass.c_str(), &dbg_errbuf) )
|
||||
{
|
||||
if ( batch ) // avoid endless (and useless) loop in batch mode
|
||||
return false;
|
||||
if ( !dbg_errbuf.empty() )
|
||||
msg("%s\n", dbg_errbuf.begin());
|
||||
// hrw
|
||||
const char *winremote = inf_is_64bit() ? "win64_remote64.exe" : "win32_remote.exe";
|
||||
qstring formstr;
|
||||
formstr.sprnt(
|
||||
"Remote PDB server\n"
|
||||
"In order to load PDB information, IDA requires a running %s debugger server\n"
|
||||
"running on a Windows host, but it could not connect to the %s debugger\n"
|
||||
"at the current specified address.\n"
|
||||
"Please make sure that %s is running there.\n\n"
|
||||
"<#Name of the remote host#~H~ostname :q:1023:30::> <#Remote port number#Po~r~t:D::8::>\n"
|
||||
"<#Password for the remote host#Pass~w~ord :q:1023:30::>\n"
|
||||
"Hint: to change this permanently, edit pdb.cfg.\n\n",
|
||||
winremote, winremote, winremote);
|
||||
uval_t sport = port;
|
||||
int r = ask_form(formstr.c_str(), &server, &sport, &pass);
|
||||
if ( r != 1 )
|
||||
return false;
|
||||
port = sport;
|
||||
}
|
||||
msg("PDB: successfully connected to %s\n", server.c_str());
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
//----------------------------------------------------------------------------
|
||||
#define REPORT_ERROR(Msg, Rc) \
|
||||
do \
|
||||
{ \
|
||||
qfree(outbuf); \
|
||||
qstrncpy(errbuf, Msg, sizeof(errbuf)); \
|
||||
return Rc; \
|
||||
} while ( false )
|
||||
|
||||
//-------------------------------------------------------------------------
|
||||
HRESULT remote_pdb_access_t::open_connection()
|
||||
{
|
||||
// Load win32 debugger (FIXME: Should just use an RPC client, not a full debugger!)
|
||||
if ( !load_win32_debugger() )
|
||||
return S_FALSE;
|
||||
|
||||
// Init remote.
|
||||
bytevec_t oper;
|
||||
compiler_info_t cc;
|
||||
inf_get_cc(&cc);
|
||||
oper.append(&cc, sizeof(cc));
|
||||
oper.pack_str(pdbargs.pdb_path);
|
||||
oper.pack_str(pdbargs.input_path);
|
||||
oper.append(&pdbargs.pdb_sign, sizeof(pdbargs.pdb_sign));
|
||||
oper.pack_str(pdbargs.spath);
|
||||
oper.pack_ea64(get_base_address());
|
||||
oper.pack_dd(pdbargs.flags);
|
||||
|
||||
void *outbuf = NULL;
|
||||
ssize_t outsize = 0;
|
||||
ioctl_pdb_code_t rc = send_ioctl(
|
||||
WIN32_IOCTL_PDB_OPEN,
|
||||
oper.begin(), oper.size(), &outbuf, &outsize);
|
||||
if ( rc != pdb_ok || outsize < 1 )
|
||||
REPORT_ERROR(
|
||||
"PDB symbol extraction is not supported by the remote server",
|
||||
E_FAIL);
|
||||
|
||||
// remote PDB session has become active
|
||||
bytevec_t sidbuf;
|
||||
{
|
||||
const uchar *ptr = (const uchar *) outbuf;
|
||||
const uchar *const end = ptr + outsize;
|
||||
remote_session_id = unpack_dd(&ptr, end);
|
||||
QASSERT(30493, remote_session_id > 0);
|
||||
sidbuf.pack_dd(remote_session_id);
|
||||
}
|
||||
|
||||
// now, do the polling game.
|
||||
bool done = false;
|
||||
while ( !done )
|
||||
{
|
||||
qfree(outbuf);
|
||||
outbuf = NULL;
|
||||
qsleep(100);
|
||||
user_cancelled(); // refresh the output window
|
||||
rc = send_ioctl(
|
||||
WIN32_IOCTL_PDB_OPERATION_COMPLETE,
|
||||
sidbuf.begin(), sidbuf.size(),
|
||||
&outbuf, &outsize);
|
||||
if ( rc != pdb_ok || outsize <= 0 )
|
||||
REPORT_ERROR(
|
||||
"remote server reported error while opening PDB",
|
||||
E_FAIL);
|
||||
const uchar *ptr = (const uchar *)outbuf;
|
||||
const uchar *const end = ptr + outsize;
|
||||
pdb_op_completion_t status = pdb_op_completion_t(unpack_dd(&ptr, end));
|
||||
done = true; // only 'not complete' status will make us continue.
|
||||
switch ( status )
|
||||
{
|
||||
case pdb_op_not_complete:
|
||||
done = false;
|
||||
break;
|
||||
case pdb_op_complete:
|
||||
{
|
||||
set_global_symbol_id(unpack_dd(&ptr, end));
|
||||
set_machine_type(unpack_dd(&ptr, end));
|
||||
set_dia_version(unpack_dd(&ptr, end));
|
||||
const char *fname = unpack_str(&ptr, end);
|
||||
// TODO The printed path is wrong (test with pc_gdb_notepad.exe).
|
||||
msg("PDB: opened \"%s\"\n", fname);
|
||||
}
|
||||
break;
|
||||
case pdb_op_failure:
|
||||
{
|
||||
const char *errmsg = unpack_str(&ptr, end);
|
||||
REPORT_ERROR(errmsg, E_FAIL);
|
||||
// if opening pdb fails, win32_remote closes the MSDIA pdb
|
||||
// session automatically.
|
||||
remote_session_id = -1; //-V779 Unreachable code detected
|
||||
}
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
qfree(outbuf);
|
||||
|
||||
return remote_session_id > 0 ? S_OK : E_FAIL;
|
||||
}
|
||||
|
||||
|
||||
//----------------------------------------------------------------------------
|
||||
ioctl_pdb_code_t remote_pdb_access_t::send_ioctl(
|
||||
int fn,
|
||||
const void *buf,
|
||||
size_t size,
|
||||
void **outbuf,
|
||||
ssize_t *outsz)
|
||||
{
|
||||
if ( dbg == NULL )
|
||||
return pdb_error;
|
||||
|
||||
deb(IDA_DEBUG_DEBUGGER, "PDB: send_ioctl(fn=%d, size=%" FMT_Z ")\n", fn, size);
|
||||
// internal_ioctl() will either send the request to the debugger thread if
|
||||
// it exists (i.e., we are in a debugging session), or perform it directly.
|
||||
ioctl_pdb_code_t code = ioctl_pdb_code_t(internal_ioctl(fn, buf, size, outbuf, outsz));
|
||||
// ioctl_pdb_code_t code = ioctl_pdb_code_t(internal_ioctl dbg->send_ioctl(fn, buf, size, outbuf, outsz));
|
||||
deb(IDA_DEBUG_DEBUGGER, "PDB: send_ioctl(fn=%d) complete. Code=%d\n", fn, int(code));
|
||||
return code;
|
||||
}
|
||||
|
||||
//-------------------------------------------------------------------------
|
||||
HRESULT remote_pdb_access_t::_do_iterate_symbols_ids(
|
||||
const DWORD *ids,
|
||||
size_t count,
|
||||
enum SymTagEnum type,
|
||||
children_visitor_t &visitor)
|
||||
{
|
||||
HRESULT hr = S_OK;
|
||||
for ( size_t i = 0, n = count; i < n; ++i, ++ids )
|
||||
{
|
||||
DWORD tag;
|
||||
pdb_sym_t *cur = create_sym(*ids);
|
||||
pdb_sym_janitor_t janitor_cur(cur);
|
||||
if ( type == SymTagNull
|
||||
|| cur->get_symTag(&tag) == S_OK && tag == type )
|
||||
{
|
||||
hr = visitor.visit_child(*cur);
|
||||
if ( FAILED(hr) )
|
||||
break;
|
||||
}
|
||||
}
|
||||
return hr;
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------------
|
||||
HRESULT remote_pdb_access_t::do_iterate_children(
|
||||
pdb_sym_t &sym,
|
||||
enum SymTagEnum type,
|
||||
children_visitor_t &visitor)
|
||||
{
|
||||
sym_data_t *symbol;
|
||||
ioctl_pdb_code_t code = get_sym_data(sym, &symbol);
|
||||
QASSERT(30205, code == pdb_ok);
|
||||
QASSERT(30206, type < SymTagMax);
|
||||
sym_data_t::children_t &children = symbol->children_infos[type];
|
||||
if ( children.ids == NULL )
|
||||
{
|
||||
qvector<DWORD> children_ids;
|
||||
code = fetch_children_infos(sym, type, &children_ids);
|
||||
if ( code == pdb_ok )
|
||||
{
|
||||
children.cnt = children_ids.size();
|
||||
children.ids = children_ids.extract();
|
||||
}
|
||||
}
|
||||
|
||||
HRESULT hr = E_FAIL;
|
||||
if ( code == pdb_ok )
|
||||
hr = _do_iterate_symbols_ids(
|
||||
children.ids,
|
||||
children.cnt,
|
||||
type,
|
||||
visitor);
|
||||
return hr;
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------------
|
||||
HRESULT remote_pdb_access_t::load(pdb_sym_t &pdbsym, DWORD id)
|
||||
{
|
||||
sym_data_t *sd;
|
||||
if ( get_sym_data(id, &sd) != pdb_ok )
|
||||
return E_FAIL;
|
||||
QASSERT(30544, pdbsym.whoami() == REMOTE_PDB_SYM);
|
||||
remote_pdb_sym_t &sym = (remote_pdb_sym_t &)pdbsym;
|
||||
sym.set_symbol_data(sd);
|
||||
return S_OK;
|
||||
}
|
||||
|
||||
#define HAS_REMAINING_OR_FAIL(Ptr, End) \
|
||||
do \
|
||||
{ \
|
||||
if ( Ptr >= End ) \
|
||||
return E_FAIL; \
|
||||
} while ( false )
|
||||
|
||||
#define ALL_CONSUMED_OR_FAIL(Ptr, End) \
|
||||
do \
|
||||
{ \
|
||||
if ( Ptr != End ) \
|
||||
return E_FAIL; \
|
||||
} while ( false )
|
||||
|
||||
//-------------------------------------------------------------------------
|
||||
HRESULT remote_pdb_access_t::handle_fetch_lnnums(
|
||||
pdb_lnnums_t *out,
|
||||
const bytevec_t &resp) const
|
||||
{
|
||||
const uchar *ptr = resp.begin();
|
||||
const uchar *const end = resp.end();
|
||||
uint32 nlines = unpack_dd(&ptr, end);
|
||||
for ( uint32 i = 0; i < nlines; ++i )
|
||||
{
|
||||
HAS_REMAINING_OR_FAIL(ptr, end);
|
||||
pdb_lnnum_t &ln = out->push_back();
|
||||
ln.va = ULONGLONG(unpack_ea64(&ptr, end));
|
||||
ln.length = unpack_dd(&ptr, end);
|
||||
ln.columnNumber = unpack_dd(&ptr, end);
|
||||
ln.columnNumberEnd = unpack_dd(&ptr, end);
|
||||
ln.lineNumber = unpack_dd(&ptr, end);
|
||||
ln.lineNumberEnd = unpack_dd(&ptr, end);
|
||||
ln.file_id = unpack_dd(&ptr, end);
|
||||
ln.statement = unpack_db(&ptr, end);
|
||||
}
|
||||
ALL_CONSUMED_OR_FAIL(ptr, end);
|
||||
return S_OK;
|
||||
}
|
||||
|
||||
//-------------------------------------------------------------------------
|
||||
HRESULT remote_pdb_access_t::sip_retrieve_lines_by_va(
|
||||
pdb_lnnums_t *out,
|
||||
ULONGLONG va,
|
||||
ULONGLONG length)
|
||||
{
|
||||
bytevec_t req, resp;
|
||||
req.pack_ea64(va);
|
||||
req.pack_dq(length);
|
||||
ioctl_pdb_code_t code = perform_op(
|
||||
WIN32_IOCTL_PDB_SIP_FETCH_LINES_BY_VA, req, &resp);
|
||||
return code == pdb_ok ? handle_fetch_lnnums(out, resp) : E_FAIL;
|
||||
}
|
||||
|
||||
//-------------------------------------------------------------------------
|
||||
HRESULT remote_pdb_access_t::sip_retrieve_lines_by_coords(
|
||||
pdb_lnnums_t *out,
|
||||
DWORD file_id,
|
||||
int lnnum,
|
||||
int colnum)
|
||||
{
|
||||
bytevec_t req, resp;
|
||||
req.pack_dd(file_id);
|
||||
req.pack_dd(lnnum);
|
||||
req.pack_dd(colnum);
|
||||
ioctl_pdb_code_t code = perform_op(
|
||||
WIN32_IOCTL_PDB_SIP_FETCH_LINES_BY_COORDS, req, &resp);
|
||||
return code == pdb_ok ? handle_fetch_lnnums(out, resp) : E_FAIL;
|
||||
}
|
||||
|
||||
//-------------------------------------------------------------------------
|
||||
HRESULT remote_pdb_access_t::sip_iterate_symbols_at_ea(
|
||||
ULONGLONG va,
|
||||
ULONGLONG size,
|
||||
enum SymTagEnum tag,
|
||||
children_visitor_t &visitor)
|
||||
{
|
||||
qvector<DWORD> ids;
|
||||
bytevec_t req;
|
||||
req.pack_ea64(va);
|
||||
req.pack_dq(size);
|
||||
req.pack_dd(tag);
|
||||
ioctl_pdb_code_t code = perform_op(
|
||||
WIN32_IOCTL_PDB_SIP_FETCH_SYMBOLS_AT_VA, req, &ids);
|
||||
if ( code != pdb_ok )
|
||||
return E_FAIL;
|
||||
return _do_iterate_symbols_ids(
|
||||
ids.begin(),
|
||||
ids.size(),
|
||||
tag,
|
||||
visitor);
|
||||
}
|
||||
|
||||
//-------------------------------------------------------------------------
|
||||
HRESULT remote_pdb_access_t::sip_iterate_file_compilands(
|
||||
DWORD file_id,
|
||||
children_visitor_t &visitor)
|
||||
{
|
||||
qvector<DWORD> ids;
|
||||
bytevec_t req;
|
||||
req.pack_dd(file_id);
|
||||
ioctl_pdb_code_t code = perform_op(
|
||||
WIN32_IOCTL_PDB_SIP_FETCH_FILE_COMPILANDS, req, &ids);
|
||||
if ( code != pdb_ok )
|
||||
return E_FAIL;
|
||||
return _do_iterate_symbols_ids(
|
||||
ids.begin(),
|
||||
ids.size(),
|
||||
SymTagNull,
|
||||
visitor);
|
||||
}
|
||||
|
||||
//-------------------------------------------------------------------------
|
||||
HRESULT remote_pdb_access_t::sip_retrieve_file_path(
|
||||
qstring *out,
|
||||
qstring *,
|
||||
DWORD file_id)
|
||||
{
|
||||
bytevec_t req, resp;
|
||||
req.pack_dd(file_id);
|
||||
ioctl_pdb_code_t code = perform_op(
|
||||
WIN32_IOCTL_PDB_SIP_FETCH_FILE_PATH, req, &resp);
|
||||
if ( code != pdb_ok )
|
||||
return E_FAIL;
|
||||
|
||||
const uchar *ptr = resp.begin();
|
||||
const uchar *const end = resp.end();
|
||||
HAS_REMAINING_OR_FAIL(ptr, end);
|
||||
*out = unpack_str(&ptr, end);
|
||||
ALL_CONSUMED_OR_FAIL(ptr, end);
|
||||
return S_OK;
|
||||
}
|
||||
|
||||
//-------------------------------------------------------------------------
|
||||
HRESULT remote_pdb_access_t::handle_fetch_file_ids(
|
||||
qvector<DWORD> *out,
|
||||
const bytevec_t &resp) const
|
||||
{
|
||||
const uchar *ptr = resp.begin();
|
||||
const uchar *const end = resp.end();
|
||||
uint32 nfiles = unpack_dd(&ptr, end);
|
||||
out->resize(nfiles);
|
||||
for ( uint32 i = 0; i < nfiles; ++i )
|
||||
{
|
||||
HAS_REMAINING_OR_FAIL(ptr, end);
|
||||
out->at(i) = unpack_dd(&ptr, end);
|
||||
}
|
||||
ALL_CONSUMED_OR_FAIL(ptr, end);
|
||||
return S_OK;
|
||||
}
|
||||
|
||||
//-------------------------------------------------------------------------
|
||||
HRESULT remote_pdb_access_t::sip_retrieve_symbol_files(
|
||||
qvector<DWORD> *out,
|
||||
pdb_sym_t &pdbsym)
|
||||
{
|
||||
QASSERT(30538, pdbsym.whoami() == REMOTE_PDB_SYM);
|
||||
remote_pdb_sym_t &sym = (remote_pdb_sym_t &)pdbsym;
|
||||
bytevec_t req, resp;
|
||||
req.pack_dd(sym.data->get_id());
|
||||
ioctl_pdb_code_t code = perform_op(
|
||||
WIN32_IOCTL_PDB_SIP_FETCH_SYMBOL_FILES, req, &resp);
|
||||
return code == pdb_ok ? handle_fetch_file_ids(out, resp) : E_FAIL;
|
||||
}
|
||||
|
||||
//-------------------------------------------------------------------------
|
||||
HRESULT remote_pdb_access_t::sip_find_files(
|
||||
qvector<DWORD> *out,
|
||||
const char *fileName)
|
||||
{
|
||||
bytevec_t req, resp;
|
||||
req.pack_str(fileName);
|
||||
ioctl_pdb_code_t code = perform_op(
|
||||
WIN32_IOCTL_PDB_SIP_FIND_FILES, req, &resp);
|
||||
return code == pdb_ok ? handle_fetch_file_ids(out, resp) : E_FAIL;
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------------
|
||||
DWORD remote_pdb_access_t::build_and_register_sym_data(
|
||||
const uchar **raw,
|
||||
const uchar *end)
|
||||
{
|
||||
DWORD child_sym = unpack_dd(raw, end);
|
||||
token_mask_t tokens = unpack_dq(raw, end);
|
||||
uint32 datasz = unpack_dd(raw, end);
|
||||
const uchar *data = (const uchar *)unpack_obj_inplace(raw, end, datasz);
|
||||
cache[child_sym] = new sym_data_t(tokens, data, datasz, SYMDAT_PACKED, &warned);
|
||||
return child_sym;
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------------
|
||||
void remote_pdb_access_t::handle_fetch_response(
|
||||
const uchar **ptr,
|
||||
const uchar *end,
|
||||
qvector<DWORD> *ids_storage)
|
||||
{
|
||||
// Build cache!
|
||||
uint32 nchildren = 0;
|
||||
unpack_obj(&nchildren, sizeof(nchildren), ptr, end);
|
||||
if ( ids_storage != NULL )
|
||||
ids_storage->reserve(nchildren);
|
||||
for ( uint32 i = 0; i < nchildren; i++ )
|
||||
{
|
||||
DWORD created = build_and_register_sym_data(ptr, end);
|
||||
if ( ids_storage != NULL )
|
||||
ids_storage->push_back(created);
|
||||
}
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------------
|
||||
ioctl_pdb_code_t remote_pdb_access_t::perform_op(
|
||||
int op_type,
|
||||
const bytevec_t &oper,
|
||||
void *data)
|
||||
{
|
||||
void *outbuf = NULL;
|
||||
ssize_t outsize = 0;
|
||||
bytevec_t raw;
|
||||
QASSERT(30494, remote_session_id > 0);
|
||||
raw.pack_dd(remote_session_id);
|
||||
if ( !oper.empty() )
|
||||
raw.append(oper.begin(), oper.size());
|
||||
ioctl_pdb_code_t rc = send_ioctl(op_type, raw.begin(), raw.size(), &outbuf, &outsize);
|
||||
if ( rc != pdb_ok )
|
||||
REPORT_ERROR(
|
||||
"PDB symbol extraction is not supported by the remote server",
|
||||
rc);
|
||||
|
||||
// msg(" ok\n");
|
||||
|
||||
// By now, the operation will be done. Let's parse
|
||||
// the contents of the output buffer.
|
||||
const uchar *ptr = (const uchar *)outbuf;
|
||||
const uchar *const end = ptr + outsize;
|
||||
switch ( op_type )
|
||||
{
|
||||
case WIN32_IOCTL_PDB_FETCH_SYMBOL:
|
||||
case WIN32_IOCTL_PDB_FETCH_CHILDREN:
|
||||
case WIN32_IOCTL_PDB_SIP_FETCH_SYMBOLS_AT_VA:
|
||||
case WIN32_IOCTL_PDB_SIP_FETCH_FILE_COMPILANDS:
|
||||
QASSERT(30207, outsize >= (4 /*(unpacked) nchildren*/));
|
||||
handle_fetch_response(&ptr, end, (qvector<DWORD> *)data);
|
||||
break;
|
||||
case WIN32_IOCTL_PDB_SIP_FETCH_LINES_BY_VA:
|
||||
case WIN32_IOCTL_PDB_SIP_FETCH_LINES_BY_COORDS:
|
||||
case WIN32_IOCTL_PDB_SIP_FETCH_FILE_PATH:
|
||||
case WIN32_IOCTL_PDB_SIP_FETCH_SYMBOL_FILES:
|
||||
case WIN32_IOCTL_PDB_SIP_FIND_FILES:
|
||||
{
|
||||
bytevec_t *bvout = (bytevec_t *) data;
|
||||
bvout->append(outbuf, outsize);
|
||||
}
|
||||
break;
|
||||
case WIN32_IOCTL_PDB_CLOSE:
|
||||
break;
|
||||
default:
|
||||
INTERR(30208);
|
||||
}
|
||||
|
||||
qfree(outbuf);
|
||||
|
||||
return pdb_ok;
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------------
|
||||
ioctl_pdb_code_t remote_pdb_access_t::fetch_children_infos(
|
||||
pdb_sym_t &pdbsym,
|
||||
enum SymTagEnum type,
|
||||
qvector<DWORD> *children_ids)
|
||||
{
|
||||
QASSERT(30539, pdbsym.whoami() == REMOTE_PDB_SYM);
|
||||
remote_pdb_sym_t &sym = (remote_pdb_sym_t &)pdbsym;
|
||||
bytevec_t oper;
|
||||
oper.pack_dd(sym.data->get_id());
|
||||
oper.pack_dd(type);
|
||||
// msg("Fetching children: 0x%x", sym);
|
||||
return perform_op(WIN32_IOCTL_PDB_FETCH_CHILDREN, oper, children_ids);
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------------
|
||||
sym_data_t *remote_pdb_access_t::get_sym_data_from_cache(DWORD id)
|
||||
{
|
||||
typedef std::map<DWORD,sym_data_t*>::const_iterator citer;
|
||||
citer it = cache.find(id);
|
||||
if ( it != cache.end() )
|
||||
return it->second;
|
||||
return NULL;
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------------
|
||||
ioctl_pdb_code_t remote_pdb_access_t::get_sym_data(pdb_sym_t &pdbsym, sym_data_t **out)
|
||||
{
|
||||
QASSERT(30540, pdbsym.whoami() == REMOTE_PDB_SYM);
|
||||
remote_pdb_sym_t &sym = (remote_pdb_sym_t &)pdbsym;
|
||||
DWORD id = sym.data->get_id();
|
||||
return get_sym_data(id, out);
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------------
|
||||
ioctl_pdb_code_t remote_pdb_access_t::get_sym_data(DWORD id, sym_data_t **out)
|
||||
{
|
||||
sym_data_t *found = get_sym_data_from_cache(id);
|
||||
if ( found != NULL )
|
||||
{
|
||||
*out = found;
|
||||
return pdb_ok;
|
||||
}
|
||||
else
|
||||
{
|
||||
bytevec_t oper;
|
||||
oper.pack_dd(id);
|
||||
ioctl_pdb_code_t rc = perform_op(WIN32_IOCTL_PDB_FETCH_SYMBOL, oper, NULL);
|
||||
if ( rc == pdb_ok )
|
||||
{
|
||||
rc = get_sym_data(id, out);
|
||||
QASSERT(30209, rc == pdb_ok);
|
||||
}
|
||||
return rc;
|
||||
}
|
||||
}
|
||||
163
idasdk76/plugins/pdb/pdbremote.hpp
Normal file
163
idasdk76/plugins/pdb/pdbremote.hpp
Normal file
@@ -0,0 +1,163 @@
|
||||
|
||||
#ifndef PDBREMOTE_HPP
|
||||
#define PDBREMOTE_HPP
|
||||
|
||||
#include <network.hpp>
|
||||
#include "../../dbg/win32/win32_rpc.h"
|
||||
#include "pdbaccess.hpp"
|
||||
|
||||
// The PDB related code that works on Unix
|
||||
// It connects to a Windows computer and asks to retrieve PDB info
|
||||
|
||||
//----------------------------------------------------------------------------
|
||||
bool is_win32_remote_debugger_loaded();
|
||||
|
||||
//----------------------------------------------------------------------------
|
||||
//-V:remote_pdb_access_t:730 not all members of a class are initialized inside the constructor
|
||||
class remote_pdb_access_t : public pdb_access_t
|
||||
{
|
||||
public:
|
||||
remote_pdb_access_t(
|
||||
const pdbargs_t &args,
|
||||
const char *_host,
|
||||
int _port,
|
||||
const char *_pwd)
|
||||
: pdb_access_t(args),
|
||||
host(_host),
|
||||
port(_port),
|
||||
pwd(_pwd),
|
||||
remote_session_id(-1)
|
||||
{
|
||||
set_base_address(args.loaded_base);
|
||||
}
|
||||
|
||||
virtual ~remote_pdb_access_t();
|
||||
|
||||
// Open connection, create PDB session.
|
||||
HRESULT open_connection();
|
||||
// Close PDB session, close connection.
|
||||
void close_connection();
|
||||
|
||||
virtual HRESULT do_iterate_children(
|
||||
pdb_sym_t &sym,
|
||||
enum SymTagEnum type,
|
||||
children_visitor_t &visitor) override;
|
||||
virtual HRESULT load(pdb_sym_t &sym, DWORD id) override;
|
||||
|
||||
virtual HRESULT sip_retrieve_lines_by_va(
|
||||
pdb_lnnums_t *out,
|
||||
ULONGLONG va,
|
||||
ULONGLONG length) override;
|
||||
virtual HRESULT sip_retrieve_lines_by_coords(
|
||||
pdb_lnnums_t *out,
|
||||
DWORD file_id,
|
||||
int lnnum,
|
||||
int colnum) override;
|
||||
virtual HRESULT sip_iterate_symbols_at_ea(
|
||||
ULONGLONG va,
|
||||
ULONGLONG size,
|
||||
enum SymTagEnum tag,
|
||||
children_visitor_t &visitor) override;
|
||||
virtual HRESULT sip_iterate_file_compilands(
|
||||
DWORD file_id,
|
||||
children_visitor_t &visitor) override;
|
||||
virtual HRESULT sip_retrieve_file_path(
|
||||
qstring *out,
|
||||
qstring *errbuf,
|
||||
DWORD file_id) override;
|
||||
virtual HRESULT sip_retrieve_symbol_files(
|
||||
qvector<DWORD> *out,
|
||||
pdb_sym_t &sym) override;
|
||||
virtual HRESULT sip_find_files(
|
||||
qvector<DWORD> *out,
|
||||
const char *name) override;
|
||||
|
||||
virtual pdb_sym_t *create_sym(void *data, bool) override
|
||||
{
|
||||
sym_data_t *sym = (sym_data_t *)data;
|
||||
return new remote_pdb_sym_t(this, sym);
|
||||
}
|
||||
pdb_sym_t *create_sym(DWORD sym_id) { return pdb_access_t::create_sym(sym_id); }
|
||||
|
||||
// Possibly remote operation.
|
||||
// If NULL is returned, it means the symbol is not available, nor
|
||||
// could it be fetched remotely.
|
||||
ioctl_pdb_code_t get_sym_data(pdb_sym_t &sym, sym_data_t **);
|
||||
ioctl_pdb_code_t get_sym_data(DWORD sym_id, sym_data_t **);
|
||||
|
||||
|
||||
private:
|
||||
HRESULT _do_iterate_symbols_ids(
|
||||
const DWORD *ids,
|
||||
size_t count,
|
||||
enum SymTagEnum type,
|
||||
children_visitor_t &visitor);
|
||||
|
||||
#define SAFE_GET(type) \
|
||||
sym_data_t *sym_data; \
|
||||
ioctl_pdb_code_t result = get_sym_data(sym, &sym_data); \
|
||||
if ( result == pdb_ok ) \
|
||||
return sym_data->get_##type(token, out); \
|
||||
else \
|
||||
return E_FAIL
|
||||
|
||||
// Build sym_data_t instance, and register it into the 'cache'.
|
||||
DWORD build_and_register_sym_data(const uchar **raw, const uchar *end);
|
||||
|
||||
// Whenever fetch_children_infos() or get_sym_data() performs
|
||||
// a remote operation, this is used to handle the response
|
||||
// and add the fetched symbol data to the cache.
|
||||
void handle_fetch_response(
|
||||
const uchar **ptr,
|
||||
const uchar *end,
|
||||
qvector<DWORD> *ids_storage);
|
||||
|
||||
// Remote operation.
|
||||
ioctl_pdb_code_t fetch_children_infos(
|
||||
pdb_sym_t &sym,
|
||||
enum SymTagEnum type,
|
||||
qvector<DWORD> *children_ids);
|
||||
|
||||
HRESULT handle_fetch_lnnums(
|
||||
pdb_lnnums_t *out,
|
||||
const bytevec_t &resp) const;
|
||||
|
||||
HRESULT handle_fetch_file_ids(
|
||||
qvector<DWORD> *out,
|
||||
const bytevec_t &resp) const;
|
||||
|
||||
sym_data_t *get_sym_data_from_cache(DWORD id);
|
||||
|
||||
// Low-level interface used by open_connection(), fetch_children_infos(), and get_sym_data().
|
||||
// 'fetch_type' is one of
|
||||
// WIN32_IOCTL_PDB_OPEN,
|
||||
// WIN32_IOCTL_PDB_FETCH_SYMBOL,
|
||||
// WIN32_IOCTL_PDB_FETCH_CHILDREN
|
||||
ioctl_pdb_code_t perform_op(int op_type, const bytevec_t &oper, void *data);
|
||||
|
||||
ioctl_pdb_code_t send_ioctl(
|
||||
int fn,
|
||||
const void *buf,
|
||||
size_t size,
|
||||
void **poutbuf,
|
||||
ssize_t *poutsize);
|
||||
|
||||
std::map<DWORD, sym_data_t*> cache;
|
||||
const char *user_spath;
|
||||
char errbuf[MAXSTR];
|
||||
|
||||
// For the moment, we'll channel all IOCTL requests
|
||||
// through the debugger. Ideally, we should be able to just
|
||||
// use a RPC client.
|
||||
bool load_win32_debugger(void);
|
||||
|
||||
const char *host;
|
||||
int port;
|
||||
const char *pwd;
|
||||
bool was_connected;
|
||||
bool is_dbg_module;
|
||||
int remote_session_id;
|
||||
bool warned = false;
|
||||
};
|
||||
|
||||
#endif // PDBREMOTE_HPP
|
||||
1294
idasdk76/plugins/pdb/sip.cpp
Normal file
1294
idasdk76/plugins/pdb/sip.cpp
Normal file
File diff suppressed because it is too large
Load Diff
9
idasdk76/plugins/pdb/sip.hpp
Normal file
9
idasdk76/plugins/pdb/sip.hpp
Normal file
@@ -0,0 +1,9 @@
|
||||
|
||||
#ifndef PDB_SIP_H
|
||||
#define PDB_SIP_H
|
||||
|
||||
bool apply_debug_info(pdbargs_t &pdbargs);
|
||||
|
||||
#include "pdbaccess.hpp"
|
||||
|
||||
#endif // PDB_SIP_H
|
||||
2424
idasdk76/plugins/pdb/tilbuild.cpp
Normal file
2424
idasdk76/plugins/pdb/tilbuild.cpp
Normal file
File diff suppressed because it is too large
Load Diff
216
idasdk76/plugins/pdb/tilbuild.hpp
Normal file
216
idasdk76/plugins/pdb/tilbuild.hpp
Normal file
@@ -0,0 +1,216 @@
|
||||
#pragma once
|
||||
|
||||
//----------------------------------------------------------------------------
|
||||
enum cvt_code_t
|
||||
{
|
||||
cvt_failed,
|
||||
cvt_ok,
|
||||
cvt_typedef // conversion resulted in a typedef to a named type
|
||||
};
|
||||
|
||||
//----------------------------------------------------------------------------
|
||||
// PBD provides the offset of a bitfield inside a bitfield group.
|
||||
// We subclass udt_member_t in order to keep that information separate from
|
||||
// the 'offset' field.
|
||||
struct pdb_udt_member_t : public udt_member_t
|
||||
{
|
||||
uint32 bit_offset; ///< member offset in bits from start of bitfield group
|
||||
};
|
||||
DECLARE_TYPE_AS_MOVABLE(pdb_udt_member_t);
|
||||
typedef qvector<pdb_udt_member_t> pdbudtmembervec_t; ///< vector of pdb udt member objects
|
||||
|
||||
//----------------------------------------------------------------------------
|
||||
// stripped-down version of udt_type_data_t with only the fields used by pdb.
|
||||
struct pdb_udt_type_data_t : public pdbudtmembervec_t
|
||||
{
|
||||
size_t total_size; ///< total structure size in bytes
|
||||
uint32 taudt_bits; ///< TA... and TAUDT... bits
|
||||
bool is_union; ///< is union or struct?
|
||||
|
||||
pdb_udt_type_data_t(void)
|
||||
: total_size(0),
|
||||
taudt_bits(0),
|
||||
is_union(false)
|
||||
{
|
||||
}
|
||||
|
||||
void convert_to_tinfo_udt(udt_type_data_t *out);
|
||||
};
|
||||
DECLARE_TYPE_AS_MOVABLE(pdb_udt_type_data_t);
|
||||
|
||||
//----------------------------------------------------------------------------
|
||||
class til_builder_t
|
||||
{
|
||||
protected:
|
||||
pdb_ctx_t &pv;
|
||||
public:
|
||||
|
||||
//----------------------------------------------------------------------------
|
||||
struct tpinfo_t
|
||||
{
|
||||
cvt_code_t cvt_code;
|
||||
bool is_notype;
|
||||
tinfo_t type;
|
||||
til_t *ti; // FIXME: do we need this?
|
||||
tpinfo_t(void) : cvt_code(cvt_ok), is_notype(false), ti(NULL) {}
|
||||
tpinfo_t(til_t *_ti, const tinfo_t &t) : cvt_code(cvt_ok), is_notype(false), type(t), ti(_ti) {}
|
||||
const char *dstr(void) const
|
||||
{
|
||||
if ( cvt_code == cvt_failed )
|
||||
return "#cvt_failed";
|
||||
|
||||
static qstring res;
|
||||
if ( !type.print(&res) )
|
||||
res = "#print_failed";
|
||||
return res.c_str();
|
||||
}
|
||||
};
|
||||
|
||||
//----------------------------------------------------------------------------
|
||||
til_builder_t(pdb_ctx_t &_pv, til_t *_ti, pdb_access_t *_pa)
|
||||
: pv(_pv),
|
||||
unnamed_idx(0),
|
||||
level(0),
|
||||
ti(_ti),
|
||||
pdb_access(NULL),
|
||||
enregistered_bug(false)
|
||||
{
|
||||
set_pdb_access(_pa);
|
||||
}
|
||||
|
||||
virtual ~til_builder_t()
|
||||
{
|
||||
typemap.clear();
|
||||
tpdefs.clear();
|
||||
handled.clear();
|
||||
creating.clear();
|
||||
unnamed_types.clear();
|
||||
}
|
||||
|
||||
void set_pdb_access(pdb_access_t *_pdb_access)
|
||||
{
|
||||
pdb_access = _pdb_access;
|
||||
}
|
||||
|
||||
typedef std::map<DWORD, tpinfo_t> typemap_t;
|
||||
typedef std::map<DWORD, tinfo_t> tpdefs_t;
|
||||
typedef std::set<DWORD> idset_t;
|
||||
typedef std::map<qstring, int> creating_t;
|
||||
typedef std::set<uint32> unnamed_t;
|
||||
|
||||
struct vft_info_t
|
||||
{
|
||||
udt_type_data_t udt; // collected vft members
|
||||
qstring base0; // base vftable at offset 0
|
||||
|
||||
vft_info_t() { udt.taudt_bits |= TAUDT_VFTABLE; }
|
||||
bool empty() const { return udt.empty() && base0.empty(); }
|
||||
};
|
||||
typedef std::map<qstring, vft_info_t> vftmap_t;
|
||||
|
||||
// remove `anonymous-namespace'::
|
||||
// also remove `anonymous namespace'::
|
||||
void remove_anonymous_namespaces(qstring &storage);
|
||||
|
||||
bool get_symbol_type(tpinfo_t *out, pdb_sym_t &sym, int *p_id);
|
||||
bool retrieve_type(tpinfo_t *out, pdb_sym_t &sym, pdb_sym_t *parent, int *p_id);
|
||||
bool retrieve_arguments(
|
||||
pdb_sym_t &sym,
|
||||
func_type_data_t &fi,
|
||||
pdb_sym_t *funcSym);
|
||||
cm_t convert_cc(DWORD cc0) const;
|
||||
bool get_variant_string_value(qstring *out, pdb_sym_t &sym) const;
|
||||
uint32 get_variant_long_value(pdb_sym_t &sym) const;
|
||||
bool begin_creation(DWORD tag, const qstring &name, uint32 *p_id);
|
||||
uint32 end_creation(const qstring &name);
|
||||
bool is_member_func(tinfo_t *class_type, pdb_sym_t &typeSym, pdb_sym_t *funcSym);
|
||||
bool is_frame_reg(int regnum) const;
|
||||
bool is_complex_return(pdb_sym_t &sym) const;
|
||||
bool is_unnamed_tag_typedef(const tinfo_t &tif) const;
|
||||
bool is_intel386(DWORD machine_type) const;
|
||||
bool is_arm(DWORD machine_type) const;
|
||||
int get_symbol_funcarg_info(
|
||||
funcarg_t *out,
|
||||
pdb_sym_t &sym,
|
||||
DWORD /*dwDataKind*/,
|
||||
DWORD locType,
|
||||
int stack_off);
|
||||
void enum_function_args(pdb_sym_t &sym, func_type_data_t &args);
|
||||
cvt_code_t verify_struct(pdb_udt_type_data_t &udt) const;
|
||||
cvt_code_t verify_union(
|
||||
pdb_udt_type_data_t *out,
|
||||
pdb_udt_type_data_t::iterator p1,
|
||||
pdb_udt_type_data_t::const_iterator p2) const;
|
||||
cvt_code_t create_union(
|
||||
tinfo_t *out,
|
||||
size_t *p_total_size,
|
||||
pdb_udt_type_data_t::iterator p1,
|
||||
pdb_udt_type_data_t::const_iterator p2) const;
|
||||
cvt_code_t convert_basetype(tpinfo_t *out, DWORD baseType, int size) const;
|
||||
cvt_code_t make_vtable_struct(tinfo_t *out, pdb_sym_t &sym);
|
||||
cvt_code_t convert_udt(tinfo_t *out, pdb_sym_t &sym, DWORD64 size);
|
||||
cvt_code_t create_udt(tinfo_t *out, pdb_udt_type_data_t *udt, int udtKind, const char *udt_name) const;
|
||||
cvt_code_t create_udt_ref(tinfo_t *out, pdb_udt_type_data_t *udt, int udt_kind) const;
|
||||
cvt_code_t really_convert_type(tpinfo_t *out, pdb_sym_t &sym, pdb_sym_t *parent, DWORD tag);
|
||||
cvt_code_t convert_type(
|
||||
tpinfo_t *out,
|
||||
pdb_sym_t &sym,
|
||||
pdb_sym_t *parent,
|
||||
DWORD type,
|
||||
DWORD tag);
|
||||
cvt_code_t handle_overlapping_members(pdb_udt_type_data_t *udt) const;
|
||||
// Will iterate on children, and call handle_function_child()
|
||||
HRESULT handle_symbols(pdb_sym_t &pGlobal);
|
||||
HRESULT handle_globals(pdb_sym_t &pGlobal);
|
||||
HRESULT handle_publics(pdb_sym_t &pGlobal);
|
||||
HRESULT handle_types(pdb_sym_t &pGlobal);
|
||||
HRESULT build(pdb_sym_t &pGlobal);
|
||||
ea_t get_load_address() const { return pdb_access->get_base_address(); }
|
||||
HRESULT handle_symbol(pdb_sym_t &sym);
|
||||
size_t get_symbol_type_length(pdb_sym_t &sym) const;
|
||||
void create_vftables();
|
||||
// check for MS or IDA vftable name,
|
||||
// get type ordinal of vftable
|
||||
// returns the type is creating
|
||||
bool get_vft_name(qstring *vft_name, uint32 *ord, const char *udt_name, uint32_t offset=0);
|
||||
|
||||
virtual HRESULT before_iterating(pdb_sym_t &global_sym);
|
||||
virtual HRESULT after_iterating(pdb_sym_t &global_sym);
|
||||
virtual bool iterate_symbols_once_more(pdb_sym_t & /*global_sym*/) { return false; }
|
||||
virtual bool get_symbol_name(pdb_sym_t &sym, qstring &storage);
|
||||
virtual bool handle_symbol_at_ea(
|
||||
pdb_sym_t &sym,
|
||||
DWORD tag,
|
||||
ea_t ea,
|
||||
qstring &name);
|
||||
virtual void type_created(ea_t /*ea*/, int /*id*/, const char * /*name*/, const tinfo_t & /*ptr*/) const;
|
||||
virtual void handle_function_type(pdb_sym_t &fun_sym, ea_t ea);
|
||||
virtual HRESULT handle_function_child(
|
||||
pdb_sym_t &fun_sym,
|
||||
ea_t ea,
|
||||
pdb_sym_t &child_sym,
|
||||
DWORD child_tag,
|
||||
DWORD child_loc_type);
|
||||
virtual cvt_code_t handle_unnamed_overlapping_member(
|
||||
pdb_udt_type_data_t * /*udt*/,
|
||||
qstack<qstring> * /*union_names*/,
|
||||
qstring * /*name*/) const
|
||||
{
|
||||
return cvt_ok;
|
||||
}
|
||||
|
||||
protected:
|
||||
typemap_t typemap; // id -> type info
|
||||
tpdefs_t tpdefs; // id -> enum type defined in base til
|
||||
idset_t handled; // set of handled symbols
|
||||
creating_t creating;
|
||||
unnamed_t unnamed_types;
|
||||
vftmap_t vftmap; // vftable name -> vft info
|
||||
int unnamed_idx;
|
||||
int level;
|
||||
|
||||
public:
|
||||
til_t *ti;
|
||||
pdb_access_t *pdb_access;
|
||||
bool enregistered_bug;
|
||||
};
|
||||
198
idasdk76/plugins/pdb/varser.hpp
Normal file
198
idasdk76/plugins/pdb/varser.hpp
Normal file
@@ -0,0 +1,198 @@
|
||||
|
||||
#ifndef VARSER_HPP
|
||||
#define VARSER_HPP
|
||||
|
||||
// Variant serializer/deserializer.
|
||||
struct varser_t
|
||||
{
|
||||
#ifdef __NT__
|
||||
static bool serialize(bytevec_t &out, const VARIANT &var);
|
||||
#else
|
||||
static bool deserialize(VARIANT &var, const uchar **in, const uchar *const end);
|
||||
#endif
|
||||
};
|
||||
|
||||
#ifdef __NT__
|
||||
//-------------------------------------------------------------------------
|
||||
bool varser_t::serialize(bytevec_t &out, const VARIANT &var)
|
||||
{
|
||||
out.pack_dw(var.vt);
|
||||
if ( (var.vt & VT_BYREF) == VT_BYREF
|
||||
|| (var.vt & VT_ARRAY) == VT_ARRAY )
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
const size_t sz_before = out.size();
|
||||
switch ( var.vt )
|
||||
{
|
||||
case VT_EMPTY: // = 0x0000,
|
||||
case VT_NULL: // = 0x0001,
|
||||
break;
|
||||
case VT_I2: // = 0x0002,
|
||||
case VT_UI2: // = 0x0012,
|
||||
out.pack_dw(var.uiVal);
|
||||
break;
|
||||
case VT_I4: // = 0x0003,
|
||||
case VT_UI4: // = 0x0013,
|
||||
out.pack_dd(var.ulVal);
|
||||
break;
|
||||
case VT_R4: // = 0x0004,
|
||||
out.pack_dd(*(uint32*)&var.fltVal);
|
||||
break;
|
||||
case VT_R8: // = 0x0005,
|
||||
out.pack_dq(*(uint64*)&var.dblVal);
|
||||
break;
|
||||
case VT_CY: // = 0x0006,
|
||||
case VT_DATE: // = 0x0007,
|
||||
break;
|
||||
case VT_BSTR: // = 0x0008,
|
||||
{
|
||||
uint8 *ptr = (uint8*) var.bstrVal;
|
||||
ptr -= 4;
|
||||
uint32 bcnt = * (uint32*) ptr;
|
||||
out.pack_buf(ptr + 4, bcnt);
|
||||
}
|
||||
break;
|
||||
case VT_DISPATCH: // = 0x0009,
|
||||
case VT_ERROR: // = 0x000A,
|
||||
case VT_BOOL: // = 0x000B,
|
||||
case VT_VARIANT: // = 0x000C,
|
||||
case VT_UNKNOWN: // = 0x000D,
|
||||
case VT_DECIMAL: // = 0x000E,
|
||||
case VT_I1: // = 0x0010,
|
||||
case VT_UI1: // = 0x0011,
|
||||
out.pack_db(var.bVal);
|
||||
break;
|
||||
case VT_I8: // = 0x0014,
|
||||
case VT_UI8: // = 0x0015,
|
||||
out.pack_dq(var.ullVal);
|
||||
break;
|
||||
case VT_INT: // = 0x0016,
|
||||
case VT_UINT: // = 0x0017,
|
||||
case VT_HRESULT: // = 0x0019,
|
||||
out.pack_dd(var.uintVal);
|
||||
break;
|
||||
case VT_VOID: // = 0x0018,
|
||||
case VT_PTR: // = 0x001A,
|
||||
case VT_SAFEARRAY: // = 0x001B,
|
||||
case VT_CARRAY: // = 0x001C,
|
||||
case VT_USERDEFINED: // = 0x001D,
|
||||
case VT_LPSTR: // = 0x001E,
|
||||
case VT_LPWSTR: // = 0x001F,
|
||||
case VT_RECORD: // = 0x0024,
|
||||
case VT_INT_PTR: // = 0x0025,
|
||||
case VT_UINT_PTR: // = 0x0026,
|
||||
break;
|
||||
default: break;
|
||||
}
|
||||
return out.size() > sz_before;
|
||||
}
|
||||
#else
|
||||
//-------------------------------------------------------------------------
|
||||
bool varser_t::deserialize(VARIANT &var, const uchar **in, const uchar *const end)
|
||||
{
|
||||
var.vt = unpack_dw(in, end);
|
||||
if ( (var.vt & VT_BYREF) == VT_BYREF
|
||||
|| (var.vt & VT_ARRAY) == VT_ARRAY )
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
bool ok = false;
|
||||
switch ( var.vt )
|
||||
{
|
||||
case VT_EMPTY: // = 0x0000,
|
||||
case VT_NULL: // = 0x0001,
|
||||
break;
|
||||
case VT_I2: // = 0x0002,
|
||||
case VT_UI2: // = 0x0012,
|
||||
var.uiVal = unpack_dw(in, end);
|
||||
ok = true;
|
||||
break;
|
||||
case VT_I4: // = 0x0003,
|
||||
case VT_UI4: // = 0x0013,
|
||||
var.ulVal = unpack_dd(in, end);
|
||||
ok = true;
|
||||
break;
|
||||
case VT_R4: // = 0x0004,
|
||||
{
|
||||
uint32 res = unpack_dd(in, end);
|
||||
var.fltVal = *(FLOAT*)&res;
|
||||
ok = true;
|
||||
}
|
||||
break;
|
||||
case VT_R8: // = 0x0005,
|
||||
{
|
||||
uint64 res = unpack_dq(in, end);
|
||||
var.dblVal = *(DOUBLE*)&res;
|
||||
ok = true;
|
||||
}
|
||||
break;
|
||||
case VT_CY: // = 0x0006,
|
||||
case VT_DATE: // = 0x0007,
|
||||
break;
|
||||
case VT_BSTR: // = 0x0008,
|
||||
{
|
||||
uint32 bcnt = unpack_dd(in, end);
|
||||
uint32 nbytes = bcnt + 4 + 2; // +2 for terminating null character
|
||||
QASSERT(30472, nbytes > bcnt); // check for integer overflow
|
||||
uint8 *raw = (uint8 *)qalloc(nbytes);
|
||||
if ( raw != NULL )
|
||||
{
|
||||
*(uint32*)raw = bcnt;
|
||||
raw += 4;
|
||||
unpack_obj(raw, bcnt, in, end);
|
||||
raw[bcnt] = '\0';
|
||||
raw[bcnt+1] = '\0';
|
||||
var.bstrVal = raw;
|
||||
ok = true;
|
||||
}
|
||||
}
|
||||
break;
|
||||
case VT_LPSTR: // = 0x001E,
|
||||
case VT_LPWSTR: // = 0x001F,
|
||||
{
|
||||
char *tmp = qstrdup(unpack_str(in, end));
|
||||
var.byref = tmp;
|
||||
ok = true;
|
||||
}
|
||||
break;
|
||||
case VT_DISPATCH: // = 0x0009,
|
||||
case VT_ERROR: // = 0x000A,
|
||||
case VT_BOOL: // = 0x000B,
|
||||
case VT_VARIANT: // = 0x000C,
|
||||
case VT_UNKNOWN: // = 0x000D,
|
||||
case VT_DECIMAL: // = 0x000E,
|
||||
case VT_I1: // = 0x0010,
|
||||
case VT_UI1: // = 0x0011,
|
||||
var.bVal = unpack_db(in, end);
|
||||
ok = true;
|
||||
break;
|
||||
case VT_I8: // = 0x0014,
|
||||
case VT_UI8: // = 0x0015,
|
||||
var.ullVal = unpack_dq(in, end);
|
||||
ok = true;
|
||||
break;
|
||||
case VT_INT: // = 0x0016,
|
||||
case VT_UINT: // = 0x0017,
|
||||
case VT_HRESULT: // = 0x0019,
|
||||
var.uintVal = unpack_dd(in, end);
|
||||
ok = true;
|
||||
break;
|
||||
case VT_VOID: // = 0x0018,
|
||||
case VT_PTR: // = 0x001A,
|
||||
case VT_SAFEARRAY: // = 0x001B,
|
||||
case VT_CARRAY: // = 0x001C,
|
||||
case VT_USERDEFINED: // = 0x001D,
|
||||
case VT_RECORD: // = 0x0024,
|
||||
case VT_INT_PTR: // = 0x0025,
|
||||
case VT_UINT_PTR: // = 0x0026,
|
||||
break;
|
||||
default: break;
|
||||
}
|
||||
return ok;
|
||||
}
|
||||
#endif // __NT__
|
||||
|
||||
#endif // VARSER_HPP
|
||||
Reference in New Issue
Block a user