Add trampoline symbols to native debug info.
The debugger needs them to unwind through the trampolines and to
understand what is happening in the call stack.
Change-Id: Ia554058c3796788adcd7336d620a7734eb366905
diff --git a/compiler/debug/elf_debug_info_writer.h b/compiler/debug/elf_debug_info_writer.h
index af74d4c..a6e6f8b 100644
--- a/compiler/debug/elf_debug_info_writer.h
+++ b/compiler/debug/elf_debug_info_writer.h
@@ -46,6 +46,7 @@
static std::vector<const char*> GetParamNames(const MethodDebugInfo* mi) {
std::vector<const char*> names;
if (mi->code_item != nullptr) {
+ DCHECK(mi->dex_file != nullptr);
const uint8_t* stream = mi->dex_file->GetDebugInfoStream(mi->code_item);
if (stream != nullptr) {
DecodeUnsignedLeb128(&stream); // line.
@@ -133,6 +134,7 @@
const char* last_dex_class_desc = nullptr;
for (auto mi : compilation_unit.methods) {
+ DCHECK(mi->dex_file != nullptr);
const DexFile* dex = mi->dex_file;
const DexFile::CodeItem* dex_code = mi->code_item;
const DexFile::MethodId& dex_method = dex->GetMethodId(mi->dex_method_index);
diff --git a/compiler/debug/elf_debug_line_writer.h b/compiler/debug/elf_debug_line_writer.h
index ed26d96..9875c71 100644
--- a/compiler/debug/elf_debug_line_writer.h
+++ b/compiler/debug/elf_debug_line_writer.h
@@ -117,6 +117,7 @@
Elf_Addr method_address = base_address + mi->code_address;
PositionInfos dex2line_map;
+ DCHECK(mi->dex_file != nullptr);
const DexFile* dex = mi->dex_file;
if (!dex->DecodeDebugPositionInfo(mi->code_item, PositionInfoCallback, &dex2line_map)) {
continue;
diff --git a/compiler/debug/elf_debug_writer.cc b/compiler/debug/elf_debug_writer.cc
index 0ca7370..4dd8024 100644
--- a/compiler/debug/elf_debug_writer.cc
+++ b/compiler/debug/elf_debug_writer.cc
@@ -39,35 +39,31 @@
const ArrayRef<const MethodDebugInfo>& method_infos,
dwarf::CFIFormat cfi_format,
bool write_oat_patches) {
- // Add methods to .symtab.
+ // Write .strtab and .symtab.
WriteDebugSymbols(builder, method_infos, true /* with_signature */);
- // Generate CFI (stack unwinding information).
- WriteCFISection(builder, method_infos, cfi_format, write_oat_patches);
- // Write DWARF .debug_* sections.
- WriteDebugSections(builder, method_infos, write_oat_patches);
-}
-template<typename ElfTypes>
-static void WriteDebugSections(ElfBuilder<ElfTypes>* builder,
- const ArrayRef<const MethodDebugInfo>& method_infos,
- bool write_oat_patches) {
+ // Write .debug_frame.
+ WriteCFISection(builder, method_infos, cfi_format, write_oat_patches);
+
// Group the methods into compilation units based on source file.
std::vector<ElfCompilationUnit> compilation_units;
const char* last_source_file = nullptr;
for (const MethodDebugInfo& mi : method_infos) {
- auto& dex_class_def = mi.dex_file->GetClassDef(mi.class_def_index);
- const char* source_file = mi.dex_file->GetSourceFile(dex_class_def);
- if (compilation_units.empty() || source_file != last_source_file) {
- compilation_units.push_back(ElfCompilationUnit());
+ if (mi.dex_file != nullptr) {
+ auto& dex_class_def = mi.dex_file->GetClassDef(mi.class_def_index);
+ const char* source_file = mi.dex_file->GetSourceFile(dex_class_def);
+ if (compilation_units.empty() || source_file != last_source_file) {
+ compilation_units.push_back(ElfCompilationUnit());
+ }
+ ElfCompilationUnit& cu = compilation_units.back();
+ cu.methods.push_back(&mi);
+ // All methods must have the same addressing mode otherwise the min/max below does not work.
+ DCHECK_EQ(cu.methods.front()->is_code_address_text_relative, mi.is_code_address_text_relative);
+ cu.is_code_address_text_relative = mi.is_code_address_text_relative;
+ cu.code_address = std::min(cu.code_address, mi.code_address);
+ cu.code_end = std::max(cu.code_end, mi.code_address + mi.code_size);
+ last_source_file = source_file;
}
- ElfCompilationUnit& cu = compilation_units.back();
- cu.methods.push_back(&mi);
- // All methods must have the same addressing mode otherwise the min/max below does not work.
- DCHECK_EQ(cu.methods.front()->is_code_address_text_relative, mi.is_code_address_text_relative);
- cu.is_code_address_text_relative = mi.is_code_address_text_relative;
- cu.code_address = std::min(cu.code_address, mi.code_address);
- cu.code_end = std::max(cu.code_end, mi.code_address + mi.code_size);
- last_source_file = source_file;
}
// Write .debug_line section.
@@ -185,6 +181,31 @@
}
}
+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 7f5d24d..736370e 100644
--- a/compiler/debug/elf_debug_writer.h
+++ b/compiler/debug/elf_debug_writer.h
@@ -17,6 +17,8 @@
#ifndef ART_COMPILER_DEBUG_ELF_DEBUG_WRITER_H_
#define ART_COMPILER_DEBUG_ELF_DEBUG_WRITER_H_
+#include <vector>
+
#include "base/macros.h"
#include "base/mutex.h"
#include "debug/dwarf/dwarf_constants.h"
@@ -24,6 +26,7 @@
#include "utils/array_ref.h"
namespace art {
+class OatHeader;
namespace mirror {
class Class;
}
@@ -55,6 +58,8 @@
const ArrayRef<mirror::Class*>& types)
SHARED_REQUIRES(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 0a199da..045eddd 100644
--- a/compiler/debug/elf_symtab_writer.h
+++ b/compiler/debug/elf_symtab_writer.h
@@ -39,7 +39,7 @@
static void WriteDebugSymbols(ElfBuilder<ElfTypes>* builder,
const ArrayRef<const MethodDebugInfo>& method_infos,
bool with_signature) {
- bool generated_mapping_symbol = false;
+ uint64_t mapping_symbol_address = std::numeric_limits<uint64_t>::max();
auto* strtab = builder->GetStrTab();
auto* symtab = builder->GetSymTab();
@@ -64,12 +64,20 @@
if (info.deduped) {
continue; // Add symbol only for the first instance.
}
- std::string name = PrettyMethod(info.dex_method_index, *info.dex_file, with_signature);
- if (deduped_addresses.find(info.code_address) != deduped_addresses.end()) {
- name += " [DEDUPED]";
+ size_t name_offset;
+ if (info.trampoline_name != nullptr) {
+ name_offset = strtab->Write(info.trampoline_name);
+ } else {
+ DCHECK(info.dex_file != nullptr);
+ std::string name = PrettyMethod(info.dex_method_index, *info.dex_file, with_signature);
+ if (deduped_addresses.find(info.code_address) != deduped_addresses.end()) {
+ name += " [DEDUPED]";
+ }
+ // If we write method names without signature, we might see the same name multiple times.
+ name_offset = (name == last_name ? last_name_offset : strtab->Write(name));
+ last_name = std::move(name);
+ last_name_offset = name_offset;
}
- // If we write method names without signature, we might see the same name multiple times.
- size_t name_offset = (name == last_name ? last_name_offset : strtab->Write(name));
const auto* text = info.is_code_address_text_relative ? builder->GetText() : nullptr;
uint64_t address = info.code_address + (text != nullptr ? text->GetAddress() : 0);
@@ -82,14 +90,11 @@
// 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 (info.isa == kThumb2) {
- if (!generated_mapping_symbol || !kGenerateSingleArmMappingSymbol) {
+ if (address < mapping_symbol_address || !kGenerateSingleArmMappingSymbol) {
symtab->Add(strtab->Write("$t"), text, address & ~1, 0, STB_LOCAL, STT_NOTYPE);
- generated_mapping_symbol = true;
+ mapping_symbol_address = address;
}
}
-
- last_name = std::move(name);
- last_name_offset = name_offset;
}
strtab->End();
diff --git a/compiler/debug/method_debug_info.h b/compiler/debug/method_debug_info.h
index 1ccc705..ed1da2c 100644
--- a/compiler/debug/method_debug_info.h
+++ b/compiler/debug/method_debug_info.h
@@ -24,7 +24,8 @@
namespace debug {
struct MethodDebugInfo {
- const DexFile* dex_file;
+ const char* trampoline_name;
+ const DexFile* dex_file; // Native methods (trampolines) do not reference dex file.
size_t class_def_index;
uint32_t dex_method_index;
uint32_t access_flags;
@@ -37,7 +38,7 @@
uint64_t code_address;
uint32_t code_size;
uint32_t frame_size_in_bytes;
- const uint8_t* code_info;
+ const void* code_info;
ArrayRef<const uint8_t> cfi;
};
diff --git a/compiler/oat_writer.cc b/compiler/oat_writer.cc
index 2b511fc..c2f19c9 100644
--- a/compiler/oat_writer.cc
+++ b/compiler/oat_writer.cc
@@ -811,7 +811,8 @@
if (compiler_options.GenerateAnyDebugInfo() && 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 = debug::MethodDebugInfo();
+ info.trampoline_name = nullptr;
info.dex_file = dex_file_;
info.class_def_index = class_def_index_;
info.dex_method_index = it.GetMemberIndex();
diff --git a/compiler/oat_writer.h b/compiler/oat_writer.h
index 74aab4e..5e7a4a3 100644
--- a/compiler/oat_writer.h
+++ b/compiler/oat_writer.h
@@ -202,6 +202,10 @@
~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 cc1a806..7a82063 100644
--- a/compiler/optimizing/optimizing_compiler.cc
+++ b/compiler/optimizing/optimizing_compiler.cc
@@ -919,7 +919,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 = debug::MethodDebugInfo();
+ info.trampoline_name = nullptr;
info.dex_file = dex_file;
info.class_def_index = class_def_idx;
info.dex_method_index = method_idx;