FpDebug: Show "class var" if in current context (no class/instance-name prefix).

(cherry picked from commit d8188bb780)
This commit is contained in:
Martin 2021-11-30 15:50:52 +01:00
parent 709f86d99f
commit 340f6f1502
5 changed files with 176 additions and 11 deletions

View File

@ -123,10 +123,13 @@ type
function FindExportedSymbolInUnits(const AName: String; const ANameInfo: TNameSearchInfo; function FindExportedSymbolInUnits(const AName: String; const ANameInfo: TNameSearchInfo;
SkipCompUnit: TDwarfCompilationUnit; out ADbgValue: TFpValue; const OnlyUnitNameLower: String = ''): Boolean; SkipCompUnit: TDwarfCompilationUnit; out ADbgValue: TFpValue; const OnlyUnitNameLower: String = ''): Boolean;
function FindSymbolInStructure(const AName: String; const ANameInfo: TNameSearchInfo; function FindSymbolInStructure(const AName: String; const ANameInfo: TNameSearchInfo;
InfoEntry: TDwarfInformationEntry; out ADbgValue: TFpValue): Boolean; virtual;
function FindSymbolInStructureRecursive(const AName: String; const ANameInfo: TNameSearchInfo;
InfoEntry: TDwarfInformationEntry; out ADbgValue: TFpValue): Boolean; inline; InfoEntry: TDwarfInformationEntry; out ADbgValue: TFpValue): Boolean; inline;
// FindLocalSymbol: for the subroutine itself // FindLocalSymbol: for the subroutine itself
function FindLocalSymbol(const AName: String; const ANameInfo: TNameSearchInfo; function FindLocalSymbol(const AName: String; const ANameInfo: TNameSearchInfo;
InfoEntry: TDwarfInformationEntry; out ADbgValue: TFpValue): Boolean; virtual; InfoEntry: TDwarfInformationEntry; out ADbgValue: TFpValue): Boolean; virtual;
procedure Init; virtual;
public public
constructor Create(ALocationContext: TFpDbgLocationContext; ASymbol: TFpSymbol; ADwarf: TFpDwarfInfo); constructor Create(ALocationContext: TFpDbgLocationContext; ASymbol: TFpSymbol; ADwarf: TFpDwarfInfo);
destructor Destroy; override; destructor Destroy; override;
@ -1474,22 +1477,34 @@ end;
function TFpDwarfInfoSymbolScope.FindSymbolInStructure(const AName: String; function TFpDwarfInfoSymbolScope.FindSymbolInStructure(const AName: String;
const ANameInfo: TNameSearchInfo; InfoEntry: TDwarfInformationEntry; out const ANameInfo: TNameSearchInfo; InfoEntry: TDwarfInformationEntry; out
ADbgValue: TFpValue): Boolean; ADbgValue: TFpValue): Boolean;
begin
ADbgValue := nil;
Result := False;
end;
function TFpDwarfInfoSymbolScope.FindSymbolInStructureRecursive(const AName: String;
const ANameInfo: TNameSearchInfo; InfoEntry: TDwarfInformationEntry; out
ADbgValue: TFpValue): Boolean;
var var
InfoEntryInheritance: TDwarfInformationEntry; InfoEntryInheritance: TDwarfInformationEntry;
FwdInfoPtr: Pointer; FwdInfoPtr: Pointer;
FwdCompUint: TDwarfCompilationUnit; FwdCompUint: TDwarfCompilationUnit;
SelfParam: TFpValue; SelfParam: TFpValue;
StartScope: Integer;
begin begin
Result := False; Result := False;
ADbgValue := nil; ADbgValue := nil;
InfoEntry.AddReference; InfoEntry.AddReference;
InfoEntryInheritance := nil;
while True do begin while True do begin
if not InfoEntry.IsAddressInStartScope(FAddress) then if not InfoEntry.IsAddressInStartScope(FAddress) then
break; break;
InfoEntryInheritance.ReleaseReference;
InfoEntryInheritance := InfoEntry.FindChildByTag(DW_TAG_inheritance); InfoEntryInheritance := InfoEntry.FindChildByTag(DW_TAG_inheritance);
StartScope := InfoEntry.ScopeIndex;
if InfoEntry.GoNamedChildEx(ANameInfo) then begin if InfoEntry.GoNamedChildEx(ANameInfo) then begin
if InfoEntry.IsAddressInStartScope(FAddress) then begin if InfoEntry.IsAddressInStartScope(FAddress) then begin
SelfParam := GetSelfParameter; SelfParam := GetSelfParameter;
@ -1501,12 +1516,13 @@ begin
if ADbgValue = nil then begin // Todo: abort the searh /SetError if ADbgValue = nil then begin // Todo: abort the searh /SetError
ADbgValue := SymbolToValue(TFpSymbolDwarf.CreateSubClass(AName, InfoEntry)); ADbgValue := SymbolToValue(TFpSymbolDwarf.CreateSubClass(AName, InfoEntry));
end; end;
InfoEntry.ReleaseReference; break;
InfoEntryInheritance.ReleaseReference;
Result := True;
exit;
end; end;
end; end;
InfoEntry.ScopeIndex := StartScope;
if FindSymbolInStructure(AName, ANameInfo, InfoEntry, ADbgValue) then
break;
if not( (InfoEntryInheritance <> nil) and if not( (InfoEntryInheritance <> nil) and
@ -1515,10 +1531,10 @@ begin
break; break;
InfoEntry.ReleaseReference; InfoEntry.ReleaseReference;
InfoEntry := TDwarfInformationEntry.Create(FwdCompUint, FwdInfoPtr); InfoEntry := TDwarfInformationEntry.Create(FwdCompUint, FwdInfoPtr);
InfoEntryInheritance.ReleaseReference;
DebugLn(FPDBG_DWARF_SEARCH, ['TDbgDwarf.FindIdentifier PARENT ', dbgs(InfoEntry, FwdCompUint) ]); DebugLn(FPDBG_DWARF_SEARCH, ['TDbgDwarf.FindIdentifier PARENT ', dbgs(InfoEntry, FwdCompUint) ]);
end; end;
InfoEntryInheritance.ReleaseReference;
InfoEntry.ReleaseReference; InfoEntry.ReleaseReference;
Result := ADbgValue <> nil; Result := ADbgValue <> nil;
end; end;
@ -1541,6 +1557,11 @@ begin
Result := ADbgValue <> nil; Result := ADbgValue <> nil;
end; end;
procedure TFpDwarfInfoSymbolScope.Init;
begin
//
end;
constructor TFpDwarfInfoSymbolScope.Create( constructor TFpDwarfInfoSymbolScope.Create(
ALocationContext: TFpDbgLocationContext; ASymbol: TFpSymbol; ALocationContext: TFpDbgLocationContext; ASymbol: TFpSymbol;
ADwarf: TFpDwarfInfo); ADwarf: TFpDwarfInfo);
@ -1552,6 +1573,7 @@ begin
FAddress := LocationContext.Address; // for quick access FAddress := LocationContext.Address; // for quick access
if FSymbol <> nil then if FSymbol <> nil then
FSymbol.AddReference{$IFDEF WITH_REFCOUNT_DEBUG}(@FSymbol, 'Context to Symbol'){$ENDIF}; FSymbol.AddReference{$IFDEF WITH_REFCOUNT_DEBUG}(@FSymbol, 'Context to Symbol'){$ENDIF};
Init;
end; end;
destructor TFpDwarfInfoSymbolScope.Destroy; destructor TFpDwarfInfoSymbolScope.Destroy;
@ -1648,7 +1670,7 @@ begin
if (tg = DW_TAG_class_type) or (tg = DW_TAG_structure_type) then begin if (tg = DW_TAG_class_type) or (tg = DW_TAG_structure_type) then begin
if FindSymbolInStructure(AName,NameInfo, InfoEntry, Result) then begin if FindSymbolInStructureRecursive(AName,NameInfo, InfoEntry, Result) then begin
exit; // TODO: check error exit; // TODO: check error
end; end;
//InfoEntry.ScopeIndex := StartScopeIdx; //InfoEntry.ScopeIndex := StartScopeIdx;

View File

@ -72,6 +72,8 @@ type
class function ClassCanHandleCompUnit(ACU: TDwarfCompilationUnit): Boolean; override; class function ClassCanHandleCompUnit(ACU: TDwarfCompilationUnit): Boolean; override;
public public
function GetDwarfSymbolClass(ATag: Cardinal): TDbgDwarfSymbolBaseClass; override; function GetDwarfSymbolClass(ATag: Cardinal): TDbgDwarfSymbolBaseClass; override;
function CreateScopeForSymbol(ALocationContext: TFpDbgLocationContext; ASymbol: TFpSymbol;
ADwarf: TFpDwarfInfo): TFpDbgSymbolScope; override;
//class function CreateSymbolScope(AThreadId, AStackFrame: Integer; AnAddress: TDBGPtr; ASymbol: TFpSymbol; //class function CreateSymbolScope(AThreadId, AStackFrame: Integer; AnAddress: TDBGPtr; ASymbol: TFpSymbol;
// ADwarf: TFpDwarfInfo): TFpDbgSymbolScope; override; // ADwarf: TFpDwarfInfo): TFpDbgSymbolScope; override;
//class function CreateProcSymbol(ACompilationUnit: TDwarfCompilationUnit; //class function CreateProcSymbol(ACompilationUnit: TDwarfCompilationUnit;
@ -88,13 +90,25 @@ type
private private
FOuterNestContext: TFpDbgSymbolScope; FOuterNestContext: TFpDbgSymbolScope;
FOuterNotFound: Boolean; FOuterNotFound: Boolean;
FClassVarStaticPrefix: String;
protected protected
function FindLocalSymbol(const AName: String; const ANameInfo: TNameSearchInfo; function FindLocalSymbol(const AName: String; const ANameInfo: TNameSearchInfo;
InfoEntry: TDwarfInformationEntry; out ADbgValue: TFpValue): Boolean; override; InfoEntry: TDwarfInformationEntry; out ADbgValue: TFpValue): Boolean; override;
function FindSymbolInStructure(const AName: String;
const ANameInfo: TNameSearchInfo; InfoEntry: TDwarfInformationEntry; out
ADbgValue: TFpValue): Boolean; override;
procedure Init; override;
public public
destructor Destroy; override; destructor Destroy; override;
end; end;
{ TFpDwarfFreePascalSymbolScopeDwarf3 }
TFpDwarfFreePascalSymbolScopeDwarf3 = class(TFpDwarfFreePascalSymbolScope)
protected
procedure Init; override;
end;
{%EndRegion } {%EndRegion }
{%Region * ***** Value & Types ***** *} {%Region * ***** Value & Types ***** *}
@ -450,6 +464,13 @@ begin
end; end;
end; end;
function TFpDwarfFreePascalSymbolClassMapDwarf3.CreateScopeForSymbol(
ALocationContext: TFpDbgLocationContext; ASymbol: TFpSymbol;
ADwarf: TFpDwarfInfo): TFpDbgSymbolScope;
begin
Result := TFpDwarfFreePascalSymbolScopeDwarf3.Create(ALocationContext, ASymbol, ADwarf);
end;
type type
{ TFpDbgDwarfSimpleLocationContext } { TFpDbgDwarfSimpleLocationContext }
@ -613,12 +634,63 @@ begin
Result := True; // self, global was done by outer Result := True; // self, global was done by outer
end; end;
function TFpDwarfFreePascalSymbolScope.FindSymbolInStructure(
const AName: String; const ANameInfo: TNameSearchInfo;
InfoEntry: TDwarfInformationEntry; out ADbgValue: TFpValue): Boolean;
var
CU: TDwarfCompilationUnit;
CurClassName, StaticName, FoundName: String;
MangledNameInfo: TNameSearchInfo;
FoundInfoEntry: TDwarfInformationEntry;
IsExternal: Boolean;
begin
Result := inherited FindSymbolInStructure(AName, ANameInfo, InfoEntry, ADbgValue);
if Result then
exit;
CU := InfoEntry.CompUnit;
if (CU <> nil) and InfoEntry.HasValidScope and
InfoEntry.ReadName(CurClassName) and not InfoEntry.IsArtificial
then begin
StaticName := FClassVarStaticPrefix + LowerCase(CurClassName) + '_' + UpperCase(AName);
MangledNameInfo := NameInfoForSearch(StaticName);
if CU.KnownNameHashes^[MangledNameInfo.NameHash and KnownNameHashesBitMask] then begin
if FindExportedSymbolInUnit(CU, MangledNameInfo, FoundInfoEntry, IsExternal) then begin
if {(IsExternal) and} (FoundInfoEntry.ReadName(FoundName)) then begin
if FoundName = StaticName then begin // must be case-sensitive
ADbgValue := SymbolToValue(TFpSymbolDwarf.CreateSubClass(AName, FoundInfoEntry));
Result := True;
end;
end;
FoundInfoEntry.ReleaseReference;
if Result then
exit;
end;
end;
end;
end;
procedure TFpDwarfFreePascalSymbolScope.Init;
begin
inherited Init;
FClassVarStaticPrefix := '_static_';
end;
destructor TFpDwarfFreePascalSymbolScope.Destroy; destructor TFpDwarfFreePascalSymbolScope.Destroy;
begin begin
FOuterNestContext.ReleaseReference; FOuterNestContext.ReleaseReference;
inherited Destroy; inherited Destroy;
end; end;
{ TFpDwarfFreePascalSymbolScopeDwarf3 }
procedure TFpDwarfFreePascalSymbolScopeDwarf3.Init;
begin
inherited Init;
FClassVarStaticPrefix := '$_static_';
end;
{ TFpSymbolDwarfV2FreePascalTypeStructure } { TFpSymbolDwarfV2FreePascalTypeStructure }
function TFpSymbolDwarfV2FreePascalTypeStructure.IsShortString: Boolean; function TFpSymbolDwarfV2FreePascalTypeStructure.IsShortString: Boolean;

View File

@ -18,7 +18,7 @@ type
FEvalDone: Boolean; FEvalDone: Boolean;
procedure DoEvalDone(Sender: TObject; ASuccess: Boolean; procedure DoEvalDone(Sender: TObject; ASuccess: Boolean;
ResultText: String; ResultDBGType: TDBGType); ResultText: String; ResultDBGType: TDBGType);
procedure RunToPause(var ABrk: TDBGBreakPoint); procedure RunToPause(var ABrk: TDBGBreakPoint; ADisableBreak: Boolean = True);
published published
procedure TestWatchesScope; procedure TestWatchesScope;
procedure TestWatchesValue; procedure TestWatchesValue;
@ -37,11 +37,13 @@ var
ControlTestWatchAddressOf, ControlTestWatchTypeCast, ControlTestModify, ControlTestWatchAddressOf, ControlTestWatchTypeCast, ControlTestModify,
ControlTestExpression, ControlTestErrors: Pointer; ControlTestExpression, ControlTestErrors: Pointer;
procedure TTestWatches.RunToPause(var ABrk: TDBGBreakPoint); procedure TTestWatches.RunToPause(var ABrk: TDBGBreakPoint;
ADisableBreak: Boolean);
begin begin
Debugger.RunToNextPause(dcRun); Debugger.RunToNextPause(dcRun);
AssertDebuggerState(dsPause); AssertDebuggerState(dsPause);
ABrk.Enabled := False; if ADisableBreak then
ABrk.Enabled := False;
end; end;
procedure TTestWatches.DoEvalDone(Sender: TObject; ASuccess: Boolean; procedure TTestWatches.DoEvalDone(Sender: TObject; ASuccess: Boolean;
@ -1123,6 +1125,12 @@ for i := StartIdx to t.Count-1 do
for i := StartIdxClassConst to t.Count-1 do for i := StartIdxClassConst to t.Count-1 do
t.Tests[i].SkipIf(ALoc in [tlClassConst]); t.Tests[i].SkipIf(ALoc in [tlClassConst]);
// Trigger a search through everything
t.Add('NotExistingFooBar123_X', weInteger(0))^.AddFlag(ehExpectError);
end; end;
var var
@ -1130,7 +1138,7 @@ var
t: TWatchExpectationList; t: TWatchExpectationList;
Src: TCommonSource; Src: TCommonSource;
BrkPrg, BrkFooBegin, BrkFoo, BrkFooVar, BrkFooVarBegin, BrkPrg, BrkFooBegin, BrkFoo, BrkFooVar, BrkFooVarBegin,
BrkFooConstRef: TDBGBreakPoint; BrkFooConstRef, BrkMethFoo, BrkBaseMethFoo: TDBGBreakPoint;
c, i: Integer; c, i: Integer;
begin begin
if SkipTest then exit; if SkipTest then exit;
@ -1158,6 +1166,9 @@ begin
BrkFooVarBegin := Debugger.SetBreakPoint(Src, 'FooVarBegin'); BrkFooVarBegin := Debugger.SetBreakPoint(Src, 'FooVarBegin');
BrkFooVar := Debugger.SetBreakPoint(Src, 'FooVar'); BrkFooVar := Debugger.SetBreakPoint(Src, 'FooVar');
BrkFooConstRef := Debugger.SetBreakPoint(Src, 'FooConstRef'); BrkFooConstRef := Debugger.SetBreakPoint(Src, 'FooConstRef');
BrkMethFoo := Debugger.SetBreakPoint(Src, 'MethFoo'); // call with TMyClass
BrkBaseMethFoo := Debugger.SetBreakPoint(Src, 'BaseMethFoo'); // call with TMyClass
AssertDebuggerNotInErrorState; AssertDebuggerNotInErrorState;
(* ************ Nested Functions ************* *) (* ************ Nested Functions ************* *)
@ -1358,6 +1369,39 @@ if Compiler.Version < 030300 then
t.CheckResults; t.CheckResults;
RunToPause(BrkBaseMethFoo, False);
t.Clear;
t.Add('BaseMethFoo of TMyClass1 - ClassBaseVar1', 'ClassBaseVar1', weInteger(118));
// t.Add('BaseMethFoo of TMyClass1 - ClassVar1', 'ClassVar1', weInteger(119));
// Trigger a search through everything
t.Add('BaseMethFoo of NotExistingFooBar123_X', weInteger(0))^.AddFlag(ehExpectError);
//AddWatches(t, 'foo const ref args', 'argconstref', 001, 'B', tlParam);
t.EvaluateWatches;
t.CheckResults;
RunToPause(BrkMethFoo);
t.Clear;
t.Add('MethFoo of TMyClass1 - ClassBaseVar1', 'ClassBaseVar1', weInteger(118));
t.Add('MethFoo of TMyClass1 - ClassVar1', 'ClassVar1', weInteger(119));
// Trigger a search through everything
t.Add('MethFoo of TMyClass1 - NotExistingFooBar123_X', weInteger(0))^.AddFlag(ehExpectError);
//AddWatches(t, 'foo const ref args', 'argconstref', 001, 'B', tlParam);
t.EvaluateWatches;
t.CheckResults;
RunToPause(BrkBaseMethFoo);
t.Clear;
t.Add('BaseMethFoo of TMyBaseClass - ClassBaseVar1', 'ClassBaseVar1', weInteger(118));
// t.Add('BaseMethFoo of TMyBaseClass - ClassVar1', 'ClassVar1', weInteger(119));
// Trigger a search through everything
t.Add('BaseMethFoo of TMyBaseClass - NotExistingFooBar123_X', weInteger(0))^.AddFlag(ehExpectError);
//AddWatches(t, 'foo const ref args', 'argconstref', 001, 'B', tlParam);
t.EvaluateWatches;
t.CheckResults;
finally finally
Debugger.RunToNextPause(dcStop); Debugger.RunToNextPause(dcStop);
t.Free; t.Free;

View File

@ -13,6 +13,7 @@ program WatchesValuePrg;
{$hints off} {$hints off}
{$notes off} {$notes off}
{$warnings off} {$warnings off}
{$inline off}
uses sysutils, Classes; uses sysutils, Classes;
@ -68,7 +69,7 @@ type
var var
BreakDummy: PtrUInt; BreakDummy, BreakDummy2: PtrUInt;
PByteDummy: PByte; PByteDummy: PByte;
p: Pointer; p: Pointer;
pw: PWord; // ensure we have the type pw: PWord; // ensure we have the type
@ -349,10 +350,13 @@ type
TEST_PREPOCESS(WatchesValuePrgIdent.inc, pre__=cl_v_, _OP_=:, (=;//, _O2_=:, _EQ_=, _BLOCK_=TestVar ) TEST_PREPOCESS(WatchesValuePrgIdent.inc, pre__=cl_v_, _OP_=:, (=;//, _O2_=:, _EQ_=, _BLOCK_=TestVar )
public public
function SomeMeth1(SomeValue: Integer): Boolean; function SomeMeth1(SomeValue: Integer): Boolean;
procedure BaseMethFoo;
public public
(* LOCATION: field in baseclass *) (* LOCATION: field in baseclass *)
// mbcByte: Byte; // mbcByte: Byte;
TEST_PREPOCESS(WatchesValuePrgIdent.inc, pre__=mbc, _OP_=:, (=;//, _O2_=:, _EQ_=, _BLOCK_=TestVar ) TEST_PREPOCESS(WatchesValuePrgIdent.inc, pre__=mbc, _OP_=:, (=;//, _O2_=:, _EQ_=, _BLOCK_=TestVar )
public class var
ClassBaseVar1: integer;
end; end;
PMyBaseClass = ^TMyBaseClass; PMyBaseClass = ^TMyBaseClass;
@ -367,6 +371,9 @@ type
function SomeFuncIntRes(): Integer; function SomeFuncIntRes(): Integer;
function SomeFuncIntResAdd(a: integer): Integer; function SomeFuncIntResAdd(a: integer): Integer;
procedure MethFoo;
public class var
ClassVar1: integer;
end; end;
PMyClass = ^TMyClass; PMyClass = ^TMyClass;
@ -479,6 +486,18 @@ begin end;
function TMyBaseClass.SomeMeth1(SomeValue: Integer): Boolean; function TMyBaseClass.SomeMeth1(SomeValue: Integer): Boolean;
begin result := SomeValue = 0; end; begin result := SomeValue = 0; end;
procedure TMyBaseClass.BaseMethFoo;
begin
BreakDummy:= 112; // TEST_BREAKPOINT=BaseMethFoo
BreakDummy2 := ClassBaseVar1;
end;
procedure TMyClass.MethFoo;
begin
BreakDummy:= 113; // TEST_BREAKPOINT=MethFoo
BreakDummy2 := ClassVar1;
end;
procedure Foo( procedure Foo(
(* LOCATION: param *) (* LOCATION: param *)
TEST_PREPOCESS(WatchesValuePrgIdent.inc, pre__=arg, _OP_=:, (=;//, _O2_=:, _EQ_= , _BLOCK_=TestArg) TEST_PREPOCESS(WatchesValuePrgIdent.inc, pre__=arg, _OP_=:, (=;//, _O2_=:, _EQ_= , _BLOCK_=TestArg)
@ -969,5 +988,13 @@ begin
0 0
); );
TMyClass.ClassBaseVar1 := 118;
TMyClass.ClassVar1 := 119;
MyClass1.BaseMethFoo();
MyClass1.MethFoo();
MyClass2.BaseMethFoo();
end. end.