2 TITLE DEBCOM1
.ASM
- PART1 DEBUGGER COMMANDS PC DOS
3 ;======================= START OF SPECIFICATIONS =========================
5 ; MODULE NAME: DECOM1.SAL
7 ; DESCRIPTIVE NAME: DEBUGGING TOOL
9 ; FUNCTION: PROVIDES USERS WITH A TOOL FOR DEBUGGING PROGRAMS.
11 ; ENTRY POINT: ANY CALLED ROUTINE
19 ; INTERNAL REFERENCES:
21 ; EXTERNAL REFERENCES:
23 ; ROUTINE: DEBCOM2 - CONTAINS ROUTINES CALLED BY DEBUG
24 ; DEBCOM3 - CONTAINS ROUTINES CALLED BY DEBUG
25 ; DEBASM - CONTAINS ROUTINES CALLED BY DEBUG
26 ; DEBUASM - CONTAINS ROUTINES CALLED BY DEBUG
27 ; DEBMES - CONTAINS ROUTINES CALLED BY DEBUG
29 ; NOTES: THIS MODULE IS TO BE PREPPED BY SALUT WITH THE "PR" OPTIONS.
30 ; LINK DEBUG+DEBCOM1+DEBCOM2+DEBCOM3+DEBASM+DEBUASM+DEBERR+
31 ; DEBCONST+DEBDATA+DEBMES
35 ; AN000 VERSION 4.00 - REVISIONS MADE RELATE TO THE FOLLOWING:
37 ; - IMPLEMENT DBCS HANDLING DMS:6/17/87
38 ; - IMPLEMENT MESSAGE RETRIEVER DMS:6/17/87
39 ; - IMPLEMENT > 32MB SUPPORT DMS:6/17/87
41 ; COPYRIGHT: "MS DOS DEBUG UTILITY"
42 ; "VERSION 4.00 (C) COPYRIGHT 1988 Microsoft"
43 ; "LICENSED MATERIAL - PROPERTY OF Microsoft "
45 ;======================= END OF SPECIFICATIONS ===========================
47 ; Routines to perform debugger commands except ASSEMble and UASSEMble
50 %
OUT COMPONENT
=DEBUG
, MODULE
=DEBCOM1
59 CODE SEGMENT PUBLIC BYTE
62 CONST
SEGMENT PUBLIC BYTE
64 EXTRN DISPB
:WORD,DSIZ
:BYTE,DSSAVE
:WORD
66 EXTRN CIN
:DWORD,PFLAG
:BYTE
73 DATA SEGMENT PUBLIC BYTE
74 EXTRN DEFLEN
:WORD,BYTEBUF
:BYTE,DEFDUMP
:BYTE
75 EXTRN ARG_BUF
:BYTE,ARG_BUF_PTR
:BYTE
76 EXTRN ONE_CHAR_BUF
:BYTE,ONE_CHAR_BUF_PTR
:WORD
79 DG GROUP
CODE,CONST
,CSTACK
,DATA
81 CODE SEGMENT PUBLIC BYTE
82 ASSUME
CS:DG
,DS:DG
,ES:DG
,SS:DG
83 PUBLIC HEXCHK
,GETHEX1
,PRINT
,DSRANGE
,ADDRESS
,HEXIN
,PERROR
84 PUBLIC GETHEX
,GET_ADDRESS
,GETEOL
,GETHX
,PERR
85 PUBLIC PERR
,MOVE
,DUMP
,ENTERDATA
,FILL
,SEARCH
,DEFAULT
88 EXTRN DISPREG
:NEAR,DEVIOCALL
:NEAR
90 EXTRN CRLF
:NEAR,OUTDI
:NEAR,OUTSI
:NEAR,SCANP
:NEAR
91 EXTRN SCANB
:NEAR,BLANK
:NEAR,TAB
:NEAR,COMMAND
:NEAR
92 EXTRN HEX
:NEAR,BACKUP
:NEAR
93 EXTRN PRINTF_CRLF
:NEAR,HEX_ADDRESS_ONLY
:NEAR,HEX_ADDRESS_STR
:NEAR
96 ; RANGE - Looks for parameters defining an address range.
97 ; The first parameter is the starting address. The second parameter
98 ; may specify the ending address, or it may be preceded by
99 ; "L" and specify a length (4 digits max), or it may be
100 ; omitted and a length of 128 bytes is assumed. Returns with
101 ; segment in AX, displacement in DX, and length in CX.
103 MOV BP,[DSSAVE
] ; Set default segment to DS
104 MOV [DEFLEN
],128 ; And default length to 128 bytes
108 PUSH AX ; Save segment
109 PUSH DX ; Save offset
110 CALL SCANP
; Get to next parameter
113 CMP AL,UPPER_L
; Length indicator?
116 MOV DX,[DEFLEN
] ; Default length
117 CALL HEXIN
; Second parameter present?
119 JC GETDEF
; If not, use default
122 CALL GETHEX
; Get ending address (same segment)
124 MOV CX,DX ; Low 16 bits of ending addr.
125 POP DX ; Low 16 bits of starting addr.
126 SUB CX,DX ; Compute range
130 JMP PERROR
; Negative range
132 INC CX ; Include last location
133 ; JCXZ DSRNG1 ; Wrap around error
134 ; Removing this instruction allows 0 FFFF to valid range
135 POP AX ; Restore segment
138 POP CX ; get original offset
140 NEG CX ; rest of segment
141 JZ RNGRET
; use default
143 CMP CX,DX ; more room in segment?
144 JAE RNGRET
; yes, use default
146 JMP RNGRET1
; no, length is in CX
149 INC SI ; Skip over "L" to length
150 MOV CX,4 ; Length may have 4 digits
151 CALL GETHEX
; Get the range
162 JAE DSRNG1
; Look for wrap error
168 ; DI points to default address and CX has default length
171 JZ USEDEF
; Use default if no parameters
180 LODSW ; Get default displacement
182 LODSW ; Get default segment
185 ; Dump an area of memory in both hex and ASCII
189 MOV DI,OFFSET DG
:DEFDUMP
190 CALL DEFAULT
; Get range if specified
192 MOV DS,AX ; Set segment
195 MOV SI,DX ; SI has displacement in segment
196 PUSH SI ; save SI away
200 AND SI,AX ; convert to para number
201 MOV DI,OFFSET DG
:ARG_BUF
; Build the output str in arg_buf
202 CALL OUTSI
; display location
205 ; Determine where the registers display should begin.
206 MOV AX,SI ; move offset
207 MOV AH,3 ; spaces per byte
208 AND AL,DSIZ
; convert to real offset
209 MUL AH ; 3 char positions per byte of output
210 OR AL,AL ; at beginning?
211 JZ INROW
; if so, then no movement.
219 PUSH SI ; Save address for ASCII dump
221 CALL BLANK
; Space between bytes
223 LODSB ; Get byte to dump
224 CALL HEX
; and display it
226 POP DX ; DX has start addr. for ASCII dump
227 DEC CX ; Drop loop count
228 JZ ASCII
; If through do ASCII dump
231 TEST AL,DSIZ
; On row boundary?
234 PUSH DX ; Didn't need ASCII addr. yet
235 TEST AL,7 ; On 8-byte boundary?
238 MOV AL,CHAR_MINUS
; Mark every 8 bytes with "-"
243 CALL ASCII
; Show it in ASCII
245 MOV DI,OFFSET DG
:ARG_BUF
; Build the output str in arg_buf
246 CALL OUTSI
; Get the address at start of line
248 JMP INROW
; Loop until count is zero
250 ; Produce a dump of the ascii text characters. We take the current SI which
251 ; contains the byte after the last one dumped. From this we determine how
252 ; many spaces we need to output to get to the ascii column. Then we look at
253 ; the beginning address of the dump to tsee how many spaces we need to indent.
255 PUSH CX ; Save count of remaining bytes
256 ; Determine how many spaces to go until the ASCII column.
257 MOV AX,SI ; get offset of next byte
261 ; AX now has the number of bytes that we have displayed: 1 to Dsiz+1.
262 ; Compute characters remaining to be displayed. We *always* put the ASCII
263 ; dump in column 51 (or whereever)
264 SUB AL,10H
; get negative of number
266 NEG AL ; convert to positive
267 CBW ; convert to word
268 ; 3 character positions for each byte displayed.
272 ; Compute indent for ascii dump
280 ; Set up for true dump
285 LODSB ; Get ASCII byte to dump
287 JAE NOPRT
; Don't print RUBOUT or above
290 JAE PRIN
; print space through RUBOUT-1
293 MOV AL,CHAR_PERIOD
; If unprintable character
296 LOOP ASCDMP
; CX times
311 POP CX ; Restore overall dump len
312 MOV WORD PTR [DEFDUMP
],SI
313 MOV WORD PTR [DEFDUMP
+WORD],DS ; Save last address as def
317 ; Block move one area of memory to another Overlapping moves are performed
318 ; correctly, i.e., so that a source byte is not overwritten until after it has
321 CALL DSRANGE
; Get range of source area
323 PUSH CX ; Save length
324 PUSH AX ; Save segment
325 PUSH DX ; Save source displacement
326 CALL ADDRESS
; Get destination address (sam
328 CALL GETEOL
; Check for errors
331 MOV DI,DX ; Set dest. displacement
332 POP BX ; Source segment
334 MOV ES,AX ; Destination segment
336 CMP DI,SI ; Check direction of move
337 SBB AX,BX ; Extend the CMP to 32 bits
338 JB COPYLIST
; Move forward into lower mem.
340 ; Otherwise, move backward. Figure end of source and destination
341 ; areas and flip direction flag.
343 ADD SI,CX ; End of source area
344 ADD DI,CX ; End of destination area
345 STD ; Reverse direction
348 MOVSB ; Do at least 1 - Range is 1-1
350 REP MOVSB ; Block move
354 ; Fill an area of memory with a list values. If the list
355 ; is bigger than the area, don't use the whole list. If the
356 ; list is smaller, repeat it as many times as necessary.
358 CALL DSRANGE
; Get range to fill
360 PUSH CX ; Save length
361 PUSH AX ; Save segment number
362 PUSH DX ; Save displacement
363 CALL LIST
; Get list of values to fill w
365 POP DI ; Displacement in segment
368 CMP BX,CX ; BX is length of fill list
369 MOV SI,OFFSET DG
:BYTEBUF
; List is in byte buffer
372 JAE COPYLIST
; If list is big, copy part of
375 SUB CX,BX ; How much bigger is area than
376 XCHG CX,BX ; CX=length of list
377 PUSH DI ; Save starting addr. of area
378 REP MOVSB ; Move list into area
380 ; The list has been copied into the beginning of the
381 ; specified area of memory. SI is the first address
382 ; of that area, DI is the end of the copy of the list
383 ; plus one, which is where the list will begin to repeat.
384 ; All we need to do now is copy [SI] to [DI] until the
385 ; end of the memory area is reached. This will cause the
386 ; list to repeat as many times as necessary.
387 MOV CX,BX ; Length of area minus list
388 PUSH ES ; Different index register
389 POP DS ; requires different segment r
390 JMP SHORT COPYLIST
; Do the block move
392 ; Search a specified area of memory for given list of bytes.
393 ; Print address of first byte of each match.
395 CALL DSRANGE
; Get area to be searched
398 PUSH AX ; Save segment number
399 PUSH DX ; Save displacement
400 CALL LIST
; Get search list
402 DEC BX ; No. of bytes in list-1
403 POP DI ; Displacement within segment
405 POP CX ; Length to be searched
406 SUB CX,BX ; minus length of list
408 MOV SI,OFFSET DG
:BYTEBUF
; List kept in byte buffer
409 LODSB ; Bring first byte into AL
411 SCASB ; Search for first byte
412 LOOPNE DOSCAN
; Do at least once by using LO
414 JNZ RET1
; Exit if not found
416 PUSH BX ; Length of list minus 1
418 PUSH DI ; Will resume search here
419 REPE CMPSB ; Compare rest of string
420 MOV CX,BX ; Area length back in CX
421 POP DI ; Next search location
422 POP BX ; Restore list length
423 JNZ TTEST
; Continue search if no match
425 DEC DI ; Match address
426 CALL OUTDI
; Print it
428 INC DI ; Restore search address
429 CALL HEX_ADDRESS_ONLY
; Print the addresss
436 JMP SHORT SCAN
; Look for next occurrence
438 ; Get the next parameter, which must be a hex number.
439 ; CX is maximum number of digits the number may have.
441 ;=========================================================================
442 ; GETHX: This routine calculates the binary representation of an address
443 ; entered in ASCII by a user. GETHX has been modified to provide
444 ; support for sector addresses > 32mb. To do this the bx register
445 ; has been added to provide a 32 bit address. BX is the high word
446 ; and DX is the low word. For routines that rely on DX for a 16
447 ; bit address, the use of BX will have no effect.
450 ;=========================================================================
455 XOR DX,DX ; Initialize the number
456 xor bx,bx ;an000;initialize high word for
458 CALL HEXIN
; Get a hex digit
460 JC HXERR
; Must be one valid digit
462 MOV DL,AL ; First 4 bits in position
464 INC SI ; Next char in buffer
466 CALL HEXIN
; Get another hex digit?
468 JC RETHX
; All done if no more digits
471 JCXZ HXERR
; Too many digits?
474 call ADDRESS_32_BIT
;an000;multiply by 32
475 JMP SHORT GETLP
; Get more digits
478 CALL GETHX
; Scan to next parameter
491 ; Check if next character in the input buffer is a hex digit
492 ; and convert it to binary if it is. Carry set if not.
495 ; Check if AL is a hex digit and convert it to binary if it
496 ; is. Carry set if not.
498 SUB AL,CHAR_ZERO
; Kill ASCII numeric bias
506 SUB AL,7 ; Kill A-F bias
515 ; Process one parameter when a list of bytes is
516 ; required. Carry set if parameter bad. Called by LIST.
518 CALL SCANP
; Scan to parameter
520 CALL HEXIN
; Is it in hex?
522 JC STRINGCHK
; If not, could be a string
524 MOV CX,2 ; Only 2 hex digits for bytes
525 push bx ;an000;save it - we stomp it
526 CALL GETHEX
; Get the byte value
527 pop bx ;an000;restore it
529 MOV [BX],DL ; Add to list
532 CLC ; Parameter was OK
536 MOV AL,[SI] ; Get first character of param
537 CMP AL,SINGLE_QUOTE
; String?
540 CMP AL,DOUBLE_QUOTE
; Either quote is all right
543 STC ; Not string, not hex - bad
546 MOV AH,AL ; Save for closing quote
549 LODSB ; Next char of string
550 CMP AL,CR
; Check for end of line
551 JZ PERR
; Must find a close quote
553 CMP AL,AH ; Check for close quote
554 JNZ STOSTRG
; Add new character to list
556 CMP AH,[SI] ; Two quotes in a row?
557 JNZ GRET
; If not, we're done
559 INC SI ; Yes - skip second one
561 MOV [BX],AL ; Put new char in list
563 JMP SHORT STRNGLP
; Get more characters
565 ; Get a byte list for ENTER, FILL or SEARCH. Accepts any number
566 ; of 2-digit hex values or character strings in either single
567 ; (') or double (") quotes.
569 MOV BX,OFFSET DG
:BYTEBUF
; Put byte list in the byte buffer
571 CALL LISTITEM
; Process a parameter
573 JNC LISTLP
; If OK, try for more
575 SUB BX,OFFSET DG
:BYTEBUF
; BX now has no. of bytes in list
576 JZ PERROR
; List must not be empty
578 ; Make sure there is nothing more on the line except for
579 ; blanks and carriage return. If there is, it is an
580 ; unrecognized parameter and an error.
582 CALL SCANB
; Skip blanks
584 JNZ PERROR
; Better be a RETURN
588 ; Command error. SI has been incremented beyond the command letter so it must
589 ; decremented for the error pointer to work.
592 ; Syntax error. SI points to character in the input buffer which caused
593 ; error. By subtracting from start of buffer, we will know how far to tab
594 ; over to appear directly below it on the terminal. Then print "^ Error".
596 SUB SI,OFFSET DG
:(BYTEBUF
-1) ; How many char processed so far?
597 MOV CX,SI ; Parameter for TAB in CX
598 MOV DI,OFFSET DG
:ARG_BUF
;
599 CALL TAB
; Directly below bad char
601 MOV BYTE PTR [DI],0 ; nul terminate the tab
602 MOV DX,OFFSET DG
:SYNERR_PTR
; Error message
603 ; Print error message and abort to command level
609 ; Gets an address in Segment:Displacement format. Segment may be omitted
610 ; and a default (kept in BP) will be used, or it may be a segment
611 ; register (DS, ES, SS, CS). Returns with segment in AX, OFFSET in DX.
633 MOV AX,BP ; Get default segment
634 CMP BYTE PTR [SI],CHAR_COLON
639 INC SI ; Skip over ":"
652 MOV DI,OFFSET DG
:SEGLET
; SEGLET DB "CSED"
661 CMP BYTE PTR [SI],CHAR_COLON
667 SEGLET
DB "CSED" ; First letter of each of the segregs: CS,SS,ES,DS
669 ; Short form of ENTER command. A list of values from the
670 ; command line are put into memory without using normal
673 CALL LIST
; Get the bytes to enter
675 POP DI ; Displacement within segment
676 POP ES ; Segment to enter into
677 MOV SI,OFFSET DG
:BYTEBUF
; List of bytes is in byte buffer
678 MOV CX,BX ; Count of bytes
679 REP MOVSB ; Enter that byte list
682 ; Enter values into memory at a specified address. If the line contains
683 ; nothing but the address we go into "enter mode", where the address and its
684 ; current value are printed and the user may change it if desired. To change,
685 ; type in new value in hex. Backspace works to correct errors. If an illegal
686 ; hex digit or too many digits are typed, the bell is sounded but it is
687 ; otherwise ignored. To go to the next byte (with or without change), hit
688 ; space bar. To back CLDto a previous address, type "-". On every 8-byte
689 ; boundary a new line is started and the address is printed. To terminate
690 ; command, type carriage return.
691 ; Alternatively, the list of bytes to be entered may be included on the
692 ; original command line immediately following the address. This is in regular
693 ; LIST format so any number of hex values or strings in quotes may be entered.
695 MOV BP,[DSSAVE
] ; Set default segment to DS
698 PUSH AX ; Save for later
700 CALL SCANB
; Any more parameters?
702 JNZ GETLIST
; If not end-of-line get list
704 POP DI ; Displacement of ENTER
707 CALL OUTDI
; Print address of entry
713 MOV DI,OFFSET DG
:ARG_BUF
723 MOV AL,ES:[DI] ; Get current value
728 MOV DI,OFFSET DG
:ARG_BUF
729 CALL HEX
; And display it
735 MOV DX,OFFSET DG
:ARG_BUF_PTR
741 MOV CX,2 ; Max of 2 digits in new value
742 MOV DX,0 ; Intial new value
744 CALL INPT
; Get digit from user
747 CALL HEXCHK
; Hex digit?
749 XCHG AH,AL ; Need original for echo
750 JC NOHEX
; If not, try special command
752 MOV DH,DL ; Rotate new value
753 MOV DL,AH ; And include new digit
754 LOOP GETDIG
; At most 2 digits
756 ; We have two digits, so all we will accept now is a command.
758 CALL INPT
; Get command character
760 CMP AL,CHAR_BACKSPACE
; Backspace
763 CMP AL,CHAR_RUBOUT
; RUBOUT
766 CMP AL,CHAR_MINUS
; Back up to previous address
769 CMP AL,CR
; All done with command?
772 CMP AL,CHAR_BLANK
; Go to next address
775 MOV AL,CHAR_BACKSPACE
776 CALL OUT_CHAR
; Back up over illegal character
785 MOV AL,CHAR_BACKSPACE
788 CMP CL,2 ; CX=2 means nothing typed yet
789 JZ PUTDOT
; Put back the dot we backed up over
791 INC CL ; Accept one more character
792 MOV DL,DH ; Rotate out last digit
793 MOV DH,CH ; Zero this digit
794 CALL BACKUP
; Physical backspace
796 JMP SHORT GETDIG
; Get more digits
804 ; If new value has been entered, convert it to binary and
805 ; put into memory. Always bump pointer to next location
807 CMP CL,2 ; CX=2 means nothing typed yet
808 JZ NOSTO
; So no new value to store
810 ; Rotate DH left 4 bits to combine with DL and make a byte value
815 OR DL,DH ; Hex is now converted to binary
816 MOV ES:[DI],DL ; Store new value
818 INC DI ; Prepare for next location
822 CALL STORE ; Enter new value
824 INC CX ; Leave a space plus two for
825 INC CX ; each digit not entered
827 MOV DI,OFFSET DG
:ARG_BUF
835 MOV DX,OFFSET DG
:ARG_BUF_PTR
840 MOV AX,DI ; Next memory address
841 AND AL,7 ; Check for 8-byte boundary
842 JZ NEWROW
; Take 8 per line
847 CALL CRLF
; Terminate line
849 JMP GETROW
; Print address on new line
852 CALL STORE ; Enter the new value
854 ; DI has been bumped to next byte. Drop it 2 to go to previous addr
857 JMP SHORT NEWROW
; Terminate line after backing CLD
860 CALL STORE ; Enter the new value
862 JMP CRLF
; CR/LF and terminate
864 ; Console input of single character
866 INPT: ;*** change for build - label to inpt
878 INT VEC_CTRL_BREAK
;23H
881 CMP AL,UPPER_P
- CHAR_AT_SIGN
884 CMP AL,UPPER_N
- CHAR_AT_SIGN
897 INPT: ; Change label for build
898 MOV AH,Std_Con_Input
;OPTION=1, STANDARD CONSOLE INPUT
910 MOV DI,OFFSET DG
:ONE_CHAR_BUF
914 MOV DX,OFFSET DG
:ONE_CHAR_BUF_PTR
922 ;=========================================================================
923 ; ADDRESS_32_BIT: This routine will build an address for 32bit sector
924 ; addressibility. BX will be the high word, with DX being
927 ; Inputs : DX/BX - registers to contain 32bit sector address
928 ; DX & BX are both initialized to 0 on first call to routine.
930 ; Outputs: DX/BX - registers to contain 32bit sector address
933 ;=========================================================================
935 ADDRESS_32_BIT proc
near ;an000;perform 32 bit address
937 push cx ;an000;save affected regs.
938 mov cx,04h ;an000;initialize to
940 ; $do ;an000;while cx not= 0
942 cmp cx,00h ;an000;are we done?
943 ; $leave e ;an000;yes, quit loop
945 shl bx,1 ;an000;shift bx 1 bit
946 shl dx,1 ;an000;shift dx 1 bit
947 ; $if c ;an000;did low word carry
949 or bx,01h ;an000;set bit 0 of high word
952 dec cx ;an000;decrease counter
953 ; $enddo ;an000;end while loop
956 or dl, al ;an000;overlay low word
958 ; portion of the address
959 pop cx ;an000;restore affected regs.
961 ret ;an000;return to caller
963 ADDRESS_32_BIT endp
;an000;end proc