History

Addition of examine memory command to debugger. Re-design debugger command processing.

arr committed 10 years ago

Commit f2771671 parent e9ca2863 files · +255 −70Browse files

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

Unified · Split

src/exec/debugger.cpp+228−69
@@ -73,8 +73,26 @@ namespace · 72 unmodified lines
73 << "\n";73 << "\n";
74 }74 }
75 75
76 // Debug command context
77 struct dbg_cmd_cxt_t
78 {
79 dbg_cmd_cxt_t(const vm_t &v, const vm_registers_t &r)
80 : initial_register{ r }
81 , exit_break{ false }
82 , vm{ v }
83 {
84 current_register = &initial_register;
85 }
86
87 bool exit_break;
88
89 const vm_t &vm;
90 const vm_registers_t *current_register;
91 const vm_registers_t &initial_register;
92 };
93
76 // Debug command exec operation94 // Debug command exec operation
77 using dbg_cmd_exec_t = bool(*)(const std::vector<std::string> &, const vm_t &, const vm_registers_t &);95 using dbg_cmd_exec_t = void(*)(const std::vector<std::string> &, dbg_cmd_cxt_t &cxt);
78 96
79 // Debug command97 // Debug command
80 struct dbg_cmd_t98 struct dbg_cmd_t
@@ -118,9 +136,49 @@ namespace · 37 unmodified lines
118 136
119 std::ostream& operator<<(std::ostream &ss, const vm_string_t *s)137 std::ostream& operator<<(std::ostream &ss, const vm_string_t *s)
120 {138 {
139 auto escaped_string = std::stringstream{};
140 auto str = s->str();
141 if (str != nullptr)
142 {
143 while (*str != '\0')
144 {
145 switch (*str)
146 {
147 case '\\':
148 escaped_string << "\\\\";
149 break;
150 case '\a':
151 escaped_string << "\\a";
152 break;
153 case '\b':
154 escaped_string << "\\b";
155 break;
156 case '\f':
157 escaped_string << "\\f";
158 break;
159 case '\n':
160 escaped_string << "\\n";
161 break;
162 case '\r':
163 escaped_string << "\\r";
164 break;
165 case '\t':
166 escaped_string << "\\t";
167 break;
168 case '\v':
169 escaped_string << "\\v";
170 break;
171 default:
172 escaped_string << *str;
173 }
174
175 str++;
176 }
177 }
178
121 ss << "string\n"179 ss << "string\n"
122 << "\tlength: " << s->get_length() << "\n"180 << "\tlength: " << s->get_length() << "\n"
123 << "\tvalue: " << s->str() << "\n";181 << "\tvalue: \"" << escaped_string.str() << "\"\n";
124 182
125 return ss;183 return ss;
126 }184 }
@@ -149,10 +207,33 @@ namespace · 22 unmodified lines
149 return ss;207 return ss;
150 }208 }
151 209
152 std::ostream& operator<<(std::ostream &ss, const vm_alloc_t *a)210 std::ostream& operator<<(std::ostream &ss, const vm_alloc_t *alloc)
153 {211 {
154 ss << "alloc\n"212 if (alloc == nullptr)
155 << "\tsize: " << a->alloc_type->size_in_bytes << "\n";213 {
214 ss << "<nil>";
215 }
216 else if (alloc->alloc_type == intrinsic_type_desc::type<vm_string_t>())
217 {
218 ss << vm_alloc_t::from_allocation<vm_string_t>(alloc->get_allocation());
219 }
220 else if (alloc->alloc_type == intrinsic_type_desc::type<vm_array_t>())
221 {
222 ss << vm_alloc_t::from_allocation<vm_array_t>(alloc->get_allocation());
223 }
224 else if (alloc->alloc_type == intrinsic_type_desc::type<vm_list_t>())
225 {
226 ss << vm_alloc_t::from_allocation<vm_list_t>(alloc->get_allocation());
227 }
228 else if (alloc->alloc_type == intrinsic_type_desc::type<vm_channel_t>())
229 {
230 ss << vm_alloc_t::from_allocation<vm_channel_t>(alloc->get_allocation());
231 }
232 else
233 {
234 ss << "alloc\n"
235 << "\tsize: " << alloc->alloc_type->size_in_bytes << "\n";
236 }
156 237
157 return ss;238 return ss;
158 }239 }
@@ -210,72 +291,54 @@ namespace · 51 unmodified lines
210 auto frame_string = std::stringstream{};291 auto frame_string = std::stringstream{};
211 enum_pointer_fields(*frame->frame_type, frame->base(), [&frame_string](pointer_t p)292 enum_pointer_fields(*frame->frame_type, frame->base(), [&frame_string](pointer_t p)
212 {293 {
213 frame_string << std::showbase << std::hex << reinterpret_cast<uintptr_t>(p) << " : " << std::dec;294 frame_string << std::showbase << std::hex << reinterpret_cast<uintptr_t>(p) << " : " << std::dec << vm_alloc_t::from_allocation(p);
214
215 auto alloc = vm_alloc_t::from_allocation(p);
216 if (alloc->alloc_type == intrinsic_type_desc::type<vm_string_t>())
217 frame_string << vm_alloc_t::from_allocation<vm_string_t>(p);
218 else if (alloc->alloc_type == intrinsic_type_desc::type<vm_array_t>())
219 frame_string << vm_alloc_t::from_allocation<vm_array_t>(p);
220 else if (alloc->alloc_type == intrinsic_type_desc::type<vm_list_t>())
221 frame_string << vm_alloc_t::from_allocation<vm_list_t>(p);
222 else if (alloc->alloc_type == intrinsic_type_desc::type<vm_channel_t>())
223 frame_string << vm_alloc_t::from_allocation<vm_channel_t>(p);
224 else
225 frame_string << alloc;
226 });295 });
227 296
228 return frame_string.str();297 return frame_string.str();
229 }298 }
230 299
231 bool cmd_continue(const std::vector<std::string> &, const vm_t &, const vm_registers_t &)300 void cmd_continue(const std::vector<std::string> &, dbg_cmd_cxt_t &cxt)
232 {301 {
233 return false;302 cxt.exit_break = true;
234 }303 }
235 304
236 bool cmd_print_registers(const std::vector<std::string> &, const vm_t &, const vm_registers_t &r)305 void cmd_print_registers(const std::vector<std::string> &, dbg_cmd_cxt_t &cxt)
237 {306 {
238 auto s = registers_to_string(r);307 auto s = registers_to_string(*cxt.current_register);
239 debug_print_info(s);308 debug_print_info(s);
240
241 return true;
242 }309 }
243 310
244 bool cmd_print_threads(const std::vector<std::string> &, const vm_t &vm, const vm_registers_t &)311 void cmd_print_threads(const std::vector<std::string> &, dbg_cmd_cxt_t &cxt)
245 {312 {
246 auto msg = std::stringstream{};313 auto msg = std::stringstream{};
247 msg << "Threads:\n";314 msg << "Threads:\n";
248 for (auto t : vm.get_scheduler_control().get_all_threads())315 for (auto t : cxt.vm.get_scheduler_control().get_all_threads())
249 msg << " " << std::setw(5) << t->get_thread_id() << " - " << t->get_state() << "\n";316 msg << " " << std::setw(5) << t->get_thread_id() << " - " << t->get_state() << "\n";
250 317
251 debug_print_info(msg.str());318 debug_print_info(msg.str());
252
253 return true;
254 }319 }
255 320
256 bool cmd_print_modules(const std::vector<std::string> &, const vm_t &vm, const vm_registers_t &)321 void cmd_print_modules(const std::vector<std::string> &, dbg_cmd_cxt_t &cxt)
257 {322 {
258 auto msg = std::stringstream{};323 auto msg = std::stringstream{};
259 msg << "Modules:\n";324 msg << "Modules:\n";
260 for (auto m : vm.get_loaded_modules())325 for (auto m : cxt.vm.get_loaded_modules())
261 msg << " " << m->module_name->str() << "\n";326 msg << " " << m->module_name->str() << "\n";
262 327
263 debug_print_info(msg.str());328 debug_print_info(msg.str());
264
265 return true;
266 }329 }
267 330
268 bool cmd_stacktrace(const std::vector<std::string> &a, const vm_t &vm, const vm_registers_t &r)331 void cmd_stacktrace(const std::vector<std::string> &a, dbg_cmd_cxt_t &cxt)
269 {332 {
270 auto thread_registers = std::map<uint32_t, const vm_registers_t*>{};333 auto thread_registers = std::map<uint32_t, const vm_registers_t*>{};
271 if (a.size() == 1)334 if (a.size() == 1)
272 {335 {
273 thread_registers[r.thread.get_thread_id()] = &r;336 thread_registers[cxt.current_register->thread.get_thread_id()] = cxt.current_register;
274 }337 }
275 else338 else
276 {339 {
277 uint32_t thread_id;340 uint32_t thread_id;
278 auto all_threads = vm.get_scheduler_control().get_all_threads();341 auto all_threads = cxt.vm.get_scheduler_control().get_all_threads();
279 if (a[1].compare("*") == 0)342 if (a[1].compare("*") == 0)
280 {343 {
281 thread_id = 0;344 thread_id = 0;
@@ -289,7 +352,7 @@ namespace · 7 unmodified lines
289 catch (...)352 catch (...)
290 {353 {
291 debug_print_error("Invalid thread ID format");354 debug_print_error("Invalid thread ID format");
292 return true;355 return;
293 }356 }
294 }357 }
295 358
@@ -311,7 +374,7 @@ namespace · 15 unmodified lines
311 if (thread_registers.empty())374 if (thread_registers.empty())
312 {375 {
313 debug_print_error("Unknown thread ID");376 debug_print_error("Unknown thread ID");
314 return true;377 return;
315 }378 }
316 379
317 auto msg = std::stringstream{};380 auto msg = std::stringstream{};
@@ -323,19 +386,14 @@ namespace · 5 unmodified lines
323 }386 }
324 387
325 debug_print_info(msg.str());388 debug_print_info(msg.str());
326
327 return true;
328 }389 }
329 390
330 // Forward declaration391 void cmd_switchthread(const std::vector<std::string> &a, dbg_cmd_cxt_t &cxt)
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 {392 {
335 if (a.size() == 1)393 if (a.size() == 1)
336 {394 {
337 debug_print_error("Must supply a target thread ID");395 debug_print_error("Must supply a target thread ID");
338 return true;396 return;
339 }397 }
340 398
341 uint32_t thread_id;399 uint32_t thread_id;
@@ -346,10 +404,10 @@ namespace · 4 unmodified lines
346 catch (...)404 catch (...)
347 {405 {
348 debug_print_error("Invalid thread ID format");406 debug_print_error("Invalid thread ID format");
349 return true;407 return;
350 }408 }
351 409
352 auto all_threads = vm.get_scheduler_control().get_all_threads();410 auto all_threads = cxt.vm.get_scheduler_control().get_all_threads();
353 411
354 // Find the thread412 // Find the thread
355 for (auto t : all_threads)413 for (auto t : all_threads)
@@ -357,18 +415,15 @@ namespace · 1 unmodified line
357 const auto tid = t->get_thread_id();415 const auto tid = t->get_thread_id();
358 if (tid == thread_id)416 if (tid == thread_id)
359 {417 {
360 prompt(vm, t->get_registers());418 cxt.current_register = &t->get_registers();
361 419 return;
362 // If we are returning from a thread switch we are not continuing, so return false to indicate as such.
363 return false;
364 }420 }
365 }421 }
366 422
367 debug_print_error("Unknown thread ID");423 debug_print_error("Unknown thread ID");
368 return true;
369 }424 }
370 425
371 bool cmd_disassemble(const std::vector<std::string> &a, const vm_t &, const vm_registers_t &r)426 void cmd_disassemble(const std::vector<std::string> &a, dbg_cmd_cxt_t &cxt)
372 {427 {
373 auto disassemble_length = 1;428 auto disassemble_length = 1;
374 if (a.size() > 1)429 if (a.size() > 1)
@@ -380,10 +435,11 @@ namespace · 5 unmodified lines
380 catch (...)435 catch (...)
381 {436 {
382 debug_print_error("Invalid disassemble count format");437 debug_print_error("Invalid disassemble count format");
383 return true;438 return;
384 }439 }
385 }440 }
386 441
442 const auto &r = *cxt.current_register;
387 const auto &code_section = r.module_ref->code_section;443 const auto &code_section = r.module_ref->code_section;
388 444
389 auto begin_index = static_cast<std::size_t>(r.pc);445 auto begin_index = static_cast<std::size_t>(r.pc);
@@ -404,21 +460,122 @@ namespace · 14 unmodified lines
404 msg << " " << std::setw(5) << i << ": " << code_section[i].op << "\n";460 msg << " " << std::setw(5) << i << ": " << code_section[i].op << "\n";
405 461
406 debug_print_info(msg.str());462 debug_print_info(msg.str());
463 }
464
465 void cmd_examine(const std::vector<std::string> &a, dbg_cmd_cxt_t &cxt)
466 {
467 if (a.size() < 3)
468 {
469 debug_print_error("Invalid number of arguments");
470 return;
471 }
407 472
408 return true;473 std::shared_ptr<const type_descriptor_t> base_type;
474 word_t *base_pointer;
475 auto &base_ptr_id = a[1];
476 if (base_ptr_id.compare("mp") == 0)
477 {
478 base_type = cxt.current_register->mp_base->alloc_type;
479 base_pointer = reinterpret_cast<word_t *>(cxt.current_register->mp_base->get_allocation());
480 }
481 else if (base_ptr_id.compare("fp") == 0)
482 {
483 auto frame = cxt.current_register->stack.peek_frame();
484 if (frame == nullptr)
485 {
486 debug_print_error("Invalid frame pointer ");
487 return;
488 }
489
490 base_type = frame->frame_type;
491 base_pointer = reinterpret_cast<word_t *>(frame->base());
492 }
493 else
494 {
495 debug_print_error("Invalid memory base pointer");
496 return;
497 }
498
499 assert(base_type != nullptr && base_pointer != nullptr);
500
501 const auto pointer_size = static_cast<int>(sizeof(pointer_t));
502 auto byte_offset1 = int{ 0 };
503 auto byte_offset2 = int{ -1 };
504 try
505 {
506 byte_offset1 = std::stoi(a[2]);
507
508 // The 4th argument is optional
509 if (a.size() >= 4)
510 byte_offset2 = std::stoi(a[3]);
511 }
512 catch (...)
513 {
514 debug_print_error("Invalid memory offset format");
515 return;
516 }
517
518 if (0 > byte_offset1 || byte_offset1 >= base_type->size_in_bytes)
519 {
520 debug_print_error("First offset out of range");
521 return;
522 }
523
524 auto msg = std::stringstream{};
525 if (byte_offset2 != -1)
526 msg << " " << byte_offset2 << "(" << byte_offset1 << "(" << a[1] << ")):\n";
527 else
528 msg << " " << byte_offset1 << "(" << a[1] << "):\n";
529
530 auto value_is_pointer = bool{ false };
531 const auto pointer_offset1 = byte_offset1 / pointer_size;
532 auto value_to_examine = reinterpret_cast<pointer_t>(base_pointer[pointer_offset1]);
533 if (runtime::is_offset_pointer(*base_type, pointer_offset1))
534 {
535 value_is_pointer = true;
536 auto alloc_to_examine = vm_alloc_t::from_allocation(value_to_examine);
537 if (byte_offset2 != -1)
538 {
539 if (alloc_to_examine == nullptr)
540 {
541 debug_print_error("First offset is nil");
542 return;
543 }
544
545 if (0 > byte_offset2 || byte_offset2 >= alloc_to_examine->alloc_type->size_in_bytes)
546 {
547 debug_print_error("Second offset out of range");
548 return;
549 }
550
551 // Update data pointer for 2nd indirection
552 base_pointer = reinterpret_cast<word_t *>(alloc_to_examine->get_allocation());
553 base_type = alloc_to_examine->alloc_type;
554
555 const auto pointer_offset2 = byte_offset2 / pointer_size;
556 value_to_examine = reinterpret_cast<pointer_t>(base_pointer[pointer_offset2]);
557 value_is_pointer = runtime::is_offset_pointer(*base_type, pointer_offset2);
558 }
559 }
560
561 if (value_is_pointer)
562 msg << " " << vm_alloc_t::from_allocation(value_to_examine);
563 else
564 msg << " " << std::setw(8) << std::showbase << std::hex << value_to_examine << std::dec;
565
566 debug_print_info(msg.str());
409 }567 }
410 568
411 // Forward declaration569 // Forward declaration
412 void print_help();570 void print_help();
413 571
414 bool cmd_help(const std::vector<std::string> &, const vm_t &, const vm_registers_t &)572 void cmd_help(const std::vector<std::string> &, dbg_cmd_cxt_t &)
415 {573 {
416 print_help();574 print_help();
417 return true;
418 }575 }
419 576
420 // Easter egg577 // ee
421 bool cmd_tlk_tilde_star(const std::vector<std::string> &, const vm_t &, const vm_registers_t &)578 void cmd_tlk_tilde_star(const std::vector<std::string> &, dbg_cmd_cxt_t &)
422 {579 {
423 std::cout580 std::cout
424 << console_modifiers::black_font581 << console_modifiers::black_font
@@ -460,8 +617,6 @@ namespace · 35 unmodified lines
460 << console_modifiers::bold617 << console_modifiers::bold
461 << "!\n"618 << "!\n"
462 << console_modifiers::reset_all;619 << console_modifiers::reset_all;
463
464 return true;
465 }620 }
466 621
467 const dbg_cmd_t cmds[] =622 const dbg_cmd_t cmds[] =
@@ -473,7 +628,10 @@ namespace · 5 unmodified lines
473 { "sw", "Stack walk/back trace", "bt ([0-9]+|\\*)?", "bt, bt 34, bt *", cmd_stacktrace },628 { "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 },629 { "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 },630 { "d", "Disassemble the next/previous N instructions", "d (-?[0-9]+)?", "d, d -4, d 5", cmd_disassemble },
631 { "x", "Examine memory", "x [mp|fp] [0-9]+ ([0-9]+)?", "x mp 3, x fp 20 6", cmd_examine },
476 { "?", "Print help", nullptr, nullptr, cmd_help },632 { "?", "Print help", nullptr, nullptr, cmd_help },
633
634 // Undocumented commands
477 { "tlk~*", nullptr, nullptr, nullptr, cmd_tlk_tilde_star }635 { "tlk~*", nullptr, nullptr, nullptr, cmd_tlk_tilde_star }
478 };636 };
479 637
@@ -548,12 +706,14 @@ namespace · 68 unmodified lines
548 706
549 std::locale loc;707 std::locale loc;
550 std::string cmd;708 std::string cmd;
709
710 dbg_cmd_cxt_t cxt{ vm, r };
551 for (;;)711 for (;;)
552 {712 {
553 std::cout713 std::cout
554 << console_modifiers::green_font714 << console_modifiers::green_font
555 << console_modifiers::bold715 << console_modifiers::bold
556 << r.thread.get_thread_id()716 << cxt.current_register->thread.get_thread_id()
557 << " >>> "717 << " >>> "
558 << console_modifiers::reset_all;718 << console_modifiers::reset_all;
559 719
@@ -566,16 +726,15 @@ namespace · 6 unmodified lines
566 continue;726 continue;
567 727
568 auto cmd_exec = find_cmd(cmd_tokens[0]);728 auto cmd_exec = find_cmd(cmd_tokens[0]);
569 if (cmd_exec != nullptr)729 if (cmd_exec == nullptr)
570 {
571 if (!cmd_exec(cmd_tokens, vm, r))
572 break;
573 }
574 else
575 {730 {
576 debug_print_error("Unknown command");731 debug_print_error("Unknown command. '?' for help.");
577 print_help();732 continue;
578 }733 }
734
735 cmd_exec(cmd_tokens, cxt);
736 if (cxt.exit_break)
737 break;
579 }738 }
580 }739 }
581}740}