Landing for Rodolph Perfetta.
Fix the ARM simulator, the ARM disassembler and extend the stop feature. The stop feature in the simulator now support enabling, disabling and counting. BUG=None TEST=None git-svn-id: http://v8.googlecode.com/svn/branches/bleeding_edge@5723 ce2b1a6d-e550-0410-aec6-3dcde31c8c00
This commit is contained in:
parent
c964e478bf
commit
2122827893
@ -1004,7 +1004,7 @@ void Assembler::blx(int branch_offset) { // v5 and above
|
|||||||
int h = ((branch_offset & 2) >> 1)*B24;
|
int h = ((branch_offset & 2) >> 1)*B24;
|
||||||
int imm24 = branch_offset >> 2;
|
int imm24 = branch_offset >> 2;
|
||||||
ASSERT(is_int24(imm24));
|
ASSERT(is_int24(imm24));
|
||||||
emit(15 << 28 | B27 | B25 | h | (imm24 & Imm24Mask));
|
emit(nv | B27 | B25 | h | (imm24 & Imm24Mask));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@ -1634,15 +1634,29 @@ void Assembler::stm(BlockAddrMode am,
|
|||||||
|
|
||||||
|
|
||||||
// Exception-generating instructions and debugging support.
|
// Exception-generating instructions and debugging support.
|
||||||
void Assembler::stop(const char* msg) {
|
// Stops with a non-negative code less than kNumOfWatchedStops support
|
||||||
|
// enabling/disabling and a counter feature. See simulator-arm.h .
|
||||||
|
void Assembler::stop(const char* msg, Condition cond, int32_t code) {
|
||||||
#ifndef __arm__
|
#ifndef __arm__
|
||||||
// The simulator handles these special instructions and stops execution.
|
// See constants-arm.h SoftwareInterruptCodes. Unluckily the Assembler and
|
||||||
emit(15 << 28 | ((intptr_t) msg));
|
// Simulator do not share constants declaration.
|
||||||
|
ASSERT(code >= kDefaultStopCode);
|
||||||
|
static const uint32_t kStopInterruptCode = 1 << 23;
|
||||||
|
static const uint32_t kMaxStopCode = kStopInterruptCode - 1;
|
||||||
|
// The Simulator will handle the stop instruction and get the message address.
|
||||||
|
// It expects to find the address just after the svc instruction.
|
||||||
|
BlockConstPoolFor(2);
|
||||||
|
if (code >= 0) {
|
||||||
|
svc(kStopInterruptCode + code, cond);
|
||||||
|
} else {
|
||||||
|
svc(kStopInterruptCode + kMaxStopCode, cond);
|
||||||
|
}
|
||||||
|
emit(reinterpret_cast<Instr>(msg));
|
||||||
#else // def __arm__
|
#else // def __arm__
|
||||||
#ifdef CAN_USE_ARMV5_INSTRUCTIONS
|
#ifdef CAN_USE_ARMV5_INSTRUCTIONS
|
||||||
bkpt(0);
|
bkpt(0);
|
||||||
#else // ndef CAN_USE_ARMV5_INSTRUCTIONS
|
#else // ndef CAN_USE_ARMV5_INSTRUCTIONS
|
||||||
swi(0x9f0001);
|
svc(0x9f0001);
|
||||||
#endif // ndef CAN_USE_ARMV5_INSTRUCTIONS
|
#endif // ndef CAN_USE_ARMV5_INSTRUCTIONS
|
||||||
#endif // def __arm__
|
#endif // def __arm__
|
||||||
}
|
}
|
||||||
@ -1654,7 +1668,7 @@ void Assembler::bkpt(uint32_t imm16) { // v5 and above
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
void Assembler::swi(uint32_t imm24, Condition cond) {
|
void Assembler::svc(uint32_t imm24, Condition cond) {
|
||||||
ASSERT(is_uint24(imm24));
|
ASSERT(is_uint24(imm24));
|
||||||
emit(cond | 15*B24 | imm24);
|
emit(cond | 15*B24 | imm24);
|
||||||
}
|
}
|
||||||
|
@ -904,10 +904,13 @@ class Assembler : public Malloced {
|
|||||||
void stm(BlockAddrMode am, Register base, RegList src, Condition cond = al);
|
void stm(BlockAddrMode am, Register base, RegList src, Condition cond = al);
|
||||||
|
|
||||||
// Exception-generating instructions and debugging support
|
// Exception-generating instructions and debugging support
|
||||||
void stop(const char* msg);
|
static const int kDefaultStopCode = -1;
|
||||||
|
void stop(const char* msg,
|
||||||
|
Condition cond = al,
|
||||||
|
int32_t code = kDefaultStopCode);
|
||||||
|
|
||||||
void bkpt(uint32_t imm16); // v5 and above
|
void bkpt(uint32_t imm16); // v5 and above
|
||||||
void swi(uint32_t imm24, Condition cond = al);
|
void svc(uint32_t imm24, Condition cond = al);
|
||||||
|
|
||||||
// Coprocessor instructions
|
// Coprocessor instructions
|
||||||
|
|
||||||
|
@ -186,12 +186,18 @@ enum Shift {
|
|||||||
|
|
||||||
// Special Software Interrupt codes when used in the presence of the ARM
|
// Special Software Interrupt codes when used in the presence of the ARM
|
||||||
// simulator.
|
// simulator.
|
||||||
|
// svc (formerly swi) provides a 24bit immediate value. Use bits 22:0 for
|
||||||
|
// standard SoftwareInterrupCode. Bit 23 is reserved for the stop feature.
|
||||||
enum SoftwareInterruptCodes {
|
enum SoftwareInterruptCodes {
|
||||||
// transition to C code
|
// transition to C code
|
||||||
call_rt_redirected = 0x10,
|
call_rt_redirected = 0x10,
|
||||||
// break point
|
// break point
|
||||||
break_point = 0x20
|
break_point = 0x20,
|
||||||
|
// stop
|
||||||
|
stop = 1 << 23
|
||||||
};
|
};
|
||||||
|
static const int32_t kStopCodeMask = stop - 1;
|
||||||
|
static const uint32_t kMaxStopCode = stop - 1;
|
||||||
|
|
||||||
|
|
||||||
// Type of VFP register. Determines register encoding.
|
// Type of VFP register. Determines register encoding.
|
||||||
@ -325,7 +331,7 @@ class Instr {
|
|||||||
inline int SImmed24Field() const { return ((InstructionBits() << 8) >> 8); }
|
inline int SImmed24Field() const { return ((InstructionBits() << 8) >> 8); }
|
||||||
|
|
||||||
// Fields used in Software interrupt instructions
|
// Fields used in Software interrupt instructions
|
||||||
inline SoftwareInterruptCodes SwiField() const {
|
inline SoftwareInterruptCodes SvcField() const {
|
||||||
return static_cast<SoftwareInterruptCodes>(Bits(23, 0));
|
return static_cast<SoftwareInterruptCodes>(Bits(23, 0));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -70,7 +70,7 @@ void CPU::FlushICache(void* start, size_t size) {
|
|||||||
// __arm__ may be defined in thumb mode.
|
// __arm__ may be defined in thumb mode.
|
||||||
register uint32_t scno asm("r7") = __ARM_NR_cacheflush;
|
register uint32_t scno asm("r7") = __ARM_NR_cacheflush;
|
||||||
asm volatile(
|
asm volatile(
|
||||||
"swi 0x0"
|
"svc 0x0"
|
||||||
: "=r" (beg)
|
: "=r" (beg)
|
||||||
: "0" (beg), "r" (end), "r" (flg), "r" (scno));
|
: "0" (beg), "r" (end), "r" (flg), "r" (scno));
|
||||||
#else
|
#else
|
||||||
@ -83,7 +83,7 @@ void CPU::FlushICache(void* start, size_t size) {
|
|||||||
".ARM \n"
|
".ARM \n"
|
||||||
"1: push {r7} \n\t"
|
"1: push {r7} \n\t"
|
||||||
"mov r7, %4 \n\t"
|
"mov r7, %4 \n\t"
|
||||||
"swi 0x0 \n\t"
|
"svc 0x0 \n\t"
|
||||||
"pop {r7} \n\t"
|
"pop {r7} \n\t"
|
||||||
"@ Enter THUMB Mode\n\t"
|
"@ Enter THUMB Mode\n\t"
|
||||||
"adr r3, 2f+1 \n\t"
|
"adr r3, 2f+1 \n\t"
|
||||||
@ -98,20 +98,20 @@ void CPU::FlushICache(void* start, size_t size) {
|
|||||||
#if defined (__arm__) && !defined(__thumb__)
|
#if defined (__arm__) && !defined(__thumb__)
|
||||||
// __arm__ may be defined in thumb mode.
|
// __arm__ may be defined in thumb mode.
|
||||||
asm volatile(
|
asm volatile(
|
||||||
"swi %1"
|
"svc %1"
|
||||||
: "=r" (beg)
|
: "=r" (beg)
|
||||||
: "i" (__ARM_NR_cacheflush), "0" (beg), "r" (end), "r" (flg));
|
: "i" (__ARM_NR_cacheflush), "0" (beg), "r" (end), "r" (flg));
|
||||||
#else
|
#else
|
||||||
// Do not use the value of __ARM_NR_cacheflush in the inline assembly
|
// Do not use the value of __ARM_NR_cacheflush in the inline assembly
|
||||||
// below, because the thumb mode value would be used, which would be
|
// below, because the thumb mode value would be used, which would be
|
||||||
// wrong, since we switch to ARM mode before executing the swi instruction
|
// wrong, since we switch to ARM mode before executing the svc instruction
|
||||||
asm volatile(
|
asm volatile(
|
||||||
"@ Enter ARM Mode \n\t"
|
"@ Enter ARM Mode \n\t"
|
||||||
"adr r3, 1f \n\t"
|
"adr r3, 1f \n\t"
|
||||||
"bx r3 \n\t"
|
"bx r3 \n\t"
|
||||||
".ALIGN 4 \n\t"
|
".ALIGN 4 \n\t"
|
||||||
".ARM \n"
|
".ARM \n"
|
||||||
"1: swi 0x9f0002 \n"
|
"1: svc 0x9f0002 \n"
|
||||||
"@ Enter THUMB Mode\n\t"
|
"@ Enter THUMB Mode\n\t"
|
||||||
"adr r3, 2f+1 \n\t"
|
"adr r3, 2f+1 \n\t"
|
||||||
"bx r3 \n\t"
|
"bx r3 \n\t"
|
||||||
|
@ -108,7 +108,7 @@ class Decoder {
|
|||||||
void PrintShiftImm(Instr* instr);
|
void PrintShiftImm(Instr* instr);
|
||||||
void PrintShiftSat(Instr* instr);
|
void PrintShiftSat(Instr* instr);
|
||||||
void PrintPU(Instr* instr);
|
void PrintPU(Instr* instr);
|
||||||
void PrintSoftwareInterrupt(SoftwareInterruptCodes swi);
|
void PrintSoftwareInterrupt(SoftwareInterruptCodes svc);
|
||||||
|
|
||||||
// Handle formatting of instructions and their options.
|
// Handle formatting of instructions and their options.
|
||||||
int FormatRegister(Instr* instr, const char* option);
|
int FormatRegister(Instr* instr, const char* option);
|
||||||
@ -126,8 +126,8 @@ class Decoder {
|
|||||||
void DecodeType4(Instr* instr);
|
void DecodeType4(Instr* instr);
|
||||||
void DecodeType5(Instr* instr);
|
void DecodeType5(Instr* instr);
|
||||||
void DecodeType6(Instr* instr);
|
void DecodeType6(Instr* instr);
|
||||||
void DecodeType7(Instr* instr);
|
// Type 7 includes special Debugger instructions.
|
||||||
void DecodeUnconditional(Instr* instr);
|
int DecodeType7(Instr* instr);
|
||||||
// For VFP support.
|
// For VFP support.
|
||||||
void DecodeTypeVFP(Instr* instr);
|
void DecodeTypeVFP(Instr* instr);
|
||||||
void DecodeType6CoprocessorIns(Instr* instr);
|
void DecodeType6CoprocessorIns(Instr* instr);
|
||||||
@ -290,8 +290,8 @@ void Decoder::PrintPU(Instr* instr) {
|
|||||||
|
|
||||||
// Print SoftwareInterrupt codes. Factoring this out reduces the complexity of
|
// Print SoftwareInterrupt codes. Factoring this out reduces the complexity of
|
||||||
// the FormatOption method.
|
// the FormatOption method.
|
||||||
void Decoder::PrintSoftwareInterrupt(SoftwareInterruptCodes swi) {
|
void Decoder::PrintSoftwareInterrupt(SoftwareInterruptCodes svc) {
|
||||||
switch (swi) {
|
switch (svc) {
|
||||||
case call_rt_redirected:
|
case call_rt_redirected:
|
||||||
Print("call_rt_redirected");
|
Print("call_rt_redirected");
|
||||||
return;
|
return;
|
||||||
@ -299,9 +299,16 @@ void Decoder::PrintSoftwareInterrupt(SoftwareInterruptCodes swi) {
|
|||||||
Print("break_point");
|
Print("break_point");
|
||||||
return;
|
return;
|
||||||
default:
|
default:
|
||||||
out_buffer_pos_ += v8i::OS::SNPrintF(out_buffer_ + out_buffer_pos_,
|
if (svc >= stop) {
|
||||||
"%d",
|
out_buffer_pos_ += v8i::OS::SNPrintF(out_buffer_ + out_buffer_pos_,
|
||||||
swi);
|
"%d - 0x%x",
|
||||||
|
svc & kStopCodeMask,
|
||||||
|
svc & kStopCodeMask);
|
||||||
|
} else {
|
||||||
|
out_buffer_pos_ += v8i::OS::SNPrintF(out_buffer_ + out_buffer_pos_,
|
||||||
|
"%d",
|
||||||
|
svc);
|
||||||
|
}
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -553,9 +560,9 @@ int Decoder::FormatOption(Instr* instr, const char* format) {
|
|||||||
PrintShiftRm(instr);
|
PrintShiftRm(instr);
|
||||||
return 8;
|
return 8;
|
||||||
}
|
}
|
||||||
} else if (format[1] == 'w') { // 'swi
|
} else if (format[1] == 'v') { // 'svc
|
||||||
ASSERT(STRING_STARTS_WITH(format, "swi"));
|
ASSERT(STRING_STARTS_WITH(format, "svc"));
|
||||||
PrintSoftwareInterrupt(instr->SwiField());
|
PrintSoftwareInterrupt(instr->SvcField());
|
||||||
return 3;
|
return 3;
|
||||||
} else if (format[1] == 'i') { // 'sign: signed extra loads and stores
|
} else if (format[1] == 'i') { // 'sign: signed extra loads and stores
|
||||||
ASSERT(STRING_STARTS_WITH(format, "sign"));
|
ASSERT(STRING_STARTS_WITH(format, "sign"));
|
||||||
@ -1004,72 +1011,27 @@ void Decoder::DecodeType6(Instr* instr) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
void Decoder::DecodeType7(Instr* instr) {
|
int Decoder::DecodeType7(Instr* instr) {
|
||||||
if (instr->Bit(24) == 1) {
|
if (instr->Bit(24) == 1) {
|
||||||
Format(instr, "swi'cond 'swi");
|
if (instr->SvcField() >= stop) {
|
||||||
|
Format(instr, "stop'cond 'svc");
|
||||||
|
// Also print the stop message. Its address is encoded
|
||||||
|
// in the following 4 bytes.
|
||||||
|
out_buffer_pos_ +=
|
||||||
|
v8i::OS::SNPrintF(out_buffer_ + out_buffer_pos_,
|
||||||
|
"\n %p %08x stop message: %s",
|
||||||
|
reinterpret_cast<int32_t*>(instr + Instr::kInstrSize),
|
||||||
|
*reinterpret_cast<char**>(instr + Instr::kInstrSize),
|
||||||
|
*reinterpret_cast<char**>(instr + Instr::kInstrSize));
|
||||||
|
// We have decoded 2 * Instr::kInstrSize bytes.
|
||||||
|
return 2 * Instr::kInstrSize;
|
||||||
|
} else {
|
||||||
|
Format(instr, "svc'cond 'svc");
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
DecodeTypeVFP(instr);
|
DecodeTypeVFP(instr);
|
||||||
}
|
}
|
||||||
}
|
return Instr::kInstrSize;
|
||||||
|
|
||||||
void Decoder::DecodeUnconditional(Instr* instr) {
|
|
||||||
if (instr->Bits(7, 4) == 0xB && instr->Bits(27, 25) == 0 && instr->HasL()) {
|
|
||||||
Format(instr, "'memop'h'pu 'rd, ");
|
|
||||||
bool immediate = instr->HasB();
|
|
||||||
switch (instr->PUField()) {
|
|
||||||
case 0: {
|
|
||||||
// Post index, negative.
|
|
||||||
if (instr->HasW()) {
|
|
||||||
Unknown(instr);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
if (immediate) {
|
|
||||||
Format(instr, "['rn], #-'imm12");
|
|
||||||
} else {
|
|
||||||
Format(instr, "['rn], -'rm");
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
case 1: {
|
|
||||||
// Post index, positive.
|
|
||||||
if (instr->HasW()) {
|
|
||||||
Unknown(instr);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
if (immediate) {
|
|
||||||
Format(instr, "['rn], #+'imm12");
|
|
||||||
} else {
|
|
||||||
Format(instr, "['rn], +'rm");
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
case 2: {
|
|
||||||
// Pre index or offset, negative.
|
|
||||||
if (immediate) {
|
|
||||||
Format(instr, "['rn, #-'imm12]'w");
|
|
||||||
} else {
|
|
||||||
Format(instr, "['rn, -'rm]'w");
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
case 3: {
|
|
||||||
// Pre index or offset, positive.
|
|
||||||
if (immediate) {
|
|
||||||
Format(instr, "['rn, #+'imm12]'w");
|
|
||||||
} else {
|
|
||||||
Format(instr, "['rn, +'rm]'w");
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
default: {
|
|
||||||
// The PU field is a 2-bit field.
|
|
||||||
UNREACHABLE();
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
Format(instr, "break 'msg");
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@ -1332,7 +1294,7 @@ int Decoder::InstructionDecode(byte* instr_ptr) {
|
|||||||
"%08x ",
|
"%08x ",
|
||||||
instr->InstructionBits());
|
instr->InstructionBits());
|
||||||
if (instr->ConditionField() == special_condition) {
|
if (instr->ConditionField() == special_condition) {
|
||||||
DecodeUnconditional(instr);
|
UNIMPLEMENTED();
|
||||||
return Instr::kInstrSize;
|
return Instr::kInstrSize;
|
||||||
}
|
}
|
||||||
switch (instr->TypeField()) {
|
switch (instr->TypeField()) {
|
||||||
@ -1362,8 +1324,7 @@ int Decoder::InstructionDecode(byte* instr_ptr) {
|
|||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case 7: {
|
case 7: {
|
||||||
DecodeType7(instr);
|
return DecodeType7(instr);
|
||||||
break;
|
|
||||||
}
|
}
|
||||||
default: {
|
default: {
|
||||||
// The type field is 3-bits in the ARM encoding.
|
// The type field is 3-bits in the ARM encoding.
|
||||||
|
@ -112,15 +112,29 @@ static void InitializeCoverage() {
|
|||||||
|
|
||||||
|
|
||||||
void Debugger::Stop(Instr* instr) {
|
void Debugger::Stop(Instr* instr) {
|
||||||
char* str = reinterpret_cast<char*>(instr->InstructionBits() & 0x0fffffff);
|
// Get the stop code.
|
||||||
if (strlen(str) > 0) {
|
uint32_t code = instr->SvcField() & kStopCodeMask;
|
||||||
|
// Retrieve the encoded address, which comes just after this stop.
|
||||||
|
char** msg_address =
|
||||||
|
reinterpret_cast<char**>(sim_->get_pc() + Instr::kInstrSize);
|
||||||
|
char* msg = *msg_address;
|
||||||
|
ASSERT(msg != NULL);
|
||||||
|
|
||||||
|
// Update this stop description.
|
||||||
|
if (isWatchedStop(code) && !watched_stops[code].desc) {
|
||||||
|
watched_stops[code].desc = msg;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (strlen(msg) > 0) {
|
||||||
if (coverage_log != NULL) {
|
if (coverage_log != NULL) {
|
||||||
fprintf(coverage_log, "%s\n", str);
|
fprintf(coverage_log, "%s\n", msg);
|
||||||
fflush(coverage_log);
|
fflush(coverage_log);
|
||||||
}
|
}
|
||||||
instr->SetInstructionBits(0xe1a00000); // Overwrite with nop.
|
// Overwrite the instruction and address with nops.
|
||||||
|
instr->SetInstructionBits(kNopInstr);
|
||||||
|
reinterpret_cast<Instr*>(msg_address)->SetInstructionBits(kNopInstr);
|
||||||
}
|
}
|
||||||
sim_->set_pc(sim_->get_pc() + Instr::kInstrSize);
|
sim_->set_pc(sim_->get_pc() + 2 * Instr::kInstrSize);
|
||||||
}
|
}
|
||||||
|
|
||||||
#else // ndef GENERATED_CODE_COVERAGE
|
#else // ndef GENERATED_CODE_COVERAGE
|
||||||
@ -130,9 +144,16 @@ static void InitializeCoverage() {
|
|||||||
|
|
||||||
|
|
||||||
void Debugger::Stop(Instr* instr) {
|
void Debugger::Stop(Instr* instr) {
|
||||||
const char* str = (const char*)(instr->InstructionBits() & 0x0fffffff);
|
// Get the stop code.
|
||||||
PrintF("Simulator hit %s\n", str);
|
uint32_t code = instr->SvcField() & kStopCodeMask;
|
||||||
sim_->set_pc(sim_->get_pc() + Instr::kInstrSize);
|
// Retrieve the encoded address, which comes just after this stop.
|
||||||
|
char* msg = *reinterpret_cast<char**>(sim_->get_pc() + Instr::kInstrSize);
|
||||||
|
// Update this stop description.
|
||||||
|
if (sim_->isWatchedStop(code) && !sim_->watched_stops[code].desc) {
|
||||||
|
sim_->watched_stops[code].desc = msg;
|
||||||
|
}
|
||||||
|
PrintF("Simulator hit %s\n", msg);
|
||||||
|
sim_->set_pc(sim_->get_pc() + 2 * Instr::kInstrSize);
|
||||||
Debug();
|
Debug();
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
@ -359,6 +380,7 @@ void Debugger::Debug() {
|
|||||||
// use a reasonably large buffer
|
// use a reasonably large buffer
|
||||||
v8::internal::EmbeddedVector<char, 256> buffer;
|
v8::internal::EmbeddedVector<char, 256> buffer;
|
||||||
|
|
||||||
|
byte* prev = NULL;
|
||||||
byte* cur = NULL;
|
byte* cur = NULL;
|
||||||
byte* end = NULL;
|
byte* end = NULL;
|
||||||
|
|
||||||
@ -368,9 +390,9 @@ void Debugger::Debug() {
|
|||||||
} else if (argc == 2) {
|
} else if (argc == 2) {
|
||||||
int32_t value;
|
int32_t value;
|
||||||
if (GetValue(arg1, &value)) {
|
if (GetValue(arg1, &value)) {
|
||||||
cur = reinterpret_cast<byte*>(value);
|
cur = reinterpret_cast<byte*>(sim_->get_pc());
|
||||||
// no length parameter passed, assume 10 instructions
|
// Disassemble <arg1> instructions.
|
||||||
end = cur + (10 * Instr::kInstrSize);
|
end = cur + (value * Instr::kInstrSize);
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
int32_t value1;
|
int32_t value1;
|
||||||
@ -382,10 +404,10 @@ void Debugger::Debug() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
while (cur < end) {
|
while (cur < end) {
|
||||||
dasm.InstructionDecode(buffer, cur);
|
prev = cur;
|
||||||
|
cur += dasm.InstructionDecode(buffer, cur);
|
||||||
PrintF(" 0x%08x %s\n",
|
PrintF(" 0x%08x %s\n",
|
||||||
reinterpret_cast<intptr_t>(cur), buffer.start());
|
reinterpret_cast<intptr_t>(prev), buffer.start());
|
||||||
cur += Instr::kInstrSize;
|
|
||||||
}
|
}
|
||||||
} else if (strcmp(cmd, "gdb") == 0) {
|
} else if (strcmp(cmd, "gdb") == 0) {
|
||||||
PrintF("relinquishing control to gdb\n");
|
PrintF("relinquishing control to gdb\n");
|
||||||
@ -418,13 +440,58 @@ void Debugger::Debug() {
|
|||||||
PrintF("OVERFLOW flag: %d; ", sim_->overflow_vfp_flag_);
|
PrintF("OVERFLOW flag: %d; ", sim_->overflow_vfp_flag_);
|
||||||
PrintF("UNDERFLOW flag: %d; ", sim_->underflow_vfp_flag_);
|
PrintF("UNDERFLOW flag: %d; ", sim_->underflow_vfp_flag_);
|
||||||
PrintF("INEXACT flag: %d; ", sim_->inexact_vfp_flag_);
|
PrintF("INEXACT flag: %d; ", sim_->inexact_vfp_flag_);
|
||||||
} else if (strcmp(cmd, "unstop") == 0) {
|
} else if (strcmp(cmd, "stop") == 0) {
|
||||||
intptr_t stop_pc = sim_->get_pc() - Instr::kInstrSize;
|
int32_t value;
|
||||||
|
intptr_t stop_pc = sim_->get_pc() - 2 * Instr::kInstrSize;
|
||||||
Instr* stop_instr = reinterpret_cast<Instr*>(stop_pc);
|
Instr* stop_instr = reinterpret_cast<Instr*>(stop_pc);
|
||||||
if (stop_instr->ConditionField() == special_condition) {
|
Instr* msg_address =
|
||||||
stop_instr->SetInstructionBits(kNopInstr);
|
reinterpret_cast<Instr*>(stop_pc + Instr::kInstrSize);
|
||||||
|
if ((argc == 2) && (strcmp(arg1, "unstop") == 0)) {
|
||||||
|
// Remove the current stop.
|
||||||
|
if (sim_->isStopInstruction(stop_instr)) {
|
||||||
|
stop_instr->SetInstructionBits(kNopInstr);
|
||||||
|
msg_address->SetInstructionBits(kNopInstr);
|
||||||
|
} else {
|
||||||
|
PrintF("Not at debugger stop.\n");
|
||||||
|
}
|
||||||
|
} else if (argc == 3) {
|
||||||
|
// Print information about all/the specified breakpoint(s).
|
||||||
|
if (strcmp(arg1, "info") == 0) {
|
||||||
|
if (strcmp(arg2, "all") == 0) {
|
||||||
|
PrintF("Stop information:\n");
|
||||||
|
for (uint32_t i = 0; i < sim_->kNumOfWatchedStops; i++) {
|
||||||
|
sim_->PrintStopInfo(i);
|
||||||
|
}
|
||||||
|
} else if (GetValue(arg2, &value)) {
|
||||||
|
sim_->PrintStopInfo(value);
|
||||||
|
} else {
|
||||||
|
PrintF("Unrecognized argument.\n");
|
||||||
|
}
|
||||||
|
} else if (strcmp(arg1, "enable") == 0) {
|
||||||
|
// Enable all/the specified breakpoint(s).
|
||||||
|
if (strcmp(arg2, "all") == 0) {
|
||||||
|
for (uint32_t i = 0; i < sim_->kNumOfWatchedStops; i++) {
|
||||||
|
sim_->EnableStop(i);
|
||||||
|
}
|
||||||
|
} else if (GetValue(arg2, &value)) {
|
||||||
|
sim_->EnableStop(value);
|
||||||
|
} else {
|
||||||
|
PrintF("Unrecognized argument.\n");
|
||||||
|
}
|
||||||
|
} else if (strcmp(arg1, "disable") == 0) {
|
||||||
|
// Disable all/the specified breakpoint(s).
|
||||||
|
if (strcmp(arg2, "all") == 0) {
|
||||||
|
for (uint32_t i = 0; i < sim_->kNumOfWatchedStops; i++) {
|
||||||
|
sim_->DisableStop(i);
|
||||||
|
}
|
||||||
|
} else if (GetValue(arg2, &value)) {
|
||||||
|
sim_->DisableStop(value);
|
||||||
|
} else {
|
||||||
|
PrintF("Unrecognized argument.\n");
|
||||||
|
}
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
PrintF("Not at debugger stop.");
|
PrintF("Wrong usage. Use help command for more information.\n");
|
||||||
}
|
}
|
||||||
} else if ((strcmp(cmd, "t") == 0) || strcmp(cmd, "trace") == 0) {
|
} else if ((strcmp(cmd, "t") == 0) || strcmp(cmd, "trace") == 0) {
|
||||||
::v8::internal::FLAG_trace_sim = !::v8::internal::FLAG_trace_sim;
|
::v8::internal::FLAG_trace_sim = !::v8::internal::FLAG_trace_sim;
|
||||||
@ -455,11 +522,29 @@ void Debugger::Debug() {
|
|||||||
PrintF(" set a break point on the address\n");
|
PrintF(" set a break point on the address\n");
|
||||||
PrintF("del\n");
|
PrintF("del\n");
|
||||||
PrintF(" delete the breakpoint\n");
|
PrintF(" delete the breakpoint\n");
|
||||||
PrintF("unstop\n");
|
|
||||||
PrintF(" ignore the stop instruction at the current location");
|
|
||||||
PrintF(" from now on\n");
|
|
||||||
PrintF("trace (alias 't')\n");
|
PrintF("trace (alias 't')\n");
|
||||||
PrintF(" toogle the tracing of all executed statements\n");
|
PrintF(" toogle the tracing of all executed statements\n");
|
||||||
|
PrintF("stop feature:\n");
|
||||||
|
PrintF(" Description:\n");
|
||||||
|
PrintF(" Stops are debug instructions inserted by\n");
|
||||||
|
PrintF(" the Assembler::stop() function.\n");
|
||||||
|
PrintF(" When hitting a stop, the Simulator will\n");
|
||||||
|
PrintF(" stop and and give control to the Debugger.\n");
|
||||||
|
PrintF(" The first %d stop codes are watched:\n",
|
||||||
|
Simulator::kNumOfWatchedStops);
|
||||||
|
PrintF(" - They can be enabled / disabled: the Simulator\n");
|
||||||
|
PrintF(" will / won't stop when hitting them.\n");
|
||||||
|
PrintF(" - The Simulator keeps track of how many times they \n");
|
||||||
|
PrintF(" are met. (See the info command.) Going over a\n");
|
||||||
|
PrintF(" disabled stop still increases its counter. \n");
|
||||||
|
PrintF(" Commands:\n");
|
||||||
|
PrintF(" stop info all/<code> : print infos about number <code>\n");
|
||||||
|
PrintF(" or all stop(s).\n");
|
||||||
|
PrintF(" stop enable/disable all/<code> : enables / disables\n");
|
||||||
|
PrintF(" all or number <code> stop(s)\n");
|
||||||
|
PrintF(" stop unstop\n");
|
||||||
|
PrintF(" ignore the stop instruction at the current location\n");
|
||||||
|
PrintF(" from now on\n");
|
||||||
} else {
|
} else {
|
||||||
PrintF("Unknown command: %s\n", cmd);
|
PrintF("Unknown command: %s\n", cmd);
|
||||||
}
|
}
|
||||||
@ -643,9 +728,9 @@ Simulator::Simulator() {
|
|||||||
// the simulator. The external reference will be a function compiled for the
|
// the simulator. The external reference will be a function compiled for the
|
||||||
// host architecture. We need to call that function instead of trying to
|
// host architecture. We need to call that function instead of trying to
|
||||||
// execute it with the simulator. We do that by redirecting the external
|
// execute it with the simulator. We do that by redirecting the external
|
||||||
// reference to a swi (software-interrupt) instruction that is handled by
|
// reference to a svc (Supervisor Call) instruction that is handled by
|
||||||
// the simulator. We write the original destination of the jump just at a known
|
// the simulator. We write the original destination of the jump just at a known
|
||||||
// offset from the swi instruction so the simulator knows what to call.
|
// offset from the svc instruction so the simulator knows what to call.
|
||||||
class Redirection {
|
class Redirection {
|
||||||
public:
|
public:
|
||||||
Redirection(void* external_function, bool fp_return)
|
Redirection(void* external_function, bool fp_return)
|
||||||
@ -1434,8 +1519,8 @@ typedef double (*SimulatorRuntimeFPCall)(int32_t arg0,
|
|||||||
// Software interrupt instructions are used by the simulator to call into the
|
// Software interrupt instructions are used by the simulator to call into the
|
||||||
// C-based V8 runtime.
|
// C-based V8 runtime.
|
||||||
void Simulator::SoftwareInterrupt(Instr* instr) {
|
void Simulator::SoftwareInterrupt(Instr* instr) {
|
||||||
int swi = instr->SwiField();
|
int svc = instr->SvcField();
|
||||||
switch (swi) {
|
switch (svc) {
|
||||||
case call_rt_redirected: {
|
case call_rt_redirected: {
|
||||||
// Check if stack is aligned. Error if not aligned is reported below to
|
// Check if stack is aligned. Error if not aligned is reported below to
|
||||||
// include information on the function called.
|
// include information on the function called.
|
||||||
@ -1505,9 +1590,98 @@ void Simulator::SoftwareInterrupt(Instr* instr) {
|
|||||||
dbg.Debug();
|
dbg.Debug();
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
// stop uses all codes greater than 1 << 23.
|
||||||
default: {
|
default: {
|
||||||
UNREACHABLE();
|
if (svc >= (1 << 23)) {
|
||||||
break;
|
uint32_t code = svc & kStopCodeMask;
|
||||||
|
if (isWatchedStop(code)) {
|
||||||
|
IncreaseStopCounter(code);
|
||||||
|
}
|
||||||
|
// Stop if it is enabled, otherwise go on jumping over the stop
|
||||||
|
// and the message address.
|
||||||
|
if (isEnabledStop(code)) {
|
||||||
|
Debugger dbg(this);
|
||||||
|
dbg.Stop(instr);
|
||||||
|
} else {
|
||||||
|
set_pc(get_pc() + 2 * Instr::kInstrSize);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
// This is not a valid svc code.
|
||||||
|
UNREACHABLE();
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// Stop helper functions.
|
||||||
|
bool Simulator::isStopInstruction(Instr* instr) {
|
||||||
|
return (instr->Bits(27, 24) == 0xF) && (instr->SvcField() >= stop);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
bool Simulator::isWatchedStop(uint32_t code) {
|
||||||
|
ASSERT(code <= kMaxStopCode);
|
||||||
|
return code < kNumOfWatchedStops;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
bool Simulator::isEnabledStop(uint32_t code) {
|
||||||
|
ASSERT(code <= kMaxStopCode);
|
||||||
|
// Unwatched stops are always enabled.
|
||||||
|
return !isWatchedStop(code) ||
|
||||||
|
!(watched_stops[code].count & kStopDisabledBit);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void Simulator::EnableStop(uint32_t code) {
|
||||||
|
ASSERT(isWatchedStop(code));
|
||||||
|
if (!isEnabledStop(code)) {
|
||||||
|
watched_stops[code].count &= ~kStopDisabledBit;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void Simulator::DisableStop(uint32_t code) {
|
||||||
|
ASSERT(isWatchedStop(code));
|
||||||
|
if (isEnabledStop(code)) {
|
||||||
|
watched_stops[code].count |= kStopDisabledBit;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void Simulator::IncreaseStopCounter(uint32_t code) {
|
||||||
|
ASSERT(code <= kMaxStopCode);
|
||||||
|
ASSERT(isWatchedStop(code));
|
||||||
|
if ((watched_stops[code].count & ~(1 << 31)) == 0x7fffffff) {
|
||||||
|
PrintF("Stop counter for code %i has overflowed.\n"
|
||||||
|
"Enabling this code and reseting the counter to 0.\n", code);
|
||||||
|
watched_stops[code].count = 0;
|
||||||
|
EnableStop(code);
|
||||||
|
} else {
|
||||||
|
watched_stops[code].count++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// Print a stop status.
|
||||||
|
void Simulator::PrintStopInfo(uint32_t code) {
|
||||||
|
ASSERT(code <= kMaxStopCode);
|
||||||
|
if (!isWatchedStop(code)) {
|
||||||
|
PrintF("Stop not watched.");
|
||||||
|
} else {
|
||||||
|
const char* state = isEnabledStop(code) ? "Enabled" : "Disabled";
|
||||||
|
int32_t count = watched_stops[code].count & ~kStopDisabledBit;
|
||||||
|
// Don't print the state of unused breakpoints.
|
||||||
|
if (count != 0) {
|
||||||
|
if (watched_stops[code].desc) {
|
||||||
|
PrintF("stop %i - 0x%x: \t%s, \tcounter = %i, \t%s\n",
|
||||||
|
code, code, state, count, watched_stops[code].desc);
|
||||||
|
} else {
|
||||||
|
PrintF("stop %i - 0x%x: \t%s, \tcounter = %i\n",
|
||||||
|
code, code, state, count);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -2216,73 +2390,6 @@ void Simulator::DecodeType7(Instr* instr) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
void Simulator::DecodeUnconditional(Instr* instr) {
|
|
||||||
if (instr->Bits(7, 4) == 0x0B && instr->Bits(27, 25) == 0 && instr->HasL()) {
|
|
||||||
// Load halfword instruction, either register or immediate offset.
|
|
||||||
int rd = instr->RdField();
|
|
||||||
int rn = instr->RnField();
|
|
||||||
int32_t rn_val = get_register(rn);
|
|
||||||
int32_t addr = 0;
|
|
||||||
int32_t offset;
|
|
||||||
if (instr->Bit(22) == 0) {
|
|
||||||
// Register offset.
|
|
||||||
int rm = instr->RmField();
|
|
||||||
offset = get_register(rm);
|
|
||||||
} else {
|
|
||||||
// Immediate offset
|
|
||||||
offset = instr->Bits(3, 0) + (instr->Bits(11, 8) << 4);
|
|
||||||
}
|
|
||||||
switch (instr->PUField()) {
|
|
||||||
case 0: {
|
|
||||||
// Post index, negative.
|
|
||||||
ASSERT(!instr->HasW());
|
|
||||||
addr = rn_val;
|
|
||||||
rn_val -= offset;
|
|
||||||
set_register(rn, rn_val);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
case 1: {
|
|
||||||
// Post index, positive.
|
|
||||||
ASSERT(!instr->HasW());
|
|
||||||
addr = rn_val;
|
|
||||||
rn_val += offset;
|
|
||||||
set_register(rn, rn_val);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
case 2: {
|
|
||||||
// Pre index or offset, negative.
|
|
||||||
rn_val -= offset;
|
|
||||||
addr = rn_val;
|
|
||||||
if (instr->HasW()) {
|
|
||||||
set_register(rn, rn_val);
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
case 3: {
|
|
||||||
// Pre index or offset, positive.
|
|
||||||
rn_val += offset;
|
|
||||||
addr = rn_val;
|
|
||||||
if (instr->HasW()) {
|
|
||||||
set_register(rn, rn_val);
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
default: {
|
|
||||||
// The PU field is a 2-bit field.
|
|
||||||
UNREACHABLE();
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
// Not sign extending, so load as unsigned.
|
|
||||||
uint16_t halfword = ReadH(addr, instr);
|
|
||||||
set_register(rd, halfword);
|
|
||||||
} else {
|
|
||||||
Debugger dbg(this);
|
|
||||||
dbg.Stop(instr);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
// void Simulator::DecodeTypeVFP(Instr* instr)
|
// void Simulator::DecodeTypeVFP(Instr* instr)
|
||||||
// The Following ARMv7 VFPv instructions are currently supported.
|
// The Following ARMv7 VFPv instructions are currently supported.
|
||||||
// vmov :Sn = Rt
|
// vmov :Sn = Rt
|
||||||
@ -2655,7 +2762,7 @@ void Simulator::InstructionDecode(Instr* instr) {
|
|||||||
PrintF(" 0x%08x %s\n", reinterpret_cast<intptr_t>(instr), buffer.start());
|
PrintF(" 0x%08x %s\n", reinterpret_cast<intptr_t>(instr), buffer.start());
|
||||||
}
|
}
|
||||||
if (instr->ConditionField() == special_condition) {
|
if (instr->ConditionField() == special_condition) {
|
||||||
DecodeUnconditional(instr);
|
UNIMPLEMENTED();
|
||||||
} else if (ConditionallyExecute(instr)) {
|
} else if (ConditionallyExecute(instr)) {
|
||||||
switch (instr->TypeField()) {
|
switch (instr->TypeField()) {
|
||||||
case 0:
|
case 0:
|
||||||
|
@ -226,6 +226,15 @@ class Simulator {
|
|||||||
void HandleRList(Instr* instr, bool load);
|
void HandleRList(Instr* instr, bool load);
|
||||||
void SoftwareInterrupt(Instr* instr);
|
void SoftwareInterrupt(Instr* instr);
|
||||||
|
|
||||||
|
// Stop helper functions.
|
||||||
|
inline bool isStopInstruction(Instr* instr);
|
||||||
|
inline bool isWatchedStop(uint32_t bkpt_code);
|
||||||
|
inline bool isEnabledStop(uint32_t bkpt_code);
|
||||||
|
inline void EnableStop(uint32_t bkpt_code);
|
||||||
|
inline void DisableStop(uint32_t bkpt_code);
|
||||||
|
inline void IncreaseStopCounter(uint32_t bkpt_code);
|
||||||
|
void PrintStopInfo(uint32_t code);
|
||||||
|
|
||||||
// Read and write memory.
|
// Read and write memory.
|
||||||
inline uint8_t ReadBU(int32_t addr);
|
inline uint8_t ReadBU(int32_t addr);
|
||||||
inline int8_t ReadB(int32_t addr);
|
inline int8_t ReadB(int32_t addr);
|
||||||
@ -252,7 +261,6 @@ class Simulator {
|
|||||||
void DecodeType5(Instr* instr);
|
void DecodeType5(Instr* instr);
|
||||||
void DecodeType6(Instr* instr);
|
void DecodeType6(Instr* instr);
|
||||||
void DecodeType7(Instr* instr);
|
void DecodeType7(Instr* instr);
|
||||||
void DecodeUnconditional(Instr* instr);
|
|
||||||
|
|
||||||
// Support for VFP.
|
// Support for VFP.
|
||||||
void DecodeTypeVFP(Instr* instr);
|
void DecodeTypeVFP(Instr* instr);
|
||||||
@ -317,6 +325,23 @@ class Simulator {
|
|||||||
// Registered breakpoints.
|
// Registered breakpoints.
|
||||||
Instr* break_pc_;
|
Instr* break_pc_;
|
||||||
instr_t break_instr_;
|
instr_t break_instr_;
|
||||||
|
|
||||||
|
// A stop is watched if its code is less than kNumOfWatchedStops.
|
||||||
|
// Only watched stops support enabling/disabling and the counter feature.
|
||||||
|
static const uint32_t kNumOfWatchedStops = 256;
|
||||||
|
|
||||||
|
// Breakpoint is disabled if bit 31 is set.
|
||||||
|
static const uint32_t kStopDisabledBit = 1 << 31;
|
||||||
|
|
||||||
|
// A stop is enabled, meaning the simulator will stop when meeting the
|
||||||
|
// instruction, if bit 31 of watched_stops[code].count is unset.
|
||||||
|
// The value watched_stops[code].count & ~(1 << 31) indicates how many times
|
||||||
|
// the breakpoint was hit or gone through.
|
||||||
|
struct StopCoundAndDesc {
|
||||||
|
uint32_t count;
|
||||||
|
char* desc;
|
||||||
|
};
|
||||||
|
StopCoundAndDesc watched_stops[kNumOfWatchedStops];
|
||||||
};
|
};
|
||||||
|
|
||||||
} } // namespace assembler::arm
|
} } // namespace assembler::arm
|
||||||
|
Loading…
Reference in New Issue
Block a user