1; TRAPOUT2.ASM v2.0 by ARK (ark@lhq.com, root@ark.dyn.ml.org) 11-28-97 2; Traps IN and OUT instructions in INT 10h and displays DX and AX/AL values. 3; 4; In the header "T DX/I AX/L", T is the Type of instruction (I=IN, O=OUT), 5; DX/I is the value of DX or the Immediate value if port<256, and AX/L 6; is the value of AX or AL depending on if an 8 or 16 bit value is listed. 7; AX/L is meaningless for IN's since it is the value if AX/L *before* the 8; call to IN. 9; 10; This is very useful to find information about how your video card works. 11; I wrote this to get register dumps for my Trident TVGA9440AGi card so 12; that I could use it under Linux. 13; 14; NOTE: Pipe the output or you won't see anything! 15; (ex: TRAP-OUT 4F02 0101 > 640x480.256) 16; 17; New in v2.0: 18; * Traces into INT 10 calls that are called from inside INT 10! 19; * Allows AX and BX values to be specified! 20; * Command line accepts trailing spaces now. 21; x Code to trap INT's also! (T column='N', DX/I=INT ##, AX/L=AX value) 22; (Its commented out - but you can recompile with it if you want) 23; 24; How to assemble with Borland: 25; tasm /ml /zd ncr.asm (case sensitive, line number debug info only) 26; tlink /x /t ncr.obj (no map, make com file) 27; 28 29.model tiny ; Tiny memory model, all segments point to the same 64K 30.286 ; This code will run on a 286... actually, it 31.code ; Everything is in the code segment(cs) will probably 32.startup ; Startup run on anything 33 34jmp Start ; Go to beginning of progam 35realINT1 dd 52411A3Eh ; Address of original INT 01h routine offset 36realINT10 dd 3C1B214Bh ; Memory for [es:bx] of the real INT 10h 37 ; (defaults are '>-ARK!-<' just for looks in the .COM) 38 39; strings 40no_command_line db 'Use: TRAPOUT2 [AX] [BX]',13,10 41db ' Traces all IN/OUT calls inside INT 10h',13,10,36 42tracing db 'Tracing INT 10h with AX:',36 43bx_msg db ' BX:',36 44header db 13,10,'T DX/I AX/L',13,10,36 45 46INT1 proc ; Interrupt Service Routine for Single Step Debugging 47 push ax ; save registers 48 push dx 49 push es 50 push di 51 push bp 52 53 mov bp,sp ; set bp to the stack 54 push word ptr cs:[bp+12] ; put the real cs 55 pop es ; into es 56 push word ptr cs:[bp+10] ; put the real ip 57 pop di ; into di 58 mov al,byte ptr es:[di] ; set al to the next instruction that will 59 ; be executed after this INT 01 is done. 60 61; This code will trap INT's also... 62; cmp al,0CDh ; If al is not CD (INT) keep going 63; jne not_int ; If it is, display some stuff... 64;; This will skip doing the INT's... 65;; add word ptr cs:[bp+10],2 ; Add 2 to the real ip, to skip the INT 66; mov dl,4Eh ; Display an N 67; mov ah,02h ; The immediate value/DX is the INT ## 68; int 21h ; that is called. AX is the value before 69; mov dl,20h ; Display a space 70; mov ah,02h ; 71; int 21h ; Display the immediate value which is 72; jmp is_imm ; reallly the interrupt number called. 73 74 not_int: 75 and al,0F4h ; If al is E4-E7 or EC-EF (all IN/OUT's) 76 cmp al,0E4h ; Then we display our stuff 77 jne not_io ; Otherwise, do nothing 78 ; note: 1 more byte of code after this 79 ; jmp will make it out of range... 80 81 mov al,byte ptr es:[di] ; Set al to next instruction 82 test al,02h ; If bit 1 is set then we have an OUT 83 jz is_in ; If bit 1 is 0, we have an IN 84 85 mov dl,4Fh ; Display an O 86 mov ah,02h 87 int 21h 88 jmp dx_or_imd 89 90 is_in: ; Display an I 91 mov dl,49h 92 mov ah,02h 93 int 21h 94 95 dx_or_imd: ; Display a space 96 mov dl,20h 97 mov ah,02h 98 int 21h 99 100 mov al,byte ptr es:[di] ; Set al to next instruction 101 test al,08h ; If bit 3 is set then we are using DX 102 jz is_imm ; If bit 3 is 0, we are using an immediate 103 104 mov ax,[bp+6] ; restore dx to ax 105 call ShowHex ; Display dx 106 call ShowHex 107 call ShowHex 108 call ShowHex 109 jmp ax_or_al 110 111 is_imm: 112 mov dl,20h ; Display 2 spaces 113 mov ah,02h 114 int 21h 115 mov dl,20h 116 mov ah,02h 117 int 21h 118 119 mov ah,byte ptr es:[di+1] ; Set ah to byte after the next instruction 120 call ShowHex ; Display the immediate value 121 call ShowHex 122 123 ax_or_al: 124 mov dl,2Ch ; Display a comma 125 mov ah,02h 126 int 21h 127 128 mov al,byte ptr es:[di] ; Set al to next instruction 129 test al,01h ; If bit 0 is set then we are using AX 130 jz is_al ; If bit 0 is 0, we are using AL 131 132 mov ax,[bp+8] ; Restore ax 133 call ShowHex ; Display ax 134 call ShowHex 135 call ShowHex 136 call ShowHex 137 jmp print_next_line 138 139 is_al: 140 mov ah,[bp+8] ; Restore al to ah 141 call ShowHex ; Display al 142 call ShowHex 143 144 print_next_line: 145 mov dl,0Dh ; print a newline 146 mov ah,02h 147 int 21h 148 mov dl,0Ah 149 mov ah,02h 150 int 21h 151 152 not_io: 153 pop bp ; restore registers 154 pop di 155 pop es 156 pop dx 157 pop ax 158 iret ; end interrupt 159INT1 endp 160 161; INT 10h that fakes the real INT 10 and sets the trap flag. 162INT10 proc ; Interrupt Service Routine for Tracing INT 10h 163 push ax ; Save AX 164 pushf ; Put flags on the stack 165 pop ax ; Then into AX 166 or ax,0100h ; Set the trap flag 167 push ax ; Trap Flag calls INT 01h between every instruction 168 popf ; Stuff new flags back into the flags register 169 pop ax ; Restore AX 170 171 cli ; Fake INT call: clear interrupt flag, skip clearing 172 pushf ; trap flag, push flags, call to location. 173 call cs:[realINT10] ; This call to INT 10h is be trapped for 174 ; IN/OUT/INT Normal INT calls would clear 175 ; the trap flag and then INT 01h would never 176 ; be called. 177 iret ; end interrupt 178INT10 endp 179 180; function that prints the highest 4 bits of ax as text {0-9,A-F} to stdout 181; ax will be shifted left 4 bits on return. 182ShowHex proc 183 push ax ; save registers 184 push dx 185 186 shr ax,0Ch ; move the highest 4 bits to the lowest 4 187 and al,0Fh ; limit to lowest 4 bits 188 or al,30h ; change range to 30h-3Fh {0-9:;<=>?} 189 cmp al,39h ; if it is 30h-39h 190 jbe is_0_thru_9 ; then its already set 191 add al,07h ; otherwise change :;<=>? to A-F 192 is_0_thru_9: 193 mov dl,al 194 mov ah,02h 195 int 21h 196 197 pop dx ; restore dx 198 pop ax ; restore ax 199 shl ax,4 ; set up ax for next call 200 ret ; return 201ShowHex endp 202 203Start: ; Program begins here 204 mov si,0080h ; CS:0080h is the command line 205 cmp byte ptr [si],10 ; I want it to be at least 10 bytes long 206 jae process_command_line ; if not, abort 207 208 mov dx,offset no_command_line ; ds is preset 209 mov ah,09h ; Dos function 09h 210 int 21h ; Display no command line string 211 ret ; Exit program 212 213 process_command_line: 214 inc si ; move si to start of actual string 215 mov ax,[si+1] ; copy first 2 chrs to ax, skipping the space 216 mov bx,[si+3] ; copy 2nd two characters to bx 217 sub al,30h ; subtract 30h so chrs 0-9 have value 0-9 218 cmp al,09h ; if its 0-9, its ok. 219 jbe al_is_ok ; if its not, its probably A-F or a-f 220 sub al,07h ; so subtract 7 more 221 and al,0Fh ; and limit to 0-F 222 al_is_ok: 223 sub ah,30h ; do the same to ah 224 cmp ah,09h 225 jbe ah_is_ok 226 sub ah,07h 227 and ah,0Fh 228 ah_is_ok: 229 sub bl,30h ; do the same to bl 230 cmp bl,09h 231 jbe bl_is_ok 232 sub bl,07h 233 and bl,0Fh 234 bl_is_ok: 235 sub bh,30h ; do the same to bh 236 cmp bh,09h 237 jbe bh_is_ok 238 sub bh,07h 239 and bh,0Fh 240 bh_is_ok: 241 shl al,04h ; Combine the values so that AL-AH-BL-BH 242 or ah,al ; Goes into --AH- --AL- 243 mov al,bl ; <----AX---> 244 shl al,04h 245 or al,bh 246 mov word ptr [si],ax ; store the value over the string 247 248 mov ax,[si+6] ; copy 3rd 2 chrs to ax, skip the 2nd space 249 mov bx,[si+8] ; copy 4th two characters to bx 250 sub al,30h ; subtract 30h so chrs 0-9 have value 0-9 251 cmp al,09h ; if its 0-9, its ok. 252 jbe al_is_ok2 ; if its not, its probably A-F or a-f 253 sub al,07h ; so subtract 7 more 254 and al,0Fh ; and limit to 0-F 255 al_is_ok2: 256 sub ah,30h ; do the same to ah 257 cmp ah,09h 258 jbe ah_is_ok2 259 sub ah,07h 260 and ah,0Fh 261 ah_is_ok2: 262 sub bl,30h ; do the same to bl 263 cmp bl,09h 264 jbe bl_is_ok2 265 sub bl,07h 266 and bl,0Fh 267 bl_is_ok2: 268 sub bh,30h ; do the same to bh 269 cmp bh,09h 270 jbe bh_is_ok2 271 sub bh,07h 272 and bh,0Fh 273 bh_is_ok2: 274 shl al,04h ; Combine the values so that AL-AH-BL-BH 275 or ah,al ; Goes into --AH- --AL- 276 mov al,bl ; <----AX---> 277 shl al,04h 278 or al,bh 279 mov word ptr [si+2],ax ; store the value over the string 280 ; Now [si] contains the real values of AX and BX 281 282 mov dx,offset tracing ; ds is preset 283 mov ah,09h ; Dos function 09h 284 int 21h ; Display tracing string 285 mov ax,word ptr [si] ; Restore ax 286 call ShowHex ; Display command line 287 call ShowHex ; ax value back to user 288 call ShowHex ; by placing it in ax 289 call ShowHex ; and calling ShowHex 290 mov dx,offset bx_msg ; ds is preset 291 mov ah,09h ; Dos function 09h 292 int 21h ; Display bx message 293 mov ax,word ptr [si+2] ; Restore bx into ax 294 call ShowHex ; Display command line 295 call ShowHex ; bx value back to user 296 call ShowHex ; by placing it in ax 297 call ShowHex ; and calling ShowHex 298 mov dx,offset header ; ds is preset 299 mov ah,09h ; Dos function 09h 300 int 21h ; Display header to output 301 302 mov ax,3501h ; Dos function 35h, Get vector of INT 01h 303 int 21h ; Store it in es:bx 304 mov word ptr [realINT1],bx ; Store address of original INT 01h 305 mov word ptr [realINT1+2],es ; into realINT1 306 307 mov ax,3510h ; Dos function 35h, Get vector of INT 10h 308 int 21h ; Store it in es:bx 309 mov word ptr [realINT10],bx ; Store address of original INT 10h 310 mov word ptr [realINT10+2],es ; into realINT10 so we can fake an INT 311 312 mov ax,2501h ; Dos function 25h, Store DS:DX to INT 01h 313 mov dx,offset INT1 ; ds is preset, dx is the handler's offset 314 int 21h ; Set new Single Step handler 315 316 mov ax,2510h ; Dos function 25h, Store DS:DX to INT 10h 317 mov dx,offset INT10 ; ds is preset, dx is the handler's offset 318 int 21h ; Set new Video Interrupt 319 320 mov ax,word ptr [si] ; We will use the command line ax/bx 321 mov bx,word ptr [si+2] ; values for the fake int call 322 int 10h ; Call my int 10 which fakes the 323 ; real int 10 and traps it. 324 325 mov ax,2501h ; Dos function 25h, Store DS:DX to INT 01h 326 mov dx,word ptr [realINT1] ; ds/dx are in realINT1 327 push ds ; Save old ds 328 push word ptr [realINT1+2] ; Put segment on stack 329 pop ds ; Set ds to the segment 330 int 21h ; Reset old Single Step handler 331 pop ds ; Restore old ds 332 333 mov ax,2510h ; Dos function 25h, Store DS:DX to INT 10h 334 mov dx,word ptr [realINT10] ; ds/dx are in realINT10 335 push ds ; Save old ds 336 push word ptr [realINT10+2] ; Put segment on stack 337 pop ds ; Set ds to the segment 338 int 21h ; Reset old Video Interrupt 339 pop ds ; Restore old ds 340 341 mov ax,0003h ; Set ax to 3 342 int 10h ; Set 80x25 Text mode 343 ret ; End of program 344end ; End of file 345