📄 simulator-arm.cc.svn-base
字号:
// Copyright 2008 the V8 project authors. 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 Google Inc. 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 THE COPYRIGHT HOLDERS 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 THE COPYRIGHT// OWNER OR CONTRIBUTORS 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 <stdlib.h>#include "v8.h"#include "disasm.h"#include "constants-arm.h"#include "simulator-arm.h"#if !defined(__arm__)// Only build the simulator if not compiling for real ARM hardware.namespace assembler { namespace arm {using ::v8::internal::Object;using ::v8::internal::PrintF;using ::v8::internal::OS;using ::v8::internal::ReadLine;using ::v8::internal::DeleteArray;// This macro provides a platform independent use of sscanf. The reason for// SScanF not beeing implemented in a platform independent was through// ::v8::internal::OS in the same way as SNPrintF is that the Windows C Run-Time// Library does not provide vsscanf.#ifdef WIN32#define SScanF sscanf_s#else#define SScanF sscanf // NOLINT#endif// The Debugger class is used by the simulator while debugging simulated ARM// code.class Debugger { public: explicit Debugger(Simulator* sim); ~Debugger(); void Stop(Instr* instr); void Debug(); private: static const instr_t kBreakpointInstr = ((AL << 28) | (7 << 25) | (1 << 24) | break_point); static const instr_t kNopInstr = ((AL << 28) | (13 << 21)); Simulator* sim_; bool GetValue(char* desc, int32_t* value); // Set or delete a breakpoint. Returns true if successful. bool SetBreakpoint(Instr* breakpc); bool DeleteBreakpoint(Instr* breakpc); // Undo and redo all breakpoints. This is needed to bracket disassembly and // execution to skip past breakpoints when run from the debugger. void UndoBreakpoints(); void RedoBreakpoints();};Debugger::Debugger(Simulator* sim) { sim_ = sim;}Debugger::~Debugger() {}void Debugger::Stop(Instr* instr) { const char* str = (const char*)(instr->InstructionBits() & 0x0fffffff); PrintF("Simulator hit %s\n", str); sim_->set_pc(sim_->get_pc() + Instr::kInstrSize); Debug();}static const char* reg_names[] = { "r0", "r1", "r2", "r3", "r4", "r5", "r6", "r7", "r8", "r9", "r10", "r11", "r12", "r13", "r14", "r15", "pc", "lr", "sp", "ip", "fp", "sl", ""};static int reg_nums[] = { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 15, 14, 13, 12, 11, 10};static int RegNameToRegNum(char* name) { int reg = 0; while (*reg_names[reg] != 0) { if (strcmp(reg_names[reg], name) == 0) { return reg_nums[reg]; } reg++; } return -1;}bool Debugger::GetValue(char* desc, int32_t* value) { int regnum = RegNameToRegNum(desc); if (regnum >= 0) { if (regnum == 15) { *value = sim_->get_pc(); } else { *value = sim_->get_register(regnum); } return true; } else { return SScanF(desc, "%i", value) == 1; } return false;}bool Debugger::SetBreakpoint(Instr* breakpc) { // Check if a breakpoint can be set. If not return without any side-effects. if (sim_->break_pc_ != NULL) { return false; } // Set the breakpoint. sim_->break_pc_ = breakpc; sim_->break_instr_ = breakpc->InstructionBits(); // Not setting the breakpoint instruction in the code itself. It will be set // when the debugger shell continues. return true;}bool Debugger::DeleteBreakpoint(Instr* breakpc) { if (sim_->break_pc_ != NULL) { sim_->break_pc_->SetInstructionBits(sim_->break_instr_); } sim_->break_pc_ = NULL; sim_->break_instr_ = 0; return true;}void Debugger::UndoBreakpoints() { if (sim_->break_pc_ != NULL) { sim_->break_pc_->SetInstructionBits(sim_->break_instr_); }}void Debugger::RedoBreakpoints() { if (sim_->break_pc_ != NULL) { sim_->break_pc_->SetInstructionBits(kBreakpointInstr); }}void Debugger::Debug() { intptr_t last_pc = -1; bool done = false;#define COMMAND_SIZE 63#define ARG_SIZE 255#define STR(a) #a#define XSTR(a) STR(a) char cmd[COMMAND_SIZE + 1]; char arg1[ARG_SIZE + 1]; char arg2[ARG_SIZE + 1]; // make sure to have a proper terminating character if reaching the limit cmd[COMMAND_SIZE] = 0; arg1[ARG_SIZE] = 0; arg2[ARG_SIZE] = 0; // Undo all set breakpoints while running in the debugger shell. This will // make them invisible to all commands. UndoBreakpoints(); while (!done) { if (last_pc != sim_->get_pc()) { disasm::Disassembler dasm; // use a reasonably large buffer v8::internal::EmbeddedVector<char, 256> buffer; dasm.InstructionDecode(buffer, reinterpret_cast<byte*>(sim_->get_pc())); PrintF(" 0x%x %s\n", sim_->get_pc(), buffer.start()); last_pc = sim_->get_pc(); } char* line = ReadLine("sim> "); if (line == NULL) { break; } else { // Use sscanf to parse the individual parts of the command line. At the // moment no command expects more than two parameters. int args = SScanF(line, "%" XSTR(COMMAND_SIZE) "s " "%" XSTR(ARG_SIZE) "s " "%" XSTR(ARG_SIZE) "s", cmd, arg1, arg2); if ((strcmp(cmd, "si") == 0) || (strcmp(cmd, "stepi") == 0)) { sim_->InstructionDecode(reinterpret_cast<Instr*>(sim_->get_pc())); } else if ((strcmp(cmd, "c") == 0) || (strcmp(cmd, "cont") == 0)) { // Execute the one instruction we broke at with breakpoints disabled. sim_->InstructionDecode(reinterpret_cast<Instr*>(sim_->get_pc())); // Leave the debugger shell. done = true; } else if ((strcmp(cmd, "p") == 0) || (strcmp(cmd, "print") == 0)) { if (args == 2) { int32_t value; if (GetValue(arg1, &value)) { PrintF("%s: %d 0x%x\n", arg1, value, value); } else { PrintF("%s unrecognized\n", arg1); } } else { PrintF("print value\n"); } } else if ((strcmp(cmd, "po") == 0) || (strcmp(cmd, "printobject") == 0)) { if (args == 2) { int32_t value; if (GetValue(arg1, &value)) { Object* obj = reinterpret_cast<Object*>(value); USE(obj); PrintF("%s: \n", arg1);#if defined(DEBUG) obj->PrintLn();#endif // defined(DEBUG) } else { PrintF("%s unrecognized\n", arg1); } } else { PrintF("printobject value\n"); } } else if (strcmp(cmd, "disasm") == 0) { disasm::Disassembler dasm; // use a reasonably large buffer v8::internal::EmbeddedVector<char, 256> buffer; byte* cur = NULL; byte* end = NULL; if (args == 1) { cur = reinterpret_cast<byte*>(sim_->get_pc()); end = cur + (10 * Instr::kInstrSize); } else if (args == 2) { int32_t value; if (GetValue(arg1, &value)) { cur = reinterpret_cast<byte*>(value); // no length parameter passed, assume 10 instructions end = cur + (10 * Instr::kInstrSize); } } else { int32_t value1; int32_t value2; if (GetValue(arg1, &value1) && GetValue(arg2, &value2)) { cur = reinterpret_cast<byte*>(value1); end = cur + (value2 * Instr::kInstrSize); } } while (cur < end) { dasm.InstructionDecode(buffer, cur); PrintF(" 0x%x %s\n", cur, buffer.start()); cur += Instr::kInstrSize; } } else if (strcmp(cmd, "gdb") == 0) { PrintF("relinquishing control to gdb\n"); v8::internal::OS::DebugBreak(); PrintF("regaining control from gdb\n"); } else if (strcmp(cmd, "break") == 0) { if (args == 2) { int32_t value; if (GetValue(arg1, &value)) { if (!SetBreakpoint(reinterpret_cast<Instr*>(value))) { PrintF("setting breakpoint failed\n"); } } else { PrintF("%s unrecognized\n", arg1); } } else { PrintF("break addr\n"); } } else if (strcmp(cmd, "del") == 0) { if (!DeleteBreakpoint(NULL)) { PrintF("deleting breakpoint failed\n"); } } else if (strcmp(cmd, "flags") == 0) { PrintF("N flag: %d; ", sim_->n_flag_); PrintF("Z flag: %d; ", sim_->z_flag_); PrintF("C flag: %d; ", sim_->c_flag_); PrintF("V flag: %d\n", sim_->v_flag_); } else if (strcmp(cmd, "unstop") == 0) { intptr_t stop_pc = sim_->get_pc() - Instr::kInstrSize; Instr* stop_instr = reinterpret_cast<Instr*>(stop_pc); if (stop_instr->ConditionField() == special_condition) { stop_instr->SetInstructionBits(kNopInstr); } else { PrintF("Not at debugger stop."); } } else { PrintF("Unknown command: %s\n", cmd); } } DeleteArray(line); } // Add all the breakpoints back to stop execution and enter the debugger // shell when hit. RedoBreakpoints();#undef COMMAND_SIZE#undef ARG_SIZE#undef STR#undef XSTR}Simulator::Simulator() { // Setup simulator support first. Some of this information is needed to // setup the architecture state. size_t stack_size = 1 * 1024*1024; // allocate 1MB for stack stack_ = reinterpret_cast<char*>(malloc(stack_size)); pc_modified_ = false; icount_ = 0; break_pc_ = NULL; break_instr_ = 0; // Setup architecture state. // All registers are initialized to zero to start with. for (int i = 0; i < num_registers; i++) { registers_[i] = 0; } n_flag_ = false; z_flag_ = false; c_flag_ = false; v_flag_ = false; // The sp is initialized to point to the bottom (high address) of the // allocated stack area. To be safe in potential stack underflows we leave // some buffer below. registers_[sp] = reinterpret_cast<int32_t>(stack_) + stack_size - 64; // The lr and pc are initialized to a known bad value that will cause an // access violation if the simulator ever tries to execute it. registers_[pc] = bad_lr; registers_[lr] = bad_lr;}// This is the Simulator singleton. Currently only one thread is supported by// V8. If we had multiple threads, then we should have a Simulator instance on// a per thread basis.static Simulator* the_sim = NULL;// Get the active Simulator for the current thread. See comment above about// using a singleton currently.Simulator* Simulator::current() { if (the_sim == NULL) { the_sim = new Simulator(); } return the_sim;}// Sets the register in the architecture state. It will also deal with updating// Simulator internal state for special registers such as PC.void Simulator::set_register(int reg, int32_t value) { ASSERT((reg >= 0) && (reg < num_registers)); if (reg == pc) { pc_modified_ = true; } registers_[reg] = value;}// Get the register from the architecture state. This function does handle// the special case of accessing the PC register.int32_t Simulator::get_register(int reg) const { ASSERT((reg >= 0) && (reg < num_registers)); return registers_[reg] + ((reg == pc) ? Instr::kPCReadOffset : 0);}// Raw access to the PC register.void Simulator::set_pc(int32_t value) { pc_modified_ = true; registers_[pc] = value;}// Raw access to the PC register without the special adjustment when reading.int32_t Simulator::get_pc() const { return registers_[pc];}// Returns the limit of the stack area to enable checking for stack overflows.uintptr_t Simulator::StackLimit() const { // Leave a safety margin of 256 bytes to prevent overrunning the stack when // pushing values. return reinterpret_cast<uintptr_t>(stack_) + 256;}// Unsupported instructions use Format to print an error and stop execution.void Simulator::Format(Instr* instr, const char* format) { PrintF("Simulator found unsupported instruction:\n 0x%x: %s\n", instr, format); UNIMPLEMENTED();}// Checks if the current instruction should be executed based on its// condition bits.bool Simulator::ConditionallyExecute(Instr* instr) { switch (instr->ConditionField()) { case EQ: return z_flag_; case NE: return !z_flag_; case CS: return c_flag_; case CC: return !c_flag_; case MI: return n_flag_; case PL: return !n_flag_; case VS: return v_flag_; case VC: return !v_flag_; case HI: return c_flag_ && !z_flag_; case LS: return !c_flag_ || z_flag_; case GE: return n_flag_ == v_flag_; case LT: return n_flag_ != v_flag_; case GT: return !z_flag_ && (n_flag_ == v_flag_); case LE: return z_flag_ || (n_flag_ != v_flag_); case AL: return true; default: UNREACHABLE(); } return false;}// Calculate and set the Negative and Zero flags.void Simulator::SetNZFlags(int32_t val) { n_flag_ = (val < 0); z_flag_ = (val == 0);}// Set the Carry flag.void Simulator::SetCFlag(bool val) { c_flag_ = val;}// Set the oVerflow flag.void Simulator::SetVFlag(bool val) { v_flag_ = val;}// Calculate C flag value for additions.bool Simulator::CarryFrom(int32_t left, int32_t right) { uint32_t uleft = static_cast<uint32_t>(left); uint32_t uright = static_cast<uint32_t>(right); uint32_t urest = 0xffffffffU - uleft; return (uright > urest);}// Calculate C flag value for subtractions.bool Simulator::BorrowFrom(int32_t left, int32_t right) { uint32_t uleft = static_cast<uint32_t>(left);
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -