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

662 lines
23 KiB
C++

#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