Extend the DWARF library to support .debug_info section.

Change-Id: I9916abd8db227e7a73a3311294e675be5222a709
diff --git a/compiler/dwarf/debug_info_entry_writer.h b/compiler/dwarf/debug_info_entry_writer.h
new file mode 100644
index 0000000..c0350b6
--- /dev/null
+++ b/compiler/dwarf/debug_info_entry_writer.h
@@ -0,0 +1,248 @@
+/*
+ * Copyright (C) 2014 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_DWARF_DEBUG_INFO_ENTRY_WRITER_H_
+#define ART_COMPILER_DWARF_DEBUG_INFO_ENTRY_WRITER_H_
+
+#include <unordered_map>
+
+#include "dwarf.h"
+#include "leb128.h"
+#include "writer.h"
+
+namespace art {
+namespace dwarf {
+
+// 32-bit FNV-1a hash function which we use to find duplicate abbreviations.
+// See http://en.wikipedia.org/wiki/Fowler%E2%80%93Noll%E2%80%93Vo_hash_function
+template< typename Allocator >
+struct FNVHash {
+  size_t operator()(const std::vector<uint8_t, Allocator>& v) const {
+    uint32_t hash = 2166136261u;
+    for (size_t i = 0; i < v.size(); i++) {
+      hash = (hash ^ v[i]) * 16777619u;
+    }
+    return hash;
+  }
+};
+
+/*
+ * Writer for debug information entries (DIE).
+ * It also handles generation of abbreviations.
+ *
+ * Usage:
+ *   StartTag(DW_TAG_compile_unit, DW_CHILDREN_yes);
+ *     WriteStrp(DW_AT_producer, "Compiler name", debug_str);
+ *     StartTag(DW_TAG_subprogram, DW_CHILDREN_no);
+ *       WriteStrp(DW_AT_name, "Foo", debug_str);
+ *     EndTag();
+ *   EndTag();
+ */
+template< typename Allocator = std::allocator<uint8_t> >
+class DebugInfoEntryWriter FINAL : private Writer<Allocator> {
+ public:
+  // Start debugging information entry.
+  void StartTag(Tag tag, Children children) {
+    DCHECK(has_children) << "This tag can not have nested tags";
+    if (inside_entry_) {
+      // Write abbrev code for the previous entry.
+      this->UpdateUleb128(abbrev_code_offset_, EndAbbrev());
+      inside_entry_ = false;
+    }
+    StartAbbrev(tag, children);
+    // Abbrev code placeholder of sufficient size.
+    abbrev_code_offset_ = this->data()->size();
+    this->PushUleb128(NextAbbrevCode());
+    depth_++;
+    inside_entry_ = true;
+    has_children = (children == DW_CHILDREN_yes);
+  }
+
+  // End debugging information entry.
+  void EndTag() {
+    DCHECK_GT(depth_, 0);
+    if (inside_entry_) {
+      // Write abbrev code for this tag.
+      this->UpdateUleb128(abbrev_code_offset_, EndAbbrev());
+      inside_entry_ = false;
+    }
+    if (has_children) {
+      this->PushUint8(0);  // End of children.
+    }
+    depth_--;
+    has_children = true;  // Parent tag obviously has children.
+  }
+
+  void WriteAddr(Attribute attrib, uint64_t value) {
+    AddAbbrevAttribute(attrib, DW_FORM_addr);
+    if (is64bit_) {
+      this->PushUint64(value);
+    } else {
+      this->PushUint32(value);
+    }
+  }
+
+  void WriteBlock(Attribute attrib, const void* ptr, int size) {
+    AddAbbrevAttribute(attrib, DW_FORM_block);
+    this->PushUleb128(size);
+    this->PushData(ptr, size);
+  }
+
+  void WriteData1(Attribute attrib, uint8_t value) {
+    AddAbbrevAttribute(attrib, DW_FORM_data1);
+    this->PushUint8(value);
+  }
+
+  void WriteData2(Attribute attrib, uint16_t value) {
+    AddAbbrevAttribute(attrib, DW_FORM_data2);
+    this->PushUint16(value);
+  }
+
+  void WriteData4(Attribute attrib, uint32_t value) {
+    AddAbbrevAttribute(attrib, DW_FORM_data4);
+    this->PushUint32(value);
+  }
+
+  void WriteData8(Attribute attrib, uint64_t value) {
+    AddAbbrevAttribute(attrib, DW_FORM_data8);
+    this->PushUint64(value);
+  }
+
+  void WriteSdata(Attribute attrib, int value) {
+    AddAbbrevAttribute(attrib, DW_FORM_sdata);
+    this->PushSleb128(value);
+  }
+
+  void WriteUdata(Attribute attrib, int value) {
+    AddAbbrevAttribute(attrib, DW_FORM_udata);
+    this->PushUleb128(value);
+  }
+
+  void WriteUdata(Attribute attrib, uint32_t value) {
+    AddAbbrevAttribute(attrib, DW_FORM_udata);
+    this->PushUleb128(value);
+  }
+
+  void WriteFlag(Attribute attrib, bool value) {
+    AddAbbrevAttribute(attrib, DW_FORM_flag);
+    this->PushUint8(value ? 1 : 0);
+  }
+
+  void WriteRef4(Attribute attrib, int cu_offset) {
+    AddAbbrevAttribute(attrib, DW_FORM_ref4);
+    this->PushUint32(cu_offset);
+  }
+
+  void WriteRef(Attribute attrib, int cu_offset) {
+    AddAbbrevAttribute(attrib, DW_FORM_ref_udata);
+    this->PushUleb128(cu_offset);
+  }
+
+  void WriteString(Attribute attrib, const char* value) {
+    AddAbbrevAttribute(attrib, DW_FORM_string);
+    this->PushString(value);
+  }
+
+  void WriteStrp(Attribute attrib, int address) {
+    AddAbbrevAttribute(attrib, DW_FORM_strp);
+    this->PushUint32(address);
+  }
+
+  void WriteStrp(Attribute attrib, const char* value, std::vector<uint8_t>* debug_str) {
+    AddAbbrevAttribute(attrib, DW_FORM_strp);
+    int address = debug_str->size();
+    debug_str->insert(debug_str->end(), value, value + strlen(value) + 1);
+    this->PushUint32(address);
+  }
+
+  bool is64bit() const { return is64bit_; }
+
+  using Writer<Allocator>::data;
+
+  DebugInfoEntryWriter(bool is64bitArch,
+                       std::vector<uint8_t, Allocator>* debug_abbrev,
+                       const Allocator& alloc = Allocator())
+      : Writer<Allocator>(&entries_),
+        debug_abbrev_(debug_abbrev),
+        current_abbrev_(alloc),
+        abbrev_codes_(alloc),
+        entries_(alloc),
+        is64bit_(is64bitArch) {
+    debug_abbrev_.PushUint8(0);  // Add abbrev table terminator.
+  }
+
+  ~DebugInfoEntryWriter() {
+    DCHECK_EQ(depth_, 0);
+  }
+
+ private:
+  // Start abbreviation declaration.
+  void StartAbbrev(Tag tag, Children children) {
+    DCHECK(!inside_entry_);
+    current_abbrev_.clear();
+    EncodeUnsignedLeb128(&current_abbrev_, tag);
+    current_abbrev_.push_back(children);
+  }
+
+  // Add attribute specification.
+  void AddAbbrevAttribute(Attribute name, Form type) {
+    DCHECK(inside_entry_) << "Call StartTag before adding attributes.";
+    EncodeUnsignedLeb128(&current_abbrev_, name);
+    EncodeUnsignedLeb128(&current_abbrev_, type);
+  }
+
+  int NextAbbrevCode() {
+    return 1 + abbrev_codes_.size();
+  }
+
+  // End abbreviation declaration and return its code.
+  int EndAbbrev() {
+    DCHECK(inside_entry_);
+    auto it = abbrev_codes_.insert(std::make_pair(std::move(current_abbrev_),
+                                                  NextAbbrevCode()));
+    int abbrev_code = it.first->second;
+    if (UNLIKELY(it.second)) {  // Inserted new entry.
+      const std::vector<uint8_t, Allocator>& abbrev = it.first->first;
+      debug_abbrev_.Pop();  // Remove abbrev table terminator.
+      debug_abbrev_.PushUleb128(abbrev_code);
+      debug_abbrev_.PushData(abbrev.data(), abbrev.size());
+      debug_abbrev_.PushUint8(0);  // Attribute list end.
+      debug_abbrev_.PushUint8(0);  // Attribute list end.
+      debug_abbrev_.PushUint8(0);  // Add abbrev table terminator.
+    }
+    return abbrev_code;
+  }
+
+ private:
+  // Fields for writing and deduplication of abbrevs.
+  Writer<Allocator> debug_abbrev_;
+  std::vector<uint8_t, Allocator> current_abbrev_;
+  std::unordered_map<std::vector<uint8_t, Allocator>, int,
+                     FNVHash<Allocator> > abbrev_codes_;
+
+  // Fields for writing of debugging information entries.
+  std::vector<uint8_t, Allocator> entries_;
+  bool is64bit_;
+  int depth_ = 0;
+  size_t abbrev_code_offset_ = 0;  // Location to patch once we know the code.
+  bool inside_entry_ = false;  // Entry ends at first child (if any).
+  bool has_children = true;
+};
+
+}  // namespace dwarf
+}  // namespace art
+
+#endif  // ART_COMPILER_DWARF_DEBUG_INFO_ENTRY_WRITER_H_