Skip to content

Commit 5604401

Browse files
[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.
1 parent 5936c02 commit 5604401

File tree

5 files changed

+599
-538
lines changed

5 files changed

+599
-538
lines changed
Lines changed: 151 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,151 @@
1+
#ifndef LLVM_DEBUGINFO_DWARF_DWARFDEBUGCFIPROGRAM_H
2+
#define LLVM_DEBUGINFO_DWARF_DWARFDEBUGCFIPROGRAM_H
3+
4+
#include "llvm/ADT/ArrayRef.h"
5+
#include "llvm/ADT/SmallString.h"
6+
#include "llvm/ADT/iterator.h"
7+
#include "llvm/DebugInfo/DWARF/DWARFDataExtractor.h"
8+
#include "llvm/DebugInfo/DWARF/DWARFExpression.h"
9+
#include "llvm/Support/Error.h"
10+
#include "llvm/TargetParser/Triple.h"
11+
#include <map>
12+
#include <memory>
13+
#include <vector>
14+
15+
namespace llvm {
16+
17+
namespace dwarf {
18+
/// Represent a sequence of Call Frame Information instructions that, when read
19+
/// in order, construct a table mapping PC to frame state. This can also be
20+
/// referred to as "CFI rules" in DWARF literature to avoid confusion with
21+
/// computer programs in the broader sense, and in this context each instruction
22+
/// would be a rule to establish the mapping. Refer to pg. 172 in the DWARF5
23+
/// manual, "6.4.1 Structure of Call Frame Information".
24+
class CFIProgram {
25+
public:
26+
static constexpr size_t MaxOperands = 3;
27+
typedef SmallVector<uint64_t, MaxOperands> Operands;
28+
29+
/// An instruction consists of a DWARF CFI opcode and an optional sequence of
30+
/// operands. If it refers to an expression, then this expression has its own
31+
/// sequence of operations and operands handled separately by DWARFExpression.
32+
struct Instruction {
33+
Instruction(uint8_t Opcode) : Opcode(Opcode) {}
34+
35+
uint8_t Opcode;
36+
Operands Ops;
37+
// Associated DWARF expression in case this instruction refers to one
38+
std::optional<DWARFExpression> Expression;
39+
40+
Expected<uint64_t> getOperandAsUnsigned(const CFIProgram &CFIP,
41+
uint32_t OperandIdx) const;
42+
43+
Expected<int64_t> getOperandAsSigned(const CFIProgram &CFIP,
44+
uint32_t OperandIdx) const;
45+
};
46+
47+
using InstrList = std::vector<Instruction>;
48+
using iterator = InstrList::iterator;
49+
using const_iterator = InstrList::const_iterator;
50+
51+
iterator begin() { return Instructions.begin(); }
52+
const_iterator begin() const { return Instructions.begin(); }
53+
iterator end() { return Instructions.end(); }
54+
const_iterator end() const { return Instructions.end(); }
55+
56+
unsigned size() const { return (unsigned)Instructions.size(); }
57+
bool empty() const { return Instructions.empty(); }
58+
uint64_t codeAlign() const { return CodeAlignmentFactor; }
59+
int64_t dataAlign() const { return DataAlignmentFactor; }
60+
Triple::ArchType triple() const { return Arch; }
61+
62+
CFIProgram(uint64_t CodeAlignmentFactor, int64_t DataAlignmentFactor,
63+
Triple::ArchType Arch)
64+
: CodeAlignmentFactor(CodeAlignmentFactor),
65+
DataAlignmentFactor(DataAlignmentFactor),
66+
Arch(Arch) {}
67+
68+
/// Parse and store a sequence of CFI instructions from Data,
69+
/// starting at *Offset and ending at EndOffset. *Offset is updated
70+
/// to EndOffset upon successful parsing, or indicates the offset
71+
/// where a problem occurred in case an error is returned.
72+
Error parse(DWARFDataExtractor Data, uint64_t *Offset, uint64_t EndOffset);
73+
74+
void dump(raw_ostream &OS, DIDumpOptions DumpOpts, unsigned IndentLevel,
75+
std::optional<uint64_t> InitialLocation) const;
76+
77+
void addInstruction(const Instruction &I) { Instructions.push_back(I); }
78+
79+
/// Get a DWARF CFI call frame string for the given DW_CFA opcode.
80+
StringRef callFrameString(unsigned Opcode) const;
81+
82+
private:
83+
std::vector<Instruction> Instructions;
84+
const uint64_t CodeAlignmentFactor;
85+
const int64_t DataAlignmentFactor;
86+
Triple::ArchType Arch;
87+
88+
/// Convenience method to add a new instruction with the given opcode.
89+
void addInstruction(uint8_t Opcode) {
90+
Instructions.push_back(Instruction(Opcode));
91+
}
92+
93+
/// Add a new single-operand instruction.
94+
void addInstruction(uint8_t Opcode, uint64_t Operand1) {
95+
Instructions.push_back(Instruction(Opcode));
96+
Instructions.back().Ops.push_back(Operand1);
97+
}
98+
99+
/// Add a new instruction that has two operands.
100+
void addInstruction(uint8_t Opcode, uint64_t Operand1, uint64_t Operand2) {
101+
Instructions.push_back(Instruction(Opcode));
102+
Instructions.back().Ops.push_back(Operand1);
103+
Instructions.back().Ops.push_back(Operand2);
104+
}
105+
106+
/// Add a new instruction that has three operands.
107+
void addInstruction(uint8_t Opcode, uint64_t Operand1, uint64_t Operand2,
108+
uint64_t Operand3) {
109+
Instructions.push_back(Instruction(Opcode));
110+
Instructions.back().Ops.push_back(Operand1);
111+
Instructions.back().Ops.push_back(Operand2);
112+
Instructions.back().Ops.push_back(Operand3);
113+
}
114+
115+
/// Types of operands to CFI instructions
116+
/// In DWARF, this type is implicitly tied to a CFI instruction opcode and
117+
/// thus this type doesn't need to be explicitly written to the file (this is
118+
/// not a DWARF encoding). The relationship of instrs to operand types can
119+
/// be obtained from getOperandTypes() and is only used to simplify
120+
/// instruction printing.
121+
enum OperandType {
122+
OT_Unset,
123+
OT_None,
124+
OT_Address,
125+
OT_Offset,
126+
OT_FactoredCodeOffset,
127+
OT_SignedFactDataOffset,
128+
OT_UnsignedFactDataOffset,
129+
OT_Register,
130+
OT_AddressSpace,
131+
OT_Expression
132+
};
133+
134+
/// Get the OperandType as a "const char *".
135+
static const char *operandTypeString(OperandType OT);
136+
137+
/// Retrieve the array describing the types of operands according to the enum
138+
/// above. This is indexed by opcode.
139+
static ArrayRef<OperandType[MaxOperands]> getOperandTypes();
140+
141+
/// Print \p Opcode's operand number \p OperandIdx which has value \p Operand.
142+
void printOperand(raw_ostream &OS, DIDumpOptions DumpOpts,
143+
const Instruction &Instr, unsigned OperandIdx,
144+
uint64_t Operand, std::optional<uint64_t> &Address) const;
145+
};
146+
147+
} // end namespace dwarf
148+
149+
} // end namespace llvm
150+
151+
#endif // LLVM_DEBUGINFO_DWARF_DWARFDEBUGCFIPROGRAM_H

llvm/include/llvm/DebugInfo/DWARF/DWARFDebugFrame.h

Lines changed: 1 addition & 130 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@
1212
#include "llvm/ADT/ArrayRef.h"
1313
#include "llvm/ADT/SmallString.h"
1414
#include "llvm/ADT/iterator.h"
15+
#include "llvm/DebugInfo/DWARF/DWARFCFIProgram.h"
1516
#include "llvm/DebugInfo/DWARF/DWARFExpression.h"
1617
#include "llvm/Support/Error.h"
1718
#include "llvm/TargetParser/Triple.h"
@@ -309,7 +310,6 @@ class UnwindRow {
309310

310311
raw_ostream &operator<<(raw_ostream &OS, const UnwindRow &Row);
311312

312-
class CFIProgram;
313313
class CIE;
314314
class FDE;
315315

@@ -398,135 +398,6 @@ class UnwindTable {
398398

399399
raw_ostream &operator<<(raw_ostream &OS, const UnwindTable &Rows);
400400

401-
/// Represent a sequence of Call Frame Information instructions that, when read
402-
/// in order, construct a table mapping PC to frame state. This can also be
403-
/// referred to as "CFI rules" in DWARF literature to avoid confusion with
404-
/// computer programs in the broader sense, and in this context each instruction
405-
/// would be a rule to establish the mapping. Refer to pg. 172 in the DWARF5
406-
/// manual, "6.4.1 Structure of Call Frame Information".
407-
class CFIProgram {
408-
public:
409-
static constexpr size_t MaxOperands = 3;
410-
typedef SmallVector<uint64_t, MaxOperands> Operands;
411-
412-
/// An instruction consists of a DWARF CFI opcode and an optional sequence of
413-
/// operands. If it refers to an expression, then this expression has its own
414-
/// sequence of operations and operands handled separately by DWARFExpression.
415-
struct Instruction {
416-
Instruction(uint8_t Opcode) : Opcode(Opcode) {}
417-
418-
uint8_t Opcode;
419-
Operands Ops;
420-
// Associated DWARF expression in case this instruction refers to one
421-
std::optional<DWARFExpression> Expression;
422-
423-
Expected<uint64_t> getOperandAsUnsigned(const CFIProgram &CFIP,
424-
uint32_t OperandIdx) const;
425-
426-
Expected<int64_t> getOperandAsSigned(const CFIProgram &CFIP,
427-
uint32_t OperandIdx) const;
428-
};
429-
430-
using InstrList = std::vector<Instruction>;
431-
using iterator = InstrList::iterator;
432-
using const_iterator = InstrList::const_iterator;
433-
434-
iterator begin() { return Instructions.begin(); }
435-
const_iterator begin() const { return Instructions.begin(); }
436-
iterator end() { return Instructions.end(); }
437-
const_iterator end() const { return Instructions.end(); }
438-
439-
unsigned size() const { return (unsigned)Instructions.size(); }
440-
bool empty() const { return Instructions.empty(); }
441-
uint64_t codeAlign() const { return CodeAlignmentFactor; }
442-
int64_t dataAlign() const { return DataAlignmentFactor; }
443-
Triple::ArchType triple() const { return Arch; }
444-
445-
CFIProgram(uint64_t CodeAlignmentFactor, int64_t DataAlignmentFactor,
446-
Triple::ArchType Arch)
447-
: CodeAlignmentFactor(CodeAlignmentFactor),
448-
DataAlignmentFactor(DataAlignmentFactor),
449-
Arch(Arch) {}
450-
451-
/// Parse and store a sequence of CFI instructions from Data,
452-
/// starting at *Offset and ending at EndOffset. *Offset is updated
453-
/// to EndOffset upon successful parsing, or indicates the offset
454-
/// where a problem occurred in case an error is returned.
455-
Error parse(DWARFDataExtractor Data, uint64_t *Offset, uint64_t EndOffset);
456-
457-
void dump(raw_ostream &OS, DIDumpOptions DumpOpts, unsigned IndentLevel,
458-
std::optional<uint64_t> InitialLocation) const;
459-
460-
void addInstruction(const Instruction &I) { Instructions.push_back(I); }
461-
462-
/// Get a DWARF CFI call frame string for the given DW_CFA opcode.
463-
StringRef callFrameString(unsigned Opcode) const;
464-
465-
private:
466-
std::vector<Instruction> Instructions;
467-
const uint64_t CodeAlignmentFactor;
468-
const int64_t DataAlignmentFactor;
469-
Triple::ArchType Arch;
470-
471-
/// Convenience method to add a new instruction with the given opcode.
472-
void addInstruction(uint8_t Opcode) {
473-
Instructions.push_back(Instruction(Opcode));
474-
}
475-
476-
/// Add a new single-operand instruction.
477-
void addInstruction(uint8_t Opcode, uint64_t Operand1) {
478-
Instructions.push_back(Instruction(Opcode));
479-
Instructions.back().Ops.push_back(Operand1);
480-
}
481-
482-
/// Add a new instruction that has two operands.
483-
void addInstruction(uint8_t Opcode, uint64_t Operand1, uint64_t Operand2) {
484-
Instructions.push_back(Instruction(Opcode));
485-
Instructions.back().Ops.push_back(Operand1);
486-
Instructions.back().Ops.push_back(Operand2);
487-
}
488-
489-
/// Add a new instruction that has three operands.
490-
void addInstruction(uint8_t Opcode, uint64_t Operand1, uint64_t Operand2,
491-
uint64_t Operand3) {
492-
Instructions.push_back(Instruction(Opcode));
493-
Instructions.back().Ops.push_back(Operand1);
494-
Instructions.back().Ops.push_back(Operand2);
495-
Instructions.back().Ops.push_back(Operand3);
496-
}
497-
498-
/// Types of operands to CFI instructions
499-
/// In DWARF, this type is implicitly tied to a CFI instruction opcode and
500-
/// thus this type doesn't need to be explicitly written to the file (this is
501-
/// not a DWARF encoding). The relationship of instrs to operand types can
502-
/// be obtained from getOperandTypes() and is only used to simplify
503-
/// instruction printing.
504-
enum OperandType {
505-
OT_Unset,
506-
OT_None,
507-
OT_Address,
508-
OT_Offset,
509-
OT_FactoredCodeOffset,
510-
OT_SignedFactDataOffset,
511-
OT_UnsignedFactDataOffset,
512-
OT_Register,
513-
OT_AddressSpace,
514-
OT_Expression
515-
};
516-
517-
/// Get the OperandType as a "const char *".
518-
static const char *operandTypeString(OperandType OT);
519-
520-
/// Retrieve the array describing the types of operands according to the enum
521-
/// above. This is indexed by opcode.
522-
static ArrayRef<OperandType[MaxOperands]> getOperandTypes();
523-
524-
/// Print \p Opcode's operand number \p OperandIdx which has value \p Operand.
525-
void printOperand(raw_ostream &OS, DIDumpOptions DumpOpts,
526-
const Instruction &Instr, unsigned OperandIdx,
527-
uint64_t Operand, std::optional<uint64_t> &Address) const;
528-
};
529-
530401
/// An entry in either debug_frame or eh_frame. This entry can be a CIE or an
531402
/// FDE.
532403
class FrameEntry {

llvm/lib/DebugInfo/DWARF/CMakeLists.txt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@ add_llvm_component_library(LLVMDebugInfoDWARF
22
DWARFAbbreviationDeclaration.cpp
33
DWARFAddressRange.cpp
44
DWARFAcceleratorTable.cpp
5+
DWARFCFIProgram.cpp
56
DWARFCompileUnit.cpp
67
DWARFContext.cpp
78
DWARFDataExtractor.cpp

0 commit comments

Comments
 (0)