diff options
author | David Srbecky <dsrbecky@google.com> | 2015-06-19 18:25:56 +0000 |
---|---|---|
committer | Android (Google) Code Review <android-gerrit@google.com> | 2015-06-19 18:26:45 +0000 |
commit | db538d309bc34e025e921a04f10b4ee745bd9f1d (patch) | |
tree | 9ff4d516df8d23a62bdb2a573575b31df00c5237 /compiler | |
parent | 3e91a44bc9063f7f69b5415e3cf162991f73283f (diff) | |
parent | a26cb57f46fd3f27a930d9d688fe8670c1f24754 (diff) | |
download | art-db538d309bc34e025e921a04f10b4ee745bd9f1d.zip art-db538d309bc34e025e921a04f10b4ee745bd9f1d.tar.gz art-db538d309bc34e025e921a04f10b4ee745bd9f1d.tar.bz2 |
Merge "ART stack unwinding fixes for libunwind/gdb/lldb." into mnc-dev
Diffstat (limited to 'compiler')
-rw-r--r-- | compiler/cfi_test.h | 12 | ||||
-rw-r--r-- | compiler/dex/quick/codegen_util.cc | 4 | ||||
-rw-r--r-- | compiler/dex/quick/quick_cfi_test.cc | 3 | ||||
-rw-r--r-- | compiler/dex/quick/x86/quick_assemble_x86_test.cc | 3 | ||||
-rw-r--r-- | compiler/driver/compiler_driver.cc | 4 | ||||
-rw-r--r-- | compiler/driver/compiler_options.cc | 9 | ||||
-rw-r--r-- | compiler/driver/compiler_options.h | 17 | ||||
-rw-r--r-- | compiler/dwarf/dwarf_constants.h | 8 | ||||
-rw-r--r-- | compiler/dwarf/dwarf_test.cc | 36 | ||||
-rw-r--r-- | compiler/dwarf/dwarf_test.h | 10 | ||||
-rw-r--r-- | compiler/dwarf/headers.h | 43 | ||||
-rw-r--r-- | compiler/elf_builder.h | 31 | ||||
-rw-r--r-- | compiler/elf_writer_debug.cc | 110 | ||||
-rw-r--r-- | compiler/elf_writer_debug.h | 15 | ||||
-rw-r--r-- | compiler/elf_writer_quick.cc | 185 | ||||
-rw-r--r-- | compiler/elf_writer_quick.h | 2 | ||||
-rw-r--r-- | compiler/elf_writer_test.cc | 98 | ||||
-rw-r--r-- | compiler/jit/jit_compiler.cc | 3 | ||||
-rw-r--r-- | compiler/jni/quick/jni_compiler.cc | 2 | ||||
-rw-r--r-- | compiler/oat_writer.cc | 11 | ||||
-rw-r--r-- | compiler/oat_writer.h | 19 | ||||
-rw-r--r-- | compiler/optimizing/optimizing_compiler.cc | 6 |
22 files changed, 322 insertions, 309 deletions
diff --git a/compiler/cfi_test.h b/compiler/cfi_test.h index f7501d2..5e345db 100644 --- a/compiler/cfi_test.h +++ b/compiler/cfi_test.h @@ -30,6 +30,8 @@ namespace art { +constexpr dwarf::CFIFormat kCFIFormat = dwarf::DW_DEBUG_FRAME_FORMAT; + class CFITest : public dwarf::DwarfTest { public: void GenerateExpected(FILE* f, InstructionSet isa, const char* isa_str, @@ -46,11 +48,11 @@ class CFITest : public dwarf::DwarfTest { // Pretty-print CFI opcodes. constexpr bool is64bit = false; dwarf::DebugFrameOpCodeWriter<> initial_opcodes; - dwarf::WriteEhFrameCIE(is64bit, dwarf::DW_EH_PE_absptr, dwarf::Reg(8), - initial_opcodes, &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); + dwarf::WriteDebugFrameCIE(is64bit, dwarf::DW_EH_PE_absptr, dwarf::Reg(8), + initial_opcodes, kCFIFormat, &debug_frame_data_); + std::vector<uintptr_t> debug_frame_patches; + dwarf::WriteDebugFrameFDE(is64bit, 0, 0, actual_asm.size(), &actual_cfi, + kCFIFormat, &debug_frame_data_, &debug_frame_patches); ReformatCfi(Objdump(false, "-W"), &lines); // Pretty-print assembly. auto* opts = new DisassemblerOptions(false, actual_asm.data(), true); diff --git a/compiler/dex/quick/codegen_util.cc b/compiler/dex/quick/codegen_util.cc index f4bf31f..c803e65 100644 --- a/compiler/dex/quick/codegen_util.cc +++ b/compiler/dex/quick/codegen_util.cc @@ -670,7 +670,7 @@ bool Mir2Lir::VerifyCatchEntries() { void Mir2Lir::CreateMappingTables() { - bool generate_src_map = cu_->compiler_driver->GetCompilerOptions().GetIncludeDebugSymbols(); + bool generate_src_map = cu_->compiler_driver->GetCompilerOptions().GetGenerateDebugInfo(); uint32_t pc2dex_data_size = 0u; uint32_t pc2dex_entries = 0u; @@ -1071,7 +1071,7 @@ Mir2Lir::Mir2Lir(CompilationUnit* cu, MIRGraph* mir_graph, ArenaAllocator* arena pc_rel_temp_(nullptr), dex_cache_arrays_min_offset_(std::numeric_limits<uint32_t>::max()), cfi_(&last_lir_insn_, - cu->compiler_driver->GetCompilerOptions().GetIncludeCFI(), + cu->compiler_driver->GetCompilerOptions().GetGenerateDebugInfo(), arena), in_to_reg_storage_mapping_(arena) { switch_tables_.reserve(4); diff --git a/compiler/dex/quick/quick_cfi_test.cc b/compiler/dex/quick/quick_cfi_test.cc index 8694ebc..dd68dd4 100644 --- a/compiler/dex/quick/quick_cfi_test.cc +++ b/compiler/dex/quick/quick_cfi_test.cc @@ -59,8 +59,7 @@ class QuickCFITest : public CFITest { false, CompilerOptions::kDefaultTopKProfileThreshold, false, - true, // include_debug_symbols. - true, // include_cfi + true, // generate_debug_info. false, false, false, diff --git a/compiler/dex/quick/x86/quick_assemble_x86_test.cc b/compiler/dex/quick/x86/quick_assemble_x86_test.cc index f58f206..798e23f 100644 --- a/compiler/dex/quick/x86/quick_assemble_x86_test.cc +++ b/compiler/dex/quick/x86/quick_assemble_x86_test.cc @@ -42,8 +42,7 @@ class QuickAssembleX86TestBase : public testing::Test { false, CompilerOptions::kDefaultTopKProfileThreshold, false, - false, - false, + CompilerOptions::kDefaultGenerateDebugInfo, false, false, false, diff --git a/compiler/driver/compiler_driver.cc b/compiler/driver/compiler_driver.cc index 55fabcc..e5fa54e 100644 --- a/compiler/driver/compiler_driver.cc +++ b/compiler/driver/compiler_driver.cc @@ -76,8 +76,8 @@ namespace art { static constexpr bool kTimeCompileMethod = !kIsDebugBuild; -// Whether to produce 64-bit ELF files for 64-bit targets. Leave this off for now. -static constexpr bool kProduce64BitELFFiles = false; +// Whether to produce 64-bit ELF files for 64-bit targets. +static constexpr bool kProduce64BitELFFiles = true; // Whether classes-to-compile and methods-to-compile are only applied to the boot image, or, when // given, too all compilations. diff --git a/compiler/driver/compiler_options.cc b/compiler/driver/compiler_options.cc index c5fc98a..226e6b7 100644 --- a/compiler/driver/compiler_options.cc +++ b/compiler/driver/compiler_options.cc @@ -30,8 +30,7 @@ CompilerOptions::CompilerOptions() include_patch_information_(kDefaultIncludePatchInformation), top_k_profile_threshold_(kDefaultTopKProfileThreshold), debuggable_(false), - include_debug_symbols_(kDefaultIncludeDebugSymbols), - include_cfi_(false), + generate_debug_info_(kDefaultGenerateDebugInfo), implicit_null_checks_(true), implicit_so_checks_(true), implicit_suspend_checks_(false), @@ -56,8 +55,7 @@ CompilerOptions::CompilerOptions(CompilerFilter compiler_filter, bool include_patch_information, double top_k_profile_threshold, bool debuggable, - bool include_debug_symbols, - bool include_cfi, + bool generate_debug_info, bool implicit_null_checks, bool implicit_so_checks, bool implicit_suspend_checks, @@ -76,8 +74,7 @@ CompilerOptions::CompilerOptions(CompilerFilter compiler_filter, include_patch_information_(include_patch_information), top_k_profile_threshold_(top_k_profile_threshold), debuggable_(debuggable), - include_debug_symbols_(include_debug_symbols), - include_cfi_(include_cfi), + generate_debug_info_(generate_debug_info), implicit_null_checks_(implicit_null_checks), implicit_so_checks_(implicit_so_checks), implicit_suspend_checks_(implicit_suspend_checks), diff --git a/compiler/driver/compiler_options.h b/compiler/driver/compiler_options.h index bf3f8ec..356663b 100644 --- a/compiler/driver/compiler_options.h +++ b/compiler/driver/compiler_options.h @@ -49,7 +49,7 @@ class CompilerOptions FINAL { static const size_t kDefaultTinyMethodThreshold = 20; static const size_t kDefaultNumDexMethodsThreshold = 900; static constexpr double kDefaultTopKProfileThreshold = 90.0; - static const bool kDefaultIncludeDebugSymbols = kIsDebugBuild; + static const bool kDefaultGenerateDebugInfo = kIsDebugBuild; static const bool kDefaultIncludePatchInformation = false; CompilerOptions(); @@ -64,8 +64,7 @@ class CompilerOptions FINAL { bool include_patch_information, double top_k_profile_threshold, bool debuggable, - bool include_debug_symbols, - bool include_cfi, + bool generate_debug_info, bool implicit_null_checks, bool implicit_so_checks, bool implicit_suspend_checks, @@ -146,13 +145,8 @@ class CompilerOptions FINAL { return debuggable_; } - bool GetIncludeDebugSymbols() const { - return include_debug_symbols_; - } - - bool GetIncludeCFI() const { - // include-debug-symbols implies include-cfi. - return include_cfi_ || include_debug_symbols_; + bool GetGenerateDebugInfo() const { + return generate_debug_info_; } bool GetImplicitNullChecks() const { @@ -212,8 +206,7 @@ class CompilerOptions FINAL { // When using a profile file only the top K% of the profiled samples will be compiled. const double top_k_profile_threshold_; const bool debuggable_; - const bool include_debug_symbols_; - const bool include_cfi_; + const bool generate_debug_info_; const bool implicit_null_checks_; const bool implicit_so_checks_; const bool implicit_suspend_checks_; diff --git a/compiler/dwarf/dwarf_constants.h b/compiler/dwarf/dwarf_constants.h index 61a44cd..3b570e5 100644 --- a/compiler/dwarf/dwarf_constants.h +++ b/compiler/dwarf/dwarf_constants.h @@ -680,6 +680,14 @@ enum ExceptionHeaderValueApplication : uint8_t { DW_EH_PE_aligned = 0x50, }; +enum CFIFormat : uint8_t { + // This is the original format as defined by the specification. + // It is used for the .debug_frame section. + DW_DEBUG_FRAME_FORMAT, + // Slightly modified format used for the .eh_frame section. + DW_EH_FRAME_FORMAT +}; + } // namespace dwarf } // namespace art diff --git a/compiler/dwarf/dwarf_test.cc b/compiler/dwarf/dwarf_test.cc index edba00a..4d423d0 100644 --- a/compiler/dwarf/dwarf_test.cc +++ b/compiler/dwarf/dwarf_test.cc @@ -29,6 +29,8 @@ namespace dwarf { // Run the tests only on host since we need objdump. #ifndef HAVE_ANDROID_OS +constexpr CFIFormat kCFIFormat = DW_DEBUG_FRAME_FORMAT; + TEST_F(DwarfTest, DebugFrame) { const bool is64bit = false; @@ -120,30 +122,30 @@ TEST_F(DwarfTest, DebugFrame) { DW_CHECK_NEXT("DW_CFA_restore: r5 (ebp)"); DebugFrameOpCodeWriter<> initial_opcodes; - WriteEhFrameCIE(is64bit, DW_EH_PE_absptr, Reg(is64bit ? 16 : 8), - initial_opcodes, &eh_frame_data_); - std::vector<uintptr_t> eh_frame_patches; + WriteDebugFrameCIE(is64bit, DW_EH_PE_absptr, Reg(is64bit ? 16 : 8), + initial_opcodes, kCFIFormat, &debug_frame_data_); + std::vector<uintptr_t> debug_frame_patches; std::vector<uintptr_t> expected_patches { 28 }; // NOLINT - WriteEhFrameFDE(is64bit, 0, 0x01000000, 0x01000000, opcodes.data(), - &eh_frame_data_, &eh_frame_patches); + WriteDebugFrameFDE(is64bit, 0, 0x01000000, 0x01000000, opcodes.data(), + kCFIFormat, &debug_frame_data_, &debug_frame_patches); - EXPECT_EQ(expected_patches, eh_frame_patches); + EXPECT_EQ(expected_patches, debug_frame_patches); CheckObjdumpOutput(is64bit, "-W"); } TEST_F(DwarfTest, DebugFrame64) { constexpr bool is64bit = true; DebugFrameOpCodeWriter<> initial_opcodes; - WriteEhFrameCIE(is64bit, DW_EH_PE_absptr, Reg(16), - initial_opcodes, &eh_frame_data_); + WriteDebugFrameCIE(is64bit, DW_EH_PE_absptr, Reg(16), + initial_opcodes, kCFIFormat, &debug_frame_data_); DebugFrameOpCodeWriter<> opcodes; - std::vector<uintptr_t> eh_frame_patches; + std::vector<uintptr_t> debug_frame_patches; std::vector<uintptr_t> expected_patches { 32 }; // NOLINT - WriteEhFrameFDE(is64bit, 0, 0x0100000000000000, 0x0200000000000000, - opcodes.data(), &eh_frame_data_, &eh_frame_patches); + WriteDebugFrameFDE(is64bit, 0, 0x0100000000000000, 0x0200000000000000, + opcodes.data(), kCFIFormat, &debug_frame_data_, &debug_frame_patches); DW_CHECK("FDE cie=00000000 pc=100000000000000..300000000000000"); - EXPECT_EQ(expected_patches, eh_frame_patches); + EXPECT_EQ(expected_patches, debug_frame_patches); CheckObjdumpOutput(is64bit, "-W"); } @@ -173,11 +175,11 @@ TEST_F(DwarfTest, x86_64_RegisterMapping) { DW_CHECK_NEXT("DW_CFA_offset: r14 (r14)"); DW_CHECK_NEXT("DW_CFA_offset: r15 (r15)"); DebugFrameOpCodeWriter<> initial_opcodes; - WriteEhFrameCIE(is64bit, DW_EH_PE_absptr, Reg(16), - initial_opcodes, &eh_frame_data_); - std::vector<uintptr_t> eh_frame_patches; - WriteEhFrameFDE(is64bit, 0, 0x0100000000000000, 0x0200000000000000, - opcodes.data(), &eh_frame_data_, &eh_frame_patches); + WriteDebugFrameCIE(is64bit, DW_EH_PE_absptr, Reg(16), + initial_opcodes, kCFIFormat, &debug_frame_data_); + std::vector<uintptr_t> debug_frame_patches; + WriteDebugFrameFDE(is64bit, 0, 0x0100000000000000, 0x0200000000000000, + opcodes.data(), kCFIFormat, &debug_frame_data_, &debug_frame_patches); CheckObjdumpOutput(is64bit, "-W"); } diff --git a/compiler/dwarf/dwarf_test.h b/compiler/dwarf/dwarf_test.h index 370c744..f819c49 100644 --- a/compiler/dwarf/dwarf_test.h +++ b/compiler/dwarf/dwarf_test.h @@ -68,7 +68,7 @@ class DwarfTest : public CommonRuntimeTest { RawSection debug_abbrev(".debug_abbrev", SHT_PROGBITS, 0, nullptr, 0, 1, 0); RawSection debug_str(".debug_str", SHT_PROGBITS, 0, nullptr, 0, 1, 0); RawSection debug_line(".debug_line", SHT_PROGBITS, 0, nullptr, 0, 1, 0); - RawSection eh_frame(".eh_frame", SHT_PROGBITS, SHF_ALLOC, nullptr, 0, kPageSize, 0); + RawSection debug_frame(".debug_frame", SHT_PROGBITS, 0, nullptr, 0, 8, 0); if (!debug_info_data_.empty()) { debug_info.SetBuffer(debug_info_data_); builder.RegisterSection(&debug_info); @@ -85,9 +85,9 @@ class DwarfTest : public CommonRuntimeTest { debug_line.SetBuffer(debug_line_data_); builder.RegisterSection(&debug_line); } - if (!eh_frame_data_.empty()) { - eh_frame.SetBuffer(eh_frame_data_); - builder.RegisterSection(&eh_frame); + if (!debug_frame_data_.empty()) { + debug_frame.SetBuffer(debug_frame_data_); + builder.RegisterSection(&debug_frame); } ScratchFile file; builder.Write(file.GetFile()); @@ -166,7 +166,7 @@ class DwarfTest : public CommonRuntimeTest { } // Buffers which are going to assembled into ELF file and passed to objdump. - std::vector<uint8_t> eh_frame_data_; + std::vector<uint8_t> debug_frame_data_; std::vector<uint8_t> debug_info_data_; std::vector<uint8_t> debug_abbrev_data_; std::vector<uint8_t> debug_str_data_; diff --git a/compiler/dwarf/headers.h b/compiler/dwarf/headers.h index 9f64766..ad315ee 100644 --- a/compiler/dwarf/headers.h +++ b/compiler/dwarf/headers.h @@ -35,17 +35,18 @@ namespace dwarf { // 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. +// Write common information entry (CIE) to .debug_frame or .eh_frame section. template<typename Allocator> -void WriteEhFrameCIE(bool is64bit, - ExceptionHeaderValueApplication address_type, - Reg return_address_register, - const DebugFrameOpCodeWriter<Allocator>& opcodes, - std::vector<uint8_t>* eh_frame) { - Writer<> writer(eh_frame); +void WriteDebugFrameCIE(bool is64bit, + ExceptionHeaderValueApplication address_type, + Reg return_address_register, + const DebugFrameOpCodeWriter<Allocator>& opcodes, + CFIFormat format, + std::vector<uint8_t>* debug_frame) { + Writer<> writer(debug_frame); size_t cie_header_start_ = writer.data()->size(); writer.PushUint32(0); // Length placeholder. - writer.PushUint32(0); // CIE id. + writer.PushUint32((format == DW_EH_FRAME_FORMAT) ? 0 : 0xFFFFFFFF); // CIE id. writer.PushUint8(1); // Version. writer.PushString("zR"); writer.PushUleb128(DebugFrameOpCodeWriter<Allocator>::kCodeAlignmentFactor); @@ -62,20 +63,26 @@ void WriteEhFrameCIE(bool is64bit, writer.UpdateUint32(cie_header_start_, writer.data()->size() - cie_header_start_ - 4); } -// Write frame description entry (FDE) to .eh_frame section. +// Write frame description entry (FDE) to .debug_frame or .eh_frame section. 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<uintptr_t>* eh_frame_patches) { - Writer<> writer(eh_frame); +void WriteDebugFrameFDE(bool is64bit, size_t cie_offset, + uint64_t initial_address, uint64_t address_range, + const std::vector<uint8_t, Allocator>* opcodes, + CFIFormat format, + std::vector<uint8_t>* debug_frame, + std::vector<uintptr_t>* debug_frame_patches) { + Writer<> writer(debug_frame); size_t fde_header_start = writer.data()->size(); writer.PushUint32(0); // Length placeholder. - uint32_t cie_pointer = writer.data()->size() - cie_offset; - writer.PushUint32(cie_pointer); + if (format == DW_EH_FRAME_FORMAT) { + uint32_t cie_pointer = writer.data()->size() - cie_offset; + writer.PushUint32(cie_pointer); + } else { + uint32_t cie_pointer = cie_offset; + writer.PushUint32(cie_pointer); + } // Relocate initial_address, but not address_range (it is size). - eh_frame_patches->push_back(writer.data()->size()); + debug_frame_patches->push_back(writer.data()->size()); if (is64bit) { writer.PushUint64(initial_address); writer.PushUint64(address_range); diff --git a/compiler/elf_builder.h b/compiler/elf_builder.h index 2c68bb8..bbd962f 100644 --- a/compiler/elf_builder.h +++ b/compiler/elf_builder.h @@ -166,6 +166,10 @@ class ElfBuilder FINAL { patched_(false), patch_(patch), patch_base_section_(patch_base_section) { } + RawSection(const std::string& name, Elf_Word type) + : RawSection(name, type, 0, nullptr, 0, 1, 0, nullptr, nullptr) { + } + Elf_Word GetSize() const OVERRIDE { return buffer_.size(); } @@ -263,7 +267,7 @@ class ElfBuilder FINAL { class StrtabSection FINAL : public Section { public: StrtabSection(const std::string& name, Elf_Word flags) - : Section(name, SHT_STRTAB, flags, nullptr, 0, 1, 1) { + : Section(name, SHT_STRTAB, flags, nullptr, 0, 1, 0) { buffer_.reserve(4 * KB); // The first entry of strtab must be empty string. buffer_ += '\0'; @@ -306,7 +310,7 @@ class ElfBuilder FINAL { SymtabSection(const std::string& name, Elf_Word type, Elf_Word flags, StrtabSection* strtab) - : Section(name, type, flags, strtab, 0, sizeof(Elf_Word), sizeof(Elf_Sym)), + : Section(name, type, flags, strtab, 0, sizeof(Elf_Off), sizeof(Elf_Sym)), strtab_(strtab) { } @@ -499,7 +503,7 @@ class ElfBuilder FINAL { text_(".text", SHT_PROGBITS, SHF_ALLOC | SHF_EXECINSTR, nullptr, 0, kPageSize, 0, text_size, text_writer), bss_(".bss", bss_size), - dynamic_(".dynamic", &dynsym_), + dynamic_(".dynamic", &dynstr_), strtab_(".strtab", 0), symtab_(".symtab", SHT_SYMTAB, 0, &strtab_), shstrtab_(".shstrtab", 0) { @@ -641,11 +645,10 @@ class ElfBuilder FINAL { // It is easiest to just reserve a fixed amount of space for them. constexpr size_t kMaxProgramHeaders = 8; constexpr size_t kProgramHeadersOffset = sizeof(Elf_Ehdr); - constexpr size_t kProgramHeadersSize = sizeof(Elf_Phdr) * kMaxProgramHeaders; // Layout of all sections - determine the final file offsets and addresses. // This must be done after we have built all sections and know their size. - Elf_Off file_offset = kProgramHeadersOffset + kProgramHeadersSize; + Elf_Off file_offset = kProgramHeadersOffset + sizeof(Elf_Phdr) * kMaxProgramHeaders; Elf_Addr load_address = file_offset; std::vector<Elf_Shdr> section_headers; section_headers.reserve(1u + sections.size()); @@ -674,7 +677,7 @@ class ElfBuilder FINAL { // Collect section headers into continuous array for convenience. section_headers.push_back(*header); } - Elf_Off section_headers_offset = RoundUp(file_offset, sizeof(Elf_Word)); + Elf_Off section_headers_offset = RoundUp(file_offset, sizeof(Elf_Off)); // Create program headers now that we know the layout of the whole file. // Each segment contains one or more sections which are mapped together. @@ -682,8 +685,7 @@ class ElfBuilder FINAL { // PT_LOAD does the mapping. Other PT_* types allow the program to locate // interesting parts of memory and their addresses overlap with PT_LOAD. std::vector<Elf_Phdr> program_headers; - program_headers.push_back(MakeProgramHeader(PT_PHDR, PF_R, - kProgramHeadersOffset, kProgramHeadersSize, sizeof(Elf_Word))); + program_headers.push_back(Elf_Phdr()); // Placeholder for PT_PHDR. // Create the main LOAD R segment which spans all sections up to .rodata. const Elf_Shdr* rodata = rodata_.GetHeader(); program_headers.push_back(MakeProgramHeader(PT_LOAD, PF_R, @@ -709,6 +711,9 @@ class ElfBuilder FINAL { program_headers.push_back(MakeProgramHeader(PT_GNU_EH_FRAME, PF_R, *eh_frame_hdr)); } } + DCHECK_EQ(program_headers[0].p_type, 0u); // Check placeholder. + program_headers[0] = MakeProgramHeader(PT_PHDR, PF_R, + kProgramHeadersOffset, program_headers.size() * sizeof(Elf_Phdr), sizeof(Elf_Off)); CHECK_LE(program_headers.size(), kMaxProgramHeaders); // Create the main ELF header. @@ -777,10 +782,12 @@ class ElfBuilder FINAL { template<typename T> static bool WriteArray(File* elf_file, const T* data, size_t count) { - DCHECK(data != nullptr); - if (!elf_file->WriteFully(data, count * sizeof(T))) { - PLOG(ERROR) << "Failed to write to file " << elf_file->GetPath(); - return false; + if (count != 0) { + DCHECK(data != nullptr); + if (!elf_file->WriteFully(data, count * sizeof(T))) { + PLOG(ERROR) << "Failed to write to file " << elf_file->GetPath(); + return false; + } } return true; } diff --git a/compiler/elf_writer_debug.cc b/compiler/elf_writer_debug.cc index dbbe82e..c68bbc0 100644 --- a/compiler/elf_writer_debug.cc +++ b/compiler/elf_writer_debug.cc @@ -30,9 +30,10 @@ namespace art { namespace dwarf { -static void WriteEhFrameCIE(InstructionSet isa, - ExceptionHeaderValueApplication addr_type, - std::vector<uint8_t>* eh_frame) { +static void WriteDebugFrameCIE(InstructionSet isa, + ExceptionHeaderValueApplication addr_type, + CFIFormat format, + std::vector<uint8_t>* eh_frame) { // Scratch registers should be marked as undefined. This tells the // debugger that its value in the previous frame is not recoverable. bool is64bit = Is64BitInstructionSet(isa); @@ -58,7 +59,8 @@ static void WriteEhFrameCIE(InstructionSet isa, } } auto return_reg = Reg::ArmCore(14); // R14(LR). - WriteEhFrameCIE(is64bit, addr_type, return_reg, opcodes, eh_frame); + WriteDebugFrameCIE(is64bit, addr_type, return_reg, + opcodes, format, eh_frame); return; } case kArm64: { @@ -81,7 +83,8 @@ static void WriteEhFrameCIE(InstructionSet isa, } } auto return_reg = Reg::Arm64Core(30); // R30(LR). - WriteEhFrameCIE(is64bit, addr_type, return_reg, opcodes, eh_frame); + WriteDebugFrameCIE(is64bit, addr_type, return_reg, + opcodes, format, eh_frame); return; } case kMips: @@ -97,7 +100,8 @@ static void WriteEhFrameCIE(InstructionSet isa, } } auto return_reg = Reg::MipsCore(31); // R31(RA). - WriteEhFrameCIE(is64bit, addr_type, return_reg, opcodes, eh_frame); + WriteDebugFrameCIE(is64bit, addr_type, return_reg, + opcodes, format, eh_frame); return; } case kX86: { @@ -123,7 +127,8 @@ static void WriteEhFrameCIE(InstructionSet isa, } } auto return_reg = Reg::X86Core(8); // R8(EIP). - WriteEhFrameCIE(is64bit, addr_type, return_reg, opcodes, eh_frame); + WriteDebugFrameCIE(is64bit, addr_type, return_reg, + opcodes, format, eh_frame); return; } case kX86_64: { @@ -149,7 +154,8 @@ static void WriteEhFrameCIE(InstructionSet isa, } } auto return_reg = Reg::X86_64Core(16); // R16(RIP). - WriteEhFrameCIE(is64bit, addr_type, return_reg, opcodes, eh_frame); + WriteDebugFrameCIE(is64bit, addr_type, return_reg, + opcodes, format, eh_frame); return; } case kNone: @@ -159,58 +165,61 @@ static void WriteEhFrameCIE(InstructionSet isa, UNREACHABLE(); } -void WriteEhFrame(const CompilerDriver* compiler, - const OatWriter* oat_writer, - ExceptionHeaderValueApplication address_type, - std::vector<uint8_t>* eh_frame, - std::vector<uintptr_t>* eh_frame_patches, - std::vector<uint8_t>* eh_frame_hdr, - std::vector<uintptr_t>* eh_frame_hdr_patches) { +void WriteCFISection(const CompilerDriver* compiler, + const OatWriter* oat_writer, + ExceptionHeaderValueApplication address_type, + CFIFormat format, + std::vector<uint8_t>* debug_frame, + std::vector<uintptr_t>* debug_frame_patches, + std::vector<uint8_t>* eh_frame_hdr, + std::vector<uintptr_t>* eh_frame_hdr_patches) { const auto& method_infos = oat_writer->GetMethodDebugInfo(); const InstructionSet isa = compiler->GetInstructionSet(); - // Write .eh_frame section. + // Write .eh_frame/.debug_frame section. std::map<uint32_t, size_t> address_to_fde_offset_map; - size_t cie_offset = eh_frame->size(); - WriteEhFrameCIE(isa, address_type, eh_frame); + size_t cie_offset = debug_frame->size(); + WriteDebugFrameCIE(isa, address_type, format, debug_frame); for (const OatWriter::DebugInfo& mi : method_infos) { if (!mi.deduped_) { // Only one FDE per unique address. const SwapVector<uint8_t>* opcodes = mi.compiled_method_->GetCFIInfo(); if (opcodes != nullptr) { - address_to_fde_offset_map.emplace(mi.low_pc_, eh_frame->size()); - WriteEhFrameFDE(Is64BitInstructionSet(isa), cie_offset, - mi.low_pc_, mi.high_pc_ - mi.low_pc_, - opcodes, eh_frame, eh_frame_patches); + address_to_fde_offset_map.emplace(mi.low_pc_, debug_frame->size()); + WriteDebugFrameFDE(Is64BitInstructionSet(isa), cie_offset, + mi.low_pc_, mi.high_pc_ - mi.low_pc_, + opcodes, format, debug_frame, debug_frame_patches); } } } - // Write .eh_frame_hdr section. - Writer<> header(eh_frame_hdr); - header.PushUint8(1); // Version. - // Encoding of .eh_frame pointer - libunwind does not honor datarel here, - // so we have to use pcrel which means relative to the pointer's location. - header.PushUint8(DW_EH_PE_pcrel | DW_EH_PE_sdata4); - // Encoding of binary search table size. - header.PushUint8(DW_EH_PE_udata4); - // Encoding of binary search table addresses - libunwind supports only this - // specific combination, which means relative to the start of .eh_frame_hdr. - header.PushUint8(DW_EH_PE_datarel | DW_EH_PE_sdata4); - // .eh_frame pointer - .eh_frame_hdr section is after .eh_frame section - const int32_t relative_eh_frame_begin = -static_cast<int32_t>(eh_frame->size()); - header.PushInt32(relative_eh_frame_begin - 4U); - // Binary search table size (number of entries). - header.PushUint32(dchecked_integral_cast<uint32_t>(address_to_fde_offset_map.size())); - // Binary search table. - for (const auto& address_to_fde_offset : address_to_fde_offset_map) { - u_int32_t code_address = address_to_fde_offset.first; - int32_t fde_address = dchecked_integral_cast<int32_t>(address_to_fde_offset.second); - eh_frame_hdr_patches->push_back(header.data()->size()); - header.PushUint32(code_address); - // We know the exact layout (eh_frame is immediately before eh_frame_hdr) - // and the data is relative to the start of the eh_frame_hdr, - // so patching isn't necessary (in contrast to the code address above). - header.PushInt32(relative_eh_frame_begin + fde_address); + if (format == DW_EH_FRAME_FORMAT) { + // Write .eh_frame_hdr section. + Writer<> header(eh_frame_hdr); + header.PushUint8(1); // Version. + // Encoding of .eh_frame pointer - libunwind does not honor datarel here, + // so we have to use pcrel which means relative to the pointer's location. + header.PushUint8(DW_EH_PE_pcrel | DW_EH_PE_sdata4); + // Encoding of binary search table size. + header.PushUint8(DW_EH_PE_udata4); + // Encoding of binary search table addresses - libunwind supports only this + // specific combination, which means relative to the start of .eh_frame_hdr. + header.PushUint8(DW_EH_PE_datarel | DW_EH_PE_sdata4); + // .eh_frame pointer - .eh_frame_hdr section is after .eh_frame section + const int32_t relative_eh_frame_begin = -static_cast<int32_t>(debug_frame->size()); + header.PushInt32(relative_eh_frame_begin - 4U); + // Binary search table size (number of entries). + header.PushUint32(dchecked_integral_cast<uint32_t>(address_to_fde_offset_map.size())); + // Binary search table. + for (const auto& address_to_fde_offset : address_to_fde_offset_map) { + u_int32_t code_address = address_to_fde_offset.first; + int32_t fde_address = dchecked_integral_cast<int32_t>(address_to_fde_offset.second); + eh_frame_hdr_patches->push_back(header.data()->size()); + header.PushUint32(code_address); + // We know the exact layout (eh_frame is immediately before eh_frame_hdr) + // and the data is relative to the start of the eh_frame_hdr, + // so patching isn't necessary (in contrast to the code address above). + header.PushInt32(relative_eh_frame_begin + fde_address); + } } } @@ -235,6 +244,7 @@ void WriteDebugSections(const CompilerDriver* compiler, std::vector<uintptr_t>* debug_line_patches) { const std::vector<OatWriter::DebugInfo>& method_infos = oat_writer->GetMethodDebugInfo(); const InstructionSet isa = compiler->GetInstructionSet(); + const bool is64bit = Is64BitInstructionSet(isa); // Find all addresses (low_pc) which contain deduped methods. // The first instance of method is not marked deduped_, but the rest is. @@ -272,7 +282,7 @@ void WriteDebugSections(const CompilerDriver* compiler, } size_t debug_abbrev_offset = debug_abbrev->size(); - DebugInfoEntryWriter<> info(false /* 32 bit */, debug_abbrev); + DebugInfoEntryWriter<> info(is64bit, debug_abbrev); info.StartTag(DW_TAG_compile_unit, DW_CHILDREN_yes); info.WriteStrp(DW_AT_producer, "Android dex2oat", debug_str); info.WriteData1(DW_AT_language, DW_LANG_Java); @@ -317,7 +327,7 @@ void WriteDebugSections(const CompilerDriver* compiler, case kX86_64: break; } - DebugLineOpCodeWriter<> opcodes(false /* 32bit */, code_factor_bits_); + DebugLineOpCodeWriter<> opcodes(is64bit, code_factor_bits_); opcodes.SetAddress(cunit_low_pc); if (dwarf_isa != -1) { opcodes.SetISA(dwarf_isa); diff --git a/compiler/elf_writer_debug.h b/compiler/elf_writer_debug.h index 28d0e2c..69f7e0d 100644 --- a/compiler/elf_writer_debug.h +++ b/compiler/elf_writer_debug.h @@ -25,13 +25,14 @@ namespace art { namespace dwarf { -void WriteEhFrame(const CompilerDriver* compiler, - const OatWriter* oat_writer, - ExceptionHeaderValueApplication address_type, - std::vector<uint8_t>* eh_frame, - std::vector<uintptr_t>* eh_frame_patches, - std::vector<uint8_t>* eh_frame_hdr, - std::vector<uintptr_t>* eh_frame_hdr_patches); +void WriteCFISection(const CompilerDriver* compiler, + const OatWriter* oat_writer, + ExceptionHeaderValueApplication address_type, + CFIFormat format, + std::vector<uint8_t>* debug_frame, + std::vector<uintptr_t>* debug_frame_patches, + std::vector<uint8_t>* eh_frame_hdr, + std::vector<uintptr_t>* eh_frame_hdr_patches); void WriteDebugSections(const CompilerDriver* compiler, const OatWriter* oat_writer, diff --git a/compiler/elf_writer_quick.cc b/compiler/elf_writer_quick.cc index 79f9955..ddee3ba 100644 --- a/compiler/elf_writer_quick.cc +++ b/compiler/elf_writer_quick.cc @@ -19,6 +19,7 @@ #include <unordered_map> #include <unordered_set> +#include "base/casts.h" #include "base/logging.h" #include "base/unix_file/fd_file.h" #include "compiled_method.h" @@ -37,6 +38,23 @@ namespace art { +// .eh_frame and .debug_frame are almost identical. +// Except for some minor formatting differences, the main difference +// is that .eh_frame is allocated within the running program because +// it is used by C++ exception handling (which we do not use so we +// can choose either). C++ compilers generally tend to use .eh_frame +// because if they need it sometimes, they might as well always use it. +constexpr dwarf::CFIFormat kCFIFormat = dwarf::DW_EH_FRAME_FORMAT; + +// The ARM specification defines three special mapping symbols +// $a, $t and $d which mark ARM, Thumb and data ranges respectively. +// These symbols can be used by tools, for example, to pretty +// print instructions correctly. Objdump will use them if they +// exist, but it will still work well without them. +// However, these extra symbols take space, so let's just generate +// one symbol which marks the whole .text section as code. +constexpr bool kGenerateSingleArmMappingSymbol = true; + template <typename ElfTypes> bool ElfWriterQuick<ElfTypes>::Create(File* elf_file, OatWriter* oat_writer, @@ -51,36 +69,17 @@ bool ElfWriterQuick<ElfTypes>::Create(File* elf_file, template <typename ElfTypes> static void WriteDebugSymbols(ElfBuilder<ElfTypes>* builder, OatWriter* oat_writer); -// Encode patch locations in .oat_patches format. +// Encode patch locations as LEB128 list of deltas between consecutive addresses. template <typename ElfTypes> -void ElfWriterQuick<ElfTypes>::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); +void ElfWriterQuick<ElfTypes>::EncodeOatPatches(const std::vector<uintptr_t>& locations, + std::vector<uint8_t>* buffer) { + buffer->reserve(buffer->size() + locations.size() * 2); // guess 2 bytes per ULEB128. + uintptr_t address = 0; // relative to start of section. + for (uintptr_t location : locations) { + DCHECK_GE(location, address) << "Patch locations are not in sorted order"; + EncodeUnsignedLeb128(buffer, dchecked_integral_cast<uint32_t>(location - address)); + address = location; } - buffer->push_back(0); // End of sections. } class RodataWriter FINAL : public CodeOutput { @@ -156,61 +155,95 @@ bool ElfWriterQuick<ElfTypes>::Write( isa, rodata_size, &rodata_writer, text_size, &text_writer, bss_size)); // Add debug sections. - // They are stack allocated here (in the same scope as the builder), - // but they are registred with the builder only if they are used. + // They are allocated here (in the same scope as the builder), + // but they are registered with the builder only if they are used. using RawSection = typename ElfBuilder<ElfTypes>::RawSection; const auto* text = builder->GetText(); const bool is64bit = Is64BitInstructionSet(isa); - RawSection eh_frame(".eh_frame", SHT_PROGBITS, SHF_ALLOC, nullptr, 0, kPageSize, 0, - is64bit ? Patch<Elf_Addr, uint64_t, kPointerRelativeAddress> : - Patch<Elf_Addr, uint32_t, kPointerRelativeAddress>, - text); - RawSection eh_frame_hdr(".eh_frame_hdr", SHT_PROGBITS, SHF_ALLOC, nullptr, 0, 4, 0, - Patch<Elf_Addr, uint32_t, kSectionRelativeAddress>, text); - RawSection debug_info(".debug_info", SHT_PROGBITS, 0, nullptr, 0, 1, 0, - Patch<Elf_Addr, uint32_t, kAbsoluteAddress>, text); - RawSection debug_abbrev(".debug_abbrev", SHT_PROGBITS, 0, nullptr, 0, 1, 0); - RawSection debug_str(".debug_str", SHT_PROGBITS, 0, nullptr, 0, 1, 0); - RawSection debug_line(".debug_line", SHT_PROGBITS, 0, nullptr, 0, 1, 0, - Patch<Elf_Addr, uint32_t, kAbsoluteAddress>, text); + const int pointer_size = GetInstructionSetPointerSize(isa); + std::unique_ptr<RawSection> eh_frame(new RawSection( + ".eh_frame", SHT_PROGBITS, SHF_ALLOC, nullptr, 0, kPageSize, 0, + is64bit ? Patch<Elf_Addr, uint64_t, kPointerRelativeAddress> : + Patch<Elf_Addr, uint32_t, kPointerRelativeAddress>, + text)); + std::unique_ptr<RawSection> eh_frame_hdr(new RawSection( + ".eh_frame_hdr", SHT_PROGBITS, SHF_ALLOC, nullptr, 0, 4, 0, + Patch<Elf_Addr, uint32_t, kSectionRelativeAddress>, text)); + std::unique_ptr<RawSection> debug_frame(new RawSection( + ".debug_frame", SHT_PROGBITS, 0, nullptr, 0, pointer_size, 0, + is64bit ? Patch<Elf_Addr, uint64_t, kAbsoluteAddress> : + Patch<Elf_Addr, uint32_t, kAbsoluteAddress>, + text)); + std::unique_ptr<RawSection> debug_frame_oat_patches(new RawSection( + ".debug_frame.oat_patches", SHT_OAT_PATCH)); + std::unique_ptr<RawSection> debug_info(new RawSection( + ".debug_info", SHT_PROGBITS, 0, nullptr, 0, 1, 0, + Patch<Elf_Addr, uint32_t, kAbsoluteAddress>, text)); + std::unique_ptr<RawSection> debug_info_oat_patches(new RawSection( + ".debug_info.oat_patches", SHT_OAT_PATCH)); + std::unique_ptr<RawSection> debug_abbrev(new RawSection( + ".debug_abbrev", SHT_PROGBITS)); + std::unique_ptr<RawSection> debug_str(new RawSection( + ".debug_str", SHT_PROGBITS)); + std::unique_ptr<RawSection> debug_line(new RawSection( + ".debug_line", SHT_PROGBITS, 0, nullptr, 0, 1, 0, + Patch<Elf_Addr, uint32_t, kAbsoluteAddress>, text)); + std::unique_ptr<RawSection> debug_line_oat_patches(new RawSection( + ".debug_line.oat_patches", SHT_OAT_PATCH)); if (!oat_writer->GetMethodDebugInfo().empty()) { - if (compiler_driver_->GetCompilerOptions().GetIncludeCFI()) { - dwarf::WriteEhFrame( - compiler_driver_, oat_writer, dwarf::DW_EH_PE_pcrel, - eh_frame.GetBuffer(), eh_frame.GetPatchLocations(), - eh_frame_hdr.GetBuffer(), eh_frame_hdr.GetPatchLocations()); - builder->RegisterSection(&eh_frame); - builder->RegisterSection(&eh_frame_hdr); - } - if (compiler_driver_->GetCompilerOptions().GetIncludeDebugSymbols()) { + if (compiler_driver_->GetCompilerOptions().GetGenerateDebugInfo()) { + // Generate CFI (stack unwinding information). + if (kCFIFormat == dwarf::DW_EH_FRAME_FORMAT) { + dwarf::WriteCFISection( + compiler_driver_, oat_writer, + dwarf::DW_EH_PE_pcrel, kCFIFormat, + eh_frame->GetBuffer(), eh_frame->GetPatchLocations(), + eh_frame_hdr->GetBuffer(), eh_frame_hdr->GetPatchLocations()); + builder->RegisterSection(eh_frame.get()); + builder->RegisterSection(eh_frame_hdr.get()); + } else { + DCHECK(kCFIFormat == dwarf::DW_DEBUG_FRAME_FORMAT); + dwarf::WriteCFISection( + compiler_driver_, oat_writer, + dwarf::DW_EH_PE_absptr, kCFIFormat, + debug_frame->GetBuffer(), debug_frame->GetPatchLocations(), + nullptr, nullptr); + builder->RegisterSection(debug_frame.get()); + EncodeOatPatches(*debug_frame->GetPatchLocations(), + debug_frame_oat_patches->GetBuffer()); + builder->RegisterSection(debug_frame_oat_patches.get()); + } // Add methods to .symtab. WriteDebugSymbols(builder.get(), oat_writer); // Generate DWARF .debug_* sections. dwarf::WriteDebugSections( compiler_driver_, oat_writer, - debug_info.GetBuffer(), debug_info.GetPatchLocations(), - debug_abbrev.GetBuffer(), - debug_str.GetBuffer(), - debug_line.GetBuffer(), debug_line.GetPatchLocations()); - builder->RegisterSection(&debug_info); - builder->RegisterSection(&debug_abbrev); - builder->RegisterSection(&debug_str); - builder->RegisterSection(&debug_line); - *oat_writer->GetAbsolutePatchLocationsFor(".debug_info") = - *debug_info.GetPatchLocations(); - *oat_writer->GetAbsolutePatchLocationsFor(".debug_line") = - *debug_line.GetPatchLocations(); + debug_info->GetBuffer(), debug_info->GetPatchLocations(), + debug_abbrev->GetBuffer(), + debug_str->GetBuffer(), + debug_line->GetBuffer(), debug_line->GetPatchLocations()); + builder->RegisterSection(debug_info.get()); + EncodeOatPatches(*debug_info->GetPatchLocations(), + debug_info_oat_patches->GetBuffer()); + builder->RegisterSection(debug_info_oat_patches.get()); + builder->RegisterSection(debug_abbrev.get()); + builder->RegisterSection(debug_str.get()); + builder->RegisterSection(debug_line.get()); + EncodeOatPatches(*debug_line->GetPatchLocations(), + debug_line_oat_patches->GetBuffer()); + builder->RegisterSection(debug_line_oat_patches.get()); } } - // Add relocation section. - RawSection oat_patches(".oat_patches", SHT_OAT_PATCH, 0, nullptr, 0, 1, 0); - 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()) { - EncodeOatPatches(oat_writer->GetAbsolutePatchLocations(), oat_patches.GetBuffer()); - builder->RegisterSection(&oat_patches); + // Add relocation section for .text. + std::unique_ptr<RawSection> text_oat_patches(new RawSection( + ".text.oat_patches", SHT_OAT_PATCH)); + if (compiler_driver_->GetCompilerOptions().GetIncludePatchInformation()) { + // Note that ElfWriter::Fixup will be called regardless and therefore + // we need to include oat_patches for debug sections unconditionally. + EncodeOatPatches(oat_writer->GetAbsolutePatchLocations(), + text_oat_patches->GetBuffer()); + builder->RegisterSection(text_oat_patches.get()); } return builder->Write(elf_file_); @@ -219,6 +252,7 @@ bool ElfWriterQuick<ElfTypes>::Write( template <typename ElfTypes> static void WriteDebugSymbols(ElfBuilder<ElfTypes>* builder, OatWriter* oat_writer) { const std::vector<OatWriter::DebugInfo>& method_info = oat_writer->GetMethodDebugInfo(); + bool generated_mapping_symbol = false; // Find all addresses (low_pc) which contain deduped methods. // The first instance of method is not marked deduped_, but the rest is. @@ -247,9 +281,14 @@ static void WriteDebugSymbols(ElfBuilder<ElfTypes>* builder, OatWriter* oat_writ // Conforming to aaelf, add $t mapping symbol to indicate start of a sequence of thumb2 // instructions, so that disassembler tools can correctly disassemble. + // Note that even if we generate just a single mapping symbol, ARM's Streamline + // requires it to match function symbol. Just address 0 does not work. if (it->compiled_method_->GetInstructionSet() == kThumb2) { - symtab->AddSymbol("$t", builder->GetText(), it->low_pc_ & ~1, true, - 0, STB_LOCAL, STT_NOTYPE); + if (!generated_mapping_symbol || !kGenerateSingleArmMappingSymbol) { + symtab->AddSymbol("$t", builder->GetText(), it->low_pc_ & ~1, true, + 0, STB_LOCAL, STT_NOTYPE); + generated_mapping_symbol = true; + } } } } diff --git a/compiler/elf_writer_quick.h b/compiler/elf_writer_quick.h index 955b568..fd202ee 100644 --- a/compiler/elf_writer_quick.h +++ b/compiler/elf_writer_quick.h @@ -35,7 +35,7 @@ class ElfWriterQuick FINAL : public ElfWriter { const CompilerDriver& driver) SHARED_LOCKS_REQUIRED(Locks::mutator_lock_); - static void EncodeOatPatches(const OatWriter::PatchLocationsMap& sections, + static void EncodeOatPatches(const std::vector<uintptr_t>& locations, std::vector<uint8_t>* buffer); protected: diff --git a/compiler/elf_writer_test.cc b/compiler/elf_writer_test.cc index 08523d8..ccf34b8 100644 --- a/compiler/elf_writer_test.cc +++ b/compiler/elf_writer_test.cc @@ -88,73 +88,41 @@ 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; + const std::vector<std::vector<uintptr_t>> test_data { + { 0, 4, 8, 15, 128, 200 }, + { 8, 8 + 127 }, + { 8, 8 + 128 }, + { }, + }; + for (const auto& patch_locations : test_data) { + constexpr int32_t delta = 0x11235813; + + // Encode patch locations. + std::vector<uint8_t> oat_patches; + ElfWriterQuick32::EncodeOatPatches(patch_locations, &oat_patches); + + // Create buffer to be patched. + std::vector<uint8_t> initial_data(256); + for (size_t i = 0; i < initial_data.size(); i++) { + initial_data[i] = i; + } + + // Patch manually. + std::vector<uint8_t> expected = initial_data; + for (uintptr_t location : patch_locations) { + typedef __attribute__((__aligned__(1))) uint32_t UnalignedAddress; + *reinterpret_cast<UnalignedAddress*>(expected.data() + location) += delta; + } + + // Decode and apply patch locations. + std::vector<uint8_t> actual = initial_data; + ElfFileImpl32::ApplyOatPatches( + oat_patches.data(), oat_patches.data() + oat_patches.size(), delta, + actual.data(), actual.data() + actual.size()); + + EXPECT_EQ(expected, actual); } - 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/jit/jit_compiler.cc b/compiler/jit/jit_compiler.cc index ce277cd..a1d8226 100644 --- a/compiler/jit/jit_compiler.cc +++ b/compiler/jit/jit_compiler.cc @@ -74,8 +74,7 @@ JitCompiler::JitCompiler() : total_time_(0) { false, CompilerOptions::kDefaultTopKProfileThreshold, false, // TODO: Think about debuggability of JIT-compiled code. - false, - false, + CompilerOptions::kDefaultGenerateDebugInfo, false, false, false, diff --git a/compiler/jni/quick/jni_compiler.cc b/compiler/jni/quick/jni_compiler.cc index 0347c5e..4d7d86c 100644 --- a/compiler/jni/quick/jni_compiler.cc +++ b/compiler/jni/quick/jni_compiler.cc @@ -94,7 +94,7 @@ CompiledMethod* ArtJniCompileMethodInternal(CompilerDriver* driver, // Assembler that holds generated instructions std::unique_ptr<Assembler> jni_asm(Assembler::Create(instruction_set)); - jni_asm->cfi().SetEnabled(driver->GetCompilerOptions().GetIncludeCFI()); + jni_asm->cfi().SetEnabled(driver->GetCompilerOptions().GetGenerateDebugInfo()); // Offsets into data structures // TODO: if cross compiling these offsets are for the host not the target diff --git a/compiler/oat_writer.cc b/compiler/oat_writer.cc index 633bf64..a98a304 100644 --- a/compiler/oat_writer.cc +++ b/compiler/oat_writer.cc @@ -351,9 +351,8 @@ class OatWriter::InitCodeMethodVisitor : public OatDexMethodVisitor { public: InitCodeMethodVisitor(OatWriter* writer, size_t offset) : OatDexMethodVisitor(writer, offset), - text_absolute_patch_locations_(writer->GetAbsolutePatchLocationsFor(".text")), debuggable_(writer->GetCompilerDriver()->GetCompilerOptions().GetDebuggable()) { - text_absolute_patch_locations_->reserve( + writer_->absolute_patch_locations_.reserve( writer_->compiler_driver_->GetNonRelativeLinkerPatchCount()); } @@ -444,14 +443,13 @@ 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()) { - text_absolute_patch_locations_->push_back(base_loc + patch.LiteralOffset()); + writer_->absolute_patch_locations_.push_back(base_loc + patch.LiteralOffset()); } } } } - if (writer_->compiler_driver_->GetCompilerOptions().GetIncludeDebugSymbols() || - writer_->compiler_driver_->GetCompilerOptions().GetIncludeCFI()) { + if (writer_->compiler_driver_->GetCompilerOptions().GetGenerateDebugInfo()) { // Record debug information for this function if we are doing that. const uint32_t quick_code_start = quick_code_offset - writer_->oat_header_->GetExecutableOffset() - thumb_offset; @@ -547,9 +545,6 @@ class OatWriter::InitCodeMethodVisitor : public OatDexMethodVisitor { // 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>* const text_absolute_patch_locations_; - // Cache of compiler's --debuggable option. const bool debuggable_; }; diff --git a/compiler/oat_writer.h b/compiler/oat_writer.h index 6f1b4ec..82b9377 100644 --- a/compiler/oat_writer.h +++ b/compiler/oat_writer.h @@ -19,7 +19,6 @@ #include <stdint.h> #include <cstddef> -#include <map> #include <memory> #include "linker/relative_patcher.h" // For linker::RelativePatcherTargetProvider. @@ -82,8 +81,6 @@ 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, @@ -105,19 +102,10 @@ class OatWriter { return bss_size_; } - const PatchLocationsMap& GetAbsolutePatchLocations() const { + const std::vector<uintptr_t>& 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(); - } - bool WriteRodata(OutputStream* out); bool WriteCode(OutputStream* out); @@ -339,9 +327,8 @@ class OatWriter { std::unique_ptr<linker::RelativePatcher> relative_patcher_; - // 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_; + // The locations of absolute patches relative to the start of the executable section. + std::vector<uintptr_t> absolute_patch_locations_; // Map method reference to assigned offset. // Wrap the map in a class implementing linker::RelativePatcherTargetProvider. diff --git a/compiler/optimizing/optimizing_compiler.cc b/compiler/optimizing/optimizing_compiler.cc index c7b2c67..5632434 100644 --- a/compiler/optimizing/optimizing_compiler.cc +++ b/compiler/optimizing/optimizing_compiler.cc @@ -404,7 +404,7 @@ CompiledMethod* OptimizingCompiler::CompileOptimized(HGraph* graph, codegen->CompileOptimized(&allocator); DefaultSrcMap src_mapping_table; - if (compiler_driver->GetCompilerOptions().GetIncludeDebugSymbols()) { + if (compiler_driver->GetCompilerOptions().GetGenerateDebugInfo()) { codegen->BuildSourceMap(&src_mapping_table); } @@ -441,7 +441,7 @@ CompiledMethod* OptimizingCompiler::CompileBaseline( std::vector<uint8_t> mapping_table; codegen->BuildMappingTable(&mapping_table); DefaultSrcMap src_mapping_table; - if (compiler_driver->GetCompilerOptions().GetIncludeDebugSymbols()) { + if (compiler_driver->GetCompilerOptions().GetGenerateDebugInfo()) { codegen->BuildSourceMap(&src_mapping_table); } std::vector<uint8_t> vmap_table; @@ -533,7 +533,7 @@ CompiledMethod* OptimizingCompiler::TryCompile(const DexFile::CodeItem* code_ite return nullptr; } codegen->GetAssembler()->cfi().SetEnabled( - compiler_driver->GetCompilerOptions().GetIncludeCFI()); + compiler_driver->GetCompilerOptions().GetGenerateDebugInfo()); PassInfoPrinter pass_info_printer(graph, method_name.c_str(), |