// 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; }
BufferOffset Assembler::DataProcShiftedRegister(const Register& rd, const Register& rn, const Operand& operand, FlagsUpdate S, Instr op) { VIXL_ASSERT(operand.IsShiftedRegister()); VIXL_ASSERT(rn.Is64Bits() || (rn.Is32Bits() && is_uint5(operand.shift_amount()))); return Emit(SF(rd) | op | Flags(S) | ShiftDP(operand.shift()) | ImmDPShift(operand.shift_amount()) | Rm(operand.reg()) | Rn(rn) | Rd(rd)); }
void MozBaseAssembler::WritePoolHeader(uint8_t* start, js::jit::Pool* p, bool isNatural) { JS_STATIC_ASSERT(sizeof(PoolHeader) == 4); // Get the total size of the pool. const uintptr_t totalPoolSize = sizeof(PoolHeader) + p->getPoolSize(); const uintptr_t totalPoolInstructions = totalPoolSize / sizeof(Instruction); VIXL_ASSERT((totalPoolSize & 0x3) == 0); VIXL_ASSERT(totalPoolInstructions < (1 << 15)); PoolHeader header(totalPoolInstructions, isNatural); *(PoolHeader*)start = header; }
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, ®_value, sizeof(address)); return address; }
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); }
ptrdiff_t Assembler::LinkAndGetOffsetTo(BufferOffset branch, Label* label) { if (armbuffer_.oom()) return js::jit::LabelBase::INVALID_OFFSET; if (label->bound()) { // The label is bound: all uses are already linked. ptrdiff_t branch_offset = ptrdiff_t(branch.getOffset() / element_size); ptrdiff_t label_offset = ptrdiff_t(label->offset() / element_size); return label_offset - branch_offset; } if (!label->used()) { // The label is unbound and unused: store the offset in the label itself // for patching by bind(). label->use(branch.getOffset()); return js::jit::LabelBase::INVALID_OFFSET; } // The label is unbound but used. Create an implicit linked list between // the branches, and update the linked list head in the label struct. ptrdiff_t prevHeadOffset = static_cast<ptrdiff_t>(label->offset()); label->use(branch.getOffset()); VIXL_ASSERT(prevHeadOffset - branch.getOffset() != js::jit::LabelBase::INVALID_OFFSET); return prevHeadOffset - branch.getOffset(); }
void MozBaseAssembler::WritePoolGuard(BufferOffset branch, Instruction* inst, BufferOffset dest) { int byteOffset = dest.getOffset() - branch.getOffset(); VIXL_ASSERT(byteOffset % kInstructionSize == 0); int instOffset = byteOffset >> kInstructionSizeLog2; Assembler::b(inst, instOffset); }
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 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); }
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->PrintFPRegisters(); } 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; }
void Assembler::adrp(const Register& rd, Label* label) { VIXL_ASSERT(AllowPageOffsetDependentCode()); // Flush the instruction buffer if necessary before getting an offset. BufferOffset offset = Emit(0); Instruction* ins = getInstructionAt(offset); // Encode the relative offset. adrp(ins, rd, LinkAndGetPageOffsetTo(offset, label)); }
BufferOffset Assembler::b(Label* label, Condition cond) { // Flush the instruction buffer if necessary before getting an offset. BufferOffset branch = b(0, Always); Instruction* ins = getInstructionAt(branch); VIXL_ASSERT(ins->IsCondBranchImm()); // Encode the relative offset. b(ins, LinkAndGetInstructionOffsetTo(branch, label), cond); return branch; }
unsigned CountClearHalfWords(uint64_t imm, unsigned reg_size) { VIXL_ASSERT((reg_size % 8) == 0); int count = 0; for (unsigned i = 0; i < (reg_size / 16); i++) { if ((imm & 0xffff) == 0) { count++; } imm >>= 16; } return count; }
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; }
BufferOffset Assembler::Logical(const Register& rd, const Register& rn, const Operand& operand, LogicalOp op) { VIXL_ASSERT(rd.size() == rn.size()); if (operand.IsImmediate()) { int64_t immediate = operand.immediate(); unsigned reg_size = rd.size(); VIXL_ASSERT(immediate != 0); VIXL_ASSERT(immediate != -1); VIXL_ASSERT(rd.Is64Bits() || is_uint32(immediate)); // If the operation is NOT, invert the operation and immediate. if ((op & NOT) == NOT) { op = static_cast<LogicalOp>(op & ~NOT); immediate = rd.Is64Bits() ? ~immediate : (~immediate & kWRegMask); } unsigned n, imm_s, imm_r; if (IsImmLogical(immediate, reg_size, &n, &imm_s, &imm_r)) { // Immediate can be encoded in the instruction. return LogicalImmediate(rd, rn, n, imm_s, imm_r, op); } else { // This case is handled in the macro assembler. VIXL_UNREACHABLE(); } } else { VIXL_ASSERT(operand.IsShiftedRegister()); VIXL_ASSERT(operand.reg().size() == rd.size()); Instr dp_op = static_cast<Instr>(op | LogicalShiftedFixed); return DataProcShiftedRegister(rd, rn, operand, LeaveFlags, dp_op); } }
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 Simulator::ResetState() { // Reset the system registers. nzcv_ = SimSystemRegister::DefaultValueFor(NZCV); fpcr_ = SimSystemRegister::DefaultValueFor(FPCR); // Reset registers to 0. pc_ = NULL; pc_modified_ = false; for (unsigned i = 0; i < kNumberOfRegisters; i++) { set_xreg(i, 0xbadbeef); } // Set FP registers to a value that is a NaN in both 32-bit and 64-bit FP. uint64_t nan_bits = UINT64_C(0x7ff0dead7f8beef1); VIXL_ASSERT(IsSignallingNaN(rawbits_to_double(nan_bits & kDRegMask))); VIXL_ASSERT(IsSignallingNaN(rawbits_to_float(nan_bits & kSRegMask))); for (unsigned i = 0; i < kNumberOfFPRegisters; i++) { set_dreg_bits(i, nan_bits); } // Returning to address 0 exits the Simulator. set_lr(kEndOfSimAddress); set_resume_pc(nullptr); }
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; }
bool UnknownCommand::Run(Debugger* debugger) { VIXL_ASSERT(debugger->IsDebuggerRunning()); USE(debugger); printf(" ** Unknown Command:"); const int size = args_.size(); for (int i = 0; i < size; ++i) { printf(" "); args_[i]->Print(stdout); } printf(" **\n"); return false; }
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"); }
bool InvalidCommand::Run(Debugger* debugger) { VIXL_ASSERT(debugger->IsDebuggerRunning()); USE(debugger); printf(" ** Invalid Command:"); const int size = args_.size(); for (int i = 0; i < size; ++i) { printf(" "); if (i == index_) { printf(">>"); args_[i]->Print(stdout); printf("<<"); } else { args_[i]->Print(stdout); } } printf(" **\n"); printf(" ** %s\n", cause_); return false; }
void Debugger::PrintFPRegister(const FPRegister& target_fpreg, const FormatToken* format) { const uint64_t 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 = fpreg<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"); }
Header(uint32_t data) : data(data) { JS_STATIC_ASSERT(sizeof(Header) == sizeof(uint32_t)); VIXL_ASSERT(ONES == 0xffff); }
static RegisterToken* Cast(Token* tok) { VIXL_ASSERT(tok->IsRegister()); return reinterpret_cast<RegisterToken*>(tok); }
void FPRegisterToken::Print(FILE* out) const { VIXL_ASSERT(value().IsValid()); char prefix = value().Is32Bits() ? 's' : 'd'; fprintf(out, "[FPRegister %c%" PRIu32 "]", prefix, value().code()); }
void RegisterToken::Print(FILE* out) const { VIXL_ASSERT(value().IsValid()); fprintf(out, "[Register %s]", Name()); }
bool ContinueCommand::Run(Debugger* debugger) { VIXL_ASSERT(debugger->IsDebuggerRunning()); debugger->set_debug_parameters(debugger->debug_parameters() & ~DBG_ACTIVE); return true; }
static FormatToken* Cast(Token* tok) { VIXL_ASSERT(tok->IsFormat()); return reinterpret_cast<FormatToken*>(tok); }
static IntegerToken* Cast(Token* tok) { VIXL_ASSERT(tok->IsInteger()); return reinterpret_cast<IntegerToken*>(tok); }
static AddressToken* Cast(Token* tok) { VIXL_ASSERT(tok->IsAddress()); return reinterpret_cast<AddressToken*>(tok); }