comment ~ ==================================================================
A 32bit protected mode debugger V1.11
Copyright (c) Adam Seychell,1995. All rights reserved
Last Modified on 1st Oct 1995
You may use this source code in any way you wish provided that the
following conditions are met;
1) Any software what uses any part of this program must be for
for non-profitable use.
2) Send me a copy of improvments you have made to the debugger.
I have released the source in the hope it will be useful. The debugger
source code may be used or improved by others who are interested in
debeloping thier own. This source code is written in MASM 6.1 and by
no means is it written neatly. If someone wants to write thier
own debugger then best thing would be to use the instruction decode
routine ( DEBUG.INC ) since this is a general routine for displaying
486 instructions as a string. The rest of the debugger could be written
in 32bit C/C++ and while still using ASM for the exception handlers.
~
OPTION OLDSTRUCTS
.386
.MODEL FLAT
.CODE
EXTERNDEF Debug :Near
EXTERNDEF _Debug :Near
EXTERNDEF debug :Near
EXTERNDEF _debug :Near
EXTERNDEF _Debug_Run :Near
EXTERNDEF _debug_run :Near
EXTERNDEF _debugrun :Near
EXTERNDEF _DebugRun :Near
EXTERNDEF Debug_Run :Near
EXTERNDEF debug_run :Near
EXTERNDEF debugrun :Near
EXTERNDEF DebugRun :Near
include debug.inc ; This is the instruction decoding routine
ScreenHeight EQU 50
ScreenWidth EQU 80
boarder_color EQU 3fh
back_color EQU 3fh
back_color_EA EQU 03fh
selected_color EQU 1fh
selected_brkpt_color EQU 0dfh
brkpt_color EQU 4fh
registers_color EQU 30h
RegistersHiLight_color EQU 34h
menu_color EQU 70h
menu_color1 EQU 78h
heading_color EQU 3bh
hilight_color EQU 75h
mesg_box_text_color EQU 071h
mesg_box_color EQU 07eh
Number_brkpts EQU 50
TRUE EQU 1
FALSE EQU 0
man_font LABEL byte
Include man_font.inc
VIDEO_BUFFERS STRUC
BitPlane1 DB 8192 dup (?) ; The 8KB of screen memory
BitPlane2 DB 8192 dup (?) ; The 8KB of video font memory
VIDEO_BUFFERS ENDS
program_reg STRUC
prg_eax dd ?
prg_ecx dd ?
prg_edx dd ?
prg_ebx dd ?
prg_esp dd ?
prg_ebp dd ?
prg_esi dd ?
prg_edi dd ?
prg_EIP dd ?
prg_es dd ?
prg_cs dd ?
prg_ss dd ?
prg_ds dd ?
prg_fs dd ?
prg_gs dd ?
prg_eflags dd ?
program_reg ENDS
_BSS SEGMENT
VideoBuffers VIDEO_BUFFERS <>
registers_save program_reg <>
origonal_registers program_reg <>
Registers_saved_backlog program_reg 48 DUP ({})
_BSS ENDS
.CODE
align 4
;=---------=====------======-----
BreakPoint_EIP dd Number_brkpts dup (0)
BreakPoint_saved db Number_brkpts dup (0)
MOD_RM_EffectiveAddress dd 0
MOD_RM_DefaultSegmentReg dd 0
MOD_RM_size db 0
MOD_RM_SegmentReg db 0
align 4
Segment_Base DD 0
_0b8000h dd 0B8000h ; 32bit offset
Program_Addr dd 0 ; 32bit offset
Zero_Addr dd 0 ; 32bit offset
screen_EIP_value dd 0
selected_EIP dd 0
BacklogRegPTR_tail dd 0
BacklogRegPTR_head dd 0
screen_ending_EIP dd 0
CODE32_sel dw 0 ; Selector
Zero_sel dw 0 ; Selector
saved_IRQ1 df 0
saved_int21 df 0
saved_INT32 df 0
prg_videomode db 0
special_brkpt_EIP dd 0
special_brkpt_save db 0
special_brkpt db False
haveOrigonalRegisters db False
step_flag db False
users_screen db True
program_is_running db False
InitDebugOnly db False
Debug_operating db False
Testing_EA_TEXT db False
conditional_jump db False
DebuggerTerminated db False
Key_flags db 0
selected_line sbyte 0
MOD_RM_flag db 0
Kbd_Rate db -1
Kbd_Delay db -1
;---------- VGA register saved --------------------------
VideoReg_CRTC_index db 0
VideoReg_SQ_index db 0
VideoReg_GC_index db 0
VideoReg_MiscOutp db 0
VideoReg_CRTC db 19h dup (0)
VideoReg_SQ db 5h dup (0)
VideoReg_GC db 9h dup (0)
VideoReg_Attr db 15h dup (0)
VideoReg_Palette db 768 dup (0)
VideoReg_PELaddrWrite db 0
BIOS_cursor dw 0
string_buffer db 50 dup (0)
menu_alt_bar_text Label byte
db 0,hilight_color,' Alt: ',0,menu_color,' '
db 0,hilight_color,'X-',0,menu_color,'Exit '
db 0,hilight_color,'F4-',0,menu_color,'Back '
db 0,hilight_color,'F5-',0,menu_color,'User screen '
db 0,hilight_color,'F9-',0,menu_color,'Goto beginning '
db ' $'
menu_bar_text Label byte
db 0,menu_color,' '
db 0,hilight_color,'F2-',0,menu_color,'Brkpt '
db 0,hilight_color,'F4-',0,menu_color,'Here '
db 0,hilight_color,'F7-',0,menu_color,'Next '
db 0,hilight_color,'F8-',0,menu_color,'Step '
db 0,hilight_color,'F9-',0,menu_color,'Run '
db ' $'
stk_mesg db 0,heading_color,'Stack frame$'
stk_ptrmesg db 0,heading_color,'ss:esp$'
seg_mesg db' selector base limit selector base limit $'
;===========================================================================
;
; The routine wich starts the dubugger
;
; This roitine will just init the debugger and set the Trap flag
;
;
;===========================================================================
align 4
_Debug:
;_debug:
;debug:
Debug PROC
push ds ; save DS
mov ax,_TEXT
mov ds,ax
pop registers_save.prg_ds
pushfd ; Save eflags
pop registers_save.prg_eflags
mov registers_save.prg_es,es ; Save ES
pop registers_save.prg_EIP ; Save EIP
mov registers_save.prg_esp,esp ; Save SS:ESP
sub registers_save.prg_esp,4
mov registers_save.prg_SS,ss
pushad
push ds
pop es
mov Debug_operating,True
call Debugger_init
;* start the debugging *
mov byte ptr [debug],11001100b ; put a INT 3
mov byte ptr [debug+1],11000011b ; put a ret
mov byte ptr [debug_Run+1],11000011b ; put a ret
push registers_save.prg_es
push registers_save.prg_ds
.if Debug_operating == False
pop ds
pop es
popad
push word ptr cs:registers_save.prg_eflags
popf
sti
jmp cs:registers_save.prg_Eip ; goto program without debug
.endif
.if InitDebugOnly == False
or registers_save.prg_eflags,00100000000b
.endif
pop ds
pop es
popad
push cs:registers_save.prg_eflags ; set eflags with TF set
popfd
jmp cs:registers_save.prg_Eip ; goto program
Debug ENDP
;===========================================================================
;
; The routine initalizes the dubugger but does not set the Trap flag
; thus continuing normal program execution.
;
;
;===========================================================================
align 4
_Debug_Run:
;_debug_run:
;_debugrun:
;_DebugRun:
;Debug_Run:
;debug_run:
;debugrun:
;DebugRun:
Debug_Run PROC
push ds
mov ax,_TEXT
mov ds,ax
mov InitDebugOnly, True
call Debug
pop ds
ret
Debug_Run ENDP
;==========================================================================
;
; initalize the debugger !!!!!!!!!!!!!!!!
;
; This gets run only once when the debugger is started
;
;
;==========================================================================
debugger_init PROC PRIVATE
mov ax,0EE00h ; Get selecor values
int 31h
mov Zero_SEL,Bx
mov ax,0EE02h ; Fixup address information
int 31h
mov Program_Addr,Ebx
neg Ebx
mov Zero_Addr,Ebx
add Ebx,0b8000h
mov _0B8000h,Ebx
; If the Current Privilege Level (CPL) is above 0 then
; we can't run the debugger
;
mov ax,cs
lar eax,eax
test ah,01100000b
jz CPL_0 ; brach if the CPL = 0
;
; display the error message
;
.if InitDebugOnly != True
call Debuggers_Video
mov edx,offset Mesg_dpmi_is_bad
call print_message_box
mov edx,offset Mesg_dpmi_is_bad1
call print_message_box
call restore_video
.endif
mov Debug_Operating ,False
ret ; Return to main program with no debugger
CPL_0:
mov ax,cs ; Set RPL field to zero
and al,11111100b
push eax
push offset Load_cs
retf
Load_cs:
cli
.IF InitDebugOnly == True
mov Program_is_running, True
.ELSE
call Debuggers_Video
;------------ set starting instuction -------------
mov eax,registers_save.prg_Eip
mov screen_EIP_value,eax
cld
mov edx,offset intro_mesg
call print_message_box
.ENDIF
;--------- See if can set/get keyboard typmatic rate -----
mov ah,9
int 16h
jc LeaveKbd
and al,00001100b
cmp al,00001100b
jne LeaveKbd
;---------------- Save keyboard typmatic rate ----------
mov ah,03
mov al,06h
int 16h
mov Kbd_Rate,bl ; Rate (0..1fh)
mov Kbd_Delay,bh ; Delay (0..3)
;---------------- set fast keyboard typmatic rate ----------
mov ah,03
mov al,05h
mov bl,0 ; Rate (0..1fh)
mov bh,0 ; Delay (0..3)
int 16h
LeaveKbd:
;---------------- hook INT21 AH=4Ch ----------------
mov bl,21h
call GetIntVector
mov dword ptr saved_int21,edx
mov word ptr saved_int21+4,cx
mov edx,offset terminate_Hooker
mov cx,cs
call SetIntVector
;---------------- hook IRQ 1 the keyboard interrupt ----------------
mov bl,1
call GetIRQvector
mov dword ptr saved_IRQ1,edx
mov word ptr saved_IRQ1+4,cx
mov edx,offset keyboard_ISR
mov cx,cs
call SetIRQvector
;---------------- set debug interrupt hanlder ( INT 1 ) -------------
mov bl,1
mov edx,offset Debug_Exception
mov cx,cs
call SetIntVector
;-------------- set the page faults handler -----------------
mov bl,14
call GetIntVector
mov dword ptr Old_IntVect14,edx
mov word ptr Old_IntVect14+4,cx
mov bl,14
mov edx,offset PageFalts_Exception
mov cx,cs
call SetIntVector
;-------------- set the break point handler (opcode 0CCh) -----------------
mov bl,3
mov edx,offset BreakPoint_Exception
mov cx,cs
call SetIntVector
;-------------- the General protection exception vector --------
mov bl,13
call GetIntVector
mov dword ptr Old_IntVect13,edx
mov word ptr Old_IntVect13+4,cx
mov bl,13
mov edx,offset GeneralProtection_Exception
mov cx,cs
call SetIntVector
;-------------- set the Invalid Opcode handler --------
mov bl,6
mov edx,offset InvalidOpcode_Exception
mov cx,cs
call SetIntVector
;-------------- set the Divide Error handler --------
mov bl,0
mov edx,offset DivideError_Exception
mov cx,cs
call SetIntVector
ret
debugger_init ENDP ;=========== end of debugger inialization =
intro_mesg db '32bit protected mode debugger V1.11 By Adam Seychell$'
mem_mesg db 'Warning: Insufficient memory. Video buffering will be disabled $'
Mesg_dpmi_is_bad db 'Debugger cannot be run above Privlidge Level 0$'
Mesg_dpmi_is_bad1 db 'Press a key to begin normal progam execution$'
;=========================================================================
;
; Save the *complete* VGA video card state
;
;
;=========================================================================
save_CompleteVideoState PROC PRIVATE
cld
cli
;
; Save some VGA registers
;
;--- get and save programs video mode ------------
mov ah,0fh
Int 10h
mov prg_videomode,al
;------- save the CRT controller registers ------------
mov dx,3D4h
in al,dx
mov VideoReg_CRTC_index,al
xor ecx,ecx
@@: mov dx,3D4h
mov al,cl
out dx,al
mov dx,3D5h
in al,dx
mov VideoReg_CRTC[ecx],al
inc cl
cmp cl,SIZEOF VideoReg_CRTC
jb @b
;------- save the Sequencure controller registers ------------
mov dx,3C4h
in al,dx
mov VideoReg_SQ_index,al
xor ecx,ecx
@@: mov dx,3C4h
mov al,cl
out dx,al
mov dx,3C5h
in al,dx
mov VideoReg_SQ[ecx],al
inc cl
cmp cl,SIZEOF VideoReg_SQ
jb @b
;------- save the Graphic Controller Registers ------------
mov dx,3CEh
in al,dx
mov VideoReg_GC_index,al
xor ecx,ecx
@@: mov dx,3CEh
mov al,cl
out dx,al
mov dx,3CFh
in al,dx
mov VideoReg_GC[ecx],al
inc cl
cmp cl,SIZEOF VideoReg_GC
jb @b
;------- save the Attribute Controller Registers ------------
mov dx,3DAh ; reset flip flop
in al,dx
xor ecx,ecx
@@:
mov dx,3C0h
mov al,cl
out dx,al
inc dl
in al,dx
dec dl
out dx,al
mov VideoReg_ATTr[ecx],al
inc cl
cmp cl,SIZEOF VideoReg_ATTr
jb @b
mov dx,3C0h
mov al,20h ; Enaple palette
out dx,al
mov dx,3DAh ; reset flip flop
in al,dx
;----- save the video memory that gets wiped on mode switching ------
; set up registers to accsess one Bit plane only
mov dx,3C4h ; sequencer reg group
mov al,4
mov ah,0111b
out dx,ax
mov dx,3CEh ; The Graphics Controller reg group
mov al,5 ; Mode Register
mov ah,00000000b
out dx,ax
mov al,6 ; Miscellaneous Register
mov ah,1100b
out dx,ax
mov al,4 ; set Read Map Mask Register
mov ah,2 ; to read to bit plane 2
out dx,ax
;--------- save a bit of Bit Plane 2 ( the 8KB of video font memory ) -
mov esi,_0b8000h
mov edi,Offset VideoBuffers.BitPlane2
mov ecx,(sizeof BitPlane2 )/4
rep movsd
; set up registers to accsess one Bit plane 0 and 1 chained together
mov dx,3C4h ; sequencer reg group
mov al,4
mov ah,0011b ; Chain four enabled
out dx,ax
mov dx,3CEh ; The Graphics Controller reg group
mov al,5 ; Mode Register
mov ah,00010000b
out dx,ax
mov al,6 ; Miscellaneous Register
mov ah,1110b
out dx,ax
mov al,4 ; set Read Map Mask Register
mov ah,0 ; to read to bit plane 0
out dx,ax
;--------- save a bit of Bit Plane 0 and 1 together ---------
mov edi,Offset VideoBuffers.BitPlane1
mov ecx,(sizeof BitPlane1 )/4
mov esi,_0B8000h
rep movsd
mov dx,3C4h ; sequencer reg group
mov al,4
mov ah,VideoReg_SQ[4]
out dx,ax
mov dx,3CEh ; The Graphics Controller reg group
mov al,4 ; set Read Map Mask Register
mov ah,VideoReg_GC[4]
out dx,ax
mov al,5 ; Mode Register
mov ah,VideoReg_GC[5]
out dx,ax
mov al,6 ; Misellaneous Register
mov ah,VideoReg_GC[6]
out dx,ax
;--------- save the general or external VGA registers ----------
mov dx,3CCh
in al,dx
mov VideoReg_MiscOutp,al
;--------- save the palette----------------------------
mov dx,3C8h
in al,dx
mov VideoReg_PELaddrWrite,al
mov dx,3C7h
mov al,0
out dx,al
mov dx,3C9h
xor ecx,ecx
@@: in al,dx
mov VideoReg_Palette[ecx],al
in al,dx
mov VideoReg_Palette[ecx+1],al
in al,dx
mov VideoReg_Palette[ecx+2],al
add ecx,3
cmp ecx,SIZEOF VideoReg_Palette
jb @b
;------ save cursor position ------------------
mov ah,3
mov bh,0
int 10h
mov BIOS_cursor,dx
ret
;========== finished saveing the video state =====================
save_CompleteVideoState ENDP
;===================================================================
;
;
; load the VGA video state from what was saved in the
; "save_CompleteVideoState" procedure above
;
;
;===================================================================
restore_video PROC PRIVATE
cld
.IF users_screen
ret
.Endif
pushad
;---- first retrun video mode -------------------
xor eax,eax
mov al,prg_videomode
cmp al,3h
; je _Vmode3
cmp al,83h
; je _Vmode3
or al,80h
int 10h
_Vmode3:
;------ restore cursor position ------------------
mov ah,2
mov bh,0
mov dx,BIOS_cursor
int 10h
;----- restore the video memory that gets wiped on mode switching ------
; set up registers to accsess one Bit plane only
; set for sequentual memory addressing
mov dx,3C4h ; sequencer reg group
mov al,4
mov ah,0111b
out dx,ax
mov dx,3CEh ; The Graphics Controller reg group
mov al,5 ; Mode Register
mov ah,00000000b
out dx,ax
mov dx,3ceh ; The Graphics Controller reg group
mov al,6 ; Misellaneous Register
mov ah,1100b
out dx,ax
; set Map Mask Register
mov dx,3c4h ; sequencer reg group
mov al,2
mov ah,0100b ;to write to bit plane 2
out dx,ax
; can now fill up the video font memory
mov edi,_0b8000h
mov esi,Offset VideoBuffers.BitPlane2
mov ecx,(sizeof BitPlane2 )/4
rep movsd
; set up registers to accsess one Bit plane 0 and 1 chained together
mov dx,3C4h ; sequencer reg group
mov al,4
mov ah,00011b ; Chain four enabled
out dx,ax
mov dx,3CEh ; The Graphics Controller reg group
mov al,5 ; Mode Register
mov ah,00010000b
out dx,ax
mov al,6 ; Miscellaneous Register
mov ah,1110b
out dx,ax
; set Map Mask Register
mov dx,3c4h ; sequencer reg group
mov al,2
mov ah,0011b ;to write to bit plane 0 and 1
out dx,ax
;--------- restore the first 4KB of bit plane 0 and 1 ---------
mov esi,Offset VideoBuffers.BitPlane1
mov ecx,(sizeof BitPlane1 )/4
mov edi,_0B8000h
rep movsd
;--------- Resotre the general or external VGA registers ----------
mov dx,3C2h
mov al,VideoReg_MiscOutp
out dx,al
;------- restore the CRT controller registers ------------
mov al,VideoReg_CRTC[ecx] ; Turn off protection
mov dx,3D4h
mov ah,VideoReg_CRTC[11h]
and ah,01111111b
mov al,11h
out dx,ax
xor ecx,ecx
@@: mov dx,3D4h
mov al,cl
out dx,al
mov dx,3D5h
mov al,VideoReg_CRTC[ecx]
out dx,al
inc cl
cmp cl,SIZEOF VideoReg_CRTC
jb @b
mov dx,3D4h
mov al,VideoReg_CRTC_index
out dx,al
;------- restore the Graphic Controller Registers ------------
xor ecx,ecx
@@: mov dx,3CEh
mov al,cl
out dx,al
mov dx,3CFh
mov al,VideoReg_GC[ecx]
out dx,al
inc cl
cmp cl,SIZEOF VideoReg_GC
jb @b
mov dx,3CEh
mov al,VideoReg_GC_index
out dx,al
;------- Restore the Sequencure controller registers ------------
xor ecx,ecx
@@: mov dx,3C4h
mov al,cl
out dx,al
mov dx,3C5h
mov al,VideoReg_SQ[ecx]
out dx,al
inc cl
cmp cl,SIZEOF VideoReg_SQ
jb @b
mov dx,3C4h
out dx,al
mov al,VideoReg_SQ_index
;------- Restore the Attribute Controller Registers ------------
mov dx,3DAh ; reset flip flop
in al,dx
xor ecx,ecx
@@:
mov dx,3C0h
mov al,cl
out dx,al
mov al,VideoReg_ATTr[ecx]
out dx,al
inc cl
cmp cl,SIZEOF VideoReg_ATTr
jb @b
mov dx,3C0h
mov al,20h ; Enaple palette
out dx,al
mov dx,3DAh ; reset flip flop
in al,dx
;--------- Retore the palette----------------------------
mov dx,3C8h
mov al,0
out dx,al
mov dx,3C9h
xor ecx,ecx
@@: mov al,VideoReg_Palette[ecx]
out dx,al
mov al,VideoReg_Palette[ecx+1]
out dx,al
mov al,VideoReg_Palette[ecx+2]
out dx,al
add ecx,3
cmp ecx,SIZEOF VideoReg_Palette
jb @b
mov dx,3C8h
mov al,VideoReg_PELaddrWrite
out dx,al
mov users_screen,True
popad
ret
restore_video ENDP
;========================================================================
; This procedure will test the address in ECX to see if it's a valid
; location, i.e will not cause a page fault.
;
;
; Return If location is Ok then
; testing_EA_TEXT = True
; else
; testing_EA_TEXT = False
;
;========================================================================
Test_location PROC PRIVATE USES ES
mov es,Zero_SEL
jmp $+2
mov testing_EA_TEXT,True
tea_ins:
mov ebx,es:[ecx]
mov ecx,es:[ecx+4]
tea_ins_size EQU $ - tea_ins
nop
nop
nop
nop
nop
nop
ret
Test_location ENDP
;===========================================================================
;
; Look at current instrucion and see if a VGA register was modified
;
;
; Expects "registers_save.prg_EIP" pointing to instruction
;
; Returns: restores video state if instruction was using a VGA port
;
;===========================================================================
CheckVGAport PROC PRIVATE
pushad
mov eax,registers_save.prg_EIP
mov eax,[eax]
mov cl,2
Loopeer:
.IF al == 66h ; igonre operand size prefix
shr eax,8
.ELSEIF al == 11110010b ; igonre any stupid REP prefix
shr eax,8
.ENDIF
dec cl
jnz Loopeer
and al,01111100b
cmp AL ,01101100b ;see if IN,OUT, INS or OUTS
je getPortIn
jmp exit
getPortIn:
mov eax,registers_save.prg_edx
mov edi,offset allVGAports
cld
mov ecx,19
repne scasw
jne exit
call Restore_Video
exit: popad
ret
allVGAports dw 3D4h,3D5h,3C4h,3C5h,3CEh,3CFh,3CCh,3CAh,3C2h,3DAh
dw 3c0h,3c8h,3c9h,3c7h,3d6h,3c3h,3cdh,3d4h,3d5h
CheckVGAport ENDP
draw_char MACRO char
mov al,char
call _draw_char
ENDM
draw_2char MACRO char
mov bx,char
call _draw_2char
ENDM
draw_vert MACRO char,count
mov al,char
mov cl, count
call _draw_vert
ENDM
draw_horz MACRO char,count
mov al,char
mov cl, count
call _draw_horz
ENDM
;================================================================
;
;
; Displays a repeated character on the screen Verticaly
;
; Expects edi = character offset in the screen memory.
; al = character
; cl = repeat
; ah = color
;
;================================================================
_draw_vert PROC PRIVATE
mov edx,_0B8000h
@@: mov word ptr [edi*2+edx],ax
add edi,80
dec cl
jnz @b
ret
_draw_vert ENDP
;================================================================
;
;
; Displays a repeated character on the screen horizonataly
;
; Expects edi = character offset in the screen memory.
; al = character
; cl = repeat
; ah = color
;
;================================================================
_draw_horz PROC PRIVATE
mov edx,_0B8000h
@@: mov word ptr [edi*2+edx],ax
inc edi
dec cl
jnz @b
ret
_draw_horz ENDP
;================================================================
;
;
; Displays a single character on the screen
;
; Expects edi = character offset in the screen memory.
; al = character
; ah = color
;
;================================================================
_draw_char PROC PRIVATE
mov edx,_0B8000h
mov word ptr [edi*2+edx],ax
inc edi
ret
_draw_char ENDP
;================================================================
;
;
; Displays two characters on the screen
;
; Expects edi = character offset in the screen memory.
; bh = character 1
; bl = character 2
; ah = color
;
;================================================================
_draw_2char PROC PRIVATE
mov al,bh
mov edx,_0B8000h
mov word ptr [edi*2+edx],ax
inc edi
mov al,bl
mov word ptr [edi*2+edx],ax
inc edi
ret
_draw_2char ENDP
;================================================================
;
;
; Display a string on the screen
;
; Expects edi = character offset in the screen memory.
; edx = points to the string that terminates with a '$'
; ah = color
;
;================================================================
plot_string PROC PRIVATE USES EBX
mov ebx,_0B8000h
leer: mov al,[edx]
cmp al,'$'
je exit
cmp al,0
jne @f
mov ax,[edx+1]
add edx,2
xchg al,ah
@@: mov word ptr [edi*2+ebx],ax
inc edi
inc edx
jmp leer
exit: ret
plot_string ENDP
;================================================================
;
;
; Display a hexidecimal number on the screen
;
; Expects edi = character offset in the screen memory.
; ebx = The number to display
; cl = The number of nibbles to display
;
;================================================================
print_hex PROC PRIVATE USES EBX EBP EDX ECX
mov edx,_0B8000h
he_plotloop:
rol ebx,4
movzx ebp,bl
and ebp,0fh
mov al,ds:hex_chars[ebp]
mov word ptr [edi*2+edx],ax
inc edi
dec cl
jnz he_plotloop
ret
hex_chars db '0123456789abcdef'
print_hex ENDP
;================================================================
;
;
; This will display all the segment register values and
; the base addresses and limit.
;
;
; Expects Nothing
;
;================================================================
Display_SegReg_info PROC PRIVATE
mov edi,(1 + ScreenWidth*(ScreenHeight-5) )
mov ah,heading_color
mov edx,offset seg_mesg
call plot_string
mov edi,(2 + ScreenWidth*(ScreenHeight-4) )
mov ah,registers_color
xor ebp,ebp
plot_segloop:
mov edx,offset ES_symb
add edx,ebp
call plot_string
draw_char '='
mov ebx,ds:registers_save.prg_es[ebp]
mov cl,4
ror ebx,16
call print_hex
movzx ecx,word ptr ds:registers_save.prg_es[ebp]
lsl ebx,ecx
jz @f
mov edx,offset nul_sel_measg
call plot_string
jmp invsel
nul_sel_measg db '··Invalid selector··$'
@@:
draw_2char ' '
mov ebx,Program_Addr
.if cx == Zero_Sel
xor ebx,ebx
.endif
mov cl,8
call print_hex
draw_2char ' '
lsl ebx,ds:registers_save.prg_es[ebp]
mov cl,8
call print_hex
invsel: add edi,ScreenWidth-27
add ebp,4
cmp edi,( ScreenWidth*(ScreenHeight-1) )
jb plot_segloop
cmp edi,(2+ ScreenWidth*(ScreenHeight-1) )
ja exit
mov edi,(33+ ScreenWidth*(ScreenHeight-4) )
jmp plot_segloop
exit: ret
Display_SegReg_info ENDP
;================================================================
;
;
; This will display all the debug register values and
; the the R,W and LEN fields of each
;
; Expects : Nothing
;================================================================
Display_DRx_info PROC PRIVATE
mov edi,(1 + ScreenWidth*(ScreenHeight-5) )
mov ah,heading_color
mov edx,offset HardwareBrkpts_mesg
call plot_string
;---- display the break point regieters -----------
mov edi,(2 + ScreenWidth*(ScreenHeight-4) )
mov ah,registers_color
draw_2char 'DR'
draw_2char '0='
mov ebx,DR0
mov cl,0
call Plot_DR
mov edi,(2 + ScreenWidth*(ScreenHeight-3) )
draw_2char 'DR'
draw_2char '1='
mov ebx,DR1
mov cl,2
call Plot_DR
mov edi,(33 + ScreenWidth*(ScreenHeight-4) )
draw_2char 'DR'
draw_2char '2='
mov ebx,DR2
mov cl,4
call Plot_DR
mov edi,(33 + ScreenWidth*(ScreenHeight-3) )
draw_2char 'DR'
draw_2char '3='
mov ebx,DR3
mov cl,6
call Plot_DR
mov edi,(2 + ScreenWidth*(ScreenHeight-2) )
draw_horz ' ',58
ret
Plot_DR PROC PRIVATE ;------------ sub proc for plotiing one DR reg ---
mov ebp,DR7
shr ebp,cl
push ecx
mov cl,8
call print_hex
pop ecx
test ebp,00000003h ; look at Gi and Li bits
jnz @f
mov edx,offset nul_DRx_measg
call plot_string
ret
@@: shr ebp,cl
draw_char ' '
draw_2char 'W='
mov bx,'0 '
test ebp,00010000h
jz @f
mov bh,'1'
@@: call _draw_2char
draw_2char 'R='
mov bx,'0 '
test ebp,00020000h
jz @f
mov bh,'1'
@@: call _draw_2char
draw_2char 'LE'
draw_2char 'N='
mov ebx,ebp
and ebx,000C0000h
rol ebx,10
mov cl,1
call Print_hex
draw_char ' '
ret
Plot_DR ENDP
nul_DRx_measg db ' ···disabled·· $'
HardwareBrkpts_mesg db ' 80386 Linear Address Breakpoint Registers $'
Display_DRx_info ENDP
;========================================================================
;
; This will update the registers log storage.
;
; Expects : Nothing
;
;========================================================================
Update_register_LOG PROC PRIVATE
;------ copy all regs into back log --------------
mov edi,BacklogRegPTR_head
add edi,offset registers_saved_backlog
mov esi,offset registers_save
mov ecx,(SIZEOF program_reg ) /4
rep movsd
mov eax,BacklogRegPTR_head
add eax, SIZEOF program_reg
.if eax >= SIZEOF registers_saved_backlog
xor eax,eax
.endif
mov BacklogRegPTR_head,eax
.if BacklogRegPTR_tail == EAX
mov eax,BacklogRegPTR_tail
add eax, SIZEOF program_reg
.if eax >= SIZEOF registers_saved_backlog
xor eax,eax
.endif
mov BacklogRegPTR_tail,eax
.endif
ret
Update_register_LOG ENDP
;================================================================
;
;
; This will display all the register values, flags and all the
; intructions on the screen ( except segment and debug registers )
;
;
;================================================================
refresh_screen PROC PRIVATE
local old_esi :dword
local count1 :dword
local line_count :byte
local current_instruc :byte
local brkpt_flag :byte
local InstCursor_flag :byte
;----- print the nine registers on the screen ----------------
mov edi,(ScreenWidth*1+66)
xor esi,esi
RegPrint_LOOP:
mov cl,8
mov ebx,registers_save.prg_eax[esi*4]
mov ah,registers_color
mov edx,BacklogRegPTR_head
.if BacklogRegPTR_tail != EDX
sub edx, SIZEOF program_reg
jge @f
mov edx,SIZEOF registers_saved_backlog - SIZEOF program_reg
@@:
.if ( EBX != Dword PTR registers_saved_backlog[edx+esi*4] ) \
&& ( ESI != 8 )
mov ah,RegistersHiLight_color
.endif
.endif
call print_hex
inc esi
add edi,80-8
cmp esi,9
jb RegPrint_LOOP
;----- print the eight flags ----------------
mov ah,registers_color
mov edi,(ScreenWidth*1+78)
mov al,'0'
test registers_save.prg_eflags,0000000000001b
jz @f
mov al,'1'
@@: call _draw_char
mov edi,(ScreenWidth*2+78)
mov al,'0'
test registers_save.prg_eflags,0000001000000b
jz @f
mov al,'1'
@@: call _draw_char
mov edi,(ScreenWidth*3+78)
mov al,'0'
test registers_save.prg_eflags,0000010000000b
jz @f
mov al,'1'
@@: call _draw_char
mov edi,(ScreenWidth*4+78)
mov al,'0'
test registers_save.prg_eflags,0100000000000b
jz @f
mov al,'1'
@@: call _draw_char
mov edi,(ScreenWidth*5+78)
mov al,'0'
test registers_save.prg_eflags,0000000000100b
jz @f
mov al,'1'
@@: call _draw_char
mov edi,(ScreenWidth*6+78)
mov al,'0'
test registers_save.prg_eflags,0000000010000b
jz @f
mov al,'1'
@@: call _draw_char
mov edi,(ScreenWidth*7+78)
mov al,'0'
test registers_save.prg_eflags,0001000000000b
jz @f
mov al,'1'
@@: call _draw_char
mov edi,(ScreenWidth*8+78)
mov al,'0'
test registers_save.prg_eflags,0010000000000b
jz @f
mov al,'1'
@@: call _draw_char
;========== plot the stack frame =======================
mov edi,(ScreenWidth*(ScreenHeight-2)+67)
mov esi,registers_save.prg_esp
push es
mov bx,word ptr registers_save.prg_ss
mov es,bx
.IF BX == _TEXT
mov ebx,Program_addr
mov Segment_Base,ebx
.ElseIF BX == Zero_SEL
mov Segment_Base,0
.else
mov Segment_Base,0
.endif
stlplol:
mov ecx,esi
add ecx,Segment_Base
Call Test_location ; Test location DS:[ECX]
.If Testing_EA_TEXT == True
mov ebx,es:[esi]
mov cl,8
call print_hex
mov Testing_EA_TEXT,False
.Else
mov edx,Offset Bad_stack_mesg
call Plot_String
.Endif
sub edi,80+8
add esi,4
cmp edi,(ScreenWidth*12+67)
jae stlplol
pop es
;=========== plot the intructions ========================================
;=========== plot the intructions ========================================
;=========== plot the intructions ========================================
;=========== plot the intructions ========================================
;=========== plot the intructions ========================================
Plot_The_Instructions:
mov count1,0
mov esi,screen_EIP_value
mov line_count,0
mov InstCursor_flag,FALSE
mov eax,ESI
mov ecx,Number_brkpts
mov edi,offset BreakPoint_EIP
repne scasd
mov brkpt_flag,False
jne no_brkpt_
sub edi,offset BreakPoint_EIP+4
shr edi,2
mov brkpt_flag,True
mov al,BreakPoint_saved[edi] ; temperarly put
mov [esi],al ; in old intruction
mov old_esi,esi
no_brkpt_:
back_more:
.if selected_line > (ScreenHeight-8)
mov selected_line,(ScreenHeight-8)
mov edi,offset string_buffer
call decode_instruction
mov screen_EIP_value,esi
.elseif selected_line < 0
inc selected_line
mov edi,offset string_buffer
mov old_esi,esi
mov cl,8
tryagn: dec cl
jz stptry
dec screen_EIP_value
mov esi,screen_EIP_value
mov edi,offset string_buffer
call decode_instruction
cmp esi,old_esi
jne tryagn
stptry: mov esi,screen_EIP_value
jmp back_more
.endif
;------- Put back break point if is here-------
.if brkpt_flag == True
mov eax,old_esi
mov byte ptr [eax],0CCh
.endif
.if step_flag == 1
mov eax,registers_save.prg_EIP
.if eax < esi
mov screen_EIP_value,eax
mov esi,eax
.endif
.if eax > screen_ending_EIP
mov screen_EIP_value,eax
mov esi,eax
.endif
mov Selected_EIP,eax
.endif
mainloop: ;============= MAIN LOOP ========================
mov screen_ending_EIP,esi
mov ah,registers_color
.if step_flag == 1
.if registers_save.prg_EIP == esi
mov al,line_count
mov selected_line,al
mov ah,selected_color
mov step_flag,False
.endif
.else
mov al,selected_line
.if line_count == al
mov ah,selected_color
mov selected_EIP,esi
.endif
.endif
push eax
mov eax,ESI
and eax,eax
jz no_brkpt
mov ecx,Number_brkpts
mov edi,offset BreakPoint_EIP
repne scasd
pop eax
mov brkpt_flag,False
jne no_brkpt
sub edi,offset BreakPoint_EIP+4
shr edi,2
mov brkpt_flag,True
mov al,BreakPoint_saved[edi] ; temperarly put
mov [esi],al ; in old intruction
.if ah == selected_color
mov ah,selected_brkpt_color
.else
mov ah,brkpt_color
.endif
no_brkpt:
mov edi,(ScreenWidth*1 +1 )
add edi,count1
add count1,ScreenWidth
draw_2char 'cs'
draw_char ':'
mov ebx,esi
mov cl,8
call print_hex
;-- copy string buffer to screen ----
.if registers_save.prg_EIP == esi
mov bl,4
mov al,213
@@: call _draw_char
inc al
dec bl
jnz @b
.else
draw_horz ' ',4
.endif
;======= plot the instuction ============
push edi
mov edi,offset string_buffer
mov ecx,edi
call decode_instruction
sub ecx,edi
neg ecx
pop edi
xor ebx,ebx
@@: mov al,string_buffer[ebx]
inc ebx
call _draw_char
dec ecx
jnz @b
mov ecx,43
; .if current_instruc > ' '
; .if conditional_jump == True
; draw_char ''
; .endif
; mov ecx,42
; .endif
mov al,' '
@@: cmp ebx,ecx
jae er4
call _draw_char
inc ebx
jmp @b
er4:
;------- plot the effective address of the mod r/m field ----
.IF (AH == selected_brkpt_color) || (AH == selected_color)
or InstCursor_flag,True
pushad
mov edi,27
.if MOD_RM_flag == True
mov ah,back_color
draw_horz '═',33
mov edi,27
mov ah,back_color_EA
draw_char ' '
mov edx,op_seg_overide
.if edx == NULL
mov edx,MOD_RM_DefaultSegmentReg
.endif
sub edx,offset ES_symb
mov ebx,ds:registers_save.prg_es[edx]
mov cx,cs
.if BX == CX
mov ecx,Program_Addr
.elseif BX == _TEXT
mov ecx,Program_Addr
.elseif BX == ZERO_SEL
xor ecx,ecx
.else
add edx,offset ES_symb
call Plot_string
mov edx,offset inv_sel_mesg
jmp inval_addre ; invalid sel if
.endif
mov Segment_Base,ecx
add edx,offset ES_symb
call Plot_string
draw_2char ':['
mov ebx,MOD_RM_EffectiveAddress
mov cl,8
call print_hex
push ebx
draw_2char '] '
draw_2char '= '
pop ecx
add ecx,Segment_Base
Call Test_location ; Test linear addr ECX
.if testing_EA_TEXT == True
push ebx
draw_char '0'
.if MOD_RM_size == 3
mov ebx,ecx
mov cl,4
rol ebx,16
call print_hex
draw_char ':'
.endif
pop ebx
.if MOD_RM_size >= 2
mov cl,8
.elseif MOD_RM_size == 1
mov cl,4
rol ebx,16
.else
mov cl,2
rol ebx,24
.endif
mov testing_EA_TEXT,False
call print_hex
.else
mov edx,offset inv_adr_mesg
inval_addre: call Plot_String
.endif
draw_char ' '
.else
mov ah,back_color
draw_horz '═',33
.endif
popad
.ENDIF
;------- Put back break point if is here-------
.if brkpt_flag == True
mov eax,screen_ending_EIP
mov byte ptr [eax],0CCh
.endif
inc line_count
cmp line_count,(ScreenHeight-7)
jb mainloop
; If the selected instruction was not displayed then
; replaot the screen with the selected instruction at the top.
;
.If InstCursor_flag == FALSE
mov selected_line,0
mov eax,registers_save.prg_EIP
mov Selected_EIP,eax
mov Screen_EIP_value,eax
jmp Plot_The_Instructions
.Endif
ret
inv_adr_mesg db 'illegal address$'
inv_sel_mesg db ': illegal selector$'
Bad_stack_mesg db '≡≡≡≡≡≡≡≡$'
refresh_screen ENDP
;========================================================================
; ISR for terminate hooking INT21h AH=4Ch
;
; Used to trap any INT21h AH=4Ch. so can notify the user that the program
; has terminated
;
;=========================================================================
terminate_Hooker PROC PRIVATE
cli
.IF ( ah == 4Ch ) && ( cs:InitDebugOnly == False ) && (cs:DebuggerTerminated == False)
pushad
push es
push ds
xor eax,eax ;disable debug registers
mov DR7,eax
mov ax,_TEXT
mov ds,ax
mov es,ax
mov users_screen,False
.If Program_is_running
mov users_screen,True
.Endif
call debuggers_video
mov edx,offset exit_code
call print_message_box
pop ds
pop es
popad
sub dword ptr [esp],2
jmp Handle_Debug_Exception
.ENDIF
jmp cs:saved_int21
exit_code db ' Program terminated with exit code INT 21h AH=4Ch $'
terminate_Hooker ENDP
;===================================================================
;
;
; PRINTS A MESSAGE IN THE SCREEN IN A BOX and waits for a key.
;Expects:
; EDX = points to a string that ends with a '$'
;
;===================================================================
print_message_box PROC PRIVATE
local height :byte
local lenth :byte
mov height,6
mov al,'$'
mov edi,edx
push edx
cld
@@: scasb
jne @b
sub edi,edx
add edi,4
mov eax,edi
mov lenth,al
shr edi,1
neg edi
add edi,39+ScreenWidth* (ScreenHeight/2 - 3)
push edi
mov ah,mesg_box_color
push edi
add edi,ScreenWidth
draw_vert '║',height
pop edi
push edi
draw_char '╔'
draw_horz '═',lenth
draw_char '╗'
add edi,ScreenWidth-1
draw_vert '║',height
pop edi
add edi,ScreenWidth+1
mov ch,height
@@: push edi
draw_horz ' ',lenth
pop edi
add edi,ScreenWidth
dec ch
jnz @b
dec edi
draw_char '╚'
draw_horz '═',lenth
draw_char '╝'
pop edi
mov eax,ScreenWidth
mul height
shr eax,1
add edi,eax
add edi,3
pop edx
mov ah,mesg_box_text_color
call plot_string
add edi,ScreenWidth*3
movzx eax,lenth
shr eax,1
sub edi,eax
mov ah,(mesg_box_color and 0f0h) or 8
mov edx,offset mesg_OK_
call plot_string
sub edi,ScreenWidth+5
mov ah,0A1h
mov edx,offset mesg_OK
call plot_string
mov ah,(mesg_box_color and 0f0h) or 8
draw_char '▄'
mov eax,Zero_addr ; clear the keyboard buffer
mov dx,[eax+41ch]
mov [eax+41ah],dx
@@:
in al,64h ; Read key only when 8242 is ready
test al,1
jz @b
in al,60h ; wait for enter key
test al,80h ; see if was a release code
jz go_make
INT 9 ; Must send code to BIOS
jmp @b
go_make: sub al,3Bh ; loop if key was an Function key
cmp al,10
jbe @b
call debuggers_video
ret
mesg_OK db ' OK $'
mesg_OK_ db '▀▀▀▀$'
print_message_box ENDP
;===================================================================
;
;
; SETS UP THE VIDEO SCREEN FOR THE DEBUGGER
;
;
;===================================================================
debuggers_video PROC PRIVATE
pushad
.IF Users_Screen
call save_CompleteVideoState
mov ax,83h ; Goto VGA Text Mode 80x25
int 10h
mov bl,00h ; Text Mode 80x50
mov ah,11h
mov al,12h
int 10h
.ENDIF
;------------------ put in my man -----------------------
; set up registers to accsess Bit plane 2 only
; set for sequentual memory addressing
mov dx,3C4h ; sequencer reg group
mov al,4
mov ah,0111b
out dx,ax
mov dx,3ceh ; The Graphics Controller reg group
mov al,6 ; Misellaneous Register
mov ah,1100b
out dx,ax
; set Map Mask Register
mov dx,3c4h ; sequencer reg group
mov al,2
mov ah,0100b ;to write to bit plane 2
out dx,ax
; can now fill up the video font memory
cld
mov esi,offset man_font
mov edi,_0b8000h
add edi,20h*213 ; put man at chars 213..216
mov ecx,20h*4
rep movsb
; set for sequentual memory addressing
mov dx,3C4h ; sequencer reg group
mov al,4
mov ah,0011b
out dx,ax
mov dx,3ceh ; The Graphics Controller reg group
mov al,6 ; Misellaneous Register
mov ah,1110b
out dx,ax
; set Map Mask Register
mov dx,3c4h ; sequencer reg group
mov al,2
mov ah,0011b ;to write to bit plane 1+0
out dx,ax
;----- disable character blinking-------------------------
mov dx,3DAh
in al,dx
mov dl,0C0h
mov al,10h or 20h
out dx,al
inc dl
in al,dx
and al,NOT 8
dec dl
out dx,al
;----- turn off cursor -------------------------
mov dx,3D4h
mov ax,200Ah
out dx,ax
;---------------- draw the screen -----------------------
mov edi,_0B8000h
mov ax,back_color*256
mov ecx, ScreenWidth * ScreenHeight
cld
rep stosw
mov ah,boarder_color
mov edi,(0+ 80*1 )
draw_vert '║',18+25
draw_char '╟'
draw_horz '─',59
draw_char '┤'
mov edi,(0+ 80*0 )
draw_char '╔'
draw_horz '═',59
draw_char '╤'
draw_horz '═',13
draw_char '╤'
draw_horz '═',4
draw_char '╗'
mov edi,(0+ 80*45 )
draw_vert '║',4
mov edi,(60+ 80*45 )
draw_vert '│',4
mov edi,(60+ 80*11 )
draw_vert '│',33
mov edi,(60+ 80* 1 )
draw_vert '│',9
draw_char '├'
draw_horz '─',13
draw_char '┴'
draw_horz '─',4
draw_char '╢'
mov edi,(79+ 80*1 )
draw_vert '║',9
mov edi,(79+ 80*11 )
draw_vert '║',38
mov edi,(74+ 80*1 )
draw_vert '│',9
mov edi,(64+ 80*11 )
mov edx,offset stk_mesg
call plot_string
mov edi,(61+ 80*(ScreenHeight-2) )
mov edx,offset stk_ptrmesg
call plot_string
mov edi,(80*1+62)
mov edx,offset EAX_symb
mov ah,registers_color
@@: call plot_string
add edi,80-3
add edx,1
cmp edx,offset EAX_symb+9*4
jb @b
mov edi,(80*1+76)
draw_2char 'c=' ;-------- DRAW CARRY FLAG STATE ----------
mov edi,(80*2+76)
draw_2char 'z=' ;-------- DRAW ZERO FLAG STATE ----------
mov edi,(80*3+76)
draw_2char 's=' ;-------- DRAW SIGN FLAG STATE ----------
mov edi,(80*3+76)
draw_2char 's=' ;-------- DRAW SIGN FLAG STATE ----------
mov edi,(80*4+76)
draw_2char 'o=' ;-------- DRAW OVERFLAW FLAG STATE ----------
mov edi,(80*5+76)
draw_2char 'p=' ;-------- DRAW PARITY FLAG STATE ----------
mov edi,(80*6+76)
draw_2char 'a=' ;-------- DRAW AUX FLAG STATE ----------
mov edi,(80*7+76)
draw_2char 'i=' ;-------- DRAW INTERRUPT FLAG STATE ----------
mov edi,(80*8+76)
draw_2char 'd=' ;-------- DRAW DIRECTION FLAG STATE ----------
mov Users_Screen , False
popad
ret
debuggers_video ENDP
;===================================================================
;
;
; THIS PROC TRAPS ANY VIDEO MODE CHANGING BY THE PROGRAM
; So we can keep track of the video state at all times
;
;===================================================================
Video_mode_trap PROC PRIVATE
pushfd
push ds
push es
push eax
mov ax,_TEXT
mov ds,ax
mov es,ax
pop eax
cmp byte ptr [esp+4*5],10h
jne no_video_change
cmp ah,0
jne no_video_change
cmp program_is_running, True
jne no_video_change
push 10h
pushfd
push cs
push offset JO99
jmp saved_INT32
JO99:
call save_CompleteVideoState
no_video_change:
pop es
pop ds
popfd
jmp cs:saved_INT32
Video_mode_trap ENDP
;=========================================================================
;
; The debugger's low level keyboard handler ( for traping CTRL-BREAK )
;
;=========================================================================
keyboard_ISR PROC PRIVATE
test byte ptr [esp+4*2+2],10b ; don't trap if was in V86 mode
jnz noPM
push ds
push es
pushad
mov ax,_TEXT
mov ds,ax
mov es,ax
in al,60h ;get scan code from perifial port A
.if program_is_running == True
.if scan_coden == 0
cmp al,0e0h
jne no_break
.elseif scan_coden == 1
cmp al,046h
jne no_break
.elseif scan_coden == 2
cmp al,0e0h
jne no_break
.elseif scan_coden == 3
cmp al,0c6h
jne no_break
;-------- set the ctrl-breaker -----------
mov al,20h ; Send EOI cmd to 8259
out 20h,al
mov program_is_running , False
call debuggers_video
mov edx,offset user_ctrl_breaked
call print_message_box
popad
pop es
pop ds
or byte ptr [esp+4*2+1],1 ; set TF
jmp Handle_Debug_Exception
.ENDIF
inc scan_coden
.ENDIF
noTrap:
popad
pop es
pop ds
noPM: jmp cs:saved_IRQ1
no_break:
mov scan_coden,0
jmp noTrap
scan_coden db 0
user_ctrl_breaked db ' Program Stoped with CTRL-BREAK $'
keyboard_ISR ENDP
;===========================================================================
;
; This is the INT 3 breakpoint exception handler.
;
;
;
;===========================================================================
BreakPoint_Exception PROC PRIVATE
push ds
pushad
mov ax,_TEXT
mov ds,ax
mov eax,Zero_addr ; clear the keyboard buffer
mov dx,[eax+41ch]
mov [eax+41ah],dx
cmp special_brkpt,True
je special_CCh
nospecial_CCh:
mov eax,[esp+4*9] ; get EIP from stack
push es
push ds
pop es
dec eax
mov ecx,Number_brkpts
mov edi,offset BreakPoint_EIP
cld
repne scasd
pop es
jne not_a_brkpt
;---------- put back origonal intruction --------------
dec dword ptr [esp+4*9] ; decreament EIP on stack
sub edi,offset BreakPoint_EIP+4
shr edi,2
mov dl,BreakPoint_saved[edi]
mov [eax],dl ; restore byte in the instruction
.if program_is_running == True
popad
pop ds
or byte ptr [esp+4*2+1],1 ; set Trap Flag on stack
jmp Handle_Debug_Exception
.else
popad
pop ds
iretd ; set to debugging mode (again)
.endif
not_a_brkpt: ;-------------------------------------------------
cmp byte ptr [eax],0CCh
je normal_CCh
dec eax
cmp word ptr [eax],03cdh
je normal_INT_3
popad
pop ds
iretd
normal_CCh:
.if program_is_running == True
sub dword ptr [esp+4*9],1 ; decreament EIP on stack
jmp exit
.endif
jmp exit
normal_INT_3:
.if program_is_running == True
sub dword ptr [esp+4*9],2 ; decreament EIP on stack
jmp exit
.endif
popad
pop ds
iretd
special_CCh:
mov ebx,dword ptr [esp+4*9] ; look to see if on a special
dec ebx
mov eax,special_brkpt_EIP
cmp ebx,eax
jne nospecial_CCh
mov special_brkpt,False
dec dword ptr [esp+4*9]
mov dl,special_brkpt_save
mov [eax],dl ; delete the 0CCh
exit:
popad
pop ds
or byte ptr [esp+4*2+1],1 ; set Trap Flag on stack
jmp Handle_Debug_Exception
BreakPoint_Exception ENDP
;===========================================================================
;
; The General Protection handler ( Interrupt 13 )
;
;
;===========================================================================
GeneralProtection_Exception PROC PRIVATE
; Read the ISR (Interrupt Service Register) to see if a IRQ is waiting
; to be serviced.
;
push eax
mov al,00001011b ; OCW3 to read ISR on next read
out 20h,al ; write to base I/O address of 8259A
in al,20h ; read ISR
and al,al
pop eax
jz non_V86_exec ; Brach if a IRQs is not awaiting
jmp cs:old_IntVect13
non_V86_exec:
add esp,4
push edx
mov edx,offset GP_mesg
jmp Close_the_fatal_falt
align 4
old_IntVect13 df 0
GP_mesg db 'Instruction Caused a General Protection Exception $'
GeneralProtection_Exception endp
;===========================================================================
;
; The Invalid Opcode handler ( Interrupt 6 )
;
;
;===========================================================================
InvalidOpcode_Exception PROC PRIVATE
push edx
mov edx,offset badI_mesg
jmp Close_the_fatal_falt
badI_mesg db 'Program executed an Invalid Opcode $'
InvalidOpcode_Exception ENDP
;===========================================================================
;
; The Divide by Zero handler ( Interrupt 0 )
;
;
;===========================================================================
DivideError_Exception PROC PRIVATE
push edx
mov edx,offset divide0_mesg
jmp Close_the_fatal_falt
divide0_mesg db ' Division By Zero Error$'
DivideError_Exception ENDP
;===========================================================================
;
; The Page Fault handler ( Interrupt 14 )
;
;
;===========================================================================
PageFalts_Exception PROC PRIVATE
; Read the ISR (Interrupt Service Register) to see if a IRQ is waiting
; to be serviced for VCPI server.
;
push eax
mov al,00001011b ; OCW3 to read ISR on next read
out 20h,al ; write to base I/O address of 8259A
in al,20h ; read ISR
and al,al
pop eax
jz skip_8259pf ; Brach if a IRQs is not awaiting
jmp cs:old_IntVect14
skip_8259pf:
add esp,4
.IF cs:Testing_EA_TEXT == True
push ds
push dword ptr _TEXT
pop ds
mov Testing_EA_TEXT,False
pop ds
add dword ptr [esp],tea_ins_size ; skip intruction that caused
iretd
.ENDIF
push edx
mov edx,offset PF_mesg
jmp Close_the_fatal_falt
PF_mesg db 'Instruction caused a Page Falt $'
old_IntVect14 df 0
PageFalts_Exception ENDP
;===========================================================================
;
; This rotine displays the exception error message and stuff
; Used by the above CPU exception routines
;===========================================================================
Close_the_fatal_falt PROC PRIVATE
push ds
push es
pushad
mov ax,_TEXT
mov ds,ax
mov es,ax
xor eax,eax ;disable debug registers
mov DR7,eax
mov eax,[esp+4*11] ; get EIP from stack
mov Step_flag,True
mov Selected_EIP,eax
mov screen_EIP_value,eax
mov registers_save.prg_EIP,eax
mov registers_save.prg_CS,cs
cld
push edx
call debuggers_video
call refresh_screen
pop edx
call print_message_box
popad
pop es
pop ds
pop edx
or byte ptr [esp+4*2+1],1 ; set Trap Flag on stack
jmp Handle_Debug_Exception ; set to debugging mode (again)
Close_the_fatal_falt ENDP
hardwareInstruc_mesg db ' Instruction Fault on Breakpoint Register '
DRx_mesg1 db ' $'
hardwareData_mesg db ' Data Trap on Breakpoint Register '
DRx_mesg2 db ' $'
;===========================================================================
;
; THE MAIN DEBUG EXCEPTION HANDLER ( INTERRUPT ONE )
;
;
;===========================================================================
Debug_Exception PROC PRIVATE
pushad
push ds
push es
mov ax,_TEXT
mov ds,ax
mov es,ax
.IF cs:Testing_EA_TEXT == True
mov Testing_EA_TEXT,False
pop es
pop ds
popad
iretd ; return to intruction on in EA test mode
.ENDIF
;================= GET DEBUG EXCEPTION STATUS from DR6 ========
mov eax,DR6
mov ebx,DR7
mov DRx_mesg1,'0'
mov DRx_mesg2,'0'
test al,1
jz brkpt1
test bl,3
jz brkpt1
shr ebx,16
jmp found_brkptReg
brkpt1: mov DRx_mesg1,'1'
mov DRx_mesg2,'1'
test al,2
jz brkpt2
test bl,0ch
jz brkpt2
shr ebx,20
jmp found_brkptReg
brkpt2: mov DRx_mesg1,'2'
mov DRx_mesg2,'2'
test al,4
jz brkpt3
test bl,030h
jz brkpt3
shr ebx,24
jmp found_brkptReg
brkpt3: mov DRx_mesg1,'3'
mov DRx_mesg2,'3'
test al,8
jz no_brkpt
test bl,0c0h
jz no_brkpt
shr ebx,28
found_brkptReg:
test bl,03
jz RW0
push offset hardwareData_mesg
jmp RW1
RW0: push offset hardwareInstruc_mesg
RW1: call Debuggers_video
mov eax,[esp+4*11] ; get EIP form stack
mov Selected_EIP,eax
mov step_flag,True
mov registers_save.prg_EIP,eax
call refresh_screen
pop edx
call print_message_box
or dword ptr [esp+4*12],010100h ; Set the TF and RF
jmp Step_debug
no_brkpt:
test eax,4000h
jz normal_INT1
Step_debug:
xor eax,eax
mov DR6,eax ; must clear the DR6 bits
normal_INT1: pop es
pop ds
popad
jmp handle_Debug_Exception
Debug_Exception ENDP
;===========================================================================
;
; THE GENARAL DEBUG EXCEPTION HANDLER for exceptions from breakpoints
; , TF or any breakpoint registers.
;
; This is the main routine of the whole debugger.
;
;===========================================================================
Handle_Debug_Exception PROC PRIVATE
push ds
push dword ptr _TEXT
pop ds
pop registers_save.prg_ds
pop registers_save.prg_EIP
pop registers_save.prg_cs
pop registers_save.prg_eflags
mov registers_save.prg_Eax, eax
mov registers_save.prg_Ebx, ebx
mov registers_save.prg_Ecx, ecx
mov registers_save.prg_Edx, edx
mov registers_save.prg_Edi, edi
mov registers_save.prg_Esi, esi
mov registers_save.prg_Ebp, ebp
mov registers_save.prg_Esp, esp
mov registers_save.prg_ss , ss
mov registers_save.prg_es , es
mov registers_save.prg_fs , fs
mov registers_save.prg_gs , gs
pushad
push fs
push es
push ds ; Load ES with data selector
pop es
cld
;-------------------------------------------------------------------
mov program_is_running,False
.if haveOrigonalRegisters == False
mov edi,offset origonal_registers
mov esi,offset registers_save
mov ecx,(SIZEOF registers_save)/4
rep movsd
mov haveOrigonalRegisters,True
.endif
mov eax,registers_save.prg_EIP
mov Selected_EIP,eax
mov step_flag,True
.if Users_Screen == True
call Debuggers_Video
.endif
.if InitDebugOnly == True
mov edx,offset intro_mesg
call print_message_box
mov InitDebugOnly,False
.endif
main_loop:
call refresh_screen
key_waitloop:
test Key_flags,010b ; look at CTL flag
jz no_ctrl
call Display_DRx_info
mov edi,(0 + 80*49 )
mov ah,menu_color
draw_horz ' ',80
jmp skip_disp
no_ctrl:
test Key_flags,1 ; look at ALT flag
jnz disp_nalt
call Display_SegReg_info
mov edx,offset menu_bar_text
jmp disp_alt
disp_nalt:
mov edx,offset menu_alt_bar_text
disp_alt: mov edi,(0 + 80*49 )
mov ah,menu_color
call plot_string
skip_disp:
;=======================================================
in al,64h
test al,1
jz key_waitloop
in al,60h
.if al == 38h ; set for 'Alt'
or Key_flags,1
.elseif al == 38h or 80h
and Key_flags,Not 1 ; clear 'Alt'
.elseif al == 1Dh ; set for 'Ctrl'
or Key_flags,2
INT 9
.elseif al == 1Dh or 80h
and Key_flags,Not 2 ; clear 'Ctrl'
INT 9
.endif
push eax
in al,61h ; (pulse PPI port B bit 1
or al,80h ;set bit 7 ; to acknoledge the keyboard)
out 61,al
and al,7fh ;clear bit 7
out 61h,al
pop eax
test al,80h
jnz key_waitloop
mov ah,al
mov al,Key_flags
.if ah == 50h
inc selected_line
.elseif ah == 48h
dec selected_line
.endif
cmp ax , 3F01h ;alt+F5
je user_screen
cmp ax, 4300h ;F9
je run_program
cmp ax, 4301h ;alt+F9
je goto_start
cmp ax, 3E00h ;F4
je here
cmp ax, 3C00h ;F2
je set_brkpt
cmp ax , 4200h ;F8
je large_steping
cmp ax, 4100h ;F7
je step_intruc
cmp ax, 3E01h ;alt+F4
je back_step
cmp ax, 2D01h ;alt+X
je exit_program
cmp ah, 51h ; pgDown
je page_Down
cmp ah, 49h ; pgUP
je page_Up
jmp main_loop
continue_debugging:
pop es
pop fs
popad
mov ds,registers_save.prg_ds
push cs:registers_save.prg_eflags
push cs:registers_save.prg_cs
push cs:registers_save.prg_EIP
iretd
page_Up:
sub selected_line,(ScreenHeight-10)
jmp main_loop
page_Down:
mov eax,screen_ending_EIP
mov screen_EIP_value,eax
jmp main_loop
large_steping:
mov eax,registers_save.prg_EIP
mov ecx,Number_brkpts
mov edi,offset BreakPoint_EIP
repne scasd
jne @f
sub edi,offset BreakPoint_EIP+4
shr edi,2
mov dl,BreakPoint_saved[edi]
mov [eax],dl
@@:
mov esi,eax
mov edi,offset string_buffer
call Decode_instruction
cmp dword ptr string_buffer,06c6c6163h ; look for "call"
je skipcall
cmp dword ptr string_buffer,0706f6f6ch ; look for "loop"
je skipcall
and dword ptr string_buffer,0ffffffh
cmp dword ptr string_buffer,00706572h ; look for "rep"
jne step_intruc
skipcall:
call CheckVGAport
mov special_brkpt_EIP,esi
mov dl,[esi]
mov special_brkpt_save,dl
mov byte ptr [esi],0CCh ; insert the CC
mov special_brkpt,True
mov program_is_running,True
call restore_video ; goto users screen
and registers_save.prg_eflags,not 00100000000b
mov BacklogRegPTR_head,0 ; clear backlog
mov BacklogRegPTR_tail,0
jmp continue_debugging
step_intruc:
call Update_register_LOG
mov eax,registers_save.prg_EIP
mov ecx,Number_brkpts
mov edi,offset BreakPoint_EIP
repne scasd
jne @f
sub edi,offset BreakPoint_EIP+4
shr edi,2
mov dl,BreakPoint_saved[edi]
mov [eax],dl
@@:
call CheckVGAport
.if byte ptr [eax] == 0CDh ;see if a INT n instruction
.if byte ptr [eax+1] == 21h ; must not stop INt 21h ah=4ch
cmp byte ptr registers_save.prg_eax+1,04Ch
je continue_debugging
.endif
add eax,2
mov special_brkpt_EIP,eax
mov dl,[eax]
mov special_brkpt_save,dl
mov byte ptr [eax],0CCh ; insert the CC
mov special_brkpt,True
mov BacklogRegPTR_head,0 ; clear backlog
mov BacklogRegPTR_tail,0
mov program_is_running,True
call restore_video ; goto users screen
and registers_save.prg_eflags,not 00100000000b
jmp continue_debugging
.endif
jne continue_debugging
run_program:
mov BacklogRegPTR_head,0 ; clear backlog
mov BacklogRegPTR_tail,0
call restore_video
mov eax,registers_save.prg_eip
mov ecx,Number_brkpts
mov edi,offset BreakPoint_EIP
repne scasd
je continue_debugging ; don't run a debugger break point
.if byte ptr [eax] == 0CCh ; don't run a users break point
inc registers_save.prg_eip
.elseif word ptr [eax] == 03CDh
add registers_save.prg_eip,2
.endif
mov program_is_running,True
and registers_save.prg_eflags,not 00100000000b
jmp continue_debugging
exit_program:
xor eax,eax ;disable debug registers
mov DR7,eax
; mov ax,003h ; Goto normal text mode on exit
; int 10h
; cmp prg_VideoMode, 3
; je Jd3
; cmp prg_VideoMode, 83h
; jne Jl2
;Jd3:
call Restore_Video ; Goto normal users mode on exit
Jl2:
mov ah,03 ;- Restore keyboard typmatic rate
mov al,05h
mov bl,Kbd_Rate ; Rate (0..1fh)
mov bh,Kbd_Delay ; Delay (0..3)
cmp bl,-1
je @f
int 16h
@@: mov DebuggerTerminated,True
mov ax,4C00h
int 21h ; Terminate to Operating system
user_screen:
call Restore_video
@@:
in al,64h ; Read key only when 8242 is ready
test al,1
jz @b
in al,60h ; wait for enter key
.if al == 38h ; set for 'Alt'
or Key_flags,1
.elseif al == 38h or 80h
and Key_flags,Not 1 ; clear 'Alt'
.endif
test al,80h ; loop if release code
jnz @b
call Debuggers_Video
jmp main_loop
here:
mov eax,Selected_EIP
mov registers_save.prg_EIP,eax
jmp main_loop
goto_start:
call debuggers_video
mov BacklogRegPTR_head,0
mov BacklogRegPTR_tail,0
mov Step_flag,True
.if haveOrigonalRegisters == True
mov esi,offset origonal_registers
mov edi,offset registers_save
mov ecx,(SIZEOF registers_save)/4
rep movsd
.endif
call refresh_screen
jmp load_all_regs
;============================ The Break Point mangaging routine ===========
set_brkpt:
mov eax,Selected_EIP
mov ecx,Number_brkpts
mov edi,offset BreakPoint_EIP
repne scasd
je Deleate_brkpt
xor eax,eax
mov ecx,Number_brkpts
mov edi,offset BreakPoint_EIP
repne scasd
je insert_a_brkpt
;------ show that no more break points can be used---------
mov edx,offset brkpts_are_full_mesg
call print_message_box
jmp main_loop
brkpts_are_full_mesg label byte
db 'No more than 50 Breakpoints can be assigned $'
Deleate_brkpt:
sub edi,offset BreakPoint_EIP+4
;---------- take away the break point --------------
mov BreakPoint_EIP[edi],0
shr edi,2
mov dl,BreakPoint_saved[edi]
mov eax,Selected_EIP
mov [eax],dl ; restore byte in the instruction
jmp main_loop
insert_a_brkpt:
sub edi,offset BreakPoint_EIP+4
mov eax,Selected_EIP
mov dx,[eax] ; save byte in the instruction
cmp dl,0cch ; not allowed to put brk pts on top of brk pts
je stupid_person
cmp dx,03CDh
je stupid_person
mov BreakPoint_EIP[edi],eax
shr edi,2
mov BreakPoint_saved[edi],dl
mov byte ptr [eax],0CCH ; but in a INT 3
jmp main_loop
stupid_person:
mov edx,offset mesg_1234
call print_message_box
jmp main_loop
mesg_1234 db 'Are you stupid? You can''t put a Breakpoint on a Breakpoint ¡$'
back_step:
mov eax,BacklogRegPTR_head
.if BacklogRegPTR_tail != EAX
sub eax, SIZEOF program_reg
jge @f
mov eax,SIZEOF registers_saved_backlog - SIZEOF program_reg
@@: mov BacklogRegPTR_head,eax
;------ copy all regs into back log --------------
mov esi,BacklogRegPTR_head
mov BacklogRegPTR_head,eax
add esi,offset registers_saved_backlog
mov edi,offset registers_save
mov ecx,(SIZEOF program_reg ) /4
rep movsd
.else
jmp main_loop
.endif
pop es
pop fs
popad
load_all_regs PROC PRIVATE
mov eax,registers_save.prg_Eax
mov ebx,registers_save.prg_Ebx
mov ecx,registers_save.prg_Ecx
mov edx,registers_save.prg_Edx
mov edi,registers_save.prg_Edi
mov esi,registers_save.prg_Esi
mov ebp,registers_save.prg_Ebp
mov esp,registers_save.prg_Esp
mov ss,registers_save.prg_ss
mov es,registers_save.prg_es
mov fs,registers_save.prg_fs
mov gs,registers_save.prg_gs
mov ds,registers_save.prg_ds
push cs:registers_save.prg_eflags
push cs:registers_save.prg_cs
push cs:registers_save.prg_EIP
jmp Handle_Debug_Exception
load_all_regs ENDP
Handle_Debug_Exception ENDP
;----------------------------------------------------------------------
;
; The following routines are used to make calling DOS32 services easier.
;----------------------------------------------------------------------
SetIntVector PROC PRIVATE Uses Eax
mov ax,0205h
int 31h
ret
SetIntVector ENDP
GetIntVector PROC PRIVATE Uses Eax
mov ax,0204h
int 31h
ret
GetIntVector ENDP
GetIrqVector PROC PRIVATE Uses Eax Ebx
cmp bl,8h
jb @@j1
add bl,60h
@@j1: add bl,8
mov ax,0204h
int 31h
ret
GetIrqVector ENDP
SetIrqVector PROC PRIVATE Uses Eax Ebx
cmp bl,8h
jb @@j1
add bl,60h
@@j1: add bl,8
mov ax,0205h
int 31h
ret
SetIrqVector ENDP
debugger_ending EQU $ ; Define the debuggers ending address
END
\\\\\\\