2240 lines
68 KiB
C
2240 lines
68 KiB
C
/**
|
||
*** 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 <stdlib.h>
|
||
|
||
#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;
|
||
|
||
}
|
||
}
|
||
}
|
||
}
|