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(¤t_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(¤t_abbrev_, name);
+ EncodeUnsignedLeb128(¤t_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_