Skip to content

Commit 1981374

Browse files
author
Amirhossein Pashaeehir
committed
Fix the nested frame case and document the updateReceiver behavior
1 parent 1e9b4e6 commit 1981374

File tree

4 files changed

+86
-18
lines changed

4 files changed

+86
-18
lines changed

llvm/include/llvm/DWARFCFIChecker/DWARFCFIFunctionFrameStreamer.h

Lines changed: 17 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -60,12 +60,27 @@ class CFIFunctionFrameStreamer : public MCStreamer {
6060
void emitCFIEndProcImpl(MCDwarfFrameInfo &CurFrame) override;
6161

6262
private:
63+
/// This method sends the last instruction, along with its associated
64+
/// directives, to the receiver and then updates the internal state of the
65+
/// class. It moves the directive index to after the last directive and sets
66+
/// the last instruction to \p NewInst . This method assumes it is called in
67+
/// the middle of an unfinished DWARF debug frame; if not, an assertion will
68+
/// fail.
6369
void updateReceiver(const std::optional<MCInst> &NewInst);
6470

6571
private:
66-
std::vector<std::optional<MCInst>> FrameLastInstructions; //! FIXME
67-
std::vector<unsigned> FrameLastDirectiveIndices; //! FIXME
72+
/// The following fields are stacks that store the state of the stream sent to
73+
/// the receiver in each frame. This class, like `MCStreamer`, assumes that
74+
/// the debug frames are intertwined with each other only in stack form.
75+
76+
/// The last instruction that is not sent to the receiver for each frame.
77+
std::vector<std::optional<MCInst>> LastInstructions;
78+
/// The index of the last directive that is not sent to the receiver for each
79+
/// frame.
80+
std::vector<unsigned> LastDirectiveIndices;
81+
/// The index of each frame in `DwarfFrameInfos` field in `MCStreamer`.
6882
std::vector<unsigned> FrameIndices;
83+
6984
std::unique_ptr<CFIFunctionFrameReceiver> Receiver;
7085
};
7186

llvm/lib/DWARFCFIChecker/DWARFCFIFunctionFrameStreamer.cpp

Lines changed: 22 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -19,15 +19,16 @@ using namespace llvm;
1919

2020
void CFIFunctionFrameStreamer::updateReceiver(
2121
const std::optional<MCInst> &NewInst) {
22-
assert(!FrameIndices.empty() && hasUnfinishedDwarfFrameInfo() &&
23-
"FunctionUnitStreamer frame indices should be synced with "
24-
"MCStreamer's"); //! FIXME split this assertions and also check another
25-
//! vectors
26-
//! Add tests for nested frames
22+
assert(hasUnfinishedDwarfFrameInfo() &&
23+
"should have an unfinished DWARF frame here");
24+
assert(!FrameIndices.empty() &&
25+
"there should be an index available for the current frame");
26+
assert(FrameIndices.size() == LastInstructions.size());
27+
assert(LastInstructions.size() == LastDirectiveIndices.size());
2728

2829
auto Frames = getDwarfFrameInfos();
2930
assert(FrameIndices.back() < Frames.size());
30-
unsigned LastDirectiveIndex = FrameLastDirectiveIndices.back();
31+
unsigned LastDirectiveIndex = LastDirectiveIndices.back();
3132
unsigned CurrentDirectiveIndex =
3233
Frames[FrameIndices.back()].Instructions.size();
3334
assert(CurrentDirectiveIndex >= LastDirectiveIndex);
@@ -41,41 +42,46 @@ void CFIFunctionFrameStreamer::updateReceiver(
4142
.drop_back(LastFrame->Instructions.size() - CurrentDirectiveIndex);
4243
}
4344

44-
auto MaybeLastInstruction = FrameLastInstructions.back();
45+
auto MaybeLastInstruction = LastInstructions.back();
4546
if (MaybeLastInstruction)
47+
// The directives are associated with an instruction.
4648
Receiver->emitInstructionAndDirectives(*MaybeLastInstruction, Directives);
4749
else
50+
// The directives are the prologue directives.
4851
Receiver->startFunctionFrame(false /* TODO: should put isEH here */,
4952
Directives);
5053

51-
FrameLastInstructions.back() = NewInst;
52-
FrameLastDirectiveIndices.back() = CurrentDirectiveIndex;
54+
// Update the internal state for the top frame.
55+
LastInstructions.back() = NewInst;
56+
LastDirectiveIndices.back() = CurrentDirectiveIndex;
5357
}
5458

5559
void CFIFunctionFrameStreamer::emitInstruction(const MCInst &Inst,
5660
const MCSubtargetInfo &STI) {
57-
if (hasUnfinishedDwarfFrameInfo()) {
61+
if (hasUnfinishedDwarfFrameInfo())
62+
// Send the last instruction with the unsent directives already in the frame
63+
// to the receiver.
5864
updateReceiver(Inst);
59-
}
6065
}
6166

6267
void CFIFunctionFrameStreamer::emitCFIStartProcImpl(MCDwarfFrameInfo &Frame) {
63-
FrameLastInstructions.push_back(std::nullopt);
64-
FrameLastDirectiveIndices.push_back(0);
68+
LastInstructions.push_back(std::nullopt);
69+
LastDirectiveIndices.push_back(0);
6570
FrameIndices.push_back(getNumFrameInfos());
6671

6772
MCStreamer::emitCFIStartProcImpl(Frame);
6873
}
6974

7075
void CFIFunctionFrameStreamer::emitCFIEndProcImpl(MCDwarfFrameInfo &CurFrame) {
76+
// Send the last instruction with the final directives of the current frame to
77+
// the receiver.
7178
updateReceiver(std::nullopt);
7279

7380
assert(!FrameIndices.empty() && "There should be at least one frame to pop");
74-
FrameLastDirectiveIndices.pop_back();
75-
FrameLastInstructions.pop_back();
81+
LastDirectiveIndices.pop_back();
82+
LastInstructions.pop_back();
7683
FrameIndices.pop_back();
7784

78-
dbgs() << "finishing frame\n";
7985
Receiver->finishFunctionFrame();
8086

8187
MCStreamer::emitCFIEndProcImpl(CurFrame);
Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
# RUN: llvm-mc %s --validate-cfi --filetype=null 2>&1 \
2+
# RUN: | FileCheck %s --allow-empty
3+
# CHECK-NOT: warning:
4+
5+
.pushsection A
6+
f:
7+
.cfi_startproc
8+
.pushsection B
9+
g:
10+
.cfi_startproc
11+
ret
12+
.cfi_endproc
13+
.popsection
14+
ret
15+
.cfi_endproc
16+
.popsection
Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,31 @@
1+
# RUN: not llvm-mc %s --validate-cfi --filetype=null 2>&1 \
2+
# RUN: | FileCheck %s
3+
4+
.pushsection A
5+
f:
6+
.cfi_startproc
7+
# TODO: Remove this line when the initial frame directives set the callee saved registers
8+
.cfi_undefined %flags
9+
addq $10, %rbp
10+
# CHECK: error: changed register RBP, that register RBP's unwinding rule uses, but there is no CFI directives about it
11+
nop
12+
.cfi_undefined %rbp
13+
14+
.pushsection B
15+
g:
16+
.cfi_startproc
17+
# TODO: Remove this line when the initial frame directives set the callee saved registers
18+
.cfi_undefined %flags
19+
addq $10, %rbp
20+
# CHECK: error: changed register RBP, that register RBP's unwinding rule uses, but there is no CFI directives about it
21+
nop
22+
.cfi_undefined %rsi
23+
ret
24+
.cfi_endproc
25+
.popsection
26+
27+
addq $10, %rsi
28+
# CHECK: error: changed register RSI, that register RSI's unwinding rule uses, but there is no CFI directives about it
29+
ret
30+
.cfi_endproc
31+
.popsection

0 commit comments

Comments
 (0)