From: ilepore@nyx.cs.du.edu (Ian Lepore)
Subject: Re: Using Setexec() [a bit of help needed]
Organization: University of Denver, Dept. of Math & Comp. Sci.
Date: Tue, 18 Aug 92 00:27:02 GMT

Organization: Nyx, Public Access Unix at U. of Denver Math/CS dept.
X-Disclaimer: Nyx is a public access Unix system run by the University
	of Denver for the Denver community.  The University has neither
	control over nor responsibility for the opinions of users.

 Using your example code, your call to set the interupt s/b:
 
   Setexc(2, BusError);
 
 But, since BusError() appears later in the code, you'll also need to add
an "extern void BusError();" before the Setexc() call, or move the BusError()
routine earlier in your code.  That handles the C-syntax part of your 
question, but the full answer is longer...
 
 Depending on your compiler (you didn't say which one you're using), you
may need to declare BusError() using a keyword such as _interupt.  If your
compiler doesn't support that keyword, there's a good chance you won't be
able to write the BusError() routine in C.  When the routine gets control,
the machine will be in supervisor mode.  Trying to use printf() in supervisor
mode will probably lead to a crash.
 
 The best fix is to use signal(SIGSEGV, handler_function) if your library 
includes a signal-handling system.  If it doesn't, here's some assembler
code which you should be able to adapt to your purposes:
 
----------- cut here ----------------
;*************************************************************************
;*
;* EXHANDLR.S - Machine exception handler.
;*
;*  This module hooks exception vectors 2, 3, 4, 5, 8, and 102 to catch ^C,
;*  null pointer de-referencing, and so on.  When an exception occurs, the
;*  handler routine cleans the exception info off the supervisor stack,
;*  forces the machine back to user mode, and does a longjmp() through
;*  the jump buffer specified during the init call.
;*
;*  This code can be assembled with MadMac or Sozobon's JAS.  
;*
;*  Typical usage is:
;*
;*  RESTART_PROGRAM:
;*
;*      if (0 != (exception = setjmp(exception_handler))) {
;*          exh_remove_handler();   /* prevent ugly recursions */
;*         if (exception > 0)
;*             printf("Exception %d has been handled.\n", exception);
;*          else
;*             printf("Process termination has been handled.\n");
;*          goto RESTART_PROGRAM;   /* or exit() or Pterm() here */
;*      }
;*      exh_init_handler(exception_handler);
;*
;*  The salient points are to install the setjmp() before the init_handler
;*  call, and to be sure and remove the handler as the first thing right
;*  after a return from longjump, to prevent recursion if another exception
;*  happens while you're handling the first exception.  If you are going
;*  to take some restart action instead of terminating the program during
;*  exception handling, be sure to re-install the setjmp() and the 
;*  exception handler before getting into your main logic again.
;*
;*  Remember that the processor termination handler catches ALL 
;*  terminations, not just ^C, so if your program has exit() calls all
;*  over the place, plan to get control if one of them is used to exit
;*  the program.  As of now, I don't know of a good way of catching only
;*  ^C terminations but not exit() terminations.  (Other than replacing
;*  your library exit() routine with something that removes the handlers
;*  and then continues by calling _exit().  Not all libraries support a
;*  two-tiered exit/_exit system, dLibs does.)
;*************************************************************************

        .globl  _exh_init_handler       ;* export our name
        .globl  _exh_remove_handler     ;* export our name
        .globl  _longjmp                ;* import name of library routine

        .bss

oldex2:    .ds.l 1               ;* old exception vector 2 contents
oldex3:    .ds.l 1               ;* old exception vector 3 contents
oldex4:    .ds.l 1               ;* old exception vector 4 contents
oldex5:    .ds.l 1               ;* old exception vector 5 contents
oldex8:    .ds.l 1               ;* old exception vector 8 contents
oldex102:  .ds.l 1               ;* old exception vector 102 contents
ex_jmpbuf: .ds.l 1               ;* pointer to jmp_buf for longjmp

        .text

;*****************************************************************************
;* the exception handlers...
;*****************************************************************************

newex2:                             ;* Exception 2 - address error
        moveq.l #2,d0
        addq.l  #8,sp               ;* (clean extra 8 bytes off the stack)
        bra.b   cleanex
newex3:                             ;* Exception 3 - bus error
        moveq.l #3,d0
        addq.l  #8,sp               ;* (clean extra 8 bytes off the stack)
        bra.b   cleanex

newex4:                             ;* Exception 4 - illegal instruction
        moveq.l #4,d0
        bra.b   cleanex

newex5:                             ;* Exception 5 - divide by zero
        moveq.l #5,d0
        bra.b   cleanex

newex8:                             ;* Exception 8 - privilege violation
        moveq.l #8,d0
        bra.b   cleanex

newex102:                           ;* Exception 102 - ^C (Pterm) handler
        move.w  #-32,d0             ;* (DOS uses -32 for a ^C return code,
        bra.b   do_ljump            ;* so we'll do the same.)

cleanex:
        addq.l  #6,sp               ;* Remove exception SR and PC,
do_ljump:
;*      and.w   #$DFFF,sr           ;* force machine back to user mode.
        .dc.w   $027C               ;* JAS doesn't understand the SR reg...
        .dc.w   $DFFF               ;* these two lines are AND.W #$DFFF,SR
        move.w  d0,-(sp)            ;* Stack exception code.
        move.l  ex_jmpbuf,-(sp)     ;* Stack address of jump buffer.
        jsr     _longjmp            ;* Execute longjmp() function.

;*****************************************************************************
;* the init routine, installs handlers...
;*****************************************************************************

_exh_init_handler:

        move.l  4(sp),d0
        beq     punt
        move.l  d0,ex_jmpbuf

        pea     newex2
        move.l  #$00050002,-(sp)
        trap    #13                 ;* Setexc(2,&newex2)
        addq.l  #8,sp
        move.l  d0,oldex2           ;* Save old vector.

        pea     newex3
        move.l  #$00050003,-(sp)
        trap    #13                 ;* Setexc(3,&newex3)
        addq.l  #8,sp
        move.l  d0,oldex3           ;* Save old vector.

        pea     newex4
        move.l  #$00050004,-(sp)
        trap    #13                 ;* Setexc(4,&newex4)
        addq.l  #8,sp
        move.l  d0,oldex4           ;* Save old vector.

        pea     newex5
        move.l  #$00050005,-(sp)
        trap    #13                 ;* Setexc(5,&newex5)
        addq.l  #8,sp
        move.l  d0,oldex5           ;* Save old vector.

        pea     newex8
        move.l  #$00050008,-(sp)
        trap    #13                 ;* Setexc(8,&newex8)
        addq.l  #8,sp
        move.l  d0,oldex8           ;* Save old vector.

        pea     newex102
        move.l  #$00050102,-(sp)
        trap    #13                 ;* Setexc(102,&newex102)
        addq.l  #8,sp
        move.l  d0,oldex102         ;* Save old vector.
punt:
        rts                         ;* All done, return to caller.

;*****************************************************************************
;* the remove routine, de-installs handlers...
;*****************************************************************************

_exh_remove_handler:

        move.l  oldex2,-(sp)
        move.l  #$00050002,-(sp)
        trap    #13                 ;* Setexc(2,oldex2)
        addq.l  #8,sp

        move.l  oldex3,-(sp)
        move.l  #$00050003,-(sp)
        trap    #13                 ;* Setexc(3,oldex3)
        addq.l  #8,sp

        move.l  oldex4,-(sp)
        move.l  #$00050004,-(sp)
        trap    #13                 ;* Setexc(4,oldex4)
        addq.l  #8,sp

        move.l  oldex5,-(sp)
        move.l  #$00050005,-(sp)
        trap    #13                 ;* Setexc(5,oldex5)
        addq.l  #8,sp

        move.l  oldex8,-(sp)
        move.l  #$00050008,-(sp)
        trap    #13                 ;* Setexc(8,oldex8)
        addq.l  #8,sp

        move.l  oldex102,-(sp)
        move.l  #$00050102,-(sp)
        trap    #13                 ;* Setexc(102,oldex102)
        addq.l  #8,sp

        rts

        end

--------- cut here ----------------
 
 That's the code I use to trap unexpected errors in the HCC compiler piece.
It's appropriate for simple things like issuing a message, closing files,
and exiting the program.  It is *NOT* appropriate for complex handling such
as recovering from the bus error and continuing processing.

--
- Ian
(void *) where prohibited by law

Newsgroups: comp.sys.atari.st.tech