1
; DEBUG.ASM Masm/JWasm assembler source for Debug/X.
4
; jwasm -bin -Fo debug.com debug.asm
6
; To create DEBUGX, the DPMI aware version of debug, use:
7
; jwasm -D?DPMI=1 -bin -Fo debugx.com debug.asm
9
; ============================================================================
11
; Copyright (c) 1995-2003 Paul Vojta
13
; Permission is hereby granted, free of charge, to any person obtaining a copy
14
; of this software and associated documentation files (the "Software"), to
15
; deal in the Software without restriction, including without limitation the
16
; rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
17
; sell copies of the Software, and to permit persons to whom the Software is
18
; furnished to do so, subject to the following conditions:
20
; The above copyright notice and this permission notice shall be included in
21
; all copies or substantial portions of the Software.
23
; THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
24
; IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
25
; FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
26
; PAUL VOJTA BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
27
; IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
28
; CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
30
; ============================================================================
32
; Japheth: all extensions made by me are Public Domain. This does not
33
; affect other copyrights.
34
; This file is now best viewed with TAB size 4!
35
; ============================================================================
37
; 0.95e [11 January 2003] Fixed a bug in the assember.
38
; 0.95f [10 September 2003] Converted to NASM; fixed some syntax
40
; 0.98 [27 October 2003] Added EMS commands and copyright conditions.
42
; The changes which were done by my, japheth, are described in
46
; - allow to modify floating point registers
47
; - better syntax checks for A (so i.e. "mov ax,al" is rejected)
48
; - add MMX instructions for A and U
49
; - support loading *.HEX files
50
; - hide debug's IVT vectors 0,1,3 for d(i)? Alternately, init them only when the
51
; first G/P/T cmd is run, like MS Debug does for 1 & 3?
57
; option noljmp ;enable to see the short jump extensions
65
TOUPPER_W equ (TOUPPER shl 8) or TOUPPER
66
MNEMONOFS equ 28 ;offset in output line where mnemonics start (disassember)
67
STACKSIZ equ 200h ;debug's stack size
68
MCLOPT equ 1 ;1=accept /m cmdline opt ( disable IRQ checks for int 08-0F )
69
LINE_IN_LEN equ 257 ;length of line_in (including header stuff)
72
FMTEXE equ 0 ;1=debugger binary has .EXE format
75
DRIVER equ 0 ;1=create a device driver (for CONFIG.SYS) variant
78
BOOTDBG equ 0 ;1=create a bootstrap binary (DebugB)
81
RING0 equ 0 ;1=create a ring0 debugger variant (DebugR)
84
?DPMI equ 0 ;1=create a DPMI-aware variant (DebugX)
87
LMODE equ 0 ;1=long mode version if RING0==1 - this will define a 64-bit segment ( requires JWasm )
90
;--- default assembly-time values; may be overwritten below.
92
DGCMD = 0 ; support DG cmd
93
DICMD = 0 ; support DI cmd
94
DLCMD = 0 ; support DL cmd
95
DMCMD = 1 ; support DM cmd
96
DPCMD = 0 ; support DP cmd (dump partition)
97
DPCMDR0 = 0 ; support DP cmd (dump paging table, ring0 only)
98
DTCMD = 0 ; support DT cmd
99
DXCMD = 0 ; support DX cmd
100
QCMD = 1 ; support Q cmd
101
LCMD = 1 ; support L cmd
102
WCMD = 1 ; support W cmd
103
XCMDS = 1 ; support Xx cmds
104
LCMDFILE = 1 ; support L cmd for files and N cmd
105
WCMDFILE = 1 ; support W cmd for files and N cmd
106
USESDA = 1 ; use SDA to get/set PSP in real-mode
107
INT22 = 1 ; handle int 22h ( DOS program termination )
108
INT2324 = 1 ; switch int 23h & 24h for debugger/debuggee
109
USEFP2STR = 0 ; 1=use FloatToStr()
110
FLATSS = 0 ; always 0 except for DebugRL; flat stack needed for long mode ring0 variant.
112
SKIPBPINDBG equ 1 ; 1=breakpoints occuring while in debug are reported, won't reenter debug
115
CS32 equ 40h or 20h ; check both default size and 64-bit mode
117
CS32 equ 40h ; check just the default size in legacy
123
V86M equ 0 ; 1=support v86 mode ( for RING0 only )
128
DBGNAME equ <"DEBUG64">
129
DBGNAME2 equ <"Debug64">
130
@VecAttr textequ <lowword>
131
;--- long mode needs a flat 32-bit stack inside debug!
132
;--- that's because otherwise an exception inside the PL0 debugger
133
;--- would switch to 64-bit code with a 16-bit "flat" stack pointer.
134
FLATSS = 1 ; 1=32-bit flat stack
136
DBGNAME equ <"DEB386">
137
DBGNAME2 equ <"Deb386">
141
USEHWBP equ 1 ; 1=use 386 hw breakpoints
143
;NOEXTENDER equ 0 ; ??? used at all for ring0 ???
144
DISPPL0STK equ 0 ;1=display ring 0 stack in register dump
145
CHKIOPL equ 1 ;1=don't stop if GPF cause of IOPL==0 and iosensitive instr
156
DBGNAME equ <"DEBUGX">
157
DBGNAME2 equ <"DebugX">
159
VDD equ 1 ;1=try to load DEBXXVDD.DLL
160
NOEXTENDER equ 1 ;1=don't assume DPMI host includes a DOS extender
161
WIN9XSUPP equ 1 ;1=avoid to hook DPMI entry when running in Win9x
162
DOSEMU equ 1 ;1=avoid to hook DPMI entry when running in DosEmu
163
DISPHOOK equ 1 ;1=display "DPMI entry hooked..."
165
CATCHEXC06 equ 0 ;1=catch exception 06h in protected-mode
168
CATCHEXC07 equ 0 ;1=catch exception 07h in protected-mode
170
CATCHEXC0C equ 1 ;1=catch exception 0Ch in protected-mode
171
CATCHINT21 equ 1 ;1=hook into protected-mode int 21h
173
CATCHINT31 equ 0 ;1=hook DPMI int 31h
175
CATCHINT41 equ 1 ;1=hook into protected-mode debug interface
176
MMXSUPP equ 1 ;1=support MMX specific commands
178
USEHWBP equ 1 ;1=try to use 386 hw breakpoints (fails on NTVDM/DosEmu)
181
BCMD equ 0 ;BCMD=1 requires USEHWBP=1
189
DBGNAME2 equ <"Debug">
212
ifndef CATCHINT0C ; may be activated with cmdline option
219
QCMD = 0 ; may be set to 1
244
USEUNREAL equ 0 ;1=use "unreal" mode for DX cmd ( won't work in v86 )
250
VXCHG equ 0 ;1=support video swap so outputs remain separated
253
ALTVID equ 0 ;1=support alternate video adapter
265
if (DRIVER or BOOTDBG or RING0)
268
REDIRECT equ 1 ;stdin/stdout redirection
271
SYSRQINT equ 9 ;if CATCHSYSREQ==1, defines the method (int 09h or int 15h)
274
CATCHINT01 equ 1 ;catch INT 01 (single-step)
275
NOEXC01INDBG equ 1 ;v2.01: ignore unexpected debug exceptions in debug itself
278
CATCHINT03 equ 1 ;catch INT 03 (break)
281
CATCHINT06 equ 0 ;catch exception 06h
284
CATCHINT07 equ 0 ;catch exception 07h
287
CATCHINT0C equ 0 ;catch exception 0Ch
290
CATCHINT0D equ 0 ;catch exception 0Dh
293
CATCHSYSREQ equ 0 ;catch int 09h/15h (sysreq)
296
CATCHINT41 equ 0 ;hook int 41h
306
EXCCSIP equ 1 ;display CS:IP where exception occured
308
EXCCSEIP equ 1 ;debugger may callout to v86-monitor, which is 32-bit CS
310
EXCCSEIP equ 0 ;may be activated if unknown exceptions occur in debugger
318
ALASAP dw ? ;+02 Address of LAst Segment Allocated to Program
320
TPIV dd ? ;+0A Terminate Program Interrupt Vector (int 22h)
321
CCIV dd ? ;+0E Control C Interrupt Vector (int 23h)
322
CEIV dd ? ;+12 Critical Error Interrupt Vector (int 24h)
324
PARENT dw ? ;+16 segment of parent PSP
326
SPSAV dd ? ;+2E Saved SS:SP in last DOS call
331
DTA db 128 dup (?);Program arguments; also used to store file name (N cmd)
334
;--- attributes returned by int 21h, ax=4400h
335
AT_DEVICE equ 80h ; is device (not file)
338
@dprintf macro text:req,a1,a2,a3,a4,a5,a6,a7,a8
345
for x,<a8,a7,a6,a5,a4,a3,a2,a1>
358
;--- restore segment register (DS/ES) to DGROUP
360
@RestoreSeg macro segm
362
mov segm, cs:[wDgroup]
369
;--- sizeprf is to make DEBUG's support for 32bit code as small as possible.
370
;--- for this to achieve a patch table is created in _IDATA which is filled
371
;--- by memory offsets where prefix bytes 66h or 67h are found.
390
;--- standard BOPs for communication with DEBXXVDD on NT platforms
392
db 0C4h, 0C4h, 58h, 0
394
UnRegisterModule macro
395
db 0C4h, 0C4h, 58h, 1
398
db 0C4h, 0C4h, 58h, 2
404
;--- define segments. Usually, the debugger runs in the tiny memory model,
405
;--- that is, all segments are grouped into "physical segment" DGROUP, and
406
;--- CS=SS=DS=ES=DGROUP ( exception: RING0=1 && FLATSS=1 ). When other memory
407
;--- regions are to be accessed, preferably ES is temporary used then, in a
408
;--- few cases ( m/c cmds ) also DS.
410
_TEXT segment dword public 'CODE'
416
_TEXT64 segment use64 para public 'CODE' ; alignment para is needed for correct offsets
422
CONST segment readonly word public 'DATA'
425
ASMDATA segment word public 'DATA'
429
OTDATA segment word public 'DATA'
432
_DATA segment dword public 'DATA'
436
_ITEXT segment dword public 'I_CODE'
438
_ITEXT segment word public 'I_CODE'
442
_IDATA segment word public 'I_DATA'
446
DGROUP group _TEXT, CONST, ASMDATA, OTDATA, _DATA, _ITEXT, _IDATA
449
STACK segment para stack 'STACK'
461
dw 08000h ; driver flags : character dev
462
Strat dw offset strategy ; offset to strategy routine
463
Intrp dw offset driver_entry ; offset to interrupt handler
464
device_name db 'DEBUG$RR' ; device driver name
467
req_size db ? ;+0 number of bytes stored
468
unit_id db ? ;+1 unit ID code
469
cmd db ? ;+2 command code
470
status dw ? ;+3 status word
471
rsvd db 8 dup(?);+5 reserved
477
mov word ptr cs:[request_ptr+0],bx
478
mov word ptr cs:[request_ptr+2],es
483
lds di, cs:[request_ptr] ; load address of request header
484
mov [di].req_hdr.status,8103h
490
ife (RING0 or BOOTDBG)
500
jmp getr0stk ; get ring 0 SS:ESP
501
org start+6 ; entercmd must be start+2*3
502
jmp uninstall ; uninstall
511
;--- cmds b,j,k,v,y and z don't exist yet
516
bcmdv dw b_cmderr ; may be dynamically set to b_cmd
521
dw e_cmd, f_cmd, g_cmd, h_cmd
522
dw i_cmd, cmd_error, cmd_error
529
if LCMDFILE or WCMDFILE
540
dw r_cmd, s_cmd, t_cmd
562
dbg2324 dw i23pm, i24pm
570
top_sp dd 0 ;debugger's SP top ( also end of debug's MCB )
571
run_sp dd 0 ;debugger's SP when run() is executed ( also used temp. by disasm )
573
top_sp dw 0 ;debugger's SP top ( also end of debug's MCB )
574
run_sp dw 0 ;debugger's SP when run() is executed
576
errret dw 0 ;return here if error
577
ife (BOOTDBG or RING0)
578
spadjust dw 40h ;adjust sp by this amount for save
579
pspdbe dw 0 ;debuggee's program segment prefix (segment/selector)
582
;--- wDgroup contains the DGROUP segment, not translated!
583
;--- pspdbg contains the PSP, not translated
584
;--- pspdbgpm is the translated pspdbg (.EXE only)
585
;--- in protected-mode, the code usually uses [dssel] to set SS and DS
587
wDgroup label word ;pspdbg is the PSP segment or just the CS segment (Dgroup)
589
dw 0 ;for .EXE, DGROUP and debugger's psp are different
591
pspdbg dw 0 ;debugger's PSP - always a segment
593
pspdbgpm dw 0 ;selector for debugger's PSP
597
run2324 dw 0,0,0,0 ;debuggee's interrupt vectors 23 and 24 (both modes)
599
dw 0,0 ;in DPMI32, vectors are FWORDs
609
hVdd dw -1 ;handle of NT helper VDD
613
sav2324 dw 0,0,0,0 ;debugger's interrupt vectors 23 and 24 (real-mode only)
616
psp22 dw 0,0 ;original terminate address in debugger's PSP
617
parent dw 0 ;original parent PSP in debugger's PSP (must be next)
620
wMCB dw 0 ;start of MCB chain (always segment)
622
ife ( BOOTDBG or RING0 )
623
pInDOS dd 0 ;far16 address of InDOS flag (real mode)
626
InDosSel dw 0 ;selector value for pInDOS in protected-mode
637
xmsdrv dd 0 ; XMM driver address, obtained thru int 2F, ax=4310h
638
xmsmove XMSM <> ; XMS block move struct, used to save/restore screens
639
csrpos dw 0 ; cursor position of currently inactive screen
640
vrows db 0 ; current rows; to see if debuggee changed video mode
643
if ALTVID ; exchange some video BIOS data fields for option /2.
644
oldcsrpos dw 0 ; cursor position
645
oldcrtp dw 0 ; CRTC port
646
oldcols dw 80 ; columns
648
oldmode db 0 ; video mode
649
oldrows db 24 ; rows - 1
652
pSDA dd 0 ;far16 address of DOS swappable data area (real-mode)
654
SDASel dw 0 ;selector value for pSDA in protected-mode
658
hakstat db 0 ;whether we have hacked vectors 23/24 or not
660
machine db 0 ;cpu (0=8086,1,2,3=80386,...)
662
RM_386REGS equ 1 ;bit 0: 1=386 register display
666
rmode db 0 ;flags for R command
668
tmode db 0 ;bit 0: 1=ms-debug compatible trace mode
672
wStoreBP dw offset storebpdef ; proc to set first bp for G/P/T
673
wRMSetBP dw offset r0sethwbp ; proc to set hw bps in real-mode/r0
674
wRMResetBP dw offset r0resethwbp ; proc to reset hw bps in real-mode/r0
677
has_87 db 0 ;if there is a math coprocessor present
678
mach_87 db 0 ;coprocessor (0=8087,1,2,3=80387,...)
682
bInDbg db 0 ;1=debugger is running
683
if MCLOPT and ( CATCHINT0C or CATCHINT0D )
684
bMPicB db 8 ;master PIC base
687
fStdin db AT_DEVICE;flags stdin
688
fStdout db AT_DEVICE;flags stdout
690
swchar db '-' ;switch character
691
vpage db 0 ;video page the debugger is to use for BIOS output
692
swch1 db ' ' ;switch character if it's a slash
693
promptlen dw 0 ;length of prompt
695
bufnext dw line_in+2 ;if stdin=file: address of next available character
696
bufend dw line_in+2 ;if stdin=file: address + 1 of last valid character
699
a_addr dw 0,0,0 ;address for next A command
700
d_addr dw 0,0,0 ;address for last D command; must follow a_addr
701
u_addr dw 0,0,0 ;address for last U command; must follow d_addr
707
BP_TEMP equ 20h ;1=bp is temporary
708
BP_ACTIVE equ 40h ;1=bp has been set
709
BP_USED equ 80h ;1=used,0=free
721
HWBps HWBPSTRUCT MAXHWBP dup (<0,0>)
725
x_addr dd 0 ;(phys) address for last DX command
727
eqladdr dw 0,0,0 ;optional '=' argument in G, P and T command
728
;run_cs dw 0 ;save original CS when running in G
731
run_int db 0,0 ;interrupt type that stopped the running
732
eqflag db 0 ;flag indicating presence of '=' argument
733
bInit db 0 ;0=ensure a valid opcode is at debuggee's CS:IP
735
scratchsel dw 0 ;scratch selector ( used by cmds a,c,e,f,g,m,p,t )
738
bV86Bp db 0F4h ;may be 0F4h or 63h
740
bCSAttr db 0 ;current code attribute (D bit).
741
bAddr32 db 0 ;1=offset is 32-bit ( segment limit > 0ffffh )
742
bFlagsPM db 0 ;bit 0: 0=no default set for A cmd
744
;--- exceptions trapped ( modified by VC/VT )
745
wTrappedExc dw (1 shl 0) or (1 shl 1) or (1 shl 3) or (CATCHINT06 shl 6) (CATCHINT07 shl 7) or \
746
(CATCHINT0C shl 12 ) or (CATCHINT0D shl 13) or (1 shl 14)
752
if LCMDFILE or WCMDFILE
753
fileext db 0 ;file extension (0 if no file name)
764
;--- 0: packet is not used (int 25h/26h, cx!=FFFF)
765
;--- 1: packet is used (int 25h/26h, cx==FFFF)
766
;--- 2: packet is used (int 21h, ax=7305h, cx==FFFF)
770
secno dd ? ;sector number
771
numsecs dw ? ;number of sectors to read
772
dstofs dw ? ;ofs transfer address
773
dstseg dw ? ;seg transfer address
777
PACKET32 struc ; this is for DPMI32 only
787
packet PACKET <0,0,0,0>
789
dw 0 ; reserve space for the additional 2 bytes of PACKET32
794
if RING0 ; vectors in intsave are either real-mode or - if RING0 == 1 - protected-mode
795
INTVEC textequ <FWORD>
797
INTVEC textequ <DWORD>
800
;--- order in intsave must match order in inttab
803
oldi00 INTVEC 0 ;saved vector i00
804
if RING0 or CATCHINT01
805
oldi01 INTVEC 0 ;saved vector i01
807
if RING0 or CATCHINT03
808
oldi03 INTVEC 0 ;saved vector i03
811
oldi06 INTVEC 0 ;saved vector i06
814
oldi07 INTVEC 0 ;saved vector i07
817
oldi0C INTVEC 0 ;saved vector i0C
820
oldi0D INTVEC 0 ;saved vector i0D
823
oldi0E INTVEC 0 ;saved vector i0E
826
oldisrq INTVEC 0 ;saved vector i09/i15
829
INTVEC 0 ;saved vector i22 ( real-mode only )
831
if RING0 and CATCHINT41
832
oldint41 INTVEC 0 ;saved vector i41 ( protected-mode only )
834
if ?DPMI ;must be last
835
oldi2f dd 0 ; real-mode only
839
int10vec df 0 ; (int 10h) output routine
840
int16vec df 0 ; (int 16h) input routine
844
dw 8 ; selector 8 is 64-bit ( Dos32cm )
847
jmpv161s dw 0 ; debugger cs
849
o dw offset intrtnp2,0
850
jmpv162s dw 0 ; debugger cs
851
dwBase64 dd 0 ; linear address start _TEXT64
854
dwBase dd 0 ; linear address start _TEXT
858
;--- Parameter block for exec call.
862
environ dw ? ; +0 environment segment
863
cmdtail dd ? ; +2 address of command tail to copy
864
fcb1 dd ? ;+6 address of first FCB to copy
865
fcb2 dd ? ;+10 address of second FCB to copy
866
sssp dd ? ;+14 initial SS:SP
867
csip dd ? ;+18 initial CS:IP
870
execblk EXECS {0,0,PSPS.FCB1,PSPS.FCB2,0,0}
874
rDI dw ?,? ;+00 edi ; must be in PUSHAD order
883
rDS dw ? ;+32 ds ; check run()/intrtn()/createdummytask() if this order changes!
885
rFS dw ? ;+36 fs ; v2.0: order changed
887
rSS dw ? ;+40 ss ; should start on a DWORD boundary ( in case AC is on )
890
dw ? ; added ( for 32-bit CS push )
895
rFL dw ?,? ;+54 eflags
907
msw dw ? ;0000=real-mode, FFFF=protected-mode
911
;--- Register save area.
913
align 4 ;--- must be DWORD aligned!
921
;--- table of interrupt initialization
928
;--- must match order in intsave
931
INTITEM <00h, @VecAttr intr00>
933
INTITEM <01h, @VecAttr intr01>
936
INTITEM <03h, @VecAttr intr03>
939
INTITEM <06h, @VecAttr intr06>
942
INTITEM <07h, @VecAttr intr07>
945
INTITEM <0Ch, @VecAttr intr0C>
948
INTITEM <0Dh, @VecAttr intr0D>
951
INTITEM <0Eh, @VecAttr intr0E>
954
INTITEM <SYSRQINT, intrsrq>
957
INTITEM <22h, intr22dbg>
959
if RING0 and CATCHINT41
960
itab41 INTITEM <41h, intr41>
962
NUMINTS = ( $ - inttab ) / sizeof INTITEM
967
;--- register names for 'r'. One item is 2 bytes.
968
;--- regofs must follow regnames and order of items must match
969
;--- those in regnames.
971
regnames db 'AX','BX','CX','DX',
972
'SP','BP','SI','DI','IP','FL',
973
'DS','ES','SS','CS','FS','GS'
974
NUMREGNAMES equ ($ - regnames) / 2
975
regofs dw regs.rAX, regs.rBX, regs.rCX, regs.rDX,
976
regs.rSP, regs.rBP, regs.rSI, regs.rDI, regs.rIP, regs.rFL,
977
regs.rDS, regs.rES, regs.rSS, regs.rCS, regs.rFS, regs.rGS
979
;--- arrays flgbits, flgnams and flgnons must be consecutive
980
flgbits dw 800h,400h,200h,80h,40h,10h,4,1
981
flgnams db 'NV','UP','DI','PL','NZ','NA','PO','NC'
982
flgnons db 'OV','DN','EI','NG','ZR','AC','PE','CY'
984
;--- Instruction set information needed for the 'p' command.
985
;--- arrays ppbytes and ppinfo must be consecutive!
987
ppbytes db 66h,67h,26h,2eh,36h,3eh,64h,65h,0f2h,0f3h ;prefixes
988
db 0ach,0adh,0aah,0abh,0a4h,0a5h ;lods,stos,movs
989
db 0a6h,0a7h,0aeh,0afh ;cmps,scas
990
db 6ch,6dh,6eh,6fh ;ins,outs
991
db 0cch,0cdh ;int instructions
992
db 0e0h,0e1h,0e2h ;loop instructions
993
db 0e8h ;call rel16/32
994
db 09ah ;call far seg16:16/32
995
; (This last one is done explicitly by the code.)
996
; db 0ffh ;ff/2 or ff/3: indirect call
998
; Info for the above, respectively.
1000
; 81h = address size prefix.
1001
; 82h = operand size prefix;
1002
; If the high bit is not set, the next highest bit (40h) indicates that
1003
; the instruction size depends on whether there is an address size prefix,
1004
; and the remaining bits tell the number of additional bytes in the
1012
ppinfo db 82h,81h,80h,80h,80h,80h,80h,80h,80h,80h ;prefixes
1013
db 0,0,0,0,0,0 ;string instr
1014
db 0,0,0,0 ;string instr
1015
db 0,0,0,0 ;string instr
1017
db 1,1,1 ;LOOPx instr
1018
db 42h ;near CALL instr
1019
db 44h ;far CALL instr
1025
ife (BOOTDBG or RING0)
1026
db '!' ;additional prompt if InDos flag is set
1029
prompt1 db @CatStr(!',%PROMPT,!')
1032
prompt1 db '>' ;indicates v86 mode for DebugRV
1034
prompt1 db '-' ;main prompt
1038
prompt2 db ':' ;prompt for register value
1044
prompt3 db '#' ;protected-mode prompt
1047
helpmsg db DBGNAME2, ' v',@CatStr(!',%VERSION,!'),CR,LF
1048
db 'assemble', TAB, 'A [address]',CR,LF
1050
db 'clear bp', TAB, 'BC # (#=0|1|2|3)',CR,LF
1051
db 'set/show bp', TAB, 'BP [address [type]]',CR,LF
1053
db 'compare', TAB, TAB, 'C range address',CR,LF
1054
db 'dump', TAB, TAB, 'D [range]',CR,LF
1056
db 'dump GDT', TAB, 'DG selector [count]',CR,LF
1060
db 'dump IDT', TAB, 'DI interrupt [count]',CR,LF
1062
db 'dump interrupt', TAB, 'DI interrupt [count]',CR,LF
1066
db 'dump LDT', TAB, 'DL selector [count]',CR,LF
1069
db 'dump MCB chain', TAB, 'DM',CR,LF
1072
db 'dump partitions', TAB, 'DP physical_disk',CR,LF
1074
db 'dump page table', TAB, 'DP [linear_address]',CR,LF
1077
db 'dump TSS', TAB, 'DT [port count]',CR,LF
1080
db 'dump ext memory', TAB, 'DX [physical_address]',CR,LF
1082
db 'enter', TAB, TAB, 'E address [list]',CR,LF
1083
db 'fill', TAB, TAB, 'F range list',CR,LF
1084
db 'go', TAB, TAB, 'G [=address] [breakpts]',CR,LF
1085
db 'hex add/sub', TAB, 'H value1 value2',CR,LF
1086
db 'input', TAB, TAB, 'I[W|D] port',CR,LF
1088
db 'load program', TAB, 'L [address]',CR,LF
1091
db 'load sectors', TAB, 'L address disk sector count',CR,LF
1093
db 'load sectors', TAB, 'L address drive sector count',CR,LF
1095
db 'move', TAB, TAB, 'M range address',CR,LF
1096
db '80x86 mode', TAB, 'M [x] (x=0..6)',CR,LF
1097
db 'set FPU mode', TAB, 'MC [2|N] (2=287,N=no FPU)',CR,LF
1098
if LCMDFILE or WCMDFILE
1099
db 'set name', TAB, 'N [[drive:][path]progname [arglist]]',CR,LF
1101
db 'output', TAB, TAB, 'O[W|D] port value',CR,LF
1102
db 'proceed', TAB, TAB, 'P [=address] [count]',CR,LF
1104
db 'quit', TAB, TAB, 'Q',CR,LF
1106
db 'forced pm quit', TAB, 'QQ',CR,LF
1109
db 'register', TAB, 'R [register [value]]',CR,LF
1114
db 'MMX register', TAB, 'RM',CR,LF
1116
db 'FPU register', TAB, 'RN',CR,LF
1117
db 'toggle 386 regs', TAB, 'RX',CR,LF
1118
db 'search', TAB, TAB, 'S range list',CR,LF
1123
db 'skip exception', TAB, 'SK',CR,LF
1125
db 'trace', TAB, TAB, 'T [=address] [count]',CR,LF
1126
db 'trace mode', TAB, 'TM [0|1]',CR,LF
1127
db 'unassemble', TAB, 'U [range]',CR,LF
1129
db 'view screen', TAB, 'V',CR,LF
1132
db 'clr/trap vector', TAB, 'V[C|T] vector',CR,LF
1133
db 'list vectors', TAB, 'VL',CR,LF
1136
db 'write program', TAB, 'W [address]',CR,LF
1139
db 'write sectors', TAB, 'W address drive sector count',CR,LF
1142
db 'expanded mem', TAB, 'XA/XD/XM/XR/XS,X? for help'
1146
db "prompts: '-' = real/v86-mode; '#' = protected-mode"
1149
size_helpmsg2 equ $ - helpmsg2
1154
errcarat db '^ Error'
1156
ife (BOOTDBG or RING0)
1157
dskerr0 db 'Write protect error',0
1158
dskerr1 db 'Unknown unit error',0
1159
dskerr2 db 'Drive not ready',0
1160
dskerr3 db 'Unknown command',0
1161
dskerr4 db 'Data error (CRC)',0
1162
dskerr6 db 'Seek error',0
1163
dskerr7 db 'Unknown media type',0
1164
dskerr8 db 'Sector not found',0
1165
dskerr9 db 'Unknown error',0
1166
dskerra db 'Write fault',0
1167
dskerrb db 'Read fault',0
1168
dskerrc db 'General failure',0
1170
dskerrs db dskerr0-dskerr0,dskerr1-dskerr0
1171
db dskerr2-dskerr0,dskerr3-dskerr0
1172
db dskerr4-dskerr0,dskerr9-dskerr0
1173
db dskerr6-dskerr0,dskerr7-dskerr0
1174
db dskerr8-dskerr0,dskerr9-dskerr0
1175
db dskerra-dskerr0,dskerrb-dskerr0
1178
dskerr1 db "Invalid disk",CR,LF,'$'
1179
dskerrb db "Read fault",CR,LF,'$'
1180
szNoHD db "Not a HD",CR,LF,'$'
1184
szDrive db ' ____ing drive '
1185
driveno db 0,0 ;drive# for L/W cmds
1188
msg8088 db '8086/88',0
1190
no_copr db ' without coprocessor',0
1191
has_copr db ' with coprocessor',0
1192
has_287 db ' with 287',0
1193
regs386 db '386 regs o',0
1194
tmodes db 'trace mode is '
1195
tmodes2 db '? - INTs are ',0
1197
tmode0 db 'processed',0
1198
unused db ' (unused)',0
1200
needsmsg db '[needs x86]' ;<--- modified (7 and 9)
1201
needsmath db '[needs math coprocessor]'
1202
obsolete db '[obsolete]'
1204
;--- exception 00-0E, Int 22h & SysReq messages
1206
int0msg db 'Divide error',CR,LF,'$'
1207
int1msg db 'Unexpected single-step interrupt',CR,LF,'$'
1208
int3msg db 'Unexpected breakpoint interrupt',CR,LF,'$'
1209
if CATCHINT06 or CATCHEXC06
1210
exc06msg db 'Invalid opcode fault',CR,LF,'$'
1212
if CATCHINT07 or CATCHEXC07
1213
exc07msg db 'Coprocessor not present',CR,LF,'$'
1215
if CATCHINT0C or CATCHEXC0C
1216
exc0Cmsg db 'Stack fault',CR,LF,'$'
1219
exc0Dmsg db 'General protection fault',CR,LF,'$'
1223
exc0Emsg db 'Page fault, CR2='
1224
exc0Ecr2 db '________',CR,LF,'$'
1226
exc0Emsg db 'Page fault.',CR,LF,'$'
1230
progtrm db CR,LF,'Program terminated normally ('
1231
progexit db '____)',CR,LF,'$'
1234
sysrqmsg db 'SysRq detected',CR,LF,'$'
1237
EXC00MSG equ offset int0msg - offset int0msg
1238
EXC01MSG equ offset int1msg - offset int0msg
1239
EXC03MSG equ offset int3msg - offset int0msg
1240
if CATCHINT06 or CATCHEXC06
1241
EXC06MSG equ offset exc06msg - offset int0msg
1243
if CATCHINT07 or CATCHEXC07
1244
EXC07MSG equ offset exc07msg - offset int0msg
1246
if CATCHINT0C or CATCHEXC0C
1247
EXC0CMSG equ offset exc0Cmsg - offset int0msg
1250
EXC0DMSG equ offset exc0Dmsg - offset int0msg
1253
EXC0EMSG equ offset exc0Emsg - offset int0msg
1256
INT22MSG equ offset progtrm - offset int0msg
1259
SYSRQMSG equ offset sysrqmsg - offset int0msg
1266
nodosext db 'Command not supported in protected-mode without a DOS-Extender',CR,LF,'$'
1267
nopmsupp db 'Command not supported in protected-mode',CR,LF,'$'
1269
dpmihook db 'DPMI entry hooked, new entry=',0
1271
nodesc db 'not accessible in real-mode',0
1272
gatewrong db 'gate not accessible',0
1275
segerr db "Debuggee segments invalid",CR,LF,'$'
1276
fpuemerr db "CR0.EM=1, won't run FPU opcodes",CR,LF,'$'
1278
plerr db "can't quit protected-mode",CR,LF,'$'
1281
cantwritebp db "Can't write breakpoint",CR,LF,'$'
1284
nowhexe db 'EXE and HEX files cannot be written',CR,LF,'$'
1285
nownull db 'Cannot write: no file name given',CR,LF,'$'
1286
wwmsg1 db 'Writing $'
1287
wwmsg2 db ' bytes',CR,LF,'$'
1288
diskful db 'Disk full',CR,LF,'$'
1290
if LCMDFILE or WCMDFILE
1292
openerr1 db '____ opening file',CR,LF,'$'
1293
doserr2 db 'File not found',CR,LF,'$'
1294
doserr3 db 'Path not found',CR,LF,'$'
1295
doserr5 db 'Access denied',CR,LF,'$'
1296
doserr8 db 'Insufficient memory',CR,LF,'$'
1301
;--- EMS error strings
1303
;emmname db 'EMMXXXX0'
1304
emsnot db 'EMS not installed',0
1305
emserr1 db 'EMS internal error',0
1306
emserr3 db 'Handle not found',0
1307
emserr5 db 'No free handles',0
1308
emserr7 db 'Total pages exceeded',0
1309
emserr8 db 'Free pages exceeded',0
1310
emserr9 db 'Parameter error',0
1311
emserra db 'Logical page out of range',0
1312
emserrb db 'Physical page out of range',0
1313
emserrx db 'EMS error '
1316
emserrs dw emserr1,emserr1,0,emserr3,0,emserr5,0,emserr7,emserr8,emserr9
1319
xhelpmsg db 'Expanded memory (EMS) commands:',CR,LF
1320
db ' Allocate', TAB, 'XA count',CR,LF
1321
db ' Deallocate', TAB, 'XD handle',CR,LF
1322
db ' Map memory', TAB, 'XM logical-page physical-page handle',CR,LF
1323
db ' Reallocate', TAB, 'XR handle count',CR,LF
1324
db ' Show status', TAB, 'XS',CR,LF
1325
size_xhelpmsg equ $ - xhelpmsg
1327
;--- strings used by XA, XD, XR and XM commands
1329
xaans db 'Handle created: ',0
1330
xdans db 'Handle deallocated: ',0
1331
xrans db 'Handle reallocated',0
1332
xmans db 'Logical page '
1333
xmans_pos1 equ $ - xmans
1334
db '____ mapped to physical page '
1335
xmans_pos2 equ $ - xmans
1338
;--- strings used by XS command
1341
xsstr1a db '____ has '
1342
xsstr1b db '____ pages allocated',CR,LF
1343
size_xsstr1 equ $ - xsstr1
1345
xsstr2 db 'phys. page '
1346
xsstr2a db '__ = segment '
1348
size_xsstr2 equ $ - xsstr2
1350
xsstr3 db ' of a total ',0
1354
xsstr3b db 'es have been allocated',0
1356
xsnopgs db 'no mappable pages',CR,LF,CR,LF,'$'
1366
;--- get ring0 SS:ESP
1370
mov eax, cs:[regs.r0Esp]
1371
mov dx, cs:[regs.r0SS]
1374
and al, 0F0h ; aligned to 16-byte
1376
;--- it's important to generally subtract 10 dwords, regs.rFL will be modified by "skip" and cannot be used
1377
sub eax, 10*4 ; adjust ESP ( ERRC, EIP, CS, EFL, ESP, SS, ES, DS, FS, GS )
1379
sub eax, 6*4 ; adjust ESP ( ERRC, EIP, CS, EFL, ESP, SS )
1385
;--- save/restore GDT descriptor of scratch selector
1386
;--- al=1 -> save, al=0 -> restore
1399
movzx esi, [scratchsel]
1403
mov di, offset sdescsave
1430
simrealmodeint proto stdcall :word, :word
1435
;dpmientry dd 0 ;dpmi entry point returned by dpmi host
1436
dpmiwatch dd 0 ;address of dpmi initial switch to protected mode
1437
dssel dw 0 ;debugger's segment DATA
1438
cssel dw 0 ;debugger's segment CODE - also used as flag if initial switch has occured!
1439
dpmi_rm2pm dd 0 ;raw mode switch real-mode to protected-mode
1440
dpmi_pm2rm df 0 ;raw mode switch protected-mode to real-mode
1441
dpmi_size dw 0 ;size of raw mode save state buffer
1442
dpmi_rmsav dd 0 ;raw mode save state real-mode
1443
dpmi_pmsav df 0 ;raw mode save state protected-mode
1444
wOfsSize dw 0 ;size offset (2 or 4) for far16/far32
1445
dpmi32 db 0 ;bit 0: 0=16-bit client, 1=32-bit client
1446
bNoHook2F db 0 ;1=int 2F, ax=1687h cannot be hooked (win3x/9x dos box, DosEmu?)
1448
;--- pmints and pmvectors must match!
1449
pmvectors label fword ; vectors must be consecutive and in this order!
1470
dpmidisable: ;set [IP+1]=0 if hook 2F is to be disabled
1478
mov word ptr cs:[dpmientry+0],di
1479
mov word ptr cs:[dpmientry+2],es
1480
mov di,offset mydpmientry
1486
;--- this code is called
1487
;--- 1. if int 2f, ax=1687h has been hooked ( winnt, hdpmi, ... )
1488
;--- the debuggee will then call this proc directly to switch to protected-mode
1489
;--- 2. if int 2f, ax=1687h has NOT been hooked ( win3x, win9x, dosemu )
1490
;--- the debugger has to detect ( inside trace cmd ) that the dpmi entry
1491
;--- address has been reached.
1494
; call cs:[dpmientry] ;call the REAL dpmi entry
1495
db 9ah ; opcode call ssss:oooo
1504
pmints label byte ;pmints and pmvectors must match!
1517
LPMINTS equ ($ - offset pmints) / 3
1528
NUMSEGS equ ($-convsegs)/2
1531
exctab label byte ; DPMI exception table
1551
dbeexc0d0e label word ; saved debuggee's exc 0d/0e when debugger is entered
1555
;--- client entered protected mode.
1556
;--- inp: [sp+4] = client real-mode CS
1560
_ds dw ? ; client's DS ( selector )
1561
dw 8 dup (?) ; pusha
1562
;_ret dw ? ; return addr initdpmi()
1563
_ip dw ? ; client's IP
1564
_cs dw ? ; client's CS
1572
mov ax,000Ah ;get a data descriptor for DEBUG's segment
1576
@dprintf "initdpmi: client entered pm"
1581
cmp [machine],3 ; is at least a 80386?
1597
mov byte ptr [wOfsSize], ah
1599
mov [patchint21pm], cl
1602
mov [patchint31pm], cl
1605
mov [patchint41pm], cl
1607
mov [patchiretpm], cl
1608
mov [patchfarretpm], cl
1609
mov [patchfarretpmval], ah
1610
mov [patchrmswitch], cl
1611
mov [patchsrstate], cl
1613
mov cx,2 ;alloc 2 descriptors
1621
mov [scratchsel],ax ;the first is used as scratch descriptor
1622
xchg bx,ax ; mov bx, ax
1624
cmp [machine], 3 ; is at least a 80386?
1626
; test [dpmi32], 1 ; 32-bit client?
1628
dec cx ; then limit=ffffffff
1633
add bx,8 ;the second selector is client's CS
1634
xor cx,cx ;this limit is FFFF even for 32-bits
1637
mov dx,[bp].INSTFRM._cs ; get client's CS
1638
call setrmaddr ; set base
1641
shr cx,8 ; CS remains 16-bit
1644
mov [bp].INSTFRM._cs,bx ; set client's CS
1653
;--- v2.0: (re)init default for d cmd
1654
mov ax, [bp].INSTFRM._ds
1656
mov [bFlagsPM], 0 ; reset all pm flags
1659
mov bx,word ptr [pInDOS+2]
1664
mov bx,word ptr [pSDA+2]
1670
if 0 ; v2.0: removed, default for a/d cmds see above
1671
mov si,offset convsegs
1684
sizeprf ; push edi - save hiword(edi)
1687
mov bp,[wOfsSize] ; get offset size for far16/far32
1688
mov ax,0305h ; get raw-mode save state addresses
1690
mov word ptr [dpmi_rmsav+0],cx
1691
mov word ptr [dpmi_rmsav+2],bx
1692
sizeprf ; mov dword ptr [dpmi_pmsav],edi
1693
mov word ptr [dpmi_pmsav],di
1694
mov word ptr ds:[bp+dpmi_pmsav],si
1695
mov word ptr [dpmi_size],ax
1696
mov ax,0306h ; get raw-mode switch addresses
1698
mov word ptr [dpmi_rm2pm+0],cx
1699
mov word ptr [dpmi_rm2pm+2],bx
1700
sizeprf ; mov dword ptr [dpmi_pm2rm],edi
1701
mov word ptr [dpmi_pm2rm],di
1702
mov word ptr ds:[bp+dpmi_pm2rm],si
1704
sizeprf ; pop edi - restore hiword(edi)
1707
;--- hook exceptions 0,1,3,6,(7),(C),D,E
1710
mov si,offset exctab
1711
sizeprf ; push edx - save hiword(edx)
1713
sizeprf ; xor edx,edx
1723
cmp si,offset endexctab
1726
;--- hook DPMI protected-mode interrupts
1729
mov si, offset pmvectors
1730
mov di, offset pmints
1737
sizeprf ;mov [si], edx
1740
sizeprf ;xor edx, edx
1746
add si, sizeof fword
1752
sizeprf ; pop edx - restore hiword(edx)
1755
mov bl,2Fh ;get int 2Fh real-mode vector
1758
cmp cx,[wDgroup] ;did we hook it and are the last in chain?
1760
mov dx,word ptr [oldi2f+0]
1762
xchg cx,word ptr [oldi2f+2] ;then unhook
1773
;--- v2.0: set/reset debugger's exception vectors for 0D/0E. Since the
1774
;--- debugger very easily causes those exceptions, and the debuggee might
1775
;--- have set the vectors to its own routines, it's a must to restore them
1776
;--- to debugger code while the debugger is active.
1778
;--- setdbeexc0d0e: set debuggee's exception 0d/0e when running it
1783
mov si, offset dbeexc0d0e
1788
sizeprf ; mov edx, eax
1803
;--- set debugger's exception 0d/0e when reentering it
1804
;--- for int 31h, ax=203h, flag [bInDbg] must be 1 if CATCHINT31 is active.
1809
mov di, offset dbeexc0d0e
1810
mov si, offset exc0d
1821
sizeprf ; movzx edx, si
1841
patchint21pm db 66h ; jmp fword ptr cs:[oldint21]
1854
cmp cs:[bInDbg],0; v2.0 do nothing if debugger is active
1856
cmp ax,0203h ; set exception vector?
1858
cmp ax,0212h ; v2.0: set exception vector v1.0?
1861
patchint31pm db 66h ; jmp fword ptr cs:[oldint31]
1881
patchiretpm db 66h ; iretd
1889
patchfarretpmval equ byte ptr ($ - 2)
1918
; intr22dbg - INT 22 (Program terminate) interrupt handler.
1919
; This is for DEBUG itself: it's a catch-all for the various INT 23
1920
; and INT 24 calls that may occur unpredictably at any time.
1921
; What we do is pretend to be a command interpreter (which we are,
1922
; in a sense, just a different sort of command) by setting the PSP of
1923
; our parent equal to our own PSP so that DOS does not free our memory
1924
; when we quit. Therefore control ends up here when Control-Break or
1925
; an Abort in Abort/Retry/Fail is selected.
1928
cld ;reestablish things
1935
mov ds, cs:[wDgroup]
1941
;--- fall through to cmdloop!
1943
;--- Begin main command loop.
1947
mov esp,[top_sp] ;restore stack (this must be first)
1949
mov sp,[top_sp] ;restore stack (this must be first)
1951
mov [errret],offset cmdloop
1962
call isdebuggeeloaded
1964
call createdummytask ;if no task is active, create a dummy one
1969
mov dx,offset prompt1
1971
if ?DPMI or ( RING0 and V86M )
1972
mov dx,offset prompt1
1973
call ispm_dbe ; debuggee in rm/pm?
1976
mov dx,offset prompt3
1979
ife (BOOTDBG or RING0)
1985
mov [vpage], bh ;ensure [vpage] is initialized if InDos is set
1987
dec dx ;if inside DOS, display a '!' before the real prompt
1991
call getline ;prompted input
1999
je cmdloop ;if comment
2001
je printhelp ;if request for help
2005
ja errorj1 ;if not recognized
2011
mov [lastcmd],offset dmycmd
2012
mov ah,[si-2] ; v2.0: for easily detecting 2-byte cmds
2015
sizeprfX ;clear ecx - needed for cmds that call getrange
2017
mov di,offset line_out
2019
jmp cmdloop ;back to the top
2031
mov dx,offset helpmsg
2032
mov cx,offset helpmsg2 - offset helpmsg
2035
mov dx,offset helpmsg2
2036
mov cx,size_helpmsg2
2042
test [fStdin], AT_DEVICE ;stdin a file?
2044
test [fStdout], AT_DEVICE ;stdout a file?
2049
mov ax,40h ;0040h is a bimodal segment/selector
2051
cmp byte ptr ds:[84h],30 ;rows >= 30?
2054
cmp byte ptr ds:[484h], 30
2058
mov dx,offset presskey
2059
mov cx,sizeof presskey
2063
mov ah,0 ;v1.27: use BIOS
2099
;--- called by c_cmd, e_cmd, f_cmd, m_cmd, s_cmd
2106
;--- C command - compare bytes.
2109
call parsecm ;parse arguments (sets DS:e/si, ES:e/di, e/cx)
2110
;--- note: DS unknown here
2117
cc1: ;<--- continue compare
2122
call dohack ;set debuggee's int 23/24
2128
db 67h ;repe cmpsb ds:[esi],es:[edi]
2133
;--- v2.0: "mov dl,[si-1]" and "mov dl,[esi-1]" differ not just in the prefix!
2134
;--- mov dl, [si-1]: 8A 54 FF
2135
;--- mov dl,[esi-1]: 67 8A 56 FF
2147
mov dl,[si-1] ;save the possibly errant characters
2154
call unhack ;set debugger's int 23/24
2159
jmp cc2 ;if we're done
2164
;--- set ES to dgroup ( needed for output routines )
2166
sizeprfX ;mov ebx,edi
2167
mov bx,di ;save [E]DI
2168
mov di,offset line_out
2174
mov bp,offset hexword
2177
sizeprf ;mov eax, esi
2183
mov bp,offset hexdword
2208
sizeprf ;mov eax, ebx
2219
;--- set DS to dgroup
2234
jmp cc1 ;if not done yet
2252
szMappedCr3 db ", mapped at ",0
2255
mov si, offset szCr3
2260
and si, 0F000h ;esi=physical address
2261
mov cx, 4 ; cx=size in bytes
2262
mov ax, 2 ; return linear address (in esi) of physical region
2264
;--- callout int 22h requires to set the host ring0 stack!
2269
int 22h ; win396 debugger interface
2276
mov si, offset szCr3
2286
;--- DP disk - display partition table of a fixed disk
2288
call getbyte ;get byte into DL
2289
call chkeol ;expect end of line here
2292
mov dx, offset szNoHD
2296
mov word ptr packet.secno+0, 0
2297
mov word ptr packet.secno+2, 0
2298
mov packet.numsecs, 1
2299
mov packet.dstofs, sp
2300
mov packet.dstseg, ds
2303
add sp, 1BEh ; offset PT
2308
mov di, offset line_out
2312
mov al, [si+4] ; partition type
2316
mov ax, [si+10] ; hiword start LBA
2318
mov ax, [si+8] ; loword start LBA
2322
mov ax, [si+14] ; hiword size LBA
2324
mov ax, [si+12] ; loword size LBA
2342
;--- get base of descriptor table for selector in BX
2343
;--- out: NC, eax=base, dx=limit
2345
;--- other registers preserved
2360
; mov eax, [bp-4] ; get linear address GDT
2361
@dprintf "getlinearbaseDT: bx=%X", bx
2368
@dprintf "getlinearbaseDT: ldt=%X", bx
2369
call getlinearbaseBX
2370
@dprintf "getlinearbaseDT: eax=%lX", eax
2384
;--- get linear base of descriptor in BX
2385
;--- in: BX=selector, EAX=base of descriptor table
2386
;--- out: EAX=base of descriptor, DX=limit of descriptor
2391
add eax, edx ; now eax -> GDT/LDT descriptor
2399
xchg eax, edx ; base to eax, limit to dx
2419
descbase db ' base=???????? limit=???????? attr=????',0
2425
call getword ;get word into DX
2445
mov si, dx ;save count
2452
call getlinearbaseDT ; get linear base & limit of descriptor table for BX
2456
pushf ; save error flag of getlinearbase
2460
mov si, offset szldtr
2466
mov si, offset szgdtr
2496
mov si,offset nodesc ; error "not accessible in real-mode"
2502
mov di,offset line_out
2507
mov si,offset descbase
2512
; jnz skipdesc ;tell that this descriptor is invalid
2520
cmp bx, [ebp-6] ;beyond limit?
2522
cmp bx, [bp-6] ;beyond limit?
2545
add di, 6 ; render base
2551
sizeprf ;lsl eax,ebx
2554
sizeprf ;lar edx,ebx
2558
mov di,offset line_out+25
2561
call hexdword; limit 32-bit
2564
call hexword; limit 16-bit
2569
mov di,offset line_out+25+14
2573
mov di,offset line_out+25+14+4 ; position to end of line
2574
call putsline ; add cr/lf, then print
2612
call getbyte ;get byte into DL
2618
call getword ;get word into DL ( max is 100h )
2622
inc dx ;ensure that count is at least 1
2624
mov si,dx ;save count
2628
mov si, offset szidtr
2631
mov ax,word ptr [real_end-6]
2636
mov eax,dword ptr [real_end-4]
2641
gateout_00: ;<--- next int/exc
2642
mov di,offset line_out
2688
cmp bx, word ptr [real_end-6]
2690
add ebx, dword ptr [real_end-4]
2693
mov ax, [ebx].GATE.wSeg
2697
mov ax, [ebx].GATE.wOfsHi
2699
mov ax, [ebx].GATE.wOfsLo
2703
mov ax, [ebx].GATE.wAttr
2733
mov di,offset line_out
2734
mov si,offset gatewrong
2740
call dohack ;set debuggee's int 23/24
2751
call unhack ;set debugger's int 23/24
2766
;--- dm cmd: display list of MCBs
2770
; mov di,offset line_out
2777
call putsline ;destroys cx,dx,bx
2782
mov di,offset line_out
2785
call hexword ;segment address of MCB
2788
mov al,ds:[0000];'M' or 'Z'
2797
mov ax,ds:[0001];MCB owner
2802
mov ax,ds:[0003];MCB size in paragraphs
2813
cmp bx,si ;is it a "system" MCB?
2816
call setds2bx ;destroys cx if in pm
2818
nextmcbchar: ;copy "name" of owner MCB
2831
call putsline ;destroys cx,dx,bx
2860
dwLink dd ? ;+00 selector
2912
szPL0Stk db " RSP0=",0
2914
szPL0Stk db " R0 SS:ESP=",0
2917
szTrapped db "trapped ports:",13,10,'$'
2925
call getword ;get word into DX
2930
call getword ;get word into DX
2945
call getlinearbaseDT ;TSS is always in GDT
2947
call getlinearbaseBX ;ret: eax=linear addr, dx=limit
2948
@dprintf "dt: bx=%X eax=%lX, limit=%X", bx, eax, dx
2951
mov si, offset szPL0Stk
2957
mov eax, dword ptr [ebx].TSS._Rsp0+4
2959
mov eax, dword ptr [ebx].TSS._Rsp0+0
2962
mov ax, word ptr [ebx].TSS._SS0
2966
mov eax, [ebx].TSS._Esp0
2970
;--- display trapped ports;
2972
;--- check if TSS does indeed include an IO permission bitmap.
2974
;--- BP=port to start with
2975
;--- SI=number of ports to check
2981
add ax, [ebx].TSS.wOffs
2985
movzx eax, [ebx].TSS.wOffs
2990
mov si, offset szIOPB
2998
@dprintf "dt_cmd: start port=%X cnt=%X", bp, si
3000
mov di, offset line_out
3001
mov dx, offset szTrapped
3012
@dprintf "dt_cmd: found trapped port=%X", bp
3023
mov di, offset line_out
3034
;--- DX command. Display extended memory
3035
;--- works for 80386+ only.
3043
dw -1,0,9200h,0CFh ; 32-bit flat data descriptor
3044
dw -1,0,9200h,0 ; 16-bit data descriptor
3053
;--- set/reset unreal mode
3059
add eax,offset gdt-8
3060
mov dword ptr cs:[GDTR+2],eax
3081
push ax ; check for IRQ. If request, jmp to previous handler
3085
test al, 20h ; real IRQ 5?
3108
mov dx,word ptr [x_addr+0]
3109
mov bx,word ptr [x_addr+2]
3112
call getdword ;get linear address into bx:dx
3113
call chkeol ;expect end of line here
3115
mov [lastcmd],offset dx_cmd
3121
;--- the dx cmd, when using int 15h,ah=87, has the
3122
;--- side effect that unreal-mode most likely is disabled
3123
;--- after the call. Setting USEUNREAL=1 avoids that,
3124
;--- but has the disadvantange that DX won't work in v86-mode!
3126
smsw ax ; don't use ispm, since that won't detect v86!
3136
mov cs:[oldint0d], ebx
3141
mov edi,offset line_out+128
3142
rep movsd es:[edi], ds:[esi]
3144
dec al ;has an exception occured?
3145
jz @F ;if no, don't reset unreal mode!
3151
; mov di,offset line_out ;create a GDT for Int 15h, ah=87h
3153
mov cx,6*4 ;init 6 descriptors (48 bytes)
3156
mov ax,007Fh;limit of source (128 bytes)
3158
mov ax,dx ;base[0-15] of source
3160
mov al,bl ;base[16-23] of source
3164
mov al,bh ;base[24-31] of source
3166
mov ax,007Fh;limit of dest
3168
lea eax,[line_out+128]
3172
stosw ;base[0-15] of dest
3174
stosb ;base[16-23] of dest
3179
stosb ;base[24-31] of dest
3180
mov si,offset line_out ;ds:si -> GDT
3181
mov cx,0040h ;number of words to copy
3186
invoke simrealmodeint, 15h, cs:[wDgroup]
3194
mov si,offset line_out+128
3197
mov di,offset line_out
3218
mov byte ptr [di-(8*3+1)],'-' ;display a '-' after 8 bytes
3236
test byte ptr[regs.rFL+2],2
3238
cmp ax, [scratchsel]
3240
mov ax, [scratchv86]
3246
;--- D command - hex/ascii dump.
3250
jne dd1 ; if an argument was given
3251
sizeprfX ; mov edx,[d_addr]
3257
@movs bx, [regs.rDS]
3261
sizeprfX ; mov esi,edx
3264
;--- ?PM: we don't know yet if limit is > 64kB
3265
;--- so we stop at 64 kB in any case
3267
add dx,80h-1; compute range of 80h or until end of segment
3273
pDispOfs dw ? ; display offset 16/32
3274
pGetB dw ? ; get # of bytes to print in cx
3275
pLoad dw ? ; load a byte
3276
pEnd dw ? ; check if dump is done
3280
dd16 DMPJT < hexword, getb16, load16, end16>
3282
dd32 DMPJT <hexdword, getb32, load32, end32>
3286
ife DGCMD+DICMD+DLCMD+DPCMD+DTCMD+DXCMD ; if just the DM cmd exists (std debug)
3289
cmp ah,'d' ; char 'd' just before g/i/l/m/p/t/x?
3299
@condcmd macro ifcond, byt_,ofs_
3308
@condcmd DGCMD,'g',dgl_cmd
3309
@condcmd DICMD,'i',di_cmd
3310
@condcmd DLCMD,'l',dgl_cmd
3311
@condcmd DMCMD,'m',dm_cmd
3312
@condcmd DPCMD or DPCMDR0,'p',dp_cmd
3313
@condcmd DTCMD,'t',dt_cmd
3314
@condcmd DXCMD,'x',dx_cmd
3315
size_dcmds equ ($ - offset dcmds) / 3
3323
cmp ah,'d' ; char 'd' just before g/i/l/m/p/t/x?
3326
mov bx, offset dcmds
3342
mov cx,80h ;default length
3343
call getrangeDS ;get address range into bx:(e)dx ... bx:(e)cx
3344
call chkeol ;expect end of line here
3346
sizeprfX ; mov esi,edx
3348
sizeprfX ; mov edx,ecx (14.2.2021)
3349
mov dx,cx ; dx = end address
3351
;--- Parsing is done. Print lines.
3352
;--- BX=segment/selector
3353
;--- E/SI=src offset, E/DX=end src
3356
mov [d_addr+4], bx ;save segment/selector (offset is saved later)
3357
mov [lastcmd], offset d_cmd
3360
call getseglimit ;Z flag set if segment limit is <= 64 kB
3365
@dprintf "d: bx:esi=%X:%lX edx=%lx", bx, esi, edx
3366
call prephack ;set up for faking int vectors 23 and 24
3369
mov di,offset line_out
3370
@dispsegm [d_addr+4]
3373
sizeprfX ; mov eax, esi
3378
call DMPPFX[bp].DMPJT.pDispOfs
3391
mov byte ptr [di+3*8-1],'-'
3396
call DMPPFX[bp].DMPJT.pGetB
3398
call dohack ;set debuggee's int 23/24
3401
call DMPPFX[bp].DMPJT.pLoad
3407
jb dd7 ;if control character
3409
jbe dd8 ;if printable
3420
call unhack ;set debugger's int 23/24
3425
call DMPPFX[bp].DMPJT.pEnd
3427
sizeprfX ;mov [d_addr],esi
3441
cmp cx,dx ;compare with end address
3442
jb @F ;if we write to the end of the line
3446
inc cx ;cx = number of bytes to print this line
3479
test byte ptr [regs.rFL+2], 2 ; v86-mode
3483
;--- either use scratch selector or flat selector
3484
;--- both variants have their pros and cons.
3485
;--- still to decide...
3492
wSegm dw ? ;src/dst register
3496
movzx edx, [esp].V86OFSFR.wSegm
3500
mov [esp].V86OFSFR.wSegm, dx
3508
wSegm dw ? ;src/dst register
3513
mov dx, [esp].V86OFSFR.wSegm
3515
mov [esp].V86OFSFR.wSegm, bx
3526
;--- E command - edit memory.
3531
call getaddr ;get address into bx:(e)dx
3534
je ee1 ;if prompt mode
3535
push dx ;save destination offset
3536
call getstr ;get data bytes SI -> line_out
3538
mov dx,offset line_out
3539
sub cx,dx ;length of byte string
3544
call IsOfs32 ;v1.29: if limit is > 64kB, skip test
3548
jc errorj4 ;if it wraps around
3550
call dohack ;set debuggee's int 23/24
3560
mov dx,di ;dx was destroyed
3564
db 67h ;rep movsb [edi], [esi]
3570
;--- Restore ds + es and undo the interrupt vector hack.
3571
;--- This code is also used by the 'm' command.
3578
;--- store2324 is called after debuggee memory has been written (just e cmd)
3579
mov di,offset run2324 ;debuggee's int 23/24 values
3580
call store2324 ;copy IVT 23/24 to di ( real-mode only )
3581
call unhack ;set debugger's int 23/24
3585
;--- Prompt mode. BX:E/DX=addr, DI=line_out
3588
@dprintf "e: bx:edx=%X:%lX", bx, edx
3590
mov [bufnext], si ; update buffer ptr in case stdin is file
3592
mov bp,offset hexword
3596
mov bp,offset hexdword
3600
;--- Begin loop over lines.
3602
e_nextl: ;<--- next line
3603
@dispsegm bx ;print out segment part
3606
sizeprfX ;mov eax,edx
3610
;--- Begin loop over bytes.
3612
e_nextb: ;<--- next byte
3617
call dohack ;set debuggee's int 23/24
3618
call readmem ;read byte at BX:(E)DX
3619
call unhack ;set debugger's int 23/24
3620
call hexbyte ;print old value of byte
3626
mov si,offset line_out+16 ;address of buffer for characters
3627
xor cx,cx ;number of characters so far
3629
;--- get a byte (2 chars)
3630
;--- this is a simple "editor" that allows max 2 chars as input:
3632
;--- + control chars SPACE, CR, BS, '-'
3634
e_nextc: ;<--- get next char
3636
test [fStdin], AT_DEVICE
3637
jnz ee9 ;jmp if it's a tty
3641
jb @F ;if there's a character already
3642
call fillbuf ;fill buffer with a new line; init SI
3646
lodsb ;get the character
3654
call InDos ;v1.27: use BIOS if InDOS
3656
mov ah,8 ;console input without echo
3657
; int 21h ;v1.29: don't use INT instruction;
3658
call doscall ;might make debuggee run if int 21h is intercepted
3673
je e_spcr ;if done with this byte
3677
je e_bs ;if backspace
3680
cmp cx,2 ;otherwise, it should be a hex character
3681
jae e_nextc ;if we have a full byte already
3684
jc e_nextc ;if it's not a hex character
3686
lodsb ;get the character back
3690
jcxz e_nextc ;if nothing to backspace over
3699
dec dx ;decrement offset part
3700
mov di,offset line_out
3702
mov ax,LF * 256 + CR;terminate this line
3704
jmp e_nextl ;back for another line
3707
call storebyte ;store byte if CX != 0
3709
inc dx ;increment offset
3710
mov di,offset line_out
3716
add cx,4 ;compute 3 - cx
3718
rep stosb ;store that many spaces
3719
jmp e_nextb ;back for more
3722
jmp putsline ;call putsline and return
3724
;--- byte has been entered (1 or 2 chars)
3727
;--- bx:e/dx: address to store byte
3731
jcxz sb_done ;if no change for this byte
3732
mov [si],al ;terminate the string
3733
sub si,cx ;point to beginning
3734
push ax ;v1.29: save/restore value of AL to avoid stop if 'D' is entered
3738
call getbyte ;convert byte to binary (DL)
3742
call dohack ;set debuggee's int 23/24
3744
push bx ;bx may be changed by writemem in pm
3746
call writemem ;write AL at BX:(E)DX
3751
mov di,offset run2324 ;debuggee's int 23/24
3752
call store2324 ;copy IVT 23/24 to di ( real-mode only )
3753
call unhack ;set debugger's int 23/24
3760
;--- F command - fill memory
3761
;--- entry: SI=line, CX=0, AL=last char
3764
call getrangeDS ;get address range into bx:(e)dx/(e)cx
3778
inc cx ;cx = number of bytes
3780
push dx ;save start address
3783
call getstr ;get string of bytes
3785
sub cx, offset line_out
3787
call IsWriteableBX ; ensure BX is writeable
3798
pop eax ; eax=size ( of mem block )
3799
; @dprintf "f_cmd: eax=%lX, ecx=%lX, es:edi=%X:%lX", eax, ecx, es, edi
3801
div ecx ; ecx=size of hex-string entered
3802
mov esi, offset line_out
3808
rep movsb es:[edi], ds:[esi]
3815
; jecxz exit ;rep with ecx=0 is a nop
3816
rep movsb es:[edi], ds:[esi]
3820
mov al,byte ptr [line_out]
3828
je onebyte16;a common optimization
3830
xor dx,dx ;now size in DX:AX
3832
adc dx,0 ;convert 0000:0000 to 0001:0000
3833
div cx ;compute number of whole repetitions
3834
mov si,offset line_out
3836
jz partial16;if less than one whole rep
3844
jnz nextcopy16 ;if more to go
3847
; jcxz exit ;rep with cx=0 is a nop
3852
mov al,byte ptr [line_out]
3853
stosb ;cx=0 -> 64 kB
3862
;--- breakpoints are stored in line_out, with this format
3865
;--- DWORD/WORD offset of bp
3866
;--- WORD segment of bp
3870
mov di,offset resetbp1
3872
mov si,offset line_out
3874
xchg cx, ax ;mov cx,ax
3879
sizeprfX ;xchg edx,eax
3880
xchg dx,ax ;mov dx,ax
3882
xchg bx,ax ;mov bx,ax
3883
call di ;call setbp1/resetbp1
3885
loop nextbp ;next bp
3890
call writemem ; write byte at bx:e/dx, C if write was unsuccessful (ROM)
3891
mov [si],ah ; save the current contents
3893
call bp ; either ignore error (g cmd) or abort with msg (p cmd)
3900
call writemem ; write byte at bx:e/dx
3908
;--- with DEBUGX: when a mode switch did occur in the debuggee,
3909
;--- the segment parts of the breakpoint addresses are no
3910
;--- longer valid in the new mode. To enable the debugger to reset the
3911
;--- breakpoints, it has to switch temporarily to the previous mode.
3912
;--- in: DX=old value of regs.msw
3917
jz resetbps ; mode didn't change, use normal reset routine
3919
cmp [run_int], INT22MSG ;skip reseting bps if debuggee terminated
3922
cmp byte ptr [line_out],0 ;any breakpoints defined?
3924
mov cx,[dpmi_size] ; don't call save state if buffer size is zero.
3925
jcxz do_switch ; this avoids a CWSDPMI bug
3927
mov al,0 ; al=0 is "save state"
3930
mov al,1 ; al=1 is "restore state"
3936
call switchmode ; switch to old mode
3938
jmp switchmode ; switch back to new mode
3942
;--- si:e/di: new cs:e/ip
3943
;--- dx:e/bx: new ss:e/sp
3946
sizeprf ;xor ebx,ebx
3947
xor bx,bx ;clears hiword EBX if cpu >= 386
3949
sizeprf ;xor edi,edi
3950
xor di,di ;clears hiword EDI if cpu >= 386
3951
mov di,back_after_switch
3954
mov ax,[dssel] ;switch rm -> pm
3960
mov ax,[wDgroup] ;switch pm -> rm
3964
patchrmswitch db 66h ;jmp fword ptr [dpmi_pm2rm]
3965
jmp dword ptr [dpmi_pm2rm]
3970
;--- save/restore task state in ES:(E)DI
3973
sizeprf ;xor edi,edi
3974
xor di,di ;clears hiword EDI if cpu >= 386
3976
add di,2 ;the save space starts at [sp+2]
3982
patchsrstate db 66h ;call fword ptr [dpmi_pmsav]
3983
call dword ptr [dpmi_pmsav]
3991
;--- problem is that [pspdbg] is always a segment value
4001
@ds_mypsp textequ <call mypsp>
4003
@ds_mypsp textequ <mov ds, [pspdbg]>
4011
call parseql ;get optional <=addr> argument; always writes [eqladdr+4]
4013
;--- Parse the rest of the line for breakpoints
4015
mov di,offset line_out
4016
xor ax,ax ; init bp cnt to 0
4024
cmp al,CR ;end of line?
4027
;--- calling getaddr was a bug in protected-mode up to v1.29.
4028
;--- ( it was a different getaddr than now, one that ensured the
4029
;--- segment part is a writeable selector in pm; with 2.0, getaddr
4030
;--- does this no longer ).
4031
;--- Anyway, multiple BPs with different segment parts all used
4032
;--- the very same "scratch" selector, resulting in "random" mem writes.
4034
@movs bx,[eqladdr+4] ;default segment ( either CS or segm of '=' )
4035
call getaddr ;get address into bx:(e)dx
4037
test byte ptr [regs.rFL+2],2
4039
cmp bx, [scratchsel]
4041
;--- if v86-mode, don't store the scratch selector in the list of BPs
4042
;--- instead, use linear addresses (and the flat selector)
4044
movzx ebx, [scratchv86]
4050
@dprintf "g_cmd: bp=%X:%lX", bx, edx
4060
mov bp, offset storebpdef
4063
@dprintf "std int3 bp, cs:eip=%X:%lX di=%X lo=%X", bx, edx, di, offset line_out
4064
sizeprfX ;xchg eax,edx
4065
xchg ax,dx ;mov ax,dx
4068
xchg ax,bx ;mov ax,bx
4070
inc di ; reserve to store byte at bp location
4071
inc byte ptr line_out ;use [line_out+0] to count bps
4082
;--- Store breakpoint bytes in the given locations.
4084
;--- v2.50: abort g as in t/p if bp can't be written
4085
; mov bp, offset _ret ; ignore write errors for g
4086
mov bp, offset bp_writeerr
4087
gg_1:: ; <--- called by p/t ( run an int/call/... - set 1 bp )
4088
mov di,offset setbp1
4089
call setbps ; may cause a GPF in protected-mode if location is read-only
4090
@dprintf "g_cmd: calling run"
4093
push [regs.msw] ;save old MSW
4095
call run ;run the program
4105
@dprintf "g_cmd: run returned, [spadjust]=%X, [spsav]=%X:%X", cs:[spadjust], word ptr ds:[PSPS.SPSAV+2], word ptr ds:[PSPS.SPSAV]
4113
mov [bCSAttr],al ; must be set for getcseipbyte()
4117
;--- this is inactive since v2.0;
4118
;--- not needed for soft/hard bp detection?
4119
;--- see comment below - no safe detection for soft BPs anymore!
4122
call getcseipbyte ;get byte at [cs:eip-1], set E/BX to E/IP-1
4126
;--- Restore breakpoint bytes.
4129
;--- if debuggee has terminated ( [run_int] == INT22MSG ),
4130
;--- nothing will be done if mode has changed ( see resetbpsEx() ).
4131
call resetbpsEx ;reset BPs ( expects DX=old msw ), may switch tmp. to previous mode
4135
@dprintf "g_cmd: resetbps done"
4137
;--- Finish up. Check if it was one of _our_ breakpoints.
4138
;--- if yes, decrement (E)IP
4140
if 0 ; v2.0: not needed for soft/hard bp detection?
4142
cmp al,0CCh ; was a CC at CS:[EIP-1]?
4151
cmp [run_int], EXC03MSG
4154
call getcseipbyte ; get byte [cs:eip-1], sets E/BX
4155
cmp al, 0CCh ; still a INT3 at [cs:eip-1] ?
4158
;--- here E/IP is decremented because DEBUG assumes an INT3 has been restored.
4159
;--- it's not always true, though - the INT3 may have been routed from protected-mode;
4160
;--- or anything else has just jumped to the vector for INT3.
4162
test [bCSAttr], CS32
4164
db 66h ;mov [regs.rIP],ebx
4166
mov [regs.rIP], bx ; decrement (E)IP
4168
mov [run_int], -1 ; v2.0: reset entry ( so SK cmd won't accept soft bps )
4171
call dumpregs ; then just display register dump
4173
ret ; and done ( no "unexpected breakpoint" msg )
4175
jmp ue_int ;print messages and quit.
4179
;--- H command - hex addition and subtraction.
4182
call getdword ;get dword in BX:DX
4187
call chkeol ;expect end of line here
4189
pop ax ;first value in AX:CX, second in BX:DX
4193
jnz hh32 ;32bit values
4209
mov bp,cx ;first value in SI:BP now
4238
;--- I command - input from I/O port.
4251
mov ah,[si-2] ;distiguish 'id' and 'i d'
4261
call getword ;get word into DX
4262
call chkeol ;expect end of line here
4288
mov si,word ptr [pSDA+0]
4291
mov ds,word ptr cs:[pSDA+2]
4295
ispm_dbe: ; debuggee in protected-mode?
4296
ispm_dbg: ; debugger in protected-mode
4297
cmp cs:[regs.msw],0 ;returns: Z=real-mode, NZ=prot-mode
4300
elseif RING0 and V86M
4301
ispm_dbe: ; return Z if debuggee in v86-mode
4303
mov ax, [regs.rFL+2]
4312
setpspdbg: ; set debugger's PSP
4319
jmp simrealmodeint21
4324
setpsp proc ; <--- entry to set debuggee's PSP
4342
call simrealmodeint21
4356
cmp word ptr [pSDA+2],0
4378
ife (BOOTDBG or RING0)
4386
call simrealmodeint21
4399
cmp word ptr [pSDA+2],0
4427
invoke simrealmodeint, 21h, cs:[wDgroup]
4438
RMCS struc ;the DPMI "real-mode call structure"
4460
;--- call DPMI simulate real-mode interrupt (0x300) function
4462
simrealmodeint proc stdcall uses es intno:word, dataseg:word
4483
sizeprf ;lea edi,rmcs
4488
mov ah,byte ptr rmcs.rFlags
4503
;--- this proc is called in pmode only
4505
;--- called by L/W cmds.
4507
isextenderavailable proc
4514
sizeprf ;lea esi, szMSDOS
4515
lea si, szMSDOS ;must be LEA, don't change to "mov si,offset szMSDOS"!
4527
szMSDOS db "MS-DOS",0
4530
isextenderavailable endp
4535
mov dx,offset nodosext
4546
;--- ensure a debuggee PSP exists;
4547
;--- set SI:DI to CS:IP, preserve AX, BX, DX
4549
ensuredebuggeeloaded proc
4551
call isdebuggeeloaded
4555
call createdummytask
4563
ensuredebuggeeloaded endp
4568
;--- abs disk read, arguments in [packet]
4571
;--- modifies all std regs except sp, bp
4573
.errnz RING0, <int 13h not yet supported>
4576
@dprintf "readsect: disk=%X", ax
4589
mov bx, offset packet
4590
@dprintf "readsect: lba access, dx=%X, secno=%lX", dx, [bx].PACKET.secno
4593
push word ptr [bx].PACKET.secno+2
4594
push word ptr [bx].PACKET.secno+0
4595
push [bx].PACKET.dstseg
4596
push [bx].PACKET.dstofs
4597
push [bx].PACKET.numsecs
4613
mov bx, offset packet
4618
@dprintf "l: chs access, dx=X, cx=%X", dx, cx
4620
mov al, byte ptr [bx].PACKET.numsecs
4622
les bx, dword ptr [bx].PACKET.dstofs
4628
mov dx, offset dskerrb
4631
mov dx, offset dskerr1
4642
mov cx, word ptr [bx].PACKET.secno+0
4643
mov ax, word ptr [bx].PACKET.secno+2
4663
;--- L command - absolute disk read.
4666
call parselw ;returns AL=drive, BX=packet
4667
jz cmd_error ;Z means max 1 arg; must be a full command
4677
;--- L command - read a program, or disk sectors, from disk.
4680
call parselw ;parse it, addr in bx:(e)dx
4682
jz ll1 ;Z if max 1 argument (read program)
4689
call isextenderavailable
4693
cmp cs:[usepacket],2
4695
mov dl,al ;A=0,B=1,C=2,...
4696
xor si,si ;read drive
4702
inc dl ;A=1,B=2,C=3,...
4703
mov ax,7305h ;DS:(E)BX -> packet
4705
int 21h ;use int 21h here, not doscall!
4710
add cl,[dpmi32] ;5/6=far16/far32 ptr
4717
mov cx,"er" ;CX:DX="read"
4723
;--- For .com or .exe files, we can only load at cs:100. Check that first.
4726
test [fileext], EXT_COM or EXT_EXE
4727
jz loadfile ;if not .com or .exe file
4729
jne l_err ;if segment is wrong
4731
je loadfile ;if address is OK (or not given)
4733
jmp cmd_error ;can only load .com or .exe at cs:100
4743
;--- load (any) file (if not .EXE or .COM, load at BX:DX)
4744
;--- open file and get length.
4745
;--- in protected-mode, this will work with a DOS extender only.
4748
mov si,bx ;save destination address, segment
4749
mov di,dx ;and offset
4750
mov ax,3d00h ;open file for reading
4755
mov dx,PSPS.DTA ;n cmd has stored file spec at DTA!
4761
jmp io_error ;print error message
4763
xchg ax,bx ;mov bx,ax
4764
mov ax,4202h ;lseek EOF
4769
; Split off file types
4773
; si:di load address (CS:100h for .EXE or .COM)
4775
test [fileext],EXT_COM or EXT_EXE
4776
jnz loadpgm ;if .com or .exe file
4779
;--- dont load a file in protected mode,
4780
;--- the read loop makes some segment register arithmetic
4783
mov dx,offset nopmsupp
4785
jmp cl_exit ; close file and exit
4789
;--- Load it ourselves.
4790
;--- For non-.com/.exe files, we just do a read, and set BX:CX to the
4791
;--- number of bytes read.
4793
call ensuredebuggeeloaded ;make sure a debuggee PSP exists
4796
;--- Check the size against available space.
4801
cmp si,es:[PSPS.ALASAP]
4805
jae ll6 ;if loading past end of mem, allow through ffff
4806
add si,es:[PSPS.ALASAP] ;si = number of paragraphs available
4815
sbb bx,cx ;bx:si = number of words left
4816
jb ll9 ;if already we're out of space
4821
jae ll10 ;if not out of space
4823
pop bx ;out of space
4825
mov dx,offset doserr8 ;not enough memory
4826
call int21ah9 ;print string
4833
;--- Store length in registers
4835
;--- seems a bit unwise to modify registers if a debuggee is running
4836
;--- but MS DEBUG does it as well
4860
add si,di ;si:dx is the address to read to
4862
;--- Begin loop over chunks to read
4865
mov ah,3fh ;read from file into DS:(E)DX
4866
mov cx,0fe00h ;read up to this many bytes
4870
add si,0fe0h ;wont work in protected-mode!
4872
je ll11 ;if end of file reached
4874
;--- Close the file and finish up.
4877
mov ah,3eh ;close file
4892
sizeprf ;pop dword ptr [regs.rFL]
4894
sizeprf ;mov dword ptr [regs.rSP],esp
4895
mov [regs.rSP],sp ;low 16bit of ESP will be overwritten
4902
;--- file is .EXE or .COM
4903
;--- bx=file handle, dx:ax=file size
4906
mov ah,3eh ;close file
4908
pop bx ;dx:bx is the file length
4912
;--- adjust .exe size by 200h (size of header? who knows )
4914
test [fileext],EXT_EXE
4921
@dprintf "loadpgm, dx:bx=%X:%X", dx, bx
4925
;--- cancel current process (unless there is none)
4926
;--- this will also put cpu back to real-mode!!!
4928
call isdebuggeeloaded
4933
@dprintf "loadpgm, init regs, ds=%X, es=%X", ds, es
4938
mov cx, sizeof regs / 2
4942
pop word ptr [regs.rBX]
4943
pop word ptr [regs.rCX]
4950
;--- Fix up interrupt vectors in PSP
4953
mov si,PSPS.CCIV ;address of original INT 23 and 24 (in PSP)
4954
mov di,offset run2324
4961
;--- Actual program loading. Use the DOS interrupt.
4963
mov dx,PSPS.DTA ;file to load in DS:SI
4964
mov bx,offset execblk ;parameter block in ES:BX
4965
mov ax,4b01h ;load program, don't execute
4971
jmp io_error ;if error
4975
;--- we calculate the stack space used by previous dos call (ax=4b01)
4976
;--- and use the result (in spadjust) to adjust the field PSP:[2Eh]
4977
;--- in the debugger's PSP whenever the debuggee is to be executed ("run").
4981
sub ax,word ptr es:[PSPS.SPSAV]
4983
sub ax,word ptr ds:[PSPS.SPSAV]
4991
;--- use the values for CS:IP SS:SP returned by the loader
4993
les si,dword ptr [execblk.sssp]
4994
lodsw es:[si] ;recover ax
4998
les si,dword ptr [execblk.csip]
5006
;--- get the debuggee's PSP and store it in debuggee's DS,ES
5009
xchg ax,bx ;mov ax,bx
5011
mov di,offset regs.rDS
5015
call setpspdbg ;switch back to debugger's PSP
5017
;--- Finish up. Set termination address.
5019
mov ax,2522h ;set interrupt vector 22
5020
mov dx,offset intr22
5023
mov word ptr es:[PSPS.TPIV+0],dx
5024
mov word ptr es:[PSPS.TPIV+2],cs
5029
;--- Set up initial addresses for a/d/u commands.
5030
;--- out: ax=regs.rCS
5033
mov di,offset a_addr
5034
mov si,offset regs.rIP
5037
movsw ; write a_addr eip
5039
stosw ; write a_addr cs
5042
rep movsw ; copy a_addr to d_addr and u_addr
5049
;--- 'm'achine command: set machine type.
5055
; je mach_query ;if just an 'm' (query machine type)
5060
ja errorj3 ;dl must be 0-6
5061
mov [machine],al ;set machine type
5062
mov [mach_87],al ;coprocessor type, too
5065
and [rmode],not RM_386REGS ;reset 386 register display
5073
;--- 'mc' command: set coprocessor.
5074
;--- optional arguments:
5075
;--- N: no coprocessor
5076
;--- 2: 80287 with 80386
5079
call skipwhite ;get next nonblank character
5089
jne @F ;if something else
5090
mov [has_87],0 ;clear coprocessor flag
5094
jne errorj3 ;if not '2'
5096
jnz errorj3 ;if not a 386
5099
mov [has_87],1 ;set coprocessor flag
5104
;--- M command - move/copy memory.
5105
;--- 1. check if there's no argument at all: mach_query, display cpu
5106
;--- 2. check for MC cmd: mc_cmd, set/reset coprocessor
5107
;--- 3. check if there's just 1 argument: mach, set cpu
5113
or ax,TOLOWER or (TOLOWER shl 8)
5114
cmp ax,'mc' ; mc cmd?
5117
cmp al,'0' ; is there a '$' or '%' modifier?
5118
jb ismove ; ( would throw an error in getdword )
5128
je mach ; jump if 1 argument only
5132
call parsecm ;parse arguments: src=DS:(E)SI, dst=ES:(E)DI, length-1=(E)CX
5133
;--- note: DS unknown here
5141
;--- TODO: do overlapping check in protected-mode
5143
@dprintf "m_cmd: ds:esi=%X:%lX, es:edi=%X:%lX, ecx=%lX", ds, esi, es, edi, ecx
5149
shr dx,cl ; BX:DX=dst seg:ofs
5150
add dx,bx ;upper 16 bits of destination
5156
jne m3 ;if we know which is larger
5167
push ss ;ds = dgroup
5169
call dohack ;set debuggee's int 23/24
5173
;--- v2.0: ensure ES is writeable ( parsecm does that no longer )
5181
call IsWriteableBX ; expects DS(,ES)=dgroup
5193
rep movsb es:[edi], ds:[esi]
5194
movsb es:[edi], ds:[esi]
5201
jae @F ;if forward copy is OK
5206
rep movsb ;do the move
5207
movsb ;one more byte
5209
jmp ee0a ;restore ds and es and undo the int2324 pointer hack
5212
;--- M without argument - display machine type.
5215
mov si,offset msg8088
5219
mov si,offset msgx86
5223
call copystring ;si->di
5224
mov si,offset no_copr
5226
je @F ;if no coprocessor
5227
mov si,offset has_copr
5230
je @F ;if has coprocessor same as processor
5231
mov si,offset has_287
5233
call copystring ;si->di
5234
jmp putsline ;call puts and quit
5237
if LCMDFILE or WCMDFILE
5239
;--- N command - change the name of the program being debugged.
5240
;--- modifies the debugger's PSP; actually, both the program name
5241
;--- and the tail are stored in the DTA.
5243
;--- Actually, the current N cmd is NOT compatible with MS Debug. MS Debug's
5244
;--- N cmd modifies the debuggee's PSP. So it's an easy way to modify
5245
;--- the program's arguments. OTOH, it removes the file_spec only on entry.
5247
;--- possible fix: copy debug's PSP:5C-7B and DTA:xx-7F (xx=strlen(file_spec) + 1)
5248
;--- to the debuggee PSP as soon as it has been created.
5259
mov di,PSPS.DTA ;destination address
5264
;--- Copy and canonicalize file name.
5265
;--- v2.50: check max. length to ensure that debug's _TEXT segment isn't modified.
5266
;--- out: [fileext]=0 if no file spec at all
5267
;--- [execblk.cmdtail] -> behind file spec
5269
mov cx, sizeof PSPS.DTA - 1
5272
je nn3 ;if end of line
5273
call ifsep ;check for separators space, TAB, comma, ;, =
5274
je nn3 ;if end of file name
5276
je nn3 ;if '/' (and '/' is the switch character)
5278
jb @F ;if not lower case
5281
and al,TOUPPER ;convert to upper case
5285
loop nextc ;back for more
5288
mov al,0 ;null terminate the file name string
5290
mov word ptr [execblk.cmdtail],di ;save start of command tail
5292
;--- file name stored as asciiz at psp:80h;
5293
;--- now set [fileext];
5300
je nn3d ;if no file name at all
5302
jb nn3c ;if no extension (name too short)
5304
mov bx,offset exts ;check for .EXE, .COM and .HEX
5321
;--- Finish the N command
5322
;--- 1. copy what's left behind the file spec to line_out
5330
mov di,offset line_out
5334
lodsb ;copy the remainder to line_out
5344
;--- Set up FCBs. src is line_out
5347
call DoFCB ;first FCB: parse name DS:SI into FCB es:di
5348
mov byte ptr [regs.rAX+0],al
5350
call DoFCB ;second FCB
5351
mov byte ptr[regs.rAX+1],al
5353
;--- Copy command tail from line_out to
5354
;--- PSP, just behind zero-terminated file spec.
5356
mov si,offset line_out
5359
jcxz notail ; if no more space left behind file spec
5361
inc di ; skip byte used for byte cnt
5366
loopne @B ;if not end of string
5367
pop ax ;recover old DI
5371
sub ax,di ;compute length of tail
5377
;--- Subroutine to process an FCB.
5389
je nn10 ;if switch character
5392
mov ax,2901h;parse filename into FCB
5396
lodsb ;skip till separator
5400
je @F ;if separator character
5402
jne @B ;if not swchar (sort of)
5412
;--- Handle a switch (differently).
5417
je nn7 ;if end of string
5419
je nn10 ;if another separator
5425
jb @F ;if not a lower case letter
5428
and al,TOUPPER ;convert to upper case
5442
ret ;return with AL=0
5447
;--- O command - output to I/O port.
5460
mov ah,[si-2] ;distiguish 'od' and 'o d'
5477
call getbyte ;dl=byte
5478
call chkeol ;expect end of line here
5479
xchg ax,dx ;al = byte
5480
pop dx ;recover port number
5484
call getword ;dx=word
5485
call chkeol ;expect end of line here
5486
xchg ax,dx ;ax = word
5492
call getdword ;bx:dx=dword
5493
call chkeol ;expect end of line here
5505
;--- ensure segment in BX is writeable.
5506
;--- if it isn't, BX may be set to an alias (scratchsel)
5507
;--- expects DS,SS=dgroup ( for ?DPMI, also ES=dgroup )
5508
;--- out: Carry=1 if segment not writeable
5510
;--- setcseipbyte(); write at regs.cs:e/ip + cx
5511
;--- writemem(): write byte at bx:e/dx
5525
sizeprf ; lea edi,[di] (synonym for movzx edi,di), 3 bytes long
5527
mov ax,000Bh ;get descriptor
5530
test byte ptr [di+5],8 ;code segment?
5532
and byte ptr [di+5],0F3h;reset CODE+conforming attr
5533
or byte ptr [di+5],2 ;set writable
5534
mov bx, [scratchsel]
5549
call getlinearbaseDT
5567
movzx eax, [scratchsel]
5569
@dprintf "IsWriteableBX: esi=%lX, edi=%lX", esi, edi
5580
mov bx, [scratchsel]
5598
;--- in: DX=real-mode segment
5599
;--- out: BX=scratch sel, base modified to match the segment in DX
5603
mov [scratchv86], dx
5617
movzx ebx, [scratchsel]
5620
movzx eax, word ptr [ebp+5*4] ;get DX
5622
movzx eax, word ptr [bp+5*4] ;get DX
5627
mov word ptr [ebx+0], -1
5628
mov word ptr [ebx+2], ax
5630
mov byte ptr [ebx+4], al
5631
mov word ptr [ebx+5], 0093h ; data, writeable, present, 16-bit
5632
mov byte ptr [ebx+7], ah
5635
mov bx, [scratchsel]
5643
mov bx,cs:[scratchsel]
5644
setrmaddr: ;<--- set selector in BX to segment address in DX
5654
;--- out: AL= HiByte of attributes of current CS
5655
;--- out: ZF=1 if descriptor's default-size is 16bit
5656
;--- called by P, T, U
5657
;--- modifies EAX, BX
5661
getseldefsize:: ;<--- any selector in BX
5678
;--- in: segment/selector in BX
5679
;--- out: ZF=1 if in real-mode or segment limit is <= 64 kB
5691
lar eax,ebx ; v2.0: first check if expand down
5695
bt eax, 22 ; if yes, is default bit set?
5710
;--- read [EIP+x] value
5713
;--- [regh_(e)ip]=EIP
5714
;--- out: AL=[CS:(E)IP]
5716
;--- called by T and G
5720
@movs es, [regs.rCS]
5721
sizeprfX ;mov ebx,[regs.rIP]
5724
test [bCSAttr], CS32
5741
;--- set [EIP+x] value
5743
;--- AL=byte to write
5752
call IsWriteableBX ; checks descriptor only, can't detect r/o pages
5759
test [bCSAttr], CS32
5776
;--- write a byte (AL) at BX:E/DX
5777
;--- OUT: AH=old value at that location
5778
;--- C if byte couldn't be written
5779
;--- used by A, E, G (breakpoints)
5787
call IsWriteableBX ;ensure that bx has a writeable selector
5788
; jc err ;v2.0: don't exit silently, better to cause a GPF
5791
@dprintf "writemem: bx:edx=%X:%lX", bx, edx
5802
@dprintf "writemem: bx:dx=%X:%X", bx, dx
5820
;--- read byte from memory
5821
;--- in: BX:(E)DX=address
5823
;--- used by e_cmd prompt mode
5824
;--- BX may be modified
5828
call getseglimit ;attribute of selector in BX, Z if limit is <= 0ffffh
5847
;--- P command - proceed (i.e., skip over call/int/loop/string instruction).
5850
call parse_pt ;process arguments
5852
;--- Do it <CX=count> times. First check the type of instruction.
5854
instrloop: ; <--- next instruction
5856
mov dx,15 ; DL = number of bytes to go; DH = prefix flags.
5861
mov dh,PP_ADRSIZ + PP_OPSIZ
5864
sizeprfX ; mov esi,[regs.rIP]
5866
nextprf: ; <- get next prefix byte
5867
call getnextb ; AL=[cs:(e)ip], eip++
5868
mov di,offset ppbytes
5871
jne pp5 ; if not one of these
5873
mov al,[di+PPLEN-1] ; get corresponding byte in ppinfo
5875
jz @F ; if not a prefix
5876
xor dh,al ; update the flags
5878
jnz nextprf ; if not out of bytes
5879
jmp dotrace ; more than 15 prefixes will cause a GPF
5882
jz @F ; if no size dependency
5884
and dh,PP_OPSIZ ; for CALL, operand size 2->4, 4->6
5888
call addeip ; add ax to instruction pointer in (E)SI
5889
jmp proceed0; we have a skippable instruction here
5892
cmp al,0ffh ; indirect call?
5895
jmp dotrace ; just an ordinary instruction
5900
call getnextb ; get MOD REG R/M byte
5901
and al,not 8 ; clear lowest bit of REG field (/3 --> /2)
5902
xor al,10h ; /2 --> /0
5906
jmp dotrace ; if not ff/2 or ff/3
5909
jnz dotrace ; if not ff/2 or ff/3
5912
jae proceed0; if just a register
5914
jnz pp6 ; if 32 bit addressing
5916
je proceed2 ; if just plain disp16
5918
jb proceed0 ; if indirect register
5920
jb proceed1 ; if disp8[reg(s)]
5921
jmp proceed2; it's disp16[reg(s)]
5923
jmp instrloop; back for more
5927
je proceed4 ; if just plain disp32
5930
jnz @F ; if no SIB byte
5934
jb proceed0 ; if indirect register
5936
jb proceed1 ; if disp8[reg(s)]
5937
; otherwise, it's disp32[reg(s)]
5949
;--- Ordinary instruction. Just do a trace.
5952
or byte ptr [regs.rFL+1],1 ;set single-step mode
5954
cmp [run_int], EXC01MSG
5955
jne pp15 ; stop if some other interrupt
5957
pp13: ;<--- Common part to finish up.
5959
loop back2top ;back for more
5962
jmp ue_int ;print message about unexpected interrupt and quit
5966
test [bCSAttr], CS32
5975
test [bCSAttr], CS32
5986
;--- getnextb - Get next byte in instruction stream.
5993
test cs:[bCSAttr], CS32
6002
@movs bx, [regs.rCS]
6004
;--- Special instruction. Set a breakpoint and run until we hit it.
6005
;--- BX:(E)SI == address where a breakpoint is to be set.
6007
doproceed1:: ;<--- used by T if an INT is to be processed
6008
@dprintf "doproceed1: bx:esi=%X:%lX", bx, esi
6009
mov di,offset line_out ;use the same breakpoint structure as in G
6013
sizeprfX ; mov edx, esi
6015
call [wStoreBP] ; optionally use 386 debug register for auto breakpoints?
6019
sizeprfX ;xchg eax,esi
6026
mov bp, offset bp_writeerr ; abort if bp couldn't be written
6027
call gg_1 ; use g_cmd to write bp, run program, reset bp
6030
mov dx, offset cantwritebp
6042
mov si, offset pmvectors
6043
mov di, offset pmints
6048
sizeprf ; mov edx, [si]
6054
add si, sizeof fword
6065
;--- Q command - quit.
6071
;--- the ring0 debugger core doesn't really know how to "quit";
6072
;--- that's why the Q cmd isn't active as default.
6073
;--- If activated, this code checks if current debuggee's CS is
6074
;--- non-priviledged - if yes, it pokes a "dos exit" at the current
6075
;--- instruction pointer. That's rather hackish, the current OS may
6076
;--- not have implemented an int 21h API at all. However, it will work
6077
;--- in many cases and hence seems better than nothing.
6079
@movs bx, [regs.rCS]
6083
jz @F ; can't exit in ring 0
6085
mov edx, dword ptr [regs.rIP]
6088
mov dword ptr [edx], 21CD4CB4h ; mov ah,4ch , int 21h
6093
mov dx, offset plerr
6099
mov byte ptr [dpmidisable+1],0 ;disble DPMI hook
6100
inc [bNoHook2F] ;avoid a new hook while terminating
6103
;--- cancel child's process if any
6104
;--- this will drop to real-mode if debuggee is in pmode
6106
;--- v1.29: debugx: if debuggee is in pm, 'q' will try to terminate it - else it really quits
6110
cmp al,'Q' ;"qq" entered?
6130
mov dx,[xmsmove.dsthdl]
6135
mov al,0 ; restore debuggee screen
6139
mov ah,0Ah ; and free XMS handle
6148
;--- Restore interrupt vectors.
6150
mov di,offset intsave
6151
mov si,offset inttab
6160
; add si,2 ; skip rest of INTITEM (now done below)
6172
lodsw ; skip rest of INTITEM (16-bit offset)
6176
;--- Restore termination address.
6180
mov si,offset psp22 ;restore termination address
6184
mov di,PSPS.PARENT ;restore PSP of parent
6190
;--- int 20h sets error code to 0.
6191
;--- might be better to use int 21h, ax=4Cxxh
6192
;--- and load the error code returned by the debuggee
6201
jmp cmdloop ;returned? then something is terribly wrong.
6219
;--- RX command: toggle mode of R command (16 - 32 bit registers)
6229
; mov di,offset line_out
6230
mov si,offset regs386
6231
call copystring ;si->di
6232
xor [rmode],RM_386REGS
6238
; mov al,0 ; v2.0: removed
6245
;--- RN command: display FPU status
6260
;--- R command - manipulate registers.
6264
jne @F ;if there's an argument
6280
;--- an additional register parameter was given
6285
mov di,offset regnames
6289
mov di,offset line_out
6290
jne rr2 ;if not found in standard register names
6291
cmp byte ptr [si],20h ;avoid "ES" to be found for "ESI" or "ESP"
6293
stosw ;print register name
6296
mov bx,[bx+NUMREGNAMES*2-2]
6297
call skipcomma ;skip white spaces
6299
jne rr1a ;if not end of line
6300
push bx ;save bx for later
6303
call getline0 ;prompt for new value
6306
je rr1b ;if no change required
6309
call chkeol ;expect end of line here
6310
mov [bx],dx ;save new value
6314
;--- is it the F(lags) register?
6322
je rr2b ;if end of line
6324
je rr2a ;if white space
6329
jmp errorj9 ;if not, then it's an error
6333
jne rr3 ;if not end of line
6336
call getline0 ;get input line (using line_out as prompt)
6339
je rr1b ;return if done
6342
and ax,TOUPPER_W;here's the mnemonic
6343
mov di,offset flgnams
6346
jne rr6 ;if no match
6347
cmp di,offset flgnons
6348
ja rr4 ;if we're clearing
6360
jmp rr3 ;check if more
6362
;--- it is neither 16bit register nor the F(lags) register.
6363
;--- check for valid 32bit register name!
6372
cmp al,'S' ;avoid EDS,ECS,ESS,... to be accepted!
6376
mov di,offset regnames
6380
;--- it is a valid 32bit register name
6383
mov di,offset line_out
6384
mov byte ptr [di],'E'
6389
mov bx,[bx+NUMREGNAMES*2-2]
6390
call skipcomma ;skip white spaces
6392
jne rr1aX ;if not end of line
6398
call getline0 ;prompt for new value
6401
je rr1bX ;if no change required
6407
call chkeol ;expect end of line here
6408
mov [bx+0],dx ;save new value
6409
mov [bx+2],cx ;save new value
6416
dec si ;back up one before flagging an error
6424
exctab label byte ; ring 0 exc table used by SK, VC, VT
6439
SIZEEXCTAB equ $ - offset exctab
6441
noskip db "No exception to skip",13,10,'$'
6442
yesskip db "Exception skipped",13,10,'$'
6447
;--- actually, the only exceptions that cannot be skipped
6448
;--- are breakpoints set by the debugger itself.
6455
mov si, offset exctab
6456
mov bx, offset intsave
6461
add bx, sizeof INTVEC
6463
mov dx, offset noskip
6467
mov ebx, dword ptr [regs.rSP]
6470
test byte ptr [regs.rFL+2], 2
6474
and ah, 60h ; exception occured in ring 0?
6475
jz @F ; then there's no stack switch.
6477
mov ebx, [regs.r0Esp] ; no, use saved r0 stack
6479
@dprintf "sk: r3 exc, old r0 ss:esp=%X:%lX, vec=%X", dx, ebx, si
6480
sub ebx, 2*4 ; and correct esp for saved r3 ss:esp
6482
test byte ptr [regs.rFL+2], 2
6484
sub ebx, 4*4 ; for v86-mode, space for saved r3 regs es,ds,fs,gs
6485
and byte ptr [regs.rFL+2], not 2 ; reset VM flag
6494
;--- dx=ss, ebx=esp, esi -> intsave entry for exception
6495
bt [run_intw], 15 ; exc with error code?
6497
sub ebx, 1*4 ; correct error code
6499
sub ebx, 3*4 ; correct cs:eip & efl
6500
mov dword ptr [regs.rSP], ebx
6503
mov dword ptr [regs.rIP], eax
6504
mov dword ptr [u_addr], eax
6511
mov byte ptr [regs.rFL+1], ah
6513
mov [run_int+1], -1 ; reset run_int, so skip is "deactivated" for this time
6514
mov dx, offset yesskip
6521
;--- S command - search for a string of bytes.
6532
call getrangeDS ;get address range into BX:(E)DX..BX:(E)CX
6536
call getstr ;get string of bytes, size: di - (lineout+1)
6540
sub di,offset line_out ;di = number of bytes to look for
6546
@dprintf "s_cmd: bx:edx=%X:%lX, ecx=%lX, di=%X", bx, edx, ecx, di
6554
@dprintf "s_cmd: bx:dx=%X:%X, cx=%X, di=%X", bx, dx, cx, di
6556
sub cx,dx ;cx = number of bytes in search range minus one
6557
sub cx,di ;number of possible positions of string minus 1
6561
; inc cx ;cx = number of possible positions of string
6562
sizeprfX ;xchg edx, edi
6563
xchg dx,di ;set (E)DI to offset
6564
call dohack ;set debuggee's int 23/24
6566
sss1: ;<---- search next occurance
6567
mov es, bx ;set the segment
6568
mov si,offset line_out ;si = address of search string
6569
lodsb ;first character in al
6573
; @dprintf "s_cmd scasb: es:edi=%X:%lX, ecx=%lX ax=%X", es, edi, ecx, ax
6575
repne scasb es:[edi]
6584
; @dprintf "s_cmd cmpsb: es:edi=%X:%lX, ecx=%lX, ds:esi=%X:%lX", es, edi, ecx, ds, esi
6585
repe cmpsb ds:[esi], es:[edi]
6587
jne @F ;if not equal
6597
repne scasb ;look for first byte
6599
scasb ;count in CX was cnt-1
6600
jne sss3 ;if we're done
6607
jne @F ;if not equal
6612
loop sss1 ;go back for more
6614
jmp unhack ;set debugger's int 23/24
6616
;--- display position
6617
;--- the search string is in line_out.
6618
;--- so we have to write to [SI] ( which here points just behind search string )
6621
call unhack ;set debugger's int 23/24
6623
sizeprfX ;xchg esi, edi
6624
xchg si,di ;render position right after search string
6625
push di ;v2.02 save pos on stack (in v2.0-v2.01, it was saved in CX)
6626
push ds ;v2.02 restore ES; needed for hex(d)word
6644
mov ax,( LF shl 8 ) or CR
6646
pop dx ;get pos from stack
6649
call stdout ;write cx chars from ds:dx to stdout
6651
sizeprfX ;mov edi, esi
6653
jmp dohack ;set debuggee's int 23/24
6666
call chkeol ;expect end of line here
6670
mov si, offset tmode0
6674
mov si, offset tmode1
6679
mov si, offset tmodes
6688
;--- T command - Trace.
6697
; mov [lastcmd], offset tt0
6698
mov [lastcmd], offset t_cmd
6699
call parse_pt ;process arguments
6709
;--- trace one instruction
6719
cmp bx,word ptr [dpmiwatch+0] ;catch the initial switch to protected mode
6721
cmp ax,word ptr [dpmiwatch+2]
6723
cmp [bNoHook2F],0 ;current CS:IP is dpmi entry
6725
;if int 2fh is *not* hooked ( win3x, win9x, dosemu )
6726
mov [regs.rIP],offset mydpmientry
6730
pop es ;run code until RETF
6743
cmp al,0CDh ; an INT instruction?
6747
cmp al,3 ; 2-byte INT 3?
6749
test byte ptr [tmode], 1 ;TM=1?
6754
or byte ptr [regs.rFL+1],1h ;set single-step mode
6760
cmp al,9Ch ;was opcode "PUSHF"?
6762
call clear_tf_onstack
6764
cmp [run_int], EXC01MSG
6766
jmp ue_int ;if some other interrupt ( is always "unexpected" )
6771
; an INT is to be processed (TM is 0)
6772
; to avoid the nasty x86 bug which makes IRET
6773
; cause a debug exception 1 instruction too late
6774
; a breakpoint is set behind the INT
6776
; if the int will terminate the debuggee (int 21h, ah=4Ch)
6777
; it is important that the breakpoint won't be restored!
6781
call ispm_dbe ; in protected-mode?
6782
jnz useproceed ; then don't check, optionally use hw bp
6784
if RING0 and USEHWBP ; no check for DebugR if USEHWBP is 1
6787
call iswriteablecseip ;is current CS:IP in ROM?
6788
jc isstdtrace ;then do standard trace
6792
sizeprfX ; mov esi,[regs.rIP]
6800
call doproceed1 ;set BP at BX:(E)SI and run debuggee
6803
;--- current instruction is INT, TM is 1, single-step into the interrupt
6813
int 31h ;get vector in CX:(E)DX
6815
test bl,4 ;is it a LDT selector?
6819
sizeprf ;mov esi,edx
6828
test byte ptr [regs.rFL+2],2
6849
mov si, ds:[ebx+eax+6]
6851
mov si, ds:[ebx+eax+0]
6852
mov bx, ds:[ebx+eax+2]
6855
call doproceed1 ; expects bp to be set at BX:(E)SI
6858
if (RING0 eq 0) or V86M
6865
movzx eax, word ptr [ebx*4+2]
6867
movzx esi, word ptr [ebx*4+0]
6874
shl bx,1 ;stay 8086 compatible in real-mode!
6877
lds si,[bx+0] ; check if IVT is R/O? What's the purpose?
6879
xor byte ptr [si],0FFh
6887
call doproceed1 ; set bp at BX:ESI, then GO
6898
mov ds,[regs.rSS] ;emulate an INT
6907
and byte ptr [regs.rFL+1],0FCh ;clear IF + TF
6914
;--- test if memory at CS:E/IP can be written to.
6917
;--- IN: CX=offset for (E)IP
6919
if RING0 and USEHWBP ; remove if RING==1 and USEHWBP==1
6921
iswriteablecseip proc
6922
call getcseipbyte ;get byte ptr at CS:EIP+CX
6928
cmp ah,al ;is it ROM?
6937
iswriteablecseip endp
6940
;--- clear TF in the copy of flags register onto the stack
6942
clear_tf_onstack proc
6944
@movs es, [regs.rSS]
6947
; call getseglimit ; v1.29: segment limit doesn't matter,
6948
call getseldefsize ; check defsize if ESP is to be used.
6951
mov ebx,dword ptr [regs.rSP]
6952
and byte ptr es:[ebx+1],not 1
6956
@dprintf "clear_tf_onstack: es=%X", es
6959
and byte ptr es:[bx+1],not 1
6963
clear_tf_onstack endp
6965
;--- Print message about unexpected interrupt, dump registers, and end
6966
;--- command. This code is used by G, P and T cmds.
6970
if RING0 and CATCHSYSREQ
6972
btr word ptr [bFlagsPM], 1
6978
and word ptr ds:[417h], not ( 200h or 8) ;reset "Alt pressed" flags
6983
add dx, offset int0msg
6984
call int21ah9 ;print string
6986
cmp dx, offset progtrm
6987
je @F ;if it terminated, skip the registers
6991
jmp cmdloop ;back to the start
6993
;--- "unexpected" exception in real-mode inside debugger
6996
if CATCHINT07 or CATCHINT0C or CATCHINT0D or SKIPBPINDBG
7015
if ?PM or CATCHINT07 or CATCHINT0C or CATCHINT0D
7017
;--- "unexpected" exception occured inside debugger
7018
;--- [SP] = msg, cs, [e]ip
7023
call unhack ;set debugger's int 23/24
7025
test [disflags], DIS_I_MEMACC
7033
add dx, offset int0msg
7034
call int21ah9 ;print string
7038
mov di,offset line_out
7039
mov si,offset excloc ; "CS:IP="
7061
;--- U command - disassemble.
7064
mov [lastcmd],offset u_cmd
7065
mov cx,20h ;default length
7067
je uuloop ;if no address was given
7069
call getrange ;get address range into bx:(e)dx/(e)cx
7070
call chkeol ;expect end of line here
7071
sizeprfX ;mov [u_addr+0],edx
7076
sizeprfX ;sub ecx, edx
7078
@dprintf "u_cmd: u_addr=%X:%lX, ecx=%lX", bx, edx, ecx
7080
;--- At this point, e/cx holds the size
7081
;--- the disassembler won't use any registers as parameters,
7082
;--- it always disassembles the code at [u_addr] and updates
7083
;--- that variable accordingly.
7088
call disasm1 ;disassemble one instruction
7092
mov bx, [dis_n] ;bytes disassembled
7093
sizeprfX ;movzx ebx, bx
7095
sizeprfX ;sub ecx, ebx
7100
ja uuloop ;if we haven't reached the goal
7106
lockdrive: ;lock logical volume
7113
mov bh,0 ;lock level (0 means what?)
7114
mov cx,084Ah ;isn't this for non-FAT32 drives only?
7115
mov dx,0001h ;permission flags (1=allow writes)
7130
; mov bh,0 ;bh has no meaning for unlock
7131
mov cx,086Ah ;isn't this for non-FAT32 drives only?
7141
;--- W command - write a program, or disk sectors, to disk.
7144
call parselw ;parse L and W argument format (out: bx:(e)dx=address)
7146
jz write_file ;if request to write program
7148
jz cmd_error ;no support to write program
7153
call isextenderavailable ;in protected-mode, DOS translation needed
7155
mov dx,offset nodosext
7159
cmp cs:[usepacket],2
7161
mov dl,al ;A=0,B=1,C=2,...
7162
mov si,6001h ;write, assume "file data"
7168
inc dl ;A=1,B=2,C=3,...
7170
mov ax,7305h ;DS:(E)BX->packet
7172
int 21h ;use int 21h here, not doscall
7187
mov cx,"rw" ;cx:dx="writ"
7189
; jmp disp_diskresult ; fall thru to disp_diskresult
7193
;--- display disk access result ( C if error )
7194
;--- CX:DX="read"/"writ"
7197
mov bx,ss ;restore segment registers
7201
jnc ww3 ;if no error
7202
mov word ptr [szDrive+1], cx
7203
mov word ptr [szDrive+3], dx
7210
; shl ax,1 ; v2.0: removed - dskerrs is a byte offset table
7212
mov al, [si+dskerrs]
7213
mov si, offset dskerr0
7215
mov di, offset line_out
7217
mov si, offset szDrive
7221
jmp cmdloop ;can't ret because stack is wrong
7229
;--- Write to file. First check the file extension.
7230
;--- size of file to be written is in client's BX:CX,
7231
;--- default start address is DS:100h
7234
mov al,[fileext] ;get flags of file extension
7235
test al,EXT_EXE + EXT_HEX
7236
jz @F ;if not EXE or HEX
7237
mov dx,offset nowhexe
7241
jnz ww7 ;if extension exists
7242
mov dx,offset nownull
7246
;--- File extension is OK; write it. First, create the file.
7247
;--- bx:e/dx = start address
7253
mov dx,offset nopmsupp ;cmd rejected in protected-mode
7257
mov bp,offset line_out
7259
jb @F ;if dx < fe00h
7260
sub dh,0feh ;dx -= 0xfe00
7263
mov [bp+10],dx ;save lower part of address in line_out+10
7264
mov si,bx ;upper part goes into si
7269
xor cx,cx ;no attributes
7271
mov ah,3ch ;create file
7276
jc io_error ;if error
7277
push ax ;save file handle
7279
;--- Print message about writing.
7281
mov dx,offset wwmsg1
7282
call int21ah9 ;print string
7284
cmp ax,10h ;max size = 0fffffh
7285
jb @F ;if not too large
7286
xor ax,ax ;too large: zero it out
7291
call hexnyb ;convert to hex digit and print
7296
call puts ;print size
7297
mov dx,offset wwmsg2
7298
call int21ah9 ;print string
7300
;--- Now write the file. Size remaining is in line_out+6.
7302
pop bx ;recover file handle
7303
mov dx,[bp+10] ;address to write from is si:dx
7307
cmp byte ptr [bp+8],0
7308
jnz @F ;if more than 0fe00h bytes remaining
7313
xchg ax,cx ;mov cx,ax
7315
mov ah,40h ;write to file
7316
int 21h ;use INT, not doscall
7320
jne ww13 ;if disk full
7321
xor dx,dx ;next time write from xxxx:0
7322
add si,0fe0h ;update segment pointer
7325
sbb byte ptr [bp+8],0
7326
jnz ww11 ;if more to go
7332
mov dx,offset diskful
7333
call int21ah9 ;print string
7339
mov ah,41h ;unlink file
7348
mov ah,3eh ;close file
7355
if LCMDFILE or WCMDFILE
7357
;--- Error opening file. This is also called by the load command.
7361
mov dx,offset doserr2 ;File not found
7364
mov dx,offset doserr3 ;Path not found
7367
mov dx,offset doserr5 ;Access denied
7370
mov dx,offset doserr8 ;Insufficient memory
7372
mov di,offset openerr1
7374
mov dx,offset openerr ;Error ____ opening file
7383
if 1 ;v2.0: check InDos, if set use stdout()
7391
if 1 ;v2.0: get size of $-string DS:DX, then call stdout; SI, CX not modified
7411
;--- X commands - manipulate EMS memory.
7413
;--- XA - Allocate EMS.
7417
call chkeol ;expect end of line here
7419
mov ah,43h ;allocate handle
7422
mov ax,5A00h ;use the EMS 4.0 version to alloc 0 pages
7426
mov si,offset xaans ; "Handle created: "
7430
jmp putsline ;print string and return
7433
;--- XD - Deallocate EMS handle.
7438
call chkeol ;expect end of line here
7439
mov ah,45h ;deallocate handle
7442
mov si,offset xdans ; "Handle deallocated: "
7446
jmp putsline ;print string and return
7450
;--- x main dispatcher
7454
je xhelp ;if a call for help
7460
je xs ;if XS command
7466
je xa ;if XA command
7468
je xd ;if XD command
7470
je xr ;if XR command
7472
je xm ;if XM command
7476
mov dx,offset xhelpmsg
7477
mov cx,size_xhelpmsg
7478
jmp stdout ;print string and return
7481
;--- XR - Reallocate EMS handle.
7482
;--- DX = first argument (=handle)
7487
call getword ;get count argument into DX
7488
call chkeol ;expect end of line here
7490
mov ah,51h ;reallocate handle
7492
mov si,offset xrans ; "Handle reallocated: "
7494
jmp putsline ;print string and return
7498
;--- XM - Map EMS memory to physical page.
7499
;--- DX = first argument [=logical page (FFFF means unmap)]
7502
mov bx,dx ;save it in BX
7504
call getbyte ;get physical page (DL)
7507
call getword ;get handle into DX
7508
call chkeol ;expect end of line
7509
pop ax ;recover physical page into AL
7511
mov ah,44h ;function 5 - map memory
7516
mov di,offset line_out + xmans_pos1
7517
xchg ax,bx ;mov ax,bx
7519
mov di,offset line_out + xmans_pos2
7523
jmp putsline ;print string and return
7527
;--- XS - Print EMS status.
7531
call chkeol ;no arguments allowed
7533
; First print out the handles and handle sizes. This can be done either
7534
; by trying all possible handles or getting a handle table.
7535
; The latter is preferable, if it fits in memory.
7537
mov ah,4bh ;function 12 - get handle count
7539
cmp bx,( real_end - line_out ) / 4
7540
jbe xs3 ;if we can do it by getting the table
7542
xor dx,dx ;start handle
7544
mov ah,4ch ;function 13 - get handle pages
7546
cmp ah,83h ; error "invalid handle"?
7547
je xs2 ;if no such handle
7550
jmp ems_err ;if other error
7552
xchg ax,bx ;mov ax,bx
7556
jnz nexthdl ;if more to be done
7558
jmp xs5 ;done with this part
7560
;--- Get the information in tabular form.
7563
mov ah,4dh ;function 14 - get all handle pages
7564
mov di,offset line_out
7566
and bx,bx ;has returned no of entries in BX
7575
jnz @B ;if more to go
7579
call int21ah9 ;print string
7581
; Next print the mappable physical address array.
7582
; The size of the array shouldn't be a problem.
7584
mov ax,5800h ;function 25 - get mappable phys. address array
7585
mov di,offset line_out ;address to put array
7587
mov dx,offset xsnopgs
7588
jcxz xs7 ;NO mappable pages!
7594
mov di,offset xsstr2b
7597
mov di,offset xsstr2a
7599
mov dx,offset xsstr2
7601
call stdout ;print string
7605
mov dx,offset crlf ;blank line
7606
call int21ah9 ;print string
7609
mov dx,offset crlf ;blank line
7611
call int21ah9 ;print string
7613
;--- Finally, print the cumulative totals.
7615
mov ah,42h ;function 3 - get unallocated page count
7617
mov ax,dx ;total pages available
7618
sub ax,bx ;number of pages allocated
7619
mov bx,offset xsstrpg
7620
call sumshow ;print the line
7621
mov ah,4bh ;function 12 - get handle count
7625
;--- try EMS 4.0 function 5402h to get total number of handles
7628
int 67h ;don't use emscall, this function may fail!
7632
mov dx,0ffh ;total number of handles
7634
pop ax ;ax = number of handles allocated
7635
mov bx,offset xsstrhd
7636
call sumshow ;print the line
7642
;--- in case of error, return to cmd loop
7649
invoke simrealmodeint, 67h, cs:[wDgroup]
7667
jg ce2 ;if out of range
7668
cbw ;80->ff80 ... 8B->ff8B
7670
shl bx,1 ;ff80->ff00 ... ff8B->ff16
7671
mov si,[emserrs+100h+bx]
7673
jnz ems_err3 ;if there's a word there
7675
mov di,offset emserrxa
7677
mov si,offset emserrx
7679
mov di,offset line_out
7680
call copystring ;si->di
7702
mov ax,3567h ;get interrupt vector 67h
7709
mov ah,46h ;get version
7716
mov si,offset emsnot
7720
;--- HNDLSHOW - Print XS line giving the handle and pages allocated.
7730
mov di,offset xsstr1b
7733
mov di,offset xsstr1a
7736
mov dx,offset xsstr1
7743
;--- SUMSHOW - Print summary line for XS command.
7745
;---Entry AX Number of xxxx's that have been used
7746
; DX Total number of xxxx's
7749
; Exit String printed
7751
; Uses AX, CX, DX, DI
7754
mov di,offset line_out
7755
call trimhex ; ax ( skip leading zeros )
7756
mov si,offset xsstr3 ; " of a total "
7758
xchg ax,dx ; mov ax,dx
7760
mov si,offset xsstr3a ; " EMS "
7762
mov si,bx ; "pag"/"handl"
7764
mov si,offset xsstr3b ; "es have been allocated"
7770
; TRIMHEX - Print word without leading zeroes.
7772
; Entry AX Number to print
7773
; DI Where to print it
7780
sub di,4 ;back up DI to start of word
7785
jne @F ;return if not a '0'
7786
mov byte ptr [di-1],' '
7795
;--- syntax error handler.
7796
;--- in: SI->current char in line_in
7800
sub cx,offset line_in+4
7802
mov di,offset line_out
7805
ja @F ;if we're really messed up
7806
inc cx ;number of spaces to skip
7810
mov si,offset errcarat
7811
mov cl,sizeof errcarat
7813
call putsline ;print string
7819
;--- FREEMEM - cancel child process
7823
; @dprintf "freemem enter"
7825
mov [regs.rIP],offset fmem2
7826
mov [regs.rFL], 202h; v1.29: ensure TF is clear ( TF=1 may cause "memory corrupt" error if returning to DOS )
7834
mov [regs.rSP],sp ; save sp-2
7837
; @dprintf "freemem back from run"
7838
cmp [run_int],INT22MSG ; v2.50: in case prog termination failed...
7839
jnz ue_int ; stop and display msg
7852
;--- setint2324 is called by "run", to set debuggee's INT 23/24.
7853
;--- Don't use INT 21h here, DOS might be "in use".
7854
;--- Registers may be modified - will soon be set to debuggee's...
7855
;--- counterpart is getint2324().
7858
mov si,offset run2324
7886
sizeprf ;mov edx,[si+0]
7916
mov si, offset regs.rDS
7935
WPENABLE equ 1 ;local wp enable
7936
;WPENABLE equ 2 ;global wp enable
7938
;--- DR6 (debug status register):
7939
;--- bits 0-3: 1=bp# condition detected (must be cleared by software)
7940
;--- bit 12: read as 0
7941
;--- bit 13: BD, debug register access detected
7942
;--- bit 14: BS, bp single step
7943
;--- bit 15: BT, bp task switch
7944
;--- rest of bits read as 1
7945
;--- DR7 (debug control register):
7946
;--- bit 0-7: L0,G0 - L3,G3
7948
;--- type ( optional 2. argument ) will be copied to bits 16-31 (RWx,LENx)
7949
;--- bp0 bit 16-17: type (0=exec, 1=write, 2=I/O [if CR4.DE=1], 3=read or write)
7950
;--- bp0 bit 18-19: len (0=1 byte, 1=2 byte, 2=8 byte, 3=4 byte )
7952
;--- map (hard) breakpoints to debug registers
7953
;--- entry will be patched to NOP NOP if hw bp enabled!
7959
mov bp, offset pmsethwbp
7966
mov si, offset HWBps
7974
@dprintf "setHWBps %lX", edx
7980
or byte ptr [si-1], BP_ACTIVE
7981
; or byte ptr [regs.rFL+2], 1 ; set resume flag so a hwbp at cs:eip will be skipped (see comment below)
7989
;--- set resume flag generally - another debugger
7990
;--- might have set a HW bp, and without RF=1 we would be stuck...
7991
or byte ptr [regs.rFL+2], 1
8003
shr dl, 2 ; dl = size (was in bits 2-3)
8004
and dx, 303h ; dh = type (0=exec,1=read, 2=r/w)
8005
add dl, 1 ; 0->1, 1->2, 3->4
8006
@dprintf "pmsethwbp bx:cx=%X%04X dx=%X", bx, cx, dx
8007
mov ax, 0b00h ; set watchpoint
8011
@dprintf "pmsethwbp hdl=%X", bx
8012
mov ax, 0b03h ; clear status in dr6
8018
if 1; it's used both in ring0 and real-mode
8026
and edx, 0fh ; type in bits 0-3
8030
add cl, 16 ; cl = 16|20|24 for bp0|1|2
8035
or eax, edx ; set type (RW0, LEN0 )
8039
or al, bl ; set G|L0|1|2=1
8040
or ah, WPENABLE ; set G|LE=1 ("legacy")
8044
@dprintf "r0sethwbp dr7=%lX dr6=%lX", eax, ebx
8050
add bx, offset setdrx
8064
;--- unmap (hard) breakpoints from debug registers
8065
;--- entry will be patched to NOP if hw bp enabled!
8067
;--- todo: for ring0, it's probably a good idea not to just
8068
;--- scan the bp table, but check the debug registers directly.
8069
;--- they may have been set by another PL0 debugger and
8070
;--- perhaps we want to cooperate by importing the bp?
8071
;--- At the very least, it should be checked if the addresses
8072
;--- in HWBps and DR0-3 do match. If no, a warning is to be
8079
mov bp, offset pmresethwbp
8081
jnz @F ; skip if in real/v86-mode
8083
mov bp, [wRMResetBP]
8087
mov si, offset HWBps
8093
and al, not BP_ACTIVE
8113
mov ax, 0b02h ; get status
8116
mov ax, 0b01h ; clear watchpoint
8118
@dprintf "pmresetHWBps hdl=%X", bx
8125
and al, dl ; disable G0|1|2
8129
btr ax, cx ; clear bit in DR6
8133
@dprintf "r0resethwbp bp#=%X", cx
8141
;--- This is the routine that starts up the running program.
8146
;--- check segment values, since there's no stack switch if a GPF occurs.
8148
test byte ptr [regs.rFL+2], 2 ;v86-mode?
8152
mov dx, offset segerr
8159
mov dx, offset cantwritebp
8165
call srscratch ; restore scratch GDT entry
8168
call seteq ;set CS:E/IP to '=' address
8170
;--- set debuggee context
8172
mov al, 0 ;restore debuggee screen
8180
call setpsp ;set debuggee's PSP
8182
call setint2324 ;set debuggee's int 23/24
8191
mov [run_sp],esp ;save stack position
8193
mov [run_sp],sp ;save stack position
8195
ife (DRIVER or BOOTDBG or RING0)
8196
; 16.2.2021: check if saved SS is debugger's SS. If no, don't adjust saved SP.
8197
; SS may be != saved SS if debugger is stopped in protected-mode - then the
8198
; current DPMI real-mode stack may be stored in PSPS.SPSAV.
8204
cmp ax,word ptr ds:[PSPS.SPSAV+2]
8207
mov word ptr ds:[PSPS.SPSAV],sp
8221
@dprintf "r0 ss:esp=%X:%lX efl=%lX", word ptr [regs.r0SSEsp+4], dword ptr [regs.r0SSEsp], dword ptr [regs.rFL]
8229
pop es ;temporary load DS value into ES (to make sure it is valid)
8230
pop es ;now load the true value for ES
8241
add sp,6;skip hi ebp+reserved
8249
add sp,2;skip hi eax
8252
add sp,2*2 ; skip places for FS,GS
8256
;--- FS and GS might be "unset" ( still containing real-mode values )
8257
;--- so check if value has changed and if not, don't write the regs
8270
test byte ptr [regs.rFL+2], 2
8273
lss esp, [regs.r0SSEsp]
8285
push dword ptr [regs.rSP]
8286
push dword ptr [regs.rFL]
8289
push dword ptr [regs.rIP]
8305
lss esp, [regs.r0SSEsp] ; debuggee runs in non-privileged mode, so
8306
push dword ptr [regs.rSS] ; create a full IRETD stack frame with SS:ESP
8307
push dword ptr [regs.rSP]
8313
patch_movsp label byte ;patch with 3Eh (=DS:) if cpu < 386
8314
db 66h ;mov esp,[regs.rSP]
8315
mov sp,[regs.rSP] ;restore program stack
8317
sizeprf ;push dword ptr [regs.rFL]
8319
sizeprf ;push dword ptr [regs.rCS]
8321
sizeprf ;push dword ptr [regs.rIP]
8327
test byte ptr [regs.rFL+1],2 ;IF set?
8330
sti ; required for ring3 protected mode if IOPL==0
8332
patch_iret label byte ; patch with CFh (=IRET) if cpu < 386
8335
iretd ; jump to program
8339
;--- debugger entries
8343
include <TRAPPL.INC>
8345
include <TRAPPV.INC>
8354
;--- also: entry DPMI protected-mode
8355
;--- in: SS:SP=regs.rSS
8359
;--- DWORD pushs are safe here
8366
popf ;skip LoWord(EFL)
8367
pop word ptr ss:[regs.rFL+2]
8371
popfd ;clear HiWord(EFL) inside debugger (resets AC flag)
8380
sub sp, 2*2 ; skip space for GS, FS
8397
intrtn1:: ;<--- entry for int 22
8402
mov esp, cs:[run_sp] ;restore running stack
8404
movzx esp,cs:[run_sp] ;restore running stack
8407
mov sp,cs:[run_sp] ;restore running stack
8412
sti ;interrupts back on
8417
;--- calling int 2Fh here is a problem, since breakpoints aren't reset yet.
8418
;--- this makes it impossible to trace this interrupt.
8420
mov ax,1686h ; actually, fn 1686h tells if int 31h API is available
8425
mov ax,cs ;v2.50: adjusted so it works for both .COM and .EXE formats
8427
sub ax,dx ;Z=rm,NZ=pm
8428
cmp ax,1 ;C=rm,NC=pm
8430
sbb ax,ax ;0=rm,-1=pm
8432
mov [regs.msw],ax ;0000=real-mode, FFFF=protected-mode
8436
ife (BOOTDBG or RING0)
8443
mov [bInDbg],1 ; v2.0: must be set before setdbgexc0d0e
8445
;--- set debugger context
8448
call getint2324 ;save debuggee's int 23/24, set debugger's int 23/24
8454
cmp [run_int], EXC0EMSG
8456
call rendercr2 ; add value of CR2 to msg
8459
call srscratch ;save GDT scratch entry
8467
call setpspdbg ;set debugger's PSP
8469
and byte ptr [regs.rFL+1],not 1 ;clear single-step interrupt
8471
; mov [bInDbg],1 ; v2.0: do this earlier ( see above )
8473
cmp [run_int], INT22MSG
8476
mov [cssel],0 ;reset flag 'initial switch has occured'
8480
mov di,offset progexit
8485
call checkgfx ; see if current mode is gfx, set to text if yet
8488
mov al, 1 ; restore debugger screen
8494
mov al, es:[84h] ; did the number of screen rows change?
8495
mov bh, es:[62h] ; BH=video page
8500
mov dh, al ; yes. we cannot fully restore, but at least clear
8501
mov dl, 0 ; bottom line to ensure the debugger displays are seen.
8502
mov ah, 2 ; set cursor pos
8504
mov bl, 07h ; BL=attribute, BH=video page
8505
mov cx, 80 ; CX=columns
8506
mov ax, 0920h ; AL=char to display
8511
;--- with page flips, there are problems with many BIOSes:
8512
;--- the debugger displays may get the color of the debuggee!
8513
;--- if there's any trick to convince the BIOS not to do this,
8514
;--- implement it here!
8521
@dprintf "debug entered"
8526
mov dx, 3CEh ; see if in graphics mode
8547
;--- set a hw bp at bx:edx;
8548
;--- bx and edx must be preserved.
8549
;--- this proc is called only if cpu is 80386+
8550
;--- and hw debug registers are accessible.
8562
@dprintf "sethwbptmp: linear=%lX (cs:eip=%X:%lX)", eax, bx, edx
8564
mov al, BP_CODE or BP_USED or BP_TEMP
8571
;--- find a free place in hw bp table
8572
;--- bx=segment/selector
8576
;--- DI = free entry in hw bp table
8581
mov di, offset HWBps
8584
test [di].HWBPSTRUCT.bType, BP_USED
8586
add di, sizeof HWBPSTRUCT
8592
call getlinearbaseDT ; eax=base of descriptor table for BX
8594
call getlinearbaseBX ; eax=base of BX
8598
call ispm_dbg ; in protected-mode?
8602
jc @F ; can't get base of BX
8625
no_free_bp db "All BPs used",CR,LF,'$'
8626
bp_not_set db "BP isn't set",CR,LF,'$'
8627
b_inactive db "cmd inactive",CR,LF,'$'
8630
;--- handle BP/BC cmds.
8631
;--- this code will only run if cpu is 80386+.
8639
cmp al, 'c' ; is it BC?
8641
cmp al, 'p' ; or BP?
8644
jmp cmd_error ; anything else is unknown
8647
cmp al,CR ; no argument given? then just display status...
8649
call getbyte ; get byte into DL
8654
imul ax, sizeof HWBPSTRUCT
8657
xchg al,[bx][HWBps].bType
8659
mov dx, offset bp_not_set
8664
cmp al,CR ; no argument given? then just display status...
8666
@movs bx,[regs.rCS];default segment to use
8667
call getaddr ; get address into bx:e/dx
8670
mov dl, 0 ; default type: 0=exec (1=write,2=io,3=rw)
8671
cmp al,CR ; second argument (=type) given?
8673
call getbyte ; get byte into DL
8678
pop dx ; restore type
8679
pop ecx ; get offset
8688
and al, 0fh ; real type is 4 bits only
8693
mov dx, offset no_free_bp
8697
mov dx, offset b_inactive
8701
mov si, offset HWBps
8707
@dprintf "bp: cx=%X, edx=%lX, al=%X", cx, edx, ax
8710
mov di, offset line_out
8751
notrappedexc db "No exc to (un)trap",13,10,'$'
8756
call getbyte ; get byte into DL
8757
call chkeol ; expect end of line here
8758
mov si, offset exctab
8766
mov dx, offset notrappedexc
8773
;--- clear trapped vector: VC exc#
8777
btr [wTrappedExc], dx
8781
;--- trap vector: VT exc#
8785
bts [wTrappedExc], dx
8789
;--- list trapped vectors: VL
8793
call chkeol ; expect end of line here
8794
mov si, offset exctab
8795
mov bx, offset intsave
8798
mov di, offset line_out
8811
bt [wTrappedExc], dx
8818
add bx, sizeof INTVEC
8829
;--- show debuggee screen, wait for a keypress, then restore debugger screen
8848
if 0;ndef VXCHGBIOS ; v2.0: no longer needed, swapscreen has set cursor
8849
;--- swapscreen has restored screen and cursor pos, but we want
8850
;--- the cursor be shown on the screen - so set it thru BIOS calls.
8851
mov ah, 0Fh ; get current mode (and video page in BH)
8853
mov ah, 3 ; get cursor pos of page in BH
8855
mov ah, 2 ; set cursor pos of page in BH
8871
;--- AL=0: save debugger screen, restore debuggee screen
8872
;--- AL=1: save debuggee screen, restore debugger screen
8876
.errnz BOOTDBG or RING0,<v cmd with XMS swap not supported>
8877
mov si, offset xmsmove
8878
cmp [si].XMSM.dsthdl,0
8881
shl ax, 14 ; 0->0000, 1 -> 4000h
8882
mov word ptr [si].XMSM.dstadr, ax
8884
;--- use offset & size of current video page as src/dst for
8885
;--- xms block move. Also toggle cursor pos debuggee/debugger.
8887
push 0040h ; 0040h is used because it also works in protected-mode
8890
mov word ptr [si].XMSM.size_, ax
8892
mov word ptr [si].XMSM.srcadr+0, ax
8894
;--- get/set cursor pos manually for speed reasons.
8898
mov dx, es:[bx+50h] ; get cursor pos of current page
8911
mov ah,0Bh ; save video screen to xms
8915
xor byte ptr [si].XMSM.srcadr+1, 40h
8917
mov ah,0Bh ; restore video screen from xms
8921
mov ah, 05h ; just use BIOS to activate video page
8936
mov ax, [si].XMSM.srchdl
8937
mov cx, word ptr [si].XMSM.srcadr+0
8938
mov dx, word ptr [si].XMSM.srcadr+2
8939
xchg ax, [si].XMSM.dsthdl
8940
xchg cx, word ptr [si].XMSM.dstadr+0
8941
xchg dx, word ptr [si].XMSM.dstadr+2
8942
mov [si].XMSM.srchdl, ax
8943
mov word ptr [si].XMSM.srcadr+0, cx
8944
mov word ptr [si].XMSM.srcadr+2, dx
8959
push word ptr [xmsdrv+2] ; cs
8960
push word ptr [xmsdrv+0] ; ip
8967
sizeprf ;mov edi, esp
8969
mov es:[di].RMCS.rSI, si
8970
mov es:[di].RMCS.rAX, ax
8986
@dprintf "v_cmd: ax=%X", ax
9000
;--- switch to debugger/debuggee screen with option /2.
9001
;--- since DOS/BIOS is used for output, there's no guarantee that it will work.
9002
;--- this code assumes that page 0 is set.
9005
ret ;will be patched to "push ds" if "/2" cmdline switch and second adapter exists
9009
mov cx, 0040h ; 0040h is supposed to work in both rm/pm
9011
mov cx, cs:[oldcsrpos]
9012
and byte ptr ds:[10h], not 30h
9015
or byte ptr ds:[10h], 30h
9034
;--- this is low-level, called on entry into the debugger.
9035
;--- the debuggee's registers have already been saved here.
9036
;--- 1. save IVT vectors 23/24 ("debuggee's") to [run2324]
9037
;--- 2. restore IVT vectors 23/24 ("debugger's") from PSP:[CCIV]
9039
;--- Int 21h should not be used here!
9042
mov di,offset run2324
9052
movsw ;save interrupt vector 23h
9054
movsw ;save interrupt vector 24h
9065
mov si,PSPS.CCIV ;move from debugger's PSP to IVT
9080
mov si, offset dbg2324
9084
sizeprf ;mov [di+0],edx
9088
sizeprf ;xor edx, edx
9109
; The next three subroutines concern the handling of INT 23 and 24.
9110
; These interrupt vectors are saved and restored when running the
9111
; child process, but are not active when DEBUG itself is running.
9112
; It is still useful for the programmer to be able to check where INT 23
9113
; and 24 point, so these values are copied into the interrupt table
9114
; during parts of the c, d, e, m, and s commands, so that they appear
9115
; to be in effect. The e command also copies these values back.
9116
; Between calls to dohack and unhack, there should be no calls to DOS,
9117
; so that there is no possibility of these vectors being used when
9118
; the child process is not running.
9120
;--- for protected-mode, this whole procedure with prepare-do-undo is
9121
;--- pretty useless - hence all three procs are dummies while in pm.
9122
;--- OTOH, it might be useful, to adjust the DI cmd in protected-mode
9123
;--- to return the debuggee's vectors for 23h/24h.
9125
; PREPHACK - Set up for interrupt vector substitution.
9126
; save current value of Int 23/24 (debugger's) to sav2324
9132
jnz @F ;if hack status error
9134
mov di,offset sav2324 ;debugger's Int2324
9135
call store2324 ;copy IVT 23/24 to di (real-mode only)
9138
@@: ;this is actually a programming error!
9141
mov dx,offset ph_msg ;'error in sequence of calls to hack'
9142
call int21ah9 ;print string
9153
ph_msg db 'Error in sequence of calls to hack.',CR,LF,'$'
9156
;--- get current int 23/24, store them at ES:DI
9157
;--- DI is either sav2324 (debugger's) or run2324 (debuggee's)
9162
jnz _ret ;nothing to do if in PM
9181
; DOHACK - set debuggee's int 23/24
9184
; DOHACK/UNHACK: It's OK to do either of these twice in a row.
9185
; In particular, the 's' command may do unhack twice in a row.
9191
call ispm_dbg ; v2.0: dohack is dummy in protected-mode
9195
mov si,offset run2324 ;debuggee's interrupt vectors
9200
;--- UNHACK - set debugger's int 23/24
9201
;--- Entry ds = dgroup
9208
jnz _ret ; v2.0: unhack is dummy now
9211
mov si,offset sav2324 ;debugger's interrupt vectors
9231
;--- InDos: return NZ if DOS cannot be used
9234
if ( BOOTDBG or RING0 )
9243
mov si,word ptr [pInDOS+0]
9246
mov ds, word ptr cs:[pInDOS+2]
9264
mov dx, offset bChar
9282
; GETLINE - Print a prompt (address in DX, length in CX) and read a line
9284
; GETLINE0 - Same as above, but use the output line (so far), plus two
9285
; spaces and a colon, as a prompt.
9286
; GETLINE00 - Same as above, but use the output line (so far) as a prompt.
9287
; Entry CX Length of prompt (getline only)
9288
; DX Address of prompt string (getline only)
9290
; DI Address + 1 of last character in prompt (getline0 and
9293
; Exit AL First nonwhite character in input line
9294
; SI Address of the next character after that
9295
; Uses AH,BX,CX,DX,DI
9298
mov ax,' ' ;add two spaces and a colon
9303
mov dx,offset line_out
9308
mov [promptlen],cx ;save length of prompt
9309
call stdout ;write prompt (string DX, size CX)
9311
test [fStdin], AT_DEVICE
9312
jnz gl5 ;jmp if tty input
9314
mov [lastcmd], offset dmycmd
9316
; This part reads the input line from a file (in the case of
9317
; 'debug < file'). It is necessary to do this by hand because DOS
9318
; function 0ah does not handle EOF correctly otherwise. This is
9319
; especially important for debug because it traps Control-C.
9325
mov dx,offset line_in + 2
9327
call stdout ;print out the received line
9332
;--- input a line if stdin is a device (tty)
9333
mov dx,offset line_in
9337
mov ah,0ah ;buffered keyboard input
9343
mov si,offset line_in + 2
9393
mov byte ptr [di-1],al
9409
; FILLBUF - Fill input buffer, read from a file.
9410
; called by getline & within 'e' cmd in interactive mode.
9411
; Exit SI Next readable byte
9412
; Carry flag is set if and only if there is an error (e.g., eof)
9420
mov si, offset line_in+2
9423
;--- read input bytewise until LF.
9424
;--- note that debug expects CR/LF pairs -
9425
;--- lines with just LF as EOL marker won't do.
9429
cmp dx, offset line_in+LINE_IN_LEN ; "line too long" is treated as EOF
9433
mov ah, 3fh ; read file
9442
dec si ; the LF itself should NOT be handled by the cmds.
9458
; PARSECM - Parse arguments for C and M commands.
9459
; Entry AL First nonwhite character of parameters
9460
; SI Address of the character after that
9461
; Exit DS:(E)SI Address from first parameter
9462
; ES:(E)DI Address from second parameter
9463
; (E)CX Length of address range minus one
9464
; m cmd in real-mode expects dst segm:ofs in BX:DX
9469
call getrangeDS ;get address range into bx:(e)dx bx:(e)cx
9470
push bx ;save segment first address ( src for m cmd )
9476
push edx ;save offset first address
9482
sub cx,dx ;number of bytes minus one
9484
;--- there's just one scratch selector
9485
;--- but m & c may require another one for the addr argument behind the range.
9486
;--- so if the range's segment is scratchsel,
9487
;--- change it to FLAT
9488
test byte ptr [regs.rFL+2], 2 ;v86-mode?
9490
cmp bx, [scratchsel]
9496
movzx ebx, [scratchv86]
9511
;--- get the second ( destination ) address
9513
@movs bx,[regs.rDS] ; DS = default for "destination"
9518
call getaddr ;get address into bx:(e)dx
9519
mov [bAddr32],1 ;restore bAddr32
9533
call getaddr ;get destination address into bx:(e)dx
9537
jc errorj7 ;if it wrapped around
9538
call chkeol ;expect end of line
9551
; PARSELW - Parse command line for L and W commands.
9553
; Entry AL First nonwhite character of parameters
9554
; SI Address of the character after that
9556
; Exit If there is at most one argument (program load/write), then the
9557
; zero flag is set, and registers are set as follows:
9558
; bx:(e)dx Transfer address
9560
; If there are more arguments (absolute disk read/write), then the
9561
; zero flag is clear, and registers are set as follows:
9565
; CX Number of sectors to read
9566
; DX Beginning logical sector number
9567
; DS:BX Transfer address
9571
; BX Offset of packet
9575
mov bx,[regs.rCS] ;default segment
9576
mov dx,100h ;default offset
9578
je plw2 ;if no arguments
9579
;--- v2.0: added IsWriteableBX since getaddr will no longer translate BX
9580
;--- to a writeable selector.
9581
call getaddr ;get buffer address into bx:(e)dx
9587
je plw2 ;if only one argument
9588
push bx ;save segment
9589
push dx ;save offset
9590
mov bx,80h ;max number of sectors to read
9592
jz @F ;if address is zero
9594
shr dx,cl ;max number of sectors which can be read
9597
call getbyte ;get drive number (DL)
9602
call getdword ;get relative sector number
9604
push bx ;save sector number high
9605
push dx ;save sector number low
9606
push si ;in case we find an error
9607
call getword ;get sector count
9610
jae errorj7 ;if too many sectors
9613
call chkeol ;expect end of line
9615
jnz plw3 ;if new-style packet called for
9616
pop si ;in case of error
9617
pop dx ;get LoWord starting logical sector number
9619
or bx,bx ;just a 16bit sector number possible
9620
jnz errorj7 ;if too big
9621
pop ax ;drive number
9622
pop bx ;transfer buffer ofs
9623
pop ds ;transfer buffer seg
9624
or cx,cx ;set nonzero flag
9628
;--- new style packet, [usepacket] != 0
9632
mov bx,offset packet
9633
pop word ptr [bx].PACKET.secno+0
9634
pop word ptr [bx].PACKET.secno+2
9635
mov [bx].PACKET.numsecs,cx
9636
pop ax ;drive number
9637
pop word ptr [bx].PACKET.dstofs
9648
mov [bx].PACKET32.dstseg,dx
9650
shr edx,16 ;get HiWord(offset)
9657
mov [bx].PACKET.dstseg,dx ;PACKET.dstseg or HiWord(PACKET32.dstofs)
9658
dec cx ;set nonzero flag and make cx = -1
9664
; PARSE_PT - Parse 'p' or 't' command.
9665
; Entry AL First character of command
9666
; SI Address of next character
9667
; Exit CX Number of times to repeat
9671
call parseql ;get optional <=addr> argument
9672
call skipcomm0 ;skip any white space
9673
mov cx,1 ;default count
9675
je @F ;if no count given
9677
call chkeol ;expect end of line here
9679
jcxz errorj10 ;must be at least 1
9681
; call seteq ;make the = operand take effect
9685
; PARSEQL - Parse '=' operand for 'g', 'p' and 't' commands.
9686
; Entry AL First character of command
9687
; SI Address of next character
9688
; Exit AL First character beyond range
9689
; SI Address of the character after that
9690
; eqflag Nonzero if an '=' operand was present
9691
; eqladdr Address, if one was given
9692
; Uses AH,BX,CX,(E)DX.
9696
mov bx,[regs.rCS] ;default segment
9699
jne peq1 ;if no '=' operand
9702
sizeprf ;xor edx, edx
9708
call getaddr ;get address into bx:(e)dx
9709
sizeprfX ;mov [eqladdr+0],edx
9712
test byte ptr [regs.rFL+2],2
9714
mov bx,[scratchv86] ; don't store the scratch selector in eqladdr - must be a segment value in v86
9722
; SETEQ - Copy the = arguments to their place, if appropriate. This
9723
; is not done immediately, because the g/p/t cmds may have syntax errors.
9727
cmp [eqflag],'=' ;'=' argument given?
9729
sizeprfX ;mov eax,[eqladdr+0]
9731
sizeprfX ;mov [regs.rIP+0],eax
9735
mov [eqflag],0 ;clear the flag
9740
;--- get a valid offset for segment in BX
9741
;--- in: BX=segment/selector
9742
;--- out: offset in (E)DX
9760
sizeprfX ; v2.0: xor edx,edx
9763
; @dprintf "getofsforbx: edx=%lX", edx
9770
;--- a range is entered with the L/ength argument
9771
;--- get a valid length for segment in BX
9772
;--- L=0 means 64 kB (at least in 16bit mode)
9773
;--- return with NC if value ok.
9801
; jcxz glfbx_2 ;0 means 64k
9803
add cx,dx ;C if it wraps around
9808
;--- get range with default segment DS
9815
; getrange - Get address range from input line.
9816
; a range consists of:
9817
; 1. a start address: [segment:]start-offset
9818
; 2. an end-offset or a 'L' followed by a length.
9819
; Entry AL First character of range
9820
; SI Address of next character
9821
; BX Default segment to use
9822
; (E)CX Default length to use (or 0 if not allowed)
9823
; Exit AL First character beyond range
9824
; SI Address of the character after that
9825
; BX:(E)DX First address in range
9826
; BX:(E)CX Last address in range
9829
getrange proc ; used by c, d, m, s, u cmds
9831
call getaddr ;get address into bx:(e)dx (sets bAddr32 if ?PM)
9836
pop si ;restore si and cx
9838
jcxz errorj10 ;if a range is mandatory
9840
call IsOfs32 ;can be NZ only on a 80386+
9845
jnc gr1 ;if no wraparound
9846
or ecx,-1 ;go to end of segment
9852
jnc gr1 ;if no wraparound
9853
mov cx,0ffffh ;go to end of segment
9862
je gr3 ;if a range is given
9863
; call skipwh0 ;get next nonblank
9883
ja errorj2 ;if empty range
9887
call skipcomma ;discard the 'l'
9891
add sp,4 ;discard saved cx, si
9898
; getaddr - Get address from input line.
9899
; Entry AL First character of address
9900
; SI Address of next character
9901
; BX Default segment to use
9902
; Exit AL First character beyond address
9903
; SI Address of the character after that
9904
; BX:(E)DX Address found
9911
cmp al, '$' ; a real-mode segment?
9928
cmp al, '%' ; a linear address?
9933
;--- hack for a/u cmds: allow to enter a real-mode address.
9934
;--- since DebugR[L] cannot handle v86-mode exceptions,
9935
;--- this hack allows to at least (dis)assemble real-mode code parts.
9939
;--- in v86-mode, '$' is unknown
9940
test byte ptr [regs.rFL+2],2 ; syntax NOT valid in v86-mode
9943
cmp [lastcmd], offset u_cmd ; u cmd?
9945
cmp [errret], offset cmdloop; a cmd?
9953
call setscratchsel ; set BX to scratchsel
9957
cmp al,'#' ; segment part is a selector?
9959
test byte ptr [regs.rFL+2],2 ; syntax valid only in v86-mode
9963
@dprintf "getaddr: # detected, selector=%X ax=%X", dx, ax
9976
je ga2 ;if this is a segment descriptor
9983
pop ax ;throw away saved si
9984
@movs bx,dx ;mov segment into BX
9986
call skipwhite ;skip to next word
9988
mov [bAddr32],0 ;v2.0: init bAddr32, will be set if limit > 64k
9992
@dprintf "getaddr: bx:edx=%X:%lX, bAddr32=%X", bx, edx, word ptr [bAddr32]
9997
; GETSTR - Get string of bytes. Put the answer in line_out.
9998
; Entry AL first character
9999
; SI address of next character
10000
; Exit [line_out] first byte of string
10001
; DI address of last+1 byte of string
10005
mov di,offset line_out
10007
je errorj2 ;we don't allow empty byte strings
10013
call getbyte;byte in DL
10014
mov [di],dl ;store the byte
10019
mov ah,al ;save quote character
10023
je gs5 ;if possible end of string
10025
je errorj2 ;if end of line
10027
stosb ;save character and continue
10033
je gs4 ;if doubled quote character
10035
call skipcomm0 ;go back for more
10037
jne gs1 ;if not done yet
10041
;--- in: AL=first char
10043
;--- out: value in BX:DX
10049
mov di,offset regnames
10051
mov ah,[si] ;get second char of name
10053
cmp byte ptr [si+1],'A'
10054
jnc maybenotasymbol
10058
mov di, [di+NUMREGNAMES*2 - 2]
10061
inc si ;skip over second char
10068
cmp al,'E' ;386 standard register names start with E
10075
mov di,offset regs.rIP
10078
mov cx,8 ;scan for the 8 standard register names only
10081
mov di,[di+NUMREGNAMES*2 - 2]
10083
mov bx,[di+2] ;get HiWord of DWORD register
10094
; GETDWORD - Get (hex) dword from input line.
10095
; Entry AL first character
10096
; SI address of next character
10098
; AL first character not in the word
10099
; SI address of the next character after that
10109
jc errorj6 ;if error
10112
xor bx,bx ;clear high order word
10118
jnz errorj6 ;if too big
10121
shl dx,1 ;double shift left
10133
; GETWORD - Get (hex) word from input line.
10134
; Entry AL first character
10135
; SI address of next character
10137
; AL first character not in the word
10138
; SI address of the next character after that
10144
and bx,bx ;hiword clear?
10146
jnz errorj6 ;if error
10150
; GETBYTE - Get (hex) byte from input line into DL.
10151
; Entry AL first character
10152
; SI address of next character
10154
; AL first character not in the word
10155
; SI address of the next character after that
10161
jnz errorj6 ;if error
10164
;--- GETNYB - Convert the hex character in AL into a nybble. Return
10165
;--- carry set in case of error.
10171
jbe gn1 ;if normal digit
10177
ja gn2 ;if not a-f or A-F
10180
inc sp ;normal return (first pop old AX)
10185
pop ax ;error return
10189
;--- CHKEOL1 - Check for end of line.
10194
jne errorj8 ;if not found
10200
; SKIPCOMMA - Skip white space, then an optional comma, and more white
10202
; SKIPCOMM0 - Same as above, but we already have the character in AL.
10209
jne sc2 ;if no comma
10213
jne sc1 ;if not end of line
10218
add sp,2 ;pop si into nowhere
10222
;--- SKIPALPHA - Skip alphabetic character, and then white space.
10231
; jmp skipwhite ;(control falls through)
10233
;--- SKIPWHITE - Skip spaces and tabs.
10234
;--- SKIPWH0 - Same as above, but we already have the character in AL.
10245
;--- IFSEP Compare AL with separators ' ', '\t', ',', ';', '='.
10260
;--- disassembler code
10262
include <DISASM.INC>
10264
; SHOWMACH - Return strings
10265
; "[needs _86]" or "[needs _87]",
10266
; "[needs math coprocessor]" or "[obsolete]"
10267
; Entry di -> table of obsolete instructions ( 5 items )
10269
; Exit si Address of string
10270
; cx Length of string, or 0 if not needed
10274
mov si,offset needsmsg ;candidate message
10275
test [ai.dmflags],DM_COPR
10276
jz is_cpu ;if not a coprocessor instruction
10277
mov byte ptr [si+9],'7' ;change message text ('x87')
10280
jnz sm2 ;if it has a coprocessor
10282
cmp al,[ai.dismach]
10283
jb sm3 ;if we display the message
10284
mov si,offset needsmath ;print this message instead
10285
mov cx,sizeof needsmath
10289
mov byte ptr [si+9],'6' ;reset message text ('x86')
10292
cmp al,[ai.dismach]
10293
jae sm4 ;if no message (so far)
10295
mov al,[ai.dismach]
10298
mov cx,sizeof needsmsg ;length of the message
10301
;--- Check for obsolete instruction.
10304
mov si,offset obsolete ;candidate message
10305
mov ax,cx ;get info on this instruction
10308
jne @F ;if no matches
10309
mov di,offset obsmach + 5 - 1
10311
xor cx,cx ;clear CX: no message
10314
jle @F ;if this machine is OK
10315
mov cx,sizeof obsolete
10320
;--- DUMPREGS - Dump registers and print 1 disassembled line at CS:EIP.
10323
; @dprintf "dumpregs"
10324
mov si,offset regnames
10325
mov di,offset line_out
10327
mov bx,offset regfmt16
10328
test [rmode],RM_386REGS
10330
mov bx,offset regfmt32
10337
call word ptr [bx+1]
10339
test byte ptr [bx],80h
10344
add bx, sizeof FMTITEM
10355
;--- display 1 disassembled line at CS:[E]IP
10357
mov si, offset regs.rIP
10358
mov di, offset u_addr
10361
@movs ax,[regs.rCS] ; problem: if V86M and v86-mode, this will be the scratch sel
10363
mov al, DIS_F_REPT or DIS_F_SHOW
10366
;--- 'r' resets default setting for 'u' to CS:[E]IP
10368
sizeprf ; mov eax, [regs.rIP]
10370
sizeprf ; mov [u_addr], eax
10379
;--- 16bit: 8 std regs, NL, skip 2, 4 seg regs, IP, flags
10380
;--- 32bit: 6 std regs, NL, 2 std regs+IP+FL, flags, NL, 6 seg regs
10383
regfmt16 FMTITEM <88h,dmpr1w>,<2,skipregs>,<4,dmpr1w>,<1,dmpip>,<80h,dmpflags>
10384
regfmt32 label FMTITEM
10385
FMTITEM <86h,dmpr1d>
10387
FMTITEM <80h,dmpflags>
10389
FMTITEM <86h,dmpr1w>
10396
mov si, offset regnames+10*2 ; just position SI to segment regs
10400
mov si, offset regnames+8*2
10403
;--- Function to print multiple WORD register entries.
10404
;--- SI->register names (2 bytes)
10411
mov bx,[si+NUMREGNAMES*2-2]
10419
;--- Function to print multiple DWORD register entries.
10420
;--- SI->register names (2 bytes)
10429
mov bx,[si+NUMREGNAMES*2-2]
10443
pl0esp db "[PL0 SS:ESP="
10449
test byte ptr [regs.rFL+2],2
10456
mov si, offset pl0esp
10457
mov cl, sizeof pl0esp
10459
mov ax, [regs.r0SS]
10463
mov eax, [regs.r0Esp]
10479
include <FPTOSTR.INC>
10482
;--- the layout for FSAVE/FRSTOR depends on mode and 16/32bit
10491
opc dw ? ;real-mode: opcode[0-10], ip 16-19 in high bits
10492
fcs dw ? ;protected-mode: ip selector
10494
fop dw ? ;operand ptr offset
10496
foph dw ? ;real-mode: operand ptr 16-19 in high bits
10497
fos dw ? ;protected-mode: operand ptr selector
10508
fip dd ? ;ip offset (real-mode: bits 0-15 only)
10511
fopcr dd ? ;real-mode: opcode (0-10), ip (12-27)
10514
fcs dw ? ;protected-mode: ip selector
10515
fopcp dw ? ;protected-mode: opcode(bits 0-10)
10518
foo dd ? ;operand ptr offset (real-mode: bits 0-15 only)
10521
fooh dd ? ;real-mode: operand ptr (12-27)
10524
fos dw ? ;protected-mode: operand ptr selector
10525
dw ? ;protected-mode: not used
10532
fregnames label byte
10533
db "CW", "SW", "TW"
10534
db "OPC=", "IP=", "DP="
10539
;--- dumpregsFPU - Dump Floating Point Registers
10540
;--- modifies SI, DI, [E]AX, BX, CX, [E]DX
10541
;--- Note: value of CR0 bits 1=MP,2=EM,3=TS may have unwanted effects:
10542
;--- 1. if MP=1 and TS=1, an fwait will raise exc 07
10543
;--- 2. if EM=1, any fpu opcode will raise exc 07.
10548
mov dx, offset fpuemerr
10550
test al, 4 ;CR0.EM=1?
10554
mov di,offset line_out
10555
mov si,offset fregnames
10556
mov bx,offset line_in + 2
10560
;--- display CW. SW and TW
10578
;--- in 16bit format protected-mode, there's no OPC
10579
;--- for 32bit, there's one, but the location is different from real-mode
10585
add bx,2 ;location of OPC in protected-mode differs from real-mode!
10588
add si,4 ;no OPC for FPENV16 in protected-mode
10596
lodsw ;skip word/dword
10599
and ax,07FFh ;bits 0-10 only
10606
;--- display IP and DP
10608
mov cl,2 ;ch is 0 already
10616
sizeprf ;mov edx,eax
10631
sizeprf ;shr eax,cl
10638
call hexnyb ;convert to hex digit and print
10640
sizeprfX ;mov eax,edx
10661
;--- display ST0 - ST7
10665
pop dx ;get CW (not used)
10668
shr ax, cl ;mov TOP to bits 1-3
10674
nextst: ;<- next float to display
10675
mov di,offset line_out
10685
ror bp,1 ;remain 8086 compatible here!
10687
and al,3 ;00=valid,01=zero,02=NaN,03=Empty
10689
mov si,offset dEmpty
10690
mov cl, sizeof dEmpty
10694
mov cl, sizeof dNaN
10726
cmp di, offset line_out+26
10738
add si,10 ;sizeof TBYTE
10742
.286 ;avoid WAIT prefix
10744
frstor [line_in + 2]
10749
;--- DMPFLAGS - Dump flags output.
10752
mov si,offset flgbits
10753
mov cx,8 ;lengthof flgbits
10758
jz @F ;if not asserted
10771
fnsaved [line_in + 2]
10772
mov si,offset line_in + 7*4 + 2
10774
; mov di, offset line_out
10804
mov di,offset line_out
10809
fldenvd [line_in + 2]
10815
;--- copystring - copy non-empty null-terminated string.
10818
;--- modifies SI, DI, AL
10830
;--- display 16/32-bit offset in E/AX
10834
test [bCSAttr], CS32
10840
; HEXDWORD - Print hex dword (in EAX).
10841
; clears HiWord(EAX)
10843
; HEXWORD - Print hex word (in AX).
10844
; HEXBYTE - Print hex byte (in AL).
10845
; HEXNYB - Print hex digit.
10855
hexdword endp ;fall through!
10862
hexword endp ;fall through!
10882
add al,90h ;these four instructions change to ascii hex
10889
; TRIMPUTS - Trim excess blanks from string and print (with CR/LF).
10890
; PUTSLINE - Add CR/LF to string and print it.
10891
; PUTS - Print string through DI.
10895
cmp byte ptr [di],' '
10900
mov ax,LF * 256 + CR
10905
mov dx,offset line_out
10909
;--- stdout: write DS:DX, size CX to STDOUT (1)
10919
mov bx,1 ;standard output
10920
mov ah,40h ;write to file
10924
@@: ;use BIOS for output
10931
mov bh,[vpage] ;v2.0: use the current video page
10932
cmp al, TAB ;v2.0: handle tabs
10949
;--- interpret TAB in BIOS output
10963
and cx, 7 ; 0 1 2 3 4 5 6 7
10964
sub cl, 8 ;-8 -7 -6 -5 -4 -3 -2 -1
10965
neg cl ; 8 7 6 5 4 3 2 1
10986
include <DPRINTFR.INC>
10988
include <DPRINTF.INC>
10995
createdummytask proc
10997
@dprintf "createdummytask"
10998
mov di, offset regs
10999
mov cx, sizeof regs / 2
11003
mov ah,48h ;get largest free block
11006
cmp bx,11h ;must be at least 110h bytes!!!
11008
mov ah,48h ;allocate it
11010
jc ct_done ;shouldn't happen
11012
inc byte ptr [regs.rIP+1] ;set IP=100h
11014
call setespefl ; set regs.rSP/rFL
11017
mov di,offset regs.rDS ;init regs.rDS,regs.rES
11020
mov di,offset regs.rSS ;init regs.rSS,regs.rCS
11023
call setup_adu ; setup default for a/d/u cmds
11024
xchg ax, bx ; bx = CS; bx:dx = where to load program
11026
pop ax ;get size of memory block
11029
mov es:[PSPS.ALASAP],dx
11031
jbe @F ;if memory left <= 64K
11032
xor ax,ax ;ax = 1000h (same thing, after shifting)
11039
xchg ax,di ;es:di = child stack pointer
11041
stosw ;push 0 on client's stack
11045
mov ah,55h ;create child PSP
11047
mov si,es:[PSPS.ALASAP]
11048
clc ;works around OS/2 bug
11050
mov word ptr es:[PSPS.TPIV+0],offset intr22
11051
mov word ptr es:[PSPS.TPIV+2],cs
11055
mov byte ptr es:[100h],0C3h ;place opcode for 'RET' at CS:IP
11059
;--- set owner and name to newly created PSP
11065
mov byte ptr es:[0008],0
11066
push ds ;restore ES
11069
call getint2324 ; v2.0 init [run2324]
11071
call setpspdbg ;set debugger's PSP
11075
createdummytask endp
11081
;--- hook int 2Fh if a DPMI host is found
11082
;--- for Win3x/9x and DosEmu host
11083
;--- int 2Fh, ax=1687h is not hooked, however
11084
;--- because it doesn't work. Debugging
11085
;--- in protected-mode still may work, but
11086
;--- the initial-switch to PM must be single-stepped
11087
;--- modifies AX, BX, CX, DX, DI
11093
cmp word ptr [oldi2f+2],0
11095
mov ax,1687h ;DPMI host installed?
11099
mov word ptr [dpmientry+0],di ;true host DPMI entry
11100
mov word ptr [dpmientry+2],es
11101
mov word ptr [dpmiwatch+0],di
11102
mov word ptr [dpmiwatch+2],es
11103
cmp [bNoHook2F],0 ;can int 2Fh be hooked?
11105
mov word ptr [dpmiwatch+0],offset mydpmientry
11106
mov word ptr [dpmiwatch+2],cs
11109
mov word ptr [oldi2f+0],bx
11110
mov word ptr [oldi2f+2],es
11111
mov dx,offset debug2F
11112
@dprintf "hook2f: new int2F vector=%X:%X", ds, dx
11119
;--- don't use line_out here!
11120
mov di,offset line_in + 128
11122
mov si,offset dpmihook
11129
mov ax,offset mydpmientry
11131
mov ax,LF * 256 + CR
11151
mov ds, cs:[wDgroup]
11158
mov si, offset inttab
11159
mov di, offset intsave
11161
movzx edx, byte ptr [si]
11164
mov es:[ebx+edx+0], ax
11166
mov es:[ebx+edx+6], ax
11168
mov es:[ebx+edx+2], ax
11169
add si, sizeof INTITEM
11170
add di, sizeof INTVEC
11178
endoftext16 label byte
11184
;--- I/O buffers. (End of permanently resident part.)
11186
line_in db 255,0,CR ;length = 257
11187
line_out equ line_in+LINE_IN_LEN+1;length = 1 + 263
11188
real_end equ line_in+LINE_IN_LEN+1+264
11196
bHWBPflgs db HWBP_ACTIVE
11207
dd 0DEADBEEFh ; marker for start of _ITEXT, don't remove!
11210
;--- initcont is located at the start of _ITEXT because either
11211
;--- a word is written into this segment ( the "mov [bx], ..." below )
11212
;--- or SP has to be adjusted before memory is freed.
11213
;--- ax,bx=top of memory
11217
if DRIVER or RING0 or BOOTDBG
11219
mov [bx], offset ue_int ; make debug display "unexpected interrupt"
11230
mov es, [wDgroup] ; copy debugger beyond conv. memory
11239
lss esp, [regs.r0SSEsp] ; switch stack back
11241
and byte ptr [esp+1], 0BFh ; reset NT flag
11250
mov [bInDbg], 1 ; v2.01: variable is set only when debug is entered via interrupt
11262
int 21h ;free rest of DOS memory
11263
mov byte ptr [line_out-1],'0' ;initialize line_out?
11267
push ds ; loadfile expects ds=es=dgroup
11278
;---------------------------------------
11279
;--- Debug initialization code.
11280
;---------------------------------------
11283
ife (DRIVER or BOOTDBG or RING0)
11286
imsg1 db DBGNAME,' version ',@CatStr(!',%VERSION,!'),CR,LF,LF
11287
db 'Usage: ', DBGNAME, ' '
11288
if ALTVID or USEHWBP
11291
db '[[drive:][path]progname [arglist]]',CR,LF
11292
if ALTVID or USEHWBP
11293
db ' options:',CR,LF
11295
db ' /2: use alternate video adapter for output if available',CR,LF
11298
db ' /s: hardware breakpoints switched off',CR,LF
11300
db ' /v: allow hardware breakpoints in v86 mode',CR,LF
11304
db ' progname: (executable) file to debug or examine',CR,LF
11305
db ' arglist: parameters given to program',CR,LF,LF
11306
db 'For a list of debugging commands, '
11307
db 'run ', DBGNAME, ' and type ? at the prompt.',CR,LF,'$'
11309
imsg2 db 'Invalid switch - '
11310
imsg2a db 'x',CR,LF,'$'
11316
dDosEmuDate db "02/25/93"
11321
szDebxxVdd db "DEBXXVDD.DLL",0
11322
szDispatch db "Dispatch",0
11330
units db ? ;+13 number of supported units
11331
endaddr dd ? ;+14 end address of resident part
11332
cmdline dd ? ;+18 address of command line
11335
driver_entry proc far
11339
lds di, cs:[request_ptr] ; load address of request header
11340
mov [di].req_hdr.status,0100h
11352
mov [Intrp],offset interrupt
11353
mov dx,offset drv_installed
11363
mov word ptr [di].init_req.endaddr+0,bx ; if bx == 0, driver won't be installed
11364
mov word ptr [di].init_req.endaddr+2,cs ; set end address
11370
db "DEBUGX device driver installed",13,10,'$'
11376
mov dx,offset cantrun
11382
db DBGNAME2, "g v",@CatStr(!',%VERSION,!')," is a device driver variant of Debug/X.",13,10
11383
db "It's supposed to be loaded in CONFIG.SYS via 'DEVICE=",DBGNAME2,"g.exe'.",13,10
11388
;--- initialization.
11389
;--- BOOTDBG: no cmdline
11390
;--- RING0: ESI -> cmdline ( linear address )
11391
;--- DRIVER: cmdline in init_req.cmdline
11392
;--- anything else: PSP:80h
11393
;--- register (E)BP must be preserved!
11404
;--- loword(ax): dgroup selector
11405
;--- hiword(ax): scratch selector
11406
;--- cx: flat data selector
11407
;--- bp: size dgroup ( also, value of SP during init )
11408
;--- ebx: offset output routine (int 10h)
11409
;--- edx: offset input routine (int 16h)
11413
CS64SEL equ 8 ; to be fixed: 64-bit code selector for DebugRL is 8 (Dos32cm)
11421
mov [scratchsel], ax
11428
@checkss ; ensure hiword esp isn't trashed
11430
mov ax, [esp+2*2+4] ; get caller's CS
11431
mov dword ptr [int10vec+0], ebx
11432
mov word ptr [int10vec+4], ax
11433
mov dword ptr [int16vec+0], edx
11434
mov word ptr [int16vec+4], ax
11436
;--- set ring0 stack so output is possible during init
11437
mov [regs.r0Esp], esp
11438
mov [regs.r0SS], ss
11440
;--- invalidate a & d segment part ( will then be reinitialized )
11468
;--- get [dwBase64] - linear address of _TEXT64
11469
;--- depends on how _TEXT64 is aligned!
11470
;--- currently align 16
11474
mov edx, offset endoftext16
11475
add dx, TEXT64ALIGN-1
11476
and dx, not TEXT64ALIGN-1
11478
mov [dwBase64], eax
11479
@dprintf "initcode: dwBase64=%lX, start TEXT64=%X", eax, dx
11488
push edi ; addr IDT now at [e/bp-6]
11489
@dprintf "initcode: cs=%X, ds=%X, flat=%X, ebp=%lX, es:edi=%X:%lX, esi=%lX", cs, ds, cx, ebp, es, edi, esi
11516
mov word ptr [execblk.cmdtail+2],ax
11517
mov word ptr [execblk.fcb1+2],ax
11518
mov word ptr [execblk.fcb2+2],ax
11523
mov [wDgroup], ax ; this will set alias [pspdbg] if FMTEXE==0
11525
;--- Check for console input vs. input from a file or other device.
11528
mov ax,4400h ;IOCTL--get info
11534
mov ax,4400h ;IOCTL--get info
11544
; Determine the processor type. This is adapted from code in the
11545
; Pentium<tm> Family User's Manual, Volume 3: Architecture and
11546
; Programming Manual, Intel Corp., 1994, Chapter 5. That code contains
11547
; the following comment:
11549
; This program has been developed by Intel Corporation.
11550
; Software developers have Intel's permission to incorporate
11551
; this source code into your software royalty free.
11553
; Intel 8086 CPU check.
11554
; Bits 12-15 of the FLAGS register are always set on the 8086 processor.
11555
; Probably the 186 as well.
11560
jnz init6 ;if 8086 or 80186 (can't tell them apart)
11562
; Intel 286 CPU check.
11563
; Bits 12-15 of the flags register are always clear on the
11564
; Intel 286 processor in real-address mode.
11567
pushf ;get original flags into AX
11569
or ax,0f000h ;try to set bits 12-15
11570
push ax ;save new flags value on stack
11571
popf ;replace current flags value
11572
pushf ;get new flags
11573
pop ax ;store new flags in AX
11574
test ah,0f0h ;if bits 12-15 clear, CPU = 80286
11577
; Intel 386 CPU check.
11578
; The AC bit, bit #18, is a new bit introduced in the EFLAGS
11579
; register on the Intel486 DX cpu to generate alignment faults.
11580
; This bit cannot be set on the Intel386 CPU.
11584
; It is now safe to use 32-bit opcode/operands.
11587
inc [bHWBPflgs] ; bit 0=1 (HWBP_ACTIVE)
11594
mov bx,sp ;save current stack pointer to align
11595
and sp,not 3 ;align stack to avoid AC fault
11596
pushfd ;push original EFLAGS
11597
pop eax ;get original EFLAGS
11598
mov ecx,eax ;save original EFLAGS in CX
11599
xor eax,40000h ;flip (XOR) AC bit in EFLAGS
11600
push eax ;put new EFLAGS value on stack
11601
popfd ;replace EFLAGS value
11602
pushfd ;get new EFLAGS
11603
pop eax ;store new EFLAGS value in EAX
11605
jz init5 ;if 80386 CPU
11607
; Intel486 DX CPU, Intel487 SX NDP, and Intel486 SX CPU check.
11608
; Checking for ability to set/clear ID flag (bit 21) in EFLAGS
11609
; which indicates the presence of a processor with the ability
11610
; to use the CPUID instruction.
11612
; inc [machine] ;it's a 486
11613
mov eax,ecx ;get original EFLAGS
11614
xor eax,200000h ;flip (XOR) ID bit in EFLAGS
11615
push eax ;save new EFLAGS value on stack
11616
popfd ;replace current EFLAGS value
11617
pushfd ;get new EFLAGS
11618
pop eax ;store new EFLAGS in EAX
11619
cmp eax,ecx ;check if it's changed
11620
je init5 ;if it's a 486 (can't toggle ID bit)
11622
popfd ;restore AC bit in EFLAGS first
11623
mov sp,bx ;restore original stack pointer
11625
;--- Execute CPUID instruction.
11629
xor eax,eax ;set up input for CPUID instruction
11632
jl init6 ;if 1 is not a valid input value for CPUID
11633
xor eax,eax ;otherwise, run CPUID with ax = 1
11641
and al,0fh ;bits 8-11 are the model number
11644
mov al,6 ;if > 6, set it to 6
11646
mov [machine],al;save it
11647
jmp init6 ;don't restore SP
11651
popfd ;restore AC bit in EFLAGS first
11652
mov sp,bx ;restore original stack pointer
11655
.8086 ;back to 1980s technology
11658
; Next determine the type of FPU in a system and set the mach_87
11659
; variable with the appropriate value.
11661
; Coprocessor check.
11662
; The algorithm is to determine whether the floating-point
11663
; status and control words can be written to. If not, no
11664
; coprocessor exists. If the status and control words can be
11665
; written to, the correct coprocessor is then determined
11666
; depending on the processor ID. The Intel386 CPU can
11667
; work with either an Intel 287 NDP or an Intel387 NDP.
11668
; The infinity of the coprocessormust be checked
11669
; to determine the correct coprocessor ID.
11677
BPOFS equ <ebp-8> ; for RING0, there're already 6 bytes used
11679
BPOFS equ <bp-8> ; for RING0, there're already 6 bytes used
11683
mov [mach_87],al ;by default, set mach_87 to machine
11685
cmp al,5 ;a Pentium or above always will have a FPU
11689
fninit ;reset FP status word
11690
mov ax,5a5ah ;init with non-zero value
11692
fnstsw [BPOFS] ;save FP status word
11693
pop ax ;check FP status word
11695
jne init7 ;if no FPU present
11698
fnstcw [BPOFS] ;save FP control word
11699
pop ax ;check FP control word
11700
and ax,103fh ;see if selected parts look OK
11702
jne init7 ;if no FPU present
11703
inc [has_87] ;there's an FPU
11705
;--- If we're using a 386, check for 287 vs. 387 by checking whether
11706
;--- +infinity = -infinity.
11709
jne init7 ;if not a 386
11710
fld1 ;must use default control from FNINIT
11711
fldz ;form infinity
11712
fdivp ST(1),ST ;1 / 0 = infinity
11713
fld ST ;form negative infinity
11715
fcompp ;see if they are the same and remove them
11720
fstsw [BPOFS] ;look at status from FCOMPP
11724
jnz init7 ;if they are different, then it's a 387
11725
dec [mach_87] ;otherwise, it's a 287
11728
;--- remove size and addr prefixes if cpu is < 80386
11730
; mov [machine], 2; activate to test non-386 code branches
11735
mov si,offset patches
11740
mov byte ptr [bx],90h
11742
mov [patch_movsp],3Eh ;set ("unnecessary") DS segment prefix
11743
mov [patch_iret],0CFh ;code for IRET
11747
;--- Check DOS version
11749
ife (BOOTDBG or RING0)
11750
mov ax,3000h ;check DOS version
11754
jb init2 ;if version < 3.3, then don't use new INT 25h method
11761
cmp bx,3205h ; NTVDM?
11764
mov bHWBPflgs,0 ; no hwbp for NTVDM
11766
mov si,offset szDebxxVdd ;DS:SI->"DEBXXVDD.DLL"
11767
mov bx,offset szDispatch ;DS:BX->"Dispatch"
11768
mov di,offset szInit ;ES:DI->"Init"
11778
inc [usepacket] ;enable FAT32 access method for L/W
11782
;--- Interpret switches and erase them from the command line.
11787
mov ax,3700h ;get switch character in DL
11799
les si, cs:[request_ptr] ; load address of request header
11800
les si, es:[si].init_req.cmdline
11802
lodsb es:[si] ; skip program name
11832
;--- Process the /? switch (or the [swchar]? switch).
11833
;--- If swchar != / and /? occurs, make sure nothing follows.
11836
je @F ;if switch character
11838
jne doneoptions ;if not the help switch
11850
;helpexit: ; Print help message and exit
11851
mov dx,offset imsg1 ;command-line help message
11852
; call int21ah9 ;v2.0: int21ah9 cannot be used ( pInDOS not yet set )
11873
mov byte ptr [setscreen], 1Eh ;"push ds"
11875
mov ax, 40h ; segment value 40h even works in Jemm ring 0
11888
;--- to initially get the cursor pos of the alt screen, read the CRT.
11889
;--- this code assumes that page 0 is active ( offset == 0 );
11890
;--- could be fixed by reading CRT 0Ch/0Dh.
11905
mov [oldcsrpos], ax
11911
;--- ||| Other switches may go here.
11914
cmp al,'s' ; don't use debug registers in real-mode/protected-mode?
11920
cmp al,'v' ; use debug registers in v86-mode?
11922
or [bHWBPflgs],HWBP_V86
11928
if MCLOPT and ( CATCHINT0C or CATCHINT0D )
11929
cmp al, 'm' ; /m cmdline option?
11936
if RING0 and CATCHINT41
11937
cmp al, 'i' ; /i cmdline option?
11939
mov [itab41.bInt], -1; deactivate Int 41h hook
11945
cmp al, 'b' ; set alternate v86-monitor bp?
11947
mov [bV86Bp], 63h; assume v86 monitor bp is ARPL
11952
ife (DRIVER or RING0) ; those versions ignore invalid cmdline args
11954
mov dx,offset imsg2 ;Invalid switch
11955
; call int21ah9 ;v2.0: int21ah9 cannot be used ( pInDOS not yet set )
11958
mov ax,4c01h ;Quit and return error status
11964
ife (DRIVER or RING0)
11967
;--- if format is .EXE, the cmdline must be copied to DGROUP for n cmd.
11981
call n_cmd ; Feed the remaining command line to the 'n' command.
11991
;--- get final address of debugger behind conv. memory
11996
mov ax, offset real_end + STACKSIZ + (1024-1)
12004
mov [wDgroup], ax ; BOOTDBG: wDgroup and pspdbg must be updated!
12009
mov ah,52h ;get list of lists
12011
mov ax,es:[bx-2] ;start of MCBs
12015
ife (BOOTDBG or RING0)
12018
mov word ptr [pInDOS+0],bx
12019
mov word ptr [pInDOS+2],es
12021
;--- get address of DOS swappable DATA area
12022
;--- to be used to get/set PSP and thus avoid DOS calls
12023
;--- will not work for DOS < 3
12032
mov word ptr [pSDA+0],si
12033
mov word ptr [pSDA+2],ax
12039
;--- Windows 3x/9x and DosEmu are among those hosts which handle some
12040
;--- V86 Ints internally without first calling the interrupt chain.
12041
;--- This causes various sorts of troubles and incompatibilities.
12044
mov ax,1600h ;running in a win3x/win9x dos box?
12046
and al,al ;returns in AL 3=win3x, 4=win9x
12053
mov si,offset dDosEmuDate
12055
repe cmpsw ;running in DosEmu?
12058
jmp dpmihostchecked
12061
mov [bHWBPflgs],0; disable hw bps for DosEmu
12069
;--- setup hardware bp usage
12072
test [bHWBPflgs],HWBP_ACTIVE
12075
mov word ptr [setHWBps], ax ; patch code to NOPs
12076
mov byte ptr [resetHWBps], al
12077
mov [wStoreBP], offset storebpx
12079
mov [bcmdv], offset b_cmd ;activate b cmd (requires 80386)
12082
;--- debug register access in v86 may be supported by v86-monitor
12083
;--- jemm & qemm are ok; MS emm386 & Win3x/9x are not.
12088
jz @F ; if in real-mode
12089
test [bHWBPflgs],HWBP_V86
12090
jnz @F ; if cmdline option /v
12091
mov byte ptr v86patch,0F9h ; patch to STC, disables hwbp in v86
12106
;--- Save and modify termination address and the parent PSP field.
12109
mov di,offset psp22
12112
mov word ptr [si-4],offset intr22dbg
12120
mov es:[pspdbe], ds
12123
mov [pspdbe],cs ;indicate there is no debuggee loaded yet
12130
mov ax,4300h ; check if XMM is here
12133
jnz noxmm ; no - no screen flip
12136
mov word ptr [xmsdrv+0],bx
12137
mov word ptr [xmsdrv+2],es
12139
mov dx,32 ; alloc 32 kB EMB
12144
mov si, offset xmsmove
12145
mov [si].XMSM.dsthdl, dx ; save the handle in block move struct.
12146
mov byte ptr [si].XMSM.dstadr+1, 40h; the XMS memory will be used to
12147
push 0 ; save/restore 2 screens, with a max
12148
pop es ; capacity per screen of 16 kB
12149
mov ax,es:[44Ch] ; current screen size, might change!
12150
mov word ptr [si].XMSM.size_, ax
12151
mov ax, es:[44Eh] ; page start in video memory
12152
mov word ptr [si].XMSM.srcadr+0, ax
12154
cmp byte ptr es:[463h],0B4h
12158
mov word ptr [si].XMSM.srcadr+2, ax
12161
mov ah, 0Fh ; get active video page in BH
12163
mov ah, 3 ; get cursor pos in DX of active page
12166
mov ah, 0Bh ; save current screen now
12171
;--- use BIOS to swap page 0/1, a simple approach
12172
;--- that in theory would fit perfectly, but
12173
;--- unfortunately in reality may have quirks.
12178
movzx esi, word ptr ds:[44Eh]
12179
movzx ecx, word ptr ds:[44Ch]
12180
mov dx, ds:[450h+0*1]
12181
mov ds:[450h+1*2], dx
12183
cmp byte ptr ds:[463], 0B4h
12193
rep movsb es:[edi], ds:[esi]
12199
mov si, es:[44Eh] ; page offset curr page
12200
mov cx, es:[44Ch] ; page size
12202
mov ax, 0501h ; debugger page is 1
12203
ife (DRIVER or BOOTDBG)
12204
mov [vpage], al ; std: init here since we'll jump right into the debugger
12207
mov di, es:[44Eh] ; page offset page 1
12208
mov dx, es:[450h+0*1]
12209
mov es:[450h+1*2], dx
12210
mov ax, 0B000h ; copy page contents to page 1
12211
cmp byte ptr es:[463h],0B4h
12226
;--- Set up interrupt vectors.
12229
mov si, offset inttab
12230
mov di, offset intsave
12233
les ebx, [bp-6] ; load address of GDT
12234
@dprintf "initcode: setup int vectors, es:ebx=%X:%lX", es, ebx
12246
shl edx, 1 ; in long mode, vector size is 16
12248
mov ax, es:[ebx+edx*8+0]
12250
mov ax, es:[ebx+edx*8+6]
12252
mov ax, es:[ebx+edx*8+2]
12268
xchg ax, dx ;save int # in dl
12270
; mov ax, [si] ;get address
12271
lodsw ;get address (16-bit offset)
12274
movzx eax, ax ;in long mode, IDT vectors must be 64-bit!
12275
add eax, [dwBase64]
12276
mov es:[ebx+edx*8+0], ax
12277
mov word ptr es:[ebx+edx*8+2], CS64SEL ; CS must be 64-bit
12280
mov es:[ebx+edx*8+0], ax
12281
mov es:[ebx+edx*8+2], cs
12284
mov es:[ebx+edx*8+6], ax
12291
xchg ax, dx ;AL=int#, DX=offset
12292
mov ah, 25h ;set interrupt vector
12296
add di, sizeof INTVEC
12299
;--- prepare to shrink DEBUG and set its stack
12301
mov ax, offset real_end + STACKSIZ + 15
12302
and al, not 15 ; debug's top of stack
12307
@dprintf "top_sp=%lX", eax
12318
cntpatch = ($ - patches) / 2