home *** CD-ROM | disk | FTP | other *** search
/ Power-Programmierung / CD2.mdf / tools / debugger / mdebug / mdebug1 / mdcmd.a86 < prev    next >
Encoding:
Text File  |  1992-05-29  |  20.9 KB  |  719 lines

  1. ; ----------------------------
  2. ; MDCmd
  3. ;
  4. ; Funktion:  Ausführen von Befehlen über MDEBUG (für TP 4.0 oder höher)
  5. ;
  6. ; Deklaration im Turbo-Pascal-Quelltext:
  7. ;
  8. ; {$F+} FUNCTION  MDCmd(    CheckInts : BOOLEAN;
  9. ;                       VAR regs      : REGISTER;
  10. ;                       VAR commands  : STRING) : BYTE; EXTERNAL;
  11. ; {$F-}
  12. ;
  13. ; Eingabe:   CheckInts - TRUE  : Unterdrückt die Ausführung der Interrupts
  14. ;                                20h, 27h und der Funktionen 0 und 31h des
  15. ;                                Interrupts 21h während des Aufrufs von
  16. ;                                MDEBUG
  17. ;                        FALSE : keine Überprüfung der Interrupts
  18. ;            regs      - Register-Werte für den Aufruf
  19. ;                        Bes.: Bei aktivem Passwort von MDEBUG  M U S S
  20. ;                              regs.DS:regs.SI entweder auf das Passwort
  21. ;                              ODER auf ein Nullbyte (= Passwort-Abfrage
  22. ;                              vom Benutzer) zeigen!
  23. ;                              Der Inhalt des Registers AX wird von der
  24. ;                              Routine verändert.
  25. ;            commands  - auszuführende Befehle als PASCAL-String
  26. ;
  27. ; Ausgabe:  regs  enthält die von MDEBUG gelieferten Register-Werte
  28. ;
  29. ;           Funktionswert:    -1 - Fehler beim Aufruf
  30. ;                          sonst - Aufruf ausgeführt
  31. ;
  32. ; Bes.:     Benötigt CHECKMD.OBJ, der Quelltext ist nicht vollständig MASM-
  33. ;           kompatibel.
  34. ;           Die Interrupts 20h, 21h und 27h werden temporär auf eine eigene
  35. ;           Routine gesetzt (über die Funktionen 25h und 35h des Interrupt
  36. ;           21h). Und in der Statustabelle von MDEBUG wird der Eintrag für
  37. ;           die zu benutzende Routine für den Interrupt 16h temporär auf
  38. ;           eine eigene Routine gesetzt.
  39. ;           Alle von der Routine benutzten internen Variablen liegen im
  40. ;           Codesegment.
  41. ;           Die Nummer des User-Ints wird direkt in den Code eingepatcht
  42. ;           (selbstmodifizierender Code!).
  43. ;
  44. ; Übersetzen: A86 MDCMD.A86 to MDCMD.OBJ
  45. ;
  46. ; (c) Bernd Schemmer 8/1991
  47. ; Letzter Update: 25.03.1992
  48. ; ----------------------------
  49.  
  50.          PUBLIC MDCmd         ; PUBLIC-Anweisung für die Routine
  51.  
  52.          EXTRN  CHECKMD:FAR   ; Die Routine CHECKMD ist in der Datei CHECKMD.OBJ
  53.                               ; definiert
  54.  
  55. ; ----------------------------
  56.  
  57. CODE SEGMENT BYTE PUBLIC
  58.          ASSUME CS:CODE,DS:CODE,ES:CODE,SS:CODE
  59.  
  60. Registers STRUC [BX]          ; Typ-Definitions des Turbo-Pascal-Typs REGISTER
  61.            _AX    dw ?        ; (Definition nicht MASM-kompatibel)
  62.            _BX    dw ?
  63.            _CX    dw ?
  64.            _DX    dw ?
  65.            _BP    dw ?
  66.            _SI    dw ?
  67.            _DI    dw ?
  68.            _DS    dw ?
  69.            _ES    dw ?
  70.            _FLAGS dw ?
  71.           ENDS
  72.  
  73.                               ; Offsets der Parameter auf dem Stack
  74. CheckInts     EQU  BYTE PTR [BP+0Eh]
  75. regs          EQU DWORD PTR [BP+0Ah]
  76. commands      EQU DWORD PTR [BP+06h]
  77.  
  78. CtrlChar      EQU '^'         ; Zeichen für CTRL-Tasten
  79. NumberSign    EQU '#'         ; Zeichen für Scancodes
  80.  
  81. StatusAufruf  EQU 00h         ; Funktions-Nummern für den User-Int von
  82. MDebugAufruf  EQU 04h         ; MDEBUG
  83. InAktivAufruf EQU 05h
  84.  
  85. Int16Offset   EQU 0Ah         ; Offset der Adresse der von MDEBUG genutzten
  86. Int16Segment  EQU 0Ch         ; Routine für den Interrupt 16h im Status-Record
  87.                               ; von MDEBUG
  88.  
  89. ; ------------------
  90.  
  91. StatusTable   dw 0,0          ; Adresse der Statustabelle von MDEBUG
  92.  
  93.                               ; Für die Variablen zum Sichern der Adresse der
  94.                               ; alten Routine für die Interrupts gilt:
  95.                               ; Falls das erste Wort 0FFFFh (= -1) enhält,
  96.                               ; wurde der Interrupt noch nicht umgesetzt bzw.
  97.                               ; schon wieder restauriert.
  98.  
  99. OldInt20      dw 0FFFFh,0     ; Adresse der alten Routine für den Interrupt 20h
  100. OldInt21      dw 0FFFFh,0     ; Adresse der alten Routine für den Interrupt 21h
  101. OldInt27      dw 0FFFFh,0     ; Adresse der alten Routine für den Interrupt 27h
  102.  
  103. OldInt16      dw 0FFFFh,0     ; Adresse der alten Routine für den Interrupt 16h
  104.                               ; (aus der Statustabelle von MDEBUG)
  105. Int16Sem      db 0FFh         ; Semaphor für die neue Int-16h-Routine
  106.                               ; Es gilt: 0FFh ->> Eintrag wurde noch nicht
  107.                               ;                   umgesetzt oder schon wieder
  108.                               ;                   restauriert
  109.                               ;            0h ->> Eintrag muß noch restauriert
  110.                               ;                   werden
  111.  
  112. SavedBP       dw 0            ; Speicherstelle zum Sichern von BP
  113.  
  114. PufferCount   db 0            ; akt. Anzahl Zeichen im Puffer für den neuen
  115.                               ; Interrupt 16h
  116.               db 0            ; dummy, ermöglicht den Wortweisen Zugriff auf
  117.                               ; die Variable Puffercount
  118.  
  119. PufferZeiger  dw 0,0          ; Zeiger auf den Puffer für den neuen Interrupt 16h
  120.                               ; (= Zeiger auf die Variable commands)
  121.  
  122. CheckInts_    db 0            ; Speicherstelle für den Parameter CheckInts
  123.  
  124. ; ----------------------------
  125.  
  126. MDCmd PROC FAR
  127.          push bp
  128.          mov bp,sp            ; Stack adressierbar machen
  129.  
  130. ; ------------------
  131.  
  132.          push bx              ; Register sichern
  133.          push cx
  134.          push dx
  135.          push si
  136.          push di
  137.          push es
  138.          push ds
  139.          pushf
  140.  
  141. ; ------------------
  142.  
  143.          mov al,CheckInts     ; Variablen initialisieren
  144.          mov cs:CheckInts_,al
  145.  
  146.          lds bx,commands
  147.          mov al,[bx]          ; AL = Längenzähler des Parameters commmands
  148.                               ;    = Anzahl Zeichen im Puffer für den neuen
  149.                               ;      Interrupt 16h
  150.          mov dx,ds            ; DX:BX = Adresse des Puffers für den neuen
  151.                               ;         Interrupt 16h
  152.  
  153.          push cs
  154.          pop ds               ; DS=CS
  155.          mov PufferCount,al
  156.  
  157.          inc bx               ; Längenbyte überlesen
  158.          mov PufferZeiger,bx
  159.          mov PufferZeiger+2,dx
  160.  
  161. ; ------------------
  162.  
  163.          call CheckMD         ; Testen, ob MDEBUG geladen ist
  164.          mov IntNumber,al     ; evtl. User-Int von MDEBUG sichern
  165.  
  166.          cmp al,-1            ; auf Fehler testen
  167.          je MDCmd_0
  168.          or al,al
  169.          jne MDCmd_1
  170. MDCmd_0:
  171.          jmp MDCmdError
  172.  
  173. ; ------------------
  174. MDCmd_1:
  175.          call SetInt16        ; Interrupt-16h-Routine in MDEBUG umsetzen
  176.          jc MDCmd_0           ; Fehler aufgetreten
  177.  
  178. ; ------------------
  179.  
  180.          call SetInterrupts   ; Interrupt 20h, 21h und 27h sichern und
  181.                               ; umsetzen
  182. ; ------------------
  183.          mov SavedBP,bp       ; BP sichern
  184.  
  185.          lds bx,regs          ; DS:BX -> Parameter regs
  186.  
  187.                               ; Register laden
  188.          mov cx,_cx           ; Register CX
  189.          mov dx,_dx           ; Register DX
  190.          mov bp,_bp           ; Register BP
  191.          mov si,_si           ; Register SI
  192.          mov di,_di           ; Register DI
  193.          mov es,_es           ; Register ES
  194.          push _flags          ; Flagregister
  195.          popf
  196.  
  197.          push _ds
  198.          push _bx
  199.          pop bx               ; Register BX
  200.          pop ds               ; Register DS
  201.  
  202.          mov ah,MDebugAufruf
  203.          call CallMDebug      ; MDEBUG aufrufen
  204.  
  205.          push bp              ; Register sichern
  206.          push bx
  207.          push ds
  208.  
  209.          mov bp,cs:SavedBP
  210.          lds bx,regs          ; DS:BX -> Parameter regs
  211.  
  212.          mov _ax,ax           ; Register AX
  213.          mov _cx,cx           ; Register CX
  214.          mov _dx,dx           ; Register DX
  215.          mov _si,si           ; Register SI
  216.          mov _di,di           ; Register DI
  217.          mov _es,es           ; Register ES
  218.  
  219.          pushf
  220.          pop ax
  221.          mov _flags,ax        ; Flagregister
  222.  
  223.          pop ax
  224.          mov _ds,ax           ; Register DS
  225.  
  226.          pop ax
  227.          mov _bx,ax           ; Register BX
  228.  
  229.          pop bp
  230.          mov _bp,bp           ; Register BP
  231.  
  232.          sti
  233.          mov al,0
  234.          jnc MDCmdEnd
  235.  
  236. ; ----------------------------
  237. MDCmdError:
  238.          mov ax,0FFFFh
  239.  
  240. MDCmdEnd:
  241.          call ResetInterrupts ; Interrupts zurücksetzen
  242.  
  243.          popf                 ; Register restaurieren
  244.          pop ds
  245.          pop es
  246.          pop di
  247.          pop si
  248.          pop dx
  249.          pop cx
  250.          pop bx
  251.  
  252.          pop bp
  253.          retf 0A              ; Parameter vom Stack und raus
  254.  
  255. ; ----------------------------
  256. ; NewInt16
  257. ;
  258. ; Funktion: Neue Interrupt 16h-Routine
  259. ;
  260. ; Bes.:     Aufruf nur per INT-Befehl!
  261. ;
  262. Int16Code dw 0
  263.  
  264. NewInt16:
  265.          mov cs:Int16Code,ax
  266.  
  267.          cmp cs:PufferCount,0
  268.          je Int16Through      ; Puffer ist leer, alte Routine für den
  269.                               ; Interrupt 16h aufrufen
  270.  
  271.                               ; Funktions-Code überprüfen
  272.          cmp ah,00h
  273.          je Function0         ; Funktion 0 : GetKey
  274.          cmp ah,010h
  275.          je Function0         ; Funktion 10: GetKey
  276.          cmp ah,01h
  277.          je Function01        ; Funktion 1 : Look Ahead
  278.          cmp ah,011h
  279.          je Function01        ; Funktion 11: Look Ahead
  280.  
  281. Int16Through:                 ; Aufruf weiterleiten zum alten Interrupt
  282.          jmp dword ptr cs:OldInt16
  283.  
  284. Function0:
  285.          call GetBufferKey    ; Nächste 'Taste' ermitteln
  286.          or ax,ax
  287.          jnz Function0_End
  288.                               ; Code 0 (Simuliere leeren Tastaturpuffer)
  289.          mov ax,cs:Int16Code  ; überlesen
  290.          jmp NewInt16
  291.  
  292. Function0_End:
  293.          iret
  294.  
  295. Function01:
  296.                               ; Look Ahead
  297.          push cs:PufferZeiger
  298.          push WORD PTR cs:PufferCount
  299.  
  300.          call GetBufferKey
  301.          or ax,ax
  302.          jnz Function01_1
  303.                               ; Code 0 -> leeren Puffer simulieren
  304.          add sp,4             ; gesicherte Werte vom Stack
  305.          xor ax,ax            ; Zeroflag setzen
  306.          sti
  307.          retf 2
  308.  
  309. Function01_1:
  310.          pop WORD PTR cs:PufferCount
  311.          pop cs:PufferZeiger
  312.  
  313.          cmp cs:PufferCount,0
  314.          sti
  315.          retf 02
  316.  
  317. ; ----------------------------
  318. ; GetBufferKey
  319. ;
  320. ; Funktion: Ermittelt die nächste 'Taste' aus dem Puffer
  321. ;
  322. ; Ausgabe:  AX = 'Taste'
  323. ;           Die Variablen zur Verwaltung des Puffers wurden korrigiert
  324. ;
  325. GetBufferKey PROC NEAR
  326.          push ds
  327.          push si
  328.          push cx
  329.          
  330.          mov cx,WORD PTR cs:PufferCount
  331.                               ; CX = Anzahl restlicher Zeichen im Puffer
  332.  
  333.          lds si,DWORD PTR cs:PufferZeiger
  334.                               ; DS:SI -> akt. Zeichen im Puffer
  335.          mov al,[si]
  336.          inc si               ; AL = akt. Zeichen aus dem Puffer
  337.         
  338.          dec cx               ; Anzahl der restlichen Zeichen im Puffer
  339.                               ; korrigieren
  340.  
  341.          cmp al,CtrlChar      ; Zeichen auswerten
  342.          jne NoCtrlChar
  343. ; --------
  344.                               ; Kontroll-Zeichen '^'
  345.          mov ah,[si]          ; AH = nächstes Zeichen
  346.          cmp ah,'A'
  347.          jb InvalidCtrlChar
  348.          cmp ah,'Z'
  349.          ja InvalidCtrlChar
  350.          sub ah,'@'           ; nächstes Zeichen zw. 'A' und 'Z'
  351.          mov al,ah            ; ->> CTRL-Taste
  352.  
  353.          inc si               ; Variablen für die Pufferverwaltung korrigieren
  354.          dec cx
  355.  
  356. InvalidCtrlChar:
  357.          xor ah,ah            ; '^' so übernehmen
  358.          jmp GetBufferKeyEnd
  359.  
  360. ; --------
  361. NoCtrlChar:
  362.          cmp al,NumberSign
  363.          jne GetBufferKeyEnd
  364. ; --------
  365.          call GetScanCode
  366.  
  367. GetBufferKeyEnd:
  368.                               ; Variablen für die Pufferverwaltung sichern
  369.          mov cs:PufferZeiger,si
  370.          mov WORD PTR cs:PufferCount,cx
  371.  
  372.          pop cx
  373.          pop si
  374.          pop ds
  375.          ret
  376.  
  377. ; ----------------------------
  378. ; GetScanCode
  379. ;
  380. ; Funktion:           Konvertieren einer ASCII-Zeichenkette in einen SCAN-Code
  381. ;
  382. ; Eingabe-Parameter:  DS:SI - Zu konvertierende Zeichenkette
  383. ;                     CX = Anzahl restlicher Zeichen im Puffer
  384. ;
  385. ; Ausgabe-Parameter:  AX = SCAN-Code oder '#'
  386. ;                     SI -> nächstes Zeichen im Puffer
  387. ;                     und CX enthält die Anzahl der restlicher
  388. ;                     Zeichen im Puffer
  389. ;
  390. ; Bes.:               Falls der angegebene Wert weniger als 4 Ziffern hat,
  391. ;                     wird von links mit Nullen aufgefüllt.
  392. ;
  393. GetScanCode PROC NEAR
  394.          push bx
  395.          push dx
  396.  
  397.          mov dx,4             ; max. 4 Zeichen
  398.          xor bx,bx            ; BX = Ergebnis
  399.  
  400.          mov al,[si]          ; AL = erstes Zeichen
  401.          call Hex_Digit?
  402.          mov bl,al
  403.          jnc GetScancode0
  404.                               ; Nummernzeichen übernehmen
  405.          mov bx,NumberSign
  406.          jmp GetScancodeEnd
  407.  
  408. GetScancode0:
  409.          inc si               ; Zeiger korrigieren
  410.          dec cx               ; Anzahl Zeichen im Puffer korrigieren
  411.          jcxz GetScancodeEnd  ; Ende des Puffers erreicht
  412.  
  413.          dec dx               ; schon 4 Zeichen gelesen?
  414.          jz GetScancodeEnd    ; ja, Scancode zuende
  415.  
  416.          mov al,[si]          ; AL = akt. Zeichen
  417.          call Hex_Digit?
  418.          jc GetScancodeEnd    ; Zahl zuende
  419.  
  420.          shl bx,1
  421.          shl bx,1
  422.          shl bx,1
  423.          shl bx,1
  424.          or bl,al
  425.  
  426.          jmp GetScancode0
  427.  
  428. GetScancodeEnd:
  429.           mov ax,bx           ; 'Taste' nach AX
  430.  
  431.           pop dx
  432.           pop bx
  433.           ret
  434.  
  435. ; --------------------------------------
  436. ; Hex_Digit?
  437. ;
  438. ; Funktion:  Wandelt das ASCII-Zeichen in dessen binaeren Wert,
  439. ;            falls es sich um eine Hexziffer handelt.
  440. ;            Im Fehlerfall wird das Carry-Flag gesetzt
  441. ;
  442. ; Eingabe:   AL = ASCII-Zeichen
  443. ;
  444. ; Ausgabe:   CF = 0 ->> AL = binärer Wert
  445. ;            CF = 1 ->> Fehler, ASCII-Zeichen ist keine Hexziffer
  446. ;
  447. Hex_digit? PROC NEAR
  448.          cmp al,'9'
  449.          ja HexDigit1
  450.          sub al,'0'
  451.          jmp HexDigit2
  452.  
  453. HexDigit1:
  454.          and al,0DFh
  455.          sub al,'A'-10xD
  456.  
  457. HexDigit2:
  458.          cmp al,010h
  459.          cmc
  460.          ret
  461.  
  462. ; ----------------------------
  463. ; SetInt16
  464. ;
  465. ; Funktion:  Sichert die Adresse der Statustabelle von MDEBUG und der alten
  466. ;            Routine für den Interrupt 16h aus der Statustabelle von MDEBUG.
  467.  
  468. ;            Schreibt die Adresse der neuen Routine für den Interrupt 16h
  469. ;            in die Statustabelle von MDEBUG
  470. ;
  471. ; Ausgabe:   CF = 0 ->> okay
  472. ;            CF = 1 ->> Fehler beim Aufruf von MDEBUG, keine Änderungen
  473. ;                       vorgenommen
  474. ;
  475. SetInt16 PROC NEAR
  476.          push ds
  477.          push si
  478.          push bx
  479.          lds bx,regs          ; DS:BX -> Parameter regs
  480.          mov si,_si
  481.          mov ds,_ds           ; DS:SI -> evtl. Passwort
  482.  
  483.          mov ah,StatusAufruf  ; Daten von MDEBUG ermitteln
  484.          call CallMDebug
  485.          jc SetInt16Error     ; Fehler beim Aufruf von MDEBUG
  486.  
  487.          cli
  488.          mov cs:Int16Sem,0    ; Semaphor löschen
  489.  
  490.                               ; DS:SI -> Statustabelle von MDEBUG
  491.                               ; Adresse dieser speichern
  492.          mov cs:StatusTable,si
  493.          mov cs:StatusTable+2,ds
  494.  
  495.                               ; alte Adresse der Int-16h-Routine speichern
  496.          mov ax,[si+Int16Offset]
  497.          mov cs:OldInt16,ax
  498.          mov ax,[si+Int16Segment]
  499.          mov cs:OldInt16+2,ax
  500.  
  501.                               ; Neue Adresse des Interrupt 16h eintragen
  502.          mov WORD PTR [si+Int16Offset],Offset NewInt16
  503.  
  504.          mov WORD PTR [si+Int16Segment],cs
  505.          sti
  506.          clc
  507.  
  508. SetInt16Error:
  509.          pop bx
  510.          pop si
  511.          pop ds
  512.          ret
  513.  
  514. ; ----------------------------
  515. ; ResetInt16
  516. ;
  517. ; Funktion:  Restauriert die Adresse der alten Routine für den Interrupt 16h
  518. ;            in der Statustabelle von MDEBUG
  519. ;
  520. ; Bes.:      Verändert keine Register!
  521. ;
  522. ResetInt16 PROC NEAR
  523.          push ds
  524.          push si
  525.          push ax
  526.  
  527.          cli
  528.          xor al,al            ; Semaphor testen und setzen
  529.          dec al               ; AL = -1
  530.          xchg cs:[Int16Sem],al
  531.          or al,al
  532.          jnz ResetInt16End    ; Int 16h wurde schon restauriert
  533.  
  534.          lds si,cs:StatusTable
  535.                               ; DS:SI -> Statustabelle von MDEBUG
  536.  
  537.          mov ax,cs:Oldint16   ; alte Adresse der Routine restaurieren
  538.          mov ds:[si+Int16Offset],ax
  539.          mov ax,cs:OldInt16+2
  540.          mov ds:[si+Int16Segment],ax
  541.  
  542. ResetInt16End:
  543.          sti
  544.  
  545.          pop ax
  546.          pop si
  547.          pop ds
  548.          ret
  549.  
  550. ; ----------------------------
  551. ; SetInterrupts
  552. ;
  553. ; Funktion: Sichern und umsetzen der Interrupts 20h, 21h und 27h
  554. ;
  555. ; Eingabe:  DS = CS
  556. ;
  557. SetInterrupts PROC NEAR
  558.          mov ax,03521h        ; Interrupt 21h sichern und umsetzen
  559.          int 021h
  560.          mov OldInt21,bx
  561.          mov OldInt21+2,es
  562.          mov ax,02521h
  563.          mov dx,offset NewInt21
  564.          int 021h
  565.  
  566.          mov ax,03520h        ; Interrupt 20h sichern und umsetzen
  567.          int 021h
  568.          mov OldInt20,bx
  569.          mov OldInt20+2,es
  570.          mov ax,02520h
  571.          mov dx,offset NewInt20
  572.          int 021h
  573.  
  574.          mov ax,03527h        ; Interrupt 27h sichern und umsetzen
  575.          int 021h
  576.          mov OldInt27,bx
  577.          mov OldInt27+2,es
  578.          mov ax,02527h
  579.          mov dx,offset NewInt27
  580.          int 021h
  581.          ret
  582.  
  583. ; ----------------------------
  584. ; NewInt27
  585. ;
  586. ; Funktion:  Restaurieren der Interrupts falls der Interrupt 27h
  587. ;            aus MDEBUG heraus aufgerufen wird
  588. ;
  589. NewInt27:
  590.          cmp cs:CheckInts_,0h ; Interrupt-Aufruf unterdrücken?
  591.          jne IgnoreInts1
  592.          call ResetInterrupts
  593.          int 027h
  594.  
  595. ; ----------------------------
  596. ; NewInt20
  597. ;
  598. ; Funktion:  Restaurieren der Interrupts falls der Interrupt 20h
  599. ;            aus MDEBUG heraus aufgerufen wird
  600. ;
  601. NewInt20:
  602.          cmp cs:CheckInts_,0h ; Interrupt-Aufruf unterdrücken?
  603.          jne IgnoreInts1
  604.          call ResetInterrupts
  605.          int 020h
  606.  
  607. ; ----------------------------
  608. ; NewInt21
  609. ;
  610. ; Funktion:  Abfangen der Funktionen 00, 31h und 4Ch des Interrupts 21h
  611. ;            Restaurieren der Interrupts falls diese Funktionen aus
  612. ;            MDEBUG heraus aufgerufen werden
  613. ;
  614. NewInt21:
  615.          pushf
  616.          cmp ah,0
  617.          je NewInt21_1
  618.          cmp ah,031h
  619.          je NewInt21_1
  620.          cmp ah,04Ch
  621.          jne NewInt21_0
  622.  
  623.          push bx
  624.          push ax
  625.          mov ah,InAktivAufruf
  626.          mov bl,0           ; BL = Neuer Wert für das Aktiv-Flag
  627.          call CallMDEBUG    ; Aktiv-Flag von MDEBUG zurücksetzen
  628.          pop ax
  629.          pop bx
  630.          jmp SHORT NewInt21_2
  631.  
  632. NewInt21_0:
  633.          popf               ; weiter zum alten Interrupt
  634.          jmp dword ptr cs:OldInt21
  635.  
  636. NewInt21_1:
  637.          cmp cs:CheckInts_,0h ; Interrupt-Aufruf unterdrücken?
  638.          jne IgnoreInts
  639.  
  640. NewInt21_2:
  641.          popf
  642.          call ResetInterrupts ; Interrupt-Adressen korrigieren
  643.          int 021h             ; und eigentliche Funktion ausführen
  644.  
  645.          pushf                ; zur Vorsicht, falls der Interrupt zurückkehrt
  646. IgnoreInts:
  647.          popf
  648. IgnoreInts1:
  649.          iret
  650.  
  651. ; ----------------------------
  652. ; ResetInterrupts
  653. ;
  654. ; Funktion: Zurücksetzen der Interrupts 20h, 21h, 27h und 16h.
  655. ;
  656. ResetInterrupts PROC NEAR
  657.          push ax
  658.          push ds
  659.          push dx
  660.          push bx
  661.  
  662.          mov bx,0FFFFh
  663.  
  664.          mov ax,02521h
  665.          lds dx,cs:OLdint21
  666.  
  667.          cmp dx,bx            ; Interrupt schon restauriert?
  668.          if nz int 021h       ;
  669.          mov cs:OldInt21,bx   ; Semaphor setzen
  670.  
  671.          mov ax,02520h
  672.          lds dx,cs:OldInt20
  673.          cmp dx,0FFFFh        ; Interrupt schon restauriert?
  674.          if nz int 021h       ;
  675.          mov cs:OldInt20,bx   ; Semaphor setzen
  676.  
  677.          mov ax,02527h
  678.          lds dx,cs:OldInt27
  679.          cmp dx,0FFFFh        ; Interrupt schon restauriert?
  680.          if nz int 021h       ;
  681.          mov cs:OldInt27,bx   ; Semaphor setzen
  682.  
  683.          pop bx
  684.          pop dx
  685.          pop ds
  686.          pop ax
  687.  
  688.          call ResetInt16      ; Interrupt 16h zurücksetzen
  689.          ret
  690.  
  691. ; ----------------------------
  692. ; CallMDebug
  693. ;
  694. ; Funktion: Aufruf von MDEBUG
  695. ;
  696. ; Eingabe:  Alle Register
  697. ;
  698. ; Ausgabe:  CF = 0 ->> Aufruf okay
  699. ;           CF = 1 ->> Aufruf gescheitert
  700. ;
  701. CallMDebug PROC NEAR
  702.          clc                  ; Carryflag löschen
  703.          db 0CDh              ; Maschinencode für INT-Befehl
  704. IntNumber db 060h             ; Nummer des User-Ints von MDEBUG (wird gepatcht)
  705.          jc ret
  706.          cmp ah,0FFh
  707.          je CallMDebugError
  708.          clc
  709.          ret
  710.  
  711. CallMDebugError:
  712.          stc
  713.          ret
  714.  
  715. ; ----------------------------
  716.          CODE ENDS
  717. ; ----------------------------
  718.  
  719.