From 34fa79ece5b3a1940d412cd94dbdcc4225aae72f Mon Sep 17 00:00:00 2001 From: Brian Carlstrom Date: Sun, 14 Sep 2014 20:34:17 -0700 Subject: [PATCH] Avoid printing absolute addresses in oatdump - Added printing of OatClass offsets. - Added printing of OatMethod offsets. - Added bounds checks for code size size, code size, mapping table, gc map, vmap table. - Added sanity check of 100k for code size. - Added partial disassembly of questionable code. - Added --no-disassemble to disable disassembly. - Added --no-dump:vmap to disable vmap dumping. - Reordered OatMethod info to be in file order. Bug: 15567083 Change-Id: Id86a21e06d4a28f29f16fd018cba7e55c57f849a --- build/Android.gtest.mk | 1 + disassembler/disassembler.cc | 22 +- disassembler/disassembler.h | 33 ++- disassembler/disassembler_arm.cc | 14 +- disassembler/disassembler_arm.h | 3 +- disassembler/disassembler_arm64.cc | 3 +- disassembler/disassembler_arm64.h | 2 +- disassembler/disassembler_mips.cc | 15 +- disassembler/disassembler_mips.h | 3 +- disassembler/disassembler_x86.cc | 8 +- disassembler/disassembler_x86.h | 4 +- oatdump/oatdump.cc | 431 +++++++++++++++++++++++++++--------- runtime/base/stringprintf_test.cc | 29 +++ runtime/oat_file-inl.h | 49 ++++ runtime/oat_file.cc | 47 ++-- runtime/oat_file.h | 34 ++- runtime/verifier/method_verifier.cc | 8 +- 17 files changed, 542 insertions(+), 164 deletions(-) create mode 100644 runtime/base/stringprintf_test.cc diff --git a/build/Android.gtest.mk b/build/Android.gtest.mk index 9ee3b6965..a7d852ba3 100644 --- a/build/Android.gtest.mk +++ b/build/Android.gtest.mk @@ -76,6 +76,7 @@ RUNTIME_GTEST_COMMON_SRC_FILES := \ runtime/base/histogram_test.cc \ runtime/base/mutex_test.cc \ runtime/base/scoped_flock_test.cc \ + runtime/base/stringprintf_test.cc \ runtime/base/timing_logger_test.cc \ runtime/base/unix_file/fd_file_test.cc \ runtime/base/unix_file/mapped_file_test.cc \ diff --git a/disassembler/disassembler.cc b/disassembler/disassembler.cc index 41ee21365..c97bf64c5 100644 --- a/disassembler/disassembler.cc +++ b/disassembler/disassembler.cc @@ -19,6 +19,7 @@ #include #include "base/logging.h" +#include "base/stringprintf.h" #include "disassembler_arm.h" #include "disassembler_arm64.h" #include "disassembler_mips.h" @@ -26,21 +27,30 @@ namespace art { -Disassembler* Disassembler::Create(InstructionSet instruction_set) { +Disassembler* Disassembler::Create(InstructionSet instruction_set, DisassemblerOptions* options) { if (instruction_set == kArm || instruction_set == kThumb2) { - return new arm::DisassemblerArm(); + return new arm::DisassemblerArm(options); } else if (instruction_set == kArm64) { - return new arm64::DisassemblerArm64(); + return new arm64::DisassemblerArm64(options); } else if (instruction_set == kMips) { - return new mips::DisassemblerMips(); + return new mips::DisassemblerMips(options); } else if (instruction_set == kX86) { - return new x86::DisassemblerX86(false); + return new x86::DisassemblerX86(options, false); } else if (instruction_set == kX86_64) { - return new x86::DisassemblerX86(true); + return new x86::DisassemblerX86(options, true); } else { UNIMPLEMENTED(FATAL) << "no disassembler for " << instruction_set; return NULL; } } +std::string Disassembler::FormatInstructionPointer(const uint8_t* begin) { + if (disassembler_options_->absolute_addresses_) { + return StringPrintf("%p", begin); + } else { + size_t offset = begin - disassembler_options_->base_address_; + return StringPrintf("0x%08zx", offset); + } +} + } // namespace art diff --git a/disassembler/disassembler.h b/disassembler/disassembler.h index 183e692ff..487f43315 100644 --- a/disassembler/disassembler.h +++ b/disassembler/disassembler.h @@ -26,10 +26,31 @@ namespace art { +class DisassemblerOptions { + public: + // Should the disassembler print absolute or relative addresses. + const bool absolute_addresses_; + + // Base addess for calculating relative code offsets when absolute_addresses_ is false. + const uint8_t* const base_address_; + + DisassemblerOptions(bool absolute_addresses, const uint8_t* base_address) + : absolute_addresses_(absolute_addresses), base_address_(base_address) {} + + private: + DISALLOW_COPY_AND_ASSIGN(DisassemblerOptions); +}; + class Disassembler { public: - static Disassembler* Create(InstructionSet instruction_set); - virtual ~Disassembler() {} + // Creates a Disassembler for the given InstructionSet with the + // non-null DisassemblerOptions which become owned by the + // Disassembler. + static Disassembler* Create(InstructionSet instruction_set, DisassemblerOptions* options); + + virtual ~Disassembler() { + delete disassembler_options_; + } // Dump a single instruction returning the length of that instruction. virtual size_t Dump(std::ostream& os, const uint8_t* begin) = 0; @@ -37,9 +58,15 @@ class Disassembler { virtual void Dump(std::ostream& os, const uint8_t* begin, const uint8_t* end) = 0; protected: - Disassembler() {} + explicit Disassembler(DisassemblerOptions* disassembler_options) + : disassembler_options_(disassembler_options) { + CHECK(disassembler_options_ != nullptr); + } + + std::string FormatInstructionPointer(const uint8_t* begin); private: + DisassemblerOptions* disassembler_options_; DISALLOW_COPY_AND_ASSIGN(Disassembler); }; diff --git a/disassembler/disassembler_arm.cc b/disassembler/disassembler_arm.cc index 56023c159..54e77612a 100644 --- a/disassembler/disassembler_arm.cc +++ b/disassembler/disassembler_arm.cc @@ -94,7 +94,7 @@ void DisassemblerArm::DumpMemoryDomain(std::ostream& os, uint32_t domain) { } void DisassemblerArm::DumpBranchTarget(std::ostream& os, const uint8_t* instr_ptr, int32_t imm32) { - os << StringPrintf("%+d (%p)", imm32, instr_ptr + imm32); + os << StringPrintf("%+d (", imm32) << FormatInstructionPointer(instr_ptr + imm32) << ")"; } static uint32_t ReadU16(const uint8_t* ptr) { @@ -356,7 +356,9 @@ void DisassemblerArm::DumpArm(std::ostream& os, const uint8_t* instr_ptr) { opcode += kConditionCodeNames[cond]; opcode += suffixes; // TODO: a more complete ARM disassembler could generate wider opcodes. - os << StringPrintf("%p: %08x\t%-7s ", instr_ptr, instruction, opcode.c_str()) << args.str() << '\n'; + os << FormatInstructionPointer(instr_ptr) + << StringPrintf(": %08x\t%-7s ", instruction, opcode.c_str()) + << args.str() << '\n'; } int32_t ThumbExpand(int32_t imm12) { @@ -1608,7 +1610,9 @@ size_t DisassemblerArm::DumpThumb32(std::ostream& os, const uint8_t* instr_ptr) opcode << "UNKNOWN " << op2; } - os << StringPrintf("%p: %08x\t%-7s ", instr_ptr, instr, opcode.str().c_str()) << args.str() << '\n'; + os << FormatInstructionPointer(instr_ptr) + << StringPrintf(": %08x\t%-7s ", instr, opcode.str().c_str()) + << args.str() << '\n'; return 4; } // NOLINT(readability/fn_size) @@ -1936,7 +1940,9 @@ size_t DisassemblerArm::DumpThumb16(std::ostream& os, const uint8_t* instr_ptr) it_conditions_.pop_back(); } - os << StringPrintf("%p: %04x \t%-7s ", instr_ptr, instr, opcode.str().c_str()) << args.str() << '\n'; + os << FormatInstructionPointer(instr_ptr) + << StringPrintf(": %04x \t%-7s ", instr, opcode.str().c_str()) + << args.str() << '\n'; } return 2; } diff --git a/disassembler/disassembler_arm.h b/disassembler/disassembler_arm.h index f6d7fdad5..f870e8ef8 100644 --- a/disassembler/disassembler_arm.h +++ b/disassembler/disassembler_arm.h @@ -26,8 +26,7 @@ namespace arm { class DisassemblerArm FINAL : public Disassembler { public: - DisassemblerArm() { - } + explicit DisassemblerArm(DisassemblerOptions* options) : Disassembler(options) {} size_t Dump(std::ostream& os, const uint8_t* begin) OVERRIDE; void Dump(std::ostream& os, const uint8_t* begin, const uint8_t* end) OVERRIDE; diff --git a/disassembler/disassembler_arm64.cc b/disassembler/disassembler_arm64.cc index 864d22da7..5d0c2189c 100644 --- a/disassembler/disassembler_arm64.cc +++ b/disassembler/disassembler_arm64.cc @@ -34,7 +34,8 @@ static uint32_t ReadU32(const uint8_t* ptr) { size_t DisassemblerArm64::Dump(std::ostream& os, const uint8_t* begin) { uint32_t instruction = ReadU32(begin); decoder.Decode(reinterpret_cast(&instruction)); - os << StringPrintf("%p: %08x\t%s\n", begin, instruction, disasm.GetOutput()); + os << FormatInstructionPointer(begin) + << StringPrintf(": %08x\t%s\n", instruction, disasm.GetOutput()); return vixl::kInstructionSize; } diff --git a/disassembler/disassembler_arm64.h b/disassembler/disassembler_arm64.h index 28c0fa755..ad20c7022 100644 --- a/disassembler/disassembler_arm64.h +++ b/disassembler/disassembler_arm64.h @@ -27,7 +27,7 @@ namespace arm64 { class DisassemblerArm64 FINAL : public Disassembler { public: - DisassemblerArm64() { + explicit DisassemblerArm64(DisassemblerOptions* options) : Disassembler(options) { decoder.AppendVisitor(&disasm); } diff --git a/disassembler/disassembler_mips.cc b/disassembler/disassembler_mips.cc index 5e89f6f56..bd5fac737 100644 --- a/disassembler/disassembler_mips.cc +++ b/disassembler/disassembler_mips.cc @@ -168,7 +168,7 @@ static uint32_t ReadU32(const uint8_t* ptr) { return ptr[0] | (ptr[1] << 8) | (ptr[2] << 16) | (ptr[3] << 24); } -static void DumpMips(std::ostream& os, const uint8_t* instr_ptr) { +size_t DisassemblerMips::Dump(std::ostream& os, const uint8_t* instr_ptr) { uint32_t instruction = ReadU32(instr_ptr); uint32_t rs = (instruction >> 21) & 0x1f; // I-type, R-type. @@ -197,7 +197,8 @@ static void DumpMips(std::ostream& os, const uint8_t* instr_ptr) { int32_t offset = static_cast(instruction & 0xffff); offset <<= 2; offset += 4; // Delay slot. - args << StringPrintf("%p ; %+d", instr_ptr + offset, offset); + args << FormatInstructionPointer(instr_ptr + offset) + << StringPrintf(" ; %+d", offset); } break; case 'D': args << 'r' << rd; break; @@ -254,17 +255,15 @@ static void DumpMips(std::ostream& os, const uint8_t* instr_ptr) { } } - os << StringPrintf("%p: %08x\t%-7s ", instr_ptr, instruction, opcode.c_str()) << args.str() << '\n'; -} - -size_t DisassemblerMips::Dump(std::ostream& os, const uint8_t* begin) { - DumpMips(os, begin); + os << FormatInstructionPointer(instr_ptr) + << StringPrintf(": %08x\t%-7s ", instruction, opcode.c_str()) + << args.str() << '\n'; return 4; } void DisassemblerMips::Dump(std::ostream& os, const uint8_t* begin, const uint8_t* end) { for (const uint8_t* cur = begin; cur < end; cur += 4) { - DumpMips(os, cur); + Dump(os, cur); } } diff --git a/disassembler/disassembler_mips.h b/disassembler/disassembler_mips.h index e1fb0340a..00b2f8dbb 100644 --- a/disassembler/disassembler_mips.h +++ b/disassembler/disassembler_mips.h @@ -26,8 +26,7 @@ namespace mips { class DisassemblerMips FINAL : public Disassembler { public: - DisassemblerMips() { - } + explicit DisassemblerMips(DisassemblerOptions* options) : Disassembler(options) {} size_t Dump(std::ostream& os, const uint8_t* begin) OVERRIDE; void Dump(std::ostream& os, const uint8_t* begin, const uint8_t* end) OVERRIDE; diff --git a/disassembler/disassembler_x86.cc b/disassembler/disassembler_x86.cc index 0ca896228..470849892 100644 --- a/disassembler/disassembler_x86.cc +++ b/disassembler/disassembler_x86.cc @@ -1227,7 +1227,9 @@ DISASSEMBLER_ENTRY(cmp, displacement = *reinterpret_cast(instr); instr += 4; } - args << StringPrintf("%+d (%p)", displacement, instr + displacement); + args << StringPrintf("%+d (", displacement) + << FormatInstructionPointer(instr + displacement) + << ")"; } if (prefix[1] == kFs && !supports_rex_) { args << " ; "; @@ -1250,8 +1252,8 @@ DISASSEMBLER_ENTRY(cmp, default: LOG(FATAL) << "Unreachable"; } prefixed_opcode << opcode.str(); - os << StringPrintf("%p: %22s \t%-7s ", begin_instr, hex.str().c_str(), - prefixed_opcode.str().c_str()) + os << FormatInstructionPointer(begin_instr) + << StringPrintf(": %22s \t%-7s ", hex.str().c_str(), prefixed_opcode.str().c_str()) << args.str() << '\n'; return instr - begin_instr; } // NOLINT(readability/fn_size) diff --git a/disassembler/disassembler_x86.h b/disassembler/disassembler_x86.h index 2565bb1ee..f448662f6 100644 --- a/disassembler/disassembler_x86.h +++ b/disassembler/disassembler_x86.h @@ -24,8 +24,8 @@ namespace x86 { class DisassemblerX86 FINAL : public Disassembler { public: - explicit DisassemblerX86(bool supports_rex) : supports_rex_(supports_rex) { - } + DisassemblerX86(DisassemblerOptions* options, bool supports_rex) + : Disassembler(options), supports_rex_(supports_rex) {} size_t Dump(std::ostream& os, const uint8_t* begin) OVERRIDE; void Dump(std::ostream& os, const uint8_t* begin, const uint8_t* end) OVERRIDE; diff --git a/oatdump/oatdump.cc b/oatdump/oatdump.cc index 0065a1ff3..7607bf0f5 100644 --- a/oatdump/oatdump.cc +++ b/oatdump/oatdump.cc @@ -76,8 +76,8 @@ static void usage() { " Example: --boot-image=/system/framework/boot.art\n" "\n"); fprintf(stderr, - " --instruction-set=(arm|arm64|mips|x86|x86_64): for locating the image file based on the image location\n" - " set.\n" + " --instruction-set=(arm|arm64|mips|x86|x86_64): for locating the image\n" + " file based on the image location set.\n" " Example: --instruction-set=x86\n" " Default: %s\n" "\n", @@ -87,9 +87,20 @@ static void usage() { " Example: --output=/tmp/oatdump.txt\n" "\n"); fprintf(stderr, - " --dump:[raw_mapping_table|raw_gc_map]\n" - " Example: --dump:raw_gc_map\n" - " Default: neither\n" + " --dump:raw_mapping_table enables dumping of the mapping table.\n" + " Example: --dump:raw_mapping_table\n" + "\n"); + fprintf(stderr, + " --dump:raw_mapping_table enables dumping of the GC map.\n" + " Example: --dump:raw_gc_map\n" + "\n"); + fprintf(stderr, + " --no-dump:vmap may be used to disable vmap dumping.\n" + " Example: --no-dump:vmap\n" + "\n"); + fprintf(stderr, + " --no-disassemble may be used to disable disassembly.\n" + " Example: --no-disassemble\n" "\n"); exit(EXIT_FAILURE); } @@ -105,18 +116,45 @@ const char* image_roots_descriptions_[] = { "kClassRoots", }; +class OatDumperOptions { + public: + OatDumperOptions(bool dump_raw_mapping_table, + bool dump_raw_gc_map, + bool dump_vmap, + bool disassemble_code, + bool absolute_addresses) + : dump_raw_mapping_table_(dump_raw_mapping_table), + dump_raw_gc_map_(dump_raw_gc_map), + dump_vmap_(dump_vmap), + disassemble_code_(disassemble_code), + absolute_addresses_(absolute_addresses) {} + + const bool dump_raw_mapping_table_; + const bool dump_raw_gc_map_; + const bool dump_vmap_; + const bool disassemble_code_; + const bool absolute_addresses_; +}; + class OatDumper { public: - explicit OatDumper(const OatFile& oat_file, bool dump_raw_mapping_table, bool dump_raw_gc_map) + explicit OatDumper(const OatFile& oat_file, OatDumperOptions* options) : oat_file_(oat_file), oat_dex_files_(oat_file.GetOatDexFiles()), - dump_raw_mapping_table_(dump_raw_mapping_table), - dump_raw_gc_map_(dump_raw_gc_map), - disassembler_(Disassembler::Create(oat_file_.GetOatHeader().GetInstructionSet())) { + options_(options), + disassembler_(Disassembler::Create(oat_file_.GetOatHeader().GetInstructionSet(), + new DisassemblerOptions(options_->absolute_addresses_, + oat_file.Begin()))) { AddAllOffsets(); } - void Dump(std::ostream& os) { + ~OatDumper() { + delete options_; + delete disassembler_; + } + + bool Dump(std::ostream& os) { + bool success = true; const OatHeader& oat_header = oat_file_.GetOatHeader(); os << "MAGIC:\n"; @@ -137,7 +175,7 @@ class OatDumper { #define DUMP_OAT_HEADER_OFFSET(label, offset) \ os << label " OFFSET:\n"; \ os << StringPrintf("0x%08x", oat_header.offset()); \ - if (oat_header.offset() != 0) { \ + if (oat_header.offset() != 0 && options_->absolute_addresses_) { \ os << StringPrintf(" (%p)", oat_file_.Begin() + oat_header.offset()); \ } \ os << StringPrintf("\n\n"); @@ -165,7 +203,10 @@ class OatDumper { GetQuickToInterpreterBridgeOffset); #undef DUMP_OAT_HEADER_OFFSET - os << "IMAGE PATCH DELTA:\n" << oat_header.GetImagePatchDelta(); + os << "IMAGE PATCH DELTA:\n"; + os << StringPrintf("%d (0x%08x)\n\n", + oat_header.GetImagePatchDelta(), + oat_header.GetImagePatchDelta()); os << "IMAGE FILE LOCATION OAT CHECKSUM:\n"; os << StringPrintf("0x%08x\n\n", oat_header.GetImageFileLocationOatChecksum()); @@ -186,19 +227,28 @@ class OatDumper { os << "\n"; } - os << "BEGIN:\n"; - os << reinterpret_cast(oat_file_.Begin()) << "\n\n"; + if (options_->absolute_addresses_) { + os << "BEGIN:\n"; + os << reinterpret_cast(oat_file_.Begin()) << "\n\n"; + + os << "END:\n"; + os << reinterpret_cast(oat_file_.End()) << "\n\n"; + } - os << "END:\n"; - os << reinterpret_cast(oat_file_.End()) << "\n\n"; + os << "SIZE:\n"; + os << oat_file_.Size() << "\n\n"; os << std::flush; for (size_t i = 0; i < oat_dex_files_.size(); i++) { const OatFile::OatDexFile* oat_dex_file = oat_dex_files_[i]; CHECK(oat_dex_file != nullptr); - DumpOatDexFile(os, *oat_dex_file); + if (!DumpOatDexFile(os, *oat_dex_file)) { + success = false; + } } + os << std::flush; + return success; } size_t ComputeSize(const void* oat_data) { @@ -286,6 +336,10 @@ class OatDumper { offsets_.insert(oat_file_.Size()); } + static uint32_t AlignCodeOffset(uint32_t maybe_thumb_offset) { + return maybe_thumb_offset & ~0x1; // TODO: Make this Thumb2 specific. + } + void AddOffsets(const OatFile::OatMethod& oat_method) { uint32_t code_offset = oat_method.GetCodeOffset(); if (oat_file_.GetOatHeader().GetInstructionSet() == kThumb2) { @@ -297,8 +351,9 @@ class OatDumper { offsets_.insert(oat_method.GetNativeGcMapOffset()); } - void DumpOatDexFile(std::ostream& os, const OatFile::OatDexFile& oat_dex_file) { - os << "OAT DEX FILE:\n"; + bool DumpOatDexFile(std::ostream& os, const OatFile::OatDexFile& oat_dex_file) { + bool success = true; + os << "OatDexFile:\n"; os << StringPrintf("location: %s\n", oat_dex_file.GetDexFileLocation().c_str()); os << StringPrintf("checksum: 0x%08x\n", oat_dex_file.GetDexFileLocationChecksum()); @@ -308,24 +363,30 @@ class OatDumper { std::unique_ptr dex_file(oat_dex_file.OpenDexFile(&error_msg)); if (dex_file.get() == nullptr) { os << "NOT FOUND: " << error_msg << "\n\n"; - return; + os << std::flush; + return false; } for (size_t class_def_index = 0; class_def_index < dex_file->NumClassDefs(); class_def_index++) { const DexFile::ClassDef& class_def = dex_file->GetClassDef(class_def_index); const char* descriptor = dex_file->GetClassDescriptor(class_def); + uint32_t oat_class_offset = oat_dex_file.GetOatClassOffset(class_def_index); const OatFile::OatClass oat_class = oat_dex_file.GetOatClass(class_def_index); - os << StringPrintf("%zd: %s (type_idx=%d)", class_def_index, descriptor, class_def.class_idx_) + os << StringPrintf("%zd: %s (offset=0x%08x) (type_idx=%d)", + class_def_index, descriptor, oat_class_offset, class_def.class_idx_) << " (" << oat_class.GetStatus() << ")" << " (" << oat_class.GetType() << ")\n"; // TODO: include bitmap here if type is kOatClassSomeCompiled? Indenter indent_filter(os.rdbuf(), kIndentChar, kIndentBy1Count); std::ostream indented_os(&indent_filter); - DumpOatClass(indented_os, oat_class, *(dex_file.get()), class_def); + if (!DumpOatClass(indented_os, oat_class, *(dex_file.get()), class_def)) { + success = false; + } } os << std::flush; + return success; } static void SkipAllFields(ClassDataItemIterator& it) { @@ -337,38 +398,51 @@ class OatDumper { } } - void DumpOatClass(std::ostream& os, const OatFile::OatClass& oat_class, const DexFile& dex_file, + bool DumpOatClass(std::ostream& os, const OatFile::OatClass& oat_class, const DexFile& dex_file, const DexFile::ClassDef& class_def) { + bool success = true; const byte* class_data = dex_file.GetClassData(class_def); if (class_data == nullptr) { // empty class such as a marker interface? - return; + os << std::flush; + return success; } ClassDataItemIterator it(dex_file, class_data); SkipAllFields(it); - uint32_t class_method_idx = 0; + uint32_t class_method_index = 0; while (it.HasNextDirectMethod()) { - const OatFile::OatMethod oat_method = oat_class.GetOatMethod(class_method_idx); - DumpOatMethod(os, class_def, class_method_idx, oat_method, dex_file, - it.GetMemberIndex(), it.GetMethodCodeItem(), it.GetRawMemberAccessFlags()); - class_method_idx++; + if (!DumpOatMethod(os, class_def, class_method_index, oat_class, dex_file, + it.GetMemberIndex(), it.GetMethodCodeItem(), + it.GetRawMemberAccessFlags())) { + success = false; + } + class_method_index++; it.Next(); } while (it.HasNextVirtualMethod()) { - const OatFile::OatMethod oat_method = oat_class.GetOatMethod(class_method_idx); - DumpOatMethod(os, class_def, class_method_idx, oat_method, dex_file, - it.GetMemberIndex(), it.GetMethodCodeItem(), it.GetRawMemberAccessFlags()); - class_method_idx++; + if (!DumpOatMethod(os, class_def, class_method_index, oat_class, dex_file, + it.GetMemberIndex(), it.GetMethodCodeItem(), + it.GetRawMemberAccessFlags())) { + success = false; + } + class_method_index++; it.Next(); } DCHECK(!it.HasNext()); os << std::flush; + return success; } - void DumpOatMethod(std::ostream& os, const DexFile::ClassDef& class_def, + static constexpr uint32_t kPrologueBytes = 16; + + // When this was picked, the largest arm method was 55,256 bytes and arm64 was 50,412 bytes. + static constexpr uint32_t kMaxCodeSize = 100 * 1000; + + bool DumpOatMethod(std::ostream& os, const DexFile::ClassDef& class_def, uint32_t class_method_index, - const OatFile::OatMethod& oat_method, const DexFile& dex_file, + const OatFile::OatClass& oat_class, const DexFile& dex_file, uint32_t dex_method_idx, const DexFile::CodeItem* code_item, uint32_t method_access_flags) { + bool success = true; os << StringPrintf("%d: %s (dex_method_idx=%d)\n", class_method_index, PrettyMethod(dex_method_idx, dex_file, true).c_str(), dex_method_idx); @@ -387,47 +461,183 @@ class OatDumper { verifier.reset(DumpVerifier(*indent2_os, dex_method_idx, &dex_file, class_def, code_item, method_access_flags)); } + + uint32_t oat_method_offsets_offset = oat_class.GetOatMethodOffsetsOffset(class_method_index); + const OatMethodOffsets* oat_method_offsets = oat_class.GetOatMethodOffsets(class_method_index); + const OatFile::OatMethod oat_method = oat_class.GetOatMethod(class_method_index); { - *indent1_os << "OAT DATA:\n"; + *indent1_os << "OatMethodOffsets "; + if (options_->absolute_addresses_) { + *indent1_os << StringPrintf("%p ", oat_method_offsets); + } + *indent1_os << StringPrintf("(offset=0x%08x)\n", oat_method_offsets_offset); + if (oat_method_offsets_offset > oat_file_.Size()) { + *indent1_os << StringPrintf( + "WARNING: oat method offsets offset 0x%08x is past end of file 0x%08zx.\n", + oat_method_offsets_offset, oat_file_.Size()); + // If we can't read OatMethodOffsets, the rest of the data is dangerous to read. + os << std::flush; + return false; + } - *indent2_os << StringPrintf("frame_size_in_bytes: %zd\n", oat_method.GetFrameSizeInBytes()); - *indent2_os << StringPrintf("core_spill_mask: 0x%08x ", oat_method.GetCoreSpillMask()); - DumpSpillMask(*indent2_os, oat_method.GetCoreSpillMask(), false); - *indent2_os << StringPrintf("\nfp_spill_mask: 0x%08x ", oat_method.GetFpSpillMask()); - DumpSpillMask(*indent2_os, oat_method.GetFpSpillMask(), true); - *indent2_os << StringPrintf("\nvmap_table: %p (offset=0x%08x)\n", - oat_method.GetVmapTable(), oat_method.GetVmapTableOffset()); - DumpVmap(*indent2_os, oat_method); - *indent2_os << StringPrintf("mapping_table: %p (offset=0x%08x)\n", - oat_method.GetMappingTable(), oat_method.GetMappingTableOffset()); - if (dump_raw_mapping_table_) { - Indenter indent3_filter(indent2_os->rdbuf(), kIndentChar, kIndentBy1Count); - std::ostream indent3_os(&indent3_filter); - DumpMappingTable(indent3_os, oat_method); + uint32_t code_offset = oat_method.GetCodeOffset(); + *indent2_os << StringPrintf("code_offset: 0x%08x ", code_offset); + uint32_t aligned_code_begin = AlignCodeOffset(oat_method.GetCodeOffset()); + if (aligned_code_begin > oat_file_.Size()) { + *indent2_os << StringPrintf("WARNING: " + "code offset 0x%08x is past end of file 0x%08zx.\n", + aligned_code_begin, oat_file_.Size()); + success = false; } - *indent2_os << StringPrintf("gc_map: %p (offset=0x%08x)\n", - oat_method.GetNativeGcMap(), oat_method.GetNativeGcMapOffset()); - if (dump_raw_gc_map_) { + *indent2_os << "\n"; + + *indent2_os << "gc_map: "; + if (options_->absolute_addresses_) { + *indent2_os << StringPrintf("%p ", oat_method.GetNativeGcMap()); + } + uint32_t gc_map_offset = oat_method.GetNativeGcMapOffset(); + *indent2_os << StringPrintf("(offset=0x%08x)\n", gc_map_offset); + if (gc_map_offset > oat_file_.Size()) { + *indent2_os << StringPrintf("WARNING: " + "gc map table offset 0x%08x is past end of file 0x%08zx.\n", + gc_map_offset, oat_file_.Size()); + success = false; + } else if (options_->dump_raw_gc_map_) { Indenter indent3_filter(indent2_os->rdbuf(), kIndentChar, kIndentBy1Count); std::ostream indent3_os(&indent3_filter); DumpGcMap(indent3_os, oat_method, code_item); } } { - const void* code = oat_method.GetQuickCode(); - uint32_t code_size = oat_method.GetQuickCodeSize(); - if (code == nullptr) { - code = oat_method.GetPortableCode(); - code_size = oat_method.GetPortableCodeSize(); + *indent1_os << "OatQuickMethodHeader "; + uint32_t method_header_offset = oat_method.GetOatQuickMethodHeaderOffset(); + const OatQuickMethodHeader* method_header = oat_method.GetOatQuickMethodHeader(); + + if (options_->absolute_addresses_) { + *indent1_os << StringPrintf("%p ", method_header); + } + *indent1_os << StringPrintf("(offset=0x%08x)\n", method_header_offset); + if (method_header_offset > oat_file_.Size()) { + *indent1_os << StringPrintf( + "WARNING: oat quick method header offset 0x%08x is past end of file 0x%08zx.\n", + method_header_offset, oat_file_.Size()); + // If we can't read the OatQuickMethodHeader, the rest of the data is dangerous to read. + os << std::flush; + return false; + } + + *indent2_os << "mapping_table: "; + if (options_->absolute_addresses_) { + *indent2_os << StringPrintf("%p ", oat_method.GetMappingTable()); } - *indent1_os << StringPrintf("CODE: %p (offset=0x%08x size=%d)%s\n", - code, - oat_method.GetCodeOffset(), - code_size, - code != nullptr ? "..." : ""); + uint32_t mapping_table_offset = oat_method.GetMappingTableOffset(); + *indent2_os << StringPrintf("(offset=0x%08x)\n", oat_method.GetMappingTableOffset()); + if (mapping_table_offset > oat_file_.Size()) { + *indent2_os << StringPrintf("WARNING: " + "mapping table offset 0x%08x is past end of file 0x%08zx. " + "mapping table offset was loaded from offset 0x%08x.\n", + mapping_table_offset, oat_file_.Size(), + oat_method.GetMappingTableOffsetOffset()); + success = false; + } else if (options_->dump_raw_mapping_table_) { + Indenter indent3_filter(indent2_os->rdbuf(), kIndentChar, kIndentBy1Count); + std::ostream indent3_os(&indent3_filter); + DumpMappingTable(indent3_os, oat_method); + } + + *indent2_os << "vmap_table: "; + if (options_->absolute_addresses_) { + *indent2_os << StringPrintf("%p ", oat_method.GetVmapTable()); + } + uint32_t vmap_table_offset = oat_method.GetVmapTableOffset(); + *indent2_os << StringPrintf("(offset=0x%08x)\n", vmap_table_offset); + if (vmap_table_offset > oat_file_.Size()) { + *indent2_os << StringPrintf("WARNING: " + "vmap table offset 0x%08x is past end of file 0x%08zx. " + "vmap table offset was loaded from offset 0x%08x.\n", + vmap_table_offset, oat_file_.Size(), + oat_method.GetVmapTableOffsetOffset()); + success = false; + } else if (options_->dump_vmap_) { + DumpVmap(*indent2_os, oat_method); + } + } + { + *indent1_os << "QuickMethodFrameInfo\n"; + + *indent2_os << StringPrintf("frame_size_in_bytes: %zd\n", oat_method.GetFrameSizeInBytes()); + *indent2_os << StringPrintf("core_spill_mask: 0x%08x ", oat_method.GetCoreSpillMask()); + DumpSpillMask(*indent2_os, oat_method.GetCoreSpillMask(), false); + *indent2_os << "\n"; + *indent2_os << StringPrintf("fp_spill_mask: 0x%08x ", oat_method.GetFpSpillMask()); + DumpSpillMask(*indent2_os, oat_method.GetFpSpillMask(), true); + *indent2_os << "\n"; + } + { + *indent1_os << "CODE: "; + uint32_t code_size_offset = oat_method.GetQuickCodeSizeOffset(); + if (code_size_offset > oat_file_.Size()) { + *indent2_os << StringPrintf("WARNING: " + "code size offset 0x%08x is past end of file 0x%08zx.", + code_size_offset, oat_file_.Size()); + success = false; + } else { + const void* code = oat_method.GetQuickCode(); + uint32_t code_size = oat_method.GetQuickCodeSize(); + if (code == nullptr) { + code = oat_method.GetPortableCode(); + code_size = oat_method.GetPortableCodeSize(); + code_size_offset = 0; + } + uint32_t code_offset = oat_method.GetCodeOffset(); + uint32_t aligned_code_begin = AlignCodeOffset(code_offset); + uint64_t aligned_code_end = aligned_code_begin + code_size; - DumpCode(*indent2_os, verifier.get(), oat_method, code_item); + if (options_->absolute_addresses_) { + *indent1_os << StringPrintf("%p ", code); + } + *indent1_os << StringPrintf("(code_offset=0x%08x size_offset=0x%08x size=%u)%s\n", + code_offset, + code_size_offset, + code_size, + code != nullptr ? "..." : ""); + + if (aligned_code_begin > oat_file_.Size()) { + *indent2_os << StringPrintf("WARNING: " + "start of code at 0x%08x is past end of file 0x%08zx.", + aligned_code_begin, oat_file_.Size()); + success = false; + } else if (aligned_code_end > oat_file_.Size()) { + *indent2_os << StringPrintf("WARNING: " + "end of code at 0x%08" PRIx64 " is past end of file 0x%08zx. " + "code size is 0x%08x loaded from offset 0x%08x.\n", + aligned_code_end, oat_file_.Size(), + code_size, code_size_offset); + success = false; + if (options_->disassemble_code_) { + if (code_size_offset + kPrologueBytes <= oat_file_.Size()) { + DumpCode(*indent2_os, verifier.get(), oat_method, code_item, true, kPrologueBytes); + } + } + } else if (code_size > kMaxCodeSize) { + *indent2_os << StringPrintf("WARNING: " + "code size %d is bigger than max expected threshold of %d. " + "code size is 0x%08x loaded from offset 0x%08x.\n", + code_size, kMaxCodeSize, + code_size, code_size_offset); + success = false; + if (options_->disassemble_code_) { + if (code_size_offset + kPrologueBytes <= oat_file_.Size()) { + DumpCode(*indent2_os, verifier.get(), oat_method, code_item, true, kPrologueBytes); + } + } + } else if (options_->disassemble_code_) { + DumpCode(*indent2_os, verifier.get(), oat_method, code_item, !success, 0); + } + } } + os << std::flush; + return success; } void DumpSpillMask(std::ostream& os, uint32_t spill_mask, bool is_float) { @@ -701,11 +911,14 @@ class OatDumper { } void DumpCode(std::ostream& os, verifier::MethodVerifier* verifier, - const OatFile::OatMethod& oat_method, const DexFile::CodeItem* code_item) { + const OatFile::OatMethod& oat_method, const DexFile::CodeItem* code_item, + bool bad_input, size_t code_size) { const void* portable_code = oat_method.GetPortableCode(); const void* quick_code = oat_method.GetQuickCode(); - size_t code_size = oat_method.GetQuickCodeSize(); + if (code_size == 0) { + code_size = oat_method.GetQuickCodeSize(); + } if ((code_size == 0) || ((portable_code == nullptr) && (quick_code == nullptr))) { os << "NO CODE!\n"; return; @@ -713,13 +926,17 @@ class OatDumper { const uint8_t* quick_native_pc = reinterpret_cast(quick_code); size_t offset = 0; while (offset < code_size) { - DumpMappingAtOffset(os, oat_method, offset, false); + if (!bad_input) { + DumpMappingAtOffset(os, oat_method, offset, false); + } offset += disassembler_->Dump(os, quick_native_pc + offset); - uint32_t dex_pc = DumpMappingAtOffset(os, oat_method, offset, true); - if (dex_pc != DexFile::kDexNoIndex) { - DumpGcMapAtNativePcOffset(os, oat_method, code_item, offset); - if (verifier != nullptr) { - DumpVRegsAtDexPc(os, verifier, oat_method, code_item, dex_pc); + if (!bad_input) { + uint32_t dex_pc = DumpMappingAtOffset(os, oat_method, offset, true); + if (dex_pc != DexFile::kDexNoIndex) { + DumpGcMapAtNativePcOffset(os, oat_method, code_item, offset); + if (verifier != nullptr) { + DumpVRegsAtDexPc(os, verifier, oat_method, code_item, dex_pc); + } } } } @@ -730,23 +947,22 @@ class OatDumper { } const OatFile& oat_file_; - std::vector oat_dex_files_; - bool dump_raw_mapping_table_; - bool dump_raw_gc_map_; + const std::vector oat_dex_files_; + const OatDumperOptions* options_; std::set offsets_; - std::unique_ptr disassembler_; + Disassembler* disassembler_; }; class ImageDumper { public: explicit ImageDumper(std::ostream* os, gc::space::ImageSpace& image_space, - const ImageHeader& image_header, bool dump_raw_mapping_table, - bool dump_raw_gc_map) - : os_(os), image_space_(image_space), image_header_(image_header), - dump_raw_mapping_table_(dump_raw_mapping_table), - dump_raw_gc_map_(dump_raw_gc_map) {} + const ImageHeader& image_header, OatDumperOptions* oat_dumper_options) + : os_(os), + image_space_(image_space), + image_header_(image_header), + oat_dumper_options_(oat_dumper_options) {} - void Dump() SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) { + bool Dump() SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) { std::ostream& os = *os_; os << "MAGIC: " << image_header_.GetMagic() << "\n\n"; @@ -820,15 +1036,14 @@ class ImageDumper { oat_file = OatFile::Open(oat_location, oat_location, nullptr, false, &error_msg); if (oat_file == nullptr) { os << "NOT FOUND: " << error_msg << "\n"; - return; + return false; } } os << "\n"; stats_.oat_file_bytes = oat_file->Size(); - oat_dumper_.reset(new OatDumper(*oat_file, dump_raw_mapping_table_, - dump_raw_gc_map_)); + oat_dumper_.reset(new OatDumper(*oat_file, oat_dumper_options_.release())); for (const OatFile::OatDexFile* oat_dex_file : oat_file->GetOatDexFiles()) { CHECK(oat_dex_file != nullptr); @@ -896,7 +1111,7 @@ class ImageDumper { os << std::flush; - oat_dumper_->Dump(os); + return oat_dumper_->Dump(os); } private: @@ -1449,12 +1664,11 @@ class ImageDumper { // threshold, we assume 2 bytes per instruction and 2 instructions per block. kLargeMethodDexBytes = 16000 }; - std::unique_ptr oat_dumper_; std::ostream* os_; gc::space::ImageSpace& image_space_; const ImageHeader& image_header_; - bool dump_raw_mapping_table_; - bool dump_raw_gc_map_; + std::unique_ptr oat_dumper_; + std::unique_ptr oat_dumper_options_; DISALLOW_COPY_AND_ASSIGN(ImageDumper); }; @@ -1480,6 +1694,8 @@ static int oatdump(int argc, char** argv) { std::unique_ptr out; bool dump_raw_mapping_table = false; bool dump_raw_gc_map = false; + bool dump_vmap = true; + bool disassemble_code = true; for (int i = 0; i < argc; i++) { const StringPiece option(argv[i]); @@ -1502,15 +1718,14 @@ static int oatdump(int argc, char** argv) { } else if (instruction_set_str == "x86_64") { instruction_set = kX86_64; } - } else if (option.starts_with("--dump:")) { - if (option == "--dump:raw_mapping_table") { - dump_raw_mapping_table = true; - } else if (option == "--dump:raw_gc_map") { - dump_raw_gc_map = true; - } else { - fprintf(stderr, "Unknown argument %s\n", option.data()); - usage(); - } + } else if (option =="--dump:raw_mapping_table") { + dump_raw_mapping_table = true; + } else if (option == "--dump:raw_gc_map") { + dump_raw_gc_map = true; + } else if (option == "--no-dump:vmap") { + dump_vmap = false; + } else if (option == "--no-disassemble") { + disassemble_code = false; } else if (option.starts_with("--output=")) { const char* filename = option.substr(strlen("--output=")).data(); out.reset(new std::ofstream(filename)); @@ -1535,6 +1750,13 @@ static int oatdump(int argc, char** argv) { return EXIT_FAILURE; } + // If we are only doing the oat file, disable absolute_addresses. Keep them for image dumping. + bool absolute_addresses = (oat_filename == nullptr); + std::unique_ptr oat_dumper_options(new OatDumperOptions(dump_raw_mapping_table, + dump_raw_gc_map, + dump_vmap, + disassemble_code, + absolute_addresses)); if (oat_filename != nullptr) { std::string error_msg; OatFile* oat_file = @@ -1543,9 +1765,9 @@ static int oatdump(int argc, char** argv) { fprintf(stderr, "Failed to open oat file from '%s': %s\n", oat_filename, error_msg.c_str()); return EXIT_FAILURE; } - OatDumper oat_dumper(*oat_file, dump_raw_mapping_table, dump_raw_gc_map); - oat_dumper.Dump(*os); - return EXIT_SUCCESS; + OatDumper oat_dumper(*oat_file, oat_dumper_options.release()); + bool success = oat_dumper.Dump(*os); + return (success) ? EXIT_SUCCESS : EXIT_FAILURE; } RuntimeOptions options; @@ -1589,10 +1811,9 @@ static int oatdump(int argc, char** argv) { fprintf(stderr, "Invalid image header %s\n", image_location); return EXIT_FAILURE; } - ImageDumper image_dumper(os, *image_space, image_header, - dump_raw_mapping_table, dump_raw_gc_map); - image_dumper.Dump(); - return EXIT_SUCCESS; + ImageDumper image_dumper(os, *image_space, image_header, oat_dumper_options.release()); + bool success = image_dumper.Dump(); + return (success) ? EXIT_SUCCESS : EXIT_FAILURE; } } // namespace art diff --git a/runtime/base/stringprintf_test.cc b/runtime/base/stringprintf_test.cc new file mode 100644 index 000000000..0bfde33a3 --- /dev/null +++ b/runtime/base/stringprintf_test.cc @@ -0,0 +1,29 @@ +/* + * Copyright (C) 2011 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "stringprintf.h" + +#include "gtest/gtest.h" + +namespace art { + +TEST(StringPrintfTest, HexSizeT) { + size_t size = 0x00107e59; + EXPECT_STREQ("00107e59", StringPrintf("%08zx", size).c_str()); + EXPECT_STREQ("0x00107e59", StringPrintf("0x%08zx", size).c_str()); +} + +} // namespace art diff --git a/runtime/oat_file-inl.h b/runtime/oat_file-inl.h index 97ca6b2b3..9570bb501 100644 --- a/runtime/oat_file-inl.h +++ b/runtime/oat_file-inl.h @@ -21,6 +21,39 @@ namespace art { +inline const OatQuickMethodHeader* OatFile::OatMethod::GetOatQuickMethodHeader() const { + const void* code = mirror::ArtMethod::EntryPointToCodePointer(GetQuickCode()); + if (code == nullptr) { + return nullptr; + } + // Return a pointer to the packed struct before the code. + return reinterpret_cast(code) - 1; +} + +inline uint32_t OatFile::OatMethod::GetOatQuickMethodHeaderOffset() const { + const OatQuickMethodHeader* method_header = GetOatQuickMethodHeader(); + if (method_header == nullptr) { + return 0u; + } + return reinterpret_cast(method_header) - begin_; +} + +inline uint32_t OatFile::OatMethod::GetQuickCodeSize() const { + const void* code = mirror::ArtMethod::EntryPointToCodePointer(GetQuickCode()); + if (code == nullptr) { + return 0u; + } + return reinterpret_cast(code)[-1].code_size_; +} + +inline uint32_t OatFile::OatMethod::GetQuickCodeSizeOffset() const { + const OatQuickMethodHeader* method_header = GetOatQuickMethodHeader(); + if (method_header == nullptr) { + return 0u; + } + return reinterpret_cast(&method_header->code_size_) - begin_; +} + inline size_t OatFile::OatMethod::GetFrameSizeInBytes() const { const void* code = mirror::ArtMethod::EntryPointToCodePointer(GetQuickCode()); if (code == nullptr) { @@ -50,11 +83,27 @@ inline uint32_t OatFile::OatMethod::GetMappingTableOffset() const { return static_cast(mapping_table != nullptr ? mapping_table - begin_ : 0u); } +inline uint32_t OatFile::OatMethod::GetMappingTableOffsetOffset() const { + const OatQuickMethodHeader* method_header = GetOatQuickMethodHeader(); + if (method_header == nullptr) { + return 0u; + } + return reinterpret_cast(&method_header->mapping_table_offset_) - begin_; +} + inline uint32_t OatFile::OatMethod::GetVmapTableOffset() const { const uint8_t* vmap_table = GetVmapTable(); return static_cast(vmap_table != nullptr ? vmap_table - begin_ : 0u); } +inline uint32_t OatFile::OatMethod::GetVmapTableOffsetOffset() const { + const OatQuickMethodHeader* method_header = GetOatQuickMethodHeader(); + if (method_header == nullptr) { + return 0u; + } + return reinterpret_cast(&method_header->vmap_table_offset_) - begin_; +} + inline const uint8_t* OatFile::OatMethod::GetMappingTable() const { const void* code = mirror::ArtMethod::EntryPointToCodePointer(GetQuickCode()); if (code == nullptr) { diff --git a/runtime/oat_file.cc b/runtime/oat_file.cc index 1ee53b864..0f8dd99c3 100644 --- a/runtime/oat_file.cc +++ b/runtime/oat_file.cc @@ -458,8 +458,12 @@ const DexFile* OatFile::OatDexFile::OpenDexFile(std::string* error_msg) const { dex_file_location_checksum_, error_msg); } +uint32_t OatFile::OatDexFile::GetOatClassOffset(uint16_t class_def_index) const { + return oat_class_offsets_pointer_[class_def_index]; +} + OatFile::OatClass OatFile::OatDexFile::GetOatClass(uint16_t class_def_index) const { - uint32_t oat_class_offset = oat_class_offsets_pointer_[class_def_index]; + uint32_t oat_class_offset = GetOatClassOffset(class_def_index); const byte* oat_class_pointer = oat_file_->Begin() + oat_class_offset; CHECK_LT(oat_class_pointer, oat_file_->End()) << oat_file_->GetLocation(); @@ -532,32 +536,48 @@ OatFile::OatClass::OatClass(const OatFile* oat_file, } } -const OatFile::OatMethod OatFile::OatClass::GetOatMethod(uint32_t method_index) const { +uint32_t OatFile::OatClass::GetOatMethodOffsetsOffset(uint32_t method_index) const { + const OatMethodOffsets* oat_method_offsets = GetOatMethodOffsets(method_index); + if (oat_method_offsets == nullptr) { + return 0u; + } + return reinterpret_cast(oat_method_offsets) - oat_file_->Begin(); +} + +const OatMethodOffsets* OatFile::OatClass::GetOatMethodOffsets(uint32_t method_index) const { // NOTE: We don't keep the number of methods and cannot do a bounds check for method_index. - if (methods_pointer_ == NULL) { + if (methods_pointer_ == nullptr) { CHECK_EQ(kOatClassNoneCompiled, type_); - return OatMethod(NULL, 0, 0); + return nullptr; } size_t methods_pointer_index; - if (bitmap_ == NULL) { + if (bitmap_ == nullptr) { CHECK_EQ(kOatClassAllCompiled, type_); methods_pointer_index = method_index; } else { CHECK_EQ(kOatClassSomeCompiled, type_); if (!BitVector::IsBitSet(bitmap_, method_index)) { - return OatMethod(NULL, 0, 0); + return nullptr; } size_t num_set_bits = BitVector::NumSetBits(bitmap_, method_index); methods_pointer_index = num_set_bits; } const OatMethodOffsets& oat_method_offsets = methods_pointer_[methods_pointer_index]; + return &oat_method_offsets; +} + +const OatFile::OatMethod OatFile::OatClass::GetOatMethod(uint32_t method_index) const { + const OatMethodOffsets* oat_method_offsets = GetOatMethodOffsets(method_index); + if (oat_method_offsets == nullptr) { + return OatMethod(nullptr, 0, 0); + } if (oat_file_->IsExecutable() || Runtime::Current() == nullptr || // This case applies for oatdump. Runtime::Current()->IsCompiler()) { return OatMethod( oat_file_->Begin(), - oat_method_offsets.code_offset_, - oat_method_offsets.gc_map_offset_); + oat_method_offsets->code_offset_, + oat_method_offsets->gc_map_offset_); } else { // We aren't allowed to use the compiled code. We just force it down the interpreted version. return OatMethod(oat_file_->Begin(), 0, 0); @@ -574,17 +594,6 @@ OatFile::OatMethod::OatMethod(const byte* base, OatFile::OatMethod::~OatMethod() {} - -uint32_t OatFile::OatMethod::GetQuickCodeSize() const { - uintptr_t code = reinterpret_cast(GetQuickCode()); - if (code == 0) { - return 0; - } - // TODO: make this Thumb2 specific - code &= ~0x1; - return reinterpret_cast(code)[-1]; -} - void OatFile::OatMethod::LinkMethod(mirror::ArtMethod* method) const { CHECK(method != NULL); method->SetEntryPointFromPortableCompiledCode(GetPortableCode()); diff --git a/runtime/oat_file.h b/runtime/oat_file.h index d8b48a9bf..e5cd6ec53 100644 --- a/runtime/oat_file.h +++ b/runtime/oat_file.h @@ -114,13 +114,22 @@ class OatFile { } } + // Returns 0. uint32_t GetPortableCodeSize() const { // TODO: With Quick, we store the size before the code. With Portable, the code is in a .o // file we don't manage ourselves. ELF symbols do have a concept of size, so we could capture // that and store it somewhere, such as the OatMethod. return 0; } + + // Returns size of quick code. uint32_t GetQuickCodeSize() const; + uint32_t GetQuickCodeSizeOffset() const; + + // Returns OatQuickMethodHeader for debugging. Most callers should + // use more specific methods such as GetQuickCodeSize. + const OatQuickMethodHeader* GetOatQuickMethodHeader() const; + uint32_t GetOatQuickMethodHeaderOffset() const; const uint8_t* GetNativeGcMap() const { return GetOatPointer(native_gc_map_offset_); @@ -129,10 +138,14 @@ class OatFile { size_t GetFrameSizeInBytes() const; uint32_t GetCoreSpillMask() const; uint32_t GetFpSpillMask() const; - uint32_t GetMappingTableOffset() const; - uint32_t GetVmapTableOffset() const; + const uint8_t* GetMappingTable() const; + uint32_t GetMappingTableOffset() const; + uint32_t GetMappingTableOffsetOffset() const; + const uint8_t* GetVmapTable() const; + uint32_t GetVmapTableOffset() const; + uint32_t GetVmapTableOffsetOffset() const; ~OatMethod(); @@ -171,11 +184,21 @@ class OatFile { } // Get the OatMethod entry based on its index into the class - // defintion. direct methods come first, followed by virtual - // methods. note that runtime created methods such as miranda + // defintion. Direct methods come first, followed by virtual + // methods. Note that runtime created methods such as miranda // methods are not included. const OatMethod GetOatMethod(uint32_t method_index) const; + // Return a pointer to the OatMethodOffsets for the requested + // method_index, or nullptr if none is present. Note that most + // callers should use GetOatMethod. + const OatMethodOffsets* GetOatMethodOffsets(uint32_t method_index) const; + + // Return the offset from the start of the OatFile to the + // OatMethodOffsets for the requested method_index, or 0 if none + // is present. Note that most callers should use GetOatMethod. + uint32_t GetOatMethodOffsetsOffset(uint32_t method_index) const; + OatClass() {} private: @@ -229,6 +252,9 @@ class OatFile { // Returns the OatClass for the class specified by the given DexFile class_def_index. OatClass GetOatClass(uint16_t class_def_index) const; + // Returns the offset to the OatClass information. Most callers should use GetOatClass. + uint32_t GetOatClassOffset(uint16_t class_def_index) const; + ~OatDexFile(); private: diff --git a/runtime/verifier/method_verifier.cc b/runtime/verifier/method_verifier.cc index c65b02f29..1720e18b4 100644 --- a/runtime/verifier/method_verifier.cc +++ b/runtime/verifier/method_verifier.cc @@ -3323,8 +3323,8 @@ mirror::ArtMethod* MethodVerifier::GetQuickInvokedMethod(const Instruction* inst } mirror::ArtMethod* MethodVerifier::VerifyInvokeVirtualQuickArgs(const Instruction* inst, - bool is_range) { - DCHECK(Runtime::Current()->IsStarted()); + bool is_range) { + DCHECK(Runtime::Current()->IsStarted() || verify_to_dump_); mirror::ArtMethod* res_method = GetQuickInvokedMethod(inst, work_line_.get(), is_range); if (res_method == nullptr) { @@ -3840,7 +3840,7 @@ mirror::ArtField* MethodVerifier::GetQuickFieldAccess(const Instruction* inst, void MethodVerifier::VerifyIGetQuick(const Instruction* inst, RegType& insn_type, bool is_primitive) { - DCHECK(Runtime::Current()->IsStarted()); + DCHECK(Runtime::Current()->IsStarted() || verify_to_dump_); mirror::ArtField* field = GetQuickFieldAccess(inst, work_line_.get()); if (field == nullptr) { Fail(VERIFY_ERROR_BAD_CLASS_HARD) << "Cannot infer field from " << inst->Name(); @@ -3900,7 +3900,7 @@ void MethodVerifier::VerifyIGetQuick(const Instruction* inst, RegType& insn_type void MethodVerifier::VerifyIPutQuick(const Instruction* inst, RegType& insn_type, bool is_primitive) { - DCHECK(Runtime::Current()->IsStarted()); + DCHECK(Runtime::Current()->IsStarted() || verify_to_dump_); mirror::ArtField* field = GetQuickFieldAccess(inst, work_line_.get()); if (field == nullptr) { Fail(VERIFY_ERROR_BAD_CLASS_HARD) << "Cannot infer field from " << inst->Name(); -- 2.11.0