home *** CD-ROM | disk | FTP | other *** search
/ Power-Programmierung / CD1.mdf / magazine / drdobbs / 1989 / 02 / menico.asc < prev    next >
Text File  |  1989-01-04  |  11KB  |  401 lines

  1. _Debugging TSR Programs_
  2. by Costas Menico
  3.  
  4. [LISTING ONE]
  5.  
  6. ;
  7. ;     Set TABS to 8 for viewing with editor.
  8. ;
  9. ;-------------------------------------------------------;
  10. ; KEYSWAP program                             ;
  11. ; By     Costas Menico.                    ;
  12. ;        Software Bottling Company        ;
  13. ;         6600 Long Island Expressway        ;
  14. ;        Maspeth, N.Y. 11378            ;
  15. ;        718-458-3700                ;
  16. ; This program will swap the F8 & F10 key for the     ;
  17. ;   Up and Down arrow keys.                ;
  18. ; Demonstrator program for debugging memory resident    ;
  19. ;    program using Turbo Debugger.            ;
  20. ;-------------------------------------------------------;
  21.  
  22.     .model small
  23.  
  24. ; Set key values.
  25. ; For the SCAN and ASCII codes of any other keys, see the BIOS manual
  26. f8key    equ 4200h        ; define the F8 key
  27. f10key    equ 4400h        ; define the F10 key
  28. upkey    equ 4800h        ; define the up arrow key
  29. downkey    equ 5000h        ; define the down arrow key
  30.  
  31. DOSCALL    equ <int 21h>         ; DOS interrupt call
  32. LOADSEG MACRO segr1, segr2    ; Load segment register
  33.     push segr2        ;   macro.
  34.     pop segr1
  35.     ENDM
  36.     
  37.     
  38. ; Publics area
  39. public start, oldint16, int16handler, exit, test_for_key
  40. public load_tsr, tsr_terminate, chain_vector, f10pressed
  41.  
  42. ; Start Code
  43.     .code
  44.     assume cs:_text, ds:_text, es:_text, ss:nothing
  45.     
  46. ;-------------------;
  47. ; Our program start ;
  48. ;-------------------;
  49.     org 100h        ; COM file starting program address.
  50. start:    
  51.     jmp load_tsr        ; Load our program resident.
  52.  
  53. ; Data area. Since this is COM file all data
  54. ; and code are in the Code segment.
  55.     evendata
  56. oldint16     dd    0    ; Area for old interrupt 16h vector.
  57. stackbot    dw  128 dup('?'); Our stack bottom.
  58. stacktop    equ $-2        ; Our stack top.
  59.  
  60. ;-----------------------------------------------;
  61. ; Entry to keyboard handler.             ;
  62. ; We get here when any application or DOS    ;
  63. ; executes an INT 16h.                ;
  64. ; Input:    AH=0    -    Get a key    ;
  65. ; Output:    The key in AX            ;
  66. ; Input:    AH=1    -    Check for key    ;
  67. ; Ouput:    The available key in AX        ;
  68. ; Input:    AH=2    -    Get shift flags    ;
  69. ; Output:    The shift flags in AL        ;
  70. ;-----------------------------------------------;
  71. int16handler proc far
  72.     pushf            ; Save flags status.
  73.     or ah, ah        ; Are we getting a key?
  74.     je test_for_key        ; Yes - goto to test for F10.
  75.  
  76.     popf            ; No - pop flags and
  77.     jmp cs:oldint16        ;   jump to old interrupt handler.
  78.  
  79. ; Get a pressed key and test if it was 
  80. ;    and F10
  81. test_for_key:    
  82.     popf            ; Pop the original flags.
  83.     pushf            ; Push them again
  84.     call cs:oldint16    ;   and simulate INT 16h.
  85.     
  86.     pushf            ; Save flags.
  87.     cmp ax, f10key         ; is this an F10 key?
  88.     jne is_it_f8        ;   no - check for F8.
  89. f10pressed:    
  90.     mov ax, downkey        ;   yes - set swap key in ax.
  91.     jmp short exit
  92. is_it_f8:    
  93.     cmp ax, f8key         ; is this an F8 key?
  94.     jne exit        ;   no - exit
  95.     mov ax, upkey        ;   yes - set swap key in ax.
  96. exit:                        
  97.     popf            ; Pop the saved flags.
  98.     
  99.     iret            ; Return to caller with key in ax.
  100. int16handler endp
  101.  
  102. IFDEF DEBUG
  103.     ; Assemble this section to debug the TSR with Turbo Debugger.
  104.     ; You must assemble with the /DDEBUG option.
  105.     include tsrdebug.asm
  106. ENDIF
  107.  
  108. ;===============================================;
  109. ; Load KEYSWAP, and terminate but stay resident.;
  110. ; Once KEYSWAP is loaded all code from here on  ;
  111. ;   is discarded.                ;
  112. ;===============================================;
  113.  
  114. load_tsr:
  115.  
  116.     ; Set SP to our internal stack area
  117.     cli            ; Do not interrupt while
  118.     mov sp, offset stacktop    ;   stack pointer is being adjusted.
  119.     sti            ; Now interrupt.
  120.     
  121.     call chain_vector    ; Install our keyboard interrupt.
  122.  
  123. IFDEF DEBUG
  124.     ; Assemble this section to debug the TSR with Turbo Debugger.
  125.     ; You must assemble with the /DDEBUG option.
  126.     call tsr_simulate
  127. ELSE
  128.     ; Assemble this section to run without the debugging.
  129.     call tsr_terminate
  130. ENDIF
  131.                             
  132. ;-----------------------------;
  133. ; Save old interrupt 16 vector; 
  134. ; and point it to our handler ;
  135. ;-----------------------------;
  136. chain_vector proc uses ax bx dx es
  137.     mov ax, 3516h        ; Get the int 16h keyboard vector.
  138.     DOSCALL                        
  139.     mov word ptr oldint16, bx; Save old vector in our data area.
  140.     mov word ptr oldint16[2], es
  141.     
  142.     mov ax, 2516h        ; Set the new vector of our
  143.     mov dx, offset int16handler; interrupt 16h keyboard handler.
  144.     DOSCALL
  145.     ret
  146. chain_vector endp
  147.  
  148. ;-----------------------------;
  149. ; Terminate and stay resident ;
  150. ;-----------------------------;
  151. tsr_terminate proc
  152.     mov dx, offset load_tsr    ; Get offset address of program
  153.     mov cl, 4        ;   code to discard.
  154.     shr dx, cl        ; Convert to pargraphs.
  155.     inc dx            ; Round off to the next paragraph.
  156.     mov ax, 3100h        ; Terminate & stay resident function.
  157.     DOSCALL    
  158. tsr_terminate endp
  159.     
  160. @CurSeg ends
  161.  
  162.     end start
  163.  
  164.  
  165.  
  166. [LISTING TWO]
  167.  
  168. ;---------------------------------------------------------------;
  169. ; Include file TSRDEBUG.ASM                                     ;
  170. ;                                ;
  171. ; Assemble this code if you will debug with Turbo Debugger    ;
  172. ; You must assemble with the /DDEBUG option.            ;
  173. ;---------------------------------------------------------------;
  174.  
  175. public param, command_com
  176. public tsr_simulate, unchain_vector, int9handler
  177.  
  178. BREAKPOINT    equ <int 3>    ; Debugger break point
  179. ctrlflag    equ 4        ; Ctrl key BIOS indicator flag.
  180. enterscan    equ 28        ; Scan code for Enter key.
  181. kbdflags    equ 417h    ; BIOS keyboard flags location
  182.  
  183. ; Load & Execute parameter block structure
  184. execparam struc
  185. envstr_addr    dw 0        ; Environment pointer
  186. cmdline_ofs     dw 0        ; Offset to command line.
  187. cmdline_seg    dw 0        ; Segment to command line.
  188. fcb1_ofs    dw 0        ; Offset of fcb1.
  189. fcb1_seg    dw 0        ; Segment of fcb1
  190. fcb2_ptr    dw 0        ; Offset of fcb2.
  191. fcb2_seg    dw 0        ; Segment of fcb2.
  192. execparam ends
  193.  
  194.  
  195. oldint9        dd 0        ; Area for old int 9 vector.
  196. paramvals    equ <0,offset cmd_line,?,offset fcb1,?,offset fcb2,?>
  197. ;
  198. ; Shows below how the data above is initialized.
  199. ;
  200. comment ^
  201.     0,            ; Use current environment
  202.     offset cmd_line,?     ; Point to command line.
  203.     offset fcb1,?        ; Offset & Seg of fcb1.
  204.     offset fcb2,?         ; Offset & Seg of fcb2.
  205. ^
  206. param        execparam <paramvals>
  207. command_com    db 'c:\command.com',0
  208. cmd_line    db 0, 0dh    ; Command line is null.
  209. savess        dw 0        ; Save SS here.
  210. savesp        dw 0        ; Save SP here.
  211. fcb1        db 16 dup(0)    ; Blank area for FCB1
  212. fcb2        db 27 dup(0)    ; Blank area for FCB2
  213.  
  214. ;-----------------------------------------------;
  215. ; Int 9 handler. Ctrl-Enter key check.        ;
  216. ; Each time a key is pressed it is checked    ;
  217. ;     if the Ctrl & Enter key were pressed    ;
  218. ;    simultaneously. If they were then we    ;
  219. ;    interrupt Turbo Debugger        ;
  220. ;-----------------------------------------------;
  221. int9handler proc far
  222.     pushf            ; Save the flags
  223.     push ax            ; Save ax
  224.     push ds            ; Save dx
  225.     xor    ax, ax        ; Point DS to segment 0
  226.     mov ds, ax
  227.     ; Is the Ctrl key pressed?
  228.     test byte ptr ds:[kbdflags], ctrlflag 
  229.     je exitint9        ; No - call old int 9 & exit.
  230.     
  231.     in al, 60h             ; Yes - get the scan code of key.
  232.     cmp al, enterscan       ; Is it the Enter key?
  233.     je breakkey        ; Yes - go to break Turbo Debug
  234. exitint9:            ; No - call old int 9 & exit
  235.  
  236.     pop ds            ; Pop ds & ax before jump.
  237.     pop ax
  238.     popf            ; Pop flags
  239.         jmp cs:oldint9        ; Jump to the old int 9
  240.     
  241. breakkey:
  242.     pop ds            ; Pop ds & ax before jump.
  243.     pop ax
  244.     popf            ; Pop flags
  245.     
  246.     in al, 61h        ; Reset the keyboard controller
  247.     mov ah, al        ;   for next key.
  248.     or al, 80h
  249.     out 61h, al
  250.     xchg ah, al
  251.     out 61h, al
  252.     mov al, 20h        ; Enable interrupts
  253.     out 20h, al
  254.     
  255.     BREAKPOINT             ; Execute our break point.
  256.                 ; Turbo Debugger STOPS HERE!.
  257.                 ;   To find out what the program
  258.                 ;   was doing press F7 (Trace)
  259.                 ;   twice.
  260.     iret                        
  261. int9handler endp
  262.  
  263. ;---------------------------------------;
  264. ; Simulate Terminate and stay resident    ;
  265. ; Frees unecessary memory and loads &    ;
  266. ;     executes COMMAND.COM           ;
  267. ;---------------------------------------;
  268. tsr_simulate proc
  269.     ; Free unused memory.
  270.  
  271.     LOADSEG ES, CS        ; Point ES to our segment.
  272.     mov bx, offset load_tsr    ; Get offset address of program
  273.     mov cl, 4        ;   code to discard.
  274.     shr bx, cl                    
  275.     inc bx            ; round off to the next paragraph
  276.     mov ah, 4ah        ; Shrink allocated block function
  277.     DOSCALL            ; call DOS
  278.     
  279.     ; Save stack registers
  280.     mov savess, ss        ; Save stack segment.
  281.     mov savesp, sp        ; Save stack pointer.
  282.  
  283.     ; Chain unto int 9 for debugger break key.
  284.     mov ax, 3509h        ; Get the int 9 keyboard vector.
  285.     DOSCALL                        
  286.     mov word ptr oldint9, bx; Save old vector in our data area.
  287.     mov word ptr oldint9[2], es
  288.     mov ax, 2509h        ; Set the new vector of our
  289.     mov dx, offset int9handler; interrupt 9 keyboard handler.
  290.     DOSCALL
  291.  
  292.     ; Load and execute COMMAND.COM
  293.  
  294.     LOADSEG ES, CS        ; Point ES to our segment
  295.     mov dx, offset command_com; Point to COMMAND.COM file path.
  296.     mov bx, offset param    ; Get address of param block.
  297.     mov [bx].cmdline_seg, ds; Get segment of the command line.
  298.     mov [bx].fcb1_seg, ds    ; Get segment of fcb1
  299.     mov [bx].fcb2_seg, ds    ; Get segment of fcb2
  300.     mov ax, 4b00h
  301.     DOSCALL            ; Load and execute COMMAND.COM. 
  302.     
  303.     
  304.     ; Upon return form load and execute, all registers are 
  305.     ; destroyed and the necessary ones, must be recovered.
  306.     
  307.     cli            ; Turn interrupts off.
  308.     mov ss, cs:savess    ; Recover stack segment.
  309.     mov sp, cs:savesp    ; Recover stack pointer.
  310.     sti
  311.  
  312.     LOADSEG DS, CS        ; Recover data segment
  313.  
  314.     ; Unchain all our handlers, and terminate program.
  315.     
  316.     mov ax, 2509h        ; Unchain our int 9 vector and put 
  317.     lds dx, oldint9        ;     original in.
  318.     DOSCALL
  319.     
  320.     call unchain_vector    ; Unchain our keyboard handler
  321.     
  322.     mov ax, 4c00h        ; Terminate program.
  323.     DOSCALL
  324. tsr_simulate endp
  325.  
  326. ;----------------------------------------;
  327. ; Unchain vectors before exiting debugger ;
  328. ;----------------------------------------;
  329. unchain_vector proc uses ds ax
  330.     mov ax, 2516h        ; Unchain our vector and put 
  331.     lds dx, oldint16    ;     original in.
  332.     DOSCALL
  333.     ret
  334. unchain_vector endp    
  335.  
  336.  
  337.  
  338.  
  339. [Example 1: Typical structure of a TSR program]
  340.         
  341.  
  342. ; This portion remains resident
  343.     tsr data 
  344.     tsr interrupt handlers
  345.     tsr other programs
  346.  
  347. ; This portion is freed when the DOS Terminate
  348. ; and Stay resident function is executed.
  349.     data area
  350. load entry point:
  351.     create stack
  352.     call other check routines 
  353.     (e.g. DOS version, parameters, available memory, etc.)
  354.     chain tsr interrupt handlers
  355.     determine size of tsr to keep
  356.     call DOS TSR function
  357. end
  358.         
  359.  
  360.  
  361.  
  362. [Example 2: DOS functions used in KEYSWAP]
  363.  
  364. Note: The following is a list of the DOS INT 21h functions used
  365. in KEYSWAP.  Remember that if any DOS function returns with the
  366. CARRY flag set, the function had a problem. Usually the error
  367. reason is returned in the AX register. For more information, see
  368. the DOS Technical Reference manual, or one of the dozens of books
  369. on the subject.
  370.  
  371. Set the vector of interrupt:
  372. Input:    AH = 25h, AL = interrupt # 
  373.     DS:DX = segment & offset value of new interrupt handler.
  374.  
  375. Terminate but stay resident:
  376. Input:    AH = 31h, AL = errorlevel
  377.     DX = # of paragraphs to keep.
  378.  
  379. Get the vector of interrupt:
  380. Input:
  381.     AH = 35h, AL = interrupt #
  382. Output:
  383.     ES:BX = segment & offset value of the current interrupt handler.
  384.         
  385. Shrink allocated memory:
  386. Input:    AH = 4Ah, ES = Segment to shrink
  387.     BX = paragraphs to keep.
  388.         
  389. Load & Execute:
  390. Input:    AH = 4Bh, AL = 0 (If AL = 3 then it only loads)
  391.     ES:BX = segment and offset of params block
  392.         (for param block format see the program)
  393.     DS:DX = segement & offset of command (ASCIIZ string).
  394. Output: None, but all registers including SS and SP are
  395.     destroyed.        
  396.  
  397. Terminate program:
  398. Input:    AH = 4Ch, AL = errorlevel
  399.  
  400.  
  401.