]> CyberLeo.Net >> Repos - FreeBSD/FreeBSD.git/blob - contrib/llvm/lib/Target/X86/MCTargetDesc/X86WinCOFFTargetStreamer.cpp
Merge llvm, clang, compiler-rt, libc++, libunwind, lld, lldb and openmp
[FreeBSD/FreeBSD.git] / contrib / llvm / lib / Target / X86 / MCTargetDesc / X86WinCOFFTargetStreamer.cpp
1 //===-- X86WinCOFFTargetStreamer.cpp ----------------------------*- C++ -*-===//
2 //
3 //                     The LLVM Compiler Infrastructure
4 //
5 // This file is distributed under the University of Illinois Open Source
6 // License. See LICENSE.TXT for details.
7 //
8 //===----------------------------------------------------------------------===//
9
10 #include "X86MCTargetDesc.h"
11 #include "X86TargetStreamer.h"
12 #include "llvm/DebugInfo/CodeView/CodeView.h"
13 #include "llvm/MC/MCCodeView.h"
14 #include "llvm/MC/MCContext.h"
15 #include "llvm/MC/MCInstPrinter.h"
16 #include "llvm/MC/MCRegisterInfo.h"
17 #include "llvm/MC/MCSubtargetInfo.h"
18 #include "llvm/Support/FormattedStream.h"
19
20 using namespace llvm;
21 using namespace llvm::codeview;
22
23 namespace {
24 /// Implements Windows x86-only directives for assembly emission.
25 class X86WinCOFFAsmTargetStreamer : public X86TargetStreamer {
26   formatted_raw_ostream &OS;
27   MCInstPrinter &InstPrinter;
28
29 public:
30   X86WinCOFFAsmTargetStreamer(MCStreamer &S, formatted_raw_ostream &OS,
31                               MCInstPrinter &InstPrinter)
32       : X86TargetStreamer(S), OS(OS), InstPrinter(InstPrinter) {}
33
34   bool emitFPOProc(const MCSymbol *ProcSym, unsigned ParamsSize,
35                    SMLoc L) override;
36   bool emitFPOEndPrologue(SMLoc L) override;
37   bool emitFPOEndProc(SMLoc L) override;
38   bool emitFPOData(const MCSymbol *ProcSym, SMLoc L) override;
39   bool emitFPOPushReg(unsigned Reg, SMLoc L) override;
40   bool emitFPOStackAlloc(unsigned StackAlloc, SMLoc L) override;
41   bool emitFPOStackAlign(unsigned Align, SMLoc L) override;
42   bool emitFPOSetFrame(unsigned Reg, SMLoc L) override;
43 };
44
45 /// Represents a single FPO directive.
46 struct FPOInstruction {
47   MCSymbol *Label;
48   enum Operation {
49     PushReg,
50     StackAlloc,
51     StackAlign,
52     SetFrame,
53   } Op;
54   unsigned RegOrOffset;
55 };
56
57 struct FPOData {
58   const MCSymbol *Function = nullptr;
59   MCSymbol *Begin = nullptr;
60   MCSymbol *PrologueEnd = nullptr;
61   MCSymbol *End = nullptr;
62   unsigned ParamsSize = 0;
63
64   SmallVector<FPOInstruction, 5> Instructions;
65 };
66
67 /// Implements Windows x86-only directives for object emission.
68 class X86WinCOFFTargetStreamer : public X86TargetStreamer {
69   /// Map from function symbol to its FPO data.
70   DenseMap<const MCSymbol *, std::unique_ptr<FPOData>> AllFPOData;
71
72   /// Current FPO data created by .cv_fpo_proc.
73   std::unique_ptr<FPOData> CurFPOData;
74
75   bool haveOpenFPOData() { return !!CurFPOData; }
76
77   /// Diagnoses an error at L if we are not in an FPO prologue. Return true on
78   /// error.
79   bool checkInFPOPrologue(SMLoc L);
80
81   MCSymbol *emitFPOLabel();
82
83   MCContext &getContext() { return getStreamer().getContext(); }
84
85 public:
86   X86WinCOFFTargetStreamer(MCStreamer &S) : X86TargetStreamer(S) {}
87
88   bool emitFPOProc(const MCSymbol *ProcSym, unsigned ParamsSize,
89                    SMLoc L) override;
90   bool emitFPOEndPrologue(SMLoc L) override;
91   bool emitFPOEndProc(SMLoc L) override;
92   bool emitFPOData(const MCSymbol *ProcSym, SMLoc L) override;
93   bool emitFPOPushReg(unsigned Reg, SMLoc L) override;
94   bool emitFPOStackAlloc(unsigned StackAlloc, SMLoc L) override;
95   bool emitFPOStackAlign(unsigned Align, SMLoc L) override;
96   bool emitFPOSetFrame(unsigned Reg, SMLoc L) override;
97 };
98 } // end namespace
99
100 bool X86WinCOFFAsmTargetStreamer::emitFPOProc(const MCSymbol *ProcSym,
101                                               unsigned ParamsSize, SMLoc L) {
102   OS << "\t.cv_fpo_proc\t";
103   ProcSym->print(OS, getStreamer().getContext().getAsmInfo());
104   OS << ' ' << ParamsSize << '\n';
105   return false;
106 }
107
108 bool X86WinCOFFAsmTargetStreamer::emitFPOEndPrologue(SMLoc L) {
109   OS << "\t.cv_fpo_endprologue\n";
110   return false;
111 }
112
113 bool X86WinCOFFAsmTargetStreamer::emitFPOEndProc(SMLoc L) {
114   OS << "\t.cv_fpo_endproc\n";
115   return false;
116 }
117
118 bool X86WinCOFFAsmTargetStreamer::emitFPOData(const MCSymbol *ProcSym,
119                                               SMLoc L) {
120   OS << "\t.cv_fpo_data\t";
121   ProcSym->print(OS, getStreamer().getContext().getAsmInfo());
122   OS << '\n';
123   return false;
124 }
125
126 bool X86WinCOFFAsmTargetStreamer::emitFPOPushReg(unsigned Reg, SMLoc L) {
127   OS << "\t.cv_fpo_pushreg\t";
128   InstPrinter.printRegName(OS, Reg);
129   OS << '\n';
130   return false;
131 }
132
133 bool X86WinCOFFAsmTargetStreamer::emitFPOStackAlloc(unsigned StackAlloc,
134                                                     SMLoc L) {
135   OS << "\t.cv_fpo_stackalloc\t" << StackAlloc << '\n';
136   return false;
137 }
138
139 bool X86WinCOFFAsmTargetStreamer::emitFPOStackAlign(unsigned Align, SMLoc L) {
140   OS << "\t.cv_fpo_stackalign\t" << Align << '\n';
141   return false;
142 }
143
144 bool X86WinCOFFAsmTargetStreamer::emitFPOSetFrame(unsigned Reg, SMLoc L) {
145   OS << "\t.cv_fpo_setframe\t";
146   InstPrinter.printRegName(OS, Reg);
147   OS << '\n';
148   return false;
149 }
150
151 bool X86WinCOFFTargetStreamer::checkInFPOPrologue(SMLoc L) {
152   if (!haveOpenFPOData() || CurFPOData->PrologueEnd) {
153     getContext().reportError(
154         L,
155         "directive must appear between .cv_fpo_proc and .cv_fpo_endprologue");
156     return true;
157   }
158   return false;
159 }
160
161 MCSymbol *X86WinCOFFTargetStreamer::emitFPOLabel() {
162   MCSymbol *Label = getContext().createTempSymbol("cfi", true);
163   getStreamer().EmitLabel(Label);
164   return Label;
165 }
166
167 bool X86WinCOFFTargetStreamer::emitFPOProc(const MCSymbol *ProcSym,
168                                            unsigned ParamsSize, SMLoc L) {
169   if (haveOpenFPOData()) {
170     getContext().reportError(
171         L, "opening new .cv_fpo_proc before closing previous frame");
172     return true;
173   }
174   CurFPOData = llvm::make_unique<FPOData>();
175   CurFPOData->Function = ProcSym;
176   CurFPOData->Begin = emitFPOLabel();
177   CurFPOData->ParamsSize = ParamsSize;
178   return false;
179 }
180
181 bool X86WinCOFFTargetStreamer::emitFPOEndProc(SMLoc L) {
182   if (!haveOpenFPOData()) {
183     getContext().reportError(L, ".cv_fpo_endproc must appear after .cv_proc");
184     return true;
185   }
186   if (!CurFPOData->PrologueEnd) {
187     // Complain if there were prologue setup instructions but no end prologue.
188     if (!CurFPOData->Instructions.empty()) {
189       getContext().reportError(L, "missing .cv_fpo_endprologue");
190       CurFPOData->Instructions.clear();
191     }
192
193     // Claim there is a zero-length prologue to make the label math work out
194     // later.
195     CurFPOData->PrologueEnd = CurFPOData->Begin;
196   }
197
198   CurFPOData->End = emitFPOLabel();
199   const MCSymbol *Fn = CurFPOData->Function;
200   AllFPOData.insert({Fn, std::move(CurFPOData)});
201   return false;
202 }
203
204 bool X86WinCOFFTargetStreamer::emitFPOSetFrame(unsigned Reg, SMLoc L) {
205   if (checkInFPOPrologue(L))
206     return true;
207   FPOInstruction Inst;
208   Inst.Label = emitFPOLabel();
209   Inst.Op = FPOInstruction::SetFrame;
210   Inst.RegOrOffset = Reg;
211   CurFPOData->Instructions.push_back(Inst);
212   return false;
213 }
214
215 bool X86WinCOFFTargetStreamer::emitFPOPushReg(unsigned Reg, SMLoc L) {
216   if (checkInFPOPrologue(L))
217     return true;
218   FPOInstruction Inst;
219   Inst.Label = emitFPOLabel();
220   Inst.Op = FPOInstruction::PushReg;
221   Inst.RegOrOffset = Reg;
222   CurFPOData->Instructions.push_back(Inst);
223   return false;
224 }
225
226 bool X86WinCOFFTargetStreamer::emitFPOStackAlloc(unsigned StackAlloc, SMLoc L) {
227   if (checkInFPOPrologue(L))
228     return true;
229   FPOInstruction Inst;
230   Inst.Label = emitFPOLabel();
231   Inst.Op = FPOInstruction::StackAlloc;
232   Inst.RegOrOffset = StackAlloc;
233   CurFPOData->Instructions.push_back(Inst);
234   return false;
235 }
236
237 bool X86WinCOFFTargetStreamer::emitFPOStackAlign(unsigned Align, SMLoc L) {
238   if (checkInFPOPrologue(L))
239     return true;
240   if (!llvm::any_of(CurFPOData->Instructions, [](const FPOInstruction &Inst) {
241         return Inst.Op == FPOInstruction::SetFrame;
242       })) {
243     getContext().reportError(
244         L, "a frame register must be established before aligning the stack");
245     return true;
246   }
247   FPOInstruction Inst;
248   Inst.Label = emitFPOLabel();
249   Inst.Op = FPOInstruction::StackAlign;
250   Inst.RegOrOffset = Align;
251   CurFPOData->Instructions.push_back(Inst);
252   return false;
253 }
254
255 bool X86WinCOFFTargetStreamer::emitFPOEndPrologue(SMLoc L) {
256   if (checkInFPOPrologue(L))
257     return true;
258   CurFPOData->PrologueEnd = emitFPOLabel();
259   return false;
260 }
261
262 namespace {
263 struct RegSaveOffset {
264   RegSaveOffset(unsigned Reg, unsigned Offset) : Reg(Reg), Offset(Offset) {}
265
266   unsigned Reg = 0;
267   unsigned Offset = 0;
268 };
269
270 struct FPOStateMachine {
271   explicit FPOStateMachine(const FPOData *FPO) : FPO(FPO) {}
272
273   const FPOData *FPO = nullptr;
274   unsigned FrameReg = 0;
275   unsigned FrameRegOff = 0;
276   unsigned CurOffset = 0;
277   unsigned LocalSize = 0;
278   unsigned SavedRegSize = 0;
279   unsigned StackOffsetBeforeAlign = 0;
280   unsigned StackAlign = 0;
281   unsigned Flags = 0; // FIXME: Set HasSEH / HasEH.
282
283   SmallString<128> FrameFunc;
284
285   SmallVector<RegSaveOffset, 4> RegSaveOffsets;
286
287   void emitFrameDataRecord(MCStreamer &OS, MCSymbol *Label);
288 };
289 } // end namespace
290
291 static Printable printFPOReg(const MCRegisterInfo *MRI, unsigned LLVMReg) {
292   return Printable([MRI, LLVMReg](raw_ostream &OS) {
293     switch (LLVMReg) {
294     // MSVC only seems to emit symbolic register names for EIP, EBP, and ESP,
295     // but the format seems to support more than that, so we emit them.
296     case X86::EAX: OS << "$eax"; break;
297     case X86::EBX: OS << "$ebx"; break;
298     case X86::ECX: OS << "$ecx"; break;
299     case X86::EDX: OS << "$edx"; break;
300     case X86::EDI: OS << "$edi"; break;
301     case X86::ESI: OS << "$esi"; break;
302     case X86::ESP: OS << "$esp"; break;
303     case X86::EBP: OS << "$ebp"; break;
304     case X86::EIP: OS << "$eip"; break;
305     // Otherwise, get the codeview register number and print $N.
306     default:
307       OS << '$' << MRI->getCodeViewRegNum(LLVMReg);
308       break;
309     }
310   });
311 }
312
313 void FPOStateMachine::emitFrameDataRecord(MCStreamer &OS, MCSymbol *Label) {
314   unsigned CurFlags = Flags;
315   if (Label == FPO->Begin)
316     CurFlags |= FrameData::IsFunctionStart;
317
318   // Compute the new FrameFunc string.
319   FrameFunc.clear();
320   raw_svector_ostream FuncOS(FrameFunc);
321   const MCRegisterInfo *MRI = OS.getContext().getRegisterInfo();
322   assert((StackAlign == 0 || FrameReg != 0) &&
323          "cannot align stack without frame reg");
324   StringRef CFAVar = StackAlign == 0 ? "$T0" : "$T1";
325
326   if (FrameReg) {
327     // CFA is FrameReg + FrameRegOff.
328     FuncOS << CFAVar << ' ' << printFPOReg(MRI, FrameReg) << ' ' << FrameRegOff
329            << " + = ";
330
331     // Assign $T0, the VFRAME register, the value of ESP after it is aligned.
332     // Starting from the CFA, we subtract the size of all pushed registers, and
333     // align the result. While we don't store any CSRs in this area, $T0 is used
334     // by S_DEFRANGE_FRAMEPOINTER_REL records to find local variables.
335     if (StackAlign) {
336       FuncOS << "$T0 " << CFAVar << ' ' << StackOffsetBeforeAlign << " - "
337              << StackAlign << " @ = ";
338     }
339   } else {
340     // The address of return address is ESP + CurOffset, but we use .raSearch to
341     // match MSVC. This seems to ask the debugger to subtract some combination
342     // of LocalSize and SavedRegSize from ESP and grovel around in that memory
343     // to find the address of a plausible return address.
344     FuncOS << CFAVar << " .raSearch = ";
345   }
346
347   // Caller's $eip should be dereferenced CFA, and $esp should be CFA plus 4.
348   FuncOS << "$eip " << CFAVar << " ^ = ";
349   FuncOS << "$esp " << CFAVar << " 4 + = ";
350
351   // Each saved register is stored at an unchanging negative CFA offset.
352   for (RegSaveOffset RO : RegSaveOffsets)
353     FuncOS << printFPOReg(MRI, RO.Reg) << ' ' << CFAVar << ' ' << RO.Offset
354            << " - ^ = ";
355
356   // Add it to the CV string table.
357   CodeViewContext &CVCtx = OS.getContext().getCVContext();
358   unsigned FrameFuncStrTabOff = CVCtx.addToStringTable(FuncOS.str()).second;
359
360   // MSVC has only ever been observed to emit a MaxStackSize of zero.
361   unsigned MaxStackSize = 0;
362
363   // The FrameData record format is:
364   //   ulittle32_t RvaStart;
365   //   ulittle32_t CodeSize;
366   //   ulittle32_t LocalSize;
367   //   ulittle32_t ParamsSize;
368   //   ulittle32_t MaxStackSize;
369   //   ulittle32_t FrameFunc; // String table offset
370   //   ulittle16_t PrologSize;
371   //   ulittle16_t SavedRegsSize;
372   //   ulittle32_t Flags;
373
374   OS.emitAbsoluteSymbolDiff(Label, FPO->Begin, 4); // RvaStart
375   OS.emitAbsoluteSymbolDiff(FPO->End, Label, 4);   // CodeSize
376   OS.EmitIntValue(LocalSize, 4);
377   OS.EmitIntValue(FPO->ParamsSize, 4);
378   OS.EmitIntValue(MaxStackSize, 4);
379   OS.EmitIntValue(FrameFuncStrTabOff, 4); // FrameFunc
380   OS.emitAbsoluteSymbolDiff(FPO->PrologueEnd, Label, 2);
381   OS.EmitIntValue(SavedRegSize, 2);
382   OS.EmitIntValue(CurFlags, 4);
383 }
384
385 /// Compute and emit the real CodeView FrameData subsection.
386 bool X86WinCOFFTargetStreamer::emitFPOData(const MCSymbol *ProcSym, SMLoc L) {
387   MCStreamer &OS = getStreamer();
388   MCContext &Ctx = OS.getContext();
389
390   auto I = AllFPOData.find(ProcSym);
391   if (I == AllFPOData.end()) {
392     Ctx.reportError(L, Twine("no FPO data found for symbol ") +
393                            ProcSym->getName());
394     return true;
395   }
396   const FPOData *FPO = I->second.get();
397   assert(FPO->Begin && FPO->End && FPO->PrologueEnd && "missing FPO label");
398
399   MCSymbol *FrameBegin = Ctx.createTempSymbol(),
400            *FrameEnd = Ctx.createTempSymbol();
401
402   OS.EmitIntValue(unsigned(DebugSubsectionKind::FrameData), 4);
403   OS.emitAbsoluteSymbolDiff(FrameEnd, FrameBegin, 4);
404   OS.EmitLabel(FrameBegin);
405
406   // Start with the RVA of the function in question.
407   OS.EmitValue(MCSymbolRefExpr::create(FPO->Function,
408                                        MCSymbolRefExpr::VK_COFF_IMGREL32, Ctx),
409                4);
410
411   // Emit a sequence of FrameData records.
412   FPOStateMachine FSM(FPO);
413
414   FSM.emitFrameDataRecord(OS, FPO->Begin);
415   for (const FPOInstruction &Inst : FPO->Instructions) {
416     switch (Inst.Op) {
417     case FPOInstruction::PushReg:
418       FSM.CurOffset += 4;
419       FSM.SavedRegSize += 4;
420       FSM.RegSaveOffsets.push_back({Inst.RegOrOffset, FSM.CurOffset});
421       break;
422     case FPOInstruction::SetFrame:
423       FSM.FrameReg = Inst.RegOrOffset;
424       FSM.FrameRegOff = FSM.CurOffset;
425       break;
426     case FPOInstruction::StackAlign:
427       FSM.StackOffsetBeforeAlign = FSM.CurOffset;
428       FSM.StackAlign = Inst.RegOrOffset;
429       break;
430     case FPOInstruction::StackAlloc:
431       FSM.CurOffset += Inst.RegOrOffset;
432       FSM.LocalSize += Inst.RegOrOffset;
433       // No need to emit FrameData for stack allocations with a frame pointer.
434       if (FSM.FrameReg)
435         continue;
436       break;
437     }
438     FSM.emitFrameDataRecord(OS, Inst.Label);
439   }
440
441   OS.EmitValueToAlignment(4, 0);
442   OS.EmitLabel(FrameEnd);
443   return false;
444 }
445
446 MCTargetStreamer *llvm::createX86AsmTargetStreamer(MCStreamer &S,
447                                                    formatted_raw_ostream &OS,
448                                                    MCInstPrinter *InstPrinter,
449                                                    bool IsVerboseAsm) {
450   // FIXME: This makes it so we textually assemble COFF directives on ELF.
451   // That's kind of nonsensical.
452   return new X86WinCOFFAsmTargetStreamer(S, OS, *InstPrinter);
453 }
454
455 MCTargetStreamer *
456 llvm::createX86ObjectTargetStreamer(MCStreamer &S, const MCSubtargetInfo &STI) {
457   // No need to register a target streamer.
458   if (!STI.getTargetTriple().isOSBinFormatCOFF())
459     return nullptr;
460   // Registers itself to the MCStreamer.
461   return new X86WinCOFFTargetStreamer(S);
462 }