[llvm] [NFC] Extract DWARFCFIProgram into separate files (PR #139326)
via llvm-commits
llvm-commits at lists.llvm.org
Fri May 9 14:03:20 PDT 2025
https://github.com/Sterling-Augustine created https://github.com/llvm/llvm-project/pull/139326
CFIPrograms' most common uses are within debug frames, but it is not their only use. For example, some assembly writers encode them by hand into .cfi_escape directives. This PR extracts code for them into its own files, setting them up to be evaluated from outside debug frames themselves.
One in a series of NFC DebugInfo/DWARF refactoring changes to layer it more cleanly, so that binary CFI parsing can be used from low-level code, (such as byte strings created via .cfi_escape) without circular dependencies. The final goal is to make a more limited dwarf library usable from lower-level code.
>From 56044015d6a620412e030716dace40fdd544326c Mon Sep 17 00:00:00 2001
From: Sterling Augustine <saugustine at google.com>
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 <map>
+#include <memory>
+#include <vector>
+
+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<uint64_t, MaxOperands> 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<DWARFExpression> Expression;
+
+ Expected<uint64_t> getOperandAsUnsigned(const CFIProgram &CFIP,
+ uint32_t OperandIdx) const;
+
+ Expected<int64_t> getOperandAsSigned(const CFIProgram &CFIP,
+ uint32_t OperandIdx) const;
+ };
+
+ using InstrList = std::vector<Instruction>;
+ 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<uint64_t> 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<Instruction> 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<OperandType[MaxOperands]> 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<uint64_t> &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<uint64_t, MaxOperands> 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<DWARFExpression> Expression;
-
- Expected<uint64_t> getOperandAsUnsigned(const CFIProgram &CFIP,
- uint32_t OperandIdx) const;
-
- Expected<int64_t> getOperandAsSigned(const CFIProgram &CFIP,
- uint32_t OperandIdx) const;
- };
-
- using InstrList = std::vector<Instruction>;
- 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<uint64_t> 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<Instruction> 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<OperandType[MaxOperands]> 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<uint64_t> &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 <cassert>
+#include <cinttypes>
+#include <cstdint>
+#include <optional>
+
+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 "<unknown CFIProgram::OperandType>";
+}
+
+llvm::Expected<uint64_t>
+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<int64_t>
+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::OperandType[CFIProgram::MaxOperands]>
+CFIProgram::getOperandTypes() {
+ static OperandType OpTypes[DW_CFA_restore + 1][MaxOperands];
+ static bool Initialized = false;
+ if (Initialized) {
+ return ArrayRef<OperandType[MaxOperands]>(&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<OperandType[MaxOperands]>(&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<uint64_t> &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<uint64_t> 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> 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 "<unknown CFIProgram::OperandType>";
-}
-
-llvm::Expected<uint64_t>
-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<int64_t>
-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::OperandType[CFIProgram::MaxOperands]>
-CFIProgram::getOperandTypes() {
- static OperandType OpTypes[DW_CFA_restore + 1][MaxOperands];
- static bool Initialized = false;
- if (Initialized) {
- return ArrayRef<OperandType[MaxOperands]>(&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<OperandType[MaxOperands]>(&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<uint64_t> &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<uint64_t> 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 <saugustine at google.com>
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 << ' ';
More information about the llvm-commits
mailing list