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/debug_info.h b/compiler/debug/debug_info.h
new file mode 100644
index 0000000..04c6991
--- /dev/null
+++ b/compiler/debug/debug_info.h
@@ -0,0 +1,46 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef ART_COMPILER_DEBUG_DEBUG_INFO_H_
+#define ART_COMPILER_DEBUG_DEBUG_INFO_H_
+
+#include <map>
+
+#include "base/array_ref.h"
+#include "method_debug_info.h"
+
+namespace art {
+class DexFile;
+
+namespace debug {
+
+// References inputs for all debug information which can be written into the ELF file.
+struct DebugInfo {
+  // Describes compiled code in the .text section.
+  ArrayRef<const MethodDebugInfo> compiled_methods;
+
+  // Describes dex-files in the .dex section.
+  std::map<uint32_t, const DexFile*> dex_files;  // Offset in section -> dex file content.
+
+  bool Empty() const {
+    return compiled_methods.empty() && dex_files.empty();
+  }
+};
+
+}  // namespace debug
+}  // namespace art
+
+#endif  // ART_COMPILER_DEBUG_DEBUG_INFO_H_
diff --git a/compiler/debug/elf_debug_writer.cc b/compiler/debug/elf_debug_writer.cc
index a626729..bb2a214 100644
--- a/compiler/debug/elf_debug_writer.cc
+++ b/compiler/debug/elf_debug_writer.cc
@@ -38,18 +38,18 @@
 
 template <typename ElfTypes>
 void WriteDebugInfo(linker::ElfBuilder<ElfTypes>* builder,
-                    const ArrayRef<const MethodDebugInfo>& method_infos,
+                    const DebugInfo& debug_info,
                     dwarf::CFIFormat cfi_format,
                     bool write_oat_patches) {
   // Write .strtab and .symtab.
-  WriteDebugSymbols(builder, method_infos, true /* with_signature */);
+  WriteDebugSymbols(builder, false /* mini-debug-info */, debug_info);
 
   // Write .debug_frame.
-  WriteCFISection(builder, method_infos, cfi_format, write_oat_patches);
+  WriteCFISection(builder, debug_info.compiled_methods, cfi_format, write_oat_patches);
 
   // Group the methods into compilation units based on class.
   std::unordered_map<const DexFile::ClassDef*, ElfCompilationUnit> class_to_compilation_unit;
-  for (const MethodDebugInfo& mi : method_infos) {
+  for (const MethodDebugInfo& mi : debug_info.compiled_methods) {
     if (mi.dex_file != nullptr) {
       auto& dex_class_def = mi.dex_file->GetClassDef(mi.class_def_index);
       ElfCompilationUnit& cu = class_to_compilation_unit[&dex_class_def];
@@ -108,21 +108,27 @@
 std::vector<uint8_t> MakeMiniDebugInfo(
     InstructionSet isa,
     const InstructionSetFeatures* features,
-    uint64_t text_address,
-    size_t text_size,
-    const ArrayRef<const MethodDebugInfo>& method_infos) {
+    uint64_t text_section_address,
+    size_t text_section_size,
+    uint64_t dex_section_address,
+    size_t dex_section_size,
+    const DebugInfo& debug_info) {
   if (Is64BitInstructionSet(isa)) {
     return MakeMiniDebugInfoInternal<ElfTypes64>(isa,
                                                  features,
-                                                 text_address,
-                                                 text_size,
-                                                 method_infos);
+                                                 text_section_address,
+                                                 text_section_size,
+                                                 dex_section_address,
+                                                 dex_section_size,
+                                                 debug_info);
   } else {
     return MakeMiniDebugInfoInternal<ElfTypes32>(isa,
                                                  features,
-                                                 text_address,
-                                                 text_size,
-                                                 method_infos);
+                                                 text_section_address,
+                                                 text_section_size,
+                                                 dex_section_address,
+                                                 dex_section_size,
+                                                 debug_info);
   }
 }
 
@@ -133,7 +139,8 @@
     bool mini_debug_info,
     const MethodDebugInfo& mi) {
   CHECK_EQ(mi.is_code_address_text_relative, false);
-  ArrayRef<const MethodDebugInfo> method_infos(&mi, 1);
+  DebugInfo debug_info{};
+  debug_info.compiled_methods = ArrayRef<const debug::MethodDebugInfo>(&mi, 1);
   std::vector<uint8_t> buffer;
   buffer.reserve(KB);
   linker::VectorOutputStream out("Debug ELF file", &buffer);
@@ -146,12 +153,14 @@
                                                  features,
                                                  mi.code_address,
                                                  mi.code_size,
-                                                 method_infos);
+                                                 /* dex_section_address */ 0,
+                                                 /* dex_section_size */ 0,
+                                                 debug_info);
     builder->WriteSection(".gnu_debugdata", &mdi);
   } else {
     builder->GetText()->AllocateVirtualMemory(mi.code_address, mi.code_size);
     WriteDebugInfo(builder.get(),
-                   method_infos,
+                   debug_info,
                    dwarf::DW_DEBUG_FRAME_FORMAT,
                    false /* write_oat_patches */);
   }
@@ -209,12 +218,12 @@
 // Explicit instantiations
 template void WriteDebugInfo<ElfTypes32>(
     linker::ElfBuilder<ElfTypes32>* builder,
-    const ArrayRef<const MethodDebugInfo>& method_infos,
+    const DebugInfo& debug_info,
     dwarf::CFIFormat cfi_format,
     bool write_oat_patches);
 template void WriteDebugInfo<ElfTypes64>(
     linker::ElfBuilder<ElfTypes64>* builder,
-    const ArrayRef<const MethodDebugInfo>& method_infos,
+    const DebugInfo& debug_info,
     dwarf::CFIFormat cfi_format,
     bool write_oat_patches);
 
diff --git a/compiler/debug/elf_debug_writer.h b/compiler/debug/elf_debug_writer.h
index a47bf07..8ad0c42 100644
--- a/compiler/debug/elf_debug_writer.h
+++ b/compiler/debug/elf_debug_writer.h
@@ -23,6 +23,7 @@
 #include "base/macros.h"
 #include "base/mutex.h"
 #include "debug/dwarf/dwarf_constants.h"
+#include "debug/debug_info.h"
 #include "linker/elf_builder.h"
 
 namespace art {
@@ -36,7 +37,7 @@
 template <typename ElfTypes>
 void WriteDebugInfo(
     linker::ElfBuilder<ElfTypes>* builder,
-    const ArrayRef<const MethodDebugInfo>& method_infos,
+    const DebugInfo& debug_info,
     dwarf::CFIFormat cfi_format,
     bool write_oat_patches);
 
@@ -45,7 +46,9 @@
     const InstructionSetFeatures* features,
     uint64_t text_section_address,
     size_t text_section_size,
-    const ArrayRef<const MethodDebugInfo>& method_infos);
+    uint64_t dex_section_address,
+    size_t dex_section_size,
+    const DebugInfo& debug_info);
 
 std::vector<uint8_t> MakeElfFileForJIT(
     InstructionSet isa,
diff --git a/compiler/debug/elf_gnu_debugdata_writer.h b/compiler/debug/elf_gnu_debugdata_writer.h
index 78b8e27..a88c5cb 100644
--- a/compiler/debug/elf_gnu_debugdata_writer.h
+++ b/compiler/debug/elf_gnu_debugdata_writer.h
@@ -82,18 +82,23 @@
     const InstructionSetFeatures* features,
     typename ElfTypes::Addr text_section_address,
     size_t text_section_size,
-    const ArrayRef<const MethodDebugInfo>& method_infos) {
+    typename ElfTypes::Addr dex_section_address,
+    size_t dex_section_size,
+    const DebugInfo& debug_info) {
   std::vector<uint8_t> buffer;
   buffer.reserve(KB);
   linker::VectorOutputStream out("Mini-debug-info ELF file", &buffer);
   std::unique_ptr<linker::ElfBuilder<ElfTypes>> builder(
       new linker::ElfBuilder<ElfTypes>(isa, features, &out));
   builder->Start(false /* write_program_headers */);
-  // Mirror .text as NOBITS section since the added symbols will reference it.
+  // Mirror ELF sections as NOBITS since the added symbols will reference them.
   builder->GetText()->AllocateVirtualMemory(text_section_address, text_section_size);
-  WriteDebugSymbols(builder.get(), method_infos, false /* with_signature */);
+  if (dex_section_size != 0) {
+    builder->GetDex()->AllocateVirtualMemory(dex_section_address, dex_section_size);
+  }
+  WriteDebugSymbols(builder.get(), true /* mini-debug-info */, debug_info);
   WriteCFISection(builder.get(),
-                  method_infos,
+                  debug_info.compiled_methods,
                   dwarf::DW_DEBUG_FRAME_FORMAT,
                   false /* write_oat_paches */);
   builder->End();
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
diff --git a/compiler/linker/elf_builder.h b/compiler/linker/elf_builder.h
index 5262ab6..3145497 100644
--- a/compiler/linker/elf_builder.h
+++ b/compiler/linker/elf_builder.h
@@ -196,6 +196,11 @@
       return section_index_;
     }
 
+    // Returns true if this section has been added.
+    bool Exists() const {
+      return section_index_ != 0;
+    }
+
    private:
     // Add this section to the list of generated ELF sections (if not there already).
     // It also ensures the alignment is sufficient to generate valid program headers,
@@ -304,42 +309,46 @@
                   /* info */ 0,
                   align,
                   /* entsize */ 0),
-          current_offset_(0) {
+          current_offset_(0),
+          last_offset_(0) {
     }
 
     Elf_Word Write(const std::string& name) {
       if (current_offset_ == 0) {
         DCHECK(name.empty());
+      } else if (name == last_name_) {
+        return last_offset_;  // Very simple string de-duplication.
       }
-      Elf_Word offset = current_offset_;
+      last_name_ = name;
+      last_offset_ = current_offset_;
       this->WriteFully(name.c_str(), name.length() + 1);
       current_offset_ += name.length() + 1;
-      return offset;
+      return last_offset_;
     }
 
    private:
     Elf_Word current_offset_;
+    std::string last_name_;
+    Elf_Word last_offset_;
   };
 
   // Writer of .dynsym and .symtab sections.
-  class SymbolSection FINAL : public CachedSection {
+  class SymbolSection FINAL : public Section {
    public:
     SymbolSection(ElfBuilder<ElfTypes>* owner,
                   const std::string& name,
                   Elf_Word type,
                   Elf_Word flags,
                   Section* strtab)
-        : CachedSection(owner,
-                        name,
-                        type,
-                        flags,
-                        strtab,
-                        /* info */ 0,
-                        sizeof(Elf_Off),
-                        sizeof(Elf_Sym)) {
-      // The symbol table always has to start with NULL symbol.
-      Elf_Sym null_symbol = Elf_Sym();
-      CachedSection::Add(&null_symbol, sizeof(null_symbol));
+        : Section(owner,
+                  name,
+                  type,
+                  flags,
+                  strtab,
+                  /* info */ 0,
+                  sizeof(Elf_Off),
+                  sizeof(Elf_Sym)) {
+      syms_.push_back(Elf_Sym());  // The symbol table always has to start with NULL symbol.
     }
 
     // Buffer symbol for this section.  It will be written later.
@@ -362,6 +371,7 @@
       Add(name, section_index, addr, size, binding, type);
     }
 
+    // Buffer symbol for this section.  It will be written later.
     void Add(Elf_Word name,
              Elf_Word section_index,
              Elf_Addr addr,
@@ -375,8 +385,19 @@
       sym.st_other = 0;
       sym.st_shndx = section_index;
       sym.st_info = (binding << 4) + (type & 0xf);
-      CachedSection::Add(&sym, sizeof(sym));
+      syms_.push_back(sym);
     }
+
+    Elf_Word GetCacheSize() { return syms_.size() * sizeof(Elf_Sym); }
+
+    void WriteCachedSection() {
+      this->Start();
+      this->WriteFully(syms_.data(), syms_.size() * sizeof(Elf_Sym));
+      this->End();
+    }
+
+   private:
+    std::vector<Elf_Sym> syms_;  // Buffered/cached content of the whole section.
   };
 
   class AbiflagsSection FINAL : public Section {