blob: d9b367bdf16b7df23c75e3fd611442c6fc27ce76 [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
Vladimir Markoec7802a2015-10-01 20:57:57 +010032template <typename Vector>
David Srbeckyb5362472015-04-08 19:37:39 +010033struct FNVHash {
Vladimir Markoec7802a2015-10-01 20:57:57 +010034 static_assert(std::is_same<typename Vector::value_type, uint8_t>::value, "Invalid value type");
35
36 size_t operator()(const Vector& v) const {
David Srbeckyb5362472015-04-08 19:37:39 +010037 uint32_t hash = 2166136261u;
38 for (size_t i = 0; i < v.size(); i++) {
39 hash = (hash ^ v[i]) * 16777619u;
40 }
41 return hash;
42 }
43};
44
45/*
46 * Writer for debug information entries (DIE).
47 * It also handles generation of abbreviations.
48 *
49 * Usage:
50 * StartTag(DW_TAG_compile_unit, DW_CHILDREN_yes);
51 * WriteStrp(DW_AT_producer, "Compiler name", debug_str);
52 * StartTag(DW_TAG_subprogram, DW_CHILDREN_no);
53 * WriteStrp(DW_AT_name, "Foo", debug_str);
54 * EndTag();
55 * EndTag();
56 */
Vladimir Markoec7802a2015-10-01 20:57:57 +010057template <typename Vector = std::vector<uint8_t>>
58class DebugInfoEntryWriter FINAL : private Writer<Vector> {
59 static_assert(std::is_same<typename Vector::value_type, uint8_t>::value, "Invalid value type");
60
David Srbeckyb5362472015-04-08 19:37:39 +010061 public:
62 // Start debugging information entry.
63 void StartTag(Tag tag, Children children) {
64 DCHECK(has_children) << "This tag can not have nested tags";
65 if (inside_entry_) {
66 // Write abbrev code for the previous entry.
67 this->UpdateUleb128(abbrev_code_offset_, EndAbbrev());
68 inside_entry_ = false;
69 }
70 StartAbbrev(tag, children);
71 // Abbrev code placeholder of sufficient size.
72 abbrev_code_offset_ = this->data()->size();
73 this->PushUleb128(NextAbbrevCode());
74 depth_++;
75 inside_entry_ = true;
76 has_children = (children == DW_CHILDREN_yes);
77 }
78
79 // End debugging information entry.
80 void EndTag() {
81 DCHECK_GT(depth_, 0);
82 if (inside_entry_) {
83 // Write abbrev code for this tag.
84 this->UpdateUleb128(abbrev_code_offset_, EndAbbrev());
85 inside_entry_ = false;
86 }
87 if (has_children) {
88 this->PushUint8(0); // End of children.
89 }
90 depth_--;
91 has_children = true; // Parent tag obviously has children.
92 }
93
94 void WriteAddr(Attribute attrib, uint64_t value) {
95 AddAbbrevAttribute(attrib, DW_FORM_addr);
David Srbecky2f6cdb02015-04-11 00:17:53 +010096 patch_locations_.push_back(this->data()->size());
David Srbeckyb5362472015-04-08 19:37:39 +010097 if (is64bit_) {
98 this->PushUint64(value);
99 } else {
100 this->PushUint32(value);
101 }
102 }
103
104 void WriteBlock(Attribute attrib, const void* ptr, int size) {
105 AddAbbrevAttribute(attrib, DW_FORM_block);
106 this->PushUleb128(size);
107 this->PushData(ptr, size);
108 }
109
110 void WriteData1(Attribute attrib, uint8_t value) {
111 AddAbbrevAttribute(attrib, DW_FORM_data1);
112 this->PushUint8(value);
113 }
114
115 void WriteData2(Attribute attrib, uint16_t value) {
116 AddAbbrevAttribute(attrib, DW_FORM_data2);
117 this->PushUint16(value);
118 }
119
120 void WriteData4(Attribute attrib, uint32_t value) {
121 AddAbbrevAttribute(attrib, DW_FORM_data4);
122 this->PushUint32(value);
123 }
124
125 void WriteData8(Attribute attrib, uint64_t value) {
126 AddAbbrevAttribute(attrib, DW_FORM_data8);
127 this->PushUint64(value);
128 }
129
130 void WriteSdata(Attribute attrib, int value) {
131 AddAbbrevAttribute(attrib, DW_FORM_sdata);
132 this->PushSleb128(value);
133 }
134
135 void WriteUdata(Attribute attrib, int value) {
136 AddAbbrevAttribute(attrib, DW_FORM_udata);
137 this->PushUleb128(value);
138 }
139
140 void WriteUdata(Attribute attrib, uint32_t value) {
141 AddAbbrevAttribute(attrib, DW_FORM_udata);
142 this->PushUleb128(value);
143 }
144
145 void WriteFlag(Attribute attrib, bool value) {
146 AddAbbrevAttribute(attrib, DW_FORM_flag);
147 this->PushUint8(value ? 1 : 0);
148 }
149
150 void WriteRef4(Attribute attrib, int cu_offset) {
151 AddAbbrevAttribute(attrib, DW_FORM_ref4);
152 this->PushUint32(cu_offset);
153 }
154
155 void WriteRef(Attribute attrib, int cu_offset) {
156 AddAbbrevAttribute(attrib, DW_FORM_ref_udata);
157 this->PushUleb128(cu_offset);
158 }
159
160 void WriteString(Attribute attrib, const char* value) {
161 AddAbbrevAttribute(attrib, DW_FORM_string);
162 this->PushString(value);
163 }
164
165 void WriteStrp(Attribute attrib, int address) {
166 AddAbbrevAttribute(attrib, DW_FORM_strp);
167 this->PushUint32(address);
168 }
169
170 void WriteStrp(Attribute attrib, const char* value, std::vector<uint8_t>* debug_str) {
171 AddAbbrevAttribute(attrib, DW_FORM_strp);
172 int address = debug_str->size();
173 debug_str->insert(debug_str->end(), value, value + strlen(value) + 1);
174 this->PushUint32(address);
175 }
176
David Srbecky2f6cdb02015-04-11 00:17:53 +0100177 bool Is64bit() const { return is64bit_; }
178
179 const std::vector<uintptr_t>& GetPatchLocations() const {
180 return patch_locations_;
181 }
David Srbeckyb5362472015-04-08 19:37:39 +0100182
Vladimir Markoec7802a2015-10-01 20:57:57 +0100183 using Writer<Vector>::data;
David Srbeckyb5362472015-04-08 19:37:39 +0100184
185 DebugInfoEntryWriter(bool is64bitArch,
Vladimir Markoec7802a2015-10-01 20:57:57 +0100186 Vector* debug_abbrev,
187 const typename Vector::allocator_type& alloc =
188 typename Vector::allocator_type())
189 : Writer<Vector>(&entries_),
David Srbeckyb5362472015-04-08 19:37:39 +0100190 debug_abbrev_(debug_abbrev),
191 current_abbrev_(alloc),
192 abbrev_codes_(alloc),
193 entries_(alloc),
194 is64bit_(is64bitArch) {
195 debug_abbrev_.PushUint8(0); // Add abbrev table terminator.
196 }
197
198 ~DebugInfoEntryWriter() {
199 DCHECK_EQ(depth_, 0);
200 }
201
202 private:
203 // Start abbreviation declaration.
204 void StartAbbrev(Tag tag, Children children) {
205 DCHECK(!inside_entry_);
206 current_abbrev_.clear();
207 EncodeUnsignedLeb128(&current_abbrev_, tag);
208 current_abbrev_.push_back(children);
209 }
210
211 // Add attribute specification.
212 void AddAbbrevAttribute(Attribute name, Form type) {
213 DCHECK(inside_entry_) << "Call StartTag before adding attributes.";
214 EncodeUnsignedLeb128(&current_abbrev_, name);
215 EncodeUnsignedLeb128(&current_abbrev_, type);
216 }
217
218 int NextAbbrevCode() {
219 return 1 + abbrev_codes_.size();
220 }
221
222 // End abbreviation declaration and return its code.
223 int EndAbbrev() {
224 DCHECK(inside_entry_);
225 auto it = abbrev_codes_.insert(std::make_pair(std::move(current_abbrev_),
226 NextAbbrevCode()));
227 int abbrev_code = it.first->second;
228 if (UNLIKELY(it.second)) { // Inserted new entry.
Vladimir Markoec7802a2015-10-01 20:57:57 +0100229 const Vector& abbrev = it.first->first;
David Srbeckyb5362472015-04-08 19:37:39 +0100230 debug_abbrev_.Pop(); // Remove abbrev table terminator.
231 debug_abbrev_.PushUleb128(abbrev_code);
232 debug_abbrev_.PushData(abbrev.data(), abbrev.size());
233 debug_abbrev_.PushUint8(0); // Attribute list end.
234 debug_abbrev_.PushUint8(0); // Attribute list end.
235 debug_abbrev_.PushUint8(0); // Add abbrev table terminator.
236 }
237 return abbrev_code;
238 }
239
240 private:
241 // Fields for writing and deduplication of abbrevs.
Vladimir Markoec7802a2015-10-01 20:57:57 +0100242 Writer<Vector> debug_abbrev_;
243 Vector current_abbrev_;
244 std::unordered_map<Vector, int,
245 FNVHash<Vector> > abbrev_codes_;
David Srbeckyb5362472015-04-08 19:37:39 +0100246
247 // Fields for writing of debugging information entries.
Vladimir Markoec7802a2015-10-01 20:57:57 +0100248 Vector entries_;
David Srbeckyb5362472015-04-08 19:37:39 +0100249 bool is64bit_;
250 int depth_ = 0;
251 size_t abbrev_code_offset_ = 0; // Location to patch once we know the code.
252 bool inside_entry_ = false; // Entry ends at first child (if any).
253 bool has_children = true;
David Srbecky2f6cdb02015-04-11 00:17:53 +0100254 std::vector<uintptr_t> patch_locations_;
David Srbeckyb5362472015-04-08 19:37:39 +0100255};
256
257} // namespace dwarf
258} // namespace art
259
260#endif // ART_COMPILER_DWARF_DEBUG_INFO_ENTRY_WRITER_H_