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