⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 vunwind.c

📁 windows ce 3.00 嵌入式操作系统源代码
💻 C
📖 第 1 页 / 共 2 页
字号:
        specified function or NULL if the function is a leaf function.

    ContextRecord - Supplies the address of a context record.

    InFunction - Supplies a pointer to a variable that receives whether the
        control PC is within the current function.

    EstablisherFrame - Supplies a pointer to a variable that receives the
        the establisher frame pointer value.

Return Value:
    The address where control left the previous frame is returned as the
    function value.

 --*/
{
    ITERATOR Iterator[8];
    PITERATOR Piterator;
    ULONG Address;
    PDOUBLE FloatingRegister;
    PPC_INSTRUCTION I;
    PULONG IntegerRegister;
    ULONG NextPc, Pc;
    BOOLEAN RestoredLr = FALSE;
    BOOLEAN RestoredSp = FALSE;
    BOOLEAN ComputedSp = FALSE;
    ULONG Rt;
    MILLICODE_INFO Info;
    INSTR_CLASS InstrClass;
    ULONG EstablisherFrameValue;

	//
    // Set the base address of the integer and floating register arrays.
    //

    FloatingRegister = &ContextRecord->Fpr0;
    IntegerRegister = &ContextRecord->Gpr0;

    //
    // If the function is a leaf function, perform the default unwinding
    // action and check to see if the function was called via glue.
    //
    if (FunctionEntry == NULL) {
        //
        // Set point at which control left the previous routine.
        //

        return( ContextRecord->Lr - 4 );
    }
    //
    // Set initial values for EstablisherFrame and Offset.
    // (this may need more careful planning IBMPLJ).
    //

    NOT_IMAGEHLP (*EstablisherFrame =
                  EstablisherFrameValue = ContextRecord->Gpr1);

    READ_ULONG (ControlPc, I.Long);
    if (I.Long == RETURN_INSTR) {
        //
        // If the instruction at the point where control left the specified
        // function is a return, then any saved registers have been restored
        // and the control PC is not considered to be in the function
        // (i.e., in an epilogue).
        //
        NOT_IMAGEHLP(*InFunction = FALSE);
        return( ContextRecord->Lr );
    }
    InstrClass = ClassifyInstruction(&I, UnwindReverse, ControlPc, &Info);
    if (InstrClass == InstrRestoreCode) {
        //
        // If the instruction at the point where control left the
        // specified function is a branch to register restore
        // millicode, the state is restored by simulating the
        // execution of the restore millicode.  The control PC is in
        // an epilogue.
        //
        Iterator[0].BeginPc = Info.TargetPc;
        Iterator[0].EndPc = Info.FunctionEntry->EndAddress;
        Iterator[0].Increment = 4;
        Iterator[0].Intent = UnwindForward;
        NOT_IMAGEHLP(*InFunction = FALSE);

    } else if (FunctionEntry->ExceptionHandler == 0 &&
               (ULONG)FunctionEntry->HandlerData == 2) {
        //
        // If the address is in register restore millicode, the state
        // is restored by completing the execution of the restore
        // millicode.  The control PC is in an epilogue.
        //
        Iterator[0].BeginPc = ControlPc;
        Iterator[0].EndPc = FunctionEntry->EndAddress;
        Iterator[0].Increment = 4;
        Iterator[0].Intent = UnwindForward;
        NOT_IMAGEHLP(*InFunction = FALSE);

    } else {

        //
        // If the address where control left the specified function is
        // outside the limits of the prologue, then the control PC is
        // considered to be within the function and the control
        // address is set to the end of the prologue. Otherwise, the
        // control PC is not considered to be within the function
        // (i.e., in the prologue).
        //
        Iterator[0].EndPc = FunctionEntry->BeginAddress - 4;
        Iterator[0].Increment = -4;
        Iterator[0].Intent = UnwindReverse;
        if (ControlPc < FunctionEntry->BeginAddress
                || ControlPc >= (FunctionEntry->PrologEndAddress & ~3)) {
            NOT_IMAGEHLP(*InFunction = TRUE);
            Iterator[0].BeginPc = ((FunctionEntry->PrologEndAddress & ~3) - 4);
        } else {
            NOT_IMAGEHLP(*InFunction = FALSE);
            Iterator[0].BeginPc = ControlPc - 4;
        }
    }

    //
    // Scan through the given instructions and reload callee registers
    // as indicated.
    //
    NextPc = ContextRecord->Lr - 4;
    for (Piterator = Iterator; Piterator >= Iterator; Piterator--) {

        for (Pc = Piterator->BeginPc;
             Pc != Piterator->EndPc;
             Pc += Piterator->Increment) {

            READ_ULONG (Pc, I.Long);
            Address = IntegerRegister[I.Dform_RA] + I.Dform_D;
            Rt = I.Dform_RT;
            switch (ClassifyInstruction (&I, Piterator->Intent, Pc, &Info)) {

              //
              // Move from Link Register (save LR in a GPR)
              //
              // In the usual case, the link register gets set by a call
              // instruction so the PC value should point to the
              // instruction that sets the link register.  In an interrupt
              // or exception frame, the link register and PC value are
              // independent.  By convention, fake prologues for these
              // frames store the link register twice: once to the link
              // register location, once to the faulting PC location.
              //
              // If this is the first time that RA is being restored,
              // then set the address of where control left the previous
              // frame. Otherwise, this is an interrupt or exception and
              // the return PC should be biased by 4 and the link register
              // value should be updated.
              //
              case InstrMFLR:

                ContextRecord->Lr = IntegerRegister[Rt];
                if ( RestoredLr == FALSE ) {
                    NextPc = ContextRecord->Lr - 4;
                    RestoredLr = TRUE;
                } else {
                    NextPc += 4;
                }
                continue; // Next PC

              //
              // Branch to Link Register (forward execution).
              //
              case InstrBLR:
                NextPc = ContextRecord->Lr - 4;
                break; // Terminate simulation--start next iterator.

              //
              // Move from Condition Register (save CR in a GPR)
              //
              case InstrMFCR:
                ContextRecord->Cr = IntegerRegister[Rt];
                continue; // Next PC

              //
              // Store word (save a GPR)
              //
              case InstrSTW:
              //
              // Even though a stw  r.sp, xxxx in general is an invalid
              // proloque instruction there are places in the kernel
              // fake prologues (KiExceptionExit) where we must use this,
              // so handle it.
              //
				READ_ULONG (Address, IntegerRegister[Rt]);
				// Check for an SP update
				if ( Rt == GPR1 )
					RestoredSp = TRUE;
                continue; // Next PC

              //
              // Store word with update, Store word with update indexed
              // (buy stack frame, updating stack pointer and link
              // cell in storage)
              //
              case InstrSTWU:
				// STWU should only be used for updating SP
				DEBUGCHK(I.Dform_RT == GPR1);
				DEBUGCHK(I.Dform_RA == GPR1);
				  
				// Do not update SP twice.  CaptureContext is an example of 
				// a prolog where only the last sp update (the first one the 
				// unwinder encounters) should be unwound.
				if ( RestoredSp == FALSE )
				{
					Address = IntegerRegister[GPR1];
					READ_ULONG(Address,IntegerRegister[GPR1]);
					
                    *EstablisherFrame = ContextRecord->Gpr1;
					EstablisherFrameValue = ContextRecord->Gpr1;
                    RestoredSp = TRUE;
				}
                continue; // Next PC

              //
              // Store floating point double (save an FPR)
              //
              case InstrSTFD:
                READ_DOUBLE (Address, FloatingRegister[Rt]);
                continue; // Next PC

              //
              // Move register.  Certain forms are ignored based on the intent.
              //
              case InstrMR:
                IntegerRegister[Rt] = IntegerRegister[I.Xform_RA];
                continue; // Next PC
              case InstrMRfwd:
                IntegerRegister[I.Xform_RA] = IntegerRegister[Rt];
                continue; // Next PC

              //
              // Add immediate.  Certain forms are ignored based on the intent.
              //
              case InstrADDIfwd:
                IntegerRegister[Rt] = Address;
                continue; // Next PC
              case InstrADDIr12:
                if (!ComputedSp) {
                  // No intervening instruction changes r.1, so compute
                  // addi r.12,r.1,N instead of addi r.12,r.12,N.
                  IntegerRegister[Rt] = IntegerRegister[GPR1];
                }
                IntegerRegister[Rt] += I.Dform_SI;
                break; // Terminate search--start next iterator.

              //
              // Store with update while searching for the value of r.12
              //
              case InstrSTWUr12:
                ComputedSp = TRUE;
                Address = IntegerRegister[GPR1];
                READ_ULONG(Address,IntegerRegister[GPR12]);
                continue; // Next PC

              //
              // A call to a register save millicode.
              //
              case InstrSaveCode:

                //
                // Push an iterator to incorporate the actions of the
                // millicode.
                //
                Piterator++;
                Piterator->BeginPc = Info.FunctionEntry->EndAddress - 4;
                Piterator->EndPc = Info.TargetPc - 4;
                Piterator->Increment = -4;
                Piterator->Intent = UnwindReverseR12;
                //
                // Push an iterator to determine the current value of r.12
                //
                Piterator++;
                Piterator->BeginPc = Pc - 4;
                Piterator->EndPc = Piterator[-2].EndPc;
                Piterator->Increment = -4;
                Piterator->Intent = UnwindR12;
                ComputedSp = FALSE;
                //
                // Update the start of the original iterator so it can later
                // resume where it left off.
                //
                Piterator[-2].BeginPc = Pc - 4;
                Piterator++;
                break; // Start the next iterator.

              //
              // A branch was encountered in the prologue to a routine
              // identified as glue code.  This should only happen from
              // fake prologues such as those in the system exception
              // handler.
              //
              // We handle it by pushing an iterator to incorporate
              // the actions of the glue code prologue.
              //
             case InstrGlue:
                //
                // Check that we don't nest too deeply.  Verify that
                // we can push this iterator and the iterators for a
                // glue sequence.  There's no need to make this check
                // elsewhere because B_OP is only recognized during
                // UnwindReverse.  Returing zero is the only error action
                // we have.
                //

                if (Piterator - Iterator + 4
                    > sizeof (Iterator) / sizeof (Iterator[0]))
                    return 0;
                //
                // Push an iterator to incorporate the actions of the glue
                // code's prologue.  Check that we don't nest too deeply.
                // Verify that we can push this iterator and the iterators
                // for a glue sequence.
                //
                Piterator++;
                Piterator->BeginPc
                  = (Info.FunctionEntry->PrologEndAddress & ~3) - 4;
                Piterator->EndPc = Info.FunctionEntry->BeginAddress - 4;
                Piterator->Increment = -4;
                Piterator->Intent = UnwindReverse;
                //
                // Update the start of the original iterator so it can later
                // resume where it left off.
                //
                Piterator[-1].BeginPc = Pc - 4;
                Piterator++;
                break; // Start the next iterator.

              //
              // Special "set establisher" instruction (rfi).
              //
              // Kernel fake prologues that can't use stwu (KiExceptionExit,
              // KiAlternateExit) use an rfi instruction to tell the
              // unwinder to update the establisher frame pointer using
              // the current value of sp.
              //
              case InstrSetEstablisher:
                NOT_IMAGEHLP (*EstablisherFrame =
                                  EstablisherFrameValue = ContextRecord->Gpr1);
                continue; // Next PC

              //
              // None of the above.  Just ignore the instruction.  It
              // is presumed to be non-prologue code that has been
              // merged into the prologue for scheduling purposes.  It
              // may also be improper code in a register save/restore
              // millicode routine or unimportant code when
              // determining the value of r.12.
              //
              case InstrIgnore:
              default:
                continue; // Next PC
            }
            break; // Start the next iterator.
        } // end foreach Pc
    } // end foreach Iterator

    return NextPc;
}

#undef NOT_IMAGEHLP

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -