test: alpha/exdsptch.c File Reference

Main Page | Class Hierarchy | Class List | File List | Class Members | File Members

# exdsptch.c File Reference

`#include "ntrtlp.h"`

Go to the source code of this file.

## Defines

#define | RAISE_EXCEPTION(Status, ExceptionRecordt)
#define | IS_HANDLER_DEFINED(FunctionEntry) (RF_EXCEPTION_HANDLER(FunctionEntry) != 0)
#define | Virtual VirtualFramePointer
#define | Real RealFramePointer
#define | _RtlpDebugDisassemble(ControlPc, ContextRecord)
#define | _RtlpFoundTrapFrame(NextPc)
#define | _RtlpVirtualUnwindExit(NextPc, ContextRecord, EstablisherFrame)

## Functions

int __cdecl | sprintf (char *, const char *,...)
VOID | RtlpRaiseException (IN PEXCEPTION_RECORD ExceptionRecord)
VOID | RtlpRaiseStatus (IN NTSTATUS Status)
ULONG_PTR | RtlpVirtualUnwind (IN ULONG_PTR ControlPc, IN PRUNTIME_FUNCTION FunctionEntry, IN PCONTEXT ContextRecord, OUT PBOOLEAN InFunction, OUT PFRAME_POINTERS EstablisherFrame)
PRUNTIME_FUNCTION | RtlLookupDynamicFunctionEntry (IN ULONG_PTR ControlPc)
PRUNTIME_FUNCTION | RtlLookupStaticFunctionEntry (IN ULONG_PTR ControlPc, OUT PBOOLEAN InImage)
VOID | RtlGetUnwindFunctionEntry (IN ULONG_PTR ControlPc, IN PRUNTIME_FUNCTION FunctionEntry, OUT PRUNTIME_FUNCTION UnwindFunctionEntry, OUT PULONG StackAdjust, OUT PULONG_PTR FixedReturn)
BOOLEAN | RtlDispatchException (IN PEXCEPTION_RECORD ExceptionRecord, IN PCONTEXT ContextRecord)
PRUNTIME_FUNCTION | RtlLookupFunctionEntry (IN ULONG_PTR ControlPc)
VOID | RtlRaiseException (IN PEXCEPTION_RECORD ExceptionRecord)
VOID | RtlRaiseStatus (IN NTSTATUS Status)
VOID | RtlUnwind (IN PVOID TargetFrame OPTIONAL, IN PVOID TargetIp OPTIONAL, IN PEXCEPTION_RECORD ExceptionRecord OPTIONAL, IN PVOID ReturnValue)
VOID | RtlUnwind2 (IN PVOID TargetFrame OPTIONAL, IN PVOID TargetIp OPTIONAL, IN PEXCEPTION_RECORD ExceptionRecord OPTIONAL, IN PVOID ReturnValue, IN PCONTEXT ContextRecord)
ULONG_PTR | RtlVirtualUnwind (IN ULONG_PTR ControlPc, IN PRUNTIME_FUNCTION FunctionEntry, IN OUT PCONTEXT ContextRecord, OUT PBOOLEAN InFunction, OUT PFRAME_POINTERS EstablisherFrame, IN OUT PKNONVOLATILE_CONTEXT_POINTERS ContextPointers OPTIONAL)
PRUNTIME_FUNCTION | RtlLookupDirectFunctionEntry (IN ULONG_PTR ControlPc)
PLIST_ENTRY | RtlGetFunctionTableListHead (VOID)
BOOLEAN | RtlAddFunctionTable (IN PRUNTIME_FUNCTION FunctionTable, IN ULONG EntryCount)
BOOLEAN | RtlDeleteFunctionTable (IN PRUNTIME_FUNCTION FunctionTable)

## Variables

LIST_ENTRY | DynamicFunctionTable

## Define Documentation

#define _RtlpDebugDisassemble | ( | ControlPc,
|  | ContextRecord |  | ) |

| Definition at line 1448 of file alpha/exdsptch.c. Referenced by RtlVirtualUnwind().

#define _RtlpFoundTrapFrame | ( | NextPc |  | ) |

| Definition at line 1449 of file alpha/exdsptch.c. Referenced by RtlVirtualUnwind().

#define _RtlpVirtualUnwindExit | ( | NextPc,
|  | ContextRecord,
|  | EstablisherFrame |  | ) |

| Definition at line 1450 of file alpha/exdsptch.c. Referenced by RtlVirtualUnwind().

#define IS_HANDLER_DEFINED | ( | FunctionEntry |  | ) | (RF_EXCEPTION_HANDLER(FunctionEntry) != 0)

| Definition at line 79 of file alpha/exdsptch.c. Referenced by RtlDispatchException(), RtlUnwind2(), RtlUnwindReturn(), and RtlUnwindRfp().

#define RAISE_EXCEPTION | ( | Status,
|  | ExceptionRecordt |  | ) |

Value:

    { \
        EXCEPTION_RECORD ExceptionRecordn; \
                                                \
        ExceptionRecordn.ExceptionCode = Status; \
        ExceptionRecordn.ExceptionFlags = EXCEPTION_NONCONTINUABLE; \
        ExceptionRecordn.ExceptionRecord = ExceptionRecordt; \
        ExceptionRecordn.NumberParameters = 0; \
        RtlRaiseException(&ExceptionRecordn); \
        }

Definition at line 65 of file alpha/exdsptch.c.

Referenced by RtlDispatchException(), RtlUnwind2(), RtlUnwindReturn(), and RtlUnwindRfp().

#define Real RealFramePointer

| Definition at line 106 of file alpha/exdsptch.c.

#define Virtual VirtualFramePointer

| Definition at line 105 of file alpha/exdsptch.c. Referenced by KeFlushMultipleTb(), KeFlushMultipleTb64(), KeFlushSingleTb(), KeFlushSingleTb64(), KiFlushMultipleTbTarget(), KiFlushMultipleTbTarget64(), KiFlushSingleTbSynchronous(), KiFlushSingleTbTarget(), KiFlushSingleTbTarget64(), KiFlushTargetMultipleTb(), MiGetKSegAddress(), UdfAddToPcb(), UdfCompletePcb(), UdfDeletePcb(), UdfEquivalentPcb(), UdfInitializePcb(), UdfLookupPsnOfExtent(), and UdfUpdateVcbPhase0().

## Function Documentation

BOOLEAN RtlAddFunctionTable | ( | IN PRUNTIME_FUNCTION | FunctionTable,
|  | IN ULONG | EntryCount
| ) |

Definition at line 2869 of file alpha/exdsptch.c.

References DynamicFunctionTable, FALSE, LoaderLock, NULL, RtlAllocateHeap, and TRUE.

    02876                    :
    02877
    02878     Add a dynamic function table to the dynamic function table list. Dynamic
    02879     function tables describe code generated at run-time. The dynamic function
    02880     tables are searched via a call to RtlLookupDynamicFunctionEntry().
    02881     Normally this is only invoked via calls to RtlLookupFunctionEntry().
    02882
    02883     The FunctionTable entries need not be sorted in any particular order. The
    02884     list is scanned for a Min and Max address range and whether or not it is
    02885     sorted. If the latter RtlLookupDynamicFunctionEntry() uses a binary
    02886     search, otherwise it uses a linear search.
    02887
    02888     The dynamic function entries will be searched only after a search
    02889     through the static function entries associated with all current
    02890     process images has failed.
    02891
    02892 Arguments:
    02893
    02894    FunctionTable       Address of an array of function entries where
    02895                        each element is of type RUNTIME_FUNCTION.
    02896
    02897    EntryCount          The number of function entries in the array
    02898
    02899 Return value:
    02900
    02901    TRUE                if RtlAddFunctionTable completed successfully
    02902    FALSE               if RtlAddFunctionTable completed unsuccessfully
    02903
    02904 --*/
    02905 {
    02906     PDYNAMIC_FUNCTION_TABLE pNew;
    02907     PRUNTIME_FUNCTION FunctionEntry;
    02908     ULONG i;
    02909
    02910     if (EntryCount == 0)
    02911         return FALSE;
    02912
    02913     //
    02914     // Make sure the link list is initialized;
    02915     //
    02916
    02917     if (DynamicFunctionTable.Flink == NULL) {
    02918        InitializeListHead(&DynamicFunctionTable);
    02919     }
    02920
    02921     //
    02922     //  Allocate memory for this link list entry
    02923     //
    02924
    02925     pNew = RtlAllocateHeap( RtlProcessHeap(), 0, sizeof(DYNAMIC_FUNCTION_TABLE) );
    02926
    02927     if (pNew != NULL) {
    02928         pNew->FunctionTable = FunctionTable;
    02929         pNew->EntryCount = EntryCount;
    02930         NtQuerySystemTime( &pNew->TimeStamp );
    02931
    02932         //
    02933         // Scan the function table for Minimum/Maximum and to determine
    02934         // if it is sorted. If the latter, we can perform a binary search.
    02935         //
    02936
    02937         FunctionEntry = FunctionTable;
    02938         pNew->MinimumAddress = RF_BEGIN_ADDRESS(FunctionEntry);
    02939         pNew->MaximumAddress = RF_END_ADDRESS(FunctionEntry);
    02940         pNew->Sorted = TRUE;
    02941         FunctionEntry++;
    02942
    02943         for (i = 1; i < EntryCount; FunctionEntry++, i++) {
    02944             if (pNew->Sorted && FunctionEntry->BeginAddress < FunctionTable[i-1].BeginAddress) {
    02945                 pNew->Sorted = FALSE;
    02946             }
    02947             if (FunctionEntry->BeginAddress < pNew->MinimumAddress) {
    02948                 pNew->MinimumAddress = RF_BEGIN_ADDRESS(FunctionEntry);
    02949             }
    02950             if (FunctionEntry->EndAddress > pNew->MaximumAddress) {
    02951                 pNew->MaximumAddress = RF_END_ADDRESS(FunctionEntry);
    02952             }
    02953         }
    02954
    02955         //
    02956         // Insert the new entry in the dynamic function table list.
    02957         // Protect the insertion with the loader lock.
    02958         //
    02959
    02960         RtlEnterCriticalSection((PRTL_CRITICAL_SECTION)NtCurrentPeb()->LoaderLock);
    02961         InsertTailList((PLIST_ENTRY)&DynamicFunctionTable, (PLIST_ENTRY)pNew);
    02962         RtlLeaveCriticalSection((PRTL_CRITICAL_SECTION)NtCurrentPeb()->LoaderLock);
    02963
    02964         return TRUE;
    02965     } else {
    02966         return FALSE;
    02967     }
    02968 }

BOOLEAN RtlDeleteFunctionTable | ( | IN PRUNTIME_FUNCTION | FunctionTable | ) |

Definition at line 2971 of file alpha/exdsptch.c.

References DynamicFunctionTable, FALSE, LoaderLock, RtlFreeHeap, Status, and TRUE.

    02974 {
    02975
    02976 /*++
    02977
    02978 Routine Description:
    02979
    02980     Remove a dynamic function table from the dynamic function table list.
    02981
    02982 Arguments:
    02983
    02984    FunctionTable       Address of an array of function entries that
    02985                        was passed in a previous call to RtlAddFunctionTable
    02986
    02987 Return Value
    02988
    02989     TRUE - If function completed successfully
    02990     FALSE - If function completed unsuccessfully
    02991
    02992 --*/
    02993
    02994     PDYNAMIC_FUNCTION_TABLE CurrentEntry;
    02995     PLIST_ENTRY Head;
    02996     PLIST_ENTRY Next;
    02997     BOOLEAN Status = FALSE;
    02998
    02999     RtlEnterCriticalSection((PRTL_CRITICAL_SECTION)NtCurrentPeb()->LoaderLock);
    03000
    03001     //
    03002     // Search the dynamic function table list for a match on the the function
    03003     // table address.
    03004     //
    03005
    03006     Head = &DynamicFunctionTable;
    03007     for (Next = Head->Blink; Next != Head; Next = Next->Blink) {
    03008         CurrentEntry = CONTAINING_RECORD(Next,DYNAMIC_FUNCTION_TABLE,Links);
    03009         if (CurrentEntry->FunctionTable == FunctionTable) {
    03010             RemoveEntryList((PLIST_ENTRY)CurrentEntry);
    03011             RtlFreeHeap( RtlProcessHeap(), 0, CurrentEntry );
    03012             Status = TRUE;
    03013             break;
    03014         }
    03015     }
    03016
    03017     RtlLeaveCriticalSection((PRTL_CRITICAL_SECTION)NtCurrentPeb()->LoaderLock);
    03018     return Status;
    03019 }

BOOLEAN RtlDispatchException | ( | IN PEXCEPTION_RECORD | ExceptionRecord,
|  | IN PCONTEXT | ContextRecord
| ) |

Definition at line 162 of file alpha/exdsptch.c.

References Count, DbgPrint, DISPATCHER_CONTEXT, EXCEPTION_NESTED_CALL, EXCEPTION_NONCONTINUABLE, EXCEPTION_STACK_INVALID, ExceptionContinueExecution, ExceptionContinueSearch, ExceptionNestedException, FALSE, Index, IS_HANDLER_DEFINED, NtGlobalFlag, NULL, RAISE_EXCEPTION, RtlLookupFunctionEntry(), RtlpExecuteHandlerForException(), RtlpGetStackLimits(), RtlpLogExceptionHandler(), RtlpLogLastExceptionDisposition(), RtlVirtualUnwind(), and TRUE.

    00169                    :
    00170
    00171     This function attempts to dispatch an exception to a frame based
    00172     handler by searching backwards through the stack based call frames.
    00173     The search begins with the frame specified in the context record and
    00174     continues backward until either a handler is found that handles the
    00175     exception, the stack is found to be invalid (i.e., out of limits or
    00176     unaligned), or the end of the call hierarchy is reached.
    00177
    00178     As each frame is encountered, the PC where control left the corresponding
    00179     function is determined and used to lookup exception handler information
    00180     in the runtime function table built by the linker. If the respective
    00181     routine has an exception handler, then the handler is called. If the
    00182     handler does not handle the exception, then the prologue of the routine
    00183     is executed backwards to "unwind" the effect of the prologue and then
    00184     the next frame is examined.
    00185
    00186 Arguments:
    00187
    00188     ExceptionRecord - Supplies a pointer to an exception record.
    00189
    00190     ContextRecord - Supplies a pointer to a context record.
    00191
    00192 Return Value:
    00193
    00194     If the exception is handled by one of the frame based handlers, then
    00195     a value of TRUE is returned. Otherwise a value of FALSE is returned.
    00196
    00197 --*/
    00198
    00199 {
    00200
    00201     CONTEXT ContextRecord1;
    00202     ULONG_PTR ControlPc;
    00203 #if DBG
    00204     ULONG_PTR ControlPcHistory[PC_HISTORY_DEPTH];
    00205     ULONG ControlPcHistoryIndex = 0;
    00206 #endif
    00207     DISPATCHER_CONTEXT DispatcherContext;
    00208     EXCEPTION_DISPOSITION Disposition;
    00209     FRAME_POINTERS EstablisherFrame;
    00210     ULONG ExceptionFlags;
    00211 #if DBG
    00212     LONG FrameDepth = 0;
    00213 #endif
    00214     PRUNTIME_FUNCTION FunctionEntry;
    00215     ULONG_PTR HighLimit;
    00216     BOOLEAN InFunction;
    00217     ULONG_PTR LowLimit;
    00218     ULONG_PTR NestedFrame;
    00219     ULONG_PTR NextPc;
    00220
    00221     //
    00222     // Get current stack limits, copy the context record, get the initial
    00223     // PC value, capture the exception flags, and set the nested exception
    00224     // frame pointer.
    00225     //
    00226     // The initial PC value is obtained from ExceptionAddress rather than
    00227     // from ContextRecord.Fir since some Alpha exceptions are asynchronous.
    00228     //
    00229
    00230     RtlpGetStackLimits(&LowLimit, &HighLimit);
    00231     RtlMoveMemory(&ContextRecord1, ContextRecord, sizeof(CONTEXT));
    00232     ControlPc = (ULONG_PTR)ExceptionRecord->ExceptionAddress;
    00233
    00234 #if DBG
    00235     if ((ULONG_PTR)ExceptionRecord->ExceptionAddress != (ULONG_PTR)ContextRecord->Fir) {
    00236         DbgPrint("RtlDispatchException: ExceptionAddress = %p, Fir = %p\n",
    00237                  ExceptionRecord->ExceptionAddress, (ULONG_PTR)ContextRecord->Fir);
    00238     }
    00239 #endif
    00240
    00241     ExceptionFlags = ExceptionRecord->ExceptionFlags & EXCEPTION_NONCONTINUABLE;
    00242     NestedFrame = 0;
    00243
    00244 #if DBG
    00245     if (RtlDebugFlags & RTL_DBG_DISPATCH_EXCEPTION) {
    00246         DbgPrint("\nRtlDispatchException(ExceptionRecord = %p, ContextRecord = %p)\n",
    00247                  ExceptionRecord, ContextRecord);
    00248         DbgPrint("RtlDispatchException: ControlPc = %p, ExceptionRecord->ExceptionCode = %lx\n",
    00249                  ControlPc, ExceptionRecord->ExceptionCode);
    00250     }
    00251 #endif
    00252
    00253     //
    00254     // Start with the frame specified by the context record and search
    00255     // backwards through the call frame hierarchy attempting to find an
    00256     // exception handler that will handle the exception.
    00257     //
    00258
    00259     do {
    00260 #if DBG
    00261         if (RtlDebugFlags & RTL_DBG_DISPATCH_EXCEPTION_DETAIL) {
    00262             DbgPrint("RtlDispatchException: Loop: FrameDepth = %d, sp = %p, ControlPc = %p\n",
    00263                      FrameDepth, (ULONG_PTR)ContextRecord1.IntSp, ControlPc);
    00264             FrameDepth -= 1;
    00265         }
    00266 #endif
    00267
    00268         //
    00269         // Lookup the function table entry using the point at which control
    00270         // left the procedure.
    00271         //
    00272
    00273         FunctionEntry = RtlLookupFunctionEntry(ControlPc);
    00274
    00275         //
    00276         // If there is a function table entry for the routine, then virtually
    00277         // unwind to the caller of the current routine to obtain the virtual
    00278         // frame pointer of the establisher and check if there is an exception
    00279         // handler for the frame.
    00280         //
    00281
    00282         if (FunctionEntry != NULL) {
    00283             NextPc = RtlVirtualUnwind(ControlPc,
    00284                                       FunctionEntry,
    00285                                       &ContextRecord1,
    00286                                       &InFunction,
    00287                                       &EstablisherFrame,
    00288                                       NULL);
    00289
    00290             //
    00291             // If the virtual frame pointer is not within the specified stack
    00292             // limits or the virtual frame pointer is unaligned, then set the
    00293             // stack invalid flag in the exception record and return exception
    00294             // not handled. Otherwise, check if the current routine has an
    00295             // exception handler.
    00296             //
    00297
    00298             if ((EstablisherFrame.Virtual < LowLimit) ||
    00299                 (EstablisherFrame.Virtual > HighLimit) ||
    00300                 ((EstablisherFrame.Virtual & 0xF) != 0)) {
    00301
    00302 #if DBG
    00303                 DbgPrint("\n****** Warning - stack invalid (exception).\n");
    00304                 DbgPrint("  EstablisherFrame.Virtual = %p, EstablisherFrame.Real = %p\n",
    00305                          EstablisherFrame.Virtual, EstablisherFrame.Real);
    00306                 DbgPrint("  LowLimit = %p, HighLimit = %p\n",
    00307                          LowLimit, HighLimit);
    00308                 DbgPrint("  NextPc = %p, ControlPc = %p\n",
    00309                          NextPc, ControlPc);
    00310                 DbgPrint("  Now setting EXCEPTION_STACK_INVALID flag.\n");
    00311 #endif
    00312
    00313                 ExceptionFlags |= EXCEPTION_STACK_INVALID;
    00314                 break;
    00315
    00316             } else if (IS_HANDLER_DEFINED(FunctionEntry) && InFunction) {
    00317
    00318                 ULONG Index;
    00319
    00320 #if DBG
    00321                 if (RtlDebugFlags & RTL_DBG_DISPATCH_EXCEPTION_DETAIL) {
    00322                     DbgPrint("RtlDispatchException: ExceptionHandler = %p, HandlerData = %p\n",
    00323                              FunctionEntry->ExceptionHandler, FunctionEntry->HandlerData);
    00324                 }
    00325 #endif
    00326
    00327                 //
    00328                 // The frame has an exception handler. The handler must be
    00329                 // executed by calling another routine that is written in
    00330                 // assembler. This is required because up level addressing
    00331                 // of the handler information is required when a nested
    00332                 // exception is encountered.
    00333                 //
    00334
    00335                 DispatcherContext.ControlPc = ControlPc;
    00336                 DispatcherContext.FunctionEntry = FunctionEntry;
    00337                 DispatcherContext.EstablisherFrame = EstablisherFrame.Virtual;
    00338                 DispatcherContext.ContextRecord = ContextRecord;
    00339                 ExceptionRecord->ExceptionFlags = ExceptionFlags;
    00340
    00341                 if (NtGlobalFlag & FLG_ENABLE_EXCEPTION_LOGGING) {
    00342                     Index = RtlpLogExceptionHandler(
    00343                                     ExceptionRecord,
    00344                                     ContextRecord,
    00345                                     ControlPc,
    00346                                     FunctionEntry,
    00347                                     sizeof(RUNTIME_FUNCTION));
    00348                 }
    00349
    00350 #if DBG
    00351                 if (RtlDebugFlags & RTL_DBG_DISPATCH_EXCEPTION_DETAIL) {
    00352                     DbgPrint("RtlDispatchException: calling RtlpExecuteHandlerForException, ControlPc = %lx Handler = %lx\n",
    00353                              ControlPc, RF_EXCEPTION_HANDLER(FunctionEntry) );
    00354                 }
    00355 #endif
    00356                 Disposition =
    00357                     RtlpExecuteHandlerForException(ExceptionRecord,
    00358                                                    EstablisherFrame.Virtual,
    00359                                                    ContextRecord,
    00360                                                    &DispatcherContext,
    00361                                                    RF_EXCEPTION_HANDLER(FunctionEntry));
    00362 #if DBG
    00363                 if (RtlDebugFlags & RTL_DBG_DISPATCH_EXCEPTION_DETAIL) {
    00364                     DbgPrint("RtlDispatchException: RtlpExecuteHandlerForException returned Disposition = %lx\n", Disposition);
    00365                 }
    00366 #endif
    00367
    00368                 if (NtGlobalFlag & FLG_ENABLE_EXCEPTION_LOGGING) {
    00369                     RtlpLogLastExceptionDisposition(Index, Disposition);
    00370                 }
    00371
    00372                 ExceptionFlags |=
    00373                     (ExceptionRecord->ExceptionFlags & EXCEPTION_NONCONTINUABLE);
    00374
    00375                 //
    00376                 // If the current scan is within a nested context and the frame
    00377                 // just examined is the end of the nested region, then clear
    00378                 // the nested context frame and the nested exception flag in
    00379                 // the exception flags.
    00380                 //
    00381
    00382                 if (NestedFrame == EstablisherFrame.Virtual) {
    00383                     ExceptionFlags &= (~EXCEPTION_NESTED_CALL);
    00384                     NestedFrame = 0;
    00385                 }
    00386
    00387                 //
    00388                 // Case on the handler disposition.
    00389                 //
    00390
    00391                 switch (Disposition) {
    00392
    00393                     //
    00394                     // The disposition is to continue execution.
    00395                     //
    00396                     // If the exception is not continuable, then raise the
    00397                     // exception STATUS_NONCONTINUABLE_EXCEPTION. Otherwise
    00398                     // return exception handled.
    00399                     //
    00400
    00401                 case ExceptionContinueExecution :
    00402                     if ((ExceptionFlags & EXCEPTION_NONCONTINUABLE) != 0) {
    00403                         RAISE_EXCEPTION(STATUS_NONCONTINUABLE_EXCEPTION, ExceptionRecord);
    00404
    00405                     } else {
    00406 #if DBG
    00407                         if (RtlDebugFlags & RTL_DBG_DISPATCH_EXCEPTION) {
    00408                             DbgPrint("RtlDispatchException: returning TRUE\n");
    00409                         }
    00410 #endif
    00411                         return TRUE;
    00412                     }
    00413
    00414                     //
    00415                     // The disposition is to continue the search.
    00416                     //
    00417                     // Get next frame address and continue the search.
    00418                     //
    00419
    00420                 case ExceptionContinueSearch :
    00421                     break;
    00422
    00423                     //
    00424                     // The disposition is nested exception.
    00425                     //
    00426                     // Set the nested context frame to the establisher frame
    00427                     // address and set the nested exception flag in the
    00428                     // exception flags.
    00429                     //
    00430
    00431                 case ExceptionNestedException :
    00432                     ExceptionFlags |= EXCEPTION_NESTED_CALL;
    00433                     if (DispatcherContext.EstablisherFrame > NestedFrame) {
    00434                         NestedFrame = DispatcherContext.EstablisherFrame;
    00435                     }
    00436
    00437                     break;
    00438
    00439                     //
    00440                     // All other disposition values are invalid.
    00441                     //
    00442                     // Raise invalid disposition exception.
    00443                     //
    00444
    00445                 default :
    00446                     RAISE_EXCEPTION(STATUS_INVALID_DISPOSITION, ExceptionRecord);
    00447                 }
    00448             }
    00449
    00450         } else {
    00451
    00452             //
    00453             // Set point at which control left the previous routine.
    00454             //
    00455
    00456             NextPc = (ULONG_PTR)ContextRecord1.IntRa - 4;
    00457
    00458             //
    00459             // If the next control PC is the same as the old control PC, then
    00460             // the function table is not correctly formed.
    00461             //
    00462
    00463             if (NextPc == ControlPc) {
    00464 #if DBG
    00465                 ULONG Count;
    00466                 DbgPrint("\n****** Warning - malformed function table (exception).\n");
    00467                 DbgPrint("ControlPc = %p, NextPc %p", NextPc, ControlPc);
    00468                 for (Count = 0; Count < PC_HISTORY_DEPTH; Count += 1) {
    00469                     if (ControlPcHistoryIndex > 0) {
    00470                         ControlPcHistoryIndex -= 1;
    00471                         ControlPc = ControlPcHistory[ControlPcHistoryIndex % PC_HISTORY_DEPTH];
    00472                         DbgPrint(", %p", ControlPc);
    00473                     }
    00474                 }
    00475                 DbgPrint(ControlPcHistoryIndex == 0 ? ".\n" : ", ...\n");
    00476 #endif
    00477                 break;
    00478             }
    00479         }
    00480
    00481         //
    00482         // Set point at which control left the previous routine.
    00483         //
    00484
    00485 #if DBG
    00486         ControlPcHistory[ControlPcHistoryIndex % PC_HISTORY_DEPTH] = ControlPc;
    00487         ControlPcHistoryIndex += 1;
    00488 #endif
    00489         ControlPc = NextPc;
    00490
    00491     } while ((ULONG_PTR)ContextRecord1.IntSp < HighLimit);
    00492
    00493     //
    00494     // Set final exception flags and return exception not handled.
    00495     //
    00496
    00497     ExceptionRecord->ExceptionFlags = ExceptionFlags;
    00498 #if DBG
    00499     if (RtlDebugFlags & RTL_DBG_DISPATCH_EXCEPTION) {
    00500         DbgPrint("RtlDispatchException: returning FALSE\n");
    00501     }
    00502 #endif
    00503     return FALSE;
    00504 }

PLIST_ENTRY RtlGetFunctionTableListHead | ( | VOID |  | ) |

Definition at line 2849 of file alpha/exdsptch.c.

References DynamicFunctionTable.

    02855                    :
    02856
    02857     Return the address of the dynamic function table list head.
    02858
    02859 Return value:
    02860
    02861     Address of dynamic function table list head.
    02862
    02863 --*/
    02864 {
    02865     return &DynamicFunctionTable;
    02866 }

VOID RtlGetUnwindFunctionEntry | ( | IN ULONG_PTR | ControlPc,
|  | IN PRUNTIME_FUNCTION | FunctionEntry,
|  | OUT PRUNTIME_FUNCTION | UnwindFunctionEntry,
|  | OUT PULONG | StackAdjust,
|  | OUT PULONG_PTR | FixedReturn
| ) |

Definition at line 2536 of file alpha/exdsptch.c.

References DbgPrint, NULL, and RtlLookupDirectFunctionEntry().

Referenced by RtlVirtualUnwind().

    02545                    :
    02546
    02547     This function returns a function entry (RUNTIME_FUNCTION) suitable
    02548     for unwinding from ControlPc. It encapsulates the handling of primary
    02549     and secondary function entries so that this processing is not duplicated
    02550     in RtlVirtualUnwind and other similar functions.
    02551
    02552 Arguments:
    02553
    02554     ControlPc - Supplies the address where control left the specified
    02555         function.
    02556
    02557     FunctionEntry - Supplies the address of the function table entry for the
    02558         specified function.
    02559
    02560     UnwindFunctionEntry - Supplies the address of a function table entry which
    02561         will be setup with appropriate fields for unwinding from ControlPc
    02562
    02563     StackAdjust - Receives the optional stack adjustment amount specified
    02564         in RF_NULL_CONTEXT type secondary function entries. Will be zero
    02565         if no null-context stack adjustment is required.
    02566
    02567     FixedReturn - Receives the return address specified by fixed-return functin
    02568         entries. Will be zero if a fixed return address was not specified.
    02569
    02570 Return Value:
    02571
    02572     None.
    02573
    02574 --*/
    02575
    02576 {
    02577     ULONG EntryType = 0;
    02578     PRUNTIME_FUNCTION SecondaryFunctionEntry = NULL;
    02579     ULONG_PTR AlternateProlog;
    02580
    02581     *FixedReturn = 0;
    02582     *StackAdjust = 0;
    02583
    02584     // FunctionEntry should never be null, but if it is create one that
    02585     // looks like a leaf entry for ControlPc
    02586
    02587     if (FunctionEntry == NULL) {
    02588 #if DBG
    02589         DbgPrint("\n****** Warning - Null function table entry for unwinding.\n");
    02590 #endif
    02591         UnwindFunctionEntry->BeginAddress     = ControlPc;
    02592         UnwindFunctionEntry->EndAddress       = ControlPc+4;
    02593         UnwindFunctionEntry->ExceptionHandler = NULL;
    02594         UnwindFunctionEntry->HandlerData      = 0;
    02595         UnwindFunctionEntry->PrologEndAddress = ControlPc;
    02596         return;
    02597     }
    02598
    02599     //
    02600     // Because of the secondary-to-primary function entry indirection applied by
    02601     // RtlLookupFunctionEntry() ControlPc may not be within the range described
    02602     // by the supplied function entry. Call RtlLookupDirectFunctionEntry()
    02603     // to recover the actual (secondary) function entry.  If we don't get a
    02604     // valid associated function entry then process the unwind with the one
    02605     // supplied, trusting that the caller has supplied the given entry intentionally.
    02606     //
    02607     // A secondary function entry is a RUNTIME_FUNCTION entry where
    02608     // PrologEndAddress is not in the range of BeginAddress to EndAddress.
    02609     // There are three types of secondary function entries. They are
    02610     // distinquished by the Entry Type field (2 bits):
    02611     //
    02612     // RF_NOT_CONTIGUOUS - discontiguous code
    02613     // RF_ALT_ENT_PROLOG - alternate entry point prologue
    02614     // RF_NULL_CONTEXT   - null-context code
    02615     //
    02616
    02617     if ((ControlPc <  RF_BEGIN_ADDRESS(FunctionEntry)) ||
    02618         (ControlPc >= RF_END_ADDRESS(FunctionEntry))) {
    02619
    02620         // ControlPC is not in the range of the supplied function entry.
    02621         // Get the actual function entry which is expected to be the
    02622         // associated secondary function entry.
    02623
    02624 #if DBG
    02625         if (RtlDebugFlags & RTL_DBG_FUNCTION_ENTRY) {
    02626             DbgPrint("\nGetUnwindFunctionEntry:RtlLookupDirectFunctionEntry(ControlPc=%lx)\n", ControlPc);
    02627         }
    02628 #endif
    02629         SecondaryFunctionEntry = RtlLookupDirectFunctionEntry( ControlPc );
    02630
    02631         if (SecondaryFunctionEntry) {
    02632
    02633 #if DBG
    02634             ShowRuntimeFunction(SecondaryFunctionEntry, "GetUnwindFunctionEntry: LookupDirectFunctionEntry");
    02635 #endif
    02636
    02637             // If this is a null-context tail region then unwind with a null-context-like descriptor
    02638
    02639             if ((ControlPc >= RF_END_ADDRESS(SecondaryFunctionEntry)-(RF_NULL_CONTEXT_COUNT(SecondaryFunctionEntry)*4)) &&
    02640                 (ControlPc <  RF_END_ADDRESS(SecondaryFunctionEntry))) {
    02641
    02642                 // Use the secondary function entry with PrologEndAddress = BeginAddress.
    02643                 // This ensures that the prologue is not reverse executed.
    02644
    02645                 UnwindFunctionEntry->BeginAddress     = RF_BEGIN_ADDRESS(SecondaryFunctionEntry);
    02646                 UnwindFunctionEntry->EndAddress       = RF_END_ADDRESS(SecondaryFunctionEntry);
    02647                 UnwindFunctionEntry->ExceptionHandler = 0;
    02648                 UnwindFunctionEntry->HandlerData      = 0;
    02649                 UnwindFunctionEntry->PrologEndAddress = RF_BEGIN_ADDRESS(SecondaryFunctionEntry);
    02650                 return;
    02651             }
    02652
    02653             if ((SecondaryFunctionEntry->PrologEndAddress < RF_BEGIN_ADDRESS(SecondaryFunctionEntry)) ||
    02654                 (SecondaryFunctionEntry->PrologEndAddress > RF_END_ADDRESS(SecondaryFunctionEntry))) {
    02655
    02656                 // Got a secondary function entry as expected. But if indirection doesn't point
    02657                 // to FunctionEntry then ignore it and use the caller supplied FunctionEntry.
    02658
    02659                 if (RF_PROLOG_END_ADDRESS(SecondaryFunctionEntry) != (ULONG_PTR)FunctionEntry) {
    02660 #if DBG
    02661                     DbgPrint("RtlGetUnwindFunctionEntry: unexpected secondary function entry from RtlLookupDirectFunctionEntry\n");
    02662 #endif
    02663                     SecondaryFunctionEntry = NULL;
    02664                 }
    02665             } else {
    02666
    02667                 // Got a primary function entry. The only valid type is a
    02668                 // Fixed Return Function Entry, which if present gets processed
    02669                 // at the end.  Even if it is not a fixed return function entry,
    02670                 // use it, since its prolog matches up with the control PC.
    02671
    02672                 FunctionEntry = SecondaryFunctionEntry;
    02673                 SecondaryFunctionEntry = NULL;
    02674
    02675 #if DBG
    02676                 if (!RF_FIXED_RETURN(FunctionEntry)) {
    02677                 DbgPrint("RtlGetUnwindFunctionEntry: unexpected primary function entry from RtlLookupDirectFunctionEntry\n");
    02678                 }
    02679 #endif
    02680             }
    02681 #if DBG
    02682         } else {
    02683             DbgPrint("GetUnwindFunctionEntry: LookupDirectFunctionEntry returned NULL\n");
    02684 #endif
    02685         }
    02686
    02687     } else {
    02688
    02689         // ControlPC is in the range of the supplied function entry.
    02690         // Check if it is a secondary function entry. If so, get the
    02691         // associated primary function entry.
    02692
    02693         // If this is a null-context tail region then unwind with a null-context-like descriptor
    02694
    02695         if ((ControlPc >= RF_END_ADDRESS(FunctionEntry)-(RF_NULL_CONTEXT_COUNT(FunctionEntry)*4)) &&
    02696             (ControlPc <  RF_END_ADDRESS(FunctionEntry))) {
    02697
    02698             // Create the unwind function entry with PrologEndAddress = BeginAddress.
    02699             // This ensures that the prologue is not reverse executed.
    02700
    02701             UnwindFunctionEntry->BeginAddress     = RF_BEGIN_ADDRESS(FunctionEntry);
    02702             UnwindFunctionEntry->EndAddress       = RF_END_ADDRESS(FunctionEntry);
    02703             UnwindFunctionEntry->ExceptionHandler = 0;
    02704             UnwindFunctionEntry->HandlerData      = 0;
    02705             UnwindFunctionEntry->PrologEndAddress = RF_BEGIN_ADDRESS(FunctionEntry);
    02706             return;
    02707         }
    02708
    02709         if ((FunctionEntry->PrologEndAddress < RF_BEGIN_ADDRESS(FunctionEntry)) ||
    02710             (FunctionEntry->PrologEndAddress > RF_END_ADDRESS(FunctionEntry))) {
    02711
    02712             SecondaryFunctionEntry = FunctionEntry;
    02713             FunctionEntry = (PRUNTIME_FUNCTION)RF_PROLOG_END_ADDRESS(SecondaryFunctionEntry);
    02714 #if DBG
    02715             DbgPrint("RtlGetUnwindFunctionEntry: received secondary function entry\n");
    02716 #endif
    02717         }
    02718     }
    02719
    02720 #if DBG
    02721     if (ControlPc & 0x3) {
    02722         DbgPrint("RtlGetUnwindFunctionEntry: Warning - Invalid ControlPc %lx for unwinding.\n", ControlPc);
    02723     } else if (RF_BEGIN_ADDRESS(FunctionEntry) >= RF_END_ADDRESS(FunctionEntry)) {
    02724         ShowRuntimeFunction(FunctionEntry, "RtlGetUnwindFunctionEntry: Warning - BeginAddress < EndAddress.");
    02725     } else if (FunctionEntry->PrologEndAddress < RF_BEGIN_ADDRESS(FunctionEntry)) {
    02726         ShowRuntimeFunction(FunctionEntry, "RtlGetUnwindFunctionEntry: Warning - PrologEndAddress < BeginAddress.");
    02727     } else if (FunctionEntry->PrologEndAddress > RF_END_ADDRESS(FunctionEntry)) {
    02728         ShowRuntimeFunction(FunctionEntry, "RtlGetUnwindFunctionEntry: Warning - PrologEndAddress > EndAddress.");
    02729     }
    02730 #endif
    02731
    02732     // FunctionEntry is now the primary function entry and if SecondaryFunctionEntry is
    02733     // not NULL then it is the secondary function entry that contains the ControlPC. Setup a
    02734     // copy of the FunctionEntry suitable for unwinding. By default use the supplied FunctionEntry.
    02735
    02736     if (SecondaryFunctionEntry) {
    02737
    02738         // Extract the secondary function entry type.
    02739
    02740         EntryType = RF_ENTRY_TYPE(SecondaryFunctionEntry);
    02741
    02742         if (EntryType == RF_NOT_CONTIGUOUS) {
    02743             // The exception happened in the body of the procedure but in a non-contiguous
    02744             // section of code. Regardless of what entry point was used, it is normally valid
    02745             // to unwind using the primary entry point prologue. The only exception is when an
    02746             // alternate prologue is specified However, there may be an
    02747             // alternate prologue end addresss specified in which case unwind using this
    02748             // block as though it were the primary.
    02749
    02750             AlternateProlog = RF_ALT_PROLOG(SecondaryFunctionEntry);
    02751
    02752             if ((AlternateProlog >= RF_BEGIN_ADDRESS(SecondaryFunctionEntry)) &&
    02753                 (AlternateProlog <  RF_END_ADDRESS(SecondaryFunctionEntry))) {
    02754
    02755                 // If the control PC is in the alternate prologue, use the secondary.
    02756                 // The control Pc is not in procedure context.
    02757
    02758                 if ((ControlPc >= RF_BEGIN_ADDRESS(SecondaryFunctionEntry)) &&
    02759                     (ControlPc <  AlternateProlog)) {
    02760
    02761                     UnwindFunctionEntry->BeginAddress     = RF_BEGIN_ADDRESS(SecondaryFunctionEntry);
    02762                     UnwindFunctionEntry->EndAddress       = RF_END_ADDRESS(SecondaryFunctionEntry);
    02763                     UnwindFunctionEntry->ExceptionHandler = 0;
    02764                     UnwindFunctionEntry->HandlerData      = 0;
    02765                     UnwindFunctionEntry->PrologEndAddress = AlternateProlog;
    02766                     return;
    02767                 }
    02768             }
    02769
    02770             // Fall out of the if statement to pick up the primary function entry below.
    02771             // This code is in-procedure-context and subject to the primary's prologue
    02772             // and exception handlers.
    02773
    02774
    02775         } else if (EntryType == RF_ALT_ENT_PROLOG) {
    02776
    02777             // Exception occured in an alternate entry point prologue.
    02778             // Use the secondary function entry with a fixed-up PrologEndAddress.
    02779
    02780             UnwindFunctionEntry->BeginAddress     = RF_BEGIN_ADDRESS(SecondaryFunctionEntry);
    02781             UnwindFunctionEntry->EndAddress       = RF_END_ADDRESS(SecondaryFunctionEntry);
    02782             UnwindFunctionEntry->ExceptionHandler = 0;
    02783             UnwindFunctionEntry->HandlerData      = 0;
    02784             UnwindFunctionEntry->PrologEndAddress = RF_END_ADDRESS(UnwindFunctionEntry);
    02785
    02786             // Check for an alternate prologue.
    02787
    02788             AlternateProlog = RF_ALT_PROLOG(SecondaryFunctionEntry);
    02789             if (AlternateProlog >= UnwindFunctionEntry->BeginAddress &&
    02790                 AlternateProlog <  UnwindFunctionEntry->EndAddress ) {
    02791                 // The prologue is only part of the procedure
    02792                 UnwindFunctionEntry->PrologEndAddress = AlternateProlog;
    02793             }
    02794
    02795             return;
    02796
    02797         } else if (EntryType == RF_NULL_CONTEXT) {
    02798
    02799             // Exception occured in null-context code associated with a primary function.
    02800             // Use the secondary function entry with a PrologEndAddress = BeginAddress.
    02801             // There is no prologue for null-context code.
    02802
    02803             *StackAdjust = RF_STACK_ADJUST(SecondaryFunctionEntry);
    02804             UnwindFunctionEntry->BeginAddress     = RF_BEGIN_ADDRESS(SecondaryFunctionEntry);
    02805             UnwindFunctionEntry->EndAddress       = RF_END_ADDRESS(SecondaryFunctionEntry);
    02806             UnwindFunctionEntry->ExceptionHandler = 0;
    02807             UnwindFunctionEntry->HandlerData      = 0;
    02808             UnwindFunctionEntry->PrologEndAddress = RF_BEGIN_ADDRESS(SecondaryFunctionEntry);
    02809             return;
    02810         }
    02811
    02812     }
    02813
    02814     // Use the primary function entry
    02815
    02816     *UnwindFunctionEntry = *FunctionEntry;
    02817     UnwindFunctionEntry->EndAddress = RF_END_ADDRESS(UnwindFunctionEntry);  // Remove null-context count
    02818
    02819     // If the primary has a fixed return address, pull that out now.
    02820
    02821     if (RF_IS_FIXED_RETURN(FunctionEntry)) {
    02822         *FixedReturn = RF_FIXED_RETURN(FunctionEntry);
    02823         UnwindFunctionEntry->ExceptionHandler = 0;
    02824         UnwindFunctionEntry->HandlerData      = 0;
    02825     }
    02826
    02827     // If the ControlPc is in the primary Null context, return null context.
    02828     // Otherwise, remove Null context count
    02829
    02830     if ((ControlPc >= RF_END_ADDRESS(FunctionEntry)-(RF_NULL_CONTEXT_COUNT(FunctionEntry)*4)) &&
    02831         (ControlPc <  RF_END_ADDRESS(FunctionEntry))) {
    02832
    02833         // Exception occured in null-context code associated with a primary function.
    02834         // Create the unwind function entry with a PrologEndAddress = BeginAddress.
    02835         // This ensures that the prologue is not reverse executed.
    02836
    02837         UnwindFunctionEntry->EndAddress       = RF_END_ADDRESS(FunctionEntry);
    02838         UnwindFunctionEntry->ExceptionHandler = 0;
    02839         UnwindFunctionEntry->HandlerData      = 0;
    02840         UnwindFunctionEntry->PrologEndAddress = RF_BEGIN_ADDRESS(FunctionEntry);
    02841     }
    02842     else {
    02843         UnwindFunctionEntry->EndAddress       = RF_END_ADDRESS(FunctionEntry);
    02844     }
    02845 }
    #if !defined(NTOS_KERNEL_RUNTIME)

PRUNTIME_FUNCTION RtlLookupDirectFunctionEntry | ( | IN ULONG_PTR | ControlPc | ) |

Definition at line 2364 of file alpha/exdsptch.c.

References DbgPrint, NULL, RtlLookupDynamicFunctionEntry(), and RtlLookupStaticFunctionEntry().

Referenced by RtlGetUnwindFunctionEntry(), and RtlLookupFunctionEntry().

    02370                    :
    02371
    02372     This function searches the currently active function tables (static and dynamic)
    02373     for an entry that corresponds to the specified PC value.
    02374
    02375 Arguments:
    02376
    02377     ControlPc - Supplies the address of an instruction within the specified
    02378         function.
    02379
    02380 Return Value:
    02381
    02382     If there is no entry in the function table for the specified PC, then
    02383     NULL is returned. Otherwise, the address of the function table entry
    02384     that corresponds to the specified PC is returned.
    02385
    02386 --*/
    02387
    02388 {
    02389     PRUNTIME_FUNCTION FunctionEntry;
    02390     BOOLEAN InImage;
    02391
    02392     //
    02393     // look for function entry in static function tables
    02394     //
    02395
    02396     FunctionEntry = RtlLookupStaticFunctionEntry( ControlPc, &InImage );
    02397
    02398 #if !defined(NTOS_KERNEL_RUNTIME)
    02399     //
    02400     // If not in static image range and no static function entry
    02401     // found then look for a dynamic function entry
    02402     //
    02403
    02404     if (FunctionEntry == NULL && !InImage) {
    02405
    02406         FunctionEntry = RtlLookupDynamicFunctionEntry( ControlPc );
    02407
    02408     }
    02409 #endif
    02410
    02411 #if DBG
    02412     if (RtlDebugFlags & RTL_DBG_FUNCTION_ENTRY) {
    02413         DbgPrint("RtlLookupDirectFunctionEntry: returning FunctionEntry = %p\n", FunctionEntry);
    02414     }
    02415 #endif
    02416
    02417     return FunctionEntry;
    02418 }

PRUNTIME_FUNCTION RtlLookupDynamicFunctionEntry | ( | IN ULONG_PTR | ControlPc | ) |

Definition at line 3022 of file alpha/exdsptch.c.

References DynamicFunctionTable, LoaderLock, and NULL.

    03028                    :
    03029
    03030   This function searches through the dynamic function entry
    03031   tables and returns the function entry address that corresponds
    03032   to the specified ControlPc. This routine does NOT perform the
    03033   secondary function entry indirection. That is performed
    03034   by RtlLookupFunctionEntry().
    03035
    03036   Argument:
    03037
    03038      ControlPc           Supplies a ControlPc.
    03039
    03040   Return Value
    03041
    03042      NULL - No function entry found that contains the ControlPc.
    03043
    03044      NON-NULL - Address of the function entry that describes the
    03045                 code containing ControlPC.
    03046
    03047 --*/
    03048
    03049 {
    03050     PDYNAMIC_FUNCTION_TABLE CurrentEntry;
    03051     PLIST_ENTRY Next,Head;
    03052     PRUNTIME_FUNCTION FunctionTable;
    03053     PRUNTIME_FUNCTION FunctionEntry;
    03054     LONG High;
    03055     LONG Low;
    03056     LONG Middle;
    03057
    03058     if (DynamicFunctionTable.Flink == NULL)
    03059         return NULL;
    03060
    03061     if (RtlTryEnterCriticalSection((PRTL_CRITICAL_SECTION)NtCurrentPeb()->LoaderLock) ) {
    03062
    03063         //
    03064         //  Search the tree starting from the head, continue until the entry
    03065         //  is found or we reach the end of the list.
    03066         //
    03067
    03068         Head = &DynamicFunctionTable;
    03069         for (Next = Head->Blink; Next != Head; Next = Next->Blink) {
    03070             CurrentEntry = CONTAINING_RECORD(Next,DYNAMIC_FUNCTION_TABLE,Links);
    03071             FunctionTable = CurrentEntry->FunctionTable;
    03072
    03073             //
    03074             // Check if the ControlPC is within the range of this function table
    03075             //
    03076
    03077             if ((ControlPc >= CurrentEntry->MinimumAddress) &&
    03078                 (ControlPc <  CurrentEntry->MaximumAddress) ) {
    03079
    03080                 // If this function table is sorted do a binary search.
    03081
    03082                 if (CurrentEntry->Sorted) {
    03083
    03084                     //
    03085                     // Perform binary search on the function table for a function table
    03086                     // entry that subsumes the specified PC.
    03087                     //
    03088
    03089                     Low = 0;
    03090                     High = CurrentEntry->EntryCount -1 ;
    03091                     while (High >= Low) {
    03092
    03093                         //
    03094                         // Compute next probe index and test entry. If the specified PC
    03095                         // is greater than of equal to the beginning address and less
    03096                         // than the ending address of the function table entry, then
    03097                         // return the address of the function table entry. Otherwise,
    03098                         // continue the search.
    03099                         //
    03100
    03101                         Middle = (Low + High) >> 1;
    03102                         FunctionEntry = &FunctionTable[Middle];
    03103                         if (ControlPc < RF_BEGIN_ADDRESS(FunctionEntry)) {
    03104                             High = Middle - 1;
    03105
    03106                         } else if (ControlPc >= RF_END_ADDRESS(FunctionEntry)) {
    03107                             Low = Middle + 1;
    03108
    03109                         } else {
    03110 #if DBG
    03111                             ShowRuntimeFunction(FunctionEntry, "RtlLookupDynamicFunctionEntry: binary search" );
    03112 #endif
    03113                             RtlLeaveCriticalSection((PRTL_CRITICAL_SECTION)NtCurrentPeb()->LoaderLock);
    03114                             return FunctionEntry;
    03115                         }
    03116                     }
    03117
    03118                 } else {    // Not sorted. Do linear search.
    03119
    03120                     PRUNTIME_FUNCTION LastFunctionEntry = &FunctionTable[CurrentEntry->EntryCount];
    03121
    03122                     for (FunctionEntry = FunctionTable; FunctionEntry < LastFunctionEntry; FunctionEntry++) {
    03123                         if ((ControlPc >= RF_BEGIN_ADDRESS(FunctionEntry)) &&
    03124                             (ControlPc <  RF_END_ADDRESS(FunctionEntry))) {
    03125 #if DBG
    03126                             ShowRuntimeFunction(FunctionEntry, "RtlLookupDynamicFunctionEntry: linear search" );
    03127 #endif
    03128                             RtlLeaveCriticalSection((PRTL_CRITICAL_SECTION)NtCurrentPeb()->LoaderLock);
    03129                             return FunctionEntry;
    03130                         }
    03131                     }
    03132                 } // binary/linear search
    03133             } // if in range
    03134         } // for (... Next != Head ...)
    03135
    03136         RtlLeaveCriticalSection((PRTL_CRITICAL_SECTION)NtCurrentPeb()->LoaderLock);
    03137     } // LoaderLock
    03138
    03139
    03140     return NULL;
    03141 }
    #endif

PRUNTIME_FUNCTION RtlLookupFunctionEntry | ( | IN ULONG_PTR | ControlPc | ) |

Definition at line 507 of file alpha/exdsptch.c.

References DbgPrint, NULL, RtlLookupDirectFunctionEntry(), and RtlLookupFunctionEntry().

    00513                    :
    00514
    00515     This function searches the currently active function tables (static and dynamic)
    00516     for an entry that corresponds to the specified PC value. If the entry is for a
    00517     secondary function entry then the primary function table entry is obtained
    00518     via an indirection through the PrologEndAddress. RtlLookupDirectFunctionEntry()
    00519     performs the same function without the indirection to the primary function table.
    00520     Because RtlLookupFunctionEntry() always returns the primary function entry, it
    00521     has the property such that
    00522
    00523         RtlLookupFunctionEntry(Pc1) == RtlLookupFunctionEntry(Pc2)
    00524
    00525         implies
    00526
    00527         Pc1 and Pc2 are in the same procedure.
    00528
    00529 Arguments:
    00530
    00531     ControlPc - Supplies the address of an instruction within the specified
    00532         function.
    00533
    00534 Return Value:
    00535
    00536     If there is no entry in the function table for the specified PC, then
    00537     NULL is returned. Otherwise, the address of the primary function table
    00538     entry that corresponds to the specified PC is returned.
    00539
    00540 --*/
    00541
    00542 {
    00543     PRUNTIME_FUNCTION FunctionEntry;
    00544
    00545     // Look for a static or dynamic function entry
    00546
    00547     FunctionEntry = RtlLookupDirectFunctionEntry( ControlPc );
    00548
    00549     if (FunctionEntry != NULL) {
    00550
    00551         //
    00552         // The capability exists for more than one function entry
    00553         // to map to the same function. This permits a function to
    00554         // have discontiguous code segments described by separate
    00555         // function table entries. If the ending prologue address
    00556         // is not within the limits of the begining and ending
    00557         // address of the function able entry, then the prologue
    00558         // ending address is the address of the primary function
    00559         // table entry that accurately describes the ending prologue
    00560         // address.
    00561         //
    00562
    00563         if ((RF_PROLOG_END_ADDRESS(FunctionEntry) <  RF_BEGIN_ADDRESS(FunctionEntry)) ||
    00564             (RF_PROLOG_END_ADDRESS(FunctionEntry) >= RF_END_ADDRESS(FunctionEntry))) {
    00565 #if DBG
    00566             ShowRuntimeFunction(FunctionEntry, "RtlLookupFunctionEntry: secondary entry" );
    00567 #endif
    00568             // Officially the PrologEndAddress field in secondary function entries
    00569             // doesn't have the exception mode bits there have been some versions
    00570             // of alpha tools that put them there. Strip them off to be safe.
    00571
    00572             FunctionEntry = (PRUNTIME_FUNCTION)RF_PROLOG_END_ADDRESS(FunctionEntry);
    00573         } else if (RF_IS_FIXED_RETURN(FunctionEntry)) {
    00574             ULONG_PTR FixedReturn = RF_FIXED_RETURN(FunctionEntry);
    00575
    00576 #if DBG
    00577             ShowRuntimeFunction(FunctionEntry, "LookupFunctionEntry: fixed return entry");
    00578 #endif
    00579             // Recursively call LookupFunctionEntry to ensure we get a primary function entry here.
    00580             // Check for incorrectly formed function entry where the fixed return points to itself.
    00581
    00582             if ((FixedReturn <  RF_BEGIN_ADDRESS(FunctionEntry)) ||
    00583                 (FixedReturn >= RF_END_ADDRESS(FunctionEntry))) {
    00584                 FunctionEntry = RtlLookupFunctionEntry( RF_FIXED_RETURN(FunctionEntry) );
    00585             }
    00586         }
    00587 #if DBG
    00588         else {
    00589             ShowRuntimeFunction(FunctionEntry, "RtlLookupFunctionEntry: primary entry" );
    00590         }
    00591 #endif
    00592     }
    00593
    00594 #if DBG
    00595     if (RtlDebugFlags & RTL_DBG_FUNCTION_ENTRY) {
    00596         DbgPrint("RtlLookupFunctionEntry: returning FunctionEntry = %lx\n", FunctionEntry);
    00597     }
    00598 #endif
    00599     return FunctionEntry;
    00600 }

PRUNTIME_FUNCTION RtlLookupStaticFunctionEntry | ( | IN ULONG_PTR | ControlPc,
|  | OUT PBOOLEAN | InImage
| ) |

Definition at line 2421 of file alpha/exdsptch.c.

References DbgPrint, NULL, RtlImageDirectoryEntryToData(), RtlPcToFileHeader(), and TRUE.

    02428                    :
    02429
    02430     This function searches the currently active static function tables for an
    02431     entry that corresponds to the specified PC value.
    02432
    02433 Arguments:
    02434
    02435     ControlPc - Supplies the address of an instruction within the specified
    02436         function.
    02437
    02438     InImage - Address to recieve a flag indicating whether the ControlPc
    02439         was in the range of a static function table
    02440
    02441 Return Value:
    02442
    02443     If there is no entry in the static function tables for the specified PC,
    02444     then NULL is returned. Otherwise, the address of the function table entry
    02445     that corresponds to the specified PC is returned.
    02446
    02447 --*/
    02448
    02449 {
    02450     PRUNTIME_FUNCTION FunctionEntry;
    02451     PRUNTIME_FUNCTION FunctionTable;
    02452     ULONG SizeOfExceptionTable;
    02453     LONG High;
    02454     PVOID ImageBase;
    02455     LONG Low;
    02456     LONG Middle;
    02457
    02458     //
    02459     // Search for the image that includes the specified PC value.
    02460     //
    02461
    02462     ImageBase = RtlPcToFileHeader((PVOID)ControlPc, &ImageBase);
    02463
    02464 #if DBG
    02465     if (RtlDebugFlags & RTL_DBG_FUNCTION_ENTRY) {
    02466         DbgPrint("RtlLookupStaticFunctionEntry(ControlPc = %p) ImageBase = %p\n",
    02467                  ControlPc, ImageBase);
    02468     }
    02469 #endif
    02470
    02471     //
    02472     // If an image is found that includes the specified PC, then locate the
    02473     // function table for the image.
    02474     //
    02475
    02476     *InImage = (ImageBase != NULL);
    02477     FunctionEntry = NULL;
    02478     if (ImageBase != NULL) {
    02479         FunctionTable = (PRUNTIME_FUNCTION)RtlImageDirectoryEntryToData(
    02480                          ImageBase, TRUE, IMAGE_DIRECTORY_ENTRY_EXCEPTION,
    02481                          &SizeOfExceptionTable);
    02482 #if DBG
    02483         if (RtlDebugFlags & RTL_DBG_FUNCTION_ENTRY_DETAIL) {
    02484             DbgPrint("RtlLookupStaticFunctionEntry: FunctionTable = %p, SizeOfExceptionTable = %lx\n",
    02485                      FunctionTable, SizeOfExceptionTable);
    02486         }
    02487 #endif
    02488
    02489         //
    02490         // If a function table is located, then search the function table
    02491         // for a function table entry for the specified PC.
    02492         //
    02493
    02494         if (FunctionTable != NULL) {
    02495
    02496             //
    02497             // Initialize search indicies.
    02498             //
    02499
    02500             Low = 0;
    02501             High = (SizeOfExceptionTable / sizeof(RUNTIME_FUNCTION)) - 1;
    02502
    02503             //
    02504             // Perform binary search on the function table for a function table
    02505             // entry that subsumes the specified PC.
    02506             //
    02507
    02508             while (High >= Low) {
    02509
    02510                 //
    02511                 // Compute next probe index and test entry. If the specified PC
    02512                 // is greater than of equal to the beginning address and less
    02513                 // than the ending address of the function table entry, then
    02514                 // return the address of the function table entry. Otherwise,
    02515                 // continue the search.
    02516                 //
    02517
    02518                 Middle = (Low + High) >> 1;
    02519                 FunctionEntry = &FunctionTable[Middle];
    02520                 if (ControlPc < RF_BEGIN_ADDRESS(FunctionEntry)) {
    02521                     High = Middle - 1;
    02522
    02523                 } else if (ControlPc >= RF_END_ADDRESS(FunctionEntry)) {
    02524                     Low = Middle + 1;
    02525
    02526                 } else {
    02527                     return FunctionEntry;
    02528                 }
    02529             } // while (High >= Low)
    02530         } // FunctionTable != NULL
    02531     } // ImageBase != NULL
    02532     return NULL;
    02533 }

VOID RtlpRaiseException | ( | IN PEXCEPTION_RECORD | ExceptionRecord | ) |

Definition at line 643 of file alpha/exdsptch.c.

References NTSTATUS(), NULL, RtlLookupFunctionEntry(), RtlRaiseStatus(), RtlVirtualUnwind(), Status, and TRUE.

    00649                    :
    00650
    00651     This function raises a software exception by building a context record
    00652     and calling the raise exception system service.
    00653
    00654 Arguments:
    00655
    00656     ExceptionRecord - Supplies a pointer to an exception record.
    00657
    00658 Return Value:
    00659
    00660     None.
    00661
    00662 --*/
    00663
    00664 {
    00665
    00666     ULONG_PTR ControlPc;
    00667     CONTEXT ContextRecord;
    00668     FRAME_POINTERS EstablisherFrame;
    00669     PRUNTIME_FUNCTION FunctionEntry;
    00670     BOOLEAN InFunction;
    00671     ULONG_PTR NextPc;
    00672     NTSTATUS Status;
    00673
    00674     //
    00675     // Capture the current context, virtually unwind to the caller of this
    00676     // routine, set the fault instruction address to that of the caller, and
    00677     // call the raise exception system service.
    00678     //
    00679
    00680     RtlCaptureContext(&ContextRecord);
    00681     ControlPc = (ULONG_PTR)ContextRecord.IntRa - 4;
    00682     FunctionEntry = RtlLookupFunctionEntry(ControlPc);
    00683     NextPc = RtlVirtualUnwind(ControlPc,
    00684                               FunctionEntry,
    00685                               &ContextRecord,
    00686                               &InFunction,
    00687                               &EstablisherFrame,
    00688                               NULL);
    00689
    00690     ContextRecord.Fir = (ULONGLONG)(LONG_PTR)NextPc + 4;
    00691     ExceptionRecord->ExceptionAddress = (PVOID)ContextRecord.Fir;
    00692     Status = ZwRaiseException(ExceptionRecord, &ContextRecord, TRUE);
    00693
    00694     //
    00695     // There should never be a return from this system service unless
    00696     // there is a problem with the argument list itself. Raise another
    00697     // exception specifying the status value returned.
    00698     //
    00699
    00700     RtlRaiseStatus(Status);
    00701     return;
    00702 }

VOID RtlpRaiseStatus | ( | IN NTSTATUS | Status | ) |

Definition at line 745 of file alpha/exdsptch.c.

References EXCEPTION_NONCONTINUABLE, NULL, RtlLookupFunctionEntry(), RtlRaiseStatus(), RtlVirtualUnwind(), Status, and TRUE.

    00751                    :
    00752
    00753     This function raises an exception with the specified status value. The
    00754     exception is marked as noncontinuable with no parameters.
    00755
    00756 Arguments:
    00757
    00758     Status - Supplies the status value to be used as the exception code
    00759         for the exception that is to be raised.
    00760
    00761 Return Value:
    00762
    00763     None.
    00764
    00765 --*/
    00766
    00767 {
    00768
    00769     ULONG_PTR ControlPc;
    00770     CONTEXT ContextRecord;
    00771     FRAME_POINTERS EstablisherFrame;
    00772     EXCEPTION_RECORD ExceptionRecord;
    00773     PRUNTIME_FUNCTION FunctionEntry;
    00774     BOOLEAN InFunction;
    00775     ULONG_PTR NextPc;
    00776
    00777     //
    00778     // Construct an exception record.
    00779     //
    00780
    00781     ExceptionRecord.ExceptionCode = Status;
    00782     ExceptionRecord.ExceptionRecord = (PEXCEPTION_RECORD)NULL;
    00783     ExceptionRecord.NumberParameters = 0;
    00784     ExceptionRecord.ExceptionFlags = EXCEPTION_NONCONTINUABLE;
    00785
    00786     //
    00787     // Capture the current context, virtually unwind to the caller of this
    00788     // routine, set the fault instruction address to that of the caller, and
    00789     // call the raise exception system service.
    00790     //
    00791
    00792     RtlCaptureContext(&ContextRecord);
    00793     ControlPc = (ULONG_PTR)ContextRecord.IntRa - 4;
    00794     FunctionEntry = RtlLookupFunctionEntry(ControlPc);
    00795     NextPc = RtlVirtualUnwind(ControlPc,
    00796                               FunctionEntry,
    00797                               &ContextRecord,
    00798                               &InFunction,
    00799                               &EstablisherFrame,
    00800                               NULL);
    00801
    00802     ContextRecord.Fir = (ULONGLONG)(LONG_PTR)NextPc + 4;
    00803     ExceptionRecord.ExceptionAddress = (PVOID)ContextRecord.Fir;
    00804     Status = ZwRaiseException(&ExceptionRecord, &ContextRecord, TRUE);
    00805
    00806     //
    00807     // There should never be a return from this system service unless
    00808     // there is a problem with the argument list itself. Raise another
    00809     // exception specifying the status value returned.
    00810     //
    00811
    00812     RtlRaiseStatus(Status);
    00813     return;
    00814 }

ULONG_PTR RtlpVirtualUnwind | ( | IN ULONG_PTR | ControlPc,
|  | IN PRUNTIME_FUNCTION | FunctionEntry,
|  | IN PCONTEXT | ContextRecord,
|  | OUT PBOOLEAN | InFunction,
|  | OUT PFRAME_POINTERS | EstablisherFrame
| ) |

Definition at line 2284 of file alpha/exdsptch.c.

References NULL, and RtlVirtualUnwind().

    02294                    :
    02295
    02296     This function virtually unwinds the specfified function by executing its
    02297     prologue code backwards.
    02298
    02299     If the function is a leaf function, then the address where control left
    02300     the previous frame is obtained from the context record. If the function
    02301     is a nested function, but not an exception or interrupt frame, then the
    02302     prologue code is executed backwards and the address where control left
    02303     the previous frame is obtained from the updated context record.
    02304
    02305     Otherwise, an exception or interrupt entry to the system is being unwound
    02306     and a specially coded prologue restores the return address twice. Once
    02307     from the fault instruction address and once from the saved return address
    02308     register. The first restore is returned as the function value and the
    02309     second restore is place in the updated context record.
    02310
    02311     If a context pointers record is specified, then the address where each
    02312     nonvolatile registers is restored from is recorded in the appropriate
    02313     element of the context pointers record.
    02314
    02315     N.B. This function copies the specified context record and only computes
    02316          the establisher frame and whether control is actually in a function.
    02317
    02318 Arguments:
    02319
    02320     ControlPc - Supplies the address where control left the specified
    02321         function.
    02322
    02323     FunctionEntry - Supplies the address of the function table entry for the
    02324         specified function.
    02325
    02326     ContextRecord - Supplies the address of a context record.
    02327
    02328     InFunction - Supplies a pointer to a variable that receives whether the
    02329         control PC is within the current function.
    02330
    02331     EstablisherFrame - Supplies a pointer to a variable that receives the
    02332         the establisher frame pointer value.
    02333
    02334     ContextPointers - Supplies an optional pointer to a context pointers
    02335         record.
    02336
    02337 Return Value:
    02338
    02339     The address where control left the previous frame is returned as the
    02340     function value.
    02341
    02342 --*/
    02343
    02344 {
    02345
    02346     CONTEXT LocalContext;
    02347
    02348     //
    02349     // Copy the context record so updates will not be reflected in the
    02350     // original copy and then virtually unwind to the caller of the
    02351     // specified control point.
    02352     //
    02353
    02354     RtlMoveMemory((PVOID)&LocalContext, ContextRecord, sizeof(CONTEXT));
    02355     return RtlVirtualUnwind(ControlPc,
    02356                             FunctionEntry,
    02357                             &LocalContext,
    02358                             InFunction,
    02359                             EstablisherFrame,
    02360                             NULL);
    02361 }

VOID RtlRaiseException | ( | IN PEXCEPTION_RECORD | ExceptionRecord | ) |

Definition at line 603 of file alpha/exdsptch.c.

References DbgPrint, and RtlpRaiseException().

Referenced by RtlAcquireResourceExclusive(), RtlAcquireResourceShared(), RtlConvertSharedToExclusive(), and RtlpWaitForCriticalSection().

    00609                    :
    00610
    00611     This function raises a software exception by building a context record
    00612     and calling the raise exception system service.
    00613
    00614     N.B. This routine is a shell routine that simply calls another routine
    00615          to do the real work. The reason this is done is to avoid a problem
    00616          in try/finally scopes where the last statement in the scope is a
    00617          call to raise an exception.
    00618
    00619 Arguments:
    00620
    00621     ExceptionRecord - Supplies a pointer to an exception record.
    00622
    00623 Return Value:
    00624
    00625     None.
    00626
    00627 --*/
    00628
    00629 {
    00630
    00631 #if DBG
    00632     if (RtlDebugFlags & RTL_DBG_RAISE_EXCEPTION) {
    00633         DbgPrint("RtlRaiseException(ExceptionRecord = %p) Status = %lx\n",
    00634                  ExceptionRecord, ExceptionRecord->ExceptionCode);
    00635     }
    00636 #endif
    00637
    00638     RtlpRaiseException(ExceptionRecord);
    00639     return;
    00640 }

VOID RtlRaiseStatus | ( | IN NTSTATUS | Status | ) |

Definition at line 705 of file alpha/exdsptch.c.

References DbgPrint, RtlpRaiseStatus(), and Status.

    00711                    :
    00712
    00713     This function raises an exception with the specified status value. The
    00714     exception is marked as noncontinuable with no parameters.
    00715
    00716     N.B. This routine is a shell routine that simply calls another routine
    00717          to do the real work. The reason this is done is to avoid a problem
    00718          in try/finally scopes where the last statement in the scope is a
    00719          call to raise an exception.
    00720
    00721 Arguments:
    00722
    00723     Status - Supplies the status value to be used as the exception code
    00724         for the exception that is to be raised.
    00725
    00726 Return Value:
    00727
    00728     None.
    00729
    00730 --*/
    00731
    00732 {
    00733
    00734 #if DBG
    00735     if (RtlDebugFlags & RTL_DBG_RAISE_EXCEPTION) {
    00736         DbgPrint("RtlRaiseStatus(Status = %lx)\n", Status);
    00737     }
    00738 #endif
    00739
    00740     RtlpRaiseStatus(Status);
    00741     return;
    00742 }

VOID RtlUnwind | ( | IN PVOID TargetFrame | OPTIONAL,
|  | IN PVOID TargetIp | OPTIONAL,
|  | IN PEXCEPTION_RECORD ExceptionRecord | OPTIONAL,
|  | IN PVOID | ReturnValue
| ) |

Definition at line 817 of file alpha/exdsptch.c.

References RtlUnwind2().

    00826                    :
    00827
    00828     This function initiates an unwind of procedure call frames. The machine
    00829     state at the time of the call to unwind is captured in a context record
    00830     and the unwinding flag is set in the exception flags of the exception
    00831     record. If the TargetFrame parameter is not specified, then the exit unwind
    00832     flag is also set in the exception flags of the exception record. A backward
    00833     scan through the procedure call frames is then performed to find the target
    00834     of the unwind operation.
    00835
    00836     As each frame is encounter, the PC where control left the corresponding
    00837     function is determined and used to lookup exception handler information
    00838     in the runtime function table built by the linker. If the respective
    00839     routine has an exception handler, then the handler is called.
    00840
    00841     N.B. This routine is provided for backward compatibility with release 1.
    00842
    00843 Arguments:
    00844
    00845     TargetFrame - Supplies an optional pointer to the call frame that is the
    00846         target of the unwind. If this parameter is not specified, then an exit
    00847         unwind is performed.
    00848
    00849     TargetIp - Supplies an optional instruction address that specifies the
    00850         continuation address of the unwind. This address is ignored if the
    00851         target frame parameter is not specified.
    00852
    00853     ExceptionRecord - Supplies an optional pointer to an exception record.
    00854
    00855     ReturnValue - Supplies a value that is to be placed in the integer
    00856         function return register just before continuing execution.
    00857
    00858 Return Value:
    00859
    00860     None.
    00861
    00862 --*/
    00863
    00864 {
    00865     CONTEXT ContextRecord;
    00866
    00867
    00868     //
    00869     // Call real unwind routine specifying a context record as an
    00870     // extra argument.
    00871     //
    00872
    00873     RtlUnwind2(TargetFrame,
    00874                TargetIp,
    00875                ExceptionRecord,
    00876                ReturnValue,
    00877                &ContextRecord);
    00878
    00879     return;
    00880 }

VOID RtlUnwind2 | ( | IN PVOID TargetFrame | OPTIONAL,
|  | IN PVOID TargetIp | OPTIONAL,
|  | IN PEXCEPTION_RECORD ExceptionRecord | OPTIONAL,
|  | IN PVOID | ReturnValue,
|  | IN PCONTEXT | ContextRecord
| ) |

Definition at line 883 of file alpha/exdsptch.c.

References Count, DbgPrint, EXCEPTION_COLLIDED_UNWIND, EXCEPTION_EXIT_UNWIND, EXCEPTION_TARGET_UNWIND, EXCEPTION_UNWINDING, ExceptionCollidedUnwind, ExceptionContinueSearch, FALSE, IS_HANDLER_DEFINED, NULL, RAISE_EXCEPTION, RtlLookupFunctionEntry(), RtlpExecuteHandlerForUnwind(), RtlpGetStackLimits(), RtlpRestoreContext(), RtlpVirtualUnwind(), RtlRaiseStatus(), and RtlVirtualUnwind().

    00893                    :
    00894
    00895     This function initiates an unwind of procedure call frames. The machine
    00896     state at the time of the call to unwind is captured in a context record
    00897     and the unwinding flag is set in the exception flags of the exception
    00898     record. If the TargetFrame parameter is not specified, then the exit unwind
    00899     flag is also set in the exception flags of the exception record. A backward
    00900     scan through the procedure call frames is then performed to find the target
    00901     of the unwind operation.
    00902
    00903     As each frame is encounter, the PC where control left the corresponding
    00904     function is determined and used to lookup exception handler information
    00905     in the runtime function table built by the linker. If the respective
    00906     routine has an exception handler, then the handler is called.
    00907
    00908     N.B. This routine is provided for backward compatibility with release 1.
    00909
    00910 Arguments:
    00911
    00912     TargetFrame - Supplies an optional pointer to the call frame that is the
    00913         target of the unwind. If this parameter is not specified, then an exit
    00914         unwind is performed.
    00915
    00916     TargetIp - Supplies an optional instruction address that specifies the
    00917         continuation address of the unwind. This address is ignored if the
    00918         target frame parameter is not specified.
    00919
    00920     ExceptionRecord - Supplies an optional pointer to an exception record.
    00921
    00922     ReturnValue - Supplies a value that is to be placed in the integer
    00923         function return register just before continuing execution.
    00924
    00925 Return Value:
    00926
    00927     None.
    00928
    00929 --*/
    00930
    00931 {
    00932     ULONG_PTR ControlPc;
    00933 #if DBG
    00934     ULONG_PTR ControlPcHistory[PC_HISTORY_DEPTH];
    00935     ULONG ControlPcHistoryIndex = 0;
    00936 #endif
    00937     DISPATCHER_CONTEXT DispatcherContext;
    00938     EXCEPTION_DISPOSITION Disposition;
    00939     FRAME_POINTERS EstablisherFrame;
    00940     ULONG ExceptionFlags;
    00941     EXCEPTION_RECORD ExceptionRecord1;
    00942 #if DBG
    00943     LONG FrameDepth = 0;
    00944 #endif
    00945     PRUNTIME_FUNCTION FunctionEntry;
    00946     ULONG_PTR HighLimit;
    00947     BOOLEAN InFunction;
    00948     ULONG_PTR LowLimit;
    00949     ULONG_PTR NextPc;
    00950
    00951 #if DBG
    00952     if (RtlDebugFlags & RTL_DBG_UNWIND) {
    00953         DbgPrint("\nRtlUnwind(TargetFrame = %p, TargetIp = %p,, ReturnValue = %lx)\n",
    00954                  TargetFrame, TargetIp, ReturnValue);
    00955     }
    00956 #endif
    00957
    00958     //
    00959     // Get current stack limits, capture the current context, virtually
    00960     // unwind to the caller of this routine, get the initial PC value, and
    00961     // set the unwind target address.
    00962     //
    00963
    00964     RtlpGetStackLimits(&LowLimit, &HighLimit);
    00965     RtlCaptureContext(ContextRecord);
    00966     ControlPc = (ULONG_PTR)ContextRecord->IntRa - 4;
    00967     FunctionEntry = RtlLookupFunctionEntry(ControlPc);
    00968     NextPc = RtlVirtualUnwind(ControlPc,
    00969                               FunctionEntry,
    00970                               ContextRecord,
    00971                               &InFunction,
    00972                               &EstablisherFrame,
    00973                               NULL);
    00974
    00975     ControlPc = NextPc;
    00976     ContextRecord->Fir = (ULONGLONG)(LONG_PTR)TargetIp;
    00977
    00978     //
    00979     // If an exception record is not specified, then build a local exception
    00980     // record for use in calling exception handlers during the unwind operation.
    00981     //
    00982
    00983     if (ARGUMENT_PRESENT(ExceptionRecord) == FALSE) {
    00984         ExceptionRecord = &ExceptionRecord1;
    00985         ExceptionRecord1.ExceptionCode = STATUS_UNWIND;
    00986         ExceptionRecord1.ExceptionRecord = NULL;
    00987         ExceptionRecord1.ExceptionAddress = (PVOID)ControlPc;
    00988         ExceptionRecord1.NumberParameters = 0;
    00989     }
    00990
    00991     //
    00992     // If the target frame of the unwind is specified, then a normal unwind
    00993     // is being performed. Otherwise, an exit unwind is being performed.
    00994     //
    00995
    00996     ExceptionFlags = EXCEPTION_UNWINDING;
    00997     if (ARGUMENT_PRESENT(TargetFrame) == FALSE) {
    00998         ExceptionRecord->ExceptionFlags |= EXCEPTION_EXIT_UNWIND;
    00999     }
    01000
    01001     //
    01002     // Scan backward through the call frame hierarchy and call exception
    01003     // handlers until the target frame of the unwind is reached.
    01004     //
    01005
    01006     do {
    01007
    01008 #if DBG
    01009     if (RtlDebugFlags & RTL_DBG_UNWIND_DETAIL) {
    01010         DbgPrint("RtlUnwind: Loop: FrameDepth = %d, sp = %p, ControlPc = %p\n",
    01011                  FrameDepth, (ULONG_PTR)ContextRecord->IntSp, ControlPc);
    01012         FrameDepth -= 1;
    01013     }
    01014 #endif
    01015
    01016         //
    01017         // Lookup the function table entry using the point at which control
    01018         // left the procedure.
    01019         //
    01020
    01021         FunctionEntry = RtlLookupFunctionEntry(ControlPc);
    01022
    01023         //
    01024         // If there is a function table entry for the routine, then virtually
    01025         // unwind to the caller of the routine to obtain the virtual frame
    01026         // pointer of the establisher, but don't update the context record.
    01027         //
    01028
    01029         if (FunctionEntry != NULL) {
    01030             NextPc = RtlpVirtualUnwind(ControlPc,
    01031                                        FunctionEntry,
    01032                                        ContextRecord,
    01033                                        &InFunction,
    01034                                        &EstablisherFrame);
    01035
    01036             //
    01037             // If the virtual frame pointer is not within the specified stack
    01038             // limits, the virtual frame pointer is unaligned, or the target
    01039             // frame is below the virtual frame and an exit unwind is not being
    01040             // performed, then raise the exception STATUS_BAD_STACK. Otherwise,
    01041             // check to determine if the current routine has an exception
    01042             // handler.
    01043             //
    01044
    01045             if ((EstablisherFrame.Virtual < LowLimit) ||
    01046                 (EstablisherFrame.Virtual > HighLimit) ||
    01047                 ((ARGUMENT_PRESENT(TargetFrame) != FALSE) &&
    01048                  ((ULONG_PTR)TargetFrame < EstablisherFrame.Virtual)) ||
    01049                 ((EstablisherFrame.Virtual & 0xF) != 0)) {
    01050
    01051 #if DBG
    01052                 DbgPrint("\n****** Warning - bad stack or target frame (unwind).\n");
    01053                 DbgPrint("  EstablisherFrame Virtual = %p, Real = %p\n",
    01054                          EstablisherFrame.Virtual, EstablisherFrame.Real);
    01055                 DbgPrint("  TargetFrame = %p\n", TargetFrame);
    01056                 if ((ARGUMENT_PRESENT(TargetFrame) != FALSE) &&
    01057                     ((ULONG_PTR)TargetFrame < EstablisherFrame.Virtual)) {
    01058                     DbgPrint("  TargetFrame is below EstablisherFrame!\n");
    01059                 }
    01060                 DbgPrint("  Previous EstablisherFrame (sp) = %p\n",
    01061                          (ULONG_PTR)ContextRecord->IntSp);
    01062                 DbgPrint("  LowLimit = %p, HighLimit = %p\n",
    01063                          LowLimit, HighLimit);
    01064                 DbgPrint("  NextPc = %p, ControlPc = %p\n",
    01065                          NextPc, ControlPc);
    01066                 DbgPrint("  Now raising STATUS_BAD_STACK exception.\n");
    01067 #endif
    01068
    01069                 RAISE_EXCEPTION(STATUS_BAD_STACK, ExceptionRecord);
    01070
    01071             } else if (IS_HANDLER_DEFINED(FunctionEntry) && InFunction) {
    01072
    01073 #if DBG
    01074     if (RtlDebugFlags & RTL_DBG_DISPATCH_EXCEPTION_DETAIL) {
    01075     DbgPrint("RtlUnwind: ExceptionHandler = %p, HandlerData = %p\n",
    01076              FunctionEntry->ExceptionHandler, FunctionEntry->HandlerData);
    01077 }
    01078 #endif
    01079
    01080                 //
    01081                 // The frame has an exception handler.
    01082                 //
    01083                 // The control PC, establisher frame pointer, the address
    01084                 // of the function table entry, and the address of the
    01085                 // context record are all stored in the dispatcher context.
    01086                 // This information is used by the unwind linkage routine
    01087                 // and can be used by the exception handler itself.
    01088                 //
    01089                 // A linkage routine written in assembler is used to actually
    01090                 // call the actual exception handler. This is required by the
    01091                 // exception handler that is associated with the linkage
    01092                 // routine so it can have access to two sets of dispatcher
    01093                 // context when it is called.
    01094                 //
    01095
    01096                 DispatcherContext.ControlPc = ControlPc;
    01097                 DispatcherContext.FunctionEntry = FunctionEntry;
    01098                 DispatcherContext.EstablisherFrame = EstablisherFrame.Virtual;
    01099                 DispatcherContext.ContextRecord = ContextRecord;
    01100
    01101                 //
    01102                 // Call the exception handler.
    01103                 //
    01104
    01105                 do {
    01106
    01107                     //
    01108                     // If the establisher frame is the target of the unwind
    01109                     // operation, then set the target unwind flag.
    01110                     //
    01111
    01112                     if ((ULONG_PTR)TargetFrame == EstablisherFrame.Virtual) {
    01113                         ExceptionFlags |= EXCEPTION_TARGET_UNWIND;
    01114                     }
    01115
    01116                     ExceptionRecord->ExceptionFlags = ExceptionFlags;
    01117
    01118                     //
    01119                     // Set the specified return value in case the exception
    01120                     // handler directly continues execution.
    01121                     //
    01122
    01123                     ContextRecord->IntV0 = (ULONGLONG)(LONG_PTR)ReturnValue;
    01124 #if DBG
    01125     if (RtlDebugFlags & RTL_DBG_UNWIND_DETAIL) {
    01126         DbgPrint("RtlUnwind: calling RtlpExecuteHandlerForUnwind, ControlPc = %p\n", ControlPc);
    01127     }
    01128 #endif
    01129                     Disposition =
    01130                         RtlpExecuteHandlerForUnwind(ExceptionRecord,
    01131                                                     EstablisherFrame.Virtual,
    01132                                                     ContextRecord,
    01133                                                     &DispatcherContext,
    01134                                                     RF_EXCEPTION_HANDLER(FunctionEntry));
    01135 #if DBG
    01136     if (RtlDebugFlags & RTL_DBG_UNWIND_DETAIL) {
    01137         DbgPrint("RtlUnwind: RtlpExecuteHandlerForUnwind returned Disposition = %lx\n", Disposition);
    01138     }
    01139 #endif
    01140
    01141                     //
    01142                     // Clear target unwind and collided unwind flags.
    01143                     //
    01144
    01145                     ExceptionFlags &= ~(EXCEPTION_COLLIDED_UNWIND |
    01146                                         EXCEPTION_TARGET_UNWIND);
    01147
    01148                     //
    01149                     // Case on the handler disposition.
    01150                     //
    01151
    01152                     switch (Disposition) {
    01153
    01154                         //
    01155                         // The disposition is to continue the search.
    01156                         //
    01157                         // If the target frame has not been reached, then
    01158                         // virtually unwind to the caller of the current
    01159                         // routine, update the context record, and continue
    01160                         // the search for a handler.
    01161                         //
    01162
    01163                     case ExceptionContinueSearch :
    01164                         if (EstablisherFrame.Virtual != (ULONG_PTR)TargetFrame) {
    01165                             NextPc = RtlVirtualUnwind(ControlPc,
    01166                                                       FunctionEntry,
    01167                                                       ContextRecord,
    01168                                                       &InFunction,
    01169                                                       &EstablisherFrame,
    01170                                                       NULL);
    01171                         }
    01172
    01173                         break;
    01174
    01175                         //
    01176                         // The disposition is collided unwind.
    01177                         //
    01178                         // Set the target of the current unwind to the context
    01179                         // record of the previous unwind, and reexecute the
    01180                         // exception handler from the collided frame with the
    01181                         // collided unwind flag set in the exception record.
    01182                         //
    01183
    01184                     case ExceptionCollidedUnwind :
    01185                         ControlPc = DispatcherContext.ControlPc;
    01186                         FunctionEntry = DispatcherContext.FunctionEntry;
    01187                         ContextRecord = DispatcherContext.ContextRecord;
    01188                         ContextRecord->Fir = (ULONGLONG)(LONG_PTR)TargetIp;
    01189                         ExceptionFlags |= EXCEPTION_COLLIDED_UNWIND;
    01190                         EstablisherFrame.Virtual = DispatcherContext.EstablisherFrame;
    01191                         break;
    01192
    01193                         //
    01194                         // All other disposition values are invalid.
    01195                         //
    01196                         // Raise invalid disposition exception.
    01197                         //
    01198
    01199                     default :
    01200                         RAISE_EXCEPTION(STATUS_INVALID_DISPOSITION, ExceptionRecord);
    01201                     }
    01202
    01203                 } while ((ExceptionFlags & EXCEPTION_COLLIDED_UNWIND) != 0);
    01204             } else {
    01205
    01206                 //
    01207                 // Virtually unwind to the caller of the current routine and
    01208                 // update the context record.
    01209                 //
    01210
    01211                 if (EstablisherFrame.Virtual != (ULONG_PTR)TargetFrame) {
    01212                     NextPc = RtlVirtualUnwind(ControlPc,
    01213                                               FunctionEntry,
    01214                                               ContextRecord,
    01215                                               &InFunction,
    01216                                               &EstablisherFrame,
    01217                                               NULL);
    01218                 }
    01219             }
    01220
    01221         } else {
    01222
    01223             //
    01224             // Set point at which control left the previous routine.
    01225             //
    01226
    01227             NextPc = (ULONG_PTR)ContextRecord->IntRa - 4;
    01228
    01229             //
    01230             // If the next control PC is the same as the old control PC, then
    01231             // the function table is not correctly formed.
    01232             //
    01233
    01234             if (NextPc == ControlPc) {
    01235 #if DBG
    01236                 ULONG Count;
    01237                 DbgPrint("\n****** Warning - malformed function table (unwind).\n");
    01238                 DbgPrint("ControlPc = %p, %p", NextPc, ControlPc);
    01239                 for (Count = 0; Count < PC_HISTORY_DEPTH; Count += 1) {
    01240                     if (ControlPcHistoryIndex > 0) {
    01241                         ControlPcHistoryIndex -= 1;
    01242                         ControlPc = ControlPcHistory[ControlPcHistoryIndex % PC_HISTORY_DEPTH];
    01243                         DbgPrint(", %p", ControlPc);
    01244                     }
    01245                 }
    01246                 DbgPrint(ControlPcHistoryIndex == 0 ? ".\n" : ", ...\n");
    01247                 DbgPrint("  Now raising STATUS_BAD_FUNCTION_TABLE exception.\n");
    01248 #endif
    01249                 RtlRaiseStatus(STATUS_BAD_FUNCTION_TABLE);
    01250             }
    01251         }
    01252
    01253         //
    01254         // Set point at which control left the previous routine.
    01255         //
    01256
    01257 #if DBG
    01258         ControlPcHistory[ControlPcHistoryIndex % PC_HISTORY_DEPTH] = ControlPc;
    01259         ControlPcHistoryIndex += 1;
    01260 #endif
    01261         ControlPc = NextPc;
    01262
    01263     } while ((EstablisherFrame.Virtual < HighLimit) &&
    01264              (EstablisherFrame.Virtual != (ULONG_PTR)TargetFrame));
    01265
    01266     //
    01267     // If the establisher stack pointer is equal to the target frame
    01268     // pointer, then continue execution. Otherwise, an exit unwind was
    01269     // performed or the target of the unwind did not exist and the
    01270     // debugger and subsystem are given a second chance to handle the
    01271     // unwind.
    01272     //
    01273
    01274     if (EstablisherFrame.Virtual == (ULONG_PTR)TargetFrame) {
    01275         ContextRecord->IntV0 = (ULONGLONG)(LONG_PTR)ReturnValue;
    01276
    01277 #if DBG
    01278     if (RtlDebugFlags & RTL_DBG_UNWIND) {
    01279         DbgPrint("RtlUnwind: finished unwinding, and calling RtlpRestoreContext(%lx)\n",ContextRecord);
    01280     }
    01281 #endif
    01282
    01283         RtlpRestoreContext(ContextRecord);
    01284
    01285     } else {
    01286
    01287 #if DBG
    01288     if (RtlDebugFlags & RTL_DBG_UNWIND) {
    01289         DbgPrint("RtlUnwind: finished unwinding, but calling ZwRaiseException\n");
    01290     }
    01291 #endif
    01292
    01293         ZwRaiseException(ExceptionRecord, ContextRecord, FALSE);
    01294     }
    01295
    01296 }

ULONG_PTR RtlVirtualUnwind | ( | IN ULONG_PTR | ControlPc,
|  | IN PRUNTIME_FUNCTION | FunctionEntry,
|  | IN OUT PCONTEXT | ContextRecord,
|  | OUT PBOOLEAN | InFunction,
|  | OUT PFRAME_POINTERS | EstablisherFrame,
|  | IN OUT PKNONVOLATILE_CONTEXT_POINTERS ContextPointers | OPTIONAL
| ) |

Definition at line 1455 of file alpha/exdsptch.c.

References _RtlpDebugDisassemble, _RtlpFoundTrapFrame, _RtlpVirtualUnwindExit, DbgPrint, FALSE, LDA_OP, RtlGetUnwindFunctionEntry(), and TRUE.

    01466                    :
    01467
    01468     This function virtually unwinds the specified function by executing its
    01469     prologue code backwards. Given the current context and the instructions
    01470     that preserve registers in the prologue, it is possible to recreate the
    01471     nonvolatile context at the point the function was called.
    01472
    01473     If the function is a leaf function, then the address where control left
    01474     the previous frame is obtained from the context record. If the function
    01475     is a nested function, but not an exception or interrupt frame, then the
    01476     prologue code is executed backwards and the address where control left
    01477     the previous frame is obtained from the updated context record.
    01478
    01479     Otherwise, an exception or interrupt entry to the system is being unwound
    01480     and a specially coded prologue restores the return address twice. Once
    01481     from the fault instruction address and once from the saved return address
    01482     register. The first restore is returned as the function value and the
    01483     second restore is placed in the updated context record.
    01484
    01485     During the unwind, the virtual and real frame pointers for the function
    01486     are calculated and returned in the given frame pointers structure.
    01487
    01488     If a context pointers record is specified, then the address where each
    01489     register is restored from is recorded in the appropriate element of the
    01490     context pointers record.
    01491
    01492 Arguments:
    01493
    01494     ControlPc - Supplies the address where control left the specified
    01495         function.
    01496
    01497     FunctionEntry - Supplies the address of the function table entry for the
    01498         specified function.
    01499
    01500     ContextRecord - Supplies the address of a context record.
    01501
    01502     InFunction - Supplies a pointer to a variable that receives whether the
    01503         control PC is within the current function.
    01504
    01505     EstablisherFrame - Supplies a pointer to a frame pointers structure
    01506         that will receive the values for the virtual frame pointer and the
    01507         real frame pointer. The value of the real frame pointer is reliable
    01508         only when InFunction is TRUE.
    01509
    01510     ContextPointers - Supplies an optional pointer to a context pointers
    01511         record.
    01512
    01513 Return Value:
    01514
    01515     The address where control left the previous frame is returned as the
    01516     function value.
    01517
    01518 Implementation Notes:
    01519
    01520     N.B. "where control left" is not the "return address" of the call in the
    01521     previous frame. For normal frames, NextPc points to the last instruction
    01522     that completed in the previous frame (the JSR/BSR). The difference between
    01523     NextPc and NextPc + 4 (return address) is important for correct behavior
    01524     in boundary cases of exception addresses and scope tables.
    01525
    01526     For exception and interrupt frames, NextPc is obtained from the trap frame
    01527     contination address (Fir). For faults and synchronous traps, NextPc is both
    01528     the last instruction to execute in the previous frame and the next
    01529     instruction to execute if the function were to return. For asynchronous
    01530     traps, NextPc is the continuation address. It is the responsibility of the
    01531     compiler to insert TRAPB instructions to insure asynchronous traps do not
    01532     occur outside the scope from the instruction(s) that caused them.
    01533
    01534     N.B. in this and other files where RtlVirtualUnwind is used, the variable
    01535     named NextPc is perhaps more accurately, LastPc - the last PC value in
    01536     the previous frame, or CallPc - the address of the call instruction, or
    01537     ControlPc - the address where control left the previous frame. Instead
    01538     think of NextPc as the next PC to use in another call to virtual unwind.
    01539
    01540     The Alpha version of virtual unwind is similar in design, but slightly
    01541     more complex than the Mips version. This is because Alpha compilers
    01542     are given more flexibility to optimize generated code and instruction
    01543     sequences, including within procedure prologues. In addition, because of
    01544     the current inability of the GEM compiler to materialize virtual frame
    01545     pointers, this function must manage both virtual and real frame pointers.
    01546
    01547 --*/
    01548
    01549 {
    01550
    01551     ULONG_PTR Address;
    01552     ULONG DecrementOffset;
    01553     ULONG DecrementRegister;
    01554     ALPHA_INSTRUCTION FollowingInstruction;
    01555     PULONGLONG FloatingRegister;
    01556     ULONG_PTR FrameSize;
    01557     ULONG Function;
    01558     ALPHA_INSTRUCTION Instruction;
    01559     PULONGLONG IntegerRegister;
    01560     ULONG Literal8;
    01561     ULONG_PTR NextPc;
    01562     LONG Offset16;
    01563     ULONG Opcode;
    01564     ULONG Ra;
    01565     ULONG Rb;
    01566     ULONG Rc;
    01567     BOOLEAN RestoredRa;
    01568     BOOLEAN RestoredSp;
    01569     RUNTIME_FUNCTION UnwindFunctionEntry;
    01570     ULONG StackAdjust;
    01571     ULONG_PTR FixedReturn;
    01572
    01573 #if DBG
    01574     if (RtlDebugFlags & RTL_DBG_VIRTUAL_UNWIND) {
    01575         DbgPrint("\nRtlVirtualUnwind(ControlPc = %p, FunctionEntry = %p,) sp = %p\n",
    01576                  ControlPc, FunctionEntry, (ULONG_PTR)ContextRecord->IntSp);
    01577     }
    01578 #endif
    01579
    01580     // Construct a function entry suitable for unwinding from ControlPc
    01581
    01582     RtlGetUnwindFunctionEntry( ControlPc, FunctionEntry, &UnwindFunctionEntry, &StackAdjust, &FixedReturn );
    01583
    01584 #if DBG
    01585     ShowRuntimeFunction(&UnwindFunctionEntry, "RtlVirtualUnwind: unwind function entry" );
    01586 #endif
    01587     //
    01588     // Set the base address of the integer and floating register arrays within
    01589     // the context record. Each set of 32 registers is known to be contiguous.
    01590     //
    01591
    01592     IntegerRegister = &ContextRecord->IntV0;
    01593     FloatingRegister = &ContextRecord->FltF0;
    01594
    01595     //
    01596     // Handle the epilogue case where the next instruction is a return.
    01597     //
    01598     // Exception handlers cannot be called if the ControlPc is within the
    01599     // epilogue because exception handlers expect to operate with a current
    01600     // stack frame. The value of SP is not current within the epilogue.
    01601     //
    01602
    01603     Instruction.Long = *((PULONG)ControlPc);
    01604     if (IS_RETURN_0001_INSTRUCTION(Instruction.Long)) {
    01605         Rb = Instruction.Jump.Rb;
    01606         NextPc = (ULONG_PTR)IntegerRegister[Rb] - 4;
    01607
    01608         //
    01609         // The instruction at the point where control left the specified
    01610         // function is a return, so any saved registers have already been
    01611         // restored, and the stack pointer has already been adjusted. The
    01612         // stack does not need to be unwound in this case and the saved
    01613         // return address register is returned as the function value.
    01614         //
    01615         // In fact, reverse execution of the prologue is not possible in
    01616         // this case: the stack pointer has already been incremented and
    01617         // so, for this frame, neither a valid stack pointer nor frame
    01618         // pointer exists from which to begin reverse execution of the
    01619         // prologue. In addition, the integrity of any data on the stack
    01620         // below the stack pointer is never guaranteed (due to interrupts
    01621         // and exceptions).
    01622         //
    01623         // The epilogue instruction sequence is:
    01624         //
    01625         // ==>  ret   zero, (Ra), 1     // return
    01626         // or
    01627         //
    01628         //      mov   ra, Rx            // save return address
    01629         //      ...
    01630         // ==>  ret   zero, (Rx), 1     // return
    01631         //
    01632
    01633         EstablisherFrame->Real = 0;
    01634         EstablisherFrame->Virtual = (ULONG_PTR)ContextRecord->IntSp;
    01635         *InFunction = FALSE;
    01636         _RtlpDebugDisassemble(ControlPc, ContextRecord);
    01637         _RtlpVirtualUnwindExit(NextPc, ContextRecord, EstablisherFrame);
    01638         return NextPc;
    01639     }
    01640
    01641     //
    01642     // Handle the epilogue case where the next two instructions are a stack
    01643     // frame deallocation and a return.
    01644     //
    01645
    01646     FollowingInstruction.Long = *((PULONG)(ControlPc + 4));
    01647     if (IS_RETURN_0001_INSTRUCTION(FollowingInstruction.Long)) {
    01648         Rb = FollowingInstruction.Jump.Rb;
    01649         NextPc = (ULONG_PTR)IntegerRegister[Rb] - 4;
    01650
    01651         //
    01652         // The second instruction following the point where control
    01653         // left the specified function is a return. If the instruction
    01654         // before the return is a stack increment instruction, then all
    01655         // saved registers have already been restored except for SP.
    01656         // The value of the stack pointer register cannot be recovered
    01657         // through reverse execution of the prologue because in order
    01658         // to begin reverse execution either the stack pointer or the
    01659         // frame pointer (if any) must still be valid.
    01660         //
    01661         // Instead, the effect that the stack increment instruction
    01662         // would have had on the context is manually applied to the
    01663         // current context. This is forward execution of the epilogue
    01664         // rather than reverse execution of the prologue.
    01665         //
    01666         // In an epilogue, as in a prologue, the stack pointer is always
    01667         // adjusted with a single instruction: either an immediate-value
    01668         // (lda) or a register-value (addq) add instruction.
    01669         //
    01670
    01671         Function = Instruction.OpReg.Function;
    01672         Offset16 = Instruction.Memory.MemDisp;
    01673         Opcode = Instruction.OpReg.Opcode;
    01674         Ra = Instruction.OpReg.Ra;
    01675         Rb = Instruction.OpReg.Rb;
    01676         Rc = Instruction.OpReg.Rc;
    01677
    01678         if ((Opcode == LDA_OP) && (Ra == SP_REG)) {
    01679
    01680             //
    01681             // Load Address instruction.
    01682             //
    01683             // Since the destination (Ra) register is SP, an immediate-
    01684             // value stack deallocation operation is being performed. The
    01685             // displacement value should be added to SP. The displacement
    01686             // value is assumed to be positive. The amount of stack
    01687             // deallocation possible using this instruction ranges from
    01688             // 16 to 32752 (32768 - 16) bytes. The base register (Rb) is
    01689             // usually SP, but may be another register.
    01690             //
    01691             // The epilogue instruction sequence is:
    01692             //
    01693             // ==>  lda   sp, +N(sp)        // deallocate stack frame
    01694             //      ret   zero, (ra)        // return
    01695             // or
    01696             //
    01697             // ==>  lda   sp, +N(Rx)        // restore SP and deallocate frame
    01698             //      ret   zero, (ra)        // return
    01699             //
    01700
    01701             ContextRecord->IntSp = Offset16 + IntegerRegister[Rb];
    01702             EstablisherFrame->Real = 0;
    01703             EstablisherFrame->Virtual = (ULONG_PTR)ContextRecord->IntSp;
    01704             *InFunction = FALSE;
    01705             _RtlpDebugDisassemble(ControlPc, ContextRecord);
    01706             _RtlpDebugDisassemble(ControlPc + 4, ContextRecord);
    01707             _RtlpVirtualUnwindExit(NextPc, ContextRecord, EstablisherFrame);
    01708             return NextPc;
    01709
    01710         } else if ((Opcode == ARITH_OP) && (Function == ADDQ_FUNC) &&
    01711                    (Rc == SP_REG) &&
    01712                    (Instruction.OpReg.RbvType == RBV_REGISTER_FORMAT)) {
    01713
    01714             //
    01715             // Add Quadword instruction.
    01716             //
    01717             // Since both source operands are registers, and the
    01718             // destination register is SP, a register-value stack
    01719             // deallocation is being performed. The value of the two
    01720             // source registers should be added and this is the new
    01721             // value of SP. One of the source registers is usually SP,
    01722             // but may be another register.
    01723             //
    01724             // The epilogue instruction sequence is:
    01725             //
    01726             //      ldiq  Rx, N             // set [large] frame size
    01727             //      ...
    01728             // ==>  addq  sp, Rx, sp        // deallocate stack frame
    01729             //      ret   zero, (ra)        // return
    01730             // or
    01731             //
    01732             // ==>  addq  Rx, Ry, sp        // restore SP and deallocate frame
    01733             //      ret   zero, (ra)        // return
    01734             //
    01735
    01736             ContextRecord->IntSp = IntegerRegister[Ra] + IntegerRegister[Rb];
    01737             EstablisherFrame->Real = 0;
    01738             EstablisherFrame->Virtual = (ULONG_PTR)ContextRecord->IntSp;
    01739             *InFunction = FALSE;
    01740             _RtlpDebugDisassemble(ControlPc, ContextRecord);
    01741             _RtlpDebugDisassemble(ControlPc + 4, ContextRecord);
    01742             _RtlpVirtualUnwindExit(NextPc, ContextRecord, EstablisherFrame);
    01743             return NextPc;
    01744         }
    01745     }
    01746
    01747     //
    01748     // By default set the frame pointers to the current value of SP.
    01749     //
    01750     // When a procedure is called, the value of SP before the stack
    01751     // allocation instruction is the virtual frame pointer. When reverse
    01752     // executing instructions in the prologue, the value of SP before the
    01753     // stack allocation instruction is encountered is the real frame
    01754     // pointer. This is the current value of SP unless the procedure uses
    01755     // a frame pointer (e.g., FP_REG).
    01756     //
    01757
    01758     EstablisherFrame->Real = (ULONG_PTR)ContextRecord->IntSp;
    01759     EstablisherFrame->Virtual = (ULONG_PTR)ContextRecord->IntSp;
    01760
    01761     //
    01762     // If the address where control left the specified function is beyond
    01763     // the end of the prologue, then the control PC is considered to be
    01764     // within the function and the control address is set to the end of
    01765     // the prologue. Otherwise, the control PC is not considered to be
    01766     // within the function (i.e., the prologue).
    01767     //
    01768     // N.B. PrologEndAddress is equal to BeginAddress for a leaf function.
    01769     //
    01770     // The low-order two bits of PrologEndAddress are reserved for the IEEE
    01771     // exception mode and so must be masked out.
    01772     //
    01773
    01774     if ((ControlPc < UnwindFunctionEntry.BeginAddress) ||
    01775         (ControlPc >= UnwindFunctionEntry.PrologEndAddress)) {
    01776         *InFunction = TRUE;
    01777         ControlPc = (UnwindFunctionEntry.PrologEndAddress & (~(UINT_PTR)0x3));
    01778
    01779     } else {
    01780         *InFunction = FALSE;
    01781     }
    01782
    01783     //
    01784     // Scan backward through the prologue to reload callee saved registers
    01785     // that were stored or copied and to increment the stack pointer if it
    01786     // was decremented.
    01787     //
    01788
    01789     DecrementRegister = ZERO_REG;
    01790     NextPc = (ULONG_PTR)ContextRecord->IntRa - 4;
    01791     RestoredRa = FALSE;
    01792     RestoredSp = FALSE;
    01793     while (ControlPc > UnwindFunctionEntry.BeginAddress) {
    01794
    01795         //
    01796         // Get instruction value, decode fields, case on opcode value, and
    01797         // reverse register store and stack decrement operations.
    01798         // N.B. The location of Opcode, Ra, Rb, and Rc is the same across
    01799         // all opcode formats. The same is not true for Function.
    01800         //
    01801
    01802         ControlPc -= 4;
    01803         Instruction.Long = *((PULONG)ControlPc);
    01804         Function = Instruction.OpReg.Function;
    01805         Literal8 = Instruction.OpLit.Literal;
    01806         Offset16 = Instruction.Memory.MemDisp;
    01807         Opcode = Instruction.OpReg.Opcode;
    01808         Ra = Instruction.OpReg.Ra;
    01809         Rb = Instruction.OpReg.Rb;
    01810         Rc = Instruction.OpReg.Rc;
    01811
    01812         //
    01813         // Compare against each instruction type that will affect the context
    01814         // and that is allowed in a prologue. Any other instructions found
    01815         // in the prologue will be ignored since they are assumed to have no
    01816         // effect on the context.
    01817         //
    01818
    01819         switch (Opcode) {
    01820
    01821         case STQ_OP :
    01822
    01823             //
    01824             // Store Quad instruction.
    01825             //
    01826             // If the base register is SP, then reload the source register
    01827             // value from the value stored on the stack.
    01828             //
    01829             // The prologue instruction sequence is:
    01830             //
    01831             // ==>  stq   Rx, N(sp)         // save integer register Rx
    01832             //
    01833
    01834             if ((Rb == SP_REG) && (Ra != ZERO_REG)) {
    01835
    01836                 //
    01837                 // Reload the register by retrieving the value previously
    01838                 // stored on the stack.
    01839                 //
    01840
    01841                 Address = Offset16 + (LONG_PTR)ContextRecord->IntSp;
    01842                 IntegerRegister[Ra] = *((PULONGLONG)Address);
    01843
    01844                 //
    01845                 // If the destination register is RA and this is the first
    01846                 // time that RA is being restored, then set the address of
    01847                 // where control left the previous frame. Otherwise, if this
    01848                 // is the second time RA is being restored, then the first
    01849                 // one was an interrupt or exception address and the return
    01850                 // PC should not have been biased by 4.
    01851                 //
    01852
    01853                 if (Ra == RA_REG) {
    01854                     if (RestoredRa == FALSE) {
    01855                         NextPc = (ULONG_PTR)ContextRecord->IntRa - 4;
    01856                         RestoredRa = TRUE;
    01857
    01858                     } else {
    01859                         NextPc += 4;
    01860                         _RtlpFoundTrapFrame(NextPc);
    01861                     }
    01862
    01863                 //
    01864                 // Otherwise, if the destination register is SP and this is
    01865                 // the first time that SP is being restored, then set the
    01866                 // establisher frame pointers.
    01867                 //
    01868
    01869                 } else if ((Ra == SP_REG) && (RestoredSp == FALSE)) {
    01870                     EstablisherFrame->Virtual = (ULONG_PTR)ContextRecord->IntSp;
    01871                     EstablisherFrame->Real = (ULONG_PTR)ContextRecord->IntSp;
    01872                     RestoredSp = TRUE;
    01873                 }
    01874
    01875                 //
    01876                 // If a context pointer record is specified, then record
    01877                 // the address where the destination register contents
    01878                 // are stored.
    01879                 //
    01880
    01881                 if (ARGUMENT_PRESENT(ContextPointers)) {
    01882                     ContextPointers->IntegerContext[Ra] = (PULONGLONG)Address;
    01883                 }
    01884                 _RtlpDebugDisassemble(ControlPc, ContextRecord);
    01885             }
    01886             break;
    01887
    01888         case LDAH_OP :
    01889             Offset16 <<= 16;
    01890
    01891         case LDA_OP :
    01892
    01893             //
    01894             // Load Address High, Load Address instruction.
    01895             //
    01896             // There are several cases where the lda and/or ldah instructions
    01897             // are used: one to decrement the stack pointer directly, and the
    01898             // others to load immediate values into another register and that
    01899             // register is then used to decrement the stack pointer.
    01900             //
    01901             // In the examples below, as a single instructions or as a pair,
    01902             // a lda may be substituted for a ldah and visa-versa.
    01903             //
    01904
    01905             if (Ra == SP_REG) {
    01906                 if (Rb == SP_REG) {
    01907
    01908                     //
    01909                     // If both the destination (Ra) and base (Rb) registers
    01910                     // are SP, then a standard stack allocation was performed
    01911                     // and the negated displacement value is the stack frame
    01912                     // size. The amount of stack allocation possible using
    01913                     // the lda instruction ranges from 16 to 32768 bytes and
    01914                     // the amount of stack allocation possible using the ldah
    01915                     // instruction ranges from 65536 to 2GB in multiples of
    01916                     // 65536 bytes. It is rare for the ldah instruction to be
    01917                     // used in this manner.
    01918                     //
    01919                     // The prologue instruction sequence is:
    01920                     //
    01921                     // ==>  lda   sp, -N(sp)    // allocate stack frame
    01922                     //
    01923
    01924                     FrameSize = -Offset16;
    01925                     goto StackAllocation;
    01926
    01927                 } else {
    01928
    01929                     //
    01930                     // The destination register is SP and the base register
    01931                     // is not SP, so this instruction must be the second
    01932                     // half of an instruction pair to allocate a large size
    01933                     // (>32768 bytes) stack frame. Save the displacement value
    01934                     // as the partial decrement value and postpone adjusting
    01935                     // the value of SP until the first instruction of the pair
    01936                     // is encountered.
    01937                     //
    01938                     // The prologue instruction sequence is:
    01939                     //
    01940                     //      ldah  Rx, -N(sp)    // prepare new SP (upper)
    01941                     // ==>  lda   sp, sN(Rx)    // allocate stack frame
    01942                     //
    01943
    01944                     DecrementRegister = Rb;
    01945                     DecrementOffset = Offset16;
    01946                     _RtlpDebugDisassemble(ControlPc, ContextRecord);
    01947                 }
    01948
    01949             } else if (Ra == DecrementRegister) {
    01950                 if (Rb == DecrementRegister) {
    01951
    01952                     //
    01953                     // Both the destination and base registers are the
    01954                     // decrement register, so this instruction exists as the
    01955                     // second half of a two instruction pair to load a
    01956                     // 31-bit immediate value into the decrement register.
    01957                     // Save the displacement value as the partial decrement
    01958                     // value.
    01959                     //
    01960                     // The prologue instruction sequence is:
    01961                     //
    01962                     //      ldah  Rx, +N(zero)      // set frame size (upper)
    01963                     // ==>  lda   Rx, sN(Rx)        // set frame size (+lower)
    01964                     //      ...
    01965                     //      subq  sp, Rx, sp        // allocate stack frame
    01966                     //
    01967
    01968                     DecrementOffset += Offset16;
    01969                     _RtlpDebugDisassemble(ControlPc, ContextRecord);
    01970
    01971                 } else if (Rb == ZERO_REG) {
    01972
    01973                     //
    01974                     // The destination register is the decrement register and
    01975                     // the base register is zero, so this instruction exists
    01976                     // to load an immediate value into the decrement register.
    01977                     // The stack frame size is the new displacement value added
    01978                     // to the previous displacement value, if any.
    01979                     //
    01980                     // The prologue instruction sequence is:
    01981                     //
    01982                     // ==>  lda   Rx, +N(zero)      // set frame size
    01983                     //      ...
    01984                     //      subq  sp, Rx, sp        // allocate stack frame
    01985                     // or
    01986                     //
    01987                     // ==>  ldah  Rx, +N(zero)      // set frame size (upper)
    01988                     //      lda   Rx, sN(Rx)        // set frame size (+lower)
    01989                     //      ...
    01990                     //      subq  sp, Rx, sp        // allocate stack frame
    01991                     //
    01992
    01993                     FrameSize = (Offset16 + DecrementOffset);
    01994                     goto StackAllocation;
    01995
    01996                 } else if (Rb == SP_REG) {
    01997
    01998                     //
    01999                     // The destination (Ra) register is SP and the base (Rb)
    02000                     // register is the decrement register, so a two
    02001                     // instruction, large size (>32768 bytes) stack frame
    02002                     // allocation was performed. Add the new displacement
    02003                     // value to the previous displacement value. The negated
    02004                     // displacement value is the stack frame size.
    02005                     //
    02006                     // The prologue instruction sequence is:
    02007                     //
    02008                     // ==>  ldah  Rx, -N(sp)    // prepare new SP (upper)
    02009                     //      lda   sp, sN(Rx)    // allocate stack frame
    02010                     //
    02011
    02012                     FrameSize = -(Offset16 + (LONG)DecrementOffset);
    02013                     goto StackAllocation;
    02014                 }
    02015             }
    02016             break;
    02017
    02018         case ARITH_OP :
    02019
    02020             if ((Function == ADDQ_FUNC) &&
    02021                 (Instruction.OpReg.RbvType != RBV_REGISTER_FORMAT)) {
    02022
    02023                 //
    02024                 // Add Quadword (immediate) instruction.
    02025                 //
    02026                 // If the first source register is zero, and the second
    02027                 // operand is a literal, and the destination register is
    02028                 // the decrement register, then the instruction exists
    02029                 // to load an unsigned immediate value less than 256 into
    02030                 // the decrement register. The immediate value is the stack
    02031                 // frame size.
    02032                 //
    02033                 // The prologue instruction sequence is:
    02034                 //
    02035                 // ==>  addq  zero, N, Rx       // set frame size
    02036                 //      ...
    02037                 //      subq  sp, Rx, sp        // allocate stack frame
    02038                 //
    02039
    02040                 if ((Ra == ZERO_REG) && (Rc == DecrementRegister)) {
    02041                     FrameSize = Literal8;
    02042                     goto StackAllocation;
    02043                 }
    02044
    02045             } else if ((Function == SUBQ_FUNC) &&
    02046                        (Instruction.OpReg.RbvType == RBV_REGISTER_FORMAT)) {
    02047
    02048                 //
    02049                 // Subtract Quadword (register) instruction.
    02050                 //
    02051                 // If both source operands are registers and the first
    02052                 // source (minuend) register and the destination
    02053                 // (difference) register are both SP, then a register value
    02054                 // stack allocation was performed and the second source
    02055                 // (subtrahend) register value will be added to SP when its
    02056                 // value is known. Until that time save the register number of
    02057                 // this decrement register.
    02058                 //
    02059                 // The prologue instruction sequence is:
    02060                 //
    02061                 //      ldiq  Rx, N             // set frame size
    02062                 //      ...
    02063                 // ==>  subq  sp, Rx, sp        // allocate stack frame
    02064                 //
    02065
    02066                 if ((Ra == SP_REG) && (Rc == SP_REG)) {
    02067                     DecrementRegister = Rb;
    02068                     DecrementOffset = 0;
    02069                     _RtlpDebugDisassemble(ControlPc, ContextRecord);
    02070                 }
    02071             }
    02072             break;
    02073
    02074         case BIT_OP :
    02075
    02076             //
    02077             // If the second operand is a register the bit set instruction
    02078             // may be a register move instruction, otherwise if the second
    02079             // operand is a literal, the bit set instruction may be a load
    02080             // immediate value instruction.
    02081             //
    02082
    02083             if ((Function == BIS_FUNC) && (Rc != ZERO_REG)) {
    02084                 if (Instruction.OpReg.RbvType == RBV_REGISTER_FORMAT) {
    02085
    02086                     //
    02087                     // Bit Set (register move) instruction.
    02088                     //
    02089                     // If both source registers are the same register, or
    02090                     // one of the source registers is zero, then this is a
    02091                     // register move operation. Restore the value of the
    02092                     // source register by copying the current destination
    02093                     // register value back to the source register.
    02094                     //
    02095                     // The prologue instruction sequence is:
    02096                     //
    02097                     // ==>  bis   Rx, Rx, Ry        // copy register Rx
    02098                     // or
    02099                     //
    02100                     // ==>  bis   Rx, zero, Ry      // copy register Rx
    02101                     // or
    02102                     //
    02103                     // ==>  bis   zero, Rx, Ry      // copy register Rx
    02104                     //
    02105
    02106                     if (Ra == ZERO_REG) {
    02107
    02108                         //
    02109                         // Map the third case above to the first case.
    02110                         //
    02111
    02112                         Ra = Rb;
    02113
    02114                     } else if (Rb == ZERO_REG) {
    02115
    02116                         //
    02117                         // Map the second case above to the first case.
    02118                         //
    02119
    02120                         Rb = Ra;
    02121                     }
    02122
    02123                     if ((Ra == Rb) && (Ra != ZERO_REG)) {
    02124                         IntegerRegister[Ra] = IntegerRegister[Rc];
    02125
    02126                         //
    02127                         // If the destination register is RA and this is the
    02128                         // first time that RA is being restored, then set the
    02129                         // address of where control left the previous frame.
    02130                         // Otherwise, if this is the second time RA is being
    02131                         // restored, then the first one was an interrupt or
    02132                         // exception address and the return PC should not
    02133                         // have been biased by 4.
    02134                         //
    02135
    02136                         if (Ra == RA_REG) {
    02137                             if (RestoredRa == FALSE) {
    02138                                 NextPc = (ULONG_PTR)ContextRecord->IntRa - 4;
    02139                                 RestoredRa = TRUE;
    02140
    02141                             } else {
    02142                                 NextPc += 4;
    02143                                 _RtlpFoundTrapFrame(NextPc);
    02144                             }
    02145
    02146                         //
    02147                         // If the source register is SP and this is the first
    02148                         // time SP is set, then this is a frame pointer set
    02149                         // instruction. Reset the frame pointers to this new
    02150                         // value of SP.
    02151                         //
    02152
    02153                         } else if ((Ra == SP_REG) && (RestoredSp == FALSE)) {
    02154                             EstablisherFrame->Virtual = (ULONG_PTR)ContextRecord->IntSp;
    02155                             EstablisherFrame->Real = (ULONG_PTR)ContextRecord->IntSp;
    02156                             RestoredSp = TRUE;
    02157                         }
    02158
    02159                         _RtlpDebugDisassemble(ControlPc, ContextRecord);
    02160                     }
    02161
    02162                 } else {
    02163
    02164                     //
    02165                     // Bit Set (load immediate) instruction.
    02166                     //
    02167                     // If the first source register is zero, and the second
    02168                     // operand is a literal, and the destination register is
    02169                     // the decrement register, then this instruction exists
    02170                     // to load an unsigned immediate value less than 256 into
    02171                     // the decrement register. The decrement register value is
    02172                     // the stack frame size.
    02173                     //
    02174                     // The prologue instruction sequence is:
    02175                     //
    02176                     // ==>  bis   zero, N, Rx       // set frame size
    02177                     //      ...
    02178                     //      subq  sp, Rx, sp        // allocate stack frame
    02179                     //
    02180
    02181                     if ((Ra == ZERO_REG) && (Rc == DecrementRegister)) {
    02182                         FrameSize = Literal8;
    02183 StackAllocation:
    02184                         //
    02185                         // Add the frame size to SP to reverse the stack frame
    02186                         // allocation, leave the real frame pointer as is, set
    02187                         // the virtual frame pointer with the updated SP value,
    02188                         // and clear the decrement register.
    02189                         //
    02190
    02191                         ContextRecord->IntSp += FrameSize;
    02192                         EstablisherFrame->Virtual = (ULONG_PTR)ContextRecord->IntSp;
    02193                         DecrementRegister = ZERO_REG;
    02194                         _RtlpDebugDisassemble(ControlPc, ContextRecord);
    02195                     }
    02196                 }
    02197             }
    02198             break;
    02199
    02200         case STT_OP :
    02201
    02202             //
    02203             // Store T-Floating (quadword integer) instruction.
    02204             //
    02205             // If the base register is SP, then reload the source register
    02206             // value from the value stored on the stack.
    02207             //
    02208             // The prologue instruction sequence is:
    02209             //
    02210             // ==>  stt   Fx, N(sp)         // save floating register Fx
    02211             //
    02212
    02213             if ((Rb == SP_REG) && (Ra != FZERO_REG)) {
    02214
    02215                 //
    02216                 // Reload the register by retrieving the value previously
    02217                 // stored on the stack.
    02218                 //
    02219
    02220                 Address = Offset16 + (LONG_PTR)ContextRecord->IntSp;
    02221                 FloatingRegister[Ra] = *((PULONGLONG)Address);
    02222
    02223                 //
    02224                 // If a context pointer record is specified, then record
    02225                 // the address where the destination register contents are
    02226                 // stored.
    02227                 //
    02228
    02229                 if (ARGUMENT_PRESENT(ContextPointers)) {
    02230                     ContextPointers->FloatingContext[Ra] = (PULONGLONG)Address;
    02231                 }
    02232                 _RtlpDebugDisassemble(ControlPc, ContextRecord);
    02233             }
    02234             break;
    02235
    02236         case FPOP_OP :
    02237
    02238             //
    02239             // N.B. The floating operate function field is not the same as
    02240             // the integer operate nor the jump function fields.
    02241             //
    02242
    02243             if (Instruction.FpOp.Function == CPYS_FUNC) {
    02244
    02245                 //
    02246                 // Copy Sign (floating-point move) instruction.
    02247                 //
    02248                 // If both source registers are the same register, then this is
    02249                 // a floating-point register move operation. Restore the value
    02250                 // of the source register by copying the current destination
    02251                 // register value to the source register.
    02252                 //
    02253                 // The prologue instruction sequence is:
    02254                 //
    02255                 // ==>  cpys  Fx, Fx, Fy        // copy floating register Fx
    02256                 //
    02257
    02258                 if ((Ra == Rb) && (Ra != FZERO_REG)) {
    02259                     FloatingRegister[Ra] = FloatingRegister[Rc];
    02260                     _RtlpDebugDisassemble(ControlPc, ContextRecord);
    02261                 }
    02262             }
    02263
    02264         default :
    02265             break;
    02266         }
    02267     }
    02268
    02269     // Check for exlicit stack adjust amount
    02270
    02271     if (StackAdjust) {
    02272         ContextRecord->IntSp += StackAdjust;
    02273     }
    02274
    02275     if (FixedReturn != 0) {
    02276         NextPc = FixedReturn;
    02277     }
    02278
    02279     _RtlpVirtualUnwindExit(NextPc, ContextRecord, EstablisherFrame);
    02280     return NextPc;
    02281 }

int __cdecl sprintf | ( | char * | ,
|  | const char * | ,
|  |  | ...
| ) |

## Variable Documentation

LIST_ENTRY DynamicFunctionTable

| Definition at line 137 of file alpha/exdsptch.c. Referenced by RtlAddFunctionTable(), RtlDeleteFunctionTable(), RtlGetFunctionTableListHead(), and RtlLookupDynamicFunctionEntry().