2021-07-22 21:39:20 +00:00
|
|
|
$CHECKING:OFF
|
|
|
|
|
2021-07-26 17:52:14 +00:00
|
|
|
SUB vwatch (globalVariables AS _OFFSET, localVariables AS _OFFSET)
|
2021-07-22 21:39:20 +00:00
|
|
|
STATIC AS LONG ideHost, breakpointCount, skipCount, timeout, startLevel, lastLine
|
|
|
|
STATIC AS LONG callStackLength, runToLine
|
|
|
|
STATIC AS _BYTE pauseMode, stepOver, bypass, setNextLine
|
|
|
|
STATIC buffer$, endc$
|
2021-07-26 17:52:14 +00:00
|
|
|
DIM AS LONG i, tempIndex, localIndex
|
2021-07-22 21:39:20 +00:00
|
|
|
DIM AS _OFFSET address
|
|
|
|
DIM AS _MEM m
|
2021-07-26 17:52:14 +00:00
|
|
|
DIM start!, temp$, cmd$, value$, k&, dataType$, result$
|
2021-07-22 21:39:20 +00:00
|
|
|
|
|
|
|
DECLARE LIBRARY
|
|
|
|
SUB vwatch_stoptimers ALIAS stop_timers
|
|
|
|
SUB vwatch_starttimers ALIAS start_timers
|
|
|
|
SUB unlockvWatchHandle
|
|
|
|
END DECLARE
|
|
|
|
|
|
|
|
IF bypass THEN EXIT SUB
|
|
|
|
|
|
|
|
vwatch_goto = 0
|
|
|
|
|
|
|
|
IF ideHost = 0 THEN
|
|
|
|
timeout = 10
|
|
|
|
endc$ = "<END>"
|
|
|
|
|
|
|
|
'initial setup
|
|
|
|
GOSUB Connect
|
|
|
|
|
|
|
|
'send this binary's path/exe name
|
|
|
|
cmd$ = "me:" + COMMAND$(0)
|
|
|
|
GOSUB SendCommand
|
|
|
|
|
|
|
|
DO
|
|
|
|
GOSUB GetCommand
|
|
|
|
SELECT CASE cmd$
|
|
|
|
CASE "vwatch"
|
|
|
|
IF value$ <> "ok" THEN
|
|
|
|
unlockvWatchHandle: CLOSE #ideHost
|
|
|
|
bypass = -1
|
|
|
|
EXIT SUB
|
|
|
|
END IF
|
|
|
|
CASE "line count"
|
|
|
|
REDIM vwatch_breakpoints(CVL(value$)) AS _BYTE
|
|
|
|
REDIM vwatch_skiplines(CVL(value$)) AS _BYTE
|
|
|
|
CASE "breakpoint count"
|
|
|
|
breakpointCount = CVL(value$)
|
|
|
|
CASE "breakpoint list"
|
|
|
|
IF LEN(value$) \ 4 <> breakpointCount THEN
|
|
|
|
cmd$ = "quit:Communication error."
|
|
|
|
GOSUB SendCommand
|
|
|
|
unlockvWatchHandle: CLOSE #ideHost
|
|
|
|
bypass = -1
|
|
|
|
EXIT SUB
|
|
|
|
END IF
|
|
|
|
FOR i = 1 TO breakpointCount
|
|
|
|
temp$ = MID$(value$, i * 4 - 3, 4)
|
|
|
|
vwatch_breakpoints(CVL(temp$)) = -1
|
|
|
|
NEXT
|
|
|
|
CASE "skip count"
|
|
|
|
skipCount = CVL(value$)
|
|
|
|
CASE "skip list"
|
|
|
|
IF LEN(value$) \ 4 <> skipCount THEN
|
|
|
|
cmd$ = "quit:Communication error."
|
|
|
|
GOSUB SendCommand
|
|
|
|
unlockvWatchHandle: CLOSE #ideHost
|
|
|
|
bypass = -1
|
|
|
|
EXIT SUB
|
|
|
|
END IF
|
|
|
|
FOR i = 1 TO skipCount
|
|
|
|
temp$ = MID$(value$, i * 4 - 3, 4)
|
|
|
|
vwatch_skiplines(CVL(temp$)) = -1
|
|
|
|
NEXT
|
|
|
|
CASE "run"
|
|
|
|
IF vwatch_breakpoints(vwatch_linenumber) THEN EXIT DO
|
|
|
|
pauseMode = 0
|
|
|
|
EXIT SUB
|
|
|
|
CASE "break"
|
|
|
|
pauseMode = -1
|
|
|
|
EXIT DO
|
|
|
|
END SELECT
|
|
|
|
LOOP
|
|
|
|
END IF
|
|
|
|
|
|
|
|
IF vwatch_linenumber = 0 THEN
|
|
|
|
GOSUB SendCallStack
|
|
|
|
cmd$ = "quit:Program ended."
|
|
|
|
GOSUB SendCommand
|
|
|
|
unlockvWatchHandle: CLOSE #ideHost
|
|
|
|
bypass = -1
|
|
|
|
ideHost = 0
|
|
|
|
EXIT SUB
|
|
|
|
ELSEIF vwatch_linenumber = -1 THEN
|
|
|
|
'report an error in the most recent line
|
|
|
|
GOSUB SendCallStack
|
|
|
|
cmd$ = "error:" + MKL$(lastLine)
|
|
|
|
GOSUB SendCommand
|
|
|
|
EXIT SUB
|
|
|
|
ELSEIF vwatch_linenumber = -2 THEN
|
|
|
|
'report a new sub/function has been "entered"
|
|
|
|
IF LEN(vwatch_callstack) > 100000 THEN
|
|
|
|
vwatch_callstack = ""
|
|
|
|
callStackLength = 0
|
|
|
|
END IF
|
|
|
|
callStackLength = callStackLength + 1
|
|
|
|
IF LEN(vwatch_callstack) THEN vwatch_callstack = vwatch_callstack + CHR$(0)
|
|
|
|
vwatch_callstack = vwatch_callstack + vwatch_subname$ + ", line" + STR$(lastLine)
|
|
|
|
EXIT SUB
|
|
|
|
ELSEIF vwatch_linenumber = -3 THEN
|
|
|
|
'handle STOP - instead of quitting, pause execution
|
|
|
|
pauseMode = -1
|
|
|
|
stepOver = 0
|
|
|
|
EXIT SUB
|
|
|
|
END IF
|
|
|
|
|
|
|
|
IF vwatch_linenumber = lastLine AND setNextLine = 0 THEN EXIT SUB
|
|
|
|
setNextLine = 0
|
|
|
|
lastLine = vwatch_linenumber
|
|
|
|
|
|
|
|
GOSUB GetCommand
|
|
|
|
SELECT CASE cmd$
|
|
|
|
CASE "break"
|
|
|
|
pauseMode = -1
|
|
|
|
stepOver = 0
|
|
|
|
runToLine = 0
|
|
|
|
cmd$ = ""
|
|
|
|
CASE "set breakpoint"
|
|
|
|
vwatch_breakpoints(CVL(value$)) = -1
|
|
|
|
vwatch_skiplines(CVL(value$)) = 0
|
|
|
|
CASE "clear breakpoint"
|
|
|
|
vwatch_breakpoints(CVL(value$)) = 0
|
|
|
|
CASE "set skip line"
|
|
|
|
vwatch_skiplines(CVL(value$)) = -1
|
|
|
|
vwatch_breakpoints(CVL(value$)) = 0
|
|
|
|
CASE "clear skip line"
|
|
|
|
vwatch_skiplines(CVL(value$)) = 0
|
|
|
|
CASE "clear all breakpoints"
|
|
|
|
REDIM vwatch_breakpoints(UBOUND(vwatch_breakpoints)) AS _BYTE
|
|
|
|
CASE "clear all skips"
|
|
|
|
REDIM vwatch_skiplines(UBOUND(vwatch_skiplines)) AS _BYTE
|
|
|
|
END SELECT
|
|
|
|
|
|
|
|
IF vwatch_skiplines(vwatch_linenumber) THEN vwatch_goto = -vwatch_linenumber: EXIT SUB
|
|
|
|
|
|
|
|
IF stepOver = -1 AND vwatch_sublevel > startLevel AND vwatch_breakpoints(vwatch_linenumber) = 0 THEN
|
|
|
|
EXIT SUB
|
|
|
|
ELSEIF stepOver = -1 AND vwatch_sublevel = startLevel THEN
|
|
|
|
stepOver = 0
|
|
|
|
pauseMode = -1
|
|
|
|
END IF
|
|
|
|
|
|
|
|
IF runToLine > 0 AND runToLine <> vwatch_linenumber THEN
|
|
|
|
EXIT SUB
|
|
|
|
ELSEIF runToLine > 0 AND runToLine = vwatch_linenumber THEN
|
|
|
|
pauseMode = -1
|
|
|
|
runToLine = 0
|
|
|
|
END IF
|
|
|
|
|
|
|
|
IF vwatch_breakpoints(vwatch_linenumber) = 0 AND pauseMode = 0 THEN
|
|
|
|
EXIT SUB
|
|
|
|
END IF
|
|
|
|
|
|
|
|
vwatch_stoptimers
|
|
|
|
cmd$ = "line number:"
|
|
|
|
IF vwatch_breakpoints(vwatch_linenumber) THEN cmd$ = "breakpoint:"
|
|
|
|
cmd$ = cmd$ + MKL$(vwatch_linenumber)
|
|
|
|
GOSUB SendCommand
|
|
|
|
|
|
|
|
DO 'main loop
|
|
|
|
SELECT CASE cmd$
|
|
|
|
CASE "run"
|
|
|
|
pauseMode = 0
|
|
|
|
stepOver = 0
|
|
|
|
vwatch_starttimers
|
|
|
|
EXIT SUB
|
|
|
|
CASE "run to line"
|
|
|
|
pauseMode = 0
|
|
|
|
stepOver = 0
|
|
|
|
runToLine = CVL(value$)
|
|
|
|
vwatch_starttimers
|
|
|
|
EXIT SUB
|
|
|
|
CASE "step"
|
|
|
|
pauseMode = -1
|
|
|
|
stepOver = 0
|
|
|
|
EXIT SUB
|
|
|
|
CASE "step over"
|
|
|
|
pauseMode = -1
|
|
|
|
stepOver = -1
|
|
|
|
startLevel = vwatch_sublevel
|
|
|
|
vwatch_starttimers
|
|
|
|
EXIT SUB
|
|
|
|
CASE "step out"
|
|
|
|
pauseMode = -1
|
|
|
|
stepOver = -1
|
|
|
|
startLevel = vwatch_sublevel - 1
|
|
|
|
vwatch_starttimers
|
|
|
|
EXIT SUB
|
|
|
|
CASE "free"
|
|
|
|
unlockvWatchHandle: CLOSE #ideHost
|
|
|
|
ideHost = 0
|
|
|
|
bypass = -1
|
|
|
|
vwatch_starttimers
|
|
|
|
EXIT SUB
|
|
|
|
CASE "set breakpoint"
|
|
|
|
vwatch_breakpoints(CVL(value$)) = -1
|
|
|
|
vwatch_skiplines(CVL(value$)) = 0
|
|
|
|
CASE "clear breakpoint"
|
|
|
|
vwatch_breakpoints(CVL(value$)) = 0
|
|
|
|
CASE "clear all breakpoints"
|
|
|
|
REDIM vwatch_breakpoints(UBOUND(vwatch_breakpoints)) AS _BYTE
|
|
|
|
CASE "clear all skips"
|
|
|
|
REDIM vwatch_skiplines(UBOUND(vwatch_skiplines)) AS _BYTE
|
|
|
|
CASE "call stack"
|
|
|
|
'send call stack history"
|
|
|
|
GOSUB SendCallStack
|
2021-07-26 17:52:14 +00:00
|
|
|
CASE "global var"
|
|
|
|
tempIndex = CVL(LEFT$(value$, 4))
|
|
|
|
localIndex = CVL(MID$(value$, 5, 4))
|
|
|
|
dataType$ = MID$(value$, 9)
|
|
|
|
address = globalVariables + LEN(address) * localIndex
|
|
|
|
GOSUB GetMemData
|
|
|
|
$CONSOLE
|
|
|
|
_ECHO "global var requested:" + STR$(tempIndex) + dataType$
|
|
|
|
_ECHO "== result = " + result$
|
|
|
|
cmd$ = "global var:" + MKL$(tempIndex) + result$
|
|
|
|
GOSUB SendCommand
|
|
|
|
CASE "local var"
|
|
|
|
tempIndex = CVL(LEFT$(value$, 4))
|
|
|
|
localIndex = CVL(MID$(value$, 5, 4))
|
|
|
|
dataType$ = MID$(value$, 9)
|
|
|
|
address = localVariables + LEN(address) * localIndex
|
|
|
|
GOSUB GetMemData
|
|
|
|
_ECHO "local var requested:" + STR$(tempIndex) + dataType$
|
|
|
|
_ECHO "== result = " + result$
|
|
|
|
cmd$ = "local var:" + MKL$(tempIndex) + result$
|
|
|
|
GOSUB SendCommand
|
2021-07-24 22:31:58 +00:00
|
|
|
CASE "current sub"
|
|
|
|
cmd$ = "current sub:" + vwatch_subname
|
|
|
|
GOSUB SendCommand
|
2021-07-22 21:39:20 +00:00
|
|
|
CASE "set next line"
|
|
|
|
pauseMode = -1
|
|
|
|
stepOver = 0
|
|
|
|
setNextLine = -1
|
|
|
|
vwatch_goto = CVL(value$)
|
|
|
|
EXIT SUB
|
|
|
|
CASE "set skip line"
|
|
|
|
vwatch_skiplines(CVL(value$)) = -1
|
|
|
|
vwatch_breakpoints(CVL(value$)) = 0
|
|
|
|
CASE "clear skip line"
|
|
|
|
vwatch_skiplines(CVL(value$)) = 0
|
|
|
|
END SELECT
|
|
|
|
|
|
|
|
GOSUB GetCommand
|
|
|
|
_LIMIT 100
|
|
|
|
LOOP
|
|
|
|
|
|
|
|
vwatch_starttimers
|
|
|
|
EXIT SUB
|
|
|
|
|
|
|
|
Connect:
|
|
|
|
DIM ideport$
|
|
|
|
ideport$ = ENVIRON$("QB64DEBUGPORT")
|
|
|
|
IF ideport$ = "" THEN bypass = -1: EXIT SUB
|
|
|
|
|
|
|
|
start! = TIMER
|
|
|
|
DO
|
|
|
|
k& = _KEYHIT
|
|
|
|
ideHost = _OPENCLIENT("QB64IDE:" + ideport$ + ":localhost")
|
|
|
|
_LIMIT 30
|
|
|
|
LOOP UNTIL k& = 27 OR ideHost <> 0 OR TIMER - start! > timeout
|
|
|
|
IF ideHost = 0 THEN bypass = -1: EXIT SUB
|
|
|
|
RETURN
|
|
|
|
|
|
|
|
GetCommand:
|
|
|
|
GET #ideHost, , temp$
|
|
|
|
buffer$ = buffer$ + temp$
|
|
|
|
|
|
|
|
IF INSTR(buffer$, endc$) THEN
|
|
|
|
cmd$ = LEFT$(buffer$, INSTR(buffer$, endc$) - 1)
|
|
|
|
buffer$ = MID$(buffer$, INSTR(buffer$, endc$) + LEN(endc$))
|
|
|
|
|
|
|
|
IF INSTR(cmd$, ":") THEN
|
|
|
|
value$ = MID$(cmd$, INSTR(cmd$, ":") + 1)
|
|
|
|
cmd$ = LEFT$(cmd$, INSTR(cmd$, ":") - 1)
|
|
|
|
ELSE
|
|
|
|
value$ = ""
|
|
|
|
END IF
|
|
|
|
ELSE
|
|
|
|
cmd$ = "": value$ = ""
|
|
|
|
END IF
|
|
|
|
RETURN
|
|
|
|
|
|
|
|
SendCallStack:
|
|
|
|
cmd$ = "call stack size:" + MKL$(callStackLength)
|
|
|
|
GOSUB SendCommand
|
|
|
|
cmd$ = "call stack:" + vwatch_callstack
|
|
|
|
GOSUB SendCommand
|
|
|
|
RETURN
|
|
|
|
|
|
|
|
SendCommand:
|
|
|
|
cmd$ = cmd$ + endc$
|
|
|
|
PUT #ideHost, , cmd$
|
|
|
|
cmd$ = ""
|
|
|
|
RETURN
|
2021-07-26 17:52:14 +00:00
|
|
|
|
|
|
|
GetMemData:
|
|
|
|
DIM integerType AS INTEGER, uintegerType AS _UNSIGNED INTEGER
|
|
|
|
DIM longType AS LONG, ulongType AS _UNSIGNED LONG
|
|
|
|
DIM singleType AS SINGLE, doubleType AS DOUBLE
|
|
|
|
|
|
|
|
SELECT CASE dataType$
|
|
|
|
CASE "INTEGER"
|
|
|
|
integerType = _MEMGET(m, address, INTEGER)
|
|
|
|
result$ = STR$(integerType)
|
|
|
|
CASE "_UNSIGNED INTEGER"
|
|
|
|
uintegerType = _MEMGET(m, address, _UNSIGNED INTEGER)
|
|
|
|
result$ = STR$(uintegerType)
|
|
|
|
CASE "LONG"
|
|
|
|
longType = _MEMGET(m, address, LONG)
|
|
|
|
result$ = STR$(longType)
|
|
|
|
CASE "_UNSIGNED LONG"
|
|
|
|
ulongType = _MEMGET(m, address, _UNSIGNED LONG)
|
|
|
|
result$ = STR$(ulongType)
|
|
|
|
CASE "SINGLE"
|
|
|
|
singleType = _MEMGET(m, address, SINGLE)
|
|
|
|
result$ = STR$(singleType)
|
|
|
|
CASE "DOUBLE"
|
|
|
|
doubleType = _MEMGET(m, address, DOUBLE)
|
|
|
|
result$ = STR$(doubleType)
|
|
|
|
END SELECT
|
|
|
|
RETURN
|
2021-07-22 21:39:20 +00:00
|
|
|
END SUB
|