Fix reading Time zone rules using Julian days (#17672)
[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 #endif // UNIX_AMD64_ABI
131
132 //------------------------------------------------------------------------
133 // Compiler::unwindBegProlog: Initialize the unwind info data structures.
134 // Called at the beginning of main function or funclet prolog generation.
135 //
136 void Compiler::unwindBegProlog()
137 {
138 #ifdef UNIX_AMD64_ABI
139     if (generateCFIUnwindCodes())
140     {
141         unwindBegPrologCFI();
142     }
143     else
144 #endif // UNIX_AMD64_ABI
145     {
146         unwindBegPrologWindows();
147     }
148 }
149
150 void Compiler::unwindBegPrologWindows()
151 {
152     assert(compGeneratingProlog);
153
154     FuncInfoDsc* func = funCurrentFunc();
155
156     // There is only one prolog for a function/funclet, and it comes first. So now is
157     // a good time to initialize all the unwind data structures.
158
159     unwindGetFuncLocations(func, true, &func->startLoc, &func->endLoc);
160
161     if (fgFirstColdBlock != nullptr)
162     {
163         unwindGetFuncLocations(func, false, &func->coldStartLoc, &func->coldEndLoc);
164     }
165
166     func->unwindCodeSlot                  = sizeof(func->unwindCodes);
167     func->unwindHeader.Version            = 1;
168     func->unwindHeader.Flags              = 0;
169     func->unwindHeader.CountOfUnwindCodes = 0;
170     func->unwindHeader.FrameRegister      = 0;
171     func->unwindHeader.FrameOffset        = 0;
172 }
173
174 //------------------------------------------------------------------------
175 // Compiler::unwindEndProlog: Called at the end of main function or funclet
176 // prolog generation to indicate there is no more unwind information for this prolog.
177 //
178 void Compiler::unwindEndProlog()
179 {
180     assert(compGeneratingProlog);
181 }
182
183 //------------------------------------------------------------------------
184 // Compiler::unwindBegEpilog: Called at the beginning of main function or funclet
185 // epilog generation.
186 //
187 void Compiler::unwindBegEpilog()
188 {
189     assert(compGeneratingEpilog);
190 }
191
192 //------------------------------------------------------------------------
193 // Compiler::unwindEndEpilog: Called at the end of main function or funclet
194 // epilog generation.
195 //
196 void Compiler::unwindEndEpilog()
197 {
198     assert(compGeneratingEpilog);
199 }
200
201 //------------------------------------------------------------------------
202 // Compiler::unwindPush: Record a push/save of a register.
203 //
204 // Arguments:
205 //    reg - The register being pushed/saved.
206 //
207 void Compiler::unwindPush(regNumber reg)
208 {
209 #ifdef UNIX_AMD64_ABI
210     if (generateCFIUnwindCodes())
211     {
212         unwindPushPopCFI(reg);
213     }
214     else
215 #endif // UNIX_AMD64_ABI
216     {
217         unwindPushWindows(reg);
218     }
219 }
220
221 void Compiler::unwindPushWindows(regNumber reg)
222 {
223     assert(compGeneratingProlog);
224
225     FuncInfoDsc* func = funCurrentFunc();
226
227     assert(func->unwindHeader.Version == 1);            // Can't call this before unwindBegProlog
228     assert(func->unwindHeader.CountOfUnwindCodes == 0); // Can't call this after unwindReserve
229     assert(func->unwindCodeSlot > sizeof(UNWIND_CODE));
230     UNWIND_CODE* code     = (UNWIND_CODE*)&func->unwindCodes[func->unwindCodeSlot -= sizeof(UNWIND_CODE)];
231     unsigned int cbProlog = unwindGetCurrentOffset(func);
232     noway_assert((BYTE)cbProlog == cbProlog);
233     code->CodeOffset = (BYTE)cbProlog;
234
235     if ((RBM_CALLEE_SAVED & genRegMask(reg))
236 #if ETW_EBP_FRAMED
237         // In case of ETW_EBP_FRAMED defined the REG_FPBASE (RBP)
238         // is excluded from the callee-save register list.
239         // Make sure the register gets PUSH unwind info in this case,
240         // since it is pushed as a frame register.
241         || (reg == REG_FPBASE)
242 #endif // ETW_EBP_FRAMED
243             )
244     {
245         code->UnwindOp = UWOP_PUSH_NONVOL;
246         code->OpInfo   = (BYTE)reg;
247     }
248     else
249     {
250         // Push of a volatile register is just a small stack allocation
251         code->UnwindOp = UWOP_ALLOC_SMALL;
252         code->OpInfo   = 0;
253     }
254 }
255
256 #ifdef UNIX_AMD64_ABI
257 #endif // UNIX_AMD64_ABI
258
259 //------------------------------------------------------------------------
260 // Compiler::unwindAllocStack: Record a stack frame allocation (sub sp, X).
261 //
262 // Arguments:
263 //    size - The size of the stack frame allocation (the amount subtracted from the stack pointer).
264 //
265 void Compiler::unwindAllocStack(unsigned size)
266 {
267 #ifdef UNIX_AMD64_ABI
268     if (generateCFIUnwindCodes())
269     {
270         unwindAllocStackCFI(size);
271     }
272     else
273 #endif // UNIX_AMD64_ABI
274     {
275         unwindAllocStackWindows(size);
276     }
277 }
278
279 void Compiler::unwindAllocStackWindows(unsigned size)
280 {
281     assert(compGeneratingProlog);
282
283     FuncInfoDsc* func = funCurrentFunc();
284
285     assert(func->unwindHeader.Version == 1);            // Can't call this before unwindBegProlog
286     assert(func->unwindHeader.CountOfUnwindCodes == 0); // Can't call this after unwindReserve
287     assert(size % 8 == 0);                              // Stack size is *always* 8 byte aligned
288     UNWIND_CODE* code;
289     if (size <= 128)
290     {
291         assert(func->unwindCodeSlot > sizeof(UNWIND_CODE));
292         code           = (UNWIND_CODE*)&func->unwindCodes[func->unwindCodeSlot -= sizeof(UNWIND_CODE)];
293         code->UnwindOp = UWOP_ALLOC_SMALL;
294         code->OpInfo   = (size - 8) / 8;
295     }
296     else if (size <= 0x7FFF8)
297     {
298         assert(func->unwindCodeSlot > (sizeof(UNWIND_CODE) + sizeof(USHORT)));
299         USHORT* codedSize = (USHORT*)&func->unwindCodes[func->unwindCodeSlot -= sizeof(USHORT)];
300         *codedSize        = (USHORT)(size / 8);
301         code              = (UNWIND_CODE*)&func->unwindCodes[func->unwindCodeSlot -= sizeof(UNWIND_CODE)];
302         code->UnwindOp    = UWOP_ALLOC_LARGE;
303         code->OpInfo      = 0;
304     }
305     else
306     {
307         assert(func->unwindCodeSlot > (sizeof(UNWIND_CODE) + sizeof(ULONG)));
308         ULONG* codedSize = (ULONG*)&func->unwindCodes[func->unwindCodeSlot -= sizeof(ULONG)];
309         *codedSize       = size;
310         code             = (UNWIND_CODE*)&func->unwindCodes[func->unwindCodeSlot -= sizeof(UNWIND_CODE)];
311         code->UnwindOp   = UWOP_ALLOC_LARGE;
312         code->OpInfo     = 1;
313     }
314     unsigned int cbProlog = unwindGetCurrentOffset(func);
315     noway_assert((BYTE)cbProlog == cbProlog);
316     code->CodeOffset = (BYTE)cbProlog;
317 }
318
319 //------------------------------------------------------------------------
320 // Compiler::unwindSetFrameReg: Record a frame register.
321 //
322 // Arguments:
323 //    reg    - The register being set as the frame register.
324 //    offset - The offset from the current stack pointer that the frame pointer will point at.
325 //
326 void Compiler::unwindSetFrameReg(regNumber reg, unsigned offset)
327 {
328 #ifdef UNIX_AMD64_ABI
329     if (generateCFIUnwindCodes())
330     {
331         unwindSetFrameRegCFI(reg, offset);
332     }
333     else
334 #endif // UNIX_AMD64_ABI
335     {
336         unwindSetFrameRegWindows(reg, offset);
337     }
338 }
339
340 void Compiler::unwindSetFrameRegWindows(regNumber reg, unsigned offset)
341 {
342     assert(compGeneratingProlog);
343
344     FuncInfoDsc* func = funCurrentFunc();
345
346     assert(func->unwindHeader.Version == 1);            // Can't call this before unwindBegProlog
347     assert(func->unwindHeader.CountOfUnwindCodes == 0); // Can't call this after unwindReserve
348     unsigned int cbProlog = unwindGetCurrentOffset(func);
349     noway_assert((BYTE)cbProlog == cbProlog);
350
351     func->unwindHeader.FrameRegister = (BYTE)reg;
352
353 #ifdef UNIX_AMD64_ABI
354     if (offset > 240)
355     {
356         // On Unix only, we have a CLR-only extension to the AMD64 unwind codes: UWOP_SET_FPREG_LARGE.
357         // It has a 32-bit offset (scaled). You must set UNWIND_INFO.FrameOffset to 15. The 32-bit
358         // offset follows in 2 UNWIND_CODE fields.
359
360         assert(func->unwindCodeSlot > (sizeof(UNWIND_CODE) + sizeof(ULONG)));
361         ULONG* codedSize = (ULONG*)&func->unwindCodes[func->unwindCodeSlot -= sizeof(ULONG)];
362         assert(offset % 16 == 0);
363         *codedSize = offset / 16;
364
365         UNWIND_CODE* code              = (UNWIND_CODE*)&func->unwindCodes[func->unwindCodeSlot -= sizeof(UNWIND_CODE)];
366         code->CodeOffset               = (BYTE)cbProlog;
367         code->OpInfo                   = 0;
368         code->UnwindOp                 = UWOP_SET_FPREG_LARGE;
369         func->unwindHeader.FrameOffset = 15;
370     }
371     else
372 #endif // UNIX_AMD64_ABI
373     {
374         assert(func->unwindCodeSlot > sizeof(UNWIND_CODE));
375         UNWIND_CODE* code = (UNWIND_CODE*)&func->unwindCodes[func->unwindCodeSlot -= sizeof(UNWIND_CODE)];
376         code->CodeOffset  = (BYTE)cbProlog;
377         code->OpInfo      = 0;
378         code->UnwindOp    = UWOP_SET_FPREG;
379         assert(offset <= 240);
380         assert(offset % 16 == 0);
381         func->unwindHeader.FrameOffset = offset / 16;
382     }
383 }
384
385 //------------------------------------------------------------------------
386 // Compiler::unwindSaveReg: Record a register save.
387 //
388 // Arguments:
389 //    reg    - The register being saved.
390 //    offset - The offset from the current stack pointer where the register is being saved.
391 //
392 void Compiler::unwindSaveReg(regNumber reg, unsigned offset)
393 {
394 #ifdef UNIX_AMD64_ABI
395     if (generateCFIUnwindCodes())
396     {
397         unwindSaveRegCFI(reg, offset);
398     }
399     else
400 #endif // UNIX_AMD64_ABI
401     {
402         unwindSaveRegWindows(reg, offset);
403     }
404 }
405
406 void Compiler::unwindSaveRegWindows(regNumber reg, unsigned offset)
407 {
408     assert(compGeneratingProlog);
409
410     FuncInfoDsc* func = funCurrentFunc();
411
412     assert(func->unwindHeader.Version == 1);            // Can't call this before unwindBegProlog
413     assert(func->unwindHeader.CountOfUnwindCodes == 0); // Can't call this after unwindReserve
414     if (RBM_CALLEE_SAVED & genRegMask(reg))
415     {
416         UNWIND_CODE* code;
417         if (offset < 0x80000)
418         {
419             assert(func->unwindCodeSlot > (sizeof(UNWIND_CODE) + sizeof(USHORT)));
420             USHORT* codedSize = (USHORT*)&func->unwindCodes[func->unwindCodeSlot -= sizeof(USHORT)];
421             code              = (UNWIND_CODE*)&func->unwindCodes[func->unwindCodeSlot -= sizeof(UNWIND_CODE)];
422
423             // As per AMD64 ABI, if saving entire xmm reg, then offset need to be scaled by 16.
424             if (genIsValidFloatReg(reg))
425             {
426                 *codedSize     = (USHORT)(offset / 16);
427                 code->UnwindOp = UWOP_SAVE_XMM128;
428             }
429             else
430             {
431                 *codedSize     = (USHORT)(offset / 8);
432                 code->UnwindOp = UWOP_SAVE_NONVOL;
433             }
434         }
435         else
436         {
437             assert(func->unwindCodeSlot > (sizeof(UNWIND_CODE) + sizeof(ULONG)));
438             ULONG* codedSize = (ULONG*)&func->unwindCodes[func->unwindCodeSlot -= sizeof(ULONG)];
439             *codedSize       = offset;
440             code             = (UNWIND_CODE*)&func->unwindCodes[func->unwindCodeSlot -= sizeof(UNWIND_CODE)];
441             code->UnwindOp   = (genIsValidFloatReg(reg)) ? UWOP_SAVE_XMM128_FAR : UWOP_SAVE_NONVOL_FAR;
442         }
443         code->OpInfo          = (BYTE)reg;
444         unsigned int cbProlog = unwindGetCurrentOffset(func);
445         noway_assert((BYTE)cbProlog == cbProlog);
446         code->CodeOffset = (BYTE)cbProlog;
447     }
448 }
449
450 #ifdef UNIX_AMD64_ABI
451 void Compiler::unwindSaveRegCFI(regNumber reg, unsigned offset)
452 {
453     assert(compGeneratingProlog);
454
455     if (RBM_CALLEE_SAVED & genRegMask(reg))
456     {
457         FuncInfoDsc* func = funCurrentFunc();
458
459         unsigned int cbProlog = unwindGetCurrentOffset(func);
460         noway_assert((BYTE)cbProlog == cbProlog);
461         createCfiCode(func, cbProlog, CFI_REL_OFFSET, mapRegNumToDwarfReg(reg), offset);
462     }
463 }
464 #endif // UNIX_AMD64_ABI
465
466 #ifdef DEBUG
467
468 //------------------------------------------------------------------------
469 // DumpUnwindInfo: Dump the unwind data.
470 //
471 // Arguments:
472 //    isHotCode   - true if this unwind data is for the hot section, false otherwise.
473 //    startOffset - byte offset of the code start that this unwind data represents.
474 //    endOffset   - byte offset of the code end   that this unwind data represents.
475 //    pHeader     - pointer to the unwind data blob.
476 //
477 void DumpUnwindInfo(bool                     isHotCode,
478                     UNATIVE_OFFSET           startOffset,
479                     UNATIVE_OFFSET           endOffset,
480                     const UNWIND_INFO* const pHeader)
481 {
482     printf("Unwind Info%s:\n", isHotCode ? "" : " COLD");
483     printf("  >> Start offset   : 0x%06x (not in unwind data)\n", dspOffset(startOffset));
484     printf("  >>   End offset   : 0x%06x (not in unwind data)\n", dspOffset(endOffset));
485
486     if (pHeader == nullptr)
487     {
488         // Cold AMD64 code doesn't have unwind info; the VM creates chained unwind info.
489         assert(!isHotCode);
490         return;
491     }
492
493     printf("  Version           : %u\n", pHeader->Version);
494     printf("  Flags             : 0x%02x", pHeader->Flags);
495     if (pHeader->Flags)
496     {
497         const UCHAR flags = pHeader->Flags;
498         printf(" (");
499         if (flags & UNW_FLAG_EHANDLER)
500         {
501             printf(" UNW_FLAG_EHANDLER");
502         }
503         if (flags & UNW_FLAG_UHANDLER)
504         {
505             printf(" UNW_FLAG_UHANDLER");
506         }
507         if (flags & UNW_FLAG_CHAININFO)
508         {
509             printf(" UNW_FLAG_CHAININFO");
510         }
511         printf(")");
512     }
513     printf("\n");
514     printf("  SizeOfProlog      : 0x%02X\n", pHeader->SizeOfProlog);
515     printf("  CountOfUnwindCodes: %u\n", pHeader->CountOfUnwindCodes);
516     printf("  FrameRegister     : %s (%u)\n",
517            (pHeader->FrameRegister == 0) ? "none" : getRegName(pHeader->FrameRegister),
518            pHeader->FrameRegister); // RAX (0) is not allowed as a frame register
519     if (pHeader->FrameRegister == 0)
520     {
521         printf("  FrameOffset       : N/A (no FrameRegister) (Value=%u)\n", pHeader->FrameOffset);
522     }
523     else
524     {
525         printf("  FrameOffset       : %u * 16 = 0x%02X\n", pHeader->FrameOffset, pHeader->FrameOffset * 16);
526     }
527     printf("  UnwindCodes       :\n");
528
529     for (unsigned i = 0; i < pHeader->CountOfUnwindCodes; i++)
530     {
531         unsigned                 offset;
532         const UNWIND_CODE* const pCode = &(pHeader->UnwindCode[i]);
533         switch (pCode->UnwindOp)
534         {
535             case UWOP_PUSH_NONVOL:
536                 printf("    CodeOffset: 0x%02X UnwindOp: UWOP_PUSH_NONVOL (%u)     OpInfo: %s (%u)\n",
537                        pCode->CodeOffset, pCode->UnwindOp, getRegName(pCode->OpInfo), pCode->OpInfo);
538                 break;
539
540             case UWOP_ALLOC_LARGE:
541                 printf("    CodeOffset: 0x%02X UnwindOp: UWOP_ALLOC_LARGE (%u)     OpInfo: %u - ", pCode->CodeOffset,
542                        pCode->UnwindOp, pCode->OpInfo);
543                 if (pCode->OpInfo == 0)
544                 {
545                     i++;
546                     printf("Scaled small  \n      Size: %u * 8 = %u = 0x%05X\n", pHeader->UnwindCode[i].FrameOffset,
547                            pHeader->UnwindCode[i].FrameOffset * 8, pHeader->UnwindCode[i].FrameOffset * 8);
548                 }
549                 else if (pCode->OpInfo == 1)
550                 {
551                     i++;
552                     printf("Unscaled large\n      Size: %u = 0x%08X\n\n", *(ULONG*)&(pHeader->UnwindCode[i]),
553                            *(ULONG*)&(pHeader->UnwindCode[i]));
554                     i++;
555                 }
556                 else
557                 {
558                     printf("Unknown\n");
559                 }
560                 break;
561
562             case UWOP_ALLOC_SMALL:
563                 printf("    CodeOffset: 0x%02X UnwindOp: UWOP_ALLOC_SMALL (%u)     OpInfo: %u * 8 + 8 = %u = 0x%02X\n",
564                        pCode->CodeOffset, pCode->UnwindOp, pCode->OpInfo, pCode->OpInfo * 8 + 8, pCode->OpInfo * 8 + 8);
565                 break;
566
567             case UWOP_SET_FPREG:
568                 printf("    CodeOffset: 0x%02X UnwindOp: UWOP_SET_FPREG (%u)       OpInfo: Unused (%u)\n",
569                        pCode->CodeOffset, pCode->UnwindOp, pCode->OpInfo); // This should be zero
570                 break;
571
572 #ifdef UNIX_AMD64_ABI
573
574             case UWOP_SET_FPREG_LARGE:
575                 printf("    CodeOffset: 0x%02X UnwindOp: UWOP_SET_FPREG_LARGE (%u) OpInfo: Unused (%u)\n",
576                        pCode->CodeOffset, pCode->UnwindOp, pCode->OpInfo); // This should be zero
577                 i++;
578                 offset = *(ULONG*)&(pHeader->UnwindCode[i]);
579                 i++;
580                 printf("      Scaled Offset: %u * 16 = %u = 0x%08X\n", offset, offset * 16, offset * 16);
581                 if ((offset & 0xF0000000) != 0)
582                 {
583                     printf("      Illegal unscaled offset: too large\n");
584                 }
585                 break;
586
587 #endif // UNIX_AMD64_ABI
588
589             case UWOP_SAVE_NONVOL:
590                 printf("    CodeOffset: 0x%02X UnwindOp: UWOP_SAVE_NONVOL (%u)     OpInfo: %s (%u)\n",
591                        pCode->CodeOffset, pCode->UnwindOp, getRegName(pCode->OpInfo), pCode->OpInfo);
592                 i++;
593                 printf("      Scaled Small Offset: %u * 8 = %u = 0x%05X\n", pHeader->UnwindCode[i].FrameOffset,
594                        pHeader->UnwindCode[i].FrameOffset * 8, pHeader->UnwindCode[i].FrameOffset * 8);
595                 break;
596
597             case UWOP_SAVE_NONVOL_FAR:
598                 printf("    CodeOffset: 0x%02X UnwindOp: UWOP_SAVE_NONVOL_FAR (%u) OpInfo: %s (%u)\n",
599                        pCode->CodeOffset, pCode->UnwindOp, getRegName(pCode->OpInfo), pCode->OpInfo);
600                 i++;
601                 printf("      Unscaled Large Offset: 0x%08X\n\n", *(ULONG*)&(pHeader->UnwindCode[i]));
602                 i++;
603                 break;
604
605             case UWOP_SAVE_XMM128:
606                 printf("    CodeOffset: 0x%02X UnwindOp: UWOP_SAVE_XMM128 (%u)     OpInfo: XMM%u (%u)\n",
607                        pCode->CodeOffset, pCode->UnwindOp, pCode->OpInfo, pCode->OpInfo);
608                 i++;
609                 printf("      Scaled Small Offset: %u * 16 = %u = 0x%05X\n", pHeader->UnwindCode[i].FrameOffset,
610                        pHeader->UnwindCode[i].FrameOffset * 16, pHeader->UnwindCode[i].FrameOffset * 16);
611                 break;
612
613             case UWOP_SAVE_XMM128_FAR:
614                 printf("    CodeOffset: 0x%02X UnwindOp: UWOP_SAVE_XMM128_FAR (%u) OpInfo: XMM%u (%u)\n",
615                        pCode->CodeOffset, pCode->UnwindOp, pCode->OpInfo, pCode->OpInfo);
616                 i++;
617                 printf("      Unscaled Large Offset: 0x%08X\n\n", *(ULONG*)&(pHeader->UnwindCode[i]));
618                 i++;
619                 break;
620
621             case UWOP_EPILOG:
622             case UWOP_SPARE_CODE:
623             case UWOP_PUSH_MACHFRAME:
624             default:
625                 printf("    Unrecognized UNWIND_CODE: 0x%04X\n", *(USHORT*)pCode);
626                 break;
627         }
628     }
629 }
630
631 #endif // DEBUG
632
633 //------------------------------------------------------------------------
634 // Compiler::unwindReserve: Ask the VM to reserve space for the unwind information
635 // for the function and all its funclets. Called once, just before asking the VM
636 // for memory and emitting the generated code. Calls unwindReserveFunc() to handle
637 // the main function and each of the funclets, in turn.
638 //
639 void Compiler::unwindReserve()
640 {
641     assert(!compGeneratingProlog);
642     assert(!compGeneratingEpilog);
643
644     assert(compFuncInfoCount > 0);
645     for (unsigned funcIdx = 0; funcIdx < compFuncInfoCount; funcIdx++)
646     {
647         unwindReserveFunc(funGetFunc(funcIdx));
648     }
649 }
650
651 //------------------------------------------------------------------------
652 // Compiler::unwindReserveFunc: Reserve the unwind information from the VM for a
653 // given main function or funclet.
654 //
655 // Arguments:
656 //    func - The main function or funclet to reserve unwind info for.
657 //
658 void Compiler::unwindReserveFunc(FuncInfoDsc* func)
659 {
660     unwindReserveFuncHelper(func, true);
661
662     if (fgFirstColdBlock != nullptr)
663     {
664         unwindReserveFuncHelper(func, false);
665     }
666 }
667
668 //------------------------------------------------------------------------
669 // Compiler::unwindReserveFuncHelper: Reserve the unwind information from the VM for a
670 // given main function or funclet, for either the hot or the cold section.
671 //
672 // Arguments:
673 //    func      - The main function or funclet to reserve unwind info for.
674 //    isHotCode - 'true' to reserve the hot section, 'false' to reserve the cold section.
675 //
676 void Compiler::unwindReserveFuncHelper(FuncInfoDsc* func, bool isHotCode)
677 {
678     DWORD unwindCodeBytes = 0;
679     if (isHotCode)
680     {
681 #ifdef UNIX_AMD64_ABI
682         if (generateCFIUnwindCodes())
683         {
684             unwindCodeBytes = (DWORD)(func->cfiCodes->size() * sizeof(CFI_CODE));
685         }
686         else
687 #endif // UNIX_AMD64_ABI
688         {
689             assert(func->unwindHeader.Version == 1);            // Can't call this before unwindBegProlog
690             assert(func->unwindHeader.CountOfUnwindCodes == 0); // Only call this once per prolog
691
692             // Set the size of the prolog to be the last encoded action
693             if (func->unwindCodeSlot < sizeof(func->unwindCodes))
694             {
695                 UNWIND_CODE* code               = (UNWIND_CODE*)&func->unwindCodes[func->unwindCodeSlot];
696                 func->unwindHeader.SizeOfProlog = code->CodeOffset;
697             }
698             else
699             {
700                 func->unwindHeader.SizeOfProlog = 0;
701             }
702             func->unwindHeader.CountOfUnwindCodes =
703                 (BYTE)((sizeof(func->unwindCodes) - func->unwindCodeSlot) / sizeof(UNWIND_CODE));
704
705             // Prepend the unwindHeader onto the unwind codes
706             assert(func->unwindCodeSlot >= offsetof(UNWIND_INFO, UnwindCode));
707
708             func->unwindCodeSlot -= offsetof(UNWIND_INFO, UnwindCode);
709             UNWIND_INFO* pHeader = (UNWIND_INFO*)&func->unwindCodes[func->unwindCodeSlot];
710             memcpy(pHeader, &func->unwindHeader, offsetof(UNWIND_INFO, UnwindCode));
711
712             unwindCodeBytes = sizeof(func->unwindCodes) - func->unwindCodeSlot;
713         }
714     }
715
716     BOOL isFunclet  = (func->funKind != FUNC_ROOT);
717     BOOL isColdCode = isHotCode ? FALSE : TRUE;
718
719     eeReserveUnwindInfo(isFunclet, isColdCode, unwindCodeBytes);
720 }
721
722 //------------------------------------------------------------------------
723 // Compiler::unwindEmit: Report all the unwind information to the VM.
724 //
725 // Arguments:
726 //    pHotCode  - Pointer to the beginning of the memory with the function and funclet hot  code.
727 //    pColdCode - Pointer to the beginning of the memory with the function and funclet cold code.
728 //
729 void Compiler::unwindEmit(void* pHotCode, void* pColdCode)
730 {
731     assert(!compGeneratingProlog);
732     assert(!compGeneratingEpilog);
733
734     assert(compFuncInfoCount > 0);
735     for (unsigned funcIdx = 0; funcIdx < compFuncInfoCount; funcIdx++)
736     {
737         unwindEmitFunc(funGetFunc(funcIdx), pHotCode, pColdCode);
738     }
739 }
740
741 //------------------------------------------------------------------------
742 // Compiler::unwindEmitFuncHelper: Report the unwind information to the VM for a
743 // given main function or funclet, for either the hot or cold section.
744 //
745 // Arguments:
746 //    func      - The main function or funclet to reserve unwind info for.
747 //    pHotCode  - Pointer to the beginning of the memory with the function and funclet hot  code.
748 //    pColdCode - Pointer to the beginning of the memory with the function and funclet cold code.
749 //                Ignored if 'isHotCode' is true.
750 //    isHotCode - 'true' to report the hot section, 'false' to report the cold section.
751 //
752 void Compiler::unwindEmitFuncHelper(FuncInfoDsc* func, void* pHotCode, void* pColdCode, bool isHotCode)
753 {
754     UNATIVE_OFFSET startOffset;
755     UNATIVE_OFFSET endOffset;
756     DWORD          unwindCodeBytes = 0;
757     BYTE*          pUnwindBlock    = nullptr;
758
759     if (isHotCode)
760     {
761         if (func->startLoc == nullptr)
762         {
763             startOffset = 0;
764         }
765         else
766         {
767             startOffset = func->startLoc->CodeOffset(genEmitter);
768         }
769
770         if (func->endLoc == nullptr)
771         {
772             endOffset = info.compNativeCodeSize;
773         }
774         else
775         {
776             endOffset = func->endLoc->CodeOffset(genEmitter);
777         }
778
779 #ifdef UNIX_AMD64_ABI
780         if (generateCFIUnwindCodes())
781         {
782             DWORD size = (DWORD)func->cfiCodes->size();
783             if (size > 0)
784             {
785                 unwindCodeBytes = size * sizeof(CFI_CODE);
786                 pUnwindBlock    = (BYTE*)&(*func->cfiCodes)[0];
787             }
788         }
789         else
790 #endif // UNIX_AMD64_ABI
791         {
792             unwindCodeBytes = sizeof(func->unwindCodes) - func->unwindCodeSlot;
793
794 #ifdef DEBUG
795             UNWIND_INFO* pUnwindInfo = (UNWIND_INFO*)(&func->unwindCodes[func->unwindCodeSlot]);
796             DWORD        unwindCodeBytesSpecified =
797                 offsetof(UNWIND_INFO, UnwindCode) +
798                 pUnwindInfo->CountOfUnwindCodes * sizeof(UNWIND_CODE); // This is what the unwind codes themselves say;
799                                                                        // it better match what we tell the VM.
800             assert(unwindCodeBytes == unwindCodeBytesSpecified);
801 #endif // DEBUG
802
803             pUnwindBlock = &func->unwindCodes[func->unwindCodeSlot];
804         }
805     }
806     else
807     {
808         assert(fgFirstColdBlock != nullptr);
809         assert(func->funKind == FUNC_ROOT); // No splitting of funclets.
810
811         if (func->coldStartLoc == nullptr)
812         {
813             startOffset = 0;
814         }
815         else
816         {
817             startOffset = func->coldStartLoc->CodeOffset(genEmitter);
818         }
819
820         if (func->coldEndLoc == nullptr)
821         {
822             endOffset = info.compNativeCodeSize;
823         }
824         else
825         {
826             endOffset = func->coldEndLoc->CodeOffset(genEmitter);
827         }
828     }
829
830 #ifdef DEBUG
831     if (opts.dspUnwind)
832     {
833 #ifdef UNIX_AMD64_ABI
834         if (generateCFIUnwindCodes())
835         {
836             DumpCfiInfo(isHotCode, startOffset, endOffset, unwindCodeBytes, (const CFI_CODE* const)pUnwindBlock);
837         }
838         else
839 #endif // UNIX_AMD64_ABI
840         {
841             DumpUnwindInfo(isHotCode, startOffset, endOffset, (const UNWIND_INFO* const)pUnwindBlock);
842         }
843     }
844 #endif // DEBUG
845
846     // Adjust for cold or hot code:
847     // 1. The VM doesn't want the cold code pointer unless this is cold code.
848     // 2. The startOffset and endOffset need to be from the base of the hot section for hot code
849     //    and from the base of the cold section for cold code
850
851     if (isHotCode)
852     {
853         assert(endOffset <= info.compTotalHotCodeSize);
854         pColdCode = nullptr;
855     }
856     else
857     {
858         assert(startOffset >= info.compTotalHotCodeSize);
859         startOffset -= info.compTotalHotCodeSize;
860         endOffset -= info.compTotalHotCodeSize;
861     }
862
863     eeAllocUnwindInfo((BYTE*)pHotCode, (BYTE*)pColdCode, startOffset, endOffset, unwindCodeBytes, pUnwindBlock,
864                       (CorJitFuncKind)func->funKind);
865 }
866
867 //------------------------------------------------------------------------
868 // Compiler::unwindEmitFunc: Report the unwind information to the VM for a
869 // given main function or funclet. Reports the hot section, then the cold
870 // section if necessary.
871 //
872 // Arguments:
873 //    func      - The main function or funclet to reserve unwind info for.
874 //    pHotCode  - Pointer to the beginning of the memory with the function and funclet hot  code.
875 //    pColdCode - Pointer to the beginning of the memory with the function and funclet cold code.
876 //
877 void Compiler::unwindEmitFunc(FuncInfoDsc* func, void* pHotCode, void* pColdCode)
878 {
879     // Verify that the JIT enum is in sync with the JIT-EE interface enum
880     static_assert_no_msg(FUNC_ROOT == (FuncKind)CORJIT_FUNC_ROOT);
881     static_assert_no_msg(FUNC_HANDLER == (FuncKind)CORJIT_FUNC_HANDLER);
882     static_assert_no_msg(FUNC_FILTER == (FuncKind)CORJIT_FUNC_FILTER);
883
884     unwindEmitFuncHelper(func, pHotCode, pColdCode, true);
885
886     if (pColdCode != nullptr)
887     {
888         unwindEmitFuncHelper(func, pHotCode, pColdCode, false);
889     }
890 }
891
892 #endif // _TARGET_AMD64_