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, ®_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