Improve ARM-Simulator.

This patch
- removes the unimplemented code crash when rendering invalid/unknown instructions and prints "unknown" instead.
- prints the beginning of the constant pool marker.
- adds "da" as a shortcut for "disasm".
- print hexadecimal representation of double and single registers. This makes it easier to debug move/conversion code that uses temporary int32 values in floating point registers.
- annotates the stack with short prints of the values (HeapObjects and smis),
- makes disasm take an address or a register as second argument without a third argument, which defaults to printing ten instructions.

Review URL: http://codereview.chromium.org/6676042

git-svn-id: http://v8.googlecode.com/svn/branches/bleeding_edge@7279 ce2b1a6d-e550-0410-aec6-3dcde31c8c00
This commit is contained in:
karlklose@chromium.org 2011-03-21 09:59:58 +00:00
parent b604befe61
commit e820926108
4 changed files with 100 additions and 28 deletions

View File

@ -2748,8 +2748,8 @@ void Assembler::CheckConstPool(bool force_emit, bool require_jump) {
RecordComment("[ Constant Pool"); RecordComment("[ Constant Pool");
// Put down constant pool marker "Undefined instruction" as specified by // Put down constant pool marker "Undefined instruction" as specified by
// A3.1 Instruction set encoding. // A5.6 (ARMv7) Instruction set encoding.
emit(0x03000000 | num_prinfo_); emit(kConstantPoolMarker | num_prinfo_);
// Emit constant pool entries. // Emit constant pool entries.
for (int i = 0; i < num_prinfo_; i++) { for (int i = 0; i < num_prinfo_; i++) {

View File

@ -89,6 +89,11 @@
namespace v8 { namespace v8 {
namespace internal { namespace internal {
// Constant pool marker.
static const int kConstantPoolMarkerMask = 0xffe00000;
static const int kConstantPoolMarker = 0x0c000000;
static const int kConstantPoolLengthMask = 0x001ffff;
// Number of registers in normal ARM mode. // Number of registers in normal ARM mode.
static const int kNumRegisters = 16; static const int kNumRegisters = 16;

View File

@ -89,6 +89,9 @@ class Decoder {
// Returns the length of the disassembled machine instruction in bytes. // Returns the length of the disassembled machine instruction in bytes.
int InstructionDecode(byte* instruction); int InstructionDecode(byte* instruction);
static bool IsConstantPoolAt(byte* instr_ptr);
static int ConstantPoolSizeAt(byte* instr_ptr);
private: private:
// Bottleneck functions to print into the out_buffer. // Bottleneck functions to print into the out_buffer.
void PrintChar(const char ch); void PrintChar(const char ch);
@ -899,6 +902,7 @@ void Decoder::DecodeType2(Instruction* instr) {
case da_x: { case da_x: {
if (instr->HasW()) { if (instr->HasW()) {
Unknown(instr); // not used in V8 Unknown(instr); // not used in V8
return;
} }
Format(instr, "'memop'cond'b 'rd, ['rn], #-'off12"); Format(instr, "'memop'cond'b 'rd, ['rn], #-'off12");
break; break;
@ -906,6 +910,7 @@ void Decoder::DecodeType2(Instruction* instr) {
case ia_x: { case ia_x: {
if (instr->HasW()) { if (instr->HasW()) {
Unknown(instr); // not used in V8 Unknown(instr); // not used in V8
return;
} }
Format(instr, "'memop'cond'b 'rd, ['rn], #+'off12"); Format(instr, "'memop'cond'b 'rd, ['rn], #+'off12");
break; break;
@ -992,13 +997,17 @@ void Decoder::DecodeType3(Instruction* instr) {
void Decoder::DecodeType4(Instruction* instr) { void Decoder::DecodeType4(Instruction* instr) {
ASSERT(instr->Bit(22) == 0); // Privileged mode currently not supported. if (instr->Bit(22) != 0) {
// Privileged mode currently not supported.
Unknown(instr);
} else {
if (instr->HasL()) { if (instr->HasL()) {
Format(instr, "ldm'cond'pu 'rn'w, 'rlist"); Format(instr, "ldm'cond'pu 'rn'w, 'rlist");
} else { } else {
Format(instr, "stm'cond'pu 'rn'w, 'rlist"); Format(instr, "stm'cond'pu 'rn'w, 'rlist");
} }
} }
}
void Decoder::DecodeType5(Instruction* instr) { void Decoder::DecodeType5(Instruction* instr) {
@ -1042,6 +1051,8 @@ int Decoder::DecodeType7(Instruction* instr) {
// vmov: Rt = Sn // vmov: Rt = Sn
// vcvt: Dd = Sm // vcvt: Dd = Sm
// vcvt: Sd = Dm // vcvt: Sd = Dm
// Dd = vabs(Dm)
// Dd = vneg(Dm)
// Dd = vadd(Dn, Dm) // Dd = vadd(Dn, Dm)
// Dd = vsub(Dn, Dm) // Dd = vsub(Dn, Dm)
// Dd = vmul(Dn, Dm) // Dd = vmul(Dn, Dm)
@ -1297,7 +1308,23 @@ void Decoder::DecodeType6CoprocessorIns(Instruction* instr) {
break; break;
} }
} else { } else {
UNIMPLEMENTED(); // Not used by V8. Unknown(instr); // Not used by V8.
}
}
bool Decoder::IsConstantPoolAt(byte* instr_ptr) {
int instruction_bits = *(reinterpret_cast<int*>(instr_ptr));
return (instruction_bits & kConstantPoolMarkerMask) == kConstantPoolMarker;
}
int Decoder::ConstantPoolSizeAt(byte* instr_ptr) {
if (IsConstantPoolAt(instr_ptr)) {
int instruction_bits = *(reinterpret_cast<int*>(instr_ptr));
return instruction_bits & kConstantPoolLengthMask;
} else {
return -1;
} }
} }
@ -1310,7 +1337,15 @@ int Decoder::InstructionDecode(byte* instr_ptr) {
"%08x ", "%08x ",
instr->InstructionBits()); instr->InstructionBits());
if (instr->ConditionField() == kSpecialCondition) { if (instr->ConditionField() == kSpecialCondition) {
UNIMPLEMENTED(); Unknown(instr);
return Instruction::kInstrSize;
}
int instruction_bits = *(reinterpret_cast<int*>(instr_ptr));
if ((instruction_bits & kConstantPoolMarkerMask) == kConstantPoolMarker) {
out_buffer_pos_ += OS::SNPrintF(out_buffer_ + out_buffer_pos_,
"constant pool begin (length %d)",
instruction_bits &
kConstantPoolLengthMask);
return Instruction::kInstrSize; return Instruction::kInstrSize;
} }
switch (instr->TypeValue()) { switch (instr->TypeValue()) {
@ -1413,12 +1448,7 @@ int Disassembler::InstructionDecode(v8::internal::Vector<char> buffer,
int Disassembler::ConstantPoolSizeAt(byte* instruction) { int Disassembler::ConstantPoolSizeAt(byte* instruction) {
int instruction_bits = *(reinterpret_cast<int*>(instruction)); return v8::internal::Decoder::ConstantPoolSizeAt(instruction);
if ((instruction_bits & 0xfff00000) == 0x03000000) {
return instruction_bits & 0x0000ffff;
} else {
return -1;
}
} }

View File

@ -316,16 +316,26 @@ void ArmDebugger::Debug() {
} }
for (int i = 0; i < kNumVFPDoubleRegisters; i++) { for (int i = 0; i < kNumVFPDoubleRegisters; i++) {
dvalue = GetVFPDoubleRegisterValue(i); dvalue = GetVFPDoubleRegisterValue(i);
PrintF("%3s: %f\n", uint64_t as_words = BitCast<uint64_t>(dvalue);
VFPRegisters::Name(i, true), dvalue); PrintF("%3s: %f 0x%08x %08x\n",
VFPRegisters::Name(i, true),
dvalue,
static_cast<uint32_t>(as_words >> 32),
static_cast<uint32_t>(as_words & 0xffffffff));
} }
} else { } else {
if (GetValue(arg1, &value)) { if (GetValue(arg1, &value)) {
PrintF("%s: 0x%08x %d \n", arg1, value, value); PrintF("%s: 0x%08x %d \n", arg1, value, value);
} else if (GetVFPSingleValue(arg1, &svalue)) { } else if (GetVFPSingleValue(arg1, &svalue)) {
PrintF("%s: %f \n", arg1, svalue); uint32_t as_word = BitCast<uint32_t>(svalue);
PrintF("%s: %f 0x%08x\n", arg1, svalue, as_word);
} else if (GetVFPDoubleValue(arg1, &dvalue)) { } else if (GetVFPDoubleValue(arg1, &dvalue)) {
PrintF("%s: %f \n", arg1, dvalue); uint64_t as_words = BitCast<uint64_t>(dvalue);
PrintF("%s: %f 0x%08x %08x\n",
arg1,
dvalue,
static_cast<uint32_t>(as_words >> 32),
static_cast<uint32_t>(as_words & 0xffffffff));
} else { } else {
PrintF("%s unrecognized\n", arg1); PrintF("%s unrecognized\n", arg1);
} }
@ -380,11 +390,24 @@ void ArmDebugger::Debug() {
end = cur + words; end = cur + words;
while (cur < end) { while (cur < end) {
PrintF(" 0x%08x: 0x%08x %10d\n", PrintF(" 0x%08x: 0x%08x %10d",
reinterpret_cast<intptr_t>(cur), *cur, *cur); reinterpret_cast<intptr_t>(cur), *cur, *cur);
HeapObject* obj = reinterpret_cast<HeapObject*>(*cur);
int value = *cur;
Heap* current_heap = v8::internal::Isolate::Current()->heap();
if (current_heap->Contains(obj) || ((value & 1) == 0)) {
PrintF(" (");
if ((value & 1) == 0) {
PrintF("smi %d", value / 2);
} else {
obj->ShortPrint();
}
PrintF(")");
}
PrintF("\n");
cur++; cur++;
} }
} else if (strcmp(cmd, "disasm") == 0) { } else if (strcmp(cmd, "disasm") == 0 || strcmp(cmd, "di") == 0) {
disasm::NameConverter converter; disasm::NameConverter converter;
disasm::Disassembler dasm(converter); disasm::Disassembler dasm(converter);
// use a reasonably large buffer // use a reasonably large buffer
@ -398,12 +421,24 @@ void ArmDebugger::Debug() {
cur = reinterpret_cast<byte*>(sim_->get_pc()); cur = reinterpret_cast<byte*>(sim_->get_pc());
end = cur + (10 * Instruction::kInstrSize); end = cur + (10 * Instruction::kInstrSize);
} else if (argc == 2) { } else if (argc == 2) {
int regnum = Registers::Number(arg1);
if (regnum != kNoRegister || strncmp(arg1, "0x", 2) == 0) {
// The argument is an address or a register name.
int32_t value;
if (GetValue(arg1, &value)) {
cur = reinterpret_cast<byte*>(value);
// Disassemble 10 instructions at <arg1>.
end = cur + (10 * Instruction::kInstrSize);
}
} else {
// The argument is the number of instructions.
int32_t value; int32_t value;
if (GetValue(arg1, &value)) { if (GetValue(arg1, &value)) {
cur = reinterpret_cast<byte*>(sim_->get_pc()); cur = reinterpret_cast<byte*>(sim_->get_pc());
// Disassemble <arg1> instructions. // Disassemble <arg1> instructions.
end = cur + (value * Instruction::kInstrSize); end = cur + (value * Instruction::kInstrSize);
} }
}
} else { } else {
int32_t value1; int32_t value1;
int32_t value2; int32_t value2;
@ -524,8 +559,10 @@ void ArmDebugger::Debug() {
PrintF("mem <address> [<words>]\n"); PrintF("mem <address> [<words>]\n");
PrintF(" dump memory content, default dump 10 words)\n"); PrintF(" dump memory content, default dump 10 words)\n");
PrintF("disasm [<instructions>]\n"); PrintF("disasm [<instructions>]\n");
PrintF("disasm [[<address>] <instructions>]\n"); PrintF("disasm [<address/register>]\n");
PrintF(" disassemble code, default is 10 instructions from pc\n"); PrintF("disasm [[<address/register>] <instructions>]\n");
PrintF(" disassemble code, default is 10 instructions\n");
PrintF(" from pc (alias 'di')\n");
PrintF("gdb\n"); PrintF("gdb\n");
PrintF(" enter gdb\n"); PrintF(" enter gdb\n");
PrintF("break <address>\n"); PrintF("break <address>\n");