blob: aa31036c8b0bb797f9bfbc96b51b3262df2b509a [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"
25#include "dwarf/writer.h"
David Srbeckyb5362472015-04-08 19:37:39 +010026#include "leb128.h"
David Srbeckyb5362472015-04-08 19:37:39 +010027
28namespace art {
29namespace dwarf {
30
31// 32-bit FNV-1a hash function which we use to find duplicate abbreviations.
32// See http://en.wikipedia.org/wiki/Fowler%E2%80%93Noll%E2%80%93Vo_hash_function
Vladimir Markoec7802a2015-10-01 20:57:57 +010033template <typename Vector>
David Srbeckyb5362472015-04-08 19:37:39 +010034struct FNVHash {
Vladimir Markoec7802a2015-10-01 20:57:57 +010035 static_assert(std::is_same<typename Vector::value_type, uint8_t>::value, "Invalid value type");
36
37 size_t operator()(const Vector& v) const {
David Srbeckyb5362472015-04-08 19:37:39 +010038 uint32_t hash = 2166136261u;
39 for (size_t i = 0; i < v.size(); i++) {
40 hash = (hash ^ v[i]) * 16777619u;
41 }
42 return hash;
43 }
44};
45
46/*
47 * Writer for debug information entries (DIE).
48 * It also handles generation of abbreviations.
49 *
50 * Usage:
David Srbecky04b05262015-11-09 18:05:48 +000051 * StartTag(DW_TAG_compile_unit);
David Srbeckyb5362472015-04-08 19:37:39 +010052 * WriteStrp(DW_AT_producer, "Compiler name", debug_str);
David Srbecky04b05262015-11-09 18:05:48 +000053 * StartTag(DW_TAG_subprogram);
David Srbeckyb5362472015-04-08 19:37:39 +010054 * WriteStrp(DW_AT_name, "Foo", debug_str);
55 * EndTag();
56 * EndTag();
57 */
Vladimir Markoec7802a2015-10-01 20:57:57 +010058template <typename Vector = std::vector<uint8_t>>
59class DebugInfoEntryWriter FINAL : private Writer<Vector> {
60 static_assert(std::is_same<typename Vector::value_type, uint8_t>::value, "Invalid value type");
61
David Srbeckyb5362472015-04-08 19:37:39 +010062 public:
David Srbecky04b05262015-11-09 18:05:48 +000063 static constexpr size_t kCompilationUnitHeaderSize = 11;
64
David Srbeckyb5362472015-04-08 19:37:39 +010065 // Start debugging information entry.
David Srbecky04b05262015-11-09 18:05:48 +000066 // Returns offset of the entry in compilation unit.
67 size_t StartTag(Tag tag) {
David Srbeckyb5362472015-04-08 19:37:39 +010068 if (inside_entry_) {
69 // Write abbrev code for the previous entry.
David Srbecky04b05262015-11-09 18:05:48 +000070 // Parent entry is finalized before any children are written.
71 this->UpdateUleb128(abbrev_code_offset_, EndAbbrev(DW_CHILDREN_yes));
David Srbeckyb5362472015-04-08 19:37:39 +010072 inside_entry_ = false;
73 }
David Srbecky04b05262015-11-09 18:05:48 +000074 StartAbbrev(tag);
David Srbeckyb5362472015-04-08 19:37:39 +010075 // Abbrev code placeholder of sufficient size.
76 abbrev_code_offset_ = this->data()->size();
77 this->PushUleb128(NextAbbrevCode());
78 depth_++;
79 inside_entry_ = true;
David Srbecky04b05262015-11-09 18:05:48 +000080 return abbrev_code_offset_ + kCompilationUnitHeaderSize;
David Srbeckyb5362472015-04-08 19:37:39 +010081 }
82
83 // End debugging information entry.
84 void EndTag() {
85 DCHECK_GT(depth_, 0);
86 if (inside_entry_) {
David Srbecky04b05262015-11-09 18:05:48 +000087 // Write abbrev code for this entry.
88 this->UpdateUleb128(abbrev_code_offset_, EndAbbrev(DW_CHILDREN_no));
David Srbeckyb5362472015-04-08 19:37:39 +010089 inside_entry_ = false;
David Srbecky04b05262015-11-09 18:05:48 +000090 // This entry has no children and so there is no terminator.
91 } else {
92 // The entry has been already finalized so it must be parent entry
93 // and we need to write the terminator required by DW_CHILDREN_yes.
94 this->PushUint8(0);
David Srbeckyb5362472015-04-08 19:37:39 +010095 }
96 depth_--;
David Srbeckyb5362472015-04-08 19:37:39 +010097 }
98
99 void WriteAddr(Attribute attrib, uint64_t value) {
100 AddAbbrevAttribute(attrib, DW_FORM_addr);
David Srbecky2f6cdb02015-04-11 00:17:53 +0100101 patch_locations_.push_back(this->data()->size());
David Srbeckyb5362472015-04-08 19:37:39 +0100102 if (is64bit_) {
103 this->PushUint64(value);
104 } else {
105 this->PushUint32(value);
106 }
107 }
108
David Srbecky04b05262015-11-09 18:05:48 +0000109 void WriteBlock(Attribute attrib, const void* ptr, size_t num_bytes) {
David Srbeckyb5362472015-04-08 19:37:39 +0100110 AddAbbrevAttribute(attrib, DW_FORM_block);
David Srbecky04b05262015-11-09 18:05:48 +0000111 this->PushUleb128(num_bytes);
112 this->PushData(ptr, num_bytes);
David Srbeckyb5362472015-04-08 19:37:39 +0100113 }
114
115 void WriteData1(Attribute attrib, uint8_t value) {
116 AddAbbrevAttribute(attrib, DW_FORM_data1);
117 this->PushUint8(value);
118 }
119
120 void WriteData2(Attribute attrib, uint16_t value) {
121 AddAbbrevAttribute(attrib, DW_FORM_data2);
122 this->PushUint16(value);
123 }
124
125 void WriteData4(Attribute attrib, uint32_t value) {
126 AddAbbrevAttribute(attrib, DW_FORM_data4);
127 this->PushUint32(value);
128 }
129
130 void WriteData8(Attribute attrib, uint64_t value) {
131 AddAbbrevAttribute(attrib, DW_FORM_data8);
132 this->PushUint64(value);
133 }
134
135 void WriteSdata(Attribute attrib, int value) {
136 AddAbbrevAttribute(attrib, DW_FORM_sdata);
137 this->PushSleb128(value);
138 }
139
140 void WriteUdata(Attribute attrib, int value) {
141 AddAbbrevAttribute(attrib, DW_FORM_udata);
142 this->PushUleb128(value);
143 }
144
145 void WriteUdata(Attribute attrib, uint32_t value) {
146 AddAbbrevAttribute(attrib, DW_FORM_udata);
147 this->PushUleb128(value);
148 }
149
150 void WriteFlag(Attribute attrib, bool value) {
151 AddAbbrevAttribute(attrib, DW_FORM_flag);
152 this->PushUint8(value ? 1 : 0);
153 }
154
David Srbecky04b05262015-11-09 18:05:48 +0000155 void WriteRef4(Attribute attrib, uint32_t cu_offset) {
David Srbeckyb5362472015-04-08 19:37:39 +0100156 AddAbbrevAttribute(attrib, DW_FORM_ref4);
157 this->PushUint32(cu_offset);
158 }
159
David Srbecky04b05262015-11-09 18:05:48 +0000160 void WriteRef(Attribute attrib, uint32_t cu_offset) {
David Srbeckyb5362472015-04-08 19:37:39 +0100161 AddAbbrevAttribute(attrib, DW_FORM_ref_udata);
162 this->PushUleb128(cu_offset);
163 }
164
165 void WriteString(Attribute attrib, const char* value) {
166 AddAbbrevAttribute(attrib, DW_FORM_string);
167 this->PushString(value);
168 }
169
David Srbecky04b05262015-11-09 18:05:48 +0000170 void WriteStrp(Attribute attrib, size_t debug_str_offset) {
David Srbeckyb5362472015-04-08 19:37:39 +0100171 AddAbbrevAttribute(attrib, DW_FORM_strp);
David Srbecky04b05262015-11-09 18:05:48 +0000172 this->PushUint32(dchecked_integral_cast<uint32_t>(debug_str_offset));
David Srbeckyb5362472015-04-08 19:37:39 +0100173 }
174
David Srbecky04b05262015-11-09 18:05:48 +0000175 void WriteStrp(Attribute attrib, const char* str, size_t len,
176 std::vector<uint8_t>* debug_str) {
David Srbeckyb5362472015-04-08 19:37:39 +0100177 AddAbbrevAttribute(attrib, DW_FORM_strp);
David Srbecky04b05262015-11-09 18:05:48 +0000178 this->PushUint32(debug_str->size());
179 debug_str->insert(debug_str->end(), str, str + len);
180 debug_str->push_back(0);
181 }
182
183 void WriteStrp(Attribute attrib, const char* str, std::vector<uint8_t>* debug_str) {
184 WriteStrp(attrib, str, strlen(str), debug_str);
David Srbeckyb5362472015-04-08 19:37:39 +0100185 }
186
David Srbecky2f6cdb02015-04-11 00:17:53 +0100187 bool Is64bit() const { return is64bit_; }
188
189 const std::vector<uintptr_t>& GetPatchLocations() const {
190 return patch_locations_;
191 }
David Srbeckyb5362472015-04-08 19:37:39 +0100192
David Srbecky04b05262015-11-09 18:05:48 +0000193 int Depth() const { return depth_; }
194
Vladimir Markoec7802a2015-10-01 20:57:57 +0100195 using Writer<Vector>::data;
David Srbecky04b05262015-11-09 18:05:48 +0000196 using Writer<Vector>::size;
197 using Writer<Vector>::UpdateUint32;
David Srbeckyb5362472015-04-08 19:37:39 +0100198
199 DebugInfoEntryWriter(bool is64bitArch,
Vladimir Markoec7802a2015-10-01 20:57:57 +0100200 Vector* debug_abbrev,
201 const typename Vector::allocator_type& alloc =
202 typename Vector::allocator_type())
203 : Writer<Vector>(&entries_),
David Srbeckyb5362472015-04-08 19:37:39 +0100204 debug_abbrev_(debug_abbrev),
205 current_abbrev_(alloc),
206 abbrev_codes_(alloc),
207 entries_(alloc),
208 is64bit_(is64bitArch) {
209 debug_abbrev_.PushUint8(0); // Add abbrev table terminator.
210 }
211
212 ~DebugInfoEntryWriter() {
David Srbecky04b05262015-11-09 18:05:48 +0000213 DCHECK(!inside_entry_);
David Srbeckyb5362472015-04-08 19:37:39 +0100214 DCHECK_EQ(depth_, 0);
215 }
216
217 private:
218 // Start abbreviation declaration.
David Srbecky04b05262015-11-09 18:05:48 +0000219 void StartAbbrev(Tag tag) {
David Srbeckyb5362472015-04-08 19:37:39 +0100220 current_abbrev_.clear();
221 EncodeUnsignedLeb128(&current_abbrev_, tag);
David Srbecky04b05262015-11-09 18:05:48 +0000222 has_children_offset_ = current_abbrev_.size();
223 current_abbrev_.push_back(0); // Place-holder for DW_CHILDREN.
David Srbeckyb5362472015-04-08 19:37:39 +0100224 }
225
226 // Add attribute specification.
227 void AddAbbrevAttribute(Attribute name, Form type) {
228 DCHECK(inside_entry_) << "Call StartTag before adding attributes.";
229 EncodeUnsignedLeb128(&current_abbrev_, name);
230 EncodeUnsignedLeb128(&current_abbrev_, type);
231 }
232
233 int NextAbbrevCode() {
234 return 1 + abbrev_codes_.size();
235 }
236
237 // End abbreviation declaration and return its code.
David Srbecky04b05262015-11-09 18:05:48 +0000238 int EndAbbrev(Children has_children) {
239 DCHECK(!current_abbrev_.empty());
240 current_abbrev_[has_children_offset_] = has_children;
David Srbeckyb5362472015-04-08 19:37:39 +0100241 auto it = abbrev_codes_.insert(std::make_pair(std::move(current_abbrev_),
242 NextAbbrevCode()));
243 int abbrev_code = it.first->second;
244 if (UNLIKELY(it.second)) { // Inserted new entry.
Vladimir Markoec7802a2015-10-01 20:57:57 +0100245 const Vector& abbrev = it.first->first;
David Srbeckyb5362472015-04-08 19:37:39 +0100246 debug_abbrev_.Pop(); // Remove abbrev table terminator.
247 debug_abbrev_.PushUleb128(abbrev_code);
248 debug_abbrev_.PushData(abbrev.data(), abbrev.size());
249 debug_abbrev_.PushUint8(0); // Attribute list end.
250 debug_abbrev_.PushUint8(0); // Attribute list end.
251 debug_abbrev_.PushUint8(0); // Add abbrev table terminator.
252 }
253 return abbrev_code;
254 }
255
256 private:
257 // Fields for writing and deduplication of abbrevs.
Vladimir Markoec7802a2015-10-01 20:57:57 +0100258 Writer<Vector> debug_abbrev_;
259 Vector current_abbrev_;
David Srbecky04b05262015-11-09 18:05:48 +0000260 size_t has_children_offset_ = 0;
Vladimir Markoec7802a2015-10-01 20:57:57 +0100261 std::unordered_map<Vector, int,
262 FNVHash<Vector> > abbrev_codes_;
David Srbeckyb5362472015-04-08 19:37:39 +0100263
264 // Fields for writing of debugging information entries.
Vladimir Markoec7802a2015-10-01 20:57:57 +0100265 Vector entries_;
David Srbeckyb5362472015-04-08 19:37:39 +0100266 bool is64bit_;
267 int depth_ = 0;
268 size_t abbrev_code_offset_ = 0; // Location to patch once we know the code.
269 bool inside_entry_ = false; // Entry ends at first child (if any).
David Srbecky2f6cdb02015-04-11 00:17:53 +0100270 std::vector<uintptr_t> patch_locations_;
David Srbeckyb5362472015-04-08 19:37:39 +0100271};
272
273} // namespace dwarf
274} // namespace art
275
276#endif // ART_COMPILER_DWARF_DEBUG_INFO_ENTRY_WRITER_H_