Debugger, LazDebuggerIntf: Introduce SetNumValue and SetTypeName

This commit is contained in:
Martin 2022-01-30 19:50:44 +01:00
parent 442f57cf49
commit 8e3c816593
5 changed files with 224 additions and 14 deletions

View File

@ -14615,7 +14615,9 @@ var
var
S: String;
ResultList: TGDBMINameValueList;
frameidx: Integer;
frameidx, n: Integer;
NumVal: QWord;
NumFlags: TNumValueFlags;
{$IFDEF DBG_WITH_GDB_WATCHES} R: TGDBMIExecResult; {$ENDIF}
begin
SelectContext;
@ -14675,6 +14677,36 @@ begin
finally
UnSelectContext;
if FWatchValue <> nil then begin
if (FTypeInfo <> nil) and (FTypeInfo.Kind in [skSimple, skPointer, skInteger, skCardinal]) and
(FWatchValue.RepeatCount <= 0)
then begin
NumFlags := [];
n := 0;
if (FTypeInfo.Kind = skPointer) then begin
NumFlags := [nvfAddrType];
n := TargetInfo^.TargetPtrSize;
end;
FTextValue := Trim(FTextValue);
if (FTypeInfo.Kind = skInteger) or ((FTextValue <> '') and (FTextValue[1]='-')) then begin
if TryStrToInt64(FTextValue, Int64(NumVal)) then begin
FWatchValue.SetNumValue(NumVal, n, NumFlags);
FWatchValue.SetTypeName(FTypeInfo.TypeName);
FWatchValue.Validity := FValidity;
exit;
end;
end
else begin
Include(NumFlags, nvfUnsigned);
if TryStrToQWord(FTextValue, NumVal) then begin
FWatchValue.SetNumValue(NumVal, n, NumFlags);
FWatchValue.SetTypeName(FTypeInfo.TypeName);
FWatchValue.Validity := FValidity;
exit;
end;
end;
end;
FWatchValue.Value := FTextValue;
FWatchValue.TypeInfo := TypeInfo;
FWatchValue.Validity := FValidity;

View File

@ -950,7 +950,7 @@ var
APasExpr, PasExpr2: TFpPascalExpression;
PrettyPrinter: TFpPascalPrettyPrinter;
ResValue: TFpValue;
CastName, ResText2: String;
CastName, ResText2, t: String;
begin
Result := False;
AResText := '';
@ -1019,6 +1019,34 @@ begin
exit;
end;
if (FWatchValue <> nil) and (ADispFormat <> wdfMemDump) and (FWatchValue.RepeatCount <= 0) and
(ResValue <> nil) and (not IsError(ResValue.LastError))
then begin
t := '';
if ResValue.TypeInfo <> nil then
GetTypeName(t, ResValue.TypeInfo, []);
case ResValue.Kind of
skPointer: begin
if ResValue.FieldFlags * [svfString, svfWideString] = [] then begin
FWatchValue.SetNumValue(ResValue.AsCardinal, SizeToFullBytes(ResValue.DataSize), [nvfUnsigned, nvfAddrType]);
FWatchValue.SetTypeName(t);
exit;
end;
end;
skInteger: begin
FWatchValue.SetNumValue(QWord(ResValue.AsInteger), SizeToFullBytes(ResValue.DataSize), []);
FWatchValue.SetTypeName(t);
exit;
end;
skCardinal: begin
FWatchValue.SetNumValue(ResValue.AsCardinal, SizeToFullBytes(ResValue.DataSize), [nvfUnsigned]);
FWatchValue.SetTypeName(t);
exit;
end;
end;
end;
PrettyPrinter := TFpPascalPrettyPrinter.Create(FExpressionScope.SizeOfAddress);
PrettyPrinter.Context := FExpressionScope.LocationContext;

View File

@ -150,6 +150,15 @@ type
TDBGTypeBase = class(TObject)
end;
TNumValueFlag = (
nvfUnsigned,
//nvfUnknownSize, // same as size = 0
nvfAddrType // default to hex display (Pointer)
);
TNumValueFlags = set of TNumValueFlag;
{ TWatchValueIntf }
TWatchValueIntf = interface(TDbgDataRequestIntf)
@ -182,6 +191,9 @@ type
procedure AddNotification(AnEventType: TWatcheEvaluateEvent; AnEvent: TNotifyEvent);
procedure RemoveNotification(AnEventType: TWatcheEvaluateEvent; AnEvent: TNotifyEvent);
procedure SetNumValue(ANumValue: QWord; AByteSize: Integer = 0; AFlags: TNumValueFlags = []);
procedure SetTypeName(ATypeName: String);
function GetDisplayFormat: TWatchDisplayFormat;
function GetEvaluateFlags: TWatcheEvaluateFlags;
function GetExpression: String;

View File

@ -42,9 +42,9 @@ uses
{$ifdef Windows} ActiveX, {$else} laz.FakeActiveX, {$endif}
IDEWindowIntf, Menus, ComCtrls, ActnList, ExtCtrls, StdCtrls, LCLType,
IDEImagesIntf, LazarusIDEStrConsts, DebuggerStrConst, Debugger,
DebuggerTreeView, DebuggerDlg, DbgIntfBaseTypes, DbgIntfDebuggerBase,
DbgIntfMiscClasses, SynEdit, laz.VirtualTrees, LazDebuggerIntf,
BaseDebugManager, EnvironmentOpts;
DebuggerTreeView, IdeDebuggerBase, DebuggerDlg, DbgIntfBaseTypes,
DbgIntfDebuggerBase, DbgIntfMiscClasses, SynEdit, laz.VirtualTrees,
LazDebuggerIntf, BaseDebugManager, EnvironmentOpts;
type
@ -1018,12 +1018,19 @@ begin
if (WatchValue <> nil) and
( (GetSelectedSnapshot = nil) or not(WatchValue.Validity in [ddsUnknown, ddsEvaluating, ddsRequested]) )
then begin
WatchValueStr := ClearMultiline(DebugBoss.FormatValue(WatchValue.TypeInfo, WatchValue.Value));
if (WatchValue.TypeInfo <> nil) and
(WatchValue.TypeInfo.Attributes * [saArray, saDynArray] <> []) and
(WatchValue.TypeInfo.Len >= 0)
then tvWatches.NodeText[VNode, COL_WATCH_VALUE-1] := Format(drsLen, [WatchValue.TypeInfo.Len]) + WatchValueStr
else tvWatches.NodeText[VNode, COL_WATCH_VALUE-1] := WatchValueStr;
if (vtNumVal in WatchValue.ValidTypes) and
not(AWatch.DisplayFormat in [wdfMemDump, wdfChar, wdfString, wdfFloat])
then begin
tvWatches.NodeText[VNode, COL_WATCH_VALUE-1] := WatchValue.NumValue[AWatch.DisplayFormat];
end
else begin
WatchValueStr := ClearMultiline(DebugBoss.FormatValue(WatchValue.TypeInfo, WatchValue.Value));
if (WatchValue.TypeInfo <> nil) and
(WatchValue.TypeInfo.Attributes * [saArray, saDynArray] <> []) and
(WatchValue.TypeInfo.Len >= 0)
then tvWatches.NodeText[VNode, COL_WATCH_VALUE-1] := Format(drsLen, [WatchValue.TypeInfo.Len]) + WatchValueStr
else tvWatches.NodeText[VNode, COL_WATCH_VALUE-1] := WatchValueStr;
end;
end
else
tvWatches.NodeText[VNode, COL_WATCH_VALUE-1]:= '<not evaluated>';

View File

@ -6,12 +6,15 @@ interface
uses
Classes, SysUtils, DbgIntfDebuggerBase, DbgIntfMiscClasses, LazClasses,
LazLoggerBase, LazDebuggerIntf, LazDebuggerTemplate;
LazLoggerBase, StrUtils, LazDebuggerIntf, LazDebuggerTemplate;
type
TWatch = class;
TWatchValueTypeFlag = (vtTypeName, vtNumVal);
TWatchValueTypeFlags = set of TWatchValueTypeFlag;
{ TWatchValue }
TWatchValue = class(TRefCountedObject)
@ -21,6 +24,13 @@ type
FValue: String;
FValidity: TDebuggerDataState;
FValidTypes: TWatchValueTypeFlags;
FNumValue: QWord;
FNumByteSize: Integer;
FNumFlags: TNumValueFlags;
FTypeName: String;
function GetNumValue(ADispFormat: TWatchDisplayFormat): String;
protected
procedure SetWatch(AValue: TWatch); virtual;
function GetDisplayFormat: TWatchDisplayFormat;
@ -33,6 +43,9 @@ type
procedure SetValue(AValue: String);
procedure SetTypeInfo(AValue: TDBGType);
procedure SetTypeInfo(AValue: TDBGTypeBase);
procedure SetNumValue(ANumValue: QWord; AByteSize: Integer = 0; AFlags: TNumValueFlags = []);
procedure SetTypeName(ATypeName: String);
protected
FDisplayFormat: TWatchDisplayFormat;
FEvaluateFlags: TWatcheEvaluateFlags;
@ -54,11 +67,18 @@ type
property ThreadId: Integer read GetThreadId;
property StackFrame: Integer read GetStackFrame;
property Expression: String read GetExpression;
public
property ValidTypes: TWatchValueTypeFlags read FValidTypes;
public
property Watch: TWatch read FWatch write SetWatch;
property Validity: TDebuggerDataState read GetValidity write SetValidity;
property Value: String read GetValue write SetValue;
property TypeInfo: TDBGType read GetTypeInfo write SetTypeInfo;
property NumValue[ADispFormat: TWatchDisplayFormat]: String read GetNumValue;
property NumValueRaw: QWord read FNumValue;
property TypeName: String read FTypeName;
property NumFlags: TNumValueFlags read FNumFlags;
end;
{ TWatchValueList }
@ -185,6 +205,89 @@ begin
Result := FEvaluateFlags;
end;
function TWatchValue.GetNumValue(ADispFormat: TWatchDisplayFormat): String;
function HexDigicCount(ANum: QWord; AForceAddr: Boolean = False): integer;
begin
if (FNumValue > high(DWord)) then
Result := 16
else
if (FNumValue > high(Word)) then
Result := 8
else
if (FNumValue > high(Byte)) then
Result := 4
else
Result := 2;
if FNumByteSize*2 > Result then
Result := FNumByteSize*2;
if AForceAddr or ( (nvfAddrType in FNumFlags) and (FNumByteSize = 0) ) then begin
// Fallback / TODO: Use Target-AddrSize
if Result < SizeOf(Pointer)*2 then
Result := 16;
end;
end;
var
n: Integer;
t: String;
begin
if (Validity <> ddsValid) or not(vtNumVal in FValidTypes) then
exit(Value);
if (nvfAddrType in FNumFlags) and (FTypeName <> '') and
(ADispFormat in [wdfDefault, wdfStructure])
then
t := FTypeName;
if ( ((nvfAddrType in FNumFlags) and (ADispFormat in [wdfDefault, wdfStructure])) or
(ADispFormat = wdfPointer)
) and
(FNumValue = 0)
then begin
Result := 'nil';
end
else begin
if not (ADispFormat in [wdfDecimal, wdfUnsigned, wdfHex, wdfBinary, wdfPointer]) then begin
//wdfDefault, wdfStructure, wdfChar, wdfString, wdfFloat
if nvfAddrType in FNumFlags then
ADispFormat := wdfPointer
else
if nvfUnsigned in FNumFlags then
ADispFormat := wdfUnsigned
else
ADispFormat := wdfDecimal;
end;
case ADispFormat of
wdfUnsigned: begin
Result := IntToStr(QWord(FNumValue))
end;
wdfHex: begin
n := HexDigicCount(FNumValue);
Result := '$'+IntToHex(QWord(FNumValue), n);
end;
wdfBinary: begin
n := HexDigicCount(FNumValue);
Result := '%'+IntToBin(Int64(FNumValue), n*4);
end;
wdfPointer: begin
n := HexDigicCount(FNumValue, True);
Result := '$'+IntToHex(QWord(FNumValue), n);
end;
else begin // wdfDecimal
if nvfUnsigned in FNumFlags then
Result := IntToStr(QWord(FNumValue))
else
Result := IntToStr(Int64(FNumValue));
end;
end;
end;
if t <> '' then
Result := t + '(' + Result + ')';
end;
procedure TWatchValue.SetWatch(AValue: TWatch);
begin
if FWatch = AValue then Exit;
@ -225,9 +328,27 @@ begin
SetTypeInfo(TDBGType(AValue));
end;
procedure TWatchValue.SetNumValue(ANumValue: QWord; AByteSize: Integer;
AFlags: TNumValueFlags);
begin
assert(not(vtNumVal in FValidTypes), 'TWatchValue.SetNumValue: not(vtNumVal in FValidTypes)');
Include(FValidTypes, vtNumVal);
FNumValue := ANumValue;
FNumByteSize := AByteSize;
FNumFlags := AFlags;
end;
procedure TWatchValue.SetTypeName(ATypeName: String);
begin
assert(not(vtTypeName in FValidTypes), 'TWatchValue.SetTypeName: not(vtTypeName in FValidTypes)');
Include(FValidTypes, vtTypeName);
FTypeName := ATypeName;
end;
procedure TWatchValue.DoDataValidityChanged(AnOldValidity: TDebuggerDataState);
begin
//
end;
function TWatchValue.GetExpression: String;
@ -272,6 +393,12 @@ begin
end;
FValue := AnOther.FValue;
FValidity := AnOther.FValidity;
FValidTypes := AnOther.FValidTypes;
FNumValue := AnOther.FNumValue;
FNumByteSize := AnOther.FNumByteSize;
FNumFlags := AnOther.FNumFlags;
FTypeName := AnOther.FTypeName;
end;
{ TWatch }
@ -435,7 +562,11 @@ begin
while i >= 0 do begin
Result := TWatchValue(FList[i]);
if (Result.ThreadId = AThreadId) and (Result.StackFrame = AStackFrame) and
(Result.DisplayFormat = FWatch.DisplayFormat) and
( ( (vtNumVal in Result.ValidTypes) and
not(FWatch.DisplayFormat in [wdfMemDump, wdfChar, wdfString, wdfFloat])
) or
(Result.DisplayFormat = FWatch.DisplayFormat)
) and
(Result.RepeatCount = FWatch.RepeatCount) and
(Result.EvaluateFlags = FWatch.EvaluateFlags)
then