http://msdn.microsoft.com/library/default.asp?url=/library/en-us/debug/base/rtlvirtualunwind.asp
does not appear to be valid for X64. Having stepped into the security check
(/GS) code, which uses it, to try to figure it out it appears that the X64
version expects an additional parameter to what is documented. However,
despite having tried it I cannot get the following code, which runs okay on
Itanium, to unwind two levels up the stack. The second call to
RtlLookupFunctionEntry does not appear to be returning correct information.
Curiously, if the _alloca is removed it works correctly.
Is there some documentation that will indicate what is wrong, or failing
that can somebody tell me what modification would need to be made to the
stack_walk routine to make it work ?
Thanks. Here is the sample code :
#include <windows.h>
// Define the function prototypes and structures used by the unwind routines
as they are
// not included in the Platform SDK headers (the IA64 versions are in
ntia64.h in the DDK).
// Not actually used other than by the function declaration, so contents are
not important.
typedef struct _KNONVOLATILE_CONTEXT_POINTERS {
PULONGLONG dummy;
} KNONVOLATILE_CONTEXT_POINTERS, *PKNONVOLATILE_CONTEXT_POINTERS;
PRUNTIME_FUNCTION
RtlLookupFunctionEntry (
IN ULONGLONG ControlPc,
OUT PULONGLONG ImageBase,
OUT PULONGLONG TargetGp
);
typedef struct _FRAME_POINTERS {
ULONGLONG MemoryStackFp;
ULONGLONG BackingStoreFp;
} FRAME_POINTERS, *PFRAME_POINTERS;
ULONGLONG
RtlVirtualUnwind (
#ifdef _M_AMD64
OUT PULONGLONG Bhah, // Not documented in MSDN so this is a guess.
#endif
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
);
ULONGLONG func();
ULONGLONG stub();
ULONGLONG stack_walk();
main()
{
ULONGLONG pc = func();
}
ULONGLONG func()
{
int p1;
return stub();
}
ULONGLONG stub()
{
int p1;
char *ptr = _alloca(10);
return stack_walk();
}
/*
** stack_walk()
**
*/
ULONGLONG stack_walk()
{
int i;
CONTEXT context;
PRUNTIME_FUNCTION entry;
FRAME_POINTERS EstablisherFrame;
BOOLEAN InFunction;
ULONGLONG ImageBase, TargetGp, ReturnPC, ControlPC;
ULONGLONG ret;
context.ContextFlags = CONTEXT_ALL;
RtlCaptureContext(&context);
#ifdef _M_IA64
ControlPC = context.StIIP;
#else
ControlPC = context.Rip;
#endif
/* Step two levels up the stack. First level is return address of current
* function, second is the return address of the stub that called it.
*/
for (i = 0; i < 2; i++)
{
entry = RtlLookupFunctionEntry(ControlPC, &ImageBase, &TargetGp);
#ifdef _M_IA64
ReturnPC = RtlVirtualUnwind(ImageBase, ControlPC, entry, &context,
&InFunction, &EstablisherFrame, NULL);
if (ReturnPC == 0)
{
return 0;
break;
}
#else
RtlVirtualUnwind(NULL, ImageBase, ControlPC, entry, &context, &InFunction,
&EstablisherFrame, NULL);
ReturnPC = context.Rip;
#endif
ControlPC = ReturnPC;
}
ret = ReturnPC;
return ret;
}
It seems that you are right...
But passing "0" should be ok...
If you have MSDN subscription (Prof. or better) you should contact MS
product support for more infos (and reporting the docu-bug):
http://msdn.microsoft.com/subscriptions/support/technical/
--
Greetings
Jochen
My blog about Win32 and .NET
http://blog.kalmbachnet.de/
I think MS also missed to put the file "ntamd64.h" into the ddk
inc-folder... in this file the RtlVirtualUnwind is correctly defined.
The ntia64.h file is available in the DDK
(C:\WINDDK\3790.1830\inc\ddk\wxp\ntia64.h)... (with the wrong
declaration for x64...)
For x64 the first parameter is ULONG (not PULONGLONG as you assumed) and
you can safely pass 0; for more info you should contact product support...