| @@ -5,9 +5,12 @@ · 4 unmodified lines |
| 5 | // | 5 | // |
| 6 | | 6 | |
| 7 | #include <iostream> | 7 | #include <iostream> |
| | 8 | #include <iomanip> |
| 8 | #include <sstream> | 9 | #include <sstream> |
| 9 | #include <string> | 10 | #include <string> |
| | 11 | #include <algorithm> |
| 10 | #include <locale> | 12 | #include <locale> |
| | 13 | #include <map> |
| 11 | #include <vm_tools.h> | 14 | #include <vm_tools.h> |
| 12 | #include <utils.h> | 15 | #include <utils.h> |
| 13 | #include <vm_memory.h> | 16 | #include <vm_memory.h> |
| @@ -19,6 +22,70 @@ using namespace disvm::runtime; · 5 unmodified lines |
| 19 | | 22 | |
| 20 | namespace | 23 | namespace |
| 21 | { | 24 | { |
| | 25 | // https://en.wikipedia.org/wiki/ANSI_escape_code |
| | 26 | namespace console_modifiers |
| | 27 | { |
| | 28 | #define CSI "\33[" |
| | 29 | |
| | 30 | const auto black_font = CSI "30m"; |
| | 31 | const auto red_font = CSI "31m"; |
| | 32 | const auto green_font = CSI "32m"; |
| | 33 | const auto yellow_font = CSI "33m"; |
| | 34 | const auto blue_font = CSI "34m"; |
| | 35 | const auto magenta_font = CSI "35m"; |
| | 36 | const auto cyan_font = CSI "36m"; |
| | 37 | const auto white_font = CSI "37m"; |
| | 38 | |
| | 39 | const auto black_bkg = CSI "40m"; |
| | 40 | const auto red_bkg = CSI "41m"; |
| | 41 | const auto green_bkg = CSI "42m"; |
| | 42 | const auto yellow_bkg = CSI "43m"; |
| | 43 | const auto blue_bkg = CSI "44m"; |
| | 44 | const auto magenta_bkg = CSI "45m"; |
| | 45 | const auto cyan_bkg = CSI "46m"; |
| | 46 | const auto white_bkg = CSI "47m"; |
| | 47 | |
| | 48 | const auto bold = CSI "1m"; |
| | 49 | |
| | 50 | const auto reset_all = CSI "0m"; |
| | 51 | |
| | 52 | #undef CSI |
| | 53 | } |
| | 54 | |
| | 55 | void debug_print_error(const std::string &str) |
| | 56 | { |
| | 57 | std::cout |
| | 58 | << console_modifiers::red_font |
| | 59 | << console_modifiers::bold |
| | 60 | << "Error: " |
| | 61 | << str |
| | 62 | << console_modifiers::reset_all |
| | 63 | << "\n"; |
| | 64 | } |
| | 65 | |
| | 66 | void debug_print_info(const std::string &str) |
| | 67 | { |
| | 68 | std::cout |
| | 69 | << console_modifiers::yellow_font |
| | 70 | << console_modifiers::bold |
| | 71 | << str |
| | 72 | << console_modifiers::reset_all |
| | 73 | << "\n"; |
| | 74 | } |
| | 75 | |
| | 76 | // Debug command exec operation |
| | 77 | using dbg_cmd_exec_t = bool(*)(const std::vector<std::string> &, const vm_t &, const vm_registers_t &); |
| | 78 | |
| | 79 | // Debug command |
| | 80 | struct dbg_cmd_t |
| | 81 | { |
| | 82 | const char *cmd; |
| | 83 | const char *description; |
| | 84 | const char *syntax; |
| | 85 | const char *example; |
| | 86 | dbg_cmd_exec_t exec; |
| | 87 | }; |
| | 88 | |
| 22 | std::string stack_to_string(const vm_registers_t &r) | 89 | std::string stack_to_string(const vm_registers_t &r) |
| 23 | { | 90 | { |
| 24 | auto msg = std::stringstream{}; | 91 | auto msg = std::stringstream{}; |
| @@ -41,10 +108,10 @@ namespace · 16 unmodified lines |
| 41 | | 108 | |
| 42 | register_string | 109 | register_string |
| 43 | << "Registers:\n" | 110 | << "Registers:\n" |
| 44 | << " Thread ID: " << r.thread.get_thread_id() << "\n" | 111 | << " Thread ID: " << r.thread.get_thread_id() << "\n" |
| 45 | << " Module: " << r.module_ref->module->module_name->str() << "\n" | 112 | << " Module: " << r.module_ref->module->module_name->str() << "\n" |
| 46 | << "Program counter: " << r.pc << "\n" | 113 | << " PC: " << r.pc << "\n" |
| 47 | << " Opcode: " << r.module_ref->code_section[r.pc].op << "\n"; | 114 | << " Opcode: " << r.module_ref->code_section[r.pc].op << "\n"; |
| 48 | | 115 | |
| 49 | return register_string.str(); | 116 | return register_string.str(); |
| 50 | } | 117 | } |
| @@ -52,8 +119,8 @@ namespace · 1 unmodified line |
| 52 | std::ostream& operator<<(std::ostream &ss, const vm_string_t *s) | 119 | std::ostream& operator<<(std::ostream &ss, const vm_string_t *s) |
| 53 | { | 120 | { |
| 54 | ss << "string\n" | 121 | ss << "string\n" |
| 55 | << "\tlength: " << s->get_length() << "\n" | 122 | << "\tlength: " << s->get_length() << "\n" |
| 56 | << "\tvalue: " << s->str() << "\n"; | 123 | << "\tvalue: " << s->str() << "\n"; |
| 57 | | 124 | |
| 58 | return ss; | 125 | return ss; |
| 59 | } | 126 | } |
| @@ -61,7 +128,7 @@ namespace · 1 unmodified line |
| 61 | std::ostream& operator<<(std::ostream &ss, const vm_array_t *a) | 128 | std::ostream& operator<<(std::ostream &ss, const vm_array_t *a) |
| 62 | { | 129 | { |
| 63 | ss << "array\n" | 130 | ss << "array\n" |
| 64 | << "\tlength: " << a->get_length() << "\n"; | 131 | << "\tlength: " << a->get_length() << "\n"; |
| 65 | | 132 | |
| 66 | return ss; | 133 | return ss; |
| 67 | } | 134 | } |
| @@ -69,7 +136,7 @@ namespace · 1 unmodified line |
| 69 | std::ostream& operator<<(std::ostream &ss, const vm_list_t *l) | 136 | std::ostream& operator<<(std::ostream &ss, const vm_list_t *l) |
| 70 | { | 137 | { |
| 71 | ss << "list\n" | 138 | ss << "list\n" |
| 72 | << "\tlength: " << l->get_length() << "\n"; | 139 | << "\tlength: " << l->get_length() << "\n"; |
| 73 | | 140 | |
| 74 | return ss; | 141 | return ss; |
| 75 | } | 142 | } |
| @@ -77,15 +144,59 @@ namespace · 1 unmodified line |
| 77 | std::ostream& operator<<(std::ostream &ss, const vm_channel_t *c) | 144 | std::ostream& operator<<(std::ostream &ss, const vm_channel_t *c) |
| 78 | { | 145 | { |
| 79 | ss << "channel\n" | 146 | ss << "channel\n" |
| 80 | << "\tbuffer size: " << c->get_buffer_size() << "\n"; | 147 | << "\tbuffer size: " << c->get_buffer_size() << "\n"; |
| 81 | | 148 | |
| 82 | return ss; | 149 | return ss; |
| 83 | } | 150 | } |
| 84 | | 151 | |
| 85 | std::ostream& operator<<(std::ostream &ss, const vm_alloc_t *a) | 152 | std::ostream& operator<<(std::ostream &ss, const vm_alloc_t *a) |
| 86 | { | 153 | { |
| 87 | ss << "alloc\n" | 154 | ss << "alloc\n" |
| 88 | << "\tsize: " << a->alloc_type->size_in_bytes << "\n"; | 155 | << "\tsize: " << a->alloc_type->size_in_bytes << "\n"; |
| | 156 | |
| | 157 | return ss; |
| | 158 | } |
| | 159 | |
| | 160 | std::ostream& operator<<(std::ostream &ss, const vm_thread_state_t s) |
| | 161 | { |
| | 162 | switch (s) |
| | 163 | { |
| | 164 | case vm_thread_state_t::unknown: |
| | 165 | ss << "unknown"; |
| | 166 | break; |
| | 167 | case vm_thread_state_t::blocked_in_alt: |
| | 168 | ss << "blocked-in-alt"; |
| | 169 | break; |
| | 170 | case vm_thread_state_t::blocked_sending: |
| | 171 | ss << "blocked-sending"; |
| | 172 | break; |
| | 173 | case vm_thread_state_t::blocked_receiving: |
| | 174 | ss << "blocked-receiving"; |
| | 175 | break; |
| | 176 | case vm_thread_state_t::debug: |
| | 177 | ss << "debug"; |
| | 178 | break; |
| | 179 | case vm_thread_state_t::ready: |
| | 180 | ss << "ready"; |
| | 181 | break; |
| | 182 | case vm_thread_state_t::running: |
| | 183 | ss << "running"; |
| | 184 | break; |
| | 185 | case vm_thread_state_t::release: |
| | 186 | ss << "release"; |
| | 187 | break; |
| | 188 | case vm_thread_state_t::exiting: |
| | 189 | ss << "exiting"; |
| | 190 | break; |
| | 191 | case vm_thread_state_t::empty_stack: |
| | 192 | ss << "empty-stack"; |
| | 193 | break; |
| | 194 | case vm_thread_state_t::broken: |
| | 195 | ss << "broken"; |
| | 196 | break; |
| | 197 | default: |
| | 198 | ss << "??"; |
| | 199 | } |
| 89 | | 200 | |
| 90 | return ss; | 201 | return ss; |
| 91 | } | 202 | } |
| @@ -117,65 +228,317 @@ namespace · 25 unmodified lines |
| 117 | return frame_string.str(); | 228 | return frame_string.str(); |
| 118 | } | 229 | } |
| 119 | | 230 | |
| 120 | namespace console_modifiers | 231 | bool cmd_continue(const std::vector<std::string> &, const vm_t &, const vm_registers_t &) |
| 121 | { | 232 | { |
| 122 | #define CSI "\33[" | 233 | return false; |
| | 234 | } |
| 123 | | 235 | |
| 124 | const auto black_font = CSI "30m"; | 236 | bool cmd_print_registers(const std::vector<std::string> &, const vm_t &, const vm_registers_t &r) |
| 125 | const auto red_font = CSI "31m"; | 237 | { |
| 126 | const auto green_font = CSI "32m"; | 238 | auto s = registers_to_string(r); |
| 127 | const auto yellow_font = CSI "33m"; | 239 | debug_print_info(s); |
| 128 | const auto blue_font = CSI "34m"; | | |
| 129 | const auto magenta_font = CSI "35m"; | | |
| 130 | const auto cyan_font = CSI "36m"; | | |
| 131 | const auto white_font = CSI "37m"; | | |
| 132 | | 240 | |
| 133 | const auto black_bkg = CSI "40m"; | 241 | return true; |
| 134 | const auto red_bkg = CSI "41m"; | 242 | } |
| 135 | const auto green_bkg = CSI "42m"; | | |
| 136 | const auto yellow_bkg = CSI "43m"; | | |
| 137 | const auto blue_bkg = CSI "44m"; | | |
| 138 | const auto magenta_bkg = CSI "45m"; | | |
| 139 | const auto cyan_bkg = CSI "46m"; | | |
| 140 | const auto white_bkg = CSI "47m"; | | |
| 141 | | 243 | |
| 142 | const auto bold = CSI "1m"; | 244 | bool cmd_print_threads(const std::vector<std::string> &, const vm_t &vm, const vm_registers_t &) |
| | 245 | { |
| | 246 | auto msg = std::stringstream{}; |
| | 247 | msg << "Threads:\n"; |
| | 248 | for (auto t : vm.get_scheduler_control().get_all_threads()) |
| | 249 | msg << " " << std::setw(5) << t->get_thread_id() << " - " << t->get_state() << "\n"; |
| 143 | | 250 | |
| 144 | const auto reset_all = CSI "0m"; | 251 | debug_print_info(msg.str()); |
| 145 | | 252 | |
| 146 | #undef CSI | 253 | return true; |
| 147 | } | 254 | } |
| 148 | | 255 | |
| 149 | void debug_print_error(const std::string &str) | 256 | bool cmd_print_modules(const std::vector<std::string> &, const vm_t &vm, const vm_registers_t &) |
| 150 | { | 257 | { |
| 151 | std::cout | 258 | auto msg = std::stringstream{}; |
| 152 | << console_modifiers::red_font | 259 | msg << "Modules:\n"; |
| 153 | << console_modifiers::bold | 260 | for (auto m : vm.get_loaded_modules()) |
| 154 | << "Error: " | 261 | msg << " " << m->module_name->str() << "\n"; |
| 155 | << str | 262 | |
| 156 | << console_modifiers::reset_all | 263 | debug_print_info(msg.str()); |
| 157 | << "\n"; | 264 | |
| | 265 | return true; |
| 158 | } | 266 | } |
| 159 | | 267 | |
| 160 | void debug_print_info(const std::string &str) | 268 | bool cmd_stacktrace(const std::vector<std::string> &a, const vm_t &vm, const vm_registers_t &r) |
| | 269 | { |
| | 270 | auto thread_registers = std::map<uint32_t, const vm_registers_t*>{}; |
| | 271 | if (a.size() == 1) |
| | 272 | { |
| | 273 | thread_registers[r.thread.get_thread_id()] = &r; |
| | 274 | } |
| | 275 | else |
| | 276 | { |
| | 277 | uint32_t thread_id; |
| | 278 | auto all_threads = vm.get_scheduler_control().get_all_threads(); |
| | 279 | if (a[1].compare("*") == 0) |
| | 280 | { |
| | 281 | thread_id = 0; |
| | 282 | } |
| | 283 | else |
| | 284 | { |
| | 285 | try |
| | 286 | { |
| | 287 | thread_id = std::stoi(a[1]); |
| | 288 | } |
| | 289 | catch (...) |
| | 290 | { |
| | 291 | debug_print_error("Invalid thread ID format"); |
| | 292 | return true; |
| | 293 | } |
| | 294 | } |
| | 295 | |
| | 296 | // Find the thread(s) |
| | 297 | for (auto t : all_threads) |
| | 298 | { |
| | 299 | const auto tid = t->get_thread_id(); |
| | 300 | if (thread_id == 0 || tid == thread_id) |
| | 301 | { |
| | 302 | thread_registers[tid] = &t->get_registers(); |
| | 303 | |
| | 304 | // If we are looking for a single thread, we found it. |
| | 305 | if (thread_id != 0) |
| | 306 | break; |
| | 307 | } |
| | 308 | } |
| | 309 | } |
| | 310 | |
| | 311 | if (thread_registers.empty()) |
| | 312 | { |
| | 313 | debug_print_error("Unknown thread ID"); |
| | 314 | return true; |
| | 315 | } |
| | 316 | |
| | 317 | auto msg = std::stringstream{}; |
| | 318 | for (auto t : thread_registers) |
| | 319 | { |
| | 320 | msg << "Thread " << t.first << ":\n"; |
| | 321 | msg << stack_to_string(*t.second); |
| | 322 | msg << "\n"; |
| | 323 | } |
| | 324 | |
| | 325 | debug_print_info(msg.str()); |
| | 326 | |
| | 327 | return true; |
| | 328 | } |
| | 329 | |
| | 330 | // Forward declaration |
| | 331 | void prompt(const vm_t &, const vm_registers_t &); |
| | 332 | |
| | 333 | bool cmd_switchthread(const std::vector<std::string> &a, const vm_t &vm, const vm_registers_t &r) |
| | 334 | { |
| | 335 | if (a.size() == 1) |
| | 336 | { |
| | 337 | debug_print_error("Must supply a target thread ID"); |
| | 338 | return true; |
| | 339 | } |
| | 340 | |
| | 341 | uint32_t thread_id; |
| | 342 | try |
| | 343 | { |
| | 344 | thread_id = std::stoi(a[1]); |
| | 345 | } |
| | 346 | catch (...) |
| | 347 | { |
| | 348 | debug_print_error("Invalid thread ID format"); |
| | 349 | return true; |
| | 350 | } |
| | 351 | |
| | 352 | auto all_threads = vm.get_scheduler_control().get_all_threads(); |
| | 353 | |
| | 354 | // Find the thread |
| | 355 | for (auto t : all_threads) |
| | 356 | { |
| | 357 | const auto tid = t->get_thread_id(); |
| | 358 | if (tid == thread_id) |
| | 359 | { |
| | 360 | prompt(vm, t->get_registers()); |
| | 361 | |
| | 362 | // If we are returning from a thread switch we are not continuing, so return false to indicate as such. |
| | 363 | return false; |
| | 364 | } |
| | 365 | } |
| | 366 | |
| | 367 | debug_print_error("Unknown thread ID"); |
| | 368 | return true; |
| | 369 | } |
| | 370 | |
| | 371 | bool cmd_disassemble(const std::vector<std::string> &a, const vm_t &, const vm_registers_t &r) |
| | 372 | { |
| | 373 | auto disassemble_length = 1; |
| | 374 | if (a.size() > 1) |
| | 375 | { |
| | 376 | try |
| | 377 | { |
| | 378 | disassemble_length = std::stoi(a[1]); |
| | 379 | } |
| | 380 | catch (...) |
| | 381 | { |
| | 382 | debug_print_error("Invalid disassemble count format"); |
| | 383 | return true; |
| | 384 | } |
| | 385 | } |
| | 386 | |
| | 387 | const auto &code_section = r.module_ref->code_section; |
| | 388 | |
| | 389 | auto begin_index = static_cast<std::size_t>(r.pc); |
| | 390 | auto end_index = static_cast<std::size_t>(r.pc + 1); |
| | 391 | if (disassemble_length < 0) |
| | 392 | { |
| | 393 | const auto begin_maybe = r.pc - (-disassemble_length) + 1; |
| | 394 | begin_index = static_cast<std::size_t>(std::max(begin_maybe, 0)); |
| | 395 | } |
| | 396 | else |
| | 397 | { |
| | 398 | const auto end_maybe = static_cast<std::size_t>(r.pc + disassemble_length); |
| | 399 | end_index = std::min(end_maybe, code_section.size()); |
| | 400 | } |
| | 401 | |
| | 402 | auto msg = std::stringstream{}; |
| | 403 | for (auto i = begin_index; i < end_index; ++i) |
| | 404 | msg << " " << std::setw(5) << i << ": " << code_section[i].op << "\n"; |
| | 405 | |
| | 406 | debug_print_info(msg.str()); |
| | 407 | |
| | 408 | return true; |
| | 409 | } |
| | 410 | |
| | 411 | // Forward declaration |
| | 412 | void print_help(); |
| | 413 | |
| | 414 | bool cmd_help(const std::vector<std::string> &, const vm_t &, const vm_registers_t &) |
| | 415 | { |
| | 416 | print_help(); |
| | 417 | return true; |
| | 418 | } |
| | 419 | |
| | 420 | // Easter egg |
| | 421 | bool cmd_tlk_tilde_star(const std::vector<std::string> &, const vm_t &, const vm_registers_t &) |
| 161 | { | 422 | { |
| 162 | std::cout | 423 | std::cout |
| | 424 | << console_modifiers::black_font |
| | 425 | << console_modifiers::white_bkg |
| | 426 | << "H" |
| | 427 | << console_modifiers::reset_all |
| | 428 | << console_modifiers::red_font |
| | 429 | << console_modifiers::bold |
| | 430 | << "e" |
| | 431 | << console_modifiers::green_font |
| | 432 | << console_modifiers::bold |
| | 433 | << "l" |
| 163 | << console_modifiers::yellow_font | 434 | << console_modifiers::yellow_font |
| 164 | << console_modifiers::bold | 435 | << console_modifiers::bold |
| 165 | << str | 436 | << "l" |
| | 437 | << console_modifiers::blue_font |
| | 438 | << console_modifiers::bold |
| | 439 | << "o" |
| | 440 | << console_modifiers::magenta_font |
| | 441 | << console_modifiers::bold |
| | 442 | << ", " |
| | 443 | << console_modifiers::black_font |
| | 444 | << console_modifiers::white_bkg |
| | 445 | << "W" |
| 166 | << console_modifiers::reset_all | 446 | << console_modifiers::reset_all |
| 167 | << "\n"; | 447 | << console_modifiers::red_font |
| | 448 | << console_modifiers::bold |
| | 449 | << "o" |
| | 450 | << console_modifiers::green_font |
| | 451 | << console_modifiers::bold |
| | 452 | << "r" |
| | 453 | << console_modifiers::yellow_font |
| | 454 | << console_modifiers::bold |
| | 455 | << "l" |
| | 456 | << console_modifiers::blue_font |
| | 457 | << console_modifiers::bold |
| | 458 | << "d" |
| | 459 | << console_modifiers::magenta_font |
| | 460 | << console_modifiers::bold |
| | 461 | << "!\n" |
| | 462 | << console_modifiers::reset_all; |
| | 463 | |
| | 464 | return true; |
| 168 | } | 465 | } |
| 169 | | 466 | |
| 170 | auto prompt_help = | 467 | const dbg_cmd_t cmds[] = |
| 171 | R"(Help: | 468 | { |
| 172 | c C - continue | 469 | { "c", "Continue", nullptr, nullptr, cmd_continue }, |
| 173 | r R - print registers | 470 | { "r", "Print registers", nullptr, nullptr, cmd_print_registers }, |
| 174 | w W - print stack | 471 | { "t", "Print all threads", nullptr, nullptr, cmd_print_threads }, |
| 175 | ? - help | 472 | { "m", "Print all loaded modules", nullptr, nullptr, cmd_print_modules }, |
| 176 | )"; | 473 | { "sw", "Stack walk/back trace", "bt ([0-9]+|\\*)?", "bt, bt 34, bt *", cmd_stacktrace }, |
| | 474 | { "st", "Switch to thread", "st [0-9]+", "st 42", cmd_switchthread }, |
| | 475 | { "d", "Disassemble the next/previous N instructions", "d (-?[0-9]+)?", "d, d -4, d 5", cmd_disassemble }, |
| | 476 | { "?", "Print help", nullptr, nullptr, cmd_help }, |
| | 477 | { "tlk~*", nullptr, nullptr, nullptr, cmd_tlk_tilde_star } |
| | 478 | }; |
| | 479 | |
| | 480 | dbg_cmd_exec_t find_cmd(const std::string &cmd_maybe) |
| | 481 | { |
| | 482 | for (auto i = std::size_t{}; i < sizeof(cmds) / sizeof(cmds[0]); ++i) |
| | 483 | { |
| | 484 | if (cmd_maybe.compare(cmds[i].cmd) == 0) |
| | 485 | return cmds[i].exec; |
| | 486 | } |
| | 487 | |
| | 488 | // [TODO] Didn't find the cmd, try ignoring case? |
| | 489 | return nullptr; |
| | 490 | } |
| 177 | | 491 | |
| 178 | void prompt(const vm_registers_t &r) | 492 | void print_help() |
| | 493 | { |
| | 494 | auto ss = std::stringstream{}; |
| | 495 | ss << "Commands:\n"; |
| | 496 | for (auto i = std::size_t{}; i < sizeof(cmds) / sizeof(cmds[0]); ++i) |
| | 497 | { |
| | 498 | auto &c = cmds[i]; |
| | 499 | |
| | 500 | // Ignore if undocumented |
| | 501 | if (c.description == nullptr) |
| | 502 | continue; |
| | 503 | |
| | 504 | ss << " " << c.cmd << "\t" << c.description << "\n"; |
| | 505 | |
| | 506 | if (c.syntax != nullptr) |
| | 507 | ss << "\t Syntax: " << c.syntax << "\n"; |
| | 508 | |
| | 509 | if (c.example != nullptr) |
| | 510 | ss << "\t Example(s): " << c.example << "\n"; |
| | 511 | } |
| | 512 | |
| | 513 | debug_print_info(ss.str()); |
| | 514 | } |
| | 515 | |
| | 516 | // split the string using the supplied delimiter |
| | 517 | std::vector<std::string> split(const std::string &str, const char delim = ' ') |
| | 518 | { |
| | 519 | auto split_string = std::vector<std::string>{}; |
| | 520 | |
| | 521 | auto curr = str.begin(); |
| | 522 | auto end = str.cend(); |
| | 523 | while (curr != end) |
| | 524 | { |
| | 525 | auto curr_begin = curr; |
| | 526 | while (curr != end && *curr != delim) |
| | 527 | ++curr; |
| | 528 | |
| | 529 | if (curr_begin != curr) |
| | 530 | split_string.push_back(std::move(std::string{ curr_begin, curr })); |
| | 531 | |
| | 532 | if (curr == end) |
| | 533 | break; |
| | 534 | |
| | 535 | ++curr; |
| | 536 | } |
| | 537 | |
| | 538 | return split_string; |
| | 539 | } |
| | 540 | |
| | 541 | void prompt(const vm_t &vm, const vm_registers_t &r) |
| 179 | { | 542 | { |
| 180 | std::cout | 543 | std::cout |
| 181 | << console_modifiers::green_font | 544 | << console_modifiers::green_font |
| @@ -198,29 +561,20 @@ R"(Help: · 16 unmodified lines |
| 198 | if (cmd.empty()) | 561 | if (cmd.empty()) |
| 199 | continue; | 562 | continue; |
| 200 | | 563 | |
| 201 | auto c = std::toupper(cmd[0], loc); | 564 | const auto cmd_tokens = split(cmd); |
| 202 | if (c == 'R') | 565 | if (cmd_tokens.empty()) |
| 203 | { | 566 | continue; |
| 204 | auto str = registers_to_string(r); | 567 | |
| 205 | debug_print_info(str); | 568 | auto cmd_exec = find_cmd(cmd_tokens[0]); |
| 206 | } | 569 | if (cmd_exec != nullptr) |
| 207 | else if (c == 'W') | | |
| 208 | { | | |
| 209 | auto str = stack_to_string(r); | | |
| 210 | debug_print_info(str); | | |
| 211 | } | | |
| 212 | else if (c == 'C') | | |
| 213 | { | | |
| 214 | break; | | |
| 215 | } | | |
| 216 | else if (c == '?') | | |
| 217 | { | 570 | { |
| 218 | debug_print_info(prompt_help); | 571 | if (!cmd_exec(cmd_tokens, vm, r)) |
| | 572 | break; |
| 219 | } | 573 | } |
| 220 | else | 574 | else |
| 221 | { | 575 | { |
| 222 | debug_print_error("Unknown command"); | 576 | debug_print_error("Unknown command"); |
| 223 | debug_print_info(prompt_help); | 577 | print_help(); |
| 224 | } | 578 | } |
| 225 | } | 579 | } |
| 226 | } | 580 | } |
| @@ -229,6 +583,7 @@ R"(Help: · 2 unmodified lines |
| 229 | void debugger::on_load(vm_t &vm, vm_tool_controller_t &controller, std::size_t tool_id) | 583 | void debugger::on_load(vm_t &vm, vm_tool_controller_t &controller, std::size_t tool_id) |
| 230 | { | 584 | { |
| 231 | _tool_id = tool_id; | 585 | _tool_id = tool_id; |
| | 586 | _vm = &vm; |
| 232 | | 587 | |
| 233 | _event_cookies.push_back(controller.subscribe_event(vm_event_t::thread_begin, [](vm_event_t, vm_event_context_t &cxt) | 588 | _event_cookies.push_back(controller.subscribe_event(vm_event_t::thread_begin, [](vm_event_t, vm_event_context_t &cxt) |
| 234 | { | 589 | { |
| @@ -264,15 +619,15 @@ void debugger::on_load(vm_t &vm, vm_tool_controller_t &controller, std::size_t t · 29 unmodified lines |
| 264 | debug_print_info(ss.str()); | 619 | debug_print_info(ss.str()); |
| 265 | })); | 620 | })); |
| 266 | | 621 | |
| 267 | _event_cookies.push_back(controller.subscribe_event(vm_event_t::exception_unhandled, [](vm_event_t, vm_event_context_t &cxt) | 622 | _event_cookies.push_back(controller.subscribe_event(vm_event_t::exception_unhandled, [&](vm_event_t, vm_event_context_t &cxt) |
| 268 | { | 623 | { |
| 269 | auto ss = std::stringstream{}; | 624 | auto ss = std::stringstream{}; |
| 270 | ss << "Unhandled exception '" | 625 | ss << "Unhandled exception '" |
| 271 | << cxt.value2.str->str() | 626 | << cxt.value2.str->str() |
| 272 | << "' thrown."; | 627 | << "'"; |
| 273 | | 628 | |
| 274 | debug_print_error(ss.str()); | 629 | debug_print_error(ss.str()); |
| 275 | prompt(*cxt.value1.registers); | 630 | prompt(*_vm, *cxt.value1.registers); |
| 276 | })); | 631 | })); |
| 277 | | 632 | |
| 278 | _event_cookies.push_back(controller.subscribe_event(vm_event_t::module_load, [](vm_event_t, vm_event_context_t &cxt) | 633 | _event_cookies.push_back(controller.subscribe_event(vm_event_t::module_load, [](vm_event_t, vm_event_context_t &cxt) |
| @@ -304,4 +659,5 @@ void debugger::on_unload() · 25 unmodified lines |
| 304 | _controller->unsubscribe_event(ec); | 659 | _controller->unsubscribe_event(ec); |
| 305 | | 660 | |
| 306 | _controller = nullptr; | 661 | _controller = nullptr; |
| | 662 | _vm = nullptr; |
| 307 | } | 663 | } |