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
diff --git a/compiler/debug/elf_debug_writer.cc b/compiler/debug/elf_debug_writer.cc
index 7fa6e14..16e73b0 100644
--- a/compiler/debug/elf_debug_writer.cc
+++ b/compiler/debug/elf_debug_writer.cc
@@ -174,31 +174,6 @@
}
}
-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 5d68810..6e26ba3 100644
--- a/compiler/debug/elf_debug_writer.h
+++ b/compiler/debug/elf_debug_writer.h
@@ -58,8 +58,6 @@
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 af9f091..abd2699 100644
--- a/compiler/debug/elf_symtab_writer.h
+++ b/compiler/debug/elf_symtab_writer.h
@@ -65,7 +65,7 @@
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 ed1da2c..5678910 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 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 4ca5afe..6e63bf8 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 @@
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 @@
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 5197ce2..4c2be1e 100644
--- a/compiler/linker/arm/relative_patcher_arm_base.h
+++ b/compiler/linker/arm/relative_patcher_arm_base.h
@@ -34,6 +34,7 @@
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 @@
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 2ac2a1d..704feeb 100644
--- a/compiler/linker/arm/relative_patcher_thumb2.cc
+++ b/compiler/linker/arm/relative_patcher_thumb2.cc
@@ -281,7 +281,7 @@
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 @@
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 183e5e6..68386c0 100644
--- a/compiler/linker/arm/relative_patcher_thumb2.h
+++ b/compiler/linker/arm/relative_patcher_thumb2.h
@@ -84,6 +84,7 @@
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 4960f4d..270ba3c 100644
--- a/compiler/linker/arm64/relative_patcher_arm64.cc
+++ b/compiler/linker/arm64/relative_patcher_arm64.cc
@@ -535,6 +535,35 @@
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 b00dd08..8ba5997 100644
--- a/compiler/linker/arm64/relative_patcher_arm64.h
+++ b/compiler/linker/arm64/relative_patcher_arm64.h
@@ -76,6 +76,7 @@
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 6c974c3..408ac22 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 @@
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 d6eda34..5714a7d 100644
--- a/compiler/linker/mips/relative_patcher_mips.h
+++ b/compiler/linker/mips/relative_patcher_mips.h
@@ -44,6 +44,7 @@
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 d9f4758..2bcd98a 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 @@
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 f478d7f..6d7c638 100644
--- a/compiler/linker/mips64/relative_patcher_mips64.h
+++ b/compiler/linker/mips64/relative_patcher_mips64.h
@@ -42,6 +42,7 @@
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 bdc1ee1..1c5c8a0 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 @@
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 e967901..f89fba6 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 @@
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 ee49453..dc15bb0 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 @@
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 38c8228..53a0966 100644
--- a/compiler/linker/relative_patcher.h
+++ b/compiler/linker/relative_patcher.h
@@ -31,6 +31,10 @@
class LinkerPatch;
class OutputStream;
+namespace debug {
+struct MethodDebugInfo;
+} // namespace debug
+
namespace linker {
/**
@@ -114,6 +118,9 @@
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 bf3a648..6a9690d 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 @@
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 ca83a72..6097345 100644
--- a/compiler/linker/x86/relative_patcher_x86_base.h
+++ b/compiler/linker/x86/relative_patcher_x86_base.h
@@ -33,6 +33,7 @@
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 cc8c6df..7ae3866 100644
--- a/compiler/oat_writer.cc
+++ b/compiler/oat_writer.cc
@@ -867,16 +867,19 @@
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 @@
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 @@
}
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 @@
}
}
- 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 @@
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 @@
}
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 @@
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 @@
// 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::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();
+ 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(); \
+ #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 @@
#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 7f2045f..ef0ce52 100644
--- a/compiler/oat_writer.h
+++ b/compiler/oat_writer.h
@@ -231,10 +231,6 @@
~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 399cd98..73b0fa2 100644
--- a/compiler/optimizing/optimizing_compiler.cc
+++ b/compiler/optimizing/optimizing_compiler.cc
@@ -1269,8 +1269,8 @@
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;
diff --git a/dex2oat/dex2oat.cc b/dex2oat/dex2oat.cc
index 4ecb043..d8caf42 100644
--- a/dex2oat/dex2oat.cc
+++ b/dex2oat/dex2oat.cc
@@ -2119,8 +2119,6 @@
std::unique_ptr<ElfWriter>& elf_writer = elf_writers_[i];
std::unique_ptr<OatWriter>& oat_writer = oat_writers_[i];
- oat_writer->AddMethodDebugInfos(debug::MakeTrampolineInfos(oat_writer->GetOatHeader()));
-
// We need to mirror the layout of the ELF file in the compressed debug-info.
// Therefore PrepareDebugInfo() relies on the SetLoadedSectionSizes() call further above.
elf_writer->PrepareDebugInfo(oat_writer->GetMethodDebugInfo());
diff --git a/oatdump/oatdump.cc b/oatdump/oatdump.cc
index 4161067..13f7211 100644
--- a/oatdump/oatdump.cc
+++ b/oatdump/oatdump.cc
@@ -178,10 +178,32 @@
oat_file_->BssRootsOffset());
builder_->WriteDynamicSection();
+ const OatHeader& oat_header = oat_file_->GetOatHeader();
+ #define DO_TRAMPOLINE(fn_name) \
+ if (oat_header.Get ## fn_name ## Offset() != 0) { \
+ debug::MethodDebugInfo info = {}; \
+ info.trampoline_name = #fn_name; \
+ info.isa = oat_header.GetInstructionSet(); \
+ info.is_code_address_text_relative = true; \
+ size_t code_offset = oat_header.Get ## fn_name ## Offset(); \
+ code_offset -= CompiledCode::CodeDelta(oat_header.GetInstructionSet()); \
+ info.code_address = code_offset - oat_header.GetExecutableOffset(); \
+ info.code_size = 0; /* The symbol lasts until the next symbol. */ \
+ method_debug_infos_.push_back(std::move(info)); \
+ }
+ DO_TRAMPOLINE(InterpreterToInterpreterBridge)
+ DO_TRAMPOLINE(InterpreterToCompiledCodeBridge)
+ DO_TRAMPOLINE(JniDlsymLookup);
+ DO_TRAMPOLINE(QuickGenericJniTrampoline);
+ DO_TRAMPOLINE(QuickImtConflictTrampoline);
+ DO_TRAMPOLINE(QuickResolutionTrampoline);
+ DO_TRAMPOLINE(QuickToInterpreterBridge);
+ #undef DO_TRAMPOLINE
+
Walk();
- for (const auto& trampoline : debug::MakeTrampolineInfos(oat_file_->GetOatHeader())) {
- method_debug_infos_.push_back(trampoline);
- }
+
+ // TODO: Try to symbolize link-time thunks?
+ // This would require disassembling all methods to find branches outside the method code.
debug::WriteDebugInfo(builder_.get(),
ArrayRef<const debug::MethodDebugInfo>(method_debug_infos_),
@@ -282,8 +304,8 @@
// Clear Thumb2 bit.
const void* code_address = EntryPointToCodePointer(reinterpret_cast<void*>(entry_point));
- 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 = dex_method_index;