mdoerr@uklirb.UUCP (10/10/86)
Ask > Challenge: can anybody devise a way to stop a running program that does > not do any I/O (i.e. does not respond to ctrl-C), but WITHOUT rebooting!? > (I currently embed calls to keybrk() here and there in my loops, where > keybrk() is just a call to GEMDOS to see if ctrl-C was pressed, and an exit() > if it was... - that works but is ugly!) - I would like some program that > responds to an interrupt (say the alt-Help) and stops the currently running > application, in a clean way (no crashes or reboots, ability to do it > repeatedly in a session). I would like this ditty to be a separate program > that you run once and then it sits resident in RAM. I have tried such > a thing, with the interrupt handler doing an RTE to itself and then calling > gemdos(0) - but I get mysterious crashes after a few uses! Any ideas? > > - Moshe Braner and thou shall receive: WATCHER is another goodie from the Happy-Computer PD-Disk (remember MONST). It should work as follows: If your program gets stuck in an endless loop then press 3 times CTRL-B and once CTRL-C The executable has been UUENCODED on the ST. The source is for assembly language adventurers. As an additional bonus I've thrown in TBUG.PRG. Place multiple copies of it into the AUTO folder of your best friend and watch his/her eyes fall out. Have fun, but don't flame me! Michael Doerr Uni. of Kaiserslautern (Germany) uucp: ...!seismo!unido!uklirb!mdoerr ----------------- This is NO shell archive ------------------ begin 777 WATCHER.PRG M8!H %2 "@ !@ "!O 0L/ 0#<J ,W*@ M%-RH !PCQ@ 5P_/ !/SP #DY.6(\CP 6 O/ $H_/ F3DY<CT)G M+SD %</SP ,4Y!,#D 14Y4@@>0 !%9"04JP$ !G"%A!LD!F]$YU(_D M !P !9"/\ B '!%\! )+P "63G4CSP 6@O.0 61.=2!Y M !:# 0P'P@ &<"3G5"N0 7 @>0 6 B: ,B@ !#0H 8V* (. ,Z M K9"9@).=6X$. %91 PQ )0 V8&4KD %P6$6X16SLMD)N&$)%. ,,,0 " M4 -F!E*Y !<%A%N$5L[ RY P 7!L DYU('D %H(^@ @ 6PA M? 2@ DYU+SD %L2.?@X"\\ !4C\\ I.05R/2CD %39P9,WP<' I3G5"9TY!" !@2!A N!@X(!@@0!BX<$ H(!@H*#@!, end --------------- Cut Here --------------------------------- begin 777 TBUG.PRG M8!H +V $*G/SP ($Y!7(\CP @A( MY__^82),WW__+SD ((/SP ($Y!7(\_/ +SP /H/SP ,4Y!('D 16 M(^@ ! @Q#^0 (8A20 $0?D )*(\@ (^0?D *&(\@ )",#D M 2\ H #^(\ (8(_P "1DYU0H 0.0#_@@'A@- Y /^" ^& M(\ (<(#D (<T+D (8($!#^0 B!A $B(#D (<T+D (8($ B M>0 CXD>0 D)A #H80 !($* $#D _X(###D P #_@@-L$-"\ 0+ Y M /^"!VSX8!RP.0#_@@=O[M"\ 0,"\ _[ Y /^"!VSX(#D (<T+D M (8($!#^0 B!A "Z(#D (<T+D (8($!2N0 D9*: * 9@92N0 M D8,N0 @ )&;UY#^0 FA%^0 J2S^0 CYF#$/Y "2D7Y " MAB/) "/B/* "0B/\ D8&N0 % (8#+D #_X "&&T2 M,#D 2\ H #^(\ (83G5P#C(:1E"#4$90,A PF8-0T?P !04<C_ MZDYU< XRT-'\ 4%'(__9.=7 .,)G1_ %!1R/_V3G4@>0 @RQ_ M !G DZ03G4 M P?F?;R9F!6I$8MUKI&( M%:@1BW_^C; 'X / 8# &?@/;X9F96HT8AUKA&)%:C1B'_^#;$'X / 8 M P?F?_R?^!_Y'_M__I_X'_@?^W_^C_ 'X / 8# &?@/_X?^9_XW_A__A_Y M'_C?^'_^#_$'X / 8 H0RD@3RX@2F]P<&EC:"P@06T@2&]N:6=B;&5E:R Q M-"P@,S,P,"!"<F%U;G-C:'=E:6< #! F!@H&!@82"AH&!@@*!@@&3 8( 2"@8(# H(!@8(!@8&"@H*%$0 end --------------------- Cut Once More ------------------------- * watcher.s * written by ww&js on 13.2.86/14.2.86 * Dieses Programm ermoeglicht es, Programme mit Endlosschleifen * abzubrechen. gemdos equ 1 * System-Aufruf Konstanten xbios equ 14 print equ $09 * GEMDOS Systemaufrufe keep equ $31 readline equ $0a iorec equ 14 * XBIOS Systemaufrufe super equ 38 ibuf equ 0 * Offsets of struct iorec isize equ 4 ihd equ 6 itail equ 8 ctrl_b equ 2 * Control-B _vblqueue equ $456 * Systemaddresen: VBL Adressen nvbls equ $454 * Anzahl VBL-Routinen level_4 equ $70 * Level 4 Interruptvector .bss laenge .ds.l 1 iorecp .ds.l 1 oldlevel .ds.l 1 merksp .ds.l 1 merkpc .ds.l 1 count .ds.l 1 * Berechne Groesse des Programms: .text move.l 4(sp),a0 * basepage Adresse move.l #$100,d6 * basepage Groesse add.l 12(a0),d6 * text Groesse add.l 20(a0),d6 * data Groesse add.l 28(a0),d6 * bss Groesse move.l d6,laenge * abspeichern move #1,-(sp) * XBIOS iorec(1) (Tastaturpuffer) move #iorec,-(sp) * (liefert den Beschreibungsblock) trap #xbios addq.l #4,sp move.l d0,iorecp * Adresse merken move.l #main,-(sp) * Routine main im Supervisormode ... move #super,-(sp) * ...laufen lassen trap #xbios addq.l #6,sp clr -(sp) * GEMDOS keep(laenge,0) move.l laenge,-(sp) * (Programm wird beendet, aber... move #keep,-(sp) * ...im Speicher resident gehalten) trap #gemdos * Routine vbl in Liste der VBL-Routinen eintragen main move nvbls,d0 * Anzahl VBL-Routinen lsl #2,d0 move.l _vblqueue,a0 * Adr. der VBL-Routinen clr d1 loop1 tst.l (a0,d1) * Routine frei? beq free * ja, freier Platz gefunden addq #4,d1 * naechste Routine cmp d0,d1 * Ende? bne loop1 rts * keine freie Routine gefunden, return * freie VBL-Routine gefunden; Interruptvektor und eigene Routine * eintragen: free move.l level_4,oldlevel * bisherigen Int.-Vektor merken move.l #newlevel,level_4 * neuen Int.-Vektor eintragen lea (a0,d1),a2 * Adr. der freien VBL-Routine move.l #vbl,(a2) * eigene VBL-Routine eintragen rts * fertig * eigene Level 4 Interruptbehandlung (VBL Interrupt) newlevel move.l sp,merksp * Stackpointer merken move.l oldlevel,-(sp) * zur System-Interruptbehandlung springen rts * eigene VBL-Routine vbl move.l merksp,a0 * Interrupt-Stackpointer laden move (a0),d0 * SSR des unterbrochenen Programms and #$2000,d0 * User/Supervisor Bit testen beq continue * nicht gesetzt -> User-Mode rts * unterbrochenes Programm war im Super- * * visor Mode; nicht abbrechen * unterbrochenes Programm ist im User-Mode; XBIOS Tastaturpuffer * nach CTRL-B durchsuchen: continue clr.l count * Zaehler init. move.l iorecp,a0 * Adr. Pufferbeschreibungsblock move.l ibuf(a0),a1 * Adr. Tastaturpuffer move isize(a0),d1 * Puffergroesse (in bytes) move ihd(a0),d2 * Ringpuffer Anfang (Index) move itail(a0),d3 * Ringpuffer Ende (Index) move d3,d4 * D4: Ende fuer erste Schleife move d2,d5 * D5: Laufvariable cmp d2,d3 * Testen ob Puffer leer bne cont2 * nicht leer rts * leer; cont2 bgt nowrap * nur eine Schleife move d1,d4 * 2 Schleifen; erste bis Puffergroesse... subq #4,d4 * ...-4 nowrap cmp.b #ctrl_b,3(a1,d5) * CTRL-B im Puffer? bne cont3 * nein addq.l #1,count * zaehlen cont3 addq #4,d5 * naechster Index cmp d5,d4 * Ende erreicht? bge nowrap * Nein, weiter cmp d2,d3 * Test ob 2 Schleifen bgt ende * nein, fertig mit Durchsuchen clr d5 * Schleife 2 von 0 bis... move d3,d4 * ...Ende Index loop3 cmp.b #ctrl_b,3(a1,d5) * Schleife wie oben bne cont4 addq.l #1,count cont4 addq #4,d5 cmp d5,d4 bge loop3 * Schleifenende ende cmp.l #3,count * mindestens 3 mal CTRL-B gefunden? bge kill * ja, kill'em all rts * sonst normaler Ruecksprung * Ruecksprung des unterbrochenen Programms umleiten: kill move.l merksp,a0 * Interrupt Stackpointer move.l 2(a0),merkpc * Original-Ruecksprungadresse merken move.l #abort,2(a0) * neue Ruecksprungadr. dafuer eintragen rts * Ende VBL-Routine * An diese Stelle wird der Ruecksprung des unterbrochenen Programms * umgeleitet, falls 3 mal CTRL-B im Tastaturpuffer gefunden wurde abort move.l merkpc,-(sp) * Original-Ruecksprungadresse movem.l d0-d2/a0-a2,-(sp) * Register retten move.l #ibuff,-(sp) * Eingabezeile lesen move #readline,-(sp) trap #gemdos addq.l #6,sp tst.b ibuff+1 * Eingabe da? beq exit * Nein, vermutlich EOF bei Input Redirection movem.l (sp)+,d0-d2/a0-a2 * ansonsten Programm fortsetzen rts exit clr -(sp) trap #gemdos .data ibuff .dc.b 8,0 .ds.b 8 .end ------------------ This Is The End ----------------------------
braner@batcomputer.TN.CORNELL.EDU (braner) (10/18/86)
[]
Finally, it seems I am on the right track towards writing a program
that will stop other programs. The following, after running, sits
in RAM invisibly, until you hold down Control, Alternate and BOTH
shift keys and press another key (e.g. Return). The program in
progress at the time will be terminated.
One problem I had to solve was how to avoid OS calls from
inside the interrupt handler. I did that by using direct
peeking of the shift keys status, and by doing the actual
termination of the program AFTER the RTE.
WARNING: This program uses some addresses that are essential
but not official. I found them out by snooping around in the
ROM code. They may be changed in future versions of TOS.
Atari will send their death squads after you if you use these
addresses in a commercial program!
Here is the heart of the routine, in commented assembly syntax:
asm {
/*
* call supexec() to install our thing
*/
PEA install(PC)
MOVE.W #38,-(A7)
TRAP #14
ADDQ.L #6,A7
/*
* terminate and stay resident
*/
CLR.W -(A7)
MOVE.L #0x00000200,-(A7)
MOVE.W #0x31,-(A7)
TRAP #1
install:
/*
* install our keyboard interrupt handler
* (has to be done in supervisor mode)
*/
PEA handler(PC)
MOVE.L (A7)+,0x118 /* pointer to kbd intrpt subr */
RTS
handler:
/*
* check keyboard shift status
*/
CMPI.B #0x0F,0xE1B /* shift status variable */
BCS.S normal
/*
* overwrite return address with our posthandler
*/
PEA killer(PC)
MOVE.L (A7),6(A7)
ADDQ.L #4,A7
normal:
/*
* go do the usual thing, usually return to interrupted program
*/
JMP 0xFC281C /* where $118 pointed to */
killer:
/*
* RTE to here to terminate program
*/
CLR.L -(A7)
TRAP #1
/*
* should not come back, but: 6 bombs if you do
*/
CHK #-1,D0
}
Here is a hex dump of the complete program (140 bytes):
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
60 1A 00 00 00 70 00 00 00 00 00 00 00 00 00 00
00 00 00 00 00 00 00 00 00 00 FF FF 2A 4F 2A 6D
00 04 20 2D 00 0C D0 AD 00 14 D0 AD 00 1C D0 BC
00 00 01 00 2F 00 2F 0D 3F 00 3F 3C 00 4A 4E 41
DF FC 00 00 00 0C 48 7A 00 1A 4E 71 3F 3C 00 26
4E 4E 5C 8F 42 67 2F 3C 00 00 02 00 3F 3C 00 31
4E 41 48 7A 00 08 21 DF 01 18 4E 75 0C 38 00 0F
0E 1B 65 0A 48 7A 00 0E 2F 57 00 06 58 8F 4E F9
00 FC 28 1C 42 A7 4E 41 41 BC FF FF
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
Please try it out and comment on its performance under various
circumstances. Remember: the object is a clean break, with no
after effects, avoiding RESETs when possible.
- Moshe Braner
<braner@amvax.tn.cornell.edu>
P.S. I have not tried "Watcher" yet - it may be similar or better?
braner@batcomputer.TN.CORNELL.EDU (braner) (10/19/86)
[]
Recently I posted here a program that, after running it once,
was supposed to kill any program in progress upon pressing
Ctrl-Alternate-both_Shifts-Return. Turns out that the program
did not work outside of micro-C-Shell, and poorly even there!
I took a careful look at WATCHER.S (also posted here recently) and
noticed there that a kill is NOT done if the interrupted program
was in supervisor mode. I don't know why, maybe because that
signals that another interrupt handler (or TRAP!) is in progress.
Incorporating that idea, jumping to the last part of the ROM
bomb handler to do the termination, and some streamlining yielded
the following program which seems to work a lot better.
(you have to press Ctrl-Alt-both_Shifts-Return several times
sometimes, probably in order to catch it in user mode...)
Mystery remaining:
When it terminates, two bombs are displayed. WHY?
WARNING:
This program uses some addresses that are essential
but not official. I found them out by snooping around in the
ROM code. They may be changed in future versions of TOS.
Atari will send their death squads after you if you use these
addresses in a commercial program!
Here is the heart of the routine, in commented assembly syntax:
asm {
/*
* call supexec() to install our thing
*/
PEA install(PC)
MOVE.W #38,-(A7)
TRAP #14
ADDQ.L #6,A7
/*
* terminate and stay resident
*/
CLR.W -(A7)
MOVE.L #0x00000200,-(A7)
MOVE.W #0x31,-(A7)
TRAP #1
install:
/*
* install our keyboard interrupt handler
* (has to be done in supervisor mode)
*/
PEA handler(PC)
MOVE.L (A7)+,0x118 /* pointer to kbd intrpt subr */
RTS
handler:
/*
* check mode of interrupted program and keyboard shift status
*/
BTST #5,(A7) /* check for super mode */
BNE.S normal
CMPI.B #0x0F,0xE1B /* kbd state variable */
BCS.S normal
/*
* overwrite return address with fatal address
*/
MOVE.L #0xFC0A5A,2(A7) /* near end of _term */
normal:
/*
* go do the usual thing, usually return to interrupted program
*/
JMP 0xFC281C /* where $118 pointed to */
}
Here is a hex dump of the complete program (92 bytes):
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
60 1A 00 00 00 70 00 00 00 00 00 00 00 00 00 00
00 00 00 00 00 00 00 00 00 00 FF FF 48 7A 00 18
3F 3C 00 26 4E 4E 5C 8F 42 67 2F 3C 00 00 02 00
3F 3C 00 31 4E 41 48 7A 00 08 21 DF 01 18 4E 75
08 17 00 05 66 10 0C 38 00 0F 0E 1B 65 08 2F 7C
00 FC 0A 5A 00 02 4E F9 00 FC 28 1C
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
Any comments/experiences welcome!
- Moshe Braner
<braner@amvax.tn.cornell.edu>
DISCLAIMER: The mention of "death squads" was not meant to discredit
Atari, Corp in any way. Also, I do not want to trivialize the grim
reality of death sqauds in some parts of "civilization".
braner@batcomputer.TN.CORNELL.EDU (braner) (10/20/86)
[] Reminder: after running this program ONCE, holding down Control, Alternate and BOTH Shift keys and pressing any other key will stop the program running at the time, as long as it is in user mode. Since programs call OS routines which execute in supervisor mode, and since this program will act only if the interrupted program is in user mode, you may have to repeat pressing the last key several times. The two bombs were due to the RTE to $FC0A5A in user mode, where a MOVE.L #$93A,$4A2 is attempted. Here is a corrected version with BSET #5,(A7) added before the RTE, to keep it in supervisor mode. (Hex dump of the complete program - 96 bytes): ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 60 1A 00 00 00 70 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 FF FF 48 7A 00 18 3F 3C 00 26 4E 4E 5C 8F 42 67 2F 3C 00 00 02 00 3F 3C 00 31 4E 41 48 7A 00 08 21 DF 01 18 4E 75 08 17 00 05 66 14 0C 38 00 0F 0E 1B 65 0C 08 D7 00 05 2F 7C 00 FC 0A 5A 00 02 4E F9 00 FC 28 1C ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ Have a clean break! - Moshe Braner <braner@amvax.tn.cornell.edu>