blob: e5bbed3c8e5785477fb4a27a77d347018bf5087d [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 Srbecky04b05262015-11-09 18:05:48 +000023#include "base/casts.h"
David Srbecky7c869b32015-04-12 08:47:47 +010024#include "dwarf/dwarf_constants.h"
David Srbecky91cb54e2016-01-15 13:47:59 +000025#include "dwarf/expression.h"
David Srbecky7c869b32015-04-12 08:47:47 +010026#include "dwarf/writer.h"
David Srbeckyb5362472015-04-08 19:37:39 +010027#include "leb128.h"
David Srbeckyb5362472015-04-08 19:37:39 +010028
29namespace art {
30namespace dwarf {
31
32// 32-bit FNV-1a hash function which we use to find duplicate abbreviations.
33// See http://en.wikipedia.org/wiki/Fowler%E2%80%93Noll%E2%80%93Vo_hash_function
Vladimir Markoec7802a2015-10-01 20:57:57 +010034template <typename Vector>
David Srbeckyb5362472015-04-08 19:37:39 +010035struct FNVHash {
Vladimir Markoec7802a2015-10-01 20:57:57 +010036 static_assert(std::is_same<typename Vector::value_type, uint8_t>::value, "Invalid value type");
37
38 size_t operator()(const Vector& v) const {
David Srbeckyb5362472015-04-08 19:37:39 +010039 uint32_t hash = 2166136261u;
40 for (size_t i = 0; i < v.size(); i++) {
41 hash = (hash ^ v[i]) * 16777619u;
42 }
43 return hash;
44 }
45};
46
47/*
48 * Writer for debug information entries (DIE).
49 * It also handles generation of abbreviations.
50 *
51 * Usage:
David Srbecky04b05262015-11-09 18:05:48 +000052 * StartTag(DW_TAG_compile_unit);
David Srbeckyb5362472015-04-08 19:37:39 +010053 * WriteStrp(DW_AT_producer, "Compiler name", debug_str);
David Srbecky04b05262015-11-09 18:05:48 +000054 * StartTag(DW_TAG_subprogram);
David Srbeckyb5362472015-04-08 19:37:39 +010055 * WriteStrp(DW_AT_name, "Foo", debug_str);
56 * EndTag();
57 * EndTag();
58 */
Vladimir Markoec7802a2015-10-01 20:57:57 +010059template <typename Vector = std::vector<uint8_t>>
60class DebugInfoEntryWriter FINAL : private Writer<Vector> {
61 static_assert(std::is_same<typename Vector::value_type, uint8_t>::value, "Invalid value type");
62
David Srbeckyb5362472015-04-08 19:37:39 +010063 public:
David Srbecky04b05262015-11-09 18:05:48 +000064 static constexpr size_t kCompilationUnitHeaderSize = 11;
65
David Srbeckyb5362472015-04-08 19:37:39 +010066 // Start debugging information entry.
David Srbecky04b05262015-11-09 18:05:48 +000067 // Returns offset of the entry in compilation unit.
68 size_t StartTag(Tag tag) {
David Srbeckyb5362472015-04-08 19:37:39 +010069 if (inside_entry_) {
70 // Write abbrev code for the previous entry.
David Srbecky04b05262015-11-09 18:05:48 +000071 // Parent entry is finalized before any children are written.
72 this->UpdateUleb128(abbrev_code_offset_, EndAbbrev(DW_CHILDREN_yes));
David Srbeckyb5362472015-04-08 19:37:39 +010073 inside_entry_ = false;
74 }
David Srbecky04b05262015-11-09 18:05:48 +000075 StartAbbrev(tag);
David Srbeckyb5362472015-04-08 19:37:39 +010076 // Abbrev code placeholder of sufficient size.
77 abbrev_code_offset_ = this->data()->size();
78 this->PushUleb128(NextAbbrevCode());
79 depth_++;
80 inside_entry_ = true;
David Srbecky04b05262015-11-09 18:05:48 +000081 return abbrev_code_offset_ + kCompilationUnitHeaderSize;
David Srbeckyb5362472015-04-08 19:37:39 +010082 }
83
84 // End debugging information entry.
85 void EndTag() {
86 DCHECK_GT(depth_, 0);
87 if (inside_entry_) {
David Srbecky04b05262015-11-09 18:05:48 +000088 // Write abbrev code for this entry.
89 this->UpdateUleb128(abbrev_code_offset_, EndAbbrev(DW_CHILDREN_no));
David Srbeckyb5362472015-04-08 19:37:39 +010090 inside_entry_ = false;
David Srbecky04b05262015-11-09 18:05:48 +000091 // This entry has no children and so there is no terminator.
92 } else {
93 // The entry has been already finalized so it must be parent entry
94 // and we need to write the terminator required by DW_CHILDREN_yes.
95 this->PushUint8(0);
David Srbeckyb5362472015-04-08 19:37:39 +010096 }
97 depth_--;
David Srbeckyb5362472015-04-08 19:37:39 +010098 }
99
100 void WriteAddr(Attribute attrib, uint64_t value) {
101 AddAbbrevAttribute(attrib, DW_FORM_addr);
David Srbecky2f6cdb02015-04-11 00:17:53 +0100102 patch_locations_.push_back(this->data()->size());
David Srbeckyb5362472015-04-08 19:37:39 +0100103 if (is64bit_) {
104 this->PushUint64(value);
105 } else {
106 this->PushUint32(value);
107 }
108 }
109
David Srbecky91cb54e2016-01-15 13:47:59 +0000110 void WriteBlock(Attribute attrib, const uint8_t* ptr, size_t num_bytes) {
David Srbeckyb5362472015-04-08 19:37:39 +0100111 AddAbbrevAttribute(attrib, DW_FORM_block);
David Srbecky04b05262015-11-09 18:05:48 +0000112 this->PushUleb128(num_bytes);
113 this->PushData(ptr, num_bytes);
David Srbeckyb5362472015-04-08 19:37:39 +0100114 }
115
David Srbecky91cb54e2016-01-15 13:47:59 +0000116 void WriteExprLoc(Attribute attrib, const Expression& expr) {
David Srbecky0fd295f2015-11-16 16:39:10 +0000117 AddAbbrevAttribute(attrib, DW_FORM_exprloc);
David Srbecky91cb54e2016-01-15 13:47:59 +0000118 this->PushUleb128(dchecked_integral_cast<uint32_t>(expr.size()));
119 this->PushData(expr.data());
David Srbecky0fd295f2015-11-16 16:39:10 +0000120 }
121
David Srbeckyb5362472015-04-08 19:37:39 +0100122 void WriteData1(Attribute attrib, uint8_t value) {
123 AddAbbrevAttribute(attrib, DW_FORM_data1);
124 this->PushUint8(value);
125 }
126
127 void WriteData2(Attribute attrib, uint16_t value) {
128 AddAbbrevAttribute(attrib, DW_FORM_data2);
129 this->PushUint16(value);
130 }
131
132 void WriteData4(Attribute attrib, uint32_t value) {
133 AddAbbrevAttribute(attrib, DW_FORM_data4);
134 this->PushUint32(value);
135 }
136
137 void WriteData8(Attribute attrib, uint64_t value) {
138 AddAbbrevAttribute(attrib, DW_FORM_data8);
139 this->PushUint64(value);
140 }
141
David Srbecky0fd295f2015-11-16 16:39:10 +0000142 void WriteSecOffset(Attribute attrib, uint32_t offset) {
143 AddAbbrevAttribute(attrib, DW_FORM_sec_offset);
144 this->PushUint32(offset);
145 }
146
David Srbeckyb5362472015-04-08 19:37:39 +0100147 void WriteSdata(Attribute attrib, int value) {
148 AddAbbrevAttribute(attrib, DW_FORM_sdata);
149 this->PushSleb128(value);
150 }
151
152 void WriteUdata(Attribute attrib, int value) {
153 AddAbbrevAttribute(attrib, DW_FORM_udata);
154 this->PushUleb128(value);
155 }
156
157 void WriteUdata(Attribute attrib, uint32_t value) {
158 AddAbbrevAttribute(attrib, DW_FORM_udata);
159 this->PushUleb128(value);
160 }
161
162 void WriteFlag(Attribute attrib, bool value) {
163 AddAbbrevAttribute(attrib, DW_FORM_flag);
164 this->PushUint8(value ? 1 : 0);
165 }
166
David Srbecky04b05262015-11-09 18:05:48 +0000167 void WriteRef4(Attribute attrib, uint32_t cu_offset) {
David Srbeckyb5362472015-04-08 19:37:39 +0100168 AddAbbrevAttribute(attrib, DW_FORM_ref4);
169 this->PushUint32(cu_offset);
170 }
171
David Srbecky04b05262015-11-09 18:05:48 +0000172 void WriteRef(Attribute attrib, uint32_t cu_offset) {
David Srbeckyb5362472015-04-08 19:37:39 +0100173 AddAbbrevAttribute(attrib, DW_FORM_ref_udata);
174 this->PushUleb128(cu_offset);
175 }
176
177 void WriteString(Attribute attrib, const char* value) {
178 AddAbbrevAttribute(attrib, DW_FORM_string);
179 this->PushString(value);
180 }
181
David Srbecky04b05262015-11-09 18:05:48 +0000182 void WriteStrp(Attribute attrib, size_t debug_str_offset) {
David Srbeckyb5362472015-04-08 19:37:39 +0100183 AddAbbrevAttribute(attrib, DW_FORM_strp);
David Srbecky04b05262015-11-09 18:05:48 +0000184 this->PushUint32(dchecked_integral_cast<uint32_t>(debug_str_offset));
David Srbeckyb5362472015-04-08 19:37:39 +0100185 }
186
David Srbecky04b05262015-11-09 18:05:48 +0000187 void WriteStrp(Attribute attrib, const char* str, size_t len,
188 std::vector<uint8_t>* debug_str) {
David Srbeckyb5362472015-04-08 19:37:39 +0100189 AddAbbrevAttribute(attrib, DW_FORM_strp);
David Srbecky04b05262015-11-09 18:05:48 +0000190 this->PushUint32(debug_str->size());
191 debug_str->insert(debug_str->end(), str, str + len);
192 debug_str->push_back(0);
193 }
194
195 void WriteStrp(Attribute attrib, const char* str, std::vector<uint8_t>* debug_str) {
196 WriteStrp(attrib, str, strlen(str), debug_str);
David Srbeckyb5362472015-04-08 19:37:39 +0100197 }
198
David Srbecky2f6cdb02015-04-11 00:17:53 +0100199 bool Is64bit() const { return is64bit_; }
200
201 const std::vector<uintptr_t>& GetPatchLocations() const {
202 return patch_locations_;
203 }
David Srbeckyb5362472015-04-08 19:37:39 +0100204
David Srbecky04b05262015-11-09 18:05:48 +0000205 int Depth() const { return depth_; }
206
Vladimir Markoec7802a2015-10-01 20:57:57 +0100207 using Writer<Vector>::data;
David Srbecky04b05262015-11-09 18:05:48 +0000208 using Writer<Vector>::size;
209 using Writer<Vector>::UpdateUint32;
David Srbeckyb5362472015-04-08 19:37:39 +0100210
211 DebugInfoEntryWriter(bool is64bitArch,
Vladimir Markoec7802a2015-10-01 20:57:57 +0100212 Vector* debug_abbrev,
213 const typename Vector::allocator_type& alloc =
214 typename Vector::allocator_type())
215 : Writer<Vector>(&entries_),
David Srbeckyb5362472015-04-08 19:37:39 +0100216 debug_abbrev_(debug_abbrev),
217 current_abbrev_(alloc),
218 abbrev_codes_(alloc),
219 entries_(alloc),
220 is64bit_(is64bitArch) {
221 debug_abbrev_.PushUint8(0); // Add abbrev table terminator.
222 }
223
224 ~DebugInfoEntryWriter() {
David Srbecky04b05262015-11-09 18:05:48 +0000225 DCHECK(!inside_entry_);
David Srbeckyb5362472015-04-08 19:37:39 +0100226 DCHECK_EQ(depth_, 0);
227 }
228
229 private:
230 // Start abbreviation declaration.
David Srbecky04b05262015-11-09 18:05:48 +0000231 void StartAbbrev(Tag tag) {
David Srbeckyb5362472015-04-08 19:37:39 +0100232 current_abbrev_.clear();
233 EncodeUnsignedLeb128(&current_abbrev_, tag);
David Srbecky04b05262015-11-09 18:05:48 +0000234 has_children_offset_ = current_abbrev_.size();
235 current_abbrev_.push_back(0); // Place-holder for DW_CHILDREN.
David Srbeckyb5362472015-04-08 19:37:39 +0100236 }
237
238 // Add attribute specification.
239 void AddAbbrevAttribute(Attribute name, Form type) {
240 DCHECK(inside_entry_) << "Call StartTag before adding attributes.";
241 EncodeUnsignedLeb128(&current_abbrev_, name);
242 EncodeUnsignedLeb128(&current_abbrev_, type);
243 }
244
245 int NextAbbrevCode() {
246 return 1 + abbrev_codes_.size();
247 }
248
249 // End abbreviation declaration and return its code.
David Srbecky04b05262015-11-09 18:05:48 +0000250 int EndAbbrev(Children has_children) {
251 DCHECK(!current_abbrev_.empty());
252 current_abbrev_[has_children_offset_] = has_children;
David Srbeckyb5362472015-04-08 19:37:39 +0100253 auto it = abbrev_codes_.insert(std::make_pair(std::move(current_abbrev_),
254 NextAbbrevCode()));
255 int abbrev_code = it.first->second;
256 if (UNLIKELY(it.second)) { // Inserted new entry.
Vladimir Markoec7802a2015-10-01 20:57:57 +0100257 const Vector& abbrev = it.first->first;
David Srbeckyb5362472015-04-08 19:37:39 +0100258 debug_abbrev_.Pop(); // Remove abbrev table terminator.
259 debug_abbrev_.PushUleb128(abbrev_code);
260 debug_abbrev_.PushData(abbrev.data(), abbrev.size());
261 debug_abbrev_.PushUint8(0); // Attribute list end.
262 debug_abbrev_.PushUint8(0); // Attribute list end.
263 debug_abbrev_.PushUint8(0); // Add abbrev table terminator.
264 }
265 return abbrev_code;
266 }
267
268 private:
269 // Fields for writing and deduplication of abbrevs.
Vladimir Markoec7802a2015-10-01 20:57:57 +0100270 Writer<Vector> debug_abbrev_;
271 Vector current_abbrev_;
David Srbecky04b05262015-11-09 18:05:48 +0000272 size_t has_children_offset_ = 0;
Vladimir Markoec7802a2015-10-01 20:57:57 +0100273 std::unordered_map<Vector, int,
274 FNVHash<Vector> > abbrev_codes_;
David Srbeckyb5362472015-04-08 19:37:39 +0100275
276 // Fields for writing of debugging information entries.
Vladimir Markoec7802a2015-10-01 20:57:57 +0100277 Vector entries_;
David Srbeckyb5362472015-04-08 19:37:39 +0100278 bool is64bit_;
279 int depth_ = 0;
280 size_t abbrev_code_offset_ = 0; // Location to patch once we know the code.
281 bool inside_entry_ = false; // Entry ends at first child (if any).
David Srbecky2f6cdb02015-04-11 00:17:53 +0100282 std::vector<uintptr_t> patch_locations_;
David Srbeckyb5362472015-04-08 19:37:39 +0100283};
284
285} // namespace dwarf
286} // namespace art
287
288#endif // ART_COMPILER_DWARF_DEBUG_INFO_ENTRY_WRITER_H_