summaryrefslogtreecommitdiffstats
path: root/compiler
diff options
context:
space:
mode:
authorDavid Srbecky <dsrbecky@google.com>2015-06-19 18:25:56 +0000
committerAndroid (Google) Code Review <android-gerrit@google.com>2015-06-19 18:26:45 +0000
commitdb538d309bc34e025e921a04f10b4ee745bd9f1d (patch)
tree9ff4d516df8d23a62bdb2a573575b31df00c5237 /compiler
parent3e91a44bc9063f7f69b5415e3cf162991f73283f (diff)
parenta26cb57f46fd3f27a930d9d688fe8670c1f24754 (diff)
downloadart-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.h12
-rw-r--r--compiler/dex/quick/codegen_util.cc4
-rw-r--r--compiler/dex/quick/quick_cfi_test.cc3
-rw-r--r--compiler/dex/quick/x86/quick_assemble_x86_test.cc3
-rw-r--r--compiler/driver/compiler_driver.cc4
-rw-r--r--compiler/driver/compiler_options.cc9
-rw-r--r--compiler/driver/compiler_options.h17
-rw-r--r--compiler/dwarf/dwarf_constants.h8
-rw-r--r--compiler/dwarf/dwarf_test.cc36
-rw-r--r--compiler/dwarf/dwarf_test.h10
-rw-r--r--compiler/dwarf/headers.h43
-rw-r--r--compiler/elf_builder.h31
-rw-r--r--compiler/elf_writer_debug.cc110
-rw-r--r--compiler/elf_writer_debug.h15
-rw-r--r--compiler/elf_writer_quick.cc185
-rw-r--r--compiler/elf_writer_quick.h2
-rw-r--r--compiler/elf_writer_test.cc98
-rw-r--r--compiler/jit/jit_compiler.cc3
-rw-r--r--compiler/jni/quick/jni_compiler.cc2
-rw-r--r--compiler/oat_writer.cc11
-rw-r--r--compiler/oat_writer.h19
-rw-r--r--compiler/optimizing/optimizing_compiler.cc6
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, &section0_expected, delta);
- PatchSection(patches1, &section1_expected, delta);
- PatchSection(patches2, &section2_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(),