home *** CD-ROM | disk | FTP | other *** search
/ Simtel MSDOS 1992 June / SIMTEL_0692.cdr / msdos / c / break.arc / BREAK.ASM next >
Assembly Source File  |  1985-08-21  |  14KB  |  597 lines

  1.     title BREAK - handle ctrl-break
  2.     include    m:dos.mac
  3. debug=0
  4.     subttl Documentation
  5. ;*****************************************************************************
  6. ; This code uses the standard Lattice interface.  The logical device 'm:'
  7. ; represents the memory model being used.  Supply your own path to dos.mac
  8. ;
  9. ; This code is intended to allow me to break out of various perverse
  10. ; loops in my application code.  
  11. ;
  12. ;              * * * W A R N I N G * * *
  13. ;
  14. ; This code is an extreme *HACK*.  It solves my problem.  It may not solve
  15. ; yours.  I make no guarantees.  Use at your own risk!
  16. ;
  17. ; It was tested using a Hercules monocrhome card.  I make no guarantees that
  18. ; I have done anything reasonable with respect to color cards.
  19. ;
  20. ;
  21. ;                 Restrictions
  22. ;
  23. ; The current code works only for the Lattice C compiler using the S or D
  24. ; models (64K program segment).  It depends upon the fact that the CS register
  25. ; is global to the entire code body.  It will probably not have the desired
  26. ; effect if you are executing out of the P or L models.
  27. ;
  28. ;
  29. ; Failure to clear the handler before exiting the program will lead to
  30. ; various bizarre behavior.  Calling the initialization more than once
  31. ; will confuse the world beyond practical recovery.
  32. ;
  33. ;                   Abstract
  34. ;
  35. ; A procedure is called to establish the existence of the control-break 
  36. ; handler (interrupt 1BH).  If a control-break is taken during program
  37. ; execution, and the CS:IP was in the user's code, execution is terminated.
  38. ;
  39. ; This code is to be linked into the user's application.
  40. ;                Hacks
  41. ;
  42. ; What the initialization procedure does is record the CS: of the caller, 
  43. ; which in the small memory model must be the CS: of all the code.  It then
  44. ; sets up the interrupt 1BH to point to its intercept routine.
  45. ;
  46. ; The finalization procedure restores the interrupt vector 1BH to its previous
  47. ; value.
  48. ;
  49. ; The intercept routine uses the BIOS calls to write an informative message to
  50. ; the user.  It then reaches back into the stack a fixed number of bytes and
  51. ; examines the CS: at the time the interrupt from the keyboard was taken.
  52. ;
  53. ; BEWARE!  If you are not using the BIOS intercepts but are using any sort
  54. ; of keyboard extender (BUF160, ProKey, SuperKey) you will have to determine
  55. ; where this interrupt has stored the old CS:IP.  Have fun.
  56. ;
  57. ; If the CS: of the executing code (at the time the 1BH was taken) was in the
  58. ; user space, the IP: is modified to point to some termination code.  Normal
  59. ; return is then taken, except that when the BIOS exits the keyboard interrupt
  60. ; it returns to the exit control code and the process terminates.
  61. ;
  62. ;             Possible extensions
  63. ;
  64. ; SETCTL(x) where x is the address of a procedure could call an arbitrary
  65. ; procedure.  Note, however, that the old CS:IP is currently destroyed, so
  66. ; anyone extending this would have to make appropriate changes.
  67. ;
  68. ;               * * * B E W A R E * * *
  69. ;
  70. ; This code is delicate and high-risk.  It works well enough for my one
  71. ; application.  I may have missed all sorts of bizarre DOS or BIOS hacks.
  72. ;
  73. ; It is not guaranteed to be bug-free.  The user assumes all risk in using
  74. ; it.  This is code that should be used only if you understand enough of
  75. ; DOS/BIOS hacking to be sure it will work for you.
  76. ;
  77. ;
  78.  
  79.     subttl Interface specifications
  80. ;-----------------------------------------------------------------------------
  81. ; extern void SETCTL();
  82. ;    
  83. ; Effects: 
  84. ;    Establishes a Ctrl-brk abort handler
  85. ;
  86. ; Limitations:
  87. ;    May only be called once; subsequent calls may damage universe
  88. ;-----------------------------------------------------------------------------
  89. ; extern void CLRCTL();
  90. ;
  91. ; Effects: 
  92. ;    Resets the Ctrl-brk abort handler
  93. ;
  94. ; Limitations:
  95. ;    Should be called only if SETCTL() has been called.  However, if
  96. ;    SETCTL has not already been called, nothing will happen.
  97. ;
  98. ;*****************************************************************************
  99.  
  100.     subttl Working storage
  101.  
  102. ; This storage is in the data segment
  103.  
  104.     DSEG
  105.  
  106. UserCS    DW    ?        ; CS: of where we were interrupted
  107. UserIP    DW    ?        ; IP: of where we were interrupted 
  108. UserIPL DW    ?        ; Address of user IP: (relative to seg reg)
  109. MyCS    DW    ?        ; CS: of where we were set up from
  110.  
  111. apage    DB    ?        ; Current display page
  112.     ENDDS
  113.  
  114.  
  115.     subttl Vector locations
  116. VECTORS    SEGMENT AT 0H
  117.     ORG    1BH*4        ; ctrl-brk interrupt interrupt 
  118. CTLBRK  LABEL    DWORD
  119. CTLBRK_IP DW            ; IP of control-break vector
  120. CTLBRK_CS DW            ; CS of control-break vector
  121. VECTORS ENDS
  122.  
  123.  
  124.  
  125.     subttl  Code segment storage 
  126. ;
  127. ; This is in the code segment because I don't know how to make it addressible
  128. ; in the data segment
  129. ;
  130.     PSEG
  131.  
  132. OLD_REQ    label    DWORD        ; we store former 1BH vector here
  133. OLD_IP    DW    0        ; 0, not ?
  134. OLD_CS    DW    0        ; 0, not ?
  135.  
  136. OldAX    DW    ?
  137. OldSS    DW    ?        ; old stack segment
  138. OldSP    DW    ?        ; old stack pointer
  139.     DW    512 DUP(?)    ; local stack space for intercept routine
  140. STACK    label    WORD
  141.  
  142.     subttl  wdigit - Write a hex digit
  143. ;-----------------------------------------------------------------------------
  144. ;                    wdigit
  145. ;
  146. ; Inputs:
  147. ;    AX: Single hex digit to convert (0..15)
  148. ;    BX: Place to put it
  149. ;
  150. ; Effects:
  151. ;    AX is converted from binary to hex and placed at the location
  152. ;    defined by ES:BX
  153. ; Modified:
  154. ;    AX
  155. ;-----------------------------------------------------------------------------
  156. wdigit    PROC    NEAR
  157.     push    DI            ; ... working registers
  158.     push    SI
  159.     mov    DI,BX            ; get destination
  160.     and    AX,0FH            ; mask off l/o bits
  161.     add    AX,OFFSET TBL        ; get address of decoded byte
  162.     mov    SI,AX            ; make available for indexing
  163.     mov    AL,CS:[SI]        ; get the byte "0".."F"
  164.     mov    ES:[DI],AL        ; store it at the destination
  165.     pop    SI            ; ...restore working regs
  166.     pop    DI
  167.     ret                ; return
  168. wdigit    ENDP
  169.  
  170. TBL:    DB    '0123456789ABCDEF'    ; hex digit decode table
  171.  
  172.     subttl    cvt1
  173. ;-----------------------------------------------------------------------------
  174. ;                     cvt1
  175. ;
  176. ; Inputs:
  177. ;    AX: Word to convert
  178. ;    ES:BX Place to put character
  179. ;
  180. ; Effects:
  181. ;    Converts l/o bits of AX to character, places character at ES:BX
  182. ;    decrements BX, shifts AX right 4 bits
  183. ;
  184. ; Output conditions:
  185. ;    BX--
  186. ;    AX >>= 4
  187. ;-----------------------------------------------------------------------------
  188. cvt1    PROC    NEAR
  189.     push    AX    ; save AX
  190.     call    wdigit        ; write digit to buffer ES:BX
  191.     pop    AX        ; get old AX
  192.     SHR    AX,1        ; shift right 4
  193.     SHR    AX,1        ; ...
  194.     SHR    AX,1        ; ...
  195.     SHR    AX,1        ; ...
  196.     dec    BX        ; select next higher character position
  197.     ret
  198. cvt1    ENDP
  199.  
  200.  
  201.  
  202.     subttl  cvt - convert binary to hex
  203. ;-----------------------------------------------------------------------------
  204. ; Inputs:
  205. ;    AX - value to convert
  206. ;    ES:BX - place to put it
  207. ;
  208. ; Effects:
  209. ;    Converts binary value in AX to 4-digit hex value and places it in
  210. ;    location indexed by BX (BX points to low-order position, and is
  211. ;    decremented for each position
  212. ;
  213. ; Modified:
  214. ;    AX, BX
  215. ;-----------------------------------------------------------------------------
  216. cvt    PROC    NEAR
  217.  
  218.     call    cvt1        ; write first digit
  219.     call    cvt1        ; write second digit
  220.     call    cvt1        ; write third digit
  221.     call    cvt1        ; write fourth digit
  222.     ret
  223.  
  224. cvt    ENDP
  225.  
  226.     subttl    CTLSEEN - CTRL-BREAK handler
  227. ;-----------------------------------------------------------------------------
  228. ;                    ctlseen
  229. ; Inputs:
  230. ;    None; called as interrupt routine via interrupt 1BH
  231. ;
  232. ; Result:
  233. ;    AL=0FFH
  234. ;
  235. ; Effects:
  236. ;     Issue message: 'Ctrl-brk seen at use PC xxxx:xxxx'
  237. ;
  238. ;      If called from user program, sets up user CS:IP return value to
  239. ;    return to "exit code" which is call on C '_exit' routine.
  240. ;
  241. ;-----------------------------------------------------------------------------
  242.  
  243. CTLSEEN    PROC FAR
  244.  
  245.  
  246. if debug
  247.     int  3
  248. endif
  249. ; Set up user stack
  250.  
  251.     mov    OldSS,SS    ; Save old stack
  252.     mov    OldSP,SP    ; ...
  253.     mov    OldAX,AX    ; save AX
  254.     cli            ; interrupts off
  255.     mov    AX,CS        ; Get CS: so we can make our local stack
  256.                 ; addressible
  257.     mov    SS,AX        ; New stack segment
  258.     mov    SP,offset STACK    ; ...
  259.     sti            ; interrupts back on
  260.  
  261.     push    BX        ; Save us some working regs
  262.     push    CX        ; ...
  263.     push    DX        ; ...
  264.     push    ES        ; ...
  265.     push    BP        ; ...
  266.     push    DS        ; ...
  267.     
  268.     mov    AX,OldSP    ; We want to look at the user stack
  269.     mov    ES,OldSS    ; which will be in ES:AX
  270.  
  271. ; AX is the top of the stack upon entry (before stack switching)
  272. ;
  273. ;       +---------------+
  274. ;  AX ---> |      IP       | +0        ; return point to Interrupt handler
  275. ;       +---------------+
  276. ;       |      CS       | +2        ; return point to interrupt handler
  277. ;       +---------------+
  278. ;       |     flags     | +4
  279. ;       +---------------+
  280. ;       |      BP       | +6        ; saved regs
  281. ;       +---------------+
  282. ;       |      AX       | +8
  283. ;       +---------------+
  284. ;       |      BX       | +10
  285. ;       +---------------+
  286. ;       |      CX       | +12
  287. ;       +---------------+
  288. ;       |      DX       | +14
  289. ;       +---------------+
  290. ;       |      SI       | +16
  291. ;       +---------------+
  292. ;       |      DI       | +18
  293. ;       +---------------+
  294. ;       |      DS       | +20
  295. ;       +---------------+
  296. ;       |      ES       | +22
  297. ;       +---------------+
  298. ;       | User IP       | +24    ; return to user code
  299. ;       +---------------+
  300. ;       | User CS       | +26    ; return to user code
  301. ;       +---------------+
  302.  
  303. ; Establish addressibility of DS
  304.  
  305. ; DS := Seg(&UserIP);
  306.  
  307.     mov    BX,SEG UserIP        ; make our data area available by
  308.                     ; using SEG of some variable in it
  309.     mov    DS,BX            ; to DS:
  310.  
  311.     mov    BP,AX            ; AX is now in BP, so ES:BP holds
  312.                     ; old SS:SP
  313. ; UserIP := * (OldSS:(OldSP+24))
  314.  
  315.     mov    AX,ES:[BP+24]        ; Magic offset!  Get user IP
  316.     mov    UserIP,AX        ; Store it for later use
  317.     lea    AX,ES:[BP+24]        ; Magic offset!  Get address of where
  318.                     ; it was
  319. ; UserIPL :=  (OldSS:(OldSP+24))
  320.     mov    UserIPL,AX        ; Store this as the UserIP Location
  321.  
  322. ; UserCS := * (OldSS:(OldSP+26))
  323.  
  324.     mov    AX,ES:[BP+26]        ; Magic offset! Get user CS:
  325.     mov    UserCS,AX        ; Save it for later use
  326.  
  327. ; Video_state(&apage)
  328.  
  329.     mov    AH,15        ; return video state
  330.     int    10H
  331.                 ; AH = current video mode
  332.                 ; AL = #of columns on screen    
  333.     mov    apage,BH    ; active page in BH
  334.  
  335. ; /* Convert CS: to hex */
  336.  
  337. ;    cvt(UserCS,&MSGCS)
  338. ;        /* call cvt(AX,ES:BX) */
  339. ;    
  340.     mov    AX,CS        ; Get CS: to make msg addressible
  341.     mov    ES,AX        ; Put in ES
  342.     mov    BX,OFFSET MSGCS    ; ES:BX = Place to put digits
  343.  
  344.     mov    AX,UserCS    ; AX gets value to put into message
  345.     call    cvt        ; Go convert it, modifying message
  346.  
  347. ; /* Convert IP: to hex */
  348.  
  349. ;    cvt(UserIP,&MSGIP)
  350. ;        /* call cvt(AX,ES:BX) */
  351. ;    
  352.     mov    AX,CS        ; Get CS: to make msg addressible
  353.     mov    ES,AX        ; put in ES
  354.     mov    BX,OFFSET MSGIP    ; ES:BX = place to put digits
  355.  
  356.     mov    AX,UserIP    ; AX gets value to put into message
  357.     call    cvt        ; Go convert it, modifying message
  358.  
  359. ; Write_string(mode=0,Attr=rev,string=MSG1,length=MSG1L,CursorX=0,CursorY=24,page=apage)
  360.  
  361.     ; ES:BP = &MSG1;   /* string */
  362.  
  363.     mov    AX,CS
  364.     mov    ES,AX
  365.     mov    BP,OFFSET MSG1
  366.  
  367.     ; CX = strlen(MSG1); /* length */
  368.  
  369.     mov    CX,MSG1L
  370.  
  371.     ; DH = 24;        /* CursorY */
  372.  
  373.     mov    DH,24
  374.  
  375.     ; DL = 0;        /* CursorX */
  376.  
  377.     mov    DL,0
  378.  
  379.     ; BH = apage;        /* page */
  380.  
  381.     mov    BH,apage
  382.  
  383.     ; AL = 1;        /* mode: 1 -> BL has attr, string has chars,
  384.     ;            move cursor */
  385.  
  386.     mov    AL,1            ; 
  387.  
  388.     ; BL = 70H;        /* attribute: 70H = Reverse video block */
  389.  
  390.     mov    BL,70H            ; 
  391.  
  392.     mov    AH,19            ; write string
  393.     int    10H            ; ...
  394.  
  395.  
  396. ; /* If we came from the user's program, abort */
  397.  
  398. ; if(UserCS == MyCS) _exit()
  399.  
  400. ; /* Store the IP of the abort code in the return pointer, then return     */
  401.     mov    AX,UserCS
  402.     cmp    AX,MyCS
  403.     jne    NotMe            ; not in my program, go on
  404.  
  405.     mov    BP,UserIPL        ; get address of user IP
  406.     mov    AX,OFFSET ByeBye    ; plan to die upon return
  407.     mov    ES,OldSS        ; make segment addressible
  408.     mov    ES:[BP],AX        ; store the updated pointer
  409.  
  410. NotMe:
  411.  
  412.  
  413. ; /* Otherwise, continue as if we weren't here */
  414.  
  415.     pop    DS
  416.     pop    BP
  417.     pop    ES
  418.     pop    DX
  419.     pop    CX
  420.     pop    BX
  421.  
  422. ; /* Reset to old user stack */
  423.  
  424.     cli
  425.     mov    SS,OldSS
  426.     mov    SP,OldSP
  427.     sti
  428.     mov    AX,OldAX
  429.  
  430.  
  431. ; /* Now go to the real handler */
  432.  
  433.     jmp    OLD_REQ
  434.  
  435. CTLSEEN    ENDP
  436.  
  437. ; The message and its various subcomponents
  438.  
  439. MSG1:    DB    'Ctrl-break at PC '
  440.     DB    'xxxx'
  441. MSGCS    equ    $-1
  442.     DB    ':'
  443.     DB    'xxxx'
  444. MSGIP    equ    $-1
  445.  
  446.     DB    0DH,0AH        ; CR,LF
  447. MSG1L   equ     $-MSG1
  448.  
  449.     subttl    SETCTL - Set CTL-BRK vector
  450. ;-----------------------------------------------------------------------------
  451. ; extern void SETCTL()
  452. ;-----------------------------------------------------------------------------
  453.  
  454.     PUBLIC    SETCTL
  455.     IF LPROG
  456. SETCTL    PROC    FAR
  457.     ELSE
  458. SETCTL     PROC NEAR            ; set CTL-BRK interrupt
  459.     ENDIF
  460.     push    BP            ; C prolog
  461.     mov    BP,SP            ; ...
  462.  
  463. ; MyCS := CS;
  464.     mov    MyCS,CS            ; save CS
  465.  
  466.     ASSUME ES:VECTORS
  467.  
  468. ; OldES := ES;
  469.  
  470.     push    ES        ; save old ES
  471.     push    AX        ; save old AX
  472.  
  473. ; ES := Segment(&Vectors);
  474.  
  475.     mov    AX,VECTORS
  476.     mov    ES,AX        
  477.  
  478. ; Disable_Interrupts();
  479.  
  480.     CLI            ; turn off interrupts
  481.  
  482. ; OLD_REQ.IP := CTLBRK.IP
  483.  
  484.     mov    AX,CTLBRK
  485.     mov    OLD_REQ,AX
  486.  
  487. ; OLD_REQ.CS := CTLBRK.CS
  488.  
  489.     mov    AX,CTLBRK[2]
  490.     mov    OLD_REQ[2],AX
  491.  
  492. ; CTLBRK := &CTLSEEN
  493.  
  494.     mov    CTLBRK_IP,OFFSET CTLSEEN
  495.     mov    CTLBRK_CS,CS
  496.  
  497. ; Enable_interrupts();
  498.  
  499.     STI        ; allow interrupts
  500.  
  501. ; ES := OldES;
  502.  
  503.     pop    AX
  504.     pop    ES    
  505.  
  506. ; return;
  507.     pop    BP    ; C epilog
  508.     ret        ; return to caller
  509.  
  510. ; This is the User Exit routine
  511.  
  512.     IF LPROG
  513.     extrn    _Exit:Far
  514.     ELSE
  515.     extrn    _Exit:Near
  516.     ENDIF
  517.  
  518. ByeBye:    
  519.     call    CLRCTL
  520.     call    _Exit
  521.  
  522. SETCTL    ENDP
  523.  
  524.     subttl    CLRCTL - Clear CTL-BRK vector
  525. ;-----------------------------------------------------------------------------
  526. ; extern void CLRCTL();
  527. ;
  528. ; Resets the ctrl-break interrupt vector
  529. ;-----------------------------------------------------------------------------
  530.     PUBLIC    CLRCTL
  531.     IF    LPROG
  532. CLRCTL PROC FAR
  533.     ELSE
  534. CLRCTL PROC NEAR
  535.     ENDIF
  536.     ASSUME ES:VECTORS
  537.  
  538.  
  539. ; OldES := ES;
  540.  
  541.     push    ES        ; save old ES
  542.     push    AX        ; save old AX
  543.     push    BX
  544.  
  545. if debug
  546.     int 3
  547.     mov    AH,62H
  548.     int    21H        ; get program segment prefix
  549.     mov    PSP,BX        ; save it
  550. endif
  551.  
  552. ; ES := Segment(&Vectors);
  553.  
  554.     mov    AX,VECTORS
  555.     mov    ES,AX        
  556.  
  557. ; Disable_Interrupts();
  558.  
  559.     CLI            ; turn off interrupts
  560.  
  561. ; if(OLD_REQ == 0) goto NoVectorStored
  562.  
  563.     mov    AX,OLD_REQ
  564.     cmp    AX,0        ; is it zero?
  565.     je    NoVectorStored
  566.  
  567. ; CTLBRK.IP := OLD_REQ.IP
  568.  
  569.     mov    CTLBRK,AX
  570.  
  571. ; CTLBRK.CS := OLD_REQ.CS
  572.  
  573.     mov    AX,OLD_REQ[2]
  574.     mov    CTLBRK[2],AX
  575.  
  576. NoVectorStored:
  577.  
  578. ; Enable_interrupts();
  579.  
  580.     STI        ; allow interrupts
  581.  
  582. ; ES := OldES;
  583.  
  584.     pop    BX
  585.     pop    AX
  586.     pop    ES    
  587.  
  588.     ret        ; return to caller
  589.  
  590. PSP:    DW    ?
  591. CLRCTL  ENDP
  592.  
  593.     ENDPS
  594.     END
  595.