xref: /freebsd/contrib/llvm-project/llvm/lib/DebugInfo/DWARF/DWARFCFIPrinter.cpp (revision 1342eb5a832fa10e689a29faab3acb6054e4778c)
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 
25 using namespace llvm;
26 using namespace dwarf;
27 
28 static 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.
41 static 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(" Opcode %x", Opcode);
58     break;
59   }
60   case CFIProgram::OT_None:
61     break;
62   case CFIProgram::OT_Address:
63     OS << format(" %" PRIx64, 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(" %+" PRId64, int64_t(Operand));
71     break;
72   case CFIProgram::OT_FactoredCodeOffset: // Always Unsigned
73     if (P.codeAlign())
74       OS << format(" %" PRId64, Operand * P.codeAlign());
75     else
76       OS << format(" %" PRId64 "*code_alignment_factor", Operand);
77     if (Address && P.codeAlign()) {
78       *Address += Operand * P.codeAlign();
79       OS << format(" to 0x%" PRIx64, *Address);
80     }
81     break;
82   case CFIProgram::OT_SignedFactDataOffset:
83     if (P.dataAlign())
84       OS << format(" %" PRId64, int64_t(Operand) * P.dataAlign());
85     else
86       OS << format(" %" PRId64 "*data_alignment_factor", int64_t(Operand));
87     break;
88   case CFIProgram::OT_UnsignedFactDataOffset:
89     if (P.dataAlign())
90       OS << format(" %" PRId64, Operand * P.dataAlign());
91     else
92       OS << format(" %" PRId64 "*data_alignment_factor", Operand);
93     break;
94   case CFIProgram::OT_Register:
95     OS << ' ';
96     printRegister(OS, DumpOpts, Operand);
97     break;
98   case CFIProgram::OT_AddressSpace:
99     OS << format(" in addrspace%" PRId64, Operand);
100     break;
101   case CFIProgram::OT_Expression:
102     assert(Instr.Expression && "missing DWARFExpression object");
103     OS << " ";
104     printDwarfExpression(&Instr.Expression.value(), OS, DumpOpts, nullptr);
105     break;
106   }
107 }
108 
109 void 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(2 * IndentLevel);
116     OS << P.callFrameString(Opcode) << ":";
117     for (size_t i = 0; i < Instr.Ops.size(); ++i)
118       printOperand(OS, DumpOpts, P, Instr, i, Instr.Ops[i], Address);
119     OS << '\n';
120   }
121 }
122