LazDebuggerFp, FpDebug: Modify watches/values in target

git-svn-id: trunk@65154 -
This commit is contained in:
martin 2021-05-30 19:01:08 +00:00
parent 37c8a252a1
commit 574b3a8178
10 changed files with 1059 additions and 37 deletions

View File

@ -146,6 +146,7 @@ type
function ReadMemory(AnAddress: TDbgPtr; ASize: Cardinal; ADest: Pointer): Boolean; override; overload;
function ReadMemory(AnAddress: TDbgPtr; ASize: Cardinal; ADest: Pointer; out ABytesRead: Cardinal): Boolean; override; overload;
function ReadMemoryEx(AnAddress, AnAddressSpace: TDbgPtr; ASize: Cardinal; ADest: Pointer): Boolean; override;
function WriteMemory(AnAddress: TDbgPtr; ASize: Cardinal; ASource: Pointer): Boolean; override; overload;
function ReadRegister(ARegNum: Cardinal; out AValue: TDbgPtr; AContext: TFpDbgLocationContext): Boolean; override;
function RegisterSize(ARegNum: Cardinal): Integer; override;
@ -1303,6 +1304,12 @@ begin
result := GetDbgProcess.ReadData(AnAddress, ASize, ADest^);
end;
function TDbgMemReader.WriteMemory(AnAddress: TDbgPtr; ASize: Cardinal;
ASource: Pointer): Boolean;
begin
result := GetDbgProcess.WriteData(AnAddress, ASize, ASource^);
end;
function TDbgMemReader.ReadRegister(ARegNum: Cardinal; out AValue: TDbgPtr; AContext: TFpDbgLocationContext): Boolean;
var
ARegister: TDbgRegisterValue;

View File

@ -306,13 +306,14 @@ type
function GetFieldFlags: TFpValueFieldFlags; override;
function GetAsString: AnsiString; override;
function GetAsWideString: WideString; override;
procedure SetAsString(AValue: AnsiString); override;
end;
{ TFpValueDwarfPointer }
TFpValueDwarfPointer = class(TFpValueDwarfNumeric)
private
FPointetToAddr: TFpDbgMemLocation;
FPointedToAddr: TFpDbgMemLocation;
function GetDerefAddress: TFpDbgMemLocation;
protected
function GetAsCardinal: QWord; override;
@ -384,6 +385,7 @@ type
function GetMember(AIndex: Int64): TFpValue; override;
function GetAsCardinal: QWord; override; // only up to qmord
function IsValidTypeCast: Boolean; override;
procedure SetAsString(AValue: AnsiString); override;
public
destructor Destroy; override;
end;
@ -2133,13 +2135,18 @@ procedure TFpValueDwarfInteger.SetAsInteger(AValue: Int64);
var
Size: TFpDbgValueSize;
begin
if (not GetSize(Size)) or (Size <= 0) or (Size > SizeOf(AValue)) then
inherited SetAsCardinal(AValue)
if (not GetSize(Size)) or (Size <= 0) or (Size > SizeOf(AValue)) then begin
inherited SetAsCardinal(AValue);
end
else
if not Context.WriteSignedInt(OrdOrDataAddr, Size, AValue) then begin
SetLastError(Context.LastMemError);
Exclude(FEvaluated, doneInt);
end
else begin
FIntValue := AValue;
Include(FEvaluated, doneInt);
end;
Exclude(FEvaluated, doneUInt);
end;
procedure TFpValueDwarfInteger.SetAsCardinal(AValue: QWord);
@ -2185,13 +2192,18 @@ procedure TFpValueDwarfCardinal.SetAsCardinal(AValue: QWord);
var
Size: TFpDbgValueSize;
begin
if (not GetSize(Size)) or (Size <= 0) or (Size > SizeOf(AValue)) then
inherited SetAsCardinal(AValue)
if (not GetSize(Size)) or (Size <= 0) or (Size > SizeOf(AValue)) then begin
inherited SetAsCardinal(AValue);
end
else
if not Context.WriteUnsignedInt(OrdOrDataAddr, Size, AValue) then begin
SetLastError(Context.LastMemError);
Exclude(FEvaluated, doneUInt);
end
else begin
FValue := AValue;
Include(FEvaluated, doneUInt);
end;
Exclude(FEvaluated, doneUInt);
end;
{ TFpValueDwarfFloat }
@ -2289,6 +2301,32 @@ begin
Result := WideChar(Word(GetAsCardinal));
end;
procedure TFpValueDwarfChar.SetAsString(AValue: AnsiString);
var
Size: TFpDbgValueSize;
u: UnicodeString;
begin
if not GetSize(Size) then
Size := ZeroSize;
if Size.Size > 2 then begin
inherited SetAsString(AValue);
end
else
if Size.Size = 2 then begin
u := UTF8Decode(AValue);
if Length(u) <> 1 then
inherited SetAsString(AValue) // error
else
SetAsCardinal(Word(u[1]));
end
else begin
if Length(AValue) <> 1 then
inherited SetAsString(AValue) // error
else
SetAsCardinal(Byte(AValue[1]));
end;
end;
{ TFpValueDwarfPointer }
function TFpValueDwarfPointer.GetDerefAddress: TFpDbgMemLocation;
@ -2297,7 +2335,7 @@ var
Addr: TFpDbgMemLocation;
begin
if doneAddr in FEvaluated then begin
Result := FPointetToAddr;
Result := FPointedToAddr;
exit;
end;
Include(FEvaluated, doneAddr);
@ -2312,7 +2350,7 @@ begin
SetLastError(Context.LastMemError);
end;
end;
FPointetToAddr := Result;
FPointedToAddr := Result;
end;
function TFpValueDwarfPointer.GetAsCardinal: QWord;
@ -2493,8 +2531,14 @@ end;
procedure TFpValueDwarfPointer.SetAsCardinal(AValue: QWord);
begin
if not Context.WriteSignedInt(OrdOrDataAddr, SizeVal(Context.SizeOfAddress), AValue) then
if not Context.WriteSignedInt(OrdOrDataAddr, SizeVal(Context.SizeOfAddress), AValue) then begin
SetLastError(Context.LastMemError);
Exclude(FEvaluated, doneAddr);
end
else begin
FPointedToAddr := TargetLoc(TDBGPtr(AValue));
Include(FEvaluated, doneAddr);
end;
end;
{ TFpValueDwarfEnum }
@ -2554,13 +2598,18 @@ procedure TFpValueDwarfEnum.SetAsCardinal(AValue: QWord);
var
Size: TFpDbgValueSize;
begin
if (not GetSize(Size)) or (Size <= 0) or (Size > SizeOf(AValue)) then
inherited SetAsCardinal(AValue)
if (not GetSize(Size)) or (Size <= 0) or (Size > SizeOf(AValue)) then begin
inherited SetAsCardinal(AValue);
end
else
if not Context.WriteEnum(OrdOrDataAddr, Size, AValue) then begin
SetLastError(Context.LastMemError);
Exclude(FEvaluated, doneUInt);
end
else begin
FValue := AValue;
Include(FEvaluated, doneUInt);
end;
Exclude(FEvaluated, doneUInt);
end;
function TFpValueDwarfEnum.GetAsString: AnsiString;
@ -2811,8 +2860,9 @@ var
Size: TFpDbgValueSize;
begin
Result := 0;
if not GetSize(Size) then
if (not GetSize(Size)) or (Size < 0) or (Size > SizeOf(QWord)) then
exit;
InitMap;
if (Size <= SizeOf(Result)) and (length(FMem) > 0) then
move(FMem[0], Result, Min(SizeOf(Result), SizeToFullBytes(Size)));
end;
@ -2849,6 +2899,159 @@ begin
Result := False;
end;
procedure TFpValueDwarfSet.SetAsString(AValue: AnsiString);
type
TCharSet = set of char;
function CheckInChar(var p: PChar; c: TCharSet): Boolean;
begin
Result := p^ in c;
if Result then
inc(p)
else
SetLastError(CreateError(fpErrFailedWriteMem));
end;
procedure SkipSpaces(var p: Pchar);
begin
while p^ in [' ', #9] do inc(p);
end;
function CopySubString(PEnd, PStart: PChar): String;
begin
SetLength(Result, PEnd - PStart);
move(PStart^, Result[1], PEnd - PStart);
end;
var
Size: TFpDbgValueSize;
WriteMem: array of Byte;
p, p2: PChar;
s: String;
idx: Integer;
t: TFpSymbolDwarfType;
nest: TFpSymbol;
v, lb, hb, MemIdx, Bit: Int64;
DAddr: TFpDbgMemLocation;
begin
if not GetSize(Size) then
Size := ZeroSize;
if (Size <= 0) then begin
SetLastError(CreateError(fpErrFailedWriteMem));
exit;
end;
InitMap;
t := TypeInfo;
if t = nil then exit;
t := t.TypeInfo;
if t = nil then exit;
assert(t is TFpSymbolDwarfType, 'TDbgDwarfSetSymbolValue.GetMember t');
SetLength(WriteMem, SizeToFullBytes(Size));
p := Pchar(AValue);
SkipSpaces(p);
if not CheckInChar(p, ['[']) then
exit;
SkipSpaces(p);
if p^ <> ']' then begin // not an empty set
if t.Kind = skEnum then begin
while p^ in ['a'..'z', 'A'..'Z', '_'] do begin
p2 := p;
inc(p);
while p^ in ['a'..'z', 'A'..'Z', '_', '0'..'9'] do
inc(p);
s := LowerCase(CopySubString(p, p2));
idx := t.GetNestedSymbolCount - 1;
while idx >= 0 do begin
nest := t.GetNestedSymbol(idx);
if (nest <> nil) and (LowerCase(nest.Name) = s) then
break;
dec(idx);
end;
if (idx >= 0) then begin
v := nest.OrdinalValue;
if (v >= 0) and (v < Length(WriteMem) * 8) then begin
MemIdx := v shr 3;
Bit := 1 shl (v and 7);
WriteMem[MemIdx] := WriteMem[MemIdx] or Bit;
end
else
idx := -1;
end;
if idx < 0 then begin
SetLastError(CreateError(fpErrFailedWriteMem));
exit;
end;
SkipSpaces(p);
if p^ = ']' then
break;
if not CheckInChar(p, [',']) then
exit;
SkipSpaces(p);
end;
SkipSpaces(p);
end
else begin // set of 1..9
if not t.GetValueBounds(nil, lb, hb) then begin
SetLastError(CreateError(fpErrFailedWriteMem));
exit;
end;
while p^ in ['0'..'9', '$', '%', '&'] do begin
p2 := p;
inc(p);
case p[-1] of
'$': while p^ in ['a'..'f', 'A'..'F', '0'..'9'] do inc(p);
'&': while p^ in ['0'..'7'] do inc(p);
'%': while p^ in ['0'..'1'] do inc(p);
else while p^ in ['0'..'9'] do inc(p);
end;
if not TryStrToInt(CopySubString(p, p2), idx) then begin
SetLastError(CreateError(fpErrFailedWriteMem));
exit;
end;
idx := idx - lb;
if (idx >= 0) and (idx < Length(WriteMem) * 8) then begin
MemIdx := idx shr 3;
Bit := 1 shl (idx and 7);
WriteMem[MemIdx] := WriteMem[MemIdx] or Bit;
end
else begin
SetLastError(CreateError(fpErrFailedWriteMem));
exit;
end;
SkipSpaces(p);
if p^ = ']' then
break;
if not CheckInChar(p, [',']) then
exit;
SkipSpaces(p);
end;
SkipSpaces(p);
end;
end;
if not CheckInChar(p, [']']) then
exit;
SkipSpaces(p);
if not CheckInChar(p, [#0]) then
exit;
// we got the value
FMem := nil;
// todo writeset
GetDwarfDataAddress(DAddr);
if not Context.WriteSet(DAddr, Size, WriteMem) then begin
SetLastError(Context.LastMemError);
exit; // TODO: error
end;
end;
destructor TFpValueDwarfSet.Destroy;
begin
FTypedNumValue.ReleaseReference;
@ -3649,12 +3852,16 @@ begin
if Form in [DW_FORM_data1, DW_FORM_data2, DW_FORM_data4, DW_FORM_data8,
DW_FORM_sdata, DW_FORM_udata]
then begin
if AReadState <> nil then
AReadState^ := rfConst;
Result := InformationEntry.ReadValue(AnAttribData, AValue);
if not Result then
if Result then begin
if AReadState <> nil then
AReadState^ := rfConst;
end
else begin
if AReadState <> nil then
AReadState^ := rfError;
SetLastError(AValueObj, CreateError(fpErrAnyError));
end;
end
else
@ -3682,6 +3889,8 @@ begin
AValue := ValObj.AsInteger;
if IsError(ValObj.LastError) then begin
Result := False;
if AReadState <> nil then
AReadState^ := rfError;
SetLastError(AValueObj, ValObj.LastError);
end;
ValObj.ReleaseReference;
@ -3695,8 +3904,11 @@ begin
RefSymbol.ReleaseReference;
end;
end;
if (not Result) and (not HasError(AValueObj)) then
if (not Result) and (not HasError(AValueObj)) then begin
if AReadState <> nil then
AReadState^ := rfError;
SetLastError(AValueObj, CreateError(fpErrAnyError));
end;
end
else
@ -3720,13 +3932,19 @@ begin
InitLocParserData.ObjectDataAddress := AValueObj.OrdOrAddress;
InitLocParserData.ObjectDataAddrPush := False;
Result := LocationFromAttrData(AnAttribData, AValueObj, t, @InitLocParserData);
if Result then
AValue := Int64(t.Address)
else
if Result then begin
AValue := Int64(t.Address);
end
else begin
if AReadState <> nil then
AReadState^ := rfError;
SetLastError(AValueObj, CreateError(fpErrLocationParser));
end;
end
else begin
if AReadState <> nil then
AReadState^ := rfError;
SetLastError(AValueObj, CreateError(fpErrAnyError));
end;

View File

@ -146,6 +146,8 @@ type
// AnOpts: TFpDbgMemReadOptions): Boolean; inline;
function ReadSet (const ALocation: TFpDbgMemLocation; ASize: TFpDbgValueSize;
out AValue: TBytes): Boolean; inline;
function WriteSet (const ALocation: TFpDbgMemLocation; ASize: TFpDbgValueSize;
const AValue: TBytes): Boolean; inline;
//function ReadSet (const ALocation: TFpDbgMemLocation; ASize: TFpDbgValueSize;
// out AValue: TBytes;
// AnOpts: TFpDbgMemReadOptions): Boolean; inline;
@ -168,6 +170,7 @@ type
// inherited Memreaders should implement partial size ReadMemory, and forward it to the TDbgProcess class
function ReadMemory(AnAddress: TDbgPtr; ASize: Cardinal; ADest: Pointer; out ABytesRead: Cardinal): Boolean; virtual; overload;
function ReadMemoryEx(AnAddress, AnAddressSpace: TDbgPtr; ASize: Cardinal; ADest: Pointer): Boolean; virtual; abstract;
function WriteMemory(AnAddress: TDbgPtr; ASize: Cardinal; ASource: Pointer): Boolean; virtual; abstract; overload;
// ReadRegister may need TargetMemConvertor
// Register with reduced size are treated as unsigned
// TODO: ReadRegister should only take THREAD-ID, not context
@ -975,6 +978,12 @@ begin
Result := MemManager.ReadMemory(rdtSet, ALocation, ASize, @AValue[0], Length(AValue), Self);
end;
function TFpDbgLocationContext.WriteSet(const ALocation: TFpDbgMemLocation;
ASize: TFpDbgValueSize; const AValue: TBytes): Boolean;
begin
Result := MemManager.WriteMemory(rdtSet, ALocation, ASize, @AValue[0], Length(AValue), Self);
end;
function TFpDbgLocationContext.ReadFloat(const ALocation: TFpDbgMemLocation;
ASize: TFpDbgValueSize; out AValue: Extended): Boolean;
begin
@ -1689,6 +1698,12 @@ begin
Result := True;
end;
mlfTargetMem:
begin
if (BitOffset = 0) and (ADestSize.BitSize = 0) and (ADestSize.Size > 0) then begin
FMemReader.WriteMemory(LocToAddr(ADestLocation), SizeToFullBytes(ADestSize), ASource);
end;
end;
end;
if (not Result) and (not IsError(FLastError)) then

View File

@ -121,6 +121,13 @@ type
constructor Create(ADebugger: TFpDebugDebuggerBase; ALocals: TLocals);
end;
{ TFpThreadWorkerModifyUpdate }
TFpThreadWorkerModifyUpdate = class(TFpThreadWorkerModify)
protected
procedure DoCallback_DecRef(Data: PtrInt = 0); override;
end;
{ TFpThreadWorkerWatchValueEvalUpdate }
TFpThreadWorkerWatchValueEvalUpdate = class(TFpThreadWorkerWatchValueEval)
@ -555,6 +562,7 @@ type
function ReadMemoryEx(AnAddress, AnAddressSpace: TDbgPtr; ASize: Cardinal; ADest: Pointer): Boolean; override;
function ReadRegister(ARegNum: Cardinal; out AValue: TDbgPtr;
AContext: TFpDbgLocationContext): Boolean; override;
//WriteMemory is not overwritten. It must ONLY be called in the debug-thread
end;
{ TFpWaitForConsoleOutputThread }
@ -576,6 +584,18 @@ begin
RegisterDebugger(TFpDebugDebugger);
end;
{ TFpThreadWorkerModifyUpdate }
procedure TFpThreadWorkerModifyUpdate.DoCallback_DecRef(Data: PtrInt);
begin
//
FDebugger.Locals.CurrentLocalsList.Clear;
FDebugger.Watches.CurrentWatches.ClearValues;
FDebugger.CallStack.CurrentCallStackList.Clear;
UnQueue_DecRef;
end;
{ TFpDbgDebggerThreadWorkerItemHelper }
function TFpDbgDebggerThreadWorkerItemHelper.FpDebugger: TFpDebugDebugger;
@ -3083,6 +3103,7 @@ var
WorkItem: TFpThreadWorkerControllerRun;
AThreadId, AStackFrame: Integer;
EvalWorkItem: TFpThreadWorkerCmdEval;
WorkItemModify: TFpThreadWorkerModifyUpdate;
begin
result := False;
if assigned(FDbgController) then
@ -3254,6 +3275,15 @@ begin
FWorkQueue.PushItem(FEvalWorkItem);
Result := True;
end;
dcModify:
begin
GetCurrentThreadAndStackFrame(AThreadId, AStackFrame);
WorkItemModify := TFpThreadWorkerModifyUpdate.Create(Self, AnsiString(AParams[0].VAnsiString), AnsiString(AParams[1].VAnsiString),
AStackFrame, AThreadId);
FWorkQueue.PushItem(WorkItemModify);
WorkItemModify.DecRef;
Result := True;
end;
dcSendConsoleInput:
begin
FDbgController.CurrentProcess.SendConsoleInput(String(AParams[0].VAnsiString));
@ -3795,7 +3825,8 @@ end;
class function TFpDebugDebugger.GetSupportedCommands: TDBGCommands;
begin
Result:=[dcRun, dcStop, dcStepIntoInstr, dcStepOverInstr, dcStepOver,
dcStepTo, dcRunTo, dcPause, dcStepOut, dcStepInto, dcEvaluate, dcSendConsoleInput
dcStepTo, dcRunTo, dcPause, dcStepOut, dcStepInto, dcEvaluate, dcModify,
dcSendConsoleInput
{$IFDEF windows} , dcAttach, dcDetach {$ENDIF}
{$IFDEF linux} , dcAttach, dcDetach {$ENDIF}
];

View File

@ -123,6 +123,7 @@ type
type
TFpThreadWorkerPriority = (
twpModify, // this is a user actions
twpUser,
twpThread, twpStack, twpLocal, twpWatch,
twpContinue

View File

@ -210,6 +210,26 @@ type
destructor Destroy; override;
end;
{ TFpThreadWorkerModify }
TFpThreadWorkerModify = class(TFpDbgDebggerThreadWorkerLinkedItem)
private
FExpression, FNewVal: String;
FStackFrame, FThreadId: Integer;
FSuccess: Boolean;
protected
procedure DoCallback_DecRef(Data: PtrInt = 0); virtual; abstract;
procedure DoExecute; override;
property Success: Boolean read FSuccess;
public
constructor Create(ADebugger: TFpDebugDebuggerBase;
//APriority: TFpThreadWorkerPriority;
const AnExpression, ANewValue: String;
AStackFrame, AThreadId: Integer
);
function DebugText: String; override;
end;
{ TFpThreadWorkerEvaluate }
TFpThreadWorkerEvaluate = class(TFpDbgDebggerThreadWorkerLinkedItem)
@ -692,6 +712,70 @@ begin
inherited Destroy;
end;
{ TFpThreadWorkerModify }
procedure TFpThreadWorkerModify.DoExecute;
var
APasExpr: TFpPascalExpression;
ResValue: TFpValue;
ExpressionScope: TFpDbgSymbolScope;
i64: int64;
c64: QWord;
begin
FSuccess := False;
ExpressionScope := FDebugger.FDbgController.CurrentProcess.FindSymbolScope(FThreadId, FStackFrame);
if ExpressionScope = nil then
exit;
APasExpr := TFpPascalExpression.Create(FExpression, ExpressionScope);
try
APasExpr.ResultValue; // trigger full validation
if not APasExpr.Valid then
exit;
ResValue := APasExpr.ResultValue;
if ResValue = nil then
exit;
case ResValue.Kind of
skInteger: if TryStrToInt64(FNewVal, i64) then ResValue.AsInteger := i64;
skCardinal: if TryStrToQWord(FNewVal, c64) then ResValue.AsCardinal := c64;
skBoolean: case LowerCase(trim(FNewVal)) of
'true': ResValue.AsBool := True;
'false': ResValue.AsBool := False;
end;
skChar: ResValue.AsString := FNewVal;
skEnum: ResValue.AsString := FNewVal;
skSet: ResValue.AsString := FNewVal;
skPointer: if TryStrToQWord(FNewVal, c64) then ResValue.AsCardinal := c64;
skFloat: ;
skCurrency: ;
skVariant: ;
end;
finally
APasExpr.Free;
ExpressionScope.ReleaseReference;
Queue(@DoCallback_DecRef);
end;
end;
constructor TFpThreadWorkerModify.Create(ADebugger: TFpDebugDebuggerBase;
const AnExpression, ANewValue: String; AStackFrame, AThreadId: Integer);
begin
inherited Create(ADebugger, twpModify);
FExpression := AnExpression;
FNewVal := ANewValue;
FStackFrame := AStackFrame;
FThreadId := AThreadId;
end;
function TFpThreadWorkerModify.DebugText: String;
begin
Result := inherited DebugText;
end;
{ TFpThreadWorkerEvaluate }
function TFpThreadWorkerEvaluate.DoWatchFunctionCall(

View File

@ -7,7 +7,7 @@ interface
uses
Classes, SysUtils, fpcunit, testregistry, TestBase, TestDbgControl,
TestDbgTestSuites, TestOutputLogger, TTestWatchUtilities, TestCommonSources,
TestDbgConfig, DbgIntfDebuggerBase, DbgIntfBaseTypes;
TestDbgConfig, DbgIntfDebuggerBase, DbgIntfBaseTypes, Forms;
type
@ -15,6 +15,9 @@ type
TTestWatches = class(TDBGTestCase)
private
FEvalDone: Boolean;
procedure DoEvalDone(Sender: TObject; ASuccess: Boolean;
ResultText: String; ResultDBGType: TDBGType);
procedure RunToPause(var ABrk: TDBGBreakPoint);
published
procedure TestWatchesScope;
@ -23,6 +26,7 @@ type
procedure TestWatchesAddressOf;
procedure TestWatchesTypeCast;
procedure TestWatchesExpression;
procedure TestWatchesModify;
procedure TestWatchesErrors;
end;
@ -30,7 +34,7 @@ implementation
var
ControlTestWatch, ControlTestWatchScope, ControlTestWatchValue, ControlTestWatchFunct,
ControlTestWatchAddressOf, ControlTestWatchTypeCast,
ControlTestWatchAddressOf, ControlTestWatchTypeCast, ControlTestModify,
ControlTestExpression, ControlTestErrors: Pointer;
procedure TTestWatches.RunToPause(var ABrk: TDBGBreakPoint);
@ -40,6 +44,14 @@ begin
ABrk.Enabled := False;
end;
procedure TTestWatches.DoEvalDone(Sender: TObject; ASuccess: Boolean;
ResultText: String; ResultDBGType: TDBGType);
begin
if ResultDBGType <> nil then
ResultDBGType.Free;
FEvalDone := True;
end;
procedure TTestWatches.TestWatchesScope;
procedure AddWatchesForClassMethods(t: TWatchExpectationList; AName: String; AStackOffs: Integer);
@ -606,7 +618,7 @@ procedure TTestWatches.TestWatchesValue;
t.Add(AName, p+'Byte'+e, weCardinal(1+n, 'Byte', 1));
t.Add(AName, p+'Word'+e, weCardinal(100+n, 'Word', 2));
t.Add(AName, p+'Longword'+e, weCardinal(1000+n, 'Longword', 4));
t.Add(AName, p+'QWord'+e, weCardinal(10000+n, 'QWord', 5));
t.Add(AName, p+'QWord'+e, weCardinal(10000+n, 'QWord', 8));
t.Add(AName, p+'Shortint'+e, weInteger (50+n, 'Shortint', 1));
t.Add(AName, p+'Smallint'+e, weInteger (500+n, 'Smallint', 2));
t.Add(AName, p+'Longint'+e, weInteger (5000+n, 'Longint', 4));
@ -628,8 +640,23 @@ procedure TTestWatches.TestWatchesValue;
t.Add(AName, p+'Longint_3'+e, weInteger(-20123456+n, 'Longint', 4));
t.Add(AName, p+'Int64_3'+e, weInteger(-9123372036854775801+n, 'Int64', 8));
t.Add(AName, p+'Bool1'+e, weBool(False ));
t.Add(AName, p+'Bool2'+e, weBool(True ));
t.Add(AName, p+'Bool1'+e, weBool(False ));
t.Add(AName, p+'Bool2'+e, weBool(True ));
t.Add(AName, p+'WBool1'+e, weBool(False, 'Boolean16'));
t.Add(AName, p+'WBool2'+e, weBool(True , 'Boolean16'));
t.Add(AName, p+'LBool1'+e, weBool(False, 'Boolean32'));
t.Add(AName, p+'LBool2'+e, weBool(True , 'Boolean32'));
t.Add(AName, p+'QBool1'+e, weBool(False, 'Boolean64'));
t.Add(AName, p+'QBool2'+e, weBool(True , 'Boolean64'));
t.Add(AName, p+'ByteBool1'+e, weSizedBool(False, 'ByteBool'));
t.Add(AName, p+'ByteBool2'+e, weSizedBool(True , 'ByteBool'));
t.Add(AName, p+'WordBool1'+e, weSizedBool(False, 'WordBool'));
t.Add(AName, p+'WordBool2'+e, weSizedBool(True , 'WordBool'));
t.Add(AName, p+'LongBool1'+e, weSizedBool(False, 'LongBool'));
t.Add(AName, p+'LongBool2'+e, weSizedBool(True , 'LongBool'));
t.Add(AName, p+'QWordBool1'+e, weSizedBool(False, 'QWordBool'));
t.Add(AName, p+'QWordBool2'+e, weSizedBool(True , 'QWordBool'));
t.Add(AName, p+'Real'+e, weFloat(50.25+n, 'Real' ));
t.Add(AName, p+'Single'+e, weSingle(100.125+n, 'Single' ));
@ -947,10 +974,19 @@ StartIdxClassConst := t.Count;
// t.Add(AName, 'EnVal2', weMatch('xxx', skEnumValue));
t.Add(AName, p+'Enum16'+e, weEnum('ExVal23', 'TEnum16'));
t.Add(AName, p+'Enum16A'+e, weEnum('ExValX5', 'TEnum16'));
t.Add(AName, p+'Set'+e, weSet(['EnVal2', 'EnVal4'], 'TSet')).Skip([stDwarf]);
t.Add(AName, p+'Set2'+e, weSet(['EnVal1', 'EnVal4'], '{set}')).Skip([stDwarf])
.SkipIf(ALoc = tlParam).SkipIf(ALoc = tlPointer);
t.Add(AName, p+'Set4'+e, weSet(['E4Val02', 'E4Val0A'], 'TSet4')).Skip([stDwarf]);
t.Add(AName, p+'Set5'+e, weSet(['E5Val02', 'E5Val12'], 'TSet5')).Skip([stDwarf]);
t.Add(AName, p+'Set6'+e, weSet(['E6Val02', 'E6Val1A'], 'TSet6')).Skip([stDwarf]);
t.Add(AName, p+'Set7'+e, weSet(['E7Val02', 'E7Val3A'], 'TSet7')).Skip([stDwarf]);
t.Add(AName, p+'Set8'+e, weSet(['E8Val02', 'E8Val5B'], 'TSet8')).Skip([stDwarf]);
t.Add(AName, p+'SmallSet'+e, weSet(['22', '24', '25'], 'TSmallRangeSet')).Skip([stDwarf])
.SkipIf(ALoc = tlParam).SkipIf(ALoc = tlPointer);
t.Add(AName, p+'SmallSet2'+e, weSet(['21', '24', '25'], '{set}')).Skip([stDwarf])
@ -2110,7 +2146,7 @@ procedure TTestWatches.TestWatchesExpression;
);
var
p, e, p2, e2: String;
n, StartIdx, i, n2: Integer;
n, i, n2: Integer;
begin
p := APrefix;
e := APostFix;
@ -2202,7 +2238,7 @@ var
ExeName: String;
t: TWatchExpectationList;
Src: TCommonSource;
BrkPrg, BrkFoo, BrkFooVar, BrkFooConstRef: TDBGBreakPoint;
BrkPrg: TDBGBreakPoint;
begin
if SkipTest then exit;
if not TestControlCanTest(ControlTestExpression) then exit;
@ -2414,12 +2450,427 @@ begin
end;
end;
procedure TTestWatches.TestWatchesModify;
procedure WaitForModify;
var
i: Integer;
begin
// Modify does not have a callback (yet). So wait for an eval
FEvalDone := False;
Debugger.LazDebugger.Evaluate('p', @DoEvalDone);
i := 0;
while (not FEvalDone) and (i < 5*400) do begin // timeout after 5 sec
Application.Idle(False);
Debugger.WaitForFinishRun(25);
inc(i);
end;
end;
var
ExeName: String;
t: TWatchExpectationList;
Src: TCommonSource;
BrkPrg: TDBGBreakPoint;
begin
if SkipTest then exit;
if not TestControlCanTest(ControlTestModify) then exit;
t := nil;
Src := GetCommonSourceFor('WatchesValuePrg.Pas');
TestCompile(Src, ExeName);
AssertTrue('Start debugger', Debugger.StartDebugger(AppDir, ExeName));
try
t := TWatchExpectationList.Create(Self);
t.AcceptSkSimple := [skInteger, skCardinal, skBoolean, skChar, skFloat,
skString, skAnsiString, skCurrency, skVariant, skWideString,
skInterface];
t.AddTypeNameAlias('integer', 'integer|longint');
t.AddTypeNameAlias('cardinal', 'cardinal|longword');
t.AddTypeNameAlias('BYTEBOOL', 'boolean|BYTEBOOL');
t.AddTypeNameAlias('TEnumSub', 'TEnum|TEnumSub');
BrkPrg := Debugger.SetBreakPoint(Src, 'Prg');
AssertDebuggerNotInErrorState;
(* ************ Nested Functions ************* *)
RunToPause(BrkPrg);
t.Clear;
//t.Add(AName, p+'QWord'+e, weCardinal(10000+n, 'QWord', 8));
//t.Add(AName, p+'Shortint'+e, weInteger (50+n, 'Shortint', 1));
t.Add('(before)', 'ModifyTestByte.pre', weCardinal(qword($9696969696969696), 'QWord', 8));
t.Add('(before)', 'ModifyTestByte.post', weCardinal($69, 'Byte', 1));
t.Add('(before)', 'ModifyTestByte.val', weCardinal($01, 'Byte', 1));
t.EvaluateWatches;
t.CheckResults;
t.Clear;
Debugger.LazDebugger.Modify('ModifyTestByte.val', '131');
WaitForModify;
t.Add('(after)', 'ModifyTestByte.pre', weCardinal(qword($9696969696969696), 'QWord', 8));
t.Add('(after)', 'ModifyTestByte.post', weCardinal($69, 'Byte', 1));
t.Add('(after)', 'ModifyTestByte.val', weCardinal(131, 'Byte', 1));
t.EvaluateWatches;
t.CheckResults;
t.Clear;
t.Add('(before)', 'ModifyTestWord.pre', weCardinal(qword($9696969696969696), 'QWord', 8));
t.Add('(before)', 'ModifyTestWord.post', weCardinal($69, 'Byte', 1));
t.Add('(before)', 'ModifyTestWord.val', weCardinal($0101, 'Word', 2));
t.EvaluateWatches;
t.CheckResults;
t.Clear;
Debugger.LazDebugger.Modify('ModifyTestWord.val', '35131');
WaitForModify;
t.Add('(after)', 'ModifyTestWord.pre', weCardinal(qword($9696969696969696), 'QWord', 8));
t.Add('(after)', 'ModifyTestWord.post', weCardinal($69, 'Byte', 1));
t.Add('(after)', 'ModifyTestWord.val', weCardinal(35131, 'Word', 2));
t.EvaluateWatches;
t.CheckResults;
t.Clear;
t.Add('(before)', 'ModifyTestCardinal.pre', weCardinal(qword($9696969696969696), 'QWord', 8));
t.Add('(before)', 'ModifyTestCardinal.post', weCardinal($69, 'Byte', 1));
t.Add('(before)', 'ModifyTestCardinal.val', weCardinal($81020102, 'Cardinal', 4));
t.EvaluateWatches;
t.CheckResults;
t.Clear;
Debugger.LazDebugger.Modify('ModifyTestCardinal.val', '$9AA93333');
WaitForModify;
t.Add('(after)', 'ModifyTestCardinal.pre', weCardinal(qword($9696969696969696), 'QWord', 8));
t.Add('(after)', 'ModifyTestCardinal.post', weCardinal($69, 'Byte', 1));
t.Add('(after)', 'ModifyTestCardinal.val', weCardinal($9AA93333, 'Cardinal', 4));
t.EvaluateWatches;
t.CheckResults;
t.Clear;
t.Add('(before)', 'ModifyTestQWord.pre', weCardinal(qword($9696969696969696), 'QWord', 8));
t.Add('(before)', 'ModifyTestQWord.post', weCardinal($69, 'Byte', 1));
t.Add('(before)', 'ModifyTestQWord.val', weCardinal(qword($8102010201020102), 'QWord', 8));
t.EvaluateWatches;
t.CheckResults;
t.Clear;
Debugger.LazDebugger.Modify('ModifyTestQWord.val', '$9AA9333344224422');
WaitForModify;
t.Add('(after)', 'ModifyTestQWord.pre', weCardinal(qword($9696969696969696), 'QWord', 8));
t.Add('(after)', 'ModifyTestQWord.post', weCardinal($69, 'Byte', 1));
t.Add('(after)', 'ModifyTestQWord.val', weCardinal(qword($9AA9333344224422), 'QWord', 8));
t.EvaluateWatches;
t.CheckResults;
t.Clear;
t.Add('(before)', 'ModifyTestInt.pre', weCardinal(QWord($9696969696969696), 'QWord', 8));
t.Add('(before)', 'ModifyTestInt.post', weCardinal($69, 'Byte', 1));
t.Add('(before)', 'ModifyTestInt.val', weInteger(-$01030103, 'Integer', 4));
t.EvaluateWatches;
t.CheckResults;
t.Clear;
Debugger.LazDebugger.Modify('ModifyTestInt.val', '$44225522');
WaitForModify;
t.Add('(after)', 'ModifyTestInt.pre', weCardinal(QWord($9696969696969696), 'QWord', 8));
t.Add('(after)', 'ModifyTestInt.post', weCardinal($69, 'Byte', 1));
t.Add('(after)', 'ModifyTestInt.val', weInteger($44225522, 'Integer', 4));
t.EvaluateWatches;
t.CheckResults;
t.Clear;
t.Add('(before)', 'ModifyTestInt64.pre', weCardinal(QWord($9696969696969696), 'QWord', 8));
t.Add('(before)', 'ModifyTestInt64.post', weCardinal($69, 'Byte', 1));
t.Add('(before)', 'ModifyTestInt64.val', weInteger(-$0103010301030103, 'Int64', 8));
t.EvaluateWatches;
t.CheckResults;
t.Clear;
Debugger.LazDebugger.Modify('ModifyTestInt64.val', '$4422552201020102');
WaitForModify;
t.Add('(after)', 'ModifyTestInt64.pre', weCardinal(QWord($9696969696969696), 'QWord', 8));
t.Add('(after)', 'ModifyTestInt64.post', weCardinal($69, 'Byte', 1));
t.Add('(after)', 'ModifyTestInt64.val', weInteger($4422552201020102, 'Int64', 8));
t.EvaluateWatches;
t.CheckResults;
t.Clear;
t.Add('(before)', 'ModifyTestPointer.pre', weCardinal(QWord($9696969696969696), 'QWord', 8));
t.Add('(before)', 'ModifyTestPointer.post', weCardinal($69, 'Byte', 1));
t.Add('(before)', 'ModifyTestPointer.val', wePointerAddr(Pointer(30), 'Pointer'));
t.EvaluateWatches;
t.CheckResults;
t.Clear;
Debugger.LazDebugger.Modify('ModifyTestPointer.val', '50');
WaitForModify;
t.Add('(after)', 'ModifyTestPointer.pre', weCardinal(QWord($9696969696969696), 'QWord', 8));
t.Add('(after)', 'ModifyTestPointer.post', weCardinal($69, 'Byte', 1));
t.Add('(after)', 'ModifyTestPointer.val', wePointerAddr(Pointer(50), 'Pointer'));
t.EvaluateWatches;
t.CheckResults;
t.Clear;
t.Add('(before)', 'ModifyTestPWord.pre', weCardinal(QWord($9696969696969696), 'QWord', 8));
t.Add('(before)', 'ModifyTestPWord.post', weCardinal($69, 'Byte', 1));
t.Add('(before)', 'ModifyTestPWord.val', wePointerAddr(Pointer(40), 'PWord'));
t.EvaluateWatches;
t.CheckResults;
t.Clear;
Debugger.LazDebugger.Modify('ModifyTestPWord.val', '70');
WaitForModify;
t.Add('(after)', 'ModifyTestPWord.pre', weCardinal(QWord($9696969696969696), 'QWord', 8));
t.Add('(after)', 'ModifyTestPWord.post', weCardinal($69, 'Byte', 1));
t.Add('(after)', 'ModifyTestPWord.val', wePointerAddr(Pointer(70), 'PWord'));
t.EvaluateWatches;
t.CheckResults;
t.Clear;
t.Add('(before)', 'ModifyTestBool.pre', weCardinal(QWord($9696969696969696), 'QWord', 8));
t.Add('(before)', 'ModifyTestBool.post', weCardinal($69, 'Byte', 1));
t.Add('(before)', 'ModifyTestBool.val', weBool(True));
t.EvaluateWatches;
t.CheckResults;
t.Clear;
Debugger.LazDebugger.Modify('ModifyTestBool.val', 'False');
WaitForModify;
t.Add('(after)', 'ModifyTestBool.pre', weCardinal(QWord($9696969696969696), 'QWord', 8));
t.Add('(after)', 'ModifyTestBool.post', weCardinal($69, 'Byte', 1));
t.Add('(after)', 'ModifyTestBool.val', weBool(False));
t.EvaluateWatches;
t.CheckResults;
t.Clear;
t.Add('(before)', 'ModifyTestByteBool.pre', weCardinal(QWord($9696969696969696), 'QWord', 8));
t.Add('(before)', 'ModifyTestByteBool.post', weCardinal($69, 'Byte', 1));
t.Add('(before)', 'ModifyTestByteBool.val', weSizedBool(False, 'BYTEBOOL'));
t.EvaluateWatches;
t.CheckResults;
t.Clear;
Debugger.LazDebugger.Modify('ModifyTestByteBool.val', 'True');
WaitForModify;
t.Add('(after)', 'ModifyTestByteBool.pre', weCardinal(QWord($9696969696969696), 'QWord', 8));
t.Add('(after)', 'ModifyTestByteBool.post', weCardinal($69, 'Byte', 1));
t.Add('(after)', 'ModifyTestByteBool.val', weSizedBool(True, 'BYTEBOOL'));
t.EvaluateWatches;
t.CheckResults;
t.Clear;
t.Add('(before)', 'ModifyTestChar.pre', weCardinal(QWord($9696969696969696), 'QWord', 8));
t.Add('(before)', 'ModifyTestChar.post', weCardinal($69, 'Byte', 1));
t.Add('(before)', 'ModifyTestChar.val', weChar('B'));
t.EvaluateWatches;
t.CheckResults;
t.Clear;
Debugger.LazDebugger.Modify('ModifyTestChar.val', 'X');
WaitForModify;
t.Add('(after)', 'ModifyTestChar.pre', weCardinal(QWord($9696969696969696), 'QWord', 8));
t.Add('(after)', 'ModifyTestChar.post', weCardinal($69, 'Byte', 1));
t.Add('(after)', 'ModifyTestChar.val', weChar('X'));
t.EvaluateWatches;
t.CheckResults;
t.Clear;
t.Add('(before)', 'ModifyTestWideChar.pre', weCardinal(QWord($9696969696969696), 'QWord', 8));
t.Add('(before)', 'ModifyTestWideChar.post', weCardinal($69, 'Byte', 1));
t.Add('(before)', 'ModifyTestWideChar.val', weWideChar('B'));
t.EvaluateWatches;
t.CheckResults;
t.Clear;
Debugger.LazDebugger.Modify('ModifyTestWideChar.val', 'Y');
WaitForModify;
t.Add('(after)', 'ModifyTestWideChar.pre', weCardinal(QWord($9696969696969696), 'QWord', 8));
t.Add('(after)', 'ModifyTestWideChar.post', weCardinal($69, 'Byte', 1));
t.Add('(after)', 'ModifyTestWideChar.val', weWideChar('Y'));
t.EvaluateWatches;
t.CheckResults;
t.Clear;
t.Add('(before)', 'ModifyTestEnum.pre', weCardinal(QWord($9696969696969696), 'QWord', 8));
t.Add('(before)', 'ModifyTestEnum.post', weCardinal($69, 'Byte', 1));
t.Add('(before)', 'ModifyTestEnum.val', weEnum('EnVal2'));
t.EvaluateWatches;
t.CheckResults;
t.Clear;
Debugger.LazDebugger.Modify('ModifyTestEnum.val', 'EnVal4');
WaitForModify;
t.Add('(after)', 'ModifyTestEnum.pre', weCardinal(QWord($9696969696969696), 'QWord', 8));
t.Add('(after)', 'ModifyTestEnum.post', weCardinal($69, 'Byte', 1));
t.Add('(after)', 'ModifyTestEnum.val', weEnum('EnVal4'));
t.EvaluateWatches;
t.CheckResults;
t.Clear;
t.Add('(before)', 'ModifyTestEnum16.pre', weCardinal(QWord($9696969696969696), 'QWord', 8));
t.Add('(before)', 'ModifyTestEnum16.post', weCardinal($69, 'Byte', 1));
t.Add('(before)', 'ModifyTestEnum16.val', weEnum('ExValX2'));
t.EvaluateWatches;
t.CheckResults;
t.Clear;
Debugger.LazDebugger.Modify('ModifyTestEnum16.val', 'ExValX7');
WaitForModify;
t.Add('(after)', 'ModifyTestEnum16.pre', weCardinal(QWord($9696969696969696), 'QWord', 8));
t.Add('(after)', 'ModifyTestEnum16.post', weCardinal($69, 'Byte', 1));
t.Add('(after)', 'ModifyTestEnum16.val', weEnum('ExValX7'));
t.EvaluateWatches;
t.CheckResults;
t.Clear;
if Compiler.SymbolType <> stDwarf then begin
t.Add('(before)', 'ModifyTestSet.pre', weCardinal(QWord($9696969696969696), 'QWord', 8));
t.Add('(before)', 'ModifyTestSet.post', weCardinal($69, 'Byte', 1));
t.Add('(before)', 'ModifyTestSet.val', weSet(['EnVal2', 'EnVal4']));
t.EvaluateWatches;
t.CheckResults;
t.Clear;
Debugger.LazDebugger.Modify('ModifyTestSet.val', ' [ EnVal1, EnVal3] ');
WaitForModify;
t.Add('(after)', 'ModifyTestSet.pre', weCardinal(QWord($9696969696969696), 'QWord', 8));
t.Add('(after)', 'ModifyTestSet.post', weCardinal($69, 'Byte', 1));
t.Add('(after)', 'ModifyTestSet.val', weSet(['EnVal1', 'EnVal3']));
t.EvaluateWatches;
t.CheckResults;
t.Clear;
Debugger.LazDebugger.Modify('ModifyTestSet.val', ' [ EnVal1] ');
WaitForModify;
t.Add('(after)', 'ModifyTestSet.pre', weCardinal(QWord($9696969696969696), 'QWord', 8));
t.Add('(after)', 'ModifyTestSet.post', weCardinal($69, 'Byte', 1));
t.Add('(after)', 'ModifyTestSet.val', weSet(['EnVal1']));
t.EvaluateWatches;
t.CheckResults;
t.Clear;
Debugger.LazDebugger.Modify('ModifyTestSet.val', ' [ EnVal4] ');
WaitForModify;
t.Add('(after)', 'ModifyTestSet.pre', weCardinal(QWord($9696969696969696), 'QWord', 8));
t.Add('(after)', 'ModifyTestSet.post', weCardinal($69, 'Byte', 1));
t.Add('(after)', 'ModifyTestSet.val', weSet(['EnVal4']));
t.EvaluateWatches;
t.CheckResults;
t.Clear;
t.Add('(before)', 'ModifyTestSet4.pre', weCardinal(QWord($9696969696969696), 'QWord', 8));
t.Add('(before)', 'ModifyTestSet4.post', weCardinal($69, 'Byte', 1));
t.Add('(before)', 'ModifyTestSet4.val', weSet(['E4Val02', 'E4Val09']));
t.EvaluateWatches;
t.CheckResults;
t.Clear;
Debugger.LazDebugger.Modify('ModifyTestSet4.val', '[E4Val03,E4Val0A ]');
WaitForModify;
t.Add('(after)', 'ModifyTestSet4.pre', weCardinal(QWord($9696969696969696), 'QWord', 8));
t.Add('(after)', 'ModifyTestSet4.post', weCardinal($69, 'Byte', 1));
t.Add('(after)', 'ModifyTestSet4.val', weSet(['E4Val03', 'E4Val0A']));
t.EvaluateWatches;
t.CheckResults;
t.Clear;
Debugger.LazDebugger.Modify('ModifyTestSet4.val', ' [E4Val0B ]');
WaitForModify;
t.Add('(after)', 'ModifyTestSet4.pre', weCardinal(QWord($9696969696969696), 'QWord', 8));
t.Add('(after)', 'ModifyTestSet4.post', weCardinal($69, 'Byte', 1));
t.Add('(after)', 'ModifyTestSet4.val', weSet(['E4Val0B']));
t.EvaluateWatches;
t.CheckResults;
t.Clear;
t.Add('(before)', 'ModifyTestSet6.pre', weCardinal(QWord($9696969696969696), 'QWord', 8));
t.Add('(before)', 'ModifyTestSet6.post', weCardinal($69, 'Byte', 1));
t.Add('(before)', 'ModifyTestSet6.val', weSet(['E6Val02', 'E6Val1A']));
t.EvaluateWatches;
t.CheckResults;
t.Clear;
Debugger.LazDebugger.Modify('ModifyTestSet6.val', '[E6Val03,E6Val1B ]');
WaitForModify;
t.Add('(after)', 'ModifyTestSet6.pre', weCardinal(QWord($9696969696969696), 'QWord', 8));
t.Add('(after)', 'ModifyTestSet6.post', weCardinal($69, 'Byte', 1));
t.Add('(after)', 'ModifyTestSet6.val', weSet(['E6Val03', 'E6Val1B']));
t.EvaluateWatches;
t.CheckResults;
t.Clear;
t.Add('(before)', 'ModifyTestSet7.pre', weCardinal(QWord($9696969696969696), 'QWord', 8));
t.Add('(before)', 'ModifyTestSet7.post', weCardinal($69, 'Byte', 1));
t.Add('(before)', 'ModifyTestSet7.val', weSet(['E7Val02', 'E7Val3A']));
t.EvaluateWatches;
t.CheckResults;
t.Clear;
Debugger.LazDebugger.Modify('ModifyTestSet7.val', '[E7Val03,E7Val12,E7Val3B ]');
WaitForModify;
t.Add('(after)', 'ModifyTestSet7.pre', weCardinal(QWord($9696969696969696), 'QWord', 8));
t.Add('(after)', 'ModifyTestSet7.post', weCardinal($69, 'Byte', 1));
t.Add('(after)', 'ModifyTestSet7.val', weSet(['E7Val03', 'E7Val12', 'E7Val3B']));
t.EvaluateWatches;
t.CheckResults;
t.Clear;
t.Add('(before)', 'ModifyTestSet8.pre', weCardinal(QWord($9696969696969696), 'QWord', 8));
t.Add('(before)', 'ModifyTestSet8.post', weCardinal($69, 'Byte', 1));
t.Add('(before)', 'ModifyTestSet8.val', weSet(['E8Val02', 'E8Val59']));
t.EvaluateWatches;
t.CheckResults;
t.Clear;
Debugger.LazDebugger.Modify('ModifyTestSet8.val', '[E8Val03,E8Val12,E8Val58 ]');
WaitForModify;
t.Add('(after)', 'ModifyTestSet8.pre', weCardinal(QWord($9696969696969696), 'QWord', 8));
t.Add('(after)', 'ModifyTestSet8.post', weCardinal($69, 'Byte', 1));
t.Add('(after)', 'ModifyTestSet8.val', weSet(['E8Val03', 'E8Val12', 'E8Val58']));
t.EvaluateWatches;
t.CheckResults;
t.Clear;
t.Add('(before)', 'ModifyTestSRangeSet.pre', weCardinal(QWord($9696969696969696), 'QWord', 8));
t.Add('(before)', 'ModifyTestSRangeSet.post', weCardinal($69, 'Byte', 1));
t.Add('(before)', 'ModifyTestSRangeSet.val', weSet(['20','23','28']));
t.EvaluateWatches;
t.CheckResults;
t.Clear;
Debugger.LazDebugger.Modify('ModifyTestSRangeSet.val', '[21,$18,27 ]');
WaitForModify;
t.Add('(after)', 'ModifyTestSRangeSet.pre', weCardinal(QWord($9696969696969696), 'QWord', 8));
t.Add('(after)', 'ModifyTestSRangeSet.post', weCardinal($69, 'Byte', 1));
t.Add('(after)', 'ModifyTestSRangeSet.val', weSet(['21', '24', '27']));
t.EvaluateWatches;
t.CheckResults;
t.Clear;
Debugger.LazDebugger.Modify('ModifyTestSRangeSet.val', '[30 ]');
WaitForModify;
t.Add('(after)', 'ModifyTestSRangeSet.pre', weCardinal(QWord($9696969696969696), 'QWord', 8));
t.Add('(after)', 'ModifyTestSRangeSet.post', weCardinal($69, 'Byte', 1));
t.Add('(after)', 'ModifyTestSRangeSet.val', weSet(['30']));
t.EvaluateWatches;
t.CheckResults;
t.Clear;
end;
finally
t.Free;
Debugger.ClearDebuggerMonitors;
Debugger.FreeDebugger;
AssertTestErrors;
end;
end;
procedure TTestWatches.TestWatchesErrors;
var
ExeName: String;
t: TWatchExpectationList;
Src: TCommonSource;
BrkPrg, BrkFoo, BrkFooVar, BrkFooConstRef: TDBGBreakPoint;
BrkPrg: TDBGBreakPoint;
begin
if SkipTest then exit;
if not TestControlCanTest(ControlTestErrors) then exit;
@ -2479,6 +2930,7 @@ initialization
ControlTestWatchFunct := TestControlRegisterTest('Function', ControlTestWatch);
ControlTestWatchAddressOf := TestControlRegisterTest('AddressOf', ControlTestWatch);
ControlTestWatchTypeCast := TestControlRegisterTest('TypeCast', ControlTestWatch);
ControlTestModify := TestControlRegisterTest('Modify', ControlTestWatch);
ControlTestExpression := TestControlRegisterTest('Expression', ControlTestWatch);
ControlTestErrors := TestControlRegisterTest('Errors', ControlTestWatch);

View File

@ -175,12 +175,63 @@ type
TEnum = (EnVal1, EnVal2, EnVal3, EnVal4);
// TEnum16 more than 256 values => wordsized
TEnum16 = (
ExVal00, ExVal01, ExVal02, ExVal03, ExVal04, ExVal05, ExVal06, ExVal07, ExVal08, ExVal09, ExVal0A, ExVal0B, ExVal0C, ExVal0D, ExVal0E, ExVal0F,
ExVal10, ExVal11, ExVal12, ExVal13, ExVal14, ExVal15, ExVal16, ExVal17, ExVal18, ExVal19, ExVal1A, ExVal1B, ExVal1C, ExVal1D, ExVal1E, ExVal1F,
ExVal20, ExVal21, ExVal22, ExVal23, ExVal24, ExVal25, ExVal26, ExVal27, ExVal28, ExVal29, ExVal2A, ExVal2B, ExVal2C, ExVal2D, ExVal2E, ExVal2F,
ExVal30, ExVal31, ExVal32, ExVal33, ExVal34, ExVal35, ExVal36, ExVal37, ExVal38, ExVal39, ExVal3A, ExVal3B, ExVal3C, ExVal3D, ExVal3E, ExVal3F,
ExVal40, ExVal41, ExVal42, ExVal43, ExVal44, ExVal45, ExVal46, ExVal47, ExVal48, ExVal49, ExVal4A, ExVal4B, ExVal4C, ExVal4D, ExVal4E, ExVal4F,
ExVal50, ExVal51, ExVal52, ExVal53, ExVal54, ExVal55, ExVal56, ExVal57, ExVal58, ExVal59, ExVal5A, ExVal5B, ExVal5C, ExVal5D, ExVal5E, ExVal5F,
ExVal60, ExVal61, ExVal62, ExVal63, ExVal64, ExVal65, ExVal66, ExVal67, ExVal68, ExVal69, ExVal6A, ExVal6B, ExVal6C, ExVal6D, ExVal6E, ExVal6F,
ExVal70, ExVal71, ExVal72, ExVal73, ExVal74, ExVal75, ExVal76, ExVal77, ExVal78, ExVal79, ExVal7A, ExVal7B, ExVal7C, ExVal7D, ExVal7E, ExVal7F,
ExVal80, ExVal81, ExVal82, ExVal83, ExVal84, ExVal85, ExVal86, ExVal87, ExVal88, ExVal89, ExVal8A, ExVal8B, ExVal8C, ExVal8D, ExVal8E, ExVal8F,
ExVal90, ExVal91, ExVal92, ExVal93, ExVal94, ExVal95, ExVal96, ExVal97, ExVal98, ExVal99, ExVal9A, ExVal9B, ExVal9C, ExVal9D, ExVal9E, ExVal9F,
ExValA0, ExValA1, ExValA2, ExValA3, ExValA4, ExValA5, ExValA6, ExValA7, ExValA8, ExValA9, ExValAA, ExValAB, ExValAC, ExValAD, ExValAE, ExValAF,
ExValB0, ExValB1, ExValB2, ExValB3, ExValB4, ExValB5, ExValB6, ExValB7, ExValB8, ExValB9, ExValBA, ExValBB, ExValBC, ExValBD, ExValBE, ExValBF,
ExValC0, ExValC1, ExValC2, ExValC3, ExValC4, ExValC5, ExValC6, ExValC7, ExValC8, ExValC9, ExValCA, ExValCB, ExValCC, ExValCD, ExValCE, ExValCF,
ExValD0, ExValD1, ExValD2, ExValD3, ExValD4, ExValD5, ExValD6, ExValD7, ExValD8, ExValD9, ExValDA, ExValDB, ExValDC, ExValDD, ExValDE, ExValDF,
ExValE0, ExValE1, ExValE2, ExValE3, ExValE4, ExValE5, ExValE6, ExValE7, ExValE8, ExValE9, ExValEA, ExValEB, ExValEC, ExValED, ExValEE, ExValEF,
ExValF0, ExValF1, ExValF2, ExValF3, ExValF4, ExValF5, ExValF6, ExValF7, ExValF8, ExValF9, ExValFA, ExValFB, ExValFC, ExValFD, ExValFE, ExValFF,
ExValX0, ExValX1, ExValX2, ExValX3, ExValX4, ExValX5, ExValX6, ExValX7, ExValX8, ExValX9, ExValXA, ExValXB, ExValXC, ExValXD, ExValXE, ExValXF
);
TEnumSub = EnVal1..EnVal2;
TEnum2 = (EnVal21= 3, EnVal22=4, EnVal23=7, EnVal24=10, EnVal25=30);
TEnum3 = (EnVal31, EnVal32);
TEnum4 = ( // 12 values for 16 bit set (leave some unused)
E4Val00, E4Val01, E4Val02, E4Val03, E4Val04, E4Val05, E4Val06, E4Val07, E4Val08, E4Val09, E4Val0A, E4Val0B
);
TEnum5 = ( // 20 values for 24 bit set (leave some unused)
E5Val00, E5Val01, E5Val02, E5Val03, E5Val04, E5Val05, E5Val06, E5Val07, E5Val08, E5Val09, E5Val0A, E5Val0B, E5Val0C, E5Val0D, E5Val0E, E5Val0F,
E5Val10, E5Val11, E5Val12, E5Val13
);
TEnum6 = ( // 28 values for 32 bit set (leave some unused)
E6Val00, E6Val01, E6Val02, E6Val03, E6Val04, E6Val05, E6Val06, E6Val07, E6Val08, E6Val09, E6Val0A, E6Val0B, E6Val0C, E6Val0D, E6Val0E, E6Val0F,
E6Val10, E6Val11, E6Val12, E6Val13, E6Val14, E6Val15, E6Val16, E6Val17, E6Val18, E6Val19, E6Val1A, E6Val1B
);
TEnum7 = ( // 60 values for 8 byte set (leave some unused)
E7Val00, E7Val01, E7Val02, E7Val03, E7Val04, E7Val05, E7Val06, E7Val07, E7Val08, E7Val09, E7Val0A, E7Val0B, E7Val0C, E7Val0D, E7Val0E, E7Val0F,
E7Val10, E7Val11, E7Val12, E7Val13, E7Val14, E7Val15, E7Val16, E7Val17, E7Val18, E7Val19, E7Val1A, E7Val1B, E7Val1C, E7Val1D, E7Val1E, E7Val1F,
E7Val20, E7Val21, E7Val22, E7Val23, E7Val24, E7Val25, E7Val26, E7Val27, E7Val28, E7Val29, E7Val2A, E7Val2B, E7Val2C, E7Val2D, E7Val2E, E7Val2F,
E7Val30, E7Val31, E7Val32, E7Val33, E7Val34, E7Val35, E7Val36, E7Val37, E7Val38, E7Val39, E7Val3A, E7Val3B
);
TEnum8 = ( // 92 values for 10 byte set (leave some unused)
E8Val00, E8Val01, E8Val02, E8Val03, E8Val04, E8Val05, E8Val06, E8Val07, E8Val08, E8Val09, E8Val0A, E8Val0B, E8Val0C, E8Val0D, E8Val0E, E8Val0F,
E8Val10, E8Val11, E8Val12, E8Val13, E8Val14, E8Val15, E8Val16, E8Val17, E8Val18, E8Val19, E8Val1A, E8Val1B, E8Val1C, E8Val1D, E8Val1E, E8Val1F,
E8Val20, E8Val21, E8Val22, E8Val23, E8Val24, E8Val25, E8Val26, E8Val27, E8Val28, E8Val29, E8Val2A, E8Val2B, E8Val2C, E8Val2D, E8Val2E, E8Val2F,
E8Val30, E8Val31, E8Val32, E8Val33, E8Val34, E8Val35, E8Val36, E8Val37, E8Val38, E8Val39, E8Val3A, E8Val3B, E8Val3C, E8Val3D, E8Val3E, E8Val3F,
E8Val40, E8Val41, E8Val42, E8Val43, E8Val44, E8Val45, E8Val46, E8Val47, E8Val48, E8Val49, E8Val4A, E8Val4B, E8Val4C, E8Val4D, E8Val4E, E8Val4F,
E8Val50, E8Val51, E8Val52, E8Val53, E8Val54, E8Val55, E8Val56, E8Val57, E8Val58, E8Val59, E8Val5A, E8Val5B
);
TSet = set of TEnum;
TSet3 = set of TEnum3;
TSmallRangeSet = set of TSmallRange;
TSet4 = set of TEnum4; // 2 byte
TSet5 = set of TEnum5; // 3 byte
TSet6 = set of TEnum6; // 4 byte
TSet7 = set of TEnum7; // 8 byte
TSet8 = set of TEnum8; // 10 byte
TArrayEnum = array [TEnum] of word;
TArrayEnumSub = array [TEnumSub] of word;
@ -428,7 +479,6 @@ begin end;
function TMyBaseClass.SomeMeth1(SomeValue: Integer): Boolean;
begin result := SomeValue = 0; end;
procedure Foo(
(* LOCATION: param *)
TEST_PREPOCESS(WatchesValuePrgIdent.inc, pre__=arg, _OP_=:, (=;//, _O2_=:, _EQ_= , _BLOCK_=TestArg)
@ -505,6 +555,109 @@ begin
FFunctInt := result;
end;
var
ModifyTestByte: record
pre: qword; // padding, must not be changed
val: byte;
post: byte; // padding, must not be changed
end;
ModifyTestWord: record
pre: qword; // padding, must not be changed
val: word;
post: byte; // padding, must not be changed
end;
ModifyTestCardinal: record
pre: qword; // padding, must not be changed
val: Cardinal;
post: byte; // padding, must not be changed
end;
ModifyTestqword: record
pre: qword; // padding, must not be changed
val: qword;
post: byte; // padding, must not be changed
end;
ModifyTestint: record
pre: qword; // padding, must not be changed
val: integer;
post: byte; // padding, must not be changed
end;
ModifyTestInt64: record
pre: qword; // padding, must not be changed
val: int64;
post: byte; // padding, must not be changed
end;
ModifyTestPointer: record
pre: qword; // padding, must not be changed
val: Pointer;
post: byte; // padding, must not be changed
end;
ModifyTestPWord: record
pre: qword; // padding, must not be changed
val: PWord;
post: byte; // padding, must not be changed
end;
ModifyTestBool: record
pre: qword; // padding, must not be changed
val: Boolean;
post: byte; // padding, must not be changed
end;
ModifyTestByteBool: record
pre: qword; // padding, must not be changed
val: ByteBool;
post: byte; // padding, must not be changed
end;
ModifyTestChar: record
pre: qword; // padding, must not be changed
val: Char;
post: byte; // padding, must not be changed
end;
ModifyTestWideChar: record
pre: qword; // padding, must not be changed
val: WideChar;
post: byte; // padding, must not be changed
end;
ModifyTestEnum: record
pre: qword; // padding, must not be changed
val: TEnum;
post: byte; // padding, must not be changed
end;
ModifyTestEnum16: record
pre: qword; // padding, must not be changed
val: TEnum16;
post: byte; // padding, must not be changed
end;
ModifyTestSet: record
pre: qword; // padding, must not be changed
val: TSet;
post: byte; // padding, must not be changed
end;
ModifyTestSet4: record
pre: qword; // padding, must not be changed
val: TSet4;
post: byte; // padding, must not be changed
end;
ModifyTestSet6: record
pre: qword; // padding, must not be changed
val: TSet6;
post: byte; // padding, must not be changed
end;
ModifyTestSet7: record
pre: qword; // padding, must not be changed
val: TSet7;
post: byte; // padding, must not be changed
end;
ModifyTestSet8: record
pre: qword; // padding, must not be changed
val: TSet8;
post: byte; // padding, must not be changed
end;
ModifyTestSRangeSet: record
pre: qword; // padding, must not be changed
val: TSmallRangeSet;
post: byte; // padding, must not be changed
end;
begin
U8Data1 := #$2267; //#$E2#$89#$A7;
U8Data2 := #$2267'X';
@ -527,6 +680,27 @@ begin
dummy1 := nil;
{$ENDIF}
with ModifyTestByte do begin pre := qword($9696969696969696); post := $69; val := $01; end;
with ModifyTestWord do begin pre := qword($9696969696969696); post := $69; val := $0101; end;
with ModifyTestCardinal do begin pre := qword($9696969696969696); post := $69; val := $81020102; end;
with ModifyTestQword do begin pre := qword($9696969696969696); post := $69; val := qword($8102010201020102); end;
with ModifyTestInt do begin pre := qword($9696969696969696); post := $69; val := -$01030103; end;
with ModifyTestInt64 do begin pre := qword($9696969696969696); post := $69; val := -$0103010301030103; end;
with ModifyTestPointer do begin pre := qword($9696969696969696); post := $69; val := pointer(30); end;
with ModifyTestPWord do begin pre := qword($9696969696969696); post := $69; val := pointer(40); end;
with ModifyTestBool do begin pre := qword($9696969696969696); post := $69; val := True; end;
with ModifyTestByteBool do begin pre := qword($9696969696969696); post := $69; val := False; end;
with ModifyTestChar do begin pre := qword($9696969696969696); post := $69; val := 'B'; end;
with ModifyTestWideChar do begin pre := qword($9696969696969696); post := $69; val := 'B'; end;
with ModifyTestEnum do begin pre := qword($9696969696969696); post := $69; val := EnVal2; end;
with ModifyTestEnum16 do begin pre := qword($9696969696969696); post := $69; val := ExValX2; end;
with ModifyTestSet do begin pre := qword($9696969696969696); post := $69; val := [EnVal2, EnVal4]; end;
with ModifyTestSet4 do begin pre := qword($9696969696969696); post := $69; val := [E4Val02, E4Val09]; end;
with ModifyTestSet6 do begin pre := qword($9696969696969696); post := $69; val := [E6Val02, E6Val1A]; end;
with ModifyTestSet7 do begin pre := qword($9696969696969696); post := $69; val := [E7Val02, E7Val3A]; end;
with ModifyTestSet8 do begin pre := qword($9696969696969696); post := $69; val := [E8Val02, E8Val59]; end;
with ModifyTestSRangeSet do begin pre := qword($9696969696969696); post := $69; val := [20,23,28]; end;
(* use global const / value in "gv" will be overriden... *)
TEST_PREPOCESS(WatchesValuePrgIdent.inc,pre__=gv, {e}={, "//@@=} :=", _pre3_=gc, _BLOCK_=TestAssignGC)

View File

@ -30,6 +30,20 @@
pre__Bool1{e} _OP_ Boolean (False); //@@ _pre3_Bool1{e3};
pre__Bool2{e} _OP_ Boolean (True); //@@ _pre3_Bool2{e3};
pre__WBool1{e} _OP_ Boolean16 (False); //@@ _pre3_WBool1{e3};
pre__WBool2{e} _OP_ Boolean16 (True); //@@ _pre3_WBool2{e3};
pre__LBool1{e} _OP_ Boolean32 (False); //@@ _pre3_LBool1{e3};
pre__LBool2{e} _OP_ Boolean32 (True); //@@ _pre3_LBool2{e3};
pre__QBool1{e} _OP_ Boolean64 (False); //@@ _pre3_QBool1{e3};
pre__QBool2{e} _OP_ Boolean64 (True); //@@ _pre3_QBool2{e3};
pre__ByteBool1{e} _OP_ ByteBool (False); //@@ _pre3_ByteBool1{e3};
pre__ByteBool2{e} _OP_ ByteBool (True); //@@ _pre3_ByteBool2{e3};
pre__WordBool1{e} _OP_ WordBool (False); //@@ _pre3_WordBool1{e3};
pre__WordBool2{e} _OP_ WordBool (True); //@@ _pre3_WordBool2{e3};
pre__LongBool1{e} _OP_ LongBool (False); //@@ _pre3_LongBool1{e3};
pre__LongBool2{e} _OP_ LongBool (True); //@@ _pre3_LongBool2{e3};
pre__QWordBool1{e} _OP_ QWordBool (False); //@@ _pre3_QWordBool1{e3};
pre__QWordBool2{e} _OP_ QWordBool (True); //@@ _pre3_QWordBool2{e3};
pre__Real{e} _OP_ Real (50.25 + ADD); //@@ _pre3_Real{e3};
pre__Single{e} _OP_ Single (100.125 + ADD); //@@ _pre3_Single{e3};
@ -373,9 +387,17 @@
pre__Enum2{e} _OP_ TEnum2(EnVal21); //@@ _pre3_Enum2{e3};
pre__Enum3{e} _OP_ TEnum2(EnVal25); //@@ _pre3_Enum3{e3};
pre__Enum16{e} _OP_ TEnum16(ExVal23); //@@ _pre3_Enum16{e3};
pre__Enum16A{e} _OP_ TEnum16(ExValX5); //@@ _pre3_Enum16A{e3};
pre__Set{e} _OP_ TSet([EnVal2, EnVal4]); //@@ _pre3_Set{e3};
pre__SmallSet{e} _OP_ TSmallRangeSet([22, 24,25]); //@@ _pre3_SmallSet{e3};
pre__Set4{e} _OP_ TSet4([E4Val02, E4Val0A]); //@@ _pre3_Set4{e3};
pre__Set5{e} _OP_ TSet5([E5Val02, E5Val12]); //@@ _pre3_Set5{e3};
pre__Set6{e} _OP_ TSet6([E6Val02, E6Val1A]); //@@ _pre3_Set6{e3};
pre__Set7{e} _OP_ TSet7([E7Val02, E7Val3A]); //@@ _pre3_Set7{e3};
pre__Set8{e} _OP_ TSet8([E8Val02, E8Val5B]); //@@ _pre3_Set8{e3};
{$IFnDEF TestAssign}
pre__BitPackBoolArray{e} _O2_ TBitPackBoolArray _EQ_ (True, False, True, True); //@@ _pre3_BitPackBoolArray{e3}; // }}

View File

@ -13,7 +13,7 @@ uses
type
TWatchExpectationResultKind = (
rkMatch, rkInteger, rkCardinal, rkFloat, rkBool, rkEnum, rkSet,
rkMatch, rkInteger, rkCardinal, rkFloat, rkBool, rkSizedBool, rkEnum, rkSet,
rkChar, rkAnsiString, rkShortString, rkWideString, rkPointer, rkPointerAddr,
rkClass, rkObject, rkRecord, rkInterface, rkField,
rkStatArray, rkDynArray
@ -106,7 +106,7 @@ type
rkFloat: (
ExpFloatValue: Extended;
);
rkBool: (
rkBool, rkSizedBool: (
ExpBoolValue: Boolean;
);
rkPointerAddr: (
@ -301,6 +301,7 @@ function weDouble(AExpVal: Extended; ATypeName: String=#1): TWatchExpectationRes
function weFloat(AExpVal: Extended; ATypeName: String=''): TWatchExpectationResult;
function weBool(AExpVal: Boolean; ATypeName: String=#1): TWatchExpectationResult;
function weSizedBool(AExpVal: Boolean; ATypeName: String=''): TWatchExpectationResult; // Display as True(255) etc
function weEnum(AExpVal: string; ATypeName: String=#1): TWatchExpectationResult;
function weSet(const AExpVal: Array of string; ATypeName: String=#1): TWatchExpectationResult;
@ -478,6 +479,16 @@ begin
Result.ExpBoolValue := AExpVal;
end;
function weSizedBool(AExpVal: Boolean; ATypeName: String
): TWatchExpectationResult;
begin
Result := Default(TWatchExpectationResult);
Result.ExpResultKind := rkSizedBool;
Result.ExpSymKind := skBoolean;
Result.ExpTypeName := ATypeName;
Result.ExpBoolValue := AExpVal;
end;
function weEnum(AExpVal: string; ATypeName: String): TWatchExpectationResult;
begin
Result := Default(TWatchExpectationResult);
@ -1353,7 +1364,7 @@ begin
rkMatch: Result := CheckResultMatch(AContext, AnIgnoreRsn);
rkInteger: Result := CheckResultNum(AContext, False, AnIgnoreRsn);
rkCardinal: Result := CheckResultNum(AContext, True, AnIgnoreRsn);
rkBool: Result := CheckResultBool(AContext, AnIgnoreRsn);
rkBool, rkSizedBool: Result := CheckResultBool(AContext, AnIgnoreRsn);
rkFloat: Result := CheckResultFloat(AContext, AnIgnoreRsn);
rkEnum: Result := CheckResultEnum(AContext, AnIgnoreRsn);
rkSet: Result := CheckResultSet(AContext, AnIgnoreRsn);
@ -1526,14 +1537,21 @@ function TWatchExpectationList.CheckResultBool(
AContext: TWatchExpTestCurrentData; AnIgnoreRsn: String): Boolean;
var
Expect: TWatchExpectationResult;
s: String;
s, v: String;
i: SizeInt;
begin
with AContext.WatchExp do begin
Result := True;
Expect := AContext.Expectation;
WriteStr(s, Expect.ExpBoolValue);
Result := TestEquals('Data', s, AContext.WatchVal.Value, False, AContext, AnIgnoreRsn);
v := AContext.WatchVal.Value;
if AContext.Expectation.ExpResultKind = rkSizedBool then begin
i := pos('(', v);
if i > 1 then
delete(v, i, 99); // remove the int value in brackets
end;
Result := TestEquals('Data', s, v, False, AContext, AnIgnoreRsn);
end;
end;