History

Debugger supports breakpoints (set/clear/list) Clean up usage of final and override on various classes Distinguish tool events for vm loading module and thread loading module

arr committed 10 years ago

Commit e2f8e251 parent d8c9a3314 files · +382 −177Browse files

Showing the changes to src/exec/debugger.cpp (1 of 14 files). Show all

Unified · Split

src/exec/debugger.cpp+191−61
@@ -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 context74 // Debug command context
77 struct dbg_cmd_cxt_t75 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_string127 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 else230 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 else456 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 try465 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 try518 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 try549 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::cout825 std::cout
709 << console_modifiers::green_font826 << 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::cout836 std::cout
@@ -746,12 +862,17 @@ namespace · 25 unmodified lines
746 }862 }
747}863}
748 864
749void debugger::on_load(vm_t &vm, vm_tool_controller_t &controller, std::size_t tool_id)865debugger::debugger()
866 : _tool_id{ 0 }
867 , controller{ nullptr }
868{ }
869
870void 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
820void debugger::on_unload()951void 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}