home *** CD-ROM | disk | FTP | other *** search
- ; GRDb
- ;
- ; Copyright(c) LADsoft
- ;
- ; David Lindauer, camille@bluegrass.net
- ;
- ;
- ; DOS.ASM
- ;
- ; Function: DOS interfac
- ;
- ;MASM MODE
- .MODEL SMALL
- .386
-
-
- include eprints.inc
- include eenv.inc
- include emtrap.inc
- include ememory.inc
- include eoptions.inc
- include eloader.inc
- include eints.inc
- include ebreaks.inc
- include eswift.inc
-
- PUBLIC SetUserPSP, SetDebugPSP, userpsp, UnloadProgram
- PUBLIC int20handle,int21handle, KillFiles
- PUBLIC int1bh,CtrlBrkPressedInDOS
-
- extrn trapcount : dword
- .data
- CtrlBrkPressedInDOS db 0 ;flag this event
- userpsp dw 0 ;their PSO
-
- .CODE
- ;
- ; PSP switching
- ;
- SetDebugPSP PROC
- mov ah,51h ;undocumented call to get PSP
- int 21h
- mov [userpsp],bx ;save user's psp segment
- mov bx,[psp] ;and set up ours
- mov ah,50h ;using another undocumented call
- int 21h
- ret
- SetDebugPSP ENDP
-
-
- SetUserPSP PROC
- mov bx,[userpsp] ;get target pgm PSP
- mov ah,50h ;and set as current
- int 21h
- ret
- SetUserPSP ENDP
- ;
- ; ctrl-break handling
- ;
- int1bh PROC
- pushf
- push es
- push bp
- call untrace
- int1bcont:
- mov bp,dgroup ;point ES at our data
- mov es,bp
- mov es:[CtrlBrkPressedInDOS],1 ; assume in dos
- push es ;save our data seg
- les bp,es:[indos] ;inDOS flag at ES:BP
- test byte ptr es:[bp],0FFh ;see if any bits set
- pop es ;restore our data seg
- jnz int1bhid ; in dos is easy, break when it exits
- ; via int 21h handler
- mov es:[CtrlBrkPressedInDOS],0 ; else start a single step handler
- push 0 ;set ES to 0
- pop es
-
- ;point int1 at our stepper routine
-
- mov word ptr es:[4],offset cs:stepper ; don't worry about killing
- mov word ptr es:[6],cs ; primary tracer, it will get fixed
- mov bp,sp ;point BP at stack
-
- ;Um. [bp+6] points to the return address, so [bp+A] points to the flags
- ;pushed by the int. Flag bit 8 is TF, and we set it to enable single-step
- ;debugging
-
- or word ptr [bp+6+4],0100h ;set trap flag upon IRET
- int1bhid:
- pop bp
- pop es
- popf
- iret
- ;
- ; ctrl-break single-stepper. When ctrl-break comes in the IRET frame
- ; on the stack will point into the BIOS area. The following routine
- ; single-steps the processor until we are out of the BIOS and back
- ; in the area bounded by GRDB's PSP and the EOM
- ;
-
- stepper:
- pushf
- push es
- push bp
- mov bp,sp
- les bp,[bp + 6] ;point ES:BP at return adr
- cmp byte ptr es:[bp],0cfh ;see if next inst is IRET
- jne int1bpopf ;jmp if it isn't
- mov bp,sp ;point back at stack
-
-
- ;Let me think. If the next instruction is IRET, we must be nested inside an
- ;interrupt handler. So we skip past what we pushed, plus the 6 bytes pushed
- ;by the INT to get here, to the frame of the interrupt handler we are inside.
- ;We set HIS trap flag.
- ; Else, if the next instruction is POPF, we OR on a bit at [bp+C]. Now lets
- ;see. BP+6 points to the IP of this int, so BP+C points to the contents of
- ;the stack just past our int frame. Since the instruction is POPF, what must
- ;be on the stack is the flags (whatever it was, it will surely become the
- ;flags after the POPF). So we set the trap flag in those flags.
- ; Since POPF and IRET are the only instructions that might wipe our trace
- ;flag, these are the only cases we need to handle. All other instructions
- ;will cause this routine to be invoked immediately after execution. So this
- ;process continues until we're back from both DOS and BIOS and in the
- ;domain of ourselves or the program we are debugging.
-
- or word ptr [bp+4+6+6],100h ; set trace flag in frame
- jmp int1bhid
- int1bpopf:
- cmp byte ptr es:[bp],9dh ;if next instruction is POPF
- jne stepperfin
- mov bp,sp
- or word ptr [bp+6+6],100h ;do the same thing to us
- jmp int1bhid
- stepperfin:
- mov bp,dgroup ; else check if in
- mov es,bp ; bounds yet
- mov bp,sp ;ES is our DS, BP is stack
-
- ;[BP+8] is the segment on the stack frame for the INT that invoked this
- ;routine. See if it's our segment.
-
- mov bp,[bp+2+6] ;get segment from stack
- cmp bp,es:[psp] ;is it our PSP seg?
- jb int1bhid ;nope, its bigger
- mov es,es:[psp] ;else get our PSP into ES
- mov bp,sp ;back to stack
- mov bp,[bp+2+6] ;get that segment again
- cmp bp,es:[2] ;??? in our PSP
- jae int1bhid ;still not us?
- mov bp,sp ;BP back to stack
- and word ptr [bp+4+6],NOT 100h ;finally in bounds, off tracing
- mov bp,dgroup
- mov es,bp ;ES back to our data
- mov es:[CtrlBrkPressedInDOS],1 ;set flag
- les bp,es:[indos] ; just make sure about DOS
- test byte ptr es:[bp],0FFh ;see if in DOS now
- jnz int1bhid ; run to completion if so
- push ax ; else clear pending ints
- mov al,20h
- out 20h,al ;ACK PIC
- pop ax
- pop bp
- pop es
- popf
- jmp entry1 ; return to debugger
-
- int1bh ENDP
- ;
- ; check if we have a proper exit PSP, if we don't assume a spawn
- ; in progress
- ;
- checkpsp proc
- push ds
- push ax
- push bx
- mov ax,dgroup
- mov ds,ax ;set DS to our data segment
- mov ah,51h ;get PSP command
- pushf
- call cs:[int21adr] ;target pgm's int 21 handler
- cmp bx,[userbasepsp] ;see if their PSP
- pop bx
- pop ax
- pop ds
- ret
- checkpsp endp
- ;
- ; int 20h exit - not understood yet. Need to determine what int20adr and
- ; int21adr really point to - our code, or the user's code.
- ;
- int20handle PROC
- call checkpsp ;see if user's PSP is current
- jz x20 ;ZF if so
- jmp cs:[int20adr] ;else let user's int20 handle it?
- x20:
- mov ax,dgroup ;set DS and ES to or data
- mov ds,ax
- mov es,ax
- mov bp,sp ;reach onto stack
- mov ax,[bp+2] ;to get segment of int 20
- cmp ax,[userbasepsp] ;is
- je close20
- PRINT_MESSAGE <13,10,"Warning : Int 20h with CS <> PSP (program will crash)">
- close20:
- JMP int21exit0
- int20handle ENDP
- ;
- ; int 21h handler. Hooks 4ch,00h, 2521,3521,
- ; and exits to debugger if ctrl-break pressed
- ;
- int21handle PROC
- cmp ah,4ch ;exit to DOS command
- je int21exit4ch ;go if so
- cmp ah,0 ;old exit command
- je int21exit0 ;handle that
- cmp ax,2521h ; hook setting 21h
- jne chk35 ;nope, not doing that
- mov word ptr cs:[int21adr],dx ;snag hook address
- mov word ptr cs:[int21adr+2],ds ;from hooking app
- jmp didvect ;and skip around
-
- chk35:
- cmp ax,3521h ; hooking reading int 21h
- jne normchain ;nope, normal?
- mov bx,word ptr cs:[int21adr] ;return OUR int21 address
- mov es,word ptr cs:[int21adr+2] ;in this case
-
- ;We get here if the program being debugged was either setting or getting
- ;the DOS dispatch vector INT 21h.
-
- didvect:
- push bx ; we have to get the flags back now
- push bp
- mov bp,sp ;point to stack
- mov bx,[bp+4+4] ;flags from int 21
- xchg bx,[bp+2] ;xchg with our BX
- pop bp ;flags now on top of stack
- jmp int21join ;this will do popf, retf 2
- int21handle ENDP
-
- normchain:
- push bx ; we have to get the ie flag back
- push bp
- mov bp,sp ; all this is a grandiose simulated
- mov bx,[bp +4+4] ; interrupt
- xchg bx,[bp+2]
- pop bp
- call cs:[int21adr] ; call DOS
- pushf ;save DOS return flags
- int21join:
- push bp
- push es
- mov bp,dgroup ; check for ctrl-break
- mov es,bp
- test es:[CtrlBrkPressedInDOS],1
- pop es
- jnz i21brk ; yep- go to DOS
- pop bp
- popf ; NO, RETURN
- retf 2
-
- ;Oh brother! Well, we pushed the DOS return flags, then BP. AX contains
- ;the DOS return value. We set bp to sp and push AX. NOW the stack
- ;contains flags, bp, ax. [bp+2] points to the flags. For reasons unknown,
- ;we DON'T just MOV ax,[bp+2], we XCHG! NOW the flags are in AX and [bp+2]
- ;contains the DOS return value. So we pop AX from the push, pop
- ;bp, and ADD SP,2 to THROW AWAY the AX value we carefully put on the stack
- ;using XCHG! WHY? Why not pop bp, pop ax and just leave out the push ax
- ;and the add sp,2? Thats why we used XCHG in the first place, right?
- ; Anyway, we got here if control-break was pressed in DOS, so we are
- ;taking the DOS return flags from the REAL DOS and placing them on the
- ;stack for the debugger's return from this int21 handler.
-
- i21brk:
- mov bp,sp
- push ax
- xchg ax,[bp+2] ; get DOS return flags to stack
- mov [bp+2+6],ax ; and hit the debugger
- pop ax
- pop bp
- add sp,2
- jmp entry1
- ;
- ; DOS exit request comes here
- ;
-
- int21exit0 PROC
- sub ax,ax
- int21exit0 ENDP
-
-
-
- int21exit4ch PROC
- call checkpsp
- jnz normchain
- cld
- call untrace
- mov bx,dgroup
- mov ds,bx
- mov es,bx
- mov ss,[stackseg]
- mov sp,[stackofs]
- sti
- mov [trapcount],0
- mov [CtrlBrkPressedInDOS],0
- push ax
- call SetDebugPSP ; debug PSP
- mov si,offset dgroup : veclist ; unhook ints
- call ReleaseRMInts
- call disableBreaks ; Disable breakpoints if not
- PRINT_MESSAGE <13,10,"Normal exit, exit code: ">
- pop ax
- call PrintByte ; error code
- call crlf
- call UnLoadProgram ; unload the program
- test [lastexe],0ffh ; see if was EXE
- jz rex
- mov ax,[lastcs] ; yep, refresh CS:EIP
- mov [RegdumpCS],ax
- mov eax,[lastip]
- mov [RegdumpEIP],eax
- rex:
- jmp reentry
- int21exit4ch ENDP
- ;
- ; unload program
- ;
- UnLoadProgram PROC
- call UnLoadInts ; reinit int table
- call KillFiles ; kill their files
- call ReleaseMemory ; release memory
- mov si,offset dgroup : grdbname ; make an empty program
- call MakeEmptyProg
- ret
- UnLoadProgram ENDP
- ;
- ; kill program files by reading the handle table and closing them all
- ;
- KillFiles PROC
- call SetUserPSP
- mov fs,bx
- mov cx,fs:[32h]
- kf_lp:
- dec cx
- mov bx,cx
- mov ah,3eh
- int 21h
- cmp cx,6
- jae kf_lp
- call SetDebugPSP
- ret
- KillFiles ENDP
- end