home *** CD-ROM | disk | FTP | other *** search
Text File | 1996-12-24 | 42.3 KB | 1,220 lines |
- *
- * C initial startup procedure under AmigaDOS
- *
- * Use the following command line to make c.o
- * asm -u c.a
- *
- * Use the following command line to make cres.o
- * asm -u -dRESIDENT -ocres.o c.a
- *
- * Use the following command line to make catch.o (standard GURU catcher)
- * asm -u -dCATCH -ocatch.o c.a
- *
- * Use the following command line to make catchnr.o (GURU catcher w/out requester)
- * asm -u -dCATCH -dNOREQ -ocatchnr.o c.a
- *
- * Use the following command line to make catchres.o (resident GURU catcher)
- * asm -u -dCATCH -dRESIDENT -ocatchres.o c.a
- *
- * Use the following command line to make catchresnr.o (resi GURU catcher w/out req)
- * asm -u -dCATCH -dRESIDENT -dNOREQ -ocatchresnr.o c.a
- *
- IFD CATCH
- IFND NOREQ
- AUTOREQ set 1
- ENDC
- ENDC
-
- INCLUDE "exec/types.i"
- INCLUDE "exec/alerts.i"
- INCLUDE "exec/nodes.i"
- INCLUDE "exec/lists.i"
- INCLUDE "exec/ports.i"
- INCLUDE "exec/libraries.i"
- INCLUDE "exec/tasks.i"
- INCLUDE "exec/memory.i"
- INCLUDE "exec/execbase.i"
- INCLUDE "libraries/dos.i"
- INCLUDE "libraries/dosextens.i"
- INCLUDE "workbench/startup.i"
- INCLUDE "exec/funcdef.i"
- INCLUDE "exec/exec_lib.i"
- INCLUDE "libraries/dos_lib.i"
-
- IFD CATCH
- INCLUDE "intuition/intuition.i"
- VERSION equ 1
- REVISION equ 0
- ENDC
-
- MEMFLAGS EQU MEMF_CLEAR+MEMF_PUBLIC
- AbsExecBase EQU 4
-
- ;;;
- ;;; Stack map.
- ;;;
- OFFSET 0
- ds.b 4
- savereg ds.b 13*4
- stackbtm ds.b 4
-
-
-
- ; some usefull macros:
-
- callsys macro
- CALLLIB _LVO\1
- endm
-
- xdef _XCEXIT * exit(code) is standard way to leave C.
- xdef @_XCEXIT
- xdef __startup
-
- xref LinkerDB * linker defined base value
- xref _BSSBAS * linker defined base of BSS
- xref _BSSLEN * linker defined length of BSS
- xref __stack
-
- IFD RESIDENT
- xref RESLEN
- xref RESBASE
- xref NEWDATAL
- ENDC
-
- * library references
-
- section text,code
-
- xref __main * Name of C program to start with.
- xref __fpinit * initialize floating point
- xref __fpterm * terminate floating point
-
- __startup:
- start:
- movem.l d1-d6/a0-a6,-(a7) * save registers
-
- move.l a0,a2 * save command pointer
- move.l d0,d2 * and command length
- lea LinkerDB,a4 * load base register
- move.l AbsExecBase.W,a6
-
-
- IFND RESIDENT
- lea _BSSBAS,a3 * get base of BSS
- moveq #0,d1
- move.l #_BSSLEN,d0 * get length of BSS in longwords
- bra.s clr_lp * and clear for length given
- clr_bss move.l d1,(a3)+
- clr_lp dbf d0,clr_bss
- move.l a7,_StackPtr(A4) * Save stack ptr
- move.l a6,SysBase(A4)
-
- *------ get the size of the stack, if CLI use cli_DefaultStack
- *------ if WB use a7 - TC_SPLOWER
- move.l ThisTask(a6),A3
- move.l pr_CLI(A3),d0
- beq.s fromwb
- lsl.l #2,d0
- move.l d0,a0
- move.l cli_DefaultStack(a0),d0
- lsl.l #2,d0 * # longwords -> # bytes
- bra.s dostack
-
- fromwb:
- move.l a7,d0
- sub.l TC_SPLOWER(a3),d0
- dostack:
-
- *------ Set __base for stack checking
- move.l a7,d1
- sub.l d0,d1 * get top of stack
- add.l #128,D1 * allow for parms overflow
- move.l D1,__base(A4) * save for stack checking
-
- cmp.l __stack(a4),d0
- bcc.s nochange
-
- *-- current stack is not as big as __stack says it needs
- *-- to be. Allocate a new one.
- move.l __stack(a4),d0
- add.l #128,d0 * extra room
- move.l d0,newstacksize(a4)
-
- move.l #MEMFLAGS,d1
- callsys AllocMem
- tst.l d0
- beq.w return
-
- move.l d0,newstack(a4)
- add.l #128,d0 * extra room
- move.l d0,__base(a4)
-
- add.l __stack(a4),d0
- move.l d0,d1
-
- *-- If we're running under 2.0, call StackSwap to set up
- *-- the new stack. Otherwise, just jam the new value into
- *-- A7.
- cmpi.w #36,$14(a6)
- blt.s no20
-
- move.l d0,mystk_Pointer(a4)
- move.l d1,mystk_Upper(a4)
- sub.l newstacksize(a4),d1
- lea mystk_Lower(a4),a0
- move.l d1,(a0)
- callsys StackSwap
- bra.s nochange
-
- no20: move.l d0,a7
-
- nochange:
- ENDC
-
-
-
- IFD RESIDENT
- move.l d2,-(a7)
- movem.l a0-a2,-(a7)
-
- *------ get the size of the stack, if CLI use cli_DefaultStack
- *------ if WB use a7 - TC_SPLOWER
- move.l ThisTask(a6),A3
- move.l pr_CLI(A3),d1
- beq.s fromwb
- lsl.l #2,d1
- move.l d1,a0
- move.l cli_DefaultStack(a0),d1
- lsl.l #2,d1 * # longwords -> # bytes
- bra.s dostack
-
- fromwb:
- move.l a7,d1
- sub.l TC_SPLOWER(a3),d1
- dostack:
- moveq #0,d2 * use d2 as flag for newstack or not
- move.l #RESLEN,d0
- cmp.l __stack(a4),d1 * This a4 is in the original
- * set of data
- bcc.s nochange
- move.l __stack(a4),d1
- add.l d1,d0 * increase size of mem for new stack
- moveq #1,d2 * set flag
-
- nochange:
- move.l d1,a3 * save stacksize to set up stack checking
- move.l #MEMFLAGS,d1
- callsys AllocMem
- tst.l d0
- bne.s ok1
- movem.l (a7)+,d2/a0-a2
- bra.w return
-
- ok1: move.l d0,a0
- move.l d0,a2 * a2 now has difference
-
- move.l d0,a1
- move.l #NEWDATAL,d0
- sub.l #RESBASE,a4
-
- * copy data over
- cpy: move.l (a4)+,(a0)+
- subq.l #1,d0
- bne.s cpy
-
- * a4 now points at number of relocs
- move.l (a4)+,d0
- reloc: beq.s nreloc
- move.l a1,a0
- add.l (a4)+,a0 * a0 now has add of reloc
- add.l (a0),a2
- move.l a2,(a0)
- move.l a1,a2 * restore offset
- subq.l #1,d0
- bra.s reloc
-
- nreloc: move.l a1,a4 * set up new base register
- add.l #RESBASE,a4
-
- move.l #RESLEN,realdatasize(a4)
- movem.l (a7)+,a0-a2
-
- move.l a6,SysBase(A4)
- tst.b d2
- movem.l (a7)+,d2 * restore d2
- movem.l a7,_StackPtr(A4) * Save stack ptr (movem doesn't
- * change flags
- beq.s nochg2
-
- *------ set up new stack
- move.l a4,d0
- sub.l #RESBASE,d0
- add.l #RESLEN,d0
- add.l __stack(a4),d0 * here a4 will be pointing at the
- * new data, but __stack will be the
- * same if all goes well
- move.l d0,d1
-
-
- *-- If we're running under 2.0, call StackSwap to set up
- *-- the new stack. Otherwise, just jam the new value into
- *-- A7.
- cmpi.w #36,$14(a6)
- blt.s no20a
-
- move.l d0,mystk_Pointer(a4)
- move.l d1,mystk_Upper(a4)
- sub.l __stack(a4),d1
- lea mystk_Lower(a4),a0
- move.l d1,(a0)
- callsys StackSwap
- bra.s doneswap
-
- no20a: move.l d0,a7
-
- doneswap:
-
- move.l __stack(a4),d0
- add.l d0,realdatasize(a4) * need to know how much to free later
-
- nochg2:
- *------ Set __base for stack checking
- move.l a7,d1
- sub.l a3,d1 * get top of stack
- add.l #128,D1 * allow for parms overflow
- move.l D1,__base(A4) * save for stack checking
-
- ENDC
-
-
- *------ Save the current stack. We'll reset it to here to
- *------ Run the autoterminators.
- move.l a7,newst_Pointer(a4)
- move.l a7,newst_Upper(a4)
- lea newst_Lower(a4),a0
- move.l __base(a4),(a0)
-
- cmpi.w #36,$14(a6)
- blt.s no20b
- callsys StackSwap
-
- no20b:
-
- ifd CATCH
- move.w AttnFlags(a6),Environment+2(a4) * save copy for dump
- endc
-
-
-
- clrwb:
- clr.l _WBenchMsg(A4)
-
- *----- clear any pending signals
- moveq #0,d0
- move.l #$00003000,d1
- callsys SetSignal
-
-
- move.l ThisTask(a6),A3
-
- ifd CATCH
- move.l A3,TaskID(a4)
-
- *------ initialize exception handler
- *------ Remember to preserve the old handler first
- move.l TC_TRAPDATA(a3),oldtrapdata(A4)
- move.l TC_TRAPCODE(a3),d0 ; check current exception
- move.l d0,oldtrapcode(A4)
-
- move.l d0,a1
- callsys TypeOfMem
- tst.l d0
- bne.s 1$ * somebody else (debugger?) has vector
-
- move.l #Exception,TC_TRAPCODE(a3) * install pointers to code
- move.l a4,TC_TRAPDATA(a3) * ...and data
- 1$:
- ifd AUTOREQ
- *------ attempt to open Intuition library:
- bsr.w openIntui
- endc
- endc
-
-
- *------ attempt to open DOS library:
- lea DOSName(PC),A1
- moveq.l #0,D0
- callsys OpenLibrary
- move.l D0,DOSBase(A4)
- bne.s ok2
- moveq.l #100,d0
- bra.w exit2
-
- ok2:
-
- *------ are we running as a son of Workbench?
- move.l pr_CurrentDir(A3),__curdir(A4)
- tst.l pr_CLI(A3)
- beq.w fromWorkbench
-
- *=======================================================================
- *====== CLI Startup Code ===============================================
- *=======================================================================
- *
- * Entry: D2 = command length
- * A2 = Command pointer
- fromCLI:
- ifd CATCH
- moveq #-1,d0
- move.l d0,Starter(a4) * non-zero means CLI
- move.l a5,StackTop(a4)
- endc
-
- *------ find command name:
- move.l pr_CLI(a3),a0
- add.l a0,a0 * bcpl pointer conversion
- add.l a0,a0
- move.l cli_CommandName(a0),a1
-
- IFD CATCH
- IFND AUTOREQ
- move.l cli_StandardOutput(a0),GConsole(a4) * save output fh
- ENDC
- ENDC
-
- add.l a1,a1 * bcpl pointer conversion
- add.l a1,a1
-
- *------ collect parameters:
- move.l d2,d0 * get command line length
- moveq.l #0,d1
- move.b (a1)+,d1
- move.l a1,_ProgramName(A4)
- add.l d1,d0 * add length of command name
- addq.l #7,d0 * allow for space after command, quotes
- * and null terminator, as well as
- andi.w #$fffc,D0 * force to long word boundary
- move.l d0,Commandlen(a4)
-
- movem.l d1/a1,-(a7)
- move.l #MEMFLAGS,d1
- callsys AllocMem
- movem.l (a7)+,d1/a1
- tst.l d0
- bne.s ok_copy
-
- moveq.l #20,d0 * what should the return code be for out of mem?
- move.l d0,-(a7) * put a return code on the stack
- beq.w nodofree * Was exitToDOS
-
- ok_copy:
- move.l d0,a0
- move.l d0,Commandbuf(a4)
-
- *------ copy command line into memory
- move.l d2,d0 * get command line length
- subq.l #1,d0
- add.l d1,d2
-
- copy_line:
- move.b 0(A2,D0.W),2(A0,D2.W) * copy command line to stack
- subq.l #1,d2
- dbf d0,copy_line
- move.b #' ',2(a0,d2.w) * add space between command and parms
- subq.l #1,d2
- move.b #'"',2(a0,d2.w) * add end quote
-
- copy_cmd:
- move.b 0(a1,d2.w),1(a0,d2.w) * copy command name to stack
- dbf d2,copy_cmd
- move.b #'"',(a0)
- move.l A0,-(A7) * push command line address
- bra.s main * call C entrypoint
-
- *=======================================================================
- *====== Workbench Startup Code =========================================
- *=======================================================================
-
- fromWorkbench:
-
- ifd CATCH
- move.l TC_SPUPPER(a3),StackTop(a4) * set top of stack
- endc
-
-
- *------ we are now set up. wait for a message from our starter
- lea pr_MsgPort(A3),a0 * our process base
- callsys WaitPort
- lea pr_MsgPort(A3),a0 * our process base
- callsys GetMsg
- move.l d0,_WBenchMsg(a4)
- move.l d0,-(SP)
-
- move.l d0,a2 * get first argument
- move.l sm_ArgList(a2),d0
- beq.s do_main
- move.l DOSBase(a4),a6
- move.l d0,a0
- move.l wa_Lock(a0),d1
- callsys DupLock
- move.l d0,__curdir(A4)
- move.l d0,d1
- callsys CurrentDir
-
- do_main:
- move.l _WBenchMsg(A4),a0 * get address of workbench message
- move.l a0,-(a7) * push argv
- pea NULL(a4) * push argc
- move.l sm_ArgList(a0),a0 * get address of arguments
- move.l wa_Name(a0),_ProgramName(A4) * get name of program
-
- *=============================================
- *------ common code --------
- *=============================================
-
- main jsr __fpinit(PC) * Initialize floating point and constructors
- tst.l d0
- bne.s exit2
- jsr __main(PC) * call C entrypoint
- moveq.l #0,d0 * set successful status
- bra.s exit2
- *
-
- XCEXIT:
- _XCEXIT:
- move.l 4(SP),d0 * extract return code
- @XCEXIT:
- @_XCEXIT:
- exit2:
-
- *-- Save Return Code on the original stack
- move.l _StackPtr(a4),a2
- move.l d0,-(a2)
-
- *-- Set the stack to the first NEW stack we allocated
- *-- So C++ destructors can run with a large stack if required
- move.l newst_Lower(a4),__base(a4)
- move.l AbsExecBase.W,A6
- subq.l #4,newst_Pointer(a4) * make room for the ret code
- cmpi.w #36,$14(a6)
- blt.s noswap1
- lea newst_Lower(a4),a0
- callsys StackSwap
- bra.b swapdone
- noswap1:
- move.l newst_Pointer(a4),a7
- swapdone:
- move.l _ONEXIT(A4),d0 * exit trap function?
- beq.s exit3
- move.l d0,a0
- jsr (a0)
- exit3:
- jsr __fpterm(PC) * clean up any floating point
-
-
- *-- Swap back to original stack
- *-- If we're running under 2.0, call StackSwap
- *-- Otherwise, just jam the new value into a7
- move.l AbsExecBase.W,A6
- cmpi.w #36,$14(a6)
- blt.s noswap
- tst.l mystk_Lower(a4)
- beq.s noswap
-
- lea mystk_Lower(a4),a0
- subq.l #4,mystk_Pointer(a4) * make room for the ret code
- callsys StackSwap
-
- noswap:
- movea.l a2,a7 * restore stack ptr
-
-
- ifnd RESIDENT
- *------ free the stack if we allocated one
- move.l newstacksize(a4),d0
- beq.s exit4
- move.l newstack(a4),a1
- move.l AbsExecBase.W,A6
- callsys FreeMem
- endc
-
- exit4:
- *------ if we ran from CLI, skip workbench cleanup:
- tst.l _WBenchMsg(A4)
- beq.s exitToDOS
- move.l DOSBase(A4),a6
- move.l __curdir(a4),d1
- beq.s done_5
- callsys UnLock
- done_5:
- *------ return the startup message to our parent
- * we forbid so workbench can't UnLoadSeg() us
- * before we are done:
- move.l AbsExecBase.W,A6
- callsys Forbid
- move.l _WBenchMsg(a4),a1
- callsys ReplyMsg
- bra.s nodofree
-
- exitToDOS:
- move.l AbsExecBase.W,a6
-
- *------ Restore the original exception handler
- ifd CATCH
- move.l ThisTask(a6),A3
- move.l oldtrapdata(A4),TC_TRAPDATA(a3)
- move.l oldtrapcode(A4),TC_TRAPCODE(a3) * check current exception
- ifd AUTOREQ
- move.l IntuiBase(a4),a1
- callsys CloseLibrary * close Intuition library
- endc
- ENDC
-
- *------ free the command line buffer
- move.l Commandlen(a4),d0
- beq.s nodofree
- move.l Commandbuf(a4),a1
- callsys FreeMem
-
- *------ this rts sends us back to DOS:
- nodofree:
- move.l DOSBase(A4),a1
- callsys CloseLibrary * close Dos library
-
- IFD RESIDENT
- move.l realdatasize(a4),d0
- move.l a4,a1
- sub.l #RESBASE,a1
- callsys FreeMem
- ENDC
- move.l (a7)+,d0
-
- return:
- movem.l (a7)+,d1-d6/a0-a6
- rts
-
- DOSName dc.b 'dos.library',0
-
- ifd CATCH
- *-----------------------------------------------------------------------
- * Open the Intuition library:
-
- openIntui:
- lea IntuiName(PC),A1
- moveq.l #0,D0
- callsys OpenLibrary
- move.l D0,IntuiBase(A4)
- beq.s noDOS
- rts
-
- *-----------------------------------------------------------------------
- noDOS:
- moveq.l #100,d0
- bra.w exit2
-
-
- IntuiName dc.b 'intuition.library',0
-
- *-----------------------------------------------------------------------
- * The Exception Handler - catches GURUs and exits (semi)cleanly
- Exception:
- movem.l a0,-(a7)
- move.l AbsExecBase.W,a0
- move.l ThisTask(a0),a0
- move.l TC_TRAPDATA(a0),a0 * ...and data
- move.l (sp)+,ADump(a0) * save a0
- move.l d0,ADump+4(a0) * and d0
-
- move.l (a7)+,d0 * get exception # from stack
- move.l d0,GURUNum(a0) * and save it
- cmpi.l #3,d0 * ADDRESS or BUS error?
- bgt.s 1$ * no, skip adjustment
- btst #0,Environment+3(a0) * is it 68010 or 68020?
- bne.s 1$ * 0 means NO
- addq.l #8,a7 * adjust for 68000
- 1$:
- move.l 2(a7),d0 * get PC at crash
- move.l d0,GURUAddr(a0) * and save it
- move.l ADump+4(a0),d0 * restore a0 and d0
- move.l ADump(a0),a0
- move.l #GURUExit,2(a7) * use our own exit point
- rte
-
- *-----------------------------------------------------------------------
- * The Exception exit routine - write 'PGTB' IFF chunk to file
- * 'SnapShot.TB' in current directory, then exit to system.
-
- GURUExit:
- movem.l d0-d7/a0-a7,-(sp) * save all registers
- move.l AbsExecBase.W,a6 * make sure we are working with Exec
- callsys GetCC * safe way - works with all CPUs
- move.l ThisTask(a6),a3
- move.l TC_TRAPDATA(a3),a4 * make sure we have a valid # in a4
- move.l d0,Flags(a4) * save area
- movem.l (sp)+,d0-d7
- movem.l d0-d7,DDump(a4) * save data reg contents
- movem.l (sp)+,d0-d7
- movem.l d0-d7,ADump(a4) * save address reg contents
- tst.l StackPtr(a4) * if there's something there
- bne GExit1 * ...we've been here before!
- lea TempStore(a4),a0 * calculate addr of TempStore
- move.l a0,TempAddr(a4) * ...and save for later access
- move.l A7Store(a4),d0 * make sure we have proper TOS
- move.l d0,StackPtr(a4) * ...and save it
- moveq #0,d0
- move.l _ProgramName(a4),a0 * find length of program name
-
- ifd AUTOREQ
- move.l a0,PName(a4)
- endc
-
- subq.l #1,a0
- move.b (a0),d0
- addq.l #4,d0 * adjust for shift
- lsr.l #2,d0
- move.l d0,NameLen(a4) * store length
- add.l d0,FAILlen(a4) * and sub-chunk total
-
- moveq #0,d0 * clear d0 for use
- lea VBlankFrequency(a6),a0 * set up a0 to find correct data
- move.b (a0)+,d0 * get just in case
- move.l d0,VBlankFreq(a4) * ...so we can figure what
- move.b (a0),d0 * ...type of machine
- move.l d0,PowerSupFreq(a4) * ...we're working on
-
- lea start-4(pc),a0 * get seglist ptr
- moveq #-1,d0 * always at least 1
- 2$:
- addq.l #1,d0
- move.l (a0),d1 * find end of list
- beq.s 3$
- lsl.l #2,d1 * BPTR!!!!!
- move.l d1,a0
- bra.s 2$
- 3$:
- add.l d0,SegCount(a4) * store # of seglist pointers
- lsl.l #1,d0 * multiply by 2 for longword count
- add.l d0,FAILlen(a4) * and sub-chunk length
-
- move.l StackTop(a4),d0 * get top of stack
- sub.l StackPtr(a4),d0 * find number of bytes used
- addq.l #4,d0 * adjust for longword conversion
- lsr.l #2,d0 * convert from bytes to long
- move.l d0,StackLen(a4) * and save
- add.l d0,s2len(a4) * and sub-chunk total
-
- move.l a5,-(sp) * save a5 for later
- callsys Forbid * don't let 'em change while we ask
- move.l MemList+LH_HEAD(a6),d0 * first node in MemList
- checkchip:
- move.l d0,a5 * move node address to address reg
- move.w MH_ATTRIBUTES(a5),d4 * get node attributes
- btst #MEMB_CHIP,d4 * is it chip?
- beq.s checkfast * no, go on
- lea chipAvail(a4),a3
- bsr.w AddIt
- checkfast:
- btst #MEMB_FAST,d4 * is it fast?
- beq.s next * no, go on
- lea fastAvail(a4),a3
- bsr.w AddIt
- next:
- move.l LN_SUCC(a5),d0 * get address of next node
- bne.s checkchip * ...and loop back if valid
- callsys Permit * allow others access again
- move.l #MEMF_CHIP+MEMF_LARGEST,d1 * to find largest hunk in chip ram
- callsys AvailMem
- move.l d0,chipLargest(a4) * store
- move.l #MEMF_FAST+MEMF_LARGEST,d1 * to find largest hunk in fast ram
- callsys AvailMem
- move.l d0,fastLargest(a4) * store
- move.l (sp)+,a5 * and restore a5
-
- ifd AUTOREQ
- moveq #0,d0 * PosFlag
- move.l d0,d1 * NegFlag
- move.l d0,a0 * 0 means use current window
- lea IText1(a4),a1 * Body Text
- lea IText5(a4),a2 * Positive Gadget Text
- lea IText6(a4),a3 * Negative Gadget Text
- moveq #1,d2
- lsl.l #8,d2 * quick way to set Width
- moveq #76,d3 * Height
- move.l IntuiBase(a4),a6 * get intuition library pointer
- jsr -$15c(A6) * callsys AutoRequest
- move.l AbsExecBase.W,a6
- tst.l d0 * save SnapShot?
- beq.w GExit2 * no, just exit
- endc
-
- move.l DOSBase(a4),a6
- lea DumpName(a4),a0 * get name of output file
- move.l a0,d1
- move.l #MODE_NEWFILE,d2 * create new file
- callsys Open
- bne.s 4$
- lea DumpPath(a4),a0 * if error in current dir, try DF1:
- move.l a0,d1
- move.l #MODE_NEWFILE,d2
- callsys Open
- bne.s 4$
- move.b #'0',DumpPath+2(a4) * still error? Try DF0:
- lea DumpPath(a4),a0
- move.l a0,d1
- move.l #MODE_NEWFILE,d2
- callsys Open
-
- ifnd AUTOREQ
- bne.s 4$ * if no error, continue (finally!)
- move.l GConsole(a4),d1
- beq.w GExit2
- lea failmsg(a4),a0
- move.l a0,d2
- move.l #23,d3
- callsys Write
- endc
-
- bra.w GExit2 * else, print msg & DIE gracefully
- 4$:
- move.l d0,d5 * save file handle for Write
- move.l d0,fp(a4) * ...and in a safe place for later
- move.l d5,d1 * get file handle
- lea PGTB(a4),a0 * first part of fixed
- move.l a0,d2
- move.l #chunk_len_1,d3 * length of first
- callsys Write * ...since it gets written over
-
- move.l d5,d1 * get file handle
- move.l _ProgramName(a4),d2 * get address of program name
- move.l NameLen(a4),d3 * get # longs in program name
- lsl.l #2,d3 * ..and convert to bytes
- callsys Write
-
- move.l d5,d1 * get file handle
- lea Environment(a4),a0 * second part of fixed
- move.l a0,d2
- move.l #chunk_len_2,d3 * length of second part
- callsys Write
-
- lea start-8(pc),a0 * address of seglist (size of seg)
- move.l (a0)+,d0 * segsize
- move.l d0,TempStore+4(a4) * save it
- move.l a0,TempStore(a4) * store first number
- move.l SegCount(a4),d4
- 5$:
- move.l d5,d1 * get file handle
- move.l TempAddr(a4),d2 * address of write buffer
- moveq #TempSize,d3 * size of segment pointer
- callsys Write
- move.l TempStore(a4),a0 * retrieve pointer
- move.l (a0),d0 * get next seg pointer
- lsl.l #2,d0 * adjust
- move.l d0,TempStore(a4) * ..and save
- move.l d0,a0
- beq.b donesegs * last segment?
- move.l -4(a0),d0 * get segsize
- move.l d0,TempStore+4(a4) * ...and save it
- subq.l #1,d4 * done yet?
- bne.s 5$ * no, do next
-
- donesegs:
- tst.l _FMEM(a4) * do they want memory reported?
- beq.s 55$ * no, forget it
- move.l d5,d1
- lea subFMEM(a4),a0
- move.l a0,d2
- move.l #FMEMlen,d3
- callsys Write
-
- 55$:
- move.l d5,d1 * (get the idea?)
- lea subREGS(a4),a0 * third part of fixed
- move.l a0,d2
- move.l #chunk_len_3,d3 * length of third
- callsys Write
-
- move.l StackLen(a4),d0 * get length of stack used
- cmpi.l #2048,d0 * > 8k ?
- bgt.s 6$ * yes, dump two chunks
- move.l d5,d1
- lea STAK2(a4),a0 * whole stack chunk
- move.l a0,d2
- moveq #STAK2len,d3 * length of fixed part
- callsys Write
-
- move.l d5,d1
- move.l StackPtr(a4),d2 * address of stack
- move.l StackLen(a4),d3 * get # longwords on stack
- lsl.l #2,d3 * ..and convert to bytes
- callsys Write
- bra.s 7$
- 6$:
- move.l d5,d1
- lea STAK3(a4),a0 * top4k chunk
- move.l a0,d2
- moveq #STAK3len,d3 * length of fixed part
- callsys Write
-
- move.l d5,d1
- move.l StackTop(a4),d2 * find top of stack
- sub.l #4096,d2 * find top-4k
- move.l #4096,d3 * # bytes to write
- callsys Write
-
- move.l d5,d1
- lea STAK4(a4),a0 * bottom4k chunk
- move.l a0,d2
- moveq #STAK4len,d3 * length of fixed part
- callsys Write
-
- move.l d5,d1
- move.l StackPtr(a4),d2 * current stack address
- move.l #4096,d3 * # bytes to write
- callsys Write
- 7$:
- move.l _STAKOffset(a4),d3
- beq.s 8$
- lsr.l #2,d3
- addq.l #1,d3
- move.l d3,_STAKOffset(a4)
- addq.l #1,d3
- move.l d5,d1
- lea STAK5(a4),a0
- move.l a0,d2
- moveq #STAK5len,d3
- callsys Write
-
- move.l d5,d1
- move.l StackPtr(a4),d2
- move.l _STAKOffset(a4),d3
- subq.l #1,d3
- move.l StackLen(a4),d4
- cmp.l d3,d4
- bge.s 75$
- move.l StackLen(a4),d3
- 75$:
- lsl.l #2,d3
- callsys Write
- 8$:
- tst.l _ONGURU(A4) * user GURU function?
- beq.s 9$
- move.l d5,-(sp)
- move.l d5,d1
- lea UDAT(a4),a0
- move.l a0,d2
- move.l #UDATlen,d3
- callsys Write
- move.l d5,d1
- moveq #0,d2 * zero offset
- moveq #1,d3 * ...from EOF
- callsys Seek
- move.l d0,SeekStore(a4)
- move.l _ONGURU(a4),a0
- jsr (a0)
- addq.l #4,sp
- 9$:
- move.l fp(a4),d5
- move.l d5,d1
- moveq #0,d2 * offset from EOF
- moveq #1,d3 * OFFSET_END
- callsys Seek * Seek returns OLD position
- move.l d0,d1
- andi.l #3,d1 * did user write even longwords?
- beq.s 10$ * Yep! Nice Human.
- move.l d1,d6 * Nope, save for later.
- clr.l TempStore(a4) * clear temp storage
- move.l d5,d1
- move.l TempAddr(a4),d2
- moveq #4,d3
- sub.l d6,d3 * find how many NULLs to pad
- callsys Write
- bra.s 9$
- 10$:
- tst.l SeekStore(a4) * did we write UDAT?
- beq.s 11$ * nope!
- sub.l SeekStore(a4),d0 * find length of UDAT section
- lsr.l #2,d0 * adjust to longwords
- move.l d0,TempStore(a4) * save UDAT length for write
- move.l d5,d1
- move.l SeekStore(a4),d2 * find where to write it
- subq.l #4,d2
- moveq #-1,d3 * OFFSET_BEGINNING
- callsys Seek
- move.l d5,d1
- move.l TempAddr(a4),d2
- move.l #4,d3
- callsys Write * write length of UDAT field to file
- 11$:
- move.l d5,d1
- moveq #0,d2 * offset to 'Length' field
- moveq #1,d3 * OFFSET_END
- callsys Seek * make sure we are at end of file
- move.l d5,d1
- moveq #4,d2 * offset to 'Length' field
- moveq #-1,d3 * OFFSET_BEGINNING
- callsys Seek
- subq.l #8,d0 * adjust total length
- lsr.l #2,d0 * adjust to longwords
- move.l d0,TempStore(a4) * save for write
- move.l d5,d1
- move.l TempAddr(a4),d2
- move.l #4,d3
- callsys Write * write 'Length' field
- GExit1:
- move.l fp(a4),d1
- beq.s GExit2
- move.l DOSBase(a4),a6
- callsys Close
-
- ifnd AUTOREQ
- move.l GConsole(a4),d1
- beq.s GExit2
- lea success(a4),a0
- move.l a0,d2
- move.l #32,d3
- callsys Write
- endc
-
- GExit2:
- move.l TaskID(a4),a6
- move.l AbsExecBase.W,a6
- moveq #$47,d0
- bra.w exit2
-
- *-----------------------------------------------------------------------
- * AddIt: routine to add memory parts to variables
-
- AddIt:
- move.l MH_FREE(a5),d0
- add.l d0,(a3) * add to available
- move.l MH_UPPER(a5),d0
- sub.l MH_LOWER(a5),d0
- add.l d0,4(a3) * add to Max section
- rts
- endc
-
-
- IFD CATCH
- section __MERGED,DATA
- _ONGURU dc.l 0
- IntuiBase dc.l 0
- TaskID dc.l 0
- oldtrapcode dc.l 0
- oldtrapdata dc.l 0
-
- ifnd AUTOREQ
- GConsole dc.l 0
- failmsg dc.b 7,'Can''t write SnapShot!',10
- success dc.b 7,'GURU caught; SnapShot written!',10
- endc
-
- cnop 0,4
- _FMEM dc.l 0
- fp dc.l 0 * save SnapShot file pointer
- DumpPath dc.b 'DF1:'
- DumpName dc.b 'SnapShot.TB',0
- SeekStore dc.l 0
- TempAddr dc.l 0 * Storage for &TempStore
- TempStore dc.l 0,0 * Temporary storage for BPTR -> APTR
- TempSize equ *-TempStore
-
- cnop 0,4
- ifd AUTOREQ
- TAttr: * Text attributes for font
- dc.l TName * name of font
- dc.w TOPAZ_EIGHTY * font size
- dc.b FS_NORMAL * font style
- dc.b FPF_ROMFONT * font preferences
- TName:
- dc.b 'topaz.font',0
- cnop 0,4
-
- IText1: * Text definitions for AutoReq call
- dc.b 3,0,RP_JAM1,0 * front & back pens, drawmode and filler byte
- dc.w 6,4 * XY origin relative to container TopLeft
- dc.l TAttr * font pointer or NULL for default
- dc.l ITextText1 * pointer to text
- dc.l IText2 * next IntuiText structure
- ITextText1:
- dc.b 'Program:',0
- cnop 0,4
- IText2:
- dc.b 3,0,RP_JAM1,0
- dc.w 78,4
- dc.l TAttr
- PName dc.l 0
- dc.l IText3
- cnop 0,4
- IText3:
- dc.b 3,0,RP_JAM1,0
- dc.w 55,16
- dc.l TAttr
- dc.l ITextText3
- dc.l IText4
- ITextText3:
- dc.b 'I caught a GURU!',0
- cnop 0,4
- IText4:
- dc.b 3,0,RP_JAM1,0
- dc.w 20,28
- dc.l TAttr
- dc.l ITextText4
- dc.l 0
- ITextText4:
- dc.b 'Should I make a SnapShot?',0
- cnop 0,4
- IText5:
- dc.b 3,0,RP_JAM2,0
- dc.w 6,3
- dc.l TAttr
- dc.l ITextText5
- dc.l 0
- ITextText5:
- dc.b 'YES',0
- cnop 0,4
- IText6:
- dc.b 3,0,RP_JAM2,0
- dc.w 6,3
- dc.l TAttr
- dc.l ITextText6
- dc.l 0
- ITextText6:
- dc.b 'NO',0
- endc
-
- cnop 0,4
-
- *--------------------------------------------------------------------------
- * New IFF chunk format -
- * PGTB = Program Traceback, header for chunk
- * FAIL = reason for and environment of crash
- * REGS = registers at time of crash, including PC and CCR
- * VERS = version, revision, name of this program
- * STAK = ENTIRE stack at time of crash or, alternately,
- * the top and bottom 4k if the stack used is > 8k
- * UDAT = optional user data dump (if _ONGURU is set to a
- * function pointer in the user's program)
- *--------------------------------------------------------------------------
-
- PGTB dc.b 'PGTB'
- Length dc.l 0 * length of chunk (in longwords)
-
- subFAIL dc.b 'FAIL'
- FAILlen dc.l 9
- NameLen dc.l 0 * length of program name
- chunk_len_1 equ *-PGTB
- Environment dc.l 0 * CPU (, Math)
- VBlankFreq dc.l 0 * PAL = 50, NTSC = 60 (approx.)
- PowerSupFreq dc.l 0 * Europe = 50, USA = 60 (approx.)
- Starter dc.l 0 * 0 = WB, -1 = CLI
- GURUNum dc.l 0 * cause of crash (GURU #)
- SegCount dc.l 1 * # hunks in seglist
- chunk_len_2 equ *-Environment
-
- subFMEM dc.b 'FMEM' * FMEM - free memory at crash
- dc.l 6
- chipAvail dc.l 0 * available chip memory
- chipMax dc.l 0 * maximum chip memory
- chipLargest dc.l 0 * largest chip memory
- fastAvail dc.l 0 * available fast memory
- fastMax dc.l 0 * maximum fast memory
- fastLargest dc.l 0 * largest fast memory
- FMEMlen equ *-subFMEM
-
- subREGS dc.b 'REGS' * REGS - register storage field
- REGSlen dc.l 18
- GURUAddr dc.l 0 * PC at time of crash
- Flags dc.l 0 * Condition Code Register (CCR)
- DDump dc.l 0,0,0,0,0,0,0,0 * data registers
- ADump dc.l 0,0,0,0,0,0,0 * address registers
- A7Store dc.l 0
-
- subVERS dc.b 'VERS' * VERS - program version field
- dc.l 6
- dc.l VERSION * version #
- dc.l REVISION * revision #
- dc.l 3 * length of name of program
- IFD RESIDENT
- dc.b 'catchres.o',0,0 * name
- ENDC
- IFND RESIDENT
- dc.b 'catch.o ',0,0 * name
- ENDC
-
- subSTAK dc.b 'STAK' * STAK - stack field
- STAKlen dc.l 4
- Type dc.l 0 * 0 = Info
- StackTop dc.l 0 * top of stack pointer
- StackPtr dc.l 0 * current Stack Pointer
- StackLen dc.l 0 * # bytes used on stack
- chunk_len_3 equ *-subREGS
-
- STAK2 dc.b 'STAK'
- s2len dc.l 1 * length of subtype
- dc.l 1 * 1 = whole stack
- STAK2len equ *-STAK2
-
- STAK3 dc.b 'STAK'
- dc.l 1025
- dc.l 2 * 2 = top 4k of stack
- STAK3len equ *-STAK3
-
- STAK4 dc.b 'STAK'
- dc.l 1025
- dc.l 3 * 3 = bottom 4k of stack
- STAK4len equ *-STAK4
-
- STAK5 dc.b 'STAK'
- _STAKOffset dc.l 0
- dc.l 4 * 4 = user defined amount
- STAK5len equ *-STAK5
-
- UDAT dc.b 'UDAT'
- dc.l 0
- UDATlen equ *-UDAT
- endc
-
-
-
- section __MERGED,BSS
-
- xdef NULL,SysBase,DOSBase
- xref _FPERR
-
- xref _WBenchMsg
- xref __curdir
- xref _OSERR,_SIGFPE,_ONERR,_ONEXIT,_ONBREAK
- xref _SIGINT
- xref _ProgramName,_StackPtr,__base
-
- ifd CATCH
- xdef _ONGURU,_FMEM,_STAKOffset
- endc
-
-
-
- NULL ds.b 4
- DOSBase ds.b 4
- SysBase ds.b 4
- Commandbuf ds.b 4
- Commandlen ds.b 4
- mystk_Lower ds.b 4
- mystk_Upper ds.b 4
- mystk_Pointer ds.b 4
- newst_Lower ds.b 4
- newst_Upper ds.b 4
- newst_Pointer ds.b 4
-
-
-
- ifd RESIDENT
- realdatasize ds.b 4 * size of memory allocated for data +
- * possible stack
- endc
- ifnd RESIDENT
- newstack ds.b 4 * pointer to new stack (if needed)
- newstacksize ds.b 4 * size of new stack
- endc
-
- END
-