xref: /freebsd/contrib/llvm-project/llvm/lib/DebugInfo/DWARF/DWARFExpressionPrinter.cpp (revision 770cf0a5f02dc8983a89c6568d741fbc25baa999)
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/DWARFExpressionPrinter.h"
10 #include "llvm/ADT/SmallString.h"
11 #include "llvm/DebugInfo/DWARF/DWARFUnit.h"
12 #include "llvm/DebugInfo/DWARF/LowLevel/DWARFExpression.h"
13 #include "llvm/Support/Format.h"
14 #include <cassert>
15 #include <cstdint>
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 void prettyPrintBaseTypeRef(DWARFUnit *U, raw_ostream &OS,
26                                    DIDumpOptions DumpOpts,
27                                    ArrayRef<uint64_t> Operands,
28                                    unsigned Operand) {
29   assert(Operand < Operands.size() && "operand out of bounds");
30   if (!U) {
31     OS << format(" <base_type ref: 0x%" PRIx64 ">", Operands[Operand]);
32     return;
33   }
34   auto Die = U->getDIEForOffset(U->getOffset() + Operands[Operand]);
35   if (Die && Die.getTag() == dwarf::DW_TAG_base_type) {
36     OS << " (";
37     if (DumpOpts.Verbose)
38       OS << format("0x%08" PRIx64 " -> ", Operands[Operand]);
39     OS << format("0x%08" PRIx64 ")", U->getOffset() + Operands[Operand]);
40     if (auto Name = dwarf::toString(Die.find(dwarf::DW_AT_name)))
41       OS << " \"" << *Name << "\"";
42   } else {
43     OS << format(" <invalid base_type ref: 0x%" PRIx64 ">", Operands[Operand]);
44   }
45 }
46 
47 static bool printOp(const DWARFExpression::Operation *Op, raw_ostream &OS,
48                     DIDumpOptions DumpOpts, const DWARFExpression *Expr,
49                     DWARFUnit *U) {
50   if (Op->isError()) {
51     OS << "<decoding error>";
52     return false;
53   }
54 
55   StringRef Name = OperationEncodingString(Op->getCode());
56   assert(!Name.empty() && "DW_OP has no name!");
57   OS << Name;
58 
59   if ((Op->getCode() >= DW_OP_breg0 && Op->getCode() <= DW_OP_breg31) ||
60       (Op->getCode() >= DW_OP_reg0 && Op->getCode() <= DW_OP_reg31) ||
61       Op->getCode() == DW_OP_bregx || Op->getCode() == DW_OP_regx ||
62       Op->getCode() == DW_OP_regval_type)
63     if (prettyPrintRegisterOp(U, OS, DumpOpts, Op->getCode(),
64                               Op->getRawOperands()))
65       return true;
66 
67   for (unsigned Operand = 0; Operand < Op->getDescription().Op.size();
68        ++Operand) {
69     unsigned Size = Op->getDescription().Op[Operand];
70     unsigned Signed = Size & DWARFExpression::Operation::SignBit;
71 
72     if (Size == DWARFExpression::Operation::SizeSubOpLEB) {
73       StringRef SubName =
74           SubOperationEncodingString(Op->getCode(), Op->getRawOperand(Operand));
75       assert(!SubName.empty() && "DW_OP SubOp has no name!");
76       OS << " " << SubName;
77     } else if (Size == DWARFExpression::Operation::BaseTypeRef && U) {
78       // For DW_OP_convert the operand may be 0 to indicate that conversion to
79       // the generic type should be done. The same holds for DW_OP_reinterpret,
80       // which is currently not supported.
81       if (Op->getCode() == DW_OP_convert && Op->getRawOperand(Operand) == 0)
82         OS << " 0x0";
83       else
84         prettyPrintBaseTypeRef(U, OS, DumpOpts, Op->getRawOperands(), Operand);
85     } else if (Size == DWARFExpression::Operation::WasmLocationArg) {
86       assert(Operand == 1);
87       switch (Op->getRawOperand(0)) {
88       case 0:
89       case 1:
90       case 2:
91       case 3: // global as uint32
92       case 4:
93         OS << format(" 0x%" PRIx64, Op->getRawOperand(Operand));
94         break;
95       default:
96         assert(false);
97       }
98     } else if (Size == DWARFExpression::Operation::SizeBlock) {
99       uint64_t Offset = Op->getRawOperand(Operand);
100       for (unsigned i = 0; i < Op->getRawOperand(Operand - 1); ++i)
101         OS << format(" 0x%02x",
102                      static_cast<uint8_t>(Expr->getData()[Offset++]));
103     } else {
104       if (Signed)
105         OS << format(" %+" PRId64, (int64_t)Op->getRawOperand(Operand));
106       else if (Op->getCode() != DW_OP_entry_value &&
107                Op->getCode() != DW_OP_GNU_entry_value)
108         OS << format(" 0x%" PRIx64, Op->getRawOperand(Operand));
109     }
110   }
111   return true;
112 }
113 
114 void printDwarfExpression(const DWARFExpression *E, raw_ostream &OS,
115                           DIDumpOptions DumpOpts, DWARFUnit *U, bool IsEH) {
116   uint32_t EntryValExprSize = 0;
117   uint64_t EntryValStartOffset = 0;
118   if (E->getData().empty())
119     OS << "<empty>";
120 
121   for (auto &Op : *E) {
122     DumpOpts.IsEH = IsEH;
123     if (!printOp(&Op, OS, DumpOpts, E, U)) {
124       uint64_t FailOffset = Op.getEndOffset();
125       while (FailOffset < E->getData().size())
126         OS << format(" %02x", static_cast<uint8_t>(E->getData()[FailOffset++]));
127       return;
128     }
129 
130     if (Op.getCode() == DW_OP_entry_value ||
131         Op.getCode() == DW_OP_GNU_entry_value) {
132       OS << "(";
133       EntryValExprSize = Op.getRawOperand(0);
134       EntryValStartOffset = Op.getEndOffset();
135       continue;
136     }
137 
138     if (EntryValExprSize) {
139       EntryValExprSize -= Op.getEndOffset() - EntryValStartOffset;
140       if (EntryValExprSize == 0)
141         OS << ")";
142     }
143 
144     if (Op.getEndOffset() < E->getData().size())
145       OS << ", ";
146   }
147 }
148 
149 /// A user-facing string representation of a DWARF expression. This might be an
150 /// Address expression, in which case it will be implicitly dereferenced, or a
151 /// Value expression.
152 struct PrintedExpr {
153   enum ExprKind {
154     Address,
155     Value,
156   };
157   ExprKind Kind;
158   SmallString<16> String;
159 
160   PrintedExpr(ExprKind K = Address) : Kind(K) {}
161 };
162 
163 static bool printCompactDWARFExpr(
164     raw_ostream &OS, DWARFExpression::iterator I,
165     const DWARFExpression::iterator E,
166     std::function<StringRef(uint64_t RegNum, bool IsEH)> GetNameForDWARFReg =
167         nullptr) {
168   SmallVector<PrintedExpr, 4> Stack;
169 
170   while (I != E) {
171     const DWARFExpression::Operation &Op = *I;
172     uint8_t Opcode = Op.getCode();
173     switch (Opcode) {
174     case dwarf::DW_OP_regx: {
175       // DW_OP_regx: A register, with the register num given as an operand.
176       // Printed as the plain register name.
177       uint64_t DwarfRegNum = Op.getRawOperand(0);
178       auto RegName = GetNameForDWARFReg(DwarfRegNum, false);
179       if (RegName.empty())
180         return false;
181       raw_svector_ostream S(Stack.emplace_back(PrintedExpr::Value).String);
182       S << RegName;
183       break;
184     }
185     case dwarf::DW_OP_bregx: {
186       int DwarfRegNum = Op.getRawOperand(0);
187       int64_t Offset = Op.getRawOperand(1);
188       auto RegName = GetNameForDWARFReg(DwarfRegNum, false);
189       if (RegName.empty())
190         return false;
191       raw_svector_ostream S(Stack.emplace_back().String);
192       S << RegName;
193       if (Offset)
194         S << format("%+" PRId64, Offset);
195       break;
196     }
197     case dwarf::DW_OP_entry_value:
198     case dwarf::DW_OP_GNU_entry_value: {
199       // DW_OP_entry_value contains a sub-expression which must be rendered
200       // separately.
201       uint64_t SubExprLength = Op.getRawOperand(0);
202       DWARFExpression::iterator SubExprEnd = I.skipBytes(SubExprLength);
203       ++I;
204       raw_svector_ostream S(Stack.emplace_back().String);
205       S << "entry(";
206       printCompactDWARFExpr(S, I, SubExprEnd, GetNameForDWARFReg);
207       S << ")";
208       I = SubExprEnd;
209       continue;
210     }
211     case dwarf::DW_OP_stack_value: {
212       // The top stack entry should be treated as the actual value of tne
213       // variable, rather than the address of the variable in memory.
214       assert(!Stack.empty());
215       Stack.back().Kind = PrintedExpr::Value;
216       break;
217     }
218     case dwarf::DW_OP_nop: {
219       break;
220     }
221     case dwarf::DW_OP_LLVM_user: {
222       assert(Op.getSubCode() == dwarf::DW_OP_LLVM_nop);
223       break;
224     }
225     default:
226       if (Opcode >= dwarf::DW_OP_reg0 && Opcode <= dwarf::DW_OP_reg31) {
227         // DW_OP_reg<N>: A register, with the register num implied by the
228         // opcode. Printed as the plain register name.
229         uint64_t DwarfRegNum = Opcode - dwarf::DW_OP_reg0;
230         auto RegName = GetNameForDWARFReg(DwarfRegNum, false);
231         if (RegName.empty())
232           return false;
233         raw_svector_ostream S(Stack.emplace_back(PrintedExpr::Value).String);
234         S << RegName;
235       } else if (Opcode >= dwarf::DW_OP_breg0 &&
236                  Opcode <= dwarf::DW_OP_breg31) {
237         int DwarfRegNum = Opcode - dwarf::DW_OP_breg0;
238         int64_t Offset = Op.getRawOperand(0);
239         auto RegName = GetNameForDWARFReg(DwarfRegNum, false);
240         if (RegName.empty())
241           return false;
242         raw_svector_ostream S(Stack.emplace_back().String);
243         S << RegName;
244         if (Offset)
245           S << format("%+" PRId64, Offset);
246       } else {
247         // If we hit an unknown operand, we don't know its effect on the stack,
248         // so bail out on the whole expression.
249         OS << "<unknown op " << dwarf::OperationEncodingString(Opcode) << " ("
250            << (int)Opcode << ")>";
251         return false;
252       }
253       break;
254     }
255     ++I;
256   }
257 
258   if (Stack.size() != 1) {
259     OS << "<stack of size " << Stack.size() << ", expected 1>";
260     return false;
261   }
262 
263   if (Stack.front().Kind == PrintedExpr::Address)
264     OS << "[" << Stack.front().String << "]";
265   else
266     OS << Stack.front().String;
267 
268   return true;
269 }
270 
271 bool printDwarfExpressionCompact(
272     const DWARFExpression *E, raw_ostream &OS,
273     std::function<StringRef(uint64_t RegNum, bool IsEH)> GetNameForDWARFReg) {
274   return printCompactDWARFExpr(OS, E->begin(), E->end(), GetNameForDWARFReg);
275 }
276 
277 bool prettyPrintRegisterOp(DWARFUnit *U, raw_ostream &OS,
278                            DIDumpOptions DumpOpts, uint8_t Opcode,
279                            ArrayRef<uint64_t> Operands) {
280   if (!DumpOpts.GetNameForDWARFReg)
281     return false;
282 
283   uint64_t DwarfRegNum;
284   unsigned OpNum = 0;
285 
286   if (Opcode == DW_OP_bregx || Opcode == DW_OP_regx ||
287       Opcode == DW_OP_regval_type)
288     DwarfRegNum = Operands[OpNum++];
289   else if (Opcode >= DW_OP_breg0 && Opcode < DW_OP_bregx)
290     DwarfRegNum = Opcode - DW_OP_breg0;
291   else
292     DwarfRegNum = Opcode - DW_OP_reg0;
293 
294   auto RegName = DumpOpts.GetNameForDWARFReg(DwarfRegNum, DumpOpts.IsEH);
295   if (!RegName.empty()) {
296     if ((Opcode >= DW_OP_breg0 && Opcode <= DW_OP_breg31) ||
297         Opcode == DW_OP_bregx)
298       OS << ' ' << RegName << format("%+" PRId64, Operands[OpNum]);
299     else
300       OS << ' ' << RegName.data();
301 
302     if (Opcode == DW_OP_regval_type)
303       prettyPrintBaseTypeRef(U, OS, DumpOpts, Operands, 1);
304     return true;
305   }
306 
307   return false;
308 }
309 
310 } // namespace llvm
311