Retired Document
Important: This sample code may not represent best practices for current development. The project may use deprecated symbols and illustrate technologies and techniques that are no longer recommended.
UFailure.a
; |
; Apple Macintosh Developer Technical Support |
; |
; Exception handling for MPW Pascal, MacApp and MPW C |
; |
; UFailure (aka Signals) - ÒExceptional code, with a few exceptions.Ó |
; |
; UFailure.a - Assembly Source |
; |
; Copyright © 1985-1988 Apple Computer, Inc. |
; All rights reserved. |
; |
; Versions: 1.0 11/88 |
; |
; Components: UFailure.p November 1, 1988 |
; UFailure.h November 1, 1988 |
; UFailure.inc1.p November 1, 1988 |
; UFailure.a November 1, 1988 |
; TestCignal.c November 1, 1988 |
; TestCignal.make November 1, 1988 |
; TestSignal.p November 1, 1988 |
; TestSignal.make November 1, 1988 |
; |
; UFailure (or Signals) is a set of exception handling routines suitable for |
; use with MacApp, MPW C, and MPW Pascal. It is a jazzed-up version of the MacApp |
; UFailure unit. There is a set of C interfaces to it as well. |
; |
PRINT OFF |
INCLUDE 'Traps.a' |
PRINT ON |
STRING ASIS |
;============================================================================================= |
GblA &UsingMacApp |
If &TYPE('&Debugging') = 'UNDEFINED' Then |
GblA &Debugging |
&UsingMacApp SetA 0 ; we assume weÕre MacAppless if &Debugging isnÕt defined |
If &TYPE('&Debug') = 'UNDEFINED' Then |
&Debugging SetA 0 ; default to debugging off |
Else |
&Debugging SetA &Debug ; use the makefile definition of &Debug |
EndIf |
Else |
&UsingMacApp SetA 1 ; we assume we have MA if &Debugging is defined |
EndIf |
;============================================================================================= |
If &TYPE('Head') = 'UNDEFINED' Then |
Macro |
Head |
GblA &Debugging |
If &Debugging Then |
Link A6,#0 ; These two instructions form a slow no-op |
Move.L (SP)+,A6 |
EndIf |
EndM |
EndIf |
;============================================================================================= |
If &TYPE('Tail') = 'UNDEFINED' Then |
Macro |
Tail |
GblA &Debugging |
If &Debugging Then |
Unlk A6 |
Rts |
DC.B &Ord(&SubStr(&Syslst[1],2,1)) + $80 |
DC.B '&SubStr(&Syslst[1],3,7)' |
EndIf |
EndM |
EndIf |
;============================================================================================= |
; the following constant sets the limit on the depth of nested CatchSignals |
SigBlockSize EQU 8 ;number of elements in block |
CatchSigErr EQU 200 ;"insufficient heap" message |
SigElSize EQU 72 ;byte size of FailInfo record |
FrameRet EQU 4 ;return addr. for frame (off A6) |
SigBigA6 EQU $FFFFFFFF ;A6 at outer level (for Pascal) |
nSavedRegs EQU 11 ;number of registers saved in FailInfo record |
; offsets into the FailInfo record (see UFailure.p) |
SigA6 EQU 36 |
SigSP EQU 40 |
SigCode EQU 44 |
SigMessage EQU 46 |
SigFailA6 EQU 50 |
SigFailPC EQU 54 |
whatSignals EQU 66 |
SigFRet EQU 68 |
; The global data used by these routines follows. It is in the form of a |
; RECORD, but, unlike above, no origin is specified, which means that memory |
; space *will* be allocated. |
; This data is referenced through a WITH statement at the beginning of the |
; procs that need to get at this data. Since the Assembler knows when it is |
; referencing data in a data module (since they must be declared before they |
; are accessed), and since such data can only be accessed based on A5, there |
; is no need to explicitly specify A5 in any code which references the data |
; (unless indexing is used). Thus, in this program we have omitted all A5 |
; references when referencing the data. |
SigGlobals RECORD ;no origin means this is a data record |
;not a template(as above) |
SigEnd DS.L 1 ;current end of table |
SigNow DS.L 1 ;the current offset |
SigPointer DC.L 0 ;the handle := 0 initially |
ENDR |
If &UsingMacApp Then |
Seg 'MAInit' |
EndIf |
InitSignals PROC EXPORT ;PROCEDURE InitSignals; |
EXPORT InitUFailure |
IMPORT gTopHandler:Data |
IMPORT gInitHandler:Data |
If &UsingMacApp And &Debugging Then |
IMPORT gAskAboutAlloc:Data |
IMPORT gAskFailure:Data |
EndIf |
WITH SigGlobals |
;the above statement makes the template SigElement and the global data |
;record SigGlobals available to this procedure |
Head |
MOVE.L #SigBigA6,A6 ;make A6 valid for Signal |
InitUFailure ;PROCEDURE InitUFailure; |
CLR.L gTopHandler(A5) ;nothing in the list |
CLR.L gInitHandler(A5) ;MA has another list during initialization |
If &UsingMacApp And &Debugging Then |
CLR.B gAskAboutAlloc(A5) ;set the MA debugging guys to FALSE |
CLR.B gAskFailure(A5) |
EndIf |
MOVE.L #SigBlockSize*SigElSize,D0 |
_NewPtr ;try to get a table |
BNE.S forgetit ;we couldn't get that!? |
MOVE.L A0,SigPointer ;save it |
MOVE.L #-SigElSize,SigNow ;point "now" before start |
MOVE.L #SigBlockSize*SigElSize,SigEnd ;save the end |
forgetit RTS |
Tail 'INITUFAI' |
ENDP |
If &UsingMacApp Then |
Seg 'MAMain' |
EndIf |
CatchCFailures PROC EXPORT ;pascal void CatchCFailures(FailInfo &fi, HandlerFuncPtr handler); |
IMPORT FailCEntry |
Head |
MOVE.L (A7)+,D2 ;save return address |
MOVEQ #0,D1 ;CatchCFailures used (no A6 link, uses handler proc.) |
BRA.S FailCEntry ;finish from CatchFailures |
Tail 'CATCHCFA' |
CatchFailures PROC EXPORT ;PROCEDURE CatchFailures(VAR fi: FailInfo; |
; PROCEDURE Handler(code: INTEGER; message: LONGINT)); |
IMPORT FailuresEntry |
EXPORT FailCEntry |
WITH SigGlobals |
Head |
MOVE.L (A7)+,D2 ;save return address |
ADDQ #4,A7 ;discard A6 link |
MOVEQ #-1,D1 ;CatchFailures used (maybe A6 link???, handler proc.) |
FailCEntry |
MOVE.L (A7)+,A1 ;get handler address |
MOVE.L (A7)+,A0 ;FailInfo record address |
BRA.S FailuresEntry ;enter CatchSignal with D2, A0, A1 set |
Tail 'CATCHFAI' |
CatchSignal PROC EXPORT ;FUNCTION CatchSignal:INTEGER |
IMPORT SiggyPop2,Signal,SigDeath |
IMPORT gTopHandler:Data |
EXPORT FailuresEntry |
WITH SigGlobals |
Head |
MOVE.L (A7)+,A1 ;grab return address for ÒhandlerÓ address |
MOVE.L A1,D2 ;save return address |
MOVEQ #1,D1 ;CatchSignals used; no A6 link needed on stack, no proc. |
CLR.W (A7) ;no error code (before its time) |
MOVE.L SigPointer,D0 ;point to table |
BEQ SigDeath |
MOVE.L D0,A0 |
MOVE.L SigNow,D0 |
ADD.L #SigElSize,D0 |
MOVE.L D0,SigNow ;save new position |
CMP.L SigEnd,D0 ;have we reached the end? |
BNE.S catchit ;no, proceed |
;signals, we use 'em ourselves |
MOVE.L SigNow,SigEnd ;restore old ending offset |
MOVE.L #SigElSize,D0 |
SUB.L D0,SigNow ;ditto for current position |
MOVE.W #CatchSigErr,4(A7) ;we'll signal a "couldn't |
; catch" error |
JSR Signal ;never returns of course |
catchit |
ADD.L D0,A0 ;point to new entry |
FailuresEntry ;A0=pointer to FailInfo block,A1=handler address, |
; D1=flag showing how we entered, D2=return address |
MOVE.L A0,D0 ;save FailInfo record address |
MOVE.W D1,whatSignals(A0) ;remember whatÕs catching (-1=CatchFailures, |
; 0=CatchCFailures, 1=CatchSignal) |
BLE.S @1 ;canÕt use frame to clean up if theyÕll call Success |
CMP.L #SigBigA6,A6 ;are we at the outer level? |
BEQ.S @1 ;yes, no frame, no cleanup needed |
MOVE.L FrameRet(A6),SigFRet(A0) ;save old frame return |
; address |
LEA SiggyPop,A0 |
MOVE.L A0,FrameRet(A6) ;set cleanup code address |
MOVE.L D0,A0 ;restore FailInfo record address |
@1 |
MOVEM.L A2-A7/D3-D7,(A0) ;save all registers first (note that the saved |
; stack points to the function result for CatchSignal) |
ADD #nSavedRegs*4,A0 ;advance pointer by # bytes regs |
CLR.W (A0)+ ;clear error field |
CLR.L (A0)+ ;clear message field |
CLR.L (A0)+ ;clear A6 link |
TST.W D1 ;was CatchFailures used? |
BPL.S @2 ;no, CatchCFailures or CatchSignal; skip |
MOVE.L A6,-4(A0) ;save the A6Link |
@2 |
MOVE.L A1,(A0)+ ;save the handler ptr |
MOVE.L gTopHandler(A5),(A0)+ ;Link the FailInfo into the list |
MOVE.L D0,gTopHandler(A5) |
MOVE.L D2,(A0)+ ;remember the caller's PC for MA debugging |
MOVE.L D2,A0 ;get return address |
JMP (A0) |
Tail 'CATCHSIG' |
ALIGN |
SiggyPop |
Head |
MOVE.L D0,-(A7) ;save D0 in case weÕre returning from a c function |
MOVE.L SigPointer,A0 |
MOVE.L A0,D0 ;to set CCR |
BEQ SigDeath ;nil pointer means trouble |
MOVE.L SigNow,D0 ;grab table offset to entry |
BMI SigDeath ;if no entries then give up |
ADD.L D0,A0 ;point to current element |
MOVE.L SigFRet(A0),-(A7) ;push proc's real return address |
BSR SiggyPop2 ;pop element and call Success to pop handler |
MOVE.L (A7)+,A1 ;get procÕs return address |
MOVE.L (A7)+,D0 ;get back D0 in case weÕre returning from c |
JMP (A1) |
Tail 'SIGGYPOP' |
ENDP |
If &UsingMacApp Then |
Seg 'MAMain' |
EndIf |
FreeSignal PROC EXPORT ;PROCEDURE FreeSignal; |
IMPORT SigDeath,Success |
IMPORT gTopHandler:Data |
EXPORT SiggyPop2 |
WITH SigGlobals |
Head |
MOVE.L gTopHandler(A5),A0 ;point to FailInfo record |
MOVE.L A0,D0 ;to set CCR |
BEQ.S SigDeath |
TST.W whatSignals(A0) ;was CatchSignal used? |
BLE.S SiggyPop3 ;no, call Success and return |
MOVE.L SigNow,D0 ;grab table offset to entry |
MOVE.L SigA6(A0),A1 ;get A6 at point of CatchSignal |
CMP.L #SigBigA6,A1 ;is it at the outer level? |
BEQ.S SiggyPop2 ;yes, don't jam the address if no frame |
MOVE.L SigFRet(A0),FrameRet(A1) ;"pop" cleanup code |
SiggyPop2 |
SUB.L #SigElSize,D0 |
MOVE.L D0,SigNow ;"pop" the entry |
SiggyPop3 |
MOVE.L A0,-(A7) ;push address for Success (FailInfoÕs) |
JSR Success ;let MacApp remove FailInfo from list; return |
RTS |
Tail 'FREESIGN' |
ENDP |
If &UsingMacApp Then |
Seg 'MAMain' |
EndIf |
SignalMessage PROC EXPORT ;PROCEDURE SignalMessage(code: INTEGER; message: LONGINT); |
IMPORT SignalEntry |
WITH SigGlobals |
Head |
MOVE.L (A7)+,A1 ;get return address |
MOVE.L (A7)+,D0 ;get message |
BRA.S SignalEntry |
Tail 'SIGNALME' |
Signal PROC EXPORT ;PROCEDURE Signal(code:INTEGER); |
IMPORT Failure |
EXPORT SigDeath,SignalEntry |
code EQU 4 |
WITH SigGlobals |
Head |
MOVE.L (A7)+,A1 ;get return address |
CLR.L D0 ;message := 0 |
SignalEntry |
MOVE.W (A7)+,D1 ;get code |
BNE.S @0 ;process the signal if code is non-zero |
JMP (A1) ;return to caller (code was 0) |
@0 |
MOVE.W D1,-(A7) ;push code |
MOVE.L D0,-(A7) ;push message |
JSR Failure ;this will pop the handler and call SignalFailure |
SigDeath |
_Debugger ;wasnÕt supposed to come backÉ |
Tail 'SIGNAL ' |
ENDP |
If &UsingMacApp Then |
Seg 'MAMain' |
EndIf |
DoFailure PROC EXPORT ;PROCEDURE DoFailure(VAR fi: FailInfo); |
IMPORT Failure |
fi EQU 4 |
Head |
BSR FreeSignal ;pop this guy off (but the record is still valid) |
MOVE.L fi(A7),A0 ;get FailInfo record |
MOVEM.L (A0),A2-A7/D3-D7 ;restore regs (can't use A7 anymore) |
ADD #nSavedRegs*4,A0 ;advance pointer |
MOVE.W (A0)+,D0 ;get error |
TST.W whatSignals-nSavedRegs*4-2(A0) ;was CatchSignal used? |
BGT.S @2 ;yes, skip |
MOVE.L (A0)+,D1 ;get message |
MOVEM.L D0/D1,-(SP) ;save error and message for later use |
MOVE.W D0,-(SP) |
MOVE.L D1,-(SP) ;parameters to failure handler |
MOVE.L (A0)+,D0 ;check the A6Link |
BEQ.S @1 ;if NIL then don't pass it |
MOVE.L D0,-(SP) ;else do pass it |
@1 |
MOVE.L (A0)+,A0 ;get address of failure handler |
JSR (A0) ;call failure handler |
MOVEM.L (SP)+,D0/D1 ;get error & message back |
MOVE.W D0,-(SP) |
MOVE.L D1,-(SP) ;parameters to Failure |
JSR Failure |
_Debugger ;not supposed to fail to fail |
@2 |
MOVE.W D0,(A7) ;set CatchSignal function result |
MOVE.L 8(A0),A0 ;address of the failure handler-skip msg. & A6 link |
JMP (A0) ;go to point of CatchSignal |
Tail 'DOFAILUR' |
ENDP |
END |
Copyright © 2003 Apple Computer, Inc. All Rights Reserved. Terms of Use | Privacy Policy | Updated: 2003-01-14