1//===- DWARFCFIPrinter.cpp - Print the cfi-portions of .debug_frame -------===//
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/DWARFCFIPrinter.h"
10#include "llvm/DebugInfo/DIContext.h"
11#include "llvm/DebugInfo/DWARF/DWARFDataExtractor.h"
12#include "llvm/DebugInfo/DWARF/DWARFExpressionPrinter.h"
13#include "llvm/DebugInfo/DWARF/LowLevel/DWARFCFIProgram.h"
14#include "llvm/Support/Compiler.h"
15#include "llvm/Support/DataExtractor.h"
16#include "llvm/Support/Errc.h"
17#include "llvm/Support/ErrorHandling.h"
18#include "llvm/Support/Format.h"
19#include "llvm/Support/raw_ostream.h"
20#include <cassert>
21#include <cinttypes>
22#include <cstdint>
23#include <optional>
24
25using namespace llvm;
26using namespace dwarf;
27
28static void printRegister(raw_ostream &OS, const DIDumpOptions &DumpOpts,
29 unsigned RegNum) {
30 if (DumpOpts.GetNameForDWARFReg) {
31 auto RegName = DumpOpts.GetNameForDWARFReg(RegNum, DumpOpts.IsEH);
32 if (!RegName.empty()) {
33 OS << RegName;
34 return;
35 }
36 }
37 OS << "reg" << RegNum;
38}
39
40/// Print \p Opcode's operand number \p OperandIdx which has value \p Operand.
41static void printOperand(raw_ostream &OS, const DIDumpOptions &DumpOpts,
42 const CFIProgram &P,
43 const CFIProgram::Instruction &Instr,
44 unsigned OperandIdx, uint64_t Operand,
45 std::optional<uint64_t> &Address) {
46 assert(OperandIdx < CFIProgram::MaxOperands);
47 uint8_t Opcode = Instr.Opcode;
48 CFIProgram::OperandType Type = P.getOperandTypes()[Opcode][OperandIdx];
49
50 switch (Type) {
51 case CFIProgram::OT_Unset: {
52 OS << " Unsupported " << (OperandIdx ? "second" : "first") << " operand to";
53 auto OpcodeName = P.callFrameString(Opcode);
54 if (!OpcodeName.empty())
55 OS << " " << OpcodeName;
56 else
57 OS << format(Fmt: " Opcode %x", Vals: Opcode);
58 break;
59 }
60 case CFIProgram::OT_None:
61 break;
62 case CFIProgram::OT_Address:
63 OS << format(Fmt: " %" PRIx64, Vals: Operand);
64 Address = Operand;
65 break;
66 case CFIProgram::OT_Offset:
67 // The offsets are all encoded in a unsigned form, but in practice
68 // consumers use them signed. It's most certainly legacy due to
69 // the lack of signed variants in the first Dwarf standards.
70 OS << format(Fmt: " %+" PRId64, Vals: int64_t(Operand));
71 break;
72 case CFIProgram::OT_FactoredCodeOffset: // Always Unsigned
73 if (P.codeAlign())
74 OS << format(Fmt: " %" PRId64, Vals: Operand * P.codeAlign());
75 else
76 OS << format(Fmt: " %" PRId64 "*code_alignment_factor", Vals: Operand);
77 if (Address && P.codeAlign()) {
78 *Address += Operand * P.codeAlign();
79 OS << format(Fmt: " to 0x%" PRIx64, Vals: *Address);
80 }
81 break;
82 case CFIProgram::OT_SignedFactDataOffset:
83 if (P.dataAlign())
84 OS << format(Fmt: " %" PRId64, Vals: int64_t(Operand) * P.dataAlign());
85 else
86 OS << format(Fmt: " %" PRId64 "*data_alignment_factor", Vals: int64_t(Operand));
87 break;
88 case CFIProgram::OT_UnsignedFactDataOffset:
89 if (P.dataAlign())
90 OS << format(Fmt: " %" PRId64, Vals: Operand * P.dataAlign());
91 else
92 OS << format(Fmt: " %" PRId64 "*data_alignment_factor", Vals: Operand);
93 break;
94 case CFIProgram::OT_Register:
95 OS << ' ';
96 printRegister(OS, DumpOpts, RegNum: Operand);
97 break;
98 case CFIProgram::OT_AddressSpace:
99 OS << format(Fmt: " in addrspace%" PRId64, Vals: Operand);
100 break;
101 case CFIProgram::OT_Expression:
102 assert(Instr.Expression && "missing DWARFExpression object");
103 OS << " ";
104 printDwarfExpression(E: &Instr.Expression.value(), OS, DumpOpts, U: nullptr);
105 break;
106 }
107}
108
109void llvm::dwarf::printCFIProgram(const CFIProgram &P, raw_ostream &OS,
110 const DIDumpOptions &DumpOpts,
111 unsigned IndentLevel,
112 std::optional<uint64_t> Address) {
113 for (const auto &Instr : P) {
114 uint8_t Opcode = Instr.Opcode;
115 OS.indent(NumSpaces: 2 * IndentLevel);
116 OS << P.callFrameString(Opcode) << ":";
117 for (size_t i = 0; i < Instr.Ops.size(); ++i)
118 printOperand(OS, DumpOpts, P, Instr, OperandIdx: i, Operand: Instr.Ops[i], Address);
119 OS << '\n';
120 }
121}
122