blob: b4a4d63f01362b33b3ee76bda5aca398991c65e0 [file] [log] [blame]
David Srbecky15c19752015-03-31 14:53:55 +00001/*
2 * Copyright (C) 2015 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
David Srbecky4fda4eb2016-02-05 13:34:46 +000017#ifndef ART_COMPILER_DEBUG_DWARF_DEBUG_LINE_OPCODE_WRITER_H_
18#define ART_COMPILER_DEBUG_DWARF_DEBUG_LINE_OPCODE_WRITER_H_
David Srbecky15c19752015-03-31 14:53:55 +000019
David Srbecky2f6cdb02015-04-11 00:17:53 +010020#include <cstdint>
21
David Srbecky4fda4eb2016-02-05 13:34:46 +000022#include "debug/dwarf/dwarf_constants.h"
23#include "debug/dwarf/writer.h"
David Srbecky15c19752015-03-31 14:53:55 +000024
25namespace art {
26namespace dwarf {
27
28// Writer for the .debug_line opcodes (DWARF-3).
29// The writer is very light-weight, however it will do the following for you:
30// * Choose the most compact encoding of a given opcode.
31// * Keep track of current state and convert absolute values to deltas.
32// * Divide by header-defined factors as appropriate.
Vladimir Markoec7802a2015-10-01 20:57:57 +010033template<typename Vector = std::vector<uint8_t>>
34class DebugLineOpCodeWriter FINAL : private Writer<Vector> {
35 static_assert(std::is_same<typename Vector::value_type, uint8_t>::value, "Invalid value type");
36
David Srbecky15c19752015-03-31 14:53:55 +000037 public:
38 static constexpr int kOpcodeBase = 13;
David Srbecky91cc06c2016-03-07 16:13:58 +000039 static constexpr bool kDefaultIsStmt = false;
David Srbecky15c19752015-03-31 14:53:55 +000040 static constexpr int kLineBase = -5;
41 static constexpr int kLineRange = 14;
42
43 void AddRow() {
44 this->PushUint8(DW_LNS_copy);
45 }
46
47 void AdvancePC(uint64_t absolute_address) {
48 DCHECK_NE(current_address_, 0u); // Use SetAddress for the first advance.
49 DCHECK_GE(absolute_address, current_address_);
50 if (absolute_address != current_address_) {
51 uint64_t delta = FactorCodeOffset(absolute_address - current_address_);
52 if (delta <= INT32_MAX) {
53 this->PushUint8(DW_LNS_advance_pc);
54 this->PushUleb128(static_cast<int>(delta));
55 current_address_ = absolute_address;
56 } else {
57 SetAddress(absolute_address);
58 }
59 }
60 }
61
62 void AdvanceLine(int absolute_line) {
63 int delta = absolute_line - current_line_;
64 if (delta != 0) {
65 this->PushUint8(DW_LNS_advance_line);
66 this->PushSleb128(delta);
67 current_line_ = absolute_line;
68 }
69 }
70
71 void SetFile(int file) {
72 if (current_file_ != file) {
73 this->PushUint8(DW_LNS_set_file);
74 this->PushUleb128(file);
75 current_file_ = file;
76 }
77 }
78
79 void SetColumn(int column) {
80 this->PushUint8(DW_LNS_set_column);
81 this->PushUleb128(column);
82 }
83
David Srbecky91cc06c2016-03-07 16:13:58 +000084 void SetIsStmt(bool is_stmt) {
85 if (is_stmt_ != is_stmt) {
86 this->PushUint8(DW_LNS_negate_stmt);
87 is_stmt_ = is_stmt;
88 }
David Srbecky15c19752015-03-31 14:53:55 +000089 }
90
91 void SetBasicBlock() {
92 this->PushUint8(DW_LNS_set_basic_block);
93 }
94
95 void SetPrologueEnd() {
96 uses_dwarf3_features_ = true;
97 this->PushUint8(DW_LNS_set_prologue_end);
98 }
99
100 void SetEpilogueBegin() {
101 uses_dwarf3_features_ = true;
102 this->PushUint8(DW_LNS_set_epilogue_begin);
103 }
104
105 void SetISA(int isa) {
106 uses_dwarf3_features_ = true;
107 this->PushUint8(DW_LNS_set_isa);
108 this->PushUleb128(isa);
109 }
110
111 void EndSequence() {
112 this->PushUint8(0);
113 this->PushUleb128(1);
114 this->PushUint8(DW_LNE_end_sequence);
115 current_address_ = 0;
116 current_file_ = 1;
117 current_line_ = 1;
David Srbecky91cc06c2016-03-07 16:13:58 +0000118 is_stmt_ = kDefaultIsStmt;
David Srbecky15c19752015-03-31 14:53:55 +0000119 }
120
121 // Uncoditionally set address using the long encoding.
122 // This gives the linker opportunity to relocate the address.
123 void SetAddress(uint64_t absolute_address) {
124 DCHECK_GE(absolute_address, current_address_);
125 FactorCodeOffset(absolute_address); // Check if it is factorable.
126 this->PushUint8(0);
127 if (use_64bit_address_) {
128 this->PushUleb128(1 + 8);
129 this->PushUint8(DW_LNE_set_address);
David Srbecky2f6cdb02015-04-11 00:17:53 +0100130 patch_locations_.push_back(this->data()->size());
David Srbecky15c19752015-03-31 14:53:55 +0000131 this->PushUint64(absolute_address);
132 } else {
133 this->PushUleb128(1 + 4);
134 this->PushUint8(DW_LNE_set_address);
David Srbecky2f6cdb02015-04-11 00:17:53 +0100135 patch_locations_.push_back(this->data()->size());
David Srbecky15c19752015-03-31 14:53:55 +0000136 this->PushUint32(absolute_address);
137 }
138 current_address_ = absolute_address;
139 }
140
141 void DefineFile(const char* filename,
142 int directory_index,
143 int modification_time,
144 int file_size) {
145 int size = 1 +
146 strlen(filename) + 1 +
147 UnsignedLeb128Size(directory_index) +
148 UnsignedLeb128Size(modification_time) +
149 UnsignedLeb128Size(file_size);
150 this->PushUint8(0);
151 this->PushUleb128(size);
152 size_t start = data()->size();
153 this->PushUint8(DW_LNE_define_file);
154 this->PushString(filename);
155 this->PushUleb128(directory_index);
156 this->PushUleb128(modification_time);
157 this->PushUleb128(file_size);
158 DCHECK_EQ(start + size, data()->size());
159 }
160
161 // Compact address and line opcode.
162 void AddRow(uint64_t absolute_address, int absolute_line) {
163 DCHECK_GE(absolute_address, current_address_);
164
165 // If the address is definitely too far, use the long encoding.
166 uint64_t delta_address = FactorCodeOffset(absolute_address - current_address_);
167 if (delta_address > UINT8_MAX) {
168 AdvancePC(absolute_address);
169 delta_address = 0;
170 }
171
172 // If the line is definitely too far, use the long encoding.
173 int delta_line = absolute_line - current_line_;
174 if (!(kLineBase <= delta_line && delta_line < kLineBase + kLineRange)) {
175 AdvanceLine(absolute_line);
176 delta_line = 0;
177 }
178
179 // Both address and line should be reasonable now. Use the short encoding.
180 int opcode = kOpcodeBase + (delta_line - kLineBase) +
181 (static_cast<int>(delta_address) * kLineRange);
182 if (opcode > UINT8_MAX) {
183 // If the address is still too far, try to increment it by const amount.
184 int const_advance = (0xFF - kOpcodeBase) / kLineRange;
185 opcode -= (kLineRange * const_advance);
186 if (opcode <= UINT8_MAX) {
187 this->PushUint8(DW_LNS_const_add_pc);
188 } else {
189 // Give up and use long encoding for address.
190 AdvancePC(absolute_address);
191 // Still use the opcode to do line advance and copy.
192 opcode = kOpcodeBase + (delta_line - kLineBase);
193 }
194 }
195 DCHECK(kOpcodeBase <= opcode && opcode <= 0xFF);
196 this->PushUint8(opcode); // Special opcode.
197 current_line_ = absolute_line;
198 current_address_ = absolute_address;
199 }
200
201 int GetCodeFactorBits() const {
202 return code_factor_bits_;
203 }
204
205 uint64_t CurrentAddress() const {
206 return current_address_;
207 }
208
209 int CurrentFile() const {
210 return current_file_;
211 }
212
213 int CurrentLine() const {
214 return current_line_;
215 }
216
David Srbecky2f6cdb02015-04-11 00:17:53 +0100217 const std::vector<uintptr_t>& GetPatchLocations() const {
218 return patch_locations_;
219 }
220
Vladimir Markoec7802a2015-10-01 20:57:57 +0100221 using Writer<Vector>::data;
David Srbecky15c19752015-03-31 14:53:55 +0000222
223 DebugLineOpCodeWriter(bool use64bitAddress,
224 int codeFactorBits,
Vladimir Markoec7802a2015-10-01 20:57:57 +0100225 const typename Vector::allocator_type& alloc =
226 typename Vector::allocator_type())
227 : Writer<Vector>(&opcodes_),
David Srbecky15c19752015-03-31 14:53:55 +0000228 opcodes_(alloc),
229 uses_dwarf3_features_(false),
230 use_64bit_address_(use64bitAddress),
231 code_factor_bits_(codeFactorBits),
232 current_address_(0),
233 current_file_(1),
David Srbecky91cc06c2016-03-07 16:13:58 +0000234 current_line_(1),
235 is_stmt_(kDefaultIsStmt) {
David Srbecky15c19752015-03-31 14:53:55 +0000236 }
237
238 private:
239 uint64_t FactorCodeOffset(uint64_t offset) const {
240 DCHECK_GE(code_factor_bits_, 0);
241 DCHECK_EQ((offset >> code_factor_bits_) << code_factor_bits_, offset);
242 return offset >> code_factor_bits_;
243 }
244
Vladimir Markoec7802a2015-10-01 20:57:57 +0100245 Vector opcodes_;
David Srbecky15c19752015-03-31 14:53:55 +0000246 bool uses_dwarf3_features_;
247 bool use_64bit_address_;
248 int code_factor_bits_;
249 uint64_t current_address_;
250 int current_file_;
251 int current_line_;
David Srbecky91cc06c2016-03-07 16:13:58 +0000252 bool is_stmt_;
David Srbecky2f6cdb02015-04-11 00:17:53 +0100253 std::vector<uintptr_t> patch_locations_;
David Srbecky15c19752015-03-31 14:53:55 +0000254
255 DISALLOW_COPY_AND_ASSIGN(DebugLineOpCodeWriter);
256};
257
258} // namespace dwarf
259} // namespace art
260
David Srbecky4fda4eb2016-02-05 13:34:46 +0000261#endif // ART_COMPILER_DEBUG_DWARF_DEBUG_LINE_OPCODE_WRITER_H_