From 3dbb3c39d5b3550f992ea7d52a952113433eebb5 Mon Sep 17 00:00:00 2001 From: "Jacob.Bramley@arm.com" Date: Tue, 9 Sep 2014 12:43:43 +0000 Subject: [PATCH] Reland r23732: ARM64: Fix and improve --trace-sim register trace. - Use standard names (except that our GREY is the standard BLACK). - Make non-bold colours explicit, otherwise the boldness can carry over into subsequent colour declarations. - I've moved some colours around to make them consistent. Register value updates (which are very common) now stand out less than they did, making the less-common (and arguably more important) debug announcements appear brighter. - FP registers and values are now magenta. - Integer registers and values are now cyan. - Memory accesses are now blue. - LOG_WRITE prints the source register for stores. - Loads are logged with a format similar to that used for stores. Specifically, the memory address is printed alongside the new register value. - Updates to D registers print the raw bits as well as the double value. Updates to S registers print the raw bits as well as the float value. (Previously, we printed both double and float interpretations of the bits, which was a bit cluttered.) BUG= R=svenpanne@chromium.org Review URL: https://codereview.chromium.org/551823004 git-svn-id: https://v8.googlecode.com/svn/branches/bleeding_edge@23802 ce2b1a6d-e550-0410-aec6-3dcde31c8c00 --- src/arm64/disasm-arm64.cc | 4 +- src/arm64/instructions-arm64.h | 4 +- src/arm64/simulator-arm64.cc | 538 +++++++++++++++++++++++++++-------------- src/arm64/simulator-arm64.h | 151 +++++++++--- 4 files changed, 472 insertions(+), 225 deletions(-) diff --git a/src/arm64/disasm-arm64.cc b/src/arm64/disasm-arm64.cc index b8b1d5d..ac7cb37 100644 --- a/src/arm64/disasm-arm64.cc +++ b/src/arm64/disasm-arm64.cc @@ -1517,7 +1517,9 @@ int Disassembler::SubstituteLiteralField(Instruction* instr, case LDR_w_lit: case LDR_x_lit: case LDR_s_lit: - case LDR_d_lit: AppendToOutput("(addr %p)", instr->LiteralAddress()); break; + case LDR_d_lit: + AppendToOutput("(addr 0x%016" PRIxPTR ")", instr->LiteralAddress()); + break; default: UNREACHABLE(); } diff --git a/src/arm64/instructions-arm64.h b/src/arm64/instructions-arm64.h index bd4e753..9f3c20f 100644 --- a/src/arm64/instructions-arm64.h +++ b/src/arm64/instructions-arm64.h @@ -352,9 +352,9 @@ class Instruction { // Patch a literal load instruction to load from 'source'. void SetImmLLiteral(Instruction* source); - uint8_t* LiteralAddress() { + uintptr_t LiteralAddress() { int offset = ImmLLiteral() << kLoadLiteralScaleLog2; - return reinterpret_cast(this) + offset; + return reinterpret_cast(this) + offset; } enum CheckAlignment { NO_CHECK, CHECK_ALIGNMENT }; diff --git a/src/arm64/simulator-arm64.cc b/src/arm64/simulator-arm64.cc index 2e43dfc..277275c 100644 --- a/src/arm64/simulator-arm64.cc +++ b/src/arm64/simulator-arm64.cc @@ -30,30 +30,28 @@ namespace internal { // Helpers for colors. -// Depending on your terminal configuration, the colour names may not match the -// observed colours. -#define COLOUR(colour_code) "\033[" colour_code "m" -#define BOLD(colour_code) "1;" colour_code -#define NORMAL "" -#define GREY "30" -#define GREEN "32" -#define ORANGE "33" -#define BLUE "34" -#define PURPLE "35" -#define INDIGO "36" -#define WHITE "37" +#define COLOUR(colour_code) "\033[0;" colour_code "m" +#define COLOUR_BOLD(colour_code) "\033[1;" colour_code "m" +#define NORMAL "" +#define GREY "30" +#define RED "31" +#define GREEN "32" +#define YELLOW "33" +#define BLUE "34" +#define MAGENTA "35" +#define CYAN "36" +#define WHITE "37" typedef char const * const TEXT_COLOUR; TEXT_COLOUR clr_normal = FLAG_log_colour ? COLOUR(NORMAL) : ""; -TEXT_COLOUR clr_flag_name = FLAG_log_colour ? COLOUR(BOLD(GREY)) : ""; -TEXT_COLOUR clr_flag_value = FLAG_log_colour ? COLOUR(BOLD(WHITE)) : ""; -TEXT_COLOUR clr_reg_name = FLAG_log_colour ? COLOUR(BOLD(BLUE)) : ""; -TEXT_COLOUR clr_reg_value = FLAG_log_colour ? COLOUR(BOLD(INDIGO)) : ""; -TEXT_COLOUR clr_fpreg_name = FLAG_log_colour ? COLOUR(BOLD(ORANGE)) : ""; -TEXT_COLOUR clr_fpreg_value = FLAG_log_colour ? COLOUR(BOLD(PURPLE)) : ""; -TEXT_COLOUR clr_memory_value = FLAG_log_colour ? COLOUR(BOLD(GREEN)) : ""; -TEXT_COLOUR clr_memory_address = FLAG_log_colour ? COLOUR(GREEN) : ""; -TEXT_COLOUR clr_debug_number = FLAG_log_colour ? COLOUR(BOLD(ORANGE)) : ""; -TEXT_COLOUR clr_debug_message = FLAG_log_colour ? COLOUR(ORANGE) : ""; +TEXT_COLOUR clr_flag_name = FLAG_log_colour ? COLOUR_BOLD(WHITE) : ""; +TEXT_COLOUR clr_flag_value = FLAG_log_colour ? COLOUR(NORMAL) : ""; +TEXT_COLOUR clr_reg_name = FLAG_log_colour ? COLOUR_BOLD(CYAN) : ""; +TEXT_COLOUR clr_reg_value = FLAG_log_colour ? COLOUR(CYAN) : ""; +TEXT_COLOUR clr_fpreg_name = FLAG_log_colour ? COLOUR_BOLD(MAGENTA) : ""; +TEXT_COLOUR clr_fpreg_value = FLAG_log_colour ? COLOUR(MAGENTA) : ""; +TEXT_COLOUR clr_memory_address = FLAG_log_colour ? COLOUR_BOLD(BLUE) : ""; +TEXT_COLOUR clr_debug_number = FLAG_log_colour ? COLOUR_BOLD(YELLOW) : ""; +TEXT_COLOUR clr_debug_message = FLAG_log_colour ? COLOUR(YELLOW) : ""; TEXT_COLOUR clr_printf = FLAG_log_colour ? COLOUR(GREEN) : ""; @@ -337,7 +335,7 @@ uintptr_t Simulator::PopAddress() { uintptr_t Simulator::StackLimit() const { // Leave a safety margin of 1024 bytes to prevent overrunning the stack when // pushing values. - return reinterpret_cast(stack_limit_) + 1024; + return stack_limit_ + 1024; } @@ -380,11 +378,11 @@ void Simulator::Init(FILE* stream) { // Allocate and setup the simulator stack. stack_size_ = (FLAG_sim_stack_size * KB) + (2 * stack_protection_size_); - stack_ = new byte[stack_size_]; + stack_ = reinterpret_cast(new byte[stack_size_]); stack_limit_ = stack_ + stack_protection_size_; - byte* tos = stack_ + stack_size_ - stack_protection_size_; - // The stack pointer must be 16 bytes aligned. - set_sp(reinterpret_cast(tos) & ~0xfUL); + uintptr_t tos = stack_ + stack_size_ - stack_protection_size_; + // The stack pointer must be 16-byte aligned. + set_sp(tos & ~0xfUL); stream_ = stream; print_disasm_ = new PrintDisassembler(stream_); @@ -420,7 +418,7 @@ void Simulator::ResetState() { Simulator::~Simulator() { - delete[] stack_; + delete[] reinterpret_cast(stack_); if (FLAG_log_instruction_stats) { delete instrument_; } @@ -734,15 +732,15 @@ void* Simulator::RedirectExternalReference(void* external_function, const char* Simulator::xreg_names[] = { -"x0", "x1", "x2", "x3", "x4", "x5", "x6", "x7", -"x8", "x9", "x10", "x11", "x12", "x13", "x14", "x15", -"ip0", "ip1", "x18", "x19", "x20", "x21", "x22", "x23", -"x24", "x25", "x26", "cp", "jssp", "fp", "lr", "xzr", "csp"}; +"x0", "x1", "x2", "x3", "x4", "x5", "x6", "x7", +"x8", "x9", "x10", "x11", "x12", "x13", "x14", "x15", +"ip0", "ip1", "x18", "x19", "x20", "x21", "x22", "x23", +"x24", "x25", "x26", "cp", "jssp", "fp", "lr", "xzr", "csp"}; const char* Simulator::wreg_names[] = { -"w0", "w1", "w2", "w3", "w4", "w5", "w6", "w7", -"w8", "w9", "w10", "w11", "w12", "w13", "w14", "w15", -"w16", "w17", "w18", "w19", "w20", "w21", "w22", "w23", +"w0", "w1", "w2", "w3", "w4", "w5", "w6", "w7", +"w8", "w9", "w10", "w11", "w12", "w13", "w14", "w15", +"w16", "w17", "w18", "w19", "w20", "w21", "w22", "w23", "w24", "w25", "w26", "wcp", "wjssp", "wfp", "wlr", "wzr", "wcsp"}; const char* Simulator::sreg_names[] = { @@ -765,7 +763,12 @@ const char* Simulator::vreg_names[] = { const char* Simulator::WRegNameForCode(unsigned code, Reg31Mode mode) { + STATIC_ASSERT(arraysize(Simulator::wreg_names) == (kNumberOfRegisters + 1)); DCHECK(code < kNumberOfRegisters); + // The modulo operator has no effect here, but it silences a broken GCC + // warning about out-of-bounds array accesses. + code %= kNumberOfRegisters; + // If the code represents the stack pointer, index the name after zr. if ((code == kZeroRegCode) && (mode == Reg31IsStackPointer)) { code = kZeroRegCode + 1; @@ -775,7 +778,10 @@ const char* Simulator::WRegNameForCode(unsigned code, Reg31Mode mode) { const char* Simulator::XRegNameForCode(unsigned code, Reg31Mode mode) { + STATIC_ASSERT(arraysize(Simulator::xreg_names) == (kNumberOfRegisters + 1)); DCHECK(code < kNumberOfRegisters); + code %= kNumberOfRegisters; + // If the code represents the stack pointer, index the name after zr. if ((code == kZeroRegCode) && (mode == Reg31IsStackPointer)) { code = kZeroRegCode + 1; @@ -785,20 +791,23 @@ const char* Simulator::XRegNameForCode(unsigned code, Reg31Mode mode) { const char* Simulator::SRegNameForCode(unsigned code) { + STATIC_ASSERT(arraysize(Simulator::sreg_names) == kNumberOfFPRegisters); DCHECK(code < kNumberOfFPRegisters); - return sreg_names[code]; + return sreg_names[code % kNumberOfFPRegisters]; } const char* Simulator::DRegNameForCode(unsigned code) { + STATIC_ASSERT(arraysize(Simulator::dreg_names) == kNumberOfFPRegisters); DCHECK(code < kNumberOfFPRegisters); - return dreg_names[code]; + return dreg_names[code % kNumberOfFPRegisters]; } const char* Simulator::VRegNameForCode(unsigned code) { + STATIC_ASSERT(arraysize(Simulator::vreg_names) == kNumberOfFPRegisters); DCHECK(code < kNumberOfFPRegisters); - return vreg_names[code]; + return vreg_names[code % kNumberOfFPRegisters]; } @@ -855,6 +864,7 @@ T Simulator::AddWithCarry(bool set_flags, nzcv().SetZ(Z); nzcv().SetC(C); nzcv().SetV(V); + LogSystemRegister(NZCV); } return result; } @@ -978,6 +988,7 @@ void Simulator::FPCompare(double val0, double val1) { } else { UNREACHABLE(); } + LogSystemRegister(NZCV); } @@ -1044,117 +1055,206 @@ void Simulator::PrintInstructionsAt(Instruction* start, uint64_t count) { } -void Simulator::PrintSystemRegisters(bool print_all) { - static bool first_run = true; +void Simulator::PrintSystemRegisters() { + PrintSystemRegister(NZCV); + PrintSystemRegister(FPCR); +} + + +void Simulator::PrintRegisters() { + for (unsigned i = 0; i < kNumberOfRegisters; i++) { + PrintRegister(i); + } +} - static SimSystemRegister last_nzcv; - if (print_all || first_run || (last_nzcv.RawValue() != nzcv().RawValue())) { - fprintf(stream_, "# %sFLAGS: %sN:%d Z:%d C:%d V:%d%s\n", - clr_flag_name, - clr_flag_value, - nzcv().N(), nzcv().Z(), nzcv().C(), nzcv().V(), - clr_normal); + +void Simulator::PrintFPRegisters() { + for (unsigned i = 0; i < kNumberOfFPRegisters; i++) { + PrintFPRegister(i); } - last_nzcv = nzcv(); +} + - static SimSystemRegister last_fpcr; - if (print_all || first_run || (last_fpcr.RawValue() != fpcr().RawValue())) { - static const char * rmode[] = { - "0b00 (Round to Nearest)", - "0b01 (Round towards Plus Infinity)", - "0b10 (Round towards Minus Infinity)", - "0b11 (Round towards Zero)" - }; - DCHECK(fpcr().RMode() < arraysize(rmode)); - fprintf(stream_, "# %sFPCR: %sAHP:%d DN:%d FZ:%d RMode:%s%s\n", - clr_flag_name, - clr_flag_value, - fpcr().AHP(), fpcr().DN(), fpcr().FZ(), rmode[fpcr().RMode()], - clr_normal); +void Simulator::PrintRegister(unsigned code, Reg31Mode r31mode) { + // Don't print writes into xzr. + if ((code == kZeroRegCode) && (r31mode == Reg31IsZeroRegister)) { + return; } - last_fpcr = fpcr(); - first_run = false; + // The template is "# x:value". + fprintf(stream_, "# %s%5s: %s0x%016" PRIx64 "%s\n", + clr_reg_name, XRegNameForCode(code, r31mode), + clr_reg_value, reg(code, r31mode), clr_normal); } -void Simulator::PrintRegisters(bool print_all_regs) { - static bool first_run = true; - static int64_t last_regs[kNumberOfRegisters]; +void Simulator::PrintFPRegister(unsigned code, PrintFPRegisterSizes sizes) { + // The template is "# v:bits (d:value, ...)". - for (unsigned i = 0; i < kNumberOfRegisters; i++) { - if (print_all_regs || first_run || - (last_regs[i] != xreg(i, Reg31IsStackPointer))) { + DCHECK(sizes != 0); + DCHECK((sizes & kPrintAllFPRegValues) == sizes); + + // Print the raw bits. + fprintf(stream_, "# %s%5s: %s0x%016" PRIx64 "%s (", + clr_fpreg_name, VRegNameForCode(code), + clr_fpreg_value, fpreg(code), clr_normal); + + // Print all requested value interpretations. + bool need_separator = false; + if (sizes & kPrintDRegValue) { + fprintf(stream_, "%s%s%s: %s%g%s", + need_separator ? ", " : "", + clr_fpreg_name, DRegNameForCode(code), + clr_fpreg_value, fpreg(code), clr_normal); + need_separator = true; + } + + if (sizes & kPrintSRegValue) { + fprintf(stream_, "%s%s%s: %s%g%s", + need_separator ? ", " : "", + clr_fpreg_name, SRegNameForCode(code), + clr_fpreg_value, fpreg(code), clr_normal); + need_separator = true; + } + + // End the value list. + fprintf(stream_, ")\n"); +} + + +void Simulator::PrintSystemRegister(SystemRegister id) { + switch (id) { + case NZCV: + fprintf(stream_, "# %sNZCV: %sN:%d Z:%d C:%d V:%d%s\n", + clr_flag_name, clr_flag_value, + nzcv().N(), nzcv().Z(), nzcv().C(), nzcv().V(), + clr_normal); + break; + case FPCR: { + static const char * rmode[] = { + "0b00 (Round to Nearest)", + "0b01 (Round towards Plus Infinity)", + "0b10 (Round towards Minus Infinity)", + "0b11 (Round towards Zero)" + }; + DCHECK(fpcr().RMode() < arraysize(rmode)); fprintf(stream_, - "# %s%4s:%s 0x%016" PRIx64 "%s\n", - clr_reg_name, - XRegNameForCode(i, Reg31IsStackPointer), - clr_reg_value, - xreg(i, Reg31IsStackPointer), + "# %sFPCR: %sAHP:%d DN:%d FZ:%d RMode:%s%s\n", + clr_flag_name, clr_flag_value, + fpcr().AHP(), fpcr().DN(), fpcr().FZ(), rmode[fpcr().RMode()], clr_normal); + break; } - // Cache the new register value so the next run can detect any changes. - last_regs[i] = xreg(i, Reg31IsStackPointer); + default: + UNREACHABLE(); } - first_run = false; } -void Simulator::PrintFPRegisters(bool print_all_regs) { - static bool first_run = true; - static uint64_t last_regs[kNumberOfFPRegisters]; +void Simulator::PrintRead(uintptr_t address, + size_t size, + unsigned reg_code) { + USE(size); // Size is unused here. - // Print as many rows of registers as necessary, keeping each individual - // register in the same column each time (to make it easy to visually scan - // for changes). - for (unsigned i = 0; i < kNumberOfFPRegisters; i++) { - if (print_all_regs || first_run || (last_regs[i] != dreg_bits(i))) { - fprintf(stream_, - "# %s %4s:%s 0x%016" PRIx64 "%s (%s%s:%s %g%s %s:%s %g%s)\n", - clr_fpreg_name, - VRegNameForCode(i), - clr_fpreg_value, - dreg_bits(i), - clr_normal, - clr_fpreg_name, - DRegNameForCode(i), - clr_fpreg_value, - dreg(i), - clr_fpreg_name, - SRegNameForCode(i), - clr_fpreg_value, - sreg(i), - clr_normal); - } - // Cache the new register value so the next run can detect any changes. - last_regs[i] = dreg_bits(i); + // The template is "# x:value <- address". + fprintf(stream_, "# %s%5s: %s0x%016" PRIx64 "%s", + clr_reg_name, XRegNameForCode(reg_code), + clr_reg_value, reg(reg_code), clr_normal); + + fprintf(stream_, " <- %s0x%016" PRIxPTR "%s\n", + clr_memory_address, address, clr_normal); +} + + +void Simulator::PrintReadFP(uintptr_t address, + size_t size, + unsigned reg_code) { + // The template is "# reg:bits (reg:value) <- address". + switch (size) { + case kSRegSize: + fprintf(stream_, "# %s%5s: %s0x%016" PRIx64 "%s (%s%s: %s%gf%s)", + clr_fpreg_name, VRegNameForCode(reg_code), + clr_fpreg_value, fpreg(reg_code), clr_normal, + clr_fpreg_name, SRegNameForCode(reg_code), + clr_fpreg_value, fpreg(reg_code), clr_normal); + break; + case kDRegSize: + fprintf(stream_, "# %s%5s: %s0x%016" PRIx64 "%s (%s%s: %s%g%s)", + clr_fpreg_name, VRegNameForCode(reg_code), + clr_fpreg_value, fpreg(reg_code), clr_normal, + clr_fpreg_name, DRegNameForCode(reg_code), + clr_fpreg_value, fpreg(reg_code), clr_normal); + break; + default: + UNREACHABLE(); } - first_run = false; + + fprintf(stream_, " <- %s0x%016" PRIxPTR "%s\n", + clr_memory_address, address, clr_normal); } -void Simulator::PrintProcessorState() { - PrintSystemRegisters(); - PrintRegisters(); - PrintFPRegisters(); +void Simulator::PrintWrite(uintptr_t address, + size_t size, + unsigned reg_code) { + // The template is "# reg:value -> address". To keep the trace tidy and + // readable, the value is aligned with the values in the register trace. + switch (size) { + case kByteSizeInBytes: + fprintf(stream_, "# %s%5s<7:0>: %s0x%02" PRIx8 "%s", + clr_reg_name, WRegNameForCode(reg_code), + clr_reg_value, reg(reg_code), clr_normal); + break; + case kHalfWordSizeInBytes: + fprintf(stream_, "# %s%5s<15:0>: %s0x%04" PRIx16 "%s", + clr_reg_name, WRegNameForCode(reg_code), + clr_reg_value, reg(reg_code), clr_normal); + break; + case kWRegSize: + fprintf(stream_, "# %s%5s: %s0x%08" PRIx32 "%s", + clr_reg_name, WRegNameForCode(reg_code), + clr_reg_value, reg(reg_code), clr_normal); + break; + case kXRegSize: + fprintf(stream_, "# %s%5s: %s0x%016" PRIx64 "%s", + clr_reg_name, XRegNameForCode(reg_code), + clr_reg_value, reg(reg_code), clr_normal); + break; + default: + UNREACHABLE(); + } + + fprintf(stream_, " -> %s0x%016" PRIxPTR "%s\n", + clr_memory_address, address, clr_normal); } -void Simulator::PrintWrite(uintptr_t address, uint64_t value, - unsigned num_bytes) { - // The template is "# value -> address". The format string is not used - // directly in the printf because some compilers struggle with the - // parametrized width field (%0*). - const char* format = "# %s0x%0*" PRIx64 "%s -> %s0x%016" PRIxPTR "%s\n"; - fprintf(stream_, - format, - clr_memory_value, - num_bytes * 2, // The width in hexadecimal characters. - value, - clr_normal, - clr_memory_address, - address, - clr_normal); +void Simulator::PrintWriteFP(uintptr_t address, + size_t size, + unsigned reg_code) { + // The template is "# reg:bits (reg:value) -> address". To keep the trace tidy + // and readable, the value is aligned with the values in the register trace. + switch (size) { + case kSRegSize: + fprintf(stream_, "# %s%5s<31:0>: %s0x%08" PRIx32 "%s (%s%s: %s%gf%s)", + clr_fpreg_name, VRegNameForCode(reg_code), + clr_fpreg_value, fpreg(reg_code), clr_normal, + clr_fpreg_name, SRegNameForCode(reg_code), + clr_fpreg_value, fpreg(reg_code), clr_normal); + break; + case kDRegSize: + fprintf(stream_, "# %s%5s: %s0x%016" PRIx64 "%s (%s%s: %s%g%s)", + clr_fpreg_name, VRegNameForCode(reg_code), + clr_fpreg_value, fpreg(reg_code), clr_normal, + clr_fpreg_name, DRegNameForCode(reg_code), + clr_fpreg_value, fpreg(reg_code), clr_normal); + break; + default: + UNREACHABLE(); + } + + fprintf(stream_, " -> %s0x%016" PRIxPTR "%s\n", + clr_memory_address, address, clr_normal); } @@ -1383,6 +1483,7 @@ void Simulator::LogicalHelper(Instruction* instr, T op2) { nzcv().SetZ(CalcZFlag(result)); nzcv().SetC(0); nzcv().SetV(0); + LogSystemRegister(NZCV); } set_reg(instr->Rd(), result, instr->RdMode()); @@ -1423,6 +1524,7 @@ void Simulator::ConditionalCompareHelper(Instruction* instr, T op2) { } else { // If the condition fails, set the status flags to the nzcv immediate. nzcv().SetFlags(instr->Nzcv()); + LogSystemRegister(NZCV); } } @@ -1463,8 +1565,8 @@ void Simulator::LoadStoreHelper(Instruction* instr, AddrMode addrmode) { unsigned srcdst = instr->Rt(); unsigned addr_reg = instr->Rn(); - uint8_t* address = LoadStoreAddress(addr_reg, offset, addrmode); - uint8_t* stack = NULL; + uintptr_t address = LoadStoreAddress(addr_reg, offset, addrmode); + uintptr_t stack = 0; // Handle the writeback for stores before the store. On a CPU the writeback // and the store are atomic, but when running on the simulator it is possible @@ -1478,22 +1580,24 @@ void Simulator::LoadStoreHelper(Instruction* instr, // For store the address post writeback is used to check access below the // stack. - stack = reinterpret_cast(sp()); + stack = sp(); } LoadStoreOp op = static_cast(instr->Mask(LoadStoreOpMask)); switch (op) { - case LDRB_w: set_wreg(srcdst, MemoryRead(address)); break; - case LDRH_w: set_wreg(srcdst, MemoryRead(address)); break; - case LDR_w: set_wreg(srcdst, MemoryRead(address)); break; - case LDR_x: set_xreg(srcdst, MemoryRead(address)); break; - case LDRSB_w: set_wreg(srcdst, MemoryRead(address)); break; - case LDRSH_w: set_wreg(srcdst, MemoryRead(address)); break; - case LDRSB_x: set_xreg(srcdst, MemoryRead(address)); break; - case LDRSH_x: set_xreg(srcdst, MemoryRead(address)); break; - case LDRSW_x: set_xreg(srcdst, MemoryRead(address)); break; - case LDR_s: set_sreg(srcdst, MemoryRead(address)); break; - case LDR_d: set_dreg(srcdst, MemoryRead(address)); break; + // Use _no_log variants to suppress the register trace (LOG_REGS, + // LOG_FP_REGS). We will print a more detailed log. + case LDRB_w: set_wreg_no_log(srcdst, MemoryRead(address)); break; + case LDRH_w: set_wreg_no_log(srcdst, MemoryRead(address)); break; + case LDR_w: set_wreg_no_log(srcdst, MemoryRead(address)); break; + case LDR_x: set_xreg_no_log(srcdst, MemoryRead(address)); break; + case LDRSB_w: set_wreg_no_log(srcdst, MemoryRead(address)); break; + case LDRSH_w: set_wreg_no_log(srcdst, MemoryRead(address)); break; + case LDRSB_x: set_xreg_no_log(srcdst, MemoryRead(address)); break; + case LDRSH_x: set_xreg_no_log(srcdst, MemoryRead(address)); break; + case LDRSW_x: set_xreg_no_log(srcdst, MemoryRead(address)); break; + case LDR_s: set_sreg_no_log(srcdst, MemoryRead(address)); break; + case LDR_d: set_dreg_no_log(srcdst, MemoryRead(address)); break; case STRB_w: MemoryWrite(address, wreg(srcdst)); break; case STRH_w: MemoryWrite(address, wreg(srcdst)); break; @@ -1505,6 +1609,23 @@ void Simulator::LoadStoreHelper(Instruction* instr, default: UNIMPLEMENTED(); } + // Print a detailed trace (including the memory address) instead of the basic + // register:value trace generated by set_*reg(). + size_t access_size = 1 << instr->SizeLS(); + if (instr->IsLoad()) { + if ((op == LDR_s) || (op == LDR_d)) { + LogReadFP(address, access_size, srcdst); + } else { + LogRead(address, access_size, srcdst); + } + } else { + if ((op == STR_s) || (op == STR_d)) { + LogWriteFP(address, access_size, srcdst); + } else { + LogWrite(address, access_size, srcdst); + } + } + // Handle the writeback for loads after the load to ensure safe pop // operation even when interrupted in the middle of it. The stack pointer // is only updated after the load so pop(fp) will never break the invariant @@ -1512,7 +1633,7 @@ void Simulator::LoadStoreHelper(Instruction* instr, if (instr->IsLoad()) { // For loads the address pre writeback is used to check access below the // stack. - stack = reinterpret_cast(sp()); + stack = sp(); LoadStoreWriteBack(addr_reg, offset, addrmode); } @@ -1548,9 +1669,11 @@ void Simulator::LoadStorePairHelper(Instruction* instr, unsigned rt = instr->Rt(); unsigned rt2 = instr->Rt2(); unsigned addr_reg = instr->Rn(); - int offset = instr->ImmLSPair() << instr->SizeLSPair(); - uint8_t* address = LoadStoreAddress(addr_reg, offset, addrmode); - uint8_t* stack = NULL; + size_t access_size = 1 << instr->SizeLSPair(); + int64_t offset = instr->ImmLSPair() * access_size; + uintptr_t address = LoadStoreAddress(addr_reg, offset, addrmode); + uintptr_t address2 = address + access_size; + uintptr_t stack = 0; // Handle the writeback for stores before the store. On a CPU the writeback // and the store are atomic, but when running on the simulator it is possible @@ -1564,7 +1687,7 @@ void Simulator::LoadStorePairHelper(Instruction* instr, // For store the address post writeback is used to check access below the // stack. - stack = reinterpret_cast(sp()); + stack = sp(); } LoadStorePairOp op = @@ -1574,54 +1697,85 @@ void Simulator::LoadStorePairHelper(Instruction* instr, DCHECK(((op & LoadStorePairLBit) == 0) || (rt != rt2)); switch (op) { + // Use _no_log variants to suppress the register trace (LOG_REGS, + // LOG_FP_REGS). We will print a more detailed log. case LDP_w: { - set_wreg(rt, MemoryRead(address)); - set_wreg(rt2, MemoryRead(address + kWRegSize)); + DCHECK(access_size == kWRegSize); + set_wreg_no_log(rt, MemoryRead(address)); + set_wreg_no_log(rt2, MemoryRead(address2)); break; } case LDP_s: { - set_sreg(rt, MemoryRead(address)); - set_sreg(rt2, MemoryRead(address + kSRegSize)); + DCHECK(access_size == kSRegSize); + set_sreg_no_log(rt, MemoryRead(address)); + set_sreg_no_log(rt2, MemoryRead(address2)); break; } case LDP_x: { - set_xreg(rt, MemoryRead(address)); - set_xreg(rt2, MemoryRead(address + kXRegSize)); + DCHECK(access_size == kXRegSize); + set_xreg_no_log(rt, MemoryRead(address)); + set_xreg_no_log(rt2, MemoryRead(address2)); break; } case LDP_d: { - set_dreg(rt, MemoryRead(address)); - set_dreg(rt2, MemoryRead(address + kDRegSize)); + DCHECK(access_size == kDRegSize); + set_dreg_no_log(rt, MemoryRead(address)); + set_dreg_no_log(rt2, MemoryRead(address2)); break; } case LDPSW_x: { - set_xreg(rt, MemoryRead(address)); - set_xreg(rt2, MemoryRead(address + kWRegSize)); + DCHECK(access_size == kWRegSize); + set_xreg_no_log(rt, MemoryRead(address)); + set_xreg_no_log(rt2, MemoryRead(address2)); break; } case STP_w: { + DCHECK(access_size == kWRegSize); MemoryWrite(address, wreg(rt)); - MemoryWrite(address + kWRegSize, wreg(rt2)); + MemoryWrite(address2, wreg(rt2)); break; } case STP_s: { + DCHECK(access_size == kSRegSize); MemoryWrite(address, sreg(rt)); - MemoryWrite(address + kSRegSize, sreg(rt2)); + MemoryWrite(address2, sreg(rt2)); break; } case STP_x: { + DCHECK(access_size == kXRegSize); MemoryWrite(address, xreg(rt)); - MemoryWrite(address + kXRegSize, xreg(rt2)); + MemoryWrite(address2, xreg(rt2)); break; } case STP_d: { + DCHECK(access_size == kDRegSize); MemoryWrite(address, dreg(rt)); - MemoryWrite(address + kDRegSize, dreg(rt2)); + MemoryWrite(address2, dreg(rt2)); break; } default: UNREACHABLE(); } + // Print a detailed trace (including the memory address) instead of the basic + // register:value trace generated by set_*reg(). + if (instr->IsLoad()) { + if ((op == LDP_s) || (op == LDP_d)) { + LogReadFP(address, access_size, rt); + LogReadFP(address2, access_size, rt2); + } else { + LogRead(address, access_size, rt); + LogRead(address2, access_size, rt2); + } + } else { + if ((op == STP_s) || (op == STP_d)) { + LogWriteFP(address, access_size, rt); + LogWriteFP(address2, access_size, rt2); + } else { + LogWrite(address, access_size, rt); + LogWrite(address2, access_size, rt2); + } + } + // Handle the writeback for loads after the load to ensure safe pop // operation even when interrupted in the middle of it. The stack pointer // is only updated after the load so pop(fp) will never break the invariant @@ -1629,7 +1783,7 @@ void Simulator::LoadStorePairHelper(Instruction* instr, if (instr->IsLoad()) { // For loads the address pre writeback is used to check access below the // stack. - stack = reinterpret_cast(sp()); + stack = sp(); LoadStoreWriteBack(addr_reg, offset, addrmode); } @@ -1641,24 +1795,37 @@ void Simulator::LoadStorePairHelper(Instruction* instr, void Simulator::VisitLoadLiteral(Instruction* instr) { - uint8_t* address = instr->LiteralAddress(); + uintptr_t address = instr->LiteralAddress(); unsigned rt = instr->Rt(); switch (instr->Mask(LoadLiteralMask)) { - case LDR_w_lit: set_wreg(rt, MemoryRead(address)); break; - case LDR_x_lit: set_xreg(rt, MemoryRead(address)); break; - case LDR_s_lit: set_sreg(rt, MemoryRead(address)); break; - case LDR_d_lit: set_dreg(rt, MemoryRead(address)); break; + // Use _no_log variants to suppress the register trace (LOG_REGS, + // LOG_FP_REGS), then print a more detailed log. + case LDR_w_lit: + set_wreg_no_log(rt, MemoryRead(address)); + LogRead(address, kWRegSize, rt); + break; + case LDR_x_lit: + set_xreg_no_log(rt, MemoryRead(address)); + LogRead(address, kXRegSize, rt); + break; + case LDR_s_lit: + set_sreg_no_log(rt, MemoryRead(address)); + LogReadFP(address, kSRegSize, rt); + break; + case LDR_d_lit: + set_dreg_no_log(rt, MemoryRead(address)); + LogReadFP(address, kDRegSize, rt); + break; default: UNREACHABLE(); } } -uint8_t* Simulator::LoadStoreAddress(unsigned addr_reg, - int64_t offset, - AddrMode addrmode) { +uintptr_t Simulator::LoadStoreAddress(unsigned addr_reg, int64_t offset, + AddrMode addrmode) { const unsigned kSPRegCode = kSPRegInternalCode & kRegCodeMask; - int64_t address = xreg(addr_reg, Reg31IsStackPointer); + uint64_t address = xreg(addr_reg, Reg31IsStackPointer); if ((addr_reg == kSPRegCode) && ((address % 16) != 0)) { // When the base register is SP the stack pointer is required to be // quadword aligned prior to the address calculation and write-backs. @@ -1670,7 +1837,7 @@ uint8_t* Simulator::LoadStoreAddress(unsigned addr_reg, address += offset; } - return reinterpret_cast(address); + return address; } @@ -1685,12 +1852,12 @@ void Simulator::LoadStoreWriteBack(unsigned addr_reg, } -void Simulator::CheckMemoryAccess(uint8_t* address, uint8_t* stack) { +void Simulator::CheckMemoryAccess(uintptr_t address, uintptr_t stack) { if ((address >= stack_limit_) && (address < stack)) { fprintf(stream_, "ACCESS BELOW STACK POINTER:\n"); - fprintf(stream_, " sp is here: 0x%16p\n", stack); - fprintf(stream_, " access was here: 0x%16p\n", address); - fprintf(stream_, " stack limit is here: 0x%16p\n", stack_limit_); + fprintf(stream_, " sp is here: 0x%016" PRIx64 "\n", stack); + fprintf(stream_, " access was here: 0x%016" PRIx64 "\n", address); + fprintf(stream_, " stack limit is here: 0x%016" PRIx64 "\n", stack_limit_); fprintf(stream_, "\n"); FATAL("ACCESS BELOW STACK POINTER"); } @@ -2245,6 +2412,7 @@ void Simulator::VisitFPConditionalCompare(Instruction* instr) { } else { // If the condition fails, set the status flags to the nzcv immediate. nzcv().SetFlags(instr->Nzcv()); + LogSystemRegister(NZCV); } break; } @@ -3027,8 +3195,14 @@ void Simulator::VisitSystem(Instruction* instr) { } case MSR: { switch (instr->ImmSystemRegister()) { - case NZCV: nzcv().SetRawValue(xreg(instr->Rt())); break; - case FPCR: fpcr().SetRawValue(xreg(instr->Rt())); break; + case NZCV: + nzcv().SetRawValue(xreg(instr->Rt())); + LogSystemRegister(NZCV); + break; + case FPCR: + fpcr().SetRawValue(xreg(instr->Rt())); + LogSystemRegister(FPCR); + break; default: UNIMPLEMENTED(); } break; @@ -3239,8 +3413,8 @@ void Simulator::Debug() { } else if ((strcmp(cmd, "print") == 0) || (strcmp(cmd, "p") == 0)) { if (argc == 2) { if (strcmp(arg1, "all") == 0) { - PrintRegisters(true); - PrintFPRegisters(true); + PrintRegisters(); + PrintFPRegisters(); } else { if (!PrintValue(arg1)) { PrintF("%s unrecognized\n", arg1); @@ -3444,7 +3618,7 @@ void Simulator::VisitException(Instruction* instr) { if (FLAG_trace_sim_messages || FLAG_trace_sim || (parameters & BREAK)) { if (message != NULL) { PrintF(stream_, - "%sDebugger hit %d: %s%s%s\n", + "# %sDebugger hit %d: %s%s%s\n", clr_debug_number, code, clr_debug_message, @@ -3452,7 +3626,7 @@ void Simulator::VisitException(Instruction* instr) { clr_normal); } else { PrintF(stream_, - "%sDebugger hit %d.%s\n", + "# %sDebugger hit %d.%s\n", clr_debug_number, code, clr_normal); @@ -3479,9 +3653,9 @@ void Simulator::VisitException(Instruction* instr) { // Don't print information that is already being traced. parameters &= ~log_parameters(); // Print the requested information. - if (parameters & LOG_SYS_REGS) PrintSystemRegisters(true); - if (parameters & LOG_REGS) PrintRegisters(true); - if (parameters & LOG_FP_REGS) PrintFPRegisters(true); + if (parameters & LOG_SYS_REGS) PrintSystemRegisters(); + if (parameters & LOG_REGS) PrintRegisters(); + if (parameters & LOG_FP_REGS) PrintFPRegisters(); } // The stop parameters are inlined in the code. Skip them: diff --git a/src/arm64/simulator-arm64.h b/src/arm64/simulator-arm64.h index a9f2e09..108f6f2 100644 --- a/src/arm64/simulator-arm64.h +++ b/src/arm64/simulator-arm64.h @@ -312,7 +312,6 @@ class Simulator : public DecoderVisitor { DCHECK(IsAligned(reinterpret_cast(pc_), kInstructionSize)); CheckBreakNext(); Decode(pc_); - LogProcessorState(); increment_pc(); CheckBreakpoints(); } @@ -348,16 +347,13 @@ class Simulator : public DecoderVisitor { return reg(code, r31mode); } - // Write 'size' bits of 'value' into an integer register. The value is - // zero-extended. This behaviour matches AArch64 register writes. - - // Like set_reg(), but infer the access size from the template type. + // Write 'value' into an integer register. The value is zero-extended. This + // behaviour matches AArch64 register writes. template void set_reg(unsigned code, T value, Reg31Mode r31mode = Reg31IsZeroRegister) { - DCHECK(code < kNumberOfRegisters); - if (!IsZeroRegister(code, r31mode)) - registers_[code].Set(value); + set_reg_no_log(code, value, r31mode); + LogRegister(code, r31mode); } // Common specialized accessors for the set_reg() template. @@ -371,6 +367,26 @@ class Simulator : public DecoderVisitor { set_reg(code, value, r31mode); } + // As above, but don't automatically log the register update. + template + void set_reg_no_log(unsigned code, T value, + Reg31Mode r31mode = Reg31IsZeroRegister) { + DCHECK(code < kNumberOfRegisters); + if (!IsZeroRegister(code, r31mode)) { + registers_[code].Set(value); + } + } + + void set_wreg_no_log(unsigned code, int32_t value, + Reg31Mode r31mode = Reg31IsZeroRegister) { + set_reg_no_log(code, value, r31mode); + } + + void set_xreg_no_log(unsigned code, int64_t value, + Reg31Mode r31mode = Reg31IsZeroRegister) { + set_reg_no_log(code, value, r31mode); + } + // Commonly-used special cases. template void set_lr(T value) { @@ -430,9 +446,13 @@ class Simulator : public DecoderVisitor { // This behaviour matches AArch64 register writes. template void set_fpreg(unsigned code, T value) { - DCHECK((sizeof(value) == kDRegSize) || (sizeof(value) == kSRegSize)); - DCHECK(code < kNumberOfFPRegisters); - fpregisters_[code].Set(value); + set_fpreg_no_log(code, value); + + if (sizeof(value) <= kSRegSize) { + LogFPRegister(code, kPrintSRegValue); + } else { + LogFPRegister(code, kPrintDRegValue); + } } // Common specialized accessors for the set_fpreg() template. @@ -452,6 +472,22 @@ class Simulator : public DecoderVisitor { set_fpreg(code, value); } + // As above, but don't automatically log the register update. + template + void set_fpreg_no_log(unsigned code, T value) { + DCHECK((sizeof(value) == kDRegSize) || (sizeof(value) == kSRegSize)); + DCHECK(code < kNumberOfFPRegisters); + fpregisters_[code].Set(value); + } + + void set_sreg_no_log(unsigned code, float value) { + set_fpreg_no_log(code, value); + } + + void set_dreg_no_log(unsigned code, double value) { + set_fpreg_no_log(code, value); + } + SimSystemRegister& nzcv() { return nzcv_; } SimSystemRegister& fpcr() { return fpcr_; } @@ -478,33 +514,68 @@ class Simulator : public DecoderVisitor { // Disassemble instruction at the given address. void PrintInstructionsAt(Instruction* pc, uint64_t count); - void PrintSystemRegisters(bool print_all = false); - void PrintRegisters(bool print_all_regs = false); - void PrintFPRegisters(bool print_all_regs = false); - void PrintProcessorState(); - void PrintWrite(uintptr_t address, uint64_t value, unsigned num_bytes); + // Print all registers of the specified types. + void PrintRegisters(); + void PrintFPRegisters(); + void PrintSystemRegisters(); + + // Like Print* (above), but respect log_parameters(). void LogSystemRegisters() { - if (log_parameters_ & LOG_SYS_REGS) PrintSystemRegisters(); + if (log_parameters() & LOG_SYS_REGS) PrintSystemRegisters(); } void LogRegisters() { - if (log_parameters_ & LOG_REGS) PrintRegisters(); + if (log_parameters() & LOG_REGS) PrintRegisters(); } void LogFPRegisters() { - if (log_parameters_ & LOG_FP_REGS) PrintFPRegisters(); + if (log_parameters() & LOG_FP_REGS) PrintFPRegisters(); + } + + // Specify relevant register sizes, for PrintFPRegister. + // + // These values are bit masks; they can be combined in case multiple views of + // a machine register are interesting. + enum PrintFPRegisterSizes { + kPrintDRegValue = 1 << kDRegSize, + kPrintSRegValue = 1 << kSRegSize, + kPrintAllFPRegValues = kPrintDRegValue | kPrintSRegValue + }; + + // Print individual register values (after update). + void PrintRegister(unsigned code, Reg31Mode r31mode = Reg31IsStackPointer); + void PrintFPRegister(unsigned code, + PrintFPRegisterSizes sizes = kPrintAllFPRegValues); + void PrintSystemRegister(SystemRegister id); + + // Like Print* (above), but respect log_parameters(). + void LogRegister(unsigned code, Reg31Mode r31mode = Reg31IsStackPointer) { + if (log_parameters() & LOG_REGS) PrintRegister(code, r31mode); } - void LogProcessorState() { - LogSystemRegisters(); - LogRegisters(); - LogFPRegisters(); + void LogFPRegister(unsigned code, + PrintFPRegisterSizes sizes = kPrintAllFPRegValues) { + if (log_parameters() & LOG_FP_REGS) PrintFPRegister(code, sizes); } - template - void LogWrite(uintptr_t address, T value) { - uint64_t raw_value = 0; - DCHECK(sizeof(value) <= sizeof(raw_value)); - if (log_parameters_ & LOG_WRITE) { - memcpy(&raw_value, &value, sizeof(value)); - PrintWrite(address, raw_value, sizeof(value)); - } + void LogSystemRegister(SystemRegister id) { + if (log_parameters() & LOG_SYS_REGS) PrintSystemRegister(id); + } + + // Print memory accesses. + void PrintRead(uintptr_t address, size_t size, unsigned reg_code); + void PrintReadFP(uintptr_t address, size_t size, unsigned reg_code); + void PrintWrite(uintptr_t address, size_t size, unsigned reg_code); + void PrintWriteFP(uintptr_t address, size_t size, unsigned reg_code); + + // Like Print* (above), but respect log_parameters(). + void LogRead(uintptr_t address, size_t size, unsigned reg_code) { + if (log_parameters() & LOG_REGS) PrintRead(address, size, reg_code); + } + void LogReadFP(uintptr_t address, size_t size, unsigned reg_code) { + if (log_parameters() & LOG_FP_REGS) PrintReadFP(address, size, reg_code); + } + void LogWrite(uintptr_t address, size_t size, unsigned reg_code) { + if (log_parameters() & LOG_WRITE) PrintWrite(address, size, reg_code); + } + void LogWriteFP(uintptr_t address, size_t size, unsigned reg_code) { + if (log_parameters() & LOG_WRITE) PrintWriteFP(address, size, reg_code); } int log_parameters() { return log_parameters_; } @@ -595,14 +666,14 @@ class Simulator : public DecoderVisitor { int64_t offset, AddrMode addrmode); void LoadStorePairHelper(Instruction* instr, AddrMode addrmode); - uint8_t* LoadStoreAddress(unsigned addr_reg, - int64_t offset, - AddrMode addrmode); + uintptr_t LoadStoreAddress(unsigned addr_reg, int64_t offset, + AddrMode addrmode); void LoadStoreWriteBack(unsigned addr_reg, int64_t offset, AddrMode addrmode); - void CheckMemoryAccess(uint8_t* address, uint8_t* stack); + void CheckMemoryAccess(uintptr_t address, uintptr_t stack); + // Memory read helpers. template T MemoryRead(A address) { T value; @@ -612,11 +683,11 @@ class Simulator : public DecoderVisitor { return value; } + // Memory write helpers. template void MemoryWrite(A address, T value) { STATIC_ASSERT((sizeof(value) == 1) || (sizeof(value) == 2) || (sizeof(value) == 4) || (sizeof(value) == 8)); - LogWrite(reinterpret_cast(address), value); memcpy(reinterpret_cast(address), &value, sizeof(value)); } @@ -771,10 +842,10 @@ class Simulator : public DecoderVisitor { static const uint32_t kConditionFlagsMask = 0xf0000000; // Stack - byte* stack_; - static const intptr_t stack_protection_size_ = KB; - intptr_t stack_size_; - byte* stack_limit_; + uintptr_t stack_; + static const size_t stack_protection_size_ = KB; + size_t stack_size_; + uintptr_t stack_limit_; Decoder* decoder_; Decoder* disassembler_decoder_; -- 2.7.4