Showing the changes to src/exec/debugger.cpp (1 of 2 files). Show all
Unified · Split
| @@ -11,6 +11,7 @@ · 10 unmodified lines | ||
| 11 | 11 | #include <string> |
| 12 | 12 | #include <algorithm> |
| 13 | 13 | #include <map> |
| 14 | +#include <unordered_set> | |
| 14 | 15 | #include <utils.h> |
| 15 | 16 | #include <vm_memory.h> |
| 16 | 17 | #include <vm_asm.h> |
| @@ -383,9 +384,9 @@ namespace · 366 unmodified lines | ||
| 383 | 384 | |
| 384 | 385 | auto msg = std::stringstream{}; |
| 385 | 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 | 388 | for (auto &f : module_funcs) |
| 388 | − msg << " " << f << "\n"; | |
| 389 | + msg << "\n " << f; | |
| 389 | 390 | |
| 390 | 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 | 620 | const auto &r = *cxt.current_register; |
| 619 | 621 | const auto &code_section = r.module_ref->code_section; |
| 620 | 622 | |
| @@ -623,19 +625,19 @@ namespace · 2 unmodified lines | ||
| 623 | 625 | if (disassemble_length < 0) |
| 624 | 626 | { |
| 625 | 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 | 630 | else |
| 629 | 631 | { |
| 630 | 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 | 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 | 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 | 642 | auto op = code_section[i].op; |
| 641 | 643 | |
| @@ -645,9 +647,9 @@ namespace · 3 unmodified lines | ||
| 645 | 647 | if (op.opcode == opcode_t::brkpt) |
| 646 | 648 | { |
| 647 | 649 | // 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 | 653 | if (details.pc == i && details.module == r.module_ref->module) |
| 652 | 654 | { |
| 653 | 655 | op.opcode = details.original_opcode; |
| @@ -660,9 +662,9 @@ namespace · 6 unmodified lines | ||
| 660 | 662 | // Print source location if resolved |
| 661 | 663 | if (!resolved_pc.empty()) |
| 662 | 664 | { |
| 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"; | |
| 666 | 668 | } |
| 667 | 669 | |
| 668 | 670 | msg << op_prefix << std::setw(5) << i << ": " << op << "\n"; |
| @@ -811,18 +813,47 @@ namespace · 142 unmodified lines | ||
| 811 | 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 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()); | |
| 819 | 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' command | |
| 824 | − return; | |
| 849 | + new_value << args[i]; | |
| 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 | 859 | const dbg_cmd_t cmds[] = |
| @@ -844,7 +875,7 @@ namespace · 15 unmodified lines | ||
| 844 | 875 | { "d", "Disassemble the next/previous N instructions (default N = 4)", "d (-?[0-9]+)?", "d, d -4, d 5", cmd_disassemble }, |
| 845 | 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 | 879 | { "?", "Print help", nullptr, nullptr, cmd_help }, |
| 849 | 880 | |
| 850 | 881 | // Undocumented commands |
| @@ -865,8 +896,8 @@ namespace · 14 unmodified lines | ||
| 865 | 896 | |
| 866 | 897 | void print_help() |
| 867 | 898 | { |
| 868 | − auto ss = std::stringstream{}; | |
| 869 | − ss << "Commands:\n"; | |
| 899 | + auto msg = std::stringstream{}; | |
| 900 | + msg << "Commands:\n"; | |
| 870 | 901 | for (auto i = std::size_t{}; i < sizeof(cmds) / sizeof(cmds[0]); ++i) |
| 871 | 902 | { |
| 872 | 903 | auto &c = cmds[i]; |
| @@ -875,16 +906,33 @@ namespace · 2 unmodified lines | ||
| 875 | 906 | if (c.description == nullptr) |
| 876 | 907 | continue; |
| 877 | 908 | |
| 878 | − ss << " " << c.cmd << "\t" << c.description << "\n"; | |
| 909 | + msg << " " << c.cmd << "\t" << c.description << "\n"; | |
| 879 | 910 | |
| 880 | 911 | if (c.syntax != nullptr) |
| 881 | − ss << "\t Syntax: " << c.syntax << "\n"; | |
| 912 | + msg << "\t Syntax: " << c.syntax << "\n"; | |
| 882 | 913 | |
| 883 | 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 | 938 | void prompt(debugger &debugger, const vm_registers_t &r) |
| @@ -910,21 +958,11 @@ namespace · 19 unmodified lines | ||
| 910 | 958 | << console_modifiers::reset_all; |
| 911 | 959 | |
| 912 | 960 | std::getline(std::cin, cmd); |
| 913 | − const auto cmd_tokens = util::split(cmd); | |
| 914 | − if (cmd_tokens.empty()) | |
| 915 | − continue; | |
| 916 | 961 | |
| 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; | |
| 928 | 966 | } |
| 929 | 967 | |
| 930 | 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 | 1057 | return _vm_id_to_symbol_info.find(vm_id) != std::cend(_vm_id_to_symbol_info); |
| 1020 | 1058 | } |
| 1021 | 1059 | |
| 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 | + | |
| 1022 | 1074 | void debugger::on_load(vm_tool_controller_t &controller_, std::size_t tool_id) |
| 1023 | 1075 | { |
| 1024 | 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 | 1168 | debug_print_info(ss.str()); |
| 1117 | 1169 | |
| 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 | + } | |
| 1120 | 1176 | |
| 1121 | 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 | 1219 | catch (const std::runtime_error &e) |
| 1164 | 1220 | { |
| 1165 | 1221 | // File with assumed symbol name/extension is not the correct format |
| 1166 | − std::stringstream msg; | |
| 1222 | + auto msg = std::stringstream{}; | |
| 1167 | 1223 | msg << "Assumed symbol file '" |
| 1168 | 1224 | << symbol_path_maybe |
| 1169 | 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 | 1234 | || symbol_data->get_instruction_count() != m->code_section.size()) |
| 1179 | 1235 | { |
| 1180 | 1236 | // Symbol file does not match the loaded modules - stale file? |
| 1181 | − std::stringstream msg; | |
| 1237 | + auto msg = std::stringstream{}; | |
| 1182 | 1238 | msg << "Symbol file '" |
| 1183 | 1239 | << symbol_path_maybe |
| 1184 | 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 | 1249 | auto symbol_iter = symbol_data->get_pc_iter(); |
| 1194 | 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 | 1253 | msg << "Symbol file '" |
| 1198 | 1254 | << symbol_path_maybe |
| 1199 | 1255 | << "' loaded for '" |