218 lines
6.3 KiB
C++
218 lines
6.3 KiB
C++
//
|
|
// 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;
|