FPDebug: Value handling / array

git-svn-id: trunk@43996 -
This commit is contained in:
martin 2014-02-11 02:56:55 +00:00
parent 8c42dd719a
commit b585ed6d46
9 changed files with 752 additions and 80 deletions

2
.gitattributes vendored
View File

@ -1283,8 +1283,10 @@ components/fpdebug/test/dwarfviewer/dwarfviewer.lpr svneol=native#text/pascal
components/fpdebug/test/dwarfviewer/unit1.lfm svneol=native#text/pascal
components/fpdebug/test/dwarfviewer/unit1.pas svneol=native#text/pascal
components/fpdebug/test/testdata/dwarfsetup1.lpr svneol=native#text/pascal
components/fpdebug/test/testdata/dwarfsetuparray.lpr svneol=native#text/pascal
components/fpdebug/test/testdata/dwarfsetupbasic.lpr svneol=native#text/plain
components/fpdebug/test/testdwarfsetup1.pas svneol=native#text/pascal
components/fpdebug/test/testdwarfsetuparray.pas svneol=native#text/pascal
components/fpdebug/test/testdwarfsetupbasic.pas svneol=native#text/pascal
components/fpdebug/test/testdwarfvarious.pas svneol=native#text/pascal
components/fpdebug/test/testhelperclasses.pas svneol=native#text/pascal

View File

@ -598,6 +598,7 @@ type
function MemReader: TFpDbgMemReaderBase; inline;
function AddressSize: Byte; inline;
protected
function GetDwarfDataAddress(out AnAddress: TDbgPtr; ATargetType: TDbgDwarfTypeIdentifier = nil): Boolean; reintroduce;
procedure Reset; virtual;
function GetFieldFlags: TDbgSymbolValueFieldFlags; override;
function HasTypeCastInfo: Boolean;
@ -785,7 +786,6 @@ type
function GetSize: Integer; override;
function GetDataSize: Integer; override;
function GetDataAddress: TDbgPtr; override;
function GetDwarfDataAddress(out AnAddress: TDbgPtr; ATargetType: TDbgDwarfTypeIdentifier = nil): Boolean; reintroduce;
function IsValidTypeCast: Boolean; override;
public
destructor Destroy; override;
@ -794,6 +794,33 @@ type
function GetMemberCount: Integer; override;
end;
{ TDbgDwarfSymbolValueConstAddress }
TDbgDwarfSymbolValueConstAddress = class(TDbgSymbolValueConstAddress)
protected
procedure Update(AnAddress: TDbgPtr);
end;
{ TDbgDwarfArraySymbolValue }
TDbgDwarfArraySymbolValue = class(TDbgDwarfSymbolValue)
private
FResVal: TDbgSymbolValue;
FAddrObj: TDbgDwarfSymbolValueConstAddress;
protected
function GetFieldFlags: TDbgSymbolValueFieldFlags; override;
function GetKind: TDbgSymbolKind; override;
function GetMember(AIndex: Integer): TDbgSymbolValue; override;
function GetMemberEx(AIndex: array of Int64): TDbgSymbolValue; override;
function GetMemberCount: Integer; override;
function GetMemberCountEx(AIndex: array of Int64): Integer; override;
function GetIndexType(AIndex: Integer): TDbgSymbol; override;
function GetIndexTypeCount: Integer; override;
function IsValidTypeCast: Boolean; override;
public
destructor Destroy; override;
end;
{ TDbgDwarfIdentifier }
TDbgDwarfIdentifier = class(TDbgSymbolForwarder)
@ -1166,14 +1193,22 @@ DECL = DW_AT_decl_column, DW_AT_decl_file, DW_AT_decl_line
TDbgDwarfIdentifierArray = class(TDbgDwarfTypeIdentifier)
private
FMembers: TFpDbgCircularRefCntObjList;
FRowMajor: Boolean;
FStrideInBits: Int64;
FDwarfArrayReadFlags: set of (didtStrideRead, didtOrdering);
procedure CreateMembers;
procedure ReadStride;
procedure ReadOrdering;
protected
procedure KindNeeded; override;
function GetTypedValueObject(ATypeCast: Boolean): TDbgDwarfSymbolValue; override;
function GetFlags: TDbgSymbolFlags; override;
// GetMember: returns the TYPE/range of each index. NOT the data
function GetMember(AIndex: Integer): TDbgSymbol; override;
function GetMemberByName({%H-}AIndex: String): TDbgSymbol; override;
function GetMemberCount: Integer; override;
function GetMemberAddress(AValObject: TObject; AIndex: Array of Int64): TDbgPtr;
public
destructor Destroy; override;
end;
@ -1779,6 +1814,127 @@ begin
end;
end;
{ TDbgDwarfSymbolValueConstAddress }
procedure TDbgDwarfSymbolValueConstAddress.Update(AnAddress: TDbgPtr);
begin
Address := AnAddress;
end;
{ TDbgDwarfArraySymbolValue }
function TDbgDwarfArraySymbolValue.GetFieldFlags: TDbgSymbolValueFieldFlags;
begin
Result := inherited GetFieldFlags;
Result := Result + [svfMembers];
end;
function TDbgDwarfArraySymbolValue.GetKind: TDbgSymbolKind;
begin
Result := skArray;
end;
function TDbgDwarfArraySymbolValue.GetMember(AIndex: Integer): TDbgSymbolValue;
begin
Result := GetMemberEx([AIndex]);
end;
function TDbgDwarfArraySymbolValue.GetMemberEx(AIndex: array of Int64): TDbgSymbolValue;
var
Addr: TDbgPtr;
begin
Result := nil;
assert((FOwner is TDbgDwarfIdentifierArray) and (FOwner.Kind = skArray));
Addr := TDbgDwarfIdentifierArray(FOwner).GetMemberAddress(Self, AIndex);
if Addr = 0 then exit;
if (FAddrObj = nil) or (FAddrObj.RefCount > 1) then begin
FAddrObj.ReleaseReference;
FAddrObj := TDbgDwarfSymbolValueConstAddress.Create(Addr);
end
else begin
FAddrObj.Update(Addr);
FAddrObj.AddReference;
end;
if (FResVal = nil) or (FResVal.RefCount > 1) then begin
FResVal.ReleaseReference;
FResVal := FOwner.TypeInfo.TypeCastValue(FAddrObj);
end
else begin
TDbgDwarfSymbolValue(FResVal).SetTypeCastInfo(TDbgDwarfTypeIdentifier(FOwner), FAddrObj);
end;
FAddrObj.ReleaseReference;
Result := FResVal;
end;
function TDbgDwarfArraySymbolValue.GetMemberCount: Integer;
var
t: TDbgSymbol;
begin
Result := 0;
t := TypeInfo;
if t.MemberCount < 1 then
exit;
t := t.Member[0];
if not t.HasBounds then
exit;
Result := t.OrdHighBound - t.OrdLowBound + 1;
end;
function TDbgDwarfArraySymbolValue.GetMemberCountEx(AIndex: array of Int64): Integer;
var
t: TDbgSymbol;
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 TDbgDwarfArraySymbolValue.GetIndexType(AIndex: Integer): TDbgSymbol;
begin
Result := TypeInfo.Member[AIndex];
end;
function TDbgDwarfArraySymbolValue.GetIndexTypeCount: Integer;
begin
Result := TypeInfo.MemberCount;
end;
function TDbgDwarfArraySymbolValue.IsValidTypeCast: Boolean;
begin
Result := HasTypeCastInfo;
If not Result then
exit;
// TODO ordinal
if (FTypeCastSourceValue.FieldFlags * [svfAddress, svfSize, svfSizeOfPointer] = [svfAddress]) then
exit
else
if (FTypeCastSourceValue.FieldFlags * [svfAddress, svfSize] = [svfAddress, svfSize]) and
(FTypeCastSourceValue.Size = FOwner.FCU.FAddressSize)
then
exit
else
if (FTypeCastSourceValue.FieldFlags * [svfAddress, svfSizeOfPointer] = [svfAddress, svfSizeOfPointer])
then
exit;
Result := False;
end;
destructor TDbgDwarfArraySymbolValue.Destroy;
begin
FResVal.ReleaseReference;
inherited Destroy;
end;
{ TDbgDwarfSymbolValueConstNumber }
procedure TDbgDwarfSymbolValueConstNumber.Update(AValue: QWord; ASigned: Boolean);
@ -2264,43 +2420,6 @@ begin
Result := inherited GetDataAddress;
end;
function TDbgDwarfStructTypeCastSymbolValue.GetDwarfDataAddress(out AnAddress: TDbgPtr;
ATargetType: TDbgDwarfTypeIdentifier): Boolean;
var
fields: TDbgSymbolValueFieldFlags;
t: TDbgDwarfTypeIdentifier;
begin
Result := HasTypeCastInfo;
if not Result then
exit;
fields := FTypeCastSourceValue.FieldFlags;
AnAddress := 0;
if svfOrdinal in fields then begin
AnAddress := FTypeCastSourceValue.AsCardinal;
// MUST store, and provide address of it // for now, skip the pointer
t := FTypeCastTargetType;
if t is TDbgDwarfTypeIdentifierDeclaration then t := t.NestedTypeInfo;
if (t<> nil) and (t is TDbgDwarfTypeIdentifierPointer) then t := t.NestedTypeInfo;
if (t<> nil) then begin
Result := t.GetDataAddress(AnAddress, ATargetType);
Result := AnAddress <> 0;
exit;
end;
Result := False;
exit;
end
else
if svfAddress in fields then
AnAddress := FTypeCastSourceValue.Address;
Result := AnAddress <> 0;
if not Result then
exit;
Result := FTypeCastTargetType.GetDataAddress(AnAddress, ATargetType);
end;
function TDbgDwarfStructTypeCastSymbolValue.IsValidTypeCast: Boolean;
var
f: TDbgSymbolValueFieldFlags;
@ -2529,6 +2648,54 @@ begin
Result := FOwner.FCU.FAddressSize;
end;
function TDbgDwarfSymbolValue.GetDwarfDataAddress(out AnAddress: TDbgPtr;
ATargetType: TDbgDwarfTypeIdentifier): Boolean;
var
fields: TDbgSymbolValueFieldFlags;
t: TDbgDwarfTypeIdentifier;
begin
if FValueSymbol <> nil then begin
Assert(FValueSymbol is TDbgDwarfValueIdentifier, 'TDbgDwarfSymbolValue.GetDwarfDataAddress FValueSymbol');
Assert(TypeInfo is TDbgDwarfTypeIdentifier, 'TDbgDwarfSymbolValue.GetDwarfDataAddress TypeInfo');
Assert(not HasTypeCastInfo, 'TDbgDwarfSymbolValue.GetDwarfDataAddress not HasTypeCastInfo');
Result := FValueSymbol.GetDataAddress(AnAddress, TDbgDwarfTypeIdentifier(FOwner));
end
else
begin
// try typecast
Result := HasTypeCastInfo;
if not Result then
exit;
fields := FTypeCastSourceValue.FieldFlags;
AnAddress := 0;
if svfOrdinal in fields then begin
AnAddress := FTypeCastSourceValue.AsCardinal;
// MUST store, and provide address of it // for now, skip the pointer
t := FTypeCastTargetType;
if t is TDbgDwarfTypeIdentifierDeclaration then t := t.NestedTypeInfo;
if (t<> nil) and (t is TDbgDwarfTypeIdentifierPointer) then t := t.NestedTypeInfo;
if (t<> nil) then begin
Result := t.GetDataAddress(AnAddress, ATargetType);
Result := AnAddress <> 0;
exit;
end;
Result := False;
exit;
end
else
if svfAddress in fields then
AnAddress := FTypeCastSourceValue.Address;
Result := AnAddress <> 0;
if not Result then
exit;
Result := FTypeCastTargetType.GetDataAddress(AnAddress, ATargetType);
end;
end;
procedure TDbgDwarfSymbolValue.Reset;
begin
//
@ -5446,11 +5613,45 @@ begin
Info.ReleaseReference;
end;
procedure TDbgDwarfIdentifierArray.ReadStride;
var
t: TDbgDwarfTypeIdentifier;
begin
if didtStrideRead in FDwarfArrayReadFlags then
exit;
Include(FDwarfArrayReadFlags, didtStrideRead);
if not FInformationEntry.ReadValue(DW_AT_bit_stride, FStrideInBits) then begin
t := NestedTypeInfo;
if t = nil then
FStrideInBits := 0
else
FStrideInBits := t.Size * 8;
end;
end;
procedure TDbgDwarfIdentifierArray.ReadOrdering;
var
AVal: Integer;
begin
if didtOrdering in FDwarfArrayReadFlags then
exit;
Include(FDwarfArrayReadFlags, didtOrdering);
if FInformationEntry.ReadValue(DW_AT_ordering, AVal) then
FRowMajor := AVal = DW_ORD_row_major
else
FRowMajor := True; // default (at least in pas)
end;
procedure TDbgDwarfIdentifierArray.KindNeeded;
begin
SetKind(skArray); // Todo: static/dynamic?
end;
function TDbgDwarfIdentifierArray.GetTypedValueObject(ATypeCast: Boolean): TDbgDwarfSymbolValue;
begin
Result := TDbgDwarfArraySymbolValue.Create(Self);
end;
function TDbgDwarfIdentifierArray.GetFlags: TDbgSymbolFlags;
function IsDynSubRange(m: TDbgDwarfIdentifier): Boolean;
begin
@ -5497,6 +5698,75 @@ begin
Result := FMembers.Count;
end;
function TDbgDwarfIdentifierArray.GetMemberAddress(AValObject: TObject;
AIndex: array of Int64): TDbgPtr;
var
Offs, Factor: QWord;
i: Integer;
bsize: Integer;
m: TDbgDwarfIdentifier;
begin
assert((AValObject is TDbgDwarfValueIdentifier) or (AValObject is TDbgDwarfArraySymbolValue), 'TDbgDwarfIdentifierArray.GetMemberAddress AValObject');
ReadOrdering;
ReadStride;
Result := 0;
if (FStrideInBits <= 0) or (FStrideInBits mod 8 <> 0) then
exit;
CreateMembers;
if Length(AIndex) > FMembers.Count then
exit;
// TODO: reduce index by low-ord
if AValObject is TDbgDwarfValueIdentifier then begin
if not TDbgDwarfValueIdentifier(AValObject).GetDataAddress(Result, Self) then begin
Result := 0;
Exit;
end;
end
else
if AValObject is TDbgDwarfArraySymbolValue then begin
if not TDbgDwarfArraySymbolValue(AValObject).GetDwarfDataAddress(Result, Self) then begin
Result := 0;
Exit;
end;
end;
Offs := 0;
Factor := 1;
bsize := FStrideInBits div 8;
if FRowMajor then begin
for i := Length(AIndex) - 1 downto 0 do begin
Offs := Offs + AIndex[i] * bsize * Factor;
if i > 0 then begin
m := TDbgDwarfIdentifier(FMembers[i]);
if not m.HasBounds then begin
Result := 0;
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
Offs := Offs + AIndex[i] * bsize * Factor;
if i < Length(AIndex) - 1 then begin
m := TDbgDwarfIdentifier(FMembers[i]);
if not m.HasBounds then begin
Result := 0;
exit;
end;
Factor := Factor * (m.OrdHighBound - m.OrdLowBound + 1);
end;
end;
end;
Result := Result + Offs;
end;
destructor TDbgDwarfIdentifierArray.Destroy;
var
i: Integer;

View File

@ -128,7 +128,7 @@ const
DW_AT_prototyped = $27 ; // flag
DW_AT_return_addr = $2a ; // block, loclistptr
DW_AT_start_scope = $2c ; // constant
DW_AT_bit_stride = $2e ; // constant
DW_AT_bit_stride = $2e ; // constant // Dwarf 2 refers to it as DW_AT_stride_size
DW_AT_upper_bound = $2f ; // block, constant, reference
DW_AT_abstract_origin = $31 ; // reference
DW_AT_accessibility = $32 ; // constant

View File

@ -159,6 +159,11 @@ type
function GetMember(AIndex: Integer): TDbgSymbolValue; virtual;
function GetMemberByName(AIndex: String): TDbgSymbolValue; virtual;
function GetMemberCount: Integer; virtual;
function GetIndexType(AIndex: Integer): TDbgSymbol; virtual;
function GetIndexTypeCount: Integer; virtual;
function GetMemberCountEx(AIndex: array of Int64): Integer; virtual;
function GetMemberEx(AIndex: Array of Int64): TDbgSymbolValue; virtual;
function GetDbgSymbol: TDbgSymbol; virtual;
function GetTypeInfo: TDbgSymbol; virtual;
public
@ -183,9 +188,16 @@ type
property DataSize: Integer read GetDataSize; // Sive of Data, if avail (e.g. String, TObject, ..., BUT NOT record)
// memdump
public
// base class? Or Member inncludes member from base
// base class? Or Member includes member from base
(* Member:
For TypeInfo (skType) it excludes BaseClass For Value (skValue): ???
* skClass, skStructure:
stType: it excludes BaseClass (TODO: decide?)
stValue: ???
* skSet
stType: all members
stValue: only members set in value (Only impremented for DbgSymbolValue)
* skArray: (differs from TDbgSymbol)
The values. The type of each Index-dimension is avail via IndexType
NOTE: Values returned by Member/MemberByName are volatile.
They maybe released or changed when Member is called again.
To keep a returned Value a reference can be added (AddReference)
@ -193,6 +205,11 @@ type
property MemberCount: Integer read GetMemberCount;
property Member[AIndex: Integer]: TDbgSymbolValue read GetMember;
property MemberByName[AIndex: String]: TDbgSymbolValue read GetMemberByName; // Includes inheritance
// For Arrays (TODO pointers) only, the values stored in the array
property MemberCountEx[AIndex: Array of Int64]: Integer read GetMemberCountEx;
property MemberEx[AIndex: Array of Int64]: TDbgSymbolValue read GetMemberEx;
property IndexTypeCount: Integer read GetIndexTypeCount;
property IndexType[AIndex: Integer]: TDbgSymbol read GetIndexType;
(* DbgSymbol: The TDbgSymbol from which this value came, maybe nil.
Maybe a stType, then there is no Value *)
@ -217,6 +234,20 @@ type
constructor Create(AValue: QWord; ASigned: Boolean = True);
end;
{ TDbgSymbolValueConstAddress }
TDbgSymbolValueConstAddress = class(TDbgSymbolValue)
private
FAddress: TDbgPtr;
protected
property Address: QWord read FAddress write FAddress;
//function GetKind: TDbgSymbolKind; override; // no kind
function GetFieldFlags: TDbgSymbolValueFieldFlags; override;
function GetAddress: TDbgPtr; override;
public
constructor Create(AnAddress: TDbgPtr);
end;
{ TDbgSymbol }
TDbgSymbol = class(TDbgSymbolBase)
@ -304,8 +335,18 @@ type
property MemberVisibility: TDbgSymbolMemberVisibility read GetMemberVisibility;
property MemberCount: Integer read GetMemberCount;
(* Member:
For TypeInfo (skType) it excludes BaseClass
For Value (skValue): ???
* skClass, skStructure:
stType: it excludes BaseClass (TODO: decide?)
stValue: ???
* skSet
stType: all members
stValue: only members set in value (Only impremented for DbgSymbolValue)
* skArray:
The type of each Index-dimension
The count is the amount of dimensions
NOTE: Values returned by Member/MemberByName are volatile.
They maybe released or changed when Member is called again.
To keep a returned Value a reference can be added (AddReference)
*)
property Member[AIndex: Integer]: TDbgSymbol read GetMember;
property MemberByName[AIndex: String]: TDbgSymbol read GetMemberByName; // Includes inheritance
@ -399,6 +440,24 @@ begin
WriteStr(Result, ADbgSymbolKind);
end;
{ TDbgSymbolValueConstAddress }
function TDbgSymbolValueConstAddress.GetFieldFlags: TDbgSymbolValueFieldFlags;
begin
Result := [svfAddress, svfSizeOfPointer]
end;
function TDbgSymbolValueConstAddress.GetAddress: TDbgPtr;
begin
Result := FAddress;
end;
constructor TDbgSymbolValueConstAddress.Create(AnAddress: TDbgPtr);
begin
inherited Create;
FAddress := AnAddress;
end;
{ TFpDbgCircularRefCountedObject }
procedure TFpDbgCircularRefCountedObject.DoPlainReferenceAdded;
@ -512,6 +571,26 @@ begin
Result := [];
end;
function TDbgSymbolValue.GetIndexType(AIndex: Integer): TDbgSymbol;
begin
Result := nil;;
end;
function TDbgSymbolValue.GetIndexTypeCount: Integer;
begin
Result := 0;
end;
function TDbgSymbolValue.GetMemberEx(AIndex: array of Int64): TDbgSymbolValue;
begin
Result := nil;
end;
function TDbgSymbolValue.GetMemberCountEx(AIndex: array of Int64): Integer;
begin
Result := 0;
end;
function TDbgSymbolValue.GetKind: TDbgSymbolKind;
begin
Result := skNone;

View File

@ -247,7 +247,7 @@ type
// array[1]
protected
procedure Init; override;
//function DoGetResultType: TDbgSymbol; override;
function DoGetResultValue: TDbgSymbolValue; override;
function IsValidAfterPart(APrevPart: TFpPascalExpressionPart): Boolean; override;
function HandleNextPartInBracket(APart: TFpPascalExpressionPart): TFpPascalExpressionPart; override;
function MaybeHandlePrevPart(APrevPart: TFpPascalExpressionPart;
@ -905,39 +905,38 @@ begin
inherited Init;
end;
//function TFpPascalExpressionPartBracketIndex.DoGetResultType: TDbgSymbol;
//var
// tmp: TDbgSymbol;
//begin
// Result := nil;
// if Count <> 2 then exit;
//
// tmp := Items[0].ResultType;
// if tmp = nil then exit;
//
// if (tmp.Kind = skArray) then begin
// // TODO: check type of index
// if tmp.MemberCount < 1 then exit; // TODO error
// if tmp.MemberCount = 1 then begin
// Result := tmp.TypeInfo;
// Result.AddReference{$IFDEF WITH_REFCOUNT_DEBUG}(nil, 'DoGetResultType'){$ENDIF};
// exit;
// end;
//
// Result := TPasParserSymbolArrayDeIndex.Create(tmp);
// end
// else
// if (tmp.Kind = skPointer) then begin
// Result := tmp.TypeInfo;
// Result.AddReference{$IFDEF WITH_REFCOUNT_DEBUG}(nil, 'DoGetResultType'){$ENDIF};
// exit;
// end
// else
// if (tmp.Kind = skString) then begin
// //TODO
// exit;
// end;
//end;
function TFpPascalExpressionPartBracketIndex.DoGetResultValue: TDbgSymbolValue;
var
tmp, tmp2: TDbgSymbolValue;
begin
Result := nil;
if Count <> 2 then exit;
tmp := Items[0].ResultValue;
if tmp = nil then exit;
if (tmp.Kind = skArray) then begin
tmp2 := Items[1].ResultValue;
if not (svfOrdinal in tmp2.FieldFlags) then
exit;
Result := tmp.Member[tmp2.AsCardinal]; // todo negative ?
if Result <> nil then
Result.AddReference{$IFDEF WITH_REFCOUNT_DEBUG}(nil, 'DoGetResultValue'){$ENDIF};
exit;
//Result := TPasParserSymbolArrayDeIndex.Create(tmp);
end
else
if (tmp.Kind = skPointer) then begin
//Result := tmp.TypeInfo;
//Result.AddReference{$IFDEF WITH_REFCOUNT_DEBUG}(nil, 'DoGetResultType'){$ENDIF};
exit;
end
else
if (tmp.Kind = skString) then begin
//TODO
exit;
end;
end;
function TFpPascalExpressionPartBracketIndex.IsValidAfterPart(APrevPart: TFpPascalExpressionPart): Boolean;
begin

View File

@ -87,7 +87,7 @@
<UnitName Value="Unit1"/>
</Unit1>
<Unit2>
<Filename Value="B:\lazarus_latest\debugger\fpgdbmidebugger.pp"/>
<Filename Value="..\..\..\..\debugger\fpgdbmidebugger.pp"/>
<IsPartOfProject Value="True"/>
<UnitName Value="FpGdbmiDebugger"/>
</Unit2>

View File

@ -0,0 +1,23 @@
program DwarfSetupArray;
{$mode objfpc}{$H+}
{$IF FPC_FULLVERSION>=20701}
{$OPTIMIZATION NOREMOVEEMPTYPROCS}
{$OPTIMIZATION NOORDERFIELDS}
{$ENDIF}
{$OPTIMIZATION OFF}
{$A1}
type
TDynIntArray = Array of integer;
TStatIntArray1 = Array [0..10] of integer;
TStatIntArray2 = Array [5..10] of integer;
var // Globals
VarDynIntArray: TDynIntArray;
VarStatIntArray1: TStatIntArray1;
VarStatIntArray2: TStatIntArray2;
begin
VarStatIntArray1[1]:=0;
end.

View File

@ -0,0 +1,267 @@
unit TestDwarfSetupArray;
{$mode objfpc}{$H+}
{$IF FPC_FULLVERSION>=20701}
{$OPTIMIZATION NOREMOVEEMPTYPROCS}
{$OPTIMIZATION NOORDERFIELDS}
{$ENDIF}
{$OPTIMIZATION OFF}
{$A1}
(*
Data generated from testdata\dwarfsetupbasic.lpr
*)
interface
uses
FpDbgDwarfConst,
TestHelperClasses;
const
TTestSetupArrayProcMainAddr = $00400000;
type
{%region Types defined in the DWARF }
TDynIntArray = Array of integer;
TStatIntArray1 = Array [0..10] of integer;
TStatIntArray2 = Array [5..10] of integer;
{%endregion Types defined in the DWARF }
type
{ TTestDwarfSetupBasic }
{ TTestLoaderSetupArray }
TTestLoaderSetupArray = class(TTestDummyImageLoader)
public
constructor Create; override;
procedure PoissonTestFrame;
public
SectionDbgInfo: TTestDummySectionInfoEntries;
Unitdwarfsetuparray_lpr_0, VarVARDYNINTARRAY_1, VarVARSTATINTARRAY1_2, VarVARSTATINTARRAY2_3, Progmain_4, ProgPDWARFSETUPARRAY_init_implicit_5, ProgPDWARFSETUPARRAY_finalize_implicit_6, TypeDeclTDYNINTARRAY_7, TypePtr_8, TypeTDYNINTARRAY_9, Type_10, Type_11, TypeDeclTSTATINTARRAY1_12, TypeTSTATINTARRAY1_13, Type_14, Type_15, TypeDeclTSTATINTARRAY2_16, TypeTSTATINTARRAY2_17, Type_18, Type_19, TypeDeclLONGINT_20, TypeLONGINT_21, Type_22, TypeDeclSHORTINT_23, TypeSHORTINT_24, Type_25
: TTestDwarfInfoEntry;
// global vars
GlobalVar: record
PAD_Before: QWord; // padding will be filled with bad data
VarDynIntArray: TDynIntArray;
VarStatIntArray1: TStatIntArray1;
VarStatIntArray2: TStatIntArray2;
PAD_After: QWord;
end;
end;
implementation
{ TTestLoaderSetupArray }
constructor TTestLoaderSetupArray.Create;
begin
inherited Create;
PoissonTestFrame;
SectionDbgInfo := TestImgReader.TestSection['.debug_info'] as TTestDummySectionInfoEntries;
Unitdwarfsetuparray_lpr_0 := SectionDbgInfo.GetFirstInfoEntryObj;
// Generated with fpc 2.6.2 32 bit win
Unitdwarfsetuparray_lpr_0.Tag := DW_TAG_compile_unit;
Unitdwarfsetuparray_lpr_0.Children := 1;
Unitdwarfsetuparray_lpr_0.Add(DW_AT_name, DW_FORM_string, 'dwarfsetuparray.lpr'+#0);
Unitdwarfsetuparray_lpr_0.Add(DW_AT_producer, DW_FORM_string, 'Free Pascal 2.6.2 2013/02/16'+#0);
Unitdwarfsetuparray_lpr_0.Add(DW_AT_comp_dir, DW_FORM_string, 'B:/lazarus_latest/components/fpdebug/test/testdata/'+#0);
Unitdwarfsetuparray_lpr_0.Add(DW_AT_language, DW_FORM_data1, [$09]);
Unitdwarfsetuparray_lpr_0.Add(DW_AT_identifier_case, DW_FORM_data1, [$03]);
Unitdwarfsetuparray_lpr_0.Add(DW_AT_stmt_list, DW_FORM_data4, [$00, $00, $00, $00]);
Unitdwarfsetuparray_lpr_0.AddAddr(DW_AT_low_pc, DW_FORM_addr, $00400000);
Unitdwarfsetuparray_lpr_0.AddAddr(DW_AT_high_pc, DW_FORM_addr, $004FFFFF);
VarVARDYNINTARRAY_1 := Unitdwarfsetuparray_lpr_0.GetNewChild;
VarVARDYNINTARRAY_1.Tag := DW_TAG_variable;
VarVARDYNINTARRAY_1.Children := 0;
VarVARDYNINTARRAY_1.Add(DW_AT_name, DW_FORM_string, 'VARDYNINTARRAY'+#0);
VarVARDYNINTARRAY_1.Add(DW_AT_location, DW_FORM_block1, BytesLen1([DW_OP_addr, AddrB(@GlobalVar.VarDYNINTARRAY)])); // $03, $00, $00, $00, $00
VarVARDYNINTARRAY_1.AddRef(DW_AT_type, DW_FORM_ref4, @TypeDeclTDYNINTARRAY_7); // $41, $01, $00, $00
VarVARSTATINTARRAY1_2 := Unitdwarfsetuparray_lpr_0.GetNewChild;
VarVARSTATINTARRAY1_2.Tag := DW_TAG_variable;
VarVARSTATINTARRAY1_2.Children := 0;
VarVARSTATINTARRAY1_2.Add(DW_AT_name, DW_FORM_string, 'VARSTATINTARRAY1'+#0);
VarVARSTATINTARRAY1_2.Add(DW_AT_location, DW_FORM_block1, BytesLen1([DW_OP_addr, AddrB(@GlobalVar.VarSTATINTARRAY1)])); // $03, $00, $90, $40, $00
VarVARSTATINTARRAY1_2.AddRef(DW_AT_type, DW_FORM_ref4, @TypeDeclTSTATINTARRAY1_12); // $77, $01, $00, $00
VarVARSTATINTARRAY2_3 := Unitdwarfsetuparray_lpr_0.GetNewChild;
VarVARSTATINTARRAY2_3.Tag := DW_TAG_variable;
VarVARSTATINTARRAY2_3.Children := 0;
VarVARSTATINTARRAY2_3.Add(DW_AT_name, DW_FORM_string, 'VARSTATINTARRAY2'+#0);
VarVARSTATINTARRAY2_3.Add(DW_AT_location, DW_FORM_block1, BytesLen1([DW_OP_addr, AddrB(@GlobalVar.VarSTATINTARRAY2)])); // $03, $00, $00, $00, $00
VarVARSTATINTARRAY2_3.AddRef(DW_AT_type, DW_FORM_ref4, @TypeDeclTSTATINTARRAY2_16); // $AE, $01, $00, $00
Progmain_4 := Unitdwarfsetuparray_lpr_0.GetNewChild;
Progmain_4.Tag := DW_TAG_subprogram;
Progmain_4.Children := 0;
Progmain_4.Add(DW_AT_name, DW_FORM_string, 'main'+#0);
Progmain_4.Add(DW_AT_prototyped, DW_FORM_flag, [$01]);
Progmain_4.Add(DW_AT_calling_convention, DW_FORM_data1, [$41]);
Progmain_4.Add(DW_AT_external, DW_FORM_flag, [$01]);
Progmain_4.AddAddr(DW_AT_low_pc, DW_FORM_addr, $00400000);
Progmain_4.AddAddr(DW_AT_high_pc, DW_FORM_addr, $00400FFF);
ProgPDWARFSETUPARRAY_init_implicit_5 := Unitdwarfsetuparray_lpr_0.GetNewChild;
ProgPDWARFSETUPARRAY_init_implicit_5.Tag := DW_TAG_subprogram;
ProgPDWARFSETUPARRAY_init_implicit_5.Children := 0;
ProgPDWARFSETUPARRAY_init_implicit_5.Add(DW_AT_name, DW_FORM_string, 'P$DWARFSETUPARRAY_init_implicit'+#0);
ProgPDWARFSETUPARRAY_init_implicit_5.Add(DW_AT_prototyped, DW_FORM_flag, [$01]);
ProgPDWARFSETUPARRAY_init_implicit_5.Add(DW_AT_calling_convention, DW_FORM_data1, [$41]);
ProgPDWARFSETUPARRAY_init_implicit_5.Add(DW_AT_external, DW_FORM_flag, [$01]);
ProgPDWARFSETUPARRAY_init_implicit_5.AddAddr(DW_AT_low_pc, DW_FORM_addr, $00401000);
ProgPDWARFSETUPARRAY_init_implicit_5.AddAddr(DW_AT_high_pc, DW_FORM_addr, $00401FFF);
ProgPDWARFSETUPARRAY_finalize_implicit_6 := Unitdwarfsetuparray_lpr_0.GetNewChild;
ProgPDWARFSETUPARRAY_finalize_implicit_6.Tag := DW_TAG_subprogram;
ProgPDWARFSETUPARRAY_finalize_implicit_6.Children := 0;
ProgPDWARFSETUPARRAY_finalize_implicit_6.Add(DW_AT_name, DW_FORM_string, 'P$DWARFSETUPARRAY_finalize_implicit'+#0);
ProgPDWARFSETUPARRAY_finalize_implicit_6.Add(DW_AT_prototyped, DW_FORM_flag, [$01]);
ProgPDWARFSETUPARRAY_finalize_implicit_6.Add(DW_AT_calling_convention, DW_FORM_data1, [$41]);
ProgPDWARFSETUPARRAY_finalize_implicit_6.Add(DW_AT_external, DW_FORM_flag, [$01]);
ProgPDWARFSETUPARRAY_finalize_implicit_6.AddAddr(DW_AT_low_pc, DW_FORM_addr, $00402000);
ProgPDWARFSETUPARRAY_finalize_implicit_6.AddAddr(DW_AT_high_pc, DW_FORM_addr, $00402FFF);
TypeDeclTDYNINTARRAY_7 := Unitdwarfsetuparray_lpr_0.GetNewChild;
TypeDeclTDYNINTARRAY_7.Tag := DW_TAG_typedef;
TypeDeclTDYNINTARRAY_7.Children := 0;
TypeDeclTDYNINTARRAY_7.Add(DW_AT_name, DW_FORM_string, 'TDYNINTARRAY'+#0);
TypeDeclTDYNINTARRAY_7.AddRef(DW_AT_type, DW_FORM_ref4, @TypePtr_8); // $53, $01, $00, $00
TypePtr_8 := Unitdwarfsetuparray_lpr_0.GetNewChild;
TypePtr_8.Tag := DW_TAG_pointer_type;
TypePtr_8.Children := 0;
TypePtr_8.AddRef(DW_AT_type, DW_FORM_ref4, @TypeTDYNINTARRAY_9); // $58, $01, $00, $00
TypeTDYNINTARRAY_9 := Unitdwarfsetuparray_lpr_0.GetNewChild;
TypeTDYNINTARRAY_9.Tag := DW_TAG_array_type;
TypeTDYNINTARRAY_9.Children := 1;
TypeTDYNINTARRAY_9.Add(DW_AT_name, DW_FORM_string, 'TDYNINTARRAY'+#0);
TypeTDYNINTARRAY_9.AddRef(DW_AT_type, DW_FORM_ref4, @TypeDeclLONGINT_20); // $E5, $01, $00, $00
Type_10 := TypeTDYNINTARRAY_9.GetNewChild;
Type_10.Tag := DW_TAG_subrange_type;
Type_10.Children := 0;
Type_10.AddSLEB(DW_AT_lower_bound, DW_FORM_sdata, 0);
Type_10.AddULEB(DW_AT_byte_stride, DW_FORM_udata, 4);
Type_10.AddRef(DW_AT_type, DW_FORM_ref4, @TypeDeclLONGINT_20); // $E5, $01, $00, $00
Type_11 := Unitdwarfsetuparray_lpr_0.GetNewChild;
Type_11.Tag := DW_TAG_reference_type;
Type_11.Children := 0;
Type_11.AddRef(DW_AT_type, DW_FORM_ref4, @TypeDeclTDYNINTARRAY_7); // $41, $01, $00, $00
TypeDeclTSTATINTARRAY1_12 := Unitdwarfsetuparray_lpr_0.GetNewChild;
TypeDeclTSTATINTARRAY1_12.Tag := DW_TAG_typedef;
TypeDeclTSTATINTARRAY1_12.Children := 0;
TypeDeclTSTATINTARRAY1_12.Add(DW_AT_name, DW_FORM_string, 'TSTATINTARRAY1'+#0);
TypeDeclTSTATINTARRAY1_12.AddRef(DW_AT_type, DW_FORM_ref4, @TypeTSTATINTARRAY1_13); // $8B, $01, $00, $00
TypeTSTATINTARRAY1_13 := Unitdwarfsetuparray_lpr_0.GetNewChild;
TypeTSTATINTARRAY1_13.Tag := DW_TAG_array_type;
TypeTSTATINTARRAY1_13.Children := 1;
TypeTSTATINTARRAY1_13.Add(DW_AT_name, DW_FORM_string, 'TSTATINTARRAY1'+#0);
TypeTSTATINTARRAY1_13.AddULEB(DW_AT_byte_size, DW_FORM_udata, 44);
TypeTSTATINTARRAY1_13.AddRef(DW_AT_type, DW_FORM_ref4, @TypeDeclLONGINT_20); // $E5, $01, $00, $00
Type_14 := TypeTSTATINTARRAY1_13.GetNewChild;
Type_14.Tag := DW_TAG_subrange_type;
Type_14.Children := 0;
Type_14.AddSLEB(DW_AT_lower_bound, DW_FORM_sdata, 0);
Type_14.AddSLEB(DW_AT_upper_bound, DW_FORM_sdata, 10);
Type_14.AddULEB(DW_AT_byte_stride, DW_FORM_udata, 4);
Type_14.AddRef(DW_AT_type, DW_FORM_ref4, @TypeDeclSHORTINT_23); // $02, $02, $00, $00
Type_15 := Unitdwarfsetuparray_lpr_0.GetNewChild;
Type_15.Tag := DW_TAG_reference_type;
Type_15.Children := 0;
Type_15.AddRef(DW_AT_type, DW_FORM_ref4, @TypeDeclTSTATINTARRAY1_12); // $77, $01, $00, $00
TypeDeclTSTATINTARRAY2_16 := Unitdwarfsetuparray_lpr_0.GetNewChild;
TypeDeclTSTATINTARRAY2_16.Tag := DW_TAG_typedef;
TypeDeclTSTATINTARRAY2_16.Children := 0;
TypeDeclTSTATINTARRAY2_16.Add(DW_AT_name, DW_FORM_string, 'TSTATINTARRAY2'+#0);
TypeDeclTSTATINTARRAY2_16.AddRef(DW_AT_type, DW_FORM_ref4, @TypeTSTATINTARRAY2_17); // $C2, $01, $00, $00
TypeTSTATINTARRAY2_17 := Unitdwarfsetuparray_lpr_0.GetNewChild;
TypeTSTATINTARRAY2_17.Tag := DW_TAG_array_type;
TypeTSTATINTARRAY2_17.Children := 1;
TypeTSTATINTARRAY2_17.Add(DW_AT_name, DW_FORM_string, 'TSTATINTARRAY2'+#0);
TypeTSTATINTARRAY2_17.AddULEB(DW_AT_byte_size, DW_FORM_udata, 24);
TypeTSTATINTARRAY2_17.AddRef(DW_AT_type, DW_FORM_ref4, @TypeDeclLONGINT_20); // $E5, $01, $00, $00
Type_18 := TypeTSTATINTARRAY2_17.GetNewChild;
Type_18.Tag := DW_TAG_subrange_type;
Type_18.Children := 0;
Type_18.AddSLEB(DW_AT_lower_bound, DW_FORM_sdata, 5);
Type_18.AddSLEB(DW_AT_upper_bound, DW_FORM_sdata, 10);
Type_18.AddULEB(DW_AT_byte_stride, DW_FORM_udata, 4);
Type_18.AddRef(DW_AT_type, DW_FORM_ref4, @TypeDeclSHORTINT_23); // $02, $02, $00, $00
Type_19 := Unitdwarfsetuparray_lpr_0.GetNewChild;
Type_19.Tag := DW_TAG_reference_type;
Type_19.Children := 0;
Type_19.AddRef(DW_AT_type, DW_FORM_ref4, @TypeDeclTSTATINTARRAY2_16); // $AE, $01, $00, $00
TypeDeclLONGINT_20 := Unitdwarfsetuparray_lpr_0.GetNewChild;
TypeDeclLONGINT_20.Tag := DW_TAG_typedef;
TypeDeclLONGINT_20.Children := 0;
TypeDeclLONGINT_20.Add(DW_AT_name, DW_FORM_string, 'LONGINT'+#0);
TypeDeclLONGINT_20.AddRef(DW_AT_type, DW_FORM_ref4, @TypeLONGINT_21); // $F2, $01, $00, $00
TypeLONGINT_21 := Unitdwarfsetuparray_lpr_0.GetNewChild;
TypeLONGINT_21.Tag := DW_TAG_base_type;
TypeLONGINT_21.Children := 0;
TypeLONGINT_21.Add(DW_AT_name, DW_FORM_string, 'LONGINT'+#0);
TypeLONGINT_21.Add(DW_AT_encoding, DW_FORM_data1, [$05]);
TypeLONGINT_21.Add(DW_AT_byte_size, DW_FORM_data1, [$04]);
Type_22 := Unitdwarfsetuparray_lpr_0.GetNewChild;
Type_22.Tag := DW_TAG_reference_type;
Type_22.Children := 0;
Type_22.AddRef(DW_AT_type, DW_FORM_ref4, @TypeDeclLONGINT_20); // $E5, $01, $00, $00
TypeDeclSHORTINT_23 := Unitdwarfsetuparray_lpr_0.GetNewChild;
TypeDeclSHORTINT_23.Tag := DW_TAG_typedef;
TypeDeclSHORTINT_23.Children := 0;
TypeDeclSHORTINT_23.Add(DW_AT_name, DW_FORM_string, 'SHORTINT'+#0);
TypeDeclSHORTINT_23.AddRef(DW_AT_type, DW_FORM_ref4, @TypeSHORTINT_24); // $10, $02, $00, $00
TypeSHORTINT_24 := Unitdwarfsetuparray_lpr_0.GetNewChild;
TypeSHORTINT_24.Tag := DW_TAG_base_type;
TypeSHORTINT_24.Children := 0;
TypeSHORTINT_24.Add(DW_AT_name, DW_FORM_string, 'SHORTINT'+#0);
TypeSHORTINT_24.Add(DW_AT_encoding, DW_FORM_data1, [$05]);
TypeSHORTINT_24.Add(DW_AT_byte_size, DW_FORM_data1, [$01]);
Type_25 := Unitdwarfsetuparray_lpr_0.GetNewChild;
Type_25.Tag := DW_TAG_reference_type;
Type_25.Children := 0;
Type_25.AddRef(DW_AT_type, DW_FORM_ref4, @TypeDeclSHORTINT_23); // $02, $02, $00, $00
//
SectionDbgInfo.CreateSectionData;
SectionDbgInfo.AbbrevSection.CreateSectionData;
end;
procedure TTestLoaderSetupArray.PoissonTestFrame;
begin
// do not poison managed types
// Ensure any out of bound reads get bad data
// FillByte(GlobalVar, SizeOf(GlobalVar), $D5);
end;
end.

View File

@ -6,7 +6,7 @@ interface
uses
FpPascalParser, FpDbgDwarf, FpDbgInfo, LazLoggerBase, LazUTF8, sysutils, fpcunit,
testregistry, TestHelperClasses, TestDwarfSetup1, TestDwarfSetupBasic;
testregistry, TestHelperClasses, TestDwarfSetup1, TestDwarfSetupBasic, TestDwarfSetupArray;
type
@ -58,6 +58,7 @@ type
Procedure TestExpressionInt;
Procedure TestExpressionBool;
Procedure TestExpressionEnumAndSet;
Procedure TestExpressionArray;
Procedure TestExpressionStructures;
end;
@ -441,6 +442,38 @@ begin
end;
procedure TTestTypeInfo.TestExpressionArray;
var
sym: TDbgSymbol;
ImgLoader: TTestLoaderSetupArray;
TmpResVal: TDbgSymbolValue;
i: Integer;
s: String;
begin
InitDwarf(TTestLoaderSetupArray);
ImgLoader := TTestLoaderSetupArray(FImageLoader);
//FMemReader.RegisterValues[5] := TDbgPtr(@ImgLoader.TestStackFrame.EndPoint);
FCurrentContext := FDwarfInfo.FindContext(TTestSetupArrayProcMainAddr);
AssertTrue('got ctx', FCurrentContext <> nil);
sym := FCurrentContext.FindSymbol('VarDynIntArray');
AssertTrue('got sym', sym <> nil);
sym.ReleaseReference();
StartTest('VarDynIntArray', skArray, [ttHasType]);
StartTest('VarStatIntArray1', skArray, [ttHasType]);
StartInvalTest('VarDynIntArray[0]', 'xxx');
SetLength(ImgLoader.GlobalVar.VarDynIntArray,33);
StartTest('VarDynIntArray[0]', skInteger, [ttHasType]);
StartTest('VarDynIntArray[1]', skInteger, [ttHasType]);
StartTest('VarStatIntArray1[0]', skInteger, [ttHasType]);
end;
procedure TTestTypeInfo.TestExpressionStructures;
var
sym: TDbgSymbol;
@ -1250,7 +1283,6 @@ begin
end;
initialization
RegisterTest(TTestTypeInfo);