/** *** Copyright (C) 1996-1999 Intel Corporation. All rights reserved. *** *** The information and source code contained herein is the exclusive *** property of Intel Corporation and may not be disclosed, examined *** or reproduced in whole or in part without explicit written authorization *** from the company. *** **************************************************************************** *** *** WARNING: ntos\rtl\ia64\vunwind.c and sdktools\imagehlp\vwndia64.c are *** identical. For sake of maintenance and for debug purposes, ** please keep them as this. Thank you. *** **************************************************************************** **/ #if !defined(BUILD_DBGHELP) && !defined(BUILD_IMAGEHLP) #include "ntrtlp.h" #else // !BUILD_DBGHELP && !BUILD_IMAGEHLP #define TARGET_IA64 #define _CROSS_PLATFORM_ #define _IA64REG_ #include "walk.h" #include "private.h" #include #endif // !BUILD_DBGHELP && !BUILD_IMAGEHLP #ifdef _IMAGEHLP_SOURCE_ #define NOT_IMAGEHLP(E) #define FUNCTION_ENTRY_IS_IMAGE_STYLE #define RtlVirtualUnwind VirtualUnwindIa64 #define PRUNTIME_FUNCTION PIMAGE_RUNTIME_FUNCTION_ENTRY #define RUNTIME_FUNCTION IMAGE_RUNTIME_FUNCTION_ENTRY #define VUW_DEBUG_PRINT OutputDebugString #else // !_IMAGEHLP_SOURCE_ #define NOT_IMAGEHLP(E) E #define VUW_DEBUG_PRINT DbgPrint #endif // !_IMAGEHLP_SOURCE_ #ifdef MASK #undef MASK #endif // MASK #define MASK(bp,value) (value << bp) // // ABI values // #define SVR4_ABI 0 #define HPUX_ABI 1 #define NT_ABI 2 #ifdef KERNEL_DEBUGGER #define FUNCTION_ENTRY_IS_IMAGE_STYLE #define RtlVirtualUnwind VirtualUnwind #endif #define STATE_RECORD_STACK_SIZE 32 #define SPILLSIZE_OF_FLOAT128_IN_DWORDS 4 #define SPILLSIZE_OF_ULONGLONG_IN_DWORDS 2 #define REGISTER_SIZE sizeof(ULONGLONG) #define STATIC_REGISTER_SET_SIZE 32 #define SLOTS_PER_BUNDLE 3 #define R1_MASK 0xC0 #define R1_PREFIX 0x0 #define R1_REGION_TYPE_MASK 0x20 #define R1_LENGTH_MASK 0x1F #define R2_MASK 0xE0 #define R2_PREFIX 0x40 #define R3_MASK 0xE0 #define R3_PREFIX 0x60 #define R3_REGION_TYPE_MASK 0x3 #define P1_MASK 0xE0 #define P1_PREFIX 0x80 #define P2_MASK 0xF0 #define P2_PREFIX 0xA0 #define P3_MASK 0xF8 #define P3_PREFIX 0xB0 #define P4_MASK 0xFF #define P4_PREFIX 0xB8 #define P5_MASK 0xFF #define P5_PREFIX 0xB9 #define P6_MASK 0xE0 #define P6_PREFIX 0xC0 #define P7_MASK 0xF0 #define P7_PREFIX 0xE0 #define P8_MASK 0xFF #define P8_PREFIX 0xF0 #define P9_MASK 0xFF #define P9_PREFIX 0xF1 #define P10_MASK 0xFF #define P10_PREFIX 0xFF #define B1_MASK 0xC0 #define B1_PREFIX 0x80 #define B1_TYPE_MASK 0x20 #define B1_LABEL_MASK 0x1F #define B2_MASK 0xE0 #define B2_PREFIX 0xC0 #define B2_ECOUNT_MASK 0x1F #define B3_MASK 0xF0 #define B3_PREFIX 0xE0 #define B4_MASK 0xF0 #define B4_PREFIX 0xF0 #define B4_TYPE_MASK 0x08 // // P3 descriptor type // #define PSP_GR 0 #define RP_GR 1 #define PFS_GR 2 #define PREDS_GR 3 #define UNAT_GR 4 #define LC_GR 5 #define RP_BR 6 #define RNAT_GR 7 #define BSP_GR 8 #define BSPSTORE_GR 9 #define FPSR_GR 10 #define PRIUNAT_GR 11 // // P7 descriptor type // #define MEM_STACK_F 0 #define MEM_STACK_V 1 #define SPILL_BASE 2 #define PSP_SPREL 3 #define RP_WHEN 4 #define RP_PSPREL 5 #define PFS_WHEN 6 #define PFS_PSPREL 7 #define PREDS_WHEN 8 #define PREDS_PSPREL 9 #define LC_WHEN 10 #define LC_PSPREL 11 #define UNAT_WHEN 12 #define UNAT_PSPREL 13 #define FPSR_WHEN 14 #define FPSR_PSPREL 15 // // P8 descriptor type // #define PSP_PSPREL 0 #define RP_SPREL 1 #define PFS_SPREL 2 #define PREDS_SPREL 3 #define LC_SPREL 4 #define UNAT_SPREL 5 #define FPSR_SPREL 6 #define BSP_WHEN 7 #define BSP_PSPREL 8 #define BSP_SPREL 9 #define BSPSTORE_WHEN 10 #define BSPSTORE_PSPREL 11 #define BSPSTORE_SPREL 12 #define RNAT_WHEN 13 #define RNAT_PSPREL 14 #define RNAT_SPREL 15 #define PRIUNAT_WHEN 16 #define PRIUNAT_PSPREL 17 #define PRIUNAT_SPREL 18 #define STACK_POINTER_GR 12 #define FIRST_PRESERVED_GR 4 #define LAST_PRESERVED_GR 7 #define NUMBER_OF_PRESERVED_GR 4 #define NUMBER_OF_SCRATCH_GR 24 #define FIRST_LOW_PRESERVED_FR 2 #define LAST_LOW_PRESERVED_FR 5 #define NUMBER_OF_LOW_PRESERVED_FR 4 #define FIRST_HIGH_PRESERVED_FR 16 #define LAST_HIGH_PRESERVED_FR 31 #define NUMBER_OF_HIGH_PRESERVED_FR 16 #define NUMBER_OF_PRESERVED_FR (NUMBER_OF_LOW_PRESERVED_FR+NUMBER_OF_HIGH_PRESERVED_FR) #define FIRST_PRESERVED_BR 1 #define LAST_PRESERVED_BR 5 #define NUMBER_OF_PRESERVED_BR 5 #define NUMBER_OF_PRESERVED_MISC 8 #define NUMBER_OF_PRESERVED_REGISTERS (NUMBER_OF_PRESERVED_MISC+NUMBER_OF_PRESERVED_BR) #define REG_MISC_BASE 0 #define REG_PREDS (REG_MISC_BASE+0) #define REG_SP (REG_MISC_BASE+1) #define REG_PFS (REG_MISC_BASE+2) #define REG_RP (REG_MISC_BASE+3) #define REG_UNAT (REG_MISC_BASE+4) #define REG_LC (REG_MISC_BASE+5) #define REG_NATS (REG_MISC_BASE+6) #define REG_FPSR (REG_MISC_BASE+7) #define REG_BR_BASE (REG_MISC_BASE+NUMBER_OF_PRESERVED_MISC) #define REG_BSP 0xff // REG_MISC_BASE+8 #define REG_BSPSTORE 0xff // REG_MISC_BASE+9 #define REG_RNAT 0xff // REG_MISC_BASE+10 // // Where is a preserved register saved? // // 1. stack general register // 2. memory stack (pspoff) // 3. memory stack (spoff) // 4. branch register // #define GENERAL_REG 0 #define PSP_RELATIVE 1 #define SP_RELATIVE 2 #define BRANCH_REG 3 #define ADD_STATE_RECORD(States, RegionLength, DescBeginIndex) \ States.Top++; \ States.Top->IsTarget = FALSE; \ States.Top->MiscMask = 0; \ States.Top->FrMask = 0; \ States.Top->GrMask = 0; \ States.Top->Label = (LABEL)0; \ States.Top->Ecount = 0; \ States.Top->RegionLen = RegionLength; \ States.Top->RegionBegin = UnwindContext.SlotCount; \ States.Top->SpWhen = 0; \ States.Top->SpAdjustment = 0; \ States.Top->SpillBase = (States.Top-1)->SpillPtr; \ States.Top->SpillPtr = (States.Top-1)->SpillPtr; \ States.Top->Previous = States.Current; \ States.Top->DescBegin = DescBeginIndex; \ States.Current = States.Top #define VALID_LABEL_BIT_POSITION 15 #define LABEL_REGION(Region, Label) \ Region->Label = Label; \ Region->MiscMask |= (1 << VALID_LABEL_BIT_POSITION) #define IS_REGION_LABELED(Region) \ (Region->MiscMask & (1 << VALID_LABEL_BIT_POSITION)) #define CHECK_LABEL(State, Label) \ ( (IS_REGION_LABELED(State)) && (Label == State->Label) ) #define EXTRACT_NAT_FROM_UNAT(NatBit) \ NatBit = (UCHAR)((IntNats >> (((ULONG_PTR)Source & 0x1F8) >> 3)) & 0x1); #if DBG int UnwindDebugLevel = 0; # ifdef _IMAGEHLP_SOURCE_ # define UW_DEBUG(x) if (UnwindDebugLevel) dbPrint##x # else # define UW_DEBUG(x) if (UnwindDebugLevel) DbgPrint##x # endif #else # define UW_DEBUG(x) #endif // DBG typedef struct _REGISTER_RECORD { ULONG Where : 2; // 2-bit field ULONG SaveOffset : 30; // 30 bits for offset, big enough? ULONG When; // slot offset relative to region } REGISTER_RECORD, *PREGISTER_RECORD; typedef ULONG LABEL; typedef struct _STATE_RECORD { struct _STATE_RECORD *Previous; // pointer to outer nested prologue BOOLEAN IsTarget; // TRUE if the control pc is in this prologue UCHAR GrMask; // Mask that specifies which GRs to be restored USHORT MiscMask; // Mask that specifies which BRs and misc. registers // are to be restored. // N.B. MSBit indicates Label is valid or not. ULONG FrMask; // Mask that specifies which FRs to be restored ULONG SpAdjustment; // size of stack frame allocated in the prologue ULONG SpWhen; // slot offset relative to region ULONG SpillPtr; // current spill location ULONG SpillBase; // spill base of the region ULONG RegionBegin; // first slot of region relative to function entry ULONG RegionLen; // number of slots in the region LABEL Label; // label that identifies a post-prologue state ULONG Ecount; // number of prologue regions to pop ULONG DescBegin; // first prologue descriptor for the region ULONG DescEnd; // last prologue descriptor for the region } STATE_RECORD, *PSTATE_RECORD; typedef struct _UNWIND_CONTEXT { REGISTER_RECORD MiscRegs[NUMBER_OF_PRESERVED_REGISTERS]; REGISTER_RECORD Float[NUMBER_OF_PRESERVED_FR]; REGISTER_RECORD Integer[NUMBER_OF_PRESERVED_GR]; BOOLEAN ActiveRegionFound; UCHAR AlternateRp; USHORT Version; PUCHAR Descriptors; // beginning of descriptor data ULONG Size; // total size of all descriptors ULONG DescCount; // number of descriptor bytes processed ULONG TargetSlot; ULONG SlotCount; } UNWIND_CONTEXT, *PUNWIND_CONTEXT; typedef struct _STATE_RECORD_STACK { ULONG Size; PSTATE_RECORD Current; PSTATE_RECORD Top; PSTATE_RECORD Base; } STATE_RECORD_STACK, *PSTATE_RECORD_STACK; #define OFFSET(type, field) ((ULONG_PTR)(&((type *)0)->field)) static USHORT MiscContextOffset[NUMBER_OF_PRESERVED_REGISTERS] = { OFFSET(CONTEXT, Preds), OFFSET(CONTEXT, IntSp), OFFSET(CONTEXT, RsPFS), OFFSET(CONTEXT, BrRp), OFFSET(CONTEXT, ApUNAT), OFFSET(CONTEXT, ApLC), 0, 0, OFFSET(CONTEXT, BrS0), OFFSET(CONTEXT, BrS1), OFFSET(CONTEXT, BrS2), OFFSET(CONTEXT, BrS3), OFFSET(CONTEXT, BrS4) }; static USHORT MiscContextPointersOffset[NUMBER_OF_PRESERVED_REGISTERS] = { OFFSET(KNONVOLATILE_CONTEXT_POINTERS, Preds), OFFSET(KNONVOLATILE_CONTEXT_POINTERS, IntSp), OFFSET(KNONVOLATILE_CONTEXT_POINTERS, RsPFS), OFFSET(KNONVOLATILE_CONTEXT_POINTERS, BrRp), OFFSET(KNONVOLATILE_CONTEXT_POINTERS, ApUNAT), OFFSET(KNONVOLATILE_CONTEXT_POINTERS, ApLC), 0, 0, OFFSET(KNONVOLATILE_CONTEXT_POINTERS, BrS0), OFFSET(KNONVOLATILE_CONTEXT_POINTERS, BrS1), OFFSET(KNONVOLATILE_CONTEXT_POINTERS, BrS2), OFFSET(KNONVOLATILE_CONTEXT_POINTERS, BrS3), OFFSET(KNONVOLATILE_CONTEXT_POINTERS, BrS4) }; static UCHAR P3RecordTypeToRegisterIndex[] = {REG_SP, REG_RP, REG_PFS, REG_PREDS, REG_UNAT, REG_LC, REG_RP, REG_RNAT, REG_BSP, REG_BSPSTORE, REG_FPSR}; static UCHAR P7RecordTypeToRegisterIndex[] = {0, REG_SP, 0, REG_SP, REG_RP, REG_RP, REG_PFS, REG_PFS, REG_PREDS, REG_PREDS, REG_LC, REG_LC, REG_UNAT, REG_UNAT, REG_FPSR, REG_FPSR}; static UCHAR P8RecordTypeToRegisterIndex[] = {REG_SP, REG_RP, REG_PFS, REG_PREDS, REG_LC, REG_UNAT, REG_FPSR, REG_BSP, REG_BSP, REG_BSP, REG_BSPSTORE, REG_BSPSTORE, REG_BSPSTORE, REG_RNAT, REG_RNAT, REG_RNAT, REG_NATS, REG_NATS, REG_NATS}; UCHAR NewParsePrologueRegionPhase0 ( IN PUNWIND_CONTEXT UwContext, IN PSTATE_RECORD StateRecord, IN OUT PUCHAR AbiImmContext ); VOID NewParsePrologueRegionPhase1 ( IN PUNWIND_CONTEXT UwContext, IN PSTATE_RECORD StateRecord ); VOID SrInitialize ( IN PSTATE_RECORD_STACK StateTable, IN PSTATE_RECORD StateRecord, IN ULONG Size ) { StateTable->Size = Size; StateTable->Base = StateRecord; StateTable->Top = StateRecord; StateTable->Current = StateRecord; RtlZeroMemory(StateTable->Top, sizeof(STATE_RECORD)); } ULONG ReadLEB128 ( IN PUCHAR Descriptors, IN OUT PULONG CurrentDescIndex ) { PUCHAR Buffer; ULONG Value; ULONG ShiftCount = 7; ULONG Count; Buffer = Descriptors + *CurrentDescIndex; Count = 1; Value = Buffer[0] & 0x7F; if (Buffer[0] & 0x80) { while (TRUE) { Value += ((Buffer[Count] & 0x7F) << ShiftCount); if (Buffer[Count++] & 0x80) { ShiftCount += 7; } else { break; } } } *CurrentDescIndex += Count; return Value; } ULONGLONG RestorePreservedRegisterFromGR ( IN PCONTEXT Context, IN SHORT BsFrameSize, IN SHORT RNatSaveIndex, IN SHORT GrNumber, #ifdef _IMAGEHLP_SOURCE_ IN HANDLE hProcess, IN PREAD_PROCESS_MEMORY_ROUTINE64 ReadMemory, OUT BOOL *Succeed, #else OUT ULONG64 *SourceAddress, #endif // _IMAGEHLP_SOURCE_ OUT PUCHAR Nat OPTIONAL ) { ULONGLONG Result; SHORT Offset; SHORT Temp; #ifdef _IMAGEHLP_SOURCE_ ULONG Size; #endif // _IMAGEHLP_SOURCE_ #ifdef _IMAGEHLP_SOURCE_ *Succeed = FALSE; #endif // _IMAGEHLP_SOURCE_ if (GrNumber >= STATIC_REGISTER_SET_SIZE) { Offset = GrNumber - STATIC_REGISTER_SET_SIZE; if ( Offset < BsFrameSize ) { Temp = Offset + RNatSaveIndex - NAT_BITS_PER_RNAT_REG; while (Temp >= 0) { Offset++; Temp -= NAT_BITS_PER_RNAT_REG; } Offset = Offset * sizeof(ULONGLONG); #ifdef _IMAGEHLP_SOURCE_ *Succeed = ReadMemory(hProcess, Context->RsBSP + Offset, &Result, sizeof(ULONGLONG), &Size); #else *SourceAddress = (ULONG64)(Context->RsBSP + Offset); Result = *(PULONGLONG)(Context->RsBSP + Offset); #endif // _IMAGEHLP_SOURCE_ } else { UW_DEBUG(("ERROR: Invalid GR!\n")); } } else { if (GrNumber == 0 || GrNumber == 12) { // // Invalid GR number -> Invalid Unwind Descriptor // UW_DEBUG(("ERROR: Invalid GR!\n")); } else { UW_DEBUG(("WARNING: Target register is not a stacked GR!\n")); Offset = GrNumber - 1; NOT_IMAGEHLP(*SourceAddress = (ULONG64)(&Context->IntGp + Offset)); Result = *(&Context->IntGp + Offset); #ifdef _IMAGEHLP_SOURCE_ *Succeed = TRUE; #endif // _IMAGEHLP_SOURCE_ } } if (ARGUMENT_PRESENT(Nat)) { // // TBD: Pick up the corresponding Nat bit // *Nat = (UCHAR) 0; } return (Result); } UCHAR ParseBodyRegionDescriptors ( IN PUNWIND_CONTEXT UnwindContext, IN PSTATE_RECORD_STACK StateTable, IN ULONG RegionLen ) { LABEL Label; UCHAR FirstByte; BOOLEAN EcountDefined; BOOLEAN CopyLabel; ULONG Ecount; ULONG SlotOffset; PSTATE_RECORD StateTablePtr; PUCHAR Descriptors; CopyLabel = EcountDefined = FALSE; Descriptors = UnwindContext->Descriptors; while (UnwindContext->DescCount < UnwindContext->Size) { FirstByte = Descriptors[UnwindContext->DescCount++]; if ( (FirstByte & B1_MASK) == B1_PREFIX ) { Label = (LABEL)(FirstByte & B1_LABEL_MASK); if (FirstByte & B1_TYPE_MASK) { // // copy the entry state // CopyLabel = TRUE; } else { // // label the entry state // LABEL_REGION(StateTable->Top, Label); } UW_DEBUG(("Body region desc B1: copy=%d, label_num=%d\n", FirstByte & B1_TYPE_MASK ? TRUE : FALSE, Label)); } else if ( (FirstByte & B2_MASK) == B2_PREFIX ) { Ecount = FirstByte & B2_ECOUNT_MASK; SlotOffset = ReadLEB128(Descriptors, &UnwindContext->DescCount); EcountDefined = TRUE; UW_DEBUG(("Epilog desc B2: ecount=%d, LEB128(slot)=%d\n", Ecount, SlotOffset)); } else if ( (FirstByte & B3_MASK) == B3_PREFIX ) { SlotOffset = ReadLEB128(Descriptors, &UnwindContext->DescCount); Ecount = ReadLEB128(Descriptors, &UnwindContext->DescCount); EcountDefined = TRUE; UW_DEBUG(("Epilog desc B3: ecount=%d, LEB128 val=%d\n", Ecount, SlotOffset)); } else if ( (FirstByte & B4_MASK) == B4_PREFIX ) { Label = ReadLEB128(Descriptors, &UnwindContext->DescCount); if (FirstByte & B4_TYPE_MASK) { // // copy the entry state // CopyLabel = TRUE; } else { // // label the current top of stack // LABEL_REGION(StateTable->Top, Label); } UW_DEBUG(("Body region desc B4: copy=%d, label_num=%d\n", FirstByte & B4_TYPE_MASK, Label)); } else { // // Encounter another region header record // break; } } if (CopyLabel) { StateTablePtr = StateTable->Top; while (TRUE) { if (CHECK_LABEL(StateTablePtr, Label)) { StateTable->Current = StateTablePtr; break; } else if ((StateTablePtr == StateTable->Base)) { UW_DEBUG(("Undefined Label %d\n", Label)); break; } StateTablePtr--; } } if (EcountDefined) { Ecount++; // Ecount specifies additional level of prologue // regions to undo (i.e. a value of 0 implies 1 // prologue region) if (UnwindContext->ActiveRegionFound == FALSE) { while (Ecount-- > 0) { if (StateTable->Current->Previous) { StateTable->Current = StateTable->Current->Previous; } #if DBG else { UW_DEBUG(("WARNING: Ecount is greater than the # of active prologues!\n")); } #endif // DBG } } else { // // control PC is in this body/epilog region // if ((UnwindContext->SlotCount + RegionLen - SlotOffset) <= UnwindContext->TargetSlot) { PSTATE_RECORD SrPointer; StateTable->Current->Ecount = Ecount; SrPointer = StateTable->Current; while (Ecount > 0) { if (SrPointer->Previous) { SrPointer->Ecount = Ecount; SrPointer->SpWhen = 0; SrPointer->SpAdjustment = 0; SrPointer = SrPointer->Previous; } #if DBG else { UW_DEBUG(("WARNING: Ecount is greater than the # of active prologues!\n")); } #endif // DBG Ecount--; } } } } return FirstByte; } ULONGLONG ProcessInterruptRegion ( #ifdef _IMAGEHLP_SOURCE_ IN HANDLE hProcess, IN PREAD_PROCESS_MEMORY_ROUTINE64 ReadMemory, #else IN PKNONVOLATILE_CONTEXT_POINTERS ContextPointers, #endif _IMAGEHLP_SOURCE_ IN PUNWIND_CONTEXT UnwindContext, IN PCONTEXT Context, IN SHORT BsFrameSize, IN SHORT RNatSaveIndex, IN UCHAR AbiImmContext ) { // // no prologue descriptor in interrupt region. // PCONTEXT PrevContext; ULONGLONG NextPc; ULONG Index; SHORT TempFrameSize; BOOLEAN Success; #ifdef _IMAGEHLP_SOURCE_ ULONG Size; #else PVOID *Source; PVOID Address; #endif _IMAGEHLP_SOURCE_ if (AbiImmContext != CONTEXT_FRAME) { PKTRAP_FRAME TrapFrame; PKEXCEPTION_FRAME ExFrame; #ifdef _IMAGEHLP_SOURCE_ KTRAP_FRAME TF; KEXCEPTION_FRAME ExF; #endif // _IMAGEHLP_SOURCE_ TrapFrame = (PKTRAP_FRAME) Context->IntSp; #ifdef _IMAGEHLP_SOURCE_ if (!ReadMemory(hProcess, Context->IntSp, &TF, sizeof(KTRAP_FRAME), &Size)) { return 0; } TrapFrame = &TF; #endif // _IMAGEHLP_SOURCE_ Context->ApDCR = TrapFrame->ApDCR; Context->ApUNAT = TrapFrame->ApUNAT; Context->StFPSR = TrapFrame->StFPSR; Context->Preds = TrapFrame->Preds; Context->IntSp = TrapFrame->IntSp; Context->StIPSR = TrapFrame->StIPSR; Context->StIFS = TrapFrame->StIFS; Context->BrRp = TrapFrame->BrRp; Context->RsPFS = TrapFrame->RsPFS; #ifndef _IMAGEHLP_SOURCE_ if (ARGUMENT_PRESENT(ContextPointers)) { ContextPointers->ApUNAT = &TrapFrame->ApUNAT; ContextPointers->IntSp = &TrapFrame->IntSp; ContextPointers->BrRp = &TrapFrame->BrRp; ContextPointers->RsPFS = &TrapFrame->RsPFS; ContextPointers->Preds = &TrapFrame->Preds; } #endif // _IMAGEHLP_SOURCE_ switch (AbiImmContext) { case SYSCALL_FRAME: // // System Call Handler Frame // BsFrameSize = (SHORT)(TrapFrame->StIFS >> PFS_SIZE_SHIFT); BsFrameSize &= PFS_SIZE_MASK; break; case INTERRUPT_FRAME: case EXCEPTION_FRAME: // // External Interrupt Frame / Exception Frame // BsFrameSize = (SHORT)TrapFrame->StIFS & PFS_SIZE_MASK; break; default: break; } RNatSaveIndex = (SHORT)(TrapFrame->RsBSP >> 3) & NAT_BITS_PER_RNAT_REG; TempFrameSize = BsFrameSize - RNatSaveIndex; while (TempFrameSize > 0) { BsFrameSize++; TempFrameSize -= NAT_BITS_PER_RNAT_REG; } Context->RsBSP = TrapFrame->RsBSP - BsFrameSize * sizeof(ULONGLONG); Context->RsBSPSTORE = Context->RsBSP; Context->RsRNAT = TrapFrame->RsRNAT; NextPc = RtlIa64InsertIPSlotNumber(TrapFrame->StIIP, ((TrapFrame->StIPSR >> PSR_RI) & 0x3)); return (NextPc); } // // Kernel-to-User thunk, context of the previous frame can be // found on the user stack (i.e. context's address = sp+SCRATCH_AREA) // PrevContext = (PCONTEXT)(Context->IntSp + STACK_SCRATCH_AREA); #ifdef _IMAGEHLP_SOURCE_ if (!ReadMemory(hProcess, (DWORD64)PrevContext, Context, sizeof(CONTEXT), &Size)) { return 0; } NextPc = RtlIa64InsertIPSlotNumber(Context->StIIP, ((Context->StIPSR >> PSR_RI) & 0x3)); #else RtlCopyMemory(&Context->BrRp, &PrevContext->BrRp, (NUMBER_OF_PRESERVED_BR+3) * sizeof(ULONGLONG)); RtlCopyMemory(&Context->FltS0, &PrevContext->FltS0, NUMBER_OF_LOW_PRESERVED_FR * sizeof(FLOAT128)); RtlCopyMemory(&Context->FltS4, &PrevContext->FltS4, NUMBER_OF_HIGH_PRESERVED_FR * sizeof(FLOAT128)); RtlCopyMemory(&Context->IntS0, &PrevContext->IntS0, NUMBER_OF_PRESERVED_GR * sizeof(ULONGLONG)); RtlCopyMemory(&Context->IntV0, &PrevContext->IntV0, NUMBER_OF_SCRATCH_GR * sizeof(ULONGLONG)); Context->IntT0 = PrevContext->IntT0; Context->IntT1 = PrevContext->IntT1; Context->IntSp = PrevContext->IntSp; Context->IntNats = PrevContext->IntNats; Context->ApUNAT = PrevContext->ApUNAT; Context->ApLC = PrevContext->ApLC; Context->ApEC = PrevContext->ApEC; Context->Preds = PrevContext->Preds; Context->RsPFS = PrevContext->RsPFS; Context->RsBSP = PrevContext->RsBSP; Context->RsBSPSTORE = PrevContext->RsBSPSTORE; Context->RsRSC = PrevContext->RsRSC; Context->RsRNAT = PrevContext->RsRNAT; Context->StIFS = PrevContext->StIFS; Context->StIPSR = PrevContext->StIPSR; NextPc = RtlIa64InsertIPSlotNumber(PrevContext->StIIP, ((PrevContext->StIPSR >> PSR_RI) & 0x3)); #endif // _IMAGEHLP_SOURCE_ return(NextPc); } ULONGLONG RtlVirtualUnwind ( #ifdef _IMAGEHLP_SOURCE_ HANDLE hProcess, ULONGLONG ImageBase, ULONGLONG ControlPc, PRUNTIME_FUNCTION FunctionEntry, PCONTEXT ContextRecord, PREAD_PROCESS_MEMORY_ROUTINE64 ReadMemory #define ContextPointers ((PKNONVOLATILE_CONTEXT_POINTERS)0) #else IN ULONGLONG ImageBase, IN ULONGLONG ControlPc, IN PRUNTIME_FUNCTION FunctionEntry, IN OUT PCONTEXT ContextRecord, OUT PBOOLEAN InFunction, OUT PFRAME_POINTERS EstablisherFrame, IN OUT PKNONVOLATILE_CONTEXT_POINTERS ContextPointers OPTIONAL #endif ) /*++ Routine Description: This function virtually unwinds the specfified function by executing its prologue code backwards. If the function is a leaf function, then the address where control left the previous frame is obtained from the context record. If the function is a nested function, but not an exception or interrupt frame, then the prologue code is executed backwards and the address where control left the previous frame is obtained from the updated context record. Otherwise, an exception or interrupt entry to the system is being unwound and an especially coded prologue restores the return address twice. Once from the fault instruction address and once from the saved return address register. The first restore is returned as the function value and the second restore is placed in the updated context record. If a context pointers record is specified, then the address where each nonvolatile registers is restored from is recorded in the appropriate element of the context pointers record. Arguments: ImageBase - Supplies the base address of the module to which the function belongs. ControlPc - Supplies the address where control left the specified function. FunctionEntry - Supplies the address of the function table entry for the specified function. ContextRecord - Supplies the address of a context record. InFunction - Supplies a pointer to a variable that receives whether the control PC is within the current function. EstablisherFrame - Supplies a pointer to a variable that receives the the establisher frame pointer value. ContextPointers - Supplies an optional pointer to a context pointers record. Return Value: The address where control left the previous frame is returned as the function value. --*/ { #ifdef _IMAGEHLP_SOURCE_ BOOL Succeed; #endif // _IMAGEHLP_SOURCE_ PUCHAR Descriptors = NULL; UCHAR AbiImmContext = 0xFF; ULONG Mask; ULONGLONG NextPc; ULONG RegionLen; UCHAR FirstByte; UCHAR Nat; SHORT BsFrameSize; // in 8-byte units SHORT LocalFrameSize; // in 8-byte units SHORT TempFrameSize; // in 8-byte units SHORT RNatSaveIndex; ULONG i; PULONG Buffer; BOOLEAN IsPrologueRegion; BOOLEAN PspRestored; ULONGLONG PreviousIntSp; PVOID Destination; ULONG64 Source; ULONG64 *CtxPtr; ULONG64 *NatCtxPtr; ULONG64 IntNatsSource; ULONG64 IntNats; ULONG Size; ULONGLONG OldTopRnat; ULONGLONG NewTopRnat; UNWIND_INFO UnwindInfo; ULONG64 UnwindInfoPtr; UNWIND_CONTEXT UnwindContext; PSTATE_RECORD SrPointer; STATE_RECORD_STACK StateTable; STATE_RECORD StateRecords[STATE_RECORD_STACK_SIZE]; BsFrameSize = (SHORT)ContextRecord->StIFS & PFS_SIZE_MASK; RNatSaveIndex = (SHORT)(ContextRecord->RsBSP >> 3) & NAT_BITS_PER_RNAT_REG; TempFrameSize = RNatSaveIndex + BsFrameSize - NAT_BITS_PER_RNAT_REG; while (TempFrameSize >= 0) { BsFrameSize++; TempFrameSize -= NAT_BITS_PER_RNAT_REG; } UnwindInfoPtr = ImageBase + FunctionEntry->UnwindInfoAddress; #ifdef _IMAGEHLP_SOURCE_ if (!ReadMemory( hProcess, (ULONG64)UnwindInfoPtr, &UnwindInfo, sizeof(UNWIND_INFO), &Size)) { return 0; } UnwindContext.Version = UnwindInfo.Version; Size = UnwindInfo.DataLength * sizeof(ULONGLONG); if (Size) { Descriptors = (PUCHAR) MemAlloc (Size); if (!ReadMemory(hProcess,(ULONG64)(UnwindInfoPtr+sizeof(UNWIND_INFO)), Descriptors, Size, &Size)) { return 0; } } #else UnwindContext.Version = ((PUNWIND_INFO)UnwindInfoPtr)->Version; Size = ((PUNWIND_INFO)UnwindInfoPtr)->DataLength * sizeof(ULONGLONG); Descriptors = (PUCHAR)UnwindInfoPtr + sizeof(UNWIND_INFO); #endif // _IMAGEHLP_SOURCE_ UnwindContext.Size = Size; UnwindContext.ActiveRegionFound = FALSE; UnwindContext.AlternateRp = 0; UnwindContext.DescCount = 0; UnwindContext.SlotCount = 0; UnwindContext.TargetSlot = (ULONG)(((ControlPc - FunctionEntry->BeginAddress - ImageBase) >> 4) * SLOTS_PER_BUNDLE + ((ControlPc >> 2) & 0x3)); UnwindContext.Descriptors = Descriptors; SrInitialize(&StateTable, StateRecords, STATE_RECORD_STACK_SIZE); if (Size) { FirstByte = Descriptors[UnwindContext.DescCount++]; } while ( (UnwindContext.DescCount < UnwindContext.Size) && (!UnwindContext.ActiveRegionFound) ) { // // Assume a prologue region but not an interrupt region. // IsPrologueRegion = TRUE; // // Based on the type of region header, dispatch // to the corresponding routine that processes // the succeeding descriptors until the next // region header record. // if ((FirstByte & R1_MASK) == R1_PREFIX) { // // region header record in short format // RegionLen = FirstByte & R1_LENGTH_MASK; if (FirstByte & R1_REGION_TYPE_MASK) { IsPrologueRegion = FALSE; } else { ADD_STATE_RECORD(StateTable, RegionLen, UnwindContext.DescCount); } UW_DEBUG(("Region R1 format: body=%x, length=%d\n", IsPrologueRegion ? 0 : 1, RegionLen)); } else if ((FirstByte & R2_MASK) == R2_PREFIX) { // // general prologue region header // N.B. Skip the 2nd byte of the header and proceed to read // the region length; the header descriptors will be // processed again in phase 1. // ULONG R2DescIndex; R2DescIndex = UnwindContext.DescCount - 1; UnwindContext.DescCount++; RegionLen = ReadLEB128(Descriptors, &UnwindContext.DescCount); ADD_STATE_RECORD(StateTable, RegionLen, R2DescIndex); UW_DEBUG(("Region R2: body=0, length=%d\n", RegionLen)); } else if ((FirstByte & R3_MASK) == R3_PREFIX) { // // region header record in long format // RegionLen = ReadLEB128(Descriptors, &UnwindContext.DescCount); switch (FirstByte & R3_REGION_TYPE_MASK) { case 0: // prologue region header ADD_STATE_RECORD(StateTable, RegionLen, UnwindContext.DescCount); break; case 1: // body region header IsPrologueRegion = FALSE; break; } UW_DEBUG(("Region R3: body=%x, length=%d\n", IsPrologueRegion ? 0 : 1, RegionLen)); } else { // // Not a region header record -> Invalid unwind descriptor. // UW_DEBUG(("Invalid unwind descriptor!\n")); } if (UnwindContext.TargetSlot < (UnwindContext.SlotCount + RegionLen)) { UnwindContext.ActiveRegionFound = TRUE; StateTable.Current->IsTarget = IsPrologueRegion; } if (IsPrologueRegion) { FirstByte = NewParsePrologueRegionPhase0(&UnwindContext, StateTable.Current, &AbiImmContext); } else { FirstByte = ParseBodyRegionDescriptors(&UnwindContext, &StateTable, RegionLen); } UnwindContext.SlotCount += RegionLen; } // // Restore the value of psp and save the current NatCr. // N.B. If the value is restored from stack/bstore, turn off the // corresponding sp bit in the saved mask associated with the // prologue region in which psp is saved. // if (ARGUMENT_PRESENT(ContextPointers)) { IntNatsSource = (ULONG64)ContextPointers->ApUNAT; } IntNats = ContextRecord->ApUNAT; PreviousIntSp = ContextRecord->IntSp; PspRestored = FALSE; SrPointer = StateTable.Current; while (SrPointer != StateTable.Base) { NewParsePrologueRegionPhase1(&UnwindContext, SrPointer); if (SrPointer->MiscMask & (1 << REG_SP)) { if (UnwindContext.MiscRegs[REG_SP].Where == GENERAL_REG) { PreviousIntSp = RestorePreservedRegisterFromGR ( ContextRecord, BsFrameSize, RNatSaveIndex, (SHORT)UnwindContext.MiscRegs[REG_SP].SaveOffset, #ifdef _IMAGEHLP_SOURCE_ hProcess, ReadMemory, &Succeed, #else &Source, #endif // _IMAGEHLP_SOURCE_ &Nat ); #ifdef _IMAGEHLP_SOURCE_ if (!Succeed) { return 0; } #endif // _IMAGEHLP_SOURCE_ } else { Source = ContextRecord->IntSp + UnwindContext.MiscRegs[REG_SP].SaveOffset*4; #ifdef _IMAGEHLP_SOURCE_ if (!ReadMemory(hProcess, (ULONG64)(Source), &PreviousIntSp, sizeof(ULONGLONG), &Size)) { return 0; } #else PreviousIntSp = *(PULONGLONG)Source; #endif // _IMAGEHLP_SOURCE_ EXTRACT_NAT_FROM_UNAT(Nat); } ContextRecord->IntNats &= ~(0x1 << STACK_POINTER_GR); ContextRecord->IntNats |= (Nat << STACK_POINTER_GR); SrPointer->MiscMask &= ~(1 << REG_SP); if (ARGUMENT_PRESENT(ContextPointers)) { CtxPtr = (ULONG64 *)((ULONG_PTR)ContextPointers + MiscContextPointersOffset[REG_SP]); *CtxPtr = Source; } PspRestored = TRUE; } if (PspRestored == FALSE) { PreviousIntSp += SrPointer->SpAdjustment * 4; } SrPointer = SrPointer->Previous; } if (AbiImmContext != 0xFF) { ContextRecord->IntSp = PreviousIntSp; // trap/context frame address NextPc = ProcessInterruptRegion( #ifdef _IMAGEHLP_SOURCE_ hProcess, ReadMemory, #else ContextPointers, #endif _IMAGEHLP_SOURCE_ &UnwindContext, ContextRecord, BsFrameSize, RNatSaveIndex, AbiImmContext); goto FastExit; } // // Restore the contents of any preserved registers saved in this frame. // SrPointer = StateTable.Current; while (SrPointer != StateTable.Base) { Mask = SrPointer->MiscMask; UW_DEBUG(("MiscMask = 0x%x\n", Mask)); for (i = 0; i < NUMBER_OF_PRESERVED_REGISTERS; i++) { Destination = (PVOID)((ULONG_PTR)ContextRecord + MiscContextOffset[i]); if (Mask & 0x1) { if (ARGUMENT_PRESENT(ContextPointers)) { CtxPtr = (ULONG64 *)((ULONG_PTR)ContextPointers + MiscContextPointersOffset[i]); Source = *CtxPtr; } if (UnwindContext.MiscRegs[i].Where == GENERAL_REG) { *(PULONGLONG)Destination = RestorePreservedRegisterFromGR ( ContextRecord, BsFrameSize, RNatSaveIndex, (SHORT)UnwindContext.MiscRegs[i].SaveOffset, #ifdef _IMAGEHLP_SOURCE_ hProcess, ReadMemory, &Succeed, #else &Source, #endif // _IMAGEHLP_SOURCE_ NULL ); #ifdef _IMAGEHLP_SOURCE_ if (!Succeed) { return 0; } #endif // _IMAGEHLP_SOURCE_ } else if (UnwindContext.MiscRegs[i].Where == BRANCH_REG) { // // restore return pointer from branch register // USHORT Offset; Offset = (USHORT)UnwindContext.MiscRegs[i].SaveOffset-FIRST_PRESERVED_BR; Source = (ULONG64)(&ContextRecord->BrS0 + Offset); #ifdef _IMAGEHLP_SOURCE_ if (!ReadMemory(hProcess, (ULONG64)(Source), Destination, sizeof(ULONGLONG), &Size)) { return 0; } #else *(PULONGLONG)Destination = *(PULONGLONG)(Source); #endif // _IMAGEHLP_SOURCE_ } else if (UnwindContext.MiscRegs[i].Where == PSP_RELATIVE) { if ((SrPointer->Ecount == 0) || (UnwindContext.MiscRegs[i].SaveOffset <= (STACK_SCRATCH_AREA/sizeof(ULONG)))) { Source = PreviousIntSp + STACK_SCRATCH_AREA - UnwindContext.MiscRegs[i].SaveOffset*4; if (i == REG_NATS) { Destination = (PVOID)&IntNats; IntNatsSource = Source; } #ifdef _IMAGEHLP_SOURCE_ if (!ReadMemory(hProcess, (ULONG64)(Source), Destination, sizeof(ULONGLONG), &Size)) { return 0; } #else *(PULONGLONG)Destination = *(PULONGLONG)(Source); #endif // _IMAGEHLP_SOURCE_ } } else if (UnwindContext.MiscRegs[i].Where == SP_RELATIVE) { // // Make the necessary adjustment depending on whether // the preserved register is saved before or after the // stack pointer has been adjusted in this prologue. // if (UnwindContext.MiscRegs[i].When >= SrPointer->SpWhen && (SrPointer->RegionLen != 0)) Source = ContextRecord->IntSp + UnwindContext.MiscRegs[i].SaveOffset*4; else Source = ContextRecord->IntSp+SrPointer->SpAdjustment*4 + UnwindContext.MiscRegs[i].SaveOffset*4; if (i == REG_NATS) { Destination = (PVOID)&IntNats; IntNatsSource = Source; } #ifdef _IMAGEHLP_SOURCE_ if (!ReadMemory(hProcess, (ULONG64)(Source), Destination, sizeof(ULONGLONG), &Size)) { return 0; } #else *(PULONGLONG)Destination = *(PULONGLONG)(Source); #endif // _IMAGEHLP_SOURCE_ } if (ARGUMENT_PRESENT(ContextPointers) && (i != REG_NATS)) { *CtxPtr = Source; } } else if (Mask == 0) { // // No more registers to restore // break; } Mask = Mask >> 1; } // // Restore preserved FRs (f2 - f5, f16 - f31) // Mask = SrPointer->FrMask; Destination = (PVOID)&ContextRecord->FltS0; CtxPtr = (ULONG64 *)&ContextPointers->FltS0; UW_DEBUG(("FrMask = 0x%x\n", Mask)); for (i = 0; i < NUMBER_OF_PRESERVED_FR; i++) { if (Mask & 0x1) { if ((SrPointer->Ecount == 0) || (UnwindContext.Float[i].SaveOffset <= (STACK_SCRATCH_AREA/sizeof(ULONG)))) { Source = PreviousIntSp + STACK_SCRATCH_AREA - UnwindContext.Float[i].SaveOffset*4; #ifdef _IMAGEHLP_SOURCE_ if (!ReadMemory(hProcess, (ULONG64)(Source), Destination, sizeof(FLOAT128), &Size)) { return 0; } #else *(FLOAT128 *)Destination = *(FLOAT128 *)Source; #endif // _IMAGEHLP_SOURCE_ if (ARGUMENT_PRESENT(ContextPointers)) { *CtxPtr = Source; } } } else if (Mask == 0) { break; } Mask = Mask >> 1; if (i == (NUMBER_OF_LOW_PRESERVED_FR - 1)) { Destination = (PVOID)&ContextRecord->FltS4; CtxPtr = (ULONG64 *)(&ContextPointers->FltS4); } else { Destination = (PVOID)((FLOAT128 *)Destination+1); CtxPtr++; } } // // Restore preserved GRs (r4 - r7) // Mask = SrPointer->GrMask; Destination = (PVOID)&ContextRecord->IntS0; CtxPtr = (ULONG64 *)&ContextPointers->IntS0; NatCtxPtr = (ULONG64 *)&ContextPointers->IntS0Nat; UW_DEBUG(("GrMask = 0x%x\n", Mask)); for (i = 0; i < NUMBER_OF_PRESERVED_GR; i++) { if (Mask & 0x1) { if ((SrPointer->Ecount == 0) || (UnwindContext.Integer[i].SaveOffset <= (STACK_SCRATCH_AREA/sizeof(ULONG)))) { Source = PreviousIntSp + STACK_SCRATCH_AREA - UnwindContext.Integer[i].SaveOffset*4; #ifdef _IMAGEHLP_SOURCE_ if (!ReadMemory(hProcess, (ULONG64)(Source), Destination, sizeof(ULONGLONG), &Size)) { return 0; } #else *(PULONGLONG)Destination = *(PULONGLONG)Source; #endif // _IMAGEHLP_SOURCE_ EXTRACT_NAT_FROM_UNAT(Nat); Nat = (UCHAR)((IntNats >> (((ULONG_PTR)Source & 0x1F8) >> 3)) & 0x1); ContextRecord->IntNats &= ~(0x1 << (i+FIRST_PRESERVED_GR)); ContextRecord->IntNats |= (Nat << (i+FIRST_PRESERVED_GR)); #ifndef _IMAGEHLP_SOURCE_ if (ARGUMENT_PRESENT(ContextPointers)) { *CtxPtr = Source; *NatCtxPtr = IntNatsSource; } #endif } } else if (Mask == 0) { break; } Mask = Mask >> 1; Destination = (PVOID)((PULONGLONG)Destination+1); CtxPtr++; NatCtxPtr++; } ContextRecord->IntSp += SrPointer->SpAdjustment * 4; SrPointer = SrPointer->Previous; } ContextRecord->IntSp = PreviousIntSp; // // Restore the value of the epilogue count from the PFS // ContextRecord->ApEC = (ContextRecord->RsPFS >> PFS_EC_SHIFT) & ~(((ULONGLONG)1 << PFS_EC_SIZE) - 1); if (ARGUMENT_PRESENT(ContextPointers)) { ContextPointers->ApEC = ContextPointers->RsPFS; } FastExit: NOT_IMAGEHLP(*InFunction = TRUE); NOT_IMAGEHLP(EstablisherFrame->MemoryStackFp = ContextRecord->IntSp); NOT_IMAGEHLP(EstablisherFrame->BackingStoreFp = ContextRecord->RsBSP); #ifdef _IMAGEHLP_SOURCE_ if (Descriptors) MemFree(Descriptors); #endif // _IMAGEHLP_SOURCE_ if (AbiImmContext == 0xFF) { NextPc = *(&ContextRecord->BrRp + UnwindContext.AlternateRp); #ifndef _IMAGEHLP_SOURCE_ NextPc = RtlIa64InsertIPSlotNumber((NextPc-0x10), 2); #endif // _IMAGEHLP_SOURCE_ // // determine the local frame size of previous frame and compute // the new bsp. // OldTopRnat = (ContextRecord->RsBSP+(BsFrameSize-1)*8) | RNAT_ALIGNMENT; ContextRecord->StIFS = MASK(IFS_V, (ULONGLONG)1) | ContextRecord->RsPFS; BsFrameSize = (SHORT)ContextRecord->StIFS & PFS_SIZE_MASK; LocalFrameSize = (SHORT)(ContextRecord->StIFS >> PFS_SIZE_SHIFT) & PFS_SIZE_MASK; TempFrameSize = LocalFrameSize - RNatSaveIndex; while (TempFrameSize > 0) { LocalFrameSize++; BsFrameSize++; TempFrameSize -= NAT_BITS_PER_RNAT_REG; } ContextRecord->RsBSP -= LocalFrameSize * 8; ContextRecord->RsBSPSTORE = ContextRecord->RsBSP; // // determine if the RNAT field needs to be updated. // NewTopRnat = (ContextRecord->RsBSP+(BsFrameSize-1)*8) | RNAT_ALIGNMENT; if (NewTopRnat < OldTopRnat) { #ifdef _IMAGEHLP_SOURCE_ Destination = &ContextRecord->RsRNAT; Source = NewTopRnat; if (!ReadMemory(hProcess, (ULONG64)Source, Destination, 8, &Size)) { return 0; } #else ContextRecord->RsRNAT = *(PULONGLONG)(NewTopRnat); #endif // _IMAGEHLP_SOURCE_ } } #ifdef _IMAGEHLP_SOURCE_ UW_DEBUG(("NextPc = 0x%lx, PSP = 0x%lx, BSP = 0x%lx\n", (ULONGLONG)NextPc, (ULONGLONG)ContextRecord->IntSp, (ULONGLONG)ContextRecord->RsBSP)); #else UW_DEBUG(("NextPc = 0x%lx, PSP = 0x%lx, BSP = 0x%lx\n", (ULONGLONG)NextPc, EstablisherFrame->MemoryStackFp, EstablisherFrame->BackingStoreFp)); #endif // _IMAGEHLP_SOURCE_ return (NextPc); } UCHAR NewParsePrologueRegionPhase0 ( IN PUNWIND_CONTEXT UwContext, IN PSTATE_RECORD State, IN OUT PUCHAR AbiImmContext ) { PUCHAR Desc = UwContext->Descriptors; ULONG Offset; ULONG FrameSize; ULONG Index; UCHAR RecType; UCHAR FirstByte; UCHAR SecondByte; ULONG GrSave; ULONG TempMask; ULONG i; while (UwContext->DescCount < UwContext->Size) { FirstByte = Desc[UwContext->DescCount++]; if ( (FirstByte & P1_MASK) == P1_PREFIX) { continue; } else if ( (FirstByte & P2_MASK) == P2_PREFIX ) { UwContext->DescCount++; } else if ( (FirstByte & P3_MASK) == P3_PREFIX ) { UwContext->DescCount++; } else if ( (FirstByte & P4_MASK) == P4_PREFIX ) { UwContext->DescCount += ((State->RegionLen+3) >> 2); } else if ( (FirstByte & P5_MASK) == P5_PREFIX ) { UwContext->DescCount += 3; } else if ( (FirstByte & P6_MASK) == P6_PREFIX ) { continue; } else if ( (FirstByte & P7_MASK) == P7_PREFIX ) { RecType = FirstByte & ~P7_MASK; switch (RecType) { case MEM_STACK_F: Offset = ReadLEB128(Desc, &UwContext->DescCount); FrameSize = ReadLEB128(Desc, &UwContext->DescCount); if (UwContext->TargetSlot > (UwContext->SlotCount+Offset) || State->RegionLen == 0) { State->SpAdjustment += FrameSize*4; State->SpWhen = Offset; } break; case SPILL_BASE: State->SpillBase = ReadLEB128(Desc, &UwContext->DescCount); State->SpillPtr = State->SpillBase; break; case MEM_STACK_V: case RP_WHEN: case PFS_WHEN: case PREDS_WHEN: case LC_WHEN: case UNAT_WHEN: case FPSR_WHEN: Offset = ReadLEB128(Desc, &UwContext->DescCount); if ((State->IsTarget) && (UwContext->TargetSlot > (UwContext->SlotCount+Offset))) { Index = P7RecordTypeToRegisterIndex[RecType]; if (!(State->MiscMask & (1 << Index))) { State->MiscMask |= MASK(Index,1); UwContext->MiscRegs[Index].When = Offset; } else { UW_DEBUG(("Duplicate descriptors,")); UW_DEBUG(("unwinder may produce incorrect result!\n")); } } UW_DEBUG(("Prolog P7: type=%d slot= %d\n", RecType, Offset)); break; case PSP_SPREL: case RP_PSPREL: case PFS_PSPREL: case PREDS_PSPREL: case LC_PSPREL: case UNAT_PSPREL: case FPSR_PSPREL: Offset = ReadLEB128(Desc, &UwContext->DescCount); break; default: UW_DEBUG(("Invalid record type for descriptor P7!\n")); } } else if ( (FirstByte & P8_MASK) == P8_PREFIX ) { RecType = Desc[UwContext->DescCount++]; switch (RecType) { case PSP_PSPREL: case RP_SPREL: case PFS_SPREL: case PREDS_SPREL: case LC_SPREL: case UNAT_SPREL: case FPSR_SPREL: case BSP_PSPREL: case BSP_SPREL: case BSPSTORE_PSPREL: case BSPSTORE_SPREL: case RNAT_PSPREL: case RNAT_SPREL: case PRIUNAT_PSPREL: case PRIUNAT_SPREL: Offset = ReadLEB128(Desc, &UwContext->DescCount); UW_DEBUG(("Prolog P8: type=%d slot= %d\n", RecType, Offset)); break; case BSP_WHEN: case BSPSTORE_WHEN: case RNAT_WHEN: case PRIUNAT_WHEN: Offset = ReadLEB128(Desc, &UwContext->DescCount); if ((State->IsTarget) && (UwContext->TargetSlot > (UwContext->SlotCount+Offset))) { Index = P7RecordTypeToRegisterIndex[RecType]; if (!(State->MiscMask & (1 << Index))) { State->MiscMask |= MASK(Index,1); UwContext->MiscRegs[Index].When = Offset; } else { UW_DEBUG(("Duplicate descriptors,")); UW_DEBUG(("unwinder may produce incorrect result!\n")); } } UW_DEBUG(("Prolog P8: type=%d slot= %d\n", RecType, Offset)); break; default: UW_DEBUG(("Invalid record type for descriptor P8!\n")); } } else if ( (FirstByte & P9_MASK) == P9_PREFIX ) { UwContext->DescCount += 2; VUW_DEBUG_PRINT("Format P9 not supported yet!\n"); } else if ( (FirstByte & P10_MASK) == P10_PREFIX ) { UCHAR Abi = Desc[UwContext->DescCount++]; UCHAR Context = Desc[UwContext->DescCount++]; *AbiImmContext = Context; if (Abi != NT_ABI) { VUW_DEBUG_PRINT("Unknown ABI unwind descriptor\n"); } } else { // // Encounter another region header record // break; } } State->DescEnd = UwContext->DescCount - 2; return FirstByte; } VOID NewParsePrologueRegionPhase1 ( IN PUNWIND_CONTEXT UwContext, IN PSTATE_RECORD State ) { ULONG FrameSize; ULONG Offset; ULONG GrSave; ULONG BrBase; ULONG Index; ULONG Count; UCHAR RecType; UCHAR FirstByte, SecondByte; // 1st & 2nd bytes of a region header record ULONG DescIndex; ULONG ImaskBegin; UCHAR NextBr, NextGr, NextFr; USHORT MiscMask; ULONG TempMask; ULONG FrMask = 0; UCHAR BrMask = 0; UCHAR GrMask = 0; PUCHAR Desc = UwContext->Descriptors; BOOLEAN SpillMaskOmitted = TRUE; DescIndex = State->DescBegin; FirstByte = Desc[DescIndex]; if ((FirstByte & R2_MASK) == R2_PREFIX) { // // general prologue region header; need to process it first // ULONG GrSave, Count; UCHAR MiscMask; UCHAR SecondByte; USHORT i; DescIndex++; SecondByte = Desc[DescIndex++]; MiscMask = ((FirstByte & 0x7) << 1) | ((SecondByte & 0x80) >> 7); GrSave = SecondByte & 0x7F; ReadLEB128(Desc, &DescIndex); // advance the descriptor index if (GrSave < STATIC_REGISTER_SET_SIZE) { UW_DEBUG(("Invalid unwind descriptor!\n")); } UW_DEBUG(("Region R2: rmask=%x,grsave=%d,length=%d\n", MiscMask, GrSave, State->RegionLen)); Count = 0; for (Index = REG_PREDS; Index <= REG_RP; Index++) { if (MiscMask & 0x1) { if (!(State->IsTarget) || (State->MiscMask & MASK(Index,1))) { UwContext->MiscRegs[Index].Where = GENERAL_REG; UwContext->MiscRegs[Index].SaveOffset = GrSave+Count; UwContext->MiscRegs[Index].When = 0; State->MiscMask |= MASK(Index,1); } Count++; } MiscMask = MiscMask >> 1; } } while (DescIndex <= State->DescEnd) { FirstByte = Desc[DescIndex++]; if ( (FirstByte & P1_MASK) == P1_PREFIX) { BrMask = FirstByte & ~P1_MASK; State->MiscMask |= (BrMask << REG_BR_BASE); UW_DEBUG(("Prolog P1: brmask=%x\n", BrMask)); for (Count = REG_BR_BASE; Count < REG_BR_BASE+NUMBER_OF_PRESERVED_BR; Count++) { if (BrMask & 0x1) { UwContext->MiscRegs[Count].Where = PSP_RELATIVE; UwContext->MiscRegs[Count].When = State->RegionLen; } BrMask = BrMask >> 1; } } else if ( (FirstByte & P2_MASK) == P2_PREFIX ) { SecondByte = Desc[DescIndex++]; GrSave = SecondByte & 0x7F; BrMask = ((FirstByte & ~P2_MASK) << 1) | ((SecondByte & 0x80) >> 7); UW_DEBUG(("Prolog P2: brmask=%x reg base=%d\n", BrMask, GrSave)); State->MiscMask |= (BrMask << REG_BR_BASE); for (Count = REG_BR_BASE; Count < REG_BR_BASE+NUMBER_OF_PRESERVED_BR; Count++) { if (BrMask & 0x1) { UwContext->MiscRegs[Count].Where = GENERAL_REG; UwContext->MiscRegs[Count].SaveOffset = GrSave++; } BrMask = BrMask >> 1; } } else if ( (FirstByte & P3_MASK) == P3_PREFIX ) { SecondByte = Desc[DescIndex++]; RecType = ((SecondByte & 0x80) >> 7) | ((FirstByte & 0x7) << 1); Index = P3RecordTypeToRegisterIndex[RecType]; if (RecType == RP_BR) { UwContext->AlternateRp = SecondByte & 0x7F; } else if (!(State->IsTarget) || (State->MiscMask & MASK(Index,1))) { UwContext->MiscRegs[Index].Where = GENERAL_REG; UwContext->MiscRegs[Index].SaveOffset = SecondByte & 0x7F; UwContext->MiscRegs[Index].When = 0; State->MiscMask |= MASK(Index,1); UW_DEBUG(("Prolog P3: type=%d reg=%d\n", RecType, UwContext->MiscRegs[Index].SaveOffset)); } } else if ( (FirstByte & P4_MASK) == P4_PREFIX ) { SpillMaskOmitted = FALSE; ImaskBegin = DescIndex; DescIndex += ((State->RegionLen+3) >> 2); } else if ( (FirstByte & P5_MASK) == P5_PREFIX ) { GrMask = (Desc[DescIndex] & 0xF0) >> 4; FrMask = ((ULONG)(Desc[DescIndex] & 0xF) << 16) | ((ULONG)Desc[DescIndex+1] << 8) | ((ULONG)Desc[DescIndex+2]); DescIndex += 3; // increment the descriptor index State->GrMask |= GrMask; State->FrMask |= FrMask; UW_DEBUG(("Prolog P5: grmask = %x, frmask = %x\n", State->GrMask, State->FrMask)); } else if ( (FirstByte & P6_MASK) == P6_PREFIX ) { if (FirstByte & 0x10) { GrMask = FirstByte & 0xF; State->GrMask |= GrMask; } else { FrMask = FirstByte & 0xF; State->FrMask |= FrMask; } UW_DEBUG(("Prolog P6: is_gr = %d, mask = %x\n", (FirstByte & 0x10) ? 1 : 0, (FirstByte & 0x10) ? State->GrMask : State->FrMask)); } else if ( (FirstByte & P7_MASK) == P7_PREFIX ) { RecType = FirstByte & ~P7_MASK; switch (RecType) { case PSP_SPREL: // // sp-relative location // Index = P7RecordTypeToRegisterIndex[RecType]; Offset = ReadLEB128(Desc, &DescIndex); if (!(State->IsTarget) || (State->MiscMask & MASK(Index,1))) { UwContext->MiscRegs[Index].Where = SP_RELATIVE; UwContext->MiscRegs[Index].SaveOffset = Offset; if (!(State->MiscMask & MASK(Index,1))) { UwContext->MiscRegs[Index].When = State->RegionLen; State->MiscMask |= MASK(Index,1); } } UW_DEBUG(("Prolog P7: type=%d spoff = %d\n", RecType, Offset)); break; case RP_PSPREL: case PFS_PSPREL: case PREDS_PSPREL: case LC_PSPREL: case UNAT_PSPREL: case FPSR_PSPREL: // // psp-relative location // Index = P7RecordTypeToRegisterIndex[RecType]; Offset = ReadLEB128(Desc, &DescIndex); if (!(State->IsTarget) || (State->MiscMask & MASK(Index,1))) { UwContext->MiscRegs[Index].Where = PSP_RELATIVE; UwContext->MiscRegs[Index].SaveOffset = Offset; UwContext->MiscRegs[Index].When = 0; State->MiscMask |= MASK(Index,1); } UW_DEBUG(("Prolog P7: type=%d pspoff= %d\n", RecType, Offset)); break; case MEM_STACK_V: case RP_WHEN: case PFS_WHEN: case PREDS_WHEN: case LC_WHEN: case UNAT_WHEN: case FPSR_WHEN: // // Nevermind processing these descriptors because they // have been taken care of in phase 0 // Offset = ReadLEB128(Desc, &DescIndex); break; case MEM_STACK_F: Offset = ReadLEB128(Desc, &DescIndex); FrameSize = ReadLEB128(Desc, &DescIndex); UW_DEBUG(("Prolog P7: type=%d Slot=%d FrameSize=%d\n", RecType, Offset, FrameSize)); break; case SPILL_BASE: State->SpillBase = ReadLEB128(Desc, &DescIndex); State->SpillPtr = State->SpillBase; UW_DEBUG(("Prolog P7: type=%d, spillbase=%d\n", RecType, State->SpillBase)); break; default: UW_DEBUG(("invalid unwind descriptors\n")); } } else if ( (FirstByte & P8_MASK) == P8_PREFIX ) { RecType = Desc[DescIndex++]; switch (RecType) { case PSP_PSPREL: VUW_DEBUG_PRINT("Unsupported Unwind Descriptor!\n"); break; case RP_SPREL: case PFS_SPREL: case PREDS_SPREL: case LC_SPREL: case UNAT_SPREL: case FPSR_SPREL: case BSP_SPREL: case BSPSTORE_SPREL: case RNAT_SPREL: case PRIUNAT_SPREL: // // sp-relative location // Index = P8RecordTypeToRegisterIndex[RecType]; Offset = ReadLEB128(Desc, &DescIndex); if (!(State->IsTarget) || (State->MiscMask & MASK(Index,1))) { UwContext->MiscRegs[Index].Where = SP_RELATIVE; UwContext->MiscRegs[Index].SaveOffset = Offset; if (!(State->MiscMask & MASK(Index,1))) { UwContext->MiscRegs[Index].When=State->RegionLen; State->MiscMask |= MASK(Index,1); } } UW_DEBUG(("Prolog P8: type=%d spoff= %d\n", RecType, Offset)); break; case BSP_PSPREL: case BSPSTORE_PSPREL: case RNAT_PSPREL: case PRIUNAT_PSPREL: // // psp-relative location // Index = P8RecordTypeToRegisterIndex[RecType]; Offset = ReadLEB128(Desc, &DescIndex); if (!(State->IsTarget) || (State->MiscMask & MASK(Index,1))) { UwContext->MiscRegs[Index].Where = PSP_RELATIVE; UwContext->MiscRegs[Index].SaveOffset = Offset; UwContext->MiscRegs[Index].When = 0; State->MiscMask |= MASK(Index,1); } UW_DEBUG(("Prolog P8: type=%d pspoff= %d\n", RecType, Offset)); break; case BSP_WHEN: case BSPSTORE_WHEN: case RNAT_WHEN: case PRIUNAT_WHEN: // // Nevermind processing these descriptors because they // have been taken care of in phase 0 // Offset = ReadLEB128(Desc, &DescIndex); break; default: UW_DEBUG(("Invalid record type for descriptor P8!\n")); } } else if ( (FirstByte & P9_MASK) == P9_PREFIX ) { DescIndex += 2; VUW_DEBUG_PRINT("Format P9 not supported yet!\n"); } else if ( (FirstByte & P10_MASK) == P10_PREFIX ) { UCHAR Abi = Desc[DescIndex++]; UCHAR Context = Desc[DescIndex++]; } else { UW_DEBUG(("Invalid descriptor!\n")); } } GrMask = State->GrMask; FrMask = State->FrMask; BrMask = State->MiscMask >> REG_BR_BASE; if (!(GrMask | FrMask | BrMask)) { return; } else if (SpillMaskOmitted && !(State->IsTarget)) { // // When spillmask is omitted, floating point registers, general // registers, and then branch regisers are spilled in order. // They are not modified in the prologue region; therefore, there // is no need to restore their contents when the control ip is // in this prologue region. // // 1. floating point registers State->SpillPtr &= ~(SPILLSIZE_OF_FLOAT128_IN_DWORDS - 1); NextFr = NUMBER_OF_PRESERVED_FR - 1; while (FrMask & 0xFFFFF) { if (FrMask & 0x80000) { State->SpillPtr += SPILLSIZE_OF_FLOAT128_IN_DWORDS; UwContext->Float[NextFr].SaveOffset = State->SpillPtr; } FrMask = FrMask << 1; NextFr--; } // 2. branch registers NextBr = REG_BR_BASE + NUMBER_OF_PRESERVED_BR - 1; while (BrMask & 0x1F) { if (BrMask & 0x10) { if (UwContext->MiscRegs[NextBr].Where == PSP_RELATIVE) { State->SpillPtr += SPILLSIZE_OF_ULONGLONG_IN_DWORDS; UwContext->MiscRegs[NextBr].SaveOffset = State->SpillPtr; } } BrMask = BrMask << 1; NextBr--; } // 3. general registers NextGr = NUMBER_OF_PRESERVED_GR - 1; while (GrMask & 0xF) { if (GrMask & 0x8) { State->SpillPtr += SPILLSIZE_OF_ULONGLONG_IN_DWORDS; UwContext->Integer[NextGr].SaveOffset = State->SpillPtr; } GrMask = GrMask << 1; NextGr--; } } else if (SpillMaskOmitted && State->IsTarget) { State->GrMask = 0; State->FrMask = 0; State->MiscMask &= MASK(REG_BR_BASE, 1) - 1; } else if (SpillMaskOmitted == FALSE) { ULONG Length; if (State->IsTarget) { // // control ip is in the prologue region; clear the masks // and then process the imask to determine which preserved // Gr/Fr/Br have been saved and set the corresponding bits. // State->GrMask = 0; State->FrMask = 0; State->MiscMask &= MASK(REG_BR_BASE, 1) - 1; Length = UwContext->TargetSlot - State->RegionBegin; } else { Length = State->RegionLen; } NextGr = NUMBER_OF_PRESERVED_GR - 1; NextBr = NUMBER_OF_PRESERVED_BR - 1; NextFr = NUMBER_OF_PRESERVED_FR - 1; for (Count = 0; Count < Length; Count++) { if ((Count % 4) == 0) { FirstByte = Desc[ImaskBegin++]; } else { FirstByte = FirstByte << 2; } switch (FirstByte & 0xC0) { case 0x40: // 0x01 - save next fr while ( !(FrMask & 0x80000) && (NextFr > 0) ) { NextFr--; FrMask = FrMask << 1; } UW_DEBUG(("spilled register FS%lx\n", (ULONG)NextFr)); State->FrMask |= MASK(NextFr,1); UwContext->Float[NextFr].When = Count; State->SpillPtr += SPILLSIZE_OF_ULONGLONG_IN_DWORDS; State->SpillPtr &= ~(SPILLSIZE_OF_FLOAT128_IN_DWORDS - 1); State->SpillPtr += SPILLSIZE_OF_FLOAT128_IN_DWORDS; UwContext->Float[NextFr].SaveOffset = State->SpillPtr; NextFr--; FrMask = FrMask << 1; break; case 0x80: // 0x10 - save next gr while ( !(GrMask & 0x8) && (NextGr > 0) ) { NextGr--; GrMask = GrMask << 1; } UW_DEBUG(("spilled register S%lx\n", (ULONG)NextGr)); State->GrMask |= MASK(NextGr,1); UwContext->Integer[NextGr].When = Count; State->SpillPtr += SPILLSIZE_OF_ULONGLONG_IN_DWORDS; UwContext->Integer[NextGr].SaveOffset = State->SpillPtr; NextGr--; GrMask = GrMask << 1; break; case 0xC0: // 0x11 - save next br while ( !(BrMask & 0x10) && (NextBr > 0) ) { NextBr--; BrMask = BrMask << 1; } UW_DEBUG(("spilled register BS%lx\n", (ULONG)NextBr)); Index = REG_BR_BASE + NextBr; State->MiscMask |= MASK(Index,1); UwContext->MiscRegs[Index].When = Count; if (UwContext->MiscRegs[Index].Where == PSP_RELATIVE) { State->SpillPtr += SPILLSIZE_OF_ULONGLONG_IN_DWORDS; UwContext->MiscRegs[Index].SaveOffset = State->SpillPtr; } NextBr--; BrMask = BrMask << 1; break; default: // 0x00 - save no register break; } } } }