2730 lines
79 KiB
C
2730 lines
79 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.
|
|
***
|
|
****************************************************************************
|
|
***
|
|
*** Thierry 09/21/99 - v16
|
|
*** 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.
|
|
***
|
|
****************************************************************************
|
|
**/
|
|
|
|
#define _CROSS_PLATFORM_
|
|
#define _IA64REG_
|
|
#include <nt.h>
|
|
#include <ntrtl.h>
|
|
#include <nturtl.h>
|
|
#include "private.h"
|
|
#include "globals.h"
|
|
#include "ia64inst.h"
|
|
#define NOEXTAPI
|
|
#include "wdbgexts.h"
|
|
#include "ntdbg.h"
|
|
#include <stdlib.h>
|
|
|
|
#ifdef _IMAGEHLP_SOURCE_
|
|
#include <symbols.h>
|
|
|
|
#define NOT_IMAGEHLP(E)
|
|
#define FUNCTION_ENTRY_IS_IMAGE_STYLE
|
|
#define RtlVirtualUnwind VirtualUnwindIa64
|
|
#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 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 7
|
|
|
|
#define NUMBER_OF_PRESERVED_REGISTERS 12
|
|
|
|
|
|
#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_BR_BASE (REG_MISC_BASE+NUMBER_OF_PRESERVED_MISC)
|
|
|
|
#define REG_FPSR 0xff // REG_MISC_BASE+7
|
|
#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 const USHORT MiscContextOffset[NUMBER_OF_PRESERVED_REGISTERS] = {
|
|
OFFSET(IA64_CONTEXT, Preds),
|
|
OFFSET(IA64_CONTEXT, IntSp),
|
|
OFFSET(IA64_CONTEXT, RsPFS),
|
|
OFFSET(IA64_CONTEXT, BrRp),
|
|
OFFSET(IA64_CONTEXT, ApUNAT),
|
|
OFFSET(IA64_CONTEXT, ApLC),
|
|
0,
|
|
OFFSET(IA64_CONTEXT, BrS0),
|
|
OFFSET(IA64_CONTEXT, BrS1),
|
|
OFFSET(IA64_CONTEXT, BrS2),
|
|
OFFSET(IA64_CONTEXT, BrS3),
|
|
OFFSET(IA64_CONTEXT, BrS4)
|
|
};
|
|
|
|
static const USHORT MiscContextPointersOffset[NUMBER_OF_PRESERVED_REGISTERS] = {
|
|
OFFSET(IA64_KNONVOLATILE_CONTEXT_POINTERS, Preds),
|
|
OFFSET(IA64_KNONVOLATILE_CONTEXT_POINTERS, IntSp),
|
|
OFFSET(IA64_KNONVOLATILE_CONTEXT_POINTERS, RsPFS),
|
|
OFFSET(IA64_KNONVOLATILE_CONTEXT_POINTERS, BrRp),
|
|
OFFSET(IA64_KNONVOLATILE_CONTEXT_POINTERS, ApUNAT),
|
|
OFFSET(IA64_KNONVOLATILE_CONTEXT_POINTERS, ApLC),
|
|
0,
|
|
OFFSET(IA64_KNONVOLATILE_CONTEXT_POINTERS, BrS0),
|
|
OFFSET(IA64_KNONVOLATILE_CONTEXT_POINTERS, BrS1),
|
|
OFFSET(IA64_KNONVOLATILE_CONTEXT_POINTERS, BrS2),
|
|
OFFSET(IA64_KNONVOLATILE_CONTEXT_POINTERS, BrS3),
|
|
OFFSET(IA64_KNONVOLATILE_CONTEXT_POINTERS, BrS4)
|
|
};
|
|
|
|
static const PSTR RegOffsetNames[NUMBER_OF_PRESERVED_REGISTERS] = {
|
|
"Preds",
|
|
"IntSp",
|
|
"RsPFS",
|
|
"BrRp",
|
|
"ApUNAT",
|
|
"ApLC",
|
|
"<invalid>",
|
|
"BrS0",
|
|
"BrS1",
|
|
"BrS2",
|
|
"BrS3",
|
|
"BrS4",
|
|
};
|
|
|
|
static const UCHAR P3RecordTypeToRegisterIndex[] =
|
|
{REG_SP, REG_RP, REG_PFS, REG_PREDS, REG_UNAT, REG_LC, REG_RP};
|
|
|
|
static const 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 const 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};
|
|
|
|
|
|
/*++
|
|
|
|
Description:
|
|
|
|
The next code defines mechanism to handle the context of
|
|
the unwind process
|
|
|
|
--*/
|
|
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Initializes the FixupTable
|
|
|
|
Arguments:
|
|
|
|
iContext - index of the context in UnwindContext
|
|
|
|
--*/
|
|
|
|
void
|
|
Vwndia64InitFixupTable(UINT iContext)
|
|
{
|
|
if (iContext < VWNDIA64_UNWIND_CONTEXT_TABLE_SIZE)
|
|
{
|
|
PVWNDIA64_UNWIND_CONTEXT pContext = tlsvar(UnwindContext) + iContext;
|
|
ZeroMemory(pContext->FixupTable, sizeof(pContext->FixupTable));
|
|
}
|
|
} // Vwndia64InitFixupTable
|
|
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Adds new fixup region into the table
|
|
|
|
Arguments:
|
|
|
|
iContext - index of the context in UnwindContext
|
|
Begin, End, Fixup - fixup region data
|
|
|
|
--*/
|
|
|
|
void
|
|
Vwndia64AddFixupRegion(UINT iContext,
|
|
ULONGLONG Ip,
|
|
ULONGLONG Begin, ULONGLONG End, ULONGLONG Fixup)
|
|
{
|
|
if (iContext < VWNDIA64_UNWIND_CONTEXT_TABLE_SIZE)
|
|
{
|
|
PVWNDIA64_UNWIND_CONTEXT pContext = tlsvar(UnwindContext) + iContext;
|
|
|
|
PVWNDIA64_FUXUP_REGION FixupReg = pContext->FixupTable;
|
|
PVWNDIA64_FUXUP_REGION FixupRegLast = FixupReg +
|
|
VWNDIA64_FIXUP_TABLE_SIZE;
|
|
|
|
//
|
|
// Search for the empty region
|
|
//
|
|
while (
|
|
(FixupReg < FixupRegLast) &&
|
|
(FixupReg->Fixup &&
|
|
((FixupReg->Ip != Ip) ||
|
|
(FixupReg->Begin != Begin) ||
|
|
(FixupReg->End != End) ||
|
|
(FixupReg->Fixup != Fixup))))
|
|
{
|
|
++FixupReg;
|
|
} // while
|
|
|
|
if (FixupReg >= FixupRegLast) // not found (rare)
|
|
{
|
|
//
|
|
// Scroll the table (destructive)
|
|
//
|
|
MoveMemory(pContext->FixupTable,
|
|
pContext->FixupTable + 1,
|
|
sizeof(pContext->FixupTable) -
|
|
sizeof(VWNDIA64_FUXUP_REGION));
|
|
FixupReg = FixupRegLast - 1;
|
|
} // if
|
|
|
|
FixupReg->Ip = Ip;
|
|
FixupReg->Begin = Begin;
|
|
FixupReg->End = End;
|
|
FixupReg->Fixup = Fixup;
|
|
} // if
|
|
} // Vwndia64AddFixupRegion
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Fixes the address using the specified fixup table
|
|
|
|
Arguments:
|
|
|
|
iContext - index of the context in UnwindContext
|
|
Size - size of the buffer in bytes
|
|
Addr - point to the address that have to be fixed
|
|
|
|
Return Value:
|
|
|
|
Addr contains the fixed value
|
|
|
|
--*/
|
|
|
|
void
|
|
Vwndia64FixAddress(UINT iContext, IN OUT ULONGLONG* Addr)
|
|
{
|
|
if (iContext < VWNDIA64_UNWIND_CONTEXT_TABLE_SIZE)
|
|
{
|
|
PVWNDIA64_UNWIND_CONTEXT pContext = tlsvar(UnwindContext) + iContext;
|
|
PVWNDIA64_FUXUP_REGION FixupReg = NULL;
|
|
|
|
//
|
|
// find last containing region
|
|
//
|
|
{
|
|
PVWNDIA64_FUXUP_REGION FixupSearch = pContext->FixupTable;
|
|
PVWNDIA64_FUXUP_REGION FixupRegLast = FixupSearch +
|
|
VWNDIA64_FIXUP_TABLE_SIZE;
|
|
|
|
while ((FixupSearch < FixupRegLast) && FixupSearch->Fixup)
|
|
{
|
|
if ((FixupSearch->Begin <= *Addr) && (*Addr < FixupSearch->End))
|
|
{
|
|
FixupReg = FixupSearch;
|
|
}
|
|
++FixupSearch;
|
|
} // while
|
|
}
|
|
|
|
if (FixupReg)
|
|
{
|
|
*Addr = FixupReg->Fixup - (FixupReg->End - *Addr);
|
|
} // if
|
|
} // if
|
|
} // Vwndia64FixAddress
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Checks whether specified Ip exists in fixup table
|
|
|
|
Arguments:
|
|
|
|
iContext - index of the context in UnwindContext
|
|
Ip - to search
|
|
|
|
Return Value:
|
|
|
|
Addr contains the fixed value
|
|
|
|
--*/
|
|
|
|
BOOL
|
|
Vwndia64IsFixupIp(UINT iContext, ULONGLONG Ip)
|
|
{
|
|
if (iContext < VWNDIA64_UNWIND_CONTEXT_TABLE_SIZE)
|
|
{
|
|
PVWNDIA64_UNWIND_CONTEXT pContext = tlsvar(UnwindContext) + iContext;
|
|
|
|
PVWNDIA64_FUXUP_REGION FixupSearch = pContext->FixupTable;
|
|
PVWNDIA64_FUXUP_REGION FixupRegLast = FixupSearch +
|
|
VWNDIA64_FIXUP_TABLE_SIZE;
|
|
|
|
while ((FixupSearch < FixupRegLast) &&
|
|
FixupSearch->Ip && (FixupSearch->Ip != Ip))
|
|
{
|
|
++FixupSearch;
|
|
} // while
|
|
|
|
return (FixupSearch->Ip == Ip);
|
|
} // if
|
|
|
|
return FALSE;
|
|
} // Vwndia64IsFixupIp
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Initializes the new context
|
|
|
|
Return Value:
|
|
|
|
returns ID of the record (index in UnwindContext)
|
|
|
|
--*/
|
|
|
|
UINT
|
|
Vwndia64NewContext()
|
|
{
|
|
UINT* iContext = &tlsvar(UnwindContextNew);
|
|
|
|
if (*iContext >= VWNDIA64_UNWIND_CONTEXT_TABLE_SIZE)
|
|
{
|
|
*iContext = 0;
|
|
}
|
|
|
|
Vwndia64InitFixupTable(*iContext);
|
|
tlsvar(UnwindContext[*iContext]).bFailureReported = FALSE;
|
|
|
|
return (*iContext)++;
|
|
} // Vwndia64NewContext()
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Checks if the specified context index valid and
|
|
creates new context if otherwise
|
|
|
|
--*/
|
|
|
|
BOOL
|
|
Vwndia64ValidateContext(UINT* iContext)
|
|
{
|
|
if (!iContext) return FALSE;
|
|
if (*iContext >= VWNDIA64_UNWIND_CONTEXT_TABLE_SIZE)
|
|
{
|
|
*iContext = Vwndia64NewContext();
|
|
return FALSE;
|
|
}
|
|
return TRUE;
|
|
} //Vwndia64ValidateContext
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Check whether any failure have been reported
|
|
|
|
Arguments:
|
|
|
|
iContext - index of the context in UnwindContext
|
|
|
|
Return Value:
|
|
|
|
Returns true whether any failure have been reported
|
|
|
|
--*/
|
|
|
|
BOOL
|
|
Vwndia64FailureReported(UINT iContext)
|
|
{
|
|
PVWNDIA64_UNWIND_CONTEXT pContext;
|
|
|
|
pContext = tlsvar(UnwindContext);
|
|
return (iContext < VWNDIA64_UNWIND_CONTEXT_TABLE_SIZE) ?
|
|
pContext[iContext].bFailureReported : FALSE;
|
|
} // Vwndia64FailureReported
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Reports failure and sets appropriate flag is the unwind context
|
|
|
|
Arguments:
|
|
|
|
iContext - index of the context in UnwindContext;
|
|
use (-1) to report unconditionaly
|
|
|
|
Return Value:
|
|
|
|
none
|
|
|
|
--*/
|
|
|
|
void
|
|
Vwndia64ReportFailure(UINT iContext, LPCSTR szFormat, ...)
|
|
{
|
|
if ((g.SymOptions & SYMOPT_DEBUG) != SYMOPT_DEBUG)
|
|
{
|
|
return;
|
|
}
|
|
|
|
if (iContext < VWNDIA64_UNWIND_CONTEXT_TABLE_SIZE)
|
|
{
|
|
PVWNDIA64_UNWIND_CONTEXT pContext = tlsvar(UnwindContext) + iContext;
|
|
if (pContext->bFailureReported)
|
|
{
|
|
return;
|
|
}
|
|
pContext->bFailureReported = TRUE;
|
|
} // if
|
|
|
|
//
|
|
// Printout failure
|
|
//
|
|
{
|
|
char buf[1024];
|
|
va_list args;
|
|
|
|
va_start(args, szFormat);
|
|
strcpy(buf, "DBGHELP: ");
|
|
_vsnprintf(buf + 9, sizeof(buf) - 11, szFormat, args);
|
|
va_end(args);
|
|
|
|
SympSendDebugString(NULL, buf);
|
|
} // Printout failure
|
|
} // Vwndia64ReportFailure
|
|
|
|
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 PIA64_CONTEXT Context,
|
|
IN SHORT BsFrameSize,
|
|
IN SHORT RNatSaveIndex,
|
|
IN SHORT GrNumber,
|
|
#ifdef _IMAGEHLP_SOURCE_
|
|
IN HANDLE hProcess,
|
|
IN PREAD_PROCESS_MEMORY_ROUTINE64 ReadMemory,
|
|
IN UINT iContext,
|
|
OUT BOOL *Succeed,
|
|
#else
|
|
OUT ULONG64 *SourceAddress,
|
|
#endif // _IMAGEHLP_SOURCE_
|
|
OUT PUCHAR Nat OPTIONAL
|
|
)
|
|
{
|
|
ULONGLONG Result = 0;
|
|
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 - IA64_NAT_BITS_PER_RNAT_REG;
|
|
while (Temp >= 0) {
|
|
Offset++;
|
|
Temp -= IA64_NAT_BITS_PER_RNAT_REG;
|
|
}
|
|
Offset = Offset * sizeof(ULONGLONG);
|
|
|
|
#ifdef _IMAGEHLP_SOURCE_
|
|
{
|
|
ULONGLONG Reg = (ULONGLONG)Context->RsBSP + (ULONGLONG)Offset;
|
|
Vwndia64FixAddress(iContext, &Reg);
|
|
*Succeed = ReadMemory(hProcess, Reg,
|
|
&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,
|
|
IN UINT iContext,
|
|
#else
|
|
IN PIA64_KNONVOLATILE_CONTEXT_POINTERS ContextPointers,
|
|
#endif _IMAGEHLP_SOURCE_
|
|
IN PUNWIND_CONTEXT UnwindContext,
|
|
IN PIA64_CONTEXT Context,
|
|
IN SHORT BsFrameSize,
|
|
IN SHORT RNatSaveIndex,
|
|
IN UCHAR AbiImmContext
|
|
)
|
|
{
|
|
//
|
|
// no prologue descriptor in interrupt region.
|
|
//
|
|
|
|
ULONGLONG NextPc;
|
|
ULONG Index;
|
|
SHORT TempFrameSize;
|
|
BOOLEAN Success;
|
|
#ifdef _IMAGEHLP_SOURCE_
|
|
ULONG Size;
|
|
#else
|
|
PIA64_CONTEXT PrevContext;
|
|
PVOID *Source;
|
|
PVOID Address;
|
|
#endif _IMAGEHLP_SOURCE_
|
|
|
|
|
|
if (AbiImmContext != IA64_CONTEXT_FRAME) {
|
|
|
|
PIA64_KTRAP_FRAME TrapFrame;
|
|
PIA64_KEXCEPTION_FRAME ExFrame;
|
|
#ifdef _IMAGEHLP_SOURCE_
|
|
IA64_KTRAP_FRAME TF;
|
|
IA64_KEXCEPTION_FRAME ExF;
|
|
#endif // _IMAGEHLP_SOURCE_
|
|
|
|
TrapFrame = (PIA64_KTRAP_FRAME) Context->IntSp;
|
|
#ifdef _IMAGEHLP_SOURCE_
|
|
if (!ReadMemory(hProcess, Context->IntSp, &TF, sizeof(IA64_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 IA64_SYSCALL_FRAME:
|
|
|
|
//
|
|
// System Call Handler Frame
|
|
//
|
|
|
|
BsFrameSize = (SHORT)(TrapFrame->StIFS >> IA64_PFS_SIZE_SHIFT);
|
|
BsFrameSize &= IA64_PFS_SIZE_MASK;
|
|
break;
|
|
|
|
case IA64_INTERRUPT_FRAME:
|
|
case IA64_EXCEPTION_FRAME:
|
|
|
|
//
|
|
// External Interrupt Frame / Exception Frame
|
|
//
|
|
|
|
BsFrameSize = (SHORT)TrapFrame->StIFS & IA64_PFS_SIZE_MASK;
|
|
break;
|
|
|
|
default:
|
|
|
|
break;
|
|
}
|
|
|
|
RNatSaveIndex = (SHORT)(TrapFrame->RsBSP >> 3) & IA64_NAT_BITS_PER_RNAT_REG;
|
|
TempFrameSize = BsFrameSize - RNatSaveIndex;
|
|
while (TempFrameSize > 0) {
|
|
BsFrameSize++;
|
|
TempFrameSize -= IA64_NAT_BITS_PER_RNAT_REG;
|
|
}
|
|
|
|
NextPc = Ia64InsertIPSlotNumber(TrapFrame->StIIP,
|
|
((TrapFrame->StIPSR >> PSR_RI) & 0x3));
|
|
|
|
#ifdef _IMAGEHLP_SOURCE_
|
|
Vwndia64AddFixupRegion(iContext,
|
|
NextPc,
|
|
TrapFrame->RsBSPSTORE, TrapFrame->RsBSP,
|
|
Context->RsBSP);
|
|
#endif // _IMAGEHLP_SOURCE_
|
|
|
|
Context->RsBSP = TrapFrame->RsBSP - BsFrameSize * sizeof(ULONGLONG);
|
|
Context->RsBSPSTORE = Context->RsBSP;
|
|
Context->RsRNAT = TrapFrame->RsRNAT;
|
|
|
|
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)
|
|
//
|
|
|
|
#ifdef _IMAGEHLP_SOURCE_
|
|
if (!ReadMemory(hProcess,
|
|
Context->IntSp + IA64_STACK_SCRATCH_AREA,
|
|
Context,
|
|
sizeof(IA64_CONTEXT),
|
|
&Size))
|
|
{
|
|
return 0;
|
|
}
|
|
NextPc = Ia64InsertIPSlotNumber(Context->StIIP,
|
|
((Context->StIPSR >> PSR_RI) & 0x3));
|
|
#else
|
|
|
|
PrevContext = (PIA64_CONTEXT)(Context->IntSp + IA64_STACK_SCRATCH_AREA);
|
|
|
|
RtlCopyMemory(&Context->BrRp, &PrevContext->BrRp,
|
|
(NUMBER_OF_PRESERVED_BR+1) * 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));
|
|
|
|
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 = Ia64InsertIPSlotNumber(PrevContext->StIIP,
|
|
((PrevContext->StIPSR >> PSR_RI) & 0x3));
|
|
|
|
#endif // _IMAGEHLP_SOURCE_
|
|
|
|
return(NextPc);
|
|
}
|
|
|
|
|
|
#ifdef _IMAGEHLP_SOURCE_
|
|
|
|
BOOL
|
|
IsValidUnwindInfo64 (
|
|
const IA64_UNWIND_INFO* pUnwindInfo
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This function validates the unwind info record
|
|
|
|
Return Value:
|
|
|
|
returns false if record looks like invalid
|
|
--*/
|
|
|
|
{
|
|
if (!pUnwindInfo) return FALSE;
|
|
|
|
switch (pUnwindInfo->Version) {
|
|
case 1:
|
|
case 2:
|
|
case 3:
|
|
if (
|
|
!pUnwindInfo->DataLength ||
|
|
(pUnwindInfo->DataLength > ((1024 / sizeof(ULONG64)) * 64)))
|
|
{
|
|
return FALSE;
|
|
}
|
|
break;
|
|
default:
|
|
return FALSE;
|
|
} // switch
|
|
|
|
return TRUE;
|
|
} // IsValidUnwindInfo64
|
|
|
|
BOOL
|
|
GetUnwindInfo(
|
|
IN HANDLE hProcess,
|
|
IN ULONGLONG ImageBase,
|
|
IN ULONG UnwindInfoAddress,
|
|
|
|
IN OUT PIA64_UNWIND_INFO UnwindInfo,
|
|
IN OUT PUCHAR* Descriptors,
|
|
IN OUT PULONG DescriptorsSize,
|
|
|
|
IN PREAD_PROCESS_MEMORY_ROUTINE64 ReadMemory
|
|
)
|
|
{
|
|
ULONG BytesRead = 0;
|
|
|
|
//
|
|
// try to get UnwindInfo from the image
|
|
//
|
|
ULONG64 UnwindInfoPtr = ImageBase + UnwindInfoAddress;
|
|
|
|
if (ReadMemory(hProcess, UnwindInfoPtr,
|
|
UnwindInfo, sizeof(*UnwindInfo), &BytesRead) &&
|
|
(BytesRead == sizeof(*UnwindInfo)) &&
|
|
IsValidUnwindInfo64(UnwindInfo))
|
|
{
|
|
if (!Descriptors)
|
|
{
|
|
return TRUE;
|
|
}
|
|
|
|
if (!UnwindInfo->DataLength)
|
|
{
|
|
*Descriptors = NULL;
|
|
*DescriptorsSize = 0;
|
|
return TRUE;
|
|
}
|
|
|
|
ULONG Size = UnwindInfo->DataLength * sizeof(ULONGLONG);
|
|
*Descriptors = (PUCHAR)MemAlloc(Size);
|
|
|
|
if (*Descriptors &&
|
|
ReadMemory(hProcess,
|
|
UnwindInfoPtr + sizeof(*UnwindInfo),
|
|
*Descriptors, Size, &BytesRead) &&
|
|
BytesRead == Size)
|
|
{
|
|
if (DescriptorsSize)
|
|
{
|
|
*DescriptorsSize = Size;
|
|
}
|
|
return TRUE;
|
|
}
|
|
MemFree(*Descriptors);
|
|
}
|
|
|
|
//
|
|
// try to get UnwindInfo from the symbols
|
|
//
|
|
ULONG_PTR XDataSize;
|
|
PBYTE pXData =
|
|
(PBYTE)GetUnwindInfoFromSymbols(hProcess,
|
|
ImageBase,
|
|
UnwindInfoAddress,
|
|
&XDataSize);
|
|
|
|
if (pXData && (XDataSize >= sizeof(*UnwindInfo)))
|
|
{
|
|
memcpy(UnwindInfo, pXData, sizeof(*UnwindInfo));
|
|
|
|
if (IsValidUnwindInfo64(UnwindInfo))
|
|
{
|
|
if (!Descriptors)
|
|
{
|
|
return TRUE;
|
|
}
|
|
|
|
if (!UnwindInfo->DataLength)
|
|
{
|
|
*Descriptors = NULL;
|
|
*DescriptorsSize = 0;
|
|
return TRUE;
|
|
}
|
|
|
|
ULONG Size = UnwindInfo->DataLength * sizeof(ULONG64);
|
|
|
|
if (Size <= (XDataSize - sizeof(*UnwindInfo)))
|
|
{
|
|
*Descriptors = (PUCHAR)MemAlloc(Size);
|
|
if (*Descriptors)
|
|
{
|
|
memcpy(*Descriptors,
|
|
pXData + sizeof(*UnwindInfo),
|
|
Size);
|
|
|
|
if (DescriptorsSize)
|
|
{
|
|
*DescriptorsSize = Size;
|
|
}
|
|
|
|
return TRUE;
|
|
}
|
|
MemFree(*Descriptors);
|
|
}
|
|
}
|
|
}
|
|
|
|
return FALSE;
|
|
}
|
|
#endif // defined(_IMAGEHLP_SOURCE_)
|
|
|
|
ULONGLONG
|
|
RtlVirtualUnwind (
|
|
#ifdef _IMAGEHLP_SOURCE_
|
|
IN HANDLE hProcess,
|
|
IN ULONGLONG ImageBase,
|
|
IN ULONGLONG ControlPc,
|
|
IN PIMAGE_IA64_RUNTIME_FUNCTION_ENTRY FunctionEntry,
|
|
OUT PIA64_CONTEXT ContextRecord,
|
|
IN PREAD_PROCESS_MEMORY_ROUTINE64 ReadMemory,
|
|
IN UINT iContext
|
|
#define ContextPointers ((PIA64_KNONVOLATILE_CONTEXT_POINTERS)0)
|
|
#else
|
|
IN ULONGLONG ImageBase,
|
|
IN ULONGLONG ControlPc,
|
|
IN PIMAGE_IA64_RUNTIME_FUNCTION_ENTRY FunctionEntry,
|
|
IN OUT PIA64_CONTEXT ContextRecord,
|
|
OUT PBOOLEAN InFunction,
|
|
OUT PFRAME_POINTERS EstablisherFrame,
|
|
IN OUT PIA64_KNONVOLATILE_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;
|
|
ULONG DescrSize;
|
|
ULONGLONG OldTopRnat;
|
|
ULONGLONG NewTopRnat;
|
|
UNWIND_CONTEXT UnwindContext;
|
|
PSTATE_RECORD SrPointer;
|
|
STATE_RECORD_STACK StateTable;
|
|
STATE_RECORD StateRecords[STATE_RECORD_STACK_SIZE];
|
|
|
|
BsFrameSize = (SHORT)ContextRecord->StIFS & IA64_PFS_SIZE_MASK;
|
|
RNatSaveIndex = (SHORT)(ContextRecord->RsBSP >> 3) & IA64_NAT_BITS_PER_RNAT_REG;
|
|
TempFrameSize = RNatSaveIndex + BsFrameSize - IA64_NAT_BITS_PER_RNAT_REG;
|
|
while (TempFrameSize >= 0) {
|
|
BsFrameSize++;
|
|
TempFrameSize -= IA64_NAT_BITS_PER_RNAT_REG;
|
|
}
|
|
|
|
#ifdef _IMAGEHLP_SOURCE_
|
|
{
|
|
IA64_UNWIND_INFO UnwindInfo;
|
|
if (!GetUnwindInfo(hProcess, ImageBase, FunctionEntry->UnwindInfoAddress,
|
|
&UnwindInfo, &Descriptors, &Size,
|
|
ReadMemory))
|
|
{
|
|
Vwndia64ReportFailure(-1,
|
|
"Can't read Unwind Info - "
|
|
"StackWalk can not continue\n");
|
|
return 0;
|
|
}
|
|
|
|
UnwindContext.Version = UnwindInfo.Version;
|
|
}
|
|
#else
|
|
{
|
|
ULONG64 UnwindInfoPtr = ImageBase + FunctionEntry->UnwindInfoAddress;
|
|
UnwindContext.Version = ((PIA64_UNWIND_INFO)UnwindInfoPtr)->Version;
|
|
Size = ((PIA64_UNWIND_INFO)UnwindInfoPtr)->DataLength * sizeof(ULONGLONG);
|
|
Descriptors = (PUCHAR)UnwindInfoPtr + sizeof(IA64_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,
|
|
iContext,
|
|
&Succeed,
|
|
#else
|
|
&Source,
|
|
#endif // _IMAGEHLP_SOURCE_
|
|
&Nat
|
|
);
|
|
#ifdef _IMAGEHLP_SOURCE_
|
|
if (!Succeed) {
|
|
return 0;
|
|
}
|
|
|
|
UW_DEBUG(("Restored IntSp to %I64x\n", PreviousIntSp));
|
|
|
|
#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,
|
|
iContext,
|
|
#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,
|
|
iContext,
|
|
&Succeed,
|
|
#else
|
|
&Source,
|
|
#endif // _IMAGEHLP_SOURCE_
|
|
NULL
|
|
);
|
|
#ifdef _IMAGEHLP_SOURCE_
|
|
if (!Succeed) {
|
|
*(PULONGLONG)Destination = 0;
|
|
} else {
|
|
UW_DEBUG(("Restored %s to %I64x\n",
|
|
RegOffsetNames[i],
|
|
*(PULONGLONG)Destination));
|
|
}
|
|
|
|
#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_
|
|
Vwndia64FixAddress(iContext, &Source);
|
|
|
|
if (!ReadMemory(hProcess, (ULONG64)(Source), Destination, sizeof(ULONGLONG), &Size)) {
|
|
*(PULONGLONG)Destination = 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 <= (IA64_STACK_SCRATCH_AREA/sizeof(ULONG)))) {
|
|
Source = PreviousIntSp + IA64_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)) {
|
|
*(PULONGLONG)Destination = 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)
|
|
{
|
|
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)) {
|
|
*(PULONGLONG)Destination = 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 <= (IA64_STACK_SCRATCH_AREA/sizeof(ULONG)))) {
|
|
Source = PreviousIntSp + IA64_STACK_SCRATCH_AREA
|
|
- UnwindContext.Float[i].SaveOffset*4;
|
|
#ifdef _IMAGEHLP_SOURCE_
|
|
if (!ReadMemory(hProcess, (ULONG64)(Source), Destination, sizeof(FLOAT128), &Size)) {
|
|
*(PULONGLONG)Destination = 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 <= (IA64_STACK_SCRATCH_AREA/sizeof(ULONG)))) {
|
|
Source = PreviousIntSp + IA64_STACK_SCRATCH_AREA
|
|
- UnwindContext.Integer[i].SaveOffset*4;
|
|
|
|
#ifdef _IMAGEHLP_SOURCE_
|
|
if (!ReadMemory(hProcess, (ULONG64)(Source), Destination, sizeof(ULONGLONG), &Size)) {
|
|
*(PULONGLONG)Destination = 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 >> IA64_PFS_EC_SHIFT) &
|
|
~(((ULONGLONG)1 << IA64_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) | IA64_RNAT_ALIGNMENT;
|
|
|
|
ContextRecord->StIFS = MASK(IA64_IFS_V, (ULONGLONG)1) | ContextRecord->RsPFS;
|
|
BsFrameSize = (SHORT)ContextRecord->StIFS & IA64_PFS_SIZE_MASK;
|
|
LocalFrameSize = (SHORT)(ContextRecord->StIFS >> IA64_PFS_SIZE_SHIFT) & IA64_PFS_SIZE_MASK;
|
|
TempFrameSize = LocalFrameSize - RNatSaveIndex;
|
|
while (TempFrameSize > 0) {
|
|
LocalFrameSize++;
|
|
BsFrameSize++;
|
|
TempFrameSize -= IA64_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) | IA64_RNAT_ALIGNMENT;
|
|
|
|
if (NewTopRnat < OldTopRnat) {
|
|
|
|
#ifdef _IMAGEHLP_SOURCE_
|
|
Destination = &ContextRecord->RsRNAT;
|
|
Source = NewTopRnat;
|
|
if (!ReadMemory(hProcess, (ULONG64)Source, Destination, 8, &Size)) {
|
|
*(PULONGLONG)Destination = 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)
|
|
{
|
|
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[Index].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;
|
|
|
|
}
|
|
}
|
|
}
|
|
}
|