diff options
Diffstat (limited to 'disassembler/disassembler_arm.cc')
-rw-r--r-- | disassembler/disassembler_arm.cc | 26 |
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 |