DOS-debug

Форк
0
/
DEBUG.ASM 
12321 строка · 227.9 Кб
1
;   DEBUG.ASM Masm/JWasm assembler source for Debug/X.
2

3
;   To assemble, use:
4
;       jwasm -bin -Fo debug.com debug.asm
5
;
6
;   To create DEBUGX, the DPMI aware version of debug, use:
7
;       jwasm -D?DPMI=1 -bin -Fo debugx.com debug.asm
8

9
; ============================================================================
10
;
11
; Copyright (c) 1995-2003  Paul Vojta
12
;
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:
19
;
20
; The above copyright notice and this permission notice shall be included in
21
; all copies or substantial portions of the Software.
22
;
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.
29
;
30
; ============================================================================
31
;
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
; ============================================================================
36
;   Revision history:
37
;       0.95e [11 January 2003]  Fixed a bug in the assember.
38
;       0.95f [10 September 2003]  Converted to NASM; fixed some syntax
39
;       incompatibilities.
40
;       0.98 [27 October 2003]  Added EMS commands and copyright conditions.
41
;
42
;       The changes which were done by my, japheth, are described in
43
;       HISTORY.TXT.
44
;
45
;   To do:
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?
52

53
VERSION    textequ <2.50>
54

55
	option casemap:none
56
	option proc:private
57
;	option noljmp	;enable to see the short jump extensions
58

59
BS         equ 8
60
TAB        equ 9
61
LF         equ 10
62
CR         equ 13
63
TOLOWER    equ 20h
64
TOUPPER    equ 0dfh
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)
70

71
ifndef FMTEXE
72
FMTEXE     equ 0	;1=debugger binary has .EXE format
73
endif
74
ifndef DRIVER
75
DRIVER     equ 0	;1=create a device driver (for CONFIG.SYS) variant
76
endif
77
ifndef BOOTDBG
78
BOOTDBG    equ 0	;1=create a bootstrap binary (DebugB)
79
endif
80
ifndef RING0
81
RING0      equ 0	;1=create a ring0 debugger variant (DebugR)
82
endif
83
ifndef ?DPMI
84
?DPMI      equ 0	;1=create a DPMI-aware variant (DebugX)
85
endif
86
ifndef LMODE
87
LMODE      equ 0	;1=long mode version if RING0==1 - this will define a 64-bit segment ( requires JWasm )
88
endif
89

90
;--- default assembly-time values; may be overwritten below.
91

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.
111

112
SKIPBPINDBG equ 1	; 1=breakpoints occuring while in debug are reported, won't reenter debug
113

114
if LMODE
115
CS32	equ 40h or 20h	; check both default size and 64-bit mode
116
else
117
CS32	equ 40h		; check just the default size in legacy
118
endif
119

120
@VecAttr textequ <>
121

122
ifndef V86M
123
V86M       equ 0	; 1=support v86 mode ( for RING0 only )
124
endif
125

126
if RING0
127
 if LMODE
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
135
 else
136
DBGNAME    equ <"DEB386">
137
DBGNAME2   equ <"Deb386">
138
 endif
139

140
?PM        equ 1
141
USEHWBP    equ 1	; 1=use 386 hw breakpoints
142
VDD        equ 0
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
146
 ifndef BCMD
147
BCMD       equ 1
148
 endif
149
DGCMD      = 1
150
DICMD      = 1
151
DLCMD      = 1
152
DMCMD      = 0
153
DTCMD      = 1
154
VXCMD      = 1
155
elseif ?DPMI
156
DBGNAME    equ <"DEBUGX">
157
DBGNAME2   equ <"DebugX">
158
?PM        equ 1
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..."
164
 ifndef CATCHEXC06
165
CATCHEXC06 equ 0	;1=catch exception 06h in protected-mode
166
 endif
167
 ifndef CATCHEXC07
168
CATCHEXC07 equ 0	;1=catch exception 07h in protected-mode
169
 endif
170
CATCHEXC0C equ 1	;1=catch exception 0Ch in protected-mode
171
CATCHINT21 equ 1	;1=hook into protected-mode int 21h
172
 ifndef CATCHINT31
173
CATCHINT31 equ 0	;1=hook DPMI int 31h
174
 endif
175
CATCHINT41 equ 1	;1=hook into protected-mode debug interface
176
MMXSUPP    equ 1	;1=support MMX specific commands
177
 ifndef USEHWBP
178
USEHWBP    equ 1	;1=try to use 386 hw breakpoints (fails on NTVDM/DosEmu)
179
 endif
180
 ifndef BCMD
181
BCMD       equ 0	;BCMD=1 requires USEHWBP=1
182
 endif
183
DICMD      = 1
184
DLCMD      = 1
185
DXCMD      = 1
186
USEFP2STR  = 1
187
else
188
DBGNAME    equ <"DEBUG">
189
DBGNAME2   equ <"Debug">
190
?PM        equ 0
191
VDD        equ 0
192
NOEXTENDER equ 0
193
 ifndef BCMD
194
BCMD       equ 0
195
 endif
196
 if BCMD
197
USEHWBP    equ 1
198
 elseifndef USEHWBP
199
USEHWBP    equ 0
200
 endif
201
endif
202

203
if DRIVER
204
CATCHINT06 = 1
205
QCMD       = 0
206
LCMDFILE   = 0
207
WCMDFILE   = 0
208
INT22      = 0
209
INT2324    = 0
210
elseif RING0
211
CATCHINT06 = 1
212
 ifndef CATCHINT0C ; may be activated with cmdline option
213
CATCHINT0C = 0
214
 endif
215
CATCHINT0D = 1
216
CATCHINT41 = 0
217
DPCMDR0    = 0
218
LCMD       = 0
219
QCMD       = 0	; may be set to 1
220
WCMD       = 0
221
XCMDS      = 0
222
LCMDFILE   = 0
223
WCMDFILE   = 0
224
USESDA     = 0
225
INT22      = 0
226
INT2324    = 0
227
elseif BOOTDBG
228
CATCHINT06 = 1
229
DICMD      = 1
230
DMCMD      = 0
231
DPCMD      = 1
232
DXCMD      = 1
233
QCMD       = 0
234
WCMD       = 0
235
XCMDS      = 0
236
LCMDFILE   = 0
237
WCMDFILE   = 0
238
USESDA     = 0
239
INT22      = 0
240
INT2324    = 0
241
endif
242

243
ifndef USEUNREAL
244
USEUNREAL  equ 0	;1=use "unreal" mode for DX cmd ( won't work in v86 )
245
endif
246
ifndef MMXSUPP
247
MMXSUPP    equ 0
248
endif
249
ifndef VXCHG
250
VXCHG      equ 0	;1=support video swap so outputs remain separated
251
endif
252
ifndef ALTVID
253
ALTVID     equ 0    ;1=support alternate video adapter
254
endif
255
ifndef DICMD
256
DICMD      = 0
257
endif
258
ifndef DXCMD
259
DXCMD      = 0
260
endif
261
ifndef VXCMD
262
VXCMD      = 0
263
endif
264

265
if (DRIVER or BOOTDBG or RING0)
266
REDIRECT equ 0
267
else
268
REDIRECT equ 1		;stdin/stdout redirection
269
endif
270

271
SYSRQINT   equ 9	;if CATCHSYSREQ==1, defines the method (int 09h or int 15h)
272

273
ifndef CATCHINT01
274
CATCHINT01 equ 1	;catch INT 01 (single-step)
275
NOEXC01INDBG equ 1	;v2.01: ignore unexpected debug exceptions in debug itself
276
endif
277
ifndef CATCHINT03
278
CATCHINT03 equ 1	;catch INT 03 (break)
279
endif
280
ifndef CATCHINT06
281
CATCHINT06 equ 0	;catch exception 06h
282
endif
283
ifndef CATCHINT07
284
CATCHINT07 equ 0	;catch exception 07h
285
endif
286
ifndef CATCHINT0C
287
CATCHINT0C equ 0	;catch exception 0Ch
288
endif
289
ifndef CATCHINT0D
290
CATCHINT0D equ 0	;catch exception 0Dh
291
endif
292
ifndef CATCHSYSREQ
293
CATCHSYSREQ equ 0	;catch int 09h/15h (sysreq)
294
endif
295
ifndef CATCHINT41
296
CATCHINT41 equ 0	;hook int 41h
297
endif
298

299
ife ?DPMI
300
CATCHEXC06 equ 0
301
CATCHEXC07 equ 0
302
CATCHEXC0C equ 0
303
endif
304

305
if ?PM or CATCHINT07
306
EXCCSIP    equ 1	;display CS:IP where exception occured
307
 if V86M
308
EXCCSEIP   equ 1	;debugger may callout to v86-monitor, which is 32-bit CS
309
 else
310
EXCCSEIP   equ 0	;may be activated if unknown exceptions occur in debugger
311
 endif
312
else
313
EXCCSIP    equ 0
314
endif
315

316
PSPS struct
317
       dw ?		;+00
318
ALASAP dw ?		;+02 Address of LAst Segment  Allocated to Program
319
       dw ?,?,?	;+04
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)
323
       org 16h
324
PARENT dw ?		;+16 segment of parent PSP
325
       org 2Eh
326
SPSAV  dd ?		;+2E Saved SS:SP in last DOS call
327
       org 5Ch
328
FCB1   db 16 dup (?)
329
FCB2   db 16 dup (?)
330
       org 80h
331
DTA    db 128 dup (?);Program arguments; also used to store file name (N cmd)
332
PSPS ends
333

334
;--- attributes returned by int 21h, ax=4400h
335
AT_DEVICE  equ 80h  ; is device (not file)
336

337
ifdef _DEBUG
338
@dprintf macro text:req,a1,a2,a3,a4,a5,a6,a7,a8
339
local sym
340
CONST segment
341
sym db text,10,0
342
CONST ends
343
	pushcontext cpu
344
	.386
345
	for x,<a8,a7,a6,a5,a4,a3,a2,a1>
346
	 ifnb <x>
347
	  push x
348
	 endif
349
	endm
350
	push offset sym
351
	call dprintf
352
	popcontext cpu
353
endm
354
else
355
@dprintf textequ <;>
356
endif
357

358
;--- restore segment register (DS/ES) to DGROUP
359

360
@RestoreSeg macro segm
361
if FLATSS
362
	mov segm, cs:[wDgroup]
363
else
364
	push ss
365
	pop segm
366
endif
367
endm
368

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.
372

373
sizeprf macro
374
ife RING0
375
curreip = $
376
_IDATA segment
377
	dw curreip
378
_IDATA ends
379
endif
380
	db 66h
381
endm
382

383
sizeprfX macro
384
if ?PM
385
	sizeprf
386
endif
387
endm
388

389
if VDD
390
;--- standard BOPs for communication with DEBXXVDD on NT platforms
391
RegisterModule macro
392
	db 0C4h, 0C4h, 58h, 0
393
endm
394
UnRegisterModule macro
395
	db 0C4h, 0C4h, 58h, 1
396
endm
397
DispatchCall macro
398
	db 0C4h, 0C4h, 58h, 2
399
endm
400
endif
401

402
	.8086
403

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.
409

410
_TEXT segment dword public 'CODE'
411
_TEXT ends
412

413
if RING0
414
 if LMODE
415
	.x64
416
_TEXT64 segment use64 para public 'CODE'	; alignment para is needed for correct offsets
417
_TEXT64 ends
418
	.8086
419
 endif
420
endif
421

422
CONST segment readonly word public 'DATA'
423
CONST ends
424

425
ASMDATA segment word public 'DATA'
426
asmtab label byte
427
ASMDATA ends
428

429
OTDATA segment word public 'DATA'
430
OTDATA ends
431

432
_DATA segment dword public 'DATA'
433
_DATA ends
434

435
if RING0
436
_ITEXT segment dword public 'I_CODE'
437
else
438
_ITEXT segment word public 'I_CODE'
439
endif
440
_ITEXT ends
441

442
_IDATA segment word public 'I_DATA'
443
patches label word
444
_IDATA ends
445

446
DGROUP group _TEXT, CONST, ASMDATA, OTDATA, _DATA, _ITEXT, _IDATA
447

448
if FMTEXE or DRIVER
449
STACK segment para stack 'STACK'
450
	db STACKSIZ dup (?)
451
STACK ends
452
DGROUP group STACK
453
endif
454

455
	assume ds:DGROUP
456

457
_TEXT segment
458

459
if DRIVER
460
	dd -1
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
465

466
req_hdr struct
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
472
req_hdr ends
473

474
request_ptr dd 0
475

476
strategy:
477
	mov word ptr cs:[request_ptr+0],bx
478
	mov word ptr cs:[request_ptr+2],es
479
	retf
480
interrupt:
481
	push ds
482
	push di
483
	lds di, cs:[request_ptr]	; load address of request header
484
	mov [di].req_hdr.status,8103h
485
	pop di
486
	pop ds
487
	ret
488
else
489

490
 ife (RING0 or BOOTDBG)
491
  ife FMTEXE
492
	org 100h
493
  endif
494
 endif
495
 ife FMTEXE
496
start:
497
	jmp initcode
498
 endif
499
 if RING0
500
	jmp getr0stk	; get ring 0 SS:ESP
501
	org start+6		; entercmd must be start+2*3
502
	jmp uninstall	; uninstall
503
 endif
504

505
endif
506

507
_TEXT ends
508

509
CONST segment
510

511
;--- cmds b,j,k,v,y and z don't exist yet
512

513
cmdlist label word
514
	dw a_cmd
515
if BCMD
516
bcmdv dw b_cmderr	; may be dynamically set to b_cmd
517
else
518
	dw cmd_error
519
endif
520
	dw c_cmd, d_cmd
521
	dw e_cmd, f_cmd, g_cmd, h_cmd
522
	dw i_cmd, cmd_error, cmd_error
523
ife RING0
524
	dw l_cmd
525
else
526
	dw cmd_error
527
endif
528
	dw m_cmd
529
if LCMDFILE or WCMDFILE
530
	dw n_cmd
531
else
532
	dw cmd_error
533
endif
534
	dw o_cmd, p_cmd
535
if QCMD
536
	dw q_cmd
537
else
538
	dw cmd_error
539
endif
540
	dw r_cmd, s_cmd, t_cmd
541
	dw u_cmd
542
if VXCHG
543
	dw v_cmd
544
elseif VXCMD
545
	dw v_cmd
546
else
547
	dw cmd_error
548
endif
549
if WCMD
550
	dw w_cmd
551
else
552
	dw cmd_error
553
endif
554
if XCMDS
555
	dw x_cmd
556
else
557
	dw cmd_error
558
endif
559
ENDCMD equ <'x'>
560

561
if ?DPMI
562
dbg2324 dw i23pm, i24pm
563
endif
564

565
CONST ends
566

567
_DATA segment
568

569
if FLATSS
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 )
572
else
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
575
endif
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)
580
endif
581

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
586

587
wDgroup label word	;pspdbg is the PSP segment or just the CS segment (Dgroup)
588
if FMTEXE
589
		dw 0		;for .EXE, DGROUP and debugger's psp are different
590
endif
591
pspdbg	dw 0		;debugger's PSP - always a segment
592
if ?DPMI and FMTEXE
593
pspdbgpm dw 0		;selector for debugger's PSP
594
endif
595

596
if INT2324
597
run2324	dw 0,0,0,0	;debuggee's interrupt vectors 23 and 24 (both modes)
598
 if ?DPMI
599
		dw 0,0		;in DPMI32, vectors are FWORDs
600
 endif
601
endif
602
if RING0
603
wFlat	dw 0
604
 if V86M
605
dwV86Ofs dd 0
606
 endif
607
endif
608
if VDD
609
hVdd	dw -1		;handle of NT helper VDD
610
endif
611

612
if INT2324
613
sav2324	dw 0,0,0,0	;debugger's interrupt vectors 23 and 24 (real-mode only)
614
endif
615
if INT22
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)
618
endif
619
if DMCMD
620
wMCB	dw 0		;start of MCB chain (always segment)
621
endif
622
ife ( BOOTDBG or RING0 )
623
pInDOS	dd 0		;far16 address of InDOS flag (real mode)
624
endif
625
if ?DPMI
626
InDosSel dw 0		;selector value for pInDOS in protected-mode
627
endif
628
if VXCHG
629
 ifndef VXCHGFLIP
630
XMSM struct
631
size_  dd ?
632
srchdl dw ?
633
srcadr dd ?
634
dsthdl dw ?
635
dstadr dd ?
636
XMSM ends
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
641
 endif
642
endif
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
647
oldmr label word
648
oldmode   db 0      ; video mode
649
oldrows   db 24     ; rows - 1
650
endif
651
if USESDA
652
pSDA	dd 0		;far16 address of DOS swappable data area (real-mode)
653
 if ?DPMI
654
SDASel	dw 0		;selector value for pSDA in protected-mode
655
 endif
656
endif
657
if INT2324
658
hakstat	db 0		;whether we have hacked vectors 23/24 or not
659
endif
660
machine	db 0		;cpu (0=8086,1,2,3=80386,...)
661

662
RM_386REGS	equ 1	;bit 0: 1=386 register display
663
if RING0
664
rmode	db RM_386REGS
665
else
666
rmode	db 0		;flags for R command
667
endif
668
tmode	db 0		;bit 0: 1=ms-debug compatible trace mode
669

670
if USEHWBP
671
bBPhit   db 0
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
675
endif
676

677
has_87	db 0		;if there is a math coprocessor present
678
mach_87	db 0		;coprocessor (0=8087,1,2,3=80387,...)
679
if MMXSUPP
680
has_mmx	db 0
681
endif
682
bInDbg	db 0		;1=debugger is running
683
if MCLOPT and ( CATCHINT0C or CATCHINT0D )
684
bMPicB	db 8		;master PIC base
685
endif
686
if REDIRECT
687
fStdin	db AT_DEVICE;flags stdin
688
fStdout	db AT_DEVICE;flags stdout
689
endif
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
694
if REDIRECT
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
697
endif
698

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
702

703
if USEHWBP
704
;--- bits in bType:
705
;---   0-3: type
706
BP_CODE   equ  0h
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
710
BP_ACTIVEBIT equ 6
711

712
HWBPSTRUCT struct
713
dwLinAd dd ?
714
bType   db ?
715
 if ?DPMI
716
wHdl	dw ?	; DPMI only
717
 endif
718
HWBPSTRUCT ends
719

720
MAXHWBP equ 4
721
HWBps HWBPSTRUCT MAXHWBP dup (<0,0>)
722
endif
723

724
if DXCMD
725
x_addr	dd 0		;(phys) address for last DX command
726
endif
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
729
lastcmd	dw dmycmd
730
run_intw label word
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
734
if ?PM
735
scratchsel dw 0		;scratch selector ( used by cmds a,c,e,f,g,m,p,t )
736
 if RING0 and V86M
737
scratchv86 dw 0
738
bV86Bp     db 0F4h  ;may be 0F4h or 63h
739
 endif
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 
743
 if RING0
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)
747
  if FLATSS
748
bChar   db 0
749
  endif
750
 endif
751
endif
752
if LCMDFILE or WCMDFILE
753
fileext	db 0		;file extension (0 if no file name)
754

755
EXT_OTHER	equ 1
756
EXT_COM		equ 2
757
EXT_EXE		equ 4
758
EXT_HEX		equ 8
759
endif
760

761
ife RING0
762

763
;--- usepacket:
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)
767
usepacket db 0
768

769
PACKET struc
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
774
PACKET ends
775

776
 if ?PM
777
PACKET32 struc	; this is for DPMI32 only
778
secno	dd ?
779
numsecs	dw ?
780
dstofs	dd ?
781
dstseg	dw ?
782
PACKET32 ends
783
 endif
784

785
	align 2
786

787
packet PACKET <0,0,0,0>
788
 if ?PM
789
	dw 0	; reserve space for the additional 2 bytes of PACKET32
790
 endif
791

792
endif
793

794
if RING0	; vectors in intsave are either real-mode or - if RING0 == 1 - protected-mode
795
INTVEC textequ <FWORD>
796
else
797
INTVEC textequ <DWORD>
798
endif
799

800
;--- order in intsave must match order in inttab
801

802
intsave label dword
803
oldi00	INTVEC 0	;saved vector i00
804
if RING0 or CATCHINT01
805
oldi01	INTVEC 0	;saved vector i01
806
endif
807
if RING0 or CATCHINT03
808
oldi03	INTVEC 0	;saved vector i03
809
endif
810
if CATCHINT06
811
oldi06	INTVEC 0	;saved vector i06
812
endif
813
if CATCHINT07
814
oldi07	INTVEC 0	;saved vector i07
815
endif
816
if CATCHINT0C
817
oldi0C	INTVEC 0	;saved vector i0C
818
endif
819
if CATCHINT0D
820
oldi0D	INTVEC 0	;saved vector i0D
821
endif
822
if RING0
823
oldi0E	INTVEC 0	;saved vector i0E
824
endif
825
if CATCHSYSREQ
826
oldisrq	INTVEC 0	;saved vector i09/i15
827
endif
828
if INT22
829
		INTVEC 0	;saved vector i22 ( real-mode only )
830
endif
831
if RING0 and CATCHINT41
832
oldint41 INTVEC 0	;saved vector i41 ( protected-mode only )
833
endif
834
if ?DPMI ;must be last
835
oldi2f	dd 0		; real-mode only
836
endif
837

838
if RING0
839
int10vec df 0	; (int 10h) output routine
840
int16vec df 0	; (int 16h) input routine
841
 if LMODE
842
jmpv64  label fword
843
		dd 0
844
		dw 8	; selector 8 is 64-bit ( Dos32cm )
845
jmpv161 label fword
846
		dw offset intrtnp1,0
847
jmpv161s dw 0	; debugger cs
848
jmpv162 label fword
849
	o	dw offset intrtnp2,0
850
jmpv162s dw 0	; debugger cs
851
dwBase64 dd 0	; linear address start _TEXT64
852
 endif
853
 if FLATSS
854
dwBase   dd 0	; linear address start _TEXT
855
 endif
856
endif
857

858
;--- Parameter block for exec call.
859

860
if LCMDFILE
861
EXECS struc
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
868
EXECS ends
869

870
execblk	EXECS {0,0,PSPS.FCB1,PSPS.FCB2,0,0}
871
endif
872

873
REGS struct
874
rDI		dw ?,?	;+00 edi	; must be in PUSHAD order
875
rSI		dw ?,?	;+04 esi
876
rBP		dw ?,?	;+08 ebp
877
		dw ?,?	;+12 reserved
878
rBX		dw ?,?	;+16 ebx
879
rDX		dw ?,?	;+20 edx
880
rCX		dw ?,?	;+24 ecx
881
rAX		dw ?,?	;+28 eax
882

883
rDS		dw ?	;+32 ds		; check run()/intrtn()/createdummytask() if this order changes!
884
rES		dw ?	;+34 es
885
rFS		dw ?	;+36 fs		; v2.0: order changed
886
rGS		dw ?	;+38 gs
887
rSS		dw ?	;+40 ss		; should start on a DWORD boundary ( in case AC is on )
888
rCS		dw ?	;+42 cs
889
if ?PM
890
		dw ?	; added ( for 32-bit CS push )
891
endif
892

893
rSP		dw ?,?	;+46 esp
894
rIP		dw ?,?	;+50 eip
895
rFL		dw ?,?	;+54 eflags
896
if RING0
897
union
898
r0SSEsp df ?
899
struct
900
r0Esp dd ?
901
r0SS  dw ?
902
ends
903
ends
904
dwErrCode dd ?
905
endif
906
if ?DPMI;?PM
907
msw		dw ?	;0000=real-mode, FFFF=protected-mode
908
endif
909
REGS ends
910

911
;--- Register save area.
912

913
	align 4		;--- must be DWORD aligned!
914

915
regs REGS <>
916

917
_DATA ends
918

919
CONST segment
920

921
;--- table of interrupt initialization
922

923
INTITEM struct
924
bInt db ?
925
wOfs dw ?
926
INTITEM ends
927

928
;--- must match order in intsave
929

930
inttab label INTITEM
931
	INTITEM <00h, @VecAttr intr00>
932
if CATCHINT01
933
	INTITEM <01h, @VecAttr intr01>
934
endif
935
if CATCHINT03
936
	INTITEM <03h, @VecAttr intr03>
937
endif
938
if CATCHINT06
939
	INTITEM <06h, @VecAttr intr06>
940
endif
941
if CATCHINT07
942
	INTITEM <07h, @VecAttr intr07>
943
endif
944
if CATCHINT0C
945
	INTITEM <0Ch, @VecAttr intr0C>
946
endif
947
if CATCHINT0D
948
	INTITEM <0Dh, @VecAttr intr0D>
949
endif
950
if RING0
951
	INTITEM <0Eh, @VecAttr intr0E>
952
endif
953
if CATCHSYSREQ
954
	INTITEM <SYSRQINT, intrsrq>
955
endif
956
if INT22
957
	INTITEM <22h, intr22dbg>
958
endif
959
if RING0 and CATCHINT41
960
itab41	INTITEM <41h, intr41>
961
endif
962
NUMINTS = ( $ - inttab ) / sizeof INTITEM
963
if ?DPMI
964
	db 2Fh
965
endif
966

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.
970

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
978

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'
983

984
;--- Instruction set information needed for the 'p' command.
985
;--- arrays ppbytes and ppinfo must be consecutive!
986

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
997

998
;   Info for the above, respectively.
999
;   80h = prefix;
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
1005
;   instruction.
1006

1007
PP_ADRSIZ	equ 01h
1008
PP_OPSIZ	equ 02h
1009
PP_PREFIX	equ 80h
1010
PP_VARSIZ	equ 40h
1011

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
1016
	db 0,1											;INT instr
1017
	db 1,1,1										;LOOPx instr
1018
	db 42h											;near CALL instr
1019
	db 44h											;far CALL instr
1020

1021
PPLEN	equ $ - ppinfo
1022

1023
;--- Strings.
1024

1025
ife (BOOTDBG or RING0)
1026
    db '!'      ;additional prompt if InDos flag is set
1027
endif
1028
ifdef PROMPT
1029
prompt1	db @CatStr(!',%PROMPT,!')
1030
else
1031
 if RING0 and V86M
1032
prompt1	db '>'	;indicates v86 mode for DebugRV
1033
 else
1034
prompt1	db '-'	;main prompt
1035
 endif
1036
endif
1037

1038
prompt2	db ':'	;prompt for register value
1039

1040
if ?PM
1041
 if ?DPMI
1042
	db '!'
1043
 endif
1044
prompt3	db '#'	;protected-mode prompt
1045
endif
1046

1047
helpmsg db DBGNAME2, ' v',@CatStr(!',%VERSION,!'),CR,LF
1048
	db 'assemble', TAB, 'A [address]',CR,LF
1049
if BCMD
1050
	db 'clear bp', TAB, 'BC # (#=0|1|2|3)',CR,LF
1051
	db 'set/show bp', TAB, 'BP [address [type]]',CR,LF
1052
endif             
1053
	db 'compare', TAB, TAB, 'C range address',CR,LF
1054
	db 'dump', TAB, TAB, 'D [range]',CR,LF
1055
if DGCMD
1056
	db 'dump GDT', TAB, 'DG selector [count]',CR,LF
1057
endif
1058
if DICMD
1059
 if RING0
1060
	db 'dump IDT', TAB, 'DI interrupt [count]',CR,LF
1061
 else
1062
	db 'dump interrupt', TAB, 'DI interrupt [count]',CR,LF
1063
 endif
1064
endif
1065
if DLCMD
1066
	db 'dump LDT', TAB, 'DL selector [count]',CR,LF
1067
endif
1068
if DMCMD
1069
	db 'dump MCB chain', TAB, 'DM',CR,LF
1070
endif
1071
if DPCMD
1072
	db 'dump partitions', TAB, 'DP physical_disk',CR,LF
1073
elseif DPCMDR0
1074
	db 'dump page table', TAB, 'DP [linear_address]',CR,LF
1075
endif
1076
if DTCMD
1077
	db 'dump TSS', TAB, 'DT [port count]',CR,LF
1078
endif
1079
if DXCMD
1080
	db 'dump ext memory', TAB, 'DX [physical_address]',CR,LF
1081
endif
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
1087
if LCMDFILE
1088
	db 'load program', TAB, 'L [address]',CR,LF
1089
endif
1090
if BOOTDBG
1091
	db 'load sectors', TAB, 'L address disk sector count',CR,LF
1092
elseife RING0
1093
	db 'load sectors', TAB, 'L address drive sector count',CR,LF
1094
endif
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
1100
endif
1101
	db 'output', TAB, TAB, 'O[W|D] port value',CR,LF
1102
	db 'proceed', TAB, TAB, 'P [=address] [count]',CR,LF
1103
if QCMD
1104
	db 'quit', TAB, TAB, 'Q',CR,LF
1105
 if ?DPMI
1106
	db 'forced pm quit', TAB, 'QQ',CR,LF
1107
 endif
1108
endif
1109
	db 'register', TAB, 'R [register [value]]',CR,LF
1110
if ?DPMI
1111
helpmsg2 label byte
1112
endif
1113
if MMXSUPP
1114
	db 'MMX register', TAB, 'RM',CR,LF
1115
endif
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
1119
if ?DPMI eq 0
1120
helpmsg2 label byte
1121
endif
1122
if RING0
1123
	db 'skip exception', TAB, 'SK',CR,LF
1124
endif
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
1128
if VXCHG
1129
	db 'view screen', TAB, 'V',CR,LF
1130
endif
1131
if VXCMD
1132
	db 'clr/trap vector', TAB, 'V[C|T] vector',CR,LF
1133
	db 'list vectors', TAB, 'VL',CR,LF
1134
endif
1135
if WCMDFILE
1136
	db 'write program', TAB, 'W [address]',CR,LF
1137
endif
1138
if WCMD
1139
	db 'write sectors', TAB, 'W address drive sector count',CR,LF
1140
endif
1141
if XCMDS
1142
	db 'expanded mem', TAB, 'XA/XD/XM/XR/XS,X? for help'
1143
endif
1144
if ?DPMI
1145
	db CR,LF,LF
1146
	db "prompts: '-' = real/v86-mode; '#' = protected-mode"
1147
endif
1148
crlf db CR,LF
1149
size_helpmsg2 equ $ - helpmsg2
1150
	db '$'
1151

1152
presskey db '[more]'
1153

1154
errcarat db '^ Error'
1155

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
1169

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
1176
		db dskerrc-dskerr0
1177
elseif BOOTDBG
1178
dskerr1	db "Invalid disk",CR,LF,'$'
1179
dskerrb	db "Read fault",CR,LF,'$'
1180
szNoHD	db "Not a HD",CR,LF,'$'
1181
endif
1182

1183
if LCMD or WCMD
1184
szDrive	db ' ____ing drive '
1185
driveno db 0,0			;drive# for L/W cmds
1186
endif
1187

1188
msg8088	db '8086/88',0
1189
msgx86	db 'x86',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
1196
tmode1	db 'traced',0
1197
tmode0	db 'processed',0
1198
unused	db ' (unused)',0
1199

1200
needsmsg db '[needs x86]'		;<--- modified (7 and 9)
1201
needsmath db '[needs math coprocessor]'
1202
obsolete db '[obsolete]'
1203

1204
;--- exception 00-0E, Int 22h & SysReq messages
1205

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,'$'
1211
endif
1212
if CATCHINT07 or CATCHEXC07
1213
exc07msg db 'Coprocessor not present',CR,LF,'$'
1214
endif
1215
if CATCHINT0C or CATCHEXC0C
1216
exc0Cmsg db 'Stack fault',CR,LF,'$'
1217
endif
1218
if CATCHINT0D or ?PM
1219
exc0Dmsg db 'General protection fault',CR,LF,'$'
1220
endif
1221
if ?PM
1222
 if RING0
1223
exc0Emsg db 'Page fault, CR2='
1224
exc0Ecr2 db '________',CR,LF,'$'
1225
 else
1226
exc0Emsg db 'Page fault.',CR,LF,'$'
1227
 endif
1228
endif
1229
if INT22
1230
progtrm	db CR,LF,'Program terminated normally ('
1231
progexit db '____)',CR,LF,'$'
1232
endif
1233
if CATCHSYSREQ
1234
sysrqmsg db 'SysRq detected',CR,LF,'$'
1235
endif
1236

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
1242
endif
1243
if CATCHINT07 or CATCHEXC07
1244
EXC07MSG equ offset exc07msg - offset int0msg
1245
endif
1246
if CATCHINT0C or CATCHEXC0C
1247
EXC0CMSG equ offset exc0Cmsg - offset int0msg
1248
endif
1249
if CATCHINT0D or ?PM
1250
EXC0DMSG equ offset exc0Dmsg - offset int0msg
1251
endif
1252
if ?PM
1253
EXC0EMSG equ offset exc0Emsg - offset int0msg
1254
endif
1255
if INT22
1256
INT22MSG equ offset progtrm  - offset int0msg
1257
endif
1258
if CATCHSYSREQ
1259
SYSRQMSG equ offset sysrqmsg - offset int0msg
1260
endif
1261

1262
if EXCCSIP
1263
excloc	db 'CS:IP=',0
1264
endif
1265
if ?DPMI
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,'$'
1268
 if DISPHOOK
1269
dpmihook db 'DPMI entry hooked, new entry=',0
1270
 endif
1271
nodesc	db 'not accessible in real-mode',0
1272
gatewrong db 'gate not accessible',0
1273
endif
1274
if RING0
1275
segerr	db "Debuggee segments invalid",CR,LF,'$'
1276
fpuemerr db "CR0.EM=1, won't run FPU opcodes",CR,LF,'$'
1277
 if QCMD
1278
plerr   db "can't quit protected-mode",CR,LF,'$'
1279
 endif
1280
endif
1281
cantwritebp db "Can't write breakpoint",CR,LF,'$'
1282

1283
if WCMDFILE
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,'$'
1289
endif
1290
if LCMDFILE or WCMDFILE
1291
openerr	db 'Error '
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,'$'
1297
endif
1298

1299
if XCMDS
1300

1301
;--- EMS error strings
1302

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 '
1314
emserrxa db '__',0
1315

1316
emserrs	dw emserr1,emserr1,0,emserr3,0,emserr5,0,emserr7,emserr8,emserr9
1317
		dw emserra,emserrb
1318

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
1326

1327
;--- strings used by XA, XD, XR and XM commands
1328

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
1336
		db '__',0
1337

1338
;--- strings used by XS command
1339

1340
xsstr1	db 'Handle '
1341
xsstr1a	db '____ has '
1342
xsstr1b	db '____ pages allocated',CR,LF
1343
size_xsstr1 equ $ - xsstr1
1344

1345
xsstr2	db 'phys. page '
1346
xsstr2a	db '__ = segment '
1347
xsstr2b	db '____  '
1348
size_xsstr2 equ $ - xsstr2
1349

1350
xsstr3	db ' of a total ',0
1351
xsstr3a	db ' EMS ',0
1352
xsstrpg	db 'pag',0
1353
xsstrhd	db 'handl',0
1354
xsstr3b	db 'es have been allocated',0
1355

1356
xsnopgs	db 'no mappable pages',CR,LF,CR,LF,'$'
1357

1358
endif
1359

1360
CONST ends
1361

1362
_TEXT segment
1363

1364
if RING0
1365

1366
;--- get ring0 SS:ESP
1367

1368
getr0stk proc
1369
	.386
1370
	mov eax, cs:[regs.r0Esp]
1371
	mov dx, cs:[regs.r0SS]
1372
 if LMODE
1373
	sub eax, 6*8
1374
	and al, 0F0h	; aligned to 16-byte
1375
 elseif V86M
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 )
1378
 else
1379
	sub eax, 6*4	; adjust ESP ( ERRC, EIP, CS, EFL, ESP, SS )
1380
 endif
1381
	retd
1382
	.8086
1383
getr0stk endp
1384

1385
;--- save/restore GDT descriptor of scratch selector
1386
;--- al=1 -> save, al=0 -> restore
1387
;--- ds=dgroup
1388

1389
srscratch:
1390
	.386
1391
if FLATSS
1392
	sub esp, 6
1393
	sgdt [esp]
1394
else
1395
	mov bp, sp
1396
	sub sp, 6
1397
	sgdt [bp-6]
1398
endif
1399
	movzx esi, [scratchsel]
1400
	pop ax
1401
	pop eax
1402
	add esi, eax
1403
	mov di, offset sdescsave
1404
	push ds
1405
	mov ds, [wFlat]
1406
	cmp al,0
1407
	jz @F
1408
	mov eax, [esi+0]
1409
	mov edx, [esi+4]
1410
	pop ds
1411
	mov [di+0], eax
1412
	mov [di+4], edx
1413
	ret
1414
@@:
1415
	mov eax,cs:[di+0]
1416
	mov edx,cs:[di+4]
1417
	mov [esi+0], eax
1418
	mov [esi+4], edx
1419
	pop ds
1420
	ret
1421

1422
_DATA segment
1423
sdescsave dd 0,0
1424
_DATA ends
1425

1426
endif
1427

1428
if ?DPMI
1429

1430
simrealmodeint proto stdcall :word, :word
1431

1432

1433
_DATA segment
1434
	align 4
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?)
1447

1448
;--- pmints and pmvectors must match!
1449
pmvectors label fword	; vectors must be consecutive and in this order!
1450
if CATCHINT41
1451
oldint41  label dword
1452
	dw 0, 0, 0
1453
endif
1454
if CATCHINT31
1455
oldint31  label dword
1456
	dw 0, 0, 0
1457
endif
1458
if CATCHINT21
1459
oldint21  label dword
1460
	dw 0, 0, 0
1461
endif
1462

1463
_DATA ends
1464

1465
;--- int 2F handler
1466

1467
debug2F:
1468
	pushf
1469
	cmp ax,1687h
1470
dpmidisable:		;set [IP+1]=0 if hook 2F is to be disabled
1471
	jz @F
1472
	popf
1473
	jmp cs:[oldi2f]
1474
@@:
1475
	call cs:[oldi2f]
1476
	and ax,ax
1477
	jnz @F
1478
	mov word ptr cs:[dpmientry+0],di
1479
	mov word ptr cs:[dpmientry+2],es
1480
	mov di,offset mydpmientry
1481
	push cs
1482
	pop es
1483
@@:
1484
	iret
1485

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.
1492

1493
mydpmientry:
1494
;	call cs:[dpmientry]	;call the REAL dpmi entry
1495
	db 9ah		; opcode call ssss:oooo
1496
dpmientry dd 0
1497
	jnc initdpmi
1498
	retf
1499

1500
	.286
1501

1502
CONST segment
1503

1504
pmints label byte     ;pmints and pmvectors must match!
1505
if CATCHINT41
1506
	db 41h
1507
	dw intr41pm
1508
endif
1509
if CATCHINT31
1510
	db 31h
1511
	dw intr31pm
1512
endif
1513
if CATCHINT21
1514
	db 21h
1515
	dw intr21pm
1516
endif
1517
LPMINTS equ ($ - offset pmints) / 3
1518

1519
if 0	;v2.0: removed
1520
convsegs label word
1521
;	dw offset run_cs
1522
;	dw offset pInDOS+2
1523
;if USESDA
1524
;	dw offset pSDA+2
1525
;endif
1526
	dw offset a_addr+4
1527
	dw offset d_addr+4
1528
NUMSEGS equ ($-convsegs)/2
1529
endif
1530

1531
exctab label byte	; DPMI exception table
1532
	db 0
1533
	db 1
1534
	db 3
1535
if CATCHEXC06
1536
	db 06h
1537
endif
1538
if CATCHEXC07
1539
	db 07h
1540
endif
1541
if CATCHEXC0C
1542
	db 0Ch
1543
endif
1544
	db 0Dh
1545
	db 0Eh
1546
endexctab label byte
1547

1548
CONST ends
1549

1550
_DATA segment
1551
dbeexc0d0e label word	; saved debuggee's exc 0d/0e when debugger is entered
1552
	dw 2 dup (0,0,0)
1553
_DATA ends
1554

1555
;--- client entered protected mode.
1556
;--- inp: [sp+4] = client real-mode CS
1557

1558
INSTFRM struct
1559
	org -2
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
1565
INSTFRM ends
1566
    
1567
initdpmi proc
1568
	pusha
1569
	mov bp,sp
1570
	push ds
1571
	mov bx,cs
1572
	mov ax,000Ah	;get a data descriptor for DEBUG's segment
1573
	int 31h
1574
	jc fataldpmierr
1575
	mov ds,ax
1576
	@dprintf "initdpmi: client entered pm"
1577
	mov [cssel],cs
1578
	mov [dssel],ds
1579
	mov cl, 90h
1580
	mov ax, 200h
1581
	cmp [machine],3		; is at least a 80386?
1582
	jb @F
1583
	mov dx, ss
1584
	.386
1585
	push edx
1586
	lar edx, edx
1587
	shr edx, 23
1588
	pop edx
1589
	.286
1590
	adc al,0
1591
	jz @F
1592
	mov cl, 66h
1593
	mov ah, 4
1594
@@:
1595

1596
	mov [dpmi32], al
1597
	mov byte ptr [wOfsSize], ah
1598
if CATCHINT21
1599
	mov [patchint21pm], cl
1600
endif
1601
if CATCHINT31
1602
	mov [patchint31pm], cl
1603
endif
1604
if CATCHINT41
1605
	mov [patchint41pm], cl
1606
endif
1607
	mov [patchiretpm], cl
1608
	mov [patchfarretpm], cl
1609
	mov [patchfarretpmval], ah
1610
	mov [patchrmswitch], cl
1611
	mov [patchsrstate], cl
1612

1613
	mov cx,2		;alloc 2 descriptors
1614
	xor ax,ax
1615
	int 31h
1616
	jnc @F
1617
fataldpmierr:
1618
	mov ax,4CFFh
1619
	int 21h
1620
@@:
1621
	mov [scratchsel],ax	;the first is used as scratch descriptor
1622
	xchg bx,ax			; mov bx, ax
1623
	xor cx,cx
1624
	cmp [machine], 3	; is at least a 80386?
1625
	jb @F
1626
;	test [dpmi32], 1	; 32-bit client?
1627
;	jz @F
1628
	dec cx				; then limit=ffffffff
1629
@@:
1630
	or dx,-1
1631
	mov ax,0008h
1632
	int 31h
1633
	add bx,8		;the second selector is client's CS
1634
	xor cx,cx		;this limit is FFFF even for 32-bits
1635
	mov ax,0008h
1636
	int 31h
1637
	mov dx,[bp].INSTFRM._cs	; get client's CS
1638
	call setrmaddr			; set base
1639
	mov ax,cs
1640
	lar cx,ax
1641
	shr cx,8				; CS remains 16-bit
1642
	mov ax,0009h
1643
	int 31h
1644
	mov [bp].INSTFRM._cs,bx	; set client's CS
1645
if FMTEXE
1646
	mov bx, [pspdbg]
1647
	mov ax, 2
1648
	int 31h
1649
	mov [pspdbgpm], ax
1650
endif
1651

1652
if 1
1653
;--- v2.0: (re)init default for d cmd
1654
	mov ax, [bp].INSTFRM._ds
1655
	mov [d_addr+4], ax
1656
	mov [bFlagsPM], 0		; reset all pm flags
1657
endif
1658

1659
	mov bx,word ptr [pInDOS+2]
1660
	mov ax,2
1661
	int 31h
1662
	mov [InDosSel],ax
1663
if USESDA
1664
	mov bx,word ptr [pSDA+2]
1665
	mov ax,2
1666
	int 31h
1667
	mov [SDASel],ax
1668
endif
1669

1670
if 0	; v2.0: removed, default for a/d cmds see above
1671
	mov si,offset convsegs
1672
	mov cx,NUMSEGS
1673
@@:
1674
	lodsw
1675
	mov di,ax
1676
	mov bx,[di]
1677
	mov ax,2
1678
	int 31h
1679
	jc fataldpmierr
1680
	mov [di],ax
1681
	loop @B
1682
endif
1683

1684
	sizeprf			; push edi - save hiword(edi)
1685
	push di
1686

1687
	mov bp,[wOfsSize]	; get offset size for far16/far32
1688
	mov ax,0305h			; get raw-mode save state addresses
1689
	int 31h
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
1697
	int 31h
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
1703

1704
	sizeprf			; pop edi - restore hiword(edi)
1705
	pop di
1706

1707
;--- hook exceptions 0,1,3,6,(7),(C),D,E
1708

1709
	cld
1710
	mov si,offset exctab
1711
	sizeprf			; push edx - save hiword(edx)
1712
	push dx
1713
	sizeprf			; xor edx,edx
1714
	xor dx,dx
1715
	mov dx,offset exc00
1716
@@:
1717
	lodsb
1718
	mov bl,al
1719
	mov cx,cs
1720
	mov ax,203h
1721
	int 31h
1722
	add dx,exc01-exc00
1723
	cmp si,offset endexctab
1724
	jb @B
1725

1726
;--- hook DPMI protected-mode interrupts
1727

1728
if LPMINTS
1729
	mov si, offset pmvectors
1730
	mov di, offset pmints
1731
	mov cx, LPMINTS
1732
nextpmint:
1733
	mov bl, cs:[di]
1734
	push cx
1735
	mov ax, 204h
1736
	int 31h
1737
	sizeprf	;mov [si], edx
1738
	mov [si], dx
1739
	mov ds:[si+bp], cx
1740
	sizeprf	;xor edx, edx
1741
	xor dx, dx
1742
	mov dx, [di+1]
1743
	mov cx, cs
1744
	mov al, 5
1745
	int 31h
1746
	add si, sizeof fword
1747
	add di, 3
1748
	pop cx
1749
	loop nextpmint
1750
endif
1751

1752
	sizeprf				; pop edx - restore hiword(edx)
1753
	pop dx
1754

1755
	mov bl,2Fh			;get int 2Fh real-mode vector
1756
	mov ax,200h
1757
	int 31h
1758
	cmp cx,[wDgroup]	;did we hook it and are the last in chain?
1759
	jnz int2fnotours
1760
	mov dx,word ptr [oldi2f+0]
1761
	xor cx,cx
1762
	xchg cx,word ptr [oldi2f+2]	;then unhook
1763
	mov ax,201h
1764
	int 31h
1765
int2fnotours:
1766
	pop ds
1767
	popa
1768
	clc
1769
	retf
1770

1771
initdpmi endp
1772

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.
1777

1778
;--- setdbeexc0d0e: set debuggee's exception 0d/0e when running it
1779

1780
setdbeexc0d0e proc
1781
	call ispm_dbe
1782
	jz done
1783
	mov si, offset dbeexc0d0e
1784
	mov bl, 0dh
1785
nextexc:
1786
	sizeprf	; lodsd
1787
	lodsw
1788
	sizeprf	; mov edx, eax
1789
	mov dx, ax
1790
	lodsw
1791
	mov cx, ax
1792
	jcxz @F
1793
	mov ax, 0203h
1794
	int 31h
1795
@@:
1796
	inc bl
1797
	cmp bl, 0eh
1798
	jbe nextexc
1799
done:
1800
	ret
1801
setdbeexc0d0e endp
1802

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.
1805

1806
setdbgexc0d0e proc
1807
	call ispm_dbe
1808
	jz done
1809
	mov di, offset dbeexc0d0e
1810
	mov si, offset exc0d
1811
	mov bl, 0dh
1812
@@:
1813
	mov ax, 0202h
1814
	int 31h
1815
	sizeprf
1816
	mov ax, dx
1817
	sizeprf
1818
	stosw
1819
	mov ax, cx
1820
	stosw
1821
	sizeprf			; movzx edx, si
1822
	lea dx, [si]
1823
	mov cx, cs
1824
	mov ax, 0203h
1825
	int 31h
1826
	add si, exc01-exc00
1827
	inc bl
1828
	cmp bl, 0eh
1829
	jbe @B
1830
done:
1831
	ret
1832
setdbgexc0d0e endp
1833

1834
	include <TRAPD.INC>
1835

1836
if CATCHINT21
1837
intr21pm proc
1838
	cmp ah,04Ch
1839
	jz is4c
1840
prevint21:
1841
patchint21pm db 66h	; jmp fword ptr cs:[oldint21]
1842
	jmp cs:[oldint21]
1843
is4c:
1844
	push ds
1845
	mov ds, cs:[dssel]
1846
	call exitdpmi
1847
	pop ds
1848
	jmp prevint21
1849
intr21pm endp
1850
endif
1851

1852
if CATCHINT31
1853
intr31pm proc
1854
	cmp cs:[bInDbg],0; v2.0 do nothing if debugger is active
1855
	jnz notinterested
1856
	cmp ax,0203h	; set exception vector?
1857
	jz is203
1858
	cmp ax,0212h	; v2.0: set exception vector v1.0?
1859
	jz is212
1860
notinterested:
1861
patchint31pm db 66h	; jmp fword ptr cs:[oldint31]
1862
	jmp cs:[oldint31]
1863
is203:
1864
is212:
1865
	cmp bl,1
1866
	jz @F
1867
	cmp bl,3
1868
	jz @F
1869
	cmp bl,0Dh
1870
	jz @F
1871
	cmp bl,0Eh
1872
	jnz notinterested
1873
@@:
1874
;	jmp execiret
1875
intr31pm endp
1876
endif
1877

1878
;--- fall thru!
1879

1880
execiret:
1881
patchiretpm db 66h		; iretd
1882
	iret
1883

1884
i23pm:
1885
i24pm:
1886
	clc
1887
patchfarretpm db 66h
1888
	retf 2
1889
patchfarretpmval equ byte ptr ($ - 2)
1890

1891
	.8086
1892

1893
endif	;?DPMI
1894

1895
if CATCHINT41
1896
 if ?DPMI
1897
intr41pm:
1898
 endif
1899
intr41 proc
1900
	cmp ax, 004Fh
1901
	jz is4f
1902
 if ?DPMI
1903
patchint41pm db 66h
1904
 endif
1905
	jmp cs:[oldint41]
1906
is4f:
1907
	mov ax, 0F386h
1908
 if ?DPMI
1909
	jmp execiret
1910
 else
1911
	iretd
1912
 endif
1913
intr41 endp
1914
endif
1915

1916
if INT22
1917

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.
1926

1927
intr22dbg:
1928
	cld			;reestablish things
1929
	mov ax,cs
1930
	mov ds,ax
1931
	mov ss,ax
1932
elseif RING0
1933
 if 0
1934
entercmd:
1935
	mov ds, cs:[wDgroup]
1936
	push ds
1937
	pop ss
1938
 endif
1939
endif
1940

1941
;--- fall through to cmdloop!
1942

1943
;--- Begin main command loop.
1944

1945
cmdloop proc
1946
if FLATSS
1947
	mov esp,[top_sp]	;restore stack (this must be first)
1948
else
1949
	mov sp,[top_sp]		;restore stack (this must be first)
1950
endif
1951
	mov [errret],offset cmdloop
1952
	push ds
1953
	pop es
1954

1955
	cmp [bInDbg], 1
1956
	jz @F
1957
	mov ax, 0e07h
1958
	int 10h
1959
@@:
1960

1961
if LCMDFILE
1962
	call isdebuggeeloaded
1963
	jnz @F
1964
	call createdummytask	;if no task is active, create a dummy one
1965
@@:
1966
endif
1967
	mov cx,1
1968
ife ?PM
1969
	mov dx,offset prompt1
1970
else
1971
 if ?DPMI or ( RING0 and V86M )
1972
	mov dx,offset prompt1
1973
	call ispm_dbe			; debuggee in rm/pm?
1974
	jz @F
1975
 endif
1976
	mov dx,offset prompt3
1977
@@:
1978
endif
1979
ife (BOOTDBG or RING0)
1980
	call InDos
1981
	jz @F
1982
 ife VXCHG
1983
	mov ah, 0Fh
1984
	int 10h
1985
	mov [vpage], bh ;ensure [vpage] is initialized if InDos is set
1986
 endif
1987
	dec dx          ;if inside DOS, display a '!' before the real prompt
1988
	inc cx
1989
@@:
1990
endif
1991
	call getline	;prompted input
1992
	cmp al,CR
1993
	jnz @F
1994
	mov dx, [lastcmd]
1995
	dec si
1996
	jmp cmd4
1997
@@:
1998
	cmp al,';'
1999
	je cmdloop	;if comment
2000
	cmp al,'?'
2001
	je printhelp	;if request for help
2002
	or al,TOLOWER
2003
	sub al,'a'
2004
	cmp al,ENDCMD - 'a'
2005
	ja errorj1		;if not recognized
2006
	cbw
2007
	xchg bx,ax
2008
	call skipcomma
2009
	shl bx,1
2010
	mov dx,[cmdlist+bx]
2011
	mov [lastcmd],offset dmycmd
2012
	mov ah,[si-2]	; v2.0: for easily detecting 2-byte cmds
2013
	or ah, TOLOWER
2014
cmd4:
2015
	sizeprfX		;clear ecx - needed for cmds that call getrange
2016
	xor cx,cx
2017
	mov di,offset line_out
2018
	call dx
2019
	jmp cmdloop		;back to the top
2020

2021
errorj1:
2022
	jmp cmd_error
2023

2024
cmdloop endp
2025

2026

2027
dmycmd:
2028
	ret
2029

2030
printhelp:
2031
	mov dx,offset helpmsg
2032
	mov cx,offset helpmsg2 - offset helpmsg
2033
	call stdout
2034
	call waitkey
2035
	mov dx,offset helpmsg2
2036
	mov cx,size_helpmsg2
2037
	call stdout
2038
	jmp cmdloop		;done
2039

2040
waitkey proc
2041
if REDIRECT
2042
	test [fStdin], AT_DEVICE	;stdin a file?
2043
	jz nowait
2044
	test [fStdout], AT_DEVICE	;stdout a file?
2045
	jz nowait
2046
endif
2047
	push ds
2048
ife RING0
2049
	mov ax,40h		;0040h is a bimodal segment/selector
2050
	mov ds,ax
2051
	cmp byte ptr ds:[84h],30	;rows >= 30?
2052
else
2053
	mov ds, [wFlat]
2054
	cmp byte ptr ds:[484h], 30
2055
endif
2056
	pop ds
2057
	jnc nowait
2058
	mov dx,offset presskey
2059
	mov cx,sizeof presskey
2060
	call stdout
2061
;	mov ah,8		;use DOS
2062
;	int 21h
2063
	mov ah,0		;v1.27: use BIOS
2064
if RING0
2065
	.386
2066
	call cs:[int16vec]
2067
	.8086
2068
else
2069
	int 16h
2070
endif
2071
	mov al,CR
2072
	call stdoutal
2073
nowait:
2074
	ret
2075
waitkey endp
2076

2077
@movs macro dst, src
2078
if RING0 and V86M
2079
	push src
2080
	call v86setofs
2081
	pop dst
2082
else
2083
	mov dst, src
2084
endif
2085
endm
2086

2087
@dispsegm macro segm
2088
	mov ax,segm
2089
if RING0 and V86M
2090
	call chkdispsegm
2091
else
2092
	call hexword
2093
endif
2094
endm
2095

2096
	include lineasm.inc
2097

2098
if ?PM
2099
;--- called by c_cmd, e_cmd, f_cmd, m_cmd, s_cmd
2100
IsOfs32 proc
2101
	cmp cs:[bAddr32],0
2102
	ret
2103
IsOfs32 endp
2104
endif
2105

2106
;--- C command - compare bytes.
2107

2108
c_cmd proc
2109
	call parsecm		;parse arguments (sets DS:e/si, ES:e/di, e/cx)
2110
;--- note: DS unknown here
2111
if ?PM
2112
	call IsOfs32
2113
	jz $+3
2114
	db 66h	;inc ecx
2115
endif
2116
	inc cx
2117
cc1:			;<--- continue compare
2118
if INT2324
2119
	push ds
2120
	push ss		;ds=DGROUP
2121
	pop ds
2122
	call dohack	;set debuggee's int 23/24
2123
	pop ds
2124
endif
2125
if ?PM
2126
	call IsOfs32
2127
	jz $+3
2128
	db 67h	;repe cmpsb ds:[esi],es:[edi]
2129
endif
2130
	repe cmpsb
2131
	lahf
2132

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
2136

2137
if ?PM
2138
	call IsOfs32
2139
	jz @F
2140
	.386
2141
	mov dl,[esi-1]
2142
	mov dh,es:[edi-1]
2143
	.8086
2144
	jmp c_cont
2145
@@:
2146
endif
2147
	mov dl,[si-1]	;save the possibly errant characters
2148
	mov dh,es:[di-1]
2149
c_cont:
2150
if INT2324
2151
	push ds
2152
	push ss
2153
	pop ds
2154
	call unhack	;set debugger's int 23/24
2155
	pop ds
2156
endif
2157
	sahf
2158
	jne @F
2159
	jmp cc2		;if we're done
2160
@@:
2161
	push cx
2162
	push es
2163

2164
;--- set ES to dgroup ( needed for output routines )
2165
	@RestoreSeg es
2166
	sizeprfX	;mov ebx,edi
2167
	mov bx,di	;save [E]DI
2168
	mov di,offset line_out
2169
	mov ax,ds
2170
	call hexword
2171
	mov al,':'
2172
	stosb
2173
if ?PM
2174
	mov bp,offset hexword
2175
	sizeprf		;dec esi
2176
	dec si
2177
	sizeprf		;mov eax, esi
2178
	mov ax,si
2179
	sizeprf		;inc esi
2180
	inc si
2181
	call IsOfs32
2182
	jz @F
2183
	mov bp,offset hexdword
2184
@@:
2185
	call bp
2186
else
2187
	lea ax,[si-1]
2188
	call hexword
2189
endif
2190
	mov ax,'  '
2191
	stosw
2192
	mov al,dl
2193
	call hexbyte
2194
	mov ax,'  '
2195
	stosw
2196
	mov al,dh
2197
	call hexbyte
2198
	mov ax,'  '
2199
	stosw
2200
	pop ax
2201
	push ax
2202
	call hexword
2203
	mov al,':'
2204
	stosb
2205
if ?PM
2206
	sizeprf		;dec ebx
2207
	dec bx
2208
	sizeprf		;mov eax, ebx
2209
	mov ax,bx
2210
	sizeprf		;inc ebx
2211
	inc bx
2212
	call bp
2213
else
2214
	lea ax,[bx-1]
2215
	call hexword
2216
endif
2217

2218
	push ds
2219
;--- set DS to dgroup
2220
	@RestoreSeg ds
2221
	push bx
2222
	call putsline
2223
	pop di
2224
	pop ds
2225

2226
	pop es
2227
	pop cx
2228
if ?PM
2229
	call IsOfs32
2230
	jz $+3
2231
	db 67h	;jecxz cc2
2232
endif
2233
	jcxz cc2
2234
	jmp cc1		;if not done yet
2235
cc2:
2236
	@RestoreSeg ds
2237
	push ds
2238
	pop es
2239
	ret
2240
c_cmd endp
2241

2242
if DPCMD or DPCMDR0
2243

2244
dp_cmd proc
2245

2246
 if DPCMDR0
2247

2248
	.386
2249
 
2250
CONST segment
2251
szCr3 db "CR3=",0
2252
szMappedCr3 db ", mapped at ",0
2253
CONST ends
2254

2255
	mov si, offset szCr3
2256
	call copystring
2257
	mov eax, cr3
2258
	call hexdword
2259
	mov esi, cr3
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
2263

2264
;--- callout int 22h requires to set the host ring0 stack!
2265

2266
	mov bp, sp
2267
	mov dx, ss
2268
	lss esp, [r0SSEsp]
2269
	int 22h		; win396 debugger interface
2270
	mov ss, dx
2271
	mov sp, bp
2272

2273
	cmp ax, 1
2274
	jnz exit
2275
	push esi
2276
	mov si, offset szCr3
2277
	call copystring
2278
	pop eax
2279
	call hexdword
2280
exit:
2281
	call putsline
2282
	ret
2283

2284
 else
2285

2286
;--- DP disk - display partition table of a fixed disk
2287

2288
	call getbyte		;get byte into DL
2289
	call chkeol			;expect end of line here
2290
	mov bp, sp
2291
	mov al, dl
2292
	mov dx, offset szNoHD
2293
	and al, al
2294
	jns error
2295
	sub sp, 512
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
2301
	call readsect
2302
	jc error
2303
	add sp, 1BEh	; offset PT
2304
	mov si, sp
2305
	mov cx, 4
2306
nextp:
2307
	push cx
2308
	mov di, offset line_out
2309
	mov ax, ' 4'
2310
	sub al, cl
2311
	stosw
2312
	mov al, [si+4]	; partition type
2313
	call hexbyte
2314
	mov al, ' '
2315
	stosb
2316
	mov ax, [si+10]	; hiword start LBA
2317
	call hexword
2318
	mov ax, [si+8]	; loword start LBA
2319
	call hexword
2320
	mov al, ' '
2321
	stosb
2322
	mov ax, [si+14]	; hiword size LBA
2323
	call hexword
2324
	mov ax, [si+12]	; loword size LBA
2325
	call hexword
2326
	call putsline
2327
	pop cx
2328
	add si, 16
2329
	loop nextp
2330
	mov sp, bp
2331
	ret
2332
error:
2333
	mov sp, bp
2334
	call int21ah9
2335
	ret
2336
 endif
2337
dp_cmd endp
2338
endif
2339

2340
if RING0
2341

2342
;--- get base of descriptor table for selector in BX
2343
;--- out: NC, eax=base, dx=limit
2344
;---       C if error
2345
;--- other registers preserved
2346

2347
	.386
2348

2349
getlinearbaseDT proc
2350
if FLATSS
2351
	sub esp, 6
2352
	sgdt [esp]
2353
else
2354
	push bp
2355
	mov bp, sp
2356
	sub sp, 6
2357
	sgdt [bp-6]
2358
endif
2359
;	mov dx, [bp-6]
2360
;	mov eax, [bp-4]	; get linear address GDT
2361
	@dprintf "getlinearbaseDT: bx=%X", bx
2362
	pop dx
2363
	pop eax
2364
	test bl, 4
2365
	jz isgdt
2366
	push bx
2367
	sldt bx
2368
	@dprintf "getlinearbaseDT: ldt=%X", bx
2369
	call getlinearbaseBX
2370
	@dprintf "getlinearbaseDT: eax=%lX", eax
2371
	pop bx
2372
isgdt:
2373
	push ax
2374
	lar ax, bx
2375
	setnz al
2376
	shr al,1
2377
	pop ax
2378
ife FLATSS
2379
	pop bp
2380
endif
2381
	ret
2382
getlinearbaseDT endp
2383

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
2387

2388
getlinearbaseBX proc
2389
	movzx edx, bx
2390
	and dl, 0f8h
2391
	add eax, edx	; now eax -> GDT/LDT descriptor
2392
	push ds
2393
	mov ds, [wFlat]
2394
	mov dl, [eax+4]
2395
	mov dh, [eax+7]
2396
	shl edx, 16
2397
	mov dx, [eax+2]
2398
	mov ax, [eax+0]
2399
	xchg eax, edx	; base to eax, limit to dx
2400
	pop ds
2401
	ret
2402
getlinearbaseBX endp
2403

2404
endif
2405

2406
if DGCMD or DLCMD
2407

2408
 if RING0
2409
CONST segment
2410
szldtr db "LDTR=",0
2411
szgdtr db "GDTR=",0
2412
CONST ends
2413
 endif
2414

2415
;--- DG/DL commands
2416
;--- ah = 'l' or 'g'
2417

2418
CONST segment
2419
descbase db ' base=???????? limit=???????? attr=????',0
2420
CONST ends
2421

2422
dgl_cmd proc
2423

2424
	push ax
2425
	call getword	;get word into DX
2426
	pop cx
2427
	mov bx, dx
2428

2429
	and bl, 0f8h
2430
 if DGCMD
2431
	cmp ch, 'g'
2432
	jz @F
2433
 endif
2434
	or bl, 4
2435
@@:
2436
	call skipcomm0
2437
	mov dx,1
2438
	cmp al,CR
2439
	jz @F
2440
	call getword
2441
	and dx,dx
2442
	jnz @F
2443
	inc dx
2444
@@:
2445
	mov si, dx		;save count
2446
if RING0
2447
 if FLATSS
2448
	mov ebp, esp
2449
 else
2450
	mov bp, sp
2451
 endif
2452
	call getlinearbaseDT	; get linear base & limit of descriptor table for BX
2453
	.386
2454
	push eax
2455
	push dx
2456
	pushf         ; save error flag of getlinearbase
2457
	push si
2458
	test bl,4
2459
	jz @F
2460
	mov si, offset szldtr
2461
	call copystring
2462
	sldt ax
2463
	call hexword
2464
	jmp ldtrdone
2465
@@:
2466
	mov si, offset szgdtr
2467
	call copystring
2468
 if FLATSS
2469
	mov ax,[ebp-6]
2470
 else
2471
	mov ax,[bp-6]
2472
 endif
2473
	call hexword
2474
	mov al,'.'
2475
	stosb
2476
 if FLATSS
2477
	mov eax,[ebp-4]
2478
 else
2479
	mov eax,[bp-4]
2480
 endif
2481
	call hexdword
2482
ldtrdone:
2483
	call putsline
2484
	pop si
2485
	popf
2486
	jnc @F
2487
	test bl,4
2488
	jz @F
2489
	jmp done
2490
@@:
2491
endif
2492
if ?DPMI
2493
	.286
2494
	call ispm_dbg
2495
	jnz nextdesc
2496
	mov si,offset nodesc	; error "not accessible in real-mode"
2497
	call copystring
2498
	jmp putsline
2499
endif
2500

2501
nextdesc:
2502
	mov di,offset line_out
2503
	mov ax,bx
2504
	call hexword
2505
	push si
2506
	push di
2507
	mov si,offset descbase
2508
	call copystring
2509
	pop di
2510
	pop si
2511
;	lar ax,bx
2512
;	jnz skipdesc	;tell that this descriptor is invalid
2513
 if ?DPMI
2514
	mov ax,6
2515
	int 31h
2516
	jc @F
2517
 elseif RING0
2518
	.386
2519
  if FLATSS
2520
	cmp bx, [ebp-6]	;beyond limit?
2521
  else
2522
	cmp bx, [bp-6]	;beyond limit?
2523
  endif
2524
	jae nogdt
2525
	push ds
2526
	movzx eax, bx
2527
	and al, 0F8h
2528
  if FLATSS
2529
	add eax, [ebp-4]
2530
  else
2531
	add eax, [bp-4]
2532
  endif
2533
	mov ds, [wFlat]
2534
	mov dx, [eax+2]
2535
	mov cl, [eax+4]
2536
	mov ch, [eax+7]
2537
	.286
2538
	pop ds
2539
	stc
2540
nogdt:
2541
	jnc done
2542
	lar ax, bx
2543
	jnz desc_out
2544
 endif
2545
	add di, 6	; render base
2546
	mov ax,cx
2547
	call hexword
2548
	mov ax,dx
2549
	call hexword
2550
@@:
2551
	sizeprf		;lsl eax,ebx
2552
	lsl ax,bx
2553
	jnz desc_out
2554
	sizeprf		;lar edx,ebx
2555
	lar dx,bx
2556
	sizeprf		;shr edx,8
2557
	shr dx,8
2558
	mov di,offset line_out+25
2559
	cmp [machine],3
2560
	jb @F
2561
	call hexdword; limit 32-bit
2562
	jmp desc_o2
2563
@@:
2564
	call hexword; limit 16-bit
2565
	mov ax,"  "
2566
	stosw
2567
	stosw
2568
desc_o2:
2569
	mov di,offset line_out+25+14
2570
	mov ax,dx
2571
	call hexword; attr   
2572
desc_out:
2573
	mov di,offset line_out+25+14+4 ; position to end of line
2574
	call putsline	; add cr/lf, then print
2575
	add bx,8
2576
	dec si
2577
	jnz nextdesc
2578
done:
2579
if RING0
2580
 if FLATSS
2581
	.386
2582
	mov esp, ebp
2583
 else
2584
	mov sp, bp
2585
 endif
2586
endif
2587
	ret
2588
dgl_cmd endp
2589

2590
endif
2591

2592
if DICMD
2593

2594
 if RING0
2595
CONST segment
2596
szidtr db "IDTR=",0
2597
CONST ends
2598
 endif
2599

2600
 if RING0
2601
GATE struct
2602
wOfsLo dw ?
2603
wSeg   dw ?
2604
wAttr  dw ?
2605
wOfsHi dw ?
2606
GATE ends
2607
 endif
2608

2609
;--- DI command
2610

2611
di_cmd proc
2612
	call getbyte	;get byte into DL
2613
	mov bx,dx
2614
	call skipcomm0
2615
	mov dx,1
2616
	cmp al,CR
2617
	jz @F
2618
	call getword	;get word into DL ( max is 100h )
2619
	call chkeol
2620
	and dx,dx
2621
	jnz @F
2622
	inc dx			;ensure that count is at least 1
2623
@@:
2624
	mov si,dx		;save count
2625
if RING0
2626
	sidt [real_end-6]
2627
	push si
2628
	mov si, offset szidtr
2629
	call copystring
2630
	pop si
2631
	mov ax,word ptr [real_end-6]
2632
	call hexword
2633
	mov al,'.'
2634
	stosb
2635
	.386
2636
	mov eax,dword ptr [real_end-4]
2637
	call hexdword
2638
	call putsline
2639
endif
2640
	call prephack
2641
gateout_00: 		;<--- next int/exc
2642
	mov di,offset line_out
2643
	mov al,bl
2644
	call hexbyte
2645
	mov al,' '
2646
	stosb
2647
if ?PM
2648
 if ?DPMI
2649
	call ispm_dbe
2650
	jz gaterm
2651
	.286
2652
	mov ax,204h
2653
	cmp bl,20h
2654
	adc bh,1
2655
gateout_01:
2656
	int 31h
2657
	jc gatefailed
2658
	mov ax,cx
2659
	call hexword
2660
	mov al,':'
2661
	stosb
2662
	test [dpmi32],1
2663
	jz gate16
2664
	.386
2665
	shld eax,edx,16
2666
	call hexword
2667
	.8086
2668
gate16:
2669
	mov ax,dx
2670
	call hexword
2671
	mov al,' '
2672
	stosb
2673
	mov ax,0202h
2674
	dec bh
2675
	jnz gateout_01
2676
 else
2677
	.386
2678
	push bx
2679
	movzx ebx, bl
2680
 if V86M
2681
	mov dl, bl
2682
 endif
2683
 if LMODE
2684
	shl bx, 4
2685
 else
2686
	shl bx, 3
2687
 endif
2688
	cmp bx, word ptr [real_end-6]
2689
	ja di_done
2690
	add ebx, dword ptr [real_end-4]
2691
	push ds
2692
	mov ds, [wFlat]
2693
	mov ax, [ebx].GATE.wSeg
2694
	call hexword
2695
	mov al, ':'
2696
	stosb
2697
	mov ax, [ebx].GATE.wOfsHi
2698
	call hexword
2699
	mov ax, [ebx].GATE.wOfsLo
2700
	call hexword
2701
	mov eax, '=ta '
2702
	stosd
2703
	mov ax, [ebx].GATE.wAttr
2704
	call hexword
2705
 if V86M
2706
	mov eax, "=vi "
2707
	stosd
2708
	movzx ebx, dl
2709
	mov ax, [ebx*4+2]
2710
	call hexword
2711
	mov al,':'
2712
	stosb
2713
	mov ax, [ebx*4+0]
2714
	call hexword
2715
 endif
2716
	.8086
2717
	pop ds
2718
	pop bx
2719
 endif
2720
else
2721
	jmp gaterm
2722
endif
2723
gate_exit:
2724
	call putsline
2725
	inc bl
2726
	jz di_done
2727
	dec si
2728
	jnz gateout_00
2729
di_done:
2730
	ret
2731
if ?DPMI
2732
gatefailed:
2733
	mov di,offset line_out
2734
	mov si,offset gatewrong
2735
	call copystring
2736
	mov si,1
2737
	jmp gate_exit
2738
endif
2739
gaterm:
2740
	call dohack		;set debuggee's int 23/24
2741
	mov cl,2
2742
	push bx
2743
	shl bx,cl
2744
	push ds
2745
	xor ax,ax
2746
	mov ds,ax
2747
	mov ax,[bx+2]
2748
	mov dx,[bx+0]
2749
	pop ds
2750
	pop bx
2751
	call unhack		;set debugger's int 23/24
2752
	call hexword
2753
	mov al,':'
2754
	stosb
2755
	mov ax,dx
2756
	call hexword
2757
	jmp gate_exit
2758
di_cmd endp
2759

2760
endif
2761

2762
	.8086
2763

2764
if DMCMD
2765

2766
;--- dm cmd: display list of MCBs
2767
;--- DI=lineout
2768

2769
dm_cmd proc
2770
;	mov di,offset line_out
2771
	mov ax,"SP"
2772
	stosw
2773
	mov ax,":P"
2774
	stosw
2775
	mov ax,[pspdbe]
2776
	call hexword
2777
	call putsline	;destroys cx,dx,bx
2778

2779
	mov si,[wMCB]
2780
	push ds
2781
nextmcb:
2782
	mov di,offset line_out
2783
	call setds2si
2784
	mov ax,si
2785
	call hexword	;segment address of MCB
2786
	mov al,' '
2787
	stosb
2788
	mov al,ds:[0000];'M' or 'Z'
2789
	cmp al,'Z'
2790
	jz @F
2791
	cmp al,'M'
2792
	jnz mcbout_done
2793
@@:
2794
	call hexbyte
2795
	mov al,' '
2796
	stosb
2797
	mov ax,ds:[0001];MCB owner
2798
	mov bx,ax
2799
	call hexword
2800
	mov al,' '
2801
	stosb
2802
	mov ax,ds:[0003];MCB size in paragraphs
2803
	mov dx,ax
2804
	call hexword
2805
	mov al,' '
2806
	stosb
2807
	and bx,bx
2808
	jz mcbisfree
2809
	push si
2810
	push dx
2811
	mov si,8
2812
	mov cx,2 
2813
	cmp bx,si		;is it a "system" MCB?
2814
	jz nextmcbchar
2815
	dec bx
2816
	call setds2bx	;destroys cx if in pm
2817
	mov cx,8
2818
nextmcbchar:		;copy "name" of owner MCB
2819
	lodsb
2820
	stosb
2821
	and al,al
2822
	loopnz nextmcbchar
2823
	pop dx
2824
	pop si
2825
mcbisfree:
2826
	add si,dx
2827
	jc mcbout_done
2828
	inc si
2829
	pop ds
2830
	push ds
2831
	call putsline	;destroys cx,dx,bx
2832
	jmp nextmcb
2833
mcbout_done:
2834
	pop ds
2835
	ret
2836

2837
setds2si:
2838
	mov bx,si
2839
setds2bx:
2840
if ?DPMI
2841
	call ispm_dbe
2842
	jz sd2s_ex
2843
	mov dx,bx
2844
	call setrmsegm
2845
sd2s_ex:
2846
endif
2847
	mov ds,bx
2848
	ret
2849
dm_cmd endp
2850

2851
endif
2852

2853
if DTCMD
2854

2855
 ife LMODE
2856

2857
;--- "legacy TSS"
2858

2859
TSS struct
2860
dwLink	dd ?	;+00 selector
2861
_Esp0	dd ?	;+04
2862
_SS0    dd ?
2863
dqStk1	dq ?	;+0C
2864
dqStk2	dq ?	;+14
2865
_CR3	dd ?	;+1C
2866
_Eip	dd ?	;+20
2867
_Efl	dd ?	;+24
2868
_Eax	dd ?	;+28
2869
_Ecx	dd ?	;+2C
2870
_Edx	dd ?	;+30
2871
_Ebx	dd ?	;+34
2872
_Esp	dd ?	;+38
2873
_Ebp	dd ?	;+3C
2874
_Esi	dd ?	;+40
2875
_Edi	dd ?	;+44
2876
_ES		dd ?	;+48
2877
_CS		dd ?	;+4C
2878
_SS		dd ?	;+50
2879
_DS		dd ?	;+54
2880
_FS		dd ?	;+58
2881
_GS		dd ?	;+5C
2882
_LDT	dd ?	;+60
2883
wFlags  dw ?	;+64
2884
wOffs   dw ?	;+66
2885
TSS ends
2886

2887
 else
2888

2889
;--- long mode TSS
2890

2891
TSS struct
2892
		dd ?	;+00
2893
_Rsp0	dq ?	;+04
2894
_Rsp1	dq ?	;+0C
2895
_Rsp2	dq ?	;+14
2896
		dd ?	;+1C
2897
_Ist1	dq ?	;+24
2898
_Ist2	dq ?	;+2C
2899
_Ist3	dq ?	;+34
2900
_Ist4	dq ?	;+3C
2901
_Ist5	dq ?	;+44
2902
_Ist6	dq ?	;+4C
2903
_Ist7	dq ?	;+54
2904
		dq ?	;+5C
2905
		dw ?	;+64
2906
wOffs   dw ?	;+66
2907
TSS ends
2908
 endif
2909

2910
CONST segment
2911
if LMODE
2912
szPL0Stk db " RSP0=",0
2913
else
2914
szPL0Stk db " R0 SS:ESP=",0
2915
endif
2916
szIOPB db " IOPB=",0
2917
szTrapped db "trapped ports:",13,10,'$'
2918
CONST ends
2919
 
2920
dt_cmd proc
2921
	.386
2922
	xor dx, dx
2923
	cmp al,CR
2924
	jz @F
2925
	call getword	;get word into DX
2926
	call skipcomm0
2927
	cmp al,CR
2928
	jz cmd_error
2929
	mov bp, dx
2930
	call getword	;get word into DX
2931
	call skipcomm0
2932
	cmp al,CR
2933
	jnz cmd_error
2934
@@:
2935
	mov si, dx
2936
	mov ax,"RT"
2937
	stosw
2938
	mov al,'='
2939
	stosb
2940
	str ax
2941
	mov bx, ax
2942
	call hexword
2943
	cmp bx,0
2944
	jz done
2945
	call getlinearbaseDT	;TSS is always in GDT
2946
	jc done
2947
	call getlinearbaseBX	;ret: eax=linear addr, dx=limit
2948
	@dprintf "dt: bx=%X eax=%lX, limit=%X", bx, eax, dx
2949
	mov ebx, eax
2950
	push si
2951
	mov si, offset szPL0Stk
2952
	call copystring
2953
	pop si
2954
	push ds
2955
	mov ds, [wFlat]
2956
if LMODE
2957
	mov eax, dword ptr [ebx].TSS._Rsp0+4
2958
	call hexdword
2959
	mov eax, dword ptr [ebx].TSS._Rsp0+0
2960
	call hexdword
2961
else
2962
	mov ax, word ptr [ebx].TSS._SS0
2963
	call hexword
2964
	mov al,':'
2965
	stosb
2966
	mov eax, [ebx].TSS._Esp0
2967
	call hexdword
2968
endif
2969

2970
;--- display trapped ports;
2971

2972
;--- check if TSS does indeed include an IO permission bitmap.
2973
;--- DX=limit TSS
2974
;--- BP=port to start with
2975
;--- SI=number of ports to check
2976

2977
	mov ax, bp
2978
	add ax, si
2979
	add ax, 8-1
2980
	shr ax, 3
2981
	add ax, [ebx].TSS.wOffs
2982
	cmp dx, ax
2983
	jc done
2984

2985
	movzx eax, [ebx].TSS.wOffs
2986
	pop ds
2987
	add eax, ebx
2988
	push ax
2989
	push si
2990
	mov si, offset szIOPB
2991
	call copystring
2992
	pop si
2993
	pop ax
2994
	mov ebx, eax
2995
	call hexdword
2996
	cmp si, 0
2997
	jz done
2998
	@dprintf "dt_cmd: start port=%X cnt=%X", bp, si
2999
	call putsline
3000
	mov di, offset line_out
3001
	mov dx, offset szTrapped
3002
	call int21ah9
3003
	mov cx, si
3004
	movzx ebp, bp
3005
	mov dl,0
3006
nextport:
3007
	push ds
3008
	mov ds, [wFlat]
3009
	bt [ebx], ebp
3010
	pop ds
3011
	jnc @F
3012
	@dprintf "dt_cmd: found trapped port=%X", bp
3013
	mov ax, bp
3014
	call hexword
3015
	mov al,' '
3016
	stosb
3017
	inc dl
3018
	test dl, 7
3019
	jnz @F
3020
	pusha
3021
	call putsline
3022
	popa
3023
	mov di, offset line_out
3024
@@:
3025
	inc bp
3026
	loopnz nextport
3027
done:
3028
	call putsline
3029
	ret
3030
dt_cmd endp
3031

3032
endif
3033

3034
;--- DX command. Display extended memory
3035
;--- works for 80386+ only.
3036

3037
if DXCMD
3038

3039
if USEUNREAL
3040

3041
    align 4
3042
gdt label qword
3043
	dw -1,0,9200h,0CFh	; 32-bit flat data descriptor
3044
	dw -1,0,9200h,0		; 16-bit data descriptor
3045
GDTR label fword
3046
	dw 3*8-1
3047
	dd 0
3048

3049
SEL_FLAT equ 8
3050
SEL_DATA16 equ 16
3051

3052
	.386p
3053
;--- set/reset unreal mode
3054
setdspm:
3055
	cli
3056
	mov ax,cs
3057
	movzx eax,ax
3058
	shl eax,4
3059
	add eax,offset gdt-8
3060
	mov dword ptr cs:[GDTR+2],eax
3061
	lgdt cs:[GDTR]
3062
	mov eax,cr0
3063
	inc ax
3064
	mov cr0,eax
3065
	jmp @F
3066
@@:
3067
	mov ds,cx
3068
	dec ax
3069
	mov cr0,eax
3070
	jmp @F
3071
@@:
3072
	sti
3073
	ret
3074

3075
	.386
3076

3077
;--- exception 0D: 
3078

3079
int0d:
3080
if 1
3081
	push ax         ; check for IRQ. If request, jmp to previous handler
3082
	mov al, 0Bh
3083
	out 20h, al
3084
	in al, 20h
3085
	test al, 20h	; real IRQ 5?
3086
	pop ax
3087
	jz @F
3088
	db 0eah
3089
oldint0d dd ?
3090
@@:
3091
endif
3092
	push ds
3093
	push eax
3094
	push cx
3095
	mov cx,SEL_FLAT
3096
	call setdspm
3097
	pop cx
3098
	pop eax
3099
	mov al,0
3100
	pop ds
3101
	iret
3102
endif
3103

3104
dx_cmd proc
3105
	cmp [machine],3
3106
	jb cmd_error
3107
	.386
3108
	mov dx,word ptr [x_addr+0]
3109
	mov bx,word ptr [x_addr+2]
3110
	cmp al,CR
3111
	jz @F
3112
	call getdword	;get linear address into bx:dx
3113
	call chkeol		;expect end of line here
3114
@@:
3115
	mov [lastcmd],offset dx_cmd
3116
	push bx
3117
	push dx
3118
	pop ebp
3119

3120
if USEUNREAL
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!
3125

3126
	smsw ax			; don't use ispm, since that won't detect v86! 
3127
	test al,1
3128
	jnz dx_exit
3129
	push ds
3130
	push cs
3131
	push offset int0d
3132
	pop eax
3133
	xor ecx,ecx
3134
	mov ds,cx
3135
	mov ebx, ds:[0dh*4]
3136
	mov cs:[oldint0d], ebx
3137
	mov ds:[0dh*4], eax
3138
	mov esi,ebp
3139
	mov al,1
3140
	mov cl,20h
3141
	mov edi,offset line_out+128
3142
	rep movsd es:[edi], ds:[esi]
3143
	mov ds:[0dh*4], ebx
3144
	dec al    ;has an exception occured?
3145
	jz @F     ;if no, don't reset unreal mode!
3146
	mov cx,SEL_DATA16
3147
	call setdspm
3148
@@:
3149
	pop ds
3150
else
3151
;	mov di,offset line_out	;create a GDT for Int 15h, ah=87h
3152
	xor ax,ax
3153
	mov cx,6*4	;init 6 descriptors (48 bytes)
3154
	rep stosw
3155
	sub di,4*8
3156
	mov ax,007Fh;limit of source (128 bytes)
3157
	stosw
3158
	mov ax,dx   ;base[0-15] of source
3159
	stosw
3160
	mov al,bl   ;base[16-23] of source
3161
	stosb
3162
	mov ax,0093h
3163
	stosw
3164
	mov al,bh   ;base[24-31] of source
3165
	stosb
3166
	mov ax,007Fh;limit of dest
3167
	stosw
3168
	lea eax,[line_out+128]
3169
	movzx ebx,[wDgroup]
3170
	shl ebx,4
3171
	add eax,ebx
3172
	stosw       ;base[0-15] of dest
3173
	shr eax,16
3174
	stosb       ;base[16-23] of dest
3175
	mov bl,ah
3176
	mov ax,0093h
3177
	stosw
3178
	mov al,bl
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
3182
	mov ah,87h
3183
 if ?DPMI
3184
	call ispm_dbg
3185
	jz @F
3186
	invoke simrealmodeint, 15h, cs:[wDgroup]
3187
	jmp i15ok
3188
@@:
3189
 endif
3190
	int 15h
3191
i15ok:
3192
	jc dx_exit
3193
endif
3194
	mov si,offset line_out+128
3195
	mov ch,8h
3196
nextline:
3197
	mov di,offset line_out
3198
	mov eax,ebp
3199
	call hexdword
3200
	mov ax,"  "
3201
	stosw
3202
	lea bx,[di+3*16]
3203
	mov cl,10h
3204
nextbyte:
3205
	lodsb
3206
	mov ah,al
3207
	cmp al,20h
3208
	jnc @F
3209
	mov ah,'.'
3210
@@:
3211
	mov [bx],ah
3212
	inc bx
3213
	call hexbyte
3214
	mov al,' '
3215
	stosb
3216
	dec cl
3217
	jnz nextbyte
3218
	mov byte ptr [di-(8*3+1)],'-'	;display a '-' after 8 bytes
3219
	mov di,bx
3220
	push cx
3221
	call putsline
3222
	pop cx
3223
	add ebp,10h
3224
	dec ch
3225
	jnz nextline
3226
	mov [x_addr],ebp
3227
dx_exit:
3228
	ret
3229
	.8086
3230
dx_cmd endp
3231

3232
endif
3233

3234
if RING0 and V86M
3235
chkdispsegm proc
3236
	test byte ptr[regs.rFL+2],2
3237
	jz @F
3238
	cmp ax, [scratchsel]
3239
	jnz @F
3240
	mov ax, [scratchv86]
3241
@@:
3242
	jmp hexword
3243
chkdispsegm endp
3244
endif
3245

3246
;--- D command - hex/ascii dump.
3247

3248
d_cmd proc
3249
	cmp al,CR
3250
	jne dd1		; if an argument was given
3251
	sizeprfX	; mov edx,[d_addr]
3252
	mov dx,[d_addr]
3253
	mov bx, [d_addr+4]
3254
if RING0
3255
	verr bx
3256
	jz @F
3257
	@movs bx, [regs.rDS]
3258
	xor edx, edx
3259
@@:
3260
endif
3261
	sizeprfX	; mov esi,edx
3262
	mov si,dx
3263

3264
;--- ?PM: we don't know yet if limit is > 64kB
3265
;--- so we stop at 64 kB in any case
3266

3267
	add dx,80h-1; compute range of 80h or until end of segment
3268
	jnc dd2
3269
	or dx, -1
3270
	jmp dd2
3271

3272
DMPJT struct
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
3277
DMPJT ends
3278

3279
CONST segment
3280
dd16 DMPJT < hexword, getb16, load16, end16>
3281
if ?PM
3282
dd32 DMPJT <hexdword, getb32, load32, end32>
3283
endif
3284
CONST ends
3285

3286
ife DGCMD+DICMD+DLCMD+DPCMD+DTCMD+DXCMD	; if just the DM cmd exists (std debug)
3287

3288
dd1:
3289
	cmp ah,'d'	; char 'd' just before g/i/l/m/p/t/x?
3290
	jnz dd1_1
3291
	or al,TOLOWER
3292
 if DMCMD
3293
	cmp al,'m'
3294
	jz dm_cmd
3295
 endif
3296

3297
else
3298

3299
@condcmd macro ifcond, byt_,ofs_
3300
if ifcond
3301
	db byt_
3302
	dw offset ofs_
3303
endif
3304
endm
3305

3306
CONST segment
3307
dcmds label byte
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
3316
CONST ends
3317

3318
d_subcmd:
3319
	mov ah, al
3320
	call skipwhite
3321
	jmp word ptr [bx+1]
3322
dd1:
3323
	cmp ah,'d'	; char 'd' just before g/i/l/m/p/t/x?
3324
	jnz dd1_1
3325
	or al,TOLOWER
3326
	mov bx, offset dcmds
3327
	mov cx, size_dcmds
3328
@@:
3329
	cmp al,[bx]
3330
	jz d_subcmd
3331
	add bx, 3
3332
	loop @B
3333
endif
3334

3335
if FLATSS
3336
DMPPFX textequ <cs:>
3337
else
3338
DMPPFX textequ <>
3339
endif
3340

3341
dd1_1:
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
3345

3346
	sizeprfX	; mov esi,edx
3347
	mov si,dx
3348
	sizeprfX	; mov edx,ecx (14.2.2021)
3349
	mov dx,cx	; dx = end address
3350
    
3351
;--- Parsing is done.  Print lines.
3352
;--- BX=segment/selector
3353
;--- E/SI=src offset, E/DX=end src
3354

3355
dd2:
3356
	mov [d_addr+4], bx	;save segment/selector (offset is saved later)
3357
	mov [lastcmd], offset d_cmd
3358
	mov bp, offset dd16
3359
if ?PM
3360
	call getseglimit	;Z flag set if segment limit is <= 64 kB
3361
	jz @F
3362
	mov bp, offset dd32
3363
@@:
3364
endif
3365
	@dprintf "d: bx:esi=%X:%lX edx=%lx", bx, esi, edx
3366
	call prephack	;set up for faking int vectors 23 and 24
3367

3368
nextline:
3369
	mov di,offset line_out
3370
	@dispsegm [d_addr+4]
3371
	mov al,':'
3372
	stosb
3373
	sizeprfX		; mov eax, esi
3374
	mov ax, si
3375
	and al, 0f0h
3376
	mov cx, si
3377
	sub cx, ax
3378
	call DMPPFX[bp].DMPJT.pDispOfs
3379
;--- blank the line
3380
	mov ax,'  '
3381
	stosw
3382
	lea bx, [di+3*16]
3383
	add bx, cx
3384
	push cx
3385
	push di
3386
	mov cx, bx
3387
	sub cx, di
3388
	rep stosb
3389
	pop di
3390
	pop cx
3391
	mov byte ptr [di+3*8-1],'-'
3392
	add di,cx
3393
	add cx,cx
3394
	add di,cx
3395

3396
	call DMPPFX[bp].DMPJT.pGetB
3397

3398
	call dohack		;set debuggee's int 23/24
3399
	mov ds,[d_addr+4]
3400
nextbyte:
3401
	call DMPPFX[bp].DMPJT.pLoad
3402
	push ax
3403
	call hexbyte
3404
	inc di
3405
	pop ax
3406
	cmp al,' '
3407
	jb dd7		;if control character
3408
	cmp al,'~'
3409
	jbe dd8		;if printable
3410
dd7:
3411
	mov al,'.'
3412
dd8:
3413
	mov es:[bx],al
3414
	inc bx
3415
	loop nextbyte
3416

3417
	push es		;restore ds
3418
	pop ds
3419

3420
	call unhack	;set debugger's int 23/24
3421
	mov di,bx
3422
	push dx
3423
	call putsline
3424
	pop dx
3425
	call DMPPFX[bp].DMPJT.pEnd
3426
	jc nextline
3427
	sizeprfX	;mov [d_addr],esi
3428
	mov [d_addr],si
3429
	ret
3430

3431
if ?PM
3432
load32:
3433
	db 67h			;lodsb [esi] 
3434
endif
3435
load16:
3436
	lodsb
3437
	ret
3438
getb16:
3439
	mov cx,si
3440
	or cl,0fh
3441
	cmp cx,dx		;compare with end address
3442
	jb @F			;if we write to the end of the line
3443
	mov cx,dx
3444
@@:
3445
	sub cx,si
3446
	inc cx			;cx = number of bytes to print this line
3447
	ret
3448
end16:
3449
	dec si
3450
	cmp si,dx
3451
	inc si
3452
	ret
3453

3454
if ?PM
3455
	.386
3456
getb32:
3457
	mov ecx, esi
3458
	or cl, 0fh
3459
	cmp ecx, edx
3460
	jb @F
3461
	mov ecx, edx
3462
@@:
3463
	sub ecx, esi
3464
	inc ecx
3465
	ret
3466
end32:
3467
	dec esi
3468
	cmp esi, edx
3469
	inc esi
3470
	ret
3471
	.8086
3472
endif
3473

3474
d_cmd endp
3475

3476
if RING0 and V86M
3477

3478
v86setofs:
3479
	test byte ptr [regs.rFL+2], 2	; v86-mode
3480
	jz nov86
3481
	.386
3482

3483
;--- either use scratch selector or flat selector
3484
;--- both variants have their pros and cons.
3485
;--- still to decide...
3486

3487
 if 0
3488

3489
V86OFSFR struct
3490
	dd ?	;edx
3491
	dw ?	;return addr
3492
wSegm dw ?	;src/dst register
3493
V86OFSFR ends
3494

3495
	push edx
3496
	movzx edx, [esp].V86OFSFR.wSegm
3497
	shl edx, 4
3498
	mov [dwV86Ofs], edx
3499
	mov dx, [wFlat]
3500
	mov [esp].V86OFSFR.wSegm, dx
3501
	pop edx
3502
 else
3503

3504
V86OFSFR struct
3505
	dw ?	;dx
3506
	dw ?	;bx
3507
	dw ?	;return addr
3508
wSegm dw ?	;src/dst register
3509
V86OFSFR ends
3510

3511
	push dx
3512
	push bx
3513
	mov dx, [esp].V86OFSFR.wSegm
3514
	call setscratchsel  
3515
	mov [esp].V86OFSFR.wSegm, bx
3516
	pop bx
3517
	pop dx
3518
 endif
3519
nov86:
3520
	ret
3521
endif
3522

3523
errorj4:
3524
	jmp cmd_error
3525

3526
;--- E command - edit memory.
3527

3528
e_cmd proc
3529
	call prephack
3530
	@movs bx,[regs.rDS]
3531
	call getaddr	;get address into bx:(e)dx
3532
	call skipcomm0
3533
	cmp al,CR
3534
	je ee1			;if prompt mode
3535
	push dx			;save destination offset
3536
	call getstr		;get data bytes SI -> line_out
3537
	mov cx,di
3538
	mov dx,offset line_out
3539
	sub cx,dx		;length of byte string
3540
	pop di
3541
	mov ax,cx
3542
	dec ax
3543
if ?PM
3544
	call IsOfs32	;v1.29: if limit is > 64kB, skip test
3545
	jnz @F
3546
endif
3547
	add ax,di
3548
	jc errorj4		;if it wraps around
3549
@@:
3550
	call dohack		;set debuggee's int 23/24
3551
	mov si,dx
3552
if ?PM
3553
	call IsWriteableBX
3554
endif
3555
	mov es, bx
3556
if ?PM
3557
	call IsOfs32
3558
	jz @F
3559
	.386
3560
	mov dx,di		;dx was destroyed
3561
	mov edi,edx
3562
	movzx esi,si
3563
	movzx ecx,cx
3564
	db 67h		;rep movsb [edi], [esi]
3565
	.8086
3566
@@:
3567
endif
3568
	rep movsb
3569

3570
;--- Restore ds + es and undo the interrupt vector hack.
3571
;--- This code is also used by the 'm' command.
3572

3573
ee0a::
3574
	@RestoreSeg ds
3575
	push ds			;restore es
3576
	pop es
3577
if INT2324
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
3582
endif
3583
	ret
3584

3585
;--- Prompt mode. BX:E/DX=addr, DI=line_out
3586

3587
ee1:
3588
	@dprintf "e: bx:edx=%X:%lX", bx, edx
3589
if REDIRECT
3590
	mov [bufnext], si  ; update buffer ptr in case stdin is file
3591
endif
3592
	mov bp,offset hexword
3593
if ?PM
3594
	call IsOfs32
3595
	jz @F
3596
	mov bp,offset hexdword
3597
@@:
3598
endif
3599

3600
;--- Begin loop over lines.
3601

3602
e_nextl:			;<--- next line
3603
	@dispsegm bx	;print out segment part
3604
	mov al,':'
3605
	stosb
3606
	sizeprfX		;mov eax,edx
3607
	mov ax,dx
3608
	call bp
3609

3610
;--- Begin loop over bytes.
3611

3612
e_nextb:			;<--- next byte
3613
	push bx
3614
	push dx
3615
	mov ax,'  '
3616
	stosw
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
3621
	mov al,'.'
3622
	stosb
3623
	call puts
3624
	pop dx
3625
	pop bx
3626
	mov si,offset line_out+16	;address of buffer for characters
3627
	xor cx,cx		;number of characters so far
3628

3629
;--- get a byte (2 chars)
3630
;--- this is a simple "editor" that allows max 2 chars as input:
3631
;--- + 0-9 or A-F
3632
;--- + control chars SPACE, CR, BS, '-'
3633

3634
e_nextc:			;<--- get next char
3635
if REDIRECT
3636
	test [fStdin], AT_DEVICE
3637
	jnz ee9			;jmp if it's a tty
3638
	push si
3639
	mov si,[bufnext]
3640
	cmp si,[bufend]
3641
	jb @F			;if there's a character already
3642
	call fillbuf	;fill buffer with a new line; init SI
3643
	mov al,CR
3644
	jc ee8			;if eof
3645
@@:
3646
	lodsb			;get the character
3647
ee8:
3648
	mov [bufnext],si
3649
	pop si
3650
	jmp ee10
3651
endif
3652
ee9:
3653
ife RING0
3654
	call InDos      ;v1.27: use BIOS if InDOS
3655
	jnz @F
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
3659
	jmp ee10
3660
@@:
3661
endif
3662
	mov ah,0h
3663
if RING0
3664
	.386
3665
	call cs:[int16vec]
3666
	.8086
3667
else
3668
	int 16h
3669
endif
3670

3671
ee10:
3672
	cmp al,' '
3673
	je e_spcr		;if done with this byte
3674
	cmp al,CR
3675
	je e_spcr		;ditto
3676
	cmp al,BS
3677
	je e_bs			;if backspace
3678
	cmp al,'-'
3679
	je e_minus		;if '-'
3680
	cmp cx,2		;otherwise, it should be a hex character
3681
	jae e_nextc		;if we have a full byte already
3682
	mov [si],al
3683
	call getnyb
3684
	jc e_nextc		;if it's not a hex character
3685
	inc cx
3686
	lodsb			;get the character back
3687
	call stdoutal
3688
	jmp e_nextc
3689
e_bs:
3690
	jcxz e_nextc	;if nothing to backspace over
3691
	dec cx
3692
	dec si
3693
	call fullbsout
3694
	jmp e_nextc
3695
e_minus:
3696
	call stdoutal
3697
	call storebyte
3698
	sizeprfX		;dec edx
3699
	dec dx			;decrement offset part
3700
	mov di,offset line_out
3701
e_newline:
3702
	mov ax,LF * 256 + CR;terminate this line
3703
	stosw
3704
	jmp e_nextl		;back for another line
3705

3706
e_spcr:
3707
	call storebyte	;store byte if CX != 0
3708
	sizeprfX		;inc edx
3709
	inc dx			;increment offset
3710
	mov di,offset line_out
3711
	cmp al,CR
3712
	je e_done
3713
	test dl,7
3714
	jz e_newline
3715
	not cx
3716
	add cx,4		;compute 3 - cx
3717
	mov al,' '
3718
	rep stosb		;store that many spaces
3719
	jmp e_nextb		;back for more
3720

3721
e_done:
3722
	jmp putsline	;call putsline and return
3723

3724
;--- byte has been entered (1 or 2 chars)
3725
;--- si->behind byte
3726
;--- cx=#chars
3727
;--- bx:e/dx: address to store byte
3728
;--- ax preserved
3729

3730
storebyte:
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
3735
	push cx
3736
	push dx
3737
	lodsb
3738
	call getbyte	;convert byte to binary (DL)
3739
	mov al,dl
3740
	pop dx
3741
	pop cx
3742
	call dohack		;set debuggee's int 23/24
3743
if ?PM
3744
	push bx			;bx may be changed by writemem in pm
3745
endif
3746
	call writemem	;write AL at BX:(E)DX
3747
if ?PM
3748
	pop bx
3749
endif
3750
if INT2324
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
3754
endif
3755
	pop ax
3756
sb_done:
3757
	ret
3758
e_cmd endp
3759

3760
;--- F command - fill memory
3761
;--- entry: SI=line, CX=0, AL=last char
3762

3763
f_cmd proc
3764
	call getrangeDS	;get address range into bx:(e)dx/(e)cx
3765
if ?PM
3766
	call IsOfs32
3767
	jz @F
3768
	.386
3769
	sub ecx, edx
3770
	inc ecx
3771
	push ecx
3772
	push edx
3773
	.8086
3774
	jmp ff_01
3775
@@:
3776
endif
3777
	sub cx,dx
3778
	inc cx		;cx = number of bytes
3779
	push cx		;save it
3780
	push dx		;save start address
3781
ff_01:
3782
	call skipcomm0
3783
	call getstr		;get string of bytes
3784
	mov cx, di
3785
	sub cx, offset line_out
3786
if ?PM
3787
	call IsWriteableBX	; ensure BX is writeable
3788
endif
3789
	mov es, bx
3790
if ?PM
3791
	call IsOfs32
3792
	jz fill_16
3793
	.386
3794
	movzx ecx, cx
3795
	pop edi
3796
	cmp ecx, 1
3797
	je onebyte32
3798
	pop eax			; eax=size ( of mem block )
3799
;	@dprintf "f_cmd: eax=%lX, ecx=%lX, es:edi=%X:%lX", eax, ecx, es, edi
3800
	cdq
3801
	div ecx			; ecx=size of hex-string entered
3802
	mov esi, offset line_out
3803
	or eax, eax
3804
	jz partial32
3805
nextcopy32:
3806
	push ecx
3807
	push esi
3808
	rep movsb es:[edi], ds:[esi]
3809
	pop esi
3810
	pop ecx
3811
	dec eax
3812
	jnz nextcopy32
3813
partial32:
3814
	mov ecx, edx
3815
;	jecxz exit		;rep with ecx=0 is a nop
3816
	rep movsb es:[edi], ds:[esi]
3817
	jmp exit
3818
onebyte32:
3819
	pop ecx
3820
	mov al,byte ptr [line_out]
3821
	rep stosb es:[edi]
3822
	jmp exit
3823
fill_16:
3824
	.8086
3825
endif
3826
	pop di
3827
	cmp cx,1
3828
	je onebyte16;a common optimization
3829
	pop ax		;get size
3830
	xor dx,dx	;now size in DX:AX
3831
	cmp ax,1
3832
	adc dx,0	;convert 0000:0000 to 0001:0000
3833
	div cx		;compute number of whole repetitions
3834
	mov si,offset line_out
3835
	or ax,ax
3836
	jz partial16;if less than one whole rep
3837
nextcopy16:
3838
	push cx
3839
	push si
3840
	rep movsb
3841
	pop si
3842
	pop cx
3843
	dec ax
3844
	jnz nextcopy16	;if more to go
3845
partial16:
3846
	mov cx,dx
3847
;	jcxz exit	;rep with cx=0 is a nop
3848
	rep movsb
3849
	jmp exit
3850
onebyte16:
3851
	pop cx
3852
	mov al,byte ptr [line_out]
3853
	stosb		;cx=0 -> 64 kB
3854
	dec cx
3855
	rep stosb
3856
exit:
3857
	push ds
3858
	pop es
3859
	ret
3860
f_cmd endp
3861

3862
;--- breakpoints are stored in line_out, with this format
3863
;--- WORD cnt
3864
;--- array:
3865
;--- DWORD/WORD offset of bp
3866
;--- WORD segment of bp
3867
;--- BYTE old value
3868

3869
resetbps:
3870
	mov di,offset resetbp1
3871
setbps proc
3872
	mov si,offset line_out
3873
	lodsw
3874
	xchg cx, ax		;mov cx,ax
3875
	jcxz setbps_ex
3876
nextbp:
3877
	sizeprfX		;lodsd
3878
	lodsw
3879
	sizeprfX		;xchg edx,eax
3880
	xchg dx,ax		;mov dx,ax
3881
	lodsw
3882
	xchg bx,ax		;mov bx,ax
3883
	call di			;call setbp1/resetbp1
3884
	inc si
3885
	loop nextbp		;next bp
3886
setbps_ex:
3887
	ret
3888
setbp1::
3889
	mov al,0CCh
3890
	call writemem	; write byte at bx:e/dx, C if write was unsuccessful (ROM)
3891
	mov [si],ah		; save the current contents
3892
	jnc @F
3893
	call bp			; either ignore error (g cmd) or abort with msg (p cmd)
3894
@@:
3895
	retn
3896
resetbp1::
3897
	mov al,[si]
3898
	cmp al,0CCh
3899
	jz @F
3900
	call writemem	; write byte at bx:e/dx
3901
@@:
3902
	retn
3903

3904
setbps endp
3905

3906
if ?DPMI
3907

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
3913

3914
resetbpsEx proc
3915

3916
	cmp dx,[regs.msw]
3917
	jz resetbps			; mode didn't change, use normal reset routine
3918
if INT22
3919
	cmp [run_int], INT22MSG	;skip reseting bps if debuggee terminated
3920
	jz @F
3921
endif
3922
	cmp byte ptr [line_out],0	;any breakpoints defined?
3923
	jz @F
3924
	mov cx,[dpmi_size]	; don't call save state if buffer size is zero.
3925
	jcxz do_switch		; this avoids a CWSDPMI bug
3926
	sub sp, cx
3927
	mov al,0			; al=0 is "save state"
3928
	call sr_state
3929
	call do_switch
3930
	mov al,1			; al=1 is "restore state"
3931
	call sr_state
3932
	add sp,[dpmi_size]
3933
@@:
3934
	ret
3935
do_switch:
3936
	call switchmode 	; switch to old mode
3937
	call resetbps
3938
	jmp  switchmode 	; switch back to new mode
3939

3940
switchmode::
3941
;--- raw switch:
3942
;--- si:e/di: new cs:e/ip
3943
;--- dx:e/bx: new ss:e/sp
3944
;--- ax:      new ds
3945
;--- cx:      new es
3946
	sizeprf		;xor ebx,ebx
3947
	xor bx,bx	;clears hiword EBX if cpu >= 386
3948
	mov bx,sp
3949
	sizeprf		;xor edi,edi
3950
	xor di,di	;clears hiword EDI if cpu >= 386
3951
	mov di,back_after_switch
3952
	call ispm_dbg
3953
	jnz is_pm
3954
	mov ax,[dssel]	;switch rm -> pm
3955
	mov si,[cssel]
3956
	mov dx,ax  
3957
	mov cx,ax
3958
	jmp [dpmi_rm2pm]
3959
is_pm:
3960
	mov ax,[wDgroup]	;switch pm -> rm
3961
	mov si,ax
3962
	mov dx,ax
3963
	mov cx,ax
3964
patchrmswitch db 66h		;jmp fword ptr [dpmi_pm2rm]
3965
	jmp dword ptr [dpmi_pm2rm]
3966
back_after_switch:
3967
	xor [regs.msw],-1
3968
	retn
3969

3970
;--- save/restore task state in ES:(E)DI
3971

3972
sr_state::
3973
	sizeprf		;xor edi,edi
3974
	xor di,di	;clears hiword EDI if cpu >= 386
3975
	mov di,sp
3976
	add di,2	;the save space starts at [sp+2]
3977
	call ispm_dbg
3978
	jnz @F
3979
	call [dpmi_rmsav]
3980
	retn
3981
@@:
3982
patchsrstate db 66h		;call fword ptr [dpmi_pmsav]
3983
	call dword ptr [dpmi_pmsav]
3984
	retn
3985

3986
resetbpsEx endp
3987

3988
endif
3989

3990
if FMTEXE
3991
;--- problem is that [pspdbg] is always a segment value
3992
 if ?DPMI
3993
mypsp:
3994
	call ispm_dbg
3995
	jnz @F
3996
	mov ds, [pspdbg]
3997
	ret
3998
@@:
3999
	mov ds, [pspdbgpm]
4000
	ret
4001
@ds_mypsp textequ <call mypsp>
4002
 else
4003
@ds_mypsp textequ <mov ds, [pspdbg]>
4004
 endif
4005
endif
4006

4007
;--- G command - go.
4008

4009
g_cmd proc
4010

4011
	call parseql	;get optional <=addr> argument; always writes [eqladdr+4]
4012

4013
;--- Parse the rest of the line for breakpoints
4014

4015
	mov di,offset line_out 
4016
	xor ax,ax		; init bp cnt to 0
4017
	stosw
4018
if USEHWBP
4019
	mov bp, [wStoreBP]
4020
endif
4021
nextbp:
4022
	dec si
4023
	call skipcomma
4024
	cmp al,CR		;end of line?
4025
	je gg_parsebp_done
4026

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.
4033

4034
	@movs bx,[eqladdr+4]	;default segment ( either CS or segm of '=' )
4035
	call getaddr	;get address into bx:(e)dx
4036
if RING0 and V86M
4037
	test byte ptr [regs.rFL+2],2
4038
	jz @F
4039
	cmp bx, [scratchsel]
4040
	jnz @F
4041
;--- if v86-mode, don't store the scratch selector in the list of BPs
4042
;--- instead, use linear addresses (and the flat selector)
4043
	.386
4044
	movzx ebx, [scratchv86]
4045
	shl ebx, 4
4046
	add edx, ebx
4047
	mov bx, [wFlat]
4048
@@:
4049
endif
4050
	@dprintf "g_cmd: bp=%X:%lX", bx, edx
4051
if USEHWBP
4052
	call bp
4053
else
4054
	call storebpdef
4055
endif
4056
	jmp nextbp		;next bp
4057

4058
if USEHWBP
4059
storebpdef2:
4060
	mov bp, offset storebpdef
4061
endif
4062
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
4066
	sizeprfX		;stosd
4067
	stosw
4068
	xchg ax,bx		;mov ax,bx
4069
	stosw
4070
	inc di			; reserve to store byte at bp location
4071
	inc byte ptr line_out	;use [line_out+0] to count bps
4072
	retn
4073
if USEHWBP
4074
storebpx::
4075
	call sethwbptmp
4076
	jc storebpdef2
4077
	retn
4078
endif
4079

4080
gg_parsebp_done:
4081

4082
;--- Store breakpoint bytes in the given locations.
4083

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"
4091

4092
if ?DPMI
4093
	push [regs.msw]	;save old MSW
4094
endif
4095
	call run		;run the program
4096
if ?DPMI
4097
	pop dx			;get old MSW
4098
endif
4099

4100
ife RING0
4101
 if FMTEXE
4102
	push ds
4103
	@ds_mypsp
4104
 endif
4105
	@dprintf "g_cmd: run returned, [spadjust]=%X, [spsav]=%X:%X", cs:[spadjust], word ptr ds:[PSPS.SPSAV+2], word ptr ds:[PSPS.SPSAV]
4106
 if FMTEXE
4107
	pop ds
4108
 endif
4109
endif
4110

4111
if ?PM
4112
	call getcsattr
4113
	mov [bCSAttr],al	; must be set for getcseipbyte()
4114
endif
4115

4116
if 0
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!
4120

4121
	mov cx,-1
4122
	call getcseipbyte	;get byte at [cs:eip-1], set E/BX to E/IP-1
4123
	push ax
4124
endif
4125

4126
;--- Restore breakpoint bytes.
4127

4128
if ?DPMI
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
4132
else
4133
	call resetbps
4134
endif
4135
	@dprintf "g_cmd: resetbps done"
4136

4137
;--- Finish up.  Check if it was one of _our_ breakpoints.
4138
;--- if yes, decrement (E)IP 
4139

4140
if 0 ; v2.0: not needed for soft/hard bp detection?
4141
	pop ax
4142
	cmp al,0CCh		; was a CC at CS:[EIP-1]?
4143
	jnz gg_exit
4144
endif
4145

4146
if USEHWBP
4147
	cmp bBPhit, 0
4148
	jnz gg_ok
4149
endif
4150

4151
	cmp [run_int], EXC03MSG
4152
	jnz gg_exit
4153
	mov cx,  -1
4154
	call getcseipbyte	; get byte [cs:eip-1], sets E/BX
4155
	cmp al, 0CCh		; still a INT3 at [cs:eip-1] ?
4156
	jz gg_exit
4157

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.
4161
if ?PM
4162
	test [bCSAttr], CS32
4163
	jz $+3
4164
	db 66h	;mov [regs.rIP],ebx
4165
endif
4166
	mov [regs.rIP], bx	; decrement (E)IP
4167
if RING0
4168
	mov [run_int], -1	; v2.0: reset entry ( so SK cmd won't accept soft bps )
4169
endif
4170
gg_ok:
4171
	call dumpregs	; then just display register dump
4172
_ret:
4173
	ret				; and done ( no "unexpected breakpoint" msg )
4174
gg_exit:
4175
	jmp ue_int		;print messages and quit.
4176

4177
g_cmd endp
4178

4179
;--- H command - hex addition and subtraction.
4180

4181
h_cmd proc
4182
	call getdword	;get dword in BX:DX
4183
	push bx
4184
	push dx
4185
	call skipcomm0
4186
	call getdword
4187
	call chkeol		;expect end of line here
4188
	pop cx
4189
	pop ax			;first value in AX:CX, second in BX:DX
4190
if 0
4191
	mov si,ax
4192
	or si,bx
4193
	jnz hh32		;32bit values
4194
	mov ax,cx
4195
	add ax,dx
4196
	push cx
4197
	call hexword
4198
	pop cx
4199
	mov ax,'  '
4200
	stosw
4201
	mov ax,cx
4202
	sub ax,dx
4203
	call hexword
4204
	call putsline
4205
	ret
4206
endif
4207
hh32:
4208
	mov si,ax
4209
	mov bp,cx			;first value in SI:BP now
4210
	mov ax,cx
4211
	add ax,dx
4212
	push ax
4213
	mov ax,si
4214
	adc ax,bx
4215
	jz @F
4216
	call hexword
4217
@@:
4218
	pop ax
4219
	call hexword
4220
	mov ax,'  '
4221
	stosw
4222
	mov ax,bp
4223
	sub ax,dx
4224
	push ax
4225
	mov ax,si
4226
	sbb ax,bx
4227
	jz @F
4228
	or si,bx
4229
	jz @F
4230
	call hexword
4231
@@:
4232
	pop ax
4233
	call hexword
4234
	call putsline
4235
	ret
4236
h_cmd endp
4237

4238
;--- I command - input from I/O port.
4239

4240
i_cmd proc
4241
	mov bl,0
4242
	mov ah,al
4243
	and ah,TOUPPER
4244
	cmp ah,'W'
4245
	je ii_1
4246
	cmp [machine],3
4247
	jb ii_2
4248
	cmp ah,'D'
4249
	jne ii_2
4250
if 1
4251
	mov ah,[si-2]		;distiguish 'id' and 'i d'
4252
	and ah,TOUPPER
4253
	cmp ah,'I'
4254
	jnz ii_2
4255
endif
4256
	inc bx
4257
ii_1:
4258
	inc bx
4259
	call skipwhite
4260
ii_2:
4261
	call getword		;get word into DX
4262
	call chkeol			;expect end of line here
4263
	cmp bl,1
4264
	jz ii_3
4265
	cmp bl,2
4266
	jz ii_4
4267
	in al,dx
4268
	call hexbyte
4269
	jmp ii_5
4270
ii_3:
4271
	in ax,dx
4272
	call hexword
4273
	jmp ii_5
4274
ii_4:
4275
	.386
4276
	in eax,dx
4277
	.8086
4278
	call hexdword
4279
ii_5:
4280
	call putsline
4281
	ret
4282
i_cmd endp
4283

4284
if ?DPMI
4285

4286
LoadSDA:
4287
	call ispm_dbg
4288
	mov si,word ptr [pSDA+0]
4289
	mov ds,[SDASel]
4290
	jnz @F
4291
	mov ds,word ptr cs:[pSDA+2]
4292
@@:
4293
	ret
4294

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
4298
	ret
4299

4300
elseif RING0 and V86M
4301
ispm_dbe:	; return Z if debuggee in v86-mode
4302
	push ax
4303
	mov ax, [regs.rFL+2]
4304
	and al, 2	; VM bit  
4305
	xor al, 2
4306
	pop ax
4307
	ret
4308
endif
4309

4310
if LCMDFILE
4311

4312
setpspdbg:		; set debugger's PSP
4313
 if FMTEXE
4314
	mov bx,[pspdbg]
4315
  if ?DPMI
4316
	call ispm_dbg
4317
	mov ah, 50h
4318
	jz setpsp_rm
4319
	jmp simrealmodeint21
4320
  endif
4321
 else
4322
	mov bx,cs
4323
 endif
4324
setpsp proc		; <--- entry to set debuggee's PSP
4325
	mov ah,50h
4326
 if ?DPMI
4327
	call ispm_dbg
4328
	jz setpsp_rm
4329
  if NOEXTENDER
4330
	.286
4331
	push cx
4332
	push dx
4333
	push bx
4334
	push ax
4335
	mov ax,6
4336
	int 31h
4337
	pop ax
4338
	shl cx,12
4339
	shr dx,4
4340
	or dx,cx
4341
	mov bx,dx
4342
	call simrealmodeint21
4343
	pop bx
4344
	pop dx
4345
	pop cx
4346
	ret
4347
	.8086
4348
  else
4349
	jmp doscall_rm
4350
  endif
4351
setpsp_rm::
4352
 endif
4353

4354
 if USESDA
4355
  if ?DPMI
4356
	cmp word ptr [pSDA+2],0
4357
	jz doscall_rm
4358
  endif
4359
	push ds
4360
	push si
4361
  if ?DPMI
4362
	call LoadSDA
4363
  else
4364
	lds si,[pSDA]
4365
  endif
4366
	mov [si+10h],bx
4367
	pop si
4368
	pop ds
4369
	ret
4370
 else
4371
	jmp doscall_rm
4372
 endif
4373

4374
setpsp endp
4375

4376
endif
4377

4378
ife (BOOTDBG or RING0)
4379

4380
getpsp proc
4381
	mov ah,51h
4382
if ?DPMI
4383
	call ispm_dbg
4384
	jz getpsp_rm
4385
 if NOEXTENDER
4386
	call simrealmodeint21
4387
	mov ax,2
4388
	int 31h
4389
	mov bx,ax
4390
	ret
4391
 else
4392
	jmp doscall_rm
4393
 endif
4394
getpsp_rm:
4395
endif
4396

4397
if USESDA
4398
 if ?DPMI
4399
	cmp word ptr [pSDA+2],0
4400
	jz doscall_rm
4401
 endif
4402
	push ds
4403
	push si
4404
 if ?DPMI
4405
	call LoadSDA
4406
 else
4407
	lds si,[pSDA]
4408
 endif
4409
	mov bx,[si+10h]
4410
	pop si
4411
	pop ds
4412
	ret
4413
else
4414
	jmp doscall_rm
4415
endif
4416
getpsp endp
4417

4418
endif
4419

4420
ife RING0
4421
doscall:
4422
 if NOEXTENDER
4423
	call ispm_dbg
4424
	jz doscall_rm
4425
	.286
4426
simrealmodeint21:
4427
	invoke simrealmodeint, 21h, cs:[wDgroup]
4428
	ret
4429
	.8086
4430
 endif
4431
doscall_rm:
4432
	int 21h
4433
	ret
4434
endif
4435

4436
if ?DPMI
4437

4438
RMCS struc		;the DPMI "real-mode call structure"
4439
rDI		dw ?,?	;+0
4440
rSI		dw ?,?	;+4
4441
rBP		dw ?,?	;+8
4442
		dw ?,?	;+12
4443
rBX 	dw ?,?	;+16
4444
rDX 	dw ?,?	;+20
4445
rCX		dw ?,?	;+24
4446
rAX		dw ?,?	;+28
4447
rFlags	dw ?	;+32
4448
rES 	dw ?	;+34
4449
rDS 	dw ?	;+36
4450
rFS 	dw ?	;+38
4451
rGS 	dw ?	;+40
4452
rIP 	dw ?	;+42
4453
rCS 	dw ?	;+44
4454
rSP 	dw ?	;+46
4455
rSS 	dw ?	;+48
4456
RMCS ends
4457

4458
	.286
4459

4460
;--- call DPMI simulate real-mode interrupt (0x300) function
4461

4462
simrealmodeint proc stdcall uses es intno:word, dataseg:word
4463

4464
local rmcs:RMCS
4465

4466
	push ss
4467
	pop es
4468
	mov rmcs.rDI,di
4469
	mov rmcs.rSI,si
4470
	mov rmcs.rBX,bx
4471
	mov rmcs.rDX,dx
4472
	mov rmcs.rCX,cx
4473
	mov rmcs.rAX,ax
4474
	mov ax,[bp+0]
4475
	mov rmcs.rBP,ax
4476
	xor cx,cx
4477
	mov rmcs.rFlags,cx
4478
	mov rmcs.rSP,cx
4479
	mov rmcs.rSS,cx
4480
	mov ax,dataseg
4481
	mov rmcs.rES,ax
4482
	mov rmcs.rDS,ax
4483
	sizeprf	;lea edi,rmcs
4484
	lea di,rmcs
4485
	mov bx,intno
4486
	mov ax,0300h
4487
	int 31h
4488
	mov ah,byte ptr rmcs.rFlags
4489
	lahf
4490
	mov di,rmcs.rDI
4491
	mov si,rmcs.rSI
4492
	mov bx,rmcs.rBX
4493
	mov dx,rmcs.rDX
4494
	mov cx,rmcs.rCX
4495
	mov ax,rmcs.rAX
4496
	ret
4497
simrealmodeint endp
4498
	.8086
4499
endif
4500

4501
if ?DPMI
4502

4503
;--- this proc is called in pmode only
4504
;--- DS is unknown!
4505
;--- called by L/W cmds.
4506

4507
isextenderavailable proc
4508
	.286
4509
	push ds
4510
	push es
4511
	pusha
4512
	push ss
4513
	pop ds
4514
	sizeprf		;lea esi, szMSDOS
4515
	lea si, szMSDOS	;must be LEA, don't change to "mov si,offset szMSDOS"!
4516
	mov ax,168ah
4517
	int 2Fh
4518
	cmp al,1
4519
	cmc
4520
	popa
4521
	pop es
4522
	pop ds
4523
	ret
4524
	.8086
4525

4526
CONST segment
4527
szMSDOS	db "MS-DOS",0
4528
CONST ends
4529

4530
isextenderavailable endp
4531

4532
nodosextinst:
4533
	push ss
4534
	pop ds
4535
	mov dx,offset nodosext
4536
	jmp int21ah9
4537
endif
4538

4539
if LCMDFILE
4540

4541
isdebuggeeloaded:
4542
	mov ax,[pspdbe]
4543
	cmp ax,[pspdbg]
4544
	ret
4545

4546
;--- ensure a debuggee PSP exists;
4547
;--- set SI:DI to CS:IP, preserve AX, BX, DX
4548

4549
ensuredebuggeeloaded proc
4550
	push ax
4551
	call isdebuggeeloaded
4552
	jnz @F
4553
	push bx
4554
	push dx
4555
	call createdummytask
4556
	mov si,[regs.rCS]
4557
	mov di,[regs.rIP]
4558
	pop dx
4559
	pop bx
4560
@@:
4561
	pop ax
4562
	ret
4563
ensuredebuggeeloaded endp
4564

4565
endif
4566
if BOOTDBG or DPCMD
4567

4568
;--- abs disk read, arguments in [packet]
4569
;--- al = disk
4570
;--- out: C=error
4571
;--- modifies all std regs except sp, bp
4572

4573
	.errnz RING0, <int 13h not yet supported>
4574

4575
readsect proc
4576
	@dprintf "readsect: disk=%X", ax
4577
	mov dl, al
4578
	and al, al
4579
	jns nolba
4580
	mov bx, 055AAh
4581
	mov ah, 41h
4582
	int 13h
4583
	jc nolba
4584
	cmp bx, 0AA55h
4585
	jnz nolba
4586
	test cl, 1
4587
	jz nolba
4588
	xor cx, cx
4589
	mov bx, offset packet
4590
	@dprintf "readsect: lba access, dx=%X, secno=%lX", dx, [bx].PACKET.secno
4591
	push cx
4592
	push cx
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
4598
	mov cl, 16
4599
	push cx
4600
	mov si, sp
4601
	mov ah, 42h
4602
	int 13h
4603
	lea sp, [si+8*2]
4604
	jc disk_err
4605
done:
4606
	ret
4607
nolba:
4608
	push dx
4609
	mov ah, 8
4610
	int 13h
4611
	pop ax
4612
	jc disk_inval
4613
	mov bx, offset packet
4614
	push ax
4615
	call lba2chs
4616
	pop ax
4617
	mov dl, al
4618
	@dprintf "l: chs access, dx=X, cx=%X", dx, cx
4619
	mov ah, 2
4620
	mov al, byte ptr [bx].PACKET.numsecs
4621
	push es
4622
	les bx, dword ptr [bx].PACKET.dstofs
4623
	int 13h
4624
	pop es
4625
	jc disk_err
4626
	ret
4627
disk_err:
4628
	mov dx, offset dskerrb
4629
	jmp @F
4630
disk_inval:
4631
	mov dx, offset dskerr1
4632
@@:
4633
	stc
4634
	ret
4635
lba2chs:
4636
	mov si, cx
4637
	and si, 3Fh
4638
	mov al, dh
4639
	inc al
4640
	mov ah, 0
4641
	mov di, ax
4642
	mov cx, word ptr [bx].PACKET.secno+0
4643
	mov ax, word ptr [bx].PACKET.secno+2
4644
	xor dx, dx
4645
	div si
4646
	xchg ax, cx
4647
	div si
4648
	inc dx
4649
	xchg cx, dx
4650
	div di
4651
	mov dh, dl
4652
	mov ch, al
4653
	ror ah, 1
4654
	ror ah, 1
4655
	or cl, ah
4656
	retn
4657
readsect endp
4658

4659
endif
4660

4661
if BOOTDBG
4662

4663
;--- L command - absolute disk read.
4664

4665
l_cmd proc
4666
	call parselw	;returns AL=drive, BX=packet
4667
	jz cmd_error	;Z means max 1 arg; must be a full command
4668
	call readsect
4669
	jnc @F
4670
	call int21ah9
4671
@@:
4672
	ret
4673
l_cmd endp
4674

4675
elseife RING0
4676

4677
;--- L command - read a program, or disk sectors, from disk.
4678

4679
l_cmd proc
4680
	call parselw	;parse it, addr in bx:(e)dx
4681
 if LCMDFILE
4682
	jz ll1			;Z if max 1 argument (read program)
4683
 else
4684
	jz cmd_error
4685
 endif
4686
 if NOEXTENDER
4687
	call ispm_dbg
4688
	jz @F
4689
	call isextenderavailable
4690
	jc nodosextinst
4691
@@:
4692
 endif
4693
	cmp cs:[usepacket],2
4694
	jb ll0_1
4695
	mov dl,al		;A=0,B=1,C=2,...
4696
	xor si,si		;read drive
4697
 if VDD
4698
	mov ax,[hVdd]
4699
	cmp ax,-1
4700
	jnz callvddread
4701
 endif
4702
	inc dl			;A=1,B=2,C=3,...
4703
	mov ax,7305h	;DS:(E)BX -> packet
4704
	stc
4705
	int 21h			;use int 21h here, not doscall!
4706
	jmp ll0_2
4707
 if VDD
4708
callvddread:
4709
	mov cx,5
4710
	add cl,[dpmi32]	;5/6=far16/far32 ptr
4711
	DispatchCall
4712
	jmp ll0_2
4713
 endif
4714
ll0_1:
4715
	int 25h
4716
ll0_2:
4717
	mov cx,"er"		;CX:DX="read"
4718
	mov dx,"da"
4719
	jmp disp_diskresult
4720

4721
 if LCMDFILE
4722

4723
;--- For .com or .exe files, we can only load at cs:100.  Check that first.
4724

4725
ll1:
4726
	test [fileext], EXT_COM or EXT_EXE
4727
	jz loadfile		;if not .com or .exe file
4728
	cmp bx,[regs.rCS]
4729
	jne l_err		;if segment is wrong
4730
	cmp dx,100h
4731
	je loadfile		;if address is OK (or not given)
4732
l_err:
4733
	jmp cmd_error	;can only load .com or .exe at cs:100
4734

4735
 endif
4736

4737
l_cmd endp
4738

4739
endif
4740

4741
if LCMDFILE
4742

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.
4746

4747
loadfile proc
4748
	mov si,bx		;save destination address, segment
4749
	mov di,dx		;and offset
4750
	mov ax,3d00h	;open file for reading
4751
 if FMTEXE
4752
	push ds
4753
	mov ds, [pspdbg]
4754
 endif
4755
	mov dx,PSPS.DTA	;n cmd has stored file spec at DTA!
4756
	call doscall
4757
 if FMTEXE
4758
	pop ds
4759
 endif
4760
	jnc @F			;if no error
4761
	jmp io_error	;print error message
4762
@@:
4763
	xchg ax,bx		;mov bx,ax
4764
	mov ax,4202h	;lseek EOF
4765
	xor cx,cx
4766
	xor dx,dx
4767
	int 21h
4768

4769
;   Split off file types
4770
;   At this point:
4771
;       bx      file handle
4772
;       dx:ax   file length
4773
;       si:di   load address (CS:100h for .EXE or .COM)
4774

4775
	test [fileext],EXT_COM or EXT_EXE
4776
	jnz loadpgm		;if .com or .exe file
4777

4778
 if ?DPMI
4779
;--- dont load a file in protected mode,
4780
;--- the read loop makes some segment register arithmetic
4781
	call ispm_dbg
4782
	jz @F
4783
	mov dx,offset nopmsupp
4784
	call int21ah9
4785
	jmp cl_exit	; close file and exit
4786
@@:
4787
 endif
4788

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.
4792

4793
	call ensuredebuggeeloaded	;make sure a debuggee PSP exists
4794
	mov es, [pspdbe]
4795

4796
;--- Check the size against available space.
4797

4798
	push si
4799
	push bx
4800

4801
	cmp si,es:[PSPS.ALASAP]
4802
	pushf
4803
	neg si
4804
	popf
4805
	jae ll6				;if loading past end of mem, allow through ffff
4806
	add si,es:[PSPS.ALASAP]	;si = number of paragraphs available
4807
ll6:
4808
	mov cx,4
4809
	xor bx,bx
4810
ll7:
4811
	shl si,1
4812
	rcl bx,1
4813
	loop ll7
4814
	sub si,di
4815
	sbb bx,cx  		;bx:si = number of words left
4816
	jb ll9			;if already we're out of space
4817
	cmp bx,dx
4818
	jne @F
4819
	cmp si,ax
4820
@@:
4821
	jae ll10		;if not out of space
4822
ll9:
4823
	pop bx			;out of space
4824
	pop si
4825
	mov dx,offset doserr8	;not enough memory
4826
	call int21ah9	;print string
4827
	jmp cl_exit
4828

4829
ll10:
4830
	pop bx
4831
	pop si
4832

4833
;--- Store length in registers
4834

4835
;--- seems a bit unwise to modify registers if a debuggee is running 
4836
;--- but MS DEBUG does it as well
4837

4838
 if 0
4839
	mov cx,[regs.rCS]
4840
	cmp cx,[pspdbe]
4841
	jnz noregmodify
4842
	cmp [regs.rIP],100h
4843
	jnz noregmodify
4844
 endif
4845
	mov [regs.rBX],dx
4846
	mov [regs.rCX],ax
4847
noregmodify:    
4848

4849
;--- Rewind the file
4850

4851
	mov ax,4200h	;lseek
4852
	xor cx,cx
4853
	xor dx,dx
4854
	int 21h
4855

4856
	mov dx,0fh
4857
	and dx,di
4858
	mov cl,4
4859
	shr di,cl
4860
	add si,di		;si:dx is the address to read to
4861

4862
;--- Begin loop over chunks to read
4863

4864
ll11:
4865
	mov ah,3fh		;read from file into DS:(E)DX
4866
	mov cx,0fe00h	;read up to this many bytes
4867
	mov ds,si
4868
	int 21h
4869
    
4870
	add si,0fe0h	;wont work in protected-mode!
4871
	cmp ax,cx
4872
	je ll11			;if end of file reached
4873

4874
;--- Close the file and finish up.
4875

4876
cl_exit:
4877
	mov ah,3eh		;close file
4878
	int 21h
4879
	push ss			;restore ds
4880
	pop ds
4881
	ret				;done
4882

4883
loadfile endp
4884

4885
endif
4886

4887
if LCMDFILE
4888

4889
setespefl proc
4890
	sizeprf		;pushfd
4891
	pushf
4892
	sizeprf		;pop dword ptr [regs.rFL]
4893
	pop [regs.rFL]
4894
	sizeprf		;mov dword ptr [regs.rSP],esp
4895
	mov [regs.rSP],sp	;low 16bit of ESP will be overwritten
4896
	ret
4897
setespefl endp
4898

4899

4900
loadpgm proc
4901

4902
;--- file is .EXE or .COM
4903
;--- bx=file handle, dx:ax=file size
4904

4905
	push ax
4906
	mov ah,3eh		;close file
4907
	int 21h
4908
	pop bx			;dx:bx is the file length
4909

4910
 if 1
4911

4912
;--- adjust .exe size by 200h (size of header? who knows )
4913

4914
	test [fileext],EXT_EXE
4915
	jz @F		;if not .exe
4916
	sub bx,200h
4917
	sbb dx,0
4918
@@:
4919
 endif
4920

4921
	@dprintf "loadpgm, dx:bx=%X:%X", dx, bx
4922
	push bx
4923
	push dx
4924

4925
;--- cancel current process (unless there is none)
4926
;--- this will also put cpu back to real-mode!!!
4927

4928
	call isdebuggeeloaded
4929
	jz @F
4930
	call freemem
4931
@@:
4932

4933
	@dprintf "loadpgm, init regs, ds=%X, es=%X", ds, es
4934

4935
;--- Clear registers
4936

4937
	mov di, offset regs
4938
	mov cx, sizeof regs / 2
4939
	xor ax, ax
4940
	rep stosw
4941

4942
	pop word ptr [regs.rBX]
4943
	pop word ptr [regs.rCX]
4944

4945
if FMTEXE
4946
	push ds
4947
	mov ds, [pspdbg]
4948
endif
4949

4950
;--- Fix up interrupt vectors in PSP
4951

4952
if INT2324
4953
	mov si,PSPS.CCIV		;address of original INT 23 and 24 (in PSP)
4954
	mov di,offset run2324
4955
	movsw
4956
	movsw
4957
	movsw
4958
	movsw
4959
endif
4960

4961
;--- Actual program loading.  Use the DOS interrupt.
4962

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
4966
	int 21h
4967
if FMTEXE
4968
	pop ds
4969
endif
4970
	jnc @F
4971
	jmp io_error	;if error
4972
@@:
4973
	call setespefl
4974

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").
4978
	mov ax,sp
4979
if FMTEXE
4980
	mov es, [pspdbg]
4981
	sub ax,word ptr es:[PSPS.SPSAV]
4982
else
4983
	sub ax,word ptr ds:[PSPS.SPSAV]
4984
endif
4985
	cmp ax,80h
4986
	jb @F			;if in range
4987
	mov ax,80h
4988
@@:
4989
	mov [spadjust],ax
4990

4991
;--- use the values for CS:IP SS:SP returned by the loader
4992

4993
	les si,dword ptr [execblk.sssp]
4994
	lodsw es:[si]	;recover ax
4995
	mov [regs.rAX],ax
4996
	mov [regs.rSP],si
4997
	mov [regs.rSS],es
4998
	les si,dword ptr [execblk.csip]
4999
	mov [regs.rIP],si
5000
	mov [regs.rCS],es
5001
	mov [bInit],0
5002
	push ss
5003
	pop es
5004
	clc
5005

5006
;--- get the debuggee's PSP and store it in debuggee's DS,ES
5007

5008
	call getpsp
5009
	xchg ax,bx		;mov ax,bx
5010
	mov [pspdbe],ax
5011
	mov di,offset regs.rDS
5012
	stosw
5013
	stosw			;regs.rES
5014

5015
	call setpspdbg	;switch back to debugger's PSP
5016

5017
;--- Finish up.  Set termination address.
5018

5019
	mov ax,2522h	;set interrupt vector 22
5020
	mov dx,offset intr22
5021
	int 21h
5022
	mov es,[pspdbe]
5023
	mov word ptr es:[PSPS.TPIV+0],dx
5024
	mov word ptr es:[PSPS.TPIV+2],cs
5025

5026
	push ss
5027
	pop es
5028

5029
;--- Set up initial addresses for a/d/u commands.
5030
;--- out: ax=regs.rCS
5031

5032
setup_adu::
5033
	mov di,offset a_addr
5034
	mov si,offset regs.rIP
5035
	mov ax,[regs.rCS]
5036
	push di
5037
	movsw		; write a_addr eip
5038
	movsw
5039
	stosw		; write a_addr cs
5040
	pop si
5041
	mov cx, 2*3
5042
	rep movsw	; copy a_addr to d_addr and u_addr
5043
	ret
5044

5045
loadpgm endp
5046

5047
endif
5048

5049
;--- 'm'achine command:  set machine type.
5050

5051
mach proc
5052
;	dec si
5053
;	call skipwhite
5054
;	cmp al,CR
5055
;	je mach_query		;if just an 'm' (query machine type)
5056
	mov al,[si-1]     
5057
	call getbyte
5058
	mov al,dl
5059
	cmp al,6
5060
	ja errorj3			;dl must be 0-6
5061
	mov [machine],al	;set machine type
5062
	mov [mach_87],al	;coprocessor type, too
5063
	cmp al,3
5064
	jnc @F
5065
	and [rmode],not RM_386REGS	;reset 386 register display
5066
@@:
5067
	ret
5068
mach endp
5069

5070
errorj3:
5071
	jmp cmd_error
5072

5073
;--- 'mc' command:  set coprocessor.
5074
;--- optional arguments:
5075
;--- N: no coprocessor
5076
;--- 2: 80287 with 80386
5077

5078
mc_cmd proc
5079
	call skipwhite	;get next nonblank character
5080
	mov ah,[machine]
5081
	cmp al,CR
5082
	jz set_mpc
5083
	or al,TOLOWER
5084
	push ax
5085
	lodsb
5086
	call chkeol
5087
	pop ax
5088
	cmp al,'n'
5089
	jne @F			;if something else
5090
	mov [has_87],0	;clear coprocessor flag
5091
	ret				;done
5092
@@:
5093
	cmp al,'2'
5094
	jne errorj3		;if not '2'
5095
	cmp [machine],3
5096
	jnz errorj3		;if not a 386
5097
	mov ah,2
5098
set_mpc:
5099
	mov [has_87],1	;set coprocessor flag
5100
	mov [mach_87],ah
5101
	ret
5102
mc_cmd endp
5103

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
5108

5109
m_cmd proc
5110
	cmp al,CR
5111
	jz mach_query
5112
	mov ah,[si-2]
5113
	or ax,TOLOWER or (TOLOWER shl 8)
5114
	cmp ax,'mc'			; mc cmd?
5115
	jz mc_cmd
5116
if ?PM
5117
	cmp al,'0'			; is there a '$' or '%' modifier?
5118
	jb ismove			; ( would throw an error in getdword )
5119
endif
5120
	push si
5121
	call getdword
5122
	cmp al,CR
5123
	jz @F
5124
	call skipwhite
5125
@@:
5126
	pop si
5127
	cmp al,CR
5128
	je mach				; jump if 1 argument only
5129
ismove:
5130
	dec si
5131
	lodsb
5132
	call parsecm		;parse arguments: src=DS:(E)SI, dst=ES:(E)DI, length-1=(E)CX
5133
;--- note: DS unknown here
5134

5135
	push cx
5136
if ?PM
5137
 if ?DPMI
5138
	call ispm_dbg
5139
	jz @F
5140
 endif
5141
;--- TODO: do overlapping check in protected-mode
5142

5143
	@dprintf "m_cmd: ds:esi=%X:%lX, es:edi=%X:%lX, ecx=%lX", ds, esi, es, edi, ecx
5144
	clc
5145
	jmp m3
5146
@@:
5147
endif
5148
	mov cl,4
5149
	shr dx,cl		; BX:DX=dst seg:ofs
5150
	add dx,bx		;upper 16 bits of destination
5151
	mov ax,si
5152
	shr ax,cl
5153
	mov bx,ds
5154
	add ax,bx
5155
	cmp ax,dx
5156
	jne m3		;if we know which is larger
5157
	mov ax,si
5158
	and al,0fh
5159
	mov bx,di
5160
	and bl,0fh
5161
	cmp al,bl
5162
m3:
5163
	pop cx
5164
	lahf
5165
if INT2324
5166
	push ds
5167
	push ss		;ds = dgroup
5168
	pop ds
5169
	call dohack	;set debuggee's int 23/24
5170
	pop ds
5171
endif
5172
if ?PM
5173
;--- v2.0: ensure ES is writeable ( parsecm does that no longer )
5174
	mov bx, es
5175
	push ds
5176
	@RestoreSeg ds
5177
 if ?DPMI
5178
	push ds
5179
	pop es
5180
 endif
5181
	call IsWriteableBX	; expects DS(,ES)=dgroup
5182
	call IsOfs32
5183
	pop ds
5184
	mov es, bx
5185
	jz m3_1
5186
	.386
5187
	sahf
5188
	jae @F
5189
	add esi,ecx
5190
	add edi,ecx
5191
	std
5192
@@:
5193
	rep movsb es:[edi], ds:[esi]
5194
	movsb es:[edi], ds:[esi]
5195
	cld
5196
	jmp ee0a
5197
	.8086
5198
m3_1:
5199
endif
5200
	sahf
5201
	jae @F			;if forward copy is OK
5202
	add si,cx
5203
	add di,cx
5204
	std
5205
@@:
5206
	rep movsb		;do the move
5207
	movsb			;one more byte
5208
	cld				;restore flag
5209
	jmp ee0a		;restore ds and es and undo the int2324 pointer hack
5210
m_cmd endp
5211

5212
;--- M without argument - display machine type.
5213

5214
mach_query proc
5215
	mov si,offset msg8088
5216
	mov al,[machine]
5217
	cmp al,0
5218
	je @F		;if 8088
5219
	mov si,offset msgx86
5220
	add al,'0'
5221
	mov [si],al
5222
@@:
5223
	call copystring    ;si->di
5224
	mov si,offset no_copr
5225
	cmp [has_87],0
5226
	je @F		;if no coprocessor
5227
	mov si,offset has_copr
5228
	mov al,[mach_87]
5229
	cmp al,[machine]
5230
	je @F		;if has coprocessor same as processor
5231
	mov si,offset has_287
5232
@@:
5233
	call copystring	;si->di
5234
	jmp putsline	;call puts and quit
5235
mach_query endp
5236

5237
if LCMDFILE or WCMDFILE
5238

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.
5242

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.
5246

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.
5249

5250
CONST segment
5251
exts label byte
5252
	db ".HEX",EXT_HEX
5253
	db ".EXE",EXT_EXE
5254
	db ".COM",EXT_COM
5255
extsend label near
5256
CONST ends
5257

5258
n_cmd proc
5259
	mov di,PSPS.DTA		;destination address
5260
if FMTEXE
5261
	mov es, [pspdbg]
5262
endif
5263

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
5268

5269
	mov cx, sizeof PSPS.DTA - 1
5270
nextc:
5271
	cmp al,CR
5272
	je nn3		;if end of line
5273
	call ifsep	;check for separators space, TAB, comma, ;, =
5274
	je nn3		;if end of file name
5275
	cmp al,[swch1]
5276
	je nn3		;if '/' (and '/' is the switch character)
5277
	cmp al,'a'
5278
	jb @F		;if not lower case
5279
	cmp al,'z'
5280
	ja @F		;ditto
5281
	and al,TOUPPER	;convert to upper case
5282
@@:
5283
	stosb
5284
	lodsb
5285
	loop nextc	;back for more
5286

5287
nn3:
5288
	mov al,0		;null terminate the file name string
5289
	stosb
5290
	mov word ptr [execblk.cmdtail],di	;save start of command tail
5291

5292
;--- file name stored as asciiz at psp:80h;
5293
;--- now set [fileext];
5294
;--- AL=0
5295

5296
	push cx
5297
	push di
5298
	push si
5299
	cmp di,PSPS.DTA+1
5300
	je nn3d			;if no file name at all
5301
	cmp di,PSPS.DTA+5
5302
	jb nn3c			;if no extension (name too short)
5303
	lea dx,[di-5]
5304
	mov bx,offset exts	;check for .EXE, .COM and .HEX
5305
@@:
5306
	mov si,bx
5307
	mov di,dx
5308
	add bx,5
5309
	mov cx,4
5310
	repz cmpsb
5311
	mov al,[si]
5312
	jz nn3d
5313
	cmp bx, extsend
5314
	jb @B
5315
nn3c:
5316
	mov al,EXT_OTHER
5317
nn3d:
5318
	mov [fileext],al
5319
	pop si
5320

5321
;--- Finish the N command
5322
;--- 1. copy what's left behind the file spec to line_out
5323

5324
if FMTEXE
5325
	push es
5326
	push ds
5327
	pop es
5328
endif
5329

5330
	mov di,offset line_out
5331
	push di
5332
	dec si
5333
@@:
5334
	lodsb			;copy the remainder to line_out
5335
	stosb
5336
	cmp al,CR
5337
	jne @B
5338
	pop si
5339

5340
if FMTEXE
5341
	pop es
5342
endif
5343

5344
;--- Set up FCBs. src is line_out
5345

5346
	mov di,PSPS.FCB1
5347
	call DoFCB		;first FCB: parse name DS:SI into FCB es:di
5348
	mov byte ptr [regs.rAX+0],al
5349
	mov di,PSPS.FCB2
5350
	call DoFCB		;second FCB
5351
	mov byte ptr[regs.rAX+1],al
5352

5353
;--- Copy command tail from line_out to
5354
;--- PSP, just behind zero-terminated file spec.
5355

5356
	mov si,offset line_out
5357
	pop di
5358
	pop cx
5359
	jcxz notail	; if no more space left behind file spec
5360
	push di
5361
	inc di		; skip byte used for byte cnt
5362
@@:
5363
	lodsb
5364
	stosb
5365
	cmp al,CR
5366
	loopne @B	;if not end of string
5367
	pop ax		;recover old DI
5368
	dec di
5369
	dec di
5370
	xchg ax,di
5371
	sub ax,di	;compute length of tail
5372
	stosb
5373
notail:
5374
	ret
5375
n_cmd endp
5376

5377
;--- Subroutine to process an FCB.
5378
;--- di->FCB
5379
;--- si->file name
5380

5381
DoFCB proc
5382
@@:
5383
	lodsb
5384
	cmp al,CR
5385
	je nn7		;if end
5386
	call ifsep
5387
	je @B		;if separator
5388
	cmp al,[swchar]
5389
	je nn10		;if switch character
5390
nn7:
5391
	dec si
5392
	mov ax,2901h;parse filename into FCB
5393
	call doscall
5394
	push ax		;save AL
5395
@@:
5396
	lodsb		;skip till separator
5397
	cmp al,CR
5398
	je @F		;if end
5399
	call ifsep
5400
	je @F		;if separator character
5401
	cmp al,[swch1]
5402
	jne @B		;if not swchar (sort of)
5403
@@:
5404
	dec si
5405
	pop ax		;recover AL
5406
	cmp al,1
5407
	jne @F		;if not 1
5408
	dec ax
5409
@@:
5410
	ret
5411

5412
;--- Handle a switch (differently).
5413

5414
nn10:
5415
	lodsb
5416
	cmp al,CR
5417
	je nn7		;if end of string
5418
	call ifsep
5419
	je nn10		;if another separator
5420
	mov al,0
5421
	stosb
5422
	dec si
5423
	lodsb
5424
	cmp al,'a'
5425
	jb @F		;if not a lower case letter
5426
	cmp al,'z'
5427
	ja @F
5428
	and al,TOUPPER	;convert to upper case
5429
@@:
5430
	stosb
5431
	mov ax,'  '
5432
	stosw
5433
	stosw
5434
	stosw
5435
	stosw
5436
	stosw
5437
	xor ax,ax
5438
	stosw
5439
	stosw
5440
	stosw
5441
	stosw
5442
	ret			;return with AL=0
5443
DoFCB endp
5444

5445
endif
5446

5447
;--- O command - output to I/O port.
5448

5449
o_cmd proc
5450
	mov bl,0
5451
	mov ah,al
5452
	and ah,TOUPPER
5453
	cmp ah,'W'
5454
	je oo_1
5455
	cmp [machine],3
5456
	jb oo_2
5457
	cmp ah,'D'
5458
	jne oo_2
5459
if 1
5460
	mov ah,[si-2]		;distiguish 'od' and 'o d'
5461
	and ah,TOUPPER
5462
	cmp ah,'O'
5463
	jnz oo_2
5464
endif
5465
	inc bx
5466
oo_1:
5467
	inc bx
5468
	call skipwhite
5469
oo_2:
5470
	call getword
5471
	push dx
5472
	call skipcomm0
5473
	cmp bl,1
5474
	jz oo_4
5475
	cmp bl,2
5476
	jz oo_5
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
5481
	out dx,al
5482
	ret
5483
oo_4:
5484
	call getword	;dx=word
5485
	call chkeol		;expect end of line here
5486
	xchg ax,dx		;ax = word
5487
	pop dx
5488
	out dx,ax
5489
	ret
5490
oo_5:
5491
	.386
5492
	call getdword	;bx:dx=dword
5493
	call chkeol		;expect end of line here
5494
	push bx
5495
	push dx
5496
	pop eax
5497
	pop dx
5498
	out dx,eax
5499
	ret
5500
	.8086
5501
o_cmd endp
5502

5503
if ?PM
5504

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
5509
;--- called by:
5510
;---   setcseipbyte(); write at regs.cs:e/ip + cx
5511
;---   writemem(): write byte at bx:e/dx 
5512
;---   e, f, m cmds
5513
;---   parselw()
5514

5515
IsWriteableBX proc
5516
 if ?DPMI
5517
	call ispm_dbg
5518
	jz is_rm
5519
	.286
5520
	push ax
5521
	sizeprf				; push edi
5522
	push di
5523
	sub sp, 8
5524
	mov di, sp
5525
	sizeprf				; lea edi,[di] (synonym for movzx edi,di), 3 bytes long
5526
	lea di,[di]
5527
	mov ax,000Bh		;get descriptor
5528
	int 31h
5529
	jc @F
5530
	test byte ptr [di+5],8	;code segment?
5531
	jz @F
5532
	and byte ptr [di+5],0F3h;reset CODE+conforming attr
5533
	or byte ptr [di+5],2	;set writable
5534
	mov bx, [scratchsel]
5535
	mov ax, 000Ch
5536
	int 31h
5537
@@:
5538
	lea sp, [di+8]
5539
	sizeprf				; pop edi
5540
	pop di
5541
	pop ax
5542
	.8086
5543
is_rm:
5544
 elseif RING0
5545
	.386
5546
	verw bx
5547
	jz isok
5548
	pushad
5549
	call getlinearbaseDT
5550
	jc error
5551
	cmp bx, dx
5552
	ja error
5553
	mov esi, eax
5554
  if FLATSS
5555
	sub esp, 6
5556
	sgdt [esp]
5557
  else
5558
	mov bp, sp
5559
	sub sp, 6
5560
	sgdt [bp-6]
5561
  endif
5562
	pop di
5563
	pop edi
5564
	and bl, 0F8h
5565
	movzx ebx, bx
5566
	lea esi, [esi+ebx]
5567
	movzx eax, [scratchsel]
5568
	add edi, eax
5569
	@dprintf "IsWriteableBX: esi=%lX, edi=%lX", esi, edi
5570
	push ds
5571
	mov ds, [wFlat]
5572
	lodsd ds:[esi]
5573
	mov ds:[edi+0], eax
5574
	lodsd ds:[esi]
5575
	and ah, 0F7h	; data
5576
	or ah, 2		; writable
5577
	mov ds:[edi+4], eax
5578
	pop ds
5579
	popad
5580
	mov bx, [scratchsel]
5581
isok:
5582
 else
5583
    clc
5584
 endif
5585
	ret
5586

5587
 if RING0
5588
error:
5589
	popad
5590
	stc
5591
	ret
5592
 endif
5593

5594
IsWriteableBX endp
5595

5596
 if RING0
5597

5598
;--- in: DX=real-mode segment
5599
;--- out: BX=scratch sel, base modified to match the segment in DX
5600

5601
setscratchsel proc
5602
  if V86M
5603
	mov [scratchv86], dx
5604
  endif
5605
	pushad
5606
  if FLATSS
5607
	mov ebp, esp
5608
	sub esp, 6
5609
	sgdt [esp]
5610
  else
5611
	mov bp, sp
5612
	sub sp, 6
5613
	sgdt [bp-6]
5614
  endif
5615
	pop ax
5616
	pop eax
5617
	movzx ebx, [scratchsel]
5618
	add ebx, eax
5619
  if FLATSS
5620
	movzx eax, word ptr [ebp+5*4]	;get DX
5621
  else
5622
	movzx eax, word ptr [bp+5*4]	;get DX
5623
  endif
5624
	shl eax, 4
5625
	push ds
5626
	mov ds, [wFlat]
5627
	mov word ptr [ebx+0], -1
5628
	mov word ptr [ebx+2], ax
5629
	shr eax, 16
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
5633
	pop ds
5634
	popad
5635
	mov bx, [scratchsel]
5636
	ret
5637
setscratchsel endp
5638
 endif
5639

5640
 if ?DPMI
5641
setrmsegm:
5642
	.286
5643
	mov bx,cs:[scratchsel]
5644
setrmaddr:		;<--- set selector in BX to segment address in DX
5645
	mov cx,dx
5646
	shl dx,4
5647
	shr cx,12
5648
	mov ax,7
5649
	int 31h
5650
	ret
5651
	.8086
5652
 endif
5653

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
5658

5659
getcsattr proc
5660
	@movs bx,[regs.rCS]
5661
getseldefsize::	;<--- any selector in BX
5662
 if ?DPMI
5663
	mov al,00
5664
	cmp [machine],3
5665
	jb @F
5666
	call ispm_dbe
5667
	jz @F
5668
 endif
5669
	.386
5670
	lar eax,ebx
5671
	shr eax,16
5672
	.8086
5673
@@:
5674
	test al,40h
5675
	ret
5676
getcsattr endp
5677

5678
;--- in: segment/selector in BX
5679
;--- out: ZF=1 if in real-mode or segment limit is <= 64 kB
5680

5681
getseglimit proc
5682
	push ax
5683
 if ?DPMI
5684
	xor ax,ax
5685
	cmp [machine],3
5686
	jb is16
5687
	call ispm_dbg
5688
	jz is16
5689
 endif
5690
	.386
5691
	lar eax,ebx		; v2.0: first check if expand down
5692
	and ah,0Ch
5693
	cmp ah,4
5694
	jnz @F
5695
	bt eax, 22		; if yes, is default bit set?
5696
	jc is32ed
5697
@@:
5698
	lsl eax,ebx
5699
	shr eax,16
5700
	.8086
5701
is32ed:
5702
is16:
5703
	and ax,ax
5704
	pop ax
5705
	ret
5706
getseglimit endp
5707

5708
endif ; ?PM
5709

5710
;--- read [EIP+x] value 
5711
;--- in:  CX=x 
5712
;---      [regs.rCS]=CS
5713
;---      [regh_(e)ip]=EIP
5714
;--- out: AL=[CS:(E)IP]
5715
;---      [E]BX=[E]IP+x 
5716
;--- called by T and G
5717

5718
getcseipbyte proc
5719
	push es
5720
	@movs es, [regs.rCS]
5721
	sizeprfX		;mov ebx,[regs.rIP]
5722
	mov bx,[regs.rIP]
5723
if ?PM
5724
	test [bCSAttr], CS32
5725
	jz @F
5726
	.386
5727
	movsx ecx,cx
5728
	add ebx,ecx
5729
	mov al,es:[ebx]
5730
	pop es
5731
	ret
5732
	.8086
5733
@@:
5734
endif
5735
	add bx,cx
5736
	mov al,es:[bx]
5737
	pop es
5738
	ret
5739
getcseipbyte endp
5740

5741
;--- set [EIP+x] value 
5742
;--- in: CX=x 
5743
;--- AL=byte to write
5744
;--- [regs.rCS]=CS
5745
;--- [regs.rIP]=EIP
5746
;--- modifies [E]BX
5747

5748
setcseipbyte proc
5749
	push es
5750
	@movs bx,[regs.rCS]
5751
if ?PM
5752
	call IsWriteableBX	; checks descriptor only, can't detect r/o pages
5753
	jc scib_1
5754
endif
5755
	mov es, bx
5756
	sizeprfX
5757
	mov bx, [regs.rIP]
5758
if ?PM
5759
	test [bCSAttr], CS32
5760
	jz is_ip16
5761
	.386
5762
	movsx ecx,cx
5763
	mov es:[ebx+ecx],al
5764
scib_1:
5765
	pop es
5766
	ret
5767
	.8086
5768
is_ip16:
5769
endif
5770
	add bx,cx
5771
	mov es:[bx],al
5772
	pop es
5773
	ret
5774
setcseipbyte endp
5775

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)
5780

5781
writemem proc
5782
if ?PM
5783
 if ?DPMI
5784
	call ispm_dbg
5785
	jz weip16
5786
 endif
5787
	call IsWriteableBX		;ensure that bx has a writeable selector
5788
;	jc err					;v2.0: don't exit silently, better to cause a GPF
5789
	call getseglimit
5790
	jz weip16
5791
	@dprintf "writemem: bx:edx=%X:%lX", bx, edx
5792
	.386
5793
	push ds
5794
	mov ds, bx
5795
	mov ah, [edx]
5796
	mov [edx], al
5797
	cmp al, [edx]
5798
	jmp done
5799
	.8086
5800
weip16:
5801
endif
5802
	@dprintf "writemem: bx:dx=%X:%X", bx, dx
5803
	push ds
5804
	mov ds,bx
5805
	push bx
5806
	mov bx,dx
5807
	mov ah,[bx]
5808
	mov [bx],al
5809
	cmp al,[bx]
5810
	pop bx
5811
done:
5812
	pop ds
5813
	jnz err
5814
	ret
5815
err:
5816
	stc
5817
	ret
5818
writemem endp
5819

5820
;--- read byte from memory
5821
;--- in:  BX:(E)DX=address
5822
;--- out: AL=byte
5823
;--- used by e_cmd prompt mode
5824
;--- BX may be modified
5825

5826
readmem proc
5827
if ?PM
5828
	call getseglimit	;attribute of selector in BX, Z if limit is <= 0ffffh
5829
endif
5830
	push ds
5831
	mov ds,bx
5832
if ?PM
5833
	jz @F
5834
	.386
5835
	mov al,[edx]
5836
	.8086
5837
	pop ds
5838
	ret
5839
@@:
5840
endif
5841
	mov bx, dx
5842
	mov al,[bx]
5843
	pop ds
5844
	ret
5845
readmem endp
5846

5847
;--- P command - proceed (i.e., skip over call/int/loop/string instruction).
5848

5849
p_cmd proc
5850
	call parse_pt	;process arguments
5851

5852
;--- Do it <CX=count> times.  First check the type of instruction.
5853

5854
instrloop:			; <--- next instruction
5855
	push cx			; save cx
5856
	mov dx,15		; DL = number of bytes to go; DH = prefix flags.
5857
if ?PM
5858
	call getcsattr
5859
	mov [bCSAttr],al
5860
	jz @F
5861
	mov dh,PP_ADRSIZ + PP_OPSIZ
5862
@@:
5863
endif
5864
	sizeprfX		; mov esi,[regs.rIP]
5865
	mov si,[regs.rIP]
5866
nextprf:			; <- get next prefix byte
5867
	call getnextb	; AL=[cs:(e)ip], eip++
5868
	mov di,offset ppbytes
5869
	mov cx,PPLEN
5870
	repne scasb
5871
	jne pp5			; if not one of these
5872

5873
	mov al,[di+PPLEN-1]	; get corresponding byte in ppinfo
5874
	test al,PP_PREFIX
5875
	jz @F			; if not a prefix
5876
	xor dh,al		; update the flags
5877
	dec dl
5878
	jnz nextprf		; if not out of bytes
5879
	jmp dotrace		; more than 15 prefixes will cause a GPF
5880
@@:
5881
	test al,40h
5882
	jz @F			; if no size dependency
5883
	and al,3fh
5884
	and dh,PP_OPSIZ	; for CALL, operand size 2->4, 4->6
5885
	add al,dh
5886
@@:
5887
	cbw
5888
	call addeip	; add ax to instruction pointer in (E)SI
5889
	jmp proceed0; we have a skippable instruction here
5890

5891
pp5:
5892
	cmp al,0ffh	; indirect call?
5893
if 0
5894
	jz @F
5895
	jmp dotrace	; just an ordinary instruction
5896
@@:
5897
else
5898
	jnz dotrace
5899
endif
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
5903
	test al,38h
5904
if 0
5905
	jz @F
5906
	jmp dotrace	; if not ff/2 or ff/3
5907
@@:
5908
else
5909
	jnz dotrace	; if not ff/2 or ff/3
5910
endif
5911
	cmp al,0c0h
5912
	jae proceed0; if just a register
5913
	test dh,PP_ADRSIZ
5914
	jnz pp6		; if 32 bit addressing
5915
	cmp al,6
5916
	je proceed2	; if just plain disp16
5917
	cmp al,40h
5918
	jb proceed0	; if indirect register
5919
	cmp al,80h
5920
	jb proceed1	; if disp8[reg(s)]
5921
	jmp proceed2; it's disp16[reg(s)]
5922
back2top:
5923
	jmp instrloop; back for more
5924

5925
pp6:
5926
	cmp al,5
5927
	je proceed4	; if just plain disp32
5928
	xor al,4
5929
	test al,7
5930
	jnz @F		; if no SIB byte
5931
	call inceip
5932
@@:
5933
	cmp al,40h
5934
	jb proceed0	; if indirect register
5935
	cmp al,80h
5936
	jb proceed1	; if disp8[reg(s)]
5937
				; otherwise, it's disp32[reg(s)]
5938
proceed4:
5939
	call inceip
5940
	call inceip
5941
proceed2:
5942
	call inceip
5943
proceed1:
5944
	call inceip
5945
proceed0:
5946
	call doproceed2
5947
	jmp pp13
5948

5949
;--- Ordinary instruction.  Just do a trace.
5950

5951
dotrace:
5952
	or byte ptr [regs.rFL+1],1	;set single-step mode
5953
	call run
5954
	cmp [run_int], EXC01MSG
5955
	jne pp15		; stop if some other interrupt
5956
	call dumpregs
5957
pp13:				;<--- Common part to finish up.
5958
	pop cx
5959
	loop back2top	;back for more
5960
	ret
5961
pp15:
5962
	jmp ue_int		;print message about unexpected interrupt and quit
5963

5964
inceip::
5965
if ?PM
5966
	test [bCSAttr], CS32
5967
	jz $+3
5968
	db 66h		;inc esi
5969
endif
5970
	inc si
5971
	retn
5972

5973
addeip:
5974
if ?PM
5975
	test [bCSAttr], CS32
5976
	jz @F
5977
	.386
5978
	movzx eax,ax
5979
	.8086
5980
	db 66h		;add esi,eax
5981
@@:
5982
endif
5983
	add si,ax
5984
	retn
5985

5986
;--- getnextb - Get next byte in instruction stream.
5987
;--- [e]si = eip
5988

5989
getnextb:
5990
	push ds
5991
	@movs ds,[regs.rCS]
5992
if ?PM
5993
	test cs:[bCSAttr], CS32
5994
	jz $+3
5995
	db 67h		;lodsb [esi]
5996
endif
5997
	lodsb
5998
	pop ds
5999
	retn
6000

6001
doproceed2:
6002
	@movs bx, [regs.rCS]
6003

6004
;--- Special instruction.  Set a breakpoint and run until we hit it.
6005
;--- BX:(E)SI == address where a breakpoint is to be set.
6006

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
6010
if USEHWBP
6011
	xor ax, ax
6012
	stosw
6013
	sizeprfX	; mov edx, esi
6014
	mov dx, si
6015
	call [wStoreBP]	; optionally use 386 debug register for auto breakpoints?
6016
else
6017
	mov ax, 1	;bp cnt
6018
	stosw
6019
	sizeprfX	;xchg eax,esi
6020
	xchg ax,si
6021
	sizeprfX	;stosd
6022
	stosw
6023
	xchg ax, bx
6024
	stosw
6025
endif
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
6028
	retn
6029
bp_writeerr::
6030
	mov dx, offset cantwritebp
6031
	call int21ah9
6032
	jmp cmdloop
6033

6034
p_cmd endp
6035

6036
if ?DPMI
6037
exitdpmi proc
6038

6039
	push ax
6040
if LPMINTS
6041
	mov bp, [wOfsSize]
6042
	mov si, offset pmvectors
6043
	mov di, offset pmints
6044
	mov cx, LPMINTS
6045
nextpmint:
6046
	push cx
6047
	mov bl, [di]
6048
	sizeprf	; mov edx, [si]
6049
	mov dx, [si]
6050
	mov cx, ds:[si+bp]
6051
	mov ax, 205h
6052
	int 31h
6053
	add di, 3
6054
	add si, sizeof fword
6055
	pop cx
6056
	loop nextpmint
6057
endif
6058
	pop ax
6059
	ret
6060
exitdpmi endp
6061
endif
6062

6063
if QCMD
6064

6065
;--- Q command - quit.
6066

6067
q_cmd proc
6068

6069
 if RING0
6070

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.
6078

6079
	@movs bx, [regs.rCS]
6080
	.386
6081
	lar ax, bx
6082
	and ah, 60h
6083
	jz @F		; can't exit in ring 0
6084
	call IsWriteableBX
6085
	mov edx, dword ptr [regs.rIP]
6086
	push ds
6087
	mov ds, bx
6088
	mov dword ptr [edx], 21CD4CB4h	; mov ah,4ch , int 21h
6089
	pop ds
6090
	call run
6091
	ret
6092
@@:
6093
	mov dx, offset plerr
6094
	jmp int21ah9
6095
	.8086
6096
 else
6097

6098
  if ?DPMI
6099
	mov byte ptr [dpmidisable+1],0	;disble DPMI hook
6100
	inc [bNoHook2F]					;avoid a new hook while terminating
6101
  endif
6102

6103
;--- cancel child's process if any
6104
;--- this will drop to real-mode if debuggee is in pmode
6105
  if ?DPMI
6106
;--- v1.29: debugx: if debuggee is in pm, 'q' will try to terminate it - else it really quits
6107
	call ispm_dbe
6108
	jz realquit
6109
	and al,TOUPPER
6110
	cmp al,'Q'		;"qq" entered?
6111
	jnz @F
6112
	call exitdpmi
6113
@@:
6114
	call freemem
6115
	jmp ue_int
6116
realquit:
6117
  endif
6118
	call freemem
6119

6120
  if VDD
6121
	mov ax,[hVdd]
6122
	cmp ax,-1
6123
	jz @F
6124
	UnRegisterModule
6125
@@:
6126
  endif
6127

6128
  if VXCHG
6129
   ifndef VXCHGFLIP
6130
	mov dx,[xmsmove.dsthdl]
6131
	and dx, dx
6132
	jz @F
6133
	push dx
6134
   endif
6135
	mov al,0             ; restore debuggee screen
6136
	call swapscreen
6137
   ifndef VXCHGFLIP
6138
	pop dx
6139
	mov ah,0Ah           ; and free XMS handle
6140
	call [xmsdrv]
6141
@@:
6142
   endif
6143
  endif
6144
  if ALTVID
6145
	call setscreen
6146
  endif
6147

6148
;--- Restore interrupt vectors.
6149

6150
	mov di,offset intsave
6151
	mov si,offset inttab
6152
  if ?DPMI
6153
	mov cx,NUMINTS+1
6154
  else
6155
	mov cx,NUMINTS
6156
  endif
6157
nextint:
6158
	lodsb
6159
	push ds
6160
;	add si,2	; skip rest of INTITEM (now done below)
6161
	lds dx, [di]
6162
	add di,4
6163
	cmp al,22h
6164
	jz norestore
6165
	mov bx, ds
6166
	and bx, bx
6167
	jz norestore
6168
	mov ah,25h
6169
	int 21h
6170
norestore:
6171
	pop ds
6172
	lodsw		; skip rest of INTITEM (16-bit offset)
6173
	loop nextint
6174

6175
  if INT22
6176
;--- Restore termination address.
6177
   if FMTEXE
6178
	mov es, [pspdbg]
6179
   endif
6180
	mov si,offset psp22	;restore termination address
6181
	mov di,PSPS.TPIV
6182
	movsw
6183
	movsw
6184
	mov di,PSPS.PARENT	;restore PSP of parent
6185
	movsw
6186
  endif
6187

6188
;--- Really done.
6189

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
6193
;--- into AL.
6194

6195
  if FMTEXE
6196
	mov ax, 4C00h
6197
	int 21h
6198
  else
6199
	int 20h
6200
  endif
6201
	jmp cmdloop		;returned? then something is terribly wrong.
6202

6203
 endif
6204

6205
q_cmd endp
6206

6207
endif
6208

6209
if MMXSUPP
6210
rm_cmd proc
6211
	cmp [has_mmx],1
6212
	jnz @F
6213
	jmp dumpregsMMX
6214
@@:
6215
	ret
6216
rm_cmd endp
6217
endif
6218

6219
;--- RX command: toggle mode of R command (16 - 32 bit registers)
6220

6221
rx_cmd proc
6222
	call skipwhite
6223
	cmp al,CR
6224
	je @F
6225
	jmp rr_err
6226
@@:
6227
	cmp [machine],3
6228
	jb rx_exit
6229
;	mov di,offset line_out
6230
	mov si,offset regs386
6231
	call copystring	;si->di
6232
	xor [rmode],RM_386REGS
6233
	mov ax," n"	;"on"
6234
	jnz @F
6235
	mov ax,"ff"	;"off"
6236
@@:
6237
	stosw
6238
;	mov al,0	; v2.0: removed
6239
;	stosb
6240
	call putsline
6241
rx_exit:
6242
	ret
6243
rx_cmd endp
6244

6245
;--- RN command: display FPU status
6246

6247
rn_cmd proc
6248
	call skipwhite
6249
	cmp al,CR
6250
	je @F
6251
	jmp rr_err
6252
@@:
6253
	cmp [has_87],0
6254
	jz @F
6255
	call dumpregsFPU
6256
@@:
6257
	ret
6258
rn_cmd endp
6259

6260
;--- R command - manipulate registers.
6261

6262
r_cmd proc
6263
	cmp al,CR
6264
	jne @F		;if there's an argument
6265
	jmp dumpregs
6266
@@:
6267
	cmp ah,'r'
6268
	jnz @F
6269
	and al,TOUPPER
6270
	cmp al,'X'
6271
	je rx_cmd
6272
if MMXSUPP
6273
	cmp al,'M'
6274
	je rm_cmd
6275
endif
6276
	cmp al,'N'
6277
	je rn_cmd
6278
@@:
6279

6280
;--- an additional register parameter was given
6281

6282
	dec si
6283
	lodsw
6284
	and ax,TOUPPER_W
6285
	mov di,offset regnames
6286
	mov cx,NUMREGNAMES
6287
	repne scasw
6288
	mov bx,di
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"
6292
	ja rr2
6293
	stosw			;print register name
6294
	mov al,' '
6295
	stosb
6296
	mov bx,[bx+NUMREGNAMES*2-2]
6297
	call skipcomma	;skip white spaces
6298
	cmp al,CR
6299
	jne rr1a		;if not end of line
6300
	push bx			;save bx for later
6301
	mov ax,[bx]
6302
	call hexword
6303
	call getline0	;prompt for new value
6304
	pop bx
6305
	cmp al,CR
6306
	je rr1b			;if no change required
6307
rr1a:
6308
	call getword
6309
	call chkeol		;expect end of line here
6310
	mov [bx],dx		;save new value
6311
rr1b:
6312
	ret
6313

6314
;--- is it the F(lags) register?
6315

6316
rr2:
6317
	cmp al,'F'
6318
	jne rr6			;if not 'f'
6319
	dec si
6320
	lodsb
6321
	cmp al,CR
6322
	je rr2b			;if end of line
6323
	cmp al,' '
6324
	je rr2a			;if white space
6325
	cmp al,TAB
6326
	je rr2a			;ditto
6327
	cmp al,','
6328
	je rr2a
6329
	jmp errorj9		;if not, then it's an error
6330
rr2a:
6331
	call skipcomm0
6332
	cmp al,CR
6333
	jne rr3			;if not end of line
6334
rr2b:
6335
	call dmpflags
6336
	call getline0	;get input line (using line_out as prompt)
6337
rr3:
6338
	cmp al,CR
6339
	je rr1b			;return if done
6340
	dec si
6341
	lodsw
6342
	and ax,TOUPPER_W;here's the mnemonic
6343
	mov di,offset flgnams
6344
	mov cx,16
6345
	repne scasw
6346
	jne rr6			;if no match
6347
	cmp di,offset flgnons
6348
	ja rr4			;if we're clearing
6349
	mov ax,[di-16-2]
6350
	not ax
6351
	and [regs.rFL],ax
6352
	jmp rr5
6353

6354
rr4:
6355
	mov ax,[di-32-2]
6356
	or [regs.rFL],ax
6357

6358
rr5:
6359
	call skipcomma
6360
	jmp rr3			;check if more
6361

6362
;--- it is neither 16bit register nor the F(lags) register.
6363
;--- check for valid 32bit register name!
6364

6365
rr6:
6366
	cmp [machine],3
6367
	jb rr_err
6368
	cmp al,'E'
6369
	jnz rr_err
6370
	lodsb
6371
	and al,TOUPPER
6372
	cmp al,'S'		;avoid EDS,ECS,ESS,... to be accepted!
6373
	jz rr_err
6374
	xchg al,ah
6375
	mov cx,NUMREGNAMES
6376
	mov di,offset regnames
6377
	repne scasw
6378
	jne rr_err
6379

6380
;--- it is a valid 32bit register name
6381

6382
	mov bx,di
6383
	mov di,offset line_out
6384
	mov byte ptr [di],'E'
6385
	inc di
6386
	stosw
6387
	mov al,' '
6388
	stosb
6389
	mov bx,[bx+NUMREGNAMES*2-2]
6390
	call skipcomma	;skip white spaces
6391
	cmp al,CR
6392
	jne rr1aX   	;if not end of line
6393
	push bx
6394
	.386
6395
	mov eax,[bx+0]
6396
	.8086
6397
	call hexdword
6398
	call getline0	;prompt for new value
6399
	pop bx
6400
	cmp al,CR
6401
	je rr1bX		;if no change required
6402
rr1aX:
6403
	push bx
6404
	call getdword
6405
	mov cx,bx
6406
	pop bx
6407
	call chkeol		;expect end of line here
6408
	mov [bx+0],dx	;save new value
6409
	mov [bx+2],cx	;save new value
6410
rr1bX:
6411
	ret
6412

6413
r_cmd endp
6414

6415
rr_err:
6416
	dec si		;back up one before flagging an error
6417
errorj9:
6418
	jmp cmd_error
6419

6420
if RING0
6421

6422
CONST segment
6423

6424
exctab label byte	; ring 0 exc table used by SK, VC, VT
6425
	db 0,1,3
6426
 if CATCHINT06
6427
	db 6
6428
 endif
6429
 if CATCHINT07
6430
	db 7
6431
 endif
6432
 if CATCHINT0C
6433
	db 0Ch
6434
 endif
6435
 if CATCHINT0D
6436
	db 0Dh
6437
 endif
6438
	db 0Eh
6439
SIZEEXCTAB equ $ - offset exctab
6440

6441
noskip db "No exception to skip",13,10,'$'
6442
yesskip db "Exception skipped",13,10,'$'
6443

6444
CONST ends
6445

6446
;--- skip exception.
6447
;--- actually, the only exceptions that cannot be skipped
6448
;--- are breakpoints set by the debugger itself.
6449

6450
sk_cmd proc
6451
	.386
6452
	mov dl, [run_int+1]
6453
	and dl, 1Fh
6454
	mov cx, SIZEEXCTAB
6455
	mov si, offset exctab
6456
	mov bx, offset intsave
6457
@@:
6458
	lodsb
6459
	cmp dl, al
6460
	jz found
6461
	add bx, sizeof INTVEC
6462
	loop @B
6463
	mov dx, offset noskip
6464
	jmp int21ah9
6465
found:
6466
	xchg si, bx
6467
	mov ebx, dword ptr [regs.rSP]
6468
	mov dx, [regs.rSS]
6469
 if V86M
6470
	test byte ptr [regs.rFL+2], 2
6471
	jnz isv86
6472
 endif
6473
	lar ax, [regs.rCS]
6474
	and ah, 60h				; exception occured in ring 0?
6475
	jz @F					; then there's no stack switch.
6476
isv86:
6477
	mov ebx, [regs.r0Esp]	; no, use saved r0 stack
6478
	mov dx, [regs.r0SS]
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
6481
 if V86M
6482
	test byte ptr [regs.rFL+2], 2
6483
	jz isv86_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   
6486
	xor ax, ax
6487
	mov [regs.rDS], ax
6488
	mov [regs.rES], ax
6489
	mov [regs.rFS], ax
6490
	mov [regs.rGS], ax
6491
isv86_2:
6492
 endif
6493
@@:
6494
;--- dx=ss, ebx=esp, esi -> intsave entry for exception
6495
	bt [run_intw], 15	; exc with error code?
6496
	jnc @F
6497
	sub ebx, 1*4	; correct error code
6498
@@:
6499
	sub ebx, 3*4	; correct cs:eip & efl
6500
	mov dword ptr [regs.rSP], ebx
6501
	mov [regs.rSS], dx
6502
	lodsd
6503
	mov dword ptr [regs.rIP], eax
6504
	mov dword ptr [u_addr], eax
6505
	lodsw
6506
	mov [regs.rCS], ax
6507
	mov [u_addr+4], ax
6508

6509
	pushf
6510
	pop ax
6511
	mov byte ptr [regs.rFL+1], ah
6512

6513
	mov [run_int+1], -1		; reset run_int, so skip is "deactivated" for this time
6514
	mov dx, offset yesskip
6515
	jmp int21ah9
6516

6517
sk_cmd endp
6518

6519
endif
6520

6521
;--- S command - search for a string of bytes.
6522

6523
s_cmd proc
6524
if RING0
6525
	cmp ah,'s'
6526
	jnz @F
6527
	or al,TOLOWER
6528
	cmp al, 'k'
6529
	jz sk_cmd
6530
@@:
6531
endif
6532
	call getrangeDS	;get address range into BX:(E)DX..BX:(E)CX
6533
	call skipcomm0
6534
	push cx
6535
	push dx
6536
	call getstr		;get string of bytes, size: di - (lineout+1)
6537
	pop dx
6538
	pop cx
6539

6540
	sub di,offset line_out	;di = number of bytes to look for
6541
	dec di			;     minus one
6542
if ?PM
6543
	call IsOfs32
6544
	jz @F
6545
	.386
6546
	@dprintf "s_cmd: bx:edx=%X:%lX, ecx=%lX, di=%X", bx, edx, ecx, di
6547
	sub ecx, edx
6548
	movzx edi, di
6549
	sub ecx, edi
6550
	jb errorj9		;if none
6551
	.8086
6552
	jmp s_cont
6553
@@:
6554
	@dprintf "s_cmd: bx:dx=%X:%X, cx=%X, di=%X", bx, dx, cx, di
6555
endif
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
6558
	jb errorj9		;if none
6559
s_cont:
6560
	call prephack
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
6565

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
6570
if ?PM
6571
	call IsOfs32
6572
	jz sss1_16
6573
;	@dprintf "s_cmd scasb: es:edi=%X:%lX, ecx=%lX ax=%X", es, edi, ecx, ax
6574
	.386
6575
	repne scasb es:[edi]
6576
	je @F
6577
	scasb es:[edi]
6578
	jnz sss3
6579
@@:
6580
	push ecx
6581
	push edi
6582
	movzx ecx, dx
6583
	movzx esi, si
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]
6586
	pop edi
6587
	jne @F			;if not equal
6588
	call displaypos
6589
@@:
6590
	pop ecx
6591
	inc ecx
6592
	loop sss1
6593
	jmp unhack
6594
	.8086
6595
sss1_16:
6596
endif
6597
	repne scasb		;look for first byte
6598
	je @F
6599
	scasb			;count in CX was cnt-1
6600
	jne sss3		;if we're done
6601
@@:
6602
	push cx
6603
	push di
6604
	mov cx,dx
6605
	repe cmpsb
6606
	pop di
6607
	jne @F			;if not equal
6608
	call displaypos
6609
@@:
6610
	pop cx
6611
	inc cx
6612
	loop sss1		;go back for more
6613
sss3:
6614
	jmp unhack		;set debugger's int 23/24
6615

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 )
6619

6620
displaypos:
6621
	call unhack		;set debugger's int 23/24
6622
	push dx
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
6627
	pop es
6628
	@dispsegm bx
6629
	mov al,':'
6630
	stosb
6631
if ?PM
6632
	call IsOfs32
6633
	jz @F
6634
	.386
6635
	lea eax,[esi-1]
6636
	.8086
6637
	call hexdword
6638
	jmp s_cont3
6639
@@:
6640
endif
6641
	lea ax,[si-1]
6642
	call hexword
6643
s_cont3:
6644
	mov ax,( LF shl 8 ) or CR
6645
	stosw
6646
	pop dx			;get pos from stack
6647
	mov cx, di
6648
	sub cx, dx
6649
	call stdout		;write cx chars from ds:dx to stdout
6650
	pop dx
6651
	sizeprfX		;mov edi, esi
6652
	mov di,si
6653
	jmp dohack		;set debuggee's int 23/24
6654

6655
s_cmd endp
6656

6657
tm_cmd proc
6658
	call skipcomma
6659
	cmp al,CR
6660
	jz ismodeget
6661
	call getword
6662
	cmp dx,1
6663
	jna @F
6664
	jmp cmd_error
6665
@@:
6666
	call chkeol		;expect end of line here
6667
	mov [tmode],dl
6668
;	ret
6669
ismodeget:
6670
	mov si, offset tmode0
6671
	mov al, [tmode]
6672
	and al, 1
6673
	jz @F
6674
	mov si, offset tmode1
6675
@@:
6676
	push si
6677
	add al, '0'
6678
	mov [tmodes2], al
6679
	mov si, offset tmodes
6680
	call copystring
6681
	pop si
6682
	call copystring
6683
	call putsline
6684
	ret
6685

6686
tm_cmd endp
6687

6688
;--- T command - Trace.
6689

6690
t_cmd proc
6691
	cmp al, CR
6692
	jz tt0
6693
	or al,TOLOWER
6694
	cmp ax,'tm'
6695
	jz tm_cmd
6696
tt0:
6697
;	mov [lastcmd], offset tt0
6698
	mov [lastcmd], offset t_cmd
6699
	call parse_pt	;process arguments
6700
@@:
6701
	push cx
6702
	call trace1
6703
	pop cx
6704
	loop @B
6705
	ret
6706

6707
t_cmd endp
6708

6709
;--- trace one instruction
6710

6711
trace1 proc
6712
if ?PM
6713
	call getcsattr
6714
	mov [bCSAttr],al
6715
endif
6716
if ?DPMI
6717
	mov bx,[regs.rIP]
6718
	mov ax,[regs.rCS]
6719
	cmp bx,word ptr [dpmiwatch+0]	;catch the initial switch to protected mode
6720
	jnz trace1_1
6721
	cmp ax,word ptr [dpmiwatch+2]
6722
	jnz trace1_1
6723
	cmp [bNoHook2F],0	;current CS:IP is dpmi entry
6724
	jz @F
6725
	;if int 2fh is *not* hooked ( win3x, win9x, dosemu )
6726
	mov [regs.rIP],offset mydpmientry
6727
	mov [regs.rCS],cs
6728
@@:
6729
	push ss
6730
	pop es		;run code until RETF
6731
	push ds
6732
	mov bx,[regs.rSP]
6733
	mov ds,[regs.rSS]
6734
	mov si,[bx+0]
6735
	mov bx,[bx+2]
6736
	pop ds
6737
	call doproceed1
6738
	ret
6739
trace1_1:
6740
endif
6741
	xor cx,cx
6742
	call getcseipbyte
6743
	cmp al,0CDh			; an INT instruction?
6744
	jnz isstdtrace
6745
	inc cx
6746
	call getcseipbyte
6747
	cmp al,3			; 2-byte INT 3?
6748
	jz isstdtrace
6749
	test byte ptr [tmode], 1	;TM=1?
6750
	jz trace_int
6751
	cmp al,1			; INT 1?
6752
	jnz step_int
6753
isstdtrace:
6754
	or byte ptr [regs.rFL+1],1h	;set single-step mode
6755
	xor cx,cx
6756
	call getcseipbyte
6757
	push ax
6758
	call run
6759
	pop ax
6760
	cmp al,9Ch			;was opcode "PUSHF"?
6761
	jnz @F
6762
	call clear_tf_onstack
6763
@@:
6764
	cmp [run_int], EXC01MSG
6765
	je tt1_1
6766
	jmp ue_int			;if some other interrupt ( is always "unexpected" )
6767
tt1_1:
6768
	call dumpregs
6769
	ret
6770

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
6775

6776
; if the int will terminate the debuggee (int 21h, ah=4Ch)
6777
; it is important that the breakpoint won't be restored!
6778

6779
trace_int:
6780
if USEHWBP and ?DPMI
6781
	call ispm_dbe		; in protected-mode?
6782
	jnz useproceed		; then don't check, optionally use hw bp 
6783
endif
6784
if RING0 and USEHWBP	; no check for DebugR if USEHWBP is 1
6785
else
6786
	mov cx,2
6787
	call iswriteablecseip	;is current CS:IP in ROM?
6788
	jc isstdtrace			;then do standard trace
6789
endif
6790
useproceed:
6791
	@movs bx,[regs.rCS]
6792
	sizeprfX			; mov esi,[regs.rIP]
6793
	mov si,[regs.rIP]
6794
if ?PM
6795
	call inceip
6796
	call inceip
6797
else
6798
	add si, 2
6799
endif
6800
	call doproceed1		;set BP at BX:(E)SI and run debuggee
6801
	ret
6802

6803
;--- current instruction is INT, TM is 1, single-step into the interrupt
6804
;--- AL=int#
6805

6806
step_int:
6807
	mov bl,al
6808
if ?PM
6809
 if ?DPMI
6810
	call ispm_dbg
6811
	jz step_int_rm
6812
	mov  ax,204h
6813
	int  31h			;get vector in CX:(E)DX
6814
	mov  bx,cx
6815
	test bl,4			;is it a LDT selector?
6816
	jnz  @F
6817
	jmp  isstdtrace
6818
@@:
6819
	sizeprf		;mov  esi,edx
6820
	mov  si,dx
6821
 elseif RING0
6822
	.386
6823
  if FLATSS
6824
	sub esp, 6
6825
	sidt [esp]
6826
  else
6827
   if V86M
6828
	test byte ptr [regs.rFL+2],2
6829
	jnz step_int_rm
6830
   endif
6831
	push bp
6832
	mov bp, sp
6833
	sub sp, 6
6834
	sidt [bp-6]
6835
  endif
6836
	pop ax
6837
	pop eax
6838
  ife FLATSS
6839
	pop bp
6840
  endif
6841
	push ds
6842
	mov ds, [wFlat]
6843
	movzx ebx, bl
6844
  if LMODE
6845
	shl bx, 4
6846
  else
6847
	shl bx, 3
6848
  endif
6849
	mov si, ds:[ebx+eax+6]
6850
	shl esi, 16
6851
	mov si, ds:[ebx+eax+0]
6852
	mov bx, ds:[ebx+eax+2]
6853
	pop ds
6854
 endif
6855
	call doproceed1	; expects bp to be set at BX:(E)SI
6856
	ret
6857
endif
6858
if (RING0 eq 0) or V86M
6859
step_int_rm:
6860
	mov bh,0
6861
	push ds
6862
 if V86M
6863
	mov ds, [wFlat]
6864
	movzx ebx, bx
6865
	movzx eax, word ptr [ebx*4+2]
6866
	shl eax, 4
6867
	movzx esi, word ptr [ebx*4+0]
6868
	add esi, eax
6869
	mov bx, ds
6870
	pop ds
6871
 else
6872
	xor ax,ax
6873
	mov ds,ax
6874
	shl bx,1		;stay 8086 compatible in real-mode!
6875
	shl bx,1
6876
	cli
6877
	lds si,[bx+0]	; check if IVT is R/O? What's the purpose?
6878
	mov al,[si]
6879
	xor byte ptr [si],0FFh
6880
	cmp al,[si]
6881
	mov [si],al
6882
	sti
6883
	jz isrom
6884
	mov bx,ds
6885
	pop ds
6886
 endif
6887
	call doproceed1	; set bp at BX:ESI, then GO
6888
	ret
6889
 ife V86M
6890
isrom:
6891
	mov  ax,ds
6892
	pop  ds
6893
	xchg si,[regs.rIP]
6894
	xchg ax,[regs.rCS]
6895
	mov  cx,[regs.rFL]
6896
	push ds
6897
	mov  bx,[regs.rSP]
6898
	mov  ds,[regs.rSS]		;emulate an INT
6899
	sub  bx,6
6900
	inc  si 				;skip INT xx
6901
	inc  si
6902
	mov  [bx+0],si
6903
	mov  [bx+2],ax
6904
	mov  [bx+4],cx
6905
	pop  ds
6906
	mov  [regs.rSP],bx
6907
	and  byte ptr [regs.rFL+1],0FCh  ;clear IF + TF
6908
	jmp  tt1_1
6909
 endif
6910
endif
6911

6912
trace1 endp
6913

6914
;--- test if memory at CS:E/IP can be written to.
6915
;--- return C if not
6916
;--- used by T cmd.
6917
;--- IN: CX=offset for (E)IP
6918

6919
if RING0 and USEHWBP	; remove if RING==1 and USEHWBP==1
6920
else
6921
iswriteablecseip proc
6922
	call getcseipbyte	;get byte ptr at CS:EIP+CX
6923
	mov ah,al
6924
	xor al,0FFh
6925
	call setcseipbyte
6926
	jc notwriteable
6927
	call getcseipbyte
6928
	cmp ah,al			;is it ROM?
6929
	jz notwriteable
6930
	mov al,ah
6931
	call setcseipbyte
6932
	clc
6933
	ret
6934
notwriteable:
6935
	stc
6936
	ret
6937
iswriteablecseip endp
6938
endif
6939

6940
;--- clear TF in the copy of flags register onto the stack
6941

6942
clear_tf_onstack proc
6943
	push es
6944
	@movs es, [regs.rSS]
6945
if ?PM
6946
	mov bx,es
6947
;	call getseglimit      ; v1.29: segment limit doesn't matter,
6948
	call getseldefsize    ; check defsize if ESP is to be used.
6949
	jz @F
6950
	.386
6951
	mov ebx,dword ptr [regs.rSP]
6952
	and byte ptr es:[ebx+1],not 1
6953
	jmp ctos_1
6954
	.8086
6955
@@:
6956
	@dprintf "clear_tf_onstack: es=%X", es
6957
endif
6958
	mov bx,[regs.rSP]
6959
	and byte ptr es:[bx+1],not 1
6960
ctos_1:
6961
	pop es
6962
	ret
6963
clear_tf_onstack endp
6964

6965
;--- Print message about unexpected interrupt, dump registers, and end
6966
;--- command.  This code is used by G, P and T cmds.
6967

6968
ue_int:
6969
	mov dl, [run_int]
6970
if RING0 and CATCHSYSREQ
6971
	.386
6972
	btr word ptr [bFlagsPM], 1
6973
	.8086
6974
	jnc @F
6975
	mov dl, SYSRQMSG
6976
	push ds
6977
	mov ds, [wFlat]
6978
	and word ptr ds:[417h], not ( 200h or 8)	;reset "Alt pressed" flags
6979
	pop ds
6980
@@:
6981
endif
6982
	mov dh, 0
6983
	add dx, offset int0msg
6984
	call int21ah9	;print string
6985
if INT22
6986
	cmp dx, offset progtrm
6987
	je @F			;if it terminated, skip the registers
6988
endif
6989
	call dumpregs
6990
@@:
6991
	jmp cmdloop		;back to the start
6992

6993
;--- "unexpected" exception in real-mode inside debugger
6994

6995
ife RING0
6996
 if CATCHINT07 or CATCHINT0C or CATCHINT0D or SKIPBPINDBG
6997
ue_intxx:
6998
  if EXCCSIP
6999
	pop cx
7000
	pop dx
7001
  endif
7002
	push cs
7003
	pop ss
7004
	mov sp,cs:[top_sp]
7005
	push cx	; ip
7006
	push dx	; cs
7007
	push ax	; msg
7008

7009
;--- fall thru
7010

7011
 endif
7012
endif
7013

7014

7015
if ?PM or CATCHINT07 or CATCHINT0C or CATCHINT0D
7016

7017
;--- "unexpected" exception occured inside debugger
7018
;--- [SP] = msg, cs, [e]ip
7019

7020
ue_intx proc
7021
	cld
7022
	@RestoreSeg ds
7023
	call unhack		;set debugger's int 23/24
7024
if ?PM
7025
	test [disflags], DIS_I_MEMACC
7026
	jz @F
7027
	mov [disflags], 0
7028
	mov dx,offset crlf
7029
	call int21ah9
7030
@@:
7031
endif
7032
	pop dx
7033
	add dx, offset int0msg
7034
	call int21ah9	;print string
7035
if EXCCSIP
7036
	push ds
7037
	pop es
7038
	mov di,offset line_out
7039
	mov si,offset excloc	; "CS:IP="
7040
	call copystring
7041
	pop ax
7042
	call hexword
7043
	mov al,':'
7044
	stosb
7045
 if EXCCSEIP
7046
	.386
7047
	pop eax
7048
	.8086
7049
	call hexdword
7050
 else
7051
	pop ax
7052
	call hexword
7053
 endif
7054
	call putsline
7055
endif
7056
	jmp cmdloop
7057
ue_intx endp
7058

7059
endif
7060

7061
;--- U command - disassemble.
7062

7063
u_cmd proc
7064
	mov [lastcmd],offset u_cmd
7065
	mov cx,20h		;default length
7066
	cmp al,CR
7067
	je uuloop		;if no address was given
7068
	@movs bx,[regs.rCS]
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
7072
	mov [u_addr+0],dx
7073
	mov [u_addr+4],bx
7074
	sizeprfX		;inc ecx
7075
	inc cx
7076
	sizeprfX		;sub ecx, edx
7077
	sub cx, dx
7078
	@dprintf "u_cmd: u_addr=%X:%lX, ecx=%lX", bx, edx, ecx
7079

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.
7084

7085
uuloop:
7086
	sizeprfX		;push ecx
7087
	push cx
7088
	call disasm1	;disassemble one instruction
7089
	sizeprfX		;pop ecx
7090
	pop cx
7091
if ?PM
7092
	mov bx, [dis_n]	;bytes disassembled
7093
	sizeprfX		;movzx ebx, bx
7094
	lea bx, [bx]   
7095
	sizeprfX		;sub ecx, ebx
7096
	sub cx, bx
7097
else
7098
	sub cx, [dis_n]
7099
endif
7100
	ja uuloop		;if we haven't reached the goal
7101
	ret
7102
u_cmd endp
7103

7104
if WCMD
7105

7106
lockdrive:          ;lock logical volume
7107
	push ax
7108
	push bx
7109
	push cx
7110
	push dx
7111
	mov bl,al
7112
	inc bl
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)
7116
	mov ax,440Dh
7117
	int 21h
7118
	pop dx
7119
	pop cx
7120
	pop bx
7121
	pop ax
7122
	ret
7123
unlockdrive:
7124
	push ax
7125
	push bx
7126
	push cx
7127
	push dx
7128
	mov bl,al
7129
	inc bl
7130
;	mov bh,0		;bh has no meaning for unlock
7131
	mov cx,086Ah	;isn't this for non-FAT32 drives only?
7132
;	mov dx,0001h
7133
	mov ax,440Dh
7134
	int 21h
7135
	pop dx
7136
	pop cx
7137
	pop bx
7138
	pop ax
7139
	ret
7140

7141
;--- W command - write a program, or disk sectors, to disk.
7142

7143
w_cmd proc
7144
	call parselw	;parse L and W argument format (out: bx:(e)dx=address)
7145
if WCMDFILE
7146
	jz write_file	;if request to write program
7147
else
7148
	jz cmd_error	;no support to write program
7149
endif
7150
if NOEXTENDER
7151
	call ispm_dbg
7152
	jz @F
7153
	call isextenderavailable	;in protected-mode, DOS translation needed
7154
	jnc @F
7155
	mov dx,offset nodosext
7156
	jmp int21ah9
7157
@@:
7158
endif
7159
	cmp cs:[usepacket],2
7160
	jb ww0_1
7161
	mov dl,al		;A=0,B=1,C=2,...
7162
	mov si,6001h	;write, assume "file data"
7163
if VDD
7164
	mov ax,[hVdd]
7165
	cmp ax,-1
7166
	jnz callvddwrite
7167
endif
7168
	inc dl			;A=1,B=2,C=3,...
7169
	call lockdrive
7170
	mov ax,7305h	;DS:(E)BX->packet
7171
	stc
7172
	int 21h			;use int 21h here, not doscall
7173
	pushf
7174
	call unlockdrive
7175
	popf
7176
	jmp ww0_2
7177
if VDD
7178
callvddwrite:
7179
	mov cx,5
7180
	add cl,[dpmi32]
7181
	DispatchCall
7182
	jmp ww0_2
7183
endif
7184
ww0_1:
7185
	int 26h
7186
ww0_2:
7187
	mov cx,"rw"		;cx:dx="writ"
7188
	mov dx,"ti"
7189
;	jmp disp_diskresult	; fall thru to disp_diskresult
7190

7191
w_cmd endp
7192

7193
;--- display disk access result ( C if error )
7194
;--- CX:DX="read"/"writ"
7195

7196
disp_diskresult proc
7197
	mov bx,ss		;restore segment registers
7198
	mov ds,bx
7199
	mov sp,[top_sp]
7200
	mov es, bx
7201
	jnc ww3		;if no error
7202
	mov word ptr [szDrive+1], cx
7203
	mov word ptr [szDrive+3], dx
7204
	add [driveno], 'A'
7205
	cmp al,0ch
7206
	jbe @F		;if in range
7207
	mov al,0ch
7208
@@:
7209
	cbw
7210
;	shl ax,1	; v2.0: removed - dskerrs is a byte offset table
7211
	xchg si, ax
7212
	mov al, [si+dskerrs]
7213
	mov si, offset dskerr0
7214
	add si, ax
7215
	mov di, offset line_out
7216
	call copystring
7217
	mov si, offset szDrive
7218
	call copystring
7219
	call putsline
7220
ww3:
7221
	jmp cmdloop		;can't ret because stack is wrong
7222

7223
disp_diskresult endp
7224

7225
endif
7226

7227
if WCMDFILE
7228

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
7232

7233
write_file proc
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
7238
	jmp exitwithmsg
7239
@@:
7240
	cmp al,0
7241
	jnz ww7		;if extension exists
7242
	mov dx,offset nownull
7243
exitwithmsg:
7244
	jmp int21ah9
7245

7246
;--- File extension is OK; write it.  First, create the file.
7247
;--- bx:e/dx = start address
7248

7249
ww7:
7250
if ?DPMI
7251
	call ispm_dbg
7252
	jz @F
7253
	mov dx,offset nopmsupp	;cmd rejected in protected-mode
7254
	jmp int21ah9
7255
@@:
7256
endif
7257
	mov bp,offset line_out
7258
	cmp dh,0feh
7259
	jb @F			;if dx < fe00h
7260
	sub dh,0feh		;dx -= 0xfe00
7261
	add bx,0fe0h
7262
@@:
7263
	mov [bp+10],dx	;save lower part of address in line_out+10
7264
	mov si,bx		;upper part goes into si
7265
if FMTEXE
7266
	push ds
7267
	mov ds, [pspdbg]
7268
endif
7269
	xor cx,cx		;no attributes
7270
	mov dx,PSPS.DTA
7271
	mov ah,3ch		;create file
7272
	call doscall
7273
if FMTEXE
7274
	pop ds
7275
endif
7276
	jc io_error		;if error
7277
	push ax			;save file handle
7278

7279
;--- Print message about writing.
7280

7281
	mov dx,offset wwmsg1
7282
	call int21ah9	;print string
7283
	mov ax,[regs.rBX]
7284
	cmp ax,10h		;max size = 0fffffh
7285
	jb @F			;if not too large
7286
	xor ax,ax		;too large:  zero it out
7287
@@:
7288
	mov [bp+8],ax
7289
	or ax,ax
7290
	jz @F
7291
	call hexnyb		;convert to hex digit and print
7292
@@:
7293
	mov ax,[regs.rCX]
7294
	mov [bp+6],ax
7295
	call hexword
7296
	call puts		;print size
7297
	mov dx,offset wwmsg2
7298
	call int21ah9	;print string
7299

7300
;--- Now write the file.  Size remaining is in line_out+6.
7301

7302
	pop bx			;recover file handle
7303
	mov dx,[bp+10]	;address to write from is si:dx
7304
ww11:
7305
	mov ax,0fe00h
7306
	sub ax,dx
7307
	cmp byte ptr [bp+8],0
7308
	jnz @F			;if more than 0fe00h bytes remaining
7309
	cmp ax,[bp+6]
7310
	jb @F			;ditto
7311
	mov ax,[bp+6]
7312
@@:
7313
	xchg ax,cx		;mov cx,ax
7314
	mov ds,si
7315
	mov ah,40h		;write to file
7316
	int 21h			;use INT, not doscall
7317
	push ss			;restore DS
7318
	pop ds
7319
	cmp ax,cx
7320
	jne ww13		;if disk full
7321
	xor dx,dx		;next time write from xxxx:0
7322
	add si,0fe0h	;update segment pointer
7323
	sub [bp+6],cx
7324
	lahf
7325
	sbb byte ptr [bp+8],0
7326
	jnz ww11		;if more to go
7327
	sahf
7328
	jnz ww11		;ditto
7329
	jmp ww14		;done
7330

7331
ww13:
7332
	mov dx,offset diskful
7333
	call int21ah9	;print string
7334
if FMTEXE
7335
	push ds
7336
	mov ds, [pspdbg]
7337
endif
7338
	mov dx,PSPS.DTA
7339
	mov ah,41h		;unlink file
7340
	call doscall
7341
if FMTEXE
7342
	pop ds
7343
endif
7344

7345
;--- Close the file.
7346

7347
ww14:
7348
	mov ah,3eh		;close file
7349
	int 21h
7350
	ret
7351
write_file endp
7352

7353
endif
7354

7355
if LCMDFILE or WCMDFILE
7356

7357
;--- Error opening file.  This is also called by the load command.
7358

7359
io_error:
7360
	cmp ax,2
7361
	mov dx,offset doserr2	;File not found
7362
	je @F
7363
	cmp ax,3
7364
	mov dx,offset doserr3	;Path not found
7365
	je @F
7366
	cmp ax,5
7367
	mov dx,offset doserr5	;Access denied
7368
	je @F
7369
	cmp ax,8
7370
	mov dx,offset doserr8	;Insufficient memory
7371
	je @F
7372
	mov di,offset openerr1
7373
	call hexword
7374
	mov dx,offset openerr	;Error ____ opening file
7375
@@:
7376

7377
;--- fall thru
7378

7379
endif
7380

7381
int21ah9:
7382
ife RING0
7383
 if 1 ;v2.0: check InDos, if set use stdout()
7384
	call InDos
7385
	jnz use_stdout
7386
 endif
7387
	mov ah,9
7388
	call doscall
7389
	ret
7390
endif
7391
if 1 ;v2.0: get size of $-string DS:DX, then call stdout; SI, CX not modified
7392
use_stdout:
7393
	push si
7394
	push cx
7395
	mov si, dx
7396
@@:
7397
	lodsb
7398
	cmp al, '$'
7399
	jnz @B
7400
	dec si
7401
	sub si, dx
7402
	mov cx, si
7403
	call stdout
7404
	pop cx
7405
	pop si
7406
	ret
7407
endif
7408

7409
if XCMDS
7410

7411
;--- X commands - manipulate EMS memory.
7412

7413
;--- XA - Allocate EMS.
7414
;--- DX = pages
7415

7416
xa proc
7417
	call chkeol		;expect end of line here
7418
	mov bx,dx
7419
	mov ah,43h		;allocate handle
7420
	and bx,bx
7421
	jnz @F
7422
	mov ax,5A00h	;use the EMS 4.0 version to alloc 0 pages
7423
@@:
7424
	call emscall
7425
	push dx
7426
	mov si,offset xaans	; "Handle created: "
7427
	call copystring
7428
	pop ax
7429
	call hexword
7430
	jmp putsline	;print string and return
7431
xa endp
7432

7433
;--- XD - Deallocate EMS handle.
7434
;--- DX = handle
7435

7436
xd proc
7437

7438
	call chkeol		;expect end of line here
7439
	mov ah,45h		;deallocate handle
7440
	call emscall
7441
	push dx
7442
	mov si,offset xdans	; "Handle deallocated: "
7443
	call copystring
7444
	pop ax
7445
	call hexword
7446
	jmp putsline	;print string and return
7447

7448
xd endp
7449

7450
;--- x main dispatcher
7451

7452
x_cmd proc
7453
	cmp al,'?'
7454
	je xhelp	;if a call for help
7455
	push ax
7456
	call emschk
7457
	pop ax
7458
	or al,TOLOWER
7459
	cmp al,'s'
7460
	je xs		;if XS command
7461
	push ax
7462
	call skipcomma
7463
	call getword
7464
	pop cx
7465
	cmp cl,'a'
7466
	je xa		;if XA command
7467
	cmp cl,'d'
7468
	je xd		;if XD command
7469
	cmp cl,'r'
7470
	je xr		;if XR command
7471
	cmp cl,'m'
7472
	je xm		;if XM command
7473
	jmp cmd_error
7474

7475
xhelp:
7476
	mov dx,offset xhelpmsg
7477
	mov cx,size_xhelpmsg
7478
	jmp stdout	;print string and return
7479
x_cmd endp
7480

7481
;--- XR - Reallocate EMS handle.
7482
;--- DX = first argument (=handle)
7483

7484
xr proc
7485
	mov bx,dx
7486
	call skipcomma
7487
	call getword		;get count argument into DX
7488
	call chkeol			;expect end of line here
7489
	xchg bx,dx
7490
	mov ah,51h			;reallocate handle
7491
	call emscall
7492
	mov si,offset xrans	; "Handle reallocated: "
7493
	call copystring
7494
	jmp putsline		;print string and return
7495

7496
xr endp
7497

7498
;--- XM - Map EMS memory to physical page.
7499
;--- DX = first argument [=logical page (FFFF means unmap)]
7500

7501
xm proc
7502
	mov bx,dx		;save it in BX
7503
	call skipcomm0
7504
	call getbyte	;get physical page (DL)
7505
	push dx
7506
	call skipcomm0
7507
	call getword	;get handle into DX
7508
	call chkeol		;expect end of line
7509
	pop ax			;recover physical page into AL
7510
	push ax
7511
	mov ah,44h		;function 5 - map memory
7512
	call emscall
7513
	mov si,offset xmans
7514
	call copystring
7515
	mov bp,di
7516
	mov di,offset line_out + xmans_pos1
7517
	xchg ax,bx		;mov ax,bx
7518
	call hexword
7519
	mov di,offset line_out + xmans_pos2
7520
	pop ax
7521
	call hexbyte
7522
	mov di,bp
7523
	jmp putsline	;print string and return
7524

7525
xm endp
7526

7527
;--- XS - Print EMS status.
7528

7529
xs proc
7530
	lodsb
7531
	call chkeol		;no arguments allowed
7532

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.
7536

7537
	mov ah,4bh		;function 12 - get handle count
7538
	call emscall
7539
	cmp bx,( real_end - line_out ) / 4
7540
	jbe xs3			;if we can do it by getting the table
7541

7542
	xor dx,dx		;start handle
7543
nexthdl:
7544
	mov ah,4ch		;function 13 - get handle pages
7545
	int 67h
7546
	cmp ah,83h		; error "invalid handle"?
7547
	je xs2			;if no such handle
7548
	or ah,ah
7549
	jz @F
7550
	jmp ems_err		;if other error
7551
@@:
7552
	xchg ax,bx		;mov ax,bx
7553
	call hndlshow
7554
xs2:
7555
	inc dl
7556
	jnz nexthdl		;if more to be done
7557

7558
	jmp xs5			;done with this part
7559

7560
;--- Get the information in tabular form.
7561

7562
xs3:
7563
	mov ah,4dh		;function 14 - get all handle pages
7564
	mov di,offset line_out
7565
	call emscall
7566
	and bx,bx		;has returned no of entries in BX
7567
	jz xs5
7568
	mov si,di
7569
@@:
7570
	lodsw
7571
	xchg ax,dx
7572
	lodsw
7573
	call hndlshow
7574
	dec bx
7575
	jnz @B		;if more to go
7576

7577
xs5:
7578
	mov dx,offset crlf
7579
	call int21ah9	;print string
7580

7581
;   Next print the mappable physical address array.
7582
;   The size of the array shouldn't be a problem.
7583

7584
	mov ax,5800h	;function 25 - get mappable phys. address array
7585
	mov di,offset line_out	;address to put array
7586
	call emscall
7587
	mov dx,offset xsnopgs
7588
	jcxz xs7		;NO mappable pages!
7589

7590
	mov si,di
7591
xs6:
7592
	push cx
7593
	lodsw
7594
	mov di,offset xsstr2b
7595
	call hexword
7596
	lodsw
7597
	mov di,offset xsstr2a
7598
	call hexbyte
7599
	mov dx,offset xsstr2
7600
	mov cx,size_xsstr2
7601
	call stdout		;print string
7602
	pop cx			;end of loop
7603
	test cl,1
7604
	jz @F
7605
	mov dx,offset crlf		;blank line
7606
	call int21ah9	;print string
7607
@@:
7608
	loop xs6
7609
	mov dx,offset crlf		;blank line
7610
xs7:
7611
	call int21ah9	;print string
7612

7613
;--- Finally, print the cumulative totals.
7614

7615
	mov ah,42h		;function 3 - get unallocated page count
7616
	call emscall
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
7622
	call emscall
7623
	push bx
7624

7625
;--- try EMS 4.0 function 5402h to get total number of handles
7626

7627
	mov ax,5402h
7628
	int 67h         ;don't use emscall, this function may fail!
7629
	mov dx,bx
7630
	cmp ah,0
7631
	jz @F
7632
	mov dx,0ffh		;total number of handles
7633
@@:
7634
	pop ax			;ax = number of handles allocated
7635
	mov bx,offset xsstrhd
7636
	call sumshow	;print the line
7637
	ret				;done
7638

7639
xs endp
7640

7641
;--- Call EMS
7642
;--- in case of error, return to cmd loop
7643

7644
emscall proc
7645
if ?DPMI
7646
	call ispm_dbg
7647
	jz ems_rm
7648
	.286
7649
	invoke simrealmodeint, 67h, cs:[wDgroup]
7650
	jmp ems_call_done
7651
	.8086
7652
ems_rm:
7653
endif
7654
	int 67h
7655
ems_call_done:
7656
	and ah,ah	;error?
7657
	js ems_err
7658
	ret			;return if OK
7659

7660
emscall endp
7661

7662
;--- ems error in AH
7663

7664
ems_err proc
7665
	mov al,ah
7666
	cmp al,8bh
7667
	jg ce2		;if out of range
7668
	cbw			;80->ff80 ... 8B->ff8B
7669
	mov bx,ax
7670
	shl bx,1	;ff80->ff00 ... ff8B->ff16
7671
	mov si,[emserrs+100h+bx]
7672
	or si,si
7673
	jnz ems_err3	;if there's a word there
7674
ce2:
7675
	mov di,offset emserrxa
7676
	call hexbyte
7677
	mov si,offset emserrx
7678
ems_err3::
7679
	mov di,offset line_out
7680
	call copystring	;si->di
7681
	call putsline
7682
	jmp cmdloop
7683

7684
ems_err endp
7685

7686
;--- Check for EMS
7687

7688
emschk proc
7689
if ?DPMI
7690
	call ispm_dbg
7691
	jz emschk1
7692
	mov bl,67h
7693
	mov ax,0200h
7694
	int 31h
7695
	mov ax,cx
7696
	or ax,dx
7697
	jz echk2
7698
	jmp emschk2
7699
emschk1:
7700
endif
7701
	push es
7702
	mov ax,3567h	;get interrupt vector 67h
7703
	int 21h
7704
	mov ax,es
7705
	pop es
7706
	or ax,bx
7707
	jz echk2
7708
emschk2:
7709
	mov ah,46h		;get version
7710
;	int 67h
7711
	call emscall
7712
	and ah,ah
7713
	jnz echk2
7714
	ret
7715
echk2:
7716
	mov si,offset emsnot
7717
	jmp ems_err3
7718
emschk endp
7719

7720
;--- HNDLSHOW - Print XS line giving the handle and pages allocated.
7721
;
7722
;--- Entry   DX Handle
7723
;            AX Number of pages
7724
;
7725
;    Exit    Line printed
7726
;
7727
;    Uses    ax,cl,di.
7728

7729
hndlshow proc
7730
	mov di,offset xsstr1b
7731
	call hexword
7732
	mov ax,dx
7733
	mov di,offset xsstr1a
7734
	call hexword
7735
	push dx
7736
	mov dx,offset xsstr1
7737
	mov cx,size_xsstr1
7738
	call stdout
7739
	pop dx
7740
	ret
7741
hndlshow endp
7742

7743
;--- SUMSHOW - Print summary line for XS command.
7744
;
7745
;---Entry    AX Number of xxxx's that have been used
7746
;            DX Total number of xxxx's
7747
;            BX Name of xxxx
7748
;
7749
;   Exit     String printed
7750
;
7751
;   Uses     AX, CX, DX, DI
7752

7753
sumshow proc
7754
	mov di,offset line_out
7755
	call trimhex			; ax ( skip leading zeros )
7756
	mov si,offset xsstr3	; " of a total "
7757
	call copystring
7758
	xchg ax,dx				; mov ax,dx
7759
	call trimhex
7760
	mov si,offset xsstr3a	; " EMS "
7761
	call copystring
7762
	mov si,bx				; "pag"/"handl"
7763
	call copystring
7764
	mov si,offset xsstr3b	; "es have been allocated"
7765
	call copystring
7766
	jmp putsline
7767

7768
sumshow endp
7769

7770
;   TRIMHEX - Print word without leading zeroes.
7771
;
7772
;   Entry    AX Number to print
7773
;            DI Where to print it
7774
;
7775
;   Uses     AX, CX, DI.
7776

7777
trimhex proc
7778
	call hexword
7779
	push di
7780
	sub di,4		;back up DI to start of word
7781
	mov cx,3
7782
	mov al,'0'
7783
@@:
7784
	scasb
7785
	jne @F			;return if not a '0'
7786
	mov byte ptr [di-1],' '
7787
	loop @B
7788
@@:
7789
	pop di
7790
	ret
7791
trimhex endp
7792

7793
endif
7794

7795
;--- syntax error handler.
7796
;--- in: SI->current char in line_in
7797

7798
cmd_error proc
7799
	mov cx,si
7800
	sub cx,offset line_in+4
7801
	add cx,[promptlen]
7802
	mov di,offset line_out
7803
	mov dx,di
7804
	cmp cx,127
7805
	ja @F			;if we're really messed up
7806
	inc cx			;number of spaces to skip
7807
	mov al,' '
7808
	rep stosb
7809
@@:
7810
	mov si,offset errcarat
7811
	mov cl,sizeof errcarat
7812
	rep movsb
7813
	call putsline	;print string
7814
	jmp [errret]
7815
cmd_error endp
7816

7817
if LCMDFILE
7818

7819
;--- FREEMEM - cancel child process
7820

7821
freemem proc
7822

7823
;	@dprintf "freemem enter"
7824
	mov [regs.rCS],cs
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 )
7827
 if ?DPMI
7828
	xor ax,ax
7829
	mov [regs.rIP+2],ax
7830
	mov [regs.rSP+2],ax
7831
 endif
7832
	mov [regs.rSS],ss
7833
	push ax
7834
	mov [regs.rSP],sp	; save sp-2
7835
	pop ax
7836
	call run
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
7840
	ret
7841
fmem2:
7842
 if ?DPMI
7843
	mov ax,4cffh
7844
 else
7845
	mov ax,4c00h	;quit
7846
 endif
7847
	int 21h
7848
freemem endp
7849

7850
 if INT2324
7851

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().
7856

7857
setint2324 proc
7858
	mov si,offset run2324
7859
  if ?DPMI
7860
	call ispm_dbg
7861
	jnz si2324pm
7862
  endif
7863
	push es
7864

7865
	xor di,di
7866
	mov es, di
7867
	mov di,23h*4
7868
	movsw
7869
	movsw
7870
	movsw
7871
	movsw
7872

7873
  if ?DPMI
7874
	call InDos
7875
	jnz @F
7876
	call hook2f
7877
@@:
7878
  endif
7879

7880
	pop es
7881
	ret
7882
  if ?DPMI
7883
si2324pm:
7884
	mov bx,0223h
7885
@@:
7886
	sizeprf		;mov edx,[si+0]
7887
	mov dx,[si+0]
7888
	mov cx,[si+4]
7889
	mov ax,205h
7890
	int 31h
7891
	add si,6
7892
	inc bl
7893
	dec bh
7894
	jnz @B
7895
	ret
7896
  endif
7897
setint2324 endp
7898

7899
 endif	; INT2324
7900

7901
endif	; LCMDFILE
7902

7903
if RING0
7904
	.386
7905
checksegm proc
7906
	lar ax, [regs.rCS]
7907
	jnz error
7908
	test ah, 8
7909
	jz error
7910
	lar ax, [regs.rSS]
7911
	jnz error
7912
	test ah, 8
7913
	jnz error
7914

7915
	mov cx, 4
7916
	mov si, offset regs.rDS
7917
nextitem:
7918
	lodsw
7919
	and ax, 0fffch
7920
	jz @F
7921
	lar ax, ax
7922
	jnz error
7923
@@:
7924
	loop nextitem
7925
	ret
7926
error:
7927
	stc
7928
	ret
7929
checksegm endp
7930

7931
endif
7932

7933
if USEHWBP
7934

7935
WPENABLE equ 1	;local wp enable
7936
;WPENABLE equ 2	;global wp enable
7937

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
7947
;--- bit 8-9: LE,GE
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 )
7951

7952
;--- map (hard) breakpoints to debug registers
7953
;--- entry will be patched to NOP NOP if hw bp enabled!
7954

7955
setHWBps proc
7956
	clc
7957
	ret
7958
if ?DPMI
7959
	mov bp, offset pmsethwbp
7960
	call ispm_dbg
7961
	jnz @F
7962
endif
7963
	mov bp, [wRMSetBP]
7964
@@:
7965
	xor cx, cx
7966
	mov si, offset HWBps
7967
	.386
7968
nextbp:
7969
	lodsd
7970
	xchg eax, edx
7971
	lodsb
7972
	test al, BP_USED
7973
	jz skipbp
7974
	@dprintf "setHWBps %lX", edx
7975
	xchg eax, edx
7976
	push cx
7977
	call bp
7978
	pop cx
7979
	jc error
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)
7982
skipbp:
7983
 if ?DPMI
7984
	lodsw
7985
 endif
7986
	inc cx
7987
	cmp cl, MAXHWBP
7988
	jnz nextbp
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
7992
	ret
7993
error:
7994
	call resetHWBps
7995
	stc
7996
	ret
7997
if ?DPMI
7998
pmsethwbp: 
7999
	push eax
8000
	pop cx
8001
	pop bx
8002
	mov dh, dl
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
8008
	int 31h
8009
	jc @F
8010
	mov [si], bx
8011
	@dprintf "pmsethwbp hdl=%X", bx
8012
	mov ax, 0b03h	; clear status in dr6
8013
	int 31h
8014
@@:
8015
	retn
8016
endif
8017

8018
if 1; it's used both in ring0 and real-mode
8019

8020
r0sethwbp::
8021
	call setdrreg
8022
	mov eax, dr6
8023
	btr ax, bx
8024
	mov dr6, eax
8025
	mov eax, dr7
8026
	and edx, 0fh	; type in bits 0-3
8027
	mov ebx, 0fffffff0h
8028
	push cx
8029
	shl cl, 2
8030
	add cl, 16		; cl = 16|20|24 for bp0|1|2
8031
	shl edx, cl
8032
	rol ebx, cl
8033
	pop cx
8034
	and eax, ebx
8035
	or eax, edx		; set type (RW0, LEN0 )
8036
	mov bl, WPENABLE
8037
	shl bl, cl
8038
	shl bl, cl
8039
	or al, bl		; set G|L0|1|2=1
8040
	or ah, WPENABLE	; set G|LE=1 ("legacy")
8041
	mov dr7, eax
8042
  ifdef _DEBUG
8043
	mov ebx, dr6
8044
	@dprintf "r0sethwbp dr7=%lX dr6=%lX", eax, ebx
8045
  endif
8046
	retn
8047
setdrreg::
8048
	movzx bx, cl
8049
	shl bx, 2
8050
	add bx, offset setdrx
8051
	jmp bx
8052
setdrx:
8053
	mov dr0, eax
8054
	retn
8055
	mov dr1, eax
8056
	retn
8057
	mov dr2, eax
8058
	retn
8059
	mov dr3, eax
8060
	retn
8061
endif
8062
setHWBps endp
8063

8064
;--- unmap (hard) breakpoints from debug registers
8065
;--- entry will be patched to NOP if hw bp enabled!
8066

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
8073
;--- emitted.
8074

8075
resetHWBps proc
8076
	ret
8077
	mov [bBPhit], 0
8078
if ?DPMI
8079
	mov bp, offset pmresethwbp
8080
	call ispm_dbg
8081
	jnz @F			; skip if in real/v86-mode
8082
endif
8083
	mov bp, [wRMResetBP]
8084
@@:
8085
	xor cx, cx
8086
	mov dl, not 11b
8087
	mov si, offset HWBps
8088
nextbp:
8089
	lodsd
8090
	lodsb
8091
	test al, BP_ACTIVE
8092
	jz skipbp
8093
	and al, not BP_ACTIVE
8094
	test al, BP_TEMP
8095
	jz @F
8096
	mov al, 0
8097
@@:
8098
	and [si-1], al
8099
	call bp
8100
skipbp:
8101
 if ?DPMI
8102
	lodsw
8103
 endif
8104
	rol dl, 2
8105
	inc cx
8106
	cmp cl, MAXHWBP
8107
	jb nextbp
8108
	ret
8109

8110
 if ?DPMI
8111
pmresethwbp:
8112
	mov bx, [si]
8113
	mov ax, 0b02h	; get status
8114
	int 31h
8115
	add [bBPhit], al
8116
	mov ax, 0b01h	; clear watchpoint
8117
	int 31h
8118
	@dprintf "pmresetHWBps hdl=%X", bx
8119
	retn
8120
 endif
8121
r0resethwbp::
8122
	xor eax, eax
8123
	call setdrreg
8124
	mov eax, dr7
8125
	and al, dl		; disable G0|1|2
8126
	mov dr7, eax
8127
  if 1
8128
	mov eax, dr6
8129
	btr ax, cx		; clear bit in DR6
8130
	adc [bBPhit],ch
8131
	mov dr6, eax
8132
  endif
8133
	@dprintf "r0resethwbp bp#=%X", cx
8134
	retn
8135
resetHWBps endp
8136

8137
	.8086
8138

8139
endif ; USEHWBP
8140

8141
;--- This is the routine that starts up the running program.
8142

8143
run proc
8144

8145
if RING0
8146
;--- check segment values, since there's no stack switch if a GPF occurs.
8147
 if V86M
8148
	test byte ptr [regs.rFL+2], 2	;v86-mode?
8149
	jnz @F
8150
 endif
8151
	call checksegm
8152
	mov dx, offset segerr
8153
	jc int21ah9
8154
@@:
8155
endif
8156

8157
if USEHWBP
8158
	call setHWBps
8159
	mov dx, offset cantwritebp
8160
	jc int21ah9
8161
endif
8162

8163
if RING0
8164
	mov al, 0
8165
	call srscratch	; restore scratch GDT entry
8166
endif
8167

8168
	call seteq		;set CS:E/IP to '=' address
8169

8170
;--- set debuggee context
8171
if VXCHG
8172
	mov al, 0       ;restore debuggee screen
8173
	call swapscreen
8174
endif
8175
if ALTVID
8176
	call setscreen
8177
endif
8178
if LCMDFILE
8179
	mov bx,[pspdbe]
8180
	call setpsp		;set debuggee's PSP
8181
 if INT2324
8182
	call setint2324	;set debuggee's int 23/24
8183
 endif
8184
endif
8185
if ?DPMI
8186
	call setdbeexc0d0e
8187
endif
8188

8189
if FLATSS
8190
	.386
8191
	mov [run_sp],esp	;save stack position
8192
else
8193
	mov [run_sp],sp		;save stack position
8194
endif
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.
8199
 if FMTEXE
8200
	mov cx, ds
8201
	@ds_mypsp
8202
 endif
8203
	mov ax,ss
8204
	cmp ax,word ptr ds:[PSPS.SPSAV+2]
8205
	jnz @F
8206
	sub sp,[spadjust]
8207
	mov word ptr ds:[PSPS.SPSAV],sp
8208
@@:
8209
 if FMTEXE
8210
	mov ds, cx
8211
 endif
8212
endif
8213
ife RING0
8214
	cli
8215
endif
8216
if FLATSS
8217
	push ds
8218
	pop ss
8219
endif
8220
if RING0
8221
	@dprintf "r0 ss:esp=%X:%lX efl=%lX", word ptr [regs.r0SSEsp+4], dword ptr [regs.r0SSEsp], dword ptr [regs.rFL]
8222
endif
8223
	mov sp,offset regs
8224
ife RING0
8225
	cmp [machine],3
8226
	jb @F
8227
	.386
8228
	popad
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
8231
	pop fs
8232
	pop gs
8233
	jmp loadss
8234
	.8086
8235
@@:
8236
	pop di
8237
	pop si	;skip hi edi
8238
	pop si
8239
	pop bp	;skip hi esi
8240
	pop bp
8241
	add sp,6;skip hi ebp+reserved
8242
	pop bx
8243
	pop dx	;skip hi ebx
8244
	pop dx
8245
	pop cx	;skip hi edx
8246
	pop cx
8247
	pop ax	;skip hi ecx
8248
	pop ax
8249
	add sp,2;skip hi eax
8250
	pop es	; that's DS
8251
	pop es
8252
	add sp,2*2	; skip places for FS,GS
8253
else
8254
	.386
8255
 if 0;LMODE
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
8258
	mov ax, fs
8259
	cmp ax, [regs.rFS]
8260
	jz @F
8261
	mov fs, [regs.rFS]
8262
@@:
8263
	mov ax, gs
8264
	cmp ax, [regs.rGS]
8265
	jz @F
8266
	mov gs, [regs.rGS]
8267
@@:
8268
 endif
8269
 if V86M
8270
	test byte ptr [regs.rFL+2], 2
8271
	jz @F
8272
	popad
8273
	lss esp, [regs.r0SSEsp]
8274
	mov [bInDbg],0
8275
	push 0
8276
	push [regs.rGS]
8277
	push 0
8278
	push [regs.rFS]
8279
	push 0
8280
	push [regs.rDS]
8281
	push 0
8282
	push [regs.rES]
8283
	push 0
8284
	push [regs.rSS]
8285
	push dword ptr [regs.rSP]
8286
	push dword ptr [regs.rFL]
8287
	push 0
8288
	push [regs.rCS]
8289
	push dword ptr [regs.rIP]
8290
	iretd
8291
@@:
8292
 endif
8293
	lar ax, [regs.rCS]
8294
	and ah, 60h
8295
	popad
8296
	pop es
8297
	pop es
8298
 if 0;LMODE
8299
	lea sp,[esp+2+2]
8300
 else
8301
	pop fs
8302
	pop gs
8303
 endif
8304
	jz @F
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]
8308
	jmp r0exit
8309
@@:
8310
endif
8311
loadss:
8312
	pop ss
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
8316
r0exit:
8317
	sizeprf				;push dword ptr [regs.rFL]
8318
	push [regs.rFL]
8319
	sizeprf				;push dword ptr [regs.rCS]
8320
	push [regs.rCS]
8321
	sizeprf				;push dword ptr [regs.rIP]
8322
	push [regs.rIP]
8323
	mov [bInDbg],0
8324
if RING0
8325
	mov ds,[regs.rDS]
8326
else
8327
	test byte ptr [regs.rFL+1],2	;IF set?
8328
	mov ds,[regs.rDS]
8329
	jz @F
8330
	sti					; required for ring3 protected mode if IOPL==0
8331
@@:
8332
patch_iret label byte	; patch with CFh (=IRET) if cpu < 386
8333
endif
8334
	.386
8335
	iretd				; jump to program
8336
	.8086
8337
run endp
8338

8339
;--- debugger entries
8340

8341
if RING0
8342
 if LMODE
8343
	include <TRAPPL.INC>
8344
 elseif V86M
8345
	include <TRAPPV.INC>
8346
 else
8347
	include <TRAPP.INC>
8348
 endif
8349
else
8350
	include <TRAPR.INC>
8351
endif
8352

8353
;--- fall thru
8354
;--- also: entry DPMI protected-mode
8355
;--- in: SS:SP=regs.rSS
8356

8357
intrtn proc
8358

8359
;--- DWORD pushs are safe here
8360

8361
	cmp cs:[machine],3
8362
	jb @F
8363
	.386
8364
ife RING0
8365
	pushfd
8366
	popf		;skip LoWord(EFL)
8367
	pop word ptr ss:[regs.rFL+2]
8368
endif
8369
	push 0
8370
	pushf
8371
	popfd		;clear HiWord(EFL) inside debugger (resets AC flag)
8372
	push gs
8373
	push fs
8374
	push es
8375
	push ds
8376
	pushad
8377
	jmp intrtn1
8378
	.8086
8379
@@:
8380
	sub sp, 2*2	; skip space for GS, FS
8381
	push es
8382
	push ds
8383
	push ax
8384
	push ax
8385
	push cx
8386
	push cx
8387
	push dx
8388
	push dx
8389
	push bx
8390
	push bx
8391
	sub sp,6
8392
	push bp
8393
	push si
8394
	push si
8395
	push di
8396
	push di
8397
intrtn1::		;<--- entry for int 22
8398
if RING0
8399
	.386
8400
 if FLATSS
8401
	mov ss, cs:[wFlat]
8402
	mov esp, cs:[run_sp]	;restore running stack
8403
 else
8404
	movzx esp,cs:[run_sp]	;restore running stack
8405
 endif
8406
else
8407
	mov sp,cs:[run_sp]	;restore running stack
8408
endif
8409
	cld
8410
	@RestoreSeg ds
8411
ife RING0
8412
	sti					;interrupts back on
8413
endif
8414

8415
;if ?PM
8416
 if ?DPMI
8417
;--- calling int 2Fh here is a problem, since breakpoints aren't reset yet.
8418
;--- this makes it impossible to trace this interrupt.
8419
  if 0;DPMIMSW
8420
	mov ax,1686h	; actually, fn 1686h tells if int 31h API is available
8421
	int 2Fh
8422
	cmp ax,1
8423
	sbb ax,ax
8424
  else
8425
	mov ax,cs		;v2.50: adjusted so it works for both .COM and .EXE formats
8426
	mov dx,ds
8427
	sub ax,dx		;Z=rm,NZ=pm
8428
	cmp ax,1		;C=rm,NC=pm
8429
	cmc             ;NC=rm,C=pm
8430
	sbb ax,ax		;0=rm,-1=pm
8431
  endif
8432
	mov [regs.msw],ax	;0000=real-mode, FFFF=protected-mode
8433
 endif
8434
;endif
8435

8436
ife (BOOTDBG or RING0)
8437
	call getpsp
8438
	mov  [pspdbe],bx
8439
endif
8440

8441
	push ds
8442
	pop es
8443
	mov [bInDbg],1		; v2.0: must be set before setdbgexc0d0e
8444

8445
;--- set debugger context
8446

8447
if INT2324
8448
	call getint2324		;save debuggee's int 23/24, set debugger's int 23/24
8449
endif
8450
if ?DPMI
8451
	call setdbgexc0d0e
8452
endif
8453
if RING0
8454
	cmp [run_int], EXC0EMSG
8455
	jnz @F
8456
	call rendercr2		; add value of CR2 to msg
8457
@@:
8458
	mov al, 1
8459
	call srscratch		;save GDT scratch entry
8460
endif
8461

8462
if USEHWBP
8463
	call resetHWBps
8464
endif
8465

8466
if LCMDFILE
8467
	call setpspdbg		;set debugger's PSP
8468
endif
8469
	and byte ptr [regs.rFL+1],not 1	;clear single-step interrupt
8470

8471
;	mov [bInDbg],1		; v2.0: do this earlier ( see above )
8472
if INT22
8473
	cmp [run_int], INT22MSG
8474
	jnz @F
8475
 if ?DPMI
8476
	mov [cssel],0		;reset flag 'initial switch has occured'
8477
 endif
8478
	mov ah,4Dh
8479
	int 21h
8480
	mov di,offset progexit
8481
	call hexword
8482
@@:
8483
endif
8484
ifdef FORCETEXT
8485
	call checkgfx		; see if current mode is gfx, set to text if yet
8486
endif
8487
if VXCHG
8488
	mov al, 1           ; restore debugger screen
8489
	call swapscreen
8490
 ifndef VXCHGFLIP
8491
	push es
8492
	mov ax, 0040h
8493
	mov es, ax
8494
	mov al, es:[84h]    ; did the number of screen rows change?
8495
	mov bh, es:[62h]    ; BH=video page
8496
	mov [vpage], bh
8497
	cmp al, [vrows]
8498
	mov [vrows], al
8499
	jz @F
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
8503
	int 10h
8504
	mov bl, 07h         ; BL=attribute, BH=video page
8505
	mov cx, 80          ; CX=columns
8506
	mov ax, 0920h       ; AL=char to display
8507
	int 10h
8508
@@:
8509
	pop es
8510
 else
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!
8515
    mov [vpage], 1
8516
 endif
8517
endif
8518
if ALTVID
8519
	call setscreen
8520
endif
8521
	@dprintf "debug entered"
8522
	ret
8523

8524
ifdef FORCETEXT
8525
checkgfx:
8526
	mov dx, 3CEh 			; see if in graphics mode
8527
	in al, dx
8528
	mov bl, al
8529
	mov al, 6
8530
	out dx, al
8531
	inc dx
8532
	in al, dx
8533
	xchg bl, al
8534
	dec dx
8535
	out dx, al
8536
	test bl, 1
8537
	jz @F
8538
	mov ax, 0003h
8539
	int 10h
8540
@@:
8541
	retn
8542
endif
8543
intrtn endp
8544

8545
if USEHWBP
8546

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.
8551
;--- modifies DI!
8552

8553
	.386
8554

8555
sethwbptmp proc
8556
	push di
8557
	push edx
8558
	call findfreehwbp
8559
	pop edx
8560
	jc @F
8561
	add eax, edx
8562
	@dprintf "sethwbptmp: linear=%lX (cs:eip=%X:%lX)", eax, bx, edx
8563
	stosd
8564
	mov al, BP_CODE or BP_USED or BP_TEMP
8565
	stosb
8566
@@:
8567
	pop di
8568
	ret
8569
sethwbptmp endp
8570

8571
;--- find a free place in hw bp table
8572
;--- bx=segment/selector
8573
;--- out: C if error
8574
;---     NC ok, then
8575
;---     EAX= bx base
8576
;---     DI = free entry in hw bp table
8577

8578
	.386
8579

8580
findfreehwbp proc
8581
	mov di, offset HWBps
8582
	mov cx, MAXHWBP
8583
@@:
8584
	test [di].HWBPSTRUCT.bType, BP_USED
8585
	jz @F
8586
	add di, sizeof HWBPSTRUCT
8587
	loop @B
8588
	stc
8589
	ret
8590
@@:
8591
 if RING0
8592
	call getlinearbaseDT	; eax=base of descriptor table for BX
8593
	jc @F
8594
	call getlinearbaseBX	; eax=base of BX
8595
@@:
8596
 else
8597
  if ?DPMI
8598
	call ispm_dbg		; in protected-mode?
8599
	jz rmbase
8600
	mov ax, 6
8601
	int 31h
8602
	jc @F				; can't get base of BX
8603
	push cx
8604
	push dx
8605
	pop eax
8606
@@:
8607
	ret
8608
rmbase:
8609
  endif
8610
	movzx eax, bx
8611
	shl eax, 4
8612
v86patch::
8613
	nop
8614
 endif
8615
	ret
8616
findfreehwbp endp
8617
	
8618
	.8086
8619

8620
endif
8621

8622
if BCMD
8623

8624
CONST segment
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,'$'
8628
CONST ends
8629

8630
;--- handle BP/BC cmds.
8631
;--- this code will only run if cpu is 80386+.
8632

8633
	.386
8634

8635
b_cmd proc
8636
	cmp ah, 'b'
8637
	jnz b_err
8638
	or al, TOLOWER
8639
	cmp al, 'c'     ; is it BC?
8640
	jz bc_cmd
8641
	cmp al, 'p'     ; or BP?
8642
	jz bp_cmd
8643
b_err:
8644
	jmp cmd_error   ; anything else is unknown
8645
bc_cmd:
8646
	call skipwhite
8647
	cmp al,CR       ; no argument given? then just display status...
8648
	jz b_err
8649
	call getbyte	; get byte into DL
8650
	call chkeol
8651
	movzx ax, dl
8652
	cmp al, MAXHWBP
8653
	jnb b_err
8654
	imul ax, sizeof HWBPSTRUCT
8655
	mov bx, ax
8656
	mov al, 0
8657
	xchg al,[bx][HWBps].bType
8658
	test al, BP_USED
8659
	mov dx, offset bp_not_set
8660
	jz b_errmsg
8661
	ret
8662
bp_cmd:
8663
	call skipwhite
8664
	cmp al,CR       ; no argument given? then just display status...
8665
	jz bp_disp
8666
	@movs bx,[regs.rCS];default segment to use
8667
	call getaddr	; get address into bx:e/dx
8668
	call skipwh0
8669
	push edx
8670
	mov dl, 0		; default type: 0=exec (1=write,2=io,3=rw)
8671
	cmp al,CR       ; second argument (=type) given?
8672
	jz @F
8673
	call getbyte	; get byte into DL
8674
	call chkeol
8675
@@:
8676
	push dx
8677
	call findfreehwbp
8678
	pop dx		; restore type
8679
	pop ecx		; get offset
8680
	jc @F
8681
	add eax, ecx
8682
	stosd
8683
	mov al, dl
8684
	and al, 30h
8685
	and dl, 03h
8686
	shr al, 2
8687
	or  al, dl
8688
	and al, 0fh		; real type is 4 bits only
8689
	or al, BP_USED
8690
	stosb
8691
	ret
8692
@@:
8693
	mov dx, offset no_free_bp
8694
b_errmsg:
8695
	jmp int21ah9
8696
b_cmderr::
8697
	mov dx, offset b_inactive
8698
	jmp b_errmsg
8699

8700
bp_disp:
8701
	mov si, offset HWBps
8702
	xor cx, cx
8703
nextbp:
8704
	lodsd
8705
	xchg edx, eax
8706
	lodsb
8707
	@dprintf "bp: cx=%X, edx=%lX, al=%X", cx, edx, ax
8708
	test al, BP_USED
8709
	jz skipbp
8710
	mov di, offset line_out
8711
	push cx
8712
	push ax
8713
	mov ax,"pB"
8714
	stosw
8715
	mov al, cl
8716
	add al, '0'
8717
	mov ah, ':'
8718
	stosw
8719
	mov eax, edx
8720
	call hexdword
8721
	mov al, ' '
8722
	stosb
8723
	pop ax
8724
	mov ah, al
8725
	shl ah, 2
8726
	and al, 3
8727
	and ah, 30h
8728
	or al, ah
8729
	call hexbyte
8730
	call putsline
8731
	pop cx
8732
skipbp:
8733
if ?DPMI
8734
	lodsw
8735
endif
8736
	inc cx
8737
	cmp cl, MAXHWBP
8738
	jnz nextbp
8739
	ret
8740
b_cmd endp
8741

8742
	.8086
8743

8744
endif
8745

8746
if VXCMD
8747

8748
	.386
8749

8750
CONST segment
8751
notrappedexc db "No exc to (un)trap",13,10,'$'
8752
CONST ends
8753

8754
getexc proc
8755
	call skipwhite
8756
	call getbyte		; get byte into DL
8757
	call chkeol			; expect end of line here
8758
	mov si, offset exctab
8759
	mov cx, SIZEEXCTAB
8760
nextitem:
8761
	lodsb
8762
	cmp al, dl
8763
	loopnz nextitem
8764
	jz @F
8765
	pop ax
8766
	mov dx, offset notrappedexc
8767
	jmp int21ah9
8768
@@:
8769
	mov dh, 0
8770
	ret
8771
getexc endp
8772

8773
;--- clear trapped vector: VC exc#
8774

8775
vc_cmd proc
8776
	call getexc
8777
	btr [wTrappedExc], dx
8778
	ret
8779
vc_cmd endp
8780

8781
;--- trap vector: VT exc#
8782

8783
vt_cmd proc
8784
	call getexc
8785
	bts [wTrappedExc], dx
8786
	ret
8787
vt_cmd endp
8788

8789
;--- list trapped vectors: VL
8790

8791
vl_cmd proc
8792
	call skipwhite
8793
	call chkeol			; expect end of line here
8794
	mov si, offset exctab
8795
	mov bx, offset intsave
8796
	mov cx, SIZEEXCTAB
8797
nextitem:
8798
	mov di, offset line_out
8799
	push cx
8800
	lodsb
8801
	movzx dx, al
8802
	call hexbyte
8803
	mov al, ' '
8804
	stosb
8805
	mov ax, [bx+4]
8806
	call hexword
8807
	mov al, ':'
8808
	stosb
8809
	mov eax, [bx+0]
8810
	call hexdword
8811
	bt [wTrappedExc], dx
8812
	jc @F
8813
	mov al,'*'
8814
	stosb
8815
@@:
8816
	call putsline
8817
	pop cx
8818
	add bx, sizeof INTVEC
8819
	loop nextitem
8820
	ret
8821
vl_cmd endp
8822

8823
	.8086
8824

8825
endif
8826

8827
if VXCHG
8828

8829
;--- show debuggee screen, wait for a keypress, then restore debugger screen
8830

8831
v_cmd proc
8832
 if VXCMD
8833
 	cmp ah, 'v'
8834
	jnz @F
8835
	or al, TOLOWER
8836
	cmp al, 'c'
8837
	jz vc_cmd
8838
	cmp al, 'l'
8839
	jz vl_cmd
8840
	cmp al, 't'
8841
	jz vt_cmd
8842
@@:
8843
 endif
8844
	cmp al,CR
8845
	jnz cmd_error
8846
	mov al,0
8847
	call swapscreen
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)
8852
	int 10h
8853
	mov ah, 3          ; get cursor pos of page in BH
8854
	int 10h
8855
	mov ah, 2          ; set cursor pos of page in BH
8856
	int 10h
8857
 endif
8858
	mov ah, 10h
8859
if RING0
8860
	.386
8861
	call cs:[int16vec]
8862
	.8086
8863
else
8864
	int 16h
8865
endif
8866
	mov al, 1
8867
	call swapscreen
8868
	ret
8869
v_cmd endp
8870

8871
;--- AL=0: save debugger screen, restore debuggee screen
8872
;--- AL=1: save debuggee screen, restore debugger screen
8873

8874
swapscreen proc
8875
 ifndef VXCHGFLIP
8876
	.errnz BOOTDBG or RING0,<v cmd with XMS swap not supported>
8877
	mov si, offset xmsmove
8878
	cmp [si].XMSM.dsthdl,0
8879
	jz done
8880
	.286
8881
	shl ax, 14      ; 0->0000, 1 -> 4000h
8882
	mov word ptr [si].XMSM.dstadr, ax
8883

8884
;--- use offset & size of current video page as src/dst for
8885
;--- xms block move. Also toggle cursor pos debuggee/debugger.
8886

8887
	push 0040h  ; 0040h is used because it also works in protected-mode
8888
	pop es
8889
	mov ax, es:[4Ch]
8890
	mov word ptr [si].XMSM.size_, ax
8891
	mov ax, es:[4Eh]
8892
	mov word ptr [si].XMSM.srcadr+0, ax
8893

8894
;--- get/set cursor pos manually for speed reasons.
8895
	mov bl, es:[62h]
8896
	mov bh, 0
8897
	shl bx, 1
8898
	mov dx, es:[bx+50h]  ; get cursor pos of current page
8899
	xchg dx, [csrpos]
8900
if 0
8901
	mov es:[bx+50h], dx
8902
else
8903
	mov bh, es:[62h]
8904
	mov ah, 2
8905
	int 10h
8906
endif
8907

8908
	push ds
8909
	pop es
8910

8911
	mov ah,0Bh           ; save video screen to xms
8912
	call runxms
8913
	call swapsrcdst
8914

8915
	xor byte ptr [si].XMSM.srcadr+1, 40h
8916

8917
	mov ah,0Bh           ; restore video screen from xms
8918
	call runxms
8919
	call swapsrcdst
8920
 else
8921
    mov ah, 05h          ; just use BIOS to activate video page
8922
  if RING0
8923
	.386
8924
	call cs:[int10vec]
8925
	.8086
8926
  else
8927
	int 10h
8928
  endif
8929
 endif
8930
done:
8931
	ret
8932

8933
 ifndef VXCHGFLIP
8934
	.8086
8935
swapsrcdst:
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
8945
	ret
8946
runxms:
8947
  if ?DPMI
8948
	call ispm_dbg
8949
	jnz @F
8950
  endif
8951
	call [xmsdrv]
8952
	ret
8953
  if ?DPMI
8954
@@:
8955
	.286
8956
	xor cx, cx
8957
	push cx          ; ss:sp
8958
	push cx
8959
	push word ptr [xmsdrv+2]    ; cs
8960
	push word ptr [xmsdrv+0]    ; ip
8961
	push cx          ; fs,gs
8962
	push cx
8963
	push [wDgroup]   ; ds
8964
	push 0           ; es
8965
	pushf
8966
	sub sp, 8*4
8967
	sizeprf        ;mov edi, esp
8968
	mov di, sp
8969
	mov es:[di].RMCS.rSI, si
8970
	mov es:[di].RMCS.rAX, ax
8971
	mov bh, 0
8972
	mov ax,301h
8973
	int 31h
8974
	add sp, sizeof RMCS
8975
	.8086
8976
	ret
8977
  endif
8978
 endif
8979
swapscreen endp
8980

8981
elseif VXCMD
8982
v_cmd proc
8983
	cmp ah, 'v'
8984
	jnz @F
8985
	or al, TOLOWER
8986
	@dprintf "v_cmd: ax=%X", ax
8987
	cmp al, 'c'
8988
	jz vc_cmd
8989
	cmp al, 'l'
8990
	jz vl_cmd
8991
	cmp al, 't'
8992
	jz vt_cmd
8993
@@:
8994
	jmp cmd_error
8995
v_cmd endp
8996
endif
8997

8998
if ALTVID
8999

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. 
9003

9004
setscreen proc
9005
	ret	;will be patched to "push ds" if "/2" cmdline switch and second adapter exists
9006
	mov dx, [oldcrtp]
9007
	mov bx, [oldcols]
9008
	mov ax, [oldmr]
9009
	mov cx, 0040h         ; 0040h is supposed to work in both rm/pm
9010
	mov ds, cx
9011
	mov cx, cs:[oldcsrpos]
9012
	and byte ptr ds:[10h], not 30h
9013
	cmp dl, 0b4h
9014
	jnz @F
9015
	or  byte ptr ds:[10h], 30h
9016
@@:
9017
	xchg bx,ds:[4Ah]
9018
	xchg cx,ds:[50h]
9019
	xchg dx,ds:[63h]
9020
	xchg al,ds:[49h]
9021
	xchg ah,ds:[84h]
9022
	pop ds
9023
	mov [oldcrtp], dx
9024
	mov [oldcsrpos], cx
9025
	mov [oldcols], bx
9026
	mov [oldmr], ax
9027
	ret
9028
setscreen endp
9029

9030
endif
9031

9032
if INT2324
9033

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]
9038
;--- DS, ES = DGROUP
9039
;--- Int 21h should not be used here!
9040

9041
getint2324 proc
9042
	mov di,offset run2324
9043
 if ?DPMI
9044
	call ispm_dbg
9045
	jnz getint2324pm
9046
 endif
9047

9048
	xor si,si
9049
	mov ds,si
9050
	mov si,23h*4
9051
	push si
9052
	movsw		;save interrupt vector 23h
9053
	movsw
9054
	movsw		;save interrupt vector 24h
9055
	movsw
9056
	pop di
9057
 if FMTEXE
9058
	mov ds,cs:[pspdbg]
9059
 else
9060
	push es
9061
	pop ds
9062
 endif
9063
	xor si,si
9064
	mov es, si
9065
	mov si,PSPS.CCIV	;move from debugger's PSP to IVT
9066
	movsw
9067
	movsw
9068
	movsw
9069
	movsw
9070
 if FMTEXE
9071
	push ss
9072
	pop ds
9073
 endif
9074
	push ds
9075
	pop es
9076
	ret
9077
 if ?DPMI
9078
getint2324pm:
9079
	mov bx, 0223h
9080
	mov si, offset dbg2324
9081
@@:
9082
	mov ax, 204h
9083
	int 31h
9084
	sizeprf		;mov [di+0],edx
9085
	mov [di+0], dx
9086
	mov [di+4], cx
9087

9088
	sizeprf		;xor edx, edx
9089
	xor dx, dx
9090
	lodsw
9091
	mov dx, ax
9092
	mov cx, cs
9093
	mov ax, 205h
9094
	int 31h
9095

9096
	add di, 6
9097
	inc bl
9098
	dec bh
9099
	jnz @B
9100
	ret
9101
	.8086
9102

9103
 endif
9104

9105
getint2324 endp
9106

9107
endif
9108

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.
9119

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.
9124

9125
;   PREPHACK - Set up for interrupt vector substitution.
9126
;   save current value of Int 23/24 (debugger's) to sav2324
9127
;   Entry   es = cs
9128

9129
prephack proc
9130
if INT2324
9131
	cmp [hakstat],0
9132
	jnz @F					;if hack status error
9133
	push di
9134
	mov di,offset sav2324	;debugger's Int2324
9135
	call store2324			;copy IVT 23/24 to di (real-mode only)
9136
	pop di
9137
	ret
9138
@@:                         ;this is actually a programming error!
9139
	push ax
9140
	push dx
9141
	mov dx,offset ph_msg	;'error in sequence of calls to hack'
9142
	call int21ah9			;print string
9143
	pop dx
9144
	pop ax
9145
endif
9146
	ret
9147

9148
prephack endp
9149

9150
if INT2324
9151

9152
CONST segment
9153
ph_msg	db 'Error in sequence of calls to hack.',CR,LF,'$'
9154
CONST ends
9155

9156
;--- get current int 23/24, store them at ES:DI
9157
;--- DI is either sav2324 (debugger's) or run2324 (debuggee's)
9158

9159
store2324 proc
9160
 if ?DPMI
9161
	call ispm_dbg
9162
	jnz _ret		;nothing to do if in PM
9163
 endif
9164
	push ds
9165
	push si
9166
	xor si,si
9167
	mov ds,si
9168
	mov si,4*23h
9169
	movsw
9170
	movsw
9171
	movsw
9172
	movsw
9173
	pop si
9174
	pop ds
9175
_ret:
9176
	ret
9177
store2324 endp
9178

9179
endif
9180

9181
;   DOHACK - set debuggee's int 23/24
9182
;   Entry   ds = dgroup
9183

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.
9186

9187
dohack proc
9188
if INT2324
9189
	mov [hakstat],1
9190
 if ?DPMI
9191
	call ispm_dbg	; v2.0: dohack is dummy in protected-mode
9192
	jnz _ret
9193
 endif
9194
	push si
9195
	mov si,offset run2324	;debuggee's interrupt vectors
9196
	jmp hak1
9197

9198
endif
9199

9200
;--- UNHACK - set debugger's int 23/24
9201
;--- Entry   ds = dgroup
9202

9203
unhack::
9204
if INT2324
9205
	mov [hakstat],0
9206
 if ?DPMI
9207
	call ispm_dbg
9208
	jnz _ret		; v2.0: unhack is dummy now
9209
 endif
9210
	push si
9211
	mov si,offset sav2324	;debugger's interrupt vectors
9212
hak1:
9213
	push di
9214
	push es
9215
	xor di,di
9216
	mov es, di
9217
	mov di,4*23h
9218
	movsw
9219
	movsw
9220
	movsw
9221
	movsw
9222
	pop es
9223
	pop di
9224
	pop si
9225
_ret:
9226
endif
9227
	ret
9228

9229
dohack endp
9230

9231
;--- InDos: return NZ if DOS cannot be used
9232

9233
InDos:
9234
if ( BOOTDBG or RING0 )
9235
	push ax
9236
	or al,-1
9237
	pop ax
9238
else
9239
	push ds
9240
	push si
9241
 if ?DPMI
9242
	call ispm_dbg
9243
	mov si,word ptr [pInDOS+0]
9244
	mov ds, [InDosSel]
9245
	jnz @F
9246
	mov ds, word ptr cs:[pInDOS+2]
9247
@@:
9248
 else
9249
	lds si,[pInDOS]
9250
 endif
9251
	cmp byte ptr [si],0
9252
	pop si
9253
	pop ds
9254
endif
9255
	ret
9256

9257
stdoutal:
9258
	push cx
9259
	push dx
9260
	push ax
9261
	mov cx,1
9262
if FLATSS
9263
	mov [bChar], al
9264
	mov dx, offset bChar
9265
else
9266
	mov dx,sp
9267
endif
9268
	call stdout
9269
	pop ax
9270
	pop dx
9271
	pop cx
9272
	ret
9273

9274
fullbsout:
9275
	mov al,8
9276
	call stdoutal
9277
	mov al,20h
9278
	call stdoutal
9279
	mov al,8
9280
	jmp stdoutal
9281

9282
;   GETLINE - Print a prompt (address in DX, length in CX) and read a line
9283
;   of input.
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)
9289
;
9290
;       DI  Address + 1 of last character in prompt (getline0 and
9291
;           getline00 only)
9292
;
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
9296

9297
getline0:
9298
	mov ax,'  '		;add two spaces and a colon
9299
	stosw
9300
	mov al,':'
9301
	stosb
9302
getline00:
9303
	mov dx,offset line_out
9304
	mov cx,di
9305
	sub cx,dx
9306

9307
getline proc
9308
	mov [promptlen],cx	;save length of prompt
9309
	call stdout ;write prompt (string DX, size CX)
9310
if REDIRECT
9311
	test [fStdin], AT_DEVICE
9312
	jnz gl5		;jmp if tty input
9313

9314
	mov [lastcmd], offset dmycmd
9315

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.
9320

9321
	call fillbuf
9322
	jc q_cmd
9323
	mov [bufnext], si
9324
	mov cx,[bufend]
9325
	mov dx,offset line_in + 2
9326
	sub cx,dx
9327
	call stdout	;print out the received line
9328
	jmp gl6		;done
9329
gl5:
9330
endif
9331

9332
;--- input a line if stdin is a device (tty)
9333
	mov dx,offset line_in
9334
	call InDos
9335
	jnz rawinput
9336
ife RING0
9337
	mov ah,0ah		;buffered keyboard input
9338
	call doscall
9339
endif
9340
gl6:
9341
	mov al,10
9342
	call stdoutal
9343
	mov si,offset line_in + 2
9344
	call skipwhite
9345
	ret
9346

9347
rawinput:
9348
	push di
9349
	push ds
9350
	pop es
9351
	inc dx
9352
	inc dx
9353
	mov di,dx
9354
rawnext:
9355
	mov ah,00h
9356
if RING0
9357
	.386
9358
	call cs:[int16vec]
9359
	.8086
9360
else
9361
	int 16h
9362
endif
9363
	cmp al,0
9364
	jz rawnext
9365
	cmp al,0E0h
9366
	jz rawnext
9367
	cmp al,08h
9368
	jz del_key
9369
	cmp al,7Fh
9370
	jz del_key
9371
	stosb
9372
if RING0
9373
	cmp al, 20h
9374
	jnc @F
9375
	cmp al, 0Dh
9376
	jz @F
9377
	cmp al, 08h
9378
	jz @F
9379
	push ax
9380
	mov al, '^'
9381
	call stdoutal
9382
	pop ax
9383
	or al, 40h
9384
@@:
9385
endif
9386
	call stdoutal
9387
	cmp al,0Dh
9388
	jnz rawnext
9389
	dec di
9390
	sub di,dx
9391
	mov ax,di
9392
	mov di,dx
9393
	mov byte ptr [di-1],al
9394
	dec dx
9395
	dec dx
9396
	pop di
9397
	jmp gl6
9398
del_key:
9399
	cmp di,dx
9400
	jz rawnext
9401
	dec di
9402
	call fullbsout
9403
	jmp rawnext
9404

9405
getline endp
9406

9407
if REDIRECT
9408

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)
9413
;   Uses    None.
9414

9415
fillbuf proc
9416
	push ax
9417
	push bx
9418
	push cx
9419
	push dx
9420
	mov si, offset line_in+2
9421
	push si
9422

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.
9426

9427
@@:
9428
	mov dx, si
9429
	cmp dx, offset line_in+LINE_IN_LEN ; "line too long" is treated as EOF
9430
	jz fb1
9431
	mov cx, 1
9432
	xor bx, bx
9433
	mov ah, 3fh	; read file
9434
	call doscall
9435
	jc fb1
9436
	and ax,ax
9437
	jz fb1		; if eof
9438
	mov al,[si]
9439
	inc si
9440
	cmp al,LF
9441
	jnz @B
9442
	dec si      ; the LF itself should NOT be handled by the cmds.
9443
	jmp fb2
9444
fb1:
9445
	stc
9446
fb2:
9447
	mov [bufend], si
9448
	pop si
9449
	pop dx
9450
	pop cx
9451
	pop bx
9452
	pop ax
9453
	ret
9454
fillbuf endp
9455

9456
endif
9457

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
9465

9466
parsecm proc
9467
	call prephack
9468
	xor cx,cx
9469
	call getrangeDS	;get address range into bx:(e)dx bx:(e)cx
9470
	push bx			;save segment first address ( src for m cmd )
9471
if ?PM
9472
	call IsOfs32
9473
	jz @F
9474
	.386
9475
	sub ecx,edx
9476
	push edx		;save offset first address
9477
	push ecx
9478
	jmp pc_01
9479
	.8086
9480
@@:
9481
endif
9482
	sub cx,dx		;number of bytes minus one
9483
if RING0 and V86M
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?
9489
	jz @F
9490
	cmp bx, [scratchsel]
9491
	jnz @F
9492
	pop bx
9493
	push [wFlat]
9494
	mov [bAddr32], 1
9495
	.386
9496
	movzx ebx, [scratchv86]
9497
	shl ebx, 4
9498
	movzx edx, dx
9499
	movzx ecx, cx
9500
	add edx, ebx
9501
	push edx
9502
	push ecx
9503
	jmp pc_01
9504
@@:
9505
endif
9506
	push dx
9507
	push cx
9508
pc_01:
9509
	call skipcomm0
9510

9511
;--- get the second ( destination ) address
9512

9513
	@movs bx,[regs.rDS]	; DS = default for "destination"
9514
if ?PM
9515
	call IsOfs32
9516
	jz pc_1
9517
	.386
9518
	call getaddr		;get address into bx:(e)dx
9519
	mov [bAddr32],1		;restore bAddr32
9520
	pop ecx
9521
	mov edi,ecx
9522
	add edi,edx
9523
	jc errorj7
9524
	call chkeol
9525
	mov edi,edx
9526
	mov es, bx
9527
	pop esi
9528
	pop ds
9529
	ret
9530
	.8086
9531
pc_1:
9532
endif
9533
	call getaddr	;get destination address into bx:(e)dx
9534
	pop cx
9535
	mov di,cx
9536
	add di,dx
9537
	jc errorj7		;if it wrapped around
9538
	call chkeol		;expect end of line
9539
	mov di,dx
9540
	mov es, bx
9541
	pop si
9542
	pop ds
9543
	ret
9544
parsecm endp
9545

9546
errorj7:
9547
	jmp cmd_error
9548

9549
if LCMD or WCMD
9550

9551
;   PARSELW - Parse command line for L and W commands.
9552
;
9553
;   Entry   AL  First nonwhite character of parameters
9554
;       SI  Address of the character after that
9555
;
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
9559
;
9560
;       If there are more arguments (absolute disk read/write), then the
9561
;       zero flag is clear, and registers are set as follows:
9562
;
9563
;       [usepacket] == 0:
9564
;       AL  Drive number
9565
;       CX  Number of sectors to read
9566
;       DX  Beginning logical sector number
9567
;       DS:BX   Transfer address
9568
;
9569
;       [usepacket] != 0:
9570
;       AL  Drive number
9571
;       BX  Offset of packet
9572
;       CX  0FFFFh
9573

9574
parselw proc
9575
	mov bx,[regs.rCS]	;default segment
9576
	mov dx,100h		;default offset
9577
	cmp al,CR
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
9582
if ?PM
9583
	call IsWriteableBX
9584
endif
9585
	call skipcomm0
9586
	cmp al,CR
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
9591
	neg dx
9592
	jz @F			;if address is zero
9593
	mov cl,9
9594
	shr dx,cl		;max number of sectors which can be read
9595
	mov di,dx
9596
@@:
9597
	call getbyte	;get drive number (DL)
9598
	call skipcomm0
9599
	push dx
9600
;	add dl,'A'
9601
	mov [driveno],dl
9602
	call getdword	;get relative sector number
9603
	call skipcomm0
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
9608
	dec dx
9609
	cmp dx,di
9610
	jae errorj7		;if too many sectors
9611
	inc dx
9612
	mov cx,dx
9613
	call chkeol		;expect end of line
9614
	cmp [usepacket],0
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 
9618
	pop bx			;get HiWord 
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
9625
plw2:
9626
	ret
9627

9628
;--- new style packet, [usepacket] != 0
9629

9630
plw3:
9631
	pop bx			;discard si
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
9638
	pop dx
9639
	xor cx,cx
9640
if ?PM
9641
	call ispm_dbg
9642
	jz @F
9643
 if ?DPMI
9644
	test [dpmi32],1
9645
	jz @F
9646
 endif
9647
	.386
9648
	mov [bx].PACKET32.dstseg,dx
9649
	movzx ebx,bx
9650
	shr edx,16		;get HiWord(offset)
9651
	cmp [bAddr32],1
9652
	jz @F
9653
	xor dx,dx
9654
	.8086
9655
@@:
9656
endif
9657
	mov [bx].PACKET.dstseg,dx	;PACKET.dstseg or HiWord(PACKET32.dstofs)
9658
	dec cx			;set nonzero flag and make cx = -1
9659
	ret
9660
parselw endp
9661

9662
endif
9663

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
9668
;   Uses    AH,BX,CX,DX.
9669

9670
parse_pt proc
9671
	call parseql	;get optional <=addr> argument
9672
	call skipcomm0	;skip any white space
9673
	mov cx,1		;default count
9674
	cmp al,CR
9675
	je @F			;if no count given
9676
	call getword
9677
	call chkeol		;expect end of line here
9678
	mov cx,dx
9679
	jcxz errorj10	;must be at least 1
9680
@@:
9681
;	call seteq		;make the = operand take effect
9682
	ret
9683
parse_pt endp
9684

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.
9693

9694
parseql proc
9695

9696
	mov bx,[regs.rCS]	;default segment
9697
	mov [eqflag],al
9698
	cmp al,'='
9699
	jne peq1		;if no '=' operand
9700
	call skipwhite
9701
if ?DPMI
9702
	sizeprf			;xor edx, edx
9703
	xor dx,dx
9704
endif
9705
if RING0 and V86M
9706
	@movs bx,[regs.rCS]
9707
endif
9708
	call getaddr	;get address into bx:(e)dx
9709
	sizeprfX		;mov [eqladdr+0],edx
9710
	mov [eqladdr+0],dx
9711
if RING0 and V86M
9712
	test byte ptr [regs.rFL+2],2
9713
	jz @F
9714
	mov bx,[scratchv86]	; don't store the scratch selector in eqladdr - must be a segment value in v86
9715
@@:
9716
endif
9717
peq1:
9718
	mov [eqladdr+4],bx
9719
	ret
9720
parseql endp
9721

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.
9724
;   Uses AX.
9725

9726
seteq proc
9727
	cmp [eqflag],'='	;'=' argument given?
9728
	jnz @F
9729
	sizeprfX			;mov eax,[eqladdr+0]
9730
	mov ax,[eqladdr+0]
9731
	sizeprfX			;mov [regs.rIP+0],eax
9732
	mov [regs.rIP+0],ax
9733
	mov ax,[eqladdr+4]
9734
	mov [regs.rCS],ax
9735
	mov [eqflag],0		;clear the flag
9736
@@:
9737
	ret
9738
seteq endp
9739

9740
;--- get a valid offset for segment in BX
9741
;--- in: BX=segment/selector
9742
;--- out: offset in (E)DX
9743

9744
getofsforbx proc
9745
if ?PM
9746
	call getseglimit
9747
	jz gofbx_2
9748
	mov [bAddr32],1
9749
	push bx
9750
	call getdword
9751
	push bx
9752
	push dx
9753
	.386
9754
	pop edx
9755
	pop bx
9756
	ret
9757
	.8086
9758
gofbx_2:
9759
endif
9760
	sizeprfX		; v2.0: xor edx,edx
9761
	xor dx, dx
9762
	call getword
9763
;	@dprintf "getofsforbx: edx=%lX", edx
9764
	ret
9765
getofsforbx endp
9766

9767
errorj10:
9768
	jmp cmd_error
9769

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.
9774

9775
getlenforbx proc
9776
if ?PM
9777
	call getseglimit
9778
	jz glfbx_1
9779
	push dx
9780
	push bx
9781
	call getdword
9782
	push bx
9783
	push dx
9784
	.386
9785
	pop ecx
9786
	pop bx
9787
	pop dx
9788
	stc
9789
	jecxz glfbx_2
9790
	dec ecx
9791
	add ecx, edx
9792
	ret
9793
	.8086
9794
glfbx_1:
9795
endif
9796
	push dx
9797
	call getword
9798
	mov cx,dx
9799
	pop dx
9800
;   stc
9801
;	jcxz glfbx_2	;0 means 64k
9802
	dec cx
9803
	add cx,dx		;C if it wraps around
9804
glfbx_2:
9805
	ret
9806
getlenforbx endp
9807

9808
;--- get range with default segment DS
9809

9810
getrangeDS proc
9811
	@movs bx,[regs.rDS]
9812
;--- fall thru!
9813
getrangeDS endp
9814

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
9827
;   Uses    AH
9828

9829
getrange proc		; used by c, d, m, s, u cmds
9830
	push cx
9831
	call getaddr	;get address into bx:(e)dx (sets bAddr32 if ?PM)
9832
	push si
9833
	call skipcomm0
9834
	cmp al,' '
9835
	ja gr2
9836
	pop si			;restore si and cx
9837
	pop cx
9838
	jcxz errorj10	;if a range is mandatory
9839
if ?PM
9840
	call IsOfs32	;can be NZ only on a 80386+
9841
	jz @F
9842
	.386
9843
	dec ecx
9844
	add ecx,edx
9845
	jnc gr1			;if no wraparound
9846
	or ecx,-1		;go to end of segment
9847
	jmp gr1
9848
@@:
9849
endif
9850
	dec cx
9851
	add cx,dx
9852
	jnc gr1			;if no wraparound
9853
	mov cx,0ffffh	;go to end of segment
9854
gr1:
9855
	dec si			;restore al
9856
	lodsb
9857
	ret
9858

9859
gr2:
9860
	or al,TOLOWER
9861
	cmp al,'l'
9862
	je gr3			;if a range is given
9863
;	call skipwh0	;get next nonblank
9864
if ?PM
9865
	cmp [machine],3
9866
	jb gr2_1
9867
	.386
9868
	push edx
9869
	call getofsforbx
9870
	mov ecx,edx
9871
	pop edx
9872
	cmp edx,ecx
9873
	ja errorj2
9874
	jmp gr4
9875
	.8086
9876
gr2_1:
9877
endif
9878
	push dx
9879
	call getword
9880
	mov cx,dx
9881
	pop dx
9882
	cmp dx,cx
9883
	ja errorj2			;if empty range
9884
	jmp gr4
9885

9886
gr3:
9887
	call skipcomma		;discard the 'l'
9888
	call getlenforbx
9889
	jc errorj2
9890
gr4:
9891
	add sp,4			;discard saved cx, si
9892
	ret
9893
getrange endp
9894

9895
errorj2:
9896
	jmp cmd_error
9897

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
9905
;   Uses    AH,CX
9906

9907
getaddr proc
9908
if ?PM
9909
	mov [bAddr32],0
9910
 if ?DPMI
9911
	cmp al, '$'			; a real-mode segment?
9912
	jnz @F
9913
	lodsb
9914
	call ispm_dbg
9915
	jz @F
9916
	call getword
9917
	cmp al,':'
9918
	jnz errorj2
9919
	mov bx,dx
9920
	mov ax,2
9921
	int 31h
9922
	mov bx,ax
9923
	mov dx,ax
9924
	jc errorj2
9925
	jmp ga3
9926
@@:
9927
 elseif RING0
9928
	cmp al, '%'			; a linear address?
9929
	jnz @F
9930
	mov bx, cs:[wFlat]
9931
	jmp ga3
9932
@@:
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.
9936
	cmp al, '$'
9937
	jnz normseg
9938
  if V86M
9939
;--- in v86-mode, '$' is unknown
9940
	test byte ptr [regs.rFL+2],2	; syntax NOT valid in v86-mode
9941
	jnz errorj2
9942
  else
9943
	cmp [lastcmd], offset u_cmd	; u cmd?
9944
	jz @F
9945
	cmp [errret], offset cmdloop; a cmd?
9946
	jz normseg
9947
@@:
9948
  endif
9949
	lodsb
9950
	call getword
9951
	cmp al,':'
9952
	jnz errorj2
9953
	call setscratchsel	; set BX to scratchsel
9954
	jmp ga3
9955
normseg:
9956
  if V86M
9957
	cmp al,'#'			; segment part is a selector?
9958
	jnz @F
9959
	test byte ptr [regs.rFL+2],2	; syntax valid only in v86-mode
9960
	jz errorj2
9961
	lodsb
9962
	call getword
9963
	@dprintf "getaddr: # detected, selector=%X ax=%X", dx, ax
9964
	cmp al,':'
9965
	jnz errorj2
9966
	mov bx, dx
9967
	jmp ga3
9968
@@:
9969
  endif
9970
 endif
9971
endif
9972
	call getofsforbx
9973
	push si
9974
	call skipwh0
9975
	cmp al,':'
9976
	je ga2		;if this is a segment descriptor
9977
	pop si
9978
	dec si
9979
	lodsb
9980
	ret
9981

9982
ga2:
9983
	pop ax		;throw away saved si
9984
	@movs bx,dx	;mov segment into BX
9985
ga3:
9986
	call skipwhite	;skip to next word
9987
if ?PM
9988
	mov [bAddr32],0	;v2.0: init bAddr32, will be set if limit > 64k
9989
endif
9990
	call getofsforbx
9991
if ?PM
9992
	@dprintf "getaddr: bx:edx=%X:%lX, bAddr32=%X", bx, edx, word ptr [bAddr32]
9993
endif
9994
	ret
9995
getaddr endp
9996

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
10002
;   Uses    AX,CL,DL,SI
10003

10004
getstr proc
10005
	mov di,offset line_out
10006
	cmp al,CR
10007
	je errorj2		;we don't allow empty byte strings
10008
gs1:
10009
	cmp al,"'"
10010
	je gs2		;if string
10011
	cmp al,'"'
10012
	je gs2		;ditto
10013
	call getbyte;byte in DL
10014
	mov [di],dl	;store the byte
10015
	inc di
10016
	jmp gs6
10017

10018
gs2:
10019
	mov ah,al	;save quote character
10020
gs3:
10021
	lodsb
10022
	cmp al,ah
10023
	je gs5		;if possible end of string
10024
	cmp al,CR
10025
	je errorj2	;if end of line
10026
gs4:
10027
	stosb		;save character and continue
10028
	jmp gs3
10029

10030
gs5:
10031
	lodsb
10032
	cmp al,ah
10033
	je gs4		;if doubled quote character
10034
gs6:
10035
	call skipcomm0	;go back for more
10036
	cmp al,CR
10037
	jne gs1		;if not done yet
10038
	ret
10039
getstr endp
10040

10041
;--- in: AL=first char
10042
;---     SI->2. char
10043
;--- out: value in BX:DX
10044

10045
issymbol proc
10046
	push ax
10047
	push di
10048
	push cx
10049
	mov di,offset regnames
10050
	mov cx,NUMREGNAMES
10051
	mov ah,[si]		;get second char of name 
10052
	and ax,TOUPPER_W
10053
	cmp byte ptr [si+1],'A'
10054
	jnc maybenotasymbol
10055
	repnz scasw
10056
	jnz notasymbol
10057
	xor bx,bx
10058
	mov di, [di+NUMREGNAMES*2 - 2]
10059
getsymlow:
10060
	mov dx,[di]
10061
	inc si		;skip over second char
10062
	clc
10063
	pop cx
10064
	pop di
10065
	pop ax
10066
	ret
10067
maybenotasymbol:
10068
	cmp al,'E'		;386 standard register names start with E
10069
	jnz notasymbol
10070
	mov al,[si+1]
10071
	xchg al,ah
10072
	and ax,TOUPPER_W
10073
	cmp ax,"PI"
10074
	jnz @F
10075
	mov di,offset regs.rIP
10076
	jmp iseip
10077
@@:
10078
	mov cx,8	;scan for the 8 standard register names only
10079
	repnz scasw
10080
	jnz notasymbol
10081
	mov di,[di+NUMREGNAMES*2 - 2]
10082
iseip:
10083
	mov bx,[di+2]	;get HiWord of DWORD register
10084
	inc si
10085
	jmp getsymlow
10086
notasymbol:
10087
	pop cx
10088
	pop di
10089
	pop ax
10090
	stc
10091
	ret
10092
issymbol endp
10093

10094
;   GETDWORD - Get (hex) dword from input line.
10095
;       Entry   AL  first character
10096
;           SI  address of next character
10097
;       Exit    BX:DX   dword
10098
;           AL  first character not in the word
10099
;           SI  address of the next character after that
10100
;       Uses    AH,CL
10101

10102
getdword proc
10103
	call issymbol
10104
	jc @F
10105
	lodsb
10106
	ret
10107
@@:
10108
	call getnyb
10109
	jc errorj6		;if error
10110
	cbw
10111
	xchg ax,dx
10112
	xor bx,bx		;clear high order word
10113
nextchar:
10114
	lodsb
10115
	call getnyb
10116
	jc done
10117
	test bh,0f0h
10118
	jnz errorj6		;if too big
10119
	mov cx,4
10120
@@:
10121
	shl dx,1		;double shift left
10122
	rcl bx,1
10123
	loop @B
10124
	or dl,al
10125
	jmp nextchar
10126
done:
10127
	ret
10128
getdword endp
10129

10130
errorj6:
10131
	jmp cmd_error
10132

10133
;   GETWORD - Get (hex) word from input line.
10134
;       Entry   AL  first character
10135
;           SI  address of next character
10136
;       Exit    DX  word
10137
;           AL  first character not in the word
10138
;           SI  address of the next character after that
10139
;       Uses    AH,CL
10140

10141
getword proc
10142
	push bx
10143
	call getdword
10144
	and bx,bx		;hiword clear?
10145
	pop bx
10146
	jnz errorj6		;if error
10147
	ret
10148
getword endp
10149

10150
;   GETBYTE - Get (hex) byte from input line into DL.
10151
;       Entry   AL  first character
10152
;           SI  address of next character
10153
;       Exit    DL  byte
10154
;           AL  first character not in the word
10155
;           SI  address of the next character after that
10156
;       Uses    AH,CL
10157

10158
getbyte:
10159
	call getword
10160
	and dh,dh
10161
	jnz errorj6		;if error
10162
	ret
10163

10164
;--- GETNYB - Convert the hex character in AL into a nybble.  Return
10165
;--- carry set in case of error.
10166

10167
getnyb:
10168
	push ax
10169
	sub al,'0'
10170
	cmp al,9
10171
	jbe gn1		;if normal digit
10172
	pop ax
10173
	push ax
10174
	or al,TOLOWER
10175
	sub al,'a'
10176
	cmp al,'f'-'a'
10177
	ja gn2		;if not a-f or A-F
10178
	add al,10
10179
gn1:
10180
	inc sp		;normal return (first pop old AX)
10181
	inc sp
10182
	clc
10183
	ret
10184
gn2:
10185
	pop ax		;error return
10186
	stc
10187
	ret
10188

10189
;--- CHKEOL1 - Check for end of line.
10190

10191
chkeol:
10192
	call skipwh0
10193
	cmp al,CR
10194
	jne errorj8		;if not found
10195
	ret
10196

10197
errorj8:
10198
	jmp cmd_error
10199

10200
;   SKIPCOMMA - Skip white space, then an optional comma, and more white
10201
;       space.
10202
;   SKIPCOMM0 - Same as above, but we already have the character in AL.
10203

10204
skipcomma:
10205
	lodsb
10206
skipcomm0:
10207
	call skipwh0
10208
	cmp al,','
10209
	jne sc2		;if no comma
10210
	push si
10211
	call skipwhite
10212
	cmp al,CR
10213
	jne sc1		;if not end of line
10214
	pop si
10215
	mov al,','
10216
	ret
10217
sc1:
10218
	add sp,2	;pop si into nowhere
10219
sc2:
10220
	ret
10221

10222
;--- SKIPALPHA - Skip alphabetic character, and then white space.
10223

10224
skipalpha:
10225
	lodsb
10226
	and al,TOUPPER
10227
	sub al,'A'
10228
	cmp al,'Z'-'A'
10229
	jbe skipalpha
10230
	dec si
10231
;	jmp skipwhite	;(control falls through)
10232

10233
;--- SKIPWHITE - Skip spaces and tabs.
10234
;--- SKIPWH0 - Same as above, but we already have the character in AL.
10235

10236
skipwhite:
10237
	lodsb
10238
skipwh0:
10239
	cmp al,' '
10240
	je skipwhite
10241
	cmp al,TAB
10242
	je skipwhite
10243
	ret
10244

10245
;--- IFSEP Compare AL with separators ' ', '\t', ',', ';', '='.
10246

10247
ifsep:
10248
	cmp al,' '
10249
	je @F
10250
	cmp al,TAB
10251
	je @F
10252
	cmp al,','
10253
	je @F
10254
	cmp al,';'
10255
	je @F
10256
	cmp al,'='
10257
@@:
10258
	ret
10259

10260
;--- disassembler code
10261

10262
	include <DISASM.INC>
10263

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 )
10268
;           cx -> instruction
10269
;   Exit    si Address of string
10270
;           cx Length of string, or 0 if not needed
10271
;   Uses    al, di
10272

10273
showmach proc
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')
10278
	mov al,[mach_87]
10279
	cmp [has_87],0
10280
	jnz sm2				;if it has a coprocessor
10281
	mov al,[machine]
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
10286
	ret
10287

10288
is_cpu:
10289
	mov byte ptr [si+9],'6'	;reset message text ('x86')
10290
	mov al,[machine]
10291
sm2:
10292
	cmp al,[ai.dismach]
10293
	jae sm4				;if no message (so far)
10294
sm3:
10295
	mov al,[ai.dismach]
10296
	add al,'0'
10297
	mov [si+7],al
10298
	mov cx,sizeof needsmsg	;length of the message
10299
	ret
10300

10301
;--- Check for obsolete instruction.
10302

10303
sm4:
10304
	mov si,offset obsolete	;candidate message
10305
	mov ax,cx				;get info on this instruction
10306
	mov cx,5
10307
	repne scasw
10308
	jne @F			;if no matches
10309
	mov di,offset obsmach + 5 - 1
10310
	sub di,cx
10311
	xor cx,cx		;clear CX:  no message
10312
	mov al,[mach_87]
10313
	cmp al,[di]
10314
	jle @F			;if this machine is OK
10315
	mov cx,sizeof obsolete
10316
@@:
10317
	ret
10318
showmach endp
10319

10320
;--- DUMPREGS - Dump registers and print 1 disassembled line at CS:EIP.
10321

10322
dumpregs proc
10323
;	@dprintf "dumpregs"
10324
	mov si,offset regnames
10325
	mov di,offset line_out
10326
	mov cx, 5
10327
	mov bx,offset regfmt16
10328
	test [rmode],RM_386REGS
10329
	jz @F
10330
	mov bx,offset regfmt32
10331
@@:
10332
nextgrp:
10333
	push cx
10334
	mov cl, [bx+0]
10335
	and cx,7fh
10336
	push bx
10337
	call word ptr [bx+1]
10338
	pop bx
10339
	test byte ptr [bx],80h
10340
	jz @F
10341
	call putsline
10342
	mov di, dx
10343
@@:
10344
	add bx, sizeof FMTITEM
10345
	pop cx
10346
	loop nextgrp
10347

10348
if RING0
10349
 if DISPPL0STK
10350
	call dmpr0ssesp
10351
	call putsline
10352
 endif
10353
endif
10354

10355
;--- display 1 disassembled line at CS:[E]IP
10356

10357
	mov si, offset regs.rIP
10358
	mov di, offset u_addr
10359
	movsw
10360
	movsw
10361
	@movs ax,[regs.rCS]	; problem: if V86M and v86-mode, this will be the scratch sel
10362
	stosw
10363
	mov al, DIS_F_REPT or DIS_F_SHOW
10364
	call disasm
10365

10366
;--- 'r' resets default setting for 'u' to CS:[E]IP
10367

10368
	sizeprf			; mov eax, [regs.rIP]
10369
	mov ax,[regs.rIP]
10370
	sizeprf			; mov [u_addr], eax
10371
	mov [u_addr],ax
10372
	ret
10373

10374
FMTITEM struct
10375
bNum db ?
10376
wAdr dw ?
10377
FMTITEM ends
10378

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
10381

10382
CONST segment
10383
regfmt16 FMTITEM <88h,dmpr1w>,<2,skipregs>,<4,dmpr1w>,<1,dmpip>,<80h,dmpflags>
10384
regfmt32 label FMTITEM
10385
	FMTITEM <86h,dmpr1d>
10386
	FMTITEM <4,dmpr1d>
10387
	FMTITEM <80h,dmpflags>
10388
	FMTITEM <0,prepsr>
10389
	FMTITEM <86h,dmpr1w>
10390
CONST ends
10391

10392
skipregs:
10393
	rep lodsw
10394
	ret
10395
prepsr:
10396
	mov si, offset regnames+10*2	; just position SI to segment regs
10397
	ret
10398

10399
dmpip:
10400
	mov si, offset regnames+8*2
10401
;--- fall thru
10402

10403
;--- Function to print multiple WORD register entries.
10404
;--- SI->register names (2 bytes)
10405
;--- CX=count
10406

10407
dmpr1w:
10408
	movsw
10409
	mov al,'='
10410
	stosb
10411
	mov bx,[si+NUMREGNAMES*2-2]
10412
	mov ax,[bx]
10413
	call hexword
10414
	mov al,' '
10415
	stosb
10416
	loop dmpr1w
10417
	ret
10418

10419
;--- Function to print multiple DWORD register entries.
10420
;--- SI->register names (2 bytes)
10421
;--- CX=count
10422

10423
dmpr1d:
10424
	mov al,'E'
10425
	stosb
10426
	movsw
10427
	mov al,'='
10428
	stosb
10429
	mov bx,[si+NUMREGNAMES*2-2]
10430
	.386
10431
	mov eax,[bx]
10432
	.8086
10433
	call hexdword
10434
	mov al,' '
10435
	stosb
10436
	loop dmpr1d
10437
	ret
10438

10439
if RING0
10440
 if DISPPL0STK
10441

10442
CONST segment
10443
pl0esp db "[PL0 SS:ESP="
10444
CONST ends
10445

10446
dmpr0ssesp:
10447
	.386
10448
 if V86M
10449
	test byte ptr [regs.rFL+2],2
10450
	jnz isv86
10451
 endif
10452
	lar ax, [regs.rCS]
10453
	and ah,60h
10454
	jz @F
10455
isv86:
10456
	mov si, offset pl0esp
10457
	mov cl, sizeof pl0esp
10458
	rep movsb
10459
	mov ax, [regs.r0SS]
10460
	call hexword
10461
	mov al,':'
10462
	stosb
10463
	mov eax, [regs.r0Esp]
10464
	call hexdword
10465
	mov al,']'
10466
	stosb
10467
@@:
10468
	ret
10469
 endif
10470
endif
10471

10472

10473
dumpregs endp
10474

10475
if USEFP2STR
10476
 if RING0
10477
	.386
10478
 endif
10479
	include <FPTOSTR.INC>
10480
endif
10481

10482
;--- the layout for FSAVE/FRSTOR depends on mode and 16/32bit
10483

10484
if 0
10485
FPENV16 struc
10486
cw	dw ?
10487
sw	dw ?
10488
tw	dw ?
10489
fip	dw ?	;ip offset
10490
union
10491
opc dw ?	;real-mode: opcode[0-10], ip 16-19 in high bits
10492
fcs	dw ?	;protected-mode: ip selector
10493
ends
10494
fop	dw ?	;operand ptr offset
10495
union
10496
foph dw ?	;real-mode: operand ptr 16-19 in high bits
10497
fos	dw ?	;protected-mode: operand ptr selector
10498
ends
10499
FPENV16 ends
10500

10501
FPENV32 struc
10502
cw	dw ?
10503
	dw ?
10504
sw	dw ?
10505
	dw ?
10506
tw	dw ?
10507
	dw ?
10508
fip	dd ?	;ip offset (real-mode: bits 0-15 only)
10509
union
10510
struct
10511
fopcr dd ?	;real-mode: opcode (0-10), ip (12-27)
10512
ends
10513
struct
10514
fcs	dw ?	;protected-mode: ip selector
10515
fopcp dw ?	;protected-mode: opcode(bits 0-10)
10516
ends
10517
ends
10518
foo	dd ?	;operand ptr offset (real-mode: bits 0-15 only)
10519
union
10520
struct
10521
fooh dd ?	;real-mode: operand ptr (12-27)
10522
ends
10523
struct
10524
fos	dw ?	;protected-mode: operand ptr selector
10525
	dw ?	;protected-mode: not used
10526
ends
10527
ends
10528
FPENV32 ends
10529
endif
10530

10531
CONST segment
10532
fregnames label byte
10533
	db "CW", "SW", "TW"
10534
	db "OPC=", "IP=", "DP="
10535
dEmpty db "empty"
10536
dNaN db "NaN"
10537
CONST ends
10538

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.
10544

10545
dumpregsFPU proc
10546
if RING0
10547
	.386
10548
	mov dx, offset fpuemerr
10549
	mov eax, cr0
10550
	test al, 4		;CR0.EM=1?
10551
	jnz int21ah9
10552
	.8086
10553
endif
10554
	mov di,offset line_out
10555
	mov si,offset fregnames
10556
	mov bx,offset line_in + 2
10557
	sizeprf
10558
	fnsave [bx]
10559

10560
;--- display CW. SW and TW
10561

10562
	mov cx,3
10563
nextfpr:
10564
	movsw
10565
	mov al,'='
10566
	stosb
10567
	xchg si,bx
10568
	sizeprf		;lodsd
10569
	lodsw
10570
	xchg si,bx
10571
	push ax
10572
	call hexword
10573
	mov al,' '
10574
	stosb
10575
	loop nextfpr
10576

10577
;--- display OPC
10578
;--- in 16bit format protected-mode, there's no OPC
10579
;--- for 32bit, there's one, but the location is different from real-mode
10580

10581
	push bx
10582
if ?DPMI
10583
	call ispm_dbg
10584
	jz @F
10585
	add bx,2	;location of OPC in protected-mode differs from real-mode!
10586
	cmp [machine],3
10587
	jnb @F
10588
	add si,4	;no OPC for FPENV16 in protected-mode
10589
	jmp noopc
10590
@@:
10591
endif
10592
	movsw
10593
	movsw
10594
	xchg si,bx
10595
	sizeprf			;lodsd
10596
	lodsw			;skip word/dword
10597
	lodsw
10598
	xchg si,bx
10599
	and ax,07FFh	;bits 0-10 only
10600
	call hexword
10601
	mov al,' '
10602
	stosb
10603
noopc:
10604
	pop bx
10605

10606
;--- display IP and DP
10607

10608
	mov cl,2		;ch is 0 already
10609
nextfp:
10610
	push cx
10611
	movsw
10612
	movsb
10613
	xchg si,bx
10614
	sizeprf		;lodsd
10615
	lodsw
10616
	sizeprf		;mov edx,eax
10617
	mov dx,ax
10618
	sizeprf		;lodsd
10619
	lodsw
10620
	xchg si,bx
10621
if ?DPMI
10622
	call ispm_dbg
10623
	jz @F
10624
	call hexword
10625
	mov al,':'
10626
	stosb
10627
	jmp fppm
10628
@@:
10629
endif
10630
	mov cl,12
10631
	sizeprf		;shr eax,cl
10632
	shr ax,cl
10633
	cmp [machine],3
10634
	jb @F
10635
	call hexword
10636
	jmp fppm
10637
@@:
10638
	call hexnyb	;convert to hex digit and print
10639
fppm:
10640
	sizeprfX	;mov eax,edx
10641
	mov ax,dx
10642
if ?DPMI
10643
	call ispm_dbg
10644
	jz @F
10645
	cmp [machine],3
10646
	jb @F
10647
	call hexdword
10648
	jmp fppm32
10649
@@:
10650
endif
10651
	call hexword
10652
fppm32:
10653
	mov al,' '
10654
	stosb
10655
	pop cx
10656
	loop nextfp
10657

10658
	xchg si,bx
10659
	call trimputs
10660

10661
;--- display ST0 - ST7
10662

10663
	pop bp	;get TW
10664
	pop ax	;get SW
10665
	pop dx	;get CW (not used)
10666

10667
	mov cl,10
10668
	shr ax, cl	;mov TOP to bits 1-3
10669
	and al, 00001110b
10670
	mov cl, al
10671
	ror bp, cl
10672

10673
	mov cl,'0'
10674
nextst:         ;<- next float to display
10675
	mov di,offset line_out
10676
	push si
10677
	push cx
10678
	mov ax,"TS"
10679
	stosw
10680
	mov al,cl
10681
	mov ah,'='
10682
	stosw
10683

10684
	mov ax,bp
10685
	ror bp,1	;remain 8086 compatible here!
10686
	ror bp,1
10687
	and al,3	;00=valid,01=zero,02=NaN,03=Empty
10688
	jz isvalid
10689
	mov si,offset dEmpty
10690
	mov cl, sizeof dEmpty
10691
	cmp al,3
10692
	jz @F
10693
	mov si,offset dNaN
10694
	mov cl, sizeof dNaN
10695
	cmp al,2
10696
	jz @F
10697
	mov al,'0'
10698
	stosb
10699
	mov cl,0
10700
@@:
10701
	rep movsb
10702
	jmp regoutdone
10703
isvalid:
10704
if USEFP2STR
10705
	call FloatToStr
10706
else
10707
	mov cl, 5
10708
@@:
10709
	lodsw
10710
	push ax
10711
	loop @B
10712
	pop ax
10713
	call hexword
10714
	mov al,'.'
10715
	stosb
10716
	mov cl,4
10717
@@:
10718
	pop ax
10719
	call hexword
10720
	loop @B
10721
endif
10722
regoutdone:
10723
	mov al,' '
10724
@@:
10725
	stosb
10726
	cmp di, offset line_out+26
10727
	jb @B
10728
	pop ax
10729
	push ax
10730
	test al,1
10731
	jz @F
10732
	mov ax, 0A0Dh
10733
	stosw
10734
@@:
10735
	call puts
10736
	pop cx
10737
	pop si
10738
	add si,10	;sizeof TBYTE
10739
	inc cl
10740
	cmp cl,'8'
10741
	jnz nextst
10742
	.286	;avoid WAIT prefix
10743
	sizeprf
10744
	frstor [line_in + 2]
10745
	.8086
10746
	ret
10747
dumpregsFPU endp
10748

10749
;--- DMPFLAGS - Dump flags output.
10750

10751
dmpflags proc
10752
	mov si,offset flgbits
10753
	mov cx,8	;lengthof flgbits
10754
nextitem:
10755
	lodsw
10756
	test ax,[regs.rFL]
10757
	mov ax,[si+16-2]
10758
	jz @F			;if not asserted
10759
	mov ax,[si+32-2]
10760
@@:
10761
	stosw
10762
	mov al,' '
10763
	stosb
10764
	loop nextitem
10765
	ret
10766
dmpflags endp
10767

10768
if MMXSUPP
10769
	.386
10770
dumpregsMMX proc
10771
	fnsaved [line_in + 2]
10772
	mov si,offset line_in + 7*4 + 2
10773
	mov cl,'0'
10774
;	mov di, offset line_out
10775
nextitem:
10776
	mov ax,"MM"
10777
	stosw
10778
	mov al,cl
10779
	mov ah,'='
10780
	stosw
10781
	push cx
10782
	mov dl,8
10783
nextbyte:
10784
	lodsb
10785
	call hexbyte
10786
	mov al,' '
10787
	test dl,1
10788
	jnz @F
10789
	mov al,'-'
10790
@@:
10791
	stosb
10792
	dec dl
10793
	jnz nextbyte
10794
	dec di
10795
	mov ax,'  '
10796
	stosw
10797
	add si,2
10798
	pop cx
10799
	test cl,1
10800
	jz @F
10801
	push cx
10802
	call putsline
10803
	pop cx
10804
	mov di,offset line_out
10805
@@:
10806
	inc cl
10807
	cmp cl,'8'
10808
	jnz nextitem
10809
	fldenvd [line_in + 2]
10810
	ret
10811
dumpregsMMX endp
10812
	.8086
10813
endif
10814

10815
;--- copystring - copy non-empty null-terminated string.
10816
;--- SI->string
10817
;--- DI->buffer
10818
;--- modifies SI, DI, AL
10819

10820
copystring proc
10821
	lodsb
10822
@@:
10823
	stosb
10824
	lodsb
10825
	cmp al,0
10826
	jne @B
10827
	ret
10828
copystring endp
10829

10830
;--- display 16/32-bit offset in E/AX
10831

10832
DispOfs proc
10833
if ?PM
10834
	test [bCSAttr], CS32
10835
	jnz hexdword
10836
endif
10837
	jmp hexword
10838
DispOfs endp
10839

10840
;   HEXDWORD - Print hex dword (in EAX).
10841
;   clears HiWord(EAX)
10842

10843
;   HEXWORD - Print hex word (in AX).
10844
;   HEXBYTE - Print hex byte (in AL).
10845
;   HEXNYB - Print hex digit.
10846
;   Uses    al, di.
10847

10848
hexdword proc
10849
	push ax
10850
	.386
10851
	shr eax,16
10852
	.8086
10853
	call hexword
10854
	pop ax
10855
hexdword endp	;fall through!
10856

10857
hexword proc
10858
	push ax
10859
	mov al,ah
10860
	call hexbyte
10861
	pop ax
10862
hexword endp	;fall through!
10863

10864
hexbyte:
10865
	push ax
10866
if RING0
10867
	.386
10868
	shr al, 4
10869
else
10870
	push cx
10871
	mov cl,4
10872
	shr al,cl
10873
endif
10874
	call hexnyb
10875
ife RING0
10876
	pop cx
10877
endif
10878
	pop ax
10879

10880
hexnyb:
10881
	and al,0fh
10882
	add al,90h		;these four instructions change to ascii hex
10883
	daa
10884
	adc al,40h
10885
	daa
10886
	stosb
10887
	ret
10888

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.
10892

10893
trimputs:
10894
	dec di
10895
	cmp byte ptr [di],' '
10896
	je trimputs
10897
	inc di
10898

10899
putsline:
10900
	mov ax,LF * 256 + CR
10901
	stosw
10902

10903
puts:
10904
	mov cx,di
10905
	mov dx,offset line_out
10906
	sub cx,dx
10907

10908
;--- fall thru'
10909
;--- stdout: write DS:DX, size CX to STDOUT (1)
10910
;--- modifies ax
10911

10912
stdout proc
10913
if RING0
10914
	push bx
10915
else
10916
	call InDos
10917
	push bx
10918
	jnz @F
10919
	mov bx,1		;standard output
10920
	mov ah,40h		;write to file
10921
	call doscall
10922
	pop bx
10923
	ret
10924
@@:					;use BIOS for output
10925
endif
10926
	jcxz nooutput
10927
	push si
10928
	mov si,dx
10929
nextchar:
10930
	lodsb
10931
	mov bh,[vpage]	;v2.0: use the current video page
10932
	cmp al, TAB		;v2.0: handle tabs
10933
	jz istab
10934
	mov ah,0Eh
10935
if RING0
10936
	.386
10937
	call [int10vec]
10938
	.8086
10939
else
10940
	int 10h
10941
endif
10942
donetab:
10943
	loop nextchar
10944
	pop si
10945
nooutput:
10946
	pop bx
10947
	ret
10948

10949
;--- interpret TAB in BIOS output
10950

10951
istab:
10952
	push cx
10953
	push dx
10954
	mov ah, 3
10955
if RING0
10956
	.386
10957
	call [int10vec]
10958
	.8086
10959
else
10960
	int 10h
10961
endif
10962
	mov cl, dl
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
10966
@@:
10967
	mov ax, 0E20h
10968
if RING0
10969
	.386
10970
	call [int10vec]
10971
	.8086
10972
else
10973
	int 10h
10974
endif
10975
	loop @B
10976
	pop dx
10977
	pop cx
10978
	jmp donetab
10979

10980
stdout endp
10981

10982
ifdef _DEBUG
10983
	pushcontext cpu
10984
	.386
10985
 if RING0 and V86M
10986
	include <DPRINTFR.INC>
10987
 else
10988
	include <DPRINTF.INC>
10989
 endif
10990
	popcontext cpu
10991
endif
10992

10993
if LCMDFILE
10994

10995
createdummytask proc
10996

10997
	@dprintf "createdummytask"
10998
	mov di, offset regs
10999
	mov cx, sizeof regs / 2
11000
	xor ax, ax
11001
	rep stosw
11002

11003
	mov ah,48h		;get largest free block
11004
	mov bx,-1
11005
	int 21h
11006
	cmp bx,11h		;must be at least 110h bytes!!!
11007
	jc ct_done
11008
	mov ah,48h		;allocate it
11009
	int 21h
11010
	jc ct_done		;shouldn't happen
11011

11012
	inc byte ptr [regs.rIP+1]	;set IP=100h
11013

11014
	call setespefl	; set regs.rSP/rFL
11015

11016
	push bx
11017
	mov di,offset regs.rDS	;init regs.rDS,regs.rES
11018
	stosw
11019
	stosw
11020
	mov di,offset regs.rSS	;init regs.rSS,regs.rCS
11021
	stosw
11022
	stosw
11023
	call setup_adu	; setup default for a/d/u cmds
11024
	xchg ax, bx		; bx = CS; bx:dx = where to load program
11025
	mov es, bx
11026
	pop ax			;get size of memory block
11027
	mov dx,ax
11028
	add dx,bx
11029
	mov es:[PSPS.ALASAP],dx
11030
	cmp ax,1000h
11031
	jbe @F			;if memory left <= 64K
11032
	xor ax,ax		;ax = 1000h (same thing, after shifting)
11033
@@:
11034
	mov cl,4
11035
	shl ax,cl
11036
	dec ax
11037
	dec ax
11038
	mov [regs.rSP],ax
11039
	xchg ax,di		;es:di = child stack pointer
11040
	xor ax,ax
11041
	stosw			;push 0 on client's stack
11042

11043
;--- Create a PSP
11044

11045
	mov ah,55h		;create child PSP
11046
	mov dx,es
11047
	mov si,es:[PSPS.ALASAP]
11048
	clc				;works around OS/2 bug
11049
	int 21h
11050
	mov word ptr es:[PSPS.TPIV+0],offset intr22
11051
	mov word ptr es:[PSPS.TPIV+2],cs
11052
	cmp [bInit],0
11053
	jnz @F
11054
	inc [bInit]
11055
	mov byte ptr es:[100h],0C3h	;place opcode for 'RET' at CS:IP
11056
@@:
11057
	mov [pspdbe],es
11058

11059
;--- set owner and name to newly created PSP
11060
	mov ax,es
11061
	dec ax
11062
	mov es, ax
11063
	inc ax
11064
	mov es:[0001],ax
11065
	mov byte ptr es:[0008],0
11066
	push ds			;restore ES
11067
	pop es
11068

11069
	call getint2324	; v2.0 init [run2324]
11070

11071
	call setpspdbg	;set debugger's PSP
11072
ct_done:
11073
	ret
11074

11075
createdummytask endp
11076

11077
endif
11078

11079
if ?DPMI
11080

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
11088

11089
hook2f proc
11090
	jz @F
11091
	ret
11092
@@:
11093
	cmp word ptr [oldi2f+2],0
11094
	jnz hook2f_2
11095
	mov ax,1687h			;DPMI host installed?
11096
	int 2Fh
11097
	and ax,ax
11098
	jnz hook2f_2
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?
11104
	jnz hook2f_2
11105
	mov word ptr [dpmiwatch+0],offset mydpmientry
11106
	mov word ptr [dpmiwatch+2],cs
11107
	mov ax,352Fh
11108
	int 21h
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
11113
	mov ax,252Fh
11114
	int 21h
11115
if DISPHOOK
11116
	push ds
11117
	pop es
11118
	push si
11119
;--- don't use line_out here!
11120
	mov di,offset line_in + 128
11121
	mov dx,di
11122
	mov si,offset dpmihook
11123
	call copystring
11124
	pop si
11125
	mov ax,cs
11126
	call hexword
11127
	mov al,':'
11128
	stosb
11129
	mov ax,offset mydpmientry
11130
	call hexword
11131
	mov ax,LF * 256 + CR
11132
	stosw
11133
	mov cx,di
11134
	sub cx,dx
11135
	call stdout
11136
endif
11137
hook2f_2:
11138
	push ds
11139
	pop es
11140
	ret
11141
hook2f endp
11142

11143
endif
11144

11145
if RING0
11146
uninstall proc
11147

11148
	.386
11149
	push ds
11150
	push es
11151
	mov ds, cs:[wDgroup]
11152
	sub esp, 6
11153
	sidt [esp]
11154
	pop dx
11155
	pop ebx
11156
	mov es, [wFlat]
11157
	mov cx, NUMINTS
11158
	mov si, offset inttab
11159
	mov di, offset intsave
11160
@@:
11161
	movzx edx, byte ptr [si]
11162
	shl edx, 3
11163
	mov eax, [di]
11164
	mov es:[ebx+edx+0], ax
11165
	shr eax, 16
11166
	mov es:[ebx+edx+6], ax
11167
	mov ax, [di+4]
11168
	mov es:[ebx+edx+2], ax
11169
	add si, sizeof INTITEM
11170
	add di, sizeof INTVEC
11171
	loop @B
11172
	pop es
11173
	pop ds
11174
	retd
11175
uninstall endp
11176
endif
11177

11178
endoftext16 label byte
11179

11180
_TEXT ends
11181

11182
_DATA segment
11183

11184
;--- I/O buffers.  (End of permanently resident part.)
11185

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
11189

11190
if USEHWBP
11191

11192
HWBP_ACTIVE equ 1
11193
HWBP_V86    equ 2
11194

11195
 if RING0
11196
bHWBPflgs db HWBP_ACTIVE
11197
 else
11198
bHWBPflgs db 0
11199
 endif
11200
endif
11201

11202
_DATA ends
11203

11204
_ITEXT segment
11205

11206
if RING0
11207
	dd 0DEADBEEFh	; marker for start of _ITEXT, don't remove!
11208
endif
11209

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
11214

11215
initcont:
11216

11217
if DRIVER or RING0 or BOOTDBG
11218
	sub bx, 2
11219
	mov [bx], offset ue_int	; make debug display "unexpected interrupt"
11220
 if FLATSS
11221
	.386
11222
	movzx ebx, bx
11223
	add ebx, [dwBase]
11224
	mov [run_sp], ebx
11225
 else
11226
	mov [run_sp], bx
11227
 endif
11228
 if BOOTDBG
11229
	mov cx, ax
11230
	mov es, [wDgroup]		; copy debugger beyond conv. memory
11231
	xor di, di
11232
	xor si, si
11233
	rep movsb
11234
	pop es
11235
	pop ds
11236
	retf
11237
 elseif RING0
11238
	.386
11239
	lss esp, [regs.r0SSEsp]		; switch stack back
11240
	pushf
11241
	and byte ptr [esp+1], 0BFh	; reset NT flag
11242
	popf
11243
	pop es
11244
	pop ds
11245
	retd
11246
 else
11247
	ret
11248
 endif
11249
else
11250
	mov [bInDbg], 1	; v2.01: variable is set only when debug is entered via interrupt
11251
 if FMTEXE
11252
	mov es, [pspdbg]
11253
	add bx, 100h
11254
 else
11255
	push ds
11256
	pop es
11257
 endif
11258
	mov cl, 4
11259
	shr bx, cl
11260
	mov sp, ax
11261
	mov ah, 4Ah
11262
	int 21h			;free rest of DOS memory
11263
	mov byte ptr [line_out-1],'0'	;initialize line_out?
11264
	cmp [fileext],0
11265
	jz @F
11266
 if FMTEXE
11267
	push ds		; loadfile expects ds=es=dgroup
11268
	pop es
11269
 endif
11270
	call loadfile
11271
@@:
11272
if ALTVID
11273
	call setscreen
11274
endif
11275
	jmp cmdloop
11276
endif
11277

11278
;---------------------------------------
11279
;--- Debug initialization code.
11280
;---------------------------------------
11281

11282

11283
ife (DRIVER or BOOTDBG or RING0)
11284

11285

11286
imsg1 db DBGNAME,' version ',@CatStr(!',%VERSION,!'),CR,LF,LF
11287
	db 'Usage: ', DBGNAME, ' '
11288
 if ALTVID or USEHWBP
11289
	db '[options] '
11290
 endif
11291
	db '[[drive:][path]progname [arglist]]',CR,LF
11292
 if ALTVID or USEHWBP
11293
	db ' options:',CR,LF
11294
  if ALTVID
11295
	db '  /2: use alternate video adapter for output if available',CR,LF
11296
  endif
11297
  if USEHWBP
11298
	db '  /s: hardware breakpoints switched off',CR,LF
11299
   ife RING0
11300
	db '  /v: allow hardware breakpoints in v86 mode',CR,LF
11301
   endif
11302
  endif
11303
 endif
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,'$'
11308

11309
imsg2	db 'Invalid switch - '
11310
imsg2a	db 'x',CR,LF,'$'
11311

11312
endif
11313

11314
if ?DPMI
11315
 if DOSEMU
11316
dDosEmuDate db "02/25/93"
11317
 endif
11318
endif
11319

11320
if VDD
11321
szDebxxVdd	db "DEBXXVDD.DLL",0
11322
szDispatch	db "Dispatch",0
11323
szInit		db "Init",0
11324
endif
11325

11326
if DRIVER
11327

11328
init_req struct
11329
	req_hdr <>
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
11333
init_req ends
11334

11335
driver_entry proc far
11336

11337
	push ds
11338
	push di
11339
	lds di, cs:[request_ptr]	; load address of request header
11340
	mov [di].req_hdr.status,0100h
11341
	push bx
11342
	push ds
11343
	push es
11344
	push bp
11345
	push di
11346
	push si
11347
	push dx
11348
	push cx
11349
	push cs
11350
	pop ds
11351
	call initcode
11352
	mov [Intrp],offset interrupt
11353
	mov dx,offset drv_installed
11354
	mov ah,9
11355
	int 21h
11356
	pop cx
11357
	pop dx
11358
	pop si
11359
	pop di
11360
	pop bp
11361
	pop es
11362
	pop ds
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
11365
	pop bx
11366
	pop di
11367
	pop ds
11368
	retf
11369
drv_installed:
11370
	db "DEBUGX device driver installed",13,10,'$'
11371
driver_entry endp
11372

11373
start:
11374
	push cs
11375
	pop ds
11376
	mov dx,offset cantrun
11377
	mov ah,9
11378
	int 21h
11379
	mov ah,4ch
11380
	int 21h
11381
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
11384
	db "$"
11385

11386
endif
11387

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!
11394

11395
if FMTEXE
11396
start:
11397
endif
11398

11399
initcode proc
11400
	cld
11401
if RING0
11402

11403
;--- in:
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)
11410
;--- es:edi=IDT
11411

11412
 if LMODE
11413
CS64SEL equ 8	; to be fixed: 64-bit code selector for DebugRL is 8 (Dos32cm)
11414
 endif
11415

11416
	push ds
11417
	push es
11418
	mov ds, ax
11419
	mov [wFlat], cx
11420
	shr eax, 16
11421
	mov [scratchsel], ax
11422
 if LMODE
11423
	mov [jmpv161s], cs
11424
	mov [jmpv162s], cs
11425
 endif
11426
	.386
11427
 ife LMODE
11428
	@checkss	; ensure hiword esp isn't trashed
11429
 endif
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
11435

11436
;--- set ring0 stack so output is possible during init
11437
	mov [regs.r0Esp], esp
11438
	mov [regs.r0SS], ss
11439

11440
;--- invalidate a & d segment part ( will then be reinitialized )
11441
	xor ax, ax
11442
	mov [a_addr+4], ax
11443
	mov [d_addr+4], ax
11444

11445
;--- set stack
11446

11447
 if FLATSS
11448
	sub esp, 6
11449
	sgdt [esp]
11450
	pop ax
11451
	pop edx
11452
	movzx ebp, bp
11453
	mov ebx, cs
11454
	add ebx, edx
11455
	push ds
11456
	mov ds, cx
11457
	mov al, [ebx+4]
11458
	mov ah, [ebx+7]
11459
	shl eax, 16
11460
	mov ax, [ebx+2]
11461
	pop ds
11462
	add ebp, eax
11463
	mov ss, cx
11464
	mov esp, ebp
11465
	mov [dwBase], eax
11466
  if LMODE
11467

11468
;--- get [dwBase64] - linear address of _TEXT64
11469
;--- depends on how _TEXT64 is aligned!
11470
;--- currently align 16
11471

11472
TEXT64ALIGN equ 16
11473

11474
	mov edx, offset endoftext16
11475
	add dx, TEXT64ALIGN-1
11476
	and dx, not TEXT64ALIGN-1
11477
	add eax, edx
11478
	mov [dwBase64], eax
11479
	@dprintf "initcode: dwBase64=%lX, start TEXT64=%X", eax, dx
11480
  endif
11481

11482
 else
11483
	mov ax, ds
11484
	mov ss, ax
11485
	mov sp, bp
11486
 endif
11487
	push es
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
11490

11491
	mov ax, ds
11492
	mov es, ax
11493
	mov [machine], 3
11494

11495
elseif DRIVER
11496
	mov ax, cs
11497
elseif BOOTDBG
11498
	push ds
11499
	push es
11500
	push cs
11501
	pop ds
11502
	mov ax, cs
11503
else
11504
	mov ax, cs
11505
 if FMTEXE
11506
	mov ds, ax
11507
	mov [pspdbg], es
11508
	mov dx, ss
11509
	sub dx, ax
11510
	mov cl, 4
11511
	shl dx, cl
11512
	mov ss, ax
11513
	add sp, dx
11514
	mov ax, es
11515
 endif
11516
	mov word ptr [execblk.cmdtail+2],ax
11517
	mov word ptr [execblk.fcb1+2],ax
11518
	mov word ptr [execblk.fcb2+2],ax
11519
 if FMTEXE
11520
	mov ax, ds
11521
 endif
11522
endif
11523
	mov [wDgroup], ax	; this will set alias [pspdbg] if FMTEXE==0
11524

11525
;--- Check for console input vs. input from a file or other device.
11526

11527
if REDIRECT
11528
	mov ax,4400h	;IOCTL--get info
11529
	xor bx,bx       ;stdin
11530
	int 21h
11531
	jc @F
11532
	mov [fStdin],dl
11533
@@:
11534
	mov ax,4400h	;IOCTL--get info
11535
	mov bx,1        ;stdout
11536
	int 21h
11537
	jc @F
11538
	mov [fStdout],dl
11539
@@:
11540
endif
11541

11542
ife RING0
11543

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:
11548

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.
11552

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.
11556

11557
	push sp
11558
	pop ax
11559
	cmp ax,sp		
11560
	jnz init6		;if 8086 or 80186 (can't tell them apart)
11561

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.
11565

11566
	mov [machine],2
11567
	pushf			;get original flags into AX
11568
	pop 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
11575
	jz init6		;if 80286
11576

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.
11581

11582
	inc [machine]
11583

11584
;   It is now safe to use 32-bit opcode/operands.
11585

11586
 if USEHWBP
11587
	inc [bHWBPflgs]	; bit 0=1 (HWBP_ACTIVE)
11588
 endif
11589

11590
endif
11591

11592
	.386
11593

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
11604
	cmp eax,ecx
11605
	jz init5		;if 80386 CPU
11606

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.
11611

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)
11621
	push ecx
11622
	popfd			;restore AC bit in EFLAGS first
11623
	mov sp,bx		;restore original stack pointer
11624

11625
;--- Execute CPUID instruction.
11626

11627
	.586
11628

11629
	xor eax,eax		;set up input for CPUID instruction
11630
	cpuid
11631
	cmp eax,1
11632
	jl init6		;if 1 is not a valid input value for CPUID
11633
	xor eax,eax		;otherwise, run CPUID with ax = 1
11634
	inc eax
11635
	cpuid
11636
if MMXSUPP
11637
	test edx,800000h
11638
	setnz [has_mmx]
11639
endif
11640
	mov al,ah
11641
	and al,0fh		;bits 8-11 are the model number
11642
	cmp al,6
11643
	jbe init3		;if <= 6
11644
	mov al,6		;if > 6, set it to 6
11645
init3:
11646
	mov [machine],al;save it
11647
	jmp init6		;don't restore SP
11648

11649
init5:
11650
	push ecx
11651
	popfd			;restore AC bit in EFLAGS first
11652
	mov sp,bx		;restore original stack pointer
11653

11654
ife RING0
11655
	.8086		 	;back to 1980s technology
11656
endif
11657

11658
;   Next determine the type of FPU in a system and set the mach_87
11659
;   variable with the appropriate value.
11660

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.
11670

11671
init6:
11672
ife RING0
11673
	mov bp, sp
11674
BPOFS equ <bp-2>
11675
else
11676
 if FLATSS
11677
BPOFS equ <ebp-8>		; for RING0, there're already 6 bytes used
11678
 else
11679
BPOFS equ <bp-8>		; for RING0, there're already 6 bytes used
11680
 endif
11681
endif
11682
	mov al,[machine]
11683
	mov [mach_87],al	;by default, set mach_87 to machine
11684
	inc [has_87]
11685
	cmp al,5			;a Pentium or above always will have a FPU
11686
	jnc init7
11687
	dec [has_87]
11688

11689
	fninit				;reset FP status word
11690
	mov ax,5a5ah		;init with non-zero value
11691
	push ax
11692
	fnstsw [BPOFS]		;save FP status word
11693
	pop ax				;check FP status word
11694
	cmp al,0
11695
	jne init7			;if no FPU present
11696

11697
	push ax
11698
	fnstcw [BPOFS]		;save FP control word
11699
	pop ax				;check FP control word
11700
	and ax,103fh		;see if selected parts look OK
11701
	cmp ax,3fh
11702
	jne init7			;if no FPU present
11703
	inc [has_87]		;there's an FPU
11704

11705
;--- If we're using a 386, check for 287 vs. 387 by checking whether
11706
;--- +infinity = -infinity.
11707

11708
	cmp [machine],3
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
11714
	fchs
11715
	fcompp			;see if they are the same and remove them
11716
if RING0
11717
	fstsw ax
11718
else
11719
	push ax
11720
	fstsw [BPOFS]	;look at status from FCOMPP
11721
	pop ax
11722
endif
11723
	sahf
11724
	jnz init7		;if they are different, then it's a 387
11725
	dec [mach_87]	;otherwise, it's a 287
11726
init7:
11727

11728
;--- remove size and addr prefixes if cpu is < 80386
11729

11730
;	mov [machine], 2; activate to test non-386 code branches
11731

11732
ife RING0
11733
	cmp [machine],3
11734
	jnb nopatch
11735
	mov si,offset patches
11736
	mov cx,cntpatch
11737
@@:
11738
	lodsw
11739
	xchg ax,bx
11740
	mov byte ptr [bx],90h
11741
	loop @B
11742
	mov [patch_movsp],3Eh	;set ("unnecessary") DS segment prefix
11743
	mov [patch_iret],0CFh	;code for IRET
11744
nopatch:
11745
endif
11746

11747
;--- Check DOS version
11748

11749
ife (BOOTDBG or RING0)
11750
	mov ax,3000h	;check DOS version
11751
	int 21h
11752
	xchg al,ah
11753
	cmp ax,31fh
11754
	jb init2		;if version < 3.3, then don't use new INT 25h method
11755
	inc [usepacket]
11756
 if VDD
11757
	cmp ah,5
11758
	jnz @F
11759
	mov ax,3306h
11760
	int 21h
11761
	cmp bx,3205h	; NTVDM?
11762
	jnz @F
11763
  if USEHWBP
11764
	mov bHWBPflgs,0	; no hwbp for NTVDM
11765
  endif
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"
11769
	RegisterModule
11770
	jc init2
11771
	mov [hVdd], ax
11772
	jmp isntordos71
11773
@@:
11774
 endif
11775
	cmp ax,070Ah
11776
	jb init2
11777
isntordos71:
11778
	inc [usepacket]	;enable FAT32 access method for L/W
11779
init2:
11780
endif
11781

11782
;--- Interpret switches and erase them from the command line.
11783

11784
ife BOOTDBG
11785

11786
 ife RING0
11787
	mov ax,3700h		;get switch character in DL
11788
	int 21h
11789
	mov [swchar],dl
11790
	cmp dl,'/'
11791
	jne @F
11792
	mov [swch1],dl
11793
@@:
11794
 endif
11795

11796
 if RING0
11797
	mov es, [wFlat] 
11798
 elseif DRIVER
11799
	les si, cs:[request_ptr]	; load address of request header
11800
	les si, es:[si].init_req.cmdline
11801
@@:
11802
	lodsb es:[si]		; skip program name
11803
	cmp al,13
11804
	jz @F
11805
	cmp al,' '
11806
	jnz @B
11807
@@:
11808
 else
11809
	mov si,PSPS.DTA+1
11810
  if FMTEXE
11811
I_SRC equ <es:[si]>
11812
  else
11813
I_SRC equ <>
11814
  endif
11815
 endif
11816
contparse:
11817
@@:
11818
 if RING0
11819
	.386
11820
	lodsb es:[esi]
11821
	.8086
11822
 elseif DRIVER
11823
	lodsb es:[si]
11824
 else
11825
	lodsb I_SRC
11826
 endif
11827
	cmp al,' '
11828
	je @B
11829
	cmp al,TAB
11830
	je @B
11831

11832
;--- Process the /? switch (or the [swchar]? switch).
11833
;--- If swchar != / and /? occurs, make sure nothing follows.
11834

11835
	cmp al,[swchar]
11836
	je @F			;if switch character
11837
	cmp al,'/'
11838
	jne doneoptions	;if not the help switch
11839
@@:
11840
 if RING0
11841
	.386
11842
	lodsb es:[esi]
11843
	.8086
11844
 elseif DRIVER
11845
	lodsb es:[si]
11846
 else
11847
	lodsb I_SRC
11848
	cmp al,'?'
11849
	jne @F
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 )
11853
	mov ah,9
11854
	int 21h
11855
	int 20h			;done
11856
@@:
11857
 endif
11858

11859
 if ALTVID
11860
	cmp al,'2'
11861
	jnz noopt2
11862
	mov ax, 1A00h
11863
  if RING0
11864
	.386
11865
	call [int10vec]
11866
  else
11867
	int 10h
11868
  endif
11869
	cmp al, 1Ah
11870
	jnz noaltvid
11871
	cmp bh, 0
11872
	jz noaltvid
11873
	mov byte ptr [setscreen], 1Eh	;"push ds"
11874
	push ds
11875
	mov ax, 40h		; segment value 40h even works in Jemm ring 0
11876
	mov ds, ax
11877
	mov dx, ds:[63h]
11878
	pop ds
11879
	xor dl, 60h
11880
	mov [oldcrtp], dx
11881
	mov al, 7
11882
	cmp dl, 0B4h
11883
	jz @F
11884
	mov al, 3
11885
@@:
11886
	mov [oldmode], al
11887

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.
11891

11892
	mov al, 0eh
11893
	out dx, al
11894
	inc dx
11895
	in al, dx
11896
	mov ah, al
11897
	dec dx
11898
	mov al, 0fh
11899
	out dx, al
11900
	inc dx
11901
	in al, dx
11902
	mov bl, 80
11903
	div bl
11904
	xchg al, ah
11905
	mov [oldcsrpos], ax
11906
noaltvid:
11907
	jmp contparse
11908
noopt2:
11909
 endif
11910

11911
;--- ||| Other switches may go here.
11912

11913
 if USEHWBP
11914
	cmp al,'s'		; don't use debug registers in real-mode/protected-mode?
11915
	jnz @F
11916
	mov [bHWBPflgs],0
11917
	jmp contparse
11918
@@:
11919
  ife RING0
11920
	cmp al,'v'		; use debug registers in v86-mode?
11921
	jnz @F
11922
	or [bHWBPflgs],HWBP_V86
11923
	jmp contparse
11924
@@:
11925
  endif
11926
 endif
11927

11928
 if MCLOPT and ( CATCHINT0C or CATCHINT0D )
11929
	cmp al, 'm'		; /m cmdline option?
11930
	jnz @F
11931
	mov [bMPicB], 20h
11932
	jmp contparse
11933
@@: 
11934
 endif
11935

11936
 if RING0 and CATCHINT41
11937
	cmp al, 'i'		; /i cmdline option?
11938
	jnz noopti
11939
	mov [itab41.bInt], -1; deactivate Int 41h hook   
11940
	jmp contparse
11941
noopti:
11942
 endif
11943

11944
 if RING0 and V86M
11945
	cmp al, 'b'		; set alternate v86-monitor bp?
11946
	jnz nooptb
11947
	mov [bV86Bp], 63h; assume v86 monitor bp is ARPL
11948
	jmp contparse
11949
nooptb:
11950
 endif
11951

11952
 ife (DRIVER or RING0)	; those versions ignore invalid cmdline args
11953
	mov [imsg2a],al
11954
	mov dx,offset imsg2	;Invalid switch
11955
;	call int21ah9	;v2.0: int21ah9 cannot be used ( pInDOS not yet set )
11956
	mov ah,9
11957
	int 21h
11958
	mov ax,4c01h	;Quit and return error status
11959
	int 21h
11960
 endif
11961

11962
doneoptions:
11963

11964
 ife (DRIVER or RING0)
11965
	dec si
11966
  if FMTEXE
11967
;--- if format is .EXE, the cmdline must be copied to DGROUP for n cmd.
11968
	sub sp, 80h
11969
	mov di, sp
11970
	mov cx, es
11971
	push ds
11972
	pop es
11973
	push ds
11974
	mov ds, cx
11975
	mov cx, 40h
11976
	rep movsw
11977
	pop ds
11978
	mov si, sp
11979
  endif
11980
	lodsb
11981
	call n_cmd		; Feed the remaining command line to the 'n' command.
11982
  if FMTEXE
11983
	add sp, 80h
11984
  endif
11985
 endif
11986

11987
endif ; ife BOOTDBG
11988

11989
if BOOTDBG
11990

11991
;--- get final address of debugger behind conv. memory
11992

11993
	push ds
11994
	xor cx, cx
11995
	mov ds, cx
11996
	mov ax, offset real_end + STACKSIZ + (1024-1)
11997
	mov cl, 10
11998
	shr ax, cl
11999
	sub ds:[413h], ax
12000
	mov ax, ds:[413h]
12001
	pop ds
12002
	mov cl, 6
12003
	shl ax, cl
12004
	mov [wDgroup], ax	; BOOTDBG: wDgroup and pspdbg must be updated!
12005

12006
endif
12007

12008
if DMCMD
12009
	mov ah,52h		;get list of lists
12010
	int 21h
12011
	mov ax,es:[bx-2]	;start of MCBs
12012
	mov [wMCB],ax
12013
endif
12014

12015
ife (BOOTDBG or RING0)
12016
	mov ah,34h
12017
	int 21h
12018
	mov word ptr [pInDOS+0],bx
12019
	mov word ptr [pInDOS+2],es
12020
endif
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
12024

12025
if USESDA
12026
	push ds
12027
	mov ax,5D06h
12028
	int 21h
12029
	mov ax,ds
12030
	pop ds
12031
	jc @F
12032
	mov word ptr [pSDA+0],si
12033
	mov word ptr [pSDA+2],ax
12034
@@:
12035
endif
12036

12037
if ?DPMI
12038

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.
12042

12043
 if WIN9XSUPP
12044
	mov ax,1600h	;running in a win3x/win9x dos box?
12045
	int 2Fh
12046
	and al,al		;returns in AL 3=win3x, 4=win9x
12047
	jnz no2fhook
12048
 endif
12049
 if DOSEMU
12050
	mov ax,0F000h
12051
	mov es, ax
12052
	mov di,0FFF5h
12053
	mov si,offset dDosEmuDate
12054
	mov cx,4
12055
	repe cmpsw		;running in DosEmu?
12056
	jz no2fhook_dosemu
12057
 endif
12058
	jmp dpmihostchecked
12059
no2fhook_dosemu:
12060
 if USEHWBP
12061
	mov [bHWBPflgs],0; disable hw bps for DosEmu
12062
 endif
12063
no2fhook:
12064
	inc [bNoHook2F]
12065
dpmihostchecked:
12066

12067
endif
12068

12069
;--- setup hardware bp usage
12070

12071
if USEHWBP 
12072
	test [bHWBPflgs],HWBP_ACTIVE
12073
	jz @F
12074
	mov ax, 9090h
12075
	mov word ptr [setHWBps], ax		; patch code to NOPs
12076
	mov byte ptr [resetHWBps], al
12077
	mov [wStoreBP], offset storebpx
12078
 if BCMD
12079
	mov [bcmdv], offset b_cmd	;activate b cmd (requires 80386)
12080
 endif
12081
 ife RING0
12082
;--- debug register access in v86 may be supported by v86-monitor
12083
;--- jemm & qemm are ok; MS emm386 & Win3x/9x are not.
12084
	.286
12085
	smsw ax
12086
	.8086
12087
	test al,1
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
12092
 endif
12093
@@:
12094
endif
12095

12096
	push ds
12097
	pop es
12098

12099
if INT22
12100

12101
 if FMTEXE
12102
	push ds
12103
	mov ds, [pspdbg]
12104
 endif
12105

12106
;--- Save and modify termination address and the parent PSP field.
12107

12108
	mov si,PSPS.TPIV
12109
	mov di,offset psp22
12110
	movsw
12111
	movsw
12112
	mov word ptr [si-4],offset intr22dbg
12113

12114
	mov [si-2],cs
12115
	mov si,PSPS.PARENT
12116
	movsw
12117
	mov [si-2],cs
12118

12119
 if FMTEXE
12120
	mov es:[pspdbe], ds
12121
	pop ds
12122
 else
12123
	mov [pspdbe],cs	;indicate there is no debuggee loaded yet
12124
 endif
12125

12126
endif
12127

12128
if VXCHG
12129
 ifndef VXCHGFLIP
12130
	mov ax,4300h	; check if XMM is here
12131
	int 2Fh
12132
	cmp al,80h
12133
	jnz noxmm		; no - no screen flip
12134
	mov ax,4310h
12135
	int 2Fh
12136
	mov word ptr [xmsdrv+0],bx
12137
	mov word ptr [xmsdrv+2],es
12138
	.286
12139
	mov dx,32		; alloc 32 kB EMB
12140
	mov ah,9
12141
	call [xmsdrv]
12142
	cmp ax,1
12143
	jnz noxmm
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
12153
	mov ax, 0B000h
12154
	cmp byte ptr es:[463h],0B4h
12155
	jz @F
12156
	or ah, 8
12157
@@:
12158
	mov word ptr [si].XMSM.srcadr+2, ax
12159
	mov al, es:[484h]
12160
	mov [vrows], al
12161
	mov ah, 0Fh					; get active video page in BH
12162
	int 10h
12163
	mov ah, 3					; get cursor pos in DX of active page
12164
	int 10h
12165
	mov [csrpos], dx
12166
	mov ah, 0Bh					; save current screen now
12167
	call [xmsdrv]
12168
	.8086
12169
noxmm:
12170
 else
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.
12174
  if RING0
12175
	.386
12176
	push ds
12177
	mov ds, [wFlat]
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
12182
	mov eax, 0B0000h
12183
	cmp byte ptr ds:[463], 0B4h
12184
	jz @F
12185
	or ah, 80h
12186
@@:
12187
	mov edi, esi
12188
	add edi, ecx
12189
	add esi, eax
12190
	add edi, eax
12191
	push ds
12192
	pop es
12193
	rep movsb es:[edi], ds:[esi]
12194
	pop ds
12195
	.8086
12196
  else
12197
	xor ax, ax
12198
	mov es, ax
12199
	mov si, es:[44Eh]	; page offset curr page
12200
	mov cx, es:[44Ch]	; page size
12201
	shr cx, 1
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
12205
  endif
12206
	int 10h
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
12212
	jz @F
12213
	or ah, 8
12214
@@:
12215
	push ds
12216
	mov es, ax
12217
	mov ds, ax
12218
	rep movsw
12219
	pop ds
12220
  endif
12221
 endif
12222
	push ds
12223
	pop es
12224
endif
12225

12226
;--- Set up interrupt vectors.
12227

12228
	mov cx, NUMINTS
12229
	mov si, offset inttab
12230
	mov di, offset intsave
12231
if RING0
12232
	.386
12233
	les ebx, [bp-6]   ; load address of GDT
12234
	@dprintf "initcode: setup int vectors, es:ebx=%X:%lX", es, ebx
12235
elseif BOOTDBG
12236
	xor ax, ax
12237
	mov es, ax
12238
endif
12239
@@:
12240
	lodsb
12241
if RING0
12242
	cmp al, -1
12243
	jz skipint
12244
	movzx edx, al
12245
 if LMODE
12246
	shl edx, 1	; in long mode, vector size is 16
12247
 endif
12248
	mov ax, es:[ebx+edx*8+0]
12249
	mov [di+0], ax
12250
	mov ax, es:[ebx+edx*8+6]
12251
	mov [di+2], ax
12252
	mov ax, es:[ebx+edx*8+2]
12253
	mov [di+4], ax
12254
elseif BOOTDBG
12255
	mov bl, al
12256
	mov bh, 0
12257
	shl bx, 1
12258
	shl bx, 1
12259
	mov ax, es:[bx+0]
12260
	mov dx, es:[bx+2]
12261
	mov [di+0], ax
12262
	mov [di+2], dx
12263
else
12264
	mov ah, 35h
12265
	int 21h
12266
	mov [di+0], bx
12267
	mov [di+2], es
12268
	xchg ax, dx		;save int # in dl
12269
endif
12270
;	mov ax, [si]	;get address
12271
	lodsw			;get address (16-bit offset)
12272
if RING0
12273
 if LMODE
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
12278
	shr eax, 16
12279
 else
12280
	mov es:[ebx+edx*8+0], ax
12281
	mov es:[ebx+edx*8+2], cs
12282
	xor ax, ax
12283
 endif
12284
	mov es:[ebx+edx*8+6], ax
12285
skipint:
12286
elseif BOOTDBG
12287
	mov dx, [wDgroup]
12288
	mov es:[bx+0], ax
12289
	mov es:[bx+2], dx
12290
else
12291
	xchg ax, dx		;AL=int#, DX=offset
12292
	mov ah, 25h		;set interrupt vector
12293
	int 21h
12294
endif
12295
;	add si, 2
12296
	add di, sizeof INTVEC
12297
	loop @B
12298

12299
;--- prepare to shrink DEBUG and set its stack
12300

12301
	mov ax, offset real_end + STACKSIZ + 15
12302
	and al, not 15		; debug's top of stack
12303
	mov bx, ax
12304
if FLATSS
12305
	add eax, [dwBase]
12306
	mov [top_sp], eax
12307
	@dprintf "top_sp=%lX", eax
12308
else
12309
	mov [top_sp], ax
12310
endif
12311
	jmp initcont
12312

12313
initcode endp
12314

12315
_ITEXT ends
12316

12317
_IDATA segment
12318
cntpatch = ($ - patches) / 2
12319
_IDATA ends
12320

12321
	end start
12322

Использование cookies

Мы используем файлы cookie в соответствии с Политикой конфиденциальности и Политикой использования cookies.

Нажимая кнопку «Принимаю», Вы даете АО «СберТех» согласие на обработку Ваших персональных данных в целях совершенствования нашего веб-сайта и Сервиса GitVerse, а также повышения удобства их использования.

Запретить использование cookies Вы можете самостоятельно в настройках Вашего браузера.