; Listing7-6.asm
;
; A program that demonstrates various
; forms of the try..endtry sequences.


            option     casemap:none
            .nolist
            include    aoalib.inc
            include    aoaMacros.inc
            include    aoaExcepts.inc
            includelib aoalib.lib
            .list
            
            .const

; Program title:

             align  word
ttlStr       byte   "Listing 7-6", 0


;----------------------------------------------------------

            .code

; tstSeq-
;
;   Tests sequential try...endtry sequences
      
tstSeq      xproc   (filterProc(tstSeq), <rbx>)
            
            local   shadowStorage[56]:byte
            
            call    print
            byte    "tstSeq", nl, 0

; Note the use of a non-volatile register here.
; This ensures that EBX's value will be preserved
; should an exception occur. Note that the tstSeq
; procedure preserves RBX (see xproc, above).
; Therefore, stack unwinding will automatically
; restore RBX's value after an exception.
;
; The following code loops through the try sequence
; four times. Three of those times generate different
; exceptions, the fourth time does not generate an
; exception.

            mov     ebx, 0
repeatTry:
            try     

                cmp     ebx, 0
                ja      try1
                
                call    print
                byte    "tstSeq: int 3 is next instr", nl, 0

                int     3           ;Breakpoint exception
                
try1:           cmp     ebx, 1
                ja      try2
                call    print
                byte    "tstSeq: hlt is next instr", nl, 0

                hlt                 ;Privledged Instr

try2:           cmp     ebx, 2
                ja      try3

                call    print
                byte    "tstSeq: memAccess on next instr", nl, 0

                xor     rax, rax
                mov     rax, [rax]  ;Mem Access
                
try3:
                call    print
                byte    "tstSeq:End of protected section", nl, 0

            exception( ex(brkpt), ex(memAccess), ex(privInstr) )

                mov     edx, [rax].ExceptionRecord_t.ExceptionCode
                call    print
                byte    "tstSeq:Brkpt/access/priv exception"
                byte    nl
                byte    "Exception code:%x", nl, 0

            exception(ex(any))

                call    print
                byte    "tstSeq:Any exception 1", nl, 0

            finally
                call    print
                byte    "tstSeq:In finally #1", nl, 0

            endtry
            inc     ebx
            cmp     ebx, 4
            jb      repeatTry
            
            call    print
            byte    "tstSeq:After first try..endtry", nl, 0
           
            try
            
                int 3   
                      
            exception(ex(any))

                call    print
                byte    "tstSeq:Any exception #2", nl, 0
            
            finally ;#2
    
                call    print
                byte    "tstSeq:In finally 2", nl, 0
            
            endtry
            call    print
            byte    "tstSeq:After 2nd try..endtry", nl, 0
            
; Generate the epilog code (including ret) and end
; the procedure:

tstSeq      endxp()


;------------------------------------------------
;        
; tstNested-
;
;   Tests nested try...endtry sequences
      
tstNested   xproc   (filterProc(tstNested), <>)
            
            local   shadowStorage[56]:byte
            
            call    print
            byte    "tstNested", nl, 0
            try

                try     

                    call    print
                    byte    "startTry: int 3 is next instr", nl, 0
                    
                    int        3       ;Cause an exception
                    
                    call    print
                    byte    "This should not print", nl, 0
            
                exception(ex(brkpt))
            
                    call    print
                    byte    "Brkpt exception", nl, 0
                    
                exception(ex(any))
            
                    call    print
                    byte    "Any exception 1", nl, 0
                    
                finally
                    call    print
                    byte    "In finally #1", nl, 0
            
                endtry
                call    print
                byte    "After first endtry", nl, 0
                    
            exception(ex(any))

                call    print
                byte    "Any exception #2", nl, 0
            
            finally ;#2
    
                call    print
                byte    "In finally 2", nl, 0
            
            endtry
            call    print
            byte    "After 2nd endtry", nl, 0
            
; Generate the epilog code (including ret) and end
; the procedure:

tstNested   endxp()


        
;--------------------------------------------------
;
; excInExc-
;
;   Tests a try..endtry sequence in an exception section
      
excInExc   xproc   (filterProc(excInExc), <>)
            
            local   shadowStorage[56]:byte
            
            call    print
            byte    "excInExc", nl, 0
            try

                int  3
                    
            exception(ex(any))

                call    print
                byte    "excInExc: exception 1", nl, 0
                try
                
                    xor rax, rax    ;Cause memory access
                    mov rax, [rax]  ; exception
                    
                exception( ex(any) )
                
                    call print
                    byte "excInExc:Exception 2", nl, 0
                    
                endtry
            
            finally
    
                call    print
                byte    "excInExc:In finally 1", nl, 0
            
            endtry
            call    print
            byte    "excInExc:After outer endtry", nl, 0
            
; Generate the epilog code (including ret) and end
; the procedure:

excInExc   endxp()


        
;--------------------------------------------------
;
; Called-
;
;   Tests a try..endtry sequence in a procedure
; that calls another procedure (that generates
; the exception).
      
Called      xproc   (filterProc(Called), <>)
            
            local   shadowStorage[56]:byte
            
            call    print
            byte    "Called", nl, 0
            try

                call   exInProc
                    
            exception(ex(any))

                call    print
                byte    "Called: exception", nl, 0
            
            finally
    
                call    print
                byte    "Called:In finally", nl, 0
            
            endtry
            call    print
            byte    "Called:After outer endtry", nl, 0
            
; Generate the epilog code (including ret) and end
; the procedure:

Called      endxp()

exInProc    xproc   (frame,<>)
            int     3
exInProc    endxp()


        
;--------------------------------------------------
;
; finallyAfter-
;
;   Demonstrates how to execute finally code after
; an exception handler.
      
finallyAfter xproc   (filterProc(finallyAfter), <>)
            
            local   shadowStorage[56]:byte
            
            call    print
            byte    "finallyAfter", nl, 0
            try
            
                try

                    int 3
                    
                exception(ex(brkpt))

                    call    print
                    byte    "finallyAfter: exception", nl, 0
                    
                endtry
            
            finally
    
                call    print
                byte    "finallyAfter:In finally", nl, 0
            
            endtry
            call    print
            byte    "finallyAfter:After outer endtry", nl, 0
            
; Generate the epilog code (including ret) and end
; the procedure:

finallyAfter endxp()



        
;--------------------------------------------------
;
; Here is the main assembly language function.

            
            public  asmMain
            
            align       8
            qword       ?   ;Also for hot patching

; For the main assembly procedure, preserve all the 
; non-volatile registers. It would be cool to save  
; the XMM non-volatile registers, too, but there isn't 
; room in the prolog for them.
; 
; Had this code used a biased frame pointer (RBP) value, 
; it could have gotten away with saving them. Epilog 
; and prolog  macros don't allow that, however. So this 
; code preserves what it can (the general-purpose 64-bit 
; non-volatile registers).
            

asmMain     xproc   (frame, <rbx, rsi, rdi, r12, r13, r14, r15>)
            local       shadowStorage[64]:byte
            

; Test sequential exceptions:

            call    print
            byte    "Calling tstSeq", nl, 0

            call    tstSeq
            
            call    print
            byte    "Back from tstSeq", nl, 0
            
; Test nested exceptions:

            call    print
            byte    "Calling tstNested", nl, 0

            call    tstNested
            
            call    print
            byte    "Back from tstNested", nl, 0
            
; Call the procedure that has nested exceptions:
            
            call    print
            byte    "Calling excInExc", nl, 0
            call    excInExc
            call    print
            byte    "Back from excInExc", nl, 0
            
; Call the procedure that raises an exception
; in a called procedure:

            call    print
            byte    "Calling Called", nl, 0
            call    Called
            call    print
            byte    "Back from Called", nl, 0
            
; Call the procedure that raises an exception
; in a called procedure:

            call    print
            byte    "Calling finallyAfter", nl, 0
            call    finallyAfter
            call    print
            byte    "Back from finallyAfter", nl, 0
            
            
asmMain     endxp()
            end
