summaryrefslogtreecommitdiff
path: root/disassembler/disassembler_arm.cc
diff options
context:
space:
mode:
Diffstat (limited to 'disassembler/disassembler_arm.cc')
-rw-r--r--disassembler/disassembler_arm.cc26
1 files changed, 23 insertions, 3 deletions
diff --git a/disassembler/disassembler_arm.cc b/disassembler/disassembler_arm.cc
index bcb043883b..286faf215a 100644
--- a/disassembler/disassembler_arm.cc
+++ b/disassembler/disassembler_arm.cc
@@ -418,7 +418,12 @@ std::ostream& operator<<(std::ostream& os, T2LitType type) {
return os << static_cast<int>(type);
}
-void DumpThumb2Literal(std::ostream& args, const uint8_t* instr_ptr, uint32_t U, uint32_t imm32,
+void DumpThumb2Literal(std::ostream& args,
+ const uint8_t* instr_ptr,
+ const uintptr_t lo_adr,
+ const uintptr_t hi_adr,
+ uint32_t U,
+ uint32_t imm32,
T2LitType type) {
// Literal offsets (imm32) are not required to be aligned so we may need unaligned access.
typedef const int16_t unaligned_int16_t __attribute__ ((aligned (1)));
@@ -428,8 +433,16 @@ void DumpThumb2Literal(std::ostream& args, const uint8_t* instr_ptr, uint32_t U,
typedef const int64_t unaligned_int64_t __attribute__ ((aligned (1)));
typedef const uint64_t unaligned_uint64_t __attribute__ ((aligned (1)));
+ // Get address of literal. Bail if not within expected buffer range to
+ // avoid trying to fetch invalid literals (we can encounter this when
+ // interpreting raw data as instructions).
uintptr_t pc = RoundDown(reinterpret_cast<intptr_t>(instr_ptr) + 4, 4);
uintptr_t lit_adr = U ? pc + imm32 : pc - imm32;
+ if (lit_adr < lo_adr || lit_adr >= hi_adr) {
+ args << " ; (?)";
+ return;
+ }
+
args << " ; ";
switch (type) {
case kT2LitUByte:
@@ -482,6 +495,10 @@ size_t DisassemblerArm::DumpThumb32(std::ostream& os, const uint8_t* instr_ptr)
return DumpThumb16(os, instr_ptr);
}
+ // Set valid address range of backing buffer.
+ const uintptr_t lo_adr = reinterpret_cast<intptr_t>(GetDisassemblerOptions()->base_address_);
+ const uintptr_t hi_adr = reinterpret_cast<intptr_t>(GetDisassemblerOptions()->end_address_);
+
uint32_t op2 = (instr >> 20) & 0x7F;
std::ostringstream opcode;
std::ostringstream args;
@@ -824,7 +841,7 @@ size_t DisassemblerArm::DumpThumb32(std::ostream& os, const uint8_t* instr_ptr)
args << d << ", [" << Rn << ", #" << ((U == 1) ? "" : "-")
<< (imm8 << 2) << "]";
if (Rn.r == 15 && U == 1) {
- DumpThumb2Literal(args, instr_ptr, U, imm8 << 2, kT2LitHexLong);
+ DumpThumb2Literal(args, instr_ptr, lo_adr, hi_adr, U, imm8 << 2, kT2LitHexLong);
}
} else if (Rn.r == 13 && W == 1 && U == L) { // VPUSH/VPOP
opcode << (L == 1 ? "vpop" : "vpush");
@@ -1410,7 +1427,7 @@ size_t DisassemblerArm::DumpThumb32(std::ostream& os, const uint8_t* instr_ptr)
};
DCHECK_LT(op2 >> 1, arraysize(lit_type));
DCHECK_NE(lit_type[op2 >> 1], kT2LitInvalid);
- DumpThumb2Literal(args, instr_ptr, U, imm12, lit_type[op2 >> 1]);
+ DumpThumb2Literal(args, instr_ptr, lo_adr, hi_adr, U, imm12, lit_type[op2 >> 1]);
}
} else if ((instr & 0xFC0) == 0) {
opcode << ldr_str << sign << type << ".w";
@@ -1711,10 +1728,13 @@ size_t DisassemblerArm::DumpThumb16(std::ostream& os, const uint8_t* instr_ptr)
break;
}
} else if (opcode1 == 0x12 || opcode1 == 0x13) { // 01001x
+ const uintptr_t lo_adr = reinterpret_cast<intptr_t>(GetDisassemblerOptions()->base_address_);
+ const uintptr_t hi_adr = reinterpret_cast<intptr_t>(GetDisassemblerOptions()->end_address_);
ThumbRegister Rt(instr, 8);
uint16_t imm8 = instr & 0xFF;
opcode << "ldr";
args << Rt << ", [pc, #" << (imm8 << 2) << "]";
+ DumpThumb2Literal(args, instr_ptr, lo_adr, hi_adr, /*U*/ 1u, imm8 << 2, kT2LitHexWord);
} else if ((opcode1 >= 0x14 && opcode1 <= 0x17) || // 0101xx
(opcode1 >= 0x18 && opcode1 <= 0x1f) || // 011xxx
(opcode1 >= 0x20 && opcode1 <= 0x27)) { // 100xxx