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
11#include <string>11#include <string>
12#include <algorithm>12#include <algorithm>
13#include <map>13#include <map>
14#include <unordered_set>
14#include <utils.h>15#include <utils.h>
15#include <vm_memory.h>16#include <vm_memory.h>
16#include <vm_asm.h>17#include <vm_asm.h>
@@ -383,9 +384,9 @@ namespace · 366 unmodified lines
383 384
384 auto msg = std::stringstream{};385 auto msg = std::stringstream{};
385 auto module_funcs = cxt.dbg.get_module_functions(vm_id, name_to_match);386 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]";
387 for (auto &f : module_funcs)388 for (auto &f : module_funcs)
388 msg << " " << f << "\n";389 msg << "\n " << f;
389 390
390 debug_print_info(msg.str());391 debug_print_info(msg.str());
391 }392 }
@@ -615,6 +616,7 @@ namespace · 223 unmodified lines
615 }616 }
616 }617 }
617 618
619 auto &dbg = cxt.dbg;
618 const auto &r = *cxt.current_register;620 const auto &r = *cxt.current_register;
619 const auto &code_section = r.module_ref->code_section;621 const auto &code_section = r.module_ref->code_section;
620 622
@@ -623,19 +625,19 @@ namespace · 2 unmodified lines
623 if (disassemble_length < 0)625 if (disassemble_length < 0)
624 {626 {
625 const auto begin_maybe = r.pc - (-disassemble_length) + 1;627 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));
627 }629 }
628 else630 else
629 {631 {
630 const auto end_maybe = static_cast<std::size_t>(r.pc + disassemble_length);632 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);
632 }634 }
633 635
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);
635 assert(resolved_pc.empty() || resolved_pc.size() == (end_pc - begin_pc + 1) && "Resolved PCs should have failed or match the PC count");637 assert(resolved_pc.empty() || resolved_pc.size() == (end_pc - begin_pc + 1) && "Resolved PCs should have failed or match the PC count");
636 638
637 auto msg = std::stringstream{};639 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)
639 {641 {
640 auto op = code_section[i].op;642 auto op = code_section[i].op;
641 643
@@ -645,9 +647,9 @@ namespace · 3 unmodified lines
645 if (op.opcode == opcode_t::brkpt)647 if (op.opcode == opcode_t::brkpt)
646 {648 {
647 // Look up each of the known cookies to try and find the matching PC and module649 // 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)
649 {651 {
650 const auto details = cxt.dbg.controller->get_breakpoint_details(bp_cookie);652 const auto details = dbg.controller->get_breakpoint_details(bp_cookie);
651 if (details.pc == i && details.module == r.module_ref->module)653 if (details.pc == i && details.module == r.module_ref->module)
652 {654 {
653 op.opcode = details.original_opcode;655 op.opcode = details.original_opcode;
@@ -660,9 +662,9 @@ namespace · 6 unmodified lines
660 // Print source location if resolved662 // Print source location if resolved
661 if (!resolved_pc.empty())663 if (!resolved_pc.empty())
662 {664 {
663 const auto & r = resolved_pc[i - begin_pc];665 const auto &rpc = resolved_pc[i - begin_pc];
664 if (!r.empty())666 if (!rpc.empty())
665 msg << r << "\n";667 msg << rpc << "\n";
666 }668 }
667 669
668 msg << op_prefix << std::setw(5) << i << ": " << op << "\n";670 msg << op_prefix << std::setw(5) << i << ": " << op << "\n";
@@ -811,18 +813,47 @@ namespace · 142 unmodified lines
811 << console_modifiers::reset_all;813 << console_modifiers::reset_all;
812 }814 }
813 815
814 void set_value_cmd(const std::vector<std::string> &args, dbg_cmd_cxt_t &)816 std::unordered_set<std::string> dbg_options =
815 {817 {
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)
817 {825 {
818 // [TODO] Print all options current state826 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());
819 return;837 return;
820 }838 }
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)
822 {848 {
823 // [TODO] Print help for 'set' command849 new_value << args[i];
824 return;850
851 // For the last parsed arg
852 if (i + 1 < args.size())
853 new_value << " ";
825 }854 }
855
856 cxt.dbg.set_option(curr_option, new_value.str());
826 }857 }
827 858
828 const dbg_cmd_t cmds[] =859 const dbg_cmd_t cmds[] =
@@ -844,7 +875,7 @@ namespace · 15 unmodified lines
844 { "d", "Disassemble the next/previous N instructions (default N = 4)", "d (-?[0-9]+)?", "d, d -4, d 5", cmd_disassemble },875 { "d", "Disassemble the next/previous N instructions (default N = 4)", "d (-?[0-9]+)?", "d, d -4, d 5", cmd_disassemble },
845 { "x", "Examine memory", "x [mp|fp] [0-9]+ ([0-9]+)?", "x mp 3, x fp 20 6", cmd_examine },876 { "x", "Examine memory", "x [mp|fp] [0-9]+ ([0-9]+)?", "x mp 3, x fp 20 6", cmd_examine },
846 877
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 },
848 { "?", "Print help", nullptr, nullptr, cmd_help },879 { "?", "Print help", nullptr, nullptr, cmd_help },
849 880
850 // Undocumented commands881 // Undocumented commands
@@ -865,8 +896,8 @@ namespace · 14 unmodified lines
865 896
866 void print_help()897 void print_help()
867 {898 {
868 auto ss = std::stringstream{};899 auto msg = std::stringstream{};
869 ss << "Commands:\n";900 msg << "Commands:\n";
870 for (auto i = std::size_t{}; i < sizeof(cmds) / sizeof(cmds[0]); ++i)901 for (auto i = std::size_t{}; i < sizeof(cmds) / sizeof(cmds[0]); ++i)
871 {902 {
872 auto &c = cmds[i];903 auto &c = cmds[i];
@@ -875,16 +906,33 @@ namespace · 2 unmodified lines
875 if (c.description == nullptr)906 if (c.description == nullptr)
876 continue;907 continue;
877 908
878 ss << " " << c.cmd << "\t" << c.description << "\n";909 msg << " " << c.cmd << "\t" << c.description << "\n";
879 910
880 if (c.syntax != nullptr)911 if (c.syntax != nullptr)
881 ss << "\t Syntax: " << c.syntax << "\n";912 msg << "\t Syntax: " << c.syntax << "\n";
882 913
883 if (c.example != nullptr)914 if (c.example != nullptr)
884 ss << "\t Example(s): " << c.example << "\n";915 msg << "\t Example(s): " << c.example << "\n";
885 }916 }
886 917
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 }
888 }936 }
889 937
890 void prompt(debugger &debugger, const vm_registers_t &r)938 void prompt(debugger &debugger, const vm_registers_t &r)
@@ -910,21 +958,11 @@ namespace · 19 unmodified lines
910 << console_modifiers::reset_all;958 << console_modifiers::reset_all;
911 959
912 std::getline(std::cin, cmd);960 std::getline(std::cin, cmd);
913 const auto cmd_tokens = util::split(cmd);
914 if (cmd_tokens.empty())
915 continue;
916 961
917 try962 assert(!cxt.exit_break && "Pre-condition on exit_break state before execute failed");
918 {963 execute_single_command(cxt, cmd);
919 auto cmd_exec = find_cmd(cmd_tokens[0]);964 if (cxt.exit_break)
920 cmd_exec(cmd_tokens, cxt);965 break;
921 if (cxt.exit_break)
922 break;
923 }
924 catch (const debug_cmd_error_t &e)
925 {
926 debug_print_error(e.what());
927 }
928 }966 }
929 967
930 debugger.controller->resume_all_threads();968 debugger.controller->resume_all_threads();
@@ -1019,6 +1057,20 @@ bool debugger::symbols_exist(disvm::runtime::module_id_t vm_id) const · 88 unmodified lines
1019 return _vm_id_to_symbol_info.find(vm_id) != std::cend(_vm_id_to_symbol_info);1057 return _vm_id_to_symbol_info.find(vm_id) != std::cend(_vm_id_to_symbol_info);
1020}1058}
1021 1059
1060std::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
1069void debugger::set_option(const std::string &option, std::string value)
1070{
1071 _debugger_options[option] = std::move(value);
1072}
1073
1022void debugger::on_load(vm_tool_controller_t &controller_, std::size_t tool_id)1074void debugger::on_load(vm_tool_controller_t &controller_, std::size_t tool_id)
1023{1075{
1024 _tool_id = tool_id;1076 _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
1115 1167
1116 debug_print_info(ss.str());1168 debug_print_info(ss.str());
1117 1169
1118 auto reg_str = registers_to_string(*cxt.value1.registers);1170 const auto bp_cmd = get_option({ "bp-cmd" });
1119 debug_print_info(reg_str);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 }
1120 1176
1121 prompt(*this, *cxt.value1.registers);1177 prompt(*this, *cxt.value1.registers);
1122 }));1178 }));
@@ -1163,7 +1219,7 @@ void debugger::load_symbols(const disvm::loaded_vm_module_t &loaded_mod) · 40 unmodified lines
1163 catch (const std::runtime_error &e)1219 catch (const std::runtime_error &e)
1164 {1220 {
1165 // File with assumed symbol name/extension is not the correct format1221 // File with assumed symbol name/extension is not the correct format
1166 std::stringstream msg;1222 auto msg = std::stringstream{};
1167 msg << "Assumed symbol file '"1223 msg << "Assumed symbol file '"
1168 << symbol_path_maybe1224 << symbol_path_maybe
1169 << "' has invalid symbol format. ("1225 << "' has invalid symbol format. ("
@@ -1178,7 +1234,7 @@ void debugger::load_symbols(const disvm::loaded_vm_module_t &loaded_mod) · 8 unmodified lines
1178 || symbol_data->get_instruction_count() != m->code_section.size())1234 || symbol_data->get_instruction_count() != m->code_section.size())
1179 {1235 {
1180 // Symbol file does not match the loaded modules - stale file?1236 // Symbol file does not match the loaded modules - stale file?
1181 std::stringstream msg;1237 auto msg = std::stringstream{};
1182 msg << "Symbol file '"1238 msg << "Symbol file '"
1183 << symbol_path_maybe1239 << symbol_path_maybe
1184 << "' does not match loaded module '"1240 << "' does not match loaded module '"
@@ -1193,7 +1249,7 @@ void debugger::load_symbols(const disvm::loaded_vm_module_t &loaded_mod) · 8 unmodified lines
1193 auto symbol_iter = symbol_data->get_pc_iter();1249 auto symbol_iter = symbol_data->get_pc_iter();
1194 _vm_id_to_symbol_info[vm_id] = { std::move(symbol_data), std::move(symbol_iter) };1250 _vm_id_to_symbol_info[vm_id] = { std::move(symbol_data), std::move(symbol_iter) };
1195 1251
1196 std::stringstream msg;1252 auto msg = std::stringstream{};
1197 msg << "Symbol file '"1253 msg << "Symbol file '"
1198 << symbol_path_maybe1254 << symbol_path_maybe
1199 << "' loaded for '"1255 << "' loaded for '"