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(&current_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(&current_abbrev_, name);
210     EncodeUnsignedLeb128(&current_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