mirror of
https://gitlab.com/freepascal.org/lazarus/lazarus.git
synced 2025-05-01 18:23:43 +02:00
4770 lines
142 KiB
ObjectPascal
4770 lines
142 KiB
ObjectPascal
{
|
|
---------------------------------------------------------------------------
|
|
fpdbgdwarf.pas - Native Freepascal debugger - Dwarf symbol processing
|
|
---------------------------------------------------------------------------
|
|
|
|
This unit contains helper classes for handling and evaluating of debuggee data
|
|
described by DWARF debug symbols
|
|
|
|
---------------------------------------------------------------------------
|
|
|
|
@created(Mon Aug 1st WET 2006)
|
|
@lastmod($Date$)
|
|
@author(Marc Weustink <marc@@dommelstein.nl>)
|
|
@author(Martin Friebe)
|
|
|
|
***************************************************************************
|
|
* *
|
|
* This source is free software; you can redistribute it and/or modify *
|
|
* it under the terms of the GNU General Public License as published by *
|
|
* the Free Software Foundation; either version 2 of the License, or *
|
|
* (at your option) any later version. *
|
|
* *
|
|
* This code is distributed in the hope that it will be useful, but *
|
|
* WITHOUT ANY WARRANTY; without even the implied warranty of *
|
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU *
|
|
* General Public License for more details. *
|
|
* *
|
|
* A copy of the GNU General Public License is available on the World *
|
|
* Wide Web at <http://www.gnu.org/copyleft/gpl.html>. You can also *
|
|
* obtain it by writing to the Free Software Foundation, *
|
|
* Inc., 51 Franklin Street - Fifth Floor, Boston, MA 02110-1335, USA. *
|
|
* *
|
|
***************************************************************************
|
|
}
|
|
unit FpDbgDwarf;
|
|
|
|
{$mode objfpc}{$H+}
|
|
{off $INLINE OFF}
|
|
|
|
(* Notes:
|
|
|
|
* FpDbgDwarfValues and Context
|
|
The Values do not add a reference to the Context. Yet they require the Context.
|
|
It is the users responsibility to keep the context, as long as any value exists.
|
|
|
|
*)
|
|
|
|
interface
|
|
|
|
uses
|
|
Classes, SysUtils, types, math, FpDbgInfo, FpDbgDwarfDataClasses, FpdMemoryTools, FpErrorMessages,
|
|
FpDbgUtil, FpDbgDwarfConst, DbgIntfBaseTypes, LazUTF8, LazLoggerBase, LazClasses;
|
|
|
|
type
|
|
TFpDwarfInfo = FpDbgDwarfDataClasses.TFpDwarfInfo;
|
|
|
|
{ TFpDwarfDefaultSymbolClassMap }
|
|
|
|
TFpDwarfDefaultSymbolClassMap = class(TFpDwarfSymbolClassMap)
|
|
public
|
|
class function HandleCompUnit(ACU: TDwarfCompilationUnit): Boolean; override;
|
|
class function GetDwarfSymbolClass(ATag: Cardinal): TDbgDwarfSymbolBaseClass; override;
|
|
class function CreateContext(AThreadId, AStackFrame: Integer; AnAddress:
|
|
TDbgPtr; ASymbol: TFpDbgSymbol; ADwarf: TFpDwarfInfo): TFpDbgInfoContext; override;
|
|
class function CreateProcSymbol(ACompilationUnit: TDwarfCompilationUnit;
|
|
AInfo: PDwarfAddressInfo; AAddress: TDbgPtr): TDbgDwarfSymbolBase; override;
|
|
end;
|
|
|
|
{ TFpDwarfInfoAddressContext }
|
|
|
|
TFpDwarfInfoAddressContext = class(TFpDbgInfoContext)
|
|
private
|
|
FSymbol: TFpDbgSymbol;
|
|
FAddress: TDBGPtr;
|
|
FThreadId, FStackFrame: Integer;
|
|
FDwarf: TFpDwarfInfo;
|
|
FlastResult: TFpDbgValue;
|
|
protected
|
|
function GetSymbolAtAddress: TFpDbgSymbol; override;
|
|
function GetProcedureAtAddress: TFpDbgValue; override;
|
|
function GetAddress: TDbgPtr; override;
|
|
function GetThreadId: Integer; override;
|
|
function GetStackFrame: Integer; override;
|
|
function GetSizeOfAddress: Integer; override;
|
|
function GetMemManager: TFpDbgMemManager; override;
|
|
|
|
property Symbol: TFpDbgSymbol read FSymbol;
|
|
property Dwarf: TFpDwarfInfo read FDwarf;
|
|
property Address: TDBGPtr read FAddress write FAddress;
|
|
property ThreadId: Integer read FThreadId write FThreadId;
|
|
property StackFrame: Integer read FStackFrame write FStackFrame;
|
|
|
|
function ApplyContext(AVal: TFpDbgValue): TFpDbgValue; inline;
|
|
function SymbolToValue(ASym: TFpDbgSymbol): TFpDbgValue; inline;
|
|
procedure AddRefToVal(AVal: TFpDbgValue); inline;
|
|
function GetSelfParameter: TFpDbgValue; virtual;
|
|
|
|
function FindExportedSymbolInUnits(const AName: String; PNameUpper, PNameLower: PChar;
|
|
SkipCompUnit: TDwarfCompilationUnit; out ADbgValue: TFpDbgValue): Boolean; inline;
|
|
function FindSymbolInStructure(const AName: String; PNameUpper, PNameLower: PChar;
|
|
InfoEntry: TDwarfInformationEntry; out ADbgValue: TFpDbgValue): Boolean; inline;
|
|
// FindLocalSymbol: for the subroutine itself
|
|
function FindLocalSymbol(const AName: String; PNameUpper, PNameLower: PChar;
|
|
InfoEntry: TDwarfInformationEntry; out ADbgValue: TFpDbgValue): Boolean; virtual;
|
|
public
|
|
constructor Create(AThreadId, AStackFrame: Integer; AnAddress: TDbgPtr; ASymbol: TFpDbgSymbol; ADwarf: TFpDwarfInfo);
|
|
destructor Destroy; override;
|
|
function FindSymbol(const AName: String): TFpDbgValue; override;
|
|
end;
|
|
|
|
TFpDwarfSymbol = class;
|
|
TFpDwarfSymbolType = class;
|
|
TFpDwarfSymbolValue = class;
|
|
TFpDwarfSymbolValueClass = class of TFpDwarfSymbolValue;
|
|
TFpDwarfSymbolTypeClass = class of TFpDwarfSymbolType;
|
|
|
|
{%region Value objects }
|
|
|
|
{ TFpDwarfValueBase }
|
|
|
|
TFpDwarfValueBase = class(TFpDbgValue)
|
|
private
|
|
FContext: TFpDbgInfoContext;
|
|
public
|
|
property Context: TFpDbgInfoContext read FContext;
|
|
end;
|
|
|
|
{ TFpDwarfValueTypeDefinition }
|
|
|
|
TFpDwarfValueTypeDefinition = class(TFpDwarfValueBase)
|
|
private
|
|
FSymbol: TFpDbgSymbol; // stType
|
|
protected
|
|
function GetKind: TDbgSymbolKind; override;
|
|
function GetDbgSymbol: TFpDbgSymbol; override;
|
|
public
|
|
constructor Create(ASymbol: TFpDbgSymbol); // Only for stType
|
|
destructor Destroy; override;
|
|
function GetTypeCastedValue(ADataVal: TFpDbgValue): TFpDbgValue; override;
|
|
end;
|
|
|
|
{ TFpDwarfValue }
|
|
|
|
TFpDwarfValue = class(TFpDwarfValueBase)
|
|
private
|
|
FOwner: TFpDwarfSymbolType; // the creator, usually the type
|
|
FValueSymbol: TFpDwarfSymbolValue;
|
|
FTypeCastTargetType: TFpDwarfSymbolType;
|
|
FTypeCastSourceValue: TFpDbgValue;
|
|
|
|
FDataAddressCache: array of TFpDbgMemLocation;
|
|
FStructureValue: TFpDwarfValue;
|
|
FLastMember: TFpDwarfValue;
|
|
FLastError: TFpError;
|
|
function GetDataAddressCache(AIndex: Integer): TFpDbgMemLocation;
|
|
function MemManager: TFpDbgMemManager; inline;
|
|
function AddressSize: Byte; inline;
|
|
procedure SetDataAddressCache(AIndex: Integer; AValue: TFpDbgMemLocation);
|
|
procedure SetStructureValue(AValue: TFpDwarfValue);
|
|
protected
|
|
procedure DoReferenceAdded; override;
|
|
procedure DoReferenceReleased; override;
|
|
procedure CircleBackRefActiveChanged(NewActive: Boolean); override;
|
|
procedure SetLastMember(ALastMember: TFpDwarfValue);
|
|
function GetLastError: TFpError; override;
|
|
|
|
// Address of the symbol (not followed any type deref, or location)
|
|
function GetAddress: TFpDbgMemLocation; override;
|
|
function OrdOrAddress: TFpDbgMemLocation;
|
|
// Address of the data (followed type deref, location, ...)
|
|
function DataAddr: TFpDbgMemLocation;
|
|
function OrdOrDataAddr: TFpDbgMemLocation;
|
|
function GetDwarfDataAddress(out AnAddress: TFpDbgMemLocation; ATargetType: TFpDwarfSymbolType = nil): Boolean;
|
|
function GetStructureDwarfDataAddress(out AnAddress: TFpDbgMemLocation;
|
|
ATargetType: TFpDwarfSymbolType = nil): Boolean;
|
|
function HasDwarfDataAddress: Boolean; // TODO: is this just HasAddress?
|
|
|
|
procedure Reset; virtual; // keeps lastmember and structureninfo
|
|
function GetFieldFlags: TFpDbgValueFieldFlags; override;
|
|
function HasTypeCastInfo: Boolean;
|
|
function IsValidTypeCast: Boolean; virtual;
|
|
function GetKind: TDbgSymbolKind; override;
|
|
function GetMemberCount: Integer; override;
|
|
function GetMemberByName(AIndex: String): TFpDbgValue; override;
|
|
function GetMember(AIndex: Int64): TFpDbgValue; override;
|
|
function GetDbgSymbol: TFpDbgSymbol; override;
|
|
function GetTypeInfo: TFpDbgSymbol; override;
|
|
function GetContextTypeInfo: TFpDbgSymbol; override;
|
|
public
|
|
constructor Create(AOwner: TFpDwarfSymbolType);
|
|
destructor Destroy; override;
|
|
procedure SetValueSymbol(AValueSymbol: TFpDwarfSymbolValue);
|
|
function SetTypeCastInfo(AStructure: TFpDwarfSymbolType;
|
|
ASource: TFpDbgValue): Boolean; // Used for Typecast
|
|
// StructureValue: Any Value returned via GetMember points to its structure
|
|
property StructureValue: TFpDwarfValue read FStructureValue write SetStructureValue;
|
|
// DataAddressCache[0]: ValueAddress // DataAddressCache[1..n]: DataAddress
|
|
property DataAddressCache[AIndex: Integer]: TFpDbgMemLocation read GetDataAddressCache write SetDataAddressCache;
|
|
end;
|
|
|
|
{ TFpDwarfValueSized }
|
|
|
|
TFpDwarfValueSized = class(TFpDwarfValue)
|
|
private
|
|
FSize: Integer;
|
|
protected
|
|
function CanUseTypeCastAddress: Boolean;
|
|
function GetFieldFlags: TFpDbgValueFieldFlags; override;
|
|
function GetSize: Integer; override;
|
|
public
|
|
constructor Create(AOwner: TFpDwarfSymbolType; ASize: Integer);
|
|
end;
|
|
|
|
{ TFpDwarfValueNumeric }
|
|
|
|
TFpDwarfValueNumeric = class(TFpDwarfValueSized)
|
|
protected
|
|
FEvaluated: set of (doneUInt, doneInt, doneAddr, doneFloat);
|
|
protected
|
|
procedure Reset; override;
|
|
function GetFieldFlags: TFpDbgValueFieldFlags; override; // svfOrdinal
|
|
function IsValidTypeCast: Boolean; override;
|
|
public
|
|
constructor Create(AOwner: TFpDwarfSymbolType; ASize: Integer);
|
|
end;
|
|
|
|
{ TFpDwarfValueInteger }
|
|
|
|
TFpDwarfValueInteger = class(TFpDwarfValueNumeric)
|
|
private
|
|
FIntValue: Int64;
|
|
protected
|
|
function GetFieldFlags: TFpDbgValueFieldFlags; override;
|
|
function GetAsCardinal: QWord; override;
|
|
function GetAsInteger: Int64; override;
|
|
end;
|
|
|
|
{ TFpDwarfValueCardinal }
|
|
|
|
TFpDwarfValueCardinal = class(TFpDwarfValueNumeric)
|
|
private
|
|
FValue: QWord;
|
|
protected
|
|
function GetAsCardinal: QWord; override;
|
|
function GetFieldFlags: TFpDbgValueFieldFlags; override;
|
|
end;
|
|
|
|
{ TFpDwarfValueFloat }
|
|
|
|
TFpDwarfValueFloat = class(TFpDwarfValueNumeric) // TDbgDwarfSymbolValue
|
|
// TODO: typecasts to int should convert
|
|
private
|
|
FValue: Extended;
|
|
protected
|
|
function GetFieldFlags: TFpDbgValueFieldFlags; override;
|
|
function GetAsFloat: Extended; override;
|
|
end;
|
|
|
|
{ TFpDwarfValueBoolean }
|
|
|
|
TFpDwarfValueBoolean = class(TFpDwarfValueCardinal)
|
|
protected
|
|
function GetFieldFlags: TFpDbgValueFieldFlags; override;
|
|
function GetAsBool: Boolean; override;
|
|
end;
|
|
|
|
{ TFpDwarfValueChar }
|
|
|
|
TFpDwarfValueChar = class(TFpDwarfValueCardinal)
|
|
protected
|
|
// returns single char(byte) / widechar
|
|
function GetFieldFlags: TFpDbgValueFieldFlags; override;
|
|
function GetAsString: AnsiString; override;
|
|
function GetAsWideString: WideString; override;
|
|
end;
|
|
|
|
{ TFpDwarfValuePointer }
|
|
|
|
TFpDwarfValuePointer = class(TFpDwarfValueNumeric)
|
|
private
|
|
FLastAddrMember: TFpDbgValue;
|
|
FPointetToAddr: TFpDbgMemLocation;
|
|
protected
|
|
function GetAsCardinal: QWord; override;
|
|
function GetFieldFlags: TFpDbgValueFieldFlags; override;
|
|
function GetDataAddress: TFpDbgMemLocation; override;
|
|
function GetAsString: AnsiString; override;
|
|
function GetMember(AIndex: Int64): TFpDbgValue; override;
|
|
public
|
|
destructor Destroy; override;
|
|
end;
|
|
|
|
{ TFpDwarfValueEnum }
|
|
|
|
TFpDwarfValueEnum = class(TFpDwarfValueNumeric)
|
|
private
|
|
FValue: QWord;
|
|
FMemberIndex: Integer;
|
|
FMemberValueDone: Boolean;
|
|
procedure InitMemberIndex;
|
|
protected
|
|
procedure Reset; override;
|
|
//function IsValidTypeCast: Boolean; override;
|
|
function GetFieldFlags: TFpDbgValueFieldFlags; override;
|
|
function GetAsCardinal: QWord; override;
|
|
function GetAsString: AnsiString; override;
|
|
// Has exactly 0 (if the ordinal value is out of range) or 1 member (the current value's enum)
|
|
function GetMemberCount: Integer; override;
|
|
function GetMember({%H-}AIndex: Int64): TFpDbgValue; override;
|
|
end;
|
|
|
|
{ TFpDwarfValueEnumMember }
|
|
|
|
TFpDwarfValueEnumMember = class(TFpDwarfValue)
|
|
private
|
|
FOwnerVal: TFpDwarfSymbolValue;
|
|
protected
|
|
function GetFieldFlags: TFpDbgValueFieldFlags; override;
|
|
function GetAsCardinal: QWord; override;
|
|
function GetAsString: AnsiString; override;
|
|
function IsValidTypeCast: Boolean; override;
|
|
public
|
|
constructor Create(AOwner: TFpDwarfSymbolValue);
|
|
end;
|
|
|
|
{ TFpDwarfValueConstNumber }
|
|
|
|
TFpDwarfValueConstNumber = class(TFpDbgValueConstNumber)
|
|
protected
|
|
procedure Update(AValue: QWord; ASigned: Boolean);
|
|
end;
|
|
|
|
{ TFpDwarfValueSet }
|
|
|
|
TFpDwarfValueSet = class(TFpDwarfValueSized)
|
|
private
|
|
FMem: array of Byte;
|
|
FMemberCount: Integer;
|
|
FMemberMap: array of Integer;
|
|
FNumValue: TFpDwarfValueConstNumber;
|
|
FTypedNumValue: TFpDbgValue;
|
|
procedure InitMap;
|
|
protected
|
|
procedure Reset; override;
|
|
function GetFieldFlags: TFpDbgValueFieldFlags; override;
|
|
function GetMemberCount: Integer; override;
|
|
function GetMember(AIndex: Int64): TFpDbgValue; override;
|
|
function GetAsCardinal: QWord; override; // only up to qmord
|
|
function IsValidTypeCast: Boolean; override;
|
|
public
|
|
destructor Destroy; override;
|
|
end;
|
|
|
|
{ TFpDwarfValueStruct }
|
|
|
|
TFpDwarfValueStruct = class(TFpDwarfValue)
|
|
private
|
|
FDataAddress: TFpDbgMemLocation;
|
|
FDataAddressDone: Boolean;
|
|
protected
|
|
procedure Reset; override;
|
|
function GetFieldFlags: TFpDbgValueFieldFlags; override;
|
|
function GetAsCardinal: QWord; override;
|
|
function GetDataAddress: TFpDbgMemLocation; override;
|
|
function GetDataSize: Integer; override;
|
|
function GetSize: Integer; override;
|
|
end;
|
|
|
|
{ TFpDwarfValueStructTypeCast }
|
|
|
|
TFpDwarfValueStructTypeCast = class(TFpDwarfValue)
|
|
private
|
|
FMembers: TFpDbgCircularRefCntObjList;
|
|
FDataAddress: TFpDbgMemLocation;
|
|
FDataAddressDone: Boolean;
|
|
protected
|
|
procedure Reset; override;
|
|
function GetFieldFlags: TFpDbgValueFieldFlags; override;
|
|
function GetKind: TDbgSymbolKind; override;
|
|
function GetAsCardinal: QWord; override;
|
|
function GetSize: Integer; override;
|
|
function GetDataSize: Integer; override;
|
|
function GetDataAddress: TFpDbgMemLocation; override;
|
|
function IsValidTypeCast: Boolean; override;
|
|
public
|
|
destructor Destroy; override;
|
|
function GetMemberByName(AIndex: String): TFpDbgValue; override;
|
|
function GetMember(AIndex: Int64): TFpDbgValue; override;
|
|
function GetMemberCount: Integer; override;
|
|
end;
|
|
|
|
{ TFpDwarfValueConstAddress }
|
|
|
|
TFpDwarfValueConstAddress = class(TFpDbgValueConstAddress)
|
|
protected
|
|
procedure Update(AnAddress: TFpDbgMemLocation);
|
|
end;
|
|
|
|
{ TFpDwarfValueArray }
|
|
|
|
TFpDwarfValueArray = class(TFpDwarfValue)
|
|
private
|
|
FAddrObj: TFpDwarfValueConstAddress;
|
|
protected
|
|
function GetFieldFlags: TFpDbgValueFieldFlags; override;
|
|
function GetKind: TDbgSymbolKind; override;
|
|
function GetAsCardinal: QWord; override;
|
|
function GetDataAddress: TFpDbgMemLocation; override;
|
|
function GetMember(AIndex: Int64): TFpDbgValue; override;
|
|
function GetMemberEx(AIndex: array of Int64): TFpDbgValue; override;
|
|
function GetMemberCount: Integer; override;
|
|
function GetMemberCountEx(AIndex: array of Int64): Integer; override;
|
|
function GetIndexType(AIndex: Integer): TFpDbgSymbol; override;
|
|
function GetIndexTypeCount: Integer; override;
|
|
function IsValidTypeCast: Boolean; override;
|
|
public
|
|
destructor Destroy; override;
|
|
end;
|
|
{%endregion Value objects }
|
|
|
|
{%region Symbol objects }
|
|
|
|
TInitLocParserData = record
|
|
(* DW_AT_data_member_location: Is always pushed on stack
|
|
DW_AT_data_location: Is avalibale for DW_OP_push_object_address
|
|
*)
|
|
ObjectDataAddress: TFpDbgMemLocation;
|
|
ObjectDataAddrPush: Boolean; // always push ObjectDataAddress on stack: DW_AT_data_member_location
|
|
end;
|
|
PInitLocParserData = ^TInitLocParserData;
|
|
|
|
{ TDbgDwarfIdentifier }
|
|
|
|
{ TFpDwarfSymbol }
|
|
|
|
TFpDwarfSymbol = class(TDbgDwarfSymbolBase)
|
|
private
|
|
FNestedTypeInfo: TFpDwarfSymbolType;
|
|
FParentTypeInfo: TFpDwarfSymbol;
|
|
FDwarfReadFlags: set of (didtNameRead, didtTypeRead, didtArtificialRead, didtIsArtifical);
|
|
function GetNestedTypeInfo: TFpDwarfSymbolType;
|
|
protected
|
|
(* There will be a circular reference between parenttype and self
|
|
"self" will only set its reference to parenttype, if self has other references. *)
|
|
procedure DoReferenceAdded; override;
|
|
procedure DoReferenceReleased; override;
|
|
procedure CircleBackRefActiveChanged(ANewActive: Boolean); override;
|
|
procedure SetParentTypeInfo(AValue: TFpDwarfSymbol); virtual;
|
|
|
|
function DoGetNestedTypeInfo: TFpDwarfSymbolType; virtual;
|
|
function ReadMemberVisibility(out AMemberVisibility: TDbgSymbolMemberVisibility): Boolean;
|
|
function IsArtificial: Boolean; // usud by formal param and subprogram
|
|
procedure NameNeeded; override;
|
|
procedure TypeInfoNeeded; override;
|
|
property NestedTypeInfo: TFpDwarfSymbolType read GetNestedTypeInfo;
|
|
|
|
// OwnerTypeInfo: reverse of "NestedTypeInfo" (variable that is of this type)
|
|
// property OwnerTypeInfo: TDbgDwarfIdentifier read FOwnerTypeInfo; // write SetOwnerTypeInfo;
|
|
// ParentTypeInfo: funtion for local var / class for member
|
|
property ParentTypeInfo: TFpDwarfSymbol read FParentTypeInfo write SetParentTypeInfo;
|
|
|
|
function DataSize: Integer; virtual;
|
|
protected
|
|
function InitLocationParser(const {%H-}ALocationParser: TDwarfLocationExpression;
|
|
AnInitLocParserData: PInitLocParserData = nil): Boolean; virtual;
|
|
function LocationFromTag(ATag: Cardinal; AValueObj: TFpDwarfValue;
|
|
var AnAddress: TFpDbgMemLocation; // kept, if tag does not exist
|
|
AnInitLocParserData: PInitLocParserData = nil;
|
|
AnInformationEntry: TDwarfInformationEntry = nil;
|
|
ASucessOnMissingTag: Boolean = False
|
|
): Boolean;
|
|
// GetDataAddress: data of a class, or string
|
|
function GetDataAddress(AValueObj: TFpDwarfValue; var AnAddress: TFpDbgMemLocation;
|
|
ATargetType: TFpDwarfSymbolType; ATargetCacheIndex: Integer): Boolean;
|
|
function GetDataAddressNext(AValueObj: TFpDwarfValue; var AnAddress: TFpDbgMemLocation;
|
|
ATargetType: TFpDwarfSymbolType; ATargetCacheIndex: Integer): Boolean; virtual;
|
|
function HasAddress: Boolean; virtual;
|
|
|
|
procedure Init; override;
|
|
public
|
|
class function CreateSubClass(AName: String; AnInformationEntry: TDwarfInformationEntry): TFpDwarfSymbol;
|
|
destructor Destroy; override;
|
|
function StartScope: TDbgPtr; // return 0, if none. 0 includes all anyway
|
|
end;
|
|
|
|
{ TFpDwarfSymbolValue }
|
|
|
|
TFpDwarfSymbolValue = class(TFpDwarfSymbol) // var, const, member, ...
|
|
protected
|
|
FValueObject: TFpDwarfValue;
|
|
FMembers: TFpDbgCircularRefCntObjList;
|
|
|
|
function GetValueAddress({%H-}AValueObj: TFpDwarfValue;{%H-} out AnAddress: TFpDbgMemLocation): Boolean; virtual;
|
|
function GetValueDataAddress(AValueObj: TFpDwarfValue; out AnAddress: TFpDbgMemLocation;
|
|
ATargetType: TFpDwarfSymbolType = nil): Boolean;
|
|
procedure KindNeeded; override;
|
|
procedure MemberVisibilityNeeded; override;
|
|
function GetMember(AIndex: Int64): TFpDbgSymbol; override;
|
|
function GetMemberByName(AIndex: String): TFpDbgSymbol; override;
|
|
function GetMemberCount: Integer; override;
|
|
|
|
procedure Init; override;
|
|
public
|
|
destructor Destroy; override;
|
|
class function CreateValueSubClass(AName: String; AnInformationEntry: TDwarfInformationEntry): TFpDwarfSymbolValue;
|
|
end;
|
|
|
|
{ TFpDwarfSymbolValueWithLocation }
|
|
|
|
TFpDwarfSymbolValueWithLocation = class(TFpDwarfSymbolValue)
|
|
private
|
|
procedure FrameBaseNeeded(ASender: TObject); // Sender = TDwarfLocationExpression
|
|
protected
|
|
function GetValueObject: TFpDbgValue; override;
|
|
function InitLocationParser(const ALocationParser: TDwarfLocationExpression;
|
|
AnInitLocParserData: PInitLocParserData): Boolean; override;
|
|
end;
|
|
|
|
{ TFpDwarfSymbolType }
|
|
|
|
(* Types and allowed tags in dwarf 2
|
|
|
|
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
|
|
|
|
DW_TAG_base_type
|
|
DW_AT_encoding Y
|
|
DW_AT_bit_offset Y
|
|
DW_AT_bit_size Y
|
|
|
|
DW_TAG_base_type
|
|
| DW_TAG_typedef
|
|
| | DW_TAG_string_type
|
|
| | | DW_TAG_array_type
|
|
| | | |
|
|
| | | | DW_TAG_class_type
|
|
| | | | | DW_TAG_structure_type
|
|
| | | | | |
|
|
| | | | | | DW_TAG_enumeration_type
|
|
| | | | | | | DW_TAG_set_type
|
|
| | | | | | | | DW_TAG_enumerator
|
|
| | | | | | | | | DW_TAG_subrange_type
|
|
DW_AT_name Y Y Y Y Y Y Y Y Y Y
|
|
DW_AT_sibling Y Y Y Y Y Y Y Y Y Y
|
|
DECL Y Y Y Y Y Y Y Y Y
|
|
DW_AT_byte_size Y Y Y Y Y Y Y Y
|
|
DW_AT_abstract_origin Y Y Y Y Y Y Y Y
|
|
DW_AT_accessibility Y Y Y Y Y Y Y Y
|
|
DW_AT_declaration Y Y Y Y Y Y Y Y
|
|
DW_AT_start_scope Y Y Y Y Y Y Y
|
|
DW_AT_visibility Y Y Y Y Y Y Y Y
|
|
DW_AT_type Y Y Y Y
|
|
DW_AT_segment Y DW_TAG_string_type
|
|
DW_AT_string_length Y
|
|
DW_AT_ordering Y DW_TAG_array_type
|
|
DW_AT_stride_size Y
|
|
DW_AT_const_value Y DW_TAG_enumerator
|
|
DW_AT_count Y DW_TAG_subrange_type
|
|
DW_AT_lower_bound Y
|
|
DW_AT_upper_bound Y
|
|
|
|
DW_TAG_pointer_type
|
|
| DW_TAG_reference_type
|
|
| | DW_TAG_packed_type
|
|
| | | DW_TAG_const_type
|
|
| | | | DW_TAG_volatile_type
|
|
DW_AT_address_class Y Y
|
|
DW_AT_sibling Y Y Y Y Y
|
|
DW_AT_type Y Y Y Y Y
|
|
|
|
DECL = DW_AT_decl_column, DW_AT_decl_file, DW_AT_decl_line
|
|
*)
|
|
|
|
TFpDwarfSymbolType = class(TFpDwarfSymbol)
|
|
protected
|
|
procedure Init; override;
|
|
procedure MemberVisibilityNeeded; override;
|
|
procedure SizeNeeded; override;
|
|
function GetTypedValueObject({%H-}ATypeCast: Boolean): TFpDwarfValue; virtual; // returns refcount=1 for caller, no cached copy kept
|
|
public
|
|
class function CreateTypeSubClass(AName: String; AnInformationEntry: TDwarfInformationEntry): TFpDwarfSymbolType;
|
|
function TypeCastValue(AValue: TFpDbgValue): TFpDbgValue; override;
|
|
// TODO: flag bounds as cardinal if needed
|
|
function GetValueBounds({%H-}AValueObj: TFpDwarfValue; out ALowBound, AHighBound: Int64): Boolean; virtual;
|
|
end;
|
|
|
|
{ TFpDwarfSymbolTypeBasic }
|
|
|
|
TFpDwarfSymbolTypeBasic = class(TFpDwarfSymbolType)
|
|
//function DoGetNestedTypeInfo: TFpDwarfSymbolType; // return nil
|
|
protected
|
|
procedure KindNeeded; override;
|
|
procedure TypeInfoNeeded; override;
|
|
function GetTypedValueObject({%H-}ATypeCast: Boolean): TFpDwarfValue; override;
|
|
function GetHasBounds: Boolean; override;
|
|
function GetOrdHighBound: Int64; override;
|
|
function GetOrdLowBound: Int64; override;
|
|
end;
|
|
|
|
{ TFpDwarfSymbolTypeModifier }
|
|
|
|
TFpDwarfSymbolTypeModifier = class(TFpDwarfSymbolType)
|
|
protected
|
|
procedure TypeInfoNeeded; override;
|
|
procedure ForwardToSymbolNeeded; override;
|
|
function GetTypedValueObject(ATypeCast: Boolean): TFpDwarfValue; override;
|
|
end;
|
|
|
|
{ TFpDwarfSymbolTypeRef }
|
|
|
|
TFpDwarfSymbolTypeRef = class(TFpDwarfSymbolTypeModifier)
|
|
protected
|
|
function GetFlags: TDbgSymbolFlags; override;
|
|
function GetDataAddressNext(AValueObj: TFpDwarfValue; var AnAddress: TFpDbgMemLocation;
|
|
ATargetType: TFpDwarfSymbolType; ATargetCacheIndex: Integer): Boolean; override;
|
|
end;
|
|
|
|
{ TFpDwarfSymbolTypeDeclaration }
|
|
|
|
TFpDwarfSymbolTypeDeclaration = class(TFpDwarfSymbolTypeModifier)
|
|
protected
|
|
// fpc encodes classes as pointer, not ref (so Obj1 = obj2 compares the pointers)
|
|
// typedef > pointer > srtuct
|
|
// while a pointer to class/object: pointer > typedef > ....
|
|
function DoGetNestedTypeInfo: TFpDwarfSymbolType; override;
|
|
end;
|
|
|
|
{ TFpDwarfSymbolTypeSubRange }
|
|
TFpDwarfSubRangeBoundReadState = (rfNotRead, rfNotFound, rfConst, rfValue);
|
|
|
|
TFpDwarfSymbolTypeSubRange = class(TFpDwarfSymbolTypeModifier)
|
|
// TODO not a modifier, maybe have a forwarder base class
|
|
private
|
|
FLowBoundConst: Int64;
|
|
FLowBoundValue: TFpDwarfSymbolValue;
|
|
FLowBoundState: TFpDwarfSubRangeBoundReadState;
|
|
FHighBoundConst: Int64;
|
|
FHighBoundValue: TFpDwarfSymbolValue;
|
|
FHighBoundState: TFpDwarfSubRangeBoundReadState;
|
|
FCountConst: Int64;
|
|
FCountValue: TFpDwarfSymbolValue;
|
|
FCountState: TFpDwarfSubRangeBoundReadState;
|
|
FLowEnumIdx, FHighEnumIdx: Integer;
|
|
FEnumIdxValid: Boolean;
|
|
procedure InitEnumIdx;
|
|
procedure ReadBounds(AValueObj: TFpDwarfValue);
|
|
protected
|
|
function DoGetNestedTypeInfo: TFpDwarfSymbolType;override;
|
|
function GetHasBounds: Boolean; override;
|
|
function GetOrdHighBound: Int64; override;
|
|
function GetOrdLowBound: Int64; override;
|
|
|
|
procedure NameNeeded; override;
|
|
procedure KindNeeded; override;
|
|
procedure SizeNeeded; override;
|
|
function GetMember(AIndex: Int64): TFpDbgSymbol; override;
|
|
function GetMemberCount: Integer; override;
|
|
function GetFlags: TDbgSymbolFlags; override;
|
|
procedure Init; override;
|
|
public
|
|
function GetValueBounds(AValueObj: TFpDwarfValue; out ALowBound,
|
|
AHighBound: Int64): Boolean; override;
|
|
end;
|
|
|
|
{ TFpDwarfSymbolTypePointer }
|
|
|
|
TFpDwarfSymbolTypePointer = class(TFpDwarfSymbolType)
|
|
private
|
|
FIsInternalPointer: Boolean;
|
|
function GetIsInternalPointer: Boolean; inline;
|
|
function IsInternalDynArrayPointer: Boolean; inline;
|
|
protected
|
|
procedure TypeInfoNeeded; override;
|
|
procedure KindNeeded; override;
|
|
procedure SizeNeeded; override;
|
|
procedure ForwardToSymbolNeeded; override;
|
|
function GetDataAddressNext(AValueObj: TFpDwarfValue; var AnAddress: TFpDbgMemLocation;
|
|
ATargetType: TFpDwarfSymbolType; ATargetCacheIndex: Integer): Boolean; override;
|
|
function GetTypedValueObject(ATypeCast: Boolean): TFpDwarfValue; override;
|
|
function DataSize: Integer; override;
|
|
public
|
|
property IsInternalPointer: Boolean read GetIsInternalPointer write FIsInternalPointer; // Class (also DynArray, but DynArray is handled without this)
|
|
end;
|
|
|
|
{ TFpDwarfSymbolValueEnumMember }
|
|
|
|
TFpDwarfSymbolValueEnumMember = class(TFpDwarfSymbolValue)
|
|
FOrdinalValue: Int64;
|
|
FOrdinalValueRead, FHasOrdinalValue: Boolean;
|
|
procedure ReadOrdinalValue;
|
|
protected
|
|
procedure KindNeeded; override;
|
|
function GetHasOrdinalValue: Boolean; override;
|
|
function GetOrdinalValue: Int64; override;
|
|
procedure Init; override;
|
|
function GetValueObject: TFpDbgValue; override;
|
|
end;
|
|
|
|
|
|
{ TFpDwarfSymbolTypeEnum }
|
|
|
|
TFpDwarfSymbolTypeEnum = class(TFpDwarfSymbolType)
|
|
private
|
|
FMembers: TFpDbgCircularRefCntObjList;
|
|
procedure CreateMembers;
|
|
protected
|
|
function GetTypedValueObject({%H-}ATypeCast: Boolean): TFpDwarfValue; override;
|
|
procedure KindNeeded; override;
|
|
function GetMember(AIndex: Int64): TFpDbgSymbol; override;
|
|
function GetMemberByName(AIndex: String): TFpDbgSymbol; override;
|
|
function GetMemberCount: Integer; override;
|
|
|
|
function GetHasBounds: Boolean; override;
|
|
function GetOrdHighBound: Int64; override;
|
|
function GetOrdLowBound: Int64; override;
|
|
public
|
|
destructor Destroy; override;
|
|
end;
|
|
|
|
|
|
{ TFpDwarfSymbolTypeSet }
|
|
|
|
TFpDwarfSymbolTypeSet = class(TFpDwarfSymbolType)
|
|
protected
|
|
procedure KindNeeded; override;
|
|
function GetTypedValueObject({%H-}ATypeCast: Boolean): TFpDwarfValue; override;
|
|
function GetMemberCount: Integer; override;
|
|
function GetMember(AIndex: Int64): TFpDbgSymbol; override;
|
|
end;
|
|
|
|
(*
|
|
If not specified
|
|
.NestedTypeInfo --> copy of TypeInfo
|
|
.ParentTypeInfo --> nil
|
|
|
|
ParentTypeInfo: has a weak RefCount (only AddRef, if self has other refs)
|
|
|
|
|
|
AnObject = TFpDwarfSymbolValueVariable
|
|
|-- .TypeInfo --> TBar = TFpDwarfSymbolTypeStructure [*1]
|
|
|-- .ParentTypeInfo --> may point to subroutine, if param or local var // TODO
|
|
|
|
TBar = TFpDwarfSymbolTypeStructure
|
|
|-- .TypeInfo --> TBarBase = TFpDwarfSymbolTypeStructure
|
|
|
|
TBarBase = TFpDwarfSymbolTypeStructure
|
|
|-- .TypeInfo --> TOBject = TFpDwarfSymbolTypeStructure
|
|
|
|
TObject = TFpDwarfSymbolTypeStructure
|
|
|-- .TypeInfo --> nil
|
|
|
|
|
|
FField = TFpDwarfSymbolValueMember (declared in TBarBase)
|
|
|-- .TypeInfo --> Integer = TFpDwarfSymbolTypeBasic [*1]
|
|
|-- .ParentTypeInfo --> TBarBase
|
|
|
|
[*1] May have TFpDwarfSymbolTypeDeclaration or others
|
|
*)
|
|
|
|
{ TFpDwarfSymbolValueMember }
|
|
|
|
TFpDwarfSymbolValueMember = class(TFpDwarfSymbolValueWithLocation)
|
|
protected
|
|
function GetValueAddress(AValueObj: TFpDwarfValue; out AnAddress: TFpDbgMemLocation): Boolean; override;
|
|
function HasAddress: Boolean; override;
|
|
end;
|
|
|
|
{ TFpDwarfSymbolTypeStructure }
|
|
|
|
TFpDwarfSymbolTypeStructure = class(TFpDwarfSymbolType)
|
|
// record or class
|
|
private
|
|
FMembers: TFpDbgCircularRefCntObjList;
|
|
FLastChildByName: TFpDwarfSymbol;
|
|
FInheritanceInfo: TDwarfInformationEntry;
|
|
procedure CreateMembers;
|
|
procedure InitInheritanceInfo; inline;
|
|
protected
|
|
function DoGetNestedTypeInfo: TFpDwarfSymbolType; override;
|
|
procedure KindNeeded; override;
|
|
function GetTypedValueObject(ATypeCast: Boolean): TFpDwarfValue; override;
|
|
|
|
// GetMember, if AIndex > Count then parent
|
|
function GetMember(AIndex: Int64): TFpDbgSymbol; override;
|
|
function GetMemberByName(AIndex: String): TFpDbgSymbol; override;
|
|
function GetMemberCount: Integer; override;
|
|
|
|
function GetDataAddressNext(AValueObj: TFpDwarfValue; var AnAddress: TFpDbgMemLocation;
|
|
ATargetType: TFpDwarfSymbolType; ATargetCacheIndex: Integer): Boolean; override;
|
|
public
|
|
destructor Destroy; override;
|
|
end;
|
|
|
|
{ TFpDwarfSymbolTypeArray }
|
|
|
|
TFpDwarfSymbolTypeArray = class(TFpDwarfSymbolType)
|
|
private
|
|
FMembers: TFpDbgCircularRefCntObjList;
|
|
FRowMajor: Boolean;
|
|
FStrideInBits: Int64;
|
|
FDwarfArrayReadFlags: set of (didtStrideRead, didtOrdering);
|
|
procedure CreateMembers;
|
|
procedure ReadStride;
|
|
procedure ReadOrdering;
|
|
protected
|
|
procedure KindNeeded; override;
|
|
function GetTypedValueObject({%H-}ATypeCast: Boolean): TFpDwarfValue; override;
|
|
|
|
function GetFlags: TDbgSymbolFlags; override;
|
|
// GetMember: returns the TYPE/range of each index. NOT the data
|
|
function GetMember(AIndex: Int64): TFpDbgSymbol; override;
|
|
function GetMemberByName({%H-}AIndex: String): TFpDbgSymbol; override;
|
|
function GetMemberCount: Integer; override;
|
|
function GetMemberAddress(AValObject: TFpDwarfValue; AIndex: Array of Int64): TFpDbgMemLocation;
|
|
public
|
|
destructor Destroy; override;
|
|
end;
|
|
|
|
{ TFpDwarfSymbolValueProc }
|
|
|
|
TFpDwarfSymbolValueProc = class(TFpDwarfSymbolValue)
|
|
private
|
|
//FCU: TDwarfCompilationUnit;
|
|
FProcMembers: TRefCntObjList; // Locals
|
|
FLastMember: TFpDbgSymbol;
|
|
FAddress: TDbgPtr;
|
|
FAddressInfo: PDwarfAddressInfo;
|
|
FStateMachine: TDwarfLineInfoStateMachine;
|
|
FFrameBaseParser: TDwarfLocationExpression;
|
|
FSelfParameter: TFpDwarfValue;
|
|
function StateMachineValid: Boolean;
|
|
function ReadVirtuality(out AFlags: TDbgSymbolFlags): Boolean;
|
|
procedure CreateMembers;
|
|
protected
|
|
function GetMember(AIndex: Int64): TFpDbgSymbol; override;
|
|
function GetMemberByName(AIndex: String): TFpDbgSymbol; override;
|
|
function GetMemberCount: Integer; override;
|
|
|
|
function GetFrameBase(ASender: TDwarfLocationExpression): TDbgPtr;
|
|
procedure KindNeeded; override;
|
|
procedure SizeNeeded; override;
|
|
function GetFlags: TDbgSymbolFlags; override;
|
|
|
|
function GetColumn: Cardinal; override;
|
|
function GetFile: String; override;
|
|
// function GetFlags: TDbgSymbolFlags; override;
|
|
function GetLine: Cardinal; override;
|
|
function GetValueObject: TFpDbgValue; override;
|
|
public
|
|
constructor Create(ACompilationUnit: TDwarfCompilationUnit; AInfo: PDwarfAddressInfo; AAddress: TDbgPtr); overload;
|
|
destructor Destroy; override;
|
|
// TODO members = locals ?
|
|
function GetSelfParameter(AnAddress: TDbgPtr = 0): TFpDwarfValue;
|
|
end;
|
|
|
|
{ TFpDwarfSymbolValueVariable }
|
|
|
|
TFpDwarfSymbolValueVariable = class(TFpDwarfSymbolValueWithLocation)
|
|
protected
|
|
function GetValueAddress(AValueObj: TFpDwarfValue; out AnAddress: TFpDbgMemLocation): Boolean; override;
|
|
function HasAddress: Boolean; override;
|
|
public
|
|
end;
|
|
|
|
{ TFpDwarfSymbolValueParameter }
|
|
|
|
TFpDwarfSymbolValueParameter = class(TFpDwarfSymbolValueWithLocation)
|
|
protected
|
|
function GetValueAddress(AValueObj: TFpDwarfValue; out AnAddress: TFpDbgMemLocation): Boolean; override;
|
|
function HasAddress: Boolean; override;
|
|
function GetFlags: TDbgSymbolFlags; override;
|
|
public
|
|
end;
|
|
|
|
{ TFpDwarfSymbolUnit }
|
|
|
|
TFpDwarfSymbolUnit = class(TFpDwarfSymbol)
|
|
private
|
|
FLastChildByName: TFpDbgSymbol;
|
|
protected
|
|
procedure Init; override;
|
|
function GetMemberByName(AIndex: String): TFpDbgSymbol; override;
|
|
public
|
|
destructor Destroy; override;
|
|
end;
|
|
{%endregion Symbol objects }
|
|
|
|
implementation
|
|
|
|
var
|
|
FPDBG_DWARF_VERBOSE, FPDBG_DWARF_ERRORS, FPDBG_DWARF_WARNINGS, FPDBG_DWARF_SEARCH, FPDBG_DWARF_DATA_WARNINGS: PLazLoggerLogGroup;
|
|
|
|
{ TFpDwarfDefaultSymbolClassMap }
|
|
|
|
class function TFpDwarfDefaultSymbolClassMap.HandleCompUnit(ACU: TDwarfCompilationUnit): Boolean;
|
|
begin
|
|
Result := True;
|
|
end;
|
|
|
|
class function TFpDwarfDefaultSymbolClassMap.GetDwarfSymbolClass(ATag: Cardinal): TDbgDwarfSymbolBaseClass;
|
|
begin
|
|
case ATag of
|
|
// TODO:
|
|
DW_TAG_constant:
|
|
Result := TFpDwarfSymbolValue;
|
|
DW_TAG_string_type,
|
|
DW_TAG_union_type, DW_TAG_ptr_to_member_type,
|
|
DW_TAG_file_type,
|
|
DW_TAG_thrown_type, DW_TAG_subroutine_type:
|
|
Result := TFpDwarfSymbolType;
|
|
|
|
// Type types
|
|
DW_TAG_packed_type,
|
|
DW_TAG_const_type,
|
|
DW_TAG_volatile_type: Result := TFpDwarfSymbolTypeModifier;
|
|
DW_TAG_reference_type: Result := TFpDwarfSymbolTypeRef;
|
|
DW_TAG_typedef: Result := TFpDwarfSymbolTypeDeclaration;
|
|
DW_TAG_pointer_type: Result := TFpDwarfSymbolTypePointer;
|
|
|
|
DW_TAG_base_type: Result := TFpDwarfSymbolTypeBasic;
|
|
DW_TAG_subrange_type: Result := TFpDwarfSymbolTypeSubRange;
|
|
DW_TAG_enumeration_type: Result := TFpDwarfSymbolTypeEnum;
|
|
DW_TAG_enumerator: Result := TFpDwarfSymbolValueEnumMember;
|
|
DW_TAG_set_type: Result := TFpDwarfSymbolTypeSet;
|
|
DW_TAG_structure_type,
|
|
DW_TAG_class_type: Result := TFpDwarfSymbolTypeStructure;
|
|
DW_TAG_array_type: Result := TFpDwarfSymbolTypeArray;
|
|
// Value types
|
|
DW_TAG_variable: Result := TFpDwarfSymbolValueVariable;
|
|
DW_TAG_formal_parameter: Result := TFpDwarfSymbolValueParameter;
|
|
DW_TAG_member: Result := TFpDwarfSymbolValueMember;
|
|
DW_TAG_subprogram: Result := TFpDwarfSymbolValueProc;
|
|
//
|
|
DW_TAG_compile_unit: Result := TFpDwarfSymbolUnit;
|
|
|
|
else
|
|
Result := TFpDwarfSymbol;
|
|
end;
|
|
end;
|
|
|
|
class function TFpDwarfDefaultSymbolClassMap.CreateContext(AThreadId, AStackFrame: Integer;
|
|
AnAddress: TDbgPtr; ASymbol: TFpDbgSymbol; ADwarf: TFpDwarfInfo): TFpDbgInfoContext;
|
|
begin
|
|
Result := TFpDwarfInfoAddressContext.Create(AThreadId, AStackFrame, AnAddress, ASymbol, ADwarf);
|
|
end;
|
|
|
|
class function TFpDwarfDefaultSymbolClassMap.CreateProcSymbol(ACompilationUnit: TDwarfCompilationUnit;
|
|
AInfo: PDwarfAddressInfo; AAddress: TDbgPtr): TDbgDwarfSymbolBase;
|
|
begin
|
|
Result := TFpDwarfSymbolValueProc.Create(ACompilationUnit, AInfo, AAddress);
|
|
end;
|
|
|
|
{ TDbgDwarfInfoAddressContext }
|
|
|
|
function TFpDwarfInfoAddressContext.GetSymbolAtAddress: TFpDbgSymbol;
|
|
begin
|
|
Result := FSymbol;
|
|
end;
|
|
|
|
function TFpDwarfInfoAddressContext.GetProcedureAtAddress: TFpDbgValue;
|
|
begin
|
|
Result := inherited GetProcedureAtAddress;
|
|
ApplyContext(Result);
|
|
end;
|
|
|
|
function TFpDwarfInfoAddressContext.GetAddress: TDbgPtr;
|
|
begin
|
|
Result := FAddress;
|
|
end;
|
|
|
|
function TFpDwarfInfoAddressContext.GetThreadId: Integer;
|
|
begin
|
|
Result := FThreadId;
|
|
end;
|
|
|
|
function TFpDwarfInfoAddressContext.GetStackFrame: Integer;
|
|
begin
|
|
Result := FStackFrame;
|
|
end;
|
|
|
|
function TFpDwarfInfoAddressContext.GetSizeOfAddress: Integer;
|
|
begin
|
|
assert(FSymbol is TFpDwarfSymbol, 'TDbgDwarfInfoAddressContext.GetSizeOfAddress');
|
|
Result := TFpDwarfSymbol(FSymbol).CompilationUnit.AddressSize;
|
|
end;
|
|
|
|
function TFpDwarfInfoAddressContext.GetMemManager: TFpDbgMemManager;
|
|
begin
|
|
Result := FDwarf.MemManager;
|
|
end;
|
|
|
|
function TFpDwarfInfoAddressContext.ApplyContext(AVal: TFpDbgValue): TFpDbgValue;
|
|
begin
|
|
if (AVal <> nil) and (TFpDwarfValueBase(AVal).FContext = nil) then
|
|
TFpDwarfValueBase(AVal).FContext := Self;
|
|
end;
|
|
|
|
function TFpDwarfInfoAddressContext.SymbolToValue(ASym: TFpDbgSymbol): TFpDbgValue;
|
|
begin
|
|
if ASym = nil then begin
|
|
Result := nil;
|
|
exit;
|
|
end;
|
|
|
|
if ASym.SymbolType = stValue then begin
|
|
Result := ASym.Value;
|
|
Result.AddReference{$IFDEF WITH_REFCOUNT_DEBUG}(@FlastResult, 'FindSymbol'){$ENDIF};
|
|
end
|
|
else begin
|
|
Result := TFpDwarfValueTypeDefinition.Create(ASym);
|
|
{$IFDEF WITH_REFCOUNT_DEBUG}Result.DbgRenameReference(@FlastResult, 'FindSymbol'){$ENDIF};
|
|
end;
|
|
ASym.ReleaseReference;
|
|
end;
|
|
|
|
procedure TFpDwarfInfoAddressContext.AddRefToVal(AVal: TFpDbgValue);
|
|
begin
|
|
AVal.AddReference{$IFDEF WITH_REFCOUNT_DEBUG}(@FlastResult, 'FindSymbol'){$ENDIF};
|
|
end;
|
|
|
|
function TFpDwarfInfoAddressContext.GetSelfParameter: TFpDbgValue;
|
|
begin
|
|
Result := TFpDwarfSymbolValueProc(FSymbol).GetSelfParameter(FAddress);
|
|
if (Result <> nil) and (TFpDwarfValueBase(Result).FContext = nil) then
|
|
TFpDwarfValueBase(Result).FContext := Self;
|
|
end;
|
|
|
|
function TFpDwarfInfoAddressContext.FindExportedSymbolInUnits(const AName: String; PNameUpper,
|
|
PNameLower: PChar; SkipCompUnit: TDwarfCompilationUnit; out ADbgValue: TFpDbgValue): Boolean;
|
|
var
|
|
i, ExtVal: Integer;
|
|
CU: TDwarfCompilationUnit;
|
|
InfoEntry, FoundInfoEntry: TDwarfInformationEntry;
|
|
s: String;
|
|
begin
|
|
Result := False;
|
|
ADbgValue := nil;
|
|
InfoEntry := nil;
|
|
FoundInfoEntry := nil;
|
|
i := FDwarf.CompilationUnitsCount;
|
|
while i > 0 do begin
|
|
dec(i);
|
|
CU := FDwarf.CompilationUnits[i];
|
|
if CU = SkipCompUnit then
|
|
continue;
|
|
//DebugLn(FPDBG_DWARF_SEARCH, ['TDbgDwarf.FindIdentifier search UNIT Name=', CU.FileName]);
|
|
|
|
InfoEntry.ReleaseReference;
|
|
InfoEntry := TDwarfInformationEntry.Create(CU, nil);
|
|
InfoEntry.ScopeIndex := CU.FirstScope.Index;
|
|
|
|
if not InfoEntry.AbbrevTag = DW_TAG_compile_unit then
|
|
continue;
|
|
// compile_unit can not have startscope
|
|
|
|
s := CU.UnitName;
|
|
if (s <> '') and (CompareUtf8BothCase(PNameUpper, PNameLower, @s[1])) then begin
|
|
ReleaseRefAndNil(FoundInfoEntry);
|
|
ADbgValue := SymbolToValue(TFpDwarfSymbol.CreateSubClass(AName, InfoEntry));
|
|
break;
|
|
end;
|
|
|
|
CU.ScanAllEntries;
|
|
if InfoEntry.GoNamedChildEx(PNameUpper, PNameLower) then begin
|
|
if InfoEntry.IsAddressInStartScope(FAddress) then begin
|
|
// only variables are marked "external", but types not / so we may need all top level
|
|
FoundInfoEntry.ReleaseReference;
|
|
FoundInfoEntry := InfoEntry.Clone;
|
|
//DebugLn(FPDBG_DWARF_SEARCH, ['TDbgDwarf.FindIdentifier MAYBE FOUND Name=', CU.FileName]);
|
|
|
|
// DW_AT_visibility ?
|
|
if InfoEntry.ReadValue(DW_AT_external, ExtVal) then
|
|
if ExtVal <> 0 then
|
|
break;
|
|
// Search for better ADbgValue
|
|
end;
|
|
end;
|
|
end;
|
|
|
|
if FoundInfoEntry <> nil then begin;
|
|
ADbgValue := SymbolToValue(TFpDwarfSymbol.CreateSubClass(AName, FoundInfoEntry));
|
|
FoundInfoEntry.ReleaseReference;
|
|
end;
|
|
|
|
InfoEntry.ReleaseReference;
|
|
Result := ADbgValue <> nil;
|
|
end;
|
|
|
|
function TFpDwarfInfoAddressContext.FindSymbolInStructure(const AName: String; PNameUpper,
|
|
PNameLower: PChar; InfoEntry: TDwarfInformationEntry; out ADbgValue: TFpDbgValue): Boolean;
|
|
var
|
|
InfoEntryInheritance: TDwarfInformationEntry;
|
|
FwdInfoPtr: Pointer;
|
|
FwdCompUint: TDwarfCompilationUnit;
|
|
SelfParam: TFpDbgValue;
|
|
begin
|
|
Result := False;
|
|
ADbgValue := nil;
|
|
InfoEntry.AddReference;
|
|
|
|
while True do begin
|
|
if not InfoEntry.IsAddressInStartScope(FAddress) then
|
|
break;
|
|
|
|
InfoEntryInheritance := InfoEntry.FindChildByTag(DW_TAG_inheritance);
|
|
|
|
if InfoEntry.GoNamedChildEx(PNameUpper, PNameLower) then begin
|
|
if InfoEntry.IsAddressInStartScope(FAddress) then begin
|
|
SelfParam := GetSelfParameter;
|
|
if (SelfParam <> nil) then begin
|
|
// TODO: only valid, as long as context is valid, because if context is freed, then self is lost too
|
|
ADbgValue := SelfParam.MemberByName[AName];
|
|
assert(ADbgValue <> nil, 'FindSymbol: SelfParam.MemberByName[AName]');
|
|
if ADbgValue <> nil then
|
|
ADbgValue.AddReference{$IFDEF WITH_REFCOUNT_DEBUG}(@FlastResult, 'FindSymbol'){$ENDIF};
|
|
end
|
|
else debugln(['TDbgDwarfInfoAddressContext.FindSymbol XXXXXXXXXXXXX no self']);
|
|
;
|
|
if ADbgValue = nil then begin // Todo: abort the searh /SetError
|
|
ADbgValue := SymbolToValue(TFpDwarfSymbol.CreateSubClass(AName, InfoEntry));
|
|
end;
|
|
InfoEntry.ReleaseReference;
|
|
InfoEntryInheritance.ReleaseReference;
|
|
Result := True;
|
|
exit;
|
|
end;
|
|
end;
|
|
|
|
|
|
if not( (InfoEntryInheritance <> nil) and
|
|
(InfoEntryInheritance.ReadReference(DW_AT_type, FwdInfoPtr, FwdCompUint)) )
|
|
then
|
|
break;
|
|
InfoEntry.ReleaseReference;
|
|
InfoEntry := TDwarfInformationEntry.Create(FwdCompUint, FwdInfoPtr);
|
|
InfoEntryInheritance.ReleaseReference;
|
|
DebugLn(FPDBG_DWARF_SEARCH, ['TDbgDwarf.FindIdentifier PARENT ', dbgs(InfoEntry, FwdCompUint) ]);
|
|
end;
|
|
|
|
InfoEntry.ReleaseReference;
|
|
Result := ADbgValue <> nil;
|
|
end;
|
|
|
|
function TFpDwarfInfoAddressContext.FindLocalSymbol(const AName: String; PNameUpper,
|
|
PNameLower: PChar; InfoEntry: TDwarfInformationEntry; out ADbgValue: TFpDbgValue): Boolean;
|
|
begin
|
|
Result := False;
|
|
ADbgValue := nil;
|
|
if not InfoEntry.GoNamedChildEx(PNameUpper, PNameLower) then
|
|
exit;
|
|
if InfoEntry.IsAddressInStartScope(FAddress) and not InfoEntry.IsArtificial then begin
|
|
ADbgValue := SymbolToValue(TFpDwarfSymbol.CreateSubClass(AName, InfoEntry));
|
|
TFpDwarfSymbol(ADbgValue.DbgSymbol).ParentTypeInfo := TFpDwarfSymbolValueProc(FSymbol);
|
|
end;
|
|
Result := ADbgValue <> nil;
|
|
end;
|
|
|
|
constructor TFpDwarfInfoAddressContext.Create(AThreadId, AStackFrame: Integer;
|
|
AnAddress: TDbgPtr; ASymbol: TFpDbgSymbol; ADwarf: TFpDwarfInfo);
|
|
begin
|
|
inherited Create;
|
|
AddReference;
|
|
FAddress := AnAddress;
|
|
FThreadId := AThreadId;
|
|
FStackFrame := AStackFrame;
|
|
FDwarf := ADwarf;
|
|
FSymbol := ASymbol;
|
|
FSymbol.AddReference{$IFDEF WITH_REFCOUNT_DEBUG}(@FSymbol, 'Context to Symbol'){$ENDIF};
|
|
end;
|
|
|
|
destructor TFpDwarfInfoAddressContext.Destroy;
|
|
begin
|
|
FlastResult.ReleaseReference{$IFDEF WITH_REFCOUNT_DEBUG}(@FlastResult, 'FindSymbol'){$ENDIF};
|
|
FSymbol.ReleaseReference{$IFDEF WITH_REFCOUNT_DEBUG}(@FSymbol, 'Context to Symbol'){$ENDIF};
|
|
inherited Destroy;
|
|
end;
|
|
|
|
function TFpDwarfInfoAddressContext.FindSymbol(const AName: String): TFpDbgValue;
|
|
var
|
|
SubRoutine: TFpDwarfSymbolValueProc; // TDbgSymbol;
|
|
CU: TDwarfCompilationUnit;
|
|
//Scope,
|
|
StartScopeIdx: Integer;
|
|
InfoEntry: TDwarfInformationEntry;
|
|
NameUpper, NameLower: String;
|
|
InfoName: PChar;
|
|
tg: Cardinal;
|
|
PNameUpper, PNameLower: PChar;
|
|
begin
|
|
Result := nil;
|
|
if (FSymbol = nil) or not(FSymbol is TFpDwarfSymbolValueProc) or (AName = '') then
|
|
exit;
|
|
|
|
SubRoutine := TFpDwarfSymbolValueProc(FSymbol);
|
|
NameUpper := UTF8UpperCase(AName);
|
|
NameLower := UTF8LowerCase(AName);
|
|
PNameUpper := @NameUpper[1];
|
|
PNameLower := @NameLower[1];
|
|
|
|
try
|
|
CU := SubRoutine.CompilationUnit;
|
|
InfoEntry := SubRoutine.InformationEntry.Clone;
|
|
|
|
while InfoEntry.HasValidScope do begin
|
|
//debugln(FPDBG_DWARF_SEARCH, ['TDbgDwarf.FindIdentifier Searching ', dbgs(InfoEntry.FScope, CU)]);
|
|
StartScopeIdx := InfoEntry.ScopeIndex;
|
|
|
|
//if InfoEntry.Abbrev = nil then
|
|
// exit;
|
|
|
|
if not InfoEntry.IsAddressInStartScope(FAddress) // StartScope = first valid address
|
|
then begin
|
|
// CONTINUE: Search parent(s)
|
|
//InfoEntry.ScopeIndex := StartScopeIdx;
|
|
InfoEntry.GoParent;
|
|
Continue;
|
|
end;
|
|
|
|
if InfoEntry.ReadName(InfoName) and not InfoEntry.IsArtificial
|
|
then begin
|
|
if (CompareUtf8BothCase(PNameUpper, PNameLower, InfoName)) then begin
|
|
// TODO: this is a pascal sperific search order? Or not?
|
|
// If this is a type with a pointer or ref, need to find the pointer or ref.
|
|
InfoEntry.GoParent;
|
|
if InfoEntry.HasValidScope and
|
|
InfoEntry.GoNamedChildEx(PNameUpper, PNameLower)
|
|
then begin
|
|
if InfoEntry.IsAddressInStartScope(FAddress) and not InfoEntry.IsArtificial then begin
|
|
Result := SymbolToValue(TFpDwarfSymbol.CreateSubClass(AName, InfoEntry));
|
|
exit;
|
|
end;
|
|
end;
|
|
|
|
InfoEntry.ScopeIndex := StartScopeIdx;
|
|
Result := SymbolToValue(TFpDwarfSymbol.CreateSubClass(AName, InfoEntry));
|
|
exit;
|
|
end;
|
|
end;
|
|
|
|
|
|
tg := InfoEntry.AbbrevTag;
|
|
if (tg = DW_TAG_class_type) or (tg = DW_TAG_structure_type) then begin
|
|
if FindSymbolInStructure(AName,PNameUpper, PNameLower, InfoEntry, Result) then
|
|
exit; // TODO: check error
|
|
//InfoEntry.ScopeIndex := StartScopeIdx;
|
|
end
|
|
|
|
else
|
|
if (StartScopeIdx = SubRoutine.InformationEntry.ScopeIndex) then begin // searching in subroutine
|
|
if FindLocalSymbol(AName,PNameUpper, PNameLower, InfoEntry, Result) then
|
|
exit; // TODO: check error
|
|
//InfoEntry.ScopeIndex := StartScopeIdx;
|
|
end
|
|
// TODO: nested subroutine
|
|
|
|
else
|
|
if InfoEntry.GoNamedChildEx(PNameUpper, PNameLower) then begin
|
|
if InfoEntry.IsAddressInStartScope(FAddress) and not InfoEntry.IsArtificial then begin
|
|
Result := SymbolToValue(TFpDwarfSymbol.CreateSubClass(AName, InfoEntry));
|
|
exit;
|
|
end;
|
|
end;
|
|
|
|
// Search parent(s)
|
|
InfoEntry.ScopeIndex := StartScopeIdx;
|
|
InfoEntry.GoParent;
|
|
end;
|
|
|
|
FindExportedSymbolInUnits(AName, PNameUpper, PNameLower, CU, Result);
|
|
|
|
finally
|
|
if (Result = nil) or (InfoEntry = nil)
|
|
then DebugLn(FPDBG_DWARF_SEARCH, ['TDbgDwarf.FindIdentifier NOT found Name=', AName])
|
|
else DebugLn(FPDBG_DWARF_SEARCH, ['TDbgDwarf.FindIdentifier(',AName,') found Scope=', TFpDwarfSymbol(Result.DbgSymbol).InformationEntry.ScopeDebugText, ' ResultSymbol=', DbgSName(Result.DbgSymbol), ' ', Result.DbgSymbol.Name, ' in ', TFpDwarfSymbol(Result.DbgSymbol).CompilationUnit.FileName]);
|
|
ReleaseRefAndNil(InfoEntry);
|
|
|
|
FlastResult.ReleaseReference{$IFDEF WITH_REFCOUNT_DEBUG}(@FlastResult, 'FindSymbol'){$ENDIF};
|
|
FlastResult := Result;
|
|
|
|
assert((Result = nil) or (Result is TFpDwarfValueBase), 'TDbgDwarfInfoAddressContext.FindSymbol: (Result = nil) or (Result is TFpDwarfValueBase)');
|
|
ApplyContext(Result);
|
|
end;
|
|
end;
|
|
|
|
{ TFpDwarfValueTypeDefinition }
|
|
|
|
function TFpDwarfValueTypeDefinition.GetKind: TDbgSymbolKind;
|
|
begin
|
|
Result := skNone;
|
|
end;
|
|
|
|
function TFpDwarfValueTypeDefinition.GetDbgSymbol: TFpDbgSymbol;
|
|
begin
|
|
Result := FSymbol;
|
|
end;
|
|
|
|
constructor TFpDwarfValueTypeDefinition.Create(ASymbol: TFpDbgSymbol);
|
|
begin
|
|
inherited Create;
|
|
FSymbol := ASymbol;
|
|
FSymbol.AddReference{$IFDEF WITH_REFCOUNT_DEBUG}(@FSymbol, 'TFpDwarfValueTypeDefinition'){$ENDIF};
|
|
end;
|
|
|
|
destructor TFpDwarfValueTypeDefinition.Destroy;
|
|
begin
|
|
inherited Destroy;
|
|
FSymbol.ReleaseReference{$IFDEF WITH_REFCOUNT_DEBUG}(@FSymbol, 'TFpDwarfValueTypeDefinition'){$ENDIF};
|
|
end;
|
|
|
|
function TFpDwarfValueTypeDefinition.GetTypeCastedValue(ADataVal: TFpDbgValue): TFpDbgValue;
|
|
begin
|
|
Result := FSymbol.TypeCastValue(ADataVal);
|
|
assert((Result = nil) or (Result is TFpDwarfValue), 'TFpDwarfValueTypeDefinition.GetTypeCastedValue: (Result = nil) or (Result is TFpDwarfValue)');
|
|
if (Result <> nil) and (TFpDwarfValue(Result).FContext = nil) then
|
|
TFpDwarfValue(Result).FContext := FContext;
|
|
end;
|
|
|
|
{ TFpDwarfValue }
|
|
|
|
function TFpDwarfValue.MemManager: TFpDbgMemManager;
|
|
begin
|
|
Result := nil;
|
|
if FContext <> nil then
|
|
Result := FContext.MemManager;
|
|
|
|
if Result = nil then begin
|
|
// Either a typecast, or a member gotten from a typecast,...
|
|
assert((FOwner <> nil) and (FOwner.CompilationUnit <> nil) and (FOwner.CompilationUnit.Owner <> nil), 'TDbgDwarfSymbolValue.MemManager');
|
|
Result := FOwner.CompilationUnit.Owner.MemManager;
|
|
end;
|
|
end;
|
|
|
|
function TFpDwarfValue.GetDataAddressCache(AIndex: Integer): TFpDbgMemLocation;
|
|
begin
|
|
if AIndex < Length(FDataAddressCache) then
|
|
Result := FDataAddressCache[AIndex]
|
|
else
|
|
Result := UnInitializedLoc;
|
|
end;
|
|
|
|
function TFpDwarfValue.AddressSize: Byte;
|
|
begin
|
|
assert((FOwner <> nil) and (FOwner.CompilationUnit <> nil), 'TDbgDwarfSymbolValue.AddressSize');
|
|
Result := FOwner.CompilationUnit.AddressSize;
|
|
end;
|
|
|
|
procedure TFpDwarfValue.SetDataAddressCache(AIndex: Integer; AValue: TFpDbgMemLocation);
|
|
var
|
|
i, j: Integer;
|
|
begin
|
|
i := length(FDataAddressCache);
|
|
if AIndex >= i then begin
|
|
SetLength(FDataAddressCache, AIndex + 1 + 8);
|
|
// todo: Fillbyte 0
|
|
for j := i to Length(FDataAddressCache) - 1 do
|
|
FDataAddressCache[j] := UnInitializedLoc;
|
|
end;
|
|
FDataAddressCache[AIndex] := AValue;
|
|
end;
|
|
|
|
procedure TFpDwarfValue.SetStructureValue(AValue: TFpDwarfValue);
|
|
begin
|
|
if FStructureValue <> nil then
|
|
Reset;
|
|
|
|
if FStructureValue = AValue then
|
|
exit;
|
|
|
|
if CircleBackRefsActive and (FStructureValue <> nil) then
|
|
FStructureValue.ReleaseReference{$IFDEF WITH_REFCOUNT_DEBUG}(@FStructureValue, 'TDbgDwarfSymbolValue'){$ENDIF};
|
|
FStructureValue := AValue;
|
|
if CircleBackRefsActive and (FStructureValue <> nil) then
|
|
FStructureValue.AddReference{$IFDEF WITH_REFCOUNT_DEBUG}(@FStructureValue, 'TDbgDwarfSymbolValue'){$ENDIF};
|
|
end;
|
|
|
|
function TFpDwarfValue.GetLastError: TFpError;
|
|
begin
|
|
Result := FLastError;
|
|
end;
|
|
|
|
function TFpDwarfValue.DataAddr: TFpDbgMemLocation;
|
|
begin
|
|
// GetDwarfDataAddress(???); What about FTypeCastSourceValue.AsCardinal ?
|
|
if FValueSymbol <> nil then begin
|
|
//FValueSymbol.GetValueAddress(Self, Result);
|
|
FValueSymbol.GetValueDataAddress(Self, Result, FOwner);
|
|
if IsError(FValueSymbol.LastError) then
|
|
FLastError := FValueSymbol.LastError;
|
|
end
|
|
else
|
|
if HasTypeCastInfo then begin
|
|
Result := FTypeCastSourceValue.Address;
|
|
if IsError(FTypeCastSourceValue.LastError) then
|
|
FLastError := FTypeCastSourceValue.LastError;
|
|
|
|
if IsReadableLoc(Result) then begin
|
|
if not FTypeCastTargetType.GetDataAddress(Self, Result, FOwner, 1) then
|
|
Result := InvalidLoc;
|
|
if IsError(FTypeCastTargetType.LastError) then
|
|
FLastError := FTypeCastTargetType.LastError;
|
|
end;
|
|
end
|
|
else
|
|
Result := InvalidLoc;
|
|
end;
|
|
|
|
function TFpDwarfValue.OrdOrDataAddr: TFpDbgMemLocation;
|
|
begin
|
|
if HasTypeCastInfo and (svfOrdinal in FTypeCastSourceValue.FieldFlags) then
|
|
Result := ConstLoc(FTypeCastSourceValue.AsCardinal)
|
|
else
|
|
Result := DataAddr;
|
|
end;
|
|
|
|
function TFpDwarfValue.GetDwarfDataAddress(out AnAddress: TFpDbgMemLocation;
|
|
ATargetType: TFpDwarfSymbolType): Boolean;
|
|
var
|
|
fields: TFpDbgValueFieldFlags;
|
|
begin
|
|
if FValueSymbol <> nil then begin
|
|
Assert(FValueSymbol is TFpDwarfSymbolValue, 'TDbgDwarfSymbolValue.GetDwarfDataAddress FValueSymbol');
|
|
Assert(TypeInfo is TFpDwarfSymbolType, 'TDbgDwarfSymbolValue.GetDwarfDataAddress TypeInfo');
|
|
Assert(not HasTypeCastInfo, 'TDbgDwarfSymbolValue.GetDwarfDataAddress not HasTypeCastInfo');
|
|
Result := FValueSymbol.GetValueDataAddress(Self, AnAddress, ATargetType);
|
|
if IsError(FValueSymbol.LastError) then
|
|
FLastError := FValueSymbol.LastError;
|
|
end
|
|
|
|
else
|
|
begin
|
|
// TODO: cache own address
|
|
// try typecast
|
|
Result := HasTypeCastInfo;
|
|
if not Result then
|
|
exit;
|
|
fields := FTypeCastSourceValue.FieldFlags;
|
|
AnAddress := InvalidLoc;
|
|
if svfOrdinal in fields then
|
|
AnAddress := ConstLoc(FTypeCastSourceValue.AsCardinal)
|
|
else
|
|
if svfAddress in fields then
|
|
AnAddress := FTypeCastSourceValue.Address;
|
|
|
|
Result := IsReadableLoc(AnAddress);
|
|
if not Result then
|
|
exit;
|
|
|
|
Result := FTypeCastTargetType.GetDataAddress(Self, AnAddress, ATargetType, 1);
|
|
if IsError(FTypeCastTargetType.LastError) then
|
|
FLastError := FTypeCastTargetType.LastError;
|
|
end;
|
|
end;
|
|
|
|
function TFpDwarfValue.GetStructureDwarfDataAddress(out AnAddress: TFpDbgMemLocation;
|
|
ATargetType: TFpDwarfSymbolType): Boolean;
|
|
begin
|
|
AnAddress := InvalidLoc;
|
|
Result := StructureValue <> nil;
|
|
if Result then
|
|
Result := StructureValue.GetDwarfDataAddress(AnAddress, ATargetType);
|
|
end;
|
|
|
|
function TFpDwarfValue.HasDwarfDataAddress: Boolean;
|
|
begin
|
|
if FValueSymbol <> nil then begin
|
|
Assert(FValueSymbol is TFpDwarfSymbolValue, 'TDbgDwarfSymbolValue.GetDwarfDataAddress FValueSymbol');
|
|
Assert(TypeInfo is TFpDwarfSymbolType, 'TDbgDwarfSymbolValue.GetDwarfDataAddress TypeInfo');
|
|
Assert(not HasTypeCastInfo, 'TDbgDwarfSymbolValue.GetDwarfDataAddress not HasTypeCastInfo');
|
|
Result := FValueSymbol.HasAddress;
|
|
end
|
|
else
|
|
begin
|
|
// try typecast
|
|
Result := HasTypeCastInfo;
|
|
if not Result then
|
|
exit;
|
|
Result := FTypeCastSourceValue.FieldFlags * [svfAddress, svfOrdinal] <> [];
|
|
end;
|
|
end;
|
|
|
|
procedure TFpDwarfValue.Reset;
|
|
begin
|
|
FDataAddressCache := nil;
|
|
FLastError := NoError;
|
|
end;
|
|
|
|
function TFpDwarfValue.GetFieldFlags: TFpDbgValueFieldFlags;
|
|
begin
|
|
Result := inherited GetFieldFlags;
|
|
if FValueSymbol <> nil then begin
|
|
if FValueSymbol.HasAddress then Result := Result + [svfAddress];
|
|
end
|
|
else
|
|
if HasTypeCastInfo then begin
|
|
Result := Result + FTypeCastSourceValue.FieldFlags * [svfAddress];
|
|
end;
|
|
end;
|
|
|
|
function TFpDwarfValue.HasTypeCastInfo: Boolean;
|
|
begin
|
|
Result := (FTypeCastTargetType <> nil) and (FTypeCastSourceValue <> nil);
|
|
end;
|
|
|
|
function TFpDwarfValue.IsValidTypeCast: Boolean;
|
|
begin
|
|
Result := False;
|
|
end;
|
|
|
|
procedure TFpDwarfValue.DoReferenceAdded;
|
|
begin
|
|
inherited DoReferenceAdded;
|
|
DoPlainReferenceAdded;
|
|
end;
|
|
|
|
procedure TFpDwarfValue.DoReferenceReleased;
|
|
begin
|
|
inherited DoReferenceReleased;
|
|
DoPlainReferenceReleased;
|
|
end;
|
|
|
|
procedure TFpDwarfValue.CircleBackRefActiveChanged(NewActive: Boolean);
|
|
begin
|
|
inherited CircleBackRefActiveChanged(NewActive);
|
|
if NewActive then;
|
|
if CircleBackRefsActive then begin
|
|
if FValueSymbol <> nil then
|
|
FValueSymbol.AddReference{$IFDEF WITH_REFCOUNT_DEBUG}(@FValueSymbol, 'TDbgDwarfSymbolValue'){$ENDIF};
|
|
if FStructureValue <> nil then
|
|
FStructureValue.AddReference{$IFDEF WITH_REFCOUNT_DEBUG}(@FStructureValue, 'TDbgDwarfSymbolValue'){$ENDIF};
|
|
end
|
|
else begin
|
|
if FValueSymbol <> nil then
|
|
FValueSymbol.ReleaseReference{$IFDEF WITH_REFCOUNT_DEBUG}(@FValueSymbol, 'TDbgDwarfSymbolValue'){$ENDIF};
|
|
if FStructureValue <> nil then
|
|
FStructureValue.ReleaseReference{$IFDEF WITH_REFCOUNT_DEBUG}(@FStructureValue, 'TDbgDwarfSymbolValue'){$ENDIF};
|
|
end;
|
|
end;
|
|
|
|
procedure TFpDwarfValue.SetLastMember(ALastMember: TFpDwarfValue);
|
|
begin
|
|
if FLastMember <> nil then
|
|
FLastMember.ReleaseCirclularReference{$IFDEF WITH_REFCOUNT_DEBUG}(@FLastMember, 'TDbgDwarfSymbolValue'){$ENDIF};
|
|
|
|
FLastMember := ALastMember;
|
|
|
|
if (FLastMember <> nil) then begin
|
|
FLastMember.SetStructureValue(Self);
|
|
FLastMember.AddCirclularReference{$IFDEF WITH_REFCOUNT_DEBUG}(@FLastMember, 'TDbgDwarfSymbolValue'){$ENDIF};
|
|
if (FLastMember.FContext = nil) then
|
|
FLastMember.FContext := FContext;
|
|
end;
|
|
end;
|
|
|
|
function TFpDwarfValue.GetKind: TDbgSymbolKind;
|
|
begin
|
|
if FValueSymbol <> nil then
|
|
Result := FValueSymbol.Kind
|
|
else
|
|
if HasTypeCastInfo then
|
|
Result := FTypeCastTargetType.Kind
|
|
else
|
|
Result := inherited GetKind;
|
|
end;
|
|
|
|
function TFpDwarfValue.GetAddress: TFpDbgMemLocation;
|
|
begin
|
|
if FValueSymbol <> nil then
|
|
FValueSymbol.GetValueAddress(Self, Result)
|
|
else
|
|
if HasTypeCastInfo then
|
|
Result := FTypeCastSourceValue.Address
|
|
else
|
|
Result := inherited GetAddress;
|
|
end;
|
|
|
|
function TFpDwarfValue.OrdOrAddress: TFpDbgMemLocation;
|
|
begin
|
|
if HasTypeCastInfo and (svfOrdinal in FTypeCastSourceValue.FieldFlags) then
|
|
Result := ConstLoc(FTypeCastSourceValue.AsCardinal)
|
|
else
|
|
Result := Address;
|
|
end;
|
|
|
|
function TFpDwarfValue.GetMemberCount: Integer;
|
|
begin
|
|
if FValueSymbol <> nil then
|
|
Result := FValueSymbol.MemberCount
|
|
else
|
|
Result := inherited GetMemberCount;
|
|
end;
|
|
|
|
function TFpDwarfValue.GetMemberByName(AIndex: String): TFpDbgValue;
|
|
var
|
|
m: TFpDbgSymbol;
|
|
begin
|
|
Result := nil;
|
|
if FValueSymbol <> nil then begin
|
|
m := FValueSymbol.MemberByName[AIndex];
|
|
if m <> nil then
|
|
Result := m.Value;
|
|
end;
|
|
SetLastMember(TFpDwarfValue(Result));
|
|
end;
|
|
|
|
function TFpDwarfValue.GetMember(AIndex: Int64): TFpDbgValue;
|
|
var
|
|
m: TFpDbgSymbol;
|
|
begin
|
|
Result := nil;
|
|
if FValueSymbol <> nil then begin
|
|
m := FValueSymbol.Member[AIndex];
|
|
if m <> nil then
|
|
Result := m.Value;
|
|
end;
|
|
SetLastMember(TFpDwarfValue(Result));
|
|
end;
|
|
|
|
function TFpDwarfValue.GetDbgSymbol: TFpDbgSymbol;
|
|
begin
|
|
Result := FValueSymbol;
|
|
end;
|
|
|
|
function TFpDwarfValue.GetTypeInfo: TFpDbgSymbol;
|
|
begin
|
|
if HasTypeCastInfo then
|
|
Result := FTypeCastTargetType
|
|
else
|
|
Result := inherited GetTypeInfo;
|
|
end;
|
|
|
|
function TFpDwarfValue.GetContextTypeInfo: TFpDbgSymbol;
|
|
begin
|
|
if (FValueSymbol <> nil) and (FValueSymbol.ParentTypeInfo <> nil) then
|
|
Result := FValueSymbol.ParentTypeInfo
|
|
else
|
|
Result := nil; // internal error
|
|
end;
|
|
|
|
constructor TFpDwarfValue.Create(AOwner: TFpDwarfSymbolType);
|
|
begin
|
|
FOwner := AOwner;
|
|
inherited Create;
|
|
end;
|
|
|
|
destructor TFpDwarfValue.Destroy;
|
|
begin
|
|
FTypeCastTargetType.ReleaseReference{$IFDEF WITH_REFCOUNT_DEBUG}(@FTypeCastTargetType, ClassName+'.FTypeCastTargetType'){$ENDIF};
|
|
FTypeCastSourceValue.ReleaseReference{$IFDEF WITH_REFCOUNT_DEBUG}(@FTypeCastSourceValue, ClassName+'.FTypeCastSourceValue'){$ENDIF};
|
|
SetLastMember(nil);
|
|
inherited Destroy;
|
|
end;
|
|
|
|
procedure TFpDwarfValue.SetValueSymbol(AValueSymbol: TFpDwarfSymbolValue);
|
|
begin
|
|
if FValueSymbol = AValueSymbol then
|
|
exit;
|
|
|
|
if CircleBackRefsActive and (FValueSymbol <> nil) then
|
|
FValueSymbol.ReleaseReference{$IFDEF WITH_REFCOUNT_DEBUG}(@FValueSymbol, 'TDbgDwarfSymbolValue'){$ENDIF};
|
|
FValueSymbol := AValueSymbol;
|
|
if CircleBackRefsActive and (FValueSymbol <> nil) then
|
|
FValueSymbol.AddReference{$IFDEF WITH_REFCOUNT_DEBUG}(@FValueSymbol, 'TDbgDwarfSymbolValue'){$ENDIF};
|
|
end;
|
|
|
|
function TFpDwarfValue.SetTypeCastInfo(AStructure: TFpDwarfSymbolType;
|
|
ASource: TFpDbgValue): Boolean;
|
|
begin
|
|
Reset;
|
|
|
|
if FTypeCastSourceValue <> ASource then begin
|
|
if FTypeCastSourceValue <> nil then
|
|
FTypeCastSourceValue.ReleaseReference{$IFDEF WITH_REFCOUNT_DEBUG}(@FTypeCastSourceValue, ClassName+'.FTypeCastSourceValue'){$ENDIF};
|
|
FTypeCastSourceValue := ASource;
|
|
if FTypeCastSourceValue <> nil then
|
|
FTypeCastSourceValue.AddReference{$IFDEF WITH_REFCOUNT_DEBUG}(@FTypeCastSourceValue, ClassName+'.FTypeCastSourceValue'){$ENDIF};
|
|
end;
|
|
|
|
if FTypeCastTargetType <> AStructure then begin
|
|
if FTypeCastTargetType <> nil then
|
|
FTypeCastTargetType.ReleaseReference{$IFDEF WITH_REFCOUNT_DEBUG}(@FTypeCastTargetType, ClassName+'.FTypeCastTargetType'){$ENDIF};
|
|
FTypeCastTargetType := AStructure;
|
|
if FTypeCastTargetType <> nil then
|
|
FTypeCastTargetType.AddReference{$IFDEF WITH_REFCOUNT_DEBUG}(@FTypeCastTargetType, ClassName+'.FTypeCastTargetType'){$ENDIF};
|
|
end;
|
|
|
|
Result := IsValidTypeCast;
|
|
end;
|
|
|
|
{ TFpDwarfValueSized }
|
|
|
|
function TFpDwarfValueSized.CanUseTypeCastAddress: Boolean;
|
|
begin
|
|
Result := True;
|
|
if (FTypeCastSourceValue.FieldFlags * [svfAddress, svfSize, svfSizeOfPointer] = [svfAddress]) then
|
|
exit
|
|
else
|
|
if (FTypeCastSourceValue.FieldFlags * [svfAddress, svfSize] = [svfAddress, svfSize]) and
|
|
(FTypeCastSourceValue.Size = FSize) and (FSize > 0)
|
|
then
|
|
exit;
|
|
if (FTypeCastSourceValue.FieldFlags * [svfAddress, svfSizeOfPointer] = [svfAddress, svfSizeOfPointer]) and
|
|
not ( (FTypeCastTargetType.Kind = skPointer) //or
|
|
//(FSize = AddressSize xxxxxxx)
|
|
)
|
|
then
|
|
exit;
|
|
Result := False;
|
|
end;
|
|
|
|
function TFpDwarfValueSized.GetFieldFlags: TFpDbgValueFieldFlags;
|
|
begin
|
|
Result := inherited GetFieldFlags;
|
|
Result := Result + [svfSize];
|
|
end;
|
|
|
|
function TFpDwarfValueSized.GetSize: Integer;
|
|
begin
|
|
Result := FSize;
|
|
end;
|
|
|
|
constructor TFpDwarfValueSized.Create(AOwner: TFpDwarfSymbolType; ASize: Integer);
|
|
begin
|
|
inherited Create(AOwner);
|
|
FSize := ASize;
|
|
end;
|
|
|
|
{ TFpDwarfValueNumeric }
|
|
|
|
procedure TFpDwarfValueNumeric.Reset;
|
|
begin
|
|
inherited Reset;
|
|
FEvaluated := [];
|
|
end;
|
|
|
|
function TFpDwarfValueNumeric.GetFieldFlags: TFpDbgValueFieldFlags;
|
|
begin
|
|
Result := inherited GetFieldFlags;
|
|
Result := Result + [svfOrdinal];
|
|
end;
|
|
|
|
function TFpDwarfValueNumeric.IsValidTypeCast: Boolean;
|
|
begin
|
|
Result := HasTypeCastInfo;
|
|
If not Result then
|
|
exit;
|
|
if (svfOrdinal in FTypeCastSourceValue.FieldFlags) or CanUseTypeCastAddress then
|
|
exit;
|
|
Result := False;
|
|
end;
|
|
|
|
constructor TFpDwarfValueNumeric.Create(AOwner: TFpDwarfSymbolType; ASize: Integer);
|
|
begin
|
|
inherited Create(AOwner, ASize);
|
|
FEvaluated := [];
|
|
end;
|
|
|
|
{ TFpDwarfValueInteger }
|
|
|
|
function TFpDwarfValueInteger.GetFieldFlags: TFpDbgValueFieldFlags;
|
|
begin
|
|
Result := inherited GetFieldFlags;
|
|
Result := Result + [svfInteger];
|
|
end;
|
|
|
|
function TFpDwarfValueInteger.GetAsCardinal: QWord;
|
|
begin
|
|
Result := QWord(GetAsInteger); // include sign extension
|
|
end;
|
|
|
|
function TFpDwarfValueInteger.GetAsInteger: Int64;
|
|
begin
|
|
if doneInt in FEvaluated then begin
|
|
Result := FIntValue;
|
|
exit;
|
|
end;
|
|
Include(FEvaluated, doneInt);
|
|
|
|
if (FSize <= 0) or (FSize > SizeOf(Result)) then
|
|
Result := inherited GetAsInteger
|
|
else
|
|
if not MemManager.ReadSignedInt(OrdOrDataAddr, FSize, Result) then begin
|
|
Result := 0; // TODO: error
|
|
FLastError := MemManager.LastError;
|
|
end;
|
|
|
|
FIntValue := Result;
|
|
end;
|
|
|
|
{ TDbgDwarfCardinalSymbolValue }
|
|
|
|
function TFpDwarfValueCardinal.GetAsCardinal: QWord;
|
|
begin
|
|
if doneUInt in FEvaluated then begin
|
|
Result := FValue;
|
|
exit;
|
|
end;
|
|
Include(FEvaluated, doneUInt);
|
|
|
|
if (FSize <= 0) or (FSize > SizeOf(Result)) then
|
|
Result := inherited GetAsCardinal
|
|
else
|
|
if not MemManager.ReadUnsignedInt(OrdOrDataAddr, FSize, Result) then begin
|
|
Result := 0; // TODO: error
|
|
FLastError := MemManager.LastError;
|
|
end;
|
|
|
|
FValue := Result;
|
|
end;
|
|
|
|
function TFpDwarfValueCardinal.GetFieldFlags: TFpDbgValueFieldFlags;
|
|
begin
|
|
Result := inherited GetFieldFlags;
|
|
Result := Result + [svfCardinal];
|
|
end;
|
|
|
|
{ TFpDwarfValueFloat }
|
|
|
|
function TFpDwarfValueFloat.GetFieldFlags: TFpDbgValueFieldFlags;
|
|
begin
|
|
Result := inherited GetFieldFlags;
|
|
Result := Result + [svfFloat] - [svfOrdinal];
|
|
end;
|
|
|
|
function TFpDwarfValueFloat.GetAsFloat: Extended;
|
|
begin
|
|
if doneFloat in FEvaluated then begin
|
|
Result := FValue;
|
|
exit;
|
|
end;
|
|
Include(FEvaluated, doneUInt);
|
|
|
|
if (FSize <= 0) or (FSize > SizeOf(Result)) then
|
|
Result := inherited GetAsCardinal
|
|
else
|
|
if not MemManager.ReadFloat(OrdOrDataAddr, FSize, Result) then begin
|
|
Result := 0; // TODO: error
|
|
FLastError := MemManager.LastError;
|
|
end;
|
|
|
|
FValue := Result;
|
|
end;
|
|
|
|
{ TFpDwarfValueBoolean }
|
|
|
|
function TFpDwarfValueBoolean.GetFieldFlags: TFpDbgValueFieldFlags;
|
|
begin
|
|
Result := inherited GetFieldFlags;
|
|
Result := Result + [svfBoolean];
|
|
end;
|
|
|
|
function TFpDwarfValueBoolean.GetAsBool: Boolean;
|
|
begin
|
|
Result := QWord(GetAsCardinal) <> 0;
|
|
end;
|
|
|
|
{ TFpDwarfValueChar }
|
|
|
|
function TFpDwarfValueChar.GetFieldFlags: TFpDbgValueFieldFlags;
|
|
begin
|
|
Result := inherited GetFieldFlags;
|
|
case FSize of
|
|
1: Result := Result + [svfString];
|
|
2: Result := Result + [svfWideString];
|
|
end;
|
|
end;
|
|
|
|
function TFpDwarfValueChar.GetAsString: AnsiString;
|
|
begin
|
|
// Can typecast, because of FSize = 1, GetAsCardinal only read one byte
|
|
if FSize <> 1 then
|
|
Result := inherited GetAsString
|
|
else
|
|
Result := SysToUTF8(char(byte(GetAsCardinal)));
|
|
end;
|
|
|
|
function TFpDwarfValueChar.GetAsWideString: WideString;
|
|
begin
|
|
if FSize > 2 then
|
|
Result := inherited GetAsString
|
|
else
|
|
Result := WideChar(Word(GetAsCardinal));
|
|
end;
|
|
|
|
{ TFpDwarfValuePointer }
|
|
|
|
function TFpDwarfValuePointer.GetAsCardinal: QWord;
|
|
var
|
|
a: TFpDbgMemLocation;
|
|
begin
|
|
a := GetDataAddress;
|
|
if IsTargetAddr(a) then
|
|
Result := LocToAddr(a)
|
|
else
|
|
Result := 0;
|
|
end;
|
|
|
|
function TFpDwarfValuePointer.GetFieldFlags: TFpDbgValueFieldFlags;
|
|
var
|
|
t: TFpDbgSymbol;
|
|
begin
|
|
Result := inherited GetFieldFlags;
|
|
//TODO: svfDataAddress should depend on (hidden) Pointer or Ref in the TypeInfo
|
|
Result := Result + [svfCardinal, svfOrdinal, svfSizeOfPointer, svfDataAddress] - [svfSize]; // data address
|
|
|
|
t := TypeInfo;
|
|
if (t <> nil) then t := t.TypeInfo;
|
|
if (t <> nil) and (t.Kind = skChar) and IsReadableMem(DataAddress) then // pchar
|
|
Result := Result + [svfString]; // data address
|
|
end;
|
|
|
|
function TFpDwarfValuePointer.GetDataAddress: TFpDbgMemLocation;
|
|
begin
|
|
if doneAddr in FEvaluated then begin
|
|
Result := FPointetToAddr;
|
|
exit;
|
|
end;
|
|
Include(FEvaluated, doneAddr);
|
|
|
|
if (FSize <= 0) then
|
|
Result := InvalidLoc
|
|
else
|
|
begin
|
|
if not MemManager.ReadAddress(OrdOrDataAddr, FSize, Result) then
|
|
FLastError := MemManager.LastError;
|
|
end;
|
|
|
|
FPointetToAddr := Result;
|
|
end;
|
|
|
|
function TFpDwarfValuePointer.GetAsString: AnsiString;
|
|
var
|
|
t: TFpDbgSymbol;
|
|
i: Integer;
|
|
begin
|
|
t := TypeInfo;
|
|
if (t <> nil) then t := t.TypeInfo;
|
|
if (MemManager <> nil) and (t <> nil) and (t.Kind = skChar) and IsReadableMem(DataAddress) then begin // pchar
|
|
SetLength(Result, 2000);
|
|
i := 2000;
|
|
while (i > 0) and (not MemManager.ReadMemory(DataAddress, 2000, @Result[1])) do
|
|
i := i div 2;
|
|
SetLength(Result,i);
|
|
i := pos(#0, Result);
|
|
if i > 0 then
|
|
SetLength(Result,i-1);
|
|
exit;
|
|
end;
|
|
|
|
Result := inherited GetAsString;
|
|
end;
|
|
|
|
function TFpDwarfValuePointer.GetMember(AIndex: Int64): TFpDbgValue;
|
|
var
|
|
ti: TFpDbgSymbol;
|
|
addr: TFpDbgMemLocation;
|
|
Tmp: TFpDwarfValueConstAddress;
|
|
begin
|
|
//TODO: ?? if no TypeInfo.TypeInfo;, then return TFpDwarfValueConstAddress.Create(addr); (for mem dump)
|
|
Result := nil;
|
|
ReleaseRefAndNil(FLastAddrMember);
|
|
if (TypeInfo = nil) then begin // TODO dedicanted error code
|
|
FLastError := CreateError(fpErrAnyError, ['Can not dereference an untyped pointer']);
|
|
exit;
|
|
end;
|
|
|
|
// TODO re-use last member
|
|
|
|
ti := TypeInfo.TypeInfo;
|
|
{$PUSH}{$R-}{$Q-} // TODO: check overflow
|
|
if ti <> nil then
|
|
AIndex := AIndex * ti.Size;
|
|
addr := DataAddress;
|
|
if not IsTargetAddr(addr) then begin
|
|
FLastError := CreateError(fpErrAnyError, ['Internal dereference error']);
|
|
exit;
|
|
end;
|
|
addr.Address := addr.Address + AIndex;
|
|
{$POP}
|
|
|
|
Tmp := TFpDwarfValueConstAddress.Create(addr);
|
|
if ti <> nil then begin
|
|
Result := ti.TypeCastValue(Tmp);
|
|
Tmp.ReleaseReference;
|
|
SetLastMember(TFpDwarfValue(Result));
|
|
Result.ReleaseReference;
|
|
end
|
|
else begin
|
|
Result := Tmp;
|
|
FLastAddrMember := Result;
|
|
end;
|
|
end;
|
|
|
|
destructor TFpDwarfValuePointer.Destroy;
|
|
begin
|
|
FLastAddrMember.ReleaseReference;
|
|
inherited Destroy;
|
|
end;
|
|
|
|
{ TFpDwarfValueEnum }
|
|
|
|
procedure TFpDwarfValueEnum.InitMemberIndex;
|
|
var
|
|
v: QWord;
|
|
i: Integer;
|
|
begin
|
|
// TODO: if TypeInfo is a subrange, check against the bounds, then bypass it, and scan all members (avoid subrange scanning members)
|
|
if FMemberValueDone then exit;
|
|
// FTypeCastTargetType (if not nil) must be same as FOwner. It may have wrappers like declaration.
|
|
v := GetAsCardinal;
|
|
i := FOwner.MemberCount - 1;
|
|
while i >= 0 do begin
|
|
if FOwner.Member[i].OrdinalValue = v then break;
|
|
dec(i);
|
|
end;
|
|
FMemberIndex := i;
|
|
FMemberValueDone := True;
|
|
end;
|
|
|
|
procedure TFpDwarfValueEnum.Reset;
|
|
begin
|
|
inherited Reset;
|
|
FMemberValueDone := False;
|
|
end;
|
|
|
|
function TFpDwarfValueEnum.GetFieldFlags: TFpDbgValueFieldFlags;
|
|
begin
|
|
Result := inherited GetFieldFlags;
|
|
Result := Result + [svfOrdinal, svfMembers, svfIdentifier];
|
|
end;
|
|
|
|
function TFpDwarfValueEnum.GetAsCardinal: QWord;
|
|
begin
|
|
if doneUInt in FEvaluated then begin
|
|
Result := FValue;
|
|
exit;
|
|
end;
|
|
Include(FEvaluated, doneUInt);
|
|
|
|
if (FSize <= 0) or (FSize > SizeOf(Result)) then
|
|
Result := inherited GetAsCardinal
|
|
else
|
|
if not MemManager.ReadEnum(OrdOrDataAddr, FSize, Result) then begin
|
|
FLastError := MemManager.LastError;
|
|
Result := 0; // TODO: error
|
|
end;
|
|
|
|
FValue := Result;
|
|
end;
|
|
|
|
function TFpDwarfValueEnum.GetAsString: AnsiString;
|
|
begin
|
|
InitMemberIndex;
|
|
if FMemberIndex >= 0 then
|
|
Result := FOwner.Member[FMemberIndex].Name
|
|
else
|
|
Result := '';
|
|
end;
|
|
|
|
function TFpDwarfValueEnum.GetMemberCount: Integer;
|
|
begin
|
|
InitMemberIndex;
|
|
if FMemberIndex < 0 then
|
|
Result := 0
|
|
else
|
|
Result := 1;
|
|
end;
|
|
|
|
function TFpDwarfValueEnum.GetMember(AIndex: Int64): TFpDbgValue;
|
|
begin
|
|
InitMemberIndex;
|
|
if (FMemberIndex >= 0) and (AIndex = 0) then
|
|
Result := FOwner.Member[FMemberIndex].Value
|
|
else
|
|
Result := nil;
|
|
end;
|
|
|
|
{ TFpDwarfValueEnumMember }
|
|
|
|
function TFpDwarfValueEnumMember.GetFieldFlags: TFpDbgValueFieldFlags;
|
|
begin
|
|
Result := inherited GetFieldFlags;
|
|
Result := Result + [svfOrdinal, svfIdentifier];
|
|
end;
|
|
|
|
function TFpDwarfValueEnumMember.GetAsCardinal: QWord;
|
|
begin
|
|
Result := FOwnerVal.OrdinalValue;
|
|
end;
|
|
|
|
function TFpDwarfValueEnumMember.GetAsString: AnsiString;
|
|
begin
|
|
Result := FOwnerVal.Name;
|
|
end;
|
|
|
|
function TFpDwarfValueEnumMember.IsValidTypeCast: Boolean;
|
|
begin
|
|
assert(False, 'TDbgDwarfEnumMemberSymbolValue.IsValidTypeCast can not be returned for typecast');
|
|
Result := False;
|
|
end;
|
|
|
|
constructor TFpDwarfValueEnumMember.Create(AOwner: TFpDwarfSymbolValue);
|
|
begin
|
|
FOwnerVal := AOwner;
|
|
inherited Create(nil);
|
|
end;
|
|
|
|
{ TFpDwarfValueConstNumber }
|
|
|
|
procedure TFpDwarfValueConstNumber.Update(AValue: QWord; ASigned: Boolean);
|
|
begin
|
|
Signed := ASigned;
|
|
Value := AValue;
|
|
end;
|
|
|
|
{ TFpDwarfValueSet }
|
|
|
|
procedure TFpDwarfValueSet.InitMap;
|
|
const
|
|
BitCount: array[0..15] of byte = (0, 1, 1, 2, 1, 2, 2, 3, 1, 2, 2, 3, 2, 3, 3, 4);
|
|
var
|
|
i, i2, v, MemIdx, Bit, Cnt: Integer;
|
|
|
|
t: TFpDbgSymbol;
|
|
begin
|
|
if (length(FMem) > 0) or (FSize <= 0) then
|
|
exit;
|
|
t := TypeInfo;
|
|
if t = nil then exit;
|
|
t := t.TypeInfo;
|
|
if t = nil then exit;
|
|
|
|
if not MemManager.ReadSet(DataAddr, FSize, FMem) then begin
|
|
FLastError := MemManager.LastError;
|
|
exit; // TODO: error
|
|
end;
|
|
|
|
Cnt := 0;
|
|
for i := 0 to FSize - 1 do
|
|
Cnt := Cnt + (BitCount[FMem[i] and 15]) + (BitCount[(FMem[i] div 16) and 15]);
|
|
FMemberCount := Cnt;
|
|
|
|
if (Cnt = 0) then exit;
|
|
SetLength(FMemberMap, Cnt);
|
|
|
|
if (t.Kind = skEnum) then begin
|
|
i2 := 0;
|
|
for i := 0 to t.MemberCount - 1 do
|
|
begin
|
|
v := t.Member[i].OrdinalValue;
|
|
MemIdx := v shr 3;
|
|
Bit := 1 shl (v and 7);
|
|
if (FMem[MemIdx] and Bit) <> 0 then begin
|
|
assert(i2 < Cnt, 'TDbgDwarfSetSymbolValue.InitMap too many members');
|
|
if i2 = Cnt then break;
|
|
FMemberMap[i2] := i;
|
|
inc(i2);
|
|
end;
|
|
end;
|
|
|
|
if i2 < Cnt then begin
|
|
FMemberCount := i2;
|
|
debugln(FPDBG_DWARF_DATA_WARNINGS, ['TDbgDwarfSetSymbolValue.InitMap not enough members']);
|
|
end;
|
|
end
|
|
else begin
|
|
i2 := 0;
|
|
MemIdx := 0;
|
|
Bit := 1;
|
|
v := t.OrdLowBound;
|
|
for i := v to t.OrdHighBound do
|
|
begin
|
|
if (FMem[MemIdx] and Bit) <> 0 then begin
|
|
assert(i2 < Cnt, 'TDbgDwarfSetSymbolValue.InitMap too many members');
|
|
if i2 = Cnt then break;
|
|
FMemberMap[i2] := i - v; // offset from low-bound
|
|
inc(i2);
|
|
end;
|
|
if Bit = 128 then begin
|
|
Bit := 1;
|
|
inc(MemIdx);
|
|
end
|
|
else
|
|
Bit := Bit shl 1;
|
|
end;
|
|
|
|
if i2 < Cnt then begin
|
|
FMemberCount := i2;
|
|
debugln(FPDBG_DWARF_DATA_WARNINGS, ['TDbgDwarfSetSymbolValue.InitMap not enough members']);
|
|
end;
|
|
end;
|
|
|
|
end;
|
|
|
|
procedure TFpDwarfValueSet.Reset;
|
|
begin
|
|
inherited Reset;
|
|
SetLength(FMem, 0);
|
|
end;
|
|
|
|
function TFpDwarfValueSet.GetFieldFlags: TFpDbgValueFieldFlags;
|
|
begin
|
|
Result := inherited GetFieldFlags;
|
|
Result := Result + [svfMembers];
|
|
if FSize <= 8 then
|
|
Result := Result + [svfOrdinal];
|
|
end;
|
|
|
|
function TFpDwarfValueSet.GetMemberCount: Integer;
|
|
begin
|
|
InitMap;
|
|
Result := FMemberCount;
|
|
end;
|
|
|
|
function TFpDwarfValueSet.GetMember(AIndex: Int64): TFpDbgValue;
|
|
var
|
|
t: TFpDbgSymbol;
|
|
begin
|
|
Result := nil;
|
|
InitMap;
|
|
t := TypeInfo;
|
|
if t = nil then exit;
|
|
t := t.TypeInfo;
|
|
if t = nil then exit;
|
|
assert(t is TFpDwarfSymbolType, 'TDbgDwarfSetSymbolValue.GetMember t');
|
|
|
|
if t.Kind = skEnum then begin
|
|
Result := t.Member[FMemberMap[AIndex]].Value;
|
|
end
|
|
else begin
|
|
if (FNumValue = nil) or (FNumValue.RefCount > 1) then // refcount 1 by FTypedNumValue
|
|
FNumValue := TFpDwarfValueConstNumber.Create(FMemberMap[AIndex] + t.OrdLowBound, t.Kind = skInteger)
|
|
else
|
|
begin
|
|
FNumValue.Update(FMemberMap[AIndex] + t.OrdLowBound, t.Kind = skInteger);
|
|
FNumValue.AddReference;
|
|
end;
|
|
|
|
if (FTypedNumValue = nil) or (FTypedNumValue.RefCount > 1) then begin
|
|
FTypedNumValue.ReleaseReference;
|
|
FTypedNumValue := t.TypeCastValue(FNumValue)
|
|
end
|
|
else
|
|
TFpDwarfValue(FTypedNumValue).SetTypeCastInfo(TFpDwarfSymbolType(t), FNumValue); // update
|
|
FNumValue.ReleaseReference;
|
|
Assert((FTypedNumValue <> nil) and (TFpDwarfValue(FTypedNumValue).IsValidTypeCast), 'TDbgDwarfSetSymbolValue.GetMember FTypedNumValue');
|
|
Assert((FNumValue <> nil) and (FNumValue.RefCount > 0), 'TDbgDwarfSetSymbolValue.GetMember FNumValue');
|
|
Result := FTypedNumValue;
|
|
end;
|
|
end;
|
|
|
|
function TFpDwarfValueSet.GetAsCardinal: QWord;
|
|
begin
|
|
Result := 0;
|
|
if (FSize <= SizeOf(Result)) and (length(FMem) > 0) then
|
|
move(FMem[0], Result, FSize);
|
|
end;
|
|
|
|
function TFpDwarfValueSet.IsValidTypeCast: Boolean;
|
|
var
|
|
f: TFpDbgValueFieldFlags;
|
|
begin
|
|
Result := HasTypeCastInfo;
|
|
If not Result then
|
|
exit;
|
|
|
|
assert(FTypeCastTargetType.Kind = skSet, 'TFpDwarfValueSet.IsValidTypeCast: FTypeCastTargetType.Kind = skSet');
|
|
|
|
if (FTypeCastSourceValue.TypeInfo = FTypeCastTargetType)
|
|
then
|
|
exit; // pointer deref
|
|
|
|
f := FTypeCastSourceValue.FieldFlags;
|
|
if (f * [svfAddress, svfSize, svfSizeOfPointer] = [svfAddress]) then
|
|
exit;
|
|
|
|
if (f * [svfAddress, svfSize] = [svfAddress, svfSize]) and
|
|
(FTypeCastSourceValue.Size = FTypeCastTargetType.Size)
|
|
then
|
|
exit;
|
|
|
|
Result := False;
|
|
end;
|
|
|
|
destructor TFpDwarfValueSet.Destroy;
|
|
begin
|
|
FTypedNumValue.ReleaseReference;
|
|
inherited Destroy;
|
|
end;
|
|
|
|
{ TFpDwarfValueStruct }
|
|
|
|
procedure TFpDwarfValueStruct.Reset;
|
|
begin
|
|
inherited Reset;
|
|
FDataAddressDone := False;
|
|
end;
|
|
|
|
function TFpDwarfValueStruct.GetFieldFlags: TFpDbgValueFieldFlags;
|
|
begin
|
|
Result := inherited GetFieldFlags;
|
|
Result := Result + [svfMembers];
|
|
|
|
//TODO: svfDataAddress should depend on (hidden) Pointer or Ref in the TypeInfo
|
|
if Kind in [skClass] then begin
|
|
Result := Result + [svfOrdinal, svfDataAddress, svfDataSize]; // svfDataSize
|
|
if (FValueSymbol <> nil) and FValueSymbol.HasAddress then
|
|
Result := Result + [svfSizeOfPointer];
|
|
end
|
|
else begin
|
|
Result := Result + [svfSize];
|
|
end;
|
|
end;
|
|
|
|
function TFpDwarfValueStruct.GetAsCardinal: QWord;
|
|
begin
|
|
Result := QWord(LocToAddrOrNil(DataAddress));
|
|
end;
|
|
|
|
function TFpDwarfValueStruct.GetDataAddress: TFpDbgMemLocation;
|
|
var
|
|
t: TFpDbgMemLocation;
|
|
begin
|
|
if FValueSymbol <> nil then begin
|
|
if not FDataAddressDone then begin
|
|
FDataAddress := InvalidLoc;
|
|
FValueSymbol.GetValueAddress(Self, t);
|
|
assert(SizeOf(FDataAddress) >= AddressSize, 'TDbgDwarfStructSymbolValue.GetDataAddress');
|
|
if (MemManager <> nil) then begin
|
|
FDataAddress := MemManager.ReadAddress(t, AddressSize);
|
|
if not IsValidLoc(FDataAddress) then
|
|
FLastError := MemManager.LastError;
|
|
end;
|
|
FDataAddressDone := True;
|
|
end;
|
|
Result := FDataAddress;
|
|
end
|
|
else
|
|
Result := inherited GetDataAddress;
|
|
end;
|
|
|
|
function TFpDwarfValueStruct.GetDataSize: Integer;
|
|
begin
|
|
Assert((FValueSymbol = nil) or (FValueSymbol.TypeInfo is TFpDwarfSymbol));
|
|
if (FValueSymbol <> nil) and (FValueSymbol.TypeInfo <> nil) then
|
|
if FValueSymbol.TypeInfo.Kind = skClass then
|
|
Result := TFpDwarfSymbol(FValueSymbol.TypeInfo).DataSize
|
|
else
|
|
Result := FValueSymbol.TypeInfo.Size
|
|
else
|
|
Result := -1;
|
|
end;
|
|
|
|
function TFpDwarfValueStruct.GetSize: Integer;
|
|
begin
|
|
if (Kind <> skClass) and (FValueSymbol <> nil) and (FValueSymbol.TypeInfo <> nil) then
|
|
Result := FValueSymbol.TypeInfo.Size
|
|
else
|
|
Result := -1;
|
|
end;
|
|
|
|
{ TFpDwarfValueStructTypeCast }
|
|
|
|
procedure TFpDwarfValueStructTypeCast.Reset;
|
|
begin
|
|
inherited Reset;
|
|
FDataAddressDone := False;
|
|
end;
|
|
|
|
function TFpDwarfValueStructTypeCast.GetFieldFlags: TFpDbgValueFieldFlags;
|
|
begin
|
|
Result := inherited GetFieldFlags;
|
|
Result := Result + [svfMembers];
|
|
if kind = skClass then // todo detect hidden pointer
|
|
Result := Result + [svfDataSize]
|
|
else
|
|
Result := Result + [svfSize];
|
|
|
|
//TODO: svfDataAddress should depend on (hidden) Pointer or Ref in the TypeInfo
|
|
if Kind in [skClass] then
|
|
Result := Result + [svfOrdinal, svfDataAddress, svfSizeOfPointer]; // svfDataSize
|
|
end;
|
|
|
|
function TFpDwarfValueStructTypeCast.GetKind: TDbgSymbolKind;
|
|
begin
|
|
if HasTypeCastInfo then
|
|
Result := FTypeCastTargetType.Kind
|
|
else
|
|
Result := inherited GetKind;
|
|
end;
|
|
|
|
function TFpDwarfValueStructTypeCast.GetAsCardinal: QWord;
|
|
begin
|
|
Result := QWord(LocToAddrOrNil(DataAddress));
|
|
end;
|
|
|
|
function TFpDwarfValueStructTypeCast.GetSize: Integer;
|
|
begin
|
|
if (Kind <> skClass) and (FTypeCastTargetType <> nil) then
|
|
Result := FTypeCastTargetType.Size
|
|
else
|
|
Result := -1;
|
|
end;
|
|
|
|
function TFpDwarfValueStructTypeCast.GetDataSize: Integer;
|
|
begin
|
|
Assert((FTypeCastTargetType = nil) or (FTypeCastTargetType is TFpDwarfSymbol));
|
|
if FTypeCastTargetType <> nil then
|
|
if FTypeCastTargetType.Kind = skClass then
|
|
Result := TFpDwarfSymbol(FTypeCastTargetType).DataSize
|
|
else
|
|
Result := FTypeCastTargetType.Size
|
|
else
|
|
Result := -1;
|
|
end;
|
|
|
|
function TFpDwarfValueStructTypeCast.GetDataAddress: TFpDbgMemLocation;
|
|
var
|
|
fields: TFpDbgValueFieldFlags;
|
|
t: TFpDbgMemLocation;
|
|
begin
|
|
if HasTypeCastInfo then begin
|
|
if not FDataAddressDone then begin
|
|
// TODO: wrong for records // use GetDwarfDataAddress
|
|
fields := FTypeCastSourceValue.FieldFlags;
|
|
if svfOrdinal in fields then
|
|
FDataAddress := TargetLoc(TDbgPtr(FTypeCastSourceValue.AsCardinal))
|
|
else
|
|
if svfAddress in fields then begin
|
|
FDataAddress := InvalidLoc;
|
|
t := FTypeCastSourceValue.Address;
|
|
assert(SizeOf(FDataAddress) >= AddressSize, 'TDbgDwarfStructSymbolValue.GetDataAddress');
|
|
if (MemManager <> nil) then begin
|
|
FDataAddress := MemManager.ReadAddress(t, AddressSize);
|
|
if not IsValidLoc(FDataAddress) then
|
|
FLastError := MemManager.LastError;
|
|
end;
|
|
end;
|
|
FDataAddressDone := True;
|
|
end;
|
|
Result := FDataAddress;
|
|
end
|
|
else
|
|
Result := inherited GetDataAddress;
|
|
end;
|
|
|
|
function TFpDwarfValueStructTypeCast.IsValidTypeCast: Boolean;
|
|
var
|
|
f: TFpDbgValueFieldFlags;
|
|
begin
|
|
Result := HasTypeCastInfo;
|
|
if not Result then
|
|
exit;
|
|
|
|
if FTypeCastTargetType.Kind = skClass then begin
|
|
f := FTypeCastSourceValue.FieldFlags;
|
|
Result := (svfOrdinal in f); // ordinal is prefered in GetDataAddress
|
|
if Result then
|
|
exit;
|
|
Result := (svfAddress in f) and
|
|
( ( not(svfSize in f) ) or // either svfSizeOfPointer or a void type, e.g. pointer(1)^
|
|
( (svfSize in f) and (FTypeCastSourceValue.Size = AddressSize) )
|
|
);
|
|
end
|
|
else begin
|
|
f := FTypeCastSourceValue.FieldFlags;
|
|
if (f * [{svfOrdinal, }svfAddress] = [svfAddress]) then begin
|
|
if (f * [svfSize, svfSizeOfPointer]) = [svfSize] then
|
|
Result := Result and (FTypeCastTargetType.Size = FTypeCastSourceValue.Size)
|
|
else
|
|
if (f * [svfSize, svfSizeOfPointer]) = [svfSizeOfPointer] then
|
|
Result := Result and (FTypeCastTargetType.Size = AddressSize)
|
|
else
|
|
Result := (f * [svfSize, svfSizeOfPointer]) = []; // source is a void type, e.g. pointer(1)^
|
|
end
|
|
else
|
|
Result := False;
|
|
end;
|
|
end;
|
|
|
|
destructor TFpDwarfValueStructTypeCast.Destroy;
|
|
begin
|
|
FreeAndNil(FMembers);
|
|
inherited Destroy;
|
|
end;
|
|
|
|
function TFpDwarfValueStructTypeCast.GetMemberByName(AIndex: String): TFpDbgValue;
|
|
var
|
|
tmp: TFpDbgSymbol;
|
|
begin
|
|
Result := nil;
|
|
if not HasTypeCastInfo then
|
|
exit;
|
|
|
|
tmp := FTypeCastTargetType.MemberByName[AIndex];
|
|
if (tmp <> nil) then begin
|
|
assert((tmp is TFpDwarfSymbolValue), 'TDbgDwarfStructTypeCastSymbolValue.GetMemberByName'+DbgSName(tmp));
|
|
if FMembers = nil then
|
|
FMembers := TFpDbgCircularRefCntObjList.Create;
|
|
FMembers.Add(tmp);
|
|
|
|
Result := tmp.Value;
|
|
end;
|
|
SetLastMember(TFpDwarfValue(Result));
|
|
end;
|
|
|
|
function TFpDwarfValueStructTypeCast.GetMember(AIndex: Int64): TFpDbgValue;
|
|
var
|
|
tmp: TFpDbgSymbol;
|
|
begin
|
|
Result := nil;
|
|
if not HasTypeCastInfo then
|
|
exit;
|
|
|
|
// TODO: Why store them all in list? They are hold by the type
|
|
tmp := FTypeCastTargetType.Member[AIndex];
|
|
if (tmp <> nil) then begin
|
|
assert((tmp is TFpDwarfSymbolValue), 'TDbgDwarfStructTypeCastSymbolValue.GetMemberByName'+DbgSName(tmp));
|
|
if FMembers = nil then
|
|
FMembers := TFpDbgCircularRefCntObjList.Create;
|
|
FMembers.Add(tmp);
|
|
|
|
Result := tmp.Value;
|
|
end;
|
|
SetLastMember(TFpDwarfValue(Result));
|
|
end;
|
|
|
|
function TFpDwarfValueStructTypeCast.GetMemberCount: Integer;
|
|
var
|
|
ti: TFpDbgSymbol;
|
|
begin
|
|
Result := 0;
|
|
if not HasTypeCastInfo then
|
|
exit;
|
|
|
|
Result := FTypeCastTargetType.MemberCount;
|
|
|
|
ti := FTypeCastTargetType;
|
|
//TODO: cache result
|
|
if ti.Kind in [skClass, skObject] then
|
|
while ti.TypeInfo <> nil do begin
|
|
ti := ti.TypeInfo;
|
|
Result := Result + ti.MemberCount;
|
|
end;
|
|
end;
|
|
|
|
{ TFpDwarfValueConstAddress }
|
|
|
|
procedure TFpDwarfValueConstAddress.Update(AnAddress: TFpDbgMemLocation);
|
|
begin
|
|
Address := AnAddress;
|
|
end;
|
|
|
|
{ TFpDwarfValueArray }
|
|
|
|
function TFpDwarfValueArray.GetFieldFlags: TFpDbgValueFieldFlags;
|
|
begin
|
|
Result := inherited GetFieldFlags;
|
|
Result := Result + [svfMembers];
|
|
if (TypeInfo <> nil) and (sfDynArray in TypeInfo.Flags) then
|
|
Result := Result + [svfOrdinal, svfDataAddress];
|
|
end;
|
|
|
|
function TFpDwarfValueArray.GetKind: TDbgSymbolKind;
|
|
begin
|
|
Result := skArray;
|
|
end;
|
|
|
|
function TFpDwarfValueArray.GetAsCardinal: QWord;
|
|
begin
|
|
// TODO cache
|
|
if not MemManager.ReadUnsignedInt(OrdOrAddress, AddressSize, Result) then begin
|
|
FLastError := MemManager.LastError;
|
|
Result := 0;
|
|
end;
|
|
end;
|
|
|
|
function TFpDwarfValueArray.GetDataAddress: TFpDbgMemLocation;
|
|
begin
|
|
Result := OrdOrDataAddr;
|
|
end;
|
|
|
|
function TFpDwarfValueArray.GetMember(AIndex: Int64): TFpDbgValue;
|
|
begin
|
|
Result := GetMemberEx([AIndex]);
|
|
end;
|
|
|
|
function TFpDwarfValueArray.GetMemberEx(AIndex: array of Int64): TFpDbgValue;
|
|
var
|
|
Addr: TFpDbgMemLocation;
|
|
i: Integer;
|
|
begin
|
|
Result := nil;
|
|
assert((FOwner is TFpDwarfSymbolTypeArray) and (FOwner.Kind = skArray));
|
|
Addr := TFpDwarfSymbolTypeArray(FOwner).GetMemberAddress(Self, AIndex);
|
|
if not IsReadableLoc(Addr) then exit;
|
|
|
|
// FAddrObj.RefCount: hold by self
|
|
i := 1;
|
|
// FAddrObj.RefCount: hold by FLastMember (ignore only, if FLastMember is not hold by others)
|
|
if (FLastMember <> nil) and (FLastMember.RefCount = 1) then
|
|
i := 2;
|
|
if (FAddrObj = nil) or (FAddrObj.RefCount > i) then begin
|
|
FAddrObj.ReleaseReference{$IFDEF WITH_REFCOUNT_DEBUG}(@FAddrObj, 'TDbgDwarfArraySymbolValue'){$ENDIF};
|
|
FAddrObj := TFpDwarfValueConstAddress.Create(Addr);
|
|
{$IFDEF WITH_REFCOUNT_DEBUG}FAddrObj.DbgRenameReference(@FAddrObj, 'TDbgDwarfArraySymbolValue');{$ENDIF}
|
|
end
|
|
else begin
|
|
FAddrObj.Update(Addr);
|
|
end;
|
|
|
|
if (FLastMember = nil) or (FLastMember.RefCount > 1) then begin
|
|
SetLastMember(TFpDwarfValue(FOwner.TypeInfo.TypeCastValue(FAddrObj)));
|
|
FLastMember.ReleaseReference;
|
|
end
|
|
else begin
|
|
TFpDwarfValue(FLastMember).SetTypeCastInfo(TFpDwarfSymbolType(FOwner.TypeInfo), FAddrObj);
|
|
end;
|
|
|
|
Result := FLastMember;
|
|
end;
|
|
|
|
function TFpDwarfValueArray.GetMemberCount: Integer;
|
|
var
|
|
t, t2: TFpDbgSymbol;
|
|
Addr: TFpDbgMemLocation;
|
|
LowBound, HighBound: int64;
|
|
i: Int64;
|
|
begin
|
|
Result := 0;
|
|
t := TypeInfo;
|
|
if t.MemberCount < 1 then // IndexTypeCount;
|
|
exit;
|
|
t2 := t.Member[0]; // IndexType[0];
|
|
if not ((t2 is TFpDwarfSymbolType) and (TFpDwarfSymbolType(t2).GetValueBounds(self, LowBound, HighBound))) and
|
|
not t2.HasBounds then begin
|
|
if (sfDynArray in t.Flags) and (AsCardinal <> 0) and
|
|
GetDwarfDataAddress(Addr, TFpDwarfSymbolType(FOwner))
|
|
then begin
|
|
if not (IsReadableMem(Addr) and (LocToAddr(Addr) > 4)) then
|
|
exit;
|
|
Addr.Address := Addr.Address - AddressSize;
|
|
if MemManager.ReadSignedInt(Addr, 4, i) then begin
|
|
Result := Integer(i)+1;
|
|
exit;
|
|
end
|
|
else
|
|
FLastError := MemManager.LastError;
|
|
end;
|
|
exit;
|
|
end;
|
|
if t2.HasBounds then
|
|
Result := Integer(t2.OrdHighBound - t2.OrdLowBound + 1);
|
|
end;
|
|
|
|
function TFpDwarfValueArray.GetMemberCountEx(AIndex: array of Int64): Integer;
|
|
var
|
|
t: TFpDbgSymbol;
|
|
begin
|
|
Result := 0;
|
|
t := TypeInfo;
|
|
if length(AIndex) >= t.MemberCount then
|
|
exit;
|
|
t := t.Member[length(AIndex)];
|
|
if not t.HasBounds then
|
|
exit;
|
|
Result := t.OrdHighBound - t.OrdLowBound + 1;
|
|
end;
|
|
|
|
function TFpDwarfValueArray.GetIndexType(AIndex: Integer): TFpDbgSymbol;
|
|
begin
|
|
Result := TypeInfo.Member[AIndex];
|
|
end;
|
|
|
|
function TFpDwarfValueArray.GetIndexTypeCount: Integer;
|
|
begin
|
|
Result := TypeInfo.MemberCount;
|
|
end;
|
|
|
|
function TFpDwarfValueArray.IsValidTypeCast: Boolean;
|
|
var
|
|
f: TFpDbgValueFieldFlags;
|
|
begin
|
|
Result := HasTypeCastInfo;
|
|
If not Result then
|
|
exit;
|
|
|
|
assert(FTypeCastTargetType.Kind = skArray, 'TFpDwarfValueArray.IsValidTypeCast: FTypeCastTargetType.Kind = skArray');
|
|
//TODO: shortcut, if FTypeCastTargetType = FTypeCastSourceValue.TypeInfo ?
|
|
|
|
f := FTypeCastSourceValue.FieldFlags;
|
|
if (f * [svfAddress, svfSize, svfSizeOfPointer] = [svfAddress]) then
|
|
exit;
|
|
|
|
if sfDynArray in FTypeCastTargetType.Flags then begin
|
|
// dyn array
|
|
if (svfOrdinal in f)then
|
|
exit;
|
|
if (f * [svfAddress, svfSize] = [svfAddress, svfSize]) and
|
|
(FTypeCastSourceValue.Size = FOwner.CompilationUnit.AddressSize)
|
|
then
|
|
exit;
|
|
if (f * [svfAddress, svfSizeOfPointer] = [svfAddress, svfSizeOfPointer]) then
|
|
exit;
|
|
end
|
|
else begin
|
|
// stat array
|
|
if (f * [svfAddress, svfSize] = [svfAddress, svfSize]) and
|
|
(FTypeCastSourceValue.Size = FTypeCastTargetType.Size)
|
|
then
|
|
exit;
|
|
end;
|
|
Result := False;
|
|
end;
|
|
|
|
destructor TFpDwarfValueArray.Destroy;
|
|
begin
|
|
FAddrObj.ReleaseReference{$IFDEF WITH_REFCOUNT_DEBUG}(@FAddrObj, 'TDbgDwarfArraySymbolValue'){$ENDIF};
|
|
inherited Destroy;
|
|
end;
|
|
|
|
{ TDbgDwarfIdentifier }
|
|
|
|
function TFpDwarfSymbol.GetNestedTypeInfo: TFpDwarfSymbolType;
|
|
begin
|
|
// TODO DW_AT_start_scope;
|
|
Result := FNestedTypeInfo;
|
|
if (Result <> nil) or (didtTypeRead in FDwarfReadFlags) then
|
|
exit;
|
|
|
|
include(FDwarfReadFlags, didtTypeRead);
|
|
FNestedTypeInfo := DoGetNestedTypeInfo;
|
|
Result := FNestedTypeInfo;
|
|
end;
|
|
|
|
procedure TFpDwarfSymbol.SetParentTypeInfo(AValue: TFpDwarfSymbol);
|
|
begin
|
|
if FParentTypeInfo = AValue then exit;
|
|
|
|
if (FParentTypeInfo <> nil) and CircleBackRefsActive then
|
|
FParentTypeInfo.ReleaseReference{$IFDEF WITH_REFCOUNT_DEBUG}(@FParentTypeInfo, 'FParentTypeInfo'){$ENDIF};
|
|
|
|
FParentTypeInfo := AValue;
|
|
|
|
if (FParentTypeInfo <> nil) and CircleBackRefsActive then
|
|
FParentTypeInfo.AddReference{$IFDEF WITH_REFCOUNT_DEBUG}(@FParentTypeInfo, 'FParentTypeInfo'){$ENDIF};
|
|
end;
|
|
|
|
procedure TFpDwarfSymbol.DoReferenceAdded;
|
|
begin
|
|
inherited DoReferenceAdded;
|
|
DoPlainReferenceAdded;
|
|
end;
|
|
|
|
procedure TFpDwarfSymbol.DoReferenceReleased;
|
|
begin
|
|
inherited DoReferenceReleased;
|
|
DoPlainReferenceReleased;
|
|
end;
|
|
|
|
procedure TFpDwarfSymbol.CircleBackRefActiveChanged(ANewActive: Boolean);
|
|
begin
|
|
if (FParentTypeInfo = nil) then
|
|
exit;
|
|
if ANewActive then
|
|
FParentTypeInfo.AddReference{$IFDEF WITH_REFCOUNT_DEBUG}(@FParentTypeInfo, 'FParentTypeInfo'){$ENDIF}
|
|
else
|
|
FParentTypeInfo.ReleaseReference{$IFDEF WITH_REFCOUNT_DEBUG}(@FParentTypeInfo, 'FParentTypeInfo'){$ENDIF};
|
|
end;
|
|
|
|
function TFpDwarfSymbol.DoGetNestedTypeInfo: TFpDwarfSymbolType;
|
|
var
|
|
FwdInfoPtr: Pointer;
|
|
FwdCompUint: TDwarfCompilationUnit;
|
|
InfoEntry: TDwarfInformationEntry;
|
|
begin // Do not access anything that may need forwardSymbol
|
|
if InformationEntry.ReadReference(DW_AT_type, FwdInfoPtr, FwdCompUint) then begin
|
|
InfoEntry := TDwarfInformationEntry.Create(FwdCompUint, FwdInfoPtr);
|
|
Result := TFpDwarfSymbolType.CreateTypeSubClass('', InfoEntry);
|
|
ReleaseRefAndNil(InfoEntry);
|
|
end
|
|
else
|
|
Result := nil;
|
|
end;
|
|
|
|
function TFpDwarfSymbol.ReadMemberVisibility(out
|
|
AMemberVisibility: TDbgSymbolMemberVisibility): Boolean;
|
|
var
|
|
Val: Integer;
|
|
begin
|
|
Result := InformationEntry.ReadValue(DW_AT_external, Val);
|
|
if Result and (Val <> 0) then begin
|
|
AMemberVisibility := svPublic;
|
|
exit;
|
|
end;
|
|
|
|
Result := InformationEntry.ReadValue(DW_AT_accessibility, Val);
|
|
if not Result then exit;
|
|
case Val of
|
|
DW_ACCESS_private: AMemberVisibility := svPrivate;
|
|
DW_ACCESS_protected: AMemberVisibility := svProtected;
|
|
DW_ACCESS_public: AMemberVisibility := svPublic;
|
|
else AMemberVisibility := svPrivate;
|
|
end;
|
|
end;
|
|
|
|
function TFpDwarfSymbol.IsArtificial: Boolean;
|
|
begin
|
|
if not(didtArtificialRead in FDwarfReadFlags) then begin
|
|
if InformationEntry.IsArtificial then
|
|
Include(FDwarfReadFlags, didtIsArtifical);
|
|
Include(FDwarfReadFlags, didtArtificialRead);
|
|
end;
|
|
Result := didtIsArtifical in FDwarfReadFlags;
|
|
end;
|
|
|
|
procedure TFpDwarfSymbol.NameNeeded;
|
|
var
|
|
AName: String;
|
|
begin
|
|
if InformationEntry.ReadName(AName) then
|
|
SetName(AName)
|
|
else
|
|
inherited NameNeeded;
|
|
end;
|
|
|
|
procedure TFpDwarfSymbol.TypeInfoNeeded;
|
|
begin
|
|
SetTypeInfo(NestedTypeInfo);
|
|
end;
|
|
|
|
function TFpDwarfSymbol.DataSize: Integer;
|
|
var
|
|
t: TFpDwarfSymbolType;
|
|
begin
|
|
t := NestedTypeInfo;
|
|
if t <> nil then
|
|
Result := t.DataSize
|
|
else
|
|
Result := 0;
|
|
end;
|
|
|
|
function TFpDwarfSymbol.InitLocationParser(const ALocationParser: TDwarfLocationExpression;
|
|
AnInitLocParserData: PInitLocParserData): Boolean;
|
|
begin
|
|
if (AnInitLocParserData <> nil) and IsValidLoc(AnInitLocParserData^.ObjectDataAddress)
|
|
then begin
|
|
if AnInitLocParserData^.ObjectDataAddrPush then begin
|
|
debugln(FPDBG_DWARF_VERBOSE, ['TFpDwarfSymbol.InitLocationParser Push=', dbgs(AnInitLocParserData^.ObjectDataAddress)]);
|
|
ALocationParser.Push(AnInitLocParserData^.ObjectDataAddress, lseValue);
|
|
end
|
|
else begin
|
|
debugln(FPDBG_DWARF_VERBOSE, ['TFpDwarfSymbol.InitLocationParser CurrentObjectAddress=', dbgs(AnInitLocParserData^.ObjectDataAddress)]);
|
|
ALocationParser.CurrentObjectAddress := AnInitLocParserData^.ObjectDataAddress;
|
|
end;
|
|
end;
|
|
|
|
Result := True;
|
|
end;
|
|
|
|
function TFpDwarfSymbol.LocationFromTag(ATag: Cardinal; AValueObj: TFpDwarfValue;
|
|
var AnAddress: TFpDbgMemLocation; AnInitLocParserData: PInitLocParserData;
|
|
AnInformationEntry: TDwarfInformationEntry; ASucessOnMissingTag: Boolean): Boolean;
|
|
var
|
|
Val: TByteDynArray;
|
|
LocationParser: TDwarfLocationExpression;
|
|
begin
|
|
//debugln(['TDbgDwarfIdentifier.LocationFromTag', ClassName, ' ',Name, ' ', DwarfAttributeToString(ATag)]);
|
|
|
|
Result := False;
|
|
if AnInformationEntry = nil then
|
|
AnInformationEntry := InformationEntry;
|
|
|
|
//TODO: avoid copying data
|
|
// DW_AT_data_member_location in members [ block or const]
|
|
// DW_AT_location [block or reference] todo: const
|
|
if not AnInformationEntry.ReadValue(ATag, Val) then begin
|
|
Result := ASucessOnMissingTag;
|
|
if not Result then
|
|
AnAddress := InvalidLoc;
|
|
if not Result then
|
|
DebugLn(['LocationFromTag: failed to read DW_AT_location / ASucessOnMissingTag=', dbgs(ASucessOnMissingTag)]);
|
|
exit;
|
|
end;
|
|
|
|
AnAddress := InvalidLoc;
|
|
if Length(Val) = 0 then begin
|
|
DebugLn('LocationFromTag: Warning DW_AT_location empty');
|
|
//exit;
|
|
end;
|
|
|
|
LocationParser := TDwarfLocationExpression.Create(@Val[0], Length(Val), CompilationUnit,
|
|
AValueObj.MemManager, AValueObj.Context);
|
|
InitLocationParser(LocationParser, AnInitLocParserData);
|
|
LocationParser.Evaluate;
|
|
|
|
if IsError(LocationParser.LastError) then
|
|
SetLastError(LocationParser.LastError);
|
|
|
|
if LocationParser.ResultKind in [lseValue] then begin
|
|
AnAddress := TargetLoc(LocationParser.ResultData);
|
|
if ATag=DW_AT_location then
|
|
AnAddress.Address :=CompilationUnit.MapAddressToNewValue(AnAddress.Address);
|
|
Result := True;
|
|
end
|
|
else
|
|
if LocationParser.ResultKind in [lseRegister] then begin
|
|
AnAddress := ConstLoc(LocationParser.ResultData);
|
|
Result := True;
|
|
end
|
|
else
|
|
debugln(['TDbgDwarfIdentifier.LocationFromTag FAILED']); // TODO
|
|
|
|
LocationParser.Free;
|
|
end;
|
|
|
|
function TFpDwarfSymbol.GetDataAddress(AValueObj: TFpDwarfValue;
|
|
var AnAddress: TFpDbgMemLocation; ATargetType: TFpDwarfSymbolType;
|
|
ATargetCacheIndex: Integer): Boolean;
|
|
var
|
|
ti: TFpDwarfSymbolType;
|
|
InitLocParserData: TInitLocParserData;
|
|
begin
|
|
InitLocParserData.ObjectDataAddress := AnAddress;
|
|
InitLocParserData.ObjectDataAddrPush := False;
|
|
Result := LocationFromTag(DW_AT_data_location, AValueObj, AnAddress, @InitLocParserData, nil, True);
|
|
if not Result then
|
|
exit;
|
|
|
|
|
|
if ATargetType = Self then begin
|
|
Result := True;
|
|
exit;
|
|
end;
|
|
|
|
|
|
//TODO: Handle AValueObj.DataAddressCache[ATargetCacheIndex];
|
|
Result := GetDataAddressNext(AValueObj, AnAddress, ATargetType, ATargetCacheIndex);
|
|
if not Result then
|
|
exit;
|
|
|
|
ti := NestedTypeInfo;
|
|
if ti <> nil then
|
|
Result := ti.GetDataAddress(AValueObj, AnAddress, ATargetType, ATargetCacheIndex+1)
|
|
else
|
|
Result := ATargetType = nil; // end of type chain
|
|
end;
|
|
|
|
function TFpDwarfSymbol.GetDataAddressNext(AValueObj: TFpDwarfValue;
|
|
var AnAddress: TFpDbgMemLocation; ATargetType: TFpDwarfSymbolType;
|
|
ATargetCacheIndex: Integer): Boolean;
|
|
begin
|
|
Result := True;
|
|
end;
|
|
|
|
function TFpDwarfSymbol.HasAddress: Boolean;
|
|
begin
|
|
Result := False;
|
|
end;
|
|
|
|
procedure TFpDwarfSymbol.Init;
|
|
begin
|
|
//
|
|
end;
|
|
|
|
class function TFpDwarfSymbol.CreateSubClass(AName: String;
|
|
AnInformationEntry: TDwarfInformationEntry): TFpDwarfSymbol;
|
|
var
|
|
c: TDbgDwarfSymbolBaseClass;
|
|
begin
|
|
c := AnInformationEntry.CompUnit.DwarfSymbolClassMap.GetDwarfSymbolClass(AnInformationEntry.AbbrevTag);
|
|
Result := TFpDwarfSymbol(c.Create(AName, AnInformationEntry));
|
|
end;
|
|
|
|
destructor TFpDwarfSymbol.Destroy;
|
|
begin
|
|
inherited Destroy;
|
|
ReleaseRefAndNil(FNestedTypeInfo);
|
|
Assert(not CircleBackRefsActive, 'CircleBackRefsActive can not be is destructor');
|
|
// FParentTypeInfo := nil
|
|
end;
|
|
|
|
function TFpDwarfSymbol.StartScope: TDbgPtr;
|
|
begin
|
|
if not InformationEntry.ReadStartScope(Result) then
|
|
Result := 0;
|
|
end;
|
|
|
|
{ TFpDwarfSymbolValue }
|
|
|
|
function TFpDwarfSymbolValue.GetValueAddress(AValueObj: TFpDwarfValue; out
|
|
AnAddress: TFpDbgMemLocation): Boolean;
|
|
begin
|
|
Result := False;
|
|
end;
|
|
|
|
function TFpDwarfSymbolValue.GetValueDataAddress(AValueObj: TFpDwarfValue; out
|
|
AnAddress: TFpDbgMemLocation; ATargetType: TFpDwarfSymbolType): Boolean;
|
|
begin
|
|
Result := TypeInfo <> nil;
|
|
if not Result then
|
|
exit;
|
|
|
|
Assert((TypeInfo is TFpDwarfSymbol) and (TypeInfo.SymbolType = stType), 'TFpDwarfSymbolValue.GetDataAddress');
|
|
Result := GetValueAddress(AValueObj, AnAddress);
|
|
Result := Result and IsReadableLoc(AnAddress);
|
|
if Result then begin
|
|
Result := TFpDwarfSymbolType(TypeInfo).GetDataAddress(AValueObj, AnAddress, ATargetType, 1);
|
|
if not Result then SetLastError(TypeInfo.LastError);
|
|
end;
|
|
end;
|
|
|
|
procedure TFpDwarfSymbolValue.KindNeeded;
|
|
var
|
|
t: TFpDbgSymbol;
|
|
begin
|
|
t := TypeInfo;
|
|
if t = nil then
|
|
inherited KindNeeded
|
|
else
|
|
SetKind(t.Kind);
|
|
end;
|
|
|
|
procedure TFpDwarfSymbolValue.MemberVisibilityNeeded;
|
|
var
|
|
Val: TDbgSymbolMemberVisibility;
|
|
begin
|
|
if ReadMemberVisibility(Val) then
|
|
SetMemberVisibility(Val)
|
|
else
|
|
if TypeInfo <> nil then
|
|
SetMemberVisibility(TypeInfo.MemberVisibility)
|
|
else
|
|
inherited MemberVisibilityNeeded;
|
|
end;
|
|
|
|
function TFpDwarfSymbolValue.GetMember(AIndex: Int64): TFpDbgSymbol;
|
|
var
|
|
ti: TFpDbgSymbol;
|
|
k: TDbgSymbolKind;
|
|
begin
|
|
ti := TypeInfo;
|
|
if ti = nil then begin
|
|
Result := inherited GetMember(AIndex);
|
|
exit;
|
|
end;
|
|
|
|
k := ti.Kind;
|
|
// while holding result, until refcount added, do not call any function
|
|
Result := ti.Member[AIndex];
|
|
assert((Result = nil) or (Result is TFpDwarfSymbolValue), 'TFpDwarfSymbolValue.GetMember is Value');
|
|
|
|
if (k in [skClass, skObject, skRecord {, skArray}]) and
|
|
(Result <> nil) and (Result is TFpDwarfSymbolValue)
|
|
then begin
|
|
if FMembers = nil then
|
|
FMembers := TFpDbgCircularRefCntObjList.Create;
|
|
FMembers.Add(Result); //TODO: last member only?
|
|
end;
|
|
end;
|
|
|
|
function TFpDwarfSymbolValue.GetMemberByName(AIndex: String): TFpDbgSymbol;
|
|
var
|
|
ti: TFpDbgSymbol;
|
|
k: TDbgSymbolKind;
|
|
begin
|
|
ti := TypeInfo;
|
|
if ti = nil then begin
|
|
Result := inherited GetMemberByName(AIndex);
|
|
exit;
|
|
end;
|
|
|
|
k := ti.Kind;
|
|
|
|
// while holding result, until refcount added, do not call any function
|
|
Result := ti.MemberByName[AIndex];
|
|
assert((Result = nil) or (Result is TFpDwarfSymbolValue), 'TFpDwarfSymbolValue.GetMember is Value');
|
|
|
|
if (k in [skClass, skObject, skRecord {, skArray}]) and
|
|
(Result <> nil) and (Result is TFpDwarfSymbolValue)
|
|
then begin
|
|
if FMembers = nil then
|
|
FMembers := TFpDbgCircularRefCntObjList.Create;
|
|
FMembers.Add(Result);
|
|
end;
|
|
end;
|
|
|
|
function TFpDwarfSymbolValue.GetMemberCount: Integer;
|
|
var
|
|
ti: TFpDbgSymbol;
|
|
begin
|
|
ti := TypeInfo;
|
|
if ti <> nil then begin
|
|
Result := ti.MemberCount;
|
|
//TODO: cache result
|
|
if ti.Kind in [skClass, skObject] then
|
|
while ti.TypeInfo <> nil do begin
|
|
ti := ti.TypeInfo;
|
|
Result := Result + ti.MemberCount;
|
|
end;
|
|
end
|
|
else
|
|
Result := inherited GetMemberCount;
|
|
end;
|
|
|
|
procedure TFpDwarfSymbolValue.Init;
|
|
begin
|
|
inherited Init;
|
|
SetSymbolType(stValue);
|
|
end;
|
|
|
|
destructor TFpDwarfSymbolValue.Destroy;
|
|
begin
|
|
Assert(not CircleBackRefsActive, 'CircleBackRefsActive can not be is ddestructor');
|
|
|
|
FreeAndNil(FMembers);
|
|
if FValueObject <> nil then begin
|
|
FValueObject.SetValueSymbol(nil);
|
|
FValueObject.ReleaseCirclularReference{$IFDEF WITH_REFCOUNT_DEBUG}(@FValueObject, ClassName+'.FValueObject'){$ENDIF};
|
|
FValueObject := nil;
|
|
end;
|
|
ParentTypeInfo := nil;
|
|
inherited Destroy;
|
|
end;
|
|
|
|
class function TFpDwarfSymbolValue.CreateValueSubClass(AName: String;
|
|
AnInformationEntry: TDwarfInformationEntry): TFpDwarfSymbolValue;
|
|
var
|
|
c: TDbgDwarfSymbolBaseClass;
|
|
begin
|
|
c := AnInformationEntry.CompUnit.DwarfSymbolClassMap.GetDwarfSymbolClass(AnInformationEntry.AbbrevTag);
|
|
|
|
if c.InheritsFrom(TFpDwarfSymbolValue) then
|
|
Result := TFpDwarfSymbolValueClass(c).Create(AName, AnInformationEntry)
|
|
else
|
|
Result := nil;
|
|
end;
|
|
|
|
{ TFpDwarfSymbolValueWithLocation }
|
|
|
|
function TFpDwarfSymbolValueWithLocation.InitLocationParser(const ALocationParser: TDwarfLocationExpression;
|
|
AnInitLocParserData: PInitLocParserData): Boolean;
|
|
begin
|
|
Result := inherited InitLocationParser(ALocationParser, AnInitLocParserData);
|
|
ALocationParser.OnFrameBaseNeeded := @FrameBaseNeeded;
|
|
end;
|
|
|
|
procedure TFpDwarfSymbolValueWithLocation.FrameBaseNeeded(ASender: TObject);
|
|
var
|
|
p: TFpDwarfSymbol;
|
|
fb: TDBGPtr;
|
|
begin
|
|
debugln(FPDBG_DWARF_SEARCH, ['TFpDwarfSymbolValueVariable.FrameBaseNeeded ']);
|
|
p := ParentTypeInfo;
|
|
// TODO: what if parent is declaration?
|
|
if (p <> nil) and (p is TFpDwarfSymbolValueProc) then begin
|
|
fb := TFpDwarfSymbolValueProc(p).GetFrameBase(ASender as TDwarfLocationExpression);
|
|
(ASender as TDwarfLocationExpression).FrameBase := fb;
|
|
if fb = 0 then begin
|
|
debugln(FPDBG_DWARF_ERRORS, ['DWARF ERROR in TFpDwarfSymbolValueWithLocation.FrameBaseNeeded result is 0']);
|
|
end;
|
|
exit;
|
|
end;
|
|
|
|
{$warning TODO}
|
|
//else
|
|
//if OwnerTypeInfo <> nil then
|
|
// OwnerTypeInfo.fr;
|
|
// TODO: check owner
|
|
debugln(FPDBG_DWARF_ERRORS, ['DWARF ERROR in TFpDwarfSymbolValueWithLocation.FrameBaseNeeded no parent type info']);
|
|
(ASender as TDwarfLocationExpression).FrameBase := 0;
|
|
end;
|
|
|
|
function TFpDwarfSymbolValueWithLocation.GetValueObject: TFpDbgValue;
|
|
var
|
|
ti: TFpDbgSymbol;
|
|
begin
|
|
Result := FValueObject;
|
|
if Result <> nil then exit;
|
|
|
|
ti := TypeInfo;
|
|
if (ti = nil) or not (ti.SymbolType = stType) then exit;
|
|
|
|
FValueObject := TFpDwarfSymbolType(ti).GetTypedValueObject(False);
|
|
if FValueObject <> nil then begin
|
|
{$IFDEF WITH_REFCOUNT_DEBUG}FValueObject.DbgRenameReference(@FValueObject, ClassName+'.FValueObject');{$ENDIF}
|
|
FValueObject.MakePlainRefToCirclular;
|
|
FValueObject.SetValueSymbol(self);
|
|
end;
|
|
|
|
Result := FValueObject;
|
|
end;
|
|
|
|
{ TFpDwarfSymbolType }
|
|
|
|
procedure TFpDwarfSymbolType.Init;
|
|
begin
|
|
inherited Init;
|
|
SetSymbolType(stType);
|
|
end;
|
|
|
|
procedure TFpDwarfSymbolType.MemberVisibilityNeeded;
|
|
var
|
|
Val: TDbgSymbolMemberVisibility;
|
|
begin
|
|
if ReadMemberVisibility(Val) then
|
|
SetMemberVisibility(Val)
|
|
else
|
|
inherited MemberVisibilityNeeded;
|
|
end;
|
|
|
|
procedure TFpDwarfSymbolType.SizeNeeded;
|
|
var
|
|
ByteSize: Integer;
|
|
begin
|
|
if InformationEntry.ReadValue(DW_AT_byte_size, ByteSize) then
|
|
SetSize(ByteSize)
|
|
else
|
|
inherited SizeNeeded;
|
|
end;
|
|
|
|
function TFpDwarfSymbolType.GetTypedValueObject(ATypeCast: Boolean): TFpDwarfValue;
|
|
begin
|
|
Result := nil;
|
|
end;
|
|
|
|
function TFpDwarfSymbolType.GetValueBounds(AValueObj: TFpDwarfValue; out ALowBound,
|
|
AHighBound: Int64): Boolean;
|
|
begin
|
|
Result := HasBounds;
|
|
ALowBound := OrdLowBound;
|
|
AHighBound := OrdHighBound;
|
|
end;
|
|
|
|
class function TFpDwarfSymbolType.CreateTypeSubClass(AName: String;
|
|
AnInformationEntry: TDwarfInformationEntry): TFpDwarfSymbolType;
|
|
var
|
|
c: TDbgDwarfSymbolBaseClass;
|
|
begin
|
|
c := AnInformationEntry.CompUnit.DwarfSymbolClassMap.GetDwarfSymbolClass(AnInformationEntry.AbbrevTag);
|
|
|
|
if c.InheritsFrom(TFpDwarfSymbolType) then
|
|
Result := TFpDwarfSymbolTypeClass(c).Create(AName, AnInformationEntry)
|
|
else
|
|
Result := nil;
|
|
end;
|
|
|
|
function TFpDwarfSymbolType.TypeCastValue(AValue: TFpDbgValue): TFpDbgValue;
|
|
begin
|
|
Result := GetTypedValueObject(True);
|
|
If Result = nil then
|
|
exit;
|
|
assert(Result is TFpDwarfValue);
|
|
if not TFpDwarfValue(Result).SetTypeCastInfo(self, AValue) then
|
|
ReleaseRefAndNil(Result);
|
|
end;
|
|
|
|
{ TDbgDwarfBaseTypeIdentifier }
|
|
|
|
procedure TFpDwarfSymbolTypeBasic.KindNeeded;
|
|
var
|
|
Encoding, ByteSize: Integer;
|
|
begin
|
|
if not InformationEntry.ReadValue(DW_AT_encoding, Encoding) then begin
|
|
DebugLn(FPDBG_DWARF_WARNINGS, ['TFpDwarfSymbolTypeBasic.KindNeeded: Failed reading encoding for ', DwarfTagToString(InformationEntry.AbbrevTag)]);
|
|
inherited KindNeeded;
|
|
exit;
|
|
end;
|
|
|
|
if InformationEntry.ReadValue(DW_AT_byte_size, ByteSize) then
|
|
SetSize(ByteSize);
|
|
|
|
case Encoding of
|
|
DW_ATE_address : SetKind(skPointer);
|
|
DW_ATE_boolean: SetKind(skBoolean);
|
|
//DW_ATE_complex_float:
|
|
DW_ATE_float: SetKind(skFloat);
|
|
DW_ATE_signed: SetKind(skInteger);
|
|
DW_ATE_signed_char: SetKind(skChar);
|
|
DW_ATE_unsigned: SetKind(skCardinal);
|
|
DW_ATE_unsigned_char: SetKind(skChar);
|
|
else
|
|
begin
|
|
DebugLn(FPDBG_DWARF_WARNINGS, ['TFpDwarfSymbolTypeBasic.KindNeeded: Unknown encoding ', DwarfBaseTypeEncodingToString(Encoding), ' for ', DwarfTagToString(InformationEntry.AbbrevTag)]);
|
|
inherited KindNeeded;
|
|
end;
|
|
end;
|
|
end;
|
|
|
|
procedure TFpDwarfSymbolTypeBasic.TypeInfoNeeded;
|
|
begin
|
|
SetTypeInfo(nil);
|
|
end;
|
|
|
|
function TFpDwarfSymbolTypeBasic.GetTypedValueObject(ATypeCast: Boolean): TFpDwarfValue;
|
|
begin
|
|
case Kind of
|
|
skPointer: Result := TFpDwarfValuePointer.Create(Self, Size);
|
|
skInteger: Result := TFpDwarfValueInteger.Create(Self, Size);
|
|
skCardinal: Result := TFpDwarfValueCardinal.Create(Self, Size);
|
|
skBoolean: Result := TFpDwarfValueBoolean.Create(Self, Size);
|
|
skChar: Result := TFpDwarfValueChar.Create(Self, Size);
|
|
skFloat: Result := TFpDwarfValueFloat.Create(Self, Size);
|
|
end;
|
|
end;
|
|
|
|
function TFpDwarfSymbolTypeBasic.GetHasBounds: Boolean;
|
|
begin
|
|
Result := (kind = skInteger) or (kind = skCardinal);
|
|
end;
|
|
|
|
function TFpDwarfSymbolTypeBasic.GetOrdHighBound: Int64;
|
|
begin
|
|
case Kind of
|
|
skInteger: Result := int64( high(int64) shr (64 - Min(Size, 8) * 8));
|
|
skCardinal: Result := int64( high(qword) shr (64 - Min(Size, 8) * 8));
|
|
else
|
|
Result := inherited GetOrdHighBound;
|
|
end;
|
|
end;
|
|
|
|
function TFpDwarfSymbolTypeBasic.GetOrdLowBound: Int64;
|
|
begin
|
|
case Kind of
|
|
skInteger: Result := -(int64( high(int64) shr (64 - Min(Size, 8) * 8)))-1;
|
|
skCardinal: Result := 0;
|
|
else
|
|
Result := inherited GetOrdHighBound;
|
|
end;
|
|
end;
|
|
|
|
{ TFpDwarfSymbolTypeModifier }
|
|
|
|
procedure TFpDwarfSymbolTypeModifier.TypeInfoNeeded;
|
|
var
|
|
p: TFpDwarfSymbolType;
|
|
begin
|
|
p := NestedTypeInfo;
|
|
if p <> nil then
|
|
SetTypeInfo(p.TypeInfo)
|
|
else
|
|
SetTypeInfo(nil);
|
|
end;
|
|
|
|
procedure TFpDwarfSymbolTypeModifier.ForwardToSymbolNeeded;
|
|
begin
|
|
SetForwardToSymbol(NestedTypeInfo)
|
|
end;
|
|
|
|
function TFpDwarfSymbolTypeModifier.GetTypedValueObject(ATypeCast: Boolean): TFpDwarfValue;
|
|
var
|
|
ti: TFpDwarfSymbolType;
|
|
begin
|
|
ti := NestedTypeInfo;
|
|
if ti <> nil then
|
|
Result := ti.GetTypedValueObject(ATypeCast)
|
|
else
|
|
Result := inherited;
|
|
end;
|
|
|
|
{ TFpDwarfSymbolTypeRef }
|
|
|
|
function TFpDwarfSymbolTypeRef.GetFlags: TDbgSymbolFlags;
|
|
begin
|
|
Result := (inherited GetFlags) + [sfInternalRef];
|
|
end;
|
|
|
|
function TFpDwarfSymbolTypeRef.GetDataAddressNext(AValueObj: TFpDwarfValue;
|
|
var AnAddress: TFpDbgMemLocation; ATargetType: TFpDwarfSymbolType;
|
|
ATargetCacheIndex: Integer): Boolean;
|
|
var
|
|
t: TFpDbgMemLocation;
|
|
begin
|
|
t := AValueObj.DataAddressCache[ATargetCacheIndex];
|
|
if IsInitializedLoc(t) then begin
|
|
AnAddress := t;
|
|
end
|
|
else begin
|
|
Result := AValueObj.MemManager <> nil;
|
|
if not Result then
|
|
exit;
|
|
AnAddress := AValueObj.MemManager.ReadAddress(AnAddress, CompilationUnit.AddressSize);
|
|
AValueObj.DataAddressCache[ATargetCacheIndex] := AnAddress;
|
|
end;
|
|
Result := IsValidLoc(AnAddress);
|
|
|
|
if Result then
|
|
Result := inherited GetDataAddressNext(AValueObj, AnAddress, ATargetType, ATargetCacheIndex)
|
|
else
|
|
if IsError(AValueObj.MemManager.LastError) then
|
|
SetLastError(AValueObj.MemManager.LastError);
|
|
// Todo: other error
|
|
end;
|
|
|
|
{ TFpDwarfSymbolTypeDeclaration }
|
|
|
|
function TFpDwarfSymbolTypeDeclaration.DoGetNestedTypeInfo: TFpDwarfSymbolType;
|
|
var
|
|
ti: TFpDwarfSymbolType;
|
|
ti2: TFpDbgSymbol;
|
|
begin
|
|
Result := inherited DoGetNestedTypeInfo;
|
|
|
|
// Is internal class pointer?
|
|
// Do not trigged any cached property of the pointer
|
|
if (Result = nil) then
|
|
exit;
|
|
|
|
ti := Result;
|
|
if (ti is TFpDwarfSymbolTypeModifier) then begin
|
|
ti := TFpDwarfSymbolType(ti.TypeInfo);
|
|
if (Result = nil) then
|
|
exit;
|
|
end;
|
|
if not (ti is TFpDwarfSymbolTypePointer) then
|
|
exit;
|
|
|
|
ti2 := ti.NestedTypeInfo;
|
|
// only if it is NOT a declaration
|
|
if (ti2 <> nil) and (ti2 is TFpDwarfSymbolTypeStructure) then begin
|
|
TFpDwarfSymbolTypePointer(ti).IsInternalPointer := True;
|
|
// TODO: Flag the structure as class (save teme in KindNeeded)
|
|
end;
|
|
end;
|
|
|
|
{ TFpDwarfSymbolTypeSubRange }
|
|
|
|
procedure TFpDwarfSymbolTypeSubRange.InitEnumIdx;
|
|
var
|
|
t: TFpDwarfSymbolType;
|
|
i: Integer;
|
|
h, l: Int64;
|
|
begin
|
|
if FEnumIdxValid then
|
|
exit;
|
|
FEnumIdxValid := True;
|
|
|
|
t := NestedTypeInfo;
|
|
i := t.MemberCount - 1;
|
|
h := OrdHighBound;
|
|
l := OrdLowBound;
|
|
|
|
while (i >= 0) and (t.Member[i].OrdinalValue > h) do
|
|
dec(i);
|
|
FHighEnumIdx := i;
|
|
|
|
while (i >= 0) and (t.Member[i].OrdinalValue >= l) do
|
|
dec(i);
|
|
FLowEnumIdx := i + 1;
|
|
end;
|
|
|
|
procedure TFpDwarfSymbolTypeSubRange.ReadBounds(AValueObj: TFpDwarfValue);
|
|
var
|
|
FwdInfoPtr: Pointer;
|
|
FwdCompUint: TDwarfCompilationUnit;
|
|
NewInfo: TDwarfInformationEntry;
|
|
var
|
|
AnAddress: TFpDbgMemLocation;
|
|
InitLocParserData: TInitLocParserData;
|
|
begin
|
|
if FLowBoundState <> rfNotRead then exit;
|
|
|
|
// Todo: search attrib-IDX only once
|
|
if InformationEntry.ReadReference(DW_AT_lower_bound, FwdInfoPtr, FwdCompUint) then begin
|
|
NewInfo := TDwarfInformationEntry.Create(FwdCompUint, FwdInfoPtr);
|
|
FLowBoundValue := TFpDwarfSymbolValue.CreateValueSubClass('', NewInfo);
|
|
NewInfo.ReleaseReference;
|
|
if FLowBoundValue = nil then begin
|
|
FLowBoundState := rfNotFound;
|
|
exit;
|
|
end
|
|
else
|
|
FLowBoundState := rfValue;
|
|
end
|
|
else
|
|
if InformationEntry.ReadValue(DW_AT_lower_bound, FLowBoundConst) then begin
|
|
FLowBoundState := rfConst;
|
|
end
|
|
else
|
|
begin
|
|
//FLowBoundConst := 0; // the default
|
|
//FLowBoundState := rfConst;
|
|
FLowBoundState := rfNotFound;
|
|
exit; // incomplete type
|
|
end;
|
|
|
|
|
|
if InformationEntry.ReadReference(DW_AT_upper_bound, FwdInfoPtr, FwdCompUint) then begin
|
|
NewInfo := TDwarfInformationEntry.Create(FwdCompUint, FwdInfoPtr);
|
|
FHighBoundValue := TFpDwarfSymbolValue.CreateValueSubClass('', NewInfo);
|
|
NewInfo.ReleaseReference;
|
|
if FHighBoundValue = nil then begin
|
|
FHighBoundState := rfNotFound;
|
|
exit;
|
|
end
|
|
else
|
|
FHighBoundState := rfValue;
|
|
end
|
|
else
|
|
if InformationEntry.ReadValue(DW_AT_upper_bound, FHighBoundConst) then begin
|
|
FHighBoundState := rfConst;
|
|
end
|
|
else
|
|
begin
|
|
if assigned(AValueObj) then
|
|
InitLocParserData.ObjectDataAddress := AValueObj.Address;
|
|
InitLocParserData.ObjectDataAddrPush := False;
|
|
if assigned(AValueObj) and LocationFromTag(DW_AT_upper_bound, AValueObj, AnAddress, @InitLocParserData, InformationEntry, True) then begin
|
|
FHighBoundState := rfConst;
|
|
FHighBoundConst := Int64(AnAddress.Address);
|
|
end
|
|
else
|
|
begin
|
|
FHighBoundState := rfNotFound;
|
|
|
|
if InformationEntry.ReadReference(DW_AT_count, FwdInfoPtr, FwdCompUint) then begin
|
|
NewInfo := TDwarfInformationEntry.Create(FwdCompUint, FwdInfoPtr);
|
|
FCountValue := TFpDwarfSymbolValue.CreateValueSubClass('', NewInfo);
|
|
NewInfo.ReleaseReference;
|
|
if FCountValue = nil then begin
|
|
FCountState := rfNotFound;
|
|
exit;
|
|
end
|
|
else
|
|
FCountState := rfValue;
|
|
end
|
|
else
|
|
if InformationEntry.ReadValue(DW_AT_count, FCountConst) then begin
|
|
FCountState := rfConst;
|
|
end
|
|
else
|
|
FCountState := rfNotFound;
|
|
end;
|
|
end;
|
|
end;
|
|
|
|
function TFpDwarfSymbolTypeSubRange.DoGetNestedTypeInfo: TFpDwarfSymbolType;
|
|
begin
|
|
Result := inherited DoGetNestedTypeInfo;
|
|
if Result <> nil then
|
|
exit;
|
|
|
|
if FLowBoundState = rfValue then
|
|
Result := FLowBoundValue.TypeInfo as TFpDwarfSymbolType
|
|
else
|
|
if FHighBoundState = rfValue then
|
|
Result := FHighBoundValue.TypeInfo as TFpDwarfSymbolType
|
|
else
|
|
if FCountState = rfValue then
|
|
Result := FCountValue.TypeInfo as TFpDwarfSymbolType;
|
|
end;
|
|
|
|
function TFpDwarfSymbolTypeSubRange.GetHasBounds: Boolean;
|
|
begin
|
|
ReadBounds(nil);
|
|
// TODO: currently limited to const.
|
|
// not standard, but upper may be missing?
|
|
Result := (FLowBoundState in [rfConst]) and
|
|
( (FHighBoundState in [rfConst]) or
|
|
(FCountState in [rfConst]) );
|
|
|
|
(*
|
|
Result := (FLowBoundState in [rfValue, rfConst]) and
|
|
( (FHighBoundState in [rfValue, rfConst]) or
|
|
(FCountState in [rfValue, rfConst]) );
|
|
*)
|
|
end;
|
|
|
|
function TFpDwarfSymbolTypeSubRange.GetOrdHighBound: Int64;
|
|
begin
|
|
// Todo range check off.
|
|
//if FHighBoundState = rfValue then
|
|
// Result := FHighBoundValue.VALUE // TODO
|
|
//else
|
|
if FHighBoundState = rfConst then
|
|
Result := FHighBoundConst
|
|
else
|
|
//if FCountState = rfValue then
|
|
// Result := GetOrdLowBound + FCountValue.VALUE - 1 // TODO
|
|
//else
|
|
if FHighBoundState = rfConst then
|
|
Result := GetOrdLowBound + FCountConst - 1;
|
|
end;
|
|
|
|
function TFpDwarfSymbolTypeSubRange.GetOrdLowBound: Int64;
|
|
begin
|
|
//if FLowBoundState = rfValue then
|
|
// Result := FLowBoundValue.VALUE // TODO
|
|
//else
|
|
Result := FLowBoundConst;
|
|
end;
|
|
|
|
procedure TFpDwarfSymbolTypeSubRange.NameNeeded;
|
|
var
|
|
AName: String;
|
|
begin
|
|
if InformationEntry.ReadName(AName) then
|
|
SetName(AName)
|
|
else
|
|
SetName('');
|
|
end;
|
|
|
|
procedure TFpDwarfSymbolTypeSubRange.KindNeeded;
|
|
var
|
|
t: TFpDbgSymbol;
|
|
begin
|
|
// TODO: limit to ordinal types
|
|
if not HasBounds then begin // does ReadBounds;
|
|
SetKind(skNone); // incomplete type
|
|
end;
|
|
|
|
t := NestedTypeInfo;
|
|
if t = nil then begin
|
|
SetKind(skInteger);
|
|
SetSize(CompilationUnit.AddressSize);
|
|
end
|
|
else
|
|
SetKind(t.Kind);
|
|
end;
|
|
|
|
procedure TFpDwarfSymbolTypeSubRange.SizeNeeded;
|
|
var
|
|
t: TFpDbgSymbol;
|
|
begin
|
|
t := NestedTypeInfo;
|
|
if t = nil then begin
|
|
SetKind(skInteger);
|
|
SetSize(CompilationUnit.AddressSize);
|
|
end
|
|
else
|
|
SetSize(t.Size);
|
|
end;
|
|
|
|
function TFpDwarfSymbolTypeSubRange.GetMember(AIndex: Int64): TFpDbgSymbol;
|
|
begin
|
|
if Kind = skEnum then begin
|
|
if not FEnumIdxValid then
|
|
InitEnumIdx;
|
|
Result := NestedTypeInfo.Member[AIndex - FLowEnumIdx];
|
|
end
|
|
else
|
|
Result := inherited GetMember(AIndex);
|
|
end;
|
|
|
|
function TFpDwarfSymbolTypeSubRange.GetMemberCount: Integer;
|
|
begin
|
|
if Kind = skEnum then begin
|
|
if not FEnumIdxValid then
|
|
InitEnumIdx;
|
|
Result := FHighEnumIdx - FLowEnumIdx + 1;
|
|
end
|
|
else
|
|
Result := inherited GetMemberCount;
|
|
end;
|
|
|
|
function TFpDwarfSymbolTypeSubRange.GetFlags: TDbgSymbolFlags;
|
|
begin
|
|
Result := (inherited GetFlags) + [sfSubRange];
|
|
end;
|
|
|
|
function TFpDwarfSymbolTypeSubRange.GetValueBounds(AValueObj: TFpDwarfValue; out
|
|
ALowBound, AHighBound: Int64): Boolean;
|
|
begin
|
|
ReadBounds(AValueObj);
|
|
Result := inherited GetValueBounds(AValueObj, ALowBound, AHighBound);
|
|
end;
|
|
|
|
procedure TFpDwarfSymbolTypeSubRange.Init;
|
|
begin
|
|
FLowBoundState := rfNotRead;
|
|
FHighBoundState := rfNotRead;
|
|
FCountState := rfNotRead;
|
|
inherited Init;
|
|
end;
|
|
|
|
{ TFpDwarfSymbolTypePointer }
|
|
|
|
function TFpDwarfSymbolTypePointer.IsInternalDynArrayPointer: Boolean;
|
|
var
|
|
ti: TFpDbgSymbol;
|
|
begin
|
|
Result := False;
|
|
ti := NestedTypeInfo; // Same as TypeInfo, but does not try to be forwarded
|
|
Result := (ti <> nil) and (ti is TFpDwarfSymbolTypeArray);
|
|
if Result then
|
|
Result := (sfDynArray in ti.Flags);
|
|
end;
|
|
|
|
procedure TFpDwarfSymbolTypePointer.TypeInfoNeeded;
|
|
var
|
|
p: TFpDwarfSymbolType;
|
|
begin
|
|
p := NestedTypeInfo;
|
|
if IsInternalPointer and (p <> nil) then begin
|
|
SetTypeInfo(p.TypeInfo);
|
|
exit;
|
|
end;
|
|
SetTypeInfo(p);
|
|
end;
|
|
|
|
function TFpDwarfSymbolTypePointer.GetIsInternalPointer: Boolean;
|
|
begin
|
|
Result := FIsInternalPointer or IsInternalDynArrayPointer;
|
|
end;
|
|
|
|
procedure TFpDwarfSymbolTypePointer.KindNeeded;
|
|
var
|
|
k: TDbgSymbolKind;
|
|
begin
|
|
if IsInternalPointer then begin
|
|
k := NestedTypeInfo.Kind;
|
|
if k = skObject then
|
|
SetKind(skClass)
|
|
else
|
|
SetKind(k);
|
|
end
|
|
else
|
|
SetKind(skPointer);
|
|
end;
|
|
|
|
procedure TFpDwarfSymbolTypePointer.SizeNeeded;
|
|
begin
|
|
SetSize(CompilationUnit.AddressSize);
|
|
end;
|
|
|
|
procedure TFpDwarfSymbolTypePointer.ForwardToSymbolNeeded;
|
|
begin
|
|
if IsInternalPointer then
|
|
SetForwardToSymbol(NestedTypeInfo) // Same as TypeInfo, but does not try to be forwarded
|
|
else
|
|
SetForwardToSymbol(nil); // inherited ForwardToSymbolNeeded;
|
|
end;
|
|
|
|
function TFpDwarfSymbolTypePointer.GetDataAddressNext(AValueObj: TFpDwarfValue;
|
|
var AnAddress: TFpDbgMemLocation; ATargetType: TFpDwarfSymbolType;
|
|
ATargetCacheIndex: Integer): Boolean;
|
|
var
|
|
t: TFpDbgMemLocation;
|
|
begin
|
|
t := AValueObj.DataAddressCache[ATargetCacheIndex];
|
|
if IsInitializedLoc(t) then begin
|
|
AnAddress := t;
|
|
end
|
|
else begin
|
|
Result := AValueObj.MemManager <> nil;
|
|
if not Result then
|
|
exit;
|
|
AnAddress := AValueObj.MemManager.ReadAddress(AnAddress, CompilationUnit.AddressSize);
|
|
AValueObj.DataAddressCache[ATargetCacheIndex] := AnAddress;
|
|
end;
|
|
Result := IsValidLoc(AnAddress);
|
|
|
|
if Result then
|
|
Result := inherited GetDataAddressNext(AValueObj, AnAddress, ATargetType, ATargetCacheIndex)
|
|
else
|
|
if IsError(AValueObj.MemManager.LastError) then
|
|
SetLastError(AValueObj.MemManager.LastError);
|
|
// Todo: other error
|
|
end;
|
|
|
|
function TFpDwarfSymbolTypePointer.GetTypedValueObject(ATypeCast: Boolean): TFpDwarfValue;
|
|
begin
|
|
if IsInternalPointer then
|
|
Result := NestedTypeInfo.GetTypedValueObject(ATypeCast)
|
|
else
|
|
Result := TFpDwarfValuePointer.Create(Self, CompilationUnit.AddressSize);
|
|
end;
|
|
|
|
function TFpDwarfSymbolTypePointer.DataSize: Integer;
|
|
begin
|
|
if Kind = skClass then
|
|
Result := NestedTypeInfo.Size
|
|
else
|
|
Result := inherited DataSize;
|
|
end;
|
|
|
|
{ TDbgDwarfIdentifierEnumElement }
|
|
|
|
procedure TFpDwarfSymbolValueEnumMember.ReadOrdinalValue;
|
|
begin
|
|
if FOrdinalValueRead then exit;
|
|
FOrdinalValueRead := True;
|
|
FHasOrdinalValue := InformationEntry.ReadValue(DW_AT_const_value, FOrdinalValue);
|
|
end;
|
|
|
|
procedure TFpDwarfSymbolValueEnumMember.KindNeeded;
|
|
begin
|
|
SetKind(skEnumValue);
|
|
end;
|
|
|
|
function TFpDwarfSymbolValueEnumMember.GetHasOrdinalValue: Boolean;
|
|
begin
|
|
ReadOrdinalValue;
|
|
Result := FHasOrdinalValue;
|
|
end;
|
|
|
|
function TFpDwarfSymbolValueEnumMember.GetOrdinalValue: Int64;
|
|
begin
|
|
ReadOrdinalValue;
|
|
Result := FOrdinalValue;
|
|
end;
|
|
|
|
procedure TFpDwarfSymbolValueEnumMember.Init;
|
|
begin
|
|
FOrdinalValueRead := False;
|
|
inherited Init;
|
|
end;
|
|
|
|
function TFpDwarfSymbolValueEnumMember.GetValueObject: TFpDbgValue;
|
|
begin
|
|
Result := FValueObject;
|
|
if Result <> nil then exit;
|
|
|
|
FValueObject := TFpDwarfValueEnumMember.Create(Self);
|
|
{$IFDEF WITH_REFCOUNT_DEBUG}FValueObject.DbgRenameReference(@FValueObject, ClassName+'.FValueObject');{$ENDIF}
|
|
FValueObject.MakePlainRefToCirclular;
|
|
FValueObject.SetValueSymbol(self);
|
|
|
|
Result := FValueObject;
|
|
end;
|
|
|
|
{ TFpDwarfSymbolTypeEnum }
|
|
|
|
procedure TFpDwarfSymbolTypeEnum.CreateMembers;
|
|
var
|
|
Info, Info2: TDwarfInformationEntry;
|
|
sym: TFpDwarfSymbol;
|
|
begin
|
|
if FMembers <> nil then
|
|
exit;
|
|
FMembers := TFpDbgCircularRefCntObjList.Create;
|
|
Info := InformationEntry.FirstChild;
|
|
if Info = nil then exit;
|
|
|
|
while Info.HasValidScope do begin
|
|
if (Info.AbbrevTag = DW_TAG_enumerator) then begin
|
|
Info2 := Info.Clone;
|
|
sym := TFpDwarfSymbol.CreateSubClass('', Info2);
|
|
FMembers.Add(sym);
|
|
sym.ReleaseReference;
|
|
sym.ParentTypeInfo := self;
|
|
Info2.ReleaseReference;
|
|
end;
|
|
Info.GoNext;
|
|
end;
|
|
|
|
Info.ReleaseReference;
|
|
end;
|
|
|
|
function TFpDwarfSymbolTypeEnum.GetTypedValueObject(ATypeCast: Boolean): TFpDwarfValue;
|
|
begin
|
|
Result := TFpDwarfValueEnum.Create(Self, Size);
|
|
end;
|
|
|
|
procedure TFpDwarfSymbolTypeEnum.KindNeeded;
|
|
begin
|
|
SetKind(skEnum);
|
|
end;
|
|
|
|
function TFpDwarfSymbolTypeEnum.GetMember(AIndex: Int64): TFpDbgSymbol;
|
|
begin
|
|
CreateMembers;
|
|
Result := TFpDbgSymbol(FMembers[AIndex]);
|
|
end;
|
|
|
|
function TFpDwarfSymbolTypeEnum.GetMemberByName(AIndex: String): TFpDbgSymbol;
|
|
var
|
|
i: Integer;
|
|
s, s1, s2: String;
|
|
begin
|
|
if AIndex = '' then
|
|
s1 := UTF8UpperCase(AIndex);
|
|
s2 := UTF8LowerCase(AIndex);
|
|
CreateMembers;
|
|
i := FMembers.Count - 1;
|
|
while i >= 0 do begin
|
|
Result := TFpDbgSymbol(FMembers[i]);
|
|
s := Result.Name;
|
|
if (s <> '') and CompareUtf8BothCase(@s1[1], @s2[1], @s[1]) then
|
|
exit;
|
|
dec(i);
|
|
end;
|
|
Result := nil;
|
|
end;
|
|
|
|
function TFpDwarfSymbolTypeEnum.GetMemberCount: Integer;
|
|
begin
|
|
CreateMembers;
|
|
Result := FMembers.Count;
|
|
end;
|
|
|
|
function TFpDwarfSymbolTypeEnum.GetHasBounds: Boolean;
|
|
begin
|
|
Result := True;
|
|
end;
|
|
|
|
function TFpDwarfSymbolTypeEnum.GetOrdHighBound: Int64;
|
|
var
|
|
c: Integer;
|
|
begin
|
|
c := MemberCount;
|
|
if c > 0 then
|
|
Result := Member[c-1].OrdinalValue
|
|
else
|
|
Result := -1;
|
|
end;
|
|
|
|
function TFpDwarfSymbolTypeEnum.GetOrdLowBound: Int64;
|
|
var
|
|
c: Integer;
|
|
begin
|
|
c := MemberCount;
|
|
if c > 0 then
|
|
Result := Member[0].OrdinalValue
|
|
else
|
|
Result := 0;
|
|
end;
|
|
|
|
destructor TFpDwarfSymbolTypeEnum.Destroy;
|
|
var
|
|
i: Integer;
|
|
begin
|
|
if FMembers <> nil then
|
|
for i := 0 to FMembers.Count - 1 do
|
|
TFpDwarfSymbol(FMembers[i]).ParentTypeInfo := nil;
|
|
FreeAndNil(FMembers);
|
|
inherited Destroy;
|
|
end;
|
|
|
|
{ TFpDwarfSymbolTypeSet }
|
|
|
|
procedure TFpDwarfSymbolTypeSet.KindNeeded;
|
|
begin
|
|
SetKind(skSet);
|
|
end;
|
|
|
|
function TFpDwarfSymbolTypeSet.GetTypedValueObject(ATypeCast: Boolean): TFpDwarfValue;
|
|
begin
|
|
Result := TFpDwarfValueSet.Create(Self, Size);
|
|
end;
|
|
|
|
function TFpDwarfSymbolTypeSet.GetMemberCount: Integer;
|
|
begin
|
|
if TypeInfo.Kind = skEnum then
|
|
Result := TypeInfo.MemberCount
|
|
else
|
|
Result := inherited GetMemberCount;
|
|
end;
|
|
|
|
function TFpDwarfSymbolTypeSet.GetMember(AIndex: Int64): TFpDbgSymbol;
|
|
begin
|
|
if TypeInfo.Kind = skEnum then
|
|
Result := TypeInfo.Member[AIndex]
|
|
else
|
|
Result := inherited GetMember(AIndex);
|
|
end;
|
|
|
|
{ TFpDwarfSymbolValueMember }
|
|
|
|
function TFpDwarfSymbolValueMember.GetValueAddress(AValueObj: TFpDwarfValue; out
|
|
AnAddress: TFpDbgMemLocation): Boolean;
|
|
var
|
|
BaseAddr: TFpDbgMemLocation;
|
|
InitLocParserData: TInitLocParserData;
|
|
begin
|
|
AnAddress := AValueObj.DataAddressCache[0];
|
|
Result := IsValidLoc(AnAddress);
|
|
if IsInitializedLoc(AnAddress) then
|
|
exit;
|
|
|
|
if AValueObj = nil then debugln(['TFpDwarfSymbolValueMember.InitLocationParser: NO VAl Obj !!!!!!!!!!!!!!!'])
|
|
else if AValueObj.StructureValue = nil then debugln(['TFpDwarfSymbolValueMember.InitLocationParser: NO STRUCT Obj !!!!!!!!!!!!!!!']);
|
|
|
|
if (AValueObj = nil) or (AValueObj.StructureValue = nil) or (ParentTypeInfo = nil)
|
|
then begin
|
|
debugln(FPDBG_DWARF_ERRORS, ['DWARF ERROR in TFpDwarfSymbolValueMember.InitLocationParser Error: ',ErrorCode(LastError),' ValueObject=', DbgSName(FValueObject)]);
|
|
Result := False;
|
|
if not IsError(LastError) then
|
|
SetLastError(CreateError(fpErrLocationParserInit)); // TODO: error message?
|
|
exit;
|
|
end;
|
|
Assert((ParentTypeInfo is TFpDwarfSymbol) and (ParentTypeInfo.SymbolType = stType), '');
|
|
if not AValueObj.GetStructureDwarfDataAddress(BaseAddr, TFpDwarfSymbolType(ParentTypeInfo)) then begin
|
|
debugln(FPDBG_DWARF_ERRORS, ['DWARF ERROR in TFpDwarfSymbolValueMember.InitLocationParser Error: ',ErrorCode(LastError),' ValueObject=', DbgSName(FValueObject)]);
|
|
Result := False;
|
|
if not IsError(LastError) then
|
|
SetLastError(CreateError(fpErrLocationParserInit)); // TODO: error message?
|
|
exit;
|
|
end;
|
|
//TODO: AValueObj.StructureValue.LastError
|
|
|
|
InitLocParserData.ObjectDataAddress := BaseAddr;
|
|
InitLocParserData.ObjectDataAddrPush := True;
|
|
Result := LocationFromTag(DW_AT_data_member_location, AValueObj, AnAddress, @InitLocParserData);
|
|
|
|
AValueObj.DataAddressCache[0] := AnAddress;
|
|
end;
|
|
|
|
function TFpDwarfSymbolValueMember.HasAddress: Boolean;
|
|
begin
|
|
Result := (InformationEntry.HasAttrib(DW_AT_data_member_location));
|
|
end;
|
|
|
|
{ TFpDwarfSymbolTypeStructure }
|
|
|
|
function TFpDwarfSymbolTypeStructure.GetMemberByName(AIndex: String): TFpDbgSymbol;
|
|
var
|
|
Ident: TDwarfInformationEntry;
|
|
ti: TFpDbgSymbol;
|
|
begin
|
|
// Todo, maybe create all children?
|
|
if FLastChildByName <> nil then begin
|
|
FLastChildByName.ReleaseCirclularReference;
|
|
FLastChildByName := nil;
|
|
end;
|
|
Result := nil;
|
|
|
|
Ident := InformationEntry.FindNamedChild(AIndex);
|
|
if Ident <> nil then begin
|
|
FLastChildByName := TFpDwarfSymbol.CreateSubClass('', Ident);
|
|
FLastChildByName.MakePlainRefToCirclular;
|
|
FLastChildByName.ParentTypeInfo := self;
|
|
//assert is member ?
|
|
ReleaseRefAndNil(Ident);
|
|
Result := FLastChildByName;
|
|
|
|
exit;
|
|
end;
|
|
|
|
ti := TypeInfo; // Parent
|
|
if ti <> nil then
|
|
Result := ti.MemberByName[AIndex];
|
|
end;
|
|
|
|
function TFpDwarfSymbolTypeStructure.GetMemberCount: Integer;
|
|
begin
|
|
CreateMembers;
|
|
Result := FMembers.Count;
|
|
end;
|
|
|
|
function TFpDwarfSymbolTypeStructure.GetDataAddressNext(AValueObj: TFpDwarfValue;
|
|
var AnAddress: TFpDbgMemLocation; ATargetType: TFpDwarfSymbolType;
|
|
ATargetCacheIndex: Integer): Boolean;
|
|
var
|
|
t: TFpDbgMemLocation;
|
|
InitLocParserData: TInitLocParserData;
|
|
begin
|
|
t := AValueObj.DataAddressCache[ATargetCacheIndex];
|
|
if IsInitializedLoc(t) then begin
|
|
AnAddress := t;
|
|
Result := IsValidLoc(AnAddress);
|
|
end
|
|
else begin
|
|
InitInheritanceInfo;
|
|
//TODO: may be a constant // offset
|
|
InitLocParserData.ObjectDataAddress := AnAddress;
|
|
InitLocParserData.ObjectDataAddrPush := True;
|
|
Result := LocationFromTag(DW_AT_data_member_location, AValueObj, t, @InitLocParserData, FInheritanceInfo);
|
|
if not Result then
|
|
exit;
|
|
AnAddress := t;
|
|
AValueObj.DataAddressCache[ATargetCacheIndex] := AnAddress;
|
|
|
|
if IsError(AValueObj.MemManager.LastError) then
|
|
SetLastError(AValueObj.MemManager.LastError);
|
|
end;
|
|
|
|
Result := inherited GetDataAddressNext(AValueObj, AnAddress, ATargetType, ATargetCacheIndex);
|
|
end;
|
|
|
|
function TFpDwarfSymbolTypeStructure.GetMember(AIndex: Int64): TFpDbgSymbol;
|
|
var
|
|
ti: TFpDbgSymbol;
|
|
begin
|
|
CreateMembers;
|
|
if AIndex >= FMembers.Count then begin
|
|
ti := TypeInfo;
|
|
if ti <> nil then
|
|
Result := ti.Member[AIndex - FMembers.Count];
|
|
end
|
|
else
|
|
Result := TFpDbgSymbol(FMembers[AIndex]);
|
|
end;
|
|
|
|
destructor TFpDwarfSymbolTypeStructure.Destroy;
|
|
var
|
|
i: Integer;
|
|
begin
|
|
ReleaseRefAndNil(FInheritanceInfo);
|
|
if FMembers <> nil then begin
|
|
for i := 0 to FMembers.Count - 1 do
|
|
TFpDwarfSymbol(FMembers[i]).ParentTypeInfo := nil;
|
|
FreeAndNil(FMembers);
|
|
end;
|
|
if FLastChildByName <> nil then begin
|
|
FLastChildByName.ParentTypeInfo := nil;
|
|
FLastChildByName.ReleaseCirclularReference;
|
|
FLastChildByName := nil;
|
|
end;
|
|
inherited Destroy;
|
|
end;
|
|
|
|
procedure TFpDwarfSymbolTypeStructure.CreateMembers;
|
|
var
|
|
Info: TDwarfInformationEntry;
|
|
Info2: TDwarfInformationEntry;
|
|
sym: TFpDwarfSymbol;
|
|
begin
|
|
if FMembers <> nil then
|
|
exit;
|
|
FMembers := TFpDbgCircularRefCntObjList.Create;
|
|
Info := InformationEntry.Clone;
|
|
Info.GoChild;
|
|
|
|
while Info.HasValidScope do begin
|
|
if (Info.AbbrevTag = DW_TAG_member) or (Info.AbbrevTag = DW_TAG_subprogram) then begin
|
|
Info2 := Info.Clone;
|
|
sym := TFpDwarfSymbol.CreateSubClass('', Info2);
|
|
FMembers.Add(sym);
|
|
sym.ReleaseReference;
|
|
sym.ParentTypeInfo := self;
|
|
Info2.ReleaseReference;
|
|
end;
|
|
Info.GoNext;
|
|
end;
|
|
|
|
Info.ReleaseReference;
|
|
end;
|
|
|
|
procedure TFpDwarfSymbolTypeStructure.InitInheritanceInfo;
|
|
begin
|
|
if FInheritanceInfo = nil then
|
|
FInheritanceInfo := InformationEntry.FindChildByTag(DW_TAG_inheritance);
|
|
end;
|
|
|
|
function TFpDwarfSymbolTypeStructure.DoGetNestedTypeInfo: TFpDwarfSymbolType;
|
|
var
|
|
FwdInfoPtr: Pointer;
|
|
FwdCompUint: TDwarfCompilationUnit;
|
|
ParentInfo: TDwarfInformationEntry;
|
|
begin
|
|
Result:= nil;
|
|
InitInheritanceInfo;
|
|
if (FInheritanceInfo <> nil) and
|
|
FInheritanceInfo.ReadReference(DW_AT_type, FwdInfoPtr, FwdCompUint)
|
|
then begin
|
|
ParentInfo := TDwarfInformationEntry.Create(FwdCompUint, FwdInfoPtr);
|
|
//DebugLn(FPDBG_DWARF_SEARCH, ['Inherited from ', dbgs(ParentInfo.FInformationEntry, FwdCompUint) ]);
|
|
Result := TFpDwarfSymbolType.CreateTypeSubClass('', ParentInfo);
|
|
ParentInfo.ReleaseReference;
|
|
end;
|
|
end;
|
|
|
|
procedure TFpDwarfSymbolTypeStructure.KindNeeded;
|
|
begin
|
|
if (InformationEntry.AbbrevTag = DW_TAG_class_type) then
|
|
SetKind(skClass)
|
|
else
|
|
begin
|
|
if TypeInfo <> nil then // inheritance
|
|
SetKind(skObject) // skClass
|
|
else
|
|
if MemberByName['_vptr$TOBJECT'] <> nil then
|
|
SetKind(skObject) // skClass
|
|
else
|
|
if MemberByName['_vptr$'+Name] <> nil then
|
|
SetKind(skObject)
|
|
else
|
|
SetKind(skRecord);
|
|
end;
|
|
end;
|
|
|
|
function TFpDwarfSymbolTypeStructure.GetTypedValueObject(ATypeCast: Boolean): TFpDwarfValue;
|
|
begin
|
|
if ATypeCast then
|
|
Result := TFpDwarfValueStructTypeCast.Create(Self)
|
|
else
|
|
Result := TFpDwarfValueStruct.Create(Self);
|
|
end;
|
|
|
|
{ TFpDwarfSymbolTypeArray }
|
|
|
|
procedure TFpDwarfSymbolTypeArray.CreateMembers;
|
|
var
|
|
Info, Info2: TDwarfInformationEntry;
|
|
t: Cardinal;
|
|
sym: TFpDwarfSymbol;
|
|
begin
|
|
if FMembers <> nil then
|
|
exit;
|
|
FMembers := TFpDbgCircularRefCntObjList.Create;
|
|
|
|
Info := InformationEntry.FirstChild;
|
|
if Info = nil then exit;
|
|
|
|
while Info.HasValidScope do begin
|
|
t := Info.AbbrevTag;
|
|
if (t = DW_TAG_enumeration_type) or (t = DW_TAG_subrange_type) then begin
|
|
Info2 := Info.Clone;
|
|
sym := TFpDwarfSymbol.CreateSubClass('', Info2);
|
|
FMembers.Add(sym);
|
|
sym.ReleaseReference;
|
|
sym.ParentTypeInfo := self;
|
|
Info2.ReleaseReference;
|
|
end;
|
|
Info.GoNext;
|
|
end;
|
|
|
|
Info.ReleaseReference;
|
|
end;
|
|
|
|
procedure TFpDwarfSymbolTypeArray.ReadStride;
|
|
var
|
|
t: TFpDwarfSymbolType;
|
|
begin
|
|
if didtStrideRead in FDwarfArrayReadFlags then
|
|
exit;
|
|
Include(FDwarfArrayReadFlags, didtStrideRead);
|
|
if InformationEntry.ReadValue(DW_AT_bit_stride, FStrideInBits) then
|
|
exit;
|
|
|
|
CreateMembers;
|
|
if (FMembers.Count > 0) and // TODO: stride for diff member
|
|
(TDbgDwarfSymbolBase(FMembers[0]).InformationEntry.ReadValue(DW_AT_byte_stride, FStrideInBits))
|
|
then begin
|
|
FStrideInBits := FStrideInBits * 8;
|
|
exit;
|
|
end;
|
|
|
|
t := NestedTypeInfo;
|
|
if t = nil then
|
|
FStrideInBits := 0 // TODO error
|
|
else
|
|
FStrideInBits := t.Size * 8;
|
|
end;
|
|
|
|
procedure TFpDwarfSymbolTypeArray.ReadOrdering;
|
|
var
|
|
AVal: Integer;
|
|
begin
|
|
if didtOrdering in FDwarfArrayReadFlags then
|
|
exit;
|
|
Include(FDwarfArrayReadFlags, didtOrdering);
|
|
if InformationEntry.ReadValue(DW_AT_ordering, AVal) then
|
|
FRowMajor := AVal = DW_ORD_row_major
|
|
else
|
|
FRowMajor := True; // default (at least in pas)
|
|
end;
|
|
|
|
procedure TFpDwarfSymbolTypeArray.KindNeeded;
|
|
begin
|
|
SetKind(skArray); // Todo: static/dynamic?
|
|
end;
|
|
|
|
function TFpDwarfSymbolTypeArray.GetTypedValueObject(ATypeCast: Boolean): TFpDwarfValue;
|
|
begin
|
|
Result := TFpDwarfValueArray.Create(Self);
|
|
end;
|
|
|
|
function TFpDwarfSymbolTypeArray.GetFlags: TDbgSymbolFlags;
|
|
function IsDynSubRange(m: TFpDwarfSymbol): Boolean;
|
|
begin
|
|
Result := sfSubRange in m.Flags;
|
|
if not Result then exit;
|
|
while (m <> nil) and not(m is TFpDwarfSymbolTypeSubRange) do
|
|
m := m.NestedTypeInfo;
|
|
Result := m <> nil;
|
|
if not Result then exit; // TODO: should not happen, handle error
|
|
Result := TFpDwarfSymbolTypeSubRange(m).FHighBoundState = rfValue; // dynamic high bound
|
|
end;
|
|
var
|
|
m: TFpDbgSymbol;
|
|
begin
|
|
Result := inherited GetFlags;
|
|
if (MemberCount = 1) then begin
|
|
m := Member[0];
|
|
if (not m.HasBounds) or // e.g. Subrange with missing upper bound
|
|
(m.OrdHighBound < m.OrdLowBound) or
|
|
(IsDynSubRange(TFpDwarfSymbol(m)))
|
|
then
|
|
Result := Result + [sfDynArray]
|
|
else
|
|
Result := Result + [sfStatArray];
|
|
end
|
|
else
|
|
Result := Result + [sfStatArray];
|
|
end;
|
|
|
|
function TFpDwarfSymbolTypeArray.GetMember(AIndex: Int64): TFpDbgSymbol;
|
|
begin
|
|
CreateMembers;
|
|
Result := TFpDbgSymbol(FMembers[AIndex]);
|
|
end;
|
|
|
|
function TFpDwarfSymbolTypeArray.GetMemberByName(AIndex: String): TFpDbgSymbol;
|
|
begin
|
|
Result := nil; // no named members
|
|
end;
|
|
|
|
function TFpDwarfSymbolTypeArray.GetMemberCount: Integer;
|
|
begin
|
|
CreateMembers;
|
|
Result := FMembers.Count;
|
|
end;
|
|
|
|
function TFpDwarfSymbolTypeArray.GetMemberAddress(AValObject: TFpDwarfValue;
|
|
AIndex: array of Int64): TFpDbgMemLocation;
|
|
var
|
|
Idx, Offs, Factor: Int64;
|
|
LowBound, HighBound: int64;
|
|
i: Integer;
|
|
bsize: Integer;
|
|
m: TFpDwarfSymbol;
|
|
begin
|
|
assert((AValObject is TFpDwarfValueArray), 'TFpDwarfSymbolTypeArray.GetMemberAddress AValObject');
|
|
ReadOrdering;
|
|
ReadStride; // TODO Stride per member (member = dimension/index)
|
|
Result := InvalidLoc;
|
|
if (FStrideInBits <= 0) or (FStrideInBits mod 8 <> 0) then
|
|
exit;
|
|
|
|
CreateMembers;
|
|
if Length(AIndex) > FMembers.Count then
|
|
exit;
|
|
|
|
if AValObject is TFpDwarfValueArray then begin
|
|
if not TFpDwarfValueArray(AValObject).GetDwarfDataAddress(Result, Self) then begin
|
|
Result := InvalidLoc;
|
|
Exit;
|
|
end;
|
|
end
|
|
else
|
|
exit; // TODO error
|
|
|
|
Offs := 0;
|
|
Factor := 1;
|
|
|
|
{$PUSH}{$R-}{$Q-} // TODO: check range of index
|
|
bsize := FStrideInBits div 8;
|
|
if FRowMajor then begin
|
|
for i := Length(AIndex) - 1 downto 0 do begin
|
|
Idx := AIndex[i];
|
|
m := TFpDwarfSymbol(FMembers[i]);
|
|
if ((m is TFpDwarfSymbolType) and (TFpDwarfSymbolType(m).GetValueBounds(AValObject, LowBound, HighBound))) or
|
|
m.HasBounds then begin
|
|
Idx := Idx - m.OrdLowBound;
|
|
end;
|
|
Offs := Offs + Idx * bsize * Factor;
|
|
if i > 0 then begin
|
|
if not m.HasBounds then begin
|
|
Result := InvalidLoc;
|
|
exit;
|
|
end;
|
|
// TODO range check
|
|
Factor := Factor * (m.OrdHighBound - m.OrdLowBound + 1);
|
|
end;
|
|
end;
|
|
end
|
|
else begin
|
|
for i := 0 to Length(AIndex) - 1 do begin
|
|
Idx := AIndex[i];
|
|
m := TFpDwarfSymbol(FMembers[i]);
|
|
if m.HasBounds then begin
|
|
Idx := Idx - m.OrdLowBound;
|
|
end;
|
|
Offs := Offs + Idx * bsize * Factor;
|
|
if i < Length(AIndex) - 1 then begin
|
|
if not m.HasBounds then begin
|
|
Result := InvalidLoc;
|
|
exit;
|
|
end;
|
|
Factor := Factor * (m.OrdHighBound - m.OrdLowBound + 1);
|
|
end;
|
|
end;
|
|
end;
|
|
|
|
assert(IsTargetAddr(Result), 'DwarfArray MemberAddress');
|
|
Result.Address := Result.Address + Offs;
|
|
{$POP}
|
|
end;
|
|
|
|
destructor TFpDwarfSymbolTypeArray.Destroy;
|
|
var
|
|
i: Integer;
|
|
begin
|
|
if FMembers <> nil then begin
|
|
for i := 0 to FMembers.Count - 1 do
|
|
TFpDwarfSymbol(FMembers[i]).ParentTypeInfo := nil;
|
|
FreeAndNil(FMembers);
|
|
end;
|
|
inherited Destroy;
|
|
end;
|
|
|
|
{ TDbgDwarfSymbol }
|
|
|
|
constructor TFpDwarfSymbolValueProc.Create(ACompilationUnit: TDwarfCompilationUnit;
|
|
AInfo: PDwarfAddressInfo; AAddress: TDbgPtr);
|
|
var
|
|
InfoEntry: TDwarfInformationEntry;
|
|
begin
|
|
FAddress := AAddress;
|
|
FAddressInfo := AInfo;
|
|
|
|
InfoEntry := TDwarfInformationEntry.Create(ACompilationUnit, nil);
|
|
InfoEntry.ScopeIndex := AInfo^.ScopeIndex;
|
|
|
|
inherited Create(
|
|
String(FAddressInfo^.Name),
|
|
InfoEntry
|
|
);
|
|
|
|
SetAddress(TargetLoc(FAddressInfo^.StartPC));
|
|
|
|
InfoEntry.ReleaseReference;
|
|
//BuildLineInfo(
|
|
|
|
// AFile: String = ''; ALine: Integer = -1; AFlags: TDbgSymbolFlags = []; const AReference: TDbgSymbol = nil);
|
|
end;
|
|
|
|
destructor TFpDwarfSymbolValueProc.Destroy;
|
|
begin
|
|
FreeAndNil(FProcMembers);
|
|
FLastMember.ReleaseReference{$IFDEF WITH_REFCOUNT_DEBUG}(@FLastMember, 'TFpDwarfSymbolValueProc.FLastMember'){$ENDIF};
|
|
FreeAndNil(FStateMachine);
|
|
if FSelfParameter <> nil then begin
|
|
//TDbgDwarfIdentifier(FSelfParameter.DbgSymbol).ParentTypeInfo := nil;
|
|
FSelfParameter.ReleaseReference{$IFDEF WITH_REFCOUNT_DEBUG}(@FSelfParameter, 'FSelfParameter'){$ENDIF};
|
|
end;
|
|
inherited Destroy;
|
|
end;
|
|
|
|
function TFpDwarfSymbolValueProc.GetColumn: Cardinal;
|
|
begin
|
|
if StateMachineValid
|
|
then Result := FStateMachine.Column
|
|
else Result := inherited GetColumn;
|
|
end;
|
|
|
|
function TFpDwarfSymbolValueProc.GetFile: String;
|
|
begin
|
|
if StateMachineValid
|
|
then Result := FStateMachine.FileName
|
|
else Result := inherited GetFile;
|
|
end;
|
|
|
|
function TFpDwarfSymbolValueProc.GetLine: Cardinal;
|
|
begin
|
|
if StateMachineValid
|
|
then Result := FStateMachine.Line
|
|
else Result := inherited GetLine;
|
|
end;
|
|
|
|
function TFpDwarfSymbolValueProc.GetValueObject: TFpDbgValue;
|
|
begin
|
|
Result := FValueObject;
|
|
if Result <> nil then exit;
|
|
|
|
FValueObject := TFpDwarfValue.Create(nil);
|
|
{$IFDEF WITH_REFCOUNT_DEBUG}FValueObject.DbgRenameReference(@FValueObject, ClassName+'.FValueObject');{$ENDIF}
|
|
FValueObject.MakePlainRefToCirclular;
|
|
FValueObject.SetValueSymbol(self);
|
|
|
|
Result := FValueObject;
|
|
end;
|
|
|
|
function TFpDwarfSymbolValueProc.StateMachineValid: Boolean;
|
|
var
|
|
SM1, SM2: TDwarfLineInfoStateMachine;
|
|
begin
|
|
Result := FStateMachine <> nil;
|
|
if Result then Exit;
|
|
|
|
if FAddressInfo^.StateMachine = nil
|
|
then begin
|
|
CompilationUnit.BuildLineInfo(FAddressInfo, False);
|
|
if FAddressInfo^.StateMachine = nil then Exit;
|
|
end;
|
|
|
|
// we cannot restore a statemachine to its current state
|
|
// so we shouldn't modify FAddressInfo^.StateMachine
|
|
// so use clones to navigate
|
|
SM1 := FAddressInfo^.StateMachine.Clone;
|
|
if FAddress < SM1.Address
|
|
then begin
|
|
// The address we want to find is before the start of this symbol ??
|
|
SM1.Free;
|
|
Exit;
|
|
end;
|
|
SM2 := FAddressInfo^.StateMachine.Clone;
|
|
|
|
repeat
|
|
if (FAddress = SM1.Address)
|
|
or not SM2.NextLine
|
|
or (FAddress < SM2.Address)
|
|
then begin
|
|
// found
|
|
FStateMachine := SM1;
|
|
SM2.Free;
|
|
Result := True;
|
|
Exit;
|
|
end;
|
|
until not SM1.NextLine;
|
|
|
|
//if all went well we shouldn't come here
|
|
SM1.Free;
|
|
SM2.Free;
|
|
end;
|
|
|
|
function TFpDwarfSymbolValueProc.ReadVirtuality(out AFlags: TDbgSymbolFlags): Boolean;
|
|
var
|
|
Val: Integer;
|
|
begin
|
|
AFlags := [];
|
|
Result := InformationEntry.ReadValue(DW_AT_virtuality, Val);
|
|
if not Result then exit;
|
|
case Val of
|
|
DW_VIRTUALITY_none: ;
|
|
DW_VIRTUALITY_virtual: AFlags := [sfVirtual];
|
|
DW_VIRTUALITY_pure_virtual: AFlags := [sfVirtual];
|
|
end;
|
|
end;
|
|
|
|
procedure TFpDwarfSymbolValueProc.CreateMembers;
|
|
var
|
|
Info: TDwarfInformationEntry;
|
|
Info2: TDwarfInformationEntry;
|
|
begin
|
|
if FProcMembers <> nil then
|
|
exit;
|
|
FProcMembers := TRefCntObjList.Create;
|
|
Info := InformationEntry.Clone;
|
|
Info.GoChild;
|
|
|
|
while Info.HasValidScope do begin
|
|
if ((Info.AbbrevTag = DW_TAG_formal_parameter) or (Info.AbbrevTag = DW_TAG_variable)) //and
|
|
//not(Info.IsArtificial)
|
|
then begin
|
|
Info2 := Info.Clone;
|
|
FProcMembers.Add(Info2);
|
|
Info2.ReleaseReference;
|
|
end;
|
|
Info.GoNext;
|
|
end;
|
|
|
|
Info.ReleaseReference;
|
|
end;
|
|
|
|
function TFpDwarfSymbolValueProc.GetMember(AIndex: Int64): TFpDbgSymbol;
|
|
begin
|
|
CreateMembers;
|
|
FLastMember.ReleaseReference{$IFDEF WITH_REFCOUNT_DEBUG}(@FLastMember, 'TFpDwarfSymbolValueProc.FLastMember'){$ENDIF};
|
|
FLastMember := TFpDwarfSymbol.CreateSubClass('', TDwarfInformationEntry(FProcMembers[AIndex]));
|
|
{$IFDEF WITH_REFCOUNT_DEBUG}FLastMember.DbgRenameReference(@FLastMember, 'TFpDwarfSymbolValueProc.FLastMember');{$ENDIF}
|
|
Result := FLastMember;
|
|
end;
|
|
|
|
function TFpDwarfSymbolValueProc.GetMemberByName(AIndex: String): TFpDbgSymbol;
|
|
var
|
|
Info: TDwarfInformationEntry;
|
|
s, s2: String;
|
|
i: Integer;
|
|
begin
|
|
CreateMembers;
|
|
s2 := LowerCase(AIndex);
|
|
FLastMember.ReleaseReference{$IFDEF WITH_REFCOUNT_DEBUG}(@FLastMember, 'TFpDwarfSymbolValueProc.FLastMember'){$ENDIF};
|
|
FLastMember := nil;;
|
|
for i := 0 to FProcMembers.Count - 1 do begin
|
|
Info := TDwarfInformationEntry(FProcMembers[i]);
|
|
if Info.ReadName(s) and (LowerCase(s) = s2) then begin
|
|
FLastMember := TFpDwarfSymbol.CreateSubClass('', Info);
|
|
{$IFDEF WITH_REFCOUNT_DEBUG}FLastMember.DbgRenameReference(@FLastMember, 'TFpDwarfSymbolValueProc.FLastMember');{$ENDIF}
|
|
break;
|
|
end;
|
|
end;
|
|
Result := FLastMember;
|
|
end;
|
|
|
|
function TFpDwarfSymbolValueProc.GetMemberCount: Integer;
|
|
begin
|
|
CreateMembers;
|
|
Result := FProcMembers.Count;
|
|
end;
|
|
|
|
function TFpDwarfSymbolValueProc.GetFrameBase(ASender: TDwarfLocationExpression): TDbgPtr;
|
|
var
|
|
Val: TByteDynArray;
|
|
begin
|
|
Result := 0;
|
|
if FFrameBaseParser = nil then begin
|
|
//TODO: avoid copying data
|
|
if not InformationEntry.ReadValue(DW_AT_frame_base, Val) then begin
|
|
// error
|
|
debugln(FPDBG_DWARF_ERRORS, ['TFpDwarfSymbolValueProc.GetFrameBase failed to read DW_AT_frame_base']);
|
|
exit;
|
|
end;
|
|
if Length(Val) = 0 then begin
|
|
// error
|
|
debugln(FPDBG_DWARF_ERRORS, ['TFpDwarfSymbolValueProc.GetFrameBase failed to read DW_AT_location']);
|
|
exit;
|
|
end;
|
|
|
|
FFrameBaseParser := TDwarfLocationExpression.Create(@Val[0], Length(Val), CompilationUnit,
|
|
ASender.MemManager, ASender.Context);
|
|
FFrameBaseParser.Evaluate;
|
|
end;
|
|
|
|
if FFrameBaseParser.ResultKind in [lseValue] then
|
|
Result := FFrameBaseParser.ResultData;
|
|
|
|
if IsError(FFrameBaseParser.LastError) then begin
|
|
SetLastError(FFrameBaseParser.LastError);
|
|
debugln(FPDBG_DWARF_ERRORS, ['TFpDwarfSymbolValueProc.GetFrameBase location parser failed ', ErrorHandler.ErrorAsString(LastError)]);
|
|
end
|
|
else
|
|
if Result = 0 then begin
|
|
debugln(FPDBG_DWARF_ERRORS, ['TFpDwarfSymbolValueProc.GetFrameBase location parser failed. result is 0']);
|
|
end;
|
|
|
|
end;
|
|
|
|
procedure TFpDwarfSymbolValueProc.KindNeeded;
|
|
begin
|
|
if TypeInfo <> nil then
|
|
SetKind(skFunction)
|
|
else
|
|
SetKind(skProcedure);
|
|
end;
|
|
|
|
procedure TFpDwarfSymbolValueProc.SizeNeeded;
|
|
begin
|
|
SetSize(FAddressInfo^.EndPC - FAddressInfo^.StartPC);
|
|
end;
|
|
|
|
function TFpDwarfSymbolValueProc.GetFlags: TDbgSymbolFlags;
|
|
var
|
|
flg: TDbgSymbolFlags;
|
|
begin
|
|
Result := inherited GetFlags;
|
|
if ReadVirtuality(flg) then
|
|
Result := Result + flg;
|
|
end;
|
|
|
|
function TFpDwarfSymbolValueProc.GetSelfParameter(AnAddress: TDbgPtr): TFpDwarfValue;
|
|
const
|
|
this1: string = 'THIS';
|
|
this2: string = 'this';
|
|
self1: string = '$SELF';
|
|
self2: string = '$self';
|
|
var
|
|
InfoEntry: TDwarfInformationEntry;
|
|
tg: Cardinal;
|
|
found: Boolean;
|
|
begin
|
|
// special: search "self"
|
|
// Todo nested procs
|
|
Result := FSelfParameter;
|
|
if Result <> nil then exit;
|
|
|
|
InfoEntry := InformationEntry.Clone;
|
|
//StartScopeIdx := InfoEntry.ScopeIndex;
|
|
InfoEntry.GoParent;
|
|
tg := InfoEntry.AbbrevTag;
|
|
if (tg = DW_TAG_class_type) or (tg = DW_TAG_structure_type) then begin
|
|
InfoEntry.ScopeIndex := InformationEntry.ScopeIndex;
|
|
found := InfoEntry.GoNamedChildEx(@this1[1], @this2[1]);
|
|
if not found then begin
|
|
InfoEntry.ScopeIndex := InformationEntry.ScopeIndex;
|
|
found := InfoEntry.GoNamedChildEx(@self1[1], @self2[1]);
|
|
end;
|
|
if found then begin
|
|
if ((AnAddress = 0) or InfoEntry.IsAddressInStartScope(AnAddress)) and
|
|
InfoEntry.IsArtificial
|
|
then begin
|
|
Result := TFpDwarfValue(TFpDwarfSymbolValue.CreateValueSubClass('self', InfoEntry).Value);
|
|
FSelfParameter := Result;
|
|
FSelfParameter.AddReference{$IFDEF WITH_REFCOUNT_DEBUG}(@FSelfParameter, 'FSelfParameter'){$ENDIF};
|
|
FSelfParameter.DbgSymbol.ReleaseReference;
|
|
//FSelfParameter.DbgSymbol.ParentTypeInfo := Self;
|
|
debugln(FPDBG_DWARF_SEARCH, ['TFpDwarfSymbolValueProc.GetSelfParameter ', InfoEntry.ScopeDebugText, DbgSName(Result)]);
|
|
end;
|
|
end;
|
|
end;
|
|
InfoEntry.ReleaseReference;
|
|
end;
|
|
|
|
{ TFpDwarfSymbolValueVariable }
|
|
|
|
function TFpDwarfSymbolValueVariable.GetValueAddress(AValueObj: TFpDwarfValue; out
|
|
AnAddress: TFpDbgMemLocation): Boolean;
|
|
begin
|
|
AnAddress := AValueObj.DataAddressCache[0];
|
|
Result := IsValidLoc(AnAddress);
|
|
if IsInitializedLoc(AnAddress) then
|
|
exit;
|
|
Result := LocationFromTag(DW_AT_location, AValueObj, AnAddress);
|
|
AValueObj.DataAddressCache[0] := AnAddress;
|
|
end;
|
|
|
|
function TFpDwarfSymbolValueVariable.HasAddress: Boolean;
|
|
begin
|
|
Result := InformationEntry.HasAttrib(DW_AT_location);
|
|
end;
|
|
|
|
{ TFpDwarfSymbolValueParameter }
|
|
|
|
function TFpDwarfSymbolValueParameter.GetValueAddress(AValueObj: TFpDwarfValue; out
|
|
AnAddress: TFpDbgMemLocation): Boolean;
|
|
begin
|
|
AnAddress := AValueObj.DataAddressCache[0];
|
|
Result := IsValidLoc(AnAddress);
|
|
if IsInitializedLoc(AnAddress) then
|
|
exit;
|
|
Result := LocationFromTag(DW_AT_location, AValueObj, AnAddress);
|
|
AValueObj.DataAddressCache[0] := AnAddress;
|
|
end;
|
|
|
|
function TFpDwarfSymbolValueParameter.HasAddress: Boolean;
|
|
begin
|
|
Result := InformationEntry.HasAttrib(DW_AT_location);
|
|
end;
|
|
|
|
function TFpDwarfSymbolValueParameter.GetFlags: TDbgSymbolFlags;
|
|
begin
|
|
Result := (inherited GetFlags) + [sfParameter];
|
|
end;
|
|
|
|
{ TFpDwarfSymbolUnit }
|
|
|
|
procedure TFpDwarfSymbolUnit.Init;
|
|
begin
|
|
inherited Init;
|
|
SetSymbolType(stNone);
|
|
SetKind(skUnit);
|
|
end;
|
|
|
|
function TFpDwarfSymbolUnit.GetMemberByName(AIndex: String): TFpDbgSymbol;
|
|
var
|
|
Ident: TDwarfInformationEntry;
|
|
begin
|
|
// Todo, param to only search external.
|
|
ReleaseRefAndNil(FLastChildByName);
|
|
Result := nil;
|
|
|
|
Ident := InformationEntry.Clone;
|
|
Ident.GoNamedChildEx(AIndex);
|
|
if Ident <> nil then
|
|
Result := TFpDwarfSymbol.CreateSubClass('', Ident);
|
|
// No need to set ParentTypeInfo
|
|
ReleaseRefAndNil(Ident);
|
|
FLastChildByName := Result;
|
|
end;
|
|
|
|
destructor TFpDwarfSymbolUnit.Destroy;
|
|
begin
|
|
ReleaseRefAndNil(FLastChildByName);
|
|
inherited Destroy;
|
|
end;
|
|
|
|
initialization
|
|
DwarfSymbolClassMapList.SetDefaultMap(TFpDwarfDefaultSymbolClassMap);
|
|
|
|
FPDBG_DWARF_VERBOSE := DebugLogger.FindOrRegisterLogGroup('FPDBG_DWARF_VERBOSE' {$IFDEF FPDBG_DWARF_VERBOSE} , True {$ENDIF} );
|
|
FPDBG_DWARF_ERRORS := DebugLogger.FindOrRegisterLogGroup('FPDBG_DWARF_ERRORS' {$IFDEF FPDBG_DWARF_ERRORS} , True {$ENDIF} );
|
|
FPDBG_DWARF_WARNINGS := DebugLogger.FindOrRegisterLogGroup('FPDBG_DWARF_WARNINGS' {$IFDEF FPDBG_DWARF_WARNINGS} , True {$ENDIF} );
|
|
FPDBG_DWARF_SEARCH := DebugLogger.FindOrRegisterLogGroup('FPDBG_DWARF_SEARCH' {$IFDEF FPDBG_DWARF_SEARCH} , True {$ENDIF} );
|
|
FPDBG_DWARF_DATA_WARNINGS := DebugLogger.FindOrRegisterLogGroup('FPDBG_DWARF_DATA_WARNINGS' {$IFDEF FPDBG_DWARF_DATA_WARNINGS} , True {$ENDIF} );
|
|
|
|
end.
|
|
|