xref: /freebsd/contrib/llvm-project/llvm/lib/DebugInfo/DWARF/DWARFUnwindTablePrinter.cpp (revision 95b4436e989df29f6368f13832cb13d7cbc52eac)
1 //===----------------------------------------------------------------------===//
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/DWARFUnwindTablePrinter.h"
10 #include "llvm/DebugInfo/DIContext.h"
11 #include "llvm/DebugInfo/DWARF/DWARFExpressionPrinter.h"
12 #include "llvm/Support/ErrorHandling.h"
13 #include "llvm/Support/Format.h"
14 #include "llvm/Support/raw_ostream.h"
15 #include <cassert>
16 #include <cinttypes>
17 #include <cstdint>
18 #include <optional>
19 
20 using namespace llvm;
21 using namespace dwarf;
22 
23 static void printRegister(raw_ostream &OS, DIDumpOptions DumpOpts,
24                           unsigned RegNum) {
25   if (DumpOpts.GetNameForDWARFReg) {
26     auto RegName = DumpOpts.GetNameForDWARFReg(RegNum, DumpOpts.IsEH);
27     if (!RegName.empty()) {
28       OS << RegName;
29       return;
30     }
31   }
32   OS << "reg" << RegNum;
33 }
34 
35 /// Print an unwind location expression as text and use the register information
36 /// if some is provided.
37 ///
38 /// \param R the unwind location to print.
39 ///
40 /// \param OS the stream to use for output.
41 ///
42 /// \param MRI register information that helps emit register names insteead
43 /// of raw register numbers.
44 ///
45 /// \param IsEH true if the DWARF Call Frame Information is from .eh_frame
46 /// instead of from .debug_frame. This is needed for register number
47 /// conversion because some register numbers differ between the two sections
48 /// for certain architectures like x86.
49 static void printUnwindLocation(const UnwindLocation &UL, raw_ostream &OS,
50                                 DIDumpOptions DumpOpts) {
51   if (UL.getDereference())
52     OS << '[';
53   switch (UL.getLocation()) {
54   case UnwindLocation::Unspecified:
55     OS << "unspecified";
56     break;
57   case UnwindLocation::Undefined:
58     OS << "undefined";
59     break;
60   case UnwindLocation::Same:
61     OS << "same";
62     break;
63   case UnwindLocation::CFAPlusOffset:
64     OS << "CFA";
65     if (UL.getOffset() == 0)
66       break;
67     if (UL.getOffset() > 0)
68       OS << "+";
69     OS << UL.getOffset();
70     break;
71   case UnwindLocation::RegPlusOffset:
72     printRegister(OS, DumpOpts, UL.getRegister());
73     if (UL.getOffset() == 0 && !UL.hasAddressSpace())
74       break;
75     if (UL.getOffset() >= 0)
76       OS << "+";
77     OS << UL.getOffset();
78     if (UL.hasAddressSpace())
79       OS << " in addrspace" << UL.getAddressSpace();
80     break;
81   case UnwindLocation::DWARFExpr: {
82     if (UL.getDWARFExpressionBytes()) {
83       auto Expr = *UL.getDWARFExpressionBytes();
84       printDwarfExpression(&Expr, OS, DumpOpts, nullptr);
85     }
86     break;
87   }
88   case UnwindLocation::Constant:
89     OS << UL.getOffset();
90     break;
91   }
92   if (UL.getDereference())
93     OS << ']';
94 }
95 
96 raw_ostream &llvm::dwarf::operator<<(raw_ostream &OS,
97                                      const UnwindLocation &UL) {
98   auto DumpOpts = DIDumpOptions();
99   printUnwindLocation(UL, OS, DumpOpts);
100   return OS;
101 }
102 
103 /// Print all registers + locations that are currently defined in a register
104 /// locations.
105 ///
106 /// \param RL the register locations to print.
107 ///
108 /// \param OS the stream to use for output.
109 ///
110 /// \param MRI register information that helps emit register names insteead
111 /// of raw register numbers.
112 ///
113 /// \param IsEH true if the DWARF Call Frame Information is from .eh_frame
114 /// instead of from .debug_frame. This is needed for register number
115 /// conversion because some register numbers differ between the two sections
116 /// for certain architectures like x86.
117 static void printRegisterLocations(const RegisterLocations &RL, raw_ostream &OS,
118                                    DIDumpOptions DumpOpts) {
119   bool First = true;
120   for (uint32_t Reg : RL.getRegisters()) {
121     auto Loc = *RL.getRegisterLocation(Reg);
122     if (First)
123       First = false;
124     else
125       OS << ", ";
126     printRegister(OS, DumpOpts, Reg);
127     OS << '=';
128     printUnwindLocation(Loc, OS, DumpOpts);
129   }
130 }
131 
132 raw_ostream &llvm::dwarf::operator<<(raw_ostream &OS,
133                                      const RegisterLocations &RL) {
134   auto DumpOpts = DIDumpOptions();
135   printRegisterLocations(RL, OS, DumpOpts);
136   return OS;
137 }
138 
139 /// Print an UnwindRow to the stream.
140 ///
141 /// \param Row the UnwindRow to print.
142 ///
143 /// \param OS the stream to use for output.
144 ///
145 /// \param MRI register information that helps emit register names insteead
146 /// of raw register numbers.
147 ///
148 /// \param IsEH true if the DWARF Call Frame Information is from .eh_frame
149 /// instead of from .debug_frame. This is needed for register number
150 /// conversion because some register numbers differ between the two sections
151 /// for certain architectures like x86.
152 ///
153 /// \param IndentLevel specify the indent level as an integer. The UnwindRow
154 /// will be output to the stream preceded by 2 * IndentLevel number of spaces.
155 static void printUnwindRow(const UnwindRow &Row, raw_ostream &OS,
156                            DIDumpOptions DumpOpts, unsigned IndentLevel) {
157   OS.indent(2 * IndentLevel);
158   if (Row.hasAddress())
159     OS << format("0x%" PRIx64 ": ", Row.getAddress());
160   OS << "CFA=";
161   printUnwindLocation(Row.getCFAValue(), OS, DumpOpts);
162   if (Row.getRegisterLocations().hasLocations()) {
163     OS << ": ";
164     printRegisterLocations(Row.getRegisterLocations(), OS, DumpOpts);
165   }
166   OS << "\n";
167 }
168 
169 raw_ostream &llvm::dwarf::operator<<(raw_ostream &OS, const UnwindRow &Row) {
170   auto DumpOpts = DIDumpOptions();
171   printUnwindRow(Row, OS, DumpOpts, 0);
172   return OS;
173 }
174 
175 void llvm::dwarf::printUnwindTable(const UnwindTable &Rows, raw_ostream &OS,
176                                    DIDumpOptions DumpOpts,
177                                    unsigned IndentLevel) {
178   for (const UnwindRow &Row : Rows)
179     printUnwindRow(Row, OS, DumpOpts, IndentLevel);
180 }
181 
182 raw_ostream &llvm::dwarf::operator<<(raw_ostream &OS, const UnwindTable &Rows) {
183   auto DumpOpts = DIDumpOptions();
184   printUnwindTable(Rows, OS, DumpOpts, 0);
185   return OS;
186 }
187