899 lines
26 KiB
C++
899 lines
26 KiB
C++
|
|
#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;
|
|
}
|
|
}
|