From 926b631f3bf4fb14f31e1ba7af50df492a52cd3c Mon Sep 17 00:00:00 2001 From: FellippeHeitor Date: Thu, 16 Sep 2021 00:04:20 -0300 Subject: [PATCH] Implements watchpoints. --- internal/support/vwatch/vwatch.bm | 277 ++++++++++++++++++++++++++++-- source/ide/ide_methods.bas | 192 +++++++++++++++++---- 2 files changed, 421 insertions(+), 48 deletions(-) diff --git a/internal/support/vwatch/vwatch.bm b/internal/support/vwatch/vwatch.bm index e6c6990fb..e80067945 100644 --- a/internal/support/vwatch/vwatch.bm +++ b/internal/support/vwatch/vwatch.bm @@ -5,16 +5,16 @@ SUB vwatch (globalVariables AS _OFFSET, localVariables AS _OFFSET) STATIC AS LONG vw_runToLine, vw_originalVarLineNumber STATIC AS _BYTE vw_pauseMode, vw_stepOver, vw_bypass, vw_setNextLine, vw_hwndSent STATIC AS _OFFSET vw_ideHwnd - STATIC vw_buffer$ - DIM AS LONG vw_i, vw_tempIndex, vw_localIndex, vw_varSize, vw_cmdSize + STATIC vw_buffer$, vw_globalWatchpoints$, vw_localWatchpoints$ + DIM AS LONG vw_i, vw_j, vw_tempIndex, vw_localIndex, vw_varSize, vw_cmdSize DIM AS LONG vw_arrayElementSize, vw_element, vw_elementOffset, vw_storage, vw_blockSize DIM AS LONG vw_arrayDimension, vw_arrayTotalDimensions, vw_arrayIndex, vw_realArrayIndex DIM AS _OFFSET vw_address, vw_lBound, vw_uBound DIM AS _MEM vw_m, vw_m2 - DIM AS _BYTE vw_isArray, vw_isUDT + DIM AS _BYTE vw_isArray, vw_isUDT, vw_checkingWatchpoints DIM vw_start!, vw_temp$, vw_cmd$, vw_value$, vw_k&, vw_buf$, vw_scope$, vw_varType$ - DIM vw_prevValue$, vw_getBytes&, vw_getBytesPosition&, vw_valueBytes$, vw_dummy%& - DIM vw_arrayIndexes$ + DIM vw_getBytes&, vw_getBytesPosition&, vw_valueBytes$, vw_dummy%& + DIM vw_arrayIndexes$, vw_wpExpression$ DECLARE LIBRARY SUB vwatch_stoptimers ALIAS stop_timers @@ -27,8 +27,8 @@ SUB vwatch (globalVariables AS _OFFSET, localVariables AS _OFFSET) END DECLARE $IF WIN THEN - DECLARE DYNAMIC LIBRARY "user32" - FUNCTION SetForegroundWindow& (BYVAL hWnd AS _OFFSET) + DECLARE CUSTOMTYPE LIBRARY + FUNCTION vwSetForegroundWindow& ALIAS "SetForegroundWindow" (BYVAL hWnd AS _OFFSET) END DECLARE $END IF @@ -177,6 +177,20 @@ SUB vwatch (globalVariables AS _OFFSET, localVariables AS _OFFSET) REDIM vwatch_skiplines(UBOUND(vwatch_skiplines)) AS _BYTE END SELECT + IF LEN(vw_globalWatchpoints$) > 0 OR LEN(vw_localWatchpoints$) > 0 THEN + vw_checkingWatchpoints = -1 + GOSUB CheckWatchpoints + IF vw_checkingWatchpoints = 2 THEN + vw_checkingWatchpoints = 0 + vw_pauseMode = -1 + vw_stepOver = 0 + vw_runToLine = 0 + vw_cmd$ = "watchpoint:" + MKI$(LEN(vw_wpExpression$)) + vw_wpExpression$ + GOTO breakReached + END IF + END IF + vw_checkingWatchpoints = 0 + IF vwatch_skiplines(vwatch_linenumber) THEN vwatch_goto = -vwatch_linenumber: EXIT SUB IF vw_stepOver = -1 AND vwatch_sublevel > vw_startLevel AND vwatch_breakpoints(vwatch_linenumber) = 0 THEN @@ -197,16 +211,17 @@ SUB vwatch (globalVariables AS _OFFSET, localVariables AS _OFFSET) EXIT SUB END IF - vwatch_stoptimers vw_cmd$ = "line number:" IF vwatch_breakpoints(vwatch_linenumber) THEN vw_cmd$ = "breakpoint:" + breakReached: + vwatch_stoptimers vw_cmd$ = vw_cmd$ + MKL$(vwatch_linenumber) GOSUB SendCommand vw_cmd$ = "current sub:" + LEFT$(vwatch_stack(vwatch_sublevel), INSTR(vwatch_stack(vwatch_sublevel), ",") - 1) GOSUB SendCommand $IF WIN THEN - vw_i = SetForegroundWindow&(vw_ideHwnd) + vw_i = vwSetForegroundWindow&(vw_ideHwnd) $END IF DO 'main loop @@ -258,25 +273,45 @@ SUB vwatch (globalVariables AS _OFFSET, localVariables AS _OFFSET) 'send call stack history GOSUB SendCallStack CASE "get global var", "get local var" + getGlobalLocal: vw_getBytes& = 4: GOSUB GetBytes: vw_tempIndex = CVL(vw_valueBytes$) + PRINT "vw_tempIndex =" ; vw_tempIndex vw_getBytes& = 1: GOSUB GetBytes: vw_isArray = _CV(_BYTE, vw_valueBytes$) + PRINT "vw_isArray =" ; vw_isArray vw_getBytes& = 4: GOSUB GetBytes: vw_originalVarLineNumber = CVL(vw_valueBytes$) + PRINT "vw_originalVarLineNumber =" ; vw_originalVarLineNumber vw_getBytes& = 4: GOSUB GetBytes: vw_localIndex = CVL(vw_valueBytes$) + PRINT "vw_localIndex =" ; vw_localIndex vw_getBytes& = 4: GOSUB GetBytes: vw_arrayTotalDimensions = CVL(vw_valueBytes$) + PRINT "vw_arrayTotalDimensions =" ; vw_arrayTotalDimensions vw_getBytes& = vw_arrayTotalDimensions: GOSUB GetBytes: vw_arrayIndexes$ = vw_valueBytes$ vw_arrayTotalDimensions = vw_arrayTotalDimensions \ 4 + PRINT "vw_arrayTotalDimensions \ 4 =" ; vw_arrayTotalDimensions vw_getBytes& = 4: GOSUB GetBytes: vw_arrayElementSize = CVL(vw_valueBytes$) + PRINT "vw_arrayElementSize =" ; vw_arrayElementSize + IF vw_checkingWatchpoints THEN vw_getBytes& = 4: GOSUB GetBytes 'discard 4 bytes (isUDT) vw_getBytes& = 4: GOSUB GetBytes: vw_element = CVL(vw_valueBytes$) + PRINT "vw_element =" ; vw_element vw_getBytes& = 4: GOSUB GetBytes: vw_elementOffset = CVL(vw_valueBytes$) - vw_getBytes& = 4: GOSUB GetBytes: vw_varSize = CVL(vw_valueBytes$) - IF vw_varSize = 0 THEN GOTO cmdProcessingDone + PRINT "vw_elementOffset =" ; vw_elementOffset + vw_getBytes& = 4: GOSUB GetBytes: PRINT "LEN() = "; LEN(vw_valueBytes$): vw_varSize = CVL(vw_valueBytes$) + PRINT "vw_varSize =" ; vw_varSize + IF vw_varSize = 0 THEN + IF vw_checkingWatchpoints THEN + PRINT "RETURNING CAUSE VAR SIZE = 0": RETURN + END IF + GOTO cmdProcessingDone + END IF vw_getBytes& = 4: GOSUB GetBytes: vw_storage = CVL(vw_valueBytes$) + PRINT "vw_storage =" ; vw_storage vw_getBytes& = 2: GOSUB GetBytes: vw_i = CVI(vw_valueBytes$) IF vw_i THEN vw_getBytes& = vw_i: GOSUB GetBytes: vw_scope$ = vw_valueBytes$ + PRINT "vw_scope$ = " ; vw_scope$ END IF vw_getBytes& = 2: GOSUB GetBytes: vw_i = CVI(vw_valueBytes$) vw_getBytes& = vw_i: GOSUB GetBytes: vw_varType$ = vw_valueBytes$ + PRINT "vw_varType$ =" ; vw_varType$ IF vw_cmd$ = "get global var" THEN vw_address = _OFFSET(globalVariables) + LEN(vw_address) * vw_localIndex @@ -284,6 +319,7 @@ SUB vwatch (globalVariables AS _OFFSET, localVariables AS _OFFSET) IF vw_scope$ = LEFT$(vwatch_stack(vwatch_sublevel), INSTR(vwatch_stack(vwatch_sublevel), ",") - 1) THEN vw_address = _OFFSET(localVariables) + LEN(vw_address) * vw_localIndex ELSE + IF vw_checkingWatchpoints THEN PRINT "RETURNING CAUSE OUT OF SCOPE": RETURN GOTO cmdProcessingDone END IF END IF @@ -294,7 +330,10 @@ SUB vwatch (globalVariables AS _OFFSET, localVariables AS _OFFSET) IF vw_isArray THEN IF vw_originalVarLineNumber > 0 THEN 'prevent fetching array data before DIM line - IF vwatch_linenumber <= vw_originalVarLineNumber THEN GOTO cmdProcessingDone + IF vwatch_linenumber <= vw_originalVarLineNumber THEN + IF vw_checkingWatchpoints THEN PRINT "RETURNING CAUSE BEFORE DIM": RETURN + GOTO cmdProcessingDone + END IF END IF vw_realArrayIndex = 0 @@ -305,6 +344,7 @@ SUB vwatch (globalVariables AS _OFFSET, localVariables AS _OFFSET) vw_uBound = check_ubound%&(vw_address, vw_arrayDimension, vw_arrayTotalDimensions) vw_arrayIndex = CVL(MID$(vw_arrayIndexes$, vw_arrayDimension * 4 - 3, 4)) IF vw_arrayIndex < vw_lBound OR vw_arrayIndex > vw_uBound THEN + IF vw_checkingWatchpoints THEN PRINT "RETURNING CAUSE OUT OF BOUNDS": RETURN GOTO cmdProcessingDone END IF @@ -387,18 +427,29 @@ SUB vwatch (globalVariables AS _OFFSET, localVariables AS _OFFSET) _MEMCOPY vw_m, vw_m.OFFSET, vw_m.SIZE TO vw_m2, vw_m2.OFFSET END IF + IF vw_checkingWatchpoints THEN PRINT "RETURNING WITH VW_BUF$": RETURN + vw_cmd$ = "address read:" + MKL$(vw_tempIndex) + MKL$(vw_arrayIndex) + MKL$(vw_element) + MKL$(vw_storage) + vw_buf$ GOSUB SendCommand CASE "set global address", "set local address" + vw_getBytes& = 4: GOSUB GetBytes: vw_tempIndex = CVL(vw_valueBytes$) + vw_getBytes& = 1: GOSUB GetBytes: vw_isArray = _CV(_BYTE, vw_valueBytes$) + vw_getBytes& = 4: GOSUB GetBytes: vw_originalVarLineNumber = CVL(vw_valueBytes$) vw_getBytes& = 4: GOSUB GetBytes: vw_localIndex = CVL(vw_valueBytes$) - vw_getBytes& = 4: GOSUB GetBytes: vw_isArray = (CVL(vw_valueBytes$) <> 0) vw_getBytes& = 4: GOSUB GetBytes: vw_arrayTotalDimensions = CVL(vw_valueBytes$) vw_getBytes& = vw_arrayTotalDimensions: GOSUB GetBytes: vw_arrayIndexes$ = vw_valueBytes$ vw_arrayTotalDimensions = vw_arrayTotalDimensions \ 4 - vw_getBytes& = 4: GOSUB GetBytes: vw_isUDT = (CVL(vw_valueBytes$) <> 0) - vw_getBytes& = 4: GOSUB GetBytes: vw_elementOffset = CVL(vw_valueBytes$) vw_getBytes& = 4: GOSUB GetBytes: vw_arrayElementSize = CVL(vw_valueBytes$) + vw_getBytes& = 4: GOSUB GetBytes: vw_isUDT = (CVL(vw_valueBytes$) <> 0) + vw_getBytes& = 4: GOSUB GetBytes: vw_element = CVL(vw_valueBytes$) + vw_getBytes& = 4: GOSUB GetBytes: vw_elementOffset = CVL(vw_valueBytes$) vw_getBytes& = 4: GOSUB GetBytes: vw_varSize = CVL(vw_valueBytes$) + IF vw_varSize = 0 THEN GOTO cmdProcessingDone + vw_getBytes& = 4: GOSUB GetBytes: vw_storage = CVL(vw_valueBytes$) + vw_getBytes& = 2: GOSUB GetBytes: vw_i = CVI(vw_valueBytes$) + IF vw_i THEN + vw_getBytes& = vw_i: GOSUB GetBytes: vw_scope$ = vw_valueBytes$ + END IF vw_getBytes& = 2: GOSUB GetBytes: vw_i = CVI(vw_valueBytes$) vw_getBytes& = vw_i: GOSUB GetBytes: vw_varType$ = vw_valueBytes$ vw_getBytes& = 2: GOSUB GetBytes: vw_i = CVI(vw_valueBytes$) @@ -509,6 +560,73 @@ SUB vwatch (globalVariables AS _OFFSET, localVariables AS _OFFSET) 'vw_address now points to the actual data vw_m = _MEM(vw_address, vw_varSize) _MEMPUT vw_m, vw_m.OFFSET, vw_value$ + CASE "set global watchpoint", "set local watchpoint", "clear global watchpoint", "clear local watchpoint" + vw_getBytes& = 4: GOSUB GetBytes: vw_tempIndex = CVL(vw_valueBytes$) + vw_getBytes& = 1: GOSUB GetBytes: vw_isArray = _CV(_BYTE, vw_valueBytes$) + vw_getBytes& = 4: GOSUB GetBytes: vw_originalVarLineNumber = CVL(vw_valueBytes$) + vw_getBytes& = 4: GOSUB GetBytes: vw_localIndex = CVL(vw_valueBytes$) + vw_getBytes& = 4: GOSUB GetBytes: vw_arrayTotalDimensions = CVL(vw_valueBytes$) + vw_getBytes& = vw_arrayTotalDimensions: GOSUB GetBytes: vw_arrayIndexes$ = vw_valueBytes$ + + vw_temp$ = LEFT$(vw_value$, vw_arrayTotalDimensions + 37) + + vw_arrayTotalDimensions = vw_arrayTotalDimensions \ 4 + vw_getBytes& = 4: GOSUB GetBytes: vw_arrayElementSize = CVL(vw_valueBytes$) + vw_getBytes& = 4: GOSUB GetBytes: vw_isUDT = (CVL(vw_valueBytes$) <> 0) + vw_getBytes& = 4: GOSUB GetBytes: vw_element = CVL(vw_valueBytes$) + vw_getBytes& = 4: GOSUB GetBytes: vw_elementOffset = CVL(vw_valueBytes$) + vw_getBytes& = 4: GOSUB GetBytes: vw_varSize = CVL(vw_valueBytes$) + IF vw_varSize = 0 THEN GOTO cmdProcessingDone + vw_getBytes& = 4: GOSUB GetBytes: vw_storage = CVL(vw_valueBytes$) + vw_getBytes& = 2: GOSUB GetBytes: vw_i = CVI(vw_valueBytes$) + IF vw_i THEN + vw_getBytes& = vw_i: GOSUB GetBytes: vw_scope$ = vw_valueBytes$ + END IF + vw_getBytes& = 2: GOSUB GetBytes: vw_i = CVI(vw_valueBytes$) + vw_getBytes& = vw_i: GOSUB GetBytes: vw_varType$ = vw_valueBytes$ + vw_getBytes& = 2: GOSUB GetBytes: vw_i = CVI(vw_valueBytes$) + vw_getBytes& = vw_i: GOSUB GetBytes: vw_wpExpression$ = vw_valueBytes$ + + PRINT "WATCHPOINT ----------------------------------------------" + PRINT "vw_tempIndex =" ; vw_tempIndex + PRINT "vw_isArray =" ; vw_isArray + PRINT "vw_originalVarLineNumber =" ; vw_originalVarLineNumber + PRINT "vw_localIndex =" ; vw_localIndex + PRINT "vw_arrayTotalDimensions \ 4 =" ; vw_arrayTotalDimensions + PRINT "vw_arrayElementSize =" ; vw_arrayElementSize + PRINT "vw_element =" ; vw_element + PRINT "vw_elementOffset =" ; vw_elementOffset + PRINT "vw_varSize =" ; vw_varSize + PRINT "vw_storage =" ; vw_storage + PRINT "vw_scope$ = " ; vw_scope$ + PRINT "vw_varType$ =" ; vw_varType$ + PRINT "vw_wpExpression$ =" ; vw_wpExpression$ + + IF INSTR(vw_cmd$, " global ") THEN + vw_buf$ = vw_globalWatchpoints$ + ELSE + vw_scope$ = LEFT$(vwatch_stack(vwatch_sublevel), INSTR(vwatch_stack(vwatch_sublevel), ",") - 1) + vw_value$ = vw_value$ + MKI$(LEN(vw_scope$)) + vw_scope$ + vw_buf$ = vw_localWatchpoints$ + END IF + + vw_i = INSTR(vw_buf$, vw_temp$) + IF vw_i > 0 THEN + 'remove existing watchpoint for the same variable/index/element + vw_j = CVL(MID$(vw_buf$, vw_i - 4, 4)) + vw_buf$ = LEFT$(vw_buf$, vw_i - 5) + MID$(vw_buf$, vw_i + vw_j) + END IF + + IF LEFT$(vw_cmd$, 4) = "set " THEN + vw_value$ = MKI$(LEN(vw_wpExpression$)) + vw_wpExpression$ + vw_value$ + vw_buf$ = vw_buf$ + MKL$(LEN(vw_value$)) + vw_value$ + END IF + + IF vw_cmd$ = "set global watchpoint" THEN + vw_globalWatchpoints$ = vw_buf$ + ELSE + vw_localWatchpoints$ = vw_buf$ + END IF CASE "current sub" vw_cmd$ = "current sub:" + LEFT$(vwatch_stack(vwatch_sublevel), INSTR(vwatch_stack(vwatch_sublevel), ",") - 1) GOSUB SendCommand @@ -595,4 +713,133 @@ SUB vwatch (globalVariables AS _OFFSET, localVariables AS _OFFSET) vw_valueBytes$ = MID$(vw_value$, vw_getBytesPosition&, vw_getBytes&) vw_getBytesPosition& = vw_getBytesPosition& + vw_getBytes& RETURN + + CheckWatchpoints: + PRINT "Checking watchpoints." + DIM AS LONG vw_wpi, vw_wpj + DIM vw_wpTemp$, vw_v1$, vw_v2$ + FOR vw_wpi = 1 TO 2 + PRINT "vw_wpi ="; vw_wpi + IF vw_wpi = 1 AND LEN(vw_globalWatchpoints$) > 0 THEN + vw_wpTemp$ = vw_globalWatchpoints$ + ELSEIF vw_wpi = 2 AND LEN(vw_localWatchpoints$) > 0 THEN + vw_wpTemp$ = vw_localWatchpoints$ + ELSE + _CONTINUE + END IF + + DO WHILE LEN(vw_wpTemp$) + vw_wpj = CVL(LEFT$(vw_wpTemp$, 4)) + PRINT "vw_wpj ="; vw_wpj + vw_value$ = MID$(vw_wpTemp$, 5, vw_wpj) + vw_wpTemp$ = MID$(vw_wpTemp$, 5 + vw_wpj) + IF vw_wpi = 1 THEN vw_cmd$ = "get global var" ELSE vw_cmd$ = "get local var" + + vw_getBytesPosition& = 1 + vw_getBytes& = 2: GOSUB GetBytes: vw_i = CVI(vw_valueBytes$) + vw_getBytes& = vw_i: GOSUB GetBytes: vw_wpExpression$ = vw_valueBytes$ + PRINT "vw_wpExpression$: "; vw_wpExpression$ + vw_value$ = MID$(vw_value$, 3 + LEN(vw_wpExpression$)) + + PRINT "going to sub getGlobalLocal" + vw_getBytesPosition& = 1 + GOSUB getGlobalLocal + + PRINT "got value!! --------------------------" + PRINT "vw_varType$ = "; vw_varType$ + IF INSTR(vw_varType$, "STRING") THEN + PRINT "It's a string" + IF LEFT$(vw_wpExpression$, 1) = "=" THEN + IF _TRIM$(MID$(vw_wpExpression$, 2)) = _TRIM$(vw_buf$) THEN GOTO WatchPointBreak + ELSEIF LEFT$(vw_wpExpression$, 2) = "<=" THEN + IF _TRIM$(MID$(vw_wpExpression$, 2)) <= _TRIM$(vw_buf$) THEN GOTO WatchPointBreak + ELSEIF LEFT$(vw_wpExpression$, 2) = ">=" THEN + IF _TRIM$(MID$(vw_wpExpression$, 2)) >= _TRIM$(vw_buf$) THEN GOTO WatchPointBreak + ELSEIF LEFT$(vw_wpExpression$, 2) = "<>" THEN + IF _TRIM$(MID$(vw_wpExpression$, 2)) <> _TRIM$(vw_buf$) THEN GOTO WatchPointBreak + ELSEIF LEFT$(vw_wpExpression$, 1) = "<" THEN + IF _TRIM$(MID$(vw_wpExpression$, 2)) < _TRIM$(vw_buf$) THEN GOTO WatchPointBreak + ELSEIF LEFT$(vw_wpExpression$, 1) = ">" THEN + IF _TRIM$(MID$(vw_wpExpression$, 2)) > _TRIM$(vw_buf$) THEN GOTO WatchPointBreak + END IF + ELSE + PRINT "It's a number" + IF LEFT$(vw_wpExpression$, 1) = "=" THEN + vw_v1$ = _TRIM$(MID$(vw_wpExpression$, 2)) + ELSEIF LEFT$(vw_wpExpression$, 2) = "<=" OR LEFT$(vw_wpExpression$, 2) = ">=" OR LEFT$(vw_wpExpression$, 2) = "<>" THEN + vw_v1$ = _TRIM$(MID$(vw_wpExpression$, 3)) + ELSEIF LEFT$(vw_wpExpression$, 1) = "<" OR LEFT$(vw_wpExpression$, 1) = ">" THEN + vw_v1$ = _TRIM$(MID$(vw_wpExpression$, 2)) + END IF + + GOSUB GetV2 + PRINT "vw_v1$ = "; vw_v1$ + PRINT "vw_v2$ = "; vw_v2$ + + IF LEFT$(vw_wpExpression$, 1) = "=" THEN + IF VAL(vw_v2$) = VAL(vw_v1$) THEN GOTO WatchPointBreak + ELSEIF LEFT$(vw_wpExpression$, 2) = "<=" THEN + IF VAL(vw_v2$) <= VAL(vw_v1$) THEN GOTO WatchPointBreak + ELSEIF LEFT$(vw_wpExpression$, 2) = ">=" THEN + IF VAL(vw_v2$) >= VAL(vw_v1$) THEN GOTO WatchPointBreak + ELSEIF LEFT$(vw_wpExpression$, 2) = "<>" THEN + IF VAL(vw_v2$) <> VAL(vw_v1$) THEN GOTO WatchPointBreak + ELSEIF LEFT$(vw_wpExpression$, 1) = "<" THEN + IF VAL(vw_v2$) < VAL(vw_v1$) THEN GOTO WatchPointBreak + ELSEIF LEFT$(vw_wpExpression$, 1) = ">" THEN + IF VAL(vw_v2$) > VAL(vw_v1$) THEN GOTO WatchPointBreak + END IF + END IF + LOOP + NEXT + RETURN + + WatchPointBreak: + 'send watchpoint info and pause + vw_checkingWatchpoints = 2 + RETURN + + GetV2: + PRINT "ENTERING GetV2 --------------------------- + PRINT "vw_varType$ = "; vw_varType$ + PRINT "LEN(vw_buf$) ="; LEN(vw_buf$) + IF INSTR(vw_varType$, "BIT *") THEN + IF VAL(MID$(vw_varType$, _INSTRREV(vw_varType$, " ") + 1)) > 32 THEN + IF INSTR(vw_varType$, "UNSIGNED") THEN + vw_v2$ = STR$(_CV(_UNSIGNED _INTEGER64, vw_buf$)) + ELSE + vw_v2$ = STR$(_CV(_INTEGER64, vw_buf$)) + END IF + ELSE + IF INSTR(vw_varType$, "UNSIGNED") THEN + vw_v2$ = STR$(_CV(_UNSIGNED LONG, vw_buf$)) + ELSE + vw_v2$ = STR$(_CV(LONG, vw_buf$)) + END IF + END IF + RETURN + ELSEIF INSTR("@_BIT@BIT@_UNSIGNED _BIT@UNSIGNED BIT@", "@" + vw_varType$ + "@") THEN + IF INSTR(vw_varType$, "UNSIGNED") THEN + vw_v2$ = STR$(_CV(_UNSIGNED LONG, vw_buf$)) + ELSE + vw_v2$ = STR$(_CV(LONG, vw_buf$)) + END IF + RETURN + END IF + SELECT CASE vw_varType$ + CASE "_BYTE", "BYTE": vw_v2$ = STR$(_CV(_BYTE, vw_buf$)) + CASE "_UNSIGNED _BYTE", "UNSIGNED BYTE": vw_v2$ = STR$(_CV(_UNSIGNED _BYTE, vw_buf$)) + CASE "INTEGER": vw_v2$ = STR$(_CV(INTEGER, vw_buf$)) + CASE "_UNSIGNED INTEGER", "UNSIGNED INTEGER": vw_v2$ = STR$(_CV(_UNSIGNED INTEGER, vw_buf$)) + CASE "LONG": vw_v2$ = STR$(_CV(LONG, vw_buf$)) + CASE "_UNSIGNED LONG", "UNSIGNED LONG": vw_v2$ = STR$(_CV(_UNSIGNED LONG, vw_buf$)) + CASE "_INTEGER64", "INTEGER64": vw_v2$ = STR$(_CV(_INTEGER64, vw_buf$)) + CASE "_UNSIGNED _INTEGER64", "UNSIGNED INTEGER64": vw_v2$ = STR$(_CV(_UNSIGNED _INTEGER64, vw_buf$)) + CASE "SINGLE": vw_v2$ = STR$(CVS(vw_buf$)) + CASE "DOUBLE": vw_v2$ = STR$(CVD(vw_buf$)) + CASE "_FLOAT", "FLOAT": vw_v2$ = STR$(_CV(_FLOAT, vw_buf$)) + CASE "_OFFSET", "OFFSET": vw_v2$ = STR$(_CV(_OFFSET, vw_buf$)) + CASE "_UNSIGNED _OFFSET", "UNSIGNED OFFSET": vw_v2$ = STR$(_CV(_UNSIGNED _OFFSET, vw_buf$)) + END SELECT + RETURN END SUB diff --git a/source/ide/ide_methods.bas b/source/ide/ide_methods.bas index a4a70f40e..0da59e192 100644 --- a/source/ide/ide_methods.bas +++ b/source/ide/ide_methods.bas @@ -7128,19 +7128,24 @@ SUB DebugMode filter$ = "" DO result$ = idevariablewatchbox$(currentSub$, filter$, selectVar, returnAction) + temp$ = GetBytes$("", 0) 'reset buffer IF returnAction = 1 THEN - temp$ = GetBytes$("", 0) 'reset buffer 'set address tempIndex& = CVL(GetBytes$(result$, 4)) + tempIsArray& = _CV(_BYTE, GetBytes$(result$, 1)) + temp$ = GetBytes$(result$, 4) 'skip original line number tempLocalIndex& = CVL(GetBytes$(result$, 4)) - tempIsArray& = CVL(GetBytes$(result$, 4)) tempArrayIndex& = CVL(GetBytes$(result$, 4)) tempArrayIndexes$ = MKL$(tempArrayIndex&) + GetBytes$(result$, tempArrayIndex&) - tempIsUDT& = CVL(GetBytes$(result$, 4)) - tempElementOffset& = CVL(GetBytes$(result$, 4)) tempArrayElementSize& = CVL(GetBytes$(result$, 4)) + tempIsUDT& = CVL(GetBytes$(result$, 4)) + temp$ = GetBytes$(result$, 4) 'skip element number + tempElementOffset& = CVL(GetBytes$(result$, 4)) + temp$ = GetBytes$(result$, 4) 'skip var size tempStorage& = CVL(GetBytes$(result$, 4)) i = CVI(GetBytes$(result$, 2)) + tempScope$ = GetBytes$(result$, i) + i = CVI(GetBytes$(result$, 2)) varType$ = GetBytes$(result$, i) i = CVI(GetBytes$(result$, 2)) value$ = GetBytes$(result$, i) @@ -7227,13 +7232,18 @@ SUB DebugMode END IF END SELECT + cmd$ = cmd$ + MKL$(tempIndex&) + cmd$ = cmd$ + _MK$(_BYTE, tempIsArray& <> 0) + cmd$ = cmd$ + MKL$(0) cmd$ = cmd$ + MKL$(tempLocalIndex&) - cmd$ = cmd$ + MKL$(tempIsArray&) cmd$ = cmd$ + tempArrayIndexes$ - cmd$ = cmd$ + MKL$(tempIsUDT&) - cmd$ = cmd$ + MKL$(tempElementOffset&) cmd$ = cmd$ + MKL$(tempArrayElementSize&) + cmd$ = cmd$ + MKL$(tempIsUDT&) + cmd$ = cmd$ + MKL$(0) + cmd$ = cmd$ + MKL$(tempElementOffset&) cmd$ = cmd$ + MKL$(varSize&) + cmd$ = cmd$ + MKL$(tempStorage&) + cmd$ = cmd$ + MKI$(LEN(tempScope$)) + tempScope$ cmd$ = cmd$ + MKI$(LEN(varType$)) + varType$ cmd$ = cmd$ + MKI$(LEN(value$)) + value$ GOSUB SendCommand @@ -7246,7 +7256,61 @@ SUB DebugMode WHILE _MOUSEINPUT: WEND hidePanel = -1 GOSUB UpdateDisplay - ELSEIF returnAction = 2 THEN + ELSEIF returnAction = 2 OR returnAction = 3 THEN + 'send watchpoint data + tempIndex& = CVL(GetBytes$(result$, 4)) + tempIsArray& = _CV(_BYTE, GetBytes$(result$, 1)) <> 0 + temp$ = GetBytes$(result$, 4) 'skip original line number + tempLocalIndex& = CVL(GetBytes$(result$, 4)) + tempArrayIndex& = CVL(GetBytes$(result$, 4)) + tempArrayIndexes$ = MKL$(tempArrayIndex&) + GetBytes$(result$, tempArrayIndex&) + tempArrayElementSize& = CVL(GetBytes$(result$, 4)) + tempIsUDT& = CVL(GetBytes$(result$, 4)) + tempElement& = CVL(GetBytes$(result$, 4)) + tempElementOffset& = CVL(GetBytes$(result$, 4)) + temp$ = GetBytes$(result$, 4) 'skip var size + tempStorage& = CVL(GetBytes$(result$, 4)) + i = CVI(GetBytes$(result$, 2)) + tempScope$ = GetBytes$(result$, i) + i = CVI(GetBytes$(result$, 2)) + varType$ = GetBytes$(result$, i) + i = CVI(GetBytes$(result$, 2)) + value$ = GetBytes$(result$, i) + + IF returnAction = 2 THEN + temp$ = "set " + ELSE + 'clear watchpoint data + temp$ = "clear " + END IF + + IF LEN(usedVariableList(tempIndex&).subfunc) = 0 THEN + cmd$ = temp$ + "global watchpoint:" + ELSE + cmd$ = temp$ + "local watchpoint:" + END IF + + cmd$ = cmd$ + MKL$(tempIndex&) + cmd$ = cmd$ + _MK$(_BYTE, tempIsArray& <> 0) + cmd$ = cmd$ + MKL$(usedVariableList(tempIndex&).linenumber) + cmd$ = cmd$ + MKL$(tempLocalIndex&) + cmd$ = cmd$ + tempArrayIndexes$ + cmd$ = cmd$ + MKL$(tempArrayElementSize&) + cmd$ = cmd$ + MKL$(tempIsUDT&) + cmd$ = cmd$ + MKL$(tempElement&) + cmd$ = cmd$ + MKL$(tempElementOffset&) + cmd$ = cmd$ + MKL$(varSize&) + cmd$ = cmd$ + MKL$(tempStorage&) + cmd$ = cmd$ + MKI$(LEN(tempScope$)) + tempScope$ + cmd$ = cmd$ + MKI$(LEN(varType$)) + varType$ + cmd$ = cmd$ + MKI$(LEN(value$)) + value$ + GOSUB SendCommand + + PCOPY 3, 0: SCREEN , , 3, 0 + WHILE _MOUSEINPUT: WEND + hidePanel = -1 + GOSUB UpdateDisplay + ELSEIF returnAction = -1 THEN PCOPY 3, 0: SCREEN , , 3, 0 WHILE _MOUSEINPUT: WEND hidePanel = -1 @@ -7453,8 +7517,15 @@ SUB DebugMode GOSUB GetCommand SELECT CASE cmd$ - CASE "breakpoint", "line number" + CASE "breakpoint", "line number", "watchpoint" BypassRequestCallStack = 0 + IF cmd$ = "watchpoint" THEN + temp$ = GetBytes$("", 0) 'reset buffer + i = CVI(GetBytes$(value$, 2)) + temp$ = GetBytes$(value$, i) + result = idemessagebox("Watchpoint", temp$, "#OK") + value$ = RIGHT$(value$, 4) + END IF l = CVL(value$) idecy = l ideselect = 0 @@ -7969,7 +8040,7 @@ FUNCTION idevariablewatchbox$(currentScope$, filter$, selectVar, returnAction) o(buttonSet).typ = 3 o(buttonSet).y = dialogHeight IF IdeDebugMode > 0 AND o(buttonSet).txt = 0 THEN - o(buttonSet).txt = idenewtxt("#Add All" + sep + "#Remove All" + sep + "#Send Value" + sep + "#Close") + o(buttonSet).txt = idenewtxt("#Add All" + sep + "#Remove All" + sep + "#Send Value" + sep + "Add #Watchpoint" + sep + "#Close") ELSE o(buttonSet).txt = idenewtxt("#Add All" + sep + "#Remove All" + sep + "#Close") END IF @@ -8095,9 +8166,23 @@ FUNCTION idevariablewatchbox$(currentScope$, filter$, selectVar, returnAction) _CONTINUE END IF - IF (IdeDebugMode > 0 AND focus = 5 AND info <> 0) THEN - 'set address + IF (IdeDebugMode > 0 AND focus = 5 AND info <> 0) OR _ + (IdeDebugMode > 0 AND focus = 6 AND info <> 0) THEN + 'set address/add watchpoint sendValue: + SELECT CASE focus + CASE 5 + dlgTitle$ = "Change Value" + dlgPrompt$ = "#Index to change" + dlgPrompt2$ = "#New value" + thisReturnAction = 1 + CASE 6 + dlgTitle$ = "Add Watchpoint" + dlgPrompt$ = "#Index to monitor" + dlgPrompt2$ = "#Condition" + thisReturnAction = 2 + END SELECT + y = ABS(o(varListBox).sel) IF y >= 1 AND y <= totalVisibleVariables THEN @@ -8111,7 +8196,7 @@ FUNCTION idevariablewatchbox$(currentScope$, filter$, selectVar, returnAction) tempElementOffset$ = MKL$(0) IF usedVariableList(tempIndex&).isarray THEN setArrayRange3: - v$ = ideinputbox$("Change Value", "#Index to change", temp$, "01234567890,", 45, 0, ok) + v$ = ideinputbox$(dlgTitle$, dlgPrompt$, temp$, "01234567890,", 45, 0, ok) IF ok THEN IF LEN(v$) > 0 THEN WHILE RIGHT$(v$, 1) = ",": v$ = LEFT$(v$, LEN(v$) - 1): WEND @@ -8188,7 +8273,7 @@ FUNCTION idevariablewatchbox$(currentScope$, filter$, selectVar, returnAction) temp$ = v$ IF numelements(temp$) <> 1 THEN 'shouldn't ever happen - result = idemessagebox("Error", "Only one UDT element can be changed at a time", "#OK") + result = idemessagebox("Error", "Only one UDT element can be selected at a time", "#OK") _CONTINUE END IF @@ -8244,7 +8329,7 @@ FUNCTION idevariablewatchbox$(currentScope$, filter$, selectVar, returnAction) END IF ELSE 'shouldn't ever happen - result = idemessagebox("Error", "Cannot send value to full UDT", "#OK") + result = idemessagebox("Error", "Cannot select full UDT", "#OK") GOTO dlgLoop END IF END SELECT @@ -8279,38 +8364,78 @@ FUNCTION idevariablewatchbox$(currentScope$, filter$, selectVar, returnAction) ELSE thisWidth = 45 END IF - v$ = ideinputbox$("Change Value", "#New value", a2$, "", thisWidth, 0, ok) + getNewValueInput: + v$ = ideinputbox$(dlgTitle$, dlgPrompt2$, a2$, "", thisWidth, 0, ok) IF ok THEN - temp$ = "" - temp$ = temp$ + MKL$(tempIndex&) - temp$ = temp$ + MKL$(usedVariableList(tempIndex&).localindex) - temp$ = temp$ + MKL$(usedVariableList(tempIndex&).isarray <> 0) - temp$ = temp$ + tempArrayIndexes$ - temp$ = temp$ + MKL$(tempIsUDT&) - temp$ = temp$ + tempElementOffset$ - temp$ = temp$ + MKL$(usedVariableList(tempIndex&).arrayElementSize) - temp$ = temp$ + MKL$(storageSlot&) - temp$ = temp$ + MKI$(LEN(varType$)) + varType$ - temp$ = temp$ + MKI$(LEN(v$)) + v$ - idevariablewatchbox$ = temp$ - returnAction = 1 'actually send value + IF focus = 6 THEN + 'validate condition string first + v$ = LTRIM$(v$) + IF LEN(v$) < 2 THEN + v$ = "" + thisReturnAction = 3 'remove watchpoint for this variable + ELSE + StartWatchPointEval: + op1$ = LEFT$(v$, 1) + op2$ = MID$(v$, 2, 1) + SELECT CASE op1$ + CASE "=" + IF op2$ = "<" OR op2$ = ">" THEN + MID$(v$, 1, 2) = op2$ + "=" + GOTO StartWatchPointEval + END IF + CASE ">" + IF op2$ = "<" OR op2$ = ">" THEN + result = idemessagebox(dlgTitle$, "Invalid expression.\nYou can use =, <>, >, >=, < and <=", "#OK") + GOTO getNewValueInput + END IF + CASE "<" + CASE ELSE + result = idemessagebox(dlgTitle$, "Invalid expression.\nYou can use =, <>, >, >=, < and <=", "#OK") + GOTO getNewValueInput + END SELECT + END IF + END IF + + cmd$ = "" + cmd$ = cmd$ + MKL$(tempIndex&) + cmd$ = cmd$ + _MK$(_BYTE, usedVariableList(tempIndex&).isarray) + cmd$ = cmd$ + MKL$(usedVariableList(tempIndex&).linenumber) + cmd$ = cmd$ + MKL$(usedVariableList(tempIndex&).localIndex) + cmd$ = cmd$ + tempArrayIndexes$ + cmd$ = cmd$ + MKL$(usedVariableList(tempIndex&).arrayElementSize) + cmd$ = cmd$ + MKL$(tempIsUDT&) + cmd$ = cmd$ + MKL$(tempElement&) + IF tempElement& THEN + tempElementOffset& = CVL(MID$(usedVariableList(tempIndex&).elementOffset, tempElement& * 4 - 3, 4)) + ELSE + tempElementOffset& = 0 + END IF + cmd$ = cmd$ + MKL$(tempElementOffset&) + cmd$ = cmd$ + MKL$(varSize&) + cmd$ = cmd$ + MKL$(tempStorage&) + cmd$ = cmd$ + MKI$(LEN(usedVariableList(tempIndex&).subfunc)) + cmd$ = cmd$ + usedVariableList(tempIndex&).subfunc + cmd$ = cmd$ + MKI$(LEN(varType$)) + varType$ + cmd$ = cmd$ + MKI$(LEN(v$)) + v$ + idevariablewatchbox$ = cmd$ + returnAction = thisReturnAction 'actually send command ELSE - returnAction = 2 'redraw and carry on + returnAction = -1 'redraw and carry on END IF selectVar = y EXIT FUNCTION ELSE - result = idemessagebox("Change Value", "Variable is out of scope.", "#OK") + result = idemessagebox(dlgTitle$, "Variable is out of scope.", "#OK") END IF ELSE - result = idemessagebox("Change Value", "Select a variable first.", "#OK") + result = idemessagebox(dlgTitle$, "Select a variable first.", "#OK") END IF focus = filterBox _CONTINUE END IF IF K$ = CHR$(27) OR (IdeDebugMode = 0 AND focus = 5 AND info <> 0) OR _ - (IdeDebugMode > 0 AND focus = 6 AND info <> 0) THEN + (IdeDebugMode > 0 AND focus = 7 AND info <> 0) THEN variableWatchList$ = "" longestVarName = 0 nextvWatchDataSlot = 0 @@ -8425,6 +8550,7 @@ FUNCTION idevariablewatchbox$(currentScope$, filter$, selectVar, returnAction) IF mCLICK AND focus = 2 THEN 'list click IF timeElapsedSince(lastClick!) < .3 AND clickedItem = o(varListBox).sel THEN IF doubleClickThreshold > 0 AND mX >= p.x + doubleClickThreshold AND IdeDebugMode > 0 THEN + focus = 5 GOTO sendValue ELSE GOTO toggleWatch