Debugger: Converter, match "*" and inheritance via "is:"

This commit is contained in:
Martin 2022-08-01 18:39:58 +02:00
parent bca093c6ec
commit 48043da966
3 changed files with 158 additions and 22 deletions

View File

@ -157,10 +157,13 @@ type
//function GetInstanceClass(AValueObj: TFpValueDwarf): TFpSymbolDwarf; override; //function GetInstanceClass(AValueObj: TFpValueDwarf): TFpSymbolDwarf; override;
class function GetInstanceClassNameFromPVmt(APVmt: TDbgPtr; class function GetInstanceClassNameFromPVmt(APVmt: TDbgPtr;
AContext: TFpDbgLocationContext; ASizeOfAddr: Integer; AContext: TFpDbgLocationContext; ASizeOfAddr: Integer;
out AClassName: String; out AnError: TFpError): boolean; out AClassName: String; out AnError: TFpError;
AParentClassIndex: integer = 0;
ACompilerVersion: Cardinal = 0): boolean;
public public
function GetInstanceClassName(AValueObj: TFpValue; out function GetInstanceClassName(AValueObj: TFpValue; out
AClassName: String): boolean; override; AClassName: String;
AParentClassIndex: integer = 0): boolean; override;
end; end;
(* *** Record vs ShortString *** *) (* *** Record vs ShortString *** *)
@ -965,7 +968,8 @@ begin
end; end;
function TFpSymbolDwarfFreePascalTypeStructure.GetInstanceClassName( function TFpSymbolDwarfFreePascalTypeStructure.GetInstanceClassName(
AValueObj: TFpValue; out AClassName: String): boolean; AValueObj: TFpValue; out AClassName: String; AParentClassIndex: integer
): boolean;
var var
AnErr: TFpError; AnErr: TFpError;
begin begin
@ -973,21 +977,27 @@ begin
if not Result then if not Result then
exit; exit;
Result := GetInstanceClassNameFromPVmt(LocToAddrOrNil(AValueObj.DataAddress), Result := GetInstanceClassNameFromPVmt(LocToAddrOrNil(AValueObj.DataAddress),
TFpValueDwarf(AValueObj).Context, TFpValueDwarf(AValueObj).Context.SizeOfAddress, AClassName, AnErr); TFpValueDwarf(AValueObj).Context, TFpValueDwarf(AValueObj).Context.SizeOfAddress,
AClassName, AnErr, AParentClassIndex,
TFpDwarfFreePascalSymbolClassMap(CompilationUnit.DwarfSymbolClassMap).FCompilerVersion
);
if not Result then if not Result then
SetLastError(AValueObj, AnErr); SetLastError(AValueObj, AnErr);
end; end;
class function TFpSymbolDwarfFreePascalTypeStructure.GetInstanceClassNameFromPVmt class function TFpSymbolDwarfFreePascalTypeStructure.GetInstanceClassNameFromPVmt
(APVmt: TDbgPtr; AContext: TFpDbgLocationContext; ASizeOfAddr: Integer; out (APVmt: TDbgPtr; AContext: TFpDbgLocationContext; ASizeOfAddr: Integer; out
AClassName: String; out AnError: TFpError): boolean; AClassName: String; out AnError: TFpError; AParentClassIndex: integer;
ACompilerVersion: Cardinal): boolean;
var var
VmtAddr, ClassNameAddr: TFpDbgMemLocation; VmtAddr, ClassNameAddr, A: TFpDbgMemLocation;
NameLen: QWord; NameLen: QWord;
begin begin
Result := False; Result := False;
AnError := NoError; AnError := NoError;
AClassName := ''; AClassName := '';
if not AContext.ReadAddress(TargetLoc(APVmt), SizeVal(ASizeOfAddr), VmtAddr) then begin if not AContext.ReadAddress(TargetLoc(APVmt), SizeVal(ASizeOfAddr), VmtAddr) then begin
AnError := AContext.LastMemError; AnError := AContext.LastMemError;
exit; exit;
@ -996,6 +1006,37 @@ begin
AnError := CreateError(fpErrCanNotReadMemAtAddr, [VmtAddr.Address]); AnError := CreateError(fpErrCanNotReadMemAtAddr, [VmtAddr.Address]);
exit; exit;
end; end;
while AParentClassIndex > 0 do begin
{$PUSH}{$Q-}
VmtAddr.Address := VmtAddr.Address + TDBGPtr(2 * ASizeOfAddr);
{$POP}
A := VmtAddr;
if not AContext.ReadAddress(A, SizeVal(ASizeOfAddr), VmtAddr) then begin
AnError := AContext.LastMemError;
exit;
end;
if not IsReadableMem(VmtAddr) then begin
AnError := CreateError(fpErrCanNotReadMemAtAddr, [VmtAddr.Address]);
exit;
end;
if (ACompilerVersion >= $030200)
then begin
A := VmtAddr;
if not AContext.ReadAddress(A, SizeVal(ASizeOfAddr), VmtAddr) then begin
AnError := AContext.LastMemError;
exit;
end;
if not IsReadableMem(VmtAddr) then begin
AnError := CreateError(fpErrCanNotReadMemAtAddr, [VmtAddr.Address]);
exit;
end;
end;
dec(AParentClassIndex);
end;
{$PUSH}{$Q-} {$PUSH}{$Q-}
VmtAddr.Address := VmtAddr.Address + TDBGPtr(3 * ASizeOfAddr); VmtAddr.Address := VmtAddr.Address + TDBGPtr(3 * ASizeOfAddr);
{$POP} {$POP}

View File

@ -187,7 +187,7 @@ type
public public
function GetTypeCastedValue(ADataVal: TFpValue): TFpValue; virtual; // only if Symbol is a type function GetTypeCastedValue(ADataVal: TFpValue): TFpValue; virtual; // only if Symbol is a type
function GetInstanceClassName(out AClassName: String): boolean; virtual; function GetInstanceClassName(out AClassName: String; AParentClassIndex: integer = 0): boolean; virtual;
// base class? Or Member includes member from base // base class? Or Member includes member from base
(* Member: (* Member:
@ -463,7 +463,7 @@ type
// //
property Flags: TDbgSymbolFlags read GetFlags; property Flags: TDbgSymbolFlags read GetFlags;
property Parent: TFpSymbol read GetParent; deprecated; property Parent: TFpSymbol read GetParent; deprecated;
function GetInstanceClassName(AValueObj: TFpValue; out AClassName: String): boolean; virtual; function GetInstanceClassName(AValueObj: TFpValue; out AClassName: String; AParentClassIndex: integer = 0): boolean; virtual;
// for Subranges // Type-Symbols only? // for Subranges // Type-Symbols only?
// TODO: flag bounds as cardinal if needed // TODO: flag bounds as cardinal if needed
@ -508,7 +508,7 @@ type
function GetNestedSymbolByName(const AIndex: String): TFpSymbol; override; function GetNestedSymbolByName(const AIndex: String): TFpSymbol; override;
function GetNestedSymbolCount: Integer; override; function GetNestedSymbolCount: Integer; override;
public public
function GetInstanceClassName(AValueObj: TFpValue; out AClassName: String): boolean; override; function GetInstanceClassName(AValueObj: TFpValue; out AClassName: String; AParentClassIndex: integer = 0): boolean; override;
function GetValueBounds(AValueObj: TFpValue; out ALowBound, AHighBound: Int64): Boolean; override; function GetValueBounds(AValueObj: TFpValue; out ALowBound, AHighBound: Int64): Boolean; override;
function GetValueLowBound(AValueObj: TFpValue; out ALowBound: Int64): Boolean; override; function GetValueLowBound(AValueObj: TFpValue; out ALowBound: Int64): Boolean; override;
function GetValueHighBound(AValueObj: TFpValue; out AHighBound: Int64): Boolean; override; function GetValueHighBound(AValueObj: TFpValue; out AHighBound: Int64): Boolean; override;
@ -929,14 +929,15 @@ begin
Result := nil; Result := nil;
end; end;
function TFpValue.GetInstanceClassName(out AClassName: String): boolean; function TFpValue.GetInstanceClassName(out AClassName: String;
AParentClassIndex: integer): boolean;
var var
ti: TFpSymbol; ti: TFpSymbol;
begin begin
ti := TypeInfo; ti := TypeInfo;
Result := ti <> nil; Result := ti <> nil;
if Result then if Result then
Result := ti.GetInstanceClassName(Self, AClassName); Result := ti.GetInstanceClassName(Self, AClassName, AParentClassIndex);
end; end;
procedure TFpValue.ResetError; procedure TFpValue.ResetError;
@ -1396,7 +1397,7 @@ begin
end; end;
function TFpSymbol.GetInstanceClassName(AValueObj: TFpValue; out function TFpSymbol.GetInstanceClassName(AValueObj: TFpValue; out
AClassName: String): boolean; AClassName: String; AParentClassIndex: integer): boolean;
begin begin
AClassName := ''; AClassName := '';
Result := False; Result := False;
@ -1777,15 +1778,15 @@ begin
end; end;
function TFpSymbolForwarder.GetInstanceClassName(AValueObj: TFpValue; out function TFpSymbolForwarder.GetInstanceClassName(AValueObj: TFpValue; out
AClassName: String): boolean; AClassName: String; AParentClassIndex: integer): boolean;
var var
p: TFpSymbol; p: TFpSymbol;
begin begin
p := GetForwardToSymbol; p := GetForwardToSymbol;
if p <> nil then if p <> nil then
Result := p.GetInstanceClassName(AValueObj, AClassName) Result := p.GetInstanceClassName(AValueObj, AClassName, AParentClassIndex)
else else
Result := inherited GetInstanceClassName(AValueObj, AClassName); Result := inherited GetInstanceClassName(AValueObj, AClassName, AParentClassIndex);
end; end;
function TFpSymbolForwarder.GetValueBounds(AValueObj: TFpValue; out function TFpSymbolForwarder.GetValueBounds(AValueObj: TFpValue; out

View File

@ -6,9 +6,9 @@ interface
uses uses
Classes, SysUtils, fgl, FpDbgInfo, FpdMemoryTools, FpDbgCallContextInfo, Classes, SysUtils, fgl, FpDbgInfo, FpdMemoryTools, FpDbgCallContextInfo,
FpPascalBuilder, FpErrorMessages, FpDbgClasses, FpDbgUtil, DbgIntfBaseTypes, FpPascalBuilder, FpErrorMessages, FpDbgClasses, FpDbgUtil,
lazCollections, LazClasses, LCLProc, FpDebugDebuggerBase, DbgIntfBaseTypes, lazCollections, LazClasses, LCLProc, StrUtils,
LazDebuggerIntfBaseTypes; FpDebugDebuggerBase, LazDebuggerIntfBaseTypes;
type type
TDbgSymbolKinds = set of TDbgSymbolKind; TDbgSymbolKinds = set of TDbgSymbolKind;
@ -59,6 +59,7 @@ type
procedure Assign(ASource: TFpDbgConverterConfig); virtual; procedure Assign(ASource: TFpDbgConverterConfig); virtual;
function CheckMatch(AValue: TFpValue): Boolean; function CheckMatch(AValue: TFpValue): Boolean;
function CheckTypeMatch(AValue: TFpValue): Boolean;
property Converter: TFpDbgValueConverter read FConverter write SetConverter; property Converter: TFpDbgValueConverter read FConverter write SetConverter;
property MatchKinds: TDbgSymbolKinds read FMatchKinds write FMatchKinds; property MatchKinds: TDbgSymbolKinds read FMatchKinds write FMatchKinds;
@ -212,11 +213,104 @@ var
t: TFpSymbol; t: TFpSymbol;
TpName: String; TpName: String;
begin begin
t := AValue.TypeInfo;
Result := (AValue.Kind in (FMatchKinds * Converter.GetSupportedKinds)) and Result := (AValue.Kind in (FMatchKinds * Converter.GetSupportedKinds)) and
(t <> nil) and CheckTypeMatch(AValue);
GetTypeName(TpName, t, [tnfNoSubstitute]) and end;
(FMatchTypeNames.IndexOf(TpName) >= 0);
function TFpDbgConverterConfig.CheckTypeMatch(AValue: TFpValue): Boolean;
function MatchPattern(const AName, APattern: String): Boolean;
var
NamePos, PatternPos, p: Integer;
begin
Result := False;
if APattern = '' then
exit;
NamePos := 1;
PatternPos := 1;
while PatternPos <= Length(APattern) do begin
if APattern[PatternPos] = '*' then begin
inc(PatternPos);
end
else begin
p := PatternPos;
PatternPos := PosEx('*', APattern, p);
if PatternPos < 1 then
PatternPos := Length(APattern)+1;
if PatternPos-p > Length(AName)+1 - NamePos then
break;
NamePos := PosEx(Copy(APattern, p, PatternPos-p), AName, NamePos);
if (NamePos < 1) or
( (p = 1) and (NamePos <> 1) ) // APattern does not start with *
then
break;
inc(NamePos, PatternPos-p);
end;
end;
Result := (PatternPos = Length(APattern)+1) and
( (NamePos = Length(AName)+1) or
( (APattern[Length(APattern)] = '*') and
(NamePos <= Length(AName)+1)
)
);
end;
var
i, CnIdx: Integer;
TpName, Pattern, ValClassName: String;
t: TFpSymbol;
begin
t := AValue.TypeInfo;
Result := (t <> nil) and GetTypeName(TpName, t, [tnfNoSubstitute]);
if not Result then
exit;
TpName := LowerCase(TpName);
i := FMatchTypeNames.Count;
while i > 0 do begin
dec(i);
Pattern := LowerCase(trim(FMatchTypeNames[i]));
if AnsiStrLIComp('is:', @Pattern[1], 3) = 0 then begin
Delete(Pattern, 1, 3);
Pattern := trim(Pattern);
if (AValue.Kind in [skRecord, skClass, skObject, skInterface]) then begin
ValClassName := TpName;
while t <> nil do begin
Result := MatchPattern(ValClassName, Pattern);
if Result then
exit;
t := t.TypeInfo;
if (t = nil) or not GetTypeName(ValClassName, t, [tnfNoSubstitute]) then
break;
ValClassName := LowerCase(ValClassName);
end;
CnIdx := 0;
while AValue.GetInstanceClassName(ValClassName, CnIdx) and
(ValClassName <> '')
do begin
ValClassName := LowerCase(ValClassName);
if ValClassName = TpName then
Break;
Result := MatchPattern(ValClassName, Pattern);
if Result then
exit;
inc(CnIdx);
end;
Continue;
end;
end;
Result := MatchPattern(TpName, Pattern);
if Result then
exit;
end;
end; end;
{ TFpDbgConverterConfigList } { TFpDbgConverterConfigList }