diff --git a/components/fpdebug/fpdbgdwarf.pas b/components/fpdebug/fpdbgdwarf.pas index 05f336f93f..0c50007074 100644 --- a/components/fpdebug/fpdbgdwarf.pas +++ b/components/fpdebug/fpdbgdwarf.pas @@ -261,11 +261,16 @@ type function GetScopeIndex: Integer; procedure SetAbbrev(AValue: TDwarfAbbrev); procedure SetScopeIndex(AValue: Integer); + protected + function GoNamedChild(AName: String): Boolean; public constructor Create(ACompUnit: TDwarfCompilationUnit; AnInformationEntry: Pointer); constructor Create(ACompUnit: TDwarfCompilationUnit; AScope: TDwarfScopeInfo); property CompUnit: TDwarfCompilationUnit read FCompUnit; + function FindNamedChild(AName: String): TDwarfInformationEntry; + function FindChildByTag(ATag: Cardinal): TDwarfInformationEntry; + property Abbrev: TDwarfAbbrev read GetAbbrev write SetAbbrev; property AbbrevData: PDwarfAbbrevEntry read FAbbrevData; // only valid if Abbrev is available function HasAttrib(AnAttrib: Cardinal): boolean; @@ -541,6 +546,7 @@ type end; { TDbgDwarfTypeIdentifier } + TDbgDwarfIdentifierStructure = class; (* Types and allowed tags in dwarf 2 @@ -588,13 +594,18 @@ DECL = DW_AT_decl_column, DW_AT_decl_file, DW_AT_decl_line protected function GetIsBaseType: Boolean; virtual; function GetIsPointerType: Boolean; virtual; + function GetIsStructType: Boolean; virtual; function GetPointedToType: TDbgDwarfTypeIdentifier; virtual; + function GetStructTypeInfo: TDbgDwarfIdentifierStructure; virtual; public class function CreateTybeSubClass(AName: String; AnInformationEntry: TDwarfInformationEntry): TDbgDwarfTypeIdentifier; property TypeInfo; property IsBaseType: Boolean read GetIsBaseType; property IsPointerType: Boolean read GetIsPointerType; + property IsStructType: Boolean read GetIsStructType; + property PointedToType: TDbgDwarfTypeIdentifier read GetPointedToType; + property StructTypeInfo: TDbgDwarfIdentifierStructure read GetStructTypeInfo; end; { TDbgDwarfBaseTypeIdentifier } @@ -611,6 +622,8 @@ DECL = DW_AT_decl_column, DW_AT_decl_file, DW_AT_decl_line function GetIsBaseType: Boolean; override; function GetIsPointerType: Boolean; override; function GetPointedToType: TDbgDwarfTypeIdentifier; override; + function GetIsStructType: Boolean; override; + function GetStructTypeInfo: TDbgDwarfIdentifierStructure; override; end; { TDbgDwarfTypeIdentifierDeclaration } @@ -625,6 +638,25 @@ DECL = DW_AT_decl_column, DW_AT_decl_file, DW_AT_decl_line protected function GetIsPointerType: Boolean; override; function GetPointedToType: TDbgDwarfTypeIdentifier; override; + // fpc encodes classes as pointer, not ref (so Obj1 = obj2 compares the pointers) + function GetIsStructType: Boolean; override; + function GetStructTypeInfo: TDbgDwarfIdentifierStructure; override; + end; + + TDbgDwarfIdentifierMember = class(TDbgDwarfValueIdentifier) + end; + + { TDbgDwarfIdentifierStructure } + + TDbgDwarfIdentifierStructure = class(TDbgDwarfTypeIdentifier) + // record or class + private + function GetMemberByName(AName: String): TDbgDwarfIdentifierMember; + protected + function GetIsStructType: Boolean; override; + function GetStructTypeInfo: TDbgDwarfIdentifierStructure; override; + public + property MemberByName[AName: String]: TDbgDwarfIdentifierMember read GetMemberByName; end; { TDbgDwarfProcSymbol } @@ -1157,6 +1189,53 @@ begin end; end; +{ TDbgDwarfIdentifierStructure } + +function TDbgDwarfIdentifierStructure.GetMemberByName(AName: String): TDbgDwarfIdentifierMember; +var + Info, NewInfo, Ident: TDwarfInformationEntry; + FwdInfoPtr: Pointer; + FwdCompUint: TDwarfCompilationUnit; + r: TDbgDwarfIdentifier; +begin + Result := nil; + r := nil; + Info := FInformationEntry; + Info.AddReference; + while Info <> nil do begin + Ident := Info.FindNamedChild(AName); + if Ident <> nil then + r := TDbgDwarfTypeIdentifier.CreateSubClass('', Ident); + ReleaseRefAndNil(Ident); + if (R <> nil) and (r is TDbgDwarfIdentifierMember) then begin + ReleaseRefAndNil(Info); + Result := TDbgDwarfIdentifierMember(r); + break; + end; + + NewInfo := Info.FindChildByTag(DW_TAG_inheritance); + ReleaseRefAndNil(Info); + if NewInfo <> nil then begin + if NewInfo.ReadReference(DW_AT_type, FwdInfoPtr, FwdCompUint) then begin + Info := TDwarfInformationEntry.Create(FwdCompUint, FwdInfoPtr); + Info.SearchScope; + DebugLn(['!!!! PARENT !!! ', dbgs(Info.FScope, FwdCompUint) ]); + end; + ReleaseRefAndNil(NewInfo); + end; + end; +end; + +function TDbgDwarfIdentifierStructure.GetIsStructType: Boolean; +begin + Result := True; +end; + +function TDbgDwarfIdentifierStructure.GetStructTypeInfo: TDbgDwarfIdentifierStructure; +begin + Result := Self; +end; + { TDbgDwarfTypeIdentifierModifier } function TDbgDwarfTypeIdentifierModifier.GetIsBaseType: Boolean; @@ -1186,6 +1265,25 @@ begin Result := Result.PointedToType; end; +function TDbgDwarfTypeIdentifierModifier.GetIsStructType: Boolean; +var + ti: TDbgDwarfTypeIdentifier; +begin + ti := TypeInfo; + if ti <> nil + then Result := ti.IsStructType + else Result := False; +end; + +function TDbgDwarfTypeIdentifierModifier.GetStructTypeInfo: TDbgDwarfIdentifierStructure; +var + ti: TDbgDwarfTypeIdentifier; +begin + ti := TypeInfo; + if ti <> nil then + Result := ti.StructTypeInfo; +end; + { TDbgDwarfTypeIdentifierPointer } function TDbgDwarfTypeIdentifierPointer.GetIsPointerType: Boolean; @@ -1198,6 +1296,32 @@ begin Result := TypeInfo; end; +function TDbgDwarfTypeIdentifierPointer.GetIsStructType: Boolean; +var + ti: TDbgDwarfTypeIdentifier; +begin + Result := False; + ti := TypeInfo; + // fpc encodes classes as pointer, not ref (so Obj1 = obj2 compares the pointers) + if (ti <> nil) and (ti is TDbgDwarfIdentifierStructure) and + (ti.InformationEntry.Abbrev.tag = DW_TAG_class_type) + then + Result := True; +end; + +function TDbgDwarfTypeIdentifierPointer.GetStructTypeInfo: TDbgDwarfIdentifierStructure; +var + ti: TDbgDwarfTypeIdentifier; +begin + Result := nil; + ti := TypeInfo; + // fpc encodes classes as pointer, not ref (so Obj1 = obj2 compares the pointers) + if (ti <> nil) and (ti is TDbgDwarfIdentifierStructure) and + (ti.InformationEntry.Abbrev.tag = DW_TAG_class_type) + then + Result := TDbgDwarfIdentifierStructure(ti); +end; + { TDbgDwarfBaseTypeIdentifier } function TDbgDwarfBaseIdentifierBase.GetIsBaseType: Boolean; @@ -1212,6 +1336,11 @@ begin Result := nil; end; +function TDbgDwarfTypeIdentifier.GetStructTypeInfo: TDbgDwarfIdentifierStructure; +begin + Result := nil; +end; + function TDbgDwarfTypeIdentifier.GetIsBaseType: Boolean; begin Result := False; @@ -1222,6 +1351,11 @@ begin Result := False; end; +function TDbgDwarfTypeIdentifier.GetIsStructType: Boolean; +begin + Result := False; +end; + class function TDbgDwarfTypeIdentifier.CreateTybeSubClass(AName: String; AnInformationEntry: TDwarfInformationEntry): TDbgDwarfTypeIdentifier; var @@ -1328,6 +1462,29 @@ begin ScopeChanged; end; +function TDwarfInformationEntry.GoNamedChild(AName: String): Boolean; +var + EntryName: String; +begin + Result := False; + GoChild; + while HasValidScope do begin + if not ReadValue(DW_AT_name, EntryName) then begin + GoNext; + Continue; + end; + + if UpperCase(EntryName) = UpperCase(AName) then begin + // TODO: check DW_AT_start_scope; + DebugLn(['!!!! FOUND !!! ', dbgs(FScope, FCompUnit), DbgSName(Self)]); + Result := True; + exit; + end; + + GoNext; + end; +end; + constructor TDwarfInformationEntry.Create(ACompUnit: TDwarfCompilationUnit; AnInformationEntry: Pointer); begin @@ -1346,6 +1503,47 @@ begin ScopeChanged; end; +function TDwarfInformationEntry.FindNamedChild(AName: String): TDwarfInformationEntry; +var + ScopeEntryName: String; +begin + Result := nil; + if (not FScope.IsValid) and (FInformationEntry <> nil) then + if not SearchScope then + exit; + + Result := TDwarfInformationEntry.Create(FCompUnit, FScope); +// TODO: parent + if Result.GoNamedChild(AName) then + exit; + ReleaseRefAndNil(Result); +end; + +function TDwarfInformationEntry.FindChildByTag(ATag: Cardinal): TDwarfInformationEntry; +var + Scope: TDwarfScopeInfo; + EntryName: String; + AbbrList: TDwarfAbbrevList; + Abbr: TDwarfAbbrev; +begin + Result := nil; + if (not FScope.IsValid) and (FInformationEntry <> nil) then + if not SearchScope then + exit; + + Scope := FScope.Child; + while Scope.IsValid do begin + AbbrList := FCompUnit.FAbbrevList; + if AbbrList.FindLe128bFromPointer(Scope.Entry, Abbr) <> nil then begin + if Abbr.tag = ATag then begin + Result := TDwarfInformationEntry.Create(FCompUnit, Scope); + exit; + end; + end; + Scope.GoNext; + end; +end; + function TDwarfInformationEntry.HasAttrib(AnAttrib: Cardinal): boolean; var i: Integer; @@ -1523,9 +1721,9 @@ end; class function TDbgDwarfIdentifier.GetSubClass(ATag: Cardinal): TDbgDwarfIdentifierClass; begin case ATag of - DW_TAG_variable, DW_TAG_formal_parameter, DW_TAG_constant, DW_TAG_member: + DW_TAG_variable, DW_TAG_formal_parameter, DW_TAG_constant: Result := TDbgDwarfValueIdentifier; - + DW_TAG_member: Result := TDbgDwarfIdentifierMember; DW_TAG_base_type: Result := TDbgDwarfBaseIdentifierBase; DW_TAG_typedef: Result := TDbgDwarfTypeIdentifierDeclaration; DW_TAG_pointer_type: Result := TDbgDwarfTypeIdentifierPointer; @@ -1533,12 +1731,13 @@ begin DW_TAG_const_type, DW_TAG_volatile_type: Result := TDbgDwarfTypeIdentifierModifier; DW_TAG_reference_type, - DW_TAG_string_type, DW_TAG_array_type, DW_TAG_class_type, + DW_TAG_string_type, DW_TAG_array_type, + DW_TAG_enumeration_type, DW_TAG_subroutine_type, + DW_TAG_union_type, DW_TAG_ptr_to_member_type, + DW_TAG_set_type, DW_TAG_subrange_type, DW_TAG_file_type, + DW_TAG_thrown_type: Result := TDbgDwarfTypeIdentifier; DW_TAG_structure_type, - DW_TAG_enumeration_type, DW_TAG_subroutine_type, DW_TAG_union_type, - DW_TAG_ptr_to_member_type, DW_TAG_set_type, DW_TAG_subrange_type, DW_TAG_file_type, - DW_TAG_thrown_type: - Result := TDbgDwarfTypeIdentifier; + DW_TAG_class_type: Result := TDbgDwarfIdentifierStructure; else Result := TDbgDwarfIdentifier; @@ -2585,26 +2784,13 @@ begin while InfoEntry.HasValidScope do begin debugln(['TDbgDwarf.FindIdentifier Searching ', dbgs(InfoEntry.FScope, CU)]); StartScopeIdx := InfoEntry.ScopeIndex; - InfoEntry.GoChild; - while InfoEntry.HasValidScope do begin - if not InfoEntry.ReadValue(DW_AT_name, EntryName) then begin - InfoEntry.GoNext; - Continue; - end; - - if UpperCase(EntryName) = UpperCase(AName) then begin - // TODO: check DW_AT_start_scope; - Result := TDbgDwarfIdentifier.CreateSubClass(AName, InfoEntry); - //DebugLn(['!!!! FOUND !!! ', dbgs(InfoEntry.FScope, CU), DbgsDump(InfoEntry.FScope, CU) ]); - DebugLn(['!!!! FOUND !!! ', dbgs(InfoEntry.FScope, CU), DbgSName(Result)]); - break; - end; - - InfoEntry.GoNext; - end; - if Result <> nil then + if InfoEntry.GoNamedChild(AName) then begin + Result := TDbgDwarfIdentifier.CreateSubClass(AName, InfoEntry); + //DebugLn(['!!!! FOUND !!! ', dbgs(InfoEntry.FScope, CU), DbgsDump(InfoEntry.FScope, CU) ]); + DebugLn(['!!!! FOUND !!! ', dbgs(InfoEntry.FScope, CU), DbgSName(Result)]); break; + end; // Search parent(s) InfoEntry.ScopeIndex := StartScopeIdx; diff --git a/components/fpdebug/fppascalparser.pas b/components/fpdebug/fppascalparser.pas index 970062b77b..a29ac7a959 100644 --- a/components/fpdebug/fppascalparser.pas +++ b/components/fpdebug/fppascalparser.pas @@ -105,6 +105,7 @@ type protected procedure Init; virtual; procedure DoGetResultType(var AResultType: TFpPasExprType); virtual; + procedure InitResultTypeFromDbgInfo(var AResultType: TFpPasExprType; ADbgInfo: TDbgSymbol); Procedure ReplaceInParent(AReplacement: TFpPascalExpressionPart); procedure DoHandleEndOfExpression; virtual; @@ -238,6 +239,7 @@ type TFpPascalExpressionPartOperatorMakeRef = class(TFpPascalExpressionPartUnaryOperator) // ^TTYpe protected procedure Init; override; + function IsValidNextPart(APart: TFpPascalExpressionPart): Boolean; override; procedure DoGetResultType(var AResultType: TFpPasExprType); override; end; @@ -283,6 +285,8 @@ type TFpPascalExpressionPartOperatorMemberOf = class(TFpPascalExpressionPartBinaryOperator) // struct.member protected procedure Init; override; + function IsValidNextPart(APart: TFpPascalExpressionPart): Boolean; override; + procedure DoGetResultType(var AResultType: TFpPasExprType); override; end; implementation @@ -303,28 +307,8 @@ end; procedure TFpPascalExpressionPartIdentifer.DoGetResultType(var AResultType: TFpPasExprType); begin - FResultType.Kind := ptkInvalid; - FDbgType := FExpression.GetDbgTyeForIdentifier(GetText); - if (FDbgType = nil) then - exit; - - if (FDbgType is TDbgDwarfTypeIdentifier) then begin - AResultType.DbgType := TDbgDwarfTypeIdentifier(FDbgType); - AResultType.DbgType.AddReference; - FResultType.Kind := ptkTypeDbgType; - exit; - end; - - if FDbgType is TDbgDwarfValueIdentifier then begin - AResultType.DbgType := TDbgDwarfValueIdentifier(FDbgType).TypeInfo; - AResultType.DbgType.AddReference; - if AResultType.DbgType <> nil then - FResultType.Kind := ptkValueDbgType; - exit; - end; - - debugln(['TFpPascalExpressionPartIdentifer.DoGetResultType UNKNOWN: ', DbgSName(FDbgType)]); + InitResultTypeFromDbgInfo(AResultType, FDbgType); end; destructor TFpPascalExpressionPartIdentifer.Destroy; @@ -602,6 +586,32 @@ begin FResultType.Kind := ptkInvalid; end; +procedure TFpPascalExpressionPart.InitResultTypeFromDbgInfo(var AResultType: TFpPasExprType; + ADbgInfo: TDbgSymbol); +begin + AResultType.Kind := ptkInvalid; + if (ADbgInfo = nil) then + exit; + + if (ADbgInfo is TDbgDwarfTypeIdentifier) then begin + AResultType.DbgType := TDbgDwarfTypeIdentifier(ADbgInfo); + AResultType.DbgType.AddReference; + AResultType.Kind := ptkTypeDbgType; + exit; + end; + + if ADbgInfo is TDbgDwarfValueIdentifier then begin + AResultType.DbgType := TDbgDwarfValueIdentifier(ADbgInfo).TypeInfo; + AResultType.DbgType.AddReference; + if AResultType.DbgType <> nil then + AResultType.Kind := ptkValueDbgType; + exit; + end; + + debugln(['TFpPascalExpressionPartIdentifer.DoGetResultType UNKNOWN: ', DbgSName(ADbgInfo)]); + +end; + procedure TFpPascalExpressionPart.ReplaceInParent(AReplacement: TFpPascalExpressionPart); var i: Integer; @@ -977,6 +987,12 @@ begin inherited Init; end; +function TFpPascalExpressionPartOperatorMakeRef.IsValidNextPart(APart: TFpPascalExpressionPart): Boolean; +begin + Result := (inherited IsValidNextPart(APart)) and + (APart is TFpPascalExpressionPartIdentifer); +end; + procedure TFpPascalExpressionPartOperatorMakeRef.DoGetResultType(var AResultType: TFpPasExprType); begin AResultType.Kind := ptkInvalid; @@ -1076,5 +1092,30 @@ begin inherited Init; end; +function TFpPascalExpressionPartOperatorMemberOf.IsValidNextPart(APart: TFpPascalExpressionPart): Boolean; +begin + Result := (inherited IsValidNextPart(APart)) and + (APart is TFpPascalExpressionPartIdentifer); +end; + +procedure TFpPascalExpressionPartOperatorMemberOf.DoGetResultType(var AResultType: TFpPasExprType); +var + tmp: TFpPasExprType; + struct: TDbgDwarfIdentifierStructure; + member: TDbgDwarfIdentifierMember; +begin + AResultType.Kind := ptkInvalid; + if Count <> 2 then exit; + + tmp := Items[0].ResultType; + // Todo unit + if (tmp.Kind = ptkValueDbgType) and (tmp.DbgType.IsStructType) then begin + struct := tmp.DbgType.StructTypeInfo; + member := struct.MemberByName[Items[1].GetText]; + InitResultTypeFromDbgInfo(AResultType, member); + ReleaseRefAndNil(member); + end; +end; + end.