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
123 auto msg = std::stringstream{};123 auto msg = std::stringstream{};
124 walk_stack(r, [&msg, &dbg](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)
125 {125 {
126 auto resolved_name = dbg.resolve_function_source_line(module_ref.module, pc);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 (!resolved_name.empty())127 if (!func_maybe.empty())
128 {128 {
129 msg << resolved_name;129 assert(func_maybe.size() == 1);
130 msg << module_ref.module->module_name->str() << "!" << func_maybe[0];
130 }131 }
131 else132 else
132 {133 {
@@ -336,14 +337,19 @@ namespace · 203 unmodified lines
336 void cmd_print_modules(const std::vector<std::string> &, dbg_cmd_cxt_t &cxt)337 void cmd_print_modules(const std::vector<std::string> &, dbg_cmd_cxt_t &cxt)
337 {338 {
338 auto msg = std::stringstream{};339 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)
340 {341 {
341 auto module_instance = m.module.lock();342 auto module_instance = m.module.lock();
342 if (module_instance != nullptr)343 if (module_instance != nullptr)
343 {344 {
344 msg << std::setw(3) << m.vm_id << ": "345 msg << std::setw(3) << m.vm_id << ": "
345 << std::setw(16) << module_instance->module_name->str()346 << 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";
347 }353 }
348 354
349 return true;355 return true;
@@ -352,6 +358,38 @@ namespace · 2 unmodified lines
352 debug_print_info(msg.str());358 debug_print_info(msg.str());
353 }359 }
354 360
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
355 void cmd_breakpoint_set(const std::vector<std::string> &a, dbg_cmd_cxt_t &cxt)393 void cmd_breakpoint_set(const std::vector<std::string> &a, dbg_cmd_cxt_t &cxt)
356 {394 {
357 if (a.size() < 2)395 if (a.size() < 2)
@@ -456,7 +494,20 @@ namespace · 98 unmodified lines
456 const auto details = cxt.dbg.controller->get_breakpoint_details(cookie);494 const auto details = cxt.dbg.controller->get_breakpoint_details(cookie);
457 msg << std::setw(3) << cookie << ": "495 msg << std::setw(3) << cookie << ": "
458 << std::setw(16) << details.module->module_name->str()496 << 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";
460 }511 }
461 512
462 debug_print_info(msg.str());513 debug_print_info(msg.str());
@@ -567,21 +618,24 @@ namespace · 104 unmodified lines
567 const auto &r = *cxt.current_register;618 const auto &r = *cxt.current_register;
568 const auto &code_section = r.module_ref->code_section;619 const auto &code_section = r.module_ref->code_section;
569 620
570 auto begin_index = static_cast<std::size_t>(r.pc);621 auto begin_pc = static_cast<std::size_t>(r.pc);
571 auto end_index = static_cast<std::size_t>(r.pc + 1);622 auto end_pc = static_cast<std::size_t>(r.pc);
572 if (disassemble_length < 0)623 if (disassemble_length < 0)
573 {624 {
574 const auto begin_maybe = r.pc - (-disassemble_length) + 1;625 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));
576 }627 }
577 else628 else
578 {629 {
579 const auto end_maybe = static_cast<std::size_t>(r.pc + disassemble_length);630 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());
581 }632 }
582 633
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
583 auto msg = std::stringstream{};637 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)
585 {639 {
586 auto op = code_section[i].op;640 auto op = code_section[i].op;
587 641
@@ -603,6 +657,14 @@ namespace · 15 unmodified lines
603 }657 }
604 }658 }
605 659
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
606 msg << op_prefix << std::setw(5) << i << ": " << op << "\n";668 msg << op_prefix << std::setw(5) << i << ": " << op << "\n";
607 }669 }
608 670
@@ -771,6 +833,7 @@ namespace · 162 unmodified lines
771 { "r", "Print registers", nullptr, nullptr, cmd_print_registers },833 { "r", "Print registers", nullptr, nullptr, cmd_print_registers },
772 { "t", "Print all threads", nullptr, nullptr, cmd_print_threads },834 { "t", "Print all threads", nullptr, nullptr, cmd_print_threads },
773 { "m", "Print all loaded modules", nullptr, nullptr, cmd_print_modules },835 { "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 },
774 837
775 { "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 },838 { "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 },
776 { "bc", "Clear breakpoint(s)", "bc ([0-9]+|\\*)", "bc 3, bc *", cmd_breakpoint_clear },839 { "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
883 , controller{ nullptr }946 , controller{ nullptr }
884{ }947{ }
885 948
886std::string debugger::resolve_function_source_line(std::shared_ptr<const vm_module_t> m, vm_pc_t pc)949std::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
887{954{
888 if (m == nullptr)955 auto iter = _vm_id_to_symbol_info.find(vm_id);
889 return{};956 if (iter == std::cend(_vm_id_to_symbol_info))
890
891 auto iter = _vm_id_to_symbol_debug.find(m->vm_id);
892 if (iter == std::end(_vm_id_to_symbol_debug))
893 return{};957 return{};
894 958
895 std::stringstream ss;959 auto &d = *(iter->second.iter);
896 auto &d = *(iter->second);
897 960
898 // Position the debug symbol iterator961 // 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());
900 982
901 const auto src = d.current_source_location();983 } while (d.try_advance_pc(symbol::advance_pc_t::next_debug_statement, &next_pc));
902 984
903 ss << m->module_name->str()985 return resolved_functions_by_pc;
904 << '!'986}
905 << d.current_function_name(symbol::function_name_format_t::declaration)987
906 << " at "988std::vector<std::string> debugger::get_module_functions(disvm::runtime::module_id_t vm_id, const char *match) const
907 << d.get_source_by_id(src.source_id)989{
908 << ':'990 std::vector<std::string> funcs;
909 << src.begin_line;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 << "]";
910 1009
911 return ss.str();1010 funcs.push_back(ss.str());
1011 }
1012 }
1013
1014 return funcs;
1015}
1016
1017bool 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);
912}1020}
913 1021
914void debugger::on_load(vm_tool_controller_t &controller_, std::size_t tool_id)1022void 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
1081 }1189 }
1082 1190
1083 const auto vm_id = loaded_mod.vm_id;1191 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");1192 assert(_vm_id_to_symbol_info.find(vm_id) == std::end(_vm_id_to_symbol_info) && "Module VM ID should be unique");
1085 _vm_id_to_symbol_debug[vm_id] = symbol_data->get_debug();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) };
1086 1195
1087 std::stringstream msg;1196 std::stringstream msg;
1088 msg << "Symbol file '"1197 msg << "Symbol file '"