mirror of
https://gitlab.com/freepascal.org/lazarus/lazarus.git
synced 2025-12-04 04:57:41 +01:00
LazDebuggerFp, FpDebug: Modify watches/values in target
git-svn-id: trunk@65154 -
This commit is contained in:
parent
37c8a252a1
commit
574b3a8178
@ -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;
|
||||
|
||||
@ -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;
|
||||
|
||||
|
||||
@ -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
|
||||
|
||||
@ -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}
|
||||
];
|
||||
|
||||
@ -123,6 +123,7 @@ type
|
||||
type
|
||||
|
||||
TFpThreadWorkerPriority = (
|
||||
twpModify, // this is a user actions
|
||||
twpUser,
|
||||
twpThread, twpStack, twpLocal, twpWatch,
|
||||
twpContinue
|
||||
|
||||
@ -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(
|
||||
|
||||
@ -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);
|
||||
|
||||
|
||||
@ -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)
|
||||
|
||||
|
||||
@ -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}; // }}
|
||||
|
||||
@ -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;
|
||||
|
||||
Loading…
Reference in New Issue
Block a user