blob: 201f0b40bc3bcab7004a312628d31d2ca5346394 [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
17#ifndef ART_COMPILER_DWARF_DEBUG_LINE_OPCODE_WRITER_H_
18#define ART_COMPILER_DWARF_DEBUG_LINE_OPCODE_WRITER_H_
19
David Srbecky2f6cdb02015-04-11 00:17:53 +010020#include <cstdint>
21
David Srbecky7c869b32015-04-12 08:47:47 +010022#include "dwarf/dwarf_constants.h"
23#include "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;
39 static constexpr bool kDefaultIsStmt = true;
40 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
84 void NegateStmt() {
85 this->PushUint8(DW_LNS_negate_stmt);
86 }
87
88 void SetBasicBlock() {
89 this->PushUint8(DW_LNS_set_basic_block);
90 }
91
92 void SetPrologueEnd() {
93 uses_dwarf3_features_ = true;
94 this->PushUint8(DW_LNS_set_prologue_end);
95 }
96
97 void SetEpilogueBegin() {
98 uses_dwarf3_features_ = true;
99 this->PushUint8(DW_LNS_set_epilogue_begin);
100 }
101
102 void SetISA(int isa) {
103 uses_dwarf3_features_ = true;
104 this->PushUint8(DW_LNS_set_isa);
105 this->PushUleb128(isa);
106 }
107
108 void EndSequence() {
109 this->PushUint8(0);
110 this->PushUleb128(1);
111 this->PushUint8(DW_LNE_end_sequence);
112 current_address_ = 0;
113 current_file_ = 1;
114 current_line_ = 1;
115 }
116
117 // Uncoditionally set address using the long encoding.
118 // This gives the linker opportunity to relocate the address.
119 void SetAddress(uint64_t absolute_address) {
120 DCHECK_GE(absolute_address, current_address_);
121 FactorCodeOffset(absolute_address); // Check if it is factorable.
122 this->PushUint8(0);
123 if (use_64bit_address_) {
124 this->PushUleb128(1 + 8);
125 this->PushUint8(DW_LNE_set_address);
David Srbecky2f6cdb02015-04-11 00:17:53 +0100126 patch_locations_.push_back(this->data()->size());
David Srbecky15c19752015-03-31 14:53:55 +0000127 this->PushUint64(absolute_address);
128 } else {
129 this->PushUleb128(1 + 4);
130 this->PushUint8(DW_LNE_set_address);
David Srbecky2f6cdb02015-04-11 00:17:53 +0100131 patch_locations_.push_back(this->data()->size());
David Srbecky15c19752015-03-31 14:53:55 +0000132 this->PushUint32(absolute_address);
133 }
134 current_address_ = absolute_address;
135 }
136
137 void DefineFile(const char* filename,
138 int directory_index,
139 int modification_time,
140 int file_size) {
141 int size = 1 +
142 strlen(filename) + 1 +
143 UnsignedLeb128Size(directory_index) +
144 UnsignedLeb128Size(modification_time) +
145 UnsignedLeb128Size(file_size);
146 this->PushUint8(0);
147 this->PushUleb128(size);
148 size_t start = data()->size();
149 this->PushUint8(DW_LNE_define_file);
150 this->PushString(filename);
151 this->PushUleb128(directory_index);
152 this->PushUleb128(modification_time);
153 this->PushUleb128(file_size);
154 DCHECK_EQ(start + size, data()->size());
155 }
156
157 // Compact address and line opcode.
158 void AddRow(uint64_t absolute_address, int absolute_line) {
159 DCHECK_GE(absolute_address, current_address_);
160
161 // If the address is definitely too far, use the long encoding.
162 uint64_t delta_address = FactorCodeOffset(absolute_address - current_address_);
163 if (delta_address > UINT8_MAX) {
164 AdvancePC(absolute_address);
165 delta_address = 0;
166 }
167
168 // If the line is definitely too far, use the long encoding.
169 int delta_line = absolute_line - current_line_;
170 if (!(kLineBase <= delta_line && delta_line < kLineBase + kLineRange)) {
171 AdvanceLine(absolute_line);
172 delta_line = 0;
173 }
174
175 // Both address and line should be reasonable now. Use the short encoding.
176 int opcode = kOpcodeBase + (delta_line - kLineBase) +
177 (static_cast<int>(delta_address) * kLineRange);
178 if (opcode > UINT8_MAX) {
179 // If the address is still too far, try to increment it by const amount.
180 int const_advance = (0xFF - kOpcodeBase) / kLineRange;
181 opcode -= (kLineRange * const_advance);
182 if (opcode <= UINT8_MAX) {
183 this->PushUint8(DW_LNS_const_add_pc);
184 } else {
185 // Give up and use long encoding for address.
186 AdvancePC(absolute_address);
187 // Still use the opcode to do line advance and copy.
188 opcode = kOpcodeBase + (delta_line - kLineBase);
189 }
190 }
191 DCHECK(kOpcodeBase <= opcode && opcode <= 0xFF);
192 this->PushUint8(opcode); // Special opcode.
193 current_line_ = absolute_line;
194 current_address_ = absolute_address;
195 }
196
197 int GetCodeFactorBits() const {
198 return code_factor_bits_;
199 }
200
201 uint64_t CurrentAddress() const {
202 return current_address_;
203 }
204
205 int CurrentFile() const {
206 return current_file_;
207 }
208
209 int CurrentLine() const {
210 return current_line_;
211 }
212
David Srbecky2f6cdb02015-04-11 00:17:53 +0100213 const std::vector<uintptr_t>& GetPatchLocations() const {
214 return patch_locations_;
215 }
216
Vladimir Markoec7802a2015-10-01 20:57:57 +0100217 using Writer<Vector>::data;
David Srbecky15c19752015-03-31 14:53:55 +0000218
219 DebugLineOpCodeWriter(bool use64bitAddress,
220 int codeFactorBits,
Vladimir Markoec7802a2015-10-01 20:57:57 +0100221 const typename Vector::allocator_type& alloc =
222 typename Vector::allocator_type())
223 : Writer<Vector>(&opcodes_),
David Srbecky15c19752015-03-31 14:53:55 +0000224 opcodes_(alloc),
225 uses_dwarf3_features_(false),
226 use_64bit_address_(use64bitAddress),
227 code_factor_bits_(codeFactorBits),
228 current_address_(0),
229 current_file_(1),
230 current_line_(1) {
231 }
232
233 private:
234 uint64_t FactorCodeOffset(uint64_t offset) const {
235 DCHECK_GE(code_factor_bits_, 0);
236 DCHECK_EQ((offset >> code_factor_bits_) << code_factor_bits_, offset);
237 return offset >> code_factor_bits_;
238 }
239
Vladimir Markoec7802a2015-10-01 20:57:57 +0100240 Vector opcodes_;
David Srbecky15c19752015-03-31 14:53:55 +0000241 bool uses_dwarf3_features_;
242 bool use_64bit_address_;
243 int code_factor_bits_;
244 uint64_t current_address_;
245 int current_file_;
246 int current_line_;
David Srbecky2f6cdb02015-04-11 00:17:53 +0100247 std::vector<uintptr_t> patch_locations_;
David Srbecky15c19752015-03-31 14:53:55 +0000248
249 DISALLOW_COPY_AND_ASSIGN(DebugLineOpCodeWriter);
250};
251
252} // namespace dwarf
253} // namespace art
254
255#endif // ART_COMPILER_DWARF_DEBUG_LINE_OPCODE_WRITER_H_