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.
5 /*XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
6 XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
10 XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
11 XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
19 #if defined(_TARGET_AMD64_)
21 int Compiler::mapRegNumToDwarfReg(regNumber reg)
23 int dwarfReg = DWARF_REG_ILLEGAL;
124 noway_assert(!"unexpected REG_NUM");
130 #endif // UNIX_AMD64_ABI
132 //------------------------------------------------------------------------
133 // Compiler::unwindBegProlog: Initialize the unwind info data structures.
134 // Called at the beginning of main function or funclet prolog generation.
136 void Compiler::unwindBegProlog()
138 #ifdef UNIX_AMD64_ABI
139 if (generateCFIUnwindCodes())
141 unwindBegPrologCFI();
144 #endif // UNIX_AMD64_ABI
146 unwindBegPrologWindows();
150 void Compiler::unwindBegPrologWindows()
152 assert(compGeneratingProlog);
154 FuncInfoDsc* func = funCurrentFunc();
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.
159 unwindGetFuncLocations(func, true, &func->startLoc, &func->endLoc);
161 if (fgFirstColdBlock != nullptr)
163 unwindGetFuncLocations(func, false, &func->coldStartLoc, &func->coldEndLoc);
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;
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.
178 void Compiler::unwindEndProlog()
180 assert(compGeneratingProlog);
183 //------------------------------------------------------------------------
184 // Compiler::unwindBegEpilog: Called at the beginning of main function or funclet
185 // epilog generation.
187 void Compiler::unwindBegEpilog()
189 assert(compGeneratingEpilog);
192 //------------------------------------------------------------------------
193 // Compiler::unwindEndEpilog: Called at the end of main function or funclet
194 // epilog generation.
196 void Compiler::unwindEndEpilog()
198 assert(compGeneratingEpilog);
201 //------------------------------------------------------------------------
202 // Compiler::unwindPush: Record a push/save of a register.
205 // reg - The register being pushed/saved.
207 void Compiler::unwindPush(regNumber reg)
209 #ifdef UNIX_AMD64_ABI
210 if (generateCFIUnwindCodes())
212 unwindPushPopCFI(reg);
215 #endif // UNIX_AMD64_ABI
217 unwindPushWindows(reg);
221 void Compiler::unwindPushWindows(regNumber reg)
223 assert(compGeneratingProlog);
225 FuncInfoDsc* func = funCurrentFunc();
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;
235 if ((RBM_CALLEE_SAVED & genRegMask(reg))
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
245 code->UnwindOp = UWOP_PUSH_NONVOL;
246 code->OpInfo = (BYTE)reg;
250 // Push of a volatile register is just a small stack allocation
251 code->UnwindOp = UWOP_ALLOC_SMALL;
256 #ifdef UNIX_AMD64_ABI
257 #endif // UNIX_AMD64_ABI
259 //------------------------------------------------------------------------
260 // Compiler::unwindAllocStack: Record a stack frame allocation (sub sp, X).
263 // size - The size of the stack frame allocation (the amount subtracted from the stack pointer).
265 void Compiler::unwindAllocStack(unsigned size)
267 #ifdef UNIX_AMD64_ABI
268 if (generateCFIUnwindCodes())
270 unwindAllocStackCFI(size);
273 #endif // UNIX_AMD64_ABI
275 unwindAllocStackWindows(size);
279 void Compiler::unwindAllocStackWindows(unsigned size)
281 assert(compGeneratingProlog);
283 FuncInfoDsc* func = funCurrentFunc();
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
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;
296 else if (size <= 0x7FFF8)
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;
307 assert(func->unwindCodeSlot > (sizeof(UNWIND_CODE) + sizeof(ULONG)));
308 ULONG* codedSize = (ULONG*)&func->unwindCodes[func->unwindCodeSlot -= sizeof(ULONG)];
310 code = (UNWIND_CODE*)&func->unwindCodes[func->unwindCodeSlot -= sizeof(UNWIND_CODE)];
311 code->UnwindOp = UWOP_ALLOC_LARGE;
314 unsigned int cbProlog = unwindGetCurrentOffset(func);
315 noway_assert((BYTE)cbProlog == cbProlog);
316 code->CodeOffset = (BYTE)cbProlog;
319 //------------------------------------------------------------------------
320 // Compiler::unwindSetFrameReg: Record a frame register.
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.
326 void Compiler::unwindSetFrameReg(regNumber reg, unsigned offset)
328 #ifdef UNIX_AMD64_ABI
329 if (generateCFIUnwindCodes())
331 unwindSetFrameRegCFI(reg, offset);
334 #endif // UNIX_AMD64_ABI
336 unwindSetFrameRegWindows(reg, offset);
340 void Compiler::unwindSetFrameRegWindows(regNumber reg, unsigned offset)
342 assert(compGeneratingProlog);
344 FuncInfoDsc* func = funCurrentFunc();
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);
351 func->unwindHeader.FrameRegister = (BYTE)reg;
353 #ifdef UNIX_AMD64_ABI
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.
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;
365 UNWIND_CODE* code = (UNWIND_CODE*)&func->unwindCodes[func->unwindCodeSlot -= sizeof(UNWIND_CODE)];
366 code->CodeOffset = (BYTE)cbProlog;
368 code->UnwindOp = UWOP_SET_FPREG_LARGE;
369 func->unwindHeader.FrameOffset = 15;
372 #endif // UNIX_AMD64_ABI
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;
378 code->UnwindOp = UWOP_SET_FPREG;
379 assert(offset <= 240);
380 assert(offset % 16 == 0);
381 func->unwindHeader.FrameOffset = offset / 16;
385 //------------------------------------------------------------------------
386 // Compiler::unwindSaveReg: Record a register save.
389 // reg - The register being saved.
390 // offset - The offset from the current stack pointer where the register is being saved.
392 void Compiler::unwindSaveReg(regNumber reg, unsigned offset)
394 #ifdef UNIX_AMD64_ABI
395 if (generateCFIUnwindCodes())
397 unwindSaveRegCFI(reg, offset);
400 #endif // UNIX_AMD64_ABI
402 unwindSaveRegWindows(reg, offset);
406 void Compiler::unwindSaveRegWindows(regNumber reg, unsigned offset)
408 assert(compGeneratingProlog);
410 FuncInfoDsc* func = funCurrentFunc();
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))
417 if (offset < 0x80000)
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)];
423 // As per AMD64 ABI, if saving entire xmm reg, then offset need to be scaled by 16.
424 if (genIsValidFloatReg(reg))
426 *codedSize = (USHORT)(offset / 16);
427 code->UnwindOp = UWOP_SAVE_XMM128;
431 *codedSize = (USHORT)(offset / 8);
432 code->UnwindOp = UWOP_SAVE_NONVOL;
437 assert(func->unwindCodeSlot > (sizeof(UNWIND_CODE) + sizeof(ULONG)));
438 ULONG* codedSize = (ULONG*)&func->unwindCodes[func->unwindCodeSlot -= sizeof(ULONG)];
440 code = (UNWIND_CODE*)&func->unwindCodes[func->unwindCodeSlot -= sizeof(UNWIND_CODE)];
441 code->UnwindOp = (genIsValidFloatReg(reg)) ? UWOP_SAVE_XMM128_FAR : UWOP_SAVE_NONVOL_FAR;
443 code->OpInfo = (BYTE)reg;
444 unsigned int cbProlog = unwindGetCurrentOffset(func);
445 noway_assert((BYTE)cbProlog == cbProlog);
446 code->CodeOffset = (BYTE)cbProlog;
450 #ifdef UNIX_AMD64_ABI
451 void Compiler::unwindSaveRegCFI(regNumber reg, unsigned offset)
453 assert(compGeneratingProlog);
455 if (RBM_CALLEE_SAVED & genRegMask(reg))
457 FuncInfoDsc* func = funCurrentFunc();
459 unsigned int cbProlog = unwindGetCurrentOffset(func);
460 noway_assert((BYTE)cbProlog == cbProlog);
461 createCfiCode(func, cbProlog, CFI_REL_OFFSET, mapRegNumToDwarfReg(reg), offset);
464 #endif // UNIX_AMD64_ABI
468 //------------------------------------------------------------------------
469 // DumpUnwindInfo: Dump the unwind data.
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.
477 void DumpUnwindInfo(bool isHotCode,
478 UNATIVE_OFFSET startOffset,
479 UNATIVE_OFFSET endOffset,
480 const UNWIND_INFO* const pHeader)
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));
486 if (pHeader == nullptr)
488 // Cold AMD64 code doesn't have unwind info; the VM creates chained unwind info.
493 printf(" Version : %u\n", pHeader->Version);
494 printf(" Flags : 0x%02x", pHeader->Flags);
497 const UCHAR flags = pHeader->Flags;
499 if (flags & UNW_FLAG_EHANDLER)
501 printf(" UNW_FLAG_EHANDLER");
503 if (flags & UNW_FLAG_UHANDLER)
505 printf(" UNW_FLAG_UHANDLER");
507 if (flags & UNW_FLAG_CHAININFO)
509 printf(" UNW_FLAG_CHAININFO");
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)
521 printf(" FrameOffset : N/A (no FrameRegister) (Value=%u)\n", pHeader->FrameOffset);
525 printf(" FrameOffset : %u * 16 = 0x%02X\n", pHeader->FrameOffset, pHeader->FrameOffset * 16);
527 printf(" UnwindCodes :\n");
529 for (unsigned i = 0; i < pHeader->CountOfUnwindCodes; i++)
532 const UNWIND_CODE* const pCode = &(pHeader->UnwindCode[i]);
533 switch (pCode->UnwindOp)
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);
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)
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);
549 else if (pCode->OpInfo == 1)
552 printf("Unscaled large\n Size: %u = 0x%08X\n\n", *(ULONG*)&(pHeader->UnwindCode[i]),
553 *(ULONG*)&(pHeader->UnwindCode[i]));
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);
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
572 #ifdef UNIX_AMD64_ABI
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
578 offset = *(ULONG*)&(pHeader->UnwindCode[i]);
580 printf(" Scaled Offset: %u * 16 = %u = 0x%08X\n", offset, offset * 16, offset * 16);
581 if ((offset & 0xF0000000) != 0)
583 printf(" Illegal unscaled offset: too large\n");
587 #endif // UNIX_AMD64_ABI
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);
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);
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);
601 printf(" Unscaled Large Offset: 0x%08X\n\n", *(ULONG*)&(pHeader->UnwindCode[i]));
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);
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);
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);
617 printf(" Unscaled Large Offset: 0x%08X\n\n", *(ULONG*)&(pHeader->UnwindCode[i]));
622 case UWOP_SPARE_CODE:
623 case UWOP_PUSH_MACHFRAME:
625 printf(" Unrecognized UNWIND_CODE: 0x%04X\n", *(USHORT*)pCode);
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.
639 void Compiler::unwindReserve()
641 assert(!compGeneratingProlog);
642 assert(!compGeneratingEpilog);
644 assert(compFuncInfoCount > 0);
645 for (unsigned funcIdx = 0; funcIdx < compFuncInfoCount; funcIdx++)
647 unwindReserveFunc(funGetFunc(funcIdx));
651 //------------------------------------------------------------------------
652 // Compiler::unwindReserveFunc: Reserve the unwind information from the VM for a
653 // given main function or funclet.
656 // func - The main function or funclet to reserve unwind info for.
658 void Compiler::unwindReserveFunc(FuncInfoDsc* func)
660 unwindReserveFuncHelper(func, true);
662 if (fgFirstColdBlock != nullptr)
664 unwindReserveFuncHelper(func, false);
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.
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.
676 void Compiler::unwindReserveFuncHelper(FuncInfoDsc* func, bool isHotCode)
678 DWORD unwindCodeBytes = 0;
681 #ifdef UNIX_AMD64_ABI
682 if (generateCFIUnwindCodes())
684 unwindCodeBytes = (DWORD)(func->cfiCodes->size() * sizeof(CFI_CODE));
687 #endif // UNIX_AMD64_ABI
689 assert(func->unwindHeader.Version == 1); // Can't call this before unwindBegProlog
690 assert(func->unwindHeader.CountOfUnwindCodes == 0); // Only call this once per prolog
692 // Set the size of the prolog to be the last encoded action
693 if (func->unwindCodeSlot < sizeof(func->unwindCodes))
695 UNWIND_CODE* code = (UNWIND_CODE*)&func->unwindCodes[func->unwindCodeSlot];
696 func->unwindHeader.SizeOfProlog = code->CodeOffset;
700 func->unwindHeader.SizeOfProlog = 0;
702 func->unwindHeader.CountOfUnwindCodes =
703 (BYTE)((sizeof(func->unwindCodes) - func->unwindCodeSlot) / sizeof(UNWIND_CODE));
705 // Prepend the unwindHeader onto the unwind codes
706 assert(func->unwindCodeSlot >= offsetof(UNWIND_INFO, UnwindCode));
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));
712 unwindCodeBytes = sizeof(func->unwindCodes) - func->unwindCodeSlot;
716 BOOL isFunclet = (func->funKind != FUNC_ROOT);
717 BOOL isColdCode = isHotCode ? FALSE : TRUE;
719 eeReserveUnwindInfo(isFunclet, isColdCode, unwindCodeBytes);
722 //------------------------------------------------------------------------
723 // Compiler::unwindEmit: Report all the unwind information to the VM.
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.
729 void Compiler::unwindEmit(void* pHotCode, void* pColdCode)
731 assert(!compGeneratingProlog);
732 assert(!compGeneratingEpilog);
734 assert(compFuncInfoCount > 0);
735 for (unsigned funcIdx = 0; funcIdx < compFuncInfoCount; funcIdx++)
737 unwindEmitFunc(funGetFunc(funcIdx), pHotCode, pColdCode);
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.
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.
752 void Compiler::unwindEmitFuncHelper(FuncInfoDsc* func, void* pHotCode, void* pColdCode, bool isHotCode)
754 UNATIVE_OFFSET startOffset;
755 UNATIVE_OFFSET endOffset;
756 DWORD unwindCodeBytes = 0;
757 BYTE* pUnwindBlock = nullptr;
761 if (func->startLoc == nullptr)
767 startOffset = func->startLoc->CodeOffset(genEmitter);
770 if (func->endLoc == nullptr)
772 endOffset = info.compNativeCodeSize;
776 endOffset = func->endLoc->CodeOffset(genEmitter);
779 #ifdef UNIX_AMD64_ABI
780 if (generateCFIUnwindCodes())
782 DWORD size = (DWORD)func->cfiCodes->size();
785 unwindCodeBytes = size * sizeof(CFI_CODE);
786 pUnwindBlock = (BYTE*)&(*func->cfiCodes)[0];
790 #endif // UNIX_AMD64_ABI
792 unwindCodeBytes = sizeof(func->unwindCodes) - func->unwindCodeSlot;
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);
803 pUnwindBlock = &func->unwindCodes[func->unwindCodeSlot];
808 assert(fgFirstColdBlock != nullptr);
809 assert(func->funKind == FUNC_ROOT); // No splitting of funclets.
811 if (func->coldStartLoc == nullptr)
817 startOffset = func->coldStartLoc->CodeOffset(genEmitter);
820 if (func->coldEndLoc == nullptr)
822 endOffset = info.compNativeCodeSize;
826 endOffset = func->coldEndLoc->CodeOffset(genEmitter);
833 #ifdef UNIX_AMD64_ABI
834 if (generateCFIUnwindCodes())
836 DumpCfiInfo(isHotCode, startOffset, endOffset, unwindCodeBytes, (const CFI_CODE* const)pUnwindBlock);
839 #endif // UNIX_AMD64_ABI
841 DumpUnwindInfo(isHotCode, startOffset, endOffset, (const UNWIND_INFO* const)pUnwindBlock);
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
853 assert(endOffset <= info.compTotalHotCodeSize);
858 assert(startOffset >= info.compTotalHotCodeSize);
859 startOffset -= info.compTotalHotCodeSize;
860 endOffset -= info.compTotalHotCodeSize;
863 eeAllocUnwindInfo((BYTE*)pHotCode, (BYTE*)pColdCode, startOffset, endOffset, unwindCodeBytes, pUnwindBlock,
864 (CorJitFuncKind)func->funKind);
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.
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.
877 void Compiler::unwindEmitFunc(FuncInfoDsc* func, void* pHotCode, void* pColdCode)
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);
884 unwindEmitFuncHelper(func, pHotCode, pColdCode, true);
886 if (pColdCode != nullptr)
888 unwindEmitFuncHelper(func, pHotCode, pColdCode, false);
892 #endif // _TARGET_AMD64_