xref: /freebsd/contrib/llvm-project/llvm/lib/DWARFCFIChecker/DWARFCFIFunctionFrameStreamer.cpp (revision 700637cbb5e582861067a11aaca4d053546871d2)
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/DWARFCFIFunctionFrameStreamer.h"
10 #include "llvm/ADT/ArrayRef.h"
11 #include "llvm/MC/MCContext.h"
12 #include "llvm/MC/MCDwarf.h"
13 #include "llvm/MC/MCInst.h"
14 #include "llvm/MC/MCInstrInfo.h"
15 #include "llvm/MC/MCStreamer.h"
16 #include <optional>
17 
18 using namespace llvm;
19 
updateReceiver(const std::optional<MCInst> & NewInst)20 void CFIFunctionFrameStreamer::updateReceiver(
21     const std::optional<MCInst> &NewInst) {
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());
28 
29   auto Frames = getDwarfFrameInfos();
30   assert(FrameIndices.back() < Frames.size());
31   unsigned LastDirectiveIndex = LastDirectiveIndices.back();
32   unsigned CurrentDirectiveIndex =
33       Frames[FrameIndices.back()].Instructions.size();
34   assert(CurrentDirectiveIndex >= LastDirectiveIndex);
35 
36   const MCDwarfFrameInfo *LastFrame = &Frames[FrameIndices.back()];
37   ArrayRef<MCCFIInstruction> Directives;
38   if (LastDirectiveIndex < CurrentDirectiveIndex) {
39     Directives = ArrayRef<MCCFIInstruction>(LastFrame->Instructions);
40     Directives =
41         Directives.drop_front(LastDirectiveIndex)
42             .drop_back(LastFrame->Instructions.size() - CurrentDirectiveIndex);
43   }
44 
45   auto MaybeLastInstruction = LastInstructions.back();
46   if (MaybeLastInstruction)
47     // The directives are associated with an instruction.
48     Receiver->emitInstructionAndDirectives(*MaybeLastInstruction, Directives);
49   else
50     // The directives are the prologue directives.
51     Receiver->startFunctionFrame(false /* TODO: should put isEH here */,
52                                  Directives);
53 
54   // Update the internal state for the top frame.
55   LastInstructions.back() = NewInst;
56   LastDirectiveIndices.back() = CurrentDirectiveIndex;
57 }
58 
emitInstruction(const MCInst & Inst,const MCSubtargetInfo & STI)59 void CFIFunctionFrameStreamer::emitInstruction(const MCInst &Inst,
60                                                const MCSubtargetInfo &STI) {
61   if (hasUnfinishedDwarfFrameInfo())
62     // Send the last instruction with the unsent directives already in the frame
63     // to the receiver.
64     updateReceiver(Inst);
65 }
66 
emitCFIStartProcImpl(MCDwarfFrameInfo & Frame)67 void CFIFunctionFrameStreamer::emitCFIStartProcImpl(MCDwarfFrameInfo &Frame) {
68   LastInstructions.push_back(std::nullopt);
69   LastDirectiveIndices.push_back(0);
70   FrameIndices.push_back(getNumFrameInfos());
71 
72   MCStreamer::emitCFIStartProcImpl(Frame);
73 }
74 
emitCFIEndProcImpl(MCDwarfFrameInfo & CurFrame)75 void CFIFunctionFrameStreamer::emitCFIEndProcImpl(MCDwarfFrameInfo &CurFrame) {
76   // Send the last instruction with the final directives of the current frame to
77   // the receiver.
78   updateReceiver(std::nullopt);
79 
80   assert(!FrameIndices.empty() && "There should be at least one frame to pop");
81   LastDirectiveIndices.pop_back();
82   LastInstructions.pop_back();
83   FrameIndices.pop_back();
84 
85   Receiver->finishFunctionFrame();
86 
87   MCStreamer::emitCFIEndProcImpl(CurFrame);
88 }
89