-
Notifications
You must be signed in to change notification settings - Fork 14
Expand file tree
/
Copy pathDEBUG.TXT
More file actions
1222 lines (947 loc) · 47.3 KB
/
DEBUG.TXT
File metadata and controls
1222 lines (947 loc) · 47.3 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
794
795
796
797
798
799
800
801
802
803
804
805
806
807
808
809
810
811
812
813
814
815
816
817
818
819
820
821
822
823
824
825
826
827
828
829
830
831
832
833
834
835
836
837
838
839
840
841
842
843
844
845
846
847
848
849
850
851
852
853
854
855
856
857
858
859
860
861
862
863
864
865
866
867
868
869
870
871
872
873
874
875
876
877
878
879
880
881
882
883
884
885
886
887
888
889
890
891
892
893
894
895
896
897
898
899
900
901
902
903
904
905
906
907
908
909
910
911
912
913
914
915
916
917
918
919
920
921
922
923
924
925
926
927
928
929
930
931
932
933
934
935
936
937
938
939
940
941
942
943
944
945
946
947
948
949
950
951
952
953
954
955
956
957
958
959
960
961
962
963
964
965
966
967
968
969
970
971
972
973
974
975
976
977
978
979
980
981
982
983
984
985
986
987
988
989
990
991
992
993
994
995
996
997
998
999
1000
Contents
1. About
2. DEBUG command line
3. DEBUG commands
4. Format of Displays by Trace, Proceed, Register Commands
5. Unassemble Format
6. Instruction Operands
7. DEBUG Statements in Assembly Mode
8. Debugging with DebugX
9. Installing and Initializing DebugB
10. DebugR Basics
11. DEBUG Scripts
1. About
--------
This text is based upon a "quick and dirty DEBUG tutorial", written
by Michael Webster 2004, Public Domain.
Note: MS-Debug means the original Debug written by Microsoft.
DebugX means all DebugX variants (DebugX, DebugXv, ...).
Debug/X means the "clone" variants (both Debug and DebugX).
DEBUG means both MS-Debug and Debug/X.
Enhancements for Debug/X are marked: [ENH:...].
MS-Debug was developed originally by Tim Paterson as a tool to aid in
his development of the 16-bit x86 OS that eventually became MS-DOS
Version 1.0
A version of MS-Debug was included with every version of MS-DOS (and
PC-DOS, Compaq DOS, etc) and with every version of Windows through
Windows XP.
DEBUG supports the 8086/8088 and 8087 registers and instruction sets.
[ENH: Debug/X supports the 80386 registers and instruction sets
up to the Pentium Pro, including Floating Point instructions. The MMX
instruction set is missing, however. It is planned - and partially
implemented - for DebugX].
2. DEBUG command line
---------------------
For the version of MS-Debug that is included with Windows 98 SE, the
command line "DEBUG /?" returns:
Runs Debug, a program testing and editing tool.
DEBUG [option] [[drive:][path]filename [testfile-parameters]]
[drive:][path]filename Specifies the file you want to test.
testfile-parameters Specifies command-line information required
by the file you want to test.
options are:
/? : display cmdline format help.
[ENH:
DebugX accepts these additional options:
/2 : use an alternate (monochrome) adapter if available.
/s : debugger won't use hardware breakpoints.
/v : debugger may use hardware breakpoints even in v86-mode.
DebugR(L|V) accepts these additional options:
/m : don't assume exceptions and IRQ0-7 do overlap.
DebugRV accepts this additional option:
/b : assume v86-monitor bp is ARPL (default is HLT).
]
3. DEBUG commands
-----------------
3.1 Command Mode & Command Prompt
This section deals with the commands that DEBUG recognizes
while in command mode. Command mode, indicated by the presence of the
DEBUG command prompt (a hyphen), is the mode that DEBUG starts in.
[ENH:
Debug/X changes the command prompt if the debuggee has been stopped
inside DOS - a '!' will precede the default prompt ('!-' instead of
just '-'). DebugX changes the prompt to '#' if debuggee is in protected-
mode. Prompt '!#', which means "inside DOS" AND "in protected-mode",
is also possible, if the debuggee has been stopped in a so-called
DPMI real-mode callback that's called from inside DOS.
The DebugR variants don't "know" about DOS and hence there's never a
'!' prompt prefix. In protected-mode, a '#' prompt is displayed, just
like DebugX does. DebugRV, however, also supports v86-mode - and will
change the prompt to '>' if this mode is active.
]
For the more recent versions of DEBUG, you can cause DEBUG to display
a list of the commands and their parameters by entering a "?" at the
DEBUG command prompt.
3.2 Initial Values of CPU Register Variables
DEBUG maintains a set of variables that it uses to store a target
program's CPU registers. DEBUG initializes these variables each time
it is started. The variables for the AX, DX, BP, SI, and DI registers
are set to 0. If a target program or other file is loaded, the
variables for the BX and CX registers are set to the size of the
program or file. Otherwise, the variables for the BX and CX registers
are set to 0. If a target program is loaded, the variables for the
segment, IP, and SP registers are set to values appropriate for the
loaded program. Otherwise, the variables for the segment registers
are set to the segment address of the area of memory that DEBUG uses
to store the output from the Assemble command, the variable for IP
is set to 100h, and the variable for SP is set to FFFEh.
[ENH: Debug/X supports the 32bit registers introduced with
the 80386. The high-words of these registers are initialized to zero
on program start.]
Note that any DEBUG command that accepts a CPU register as a parameter
is actually using one of these variables. For the remainder of this
section, all register names refer to the associated variable.
3.3 Entering Addresses and Ranges
An address consists of a segment and an offset part, separated by a
colon (:). The segment part may be omitted - then a default value is
assumed, either CS or DS, depending on the context.
For the commands that accept a range parameter, the parameter can be
used to specify a starting address, or a starting and ending address,
or a starting address and a length. To differentiate a length
parameter from an ending address, the length parameter must be
preceded with an "L". The starting address parameter can include a
segment register or a segment address constant, separated from the
offset address with a colon. Some examples using the Dump command:
-D 0
-D CS:0
-D F000:FFF6
-D 0 F
-D DS:100 102
-D SS:20 L 4
Note that DEBUG recognizes only hex numbers (without a trailing "H").
[ENH:
If debuggee is in protected-mode, the segment part of an address is
a selector. If the selector has a limit beyond 64k, the offset parts
of the starting and ending address - as well as the length - can be
32bit. Examples:
#D DS:110000 110FFF
#D CS:400000 L 20000
Segment modifiers '$' and '#': For the variants that may handle both
real-mode and protected-mode, those modifiers are implemented to make
the debugger change its segment interpretation:
'$'-modifier:
DebugX: if debuggee is in protected-mode, a '$' before the segment part
will tell DebugX to interpret the address as a real-mode address. However,
this should be used sparsely, since DPMI function 0002 is used to convert
the segment - the selector returned cannot be released anymore.
DebugR: the '$' modifier is accepted for commands 'a' and 'u' only.
'#'-modifier:
DebugRV: if debuggee is in v86-mode, a '#' just before the segment part
of an address will tell DebugRV to interpret the segment as a selector.
Offset modfifier '%':
DebugR: if an address is entered without segment part, prefix '%' will
tell the debugger to interpret the offset value as linear address.
]
---
The Assemble command (A) is used to enter assembly mode. In assembly
mode, DEBUG prompts for each assembly language statement and converts
the statement into machine code that is then stored in memory. The
optional start address specifies the address at which to assemble the
first instruction. The default start address is 100h. A blank line
entered at the prompt causes DEBUG to exit assembly mode.
Syntax: A [address]
---
[ENH:
The Breakpoint commands (BP/BC) are activated for DebugB, DebugXg, DebugXv
and DebugR(L|V); optionally they may be activated for all Debug variants.
The commands use the 80386+ debug capabilities to set up to 4 "permanent"
breakpoints. If not all 4 are used, the rest may be used internally by the
G, T and P commands to set temporary breakpoints.
The feature is not available on all platforms - on NT platforms and DosEmu,
it's generally inactive. As a rule of thumb one can say that if DOS is running
on emulators, the debug registers are NOT available, while on virtualizers
they usually are. So to be sure, debug register usage may be switched off by
cmdline option /s. Else it will be active in protected-mode and real-mode; in
v86-mode, however, the feature isn't active as default, since support of the
v86 monitor programs may be unreliable. To make the debugger use it even then,
cmdline option /v is supplied.
Without argument, BP will display the currently active breakpoints. Although
the breakpoints may be entered in the usual format ( segment:offset ), they
are stored internally just as linear addresses, and so BP will display this
linear address only.
Syntax: BP [[address] type]
The type argument is a byte value, actually a field of bits: __SS__TT;
bits 0-1 define the breakpoint's type and translate to:
0 code breakpoint
1 write watchpoint
2 I/O watchpoint ( not specified by DPMI v0.9/v1.0 )
3 read/write watchpoint
while bits 4-5 set the size ( watchpoints only ):
0 byte access
1 word access
3 dword access
Bits 2-3 and 6-7 are ignored and masked out.
If no type argument is given, a code breakpoint is assumed. Note that I/O
watchpoints may be rejected by the DPMI host; in any case they require
bit DE to be set in register CR4.
To be able to continue the program after a breakpoint has been hit (without
to clear the breakpoint), the debugger will set the Resume flag ( bit 16 in
the EFlags register ). Be aware that not all DPMI hosts will reliably preserve
that flag when an interrupt occurs, thus making it appear as if the program
cannot continue.
---
Command BC is used to clear a previously set breakpoint.
Syntax: BC bp#
---]
The Compare command (C) compares two memory regions. All differences will be
listed, both addresses are displayed, with their respective data bytes.
Note that the default for the segment part of both range and address is DS.
Example:
-C 0100 l 2 0200
1234:0100 E9 65 1234:0200
1234:0101 01 02 1234:0201
Syntax: C range address
---
The Dump command (D), when used without a parameter, causes DEBUG
to display the contents of the 128-byte block of memory starting at
CS:IP if a target program is loaded, or starting at CS:100h if no
target program is loaded. The optional range parameter can be used
to specify a starting address, or a starting and ending address, or
a starting address and a length. Subsequent Dump commands without a
parameter cause DEBUG to display the contents of the 128-byte block
of memory following the block displayed by the previous Dump command.
[ENH: there is a autorepeat function implemented for D. If the last
command entered was Dump, pressing a single ENTER will count as a
subsequent Dump command.]
Syntax: D [range]
[ENH:
---
DebugR(L/V) only: the Dump GDT (DG) command displays the GDT.
Syntax: DG selector [count]
---
The Dump Interrupt (DI) command displays interrupt vectors (DebugX/
DebugR(L/V) only).
DebugX: the format depends on the current mode. In real/v86-mode, it's
the interrupt vector table (IVT) that is displayed. In protected-mode, it's
the (virtual) IDT and the exception vectors that are displayed.
-DI 0 ; Interrupt 00 in real-mode:
00 02F8:03F8
#DI 8 4 ; Interrupt and exception vectors 08-0B in 32bit protected-mode:
08 00C7:00000D28 00C7:00001228
09 00C7:00000D2D 00C7:0000122D
0A 00C7:00000D32 00C7:00001232
0B 00C7:00000D37 00C7:00001237
DebugR(L): the (real) IDT is displayed.
#DI 10 2 ; IDT vectors 10-11
10 0008:00110338 at=EE00
11 0008:00110340 at=EE00
DebugRV: besides the IDT, the IVT vector is displayed.
#DI 10 2 ; IDT and IVT vectors 10-11
10 0008:00110338 at=EE00 iv=C000:1234
11 0008:00110340 at=EE00 iv=0123:0023
Syntax: DI vector [count]
---
The Dump LDT descriptor (DL) command displays LDT descriptors (DebugX/
DebugR(L/V) only). Example:
#dl 84 2
0084 base=00110800 limit=0000014F attr=00F2
008C base=00110000 limit=000007FF attr=00F3
DebugX: DL can also be used to display limit and attributes of those GDT
descriptors which are accessible by the client. Example:
#dl 18 3
0018 base=???????? limit=FFFFFFFF attr=CFFB
0020 base=???????? limit=FFFFFFFF attr=CFF3
0028 base=???????? limit=???????? attr=????
DebugR(L/V): call gates in LDT are displayed in gate format.
Syntax: DL selector [count]
---
The Dump MCBs (DM) command displays the current DOS PSP and the DOS
Memory Control Block (MCB) chain.
Example:
PSP:1A27
0219 4D 0008 04D6 SD
06F0 4D 06F1 00BA COMMAND
07AB 4D 0000 0007
07B3 4D 06F1 0047 COMMAND
07FB 4D 0000 0039
...
First value is the segment address of the MCB, followed by 4D/5A, the
owner and size of the MCB and finally the 8-byte name of the owner.
An owner of 0000 means that this MCB describes a free memory block.
Syntax: DM
---
DebugR(L|V) only: The Dump Task State Segment (DT) command displays some
information of the current TSS: the TR register, the ring0 SS:ESP and the
address of the IO Permission Bitmap (IOPB). Optionally, one may display ports
that are trapped if the debuggee is either in V86-mode or in non-priviledged
protected mode and IOPL is 0.
Syntax: DT [port count]
---
The Dump eXtended memory command (DX) allows to examine the full range of
memory (DebugX only). It uses interrupt 15h, AH=87h for extended memory
access. It should be noted that, when running under a Expanded Memory
Manager (EMM), Interrupt 15h, AH=87h behaves slightly inconsistent:
addresses below 110000h are regarded as linear, while addresses >= 110000h
are regarded as physical.
Inside a Windows "DOS-Box", or other virtual DOS VMs, interrupt 15, AH=87h
is emulated only, that is, what is displayed usually hasn't much to do with
physical addresses. And there's a good "chance" that when an "invalid"
address is entered, the VM is instantly closed "abnormally".
Syntax: DX [address]
]
---
The Enter command (E) is used to enter data into memory. The required
address parameter specifies the starting location at which to enter
the data. If the address parameter does not specify a segment, DEBUG
uses DS. If the optional list parameter is not included, DEBUG
displays the byte value at the specified address and prompts for a
new value. The spacebar or minus key can be used to move to the next
or previous byte. Pressing the Enter key without entering a value
terminates the command. If the list parameter is included, it can
contain up to 8 byte values separated by spaces, commas, or tabs,
and/or a case significant string enclosed in single or double quotes.
Examples:
-E 100 01 02 03
-E 100 'ABC'
-E 100 'ABC' 0
Syntax: E address [list]
---
The Fill command (F) fills a memory regions with a byte pattern.
To fill for example the first 8000h bytes of current data segment
with pattern 55 AA, enter:
-F 0 L 8000 55 AA
Syntax: F range list
---
The Go command (G), when used without a parameter, causes DEBUG to
copy the contents of the register variables to the actual CPU
registers and effectively jump to the instruction at CS:IP, giving
full control to the program being debugged. DEBUG will reassert
control when the program terminates normally, a debug exception
(exception 01) or a hard-coded breakpoint (INT 03) is reached.
The optional address parameter can be used to specify the starting
address. The optional breakpoint list can be used to specify up to
10 temporary breakpoint addresses. To differentiate the address
parameter from the breakpoint list, the address parameter must be
preceded with an "=". Note that the breakpoint addresses must coincide
with the start of a valid instruction. To resume execution after a
breakpoint, use the Go command without a parameter.
Syntax: G [=address] [break0 break1...]
[ENH: Debug/X will additionally gain control in all modes if an
exception 00 (divide error) occurs. DebugX will additionally gain
control if exceptions 0Ch, 0Dh or 0Eh occur in protected-mode. Be
aware, however, that Debug/X doesn't check if the debuggee modifies
any of those vectors on its own - if this is the case, the debugger
won't be notified.
If available, DebugX will use debug watchpoints to set breakpoints.
This feature may be generally switched off by the /s cmdline option; on
Windows NT platforms and DosEmu it's always off. If enabled, it should
always work in real-mode; in protected-mode it has to be supported by
the DPMI host; in v86-mode, it's inactive, but may be explicitely switched
on by cmdline option /v.
Finally, Debug/X accepts more than 10 temporary breakpoints - they're
limited just by the max. line length.
]
---
The Hex command (H) computes the sum and difference of two hex
numbers.
Syntax: H value1 value2
[ENH: MS-Debug will handle WORD values only, Debug/X will accept
DWORD values.]
---
The Input command (I) causes DEBUG to read and display the value
from the 8-bit I/O port specified by the required port parameter.
Syntax: I port
[ENH: besides I there exists IW/ID to read a WORD/DWORD from
a 16-bit/32-bit port. ID is available on machines with a 80386+ cpu
only.]
---
The Load command (L) is used to load a file into memory. The file to
load is specified with the Name command (N). The optional address
parameter specifies the load address. The default load address is
CS:100 for all files other than EXE files, for which information in
the file header determines the load address. After DEBUG loads the
file it sets BX:CX to the file size in bytes.
A load address can be specified if the file extension is not .COM
or .EXE. Note that if a debuggee is active when a L command is about
to run, and the file extension is .COM/.EXE, the debuggee will be
terminated.
Syntax: L [address]
The Load command can also be used to load one or more logical sectors
from a disk drive into DEBUG's memory. The drive should be specified
as 0=A, 1=B, 2=C etc.
Syntax: L address drive startsector numberofsectors
[ENH: L with logical sectors on Windows XP will work for DebugX only
and requires a socalled VDD (Virtual DOS Driver) named DEBXXVDD.DLL
to be loaded.
While in protected-mode, loading non-program files is rejected;
if sectors are to be loaded, DEBUG will accept the command only if a
DOS extender is active.
]
---
The Move command (M) copies a memory region to another location. If
source and destination overlap, parts of the source will be overwritten.
Note that the default for the segment part of both range and address is DS.
Syntax: M range address
[ENH:
if M is entered without - or with one - argument, it is regarded as 'Mode'
command, which displays - or sets - the current CPU mode.
Syntax: M [mode]
'mode' is 0 for a 8086/8088, 1 for a 80186, ... 6 for a 80686 (Pentium=80586,
Pentium Pro=80686).
---
The MC command allows to set the FPU mode. This is for the A and D
commands only. To display the current FPU mode, use the M command.
Syntax: MC [N|2]
MC without argument will enable and MC N will disable the FPU. MC 2 will
set the FPU to 80287 - this is accepted only if the current cpu is a 80386.
]
---
The Name command (N) is used to input a filename (actually, a file
specification that can include a drive and a path) for a subsequent
Load or Write command. Because the Name command uses the simulated
PSP as a buffer, it can also be used to enter command line arguments
and/or switches for the program being debugged.
Be aware that the N command alters the value of the AX register, even
if entered without arguments. Also, Debug converts the input to uppercase,
and the size of filespec + arguments is limited to 79 characters.
Syntax: N filespec [arguments]
[ENH: Debug/X allows 126 characters for filespec + arguments. The input
buffer is larger, but anything entered beyond char 126 is truncated.
Generally, Debug/X's N cmd works a bit differently than MS Debug's: the
command modifies the debugger's PSP only. The command tail is copied
by DOS to the debuggee's PSP when DOS function "load program" is executed.
If a file with an extension other than .COM or .EXE is loaded, the
command tail won't be copied.
]
---
The Output command (O) causes DEBUG to write the byte specified by
the required byte parameter to the 8-bit I/O port specified by the
required port parameter (O port byte)
Syntax: O port byte
[ENH: besides O there exists OW/OD to write a WORD/DWORD to
a 16-bit/32-bit port. OD is available on machines with a 80386+ cpu
only.]
---
The Proceed command (P) functions like the Trace command (T) for all
instructions other than the repeat (REP) string, LOOP, procedure
CALL, and interrupt call (INT) instructions. For a repeat string
instruction, DEBUG executes the instruction to completion. For a
LOOP instruction, DEBUG executes the entire loop to completion.
For a procedure CALL or an interrupt call instruction, DEBUG
executes the entire call up to and including the return instruction.
After execution is complete, DEBUG continues as it does for the
Trace command.
Syntax: P [=address] [number]
[DebugX: see the remark at the T(race) command about DebugX's possible
usage of the 80386 debug registers in protected-mode and real-mode. As
for regaining control, see the remarks at the G(o) command.
]
---
The Quit command (Q) should be a no-brainer.
Syntax: Q
[DebugX: If the debuggee is in protected-mode ( indicated by the
'#' prompt ), Q will just make the debuggee to terminate and
leave protected-mode. DebugX's real-mode prompt '-' should then
appear. Entering 'q' again should now quit the debugger.
If 'Q' doesn't leave protected-mode, then there's a problem
with the debuggee or the DPMI host. In this case command variant
'QQ' may be tried. It forces an exit, although it might prevent
the debuggee from doing protected-mode clean-up work.
Note: Once a DPMI client program has done an initial switch to
protected-mode, it must be terminated by an int 21h, ah=4Ch call
in this mode. If the debugger becomes active in real-mode while
the debuggee is still running in protected-mode, the Q command
should not be used, since the DPMI host won't be able to do the
necessary clean-up work.
]
---
The Register command (R), when used without a parameter, causes
DEBUG to display the contents of the target program's CPU registers.
The optional register parameter will cause DEBUG to display the
contents of the register and prompt for a new value. When DEBUG
displays the contents of the registers, it encodes the processor
flags as follows:
Flag Set Clear
-----------------------------
Overflow OV NV
Direction DN UP
Interrupt EI DI
Sign NG PL
Zero ZR NZ
Auxiliary Carry AC NA
Parity PE PO
Carry CY NC
Syntax: R [register]
[ENH: if the register argument is given, it can be immediately
followed by the new value . No prompt will appear then.
Syntax: R [register] [value]
The processor flags can be changed in two ways. The first syntax changes
individual flags:
-R F [OV|NV|DN|UP|EI|DI|NG|PL|ZR|NZ|AC|NA|PE|PO|CY|NC]
the other syntax will set the [E]FL register:
-R [E]FL <[d]word value>
---
DebugX only: The RM command displays MMX registers.
The content is displayed from low to high bytes!
Syntax: RM
---
The RN command display the content of the floating point registers. DebugX
renders the content of these registers in "readable" floating point format,
DEBUG displays the content in raw hex format (because the rendering code
requires quite some space and DEBUG is intended to be kept small in size).
Syntax: RN
---
The RX command is active if the current cpu is a 80386 or better. Then
RX will toggle between the simple 16bit register display (which is the
default) and the full 32bit register display.
Syntax: RX
---
]
Search (S) is used to find the occurrence of a specific byte or series
of bytes within a segment. For example, to find all occurrences of 'CD 21'
in memory region DS:100-1FF, enter:
-S 100 l 100 CD 21
1234:0122
1234:01EC
Or, to find all strings "hello" in DS:0100-FFFF, enter
-S 100 FFFF 'hello'
1234:0122
1234:1221
1234:EADC
Syntax: S range list
---
The Trace command (T), when used without a parameter, causes DEBUG
to execute the instruction at CS:IP. Before the instruction is
executed, the contents of the register variables are copied to the
actual CPU registers. After the instruction has executed, and updated
the actual CPU registers (including IP), the contents of the actual
CPU registers are copied back to the register variables and the
contents of these variables are displayed. The optional address
parameter can be used to specify the starting address. The optional
count parameter can be used to specify the number of instructions to
execute. To differentiate the address parameter from the count
parameter, the address parameter must be preceded with an "=". Note
that the first byte at the specified address must be the start of a
valid instruction.
Syntax: T [=address] [number]
[ENH: if the current CS:IP points to an INT opcode, Debug/X's
behaviour depends on the current value of the TM option. If it
is 0 (the default), the debugger will regain control when the
INT has been processed. If TM is 1, the debugger will step "into"
the INT.
Furthermore, autorepeat is active for T. That is, if the last
command was T, a single ENTER will count as a repeated T command.
DebugX: the Trace command - internally, on certain conditions - has to
set a breakpoint. This may be achieved by 2 ways - either write an
INT 3 opcode to the code address or - if the cpu is at least an 80386 -
use a "hardware debug register". The first approach fails if the memory
cannot be written - in protected-mode a "page fault" will occur.
Therefore - if the DPMI host supports the feature - DebugX will prefer
to use the second method in protected-mode and true real-mode. This
feature may be suppressed by the /s cmdline option.
]
---
The Unassemble command (U), when used without any parameter, causes
DEBUG to read approximately 32 bytes of memory starting at the initial
CS:IP values specified in the file header if an EXE file is loaded,
or starting at CS:100h if any other type of file or no file is loaded.
For each instruction in this memory, DEBUG disassembles (translates
from machine code to assembly language) the instruction and displays
the address, the machine code, and the corresponding assembly language.
The optional range parameter can be used to specify a starting address,
or a starting and ending address, or a starting address and a length.
Subsequent Unassemble commands without any parameter cause DEBUG to
start at the instruction following the last instruction processed by
the previous Unassemble command.
[ENH: Autorepeat is active for U. That is, if the last command
was U, a single ENTER will count as a repeated U command.]
Syntax: U [range]
---
The Write command (W) causes DEBUG to write BX:CX bytes to the output
file. The optional address parameter specifies the starting source
address. The default starting source address is 100h. Note that
loading a file from the DEBUG command line or with the Load command
will set BX:CX to the size of the file, a feature clearly intended
to aid in the patching of executables. DEBUG rejects to write .EXE
( or .HEX ) files, since it would write it in invalid format without
header, but this security check is based just upon the file extension,
which isn't fool-proved at all.
Syntax: W [address]
---
The Write command can also be used to write one or more logical
sectors to a disk drive. The drive should be specified as for
the Load command.
Syntax: W address drive startsector numberofsectors
WARNING: You should know what you are doing when using this command.
If used inappropriately, W can cause severe data losses.
[ENH: W with logical sectors on Windows XP will work for DebugX only,
with the help of VDD DEBXXVDD.DLL.
While in protected-mode, writing files is rejected; if sectors are
to be written, DEBUG checks if a DOS extender is active and if yes,
the command is executed.
]
---
4. Format of Displays by Trace, Proceed, Register Commands
----------------------------------------------------------
For the Trace, Proceed, and Register commands, after DEBUG completes
the operations described above, it disassembles the next instruction
and displays the address of the instruction, the machine code, and
the corresponding assembly language. For the Trace and Proceed
commands, if the instruction contains a memory operand, DEBUG displays
the address that the operand refers to and the contents of that
address. The segment register specified in the address is the default
segment register for the instruction, or the segment register
specified by a segment override.
One perhaps non-obvious use for the Register command would be to
control the starting address for the next Trace or Proceed command
by loading a new value into CS and/or IP. And along the same lines,
non-obvious uses for the Assemble and Enter commands would be to
alter the instructions and/or data for the program being debugged.
5. Unassemble Format
--------------------
When DEBUG processes a Trace, Proceed, Register, or Unassemble command,
it displays assembly language (as described above) for any byte value
or sequence of byte values that it recognizes as a valid instruction.
For any other byte value, DEBUG displays the DB pseudoinstruction
followed by the byte value. DEBUG may fail to recognize a byte value
as part of a valid instruction for any of the following reasons:
The byte is part of an instruction that is specific to a later
generation x86 processor.
The disassembly process did not start at the first byte of a
valid instruction.
The byte is data.
Note that DEBUG's ability to execute an instruction (for the Trace
and Proceed commands) does not depend on its ability to recognize the
instruction.
6. Instruction operands
-----------------------
The instruction operands are the objects on which the instruction
"operates". For DEBUG, these objects can be constants, registers, or
memory. A memory operand specifies the offset address of the data to
operate on. To differentiate memory operands from constants, memory
operands must be enclosed in square brackets.
For a direct memory operand, the offset address of the data is
specified in the operand. For an indirect memory operand, the offset
address of the data is calculated at run-time using the contents of
one or two registers and an optional displacement. In 16bit code, the
registers can be a base register (BX or BP) or an index register (SI or DI),
or one of each. The following examples illustrate the differences
between constant operands, register operands, direct memory operands,
and indirect memory operands:
MOV AX,100 ; Moves the value 100 into AX
MOV AX,BX ; Copies the value in BX to AX
MOV AX,[100] ; Copies the word at DS:100 to AX
MOV AL,[BP+2]; Copies the byte at SS:BP+2 to AL
JMP 100 ; Destination offset is 100
JMP AX ; Destination offset is the value in AX
JMP [100] ; Destination offset is the word at DS:100
JMP [BX] ; Destination offset is the word at DS:BX
JMP [BX+4] ; Destination offset is the word at DS:BX+4
; Near calls work just like the jump instructions above.
7. DEBUG statements in Assembly Mode
------------------------------------
This section deals with the statements that DEBUG recognizes while
in assembly mode.
Each statement occupies a single line. For each statement, the first
character that is not a space or a tab must be a semicolon or the
start of a valid instruction mnemonic. A semicolon, at the start of
a statement or anywhere within a statement, causes DEBUG to ignore
the remainder of the line.
As previously noted, DEBUG recognizes only hex numbers (without a
trailing "H").
As previously noted, memory operands must be enclosed in square
brackets.
Segment override prefixes must be placed on the line preceding the
prefixed instruction. For example:
ES:
MOV AX,[100]
[ENH: the following syntax is also accepted:
SEG ES
MOV AX,[100]
or
MOV AX,ES:[100]
]
In addition to the items detailed above, DEBUG statements can include
the following:
The CPU register names (other than IP):
AX BX CX DX
AL AH BL BH CL CH DL DH
SP BP
SI DI
CS ES DS SS
[ENH: if cpu is 80386 or better, the extended registers are
recognised as well: EAX, EBX, ECX, EDX, ESP, EBP, ESI, EDI.
Furthermore, there are 2 new segment registers, FS and GS.]
The words NEAR (or NE) and FAR, optionally followed by PTR,
which are used to override the default forms of the CALL and JMP
instructions. The default form of a JMP instruction can be short,
near, or far, depending on the destination. The default form of a
CALL instruction can be near or far, depending on the destination.
Note that DEBUG will default to far only if the destination is
recognizable as a far address, which means that it must be a
constant of the form segment:offset (for example, "JMP F000:FFF0").
If the destination is specified by a memory operand (for example,
"JMP [100]"), DEBUG will default to near. The optional PTR has
no effect on the assembly process.
The words BYTE (or BY) and WORD (or WO) [ENH: and DWORD (or DW)],
optionally followed by PTR, which are used to specify the type for
memory data. For instructions that take two operands, DEBUG will
assume that the type for the data specified by a memory operand matches
the type for the other operand. For instructions that take one operand,
the type must be specified. The optional PTR has no effect on
the assembly process.
[ENH: for floating point opcodes, there exist 3 additional memory
types, FLOAT (or FL), DOUBLE (or DO) and TBYTE (or TB):
FLD FLOAT [100]
FSTP DOUBLE [100]
FSTP TBYTE [100]
]
The DB / DW pseudoinstructions, which are used to assemble byte / word
values [ENH: DD for dword values] . These pseudoinstructions are
normally used to set aside space for and initialize data. They can also
be used to synthesize instructions that DEBUG cannot assemble. Note
that DEBUG will not allow a trailing comment on the same line as one of
these pseudoinstructions.
The word ORG, used to set (or change) the starting address for the
assembly of instructions. Note that ORG may not be supported by
early versions of MS-Debug.
DEBUG checks for errors as it assembles each statement. If an error
is detected, DEBUG stops assembling the statement and displays
"^ Error" on the line following the statement. The position of the
caret indicates the location in the statement where DEBUG detected
the error.
8. Debugging with DebugX
------------------------
DebugX is able to debug both standard real-mode and DPMI protected-mode
applications. The DPMI applications may be either 16-bit or 32-bit.
For this to achieve DebugX has to intrude into the DPMI host's address
space when a new DPMI client starts. This is the first obstacle for
DebugX and whether it works smoothly depends on the DPMI host. NT's
DOSX.EXE works pretty well; the same is true for HDPMI or CWSDPMI. Less
good work the hosts implemented in Windows 9X or DOSEMU; on those platforms
it's required that DebugX traces through the initial switch to protected-
mode, else it will loose control of its debuggee.
Another problem may arise in true DOS: a protected-mode application
may launch its DPMI host on the fly during startup. To allow DebugX to
intrude in such a host, it has to intercept interrupt 2Fh AFTER the
DPMI host has been installed, but BEFORE the debuggee inquires the
DPMI host's entry point. This is pretty advanced stuff and to avoid
those quirks it's usually the best option to install the DPMI host
before DebugX is started.
During debugging, DebugX may become active in both protected-mode and
real-mode - it is a bimodal application, in this regard rather unique.
While the debugger is active in protected-mode, it may display faults
that happen when one tries to display memory that is inaccessible;
such faults usually can be safely ignored. However, on NT platforms
the debugger isn't notified of page faults - instead, the DOS session
usually just will be terminated.
As it has been mentioned at the Q command: when the debuggee is in
protected-mode, the behavior of DebugX's Q command differs from that
in real-mode: it won't exit the debugger session, but just exit
protected-mde, that is, terminate the DPMI client and fall back to
the real-mode prompt. Another Q cmd will then quit the debugger.
Sometimes Q may not work to exit protected-mode, then one can try
to forcably terminate the debuggee with the command variant QQ.
If a second video adapter is available, DebugX may be told to display
its output to that device via the /2 cmdline option. This gives DebugX
the ability to debug graphics applications.
Some DOS extenders may set code section pages to readonly. Up to v2.50
this did pretty reliably prevent DebugX from setting its breakpoints. Since
v2.50, Debug/X may prefer to use hardware breakpoints - and thus avoid
such problems.
9. Installing and Initializing DebugB
-------------------------------------
DebugB is a variant of DEBUG that can be used to debug boot code and DOS
during its initialization ( actually, because it doesn't depend on any DOS
interrupts, this variant is not restricted to DOS ) . Since the debugger has
to be in memory before the OS is loaded, there's a problem: since no file
system is available yet, how to load the debugger itself? There are two
approaches:
1) the DebugB file is stored somewhere on disk where it can be loaded
rather comfortably by the bootstrap code ( of either the MBR or the
partition's boot sector ), without using a file system. For FAT file
systems, this could be the "reserved" region, just behind the FAT boot
sector(s). With this approach, the bootstrap code itself has to be
modified - it has to load the debugger and then issue a far call to
initialize it.
The size of the DebugB binary may vary depending on what features are
activated, usually it's about 20 kB or 40 sectors of 512 bytes.
2) the debugger is loaded into memory above conventional memory just before
the system does a (soft) reboot. This requires that