106f32e7eSjoerg //===-- X86WinCOFFTargetStreamer.cpp ----------------------------*- C++ -*-===//
206f32e7eSjoerg //
306f32e7eSjoerg // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
406f32e7eSjoerg // See https://llvm.org/LICENSE.txt for license information.
506f32e7eSjoerg // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
606f32e7eSjoerg //
706f32e7eSjoerg //===----------------------------------------------------------------------===//
806f32e7eSjoerg 
906f32e7eSjoerg #include "X86MCTargetDesc.h"
1006f32e7eSjoerg #include "X86TargetStreamer.h"
1106f32e7eSjoerg #include "llvm/DebugInfo/CodeView/CodeView.h"
1206f32e7eSjoerg #include "llvm/MC/MCCodeView.h"
1306f32e7eSjoerg #include "llvm/MC/MCContext.h"
1406f32e7eSjoerg #include "llvm/MC/MCInstPrinter.h"
1506f32e7eSjoerg #include "llvm/MC/MCRegisterInfo.h"
1606f32e7eSjoerg #include "llvm/MC/MCSubtargetInfo.h"
1706f32e7eSjoerg #include "llvm/Support/FormattedStream.h"
1806f32e7eSjoerg 
1906f32e7eSjoerg using namespace llvm;
2006f32e7eSjoerg using namespace llvm::codeview;
2106f32e7eSjoerg 
2206f32e7eSjoerg namespace {
2306f32e7eSjoerg /// Implements Windows x86-only directives for assembly emission.
2406f32e7eSjoerg class X86WinCOFFAsmTargetStreamer : public X86TargetStreamer {
2506f32e7eSjoerg   formatted_raw_ostream &OS;
2606f32e7eSjoerg   MCInstPrinter &InstPrinter;
2706f32e7eSjoerg 
2806f32e7eSjoerg public:
X86WinCOFFAsmTargetStreamer(MCStreamer & S,formatted_raw_ostream & OS,MCInstPrinter & InstPrinter)2906f32e7eSjoerg   X86WinCOFFAsmTargetStreamer(MCStreamer &S, formatted_raw_ostream &OS,
3006f32e7eSjoerg                               MCInstPrinter &InstPrinter)
3106f32e7eSjoerg       : X86TargetStreamer(S), OS(OS), InstPrinter(InstPrinter) {}
3206f32e7eSjoerg 
3306f32e7eSjoerg   bool emitFPOProc(const MCSymbol *ProcSym, unsigned ParamsSize,
3406f32e7eSjoerg                    SMLoc L) override;
3506f32e7eSjoerg   bool emitFPOEndPrologue(SMLoc L) override;
3606f32e7eSjoerg   bool emitFPOEndProc(SMLoc L) override;
3706f32e7eSjoerg   bool emitFPOData(const MCSymbol *ProcSym, SMLoc L) override;
3806f32e7eSjoerg   bool emitFPOPushReg(unsigned Reg, SMLoc L) override;
3906f32e7eSjoerg   bool emitFPOStackAlloc(unsigned StackAlloc, SMLoc L) override;
4006f32e7eSjoerg   bool emitFPOStackAlign(unsigned Align, SMLoc L) override;
4106f32e7eSjoerg   bool emitFPOSetFrame(unsigned Reg, SMLoc L) override;
4206f32e7eSjoerg };
4306f32e7eSjoerg 
4406f32e7eSjoerg /// Represents a single FPO directive.
4506f32e7eSjoerg struct FPOInstruction {
4606f32e7eSjoerg   MCSymbol *Label;
4706f32e7eSjoerg   enum Operation {
4806f32e7eSjoerg     PushReg,
4906f32e7eSjoerg     StackAlloc,
5006f32e7eSjoerg     StackAlign,
5106f32e7eSjoerg     SetFrame,
5206f32e7eSjoerg   } Op;
5306f32e7eSjoerg   unsigned RegOrOffset;
5406f32e7eSjoerg };
5506f32e7eSjoerg 
5606f32e7eSjoerg struct FPOData {
5706f32e7eSjoerg   const MCSymbol *Function = nullptr;
5806f32e7eSjoerg   MCSymbol *Begin = nullptr;
5906f32e7eSjoerg   MCSymbol *PrologueEnd = nullptr;
6006f32e7eSjoerg   MCSymbol *End = nullptr;
6106f32e7eSjoerg   unsigned ParamsSize = 0;
6206f32e7eSjoerg 
6306f32e7eSjoerg   SmallVector<FPOInstruction, 5> Instructions;
6406f32e7eSjoerg };
6506f32e7eSjoerg 
6606f32e7eSjoerg /// Implements Windows x86-only directives for object emission.
6706f32e7eSjoerg class X86WinCOFFTargetStreamer : public X86TargetStreamer {
6806f32e7eSjoerg   /// Map from function symbol to its FPO data.
6906f32e7eSjoerg   DenseMap<const MCSymbol *, std::unique_ptr<FPOData>> AllFPOData;
7006f32e7eSjoerg 
7106f32e7eSjoerg   /// Current FPO data created by .cv_fpo_proc.
7206f32e7eSjoerg   std::unique_ptr<FPOData> CurFPOData;
7306f32e7eSjoerg 
haveOpenFPOData()7406f32e7eSjoerg   bool haveOpenFPOData() { return !!CurFPOData; }
7506f32e7eSjoerg 
7606f32e7eSjoerg   /// Diagnoses an error at L if we are not in an FPO prologue. Return true on
7706f32e7eSjoerg   /// error.
7806f32e7eSjoerg   bool checkInFPOPrologue(SMLoc L);
7906f32e7eSjoerg 
8006f32e7eSjoerg   MCSymbol *emitFPOLabel();
8106f32e7eSjoerg 
getContext()8206f32e7eSjoerg   MCContext &getContext() { return getStreamer().getContext(); }
8306f32e7eSjoerg 
8406f32e7eSjoerg public:
X86WinCOFFTargetStreamer(MCStreamer & S)8506f32e7eSjoerg   X86WinCOFFTargetStreamer(MCStreamer &S) : X86TargetStreamer(S) {}
8606f32e7eSjoerg 
8706f32e7eSjoerg   bool emitFPOProc(const MCSymbol *ProcSym, unsigned ParamsSize,
8806f32e7eSjoerg                    SMLoc L) override;
8906f32e7eSjoerg   bool emitFPOEndPrologue(SMLoc L) override;
9006f32e7eSjoerg   bool emitFPOEndProc(SMLoc L) override;
9106f32e7eSjoerg   bool emitFPOData(const MCSymbol *ProcSym, SMLoc L) override;
9206f32e7eSjoerg   bool emitFPOPushReg(unsigned Reg, SMLoc L) override;
9306f32e7eSjoerg   bool emitFPOStackAlloc(unsigned StackAlloc, SMLoc L) override;
9406f32e7eSjoerg   bool emitFPOStackAlign(unsigned Align, SMLoc L) override;
9506f32e7eSjoerg   bool emitFPOSetFrame(unsigned Reg, SMLoc L) override;
9606f32e7eSjoerg };
9706f32e7eSjoerg } // end namespace
9806f32e7eSjoerg 
emitFPOProc(const MCSymbol * ProcSym,unsigned ParamsSize,SMLoc L)9906f32e7eSjoerg bool X86WinCOFFAsmTargetStreamer::emitFPOProc(const MCSymbol *ProcSym,
10006f32e7eSjoerg                                               unsigned ParamsSize, SMLoc L) {
10106f32e7eSjoerg   OS << "\t.cv_fpo_proc\t";
10206f32e7eSjoerg   ProcSym->print(OS, getStreamer().getContext().getAsmInfo());
10306f32e7eSjoerg   OS << ' ' << ParamsSize << '\n';
10406f32e7eSjoerg   return false;
10506f32e7eSjoerg }
10606f32e7eSjoerg 
emitFPOEndPrologue(SMLoc L)10706f32e7eSjoerg bool X86WinCOFFAsmTargetStreamer::emitFPOEndPrologue(SMLoc L) {
10806f32e7eSjoerg   OS << "\t.cv_fpo_endprologue\n";
10906f32e7eSjoerg   return false;
11006f32e7eSjoerg }
11106f32e7eSjoerg 
emitFPOEndProc(SMLoc L)11206f32e7eSjoerg bool X86WinCOFFAsmTargetStreamer::emitFPOEndProc(SMLoc L) {
11306f32e7eSjoerg   OS << "\t.cv_fpo_endproc\n";
11406f32e7eSjoerg   return false;
11506f32e7eSjoerg }
11606f32e7eSjoerg 
emitFPOData(const MCSymbol * ProcSym,SMLoc L)11706f32e7eSjoerg bool X86WinCOFFAsmTargetStreamer::emitFPOData(const MCSymbol *ProcSym,
11806f32e7eSjoerg                                               SMLoc L) {
11906f32e7eSjoerg   OS << "\t.cv_fpo_data\t";
12006f32e7eSjoerg   ProcSym->print(OS, getStreamer().getContext().getAsmInfo());
12106f32e7eSjoerg   OS << '\n';
12206f32e7eSjoerg   return false;
12306f32e7eSjoerg }
12406f32e7eSjoerg 
emitFPOPushReg(unsigned Reg,SMLoc L)12506f32e7eSjoerg bool X86WinCOFFAsmTargetStreamer::emitFPOPushReg(unsigned Reg, SMLoc L) {
12606f32e7eSjoerg   OS << "\t.cv_fpo_pushreg\t";
12706f32e7eSjoerg   InstPrinter.printRegName(OS, Reg);
12806f32e7eSjoerg   OS << '\n';
12906f32e7eSjoerg   return false;
13006f32e7eSjoerg }
13106f32e7eSjoerg 
emitFPOStackAlloc(unsigned StackAlloc,SMLoc L)13206f32e7eSjoerg bool X86WinCOFFAsmTargetStreamer::emitFPOStackAlloc(unsigned StackAlloc,
13306f32e7eSjoerg                                                     SMLoc L) {
13406f32e7eSjoerg   OS << "\t.cv_fpo_stackalloc\t" << StackAlloc << '\n';
13506f32e7eSjoerg   return false;
13606f32e7eSjoerg }
13706f32e7eSjoerg 
emitFPOStackAlign(unsigned Align,SMLoc L)13806f32e7eSjoerg bool X86WinCOFFAsmTargetStreamer::emitFPOStackAlign(unsigned Align, SMLoc L) {
13906f32e7eSjoerg   OS << "\t.cv_fpo_stackalign\t" << Align << '\n';
14006f32e7eSjoerg   return false;
14106f32e7eSjoerg }
14206f32e7eSjoerg 
emitFPOSetFrame(unsigned Reg,SMLoc L)14306f32e7eSjoerg bool X86WinCOFFAsmTargetStreamer::emitFPOSetFrame(unsigned Reg, SMLoc L) {
14406f32e7eSjoerg   OS << "\t.cv_fpo_setframe\t";
14506f32e7eSjoerg   InstPrinter.printRegName(OS, Reg);
14606f32e7eSjoerg   OS << '\n';
14706f32e7eSjoerg   return false;
14806f32e7eSjoerg }
14906f32e7eSjoerg 
checkInFPOPrologue(SMLoc L)15006f32e7eSjoerg bool X86WinCOFFTargetStreamer::checkInFPOPrologue(SMLoc L) {
15106f32e7eSjoerg   if (!haveOpenFPOData() || CurFPOData->PrologueEnd) {
15206f32e7eSjoerg     getContext().reportError(
15306f32e7eSjoerg         L,
15406f32e7eSjoerg         "directive must appear between .cv_fpo_proc and .cv_fpo_endprologue");
15506f32e7eSjoerg     return true;
15606f32e7eSjoerg   }
15706f32e7eSjoerg   return false;
15806f32e7eSjoerg }
15906f32e7eSjoerg 
emitFPOLabel()16006f32e7eSjoerg MCSymbol *X86WinCOFFTargetStreamer::emitFPOLabel() {
16106f32e7eSjoerg   MCSymbol *Label = getContext().createTempSymbol("cfi", true);
162*da58b97aSjoerg   getStreamer().emitLabel(Label);
16306f32e7eSjoerg   return Label;
16406f32e7eSjoerg }
16506f32e7eSjoerg 
emitFPOProc(const MCSymbol * ProcSym,unsigned ParamsSize,SMLoc L)16606f32e7eSjoerg bool X86WinCOFFTargetStreamer::emitFPOProc(const MCSymbol *ProcSym,
16706f32e7eSjoerg                                            unsigned ParamsSize, SMLoc L) {
16806f32e7eSjoerg   if (haveOpenFPOData()) {
16906f32e7eSjoerg     getContext().reportError(
17006f32e7eSjoerg         L, "opening new .cv_fpo_proc before closing previous frame");
17106f32e7eSjoerg     return true;
17206f32e7eSjoerg   }
17306f32e7eSjoerg   CurFPOData = std::make_unique<FPOData>();
17406f32e7eSjoerg   CurFPOData->Function = ProcSym;
17506f32e7eSjoerg   CurFPOData->Begin = emitFPOLabel();
17606f32e7eSjoerg   CurFPOData->ParamsSize = ParamsSize;
17706f32e7eSjoerg   return false;
17806f32e7eSjoerg }
17906f32e7eSjoerg 
emitFPOEndProc(SMLoc L)18006f32e7eSjoerg bool X86WinCOFFTargetStreamer::emitFPOEndProc(SMLoc L) {
18106f32e7eSjoerg   if (!haveOpenFPOData()) {
18206f32e7eSjoerg     getContext().reportError(L, ".cv_fpo_endproc must appear after .cv_proc");
18306f32e7eSjoerg     return true;
18406f32e7eSjoerg   }
18506f32e7eSjoerg   if (!CurFPOData->PrologueEnd) {
18606f32e7eSjoerg     // Complain if there were prologue setup instructions but no end prologue.
18706f32e7eSjoerg     if (!CurFPOData->Instructions.empty()) {
18806f32e7eSjoerg       getContext().reportError(L, "missing .cv_fpo_endprologue");
18906f32e7eSjoerg       CurFPOData->Instructions.clear();
19006f32e7eSjoerg     }
19106f32e7eSjoerg 
19206f32e7eSjoerg     // Claim there is a zero-length prologue to make the label math work out
19306f32e7eSjoerg     // later.
19406f32e7eSjoerg     CurFPOData->PrologueEnd = CurFPOData->Begin;
19506f32e7eSjoerg   }
19606f32e7eSjoerg 
19706f32e7eSjoerg   CurFPOData->End = emitFPOLabel();
19806f32e7eSjoerg   const MCSymbol *Fn = CurFPOData->Function;
19906f32e7eSjoerg   AllFPOData.insert({Fn, std::move(CurFPOData)});
20006f32e7eSjoerg   return false;
20106f32e7eSjoerg }
20206f32e7eSjoerg 
emitFPOSetFrame(unsigned Reg,SMLoc L)20306f32e7eSjoerg bool X86WinCOFFTargetStreamer::emitFPOSetFrame(unsigned Reg, SMLoc L) {
20406f32e7eSjoerg   if (checkInFPOPrologue(L))
20506f32e7eSjoerg     return true;
20606f32e7eSjoerg   FPOInstruction Inst;
20706f32e7eSjoerg   Inst.Label = emitFPOLabel();
20806f32e7eSjoerg   Inst.Op = FPOInstruction::SetFrame;
20906f32e7eSjoerg   Inst.RegOrOffset = Reg;
21006f32e7eSjoerg   CurFPOData->Instructions.push_back(Inst);
21106f32e7eSjoerg   return false;
21206f32e7eSjoerg }
21306f32e7eSjoerg 
emitFPOPushReg(unsigned Reg,SMLoc L)21406f32e7eSjoerg bool X86WinCOFFTargetStreamer::emitFPOPushReg(unsigned Reg, SMLoc L) {
21506f32e7eSjoerg   if (checkInFPOPrologue(L))
21606f32e7eSjoerg     return true;
21706f32e7eSjoerg   FPOInstruction Inst;
21806f32e7eSjoerg   Inst.Label = emitFPOLabel();
21906f32e7eSjoerg   Inst.Op = FPOInstruction::PushReg;
22006f32e7eSjoerg   Inst.RegOrOffset = Reg;
22106f32e7eSjoerg   CurFPOData->Instructions.push_back(Inst);
22206f32e7eSjoerg   return false;
22306f32e7eSjoerg }
22406f32e7eSjoerg 
emitFPOStackAlloc(unsigned StackAlloc,SMLoc L)22506f32e7eSjoerg bool X86WinCOFFTargetStreamer::emitFPOStackAlloc(unsigned StackAlloc, SMLoc L) {
22606f32e7eSjoerg   if (checkInFPOPrologue(L))
22706f32e7eSjoerg     return true;
22806f32e7eSjoerg   FPOInstruction Inst;
22906f32e7eSjoerg   Inst.Label = emitFPOLabel();
23006f32e7eSjoerg   Inst.Op = FPOInstruction::StackAlloc;
23106f32e7eSjoerg   Inst.RegOrOffset = StackAlloc;
23206f32e7eSjoerg   CurFPOData->Instructions.push_back(Inst);
23306f32e7eSjoerg   return false;
23406f32e7eSjoerg }
23506f32e7eSjoerg 
emitFPOStackAlign(unsigned Align,SMLoc L)23606f32e7eSjoerg bool X86WinCOFFTargetStreamer::emitFPOStackAlign(unsigned Align, SMLoc L) {
23706f32e7eSjoerg   if (checkInFPOPrologue(L))
23806f32e7eSjoerg     return true;
23906f32e7eSjoerg   if (!llvm::any_of(CurFPOData->Instructions, [](const FPOInstruction &Inst) {
24006f32e7eSjoerg         return Inst.Op == FPOInstruction::SetFrame;
24106f32e7eSjoerg       })) {
24206f32e7eSjoerg     getContext().reportError(
24306f32e7eSjoerg         L, "a frame register must be established before aligning the stack");
24406f32e7eSjoerg     return true;
24506f32e7eSjoerg   }
24606f32e7eSjoerg   FPOInstruction Inst;
24706f32e7eSjoerg   Inst.Label = emitFPOLabel();
24806f32e7eSjoerg   Inst.Op = FPOInstruction::StackAlign;
24906f32e7eSjoerg   Inst.RegOrOffset = Align;
25006f32e7eSjoerg   CurFPOData->Instructions.push_back(Inst);
25106f32e7eSjoerg   return false;
25206f32e7eSjoerg }
25306f32e7eSjoerg 
emitFPOEndPrologue(SMLoc L)25406f32e7eSjoerg bool X86WinCOFFTargetStreamer::emitFPOEndPrologue(SMLoc L) {
25506f32e7eSjoerg   if (checkInFPOPrologue(L))
25606f32e7eSjoerg     return true;
25706f32e7eSjoerg   CurFPOData->PrologueEnd = emitFPOLabel();
25806f32e7eSjoerg   return false;
25906f32e7eSjoerg }
26006f32e7eSjoerg 
26106f32e7eSjoerg namespace {
26206f32e7eSjoerg struct RegSaveOffset {
RegSaveOffset__anon1b24917d0311::RegSaveOffset26306f32e7eSjoerg   RegSaveOffset(unsigned Reg, unsigned Offset) : Reg(Reg), Offset(Offset) {}
26406f32e7eSjoerg 
26506f32e7eSjoerg   unsigned Reg = 0;
26606f32e7eSjoerg   unsigned Offset = 0;
26706f32e7eSjoerg };
26806f32e7eSjoerg 
26906f32e7eSjoerg struct FPOStateMachine {
FPOStateMachine__anon1b24917d0311::FPOStateMachine27006f32e7eSjoerg   explicit FPOStateMachine(const FPOData *FPO) : FPO(FPO) {}
27106f32e7eSjoerg 
27206f32e7eSjoerg   const FPOData *FPO = nullptr;
27306f32e7eSjoerg   unsigned FrameReg = 0;
27406f32e7eSjoerg   unsigned FrameRegOff = 0;
27506f32e7eSjoerg   unsigned CurOffset = 0;
27606f32e7eSjoerg   unsigned LocalSize = 0;
27706f32e7eSjoerg   unsigned SavedRegSize = 0;
27806f32e7eSjoerg   unsigned StackOffsetBeforeAlign = 0;
27906f32e7eSjoerg   unsigned StackAlign = 0;
28006f32e7eSjoerg   unsigned Flags = 0; // FIXME: Set HasSEH / HasEH.
28106f32e7eSjoerg 
28206f32e7eSjoerg   SmallString<128> FrameFunc;
28306f32e7eSjoerg 
28406f32e7eSjoerg   SmallVector<RegSaveOffset, 4> RegSaveOffsets;
28506f32e7eSjoerg 
28606f32e7eSjoerg   void emitFrameDataRecord(MCStreamer &OS, MCSymbol *Label);
28706f32e7eSjoerg };
28806f32e7eSjoerg } // end namespace
28906f32e7eSjoerg 
printFPOReg(const MCRegisterInfo * MRI,unsigned LLVMReg)29006f32e7eSjoerg static Printable printFPOReg(const MCRegisterInfo *MRI, unsigned LLVMReg) {
29106f32e7eSjoerg   return Printable([MRI, LLVMReg](raw_ostream &OS) {
29206f32e7eSjoerg     switch (LLVMReg) {
29306f32e7eSjoerg     // MSVC only seems to emit symbolic register names for EIP, EBP, and ESP,
29406f32e7eSjoerg     // but the format seems to support more than that, so we emit them.
29506f32e7eSjoerg     case X86::EAX: OS << "$eax"; break;
29606f32e7eSjoerg     case X86::EBX: OS << "$ebx"; break;
29706f32e7eSjoerg     case X86::ECX: OS << "$ecx"; break;
29806f32e7eSjoerg     case X86::EDX: OS << "$edx"; break;
29906f32e7eSjoerg     case X86::EDI: OS << "$edi"; break;
30006f32e7eSjoerg     case X86::ESI: OS << "$esi"; break;
30106f32e7eSjoerg     case X86::ESP: OS << "$esp"; break;
30206f32e7eSjoerg     case X86::EBP: OS << "$ebp"; break;
30306f32e7eSjoerg     case X86::EIP: OS << "$eip"; break;
30406f32e7eSjoerg     // Otherwise, get the codeview register number and print $N.
30506f32e7eSjoerg     default:
30606f32e7eSjoerg       OS << '$' << MRI->getCodeViewRegNum(LLVMReg);
30706f32e7eSjoerg       break;
30806f32e7eSjoerg     }
30906f32e7eSjoerg   });
31006f32e7eSjoerg }
31106f32e7eSjoerg 
emitFrameDataRecord(MCStreamer & OS,MCSymbol * Label)31206f32e7eSjoerg void FPOStateMachine::emitFrameDataRecord(MCStreamer &OS, MCSymbol *Label) {
31306f32e7eSjoerg   unsigned CurFlags = Flags;
31406f32e7eSjoerg   if (Label == FPO->Begin)
31506f32e7eSjoerg     CurFlags |= FrameData::IsFunctionStart;
31606f32e7eSjoerg 
31706f32e7eSjoerg   // Compute the new FrameFunc string.
31806f32e7eSjoerg   FrameFunc.clear();
31906f32e7eSjoerg   raw_svector_ostream FuncOS(FrameFunc);
32006f32e7eSjoerg   const MCRegisterInfo *MRI = OS.getContext().getRegisterInfo();
32106f32e7eSjoerg   assert((StackAlign == 0 || FrameReg != 0) &&
32206f32e7eSjoerg          "cannot align stack without frame reg");
32306f32e7eSjoerg   StringRef CFAVar = StackAlign == 0 ? "$T0" : "$T1";
32406f32e7eSjoerg 
32506f32e7eSjoerg   if (FrameReg) {
32606f32e7eSjoerg     // CFA is FrameReg + FrameRegOff.
32706f32e7eSjoerg     FuncOS << CFAVar << ' ' << printFPOReg(MRI, FrameReg) << ' ' << FrameRegOff
32806f32e7eSjoerg            << " + = ";
32906f32e7eSjoerg 
33006f32e7eSjoerg     // Assign $T0, the VFRAME register, the value of ESP after it is aligned.
33106f32e7eSjoerg     // Starting from the CFA, we subtract the size of all pushed registers, and
33206f32e7eSjoerg     // align the result. While we don't store any CSRs in this area, $T0 is used
33306f32e7eSjoerg     // by S_DEFRANGE_FRAMEPOINTER_REL records to find local variables.
33406f32e7eSjoerg     if (StackAlign) {
33506f32e7eSjoerg       FuncOS << "$T0 " << CFAVar << ' ' << StackOffsetBeforeAlign << " - "
33606f32e7eSjoerg              << StackAlign << " @ = ";
33706f32e7eSjoerg     }
33806f32e7eSjoerg   } else {
33906f32e7eSjoerg     // The address of return address is ESP + CurOffset, but we use .raSearch to
34006f32e7eSjoerg     // match MSVC. This seems to ask the debugger to subtract some combination
34106f32e7eSjoerg     // of LocalSize and SavedRegSize from ESP and grovel around in that memory
34206f32e7eSjoerg     // to find the address of a plausible return address.
34306f32e7eSjoerg     FuncOS << CFAVar << " .raSearch = ";
34406f32e7eSjoerg   }
34506f32e7eSjoerg 
34606f32e7eSjoerg   // Caller's $eip should be dereferenced CFA, and $esp should be CFA plus 4.
34706f32e7eSjoerg   FuncOS << "$eip " << CFAVar << " ^ = ";
34806f32e7eSjoerg   FuncOS << "$esp " << CFAVar << " 4 + = ";
34906f32e7eSjoerg 
35006f32e7eSjoerg   // Each saved register is stored at an unchanging negative CFA offset.
35106f32e7eSjoerg   for (RegSaveOffset RO : RegSaveOffsets)
35206f32e7eSjoerg     FuncOS << printFPOReg(MRI, RO.Reg) << ' ' << CFAVar << ' ' << RO.Offset
35306f32e7eSjoerg            << " - ^ = ";
35406f32e7eSjoerg 
35506f32e7eSjoerg   // Add it to the CV string table.
35606f32e7eSjoerg   CodeViewContext &CVCtx = OS.getContext().getCVContext();
35706f32e7eSjoerg   unsigned FrameFuncStrTabOff = CVCtx.addToStringTable(FuncOS.str()).second;
35806f32e7eSjoerg 
35906f32e7eSjoerg   // MSVC has only ever been observed to emit a MaxStackSize of zero.
36006f32e7eSjoerg   unsigned MaxStackSize = 0;
36106f32e7eSjoerg 
36206f32e7eSjoerg   // The FrameData record format is:
36306f32e7eSjoerg   //   ulittle32_t RvaStart;
36406f32e7eSjoerg   //   ulittle32_t CodeSize;
36506f32e7eSjoerg   //   ulittle32_t LocalSize;
36606f32e7eSjoerg   //   ulittle32_t ParamsSize;
36706f32e7eSjoerg   //   ulittle32_t MaxStackSize;
36806f32e7eSjoerg   //   ulittle32_t FrameFunc; // String table offset
36906f32e7eSjoerg   //   ulittle16_t PrologSize;
37006f32e7eSjoerg   //   ulittle16_t SavedRegsSize;
37106f32e7eSjoerg   //   ulittle32_t Flags;
37206f32e7eSjoerg 
37306f32e7eSjoerg   OS.emitAbsoluteSymbolDiff(Label, FPO->Begin, 4); // RvaStart
37406f32e7eSjoerg   OS.emitAbsoluteSymbolDiff(FPO->End, Label, 4);   // CodeSize
375*da58b97aSjoerg   OS.emitInt32(LocalSize);
376*da58b97aSjoerg   OS.emitInt32(FPO->ParamsSize);
377*da58b97aSjoerg   OS.emitInt32(MaxStackSize);
378*da58b97aSjoerg   OS.emitInt32(FrameFuncStrTabOff); // FrameFunc
37906f32e7eSjoerg   OS.emitAbsoluteSymbolDiff(FPO->PrologueEnd, Label, 2);
380*da58b97aSjoerg   OS.emitInt16(SavedRegSize);
381*da58b97aSjoerg   OS.emitInt32(CurFlags);
38206f32e7eSjoerg }
38306f32e7eSjoerg 
38406f32e7eSjoerg /// Compute and emit the real CodeView FrameData subsection.
emitFPOData(const MCSymbol * ProcSym,SMLoc L)38506f32e7eSjoerg bool X86WinCOFFTargetStreamer::emitFPOData(const MCSymbol *ProcSym, SMLoc L) {
38606f32e7eSjoerg   MCStreamer &OS = getStreamer();
38706f32e7eSjoerg   MCContext &Ctx = OS.getContext();
38806f32e7eSjoerg 
38906f32e7eSjoerg   auto I = AllFPOData.find(ProcSym);
39006f32e7eSjoerg   if (I == AllFPOData.end()) {
39106f32e7eSjoerg     Ctx.reportError(L, Twine("no FPO data found for symbol ") +
39206f32e7eSjoerg                            ProcSym->getName());
39306f32e7eSjoerg     return true;
39406f32e7eSjoerg   }
39506f32e7eSjoerg   const FPOData *FPO = I->second.get();
39606f32e7eSjoerg   assert(FPO->Begin && FPO->End && FPO->PrologueEnd && "missing FPO label");
39706f32e7eSjoerg 
39806f32e7eSjoerg   MCSymbol *FrameBegin = Ctx.createTempSymbol(),
39906f32e7eSjoerg            *FrameEnd = Ctx.createTempSymbol();
40006f32e7eSjoerg 
401*da58b97aSjoerg   OS.emitInt32(unsigned(DebugSubsectionKind::FrameData));
40206f32e7eSjoerg   OS.emitAbsoluteSymbolDiff(FrameEnd, FrameBegin, 4);
403*da58b97aSjoerg   OS.emitLabel(FrameBegin);
40406f32e7eSjoerg 
40506f32e7eSjoerg   // Start with the RVA of the function in question.
406*da58b97aSjoerg   OS.emitValue(MCSymbolRefExpr::create(FPO->Function,
40706f32e7eSjoerg                                        MCSymbolRefExpr::VK_COFF_IMGREL32, Ctx),
40806f32e7eSjoerg                4);
40906f32e7eSjoerg 
41006f32e7eSjoerg   // Emit a sequence of FrameData records.
41106f32e7eSjoerg   FPOStateMachine FSM(FPO);
41206f32e7eSjoerg 
41306f32e7eSjoerg   FSM.emitFrameDataRecord(OS, FPO->Begin);
41406f32e7eSjoerg   for (const FPOInstruction &Inst : FPO->Instructions) {
41506f32e7eSjoerg     switch (Inst.Op) {
41606f32e7eSjoerg     case FPOInstruction::PushReg:
41706f32e7eSjoerg       FSM.CurOffset += 4;
41806f32e7eSjoerg       FSM.SavedRegSize += 4;
41906f32e7eSjoerg       FSM.RegSaveOffsets.push_back({Inst.RegOrOffset, FSM.CurOffset});
42006f32e7eSjoerg       break;
42106f32e7eSjoerg     case FPOInstruction::SetFrame:
42206f32e7eSjoerg       FSM.FrameReg = Inst.RegOrOffset;
42306f32e7eSjoerg       FSM.FrameRegOff = FSM.CurOffset;
42406f32e7eSjoerg       break;
42506f32e7eSjoerg     case FPOInstruction::StackAlign:
42606f32e7eSjoerg       FSM.StackOffsetBeforeAlign = FSM.CurOffset;
42706f32e7eSjoerg       FSM.StackAlign = Inst.RegOrOffset;
42806f32e7eSjoerg       break;
42906f32e7eSjoerg     case FPOInstruction::StackAlloc:
43006f32e7eSjoerg       FSM.CurOffset += Inst.RegOrOffset;
43106f32e7eSjoerg       FSM.LocalSize += Inst.RegOrOffset;
43206f32e7eSjoerg       // No need to emit FrameData for stack allocations with a frame pointer.
43306f32e7eSjoerg       if (FSM.FrameReg)
43406f32e7eSjoerg         continue;
43506f32e7eSjoerg       break;
43606f32e7eSjoerg     }
43706f32e7eSjoerg     FSM.emitFrameDataRecord(OS, Inst.Label);
43806f32e7eSjoerg   }
43906f32e7eSjoerg 
440*da58b97aSjoerg   OS.emitValueToAlignment(4, 0);
441*da58b97aSjoerg   OS.emitLabel(FrameEnd);
44206f32e7eSjoerg   return false;
44306f32e7eSjoerg }
44406f32e7eSjoerg 
createX86AsmTargetStreamer(MCStreamer & S,formatted_raw_ostream & OS,MCInstPrinter * InstPrinter,bool IsVerboseAsm)44506f32e7eSjoerg MCTargetStreamer *llvm::createX86AsmTargetStreamer(MCStreamer &S,
44606f32e7eSjoerg                                                    formatted_raw_ostream &OS,
44706f32e7eSjoerg                                                    MCInstPrinter *InstPrinter,
44806f32e7eSjoerg                                                    bool IsVerboseAsm) {
44906f32e7eSjoerg   // FIXME: This makes it so we textually assemble COFF directives on ELF.
45006f32e7eSjoerg   // That's kind of nonsensical.
45106f32e7eSjoerg   return new X86WinCOFFAsmTargetStreamer(S, OS, *InstPrinter);
45206f32e7eSjoerg }
45306f32e7eSjoerg 
45406f32e7eSjoerg MCTargetStreamer *
createX86ObjectTargetStreamer(MCStreamer & S,const MCSubtargetInfo & STI)45506f32e7eSjoerg llvm::createX86ObjectTargetStreamer(MCStreamer &S, const MCSubtargetInfo &STI) {
45606f32e7eSjoerg   // No need to register a target streamer.
45706f32e7eSjoerg   if (!STI.getTargetTriple().isOSBinFormatCOFF())
45806f32e7eSjoerg     return nullptr;
45906f32e7eSjoerg   // Registers itself to the MCStreamer.
46006f32e7eSjoerg   return new X86WinCOFFTargetStreamer(S);
46106f32e7eSjoerg }
462