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
55 //
66
77 #include <iostream>
8+#include <fstream>
89 #include <iomanip>
910 #include <sstream>
1011 #include <string>
@@ -117,16 +118,26 @@ namespace · 106 unmodified lines
117118 dbg_cmd_exec_t exec;
118119 };
119120
120− std::string stack_to_string(const vm_registers_t &r)
121+ std::string stack_to_string(const vm_registers_t &r, debugger &dbg)
121122 {
122123 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)
124125 {
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+ }
128139
129− msg << module_name << "@" << pc << "\n";
140+ msg << "\n";
130141 return true;
131142 });
132143
@@ -215,7 +226,7 @@ namespace · 82 unmodified lines
215226 ss << "channel\n"
216227 << "\tbuffer size: " << c->get_buffer_size() << "\n";
217228
218− return ss;
229+ return ss;
219230 }
220231
221232 std::ostream& operator<<(std::ostream &ss, const vm_alloc_t *alloc)
@@ -330,7 +341,7 @@ namespace · 108 unmodified lines
330341 auto module_instance = m.module.lock();
331342 if (module_instance != nullptr)
332343 {
333− msg << std::setw(3) << m.load_id << ": "
344+ msg << std::setw(3) << m.vm_id << ": "
334345 << std::setw(16) << module_instance->module_name->str()
335346 << std::setw(0) << " - " << m.origin->str() << "\n";
336347 }
@@ -372,7 +383,7 @@ namespace · 35 unmodified lines
372383
373384 cxt.vm.enum_loaded_modules([module_id, &module](const loaded_vm_module_t &m)
374385 {
375− if (module_id != m.load_id)
386+ if (module_id != m.vm_id)
376387 return true;
377388
378389 // Found the matching ID so stop
@@ -500,7 +511,7 @@ namespace · 121 unmodified lines
500511 for (auto t : thread_registers)
501512 {
502513 msg << "Thread " << t.first << ":\n";
503− msg << stack_to_string(*t.second);
514+ msg << stack_to_string(*t.second, cxt.dbg);
504515 msg << "\n";
505516 }
506517
@@ -856,6 +867,30 @@ debugger::debugger(const debugger_options opt) · 349 unmodified lines
856867 , controller{ nullptr }
857868 { }
858869
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+
859894 void debugger::on_load(vm_tool_controller_t &controller_, std::size_t tool_id)
860895 {
861896 _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
909944 prompt(*this, *cxt.value1.registers);
910945 }));
911946
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+
912954 _event_cookies.emplace(controller->subscribe_event(vm_event_t::module_thread_load, [&](vm_event_t, vm_event_context_t &cxt)
913955 {
914956 auto m = (*cxt.value2.module);
@@ -960,4 +1002,73 @@ void debugger::on_unload() · 45 unmodified lines
9601002 controller->unsubscribe_event(ec);
9611003
9621004 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());
9631074 }