| @@ -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 operation | 94 | // 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 command | 97 | // Debug command |
| 80 | struct dbg_cmd_t | 98 | 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 | else | 338 | 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 declaration | 391 | 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 thread | 412 | // 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 declaration | 569 | // 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 egg | 577 | // 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::cout | 580 | std::cout |
| 424 | << console_modifiers::black_font | 581 | << console_modifiers::black_font |
| @@ -460,8 +617,6 @@ namespace · 35 unmodified lines |
| 460 | << console_modifiers::bold | 617 | << 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::cout | 713 | std::cout |
| 554 | << console_modifiers::green_font | 714 | << console_modifiers::green_font |
| 555 | << console_modifiers::bold | 715 | << 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 | } |