History

Added vm_id to vm_module_t that is used by the VM to uniquely identify a module Updated tool dispatcher to pass on the loaded_vm_module_t type as the module_vm_load event argument Debugger now uses symbol data to resolve stack IPs

arr committed 9 years ago

Commit 72f24ec1 parent a3c184b10 files · +160 −35Browse files

Showing the changes to src/exec/debugger.cpp (1 of 10 files). Show all

Unified · Split

src/exec/debugger.cpp+121−10
@@ -5,6 +5,7 @@ · 4 unmodified lines
5//5//
6 6
7#include <iostream>7#include <iostream>
8#include <fstream>
8#include <iomanip>9#include <iomanip>
9#include <sstream>10#include <sstream>
10#include <string>11#include <string>
@@ -117,16 +118,26 @@ namespace · 106 unmodified lines
117 dbg_cmd_exec_t exec;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 auto msg = std::stringstream{};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 auto resolved_name = dbg.resolve_function_source_line(module_ref.module, pc);
126 if (module_ref.module->module_name != nullptr)127 if (!resolved_name.empty())
127 module_name = module_ref.module->module_name->str();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 return true;141 return true;
131 });142 });
132 143
@@ -215,7 +226,7 @@ namespace · 82 unmodified lines
215 ss << "channel\n"226 ss << "channel\n"
216 << "\tbuffer size: " << c->get_buffer_size() << "\n";227 << "\tbuffer size: " << c->get_buffer_size() << "\n";
217 228
218 return ss;229 return ss;
219 }230 }
220 231
221 std::ostream& operator<<(std::ostream &ss, const vm_alloc_t *alloc)232 std::ostream& operator<<(std::ostream &ss, const vm_alloc_t *alloc)
@@ -330,7 +341,7 @@ namespace · 108 unmodified lines
330 auto module_instance = m.module.lock();341 auto module_instance = m.module.lock();
331 if (module_instance != nullptr)342 if (module_instance != nullptr)
332 {343 {
333 msg << std::setw(3) << m.load_id << ": "344 msg << std::setw(3) << m.vm_id << ": "
334 << std::setw(16) << module_instance->module_name->str()345 << std::setw(16) << module_instance->module_name->str()
335 << std::setw(0) << " - " << m.origin->str() << "\n";346 << std::setw(0) << " - " << m.origin->str() << "\n";
336 }347 }
@@ -372,7 +383,7 @@ namespace · 35 unmodified lines
372 383
373 cxt.vm.enum_loaded_modules([module_id, &module](const loaded_vm_module_t &m)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 return true;387 return true;
377 388
378 // Found the matching ID so stop389 // Found the matching ID so stop
@@ -500,7 +511,7 @@ namespace · 121 unmodified lines
500 for (auto t : thread_registers)511 for (auto t : thread_registers)
501 {512 {
502 msg << "Thread " << t.first << ":\n";513 msg << "Thread " << t.first << ":\n";
503 msg << stack_to_string(*t.second);514 msg << stack_to_string(*t.second, cxt.dbg);
504 msg << "\n";515 msg << "\n";
505 }516 }
506 517
@@ -856,6 +867,30 @@ debugger::debugger(const debugger_options opt) · 349 unmodified lines
856 , controller{ nullptr }867 , controller{ nullptr }
857{ }868{ }
858 869
870std::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
859void debugger::on_load(vm_tool_controller_t &controller_, std::size_t tool_id)894void debugger::on_load(vm_tool_controller_t &controller_, std::size_t tool_id)
860{895{
861 _tool_id = tool_id;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 prompt(*this, *cxt.value1.registers);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 _event_cookies.emplace(controller->subscribe_event(vm_event_t::module_thread_load, [&](vm_event_t, vm_event_context_t &cxt)954 _event_cookies.emplace(controller->subscribe_event(vm_event_t::module_thread_load, [&](vm_event_t, vm_event_context_t &cxt)
913 {955 {
914 auto m = (*cxt.value2.module);956 auto m = (*cxt.value2.module);
@@ -960,4 +1002,73 @@ void debugger::on_unload() · 45 unmodified lines
960 controller->unsubscribe_event(ec);1002 controller->unsubscribe_event(ec);
961 1003
962 controller = nullptr;1004 controller = nullptr;
1005}
1006
1007void 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}