#include #include "pdbremote.hpp" #include "varser.hpp" // Since we're using the win32 local stup debugger at the moment, // this is necessary. #include //------------------------------------------------------------------------- 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::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 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 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 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 *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 *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 *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 *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 *)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 *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::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; } }