1 TITLE PART1 DEBUGGER COMMANDS
3 ; Routines to perform debugger commands except ASSEMble and UASSEMble
12 CODE SEGMENT PUBLIC BYTE 'CODE'
15 CONST
SEGMENT PUBLIC BYTE
19 EXTRN DISPB
:WORD,DSIZ
:BYTE,DSSAVE
:WORD
21 EXTRN CIN
:DWORD,PFLAG
:BYTE
26 DATA SEGMENT PUBLIC BYTE
28 EXTRN DEFLEN
:WORD,BYTEBUF
:BYTE,DEFDUMP
:BYTE
32 DG GROUP
CODE,CONST
,DATA
35 CODE SEGMENT PUBLIC BYTE 'CODE'
36 ASSUME
CS:DG
,DS:DG
,ES:DG
,SS:DG
39 PUBLIC HEXCHK
,GETHEX1
,PRINT
,DSRANGE
,ADDRESS
,HEXIN
,PERROR
40 PUBLIC GETHEX
,GET_ADDRESS
,GETEOL
,GETHX
,PERR
41 PUBLIC PERR
,MOVE
,DUMP
,ENTER,FILL
,SEARCH
,DEFAULT
44 EXTRN DISPREG
:NEAR,DEVIOCALL
:NEAR
47 EXTRN OUT:NEAR,CRLF
:NEAR,OUTDI
:NEAR,OUTSI
:NEAR,SCANP
:NEAR
48 EXTRN SCANB
:NEAR,BLANK
:NEAR,TAB
:NEAR,PRINTMES
:NEAR,COMMAND
:NEAR
49 EXTRN HEX
:NEAR,BACKUP
:NEAR
54 ; RANGE - Looks for parameters defining an address range.
55 ; The first parameter is the starting address. The second parameter
56 ; may specify the ending address, or it may be preceded by
57 ; "L" and specify a length (4 digits max), or it may be
58 ; omitted and a length of 128 bytes is assumed. Returns with
59 ; segment in AX, displacement in DX, and length in CX.
62 MOV BP,[DSSAVE
] ; Set default segment to DS
63 MOV [DEFLEN
],128 ; And default length to 128 bytes
66 PUSH AX ; Save segment
68 CALL SCANP
; Get to next parameter
70 CMP AL,"L" ; Length indicator?
72 MOV DX,[DEFLEN
] ; Default length
73 CALL HEXIN
; Second parameter present?
74 JC GetDef
; If not, use default
76 CALL GETHEX
; Get ending address (same segment)
77 MOV CX,DX ; Low 16 bits of ending addr.
78 POP DX ; Low 16 bits of starting addr.
79 SUB CX,DX ; Compute range
81 DSRNG1: JMP PERROR
; Negative range
82 DSRNG2: INC CX ; Include last location
83 JCXZ DSRNG1
; Wrap around error
84 POP AX ; Restore segment
87 POP CX ; get original offset
89 NEG CX ; rest of segment
90 JZ RngRet
; use default
91 CMP CX,DX ; more room in segment?
92 JAE RngRet
; yes, use default
93 JMP RngRet1
; no, length is in CX
96 INC SI ; Skip over "L" to length
97 MOV CX,4 ; Length may have 4 digits
98 CALL GETHEX
; Get the range
107 JAE DSRNG1
; Look for wrap error
113 ; DI points to default address and CX has default length
115 JZ USEDEF
; Use default if no parameters
121 LODSW ; Get default displacement
123 LODSW ; Get default segment
126 ; Dump an area of memory in both hex and ASCII
131 MOV DI,OFFSET DG
:DEFDUMP
132 CALL DEFAULT
; Get range if specified
133 MOV DS,AX ; Set segment
134 MOV SI,DX ; SI has displacement in segment
137 PUSH SI ; save SI away
138 AND SI,0FFF0h ; convert to para number
139 CALL OutSI
; display location
141 MOV AX,SI ; move offset
142 MOV AH,3 ; spaces per byte
143 AND AL,0Fh ; convert to real offset
144 MUL AH ; compute (AL+1)*3-1
146 JZ InRow
; if xero go on
148 MOV CX,AX ; move to convenient spot
150 POP CX ; get back count
151 JMP InRow
; display line
155 CALL OUTSI
; Print address at start of line
157 PUSH SI ; Save address for ASCII dump
160 CALL BLANK
; Space between bytes
162 LODSB ; Get byte to dump
163 CALL HEX
; and display it
164 POP DX ; DX has start addr. for ASCII dump
165 DEC CX ; Drop loop count
166 JZ ToAscii
; If through do ASCII dump
168 TEST AL,CS:(BYTE PTR DSIZ
) ; On 16-byte boundary?
170 PUSH DX ; Didn't need ASCII addr. yet
171 TEST AL,7 ; On 8-byte boundary?
173 MOV AL,"-" ; Mark every 8 bytes
177 CALL ASCII
; Show it in ASCII
178 JMP SHORT ROW
; Loop until count is zero
180 MOV AX,SI ; get offset
181 AND AL,0Fh ; real offset
182 JZ ASCII
; no loop if already there
183 SUB AL,10h
; remainder
187 MOV CX,AX ; number of chars to move
190 PUSH CX ; Save byte count
191 MOV AX,SI ; Current dump address
192 MOV SI,DX ; ASCII dump address
193 SUB AX,DX ; AX=length of ASCII dump
195 ; Compute tab length. ASCII dump always appears on right side
196 ; screen regardless of how many bytes were dumped. Figure 3
197 ; characters for each byte dumped and subtract from 51, which
198 ; allows a minimum of 3 blanks after the last byte dumped.
200 SHL AX,1 ; Length times 2
201 ADD AX,BX ; Length times 3
203 SUB CX,AX ; Amount to tab in CX
205 MOV CX,BX ; ASCII dump length back in CX
207 MOV CX,SI ; get starting point
212 ADD CX,3 ; we have the correct number to tab
215 POP CX ; get count back
218 LODSB ; Get ASCII byte to dump
219 AND AL,7FH
; ASCII uses 7 bits
220 CMP AL,7FH
; Don't try to print RUBOUT
222 CMP AL," " ; Check for control characters
225 MOV AL,"." ; If unprintable character
227 CALL OUT ; Print ASCII character
228 LOOP ASCDMP
; CX times
229 POP CX ; Restore overall dump length
230 MOV ES:WORD PTR [DEFDUMP
],SI
231 MOV ES:WORD PTR [DEFDUMP
+2],DS ; Save last address as default
232 CALL CRLF
; Print CR/LF and return
236 ; Block move one area of memory to another. Overlapping moves
237 ; are performed correctly, i.e., so that a source byte is not
238 ; overwritten until after it has been moved.
241 CALL DSRANGE
; Get range of source area
242 PUSH CX ; Save length
243 PUSH AX ; Save segment
244 PUSH DX ; Save source displacement
245 CALL ADDRESS
; Get destination address (same segment)
246 CALL GETEOL
; Check for errors
248 MOV DI,DX ; Set dest. displacement
249 POP BX ; Source segment
251 MOV ES,AX ; Destination segment
253 CMP DI,SI ; Check direction of move
254 SBB AX,BX ; Extend the CMP to 32 bits
255 JB COPYLIST
; Move forward into lower mem.
256 ; Otherwise, move backward. Figure end of source and destination
257 ; areas and flip direction flag.
259 ADD SI,CX ; End of source area
260 ADD DI,CX ; End of destination area
261 STD ; Reverse direction
264 MOVSB ; Do at least 1 - Range is 1-10000H not 0-FFFFH
266 REP MOVSB ; Block move
269 ; Fill an area of memory with a list values. If the list
270 ; is bigger than the area, don't use the whole list. If the
271 ; list is smaller, repeat it as many times as necessary.
274 CALL DSRANGE
; Get range to fill
275 PUSH CX ; Save length
276 PUSH AX ; Save segment number
277 PUSH DX ; Save displacement
278 CALL LIST
; Get list of values to fill with
279 POP DI ; Displacement in segment
282 CMP BX,CX ; BX is length of fill list
283 MOV SI,OFFSET DG
:BYTEBUF
; List is in byte buffer
285 JAE COPYLIST
; If list is big, copy part of it
287 SUB CX,BX ; How much bigger is area than list?
288 XCHG CX,BX ; CX=length of list
289 PUSH DI ; Save starting addr. of area
290 REP MOVSB ; Move list into area
292 ; The list has been copied into the beginning of the
293 ; specified area of memory. SI is the first address
294 ; of that area, DI is the end of the copy of the list
295 ; plus one, which is where the list will begin to repeat.
296 ; All we need to do now is copy [SI] to [DI] until the
297 ; end of the memory area is reached. This will cause the
298 ; list to repeat as many times as necessary.
299 MOV CX,BX ; Length of area minus list
300 PUSH ES ; Different index register
301 POP DS ; requires different segment reg.
302 JMP SHORT COPYLIST
; Do the block move
304 ; Search a specified area of memory for given list of bytes.
305 ; Print address of first byte of each match.
308 CALL DSRANGE
; Get area to be searched
310 PUSH AX ; Save segment number
311 PUSH DX ; Save displacement
312 CALL LIST
; Get search list
313 DEC BX ; No. of bytes in list-1
314 POP DI ; Displacement within segment
316 POP CX ; Length to be searched
317 SUB CX,BX ; minus length of list
319 MOV SI,OFFSET DG
:BYTEBUF
; List kept in byte buffer
320 LODSB ; Bring first byte into AL
322 SCASB ; Search for first byte
323 LOOPNE DOSCAN
; Do at least once by using LOOP
324 JNZ RET1
; Exit if not found
325 PUSH BX ; Length of list minus 1
327 PUSH DI ; Will resume search here
328 REPE CMPSB ; Compare rest of string
329 MOV CX,BX ; Area length back in CX
330 POP DI ; Next search location
331 POP BX ; Restore list length
332 JNZ TEST ; Continue search if no match
333 DEC DI ; Match address
334 CALL OUTDI
; Print it
335 INC DI ; Restore search address
339 JMP SHORT SCAN
; Look for next occurrence
341 ; Get the next parameter, which must be a hex number.
342 ; CX is maximum number of digits the number may have.
347 XOR DX,DX ; Initialize the number
348 CALL HEXIN
; Get a hex digit
349 JC HXERR
; Must be one valid digit
350 MOV DL,AL ; First 4 bits in position
352 INC SI ; Next char in buffer
354 CALL HEXIN
; Get another hex digit?
355 JC RETHX
; All done if no more digits
357 JCXZ HXERR
; Too many digits?
358 SHL DX,1 ; Multiply by 16
362 OR DL,AL ; and combine new digit
363 JMP SHORT GETLP
; Get more digits
366 CALL GETHX
; Scan to next parameter
375 ; Check if next character in the input buffer is a hex digit
376 ; and convert it to binary if it is. Carry set if not.
381 ; Check if AL has a hex digit and convert it to binary if it
382 ; is. Carry set if not.
385 SUB AL,"0" ; Kill ASCII numeric bias
391 SUB AL,7 ; Kill A-F bias
398 ; Process one parameter when a list of bytes is
399 ; required. Carry set if parameter bad. Called by LIST.
402 CALL SCANP
; Scan to parameter
403 CALL HEXIN
; Is it in hex?
404 JC STRINGCHK
; If not, could be a string
405 MOV CX,2 ; Only 2 hex digits for bytes
406 CALL GETHEX
; Get the byte value
407 MOV [BX],DL ; Add to list
409 GRET: CLC ; Parameter was OK
412 MOV AL,[SI] ; Get first character of param
415 CMP AL,'"' ; Either quote is all right
417 STC ; Not string, not hex - bad
420 MOV AH,AL ; Save for closing quote
423 LODSB ; Next char of string
424 CMP AL,13 ; Check for end of line
425 JZ PERR
; Must find a close quote
426 CMP AL,AH ; Check for close quote
427 JNZ STOSTRG
; Add new character to list
428 CMP AH,[SI] ; Two quotes in a row?
429 JNZ GRET
; If not, we're done
430 INC SI ; Yes - skip second one
432 MOV [BX],AL ; Put new char in list
434 JMP SHORT STRNGLP
; Get more characters
436 ; Get a byte list for ENTER, FILL or SEARCH. Accepts any number
437 ; of 2-digit hex values or character strings in either single
438 ; (') or double (") quotes.
441 MOV BX,OFFSET DG
:BYTEBUF
; Put byte list in the byte buffer
443 CALL LISTITEM
; Process a parameter
444 JNC LISTLP
; If OK, try for more
445 SUB BX,OFFSET DG
:BYTEBUF
; BX now has no. of bytes in list
446 JZ PERROR
; List must not be empty
448 ; Make sure there is nothing more on the line except for
449 ; blanks and carriage return. If there is, it is an
450 ; unrecognized parameter and an error.
453 CALL SCANB
; Skip blanks
454 JNZ PERROR
; Better be a RETURN
457 ; Command error. SI has been incremented beyond the
458 ; command letter so it must decremented for the
459 ; error pointer to work.
464 ; Syntax error. SI points to character in the input buffer
465 ; which caused error. By subtracting from start of buffer,
466 ; we will know how far to tab over to appear directly below
467 ; it on the terminal. Then print "^ Error".
470 SUB SI,OFFSET DG
:(BYTEBUF
-1); How many char processed so far?
471 MOV CX,SI ; Parameter for TAB in CX
472 CALL TAB
; Directly below bad char
473 MOV SI,OFFSET DG
:SYNERR
; Error message
475 ; Print error message and abort to command level
481 ; Gets an address in Segment:Displacement format. Segment may be omitted
482 ; and a default (kept in BP) will be used, or it may be a segment
483 ; register (DS, ES, SS, CS). Returns with segment in AX, OFFSET in DX.
499 MOV AX,BP ; Get default segment
500 CMP BYTE PTR [SI],":"
504 INC SI ; Skip over ":"
513 MOV DI,OFFSET DG
:SEGLET
521 CMP BYTE PTR [SI],":"
528 ; Short form of ENTER command. A list of values from the
529 ; command line are put into memory without using normal
533 CALL LIST
; Get the bytes to enter
534 POP DI ; Displacement within segment
535 POP ES ; Segment to enter into
536 MOV SI,OFFSET DG
:BYTEBUF
; List of bytes is in byte 2uffer
537 MOV CX,BX ; Count of bytes
538 REP MOVSB ; Enter that byte list
541 ; Enter values into memory at a specified address. If the
542 ; line contains nothing but the address we go into "enter
543 ; mode", where the address and its current value are printed
544 ; and the user may change it if desired. To change, type in
545 ; new value in hex. Backspace works to correct errors. If
546 ; an illegal hex digit or too many digits are typed, the
547 ; bell is sounded but it is otherwise ignored. To go to the
548 ; next byte (with or without change), hit space bar. To
549 ; back CLDto a previous address, type "-". On
550 ; every 8-byte boundary a new line is started and the address
551 ; is printed. To terminate command, type carriage return.
552 ; Alternatively, the list of bytes to be entered may be
553 ; included on the original command line immediately following
554 ; the address. This is in regular LIST format so any number
555 ; of hex values or strings in quotes may be entered.
558 MOV BP,[DSSAVE
] ; Set default segment to DS
560 PUSH AX ; Save for later
562 CALL SCANB
; Any more parameters?
563 JNZ GETLIST
; If not end-of-line get list
564 POP DI ; Displacement of ENTER
567 CALL OUTDI
; Print address of entry
568 CALL BLANK
; Leave a space
571 MOV AL,ES:[DI] ; Get current value
572 CALL HEX
; And display it
575 CALL OUT ; Prompt for new value
576 MOV CX,2 ; Max of 2 digits in new value
577 MOV DX,0 ; Intial new value
579 CALL IN ; Get digit from user
581 CALL HEXCHK
; Hex digit?
582 XCHG AH,AL ; Need original for echo
583 JC NOHEX
; If not, try special command
584 MOV DH,DL ; Rotate new value
585 MOV DL,AH ; And include new digit
586 LOOP GETDIG
; At most 2 digits
587 ; We have two digits, so all we will accept now is a command.
589 CALL IN ; Get command character
595 CMP AL,"-" ; Back CLDto previous address
597 CMP AL,13 ; All done with command?
599 CMP AL," " ; Go to next address
602 CALL OUT ; Back CLDover illegal character
611 CMP CL,2 ; CX=2 means nothing typed yet
612 JZ PUTDOT
; Put back the dot we backed CLDover
613 INC CL ; Accept one more character
614 MOV DL,DH ; Rotate out last digit
615 MOV DH,CH ; Zero this digit
616 CALL BACKUP
; Physical backspace
617 JMP SHORT GETDIG
; Get more digits
619 ; If new value has been entered, convert it to binary and
620 ; put into memory. Always bump pointer to next location
623 CMP CL,2 ; CX=2 means nothing typed yet
624 JZ NOSTO
; So no new value to store
625 ; Rotate DH left 4 bits to combine with DL and make a byte value
630 OR DL,DH ; Hex is now converted to binary
631 MOV ES:[DI],DL ; Store new value
633 INC DI ; Prepare for next location
636 CALL STORE ; Enter new value
637 INC CX ; Leave a space plus two for
638 INC CX ; each digit not entered
640 MOV AX,DI ; Next memory address
641 AND AL,7 ; Check for 8-byte boundary
642 JNZ GETBYTE
; Take 8 per line
644 CALL CRLF
; Terminate line
645 JMP GETROW
; Print address on new line
647 CALL STORE ; Enter the new value
648 ; DI has been bumped to next byte. Drop it 2 to go to previous addr
651 JMP SHORT NEWROW
; Terminate line after backing CLD
654 CALL STORE ; Enter the new value
655 JMP CRLF
; CR/LF and terminate
657 ; Console input of single character