Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
freebsd
GitHub Repository: freebsd/freebsd-src
Path: blob/main/contrib/llvm-project/llvm/lib/DWARFCFIChecker/DWARFCFIState.cpp
213766 views
1
//===----------------------------------------------------------------------===//
2
//
3
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4
// See https://llvm.org/LICENSE.txt for license information.
5
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6
//
7
//===----------------------------------------------------------------------===//
8
9
#include "llvm/DWARFCFIChecker/DWARFCFIState.h"
10
#include "llvm/BinaryFormat/Dwarf.h"
11
#include "llvm/DebugInfo/DWARF/LowLevel/DWARFUnwindTable.h"
12
#include "llvm/MC/MCDwarf.h"
13
#include "llvm/Support/Error.h"
14
#include "llvm/Support/ErrorHandling.h"
15
#include "llvm/Support/FormatVariadic.h"
16
#include <cassert>
17
#include <optional>
18
19
using namespace llvm;
20
21
std::optional<dwarf::UnwindRow> DWARFCFIState::getCurrentUnwindRow() const {
22
if (!IsInitiated)
23
return std::nullopt;
24
return Row;
25
}
26
27
void DWARFCFIState::update(const MCCFIInstruction &Directive) {
28
auto CFIP = convert(Directive);
29
30
// This is a copy of the current row, its value will be updated by
31
// `parseRows`.
32
dwarf::UnwindRow NewRow = Row;
33
34
// `parseRows` updates the current row by applying the `CFIProgram` to it.
35
// During this process, it may create multiple rows preceding the newly
36
// updated row and following the previous rows. These middle rows are stored
37
// in `PrecedingRows`. For now, there is no need to store these rows in the
38
// state, so they are ignored in the end.
39
dwarf::UnwindTable::RowContainer PrecedingRows;
40
41
// TODO: `.cfi_remember_state` and `.cfi_restore_state` directives are not
42
// supported yet. The reason is that `parseRows` expects the stack of states
43
// to be produced and used in a single `CFIProgram`. However, in this use
44
// case, each instruction creates its own `CFIProgram`, which means the stack
45
// of states is forgotten between instructions. To fix it, `parseRows` should
46
// be refactored to read the current stack of states from the argument and
47
// update it based on the `CFIProgram.`
48
if (Error Err = parseRows(CFIP, NewRow, nullptr).takeError()) {
49
Context->reportError(
50
Directive.getLoc(),
51
formatv("could not parse this CFI directive due to: {0}",
52
toString(std::move(Err))));
53
54
// Proceed the analysis by ignoring this CFI directive.
55
return;
56
}
57
58
Row = NewRow;
59
IsInitiated = true;
60
}
61
62
dwarf::CFIProgram DWARFCFIState::convert(MCCFIInstruction Directive) {
63
auto CFIP = dwarf::CFIProgram(
64
/* CodeAlignmentFactor */ 1, /* DataAlignmentFactor */ 1,
65
Context->getTargetTriple().getArch());
66
67
auto MaybeCurrentRow = getCurrentUnwindRow();
68
switch (Directive.getOperation()) {
69
case MCCFIInstruction::OpSameValue:
70
CFIP.addInstruction(dwarf::DW_CFA_same_value, Directive.getRegister());
71
break;
72
case MCCFIInstruction::OpRememberState:
73
// TODO: remember state is not supported yet, the following line does not
74
// work:
75
// CFIP.addInstruction(dwarf::DW_CFA_remember_state);
76
// The reason is explained in the `DWARFCFIState::update` method where
77
// `dwarf::parseRows` is used.
78
Context->reportWarning(Directive.getLoc(),
79
"this directive is not supported, ignoring it");
80
break;
81
case MCCFIInstruction::OpRestoreState:
82
// TODO: restore state is not supported yet, the following line does not
83
// work:
84
// CFIP.addInstruction(dwarf::DW_CFA_restore_state);
85
// The reason is explained in the `DWARFCFIState::update` method where
86
// `dwarf::parseRows` is used.
87
Context->reportWarning(Directive.getLoc(),
88
"this directive is not supported, ignoring it");
89
break;
90
case MCCFIInstruction::OpOffset:
91
CFIP.addInstruction(dwarf::DW_CFA_offset, Directive.getRegister(),
92
Directive.getOffset());
93
break;
94
case MCCFIInstruction::OpLLVMDefAspaceCfa:
95
CFIP.addInstruction(dwarf::DW_CFA_LLVM_def_aspace_cfa,
96
Directive.getRegister());
97
break;
98
case MCCFIInstruction::OpDefCfaRegister:
99
CFIP.addInstruction(dwarf::DW_CFA_def_cfa_register,
100
Directive.getRegister());
101
break;
102
case MCCFIInstruction::OpDefCfaOffset:
103
CFIP.addInstruction(dwarf::DW_CFA_def_cfa_offset, Directive.getOffset());
104
break;
105
case MCCFIInstruction::OpDefCfa:
106
CFIP.addInstruction(dwarf::DW_CFA_def_cfa, Directive.getRegister(),
107
Directive.getOffset());
108
break;
109
case MCCFIInstruction::OpRelOffset:
110
assert(
111
IsInitiated &&
112
"cannot define relative offset to a non-existing CFA unwinding rule");
113
114
CFIP.addInstruction(dwarf::DW_CFA_offset, Directive.getRegister(),
115
Directive.getOffset() - Row.getCFAValue().getOffset());
116
break;
117
case MCCFIInstruction::OpAdjustCfaOffset:
118
assert(IsInitiated &&
119
"cannot adjust CFA offset of a non-existing CFA unwinding rule");
120
121
CFIP.addInstruction(dwarf::DW_CFA_def_cfa_offset,
122
Directive.getOffset() + Row.getCFAValue().getOffset());
123
break;
124
case MCCFIInstruction::OpEscape:
125
// TODO: DWARFExpressions are not supported yet, ignoring expression here.
126
Context->reportWarning(Directive.getLoc(),
127
"this directive is not supported, ignoring it");
128
break;
129
case MCCFIInstruction::OpRestore:
130
// The `.cfi_restore register` directive restores the register's unwinding
131
// information to its CIE value. However, assemblers decide where CIE ends
132
// and the FDE starts, so the functionality of this directive depends on the
133
// assembler's decision and cannot be validated.
134
Context->reportWarning(
135
Directive.getLoc(),
136
"this directive behavior depends on the assembler, ignoring it");
137
break;
138
case MCCFIInstruction::OpUndefined:
139
CFIP.addInstruction(dwarf::DW_CFA_undefined, Directive.getRegister());
140
break;
141
case MCCFIInstruction::OpRegister:
142
CFIP.addInstruction(dwarf::DW_CFA_register, Directive.getRegister(),
143
Directive.getRegister2());
144
break;
145
case MCCFIInstruction::OpWindowSave:
146
CFIP.addInstruction(dwarf::DW_CFA_GNU_window_save);
147
break;
148
case MCCFIInstruction::OpNegateRAState:
149
CFIP.addInstruction(dwarf::DW_CFA_AARCH64_negate_ra_state);
150
break;
151
case MCCFIInstruction::OpNegateRAStateWithPC:
152
CFIP.addInstruction(dwarf::DW_CFA_AARCH64_negate_ra_state_with_pc);
153
break;
154
case MCCFIInstruction::OpGnuArgsSize:
155
CFIP.addInstruction(dwarf::DW_CFA_GNU_args_size);
156
break;
157
case MCCFIInstruction::OpLabel:
158
// `.cfi_label` does not have any functional effect on unwinding process.
159
break;
160
case MCCFIInstruction::OpValOffset:
161
CFIP.addInstruction(dwarf::DW_CFA_val_offset, Directive.getRegister(),
162
Directive.getOffset());
163
break;
164
}
165
166
return CFIP;
167
}
168
169