diff options
| -rw-r--r-- | compiler/cfi_test.h | 4 | ||||
| -rw-r--r-- | compiler/optimizing/graph_visualizer.cc | 9 | ||||
| -rw-r--r-- | disassembler/disassembler.h | 13 | ||||
| -rw-r--r-- | disassembler/disassembler_arm.cc | 26 | ||||
| -rw-r--r-- | disassembler/disassembler_arm64.cc | 10 | ||||
| -rw-r--r-- | disassembler/disassembler_arm64.h | 11 | ||||
| -rw-r--r-- | oatdump/oatdump.cc | 1 |
7 files changed, 62 insertions, 12 deletions
diff --git a/compiler/cfi_test.h b/compiler/cfi_test.h index 230cb9aeea..f8b7460935 100644 --- a/compiler/cfi_test.h +++ b/compiler/cfi_test.h @@ -55,7 +55,9 @@ class CFITest : public dwarf::DwarfTest { kCFIFormat, 0, &debug_frame_data_, &debug_frame_patches); ReformatCfi(Objdump(false, "-W"), &lines); // Pretty-print assembly. - auto* opts = new DisassemblerOptions(false, actual_asm.data(), true); + const uint8_t* asm_base = actual_asm.data(); + const uint8_t* asm_end = asm_base + actual_asm.size(); + auto* opts = new DisassemblerOptions(false, asm_base, asm_end, true); std::unique_ptr<Disassembler> disasm(Disassembler::Create(isa, opts)); std::stringstream stream; const uint8_t* base = actual_asm.data() + (isa == kThumb2 ? 1 : 0); diff --git a/compiler/optimizing/graph_visualizer.cc b/compiler/optimizing/graph_visualizer.cc index 2038c88e55..6aec463549 100644 --- a/compiler/optimizing/graph_visualizer.cc +++ b/compiler/optimizing/graph_visualizer.cc @@ -98,7 +98,9 @@ typedef Disassembler* create_disasm_prototype(InstructionSet instruction_set, DisassemblerOptions* options); class HGraphVisualizerDisassembler { public: - HGraphVisualizerDisassembler(InstructionSet instruction_set, const uint8_t* base_address) + HGraphVisualizerDisassembler(InstructionSet instruction_set, + const uint8_t* base_address, + const uint8_t* end_address) : instruction_set_(instruction_set), disassembler_(nullptr) { libart_disassembler_handle_ = dlopen(kIsDebugBuild ? "libartd-disassembler.so" : "libart-disassembler.so", RTLD_NOW); @@ -119,6 +121,7 @@ class HGraphVisualizerDisassembler { instruction_set, new DisassemblerOptions(/* absolute_addresses */ false, base_address, + end_address, /* can_read_literals */ true))); } @@ -174,7 +177,9 @@ class HGraphVisualizerPrinter : public HGraphDelegateVisitor { disassembler_(disasm_info_ != nullptr ? new HGraphVisualizerDisassembler( codegen_.GetInstructionSet(), - codegen_.GetAssembler().CodeBufferBaseAddress()) + codegen_.GetAssembler().CodeBufferBaseAddress(), + codegen_.GetAssembler().CodeBufferBaseAddress() + + codegen_.GetAssembler().CodeSize()) : nullptr), indent_(0) {} diff --git a/disassembler/disassembler.h b/disassembler/disassembler.h index b99e5c2df4..b08031587f 100644 --- a/disassembler/disassembler.h +++ b/disassembler/disassembler.h @@ -31,16 +31,23 @@ class DisassemblerOptions { // Should the disassembler print absolute or relative addresses. const bool absolute_addresses_; - // Base addess for calculating relative code offsets when absolute_addresses_ is false. + // Base address for calculating relative code offsets when absolute_addresses_ is false. const uint8_t* const base_address_; + // End address (exclusive); + const uint8_t* const end_address_; + // If set, the disassembler is allowed to look at load targets in literal // pools. const bool can_read_literals_; - DisassemblerOptions(bool absolute_addresses, const uint8_t* base_address, + DisassemblerOptions(bool absolute_addresses, + const uint8_t* base_address, + const uint8_t* end_address, bool can_read_literals) - : absolute_addresses_(absolute_addresses), base_address_(base_address), + : absolute_addresses_(absolute_addresses), + base_address_(base_address), + end_address_(end_address), can_read_literals_(can_read_literals) {} private: 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 diff --git a/disassembler/disassembler_arm64.cc b/disassembler/disassembler_arm64.cc index 5f8871470d..6a9afe5740 100644 --- a/disassembler/disassembler_arm64.cc +++ b/disassembler/disassembler_arm64.cc @@ -63,9 +63,17 @@ void CustomDisassembler::VisitLoadLiteral(const vixl::Instruction* instr) { return; } + // 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). void* data_address = instr->LiteralAddress<void*>(); - vixl::Instr op = instr->Mask(vixl::LoadLiteralMask); + if (data_address < base_address_ || data_address >= end_address_) { + AppendToOutput(" (?)"); + return; + } + // Output information on literal. + vixl::Instr op = instr->Mask(vixl::LoadLiteralMask); switch (op) { case vixl::LDR_w_lit: case vixl::LDR_x_lit: diff --git a/disassembler/disassembler_arm64.h b/disassembler/disassembler_arm64.h index 44fa53f9f6..a4e5ee8a43 100644 --- a/disassembler/disassembler_arm64.h +++ b/disassembler/disassembler_arm64.h @@ -30,8 +30,11 @@ namespace arm64 { class CustomDisassembler FINAL : public vixl::Disassembler { public: - explicit CustomDisassembler(DisassemblerOptions* options) : - vixl::Disassembler(), read_literals_(options->can_read_literals_) { + explicit CustomDisassembler(DisassemblerOptions* options) + : vixl::Disassembler(), + read_literals_(options->can_read_literals_), + base_address_(options->base_address_), + end_address_(options->end_address_) { if (!options->absolute_addresses_) { MapCodeAddress(0, reinterpret_cast<const vixl::Instruction*>(options->base_address_)); } @@ -55,6 +58,10 @@ class CustomDisassembler FINAL : public vixl::Disassembler { // true | 0x72681558: 1c000acb ldr s11, pc+344 (addr 0x726816b0) // false | 0x72681558: 1c000acb ldr s11, pc+344 (addr 0x726816b0) (3.40282e+38) const bool read_literals_; + + // Valid address range: [base_address_, end_address_) + const void* const base_address_; + const void* const end_address_; }; class DisassemblerArm64 FINAL : public Disassembler { diff --git a/oatdump/oatdump.cc b/oatdump/oatdump.cc index d2ab699599..f5458c067d 100644 --- a/oatdump/oatdump.cc +++ b/oatdump/oatdump.cc @@ -335,6 +335,7 @@ class OatDumper { disassembler_(Disassembler::Create(instruction_set_, new DisassemblerOptions(options_.absolute_addresses_, oat_file.Begin(), + oat_file.End(), true /* can_read_literals_ */))) { CHECK(options_.class_loader_ != nullptr); CHECK(options_.class_filter_ != nullptr); |