/* * 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 #include #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& 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 > class DebugInfoEntryWriter FINAL : private Writer { 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); patch_locations_.push_back(this->data()->size()); 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* 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_; } const std::vector& GetPatchLocations() const { return patch_locations_; } using Writer::data; DebugInfoEntryWriter(bool is64bitArch, std::vector* debug_abbrev, const Allocator& alloc = Allocator()) : Writer(&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& 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 debug_abbrev_; std::vector current_abbrev_; std::unordered_map, int, FNVHash > abbrev_codes_; // Fields for writing of debugging information entries. std::vector 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; std::vector patch_locations_; }; } // namespace dwarf } // namespace art #endif // ART_COMPILER_DWARF_DEBUG_INFO_ENTRY_WRITER_H_