Showing the changes to src/exec/debugger.cpp (1 of 2 files). Show all
Unified · Split
| @@ -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 | else | 630 | 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 module | 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 | 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 resolved | 662 | // 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 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 | 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' command | 849 | 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 commands | 881 | // 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 | try | 962 | 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 | ||
| 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 | void debugger::on_load(vm_tool_controller_t &controller_, std::size_t tool_id) | 1074 | void 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 format | 1221 | // 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_maybe | 1224 | << 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_maybe | 1239 | << 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_maybe | 1254 | << symbol_path_maybe |
| 1199 | << "' loaded for '" | 1255 | << "' loaded for '" |