home *** CD-ROM | disk | FTP | other *** search
- ; ----------------------------
- ; MDCmd
- ;
- ; Funktion: Ausführen von Befehlen über MDEBUG (für TP 4.0 oder höher)
- ;
- ; Deklaration im Turbo-Pascal-Quelltext:
- ;
- ; {$F+} FUNCTION MDCmd( CheckInts : BOOLEAN;
- ; VAR regs : REGISTER;
- ; VAR commands : STRING) : BYTE; EXTERNAL;
- ; {$F-}
- ;
- ; Eingabe: CheckInts - TRUE : Unterdrückt die Ausführung der Interrupts
- ; 20h, 27h und der Funktionen 0 und 31h des
- ; Interrupts 21h während des Aufrufs von
- ; MDEBUG
- ; FALSE : keine Überprüfung der Interrupts
- ; regs - Register-Werte für den Aufruf
- ; Bes.: Bei aktivem Passwort von MDEBUG M U S S
- ; regs.DS:regs.SI entweder auf das Passwort
- ; ODER auf ein Nullbyte (= Passwort-Abfrage
- ; vom Benutzer) zeigen!
- ; Der Inhalt des Registers AX wird von der
- ; Routine verändert.
- ; commands - auszuführende Befehle als PASCAL-String
- ;
- ; Ausgabe: regs enthält die von MDEBUG gelieferten Register-Werte
- ;
- ; Funktionswert: -1 - Fehler beim Aufruf
- ; sonst - Aufruf ausgeführt
- ;
- ; Bes.: Benötigt CHECKMD.OBJ, der Quelltext ist nicht vollständig MASM-
- ; kompatibel.
- ; Die Interrupts 20h, 21h und 27h werden temporär auf eine eigene
- ; Routine gesetzt (über die Funktionen 25h und 35h des Interrupt
- ; 21h). Und in der Statustabelle von MDEBUG wird der Eintrag für
- ; die zu benutzende Routine für den Interrupt 16h temporär auf
- ; eine eigene Routine gesetzt.
- ; Alle von der Routine benutzten internen Variablen liegen im
- ; Codesegment.
- ; Die Nummer des User-Ints wird direkt in den Code eingepatcht
- ; (selbstmodifizierender Code!).
- ;
- ; Übersetzen: A86 MDCMD.A86 to MDCMD.OBJ
- ;
- ; (c) Bernd Schemmer 8/1991
- ; Letzter Update: 25.03.1992
- ; ----------------------------
-
- PUBLIC MDCmd ; PUBLIC-Anweisung für die Routine
-
- EXTRN CHECKMD:FAR ; Die Routine CHECKMD ist in der Datei CHECKMD.OBJ
- ; definiert
-
- ; ----------------------------
-
- CODE SEGMENT BYTE PUBLIC
- ASSUME CS:CODE,DS:CODE,ES:CODE,SS:CODE
-
- Registers STRUC [BX] ; Typ-Definitions des Turbo-Pascal-Typs REGISTER
- _AX dw ? ; (Definition nicht MASM-kompatibel)
- _BX dw ?
- _CX dw ?
- _DX dw ?
- _BP dw ?
- _SI dw ?
- _DI dw ?
- _DS dw ?
- _ES dw ?
- _FLAGS dw ?
- ENDS
-
- ; Offsets der Parameter auf dem Stack
- CheckInts EQU BYTE PTR [BP+0Eh]
- regs EQU DWORD PTR [BP+0Ah]
- commands EQU DWORD PTR [BP+06h]
-
- CtrlChar EQU '^' ; Zeichen für CTRL-Tasten
- NumberSign EQU '#' ; Zeichen für Scancodes
-
- StatusAufruf EQU 00h ; Funktions-Nummern für den User-Int von
- MDebugAufruf EQU 04h ; MDEBUG
- InAktivAufruf EQU 05h
-
- Int16Offset EQU 0Ah ; Offset der Adresse der von MDEBUG genutzten
- Int16Segment EQU 0Ch ; Routine für den Interrupt 16h im Status-Record
- ; von MDEBUG
-
- ; ------------------
-
- StatusTable dw 0,0 ; Adresse der Statustabelle von MDEBUG
-
- ; Für die Variablen zum Sichern der Adresse der
- ; alten Routine für die Interrupts gilt:
- ; Falls das erste Wort 0FFFFh (= -1) enhält,
- ; wurde der Interrupt noch nicht umgesetzt bzw.
- ; schon wieder restauriert.
-
- OldInt20 dw 0FFFFh,0 ; Adresse der alten Routine für den Interrupt 20h
- OldInt21 dw 0FFFFh,0 ; Adresse der alten Routine für den Interrupt 21h
- OldInt27 dw 0FFFFh,0 ; Adresse der alten Routine für den Interrupt 27h
-
- OldInt16 dw 0FFFFh,0 ; Adresse der alten Routine für den Interrupt 16h
- ; (aus der Statustabelle von MDEBUG)
- Int16Sem db 0FFh ; Semaphor für die neue Int-16h-Routine
- ; Es gilt: 0FFh ->> Eintrag wurde noch nicht
- ; umgesetzt oder schon wieder
- ; restauriert
- ; 0h ->> Eintrag muß noch restauriert
- ; werden
-
- SavedBP dw 0 ; Speicherstelle zum Sichern von BP
-
- PufferCount db 0 ; akt. Anzahl Zeichen im Puffer für den neuen
- ; Interrupt 16h
- db 0 ; dummy, ermöglicht den Wortweisen Zugriff auf
- ; die Variable Puffercount
-
- PufferZeiger dw 0,0 ; Zeiger auf den Puffer für den neuen Interrupt 16h
- ; (= Zeiger auf die Variable commands)
-
- CheckInts_ db 0 ; Speicherstelle für den Parameter CheckInts
-
- ; ----------------------------
-
- MDCmd PROC FAR
- push bp
- mov bp,sp ; Stack adressierbar machen
-
- ; ------------------
-
- push bx ; Register sichern
- push cx
- push dx
- push si
- push di
- push es
- push ds
- pushf
-
- ; ------------------
-
- mov al,CheckInts ; Variablen initialisieren
- mov cs:CheckInts_,al
-
- lds bx,commands
- mov al,[bx] ; AL = Längenzähler des Parameters commmands
- ; = Anzahl Zeichen im Puffer für den neuen
- ; Interrupt 16h
- mov dx,ds ; DX:BX = Adresse des Puffers für den neuen
- ; Interrupt 16h
-
- push cs
- pop ds ; DS=CS
- mov PufferCount,al
-
- inc bx ; Längenbyte überlesen
- mov PufferZeiger,bx
- mov PufferZeiger+2,dx
-
- ; ------------------
-
- call CheckMD ; Testen, ob MDEBUG geladen ist
- mov IntNumber,al ; evtl. User-Int von MDEBUG sichern
-
- cmp al,-1 ; auf Fehler testen
- je MDCmd_0
- or al,al
- jne MDCmd_1
- MDCmd_0:
- jmp MDCmdError
-
- ; ------------------
- MDCmd_1:
- call SetInt16 ; Interrupt-16h-Routine in MDEBUG umsetzen
- jc MDCmd_0 ; Fehler aufgetreten
-
- ; ------------------
-
- call SetInterrupts ; Interrupt 20h, 21h und 27h sichern und
- ; umsetzen
- ; ------------------
- mov SavedBP,bp ; BP sichern
-
- lds bx,regs ; DS:BX -> Parameter regs
-
- ; Register laden
- mov cx,_cx ; Register CX
- mov dx,_dx ; Register DX
- mov bp,_bp ; Register BP
- mov si,_si ; Register SI
- mov di,_di ; Register DI
- mov es,_es ; Register ES
- push _flags ; Flagregister
- popf
-
- push _ds
- push _bx
- pop bx ; Register BX
- pop ds ; Register DS
-
- mov ah,MDebugAufruf
- call CallMDebug ; MDEBUG aufrufen
-
- push bp ; Register sichern
- push bx
- push ds
-
- mov bp,cs:SavedBP
- lds bx,regs ; DS:BX -> Parameter regs
-
- mov _ax,ax ; Register AX
- mov _cx,cx ; Register CX
- mov _dx,dx ; Register DX
- mov _si,si ; Register SI
- mov _di,di ; Register DI
- mov _es,es ; Register ES
-
- pushf
- pop ax
- mov _flags,ax ; Flagregister
-
- pop ax
- mov _ds,ax ; Register DS
-
- pop ax
- mov _bx,ax ; Register BX
-
- pop bp
- mov _bp,bp ; Register BP
-
- sti
- mov al,0
- jnc MDCmdEnd
-
- ; ----------------------------
- MDCmdError:
- mov ax,0FFFFh
-
- MDCmdEnd:
- call ResetInterrupts ; Interrupts zurücksetzen
-
- popf ; Register restaurieren
- pop ds
- pop es
- pop di
- pop si
- pop dx
- pop cx
- pop bx
-
- pop bp
- retf 0A ; Parameter vom Stack und raus
-
- ; ----------------------------
- ; NewInt16
- ;
- ; Funktion: Neue Interrupt 16h-Routine
- ;
- ; Bes.: Aufruf nur per INT-Befehl!
- ;
- Int16Code dw 0
-
- NewInt16:
- mov cs:Int16Code,ax
-
- cmp cs:PufferCount,0
- je Int16Through ; Puffer ist leer, alte Routine für den
- ; Interrupt 16h aufrufen
-
- ; Funktions-Code überprüfen
- cmp ah,00h
- je Function0 ; Funktion 0 : GetKey
- cmp ah,010h
- je Function0 ; Funktion 10: GetKey
- cmp ah,01h
- je Function01 ; Funktion 1 : Look Ahead
- cmp ah,011h
- je Function01 ; Funktion 11: Look Ahead
-
- Int16Through: ; Aufruf weiterleiten zum alten Interrupt
- jmp dword ptr cs:OldInt16
-
- Function0:
- call GetBufferKey ; Nächste 'Taste' ermitteln
- or ax,ax
- jnz Function0_End
- ; Code 0 (Simuliere leeren Tastaturpuffer)
- mov ax,cs:Int16Code ; überlesen
- jmp NewInt16
-
- Function0_End:
- iret
-
- Function01:
- ; Look Ahead
- push cs:PufferZeiger
- push WORD PTR cs:PufferCount
-
- call GetBufferKey
- or ax,ax
- jnz Function01_1
- ; Code 0 -> leeren Puffer simulieren
- add sp,4 ; gesicherte Werte vom Stack
- xor ax,ax ; Zeroflag setzen
- sti
- retf 2
-
- Function01_1:
- pop WORD PTR cs:PufferCount
- pop cs:PufferZeiger
-
- cmp cs:PufferCount,0
- sti
- retf 02
-
- ; ----------------------------
- ; GetBufferKey
- ;
- ; Funktion: Ermittelt die nächste 'Taste' aus dem Puffer
- ;
- ; Ausgabe: AX = 'Taste'
- ; Die Variablen zur Verwaltung des Puffers wurden korrigiert
- ;
- GetBufferKey PROC NEAR
- push ds
- push si
- push cx
-
- mov cx,WORD PTR cs:PufferCount
- ; CX = Anzahl restlicher Zeichen im Puffer
-
- lds si,DWORD PTR cs:PufferZeiger
- ; DS:SI -> akt. Zeichen im Puffer
- mov al,[si]
- inc si ; AL = akt. Zeichen aus dem Puffer
-
- dec cx ; Anzahl der restlichen Zeichen im Puffer
- ; korrigieren
-
- cmp al,CtrlChar ; Zeichen auswerten
- jne NoCtrlChar
- ; --------
- ; Kontroll-Zeichen '^'
- mov ah,[si] ; AH = nächstes Zeichen
- cmp ah,'A'
- jb InvalidCtrlChar
- cmp ah,'Z'
- ja InvalidCtrlChar
- sub ah,'@' ; nächstes Zeichen zw. 'A' und 'Z'
- mov al,ah ; ->> CTRL-Taste
-
- inc si ; Variablen für die Pufferverwaltung korrigieren
- dec cx
-
- InvalidCtrlChar:
- xor ah,ah ; '^' so übernehmen
- jmp GetBufferKeyEnd
-
- ; --------
- NoCtrlChar:
- cmp al,NumberSign
- jne GetBufferKeyEnd
- ; --------
- call GetScanCode
-
- GetBufferKeyEnd:
- ; Variablen für die Pufferverwaltung sichern
- mov cs:PufferZeiger,si
- mov WORD PTR cs:PufferCount,cx
-
- pop cx
- pop si
- pop ds
- ret
-
- ; ----------------------------
- ; GetScanCode
- ;
- ; Funktion: Konvertieren einer ASCII-Zeichenkette in einen SCAN-Code
- ;
- ; Eingabe-Parameter: DS:SI - Zu konvertierende Zeichenkette
- ; CX = Anzahl restlicher Zeichen im Puffer
- ;
- ; Ausgabe-Parameter: AX = SCAN-Code oder '#'
- ; SI -> nächstes Zeichen im Puffer
- ; und CX enthält die Anzahl der restlicher
- ; Zeichen im Puffer
- ;
- ; Bes.: Falls der angegebene Wert weniger als 4 Ziffern hat,
- ; wird von links mit Nullen aufgefüllt.
- ;
- GetScanCode PROC NEAR
- push bx
- push dx
-
- mov dx,4 ; max. 4 Zeichen
- xor bx,bx ; BX = Ergebnis
-
- mov al,[si] ; AL = erstes Zeichen
- call Hex_Digit?
- mov bl,al
- jnc GetScancode0
- ; Nummernzeichen übernehmen
- mov bx,NumberSign
- jmp GetScancodeEnd
-
- GetScancode0:
- inc si ; Zeiger korrigieren
- dec cx ; Anzahl Zeichen im Puffer korrigieren
- jcxz GetScancodeEnd ; Ende des Puffers erreicht
-
- dec dx ; schon 4 Zeichen gelesen?
- jz GetScancodeEnd ; ja, Scancode zuende
-
- mov al,[si] ; AL = akt. Zeichen
- call Hex_Digit?
- jc GetScancodeEnd ; Zahl zuende
-
- shl bx,1
- shl bx,1
- shl bx,1
- shl bx,1
- or bl,al
-
- jmp GetScancode0
-
- GetScancodeEnd:
- mov ax,bx ; 'Taste' nach AX
-
- pop dx
- pop bx
- ret
-
- ; --------------------------------------
- ; Hex_Digit?
- ;
- ; Funktion: Wandelt das ASCII-Zeichen in dessen binaeren Wert,
- ; falls es sich um eine Hexziffer handelt.
- ; Im Fehlerfall wird das Carry-Flag gesetzt
- ;
- ; Eingabe: AL = ASCII-Zeichen
- ;
- ; Ausgabe: CF = 0 ->> AL = binärer Wert
- ; CF = 1 ->> Fehler, ASCII-Zeichen ist keine Hexziffer
- ;
- Hex_digit? PROC NEAR
- cmp al,'9'
- ja HexDigit1
- sub al,'0'
- jmp HexDigit2
-
- HexDigit1:
- and al,0DFh
- sub al,'A'-10xD
-
- HexDigit2:
- cmp al,010h
- cmc
- ret
-
- ; ----------------------------
- ; SetInt16
- ;
- ; Funktion: Sichert die Adresse der Statustabelle von MDEBUG und der alten
- ; Routine für den Interrupt 16h aus der Statustabelle von MDEBUG.
-
- ; Schreibt die Adresse der neuen Routine für den Interrupt 16h
- ; in die Statustabelle von MDEBUG
- ;
- ; Ausgabe: CF = 0 ->> okay
- ; CF = 1 ->> Fehler beim Aufruf von MDEBUG, keine Änderungen
- ; vorgenommen
- ;
- SetInt16 PROC NEAR
- push ds
- push si
- push bx
- lds bx,regs ; DS:BX -> Parameter regs
- mov si,_si
- mov ds,_ds ; DS:SI -> evtl. Passwort
-
- mov ah,StatusAufruf ; Daten von MDEBUG ermitteln
- call CallMDebug
- jc SetInt16Error ; Fehler beim Aufruf von MDEBUG
-
- cli
- mov cs:Int16Sem,0 ; Semaphor löschen
-
- ; DS:SI -> Statustabelle von MDEBUG
- ; Adresse dieser speichern
- mov cs:StatusTable,si
- mov cs:StatusTable+2,ds
-
- ; alte Adresse der Int-16h-Routine speichern
- mov ax,[si+Int16Offset]
- mov cs:OldInt16,ax
- mov ax,[si+Int16Segment]
- mov cs:OldInt16+2,ax
-
- ; Neue Adresse des Interrupt 16h eintragen
- mov WORD PTR [si+Int16Offset],Offset NewInt16
-
- mov WORD PTR [si+Int16Segment],cs
- sti
- clc
-
- SetInt16Error:
- pop bx
- pop si
- pop ds
- ret
-
- ; ----------------------------
- ; ResetInt16
- ;
- ; Funktion: Restauriert die Adresse der alten Routine für den Interrupt 16h
- ; in der Statustabelle von MDEBUG
- ;
- ; Bes.: Verändert keine Register!
- ;
- ResetInt16 PROC NEAR
- push ds
- push si
- push ax
-
- cli
- xor al,al ; Semaphor testen und setzen
- dec al ; AL = -1
- xchg cs:[Int16Sem],al
- or al,al
- jnz ResetInt16End ; Int 16h wurde schon restauriert
-
- lds si,cs:StatusTable
- ; DS:SI -> Statustabelle von MDEBUG
-
- mov ax,cs:Oldint16 ; alte Adresse der Routine restaurieren
- mov ds:[si+Int16Offset],ax
- mov ax,cs:OldInt16+2
- mov ds:[si+Int16Segment],ax
-
- ResetInt16End:
- sti
-
- pop ax
- pop si
- pop ds
- ret
-
- ; ----------------------------
- ; SetInterrupts
- ;
- ; Funktion: Sichern und umsetzen der Interrupts 20h, 21h und 27h
- ;
- ; Eingabe: DS = CS
- ;
- SetInterrupts PROC NEAR
- mov ax,03521h ; Interrupt 21h sichern und umsetzen
- int 021h
- mov OldInt21,bx
- mov OldInt21+2,es
- mov ax,02521h
- mov dx,offset NewInt21
- int 021h
-
- mov ax,03520h ; Interrupt 20h sichern und umsetzen
- int 021h
- mov OldInt20,bx
- mov OldInt20+2,es
- mov ax,02520h
- mov dx,offset NewInt20
- int 021h
-
- mov ax,03527h ; Interrupt 27h sichern und umsetzen
- int 021h
- mov OldInt27,bx
- mov OldInt27+2,es
- mov ax,02527h
- mov dx,offset NewInt27
- int 021h
- ret
-
- ; ----------------------------
- ; NewInt27
- ;
- ; Funktion: Restaurieren der Interrupts falls der Interrupt 27h
- ; aus MDEBUG heraus aufgerufen wird
- ;
- NewInt27:
- cmp cs:CheckInts_,0h ; Interrupt-Aufruf unterdrücken?
- jne IgnoreInts1
- call ResetInterrupts
- int 027h
-
- ; ----------------------------
- ; NewInt20
- ;
- ; Funktion: Restaurieren der Interrupts falls der Interrupt 20h
- ; aus MDEBUG heraus aufgerufen wird
- ;
- NewInt20:
- cmp cs:CheckInts_,0h ; Interrupt-Aufruf unterdrücken?
- jne IgnoreInts1
- call ResetInterrupts
- int 020h
-
- ; ----------------------------
- ; NewInt21
- ;
- ; Funktion: Abfangen der Funktionen 00, 31h und 4Ch des Interrupts 21h
- ; Restaurieren der Interrupts falls diese Funktionen aus
- ; MDEBUG heraus aufgerufen werden
- ;
- NewInt21:
- pushf
- cmp ah,0
- je NewInt21_1
- cmp ah,031h
- je NewInt21_1
- cmp ah,04Ch
- jne NewInt21_0
-
- push bx
- push ax
- mov ah,InAktivAufruf
- mov bl,0 ; BL = Neuer Wert für das Aktiv-Flag
- call CallMDEBUG ; Aktiv-Flag von MDEBUG zurücksetzen
- pop ax
- pop bx
- jmp SHORT NewInt21_2
-
- NewInt21_0:
- popf ; weiter zum alten Interrupt
- jmp dword ptr cs:OldInt21
-
- NewInt21_1:
- cmp cs:CheckInts_,0h ; Interrupt-Aufruf unterdrücken?
- jne IgnoreInts
-
- NewInt21_2:
- popf
- call ResetInterrupts ; Interrupt-Adressen korrigieren
- int 021h ; und eigentliche Funktion ausführen
-
- pushf ; zur Vorsicht, falls der Interrupt zurückkehrt
- IgnoreInts:
- popf
- IgnoreInts1:
- iret
-
- ; ----------------------------
- ; ResetInterrupts
- ;
- ; Funktion: Zurücksetzen der Interrupts 20h, 21h, 27h und 16h.
- ;
- ResetInterrupts PROC NEAR
- push ax
- push ds
- push dx
- push bx
-
- mov bx,0FFFFh
-
- mov ax,02521h
- lds dx,cs:OLdint21
-
- cmp dx,bx ; Interrupt schon restauriert?
- if nz int 021h ;
- mov cs:OldInt21,bx ; Semaphor setzen
-
- mov ax,02520h
- lds dx,cs:OldInt20
- cmp dx,0FFFFh ; Interrupt schon restauriert?
- if nz int 021h ;
- mov cs:OldInt20,bx ; Semaphor setzen
-
- mov ax,02527h
- lds dx,cs:OldInt27
- cmp dx,0FFFFh ; Interrupt schon restauriert?
- if nz int 021h ;
- mov cs:OldInt27,bx ; Semaphor setzen
-
- pop bx
- pop dx
- pop ds
- pop ax
-
- call ResetInt16 ; Interrupt 16h zurücksetzen
- ret
-
- ; ----------------------------
- ; CallMDebug
- ;
- ; Funktion: Aufruf von MDEBUG
- ;
- ; Eingabe: Alle Register
- ;
- ; Ausgabe: CF = 0 ->> Aufruf okay
- ; CF = 1 ->> Aufruf gescheitert
- ;
- CallMDebug PROC NEAR
- clc ; Carryflag löschen
- db 0CDh ; Maschinencode für INT-Befehl
- IntNumber db 060h ; Nummer des User-Ints von MDEBUG (wird gepatcht)
- jc ret
- cmp ah,0FFh
- je CallMDebugError
- clc
- ret
-
- CallMDebugError:
- stc
- ret
-
- ; ----------------------------
- CODE ENDS
- ; ----------------------------
-
-