mirror of
https://gitlab.com/freepascal.org/lazarus/lazarus.git
synced 2025-08-27 17:00:31 +02:00
Debugger: Converter, match "*" and inheritance via "is:"
This commit is contained in:
parent
bca093c6ec
commit
48043da966
@ -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}
|
||||||
|
@ -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
|
||||||
|
@ -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 }
|
||||||
|
Loading…
Reference in New Issue
Block a user