History

Add support for inleaving source information into disassembly view in debugger.

arr committed 9 years ago

Commit eb8b0901 parent 2b710fc4 files · +217 −59Browse files

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

Unified · Split

src/exec/debugger.cpp+140−31
@@ -123,10 +123,11 @@ namespace · 122 unmodified lines
123123 auto msg = std::stringstream{};
124124 walk_stack(r, [&msg, &dbg](const pointer_t, const vm_pc_t pc, const vm_module_ref_t &module_ref)
125125 {
126− auto resolved_name = dbg.resolve_function_source_line(module_ref.module, pc);
127− if (!resolved_name.empty())
126+ auto func_maybe = dbg.resolve_to_function_source_line(module_ref.module->vm_id, pc, pc, symbol::function_name_format_t::name);
127+ if (!func_maybe.empty())
128128 {
129− msg << resolved_name;
129+ assert(func_maybe.size() == 1);
130+ msg << module_ref.module->module_name->str() << "!" << func_maybe[0];
130131 }
131132 else
132133 {
@@ -336,14 +337,19 @@ namespace · 203 unmodified lines
336337 void cmd_print_modules(const std::vector<std::string> &, dbg_cmd_cxt_t &cxt)
337338 {
338339 auto msg = std::stringstream{};
339− cxt.vm.enum_loaded_modules([&msg](const loaded_vm_module_t &m)
340+ cxt.vm.enum_loaded_modules([&msg, &cxt](const loaded_vm_module_t &m)
340341 {
341342 auto module_instance = m.module.lock();
342343 if (module_instance != nullptr)
343344 {
344345 msg << std::setw(3) << m.vm_id << ": "
345346 << std::setw(16) << module_instance->module_name->str()
346− << std::setw(0) << " - " << m.origin->str() << "\n";
347+ << std::setw(0) << " - " << m.origin->str();
348+
349+ if (cxt.dbg.symbols_exist(m.vm_id))
350+ msg << " [symbols loaded]";
351+
352+ msg << "\n";
347353 }
348354
349355 return true;
@@ -352,6 +358,38 @@ namespace · 2 unmodified lines
352358 debug_print_info(msg.str());
353359 }
354360
361+ void cmd_print_symbols(const std::vector<std::string> &a, dbg_cmd_cxt_t &cxt)
362+ {
363+ if (a.size() < 2)
364+ throw debug_cmd_error_t{ "Must supply a module ID" };
365+
366+ module_id_t vm_id;
367+ try
368+ {
369+ vm_id = std::stoul(a[1]);
370+ }
371+ catch (...)
372+ {
373+ throw debug_cmd_error_t{ "Invalid module ID format" };
374+ }
375+
376+ if (!cxt.dbg.symbols_exist(vm_id))
377+ throw debug_cmd_error_t{ "No symbols loaded for module" };
378+
379+ // Interpret the last non-module ID value as the partial name to match.
380+ const char *name_to_match = nullptr;
381+ if (a.size() > 2)
382+ name_to_match = a.back().c_str();
383+
384+ auto msg = std::stringstream{};
385+ auto module_funcs = cxt.dbg.get_module_functions(vm_id, name_to_match);
386+ msg << "Function name [PC range]\n";
387+ for (auto &f : module_funcs)
388+ msg << " " << f << "\n";
389+
390+ debug_print_info(msg.str());
391+ }
392+
355393 void cmd_breakpoint_set(const std::vector<std::string> &a, dbg_cmd_cxt_t &cxt)
356394 {
357395 if (a.size() < 2)
@@ -456,7 +494,20 @@ namespace · 98 unmodified lines
456494 const auto details = cxt.dbg.controller->get_breakpoint_details(cookie);
457495 msg << std::setw(3) << cookie << ": "
458496 << std::setw(16) << details.module->module_name->str()
459− << std::setw(0) << "@" << details.pc << "\n";
497+ << std::setw(0);
498+
499+ auto func_maybe = cxt.dbg.resolve_to_function_source_line(details.module->vm_id, details.pc, details.pc, symbol::function_name_format_t::name);
500+ if (!func_maybe.empty())
501+ {
502+ assert(func_maybe.size() == 1);
503+ msg << "!" << func_maybe[0];
504+ }
505+ else
506+ {
507+ msg << "@" << details.pc;
508+ }
509+
510+ msg << "\n";
460511 }
461512
462513 debug_print_info(msg.str());
@@ -567,21 +618,24 @@ namespace · 104 unmodified lines
567618 const auto &r = *cxt.current_register;
568619 const auto &code_section = r.module_ref->code_section;
569620
570− auto begin_index = static_cast<std::size_t>(r.pc);
571− auto end_index = static_cast<std::size_t>(r.pc + 1);
621+ auto begin_pc = static_cast<std::size_t>(r.pc);
622+ auto end_pc = static_cast<std::size_t>(r.pc);
572623 if (disassemble_length < 0)
573624 {
574625 const auto begin_maybe = r.pc - (-disassemble_length) + 1;
575− begin_index = static_cast<std::size_t>(std::max(begin_maybe, 0));
626+ begin_pc= static_cast<std::size_t>(std::max(begin_maybe, 0));
576627 }
577628 else
578629 {
579630 const auto end_maybe = static_cast<std::size_t>(r.pc + disassemble_length);
580− end_index = std::min(end_maybe, code_section.size());
631+ end_pc = std::min(end_maybe, code_section.size());
581632 }
582633
634+ auto resolved_pc = cxt.dbg.resolve_to_function_source_line(r.module_ref->module->vm_id, begin_pc, end_pc, symbol::function_name_format_t::name);
635+ assert(resolved_pc.empty() || resolved_pc.size() == (end_pc - begin_pc + 1) && "Resolved PCs should have failed or match the PC count");
636+
583637 auto msg = std::stringstream{};
584− for (auto i = begin_index; i < end_index; ++i)
638+ for (auto i = begin_pc; i < (end_pc + 1); ++i)
585639 {
586640 auto op = code_section[i].op;
587641
@@ -603,6 +657,14 @@ namespace · 15 unmodified lines
603657 }
604658 }
605659
660+ // Print source location if resolved
661+ if (!resolved_pc.empty())
662+ {
663+ const auto & r = resolved_pc[i - begin_pc];
664+ if (!r.empty())
665+ msg << r << "\n";
666+ }
667+
606668 msg << op_prefix << std::setw(5) << i << ": " << op << "\n";
607669 }
608670
@@ -771,6 +833,7 @@ namespace · 162 unmodified lines
771833 { "r", "Print registers", nullptr, nullptr, cmd_print_registers },
772834 { "t", "Print all threads", nullptr, nullptr, cmd_print_threads },
773835 { "m", "Print all loaded modules", nullptr, nullptr, cmd_print_modules },
836+ { "sym", "Print symbols for the supplied module", "sym [0-9]+ <partial function name>?", "sym 2 foo (Print symbols in module 2 containing 'foo')", cmd_print_symbols },
774837
775838 { "bs", "Set breakpoint at the specified IP in a loaded module", "bs [0-9]+ [0-9]*", "bs 3 5 (Breakpoint at IP 3 in module 5), bs 4 (Breakpoint at IP 4 in current module)", cmd_breakpoint_set },
776839 { "bc", "Clear breakpoint(s)", "bc ([0-9]+|\\*)", "bc 3, bc *", cmd_breakpoint_clear },
@@ -883,32 +946,77 @@ debugger::debugger(const debugger_options opt) · 106 unmodified lines
883946 , controller{ nullptr }
884947 { }
885948
886−std::string debugger::resolve_function_source_line(std::shared_ptr<const vm_module_t> m, vm_pc_t pc)
949+std::vector<std::string> debugger::resolve_to_function_source_line(
950+ disvm::runtime::module_id_t vm_id,
951+ vm_pc_t begin_pc,
952+ vm_pc_t end_pc,
953+ symbol::function_name_format_t fmt) const
887954 {
888− if (m == nullptr)
889− return{};
890−
891− auto iter = _vm_id_to_symbol_debug.find(m->vm_id);
892− if (iter == std::end(_vm_id_to_symbol_debug))
955+ auto iter = _vm_id_to_symbol_info.find(vm_id);
956+ if (iter == std::cend(_vm_id_to_symbol_info))
893957 return{};
894958
895− std::stringstream ss;
896− auto &d = *(iter->second);
959+ auto &d = *(iter->second.iter);
897960
898961 // Position the debug symbol iterator
899− d.set_current_pc(pc);
962+ d.set_current_pc(begin_pc);
963+
964+ std::vector<std::string> resolved_functions_by_pc(end_pc - begin_pc + 1);
965+ vm_pc_t next_pc = begin_pc;
966+ do
967+ {
968+ if (next_pc > end_pc)
969+ break;
970+
971+ std::stringstream ss;
972+ const auto function_name = d.current_function_name(fmt);
973+ if (!function_name.empty())
974+ ss << function_name << " at ";
975+
976+ const auto source_loc = d.current_source_location();
977+ ss << d.get_source_by_id(source_loc.source_id)
978+ << ':'
979+ << source_loc.begin_line;
980+
981+ resolved_functions_by_pc[next_pc - begin_pc] = std::move(ss.str());
900982
901− const auto src = d.current_source_location();
983+ } while (d.try_advance_pc(symbol::advance_pc_t::next_debug_statement, &next_pc));
902984
903− ss << m->module_name->str()
904− << '!'
905− << d.current_function_name(symbol::function_name_format_t::declaration)
906− << " at "
907− << d.get_source_by_id(src.source_id)
908− << ':'
909− << src.begin_line;
985+ return resolved_functions_by_pc;
986+}
987+
988+std::vector<std::string> debugger::get_module_functions(disvm::runtime::module_id_t vm_id, const char *match) const
989+{
990+ std::vector<std::string> funcs;
991+ auto iter = _vm_id_to_symbol_info.find(vm_id);
992+ if (iter != std::cend(_vm_id_to_symbol_info))
993+ {
994+ auto f_infos = iter->second.data->get_functions(symbol::function_name_format_t::declaration);
995+ for (auto &fi : f_infos)
996+ {
997+ // Only return functions that match the supplied string
998+ if (match != nullptr
999+ && fi.name.find(match) == std::string::npos)
1000+ continue;
1001+
1002+ std::stringstream ss;
1003+ ss << fi.name
1004+ << " ["
1005+ << fi.entry_pc
1006+ << ", "
1007+ << fi.limit_pc
1008+ << "]";
9101009
911− return ss.str();
1010+ funcs.push_back(ss.str());
1011+ }
1012+ }
1013+
1014+ return funcs;
1015+}
1016+
1017+bool debugger::symbols_exist(disvm::runtime::module_id_t vm_id) const
1018+{
1019+ return _vm_id_to_symbol_info.find(vm_id) != std::cend(_vm_id_to_symbol_info);
9121020 }
9131021
9141022 void debugger::on_load(vm_tool_controller_t &controller_, std::size_t tool_id)
@@ -1081,8 +1189,9 @@ void debugger::load_symbols(const disvm::loaded_vm_module_t &loaded_mod) · 166 unmodified lines
10811189 }
10821190
10831191 const auto vm_id = loaded_mod.vm_id;
1084− assert(_vm_id_to_symbol_debug.find(vm_id) == std::end(_vm_id_to_symbol_debug) && "Module VM ID should be unique");
1085− _vm_id_to_symbol_debug[vm_id] = symbol_data->get_debug();
1192+ assert(_vm_id_to_symbol_info.find(vm_id) == std::end(_vm_id_to_symbol_info) && "Module VM ID should be unique");
1193+ auto symbol_iter = symbol_data->get_pc_iter();
1194+ _vm_id_to_symbol_info[vm_id] = { std::move(symbol_data), std::move(symbol_iter) };
10861195
10871196 std::stringstream msg;
10881197 msg << "Symbol file '"