Generate debug symbols for interpreted methods.
Add .symtab symbols for method bytecodes in the dex section
(only if the full --generate-debug-info is enabled for now).
Test: m test-art-host-gtest
Test: testrunner.py -b --host --optimizing
Change-Id: Ie90034c921484bc4ff27c5458da78690b629dd0b
diff --git a/compiler/debug/elf_symtab_writer.h b/compiler/debug/elf_symtab_writer.h
index 57e010f..95a0b4f 100644
--- a/compiler/debug/elf_symtab_writer.h
+++ b/compiler/debug/elf_symtab_writer.h
@@ -17,9 +17,13 @@
#ifndef ART_COMPILER_DEBUG_ELF_SYMTAB_WRITER_H_
#define ART_COMPILER_DEBUG_ELF_SYMTAB_WRITER_H_
+#include <map>
#include <unordered_set>
+#include "debug/debug_info.h"
#include "debug/method_debug_info.h"
+#include "dex/dex_file-inl.h"
+#include "dex/code_item_accessors.h"
#include "linker/elf_builder.h"
#include "utils.h"
@@ -35,22 +39,26 @@
// one symbol which marks the whole .text section as code.
constexpr bool kGenerateSingleArmMappingSymbol = true;
+// Magic name for .symtab symbols which enumerate dex files used
+// by this ELF file (currently mmapped inside the .dex section).
+constexpr const char* kDexFileSymbolName = "$dexfile";
+
template <typename ElfTypes>
static void WriteDebugSymbols(linker::ElfBuilder<ElfTypes>* builder,
- const ArrayRef<const MethodDebugInfo>& method_infos,
- bool with_signature) {
+ bool mini_debug_info,
+ const DebugInfo& debug_info) {
uint64_t mapping_symbol_address = std::numeric_limits<uint64_t>::max();
auto* strtab = builder->GetStrTab();
auto* symtab = builder->GetSymTab();
- if (method_infos.empty()) {
+ if (debug_info.Empty()) {
return;
}
// Find all addresses which contain deduped methods.
// The first instance of method is not marked deduped_, but the rest is.
std::unordered_set<uint64_t> deduped_addresses;
- for (const MethodDebugInfo& info : method_infos) {
+ for (const MethodDebugInfo& info : debug_info.compiled_methods) {
if (info.deduped) {
deduped_addresses.insert(info.code_address);
}
@@ -58,9 +66,8 @@
strtab->Start();
strtab->Write(""); // strtab should start with empty string.
- std::string last_name;
- size_t last_name_offset = 0;
- for (const MethodDebugInfo& info : method_infos) {
+ // Add symbols for compiled methods.
+ for (const MethodDebugInfo& info : debug_info.compiled_methods) {
if (info.deduped) {
continue; // Add symbol only for the first instance.
}
@@ -69,14 +76,11 @@
name_offset = strtab->Write(info.trampoline_name);
} else {
DCHECK(info.dex_file != nullptr);
- std::string name = info.dex_file->PrettyMethod(info.dex_method_index, with_signature);
+ std::string name = info.dex_file->PrettyMethod(info.dex_method_index, !mini_debug_info);
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;
+ name_offset = strtab->Write(name);
}
const auto* text = builder->GetText();
@@ -97,13 +101,46 @@
}
}
}
+ // Add symbols for interpreted methods (with address range of the method's bytecode).
+ if (!debug_info.dex_files.empty() && builder->GetDex()->Exists()) {
+ auto dex = builder->GetDex();
+ for (auto it : debug_info.dex_files) {
+ uint64_t dex_address = dex->GetAddress() + it.first /* offset within the section */;
+ const DexFile* dex_file = it.second;
+ symtab->Add(strtab->Write(kDexFileSymbolName), dex, dex_address, 0, STB_LOCAL, STT_NOTYPE);
+ if (mini_debug_info) {
+ continue; // Don't add interpreter method names to mini-debug-info for now.
+ }
+ for (uint32_t i = 0; i < dex_file->NumClassDefs(); ++i) {
+ const DexFile::ClassDef& class_def = dex_file->GetClassDef(i);
+ const uint8_t* class_data = dex_file->GetClassData(class_def);
+ if (class_data == nullptr) {
+ continue;
+ }
+ for (ClassDataItemIterator item(*dex_file, class_data); item.HasNext(); item.Next()) {
+ if (!item.IsAtMethod()) {
+ continue;
+ }
+ const DexFile::CodeItem* code_item = item.GetMethodCodeItem();
+ if (code_item == nullptr) {
+ continue;
+ }
+ CodeItemInstructionAccessor code(*dex_file, code_item);
+ DCHECK(code.HasCodeItem());
+ std::string name = dex_file->PrettyMethod(item.GetMemberIndex(), !mini_debug_info);
+ size_t name_offset = strtab->Write(name);
+ uint64_t offset = reinterpret_cast<const uint8_t*>(code.Insns()) - dex_file->Begin();
+ uint64_t address = dex_address + offset;
+ size_t size = code.InsnsSizeInCodeUnits() * sizeof(uint16_t);
+ symtab->Add(name_offset, dex, address, size, STB_GLOBAL, STT_FUNC);
+ }
+ }
+ }
+ }
strtab->End();
// Symbols are buffered and written after names (because they are smaller).
- // We could also do two passes in this function to avoid the buffering.
- symtab->Start();
- symtab->Write();
- symtab->End();
+ symtab->WriteCachedSection();
}
} // namespace debug