Showing the changes to src/exec/debugger.cpp (1 of 14 files). Show all
Unified · Split
| @@ -9,9 +9,7 @@ · 8 unmodified lines | |||
| 9 | #include <sstream> | 9 | #include <sstream> |
| 10 | #include <string> | 10 | #include <string> |
| 11 | #include <algorithm> | 11 | #include <algorithm> |
| 12 | #include <locale> | ||
| 13 | #include <map> | 12 | #include <map> |
| 14 | #include <vm_tools.h> | ||
| 15 | #include <utils.h> | 13 | #include <utils.h> |
| 16 | #include <vm_memory.h> | 14 | #include <vm_memory.h> |
| 17 | #include <vm_asm.h> | 15 | #include <vm_asm.h> |
| @@ -76,16 +74,18 @@ namespace · 58 unmodified lines | |||
| 76 | // Debug command context | 74 | // Debug command context |
| 77 | struct dbg_cmd_cxt_t | 75 | struct dbg_cmd_cxt_t |
| 78 | { | 76 | { |
| 79 | dbg_cmd_cxt_t(const vm_t &v, const vm_registers_t &r) | 77 | dbg_cmd_cxt_t(debugger &d, const vm_registers_t &r) |
| 80 | : initial_register{ r } | 78 | : dbg{ d } |
| 81 | , exit_break{ false } | 79 | , exit_break{ false } |
| 82 | , vm{ v } | 80 | , initial_register{ r } |
| 81 | , vm{ d.controller->get_vm_instance() } | ||
| 83 | { | 82 | { |
| 84 | current_register = &initial_register; | 83 | current_register = &initial_register; |
| 85 | } | 84 | } |
| 86 | 85 | ||
| 87 | bool exit_break; | 86 | bool exit_break; |
| 88 | 87 | ||
| 88 | debugger &dbg; | ||
| 89 | const vm_t &vm; | 89 | const vm_t &vm; |
| 90 | const vm_registers_t *current_register; | 90 | const vm_registers_t *current_register; |
| 91 | const vm_registers_t &initial_register; | 91 | const vm_registers_t &initial_register; |
| @@ -125,10 +125,8 @@ namespace · 33 unmodified lines | |||
| 125 | auto register_string = std::stringstream{}; | 125 | auto register_string = std::stringstream{}; |
| 126 | 126 | ||
| 127 | register_string | 127 | register_string |
| 128 | << "Registers:\n" | ||
| 129 | << " Thread ID: " << r.thread.get_thread_id() << "\n" | 128 | << " Thread ID: " << r.thread.get_thread_id() << "\n" |
| 130 | << " Module: " << r.module_ref->module->module_name->str() << "\n" | 129 | << " Module: " << r.module_ref->module->module_name->str() << " PC: " << r.pc << "\n" |
| 131 | << " PC: " << r.pc << "\n" | ||
| 132 | << " Opcode: " << r.module_ref->code_section[r.pc].op << "\n"; | 130 | << " Opcode: " << r.module_ref->code_section[r.pc].op << "\n"; |
| 133 | 131 | ||
| 134 | return register_string.str(); | 132 | return register_string.str(); |
| @@ -231,8 +229,12 @@ namespace · 96 unmodified lines | |||
| 231 | } | 229 | } |
| 232 | else | 230 | else |
| 233 | { | 231 | { |
| 234 | ss << "alloc\n" | 232 | ss << "alloc - size: " << alloc->alloc_type->size_in_bytes << "\n"; |
| 235 | << "\tsize: " << alloc->alloc_type->size_in_bytes << "\n"; | 233 | |
| 234 | enum_pointer_fields(*alloc->alloc_type, alloc->get_allocation(), [&ss](pointer_t p, std::size_t o) | ||
| 235 | { | ||
| 236 | ss << " [" << o << "] " << vm_alloc_t::from_allocation(p); | ||
| 237 | }); | ||
| 236 | } | 238 | } |
| 237 | 239 | ||
| 238 | return ss; | 240 | return ss; |
| @@ -282,21 +284,6 @@ namespace · 43 unmodified lines | |||
| 282 | return ss; | 284 | return ss; |
| 283 | } | 285 | } |
| 284 | 286 | ||
| 285 | std::string to_string_frame_pointers(vm_registers_t &r) | ||
| 286 | { | ||
| 287 | auto frame = r.stack.peek_frame(); | ||
| 288 | if (frame == nullptr) | ||
| 289 | return "<empty>"; | ||
| 290 | |||
| 291 | auto frame_string = std::stringstream{}; | ||
| 292 | enum_pointer_fields(*frame->frame_type, frame->base(), [&frame_string](pointer_t p) | ||
| 293 | { | ||
| 294 | frame_string << std::showbase << std::hex << reinterpret_cast<uintptr_t>(p) << " : " << std::dec << vm_alloc_t::from_allocation(p); | ||
| 295 | }); | ||
| 296 | |||
| 297 | return frame_string.str(); | ||
| 298 | } | ||
| 299 | |||
| 300 | void cmd_continue(const std::vector<std::string> &, dbg_cmd_cxt_t &cxt) | 287 | void cmd_continue(const std::vector<std::string> &, dbg_cmd_cxt_t &cxt) |
| 301 | { | 288 | { |
| 302 | cxt.exit_break = true; | 289 | cxt.exit_break = true; |
| @@ -311,7 +298,6 @@ namespace · 8 unmodified lines | |||
| 311 | void cmd_print_threads(const std::vector<std::string> &, dbg_cmd_cxt_t &cxt) | 298 | void cmd_print_threads(const std::vector<std::string> &, dbg_cmd_cxt_t &cxt) |
| 312 | { | 299 | { |
| 313 | auto msg = std::stringstream{}; | 300 | auto msg = std::stringstream{}; |
| 314 | msg << "Threads:\n"; | ||
| 315 | for (auto t : cxt.vm.get_scheduler_control().get_all_threads()) | 301 | for (auto t : cxt.vm.get_scheduler_control().get_all_threads()) |
| 316 | msg << " " << std::setw(5) << t->get_thread_id() << " - " << t->get_state() << "\n"; | 302 | msg << " " << std::setw(5) << t->get_thread_id() << " - " << t->get_state() << "\n"; |
| 317 | 303 | ||
| @@ -321,21 +307,146 @@ namespace · 3 unmodified lines | |||
| 321 | void cmd_print_modules(const std::vector<std::string> &, dbg_cmd_cxt_t &cxt) | 307 | void cmd_print_modules(const std::vector<std::string> &, dbg_cmd_cxt_t &cxt) |
| 322 | { | 308 | { |
| 323 | auto msg = std::stringstream{}; | 309 | auto msg = std::stringstream{}; |
| 324 | msg << "Modules:\n"; | ||
| 325 | |||
| 326 | cxt.vm.enum_loaded_modules([&msg](const loaded_vm_module_t &m) | 310 | cxt.vm.enum_loaded_modules([&msg](const loaded_vm_module_t &m) |
| 327 | { | 311 | { |
| 328 | auto module_instance = m.module.lock(); | 312 | auto module_instance = m.module.lock(); |
| 329 | if (module_instance == nullptr) | 313 | if (module_instance != nullptr) |
| 330 | return; | 314 | { |
| 315 | msg << std::setw(3) << m.load_id << ": " | ||
| 316 | << std::setw(16) << module_instance->module_name->str() | ||
| 317 | << std::setw(0) << " - " << m.origin->str() << "\n"; | ||
| 318 | } | ||
| 331 | 319 | ||
| 332 | msg << std::setw(24) << module_instance->module_name->str() << std::setw(0) << " " << m.origin->str() << "\n"; | 320 | return true; |
| 333 | }); | 321 | }); |
| 334 | 322 | ||
| 335 | debug_print_info(msg.str()); | 323 | debug_print_info(msg.str()); |
| 336 | } | 324 | } |
| 337 | 325 | ||
| 338 | void cmd_stacktrace(const std::vector<std::string> &a, dbg_cmd_cxt_t &cxt) | 326 | void cmd_breakpoint_set(const std::vector<std::string> &a, dbg_cmd_cxt_t &cxt) |
| 327 | { | ||
| 328 | if (a.size() < 3) | ||
| 329 | { | ||
| 330 | debug_print_error("Must supply an IP and module ID"); | ||
| 331 | return; | ||
| 332 | } | ||
| 333 | |||
| 334 | vm_pc_t pc; | ||
| 335 | try | ||
| 336 | { | ||
| 337 | pc = std::stoul(a[1]); | ||
| 338 | } | ||
| 339 | catch (...) | ||
| 340 | { | ||
| 341 | debug_print_error("Invalid IP format"); | ||
| 342 | return; | ||
| 343 | } | ||
| 344 | |||
| 345 | uint32_t module_id; | ||
| 346 | try | ||
| 347 | { | ||
| 348 | module_id = std::stoul(a[2]); | ||
| 349 | } | ||
| 350 | catch (...) | ||
| 351 | { | ||
| 352 | debug_print_error("Invalid module ID format"); | ||
| 353 | return; | ||
| 354 | } | ||
| 355 | |||
| 356 | auto module = std::shared_ptr<vm_module_t>{}; | ||
| 357 | cxt.vm.enum_loaded_modules([module_id, &module](const loaded_vm_module_t &m) | ||
| 358 | { | ||
| 359 | if (module_id != m.load_id) | ||
| 360 | return true; | ||
| 361 | |||
| 362 | // Found the matching ID so stop | ||
| 363 | module = m.module.lock(); | ||
| 364 | return false; | ||
| 365 | }); | ||
| 366 | |||
| 367 | if (module == nullptr) | ||
| 368 | { | ||
| 369 | debug_print_error("Invalid module ID"); | ||
| 370 | return; | ||
| 371 | } | ||
| 372 | else if (util::has_flag(module->header.runtime_flag, runtime_flags_t::builtin)) | ||
| 373 | { | ||
| 374 | debug_print_error("Unable to set breakpoint in built-in module"); | ||
| 375 | return; | ||
| 376 | } | ||
| 377 | |||
| 378 | if (pc < 0 || module->code_section.size() <= static_cast<std::size_t>(pc)) | ||
| 379 | { | ||
| 380 | debug_print_error("Invalid IP for module"); | ||
| 381 | return; | ||
| 382 | } | ||
| 383 | |||
| 384 | cxt.dbg.breakpoint_cookies.push_back(cxt.dbg.controller->set_breakpoint(module, pc)); | ||
| 385 | } | ||
| 386 | |||
| 387 | void cmd_breakpoint_clear(const std::vector<std::string> &a, dbg_cmd_cxt_t &cxt) | ||
| 388 | { | ||
| 389 | if (a.size() == 1) | ||
| 390 | { | ||
| 391 | debug_print_error("Must supply a breakpoint ID or wildcard"); | ||
| 392 | return; | ||
| 393 | } | ||
| 394 | |||
| 395 | auto controller = cxt.dbg.controller; | ||
| 396 | if (a[1].compare("*") == 0) | ||
| 397 | { | ||
| 398 | // Clear all breakpoints | ||
| 399 | for (auto cookie : cxt.dbg.breakpoint_cookies) | ||
| 400 | controller->clear_breakpoint(cookie); | ||
| 401 | |||
| 402 | cxt.dbg.breakpoint_cookies.clear(); | ||
| 403 | return; | ||
| 404 | } | ||
| 405 | |||
| 406 | // Clear specific breakpoint | ||
| 407 | cookie_t breakpoint_cookie; | ||
| 408 | try | ||
| 409 | { | ||
| 410 | breakpoint_cookie = static_cast<cookie_t>(std::stoul(a[1])); | ||
| 411 | } | ||
| 412 | catch (...) | ||
| 413 | { | ||
| 414 | debug_print_error("Invalid breakpoint ID format"); | ||
| 415 | return; | ||
| 416 | } | ||
| 417 | |||
| 418 | auto cookie_iter = std::find_if( | ||
| 419 | std::begin(cxt.dbg.breakpoint_cookies), | ||
| 420 | std::end(cxt.dbg.breakpoint_cookies), | ||
| 421 | [breakpoint_cookie] (const cookie_t c) { return c == breakpoint_cookie; }); | ||
| 422 | if (cookie_iter == cxt.dbg.breakpoint_cookies.end()) | ||
| 423 | { | ||
| 424 | debug_print_error("Unknown breakpoint ID"); | ||
| 425 | return; | ||
| 426 | } | ||
| 427 | |||
| 428 | // Clear the breakpoint | ||
| 429 | controller->clear_breakpoint(breakpoint_cookie); | ||
| 430 | |||
| 431 | // Remove the cookie from the list | ||
| 432 | cxt.dbg.breakpoint_cookies.erase(cookie_iter); | ||
| 433 | } | ||
| 434 | |||
| 435 | void cmd_breakpoint_list(const std::vector<std::string> &, dbg_cmd_cxt_t &cxt) | ||
| 436 | { | ||
| 437 | auto msg = std::stringstream{}; | ||
| 438 | for (auto cookie : cxt.dbg.breakpoint_cookies) | ||
| 439 | { | ||
| 440 | const auto details = cxt.dbg.controller->get_breakpoint_details(cookie); | ||
| 441 | msg << std::setw(3) << cookie << ": " | ||
| 442 | << std::setw(16) << details.module->module_name->str() | ||
| 443 | << std::setw(0) << " @ " << details.pc << "\n"; | ||
| 444 | } | ||
| 445 | |||
| 446 | debug_print_info(msg.str()); | ||
| 447 | } | ||
| 448 | |||
| 449 | void cmd_stackwalk(const std::vector<std::string> &a, dbg_cmd_cxt_t &cxt) | ||
| 339 | { | 450 | { |
| 340 | auto thread_registers = std::map<uint32_t, const vm_registers_t*>{}; | 451 | auto thread_registers = std::map<uint32_t, const vm_registers_t*>{}; |
| 341 | if (a.size() == 1) | 452 | if (a.size() == 1) |
| @@ -345,7 +456,6 @@ namespace · 3 unmodified lines | |||
| 345 | else | 456 | else |
| 346 | { | 457 | { |
| 347 | uint32_t thread_id; | 458 | uint32_t thread_id; |
| 348 | auto all_threads = cxt.vm.get_scheduler_control().get_all_threads(); | ||
| 349 | if (a[1].compare("*") == 0) | 459 | if (a[1].compare("*") == 0) |
| 350 | { | 460 | { |
| 351 | thread_id = 0; | 461 | thread_id = 0; |
| @@ -354,7 +464,7 @@ namespace · 2 unmodified lines | |||
| 354 | { | 464 | { |
| 355 | try | 465 | try |
| 356 | { | 466 | { |
| 357 | thread_id = std::stoi(a[1]); | 467 | thread_id = std::stoul(a[1]); |
| 358 | } | 468 | } |
| 359 | catch (...) | 469 | catch (...) |
| 360 | { | 470 | { |
| @@ -364,6 +474,7 @@ namespace · 3 unmodified lines | |||
| 364 | } | 474 | } |
| 365 | 475 | ||
| 366 | // Find the thread(s) | 476 | // Find the thread(s) |
| 477 | auto all_threads = cxt.vm.get_scheduler_control().get_all_threads(); | ||
| 367 | for (auto t : all_threads) | 478 | for (auto t : all_threads) |
| 368 | { | 479 | { |
| 369 | const auto tid = t->get_thread_id(); | 480 | const auto tid = t->get_thread_id(); |
| @@ -406,7 +517,7 @@ namespace · 36 unmodified lines | |||
| 406 | uint32_t thread_id; | 517 | uint32_t thread_id; |
| 407 | try | 518 | try |
| 408 | { | 519 | { |
| 409 | thread_id = std::stoi(a[1]); | 520 | thread_id = std::stoul(a[1]); |
| 410 | } | 521 | } |
| 411 | catch (...) | 522 | catch (...) |
| 412 | { | 523 | { |
| @@ -432,7 +543,7 @@ namespace · 19 unmodified lines | |||
| 432 | 543 | ||
| 433 | void cmd_disassemble(const std::vector<std::string> &a, dbg_cmd_cxt_t &cxt) | 544 | void cmd_disassemble(const std::vector<std::string> &a, dbg_cmd_cxt_t &cxt) |
| 434 | { | 545 | { |
| 435 | auto disassemble_length = 1; | 546 | auto disassemble_length = int{ 1 }; |
| 436 | if (a.size() > 1) | 547 | if (a.size() > 1) |
| 437 | { | 548 | { |
| 438 | try | 549 | try |
| @@ -629,11 +740,17 @@ namespace · 190 unmodified lines | |||
| 629 | const dbg_cmd_t cmds[] = | 740 | const dbg_cmd_t cmds[] = |
| 630 | { | 741 | { |
| 631 | { "c", "Continue", nullptr, nullptr, cmd_continue }, | 742 | { "c", "Continue", nullptr, nullptr, cmd_continue }, |
| 743 | |||
| 632 | { "r", "Print registers", nullptr, nullptr, cmd_print_registers }, | 744 | { "r", "Print registers", nullptr, nullptr, cmd_print_registers }, |
| 633 | { "t", "Print all threads", nullptr, nullptr, cmd_print_threads }, | 745 | { "t", "Print all threads", nullptr, nullptr, cmd_print_threads }, |
| 634 | { "m", "Print all loaded modules", nullptr, nullptr, cmd_print_modules }, | 746 | { "m", "Print all loaded modules", nullptr, nullptr, cmd_print_modules }, |
| 635 | { "bt", "Stack walk/back trace for the current or supplied thread", "bt ([0-9]+|\\*)?", "bt, bt 34, bt *", cmd_stacktrace }, | 747 | |
| 636 | { "st", "Switch to thread", "st [0-9]+", "st 42", cmd_switchthread }, | 748 | { "bs", "Set breakpoint at the specified IP in a loaded module", "bs [0-9]+ [0-9]+", "bs 3 5 (Breakpoint at IP 3 in module 5)", cmd_breakpoint_set }, |
| 749 | { "bc", "Clear breakpoint(s)", "bc ([0-9]+|\\*)", "bc 3, bc *", cmd_breakpoint_clear }, | ||
| 750 | { "bl", "List breakpoints", nullptr, nullptr, cmd_breakpoint_list }, | ||
| 751 | |||
| 752 | { "sw", "Stack walk for the current or supplied thread", "sw ([0-9]+|\\*)?", "sw, sw 34, sw *", cmd_stackwalk }, | ||
| 753 | { "~", "Switch to thread", "~ [0-9]+", "~ 42", cmd_switchthread }, | ||
| 637 | { "d", "Disassemble the next/previous N instructions", "d (-?[0-9]+)?", "d, d -4, d 5", cmd_disassemble }, | 754 | { "d", "Disassemble the next/previous N instructions", "d (-?[0-9]+)?", "d, d -4, d 5", cmd_disassemble }, |
| 638 | { "x", "Examine memory", "x [mp|fp] [0-9]+ ([0-9]+)?", "x mp 3, x fp 20 6", cmd_examine }, | 755 | { "x", "Examine memory", "x [mp|fp] [0-9]+ ([0-9]+)?", "x mp 3, x fp 20 6", cmd_examine }, |
| 639 | { "?", "Print help", nullptr, nullptr, cmd_help }, | 756 | { "?", "Print help", nullptr, nullptr, cmd_help }, |
| @@ -703,7 +820,7 @@ namespace · 63 unmodified lines | |||
| 703 | return split_string; | 820 | return split_string; |
| 704 | } | 821 | } |
| 705 | 822 | ||
| 706 | void prompt(const vm_t &vm, const vm_registers_t &r) | 823 | void prompt(debugger &debugger, const vm_registers_t &r) |
| 707 | { | 824 | { |
| 708 | std::cout | 825 | std::cout |
| 709 | << console_modifiers::green_font | 826 | << console_modifiers::green_font |
| @@ -711,10 +828,9 @@ namespace · 1 unmodified line | |||
| 711 | << "'?' for help\n" | 828 | << "'?' for help\n" |
| 712 | << console_modifiers::reset_all; | 829 | << console_modifiers::reset_all; |
| 713 | 830 | ||
| 714 | std::locale loc; | ||
| 715 | std::string cmd; | 831 | std::string cmd; |
| 716 | 832 | ||
| 717 | dbg_cmd_cxt_t cxt{ vm, r }; | 833 | dbg_cmd_cxt_t cxt{ debugger, r }; |
| 718 | for (;;) | 834 | for (;;) |
| 719 | { | 835 | { |
| 720 | std::cout | 836 | std::cout |
| @@ -746,12 +862,17 @@ namespace · 25 unmodified lines | |||
| 746 | } | 862 | } |
| 747 | } | 863 | } |
| 748 | 864 | ||
| 749 | void debugger::on_load(vm_t &vm, vm_tool_controller_t &controller, std::size_t tool_id) | 865 | debugger::debugger() |
| 866 | : _tool_id{ 0 } | ||
| 867 | , controller{ nullptr } | ||
| 868 | { } | ||
| 869 | |||
| 870 | void debugger::on_load(vm_tool_controller_t &controller_, std::size_t tool_id) | ||
| 750 | { | 871 | { |
| 751 | _tool_id = tool_id; | 872 | _tool_id = tool_id; |
| 752 | _vm = &vm; | 873 | controller = &controller_; |
| 753 | 874 | ||
| 754 | _event_cookies.push_back(controller.subscribe_event(vm_event_t::thread_begin, [](vm_event_t, vm_event_context_t &cxt) | 875 | _event_cookies.push_back(controller->subscribe_event(vm_event_t::thread_begin, [](vm_event_t, vm_event_context_t &cxt) |
| 755 | { | 876 | { |
| 756 | auto t = cxt.value1.thread; | 877 | auto t = cxt.value1.thread; |
| 757 | auto ss = std::stringstream{}; | 878 | auto ss = std::stringstream{}; |
| @@ -765,7 +886,7 @@ void debugger::on_load(vm_t &vm, vm_tool_controller_t &controller, std::size_t t · 7 unmodified lines | |||
| 765 | debug_print_info(ss.str()); | 886 | debug_print_info(ss.str()); |
| 766 | })); | 887 | })); |
| 767 | 888 | ||
| 768 | _event_cookies.push_back(controller.subscribe_event(vm_event_t::thread_end, [](vm_event_t, vm_event_context_t &cxt) | 889 | _event_cookies.push_back(controller->subscribe_event(vm_event_t::thread_end, [](vm_event_t, vm_event_context_t &cxt) |
| 769 | { | 890 | { |
| 770 | auto ss = std::stringstream{}; | 891 | auto ss = std::stringstream{}; |
| 771 | ss << "Thread " | 892 | ss << "Thread " |
| @@ -775,7 +896,7 @@ void debugger::on_load(vm_t &vm, vm_tool_controller_t &controller, std::size_t t · 3 unmodified lines | |||
| 775 | debug_print_info(ss.str()); | 896 | debug_print_info(ss.str()); |
| 776 | })); | 897 | })); |
| 777 | 898 | ||
| 778 | _event_cookies.push_back(controller.subscribe_event(vm_event_t::exception_raised, [](vm_event_t, vm_event_context_t &cxt) | 899 | _event_cookies.push_back(controller->subscribe_event(vm_event_t::exception_raised, [](vm_event_t, vm_event_context_t &cxt) |
| 779 | { | 900 | { |
| 780 | auto ss = std::stringstream{}; | 901 | auto ss = std::stringstream{}; |
| 781 | ss << "Exception '" | 902 | ss << "Exception '" |
| @@ -785,7 +906,7 @@ void debugger::on_load(vm_t &vm, vm_tool_controller_t &controller, std::size_t t · 3 unmodified lines | |||
| 785 | debug_print_info(ss.str()); | 906 | debug_print_info(ss.str()); |
| 786 | })); | 907 | })); |
| 787 | 908 | ||
| 788 | _event_cookies.push_back(controller.subscribe_event(vm_event_t::exception_unhandled, [&](vm_event_t, vm_event_context_t &cxt) | 909 | _event_cookies.push_back(controller->subscribe_event(vm_event_t::exception_unhandled, [&](vm_event_t, vm_event_context_t &cxt) |
| 789 | { | 910 | { |
| 790 | auto ss = std::stringstream{}; | 911 | auto ss = std::stringstream{}; |
| 791 | ss << "Unhandled exception '" | 912 | ss << "Unhandled exception '" |
| @@ -793,37 +914,46 @@ void debugger::on_load(vm_t &vm, vm_tool_controller_t &controller, std::size_t t · 1 unmodified line | |||
| 793 | << "'"; | 914 | << "'"; |
| 794 | 915 | ||
| 795 | debug_print_error(ss.str()); | 916 | debug_print_error(ss.str()); |
| 796 | prompt(*_vm, *cxt.value1.registers); | 917 | prompt(*this, *cxt.value1.registers); |
| 797 | })); | 918 | })); |
| 798 | 919 | ||
| 799 | _event_cookies.push_back(controller.subscribe_event(vm_event_t::module_load, [](vm_event_t, vm_event_context_t &cxt) | 920 | _event_cookies.push_back(controller->subscribe_event(vm_event_t::module_thread_load, [&](vm_event_t, vm_event_context_t &cxt) |
| 800 | { | 921 | { |
| 801 | auto m = (*cxt.value1.module); | 922 | auto m = (*cxt.value2.module); |
| 802 | auto ss = std::stringstream{}; | 923 | auto ss = std::stringstream{}; |
| 803 | ss << "Module " | 924 | ss << "Module " |
| 804 | << m->module_name->str() | 925 | << m->module_name->str() |
| 805 | << " loaded ("; | 926 | << " loaded"; |
| 806 | 927 | ||
| 807 | if (!util::has_flag(m->header.runtime_flag, runtime_flags_t::builtin)) | 928 | if (util::has_flag(m->header.runtime_flag, runtime_flags_t::builtin)) |
| 808 | ss << cxt.value2.str->str(); | 929 | ss << " (built-in)"; |
| 809 | else | ||
| 810 | ss << "built-in"; | ||
| 811 | 930 | ||
| 812 | ss << ")"; | ||
| 813 | 931 | ||
| 814 | debug_print_info(ss.str()); | 932 | debug_print_info(ss.str()); |
| 815 | })); | 933 | })); |
| 816 | 934 | ||
| 817 | _controller = &controller; | 935 | _event_cookies.push_back(controller->subscribe_event(vm_event_t::breakpoint, [&](vm_event_t, vm_event_context_t &cxt) |
| 936 | { | ||
| 937 | auto ss = std::stringstream{}; | ||
| 938 | ss << "Breakpoint hit"; | ||
| 939 | if (cxt.value2.cookie != 0) | ||
| 940 | ss << " [" << cxt.value2.cookie << "]"; | ||
| 941 | |||
| 942 | debug_print_info(ss.str()); | ||
| 943 | |||
| 944 | auto reg_str = registers_to_string(*cxt.value1.registers); | ||
| 945 | debug_print_info(reg_str); | ||
| 946 | |||
| 947 | prompt(*this, *cxt.value1.registers); | ||
| 948 | })); | ||
| 818 | } | 949 | } |
| 819 | 950 | ||
| 820 | void debugger::on_unload() | 951 | void debugger::on_unload() |
| 821 | { | 952 | { |
| 822 | assert(_controller != nullptr); | 953 | assert(controller != nullptr); |
| 823 | 954 | ||
| 824 | for (auto ec : _event_cookies) | 955 | for (auto ec : _event_cookies) |
| 825 | _controller->unsubscribe_event(ec); | 956 | controller->unsubscribe_event(ec); |
| 826 | 957 | ||
| 827 | _controller = nullptr; | 958 | controller = nullptr; |
| 828 | _vm = nullptr; | ||
| 829 | } | 959 | } |