Showing the changes to src/exec/debugger.cpp (1 of 10 files). Show all
Unified · Split
| @@ -5,6 +5,7 @@ · 4 unmodified lines | ||
| 5 | 5 | // |
| 6 | 6 | |
| 7 | 7 | #include <iostream> |
| 8 | +#include <fstream> | |
| 8 | 9 | #include <iomanip> |
| 9 | 10 | #include <sstream> |
| 10 | 11 | #include <string> |
| @@ -117,16 +118,26 @@ namespace · 106 unmodified lines | ||
| 117 | 118 | dbg_cmd_exec_t exec; |
| 118 | 119 | }; |
| 119 | 120 | |
| 120 | − std::string stack_to_string(const vm_registers_t &r) | |
| 121 | + std::string stack_to_string(const vm_registers_t &r, debugger &dbg) | |
| 121 | 122 | { |
| 122 | 123 | auto msg = std::stringstream{}; |
| 123 | − walk_stack(r, [&msg](const pointer_t, const vm_pc_t pc, const vm_module_ref_t &module_ref) | |
| 124 | + walk_stack(r, [&msg, &dbg](const pointer_t, const vm_pc_t pc, const vm_module_ref_t &module_ref) | |
| 124 | 125 | { |
| 125 | − auto module_name = "<No Name>"; | |
| 126 | − if (module_ref.module->module_name != nullptr) | |
| 127 | − module_name = module_ref.module->module_name->str(); | |
| 126 | + auto resolved_name = dbg.resolve_function_source_line(module_ref.module, pc); | |
| 127 | + if (!resolved_name.empty()) | |
| 128 | + { | |
| 129 | + msg << resolved_name; | |
| 130 | + } | |
| 131 | + else | |
| 132 | + { | |
| 133 | + auto module_name = "<No Name>"; | |
| 134 | + if (module_ref.module->module_name != nullptr) | |
| 135 | + module_name = module_ref.module->module_name->str(); | |
| 136 | + | |
| 137 | + msg << module_name << "@" << pc; | |
| 138 | + } | |
| 128 | 139 | |
| 129 | − msg << module_name << "@" << pc << "\n"; | |
| 140 | + msg << "\n"; | |
| 130 | 141 | return true; |
| 131 | 142 | }); |
| 132 | 143 | |
| @@ -215,7 +226,7 @@ namespace · 82 unmodified lines | ||
| 215 | 226 | ss << "channel\n" |
| 216 | 227 | << "\tbuffer size: " << c->get_buffer_size() << "\n"; |
| 217 | 228 | |
| 218 | − return ss; | |
| 229 | + return ss; | |
| 219 | 230 | } |
| 220 | 231 | |
| 221 | 232 | std::ostream& operator<<(std::ostream &ss, const vm_alloc_t *alloc) |
| @@ -330,7 +341,7 @@ namespace · 108 unmodified lines | ||
| 330 | 341 | auto module_instance = m.module.lock(); |
| 331 | 342 | if (module_instance != nullptr) |
| 332 | 343 | { |
| 333 | − msg << std::setw(3) << m.load_id << ": " | |
| 344 | + msg << std::setw(3) << m.vm_id << ": " | |
| 334 | 345 | << std::setw(16) << module_instance->module_name->str() |
| 335 | 346 | << std::setw(0) << " - " << m.origin->str() << "\n"; |
| 336 | 347 | } |
| @@ -372,7 +383,7 @@ namespace · 35 unmodified lines | ||
| 372 | 383 | |
| 373 | 384 | cxt.vm.enum_loaded_modules([module_id, &module](const loaded_vm_module_t &m) |
| 374 | 385 | { |
| 375 | − if (module_id != m.load_id) | |
| 386 | + if (module_id != m.vm_id) | |
| 376 | 387 | return true; |
| 377 | 388 | |
| 378 | 389 | // Found the matching ID so stop |
| @@ -500,7 +511,7 @@ namespace · 121 unmodified lines | ||
| 500 | 511 | for (auto t : thread_registers) |
| 501 | 512 | { |
| 502 | 513 | msg << "Thread " << t.first << ":\n"; |
| 503 | − msg << stack_to_string(*t.second); | |
| 514 | + msg << stack_to_string(*t.second, cxt.dbg); | |
| 504 | 515 | msg << "\n"; |
| 505 | 516 | } |
| 506 | 517 | |
| @@ -856,6 +867,30 @@ debugger::debugger(const debugger_options opt) · 349 unmodified lines | ||
| 856 | 867 | , controller{ nullptr } |
| 857 | 868 | { } |
| 858 | 869 | |
| 870 | +std::string debugger::resolve_function_source_line(std::shared_ptr<const vm_module_t> m, vm_pc_t pc) | |
| 871 | +{ | |
| 872 | + if (m == nullptr) | |
| 873 | + return{}; | |
| 874 | + | |
| 875 | + auto iter = _vm_id_to_symbol_debug.find(m->vm_id); | |
| 876 | + if (iter == std::end(_vm_id_to_symbol_debug)) | |
| 877 | + return{}; | |
| 878 | + | |
| 879 | + std::stringstream ss; | |
| 880 | + auto &d = *(iter->second); | |
| 881 | + | |
| 882 | + // Position the debug symbol iterator | |
| 883 | + d.set_current_pc(pc); | |
| 884 | + | |
| 885 | + ss << m->module_name->str() | |
| 886 | + << '!' | |
| 887 | + << d.current_function_name() | |
| 888 | + << ' ' | |
| 889 | + << d.current_source_location().begin_line; | |
| 890 | + | |
| 891 | + return ss.str(); | |
| 892 | +} | |
| 893 | + | |
| 859 | 894 | void debugger::on_load(vm_tool_controller_t &controller_, std::size_t tool_id) |
| 860 | 895 | { |
| 861 | 896 | _tool_id = tool_id; |
| @@ -909,6 +944,13 @@ void debugger::on_load(vm_tool_controller_t &controller_, std::size_t tool_id) · 47 unmodified lines | ||
| 909 | 944 | prompt(*this, *cxt.value1.registers); |
| 910 | 945 | })); |
| 911 | 946 | |
| 947 | + _event_cookies.emplace(controller->subscribe_event(vm_event_t::module_vm_load, [&](vm_event_t, vm_event_context_t &cxt) | |
| 948 | + { | |
| 949 | + auto loaded_mod = cxt.value1.loaded_mod; | |
| 950 | + assert(loaded_mod != nullptr); | |
| 951 | + load_symbols(*loaded_mod); | |
| 952 | + })); | |
| 953 | + | |
| 912 | 954 | _event_cookies.emplace(controller->subscribe_event(vm_event_t::module_thread_load, [&](vm_event_t, vm_event_context_t &cxt) |
| 913 | 955 | { |
| 914 | 956 | auto m = (*cxt.value2.module); |
| @@ -960,4 +1002,73 @@ void debugger::on_unload() · 45 unmodified lines | ||
| 960 | 1002 | controller->unsubscribe_event(ec); |
| 961 | 1003 | |
| 962 | 1004 | controller = nullptr; |
| 1005 | +} | |
| 1006 | + | |
| 1007 | +void debugger::load_symbols(const disvm::loaded_vm_module_t &loaded_mod) | |
| 1008 | +{ | |
| 1009 | + auto m = loaded_mod.module.lock(); | |
| 1010 | + assert(m != nullptr && "Loaded module event should have valid module reference"); | |
| 1011 | + | |
| 1012 | + auto symbol_extension = ".sbl"; | |
| 1013 | + std::string symbol_path_maybe{ loaded_mod.origin->str() }; | |
| 1014 | + const auto ext_index = symbol_path_maybe.find_last_of('.'); | |
| 1015 | + if (ext_index == std::string::npos) | |
| 1016 | + { | |
| 1017 | + // Module doesn't have an extension so just append the symbol extension. | |
| 1018 | + symbol_path_maybe.append(symbol_extension); | |
| 1019 | + } | |
| 1020 | + else | |
| 1021 | + { | |
| 1022 | + // Replace the module extension with the symbol extension. | |
| 1023 | + symbol_path_maybe.replace(ext_index, std::string::npos, symbol_extension); | |
| 1024 | + } | |
| 1025 | + | |
| 1026 | + std::ifstream sbl_file{ symbol_path_maybe, std::ifstream::in }; | |
| 1027 | + if (!sbl_file.is_open()) | |
| 1028 | + return; | |
| 1029 | + | |
| 1030 | + std::unique_ptr<symbol::symbol_data_t> symbol_data; | |
| 1031 | + try | |
| 1032 | + { | |
| 1033 | + symbol_data = symbol::read(sbl_file); | |
| 1034 | + } | |
| 1035 | + catch (const std::runtime_error &e) | |
| 1036 | + { | |
| 1037 | + // File with assumed symbol name/extension is not the correct format | |
| 1038 | + std::stringstream msg; | |
| 1039 | + msg << "Assumed symbol file '" | |
| 1040 | + << symbol_path_maybe | |
| 1041 | + << "' has invalid symbol format. (" | |
| 1042 | + << e.what() | |
| 1043 | + << ")"; | |
| 1044 | + debug_print_error(msg.str()); | |
| 1045 | + return; | |
| 1046 | + } | |
| 1047 | + | |
| 1048 | + // Check if the symbol data matches the loaded module | |
| 1049 | + if (0 != symbol_data->get_module_name().compare(m->module_name->str()) | |
| 1050 | + || symbol_data->get_instruction_count() != m->code_section.size()) | |
| 1051 | + { | |
| 1052 | + // Symbol file does not match the loaded modules - stale file? | |
| 1053 | + std::stringstream msg; | |
| 1054 | + msg << "Symbol file '" | |
| 1055 | + << symbol_path_maybe | |
| 1056 | + << "' does not match loaded module '" | |
| 1057 | + << loaded_mod.origin->str() | |
| 1058 | + << "'."; | |
| 1059 | + debug_print_error(msg.str()); | |
| 1060 | + return; | |
| 1061 | + } | |
| 1062 | + | |
| 1063 | + const auto vm_id = loaded_mod.vm_id; | |
| 1064 | + assert(_vm_id_to_symbol_debug.find(vm_id) == std::end(_vm_id_to_symbol_debug) && "Module VM ID should be unique"); | |
| 1065 | + _vm_id_to_symbol_debug[vm_id] = symbol_data->get_debug(); | |
| 1066 | + | |
| 1067 | + std::stringstream msg; | |
| 1068 | + msg << "Symbol file '" | |
| 1069 | + << symbol_path_maybe | |
| 1070 | + << "' loaded for '" | |
| 1071 | + << loaded_mod.origin->str() | |
| 1072 | + << "'."; | |
| 1073 | + debug_print_info(msg.str()); | |
| 963 | 1074 | } |