PAGE    ,132
NAME    DFCMD
TITLE   DFCMD.ASM - Dump Formatter Commands
.286p

;***    DFCMD.ASM
;
;       Routines to perform dump formatter commands.
;
;

.xlist
        include debseg.inc
        include debmac.inc
        include debequ.inc
        include debinit.inc
        include debdesc.inc
        include debsym.inc
.list

Extern checkchr, FAR
Extern GetSymbolBuf, NEAR

extrn   _DebCalloutRoutine:far
extrn   DosExit:far, _getdbit:far
extrn   DosBufReset:far
extrn   _CListNear:far

DATA    segment word public 'DATA'
include header.inc              ; read in version string for this build

        public  GDT_Buffers
GDT_Buffers     dw      0       ;;;;;;;;;;;;;;;HACK!!!!!!!!!!!!!!

; Command line entry point saved stuff
bpsave  dw  0
spsave  dw  0
essave  dw  0

Extern fFrontEnd,       WORD
Extern DebSASTable,     WORD
Extern DefType,         WORD
Extern DebData,         WORD
Extern DumpAddr,        WORD
Extern DefMode,         BYTE
Extern EnterAddr,       WORD
Extern DisAddr,         WORD
Extern pTXT,            WORD
Extern pTXTstart,       WORD
Extern CmdInputBuffer,  BYTE
Extern RegSA,           WORD
Extern StackTop,        WORD
ifdef CRSLATER
Extern fRegDisp,        BYTE
endif
Extern MemCache,        BYTE
Extern DebStackFence,   WORD
Extern CommandScriptAddrS,      BYTE
Extern CommandScriptSize,       WORD

Extern  Dump,           NEAR
Extern  Lists,          NEAR
Extern  WithMap,        NEAR
Extern  unassem,        NEAR
Extern  ChangeDefCmd,   NEAR
Extern  reg,            NEAR
; Buffer for symbol returns
SymbolBuf       db      (MAX_NAME_SIZE * 3) DUP (?)
;xtern  SymbolBuf,      BYTE


DEB_OPT_CLEARBIT        equ     0       ; clear bit/print if clear
DEB_OPT_SETBIT          equ     1       ; set bit /print if set
DEB_OPT_TOGGLEBIT_CLEAR equ     2       ; toggle bit/print if clear
DEB_OPT_TOGGLEBIT_SET   equ     3       ; toggle bit/print if set
DEB_OPT_WORD            equ     4       ; word value

OptionTableS    struc
        OptionName      dw      ?
        OptionAddr      dw      ?
        OptionBitMask   dw      ?
        OptionType      db      ?
OptionTableS    ends

DebOptHelp      label   byte
        db      "386env - 32 bit environment (toggles)", CR, LF
        db      "dislwr - lower case display (toggles)", CR, LF
        db      "regterse - terse register set (toggles)", CR, LF
        db      0

Static  Env386Str,      STRING, "386env"
Static  DisLwrStr,      STRING, "dislwr"
Static  RegTerseStr,    STRING, "regterse"

OptionTable     label   word
        OptionTableS    <dataOFFSET Env386Str, dataOFFSET DebData.InitFlag, INIT_ENV386, DEB_OPT_TOGGLEBIT_SET>
        OptionTableS    <dataOFFSET DisLwrStr, dataOFFSET DebData.InitFlag, INIT_DISLWR, DEB_OPT_TOGGLEBIT_SET>
        OptionTableS    <dataOFFSET RegTerseStr, dataOFFSET DebData.InitFlag, INIT_NOREGTERSE, DEB_OPT_TOGGLEBIT_CLEAR>
        OptionTableS    <0>

Static bytebuf,         BUFLEN, 0       ; Table used by LIST

;
; "?" (help) command message
;
; This is a table of null-terminated strings terminated by
; a string of length zero.

HelpMsg label   byte
        db      "C <range> <addr> - compare bytes", 0
        db      "D [<range>] - dump memory", 0
        db      "DA [<range>] - dump asciiz string", 0
        db      "DB [<range>] - dump memory in bytes", 0
        db      "DW [<range>] - dump memory in words", 0
        db      "DD [<range>] - dump memory in dwords", 0
        db      "DG[A] [<range>] - dump GDT entries", 0
        db      "DI[A] [<range>] - dump IDT entries", 0
        db      "DL[A|P|S|H] [<range>] - dump LDT entries", 0
        db      "DP[A|D] [<range>] - dump page directory/table entries", 0
        db      "DT [<addr>] - dump TSS", 0
        db      "H <word> <word> - hexadd", 0
        db      "K[S|B] [<SS:BPaddr>] [<CS:IPaddr>] - stack trace", 0
        db      "LG [<mapname>] - list groups in active maps", 0
        db      "LM - list linked and active maps", 0
        db      "LN [<addr>] - list near symbols", 0
        db      "LA [<mapname>] - list absolute symbols in active maps", 0
        db      "LS [<addr>] - list symbols in group", 0
        db      "R[T]|[<reg>] [[=] <word>] - register", 0
        db      "S <range> <list> - search", 0
;        db      "SOD <filename>", 0
        db      "U [<range>] - unassemble", 0
        db      "WA <mapname> | * - add a map to the active list", 0
        db      "WR <mapname> | * - remove a map from the active list", 0
;       db      "WL           | * - remove a map from the active list", 0
;        db      "Y[?] - display/modify formatter options", 0
;        db      "Z - execute the default command", 0
;        db      "ZL - list the default command", 0
;        db      "ZS - set the default command", 0
        db      ". - external commands, execute "".?"" for help", 0
        db      "? - print help menu", 0
        db      "? <expr> | ""string"" - display expression or string", 0
        db      "<range> = [<addr>] [<word>] | <addr> [L <word>]", 0
        db      "<addr> = [& | #][<word>:]<word> | %<dword> | %%<dword>", 0
        db      "<list> = <byte> <byte> ... | ""string""", 0
        db      "<binary ops> = : | * / MOD + . - < > >= <= AND XOR OR && ||", 0
        db      "<unary ops> = &seg #sel %lin %%phy @ ! NOT SEG OFF ", 0
        db      "BY WO DW POI PORT WPORT", 0
        db      0

;***    MoreMsg
;
;       MoreMsg is the help screen prompt.  BlankMsg is used to
;       erase MoreMsg and depends upon being just after MoreMsg in the
;       data segment.

MoreMsg db      "--More--", 0
BlankMsg db     0Dh, (BlankMsg - MoreMsg - 1) dup(' '), 0Dh, 0

;***    ComandTable
;
;       Command letter table and routine address. perr prints error for
;       no such command.
;

        EVEN

CommandTable    label   byte
    CmdTable_s <"W", codeOFFSET WithMap>        ; in debsym.asm
    CmdTable_s <"C", codeOFFSET compare>        ; in debcmd.asm
    CmdTable_s <"D", codeOFFSET Dump>           ; in debdcmd.asm
    CmdTable_s <"H", codeOFFSET hexadd>         ; in debcmd.asm
    CmdTable_s <"K", codeOFFSET DumpStack>      ; in dfcmd.asm
    CmdTable_s <"L", codeOFFSET Lists>          ; in debsym.asm
    CmdTable_s <"Q", codeOFFSET QuitCmd>        ; in dfcmd.asm
    CmdTable_s <"R", codeOFFSET reg>            ; in debrcmd.asm
    CmdTable_s <"S", codeOFFSET search>         ; in debcmd.asm
    CmdTable_s <"U", codeOFFSET unassem>        ; in debucmd.asm
    CmdTable_s <"Y", codeOFFSET DebOptions>     ; in debcmd.asm
    CmdTable_s <"Z", codeOFFSET ChangeDefCmd>   ; in debbcmd.asm
    CmdTable_s <"?", codeOFFSET PrintHelpOrExp> ; in dfcmd
    CmdTable_s <".", codeOFFSET DoExtCmd>       ; in dosext.asm
    CmdTable_s <0,   codeOFFSET perr>           ; end mark, error address

extrn _bIsDebug:word
extrn _ptrIDT:word
extrn _ourversion:byte

DATA    ends

_TEXT   segment dword public 'CODE'
        assume  cs:_TEXT, ds:DGROUP, es:DGROUP, ss:DGROUP


        extrn   DosExit:far, _getdbit:far

Entry DoCmd, FAR, PUBLIC
      mov    bpsave,bp              ; save the stack, es, and basepage
      mov    essave,es
      mov    spsave,sp
      jmp    RCmdBreak           ; now start doing commands

;***    ErrBreak - print error message and break
;
;       ENTRY:  (AX) = error code
;               (BX) = pointer to AddrS
;
;       NOTE:   Can't not reset sp to StackTop because
;               the AddrS BX points maybe trashed (because
;               it is may be a local variable on the stack).
;

Entry   ErrBreak, NEAR, PUBLIC
        Pcall   CommandReset            ; reset everything
        Pcall   crlf
        Pcall   PrintMemErr
        jmp     CmdBreak

;***    RCmdBreak - do "R" command and then stop
;
;       Used to break debugger when default command
;       doesn't stop.
;

Entry   RCmdBreak, NEAR, PUBLIC
; 04/14/93 davidj copied from cmdbreak
; Reset stack and ES in case we had to jump right here
;
;; I forced this here !!! crs
;        extrn   _DebCalloutRoutine:far
        mov     word ptr [DebSASTable.DSAS_HookPM+2], SEG _DebCalloutRoutine
        mov     word ptr [DebSASTable.DSAS_HookPM], OFFSET _DebCalloutRoutine
        Pcall   CommandReset            ; reset everything

        mov     di,dataOFFSET CmdInputBuffer
        mov     pTXT,di
        mov     pTXTstart,di

        mov     ax,"R"
        stosw
        jmp     command                 ; if ctrlc stop

;***    perr
;
;       Command error. [pTXT] has been incremented beyond the
;       command letter so it must decremented for the
;       error pointer to work.
;
Entry   perr,   NEAR, PUBLIC
;;      mov     sp,[StackTop]
        Pcall   CommandReset            ; reset everything
        dec     pTXT

;***    perror
;
;       Syntax error. [pTXT] points to character in the input buffer
;       which caused error. By subtracting from start of buffer,
;       we will know how far to tab over to appear directly below
;       it on the terminal. Then print "^ Error".
;
Entry   perror, NEAR, PUBLIC
;;      mov     sp,[StackTop]
        Pcall   CommandReset            ; reset everything
        mov     dx,pTXTstart            ; print line
        Pcall   rprbuf                  ;
        Pcall   crlf

;       tab over to bad character and print "^ Error" pointing at it.
;       (DX) = address of start of command line buffer

per2:   mov     cx,pTXT
        sub     cx,dx                   ; how many char so far
        jz      per3
        Pcall   tab                     ; directly below bad char
per3:   putstr  "^ Error"

;***    CmdBreak
;
;       Break from command flow, remove any commands in
;       line buffer and start command loop.
;
Entry   CmdBreak, NEAR, PUBLIC
;
; Reset stack and ES in case we had to jump right here
;
        mov     bp,bpsave
        mov     es,essave
        mov     sp,spsave

;; I forced this here !!! crs
;        extrn   _DebCalloutRoutine:far
        mov     word ptr [DebSASTable.DSAS_HookPM+2], SEG _DebCalloutRoutine
        mov     word ptr [DebSASTable.DSAS_HookPM], OFFSET _DebCalloutRoutine
;;
;;      mov     sp,[StackTop]
        Pcall   CommandReset            ; reset everything
        mov     di,dataOFFSET CmdInputBuffer
        mov     pTXT,di
        mov     pTXTstart,di

        Pcall   crlf
        xor     al,al
        stosb

;***    command
;
;       Command interpreter entry point.
;
;       ENTRY:  NONE
;
;       EXIT:   NONE
;
DefProc command, NEAR, PUBLIC
;;      mov     sp,[StackTop]

;; davidj 08/25/93 flush the pipe buffer
;;        push    1       ; STDOUT
;;        call    DosBufReset    ; print this string
;;
        Pcall   CommandReset            ; reset everything
        Pcall   DoCommandSub            ; do the command line
        mov     al,PPROMPT              ; (AL) = real-mode prompt
cmd20:  Pcall   put_ch

        test    word ptr _fFrontEnd,-1          ; are we cmd line or debugo?
        jz     @F
        mov     al,2                    ; (AL) = real-mode prompt
        Pcall   put_ch
        Pcall   crlf
;; davidj 09/27/93 flush the pipe buffer after the prompt
          push    1       ; STDOUT
          call    DosBufReset    ; print this string
;;

ifdef CRSLATER
        mov     fRegDisp,1              ; Print the full "R" command now
endif

@@:     Pcall   inbuf                   ; Get command line
        jmp     short command           ; Get next command

EndProc NoGen

;***    DoCommand
;
;       Save old text pointer, do a command and return (if no errors).
;
;       ENTRY:  SI = pointer to command line string (null terminated).
;
;       EXIT:   NONE
;
DefProc DoCommand, NEAR, PUBLIC
        SaveReg <pTXT,pTXTstart>        ; save old command line pointers
        mov     pTXTstart,si            ; put pointer to len byte in pTXTstart
        mov     pTXT,si                 ; put pointer to buffer in pTXT
        Pcall   DoCommandSub
        RestReg <pTXTstart,pTXT>        ; restore old text pointers
EndProc
;
; Init the ASM globals
;
DefProc InitASM, FAR, PUBLIC
        push    si
        mov     si,offset DebData.InitFlag
        mov     word ptr [si], INIT_ENV386 + INIT_DISLWR
;111005 - don't check for debug kernel yet, more init is required
;111005      Pcall   CheckDebug      ; see if Kernal is retail or debug
;
; Copy the useful part of the version string into our 'C'
; variable 'ourversion[]'
;
        push    ds
        pop     es      ; make sure ES points to our data segment
        cld             ; and the direction flag is forward
        lea     si,header       ; point to start of header string
@@:     cmp     word ptr [si],'nI'  ; search for 'Internal revision'
        jz      @F
        inc     si
        jmp short @B
@@:     lea     di,_ourversion
        mov     cx,40
        rep     movsb           ; copy the string to the 'C' variable

        xor     ax,ax           ; return with Happy code
        pop     si
EndProc

;***    CheckDebug
;
;       ENTRY:  NONE
;
;       EXIT:   _bIsDebug is updated
;
;       Determine if dump file is from a DEBUG or RETAIL kernel
;
;111005 DefProc CheckDebug, NEAR, PUBLIC
DefProc CheckDebug, FAR, PUBLIC ;111005 - make callable from C code
        lsl     ax,_ptrIDT+2    ; see if this is a valid selector
        jnz     cddz            ; if not, don't touch it
        push    es
        mov     es,_ptrIDT+2    ; point to the IDT
        mov     si,2            ; point to entry #0
        mov     ax,es:[si]
        cmp     ax,160h         ; must be a retail kernel
        jz      @F
        mov     _bIsDebug,1     ; kernel debugger
        jmp     cddx
@@:     mov     _bIsDebug,0     ; it's a retail kernel
cddx:   pop     es
cddz:
EndProc

;***    DoCommandSub
;
;       Do a command and return (if no errors).
;
;       ENTRY:  pTXT, pTXTstart set up.
;
;       EXIT:   NONE
;
DefProc DoCommandSub, NEAR, LOCAL
        push    bp
        mov     si,pTXT
        Pcall   StrUpr                  ; upper case command string

;       From now and throughout command line processing, [pTXT] points
;       to next character in command line to be processed.

dcd1:   Pcall   CommandReset            ; reset everything
        cmp     DebStackFence,STACK_FENCE_VALUE
        je      dcd2
        mov     DebStackFence,STACK_FENCE_VALUE
        putstr  <"Warning! Debugger stack overflow", CR, LF>

dcd2:   Pcall   GetChrI
        jnz     dcd3                    ; jump if not end of command

        or      al,al
        je      dcd4                    ; jump if no more commands on this line

;       Must be a ";", so skip it (GetChrI won't skip a ";").

        inc     pTXT
        jmp     short dcd2

;       AL = command letter

dcd3:   mov     si,dataOFFSET CommandTable
        Pcall   ExecSubr
        Pcall   GetEOL
        jmp     short dcd1

dcd4:   pop     bp
EndProc

;***    PrintHelpOrExp
;
;       Prints the help message if no arguments.
;
DefProc PrintHelpOrExp, NEAR, LOCAL

LocVar  TmpExpr, <size ExprS>
LocVar  TmpExpr2, <size ExprS>

BeginProc
        Pcall   ScanP
        jnz     short phe1
        mov     di,dataOFFSET HelpMsg           ; (DI) = string offset
        mov     cx,23                           ; (CX) = Lines per screen
hlp0:   push    cx
        mov     dx,di                           ; (DX) = string offset
        xor     al,al
        mov     cx,0FFFFh
        repne scasb                             ; Find next string
        cmp     cx,0FFFEh                       ; Previous string length 0?
        pop     cx
        je      hlp2                            ;  yes, done
        dec     cx                              ; Room for line on screen?
        jns     short hlp1                      ;  yes, skip ahead
        push    dx
        mov     dx,dataOFFSET MoreMsg
        Pcall   rprbuf                          ; Prompt user
        Pcall   waitchr                         ; (AL) = response
        mov     dx,dataOFFSET BlankMsg
        Pcall   rprbuf                          ; Erase prompt
        pop     dx
        cmp     al,'q'                          ; Quit help?
        je      short hlp2                      ;  yes, done
        mov     cx,22                           ; Assume full screen wanted
        cmp     al,0Dh                          ; One line wanted (<enter>)?
        jne     short hlp1                      ;  no, loop
        xor     cx,cx                           ; Do one line only
hlp1:   Pcall   rprbuf                          ; Print the line
        Pcall   crlf
        jmp     short hlp0                      ; Look for more
hlp2:   jmp     phe11

phe1:   Pcall   CheckString             ; check if output string
        jne     short phe2
        mov     di,dataOFFSET bytebuf
        Pcall   ParseString
        mov     dx,dataOFFSET bytebuf
        Pcall   rprbuf
        Pcall   crlf
        jmp     phe10

phe2:   lea     si,TmpExpr              ; (SI) = pointer to ExprS struc
        Pcall   EvalExpr

        cmp     TmpExpr.ExprType,EXPR_TYPE_DATA
        je      short phe3
        jmp     phe7

phe3:   xor     bh,bh
        mov     bl,TmpExpr.ExprSize     ; (BX) = expresion size
        shl     bx,1                    ; (BX) = number of hex digits

        mov     dx,TmpExpr.ExprData.LowWord
        mov     si,TmpExpr.ExprData.HighWord    ; (SI:DX) = data word

        Pcall   OutRadix, <dx, si, 16, bx, "0">
        mov     al,"H"
        Pcall   put_ch

        Pcall   blank
        Pcall   OutRadix, <dx, si, 10, 0, 0>
        mov     al,"T"
        Pcall   put_ch
        Pcall   blank
        Pcall   OutRadix, <dx, si, 8, 0, 0>
        mov     al,"Q"
        Pcall   put_ch
        Pcall   blank
        shl     bx,2                    ; convert to number of binary digits
        Pcall   OutRadix, <dx, si, 2, bx, "0">
        mov     al,"Y"
        Pcall   put_ch
        Pcall   blank
        mov     al,"'"
        Pcall   put_ch
        mov     al,dl                   ; get low byte of data
        cmp     al," "
        jb      short phe4
        cmp     al,7Fh
        jb      short phe5
phe4:   mov     al,"."

phe5:   Pcall   put_ch
        mov     al,"'"
        Pcall   put_ch

        lea     si,TmpExpr
        Pcall   GetExprS
        Pcall   IsTrue
        jnc     short phe6              ; jump if false
        putstr  <" TRUE">
        jmp     short phe10

phe6:   putstr  <" FALSE">
        jmp     short phe10

phe7:   lea     si,TmpExpr              ; (AX) = pointer to ExprS/AddrS struc
        cmp     [si].AddrTask,0
        jne     short phe8
        Pcall   GetCurrTask             ; (AX) = current task number
        mov     [si].AddrTask,ax
phe8:   Pcall   OutAddrS, <si>

        cmp     TmpExpr.AddrType,EXPR_TYPE_LIN
        je      phe9                    ; don't print if already linear

        lea     bx,TmpExpr              ; (BX) = pointer to AddrS struc
        mov     cx,1
        Pcall   AddrToLin
        jc      phe9

        Pcall   blank
        mov     TmpExpr2.AddrOff.LowWord,dx
        mov     TmpExpr2.AddrOff.HighWord,ax
        mov     TmpExpr2.AddrType,EXPR_TYPE_LIN
        lea     si,TmpExpr2             ; (SI) = pointer to ExprS/AddrS struc
        Pcall   OutAddrS, <si>

phe9:   test    DebData.InitFlag,INIT_ENV386
        jz      phe10                   ; don't print in a 286 environment

        cmp     TmpExpr.AddrType,EXPR_TYPE_PHY
        je      phe10                   ; don't print if already physical

        lea     bx,TmpExpr              ; (BX) = pointer to AddrS struc
        mov     cx,1
        Pcall   AddrToPhy
        jc      phe10

        Pcall   blank
        mov     TmpExpr2.AddrOff.LowWord,dx
        mov     TmpExpr2.AddrOff.HighWord,ax
        mov     TmpExpr2.AddrType,EXPR_TYPE_PHY
        lea     si,TmpExpr2             ; (SI) = pointer to ExprS/AddrS struc
        Pcall   OutAddrS, <si>
phe10:  Pcall   crlf
phe11:
EndProc

;***    CommandReset - does every to reset for a new command
;
;       ENTRY   NONE
;
;       EXIT    DS, ES reinitialized
;               direction flag clear
;               forced lower case off
;
;       USES    DS, ES, Flags
;
DefProc CommandReset, NEAR, LOCAL
        cld                             ; clear direction flags
        DataContext <ds,es>             ; reset segment register
        xor     bp,bp                   ; clear backlink
        Pcall   LowerCaseOff            ; case sensitive
EndProc

;***    GetEOL
;
;       Make sure there is nothing more on the line except for
;       blanks and carriage return. If there is, it is an
;       unrecognized parameter and an error.
;
;       ENTRY:  NONE
;
;       EXIT:   NONE
;
;       USES:   FLAGS
;

DefProc GetEOL, NEAR, PUBLIC
        push    ax
        Pcall   GetChr                  ; Skip blanks
        pop     ax
        jz      short geo1
        jmp     perror
geo1:
EndProc

;***    ExecSubr - execute subroutine
;
;       Executes a subroutine it from the table when the
;       character matches the in table entry. If character is
;       invalid, it will jump to the address after end of table
;       marker (0).  Table must be terminated with a zero the
;       character field. Table format:
;
;               db      character
;               dw      routine address
;               ...
;               db      0               ; end of table
;               dw      error routine address
;
;       ENTRY:  AL = character to find in table.
;
;               DS:SI = pointer to table of characters followed by a
;               routine address to be executed if the characters.
;
;       EXIT:   NONE
;
;       USES:   AX, SI, Flags
;

DefProc ExecSubr, NEAR, PUBLIC
        mov     ah,al
es1:    lodsb
        .errnz  (offset cmd_char)
        or      al,al
        jz      es2
        cmp     al,ah
        je      es2
        add     si,size CmdTable_s - 1
        jmp     es1

es2:    lodsw
        .errnz  (offset cmd_proc - 1)
        call    ax
EndProc

;***    GetChr
;
;       Peek at current character skipping over white space only.
;
;       ENTRY:  NONE
;
;       EXIT:   AL = character
;               ZR = 1 if end of command line.
;
;       USES:   AL, FLAGS
;

DefProc GetChr, NEAR, PUBLIC
        Pcall   GetChrI                 ; Get first non-blank
        je      short gtc1
        dec     pTXT                    ; back up one character
gtc1:
EndProc

;***    GetChrI
;
;       Get next non-blank character, advance pTXT.
;
;       ENTRY:       NONE
;
;       EXIT:   AL = character
;               ZR = 1 if end of command line.
;
;       USES:   AL, FLAGS
;

DefProc GetChrI, NEAR, PUBLIC
        SaveReg <si>
        mov     si,pTXT
        cld
gti1:   lodsb
        cmp     al,' '                  ; check for white space
        je      short gti1
        cmp     al,TABCHR
        je      short gti1
        mov     pTXT,si
        dec     si
        Pcall   EOLchk
        jne     short gti2
        mov     pTXT,si                 ; Back to first non-blank
gti2:   RestReg <si>                    ; can't affect the ZF flag
EndProc

;***    EOLchk
;
;       Check if AL is ";" or NULL which indicates in of command.
;
;       ENTRY:  AL = character to check
;
;       EXIT:   ZR = 1 if end of command line.
;
;       USES:   FLAGS
;

DefProc EOLchk, NEAR, PUBLIC
        cmp     al,";"                  ; end of command if semicolon
        je      short ecr1
        or      al,al                   ; end of line if NULL
ecr1:
EndProc

;***    QuitCmd
;
;       Quick out
;

DefProc QuitCmd, NEAR, LOCAL
        push    0
        push    0
        call    DosExit
EndProc

;***    hexadd
;
;       Hex addition and subtraction
;

DefProc hexadd, NEAR, LOCAL
        Pcall   EvalWord
        mov     di,dx
        Pcall   EvalWord
        Pcall   GetEOL
        mov     si,dx
        add     dx,di
        mov     al,'+'
        Pcall   put_ch
        Pcall   out16
        Pcall   blank
        Pcall   blank
        mov     dx,di
        sub     dx,si
        mov     al,'-'
        Pcall   put_ch
        Pcall   out16
        Pcall   blank
        Pcall   blank
        mov     ax,di
        mul     si
        xchg    ax,dx
        push    ax
        mov     al,'*'
        Pcall   put_ch
        Pcall   out16
        Pcall   blank
        pop     dx
        Pcall   out16
        Pcall   blank
        Pcall   blank
        mov     ax,0FFFFh
        mov     dx,ax
        or      si,si
        jz      short hexa1
        mov     ax,di
        xor     dx,dx
        div     si
        xchg    ax,dx
hexa1:  push    ax
        mov     al,'/'
        Pcall   put_ch
        Pcall   out16
        Pcall   blank
        pop     dx
        call    out16
        Pcall   crlf
EndProc

;***    ScanP
;
;       Scan for parameters of a command skipping comma's.
;
;       ENTRY:  NONE
;
;       EXIT:   (AL) = character
;               (ZR) = 1 if end of command line.
;
;       USES:   AL, FLAGS
;

DefProc ScanP, NEAR, PUBLIC
        Pcall   GetChr                  ; Get first non-blank
        je      short scp1
        cmp     al,','                  ; check if comma
        jne     short scp1
        Pcall   SkipB
        Pcall   GetChr                  ; Get first non-blank
scp1:
EndProc

;***    SkipB
;
;       Skip Character
;
;       ENTRY:  NONE
;
;       EXIT:   AL = next character
;               ZR = 1 if end of command line.
;
;       USES:   AL, FLAGS
;

DefProc SkipB, NEAR, PUBLIC
        inc     pTXT
        Pcall   PeekChr
EndProc

;***    PeekChr
;
;       Peek at first character without skip blanks or commas.
;
;       ENTRY:  NONE
;
;       EXIT:   AL = next character
;               ZR = 1 if end of command line.
;
;       USES:   AL, FLAGS
;

DefProc PeekChr, NEAR, PUBLIC
        SaveReg <si>
        mov     si,pTXT
        lodsb
        Pcall   EOLchk
        RestReg <si>
EndProc

;***    DebOptions
;
;       Changes debugger options
;
;       ENTRY:  NONE
;
;       EXIT:   NONE
;
;       USES:   AX, BX
;

DefProc DebOptions, NEAR, LOCAL
        Pcall   PeekChr                 ; (AL) = peeked character
        jz      short dop2              ; jump if EOL, to print settings

        cmp     al,"?"
        jne     short dop1

;       Print option help list

        Pcall   SkipB
        mov     dx,dataOFFSET DebOptHelp
        Pcall   rprbuf                  ; print help message
        jmp     dopx

dop1:   Pcall   ScanP
        jnz     short dop3              ; jump if chars on line
dop2:   jmp     dop12

;       Change options settings

dop3:   Pcall   GetInStr                ; (BX) = option ptr, (CX) = option len
        mov     si,dataOFFSET OptionTable
        mov     dx,size OptionTableS
        Pcall   SearchString            ; (SI) = OptionTable entry
        jc      short dop9              ; jump if error

        mov     di,[si].OptionAddr    ; (DI) = address of option variable
        mov     ax,[si].OptionBitMask   ; (AX) = option variable bit mask
        xor     bh,bh
        mov     bl,[si].OptionType      ; (BX) = option type
        shl     bx,1
        jmp     word ptr cs:dop4[bx]

dop4    dw      codeOFFSET dop5
        .errnz  DEB_OPT_CLEARBIT-0
        dw      codeOFFSET dop6
        .errnz  DEB_OPT_SETBIT-1
        dw      codeOFFSET dop7
        .errnz  DEB_OPT_TOGGLEBIT_CLEAR-2
        dw      codeOFFSET dop7
        .errnz  DEB_OPT_TOGGLEBIT_SET-3
        dw      codeOFFSET dop8
        .errnz  DEB_OPT_WORD-4

dop5:   not     ax
        and     [di],ax                 ; clear bit
        jmp     short dop11

dop6:   or      [di],ax                 ; set bit
        jmp     short dop11

dop7:   xor     [di],ax                 ; toggle bit
        jmp     short dop11

dop8:   Pcall   GetChrI                 ; (AL) = next character
        jz      short dop9
        cmp     al,"="
        je      short dop10
dop9:   jmp     perror

dop10:  Pcall   EvalWord                ; (DX) = evaluated word expression
        mov     [di],dx

dop11:  Pcall   ScanP
        jnz     short dop3              ; jump if more characters on line
        jmp     dopx

;       Print current option settings

dop12:  mov     si,dataOFFSET OptionTable

;       Loop on each entry in OptionTable

dop13:  mov     di,[si].OptionAddr      ; (DI) = address of option variable
        mov     ax,[si].OptionBitMask   ; (AX) = option variable bit mask
        mov     dx,[si].OptionName      ; (DX) = pointer to option name
        xor     bh,bh
        mov     bl,[si].OptionType      ; (BX) = option type
        shl     bx,1
        jmp     word ptr cs:dop14[bx]

dop14   dw      codeOFFSET dop15
        .errnz        DEB_OPT_CLEARBIT-0
        dw      codeOFFSET dop16
        .errnz  DEB_OPT_SETBIT-1
        dw      codeOFFSET dop15
        .errnz  DEB_OPT_TOGGLEBIT_CLEAR-2
        dw      codeOFFSET dop16
        .errnz  DEB_OPT_TOGGLEBIT_SET-3
        dw      codeOFFSET dop18
        .errnz  DEB_OPT_WORD-4

dop15:  test    [di],ax
        jz      short dop17             ; jump if bit is clear, print name
        jmp     short dop19

dop16:  test    [di],ax
        jz      short dop19             ; jump if bit is clear, skip entry

dop17:  Pcall   rprbuf                  ; print option name
        Pcall   blank
        jmp     short dop19

dop18:  Pcall   rprbuf                  ; print option name
        mov     al,'='
        Pcall   put_ch
        mov     dx,[di]
        xor     ax,ax                   ; (AX:DX) = option value to print
        Pcall   OutHex
        Pcall   blank

dop19:  add     si,size OptionTableS    ; next entry
        cmp     [si].OptionName,0
        jne     short dop13             ; jump if more entries
        Pcall   crlf
dopx:
EndProc

;***    DoExtCmd
;
;       This command allows environment specific commands to
;       be added to the debugger.  Uses the debugger call out
;       function to call the command.
;
;       ENTRY:  NONE
;
;       EXIT:   NONE
;
;       USES:   ALL
;

DefProc DoExtCmd, NEAR, LOCAL
        Pcall   DebCallOut, <DEB_CALLOUT_EXTCMD>
EndProc

;***    DebCallOut - common debugger callout routine
;
;       Pcall   DebCallOut, <CallOutNumber>
;
;       ENTRY:  (CallOutNumber)
;
;       EXIT:   Depends on callout function
;
;       USES:   Depends on callout function
;
DefProc DebCallOut, NEAR, PUBLIC

ArgVar  CallOutNumber, WORD

BeginProc
        push    CallOutNumber
        call    [DebSASTable.DSAS_HookPM]
EndProc

;***    GetTrapTblEntry
;
;       Pcall   GetTrapTblEntry, <Intnum>
;
;       Gets the address of the idt table entry.
;
;       ENTRY:  (Intnum) = interrupt number of entry.
;
;       EXIT:   BX = address of table entry.
;
;       USES:   BX, FLAGS, other regs preserved
;
DefProc GetTrapTblEntry, NEAR, PUBLIC

ArgVar  Intnum, BYTE

BeginProc
        mov     bl,Intnum                       ; get index into trap table
        xor     bh,bh
        imul    bx,size TrapTblS
;        add     bx,dataOFFSET TrapTbl          ; larryb DEBUG
EndProc

;***    IsSeparator
;
;       ENTRY:  NONE
;
;       EXIT:   (ZR) = if command separator
;               (NZ) = if not command separator
;               (AL) = character
;
;       USES:   AL, Flags
;

DefProc IsSeparator, NEAR, PUBLIC
        Pcall   PeekChr                 ; (AL) = command letter
        jz      isp1
        cmp     al,' '
        je      isp1
        cmp     al,TABCHR
        je      isp1
        cmp     al,','
isp1:
EndProc

;***    search
;
;       Search a specified area of memory for given list of bytes.
;       Print address of first byte of each match.
;

DefProc search, NEAR, LOCAL

LocVar  Addr,    <size AddrS>
LocVar  ListLen, WORD

BeginProc
        lea     bx,Addr
        Pcall   GetDSaddr
        Pcall   EvalRange, <bx, bx, 128>
        Pcall   CheckAddr, <bx>
        jcxz    short scn7

        push    cx                      ; save search region length
        Pcall   list                    ; (BX) = list item length
        pop     dx                      ; (DX) = search region length

        dec     bx                      ; num of bytes in list - 1
        mov     ListLen,bx
        lea     bx,Addr

;       (BX) = pointer to AddrS struc
;       (DX) = current total number of bytes left

scn1:   cmp     dx,ListLen
        jbe        scn7                    ; if bytes left < list len, no match

        Pcall   GetCache                ; (DI) = buffer cache, (CX) = num bytes
        jc      short scn4              ; (DX) = num bytes left
        mov     si,cx

;       (BX) = pointer to AddrS struc
;       (CX) = number of bytes left in cache
;       (DX) = total bytes left
;       (SI) = number of bytes in cache
;       (DI) = pointer to cache

scn2:   jcxz    short scn6
        mov     al,byte ptr bytebuf
        repne   scasb
        jne     short scn6

        cmp     ListLen,0               ; if listLen == 0, one byte match
        je      scn3

        cmp     cx,ListLen
        jb      scn5                    ; jump if num of cach byte < list len

        SaveReg <cx, si, di>
        mov     si,dataOFFSET bytebuf+1
        mov     cx,ListLen
        repe    cmpsb
        RestReg <di, si, cx>
        jne     short scn2

scn3:   mov     ax,si
        sub     ax,cx
        dec     ax                      ; (AX) = number of bytes searched
        Pcall   OutAddrOff, <bx, ax, 0>
        Pcall   crlf
        Pcall   checkchr            ; check for ESC key to stop output
        jmp     short scn2

scn4:   jmp     ErrBreak

scn5:   inc     cx                        ; (CX) = number of bytes really left
        add     dx,cx                   ; add the bytes left back into len
        sub     si,cx                   ; (SI) = number of bytes searched

scn6:   Pcall   AddAddr, <si, 0>
        or      dx,dx
        jnz     short scn1              ; jump if no more bytes
scn7:
EndProc

;***    compare
;
;       Compare memory command.
;

DefProc compare, NEAR, LOCAL

LocVar  SrcAddr,  <size AddrS>
LocVar  DesAddr,  <size AddrS>
LocVar  Len,      WORD

BeginProc
        lea     bx,SrcAddr
        Pcall   GetDSaddr
        Pcall   EvalRange, <bx, bx, 128>
        Pcall   CheckAddr, <bx>
        jcxz    cmp1                    ; don't do anything if 0 bytes to comp

        mov     Len,cx                  ; Save length
        Pcall   ScanP
        jnz     short cmp3
        jmp     perror                  ; error if end of line

cmp1:   jmp     cmpx

cmp2:   jmp     ErrBreak

cmp3:   lea     bx,DesAddr
        Pcall   GetDSaddr
        Pcall   EvalAddr, <bx, bx>
        Pcall   CheckAddr, <bx>
        Pcall   GetEOL

cmp4:   mov     cx,Len
        jcxz    short cmp1

        cmp     cx,(MEMCACHESIZE/2)
        jbe     short cmp5
        mov     cx,(MEMCACHESIZE/2)
cmp5:   sub     Len,cx

        mov     di,dataOFFSET MemCache
        lea     bx,SrcAddr
        Pcall   GetBuff
        jc      cmp2

        mov     di,dataOFFSET MemCache + (MEMCACHESIZE/2)
        lea     bx,DesAddr
        Pcall   GetBuff
        jc      cmp2
        mov     si,dataOFFSET MemCache
        push    cx

cmp6:   jcxz    short cmp7
        repe    cmpsb
        je      short cmp7

        mov     ax,si
        sub     ax,dataOFFSET MemCache + 1

        lea     bx,SrcAddr
        Pcall   OutAddrOff, <bx, ax, 0>

        push    ax
        Pcall   blank
        mov     al,[si-1]
        Pcall   hex
        Pcall   blank
        Pcall   blank
        mov     al,[di-1]
        Pcall   hex
        Pcall   blank
        pop     ax

        lea     bx,DesAddr
        Pcall   OutAddrOff, <bx, ax, 0>
        Pcall   crlf
        jmp     short cmp6

cmp7:   pop     cx
        lea     bx,SrcAddr
        Pcall   AddAddr, <cx, 0>
        lea     bx,DesAddr
        Pcall   AddAddr, <cx, 0>
        jmp     short cmp4
cmpx:
EndProc

;***    list
;
;       Get a byte list for _ENTER, FILL or SEARCH. Accepts any number
;       of 2-digit hex values or character strings in either single
;       (') or double (") quotes.
;

DefProc list, NEAR, LOCAL
        mov     bx,dataOFFSET bytebuf   ; Put byte list in the byte buffer
lst1:   Pcall   listitem                ; Process a parameter
        jnc     short lst1              ; If OK, try for more
        sub     bx,dataOFFSET bytebuf   ; BX now has no. of bytes in list
        jnz     short lst2              ; List must not be empty
        jmp     perror

lst2:   Pcall   GetEOL

EndProc

;***    listitem
;
;       Process one parameter when a list of bytes is
;       required. Carry set if parameter bad. Called by LIST.
;
;       ENTRY:  BX = pointer to list byte buffer.
;
;       EXIT:   Carry set if error.
;
;       USES:   AX, BX, SI, FLAGS
;

DefProc listitem, NEAR, LOCAL
        Pcall   ScanP                   ; Scan to parameter
        push    ax
        Pcall   HexChk                  ; Is it in hex?
        pop     ax
        jc      short lsi1              ; If not, could be a string

        Pcall   EvalByte                ; Get the byte value
        mov     [bx],dl                 ; Add to list
        inc     bx
        jmp     short lsi2

lsi1:   Pcall   CheckString             ; String?
        jne     short lsi3              ; Not string, not hex - bad
        mov     di,bx                   ; (DI) = buffer address
        Pcall   ParseString
        mov     bx,di                   ; (BX) = end of string
        jc      short lsi3

lsi2:   clc                             ; Parameter was OK
        jmp     short lsi4
lsi3:   stc

lsi4:

EndProc

;***    DumpStack - stack trace command (K)
;***    DumpStack2 - stack trace command (K)
;
;       K[S|B] [<SS:BPaddr>] [<CS:IPaddr>]
;         S = 16 bit stack frame (Small)
;         B = 32 bit stack frame (Big)
;
;       ENTRY:  (DI) = size flag (DumpStack2 only)
;
;       EXIT:   NONE
;
;       USES:   AX, BX, CX, DX, SI, DI, Flags
;

DefProc DumpStack, NEAR, PUBLIC
        xor     di,di                   ; (DI) = 16 bit stack frame (0)
        Pcall   PeekChr
        jz      short dst20
        cmp     al,'S'
        je      short dst10
        cmp     al,'B'
        jne     short dst20
        inc     di                      ; (DI) = 32 bit stack frame (1)
dst10:  Pcall   SkipB
        jmp     short DumpStack2

dst20:  dec     di                      ; (DI) = default size indication (-1)

Entry   DumpStack2, NEAR, PUBLIC

LocVar  SSBPaddr, <size AddrS>
LocVar  CSIPaddr, <size AddrS>

BeginProc
        cmp     di,1
        jne     short dst30
        lea     si,CSIPaddr
        Pcall   FillLinAddr, <si, RegSA.EIPsav.LowWord, RegSA.EIPsav.HighWord>
        jmp     short dst40

dst30:  lea     bx,CSIPaddr
        Pcall   GetCSIPaddr
        mov     si,bx                   ; (SI) = CS:IP AddrS
dst40:  lea     bx,SSBPaddr             ; (BX) = SS:BP AddrS
        Pcall   FillDefAddr, <bx, RegSA.SSsav, RegSA.EBPsav.LowWord, RegSA.EBPsav.HighWord>
        Pcall   EvalAddr, <bx, bx>
        Pcall   CheckAddr, <bx>
        Pcall   EvalAddr, <si, si>
        Pcall   CheckAddr, <si>
        cmp     di,-1
        jne     short dst50
        push    bx

        push    ds          ; far pointer to structure
        push    si
        call    _getdbit
        add     sp,4
;        Ccall   getdbit, <si>

        pop     bx
        mov     di,ax                   ; (DI) = 0 if d bit clear, !0 if set
dst50:  Pcall   PrintStack
EndProc


;***    PrintStack
;
;       Print out a stack dump threading thru with BP.
;
;       ENTRY:  (BX) = AddrS containing start of SS:BP chain.
;               (SI) = AddrS containing the CS:IP of current proc.
;               (DI) = 16 bit (0) or 32 bit (!0) stack frame flag
;
;       EXIT:   NONE
;
;       USES:   BX->AddrS, SI->AddrS, AX, CX, DX, Flags
;

DefProc PrintStack, NEAR, PUBLIC

LocVar  ParmOffs, WORD


BeginProc
pst10:  and     [bx].AddrOff.LowWord,0FFFEh ; windows might have set this bit
        cmp     [bx].AddrOff.LowWord,0
        je      short pst20
        or      di,di                   ; 16 bit address?
        jz      short pst30             ;  jump if 16 bit address

        Pcall   GetDwordOff, <4, 0>     ; (AX:DX) = 32 bit near address
        jc      short pst20
        mov     [si].AddrOff.LowWord,dx
        mov     [si].AddrOff.HighWord,ax
        Pcall   OutAddrS, <si>
        Pcall   blank

;       Spit out 4 dwords of parameters

        mov     ParmOffs,8
        Pcall   GetDwordOff, <ParmOffs, 0>
        jc      short pst15
        Pcall   Out32
        Pcall   blank
        add     ParmOffs,4
        Pcall   GetDwordOff, <ParmOffs, 0>
        jc      short pst15
        Pcall   Out32
        Pcall   blank
        add     ParmOffs,4
        Pcall   GetDwordOff, <ParmOffs, 0>
        jc      short pst15
        Pcall   Out32
        Pcall   blank
        add     ParmOffs,4
        Pcall   GetDwordOff, <ParmOffs, 0>
        jc      short pst15
        Pcall   Out32
        Pcall   blank
pst15:  jmp     pst50

pst20:  jmp     pstx

pst30:  Pcall   GetWordOff, <2, 0>      ; (DX) = 16 bit near address
        jc      short pst20
        mov     [si].AddrOff.LowWord,dx
        mov     ParmOffs,6              ; assume far address

;       Check if the address is a far address

        Pcall   WhatIsClientMode
        jnc     pst40                   ; jump if real or V86 mode
        Pcall   GetWordOff, <4, 0>      ; (DX) = possible CS selector
        xchg    dx,[si].AddrSeg         ; exchange possible CS selector
        xchg    bx,si                   ; (BX) = CS:IP AddrS (SI) = SS:BP AddrS
        push    dx                      ; save original CS
        mov     cx,1
        Pcall   AddrToPhy               ; verify CS
        pop     dx                      ; (DX) = original CS
        xchg    bx,si                   ; (SI) = CS:IP AddrS (BX) = SS:BP AddrS
        jnc     pst40
        xchg    dx,[si].AddrSeg         ; if error, restore original CS
        mov     ParmOffs,4              ; whoops, near address

pst40:  Pcall   OutAddrS, <si>
        Pcall   blank

;       Spit out 4 words of parameters

        Pcall   GetWordOff, <ParmOffs, 0>
        jc      short pst50
        Pcall   out16
        Pcall   blank
        add     ParmOffs,2
        Pcall   GetWordOff, <ParmOffs, 0>
        jc      short pst50
        Pcall   out16
        Pcall   blank
        add     ParmOffs,2
        Pcall   GetWordOff, <ParmOffs, 0>
        jc      short pst50
        Pcall   out16
        Pcall   blank
        add     ParmOffs,2
        Pcall   GetWordOff, <ParmOffs, 0>
        jc      short pst50
        Pcall   out16
        Pcall   blank

pst50:  push    bx
;        xor     cx,cx                   ; (CX) = PrintNearSym flags
        Pcall   GetSymbolBuf, <dataOFFSET SymbolBuf, si>
        or      ax,ax

        jz     @F                             ; jump if not exact match
        mov     al,'['
        Pcall   put_ch
        Pcall   prtstr, <dataOFFSET SymbolBuf>
        mov     al,']'
        Pcall   put_ch
;       Pcall   PrintNearSym

@@:     Pcall   crlf
        pop     bx

        or      di,di                   ; 16 bit address?
        jz      short pst60             ;  jump if 16 bit address
        Pcall   GetDword                ; (AX:DX) = next EBP
        jc      short pstx
        mov     [bx].AddrOff.LowWord,dx
        mov     [bx].AddrOff.HighWord,ax
        jmp     pst10

pst60:  Pcall   GetWord                 ; (DX) = next BP
        jc      short pstx
        mov     [bx].AddrOff.LowWord,dx
        jmp     pst10
pstx:
EndProc

;***    PrintNearSym

DefProc PrintNearSym, NEAR, LOCAL

LocVar  symBuff, WORD

BeginProc
        SaveReg <ax, bx, cx, dx, si, di>
        dec     si
        mov     ax, [si]
        mov     al, 1
        mov     [si], ax
        push    ds
        push    si
        call    far ptr _CListNear
        add     sp,4
        push    ds      ; diem 03/18/94  df would trap while running under pmdf
        pop     es
        RestReg <di, si, dx, cx, bx, ax>
EndProc

_TEXT   ends
        end
