Generic Virtual calls for CoreRT
[platform/upstream/coreclr.git] / src / jit / unwindamd64.cpp
1 // Licensed to the .NET Foundation under one or more agreements.
2 // The .NET Foundation licenses this file to you under the MIT license.
3 // See the LICENSE file in the project root for more information.
4
5 /*XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
6 XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
7 XX                                                                           XX
8 XX                              UnwindInfo                                   XX
9 XX                                                                           XX
10 XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
11 XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
12 */
13
14 #include "jitpch.h"
15 #ifdef _MSC_VER
16 #pragma hdrstop
17 #endif
18
19 #if defined(_TARGET_AMD64_)
20 #ifdef UNIX_AMD64_ABI
21 int Compiler::mapRegNumToDwarfReg(regNumber reg)
22 {
23     int dwarfReg = DWARF_REG_ILLEGAL;
24
25     switch (reg)
26     {
27         case REG_RAX:
28             dwarfReg = 0;
29             break;
30         case REG_RCX:
31             dwarfReg = 2;
32             break;
33         case REG_RDX:
34             dwarfReg = 1;
35             break;
36         case REG_RBX:
37             dwarfReg = 3;
38             break;
39         case REG_RSP:
40             dwarfReg = 7;
41             break;
42         case REG_RBP:
43             dwarfReg = 6;
44             break;
45         case REG_RSI:
46             dwarfReg = 4;
47             break;
48         case REG_RDI:
49             dwarfReg = 5;
50             break;
51         case REG_R8:
52             dwarfReg = 8;
53             break;
54         case REG_R9:
55             dwarfReg = 9;
56             break;
57         case REG_R10:
58             dwarfReg = 10;
59             break;
60         case REG_R11:
61             dwarfReg = 11;
62             break;
63         case REG_R12:
64             dwarfReg = 12;
65             break;
66         case REG_R13:
67             dwarfReg = 13;
68             break;
69         case REG_R14:
70             dwarfReg = 14;
71             break;
72         case REG_R15:
73             dwarfReg = 15;
74             break;
75         case REG_XMM0:
76             dwarfReg = 17;
77             break;
78         case REG_XMM1:
79             dwarfReg = 18;
80             break;
81         case REG_XMM2:
82             dwarfReg = 19;
83             break;
84         case REG_XMM3:
85             dwarfReg = 20;
86             break;
87         case REG_XMM4:
88             dwarfReg = 21;
89             break;
90         case REG_XMM5:
91             dwarfReg = 22;
92             break;
93         case REG_XMM6:
94             dwarfReg = 23;
95             break;
96         case REG_XMM7:
97             dwarfReg = 24;
98             break;
99         case REG_XMM8:
100             dwarfReg = 25;
101             break;
102         case REG_XMM9:
103             dwarfReg = 26;
104             break;
105         case REG_XMM10:
106             dwarfReg = 27;
107             break;
108         case REG_XMM11:
109             dwarfReg = 28;
110             break;
111         case REG_XMM12:
112             dwarfReg = 29;
113             break;
114         case REG_XMM13:
115             dwarfReg = 30;
116             break;
117         case REG_XMM14:
118             dwarfReg = 31;
119             break;
120         case REG_XMM15:
121             dwarfReg = 32;
122             break;
123         default:
124             noway_assert(!"unexpected REG_NUM");
125     }
126
127     return dwarfReg;
128 }
129
130 void Compiler::createCfiCode(FuncInfoDsc* func, UCHAR codeOffset, UCHAR cfiOpcode, USHORT dwarfReg, INT offset)
131 {
132     CFI_CODE cfiEntry(codeOffset, cfiOpcode, dwarfReg, offset);
133     func->cfiCodes->push_back(cfiEntry);
134 }
135 #endif // UNIX_AMD64_ABI
136
137 //------------------------------------------------------------------------
138 // Compiler::unwindGetCurrentOffset: Calculate the current byte offset of the
139 // prolog being generated.
140 //
141 // Arguments:
142 //    func - The main function or funclet of interest.
143 //
144 // Return Value:
145 //    The byte offset of the prolog currently being generated.
146 //
147 UNATIVE_OFFSET Compiler::unwindGetCurrentOffset(FuncInfoDsc* func)
148 {
149     assert(compGeneratingProlog);
150     UNATIVE_OFFSET offset;
151     if (func->funKind == FUNC_ROOT)
152     {
153         offset = genEmitter->emitGetPrologOffsetEstimate();
154     }
155     else
156     {
157         assert(func->startLoc != nullptr);
158         offset = func->startLoc->GetFuncletPrologOffset(genEmitter);
159     }
160
161     return offset;
162 }
163
164 //------------------------------------------------------------------------
165 // Compiler::unwindBegProlog: Initialize the unwind info data structures.
166 // Called at the beginning of main function or funclet prolog generation.
167 //
168 void Compiler::unwindBegProlog()
169 {
170 #ifdef UNIX_AMD64_ABI
171     if (generateCFIUnwindCodes())
172     {
173         unwindBegPrologCFI();
174     }
175     else
176 #endif // UNIX_AMD64_ABI
177     {
178         unwindBegPrologWindows();
179     }
180 }
181
182 void Compiler::unwindBegPrologWindows()
183 {
184     assert(compGeneratingProlog);
185
186     FuncInfoDsc* func = funCurrentFunc();
187
188     // There is only one prolog for a function/funclet, and it comes first. So now is
189     // a good time to initialize all the unwind data structures.
190
191     unwindGetFuncLocations(func, true, &func->startLoc, &func->endLoc);
192
193     if (fgFirstColdBlock != nullptr)
194     {
195         unwindGetFuncLocations(func, false, &func->coldStartLoc, &func->coldEndLoc);
196     }
197
198     func->unwindCodeSlot                  = sizeof(func->unwindCodes);
199     func->unwindHeader.Version            = 1;
200     func->unwindHeader.Flags              = 0;
201     func->unwindHeader.CountOfUnwindCodes = 0;
202     func->unwindHeader.FrameRegister      = 0;
203     func->unwindHeader.FrameOffset        = 0;
204 }
205
206 #ifdef UNIX_AMD64_ABI
207 template <typename T>
208 inline static T* allocate_any(jitstd::allocator<void>& alloc, size_t count = 5)
209 {
210     return jitstd::allocator<T>(alloc).allocate(count);
211 }
212 typedef jitstd::vector<CFI_CODE> CFICodeVector;
213
214 void Compiler::unwindBegPrologCFI()
215 {
216     assert(compGeneratingProlog);
217
218     FuncInfoDsc* func = funCurrentFunc();
219
220     // There is only one prolog for a function/funclet, and it comes first. So now is
221     // a good time to initialize all the unwind data structures.
222
223     unwindGetFuncLocations(func, true, &func->startLoc, &func->endLoc);
224
225     if (fgFirstColdBlock != nullptr)
226     {
227         unwindGetFuncLocations(func, false, &func->coldStartLoc, &func->coldEndLoc);
228     }
229
230     jitstd::allocator<void> allocator(getAllocator());
231
232     func->cfiCodes = new (allocate_any<CFICodeVector>(allocator), jitstd::placement_t()) CFICodeVector(allocator);
233 }
234 #endif // UNIX_AMD64_ABI
235
236 //------------------------------------------------------------------------
237 // Compiler::unwindEndProlog: Called at the end of main function or funclet
238 // prolog generation to indicate there is no more unwind information for this prolog.
239 //
240 void Compiler::unwindEndProlog()
241 {
242     assert(compGeneratingProlog);
243 }
244
245 //------------------------------------------------------------------------
246 // Compiler::unwindBegEpilog: Called at the beginning of main function or funclet
247 // epilog generation.
248 //
249 void Compiler::unwindBegEpilog()
250 {
251     assert(compGeneratingEpilog);
252 }
253
254 //------------------------------------------------------------------------
255 // Compiler::unwindEndEpilog: Called at the end of main function or funclet
256 // epilog generation.
257 //
258 void Compiler::unwindEndEpilog()
259 {
260     assert(compGeneratingEpilog);
261 }
262
263 //------------------------------------------------------------------------
264 // Compiler::unwindPush: Record a push/save of a register.
265 //
266 // Arguments:
267 //    reg - The register being pushed/saved.
268 //
269 void Compiler::unwindPush(regNumber reg)
270 {
271 #ifdef UNIX_AMD64_ABI
272     if (generateCFIUnwindCodes())
273     {
274         unwindPushCFI(reg);
275     }
276     else
277 #endif // UNIX_AMD64_ABI
278     {
279         unwindPushWindows(reg);
280     }
281 }
282
283 void Compiler::unwindPushWindows(regNumber reg)
284 {
285     assert(compGeneratingProlog);
286
287     FuncInfoDsc* func = funCurrentFunc();
288
289     assert(func->unwindHeader.Version == 1);            // Can't call this before unwindBegProlog
290     assert(func->unwindHeader.CountOfUnwindCodes == 0); // Can't call this after unwindReserve
291     assert(func->unwindCodeSlot > sizeof(UNWIND_CODE));
292     UNWIND_CODE* code     = (UNWIND_CODE*)&func->unwindCodes[func->unwindCodeSlot -= sizeof(UNWIND_CODE)];
293     unsigned int cbProlog = unwindGetCurrentOffset(func);
294     noway_assert((BYTE)cbProlog == cbProlog);
295     code->CodeOffset = (BYTE)cbProlog;
296
297     if ((RBM_CALLEE_SAVED & genRegMask(reg))
298 #if ETW_EBP_FRAMED
299         // In case of ETW_EBP_FRAMED defined the REG_FPBASE (RBP)
300         // is excluded from the callee-save register list.
301         // Make sure the register gets PUSH unwind info in this case,
302         // since it is pushed as a frame register.
303         || (reg == REG_FPBASE)
304 #endif // ETW_EBP_FRAMED
305             )
306     {
307         code->UnwindOp = UWOP_PUSH_NONVOL;
308         code->OpInfo   = (BYTE)reg;
309     }
310     else
311     {
312         // Push of a volatile register is just a small stack allocation
313         code->UnwindOp = UWOP_ALLOC_SMALL;
314         code->OpInfo   = 0;
315     }
316 }
317
318 #ifdef UNIX_AMD64_ABI
319 void Compiler::unwindPushCFI(regNumber reg)
320 {
321     assert(compGeneratingProlog);
322
323     FuncInfoDsc* func = funCurrentFunc();
324
325     unsigned int cbProlog = unwindGetCurrentOffset(func);
326     noway_assert((BYTE)cbProlog == cbProlog);
327
328     createCfiCode(func, cbProlog, CFI_ADJUST_CFA_OFFSET, DWARF_REG_ILLEGAL, 8);
329     if ((RBM_CALLEE_SAVED & genRegMask(reg))
330 #if ETW_EBP_FRAMED
331         // In case of ETW_EBP_FRAMED defined the REG_FPBASE (RBP)
332         // is excluded from the callee-save register list.
333         // Make sure the register gets PUSH unwind info in this case,
334         // since it is pushed as a frame register.
335         || (reg == REG_FPBASE)
336 #endif // ETW_EBP_FRAMED
337             )
338     {
339         createCfiCode(func, cbProlog, CFI_REL_OFFSET, mapRegNumToDwarfReg(reg));
340     }
341 }
342 #endif // UNIX_AMD64_ABI
343
344 //------------------------------------------------------------------------
345 // Compiler::unwindAllocStack: Record a stack frame allocation (sub sp, X).
346 //
347 // Arguments:
348 //    size - The size of the stack frame allocation (the amount subtracted from the stack pointer).
349 //
350 void Compiler::unwindAllocStack(unsigned size)
351 {
352 #ifdef UNIX_AMD64_ABI
353     if (generateCFIUnwindCodes())
354     {
355         unwindAllocStackCFI(size);
356     }
357     else
358 #endif // UNIX_AMD64_ABI
359     {
360         unwindAllocStackWindows(size);
361     }
362 }
363
364 void Compiler::unwindAllocStackWindows(unsigned size)
365 {
366     assert(compGeneratingProlog);
367
368     FuncInfoDsc* func = funCurrentFunc();
369
370     assert(func->unwindHeader.Version == 1);            // Can't call this before unwindBegProlog
371     assert(func->unwindHeader.CountOfUnwindCodes == 0); // Can't call this after unwindReserve
372     assert(size % 8 == 0);                              // Stack size is *always* 8 byte aligned
373     UNWIND_CODE* code;
374     if (size <= 128)
375     {
376         assert(func->unwindCodeSlot > sizeof(UNWIND_CODE));
377         code           = (UNWIND_CODE*)&func->unwindCodes[func->unwindCodeSlot -= sizeof(UNWIND_CODE)];
378         code->UnwindOp = UWOP_ALLOC_SMALL;
379         code->OpInfo   = (size - 8) / 8;
380     }
381     else if (size <= 0x7FFF8)
382     {
383         assert(func->unwindCodeSlot > (sizeof(UNWIND_CODE) + sizeof(USHORT)));
384         USHORT* codedSize = (USHORT*)&func->unwindCodes[func->unwindCodeSlot -= sizeof(USHORT)];
385         *codedSize        = (USHORT)(size / 8);
386         code              = (UNWIND_CODE*)&func->unwindCodes[func->unwindCodeSlot -= sizeof(UNWIND_CODE)];
387         code->UnwindOp    = UWOP_ALLOC_LARGE;
388         code->OpInfo      = 0;
389     }
390     else
391     {
392         assert(func->unwindCodeSlot > (sizeof(UNWIND_CODE) + sizeof(ULONG)));
393         ULONG* codedSize = (ULONG*)&func->unwindCodes[func->unwindCodeSlot -= sizeof(ULONG)];
394         *codedSize       = size;
395         code             = (UNWIND_CODE*)&func->unwindCodes[func->unwindCodeSlot -= sizeof(UNWIND_CODE)];
396         code->UnwindOp   = UWOP_ALLOC_LARGE;
397         code->OpInfo     = 1;
398     }
399     unsigned int cbProlog = unwindGetCurrentOffset(func);
400     noway_assert((BYTE)cbProlog == cbProlog);
401     code->CodeOffset = (BYTE)cbProlog;
402 }
403
404 #ifdef UNIX_AMD64_ABI
405 void Compiler::unwindAllocStackCFI(unsigned size)
406 {
407     assert(compGeneratingProlog);
408
409     FuncInfoDsc* func = funCurrentFunc();
410
411     unsigned int cbProlog = unwindGetCurrentOffset(func);
412     noway_assert((BYTE)cbProlog == cbProlog);
413     createCfiCode(func, cbProlog, CFI_ADJUST_CFA_OFFSET, DWARF_REG_ILLEGAL, size);
414 }
415 #endif // UNIX_AMD64_ABI
416
417 //------------------------------------------------------------------------
418 // Compiler::unwindSetFrameReg: Record a frame register.
419 //
420 // Arguments:
421 //    reg    - The register being set as the frame register.
422 //    offset - The offset from the current stack pointer that the frame pointer will point at.
423 //
424 void Compiler::unwindSetFrameReg(regNumber reg, unsigned offset)
425 {
426 #ifdef UNIX_AMD64_ABI
427     if (generateCFIUnwindCodes())
428     {
429         unwindSetFrameRegCFI(reg, offset);
430     }
431     else
432 #endif // UNIX_AMD64_ABI
433     {
434         unwindSetFrameRegWindows(reg, offset);
435     }
436 }
437
438 void Compiler::unwindSetFrameRegWindows(regNumber reg, unsigned offset)
439 {
440     assert(compGeneratingProlog);
441
442     FuncInfoDsc* func = funCurrentFunc();
443
444     assert(func->unwindHeader.Version == 1);            // Can't call this before unwindBegProlog
445     assert(func->unwindHeader.CountOfUnwindCodes == 0); // Can't call this after unwindReserve
446     unsigned int cbProlog = unwindGetCurrentOffset(func);
447     noway_assert((BYTE)cbProlog == cbProlog);
448
449     func->unwindHeader.FrameRegister = (BYTE)reg;
450
451 #ifdef PLATFORM_UNIX
452     if (offset > 240)
453     {
454         // On Unix only, we have a CLR-only extension to the AMD64 unwind codes: UWOP_SET_FPREG_LARGE.
455         // It has a 32-bit offset (scaled). You must set UNWIND_INFO.FrameOffset to 15. The 32-bit
456         // offset follows in 2 UNWIND_CODE fields.
457
458         assert(func->unwindCodeSlot > (sizeof(UNWIND_CODE) + sizeof(ULONG)));
459         ULONG* codedSize = (ULONG*)&func->unwindCodes[func->unwindCodeSlot -= sizeof(ULONG)];
460         assert(offset % 16 == 0);
461         *codedSize = offset / 16;
462
463         UNWIND_CODE* code              = (UNWIND_CODE*)&func->unwindCodes[func->unwindCodeSlot -= sizeof(UNWIND_CODE)];
464         code->CodeOffset               = (BYTE)cbProlog;
465         code->OpInfo                   = 0;
466         code->UnwindOp                 = UWOP_SET_FPREG_LARGE;
467         func->unwindHeader.FrameOffset = 15;
468     }
469     else
470 #endif // PLATFORM_UNIX
471     {
472         assert(func->unwindCodeSlot > sizeof(UNWIND_CODE));
473         UNWIND_CODE* code = (UNWIND_CODE*)&func->unwindCodes[func->unwindCodeSlot -= sizeof(UNWIND_CODE)];
474         code->CodeOffset  = (BYTE)cbProlog;
475         code->OpInfo      = 0;
476         code->UnwindOp    = UWOP_SET_FPREG;
477         assert(offset <= 240);
478         assert(offset % 16 == 0);
479         func->unwindHeader.FrameOffset = offset / 16;
480     }
481 }
482
483 #ifdef UNIX_AMD64_ABI
484 //------------------------------------------------------------------------
485 // Compiler::unwindSetFrameRegCFI: Record a cfi info for a frame register set.
486 //
487 // Arguments:
488 //    reg    - The register being set as the frame register.
489 //    offset - The offset from the current stack pointer that the frame pointer will point at.
490 //
491 void Compiler::unwindSetFrameRegCFI(regNumber reg, unsigned offset)
492 {
493     assert(compGeneratingProlog);
494     FuncInfoDsc* func = funCurrentFunc();
495
496     unsigned int cbProlog = unwindGetCurrentOffset(func);
497     noway_assert((BYTE)cbProlog == cbProlog);
498
499     createCfiCode(func, cbProlog, CFI_DEF_CFA_REGISTER, mapRegNumToDwarfReg(reg));
500     if (offset != 0)
501     {
502         // before: cfa = rsp + old_cfa_offset;
503         //         rbp = rsp + offset;
504         // after: cfa should be based on rbp, but points to the old address:
505         //         rsp + old_cfa_offset == rbp + old_cfa_offset + adjust;
506         // adjust = -offset;
507         int adjust = -(int)offset;
508         createCfiCode(func, cbProlog, CFI_ADJUST_CFA_OFFSET, DWARF_REG_ILLEGAL, adjust);
509     }
510 }
511 #endif // UNIX_AMD64_ABI
512
513 //------------------------------------------------------------------------
514 // Compiler::unwindSaveReg: Record a register save.
515 //
516 // Arguments:
517 //    reg    - The register being saved.
518 //    offset - The offset from the current stack pointer where the register is being saved.
519 //
520 void Compiler::unwindSaveReg(regNumber reg, unsigned offset)
521 {
522 #ifdef UNIX_AMD64_ABI
523     if (generateCFIUnwindCodes())
524     {
525         unwindSaveRegCFI(reg, offset);
526     }
527     else
528 #endif // UNIX_AMD64_ABI
529     {
530         unwindSaveRegWindows(reg, offset);
531     }
532 }
533
534 void Compiler::unwindSaveRegWindows(regNumber reg, unsigned offset)
535 {
536     assert(compGeneratingProlog);
537
538     FuncInfoDsc* func = funCurrentFunc();
539
540     assert(func->unwindHeader.Version == 1);            // Can't call this before unwindBegProlog
541     assert(func->unwindHeader.CountOfUnwindCodes == 0); // Can't call this after unwindReserve
542     if (RBM_CALLEE_SAVED & genRegMask(reg))
543     {
544         UNWIND_CODE* code;
545         if (offset < 0x80000)
546         {
547             assert(func->unwindCodeSlot > (sizeof(UNWIND_CODE) + sizeof(USHORT)));
548             USHORT* codedSize = (USHORT*)&func->unwindCodes[func->unwindCodeSlot -= sizeof(USHORT)];
549             code              = (UNWIND_CODE*)&func->unwindCodes[func->unwindCodeSlot -= sizeof(UNWIND_CODE)];
550
551             // As per AMD64 ABI, if saving entire xmm reg, then offset need to be scaled by 16.
552             if (genIsValidFloatReg(reg))
553             {
554                 *codedSize     = (USHORT)(offset / 16);
555                 code->UnwindOp = UWOP_SAVE_XMM128;
556             }
557             else
558             {
559                 *codedSize     = (USHORT)(offset / 8);
560                 code->UnwindOp = UWOP_SAVE_NONVOL;
561             }
562         }
563         else
564         {
565             assert(func->unwindCodeSlot > (sizeof(UNWIND_CODE) + sizeof(ULONG)));
566             ULONG* codedSize = (ULONG*)&func->unwindCodes[func->unwindCodeSlot -= sizeof(ULONG)];
567             *codedSize       = offset;
568             code             = (UNWIND_CODE*)&func->unwindCodes[func->unwindCodeSlot -= sizeof(UNWIND_CODE)];
569             code->UnwindOp   = (genIsValidFloatReg(reg)) ? UWOP_SAVE_XMM128_FAR : UWOP_SAVE_NONVOL_FAR;
570         }
571         code->OpInfo          = (BYTE)reg;
572         unsigned int cbProlog = unwindGetCurrentOffset(func);
573         noway_assert((BYTE)cbProlog == cbProlog);
574         code->CodeOffset = (BYTE)cbProlog;
575     }
576 }
577
578 #ifdef UNIX_AMD64_ABI
579 void Compiler::unwindSaveRegCFI(regNumber reg, unsigned offset)
580 {
581     assert(compGeneratingProlog);
582
583     if (RBM_CALLEE_SAVED & genRegMask(reg))
584     {
585         FuncInfoDsc* func = funCurrentFunc();
586
587         unsigned int cbProlog = unwindGetCurrentOffset(func);
588         noway_assert((BYTE)cbProlog == cbProlog);
589         createCfiCode(func, cbProlog, CFI_REL_OFFSET, mapRegNumToDwarfReg(reg), offset);
590     }
591 }
592 #endif // UNIX_AMD64_ABI
593
594 #ifdef DEBUG
595
596 //------------------------------------------------------------------------
597 // DumpUnwindInfo: Dump the unwind data.
598 //
599 // Arguments:
600 //    isHotCode   - true if this unwind data is for the hot section, false otherwise.
601 //    startOffset - byte offset of the code start that this unwind data represents.
602 //    endOffset   - byte offset of the code end   that this unwind data represents.
603 //    pHeader     - pointer to the unwind data blob.
604 //
605 void DumpUnwindInfo(bool                     isHotCode,
606                     UNATIVE_OFFSET           startOffset,
607                     UNATIVE_OFFSET           endOffset,
608                     const UNWIND_INFO* const pHeader)
609 {
610     printf("Unwind Info%s:\n", isHotCode ? "" : " COLD");
611     printf("  >> Start offset   : 0x%06x (not in unwind data)\n", dspOffset(startOffset));
612     printf("  >>   End offset   : 0x%06x (not in unwind data)\n", dspOffset(endOffset));
613
614     if (pHeader == nullptr)
615     {
616         // Cold AMD64 code doesn't have unwind info; the VM creates chained unwind info.
617         assert(!isHotCode);
618         return;
619     }
620
621     printf("  Version           : %u\n", pHeader->Version);
622     printf("  Flags             : 0x%02x", pHeader->Flags);
623     if (pHeader->Flags)
624     {
625         const UCHAR flags = pHeader->Flags;
626         printf(" (");
627         if (flags & UNW_FLAG_EHANDLER)
628         {
629             printf(" UNW_FLAG_EHANDLER");
630         }
631         if (flags & UNW_FLAG_UHANDLER)
632         {
633             printf(" UNW_FLAG_UHANDLER");
634         }
635         if (flags & UNW_FLAG_CHAININFO)
636         {
637             printf(" UNW_FLAG_CHAININFO");
638         }
639         printf(")");
640     }
641     printf("\n");
642     printf("  SizeOfProlog      : 0x%02X\n", pHeader->SizeOfProlog);
643     printf("  CountOfUnwindCodes: %u\n", pHeader->CountOfUnwindCodes);
644     printf("  FrameRegister     : %s (%u)\n",
645            (pHeader->FrameRegister == 0) ? "none" : getRegName(pHeader->FrameRegister),
646            pHeader->FrameRegister); // RAX (0) is not allowed as a frame register
647     if (pHeader->FrameRegister == 0)
648     {
649         printf("  FrameOffset       : N/A (no FrameRegister) (Value=%u)\n", pHeader->FrameOffset);
650     }
651     else
652     {
653         printf("  FrameOffset       : %u * 16 = 0x%02X\n", pHeader->FrameOffset, pHeader->FrameOffset * 16);
654     }
655     printf("  UnwindCodes       :\n");
656
657     for (unsigned i = 0; i < pHeader->CountOfUnwindCodes; i++)
658     {
659         unsigned                 offset;
660         const UNWIND_CODE* const pCode = &(pHeader->UnwindCode[i]);
661         switch (pCode->UnwindOp)
662         {
663             case UWOP_PUSH_NONVOL:
664                 printf("    CodeOffset: 0x%02X UnwindOp: UWOP_PUSH_NONVOL (%u)     OpInfo: %s (%u)\n",
665                        pCode->CodeOffset, pCode->UnwindOp, getRegName(pCode->OpInfo), pCode->OpInfo);
666                 break;
667
668             case UWOP_ALLOC_LARGE:
669                 printf("    CodeOffset: 0x%02X UnwindOp: UWOP_ALLOC_LARGE (%u)     OpInfo: %u - ", pCode->CodeOffset,
670                        pCode->UnwindOp, pCode->OpInfo);
671                 if (pCode->OpInfo == 0)
672                 {
673                     i++;
674                     printf("Scaled small  \n      Size: %u * 8 = %u = 0x%05X\n", pHeader->UnwindCode[i].FrameOffset,
675                            pHeader->UnwindCode[i].FrameOffset * 8, pHeader->UnwindCode[i].FrameOffset * 8);
676                 }
677                 else if (pCode->OpInfo == 1)
678                 {
679                     i++;
680                     printf("Unscaled large\n      Size: %u = 0x%08X\n\n", *(ULONG*)&(pHeader->UnwindCode[i]),
681                            *(ULONG*)&(pHeader->UnwindCode[i]));
682                     i++;
683                 }
684                 else
685                 {
686                     printf("Unknown\n");
687                 }
688                 break;
689
690             case UWOP_ALLOC_SMALL:
691                 printf("    CodeOffset: 0x%02X UnwindOp: UWOP_ALLOC_SMALL (%u)     OpInfo: %u * 8 + 8 = %u = 0x%02X\n",
692                        pCode->CodeOffset, pCode->UnwindOp, pCode->OpInfo, pCode->OpInfo * 8 + 8, pCode->OpInfo * 8 + 8);
693                 break;
694
695             case UWOP_SET_FPREG:
696                 printf("    CodeOffset: 0x%02X UnwindOp: UWOP_SET_FPREG (%u)       OpInfo: Unused (%u)\n",
697                        pCode->CodeOffset, pCode->UnwindOp, pCode->OpInfo); // This should be zero
698                 break;
699
700 #ifdef PLATFORM_UNIX
701
702             case UWOP_SET_FPREG_LARGE:
703                 printf("    CodeOffset: 0x%02X UnwindOp: UWOP_SET_FPREG_LARGE (%u) OpInfo: Unused (%u)\n",
704                        pCode->CodeOffset, pCode->UnwindOp, pCode->OpInfo); // This should be zero
705                 i++;
706                 offset = *(ULONG*)&(pHeader->UnwindCode[i]);
707                 i++;
708                 printf("      Scaled Offset: %u * 16 = %u = 0x%08X\n", offset, offset * 16, offset * 16);
709                 if ((offset & 0xF0000000) != 0)
710                 {
711                     printf("      Illegal unscaled offset: too large\n");
712                 }
713                 break;
714
715 #endif // PLATFORM_UNIX
716
717             case UWOP_SAVE_NONVOL:
718                 printf("    CodeOffset: 0x%02X UnwindOp: UWOP_SAVE_NONVOL (%u)     OpInfo: %s (%u)\n",
719                        pCode->CodeOffset, pCode->UnwindOp, getRegName(pCode->OpInfo), pCode->OpInfo);
720                 i++;
721                 printf("      Scaled Small Offset: %u * 8 = %u = 0x%05X\n", pHeader->UnwindCode[i].FrameOffset,
722                        pHeader->UnwindCode[i].FrameOffset * 8, pHeader->UnwindCode[i].FrameOffset * 8);
723                 break;
724
725             case UWOP_SAVE_NONVOL_FAR:
726                 printf("    CodeOffset: 0x%02X UnwindOp: UWOP_SAVE_NONVOL_FAR (%u) OpInfo: %s (%u)\n",
727                        pCode->CodeOffset, pCode->UnwindOp, getRegName(pCode->OpInfo), pCode->OpInfo);
728                 i++;
729                 printf("      Unscaled Large Offset: 0x%08X\n\n", *(ULONG*)&(pHeader->UnwindCode[i]));
730                 i++;
731                 break;
732
733             case UWOP_SAVE_XMM128:
734                 printf("    CodeOffset: 0x%02X UnwindOp: UWOP_SAVE_XMM128 (%u)     OpInfo: XMM%u (%u)\n",
735                        pCode->CodeOffset, pCode->UnwindOp, pCode->OpInfo, pCode->OpInfo);
736                 i++;
737                 printf("      Scaled Small Offset: %u * 16 = %u = 0x%05X\n", pHeader->UnwindCode[i].FrameOffset,
738                        pHeader->UnwindCode[i].FrameOffset * 16, pHeader->UnwindCode[i].FrameOffset * 16);
739                 break;
740
741             case UWOP_SAVE_XMM128_FAR:
742                 printf("    CodeOffset: 0x%02X UnwindOp: UWOP_SAVE_XMM128_FAR (%u) OpInfo: XMM%u (%u)\n",
743                        pCode->CodeOffset, pCode->UnwindOp, pCode->OpInfo, pCode->OpInfo);
744                 i++;
745                 printf("      Unscaled Large Offset: 0x%08X\n\n", *(ULONG*)&(pHeader->UnwindCode[i]));
746                 i++;
747                 break;
748
749             case UWOP_EPILOG:
750             case UWOP_SPARE_CODE:
751             case UWOP_PUSH_MACHFRAME:
752             default:
753                 printf("    Unrecognized UNWIND_CODE: 0x%04X\n", *(USHORT*)pCode);
754                 break;
755         }
756     }
757 }
758
759 #ifdef UNIX_AMD64_ABI
760 //------------------------------------------------------------------------
761 // DumpCfiInfo: Dump the Cfi data.
762 //
763 // Arguments:
764 //    isHotCode   - true if this cfi data is for the hot section, false otherwise.
765 //    startOffset - byte offset of the code start that this cfi data represents.
766 //    endOffset   - byte offset of the code end   that this cfi data represents.
767 //    pcFiCode    - pointer to the cfi data blob.
768 //
769 void DumpCfiInfo(bool                  isHotCode,
770                  UNATIVE_OFFSET        startOffset,
771                  UNATIVE_OFFSET        endOffset,
772                  DWORD                 cfiCodeBytes,
773                  const CFI_CODE* const pCfiCode)
774 {
775     printf("Cfi Info%s:\n", isHotCode ? "" : " COLD");
776     printf("  >> Start offset   : 0x%06x \n", dspOffset(startOffset));
777     printf("  >>   End offset   : 0x%06x \n", dspOffset(endOffset));
778
779     for (int i = 0; i < cfiCodeBytes / sizeof(CFI_CODE); i++)
780     {
781         const CFI_CODE* const pCode = &(pCfiCode[i]);
782
783         UCHAR codeOffset = pCode->CodeOffset;
784         SHORT dwarfReg   = pCode->DwarfReg;
785         INT   offset     = pCode->Offset;
786
787         switch (pCode->CfiOpCode)
788         {
789             case CFI_REL_OFFSET:
790                 printf("    CodeOffset: 0x%02X Op: RelOffset DwarfReg:0x%x Offset:0x%X\n", codeOffset, dwarfReg,
791                        offset);
792                 break;
793             case CFI_DEF_CFA_REGISTER:
794                 assert(offset == 0);
795                 printf("    CodeOffset: 0x%02X Op: DefCfaRegister DwarfReg:0x%X\n", codeOffset, dwarfReg);
796                 break;
797             case CFI_ADJUST_CFA_OFFSET:
798                 assert(dwarfReg == DWARF_REG_ILLEGAL);
799                 printf("    CodeOffset: 0x%02X Op: AdjustCfaOffset Offset:0x%X\n", codeOffset, offset);
800                 break;
801             default:
802                 printf("    Unrecognized CFI_CODE: 0x%IX\n", *(UINT64*)pCode);
803                 break;
804         }
805     }
806 }
807 #endif // UNIX_AMD64_ABI
808 #endif // DEBUG
809
810 //------------------------------------------------------------------------
811 // Compiler::unwindReserve: Ask the VM to reserve space for the unwind information
812 // for the function and all its funclets. Called once, just before asking the VM
813 // for memory and emitting the generated code. Calls unwindReserveFunc() to handle
814 // the main function and each of the funclets, in turn.
815 //
816 void Compiler::unwindReserve()
817 {
818     assert(!compGeneratingProlog);
819     assert(!compGeneratingEpilog);
820
821     assert(compFuncInfoCount > 0);
822     for (unsigned funcIdx = 0; funcIdx < compFuncInfoCount; funcIdx++)
823     {
824         unwindReserveFunc(funGetFunc(funcIdx));
825     }
826 }
827
828 //------------------------------------------------------------------------
829 // Compiler::unwindReserveFunc: Reserve the unwind information from the VM for a
830 // given main function or funclet.
831 //
832 // Arguments:
833 //    func - The main function or funclet to reserve unwind info for.
834 //
835 void Compiler::unwindReserveFunc(FuncInfoDsc* func)
836 {
837     unwindReserveFuncHelper(func, true);
838
839     if (fgFirstColdBlock != nullptr)
840     {
841         unwindReserveFuncHelper(func, false);
842     }
843 }
844
845 //------------------------------------------------------------------------
846 // Compiler::unwindReserveFuncHelper: Reserve the unwind information from the VM for a
847 // given main function or funclet, for either the hot or the cold section.
848 //
849 // Arguments:
850 //    func      - The main function or funclet to reserve unwind info for.
851 //    isHotCode - 'true' to reserve the hot section, 'false' to reserve the cold section.
852 //
853 void Compiler::unwindReserveFuncHelper(FuncInfoDsc* func, bool isHotCode)
854 {
855     DWORD unwindCodeBytes = 0;
856     if (isHotCode)
857     {
858 #ifdef UNIX_AMD64_ABI
859         if (generateCFIUnwindCodes())
860         {
861             unwindCodeBytes = func->cfiCodes->size() * sizeof(CFI_CODE);
862         }
863         else
864 #endif // UNIX_AMD64_ABI
865         {
866             assert(func->unwindHeader.Version == 1);            // Can't call this before unwindBegProlog
867             assert(func->unwindHeader.CountOfUnwindCodes == 0); // Only call this once per prolog
868
869             // Set the size of the prolog to be the last encoded action
870             if (func->unwindCodeSlot < sizeof(func->unwindCodes))
871             {
872                 UNWIND_CODE* code               = (UNWIND_CODE*)&func->unwindCodes[func->unwindCodeSlot];
873                 func->unwindHeader.SizeOfProlog = code->CodeOffset;
874             }
875             else
876             {
877                 func->unwindHeader.SizeOfProlog = 0;
878             }
879             func->unwindHeader.CountOfUnwindCodes =
880                 (BYTE)((sizeof(func->unwindCodes) - func->unwindCodeSlot) / sizeof(UNWIND_CODE));
881
882             // Prepend the unwindHeader onto the unwind codes
883             assert(func->unwindCodeSlot >= offsetof(UNWIND_INFO, UnwindCode));
884
885             func->unwindCodeSlot -= offsetof(UNWIND_INFO, UnwindCode);
886             UNWIND_INFO* pHeader = (UNWIND_INFO*)&func->unwindCodes[func->unwindCodeSlot];
887             memcpy(pHeader, &func->unwindHeader, offsetof(UNWIND_INFO, UnwindCode));
888
889             unwindCodeBytes = sizeof(func->unwindCodes) - func->unwindCodeSlot;
890         }
891     }
892
893     BOOL isFunclet  = (func->funKind != FUNC_ROOT);
894     BOOL isColdCode = isHotCode ? FALSE : TRUE;
895
896     eeReserveUnwindInfo(isFunclet, isColdCode, unwindCodeBytes);
897 }
898
899 //------------------------------------------------------------------------
900 // Compiler::unwindEmit: Report all the unwind information to the VM.
901 //
902 // Arguments:
903 //    pHotCode  - Pointer to the beginning of the memory with the function and funclet hot  code.
904 //    pColdCode - Pointer to the beginning of the memory with the function and funclet cold code.
905 //
906 void Compiler::unwindEmit(void* pHotCode, void* pColdCode)
907 {
908     assert(!compGeneratingProlog);
909     assert(!compGeneratingEpilog);
910
911     assert(compFuncInfoCount > 0);
912     for (unsigned funcIdx = 0; funcIdx < compFuncInfoCount; funcIdx++)
913     {
914         unwindEmitFunc(funGetFunc(funcIdx), pHotCode, pColdCode);
915     }
916 }
917
918 //------------------------------------------------------------------------
919 // Compiler::unwindEmitFuncHelper: Report the unwind information to the VM for a
920 // given main function or funclet, for either the hot or cold section.
921 //
922 // Arguments:
923 //    func      - The main function or funclet to reserve unwind info for.
924 //    pHotCode  - Pointer to the beginning of the memory with the function and funclet hot  code.
925 //    pColdCode - Pointer to the beginning of the memory with the function and funclet cold code.
926 //                Ignored if 'isHotCode' is true.
927 //    isHotCode - 'true' to report the hot section, 'false' to report the cold section.
928 //
929 void Compiler::unwindEmitFuncHelper(FuncInfoDsc* func, void* pHotCode, void* pColdCode, bool isHotCode)
930 {
931     UNATIVE_OFFSET startOffset;
932     UNATIVE_OFFSET endOffset;
933     DWORD          unwindCodeBytes = 0;
934     BYTE*          pUnwindBlock    = nullptr;
935
936     if (isHotCode)
937     {
938         if (func->startLoc == nullptr)
939         {
940             startOffset = 0;
941         }
942         else
943         {
944             startOffset = func->startLoc->CodeOffset(genEmitter);
945         }
946
947         if (func->endLoc == nullptr)
948         {
949             endOffset = info.compNativeCodeSize;
950         }
951         else
952         {
953             endOffset = func->endLoc->CodeOffset(genEmitter);
954         }
955
956 #ifdef UNIX_AMD64_ABI
957         if (generateCFIUnwindCodes())
958         {
959             int size = func->cfiCodes->size();
960             if (size > 0)
961             {
962                 unwindCodeBytes = size * sizeof(CFI_CODE);
963                 pUnwindBlock    = (BYTE*)&(*func->cfiCodes)[0];
964             }
965         }
966         else
967 #endif // UNIX_AMD64_ABI
968         {
969             unwindCodeBytes = sizeof(func->unwindCodes) - func->unwindCodeSlot;
970
971 #ifdef DEBUG
972             UNWIND_INFO* pUnwindInfo = (UNWIND_INFO*)(&func->unwindCodes[func->unwindCodeSlot]);
973             DWORD        unwindCodeBytesSpecified =
974                 offsetof(UNWIND_INFO, UnwindCode) +
975                 pUnwindInfo->CountOfUnwindCodes * sizeof(UNWIND_CODE); // This is what the unwind codes themselves say;
976                                                                        // it better match what we tell the VM.
977             assert(unwindCodeBytes == unwindCodeBytesSpecified);
978 #endif // DEBUG
979
980             pUnwindBlock = &func->unwindCodes[func->unwindCodeSlot];
981         }
982     }
983     else
984     {
985         assert(fgFirstColdBlock != nullptr);
986         assert(func->funKind == FUNC_ROOT); // No splitting of funclets.
987
988         if (func->coldStartLoc == nullptr)
989         {
990             startOffset = 0;
991         }
992         else
993         {
994             startOffset = func->coldStartLoc->CodeOffset(genEmitter);
995         }
996
997         if (func->coldEndLoc == nullptr)
998         {
999             endOffset = info.compNativeCodeSize;
1000         }
1001         else
1002         {
1003             endOffset = func->coldEndLoc->CodeOffset(genEmitter);
1004         }
1005     }
1006
1007 #ifdef DEBUG
1008     if (opts.dspUnwind)
1009     {
1010 #ifdef UNIX_AMD64_ABI
1011         if (generateCFIUnwindCodes())
1012         {
1013             DumpCfiInfo(isHotCode, startOffset, endOffset, unwindCodeBytes, (const CFI_CODE* const)pUnwindBlock);
1014         }
1015         else
1016 #endif // UNIX_AMD64_ABI
1017         {
1018             DumpUnwindInfo(isHotCode, startOffset, endOffset, (const UNWIND_INFO* const)pUnwindBlock);
1019         }
1020     }
1021 #endif // DEBUG
1022
1023     // Adjust for cold or hot code:
1024     // 1. The VM doesn't want the cold code pointer unless this is cold code.
1025     // 2. The startOffset and endOffset need to be from the base of the hot section for hot code
1026     //    and from the base of the cold section for cold code
1027
1028     if (isHotCode)
1029     {
1030         assert(endOffset <= info.compTotalHotCodeSize);
1031         pColdCode = nullptr;
1032     }
1033     else
1034     {
1035         assert(startOffset >= info.compTotalHotCodeSize);
1036         startOffset -= info.compTotalHotCodeSize;
1037         endOffset -= info.compTotalHotCodeSize;
1038     }
1039
1040     eeAllocUnwindInfo((BYTE*)pHotCode, (BYTE*)pColdCode, startOffset, endOffset, unwindCodeBytes, pUnwindBlock,
1041                       (CorJitFuncKind)func->funKind);
1042 }
1043
1044 //------------------------------------------------------------------------
1045 // Compiler::unwindEmitFunc: Report the unwind information to the VM for a
1046 // given main function or funclet. Reports the hot section, then the cold
1047 // section if necessary.
1048 //
1049 // Arguments:
1050 //    func      - The main function or funclet to reserve unwind info for.
1051 //    pHotCode  - Pointer to the beginning of the memory with the function and funclet hot  code.
1052 //    pColdCode - Pointer to the beginning of the memory with the function and funclet cold code.
1053 //
1054 void Compiler::unwindEmitFunc(FuncInfoDsc* func, void* pHotCode, void* pColdCode)
1055 {
1056     // Verify that the JIT enum is in sync with the JIT-EE interface enum
1057     static_assert_no_msg(FUNC_ROOT == (FuncKind)CORJIT_FUNC_ROOT);
1058     static_assert_no_msg(FUNC_HANDLER == (FuncKind)CORJIT_FUNC_HANDLER);
1059     static_assert_no_msg(FUNC_FILTER == (FuncKind)CORJIT_FUNC_FILTER);
1060
1061     unwindEmitFuncHelper(func, pHotCode, pColdCode, true);
1062
1063     if (pColdCode != nullptr)
1064     {
1065         unwindEmitFuncHelper(func, pHotCode, pColdCode, false);
1066     }
1067 }
1068
1069 #endif // _TARGET_AMD64_