X86WinCOFFTargetStreamer.cpp 15 KB

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