Page 55,132 Title DDM MaxBufLen EQU 80 ;input buffer BPLen EQU 8 ;number of breakpoints cr EQU 0Dh ;carriage return lf EQU 0Ah ;line feed IOSpace EQU 0 ;equates for target space MemSpace EQU 2 RegSpace EQU 4 ReadMode EQU 0 ;mode of cell access NoReadMode EQU 1 MemSize EQU 2 ;offset of memory size in PSP TermCS EQU 0Ch ;offset of terminate address in PSP TermIP EQU 0Ah TermIntNo EQU 22h ;terminate interrupt number CBrkCS EQU 10h ;offset of the ctrl-Break address in PSP CBrkIP EQU 0Eh CBrkIntNo EQU 23h ;ctrl-break interrupt number DefaultDTA EQU 80h ;the EXE file header falls here LStkSeg EQU 8Eh LStkPtr EQU 90h LCSReg EQU 96h LIPReg EQU 94h FileSize EQU 84h ;load module file size offset in PSP HeaderSize EQU 88h ;load module header size offset in PSP RelocItem EQU 98h ;offset of first relocation item ItemCount EQU 86h ;number of relocation items myFCB EQU 5Ch ;EXE file FCB falls here in the PSP CurrentBlock EQU 0Ch ;offset of current block in FCB CurrentRecord EQU 20h ;offset of relative record no. in FCB RelRec EQU 21h ;offset of relative record no. for random access Stack Segment Stack DW 256 Dup (?) Stack ENDS Data Segment 'Data' TargSpace DW (?) TargSeg DW (?) TargOffset DW (?) BPTable DW 2*BPLen DUP (?) ;breakpoint entries contain a ;segment in the first word, the opcode being replaced in the ;first byte of the second word, 3 bits of 0's, a bit indicating ;that the table entry is in use, and a four-bit offset from the ;segment given by the first word. BPTableEnd LABEL WORD Mode DW (?) ;printing mode LoadFlag DW (?) ;indicates debugee loaded DStkp DW (?) ;saves stkp when debugee is running RegSave LABEL WORD RegAX DW 0 RegBX DW 0 RegCX DW 0 RegDX DW 0 RegSP DW 0 RegBP DW 0 RegSI DW 0 RegDI DW 0 RegCS DW 0 RegDS DW 0 RegSS DW 0 RegES DW 0 RegIP DW 0 RegFR DW 0 RegXS DW 0 RegYS DW 0 Buf DB MaxBufLen+1 Dup (?) BufLen DW (?) LoadSeg DW (?) ;segment into which to load debugee PSPSeg DW (?) RelocSeg DW (?) ;during loading, relocation is done ;relative to this segment Broken DW (?) ;nonzero means breakpoints are set in the debugee Data ENDS CSeg Segment 'Code' Assume CS: CSeg, DS: Data ;********************************************************************* DDMain PROC Far PUSH DS ;save PSP for return to DOS SUB AX, AX PUSH AX MOV AX, Data MOV DS, AX MOV PSPSeg, ES MOV CL, 4 ;the segment after the stack holds the debugee MOV AX, SP SHR AX, CL INC AX MOV BX, SS ADD AX, BX MOV LoadSeg, AX MOV RegXS, AX MOV RegYS, ES ;save PSP offset MOV TargSpace, MemSpace MOV TargSeg, 0 MOV TargOffset, 0 MOV Mode, ReadMode MOV LoadFlag, 0 CALL InitBPTable MOV BufLen, 0 ;clear input buffer MOV Broken, 0 ;Set COM1 to 2400baud, no parity, one stop bit, 8 data bits MOV AX, 0A3h MOV DX, 0 ;com card 0 INT 14h ;commands return here Main00: CALL Prompt ;Prompt Main01: CALL GetLine Main02: MOV AH, 0 ;command character is in AL MOV BX, AX SHL BX, 1 ;dispatch on command character JMP CS:ComTab[BX] ComTab LABEL WORD ;dispatch table for command characters DW QPr, QPr, CtrlB, I23, QPr, QPr, QPr, Go DW QPr, QPr, QPr, KillBP, LoadEXE, Main00, NextLoc, CurLocR DW PrevLoc, Quit, RegPrint, SStep, TermMode, QPr, QPr, CurLocN DW QPr, QPr, Prgm, QPr, QPr, QPr, QPr, QPr TermMode: MOV AH, 1 ;kbd char ready? INT 16h JE TM01 MOV AH, 3 ;RS232 transmitter ready? MOV DX, 0 INT 14h TEST AH, 20h ;bit 5 is xmt holding register empty JE TM01 MOV AH, 0 ;read keyboard INT 16h CMP AL, 14h ;control-T? JNE TM00 JMP Main00 ;exit terminal mode TM00: MOV AH, 1 ;send char to RS232 INT 14h TM01: MOV AH, 3 ;RS232 char available? MOV DX, 0 INT 14h TEST AH, 1 ;receiver ready? JE TermMode MOV AH, 2 ;get char from com line INT 14h AND AL, 7Fh ;mask character to 7 bits MOV AH, 14 ;send character to screen MOV BX, 0 INT 10h JMP TermMode Prgm: CMP LoadFlag, 0 JNE Prg00 JMP QPr ;can't do it if debugee not loaded Prg00: CALL SendCS JMP Main00 KillBP: CMP BufLen, 0 JE ZapBP CALL Parse JC KBp01 JMP QPr ;bad parse KBp01: MOV CX, TargSeg MOV DX, TargOffset MOV AX, 10h MOV SI, 0FFFFh MOV DI, 1Fh MOV BP, OFFSET KBp00 CALL ScanBP JMP QPr ;zap location not found KBp00: POP AX ;pop 2 return links POP AX MOV BPTable+2 [BX], 0 JMP Main00 ZapBP: CALL InitBPTable JMP Main00 CtrlB: CMP BufLen, 0 ;set bp if preceded by seg:offset, else print all JNE CtB00 CALL PrintBreaks JMP Main00 CtB00: CALL Parse JC CtB01 JMP QPr ;bad parse CtB01: CMP TargSpace, MemSpace JE CtB02 JMP QPr CtB02: MOV AX, 0 CALL SetBp JC CtB03 JMP QPr CtB03: JMP Main00 RegPrint: CALL PrintRegs JMP Main00 I23: INT 23h SStep: CMP LoadFlag, 1 ;1 means program has run a bit already JG SSt00 JMP QPr SSt00: MOV AX, OFFSET StepStep JMP Go04 Go: CMP LoadFlag, 0 JNE Go00 JMP QPr ;can't go unless debuggee loaded Go00: INC LoadFlag MOV DS, LoadSeg MOV DX, 80h MOV AH, 1Ah INT 21h ;set DTA to load seg:80h ;Set up the terminate (22h) and CtrlBrk (23h) interrupts ;from the debuggee PSP Go01: MOV AX, WORD PTR DS: TermIP MOV CX, WORD PTR DS: TermCS MOV BX, TermIntNo CALL SetInt MOV AX, WORD PTR DS: CBrkIP MOV CX, WORD PTR DS: CBrkCS MOV BX, CBrkIntNo CALL SetInt MOV AX, Data MOV DS, AX MOV CX, RegCS ;check for break at go location MOV DX, RegIP MOV AX, 10h MOV BP, OFFSET Go02 MOV SI, 0FFFFh MOV DI, 1Fh CALL ScanBP CALL BPExchange ;no break at go location. Set breaks AND RegFR, 0FEFFh ;clear TF MOV AX, OFFSET BrkStop MOV CX, CS MOV BX, 3 ;breakpoint interrupt is type 3 CALL SetInt ;set SS vector so that it clears TF and restarts MOV AX, OFFSET BrkStep MOV CX, CS MOV BX, 1 CALL SetInt MOV Broken, 1 ;breaks are set JMP Go03 Go02: POP AX ;pop 2 return links POP AX MOV AX, OFFSet BrkStep Go04: OR RegFR, 100h ;a breakpoint is set at go location. Set TF MOV CX, CS MOV BX, 1 ;set Single Step interrupt vector CALL SetInt MOV Broken, 0 ;breaks are not set in the debugee JMP Go03 ;Come here on a single step stop StepStep: CALL SaveRegs CALL BPSwap CALL PrintRegs MOV AL, "S" JMP Term00 ;Come here on a breakpoint stop BrkStop: CALL SaveRegs CALL BPSwap DEC RegIP ;back up IP to point to the break instruction CALL PrintRegs MOV AL, "B" JMP Term00 ;Get here on a step over a breakpointed instruction BrkStep: CALL SaveRegs CALL BPSwap AND RegFR, 0FEFFh ;clear TF MOV DS, LoadSeg JMP Go01 ;Load up the machine registers and give control to the debugee Go03: MOV DStkp, SP ;save stkp while debugee runs MOV SS, RegSS MOV SP, RegSP MOV AX, RegFR PUSH AX MOV AX, RegCS PUSH AX MOV AX, RegIP PUSH AX MOV AX, RegAX MOV BX, RegBX MOV CX, RegCX MOV DX, RegDX MOV BP, RegBP MOV SI, RegSI MOV DI, RegDI MOV ES, RegES MOV DS, RegDS IRET LoadEXE: CMP BufLen, 0 ;special relocation? JE LE10 MOV BP, 0 MOV SI, BufLen CALL NumCheck JC LE11 JMP QPr ;funny non-number for relocation segment LE10: MOV AX, LoadSeg ;normal relocation ADD AX, 10h ;debugee PSP is 100h long LE11: MOV RelocSeg, AX LE12: MOV DX, LoadSeg MOV AH, 26h ;create new program segment INT 21h ;DOS call MOV BP, DS ;lots of segment switching soon MOV ES, BP MOV DS, PSPSeg MOV DX, DefaultDTA MOV AH, 1Ah ;set DTA INT 21h MOV DX, myFCB ;open file (use debugger PSP) MOV AH, 0Fh INT 21h CMP AL, 0 JE LE00 MOV DS, BP JMP QPr ;could not open file LE00: MOV WORD PTR DS: (myFCB+CurrentBlock), 0 MOV BYTE PTR DS: (myFCB + CurrentRecord), 0 MOV AH, 14h ;sequential read INT 21h ;print the 14 header values CALL CRLF MOV BX, 0 MOV CX, 14 PUSH BP ;save segment phloop: MOV AX, WORD PTR DS: DefaultDTA[BX] ADD BX, 2 CALL PutNum MOV AL, " " CALL PutChar DEC CX JG phloop CMP WORD PTR DS: DefaultDTA, 5A4Dh JE LE01 POP BP JMP QPr LE01: POP BP MOV DS, ES: LoadSeg MOV DX, 100h ;set load segment for transfer MOV AH, 1Ah INT 21h MOV DS, ES: PSPSeg ;get starting record MOV AX, WORD PTR DS: MemSize ;copy the memory size ;information from PSP to PSP, since DOS doesn't MOV DS, ES: LoadSeg MOV WORD PTR DS: MemSize, AX ;set the Terminate and CtrlBrk addresses into the debugee PSP MOV AX, OFFSET Term MOV WORD PTR DS: TermIP, AX MOV WORD PTR DS: TermCS, CS MOV AX, OFFSET CBrk MOV WORD PTR DS: CBrkIP, AX MOV WORD PTR DS: CBrkCS, CS MOV DS, ES: PSPSeg MOV CL, 3 ;header size is in paragraphs. divide by 8 to get records. MOV AX, WORD PTR DS: HeaderSize SHR AX, CL MOV WORD PTR DS: (myFCB+RelRec), AX MOV WORD PTR DS: (myFCB+RelRec+2), 0 MOV BX, WORD PTR DS: FileSize MOV CL, 2 SHL BX, CL ;number of records in file MOV CX, BX SUB CX, AX ;number of records to read MOV DX, myFCB MOV AH, 27h ;random block read INT 21h ;DOS call MOV ES: RegAX, AX ;AL has completion code MOV ES: RegCX, CX ;CX has number of records read ;set DTA back to PSP and process relocation info. MOV DS, ES:PSPSeg MOV DX, DefaultDTA MOV AH, 1Ah ;set DTA INT 21h MOV DI, ES: LoadSeg ADD DI, 10h ;DI contains the start segment ;get SS from the header MOV AX, WORD PTR DS: LStkSeg ADD AX, DI MOV ES: RegSS, AX ;get SP MOV AX, WORD PTR DS: LStkPtr MOV ES: RegSP, AX ;get CS MOV AX, WORD PTR DS: LCSReg ADD AX, DI MOV ES: RegCS, AX ;get IP MOV AX, WORD PTR DS: LIPReg MOV ES: RegIP, AX ;set the FCB block number to 0 and the relative record no. to 1 ;in case more disk accesses are required MOV WORD PTR DS: (myFCB+CurrentBlock), 0 MOV BYTE PTR DS: (myFCB+CurrentRecord), 1 MOV DX, myFCB MOV BX, WORD PTR DS: RelocItem ;offset of the first item MOV CX, WORD PTR DS: ItemCount MOV AX, ES:RelocSeg ;put this on the stack PUSH AX RelocLoop: CMP CX, 0 ;more items? JE RelocDone MOV SI, WORD PTR DS: DefaultDTA[BX] ;offset CALL ChkDskBuf MOV AX, WORD PTR DS: DefaultDTA[BX] ;segment CALL ChkDskBuf ADD AX, DI ;segment + start segment MOV ES, AX POP AX ;get RelocSeg PUSH AX ADD AX, WORD PTR ES: [SI] ;item to be relocated MOV WORD PTR ES: [SI], AX ;put it back DEC CX JMP RelocLoop RelocDone: MOV DS, BP POP AX ;discard RelocSeg MOV AX, LoadSeg ;segment of debugee PSP MOV RegDS, AX MOV RegES, AX MOV RegFR, 0 ;interrupts OFF MOV LoadFlag, 1 ;indicate that debugee is loaded JMP Main00 Quit: RET ;return to DOS PrevLoc: MOV DX, -2 ;offset delta to access previous location JMP NL01 NextLoc: MOV DX, 2 NL01: CMP BufLen, 0 ;nonzero length is an error here JE CLR02 JMP QPr ;error prompt CurLocN: MOV Mode, NoReadMode JMP CLR01 CurLocR: MOV Mode, ReadMode CLR01: CMP BufLen, 0 JE CLR03 Call Parse JC CLR04 JMP QPr ;bad parse CLR02: ADD TargOffset, DX CMP TargSpace, RegSpace JNE CLR03 AND TargOffset, 1Fh ;mask offset in register mode CLR03: MOV BX, TargSpace ;print the current location JMP CS:PrintTab[BX] PrintTab LABEL WORD DW PrintIO,PrintMem,PrintReg PrintIO: MOV AL, "I" CALL PutChar JMP PM01 PrintMem: MOV AX, TargSeg CALL PutNum MOV AL, ":" CALL PutChar PM01: MOV AX, TargOffset CALL PutNum JMP CLR04 PrintReg: MOV BX, TargOffset CALL PrintRegName CLR04: CMP Mode, ReadMode JE CLR05 MOV AL, "\" CALL PutChar JMP CLR10 CLR05: MOV AL, "/" CALL PutChar MOV BX, TargSpace ;now get and print contents JMP CS:ReadTab[BX] ReadTab LABEL WORD DW ReadIO,ReadMem,ReadReg ReadIO: MOV DX, TargOffset IN AX, DX JMP CLR06 ReadMem: MOV ES, TargSeg MOV BX, TargOffset MOV AX, ES:[BX] JMP CLR06 ReadReg: MOV BX, TargOffset MOV AX, RegSave[BX] CLR06: CALL PutNum CLR10: MOV AL, " " CALL PutChar CALL GetLine PUSH AX ;save termination character CMP BufLen, 0 JE CLR07 MOV BP, 0 MOV SI, BufLen CALL NumCheck JC CLR08 POP AX JMP QPr ;bad number? CLR08: MOV BX, TargSpace JMP CS:WriteTab[BX] WriteTab LABEL WORD DW WriteIO, WriteMem, WriteReg WriteIO: MOV DX, TargOffset OUT DX, AX JMP CLR07 WriteMem: MOV ES,TargSeg MOV BX, TargOffset MOV ES:[BX], AX JMP CLR07 WriteReg: MOV BX, TargOffset MOV RegSave[BX], AX CLR07: POP DX CMP DL, cr JE CLR09 CALL Prompt CLR09: MOV AX, DX MOV BufLen, 0 JMP Main02 QPr: MOV AL, " " CALL PutChar MOV AL, "?" CALL PutChar CALL Prompt JMP Main01 ;Come here on a CtrlBreak interrupt CBrk: CALL SaveRegs CALL BPSwap MOV AL, "C" JMP Term00 ;Come here when the debugee terminates Term: CALL SaveRegs CALL BPSwap MOV AL, "T" Term00: CALL CRLF CALL PutChar MOV AL, "*" CALL PutChar JMP Main01 DDMain ENDP ;********************************************************************* BPSwap PROC Near ;check for breaks set, clear them if so CMP Broken, 0 JE BPS00 CALL BPExchange BPS00: RET BPSwap ENDP ;********************************************************************* PrintRegName PROC Near MOV AL, CS:RegTabB+1[BX] CALL PutChar MOV AL, CS:RegTabB[BX] CALL PutChar RET PrintRegName ENDP ;********************************************************************* SaveRegs PROC Near ;called when debuggee returns via interrupt. Save debugee's registers. ;We are operating with the debuggee's stack. PUSH DS PUSH AX MOV AX, Data MOV DS, AX MOV RegBX, BX MOV RegCX, CX MOV RegDX, DX MOV RegBP, BP MOV RegSI, SI MOV RegDI, DI MOV RegES, ES POP AX MOV RegAX, AX POP AX MOV RegDS, AX POP BX ;SaveRegs' return link POP AX ;debugee IP, CS, Flags MOV RegIP, AX POP AX MOV RegCS, AX POP AX MOV RegFR, AX MOV RegSS, SS ;debugee's stack seg MOV RegSP, SP ;debugee's sp MOV AX, Stack ;switch to our stack MOV SS, AX MOV SP, DStkp PUSH BX ;restore the ctrl-break interrupt vector MOV ES, PSPSeg MOV AX, ES: CBrkIP MOV CX, ES: CBrkCS MOV BX, CBrkIntNo CALL SetInt RET SaveRegs ENDP ;********************************************************************* Prompt PROC Near CALL CRLF MOV AL, "*" CALL PutChar RET Prompt ENDP ;********************************************************************* GetLine PROC Near MOV BufLen, 0 ;clear input buffer Gl00: MOV AH, 0 INT 16h ;character to AL CMP AL, 20h JG Gl01 ;jump if non-control char JE Gl02 ;jump if space CMP AL, 8h ;check for backspace JE Gl03 RET ;not backspace, return Gl03: CMP BufLen, 0 JE Gl00 ;jump if buffer empty DEC BufLen MOV AL, 8h ;echo BS,SP,BS CALL PutChar MOV AL, 20h CALL PutChar MOV AL, 8h CALL PutChar JMP Gl00 Gl01: CMP AL, 7Ah ;check for upper case JG Gl04 CMP AL, 61h JL Gl04 SUB AL, 20h ;make lower into upper Gl04: MOV BX, BufLen ;buffer the character MOV Buf[BX], AL CMP BX, MaxBufLen JGE Gl02 ;don't overflow buffer INC BufLen Gl02: CALL PutChar ;echo JMP Gl00 GetLine ENDP ;********************************************************************* NumCheck PROC Near ;If Buf[BP..SI-1] represents a hex number, return ;the number in AX and set carry. If not, clear carry. CMP BP, SI JE Nc03 ;zero length? MOV CL, 4 MOV AX, 0 Nc00: MOV BL, Buf[BP] CMP BL, "0" JL Nc03 CMP BL, "9" JG Nc01 SUB BL, "0" JMP Nc02 Nc01: CMP BL, "A" JL Nc03 CMP BL, "F" JG Nc03 SUB BL, "A" - 10 Nc02: SHL AX, CL OR AL, BL INC BP CMP BP, SI JL Nc00 STC RET Nc03: CLC RET NumCheck ENDP ;********************************************************************* RegCheck PROC Near ;If Buf[BP..BP+1] represents a register, return the index ;of the register in BX and set carry. If not, clear carry MOV AH, Buf[BP] MOV AL, Buf+1[BP] MOV BX, 0 Rc01: CMP AX, CS:RegTab[BX] JE Rc02 ADD BX, 2 CMP BX, Offset RegTabEnd - Offset RegTab JL Rc01 CLC RET Rc02: STC RET RegCheck ENDP ;********************************************************************* ChkDskBuf PROC NEAR PUSH AX ADD BX, 2 CMP BX, 80h JL CDB01 MOV AH, 14h ;sequential disk read INT 21h MOV BX, 0 CDB01: POP AX RET ChkDskBuf ENDP RegTab LABEL WORD RegTabB LABEL BYTE DW "AX", "BX", "CX", "DX", "SP", "BP", "SI", "DI" DW "CS", "DS", "SS", "ES", "IP", "FR", "XS", "YS" RegTabEnd LABEL WORD ;********************************************************************* PutNum PROC Near ;Print AX as a four digit hex number PUSH BX PUSH CX MOV BX, AX MOV CL, 4 CALL Pn01 CALL Pn01 CALL Pn01 CALL Pn01 POP CX POP BX RET Pn01: ROL BX, CL MOV AX, 0Fh AND AX, BX CMP AX, 0Ah JGE Pn02 ADD AX, "0" JMP Pn03 Pn02: ADD AX, "A" - 0Ah PN03: CALL PutChar RET PutNum ENDP ;********************************************************************* CRLF PROC Near PUSH AX MOV AL, cr CALL PutChar MOV AL, lf CALL PutChar POP AX RET CRLF ENDP ;********************************************************************* PutChar PROC Near PUSH AX MOV AH, 14 PUSH BX MOV BX, 0 PUSH CX PUSH BP PUSH SI PUSH DI MOV CX, SP INT 10h MOV SP, CX POP DI POP SI POP BP POP CX POP BX POP AX RET PutChar ENDP ;********************************************************************* PrintRegs PROC Near CALL CRLF MOV BX, 0 PRE00: CALL PrintRegName MOV AL, " " CALL PutChar CALL PutChar CALL PutChar ADD BX, 2 CMP BX, 28 ;14 registers to print JL PRE00 CALL CRLF MOV BX, 0 PRE01: MOV AX, RegSave[BX] CALL PutNum MOV AL, " " CALL PutChar ADD BX, 2 CMP BX, 28 JL PRE01 RET PrintRegs ENDP ;********************************************************************* Parse PROC Near ;Try to parse the input buffer contents. If successful, set ;carry and change TargSpace, TargSeg, and TargOffset. ;If not successful, clear carry. CMP BufLen, 0 JNE Pr01 STC RET Pr01: CMP BufLen, 2 JNE Pr02 MOV BP, 0 CALL RegCheck JNC Pr02 ;jump if not a register name MOV TargSpace, RegSpace MOV TargOffset, BX STC RET Pr02: CMP Buf, "I" ;check for IO Space JNE Pr03 MOV BP, 1 MOV SI, BufLen CALL NumCheck ;get offset (maybe) JNC Pr03 MOV TargSpace, IOSpace JMP Pr11 Pr03: CLD ;find index of ":" if present MOV DI, OFFSET Buf MOV AX, DS MOV ES, AX MOV AL, ":" MOV CX, BufLen REPNE SCASB JE Pr04 ;ZF means ":" was found. DI has offset+1 MOV BP, 0 ;check for isolated number MOV SI, BufLen CALL NumCheck JNC Pr10 JMP Pr12 Pr04: SUB DI, OFFSET Buf CMP DI, 3 JNE Pr05 MOV BP, 0 ;string is of form xx:. . . Check for register name CALL RegCheck JNC Pr05 MOV AX, RegSave[BX] JMP Pr06 Pr05: MOV BP, 0 ;check for segment a number MOV SI, DI DEC SI CALL NumCheck JNC Pr10 Pr06: PUSH AX ;save segment for later MOV AX, BufLen SUB AX, DI CMP AX, 2 ;check for offset a register name JNE Pr07 MOV BP, DI CALL RegCheck JNC Pr07 MOV AX, RegSave[BX] JMP Pr08 Pr07: MOV BP, DI ;check for offset a number MOV SI, BufLen CALL NumCheck JNC Pr09 Pr08: POP BX MOV TargSeg, BX Pr12: MOV TargSpace, MemSpace Pr11: MOV TargOffset, AX Pr13: STC RET Pr09: POP AX Pr10: CLC RET Parse ENDP ;********************************************************************* ScanBP PROC Near ;ScanBP is used to enumerate the entries in the breakpoint table ;and call a procedure when a match is found. ;On entry, CX,DX contains a segment,offset breakpoint address, and ;SI,DI contains a comparison mask to be applied to each table entry. ;AX contains 0 if the match is to occur on unused entries, 10h if ;in-use entries are to be matched. ;BP contains the offset of the (near) proc to be called on a match. ;First, CX,DX are adjusted so that the offset is between 0 and 15, then ;for each entry in the breakpoint table, ; (SI and BreakSegment = CX) and (DI and BreakOffset = DX) ;is calculated. If this quantity is true, the proc is called. PUSH DX AND DX, 0Fh ;isolate offset OR DX, AX ;merge in-use bit POP AX SHR AX, 1 SHR AX, 1 SHR AX, 1 SHR AX, 1 ADD CX, AX ;CX now has break segment MOV BX, 0 ScBP00: MOV AX, BPTable [BX] AND AX, SI CMP AX, CX JNE ScBP01 MOV AX, BPTable+2 [BX] AND AX, DI CMP AX, DX JNE ScBP01 CALL BP ScBP01: ADD BX, 4 CMP BX, 4*BPLen JL ScBP00 RET ScanBP ENDP ;********************************************************************* BPExchange PROC Near ;This procedure is called to plant or remove all in-use breakpoints MOV AX, 10h ;match on in-use =1 MOV CX, 0 MOV DX, CX MOV SI, CX ;mask out all of BP entry except in-use bit MOV DI, AX MOV BP, OFFSET BPEx00 ;call-back proc CALL ScanBP RET BPEx00: MOV AX, BPTable+2 [BX] MOV ES, BPTable [BX] PUSH BX MOV BX, AX AND BX, 0Fh ;isolate offset of break byte XCHG AH, BYTE PTR ES: [BX] POP BX MOV BPTable+2 [BX], AX RET BPExchange ENDP ;********************************************************************* SetBP PROC Near ;Set a breakpoint at TargSeg:TargOffset. ;If successful, set carry, else clear carry MOV AX, 10h ;check for breakpoint already set MOV CX, TargSeg MOV DX, TargOffset MOV SI, 0FFFFh MOV DI, 1Fh MOV BP, OFFSET SBP00 CALL ScanBP MOV AX, 0 ;set breakpoint. Look for unused table entry MOV CX, AX MOV DX, AX MOV SI, AX MOV DI, 10h MOV BP, OFFSET SBP03 CALL ScanBP CLC ;no unused entries RET SBP03: POP AX ;have an unused entry. Fix stack POP AX MOV AX, TargOffset AND AX, 0Fh OR AX, 0CC10h ;break inst plus in-use MOV BPTable+2 [BX], AX MOV AX, TargOffset MOV CL, 4 SHR AX, CL ADD AX, TargSeg MOV BPTable [BX], AX STC RET SBP00: POP AX ;match on the break address. Pop two return ;links POP AX STC RET SetBP ENDP ;********************************************************************* PrintBreaks PROC Near ;print all breakpoint locations MOV AX, 10h MOV CX, 0 MOV DX, CX ;look for in-use BPTable entries MOV SI, CX MOV DI, 10h MOV BP, OFFSET PBrk00 CALL ScanBP RET PBrk00: MOV AL, " " CALL PutChar MOV AX, BPTable [BX] CALL PutNum MOV AX, ":" CALL PutChar MOV AX, BPTable+2 [BX] AND AX, 0Fh CMP AX, 0Ah JL PBrk01 ADD AX, "A" - 0Ah JMP PBrk02 PBrk01: ADD AX, "0" PBrk02: CALL PutChar RET PrintBreaks ENDP ;********************************************************************* SetInt PROC Near ;AX,CX has IP,CS for interrupt routine, BX has interrupt number ;This is a DOS call, but it appears not to work PUSH AX MOV AX,0 MOV ES, AX POP AX SHL BX, 1 SHL BX, 1 MOV WORD PTR ES: [BX], AX ;IP MOV WORD PTR ES: [BX+2], CX ;CS RET SetInt ENDP ;********************************************************************* InitBPTable PROC Near MOV BX, 0 IBpT00: MOV WORD PTR BPTable+2 [BX], 0 ADD BX, 4 CMP BX, 4*BPLen JL IBpT00 RET InitBPTable ENDP ;********************************************************************* SendCS PROC Near ;Send the contents of the Debugee code segment to the Prolog ;programmer in "P" format. On entry, RegAX contains 0 if ;even bytes are to be sent, 1 if odd bytes are to be sent. ;RegBX contains the length of CS (from the linker .MAP file) ;Prolog "P" format takes two ASCII characters (0-F) per byte. ;The initial header is start address (always 0, four characters), ;end address (four characters), 3 spaces followed by "P", followed ;by endAddress - startAddress + 1 bytes (2 characters each). MOV AL, 0 ;start address zero CALL SendByte CALL SendByte MOV AX, RegBX ;length of CS MOV BX, AX AND BX, 1 ;get lsb ADD AX, BX SHR AX, 1 ;number of bytes to send MOV DX, AX SUB AX, 1 ;endAddress MOV CL, 8 ROL AX, CL ;msb(endAddress) CALL SendByte ROL AX, CL ;lsb(endAddress) CALL SendByte MOV AL, "P" CALL SendChar MOV BX, RegAX ;even/odd indicator MOV AX, RegCS ;debugee CS MOV ES, AX SCS00: MOV AL, BYTE PTR ES: [BX] CALL SendByte ADD BX, 2 DEC DX JNE SCS00 RET SendCS ENDP ;********************************************************************* SendByte PROC Near ;send byte in AL as two ASCII characters PUSH AX SHR AX, 1 ;send msb first SHR AX, 1 SHR AX, 1 SHR AX, 1 CALL SBy00 POP AX CALL SBy00 RET SBy00: PUSH AX PUSH BX MOV BX, AX AND BX, 0Fh MOV AL, CS:SByTab[BX] CALL SendChar POP BX POP AX RET SByTab LABEL BYTE DB "0123456789ABCDEF" SendByte ENDP ;********************************************************************* SendChar PROC Near CALL PutChar PUSH DX MOV DX, 0 ;com card 0 MOV AH, 1 INT 14h POP DX RET SendChar ENDP CSeg ENDS END DDMain