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