blob: f5b9ca5b64375537970b7239c870ccfe19637d20 [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
David Srbecky2f6cdb02015-04-11 00:17:53 +010020#include <cstdint>
David Srbeckyb5362472015-04-08 19:37:39 +010021#include <unordered_map>
22
David Srbecky7c869b32015-04-12 08:47:47 +010023#include "dwarf/dwarf_constants.h"
24#include "dwarf/writer.h"
David Srbeckyb5362472015-04-08 19:37:39 +010025#include "leb128.h"
David Srbeckyb5362472015-04-08 19:37:39 +010026
27namespace art {
28namespace 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
32template< typename Allocator >
33struct FNVHash {
34 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 */
55template< typename Allocator = std::allocator<uint8_t> >
56class DebugInfoEntryWriter FINAL : private Writer<Allocator> {
57 public:
58 // Start debugging information entry.
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.
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
90 void WriteAddr(Attribute attrib, uint64_t value) {
91 AddAbbrevAttribute(attrib, DW_FORM_addr);
David Srbecky2f6cdb02015-04-11 00:17:53 +010092 patch_locations_.push_back(this->data()->size());
David Srbeckyb5362472015-04-08 19:37:39 +010093 if (is64bit_) {
94 this->PushUint64(value);
95 } else {
96 this->PushUint32(value);
97 }
98 }
99
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
106 void WriteData1(Attribute attrib, uint8_t value) {
107 AddAbbrevAttribute(attrib, DW_FORM_data1);
108 this->PushUint8(value);
109 }
110
111 void WriteData2(Attribute attrib, uint16_t value) {
112 AddAbbrevAttribute(attrib, DW_FORM_data2);
113 this->PushUint16(value);
114 }
115
116 void WriteData4(Attribute attrib, uint32_t value) {
117 AddAbbrevAttribute(attrib, DW_FORM_data4);
118 this->PushUint32(value);
119 }
120
121 void WriteData8(Attribute attrib, uint64_t value) {
122 AddAbbrevAttribute(attrib, DW_FORM_data8);
123 this->PushUint64(value);
124 }
125
126 void WriteSdata(Attribute attrib, int value) {
127 AddAbbrevAttribute(attrib, DW_FORM_sdata);
128 this->PushSleb128(value);
129 }
130
131 void WriteUdata(Attribute attrib, int value) {
132 AddAbbrevAttribute(attrib, DW_FORM_udata);
133 this->PushUleb128(value);
134 }
135
136 void WriteUdata(Attribute attrib, uint32_t value) {
137 AddAbbrevAttribute(attrib, DW_FORM_udata);
138 this->PushUleb128(value);
139 }
140
141 void WriteFlag(Attribute attrib, bool value) {
142 AddAbbrevAttribute(attrib, DW_FORM_flag);
143 this->PushUint8(value ? 1 : 0);
144 }
145
146 void WriteRef4(Attribute attrib, int cu_offset) {
147 AddAbbrevAttribute(attrib, DW_FORM_ref4);
148 this->PushUint32(cu_offset);
149 }
150
151 void WriteRef(Attribute attrib, int cu_offset) {
152 AddAbbrevAttribute(attrib, DW_FORM_ref_udata);
153 this->PushUleb128(cu_offset);
154 }
155
156 void WriteString(Attribute attrib, const char* value) {
157 AddAbbrevAttribute(attrib, DW_FORM_string);
158 this->PushString(value);
159 }
160
161 void WriteStrp(Attribute attrib, int address) {
162 AddAbbrevAttribute(attrib, DW_FORM_strp);
163 this->PushUint32(address);
164 }
165
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
David Srbecky2f6cdb02015-04-11 00:17:53 +0100173 bool Is64bit() const { return is64bit_; }
174
175 const std::vector<uintptr_t>& GetPatchLocations() const {
176 return patch_locations_;
177 }
David Srbeckyb5362472015-04-08 19:37:39 +0100178
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
193 ~DebugInfoEntryWriter() {
194 DCHECK_EQ(depth_, 0);
195 }
196
197 private:
198 // Start abbreviation declaration.
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.
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
213 int NextAbbrevCode() {
214 return 1 + abbrev_codes_.size();
215 }
216
217 // End abbreviation declaration and return its code.
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;
David Srbecky2f6cdb02015-04-11 00:17:53 +0100249 std::vector<uintptr_t> patch_locations_;
David Srbeckyb5362472015-04-08 19:37:39 +0100250};
251
252} // namespace dwarf
253} // namespace art
254
255#endif // ART_COMPILER_DWARF_DEBUG_INFO_ENTRY_WRITER_H_