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
7373 << "\n";
7474 }
7575
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+
7694 // 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);
7896
7997 // Debug command
8098 struct dbg_cmd_t
@@ -118,9 +136,49 @@ namespace · 37 unmodified lines
118136
119137 std::ostream& operator<<(std::ostream &ss, const vm_string_t *s)
120138 {
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+
121179 ss << "string\n"
122180 << "\tlength: " << s->get_length() << "\n"
123− << "\tvalue: " << s->str() << "\n";
181+ << "\tvalue: \"" << escaped_string.str() << "\"\n";
124182
125183 return ss;
126184 }
@@ -149,10 +207,33 @@ namespace · 22 unmodified lines
149207 return ss;
150208 }
151209
152− std::ostream& operator<<(std::ostream &ss, const vm_alloc_t *a)
210+ std::ostream& operator<<(std::ostream &ss, const vm_alloc_t *alloc)
153211 {
154− ss << "alloc\n"
155− << "\tsize: " << a->alloc_type->size_in_bytes << "\n";
212+ if (alloc == nullptr)
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+ }
156237
157238 return ss;
158239 }
@@ -210,72 +291,54 @@ namespace · 51 unmodified lines
210291 auto frame_string = std::stringstream{};
211292 enum_pointer_fields(*frame->frame_type, frame->base(), [&frame_string](pointer_t p)
212293 {
213− frame_string << std::showbase << std::hex << reinterpret_cast<uintptr_t>(p) << " : " << std::dec;
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;
294+ frame_string << std::showbase << std::hex << reinterpret_cast<uintptr_t>(p) << " : " << std::dec << vm_alloc_t::from_allocation(p);
226295 });
227296
228297 return frame_string.str();
229298 }
230299
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)
232301 {
233− return false;
302+ cxt.exit_break = true;
234303 }
235304
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)
237306 {
238− auto s = registers_to_string(r);
307+ auto s = registers_to_string(*cxt.current_register);
239308 debug_print_info(s);
240−
241− return true;
242309 }
243310
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)
245312 {
246313 auto msg = std::stringstream{};
247314 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())
249316 msg << " " << std::setw(5) << t->get_thread_id() << " - " << t->get_state() << "\n";
250317
251318 debug_print_info(msg.str());
252−
253− return true;
254319 }
255320
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)
257322 {
258323 auto msg = std::stringstream{};
259324 msg << "Modules:\n";
260− for (auto m : vm.get_loaded_modules())
325+ for (auto m : cxt.vm.get_loaded_modules())
261326 msg << " " << m->module_name->str() << "\n";
262327
263328 debug_print_info(msg.str());
264−
265− return true;
266329 }
267330
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)
269332 {
270333 auto thread_registers = std::map<uint32_t, const vm_registers_t*>{};
271334 if (a.size() == 1)
272335 {
273− thread_registers[r.thread.get_thread_id()] = &r;
336+ thread_registers[cxt.current_register->thread.get_thread_id()] = cxt.current_register;
274337 }
275338 else
276339 {
277340 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();
279342 if (a[1].compare("*") == 0)
280343 {
281344 thread_id = 0;
@@ -289,7 +352,7 @@ namespace · 7 unmodified lines
289352 catch (...)
290353 {
291354 debug_print_error("Invalid thread ID format");
292− return true;
355+ return;
293356 }
294357 }
295358
@@ -311,7 +374,7 @@ namespace · 15 unmodified lines
311374 if (thread_registers.empty())
312375 {
313376 debug_print_error("Unknown thread ID");
314− return true;
377+ return;
315378 }
316379
317380 auto msg = std::stringstream{};
@@ -323,19 +386,14 @@ namespace · 5 unmodified lines
323386 }
324387
325388 debug_print_info(msg.str());
326−
327− return true;
328389 }
329390
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)
391+ void cmd_switchthread(const std::vector<std::string> &a, dbg_cmd_cxt_t &cxt)
334392 {
335393 if (a.size() == 1)
336394 {
337395 debug_print_error("Must supply a target thread ID");
338− return true;
396+ return;
339397 }
340398
341399 uint32_t thread_id;
@@ -346,10 +404,10 @@ namespace · 4 unmodified lines
346404 catch (...)
347405 {
348406 debug_print_error("Invalid thread ID format");
349− return true;
407+ return;
350408 }
351409
352− auto all_threads = vm.get_scheduler_control().get_all_threads();
410+ auto all_threads = cxt.vm.get_scheduler_control().get_all_threads();
353411
354412 // Find the thread
355413 for (auto t : all_threads)
@@ -357,18 +415,15 @@ namespace · 1 unmodified line
357415 const auto tid = t->get_thread_id();
358416 if (tid == thread_id)
359417 {
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;
418+ cxt.current_register = &t->get_registers();
419+ return;
364420 }
365421 }
366422
367423 debug_print_error("Unknown thread ID");
368− return true;
369424 }
370425
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)
372427 {
373428 auto disassemble_length = 1;
374429 if (a.size() > 1)
@@ -380,10 +435,11 @@ namespace · 5 unmodified lines
380435 catch (...)
381436 {
382437 debug_print_error("Invalid disassemble count format");
383− return true;
438+ return;
384439 }
385440 }
386441
442+ const auto &r = *cxt.current_register;
387443 const auto &code_section = r.module_ref->code_section;
388444
389445 auto begin_index = static_cast<std::size_t>(r.pc);
@@ -404,21 +460,122 @@ namespace · 14 unmodified lines
404460 msg << " " << std::setw(5) << i << ": " << code_section[i].op << "\n";
405461
406462 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+ }
407472
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());
409567 }
410568
411569 // Forward declaration
412570 void print_help();
413571
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 &)
415573 {
416574 print_help();
417− return true;
418575 }
419576
420− // Easter egg
421− bool cmd_tlk_tilde_star(const std::vector<std::string> &, const vm_t &, const vm_registers_t &)
577+ // ee
578+ void cmd_tlk_tilde_star(const std::vector<std::string> &, dbg_cmd_cxt_t &)
422579 {
423580 std::cout
424581 << console_modifiers::black_font
@@ -460,8 +617,6 @@ namespace · 35 unmodified lines
460617 << console_modifiers::bold
461618 << "!\n"
462619 << console_modifiers::reset_all;
463−
464− return true;
465620 }
466621
467622 const dbg_cmd_t cmds[] =
@@ -473,7 +628,10 @@ namespace · 5 unmodified lines
473628 { "sw", "Stack walk/back trace", "bt ([0-9]+|\\*)?", "bt, bt 34, bt *", cmd_stacktrace },
474629 { "st", "Switch to thread", "st [0-9]+", "st 42", cmd_switchthread },
475630 { "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 },
476632 { "?", "Print help", nullptr, nullptr, cmd_help },
633+
634+ // Undocumented commands
477635 { "tlk~*", nullptr, nullptr, nullptr, cmd_tlk_tilde_star }
478636 };
479637
@@ -548,12 +706,14 @@ namespace · 68 unmodified lines
548706
549707 std::locale loc;
550708 std::string cmd;
709+
710+ dbg_cmd_cxt_t cxt{ vm, r };
551711 for (;;)
552712 {
553713 std::cout
554714 << console_modifiers::green_font
555715 << console_modifiers::bold
556− << r.thread.get_thread_id()
716+ << cxt.current_register->thread.get_thread_id()
557717 << " >>> "
558718 << console_modifiers::reset_all;
559719
@@ -566,16 +726,15 @@ namespace · 6 unmodified lines
566726 continue;
567727
568728 auto cmd_exec = find_cmd(cmd_tokens[0]);
569− if (cmd_exec != nullptr)
570− {
571− if (!cmd_exec(cmd_tokens, vm, r))
572− break;
573− }
574− else
729+ if (cmd_exec == nullptr)
575730 {
576− debug_print_error("Unknown command");
577− print_help();
731+ debug_print_error("Unknown command. '?' for help.");
732+ continue;
578733 }
734+
735+ cmd_exec(cmd_tokens, cxt);
736+ if (cxt.exit_break)
737+ break;
579738 }
580739 }
581740 }