1/*
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_DEBUG_DWARF_DEBUG_INFO_ENTRY_WRITER_H_
18#define ART_COMPILER_DEBUG_DWARF_DEBUG_INFO_ENTRY_WRITER_H_
19
20#include <cstdint>
21#include <unordered_map>
22
23#include "base/casts.h"
24#include "debug/dwarf/debug_abbrev_writer.h"
25#include "debug/dwarf/dwarf_constants.h"
26#include "debug/dwarf/expression.h"
27#include "debug/dwarf/writer.h"
28#include "leb128.h"
29
30namespace art {
31namespace dwarf {
32
33/*
34 * Writer for debug information entries (DIE).
35 *
36 * Usage:
37 *   StartTag(DW_TAG_compile_unit);
38 *     WriteStrp(DW_AT_producer, "Compiler name", debug_str);
39 *     StartTag(DW_TAG_subprogram);
40 *       WriteStrp(DW_AT_name, "Foo", debug_str);
41 *     EndTag();
42 *   EndTag();
43 */
44template <typename Vector = std::vector<uint8_t>>
45class DebugInfoEntryWriter FINAL : private Writer<Vector> {
46  static_assert(std::is_same<typename Vector::value_type, uint8_t>::value, "Invalid value type");
47
48 public:
49  static constexpr size_t kCompilationUnitHeaderSize = 11;
50
51  // Start debugging information entry.
52  // Returns offset of the entry in compilation unit.
53  size_t StartTag(Tag tag) {
54    if (inside_entry_) {
55      // Write abbrev code for the previous entry.
56      // Parent entry is finalized before any children are written.
57      this->UpdateUleb128(abbrev_code_offset_, debug_abbrev_->EndAbbrev(DW_CHILDREN_yes));
58      inside_entry_ = false;
59    }
60    debug_abbrev_->StartAbbrev(tag);
61    // Abbrev code placeholder of sufficient size.
62    abbrev_code_offset_ = this->data()->size();
63    this->PushUleb128(debug_abbrev_->NextAbbrevCode());
64    depth_++;
65    inside_entry_ = true;
66    return abbrev_code_offset_ + kCompilationUnitHeaderSize;
67  }
68
69  // End debugging information entry.
70  void EndTag() {
71    DCHECK_GT(depth_, 0);
72    if (inside_entry_) {
73      // Write abbrev code for this entry.
74      this->UpdateUleb128(abbrev_code_offset_, debug_abbrev_->EndAbbrev(DW_CHILDREN_no));
75      inside_entry_ = false;
76      // This entry has no children and so there is no terminator.
77    } else {
78      // The entry has been already finalized so it must be parent entry
79      // and we need to write the terminator required by DW_CHILDREN_yes.
80      this->PushUint8(0);
81    }
82    depth_--;
83  }
84
85  void WriteAddr(Attribute attrib, uint64_t value) {
86    debug_abbrev_->AddAbbrevAttribute(attrib, DW_FORM_addr);
87    patch_locations_.push_back(this->data()->size());
88    if (is64bit_) {
89      this->PushUint64(value);
90    } else {
91      this->PushUint32(value);
92    }
93  }
94
95  void WriteBlock(Attribute attrib, const uint8_t* ptr, size_t num_bytes) {
96    debug_abbrev_->AddAbbrevAttribute(attrib, DW_FORM_block);
97    this->PushUleb128(num_bytes);
98    this->PushData(ptr, num_bytes);
99  }
100
101  void WriteExprLoc(Attribute attrib, const Expression& expr) {
102    debug_abbrev_->AddAbbrevAttribute(attrib, DW_FORM_exprloc);
103    this->PushUleb128(dchecked_integral_cast<uint32_t>(expr.size()));
104    this->PushData(expr.data());
105  }
106
107  void WriteData1(Attribute attrib, uint8_t value) {
108    debug_abbrev_->AddAbbrevAttribute(attrib, DW_FORM_data1);
109    this->PushUint8(value);
110  }
111
112  void WriteData2(Attribute attrib, uint16_t value) {
113    debug_abbrev_->AddAbbrevAttribute(attrib, DW_FORM_data2);
114    this->PushUint16(value);
115  }
116
117  void WriteData4(Attribute attrib, uint32_t value) {
118    debug_abbrev_->AddAbbrevAttribute(attrib, DW_FORM_data4);
119    this->PushUint32(value);
120  }
121
122  void WriteData8(Attribute attrib, uint64_t value) {
123    debug_abbrev_->AddAbbrevAttribute(attrib, DW_FORM_data8);
124    this->PushUint64(value);
125  }
126
127  void WriteSecOffset(Attribute attrib, uint32_t offset) {
128    debug_abbrev_->AddAbbrevAttribute(attrib, DW_FORM_sec_offset);
129    this->PushUint32(offset);
130  }
131
132  void WriteSdata(Attribute attrib, int value) {
133    debug_abbrev_->AddAbbrevAttribute(attrib, DW_FORM_sdata);
134    this->PushSleb128(value);
135  }
136
137  void WriteUdata(Attribute attrib, int value) {
138    debug_abbrev_->AddAbbrevAttribute(attrib, DW_FORM_udata);
139    this->PushUleb128(value);
140  }
141
142  void WriteUdata(Attribute attrib, uint32_t value) {
143    debug_abbrev_->AddAbbrevAttribute(attrib, DW_FORM_udata);
144    this->PushUleb128(value);
145  }
146
147  void WriteFlag(Attribute attrib, bool value) {
148    debug_abbrev_->AddAbbrevAttribute(attrib, DW_FORM_flag);
149    this->PushUint8(value ? 1 : 0);
150  }
151
152  void WriteFlagPresent(Attribute attrib) {
153    debug_abbrev_->AddAbbrevAttribute(attrib, DW_FORM_flag_present);
154  }
155
156  void WriteRef4(Attribute attrib, uint32_t cu_offset) {
157    debug_abbrev_->AddAbbrevAttribute(attrib, DW_FORM_ref4);
158    this->PushUint32(cu_offset);
159  }
160
161  void WriteRef(Attribute attrib, uint32_t cu_offset) {
162    debug_abbrev_->AddAbbrevAttribute(attrib, DW_FORM_ref_udata);
163    this->PushUleb128(cu_offset);
164  }
165
166  void WriteString(Attribute attrib, const char* value) {
167    debug_abbrev_->AddAbbrevAttribute(attrib, DW_FORM_string);
168    this->PushString(value);
169  }
170
171  void WriteStrp(Attribute attrib, size_t debug_str_offset) {
172    debug_abbrev_->AddAbbrevAttribute(attrib, DW_FORM_strp);
173    this->PushUint32(dchecked_integral_cast<uint32_t>(debug_str_offset));
174  }
175
176  void WriteStrp(Attribute attrib, const char* str, size_t len,
177                 std::vector<uint8_t>* debug_str) {
178    debug_abbrev_->AddAbbrevAttribute(attrib, DW_FORM_strp);
179    this->PushUint32(debug_str->size());
180    debug_str->insert(debug_str->end(), str, str + len);
181    debug_str->push_back(0);
182  }
183
184  void WriteStrp(Attribute attrib, const char* str, std::vector<uint8_t>* debug_str) {
185    WriteStrp(attrib, str, strlen(str), debug_str);
186  }
187
188  bool Is64bit() const { return is64bit_; }
189
190  const std::vector<uintptr_t>& GetPatchLocations() const {
191    return patch_locations_;
192  }
193
194  int Depth() const { return depth_; }
195
196  using Writer<Vector>::data;
197  using Writer<Vector>::size;
198  using Writer<Vector>::UpdateUint32;
199
200  DebugInfoEntryWriter(bool is64bitArch,
201                       DebugAbbrevWriter<Vector>* debug_abbrev,
202                       const typename Vector::allocator_type& alloc =
203                           typename Vector::allocator_type())
204      : Writer<Vector>(&entries_),
205        debug_abbrev_(debug_abbrev),
206        entries_(alloc),
207        is64bit_(is64bitArch) {
208  }
209
210  ~DebugInfoEntryWriter() {
211    DCHECK(!inside_entry_);
212    DCHECK_EQ(depth_, 0);
213  }
214
215 private:
216  DebugAbbrevWriter<Vector>* debug_abbrev_;
217  Vector entries_;
218  bool is64bit_;
219  int depth_ = 0;
220  size_t abbrev_code_offset_ = 0;  // Location to patch once we know the code.
221  bool inside_entry_ = false;  // Entry ends at first child (if any).
222  std::vector<uintptr_t> patch_locations_;
223};
224
225}  // namespace dwarf
226}  // namespace art
227
228#endif  // ART_COMPILER_DEBUG_DWARF_DEBUG_INFO_ENTRY_WRITER_H_
229