I think what you are looking for is something like setjump() and longjump() in C.
Here is an example:
Code: Select all
; =======================================================================
Structure JumpData
EAX.l
ECX.l
EDX.l
EBX.l
ESP.l
EBP.l
ESI.l
EDI.l
ReturnAddr.l
EndStructure
DisableDebugger
; Stores the current program state in *mark, making it a possible target for a jump
; The procedure returns normally when the jump is set up, and when LongJump() is called,
; the program execution will again return from this procedure and continue there.
;
; Returnvalue:
; - 0 when called to setup a jump target
; - 'ReturnValue' from LongJump() after a jump was made back to this location
;
Procedure SetJump(*mark.JumpData)
!mov eax, [p.p_mark]
!pop dword [eax+32]
!add esp, 4
!mov [eax], dword 0
!mov [eax+4], ecx
!mov [eax+8], edx
!mov [eax+12], ebx
!mov [eax+16], esp
!mov [eax+20], ebp
!mov [eax+24], esi
!mov [eax+28], edi
LongJump_Target:
!mov edi, [eax+28]
!mov esi, [eax+24]
!mov ebp, [eax+20]
!mov esp, [eax+16]
!mov ebx, [eax+12]
!mov edx, [eax+8]
!mov ecx, [eax+4]
!push dword [eax+32]
!mov eax, [eax]
!ret
EndProcedure
; Jumps back to the given *mark. SetJump() will return on the old location with
; the specified 'ReturnValue'.
; The LongJump() procedure never returns to where it was called from.
;
; Note: You can only jump out of procedures, not into them. So when SetJump()
; is called inside a procedure, you can only jump back to it while the execution
; has not yet left that procedure (as its stack frame is then destroyed, making it invalid to jump to)
;
Procedure LongJump(*mark.JumpData, ReturnValue.l)
*mark\EAX = ReturnValue
!mov eax, [p.p_mark]
!jmp l_longjump_target
EndProcedure
EnableDebugger
; =======================================================================
; Example:
; =======================================================================
Global jump.JumpData
Procedure Processing(value)
Debug "entering procedure: " + Str(value)
If value = 10
LongJump(@jump, 1)
ElseIf Value = 20
LongJump(@jump, 2)
Else
Processing(value+1)
EndIf
Debug "leaving procedure: " + Str(value)
EndProcedure
; Set up the jump position. In this example, the execution will return
; 3 times from this position. First normally, and then each time the LongJump()
; is called
;
Select SetJump(@jump)
Case 0: Debug "jump mark set"
Processing(0) ; start our procedure
Case 1: Debug "error 1"
Debug "trying again from 11"
Processing(11) ; start the processing again
Case 2: Debug "error 2"
; ...
EndSelect
Debug "program end"
End
Notes:
- The CallStack display of the Debugger will be wrong when you call this, as the debugger does not notice
that the procedures returned. (because technically they didn't)
- This of course does not take care of any allocated memory. (also not local String variables, LinkedLists and Arrays)
So when using this, you have to handle these things in a different way, or you will get a memory leak.
(Use global/static variables, or allocate memory blocks for them that you register somewhere so you
can correctly free them all after a LongJump)
It is not a perfect solution, as it requires extra work to get right, but it works.