672 lines
14 KiB
C++
672 lines
14 KiB
C++
|
//----------------------------------------------------------------------------
|
||
|
//
|
||
|
// IDebugRegisters implementation.
|
||
|
//
|
||
|
// Copyright (C) Microsoft Corporation, 1999-2002.
|
||
|
//
|
||
|
//----------------------------------------------------------------------------
|
||
|
|
||
|
#include "ntsdp.hpp"
|
||
|
|
||
|
STDMETHODIMP
|
||
|
DebugClient::GetNumberRegisters(
|
||
|
THIS_
|
||
|
OUT PULONG Number
|
||
|
)
|
||
|
{
|
||
|
HRESULT Status;
|
||
|
|
||
|
ENTER_ENGINE();
|
||
|
|
||
|
if (!g_Machine)
|
||
|
{
|
||
|
Status = E_UNEXPECTED;
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
*Number = g_Machine->m_NumRegs;
|
||
|
Status = S_OK;
|
||
|
}
|
||
|
|
||
|
LEAVE_ENGINE();
|
||
|
return Status;
|
||
|
}
|
||
|
|
||
|
STDMETHODIMP
|
||
|
DebugClient::GetDescription(
|
||
|
THIS_
|
||
|
IN ULONG Register,
|
||
|
OUT OPTIONAL PSTR NameBuffer,
|
||
|
IN ULONG NameBufferSize,
|
||
|
OUT OPTIONAL PULONG NameSize,
|
||
|
OUT OPTIONAL PDEBUG_REGISTER_DESCRIPTION Desc
|
||
|
)
|
||
|
{
|
||
|
HRESULT Status;
|
||
|
|
||
|
ENTER_ENGINE();
|
||
|
|
||
|
if (!g_Machine)
|
||
|
{
|
||
|
Status = E_UNEXPECTED;
|
||
|
goto Exit;
|
||
|
}
|
||
|
|
||
|
if (Register >= g_Machine->m_NumRegs)
|
||
|
{
|
||
|
Status = E_INVALIDARG;
|
||
|
goto Exit;
|
||
|
}
|
||
|
|
||
|
ULONG Type;
|
||
|
REGDEF* FullDef;
|
||
|
|
||
|
FullDef = g_Machine->RegDefFromCount(Register);
|
||
|
if (!FullDef)
|
||
|
{
|
||
|
Status = E_UNEXPECTED;
|
||
|
goto Exit;
|
||
|
}
|
||
|
|
||
|
Type = g_Machine->GetType(FullDef->Index);
|
||
|
|
||
|
Status = FillStringBuffer(FullDef->Name, 0,
|
||
|
NameBuffer, NameBufferSize, NameSize);
|
||
|
|
||
|
if (Desc != NULL)
|
||
|
{
|
||
|
ZeroMemory(Desc, sizeof(*Desc));
|
||
|
|
||
|
switch(Type)
|
||
|
{
|
||
|
case REGVAL_INT16:
|
||
|
Desc->Type = DEBUG_VALUE_INT16;
|
||
|
break;
|
||
|
case REGVAL_SUB32:
|
||
|
Desc->Flags |= DEBUG_REGISTER_SUB_REGISTER;
|
||
|
// Fall through.
|
||
|
case REGVAL_INT32:
|
||
|
Desc->Type = DEBUG_VALUE_INT32;
|
||
|
break;
|
||
|
case REGVAL_SUB64:
|
||
|
Desc->Flags |= DEBUG_REGISTER_SUB_REGISTER;
|
||
|
// Fall through.
|
||
|
case REGVAL_INT64:
|
||
|
case REGVAL_INT64N:
|
||
|
Desc->Type = DEBUG_VALUE_INT64;
|
||
|
break;
|
||
|
case REGVAL_FLOAT8:
|
||
|
Desc->Type = DEBUG_VALUE_FLOAT64;
|
||
|
break;
|
||
|
case REGVAL_FLOAT10:
|
||
|
Desc->Type = DEBUG_VALUE_FLOAT80;
|
||
|
break;
|
||
|
case REGVAL_FLOAT82:
|
||
|
Desc->Type = DEBUG_VALUE_FLOAT82;
|
||
|
break;
|
||
|
case REGVAL_FLOAT16:
|
||
|
Desc->Type = DEBUG_VALUE_FLOAT128;
|
||
|
break;
|
||
|
case REGVAL_VECTOR64:
|
||
|
Desc->Type = DEBUG_VALUE_VECTOR64;
|
||
|
break;
|
||
|
case REGVAL_VECTOR128:
|
||
|
Desc->Type = DEBUG_VALUE_VECTOR128;
|
||
|
break;
|
||
|
}
|
||
|
|
||
|
if (Desc->Flags & DEBUG_REGISTER_SUB_REGISTER)
|
||
|
{
|
||
|
REGSUBDEF* SubDef = g_Machine->RegSubDefFromIndex(FullDef->Index);
|
||
|
if (!SubDef)
|
||
|
{
|
||
|
Status = E_UNEXPECTED;
|
||
|
goto Exit;
|
||
|
}
|
||
|
|
||
|
// Find fullreg definition and count.
|
||
|
ULONG GroupIdx;
|
||
|
RegisterGroup* Group;
|
||
|
ULONG FullCount = 0;
|
||
|
|
||
|
for (GroupIdx = 0;
|
||
|
GroupIdx < g_Machine->m_NumGroups;
|
||
|
GroupIdx++)
|
||
|
{
|
||
|
Group = g_Machine->m_Groups[GroupIdx];
|
||
|
|
||
|
FullDef = Group->Regs;
|
||
|
while (FullDef->Name != NULL)
|
||
|
{
|
||
|
if (FullDef->Index == SubDef->FullReg)
|
||
|
{
|
||
|
break;
|
||
|
}
|
||
|
|
||
|
FullDef++;
|
||
|
}
|
||
|
|
||
|
FullCount += (ULONG)(FullDef - Group->Regs);
|
||
|
if (FullDef->Name != NULL)
|
||
|
{
|
||
|
break;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
DBG_ASSERT(FullDef->Name != NULL);
|
||
|
|
||
|
Desc->SubregMaster = FullCount;
|
||
|
|
||
|
// Count the bits in the mask to derive length.
|
||
|
|
||
|
ULONG64 Mask;
|
||
|
|
||
|
Mask = SubDef->Mask;
|
||
|
Desc->SubregMask = Mask;
|
||
|
|
||
|
while (Mask != 0)
|
||
|
{
|
||
|
Desc->SubregLength++;
|
||
|
Mask &= Mask - 1;
|
||
|
}
|
||
|
|
||
|
Desc->SubregShift = SubDef->Shift;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
Exit:
|
||
|
LEAVE_ENGINE();
|
||
|
return Status;
|
||
|
}
|
||
|
|
||
|
STDMETHODIMP
|
||
|
DebugClient::GetIndexByName(
|
||
|
THIS_
|
||
|
IN PCSTR Name,
|
||
|
OUT PULONG Index
|
||
|
)
|
||
|
{
|
||
|
HRESULT Status;
|
||
|
|
||
|
ENTER_ENGINE();
|
||
|
|
||
|
if (!g_Machine)
|
||
|
{
|
||
|
Status = E_UNEXPECTED;
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
RegisterGroup* Group;
|
||
|
ULONG Idx;
|
||
|
ULONG GroupIdx;
|
||
|
|
||
|
Status = E_NOINTERFACE;
|
||
|
Idx = 0;
|
||
|
for (GroupIdx = 0;
|
||
|
GroupIdx < g_Machine->m_NumGroups && Status != S_OK;
|
||
|
GroupIdx++)
|
||
|
{
|
||
|
REGDEF* Def;
|
||
|
|
||
|
Group = g_Machine->m_Groups[GroupIdx];
|
||
|
|
||
|
Def = Group->Regs;
|
||
|
while (Def->Name != NULL)
|
||
|
{
|
||
|
if (!strcmp(Def->Name, Name))
|
||
|
{
|
||
|
Status = S_OK;
|
||
|
break;
|
||
|
}
|
||
|
|
||
|
Idx++;
|
||
|
Def++;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
*Index = Idx;
|
||
|
}
|
||
|
|
||
|
LEAVE_ENGINE();
|
||
|
return Status;
|
||
|
}
|
||
|
|
||
|
STDMETHODIMP
|
||
|
DebugClient::GetValue(
|
||
|
THIS_
|
||
|
IN ULONG Register,
|
||
|
OUT PDEBUG_VALUE Value
|
||
|
)
|
||
|
{
|
||
|
HRESULT Status;
|
||
|
|
||
|
ENTER_ENGINE();
|
||
|
|
||
|
if (!IS_CUR_CONTEXT_ACCESSIBLE())
|
||
|
{
|
||
|
Status = E_UNEXPECTED;
|
||
|
goto Exit;
|
||
|
}
|
||
|
|
||
|
if (Register >= g_Machine->m_NumRegs)
|
||
|
{
|
||
|
Status = E_INVALIDARG;
|
||
|
goto Exit;
|
||
|
}
|
||
|
|
||
|
ZeroMemory(Value, sizeof(*Value));
|
||
|
|
||
|
ULONG Index;
|
||
|
REGVAL Val;
|
||
|
|
||
|
REGDEF* RegDef = g_Machine->RegDefFromCount(Register);
|
||
|
if (!RegDef)
|
||
|
{
|
||
|
Status = E_UNEXPECTED;
|
||
|
goto Exit;
|
||
|
}
|
||
|
|
||
|
g_DisableErrorPrint++;
|
||
|
|
||
|
Index = RegDef->Index;
|
||
|
__try
|
||
|
{
|
||
|
GetPseudoOrRegVal(TRUE, Index, &Val);
|
||
|
}
|
||
|
__except(CommandExceptionFilter(GetExceptionInformation()))
|
||
|
{
|
||
|
Status = E_INVALIDARG;
|
||
|
g_DisableErrorPrint--;
|
||
|
goto Exit;
|
||
|
}
|
||
|
|
||
|
g_DisableErrorPrint--;
|
||
|
|
||
|
switch(Val.Type)
|
||
|
{
|
||
|
case REGVAL_INT16:
|
||
|
Value->Type = DEBUG_VALUE_INT16;
|
||
|
Value->I16 = (USHORT)Val.I32;
|
||
|
break;
|
||
|
case REGVAL_SUB32:
|
||
|
case REGVAL_INT32:
|
||
|
Value->Type = DEBUG_VALUE_INT32;
|
||
|
Value->I32 = Val.I32;
|
||
|
break;
|
||
|
case REGVAL_SUB64:
|
||
|
case REGVAL_INT64:
|
||
|
Val.Nat = FALSE;
|
||
|
// Fall through.
|
||
|
case REGVAL_INT64N:
|
||
|
Value->Type = DEBUG_VALUE_INT64;
|
||
|
Value->I64 = Val.I64;
|
||
|
Value->Nat = Val.Nat;
|
||
|
break;
|
||
|
case REGVAL_FLOAT8:
|
||
|
Value->Type = DEBUG_VALUE_FLOAT64;
|
||
|
Value->F64 = Val.F8;
|
||
|
break;
|
||
|
case REGVAL_FLOAT10:
|
||
|
Value->Type = DEBUG_VALUE_FLOAT80;
|
||
|
memcpy(Value->F80Bytes, Val.F10, sizeof(Value->F80Bytes));
|
||
|
break;
|
||
|
case REGVAL_FLOAT82:
|
||
|
Value->Type = DEBUG_VALUE_FLOAT82;
|
||
|
memcpy(Value->F82Bytes, Val.F82, sizeof(Value->F82Bytes));
|
||
|
break;
|
||
|
case REGVAL_FLOAT16:
|
||
|
Value->Type = DEBUG_VALUE_FLOAT128;
|
||
|
memcpy(Value->F128Bytes, Val.F16, sizeof(Value->F128Bytes));
|
||
|
break;
|
||
|
case REGVAL_VECTOR64:
|
||
|
Value->Type = DEBUG_VALUE_VECTOR64;
|
||
|
memcpy(Value->RawBytes, Val.Bytes, 8);
|
||
|
break;
|
||
|
case REGVAL_VECTOR128:
|
||
|
Value->Type = DEBUG_VALUE_VECTOR128;
|
||
|
memcpy(Value->RawBytes, Val.Bytes, 16);
|
||
|
break;
|
||
|
}
|
||
|
|
||
|
Status = S_OK;
|
||
|
|
||
|
Exit:
|
||
|
LEAVE_ENGINE();
|
||
|
return Status;
|
||
|
}
|
||
|
|
||
|
STDMETHODIMP
|
||
|
DebugClient::SetValue(
|
||
|
THIS_
|
||
|
IN ULONG Register,
|
||
|
IN PDEBUG_VALUE Value
|
||
|
)
|
||
|
{
|
||
|
HRESULT Status;
|
||
|
|
||
|
ENTER_ENGINE();
|
||
|
|
||
|
if (!IS_CUR_CONTEXT_ACCESSIBLE())
|
||
|
{
|
||
|
Status = E_UNEXPECTED;
|
||
|
goto Exit;
|
||
|
}
|
||
|
|
||
|
if (Register >= g_Machine->m_NumRegs)
|
||
|
{
|
||
|
Status = E_INVALIDARG;
|
||
|
goto Exit;
|
||
|
}
|
||
|
|
||
|
ULONG Index;
|
||
|
ULONG Type;
|
||
|
REGVAL Val;
|
||
|
DEBUG_VALUE Coerce;
|
||
|
|
||
|
REGDEF* RegDef = g_Machine->RegDefFromCount(Register);
|
||
|
if (!RegDef)
|
||
|
{
|
||
|
Status = E_UNEXPECTED;
|
||
|
goto Exit;
|
||
|
}
|
||
|
|
||
|
Index = RegDef->Index;
|
||
|
Type = g_Machine->GetType(Index);
|
||
|
Val.Type = Type;
|
||
|
|
||
|
switch(Type)
|
||
|
{
|
||
|
case REGVAL_INT16:
|
||
|
Status = CoerceValue(Value, DEBUG_VALUE_INT16, &Coerce);
|
||
|
Val.I32 = Coerce.I16;
|
||
|
break;
|
||
|
case REGVAL_SUB32:
|
||
|
case REGVAL_INT32:
|
||
|
Status = CoerceValue(Value, DEBUG_VALUE_INT32, &Coerce);
|
||
|
Val.I32 = Coerce.I32;
|
||
|
break;
|
||
|
case REGVAL_INT64:
|
||
|
Val.Type = REGVAL_INT64N;
|
||
|
// Fall through.
|
||
|
case REGVAL_SUB64:
|
||
|
case REGVAL_INT64N:
|
||
|
Status = CoerceValue(Value, DEBUG_VALUE_INT64, &Coerce);
|
||
|
Val.I64 = Coerce.I64;
|
||
|
Val.Nat = Coerce.Nat ? TRUE : FALSE;
|
||
|
break;
|
||
|
case REGVAL_FLOAT8:
|
||
|
Status = CoerceValue(Value, DEBUG_VALUE_FLOAT64, &Coerce);
|
||
|
Val.F8 = Coerce.F64;
|
||
|
break;
|
||
|
case REGVAL_FLOAT10:
|
||
|
Status = CoerceValue(Value, DEBUG_VALUE_FLOAT80, &Coerce);
|
||
|
memcpy(Val.F10, Coerce.F80Bytes, sizeof(Coerce.F80Bytes));
|
||
|
break;
|
||
|
case REGVAL_FLOAT82:
|
||
|
Status = CoerceValue(Value, DEBUG_VALUE_FLOAT82, &Coerce);
|
||
|
memcpy(Val.F82, Coerce.F82Bytes, sizeof(Coerce.F82Bytes));
|
||
|
break;
|
||
|
case REGVAL_FLOAT16:
|
||
|
Status = CoerceValue(Value, DEBUG_VALUE_FLOAT128, &Coerce);
|
||
|
memcpy(Val.F16, Coerce.F128Bytes, sizeof(Coerce.F128Bytes));
|
||
|
break;
|
||
|
case REGVAL_VECTOR64:
|
||
|
Status = CoerceValue(Value, DEBUG_VALUE_VECTOR64, &Coerce);
|
||
|
memcpy(Val.Bytes, Coerce.RawBytes, 8);
|
||
|
break;
|
||
|
case REGVAL_VECTOR128:
|
||
|
Status = CoerceValue(Value, DEBUG_VALUE_VECTOR128, &Coerce);
|
||
|
memcpy(Val.Bytes, Coerce.RawBytes, 16);
|
||
|
break;
|
||
|
}
|
||
|
|
||
|
if (Status == S_OK)
|
||
|
{
|
||
|
g_DisableErrorPrint++;
|
||
|
|
||
|
__try
|
||
|
{
|
||
|
SetPseudoOrRegVal(Index, &Val);
|
||
|
}
|
||
|
__except(CommandExceptionFilter(GetExceptionInformation()))
|
||
|
{
|
||
|
Status = E_INVALIDARG;
|
||
|
}
|
||
|
|
||
|
g_DisableErrorPrint--;
|
||
|
}
|
||
|
|
||
|
Exit:
|
||
|
LEAVE_ENGINE();
|
||
|
return Status;
|
||
|
}
|
||
|
|
||
|
STDMETHODIMP
|
||
|
DebugClient::GetValues(
|
||
|
THIS_
|
||
|
IN ULONG Count,
|
||
|
IN OPTIONAL PULONG Indices,
|
||
|
IN ULONG Start,
|
||
|
OUT PDEBUG_VALUE Values
|
||
|
)
|
||
|
{
|
||
|
HRESULT Status;
|
||
|
|
||
|
ENTER_ENGINE();
|
||
|
|
||
|
if (!IS_CUR_CONTEXT_ACCESSIBLE())
|
||
|
{
|
||
|
Status = E_UNEXPECTED;
|
||
|
goto Exit;
|
||
|
}
|
||
|
|
||
|
HRESULT SingleStatus;
|
||
|
ULONG i;
|
||
|
|
||
|
Status = S_OK;
|
||
|
if (Indices != NULL)
|
||
|
{
|
||
|
for (i = 0; i < Count; i++)
|
||
|
{
|
||
|
SingleStatus = GetValue(Indices[i], Values + i);
|
||
|
if (SingleStatus != S_OK)
|
||
|
{
|
||
|
Status = SingleStatus;
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
for (i = 0; i < Count; i++)
|
||
|
{
|
||
|
SingleStatus = GetValue(Start + i, Values + i);
|
||
|
if (SingleStatus != S_OK)
|
||
|
{
|
||
|
Status = SingleStatus;
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
Exit:
|
||
|
LEAVE_ENGINE();
|
||
|
return Status;
|
||
|
}
|
||
|
|
||
|
STDMETHODIMP
|
||
|
DebugClient::SetValues(
|
||
|
THIS_
|
||
|
IN ULONG Count,
|
||
|
IN OPTIONAL PULONG Indices,
|
||
|
IN ULONG Start,
|
||
|
IN PDEBUG_VALUE Values
|
||
|
)
|
||
|
{
|
||
|
HRESULT Status;
|
||
|
|
||
|
ENTER_ENGINE();
|
||
|
|
||
|
if (!IS_CUR_CONTEXT_ACCESSIBLE())
|
||
|
{
|
||
|
Status = E_UNEXPECTED;
|
||
|
goto Exit;
|
||
|
}
|
||
|
|
||
|
HRESULT SingleStatus;
|
||
|
ULONG i;
|
||
|
|
||
|
Status = S_OK;
|
||
|
if (Indices != NULL)
|
||
|
{
|
||
|
for (i = 0; i < Count; i++)
|
||
|
{
|
||
|
SingleStatus = SetValue(Indices[i], Values + i);
|
||
|
if (SingleStatus != S_OK)
|
||
|
{
|
||
|
Status = SingleStatus;
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
for (i = 0; i < Count; i++)
|
||
|
{
|
||
|
SingleStatus = SetValue(Start + i, Values + i);
|
||
|
if (SingleStatus != S_OK)
|
||
|
{
|
||
|
Status = SingleStatus;
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
Exit:
|
||
|
LEAVE_ENGINE();
|
||
|
return Status;
|
||
|
}
|
||
|
|
||
|
STDMETHODIMP
|
||
|
DebugClient::OutputRegisters(
|
||
|
THIS_
|
||
|
IN ULONG OutputControl,
|
||
|
IN ULONG Flags
|
||
|
)
|
||
|
{
|
||
|
// Ensure that the public flags match the internal flags.
|
||
|
C_ASSERT(DEBUG_REGISTERS_INT32 == REGALL_INT32 &&
|
||
|
DEBUG_REGISTERS_INT64 == REGALL_INT64 &&
|
||
|
DEBUG_REGISTERS_FLOAT == REGALL_FLOAT);
|
||
|
|
||
|
if (Flags & ~DEBUG_REGISTERS_ALL)
|
||
|
{
|
||
|
return E_INVALIDARG;
|
||
|
}
|
||
|
|
||
|
HRESULT Status;
|
||
|
|
||
|
ENTER_ENGINE();
|
||
|
|
||
|
if (!IS_CUR_CONTEXT_ACCESSIBLE())
|
||
|
{
|
||
|
Status = E_UNEXPECTED;
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
OutCtlSave OldCtl;
|
||
|
if (!PushOutCtl(OutputControl, this, &OldCtl))
|
||
|
{
|
||
|
Status = E_INVALIDARG;
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
if (Flags == DEBUG_REGISTERS_DEFAULT)
|
||
|
{
|
||
|
Flags = g_Machine->m_AllMask;
|
||
|
}
|
||
|
|
||
|
OutCurInfo(OCI_FORCE_REG, Flags, DEBUG_OUTPUT_NORMAL);
|
||
|
Status = S_OK;
|
||
|
PopOutCtl(&OldCtl);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
LEAVE_ENGINE();
|
||
|
return Status;
|
||
|
}
|
||
|
|
||
|
STDMETHODIMP
|
||
|
DebugClient::GetInstructionOffset(
|
||
|
THIS_
|
||
|
OUT PULONG64 Offset
|
||
|
)
|
||
|
{
|
||
|
HRESULT Status;
|
||
|
|
||
|
ENTER_ENGINE();
|
||
|
|
||
|
if (!IS_CUR_CONTEXT_ACCESSIBLE())
|
||
|
{
|
||
|
Status = E_UNEXPECTED;
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
ADDR Addr;
|
||
|
g_Machine->GetPC(&Addr);
|
||
|
*Offset = Flat(Addr);
|
||
|
Status = S_OK;
|
||
|
}
|
||
|
|
||
|
LEAVE_ENGINE();
|
||
|
return Status;
|
||
|
}
|
||
|
|
||
|
STDMETHODIMP
|
||
|
DebugClient::GetStackOffset(
|
||
|
THIS_
|
||
|
OUT PULONG64 Offset
|
||
|
)
|
||
|
{
|
||
|
HRESULT Status;
|
||
|
|
||
|
ENTER_ENGINE();
|
||
|
|
||
|
if (!IS_CUR_CONTEXT_ACCESSIBLE())
|
||
|
{
|
||
|
Status = E_UNEXPECTED;
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
ADDR Addr;
|
||
|
g_Machine->GetSP(&Addr);
|
||
|
*Offset = Flat(Addr);
|
||
|
Status = S_OK;
|
||
|
}
|
||
|
|
||
|
LEAVE_ENGINE();
|
||
|
return Status;
|
||
|
}
|
||
|
|
||
|
STDMETHODIMP
|
||
|
DebugClient::GetFrameOffset(
|
||
|
THIS_
|
||
|
OUT PULONG64 Offset
|
||
|
)
|
||
|
{
|
||
|
HRESULT Status;
|
||
|
|
||
|
ENTER_ENGINE();
|
||
|
|
||
|
if (!IS_CUR_CONTEXT_ACCESSIBLE())
|
||
|
{
|
||
|
Status = E_UNEXPECTED;
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
ADDR Addr;
|
||
|
g_Machine->GetFP(&Addr);
|
||
|
*Offset = Flat(Addr);
|
||
|
Status = S_OK;
|
||
|
}
|
||
|
|
||
|
LEAVE_ENGINE();
|
||
|
return Status;
|
||
|
}
|