diff options
author | 2017-09-01 13:35:26 +0100 | |
---|---|---|
committer | 2017-09-18 16:53:30 +0100 | |
commit | 1b404a8b34f6fa80342955cb0a61673503328b51 (patch) | |
tree | df0d83903e77c55dcb476a19961ea9cccc13e616 /compiler | |
parent | fe712a8b9c247d66df013f2b4b6faa6009d745bb (diff) |
Add debug info for link-time generated thunks.
Add debug info for method call thunks (currently unused) and
Baker read barrier thunks. Refactor debug info generation
for trampolines and record their sizes; change their names
to start with upper-case letters, so that they can be easily
generated as `#fn_name`.
This improved debug info must be generated by `dex2oat -g`,
the debug info generated by `oatdump --symbolize` remains
the same as before, except for the renamed trampolines and
an adjustment for "code delta", i.e. the Thumb mode bit.
Cortex-A53 erratum 843419 workaround thunks are not covered
by this CL.
Test: Manual; run-test --gdb -Xcompiler-option -g 160, pull
symbols for gdbclient, break in the introspection
entrypoint, check that gdb knows the new symbols
(and disassembles them) and `backtrace` works when
setting $pc to an address in the thunk.
Bug: 36141117
Change-Id: Id224b72cfa7a0628799c7db65e66e24c8517aabf
Diffstat (limited to 'compiler')
23 files changed, 244 insertions, 63 deletions
diff --git a/compiler/debug/elf_debug_writer.cc b/compiler/debug/elf_debug_writer.cc index 7fa6e146c5..16e73b0824 100644 --- a/compiler/debug/elf_debug_writer.cc +++ b/compiler/debug/elf_debug_writer.cc @@ -174,31 +174,6 @@ std::vector<uint8_t> WriteDebugElfFileForClasses(InstructionSet isa, } } -std::vector<MethodDebugInfo> MakeTrampolineInfos(const OatHeader& header) { - std::map<const char*, uint32_t> trampolines = { - { "interpreterToInterpreterBridge", header.GetInterpreterToInterpreterBridgeOffset() }, - { "interpreterToCompiledCodeBridge", header.GetInterpreterToCompiledCodeBridgeOffset() }, - { "jniDlsymLookup", header.GetJniDlsymLookupOffset() }, - { "quickGenericJniTrampoline", header.GetQuickGenericJniTrampolineOffset() }, - { "quickImtConflictTrampoline", header.GetQuickImtConflictTrampolineOffset() }, - { "quickResolutionTrampoline", header.GetQuickResolutionTrampolineOffset() }, - { "quickToInterpreterBridge", header.GetQuickToInterpreterBridgeOffset() }, - }; - std::vector<MethodDebugInfo> result; - for (const auto& it : trampolines) { - if (it.second != 0) { - MethodDebugInfo info = MethodDebugInfo(); - info.trampoline_name = it.first; - info.isa = header.GetInstructionSet(); - info.is_code_address_text_relative = true; - info.code_address = it.second - header.GetExecutableOffset(); - info.code_size = 0; // The symbol lasts until the next symbol. - result.push_back(std::move(info)); - } - } - return result; -} - // Explicit instantiations template void WriteDebugInfo<ElfTypes32>( ElfBuilder<ElfTypes32>* builder, diff --git a/compiler/debug/elf_debug_writer.h b/compiler/debug/elf_debug_writer.h index 5d688108e7..6e26ba36c4 100644 --- a/compiler/debug/elf_debug_writer.h +++ b/compiler/debug/elf_debug_writer.h @@ -58,8 +58,6 @@ std::vector<uint8_t> WriteDebugElfFileForClasses( const ArrayRef<mirror::Class*>& types) REQUIRES_SHARED(Locks::mutator_lock_); -std::vector<MethodDebugInfo> MakeTrampolineInfos(const OatHeader& oat_header); - } // namespace debug } // namespace art diff --git a/compiler/debug/elf_symtab_writer.h b/compiler/debug/elf_symtab_writer.h index af9f091529..abd2699a1f 100644 --- a/compiler/debug/elf_symtab_writer.h +++ b/compiler/debug/elf_symtab_writer.h @@ -65,7 +65,7 @@ static void WriteDebugSymbols(ElfBuilder<ElfTypes>* builder, continue; // Add symbol only for the first instance. } size_t name_offset; - if (info.trampoline_name != nullptr) { + if (!info.trampoline_name.empty()) { name_offset = strtab->Write(info.trampoline_name); } else { DCHECK(info.dex_file != nullptr); diff --git a/compiler/debug/method_debug_info.h b/compiler/debug/method_debug_info.h index ed1da2c26e..567891087a 100644 --- a/compiler/debug/method_debug_info.h +++ b/compiler/debug/method_debug_info.h @@ -17,6 +17,8 @@ #ifndef ART_COMPILER_DEBUG_METHOD_DEBUG_INFO_H_ #define ART_COMPILER_DEBUG_METHOD_DEBUG_INFO_H_ +#include <string> + #include "compiled_method.h" #include "dex_file.h" @@ -24,7 +26,7 @@ namespace art { namespace debug { struct MethodDebugInfo { - const char* trampoline_name; + std::string trampoline_name; const DexFile* dex_file; // Native methods (trampolines) do not reference dex file. size_t class_def_index; uint32_t dex_method_index; diff --git a/compiler/linker/arm/relative_patcher_arm_base.cc b/compiler/linker/arm/relative_patcher_arm_base.cc index 4ca5afe177..6e63bf8990 100644 --- a/compiler/linker/arm/relative_patcher_arm_base.cc +++ b/compiler/linker/arm/relative_patcher_arm_base.cc @@ -18,6 +18,7 @@ #include "base/stl_util.h" #include "compiled_method.h" +#include "debug/method_debug_info.h" #include "linker/output_stream.h" #include "oat.h" #include "oat_quick_method_header.h" @@ -119,6 +120,25 @@ class ArmBaseRelativePatcher::ThunkData { return offsets_[pending_offset_ - 1u]; } + size_t IndexOfFirstThunkAtOrAfter(uint32_t offset) const { + size_t number_of_thunks = NumberOfThunks(); + for (size_t i = 0; i != number_of_thunks; ++i) { + if (GetThunkOffset(i) >= offset) { + return i; + } + } + return number_of_thunks; + } + + size_t NumberOfThunks() const { + return offsets_.size(); + } + + uint32_t GetThunkOffset(size_t index) const { + DCHECK_LT(index, NumberOfThunks()); + return offsets_[index]; + } + private: std::vector<uint8_t> code_; // The code of the thunk. std::vector<uint32_t> offsets_; // Offsets at which the thunk needs to be written. @@ -203,6 +223,48 @@ uint32_t ArmBaseRelativePatcher::WriteThunks(OutputStream* out, uint32_t offset) return offset; } +std::vector<debug::MethodDebugInfo> ArmBaseRelativePatcher::GenerateThunkDebugInfo( + uint32_t executable_offset) { + // For multi-oat compilation (boot image), `thunks_` records thunks for all oat files. + // To return debug info for the current oat file, we must ignore thunks before the + // `executable_offset` as they are in the previous oat files and this function must be + // called before reserving thunk positions for subsequent oat files. + size_t number_of_thunks = 0u; + for (auto&& entry : thunks_) { + const ThunkData& data = entry.second; + number_of_thunks += data.NumberOfThunks() - data.IndexOfFirstThunkAtOrAfter(executable_offset); + } + std::vector<debug::MethodDebugInfo> result; + result.reserve(number_of_thunks); + for (auto&& entry : thunks_) { + const ThunkKey& key = entry.first; + const ThunkData& data = entry.second; + size_t start = data.IndexOfFirstThunkAtOrAfter(executable_offset); + if (start == data.NumberOfThunks()) { + continue; + } + // Get the base name to use for the first occurrence of the thunk. + std::string base_name = GetThunkDebugName(key); + for (size_t i = start, num = data.NumberOfThunks(); i != num; ++i) { + debug::MethodDebugInfo info = {}; + if (i == 0u) { + info.trampoline_name = base_name; + } else { + // Add a disambiguating tag for subsequent identical thunks. Since the `thunks_` + // keeps records also for thunks in previous oat files, names based on the thunk + // index shall be unique across the whole multi-oat output. + info.trampoline_name = base_name + "_" + std::to_string(i); + } + info.isa = instruction_set_; + info.is_code_address_text_relative = true; + info.code_address = data.GetThunkOffset(i) - executable_offset; + info.code_size = data.CodeSize(); + result.push_back(std::move(info)); + } + } + return result; +} + ArmBaseRelativePatcher::ArmBaseRelativePatcher(RelativePatcherTargetProvider* provider, InstructionSet instruction_set) : provider_(provider), diff --git a/compiler/linker/arm/relative_patcher_arm_base.h b/compiler/linker/arm/relative_patcher_arm_base.h index 5197ce2549..4c2be1e1a7 100644 --- a/compiler/linker/arm/relative_patcher_arm_base.h +++ b/compiler/linker/arm/relative_patcher_arm_base.h @@ -34,6 +34,7 @@ class ArmBaseRelativePatcher : public RelativePatcher { MethodReference method_ref) OVERRIDE; uint32_t ReserveSpaceEnd(uint32_t offset) OVERRIDE; uint32_t WriteThunks(OutputStream* out, uint32_t offset) OVERRIDE; + std::vector<debug::MethodDebugInfo> GenerateThunkDebugInfo(uint32_t executable_offset) OVERRIDE; protected: ArmBaseRelativePatcher(RelativePatcherTargetProvider* provider, @@ -94,6 +95,7 @@ class ArmBaseRelativePatcher : public RelativePatcher { uint32_t target_offset); virtual std::vector<uint8_t> CompileThunk(const ThunkKey& key) = 0; + virtual std::string GetThunkDebugName(const ThunkKey& key) = 0; virtual uint32_t MaxPositiveDisplacement(const ThunkKey& key) = 0; virtual uint32_t MaxNegativeDisplacement(const ThunkKey& key) = 0; diff --git a/compiler/linker/arm/relative_patcher_thumb2.cc b/compiler/linker/arm/relative_patcher_thumb2.cc index 2ac2a1d2fc..704feeb387 100644 --- a/compiler/linker/arm/relative_patcher_thumb2.cc +++ b/compiler/linker/arm/relative_patcher_thumb2.cc @@ -281,7 +281,7 @@ void Thumb2RelativePatcher::CompileBakerReadBarrierThunk(arm::ArmVIXLAssembler& Register base_reg(BakerReadBarrierFirstRegField::Decode(encoded_data)); CheckValidReg(base_reg.GetCode()); DCHECK_EQ(kInvalidEncodedReg, BakerReadBarrierSecondRegField::Decode(encoded_data)); - DCHECK(BakerReadBarrierWidth::kWide == BakerReadBarrierWidthField::Decode(encoded_data)); + DCHECK(BakerReadBarrierWidthField::Decode(encoded_data) == BakerReadBarrierWidth::kWide); UseScratchRegisterScope temps(assembler.GetVIXLAssembler()); temps.Exclude(ip); vixl::aarch32::Label slow_path; @@ -379,6 +379,44 @@ std::vector<uint8_t> Thumb2RelativePatcher::CompileThunk(const ThunkKey& key) { return thunk_code; } +std::string Thumb2RelativePatcher::GetThunkDebugName(const ThunkKey& key) { + switch (key.GetType()) { + case ThunkType::kMethodCall: + return "MethodCallThunk"; + + case ThunkType::kBakerReadBarrier: { + uint32_t encoded_data = key.GetCustomValue1(); + BakerReadBarrierKind kind = BakerReadBarrierKindField::Decode(encoded_data); + std::ostringstream oss; + oss << "BakerReadBarrierThunk"; + switch (kind) { + case BakerReadBarrierKind::kField: + oss << "Field"; + if (BakerReadBarrierWidthField::Decode(encoded_data) == BakerReadBarrierWidth::kWide) { + oss << "Wide"; + } + oss << "_r" << BakerReadBarrierFirstRegField::Decode(encoded_data) + << "_r" << BakerReadBarrierSecondRegField::Decode(encoded_data); + break; + case BakerReadBarrierKind::kArray: + oss << "Array_r" << BakerReadBarrierFirstRegField::Decode(encoded_data); + DCHECK_EQ(kInvalidEncodedReg, BakerReadBarrierSecondRegField::Decode(encoded_data)); + DCHECK(BakerReadBarrierWidthField::Decode(encoded_data) == BakerReadBarrierWidth::kWide); + break; + case BakerReadBarrierKind::kGcRoot: + oss << "GcRoot"; + if (BakerReadBarrierWidthField::Decode(encoded_data) == BakerReadBarrierWidth::kWide) { + oss << "Wide"; + } + oss << "_r" << BakerReadBarrierFirstRegField::Decode(encoded_data); + DCHECK_EQ(kInvalidEncodedReg, BakerReadBarrierSecondRegField::Decode(encoded_data)); + break; + } + return oss.str(); + } + } +} + #undef __ uint32_t Thumb2RelativePatcher::MaxPositiveDisplacement(const ThunkKey& key) { diff --git a/compiler/linker/arm/relative_patcher_thumb2.h b/compiler/linker/arm/relative_patcher_thumb2.h index 183e5e6c96..68386c00f4 100644 --- a/compiler/linker/arm/relative_patcher_thumb2.h +++ b/compiler/linker/arm/relative_patcher_thumb2.h @@ -84,6 +84,7 @@ class Thumb2RelativePatcher FINAL : public ArmBaseRelativePatcher { protected: std::vector<uint8_t> CompileThunk(const ThunkKey& key) OVERRIDE; + std::string GetThunkDebugName(const ThunkKey& key) OVERRIDE; uint32_t MaxPositiveDisplacement(const ThunkKey& key) OVERRIDE; uint32_t MaxNegativeDisplacement(const ThunkKey& key) OVERRIDE; diff --git a/compiler/linker/arm64/relative_patcher_arm64.cc b/compiler/linker/arm64/relative_patcher_arm64.cc index 4960f4d856..270ba3c08d 100644 --- a/compiler/linker/arm64/relative_patcher_arm64.cc +++ b/compiler/linker/arm64/relative_patcher_arm64.cc @@ -535,6 +535,35 @@ std::vector<uint8_t> Arm64RelativePatcher::CompileThunk(const ThunkKey& key) { return thunk_code; } +std::string Arm64RelativePatcher::GetThunkDebugName(const ThunkKey& key) { + switch (key.GetType()) { + case ThunkType::kMethodCall: + return "MethodCallThunk"; + + case ThunkType::kBakerReadBarrier: { + uint32_t encoded_data = key.GetCustomValue1(); + BakerReadBarrierKind kind = BakerReadBarrierKindField::Decode(encoded_data); + std::ostringstream oss; + oss << "BakerReadBarrierThunk"; + switch (kind) { + case BakerReadBarrierKind::kField: + oss << "Field_r" << BakerReadBarrierFirstRegField::Decode(encoded_data) + << "_r" << BakerReadBarrierSecondRegField::Decode(encoded_data); + break; + case BakerReadBarrierKind::kArray: + oss << "Array_r" << BakerReadBarrierFirstRegField::Decode(encoded_data); + DCHECK_EQ(kInvalidEncodedReg, BakerReadBarrierSecondRegField::Decode(encoded_data)); + break; + case BakerReadBarrierKind::kGcRoot: + oss << "GcRoot_r" << BakerReadBarrierFirstRegField::Decode(encoded_data); + DCHECK_EQ(kInvalidEncodedReg, BakerReadBarrierSecondRegField::Decode(encoded_data)); + break; + } + return oss.str(); + } + } +} + #undef __ uint32_t Arm64RelativePatcher::MaxPositiveDisplacement(const ThunkKey& key) { diff --git a/compiler/linker/arm64/relative_patcher_arm64.h b/compiler/linker/arm64/relative_patcher_arm64.h index b00dd081b6..8ba59976e7 100644 --- a/compiler/linker/arm64/relative_patcher_arm64.h +++ b/compiler/linker/arm64/relative_patcher_arm64.h @@ -76,6 +76,7 @@ class Arm64RelativePatcher FINAL : public ArmBaseRelativePatcher { protected: std::vector<uint8_t> CompileThunk(const ThunkKey& key) OVERRIDE; + std::string GetThunkDebugName(const ThunkKey& key) OVERRIDE; uint32_t MaxPositiveDisplacement(const ThunkKey& key) OVERRIDE; uint32_t MaxNegativeDisplacement(const ThunkKey& key) OVERRIDE; diff --git a/compiler/linker/mips/relative_patcher_mips.cc b/compiler/linker/mips/relative_patcher_mips.cc index 6c974c308f..408ac22976 100644 --- a/compiler/linker/mips/relative_patcher_mips.cc +++ b/compiler/linker/mips/relative_patcher_mips.cc @@ -17,6 +17,7 @@ #include "linker/mips/relative_patcher_mips.h" #include "compiled_method.h" +#include "debug/method_debug_info.h" namespace art { namespace linker { @@ -90,5 +91,10 @@ void MipsRelativePatcher::PatchBakerReadBarrierBranch(std::vector<uint8_t>* code LOG(FATAL) << "UNIMPLEMENTED"; } +std::vector<debug::MethodDebugInfo> MipsRelativePatcher::GenerateThunkDebugInfo( + uint32_t executable_offset ATTRIBUTE_UNUSED) { + return std::vector<debug::MethodDebugInfo>(); // No thunks added. +} + } // namespace linker } // namespace art diff --git a/compiler/linker/mips/relative_patcher_mips.h b/compiler/linker/mips/relative_patcher_mips.h index d6eda34592..5714a7d1b0 100644 --- a/compiler/linker/mips/relative_patcher_mips.h +++ b/compiler/linker/mips/relative_patcher_mips.h @@ -44,6 +44,7 @@ class MipsRelativePatcher FINAL : public RelativePatcher { void PatchBakerReadBarrierBranch(std::vector<uint8_t>* code, const LinkerPatch& patch, uint32_t patch_offset) OVERRIDE; + std::vector<debug::MethodDebugInfo> GenerateThunkDebugInfo(uint32_t executable_offset) OVERRIDE; private: bool is_r6; diff --git a/compiler/linker/mips64/relative_patcher_mips64.cc b/compiler/linker/mips64/relative_patcher_mips64.cc index d9f4758eb1..2bcd98a2b0 100644 --- a/compiler/linker/mips64/relative_patcher_mips64.cc +++ b/compiler/linker/mips64/relative_patcher_mips64.cc @@ -17,6 +17,7 @@ #include "linker/mips64/relative_patcher_mips64.h" #include "compiled_method.h" +#include "debug/method_debug_info.h" namespace art { namespace linker { @@ -88,5 +89,10 @@ void Mips64RelativePatcher::PatchBakerReadBarrierBranch(std::vector<uint8_t>* co LOG(FATAL) << "UNIMPLEMENTED"; } +std::vector<debug::MethodDebugInfo> Mips64RelativePatcher::GenerateThunkDebugInfo( + uint32_t executable_offset ATTRIBUTE_UNUSED) { + return std::vector<debug::MethodDebugInfo>(); // No thunks added. +} + } // namespace linker } // namespace art diff --git a/compiler/linker/mips64/relative_patcher_mips64.h b/compiler/linker/mips64/relative_patcher_mips64.h index f478d7f2ef..6d7c638312 100644 --- a/compiler/linker/mips64/relative_patcher_mips64.h +++ b/compiler/linker/mips64/relative_patcher_mips64.h @@ -42,6 +42,7 @@ class Mips64RelativePatcher FINAL : public RelativePatcher { void PatchBakerReadBarrierBranch(std::vector<uint8_t>* code, const LinkerPatch& patch, uint32_t patch_offset) OVERRIDE; + std::vector<debug::MethodDebugInfo> GenerateThunkDebugInfo(uint32_t executable_offset) OVERRIDE; private: DISALLOW_COPY_AND_ASSIGN(Mips64RelativePatcher); diff --git a/compiler/linker/multi_oat_relative_patcher.h b/compiler/linker/multi_oat_relative_patcher.h index bdc1ee1d27..1c5c8a09c0 100644 --- a/compiler/linker/multi_oat_relative_patcher.h +++ b/compiler/linker/multi_oat_relative_patcher.h @@ -18,6 +18,7 @@ #define ART_COMPILER_LINKER_MULTI_OAT_RELATIVE_PATCHER_H_ #include "arch/instruction_set.h" +#include "debug/method_debug_info.h" #include "method_reference.h" #include "relative_patcher.h" #include "safe_map.h" @@ -119,6 +120,11 @@ class MultiOatRelativePatcher FINAL { relative_patcher_->PatchBakerReadBarrierBranch(code, patch, patch_offset); } + std::vector<debug::MethodDebugInfo> GenerateThunkDebugInfo(size_t executable_offset) { + executable_offset += adjustment_; + return relative_patcher_->GenerateThunkDebugInfo(executable_offset); + } + // Wrappers around RelativePatcher for statistics retrieval. uint32_t CodeAlignmentSize() const; uint32_t RelativeCallThunksSize() const; diff --git a/compiler/linker/multi_oat_relative_patcher_test.cc b/compiler/linker/multi_oat_relative_patcher_test.cc index e96790115a..f89fba698c 100644 --- a/compiler/linker/multi_oat_relative_patcher_test.cc +++ b/compiler/linker/multi_oat_relative_patcher_test.cc @@ -17,6 +17,7 @@ #include "multi_oat_relative_patcher.h" #include "compiled_method.h" +#include "debug/method_debug_info.h" #include "gtest/gtest.h" #include "vector_output_stream.h" @@ -102,6 +103,12 @@ class MultiOatRelativePatcherTest : public testing::Test { LOG(FATAL) << "UNIMPLEMENTED"; } + std::vector<debug::MethodDebugInfo> GenerateThunkDebugInfo( + uint32_t executable_offset ATTRIBUTE_UNUSED) { + LOG(FATAL) << "UNIMPLEMENTED"; + UNREACHABLE(); + } + uint32_t last_reserve_offset_ = 0u; MethodReference last_reserve_method_ = kNullMethodRef; uint32_t next_reserve_adjustment_ = 0u; diff --git a/compiler/linker/relative_patcher.cc b/compiler/linker/relative_patcher.cc index ee49453938..dc15bb087e 100644 --- a/compiler/linker/relative_patcher.cc +++ b/compiler/linker/relative_patcher.cc @@ -16,6 +16,7 @@ #include "linker/relative_patcher.h" +#include "debug/method_debug_info.h" #ifdef ART_ENABLE_CODEGEN_arm #include "linker/arm/relative_patcher_thumb2.h" #endif @@ -81,6 +82,11 @@ std::unique_ptr<RelativePatcher> RelativePatcher::Create( LOG(FATAL) << "Unexpected baker read barrier branch patch."; } + std::vector<debug::MethodDebugInfo> GenerateThunkDebugInfo( + uint32_t executable_offset ATTRIBUTE_UNUSED) OVERRIDE { + return std::vector<debug::MethodDebugInfo>(); // No thunks added. + } + private: DISALLOW_COPY_AND_ASSIGN(RelativePatcherNone); }; diff --git a/compiler/linker/relative_patcher.h b/compiler/linker/relative_patcher.h index 38c8228422..53a096627f 100644 --- a/compiler/linker/relative_patcher.h +++ b/compiler/linker/relative_patcher.h @@ -31,6 +31,10 @@ class CompiledMethod; class LinkerPatch; class OutputStream; +namespace debug { +struct MethodDebugInfo; +} // namespace debug + namespace linker { /** @@ -114,6 +118,9 @@ class RelativePatcher { const LinkerPatch& patch, uint32_t patch_offset) = 0; + virtual std::vector<debug::MethodDebugInfo> GenerateThunkDebugInfo( + uint32_t executable_offset) = 0; + protected: RelativePatcher() : size_code_alignment_(0u), diff --git a/compiler/linker/x86/relative_patcher_x86_base.cc b/compiler/linker/x86/relative_patcher_x86_base.cc index bf3a648218..6a9690d768 100644 --- a/compiler/linker/x86/relative_patcher_x86_base.cc +++ b/compiler/linker/x86/relative_patcher_x86_base.cc @@ -16,6 +16,8 @@ #include "linker/x86/relative_patcher_x86_base.h" +#include "debug/method_debug_info.h" + namespace art { namespace linker { @@ -34,6 +36,11 @@ uint32_t X86BaseRelativePatcher::WriteThunks(OutputStream* out ATTRIBUTE_UNUSED, return offset; // No thunks added; no limit on relative call distance. } +std::vector<debug::MethodDebugInfo> X86BaseRelativePatcher::GenerateThunkDebugInfo( + uint32_t executable_offset ATTRIBUTE_UNUSED) { + return std::vector<debug::MethodDebugInfo>(); // No thunks added. +} + void X86BaseRelativePatcher::PatchCall(std::vector<uint8_t>* code, uint32_t literal_offset, uint32_t patch_offset, diff --git a/compiler/linker/x86/relative_patcher_x86_base.h b/compiler/linker/x86/relative_patcher_x86_base.h index ca83a72f48..6097345657 100644 --- a/compiler/linker/x86/relative_patcher_x86_base.h +++ b/compiler/linker/x86/relative_patcher_x86_base.h @@ -33,6 +33,7 @@ class X86BaseRelativePatcher : public RelativePatcher { uint32_t literal_offset, uint32_t patch_offset, uint32_t target_offset) OVERRIDE; + std::vector<debug::MethodDebugInfo> GenerateThunkDebugInfo(uint32_t executable_offset) OVERRIDE; protected: X86BaseRelativePatcher() { } diff --git a/compiler/oat_writer.cc b/compiler/oat_writer.cc index cc8c6dfac0..7ae3866bc1 100644 --- a/compiler/oat_writer.cc +++ b/compiler/oat_writer.cc @@ -867,16 +867,19 @@ class OatWriter::InitOatClassesMethodVisitor : public DexMethodVisitor { class OatWriter::InitCodeMethodVisitor : public OatDexMethodVisitor { public: InitCodeMethodVisitor(OatWriter* writer, size_t offset) - : OatDexMethodVisitor(writer, offset), - debuggable_(writer->GetCompilerDriver()->GetCompilerOptions().GetDebuggable()) { - writer_->absolute_patch_locations_.reserve( - writer_->compiler_driver_->GetNonRelativeLinkerPatchCount()); - } + : InitCodeMethodVisitor(writer, offset, writer->GetCompilerDriver()->GetCompilerOptions()) {} bool EndClass() OVERRIDE { OatDexMethodVisitor::EndClass(); if (oat_class_index_ == writer_->oat_classes_.size()) { - offset_ = writer_->relative_patcher_->ReserveSpaceEnd(offset_); + offset_ = relative_patcher_->ReserveSpaceEnd(offset_); + if (generate_debug_info_) { + std::vector<debug::MethodDebugInfo> thunk_infos = + relative_patcher_->GenerateThunkDebugInfo(executable_offset_); + writer_->method_info_.insert(writer_->method_info_.end(), + std::make_move_iterator(thunk_infos.begin()), + std::make_move_iterator(thunk_infos.end())); + } } return true; } @@ -898,7 +901,7 @@ class OatWriter::InitCodeMethodVisitor : public OatDexMethodVisitor { bool deduped = true; MethodReference method_ref(dex_file_, it.GetMemberIndex()); if (debuggable_) { - quick_code_offset = writer_->relative_patcher_->GetOffset(method_ref); + quick_code_offset = relative_patcher_->GetOffset(method_ref); if (quick_code_offset != 0u) { // Duplicate methods, we want the same code for both of them so that the oat writer puts // the same code in both ArtMethods so that we do not get different oat code at runtime. @@ -916,14 +919,14 @@ class OatWriter::InitCodeMethodVisitor : public OatDexMethodVisitor { } if (code_size != 0) { - if (writer_->relative_patcher_->GetOffset(method_ref) != 0u) { + if (relative_patcher_->GetOffset(method_ref) != 0u) { // TODO: Should this be a hard failure? LOG(WARNING) << "Multiple definitions of " << method_ref.dex_file->PrettyMethod(method_ref.dex_method_index) - << " offsets " << writer_->relative_patcher_->GetOffset(method_ref) + << " offsets " << relative_patcher_->GetOffset(method_ref) << " " << quick_code_offset; } else { - writer_->relative_patcher_->SetOffset(method_ref, quick_code_offset); + relative_patcher_->SetOffset(method_ref, quick_code_offset); } } @@ -977,13 +980,12 @@ class OatWriter::InitCodeMethodVisitor : public OatDexMethodVisitor { } } - const CompilerOptions& compiler_options = writer_->compiler_driver_->GetCompilerOptions(); // Exclude quickened dex methods (code_size == 0) since they have no native code. - if (compiler_options.GenerateAnyDebugInfo() && code_size != 0) { + if (generate_debug_info_ && code_size != 0) { bool has_code_info = method_header->IsOptimized(); // Record debug information for this function if we are doing that. - debug::MethodDebugInfo info = debug::MethodDebugInfo(); - info.trampoline_name = nullptr; + debug::MethodDebugInfo info = {}; + DCHECK(info.trampoline_name.empty()); info.dex_file = dex_file_; info.class_def_index = class_def_index_; info.dex_method_index = it.GetMemberIndex(); @@ -991,10 +993,10 @@ class OatWriter::InitCodeMethodVisitor : public OatDexMethodVisitor { info.code_item = it.GetMethodCodeItem(); info.isa = compiled_method->GetInstructionSet(); info.deduped = deduped; - info.is_native_debuggable = compiler_options.GetNativeDebuggable(); + info.is_native_debuggable = native_debuggable_; info.is_optimized = method_header->IsOptimized(); info.is_code_address_text_relative = true; - info.code_address = code_offset - writer_->oat_header_->GetExecutableOffset(); + info.code_address = code_offset - executable_offset_; info.code_size = code_size; info.frame_size_in_bytes = compiled_method->GetFrameSizeInBytes(); info.code_info = has_code_info ? compiled_method->GetVmapTable().data() : nullptr; @@ -1012,6 +1014,17 @@ class OatWriter::InitCodeMethodVisitor : public OatDexMethodVisitor { } private: + InitCodeMethodVisitor(OatWriter* writer, size_t offset, const CompilerOptions& compiler_options) + : OatDexMethodVisitor(writer, offset), + relative_patcher_(writer->relative_patcher_), + executable_offset_(writer->oat_header_->GetExecutableOffset()), + debuggable_(compiler_options.GetDebuggable()), + native_debuggable_(compiler_options.GetNativeDebuggable()), + generate_debug_info_(compiler_options.GenerateAnyDebugInfo()) { + writer->absolute_patch_locations_.reserve( + writer->GetCompilerDriver()->GetNonRelativeLinkerPatchCount()); + } + struct CodeOffsetsKeyComparator { bool operator()(const CompiledMethod* lhs, const CompiledMethod* rhs) const { // Code is deduplicated by CompilerDriver, compare only data pointers. @@ -1035,7 +1048,7 @@ class OatWriter::InitCodeMethodVisitor : public OatDexMethodVisitor { uint32_t NewQuickCodeOffset(CompiledMethod* compiled_method, const ClassDataItemIterator& it, uint32_t thumb_offset) { - offset_ = writer_->relative_patcher_->ReserveSpace( + offset_ = relative_patcher_->ReserveSpace( offset_, compiled_method, MethodReference(dex_file_, it.GetMemberIndex())); offset_ += CodeAlignmentSize(offset_, *compiled_method); DCHECK_ALIGNED_PARAM(offset_ + sizeof(OatQuickMethodHeader), @@ -1047,8 +1060,12 @@ 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_; - // Cache of compiler's --debuggable option. + // Cache writer_'s members and compiler options. + linker::MultiOatRelativePatcher* relative_patcher_; + uint32_t executable_offset_; const bool debuggable_; + const bool native_debuggable_; + const bool generate_debug_info_; }; class OatWriter::InitMapMethodVisitor : public OatDexMethodVisitor { @@ -1935,19 +1952,33 @@ size_t OatWriter::InitOatDexFiles(size_t offset) { size_t OatWriter::InitOatCode(size_t offset) { // calculate the offsets within OatHeader to executable code size_t old_offset = offset; - size_t adjusted_offset = offset; // required to be on a new page boundary offset = RoundUp(offset, kPageSize); oat_header_->SetExecutableOffset(offset); size_executable_offset_alignment_ = offset - old_offset; + // TODO: Remove unused trampoline offsets from the OatHeader (requires oat version change). + oat_header_->SetInterpreterToInterpreterBridgeOffset(0); + oat_header_->SetInterpreterToCompiledCodeBridgeOffset(0); if (compiler_driver_->GetCompilerOptions().IsBootImage()) { InstructionSet instruction_set = compiler_driver_->GetInstructionSet(); - - #define DO_TRAMPOLINE(field, fn_name) \ - offset = CompiledCode::AlignCode(offset, instruction_set); \ - adjusted_offset = offset + CompiledCode::CodeDelta(instruction_set); \ - oat_header_->Set ## fn_name ## Offset(adjusted_offset); \ - (field) = compiler_driver_->Create ## fn_name(); \ + const bool generate_debug_info = compiler_driver_->GetCompilerOptions().GenerateAnyDebugInfo(); + size_t adjusted_offset = offset; + + #define DO_TRAMPOLINE(field, fn_name) \ + offset = CompiledCode::AlignCode(offset, instruction_set); \ + adjusted_offset = offset + CompiledCode::CodeDelta(instruction_set); \ + oat_header_->Set ## fn_name ## Offset(adjusted_offset); \ + (field) = compiler_driver_->Create ## fn_name(); \ + if (generate_debug_info) { \ + debug::MethodDebugInfo info = {}; \ + info.trampoline_name = #fn_name; \ + info.isa = instruction_set; \ + info.is_code_address_text_relative = true; \ + /* Use the code offset rather than the `adjusted_offset`. */ \ + info.code_address = offset - oat_header_->GetExecutableOffset(); \ + info.code_size = (field)->size(); \ + method_info_.push_back(std::move(info)); \ + } \ offset += (field)->size(); DO_TRAMPOLINE(jni_dlsym_lookup_, JniDlsymLookup); @@ -1958,8 +1989,6 @@ size_t OatWriter::InitOatCode(size_t offset) { #undef DO_TRAMPOLINE } else { - oat_header_->SetInterpreterToInterpreterBridgeOffset(0); - oat_header_->SetInterpreterToCompiledCodeBridgeOffset(0); oat_header_->SetJniDlsymLookupOffset(0); oat_header_->SetQuickGenericJniTrampolineOffset(0); oat_header_->SetQuickImtConflictTrampolineOffset(0); diff --git a/compiler/oat_writer.h b/compiler/oat_writer.h index 7f2045f8da..ef0ce52743 100644 --- a/compiler/oat_writer.h +++ b/compiler/oat_writer.h @@ -231,10 +231,6 @@ class OatWriter { ~OatWriter(); - void AddMethodDebugInfos(const std::vector<debug::MethodDebugInfo>& infos) { - method_info_.insert(method_info_.end(), infos.begin(), infos.end()); - } - ArrayRef<const debug::MethodDebugInfo> GetMethodDebugInfo() const { return ArrayRef<const debug::MethodDebugInfo>(method_info_); } diff --git a/compiler/optimizing/optimizing_compiler.cc b/compiler/optimizing/optimizing_compiler.cc index 399cd98983..73b0fa2bfa 100644 --- a/compiler/optimizing/optimizing_compiler.cc +++ b/compiler/optimizing/optimizing_compiler.cc @@ -1269,8 +1269,8 @@ bool OptimizingCompiler::JitCompile(Thread* self, if (compiler_options.GetGenerateDebugInfo()) { const auto* method_header = reinterpret_cast<const OatQuickMethodHeader*>(code); const uintptr_t code_address = reinterpret_cast<uintptr_t>(method_header->GetCode()); - debug::MethodDebugInfo info = debug::MethodDebugInfo(); - info.trampoline_name = nullptr; + debug::MethodDebugInfo info = {}; + DCHECK(info.trampoline_name.empty()); info.dex_file = dex_file; info.class_def_index = class_def_idx; info.dex_method_index = method_idx; |