1 | //===-- DWARFExpression.cpp -----------------------------------------------===// |
2 | // |
3 | // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. |
4 | // See https://llvm.org/LICENSE.txt for license information. |
5 | // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception |
6 | // |
7 | //===----------------------------------------------------------------------===// |
8 | |
9 | #include "llvm/DebugInfo/DWARF/DWARFExpression.h" |
10 | #include "llvm/ADT/SmallString.h" |
11 | #include "llvm/DebugInfo/DWARF/DWARFUnit.h" |
12 | #include "llvm/Support/Format.h" |
13 | #include <cassert> |
14 | #include <cstdint> |
15 | #include <vector> |
16 | |
17 | using namespace llvm; |
18 | using namespace dwarf; |
19 | |
20 | namespace llvm { |
21 | |
22 | typedef DWARFExpression::Operation Op; |
23 | typedef Op::Description Desc; |
24 | |
25 | static std::vector<Desc> getOpDescriptions() { |
26 | std::vector<Desc> Descriptions; |
27 | Descriptions.resize(new_size: 0xff); |
28 | Descriptions[DW_OP_addr] = Desc(Op::Dwarf2, Op::SizeAddr); |
29 | Descriptions[DW_OP_deref] = Desc(Op::Dwarf2); |
30 | Descriptions[DW_OP_const1u] = Desc(Op::Dwarf2, Op::Size1); |
31 | Descriptions[DW_OP_const1s] = Desc(Op::Dwarf2, Op::SignedSize1); |
32 | Descriptions[DW_OP_const2u] = Desc(Op::Dwarf2, Op::Size2); |
33 | Descriptions[DW_OP_const2s] = Desc(Op::Dwarf2, Op::SignedSize2); |
34 | Descriptions[DW_OP_const4u] = Desc(Op::Dwarf2, Op::Size4); |
35 | Descriptions[DW_OP_const4s] = Desc(Op::Dwarf2, Op::SignedSize4); |
36 | Descriptions[DW_OP_const8u] = Desc(Op::Dwarf2, Op::Size8); |
37 | Descriptions[DW_OP_const8s] = Desc(Op::Dwarf2, Op::SignedSize8); |
38 | Descriptions[DW_OP_constu] = Desc(Op::Dwarf2, Op::SizeLEB); |
39 | Descriptions[DW_OP_consts] = Desc(Op::Dwarf2, Op::SignedSizeLEB); |
40 | Descriptions[DW_OP_dup] = Desc(Op::Dwarf2); |
41 | Descriptions[DW_OP_drop] = Desc(Op::Dwarf2); |
42 | Descriptions[DW_OP_over] = Desc(Op::Dwarf2); |
43 | Descriptions[DW_OP_pick] = Desc(Op::Dwarf2, Op::Size1); |
44 | Descriptions[DW_OP_swap] = Desc(Op::Dwarf2); |
45 | Descriptions[DW_OP_rot] = Desc(Op::Dwarf2); |
46 | Descriptions[DW_OP_xderef] = Desc(Op::Dwarf2); |
47 | Descriptions[DW_OP_abs] = Desc(Op::Dwarf2); |
48 | Descriptions[DW_OP_and] = Desc(Op::Dwarf2); |
49 | Descriptions[DW_OP_div] = Desc(Op::Dwarf2); |
50 | Descriptions[DW_OP_minus] = Desc(Op::Dwarf2); |
51 | Descriptions[DW_OP_mod] = Desc(Op::Dwarf2); |
52 | Descriptions[DW_OP_mul] = Desc(Op::Dwarf2); |
53 | Descriptions[DW_OP_neg] = Desc(Op::Dwarf2); |
54 | Descriptions[DW_OP_not] = Desc(Op::Dwarf2); |
55 | Descriptions[DW_OP_or] = Desc(Op::Dwarf2); |
56 | Descriptions[DW_OP_plus] = Desc(Op::Dwarf2); |
57 | Descriptions[DW_OP_plus_uconst] = Desc(Op::Dwarf2, Op::SizeLEB); |
58 | Descriptions[DW_OP_shl] = Desc(Op::Dwarf2); |
59 | Descriptions[DW_OP_shr] = Desc(Op::Dwarf2); |
60 | Descriptions[DW_OP_shra] = Desc(Op::Dwarf2); |
61 | Descriptions[DW_OP_xor] = Desc(Op::Dwarf2); |
62 | Descriptions[DW_OP_skip] = Desc(Op::Dwarf2, Op::SignedSize2); |
63 | Descriptions[DW_OP_bra] = Desc(Op::Dwarf2, Op::SignedSize2); |
64 | Descriptions[DW_OP_eq] = Desc(Op::Dwarf2); |
65 | Descriptions[DW_OP_ge] = Desc(Op::Dwarf2); |
66 | Descriptions[DW_OP_gt] = Desc(Op::Dwarf2); |
67 | Descriptions[DW_OP_le] = Desc(Op::Dwarf2); |
68 | Descriptions[DW_OP_lt] = Desc(Op::Dwarf2); |
69 | Descriptions[DW_OP_ne] = Desc(Op::Dwarf2); |
70 | for (uint16_t LA = DW_OP_lit0; LA <= DW_OP_lit31; ++LA) |
71 | Descriptions[LA] = Desc(Op::Dwarf2); |
72 | for (uint16_t LA = DW_OP_reg0; LA <= DW_OP_reg31; ++LA) |
73 | Descriptions[LA] = Desc(Op::Dwarf2); |
74 | for (uint16_t LA = DW_OP_breg0; LA <= DW_OP_breg31; ++LA) |
75 | Descriptions[LA] = Desc(Op::Dwarf2, Op::SignedSizeLEB); |
76 | Descriptions[DW_OP_regx] = Desc(Op::Dwarf2, Op::SizeLEB); |
77 | Descriptions[DW_OP_fbreg] = Desc(Op::Dwarf2, Op::SignedSizeLEB); |
78 | Descriptions[DW_OP_bregx] = Desc(Op::Dwarf2, Op::SizeLEB, Op::SignedSizeLEB); |
79 | Descriptions[DW_OP_piece] = Desc(Op::Dwarf2, Op::SizeLEB); |
80 | Descriptions[DW_OP_deref_size] = Desc(Op::Dwarf2, Op::Size1); |
81 | Descriptions[DW_OP_xderef_size] = Desc(Op::Dwarf2, Op::Size1); |
82 | Descriptions[DW_OP_nop] = Desc(Op::Dwarf2); |
83 | Descriptions[DW_OP_push_object_address] = Desc(Op::Dwarf3); |
84 | Descriptions[DW_OP_call2] = Desc(Op::Dwarf3, Op::Size2); |
85 | Descriptions[DW_OP_call4] = Desc(Op::Dwarf3, Op::Size4); |
86 | Descriptions[DW_OP_call_ref] = Desc(Op::Dwarf3, Op::SizeRefAddr); |
87 | Descriptions[DW_OP_form_tls_address] = Desc(Op::Dwarf3); |
88 | Descriptions[DW_OP_call_frame_cfa] = Desc(Op::Dwarf3); |
89 | Descriptions[DW_OP_bit_piece] = Desc(Op::Dwarf3, Op::SizeLEB, Op::SizeLEB); |
90 | Descriptions[DW_OP_implicit_value] = |
91 | Desc(Op::Dwarf3, Op::SizeLEB, Op::SizeBlock); |
92 | Descriptions[DW_OP_stack_value] = Desc(Op::Dwarf3); |
93 | Descriptions[DW_OP_WASM_location] = |
94 | Desc(Op::Dwarf4, Op::SizeLEB, Op::WasmLocationArg); |
95 | Descriptions[DW_OP_GNU_push_tls_address] = Desc(Op::Dwarf3); |
96 | Descriptions[DW_OP_GNU_addr_index] = Desc(Op::Dwarf4, Op::SizeLEB); |
97 | Descriptions[DW_OP_GNU_const_index] = Desc(Op::Dwarf4, Op::SizeLEB); |
98 | Descriptions[DW_OP_GNU_entry_value] = Desc(Op::Dwarf4, Op::SizeLEB); |
99 | Descriptions[DW_OP_addrx] = Desc(Op::Dwarf5, Op::SizeLEB); |
100 | Descriptions[DW_OP_constx] = Desc(Op::Dwarf5, Op::SizeLEB); |
101 | Descriptions[DW_OP_convert] = Desc(Op::Dwarf5, Op::BaseTypeRef); |
102 | Descriptions[DW_OP_entry_value] = Desc(Op::Dwarf5, Op::SizeLEB); |
103 | Descriptions[DW_OP_regval_type] = |
104 | Desc(Op::Dwarf5, Op::SizeLEB, Op::BaseTypeRef); |
105 | // This Description acts as a marker that getSubOpDesc must be called |
106 | // to fetch the final Description for the operation. Each such final |
107 | // Description must share the same first SizeSubOpLEB operand. |
108 | Descriptions[DW_OP_LLVM_user] = Desc(Op::Dwarf5, Op::SizeSubOpLEB); |
109 | return Descriptions; |
110 | } |
111 | |
112 | static Desc getDescImpl(ArrayRef<Desc> Descriptions, unsigned Opcode) { |
113 | // Handle possible corrupted or unsupported operation. |
114 | if (Opcode >= Descriptions.size()) |
115 | return {}; |
116 | return Descriptions[Opcode]; |
117 | } |
118 | |
119 | static Desc getOpDesc(unsigned Opcode) { |
120 | static std::vector<Desc> Descriptions = getOpDescriptions(); |
121 | return getDescImpl(Descriptions, Opcode); |
122 | } |
123 | |
124 | static std::vector<Desc> getSubOpDescriptions() { |
125 | static constexpr unsigned LlvmUserDescriptionsSize = 1 |
126 | #define HANDLE_DW_OP_LLVM_USEROP(ID, NAME) +1 |
127 | #include "llvm/BinaryFormat/Dwarf.def" |
128 | ; |
129 | std::vector<Desc> Descriptions; |
130 | Descriptions.resize(new_size: LlvmUserDescriptionsSize); |
131 | Descriptions[DW_OP_LLVM_nop] = Desc(Op::Dwarf5, Op::SizeSubOpLEB); |
132 | return Descriptions; |
133 | } |
134 | |
135 | static Desc getSubOpDesc(unsigned Opcode, unsigned SubOpcode) { |
136 | assert(Opcode == DW_OP_LLVM_user); |
137 | static std::vector<Desc> Descriptions = getSubOpDescriptions(); |
138 | return getDescImpl(Descriptions, Opcode: SubOpcode); |
139 | } |
140 | |
141 | bool DWARFExpression::Operation::(DataExtractor Data, |
142 | uint8_t AddressSize, uint64_t Offset, |
143 | std::optional<DwarfFormat> Format) { |
144 | EndOffset = Offset; |
145 | Opcode = Data.getU8(offset_ptr: &Offset); |
146 | |
147 | Desc = getOpDesc(Opcode); |
148 | if (Desc.Version == Operation::DwarfNA) |
149 | return false; |
150 | |
151 | Operands.resize(N: Desc.Op.size()); |
152 | OperandEndOffsets.resize(N: Desc.Op.size()); |
153 | for (unsigned Operand = 0; Operand < Desc.Op.size(); ++Operand) { |
154 | unsigned Size = Desc.Op[Operand]; |
155 | unsigned Signed = Size & Operation::SignBit; |
156 | |
157 | switch (Size & ~Operation::SignBit) { |
158 | case Operation::SizeSubOpLEB: |
159 | assert(Operand == 0 && "SubOp operand must be the first operand" ); |
160 | Operands[Operand] = Data.getULEB128(offset_ptr: &Offset); |
161 | Desc = getSubOpDesc(Opcode, SubOpcode: Operands[Operand]); |
162 | if (Desc.Version == Operation::DwarfNA) |
163 | return false; |
164 | assert(Desc.Op[Operand] == Operation::SizeSubOpLEB && |
165 | "SizeSubOpLEB Description must begin with SizeSubOpLEB operand" ); |
166 | break; |
167 | case Operation::Size1: |
168 | Operands[Operand] = Data.getU8(offset_ptr: &Offset); |
169 | if (Signed) |
170 | Operands[Operand] = (int8_t)Operands[Operand]; |
171 | break; |
172 | case Operation::Size2: |
173 | Operands[Operand] = Data.getU16(offset_ptr: &Offset); |
174 | if (Signed) |
175 | Operands[Operand] = (int16_t)Operands[Operand]; |
176 | break; |
177 | case Operation::Size4: |
178 | Operands[Operand] = Data.getU32(offset_ptr: &Offset); |
179 | if (Signed) |
180 | Operands[Operand] = (int32_t)Operands[Operand]; |
181 | break; |
182 | case Operation::Size8: |
183 | Operands[Operand] = Data.getU64(offset_ptr: &Offset); |
184 | break; |
185 | case Operation::SizeAddr: |
186 | Operands[Operand] = Data.getUnsigned(offset_ptr: &Offset, byte_size: AddressSize); |
187 | break; |
188 | case Operation::SizeRefAddr: |
189 | if (!Format) |
190 | return false; |
191 | Operands[Operand] = |
192 | Data.getUnsigned(offset_ptr: &Offset, byte_size: dwarf::getDwarfOffsetByteSize(Format: *Format)); |
193 | break; |
194 | case Operation::SizeLEB: |
195 | if (Signed) |
196 | Operands[Operand] = Data.getSLEB128(OffsetPtr: &Offset); |
197 | else |
198 | Operands[Operand] = Data.getULEB128(offset_ptr: &Offset); |
199 | break; |
200 | case Operation::BaseTypeRef: |
201 | Operands[Operand] = Data.getULEB128(offset_ptr: &Offset); |
202 | break; |
203 | case Operation::WasmLocationArg: |
204 | assert(Operand == 1); |
205 | switch (Operands[0]) { |
206 | case 0: |
207 | case 1: |
208 | case 2: |
209 | case 4: |
210 | Operands[Operand] = Data.getULEB128(offset_ptr: &Offset); |
211 | break; |
212 | case 3: // global as uint32 |
213 | Operands[Operand] = Data.getU32(offset_ptr: &Offset); |
214 | break; |
215 | default: |
216 | return false; // Unknown Wasm location |
217 | } |
218 | break; |
219 | case Operation::SizeBlock: |
220 | // We need a size, so this cannot be the first operand |
221 | if (Operand == 0) |
222 | return false; |
223 | // Store the offset of the block as the value. |
224 | Operands[Operand] = Offset; |
225 | Offset += Operands[Operand - 1]; |
226 | break; |
227 | default: |
228 | llvm_unreachable("Unknown DWARFExpression Op size" ); |
229 | } |
230 | |
231 | OperandEndOffsets[Operand] = Offset; |
232 | } |
233 | |
234 | EndOffset = Offset; |
235 | return true; |
236 | } |
237 | |
238 | static void prettyPrintBaseTypeRef(DWARFUnit *U, raw_ostream &OS, |
239 | DIDumpOptions DumpOpts, |
240 | ArrayRef<uint64_t> Operands, |
241 | unsigned Operand) { |
242 | assert(Operand < Operands.size() && "operand out of bounds" ); |
243 | if (!U) { |
244 | OS << format(Fmt: " <base_type ref: 0x%" PRIx64 ">" , Vals: Operands[Operand]); |
245 | return; |
246 | } |
247 | auto Die = U->getDIEForOffset(Offset: U->getOffset() + Operands[Operand]); |
248 | if (Die && Die.getTag() == dwarf::DW_TAG_base_type) { |
249 | OS << " (" ; |
250 | if (DumpOpts.Verbose) |
251 | OS << format(Fmt: "0x%08" PRIx64 " -> " , Vals: Operands[Operand]); |
252 | OS << format(Fmt: "0x%08" PRIx64 ")" , Vals: U->getOffset() + Operands[Operand]); |
253 | if (auto Name = dwarf::toString(V: Die.find(Attr: dwarf::DW_AT_name))) |
254 | OS << " \"" << *Name << "\"" ; |
255 | } else { |
256 | OS << format(Fmt: " <invalid base_type ref: 0x%" PRIx64 ">" , Vals: Operands[Operand]); |
257 | } |
258 | } |
259 | |
260 | bool DWARFExpression::prettyPrintRegisterOp(DWARFUnit *U, raw_ostream &OS, |
261 | DIDumpOptions DumpOpts, |
262 | uint8_t Opcode, |
263 | ArrayRef<uint64_t> Operands) { |
264 | if (!DumpOpts.GetNameForDWARFReg) |
265 | return false; |
266 | |
267 | uint64_t DwarfRegNum; |
268 | unsigned OpNum = 0; |
269 | |
270 | if (Opcode == DW_OP_bregx || Opcode == DW_OP_regx || |
271 | Opcode == DW_OP_regval_type) |
272 | DwarfRegNum = Operands[OpNum++]; |
273 | else if (Opcode >= DW_OP_breg0 && Opcode < DW_OP_bregx) |
274 | DwarfRegNum = Opcode - DW_OP_breg0; |
275 | else |
276 | DwarfRegNum = Opcode - DW_OP_reg0; |
277 | |
278 | auto RegName = DumpOpts.GetNameForDWARFReg(DwarfRegNum, DumpOpts.IsEH); |
279 | if (!RegName.empty()) { |
280 | if ((Opcode >= DW_OP_breg0 && Opcode <= DW_OP_breg31) || |
281 | Opcode == DW_OP_bregx) |
282 | OS << ' ' << RegName << format(Fmt: "%+" PRId64, Vals: Operands[OpNum]); |
283 | else |
284 | OS << ' ' << RegName.data(); |
285 | |
286 | if (Opcode == DW_OP_regval_type) |
287 | prettyPrintBaseTypeRef(U, OS, DumpOpts, Operands, Operand: 1); |
288 | return true; |
289 | } |
290 | |
291 | return false; |
292 | } |
293 | |
294 | std::optional<unsigned> DWARFExpression::Operation::getSubCode() const { |
295 | if (!Desc.Op.size() || Desc.Op[0] != Operation::SizeSubOpLEB) |
296 | return std::nullopt; |
297 | return Operands[0]; |
298 | } |
299 | |
300 | bool DWARFExpression::Operation::print(raw_ostream &OS, DIDumpOptions DumpOpts, |
301 | const DWARFExpression *Expr, |
302 | DWARFUnit *U) const { |
303 | if (Error) { |
304 | OS << "<decoding error>" ; |
305 | return false; |
306 | } |
307 | |
308 | StringRef Name = OperationEncodingString(Encoding: Opcode); |
309 | assert(!Name.empty() && "DW_OP has no name!" ); |
310 | OS << Name; |
311 | |
312 | if ((Opcode >= DW_OP_breg0 && Opcode <= DW_OP_breg31) || |
313 | (Opcode >= DW_OP_reg0 && Opcode <= DW_OP_reg31) || |
314 | Opcode == DW_OP_bregx || Opcode == DW_OP_regx || |
315 | Opcode == DW_OP_regval_type) |
316 | if (prettyPrintRegisterOp(U, OS, DumpOpts, Opcode, Operands)) |
317 | return true; |
318 | |
319 | for (unsigned Operand = 0; Operand < Desc.Op.size(); ++Operand) { |
320 | unsigned Size = Desc.Op[Operand]; |
321 | unsigned Signed = Size & Operation::SignBit; |
322 | |
323 | if (Size == Operation::SizeSubOpLEB) { |
324 | StringRef SubName = SubOperationEncodingString(OpEncoding: Opcode, SubOpEncoding: Operands[Operand]); |
325 | assert(!SubName.empty() && "DW_OP SubOp has no name!" ); |
326 | OS << " " << SubName; |
327 | } else if (Size == Operation::BaseTypeRef && U) { |
328 | // For DW_OP_convert the operand may be 0 to indicate that conversion to |
329 | // the generic type should be done. The same holds for DW_OP_reinterpret, |
330 | // which is currently not supported. |
331 | if (Opcode == DW_OP_convert && Operands[Operand] == 0) |
332 | OS << " 0x0" ; |
333 | else |
334 | prettyPrintBaseTypeRef(U, OS, DumpOpts, Operands, Operand); |
335 | } else if (Size == Operation::WasmLocationArg) { |
336 | assert(Operand == 1); |
337 | switch (Operands[0]) { |
338 | case 0: |
339 | case 1: |
340 | case 2: |
341 | case 3: // global as uint32 |
342 | case 4: |
343 | OS << format(Fmt: " 0x%" PRIx64, Vals: Operands[Operand]); |
344 | break; |
345 | default: assert(false); |
346 | } |
347 | } else if (Size == Operation::SizeBlock) { |
348 | uint64_t Offset = Operands[Operand]; |
349 | for (unsigned i = 0; i < Operands[Operand - 1]; ++i) |
350 | OS << format(Fmt: " 0x%02x" , Vals: Expr->Data.getU8(offset_ptr: &Offset)); |
351 | } else { |
352 | if (Signed) |
353 | OS << format(Fmt: " %+" PRId64, Vals: (int64_t)Operands[Operand]); |
354 | else if (Opcode != DW_OP_entry_value && |
355 | Opcode != DW_OP_GNU_entry_value) |
356 | OS << format(Fmt: " 0x%" PRIx64, Vals: Operands[Operand]); |
357 | } |
358 | } |
359 | return true; |
360 | } |
361 | |
362 | void DWARFExpression::print(raw_ostream &OS, DIDumpOptions DumpOpts, |
363 | DWARFUnit *U, bool IsEH) const { |
364 | uint32_t EntryValExprSize = 0; |
365 | uint64_t EntryValStartOffset = 0; |
366 | if (Data.getData().empty()) |
367 | OS << "<empty>" ; |
368 | |
369 | for (auto &Op : *this) { |
370 | DumpOpts.IsEH = IsEH; |
371 | if (!Op.print(OS, DumpOpts, Expr: this, U)) { |
372 | uint64_t FailOffset = Op.getEndOffset(); |
373 | while (FailOffset < Data.getData().size()) |
374 | OS << format(Fmt: " %02x" , Vals: Data.getU8(offset_ptr: &FailOffset)); |
375 | return; |
376 | } |
377 | |
378 | if (Op.getCode() == DW_OP_entry_value || |
379 | Op.getCode() == DW_OP_GNU_entry_value) { |
380 | OS << "(" ; |
381 | EntryValExprSize = Op.getRawOperand(Idx: 0); |
382 | EntryValStartOffset = Op.getEndOffset(); |
383 | continue; |
384 | } |
385 | |
386 | if (EntryValExprSize) { |
387 | EntryValExprSize -= Op.getEndOffset() - EntryValStartOffset; |
388 | if (EntryValExprSize == 0) |
389 | OS << ")" ; |
390 | } |
391 | |
392 | if (Op.getEndOffset() < Data.getData().size()) |
393 | OS << ", " ; |
394 | } |
395 | } |
396 | |
397 | bool DWARFExpression::Operation::verify(const Operation &Op, DWARFUnit *U) { |
398 | for (unsigned Operand = 0; Operand < Op.Desc.Op.size(); ++Operand) { |
399 | unsigned Size = Op.Desc.Op[Operand]; |
400 | |
401 | if (Size == Operation::BaseTypeRef) { |
402 | // For DW_OP_convert the operand may be 0 to indicate that conversion to |
403 | // the generic type should be done, so don't look up a base type in that |
404 | // case. The same holds for DW_OP_reinterpret, which is currently not |
405 | // supported. |
406 | if (Op.Opcode == DW_OP_convert && Op.Operands[Operand] == 0) |
407 | continue; |
408 | auto Die = U->getDIEForOffset(Offset: U->getOffset() + Op.Operands[Operand]); |
409 | if (!Die || Die.getTag() != dwarf::DW_TAG_base_type) |
410 | return false; |
411 | } |
412 | } |
413 | |
414 | return true; |
415 | } |
416 | |
417 | bool DWARFExpression::verify(DWARFUnit *U) { |
418 | for (auto &Op : *this) |
419 | if (!Operation::verify(Op, U)) |
420 | return false; |
421 | |
422 | return true; |
423 | } |
424 | |
425 | /// A user-facing string representation of a DWARF expression. This might be an |
426 | /// Address expression, in which case it will be implicitly dereferenced, or a |
427 | /// Value expression. |
428 | struct PrintedExpr { |
429 | enum ExprKind { |
430 | Address, |
431 | Value, |
432 | }; |
433 | ExprKind Kind; |
434 | SmallString<16> String; |
435 | |
436 | PrintedExpr(ExprKind K = Address) : Kind(K) {} |
437 | }; |
438 | |
439 | static bool printCompactDWARFExpr( |
440 | raw_ostream &OS, DWARFExpression::iterator I, |
441 | const DWARFExpression::iterator E, |
442 | std::function<StringRef(uint64_t RegNum, bool IsEH)> GetNameForDWARFReg = |
443 | nullptr) { |
444 | SmallVector<PrintedExpr, 4> Stack; |
445 | |
446 | while (I != E) { |
447 | const DWARFExpression::Operation &Op = *I; |
448 | uint8_t Opcode = Op.getCode(); |
449 | switch (Opcode) { |
450 | case dwarf::DW_OP_regx: { |
451 | // DW_OP_regx: A register, with the register num given as an operand. |
452 | // Printed as the plain register name. |
453 | uint64_t DwarfRegNum = Op.getRawOperand(Idx: 0); |
454 | auto RegName = GetNameForDWARFReg(DwarfRegNum, false); |
455 | if (RegName.empty()) |
456 | return false; |
457 | raw_svector_ostream S(Stack.emplace_back(Args: PrintedExpr::Value).String); |
458 | S << RegName; |
459 | break; |
460 | } |
461 | case dwarf::DW_OP_bregx: { |
462 | int DwarfRegNum = Op.getRawOperand(Idx: 0); |
463 | int64_t Offset = Op.getRawOperand(Idx: 1); |
464 | auto RegName = GetNameForDWARFReg(DwarfRegNum, false); |
465 | if (RegName.empty()) |
466 | return false; |
467 | raw_svector_ostream S(Stack.emplace_back().String); |
468 | S << RegName; |
469 | if (Offset) |
470 | S << format(Fmt: "%+" PRId64, Vals: Offset); |
471 | break; |
472 | } |
473 | case dwarf::DW_OP_entry_value: |
474 | case dwarf::DW_OP_GNU_entry_value: { |
475 | // DW_OP_entry_value contains a sub-expression which must be rendered |
476 | // separately. |
477 | uint64_t SubExprLength = Op.getRawOperand(Idx: 0); |
478 | DWARFExpression::iterator SubExprEnd = I.skipBytes(Add: SubExprLength); |
479 | ++I; |
480 | raw_svector_ostream S(Stack.emplace_back().String); |
481 | S << "entry(" ; |
482 | printCompactDWARFExpr(OS&: S, I, E: SubExprEnd, GetNameForDWARFReg); |
483 | S << ")" ; |
484 | I = SubExprEnd; |
485 | continue; |
486 | } |
487 | case dwarf::DW_OP_stack_value: { |
488 | // The top stack entry should be treated as the actual value of tne |
489 | // variable, rather than the address of the variable in memory. |
490 | assert(!Stack.empty()); |
491 | Stack.back().Kind = PrintedExpr::Value; |
492 | break; |
493 | } |
494 | case dwarf::DW_OP_nop: { |
495 | break; |
496 | } |
497 | case dwarf::DW_OP_LLVM_user: { |
498 | assert(Op.getSubCode() && *Op.getSubCode() == dwarf::DW_OP_LLVM_nop); |
499 | break; |
500 | } |
501 | default: |
502 | if (Opcode >= dwarf::DW_OP_reg0 && Opcode <= dwarf::DW_OP_reg31) { |
503 | // DW_OP_reg<N>: A register, with the register num implied by the |
504 | // opcode. Printed as the plain register name. |
505 | uint64_t DwarfRegNum = Opcode - dwarf::DW_OP_reg0; |
506 | auto RegName = GetNameForDWARFReg(DwarfRegNum, false); |
507 | if (RegName.empty()) |
508 | return false; |
509 | raw_svector_ostream S(Stack.emplace_back(Args: PrintedExpr::Value).String); |
510 | S << RegName; |
511 | } else if (Opcode >= dwarf::DW_OP_breg0 && |
512 | Opcode <= dwarf::DW_OP_breg31) { |
513 | int DwarfRegNum = Opcode - dwarf::DW_OP_breg0; |
514 | int64_t Offset = Op.getRawOperand(Idx: 0); |
515 | auto RegName = GetNameForDWARFReg(DwarfRegNum, false); |
516 | if (RegName.empty()) |
517 | return false; |
518 | raw_svector_ostream S(Stack.emplace_back().String); |
519 | S << RegName; |
520 | if (Offset) |
521 | S << format(Fmt: "%+" PRId64, Vals: Offset); |
522 | } else { |
523 | // If we hit an unknown operand, we don't know its effect on the stack, |
524 | // so bail out on the whole expression. |
525 | OS << "<unknown op " << dwarf::OperationEncodingString(Encoding: Opcode) << " (" |
526 | << (int)Opcode << ")>" ; |
527 | return false; |
528 | } |
529 | break; |
530 | } |
531 | ++I; |
532 | } |
533 | |
534 | if (Stack.size() != 1) { |
535 | OS << "<stack of size " << Stack.size() << ", expected 1>" ; |
536 | return false; |
537 | } |
538 | |
539 | if (Stack.front().Kind == PrintedExpr::Address) |
540 | OS << "[" << Stack.front().String << "]" ; |
541 | else |
542 | OS << Stack.front().String; |
543 | |
544 | return true; |
545 | } |
546 | |
547 | bool DWARFExpression::printCompact( |
548 | raw_ostream &OS, |
549 | std::function<StringRef(uint64_t RegNum, bool IsEH)> GetNameForDWARFReg) { |
550 | return printCompactDWARFExpr(OS, I: begin(), E: end(), GetNameForDWARFReg); |
551 | } |
552 | |
553 | bool DWARFExpression::operator==(const DWARFExpression &RHS) const { |
554 | if (AddressSize != RHS.AddressSize || Format != RHS.Format) |
555 | return false; |
556 | return Data.getData() == RHS.Data.getData(); |
557 | } |
558 | |
559 | } // namespace llvm |
560 | |