1 /* 2 * Copyright (C) 2014 The Android Open Source Project 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 17 #ifndef ART_COMPILER_DWARF_DEBUG_INFO_ENTRY_WRITER_H_ 18 #define ART_COMPILER_DWARF_DEBUG_INFO_ENTRY_WRITER_H_ 19 20 #include <cstdint> 21 #include <unordered_map> 22 23 #include "dwarf/dwarf_constants.h" 24 #include "dwarf/writer.h" 25 #include "leb128.h" 26 27 namespace art { 28 namespace dwarf { 29 30 // 32-bit FNV-1a hash function which we use to find duplicate abbreviations. 31 // See http://en.wikipedia.org/wiki/Fowler%E2%80%93Noll%E2%80%93Vo_hash_function 32 template< typename Allocator > 33 struct FNVHash { operatorFNVHash34 size_t operator()(const std::vector<uint8_t, Allocator>& v) const { 35 uint32_t hash = 2166136261u; 36 for (size_t i = 0; i < v.size(); i++) { 37 hash = (hash ^ v[i]) * 16777619u; 38 } 39 return hash; 40 } 41 }; 42 43 /* 44 * Writer for debug information entries (DIE). 45 * It also handles generation of abbreviations. 46 * 47 * Usage: 48 * StartTag(DW_TAG_compile_unit, DW_CHILDREN_yes); 49 * WriteStrp(DW_AT_producer, "Compiler name", debug_str); 50 * StartTag(DW_TAG_subprogram, DW_CHILDREN_no); 51 * WriteStrp(DW_AT_name, "Foo", debug_str); 52 * EndTag(); 53 * EndTag(); 54 */ 55 template< typename Allocator = std::allocator<uint8_t> > 56 class DebugInfoEntryWriter FINAL : private Writer<Allocator> { 57 public: 58 // Start debugging information entry. StartTag(Tag tag,Children children)59 void StartTag(Tag tag, Children children) { 60 DCHECK(has_children) << "This tag can not have nested tags"; 61 if (inside_entry_) { 62 // Write abbrev code for the previous entry. 63 this->UpdateUleb128(abbrev_code_offset_, EndAbbrev()); 64 inside_entry_ = false; 65 } 66 StartAbbrev(tag, children); 67 // Abbrev code placeholder of sufficient size. 68 abbrev_code_offset_ = this->data()->size(); 69 this->PushUleb128(NextAbbrevCode()); 70 depth_++; 71 inside_entry_ = true; 72 has_children = (children == DW_CHILDREN_yes); 73 } 74 75 // End debugging information entry. EndTag()76 void EndTag() { 77 DCHECK_GT(depth_, 0); 78 if (inside_entry_) { 79 // Write abbrev code for this tag. 80 this->UpdateUleb128(abbrev_code_offset_, EndAbbrev()); 81 inside_entry_ = false; 82 } 83 if (has_children) { 84 this->PushUint8(0); // End of children. 85 } 86 depth_--; 87 has_children = true; // Parent tag obviously has children. 88 } 89 WriteAddr(Attribute attrib,uint64_t value)90 void WriteAddr(Attribute attrib, uint64_t value) { 91 AddAbbrevAttribute(attrib, DW_FORM_addr); 92 patch_locations_.push_back(this->data()->size()); 93 if (is64bit_) { 94 this->PushUint64(value); 95 } else { 96 this->PushUint32(value); 97 } 98 } 99 WriteBlock(Attribute attrib,const void * ptr,int size)100 void WriteBlock(Attribute attrib, const void* ptr, int size) { 101 AddAbbrevAttribute(attrib, DW_FORM_block); 102 this->PushUleb128(size); 103 this->PushData(ptr, size); 104 } 105 WriteData1(Attribute attrib,uint8_t value)106 void WriteData1(Attribute attrib, uint8_t value) { 107 AddAbbrevAttribute(attrib, DW_FORM_data1); 108 this->PushUint8(value); 109 } 110 WriteData2(Attribute attrib,uint16_t value)111 void WriteData2(Attribute attrib, uint16_t value) { 112 AddAbbrevAttribute(attrib, DW_FORM_data2); 113 this->PushUint16(value); 114 } 115 WriteData4(Attribute attrib,uint32_t value)116 void WriteData4(Attribute attrib, uint32_t value) { 117 AddAbbrevAttribute(attrib, DW_FORM_data4); 118 this->PushUint32(value); 119 } 120 WriteData8(Attribute attrib,uint64_t value)121 void WriteData8(Attribute attrib, uint64_t value) { 122 AddAbbrevAttribute(attrib, DW_FORM_data8); 123 this->PushUint64(value); 124 } 125 WriteSdata(Attribute attrib,int value)126 void WriteSdata(Attribute attrib, int value) { 127 AddAbbrevAttribute(attrib, DW_FORM_sdata); 128 this->PushSleb128(value); 129 } 130 WriteUdata(Attribute attrib,int value)131 void WriteUdata(Attribute attrib, int value) { 132 AddAbbrevAttribute(attrib, DW_FORM_udata); 133 this->PushUleb128(value); 134 } 135 WriteUdata(Attribute attrib,uint32_t value)136 void WriteUdata(Attribute attrib, uint32_t value) { 137 AddAbbrevAttribute(attrib, DW_FORM_udata); 138 this->PushUleb128(value); 139 } 140 WriteFlag(Attribute attrib,bool value)141 void WriteFlag(Attribute attrib, bool value) { 142 AddAbbrevAttribute(attrib, DW_FORM_flag); 143 this->PushUint8(value ? 1 : 0); 144 } 145 WriteRef4(Attribute attrib,int cu_offset)146 void WriteRef4(Attribute attrib, int cu_offset) { 147 AddAbbrevAttribute(attrib, DW_FORM_ref4); 148 this->PushUint32(cu_offset); 149 } 150 WriteRef(Attribute attrib,int cu_offset)151 void WriteRef(Attribute attrib, int cu_offset) { 152 AddAbbrevAttribute(attrib, DW_FORM_ref_udata); 153 this->PushUleb128(cu_offset); 154 } 155 WriteString(Attribute attrib,const char * value)156 void WriteString(Attribute attrib, const char* value) { 157 AddAbbrevAttribute(attrib, DW_FORM_string); 158 this->PushString(value); 159 } 160 WriteStrp(Attribute attrib,int address)161 void WriteStrp(Attribute attrib, int address) { 162 AddAbbrevAttribute(attrib, DW_FORM_strp); 163 this->PushUint32(address); 164 } 165 WriteStrp(Attribute attrib,const char * value,std::vector<uint8_t> * debug_str)166 void WriteStrp(Attribute attrib, const char* value, std::vector<uint8_t>* debug_str) { 167 AddAbbrevAttribute(attrib, DW_FORM_strp); 168 int address = debug_str->size(); 169 debug_str->insert(debug_str->end(), value, value + strlen(value) + 1); 170 this->PushUint32(address); 171 } 172 Is64bit()173 bool Is64bit() const { return is64bit_; } 174 GetPatchLocations()175 const std::vector<uintptr_t>& GetPatchLocations() const { 176 return patch_locations_; 177 } 178 179 using Writer<Allocator>::data; 180 181 DebugInfoEntryWriter(bool is64bitArch, 182 std::vector<uint8_t, Allocator>* debug_abbrev, 183 const Allocator& alloc = Allocator()) 184 : Writer<Allocator>(&entries_), 185 debug_abbrev_(debug_abbrev), 186 current_abbrev_(alloc), 187 abbrev_codes_(alloc), 188 entries_(alloc), 189 is64bit_(is64bitArch) { 190 debug_abbrev_.PushUint8(0); // Add abbrev table terminator. 191 } 192 ~DebugInfoEntryWriter()193 ~DebugInfoEntryWriter() { 194 DCHECK_EQ(depth_, 0); 195 } 196 197 private: 198 // Start abbreviation declaration. StartAbbrev(Tag tag,Children children)199 void StartAbbrev(Tag tag, Children children) { 200 DCHECK(!inside_entry_); 201 current_abbrev_.clear(); 202 EncodeUnsignedLeb128(¤t_abbrev_, tag); 203 current_abbrev_.push_back(children); 204 } 205 206 // Add attribute specification. AddAbbrevAttribute(Attribute name,Form type)207 void AddAbbrevAttribute(Attribute name, Form type) { 208 DCHECK(inside_entry_) << "Call StartTag before adding attributes."; 209 EncodeUnsignedLeb128(¤t_abbrev_, name); 210 EncodeUnsignedLeb128(¤t_abbrev_, type); 211 } 212 NextAbbrevCode()213 int NextAbbrevCode() { 214 return 1 + abbrev_codes_.size(); 215 } 216 217 // End abbreviation declaration and return its code. EndAbbrev()218 int EndAbbrev() { 219 DCHECK(inside_entry_); 220 auto it = abbrev_codes_.insert(std::make_pair(std::move(current_abbrev_), 221 NextAbbrevCode())); 222 int abbrev_code = it.first->second; 223 if (UNLIKELY(it.second)) { // Inserted new entry. 224 const std::vector<uint8_t, Allocator>& abbrev = it.first->first; 225 debug_abbrev_.Pop(); // Remove abbrev table terminator. 226 debug_abbrev_.PushUleb128(abbrev_code); 227 debug_abbrev_.PushData(abbrev.data(), abbrev.size()); 228 debug_abbrev_.PushUint8(0); // Attribute list end. 229 debug_abbrev_.PushUint8(0); // Attribute list end. 230 debug_abbrev_.PushUint8(0); // Add abbrev table terminator. 231 } 232 return abbrev_code; 233 } 234 235 private: 236 // Fields for writing and deduplication of abbrevs. 237 Writer<Allocator> debug_abbrev_; 238 std::vector<uint8_t, Allocator> current_abbrev_; 239 std::unordered_map<std::vector<uint8_t, Allocator>, int, 240 FNVHash<Allocator> > abbrev_codes_; 241 242 // Fields for writing of debugging information entries. 243 std::vector<uint8_t, Allocator> entries_; 244 bool is64bit_; 245 int depth_ = 0; 246 size_t abbrev_code_offset_ = 0; // Location to patch once we know the code. 247 bool inside_entry_ = false; // Entry ends at first child (if any). 248 bool has_children = true; 249 std::vector<uintptr_t> patch_locations_; 250 }; 251 252 } // namespace dwarf 253 } // namespace art 254 255 #endif // ART_COMPILER_DWARF_DEBUG_INFO_ENTRY_WRITER_H_ 256