xref: /freebsd/contrib/llvm-project/llvm/lib/MC/MCWin64EH.cpp (revision 700637cbb5e582861067a11aaca4d053546871d2)
1 //===- lib/MC/MCWin64EH.cpp - MCWin64EH implementation --------------------===//
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/MC/MCWin64EH.h"
10 #include "llvm/ADT/Twine.h"
11 #include "llvm/MC/MCAssembler.h"
12 #include "llvm/MC/MCContext.h"
13 #include "llvm/MC/MCExpr.h"
14 #include "llvm/MC/MCObjectStreamer.h"
15 #include "llvm/MC/MCStreamer.h"
16 #include "llvm/MC/MCSymbol.h"
17 #include "llvm/MC/MCValue.h"
18 #include "llvm/Support/Win64EH.h"
19 
20 namespace llvm {
21 class MCSection;
22 
23 /// MCExpr that represents the epilog unwind code in an unwind table.
24 class MCUnwindV2EpilogTargetExpr final : public MCTargetExpr {
25   const MCSymbol *FunctionEnd;
26   const MCSymbol *UnwindV2Start;
27   const MCSymbol *EpilogEnd;
28   uint8_t EpilogSize;
29   SMLoc Loc;
30 
MCUnwindV2EpilogTargetExpr(const WinEH::FrameInfo & FrameInfo,const WinEH::FrameInfo::Epilog & Epilog,uint8_t EpilogSize_)31   MCUnwindV2EpilogTargetExpr(const WinEH::FrameInfo &FrameInfo,
32                              const WinEH::FrameInfo::Epilog &Epilog,
33                              uint8_t EpilogSize_)
34       : FunctionEnd(FrameInfo.FuncletOrFuncEnd),
35         UnwindV2Start(Epilog.UnwindV2Start), EpilogEnd(Epilog.End),
36         EpilogSize(EpilogSize_), Loc(Epilog.Loc) {}
37 
38 public:
39   static MCUnwindV2EpilogTargetExpr *
create(const WinEH::FrameInfo & FrameInfo,const WinEH::FrameInfo::Epilog & Epilog,uint8_t EpilogSize_,MCContext & Ctx)40   create(const WinEH::FrameInfo &FrameInfo,
41          const WinEH::FrameInfo::Epilog &Epilog, uint8_t EpilogSize_,
42          MCContext &Ctx) {
43     return new (Ctx) MCUnwindV2EpilogTargetExpr(FrameInfo, Epilog, EpilogSize_);
44   }
45 
printImpl(raw_ostream & OS,const MCAsmInfo * MAI) const46   void printImpl(raw_ostream &OS, const MCAsmInfo *MAI) const override {
47     OS << ":epilog:";
48     UnwindV2Start->print(OS, MAI);
49   }
50 
51   bool evaluateAsRelocatableImpl(MCValue &Res,
52                                  const MCAssembler *Asm) const override;
53 
visitUsedExpr(MCStreamer & Streamer) const54   void visitUsedExpr(MCStreamer &Streamer) const override {
55     // Contains no sub-expressions.
56   }
57 
findAssociatedFragment() const58   MCFragment *findAssociatedFragment() const override {
59     return UnwindV2Start->getFragment();
60   }
61 };
62 }
63 
64 using namespace llvm;
65 
66 // NOTE: All relocations generated here are 4-byte image-relative.
67 
CountOfUnwindCodes(std::vector<WinEH::Instruction> & Insns)68 static uint8_t CountOfUnwindCodes(std::vector<WinEH::Instruction> &Insns) {
69   uint8_t Count = 0;
70   for (const auto &I : Insns) {
71     switch (static_cast<Win64EH::UnwindOpcodes>(I.Operation)) {
72     default:
73       llvm_unreachable("Unsupported unwind code");
74     case Win64EH::UOP_PushNonVol:
75     case Win64EH::UOP_AllocSmall:
76     case Win64EH::UOP_SetFPReg:
77     case Win64EH::UOP_PushMachFrame:
78       Count += 1;
79       break;
80     case Win64EH::UOP_SaveNonVol:
81     case Win64EH::UOP_SaveXMM128:
82       Count += 2;
83       break;
84     case Win64EH::UOP_SaveNonVolBig:
85     case Win64EH::UOP_SaveXMM128Big:
86       Count += 3;
87       break;
88     case Win64EH::UOP_AllocLarge:
89       Count += (I.Offset > 512 * 1024 - 8) ? 3 : 2;
90       break;
91     }
92   }
93   return Count;
94 }
95 
EmitAbsDifference(MCStreamer & Streamer,const MCSymbol * LHS,const MCSymbol * RHS)96 static void EmitAbsDifference(MCStreamer &Streamer, const MCSymbol *LHS,
97                               const MCSymbol *RHS) {
98   MCContext &Context = Streamer.getContext();
99   const MCExpr *Diff =
100       MCBinaryExpr::createSub(MCSymbolRefExpr::create(LHS, Context),
101                               MCSymbolRefExpr::create(RHS, Context), Context);
102   Streamer.emitValue(Diff, 1);
103 }
104 
EmitUnwindCode(MCStreamer & streamer,const MCSymbol * begin,WinEH::Instruction & inst)105 static void EmitUnwindCode(MCStreamer &streamer, const MCSymbol *begin,
106                            WinEH::Instruction &inst) {
107   uint8_t b2;
108   uint16_t w;
109   b2 = (inst.Operation & 0x0F);
110   switch (static_cast<Win64EH::UnwindOpcodes>(inst.Operation)) {
111   default:
112     llvm_unreachable("Unsupported unwind code");
113   case Win64EH::UOP_PushNonVol:
114     EmitAbsDifference(streamer, inst.Label, begin);
115     b2 |= (inst.Register & 0x0F) << 4;
116     streamer.emitInt8(b2);
117     break;
118   case Win64EH::UOP_AllocLarge:
119     EmitAbsDifference(streamer, inst.Label, begin);
120     if (inst.Offset > 512 * 1024 - 8) {
121       b2 |= 0x10;
122       streamer.emitInt8(b2);
123       w = inst.Offset & 0xFFF8;
124       streamer.emitInt16(w);
125       w = inst.Offset >> 16;
126     } else {
127       streamer.emitInt8(b2);
128       w = inst.Offset >> 3;
129     }
130     streamer.emitInt16(w);
131     break;
132   case Win64EH::UOP_AllocSmall:
133     b2 |= (((inst.Offset - 8) >> 3) & 0x0F) << 4;
134     EmitAbsDifference(streamer, inst.Label, begin);
135     streamer.emitInt8(b2);
136     break;
137   case Win64EH::UOP_SetFPReg:
138     EmitAbsDifference(streamer, inst.Label, begin);
139     streamer.emitInt8(b2);
140     break;
141   case Win64EH::UOP_SaveNonVol:
142   case Win64EH::UOP_SaveXMM128:
143     b2 |= (inst.Register & 0x0F) << 4;
144     EmitAbsDifference(streamer, inst.Label, begin);
145     streamer.emitInt8(b2);
146     w = inst.Offset >> 3;
147     if (inst.Operation == Win64EH::UOP_SaveXMM128)
148       w >>= 1;
149     streamer.emitInt16(w);
150     break;
151   case Win64EH::UOP_SaveNonVolBig:
152   case Win64EH::UOP_SaveXMM128Big:
153     b2 |= (inst.Register & 0x0F) << 4;
154     EmitAbsDifference(streamer, inst.Label, begin);
155     streamer.emitInt8(b2);
156     if (inst.Operation == Win64EH::UOP_SaveXMM128Big)
157       w = inst.Offset & 0xFFF0;
158     else
159       w = inst.Offset & 0xFFF8;
160     streamer.emitInt16(w);
161     w = inst.Offset >> 16;
162     streamer.emitInt16(w);
163     break;
164   case Win64EH::UOP_PushMachFrame:
165     if (inst.Offset == 1)
166       b2 |= 0x10;
167     EmitAbsDifference(streamer, inst.Label, begin);
168     streamer.emitInt8(b2);
169     break;
170   }
171 }
172 
EmitSymbolRefWithOfs(MCStreamer & streamer,const MCSymbol * Base,int64_t Offset)173 static void EmitSymbolRefWithOfs(MCStreamer &streamer,
174                                  const MCSymbol *Base,
175                                  int64_t Offset) {
176   MCContext &Context = streamer.getContext();
177   const MCConstantExpr *OffExpr = MCConstantExpr::create(Offset, Context);
178   const MCSymbolRefExpr *BaseRefRel = MCSymbolRefExpr::create(Base,
179                                               MCSymbolRefExpr::VK_COFF_IMGREL32,
180                                               Context);
181   streamer.emitValue(MCBinaryExpr::createAdd(BaseRefRel, OffExpr, Context), 4);
182 }
183 
EmitSymbolRefWithOfs(MCStreamer & streamer,const MCSymbol * Base,const MCSymbol * Other)184 static void EmitSymbolRefWithOfs(MCStreamer &streamer,
185                                  const MCSymbol *Base,
186                                  const MCSymbol *Other) {
187   MCContext &Context = streamer.getContext();
188   const MCSymbolRefExpr *BaseRef = MCSymbolRefExpr::create(Base, Context);
189   const MCSymbolRefExpr *OtherRef = MCSymbolRefExpr::create(Other, Context);
190   const MCExpr *Ofs = MCBinaryExpr::createSub(OtherRef, BaseRef, Context);
191   const MCSymbolRefExpr *BaseRefRel = MCSymbolRefExpr::create(Base,
192                                               MCSymbolRefExpr::VK_COFF_IMGREL32,
193                                               Context);
194   streamer.emitValue(MCBinaryExpr::createAdd(BaseRefRel, Ofs, Context), 4);
195 }
196 
EmitRuntimeFunction(MCStreamer & streamer,const WinEH::FrameInfo * info)197 static void EmitRuntimeFunction(MCStreamer &streamer,
198                                 const WinEH::FrameInfo *info) {
199   MCContext &context = streamer.getContext();
200 
201   streamer.emitValueToAlignment(Align(4));
202   EmitSymbolRefWithOfs(streamer, info->Begin, info->Begin);
203   EmitSymbolRefWithOfs(streamer, info->Begin, info->End);
204   streamer.emitValue(MCSymbolRefExpr::create(info->Symbol,
205                                              MCSymbolRefExpr::VK_COFF_IMGREL32,
206                                              context), 4);
207 }
208 
209 static std::optional<int64_t>
GetOptionalAbsDifference(const MCAssembler & Assembler,const MCSymbol * LHS,const MCSymbol * RHS)210 GetOptionalAbsDifference(const MCAssembler &Assembler, const MCSymbol *LHS,
211                          const MCSymbol *RHS) {
212   MCContext &Context = Assembler.getContext();
213   const MCExpr *Diff =
214       MCBinaryExpr::createSub(MCSymbolRefExpr::create(LHS, Context),
215                               MCSymbolRefExpr::create(RHS, Context), Context);
216   // It should normally be possible to calculate the length of a function
217   // at this point, but it might not be possible in the presence of certain
218   // unusual constructs, like an inline asm with an alignment directive.
219   int64_t value;
220   if (!Diff->evaluateAsAbsolute(value, Assembler))
221     return std::nullopt;
222   return value;
223 }
224 
EmitUnwindInfo(MCStreamer & streamer,WinEH::FrameInfo * info)225 static void EmitUnwindInfo(MCStreamer &streamer, WinEH::FrameInfo *info) {
226   // If this UNWIND_INFO already has a symbol, it's already been emitted.
227   if (info->Symbol)
228     return;
229 
230   MCContext &context = streamer.getContext();
231   MCObjectStreamer *OS = (MCObjectStreamer *)(&streamer);
232   MCSymbol *Label = context.createTempSymbol();
233 
234   streamer.emitValueToAlignment(Align(4));
235   streamer.emitLabel(Label);
236   info->Symbol = Label;
237 
238   uint8_t numCodes = CountOfUnwindCodes(info->Instructions);
239   bool LastEpilogIsAtEnd = false;
240   bool AddPaddingEpilogCode = false;
241   uint8_t EpilogSize = 0;
242   bool EnableUnwindV2 = (info->Version >= 2) && !info->EpilogMap.empty();
243   if (EnableUnwindV2) {
244     auto &LastEpilog = info->EpilogMap.back().second;
245 
246     // Calculate the size of the epilogs. Note that we +1 to the size so that
247     // the terminator instruction is also included in the epilog (the Windows
248     // unwinder does a simple range check versus the current instruction pointer
249     // so, although there are terminators that are large than 1 byte, the
250     // starting address of the terminator instruction will always be considered
251     // inside the epilog).
252     auto MaybeSize = GetOptionalAbsDifference(
253         OS->getAssembler(), LastEpilog.End, LastEpilog.UnwindV2Start);
254     if (!MaybeSize) {
255       context.reportError(LastEpilog.Loc,
256                           "Failed to evaluate epilog size for Unwind v2");
257       return;
258     }
259     assert(*MaybeSize >= 0);
260     if (*MaybeSize >= (int64_t)UINT8_MAX) {
261       context.reportError(LastEpilog.Loc,
262                           "Epilog size is too large for Unwind v2");
263       return;
264     }
265     EpilogSize = *MaybeSize + 1;
266 
267     // If the last epilog is at the end of the function, we can use a special
268     // encoding for it. Because of our +1 trick for the size, this will only
269     // work where that final terminator instruction is 1 byte long.
270     auto LastEpilogToFuncEnd = GetOptionalAbsDifference(
271         OS->getAssembler(), info->FuncletOrFuncEnd, LastEpilog.UnwindV2Start);
272     LastEpilogIsAtEnd = (LastEpilogToFuncEnd == EpilogSize);
273 
274     // If we have an odd number of epilog codes, we need to add a padding code.
275     size_t numEpilogCodes =
276         info->EpilogMap.size() + (LastEpilogIsAtEnd ? 0 : 1);
277     if ((numEpilogCodes % 2) != 0) {
278       AddPaddingEpilogCode = true;
279       numEpilogCodes++;
280     }
281 
282     // Too many epilogs to handle.
283     if ((size_t)numCodes + numEpilogCodes > UINT8_MAX) {
284       context.reportError(info->FunctionLoc,
285                           "Too many unwind codes with Unwind v2 enabled");
286       return;
287     }
288 
289     numCodes += numEpilogCodes;
290   }
291 
292   // Upper 3 bits are the version number.
293   uint8_t flags = info->Version;
294   if (info->ChainedParent)
295     flags |= Win64EH::UNW_ChainInfo << 3;
296   else {
297     if (info->HandlesUnwind)
298       flags |= Win64EH::UNW_TerminateHandler << 3;
299     if (info->HandlesExceptions)
300       flags |= Win64EH::UNW_ExceptionHandler << 3;
301   }
302   streamer.emitInt8(flags);
303 
304   if (info->PrologEnd)
305     EmitAbsDifference(streamer, info->PrologEnd, info->Begin);
306   else
307     streamer.emitInt8(0);
308 
309   streamer.emitInt8(numCodes);
310 
311   uint8_t frame = 0;
312   if (info->LastFrameInst >= 0) {
313     WinEH::Instruction &frameInst = info->Instructions[info->LastFrameInst];
314     assert(frameInst.Operation == Win64EH::UOP_SetFPReg);
315     frame = (frameInst.Register & 0x0F) | (frameInst.Offset & 0xF0);
316   }
317   streamer.emitInt8(frame);
318 
319   // Emit the epilog instructions.
320   if (EnableUnwindV2) {
321     MCDataFragment *DF = OS->getOrCreateDataFragment();
322 
323     bool IsLast = true;
324     for (const auto &Epilog : llvm::reverse(info->EpilogMap)) {
325       if (IsLast) {
326         IsLast = false;
327         uint8_t Flags = LastEpilogIsAtEnd ? 0x01 : 0;
328         streamer.emitInt8(EpilogSize);
329         streamer.emitInt8((Flags << 4) | Win64EH::UOP_Epilog);
330 
331         if (LastEpilogIsAtEnd)
332           continue;
333       }
334 
335       // Each epilog is emitted as a fixup, since we can't measure the distance
336       // between the start of the epilog and the end of the function until
337       // layout has been completed.
338       auto *MCE = MCUnwindV2EpilogTargetExpr::create(*info, Epilog.second,
339                                                      EpilogSize, context);
340       MCFixup Fixup = MCFixup::create(DF->getContents().size(), MCE, FK_Data_2);
341       DF->addFixup(Fixup);
342       DF->appendContents(2, 0);
343     }
344   }
345   if (AddPaddingEpilogCode)
346     streamer.emitInt16(Win64EH::UOP_Epilog << 8);
347 
348   // Emit unwind instructions (in reverse order).
349   uint8_t numInst = info->Instructions.size();
350   for (uint8_t c = 0; c < numInst; ++c) {
351     WinEH::Instruction inst = info->Instructions.back();
352     info->Instructions.pop_back();
353     EmitUnwindCode(streamer, info->Begin, inst);
354   }
355 
356   // For alignment purposes, the instruction array will always have an even
357   // number of entries, with the final entry potentially unused (in which case
358   // the array will be one longer than indicated by the count of unwind codes
359   // field).
360   if (numCodes & 1) {
361     streamer.emitInt16(0);
362   }
363 
364   if (flags & (Win64EH::UNW_ChainInfo << 3))
365     EmitRuntimeFunction(streamer, info->ChainedParent);
366   else if (flags &
367            ((Win64EH::UNW_TerminateHandler|Win64EH::UNW_ExceptionHandler) << 3))
368     streamer.emitValue(MCSymbolRefExpr::create(info->ExceptionHandler,
369                                               MCSymbolRefExpr::VK_COFF_IMGREL32,
370                                               context), 4);
371   else if (numCodes == 0) {
372     // The minimum size of an UNWIND_INFO struct is 8 bytes. If we're not
373     // a chained unwind info, if there is no handler, and if there are fewer
374     // than 2 slots used in the unwind code array, we have to pad to 8 bytes.
375     streamer.emitInt32(0);
376   }
377 }
378 
evaluateAsRelocatableImpl(MCValue & Res,const MCAssembler * Asm) const379 bool MCUnwindV2EpilogTargetExpr::evaluateAsRelocatableImpl(
380     MCValue &Res, const MCAssembler *Asm) const {
381   // Calculate the offset to this epilog, and validate it's within the allowed
382   // range.
383   auto Offset = GetOptionalAbsDifference(*Asm, FunctionEnd, UnwindV2Start);
384   if (!Offset) {
385     Asm->getContext().reportError(
386         Loc, "Failed to evaluate epilog offset for Unwind v2");
387     return false;
388   }
389   assert(*Offset > 0);
390   constexpr uint16_t MaxEpilogOffset = 0x0fff;
391   if (*Offset > MaxEpilogOffset) {
392     Asm->getContext().reportError(Loc,
393                                   "Epilog offset is too large for Unwind v2");
394     return false;
395   }
396 
397   // Sanity check that all epilogs are the same size.
398   auto Size = GetOptionalAbsDifference(*Asm, EpilogEnd, UnwindV2Start);
399   if (Size != (EpilogSize - 1)) {
400     Asm->getContext().reportError(
401         Loc,
402         "Size of this epilog does not match size of last epilog in function");
403     return false;
404   }
405 
406   auto HighBits = *Offset >> 8;
407   Res = MCValue::get((HighBits << 12) | (Win64EH::UOP_Epilog << 8) |
408                      (*Offset & 0xFF));
409   return true;
410 }
411 
Emit(MCStreamer & Streamer) const412 void llvm::Win64EH::UnwindEmitter::Emit(MCStreamer &Streamer) const {
413   // Emit the unwind info structs first.
414   for (const auto &CFI : Streamer.getWinFrameInfos()) {
415     MCSection *XData = Streamer.getAssociatedXDataSection(CFI->TextSection);
416     Streamer.switchSection(XData);
417     ::EmitUnwindInfo(Streamer, CFI.get());
418   }
419 
420   // Now emit RUNTIME_FUNCTION entries.
421   for (const auto &CFI : Streamer.getWinFrameInfos()) {
422     MCSection *PData = Streamer.getAssociatedPDataSection(CFI->TextSection);
423     Streamer.switchSection(PData);
424     EmitRuntimeFunction(Streamer, CFI.get());
425   }
426 }
427 
EmitUnwindInfo(MCStreamer & Streamer,WinEH::FrameInfo * info,bool HandlerData) const428 void llvm::Win64EH::UnwindEmitter::EmitUnwindInfo(MCStreamer &Streamer,
429                                                   WinEH::FrameInfo *info,
430                                                   bool HandlerData) const {
431   // Switch sections (the static function above is meant to be called from
432   // here and from Emit().
433   MCSection *XData = Streamer.getAssociatedXDataSection(info->TextSection);
434   Streamer.switchSection(XData);
435 
436   ::EmitUnwindInfo(Streamer, info);
437 }
438 
GetSubDivExpr(MCStreamer & Streamer,const MCSymbol * LHS,const MCSymbol * RHS,int Div)439 static const MCExpr *GetSubDivExpr(MCStreamer &Streamer, const MCSymbol *LHS,
440                                    const MCSymbol *RHS, int Div) {
441   MCContext &Context = Streamer.getContext();
442   const MCExpr *Expr =
443       MCBinaryExpr::createSub(MCSymbolRefExpr::create(LHS, Context),
444                               MCSymbolRefExpr::create(RHS, Context), Context);
445   if (Div != 1)
446     Expr = MCBinaryExpr::createDiv(Expr, MCConstantExpr::create(Div, Context),
447                                    Context);
448   return Expr;
449 }
450 
GetOptionalAbsDifference(MCStreamer & Streamer,const MCSymbol * LHS,const MCSymbol * RHS)451 static std::optional<int64_t> GetOptionalAbsDifference(MCStreamer &Streamer,
452                                                        const MCSymbol *LHS,
453                                                        const MCSymbol *RHS) {
454   MCObjectStreamer *OS = (MCObjectStreamer *)(&Streamer);
455   return GetOptionalAbsDifference(OS->getAssembler(), LHS, RHS);
456 }
457 
GetAbsDifference(MCStreamer & Streamer,const MCSymbol * LHS,const MCSymbol * RHS)458 static int64_t GetAbsDifference(MCStreamer &Streamer, const MCSymbol *LHS,
459                                 const MCSymbol *RHS) {
460   std::optional<int64_t> MaybeDiff =
461       GetOptionalAbsDifference(Streamer, LHS, RHS);
462   if (!MaybeDiff)
463     report_fatal_error("Failed to evaluate function length in SEH unwind info");
464   return *MaybeDiff;
465 }
466 
checkARM64Instructions(MCStreamer & Streamer,ArrayRef<WinEH::Instruction> Insns,const MCSymbol * Begin,const MCSymbol * End,StringRef Name,StringRef Type)467 static void checkARM64Instructions(MCStreamer &Streamer,
468                                    ArrayRef<WinEH::Instruction> Insns,
469                                    const MCSymbol *Begin, const MCSymbol *End,
470                                    StringRef Name, StringRef Type) {
471   if (!End)
472     return;
473   std::optional<int64_t> MaybeDistance =
474       GetOptionalAbsDifference(Streamer, End, Begin);
475   if (!MaybeDistance)
476     return;
477   uint32_t Distance = (uint32_t)*MaybeDistance;
478 
479   for (const auto &I : Insns) {
480     switch (static_cast<Win64EH::UnwindOpcodes>(I.Operation)) {
481     default:
482       break;
483     case Win64EH::UOP_TrapFrame:
484     case Win64EH::UOP_PushMachFrame:
485     case Win64EH::UOP_Context:
486     case Win64EH::UOP_ECContext:
487     case Win64EH::UOP_ClearUnwoundToCall:
488       // Can't reason about these opcodes and how they map to actual
489       // instructions.
490       return;
491     }
492   }
493   // Exclude the end opcode which doesn't map to an instruction.
494   uint32_t InstructionBytes = 4 * (Insns.size() - 1);
495   if (Distance != InstructionBytes) {
496     Streamer.getContext().reportError(
497         SMLoc(), "Incorrect size for " + Name + " " + Type + ": " +
498                      Twine(Distance) +
499                      " bytes of instructions in range, but .seh directives "
500                      "corresponding to " +
501                      Twine(InstructionBytes) + " bytes\n");
502   }
503 }
504 
ARM64CountOfUnwindCodes(ArrayRef<WinEH::Instruction> Insns)505 static uint32_t ARM64CountOfUnwindCodes(ArrayRef<WinEH::Instruction> Insns) {
506   uint32_t Count = 0;
507   for (const auto &I : Insns) {
508     switch (static_cast<Win64EH::UnwindOpcodes>(I.Operation)) {
509     default:
510       llvm_unreachable("Unsupported ARM64 unwind code");
511     case Win64EH::UOP_AllocSmall:
512       Count += 1;
513       break;
514     case Win64EH::UOP_AllocMedium:
515       Count += 2;
516       break;
517     case Win64EH::UOP_AllocLarge:
518       Count += 4;
519       break;
520     case Win64EH::UOP_SaveR19R20X:
521       Count += 1;
522       break;
523     case Win64EH::UOP_SaveFPLRX:
524       Count += 1;
525       break;
526     case Win64EH::UOP_SaveFPLR:
527       Count += 1;
528       break;
529     case Win64EH::UOP_SaveReg:
530       Count += 2;
531       break;
532     case Win64EH::UOP_SaveRegP:
533       Count += 2;
534       break;
535     case Win64EH::UOP_SaveRegPX:
536       Count += 2;
537       break;
538     case Win64EH::UOP_SaveRegX:
539       Count += 2;
540       break;
541     case Win64EH::UOP_SaveLRPair:
542       Count += 2;
543       break;
544     case Win64EH::UOP_SaveFReg:
545       Count += 2;
546       break;
547     case Win64EH::UOP_SaveFRegP:
548       Count += 2;
549       break;
550     case Win64EH::UOP_SaveFRegX:
551       Count += 2;
552       break;
553     case Win64EH::UOP_SaveFRegPX:
554       Count += 2;
555       break;
556     case Win64EH::UOP_SetFP:
557       Count += 1;
558       break;
559     case Win64EH::UOP_AddFP:
560       Count += 2;
561       break;
562     case Win64EH::UOP_Nop:
563       Count += 1;
564       break;
565     case Win64EH::UOP_End:
566       Count += 1;
567       break;
568     case Win64EH::UOP_SaveNext:
569       Count += 1;
570       break;
571     case Win64EH::UOP_TrapFrame:
572       Count += 1;
573       break;
574     case Win64EH::UOP_PushMachFrame:
575       Count += 1;
576       break;
577     case Win64EH::UOP_Context:
578       Count += 1;
579       break;
580     case Win64EH::UOP_ECContext:
581       Count += 1;
582       break;
583     case Win64EH::UOP_ClearUnwoundToCall:
584       Count += 1;
585       break;
586     case Win64EH::UOP_PACSignLR:
587       Count += 1;
588       break;
589     case Win64EH::UOP_AllocZ:
590       Count += 2;
591       break;
592     case Win64EH::UOP_SaveAnyRegI:
593     case Win64EH::UOP_SaveAnyRegIP:
594     case Win64EH::UOP_SaveAnyRegD:
595     case Win64EH::UOP_SaveAnyRegDP:
596     case Win64EH::UOP_SaveAnyRegQ:
597     case Win64EH::UOP_SaveAnyRegQP:
598     case Win64EH::UOP_SaveAnyRegIX:
599     case Win64EH::UOP_SaveAnyRegIPX:
600     case Win64EH::UOP_SaveAnyRegDX:
601     case Win64EH::UOP_SaveAnyRegDPX:
602     case Win64EH::UOP_SaveAnyRegQX:
603     case Win64EH::UOP_SaveAnyRegQPX:
604     case Win64EH::UOP_SaveZReg:
605     case Win64EH::UOP_SavePReg:
606       Count += 3;
607       break;
608     }
609   }
610   return Count;
611 }
612 
613 // Unwind opcode encodings and restrictions are documented at
614 // https://docs.microsoft.com/en-us/cpp/build/arm64-exception-handling
ARM64EmitUnwindCode(MCStreamer & streamer,const WinEH::Instruction & inst)615 static void ARM64EmitUnwindCode(MCStreamer &streamer,
616                                 const WinEH::Instruction &inst) {
617   uint8_t b, reg;
618   switch (static_cast<Win64EH::UnwindOpcodes>(inst.Operation)) {
619   default:
620     llvm_unreachable("Unsupported ARM64 unwind code");
621   case Win64EH::UOP_AllocSmall:
622     b = (inst.Offset >> 4) & 0x1F;
623     streamer.emitInt8(b);
624     break;
625   case Win64EH::UOP_AllocMedium: {
626     uint16_t hw = (inst.Offset >> 4) & 0x7FF;
627     b = 0xC0;
628     b |= (hw >> 8);
629     streamer.emitInt8(b);
630     b = hw & 0xFF;
631     streamer.emitInt8(b);
632     break;
633   }
634   case Win64EH::UOP_AllocLarge: {
635     uint32_t w;
636     b = 0xE0;
637     streamer.emitInt8(b);
638     w = inst.Offset >> 4;
639     b = (w & 0x00FF0000) >> 16;
640     streamer.emitInt8(b);
641     b = (w & 0x0000FF00) >> 8;
642     streamer.emitInt8(b);
643     b = w & 0x000000FF;
644     streamer.emitInt8(b);
645     break;
646   }
647   case Win64EH::UOP_SetFP:
648     b = 0xE1;
649     streamer.emitInt8(b);
650     break;
651   case Win64EH::UOP_AddFP:
652     b = 0xE2;
653     streamer.emitInt8(b);
654     b = (inst.Offset >> 3);
655     streamer.emitInt8(b);
656     break;
657   case Win64EH::UOP_Nop:
658     b = 0xE3;
659     streamer.emitInt8(b);
660     break;
661   case Win64EH::UOP_SaveR19R20X:
662     b = 0x20;
663     b |= (inst.Offset >> 3) & 0x1F;
664     streamer.emitInt8(b);
665     break;
666   case Win64EH::UOP_SaveFPLRX:
667     b = 0x80;
668     b |= ((inst.Offset - 1) >> 3) & 0x3F;
669     streamer.emitInt8(b);
670     break;
671   case Win64EH::UOP_SaveFPLR:
672     b = 0x40;
673     b |= (inst.Offset >> 3) & 0x3F;
674     streamer.emitInt8(b);
675     break;
676   case Win64EH::UOP_SaveReg:
677     assert(inst.Register >= 19 && "Saved reg must be >= 19");
678     reg = inst.Register - 19;
679     b = 0xD0 | ((reg & 0xC) >> 2);
680     streamer.emitInt8(b);
681     b = ((reg & 0x3) << 6) | (inst.Offset >> 3);
682     streamer.emitInt8(b);
683     break;
684   case Win64EH::UOP_SaveRegX:
685     assert(inst.Register >= 19 && "Saved reg must be >= 19");
686     reg = inst.Register - 19;
687     b = 0xD4 | ((reg & 0x8) >> 3);
688     streamer.emitInt8(b);
689     b = ((reg & 0x7) << 5) | ((inst.Offset >> 3) - 1);
690     streamer.emitInt8(b);
691     break;
692   case Win64EH::UOP_SaveRegP:
693     assert(inst.Register >= 19 && "Saved registers must be >= 19");
694     reg = inst.Register - 19;
695     b = 0xC8 | ((reg & 0xC) >> 2);
696     streamer.emitInt8(b);
697     b = ((reg & 0x3) << 6) | (inst.Offset >> 3);
698     streamer.emitInt8(b);
699     break;
700   case Win64EH::UOP_SaveRegPX:
701     assert(inst.Register >= 19 && "Saved registers must be >= 19");
702     reg = inst.Register - 19;
703     b = 0xCC | ((reg & 0xC) >> 2);
704     streamer.emitInt8(b);
705     b = ((reg & 0x3) << 6) | ((inst.Offset >> 3) - 1);
706     streamer.emitInt8(b);
707     break;
708   case Win64EH::UOP_SaveLRPair:
709     assert(inst.Register >= 19 && "Saved reg must be >= 19");
710     reg = inst.Register - 19;
711     assert((reg % 2) == 0 && "Saved reg must be 19+2*X");
712     reg /= 2;
713     b = 0xD6 | ((reg & 0x7) >> 2);
714     streamer.emitInt8(b);
715     b = ((reg & 0x3) << 6) | (inst.Offset >> 3);
716     streamer.emitInt8(b);
717     break;
718   case Win64EH::UOP_SaveFReg:
719     assert(inst.Register >= 8 && "Saved dreg must be >= 8");
720     reg = inst.Register - 8;
721     b = 0xDC | ((reg & 0x4) >> 2);
722     streamer.emitInt8(b);
723     b = ((reg & 0x3) << 6) | (inst.Offset >> 3);
724     streamer.emitInt8(b);
725     break;
726   case Win64EH::UOP_SaveFRegX:
727     assert(inst.Register >= 8 && "Saved dreg must be >= 8");
728     reg = inst.Register - 8;
729     b = 0xDE;
730     streamer.emitInt8(b);
731     b = ((reg & 0x7) << 5) | ((inst.Offset >> 3) - 1);
732     streamer.emitInt8(b);
733     break;
734   case Win64EH::UOP_SaveFRegP:
735     assert(inst.Register >= 8 && "Saved dregs must be >= 8");
736     reg = inst.Register - 8;
737     b = 0xD8 | ((reg & 0x4) >> 2);
738     streamer.emitInt8(b);
739     b = ((reg & 0x3) << 6) | (inst.Offset >> 3);
740     streamer.emitInt8(b);
741     break;
742   case Win64EH::UOP_SaveFRegPX:
743     assert(inst.Register >= 8 && "Saved dregs must be >= 8");
744     reg = inst.Register - 8;
745     b = 0xDA | ((reg & 0x4) >> 2);
746     streamer.emitInt8(b);
747     b = ((reg & 0x3) << 6) | ((inst.Offset >> 3) - 1);
748     streamer.emitInt8(b);
749     break;
750   case Win64EH::UOP_End:
751     b = 0xE4;
752     streamer.emitInt8(b);
753     break;
754   case Win64EH::UOP_SaveNext:
755     b = 0xE6;
756     streamer.emitInt8(b);
757     break;
758   case Win64EH::UOP_TrapFrame:
759     b = 0xE8;
760     streamer.emitInt8(b);
761     break;
762   case Win64EH::UOP_PushMachFrame:
763     b = 0xE9;
764     streamer.emitInt8(b);
765     break;
766   case Win64EH::UOP_Context:
767     b = 0xEA;
768     streamer.emitInt8(b);
769     break;
770   case Win64EH::UOP_ECContext:
771     b = 0xEB;
772     streamer.emitInt8(b);
773     break;
774   case Win64EH::UOP_ClearUnwoundToCall:
775     b = 0xEC;
776     streamer.emitInt8(b);
777     break;
778   case Win64EH::UOP_PACSignLR:
779     b = 0xFC;
780     streamer.emitInt8(b);
781     break;
782   case Win64EH::UOP_SaveAnyRegI:
783   case Win64EH::UOP_SaveAnyRegIP:
784   case Win64EH::UOP_SaveAnyRegD:
785   case Win64EH::UOP_SaveAnyRegDP:
786   case Win64EH::UOP_SaveAnyRegQ:
787   case Win64EH::UOP_SaveAnyRegQP:
788   case Win64EH::UOP_SaveAnyRegIX:
789   case Win64EH::UOP_SaveAnyRegIPX:
790   case Win64EH::UOP_SaveAnyRegDX:
791   case Win64EH::UOP_SaveAnyRegDPX:
792   case Win64EH::UOP_SaveAnyRegQX:
793   case Win64EH::UOP_SaveAnyRegQPX: {
794     // This assumes the opcodes are listed in the enum in a particular order.
795     int Op = inst.Operation - Win64EH::UOP_SaveAnyRegI;
796     int Writeback = Op / 6;
797     int Paired = Op % 2;
798     int Mode = (Op / 2) % 3;
799     int Offset = inst.Offset >> 3;
800     if (Writeback || Paired || Mode == 2)
801       Offset >>= 1;
802     if (Writeback)
803       --Offset;
804     b = 0xE7;
805     streamer.emitInt8(b);
806     assert(inst.Register < 32);
807     b = inst.Register | (Writeback << 5) | (Paired << 6);
808     streamer.emitInt8(b);
809     b = Offset | (Mode << 6);
810     streamer.emitInt8(b);
811     break;
812   }
813   case Win64EH::UOP_AllocZ: {
814     b = 0xDF;
815     streamer.emitInt8(b);
816     b = inst.Offset;
817     streamer.emitInt8(b);
818     break;
819   }
820   case Win64EH::UOP_SaveZReg: {
821     assert(inst.Register >= 8 && inst.Register <= 23);
822     assert(inst.Offset < 256);
823     b = 0xE7;
824     streamer.emitInt8(b);
825     reg = inst.Register - 8;
826     b = ((inst.Offset & 0xC0) >> 1) | reg;
827     streamer.emitInt8(b);
828     b = 0xC0 | (inst.Offset & 0x3F);
829     streamer.emitInt8(b);
830     break;
831   }
832   case Win64EH::UOP_SavePReg: {
833     assert(inst.Register >= 4 && inst.Register <= 15);
834     assert(inst.Offset < 256);
835     b = 0xE7;
836     streamer.emitInt8(b);
837     reg = inst.Register;
838     b = ((inst.Offset & 0xC0) >> 1) | 0x10 | reg;
839     streamer.emitInt8(b);
840     b = 0xC0 | (inst.Offset & 0x3F);
841     streamer.emitInt8(b);
842     break;
843   }
844   }
845 }
846 
847 // Returns the epilog symbol of an epilog with the exact same unwind code
848 // sequence, if it exists.  Otherwise, returns nullptr.
849 // EpilogInstrs - Unwind codes for the current epilog.
850 // Epilogs - Epilogs that potentialy match the current epilog.
851 static MCSymbol*
FindMatchingEpilog(const std::vector<WinEH::Instruction> & EpilogInstrs,const std::vector<MCSymbol * > & Epilogs,const WinEH::FrameInfo * info)852 FindMatchingEpilog(const std::vector<WinEH::Instruction>& EpilogInstrs,
853                    const std::vector<MCSymbol *>& Epilogs,
854                    const WinEH::FrameInfo *info) {
855   for (auto *EpilogStart : Epilogs) {
856     auto InstrsIter = info->EpilogMap.find(EpilogStart);
857     assert(InstrsIter != info->EpilogMap.end() &&
858            "Epilog not found in EpilogMap");
859     const auto &Instrs = InstrsIter->second.Instructions;
860 
861     if (Instrs.size() != EpilogInstrs.size())
862       continue;
863 
864     bool Match = true;
865     for (unsigned i = 0; i < Instrs.size(); ++i)
866       if (Instrs[i] != EpilogInstrs[i]) {
867         Match = false;
868         break;
869       }
870 
871     if (Match)
872       return EpilogStart;
873   }
874   return nullptr;
875 }
876 
simplifyARM64Opcodes(std::vector<WinEH::Instruction> & Instructions,bool Reverse)877 static void simplifyARM64Opcodes(std::vector<WinEH::Instruction> &Instructions,
878                                  bool Reverse) {
879   unsigned PrevOffset = -1;
880   unsigned PrevRegister = -1;
881 
882   auto VisitInstruction = [&](WinEH::Instruction &Inst) {
883     // Convert 2-byte opcodes into equivalent 1-byte ones.
884     if (Inst.Operation == Win64EH::UOP_SaveRegP && Inst.Register == 29) {
885       Inst.Operation = Win64EH::UOP_SaveFPLR;
886       Inst.Register = -1;
887     } else if (Inst.Operation == Win64EH::UOP_SaveRegPX &&
888                Inst.Register == 29) {
889       Inst.Operation = Win64EH::UOP_SaveFPLRX;
890       Inst.Register = -1;
891     } else if (Inst.Operation == Win64EH::UOP_SaveRegPX &&
892                Inst.Register == 19 && Inst.Offset <= 248) {
893       Inst.Operation = Win64EH::UOP_SaveR19R20X;
894       Inst.Register = -1;
895     } else if (Inst.Operation == Win64EH::UOP_AddFP && Inst.Offset == 0) {
896       Inst.Operation = Win64EH::UOP_SetFP;
897     } else if (Inst.Operation == Win64EH::UOP_SaveRegP &&
898                Inst.Register == PrevRegister + 2 &&
899                Inst.Offset == PrevOffset + 16) {
900       Inst.Operation = Win64EH::UOP_SaveNext;
901       Inst.Register = -1;
902       Inst.Offset = 0;
903       // Intentionally not creating UOP_SaveNext for float register pairs,
904       // as current versions of Windows (up to at least 20.04) is buggy
905       // regarding SaveNext for float pairs.
906     }
907     // Update info about the previous instruction, for detecting if
908     // the next one can be made a UOP_SaveNext
909     if (Inst.Operation == Win64EH::UOP_SaveR19R20X) {
910       PrevOffset = 0;
911       PrevRegister = 19;
912     } else if (Inst.Operation == Win64EH::UOP_SaveRegPX) {
913       PrevOffset = 0;
914       PrevRegister = Inst.Register;
915     } else if (Inst.Operation == Win64EH::UOP_SaveRegP) {
916       PrevOffset = Inst.Offset;
917       PrevRegister = Inst.Register;
918     } else if (Inst.Operation == Win64EH::UOP_SaveNext) {
919       PrevRegister += 2;
920       PrevOffset += 16;
921     } else {
922       PrevRegister = -1;
923       PrevOffset = -1;
924     }
925   };
926 
927   // Iterate over instructions in a forward order (for prologues),
928   // backwards for epilogues (i.e. always reverse compared to how the
929   // opcodes are stored).
930   if (Reverse) {
931     for (auto It = Instructions.rbegin(); It != Instructions.rend(); It++)
932       VisitInstruction(*It);
933   } else {
934     for (WinEH::Instruction &Inst : Instructions)
935       VisitInstruction(Inst);
936   }
937 }
938 
939 // Check if an epilog exists as a subset of the end of a prolog (backwards).
940 static int
getARM64OffsetInProlog(const std::vector<WinEH::Instruction> & Prolog,const std::vector<WinEH::Instruction> & Epilog)941 getARM64OffsetInProlog(const std::vector<WinEH::Instruction> &Prolog,
942                        const std::vector<WinEH::Instruction> &Epilog) {
943   // Can't find an epilog as a subset if it is longer than the prolog.
944   if (Epilog.size() > Prolog.size())
945     return -1;
946 
947   // Check that the epilog actually is a perfect match for the end (backwrds)
948   // of the prolog.
949   for (int I = Epilog.size() - 1; I >= 0; I--) {
950     if (Prolog[I] != Epilog[Epilog.size() - 1 - I])
951       return -1;
952   }
953 
954   if (Epilog.size() == Prolog.size())
955     return 0;
956 
957   // If the epilog was a subset of the prolog, find its offset.
958   return ARM64CountOfUnwindCodes(ArrayRef<WinEH::Instruction>(
959       &Prolog[Epilog.size()], Prolog.size() - Epilog.size()));
960 }
961 
checkARM64PackedEpilog(MCStreamer & streamer,WinEH::FrameInfo * info,WinEH::FrameInfo::Segment * Seg,int PrologCodeBytes)962 static int checkARM64PackedEpilog(MCStreamer &streamer, WinEH::FrameInfo *info,
963                                   WinEH::FrameInfo::Segment *Seg,
964                                   int PrologCodeBytes) {
965   // Can only pack if there's one single epilog
966   if (Seg->Epilogs.size() != 1)
967     return -1;
968 
969   MCSymbol *Sym = Seg->Epilogs.begin()->first;
970   const std::vector<WinEH::Instruction> &Epilog =
971       info->EpilogMap[Sym].Instructions;
972 
973   // Check that the epilog actually is at the very end of the function,
974   // otherwise it can't be packed.
975   uint32_t DistanceFromEnd =
976       (uint32_t)(Seg->Offset + Seg->Length - Seg->Epilogs.begin()->second);
977   if (DistanceFromEnd / 4 != Epilog.size())
978     return -1;
979 
980   int RetVal = -1;
981   // Even if we don't end up sharing opcodes with the prolog, we can still
982   // write the offset as a packed offset, if the single epilog is located at
983   // the end of the function and the offset (pointing after the prolog) fits
984   // as a packed offset.
985   if (PrologCodeBytes <= 31 &&
986       PrologCodeBytes + ARM64CountOfUnwindCodes(Epilog) <= 124)
987     RetVal = PrologCodeBytes;
988 
989   int Offset = getARM64OffsetInProlog(info->Instructions, Epilog);
990   if (Offset < 0)
991     return RetVal;
992 
993   // Check that the offset and prolog size fits in the first word; it's
994   // unclear whether the epilog count in the extension word can be taken
995   // as packed epilog offset.
996   if (Offset > 31 || PrologCodeBytes > 124)
997     return RetVal;
998 
999   // As we choose to express the epilog as part of the prolog, remove the
1000   // epilog from the map, so we don't try to emit its opcodes.
1001   info->EpilogMap.erase(Sym);
1002   return Offset;
1003 }
1004 
tryARM64PackedUnwind(WinEH::FrameInfo * info,uint32_t FuncLength,int PackedEpilogOffset)1005 static bool tryARM64PackedUnwind(WinEH::FrameInfo *info, uint32_t FuncLength,
1006                                  int PackedEpilogOffset) {
1007   if (PackedEpilogOffset == 0) {
1008     // Fully symmetric prolog and epilog, should be ok for packed format.
1009     // For CR=3, the corresponding synthesized epilog actually lacks the
1010     // SetFP opcode, but unwinding should work just fine despite that
1011     // (if at the SetFP opcode, the unwinder considers it as part of the
1012     // function body and just unwinds the full prolog instead).
1013   } else if (PackedEpilogOffset == 1) {
1014     // One single case of differences between prolog and epilog is allowed:
1015     // The epilog can lack a single SetFP that is the last opcode in the
1016     // prolog, for the CR=3 case.
1017     if (info->Instructions.back().Operation != Win64EH::UOP_SetFP)
1018       return false;
1019   } else {
1020     // Too much difference between prolog and epilog.
1021     return false;
1022   }
1023   unsigned RegI = 0, RegF = 0;
1024   int Predecrement = 0;
1025   enum {
1026     Start,
1027     Start2,
1028     Start3,
1029     IntRegs,
1030     FloatRegs,
1031     InputArgs,
1032     StackAdjust,
1033     FrameRecord,
1034     End
1035   } Location = Start;
1036   bool StandaloneLR = false, FPLRPair = false;
1037   bool PAC = false;
1038   int StackOffset = 0;
1039   int Nops = 0;
1040   // Iterate over the prolog and check that all opcodes exactly match
1041   // the canonical order and form. A more lax check could verify that
1042   // all saved registers are in the expected locations, but not enforce
1043   // the order - that would work fine when unwinding from within
1044   // functions, but not be exactly right if unwinding happens within
1045   // prologs/epilogs.
1046   for (const WinEH::Instruction &Inst : info->Instructions) {
1047     switch (Inst.Operation) {
1048     case Win64EH::UOP_End:
1049       if (Location != Start)
1050         return false;
1051       Location = Start2;
1052       break;
1053     case Win64EH::UOP_PACSignLR:
1054       if (Location != Start2)
1055         return false;
1056       PAC = true;
1057       Location = Start3;
1058       break;
1059     case Win64EH::UOP_SaveR19R20X:
1060       if (Location != Start2 && Location != Start3)
1061         return false;
1062       Predecrement = Inst.Offset;
1063       RegI = 2;
1064       Location = IntRegs;
1065       break;
1066     case Win64EH::UOP_SaveRegX:
1067       if (Location != Start2 && Location != Start3)
1068         return false;
1069       Predecrement = Inst.Offset;
1070       if (Inst.Register == 19)
1071         RegI += 1;
1072       else if (Inst.Register == 30)
1073         StandaloneLR = true;
1074       else
1075         return false;
1076       // Odd register; can't be any further int registers.
1077       Location = FloatRegs;
1078       break;
1079     case Win64EH::UOP_SaveRegPX:
1080       // Can't have this in a canonical prologue. Either this has been
1081       // canonicalized into SaveR19R20X or SaveFPLRX, or it's an unsupported
1082       // register pair.
1083       // It can't be canonicalized into SaveR19R20X if the offset is
1084       // larger than 248 bytes, but even with the maximum case with
1085       // RegI=10/RegF=8/CR=1/H=1, we end up with SavSZ = 216, which should
1086       // fit into SaveR19R20X.
1087       // The unwinding opcodes can't describe the otherwise seemingly valid
1088       // case for RegI=1 CR=1, that would start with a
1089       // "stp x19, lr, [sp, #-...]!" as that fits neither SaveRegPX nor
1090       // SaveLRPair.
1091       return false;
1092     case Win64EH::UOP_SaveRegP:
1093       if (Location != IntRegs || Inst.Offset != 8 * RegI ||
1094           Inst.Register != 19 + RegI)
1095         return false;
1096       RegI += 2;
1097       break;
1098     case Win64EH::UOP_SaveReg:
1099       if (Location != IntRegs || Inst.Offset != 8 * RegI)
1100         return false;
1101       if (Inst.Register == 19 + RegI)
1102         RegI += 1;
1103       else if (Inst.Register == 30)
1104         StandaloneLR = true;
1105       else
1106         return false;
1107       // Odd register; can't be any further int registers.
1108       Location = FloatRegs;
1109       break;
1110     case Win64EH::UOP_SaveLRPair:
1111       if (Location != IntRegs || Inst.Offset != 8 * RegI ||
1112           Inst.Register != 19 + RegI)
1113         return false;
1114       RegI += 1;
1115       StandaloneLR = true;
1116       Location = FloatRegs;
1117       break;
1118     case Win64EH::UOP_SaveFRegX:
1119       // Packed unwind can't handle prologs that only save one single
1120       // float register.
1121       return false;
1122     case Win64EH::UOP_SaveFReg:
1123       if (Location != FloatRegs || RegF == 0 || Inst.Register != 8 + RegF ||
1124           Inst.Offset != 8 * (RegI + (StandaloneLR ? 1 : 0) + RegF))
1125         return false;
1126       RegF += 1;
1127       Location = InputArgs;
1128       break;
1129     case Win64EH::UOP_SaveFRegPX:
1130       if ((Location != Start2 && Location != Start3) || Inst.Register != 8)
1131         return false;
1132       Predecrement = Inst.Offset;
1133       RegF = 2;
1134       Location = FloatRegs;
1135       break;
1136     case Win64EH::UOP_SaveFRegP:
1137       if ((Location != IntRegs && Location != FloatRegs) ||
1138           Inst.Register != 8 + RegF ||
1139           Inst.Offset != 8 * (RegI + (StandaloneLR ? 1 : 0) + RegF))
1140         return false;
1141       RegF += 2;
1142       Location = FloatRegs;
1143       break;
1144     case Win64EH::UOP_SaveNext:
1145       if (Location == IntRegs)
1146         RegI += 2;
1147       else if (Location == FloatRegs)
1148         RegF += 2;
1149       else
1150         return false;
1151       break;
1152     case Win64EH::UOP_Nop:
1153       if (Location != IntRegs && Location != FloatRegs && Location != InputArgs)
1154         return false;
1155       Location = InputArgs;
1156       Nops++;
1157       break;
1158     case Win64EH::UOP_AllocSmall:
1159     case Win64EH::UOP_AllocMedium:
1160       if (Location != Start2 && Location != Start3 && Location != IntRegs &&
1161           Location != FloatRegs && Location != InputArgs &&
1162           Location != StackAdjust)
1163         return false;
1164       // Can have either a single decrement, or a pair of decrements with
1165       // 4080 and another decrement.
1166       if (StackOffset == 0)
1167         StackOffset = Inst.Offset;
1168       else if (StackOffset != 4080)
1169         return false;
1170       else
1171         StackOffset += Inst.Offset;
1172       Location = StackAdjust;
1173       break;
1174     case Win64EH::UOP_SaveFPLRX:
1175       // Not allowing FPLRX after StackAdjust; if a StackAdjust is used, it
1176       // should be followed by a FPLR instead.
1177       if (Location != Start2 && Location != Start3 && Location != IntRegs &&
1178           Location != FloatRegs && Location != InputArgs)
1179         return false;
1180       StackOffset = Inst.Offset;
1181       Location = FrameRecord;
1182       FPLRPair = true;
1183       break;
1184     case Win64EH::UOP_SaveFPLR:
1185       // This can only follow after a StackAdjust
1186       if (Location != StackAdjust || Inst.Offset != 0)
1187         return false;
1188       Location = FrameRecord;
1189       FPLRPair = true;
1190       break;
1191     case Win64EH::UOP_SetFP:
1192       if (Location != FrameRecord)
1193         return false;
1194       Location = End;
1195       break;
1196     case Win64EH::UOP_SaveAnyRegI:
1197     case Win64EH::UOP_SaveAnyRegIP:
1198     case Win64EH::UOP_SaveAnyRegD:
1199     case Win64EH::UOP_SaveAnyRegDP:
1200     case Win64EH::UOP_SaveAnyRegQ:
1201     case Win64EH::UOP_SaveAnyRegQP:
1202     case Win64EH::UOP_SaveAnyRegIX:
1203     case Win64EH::UOP_SaveAnyRegIPX:
1204     case Win64EH::UOP_SaveAnyRegDX:
1205     case Win64EH::UOP_SaveAnyRegDPX:
1206     case Win64EH::UOP_SaveAnyRegQX:
1207     case Win64EH::UOP_SaveAnyRegQPX:
1208       // These are never canonical; they don't show up with the usual Arm64
1209       // calling convention.
1210       return false;
1211     case Win64EH::UOP_AllocLarge:
1212       // Allocations this large can't be represented in packed unwind (and
1213       // usually don't fit the canonical form anyway because we need to use
1214       // __chkstk to allocate the stack space).
1215       return false;
1216     case Win64EH::UOP_AddFP:
1217       // "add x29, sp, #N" doesn't show up in the canonical pattern (except for
1218       // N=0, which is UOP_SetFP).
1219       return false;
1220     case Win64EH::UOP_AllocZ:
1221     case Win64EH::UOP_SaveZReg:
1222     case Win64EH::UOP_SavePReg:
1223       // Canonical prologues don't support spilling SVE registers.
1224       return false;
1225     case Win64EH::UOP_TrapFrame:
1226     case Win64EH::UOP_Context:
1227     case Win64EH::UOP_ECContext:
1228     case Win64EH::UOP_ClearUnwoundToCall:
1229     case Win64EH::UOP_PushMachFrame:
1230       // These are special opcodes that aren't normally generated.
1231       return false;
1232     default:
1233       report_fatal_error("Unknown Arm64 unwind opcode");
1234     }
1235   }
1236   if (RegI > 10 || RegF > 8)
1237     return false;
1238   if (StandaloneLR && FPLRPair)
1239     return false;
1240   if (FPLRPair && Location != End)
1241     return false;
1242   if (Nops != 0 && Nops != 4)
1243     return false;
1244   if (PAC && !FPLRPair)
1245     return false;
1246   int H = Nops == 4;
1247   // There's an inconsistency regarding packed unwind info with homed
1248   // parameters; according to the documentation, the epilog shouldn't have
1249   // the same corresponding nops (and thus, to set the H bit, we should
1250   // require an epilog which isn't exactly symmetrical - we shouldn't accept
1251   // an exact mirrored epilog for those cases), but in practice,
1252   // RtlVirtualUnwind behaves as if it does expect the epilogue to contain
1253   // the same nops. See https://github.com/llvm/llvm-project/issues/54879.
1254   // To play it safe, don't produce packed unwind info with homed parameters.
1255   if (H)
1256     return false;
1257   int IntSZ = 8 * RegI;
1258   if (StandaloneLR)
1259     IntSZ += 8;
1260   int FpSZ = 8 * RegF; // RegF not yet decremented
1261   int SavSZ = (IntSZ + FpSZ + 8 * 8 * H + 0xF) & ~0xF;
1262   if (Predecrement != SavSZ)
1263     return false;
1264   if (FPLRPair && StackOffset < 16)
1265     return false;
1266   if (StackOffset % 16)
1267     return false;
1268   uint32_t FrameSize = (StackOffset + SavSZ) / 16;
1269   if (FrameSize > 0x1FF)
1270     return false;
1271   assert(RegF != 1 && "One single float reg not allowed");
1272   if (RegF > 0)
1273     RegF--; // Convert from actual number of registers, to value stored
1274   assert(FuncLength <= 0x7FF && "FuncLength should have been checked earlier");
1275   int Flag = 0x01; // Function segments not supported yet
1276   int CR = PAC ? 2 : FPLRPair ? 3 : StandaloneLR ? 1 : 0;
1277   info->PackedInfo |= Flag << 0;
1278   info->PackedInfo |= (FuncLength & 0x7FF) << 2;
1279   info->PackedInfo |= (RegF & 0x7) << 13;
1280   info->PackedInfo |= (RegI & 0xF) << 16;
1281   info->PackedInfo |= (H & 0x1) << 20;
1282   info->PackedInfo |= (CR & 0x3) << 21;
1283   info->PackedInfo |= (FrameSize & 0x1FF) << 23;
1284   return true;
1285 }
1286 
ARM64ProcessEpilogs(WinEH::FrameInfo * info,WinEH::FrameInfo::Segment * Seg,uint32_t & TotalCodeBytes,MapVector<MCSymbol *,uint32_t> & EpilogInfo)1287 static void ARM64ProcessEpilogs(WinEH::FrameInfo *info,
1288                                 WinEH::FrameInfo::Segment *Seg,
1289                                 uint32_t &TotalCodeBytes,
1290                                 MapVector<MCSymbol *, uint32_t> &EpilogInfo) {
1291 
1292   std::vector<MCSymbol *> EpilogStarts;
1293   for (auto &I : Seg->Epilogs)
1294     EpilogStarts.push_back(I.first);
1295 
1296   // Epilogs processed so far.
1297   std::vector<MCSymbol *> AddedEpilogs;
1298   for (auto *S : EpilogStarts) {
1299     MCSymbol *EpilogStart = S;
1300     auto &EpilogInstrs = info->EpilogMap[S].Instructions;
1301     uint32_t CodeBytes = ARM64CountOfUnwindCodes(EpilogInstrs);
1302 
1303     MCSymbol* MatchingEpilog =
1304       FindMatchingEpilog(EpilogInstrs, AddedEpilogs, info);
1305     int PrologOffset;
1306     if (MatchingEpilog) {
1307       assert(EpilogInfo.contains(MatchingEpilog) &&
1308              "Duplicate epilog not found");
1309       EpilogInfo[EpilogStart] = EpilogInfo.lookup(MatchingEpilog);
1310       // Clear the unwind codes in the EpilogMap, so that they don't get output
1311       // in ARM64EmitUnwindInfoForSegment().
1312       EpilogInstrs.clear();
1313     } else if ((PrologOffset = getARM64OffsetInProlog(info->Instructions,
1314                                                       EpilogInstrs)) >= 0) {
1315       EpilogInfo[EpilogStart] = PrologOffset;
1316       // If the segment doesn't have a prolog, an end_c will be emitted before
1317       // prolog opcodes. So epilog start index in opcodes array is moved by 1.
1318       if (!Seg->HasProlog)
1319         EpilogInfo[EpilogStart] += 1;
1320       // Clear the unwind codes in the EpilogMap, so that they don't get output
1321       // in ARM64EmitUnwindInfoForSegment().
1322       EpilogInstrs.clear();
1323     } else {
1324       EpilogInfo[EpilogStart] = TotalCodeBytes;
1325       TotalCodeBytes += CodeBytes;
1326       AddedEpilogs.push_back(EpilogStart);
1327     }
1328   }
1329 }
1330 
ARM64FindSegmentsInFunction(MCStreamer & streamer,WinEH::FrameInfo * info,int64_t RawFuncLength)1331 static void ARM64FindSegmentsInFunction(MCStreamer &streamer,
1332                                         WinEH::FrameInfo *info,
1333                                         int64_t RawFuncLength) {
1334   if (info->PrologEnd)
1335     checkARM64Instructions(streamer, info->Instructions, info->Begin,
1336                            info->PrologEnd, info->Function->getName(),
1337                            "prologue");
1338   struct EpilogStartEnd {
1339     MCSymbol *Start;
1340     int64_t Offset;
1341     int64_t End;
1342   };
1343   // Record Start and End of each epilog.
1344   SmallVector<struct EpilogStartEnd, 4> Epilogs;
1345   for (auto &I : info->EpilogMap) {
1346     MCSymbol *Start = I.first;
1347     auto &Instrs = I.second.Instructions;
1348     int64_t Offset = GetAbsDifference(streamer, Start, info->Begin);
1349     checkARM64Instructions(streamer, Instrs, Start, I.second.End,
1350                            info->Function->getName(), "epilogue");
1351     assert((Epilogs.size() == 0 || Offset >= Epilogs.back().End) &&
1352            "Epilogs should be monotonically ordered");
1353     // Exclue the end opcode from Instrs.size() when calculating the end of the
1354     // epilog.
1355     Epilogs.push_back({Start, Offset, Offset + (int64_t)(Instrs.size() - 1) * 4});
1356   }
1357 
1358   unsigned E = 0;
1359   int64_t SegLimit = 0xFFFFC;
1360   int64_t SegOffset = 0;
1361 
1362   if (RawFuncLength > SegLimit) {
1363 
1364     int64_t RemainingLength = RawFuncLength;
1365 
1366     while (RemainingLength > SegLimit) {
1367       // Try divide the function into segments, requirements:
1368       // 1. Segment length <= 0xFFFFC;
1369       // 2. Each Prologue or Epilogue must be fully within a segment.
1370       int64_t SegLength = SegLimit;
1371       int64_t SegEnd = SegOffset + SegLength;
1372       // Keep record on symbols and offsets of epilogs in this segment.
1373       MapVector<MCSymbol *, int64_t> EpilogsInSegment;
1374 
1375       while (E < Epilogs.size() && Epilogs[E].End < SegEnd) {
1376         // Epilogs within current segment.
1377         EpilogsInSegment[Epilogs[E].Start] = Epilogs[E].Offset;
1378         ++E;
1379       }
1380 
1381       // At this point, we have:
1382       // 1. Put all epilogs in segments already. No action needed here; or
1383       // 2. Found an epilog that will cross segments boundry. We need to
1384       //    move back current segment's end boundry, so the epilog is entirely
1385       //    in the next segment; or
1386       // 3. Left at least one epilog that is entirely after this segment.
1387       //    It'll be handled by the next iteration, or the last segment.
1388       if (E < Epilogs.size() && Epilogs[E].Offset <= SegEnd)
1389         // Move back current Segment's end boundry.
1390         SegLength = Epilogs[E].Offset - SegOffset;
1391 
1392       auto Seg = WinEH::FrameInfo::Segment(
1393           SegOffset, SegLength, /* HasProlog */!SegOffset);
1394       Seg.Epilogs = std::move(EpilogsInSegment);
1395       info->Segments.push_back(Seg);
1396 
1397       SegOffset += SegLength;
1398       RemainingLength -= SegLength;
1399     }
1400   }
1401 
1402   // Add the last segment when RawFuncLength > 0xFFFFC,
1403   // or the only segment otherwise.
1404   auto LastSeg =
1405       WinEH::FrameInfo::Segment(SegOffset, RawFuncLength - SegOffset,
1406                                 /* HasProlog */!SegOffset);
1407   for (; E < Epilogs.size(); ++E)
1408     LastSeg.Epilogs[Epilogs[E].Start] = Epilogs[E].Offset;
1409   info->Segments.push_back(LastSeg);
1410 }
1411 
ARM64EmitUnwindInfoForSegment(MCStreamer & streamer,WinEH::FrameInfo * info,WinEH::FrameInfo::Segment & Seg,bool TryPacked=true)1412 static void ARM64EmitUnwindInfoForSegment(MCStreamer &streamer,
1413                                           WinEH::FrameInfo *info,
1414                                           WinEH::FrameInfo::Segment &Seg,
1415                                           bool TryPacked = true) {
1416   MCContext &context = streamer.getContext();
1417   MCSymbol *Label = context.createTempSymbol();
1418 
1419   streamer.emitValueToAlignment(Align(4));
1420   streamer.emitLabel(Label);
1421   Seg.Symbol = Label;
1422   // Use the 1st segemnt's label as function's.
1423   if (Seg.Offset == 0)
1424     info->Symbol = Label;
1425 
1426   bool HasProlog = Seg.HasProlog;
1427   bool HasEpilogs = (Seg.Epilogs.size() != 0);
1428 
1429   uint32_t SegLength = (uint32_t)Seg.Length / 4;
1430   uint32_t PrologCodeBytes = info->PrologCodeBytes;
1431 
1432   int PackedEpilogOffset = HasEpilogs ?
1433       checkARM64PackedEpilog(streamer, info, &Seg, PrologCodeBytes) : -1;
1434 
1435   // TODO:
1436   // 1. Enable packed unwind info (.pdata only) for multi-segment functions.
1437   // 2. Emit packed unwind info (.pdata only) for segments that have neithor
1438   //    prolog nor epilog.
1439   if (info->Segments.size() == 1 && PackedEpilogOffset >= 0 &&
1440       uint32_t(PackedEpilogOffset) < PrologCodeBytes &&
1441       !info->HandlesExceptions && SegLength <= 0x7ff && TryPacked) {
1442     // Matching prolog/epilog and no exception handlers; check if the
1443     // prolog matches the patterns that can be described by the packed
1444     // format.
1445 
1446     // info->Symbol was already set even if we didn't actually write any
1447     // unwind info there. Keep using that as indicator that this unwind
1448     // info has been generated already.
1449     if (tryARM64PackedUnwind(info, SegLength, PackedEpilogOffset))
1450       return;
1451   }
1452 
1453   // If the prolog is not in this segment, we need to emit an end_c, which takes
1454   // 1 byte, before prolog unwind ops.
1455   if (!HasProlog) {
1456     PrologCodeBytes += 1;
1457     if (PackedEpilogOffset >= 0)
1458       PackedEpilogOffset += 1;
1459     // If a segment has neither prolog nor epilog, "With full .xdata record,
1460     // Epilog Count = 1. Epilog Start Index points to end_c."
1461     // https://docs.microsoft.com/en-us/cpp/build/arm64-exception-handling#function-fragments
1462     // TODO: We can remove this if testing shows zero epilog scope is ok with
1463     //       MS unwinder.
1464     if (!HasEpilogs)
1465       // Pack the fake epilog into phantom prolog.
1466       PackedEpilogOffset = 0;
1467   }
1468 
1469   uint32_t TotalCodeBytes = PrologCodeBytes;
1470 
1471   // Process epilogs.
1472   MapVector<MCSymbol *, uint32_t> EpilogInfo;
1473   ARM64ProcessEpilogs(info, &Seg, TotalCodeBytes, EpilogInfo);
1474 
1475   // Code Words, Epilog count, E, X, Vers, Function Length
1476   uint32_t row1 = 0x0;
1477   uint32_t CodeWords = TotalCodeBytes / 4;
1478   uint32_t CodeWordsMod = TotalCodeBytes % 4;
1479   if (CodeWordsMod)
1480     CodeWords++;
1481   uint32_t EpilogCount =
1482       PackedEpilogOffset >= 0 ? PackedEpilogOffset : Seg.Epilogs.size();
1483   bool ExtensionWord = EpilogCount > 31 || TotalCodeBytes > 124;
1484   if (!ExtensionWord) {
1485     row1 |= (EpilogCount & 0x1F) << 22;
1486     row1 |= (CodeWords & 0x1F) << 27;
1487   }
1488   if (info->HandlesExceptions) // X
1489     row1 |= 1 << 20;
1490   if (PackedEpilogOffset >= 0) // E
1491     row1 |= 1 << 21;
1492   row1 |= SegLength & 0x3FFFF;
1493   streamer.emitInt32(row1);
1494 
1495   // Extended Code Words, Extended Epilog Count
1496   if (ExtensionWord) {
1497     // FIXME: We should be able to split unwind info into multiple sections.
1498     if (CodeWords > 0xFF || EpilogCount > 0xFFFF)
1499       report_fatal_error(
1500           "SEH unwind data splitting is only implemented for large functions, "
1501           "cases of too many code words or too many epilogs will be done "
1502           "later");
1503     uint32_t row2 = 0x0;
1504     row2 |= (CodeWords & 0xFF) << 16;
1505     row2 |= (EpilogCount & 0xFFFF);
1506     streamer.emitInt32(row2);
1507   }
1508 
1509   if (PackedEpilogOffset < 0) {
1510     // Epilog Start Index, Epilog Start Offset
1511     for (auto &I : EpilogInfo) {
1512       MCSymbol *EpilogStart = I.first;
1513       uint32_t EpilogIndex = I.second;
1514       // Epilog offset within the Segment.
1515       uint32_t EpilogOffset = (uint32_t)(Seg.Epilogs[EpilogStart] - Seg.Offset);
1516       if (EpilogOffset)
1517         EpilogOffset /= 4;
1518       uint32_t row3 = EpilogOffset;
1519       row3 |= (EpilogIndex & 0x3FF) << 22;
1520       streamer.emitInt32(row3);
1521     }
1522   }
1523 
1524   // Note that even for segments that have no prolog, we still need to emit
1525   // prolog unwinding opcodes so that the unwinder knows how to unwind from
1526   // such a segment.
1527   // The end_c opcode at the start indicates to the unwinder that the actual
1528   // prolog is outside of the current segment, and the unwinder shouldn't try
1529   // to check for unwinding from a partial prolog.
1530   if (!HasProlog)
1531     // Emit an end_c.
1532     streamer.emitInt8((uint8_t)0xE5);
1533 
1534   // Emit prolog unwind instructions (in reverse order).
1535   for (auto Inst : llvm::reverse(info->Instructions))
1536     ARM64EmitUnwindCode(streamer, Inst);
1537 
1538   // Emit epilog unwind instructions
1539   for (auto &I : Seg.Epilogs) {
1540     auto &EpilogInstrs = info->EpilogMap[I.first].Instructions;
1541     for (const WinEH::Instruction &inst : EpilogInstrs)
1542       ARM64EmitUnwindCode(streamer, inst);
1543   }
1544 
1545   int32_t BytesMod = CodeWords * 4 - TotalCodeBytes;
1546   assert(BytesMod >= 0);
1547   for (int i = 0; i < BytesMod; i++)
1548     streamer.emitInt8(0xE3);
1549 
1550   if (info->HandlesExceptions)
1551     streamer.emitValue(
1552         MCSymbolRefExpr::create(info->ExceptionHandler,
1553                                 MCSymbolRefExpr::VK_COFF_IMGREL32, context),
1554         4);
1555 }
1556 
1557 // Populate the .xdata section.  The format of .xdata on ARM64 is documented at
1558 // https://docs.microsoft.com/en-us/cpp/build/arm64-exception-handling
ARM64EmitUnwindInfo(MCStreamer & streamer,WinEH::FrameInfo * info,bool TryPacked=true)1559 static void ARM64EmitUnwindInfo(MCStreamer &streamer, WinEH::FrameInfo *info,
1560                                 bool TryPacked = true) {
1561   // If this UNWIND_INFO already has a symbol, it's already been emitted.
1562   if (info->Symbol)
1563     return;
1564   // If there's no unwind info here (not even a terminating UOP_End), the
1565   // unwind info is considered bogus and skipped. If this was done in
1566   // response to an explicit .seh_handlerdata, the associated trailing
1567   // handler data is left orphaned in the xdata section.
1568   if (info->empty()) {
1569     info->EmitAttempted = true;
1570     return;
1571   }
1572   if (info->EmitAttempted) {
1573     // If we tried to emit unwind info before (due to an explicit
1574     // .seh_handlerdata directive), but skipped it (because there was no
1575     // valid information to emit at the time), and it later got valid unwind
1576     // opcodes, we can't emit it here, because the trailing handler data
1577     // was already emitted elsewhere in the xdata section.
1578     streamer.getContext().reportError(
1579         SMLoc(), "Earlier .seh_handlerdata for " + info->Function->getName() +
1580                      " skipped due to no unwind info at the time "
1581                      "(.seh_handlerdata too early?), but the function later "
1582                      "did get unwind info that can't be emitted");
1583     return;
1584   }
1585 
1586   simplifyARM64Opcodes(info->Instructions, false);
1587   for (auto &I : info->EpilogMap)
1588     simplifyARM64Opcodes(I.second.Instructions, true);
1589 
1590   int64_t RawFuncLength;
1591   if (!info->FuncletOrFuncEnd) {
1592     report_fatal_error("FuncletOrFuncEnd not set");
1593   } else {
1594     // FIXME: GetAbsDifference tries to compute the length of the function
1595     // immediately, before the whole file is emitted, but in general
1596     // that's impossible: the size in bytes of certain assembler directives
1597     // like .align and .fill is not known until the whole file is parsed and
1598     // relaxations are applied. Currently, GetAbsDifference fails with a fatal
1599     // error in that case. (We mostly don't hit this because inline assembly
1600     // specifying those directives is rare, and we don't normally try to
1601     // align loops on AArch64.)
1602     //
1603     // There are two potential approaches to delaying the computation. One,
1604     // we could emit something like ".word (endfunc-beginfunc)/4+0x10800000",
1605     // as long as we have some conservative estimate we could use to prove
1606     // that we don't need to split the unwind data. Emitting the constant
1607     // is straightforward, but there's no existing code for estimating the
1608     // size of the function.
1609     //
1610     // The other approach would be to use a dedicated, relaxable fragment,
1611     // which could grow to accommodate splitting the unwind data if
1612     // necessary. This is more straightforward, since it automatically works
1613     // without any new infrastructure, and it's consistent with how we handle
1614     // relaxation in other contexts.  But it would require some refactoring
1615     // to move parts of the pdata/xdata emission into the implementation of
1616     // a fragment. We could probably continue to encode the unwind codes
1617     // here, but we'd have to emit the pdata, the xdata header, and the
1618     // epilogue scopes later, since they depend on whether the we need to
1619     // split the unwind data.
1620     //
1621     // If this is fixed, remove code in AArch64ISelLowering.cpp that
1622     // disables loop alignment on Windows.
1623     RawFuncLength = GetAbsDifference(streamer, info->FuncletOrFuncEnd,
1624                                      info->Begin);
1625   }
1626 
1627   ARM64FindSegmentsInFunction(streamer, info, RawFuncLength);
1628 
1629   info->PrologCodeBytes = ARM64CountOfUnwindCodes(info->Instructions);
1630   for (auto &S : info->Segments)
1631     ARM64EmitUnwindInfoForSegment(streamer, info, S, TryPacked);
1632 
1633   // Clear prolog instructions after unwind info is emitted for all segments.
1634   info->Instructions.clear();
1635 }
1636 
ARMCountOfUnwindCodes(ArrayRef<WinEH::Instruction> Insns)1637 static uint32_t ARMCountOfUnwindCodes(ArrayRef<WinEH::Instruction> Insns) {
1638   uint32_t Count = 0;
1639   for (const auto &I : Insns) {
1640     switch (static_cast<Win64EH::UnwindOpcodes>(I.Operation)) {
1641     default:
1642       llvm_unreachable("Unsupported ARM unwind code");
1643     case Win64EH::UOP_AllocSmall:
1644       Count += 1;
1645       break;
1646     case Win64EH::UOP_AllocLarge:
1647       Count += 3;
1648       break;
1649     case Win64EH::UOP_AllocHuge:
1650       Count += 4;
1651       break;
1652     case Win64EH::UOP_WideAllocMedium:
1653       Count += 2;
1654       break;
1655     case Win64EH::UOP_WideAllocLarge:
1656       Count += 3;
1657       break;
1658     case Win64EH::UOP_WideAllocHuge:
1659       Count += 4;
1660       break;
1661     case Win64EH::UOP_WideSaveRegMask:
1662       Count += 2;
1663       break;
1664     case Win64EH::UOP_SaveSP:
1665       Count += 1;
1666       break;
1667     case Win64EH::UOP_SaveRegsR4R7LR:
1668       Count += 1;
1669       break;
1670     case Win64EH::UOP_WideSaveRegsR4R11LR:
1671       Count += 1;
1672       break;
1673     case Win64EH::UOP_SaveFRegD8D15:
1674       Count += 1;
1675       break;
1676     case Win64EH::UOP_SaveRegMask:
1677       Count += 2;
1678       break;
1679     case Win64EH::UOP_SaveLR:
1680       Count += 2;
1681       break;
1682     case Win64EH::UOP_SaveFRegD0D15:
1683       Count += 2;
1684       break;
1685     case Win64EH::UOP_SaveFRegD16D31:
1686       Count += 2;
1687       break;
1688     case Win64EH::UOP_Nop:
1689     case Win64EH::UOP_WideNop:
1690     case Win64EH::UOP_End:
1691     case Win64EH::UOP_EndNop:
1692     case Win64EH::UOP_WideEndNop:
1693       Count += 1;
1694       break;
1695     case Win64EH::UOP_Custom: {
1696       int J;
1697       for (J = 3; J > 0; J--)
1698         if (I.Offset & (0xffu << (8 * J)))
1699           break;
1700       Count += J + 1;
1701       break;
1702     }
1703     }
1704   }
1705   return Count;
1706 }
1707 
ARMCountOfInstructionBytes(ArrayRef<WinEH::Instruction> Insns,bool * HasCustom=nullptr)1708 static uint32_t ARMCountOfInstructionBytes(ArrayRef<WinEH::Instruction> Insns,
1709                                            bool *HasCustom = nullptr) {
1710   uint32_t Count = 0;
1711   for (const auto &I : Insns) {
1712     switch (static_cast<Win64EH::UnwindOpcodes>(I.Operation)) {
1713     default:
1714       llvm_unreachable("Unsupported ARM unwind code");
1715     case Win64EH::UOP_AllocSmall:
1716     case Win64EH::UOP_AllocLarge:
1717     case Win64EH::UOP_AllocHuge:
1718       Count += 2;
1719       break;
1720     case Win64EH::UOP_WideAllocMedium:
1721     case Win64EH::UOP_WideAllocLarge:
1722     case Win64EH::UOP_WideAllocHuge:
1723       Count += 4;
1724       break;
1725     case Win64EH::UOP_WideSaveRegMask:
1726     case Win64EH::UOP_WideSaveRegsR4R11LR:
1727       Count += 4;
1728       break;
1729     case Win64EH::UOP_SaveSP:
1730       Count += 2;
1731       break;
1732     case Win64EH::UOP_SaveRegMask:
1733     case Win64EH::UOP_SaveRegsR4R7LR:
1734       Count += 2;
1735       break;
1736     case Win64EH::UOP_SaveFRegD8D15:
1737     case Win64EH::UOP_SaveFRegD0D15:
1738     case Win64EH::UOP_SaveFRegD16D31:
1739       Count += 4;
1740       break;
1741     case Win64EH::UOP_SaveLR:
1742       Count += 4;
1743       break;
1744     case Win64EH::UOP_Nop:
1745     case Win64EH::UOP_EndNop:
1746       Count += 2;
1747       break;
1748     case Win64EH::UOP_WideNop:
1749     case Win64EH::UOP_WideEndNop:
1750       Count += 4;
1751       break;
1752     case Win64EH::UOP_End:
1753       // This doesn't map to any instruction
1754       break;
1755     case Win64EH::UOP_Custom:
1756       // We can't reason about what instructions this maps to; return a
1757       // phony number to make sure we don't accidentally do epilog packing.
1758       Count += 1000;
1759       if (HasCustom)
1760         *HasCustom = true;
1761       break;
1762     }
1763   }
1764   return Count;
1765 }
1766 
checkARMInstructions(MCStreamer & Streamer,ArrayRef<WinEH::Instruction> Insns,const MCSymbol * Begin,const MCSymbol * End,StringRef Name,StringRef Type)1767 static void checkARMInstructions(MCStreamer &Streamer,
1768                                  ArrayRef<WinEH::Instruction> Insns,
1769                                  const MCSymbol *Begin, const MCSymbol *End,
1770                                  StringRef Name, StringRef Type) {
1771   if (!End)
1772     return;
1773   std::optional<int64_t> MaybeDistance =
1774       GetOptionalAbsDifference(Streamer, End, Begin);
1775   if (!MaybeDistance)
1776     return;
1777   uint32_t Distance = (uint32_t)*MaybeDistance;
1778   bool HasCustom = false;
1779   uint32_t InstructionBytes = ARMCountOfInstructionBytes(Insns, &HasCustom);
1780   if (HasCustom)
1781     return;
1782   if (Distance != InstructionBytes) {
1783     Streamer.getContext().reportError(
1784         SMLoc(), "Incorrect size for " + Name + " " + Type + ": " +
1785                      Twine(Distance) +
1786                      " bytes of instructions in range, but .seh directives "
1787                      "corresponding to " +
1788                      Twine(InstructionBytes) + " bytes\n");
1789   }
1790 }
1791 
isARMTerminator(const WinEH::Instruction & inst)1792 static bool isARMTerminator(const WinEH::Instruction &inst) {
1793   switch (static_cast<Win64EH::UnwindOpcodes>(inst.Operation)) {
1794   case Win64EH::UOP_End:
1795   case Win64EH::UOP_EndNop:
1796   case Win64EH::UOP_WideEndNop:
1797     return true;
1798   default:
1799     return false;
1800   }
1801 }
1802 
1803 // Unwind opcode encodings and restrictions are documented at
1804 // https://docs.microsoft.com/en-us/cpp/build/arm-exception-handling
ARMEmitUnwindCode(MCStreamer & streamer,const WinEH::Instruction & inst)1805 static void ARMEmitUnwindCode(MCStreamer &streamer,
1806                               const WinEH::Instruction &inst) {
1807   uint32_t w, lr;
1808   int i;
1809   switch (static_cast<Win64EH::UnwindOpcodes>(inst.Operation)) {
1810   default:
1811     llvm_unreachable("Unsupported ARM unwind code");
1812   case Win64EH::UOP_AllocSmall:
1813     assert((inst.Offset & 3) == 0);
1814     assert(inst.Offset / 4 <= 0x7f);
1815     streamer.emitInt8(inst.Offset / 4);
1816     break;
1817   case Win64EH::UOP_WideSaveRegMask:
1818     assert((inst.Register & ~0x5fff) == 0);
1819     lr = (inst.Register >> 14) & 1;
1820     w = 0x8000 | (inst.Register & 0x1fff) | (lr << 13);
1821     streamer.emitInt8((w >> 8) & 0xff);
1822     streamer.emitInt8((w >> 0) & 0xff);
1823     break;
1824   case Win64EH::UOP_SaveSP:
1825     assert(inst.Register <= 0x0f);
1826     streamer.emitInt8(0xc0 | inst.Register);
1827     break;
1828   case Win64EH::UOP_SaveRegsR4R7LR:
1829     assert(inst.Register >= 4 && inst.Register <= 7);
1830     assert(inst.Offset <= 1);
1831     streamer.emitInt8(0xd0 | (inst.Register - 4) | (inst.Offset << 2));
1832     break;
1833   case Win64EH::UOP_WideSaveRegsR4R11LR:
1834     assert(inst.Register >= 8 && inst.Register <= 11);
1835     assert(inst.Offset <= 1);
1836     streamer.emitInt8(0xd8 | (inst.Register - 8) | (inst.Offset << 2));
1837     break;
1838   case Win64EH::UOP_SaveFRegD8D15:
1839     assert(inst.Register >= 8 && inst.Register <= 15);
1840     streamer.emitInt8(0xe0 | (inst.Register - 8));
1841     break;
1842   case Win64EH::UOP_WideAllocMedium:
1843     assert((inst.Offset & 3) == 0);
1844     assert(inst.Offset / 4 <= 0x3ff);
1845     w = 0xe800 | (inst.Offset / 4);
1846     streamer.emitInt8((w >> 8) & 0xff);
1847     streamer.emitInt8((w >> 0) & 0xff);
1848     break;
1849   case Win64EH::UOP_SaveRegMask:
1850     assert((inst.Register & ~0x40ff) == 0);
1851     lr = (inst.Register >> 14) & 1;
1852     w = 0xec00 | (inst.Register & 0x0ff) | (lr << 8);
1853     streamer.emitInt8((w >> 8) & 0xff);
1854     streamer.emitInt8((w >> 0) & 0xff);
1855     break;
1856   case Win64EH::UOP_SaveLR:
1857     assert((inst.Offset & 3) == 0);
1858     assert(inst.Offset / 4 <= 0x0f);
1859     streamer.emitInt8(0xef);
1860     streamer.emitInt8(inst.Offset / 4);
1861     break;
1862   case Win64EH::UOP_SaveFRegD0D15:
1863     assert(inst.Register <= 15);
1864     assert(inst.Offset <= 15);
1865     assert(inst.Register <= inst.Offset);
1866     streamer.emitInt8(0xf5);
1867     streamer.emitInt8((inst.Register << 4) | inst.Offset);
1868     break;
1869   case Win64EH::UOP_SaveFRegD16D31:
1870     assert(inst.Register >= 16 && inst.Register <= 31);
1871     assert(inst.Offset >= 16 && inst.Offset <= 31);
1872     assert(inst.Register <= inst.Offset);
1873     streamer.emitInt8(0xf6);
1874     streamer.emitInt8(((inst.Register - 16) << 4) | (inst.Offset - 16));
1875     break;
1876   case Win64EH::UOP_AllocLarge:
1877     assert((inst.Offset & 3) == 0);
1878     assert(inst.Offset / 4 <= 0xffff);
1879     w = inst.Offset / 4;
1880     streamer.emitInt8(0xf7);
1881     streamer.emitInt8((w >> 8) & 0xff);
1882     streamer.emitInt8((w >> 0) & 0xff);
1883     break;
1884   case Win64EH::UOP_AllocHuge:
1885     assert((inst.Offset & 3) == 0);
1886     assert(inst.Offset / 4 <= 0xffffff);
1887     w = inst.Offset / 4;
1888     streamer.emitInt8(0xf8);
1889     streamer.emitInt8((w >> 16) & 0xff);
1890     streamer.emitInt8((w >> 8) & 0xff);
1891     streamer.emitInt8((w >> 0) & 0xff);
1892     break;
1893   case Win64EH::UOP_WideAllocLarge:
1894     assert((inst.Offset & 3) == 0);
1895     assert(inst.Offset / 4 <= 0xffff);
1896     w = inst.Offset / 4;
1897     streamer.emitInt8(0xf9);
1898     streamer.emitInt8((w >> 8) & 0xff);
1899     streamer.emitInt8((w >> 0) & 0xff);
1900     break;
1901   case Win64EH::UOP_WideAllocHuge:
1902     assert((inst.Offset & 3) == 0);
1903     assert(inst.Offset / 4 <= 0xffffff);
1904     w = inst.Offset / 4;
1905     streamer.emitInt8(0xfa);
1906     streamer.emitInt8((w >> 16) & 0xff);
1907     streamer.emitInt8((w >> 8) & 0xff);
1908     streamer.emitInt8((w >> 0) & 0xff);
1909     break;
1910   case Win64EH::UOP_Nop:
1911     streamer.emitInt8(0xfb);
1912     break;
1913   case Win64EH::UOP_WideNop:
1914     streamer.emitInt8(0xfc);
1915     break;
1916   case Win64EH::UOP_EndNop:
1917     streamer.emitInt8(0xfd);
1918     break;
1919   case Win64EH::UOP_WideEndNop:
1920     streamer.emitInt8(0xfe);
1921     break;
1922   case Win64EH::UOP_End:
1923     streamer.emitInt8(0xff);
1924     break;
1925   case Win64EH::UOP_Custom:
1926     for (i = 3; i > 0; i--)
1927       if (inst.Offset & (0xffu << (8 * i)))
1928         break;
1929     for (; i >= 0; i--)
1930       streamer.emitInt8((inst.Offset >> (8 * i)) & 0xff);
1931     break;
1932   }
1933 }
1934 
1935 // Check if an epilog exists as a subset of the end of a prolog (backwards).
1936 // An epilog may end with one out of three different end opcodes; if this
1937 // is the first epilog that shares opcodes with the prolog, we can tolerate
1938 // that this opcode differs (and the caller will update the prolog to use
1939 // the same end opcode as the epilog). If another epilog already shares
1940 // opcodes with the prolog, the ending opcode must be a strict match.
getARMOffsetInProlog(const std::vector<WinEH::Instruction> & Prolog,const std::vector<WinEH::Instruction> & Epilog,bool CanTweakProlog)1941 static int getARMOffsetInProlog(const std::vector<WinEH::Instruction> &Prolog,
1942                                 const std::vector<WinEH::Instruction> &Epilog,
1943                                 bool CanTweakProlog) {
1944   // Can't find an epilog as a subset if it is longer than the prolog.
1945   if (Epilog.size() > Prolog.size())
1946     return -1;
1947 
1948   // Check that the epilog actually is a perfect match for the end (backwrds)
1949   // of the prolog.
1950   // If we can adjust the prolog afterwards, don't check that the end opcodes
1951   // match.
1952   int EndIdx = CanTweakProlog ? 1 : 0;
1953   for (int I = Epilog.size() - 1; I >= EndIdx; I--) {
1954     // TODO: Could also allow minor mismatches, e.g. "add sp, #16" vs
1955     // "push {r0-r3}".
1956     if (Prolog[I] != Epilog[Epilog.size() - 1 - I])
1957       return -1;
1958   }
1959 
1960   if (CanTweakProlog) {
1961     // Check that both prolog and epilog end with an expected end opcode.
1962     if (Prolog.front().Operation != Win64EH::UOP_End)
1963       return -1;
1964     if (Epilog.back().Operation != Win64EH::UOP_End &&
1965         Epilog.back().Operation != Win64EH::UOP_EndNop &&
1966         Epilog.back().Operation != Win64EH::UOP_WideEndNop)
1967       return -1;
1968   }
1969 
1970   // If the epilog was a subset of the prolog, find its offset.
1971   if (Epilog.size() == Prolog.size())
1972     return 0;
1973   return ARMCountOfUnwindCodes(ArrayRef<WinEH::Instruction>(
1974       &Prolog[Epilog.size()], Prolog.size() - Epilog.size()));
1975 }
1976 
checkARMPackedEpilog(MCStreamer & streamer,WinEH::FrameInfo * info,int PrologCodeBytes)1977 static int checkARMPackedEpilog(MCStreamer &streamer, WinEH::FrameInfo *info,
1978                                 int PrologCodeBytes) {
1979   // Can only pack if there's one single epilog
1980   if (info->EpilogMap.size() != 1)
1981     return -1;
1982 
1983   const WinEH::FrameInfo::Epilog &EpilogInfo = info->EpilogMap.begin()->second;
1984   // Can only pack if the epilog is unconditional
1985   if (EpilogInfo.Condition != 0xe) // ARMCC::AL
1986     return -1;
1987 
1988   const std::vector<WinEH::Instruction> &Epilog = EpilogInfo.Instructions;
1989   // Make sure we have at least the trailing end opcode
1990   if (info->Instructions.empty() || Epilog.empty())
1991     return -1;
1992 
1993   // Check that the epilog actually is at the very end of the function,
1994   // otherwise it can't be packed.
1995   std::optional<int64_t> MaybeDistance = GetOptionalAbsDifference(
1996       streamer, info->FuncletOrFuncEnd, info->EpilogMap.begin()->first);
1997   if (!MaybeDistance)
1998     return -1;
1999   uint32_t DistanceFromEnd = (uint32_t)*MaybeDistance;
2000   uint32_t InstructionBytes = ARMCountOfInstructionBytes(Epilog);
2001   if (DistanceFromEnd != InstructionBytes)
2002     return -1;
2003 
2004   int RetVal = -1;
2005   // Even if we don't end up sharing opcodes with the prolog, we can still
2006   // write the offset as a packed offset, if the single epilog is located at
2007   // the end of the function and the offset (pointing after the prolog) fits
2008   // as a packed offset.
2009   if (PrologCodeBytes <= 31 &&
2010       PrologCodeBytes + ARMCountOfUnwindCodes(Epilog) <= 63)
2011     RetVal = PrologCodeBytes;
2012 
2013   int Offset =
2014       getARMOffsetInProlog(info->Instructions, Epilog, /*CanTweakProlog=*/true);
2015   if (Offset < 0)
2016     return RetVal;
2017 
2018   // Check that the offset and prolog size fits in the first word; it's
2019   // unclear whether the epilog count in the extension word can be taken
2020   // as packed epilog offset.
2021   if (Offset > 31 || PrologCodeBytes > 63)
2022     return RetVal;
2023 
2024   // Replace the regular end opcode of the prolog with the one from the
2025   // epilog.
2026   info->Instructions.front() = Epilog.back();
2027 
2028   // As we choose to express the epilog as part of the prolog, remove the
2029   // epilog from the map, so we don't try to emit its opcodes.
2030   info->EpilogMap.clear();
2031   return Offset;
2032 }
2033 
parseRegMask(unsigned Mask,bool & HasLR,bool & HasR11,unsigned & Folded,int & IntRegs)2034 static bool parseRegMask(unsigned Mask, bool &HasLR, bool &HasR11,
2035                          unsigned &Folded, int &IntRegs) {
2036   if (Mask & (1 << 14)) {
2037     HasLR = true;
2038     Mask &= ~(1 << 14);
2039   }
2040   if (Mask & (1 << 11)) {
2041     HasR11 = true;
2042     Mask &= ~(1 << 11);
2043   }
2044   Folded = 0;
2045   IntRegs = -1;
2046   if (!Mask)
2047     return true;
2048   int First = 0;
2049   // Shift right until we have the bits at the bottom
2050   while ((Mask & 1) == 0) {
2051     First++;
2052     Mask >>= 1;
2053   }
2054   if ((Mask & (Mask + 1)) != 0)
2055     return false; // Not a consecutive series of bits? Can't be packed.
2056   // Count the bits
2057   int N = 0;
2058   while (Mask & (1 << N))
2059     N++;
2060   if (First < 4) {
2061     if (First + N < 4)
2062       return false;
2063     Folded = 4 - First;
2064     N -= Folded;
2065     First = 4;
2066   }
2067   if (First > 4)
2068     return false; // Can't be packed
2069   if (N >= 1)
2070     IntRegs = N - 1;
2071   return true;
2072 }
2073 
tryARMPackedUnwind(MCStreamer & streamer,WinEH::FrameInfo * info,uint32_t FuncLength)2074 static bool tryARMPackedUnwind(MCStreamer &streamer, WinEH::FrameInfo *info,
2075                                uint32_t FuncLength) {
2076   int Step = 0;
2077   bool Homing = false;
2078   bool HasR11 = false;
2079   bool HasChain = false;
2080   bool HasLR = false;
2081   int IntRegs = -1;   // r4 - r(4+N)
2082   int FloatRegs = -1; // d8 - d(8+N)
2083   unsigned PF = 0;    // Number of extra pushed registers
2084   unsigned StackAdjust = 0;
2085   // Iterate over the prolog and check that all opcodes exactly match
2086   // the canonical order and form.
2087   for (const WinEH::Instruction &Inst : info->Instructions) {
2088     switch (Inst.Operation) {
2089     default:
2090       llvm_unreachable("Unsupported ARM unwind code");
2091     case Win64EH::UOP_Custom:
2092     case Win64EH::UOP_AllocLarge:
2093     case Win64EH::UOP_AllocHuge:
2094     case Win64EH::UOP_WideAllocLarge:
2095     case Win64EH::UOP_WideAllocHuge:
2096     case Win64EH::UOP_SaveFRegD0D15:
2097     case Win64EH::UOP_SaveFRegD16D31:
2098       // Can't be packed
2099       return false;
2100     case Win64EH::UOP_SaveSP:
2101       // Can't be packed; we can't rely on restoring sp from r11 when
2102       // unwinding a packed prologue.
2103       return false;
2104     case Win64EH::UOP_SaveLR:
2105       // Can't be present in a packed prologue
2106       return false;
2107 
2108     case Win64EH::UOP_End:
2109     case Win64EH::UOP_EndNop:
2110     case Win64EH::UOP_WideEndNop:
2111       if (Step != 0)
2112         return false;
2113       Step = 1;
2114       break;
2115 
2116     case Win64EH::UOP_SaveRegsR4R7LR:
2117     case Win64EH::UOP_WideSaveRegsR4R11LR:
2118       // push {r4-r11,lr}
2119       if (Step != 1 && Step != 2)
2120         return false;
2121       assert(Inst.Register >= 4 && Inst.Register <= 11); // r4-rX
2122       assert(Inst.Offset <= 1);                          // Lr
2123       IntRegs = Inst.Register - 4;
2124       if (Inst.Register == 11) {
2125         HasR11 = true;
2126         IntRegs--;
2127       }
2128       if (Inst.Offset)
2129         HasLR = true;
2130       Step = 3;
2131       break;
2132 
2133     case Win64EH::UOP_SaveRegMask:
2134       if (Step == 1 && Inst.Register == 0x0f) {
2135         // push {r0-r3}
2136         Homing = true;
2137         Step = 2;
2138         break;
2139       }
2140       [[fallthrough]];
2141     case Win64EH::UOP_WideSaveRegMask:
2142       if (Step != 1 && Step != 2)
2143         return false;
2144       // push {r4-r9,r11,lr}
2145       // push {r11,lr}
2146       // push {r1-r5}
2147       if (!parseRegMask(Inst.Register, HasLR, HasR11, PF, IntRegs))
2148         return false;
2149       Step = 3;
2150       break;
2151 
2152     case Win64EH::UOP_Nop:
2153       // mov r11, sp
2154       if (Step != 3 || !HasR11 || IntRegs >= 0 || PF > 0)
2155         return false;
2156       HasChain = true;
2157       Step = 4;
2158       break;
2159     case Win64EH::UOP_WideNop:
2160       // add.w r11, sp, #xx
2161       if (Step != 3 || !HasR11 || (IntRegs < 0 && PF == 0))
2162         return false;
2163       HasChain = true;
2164       Step = 4;
2165       break;
2166 
2167     case Win64EH::UOP_SaveFRegD8D15:
2168       if (Step != 1 && Step != 2 && Step != 3 && Step != 4)
2169         return false;
2170       assert(Inst.Register >= 8 && Inst.Register <= 15);
2171       if (Inst.Register == 15)
2172         return false; // Can't pack this case, R==7 means no IntRegs
2173       if (IntRegs >= 0)
2174         return false;
2175       FloatRegs = Inst.Register - 8;
2176       Step = 5;
2177       break;
2178 
2179     case Win64EH::UOP_AllocSmall:
2180     case Win64EH::UOP_WideAllocMedium:
2181       if (Step != 1 && Step != 2 && Step != 3 && Step != 4 && Step != 5)
2182         return false;
2183       if (PF > 0) // Can't have both folded and explicit stack allocation
2184         return false;
2185       if (Inst.Offset / 4 >= 0x3f4)
2186         return false;
2187       StackAdjust = Inst.Offset / 4;
2188       Step = 6;
2189       break;
2190     }
2191   }
2192   if (HasR11 && !HasChain) {
2193     if (IntRegs + 4 == 10) {
2194       // r11 stored, but not chaining; can be packed if already saving r4-r10
2195       // and we can fit r11 into this range.
2196       IntRegs++;
2197       HasR11 = false;
2198     } else
2199       return false;
2200   }
2201   if (HasChain && !HasLR)
2202     return false;
2203 
2204   // Packed uneind info can't express multiple epilogues.
2205   if (info->EpilogMap.size() > 1)
2206     return false;
2207 
2208   unsigned EF = 0;
2209   int Ret = 0;
2210   if (info->EpilogMap.size() == 0) {
2211     Ret = 3; // No epilogue
2212   } else {
2213     // As the prologue and epilogue aren't exact mirrors of each other,
2214     // we have to check the epilogue too and see if it matches what we've
2215     // concluded from the prologue.
2216     const WinEH::FrameInfo::Epilog &EpilogInfo =
2217         info->EpilogMap.begin()->second;
2218     if (EpilogInfo.Condition != 0xe) // ARMCC::AL
2219       return false;
2220     const std::vector<WinEH::Instruction> &Epilog = EpilogInfo.Instructions;
2221     std::optional<int64_t> MaybeDistance = GetOptionalAbsDifference(
2222         streamer, info->FuncletOrFuncEnd, info->EpilogMap.begin()->first);
2223     if (!MaybeDistance)
2224       return false;
2225     uint32_t DistanceFromEnd = (uint32_t)*MaybeDistance;
2226     uint32_t InstructionBytes = ARMCountOfInstructionBytes(Epilog);
2227     if (DistanceFromEnd != InstructionBytes)
2228       return false;
2229 
2230     bool GotStackAdjust = false;
2231     bool GotFloatRegs = false;
2232     bool GotIntRegs = false;
2233     bool GotHomingRestore = false;
2234     bool GotLRRestore = false;
2235     bool NeedsReturn = false;
2236     bool GotReturn = false;
2237 
2238     Step = 6;
2239     for (const WinEH::Instruction &Inst : Epilog) {
2240       switch (Inst.Operation) {
2241       default:
2242         llvm_unreachable("Unsupported ARM unwind code");
2243       case Win64EH::UOP_Custom:
2244       case Win64EH::UOP_AllocLarge:
2245       case Win64EH::UOP_AllocHuge:
2246       case Win64EH::UOP_WideAllocLarge:
2247       case Win64EH::UOP_WideAllocHuge:
2248       case Win64EH::UOP_SaveFRegD0D15:
2249       case Win64EH::UOP_SaveFRegD16D31:
2250       case Win64EH::UOP_SaveSP:
2251       case Win64EH::UOP_Nop:
2252       case Win64EH::UOP_WideNop:
2253         // Can't be packed in an epilogue
2254         return false;
2255 
2256       case Win64EH::UOP_AllocSmall:
2257       case Win64EH::UOP_WideAllocMedium:
2258         if (Inst.Offset / 4 >= 0x3f4)
2259           return false;
2260         if (Step == 6) {
2261           if (Homing && FloatRegs < 0 && IntRegs < 0 && StackAdjust == 0 &&
2262               PF == 0 && Inst.Offset == 16) {
2263             GotHomingRestore = true;
2264             Step = 10;
2265           } else {
2266             if (StackAdjust > 0) {
2267               // Got stack adjust in prologue too; must match.
2268               if (StackAdjust != Inst.Offset / 4)
2269                 return false;
2270               GotStackAdjust = true;
2271             } else if (PF == Inst.Offset / 4) {
2272               // Folded prologue, non-folded epilogue
2273               StackAdjust = Inst.Offset / 4;
2274               GotStackAdjust = true;
2275             } else {
2276               // StackAdjust == 0 in prologue, mismatch
2277               return false;
2278             }
2279             Step = 7;
2280           }
2281         } else if (Step == 7 || Step == 8 || Step == 9) {
2282           if (!Homing || Inst.Offset != 16)
2283             return false;
2284           GotHomingRestore = true;
2285           Step = 10;
2286         } else
2287           return false;
2288         break;
2289 
2290       case Win64EH::UOP_SaveFRegD8D15:
2291         if (Step != 6 && Step != 7)
2292           return false;
2293         assert(Inst.Register >= 8 && Inst.Register <= 15);
2294         if (FloatRegs != (int)(Inst.Register - 8))
2295           return false;
2296         GotFloatRegs = true;
2297         Step = 8;
2298         break;
2299 
2300       case Win64EH::UOP_SaveRegsR4R7LR:
2301       case Win64EH::UOP_WideSaveRegsR4R11LR: {
2302         // push {r4-r11,lr}
2303         if (Step != 6 && Step != 7 && Step != 8)
2304           return false;
2305         assert(Inst.Register >= 4 && Inst.Register <= 11); // r4-rX
2306         assert(Inst.Offset <= 1);                          // Lr
2307         if (Homing && HasLR) {
2308           // If homing and LR is backed up, we can either restore LR here
2309           // and return with Ret == 1 or 2, or return with SaveLR below
2310           if (Inst.Offset) {
2311             GotLRRestore = true;
2312             NeedsReturn = true;
2313           } else {
2314             // Expecting a separate SaveLR below
2315           }
2316         } else {
2317           if (HasLR != (Inst.Offset == 1))
2318             return false;
2319         }
2320         GotLRRestore = Inst.Offset == 1;
2321         if (IntRegs < 0) // This opcode must include r4
2322           return false;
2323         int Expected = IntRegs;
2324         if (HasChain) {
2325           // Can't express r11 here unless IntRegs describe r4-r10
2326           if (IntRegs != 6)
2327             return false;
2328           Expected++;
2329         }
2330         if (Expected != (int)(Inst.Register - 4))
2331           return false;
2332         GotIntRegs = true;
2333         Step = 9;
2334         break;
2335       }
2336 
2337       case Win64EH::UOP_SaveRegMask:
2338       case Win64EH::UOP_WideSaveRegMask: {
2339         if (Step != 6 && Step != 7 && Step != 8)
2340           return false;
2341         // push {r4-r9,r11,lr}
2342         // push {r11,lr}
2343         // push {r1-r5}
2344         bool CurHasLR = false, CurHasR11 = false;
2345         int Regs;
2346         if (!parseRegMask(Inst.Register, CurHasLR, CurHasR11, EF, Regs))
2347           return false;
2348         if (EF > 0) {
2349           if (EF != PF && EF != StackAdjust)
2350             return false;
2351         }
2352         if (Homing && HasLR) {
2353           // If homing and LR is backed up, we can either restore LR here
2354           // and return with Ret == 1 or 2, or return with SaveLR below
2355           if (CurHasLR) {
2356             GotLRRestore = true;
2357             NeedsReturn = true;
2358           } else {
2359             // Expecting a separate SaveLR below
2360           }
2361         } else {
2362           if (CurHasLR != HasLR)
2363             return false;
2364           GotLRRestore = CurHasLR;
2365         }
2366         int Expected = IntRegs;
2367         if (HasChain) {
2368           // If we have chaining, the mask must have included r11.
2369           if (!CurHasR11)
2370             return false;
2371         } else if (Expected == 7) {
2372           // If we don't have chaining, the mask could still include r11,
2373           // expressed as part of IntRegs Instead.
2374           Expected--;
2375           if (!CurHasR11)
2376             return false;
2377         } else {
2378           // Neither HasChain nor r11 included in IntRegs, must not have r11
2379           // here either.
2380           if (CurHasR11)
2381             return false;
2382         }
2383         if (Expected != Regs)
2384           return false;
2385         GotIntRegs = true;
2386         Step = 9;
2387         break;
2388       }
2389 
2390       case Win64EH::UOP_SaveLR:
2391         if (Step != 6 && Step != 7 && Step != 8 && Step != 9)
2392           return false;
2393         if (!Homing || Inst.Offset != 20 || GotLRRestore)
2394           return false;
2395         GotLRRestore = true;
2396         GotHomingRestore = true;
2397         Step = 10;
2398         break;
2399 
2400       case Win64EH::UOP_EndNop:
2401       case Win64EH::UOP_WideEndNop:
2402         GotReturn = true;
2403         Ret = (Inst.Operation == Win64EH::UOP_EndNop) ? 1 : 2;
2404         [[fallthrough]];
2405       case Win64EH::UOP_End:
2406         if (Step != 6 && Step != 7 && Step != 8 && Step != 9 && Step != 10)
2407           return false;
2408         Step = 11;
2409         break;
2410       }
2411     }
2412 
2413     if (Step != 11)
2414       return false;
2415     if (StackAdjust > 0 && !GotStackAdjust && EF == 0)
2416       return false;
2417     if (FloatRegs >= 0 && !GotFloatRegs)
2418       return false;
2419     if (IntRegs >= 0 && !GotIntRegs)
2420       return false;
2421     if (Homing && !GotHomingRestore)
2422       return false;
2423     if (HasLR && !GotLRRestore)
2424       return false;
2425     if (NeedsReturn && !GotReturn)
2426       return false;
2427   }
2428 
2429   assert(PF == 0 || EF == 0 ||
2430          StackAdjust == 0); // Can't have adjust in all three
2431   if (PF > 0 || EF > 0) {
2432     StackAdjust = PF > 0 ? (PF - 1) : (EF - 1);
2433     assert(StackAdjust <= 3);
2434     StackAdjust |= 0x3f0;
2435     if (PF > 0)
2436       StackAdjust |= 1 << 2;
2437     if (EF > 0)
2438       StackAdjust |= 1 << 3;
2439   }
2440 
2441   assert(FuncLength <= 0x7FF && "FuncLength should have been checked earlier");
2442   int Flag = info->Fragment ? 0x02 : 0x01;
2443   int H = Homing ? 1 : 0;
2444   int L = HasLR ? 1 : 0;
2445   int C = HasChain ? 1 : 0;
2446   assert(IntRegs < 0 || FloatRegs < 0);
2447   unsigned Reg, R;
2448   if (IntRegs >= 0) {
2449     Reg = IntRegs;
2450     assert(Reg <= 7);
2451     R = 0;
2452   } else if (FloatRegs >= 0) {
2453     Reg = FloatRegs;
2454     assert(Reg < 7);
2455     R = 1;
2456   } else {
2457     // No int or float regs stored (except possibly R11,LR)
2458     Reg = 7;
2459     R = 1;
2460   }
2461   info->PackedInfo |= Flag << 0;
2462   info->PackedInfo |= (FuncLength & 0x7FF) << 2;
2463   info->PackedInfo |= (Ret & 0x3) << 13;
2464   info->PackedInfo |= H << 15;
2465   info->PackedInfo |= Reg << 16;
2466   info->PackedInfo |= R << 19;
2467   info->PackedInfo |= L << 20;
2468   info->PackedInfo |= C << 21;
2469   assert(StackAdjust <= 0x3ff);
2470   info->PackedInfo |= StackAdjust << 22;
2471   return true;
2472 }
2473 
2474 // Populate the .xdata section.  The format of .xdata on ARM is documented at
2475 // https://docs.microsoft.com/en-us/cpp/build/arm-exception-handling
ARMEmitUnwindInfo(MCStreamer & streamer,WinEH::FrameInfo * info,bool TryPacked=true)2476 static void ARMEmitUnwindInfo(MCStreamer &streamer, WinEH::FrameInfo *info,
2477                               bool TryPacked = true) {
2478   // If this UNWIND_INFO already has a symbol, it's already been emitted.
2479   if (info->Symbol)
2480     return;
2481   // If there's no unwind info here (not even a terminating UOP_End), the
2482   // unwind info is considered bogus and skipped. If this was done in
2483   // response to an explicit .seh_handlerdata, the associated trailing
2484   // handler data is left orphaned in the xdata section.
2485   if (info->empty()) {
2486     info->EmitAttempted = true;
2487     return;
2488   }
2489   if (info->EmitAttempted) {
2490     // If we tried to emit unwind info before (due to an explicit
2491     // .seh_handlerdata directive), but skipped it (because there was no
2492     // valid information to emit at the time), and it later got valid unwind
2493     // opcodes, we can't emit it here, because the trailing handler data
2494     // was already emitted elsewhere in the xdata section.
2495     streamer.getContext().reportError(
2496         SMLoc(), "Earlier .seh_handlerdata for " + info->Function->getName() +
2497                      " skipped due to no unwind info at the time "
2498                      "(.seh_handlerdata too early?), but the function later "
2499                      "did get unwind info that can't be emitted");
2500     return;
2501   }
2502 
2503   MCContext &context = streamer.getContext();
2504   MCSymbol *Label = context.createTempSymbol();
2505 
2506   streamer.emitValueToAlignment(Align(4));
2507   streamer.emitLabel(Label);
2508   info->Symbol = Label;
2509 
2510   if (!info->PrologEnd)
2511     streamer.getContext().reportError(SMLoc(), "Prologue in " +
2512                                                    info->Function->getName() +
2513                                                    " not correctly terminated");
2514 
2515   if (info->PrologEnd && !info->Fragment)
2516     checkARMInstructions(streamer, info->Instructions, info->Begin,
2517                          info->PrologEnd, info->Function->getName(),
2518                          "prologue");
2519   for (auto &I : info->EpilogMap) {
2520     MCSymbol *EpilogStart = I.first;
2521     auto &Epilog = I.second;
2522     checkARMInstructions(streamer, Epilog.Instructions, EpilogStart, Epilog.End,
2523                          info->Function->getName(), "epilogue");
2524     if (Epilog.Instructions.empty() ||
2525         !isARMTerminator(Epilog.Instructions.back()))
2526       streamer.getContext().reportError(
2527           SMLoc(), "Epilogue in " + info->Function->getName() +
2528                        " not correctly terminated");
2529   }
2530 
2531   std::optional<int64_t> RawFuncLength;
2532   const MCExpr *FuncLengthExpr = nullptr;
2533   if (!info->FuncletOrFuncEnd) {
2534     report_fatal_error("FuncletOrFuncEnd not set");
2535   } else {
2536     // As the size of many thumb2 instructions isn't known until later,
2537     // we can't always rely on being able to calculate the absolute
2538     // length of the function here. If we can't calculate it, defer it
2539     // to a relocation.
2540     //
2541     // In such a case, we won't know if the function is too long so that
2542     // the unwind info would need to be split (but this isn't implemented
2543     // anyway).
2544     RawFuncLength =
2545         GetOptionalAbsDifference(streamer, info->FuncletOrFuncEnd, info->Begin);
2546     if (!RawFuncLength)
2547       FuncLengthExpr =
2548           GetSubDivExpr(streamer, info->FuncletOrFuncEnd, info->Begin, 2);
2549   }
2550   uint32_t FuncLength = 0;
2551   if (RawFuncLength)
2552     FuncLength = (uint32_t)*RawFuncLength / 2;
2553   if (FuncLength > 0x3FFFF)
2554     report_fatal_error("SEH unwind data splitting not yet implemented");
2555   uint32_t PrologCodeBytes = ARMCountOfUnwindCodes(info->Instructions);
2556   uint32_t TotalCodeBytes = PrologCodeBytes;
2557 
2558   if (!info->HandlesExceptions && RawFuncLength && FuncLength <= 0x7ff &&
2559       TryPacked) {
2560     // No exception handlers; check if the prolog and epilog matches the
2561     // patterns that can be described by the packed format. If we don't
2562     // know the exact function length yet, we can't do this.
2563 
2564     // info->Symbol was already set even if we didn't actually write any
2565     // unwind info there. Keep using that as indicator that this unwind
2566     // info has been generated already.
2567 
2568     if (tryARMPackedUnwind(streamer, info, FuncLength))
2569       return;
2570   }
2571 
2572   int PackedEpilogOffset =
2573       checkARMPackedEpilog(streamer, info, PrologCodeBytes);
2574 
2575   // Process epilogs.
2576   MapVector<MCSymbol *, uint32_t> EpilogInfo;
2577   // Epilogs processed so far.
2578   std::vector<MCSymbol *> AddedEpilogs;
2579 
2580   bool CanTweakProlog = true;
2581   for (auto &I : info->EpilogMap) {
2582     MCSymbol *EpilogStart = I.first;
2583     auto &EpilogInstrs = I.second.Instructions;
2584     uint32_t CodeBytes = ARMCountOfUnwindCodes(EpilogInstrs);
2585 
2586     MCSymbol *MatchingEpilog =
2587         FindMatchingEpilog(EpilogInstrs, AddedEpilogs, info);
2588     int PrologOffset;
2589     if (MatchingEpilog) {
2590       assert(EpilogInfo.contains(MatchingEpilog) &&
2591              "Duplicate epilog not found");
2592       EpilogInfo[EpilogStart] = EpilogInfo.lookup(MatchingEpilog);
2593       // Clear the unwind codes in the EpilogMap, so that they don't get output
2594       // in the logic below.
2595       EpilogInstrs.clear();
2596     } else if ((PrologOffset = getARMOffsetInProlog(
2597                     info->Instructions, EpilogInstrs, CanTweakProlog)) >= 0) {
2598       if (CanTweakProlog) {
2599         // Replace the regular end opcode of the prolog with the one from the
2600         // epilog.
2601         info->Instructions.front() = EpilogInstrs.back();
2602         // Later epilogs need a strict match for the end opcode.
2603         CanTweakProlog = false;
2604       }
2605       EpilogInfo[EpilogStart] = PrologOffset;
2606       // Clear the unwind codes in the EpilogMap, so that they don't get output
2607       // in the logic below.
2608       EpilogInstrs.clear();
2609     } else {
2610       EpilogInfo[EpilogStart] = TotalCodeBytes;
2611       TotalCodeBytes += CodeBytes;
2612       AddedEpilogs.push_back(EpilogStart);
2613     }
2614   }
2615 
2616   // Code Words, Epilog count, F, E, X, Vers, Function Length
2617   uint32_t row1 = 0x0;
2618   uint32_t CodeWords = TotalCodeBytes / 4;
2619   uint32_t CodeWordsMod = TotalCodeBytes % 4;
2620   if (CodeWordsMod)
2621     CodeWords++;
2622   uint32_t EpilogCount =
2623       PackedEpilogOffset >= 0 ? PackedEpilogOffset : info->EpilogMap.size();
2624   bool ExtensionWord = EpilogCount > 31 || CodeWords > 15;
2625   if (!ExtensionWord) {
2626     row1 |= (EpilogCount & 0x1F) << 23;
2627     row1 |= (CodeWords & 0x0F) << 28;
2628   }
2629   if (info->HandlesExceptions) // X
2630     row1 |= 1 << 20;
2631   if (PackedEpilogOffset >= 0) // E
2632     row1 |= 1 << 21;
2633   if (info->Fragment) // F
2634     row1 |= 1 << 22;
2635   row1 |= FuncLength & 0x3FFFF;
2636   if (RawFuncLength)
2637     streamer.emitInt32(row1);
2638   else
2639     streamer.emitValue(
2640         MCBinaryExpr::createOr(FuncLengthExpr,
2641                                MCConstantExpr::create(row1, context), context),
2642         4);
2643 
2644   // Extended Code Words, Extended Epilog Count
2645   if (ExtensionWord) {
2646     // FIXME: We should be able to split unwind info into multiple sections.
2647     if (CodeWords > 0xFF || EpilogCount > 0xFFFF)
2648       report_fatal_error("SEH unwind data splitting not yet implemented");
2649     uint32_t row2 = 0x0;
2650     row2 |= (CodeWords & 0xFF) << 16;
2651     row2 |= (EpilogCount & 0xFFFF);
2652     streamer.emitInt32(row2);
2653   }
2654 
2655   if (PackedEpilogOffset < 0) {
2656     // Epilog Start Index, Epilog Start Offset
2657     for (auto &I : EpilogInfo) {
2658       MCSymbol *EpilogStart = I.first;
2659       uint32_t EpilogIndex = I.second;
2660 
2661       std::optional<int64_t> MaybeEpilogOffset =
2662           GetOptionalAbsDifference(streamer, EpilogStart, info->Begin);
2663       const MCExpr *OffsetExpr = nullptr;
2664       uint32_t EpilogOffset = 0;
2665       if (MaybeEpilogOffset)
2666         EpilogOffset = *MaybeEpilogOffset / 2;
2667       else
2668         OffsetExpr = GetSubDivExpr(streamer, EpilogStart, info->Begin, 2);
2669 
2670       assert(info->EpilogMap.contains(EpilogStart));
2671       unsigned Condition = info->EpilogMap[EpilogStart].Condition;
2672       assert(Condition <= 0xf);
2673 
2674       uint32_t row3 = EpilogOffset;
2675       row3 |= Condition << 20;
2676       row3 |= (EpilogIndex & 0x3FF) << 24;
2677       if (MaybeEpilogOffset)
2678         streamer.emitInt32(row3);
2679       else
2680         streamer.emitValue(
2681             MCBinaryExpr::createOr(
2682                 OffsetExpr, MCConstantExpr::create(row3, context), context),
2683             4);
2684     }
2685   }
2686 
2687   // Emit prolog unwind instructions (in reverse order).
2688   uint8_t numInst = info->Instructions.size();
2689   for (uint8_t c = 0; c < numInst; ++c) {
2690     WinEH::Instruction inst = info->Instructions.back();
2691     info->Instructions.pop_back();
2692     ARMEmitUnwindCode(streamer, inst);
2693   }
2694 
2695   // Emit epilog unwind instructions
2696   for (auto &I : info->EpilogMap) {
2697     auto &EpilogInstrs = I.second.Instructions;
2698     for (const WinEH::Instruction &inst : EpilogInstrs)
2699       ARMEmitUnwindCode(streamer, inst);
2700   }
2701 
2702   int32_t BytesMod = CodeWords * 4 - TotalCodeBytes;
2703   assert(BytesMod >= 0);
2704   for (int i = 0; i < BytesMod; i++)
2705     streamer.emitInt8(0xFB);
2706 
2707   if (info->HandlesExceptions)
2708     streamer.emitValue(
2709         MCSymbolRefExpr::create(info->ExceptionHandler,
2710                                 MCSymbolRefExpr::VK_COFF_IMGREL32, context),
2711         4);
2712 }
2713 
ARM64EmitRuntimeFunction(MCStreamer & streamer,const WinEH::FrameInfo * info)2714 static void ARM64EmitRuntimeFunction(MCStreamer &streamer,
2715                                      const WinEH::FrameInfo *info) {
2716   MCContext &context = streamer.getContext();
2717 
2718   streamer.emitValueToAlignment(Align(4));
2719   for (const auto &S : info->Segments) {
2720     EmitSymbolRefWithOfs(streamer, info->Begin, S.Offset);
2721     if (info->PackedInfo)
2722       streamer.emitInt32(info->PackedInfo);
2723     else
2724       streamer.emitValue(
2725           MCSymbolRefExpr::create(S.Symbol, MCSymbolRefExpr::VK_COFF_IMGREL32,
2726                                   context),
2727           4);
2728   }
2729 }
2730 
2731 
ARMEmitRuntimeFunction(MCStreamer & streamer,const WinEH::FrameInfo * info)2732 static void ARMEmitRuntimeFunction(MCStreamer &streamer,
2733                                    const WinEH::FrameInfo *info) {
2734   MCContext &context = streamer.getContext();
2735 
2736   streamer.emitValueToAlignment(Align(4));
2737   EmitSymbolRefWithOfs(streamer, info->Begin, info->Begin);
2738   if (info->PackedInfo)
2739     streamer.emitInt32(info->PackedInfo);
2740   else
2741     streamer.emitValue(
2742         MCSymbolRefExpr::create(info->Symbol, MCSymbolRefExpr::VK_COFF_IMGREL32,
2743                                 context),
2744         4);
2745 }
2746 
Emit(MCStreamer & Streamer) const2747 void llvm::Win64EH::ARM64UnwindEmitter::Emit(MCStreamer &Streamer) const {
2748   // Emit the unwind info structs first.
2749   for (const auto &CFI : Streamer.getWinFrameInfos()) {
2750     WinEH::FrameInfo *Info = CFI.get();
2751     if (Info->empty())
2752       continue;
2753     MCSection *XData = Streamer.getAssociatedXDataSection(CFI->TextSection);
2754     Streamer.switchSection(XData);
2755     ARM64EmitUnwindInfo(Streamer, Info);
2756   }
2757 
2758   // Now emit RUNTIME_FUNCTION entries.
2759   for (const auto &CFI : Streamer.getWinFrameInfos()) {
2760     WinEH::FrameInfo *Info = CFI.get();
2761     // ARM64EmitUnwindInfo above clears the info struct, so we can't check
2762     // empty here. But if a Symbol is set, we should create the corresponding
2763     // pdata entry.
2764     if (!Info->Symbol)
2765       continue;
2766     MCSection *PData = Streamer.getAssociatedPDataSection(CFI->TextSection);
2767     Streamer.switchSection(PData);
2768     ARM64EmitRuntimeFunction(Streamer, Info);
2769   }
2770 }
2771 
EmitUnwindInfo(MCStreamer & Streamer,WinEH::FrameInfo * info,bool HandlerData) const2772 void llvm::Win64EH::ARM64UnwindEmitter::EmitUnwindInfo(MCStreamer &Streamer,
2773                                                        WinEH::FrameInfo *info,
2774                                                        bool HandlerData) const {
2775   // Called if there's an .seh_handlerdata directive before the end of the
2776   // function. This forces writing the xdata record already here - and
2777   // in this case, the function isn't actually ended already, but the xdata
2778   // record needs to know the function length. In these cases, if the funclet
2779   // end hasn't been marked yet, the xdata function length won't cover the
2780   // whole function, only up to this point.
2781   if (!info->FuncletOrFuncEnd) {
2782     Streamer.switchSection(info->TextSection);
2783     info->FuncletOrFuncEnd = Streamer.emitCFILabel();
2784   }
2785   // Switch sections (the static function above is meant to be called from
2786   // here and from Emit().
2787   MCSection *XData = Streamer.getAssociatedXDataSection(info->TextSection);
2788   Streamer.switchSection(XData);
2789   ARM64EmitUnwindInfo(Streamer, info, /* TryPacked = */ !HandlerData);
2790 }
2791 
Emit(MCStreamer & Streamer) const2792 void llvm::Win64EH::ARMUnwindEmitter::Emit(MCStreamer &Streamer) const {
2793   // Emit the unwind info structs first.
2794   for (const auto &CFI : Streamer.getWinFrameInfos()) {
2795     WinEH::FrameInfo *Info = CFI.get();
2796     if (Info->empty())
2797       continue;
2798     MCSection *XData = Streamer.getAssociatedXDataSection(CFI->TextSection);
2799     Streamer.switchSection(XData);
2800     ARMEmitUnwindInfo(Streamer, Info);
2801   }
2802 
2803   // Now emit RUNTIME_FUNCTION entries.
2804   for (const auto &CFI : Streamer.getWinFrameInfos()) {
2805     WinEH::FrameInfo *Info = CFI.get();
2806     // ARMEmitUnwindInfo above clears the info struct, so we can't check
2807     // empty here. But if a Symbol is set, we should create the corresponding
2808     // pdata entry.
2809     if (!Info->Symbol)
2810       continue;
2811     MCSection *PData = Streamer.getAssociatedPDataSection(CFI->TextSection);
2812     Streamer.switchSection(PData);
2813     ARMEmitRuntimeFunction(Streamer, Info);
2814   }
2815 }
2816 
EmitUnwindInfo(MCStreamer & Streamer,WinEH::FrameInfo * info,bool HandlerData) const2817 void llvm::Win64EH::ARMUnwindEmitter::EmitUnwindInfo(MCStreamer &Streamer,
2818                                                      WinEH::FrameInfo *info,
2819                                                      bool HandlerData) const {
2820   // Called if there's an .seh_handlerdata directive before the end of the
2821   // function. This forces writing the xdata record already here - and
2822   // in this case, the function isn't actually ended already, but the xdata
2823   // record needs to know the function length. In these cases, if the funclet
2824   // end hasn't been marked yet, the xdata function length won't cover the
2825   // whole function, only up to this point.
2826   if (!info->FuncletOrFuncEnd) {
2827     Streamer.switchSection(info->TextSection);
2828     info->FuncletOrFuncEnd = Streamer.emitCFILabel();
2829   }
2830   // Switch sections (the static function above is meant to be called from
2831   // here and from Emit().
2832   MCSection *XData = Streamer.getAssociatedXDataSection(info->TextSection);
2833   Streamer.switchSection(XData);
2834   ARMEmitUnwindInfo(Streamer, info, /* TryPacked = */ !HandlerData);
2835 }
2836