LUSIANI@CERNVM.BITNET (08/04/88)
Sorry, only one person (jim@daemon.megasys.fidonet.org) asked me to post him my work on trap routines, but I'm not able to mail him from here. After some thought I decided to post these routines, because it appears to me that the argument is not well explained in the manual, and nobody gave me a completely exhaustive answer on this topic. In the following there are: - A handler for bus errors wich gains control before the os9 routine and is able to resume repeating the offending instruction. With the user trap handler it is not always possible to repeat the instruction: sometimes the saved pc points to the offending instruction, sometimes to the next instruction (I am working with the 68020: maybe the exception stack frames are not correctly interpreted by os9). - An example on how to use user trap routines for some vectors. Beware that I was not able to handle traps from privilege violation, line-A and line-F emulation. Any explaination? =================================================================== buserr_handler.a =================================================================== nam buserr_handler ttl Bus Error Handler for the TPP use oskdefs.d use systype.d use tppdefs.d opt lx ************************************************ * * Bus error handler * - can be installed and removed * - redirects the 68020 bus error trap vector to itself * - handles occasional bus errors (e .g. due to timeouts) by resuming * execution, and jumps to the os9 trap handler if it appears that * there is a true ineliminable bus error, thus aborting ************************************************ * Edition History * * # Date Comments By * -- -------- ------------------------------------------------- --------------- * 1 88/07/21 first try psm * 1 88/07/28 working version, installed alu * Edition equ 1 current edition number * Typ_Lang set (Prgrm<<8)+Objct mainline segment Typ_Lang set 0 Attr_Rev set (ReEnt<<8)+0 psect BUSERR_HANDLER,Typ_Lang,Attr_Rev,Edition,255,0 * psect BUSERR_HANDLER,Typ_Lang,Attr_Rev,Edition,255,Entry BusErrMess dc.b " Trap_Handler : Bus Error",C$CR,0 delim_s dc.b " - ",0 crlf_s dc.b C$CR,C$LF,0 * msg dc.b " Trap handler is leaving",C$CR,0 err_path_nam dc.b "/term",0 * the following are tricky used as variables, fooling os9 * the bus error exception routines is given the a6 base register * of the task wich did the bus error, not his one BusErrOldVec dc.l 0 ; old os9 exception vector BusErrCount dc.w 0 ; count of bus errors BusErrTicks dc.w 0 ; time of last bus error BusErrSecs dc.l 0 ; time of last bus error BusErrElaps dc.w 0 ; max time between two bus err BusErrMaxCnt dc.w 0 ; max count of close bus err BusErrPAddr dc.l 0 ; proc header addr use alb_io.a ; get string/number I/O funcs * macros to deal with pc relative addressed variables * move long with enhanced <ea> handling for destination move1l MACRO ; move1l <ea>,<ea> move.l a0,-(a7) move.l \1,-(a7) lea \2,a0 move.l (a7)+,(a0) movea (a7)+,a0 ENDM * move word with enhanced <ea> handling for destination move1w MACRO ; move1l <ea>,<ea> move.l a0,-(a7) move.w \1,-(a7) lea \2,a0 move.w (a7)+,(a0) movea (a7)+,a0 ENDM * addq word with enhanced <ea> handling for destination addq1w MACRO ; addq1w <ea>,<ea> move.l a0,-(a7) lea \2,a0 addq \1,(a0) movea (a7)+,a0 ENDM ************************************************************************ * * Begin of program * trap_init: move1w #100,BusErrElaps(pc) ; set max elapsed ticks move1w #100,BusErrMaxCnt(pc) ; set max bus err count move1l $08,BusErrOldVec(pc) ; get save addr lea BusErrHand(pc),a0 move.l a0,$08 move #3,d0 ; julian with tick os9 F$Time ; request system time move1l d0,BusErrSecs(pc) ; save seconds move1w d3,BusErrTicks(pc) ; save ticks move1w #0,BusErrCount(pc) ; zero error count rts trap_end: move.l BusErrOldVec(pc),$08 ; restore old vector * Writes #1,msg(pc) rts BusErrHand move sr,-(a7) move ccr,-(a7) movem.l a0-a6/d0-d7,-(a7) ; save all movea.l $00,a0 ; addr of sysglob move1l D_Proc(a0),BusErrPAddr(pc) ; save current proc addr move #3,d0 ; julian with tick os9 F$Time ; request system time move.l d0,d4 ; get seconds sub.l BusErrSecs(pc),d4 ; subtract old seconds cmpi.l #320,d4 ; if more than 320 seconds bgt.s go_resume ; prevent overflow errors move.l d3,d5 ; get tick rate swap d5 mulu.w d4,d5 ; get ticks to add move.l d3,d4 ; get current tick sub BusErrTicks(pc),d4 ; subtract old ticks add d5,d4 ; get time diff in ticks cmp BusErrElaps(pc),d4 ; if less than max allowed ticks ble.s same_instr ; then go to inc the counter move1w #0,BusErrCount(pc) ; reset counter bra go_resume same_instr addq1w #1,BusErrCount(pc) ; inc error count move BusErrMaxCnt(pc),d5 ; get max count of bus errors cmp BusErrCount(pc),d5 ; if more than max num of errors ble go_os9_trap ; then go to os9 trap handler go_resume move.b #Write_,d0 ; write access lea err_path_nam(pc),a0 ; path name os9 I$Open bcc open_done go_os9_trap move1w #0,BusErrCount(pc) ; reset counter movem.l (a7)+,a0-a6/d0-d7 move (a7)+,ccr move (a7)+,sr ; restore all move.l BusErrOldVec(pc),-(a7) rts ; jump to os9 trap handler open_done movea.l BusErrPAddr(pc),a0 Writeshort d0,P$ID(a0) movea.l P$PModul(a0),a0 ; addr of progr module move.l M$Name(a0),d1 ; addr of module name offset lea.l 0(a0,d1.l),a0 ; get name address Writes d0,(a0) Writes d0,delim_s(pc) move.l 66(a7),d1 Writelong d0,d1 ; prt pc of offending instr move.l 80(a7),d1 Writelong d0,d1 ; prt offending address * Writeshort d0,BusErrCount(pc) Writes d0,BusErrMess(pc) ; issue handler message movea.l $00(a7),a0 Writelong d0,a0 ; prt d0 movea.l $04(a7),a0 Writelong d0,a0 ; prt d1 movea.l $08(a7),a0 Writelong d0,a0 ; prt d2 movea.l $0c(a7),a0 Writelong d0,a0 ; prt d3 movea.l $10(a7),a0 Writelong d0,a0 ; prt d4 movea.l $14(a7),a0 Writelong d0,a0 ; prt d5 movea.l $18(a7),a0 Writelong d0,a0 ; prt d6 movea.l $1c(a7),a0 Writelong d0,a0 ; prt d7 Writes d0,crlf_s(pc) movea.l $20(a7),a0 Writelong d0,a0 ; prt a0 movea.l $24(a7),a0 Writelong d0,a0 ; prt a1 movea.l $28(a7),a0 Writelong d0,a0 ; prt a2 movea.l $2c(a7),a0 Writelong d0,a0 ; prt a3 movea.l $30(a7),a0 Writelong d0,a0 ; prt a4 movea.l $34(a7),a0 Writelong d0,a0 ; prt a5 movea.l $38(a7),a0 Writelong d0,a0 ; prt a6 move usp,a0 Writelong d0,a0 ; prt a7 Writes d0,crlf_s(pc) os9 I$Close move #3,d0 ; julian with tick os9 F$Time ; request system time move1l d0,BusErrSecs(pc) ; save seconds of last bus err move1w d3,BusErrTicks(pc) ; save ticks resBusErr movem.l (a7)+,a0-a6/d0-d7 move (a7)+,ccr move (a7)+,sr ; restore all rte ; resume execution ===================================================================== user_trap.a ===================================================================== nam Trapini ttl User Trap Handler for the TPP * use defsfile use oskdefs.d use systype.d use tppdefs.d opt lx ************************************************ * Edition History * * # Date Comments By * -- -------- ------------------------------------------------- --------------- * 1 88/07/21 first try psm * 1 88/07/28 working version alu Edition equ 1 current edition number Typ_Lang set (Prgrm<<8)+Objct mainline segment Attr_Rev set (ReEnt<<8)+0 psect TRAP_INIT,0,0,1,0,0 * psect TRAP_INIT,Typ_Lang,Attr_Rev,Edition,255,Entry AddErr_str dc.b " Trap_Handler : Address Error Holds",C$CR,0 ZerDiv_str dc.b " Trap_Handler : Divide Check Holds",C$CR,0 IllIns_str dc.b " Trap_Handler : Illegal Instruction Holds",C$CR,0 CHK_str dc.b " Trap_Handler : Bound Check Holds",C$CR,0 TRAPV_str dc.b " Trap_Handler : Trap Exception Holds",C$CR,0 BusErr_str dc.b " Trap_Handler : Bus Error Holds",C$CR,0 Priv_str dc.b " Trap_Handler : Privilege Violation Holds",C$CR,0 str_1010 dc.b " Trap_Handler : A-line Trap Holds",C$CR,0 str_1111 dc.b " Trap_Handler : F-line Trap Holds",C$CR,0 crlf_str dc.b C$CR,0 delim_s dc.b " - ",0 * * The following table lists entries which are understood * by F$Strap as substitutions, resp. removals of user * error trap handlers. * align ExcpTbl dc.w T_AddErr,AddErr_r-*-4 dc.w T_IllIns,IllIns_r-*-4 dc.w T_ZerDiv,ZerDiv_r-*-4 dc.w T_CHK,CHK_r-*-4 dc.w T_BusErr,BusErr_r-*-4 dc.w T_TRAPV ,TRAPV_r-*-4 * dc.w T_Priv,Priv_r-*-4 * dc.w T_1010,r_1010-*-4 * dc.w T_1111,r_1111-*-4 dc.w -1 vsect return_code do.l 1 ; return code from init ends use alb_io.a ; get string/number I/O funcs ************************************************************************ * * Begin of Main * Entry lea return_code(a6),a0 ; brain damaged fortran move.l a0,d0 ; parameter passing bsr UTRAP_INIT movea d0,a0 tst.l (a0) bne.s exit_err move.l #0,d0 move.l #55,d2 divu.l d0,d2 ; divide by 0 move.w #11,d4 chk.w #10,d4 ; bound check error dc.w $77ae ; illegal instruction error dc.w $a000 ; a-line instr error dc.w $f000 ; a-line instr error move $e00000,d0 ; bus error trap #7 ; trap error dc.w $0000 jmp $01 ; address error move sr,d0 ; privilege violation exit_err os9 F$Exit UTRAP_INIT: link a5,#0 movem.l d0-d1/a0-a2,-(a7) movea d0,a2 move.l #0,a0 ; current stack lea ExcpTbl(pc),a1 ; service req. table OS9 F$STrap ; install trap handler move.l d1,(a2) ; return system error bcs.s utrap_error clr.l (a2) ; clear return code utrap_error movem.l (a7)+,d0-d1/a0-a1 unlk a5 rts resume_ex1 move.l R$a7(a5),a1 ; get old stack pointer move.l R$pc(a5),-(a1) ; simulate return address move R$cc(a5),ccr ; restore status register movem.l (a5)+,d0-d7/a0-a7 ; restore all registers lea -4(a7),a7 ; point to return addr rts ; return to normal execution resume_ex2 movem.l (a7)+,d0-d7/a0-a6 ; this also works addq.l #4,a7 move (a7)+,ccr ; restore status register rts abort_ex bsr prt_status os9 F$Exit AddErr_r Writes #2,AddErr_str(pc) ; issue handler message move #0103,d1 bra abort_ex IllIns_r Writes #2,IllIns_str(pc) ; issue handler message move #0104,d1 bra abort_ex ZerDiv_r Writes #2,ZerDiv_str(pc) ; issue handler message move #0105,d1 bra abort_ex CHK_r Writes #2,CHK_str(pc) ; issue handler message move #0106,d1 bra abort_ex TRAPV_r Writes #2,TRAPV_str(pc) ; issue handler message move #0107,d1 bra abort_ex Priv_r Writes #2,Priv_str(pc) ; issue handler message move #0108,d1 bra abort_ex BusErr_r Writes #2,BusErr_str(pc) ; issue handler message move #0102,d1 bra abort_ex r_1010 Writes #2,str_1010(pc) ; issue handler message move #0110,d1 bra abort_ex r_1111 Writes #2,str_1111(pc) ; issue handler message move #0111,d1 bra abort_ex prt_status movea.l $00,a0 ; addr of sysglob movea.l D_Proc(a0),a0 ; get current proc addr Writeshort #2,P$ID(a0) ; print PID of process movea.l P$PModul(a0),a0 ; addr of progr module move.l M$Name(a0),d2 ; addr of module name offset lea.l 0(a0,d2.l),a0 ; get name address Writes #2,(a0) Writes #2,delim_s(pc) Writelong #2,R$pc(a5) ; prt pc of offending instr Writeshort #2,R$sr(a5) ; prt sr Writeshort #2,R$cc(a5) ; prt cc Writes #2,crlf_str(pc) movea.l R$d0(a5),a0 Writelong #2,a0 ; prt d0 movea.l R$d1(a5),a0 Writelong #2,a0 ; prt d1 movea.l R$d2(a5),a0 Writelong #2,a0 ; prt d2 movea.l R$d3(a5),a0 Writelong #2,a0 ; prt d3 movea.l R$d4(a5),a0 Writelong #2,a0 ; prt d4 movea.l R$d5(a5),a0 Writelong #2,a0 ; prt d5 movea.l R$d6(a5),a0 Writelong #2,a0 ; prt d6 movea.l R$d7(a5),a0 Writelong #2,a0 ; prt d7 Writes #2,crlf_str(pc) movea.l R$a0(a5),a0 Writelong #2,a0 ; prt a0 movea.l R$a1(a5),a0 Writelong #2,a0 ; prt a1 movea.l R$a2(a5),a0 Writelong #2,a0 ; prt a2 movea.l R$a3(a5),a0 Writelong #2,a0 ; prt a3 movea.l R$a4(a5),a0 Writelong #2,a0 ; prt a4 movea.l R$a5(a5),a0 Writelong #2,a0 ; prt a5 movea.l R$a6(a5),a0 Writelong #2,a0 ; prt a6 movea.l R$a7(a5),a0 Writelong #2,a0 ; prt a7 Writes #2,crlf_str(pc) rts =================================================================== regards Alberto