Remove tabs from all logging
Unified · Split
| @@ -13,6 +13,7 @@ · 12 unmodified lines | ||
| 13 | 13 | #include <utils.h> |
| 14 | 14 | #include <vm_memory.h> |
| 15 | 15 | #include <vm_asm.h> |
| 16 | +#include <exceptions.h> | |
| 16 | 17 | #include "exec.h" |
| 17 | 18 | |
| 18 | 19 | using namespace disvm; |
| @@ -289,6 +290,11 @@ namespace · 270 unmodified lines | ||
| 289 | 290 | cxt.exit_break = true; |
| 290 | 291 | } |
| 291 | 292 | |
| 293 | + void cmd_term(const std::vector<std::string> &, dbg_cmd_cxt_t &cxt) | |
| 294 | + { | |
| 295 | + throw vm_user_exception{ "Debugger signaled VM termination" }; | |
| 296 | + } | |
| 297 | + | |
| 292 | 298 | void cmd_print_registers(const std::vector<std::string> &, dbg_cmd_cxt_t &cxt) |
| 293 | 299 | { |
| 294 | 300 | auto s = registers_to_string(*cxt.current_register); |
| @@ -740,6 +746,7 @@ namespace · 445 unmodified lines | ||
| 740 | 746 | const dbg_cmd_t cmds[] = |
| 741 | 747 | { |
| 742 | 748 | { "c", "Continue", nullptr, nullptr, cmd_continue }, |
| 749 | + { "term", "Terminate the VM instance", nullptr, nullptr, cmd_term }, | |
| 743 | 750 | |
| 744 | 751 | { "r", "Print registers", nullptr, nullptr, cmd_print_registers }, |
| 745 | 752 | { "t", "Print all threads", nullptr, nullptr, cmd_print_threads }, |
| @@ -862,8 +869,18 @@ namespace · 116 unmodified lines | ||
| 862 | 869 | } |
| 863 | 870 | } |
| 864 | 871 | |
| 865 | −debugger::debugger() | |
| 866 | − : _tool_id{ 0 } | |
| 872 | +std::ostream& operator<<(std::ostream &ss, const debugger_options o) | |
| 873 | +{ | |
| 874 | + ss << "Break on enter: " << std::boolalpha << o.break_on_enter << "\n" | |
| 875 | + << "Break on module load: " << std::boolalpha << o.break_on_module_load << "\n" | |
| 876 | + << "Break on exception: " << std::boolalpha << o.break_on_exception << "\n"; | |
| 877 | + | |
| 878 | + return ss; | |
| 879 | +} | |
| 880 | + | |
| 881 | +debugger::debugger(const debugger_options &opt) | |
| 882 | + : _options{ opt } | |
| 883 | + , _tool_id{ 0 } | |
| 867 | 884 | , controller{ nullptr } |
| 868 | 885 | { } |
| 869 | 886 | |
| @@ -896,7 +913,7 @@ void debugger::on_load(vm_tool_controller_t &controller_, std::size_t tool_id) · 26 unmodified lines | ||
| 896 | 913 | debug_print_info(ss.str()); |
| 897 | 914 | })); |
| 898 | 915 | |
| 899 | − _event_cookies.push_back(controller->subscribe_event(vm_event_t::exception_raised, [](vm_event_t, vm_event_context_t &cxt) | |
| 916 | + _event_cookies.push_back(controller->subscribe_event(vm_event_t::exception_raised, [&](vm_event_t, vm_event_context_t &cxt) | |
| 900 | 917 | { |
| 901 | 918 | auto ss = std::stringstream{}; |
| 902 | 919 | ss << "Exception '" |
| @@ -904,6 +921,9 @@ void debugger::on_load(vm_tool_controller_t &controller_, std::size_t tool_id) · 1 unmodified line | ||
| 904 | 921 | << "' thrown."; |
| 905 | 922 | |
| 906 | 923 | debug_print_info(ss.str()); |
| 924 | + | |
| 925 | + if (_options.break_on_exception) | |
| 926 | + prompt(*this, *cxt.value1.registers); | |
| 907 | 927 | })); |
| 908 | 928 | |
| 909 | 929 | _event_cookies.push_back(controller->subscribe_event(vm_event_t::exception_unhandled, [&](vm_event_t, vm_event_context_t &cxt) |
| @@ -928,8 +948,20 @@ void debugger::on_load(vm_tool_controller_t &controller_, std::size_t tool_id) · 18 unmodified lines | ||
| 928 | 948 | if (util::has_flag(m->header.runtime_flag, runtime_flags_t::builtin)) |
| 929 | 949 | ss << " (built-in)"; |
| 930 | 950 | |
| 931 | − | |
| 932 | 951 | debug_print_info(ss.str()); |
| 952 | + | |
| 953 | + // If the break on enter flag was set, it will be true | |
| 954 | + // and the first module load will be the user entry module. | |
| 955 | + if (_options.break_on_enter) | |
| 956 | + { | |
| 957 | + // Reset the break on enter flag and set a breakpoint | |
| 958 | + // on the entry PC for the module - 'break on enter' | |
| 959 | + _options.break_on_enter = false; | |
| 960 | + controller->set_breakpoint(m, m->header.entry_pc); | |
| 961 | + } | |
| 962 | + | |
| 963 | + if (_options.break_on_module_load) | |
| 964 | + prompt(*this, *cxt.value1.registers); | |
| 933 | 965 | })); |
| 934 | 966 | |
| 935 | 967 | _event_cookies.push_back(controller->subscribe_event(vm_event_t::breakpoint, [&](vm_event_t, vm_event_context_t &cxt) |
| @@ -12,13 +12,22 @@ · 11 unmodified lines | ||
| 12 | 12 | #include <disvm.h> |
| 13 | 13 | #include <vm_tools.h> |
| 14 | 14 | |
| 15 | +struct debugger_options | |
| 16 | +{ | |
| 17 | + bool break_on_enter; | |
| 18 | + bool break_on_module_load; | |
| 19 | + bool break_on_exception; | |
| 20 | +}; | |
| 21 | + | |
| 22 | +std::ostream& operator<<(std::ostream &ss, const debugger_options o); | |
| 23 | + | |
| 15 | 24 | class debugger final : public disvm::runtime::vm_tool_t |
| 16 | 25 | { |
| 17 | 26 | public: |
| 18 | − debugger(); | |
| 27 | + debugger(const debugger_options &); | |
| 19 | 28 | |
| 20 | 29 | public: // vm_tool_t |
| 21 | − void on_load(disvm::runtime::vm_tool_controller_t &controller, std::size_t tool_id) override; | |
| 30 | + void on_load(disvm::runtime::vm_tool_controller_t &, std::size_t tool_id) override; | |
| 22 | 31 | |
| 23 | 32 | void on_unload() override; |
| 24 | 33 | |
| @@ -27,6 +36,7 @@ public: · 2 unmodified lines | ||
| 27 | 36 | std::vector<disvm::runtime::cookie_t> breakpoint_cookies; |
| 28 | 37 | |
| 29 | 38 | private: |
| 39 | + debugger_options _options; | |
| 30 | 40 | std::size_t _tool_id; |
| 31 | 41 | std::vector<disvm::runtime::cookie_t> _event_cookies; |
| 32 | 42 | }; |
| @@ -30,10 +30,14 @@ namespace · 29 unmodified lines | ||
| 30 | 30 | |
| 31 | 31 | std::shared_ptr<const vm_module_t> command_module; |
| 32 | 32 | |
| 33 | − std::unique_ptr<vm_module_t> create_entry_module(vm_t &vm, int argc, char* argv[]) | |
| 33 | + std::unique_ptr<vm_module_t> create_entry_module(vm_t &vm, const std::vector<char *> &vm_args) | |
| 34 | 34 | { |
| 35 | + if (vm_args.size() == 0) | |
| 36 | + throw vm_user_exception{ "Entry module not supplied" }; | |
| 37 | + | |
| 35 | 38 | // First argument is the module to load |
| 36 | − auto command_module_path = new vm_string_t{ std::strlen(argv[0]), reinterpret_cast<uint8_t *>(argv[0]) }; | |
| 39 | + auto entry_module_path = vm_args[0]; | |
| 40 | + auto command_module_path = new vm_string_t{ std::strlen(entry_module_path), reinterpret_cast<uint8_t *>(entry_module_path) }; | |
| 37 | 41 | |
| 38 | 42 | // Pre-load the command module in the VM. |
| 39 | 43 | command_module = vm.load_module(command_module_path->str()); |
| @@ -41,9 +45,9 @@ namespace · 1 unmodified line | ||
| 41 | 45 | // Convert arguments to a list |
| 42 | 46 | vm_list_t *args = nullptr; |
| 43 | 47 | vm_list_t *last = nullptr; |
| 44 | − for (auto i = 1; i < argc; ++i) | |
| 48 | + for (auto i = std::size_t{ 1 }; i < vm_args.size(); ++i) | |
| 45 | 49 | { |
| 46 | − auto tmp = argv[i]; | |
| 50 | + auto tmp = vm_args[i]; | |
| 47 | 51 | auto arg = new vm_string_t{ std::strlen(tmp), reinterpret_cast<uint8_t *>(tmp) }; |
| 48 | 52 | if (args == nullptr) |
| 49 | 53 | { |
| @@ -165,39 +169,160 @@ namespace · 115 unmodified lines | ||
| 165 | 169 | } |
| 166 | 170 | } |
| 167 | 171 | |
| 172 | +struct arg_exception_t : std::runtime_error | |
| 173 | +{ | |
| 174 | + arg_exception_t(const char *m, const char *arg) | |
| 175 | + : std::runtime_error{ m } | |
| 176 | + , arg{ arg } | |
| 177 | + { } | |
| 178 | + | |
| 179 | + const char * const arg; | |
| 180 | +}; | |
| 181 | + | |
| 182 | +struct exec_options | |
| 183 | +{ | |
| 184 | + std::vector<char *> vm_args; | |
| 185 | + | |
| 186 | + bool print_help; | |
| 187 | + bool quiet_start; | |
| 188 | + bool enabled_debugger; | |
| 189 | + debugger_options debugger; | |
| 190 | +}; | |
| 191 | + | |
| 192 | +void print_banner(const exec_options &options) | |
| 193 | +{ | |
| 194 | + std::cout | |
| 195 | + << "DisVM\n" | |
| 196 | + << "----------------\n" | |
| 197 | + << "Debugger enabled: " << std::boolalpha << options.enabled_debugger << "\n"; | |
| 198 | + | |
| 199 | + if (options.enabled_debugger) | |
| 200 | + std::cout << options.debugger << "\n"; | |
| 201 | + | |
| 202 | + std::cout << std::endl; | |
| 203 | +} | |
| 204 | + | |
| 205 | +void print_help() | |
| 206 | +{ | |
| 207 | + std::cout | |
| 208 | + << "Usage: disvm-exec [-d[e|m|x]*] [-q] [-?] <entry module> <args>*\n" | |
| 209 | + << " d - Enable debugger\n" | |
| 210 | + << " e - Break on entry\n" | |
| 211 | + << " m - Break on module load\n" | |
| 212 | + << " x - Break on exception (first chance)\n" | |
| 213 | + << " q - Suppress banner and configuration\n" | |
| 214 | + << " ? - Print help\n"; | |
| 215 | +} | |
| 216 | + | |
| 217 | +void process_arg(char* arg, std::function<char *()> next, exec_options &options) | |
| 218 | +{ | |
| 219 | + assert(arg != nullptr && next != nullptr); | |
| 220 | + if (arg[0] != '-') | |
| 221 | + { | |
| 222 | + for (; arg != nullptr; arg = next()) | |
| 223 | + options.vm_args.push_back(arg); | |
| 224 | + | |
| 225 | + return; | |
| 226 | + } | |
| 227 | + | |
| 228 | + auto arg_len = std::strlen(arg); | |
| 229 | + if (arg_len < 2) | |
| 230 | + throw arg_exception_t{ "Invalid flag format", arg }; | |
| 231 | + | |
| 232 | + switch (arg[1]) | |
| 233 | + { | |
| 234 | + case 'd': | |
| 235 | + options.enabled_debugger = true; | |
| 236 | + for (auto i = std::size_t{ 2 }; i < arg_len; ++i) | |
| 237 | + { | |
| 238 | + switch (arg[i]) | |
| 239 | + { | |
| 240 | + case 'e': options.debugger.break_on_enter = true; | |
| 241 | + break; | |
| 242 | + case 'm': options.debugger.break_on_module_load = true; | |
| 243 | + break; | |
| 244 | + case 'x': options.debugger.break_on_exception = true; | |
| 245 | + break; | |
| 246 | + } | |
| 247 | + } | |
| 248 | + | |
| 249 | + break; | |
| 250 | + | |
| 251 | + case 'q': | |
| 252 | + options.quiet_start = true; | |
| 253 | + break; | |
| 254 | + | |
| 255 | + case '?': | |
| 256 | + options.print_help = true; | |
| 257 | + break; | |
| 258 | + | |
| 259 | + default: | |
| 260 | + throw arg_exception_t{ "Unknown flag", arg }; | |
| 261 | + } | |
| 262 | +} | |
| 263 | + | |
| 168 | 264 | int main(int argc, char* argv[]) |
| 169 | 265 | { |
| 170 | − // [TODO] Handle command line arguments | |
| 171 | − assert(argc > 1); | |
| 266 | + exec_options options = {}; | |
| 267 | + | |
| 268 | + try | |
| 269 | + { | |
| 270 | + // Ignore the process name | |
| 271 | + auto arg_idx = int{ 1 }; | |
| 272 | + auto next_arg = [&]() | |
| 273 | + { | |
| 274 | + return arg_idx < argc ? argv[arg_idx++] : nullptr; | |
| 275 | + }; | |
| 276 | + | |
| 277 | + for (auto curr_arg = next_arg(); curr_arg != nullptr; curr_arg = next_arg()) | |
| 278 | + process_arg(curr_arg, next_arg, options); | |
| 279 | + } | |
| 280 | + catch (const arg_exception_t &ae) | |
| 281 | + { | |
| 282 | + std::cerr << ae.what(); | |
| 283 | + if (ae.arg != nullptr) | |
| 284 | + std::cerr << ": " << ae.arg << std::endl; | |
| 285 | + | |
| 286 | + return EXIT_FAILURE; | |
| 287 | + } | |
| 288 | + | |
| 289 | + if (!options.quiet_start) | |
| 290 | + print_banner(options); | |
| 291 | + | |
| 292 | + if (options.print_help) | |
| 293 | + { | |
| 294 | + print_help(); | |
| 295 | + return EXIT_SUCCESS; | |
| 296 | + } | |
| 172 | 297 | |
| 173 | 298 | vm_t vm; |
| 174 | 299 | |
| 175 | − //vm.load_tool(std::make_shared<debugger>()); | |
| 300 | + if (options.enabled_debugger) | |
| 301 | + vm.load_tool(std::make_shared<debugger>(options.debugger)); | |
| 176 | 302 | |
| 177 | 303 | try |
| 178 | 304 | { |
| 179 | − // Ignore the process name | |
| 180 | − auto entry = create_entry_module(vm, argc - 1, argv + 1); | |
| 305 | + auto entry = create_entry_module(vm, options.vm_args); | |
| 181 | 306 | |
| 182 | 307 | vm.exec(std::move(entry)); |
| 183 | 308 | |
| 184 | 309 | vm.spin_sleep_till_idle(std::chrono::milliseconds(100)); |
| 185 | 310 | } |
| 186 | − catch (vm_user_exception &ue) | |
| 311 | + catch (const vm_user_exception &ue) | |
| 187 | 312 | { |
| 188 | − std::cout << ue.what() << std::endl; | |
| 313 | + std::cerr << ue.what() << std::endl; | |
| 189 | 314 | |
| 190 | 315 | return EXIT_FAILURE; |
| 191 | 316 | } |
| 192 | − catch (vm_system_exception &se) | |
| 317 | + catch (const vm_system_exception &se) | |
| 193 | 318 | { |
| 194 | − std::cout | |
| 195 | − << "Internal exception:\n\t" | |
| 319 | + std::cerr | |
| 320 | + << "Internal exception:\n " | |
| 196 | 321 | << se.what() |
| 197 | 322 | << std::endl; |
| 198 | 323 | |
| 199 | 324 | return EXIT_FAILURE; |
| 200 | 325 | } |
| 201 | 326 | |
| 202 | − return 0; | |
| 327 | + return EXIT_SUCCESS; | |
| 203 | 328 | } |
| @@ -158,7 +158,7 @@ namespace · 157 unmodified lines | ||
| 158 | 158 | add_pointer_to_queue = std::function<void(pointer_t p, std::size_t)>{ [&allocs](pointer_t p, std::size_t) -> void |
| 159 | 159 | { |
| 160 | 160 | auto a = vm_alloc_t::from_allocation(p); |
| 161 | − debug::log_msg(debug::component_trace_t::garbage_collector, debug::log_level_t::debug, "\tref: %#" PRIxPTR "\n", a); | |
| 161 | + debug::log_msg(debug::component_trace_t::garbage_collector, debug::log_level_t::debug, " ref: %#" PRIxPTR "\n", a); | |
| 162 | 162 | allocs.push(a); |
| 163 | 163 | } }; |
| 164 | 164 | } |
| @@ -58,7 +58,7 @@ void default_scheduler_t::worker_main(default_scheduler_t &instance) · 57 unmodified lines | ||
| 58 | 58 | if (module_ref.module->module_name != nullptr) |
| 59 | 59 | module_name = module_ref.module->module_name->str(); |
| 60 | 60 | |
| 61 | − err_msg << "\t" << module_name << "@" << pc << "\n"; | |
| 61 | + err_msg << " " << module_name << "@" << pc << "\n"; | |
| 62 | 62 | return true; |
| 63 | 63 | }); |
| 64 | 64 | } |