blob: f34acee647f58072876bca6b07d1cc4cb48e626d [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
20#include "dwarf.h"
21#include "writer.h"
22
23namespace art {
24namespace dwarf {
25
26// Writer for the .debug_line opcodes (DWARF-3).
27// The writer is very light-weight, however it will do the following for you:
28// * Choose the most compact encoding of a given opcode.
29// * Keep track of current state and convert absolute values to deltas.
30// * Divide by header-defined factors as appropriate.
31template<typename Allocator = std::allocator<uint8_t>>
32class DebugLineOpCodeWriter FINAL : private Writer<Allocator> {
33 public:
34 static constexpr int kOpcodeBase = 13;
35 static constexpr bool kDefaultIsStmt = true;
36 static constexpr int kLineBase = -5;
37 static constexpr int kLineRange = 14;
38
39 void AddRow() {
40 this->PushUint8(DW_LNS_copy);
41 }
42
43 void AdvancePC(uint64_t absolute_address) {
44 DCHECK_NE(current_address_, 0u); // Use SetAddress for the first advance.
45 DCHECK_GE(absolute_address, current_address_);
46 if (absolute_address != current_address_) {
47 uint64_t delta = FactorCodeOffset(absolute_address - current_address_);
48 if (delta <= INT32_MAX) {
49 this->PushUint8(DW_LNS_advance_pc);
50 this->PushUleb128(static_cast<int>(delta));
51 current_address_ = absolute_address;
52 } else {
53 SetAddress(absolute_address);
54 }
55 }
56 }
57
58 void AdvanceLine(int absolute_line) {
59 int delta = absolute_line - current_line_;
60 if (delta != 0) {
61 this->PushUint8(DW_LNS_advance_line);
62 this->PushSleb128(delta);
63 current_line_ = absolute_line;
64 }
65 }
66
67 void SetFile(int file) {
68 if (current_file_ != file) {
69 this->PushUint8(DW_LNS_set_file);
70 this->PushUleb128(file);
71 current_file_ = file;
72 }
73 }
74
75 void SetColumn(int column) {
76 this->PushUint8(DW_LNS_set_column);
77 this->PushUleb128(column);
78 }
79
80 void NegateStmt() {
81 this->PushUint8(DW_LNS_negate_stmt);
82 }
83
84 void SetBasicBlock() {
85 this->PushUint8(DW_LNS_set_basic_block);
86 }
87
88 void SetPrologueEnd() {
89 uses_dwarf3_features_ = true;
90 this->PushUint8(DW_LNS_set_prologue_end);
91 }
92
93 void SetEpilogueBegin() {
94 uses_dwarf3_features_ = true;
95 this->PushUint8(DW_LNS_set_epilogue_begin);
96 }
97
98 void SetISA(int isa) {
99 uses_dwarf3_features_ = true;
100 this->PushUint8(DW_LNS_set_isa);
101 this->PushUleb128(isa);
102 }
103
104 void EndSequence() {
105 this->PushUint8(0);
106 this->PushUleb128(1);
107 this->PushUint8(DW_LNE_end_sequence);
108 current_address_ = 0;
109 current_file_ = 1;
110 current_line_ = 1;
111 }
112
113 // Uncoditionally set address using the long encoding.
114 // This gives the linker opportunity to relocate the address.
115 void SetAddress(uint64_t absolute_address) {
116 DCHECK_GE(absolute_address, current_address_);
117 FactorCodeOffset(absolute_address); // Check if it is factorable.
118 this->PushUint8(0);
119 if (use_64bit_address_) {
120 this->PushUleb128(1 + 8);
121 this->PushUint8(DW_LNE_set_address);
122 this->PushUint64(absolute_address);
123 } else {
124 this->PushUleb128(1 + 4);
125 this->PushUint8(DW_LNE_set_address);
126 this->PushUint32(absolute_address);
127 }
128 current_address_ = absolute_address;
129 }
130
131 void DefineFile(const char* filename,
132 int directory_index,
133 int modification_time,
134 int file_size) {
135 int size = 1 +
136 strlen(filename) + 1 +
137 UnsignedLeb128Size(directory_index) +
138 UnsignedLeb128Size(modification_time) +
139 UnsignedLeb128Size(file_size);
140 this->PushUint8(0);
141 this->PushUleb128(size);
142 size_t start = data()->size();
143 this->PushUint8(DW_LNE_define_file);
144 this->PushString(filename);
145 this->PushUleb128(directory_index);
146 this->PushUleb128(modification_time);
147 this->PushUleb128(file_size);
148 DCHECK_EQ(start + size, data()->size());
149 }
150
151 // Compact address and line opcode.
152 void AddRow(uint64_t absolute_address, int absolute_line) {
153 DCHECK_GE(absolute_address, current_address_);
154
155 // If the address is definitely too far, use the long encoding.
156 uint64_t delta_address = FactorCodeOffset(absolute_address - current_address_);
157 if (delta_address > UINT8_MAX) {
158 AdvancePC(absolute_address);
159 delta_address = 0;
160 }
161
162 // If the line is definitely too far, use the long encoding.
163 int delta_line = absolute_line - current_line_;
164 if (!(kLineBase <= delta_line && delta_line < kLineBase + kLineRange)) {
165 AdvanceLine(absolute_line);
166 delta_line = 0;
167 }
168
169 // Both address and line should be reasonable now. Use the short encoding.
170 int opcode = kOpcodeBase + (delta_line - kLineBase) +
171 (static_cast<int>(delta_address) * kLineRange);
172 if (opcode > UINT8_MAX) {
173 // If the address is still too far, try to increment it by const amount.
174 int const_advance = (0xFF - kOpcodeBase) / kLineRange;
175 opcode -= (kLineRange * const_advance);
176 if (opcode <= UINT8_MAX) {
177 this->PushUint8(DW_LNS_const_add_pc);
178 } else {
179 // Give up and use long encoding for address.
180 AdvancePC(absolute_address);
181 // Still use the opcode to do line advance and copy.
182 opcode = kOpcodeBase + (delta_line - kLineBase);
183 }
184 }
185 DCHECK(kOpcodeBase <= opcode && opcode <= 0xFF);
186 this->PushUint8(opcode); // Special opcode.
187 current_line_ = absolute_line;
188 current_address_ = absolute_address;
189 }
190
191 int GetCodeFactorBits() const {
192 return code_factor_bits_;
193 }
194
195 uint64_t CurrentAddress() const {
196 return current_address_;
197 }
198
199 int CurrentFile() const {
200 return current_file_;
201 }
202
203 int CurrentLine() const {
204 return current_line_;
205 }
206
207 using Writer<Allocator>::data;
208
209 DebugLineOpCodeWriter(bool use64bitAddress,
210 int codeFactorBits,
211 const Allocator& alloc = Allocator())
212 : Writer<Allocator>(&opcodes_),
213 opcodes_(alloc),
214 uses_dwarf3_features_(false),
215 use_64bit_address_(use64bitAddress),
216 code_factor_bits_(codeFactorBits),
217 current_address_(0),
218 current_file_(1),
219 current_line_(1) {
220 }
221
222 private:
223 uint64_t FactorCodeOffset(uint64_t offset) const {
224 DCHECK_GE(code_factor_bits_, 0);
225 DCHECK_EQ((offset >> code_factor_bits_) << code_factor_bits_, offset);
226 return offset >> code_factor_bits_;
227 }
228
229 std::vector<uint8_t, Allocator> opcodes_;
230 bool uses_dwarf3_features_;
231 bool use_64bit_address_;
232 int code_factor_bits_;
233 uint64_t current_address_;
234 int current_file_;
235 int current_line_;
236
237 DISALLOW_COPY_AND_ASSIGN(DebugLineOpCodeWriter);
238};
239
240} // namespace dwarf
241} // namespace art
242
243#endif // ART_COMPILER_DWARF_DEBUG_LINE_OPCODE_WRITER_H_