1285 lines · 40.1 KB · C++
RawDownload
       << "Break on module load: " << std::boolalpha << util::has_flag(o, debugger_options::break_on_module_load) << "\n"       << "Break on exception: " << std::boolalpha << util::has_flag(o, debugger_options::break_on_exception) << "\n";     return ss;} debugger::debugger(const debugger_options opt)    : _options{ opt }    , _tool_id{ 0 }    , controller{ nullptr }{ } std::vector<std::string> debugger::resolve_to_function_source_line(    disvm::runtime::module_id_t vm_id,    vm_pc_t begin_pc,    vm_pc_t end_pc,    symbol::function_name_format_t fmt) const{    auto iter = _vm_id_to_symbol_info.find(vm_id);    if (iter == std::cend(_vm_id_to_symbol_info))        return{};     auto &d = *(iter->second.iter);     // Position the debug symbol iterator    d.set_current_pc(begin_pc);     std::vector<std::string> resolved_functions_by_pc(end_pc - begin_pc + 1);    vm_pc_t next_pc = begin_pc;    do    {        if (next_pc > end_pc)            break;         std::stringstream ss;        const auto function_name = d.current_function_name(fmt);        if (!function_name.empty())            ss << function_name << " at ";         const auto source_loc = d.current_source_location();        ss << d.get_source_by_id(source_loc.source_id)            << ':'            << source_loc.begin_line;         resolved_functions_by_pc[next_pc - begin_pc] = std::move(ss.str());     } while (d.try_advance_pc(symbol::advance_pc_t::next_debug_statement, &next_pc));     return resolved_functions_by_pc;} std::vector<std::string> debugger::get_module_functions(disvm::runtime::module_id_t vm_id, const char *match) const{    std::vector<std::string> funcs;    auto iter = _vm_id_to_symbol_info.find(vm_id);    if (iter != std::cend(_vm_id_to_symbol_info))    {        auto f_infos = iter->second.data->get_functions(symbol::function_name_format_t::declaration);        for (auto &fi : f_infos)        {            // Only return functions that match the supplied string            if (match != nullptr                && fi.name.find(match) == std::string::npos)                continue;             std::stringstream ss;            ss << "["                << std::setw(5) << fi.entry_pc                << ","                << std::setw(5) << fi.limit_pc                << "]  "                << fi.name;             funcs.push_back(ss.str());        }    }     return funcs;} bool debugger::symbols_exist(disvm::runtime::module_id_t vm_id) const{    return _vm_id_to_symbol_info.find(vm_id) != std::cend(_vm_id_to_symbol_info);} std::string debugger::get_option(const std::string &option) const{    auto iter = _debugger_options.find(option);    if (iter == std::cend(_debugger_options))        return{};     return iter->second;} void debugger::set_option(const std::string &option, std::string value){    _debugger_options[option] = std::move(value);} void debugger::on_load(vm_tool_controller_t &controller_, std::size_t tool_id){    _tool_id = tool_id;    controller = &controller_;     _event_cookies.emplace(controller->subscribe_event(vm_event_t::thread_begin, [](vm_event_t, vm_event_context_t &cxt)    {        auto t = cxt.value1.thread;        auto ss = std::stringstream{};        ss << "Thread "            << t->get_thread_id()            << " started in "            << t->get_registers().module_ref->module->module_name->str()            << " @"            << t->get_registers().pc;         debug_print_info(ss.str());    }));     _event_cookies.emplace(controller->subscribe_event(vm_event_t::thread_end, [](vm_event_t, vm_event_context_t &cxt)    {        auto ss = std::stringstream{};        ss << "Thread "            << cxt.value1.thread->get_thread_id()            << " ended.";         debug_print_info(ss.str());    }));     _event_cookies.emplace(controller->subscribe_event(vm_event_t::exception_raised, [&](vm_event_t, vm_event_context_t &cxt)    {        auto ss = std::stringstream{};        ss << "Exception '"            << cxt.value2.str->str()            << "' thrown.";         debug_print_info(ss.str());         if (util::has_flag(_options, debugger_options::break_on_exception))            prompt(*this, *cxt.value1.registers);    }));     _event_cookies.emplace(controller->subscribe_event(vm_event_t::exception_unhandled, [&](vm_event_t, vm_event_context_t &cxt)    {        auto ss = std::stringstream{};        ss << "Unhandled exception '"            << cxt.value2.str->str()            << "'";         debug_print_error(ss.str());        prompt(*this, *cxt.value1.registers);    }));     _event_cookies.emplace(controller->subscribe_event(vm_event_t::module_vm_load, [&](vm_event_t, vm_event_context_t &cxt)    {        auto loaded_mod = cxt.value1.loaded_mod;        assert(loaded_mod != nullptr);        load_symbols(*loaded_mod);    }));     _event_cookies.emplace(controller->subscribe_event(vm_event_t::module_thread_load, [&](vm_event_t, vm_event_context_t &cxt)    {        auto m = (*cxt.value2.module);        auto ss = std::stringstream{};        ss << "Module "            << m->module_name->str()            << " loaded";         if (util::has_flag(m->header.runtime_flag, runtime_flags_t::builtin))            ss << " (built-in)";         debug_print_info(ss.str());         // If the break on enter flag was set, it will be true        // and the first module load will be the user entry module.        if (util::has_flag(_options, debugger_options::break_on_enter))        {            // Reset the break on enter flag and set a breakpoint            // on the entry PC for the module - 'break on enter'            _options ^= debugger_options::break_on_enter;            breakpoint_cookies.emplace(controller->set_breakpoint(m, m->header.entry_pc));        }         if (util::has_flag(_options, debugger_options::break_on_module_load))            prompt(*this, *cxt.value1.registers);    }));     _event_cookies.emplace(controller->subscribe_event(vm_event_t::breakpoint, [&](vm_event_t, vm_event_context_t &cxt)    {        auto ss = std::stringstream{};        ss << "Breakpoint hit";        if (cxt.value2.cookie != 0)            ss << " [" << cxt.value2.cookie << "]";         debug_print_info(ss.str());         auto bp_cmd = get_option({ "bp-cmd" });        if (!bp_cmd.empty())        {            dbg_cmd_cxt_t dbg_cxt{ *this, *cxt.value1.registers };            execute_single_command(dbg_cxt, std::move(bp_cmd));        }         prompt(*this, *cxt.value1.registers);    }));} void debugger::on_unload(){    assert(controller != nullptr);     for (auto ec : _event_cookies)        controller->unsubscribe_event(ec);     controller = nullptr;} void debugger::load_symbols(const disvm::loaded_vm_module_t &loaded_mod){    auto m = loaded_mod.module.lock();    assert(m != nullptr && "Loaded module event should have valid module reference");     auto symbol_extension = ".sbl";    std::string symbol_path_maybe{ loaded_mod.origin->str() };    const auto ext_index = symbol_path_maybe.find_last_of('.');    if (ext_index == std::string::npos)    {        // Module doesn't have an extension so just append the symbol extension.        symbol_path_maybe.append(symbol_extension);    }    else    {        // Replace the module extension with the symbol extension.        symbol_path_maybe.replace(ext_index, std::string::npos, symbol_extension);    }     std::ifstream sbl_file{ symbol_path_maybe, std::ifstream::in };    if (!sbl_file.is_open())        return;     std::unique_ptr<symbol::symbol_data_t> symbol_data;    try    {        symbol_data = symbol::read(sbl_file);    }    catch (const std::runtime_error &e)    {        // File with assumed symbol name/extension is not the correct format        auto msg = std::stringstream{};        msg << "Assumed symbol file '"            << symbol_path_maybe            << "' has invalid symbol format. ("            << e.what()            << ")";        debug_print_error(msg.str());        return;    }     // Check if the symbol data matches the loaded module    if (0 != symbol_data->get_module_name().compare(m->module_name->str())        || symbol_data->get_instruction_count() != m->code_section.size())    {        // Symbol file does not match the loaded modules - stale file?        auto msg = std::stringstream{};        msg << "Symbol file '"            << symbol_path_maybe            << "' does not match loaded module '"            << loaded_mod.origin->str()            << "'.";        debug_print_error(msg.str());        return;    }     const auto vm_id = loaded_mod.vm_id;    assert(_vm_id_to_symbol_info.find(vm_id) == std::end(_vm_id_to_symbol_info) && "Module VM ID should be unique");    auto symbol_iter = symbol_data->get_pc_iter();    _vm_id_to_symbol_info[vm_id] = { std::move(symbol_data), std::move(symbol_iter) };     auto msg = std::stringstream{};    msg << "Symbol file '"        << symbol_path_maybe        << "' loaded for '"        << loaded_mod.origin->str()        << "'.";    debug_print_info(msg.str());}

Lines 1001–1285 of 1285. Previous lines