diff options
-rw-r--r-- | compiler/cfi_test.h | 4 | ||||
-rw-r--r-- | compiler/dwarf/debug_info_entry_writer.h | 9 | ||||
-rw-r--r-- | compiler/dwarf/debug_line_opcode_writer.h | 9 | ||||
-rw-r--r-- | compiler/dwarf/dwarf_test.cc | 35 | ||||
-rw-r--r-- | compiler/dwarf/headers.h | 70 | ||||
-rw-r--r-- | compiler/elf_writer_debug.cc | 11 | ||||
-rw-r--r-- | compiler/elf_writer_debug.h | 2 | ||||
-rw-r--r-- | compiler/elf_writer_quick.cc | 49 | ||||
-rw-r--r-- | compiler/elf_writer_quick.h | 4 | ||||
-rw-r--r-- | compiler/elf_writer_test.cc | 72 | ||||
-rw-r--r-- | compiler/oat_writer.cc | 8 | ||||
-rw-r--r-- | compiler/oat_writer.h | 19 | ||||
-rw-r--r-- | patchoat/patchoat.cc | 76 | ||||
-rw-r--r-- | patchoat/patchoat.h | 5 | ||||
-rw-r--r-- | runtime/elf_file.cc | 573 | ||||
-rw-r--r-- | runtime/elf_file_impl.h | 6 |
16 files changed, 303 insertions, 649 deletions
diff --git a/compiler/cfi_test.h b/compiler/cfi_test.h index 9181792..cdb1b9e 100644 --- a/compiler/cfi_test.h +++ b/compiler/cfi_test.h @@ -46,7 +46,9 @@ class CFITest : public dwarf::DwarfTest { constexpr bool is64bit = false; dwarf::DebugFrameOpCodeWriter<> initial_opcodes; dwarf::WriteEhFrameCIE(is64bit, dwarf::Reg(8), initial_opcodes, &eh_frame_data_); - dwarf::WriteEhFrameFDE(is64bit, 0, 0, actual_asm.size(), &actual_cfi, &eh_frame_data_); + std::vector<uintptr_t> eh_frame_patches; + dwarf::WriteEhFrameFDE(is64bit, 0, 0, actual_asm.size(), &actual_cfi, + &eh_frame_data_, &eh_frame_patches); ReformatCfi(Objdump(false, "-W"), &lines); // Pretty-print assembly. auto* opts = new DisassemblerOptions(false, actual_asm.data(), true); diff --git a/compiler/dwarf/debug_info_entry_writer.h b/compiler/dwarf/debug_info_entry_writer.h index c0350b6..a2c9f5f 100644 --- a/compiler/dwarf/debug_info_entry_writer.h +++ b/compiler/dwarf/debug_info_entry_writer.h @@ -17,6 +17,7 @@ #ifndef ART_COMPILER_DWARF_DEBUG_INFO_ENTRY_WRITER_H_ #define ART_COMPILER_DWARF_DEBUG_INFO_ENTRY_WRITER_H_ +#include <cstdint> #include <unordered_map> #include "dwarf.h" @@ -88,6 +89,7 @@ class DebugInfoEntryWriter FINAL : private Writer<Allocator> { void WriteAddr(Attribute attrib, uint64_t value) { AddAbbrevAttribute(attrib, DW_FORM_addr); + patch_locations_.push_back(this->data()->size()); if (is64bit_) { this->PushUint64(value); } else { @@ -168,7 +170,11 @@ class DebugInfoEntryWriter FINAL : private Writer<Allocator> { this->PushUint32(address); } - bool is64bit() const { return is64bit_; } + bool Is64bit() const { return is64bit_; } + + const std::vector<uintptr_t>& GetPatchLocations() const { + return patch_locations_; + } using Writer<Allocator>::data; @@ -240,6 +246,7 @@ class DebugInfoEntryWriter FINAL : private Writer<Allocator> { size_t abbrev_code_offset_ = 0; // Location to patch once we know the code. bool inside_entry_ = false; // Entry ends at first child (if any). bool has_children = true; + std::vector<uintptr_t> patch_locations_; }; } // namespace dwarf diff --git a/compiler/dwarf/debug_line_opcode_writer.h b/compiler/dwarf/debug_line_opcode_writer.h index f34acee..77ed154 100644 --- a/compiler/dwarf/debug_line_opcode_writer.h +++ b/compiler/dwarf/debug_line_opcode_writer.h @@ -17,6 +17,8 @@ #ifndef ART_COMPILER_DWARF_DEBUG_LINE_OPCODE_WRITER_H_ #define ART_COMPILER_DWARF_DEBUG_LINE_OPCODE_WRITER_H_ +#include <cstdint> + #include "dwarf.h" #include "writer.h" @@ -119,10 +121,12 @@ class DebugLineOpCodeWriter FINAL : private Writer<Allocator> { if (use_64bit_address_) { this->PushUleb128(1 + 8); this->PushUint8(DW_LNE_set_address); + patch_locations_.push_back(this->data()->size()); this->PushUint64(absolute_address); } else { this->PushUleb128(1 + 4); this->PushUint8(DW_LNE_set_address); + patch_locations_.push_back(this->data()->size()); this->PushUint32(absolute_address); } current_address_ = absolute_address; @@ -204,6 +208,10 @@ class DebugLineOpCodeWriter FINAL : private Writer<Allocator> { return current_line_; } + const std::vector<uintptr_t>& GetPatchLocations() const { + return patch_locations_; + } + using Writer<Allocator>::data; DebugLineOpCodeWriter(bool use64bitAddress, @@ -233,6 +241,7 @@ class DebugLineOpCodeWriter FINAL : private Writer<Allocator> { uint64_t current_address_; int current_file_; int current_line_; + std::vector<uintptr_t> patch_locations_; DISALLOW_COPY_AND_ASSIGN(DebugLineOpCodeWriter); }; diff --git a/compiler/dwarf/dwarf_test.cc b/compiler/dwarf/dwarf_test.cc index ec18e96..fa12d7e 100644 --- a/compiler/dwarf/dwarf_test.cc +++ b/compiler/dwarf/dwarf_test.cc @@ -120,19 +120,27 @@ TEST_F(DwarfTest, DebugFrame) { DebugFrameOpCodeWriter<> initial_opcodes; WriteEhFrameCIE(is64bit, Reg(is64bit ? 16 : 8), initial_opcodes, &eh_frame_data_); - WriteEhFrameFDE(is64bit, 0, 0x01000000, 0x01000000, opcodes.data(), &eh_frame_data_); + std::vector<uintptr_t> eh_frame_patches; + std::vector<uintptr_t> expected_patches { 28 }; // NOLINT + WriteEhFrameFDE(is64bit, 0, 0x01000000, 0x01000000, opcodes.data(), + &eh_frame_data_, &eh_frame_patches); + + EXPECT_EQ(expected_patches, eh_frame_patches); CheckObjdumpOutput(is64bit, "-W"); } -// TODO: objdump seems to have trouble with 64bit CIE length. -TEST_F(DwarfTest, DISABLED_DebugFrame64) { +TEST_F(DwarfTest, DebugFrame64) { constexpr bool is64bit = true; DebugFrameOpCodeWriter<> initial_opcodes; WriteEhFrameCIE(is64bit, Reg(16), initial_opcodes, &eh_frame_data_); DebugFrameOpCodeWriter<> opcodes; + std::vector<uintptr_t> eh_frame_patches; + std::vector<uintptr_t> expected_patches { 32 }; // NOLINT WriteEhFrameFDE(is64bit, 0, 0x0100000000000000, 0x0200000000000000, - opcodes.data(), &eh_frame_data_); + opcodes.data(), &eh_frame_data_, &eh_frame_patches); DW_CHECK("FDE cie=00000000 pc=100000000000000..300000000000000"); + + EXPECT_EQ(expected_patches, eh_frame_patches); CheckObjdumpOutput(is64bit, "-W"); } @@ -184,7 +192,12 @@ TEST_F(DwarfTest, DebugLine) { DW_CHECK_NEXT("Entry\tDir\tTime\tSize\tName"); DW_CHECK_NEXT("1\t0\t1000\t2000\tfile.c"); - WriteDebugLineTable(include_directories, files, opcodes, &debug_line_data_); + std::vector<uintptr_t> debug_line_patches; + std::vector<uintptr_t> expected_patches { 87 }; // NOLINT + WriteDebugLineTable(include_directories, files, opcodes, + &debug_line_data_, &debug_line_patches); + + EXPECT_EQ(expected_patches, debug_line_patches); CheckObjdumpOutput(is64bit, "-W"); } @@ -219,7 +232,10 @@ TEST_F(DwarfTest, DebugLineSpecialOpcodes) { std::vector<std::string> directories; std::vector<FileEntry> files { { "file.c", 0, 1000, 2000 } }; // NOLINT - WriteDebugLineTable(directories, files, opcodes, &debug_line_data_); + std::vector<uintptr_t> debug_line_patches; + WriteDebugLineTable(directories, files, opcodes, + &debug_line_data_, &debug_line_patches); + CheckObjdumpOutput(is64bit, "-W -WL"); } @@ -271,7 +287,12 @@ TEST_F(DwarfTest, DebugInfo) { DW_CHECK_NEXT("DW_AT_high_pc DW_FORM_addr"); DW_CHECK("3 DW_TAG_compile_unit [has children]"); - dwarf::WriteDebugInfoCU(0 /* debug_abbrev_offset */, info, &debug_info_data_); + std::vector<uintptr_t> debug_info_patches; + std::vector<uintptr_t> expected_patches { 16, 20, 29, 33, 42, 46 }; // NOLINT + dwarf::WriteDebugInfoCU(0 /* debug_abbrev_offset */, info, + &debug_info_data_, &debug_info_patches); + + EXPECT_EQ(expected_patches, debug_info_patches); CheckObjdumpOutput(is64bit, "-W"); } diff --git a/compiler/dwarf/headers.h b/compiler/dwarf/headers.h index d866b91..d17d327 100644 --- a/compiler/dwarf/headers.h +++ b/compiler/dwarf/headers.h @@ -17,6 +17,8 @@ #ifndef ART_COMPILER_DWARF_HEADERS_H_ #define ART_COMPILER_DWARF_HEADERS_H_ +#include <cstdint> + #include "debug_frame_opcode_writer.h" #include "debug_info_entry_writer.h" #include "debug_line_opcode_writer.h" @@ -26,6 +28,12 @@ namespace art { namespace dwarf { +// Note that all headers start with 32-bit length. +// DWARF also supports 64-bit lengths, but we never use that. +// It is intended to support very large debug sections (>4GB), +// and compilers are expected *not* to use it by default. +// In particular, it is not related to machine architecture. + // Write common information entry (CIE) to .eh_frame section. template<typename Allocator> void WriteEhFrameCIE(bool is64bit, Reg return_address_register, @@ -33,15 +41,8 @@ void WriteEhFrameCIE(bool is64bit, Reg return_address_register, std::vector<uint8_t>* eh_frame) { Writer<> writer(eh_frame); size_t cie_header_start_ = writer.data()->size(); - if (is64bit) { - // TODO: This is not related to being 64bit. - writer.PushUint32(0xffffffff); - writer.PushUint64(0); // Length placeholder. - writer.PushUint64(0); // CIE id. - } else { - writer.PushUint32(0); // Length placeholder. - writer.PushUint32(0); // CIE id. - } + writer.PushUint32(0); // Length placeholder. + writer.PushUint32(0); // CIE id. writer.PushUint8(1); // Version. writer.PushString("zR"); writer.PushUleb128(DebugFrameOpCodeWriter<Allocator>::kCodeAlignmentFactor); @@ -55,11 +56,7 @@ void WriteEhFrameCIE(bool is64bit, Reg return_address_register, } writer.PushData(opcodes.data()); writer.Pad(is64bit ? 8 : 4); - if (is64bit) { - writer.UpdateUint64(cie_header_start_ + 4, writer.data()->size() - cie_header_start_ - 12); - } else { - writer.UpdateUint32(cie_header_start_, writer.data()->size() - cie_header_start_ - 4); - } + writer.UpdateUint32(cie_header_start_, writer.data()->size() - cie_header_start_ - 4); } // Write frame description entry (FDE) to .eh_frame section. @@ -67,20 +64,15 @@ template<typename Allocator> void WriteEhFrameFDE(bool is64bit, size_t cie_offset, uint64_t initial_address, uint64_t address_range, const std::vector<uint8_t, Allocator>* opcodes, - std::vector<uint8_t>* eh_frame) { + std::vector<uint8_t>* eh_frame, + std::vector<uintptr_t>* eh_frame_patches) { Writer<> writer(eh_frame); size_t fde_header_start = writer.data()->size(); - if (is64bit) { - // TODO: This is not related to being 64bit. - writer.PushUint32(0xffffffff); - writer.PushUint64(0); // Length placeholder. - uint64_t cie_pointer = writer.data()->size() - cie_offset; - writer.PushUint64(cie_pointer); - } else { - writer.PushUint32(0); // Length placeholder. - uint32_t cie_pointer = writer.data()->size() - cie_offset; - writer.PushUint32(cie_pointer); - } + writer.PushUint32(0); // Length placeholder. + uint32_t cie_pointer = writer.data()->size() - cie_offset; + writer.PushUint32(cie_pointer); + // Relocate initial_address, but not address_range (it is size). + eh_frame_patches->push_back(writer.data()->size()); if (is64bit) { writer.PushUint64(initial_address); writer.PushUint64(address_range); @@ -91,26 +83,28 @@ void WriteEhFrameFDE(bool is64bit, size_t cie_offset, writer.PushUleb128(0); // Augmentation data size. writer.PushData(opcodes); writer.Pad(is64bit ? 8 : 4); - if (is64bit) { - writer.UpdateUint64(fde_header_start + 4, writer.data()->size() - fde_header_start - 12); - } else { - writer.UpdateUint32(fde_header_start, writer.data()->size() - fde_header_start - 4); - } + writer.UpdateUint32(fde_header_start, writer.data()->size() - fde_header_start - 4); } // Write compilation unit (CU) to .debug_info section. template<typename Allocator> void WriteDebugInfoCU(uint32_t debug_abbrev_offset, const DebugInfoEntryWriter<Allocator>& entries, - std::vector<uint8_t>* debug_info) { + std::vector<uint8_t>* debug_info, + std::vector<uintptr_t>* debug_info_patches) { Writer<> writer(debug_info); size_t start = writer.data()->size(); writer.PushUint32(0); // Length placeholder. writer.PushUint16(3); // Version. writer.PushUint32(debug_abbrev_offset); - writer.PushUint8(entries.is64bit() ? 8 : 4); + writer.PushUint8(entries.Is64bit() ? 8 : 4); + size_t entries_offset = writer.data()->size(); writer.PushData(entries.data()); writer.UpdateUint32(start, writer.data()->size() - start - 4); + // Copy patch locations and make them relative to .debug_info section. + for (uintptr_t patch_location : entries.GetPatchLocations()) { + debug_info_patches->push_back(entries_offset + patch_location); + } } struct FileEntry { @@ -125,7 +119,8 @@ template<typename Allocator> void WriteDebugLineTable(const std::vector<std::string>& include_directories, const std::vector<FileEntry>& files, const DebugLineOpCodeWriter<Allocator>& opcodes, - std::vector<uint8_t>* debug_line) { + std::vector<uint8_t>* debug_line, + std::vector<uintptr_t>* debug_line_patches) { Writer<> writer(debug_line); size_t header_start = writer.data()->size(); writer.PushUint32(0); // Section-length placeholder. @@ -157,8 +152,13 @@ void WriteDebugLineTable(const std::vector<std::string>& include_directories, } writer.PushUint8(0); // Terminate file list. writer.UpdateUint32(header_length_pos, writer.data()->size() - header_length_pos - 4); - writer.PushData(opcodes.data()->data(), opcodes.data()->size()); + size_t opcodes_offset = writer.data()->size(); + writer.PushData(opcodes.data()); writer.UpdateUint32(header_start, writer.data()->size() - header_start - 4); + // Copy patch locations and make them relative to .debug_line section. + for (uintptr_t patch_location : opcodes.GetPatchLocations()) { + debug_line_patches->push_back(opcodes_offset + patch_location); + } } } // namespace dwarf diff --git a/compiler/elf_writer_debug.cc b/compiler/elf_writer_debug.cc index 5e8e24b..6df5ea9 100644 --- a/compiler/elf_writer_debug.cc +++ b/compiler/elf_writer_debug.cc @@ -159,7 +159,7 @@ static void WriteEhFrameCIE(InstructionSet isa, std::vector<uint8_t>* eh_frame) * @param debug_line Line number table. */ void WriteDebugSections(const CompilerDriver* compiler, - const OatWriter* oat_writer, + OatWriter* oat_writer, uint32_t text_section_offset, std::vector<uint8_t>* eh_frame, std::vector<uint8_t>* debug_info, @@ -176,6 +176,7 @@ void WriteDebugSections(const CompilerDriver* compiler, } // Write .eh_frame section. + auto* eh_frame_patches = oat_writer->GetAbsolutePatchLocationsFor(".eh_frame"); size_t cie_offset = eh_frame->size(); WriteEhFrameCIE(isa, eh_frame); for (const OatWriter::DebugInfo& mi : method_infos) { @@ -183,7 +184,7 @@ void WriteDebugSections(const CompilerDriver* compiler, if (opcodes != nullptr) { WriteEhFrameFDE(Is64BitInstructionSet(isa), cie_offset, text_section_offset + mi.low_pc_, mi.high_pc_ - mi.low_pc_, - opcodes, eh_frame); + opcodes, eh_frame, eh_frame_patches); } } @@ -211,7 +212,8 @@ void WriteDebugSections(const CompilerDriver* compiler, info.EndTag(); // DW_TAG_subprogram } info.EndTag(); // DW_TAG_compile_unit - WriteDebugInfoCU(debug_abbrev_offset, info, debug_info); + auto* debug_info_patches = oat_writer->GetAbsolutePatchLocationsFor(".debug_info"); + WriteDebugInfoCU(debug_abbrev_offset, info, debug_info, debug_info_patches); // TODO: in gdb info functions <regexp> - reports Java functions, but // source file is <unknown> because .debug_line is formed as one @@ -353,7 +355,8 @@ void WriteDebugSections(const CompilerDriver* compiler, } opcodes.AdvancePC(text_section_offset + cunit_high_pc); opcodes.EndSequence(); - WriteDebugLineTable(directories, files, opcodes, debug_line); + auto* debug_line_patches = oat_writer->GetAbsolutePatchLocationsFor(".debug_line"); + WriteDebugLineTable(directories, files, opcodes, debug_line, debug_line_patches); } } // namespace dwarf diff --git a/compiler/elf_writer_debug.h b/compiler/elf_writer_debug.h index 39a99d6..4f1e333 100644 --- a/compiler/elf_writer_debug.h +++ b/compiler/elf_writer_debug.h @@ -25,7 +25,7 @@ namespace art { namespace dwarf { void WriteDebugSections(const CompilerDriver* compiler, - const OatWriter* oat_writer, + OatWriter* oat_writer, uint32_t text_section_offset, std::vector<uint8_t>* eh_frame_data, std::vector<uint8_t>* debug_info_data, diff --git a/compiler/elf_writer_quick.cc b/compiler/elf_writer_quick.cc index e9af25f..da1f81a 100644 --- a/compiler/elf_writer_quick.cc +++ b/compiler/elf_writer_quick.cc @@ -74,6 +74,40 @@ static void WriteDebugSymbols(const CompilerDriver* compiler_driver, Elf_Sym, Elf_Ehdr, Elf_Phdr, Elf_Shdr>* builder, OatWriter* oat_writer); +// Encode patch locations in .oat_patches format. +template <typename Elf_Word, typename Elf_Sword, typename Elf_Addr, + typename Elf_Dyn, typename Elf_Sym, typename Elf_Ehdr, + typename Elf_Phdr, typename Elf_Shdr> +void ElfWriterQuick<Elf_Word, Elf_Sword, Elf_Addr, Elf_Dyn, Elf_Sym, Elf_Ehdr, + Elf_Phdr, Elf_Shdr>::EncodeOatPatches(const OatWriter::PatchLocationsMap& sections, + std::vector<uint8_t>* buffer) { + for (const auto& section : sections) { + const std::string& name = section.first; + std::vector<uintptr_t>* locations = section.second.get(); + DCHECK(!name.empty()); + std::sort(locations->begin(), locations->end()); + // Reserve buffer space - guess 2 bytes per ULEB128. + buffer->reserve(buffer->size() + name.size() + locations->size() * 2); + // Write null-terminated section name. + const uint8_t* name_data = reinterpret_cast<const uint8_t*>(name.c_str()); + buffer->insert(buffer->end(), name_data, name_data + name.size() + 1); + // Write placeholder for data length. + size_t length_pos = buffer->size(); + EncodeUnsignedLeb128(buffer, UINT32_MAX); + // Write LEB128 encoded list of advances (deltas between consequtive addresses). + size_t data_pos = buffer->size(); + uintptr_t address = 0; // relative to start of section. + for (uintptr_t location : *locations) { + DCHECK_LT(location - address, UINT32_MAX) << "Large gap between patch locations"; + EncodeUnsignedLeb128(buffer, location - address); + address = location; + } + // Update length. + UpdateUnsignedLeb128(buffer->data() + length_pos, buffer->size() - data_pos); + } + buffer->push_back(0); // End of sections. +} + template <typename Elf_Word, typename Elf_Sword, typename Elf_Addr, typename Elf_Dyn, typename Elf_Sym, typename Elf_Ehdr, typename Elf_Phdr, typename Elf_Shdr> @@ -115,16 +149,13 @@ bool ElfWriterQuick<Elf_Word, Elf_Sword, Elf_Addr, Elf_Dyn, WriteDebugSymbols(compiler_driver_, builder.get(), oat_writer); } - if (compiler_driver_->GetCompilerOptions().GetIncludePatchInformation()) { + if (compiler_driver_->GetCompilerOptions().GetIncludePatchInformation() || + // ElfWriter::Fixup will be called regardless and it needs to be able + // to patch debug sections so we have to include patches for them. + compiler_driver_->GetCompilerOptions().GetIncludeDebugSymbols()) { ElfRawSectionBuilder<Elf_Word, Elf_Sword, Elf_Shdr> oat_patches( - ".oat_patches", SHT_OAT_PATCH, 0, NULL, 0, sizeof(uintptr_t), sizeof(uintptr_t)); - const std::vector<uintptr_t>& locations = oat_writer->GetAbsolutePatchLocations(); - const uint8_t* begin = reinterpret_cast<const uint8_t*>(&locations[0]); - const uint8_t* end = begin + locations.size() * sizeof(locations[0]); - oat_patches.GetBuffer()->assign(begin, end); - if (debug) { - LOG(INFO) << "Prepared .oat_patches for " << locations.size() << " patches."; - } + ".oat_patches", SHT_OAT_PATCH, 0, NULL, 0, 1, 0); + EncodeOatPatches(oat_writer->GetAbsolutePatchLocations(), oat_patches.GetBuffer()); builder->RegisterRawSection(oat_patches); } diff --git a/compiler/elf_writer_quick.h b/compiler/elf_writer_quick.h index 4990ed0..811beb4 100644 --- a/compiler/elf_writer_quick.h +++ b/compiler/elf_writer_quick.h @@ -19,6 +19,7 @@ #include "elf_utils.h" #include "elf_writer.h" +#include "oat_writer.h" namespace art { @@ -36,6 +37,9 @@ class ElfWriterQuick FINAL : public ElfWriter { const CompilerDriver& driver) SHARED_LOCKS_REQUIRED(Locks::mutator_lock_); + static void EncodeOatPatches(const OatWriter::PatchLocationsMap& sections, + std::vector<uint8_t>* buffer); + protected: bool Write(OatWriter* oat_writer, const std::vector<const DexFile*>& dex_files, diff --git a/compiler/elf_writer_test.cc b/compiler/elf_writer_test.cc index 8e2d175..3e5ad7b 100644 --- a/compiler/elf_writer_test.cc +++ b/compiler/elf_writer_test.cc @@ -19,6 +19,9 @@ #include "base/stringprintf.h" #include "base/unix_file/fd_file.h" #include "common_compiler_test.h" +#include "elf_file.h" +#include "elf_file_impl.h" +#include "elf_writer_quick.h" #include "oat.h" #include "utils.h" @@ -85,4 +88,73 @@ TEST_F(ElfWriterTest, dlsym) { } } +// Run only on host since we do unaligned memory accesses. +#ifndef HAVE_ANDROID_OS + +static void PatchSection(const std::vector<uintptr_t>& patch_locations, + std::vector<uint8_t>* section, int32_t delta) { + for (uintptr_t location : patch_locations) { + *reinterpret_cast<int32_t*>(section->data() + location) += delta; + } +} + +TEST_F(ElfWriterTest, EncodeDecodeOatPatches) { + std::vector<uint8_t> oat_patches; // Encoded patches. + + // Encode patch locations for a few sections. + OatWriter::PatchLocationsMap sections; + std::vector<uintptr_t> patches0 { 0, 4, 8, 15, 128, 200 }; // NOLINT + sections.emplace(".section0", std::unique_ptr<std::vector<uintptr_t>>( + new std::vector<uintptr_t> { patches0 })); + std::vector<uintptr_t> patches1 { 8, 127 }; // NOLINT + sections.emplace(".section1", std::unique_ptr<std::vector<uintptr_t>>( + new std::vector<uintptr_t> { patches1 })); + std::vector<uintptr_t> patches2 { }; // NOLINT + sections.emplace(".section2", std::unique_ptr<std::vector<uintptr_t>>( + new std::vector<uintptr_t> { patches2 })); + ElfWriterQuick32::EncodeOatPatches(sections, &oat_patches); + + // Create buffers to be patched. + std::vector<uint8_t> initial_data(256); + for (size_t i = 0; i < initial_data.size(); i++) { + initial_data[i] = i; + } + std::vector<uint8_t> section0_expected = initial_data; + std::vector<uint8_t> section1_expected = initial_data; + std::vector<uint8_t> section2_expected = initial_data; + std::vector<uint8_t> section0_actual = initial_data; + std::vector<uint8_t> section1_actual = initial_data; + std::vector<uint8_t> section2_actual = initial_data; + + // Patch manually. + constexpr int32_t delta = 0x11235813; + PatchSection(patches0, §ion0_expected, delta); + PatchSection(patches1, §ion1_expected, delta); + PatchSection(patches2, §ion2_expected, delta); + + // Decode and apply patch locations. + bool section0_successful = ElfFileImpl32::ApplyOatPatches( + oat_patches.data(), oat_patches.data() + oat_patches.size(), + ".section0", delta, + section0_actual.data(), section0_actual.data() + section0_actual.size()); + EXPECT_TRUE(section0_successful); + EXPECT_EQ(section0_expected, section0_actual); + + bool section1_successful = ElfFileImpl32::ApplyOatPatches( + oat_patches.data(), oat_patches.data() + oat_patches.size(), + ".section1", delta, + section1_actual.data(), section1_actual.data() + section1_actual.size()); + EXPECT_TRUE(section1_successful); + EXPECT_EQ(section1_expected, section1_actual); + + bool section2_successful = ElfFileImpl32::ApplyOatPatches( + oat_patches.data(), oat_patches.data() + oat_patches.size(), + ".section2", delta, + section2_actual.data(), section2_actual.data() + section2_actual.size()); + EXPECT_TRUE(section2_successful); + EXPECT_EQ(section2_expected, section2_actual); +} + +#endif + } // namespace art diff --git a/compiler/oat_writer.cc b/compiler/oat_writer.cc index 5b4cc54..62c9836 100644 --- a/compiler/oat_writer.cc +++ b/compiler/oat_writer.cc @@ -350,7 +350,8 @@ class OatWriter::InitCodeMethodVisitor : public OatDexMethodVisitor { public: InitCodeMethodVisitor(OatWriter* writer, size_t offset) : OatDexMethodVisitor(writer, offset) { - writer_->absolute_patch_locations_.reserve( + text_absolute_patch_locations_ = writer->GetAbsolutePatchLocationsFor(".text"); + text_absolute_patch_locations_->reserve( writer_->compiler_driver_->GetNonRelativeLinkerPatchCount()); } @@ -442,7 +443,7 @@ class OatWriter::InitCodeMethodVisitor : public OatDexMethodVisitor { uintptr_t base_loc = offset_ - code_size - writer_->oat_header_->GetExecutableOffset(); for (const LinkerPatch& patch : compiled_method->GetPatches()) { if (!patch.IsPcRelative()) { - writer_->absolute_patch_locations_.push_back(base_loc + patch.LiteralOffset()); + text_absolute_patch_locations_->push_back(base_loc + patch.LiteralOffset()); } } } @@ -532,6 +533,9 @@ class OatWriter::InitCodeMethodVisitor : public OatDexMethodVisitor { // Deduplication is already done on a pointer basis by the compiler driver, // so we can simply compare the pointers to find out if things are duplicated. SafeMap<const CompiledMethod*, uint32_t, CodeOffsetsKeyComparator> dedupe_map_; + + // Patch locations for the .text section. + std::vector<uintptr_t>* text_absolute_patch_locations_; }; template <typename DataAccess> diff --git a/compiler/oat_writer.h b/compiler/oat_writer.h index 51bc9b4..cc2b39a 100644 --- a/compiler/oat_writer.h +++ b/compiler/oat_writer.h @@ -19,6 +19,7 @@ #include <stdint.h> #include <cstddef> +#include <map> #include <memory> #include "linker/relative_patcher.h" // For linker::RelativePatcherTargetProvider. @@ -81,6 +82,8 @@ class TimingLogger; // class OatWriter { public: + typedef std::map<std::string, std::unique_ptr<std::vector<uintptr_t>>> PatchLocationsMap; + OatWriter(const std::vector<const DexFile*>& dex_files, uint32_t image_file_location_oat_checksum, uintptr_t image_file_location_oat_begin, @@ -102,10 +105,19 @@ class OatWriter { return bss_size_; } - const std::vector<uintptr_t>& GetAbsolutePatchLocations() const { + const PatchLocationsMap& GetAbsolutePatchLocations() const { return absolute_patch_locations_; } + std::vector<uintptr_t>* GetAbsolutePatchLocationsFor(const char* section_name) { + auto it = absolute_patch_locations_.emplace( + std::string(section_name), std::unique_ptr<std::vector<uintptr_t>>()); + if (it.second) { // Inserted new item. + it.first->second.reset(new std::vector<uintptr_t>()); + } + return it.first->second.get(); + } + void SetOatDataOffset(size_t oat_data_offset) { oat_data_offset_ = oat_data_offset; } @@ -330,8 +342,9 @@ class OatWriter { std::unique_ptr<linker::RelativePatcher> relative_patcher_; - // The locations of absolute patches relative to the start of the executable section. - std::vector<uintptr_t> absolute_patch_locations_; + // The locations of absolute patches relative to the start of section. + // The map's key is the ELF's section name (including the dot). + PatchLocationsMap absolute_patch_locations_; // Map method reference to assigned offset. // Wrap the map in a class implementing linker::RelativePatcherTargetProvider. diff --git a/patchoat/patchoat.cc b/patchoat/patchoat.cc index 74c9c38..4dc0967 100644 --- a/patchoat/patchoat.cc +++ b/patchoat/patchoat.cc @@ -625,35 +625,6 @@ bool PatchOat::Patch(File* input_oat, off_t delta, File* output_oat, TimingLogge return true; } -template <typename ElfFileImpl, typename ptr_t> -bool PatchOat::CheckOatFile(ElfFileImpl* oat_file) { - auto patches_sec = oat_file->FindSectionByName(".oat_patches"); - if (patches_sec->sh_type != SHT_OAT_PATCH) { - return false; - } - ptr_t* patches = reinterpret_cast<ptr_t*>(oat_file->Begin() + patches_sec->sh_offset); - ptr_t* patches_end = patches + (patches_sec->sh_size / sizeof(ptr_t)); - auto oat_data_sec = oat_file->FindSectionByName(".rodata"); - auto oat_text_sec = oat_file->FindSectionByName(".text"); - if (oat_data_sec == nullptr) { - return false; - } - if (oat_text_sec == nullptr) { - return false; - } - if (oat_text_sec->sh_offset <= oat_data_sec->sh_offset) { - return false; - } - - for (; patches < patches_end; patches++) { - if (oat_text_sec->sh_size <= *patches) { - return false; - } - } - - return true; -} - template <typename ElfFileImpl> bool PatchOat::PatchOatHeader(ElfFileImpl* oat_file) { auto rodata_sec = oat_file->FindSectionByName(".rodata"); @@ -679,7 +650,7 @@ bool PatchOat::PatchElf() { template <typename ElfFileImpl> bool PatchOat::PatchElf(ElfFileImpl* oat_file) { TimingLogger::ScopedTiming t("Fixup Elf Text Section", timings_); - if (!PatchTextSection<ElfFileImpl>(oat_file)) { + if (!oat_file->ApplyOatPatchesTo(".text", delta_)) { return false; } @@ -731,51 +702,6 @@ bool PatchOat::PatchElf(ElfFileImpl* oat_file) { return true; } -template <typename ElfFileImpl> -bool PatchOat::PatchTextSection(ElfFileImpl* oat_file) { - auto patches_sec = oat_file->FindSectionByName(".oat_patches"); - if (patches_sec == nullptr) { - LOG(ERROR) << ".oat_patches section not found. Aborting patch"; - return false; - } - if (patches_sec->sh_type != SHT_OAT_PATCH) { - LOG(ERROR) << "Unexpected type of .oat_patches"; - return false; - } - - switch (patches_sec->sh_entsize) { - case sizeof(uint32_t): - return PatchTextSection<ElfFileImpl, uint32_t>(oat_file); - case sizeof(uint64_t): - return PatchTextSection<ElfFileImpl, uint64_t>(oat_file); - default: - LOG(ERROR) << ".oat_patches Entsize of " << patches_sec->sh_entsize << "bits " - << "is not valid"; - return false; - } -} - -template <typename ElfFileImpl, typename patch_loc_t> -bool PatchOat::PatchTextSection(ElfFileImpl* oat_file) { - bool oat_file_valid = CheckOatFile<ElfFileImpl, patch_loc_t>(oat_file); - CHECK(oat_file_valid) << "Oat file invalid"; - auto patches_sec = oat_file->FindSectionByName(".oat_patches"); - patch_loc_t* patches = reinterpret_cast<patch_loc_t*>(oat_file->Begin() + patches_sec->sh_offset); - patch_loc_t* patches_end = patches + (patches_sec->sh_size / sizeof(patch_loc_t)); - auto oat_text_sec = oat_file->FindSectionByName(".text"); - CHECK(oat_text_sec != nullptr); - uint8_t* to_patch = oat_file->Begin() + oat_text_sec->sh_offset; - uintptr_t to_patch_end = reinterpret_cast<uintptr_t>(to_patch) + oat_text_sec->sh_size; - - for (; patches < patches_end; patches++) { - CHECK_LT(*patches, oat_text_sec->sh_size) << "Bad Patch"; - uint32_t* patch_loc = reinterpret_cast<uint32_t*>(to_patch + *patches); - CHECK_LT(reinterpret_cast<uintptr_t>(patch_loc), to_patch_end); - *patch_loc += delta_; - } - return true; -} - static int orig_argc; static char** orig_argv; diff --git a/patchoat/patchoat.h b/patchoat/patchoat.h index 418650a..86f9118 100644 --- a/patchoat/patchoat.h +++ b/patchoat/patchoat.h @@ -109,11 +109,6 @@ class PatchOat { template <typename ElfFileImpl> bool PatchElf(ElfFileImpl* oat_file); template <typename ElfFileImpl> - bool PatchTextSection(ElfFileImpl* oat_file); - // Templatized version to actually do the patching with the right sized offsets. - template <typename ElfFileImpl, typename patch_loc_t> bool PatchTextSection(ElfFileImpl* oat_file); - template <typename ElfFileImpl, typename patch_loc_t> bool CheckOatFile(ElfFileImpl* oat_filec); - template <typename ElfFileImpl> bool PatchOatHeader(ElfFileImpl* oat_file); bool PatchImage() SHARED_LOCKS_REQUIRED(Locks::mutator_lock_); diff --git a/runtime/elf_file.cc b/runtime/elf_file.cc index 411ec43..f2b013f 100644 --- a/runtime/elf_file.cc +++ b/runtime/elf_file.cc @@ -25,7 +25,6 @@ #include "base/stringprintf.h" #include "base/stl_util.h" #include "base/unix_file/fd_file.h" -#include "dwarf.h" #include "elf_file_impl.h" #include "elf_utils.h" #include "leb128.h" @@ -1587,487 +1586,6 @@ Elf_Shdr* ElfFileImpl<Elf_Ehdr, Elf_Phdr, Elf_Shdr, Elf_Word, return nullptr; } -struct PACKED(1) FDE32 { - uint32_t raw_length_; - uint32_t GetLength() { - return raw_length_ + sizeof(raw_length_); - } - uint32_t CIE_pointer; - uint32_t initial_location; - uint32_t address_range; - uint8_t instructions[0]; -}; - -static FDE32* NextFDE(FDE32* frame) { - uint8_t* fde_bytes = reinterpret_cast<uint8_t*>(frame); - fde_bytes += frame->GetLength(); - return reinterpret_cast<FDE32*>(fde_bytes); -} - -static bool IsFDE(FDE32* frame) { - return frame->CIE_pointer != 0; -} - -struct PACKED(1) FDE64 { - uint32_t raw_length_; - uint64_t extended_length_; - uint64_t GetLength() { - return extended_length_ + sizeof(raw_length_) + sizeof(extended_length_); - } - uint64_t CIE_pointer; - uint64_t initial_location; - uint64_t address_range; - uint8_t instructions[0]; -}; - -static FDE64* NextFDE(FDE64* frame) { - uint8_t* fde_bytes = reinterpret_cast<uint8_t*>(frame); - fde_bytes += frame->GetLength(); - return reinterpret_cast<FDE64*>(fde_bytes); -} - -static bool IsFDE(FDE64* frame) { - return frame->CIE_pointer != 0; -} - -template <typename Elf_SOff> -static bool FixupEHFrame(Elf_SOff base_address_delta, uint8_t* eh_frame, size_t eh_frame_size) { - // TODO: Check the spec whether this is really data-dependent, or whether it's clear from the - // ELF file whether we should expect 32-bit or 64-bit. - if (*(reinterpret_cast<uint32_t*>(eh_frame)) == 0xffffffff) { - FDE64* last_frame = reinterpret_cast<FDE64*>(eh_frame + eh_frame_size); - FDE64* frame = NextFDE(reinterpret_cast<FDE64*>(eh_frame)); - for (; frame < last_frame; frame = NextFDE(frame)) { - if (!IsFDE(frame)) { - return false; - } - frame->initial_location += base_address_delta; - } - return true; - } else { - CHECK(IsInt<32>(base_address_delta)); - FDE32* last_frame = reinterpret_cast<FDE32*>(eh_frame + eh_frame_size); - FDE32* frame = NextFDE(reinterpret_cast<FDE32*>(eh_frame)); - for (; frame < last_frame; frame = NextFDE(frame)) { - if (!IsFDE(frame)) { - return false; - } - frame->initial_location += base_address_delta; - } - return true; - } -} - -static uint8_t* NextLeb128(uint8_t* current) { - DecodeUnsignedLeb128(const_cast<const uint8_t**>(¤t)); - return current; -} - -struct PACKED(1) DebugLineHeader { - uint32_t unit_length_; // TODO 32-bit specific size - uint16_t version_; - uint32_t header_length_; // TODO 32-bit specific size - uint8_t minimum_instruction_lenght_; - uint8_t default_is_stmt_; - int8_t line_base_; - uint8_t line_range_; - uint8_t opcode_base_; - uint8_t remaining_[0]; - - bool IsStandardOpcode(const uint8_t* op) const { - return *op != 0 && *op < opcode_base_; - } - - bool IsExtendedOpcode(const uint8_t* op) const { - return *op == 0; - } - - const uint8_t* GetStandardOpcodeLengths() const { - return remaining_; - } - - uint8_t* GetNextOpcode(uint8_t* op) const { - if (IsExtendedOpcode(op)) { - uint8_t* length_field = op + 1; - uint32_t length = DecodeUnsignedLeb128(const_cast<const uint8_t**>(&length_field)); - return length_field + length; - } else if (!IsStandardOpcode(op)) { - return op + 1; - } else if (*op == dwarf::DW_LNS_fixed_advance_pc) { - return op + 1 + sizeof(uint16_t); - } else { - uint8_t num_args = GetStandardOpcodeLengths()[*op - 1]; - op += 1; - for (int i = 0; i < num_args; i++) { - op = NextLeb128(op); - } - return op; - } - } - - uint8_t* GetDebugLineData() const { - const uint8_t* hdr_start = - reinterpret_cast<const uint8_t*>(&header_length_) + sizeof(header_length_); - return const_cast<uint8_t*>(hdr_start + header_length_); - } -}; - -class DebugLineInstructionIterator FINAL { - public: - static DebugLineInstructionIterator* Create(DebugLineHeader* header, size_t section_size) { - std::unique_ptr<DebugLineInstructionIterator> line_iter( - new DebugLineInstructionIterator(header, section_size)); - if (line_iter.get() == nullptr) { - return nullptr; - } else { - return line_iter.release(); - } - } - - ~DebugLineInstructionIterator() {} - - bool Next() { - if (current_instruction_ == nullptr) { - return false; - } - current_instruction_ = header_->GetNextOpcode(current_instruction_); - if (current_instruction_ >= last_instruction_) { - current_instruction_ = nullptr; - return false; - } else { - return true; - } - } - - uint8_t* GetInstruction() const { - return current_instruction_; - } - - bool IsExtendedOpcode() const { - return header_->IsExtendedOpcode(current_instruction_); - } - - uint8_t GetOpcode() { - if (!IsExtendedOpcode()) { - return *current_instruction_; - } else { - uint8_t* len_ptr = current_instruction_ + 1; - return *NextLeb128(len_ptr); - } - } - - uint8_t* GetArguments() { - if (!IsExtendedOpcode()) { - return current_instruction_ + 1; - } else { - uint8_t* len_ptr = current_instruction_ + 1; - return NextLeb128(len_ptr) + 1; - } - } - - private: - DebugLineInstructionIterator(DebugLineHeader* header, size_t size) - : header_(header), last_instruction_(reinterpret_cast<uint8_t*>(header) + size), - current_instruction_(header->GetDebugLineData()) {} - - DebugLineHeader* const header_; - uint8_t* const last_instruction_; - uint8_t* current_instruction_; -}; - -template <typename Elf_SOff> -static bool FixupDebugLine(Elf_SOff base_offset_delta, DebugLineInstructionIterator* iter) { - CHECK(IsInt<32>(base_offset_delta)); - for (; iter->GetInstruction(); iter->Next()) { - if (iter->IsExtendedOpcode() && iter->GetOpcode() == dwarf::DW_LNE_set_address) { - *reinterpret_cast<uint32_t*>(iter->GetArguments()) += base_offset_delta; - } - } - return true; -} - -struct PACKED(1) DebugInfoHeader { - uint32_t unit_length; // TODO 32-bit specific size - uint16_t version; - uint32_t debug_abbrev_offset; // TODO 32-bit specific size - uint8_t address_size; -}; - -// Returns -1 if it is variable length, which we will just disallow for now. -static int32_t FormLength(uint32_t att) { - switch (att) { - case dwarf::DW_FORM_data1: - case dwarf::DW_FORM_flag: - case dwarf::DW_FORM_flag_present: - case dwarf::DW_FORM_ref1: - return 1; - - case dwarf::DW_FORM_data2: - case dwarf::DW_FORM_ref2: - return 2; - - case dwarf::DW_FORM_addr: // TODO 32-bit only - case dwarf::DW_FORM_ref_addr: // TODO 32-bit only - case dwarf::DW_FORM_sec_offset: // TODO 32-bit only - case dwarf::DW_FORM_strp: // TODO 32-bit only - case dwarf::DW_FORM_data4: - case dwarf::DW_FORM_ref4: - return 4; - - case dwarf::DW_FORM_data8: - case dwarf::DW_FORM_ref8: - case dwarf::DW_FORM_ref_sig8: - return 8; - - case dwarf::DW_FORM_block: - case dwarf::DW_FORM_block1: - case dwarf::DW_FORM_block2: - case dwarf::DW_FORM_block4: - case dwarf::DW_FORM_exprloc: - case dwarf::DW_FORM_indirect: - case dwarf::DW_FORM_ref_udata: - case dwarf::DW_FORM_sdata: - case dwarf::DW_FORM_string: - case dwarf::DW_FORM_udata: - default: - return -1; - } -} - -class DebugTag FINAL { - public: - ~DebugTag() {} - // Creates a new tag and moves data pointer up to the start of the next one. - // nullptr means error. - static DebugTag* Create(const uint8_t** data_pointer) { - const uint8_t* data = *data_pointer; - uint32_t index = DecodeUnsignedLeb128(&data); - std::unique_ptr<DebugTag> tag(new DebugTag(index)); - tag->size_ = static_cast<uint32_t>( - reinterpret_cast<uintptr_t>(data) - reinterpret_cast<uintptr_t>(*data_pointer)); - // skip the abbrev - tag->tag_ = DecodeUnsignedLeb128(&data); - tag->has_child_ = (*data == 0); - data++; - while (true) { - uint32_t attr = DecodeUnsignedLeb128(&data); - uint32_t form = DecodeUnsignedLeb128(&data); - if (attr == 0 && form == 0) { - break; - } else if (attr == 0 || form == 0) { - // Bad abbrev. - return nullptr; - } - int32_t size = FormLength(form); - if (size == -1) { - return nullptr; - } - tag->AddAttribute(attr, static_cast<uint32_t>(size)); - } - *data_pointer = data; - return tag.release(); - } - - uint32_t GetSize() const { - return size_; - } - - bool HasChild() const { - return has_child_; - } - - uint32_t GetTagNumber() const { - return tag_; - } - - uint32_t GetIndex() const { - return index_; - } - - // Gets the offset of a particular attribute in this tag structure. - // Interpretation of the data is left to the consumer. 0 is returned if the - // tag does not contain the attribute. - uint32_t GetOffsetOf(uint32_t dwarf_attribute) const { - auto it = off_map_.find(dwarf_attribute); - if (it == off_map_.end()) { - return 0; - } else { - return it->second; - } - } - - // Gets the size of attribute - uint32_t GetAttrSize(uint32_t dwarf_attribute) const { - auto it = size_map_.find(dwarf_attribute); - if (it == size_map_.end()) { - return 0; - } else { - return it->second; - } - } - - private: - explicit DebugTag(uint32_t index) : index_(index), size_(0), tag_(0), has_child_(false) {} - void AddAttribute(uint32_t type, uint32_t attr_size) { - off_map_.insert(std::pair<uint32_t, uint32_t>(type, size_)); - size_map_.insert(std::pair<uint32_t, uint32_t>(type, attr_size)); - size_ += attr_size; - } - - const uint32_t index_; - std::map<uint32_t, uint32_t> off_map_; - std::map<uint32_t, uint32_t> size_map_; - uint32_t size_; - uint32_t tag_; - bool has_child_; -}; - -class DebugAbbrev { - public: - ~DebugAbbrev() {} - static DebugAbbrev* Create(const uint8_t* dbg_abbrev, size_t dbg_abbrev_size) { - std::unique_ptr<DebugAbbrev> abbrev(new DebugAbbrev(dbg_abbrev, dbg_abbrev + dbg_abbrev_size)); - if (!abbrev->ReadAtOffset(0)) { - return nullptr; - } - return abbrev.release(); - } - - bool ReadAtOffset(uint32_t abbrev_offset) { - tags_.clear(); - tag_list_.clear(); - const uint8_t* dbg_abbrev = begin_ + abbrev_offset; - while (dbg_abbrev < end_ && *dbg_abbrev != 0) { - std::unique_ptr<DebugTag> tag(DebugTag::Create(&dbg_abbrev)); - if (tag.get() == nullptr) { - return false; - } else { - tags_.insert(std::pair<uint32_t, uint32_t>(tag->GetIndex(), tag_list_.size())); - tag_list_.push_back(std::move(tag)); - } - } - return true; - } - - DebugTag* ReadTag(const uint8_t* entry) { - uint32_t tag_num = DecodeUnsignedLeb128(&entry); - auto it = tags_.find(tag_num); - if (it == tags_.end()) { - return nullptr; - } else { - CHECK_GT(tag_list_.size(), it->second); - return tag_list_.at(it->second).get(); - } - } - - private: - DebugAbbrev(const uint8_t* begin, const uint8_t* end) : begin_(begin), end_(end) {} - const uint8_t* const begin_; - const uint8_t* const end_; - std::map<uint32_t, uint32_t> tags_; - std::vector<std::unique_ptr<DebugTag>> tag_list_; -}; - -class DebugInfoIterator { - public: - static DebugInfoIterator* Create(DebugInfoHeader* header, size_t frame_size, - DebugAbbrev* abbrev) { - std::unique_ptr<DebugInfoIterator> iter(new DebugInfoIterator(header, frame_size, abbrev)); - if (iter->GetCurrentTag() == nullptr) { - return nullptr; - } else { - return iter.release(); - } - } - ~DebugInfoIterator() {} - - // Moves to the next DIE. Returns false if at last entry. - // TODO Handle variable length attributes. - bool next() { - if (current_entry_ == nullptr || current_tag_ == nullptr) { - return false; - } - bool reread_abbrev = false; - current_entry_ += current_tag_->GetSize(); - if (reinterpret_cast<DebugInfoHeader*>(current_entry_) >= next_cu_) { - current_cu_ = next_cu_; - next_cu_ = GetNextCu(current_cu_); - current_entry_ = reinterpret_cast<uint8_t*>(current_cu_) + sizeof(DebugInfoHeader); - reread_abbrev = true; - } - if (current_entry_ >= last_entry_) { - current_entry_ = nullptr; - return false; - } - if (reread_abbrev) { - abbrev_->ReadAtOffset(current_cu_->debug_abbrev_offset); - } - current_tag_ = abbrev_->ReadTag(current_entry_); - if (current_tag_ == nullptr) { - current_entry_ = nullptr; - return false; - } else { - return true; - } - } - - const DebugTag* GetCurrentTag() { - return const_cast<DebugTag*>(current_tag_); - } - uint8_t* GetPointerToField(uint8_t dwarf_field) { - if (current_tag_ == nullptr || current_entry_ == nullptr || current_entry_ >= last_entry_) { - return nullptr; - } - uint32_t off = current_tag_->GetOffsetOf(dwarf_field); - if (off == 0) { - // tag does not have that field. - return nullptr; - } else { - DCHECK_LT(off, current_tag_->GetSize()); - return current_entry_ + off; - } - } - - private: - static DebugInfoHeader* GetNextCu(DebugInfoHeader* hdr) { - uint8_t* hdr_byte = reinterpret_cast<uint8_t*>(hdr); - return reinterpret_cast<DebugInfoHeader*>(hdr_byte + sizeof(uint32_t) + hdr->unit_length); - } - - DebugInfoIterator(DebugInfoHeader* header, size_t frame_size, DebugAbbrev* abbrev) - : abbrev_(abbrev), - current_cu_(header), - next_cu_(GetNextCu(header)), - last_entry_(reinterpret_cast<uint8_t*>(header) + frame_size), - current_entry_(reinterpret_cast<uint8_t*>(header) + sizeof(DebugInfoHeader)), - current_tag_(abbrev_->ReadTag(current_entry_)) {} - DebugAbbrev* const abbrev_; - DebugInfoHeader* current_cu_; - DebugInfoHeader* next_cu_; - uint8_t* const last_entry_; - uint8_t* current_entry_; - DebugTag* current_tag_; -}; - -template <typename Elf_SOff> -static bool FixupDebugInfo(Elf_SOff base_address_delta, DebugInfoIterator* iter) { - CHECK(IsInt<32>(base_address_delta)); - do { - if (iter->GetCurrentTag()->GetAttrSize(dwarf::DW_AT_low_pc) != sizeof(int32_t) || - iter->GetCurrentTag()->GetAttrSize(dwarf::DW_AT_high_pc) != sizeof(int32_t)) { - LOG(ERROR) << "DWARF information with 64 bit pointers is not supported yet."; - return false; - } - uint32_t* PC_low = reinterpret_cast<uint32_t*>(iter->GetPointerToField(dwarf::DW_AT_low_pc)); - uint32_t* PC_high = reinterpret_cast<uint32_t*>(iter->GetPointerToField(dwarf::DW_AT_high_pc)); - if (PC_low != nullptr && PC_high != nullptr) { - *PC_low += base_address_delta; - *PC_high += base_address_delta; - } - } while (iter->next()); - return true; -} - template <typename Elf_Ehdr, typename Elf_Phdr, typename Elf_Shdr, typename Elf_Word, typename Elf_Sword, typename Elf_Addr, typename Elf_Sym, typename Elf_Rel, typename Elf_Rela, typename Elf_Dyn, typename Elf_Off> @@ -2076,9 +1594,7 @@ bool ElfFileImpl<Elf_Ehdr, Elf_Phdr, Elf_Shdr, Elf_Word, ::FixupDebugSections(typename std::make_signed<Elf_Off>::type base_address_delta) { const Elf_Shdr* debug_info = FindSectionByName(".debug_info"); const Elf_Shdr* debug_abbrev = FindSectionByName(".debug_abbrev"); - const Elf_Shdr* eh_frame = FindSectionByName(".eh_frame"); const Elf_Shdr* debug_str = FindSectionByName(".debug_str"); - const Elf_Shdr* debug_line = FindSectionByName(".debug_line"); const Elf_Shdr* strtab_sec = FindSectionByName(".strtab"); const Elf_Shdr* symtab_sec = FindSectionByName(".symtab"); @@ -2090,37 +1606,82 @@ bool ElfFileImpl<Elf_Ehdr, Elf_Phdr, Elf_Shdr, Elf_Word, if (base_address_delta == 0) { return true; } - if (eh_frame != nullptr && - !FixupEHFrame(base_address_delta, Begin() + eh_frame->sh_offset, eh_frame->sh_size)) { + if (!ApplyOatPatchesTo(".eh_frame", base_address_delta)) { + return false; + } + if (!ApplyOatPatchesTo(".debug_info", base_address_delta)) { return false; } + if (!ApplyOatPatchesTo(".debug_line", base_address_delta)) { + return false; + } + return true; +} - std::unique_ptr<DebugAbbrev> abbrev(DebugAbbrev::Create(Begin() + debug_abbrev->sh_offset, - debug_abbrev->sh_size)); - if (abbrev.get() == nullptr) { +template <typename Elf_Ehdr, typename Elf_Phdr, typename Elf_Shdr, typename Elf_Word, + typename Elf_Sword, typename Elf_Addr, typename Elf_Sym, typename Elf_Rel, + typename Elf_Rela, typename Elf_Dyn, typename Elf_Off> +bool ElfFileImpl<Elf_Ehdr, Elf_Phdr, Elf_Shdr, Elf_Word, + Elf_Sword, Elf_Addr, Elf_Sym, Elf_Rel, Elf_Rela, Elf_Dyn, Elf_Off> + ::ApplyOatPatchesTo(const char* target_section_name, + typename std::make_signed<Elf_Off>::type delta) { + auto patches_section = FindSectionByName(".oat_patches"); + if (patches_section == nullptr) { + LOG(ERROR) << ".oat_patches section not found."; return false; } - DebugInfoHeader* info_header = - reinterpret_cast<DebugInfoHeader*>(Begin() + debug_info->sh_offset); - std::unique_ptr<DebugInfoIterator> info_iter(DebugInfoIterator::Create(info_header, - debug_info->sh_size, - abbrev.get())); - if (info_iter.get() == nullptr) { + if (patches_section->sh_type != SHT_OAT_PATCH) { + LOG(ERROR) << "Unexpected type of .oat_patches."; return false; } - if (debug_line != nullptr) { - DebugLineHeader* line_header = - reinterpret_cast<DebugLineHeader*>(Begin() + debug_line->sh_offset); - std::unique_ptr<DebugLineInstructionIterator> line_iter( - DebugLineInstructionIterator::Create(line_header, debug_line->sh_size)); - if (line_iter.get() == nullptr) { - return false; - } - if (!FixupDebugLine(base_address_delta, line_iter.get())) { - return false; + auto target_section = FindSectionByName(target_section_name); + if (target_section == nullptr) { + LOG(ERROR) << target_section_name << " section not found."; + return false; + } + if (!ApplyOatPatches( + Begin() + patches_section->sh_offset, + Begin() + patches_section->sh_offset + patches_section->sh_size, + target_section_name, delta, + Begin() + target_section->sh_offset, + Begin() + target_section->sh_offset + target_section->sh_size)) { + LOG(ERROR) << target_section_name << " section not found in .oat_patches."; + } + return true; +} + +// Apply .oat_patches to given section. +template <typename Elf_Ehdr, typename Elf_Phdr, typename Elf_Shdr, typename Elf_Word, + typename Elf_Sword, typename Elf_Addr, typename Elf_Sym, typename Elf_Rel, + typename Elf_Rela, typename Elf_Dyn, typename Elf_Off> +bool ElfFileImpl<Elf_Ehdr, Elf_Phdr, Elf_Shdr, Elf_Word, + Elf_Sword, Elf_Addr, Elf_Sym, Elf_Rel, Elf_Rela, Elf_Dyn, Elf_Off> + ::ApplyOatPatches(const uint8_t* patches, const uint8_t* patches_end, + const char* target_section_name, + typename std::make_signed<Elf_Off>::type delta, + uint8_t* to_patch, const uint8_t* to_patch_end) { + // Read null-terminated section name. + const char* section_name; + while ((section_name = reinterpret_cast<const char*>(patches))[0] != '\0') { + patches += strlen(section_name) + 1; + uint32_t length = DecodeUnsignedLeb128(&patches); + const uint8_t* next_section = patches + length; + // Is it the section we want to patch? + if (strcmp(section_name, target_section_name) == 0) { + // Read LEB128 encoded list of advances. + while (patches < next_section) { + DCHECK_LT(patches, patches_end) << "Unexpected end of .oat_patches."; + to_patch += DecodeUnsignedLeb128(&patches); + DCHECK_LT(to_patch, to_patch_end) << "Patch past the end of " << section_name; + // TODO: 32-bit vs 64-bit. What is the right type to use here? + auto* patch_loc = reinterpret_cast<typename std::make_signed<Elf_Off>::type*>(to_patch); + *patch_loc += delta; + } + return true; } + patches = next_section; } - return FixupDebugInfo(base_address_delta, info_iter.get()); + return false; } template <typename Elf_Ehdr, typename Elf_Phdr, typename Elf_Shdr, typename Elf_Word, diff --git a/runtime/elf_file_impl.h b/runtime/elf_file_impl.h index 16d3857..383dc41 100644 --- a/runtime/elf_file_impl.h +++ b/runtime/elf_file_impl.h @@ -110,6 +110,12 @@ class ElfFileImpl { bool FixupSymbols(Elf_Addr base_address, bool dynamic); bool FixupRelocations(Elf_Addr base_address); bool FixupDebugSections(typename std::make_signed<Elf_Off>::type base_address_delta); + bool ApplyOatPatchesTo(const char* target_section_name, + typename std::make_signed<Elf_Off>::type base_address_delta); + static bool ApplyOatPatches(const uint8_t* patches, const uint8_t* patches_end, + const char* target_section_name, + typename std::make_signed<Elf_Off>::type delta, + uint8_t* to_patch, const uint8_t* to_patch_end); bool Strip(std::string* error_msg); |