Пример #1
0
static unsigned int our_stackwalk(ULONG_PTR retaddr, ULONG_PTR sp, PVOID *backtrace, unsigned int count)
{
	/* derived from http://www.nynaeve.net/Code/StackWalk64.cpp */
	CONTEXT ctx;
	DWORD64 imgbase;
	PRUNTIME_FUNCTION runfunc;
	KNONVOLATILE_CONTEXT_POINTERS nvctx;
	PVOID handlerdata;
	ULONG_PTR establisherframe;
	unsigned int frame;

	RtlCaptureContext(&ctx);

	for (frame = 0; frame < count; frame++) {

		backtrace[frame] = (PVOID)ctx.Rip;
		runfunc = RtlLookupFunctionEntry(ctx.Rip, &imgbase, NULL);
		memset(&nvctx, 0, sizeof(nvctx));
		if (runfunc == NULL) {
			ctx.Rip = (ULONG_PTR)(*(ULONG_PTR *)ctx.Rsp);
			ctx.Rsp += 8;
		}
		else {
			RtlVirtualUnwind(UNW_FLAG_NHANDLER, imgbase, ctx.Rip, runfunc, &ctx, &handlerdata, &establisherframe, &nvctx);
		}
		if (!ctx.Rip)
			break;
	}

	return frame + 1;
}
Пример #2
0
    static void __cdecl capture_current_context(CONTEXT* pContextRecord)
    {
        ULONG64           ControlPc;
        ULONG64           EstablisherFrame;
        ULONG64           ImageBase;
        PRUNTIME_FUNCTION FunctionEntry;
        PVOID             HandlerData;

        RtlCaptureContext(pContextRecord);

        ControlPc     = pContextRecord->Rip;
        FunctionEntry = RtlLookupFunctionEntry(ControlPc, &ImageBase, NULL);

        if (FunctionEntry != NULL)
        {
            RtlVirtualUnwind(
                UNW_FLAG_NHANDLER,
                ImageBase,
                ControlPc,
                FunctionEntry,
                pContextRecord,
                &HandlerData,
                &EstablisherFrame,
                NULL);
        }
    }
Пример #3
0
//
// Returns the establisher frame pointers. For catch handlers it is the parent's frame pointer.
//
EHRegistrationNode * __cdecl _GetEstablisherFrame(
    EHRegistrationNode  *pRN,
    DispatcherContext   *pDC,
    FuncInfo            *pFuncInfo,
    EHRegistrationNode  *pEstablisher
) {
    TryBlockMapEntry *pEntry;
    HandlerType *pHandler;
    ULONG_PTR HandlerAdd, ImageBase;
    unsigned num_of_try_blocks = FUNC_NTRYBLOCKS(*pFuncInfo);
    unsigned index, i;
    __ehstate_t curState;

    curState = __StateFromControlPc(pFuncInfo, pDC);
    *pEstablisher = *pRN;
    for (index = num_of_try_blocks; index > 0; index--) {
        pEntry = FUNC_PTRYBLOCK(*pFuncInfo, index -1, pDC->ImageBase);
        if (curState > TBME_HIGH(*pEntry) && curState <= TBME_CATCHHIGH(*pEntry)) {
            // Get catch handler address.
            HandlerAdd = (*RtlLookupFunctionEntry(pDC->ControlPc, &ImageBase, nullptr)).BeginAddress;
            pHandler = TBME_PLIST(*pEntry, ImageBase);
            for ( i = 0;
                  i < (unsigned)TBME_NCATCHES(*pEntry) &&
                  static_cast<ULONG_PTR>(pHandler[i].dispOfHandler) != HandlerAdd
                  ; i++);
            if ( i < (unsigned)TBME_NCATCHES(*pEntry)) {
                *pEstablisher = *(EHRegistrationNode *)OffsetToAddress(pHandler[i].dispFrame, *pRN);
                break;
            }
        }
    }
    return pEstablisher;
}
Пример #4
0
static DWORD64 WINAPI JuliaGetModuleBase64(
        _In_  HANDLE hProcess,
        _In_  DWORD64 dwAddr)
{
    //jl_printf(JL_STDOUT, "lookup base %d\n", dwAddr);
#ifdef _CPU_X86_64_
    DWORD64 ImageBase;
    PRUNTIME_FUNCTION fn = RtlLookupFunctionEntry(dwAddr, &ImageBase, &HistoryTable);
    if (fn) return ImageBase;
    if (jl_in_stackwalk) {
        return 0;
    }
    jl_in_stackwalk = 1;
    DWORD64 fbase = SymGetModuleBase64(hProcess, dwAddr);
    jl_in_stackwalk = 0;
    return fbase;
#else
    if (dwAddr == HistoryTable.dwAddr) return HistoryTable.ImageBase;
    DWORD64 ImageBase = jl_getUnwindInfo(dwAddr);
    if (ImageBase) {
        HistoryTable.dwAddr = dwAddr;
        HistoryTable.ImageBase = ImageBase;
        return ImageBase;
    }
    return SymGetModuleBase64(hProcess, dwAddr);
#endif
}
Пример #5
0
// returns the size (number of bytes) in an X64 function
ULONG 
Getx64FunctionSize ( 
    PVOID Function )
{
    PIMAGE_RUNTIME_FUNCTION_ENTRY  RuntimeFunction;
    ULONGLONG ImageBase = 0;
    ULONG FunctionSize = 0;

    // RtlLookupFunctionEntry() locates the start and end of the function
    // using the X64 exception table information in the PE file
    // RtlLookupFunctionEntry() is only available on X64 systems
    // using it makes this this module incompatible with x86 systems
    RuntimeFunction = (PIMAGE_RUNTIME_FUNCTION_ENTRY)RtlLookupFunctionEntry(
        (ULONGLONG)Function,
        &ImageBase,
        NULL );

    // if there is no valid runtime entry structure then the extents of 
    // the functions cannot be determined
    if ( ! RuntimeFunction ) {
        DPF(("%s!%s RtlLookupFunctionEntry(%p)\n", __MODULE__, __FUNCTION__,
             Function ));
        goto Exit;
    }

    // compute the number of functions in the function body based on the 
    // functions extents, note this logic will not work for BBT'd functions
    FunctionSize = RuntimeFunction->EndAddress - RuntimeFunction->BeginAddress;

    DPF(("%s!%s PRUNTIME_FUNCTION(BeginAddress=0x%08x EndAddress=0x%08x) Size=%u\n", __MODULE__, __FUNCTION__,
        RuntimeFunction->BeginAddress, RuntimeFunction->EndAddress, FunctionSize ));

Exit :
    return FunctionSize;
} // Getx64FunctionSize()
Пример #6
0
/* static */
void XDataAllocator::Register(XDataAllocation * xdataInfo, ULONG_PTR functionStart, DWORD functionSize)
{
#ifdef _WIN32
    ULONG_PTR baseAddress = functionStart;
    xdataInfo->pdata.BeginAddress = (DWORD)(functionStart - baseAddress);
    xdataInfo->pdata.UnwindData = (DWORD)((intptr_t)xdataInfo->address - baseAddress);

    NTSTATUS status = NtdllLibrary::Instance->AddGrowableFunctionTable(&xdataInfo->functionTable,
        &xdataInfo->pdata,
        /*MaxEntryCount*/ 1,
        /*Valid entry count*/ 1,
        /*RangeBase*/ functionStart,
        /*RangeEnd*/ functionStart + functionSize);
    BOOLEAN success = NT_SUCCESS(status);
    Assert(!success || xdataInfo->functionTable != nullptr);

    if (!success)
    {
        Js::Throw::XDataRegistrationError(status, functionStart);
    }

#if DBG
    // Validate that the PDATA registration succeeded
    ULONG64            imageBase = 0;
    RUNTIME_FUNCTION  *runtimeFunction = RtlLookupFunctionEntry((DWORD64)functionStart, &imageBase, nullptr);
    Assert(runtimeFunction != NULL);
#endif

#else  // !_WIN32
    Assert(ReadHead(xdataInfo->address));  // should be non-empty .eh_frame
    __REGISTER_FRAME(xdataInfo->address);
#endif
}
Пример #7
0
__declspec(noreturn) void __cdecl
__report_gsfailure (ULONG_PTR StackCookie)
{
  volatile UINT_PTR cookie[2] __MINGW_ATTRIB_UNUSED;
#if defined(_WIN64) && !defined(__aarch64__)
  ULONG64 controlPC, imgBase, establisherFrame;
  PRUNTIME_FUNCTION fctEntry;
  PVOID hndData;

  RtlCaptureContext (&GS_ContextRecord);
  controlPC = GS_ContextRecord.Rip;
  fctEntry = RtlLookupFunctionEntry (controlPC, &imgBase, NULL);
  if (fctEntry != NULL)
    {
      RtlVirtualUnwind (UNW_FLAG_NHANDLER, imgBase, controlPC, fctEntry,
			&GS_ContextRecord, &hndData, &establisherFrame, NULL);
    }
  else
#endif /* _WIN64 */
    {
#if defined(__x86_64__) || defined(_AMD64_)
      GS_ContextRecord.Rip = (ULONGLONG) _ReturnAddress();
      GS_ContextRecord.Rsp = (ULONGLONG) _AddressOfReturnAddress() + 8;
#elif defined(__i386__) || defined(_X86_)
      GS_ContextRecord.Eip = (DWORD) _ReturnAddress();
      GS_ContextRecord.Esp = (DWORD) _AddressOfReturnAddress() + 4;
#elif defined(__arm__) || defined(_ARM_)
      GS_ContextRecord.Pc = (DWORD) _ReturnAddress();
      GS_ContextRecord.Sp = (DWORD) _AddressOfReturnAddress() + 4;
#endif /* _WIN64 */
    }

#if defined(__x86_64__) || defined(_AMD64_)
  GS_ExceptionRecord.ExceptionAddress = (PVOID) GS_ContextRecord.Rip;
  GS_ContextRecord.Rcx = StackCookie;
#elif defined(__i386__) || defined(_X86_)
  GS_ExceptionRecord.ExceptionAddress = (PVOID) GS_ContextRecord.Eip;
  GS_ContextRecord.Ecx = StackCookie;
#elif defined(__arm__) || defined(_ARM_)
  GS_ExceptionRecord.ExceptionAddress = (PVOID) GS_ContextRecord.Pc;
  UNUSED_PARAM(StackCookie);
#endif /* _WIN64 */
  GS_ExceptionRecord.ExceptionCode = STATUS_STACK_BUFFER_OVERRUN;
  GS_ExceptionRecord.ExceptionFlags = EXCEPTION_NONCONTINUABLE;
  cookie[0] = __security_cookie;
  cookie[1] = __security_cookie_complement;
  SetUnhandledExceptionFilter (NULL);
  UnhandledExceptionFilter ((EXCEPTION_POINTERS *) &GS_ExceptionPointers);
  TerminateProcess (GetCurrentProcess (), STATUS_STACK_BUFFER_OVERRUN);
  abort();
}
Пример #8
0
void longjmpex( jmp_buf jb, int ret )
{
    EXCEPTION_RECORD    er;
    _JUMPEXDATA         *jd = (_JUMPEXDATA *)jb;

    er.ExceptionCode           = 0xE5670123;
    er.ExceptionFlags          = 0x00000002;
    er.ExceptionRecord         = 0L;
    er.ExceptionAddress        = 0L;
    er.NumberParameters        = 1L;
    er.ExceptionInformation[0] = jd->sp;

    if( !_ProcSetsFP( RtlLookupFunctionEntry( jd->pc ) ) )
        RtlUnwind( (void *)jd->sp, (void *)jd->pc, &er, (void *)ret );
    else
        RtlUnwindRfp( jd->fp, jd->pc, &er, ret );
} /* longjmp() */
Пример #9
0
static PVOID CALLBACK JuliaFunctionTableAccess64(
        _In_  HANDLE hProcess,
        _In_  DWORD64 AddrBase)
{
    //jl_printf(JL_STDOUT, "lookup %d\n", AddrBase);
#ifdef _CPU_X86_64_
    DWORD64 ImageBase;
    PRUNTIME_FUNCTION fn = RtlLookupFunctionEntry(AddrBase, &ImageBase, &HistoryTable);
    if (fn) return fn;
    if (jl_in_stackwalk) {
        return 0;
    }
    jl_in_stackwalk = 1;
    PVOID ftable = SymFunctionTableAccess64(hProcess, AddrBase);
    jl_in_stackwalk = 0;
    return ftable;
#else
    return SymFunctionTableAccess64(hProcess, AddrBase);
#endif
}
Пример #10
0
/* static */
void XDataAllocator::Register(XDataAllocation * xdataInfo, ULONG_PTR functionStart, DWORD functionSize)
{
#ifdef _WIN32
    ULONG_PTR baseAddress = functionStart;
    xdataInfo->pdata.BeginAddress = (DWORD)(functionStart - baseAddress);
    xdataInfo->pdata.EndAddress = (DWORD)(xdataInfo->pdata.BeginAddress + functionSize);
    xdataInfo->pdata.UnwindInfoAddress = (DWORD)((intptr_t)xdataInfo->address - baseAddress);

    BOOLEAN success = FALSE;
    if (AutoSystemInfo::Data.IsWin8OrLater())
    {
        DWORD status = NtdllLibrary::Instance->AddGrowableFunctionTable(&xdataInfo->functionTable,
            &xdataInfo->pdata,
            /*MaxEntryCount*/ 1,
            /*Valid entry count*/ 1,
            /*RangeBase*/ functionStart,
            /*RangeEnd*/ functionStart + functionSize);
        success = NT_SUCCESS(status);
        if (success)
        {
            Assert(xdataInfo->functionTable != nullptr);
        }
    }
    else
    {
        success = RtlAddFunctionTable(&xdataInfo->pdata, 1, functionStart);
    }
    Js::Throw::CheckAndThrowOutOfMemory(success);

#if DBG
    // Validate that the PDATA registration succeeded
    ULONG64            imageBase = 0;
    RUNTIME_FUNCTION  *runtimeFunction = RtlLookupFunctionEntry((DWORD64)functionStart, &imageBase, nullptr);
    Assert(runtimeFunction != NULL);
#endif

#else  // !_WIN32
    Assert(ReadHead(xdataInfo->address));  // should be non-empty .eh_frame
    __register_frame(xdataInfo->address);
#endif
}
Пример #11
0
    static void __cdecl capture_previous_context(CONTEXT* pContextRecord)
    {
        ULONG64           ControlPc;
        ULONG64           EstablisherFrame;
        ULONG64           ImageBase;
        PRUNTIME_FUNCTION FunctionEntry;
        PVOID             HandlerData;
        INT               frames;

        RtlCaptureContext(pContextRecord);

        ControlPc = pContextRecord->Rip;

        // Unwind "twice" to get the context of the caller to the "previous" caller:
        for (frames = 0; frames < 2; ++frames)
        {
            FunctionEntry = RtlLookupFunctionEntry(ControlPc, &ImageBase, NULL);

            if (FunctionEntry != NULL)
            {
                RtlVirtualUnwind(
                    UNW_FLAG_NHANDLER,
                    ImageBase,
                    ControlPc,
                    FunctionEntry,
                    pContextRecord,
                    &HandlerData,
                    &EstablisherFrame,
                    NULL);
            }
            else
            {
                break;
            }
        }
    }
Пример #12
0
VOID
RtlGetCallersAddress (
    OUT PVOID *CallersPc,
    OUT PVOID *CallersCallersPc
    )

/*++

Routine Description:

    This routine returns the address of the routine that called the routine
    that called this routine, and the routine that called the routine that
    called this routine. For example, if A called B called C which called
    this routine, the return addresses in A and B would be returned.

Arguments:

    CallersPc - Supplies a pointer to a variable that receives the address
        of the caller of the caller of this routine (B).

    CallersCallersPc - Supplies a pointer to a variable that receives the
        address of the caller of the caller of the caller of this routine
        (A).

Return Value:

    None.

Note:

    If either of the calling stack frames exceeds the limits of the stack,
    they are set to NULL.

--*/

{

    CONTEXT ContextRecord;
    ULONG EstablisherFrame;
    PRUNTIME_FUNCTION FunctionEntry;
    BOOLEAN InFunction;
    ULONG NextPc;
    ULONG HighLimit, LowLimit;

    //
    // Assume the function table entries for the various routines cannot be
    // found or there are not four procedure activation records on the stack.
    //

    *CallersPc = NULL;
    *CallersCallersPc = NULL;

    //
    // Capture the current context.
    //

    RtlCaptureContext(&ContextRecord);
    NextPc = (ULONG)ContextRecord.XIntRa;

    //
    // Get the high and low limits of the current thread's stack.
    //

    RtlpGetStackLimits(&LowLimit, &HighLimit);

    //
    // Attempt to unwind to the caller of this routine (C).
    //

    FunctionEntry = RtlLookupFunctionEntry(NextPc);
    if (FunctionEntry != NULL) {

        //
        // A function entry was found for this routine. Virtually unwind
        // to the caller of this routine (C).
        //

        NextPc = RtlVirtualUnwind(NextPc | 1,
                                  FunctionEntry,
                                  &ContextRecord,
                                  &InFunction,
                                  &EstablisherFrame,
                                  NULL);

        //
        // Attempt to unwind to the caller of the caller of this routine (B).
        //

        FunctionEntry = RtlLookupFunctionEntry(NextPc);
        if ((FunctionEntry != NULL) && ((ULONG)ContextRecord.XIntSp < HighLimit)) {

            //
            // A function table entry was found for the caller of the caller
            // of this routine (B). Virtually unwind to the caller of the
            // caller of this routine (B).
            //

            NextPc = RtlVirtualUnwind(NextPc | 1,
                                      FunctionEntry,
                                      &ContextRecord,
                                      &InFunction,
                                      &EstablisherFrame,
                                      NULL);

            *CallersPc = (PVOID)NextPc;

            //
            // Attempt to unwind to the caller of the caller of the caller
            // of the caller of this routine (A).
            //

            FunctionEntry = RtlLookupFunctionEntry(NextPc);
            if ((FunctionEntry != NULL) && ((ULONG)ContextRecord.XIntSp < HighLimit)) {

                //
                // A function table entry was found for the caller of the
                // caller of the caller of this routine (A). Virtually unwind
                // to the caller of the caller of the caller of this routine
                // (A).
                //

                NextPc = RtlVirtualUnwind(NextPc | 1,
                                          FunctionEntry,
                                          &ContextRecord,
                                          &InFunction,
                                          &EstablisherFrame,
                                          NULL);

                *CallersCallersPc = (PVOID)NextPc;
            }
        }
    }

    return;
}
Пример #13
0
VOID
ExpRaiseException (
    IN PEXCEPTION_RECORD ExceptionRecord
    )

/*++

Routine Description:

    This function raises a software exception by building a context record
    and calling the exception dispatcher directly.

Arguments:

    ExceptionRecord - Supplies a pointer to an exception record.

Return Value:

    None.

--*/

{

    ULONG ControlPc;
    CONTEXT ContextRecord;
    ULONG EstablisherFrame;
    PRUNTIME_FUNCTION FunctionEntry;
    BOOLEAN InFunction;
    ULONG NextPc;
    NTSTATUS Status;

    //
    // Capture the current context, virtually unwind to the caller of this
    // routine, set the fault instruction address to that of the caller, and
    // call the exception dispatcher.
    //

    RtlCaptureContext(&ContextRecord);
    ControlPc = ContextRecord.Lr - 4;
    FunctionEntry = RtlLookupFunctionEntry(ControlPc);
    NextPc = RtlVirtualUnwind(ControlPc,
                              FunctionEntry,
                              &ContextRecord,
                              &InFunction,
                              &EstablisherFrame,
                              NULL,
                              0,
                              0xffffffff);

    ContextRecord.Iar = NextPc + 4;
    ExceptionRecord->ExceptionAddress = (PVOID)ContextRecord.Iar;

    //
    // If the exception is successfully dispatched, then continue execution.
    // Otherwise, give the kernel debugger a chance to handle the exception.
    //

    if (RtlDispatchException(ExceptionRecord, &ContextRecord)) {
        Status = ZwContinue(&ContextRecord, FALSE);

    } else {
        Status = ZwRaiseException(ExceptionRecord, &ContextRecord, FALSE);
    }

    //
    // Either the attempt to continue execution or the attempt to give
    // the kernel debugger a chance to handle the exception failed. Raise
    // a noncontinuable exception.
    //

    ExRaiseStatus(Status);
}
Пример #14
0
int
__gnat_backtrace (void **array,
                  int size,
                  void *exclude_min,
                  void *exclude_max,
                  int skip_frames)
{
  CONTEXT context;
  UNWIND_HISTORY_TABLE history;
  int i;

  /* Get the context.  */
  RtlCaptureContext (&context);

  /* Setup unwind history table (a cached to speed-up unwinding).  */
  memset (&history, 0, sizeof (history));

  i = 0;
  while (1)
    {
      PRUNTIME_FUNCTION RuntimeFunction;
      KNONVOLATILE_CONTEXT_POINTERS NvContext;
      ULONG64 ImageBase;
      VOID *HandlerData;
      ULONG64 EstablisherFrame;

      /* Get function metadata.  */
      RuntimeFunction = RtlLookupFunctionEntry
	(context.Rip, &ImageBase, &history);

      if (!RuntimeFunction)
	{
	  /* In case of failure, assume this is a leaf function.  */
	  context.Rip = *(ULONG64 *) context.Rsp;
	  context.Rsp += 8;
	}
      else
	{
	  /* Unwind.  */
	  memset (&NvContext, 0, sizeof (KNONVOLATILE_CONTEXT_POINTERS));
	  RtlVirtualUnwind (0, ImageBase, context.Rip, RuntimeFunction,
			    &context, &HandlerData, &EstablisherFrame,
			    &NvContext);
	}

      /* 0 means bottom of the stack.  */
      if (context.Rip == 0)
	break;

      /* Skip frames.  */
      if (skip_frames > 1)
	{
	  skip_frames--;
	  continue;
	}
      /* Excluded frames.  */
      if ((void *)context.Rip >= exclude_min
	  && (void *)context.Rip <= exclude_max)
	continue;

      array[i++] = (void *)(context.Rip - 2);
      if (i >= size)
	break;
    }
  return i;
}
Пример #15
0
int
setjmp (
    IN jmp_buf JumpBuffer
    )

/*++

Routine Description:

    This function performs a set jump operation by capturing the current
    context, virtualy unwinding to the caller of set jump, and returns zero
    to the caller.

Arguments:

    JumpBuffer - Supplies the address of a jump buffer to store the virtual
        frame pointer and target address of the caller.

        N.B. This is an array of double to force quadword alignment.

Return Value:

    A value of zero is returned.

--*/

{

    CONTEXT ContextRecord;
    ULONG EstablisherFrame;
    PRUNTIME_FUNCTION FunctionEntry;
    BOOLEAN InFunction;
    PULONG JumpArray;
    ULONG NextPc;

    //
    // Capture the current context, virtually unwind to the caller of set
    // jump, and return zero to the caller.
    //

    JumpArray = (PULONG)&JumpBuffer[0];
    RtlCaptureContext(&ContextRecord);
    NextPc = ContextRecord.Lr - 4;
    FunctionEntry = RtlLookupFunctionEntry(NextPc);
    NextPc = RtlVirtualUnwind(NextPc,
                              FunctionEntry,
                              &ContextRecord,
                              &InFunction,
                              &EstablisherFrame,
                              NULL,
                              0,
                              0xffffffff);

    JumpArray[1] = NextPc + 4;
    FunctionEntry = RtlLookupFunctionEntry(NextPc);
    NextPc = RtlVirtualUnwind(NextPc,
                              FunctionEntry,
                              &ContextRecord,
                              &InFunction,
                              &EstablisherFrame,
                              NULL,
                              0,
                              0xffffffff);

    JumpArray[0] = EstablisherFrame;
    return 0;
}
Пример #16
0
void RtlUnwindActions2 (
    IN PVOID TargetFrame OPTIONAL,
    IN PEXCEPTION_RECORD ExceptionRecord OPTIONAL,
    IN PCONTEXT ContextRecord
    )

/*++

Routine Description:

    This function initiates an unwind of procedure call frames. The machine
    state at the time of the call to unwind is captured in a context record
    and the unwinding flag is set in the exception flags of the exception
    record. If the TargetFrame parameter is not specified, then the exit unwind
    flag is also set in the exception flags of the exception record. A backward
    scan through the procedure call frames is then performed to find the target
    of the unwind operation.

    As each frame is encounter, the PC where control left the corresponding
    function is determined and used to lookup exception handler information
    in the runtime function table built by the linker. If the respective
    routine has an exception handler, then the handler is called.

    N.B. This routine is provided for backward compatibility with release 1.

Arguments:

    TargetFrame - Supplies an optional pointer to the call frame that is the
        target of the unwind. If this parameter is not specified, then an exit
        unwind is performed.

    TargetIp - Supplies an optional instruction address that specifies the
        continuation address of the unwind. This address is ignored if the
        target frame parameter is not specified.

    ExceptionRecord - Supplies an optional pointer to an exception record.

    ReturnValue - Supplies a value that is to be placed in the integer
        function return register just before continuing execution.

Return Value:

    None.

--*/

{
    // These were originally parameters but are not
    // not needed in this unwinding variant because
    // no context switch to TargetIp will be performed.
    PVOID TargetIp = NULL;
    PVOID ReturnValue = NULL;

    ULONG ControlPc;
#if EH_DBG
    ULONG ControlPcHistory[PC_HISTORY_DEPTH];
    ULONG ControlPcHistoryIndex = 0;
#endif
    DISPATCHER_CONTEXT DispatcherContext;
    EXCEPTION_DISPOSITION Disposition;
    FRAME_POINTERS EstablisherFrame;
    ULONG ExceptionFlags;
    EXCEPTION_RECORD ExceptionRecord1;
#if EH_DBG
    LONG FrameDepth = 0;
#endif
    PRUNTIME_FUNCTION FunctionEntry;
    ULONG HighLimit;
    BOOLEAN InFunction;
    ULONG LowLimit;
    ULONG NextPc;

#if EH_DBG
    if (EHRtlDebugFlags & RTL_DBG_UNWIND) {
        DbgPrint("\nRtlUnwindActions2(TargetFrame = %lx, TargetIp = %lx,, ReturnValue = %lx)\n",
                 TargetFrame, TargetIp, ReturnValue);
    }
#endif
    //
    // Get current stack limits, capture the current context, virtually
    // unwind to the caller of this routine, get the initial PC value, and
    // set the unwind target address.
    //

    __CxxGetStackLimits(&LowLimit, &HighLimit);
    RtlCaptureContext(ContextRecord);
    ControlPc = (ULONG)ContextRecord->IntRa - 4;
    FunctionEntry = RtlLookupFunctionEntry(ControlPc);
    NextPc = RtlVirtualUnwind(ControlPc,
                              FunctionEntry,
                              ContextRecord,
                              &InFunction,
                              &EstablisherFrame,
                              NULL);

    ControlPc = NextPc;
    ContextRecord->Fir = (ULONGLONG)(LONG)TargetIp;

    //
    // If an exception record is not specified, then build a local exception
    // record for use in calling exception handlers during the unwind operation.
    //

    if (ARGUMENT_PRESENT(ExceptionRecord) == FALSE) {
        ExceptionRecord = &ExceptionRecord1;
        ExceptionRecord1.ExceptionCode = STATUS_UNWIND;
        ExceptionRecord1.ExceptionRecord = NULL;
        ExceptionRecord1.ExceptionAddress = (PVOID)ControlPc;
        ExceptionRecord1.NumberParameters = 0;
    }

    //
    // If the target frame of the unwind is specified, then a normal unwind
    // is being performed. Otherwise, an exit unwind is being performed.
    //

    ExceptionFlags = EXCEPTION_UNWINDING;
    if (ARGUMENT_PRESENT(TargetFrame) == FALSE) {
        ExceptionRecord->ExceptionFlags |= EXCEPTION_EXIT_UNWIND;
    }

    //
    // Scan backward through the call frame hierarchy and call exception
    // handlers until the target frame of the unwind is reached.
    //

    do {
#if EH_DBG
        if (EHRtlDebugFlags & RTL_DBG_UNWIND_DETAIL) {
            DbgPrint("RtlUnwindActions2: Loop: FrameDepth = %d, sp = %lx, ControlPc = %lx\n",
                     FrameDepth, ContextRecord->IntSp, ControlPc);
            FrameDepth -= 1;
        }
#endif

        //
        // Lookup the function table entry using the point at which control
        // left the procedure.
        //

        FunctionEntry = RtlLookupFunctionEntry(ControlPc);

        //
        // If there is a function table entry for the routine, then virtually
        // unwind to the caller of the routine to obtain the virtual frame
        // pointer of the establisher, but don't update the context record.
        //

        if (FunctionEntry != NULL) {
            {
                CONTEXT LocalContext;
                RtlMoveMemory((PVOID)&LocalContext, ContextRecord, sizeof(CONTEXT));
                NextPc = RtlVirtualUnwind(ControlPc,
                                           FunctionEntry,
                                           &LocalContext,
                                           &InFunction,
                                           &EstablisherFrame,
                                           NULL);
            }

            //
            // If the virtual frame pointer is not within the specified stack
            // limits, the virtual frame pointer is unaligned, or the target
            // frame is below the virtual frame and an exit unwind is not being
            // performed, then raise the exception STATUS_BAD_STACK. Otherwise,
            // check to determine if the current routine has an exception
            // handler.
            //

            if ((EstablisherFrame.Virtual < LowLimit) ||
                (EstablisherFrame.Virtual > HighLimit) ||
                ((ARGUMENT_PRESENT(TargetFrame) != FALSE) &&
                 ((ULONG)TargetFrame < EstablisherFrame.Virtual)) ||
                ((EstablisherFrame.Virtual & 0xF) != 0)) {
#if EH_DBG
                DbgPrint("\n****** Warning - bad stack or target frame (unwind).\n");
                DbgPrint("  EstablisherFrame Virtual = %08lx, Real = %08lx\n",
                         EstablisherFrame.Virtual, EstablisherFrame.Real);
                DbgPrint("  TargetFrame = %08lx\n", TargetFrame);
                if ((ARGUMENT_PRESENT(TargetFrame) != FALSE) &&
                    ((ULONG)TargetFrame < EstablisherFrame.Virtual)) {
                    DbgPrint("  TargetFrame is below EstablisherFrame!\n");
                }
                DbgPrint("  Previous EstablisherFrame (sp) = %08lx\n",
                         (ULONG)ContextRecord->IntSp);
                DbgPrint("  LowLimit = %08lx, HighLimit = %08lx\n",
                         LowLimit, HighLimit);
                DbgPrint("  NextPc = %08lx, ControlPc = %08lx\n",
                         NextPc, ControlPc);
                DbgPrint("  Now raising STATUS_BAD_STACK exception.\n");
#endif
                _write(2, "C++ EH run-time failure 2 - aborting\n", 37);
                abort();

            } else if ((FunctionEntry->ExceptionHandler != NULL) && InFunction) {
#if EH_DBG
                if (EHRtlDebugFlags & RTL_DBG_DISPATCH_EXCEPTION_DETAIL) {
                    DbgPrint("RtlUnwindActions2: ExceptionHandler = %lx, HandlerData = %lx\n",
                         FunctionEntry->ExceptionHandler, FunctionEntry->HandlerData);
                }
#endif

                //
                // The frame has an exception handler.
                //
                // The control PC, establisher frame pointer, the address
                // of the function table entry, and the address of the
                // context record are all stored in the dispatcher context.
                // This information is used by the unwind linkage routine
                // and can be used by the exception handler itself.
                //
                // A linkage routine written in assembler is used to actually
                // call the actual exception handler. This is required by the
                // exception handler that is associated with the linkage
                // routine so it can have access to two sets of dispatcher
                // context when it is called.
                //

                DispatcherContext.ControlPc = ControlPc;
                DispatcherContext.FunctionEntry = FunctionEntry;
                DispatcherContext.EstablisherFrame = EstablisherFrame.Virtual;
                DispatcherContext.ContextRecord = ContextRecord;

                //
                // Call the exception handler.
                //

                do {

                    //
                    // If the establisher frame is the target of the unwind
                    // operation, then set the target unwind flag.
                    //

                    if ((ULONG)TargetFrame == EstablisherFrame.Virtual) {
                        ExceptionFlags |= EXCEPTION_TARGET_UNWIND;
                    }

                    ExceptionRecord->ExceptionFlags = ExceptionFlags;

                    //
                    // Set the specified return value in case the exception
                    // handler directly continues execution.
                    //

                    ContextRecord->IntV0 = (ULONGLONG)(LONG)ReturnValue;
#if EH_DBG
                    if (EHRtlDebugFlags & RTL_DBG_UNWIND_DETAIL) {
                        DbgPrint("RtlUnwindActions2: calling __CxxExecuteHandlerForUnwind, ControlPc = %lx\n", ControlPc);
                    }
#endif
                    Disposition =
                        __CxxExecuteHandlerForUnwind(ExceptionRecord,
                                                    (PVOID)EstablisherFrame.Virtual,
                                                    ContextRecord,
                                                    &DispatcherContext,
                                                    FunctionEntry->ExceptionHandler);
#if EH_DBG
                    if (EHRtlDebugFlags & RTL_DBG_UNWIND_DETAIL) {
                        DbgPrint("RtlUnwindActions2: __CxxExecuteHandlerForUnwind returned Disposition = %lx\n", Disposition);
                    }
#endif

                    //
                    // Clear target unwind and collided unwind flags.
                    //

                    ExceptionFlags &= ~(EXCEPTION_COLLIDED_UNWIND |
                                        EXCEPTION_TARGET_UNWIND);

                    //
                    // Case on the handler disposition.
                    //

                    switch (Disposition) {

                        //
                        // The disposition is to continue the search.
                        //
                        // If the target frame has not been reached, then
                        // virtually unwind to the caller of the current
                        // routine, update the context record, and continue
                        // the search for a handler.
                        //

                    case ExceptionContinueSearch :
                        if (EstablisherFrame.Virtual != (ULONG)TargetFrame) {
                            NextPc = RtlVirtualUnwind(ControlPc,
                                                      FunctionEntry,
                                                      ContextRecord,
                                                      &InFunction,
                                                      &EstablisherFrame,
                                                      NULL);
                        }

                        break;

                        //
                        // The disposition is collided unwind.
                        //
                        // Set the target of the current unwind to the context
                        // record of the previous unwind, and reexecute the
                        // exception handler from the collided frame with the
                        // collided unwind flag set in the exception record.
                        //

                    case ExceptionCollidedUnwind :
                        ControlPc = DispatcherContext.ControlPc;
                        FunctionEntry = DispatcherContext.FunctionEntry;
                        ContextRecord = DispatcherContext.ContextRecord;
                        ContextRecord->Fir = (ULONGLONG)(LONG)TargetIp;
                        ExceptionFlags |= EXCEPTION_COLLIDED_UNWIND;
                        EstablisherFrame.Virtual = DispatcherContext.EstablisherFrame;
                        break;

                        //
                        // All other disposition values are invalid.
                        //
                        // Raise invalid disposition exception.
                        //

                    default :
                        _write(2, "C++ EH run-time failure 3 - aborting\n", 37);
                        abort();
                    }

                } while ((ExceptionFlags & EXCEPTION_COLLIDED_UNWIND) != 0);
            } else {

                //
                // Virtually unwind to the caller of the current routine and
                // update the context record.
                //

                if (EstablisherFrame.Virtual != (ULONG)TargetFrame) {
                    NextPc = RtlVirtualUnwind(ControlPc,
                                              FunctionEntry,
                                              ContextRecord,
                                              &InFunction,
                                              &EstablisherFrame,
                                              NULL);
                }
            }

        } else {

            //
            // Set point at which control left the previous routine.
            //

            NextPc = (ULONG)ContextRecord->IntRa - 4;

            //
            // If the next control PC is the same as the old control PC, then
            // the function table is not correctly formed.
            //

            if (NextPc == ControlPc) {
#if EH_DBG
                ULONG Count;
                DbgPrint("\n****** Warning - malformed function table (unwind).\n");
                DbgPrint("ControlPc = %08lx, %08lx", NextPc, ControlPc);
                for (Count = 0; Count < PC_HISTORY_DEPTH; Count += 1) {
                    if (ControlPcHistoryIndex > 0) {
                        ControlPcHistoryIndex -= 1;
                        ControlPc = ControlPcHistory[ControlPcHistoryIndex % PC_HISTORY_DEPTH];
                        DbgPrint(", %08lx", ControlPc);
                    }
                }
                DbgPrint(ControlPcHistoryIndex == 0 ? ".\n" : ", ...\n");
                DbgPrint("  Now raising STATUS_BAD_FUNCTION_TABLE exception.\n");
#endif
                _write(2, "C++ EH run-time failure 4 - aborting\n", 37);
                abort();
            }
        }

        //
        // Set point at which control left the previous routine.
        //

#if EH_DBG
        ControlPcHistory[ControlPcHistoryIndex % PC_HISTORY_DEPTH] = ControlPc;
        ControlPcHistoryIndex += 1;
#endif
        ControlPc = NextPc;

    } while ((EstablisherFrame.Virtual < HighLimit) &&
             (EstablisherFrame.Virtual != (ULONG)TargetFrame));

    //
    // If the establisher stack pointer is equal to the target frame
    // pointer, then continue execution.

    // Otherwise, something truely horrible has happend.
    //

    if (EstablisherFrame.Virtual == (ULONG)TargetFrame) {
        ContextRecord->IntV0 = (ULONGLONG)(LONG)ReturnValue;
#if EH_DBG
        if (EHRtlDebugFlags & RTL_DBG_UNWIND) {
            DbgPrint("RtlUnwindActions2: finished unwinding, and calling RtlpRestoreContext(%lx)\n",ContextRecord);
        }
#endif
        // Do not restore the context here.
        // For C++ we need to "logicaly" unwind
        //   the stack, perform several actions,
        //   and then finally "physically" unwind
        //   the stack.
        // RtlpRestoreContext(ContextRecord);
        return;

    } else {
        _write(2, "C++ EH run-time failure 1 - aborting\n", 37);
        abort();
    }
}
Пример #17
0
_WCRTLINK _EXCINFO *_SetPData( _EXCINFO *info )
{
    info->FunctionEntry = RtlLookupFunctionEntry( info->ControlPC );
    return info;
}
Пример #18
0
_Use_decl_annotations_ EXTERN_C IMAGE_RUNTIME_FUNCTION_ENTRY *
FnparseLookupFunctionEntry(FARPROC FunctionAddress, PVOID *ImageBase) {
  PAGED_CODE();

  return RtlLookupFunctionEntry(FunctionAddress, ImageBase, nullptr);
}
Пример #19
0
VOID
ExpRaiseStatus (
    IN NTSTATUS ExceptionCode
    )

/*++

Routine Description:

    This function raises an exception with the specified status value by
    building an exception record, building a context record, and calling the
    exception dispatcher directly. The exception is marked as noncontinuable
    with no parameters. There is no return from this function.

Arguments:

    ExceptionCode - Supplies the status value to be used as the exception
        code for the exception that is to be raised.

Return Value:

    None.

--*/

{

    ULONG ControlPc;
    CONTEXT ContextRecord;
    ULONG EstablisherFrame;
    EXCEPTION_RECORD ExceptionRecord;
    PRUNTIME_FUNCTION FunctionEntry;
    BOOLEAN InFunction;
    ULONG NextPc;
    NTSTATUS Status;

    //
    // Construct an exception record.
    //

    ExceptionRecord.ExceptionCode = ExceptionCode;
    ExceptionRecord.ExceptionRecord = (PEXCEPTION_RECORD)NULL;
    ExceptionRecord.NumberParameters = 0;
    ExceptionRecord.ExceptionFlags = EXCEPTION_NONCONTINUABLE;

    //
    // Capture the current context, virtually unwind to the caller of this
    // routine, set the fault instruction address to that of the caller, and
    // call the exception dispatcher.
    //

    RtlCaptureContext(&ContextRecord);
    ControlPc = ContextRecord.Lr - 4;
    FunctionEntry = RtlLookupFunctionEntry(ControlPc);
    NextPc = RtlVirtualUnwind(ControlPc,
                              FunctionEntry,
                              &ContextRecord,
                              &InFunction,
                              &EstablisherFrame,
                              NULL,
                              0,
                              0xffffffff);

    ContextRecord.Iar = NextPc + 4;
    ExceptionRecord.ExceptionAddress = (PVOID)ContextRecord.Iar;
    RtlDispatchException(&ExceptionRecord, &ContextRecord);

    //
    // An unwind was not initiated during the dispatching of a noncontinuable
    // exception. Give the kernel debugger a chance to handle the exception.
    //

    Status = ZwRaiseException(&ExceptionRecord, &ContextRecord, FALSE);

    //
    // The attempt to give the kernel debugger a chance to handle the exception
    // failed. Raise another noncontinuable exception.
    //

    ExRaiseStatus(Status);
}
Пример #20
0
void StackDump( LPVOID pMem, SIZE_T dwBytes)
{
        
    CONTEXT                       Context;
    //KNONVOLATILE_CONTEXT_POINTERS NvContext;
    //UNWIND_HISTORY_TABLE          UnwindHistoryTable;
    PRUNTIME_FUNCTION             RuntimeFunction;
    PVOID                         HandlerData;
    ULONG64                       EstablisherFrame;
    ULONG64                       ImageBase;

    //OutputDebugString(L"StackTrace64: Executing stack trace...\n");

    //
    // First, we'll get the caller's context.
    //

    RtlCaptureContext(&Context);

    //
    // Initialize the (optional) unwind history table.
    //

    /*RtlZeroMemory(
        &UnwindHistoryTable,
        sizeof(UNWIND_HISTORY_TABLE));*/

    
        //BYTE SymBol[ sizeof(SYMBOL_INFO) + STACKWALK_MAX_NAMELEN ] = {0};
        //SYMBOL_INFO* pSymbol = (SYMBOL_INFO*)SymBol;
        //DWORD64 dwDisplacement;
     
        HANDLE hProcess = GetCurrentProcess();
        MEM_INFO stInfo;
        //stInfo.parCallStack = new STACK_ARRAY;
        
        //void * p = AllocMem(sizeof(STACK_ARRAY));
        //stInfo.parCallStack = new( (void*)p ) STACK_ARRAY;

        stInfo.nMemSize = dwBytes;
        for( int i =0; i < g_StackDepth ; i++ )// only retrieve 40 functions
        {
            //
        // Try to look up unwind metadata for the current function.
        //

        RuntimeFunction = RtlLookupFunctionEntry(
            Context.Rip,
            &ImageBase,
            NULL
            );

        /*RtlZeroMemory(
            &NvContext,
            sizeof(KNONVOLATILE_CONTEXT_POINTERS));*/

        if (!RuntimeFunction)
        {
            //
            // If we don't have a RUNTIME_FUNCTION, then we've encountered
            // a leaf function.  Adjust the stack approprately.
            //

            Context.Rip  = (ULONG64)(*(PULONG64)Context.Rsp);
            Context.Rsp += 8;
        }
        else
        {
            //
            // Otherwise, call upon RtlVirtualUnwind to execute the unwind for
            // us.
            //

            RtlVirtualUnwind(
                0, //UNW_FLAG_NHANDLER,
                ImageBase,
                Context.Rip,
                RuntimeFunction,
                &Context,
                &HandlerData,
                &EstablisherFrame,
                NULL );
        }

        //
        // If we reach an RIP of zero, this means that we've walked off the end
        // of the call stack and are done.
        //

        if (!Context.Rip)
            break;

//////////////////////////////////////////////////////////////////////////
         
                 //if( SymFromAddr( hProcess, Context.Rip, &dwDisplacement, pSymbol ))
                 //{
                 //    CString cs = "Ordinal823";
                 //     if( cs == pSymbol->Name)
                 //    {
                 //        break;
                 //    }
                 //   
                 //}
//////////////////////////////////////////////////////////////////////////

            if( i <= 1 )// ignore the functions on the top of stack which is our own.
            {
                continue;
            }
            stInfo.parCallStack.push_back( Context.Rip );
        }        
        g_Config::m_MemMap[pMem] = stInfo;        
}
Пример #21
0
static __EXC_INFO* setPdata     // SET PDATA INFORMATION
    ( __EXC_INFO* info )        // - exception info
{
    info->dctx.pdata = (PData*)RtlLookupFunctionEntry( info->dctx.pc );
    return info;
}