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
01581
01582
RtlGetUnwindFunctionEntry( ControlPc, FunctionEntry, &UnwindFunctionEntry, &StackAdjust, &FixedReturn );
01583
01584
#if DBG
01585
ShowRuntimeFunction(&UnwindFunctionEntry,
"RtlVirtualUnwind: unwind function entry" );
01586
#endif
01587
01588
01589
01590
01591
01592 IntegerRegister = &ContextRecord->IntV0;
01593 FloatingRegister = &ContextRecord->FltF0;
01594
01595
01596
01597
01598
01599
01600
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
01610
01611
01612
01613
01614
01615
01616
01617
01618
01619
01620
01621
01622
01623
01624
01625
01626
01627
01628
01629
01630
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
01643
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
01653
01654
01655
01656
01657
01658
01659
01660
01661
01662
01663
01664
01665
01666
01667
01668
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
01682
01683
01684
01685
01686
01687
01688
01689
01690
01691
01692
01693
01694
01695
01696
01697
01698
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
01716
01717
01718
01719
01720
01721
01722
01723
01724
01725
01726
01727
01728
01729
01730
01731
01732
01733
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
01749
01750
01751
01752
01753
01754
01755
01756
01757
01758 EstablisherFrame->Real = (ULONG_PTR)ContextRecord->IntSp;
01759 EstablisherFrame->Virtual = (ULONG_PTR)ContextRecord->IntSp;
01760
01761
01762
01763
01764
01765
01766
01767
01768
01769
01770
01771
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
01785
01786
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
01797
01798
01799
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
01814
01815
01816
01817
01818
01819
switch (Opcode) {
01820
01821
case STQ_OP :
01822
01823
01824
01825
01826
01827
01828
01829
01830
01831
01832
01833
01834
if ((Rb == SP_REG) && (Ra != ZERO_REG)) {
01835
01836
01837
01838
01839
01840
01841 Address = Offset16 + (LONG_PTR)ContextRecord->IntSp;
01842 IntegerRegister[Ra] = *((PULONGLONG)Address);
01843
01844
01845
01846
01847
01848
01849
01850
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
01865
01866
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
01877
01878
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
01895
01896
01897
01898
01899
01900
01901
01902
01903
01904
01905
if (Ra == SP_REG) {
01906
if (Rb == SP_REG) {
01907
01908
01909
01910
01911
01912
01913
01914
01915
01916
01917
01918
01919
01920
01921
01922
01923
01924 FrameSize = -Offset16;
01925
goto StackAllocation;
01926
01927 }
else {
01928
01929
01930
01931
01932
01933
01934
01935
01936
01937
01938
01939
01940
01941
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
01954
01955
01956
01957
01958
01959
01960
01961
01962
01963
01964
01965
01966
01967
01968 DecrementOffset += Offset16;
01969
_RtlpDebugDisassemble(ControlPc, ContextRecord);
01970
01971 }
else if (Rb == ZERO_REG) {
01972
01973
01974
01975
01976
01977
01978
01979
01980
01981
01982
01983
01984
01985
01986
01987
01988
01989
01990
01991
01992
01993 FrameSize = (Offset16 + DecrementOffset);
01994
goto StackAllocation;
01995
01996 }
else if (Rb == SP_REG) {
01997
01998
01999
02000
02001
02002
02003
02004
02005
02006
02007
02008
02009
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
02025
02026
02027
02028
02029
02030
02031
02032
02033
02034
02035
02036
02037
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
02050
02051
02052
02053
02054
02055
02056
02057
02058
02059
02060
02061
02062
02063
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
02078
02079
02080
02081
02082
02083
if ((Function == BIS_FUNC) && (Rc != ZERO_REG)) {
02084
if (Instruction.OpReg.RbvType == RBV_REGISTER_FORMAT) {
02085
02086
02087
02088
02089
02090
02091
02092
02093
02094
02095
02096
02097
02098
02099
02100
02101
02102
02103
02104
02105
02106
if (Ra == ZERO_REG) {
02107
02108
02109
02110
02111
02112 Ra = Rb;
02113
02114 }
else if (Rb == ZERO_REG) {
02115
02116
02117
02118
02119
02120 Rb = Ra;
02121 }
02122
02123
if ((Ra == Rb) && (Ra != ZERO_REG)) {
02124 IntegerRegister[Ra] = IntegerRegister[Rc];
02125
02126
02127
02128
02129
02130
02131
02132
02133
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
02148
02149
02150
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
02166
02167
02168
02169
02170
02171
02172
02173
02174
02175
02176
02177
02178
02179
02180
02181
if ((Ra == ZERO_REG) && (Rc == DecrementRegister)) {
02182 FrameSize = Literal8;
02183 StackAllocation:
02184
02185
02186
02187
02188
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
02204
02205
02206
02207
02208
02209
02210
02211
02212
02213
if ((Rb == SP_REG) && (Ra != FZERO_REG)) {
02214
02215
02216
02217
02218
02219
02220 Address = Offset16 + (LONG_PTR)ContextRecord->IntSp;
02221 FloatingRegister[Ra] = *((PULONGLONG)Address);
02222
02223
02224
02225
02226
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
02240
02241
02242
02243
if (Instruction.FpOp.Function == CPYS_FUNC) {
02244
02245
02246
02247
02248
02249
02250
02251
02252
02253
02254
02255
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
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 }