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_DEBUG_DWARF_DEBUG_INFO_ENTRY_WRITER_H_
18 #define ART_COMPILER_DEBUG_DWARF_DEBUG_INFO_ENTRY_WRITER_H_
19 
20 #include <cstdint>
21 #include <unordered_map>
22 
23 #include "base/casts.h"
24 #include "base/leb128.h"
25 #include "debug/dwarf/debug_abbrev_writer.h"
26 #include "debug/dwarf/dwarf_constants.h"
27 #include "debug/dwarf/expression.h"
28 #include "debug/dwarf/writer.h"
29 
30 namespace art {
31 namespace dwarf {
32 
33 /*
34  * Writer for debug information entries (DIE).
35  *
36  * Usage:
37  *   StartTag(DW_TAG_compile_unit);
38  *     WriteStrp(DW_AT_producer, "Compiler name", debug_str);
39  *     StartTag(DW_TAG_subprogram);
40  *       WriteStrp(DW_AT_name, "Foo", debug_str);
41  *     EndTag();
42  *   EndTag();
43  */
44 template <typename Vector = std::vector<uint8_t>>
45 class DebugInfoEntryWriter FINAL : private Writer<Vector> {
46   static_assert(std::is_same<typename Vector::value_type, uint8_t>::value, "Invalid value type");
47 
48  public:
49   static constexpr size_t kCompilationUnitHeaderSize = 11;
50 
51   // Start debugging information entry.
52   // Returns offset of the entry in compilation unit.
StartTag(Tag tag)53   size_t StartTag(Tag tag) {
54     if (inside_entry_) {
55       // Write abbrev code for the previous entry.
56       // Parent entry is finalized before any children are written.
57       this->UpdateUleb128(abbrev_code_offset_, debug_abbrev_->EndAbbrev(DW_CHILDREN_yes));
58       inside_entry_ = false;
59     }
60     debug_abbrev_->StartAbbrev(tag);
61     // Abbrev code placeholder of sufficient size.
62     abbrev_code_offset_ = this->data()->size();
63     this->PushUleb128(debug_abbrev_->NextAbbrevCode());
64     depth_++;
65     inside_entry_ = true;
66     return abbrev_code_offset_ + kCompilationUnitHeaderSize;
67   }
68 
69   // End debugging information entry.
EndTag()70   void EndTag() {
71     DCHECK_GT(depth_, 0);
72     if (inside_entry_) {
73       // Write abbrev code for this entry.
74       this->UpdateUleb128(abbrev_code_offset_, debug_abbrev_->EndAbbrev(DW_CHILDREN_no));
75       inside_entry_ = false;
76       // This entry has no children and so there is no terminator.
77     } else {
78       // The entry has been already finalized so it must be parent entry
79       // and we need to write the terminator required by DW_CHILDREN_yes.
80       this->PushUint8(0);
81     }
82     depth_--;
83   }
84 
WriteAddr(Attribute attrib,uint64_t value)85   void WriteAddr(Attribute attrib, uint64_t value) {
86     debug_abbrev_->AddAbbrevAttribute(attrib, DW_FORM_addr);
87     patch_locations_.push_back(this->data()->size());
88     if (is64bit_) {
89       this->PushUint64(value);
90     } else {
91       this->PushUint32(value);
92     }
93   }
94 
WriteBlock(Attribute attrib,const uint8_t * ptr,size_t num_bytes)95   void WriteBlock(Attribute attrib, const uint8_t* ptr, size_t num_bytes) {
96     debug_abbrev_->AddAbbrevAttribute(attrib, DW_FORM_block);
97     this->PushUleb128(num_bytes);
98     this->PushData(ptr, num_bytes);
99   }
100 
WriteExprLoc(Attribute attrib,const Expression & expr)101   void WriteExprLoc(Attribute attrib, const Expression& expr) {
102     debug_abbrev_->AddAbbrevAttribute(attrib, DW_FORM_exprloc);
103     this->PushUleb128(dchecked_integral_cast<uint32_t>(expr.size()));
104     this->PushData(expr.data());
105   }
106 
WriteData1(Attribute attrib,uint8_t value)107   void WriteData1(Attribute attrib, uint8_t value) {
108     debug_abbrev_->AddAbbrevAttribute(attrib, DW_FORM_data1);
109     this->PushUint8(value);
110   }
111 
WriteData2(Attribute attrib,uint16_t value)112   void WriteData2(Attribute attrib, uint16_t value) {
113     debug_abbrev_->AddAbbrevAttribute(attrib, DW_FORM_data2);
114     this->PushUint16(value);
115   }
116 
WriteData4(Attribute attrib,uint32_t value)117   void WriteData4(Attribute attrib, uint32_t value) {
118     debug_abbrev_->AddAbbrevAttribute(attrib, DW_FORM_data4);
119     this->PushUint32(value);
120   }
121 
WriteData8(Attribute attrib,uint64_t value)122   void WriteData8(Attribute attrib, uint64_t value) {
123     debug_abbrev_->AddAbbrevAttribute(attrib, DW_FORM_data8);
124     this->PushUint64(value);
125   }
126 
WriteSecOffset(Attribute attrib,uint32_t offset)127   void WriteSecOffset(Attribute attrib, uint32_t offset) {
128     debug_abbrev_->AddAbbrevAttribute(attrib, DW_FORM_sec_offset);
129     this->PushUint32(offset);
130   }
131 
WriteSdata(Attribute attrib,int value)132   void WriteSdata(Attribute attrib, int value) {
133     debug_abbrev_->AddAbbrevAttribute(attrib, DW_FORM_sdata);
134     this->PushSleb128(value);
135   }
136 
WriteUdata(Attribute attrib,int value)137   void WriteUdata(Attribute attrib, int value) {
138     debug_abbrev_->AddAbbrevAttribute(attrib, DW_FORM_udata);
139     this->PushUleb128(value);
140   }
141 
WriteUdata(Attribute attrib,uint32_t value)142   void WriteUdata(Attribute attrib, uint32_t value) {
143     debug_abbrev_->AddAbbrevAttribute(attrib, DW_FORM_udata);
144     this->PushUleb128(value);
145   }
146 
WriteFlag(Attribute attrib,bool value)147   void WriteFlag(Attribute attrib, bool value) {
148     debug_abbrev_->AddAbbrevAttribute(attrib, DW_FORM_flag);
149     this->PushUint8(value ? 1 : 0);
150   }
151 
WriteFlagPresent(Attribute attrib)152   void WriteFlagPresent(Attribute attrib) {
153     debug_abbrev_->AddAbbrevAttribute(attrib, DW_FORM_flag_present);
154   }
155 
WriteRef4(Attribute attrib,uint32_t cu_offset)156   void WriteRef4(Attribute attrib, uint32_t cu_offset) {
157     debug_abbrev_->AddAbbrevAttribute(attrib, DW_FORM_ref4);
158     this->PushUint32(cu_offset);
159   }
160 
WriteRef(Attribute attrib,uint32_t cu_offset)161   void WriteRef(Attribute attrib, uint32_t cu_offset) {
162     debug_abbrev_->AddAbbrevAttribute(attrib, DW_FORM_ref_udata);
163     this->PushUleb128(cu_offset);
164   }
165 
WriteString(Attribute attrib,const char * value)166   void WriteString(Attribute attrib, const char* value) {
167     debug_abbrev_->AddAbbrevAttribute(attrib, DW_FORM_string);
168     this->PushString(value);
169   }
170 
WriteStrp(Attribute attrib,size_t debug_str_offset)171   void WriteStrp(Attribute attrib, size_t debug_str_offset) {
172     debug_abbrev_->AddAbbrevAttribute(attrib, DW_FORM_strp);
173     this->PushUint32(dchecked_integral_cast<uint32_t>(debug_str_offset));
174   }
175 
WriteStrp(Attribute attrib,const char * str,size_t len,std::vector<uint8_t> * debug_str)176   void WriteStrp(Attribute attrib, const char* str, size_t len,
177                  std::vector<uint8_t>* debug_str) {
178     debug_abbrev_->AddAbbrevAttribute(attrib, DW_FORM_strp);
179     this->PushUint32(debug_str->size());
180     debug_str->insert(debug_str->end(), str, str + len);
181     debug_str->push_back(0);
182   }
183 
WriteStrp(Attribute attrib,const char * str,std::vector<uint8_t> * debug_str)184   void WriteStrp(Attribute attrib, const char* str, std::vector<uint8_t>* debug_str) {
185     WriteStrp(attrib, str, strlen(str), debug_str);
186   }
187 
Is64bit()188   bool Is64bit() const { return is64bit_; }
189 
GetPatchLocations()190   const std::vector<uintptr_t>& GetPatchLocations() const {
191     return patch_locations_;
192   }
193 
Depth()194   int Depth() const { return depth_; }
195 
196   using Writer<Vector>::data;
197   using Writer<Vector>::size;
198   using Writer<Vector>::UpdateUint32;
199 
200   DebugInfoEntryWriter(bool is64bitArch,
201                        DebugAbbrevWriter<Vector>* debug_abbrev,
202                        const typename Vector::allocator_type& alloc =
203                            typename Vector::allocator_type())
204       : Writer<Vector>(&entries_),
205         debug_abbrev_(debug_abbrev),
206         entries_(alloc),
207         is64bit_(is64bitArch) {
208   }
209 
~DebugInfoEntryWriter()210   ~DebugInfoEntryWriter() {
211     DCHECK(!inside_entry_);
212     DCHECK_EQ(depth_, 0);
213   }
214 
215  private:
216   DebugAbbrevWriter<Vector>* debug_abbrev_;
217   Vector entries_;
218   bool is64bit_;
219   int depth_ = 0;
220   size_t abbrev_code_offset_ = 0;  // Location to patch once we know the code.
221   bool inside_entry_ = false;  // Entry ends at first child (if any).
222   std::vector<uintptr_t> patch_locations_;
223 };
224 
225 }  // namespace dwarf
226 }  // namespace art
227 
228 #endif  // ART_COMPILER_DEBUG_DWARF_DEBUG_INFO_ENTRY_WRITER_H_
229