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
99 #include <sstream>
1010 #include <string>
1111 #include <algorithm>
12−#include <locale>
1312 #include <map>
14−#include <vm_tools.h>
1513 #include <utils.h>
1614 #include <vm_memory.h>
1715 #include <vm_asm.h>
@@ -76,16 +74,18 @@ namespace · 58 unmodified lines
7674 // Debug command context
7775 struct dbg_cmd_cxt_t
7876 {
79− dbg_cmd_cxt_t(const vm_t &v, const vm_registers_t &r)
80− : initial_register{ r }
77+ dbg_cmd_cxt_t(debugger &d, const vm_registers_t &r)
78+ : dbg{ d }
8179 , exit_break{ false }
82− , vm{ v }
80+ , initial_register{ r }
81+ , vm{ d.controller->get_vm_instance() }
8382 {
8483 current_register = &initial_register;
8584 }
8685
8786 bool exit_break;
8887
88+ debugger &dbg;
8989 const vm_t &vm;
9090 const vm_registers_t *current_register;
9191 const vm_registers_t &initial_register;
@@ -125,10 +125,8 @@ namespace · 33 unmodified lines
125125 auto register_string = std::stringstream{};
126126
127127 register_string
128− << "Registers:\n"
129128 << " Thread ID: " << r.thread.get_thread_id() << "\n"
130− << " Module: " << r.module_ref->module->module_name->str() << "\n"
131− << " PC: " << r.pc << "\n"
129+ << " Module: " << r.module_ref->module->module_name->str() << " PC: " << r.pc << "\n"
132130 << " Opcode: " << r.module_ref->code_section[r.pc].op << "\n";
133131
134132 return register_string.str();
@@ -231,8 +229,12 @@ namespace · 96 unmodified lines
231229 }
232230 else
233231 {
234− ss << "alloc\n"
235− << "\tsize: " << alloc->alloc_type->size_in_bytes << "\n";
232+ ss << "alloc - size: " << 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+ });
236238 }
237239
238240 return ss;
@@ -282,21 +284,6 @@ namespace · 43 unmodified lines
282284 return ss;
283285 }
284286
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−
300287 void cmd_continue(const std::vector<std::string> &, dbg_cmd_cxt_t &cxt)
301288 {
302289 cxt.exit_break = true;
@@ -311,7 +298,6 @@ namespace · 8 unmodified lines
311298 void cmd_print_threads(const std::vector<std::string> &, dbg_cmd_cxt_t &cxt)
312299 {
313300 auto msg = std::stringstream{};
314− msg << "Threads:\n";
315301 for (auto t : cxt.vm.get_scheduler_control().get_all_threads())
316302 msg << " " << std::setw(5) << t->get_thread_id() << " - " << t->get_state() << "\n";
317303
@@ -321,21 +307,146 @@ namespace · 3 unmodified lines
321307 void cmd_print_modules(const std::vector<std::string> &, dbg_cmd_cxt_t &cxt)
322308 {
323309 auto msg = std::stringstream{};
324− msg << "Modules:\n";
325−
326310 cxt.vm.enum_loaded_modules([&msg](const loaded_vm_module_t &m)
327311 {
328312 auto module_instance = m.module.lock();
329− if (module_instance == nullptr)
330− return;
313+ if (module_instance != nullptr)
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+ }
331319
332− msg << std::setw(24) << module_instance->module_name->str() << std::setw(0) << " " << m.origin->str() << "\n";
320+ return true;
333321 });
334322
335323 debug_print_info(msg.str());
336324 }
337325
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)
339450 {
340451 auto thread_registers = std::map<uint32_t, const vm_registers_t*>{};
341452 if (a.size() == 1)
@@ -345,7 +456,6 @@ namespace · 3 unmodified lines
345456 else
346457 {
347458 uint32_t thread_id;
348− auto all_threads = cxt.vm.get_scheduler_control().get_all_threads();
349459 if (a[1].compare("*") == 0)
350460 {
351461 thread_id = 0;
@@ -354,7 +464,7 @@ namespace · 2 unmodified lines
354464 {
355465 try
356466 {
357− thread_id = std::stoi(a[1]);
467+ thread_id = std::stoul(a[1]);
358468 }
359469 catch (...)
360470 {
@@ -364,6 +474,7 @@ namespace · 3 unmodified lines
364474 }
365475
366476 // Find the thread(s)
477+ auto all_threads = cxt.vm.get_scheduler_control().get_all_threads();
367478 for (auto t : all_threads)
368479 {
369480 const auto tid = t->get_thread_id();
@@ -406,7 +517,7 @@ namespace · 36 unmodified lines
406517 uint32_t thread_id;
407518 try
408519 {
409− thread_id = std::stoi(a[1]);
520+ thread_id = std::stoul(a[1]);
410521 }
411522 catch (...)
412523 {
@@ -432,7 +543,7 @@ namespace · 19 unmodified lines
432543
433544 void cmd_disassemble(const std::vector<std::string> &a, dbg_cmd_cxt_t &cxt)
434545 {
435− auto disassemble_length = 1;
546+ auto disassemble_length = int{ 1 };
436547 if (a.size() > 1)
437548 {
438549 try
@@ -629,11 +740,17 @@ namespace · 190 unmodified lines
629740 const dbg_cmd_t cmds[] =
630741 {
631742 { "c", "Continue", nullptr, nullptr, cmd_continue },
743+
632744 { "r", "Print registers", nullptr, nullptr, cmd_print_registers },
633745 { "t", "Print all threads", nullptr, nullptr, cmd_print_threads },
634746 { "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 },
636− { "st", "Switch to thread", "st [0-9]+", "st 42", cmd_switchthread },
747+
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 },
637754 { "d", "Disassemble the next/previous N instructions", "d (-?[0-9]+)?", "d, d -4, d 5", cmd_disassemble },
638755 { "x", "Examine memory", "x [mp|fp] [0-9]+ ([0-9]+)?", "x mp 3, x fp 20 6", cmd_examine },
639756 { "?", "Print help", nullptr, nullptr, cmd_help },
@@ -703,7 +820,7 @@ namespace · 63 unmodified lines
703820 return split_string;
704821 }
705822
706− void prompt(const vm_t &vm, const vm_registers_t &r)
823+ void prompt(debugger &debugger, const vm_registers_t &r)
707824 {
708825 std::cout
709826 << console_modifiers::green_font
@@ -711,10 +828,9 @@ namespace · 1 unmodified line
711828 << "'?' for help\n"
712829 << console_modifiers::reset_all;
713830
714− std::locale loc;
715831 std::string cmd;
716832
717− dbg_cmd_cxt_t cxt{ vm, r };
833+ dbg_cmd_cxt_t cxt{ debugger, r };
718834 for (;;)
719835 {
720836 std::cout
@@ -746,12 +862,17 @@ namespace · 25 unmodified lines
746862 }
747863 }
748864
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)
750871 {
751872 _tool_id = tool_id;
752− _vm = &vm;
873+ controller = &controller_;
753874
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)
755876 {
756877 auto t = cxt.value1.thread;
757878 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
765886 debug_print_info(ss.str());
766887 }));
767888
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)
769890 {
770891 auto ss = std::stringstream{};
771892 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
775896 debug_print_info(ss.str());
776897 }));
777898
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)
779900 {
780901 auto ss = std::stringstream{};
781902 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
785906 debug_print_info(ss.str());
786907 }));
787908
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)
789910 {
790911 auto ss = std::stringstream{};
791912 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
793914 << "'";
794915
795916 debug_print_error(ss.str());
796− prompt(*_vm, *cxt.value1.registers);
917+ prompt(*this, *cxt.value1.registers);
797918 }));
798919
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)
800921 {
801− auto m = (*cxt.value1.module);
922+ auto m = (*cxt.value2.module);
802923 auto ss = std::stringstream{};
803924 ss << "Module "
804925 << m->module_name->str()
805− << " loaded (";
926+ << " loaded";
806927
807− if (!util::has_flag(m->header.runtime_flag, runtime_flags_t::builtin))
808− ss << cxt.value2.str->str();
809− else
810− ss << "built-in";
928+ if (util::has_flag(m->header.runtime_flag, runtime_flags_t::builtin))
929+ ss << " (built-in)";
811930
812− ss << ")";
813931
814932 debug_print_info(ss.str());
815933 }));
816934
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+ }));
818949 }
819950
820951 void debugger::on_unload()
821952 {
822− assert(_controller != nullptr);
953+ assert(controller != nullptr);
823954
824955 for (auto ec : _event_cookies)
825− _controller->unsubscribe_event(ec);
956+ controller->unsubscribe_event(ec);
826957
827− _controller = nullptr;
828− _vm = nullptr;
958+ controller = nullptr;
829959 }