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/Format.h"
15#include "llvm/Support/raw_ostream.h"
16#include <cassert>
17#include <cinttypes>
18#include <cstdint>
19
20using namespace llvm;
21using namespace dwarf;
22
23static 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.
49static 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, RegNum: 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(E: &Expr, OS, DumpOpts, U: nullptr);
85 }
86 break;
87 }
88 case UnwindLocation::Constant:
89 OS << UL.getOffset();
90 break;
91 }
92 if (UL.getDereference())
93 OS << ']';
94}
95
96raw_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.
117static void printRegisterLocations(const RegisterLocations &RL, raw_ostream &OS,
118 DIDumpOptions DumpOpts) {
119 ListSeparator LS;
120 for (uint32_t Reg : RL.getRegisters()) {
121 auto Loc = *RL.getRegisterLocation(RegNum: Reg);
122 OS << LS;
123 printRegister(OS, DumpOpts, RegNum: Reg);
124 OS << '=';
125 printUnwindLocation(UL: Loc, OS, DumpOpts);
126 }
127}
128
129raw_ostream &llvm::dwarf::operator<<(raw_ostream &OS,
130 const RegisterLocations &RL) {
131 auto DumpOpts = DIDumpOptions();
132 printRegisterLocations(RL, OS, DumpOpts);
133 return OS;
134}
135
136/// Print an UnwindRow to the stream.
137///
138/// \param Row the UnwindRow to print.
139///
140/// \param OS the stream to use for output.
141///
142/// \param MRI register information that helps emit register names insteead
143/// of raw register numbers.
144///
145/// \param IsEH true if the DWARF Call Frame Information is from .eh_frame
146/// instead of from .debug_frame. This is needed for register number
147/// conversion because some register numbers differ between the two sections
148/// for certain architectures like x86.
149///
150/// \param IndentLevel specify the indent level as an integer. The UnwindRow
151/// will be output to the stream preceded by 2 * IndentLevel number of spaces.
152static void printUnwindRow(const UnwindRow &Row, raw_ostream &OS,
153 DIDumpOptions DumpOpts, unsigned IndentLevel) {
154 OS.indent(NumSpaces: 2 * IndentLevel);
155 if (Row.hasAddress())
156 OS << format(Fmt: "0x%" PRIx64 ": ", Vals: Row.getAddress());
157 OS << "CFA=";
158 printUnwindLocation(UL: Row.getCFAValue(), OS, DumpOpts);
159 if (Row.getRegisterLocations().hasLocations()) {
160 OS << ": ";
161 printRegisterLocations(RL: Row.getRegisterLocations(), OS, DumpOpts);
162 }
163 OS << "\n";
164}
165
166raw_ostream &llvm::dwarf::operator<<(raw_ostream &OS, const UnwindRow &Row) {
167 auto DumpOpts = DIDumpOptions();
168 printUnwindRow(Row, OS, DumpOpts, IndentLevel: 0);
169 return OS;
170}
171
172void llvm::dwarf::printUnwindTable(const UnwindTable &Rows, raw_ostream &OS,
173 DIDumpOptions DumpOpts,
174 unsigned IndentLevel) {
175 for (const UnwindRow &Row : Rows)
176 printUnwindRow(Row, OS, DumpOpts, IndentLevel);
177}
178
179raw_ostream &llvm::dwarf::operator<<(raw_ostream &OS, const UnwindTable &Rows) {
180 auto DumpOpts = DIDumpOptions();
181 printUnwindTable(Rows, OS, DumpOpts, IndentLevel: 0);
182 return OS;
183}
184