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