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 void Compiler::createCfiCode(FuncInfoDsc* func, UCHAR codeOffset, UCHAR cfiOpcode, USHORT dwarfReg, INT offset)
132 CFI_CODE cfiEntry(codeOffset, cfiOpcode, dwarfReg, offset);
133 func->cfiCodes->push_back(cfiEntry);
135 #endif // UNIX_AMD64_ABI
137 //------------------------------------------------------------------------
138 // Compiler::unwindGetCurrentOffset: Calculate the current byte offset of the
139 // prolog being generated.
142 // func - The main function or funclet of interest.
145 // The byte offset of the prolog currently being generated.
147 UNATIVE_OFFSET Compiler::unwindGetCurrentOffset(FuncInfoDsc* func)
149 assert(compGeneratingProlog);
150 UNATIVE_OFFSET offset;
151 if (func->funKind == FUNC_ROOT)
153 offset = genEmitter->emitGetPrologOffsetEstimate();
157 assert(func->startLoc != nullptr);
158 offset = func->startLoc->GetFuncletPrologOffset(genEmitter);
164 //------------------------------------------------------------------------
165 // Compiler::unwindBegProlog: Initialize the unwind info data structures.
166 // Called at the beginning of main function or funclet prolog generation.
168 void Compiler::unwindBegProlog()
170 #ifdef UNIX_AMD64_ABI
171 if (generateCFIUnwindCodes())
173 unwindBegPrologCFI();
176 #endif // UNIX_AMD64_ABI
178 unwindBegPrologWindows();
182 void Compiler::unwindBegPrologWindows()
184 assert(compGeneratingProlog);
186 FuncInfoDsc* func = funCurrentFunc();
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.
191 unwindGetFuncLocations(func, true, &func->startLoc, &func->endLoc);
193 if (fgFirstColdBlock != nullptr)
195 unwindGetFuncLocations(func, false, &func->coldStartLoc, &func->coldEndLoc);
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;
206 #ifdef UNIX_AMD64_ABI
207 template <typename T>
208 inline static T* allocate_any(jitstd::allocator<void>& alloc, size_t count = 5)
210 return jitstd::allocator<T>(alloc).allocate(count);
212 typedef jitstd::vector<CFI_CODE> CFICodeVector;
214 void Compiler::unwindBegPrologCFI()
216 assert(compGeneratingProlog);
218 FuncInfoDsc* func = funCurrentFunc();
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.
223 unwindGetFuncLocations(func, true, &func->startLoc, &func->endLoc);
225 if (fgFirstColdBlock != nullptr)
227 unwindGetFuncLocations(func, false, &func->coldStartLoc, &func->coldEndLoc);
230 jitstd::allocator<void> allocator(getAllocator());
232 func->cfiCodes = new (allocate_any<CFICodeVector>(allocator), jitstd::placement_t()) CFICodeVector(allocator);
234 #endif // UNIX_AMD64_ABI
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.
240 void Compiler::unwindEndProlog()
242 assert(compGeneratingProlog);
245 //------------------------------------------------------------------------
246 // Compiler::unwindBegEpilog: Called at the beginning of main function or funclet
247 // epilog generation.
249 void Compiler::unwindBegEpilog()
251 assert(compGeneratingEpilog);
254 //------------------------------------------------------------------------
255 // Compiler::unwindEndEpilog: Called at the end of main function or funclet
256 // epilog generation.
258 void Compiler::unwindEndEpilog()
260 assert(compGeneratingEpilog);
263 //------------------------------------------------------------------------
264 // Compiler::unwindPush: Record a push/save of a register.
267 // reg - The register being pushed/saved.
269 void Compiler::unwindPush(regNumber reg)
271 #ifdef UNIX_AMD64_ABI
272 if (generateCFIUnwindCodes())
277 #endif // UNIX_AMD64_ABI
279 unwindPushWindows(reg);
283 void Compiler::unwindPushWindows(regNumber reg)
285 assert(compGeneratingProlog);
287 FuncInfoDsc* func = funCurrentFunc();
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;
297 if ((RBM_CALLEE_SAVED & genRegMask(reg))
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
307 code->UnwindOp = UWOP_PUSH_NONVOL;
308 code->OpInfo = (BYTE)reg;
312 // Push of a volatile register is just a small stack allocation
313 code->UnwindOp = UWOP_ALLOC_SMALL;
318 #ifdef UNIX_AMD64_ABI
319 void Compiler::unwindPushCFI(regNumber reg)
321 assert(compGeneratingProlog);
323 FuncInfoDsc* func = funCurrentFunc();
325 unsigned int cbProlog = unwindGetCurrentOffset(func);
326 noway_assert((BYTE)cbProlog == cbProlog);
328 createCfiCode(func, cbProlog, CFI_ADJUST_CFA_OFFSET, DWARF_REG_ILLEGAL, 8);
329 if ((RBM_CALLEE_SAVED & genRegMask(reg))
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
339 createCfiCode(func, cbProlog, CFI_REL_OFFSET, mapRegNumToDwarfReg(reg));
342 #endif // UNIX_AMD64_ABI
344 //------------------------------------------------------------------------
345 // Compiler::unwindAllocStack: Record a stack frame allocation (sub sp, X).
348 // size - The size of the stack frame allocation (the amount subtracted from the stack pointer).
350 void Compiler::unwindAllocStack(unsigned size)
352 #ifdef UNIX_AMD64_ABI
353 if (generateCFIUnwindCodes())
355 unwindAllocStackCFI(size);
358 #endif // UNIX_AMD64_ABI
360 unwindAllocStackWindows(size);
364 void Compiler::unwindAllocStackWindows(unsigned size)
366 assert(compGeneratingProlog);
368 FuncInfoDsc* func = funCurrentFunc();
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
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;
381 else if (size <= 0x7FFF8)
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;
392 assert(func->unwindCodeSlot > (sizeof(UNWIND_CODE) + sizeof(ULONG)));
393 ULONG* codedSize = (ULONG*)&func->unwindCodes[func->unwindCodeSlot -= sizeof(ULONG)];
395 code = (UNWIND_CODE*)&func->unwindCodes[func->unwindCodeSlot -= sizeof(UNWIND_CODE)];
396 code->UnwindOp = UWOP_ALLOC_LARGE;
399 unsigned int cbProlog = unwindGetCurrentOffset(func);
400 noway_assert((BYTE)cbProlog == cbProlog);
401 code->CodeOffset = (BYTE)cbProlog;
404 #ifdef UNIX_AMD64_ABI
405 void Compiler::unwindAllocStackCFI(unsigned size)
407 assert(compGeneratingProlog);
409 FuncInfoDsc* func = funCurrentFunc();
411 unsigned int cbProlog = unwindGetCurrentOffset(func);
412 noway_assert((BYTE)cbProlog == cbProlog);
413 createCfiCode(func, cbProlog, CFI_ADJUST_CFA_OFFSET, DWARF_REG_ILLEGAL, size);
415 #endif // UNIX_AMD64_ABI
417 //------------------------------------------------------------------------
418 // Compiler::unwindSetFrameReg: Record a frame register.
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.
424 void Compiler::unwindSetFrameReg(regNumber reg, unsigned offset)
426 #ifdef UNIX_AMD64_ABI
427 if (generateCFIUnwindCodes())
429 unwindSetFrameRegCFI(reg, offset);
432 #endif // UNIX_AMD64_ABI
434 unwindSetFrameRegWindows(reg, offset);
438 void Compiler::unwindSetFrameRegWindows(regNumber reg, unsigned offset)
440 assert(compGeneratingProlog);
442 FuncInfoDsc* func = funCurrentFunc();
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);
449 func->unwindHeader.FrameRegister = (BYTE)reg;
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.
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;
463 UNWIND_CODE* code = (UNWIND_CODE*)&func->unwindCodes[func->unwindCodeSlot -= sizeof(UNWIND_CODE)];
464 code->CodeOffset = (BYTE)cbProlog;
466 code->UnwindOp = UWOP_SET_FPREG_LARGE;
467 func->unwindHeader.FrameOffset = 15;
470 #endif // PLATFORM_UNIX
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;
476 code->UnwindOp = UWOP_SET_FPREG;
477 assert(offset <= 240);
478 assert(offset % 16 == 0);
479 func->unwindHeader.FrameOffset = offset / 16;
483 #ifdef UNIX_AMD64_ABI
484 //------------------------------------------------------------------------
485 // Compiler::unwindSetFrameRegCFI: Record a cfi info for a frame register set.
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.
491 void Compiler::unwindSetFrameRegCFI(regNumber reg, unsigned offset)
493 assert(compGeneratingProlog);
494 FuncInfoDsc* func = funCurrentFunc();
496 unsigned int cbProlog = unwindGetCurrentOffset(func);
497 noway_assert((BYTE)cbProlog == cbProlog);
499 createCfiCode(func, cbProlog, CFI_DEF_CFA_REGISTER, mapRegNumToDwarfReg(reg));
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;
507 int adjust = -(int)offset;
508 createCfiCode(func, cbProlog, CFI_ADJUST_CFA_OFFSET, DWARF_REG_ILLEGAL, adjust);
511 #endif // UNIX_AMD64_ABI
513 //------------------------------------------------------------------------
514 // Compiler::unwindSaveReg: Record a register save.
517 // reg - The register being saved.
518 // offset - The offset from the current stack pointer where the register is being saved.
520 void Compiler::unwindSaveReg(regNumber reg, unsigned offset)
522 #ifdef UNIX_AMD64_ABI
523 if (generateCFIUnwindCodes())
525 unwindSaveRegCFI(reg, offset);
528 #endif // UNIX_AMD64_ABI
530 unwindSaveRegWindows(reg, offset);
534 void Compiler::unwindSaveRegWindows(regNumber reg, unsigned offset)
536 assert(compGeneratingProlog);
538 FuncInfoDsc* func = funCurrentFunc();
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))
545 if (offset < 0x80000)
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)];
551 // As per AMD64 ABI, if saving entire xmm reg, then offset need to be scaled by 16.
552 if (genIsValidFloatReg(reg))
554 *codedSize = (USHORT)(offset / 16);
555 code->UnwindOp = UWOP_SAVE_XMM128;
559 *codedSize = (USHORT)(offset / 8);
560 code->UnwindOp = UWOP_SAVE_NONVOL;
565 assert(func->unwindCodeSlot > (sizeof(UNWIND_CODE) + sizeof(ULONG)));
566 ULONG* codedSize = (ULONG*)&func->unwindCodes[func->unwindCodeSlot -= sizeof(ULONG)];
568 code = (UNWIND_CODE*)&func->unwindCodes[func->unwindCodeSlot -= sizeof(UNWIND_CODE)];
569 code->UnwindOp = (genIsValidFloatReg(reg)) ? UWOP_SAVE_XMM128_FAR : UWOP_SAVE_NONVOL_FAR;
571 code->OpInfo = (BYTE)reg;
572 unsigned int cbProlog = unwindGetCurrentOffset(func);
573 noway_assert((BYTE)cbProlog == cbProlog);
574 code->CodeOffset = (BYTE)cbProlog;
578 #ifdef UNIX_AMD64_ABI
579 void Compiler::unwindSaveRegCFI(regNumber reg, unsigned offset)
581 assert(compGeneratingProlog);
583 if (RBM_CALLEE_SAVED & genRegMask(reg))
585 FuncInfoDsc* func = funCurrentFunc();
587 unsigned int cbProlog = unwindGetCurrentOffset(func);
588 noway_assert((BYTE)cbProlog == cbProlog);
589 createCfiCode(func, cbProlog, CFI_REL_OFFSET, mapRegNumToDwarfReg(reg), offset);
592 #endif // UNIX_AMD64_ABI
596 //------------------------------------------------------------------------
597 // DumpUnwindInfo: Dump the unwind data.
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.
605 void DumpUnwindInfo(bool isHotCode,
606 UNATIVE_OFFSET startOffset,
607 UNATIVE_OFFSET endOffset,
608 const UNWIND_INFO* const pHeader)
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));
614 if (pHeader == nullptr)
616 // Cold AMD64 code doesn't have unwind info; the VM creates chained unwind info.
621 printf(" Version : %u\n", pHeader->Version);
622 printf(" Flags : 0x%02x", pHeader->Flags);
625 const UCHAR flags = pHeader->Flags;
627 if (flags & UNW_FLAG_EHANDLER)
629 printf(" UNW_FLAG_EHANDLER");
631 if (flags & UNW_FLAG_UHANDLER)
633 printf(" UNW_FLAG_UHANDLER");
635 if (flags & UNW_FLAG_CHAININFO)
637 printf(" UNW_FLAG_CHAININFO");
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)
649 printf(" FrameOffset : N/A (no FrameRegister) (Value=%u)\n", pHeader->FrameOffset);
653 printf(" FrameOffset : %u * 16 = 0x%02X\n", pHeader->FrameOffset, pHeader->FrameOffset * 16);
655 printf(" UnwindCodes :\n");
657 for (unsigned i = 0; i < pHeader->CountOfUnwindCodes; i++)
660 const UNWIND_CODE* const pCode = &(pHeader->UnwindCode[i]);
661 switch (pCode->UnwindOp)
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);
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)
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);
677 else if (pCode->OpInfo == 1)
680 printf("Unscaled large\n Size: %u = 0x%08X\n\n", *(ULONG*)&(pHeader->UnwindCode[i]),
681 *(ULONG*)&(pHeader->UnwindCode[i]));
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);
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
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
706 offset = *(ULONG*)&(pHeader->UnwindCode[i]);
708 printf(" Scaled Offset: %u * 16 = %u = 0x%08X\n", offset, offset * 16, offset * 16);
709 if ((offset & 0xF0000000) != 0)
711 printf(" Illegal unscaled offset: too large\n");
715 #endif // PLATFORM_UNIX
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);
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);
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);
729 printf(" Unscaled Large Offset: 0x%08X\n\n", *(ULONG*)&(pHeader->UnwindCode[i]));
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);
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);
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);
745 printf(" Unscaled Large Offset: 0x%08X\n\n", *(ULONG*)&(pHeader->UnwindCode[i]));
750 case UWOP_SPARE_CODE:
751 case UWOP_PUSH_MACHFRAME:
753 printf(" Unrecognized UNWIND_CODE: 0x%04X\n", *(USHORT*)pCode);
759 #ifdef UNIX_AMD64_ABI
760 //------------------------------------------------------------------------
761 // DumpCfiInfo: Dump the Cfi data.
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.
769 void DumpCfiInfo(bool isHotCode,
770 UNATIVE_OFFSET startOffset,
771 UNATIVE_OFFSET endOffset,
773 const CFI_CODE* const pCfiCode)
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));
779 for (int i = 0; i < cfiCodeBytes / sizeof(CFI_CODE); i++)
781 const CFI_CODE* const pCode = &(pCfiCode[i]);
783 UCHAR codeOffset = pCode->CodeOffset;
784 SHORT dwarfReg = pCode->DwarfReg;
785 INT offset = pCode->Offset;
787 switch (pCode->CfiOpCode)
790 printf(" CodeOffset: 0x%02X Op: RelOffset DwarfReg:0x%x Offset:0x%X\n", codeOffset, dwarfReg,
793 case CFI_DEF_CFA_REGISTER:
795 printf(" CodeOffset: 0x%02X Op: DefCfaRegister DwarfReg:0x%X\n", codeOffset, dwarfReg);
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);
802 printf(" Unrecognized CFI_CODE: 0x%IX\n", *(UINT64*)pCode);
807 #endif // UNIX_AMD64_ABI
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.
816 void Compiler::unwindReserve()
818 assert(!compGeneratingProlog);
819 assert(!compGeneratingEpilog);
821 assert(compFuncInfoCount > 0);
822 for (unsigned funcIdx = 0; funcIdx < compFuncInfoCount; funcIdx++)
824 unwindReserveFunc(funGetFunc(funcIdx));
828 //------------------------------------------------------------------------
829 // Compiler::unwindReserveFunc: Reserve the unwind information from the VM for a
830 // given main function or funclet.
833 // func - The main function or funclet to reserve unwind info for.
835 void Compiler::unwindReserveFunc(FuncInfoDsc* func)
837 unwindReserveFuncHelper(func, true);
839 if (fgFirstColdBlock != nullptr)
841 unwindReserveFuncHelper(func, false);
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.
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.
853 void Compiler::unwindReserveFuncHelper(FuncInfoDsc* func, bool isHotCode)
855 DWORD unwindCodeBytes = 0;
858 #ifdef UNIX_AMD64_ABI
859 if (generateCFIUnwindCodes())
861 unwindCodeBytes = func->cfiCodes->size() * sizeof(CFI_CODE);
864 #endif // UNIX_AMD64_ABI
866 assert(func->unwindHeader.Version == 1); // Can't call this before unwindBegProlog
867 assert(func->unwindHeader.CountOfUnwindCodes == 0); // Only call this once per prolog
869 // Set the size of the prolog to be the last encoded action
870 if (func->unwindCodeSlot < sizeof(func->unwindCodes))
872 UNWIND_CODE* code = (UNWIND_CODE*)&func->unwindCodes[func->unwindCodeSlot];
873 func->unwindHeader.SizeOfProlog = code->CodeOffset;
877 func->unwindHeader.SizeOfProlog = 0;
879 func->unwindHeader.CountOfUnwindCodes =
880 (BYTE)((sizeof(func->unwindCodes) - func->unwindCodeSlot) / sizeof(UNWIND_CODE));
882 // Prepend the unwindHeader onto the unwind codes
883 assert(func->unwindCodeSlot >= offsetof(UNWIND_INFO, UnwindCode));
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));
889 unwindCodeBytes = sizeof(func->unwindCodes) - func->unwindCodeSlot;
893 BOOL isFunclet = (func->funKind != FUNC_ROOT);
894 BOOL isColdCode = isHotCode ? FALSE : TRUE;
896 eeReserveUnwindInfo(isFunclet, isColdCode, unwindCodeBytes);
899 //------------------------------------------------------------------------
900 // Compiler::unwindEmit: Report all the unwind information to the VM.
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.
906 void Compiler::unwindEmit(void* pHotCode, void* pColdCode)
908 assert(!compGeneratingProlog);
909 assert(!compGeneratingEpilog);
911 assert(compFuncInfoCount > 0);
912 for (unsigned funcIdx = 0; funcIdx < compFuncInfoCount; funcIdx++)
914 unwindEmitFunc(funGetFunc(funcIdx), pHotCode, pColdCode);
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.
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.
929 void Compiler::unwindEmitFuncHelper(FuncInfoDsc* func, void* pHotCode, void* pColdCode, bool isHotCode)
931 UNATIVE_OFFSET startOffset;
932 UNATIVE_OFFSET endOffset;
933 DWORD unwindCodeBytes = 0;
934 BYTE* pUnwindBlock = nullptr;
938 if (func->startLoc == nullptr)
944 startOffset = func->startLoc->CodeOffset(genEmitter);
947 if (func->endLoc == nullptr)
949 endOffset = info.compNativeCodeSize;
953 endOffset = func->endLoc->CodeOffset(genEmitter);
956 #ifdef UNIX_AMD64_ABI
957 if (generateCFIUnwindCodes())
959 int size = func->cfiCodes->size();
962 unwindCodeBytes = size * sizeof(CFI_CODE);
963 pUnwindBlock = (BYTE*)&(*func->cfiCodes)[0];
967 #endif // UNIX_AMD64_ABI
969 unwindCodeBytes = sizeof(func->unwindCodes) - func->unwindCodeSlot;
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);
980 pUnwindBlock = &func->unwindCodes[func->unwindCodeSlot];
985 assert(fgFirstColdBlock != nullptr);
986 assert(func->funKind == FUNC_ROOT); // No splitting of funclets.
988 if (func->coldStartLoc == nullptr)
994 startOffset = func->coldStartLoc->CodeOffset(genEmitter);
997 if (func->coldEndLoc == nullptr)
999 endOffset = info.compNativeCodeSize;
1003 endOffset = func->coldEndLoc->CodeOffset(genEmitter);
1010 #ifdef UNIX_AMD64_ABI
1011 if (generateCFIUnwindCodes())
1013 DumpCfiInfo(isHotCode, startOffset, endOffset, unwindCodeBytes, (const CFI_CODE* const)pUnwindBlock);
1016 #endif // UNIX_AMD64_ABI
1018 DumpUnwindInfo(isHotCode, startOffset, endOffset, (const UNWIND_INFO* const)pUnwindBlock);
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
1030 assert(endOffset <= info.compTotalHotCodeSize);
1031 pColdCode = nullptr;
1035 assert(startOffset >= info.compTotalHotCodeSize);
1036 startOffset -= info.compTotalHotCodeSize;
1037 endOffset -= info.compTotalHotCodeSize;
1040 eeAllocUnwindInfo((BYTE*)pHotCode, (BYTE*)pColdCode, startOffset, endOffset, unwindCodeBytes, pUnwindBlock,
1041 (CorJitFuncKind)func->funKind);
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.
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.
1054 void Compiler::unwindEmitFunc(FuncInfoDsc* func, void* pHotCode, void* pColdCode)
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);
1061 unwindEmitFuncHelper(func, pHotCode, pColdCode, true);
1063 if (pColdCode != nullptr)
1065 unwindEmitFuncHelper(func, pHotCode, pColdCode, false);
1069 #endif // _TARGET_AMD64_