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

vunwind.c File Reference

Go to the source code of this file.

Classes

struct  _MILLICODE_INFO
struct  _ITERATOR

Defines

#define NOT_IMAGEHLP(E)   E
#define GPR1   1
#define GPR2   2
#define GPR12   12
#define LINKREG   0x100
#define COUNTREG   0x120
#define OP_INTENT(OP, INTENT)   ((OP) << 2 | (INTENT))

Typedefs

typedef DOUBLE * PDOUBLE
typedef enum _INSTR_CLASS INSTR_CLASS
typedef _MILLICODE_INFO MILLICODE_INFO
typedef _MILLICODE_INFOPMILLICODE_INFO
typedef enum _UNWIND_INTENT UNWIND_INTENT
typedef _ITERATOR ITERATOR
typedef _ITERATORPITERATOR

Enumerations

enum  _INSTR_CLASS {
  InstrIgnore, InstrMFLR, InstrMFCR, InstrSTW,
  InstrSTWU, InstrSTWUr12, InstrSTFD, InstrMR,
  InstrMRr12, InstrMRfwd, InstrADDIr12, InstrADDIfwd,
  InstrSaveCode, InstrRestoreCode, InstrGlue, InstrBLR,
  InstrTOCRestore, InstrSetEstablisher
}
enum  _UNWIND_INTENT { UnwindForward, UnwindR12, UnwindReverse, UnwindReverseR12 }

Functions

NTSTATUS TryReadUlong (IN ULONG NextPc, OUT PULONG Value)
INSTR_CLASS ClassifyInstruction (PPC_INSTRUCTION *I, UNWIND_INTENT Intent, ULONG Pc, PMILLICODE_INFO Info)
ULONG RtlVirtualUnwind (IN ULONG ControlPc, IN PRUNTIME_FUNCTION FunctionEntry, IN OUT PCONTEXT ContextRecord, OUT PBOOLEAN InFunction, OUT PULONG EstablisherFrame, IN OUT PKNONVOLATILE_CONTEXT_POINTERS ContextPointers OPTIONAL, IN ULONG LowStackLimit, IN ULONG HighStackLimit)


Define Documentation

#define COUNTREG   0x120
 

Definition at line 154 of file ppc/vunwind.c.

#define GPR1   1
 

Definition at line 150 of file ppc/vunwind.c.

Referenced by ClassifyInstruction(), and RtlVirtualUnwind().

#define GPR12   12
 

Definition at line 152 of file ppc/vunwind.c.

Referenced by ClassifyInstruction(), and RtlVirtualUnwind().

#define GPR2   2
 

Definition at line 151 of file ppc/vunwind.c.

Referenced by ClassifyInstruction(), and RtlVirtualUnwind().

#define LINKREG   0x100
 

Definition at line 153 of file ppc/vunwind.c.

Referenced by ClassifyInstruction().

#define NOT_IMAGEHLP  )     E
 

Definition at line 83 of file ppc/vunwind.c.

#define OP_INTENT OP,
INTENT   )     ((OP) << 2 | (INTENT))
 

Referenced by ClassifyInstruction().


Typedef Documentation

typedef enum _INSTR_CLASS INSTR_CLASS
 

Referenced by RtlVirtualUnwind().

typedef struct _ITERATOR ITERATOR
 

typedef struct _MILLICODE_INFO MILLICODE_INFO
 

typedef DOUBLE* PDOUBLE
 

Definition at line 71 of file ppc/vunwind.c.

Referenced by RtlVirtualUnwind().

typedef struct _ITERATOR * PITERATOR
 

Referenced by RtlVirtualUnwind().

typedef struct _MILLICODE_INFO * PMILLICODE_INFO
 

typedef enum _UNWIND_INTENT UNWIND_INTENT
 


Enumeration Type Documentation

enum _INSTR_CLASS
 

Enumeration values:
InstrIgnore 
InstrMFLR 
InstrMFCR 
InstrSTW 
InstrSTWU 
InstrSTWUr12 
InstrSTFD 
InstrMR 
InstrMRr12 
InstrMRfwd 
InstrADDIr12 
InstrADDIfwd 
InstrSaveCode 
InstrRestoreCode 
InstrGlue 
InstrBLR 
InstrTOCRestore 
InstrSetEstablisher 

Definition at line 96 of file ppc/vunwind.c.

00096 { 00097 InstrIgnore, // Do not process 00098 InstrMFLR, // Move from Link Register 00099 InstrMFCR, // Move from Condition Register 00100 InstrSTW, // Store word 00101 InstrSTWU, // Store word with update 00102 InstrSTWUr12, // Store word with update during UnwindR12 00103 InstrSTFD, // Store float double 00104 InstrMR, // Move register 00105 InstrMRr12, // Move register during UnwindR12 00106 InstrMRfwd, // Move register during UnwindForward 00107 InstrADDIr12, // Add immediate during UnwindR12 00108 InstrADDIfwd, // Add immediate during UnwindForward 00109 InstrSaveCode, // Branch and link to GPR or FPR saving millicode 00110 InstrRestoreCode, // Branch to GPR or FPR saving millicode 00111 InstrGlue, // Branch or Branch and link to glue code 00112 InstrBLR, // Branch to Link Register 00113 InstrTOCRestore, // Load that restores the TOC [after a call to glue] 00114 InstrSetEstablisher // Special instruction used to set establisher frame 00115 } INSTR_CLASS;

enum _UNWIND_INTENT
 

Enumeration values:
UnwindForward 
UnwindR12 
UnwindReverse 
UnwindReverseR12 

Definition at line 131 of file ppc/vunwind.c.

00131 { 00132 UnwindForward, // Performing a forward execution 00133 UnwindR12, // Performing a reverse execution to get r.12 00134 UnwindReverse, // Performing a reverse execution 00135 UnwindReverseR12 // Performing a reverse execution allowing r.12 00136 } UNWIND_INTENT;


Function Documentation

INSTR_CLASS ClassifyInstruction PPC_INSTRUCTION *  I,
UNWIND_INTENT  Intent,
ULONG  Pc,
PMILLICODE_INFO  Info
[static]
 

Definition at line 179 of file ppc/vunwind.c.

References DWORD, _MILLICODE_INFO::FunctionEntry, GPR1, GPR12, GPR2, InstrADDIfwd, InstrADDIr12, InstrBLR, InstrGlue, InstrIgnore, InstrMFCR, InstrMFLR, InstrMR, InstrMRfwd, InstrMRr12, InstrRestoreCode, InstrSaveCode, InstrSetEstablisher, InstrSTFD, InstrSTW, InstrSTWU, InstrSTWUr12, InstrTOCRestore, Intent, LINKREG, NULL, OP_INTENT, READ_ULONG, RtlLookupFunctionEntry(), _MILLICODE_INFO::TargetPc, UnwindForward, UnwindR12, UnwindReverse, and UnwindReverseR12.

Referenced by RtlVirtualUnwind().

00191 : 00192 00193 This function inspects the instruction identified by the "Pc" 00194 argument and determines what sort of processing is needed in order 00195 to simulate its execution. Some instructions can be safely 00196 ignored altogether, in which case "InstrIgnore" is returned. For 00197 others, a value is returned indicating what kind of instruction 00198 was found. The interpreation depends on the value of "Intent". 00199 00200 Arguments: 00201 00202 I - Address of a struct containing the instruction to be examined. 00203 Intent - Type of unwinding being performed. 00204 Pc - Address of the instruction, used for computing relative branch 00205 addresses. 00206 Info - Address to store a description of the register save/restore 00207 millicode. 00208 00209 Return value: 00210 00211 One of the enum values defined above is returned. 00212 00213 --*/ 00214 00215 { 00216 // Unique value combining an opcode and an UNWIND_INTENT value. 00217 #define OP_INTENT(OP,INTENT) ((OP) << 2 | (INTENT)) 00218 00219 #ifdef _IMAGEHLP_SOURCE_ 00220 DWORD ImagehlpCb = 0; 00221 #endif 00222 00223 switch (OP_INTENT (I->Primary_Op, Intent)) { 00224 00225 // 00226 // Store word: recognize "stw r.n, disp(r.1)". Allow a base of 00227 // r.12 if we have computed its value. 00228 // 00229 case OP_INTENT (STW_OP, UnwindReverseR12): 00230 if (I->Dform_RA == GPR12) 00231 return InstrSTW; 00232 // fall thru 00233 case OP_INTENT (STW_OP, UnwindReverse): 00234 if (I->Dform_RA == GPR1) 00235 return InstrSTW; 00236 break; 00237 00238 // 00239 // Load word: recognize "lwz r.n, disp(r.x)" in epilogue millicode. 00240 // 00241 case OP_INTENT (LWZ_OP, UnwindForward): 00242 return InstrSTW; 00243 00244 // 00245 // Load word: recognize "lwz r.toc, disp(r.1)" as TOC restore 00246 // instruction. 00247 // 00248 case OP_INTENT (LWZ_OP, UnwindReverse): 00249 if (I->Dform_RA == GPR1 && 00250 I->Dform_RS == GPR2) 00251 return InstrTOCRestore; 00252 00253 // 00254 // Store word with update: recognize "stwu r.1, r.1, disp" 00255 // 00256 case OP_INTENT (STWU_OP, UnwindReverse): 00257 case OP_INTENT (STWU_OP, UnwindReverseR12): 00258 case OP_INTENT (STWU_OP, UnwindR12): 00259 if (I->Dform_RS == GPR1 && 00260 I->Dform_RA == GPR1) 00261 return (Intent == UnwindR12 ? InstrSTWUr12 : InstrSTWU); 00262 break; 00263 00264 // 00265 // Store float double: recognize "stfd f.n, disp(r.1)". Allow a 00266 // base of r.12 if we have computed its value. 00267 // 00268 case OP_INTENT (STFD_OP, UnwindReverseR12): 00269 if (I->Dform_RA == GPR12) 00270 return InstrSTFD; 00271 // fall thru 00272 case OP_INTENT (STFD_OP, UnwindReverse): 00273 if (I->Dform_RA == GPR1) 00274 return InstrSTFD; 00275 break; 00276 00277 // 00278 // Load float double: recognize "lfd f.n, disp(r.x)" 00279 // 00280 case OP_INTENT (LFD_OP, UnwindForward): 00281 return InstrSTFD; 00282 00283 // 00284 // Add immediate: recognize "addi r.12, r.1, delta" 00285 // 00286 case OP_INTENT (ADDI_OP, UnwindR12): 00287 if (I->Dform_RS == GPR12 && 00288 I->Dform_RA == GPR1) 00289 return InstrADDIr12; 00290 break; 00291 case OP_INTENT (ADDI_OP, UnwindForward): 00292 return InstrADDIfwd; 00293 00294 // 00295 // Branch (long form): recognize "bl[a] saveregs"and "b[a] restregs" 00296 // 00297 case OP_INTENT (B_OP, UnwindReverse): 00298 // 00299 // Compute branch target address, allowing for branch-relative 00300 // and branch-absolute. 00301 // 00302 Pc = ((LONG)(I->Iform_LI) << 2) + (I->Iform_AA ? 0 : Pc); 00303 00304 // 00305 // Quickly distinguish "bl subroutine" from "bl[a] saveregs". 00306 // "mtlr" is not a valid instruction in register save millicode and 00307 // is usually the first instruction in "bl subroutine". 00308 // 00309 if (I->Iform_LK) { 00310 PPC_INSTRUCTION TempI; 00311 READ_ULONG (Pc, TempI.Long); 00312 if (TempI.Primary_Op == X31_OP && 00313 TempI.Xform_XO == MFSPR_OP && 00314 TempI.XFXform_spr == LINKREG) { 00315 break; 00316 } 00317 } 00318 00319 // 00320 // Determine whether the target address is part of a register 00321 // save or register restore sequence or is a direct branch out 00322 // by checking it's function table entry. 00323 // 00324 if ((Info->FunctionEntry = (PRUNTIME_FUNCTION)RtlLookupFunctionEntry(Pc)) != NULL 00325 #ifndef FUNCTION_ENTRY_IS_IMAGE_STYLE 00326 && Info->FunctionEntry->ExceptionHandler == 0 00327 #endif 00328 ) { 00329 Info->TargetPc = Pc; 00330 switch ( 00331 #ifdef FUNCTION_ENTRY_IS_IMAGE_STYLE 00332 Info->FunctionEntry->BeginAddress - 00333 Info->FunctionEntry->PrologEndAddress 00334 #else 00335 (ULONG)Info->FunctionEntry->HandlerData 00336 #endif 00337 ) { 00338 case 1: 00339 if (I->Iform_LK) 00340 return InstrSaveCode; 00341 break; 00342 case 2: 00343 if (!I->Iform_LK) 00344 return InstrRestoreCode; 00345 break; 00346 #ifdef FUNCTION_ENTRY_IS_IMAGE_STYLE 00347 default: 00348 if ((Info->FunctionEntry->PrologEndAddress & 3) == 1) 00349 #else 00350 case 3: 00351 #endif 00352 return InstrGlue; 00353 break; 00354 } 00355 } 00356 break; // unrecognized entry point 00357 00358 // 00359 // Extended ops -- primary opcode 19 00360 // 00361 case OP_INTENT (X19_OP, UnwindForward): 00362 00363 // 00364 // BLR: recognized "bclr 20,0". 00365 // 00366 if (I->Long == RETURN_INSTR) 00367 return InstrBLR; 00368 00369 break; 00370 00371 case OP_INTENT (X19_OP, UnwindR12): 00372 case OP_INTENT (X19_OP, UnwindReverse): 00373 case OP_INTENT (X19_OP, UnwindReverseR12): 00374 // 00375 // RFI: this instruction is used in special kernel fake prologues 00376 // to indicate that the establisher frame address should be 00377 // updated using the current value of sp. 00378 // 00379 if (I->Xform_XO == RFI_OP) { 00380 return InstrSetEstablisher; 00381 } 00382 00383 break; 00384 00385 // 00386 // Extended ops -- primary opcode 31 00387 // 00388 case OP_INTENT (X31_OP, UnwindForward): 00389 case OP_INTENT (X31_OP, UnwindR12): 00390 case OP_INTENT (X31_OP, UnwindReverse): 00391 case OP_INTENT (X31_OP, UnwindReverseR12): 00392 switch (OP_INTENT (I->Xform_XO, Intent)) { 00393 00394 // 00395 // OR register: recognize "or r.x, r.y, r.y" as move-reg 00396 // 00397 case OP_INTENT (OR_OP, UnwindR12): 00398 if (I->Xform_RS == I->Xform_RB && 00399 I->Xform_RA == GPR12 && 00400 I->Xform_RB == GPR1) 00401 return InstrMRr12; 00402 break; 00403 case OP_INTENT (OR_OP, UnwindReverse): 00404 case OP_INTENT (OR_OP, UnwindReverseR12): 00405 if (I->Xform_RS == I->Xform_RB && 00406 I->Xform_RB != GPR1) 00407 return InstrMR; 00408 break; 00409 case OP_INTENT (OR_OP, UnwindForward): 00410 if (I->Xform_RS == I->Xform_RB) 00411 return InstrMRfwd; 00412 break; 00413 00414 // 00415 // Store word with update indexed: recognize "stwux r.1, r.1, r.x" 00416 // 00417 case OP_INTENT (STWUX_OP, UnwindReverse): 00418 case OP_INTENT (STWUX_OP, UnwindReverseR12): 00419 case OP_INTENT (STWUX_OP, UnwindR12): 00420 if (I->Xform_RS == GPR1 && I->Xform_RA == GPR1) 00421 return (Intent == UnwindR12 ? InstrSTWUr12 : InstrSTWU); 00422 break; 00423 00424 // 00425 // Move to/from special-purpose reg: recognize "mflr", "mtlr" 00426 // 00427 case OP_INTENT (MFSPR_OP, UnwindReverse): 00428 case OP_INTENT (MTSPR_OP, UnwindForward): 00429 if (I->XFXform_spr == LINKREG) 00430 return InstrMFLR; 00431 break; 00432 00433 // 00434 // Move from Condition Register: "mfcr r.x" 00435 // 00436 case OP_INTENT (MFCR_OP, UnwindReverse): 00437 case OP_INTENT (MFCR_OP, UnwindReverseR12): 00438 return InstrMFCR; 00439 00440 // 00441 // Move to Condition Register: "mtcrf 255,r.x" 00442 // 00443 case OP_INTENT (MTCRF_OP, UnwindForward): 00444 if (I->XFXform_FXM == 255) 00445 return InstrMFCR; 00446 break; 00447 00448 default: // unrecognized 00449 break; 00450 } 00451 00452 default: // unrecognized 00453 break; 00454 } 00455 00456 // 00457 // Instruction not recognized; just ignore it and carry on 00458 // 00459 return InstrIgnore; 00460 #undef OP_INTENT 00461 }

ULONG RtlVirtualUnwind IN ULONG  ControlPc,
IN PRUNTIME_FUNCTION  FunctionEntry,
IN OUT PCONTEXT  ContextRecord,
OUT PBOOLEAN  InFunction,
OUT PULONG  EstablisherFrame,
IN OUT PKNONVOLATILE_CONTEXT_POINTERS ContextPointers  OPTIONAL,
IN ULONG  LowStackLimit,
IN ULONG  HighStackLimit
 

Definition at line 467 of file ppc/vunwind.c.

References _ITERATOR::BeginPc, ClassifyInstruction(), DWORD, _ITERATOR::EndPc, FALSE, _MILLICODE_INFO::FunctionEntry, GPR1, GPR12, GPR2, _ITERATOR::Increment, INSTR_CLASS, InstrADDIfwd, InstrADDIr12, InstrBLR, InstrGlue, InstrIgnore, InstrMFCR, InstrMFLR, InstrMR, InstrMRfwd, InstrMRr12, InstrRestoreCode, InstrSaveCode, InstrSetEstablisher, InstrSTFD, InstrSTW, InstrSTWU, InstrSTWUr12, InstrTOCRestore, _ITERATOR::Intent, NOT_IMAGEHLP, NT_SUCCESS, NULL, PDOUBLE, PITERATOR, READ_DOUBLE, READ_ULONG, RtlLookupFunctionEntry(), _MILLICODE_INFO::TargetPc, TRUE, TryReadUlong(), UnwindForward, UnwindR12, UnwindReverse, and UnwindReverseR12.

Referenced by ExpRaiseException(), ExpRaiseStatus(), KeDumpMachineState(), PspGetSetContextApc(), PspGetSetContextSpecialApc(), PspGetSetContextSpecialApcMain(), RtlDispatchException(), RtlGetCallersAddress(), RtlpRaiseException(), RtlpRaiseStatus(), RtlpVirtualUnwind(), RtlUnwind2(), RtlUnwindReturn(), RtlUnwindRfp(), and setjmp().

00491 : 00492 00493 This function virtually unwinds the specfified function by executing its 00494 prologue code backwards. 00495 00496 If the function is a leaf function, then the address where control left 00497 the previous frame is obtained from the context record. If the function 00498 is a nested function, but not an exception or interrupt frame, then the 00499 prologue code is executed backwards and the address where control left 00500 the previous frame is obtained from the updated context record. 00501 00502 If the function is register save millicode, it is treated as a leaf 00503 function. If the function is register restore millicode, the remaining 00504 body is executed forwards and the address where control left the 00505 previous frame is obtained from the final blr instruction. 00506 00507 If the function was called via glue code and is not that glue code, 00508 the prologe of the glue code is executed backwards in addition to the 00509 above actions. 00510 00511 Otherwise, an exception or interrupt entry to the system is being 00512 unwound and a specially coded prologue restores the return address 00513 twice. Once from the fault instruction address and once from the saved 00514 return address register. The first restore is returned as the function 00515 value and the second restore is place in the updated context record. 00516 00517 If a context pointers record is specified, then the address where each 00518 nonvolatile registers is restored from is recorded in the appropriate 00519 element of the context pointers record. 00520 00521 Arguments: 00522 00523 ControlPc - Supplies the address where control left the specified 00524 function. 00525 00526 FunctionEntry - Supplies the address of the function table entry for the 00527 specified function or NULL if the function is a leaf function. 00528 00529 ContextRecord - Supplies the address of a context record. 00530 00531 InFunction - Supplies a pointer to a variable that receives whether the 00532 control PC is within the current function. 00533 00534 EstablisherFrame - Supplies a pointer to a variable that receives the 00535 the establisher frame pointer value. 00536 00537 ContextPointers - Supplies an optional pointer to a context pointers 00538 record. 00539 00540 LowStackLimit, HighStackLimit - Range of valid values for the stack 00541 pointer. This indicates whether it is valid to examine NextPc. 00542 00543 Return Value: 00544 00545 The address where control left the previous frame is returned as the 00546 function value. 00547 00548 --*/ 00549 00550 { 00551 ITERATOR Iterator[8]; 00552 PITERATOR Piterator; 00553 ULONG Address; 00554 PDOUBLE FloatingRegister; 00555 PPC_INSTRUCTION I; 00556 PULONG IntegerRegister; 00557 ULONG NextPc, Pc; 00558 BOOLEAN RestoredLr = FALSE; 00559 BOOLEAN RestoredSp = FALSE; 00560 BOOLEAN ComputedSp = FALSE; 00561 ULONG Rt; 00562 MILLICODE_INFO Info; 00563 INSTR_CLASS InstrClass; 00564 #ifdef _IMAGEHLP_SOURCE_ 00565 DWORD ImagehlpCb = 0; 00566 RUNTIME_FUNCTION SavedFunctionEntry; 00567 #else 00568 ULONG EstablisherFrameValue; 00569 #endif 00570 00571 // 00572 // Set the base address of the integer and floating register arrays. 00573 // 00574 00575 FloatingRegister = &ContextRecord->Fpr0; 00576 IntegerRegister = &ContextRecord->Gpr0; 00577 00578 // 00579 // If the function is a leaf function, perform the default unwinding 00580 // action and check to see if the function was called via glue. 00581 // 00582 if (FunctionEntry == NULL) { 00583 // 00584 // Set point at which control left the previous routine. 00585 // 00586 NextPc = ContextRecord->Lr - 4; 00587 00588 // 00589 // If the next control PC is the same as the old control PC, then 00590 // the function table is not correctly formed. 00591 // 00592 if (NextPc == ControlPc) 00593 return NextPc; 00594 00595 goto CheckForGlue; 00596 } 00597 #ifdef _IMAGEHLP_SOURCE_ 00598 else { 00599 SavedFunctionEntry = *FunctionEntry; 00600 FunctionEntry = &SavedFunctionEntry; 00601 } 00602 #endif 00603 // 00604 // Set initial values for EstablisherFrame and Offset. 00605 // (this may need more careful planning IBMPLJ). 00606 // 00607 00608 NOT_IMAGEHLP (*EstablisherFrame = 00609 EstablisherFrameValue = ContextRecord->Gpr1); 00610 00611 READ_ULONG (ControlPc, I.Long); 00612 if (I.Long == RETURN_INSTR) { 00613 // 00614 // If the instruction at the point where control left the specified 00615 // function is a return, then any saved registers have been restored 00616 // and the control PC is not considered to be in the function 00617 // (i.e., in an epilogue). 00618 // 00619 NOT_IMAGEHLP(*InFunction = FALSE); 00620 NextPc = ContextRecord->Lr; 00621 goto CheckForGlue; 00622 } 00623 InstrClass = ClassifyInstruction(&I, UnwindReverse, 00624 #ifdef _IMAGEHLP_SOURCE_ 00625 hProcess, ReadMemory, FunctionTableAccess, 00626 #endif 00627 ControlPc, &Info); 00628 if (InstrClass == InstrRestoreCode) { 00629 // 00630 // If the instruction at the point where control left the 00631 // specified function is a branch to register restore 00632 // millicode, the state is restored by simulating the 00633 // execution of the restore millicode. The control PC is in 00634 // an epilogue. 00635 // 00636 Iterator[0].BeginPc = Info.TargetPc; 00637 Iterator[0].EndPc = Info.FunctionEntry->EndAddress; 00638 Iterator[0].Increment = 4; 00639 Iterator[0].Intent = UnwindForward; 00640 NOT_IMAGEHLP(*InFunction = FALSE); 00641 00642 } else if ( 00643 #ifdef FUNCTION_ENTRY_IS_IMAGE_STYLE 00644 (FunctionEntry->BeginAddress - 00645 FunctionEntry->PrologEndAddress) == 2 00646 #else 00647 FunctionEntry->ExceptionHandler == 0 && 00648 (ULONG)FunctionEntry->HandlerData == 2 00649 #endif 00650 ) { 00651 // 00652 // If the address is in register restore millicode, the state 00653 // is restored by completing the execution of the restore 00654 // millicode. The control PC is in an epilogue. 00655 // 00656 Iterator[0].BeginPc = ControlPc; 00657 Iterator[0].EndPc = FunctionEntry->EndAddress; 00658 Iterator[0].Increment = 4; 00659 Iterator[0].Intent = UnwindForward; 00660 NOT_IMAGEHLP(*InFunction = FALSE); 00661 00662 } else { 00663 // 00664 // If the address where control left the specified function is a 00665 // TOC restore instruction and the previous instruction is a call 00666 // via glue instruction, we must forward execute the TOC restore 00667 // instruction. 00668 // 00669 if (InstrClass == InstrTOCRestore) { 00670 PPC_INSTRUCTION Iprev; 00671 READ_ULONG (ControlPc - 4, Iprev.Long); 00672 if (ClassifyInstruction (&Iprev, UnwindReverse, 00673 #ifdef _IMAGEHLP_SOURCE_ 00674 hProcess, ReadMemory, FunctionTableAccess, 00675 #endif 00676 ControlPc - 4, &Info) == InstrGlue) { 00677 // 00678 // Forward execute the TOC restore. We assume (reasonably) 00679 // that the next instruction is covered by the same function 00680 // table entry and it isn't one of the above special cases 00681 // (InstrRestoreCode or InstrBLR). 00682 // 00683 ControlPc += 4; 00684 Address = IntegerRegister[I.Dform_RA] + I.Dform_D; 00685 Rt = I.Dform_RT; 00686 READ_ULONG (Address, IntegerRegister[Rt]); 00687 if (ARGUMENT_PRESENT (ContextPointers)) 00688 ContextPointers->IntegerContext[Rt] = (PULONG) Address; 00689 } 00690 } 00691 00692 // 00693 // If the address where control left the specified function is 00694 // outside the limits of the prologue, then the control PC is 00695 // considered to be within the function and the control 00696 // address is set to the end of the prologue. Otherwise, the 00697 // control PC is not considered to be within the function 00698 // (i.e., in the prologue). 00699 // 00700 Iterator[0].EndPc = FunctionEntry->BeginAddress - 4; 00701 Iterator[0].Increment = -4; 00702 Iterator[0].Intent = UnwindReverse; 00703 if ((ControlPc < FunctionEntry->BeginAddress) || 00704 (ControlPc >= (FunctionEntry->PrologEndAddress & ~3))) { 00705 NOT_IMAGEHLP(*InFunction = TRUE); 00706 Iterator[0].BeginPc = ((FunctionEntry->PrologEndAddress & ~3) - 4); 00707 } else { 00708 NOT_IMAGEHLP(*InFunction = FALSE); 00709 Iterator[0].BeginPc = ControlPc - 4; 00710 } 00711 } 00712 00713 // 00714 // Scan through the given instructions and reload callee registers 00715 // as indicated. 00716 // 00717 NextPc = ContextRecord->Lr - 4; 00718 UnwindGlue: 00719 for (Piterator = Iterator; Piterator >= Iterator; Piterator--) { 00720 for (Pc = Piterator->BeginPc; 00721 Pc != Piterator->EndPc; 00722 Pc += Piterator->Increment) { 00723 00724 READ_ULONG (Pc, I.Long); 00725 Address = IntegerRegister[I.Dform_RA] + I.Dform_D; 00726 Rt = I.Dform_RT; 00727 switch (ClassifyInstruction (&I, Piterator->Intent, 00728 #ifdef _IMAGEHLP_SOURCE_ 00729 hProcess, ReadMemory, FunctionTableAccess, 00730 #endif 00731 Pc, &Info)) { 00732 00733 // 00734 // Move from Link Register (save LR in a GPR) 00735 // 00736 // In the usual case, the link register gets set by a call 00737 // instruction so the PC value should point to the 00738 // instruction that sets the link register. In an interrupt 00739 // or exception frame, the link register and PC value are 00740 // independent. By convention, fake prologues for these 00741 // frames store the link register twice: once to the link 00742 // register location, once to the faulting PC location. 00743 // 00744 // If this is the first time that RA is being restored, 00745 // then set the address of where control left the previous 00746 // frame. Otherwise, this is an interrupt or exception and 00747 // the return PC should be biased by 4 and the link register 00748 // value should be updated. 00749 // 00750 case InstrMFLR: 00751 ContextRecord->Lr = IntegerRegister[Rt]; 00752 if ( RestoredLr == FALSE ) { 00753 NextPc = ContextRecord->Lr - 4; 00754 RestoredLr = TRUE; 00755 } else { 00756 NextPc += 4; 00757 } 00758 continue; // Next PC 00759 00760 // 00761 // Branch to Link Register (forward execution). 00762 // 00763 case InstrBLR: 00764 NextPc = ContextRecord->Lr - 4; 00765 break; // Terminate simulation--start next iterator. 00766 00767 // 00768 // Move from Condition Register (save CR in a GPR) 00769 // 00770 case InstrMFCR: 00771 ContextRecord->Cr = IntegerRegister[Rt]; 00772 continue; // Next PC 00773 00774 // 00775 // Store word (save a GPR) 00776 // 00777 case InstrSTW: 00778 // 00779 // Even though a stw r.sp, xxxx in general is an invalid 00780 // proloque instruction there are places in the kernel 00781 // fake prologues (KiExceptionExit) where we must use this, 00782 // so handle it. 00783 // 00784 READ_ULONG (Address, IntegerRegister[Rt]); 00785 if (ARGUMENT_PRESENT (ContextPointers)) 00786 ContextPointers->IntegerContext[Rt] = (PULONG) Address; 00787 continue; // Next PC 00788 00789 // 00790 // Store word with update, Store word with update indexed 00791 // (buy stack frame, updating stack pointer and link 00792 // cell in storage) 00793 // 00794 case InstrSTWU: 00795 Address = IntegerRegister[GPR1]; 00796 READ_ULONG(Address,IntegerRegister[GPR1]); 00797 if (RestoredSp == FALSE) { 00798 NOT_IMAGEHLP (*EstablisherFrame = 00799 EstablisherFrameValue = ContextRecord->Gpr1); 00800 RestoredSp = TRUE; 00801 } 00802 if (ARGUMENT_PRESENT (ContextPointers)) 00803 ContextPointers->IntegerContext[Rt] = (PULONG) Address; 00804 continue; // Next PC 00805 00806 // 00807 // Store floating point double (save an FPR) 00808 // 00809 case InstrSTFD: 00810 READ_DOUBLE (Address, FloatingRegister[Rt]); 00811 if (ARGUMENT_PRESENT (ContextPointers)) 00812 ContextPointers->FloatingContext[Rt] = (PDOUBLE) Address; 00813 continue; // Next PC 00814 00815 // 00816 // Move register. Certain forms are ignored based on the intent. 00817 // 00818 case InstrMR: 00819 IntegerRegister[I.Xform_RA] = IntegerRegister[Rt]; 00820 continue; // Next PC 00821 case InstrMRfwd: 00822 IntegerRegister[Rt] = IntegerRegister[I.Xform_RA]; 00823 continue; // Next PC 00824 case InstrMRr12: 00825 IntegerRegister[Rt] = IntegerRegister[I.Xform_RA]; 00826 break; // Terminate search--start next iterator. 00827 00828 // 00829 // Add immediate. Certain forms are ignored based on the intent. 00830 // 00831 case InstrADDIfwd: 00832 IntegerRegister[Rt] = Address; 00833 continue; // Next PC 00834 case InstrADDIr12: 00835 if (!ComputedSp) { 00836 // No intervening instruction changes r.1, so compute 00837 // addi r.12,r.1,N instead of addi r.12,r.12,N. 00838 IntegerRegister[Rt] = IntegerRegister[GPR1]; 00839 } 00840 IntegerRegister[Rt] += I.Dform_SI; 00841 break; // Terminate search--start next iterator. 00842 00843 // 00844 // Store with update while searching for the value of r.12 00845 // 00846 case InstrSTWUr12: 00847 ComputedSp = TRUE; 00848 Address = IntegerRegister[GPR1]; 00849 READ_ULONG(Address,IntegerRegister[GPR12]); 00850 continue; // Next PC 00851 00852 // 00853 // A call to a register save millicode. 00854 // 00855 case InstrSaveCode: 00856 // 00857 // Push an iterator to incorporate the actions of the 00858 // millicode. 00859 // 00860 Piterator++; 00861 Piterator->BeginPc = Info.FunctionEntry->EndAddress - 4; 00862 Piterator->EndPc = Info.TargetPc - 4; 00863 Piterator->Increment = -4; 00864 Piterator->Intent = UnwindReverseR12; 00865 // 00866 // Push an iterator to determine the current value of r.12 00867 // 00868 Piterator++; 00869 Piterator->BeginPc = Pc - 4; 00870 Piterator->EndPc = Piterator[-2].EndPc; 00871 Piterator->Increment = -4; 00872 Piterator->Intent = UnwindR12; 00873 ComputedSp = FALSE; 00874 // 00875 // Update the start of the original iterator so it can later 00876 // resume where it left off. 00877 // 00878 Piterator[-2].BeginPc = Pc - 4; 00879 Piterator++; 00880 break; // Start the next iterator. 00881 00882 // 00883 // A branch was encountered in the prologue to a routine 00884 // identified as glue code. This should only happen from 00885 // fake prologues such as those in the system exception 00886 // handler. 00887 // 00888 // We handle it by pushing an iterator to incorporate 00889 // the actions of the glue code prologue. 00890 // 00891 case InstrGlue: 00892 // 00893 // Check that we don't nest too deeply. Verify that 00894 // we can push this iterator and the iterators for a 00895 // glue sequence. There's no need to make this check 00896 // elsewhere because B_OP is only recognized during 00897 // UnwindReverse. Returing zero is the only error action 00898 // we have. 00899 // 00900 if (Piterator - Iterator + 4 00901 > sizeof (Iterator) / sizeof (Iterator[0])) 00902 return 0; 00903 // 00904 // Push an iterator to incorporate the actions of the glue 00905 // code's prologue. Check that we don't nest too deeply. 00906 // Verify that we can push this iterator and the iterators 00907 // for a glue sequence. 00908 // 00909 Piterator++; 00910 Piterator->BeginPc 00911 = (Info.FunctionEntry->PrologEndAddress & ~3) - 4; 00912 Piterator->EndPc = Info.FunctionEntry->BeginAddress - 4; 00913 Piterator->Increment = -4; 00914 Piterator->Intent = UnwindReverse; 00915 // 00916 // Update the start of the original iterator so it can later 00917 // resume where it left off. 00918 // 00919 Piterator[-1].BeginPc = Pc - 4; 00920 Piterator++; 00921 break; // Start the next iterator. 00922 00923 // 00924 // Special "set establisher" instruction (rfi). 00925 // 00926 // Kernel fake prologues that can't use stwu (KiExceptionExit, 00927 // KiAlternateExit) use an rfi instruction to tell the 00928 // unwinder to update the establisher frame pointer using 00929 // the current value of sp. 00930 // 00931 case InstrSetEstablisher: 00932 NOT_IMAGEHLP (*EstablisherFrame = 00933 EstablisherFrameValue = ContextRecord->Gpr1); 00934 continue; // Next PC 00935 00936 // 00937 // None of the above. Just ignore the instruction. It 00938 // is presumed to be non-prologue code that has been 00939 // merged into the prologue for scheduling purposes. It 00940 // may also be improper code in a register save/restore 00941 // millicode routine or unimportant code when 00942 // determining the value of r.12. 00943 // 00944 case InstrIgnore: 00945 default: 00946 continue; // Next PC 00947 } 00948 break; // Start the next iterator. 00949 } // end foreach Pc 00950 } // end foreach Iterator 00951 00952 CheckForGlue: 00953 // 00954 // Check that we aren't at the end of the call chain. We now require 00955 // that the link register at program start-up be zero. Unfortunately, 00956 // this isn't always true. Also verify that the stack pointer remains 00957 // valid. 00958 // 00959 if (NextPc == 0 || NextPc + 4 == 0 00960 #ifdef _IMAGEHLP_SOURCE_ 00961 || NextPc == 1 00962 #else 00963 || EstablisherFrameValue < LowStackLimit 00964 || EstablisherFrameValue > HighStackLimit 00965 || (EstablisherFrameValue & 0x7) != 0 00966 #endif 00967 ) 00968 return NextPc; 00969 00970 // 00971 // Is the instruction at NextPc an branch? 00972 // 00973 #ifdef _IMAGEHLP_SOURCE_ 00974 READ_ULONG (NextPc, I.Long); 00975 #else 00976 if ( !NT_SUCCESS(TryReadUlong(NextPc, &I.Long)) ) { 00977 return NextPc; 00978 } 00979 #endif 00980 if (I.Primary_Op != B_OP) 00981 return NextPc; 00982 00983 // 00984 // Compute branch target address, allowing for branch-relative 00985 // and branch-absolute. 00986 // 00987 Pc = ((LONG)(I.Iform_LI) << 2) + (I.Iform_AA ? 0 : NextPc); 00988 00989 // 00990 // If the branch target is contained in this function table entry, 00991 // either this function is glue or it wasn't called via glue. This 00992 // is the usual case. 00993 // 00994 if (FunctionEntry != NULL 00995 && Pc >= FunctionEntry->BeginAddress 00996 && Pc < FunctionEntry->EndAddress) 00997 return NextPc; 00998 00999 // 01000 // Allow for a stub glue in the thunk and a common ptrgl function 01001 // where the stub glue does not have a function table entry. 01002 // 01003 01004 if ((FunctionEntry = (PRUNTIME_FUNCTION)RtlLookupFunctionEntry(Pc)) != NULL) { 01005 // 01006 // The target instruction must be "lwz r.x,disp(r.2)". 01007 // 01008 READ_ULONG (Pc, I.Long); 01009 if (I.Primary_Op == LWZ_OP && I.Dform_RA == GPR2) { 01010 // 01011 // The next instruction must be "b glue-code". 01012 // 01013 READ_ULONG (Pc + 4, I.Long); 01014 if (I.Primary_Op == B_OP && I.Iform_LK) { 01015 // 01016 // Compute branch target address, allowing for 01017 // branch-relative and branch-absolute. 01018 // 01019 Pc = ((LONG)(I.Iform_LI) << 2) + (I.Iform_AA ? 0 : Pc + 4); 01020 FunctionEntry = (PRUNTIME_FUNCTION)RtlLookupFunctionEntry(Pc); 01021 } 01022 } 01023 } 01024 01025 // 01026 // Determine whether the branch target is glue code. 01027 // 01028 if (!(FunctionEntry != NULL 01029 #ifndef FUNCTION_ENTRY_IS_IMAGE_STYLE 01030 && FunctionEntry->ExceptionHandler == 0 01031 && (ULONG)FunctionEntry->HandlerData == 3 01032 #else 01033 && (FunctionEntry->BeginAddress < 01034 FunctionEntry->PrologEndAddress) 01035 && (FunctionEntry->PrologEndAddress & 3) == 1 01036 #endif 01037 )) 01038 return NextPc; 01039 01040 // 01041 // Unwind the glue code prologue. We won't loop because 01042 // next time through, the branch target will be contained in 01043 // the function table entry. 01044 // 01045 #ifdef _IMAGEHLP_SOURCE_ 01046 SavedFunctionEntry = *FunctionEntry; 01047 FunctionEntry = &SavedFunctionEntry; 01048 #endif 01049 Iterator[0].EndPc = FunctionEntry->BeginAddress - 4; 01050 Iterator[0].Increment = -4; 01051 Iterator[0].Intent = UnwindReverse; 01052 Iterator[0].BeginPc = ((FunctionEntry->PrologEndAddress & ~3) - 4); 01053 goto UnwindGlue; 01054 }

NTSTATUS TryReadUlong IN ULONG  NextPc,
OUT PULONG  Value
[static]
 

Definition at line 165 of file ppc/vunwind.c.

References EXCEPTION_EXECUTE_HANDLER, and READ_ULONG.

Referenced by RtlVirtualUnwind().

00167 { 00168 try { 00169 READ_ULONG (NextPc, *Value); 00170 } except (EXCEPTION_EXECUTE_HANDLER) { 00171 return GetExceptionCode(); 00172 } 00173 return STATUS_SUCCESS; 00174 }


Generated on Sat May 15 19:46:08 2004 for test by doxygen 1.3.7