home *** CD-ROM | disk | FTP | other *** search
/ io Programmo 23 / IOPROG_23.ISO / SOFT / ASM / GRDBDL17.ZIP / DOS.ASM < prev    next >
Encoding:
Assembly Source File  |  1998-10-26  |  9.2 KB  |  355 lines

  1. ; GRDb
  2. ;
  3. ; Copyright(c) LADsoft
  4. ;
  5. ; David Lindauer, camille@bluegrass.net
  6. ;
  7. ;
  8. ; DOS.ASM
  9. ;
  10. ; Function: DOS interfac
  11. ;
  12.     ;MASM MODE
  13.     .MODEL SMALL
  14.     .386
  15.  
  16.  
  17. include eprints.inc 
  18. include eenv.inc
  19. include emtrap.inc 
  20. include ememory.inc
  21. include eoptions.inc
  22. include eloader.inc
  23. include eints.inc
  24. include ebreaks.inc
  25. include eswift.inc
  26.  
  27.     PUBLIC SetUserPSP, SetDebugPSP, userpsp, UnloadProgram
  28.     PUBLIC int20handle,int21handle, KillFiles
  29.     PUBLIC int1bh,CtrlBrkPressedInDOS
  30.  
  31.     extrn    trapcount : dword
  32.     .data
  33. CtrlBrkPressedInDOS    db    0    ;flag this event
  34. userpsp            dw    0    ;their PSO
  35.  
  36.     .CODE
  37. ;
  38. ; PSP switching
  39. ;
  40. SetDebugPSP    PROC
  41.     mov    ah,51h        ;undocumented call to get PSP
  42.     int    21h
  43.     mov    [userpsp],bx    ;save user's psp segment
  44.     mov    bx,[psp]    ;and set up ours
  45.     mov    ah,50h        ;using another undocumented call
  46.     int    21h
  47.     ret
  48. SetDebugPSP    ENDP
  49.  
  50.  
  51. SetUserPSP    PROC
  52.     mov    bx,[userpsp]    ;get target pgm PSP
  53.     mov    ah,50h        ;and set as current
  54.     int    21h
  55.     ret
  56. SetUserPSP    ENDP
  57. ;
  58. ; ctrl-break handling
  59. ;
  60. int1bh    PROC
  61.     pushf
  62.     push    es
  63.     push    bp
  64.     call    untrace
  65. int1bcont:
  66.     mov    bp,dgroup        ;point ES at our data
  67.     mov    es,bp
  68.     mov    es:[CtrlBrkPressedInDOS],1    ; assume in dos
  69.     push    es            ;save our data seg 
  70.     les    bp,es:[indos]        ;inDOS flag at ES:BP
  71.     test    byte ptr es:[bp],0FFh    ;see if any bits set
  72.     pop    es            ;restore our data seg
  73.     jnz    int1bhid        ; in dos is easy, break when it exits
  74.                     ; via int 21h handler
  75.     mov    es:[CtrlBrkPressedInDOS],0    ; else start a single step handler
  76.     push    0            ;set ES to 0
  77.     pop    es
  78.  
  79. ;point int1 at our stepper routine
  80.  
  81.     mov    word ptr es:[4],offset cs:stepper ; don't worry about killing
  82.     mov    word ptr es:[6],cs    ; primary tracer, it will get fixed
  83.     mov    bp,sp            ;point BP at stack
  84.  
  85. ;Um. [bp+6] points to the return address, so [bp+A] points to the flags
  86. ;pushed by the int.  Flag bit 8 is TF, and we set it to enable single-step
  87. ;debugging
  88.  
  89.     or    word ptr [bp+6+4],0100h    ;set trap flag upon IRET
  90. int1bhid:
  91.     pop    bp
  92.     pop    es
  93.     popf
  94.     iret
  95. ;
  96. ; ctrl-break single-stepper.  When ctrl-break comes in the IRET frame
  97. ; on the stack will point into the BIOS area.  The following routine
  98. ; single-steps the processor until we are out of the BIOS and back
  99. ; in the area bounded by GRDB's PSP and the EOM
  100. ;
  101.  
  102. stepper:
  103.     pushf                    
  104.     push    es
  105.     push    bp
  106.     mov    bp,sp
  107.     les    bp,[bp + 6]            ;point ES:BP at return adr
  108.     cmp    byte ptr es:[bp],0cfh        ;see if next inst is IRET
  109.     jne    int1bpopf            ;jmp if it isn't
  110.     mov    bp,sp                ;point back at stack
  111.  
  112.  
  113. ;Let me think. If the next instruction is IRET, we must be nested inside an
  114. ;interrupt handler. So we skip past what we pushed, plus the 6 bytes pushed
  115. ;by the INT to get here, to the frame of the interrupt handler we are inside.
  116. ;We set HIS trap flag.
  117. ; Else, if the next instruction is POPF, we OR on a bit at [bp+C]. Now lets
  118. ;see. BP+6 points to the IP of this int, so BP+C points to the contents of
  119. ;the stack just past our int frame. Since the instruction is POPF, what must
  120. ;be on the stack is the flags (whatever it was, it will surely become the
  121. ;flags after the POPF). So we set the trap flag in those flags.
  122. ; Since POPF and IRET are the only instructions that might wipe our trace
  123. ;flag, these are the only cases we need to handle. All other instructions
  124. ;will cause this routine to be invoked immediately after execution. So this
  125. ;process continues until we're back from both DOS and BIOS and in the
  126. ;domain of ourselves or the program we are debugging.
  127.  
  128.     or    word ptr [bp+4+6+6],100h    ; set trace flag in frame
  129.     jmp    int1bhid
  130. int1bpopf:
  131.     cmp    byte ptr es:[bp],9dh        ;if next instruction is POPF
  132.     jne    stepperfin
  133.     mov    bp,sp
  134.     or    word ptr [bp+6+6],100h        ;do the same thing to us
  135.     jmp    int1bhid
  136. stepperfin:
  137.     mov    bp,dgroup            ; else check if in
  138.     mov    es,bp                ; bounds yet
  139.     mov    bp,sp                 ;ES is our DS, BP is stack
  140.  
  141. ;[BP+8] is the segment on the stack frame for the INT that invoked this
  142. ;routine.  See if it's our segment.
  143.  
  144.     mov    bp,[bp+2+6]            ;get segment from stack
  145.     cmp    bp,es:[psp]            ;is it our PSP seg?
  146.     jb    int1bhid            ;nope, its bigger
  147.     mov    es,es:[psp]            ;else get our PSP into ES
  148.     mov    bp,sp                ;back to stack
  149.     mov    bp,[bp+2+6]            ;get that segment again
  150.     cmp    bp,es:[2]            ;??? in our PSP
  151.     jae    int1bhid            ;still not us?
  152.     mov    bp,sp                ;BP back to stack
  153.     and    word ptr [bp+4+6],NOT 100h    ;finally in bounds, off tracing
  154.     mov    bp,dgroup
  155.     mov    es,bp                ;ES back to our data
  156.     mov    es:[CtrlBrkPressedInDOS],1    ;set flag
  157.     les    bp,es:[indos]            ; just make sure about DOS
  158.     test    byte ptr es:[bp],0FFh        ;see if in DOS now
  159.     jnz    int1bhid            ; run to completion if so
  160.     push    ax                ; else clear pending ints
  161.     mov    al,20h
  162.     out    20h,al                ;ACK PIC
  163.     pop    ax
  164.     pop    bp
  165.     pop    es
  166.     popf
  167.     jmp    entry1                ; return to debugger
  168.  
  169. int1bh    ENDP
  170. ;
  171. ; check if we have a proper exit PSP, if we don't assume a spawn
  172. ; in progress
  173. ;
  174. checkpsp    proc
  175.     push    ds
  176.     push    ax
  177.     push    bx
  178.     mov    ax,dgroup
  179.     mov    ds,ax            ;set DS to our data segment
  180.     mov    ah,51h            ;get PSP command
  181.     pushf
  182.     call    cs:[int21adr]        ;target pgm's int 21 handler
  183.     cmp    bx,[userbasepsp]    ;see if their PSP
  184.     pop    bx
  185.     pop    ax
  186.     pop    ds
  187.     ret
  188. checkpsp    endp
  189. ;
  190. ; int 20h exit - not understood yet. Need to determine what int20adr and
  191. ; int21adr really point to - our code, or the user's code.
  192. ;
  193. int20handle    PROC
  194.     call    checkpsp        ;see if user's PSP is current
  195.     jz    x20            ;ZF if so
  196.         jmp    cs:[int20adr]        ;else let user's int20 handle it?
  197. x20:
  198.     mov    ax,dgroup        ;set DS and ES to or data
  199.     mov    ds,ax
  200.     mov    es,ax
  201.     mov    bp,sp            ;reach onto stack
  202.     mov    ax,[bp+2]        ;to get segment of int 20
  203.     cmp    ax,[userbasepsp]    ;is
  204.     je    close20
  205.     PRINT_MESSAGE    <13,10,"Warning : Int 20h with CS <> PSP (program will crash)">
  206. close20:
  207.     JMP    int21exit0
  208. int20handle    ENDP
  209. ;
  210. ; int 21h handler.  Hooks 4ch,00h, 2521,3521,
  211. ; and exits to debugger if ctrl-break pressed
  212. ;
  213. int21handle    PROC
  214.     cmp    ah,4ch            ;exit to DOS command
  215.     je    int21exit4ch        ;go if so
  216.     cmp    ah,0            ;old exit command
  217.     je    int21exit0        ;handle that
  218.     cmp    ax,2521h        ; hook setting 21h
  219.     jne    chk35            ;nope, not doing that
  220.     mov    word ptr cs:[int21adr],dx    ;snag hook address
  221.     mov    word ptr cs:[int21adr+2],ds    ;from hooking app
  222.     jmp    didvect            ;and skip around
  223.  
  224. chk35:
  225.     cmp    ax,3521h        ; hooking reading int 21h
  226.     jne    normchain        ;nope, normal?
  227.     mov    bx,word ptr cs:[int21adr]    ;return OUR int21 address
  228.     mov    es,word ptr cs:[int21adr+2]    ;in this case
  229.  
  230. ;We get here if the program being debugged was either setting or getting
  231. ;the DOS dispatch vector INT 21h.
  232.  
  233. didvect:
  234.     push    bx            ; we have to get the flags back now
  235.     push    bp
  236.     mov    bp,sp            ;point to stack
  237.     mov    bx,[bp+4+4]        ;flags from int 21
  238.     xchg    bx,[bp+2]        ;xchg with our BX
  239.     pop    bp            ;flags now on top of stack
  240.     jmp    int21join        ;this will do popf, retf 2
  241. int21handle    ENDP
  242.  
  243. normchain:
  244.     push    bx            ; we have to get the ie flag back
  245.     push    bp
  246.     mov    bp,sp            ; all this is a grandiose simulated
  247.     mov    bx,[bp +4+4]        ; interrupt
  248.     xchg    bx,[bp+2]
  249.     pop    bp
  250.     call    cs:[int21adr]        ; call DOS
  251.     pushf                ;save DOS return flags
  252. int21join:
  253.     push    bp
  254.     push    es
  255.     mov    bp,dgroup        ; check for ctrl-break
  256.     mov    es,bp
  257.     test    es:[CtrlBrkPressedInDOS],1
  258.     pop    es
  259.     jnz    i21brk            ; yep- go to DOS
  260.     pop    bp
  261.     popf                ; NO, RETURN
  262.     retf    2
  263.  
  264. ;Oh brother! Well, we pushed the DOS return flags, then BP. AX contains
  265. ;the DOS return value. We set bp to sp and push AX. NOW the stack
  266. ;contains flags, bp, ax. [bp+2] points to the flags. For reasons unknown,
  267. ;we DON'T just MOV ax,[bp+2], we XCHG! NOW the flags are in AX and [bp+2]
  268. ;contains the DOS return value. So we pop AX from the push, pop
  269. ;bp, and ADD SP,2 to THROW AWAY the AX value we carefully put on the stack
  270. ;using XCHG! WHY? Why not pop bp, pop ax and just leave out the push ax
  271. ;and the add sp,2? Thats why we used XCHG in the first place, right?
  272. ;  Anyway, we got here if control-break was pressed in DOS, so we are
  273. ;taking the DOS return flags from the REAL DOS and placing them on the
  274. ;stack for the debugger's return from this int21 handler.
  275.  
  276. i21brk:
  277.     mov    bp,sp
  278.     push    ax
  279.     xchg    ax,[bp+2]        ; get DOS return flags to stack
  280.     mov    [bp+2+6],ax        ; and hit the debugger
  281.     pop    ax
  282.     pop    bp
  283.     add    sp,2
  284.     jmp    entry1
  285. ;
  286. ; DOS exit request comes here
  287. ;
  288.     
  289. int21exit0    PROC
  290.     sub    ax,ax
  291. int21exit0    ENDP
  292.  
  293.  
  294.  
  295. int21exit4ch    PROC
  296.     call    checkpsp
  297.     jnz    normchain
  298.     cld
  299.     call    untrace
  300.     mov    bx,dgroup
  301.     mov    ds,bx
  302.     mov    es,bx
  303.     mov    ss,[stackseg]
  304.     mov    sp,[stackofs]
  305.     sti
  306.     mov    [trapcount],0
  307.     mov    [CtrlBrkPressedInDOS],0
  308.     push    ax
  309.     call    SetDebugPSP        ; debug PSP
  310.     mov    si,offset dgroup : veclist    ; unhook ints
  311.     call    ReleaseRMInts
  312.     call    disableBreaks    ; Disable breakpoints if not
  313.     PRINT_MESSAGE    <13,10,"Normal exit, exit code: ">
  314.     pop    ax
  315.     call    PrintByte    ; error code
  316.     call    crlf
  317.     call    UnLoadProgram    ; unload the program
  318.     test    [lastexe],0ffh    ; see if was EXE
  319.     jz    rex
  320.     mov    ax,[lastcs]    ; yep, refresh CS:EIP
  321.     mov    [RegdumpCS],ax
  322.     mov    eax,[lastip]
  323.     mov    [RegdumpEIP],eax
  324. rex:
  325.     jmp    reentry
  326. int21exit4ch    ENDP
  327. ;
  328. ; unload program
  329. ;
  330. UnLoadProgram    PROC
  331.     call    UnLoadInts    ; reinit int table
  332.     call    KillFiles    ; kill their files
  333.     call    ReleaseMemory    ; release memory
  334.     mov    si,offset dgroup : grdbname    ; make an empty program
  335.     call    MakeEmptyProg
  336.     ret
  337. UnLoadProgram    ENDP
  338. ;
  339. ; kill program files by reading the handle table and closing them all
  340. ;
  341. KillFiles PROC
  342.     call    SetUserPSP
  343.     mov    fs,bx
  344.     mov    cx,fs:[32h]
  345. kf_lp:
  346.     dec    cx
  347.     mov    bx,cx
  348.     mov    ah,3eh
  349.     int    21h
  350.     cmp    cx,6
  351.     jae    kf_lp
  352.     call    SetDebugPSP
  353.     ret
  354. KillFiles    ENDP
  355. end