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