1*700637cbSDimitry Andric //===----------------------------------------------------------------------===// 2*700637cbSDimitry Andric // 3*700637cbSDimitry Andric // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. 4*700637cbSDimitry Andric // See https://llvm.org/LICENSE.txt for license information. 5*700637cbSDimitry Andric // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception 6*700637cbSDimitry Andric // 7*700637cbSDimitry Andric //===----------------------------------------------------------------------===// 8*700637cbSDimitry Andric 9*700637cbSDimitry Andric #include "llvm/DWARFCFIChecker/DWARFCFIFunctionFrameStreamer.h" 10*700637cbSDimitry Andric #include "llvm/ADT/ArrayRef.h" 11*700637cbSDimitry Andric #include "llvm/MC/MCContext.h" 12*700637cbSDimitry Andric #include "llvm/MC/MCDwarf.h" 13*700637cbSDimitry Andric #include "llvm/MC/MCInst.h" 14*700637cbSDimitry Andric #include "llvm/MC/MCInstrInfo.h" 15*700637cbSDimitry Andric #include "llvm/MC/MCStreamer.h" 16*700637cbSDimitry Andric #include <optional> 17*700637cbSDimitry Andric 18*700637cbSDimitry Andric using namespace llvm; 19*700637cbSDimitry Andric updateReceiver(const std::optional<MCInst> & NewInst)20*700637cbSDimitry Andricvoid CFIFunctionFrameStreamer::updateReceiver( 21*700637cbSDimitry Andric const std::optional<MCInst> &NewInst) { 22*700637cbSDimitry Andric assert(hasUnfinishedDwarfFrameInfo() && 23*700637cbSDimitry Andric "should have an unfinished DWARF frame here"); 24*700637cbSDimitry Andric assert(!FrameIndices.empty() && 25*700637cbSDimitry Andric "there should be an index available for the current frame"); 26*700637cbSDimitry Andric assert(FrameIndices.size() == LastInstructions.size()); 27*700637cbSDimitry Andric assert(LastInstructions.size() == LastDirectiveIndices.size()); 28*700637cbSDimitry Andric 29*700637cbSDimitry Andric auto Frames = getDwarfFrameInfos(); 30*700637cbSDimitry Andric assert(FrameIndices.back() < Frames.size()); 31*700637cbSDimitry Andric unsigned LastDirectiveIndex = LastDirectiveIndices.back(); 32*700637cbSDimitry Andric unsigned CurrentDirectiveIndex = 33*700637cbSDimitry Andric Frames[FrameIndices.back()].Instructions.size(); 34*700637cbSDimitry Andric assert(CurrentDirectiveIndex >= LastDirectiveIndex); 35*700637cbSDimitry Andric 36*700637cbSDimitry Andric const MCDwarfFrameInfo *LastFrame = &Frames[FrameIndices.back()]; 37*700637cbSDimitry Andric ArrayRef<MCCFIInstruction> Directives; 38*700637cbSDimitry Andric if (LastDirectiveIndex < CurrentDirectiveIndex) { 39*700637cbSDimitry Andric Directives = ArrayRef<MCCFIInstruction>(LastFrame->Instructions); 40*700637cbSDimitry Andric Directives = 41*700637cbSDimitry Andric Directives.drop_front(LastDirectiveIndex) 42*700637cbSDimitry Andric .drop_back(LastFrame->Instructions.size() - CurrentDirectiveIndex); 43*700637cbSDimitry Andric } 44*700637cbSDimitry Andric 45*700637cbSDimitry Andric auto MaybeLastInstruction = LastInstructions.back(); 46*700637cbSDimitry Andric if (MaybeLastInstruction) 47*700637cbSDimitry Andric // The directives are associated with an instruction. 48*700637cbSDimitry Andric Receiver->emitInstructionAndDirectives(*MaybeLastInstruction, Directives); 49*700637cbSDimitry Andric else 50*700637cbSDimitry Andric // The directives are the prologue directives. 51*700637cbSDimitry Andric Receiver->startFunctionFrame(false /* TODO: should put isEH here */, 52*700637cbSDimitry Andric Directives); 53*700637cbSDimitry Andric 54*700637cbSDimitry Andric // Update the internal state for the top frame. 55*700637cbSDimitry Andric LastInstructions.back() = NewInst; 56*700637cbSDimitry Andric LastDirectiveIndices.back() = CurrentDirectiveIndex; 57*700637cbSDimitry Andric } 58*700637cbSDimitry Andric emitInstruction(const MCInst & Inst,const MCSubtargetInfo & STI)59*700637cbSDimitry Andricvoid CFIFunctionFrameStreamer::emitInstruction(const MCInst &Inst, 60*700637cbSDimitry Andric const MCSubtargetInfo &STI) { 61*700637cbSDimitry Andric if (hasUnfinishedDwarfFrameInfo()) 62*700637cbSDimitry Andric // Send the last instruction with the unsent directives already in the frame 63*700637cbSDimitry Andric // to the receiver. 64*700637cbSDimitry Andric updateReceiver(Inst); 65*700637cbSDimitry Andric } 66*700637cbSDimitry Andric emitCFIStartProcImpl(MCDwarfFrameInfo & Frame)67*700637cbSDimitry Andricvoid CFIFunctionFrameStreamer::emitCFIStartProcImpl(MCDwarfFrameInfo &Frame) { 68*700637cbSDimitry Andric LastInstructions.push_back(std::nullopt); 69*700637cbSDimitry Andric LastDirectiveIndices.push_back(0); 70*700637cbSDimitry Andric FrameIndices.push_back(getNumFrameInfos()); 71*700637cbSDimitry Andric 72*700637cbSDimitry Andric MCStreamer::emitCFIStartProcImpl(Frame); 73*700637cbSDimitry Andric } 74*700637cbSDimitry Andric emitCFIEndProcImpl(MCDwarfFrameInfo & CurFrame)75*700637cbSDimitry Andricvoid CFIFunctionFrameStreamer::emitCFIEndProcImpl(MCDwarfFrameInfo &CurFrame) { 76*700637cbSDimitry Andric // Send the last instruction with the final directives of the current frame to 77*700637cbSDimitry Andric // the receiver. 78*700637cbSDimitry Andric updateReceiver(std::nullopt); 79*700637cbSDimitry Andric 80*700637cbSDimitry Andric assert(!FrameIndices.empty() && "There should be at least one frame to pop"); 81*700637cbSDimitry Andric LastDirectiveIndices.pop_back(); 82*700637cbSDimitry Andric LastInstructions.pop_back(); 83*700637cbSDimitry Andric FrameIndices.pop_back(); 84*700637cbSDimitry Andric 85*700637cbSDimitry Andric Receiver->finishFunctionFrame(); 86*700637cbSDimitry Andric 87*700637cbSDimitry Andric MCStreamer::emitCFIEndProcImpl(CurFrame); 88*700637cbSDimitry Andric } 89