From 56044015d6a620412e030716dace40fdd544326c Mon Sep 17 00:00:00 2001 From: Sterling Augustine Date: Wed, 7 May 2025 12:47:22 -0700 Subject: [PATCH 1/2] [NFC] Move dwarf::CFIProgram from DWARFDebugFrame.[h,cpp] to its own files This is the first in a series of refactoring PRs to make it possible to parse CFI programs from raw bytes without build-time dependencies on lower-level libraries to provide relocations. Today, CFIProgram and DWARFDataProvider work without relocation providers by using if-statements. But this approach still requires the build-time dependency on the relocation provider. After this series of PRs dwarf::CFIProgram will be usable from the low-level libraries themselves without creating circular dependencies. --- .../llvm/DebugInfo/DWARF/DWARFCFIProgram.h | 151 ++++++ .../llvm/DebugInfo/DWARF/DWARFDebugFrame.h | 131 +----- llvm/lib/DebugInfo/DWARF/CMakeLists.txt | 1 + llvm/lib/DebugInfo/DWARF/DWARFCFIProgram.cpp | 445 ++++++++++++++++++ llvm/lib/DebugInfo/DWARF/DWARFDebugFrame.cpp | 409 +--------------- 5 files changed, 599 insertions(+), 538 deletions(-) create mode 100644 llvm/include/llvm/DebugInfo/DWARF/DWARFCFIProgram.h create mode 100644 llvm/lib/DebugInfo/DWARF/DWARFCFIProgram.cpp diff --git a/llvm/include/llvm/DebugInfo/DWARF/DWARFCFIProgram.h b/llvm/include/llvm/DebugInfo/DWARF/DWARFCFIProgram.h new file mode 100644 index 0000000000000..ef6027eb538fc --- /dev/null +++ b/llvm/include/llvm/DebugInfo/DWARF/DWARFCFIProgram.h @@ -0,0 +1,151 @@ +#ifndef LLVM_DEBUGINFO_DWARF_DWARFDEBUGCFIPROGRAM_H +#define LLVM_DEBUGINFO_DWARF_DWARFDEBUGCFIPROGRAM_H + +#include "llvm/ADT/ArrayRef.h" +#include "llvm/ADT/SmallString.h" +#include "llvm/ADT/iterator.h" +#include "llvm/DebugInfo/DWARF/DWARFDataExtractor.h" +#include "llvm/DebugInfo/DWARF/DWARFExpression.h" +#include "llvm/Support/Error.h" +#include "llvm/TargetParser/Triple.h" +#include +#include +#include + +namespace llvm { + +namespace dwarf { +/// Represent a sequence of Call Frame Information instructions that, when read +/// in order, construct a table mapping PC to frame state. This can also be +/// referred to as "CFI rules" in DWARF literature to avoid confusion with +/// computer programs in the broader sense, and in this context each instruction +/// would be a rule to establish the mapping. Refer to pg. 172 in the DWARF5 +/// manual, "6.4.1 Structure of Call Frame Information". +class CFIProgram { +public: + static constexpr size_t MaxOperands = 3; + typedef SmallVector Operands; + + /// An instruction consists of a DWARF CFI opcode and an optional sequence of + /// operands. If it refers to an expression, then this expression has its own + /// sequence of operations and operands handled separately by DWARFExpression. + struct Instruction { + Instruction(uint8_t Opcode) : Opcode(Opcode) {} + + uint8_t Opcode; + Operands Ops; + // Associated DWARF expression in case this instruction refers to one + std::optional Expression; + + Expected getOperandAsUnsigned(const CFIProgram &CFIP, + uint32_t OperandIdx) const; + + Expected getOperandAsSigned(const CFIProgram &CFIP, + uint32_t OperandIdx) const; + }; + + using InstrList = std::vector; + using iterator = InstrList::iterator; + using const_iterator = InstrList::const_iterator; + + iterator begin() { return Instructions.begin(); } + const_iterator begin() const { return Instructions.begin(); } + iterator end() { return Instructions.end(); } + const_iterator end() const { return Instructions.end(); } + + unsigned size() const { return (unsigned)Instructions.size(); } + bool empty() const { return Instructions.empty(); } + uint64_t codeAlign() const { return CodeAlignmentFactor; } + int64_t dataAlign() const { return DataAlignmentFactor; } + Triple::ArchType triple() const { return Arch; } + + CFIProgram(uint64_t CodeAlignmentFactor, int64_t DataAlignmentFactor, + Triple::ArchType Arch) + : CodeAlignmentFactor(CodeAlignmentFactor), + DataAlignmentFactor(DataAlignmentFactor), + Arch(Arch) {} + + /// Parse and store a sequence of CFI instructions from Data, + /// starting at *Offset and ending at EndOffset. *Offset is updated + /// to EndOffset upon successful parsing, or indicates the offset + /// where a problem occurred in case an error is returned. + Error parse(DWARFDataExtractor Data, uint64_t *Offset, uint64_t EndOffset); + + void dump(raw_ostream &OS, DIDumpOptions DumpOpts, unsigned IndentLevel, + std::optional InitialLocation) const; + + void addInstruction(const Instruction &I) { Instructions.push_back(I); } + + /// Get a DWARF CFI call frame string for the given DW_CFA opcode. + StringRef callFrameString(unsigned Opcode) const; + +private: + std::vector Instructions; + const uint64_t CodeAlignmentFactor; + const int64_t DataAlignmentFactor; + Triple::ArchType Arch; + + /// Convenience method to add a new instruction with the given opcode. + void addInstruction(uint8_t Opcode) { + Instructions.push_back(Instruction(Opcode)); + } + + /// Add a new single-operand instruction. + void addInstruction(uint8_t Opcode, uint64_t Operand1) { + Instructions.push_back(Instruction(Opcode)); + Instructions.back().Ops.push_back(Operand1); + } + + /// Add a new instruction that has two operands. + void addInstruction(uint8_t Opcode, uint64_t Operand1, uint64_t Operand2) { + Instructions.push_back(Instruction(Opcode)); + Instructions.back().Ops.push_back(Operand1); + Instructions.back().Ops.push_back(Operand2); + } + + /// Add a new instruction that has three operands. + void addInstruction(uint8_t Opcode, uint64_t Operand1, uint64_t Operand2, + uint64_t Operand3) { + Instructions.push_back(Instruction(Opcode)); + Instructions.back().Ops.push_back(Operand1); + Instructions.back().Ops.push_back(Operand2); + Instructions.back().Ops.push_back(Operand3); + } + + /// Types of operands to CFI instructions + /// In DWARF, this type is implicitly tied to a CFI instruction opcode and + /// thus this type doesn't need to be explicitly written to the file (this is + /// not a DWARF encoding). The relationship of instrs to operand types can + /// be obtained from getOperandTypes() and is only used to simplify + /// instruction printing. + enum OperandType { + OT_Unset, + OT_None, + OT_Address, + OT_Offset, + OT_FactoredCodeOffset, + OT_SignedFactDataOffset, + OT_UnsignedFactDataOffset, + OT_Register, + OT_AddressSpace, + OT_Expression + }; + + /// Get the OperandType as a "const char *". + static const char *operandTypeString(OperandType OT); + + /// Retrieve the array describing the types of operands according to the enum + /// above. This is indexed by opcode. + static ArrayRef getOperandTypes(); + + /// Print \p Opcode's operand number \p OperandIdx which has value \p Operand. + void printOperand(raw_ostream &OS, DIDumpOptions DumpOpts, + const Instruction &Instr, unsigned OperandIdx, + uint64_t Operand, std::optional &Address) const; +}; + +} // end namespace dwarf + +} // end namespace llvm + +#endif // LLVM_DEBUGINFO_DWARF_DWARFDEBUGCFIPROGRAM_H diff --git a/llvm/include/llvm/DebugInfo/DWARF/DWARFDebugFrame.h b/llvm/include/llvm/DebugInfo/DWARF/DWARFDebugFrame.h index a9a3c7edde691..b4b1e49e68a84 100644 --- a/llvm/include/llvm/DebugInfo/DWARF/DWARFDebugFrame.h +++ b/llvm/include/llvm/DebugInfo/DWARF/DWARFDebugFrame.h @@ -12,6 +12,7 @@ #include "llvm/ADT/ArrayRef.h" #include "llvm/ADT/SmallString.h" #include "llvm/ADT/iterator.h" +#include "llvm/DebugInfo/DWARF/DWARFCFIProgram.h" #include "llvm/DebugInfo/DWARF/DWARFExpression.h" #include "llvm/Support/Error.h" #include "llvm/TargetParser/Triple.h" @@ -309,7 +310,6 @@ class UnwindRow { raw_ostream &operator<<(raw_ostream &OS, const UnwindRow &Row); -class CFIProgram; class CIE; class FDE; @@ -398,135 +398,6 @@ class UnwindTable { raw_ostream &operator<<(raw_ostream &OS, const UnwindTable &Rows); -/// Represent a sequence of Call Frame Information instructions that, when read -/// in order, construct a table mapping PC to frame state. This can also be -/// referred to as "CFI rules" in DWARF literature to avoid confusion with -/// computer programs in the broader sense, and in this context each instruction -/// would be a rule to establish the mapping. Refer to pg. 172 in the DWARF5 -/// manual, "6.4.1 Structure of Call Frame Information". -class CFIProgram { -public: - static constexpr size_t MaxOperands = 3; - typedef SmallVector Operands; - - /// An instruction consists of a DWARF CFI opcode and an optional sequence of - /// operands. If it refers to an expression, then this expression has its own - /// sequence of operations and operands handled separately by DWARFExpression. - struct Instruction { - Instruction(uint8_t Opcode) : Opcode(Opcode) {} - - uint8_t Opcode; - Operands Ops; - // Associated DWARF expression in case this instruction refers to one - std::optional Expression; - - Expected getOperandAsUnsigned(const CFIProgram &CFIP, - uint32_t OperandIdx) const; - - Expected getOperandAsSigned(const CFIProgram &CFIP, - uint32_t OperandIdx) const; - }; - - using InstrList = std::vector; - using iterator = InstrList::iterator; - using const_iterator = InstrList::const_iterator; - - iterator begin() { return Instructions.begin(); } - const_iterator begin() const { return Instructions.begin(); } - iterator end() { return Instructions.end(); } - const_iterator end() const { return Instructions.end(); } - - unsigned size() const { return (unsigned)Instructions.size(); } - bool empty() const { return Instructions.empty(); } - uint64_t codeAlign() const { return CodeAlignmentFactor; } - int64_t dataAlign() const { return DataAlignmentFactor; } - Triple::ArchType triple() const { return Arch; } - - CFIProgram(uint64_t CodeAlignmentFactor, int64_t DataAlignmentFactor, - Triple::ArchType Arch) - : CodeAlignmentFactor(CodeAlignmentFactor), - DataAlignmentFactor(DataAlignmentFactor), - Arch(Arch) {} - - /// Parse and store a sequence of CFI instructions from Data, - /// starting at *Offset and ending at EndOffset. *Offset is updated - /// to EndOffset upon successful parsing, or indicates the offset - /// where a problem occurred in case an error is returned. - Error parse(DWARFDataExtractor Data, uint64_t *Offset, uint64_t EndOffset); - - void dump(raw_ostream &OS, DIDumpOptions DumpOpts, unsigned IndentLevel, - std::optional InitialLocation) const; - - void addInstruction(const Instruction &I) { Instructions.push_back(I); } - - /// Get a DWARF CFI call frame string for the given DW_CFA opcode. - StringRef callFrameString(unsigned Opcode) const; - -private: - std::vector Instructions; - const uint64_t CodeAlignmentFactor; - const int64_t DataAlignmentFactor; - Triple::ArchType Arch; - - /// Convenience method to add a new instruction with the given opcode. - void addInstruction(uint8_t Opcode) { - Instructions.push_back(Instruction(Opcode)); - } - - /// Add a new single-operand instruction. - void addInstruction(uint8_t Opcode, uint64_t Operand1) { - Instructions.push_back(Instruction(Opcode)); - Instructions.back().Ops.push_back(Operand1); - } - - /// Add a new instruction that has two operands. - void addInstruction(uint8_t Opcode, uint64_t Operand1, uint64_t Operand2) { - Instructions.push_back(Instruction(Opcode)); - Instructions.back().Ops.push_back(Operand1); - Instructions.back().Ops.push_back(Operand2); - } - - /// Add a new instruction that has three operands. - void addInstruction(uint8_t Opcode, uint64_t Operand1, uint64_t Operand2, - uint64_t Operand3) { - Instructions.push_back(Instruction(Opcode)); - Instructions.back().Ops.push_back(Operand1); - Instructions.back().Ops.push_back(Operand2); - Instructions.back().Ops.push_back(Operand3); - } - - /// Types of operands to CFI instructions - /// In DWARF, this type is implicitly tied to a CFI instruction opcode and - /// thus this type doesn't need to be explicitly written to the file (this is - /// not a DWARF encoding). The relationship of instrs to operand types can - /// be obtained from getOperandTypes() and is only used to simplify - /// instruction printing. - enum OperandType { - OT_Unset, - OT_None, - OT_Address, - OT_Offset, - OT_FactoredCodeOffset, - OT_SignedFactDataOffset, - OT_UnsignedFactDataOffset, - OT_Register, - OT_AddressSpace, - OT_Expression - }; - - /// Get the OperandType as a "const char *". - static const char *operandTypeString(OperandType OT); - - /// Retrieve the array describing the types of operands according to the enum - /// above. This is indexed by opcode. - static ArrayRef getOperandTypes(); - - /// Print \p Opcode's operand number \p OperandIdx which has value \p Operand. - void printOperand(raw_ostream &OS, DIDumpOptions DumpOpts, - const Instruction &Instr, unsigned OperandIdx, - uint64_t Operand, std::optional &Address) const; -}; - /// An entry in either debug_frame or eh_frame. This entry can be a CIE or an /// FDE. class FrameEntry { diff --git a/llvm/lib/DebugInfo/DWARF/CMakeLists.txt b/llvm/lib/DebugInfo/DWARF/CMakeLists.txt index e565821cf2942..c4bacbdc484f5 100644 --- a/llvm/lib/DebugInfo/DWARF/CMakeLists.txt +++ b/llvm/lib/DebugInfo/DWARF/CMakeLists.txt @@ -2,6 +2,7 @@ add_llvm_component_library(LLVMDebugInfoDWARF DWARFAbbreviationDeclaration.cpp DWARFAddressRange.cpp DWARFAcceleratorTable.cpp + DWARFCFIProgram.cpp DWARFCompileUnit.cpp DWARFContext.cpp DWARFDataExtractor.cpp diff --git a/llvm/lib/DebugInfo/DWARF/DWARFCFIProgram.cpp b/llvm/lib/DebugInfo/DWARF/DWARFCFIProgram.cpp new file mode 100644 index 0000000000000..bffed3f3da305 --- /dev/null +++ b/llvm/lib/DebugInfo/DWARF/DWARFCFIProgram.cpp @@ -0,0 +1,445 @@ +//===- DWARFDebugFrame.h - Parsing of .debug_frame ------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +#include "llvm/DebugInfo/DWARF/DWARFCFIProgram.h" +#include "llvm/DebugInfo/DIContext.h" +#include "llvm/DebugInfo/DWARF/DWARFDataExtractor.h" +#include "llvm/Support/Compiler.h" +#include "llvm/Support/DataExtractor.h" +#include "llvm/Support/Errc.h" +#include "llvm/Support/ErrorHandling.h" +#include "llvm/Support/Format.h" +#include "llvm/Support/raw_ostream.h" +#include +#include +#include +#include + +using namespace llvm; +using namespace dwarf; + +static void printRegister(raw_ostream &OS, DIDumpOptions DumpOpts, + unsigned RegNum) { + if (DumpOpts.GetNameForDWARFReg) { + auto RegName = DumpOpts.GetNameForDWARFReg(RegNum, DumpOpts.IsEH); + if (!RegName.empty()) { + OS << RegName; + return; + } + } + OS << "reg" << RegNum; +} + + +// See DWARF standard v3, section 7.23 +const uint8_t DWARF_CFI_PRIMARY_OPCODE_MASK = 0xc0; +const uint8_t DWARF_CFI_PRIMARY_OPERAND_MASK = 0x3f; + +Error CFIProgram::parse(DWARFDataExtractor Data, uint64_t *Offset, + uint64_t EndOffset) { + DataExtractor::Cursor C(*Offset); + while (C && C.tell() < EndOffset) { + uint8_t Opcode = Data.getRelocatedValue(C, 1); + if (!C) + break; + + // Some instructions have a primary opcode encoded in the top bits. + if (uint8_t Primary = Opcode & DWARF_CFI_PRIMARY_OPCODE_MASK) { + // If it's a primary opcode, the first operand is encoded in the bottom + // bits of the opcode itself. + uint64_t Op1 = Opcode & DWARF_CFI_PRIMARY_OPERAND_MASK; + switch (Primary) { + case DW_CFA_advance_loc: + case DW_CFA_restore: + addInstruction(Primary, Op1); + break; + case DW_CFA_offset: + addInstruction(Primary, Op1, Data.getULEB128(C)); + break; + default: + llvm_unreachable("invalid primary CFI opcode"); + } + continue; + } + + // Extended opcode - its value is Opcode itself. + switch (Opcode) { + default: + return createStringError(errc::illegal_byte_sequence, + "invalid extended CFI opcode 0x%" PRIx8, Opcode); + case DW_CFA_nop: + case DW_CFA_remember_state: + case DW_CFA_restore_state: + case DW_CFA_GNU_window_save: + case DW_CFA_AARCH64_negate_ra_state_with_pc: + // No operands + addInstruction(Opcode); + break; + case DW_CFA_set_loc: + // Operands: Address + addInstruction(Opcode, Data.getRelocatedAddress(C)); + break; + case DW_CFA_advance_loc1: + // Operands: 1-byte delta + addInstruction(Opcode, Data.getRelocatedValue(C, 1)); + break; + case DW_CFA_advance_loc2: + // Operands: 2-byte delta + addInstruction(Opcode, Data.getRelocatedValue(C, 2)); + break; + case DW_CFA_advance_loc4: + // Operands: 4-byte delta + addInstruction(Opcode, Data.getRelocatedValue(C, 4)); + break; + case DW_CFA_restore_extended: + case DW_CFA_undefined: + case DW_CFA_same_value: + case DW_CFA_def_cfa_register: + case DW_CFA_def_cfa_offset: + case DW_CFA_GNU_args_size: + // Operands: ULEB128 + addInstruction(Opcode, Data.getULEB128(C)); + break; + case DW_CFA_def_cfa_offset_sf: + // Operands: SLEB128 + addInstruction(Opcode, Data.getSLEB128(C)); + break; + case DW_CFA_LLVM_def_aspace_cfa: + case DW_CFA_LLVM_def_aspace_cfa_sf: { + auto RegNum = Data.getULEB128(C); + auto CfaOffset = Opcode == DW_CFA_LLVM_def_aspace_cfa + ? Data.getULEB128(C) + : Data.getSLEB128(C); + auto AddressSpace = Data.getULEB128(C); + addInstruction(Opcode, RegNum, CfaOffset, AddressSpace); + break; + } + case DW_CFA_offset_extended: + case DW_CFA_register: + case DW_CFA_def_cfa: + case DW_CFA_val_offset: { + // Operands: ULEB128, ULEB128 + // Note: We can not embed getULEB128 directly into function + // argument list. getULEB128 changes Offset and order of evaluation + // for arguments is unspecified. + uint64_t op1 = Data.getULEB128(C); + uint64_t op2 = Data.getULEB128(C); + addInstruction(Opcode, op1, op2); + break; + } + case DW_CFA_offset_extended_sf: + case DW_CFA_def_cfa_sf: + case DW_CFA_val_offset_sf: { + // Operands: ULEB128, SLEB128 + // Note: see comment for the previous case + uint64_t op1 = Data.getULEB128(C); + uint64_t op2 = (uint64_t)Data.getSLEB128(C); + addInstruction(Opcode, op1, op2); + break; + } + case DW_CFA_def_cfa_expression: { + uint64_t ExprLength = Data.getULEB128(C); + addInstruction(Opcode, 0); + StringRef Expression = Data.getBytes(C, ExprLength); + + DataExtractor Extractor(Expression, Data.isLittleEndian(), + Data.getAddressSize()); + // Note. We do not pass the DWARF format to DWARFExpression, because + // DW_OP_call_ref, the only operation which depends on the format, is + // prohibited in call frame instructions, see sec. 6.4.2 in DWARFv5. + Instructions.back().Expression = + DWARFExpression(Extractor, Data.getAddressSize()); + break; + } + case DW_CFA_expression: + case DW_CFA_val_expression: { + uint64_t RegNum = Data.getULEB128(C); + addInstruction(Opcode, RegNum, 0); + + uint64_t BlockLength = Data.getULEB128(C); + StringRef Expression = Data.getBytes(C, BlockLength); + DataExtractor Extractor(Expression, Data.isLittleEndian(), + Data.getAddressSize()); + // Note. We do not pass the DWARF format to DWARFExpression, because + // DW_OP_call_ref, the only operation which depends on the format, is + // prohibited in call frame instructions, see sec. 6.4.2 in DWARFv5. + Instructions.back().Expression = + DWARFExpression(Extractor, Data.getAddressSize()); + break; + } + } + } + + *Offset = C.tell(); + return C.takeError(); +} + +StringRef CFIProgram::callFrameString(unsigned Opcode) const { + return dwarf::CallFrameString(Opcode, Arch); +} + +const char *CFIProgram::operandTypeString(CFIProgram::OperandType OT) { +#define ENUM_TO_CSTR(e) \ + case e: \ + return #e; + switch (OT) { + ENUM_TO_CSTR(OT_Unset); + ENUM_TO_CSTR(OT_None); + ENUM_TO_CSTR(OT_Address); + ENUM_TO_CSTR(OT_Offset); + ENUM_TO_CSTR(OT_FactoredCodeOffset); + ENUM_TO_CSTR(OT_SignedFactDataOffset); + ENUM_TO_CSTR(OT_UnsignedFactDataOffset); + ENUM_TO_CSTR(OT_Register); + ENUM_TO_CSTR(OT_AddressSpace); + ENUM_TO_CSTR(OT_Expression); + } + return ""; +} + +llvm::Expected +CFIProgram::Instruction::getOperandAsUnsigned(const CFIProgram &CFIP, + uint32_t OperandIdx) const { + if (OperandIdx >= MaxOperands) + return createStringError(errc::invalid_argument, + "operand index %" PRIu32 " is not valid", + OperandIdx); + OperandType Type = CFIP.getOperandTypes()[Opcode][OperandIdx]; + uint64_t Operand = Ops[OperandIdx]; + switch (Type) { + case OT_Unset: + case OT_None: + case OT_Expression: + return createStringError(errc::invalid_argument, + "op[%" PRIu32 "] has type %s which has no value", + OperandIdx, CFIProgram::operandTypeString(Type)); + + case OT_Offset: + case OT_SignedFactDataOffset: + case OT_UnsignedFactDataOffset: + return createStringError( + errc::invalid_argument, + "op[%" PRIu32 "] has OperandType OT_Offset which produces a signed " + "result, call getOperandAsSigned instead", + OperandIdx); + + case OT_Address: + case OT_Register: + case OT_AddressSpace: + return Operand; + + case OT_FactoredCodeOffset: { + const uint64_t CodeAlignmentFactor = CFIP.codeAlign(); + if (CodeAlignmentFactor == 0) + return createStringError( + errc::invalid_argument, + "op[%" PRIu32 "] has type OT_FactoredCodeOffset but code alignment " + "is zero", + OperandIdx); + return Operand * CodeAlignmentFactor; + } + } + llvm_unreachable("invalid operand type"); +} + +llvm::Expected +CFIProgram::Instruction::getOperandAsSigned(const CFIProgram &CFIP, + uint32_t OperandIdx) const { + if (OperandIdx >= MaxOperands) + return createStringError(errc::invalid_argument, + "operand index %" PRIu32 " is not valid", + OperandIdx); + OperandType Type = CFIP.getOperandTypes()[Opcode][OperandIdx]; + uint64_t Operand = Ops[OperandIdx]; + switch (Type) { + case OT_Unset: + case OT_None: + case OT_Expression: + return createStringError(errc::invalid_argument, + "op[%" PRIu32 "] has type %s which has no value", + OperandIdx, CFIProgram::operandTypeString(Type)); + + case OT_Address: + case OT_Register: + case OT_AddressSpace: + return createStringError( + errc::invalid_argument, + "op[%" PRIu32 "] has OperandType %s which produces an unsigned result, " + "call getOperandAsUnsigned instead", + OperandIdx, CFIProgram::operandTypeString(Type)); + + case OT_Offset: + return (int64_t)Operand; + + case OT_FactoredCodeOffset: + case OT_SignedFactDataOffset: { + const int64_t DataAlignmentFactor = CFIP.dataAlign(); + if (DataAlignmentFactor == 0) + return createStringError(errc::invalid_argument, + "op[%" PRIu32 "] has type %s but data " + "alignment is zero", + OperandIdx, CFIProgram::operandTypeString(Type)); + return int64_t(Operand) * DataAlignmentFactor; + } + + case OT_UnsignedFactDataOffset: { + const int64_t DataAlignmentFactor = CFIP.dataAlign(); + if (DataAlignmentFactor == 0) + return createStringError(errc::invalid_argument, + "op[%" PRIu32 + "] has type OT_UnsignedFactDataOffset but data " + "alignment is zero", + OperandIdx); + return Operand * DataAlignmentFactor; + } + } + llvm_unreachable("invalid operand type"); +} + +ArrayRef +CFIProgram::getOperandTypes() { + static OperandType OpTypes[DW_CFA_restore + 1][MaxOperands]; + static bool Initialized = false; + if (Initialized) { + return ArrayRef(&OpTypes[0], DW_CFA_restore + 1); + } + Initialized = true; + +#define DECLARE_OP3(OP, OPTYPE0, OPTYPE1, OPTYPE2) \ + do { \ + OpTypes[OP][0] = OPTYPE0; \ + OpTypes[OP][1] = OPTYPE1; \ + OpTypes[OP][2] = OPTYPE2; \ + } while (false) +#define DECLARE_OP2(OP, OPTYPE0, OPTYPE1) \ + DECLARE_OP3(OP, OPTYPE0, OPTYPE1, OT_None) +#define DECLARE_OP1(OP, OPTYPE0) DECLARE_OP2(OP, OPTYPE0, OT_None) +#define DECLARE_OP0(OP) DECLARE_OP1(OP, OT_None) + + DECLARE_OP1(DW_CFA_set_loc, OT_Address); + DECLARE_OP1(DW_CFA_advance_loc, OT_FactoredCodeOffset); + DECLARE_OP1(DW_CFA_advance_loc1, OT_FactoredCodeOffset); + DECLARE_OP1(DW_CFA_advance_loc2, OT_FactoredCodeOffset); + DECLARE_OP1(DW_CFA_advance_loc4, OT_FactoredCodeOffset); + DECLARE_OP1(DW_CFA_MIPS_advance_loc8, OT_FactoredCodeOffset); + DECLARE_OP2(DW_CFA_def_cfa, OT_Register, OT_Offset); + DECLARE_OP2(DW_CFA_def_cfa_sf, OT_Register, OT_SignedFactDataOffset); + DECLARE_OP1(DW_CFA_def_cfa_register, OT_Register); + DECLARE_OP3(DW_CFA_LLVM_def_aspace_cfa, OT_Register, OT_Offset, + OT_AddressSpace); + DECLARE_OP3(DW_CFA_LLVM_def_aspace_cfa_sf, OT_Register, + OT_SignedFactDataOffset, OT_AddressSpace); + DECLARE_OP1(DW_CFA_def_cfa_offset, OT_Offset); + DECLARE_OP1(DW_CFA_def_cfa_offset_sf, OT_SignedFactDataOffset); + DECLARE_OP1(DW_CFA_def_cfa_expression, OT_Expression); + DECLARE_OP1(DW_CFA_undefined, OT_Register); + DECLARE_OP1(DW_CFA_same_value, OT_Register); + DECLARE_OP2(DW_CFA_offset, OT_Register, OT_UnsignedFactDataOffset); + DECLARE_OP2(DW_CFA_offset_extended, OT_Register, OT_UnsignedFactDataOffset); + DECLARE_OP2(DW_CFA_offset_extended_sf, OT_Register, OT_SignedFactDataOffset); + DECLARE_OP2(DW_CFA_val_offset, OT_Register, OT_UnsignedFactDataOffset); + DECLARE_OP2(DW_CFA_val_offset_sf, OT_Register, OT_SignedFactDataOffset); + DECLARE_OP2(DW_CFA_register, OT_Register, OT_Register); + DECLARE_OP2(DW_CFA_expression, OT_Register, OT_Expression); + DECLARE_OP2(DW_CFA_val_expression, OT_Register, OT_Expression); + DECLARE_OP1(DW_CFA_restore, OT_Register); + DECLARE_OP1(DW_CFA_restore_extended, OT_Register); + DECLARE_OP0(DW_CFA_remember_state); + DECLARE_OP0(DW_CFA_restore_state); + DECLARE_OP0(DW_CFA_GNU_window_save); + DECLARE_OP0(DW_CFA_AARCH64_negate_ra_state_with_pc); + DECLARE_OP1(DW_CFA_GNU_args_size, OT_Offset); + DECLARE_OP0(DW_CFA_nop); + +#undef DECLARE_OP0 +#undef DECLARE_OP1 +#undef DECLARE_OP2 + + return ArrayRef(&OpTypes[0], DW_CFA_restore + 1); +} + +/// Print \p Opcode's operand number \p OperandIdx which has value \p Operand. +void CFIProgram::printOperand(raw_ostream &OS, DIDumpOptions DumpOpts, + const Instruction &Instr, unsigned OperandIdx, + uint64_t Operand, + std::optional &Address) const { + assert(OperandIdx < MaxOperands); + uint8_t Opcode = Instr.Opcode; + OperandType Type = getOperandTypes()[Opcode][OperandIdx]; + + switch (Type) { + case OT_Unset: { + OS << " Unsupported " << (OperandIdx ? "second" : "first") << " operand to"; + auto OpcodeName = callFrameString(Opcode); + if (!OpcodeName.empty()) + OS << " " << OpcodeName; + else + OS << format(" Opcode %x", Opcode); + break; + } + case OT_None: + break; + case OT_Address: + OS << format(" %" PRIx64, Operand); + Address = Operand; + break; + case OT_Offset: + // The offsets are all encoded in a unsigned form, but in practice + // consumers use them signed. It's most certainly legacy due to + // the lack of signed variants in the first Dwarf standards. + OS << format(" %+" PRId64, int64_t(Operand)); + break; + case OT_FactoredCodeOffset: // Always Unsigned + if (CodeAlignmentFactor) + OS << format(" %" PRId64, Operand * CodeAlignmentFactor); + else + OS << format(" %" PRId64 "*code_alignment_factor", Operand); + if (Address && CodeAlignmentFactor) { + *Address += Operand * CodeAlignmentFactor; + OS << format(" to 0x%" PRIx64, *Address); + } + break; + case OT_SignedFactDataOffset: + if (DataAlignmentFactor) + OS << format(" %" PRId64, int64_t(Operand) * DataAlignmentFactor); + else + OS << format(" %" PRId64 "*data_alignment_factor" , int64_t(Operand)); + break; + case OT_UnsignedFactDataOffset: + if (DataAlignmentFactor) + OS << format(" %" PRId64, Operand * DataAlignmentFactor); + else + OS << format(" %" PRId64 "*data_alignment_factor" , Operand); + break; + case OT_Register: + OS << ' '; + printRegister(OS, DumpOpts, Operand); + break; + case OT_AddressSpace: + OS << format(" in addrspace%" PRId64, Operand); + break; + case OT_Expression: + assert(Instr.Expression && "missing DWARFExpression object"); + OS << " "; + Instr.Expression->print(OS, DumpOpts, nullptr); + break; + } +} + +void CFIProgram::dump(raw_ostream &OS, DIDumpOptions DumpOpts, + unsigned IndentLevel, + std::optional Address) const { + for (const auto &Instr : Instructions) { + uint8_t Opcode = Instr.Opcode; + OS.indent(2 * IndentLevel); + OS << callFrameString(Opcode) << ":"; + for (unsigned i = 0; i < Instr.Ops.size(); ++i) + printOperand(OS, DumpOpts, Instr, i, Instr.Ops[i], Address); + OS << '\n'; + } +} diff --git a/llvm/lib/DebugInfo/DWARF/DWARFDebugFrame.cpp b/llvm/lib/DebugInfo/DWARF/DWARFDebugFrame.cpp index 5bdc257fd8d89..aecfc4565dbc2 100644 --- a/llvm/lib/DebugInfo/DWARF/DWARFDebugFrame.cpp +++ b/llvm/lib/DebugInfo/DWARF/DWARFDebugFrame.cpp @@ -12,6 +12,7 @@ #include "llvm/ADT/StringRef.h" #include "llvm/BinaryFormat/Dwarf.h" #include "llvm/DebugInfo/DIContext.h" +#include "llvm/DebugInfo/DWARF/DWARFCFIProgram.h" #include "llvm/DebugInfo/DWARF/DWARFDataExtractor.h" #include "llvm/Support/Compiler.h" #include "llvm/Support/DataExtractor.h" @@ -247,271 +248,6 @@ Expected UnwindTable::create(const CIE *Cie) { return UT; } -// See DWARF standard v3, section 7.23 -const uint8_t DWARF_CFI_PRIMARY_OPCODE_MASK = 0xc0; -const uint8_t DWARF_CFI_PRIMARY_OPERAND_MASK = 0x3f; - -Error CFIProgram::parse(DWARFDataExtractor Data, uint64_t *Offset, - uint64_t EndOffset) { - DataExtractor::Cursor C(*Offset); - while (C && C.tell() < EndOffset) { - uint8_t Opcode = Data.getRelocatedValue(C, 1); - if (!C) - break; - - // Some instructions have a primary opcode encoded in the top bits. - if (uint8_t Primary = Opcode & DWARF_CFI_PRIMARY_OPCODE_MASK) { - // If it's a primary opcode, the first operand is encoded in the bottom - // bits of the opcode itself. - uint64_t Op1 = Opcode & DWARF_CFI_PRIMARY_OPERAND_MASK; - switch (Primary) { - case DW_CFA_advance_loc: - case DW_CFA_restore: - addInstruction(Primary, Op1); - break; - case DW_CFA_offset: - addInstruction(Primary, Op1, Data.getULEB128(C)); - break; - default: - llvm_unreachable("invalid primary CFI opcode"); - } - continue; - } - - // Extended opcode - its value is Opcode itself. - switch (Opcode) { - default: - return createStringError(errc::illegal_byte_sequence, - "invalid extended CFI opcode 0x%" PRIx8, Opcode); - case DW_CFA_nop: - case DW_CFA_remember_state: - case DW_CFA_restore_state: - case DW_CFA_GNU_window_save: - case DW_CFA_AARCH64_negate_ra_state_with_pc: - // No operands - addInstruction(Opcode); - break; - case DW_CFA_set_loc: - // Operands: Address - addInstruction(Opcode, Data.getRelocatedAddress(C)); - break; - case DW_CFA_advance_loc1: - // Operands: 1-byte delta - addInstruction(Opcode, Data.getRelocatedValue(C, 1)); - break; - case DW_CFA_advance_loc2: - // Operands: 2-byte delta - addInstruction(Opcode, Data.getRelocatedValue(C, 2)); - break; - case DW_CFA_advance_loc4: - // Operands: 4-byte delta - addInstruction(Opcode, Data.getRelocatedValue(C, 4)); - break; - case DW_CFA_restore_extended: - case DW_CFA_undefined: - case DW_CFA_same_value: - case DW_CFA_def_cfa_register: - case DW_CFA_def_cfa_offset: - case DW_CFA_GNU_args_size: - // Operands: ULEB128 - addInstruction(Opcode, Data.getULEB128(C)); - break; - case DW_CFA_def_cfa_offset_sf: - // Operands: SLEB128 - addInstruction(Opcode, Data.getSLEB128(C)); - break; - case DW_CFA_LLVM_def_aspace_cfa: - case DW_CFA_LLVM_def_aspace_cfa_sf: { - auto RegNum = Data.getULEB128(C); - auto CfaOffset = Opcode == DW_CFA_LLVM_def_aspace_cfa - ? Data.getULEB128(C) - : Data.getSLEB128(C); - auto AddressSpace = Data.getULEB128(C); - addInstruction(Opcode, RegNum, CfaOffset, AddressSpace); - break; - } - case DW_CFA_offset_extended: - case DW_CFA_register: - case DW_CFA_def_cfa: - case DW_CFA_val_offset: { - // Operands: ULEB128, ULEB128 - // Note: We can not embed getULEB128 directly into function - // argument list. getULEB128 changes Offset and order of evaluation - // for arguments is unspecified. - uint64_t op1 = Data.getULEB128(C); - uint64_t op2 = Data.getULEB128(C); - addInstruction(Opcode, op1, op2); - break; - } - case DW_CFA_offset_extended_sf: - case DW_CFA_def_cfa_sf: - case DW_CFA_val_offset_sf: { - // Operands: ULEB128, SLEB128 - // Note: see comment for the previous case - uint64_t op1 = Data.getULEB128(C); - uint64_t op2 = (uint64_t)Data.getSLEB128(C); - addInstruction(Opcode, op1, op2); - break; - } - case DW_CFA_def_cfa_expression: { - uint64_t ExprLength = Data.getULEB128(C); - addInstruction(Opcode, 0); - StringRef Expression = Data.getBytes(C, ExprLength); - - DataExtractor Extractor(Expression, Data.isLittleEndian(), - Data.getAddressSize()); - // Note. We do not pass the DWARF format to DWARFExpression, because - // DW_OP_call_ref, the only operation which depends on the format, is - // prohibited in call frame instructions, see sec. 6.4.2 in DWARFv5. - Instructions.back().Expression = - DWARFExpression(Extractor, Data.getAddressSize()); - break; - } - case DW_CFA_expression: - case DW_CFA_val_expression: { - uint64_t RegNum = Data.getULEB128(C); - addInstruction(Opcode, RegNum, 0); - - uint64_t BlockLength = Data.getULEB128(C); - StringRef Expression = Data.getBytes(C, BlockLength); - DataExtractor Extractor(Expression, Data.isLittleEndian(), - Data.getAddressSize()); - // Note. We do not pass the DWARF format to DWARFExpression, because - // DW_OP_call_ref, the only operation which depends on the format, is - // prohibited in call frame instructions, see sec. 6.4.2 in DWARFv5. - Instructions.back().Expression = - DWARFExpression(Extractor, Data.getAddressSize()); - break; - } - } - } - - *Offset = C.tell(); - return C.takeError(); -} - -StringRef CFIProgram::callFrameString(unsigned Opcode) const { - return dwarf::CallFrameString(Opcode, Arch); -} - -const char *CFIProgram::operandTypeString(CFIProgram::OperandType OT) { -#define ENUM_TO_CSTR(e) \ - case e: \ - return #e; - switch (OT) { - ENUM_TO_CSTR(OT_Unset); - ENUM_TO_CSTR(OT_None); - ENUM_TO_CSTR(OT_Address); - ENUM_TO_CSTR(OT_Offset); - ENUM_TO_CSTR(OT_FactoredCodeOffset); - ENUM_TO_CSTR(OT_SignedFactDataOffset); - ENUM_TO_CSTR(OT_UnsignedFactDataOffset); - ENUM_TO_CSTR(OT_Register); - ENUM_TO_CSTR(OT_AddressSpace); - ENUM_TO_CSTR(OT_Expression); - } - return ""; -} - -llvm::Expected -CFIProgram::Instruction::getOperandAsUnsigned(const CFIProgram &CFIP, - uint32_t OperandIdx) const { - if (OperandIdx >= MaxOperands) - return createStringError(errc::invalid_argument, - "operand index %" PRIu32 " is not valid", - OperandIdx); - OperandType Type = CFIP.getOperandTypes()[Opcode][OperandIdx]; - uint64_t Operand = Ops[OperandIdx]; - switch (Type) { - case OT_Unset: - case OT_None: - case OT_Expression: - return createStringError(errc::invalid_argument, - "op[%" PRIu32 "] has type %s which has no value", - OperandIdx, CFIProgram::operandTypeString(Type)); - - case OT_Offset: - case OT_SignedFactDataOffset: - case OT_UnsignedFactDataOffset: - return createStringError( - errc::invalid_argument, - "op[%" PRIu32 "] has OperandType OT_Offset which produces a signed " - "result, call getOperandAsSigned instead", - OperandIdx); - - case OT_Address: - case OT_Register: - case OT_AddressSpace: - return Operand; - - case OT_FactoredCodeOffset: { - const uint64_t CodeAlignmentFactor = CFIP.codeAlign(); - if (CodeAlignmentFactor == 0) - return createStringError( - errc::invalid_argument, - "op[%" PRIu32 "] has type OT_FactoredCodeOffset but code alignment " - "is zero", - OperandIdx); - return Operand * CodeAlignmentFactor; - } - } - llvm_unreachable("invalid operand type"); -} - -llvm::Expected -CFIProgram::Instruction::getOperandAsSigned(const CFIProgram &CFIP, - uint32_t OperandIdx) const { - if (OperandIdx >= MaxOperands) - return createStringError(errc::invalid_argument, - "operand index %" PRIu32 " is not valid", - OperandIdx); - OperandType Type = CFIP.getOperandTypes()[Opcode][OperandIdx]; - uint64_t Operand = Ops[OperandIdx]; - switch (Type) { - case OT_Unset: - case OT_None: - case OT_Expression: - return createStringError(errc::invalid_argument, - "op[%" PRIu32 "] has type %s which has no value", - OperandIdx, CFIProgram::operandTypeString(Type)); - - case OT_Address: - case OT_Register: - case OT_AddressSpace: - return createStringError( - errc::invalid_argument, - "op[%" PRIu32 "] has OperandType %s which produces an unsigned result, " - "call getOperandAsUnsigned instead", - OperandIdx, CFIProgram::operandTypeString(Type)); - - case OT_Offset: - return (int64_t)Operand; - - case OT_FactoredCodeOffset: - case OT_SignedFactDataOffset: { - const int64_t DataAlignmentFactor = CFIP.dataAlign(); - if (DataAlignmentFactor == 0) - return createStringError(errc::invalid_argument, - "op[%" PRIu32 "] has type %s but data " - "alignment is zero", - OperandIdx, CFIProgram::operandTypeString(Type)); - return int64_t(Operand) * DataAlignmentFactor; - } - - case OT_UnsignedFactDataOffset: { - const int64_t DataAlignmentFactor = CFIP.dataAlign(); - if (DataAlignmentFactor == 0) - return createStringError(errc::invalid_argument, - "op[%" PRIu32 - "] has type OT_UnsignedFactDataOffset but data " - "alignment is zero", - OperandIdx); - return Operand * DataAlignmentFactor; - } - } - llvm_unreachable("invalid operand type"); -} - Error UnwindTable::parseRows(const CFIProgram &CFIP, UnwindRow &Row, const RegisterLocations *InitialLocs) { // State consists of CFA value and register locations. @@ -818,149 +554,6 @@ Error UnwindTable::parseRows(const CFIProgram &CFIP, UnwindRow &Row, return Error::success(); } -ArrayRef -CFIProgram::getOperandTypes() { - static OperandType OpTypes[DW_CFA_restore + 1][MaxOperands]; - static bool Initialized = false; - if (Initialized) { - return ArrayRef(&OpTypes[0], DW_CFA_restore + 1); - } - Initialized = true; - -#define DECLARE_OP3(OP, OPTYPE0, OPTYPE1, OPTYPE2) \ - do { \ - OpTypes[OP][0] = OPTYPE0; \ - OpTypes[OP][1] = OPTYPE1; \ - OpTypes[OP][2] = OPTYPE2; \ - } while (false) -#define DECLARE_OP2(OP, OPTYPE0, OPTYPE1) \ - DECLARE_OP3(OP, OPTYPE0, OPTYPE1, OT_None) -#define DECLARE_OP1(OP, OPTYPE0) DECLARE_OP2(OP, OPTYPE0, OT_None) -#define DECLARE_OP0(OP) DECLARE_OP1(OP, OT_None) - - DECLARE_OP1(DW_CFA_set_loc, OT_Address); - DECLARE_OP1(DW_CFA_advance_loc, OT_FactoredCodeOffset); - DECLARE_OP1(DW_CFA_advance_loc1, OT_FactoredCodeOffset); - DECLARE_OP1(DW_CFA_advance_loc2, OT_FactoredCodeOffset); - DECLARE_OP1(DW_CFA_advance_loc4, OT_FactoredCodeOffset); - DECLARE_OP1(DW_CFA_MIPS_advance_loc8, OT_FactoredCodeOffset); - DECLARE_OP2(DW_CFA_def_cfa, OT_Register, OT_Offset); - DECLARE_OP2(DW_CFA_def_cfa_sf, OT_Register, OT_SignedFactDataOffset); - DECLARE_OP1(DW_CFA_def_cfa_register, OT_Register); - DECLARE_OP3(DW_CFA_LLVM_def_aspace_cfa, OT_Register, OT_Offset, - OT_AddressSpace); - DECLARE_OP3(DW_CFA_LLVM_def_aspace_cfa_sf, OT_Register, - OT_SignedFactDataOffset, OT_AddressSpace); - DECLARE_OP1(DW_CFA_def_cfa_offset, OT_Offset); - DECLARE_OP1(DW_CFA_def_cfa_offset_sf, OT_SignedFactDataOffset); - DECLARE_OP1(DW_CFA_def_cfa_expression, OT_Expression); - DECLARE_OP1(DW_CFA_undefined, OT_Register); - DECLARE_OP1(DW_CFA_same_value, OT_Register); - DECLARE_OP2(DW_CFA_offset, OT_Register, OT_UnsignedFactDataOffset); - DECLARE_OP2(DW_CFA_offset_extended, OT_Register, OT_UnsignedFactDataOffset); - DECLARE_OP2(DW_CFA_offset_extended_sf, OT_Register, OT_SignedFactDataOffset); - DECLARE_OP2(DW_CFA_val_offset, OT_Register, OT_UnsignedFactDataOffset); - DECLARE_OP2(DW_CFA_val_offset_sf, OT_Register, OT_SignedFactDataOffset); - DECLARE_OP2(DW_CFA_register, OT_Register, OT_Register); - DECLARE_OP2(DW_CFA_expression, OT_Register, OT_Expression); - DECLARE_OP2(DW_CFA_val_expression, OT_Register, OT_Expression); - DECLARE_OP1(DW_CFA_restore, OT_Register); - DECLARE_OP1(DW_CFA_restore_extended, OT_Register); - DECLARE_OP0(DW_CFA_remember_state); - DECLARE_OP0(DW_CFA_restore_state); - DECLARE_OP0(DW_CFA_GNU_window_save); - DECLARE_OP0(DW_CFA_AARCH64_negate_ra_state_with_pc); - DECLARE_OP1(DW_CFA_GNU_args_size, OT_Offset); - DECLARE_OP0(DW_CFA_nop); - -#undef DECLARE_OP0 -#undef DECLARE_OP1 -#undef DECLARE_OP2 - - return ArrayRef(&OpTypes[0], DW_CFA_restore + 1); -} - -/// Print \p Opcode's operand number \p OperandIdx which has value \p Operand. -void CFIProgram::printOperand(raw_ostream &OS, DIDumpOptions DumpOpts, - const Instruction &Instr, unsigned OperandIdx, - uint64_t Operand, - std::optional &Address) const { - assert(OperandIdx < MaxOperands); - uint8_t Opcode = Instr.Opcode; - OperandType Type = getOperandTypes()[Opcode][OperandIdx]; - - switch (Type) { - case OT_Unset: { - OS << " Unsupported " << (OperandIdx ? "second" : "first") << " operand to"; - auto OpcodeName = callFrameString(Opcode); - if (!OpcodeName.empty()) - OS << " " << OpcodeName; - else - OS << format(" Opcode %x", Opcode); - break; - } - case OT_None: - break; - case OT_Address: - OS << format(" %" PRIx64, Operand); - Address = Operand; - break; - case OT_Offset: - // The offsets are all encoded in a unsigned form, but in practice - // consumers use them signed. It's most certainly legacy due to - // the lack of signed variants in the first Dwarf standards. - OS << format(" %+" PRId64, int64_t(Operand)); - break; - case OT_FactoredCodeOffset: // Always Unsigned - if (CodeAlignmentFactor) - OS << format(" %" PRId64, Operand * CodeAlignmentFactor); - else - OS << format(" %" PRId64 "*code_alignment_factor", Operand); - if (Address && CodeAlignmentFactor) { - *Address += Operand * CodeAlignmentFactor; - OS << format(" to 0x%" PRIx64, *Address); - } - break; - case OT_SignedFactDataOffset: - if (DataAlignmentFactor) - OS << format(" %" PRId64, int64_t(Operand) * DataAlignmentFactor); - else - OS << format(" %" PRId64 "*data_alignment_factor" , int64_t(Operand)); - break; - case OT_UnsignedFactDataOffset: - if (DataAlignmentFactor) - OS << format(" %" PRId64, Operand * DataAlignmentFactor); - else - OS << format(" %" PRId64 "*data_alignment_factor" , Operand); - break; - case OT_Register: - OS << ' '; - printRegister(OS, DumpOpts, Operand); - break; - case OT_AddressSpace: - OS << format(" in addrspace%" PRId64, Operand); - break; - case OT_Expression: - assert(Instr.Expression && "missing DWARFExpression object"); - OS << " "; - Instr.Expression->print(OS, DumpOpts, nullptr); - break; - } -} - -void CFIProgram::dump(raw_ostream &OS, DIDumpOptions DumpOpts, - unsigned IndentLevel, - std::optional Address) const { - for (const auto &Instr : Instructions) { - uint8_t Opcode = Instr.Opcode; - OS.indent(2 * IndentLevel); - OS << callFrameString(Opcode) << ":"; - for (unsigned i = 0; i < Instr.Ops.size(); ++i) - printOperand(OS, DumpOpts, Instr, i, Instr.Ops[i], Address); - OS << '\n'; - } -} - // Returns the CIE identifier to be used by the requested format. // CIE ids for .debug_frame sections are defined in Section 7.24 of DWARFv5. // For CIE ID in .eh_frame sections see From 91e598d38a81ff57b86c04d84bb11b6d2a8e0ef0 Mon Sep 17 00:00:00 2001 From: Sterling Augustine Date: Wed, 7 May 2025 13:35:17 -0700 Subject: [PATCH 2/2] run clang-format --- .../llvm/DebugInfo/DWARF/DWARFCFIProgram.h | 17 ++++++++++++----- llvm/lib/DebugInfo/DWARF/DWARFCFIProgram.cpp | 9 ++++----- 2 files changed, 16 insertions(+), 10 deletions(-) diff --git a/llvm/include/llvm/DebugInfo/DWARF/DWARFCFIProgram.h b/llvm/include/llvm/DebugInfo/DWARF/DWARFCFIProgram.h index ef6027eb538fc..5c3252590e5d0 100644 --- a/llvm/include/llvm/DebugInfo/DWARF/DWARFCFIProgram.h +++ b/llvm/include/llvm/DebugInfo/DWARF/DWARFCFIProgram.h @@ -1,5 +1,13 @@ -#ifndef LLVM_DEBUGINFO_DWARF_DWARFDEBUGCFIPROGRAM_H -#define LLVM_DEBUGINFO_DWARF_DWARFDEBUGCFIPROGRAM_H +//===- DWARFCFIProgram.h ----------------------------------------*- C++ -*-===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_DEBUGINFO_DWARF_DWARFCFIPROGRAM_H +#define LLVM_DEBUGINFO_DWARF_DWARFCFIPROGRAM_H #include "llvm/ADT/ArrayRef.h" #include "llvm/ADT/SmallString.h" @@ -62,8 +70,7 @@ class CFIProgram { CFIProgram(uint64_t CodeAlignmentFactor, int64_t DataAlignmentFactor, Triple::ArchType Arch) : CodeAlignmentFactor(CodeAlignmentFactor), - DataAlignmentFactor(DataAlignmentFactor), - Arch(Arch) {} + DataAlignmentFactor(DataAlignmentFactor), Arch(Arch) {} /// Parse and store a sequence of CFI instructions from Data, /// starting at *Offset and ending at EndOffset. *Offset is updated @@ -148,4 +155,4 @@ class CFIProgram { } // end namespace llvm -#endif // LLVM_DEBUGINFO_DWARF_DWARFDEBUGCFIPROGRAM_H +#endif // LLVM_DEBUGINFO_DWARF_DWARFCFIPROGRAM_H diff --git a/llvm/lib/DebugInfo/DWARF/DWARFCFIProgram.cpp b/llvm/lib/DebugInfo/DWARF/DWARFCFIProgram.cpp index bffed3f3da305..1a4fc4930fdd9 100644 --- a/llvm/lib/DebugInfo/DWARF/DWARFCFIProgram.cpp +++ b/llvm/lib/DebugInfo/DWARF/DWARFCFIProgram.cpp @@ -1,4 +1,4 @@ -//===- DWARFDebugFrame.h - Parsing of .debug_frame ------------------------===// +//===- DWARFCFIProgram.cpp - Parsing the cfi-portions of .debug_frame -----===// // // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. // See https://llvm.org/LICENSE.txt for license information. @@ -35,7 +35,6 @@ static void printRegister(raw_ostream &OS, DIDumpOptions DumpOpts, OS << "reg" << RegNum; } - // See DWARF standard v3, section 7.23 const uint8_t DWARF_CFI_PRIMARY_OPCODE_MASK = 0xc0; const uint8_t DWARF_CFI_PRIMARY_OPERAND_MASK = 0x3f; @@ -379,7 +378,7 @@ void CFIProgram::printOperand(raw_ostream &OS, DIDumpOptions DumpOpts, if (!OpcodeName.empty()) OS << " " << OpcodeName; else - OS << format(" Opcode %x", Opcode); + OS << format(" Opcode %x", Opcode); break; } case OT_None: @@ -408,13 +407,13 @@ void CFIProgram::printOperand(raw_ostream &OS, DIDumpOptions DumpOpts, if (DataAlignmentFactor) OS << format(" %" PRId64, int64_t(Operand) * DataAlignmentFactor); else - OS << format(" %" PRId64 "*data_alignment_factor" , int64_t(Operand)); + OS << format(" %" PRId64 "*data_alignment_factor", int64_t(Operand)); break; case OT_UnsignedFactDataOffset: if (DataAlignmentFactor) OS << format(" %" PRId64, Operand * DataAlignmentFactor); else - OS << format(" %" PRId64 "*data_alignment_factor" , Operand); + OS << format(" %" PRId64 "*data_alignment_factor", Operand); break; case OT_Register: OS << ' ';