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
printRegister(raw_ostream & OS,DIDumpOptions DumpOpts,unsigned RegNum)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.
printUnwindLocation(const UnwindLocation & UL,raw_ostream & OS,DIDumpOptions DumpOpts)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
operator <<(raw_ostream & OS,const UnwindLocation & UL)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.
printRegisterLocations(const RegisterLocations & RL,raw_ostream & OS,DIDumpOptions DumpOpts)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
operator <<(raw_ostream & OS,const RegisterLocations & RL)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.
printUnwindRow(const UnwindRow & Row,raw_ostream & OS,DIDumpOptions DumpOpts,unsigned IndentLevel)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
operator <<(raw_ostream & OS,const UnwindRow & Row)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
printUnwindTable(const UnwindTable & Rows,raw_ostream & OS,DIDumpOptions DumpOpts,unsigned IndentLevel)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
operator <<(raw_ostream & OS,const UnwindTable & Rows)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