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

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;
}
}