History

Add debug options support Add breakpoint command debug option - command to execute after a breakpoint is hit

arr committed 9 years ago

Commit ea995f21 parent af5c7a92 files · +106 −44Browse files

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

Unified · Split

src/exec/debugger.cpp+99−43
@@ -11,6 +11,7 @@ · 10 unmodified lines
1111 #include <string>
1212 #include <algorithm>
1313 #include <map>
14+#include <unordered_set>
1415 #include <utils.h>
1516 #include <vm_memory.h>
1617 #include <vm_asm.h>
@@ -383,9 +384,9 @@ namespace · 366 unmodified lines
383384
384385 auto msg = std::stringstream{};
385386 auto module_funcs = cxt.dbg.get_module_functions(vm_id, name_to_match);
386− msg << "Function name [PC range]\n";
387+ msg << "Function name [PC range]";
387388 for (auto &f : module_funcs)
388− msg << " " << f << "\n";
389+ msg << "\n " << f;
389390
390391 debug_print_info(msg.str());
391392 }
@@ -615,6 +616,7 @@ namespace · 223 unmodified lines
615616 }
616617 }
617618
619+ auto &dbg = cxt.dbg;
618620 const auto &r = *cxt.current_register;
619621 const auto &code_section = r.module_ref->code_section;
620622
@@ -623,19 +625,19 @@ namespace · 2 unmodified lines
623625 if (disassemble_length < 0)
624626 {
625627 const auto begin_maybe = r.pc - (-disassemble_length) + 1;
626− begin_pc= static_cast<std::size_t>(std::max(begin_maybe, 0));
628+ begin_pc = static_cast<std::size_t>(std::max(begin_maybe, 0));
627629 }
628630 else
629631 {
630632 const auto end_maybe = static_cast<std::size_t>(r.pc + disassemble_length);
631− end_pc = std::min(end_maybe, code_section.size());
633+ end_pc = std::min(end_maybe, code_section.size() - 1);
632634 }
633635
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);
636+ auto resolved_pc = dbg.resolve_to_function_source_line(r.module_ref->module->vm_id, begin_pc, end_pc, symbol::function_name_format_t::name);
635637 assert(resolved_pc.empty() || resolved_pc.size() == (end_pc - begin_pc + 1) && "Resolved PCs should have failed or match the PC count");
636638
637639 auto msg = std::stringstream{};
638− for (auto i = begin_pc; i < (end_pc + 1); ++i)
640+ for (auto i = begin_pc; i <= end_pc; ++i)
639641 {
640642 auto op = code_section[i].op;
641643
@@ -645,9 +647,9 @@ namespace · 3 unmodified lines
645647 if (op.opcode == opcode_t::brkpt)
646648 {
647649 // Look up each of the known cookies to try and find the matching PC and module
648− for (auto bp_cookie : cxt.dbg.breakpoint_cookies)
650+ for (auto bp_cookie : dbg.breakpoint_cookies)
649651 {
650− const auto details = cxt.dbg.controller->get_breakpoint_details(bp_cookie);
652+ const auto details = dbg.controller->get_breakpoint_details(bp_cookie);
651653 if (details.pc == i && details.module == r.module_ref->module)
652654 {
653655 op.opcode = details.original_opcode;
@@ -660,9 +662,9 @@ namespace · 6 unmodified lines
660662 // Print source location if resolved
661663 if (!resolved_pc.empty())
662664 {
663− const auto & r = resolved_pc[i - begin_pc];
664− if (!r.empty())
665− msg << r << "\n";
665+ const auto &rpc = resolved_pc[i - begin_pc];
666+ if (!rpc.empty())
667+ msg << rpc << "\n";
666668 }
667669
668670 msg << op_prefix << std::setw(5) << i << ": " << op << "\n";
@@ -811,18 +813,47 @@ namespace · 142 unmodified lines
811813 << console_modifiers::reset_all;
812814 }
813815
814− void set_value_cmd(const std::vector<std::string> &args, dbg_cmd_cxt_t &)
816+ std::unordered_set<std::string> dbg_options =
815817 {
816− if (args.size() == 0)
818+ { "bp-cmd" }
819+ };
820+
821+ void set_value_cmd(const std::vector<std::string> &args, dbg_cmd_cxt_t &cxt)
822+ {
823+ auto msg = std::stringstream{};
824+ if (args.size() == 1)
817825 {
818− // [TODO] Print all options current state
826+ msg << "Debug options\n";
827+ for (auto &option : dbg_options)
828+ {
829+ auto v = cxt.dbg.get_option(option);
830+ msg << std::setw(16) << option
831+ << ": "
832+ << (v.empty() ? "<none>" : v)
833+ << "\n";
834+ }
835+
836+ debug_print_info(msg.str());
819837 return;
820838 }
821− else if (0 == args[0].compare("help"))
839+
840+ auto &curr_option = args[1];
841+ if (std::cend(dbg_options) == dbg_options.find(curr_option))
842+ throw debug_cmd_error_t{ "Invalid debug option" };
843+
844+ auto new_value = std::stringstream{};
845+
846+ // Reconstitute the parsed debug arguments - in-case of space breaks.
847+ for (auto i = std::size_t{ 2 }; i < args.size(); ++i)
822848 {
823− // [TODO] Print help for 'set' command
824− return;
849+ new_value << args[i];
850+
851+ // For the last parsed arg
852+ if (i + 1 < args.size())
853+ new_value << " ";
825854 }
855+
856+ cxt.dbg.set_option(curr_option, new_value.str());
826857 }
827858
828859 const dbg_cmd_t cmds[] =
@@ -844,7 +875,7 @@ namespace · 15 unmodified lines
844875 { "d", "Disassemble the next/previous N instructions (default N = 4)", "d (-?[0-9]+)?", "d, d -4, d 5", cmd_disassemble },
845876 { "x", "Examine memory", "x [mp|fp] [0-9]+ ([0-9]+)?", "x mp 3, x fp 20 6", cmd_examine },
846877
847− //{ "set" , "Set a debugger option", "set [ _a-zA-Z0-9]*", "'set help' for available options", set_value_cmd },
878+ { "set" , "Set a debug option", "set [ _a-zA-Z0-9]*", "'set' for available options", set_value_cmd },
848879 { "?", "Print help", nullptr, nullptr, cmd_help },
849880
850881 // Undocumented commands
@@ -865,8 +896,8 @@ namespace · 14 unmodified lines
865896
866897 void print_help()
867898 {
868− auto ss = std::stringstream{};
869− ss << "Commands:\n";
899+ auto msg = std::stringstream{};
900+ msg << "Commands:\n";
870901 for (auto i = std::size_t{}; i < sizeof(cmds) / sizeof(cmds[0]); ++i)
871902 {
872903 auto &c = cmds[i];
@@ -875,16 +906,33 @@ namespace · 2 unmodified lines
875906 if (c.description == nullptr)
876907 continue;
877908
878− ss << " " << c.cmd << "\t" << c.description << "\n";
909+ msg << " " << c.cmd << "\t" << c.description << "\n";
879910
880911 if (c.syntax != nullptr)
881− ss << "\t Syntax: " << c.syntax << "\n";
912+ msg << "\t Syntax: " << c.syntax << "\n";
882913
883914 if (c.example != nullptr)
884− ss << "\t Example(s): " << c.example << "\n";
915+ msg << "\t Example(s): " << c.example << "\n";
885916 }
886917
887− debug_print_info(ss.str());
918+ debug_print_info(msg.str());
919+ }
920+
921+ void execute_single_command(dbg_cmd_cxt_t &cxt, const std::string &cmd)
922+ {
923+ const auto cmd_tokens = util::split(cmd);
924+ if (cmd_tokens.empty())
925+ return;
926+
927+ try
928+ {
929+ auto cmd_exec = find_cmd(cmd_tokens[0]);
930+ cmd_exec(cmd_tokens, cxt);
931+ }
932+ catch (const debug_cmd_error_t &e)
933+ {
934+ debug_print_error(e.what());
935+ }
888936 }
889937
890938 void prompt(debugger &debugger, const vm_registers_t &r)
@@ -910,21 +958,11 @@ namespace · 19 unmodified lines
910958 << console_modifiers::reset_all;
911959
912960 std::getline(std::cin, cmd);
913− const auto cmd_tokens = util::split(cmd);
914− if (cmd_tokens.empty())
915− continue;
916961
917− try
918− {
919− auto cmd_exec = find_cmd(cmd_tokens[0]);
920− cmd_exec(cmd_tokens, cxt);
921− if (cxt.exit_break)
922− break;
923− }
924− catch (const debug_cmd_error_t &e)
925− {
926− debug_print_error(e.what());
927− }
962+ assert(!cxt.exit_break && "Pre-condition on exit_break state before execute failed");
963+ execute_single_command(cxt, cmd);
964+ if (cxt.exit_break)
965+ break;
928966 }
929967
930968 debugger.controller->resume_all_threads();
@@ -1019,6 +1057,20 @@ bool debugger::symbols_exist(disvm::runtime::module_id_t vm_id) const · 88 unmodified lines
10191057 return _vm_id_to_symbol_info.find(vm_id) != std::cend(_vm_id_to_symbol_info);
10201058 }
10211059
1060+std::string debugger::get_option(const std::string &option) const
1061+{
1062+ auto iter = _debugger_options.find(option);
1063+ if (iter == std::cend(_debugger_options))
1064+ return{};
1065+
1066+ return iter->second;
1067+}
1068+
1069+void debugger::set_option(const std::string &option, std::string value)
1070+{
1071+ _debugger_options[option] = std::move(value);
1072+}
1073+
10221074 void debugger::on_load(vm_tool_controller_t &controller_, std::size_t tool_id)
10231075 {
10241076 _tool_id = tool_id;
@@ -1115,8 +1167,12 @@ void debugger::on_load(vm_tool_controller_t &controller_, std::size_t tool_id) · 90 unmodified lines
11151167
11161168 debug_print_info(ss.str());
11171169
1118− auto reg_str = registers_to_string(*cxt.value1.registers);
1119− debug_print_info(reg_str);
1170+ const auto bp_cmd = get_option({ "bp-cmd" });
1171+ if (!bp_cmd.empty())
1172+ {
1173+ dbg_cmd_cxt_t dbg_cxt{ *this, *cxt.value1.registers };
1174+ execute_single_command(dbg_cxt, bp_cmd);
1175+ }
11201176
11211177 prompt(*this, *cxt.value1.registers);
11221178 }));
@@ -1163,7 +1219,7 @@ void debugger::load_symbols(const disvm::loaded_vm_module_t &loaded_mod) · 40 unmodified lines
11631219 catch (const std::runtime_error &e)
11641220 {
11651221 // File with assumed symbol name/extension is not the correct format
1166− std::stringstream msg;
1222+ auto msg = std::stringstream{};
11671223 msg << "Assumed symbol file '"
11681224 << symbol_path_maybe
11691225 << "' has invalid symbol format. ("
@@ -1178,7 +1234,7 @@ void debugger::load_symbols(const disvm::loaded_vm_module_t &loaded_mod) · 8 unmodified lines
11781234 || symbol_data->get_instruction_count() != m->code_section.size())
11791235 {
11801236 // Symbol file does not match the loaded modules - stale file?
1181− std::stringstream msg;
1237+ auto msg = std::stringstream{};
11821238 msg << "Symbol file '"
11831239 << symbol_path_maybe
11841240 << "' does not match loaded module '"
@@ -1193,7 +1249,7 @@ void debugger::load_symbols(const disvm::loaded_vm_module_t &loaded_mod) · 8 unmodified lines
11931249 auto symbol_iter = symbol_data->get_pc_iter();
11941250 _vm_id_to_symbol_info[vm_id] = { std::move(symbol_data), std::move(symbol_iter) };
11951251
1196− std::stringstream msg;
1252+ auto msg = std::stringstream{};
11971253 msg << "Symbol file '"
11981254 << symbol_path_maybe
11991255 << "' loaded for '"