Debugger-vixl.cpp (40929B)
1 // Copyright 2014, ARM Limited 2 // All rights reserved. 3 // 4 // Redistribution and use in source and binary forms, with or without 5 // modification, are permitted provided that the following conditions are met: 6 // 7 // * Redistributions of source code must retain the above copyright notice, 8 // this list of conditions and the following disclaimer. 9 // * Redistributions in binary form must reproduce the above copyright notice, 10 // this list of conditions and the following disclaimer in the documentation 11 // and/or other materials provided with the distribution. 12 // * Neither the name of ARM Limited nor the names of its contributors may be 13 // used to endorse or promote products derived from this software without 14 // specific prior written permission. 15 // 16 // THIS SOFTWARE IS PROVIDED BY ARM LIMITED AND CONTRIBUTORS "AS IS" AND ANY 17 // EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED 18 // WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 19 // DISCLAIMED. IN NO EVENT SHALL ARM LIMITED BE LIABLE FOR ANY DIRECT, INDIRECT, 20 // INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 21 // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, 22 // OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF 23 // LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING 24 // NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, 25 // EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 26 27 #include "jstypes.h" 28 29 #ifdef JS_SIMULATOR_ARM64 30 31 #include "jit/arm64/vixl/Debugger-vixl.h" 32 33 #include "mozilla/Vector.h" 34 35 #include "js/AllocPolicy.h" 36 37 namespace vixl { 38 39 // List of commands supported by the debugger. 40 #define DEBUG_COMMAND_LIST(C) \ 41 C(HelpCommand) \ 42 C(ContinueCommand) \ 43 C(StepCommand) \ 44 C(DisasmCommand) \ 45 C(PrintCommand) \ 46 C(ExamineCommand) 47 48 // Debugger command lines are broken up in token of different type to make 49 // processing easier later on. 50 class Token { 51 public: 52 virtual ~Token() {} 53 54 // Token type. 55 virtual bool IsRegister() const { return false; } 56 virtual bool IsFPRegister() const { return false; } 57 virtual bool IsIdentifier() const { return false; } 58 virtual bool IsAddress() const { return false; } 59 virtual bool IsInteger() const { return false; } 60 virtual bool IsFormat() const { return false; } 61 virtual bool IsUnknown() const { return false; } 62 // Token properties. 63 virtual bool CanAddressMemory() const { return false; } 64 virtual uint8_t* ToAddress(Debugger* debugger) const = 0; 65 virtual void Print(FILE* out = stdout) const = 0; 66 67 static Token* Tokenize(const char* arg); 68 }; 69 70 typedef mozilla::Vector<Token*, 0, js::SystemAllocPolicy> TokenVector; 71 72 // Tokens often hold one value. 73 template<typename T> class ValueToken : public Token { 74 public: 75 explicit ValueToken(T value) : value_(value) {} 76 ValueToken() {} 77 78 T value() const { return value_; } 79 80 virtual uint8_t* ToAddress(Debugger* debugger) const override { 81 USE(debugger); 82 VIXL_ABORT(); 83 } 84 85 protected: 86 T value_; 87 }; 88 89 // Integer registers (X or W) and their aliases. 90 // Format: wn or xn with 0 <= n < 32 or a name in the aliases list. 91 class RegisterToken : public ValueToken<const Register> { 92 public: 93 explicit RegisterToken(const Register reg) 94 : ValueToken<const Register>(reg) {} 95 96 virtual bool IsRegister() const override { return true; } 97 virtual bool CanAddressMemory() const override { return value().Is64Bits(); } 98 virtual uint8_t* ToAddress(Debugger* debugger) const override; 99 virtual void Print(FILE* out = stdout) const override; 100 const char* Name() const; 101 102 static Token* Tokenize(const char* arg); 103 static RegisterToken* Cast(Token* tok) { 104 VIXL_ASSERT(tok->IsRegister()); 105 return reinterpret_cast<RegisterToken*>(tok); 106 } 107 108 private: 109 static const int kMaxAliasNumber = 4; 110 static const char* kXAliases[kNumberOfRegisters][kMaxAliasNumber]; 111 static const char* kWAliases[kNumberOfRegisters][kMaxAliasNumber]; 112 }; 113 114 // Floating point registers (D or S). 115 // Format: sn or dn with 0 <= n < 32. 116 class FPRegisterToken : public ValueToken<const FPRegister> { 117 public: 118 explicit FPRegisterToken(const FPRegister fpreg) 119 : ValueToken<const FPRegister>(fpreg) {} 120 121 virtual bool IsFPRegister() const override { return true; } 122 virtual void Print(FILE* out = stdout) const override; 123 124 static Token* Tokenize(const char* arg); 125 static FPRegisterToken* Cast(Token* tok) { 126 VIXL_ASSERT(tok->IsFPRegister()); 127 return reinterpret_cast<FPRegisterToken*>(tok); 128 } 129 }; 130 131 132 // Non-register identifiers. 133 // Format: Alphanumeric string starting with a letter. 134 class IdentifierToken : public ValueToken<char*> { 135 public: 136 explicit IdentifierToken(const char* name) { 137 size_t size = strlen(name) + 1; 138 value_ = js_pod_malloc<char>(size); 139 strncpy(value_, name, size); 140 } 141 virtual ~IdentifierToken() { js_free(value_); } 142 143 virtual bool IsIdentifier() const override { return true; } 144 virtual bool CanAddressMemory() const override { return strcmp(value(), "pc") == 0; } 145 virtual uint8_t* ToAddress(Debugger* debugger) const override; 146 virtual void Print(FILE* out = stdout) const override; 147 148 static Token* Tokenize(const char* arg); 149 static IdentifierToken* Cast(Token* tok) { 150 VIXL_ASSERT(tok->IsIdentifier()); 151 return reinterpret_cast<IdentifierToken*>(tok); 152 } 153 }; 154 155 // 64-bit address literal. 156 // Format: 0x... with up to 16 hexadecimal digits. 157 class AddressToken : public ValueToken<uint8_t*> { 158 public: 159 explicit AddressToken(uint8_t* address) : ValueToken<uint8_t*>(address) {} 160 161 virtual bool IsAddress() const override { return true; } 162 virtual bool CanAddressMemory() const override { return true; } 163 virtual uint8_t* ToAddress(Debugger* debugger) const override; 164 virtual void Print(FILE* out = stdout) const override; 165 166 static Token* Tokenize(const char* arg); 167 static AddressToken* Cast(Token* tok) { 168 VIXL_ASSERT(tok->IsAddress()); 169 return reinterpret_cast<AddressToken*>(tok); 170 } 171 }; 172 173 174 // 64-bit decimal integer literal. 175 // Format: n. 176 class IntegerToken : public ValueToken<int64_t> { 177 public: 178 explicit IntegerToken(int64_t value) : ValueToken<int64_t>(value) {} 179 180 virtual bool IsInteger() const override { return true; } 181 virtual void Print(FILE* out = stdout) const override; 182 183 static Token* Tokenize(const char* arg); 184 static IntegerToken* Cast(Token* tok) { 185 VIXL_ASSERT(tok->IsInteger()); 186 return reinterpret_cast<IntegerToken*>(tok); 187 } 188 }; 189 190 // Literal describing how to print a chunk of data (up to 64 bits). 191 // Format: .ln 192 // where l (letter) is one of 193 // * x: hexadecimal 194 // * s: signed integer 195 // * u: unsigned integer 196 // * f: floating point 197 // * i: instruction 198 // and n (size) is one of 8, 16, 32 and 64. n should be omitted for 199 // instructions. 200 class FormatToken : public Token { 201 public: 202 FormatToken() {} 203 204 virtual bool IsFormat() const override { return true; } 205 virtual int SizeOf() const = 0; 206 virtual char type_code() const = 0; 207 virtual void PrintData(void* data, FILE* out = stdout) const = 0; 208 virtual void Print(FILE* out = stdout) const override = 0; 209 210 virtual uint8_t* ToAddress(Debugger* debugger) const override { 211 USE(debugger); 212 VIXL_ABORT(); 213 } 214 215 static Token* Tokenize(const char* arg); 216 static FormatToken* Cast(Token* tok) { 217 VIXL_ASSERT(tok->IsFormat()); 218 return reinterpret_cast<FormatToken*>(tok); 219 } 220 }; 221 222 223 template<typename T> class Format : public FormatToken { 224 public: 225 Format(const char* fmt, char type_code) : fmt_(fmt), type_code_(type_code) {} 226 227 virtual int SizeOf() const override { return sizeof(T); } 228 virtual char type_code() const override { return type_code_; } 229 virtual void PrintData(void* data, FILE* out = stdout) const override { 230 T value; 231 memcpy(&value, data, sizeof(value)); 232 fprintf(out, fmt_, value); 233 } 234 virtual void Print(FILE* out = stdout) const override; 235 236 private: 237 const char* fmt_; 238 char type_code_; 239 }; 240 241 // Tokens which don't fit any of the above. 242 class UnknownToken : public Token { 243 public: 244 explicit UnknownToken(const char* arg) { 245 size_t size = strlen(arg) + 1; 246 unknown_ = js_pod_malloc<char>(size); 247 strncpy(unknown_, arg, size); 248 } 249 virtual ~UnknownToken() { js_free(unknown_); } 250 virtual uint8_t* ToAddress(Debugger* debugger) const override { 251 USE(debugger); 252 VIXL_ABORT(); 253 } 254 255 virtual bool IsUnknown() const override { return true; } 256 virtual void Print(FILE* out = stdout) const override; 257 258 private: 259 char* unknown_; 260 }; 261 262 263 // All debugger commands must subclass DebugCommand and implement Run, Print 264 // and Build. Commands must also define kHelp and kAliases. 265 class DebugCommand { 266 public: 267 explicit DebugCommand(Token* name) : name_(IdentifierToken::Cast(name)) {} 268 DebugCommand() : name_(NULL) {} 269 virtual ~DebugCommand() { js_delete(name_); } 270 271 const char* name() { return name_->value(); } 272 // Run the command on the given debugger. The command returns true if 273 // execution should move to the next instruction. 274 virtual bool Run(Debugger * debugger) = 0; 275 virtual void Print(FILE* out = stdout); 276 277 static bool Match(const char* name, const char** aliases); 278 static DebugCommand* Parse(char* line); 279 static void PrintHelp(const char** aliases, 280 const char* args, 281 const char* help); 282 283 private: 284 IdentifierToken* name_; 285 }; 286 287 // For all commands below see their respective kHelp and kAliases in 288 // debugger-a64.cc 289 class HelpCommand : public DebugCommand { 290 public: 291 explicit HelpCommand(Token* name) : DebugCommand(name) {} 292 293 virtual bool Run(Debugger* debugger) override; 294 295 static DebugCommand* Build(TokenVector&& args); 296 297 static const char* kHelp; 298 static const char* kAliases[]; 299 static const char* kArguments; 300 }; 301 302 303 class ContinueCommand : public DebugCommand { 304 public: 305 explicit ContinueCommand(Token* name) : DebugCommand(name) {} 306 307 virtual bool Run(Debugger* debugger) override; 308 309 static DebugCommand* Build(TokenVector&& args); 310 311 static const char* kHelp; 312 static const char* kAliases[]; 313 static const char* kArguments; 314 }; 315 316 317 class StepCommand : public DebugCommand { 318 public: 319 StepCommand(Token* name, IntegerToken* count) 320 : DebugCommand(name), count_(count) {} 321 virtual ~StepCommand() { js_delete(count_); } 322 323 int64_t count() { return count_->value(); } 324 virtual bool Run(Debugger* debugger) override; 325 virtual void Print(FILE* out = stdout) override; 326 327 static DebugCommand* Build(TokenVector&& args); 328 329 static const char* kHelp; 330 static const char* kAliases[]; 331 static const char* kArguments; 332 333 private: 334 IntegerToken* count_; 335 }; 336 337 class DisasmCommand : public DebugCommand { 338 public: 339 static DebugCommand* Build(TokenVector&& args); 340 341 static const char* kHelp; 342 static const char* kAliases[]; 343 static const char* kArguments; 344 }; 345 346 347 class PrintCommand : public DebugCommand { 348 public: 349 PrintCommand(Token* name, Token* target, FormatToken* format) 350 : DebugCommand(name), target_(target), format_(format) {} 351 virtual ~PrintCommand() { 352 js_delete(target_); 353 js_delete(format_); 354 } 355 356 Token* target() { return target_; } 357 FormatToken* format() { return format_; } 358 virtual bool Run(Debugger* debugger) override; 359 virtual void Print(FILE* out = stdout) override; 360 361 static DebugCommand* Build(TokenVector&& args); 362 363 static const char* kHelp; 364 static const char* kAliases[]; 365 static const char* kArguments; 366 367 private: 368 Token* target_; 369 FormatToken* format_; 370 }; 371 372 class ExamineCommand : public DebugCommand { 373 public: 374 ExamineCommand(Token* name, 375 Token* target, 376 FormatToken* format, 377 IntegerToken* count) 378 : DebugCommand(name), target_(target), format_(format), count_(count) {} 379 virtual ~ExamineCommand() { 380 js_delete(target_); 381 js_delete(format_); 382 js_delete(count_); 383 } 384 385 Token* target() { return target_; } 386 FormatToken* format() { return format_; } 387 IntegerToken* count() { return count_; } 388 virtual bool Run(Debugger* debugger) override; 389 virtual void Print(FILE* out = stdout) override; 390 391 static DebugCommand* Build(TokenVector&& args); 392 393 static const char* kHelp; 394 static const char* kAliases[]; 395 static const char* kArguments; 396 397 private: 398 Token* target_; 399 FormatToken* format_; 400 IntegerToken* count_; 401 }; 402 403 // Commands which name does not match any of the known commnand. 404 class UnknownCommand : public DebugCommand { 405 public: 406 explicit UnknownCommand(TokenVector&& args) : args_(std::move(args)) {} 407 virtual ~UnknownCommand(); 408 409 virtual bool Run(Debugger* debugger) override; 410 411 private: 412 TokenVector args_; 413 }; 414 415 // Commands which name match a known command but the syntax is invalid. 416 class InvalidCommand : public DebugCommand { 417 public: 418 InvalidCommand(TokenVector&& args, int index, const char* cause) 419 : args_(std::move(args)), index_(index), cause_(cause) {} 420 virtual ~InvalidCommand(); 421 422 virtual bool Run(Debugger* debugger) override; 423 424 private: 425 TokenVector args_; 426 int index_; 427 const char* cause_; 428 }; 429 430 const char* HelpCommand::kAliases[] = { "help", NULL }; 431 const char* HelpCommand::kArguments = NULL; 432 const char* HelpCommand::kHelp = " Print this help."; 433 434 const char* ContinueCommand::kAliases[] = { "continue", "c", NULL }; 435 const char* ContinueCommand::kArguments = NULL; 436 const char* ContinueCommand::kHelp = " Resume execution."; 437 438 const char* StepCommand::kAliases[] = { "stepi", "si", NULL }; 439 const char* StepCommand::kArguments = "[n = 1]"; 440 const char* StepCommand::kHelp = " Execute n next instruction(s)."; 441 442 const char* DisasmCommand::kAliases[] = { "disasm", "di", NULL }; 443 const char* DisasmCommand::kArguments = "[n = 10]"; 444 const char* DisasmCommand::kHelp = 445 " Disassemble n instruction(s) at pc.\n" 446 " This command is equivalent to x pc.i [n = 10]." 447 ; 448 449 const char* PrintCommand::kAliases[] = { "print", "p", NULL }; 450 const char* PrintCommand::kArguments = "<entity>[.format]"; 451 const char* PrintCommand::kHelp = 452 " Print the given entity according to the given format.\n" 453 " The format parameter only affects individual registers; it is ignored\n" 454 " for other entities.\n" 455 " <entity> can be one of the following:\n" 456 " * A register name (such as x0, s1, ...).\n" 457 " * 'regs', to print all integer (W and X) registers.\n" 458 " * 'fpregs' to print all floating-point (S and D) registers.\n" 459 " * 'sysregs' to print all system registers (including NZCV).\n" 460 " * 'pc' to print the current program counter.\n" 461 ; 462 463 const char* ExamineCommand::kAliases[] = { "m", "mem", "x", NULL }; 464 const char* ExamineCommand::kArguments = "<addr>[.format] [n = 10]"; 465 const char* ExamineCommand::kHelp = 466 " Examine memory. Print n items of memory at address <addr> according to\n" 467 " the given [.format].\n" 468 " Addr can be an immediate address, a register name or pc.\n" 469 " Format is made of a type letter: 'x' (hexadecimal), 's' (signed), 'u'\n" 470 " (unsigned), 'f' (floating point), i (instruction) and a size in bits\n" 471 " when appropriate (8, 16, 32, 64)\n" 472 " E.g 'x sp.x64' will print 10 64-bit words from the stack in\n" 473 " hexadecimal format." 474 ; 475 476 const char* RegisterToken::kXAliases[kNumberOfRegisters][kMaxAliasNumber] = { 477 { "x0", NULL }, 478 { "x1", NULL }, 479 { "x2", NULL }, 480 { "x3", NULL }, 481 { "x4", NULL }, 482 { "x5", NULL }, 483 { "x6", NULL }, 484 { "x7", NULL }, 485 { "x8", NULL }, 486 { "x9", NULL }, 487 { "x10", NULL }, 488 { "x11", NULL }, 489 { "x12", NULL }, 490 { "x13", NULL }, 491 { "x14", NULL }, 492 { "x15", NULL }, 493 { "ip0", "x16", NULL }, 494 { "ip1", "x17", NULL }, 495 { "x18", "pr", NULL }, 496 { "x19", NULL }, 497 { "x20", NULL }, 498 { "x21", NULL }, 499 { "x22", NULL }, 500 { "x23", NULL }, 501 { "x24", NULL }, 502 { "x25", NULL }, 503 { "x26", NULL }, 504 { "x27", NULL }, 505 { "x28", NULL }, 506 { "fp", "x29", NULL }, 507 { "lr", "x30", NULL }, 508 { "sp", NULL} 509 }; 510 511 const char* RegisterToken::kWAliases[kNumberOfRegisters][kMaxAliasNumber] = { 512 { "w0", NULL }, 513 { "w1", NULL }, 514 { "w2", NULL }, 515 { "w3", NULL }, 516 { "w4", NULL }, 517 { "w5", NULL }, 518 { "w6", NULL }, 519 { "w7", NULL }, 520 { "w8", NULL }, 521 { "w9", NULL }, 522 { "w10", NULL }, 523 { "w11", NULL }, 524 { "w12", NULL }, 525 { "w13", NULL }, 526 { "w14", NULL }, 527 { "w15", NULL }, 528 { "w16", NULL }, 529 { "w17", NULL }, 530 { "w18", NULL }, 531 { "w19", NULL }, 532 { "w20", NULL }, 533 { "w21", NULL }, 534 { "w22", NULL }, 535 { "w23", NULL }, 536 { "w24", NULL }, 537 { "w25", NULL }, 538 { "w26", NULL }, 539 { "w27", NULL }, 540 { "w28", NULL }, 541 { "w29", NULL }, 542 { "w30", NULL }, 543 { "wsp", NULL } 544 }; 545 546 547 Debugger::Debugger(Decoder* decoder, FILE* stream) 548 : Simulator(decoder, stream), 549 debug_parameters_(DBG_INACTIVE), 550 pending_request_(false), 551 steps_(0), 552 last_command_(NULL) { 553 disasm_ = js_new<PrintDisassembler>(stdout); 554 printer_ = js_new<Decoder>(); 555 printer_->AppendVisitor(disasm_); 556 } 557 558 559 Debugger::~Debugger() { 560 js_delete(disasm_); 561 js_delete(printer_); 562 } 563 564 565 void Debugger::Run() { 566 pc_modified_ = false; 567 while (pc_ != kEndOfSimAddress) { 568 if (pending_request()) RunDebuggerShell(); 569 ExecuteInstruction(); 570 LogAllWrittenRegisters(); 571 } 572 } 573 574 575 void Debugger::PrintInstructions(const void* address, int64_t count) { 576 if (count == 0) { 577 return; 578 } 579 580 const Instruction* from = Instruction::CastConst(address); 581 if (count < 0) { 582 count = -count; 583 from -= (count - 1) * kInstructionSize; 584 } 585 const Instruction* to = from + count * kInstructionSize; 586 587 for (const Instruction* current = from; 588 current < to; 589 current = current->NextInstruction()) { 590 printer_->Decode(current); 591 } 592 } 593 594 595 void Debugger::PrintMemory(const uint8_t* address, 596 const FormatToken* format, 597 int64_t count) { 598 if (count == 0) { 599 return; 600 } 601 602 const uint8_t* from = address; 603 int size = format->SizeOf(); 604 if (count < 0) { 605 count = -count; 606 from -= (count - 1) * size; 607 } 608 const uint8_t* to = from + count * size; 609 610 for (const uint8_t* current = from; current < to; current += size) { 611 if (((current - from) % 8) == 0) { 612 printf("\n%p: ", current); 613 } 614 615 uint64_t data = Memory::Read<uint64_t>(current); 616 format->PrintData(&data); 617 printf(" "); 618 } 619 printf("\n\n"); 620 } 621 622 623 void Debugger::PrintRegister(const Register& target_reg, 624 const char* name, 625 const FormatToken* format) { 626 const uint64_t reg_size = target_reg.size(); 627 const uint64_t format_size = format->SizeOf() * 8; 628 const uint64_t count = reg_size / format_size; 629 const uint64_t mask = 0xffffffffffffffff >> (64 - format_size); 630 const uint64_t reg_value = reg<uint64_t>(target_reg.code(), 631 Reg31IsStackPointer); 632 VIXL_ASSERT(count > 0); 633 634 printf("%s = ", name); 635 for (uint64_t i = 1; i <= count; i++) { 636 uint64_t data = reg_value >> (reg_size - (i * format_size)); 637 data &= mask; 638 format->PrintData(&data); 639 printf(" "); 640 } 641 printf("\n"); 642 } 643 644 645 // TODO(all): fix this for vector registers. 646 void Debugger::PrintFPRegister(const FPRegister& target_fpreg, 647 const FormatToken* format) { 648 const unsigned fpreg_size = target_fpreg.size(); 649 const uint64_t format_size = format->SizeOf() * 8; 650 const uint64_t count = fpreg_size / format_size; 651 const uint64_t mask = 0xffffffffffffffff >> (64 - format_size); 652 const uint64_t fpreg_value = vreg<uint64_t>(fpreg_size, target_fpreg.code()); 653 VIXL_ASSERT(count > 0); 654 655 if (target_fpreg.Is32Bits()) { 656 printf("s%u = ", target_fpreg.code()); 657 } else { 658 printf("d%u = ", target_fpreg.code()); 659 } 660 for (uint64_t i = 1; i <= count; i++) { 661 uint64_t data = fpreg_value >> (fpreg_size - (i * format_size)); 662 data &= mask; 663 format->PrintData(&data); 664 printf(" "); 665 } 666 printf("\n"); 667 } 668 669 670 void Debugger::VisitException(const Instruction* instr) { 671 switch (instr->Mask(ExceptionMask)) { 672 case BRK: 673 DoBreakpoint(instr); 674 return; 675 case HLT: 676 VIXL_FALLTHROUGH(); 677 default: Simulator::VisitException(instr); 678 } 679 } 680 681 682 // Read a command. A command will be at most kMaxDebugShellLine char long and 683 // ends with '\n\0'. 684 // TODO: Should this be a utility function? 685 char* Debugger::ReadCommandLine(const char* prompt, char* buffer, int length) { 686 int fgets_calls = 0; 687 char* end = NULL; 688 689 printf("%s", prompt); 690 fflush(stdout); 691 692 do { 693 if (fgets(buffer, length, stdin) == NULL) { 694 printf(" ** Error while reading command. **\n"); 695 return NULL; 696 } 697 698 fgets_calls++; 699 end = strchr(buffer, '\n'); 700 } while (end == NULL); 701 702 if (fgets_calls != 1) { 703 printf(" ** Command too long. **\n"); 704 return NULL; 705 } 706 707 // Remove the newline from the end of the command. 708 VIXL_ASSERT(end[1] == '\0'); 709 VIXL_ASSERT((end - buffer) < (length - 1)); 710 end[0] = '\0'; 711 712 return buffer; 713 } 714 715 716 void Debugger::RunDebuggerShell() { 717 if (IsDebuggerRunning()) { 718 if (steps_ > 0) { 719 // Finish stepping first. 720 --steps_; 721 return; 722 } 723 724 printf("Next: "); 725 PrintInstructions(pc()); 726 bool done = false; 727 while (!done) { 728 char buffer[kMaxDebugShellLine]; 729 char* line = ReadCommandLine("vixl> ", buffer, kMaxDebugShellLine); 730 731 if (line == NULL) continue; // An error occurred. 732 733 DebugCommand* command = DebugCommand::Parse(line); 734 if (command != NULL) { 735 last_command_ = command; 736 } 737 738 if (last_command_ != NULL) { 739 done = last_command_->Run(this); 740 } else { 741 printf("No previous command to run!\n"); 742 } 743 } 744 745 if ((debug_parameters_ & DBG_BREAK) != 0) { 746 // The break request has now been handled, move to next instruction. 747 debug_parameters_ &= ~DBG_BREAK; 748 increment_pc(); 749 } 750 } 751 } 752 753 754 void Debugger::DoBreakpoint(const Instruction* instr) { 755 VIXL_ASSERT(instr->Mask(ExceptionMask) == BRK); 756 757 printf("Hit breakpoint at pc=%p.\n", reinterpret_cast<const void*>(instr)); 758 set_debug_parameters(debug_parameters() | DBG_BREAK | DBG_ACTIVE); 759 // Make the shell point to the brk instruction. 760 set_pc(instr); 761 } 762 763 764 static bool StringToUInt64(uint64_t* value, const char* line, int base = 10) { 765 char* endptr = NULL; 766 errno = 0; // Reset errors. 767 uint64_t parsed = strtoul(line, &endptr, base); 768 769 if (errno == ERANGE) { 770 // Overflow. 771 return false; 772 } 773 774 if (endptr == line) { 775 // No digits were parsed. 776 return false; 777 } 778 779 if (*endptr != '\0') { 780 // Non-digit characters present at the end. 781 return false; 782 } 783 784 *value = parsed; 785 return true; 786 } 787 788 789 static bool StringToInt64(int64_t* value, const char* line, int base = 10) { 790 char* endptr = NULL; 791 errno = 0; // Reset errors. 792 int64_t parsed = strtol(line, &endptr, base); 793 794 if (errno == ERANGE) { 795 // Overflow, undeflow. 796 return false; 797 } 798 799 if (endptr == line) { 800 // No digits were parsed. 801 return false; 802 } 803 804 if (*endptr != '\0') { 805 // Non-digit characters present at the end. 806 return false; 807 } 808 809 *value = parsed; 810 return true; 811 } 812 813 814 Token* Token::Tokenize(const char* arg) { 815 if ((arg == NULL) || (*arg == '\0')) { 816 return NULL; 817 } 818 819 // The order is important. For example Identifier::Tokenize would consider 820 // any register to be a valid identifier. 821 822 Token* token = RegisterToken::Tokenize(arg); 823 if (token != NULL) { 824 return token; 825 } 826 827 token = FPRegisterToken::Tokenize(arg); 828 if (token != NULL) { 829 return token; 830 } 831 832 token = IdentifierToken::Tokenize(arg); 833 if (token != NULL) { 834 return token; 835 } 836 837 token = AddressToken::Tokenize(arg); 838 if (token != NULL) { 839 return token; 840 } 841 842 token = IntegerToken::Tokenize(arg); 843 if (token != NULL) { 844 return token; 845 } 846 847 return js_new<UnknownToken>(arg); 848 } 849 850 851 uint8_t* RegisterToken::ToAddress(Debugger* debugger) const { 852 VIXL_ASSERT(CanAddressMemory()); 853 uint64_t reg_value = debugger->xreg(value().code(), Reg31IsStackPointer); 854 uint8_t* address = NULL; 855 memcpy(&address, ®_value, sizeof(address)); 856 return address; 857 } 858 859 860 void RegisterToken::Print(FILE* out) const { 861 VIXL_ASSERT(value().IsValid()); 862 fprintf(out, "[Register %s]", Name()); 863 } 864 865 866 const char* RegisterToken::Name() const { 867 if (value().Is32Bits()) { 868 return kWAliases[value().code()][0]; 869 } else { 870 return kXAliases[value().code()][0]; 871 } 872 } 873 874 875 Token* RegisterToken::Tokenize(const char* arg) { 876 for (unsigned i = 0; i < kNumberOfRegisters; i++) { 877 // Is it a X register or alias? 878 for (const char** current = kXAliases[i]; *current != NULL; current++) { 879 if (strcmp(arg, *current) == 0) { 880 return js_new<RegisterToken>(XRegister(i)); 881 } 882 } 883 884 // Is it a W register or alias? 885 for (const char** current = kWAliases[i]; *current != NULL; current++) { 886 if (strcmp(arg, *current) == 0) { 887 return js_new<RegisterToken>(WRegister(i)); 888 } 889 } 890 } 891 892 return NULL; 893 } 894 895 896 void FPRegisterToken::Print(FILE* out) const { 897 VIXL_ASSERT(value().IsValid()); 898 char prefix = value().Is32Bits() ? 's' : 'd'; 899 fprintf(out, "[FPRegister %c%" PRIu32 "]", prefix, value().code()); 900 } 901 902 903 Token* FPRegisterToken::Tokenize(const char* arg) { 904 if (strlen(arg) < 2) { 905 return NULL; 906 } 907 908 switch (*arg) { 909 case 's': 910 case 'd': 911 const char* cursor = arg + 1; 912 uint64_t code = 0; 913 if (!StringToUInt64(&code, cursor)) { 914 return NULL; 915 } 916 917 if (code > kNumberOfFPRegisters) { 918 return NULL; 919 } 920 921 VRegister fpreg = NoVReg; 922 switch (*arg) { 923 case 's': 924 fpreg = SRegister(static_cast<unsigned>(code)); 925 break; 926 case 'd': 927 fpreg = DRegister(static_cast<unsigned>(code)); 928 break; 929 default: VIXL_UNREACHABLE(); 930 } 931 932 return js_new<FPRegisterToken>(fpreg); 933 } 934 935 return NULL; 936 } 937 938 939 uint8_t* IdentifierToken::ToAddress(Debugger* debugger) const { 940 VIXL_ASSERT(CanAddressMemory()); 941 const Instruction* pc_value = debugger->pc(); 942 uint8_t* address = NULL; 943 memcpy(&address, &pc_value, sizeof(address)); 944 return address; 945 } 946 947 void IdentifierToken::Print(FILE* out) const { 948 fprintf(out, "[Identifier %s]", value()); 949 } 950 951 952 Token* IdentifierToken::Tokenize(const char* arg) { 953 if (!isalpha(arg[0])) { 954 return NULL; 955 } 956 957 const char* cursor = arg + 1; 958 while ((*cursor != '\0') && isalnum(*cursor)) { 959 ++cursor; 960 } 961 962 if (*cursor == '\0') { 963 return js_new<IdentifierToken>(arg); 964 } 965 966 return NULL; 967 } 968 969 970 uint8_t* AddressToken::ToAddress(Debugger* debugger) const { 971 USE(debugger); 972 return value(); 973 } 974 975 976 void AddressToken::Print(FILE* out) const { 977 fprintf(out, "[Address %p]", value()); 978 } 979 980 981 Token* AddressToken::Tokenize(const char* arg) { 982 if ((strlen(arg) < 3) || (arg[0] != '0') || (arg[1] != 'x')) { 983 return NULL; 984 } 985 986 uint64_t ptr = 0; 987 if (!StringToUInt64(&ptr, arg, 16)) { 988 return NULL; 989 } 990 991 uint8_t* address = reinterpret_cast<uint8_t*>(ptr); 992 return js_new<AddressToken>(address); 993 } 994 995 996 void IntegerToken::Print(FILE* out) const { 997 fprintf(out, "[Integer %" PRId64 "]", value()); 998 } 999 1000 1001 Token* IntegerToken::Tokenize(const char* arg) { 1002 int64_t value = 0; 1003 if (!StringToInt64(&value, arg)) { 1004 return NULL; 1005 } 1006 1007 return js_new<IntegerToken>(value); 1008 } 1009 1010 1011 Token* FormatToken::Tokenize(const char* arg) { 1012 size_t length = strlen(arg); 1013 switch (arg[0]) { 1014 case 'x': 1015 case 's': 1016 case 'u': 1017 case 'f': 1018 if (length == 1) return NULL; 1019 break; 1020 case 'i': 1021 if (length == 1) return js_new<Format<uint32_t>>("%08" PRIx32, 'i'); 1022 VIXL_FALLTHROUGH(); 1023 default: return NULL; 1024 } 1025 1026 char* endptr = NULL; 1027 errno = 0; // Reset errors. 1028 uint64_t count = strtoul(arg + 1, &endptr, 10); 1029 1030 if (errno != 0) { 1031 // Overflow, etc. 1032 return NULL; 1033 } 1034 1035 if (endptr == arg) { 1036 // No digits were parsed. 1037 return NULL; 1038 } 1039 1040 if (*endptr != '\0') { 1041 // There are unexpected (non-digit) characters after the number. 1042 return NULL; 1043 } 1044 1045 switch (arg[0]) { 1046 case 'x': 1047 switch (count) { 1048 case 8: return js_new<Format<uint8_t>>("%02" PRIx8, 'x'); 1049 case 16: return js_new<Format<uint16_t>>("%04" PRIx16, 'x'); 1050 case 32: return js_new<Format<uint32_t>>("%08" PRIx32, 'x'); 1051 case 64: return js_new<Format<uint64_t>>("%016" PRIx64, 'x'); 1052 default: return NULL; 1053 } 1054 case 's': 1055 switch (count) { 1056 case 8: return js_new<Format<int8_t>>("%4" PRId8, 's'); 1057 case 16: return js_new<Format<int16_t>>("%6" PRId16, 's'); 1058 case 32: return js_new<Format<int32_t>>("%11" PRId32, 's'); 1059 case 64: return js_new<Format<int64_t>>("%20" PRId64, 's'); 1060 default: return NULL; 1061 } 1062 case 'u': 1063 switch (count) { 1064 case 8: return js_new<Format<uint8_t>>("%3" PRIu8, 'u'); 1065 case 16: return js_new<Format<uint16_t>>("%5" PRIu16, 'u'); 1066 case 32: return js_new<Format<uint32_t>>("%10" PRIu32, 'u'); 1067 case 64: return js_new<Format<uint64_t>>("%20" PRIu64, 'u'); 1068 default: return NULL; 1069 } 1070 case 'f': 1071 switch (count) { 1072 case 32: return js_new<Format<float>>("%13g", 'f'); 1073 case 64: return js_new<Format<double>>("%13g", 'f'); 1074 default: return NULL; 1075 } 1076 default: 1077 VIXL_UNREACHABLE(); 1078 return NULL; 1079 } 1080 } 1081 1082 1083 template<typename T> 1084 void Format<T>::Print(FILE* out) const { 1085 unsigned size = sizeof(T) * 8; 1086 fprintf(out, "[Format %c%u - %s]", type_code_, size, fmt_); 1087 } 1088 1089 1090 void UnknownToken::Print(FILE* out) const { 1091 fprintf(out, "[Unknown %s]", unknown_); 1092 } 1093 1094 1095 void DebugCommand::Print(FILE* out) { 1096 fprintf(out, "%s", name()); 1097 } 1098 1099 1100 bool DebugCommand::Match(const char* name, const char** aliases) { 1101 for (const char** current = aliases; *current != NULL; current++) { 1102 if (strcmp(name, *current) == 0) { 1103 return true; 1104 } 1105 } 1106 1107 return false; 1108 } 1109 1110 1111 DebugCommand* DebugCommand::Parse(char* line) { 1112 TokenVector args; 1113 1114 for (char* chunk = strtok(line, " \t"); 1115 chunk != NULL; 1116 chunk = strtok(NULL, " \t")) { 1117 char* dot = strchr(chunk, '.'); 1118 if (dot != NULL) { 1119 // 'Token.format'. 1120 Token* format = FormatToken::Tokenize(dot + 1); 1121 if (format != NULL) { 1122 *dot = '\0'; 1123 (void)args.append(Token::Tokenize(chunk)); 1124 (void)args.append(format); 1125 } else { 1126 // Error while parsing the format, push the UnknownToken so an error 1127 // can be accurately reported. 1128 (void)args.append(Token::Tokenize(chunk)); 1129 } 1130 } else { 1131 (void)args.append(Token::Tokenize(chunk)); 1132 } 1133 } 1134 1135 if (args.empty()) { 1136 return NULL; 1137 } 1138 1139 if (!args[0]->IsIdentifier()) { 1140 return js_new<InvalidCommand>(std::move(args), 0, "command name is not valid"); 1141 } 1142 1143 const char* name = IdentifierToken::Cast(args[0])->value(); 1144 #define RETURN_IF_MATCH(Command) \ 1145 if (Match(name, Command::kAliases)) { \ 1146 return Command::Build(std::move(args)); \ 1147 } 1148 DEBUG_COMMAND_LIST(RETURN_IF_MATCH); 1149 #undef RETURN_IF_MATCH 1150 1151 return js_new<UnknownCommand>(std::move(args)); 1152 } 1153 1154 1155 void DebugCommand::PrintHelp(const char** aliases, 1156 const char* args, 1157 const char* help) { 1158 VIXL_ASSERT(aliases[0] != NULL); 1159 VIXL_ASSERT(help != NULL); 1160 1161 printf("\n----\n\n"); 1162 for (const char** current = aliases; *current != NULL; current++) { 1163 if (args != NULL) { 1164 printf("%s %s\n", *current, args); 1165 } else { 1166 printf("%s\n", *current); 1167 } 1168 } 1169 printf("\n%s\n", help); 1170 } 1171 1172 1173 bool HelpCommand::Run(Debugger* debugger) { 1174 VIXL_ASSERT(debugger->IsDebuggerRunning()); 1175 USE(debugger); 1176 1177 #define PRINT_HELP(Command) \ 1178 DebugCommand::PrintHelp(Command::kAliases, \ 1179 Command::kArguments, \ 1180 Command::kHelp); 1181 DEBUG_COMMAND_LIST(PRINT_HELP); 1182 #undef PRINT_HELP 1183 printf("\n----\n\n"); 1184 1185 return false; 1186 } 1187 1188 1189 DebugCommand* HelpCommand::Build(TokenVector&& args) { 1190 if (args.length() != 1) { 1191 return js_new<InvalidCommand>(std::move(args), -1, "too many arguments"); 1192 } 1193 1194 return js_new<HelpCommand>(args[0]); 1195 } 1196 1197 1198 bool ContinueCommand::Run(Debugger* debugger) { 1199 VIXL_ASSERT(debugger->IsDebuggerRunning()); 1200 1201 debugger->set_debug_parameters(debugger->debug_parameters() & ~DBG_ACTIVE); 1202 return true; 1203 } 1204 1205 1206 DebugCommand* ContinueCommand::Build(TokenVector&& args) { 1207 if (args.length() != 1) { 1208 return js_new<InvalidCommand>(std::move(args), -1, "too many arguments"); 1209 } 1210 1211 return js_new<ContinueCommand>(args[0]); 1212 } 1213 1214 1215 bool StepCommand::Run(Debugger* debugger) { 1216 VIXL_ASSERT(debugger->IsDebuggerRunning()); 1217 1218 int64_t steps = count(); 1219 if (steps < 0) { 1220 printf(" ** invalid value for steps: %" PRId64 " (<0) **\n", steps); 1221 } else if (steps > 1) { 1222 debugger->set_steps(steps - 1); 1223 } 1224 1225 return true; 1226 } 1227 1228 1229 void StepCommand::Print(FILE* out) { 1230 fprintf(out, "%s %" PRId64 "", name(), count()); 1231 } 1232 1233 1234 DebugCommand* StepCommand::Build(TokenVector&& args) { 1235 IntegerToken* count = NULL; 1236 switch (args.length()) { 1237 case 1: { // step [1] 1238 count = js_new<IntegerToken>(1); 1239 break; 1240 } 1241 case 2: { // step n 1242 Token* first = args[1]; 1243 if (!first->IsInteger()) { 1244 return js_new<InvalidCommand>(std::move(args), 1, "expects int"); 1245 } 1246 count = IntegerToken::Cast(first); 1247 break; 1248 } 1249 default: 1250 return js_new<InvalidCommand>(std::move(args), -1, "too many arguments"); 1251 } 1252 1253 return js_new<StepCommand>(args[0], count); 1254 } 1255 1256 1257 DebugCommand* DisasmCommand::Build(TokenVector&& args) { 1258 IntegerToken* count = NULL; 1259 switch (args.length()) { 1260 case 1: { // disasm [10] 1261 count = js_new<IntegerToken>(10); 1262 break; 1263 } 1264 case 2: { // disasm n 1265 Token* first = args[1]; 1266 if (!first->IsInteger()) { 1267 return js_new<InvalidCommand>(std::move(args), 1, "expects int"); 1268 } 1269 1270 count = IntegerToken::Cast(first); 1271 break; 1272 } 1273 default: 1274 return js_new<InvalidCommand>(std::move(args), -1, "too many arguments"); 1275 } 1276 1277 Token* target = js_new<IdentifierToken>("pc"); 1278 FormatToken* format = js_new<Format<uint32_t>>("%08" PRIx32, 'i'); 1279 return js_new<ExamineCommand>(args[0], target, format, count); 1280 } 1281 1282 1283 void PrintCommand::Print(FILE* out) { 1284 fprintf(out, "%s ", name()); 1285 target()->Print(out); 1286 if (format() != NULL) format()->Print(out); 1287 } 1288 1289 1290 bool PrintCommand::Run(Debugger* debugger) { 1291 VIXL_ASSERT(debugger->IsDebuggerRunning()); 1292 1293 Token* tok = target(); 1294 if (tok->IsIdentifier()) { 1295 char* identifier = IdentifierToken::Cast(tok)->value(); 1296 if (strcmp(identifier, "regs") == 0) { 1297 debugger->PrintRegisters(); 1298 } else if (strcmp(identifier, "fpregs") == 0) { 1299 debugger->PrintVRegisters(); 1300 } else if (strcmp(identifier, "sysregs") == 0) { 1301 debugger->PrintSystemRegisters(); 1302 } else if (strcmp(identifier, "pc") == 0) { 1303 printf("pc = %16p\n", reinterpret_cast<const void*>(debugger->pc())); 1304 } else { 1305 printf(" ** Unknown identifier to print: %s **\n", identifier); 1306 } 1307 1308 return false; 1309 } 1310 1311 FormatToken* format_tok = format(); 1312 VIXL_ASSERT(format_tok != NULL); 1313 if (format_tok->type_code() == 'i') { 1314 // TODO(all): Add support for instruction disassembly. 1315 printf(" ** unsupported format: instructions **\n"); 1316 return false; 1317 } 1318 1319 if (tok->IsRegister()) { 1320 RegisterToken* reg_tok = RegisterToken::Cast(tok); 1321 Register reg = reg_tok->value(); 1322 debugger->PrintRegister(reg, reg_tok->Name(), format_tok); 1323 return false; 1324 } 1325 1326 if (tok->IsFPRegister()) { 1327 FPRegister fpreg = FPRegisterToken::Cast(tok)->value(); 1328 debugger->PrintFPRegister(fpreg, format_tok); 1329 return false; 1330 } 1331 1332 VIXL_UNREACHABLE(); 1333 return false; 1334 } 1335 1336 1337 DebugCommand* PrintCommand::Build(TokenVector&& args) { 1338 if (args.length() < 2) { 1339 return js_new<InvalidCommand>(std::move(args), -1, "too few arguments"); 1340 } 1341 1342 Token* target = args[1]; 1343 if (!target->IsRegister() && 1344 !target->IsFPRegister() && 1345 !target->IsIdentifier()) { 1346 return js_new<InvalidCommand>(std::move(args), 1, "expects reg or identifier"); 1347 } 1348 1349 FormatToken* format = NULL; 1350 int target_size = 0; 1351 if (target->IsRegister()) { 1352 Register reg = RegisterToken::Cast(target)->value(); 1353 target_size = reg.SizeInBytes(); 1354 } else if (target->IsFPRegister()) { 1355 FPRegister fpreg = FPRegisterToken::Cast(target)->value(); 1356 target_size = fpreg.SizeInBytes(); 1357 } 1358 // If the target is an identifier there must be no format. This is checked 1359 // in the switch statement below. 1360 1361 switch (args.length()) { 1362 case 2: { 1363 if (target->IsRegister()) { 1364 switch (target_size) { 1365 case 4: format = js_new<Format<uint32_t>>("%08" PRIx32, 'x'); break; 1366 case 8: format = js_new<Format<uint64_t>>("%016" PRIx64, 'x'); break; 1367 default: VIXL_UNREACHABLE(); 1368 } 1369 } else if (target->IsFPRegister()) { 1370 switch (target_size) { 1371 case 4: format = js_new<Format<float>>("%8g", 'f'); break; 1372 case 8: format = js_new<Format<double>>("%8g", 'f'); break; 1373 default: VIXL_UNREACHABLE(); 1374 } 1375 } 1376 break; 1377 } 1378 case 3: { 1379 if (target->IsIdentifier()) { 1380 return js_new<InvalidCommand>(std::move(args), 2, 1381 "format is only allowed with registers"); 1382 } 1383 1384 Token* second = args[2]; 1385 if (!second->IsFormat()) { 1386 return js_new<InvalidCommand>(std::move(args), 2, "expects format"); 1387 } 1388 format = FormatToken::Cast(second); 1389 1390 if (format->SizeOf() > target_size) { 1391 return js_new<InvalidCommand>(std::move(args), 2, "format too wide"); 1392 } 1393 1394 break; 1395 } 1396 default: 1397 return js_new<InvalidCommand>(std::move(args), -1, "too many arguments"); 1398 } 1399 1400 return js_new<PrintCommand>(args[0], target, format); 1401 } 1402 1403 1404 bool ExamineCommand::Run(Debugger* debugger) { 1405 VIXL_ASSERT(debugger->IsDebuggerRunning()); 1406 1407 uint8_t* address = target()->ToAddress(debugger); 1408 int64_t amount = count()->value(); 1409 if (format()->type_code() == 'i') { 1410 debugger->PrintInstructions(address, amount); 1411 } else { 1412 debugger->PrintMemory(address, format(), amount); 1413 } 1414 1415 return false; 1416 } 1417 1418 1419 void ExamineCommand::Print(FILE* out) { 1420 fprintf(out, "%s ", name()); 1421 format()->Print(out); 1422 target()->Print(out); 1423 } 1424 1425 1426 DebugCommand* ExamineCommand::Build(TokenVector&& args) { 1427 if (args.length() < 2) { 1428 return js_new<InvalidCommand>(std::move(args), -1, "too few arguments"); 1429 } 1430 1431 Token* target = args[1]; 1432 if (!target->CanAddressMemory()) { 1433 return js_new<InvalidCommand>(std::move(args), 1, "expects address"); 1434 } 1435 1436 FormatToken* format = NULL; 1437 IntegerToken* count = NULL; 1438 1439 switch (args.length()) { 1440 case 2: { // mem addr[.x64] [10] 1441 format = js_new<Format<uint64_t>>("%016" PRIx64, 'x'); 1442 count = js_new<IntegerToken>(10); 1443 break; 1444 } 1445 case 3: { // mem addr.format [10] 1446 // mem addr[.x64] n 1447 Token* second = args[2]; 1448 if (second->IsFormat()) { 1449 format = FormatToken::Cast(second); 1450 count = js_new<IntegerToken>(10); 1451 break; 1452 } else if (second->IsInteger()) { 1453 format = js_new<Format<uint64_t>>("%016" PRIx64, 'x'); 1454 count = IntegerToken::Cast(second); 1455 } else { 1456 return js_new<InvalidCommand>(std::move(args), 2, "expects format or integer"); 1457 } 1458 VIXL_UNREACHABLE(); 1459 break; 1460 } 1461 case 4: { // mem addr.format n 1462 Token* second = args[2]; 1463 Token* third = args[3]; 1464 if (!second->IsFormat() || !third->IsInteger()) { 1465 return js_new<InvalidCommand>(std::move(args), -1, "expects addr[.format] [n]"); 1466 } 1467 format = FormatToken::Cast(second); 1468 count = IntegerToken::Cast(third); 1469 break; 1470 } 1471 default: 1472 return js_new<InvalidCommand>(std::move(args), -1, "too many arguments"); 1473 } 1474 1475 return js_new<ExamineCommand>(args[0], target, format, count); 1476 } 1477 1478 1479 UnknownCommand::~UnknownCommand() { 1480 const size_t size = args_.length(); 1481 for (size_t i = 0; i < size; ++i) { 1482 js_delete(args_[i]); 1483 } 1484 } 1485 1486 1487 bool UnknownCommand::Run(Debugger* debugger) { 1488 VIXL_ASSERT(debugger->IsDebuggerRunning()); 1489 USE(debugger); 1490 1491 printf(" ** Unknown Command:"); 1492 const size_t size = args_.length(); 1493 for (size_t i = 0; i < size; ++i) { 1494 printf(" "); 1495 args_[i]->Print(stdout); 1496 } 1497 printf(" **\n"); 1498 1499 return false; 1500 } 1501 1502 1503 InvalidCommand::~InvalidCommand() { 1504 const size_t size = args_.length(); 1505 for (size_t i = 0; i < size; ++i) { 1506 js_delete(args_[i]); 1507 } 1508 } 1509 1510 1511 bool InvalidCommand::Run(Debugger* debugger) { 1512 VIXL_ASSERT(debugger->IsDebuggerRunning()); 1513 USE(debugger); 1514 1515 printf(" ** Invalid Command:"); 1516 const size_t size = args_.length(); 1517 for (size_t i = 0; i < size; ++i) { 1518 printf(" "); 1519 if (i == static_cast<size_t>(index_)) { 1520 printf(">>"); 1521 args_[i]->Print(stdout); 1522 printf("<<"); 1523 } else { 1524 args_[i]->Print(stdout); 1525 } 1526 } 1527 printf(" **\n"); 1528 printf(" ** %s\n", cause_); 1529 1530 return false; 1531 } 1532 1533 } // namespace vixl 1534 1535 #endif // JS_SIMULATOR_ARM64