//------------------------------------------------------------------------ // DumpCfiInfo: Dump the Cfi data. // // Arguments: // isHotCode - true if this cfi data is for the hot section, false otherwise. // startOffset - byte offset of the code start that this cfi data represents. // endOffset - byte offset of the code end that this cfi data represents. // pcFiCode - pointer to the cfi data blob. // void DumpCfiInfo(bool isHotCode, UNATIVE_OFFSET startOffset, UNATIVE_OFFSET endOffset, DWORD cfiCodeBytes, const CFI_CODE * const pCfiCode) { printf("Cfi Info%s:\n", isHotCode ? "" : " COLD"); printf(" >> Start offset : 0x%06x \n", dspOffset(startOffset)); printf(" >> End offset : 0x%06x \n", dspOffset(endOffset)); for (int i = 0; i < cfiCodeBytes / sizeof(CFI_CODE); i++) { const CFI_CODE * const pCode = &(pCfiCode[i]); UCHAR codeOffset = pCode->CodeOffset; SHORT dwarfReg = pCode->DwarfReg; INT offset = pCode->Offset; switch (pCode->CfiOpCode) { case CFI_REL_OFFSET: printf(" CodeOffset: 0x%02X Op: RelOffset DwarfReg:0x%x Offset:0x%X\n", codeOffset, dwarfReg, offset); break; case CFI_DEF_CFA_REGISTER: assert(offset == 0); printf(" CodeOffset: 0x%02X Op: DefCfaRegister DwarfReg:0x%X\n", codeOffset, dwarfReg); break; case CFI_ADJUST_CFA_OFFSET: assert(dwarfReg == DWARF_REG_ILLEGAL); printf(" CodeOffset: 0x%02X Op: AdjustCfaOffset Offset:0x%X\n", codeOffset, offset); break; default: printf(" Unrecognized CFI_CODE: 0x%IX\n", *(UINT64*)pCode); break; } } }
//------------------------------------------------------------------------ // DumpUnwindInfo: Dump the unwind data. // // Arguments: // isHotCode - true if this unwind data is for the hot section, false otherwise. // startOffset - byte offset of the code start that this unwind data represents. // endOffset - byte offset of the code end that this unwind data represents. // pHeader - pointer to the unwind data blob. // void DumpUnwindInfo(bool isHotCode, UNATIVE_OFFSET startOffset, UNATIVE_OFFSET endOffset, const UNWIND_INFO * const pHeader) { printf("Unwind Info%s:\n", isHotCode ? "" : " COLD"); printf(" >> Start offset : 0x%06x (not in unwind data)\n", dspOffset(startOffset)); printf(" >> End offset : 0x%06x (not in unwind data)\n", dspOffset(endOffset)); if (pHeader == nullptr) { // Cold AMD64 code doesn't have unwind info; the VM creates chained unwind info. assert(!isHotCode); return; } printf(" Version : %u\n", pHeader->Version); printf(" Flags : 0x%02x", pHeader->Flags); if (pHeader->Flags) { const UCHAR flags = pHeader->Flags; printf(" ("); if (flags & UNW_FLAG_EHANDLER) printf(" UNW_FLAG_EHANDLER"); if (flags & UNW_FLAG_UHANDLER) printf(" UNW_FLAG_UHANDLER"); if (flags & UNW_FLAG_CHAININFO) printf(" UNW_FLAG_CHAININFO"); printf(")"); } printf("\n"); printf(" SizeOfProlog : 0x%02X\n", pHeader->SizeOfProlog); printf(" CountOfUnwindCodes: %u\n", pHeader->CountOfUnwindCodes); printf(" FrameRegister : %s (%u)\n", (pHeader->FrameRegister == 0) ? "none" : getRegName(pHeader->FrameRegister), pHeader->FrameRegister); // RAX (0) is not allowed as a frame register if (pHeader->FrameRegister == 0) { printf(" FrameOffset : N/A (no FrameRegister) (Value=%u)\n", pHeader->FrameOffset); } else { printf(" FrameOffset : %u * 16 = 0x%02X\n", pHeader->FrameOffset, pHeader->FrameOffset * 16); } printf(" UnwindCodes :\n"); for (unsigned i = 0; i < pHeader->CountOfUnwindCodes; i++) { const UNWIND_CODE * const pCode = &(pHeader->UnwindCode[i]); switch (pCode->UnwindOp) { case UWOP_PUSH_NONVOL: printf(" CodeOffset: 0x%02X UnwindOp: UWOP_PUSH_NONVOL (%u) OpInfo: %s (%u)\n", pCode->CodeOffset, pCode->UnwindOp, getRegName(pCode->OpInfo), pCode->OpInfo); break; case UWOP_ALLOC_LARGE: printf(" CodeOffset: 0x%02X UnwindOp: UWOP_ALLOC_LARGE (%u) OpInfo: %u - ", pCode->CodeOffset, pCode->UnwindOp, pCode->OpInfo); if (pCode->OpInfo == 0) { i++; printf("Scaled small \n Size: %u * 8 = %u = 0x%05X\n", pHeader->UnwindCode[i].FrameOffset, pHeader->UnwindCode[i].FrameOffset * 8, pHeader->UnwindCode[i].FrameOffset * 8); } else if (pCode->OpInfo == 1) { i++; printf("Unscaled large\n Size: %u = 0x%08X\n\n", *(ULONG*)&(pHeader->UnwindCode[i]), *(ULONG*)&(pHeader->UnwindCode[i])); i++; } else { printf("Unknown\n"); } break; case UWOP_ALLOC_SMALL: printf(" CodeOffset: 0x%02X UnwindOp: UWOP_ALLOC_SMALL (%u) OpInfo: %u * 8 + 8 = %u = 0x%02X\n", pCode->CodeOffset, pCode->UnwindOp, pCode->OpInfo, pCode->OpInfo * 8 + 8, pCode->OpInfo * 8 + 8); break; case UWOP_SET_FPREG: printf(" CodeOffset: 0x%02X UnwindOp: UWOP_SET_FPREG (%u) OpInfo: Unused (%u)\n", pCode->CodeOffset, pCode->UnwindOp, pCode->OpInfo); // This should be zero break; case UWOP_SAVE_NONVOL: printf(" CodeOffset: 0x%02X UnwindOp: UWOP_SAVE_NONVOL (%u) OpInfo: %s (%u)\n", pCode->CodeOffset, pCode->UnwindOp, getRegName(pCode->OpInfo), pCode->OpInfo); i++; printf(" Scaled Small Offset: %u * 8 = %u = 0x%05X\n", pHeader->UnwindCode[i].FrameOffset, pHeader->UnwindCode[i].FrameOffset * 8, pHeader->UnwindCode[i].FrameOffset * 8); break; case UWOP_SAVE_NONVOL_FAR: printf(" CodeOffset: 0x%02X UnwindOp: UWOP_SAVE_NONVOL_FAR (%u) OpInfo: %s (%u)\n", pCode->CodeOffset, pCode->UnwindOp, getRegName(pCode->OpInfo), pCode->OpInfo); i++; printf(" Unscaled Large Offset: 0x%08X\n\n", *(ULONG*)&(pHeader->UnwindCode[i])); i++; break; case UWOP_SAVE_XMM128: printf(" CodeOffset: 0x%02X UnwindOp: UWOP_SAVE_XMM128 (%u) OpInfo: XMM%u (%u)\n", pCode->CodeOffset, pCode->UnwindOp, pCode->OpInfo, pCode->OpInfo); i++; printf(" Scaled Small Offset: %u * 16 = %u = 0x%05X\n", pHeader->UnwindCode[i].FrameOffset, pHeader->UnwindCode[i].FrameOffset * 16, pHeader->UnwindCode[i].FrameOffset * 16); break; case UWOP_SAVE_XMM128_FAR: printf(" CodeOffset: 0x%02X UnwindOp: UWOP_SAVE_XMM128_FAR (%u) OpInfo: XMM%u (%u)\n", pCode->CodeOffset, pCode->UnwindOp, pCode->OpInfo, pCode->OpInfo); i++; printf(" Unscaled Large Offset: 0x%08X\n\n", *(ULONG*)&(pHeader->UnwindCode[i])); i++; break; case UWOP_EPILOG: case UWOP_SPARE_CODE: case UWOP_PUSH_MACHFRAME: default: printf(" Unrecognized UNWIND_CODE: 0x%04X\n", *(USHORT*)pCode); break; } } }