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
6XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
7XX XX
8XX UnwindInfo XX
9XX XX
10XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
11XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
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
21int 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//
136void 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
150void 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//
178void 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//
187void 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//
196void 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//
207void 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
221void 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//
265void 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
279void 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//
326void 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
340void 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//
392void 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
406void 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
451void 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//
477void 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 const UNWIND_CODE* const pCode = &(pHeader->UnwindCode[i]);
532 switch (pCode->UnwindOp)
533 {
534 case UWOP_PUSH_NONVOL:
535 printf(" CodeOffset: 0x%02X UnwindOp: UWOP_PUSH_NONVOL (%u) OpInfo: %s (%u)\n",
536 pCode->CodeOffset, pCode->UnwindOp, getRegName(pCode->OpInfo), pCode->OpInfo);
537 break;
538
539 case UWOP_ALLOC_LARGE:
540 printf(" CodeOffset: 0x%02X UnwindOp: UWOP_ALLOC_LARGE (%u) OpInfo: %u - ", pCode->CodeOffset,
541 pCode->UnwindOp, pCode->OpInfo);
542 if (pCode->OpInfo == 0)
543 {
544 i++;
545 printf("Scaled small \n Size: %u * 8 = %u = 0x%05X\n", pHeader->UnwindCode[i].FrameOffset,
546 pHeader->UnwindCode[i].FrameOffset * 8, pHeader->UnwindCode[i].FrameOffset * 8);
547 }
548 else if (pCode->OpInfo == 1)
549 {
550 i++;
551 printf("Unscaled large\n Size: %u = 0x%08X\n\n", *(ULONG*)&(pHeader->UnwindCode[i]),
552 *(ULONG*)&(pHeader->UnwindCode[i]));
553 i++;
554 }
555 else
556 {
557 printf("Unknown\n");
558 }
559 break;
560
561 case UWOP_ALLOC_SMALL:
562 printf(" CodeOffset: 0x%02X UnwindOp: UWOP_ALLOC_SMALL (%u) OpInfo: %u * 8 + 8 = %u = 0x%02X\n",
563 pCode->CodeOffset, pCode->UnwindOp, pCode->OpInfo, pCode->OpInfo * 8 + 8, pCode->OpInfo * 8 + 8);
564 break;
565
566 case UWOP_SET_FPREG:
567 printf(" CodeOffset: 0x%02X UnwindOp: UWOP_SET_FPREG (%u) OpInfo: Unused (%u)\n",
568 pCode->CodeOffset, pCode->UnwindOp, pCode->OpInfo); // This should be zero
569 break;
570
571#ifdef UNIX_AMD64_ABI
572
573 case UWOP_SET_FPREG_LARGE:
574 {
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 unsigned 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 }
586 break;
587
588#endif // UNIX_AMD64_ABI
589
590 case UWOP_SAVE_NONVOL:
591 printf(" CodeOffset: 0x%02X UnwindOp: UWOP_SAVE_NONVOL (%u) OpInfo: %s (%u)\n",
592 pCode->CodeOffset, pCode->UnwindOp, getRegName(pCode->OpInfo), pCode->OpInfo);
593 i++;
594 printf(" Scaled Small Offset: %u * 8 = %u = 0x%05X\n", pHeader->UnwindCode[i].FrameOffset,
595 pHeader->UnwindCode[i].FrameOffset * 8, pHeader->UnwindCode[i].FrameOffset * 8);
596 break;
597
598 case UWOP_SAVE_NONVOL_FAR:
599 printf(" CodeOffset: 0x%02X UnwindOp: UWOP_SAVE_NONVOL_FAR (%u) OpInfo: %s (%u)\n",
600 pCode->CodeOffset, pCode->UnwindOp, getRegName(pCode->OpInfo), pCode->OpInfo);
601 i++;
602 printf(" Unscaled Large Offset: 0x%08X\n\n", *(ULONG*)&(pHeader->UnwindCode[i]));
603 i++;
604 break;
605
606 case UWOP_SAVE_XMM128:
607 printf(" CodeOffset: 0x%02X UnwindOp: UWOP_SAVE_XMM128 (%u) OpInfo: XMM%u (%u)\n",
608 pCode->CodeOffset, pCode->UnwindOp, pCode->OpInfo, pCode->OpInfo);
609 i++;
610 printf(" Scaled Small Offset: %u * 16 = %u = 0x%05X\n", pHeader->UnwindCode[i].FrameOffset,
611 pHeader->UnwindCode[i].FrameOffset * 16, pHeader->UnwindCode[i].FrameOffset * 16);
612 break;
613
614 case UWOP_SAVE_XMM128_FAR:
615 printf(" CodeOffset: 0x%02X UnwindOp: UWOP_SAVE_XMM128_FAR (%u) OpInfo: XMM%u (%u)\n",
616 pCode->CodeOffset, pCode->UnwindOp, pCode->OpInfo, pCode->OpInfo);
617 i++;
618 printf(" Unscaled Large Offset: 0x%08X\n\n", *(ULONG*)&(pHeader->UnwindCode[i]));
619 i++;
620 break;
621
622 case UWOP_EPILOG:
623 case UWOP_SPARE_CODE:
624 case UWOP_PUSH_MACHFRAME:
625 default:
626 printf(" Unrecognized UNWIND_CODE: 0x%04X\n", *(USHORT*)pCode);
627 break;
628 }
629 }
630}
631
632#endif // DEBUG
633
634//------------------------------------------------------------------------
635// Compiler::unwindReserve: Ask the VM to reserve space for the unwind information
636// for the function and all its funclets. Called once, just before asking the VM
637// for memory and emitting the generated code. Calls unwindReserveFunc() to handle
638// the main function and each of the funclets, in turn.
639//
640void Compiler::unwindReserve()
641{
642 assert(!compGeneratingProlog);
643 assert(!compGeneratingEpilog);
644
645 assert(compFuncInfoCount > 0);
646 for (unsigned funcIdx = 0; funcIdx < compFuncInfoCount; funcIdx++)
647 {
648 unwindReserveFunc(funGetFunc(funcIdx));
649 }
650}
651
652//------------------------------------------------------------------------
653// Compiler::unwindReserveFunc: Reserve the unwind information from the VM for a
654// given main function or funclet.
655//
656// Arguments:
657// func - The main function or funclet to reserve unwind info for.
658//
659void Compiler::unwindReserveFunc(FuncInfoDsc* func)
660{
661 unwindReserveFuncHelper(func, true);
662
663 if (fgFirstColdBlock != nullptr)
664 {
665 unwindReserveFuncHelper(func, false);
666 }
667}
668
669//------------------------------------------------------------------------
670// Compiler::unwindReserveFuncHelper: Reserve the unwind information from the VM for a
671// given main function or funclet, for either the hot or the cold section.
672//
673// Arguments:
674// func - The main function or funclet to reserve unwind info for.
675// isHotCode - 'true' to reserve the hot section, 'false' to reserve the cold section.
676//
677void Compiler::unwindReserveFuncHelper(FuncInfoDsc* func, bool isHotCode)
678{
679 DWORD unwindCodeBytes = 0;
680 if (isHotCode)
681 {
682#ifdef UNIX_AMD64_ABI
683 if (generateCFIUnwindCodes())
684 {
685 unwindCodeBytes = (DWORD)(func->cfiCodes->size() * sizeof(CFI_CODE));
686 }
687 else
688#endif // UNIX_AMD64_ABI
689 {
690 assert(func->unwindHeader.Version == 1); // Can't call this before unwindBegProlog
691 assert(func->unwindHeader.CountOfUnwindCodes == 0); // Only call this once per prolog
692
693 // Set the size of the prolog to be the last encoded action
694 if (func->unwindCodeSlot < sizeof(func->unwindCodes))
695 {
696 UNWIND_CODE* code = (UNWIND_CODE*)&func->unwindCodes[func->unwindCodeSlot];
697 func->unwindHeader.SizeOfProlog = code->CodeOffset;
698 }
699 else
700 {
701 func->unwindHeader.SizeOfProlog = 0;
702 }
703 func->unwindHeader.CountOfUnwindCodes =
704 (BYTE)((sizeof(func->unwindCodes) - func->unwindCodeSlot) / sizeof(UNWIND_CODE));
705
706 // Prepend the unwindHeader onto the unwind codes
707 assert(func->unwindCodeSlot >= offsetof(UNWIND_INFO, UnwindCode));
708
709 func->unwindCodeSlot -= offsetof(UNWIND_INFO, UnwindCode);
710 UNWIND_INFO* pHeader = (UNWIND_INFO*)&func->unwindCodes[func->unwindCodeSlot];
711 memcpy(pHeader, &func->unwindHeader, offsetof(UNWIND_INFO, UnwindCode));
712
713 unwindCodeBytes = sizeof(func->unwindCodes) - func->unwindCodeSlot;
714 }
715 }
716
717 BOOL isFunclet = (func->funKind != FUNC_ROOT);
718 BOOL isColdCode = isHotCode ? FALSE : TRUE;
719
720 eeReserveUnwindInfo(isFunclet, isColdCode, unwindCodeBytes);
721}
722
723//------------------------------------------------------------------------
724// Compiler::unwindEmit: Report all the unwind information to the VM.
725//
726// Arguments:
727// pHotCode - Pointer to the beginning of the memory with the function and funclet hot code.
728// pColdCode - Pointer to the beginning of the memory with the function and funclet cold code.
729//
730void Compiler::unwindEmit(void* pHotCode, void* pColdCode)
731{
732 assert(!compGeneratingProlog);
733 assert(!compGeneratingEpilog);
734
735 assert(compFuncInfoCount > 0);
736 for (unsigned funcIdx = 0; funcIdx < compFuncInfoCount; funcIdx++)
737 {
738 unwindEmitFunc(funGetFunc(funcIdx), pHotCode, pColdCode);
739 }
740}
741
742//------------------------------------------------------------------------
743// Compiler::unwindEmitFuncHelper: Report the unwind information to the VM for a
744// given main function or funclet, for either the hot or cold section.
745//
746// Arguments:
747// func - The main function or funclet to reserve unwind info for.
748// pHotCode - Pointer to the beginning of the memory with the function and funclet hot code.
749// pColdCode - Pointer to the beginning of the memory with the function and funclet cold code.
750// Ignored if 'isHotCode' is true.
751// isHotCode - 'true' to report the hot section, 'false' to report the cold section.
752//
753void Compiler::unwindEmitFuncHelper(FuncInfoDsc* func, void* pHotCode, void* pColdCode, bool isHotCode)
754{
755 UNATIVE_OFFSET startOffset;
756 UNATIVE_OFFSET endOffset;
757 DWORD unwindCodeBytes = 0;
758 BYTE* pUnwindBlock = nullptr;
759
760 if (isHotCode)
761 {
762 if (func->startLoc == nullptr)
763 {
764 startOffset = 0;
765 }
766 else
767 {
768 startOffset = func->startLoc->CodeOffset(genEmitter);
769 }
770
771 if (func->endLoc == nullptr)
772 {
773 endOffset = info.compNativeCodeSize;
774 }
775 else
776 {
777 endOffset = func->endLoc->CodeOffset(genEmitter);
778 }
779
780#ifdef UNIX_AMD64_ABI
781 if (generateCFIUnwindCodes())
782 {
783 DWORD size = (DWORD)func->cfiCodes->size();
784 if (size > 0)
785 {
786 unwindCodeBytes = size * sizeof(CFI_CODE);
787 pUnwindBlock = (BYTE*)&(*func->cfiCodes)[0];
788 }
789 }
790 else
791#endif // UNIX_AMD64_ABI
792 {
793 unwindCodeBytes = sizeof(func->unwindCodes) - func->unwindCodeSlot;
794
795#ifdef DEBUG
796 UNWIND_INFO* pUnwindInfo = (UNWIND_INFO*)(&func->unwindCodes[func->unwindCodeSlot]);
797 DWORD unwindCodeBytesSpecified =
798 offsetof(UNWIND_INFO, UnwindCode) +
799 pUnwindInfo->CountOfUnwindCodes * sizeof(UNWIND_CODE); // This is what the unwind codes themselves say;
800 // it better match what we tell the VM.
801 assert(unwindCodeBytes == unwindCodeBytesSpecified);
802#endif // DEBUG
803
804 pUnwindBlock = &func->unwindCodes[func->unwindCodeSlot];
805 }
806 }
807 else
808 {
809 assert(fgFirstColdBlock != nullptr);
810 assert(func->funKind == FUNC_ROOT); // No splitting of funclets.
811
812 if (func->coldStartLoc == nullptr)
813 {
814 startOffset = 0;
815 }
816 else
817 {
818 startOffset = func->coldStartLoc->CodeOffset(genEmitter);
819 }
820
821 if (func->coldEndLoc == nullptr)
822 {
823 endOffset = info.compNativeCodeSize;
824 }
825 else
826 {
827 endOffset = func->coldEndLoc->CodeOffset(genEmitter);
828 }
829 }
830
831#ifdef DEBUG
832 if (opts.dspUnwind)
833 {
834#ifdef UNIX_AMD64_ABI
835 if (generateCFIUnwindCodes())
836 {
837 DumpCfiInfo(isHotCode, startOffset, endOffset, unwindCodeBytes, (const CFI_CODE* const)pUnwindBlock);
838 }
839 else
840#endif // UNIX_AMD64_ABI
841 {
842 DumpUnwindInfo(isHotCode, startOffset, endOffset, (const UNWIND_INFO* const)pUnwindBlock);
843 }
844 }
845#endif // DEBUG
846
847 // Adjust for cold or hot code:
848 // 1. The VM doesn't want the cold code pointer unless this is cold code.
849 // 2. The startOffset and endOffset need to be from the base of the hot section for hot code
850 // and from the base of the cold section for cold code
851
852 if (isHotCode)
853 {
854 assert(endOffset <= info.compTotalHotCodeSize);
855 pColdCode = nullptr;
856 }
857 else
858 {
859 assert(startOffset >= info.compTotalHotCodeSize);
860 startOffset -= info.compTotalHotCodeSize;
861 endOffset -= info.compTotalHotCodeSize;
862 }
863
864 eeAllocUnwindInfo((BYTE*)pHotCode, (BYTE*)pColdCode, startOffset, endOffset, unwindCodeBytes, pUnwindBlock,
865 (CorJitFuncKind)func->funKind);
866}
867
868//------------------------------------------------------------------------
869// Compiler::unwindEmitFunc: Report the unwind information to the VM for a
870// given main function or funclet. Reports the hot section, then the cold
871// section if necessary.
872//
873// Arguments:
874// func - The main function or funclet to reserve unwind info for.
875// pHotCode - Pointer to the beginning of the memory with the function and funclet hot code.
876// pColdCode - Pointer to the beginning of the memory with the function and funclet cold code.
877//
878void Compiler::unwindEmitFunc(FuncInfoDsc* func, void* pHotCode, void* pColdCode)
879{
880 // Verify that the JIT enum is in sync with the JIT-EE interface enum
881 static_assert_no_msg(FUNC_ROOT == (FuncKind)CORJIT_FUNC_ROOT);
882 static_assert_no_msg(FUNC_HANDLER == (FuncKind)CORJIT_FUNC_HANDLER);
883 static_assert_no_msg(FUNC_FILTER == (FuncKind)CORJIT_FUNC_FILTER);
884
885 unwindEmitFuncHelper(func, pHotCode, pColdCode, true);
886
887 if (pColdCode != nullptr)
888 {
889 unwindEmitFuncHelper(func, pHotCode, pColdCode, false);
890 }
891}
892
893#endif // _TARGET_AMD64_
894