// Copyright 2014, ARM Limited
// All rights reserved.
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are met:
//
//   * Redistributions of source code must retain the above copyright notice,
//     this list of conditions and the following disclaimer.
//   * Redistributions in binary form must reproduce the above copyright notice,
//     this list of conditions and the following disclaimer in the documentation
//     and/or other materials provided with the distribution.
//   * Neither the name of ARM Limited nor the names of its contributors may be
//     used to endorse or promote products derived from this software without
//     specific prior written permission.
//
// THIS SOFTWARE IS PROVIDED BY ARM LIMITED AND CONTRIBUTORS "AS IS" AND ANY
// EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
// WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
// DISCLAIMED. IN NO EVENT SHALL ARM LIMITED BE LIABLE FOR ANY DIRECT, INDIRECT,
// INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA,
// OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
// LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
// NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
// EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.

#include "js-config.h"

#ifdef JS_SIMULATOR_ARM64

#include "jit/arm64/vixl/Debugger-vixl.h"

#include "mozilla/Unused.h"
#include "mozilla/Vector.h"

#include "js/AllocPolicy.h"

namespace vixl {

// List of commands supported by the debugger.
#define DEBUG_COMMAND_LIST(C)  \
C(HelpCommand)                 \
C(ContinueCommand)             \
C(StepCommand)                 \
C(DisasmCommand)               \
C(PrintCommand)                \
C(ExamineCommand)

// Debugger command lines are broken up in token of different type to make
// processing easier later on.
class Token {
 public:
  virtual ~Token() {}

  // Token type.
  virtual bool IsRegister() const { return false; }
  virtual bool IsFPRegister() const { return false; }
  virtual bool IsIdentifier() const { return false; }
  virtual bool IsAddress() const { return false; }
  virtual bool IsInteger() const { return false; }
  virtual bool IsFormat() const { return false; }
  virtual bool IsUnknown() const { return false; }
  // Token properties.
  virtual bool CanAddressMemory() const { return false; }
  virtual uint8_t* ToAddress(Debugger* debugger) const = 0;
  virtual void Print(FILE* out = stdout) const = 0;

  static Token* Tokenize(const char* arg);
};

typedef mozilla::Vector<Token*, 0, js::SystemAllocPolicy> TokenVector;

// Tokens often hold one value.
template<typename T> class ValueToken : public Token {
 public:
  explicit ValueToken(T value) : value_(value) {}
  ValueToken() {}

  T value() const { return value_; }

  virtual uint8_t* ToAddress(Debugger* debugger) const override {
    USE(debugger);
    VIXL_ABORT();
  }

 protected:
  T value_;
};

// Integer registers (X or W) and their aliases.
// Format: wn or xn with 0 <= n < 32 or a name in the aliases list.
class RegisterToken : public ValueToken<const Register> {
 public:
  explicit RegisterToken(const Register reg)
      : ValueToken<const Register>(reg) {}

  virtual bool IsRegister() const override { return true; }
  virtual bool CanAddressMemory() const override { return value().Is64Bits(); }
  virtual uint8_t* ToAddress(Debugger* debugger) const override;
  virtual void Print(FILE* out = stdout) const override;
  const char* Name() const;

  static Token* Tokenize(const char* arg);
  static RegisterToken* Cast(Token* tok) {
    VIXL_ASSERT(tok->IsRegister());
    return reinterpret_cast<RegisterToken*>(tok);
  }

 private:
  static const int kMaxAliasNumber = 4;
  static const char* kXAliases[kNumberOfRegisters][kMaxAliasNumber];
  static const char* kWAliases[kNumberOfRegisters][kMaxAliasNumber];
};

// Floating point registers (D or S).
// Format: sn or dn with 0 <= n < 32.
class FPRegisterToken : public ValueToken<const FPRegister> {
 public:
  explicit FPRegisterToken(const FPRegister fpreg)
      : ValueToken<const FPRegister>(fpreg) {}

  virtual bool IsFPRegister() const override { return true; }
  virtual void Print(FILE* out = stdout) const override;

  static Token* Tokenize(const char* arg);
  static FPRegisterToken* Cast(Token* tok) {
    VIXL_ASSERT(tok->IsFPRegister());
    return reinterpret_cast<FPRegisterToken*>(tok);
  }
};


// Non-register identifiers.
// Format: Alphanumeric string starting with a letter.
class IdentifierToken : public ValueToken<char*> {
 public:
  explicit IdentifierToken(const char* name) {
    size_t size = strlen(name) + 1;
    value_ = js_pod_malloc<char>(size);
    strncpy(value_, name, size);
  }
  virtual ~IdentifierToken() { js_free(value_); }

  virtual bool IsIdentifier() const override { return true; }
  virtual bool CanAddressMemory() const override { return strcmp(value(), "pc") == 0; }
  virtual uint8_t* ToAddress(Debugger* debugger) const override;
  virtual void Print(FILE* out = stdout) const override;

  static Token* Tokenize(const char* arg);
  static IdentifierToken* Cast(Token* tok) {
    VIXL_ASSERT(tok->IsIdentifier());
    return reinterpret_cast<IdentifierToken*>(tok);
  }
};

// 64-bit address literal.
// Format: 0x... with up to 16 hexadecimal digits.
class AddressToken : public ValueToken<uint8_t*> {
 public:
  explicit AddressToken(uint8_t* address) : ValueToken<uint8_t*>(address) {}

  virtual bool IsAddress() const override { return true; }
  virtual bool CanAddressMemory() const override { return true; }
  virtual uint8_t* ToAddress(Debugger* debugger) const override;
  virtual void Print(FILE* out = stdout) const override;

  static Token* Tokenize(const char* arg);
  static AddressToken* Cast(Token* tok) {
    VIXL_ASSERT(tok->IsAddress());
    return reinterpret_cast<AddressToken*>(tok);
  }
};


// 64-bit decimal integer literal.
// Format: n.
class IntegerToken : public ValueToken<int64_t> {
 public:
  explicit IntegerToken(int64_t value) : ValueToken<int64_t>(value) {}

  virtual bool IsInteger() const override { return true; }
  virtual void Print(FILE* out = stdout) const override;

  static Token* Tokenize(const char* arg);
  static IntegerToken* Cast(Token* tok) {
    VIXL_ASSERT(tok->IsInteger());
    return reinterpret_cast<IntegerToken*>(tok);
  }
};

// Literal describing how to print a chunk of data (up to 64 bits).
// Format: .ln
// where l (letter) is one of
//  * x: hexadecimal
//  * s: signed integer
//  * u: unsigned integer
//  * f: floating point
//  * i: instruction
// and n (size) is one of 8, 16, 32 and 64. n should be omitted for
// instructions.
class FormatToken : public Token {
 public:
  FormatToken() {}

  virtual bool IsFormat() const override { return true; }
  virtual int SizeOf() const = 0;
  virtual char type_code() const = 0;
  virtual void PrintData(void* data, FILE* out = stdout) const = 0;
  virtual void Print(FILE* out = stdout) const override = 0;

  virtual uint8_t* ToAddress(Debugger* debugger) const override {
    USE(debugger);
    VIXL_ABORT();
  }

  static Token* Tokenize(const char* arg);
  static FormatToken* Cast(Token* tok) {
    VIXL_ASSERT(tok->IsFormat());
    return reinterpret_cast<FormatToken*>(tok);
  }
};


template<typename T> class Format : public FormatToken {
 public:
  Format(const char* fmt, char type_code) : fmt_(fmt), type_code_(type_code) {}

  virtual int SizeOf() const override { return sizeof(T); }
  virtual char type_code() const override { return type_code_; }
  virtual void PrintData(void* data, FILE* out = stdout) const override {
    T value;
    memcpy(&value, data, sizeof(value));
    fprintf(out, fmt_, value);
  }
  virtual void Print(FILE* out = stdout) const override;

 private:
  const char* fmt_;
  char type_code_;
};

// Tokens which don't fit any of the above.
class UnknownToken : public Token {
 public:
  explicit UnknownToken(const char* arg) {
    size_t size = strlen(arg) + 1;
    unknown_ = js_pod_malloc<char>(size);
    strncpy(unknown_, arg, size);
  }
  virtual ~UnknownToken() { js_free(unknown_); }
  virtual uint8_t* ToAddress(Debugger* debugger) const override {
    USE(debugger);
    VIXL_ABORT();
  }

  virtual bool IsUnknown() const override { return true; }
  virtual void Print(FILE* out = stdout) const override;

 private:
  char* unknown_;
};


// All debugger commands must subclass DebugCommand and implement Run, Print
// and Build. Commands must also define kHelp and kAliases.
class DebugCommand {
 public:
  explicit DebugCommand(Token* name) : name_(IdentifierToken::Cast(name)) {}
  DebugCommand() : name_(NULL) {}
  virtual ~DebugCommand() { js_delete(name_); }

  const char* name() { return name_->value(); }
  // Run the command on the given debugger. The command returns true if
  // execution should move to the next instruction.
  virtual bool Run(Debugger * debugger) = 0;
  virtual void Print(FILE* out = stdout);

  static bool Match(const char* name, const char** aliases);
  static DebugCommand* Parse(char* line);
  static void PrintHelp(const char** aliases,
                        const char* args,
                        const char* help);

 private:
  IdentifierToken* name_;
};

// For all commands below see their respective kHelp and kAliases in
// debugger-a64.cc
class HelpCommand : public DebugCommand {
 public:
  explicit HelpCommand(Token* name) : DebugCommand(name) {}

  virtual bool Run(Debugger* debugger) override;

  static DebugCommand* Build(TokenVector&& args);

  static const char* kHelp;
  static const char* kAliases[];
  static const char* kArguments;
};


class ContinueCommand : public DebugCommand {
 public:
  explicit ContinueCommand(Token* name) : DebugCommand(name) {}

  virtual bool Run(Debugger* debugger) override;

  static DebugCommand* Build(TokenVector&& args);

  static const char* kHelp;
  static const char* kAliases[];
  static const char* kArguments;
};


class StepCommand : public DebugCommand {
 public:
  StepCommand(Token* name, IntegerToken* count)
      : DebugCommand(name), count_(count) {}
  virtual ~StepCommand() { js_delete(count_); }

  int64_t count() { return count_->value(); }
  virtual bool Run(Debugger* debugger) override;
  virtual void Print(FILE* out = stdout) override;

  static DebugCommand* Build(TokenVector&& args);

  static const char* kHelp;
  static const char* kAliases[];
  static const char* kArguments;

 private:
  IntegerToken* count_;
};

class DisasmCommand : public DebugCommand {
 public:
  static DebugCommand* Build(TokenVector&& args);

  static const char* kHelp;
  static const char* kAliases[];
  static const char* kArguments;
};


class PrintCommand : public DebugCommand {
 public:
  PrintCommand(Token* name, Token* target, FormatToken* format)
      : DebugCommand(name), target_(target), format_(format) {}
  virtual ~PrintCommand() {
    js_delete(target_);
    js_delete(format_);
  }

  Token* target() { return target_; }
  FormatToken* format() { return format_; }
  virtual bool Run(Debugger* debugger) override;
  virtual void Print(FILE* out = stdout) override;

  static DebugCommand* Build(TokenVector&& args);

  static const char* kHelp;
  static const char* kAliases[];
  static const char* kArguments;

 private:
  Token* target_;
  FormatToken* format_;
};

class ExamineCommand : public DebugCommand {
 public:
  ExamineCommand(Token* name,
                 Token* target,
                 FormatToken* format,
                 IntegerToken* count)
      : DebugCommand(name), target_(target), format_(format), count_(count) {}
  virtual ~ExamineCommand() {
    js_delete(target_);
    js_delete(format_);
    js_delete(count_);
  }

  Token* target() { return target_; }
  FormatToken* format() { return format_; }
  IntegerToken* count() { return count_; }
  virtual bool Run(Debugger* debugger) override;
  virtual void Print(FILE* out = stdout) override;

  static DebugCommand* Build(TokenVector&& args);

  static const char* kHelp;
  static const char* kAliases[];
  static const char* kArguments;

 private:
  Token* target_;
  FormatToken* format_;
  IntegerToken* count_;
};

// Commands which name does not match any of the known commnand.
class UnknownCommand : public DebugCommand {
 public:
  explicit UnknownCommand(TokenVector&& args) : args_(std::move(args)) {}
  virtual ~UnknownCommand();

  virtual bool Run(Debugger* debugger) override;

 private:
  TokenVector args_;
};

// Commands which name match a known command but the syntax is invalid.
class InvalidCommand : public DebugCommand {
 public:
  InvalidCommand(TokenVector&& args, int index, const char* cause)
      : args_(std::move(args)), index_(index), cause_(cause) {}
  virtual ~InvalidCommand();

  virtual bool Run(Debugger* debugger) override;

 private:
  TokenVector args_;
  int index_;
  const char* cause_;
};

const char* HelpCommand::kAliases[] = { "help", NULL };
const char* HelpCommand::kArguments = NULL;
const char* HelpCommand::kHelp = "  Print this help.";

const char* ContinueCommand::kAliases[] = { "continue", "c", NULL };
const char* ContinueCommand::kArguments = NULL;
const char* ContinueCommand::kHelp = "  Resume execution.";

const char* StepCommand::kAliases[] = { "stepi", "si", NULL };
const char* StepCommand::kArguments = "[n = 1]";
const char* StepCommand::kHelp = "  Execute n next instruction(s).";

const char* DisasmCommand::kAliases[] = { "disasm", "di", NULL };
const char* DisasmCommand::kArguments = "[n = 10]";
const char* DisasmCommand::kHelp =
  "  Disassemble n instruction(s) at pc.\n"
  "  This command is equivalent to x pc.i [n = 10]."
;

const char* PrintCommand::kAliases[] = { "print", "p", NULL };
const char* PrintCommand::kArguments =  "<entity>[.format]";
const char* PrintCommand::kHelp =
  "  Print the given entity according to the given format.\n"
  "  The format parameter only affects individual registers; it is ignored\n"
  "  for other entities.\n"
  "  <entity> can be one of the following:\n"
  "   * A register name (such as x0, s1, ...).\n"
  "   * 'regs', to print all integer (W and X) registers.\n"
  "   * 'fpregs' to print all floating-point (S and D) registers.\n"
  "   * 'sysregs' to print all system registers (including NZCV).\n"
  "   * 'pc' to print the current program counter.\n"
;

const char* ExamineCommand::kAliases[] = { "m", "mem", "x", NULL };
const char* ExamineCommand::kArguments = "<addr>[.format] [n = 10]";
const char* ExamineCommand::kHelp =
  "  Examine memory. Print n items of memory at address <addr> according to\n"
  "  the given [.format].\n"
  "  Addr can be an immediate address, a register name or pc.\n"
  "  Format is made of a type letter: 'x' (hexadecimal), 's' (signed), 'u'\n"
  "  (unsigned), 'f' (floating point), i (instruction) and a size in bits\n"
  "  when appropriate (8, 16, 32, 64)\n"
  "  E.g 'x sp.x64' will print 10 64-bit words from the stack in\n"
  "  hexadecimal format."
;

const char* RegisterToken::kXAliases[kNumberOfRegisters][kMaxAliasNumber] = {
  { "x0", NULL },
  { "x1", NULL },
  { "x2", NULL },
  { "x3", NULL },
  { "x4", NULL },
  { "x5", NULL },
  { "x6", NULL },
  { "x7", NULL },
  { "x8", NULL },
  { "x9", NULL },
  { "x10", NULL },
  { "x11", NULL },
  { "x12", NULL },
  { "x13", NULL },
  { "x14", NULL },
  { "x15", NULL },
  { "ip0", "x16", NULL },
  { "ip1", "x17", NULL },
  { "x18", "pr", NULL },
  { "x19", NULL },
  { "x20", NULL },
  { "x21", NULL },
  { "x22", NULL },
  { "x23", NULL },
  { "x24", NULL },
  { "x25", NULL },
  { "x26", NULL },
  { "x27", NULL },
  { "x28", NULL },
  { "fp", "x29", NULL },
  { "lr", "x30", NULL },
  { "sp", NULL}
};

const char* RegisterToken::kWAliases[kNumberOfRegisters][kMaxAliasNumber] = {
  { "w0", NULL },
  { "w1", NULL },
  { "w2", NULL },
  { "w3", NULL },
  { "w4", NULL },
  { "w5", NULL },
  { "w6", NULL },
  { "w7", NULL },
  { "w8", NULL },
  { "w9", NULL },
  { "w10", NULL },
  { "w11", NULL },
  { "w12", NULL },
  { "w13", NULL },
  { "w14", NULL },
  { "w15", NULL },
  { "w16", NULL },
  { "w17", NULL },
  { "w18", NULL },
  { "w19", NULL },
  { "w20", NULL },
  { "w21", NULL },
  { "w22", NULL },
  { "w23", NULL },
  { "w24", NULL },
  { "w25", NULL },
  { "w26", NULL },
  { "w27", NULL },
  { "w28", NULL },
  { "w29", NULL },
  { "w30", NULL },
  { "wsp", NULL }
};


Debugger::Debugger(Decoder* decoder, FILE* stream)
    : Simulator(decoder, stream),
      debug_parameters_(DBG_INACTIVE),
      pending_request_(false),
      steps_(0),
      last_command_(NULL) {
  disasm_ = js_new<PrintDisassembler>(stdout);
  printer_ = js_new<Decoder>();
  printer_->AppendVisitor(disasm_);
}


Debugger::~Debugger() {
  js_delete(disasm_);
  js_delete(printer_);
}


void Debugger::Run() {
  pc_modified_ = false;
  while (pc_ != kEndOfSimAddress) {
    if (pending_request()) RunDebuggerShell();
    ExecuteInstruction();
    LogAllWrittenRegisters();
  }
}


void Debugger::PrintInstructions(const void* address, int64_t count) {
  if (count == 0) {
    return;
  }

  const Instruction* from = Instruction::CastConst(address);
  if (count < 0) {
    count = -count;
    from -= (count - 1) * kInstructionSize;
  }
  const Instruction* to = from + count * kInstructionSize;

  for (const Instruction* current = from;
       current < to;
       current = current->NextInstruction()) {
    printer_->Decode(current);
  }
}


void Debugger::PrintMemory(const uint8_t* address,
                           const FormatToken* format,
                           int64_t count) {
  if (count == 0) {
    return;
  }

  const uint8_t* from = address;
  int size = format->SizeOf();
  if (count < 0) {
    count = -count;
    from -= (count - 1) * size;
  }
  const uint8_t* to = from + count * size;

  for (const uint8_t* current = from; current < to; current += size) {
    if (((current - from) % 8) == 0) {
      printf("\n%p: ", current);
    }

    uint64_t data = Memory::Read<uint64_t>(current);
    format->PrintData(&data);
    printf(" ");
  }
  printf("\n\n");
}


void Debugger::PrintRegister(const Register& target_reg,
                             const char* name,
                             const FormatToken* format) {
  const uint64_t reg_size = target_reg.size();
  const uint64_t format_size = format->SizeOf() * 8;
  const uint64_t count = reg_size / format_size;
  const uint64_t mask = 0xffffffffffffffff >> (64 - format_size);
  const uint64_t reg_value = reg<uint64_t>(target_reg.code(),
                                           Reg31IsStackPointer);
  VIXL_ASSERT(count > 0);

  printf("%s = ", name);
  for (uint64_t i = 1; i <= count; i++) {
    uint64_t data = reg_value >> (reg_size - (i * format_size));
    data &= mask;
    format->PrintData(&data);
    printf(" ");
  }
  printf("\n");
}


// TODO(all): fix this for vector registers.
void Debugger::PrintFPRegister(const FPRegister& target_fpreg,
                               const FormatToken* format) {
  const unsigned fpreg_size = target_fpreg.size();
  const uint64_t format_size = format->SizeOf() * 8;
  const uint64_t count = fpreg_size / format_size;
  const uint64_t mask = 0xffffffffffffffff >> (64 - format_size);
  const uint64_t fpreg_value = vreg<uint64_t>(fpreg_size, target_fpreg.code());
  VIXL_ASSERT(count > 0);

  if (target_fpreg.Is32Bits()) {
    printf("s%u = ", target_fpreg.code());
  } else {
    printf("d%u = ", target_fpreg.code());
  }
  for (uint64_t i = 1; i <= count; i++) {
    uint64_t data = fpreg_value >> (fpreg_size - (i * format_size));
    data &= mask;
    format->PrintData(&data);
    printf(" ");
  }
  printf("\n");
}


void Debugger::VisitException(const Instruction* instr) {
  switch (instr->Mask(ExceptionMask)) {
    case BRK:
      DoBreakpoint(instr);
      return;
    case HLT:
      VIXL_FALLTHROUGH();
    default: Simulator::VisitException(instr);
  }
}


// Read a command. A command will be at most kMaxDebugShellLine char long and
// ends with '\n\0'.
// TODO: Should this be a utility function?
char* Debugger::ReadCommandLine(const char* prompt, char* buffer, int length) {
  int fgets_calls = 0;
  char* end = NULL;

  printf("%s", prompt);
  fflush(stdout);

  do {
    if (fgets(buffer, length, stdin) == NULL) {
      printf(" ** Error while reading command. **\n");
      return NULL;
    }

    fgets_calls++;
    end = strchr(buffer, '\n');
  } while (end == NULL);

  if (fgets_calls != 1) {
    printf(" ** Command too long. **\n");
    return NULL;
  }

  // Remove the newline from the end of the command.
  VIXL_ASSERT(end[1] == '\0');
  VIXL_ASSERT((end - buffer) < (length - 1));
  end[0] = '\0';

  return buffer;
}


void Debugger::RunDebuggerShell() {
  if (IsDebuggerRunning()) {
    if (steps_ > 0) {
      // Finish stepping first.
      --steps_;
      return;
    }

    printf("Next: ");
    PrintInstructions(pc());
    bool done = false;
    while (!done) {
      char buffer[kMaxDebugShellLine];
      char* line = ReadCommandLine("vixl> ", buffer, kMaxDebugShellLine);

      if (line == NULL) continue;  // An error occurred.

      DebugCommand* command = DebugCommand::Parse(line);
      if (command != NULL) {
        last_command_ = command;
      }

      if (last_command_ != NULL) {
        done = last_command_->Run(this);
      } else {
        printf("No previous command to run!\n");
      }
    }

    if ((debug_parameters_ & DBG_BREAK) != 0) {
      // The break request has now been handled, move to next instruction.
      debug_parameters_ &= ~DBG_BREAK;
      increment_pc();
    }
  }
}


void Debugger::DoBreakpoint(const Instruction* instr) {
  VIXL_ASSERT(instr->Mask(ExceptionMask) == BRK);

  printf("Hit breakpoint at pc=%p.\n", reinterpret_cast<const void*>(instr));
  set_debug_parameters(debug_parameters() | DBG_BREAK | DBG_ACTIVE);
  // Make the shell point to the brk instruction.
  set_pc(instr);
}


static bool StringToUInt64(uint64_t* value, const char* line, int base = 10) {
  char* endptr = NULL;
  errno = 0;  // Reset errors.
  uint64_t parsed = strtoul(line, &endptr, base);

  if (errno == ERANGE) {
    // Overflow.
    return false;
  }

  if (endptr == line) {
    // No digits were parsed.
    return false;
  }

  if (*endptr != '\0') {
    // Non-digit characters present at the end.
    return false;
  }

  *value = parsed;
  return true;
}


static bool StringToInt64(int64_t* value, const char* line, int base = 10) {
  char* endptr = NULL;
  errno = 0;  // Reset errors.
  int64_t parsed = strtol(line, &endptr, base);

  if (errno == ERANGE) {
    // Overflow, undeflow.
    return false;
  }

  if (endptr == line) {
    // No digits were parsed.
    return false;
  }

  if (*endptr != '\0') {
    // Non-digit characters present at the end.
    return false;
  }

  *value = parsed;
  return true;
}


Token* Token::Tokenize(const char* arg) {
  if ((arg == NULL) || (*arg == '\0')) {
    return NULL;
  }

  // The order is important. For example Identifier::Tokenize would consider
  // any register to be a valid identifier.

  Token* token = RegisterToken::Tokenize(arg);
  if (token != NULL) {
    return token;
  }

  token = FPRegisterToken::Tokenize(arg);
  if (token != NULL) {
    return token;
  }

  token = IdentifierToken::Tokenize(arg);
  if (token != NULL) {
    return token;
  }

  token = AddressToken::Tokenize(arg);
  if (token != NULL) {
    return token;
  }

  token = IntegerToken::Tokenize(arg);
  if (token != NULL) {
    return token;
  }

  return js_new<UnknownToken>(arg);
}


uint8_t* RegisterToken::ToAddress(Debugger* debugger) const {
  VIXL_ASSERT(CanAddressMemory());
  uint64_t reg_value = debugger->xreg(value().code(), Reg31IsStackPointer);
  uint8_t* address = NULL;
  memcpy(&address, &reg_value, sizeof(address));
  return address;
}


void RegisterToken::Print(FILE* out) const {
  VIXL_ASSERT(value().IsValid());
  fprintf(out, "[Register %s]", Name());
}


const char* RegisterToken::Name() const {
  if (value().Is32Bits()) {
    return kWAliases[value().code()][0];
  } else {
    return kXAliases[value().code()][0];
  }
}


Token* RegisterToken::Tokenize(const char* arg) {
  for (unsigned i = 0; i < kNumberOfRegisters; i++) {
    // Is it a X register or alias?
    for (const char** current = kXAliases[i]; *current != NULL; current++) {
      if (strcmp(arg, *current) == 0) {
        return js_new<RegisterToken>(Register::XRegFromCode(i));
      }
    }

    // Is it a W register or alias?
    for (const char** current = kWAliases[i]; *current != NULL; current++) {
      if (strcmp(arg, *current) == 0) {
        return js_new<RegisterToken>(Register::WRegFromCode(i));
      }
    }
  }

  return NULL;
}


void FPRegisterToken::Print(FILE* out) const {
  VIXL_ASSERT(value().IsValid());
  char prefix = value().Is32Bits() ? 's' : 'd';
  fprintf(out, "[FPRegister %c%" PRIu32 "]", prefix, value().code());
}


Token* FPRegisterToken::Tokenize(const char* arg) {
  if (strlen(arg) < 2) {
    return NULL;
  }

  switch (*arg) {
    case 's':
    case 'd':
      const char* cursor = arg + 1;
      uint64_t code = 0;
      if (!StringToUInt64(&code, cursor)) {
        return NULL;
      }

      if (code > kNumberOfFPRegisters) {
        return NULL;
      }

      VRegister fpreg = NoVReg;
      switch (*arg) {
        case 's':
          fpreg = VRegister::SRegFromCode(static_cast<unsigned>(code));
          break;
        case 'd':
          fpreg = VRegister::DRegFromCode(static_cast<unsigned>(code));
          break;
        default: VIXL_UNREACHABLE();
      }

      return js_new<FPRegisterToken>(fpreg);
  }

  return NULL;
}


uint8_t* IdentifierToken::ToAddress(Debugger* debugger) const {
  VIXL_ASSERT(CanAddressMemory());
  const Instruction* pc_value = debugger->pc();
  uint8_t* address = NULL;
  memcpy(&address, &pc_value, sizeof(address));
  return address;
}

void IdentifierToken::Print(FILE* out) const {
  fprintf(out, "[Identifier %s]", value());
}


Token* IdentifierToken::Tokenize(const char* arg) {
  if (!isalpha(arg[0])) {
    return NULL;
  }

  const char* cursor = arg + 1;
  while ((*cursor != '\0') && isalnum(*cursor)) {
    ++cursor;
  }

  if (*cursor == '\0') {
    return js_new<IdentifierToken>(arg);
  }

  return NULL;
}


uint8_t* AddressToken::ToAddress(Debugger* debugger) const {
  USE(debugger);
  return value();
}


void AddressToken::Print(FILE* out) const {
  fprintf(out, "[Address %p]", value());
}


Token* AddressToken::Tokenize(const char* arg) {
  if ((strlen(arg) < 3) || (arg[0] != '0') || (arg[1] != 'x')) {
    return NULL;
  }

  uint64_t ptr = 0;
  if (!StringToUInt64(&ptr, arg, 16)) {
    return NULL;
  }

  uint8_t* address = reinterpret_cast<uint8_t*>(ptr);
  return js_new<AddressToken>(address);
}


void IntegerToken::Print(FILE* out) const {
  fprintf(out, "[Integer %" PRId64 "]", value());
}


Token* IntegerToken::Tokenize(const char* arg) {
  int64_t value = 0;
  if (!StringToInt64(&value, arg)) {
    return NULL;
  }

  return js_new<IntegerToken>(value);
}


Token* FormatToken::Tokenize(const char* arg) {
  size_t length = strlen(arg);
  switch (arg[0]) {
    case 'x':
    case 's':
    case 'u':
    case 'f':
      if (length == 1) return NULL;
      break;
    case 'i':
      if (length == 1) return js_new<Format<uint32_t>>("%08" PRIx32, 'i');
      VIXL_FALLTHROUGH();
    default: return NULL;
  }

  char* endptr = NULL;
  errno = 0;  // Reset errors.
  uint64_t count = strtoul(arg + 1, &endptr, 10);

  if (errno != 0) {
    // Overflow, etc.
    return NULL;
  }

  if (endptr == arg) {
    // No digits were parsed.
    return NULL;
  }

  if (*endptr != '\0') {
    // There are unexpected (non-digit) characters after the number.
    return NULL;
  }

  switch (arg[0]) {
    case 'x':
      switch (count) {
        case 8: return js_new<Format<uint8_t>>("%02" PRIx8, 'x');
        case 16: return js_new<Format<uint16_t>>("%04" PRIx16, 'x');
        case 32: return js_new<Format<uint32_t>>("%08" PRIx32, 'x');
        case 64: return js_new<Format<uint64_t>>("%016" PRIx64, 'x');
        default: return NULL;
      }
    case 's':
      switch (count) {
        case 8: return js_new<Format<int8_t>>("%4" PRId8, 's');
        case 16: return js_new<Format<int16_t>>("%6" PRId16, 's');
        case 32: return js_new<Format<int32_t>>("%11" PRId32, 's');
        case 64: return js_new<Format<int64_t>>("%20" PRId64, 's');
        default: return NULL;
      }
    case 'u':
      switch (count) {
        case 8: return js_new<Format<uint8_t>>("%3" PRIu8, 'u');
        case 16: return js_new<Format<uint16_t>>("%5" PRIu16, 'u');
        case 32: return js_new<Format<uint32_t>>("%10" PRIu32, 'u');
        case 64: return js_new<Format<uint64_t>>("%20" PRIu64, 'u');
        default: return NULL;
      }
    case 'f':
      switch (count) {
        case 32: return js_new<Format<float>>("%13g", 'f');
        case 64: return js_new<Format<double>>("%13g", 'f');
        default: return NULL;
      }
    default:
      VIXL_UNREACHABLE();
      return NULL;
  }
}


template<typename T>
void Format<T>::Print(FILE* out) const {
  unsigned size = sizeof(T) * 8;
  fprintf(out, "[Format %c%u - %s]", type_code_, size, fmt_);
}


void UnknownToken::Print(FILE* out) const {
  fprintf(out, "[Unknown %s]", unknown_);
}


void DebugCommand::Print(FILE* out) {
  fprintf(out, "%s", name());
}


bool DebugCommand::Match(const char* name, const char** aliases) {
  for (const char** current = aliases; *current != NULL; current++) {
    if (strcmp(name, *current) == 0) {
       return true;
    }
  }

  return false;
}


DebugCommand* DebugCommand::Parse(char* line) {
  using mozilla::Unused;
  TokenVector args;

  for (char* chunk = strtok(line, " \t");
       chunk != NULL;
       chunk = strtok(NULL, " \t")) {
    char* dot = strchr(chunk, '.');
    if (dot != NULL) {
      // 'Token.format'.
      Token* format = FormatToken::Tokenize(dot + 1);
      if (format != NULL) {
        *dot = '\0';
        Unused << args.append(Token::Tokenize(chunk));
        Unused << args.append(format);
      } else {
        // Error while parsing the format, push the UnknownToken so an error
        // can be accurately reported.
        Unused << args.append(Token::Tokenize(chunk));
      }
    } else {
      Unused << args.append(Token::Tokenize(chunk));
    }
  }

  if (args.empty()) {
    return NULL;
  }

  if (!args[0]->IsIdentifier()) {
    return js_new<InvalidCommand>(std::move(args), 0, "command name is not valid");
  }

  const char* name = IdentifierToken::Cast(args[0])->value();
  #define RETURN_IF_MATCH(Command)       \
  if (Match(name, Command::kAliases)) {  \
    return Command::Build(std::move(args));   \
  }
  DEBUG_COMMAND_LIST(RETURN_IF_MATCH);
  #undef RETURN_IF_MATCH

  return js_new<UnknownCommand>(std::move(args));
}


void DebugCommand::PrintHelp(const char** aliases,
                             const char* args,
                             const char* help) {
  VIXL_ASSERT(aliases[0] != NULL);
  VIXL_ASSERT(help != NULL);

  printf("\n----\n\n");
  for (const char** current = aliases; *current != NULL; current++) {
    if (args != NULL) {
      printf("%s %s\n", *current, args);
    } else {
      printf("%s\n", *current);
    }
  }
  printf("\n%s\n", help);
}


bool HelpCommand::Run(Debugger* debugger) {
  VIXL_ASSERT(debugger->IsDebuggerRunning());
  USE(debugger);

  #define PRINT_HELP(Command)                     \
    DebugCommand::PrintHelp(Command::kAliases,    \
                            Command::kArguments,  \
                            Command::kHelp);
  DEBUG_COMMAND_LIST(PRINT_HELP);
  #undef PRINT_HELP
  printf("\n----\n\n");

  return false;
}


DebugCommand* HelpCommand::Build(TokenVector&& args) {
  if (args.length() != 1) {
    return js_new<InvalidCommand>(std::move(args), -1, "too many arguments");
  }

  return js_new<HelpCommand>(args[0]);
}


bool ContinueCommand::Run(Debugger* debugger) {
  VIXL_ASSERT(debugger->IsDebuggerRunning());

  debugger->set_debug_parameters(debugger->debug_parameters() & ~DBG_ACTIVE);
  return true;
}


DebugCommand* ContinueCommand::Build(TokenVector&& args) {
  if (args.length() != 1) {
    return js_new<InvalidCommand>(std::move(args), -1, "too many arguments");
  }

  return js_new<ContinueCommand>(args[0]);
}


bool StepCommand::Run(Debugger* debugger) {
  VIXL_ASSERT(debugger->IsDebuggerRunning());

  int64_t steps = count();
  if (steps < 0) {
    printf(" ** invalid value for steps: %" PRId64 " (<0) **\n", steps);
  } else if (steps > 1) {
    debugger->set_steps(steps - 1);
  }

  return true;
}


void StepCommand::Print(FILE* out) {
  fprintf(out, "%s %" PRId64 "", name(), count());
}


DebugCommand* StepCommand::Build(TokenVector&& args) {
  IntegerToken* count = NULL;
  switch (args.length()) {
    case 1: {  // step [1]
      count = js_new<IntegerToken>(1);
      break;
    }
    case 2: {  // step n
      Token* first = args[1];
      if (!first->IsInteger()) {
        return js_new<InvalidCommand>(std::move(args), 1, "expects int");
      }
      count = IntegerToken::Cast(first);
      break;
    }
    default:
      return js_new<InvalidCommand>(std::move(args), -1, "too many arguments");
  }

  return js_new<StepCommand>(args[0], count);
}


DebugCommand* DisasmCommand::Build(TokenVector&& args) {
  IntegerToken* count = NULL;
  switch (args.length()) {
    case 1: {  // disasm [10]
      count = js_new<IntegerToken>(10);
      break;
    }
    case 2: {  // disasm n
      Token* first = args[1];
      if (!first->IsInteger()) {
        return js_new<InvalidCommand>(std::move(args), 1, "expects int");
      }

      count = IntegerToken::Cast(first);
      break;
    }
    default:
      return js_new<InvalidCommand>(std::move(args), -1, "too many arguments");
  }

  Token* target = js_new<IdentifierToken>("pc");
  FormatToken* format = js_new<Format<uint32_t>>("%08" PRIx32, 'i');
  return js_new<ExamineCommand>(args[0], target, format, count);
}


void PrintCommand::Print(FILE* out) {
  fprintf(out, "%s ", name());
  target()->Print(out);
  if (format() != NULL) format()->Print(out);
}


bool PrintCommand::Run(Debugger* debugger) {
  VIXL_ASSERT(debugger->IsDebuggerRunning());

  Token* tok = target();
  if (tok->IsIdentifier()) {
    char* identifier = IdentifierToken::Cast(tok)->value();
    if (strcmp(identifier, "regs") == 0) {
      debugger->PrintRegisters();
    } else if (strcmp(identifier, "fpregs") == 0) {
      debugger->PrintVRegisters();
    } else if (strcmp(identifier, "sysregs") == 0) {
      debugger->PrintSystemRegisters();
    } else if (strcmp(identifier, "pc") == 0) {
      printf("pc = %16p\n", reinterpret_cast<const void*>(debugger->pc()));
    } else {
      printf(" ** Unknown identifier to print: %s **\n", identifier);
    }

    return false;
  }

  FormatToken* format_tok = format();
  VIXL_ASSERT(format_tok != NULL);
  if (format_tok->type_code() == 'i') {
    // TODO(all): Add support for instruction disassembly.
    printf(" ** unsupported format: instructions **\n");
    return false;
  }

  if (tok->IsRegister()) {
    RegisterToken* reg_tok = RegisterToken::Cast(tok);
    Register reg = reg_tok->value();
    debugger->PrintRegister(reg, reg_tok->Name(), format_tok);
    return false;
  }

  if (tok->IsFPRegister()) {
    FPRegister fpreg = FPRegisterToken::Cast(tok)->value();
    debugger->PrintFPRegister(fpreg, format_tok);
    return false;
  }

  VIXL_UNREACHABLE();
  return false;
}


DebugCommand* PrintCommand::Build(TokenVector&& args) {
  if (args.length() < 2) {
    return js_new<InvalidCommand>(std::move(args), -1, "too few arguments");
  }

  Token* target = args[1];
  if (!target->IsRegister() &&
      !target->IsFPRegister() &&
      !target->IsIdentifier()) {
    return js_new<InvalidCommand>(std::move(args), 1, "expects reg or identifier");
  }

  FormatToken* format = NULL;
  int target_size = 0;
  if (target->IsRegister()) {
    Register reg = RegisterToken::Cast(target)->value();
    target_size = reg.SizeInBytes();
  } else if (target->IsFPRegister()) {
    FPRegister fpreg = FPRegisterToken::Cast(target)->value();
    target_size = fpreg.SizeInBytes();
  }
  // If the target is an identifier there must be no format. This is checked
  // in the switch statement below.

  switch (args.length()) {
    case 2: {
      if (target->IsRegister()) {
        switch (target_size) {
          case 4: format = js_new<Format<uint32_t>>("%08" PRIx32, 'x'); break;
          case 8: format = js_new<Format<uint64_t>>("%016" PRIx64, 'x'); break;
          default: VIXL_UNREACHABLE();
        }
      } else if (target->IsFPRegister()) {
        switch (target_size) {
          case 4: format = js_new<Format<float>>("%8g", 'f'); break;
          case 8: format = js_new<Format<double>>("%8g", 'f'); break;
          default: VIXL_UNREACHABLE();
        }
      }
      break;
    }
    case 3: {
      if (target->IsIdentifier()) {
        return js_new<InvalidCommand>(std::move(args), 2,
            "format is only allowed with registers");
      }

      Token* second = args[2];
      if (!second->IsFormat()) {
        return js_new<InvalidCommand>(std::move(args), 2, "expects format");
      }
      format = FormatToken::Cast(second);

      if (format->SizeOf() > target_size) {
        return js_new<InvalidCommand>(std::move(args), 2, "format too wide");
      }

      break;
    }
    default:
      return js_new<InvalidCommand>(std::move(args), -1, "too many arguments");
  }

  return js_new<PrintCommand>(args[0], target, format);
}


bool ExamineCommand::Run(Debugger* debugger) {
  VIXL_ASSERT(debugger->IsDebuggerRunning());

  uint8_t* address = target()->ToAddress(debugger);
  int64_t  amount = count()->value();
  if (format()->type_code() == 'i') {
    debugger->PrintInstructions(address, amount);
  } else {
    debugger->PrintMemory(address, format(), amount);
  }

  return false;
}


void ExamineCommand::Print(FILE* out) {
  fprintf(out, "%s ", name());
  format()->Print(out);
  target()->Print(out);
}


DebugCommand* ExamineCommand::Build(TokenVector&& args) {
  if (args.length() < 2) {
    return js_new<InvalidCommand>(std::move(args), -1, "too few arguments");
  }

  Token* target = args[1];
  if (!target->CanAddressMemory()) {
    return js_new<InvalidCommand>(std::move(args), 1, "expects address");
  }

  FormatToken* format = NULL;
  IntegerToken* count = NULL;

  switch (args.length()) {
    case 2: {  // mem addr[.x64] [10]
      format = js_new<Format<uint64_t>>("%016" PRIx64, 'x');
      count = js_new<IntegerToken>(10);
      break;
    }
    case 3: {  // mem addr.format [10]
               // mem addr[.x64] n
      Token* second = args[2];
      if (second->IsFormat()) {
        format = FormatToken::Cast(second);
        count = js_new<IntegerToken>(10);
        break;
      } else if (second->IsInteger()) {
        format = js_new<Format<uint64_t>>("%016" PRIx64, 'x');
        count = IntegerToken::Cast(second);
      } else {
        return js_new<InvalidCommand>(std::move(args), 2, "expects format or integer");
      }
      VIXL_UNREACHABLE();
      break;
    }
    case 4: {  // mem addr.format n
      Token* second = args[2];
      Token* third = args[3];
      if (!second->IsFormat() || !third->IsInteger()) {
        return js_new<InvalidCommand>(std::move(args), -1, "expects addr[.format] [n]");
      }
      format = FormatToken::Cast(second);
      count = IntegerToken::Cast(third);
      break;
    }
    default:
      return js_new<InvalidCommand>(std::move(args), -1, "too many arguments");
  }

  return js_new<ExamineCommand>(args[0], target, format, count);
}


UnknownCommand::~UnknownCommand() {
  const size_t size = args_.length();
  for (size_t i = 0; i < size; ++i) {
    js_delete(args_[i]);
  }
}


bool UnknownCommand::Run(Debugger* debugger) {
  VIXL_ASSERT(debugger->IsDebuggerRunning());
  USE(debugger);

  printf(" ** Unknown Command:");
  const size_t size = args_.length();
  for (size_t i = 0; i < size; ++i) {
    printf(" ");
    args_[i]->Print(stdout);
  }
  printf(" **\n");

  return false;
}


InvalidCommand::~InvalidCommand() {
  const size_t size = args_.length();
  for (size_t i = 0; i < size; ++i) {
    js_delete(args_[i]);
  }
}


bool InvalidCommand::Run(Debugger* debugger) {
  VIXL_ASSERT(debugger->IsDebuggerRunning());
  USE(debugger);

  printf(" ** Invalid Command:");
  const size_t size = args_.length();
  for (size_t i = 0; i < size; ++i) {
    printf(" ");
    if (i == static_cast<size_t>(index_)) {
      printf(">>");
      args_[i]->Print(stdout);
      printf("<<");
    } else {
      args_[i]->Print(stdout);
    }
  }
  printf(" **\n");
  printf(" ** %s\n", cause_);

  return false;
}

}  // namespace vixl

#endif  // JS_SIMULATOR_ARM64
