lazarus/components/fpdebug/fpdbgdwarffreepascal.pas
Sergey Larin 20fc451aa1 FpDebug takes into account that FPC 3.3.1 changed offset of the CodePage field in TAnsiRec.
When reading strings, FpDebug sets the required CodePage to the received AnsiString, the value of which is read from the memory of the process being debugged.
2021-08-27 21:24:07 +03:00

1454 lines
45 KiB
ObjectPascal

unit FpDbgDwarfFreePascal;
{$mode objfpc}{$H+}
{$TYPEDADDRESS on}
interface
uses
Classes, SysUtils, Types, math,
FpDbgDwarfDataClasses, FpDbgDwarf, FpDbgInfo,
FpDbgUtil, FpDbgDwarfConst, FpErrorMessages, FpdMemoryTools,
DbgIntfBaseTypes,
{$ifdef FORCE_LAZLOGGER_DUMMY} LazLoggerDummy {$else} LazLoggerBase {$endif}, LazStringUtils;
type
{%Region * ***** SymbolClassMap ***** *}
{ TFpDwarfFreePascalSymbolClassMap }
TFpDwarfFreePascalSymbolClassMap = class(TFpDwarfDefaultSymbolClassMap)
strict private
class var ExistingClassMap: TFpSymbolDwarfClassMap;
private
FCompilerVersion: Cardinal;
protected
function CanHandleCompUnit(ACU: TDwarfCompilationUnit; AHelperData: Pointer): Boolean; override;
class function GetExistingClassMap: PFpDwarfSymbolClassMap; override;
public
class function GetInstanceForCompUnit(ACU: TDwarfCompilationUnit): TFpSymbolDwarfClassMap; override;
class function ClassCanHandleCompUnit(ACU: TDwarfCompilationUnit): Boolean; override;
class function GetInstanceForDbgInfo(ADbgInfo: TDbgInfo):TFpDwarfFreePascalSymbolClassMap;
public
constructor Create(ACU: TDwarfCompilationUnit; AHelperData: Pointer); override;
function GetDwarfSymbolClass(ATag: Cardinal): TDbgDwarfSymbolBaseClass; override;
function CreateScopeForSymbol(ALocationContext: TFpDbgLocationContext; ASymbol: TFpSymbol;
ADwarf: TFpDwarfInfo): TFpDbgSymbolScope; override;
//class function CreateProcSymbol(ACompilationUnit: TDwarfCompilationUnit;
// AInfo: PDwarfAddressInfo; AAddress: TDbgPtr): TDbgDwarfSymbolBase; override;
function GetInstanceClassNameFromPVmt(APVmt: TDbgPtr;
AContext: TFpDbgLocationContext; ASizeOfAddr: Integer;
out AClassName: String; out AnError: TFpError): boolean;
end;
{ TFpDwarfFreePascalSymbolClassMapDwarf2 }
TFpDwarfFreePascalSymbolClassMapDwarf2 = class(TFpDwarfFreePascalSymbolClassMap)
strict private
class var ExistingClassMap: TFpSymbolDwarfClassMap;
protected
class function GetExistingClassMap: PFpDwarfSymbolClassMap; override;
public
class function ClassCanHandleCompUnit(ACU: TDwarfCompilationUnit): Boolean; override;
public
function GetDwarfSymbolClass(ATag: Cardinal): TDbgDwarfSymbolBaseClass; override;
//class function CreateSymbolScope(AThreadId, AStackFrame: Integer; AnAddress: TDBGPtr; ASymbol: TFpSymbol;
// ADwarf: TFpDwarfInfo): TFpDbgSymbolScope; override;
//class function CreateProcSymbol(ACompilationUnit: TDwarfCompilationUnit;
// AInfo: PDwarfAddressInfo; AAddress: TDbgPtr): TDbgDwarfSymbolBase; override;
end;
{ TFpDwarfFreePascalSymbolClassMapDwarf3 }
TFpDwarfFreePascalSymbolClassMapDwarf3 = class(TFpDwarfFreePascalSymbolClassMap)
strict private
class var ExistingClassMap: TFpSymbolDwarfClassMap;
protected
class function GetExistingClassMap: PFpDwarfSymbolClassMap; override;
public
class function ClassCanHandleCompUnit(ACU: TDwarfCompilationUnit): Boolean; override;
public
function GetDwarfSymbolClass(ATag: Cardinal): TDbgDwarfSymbolBaseClass; override;
//class function CreateSymbolScope(AThreadId, AStackFrame: Integer; AnAddress: TDBGPtr; ASymbol: TFpSymbol;
// ADwarf: TFpDwarfInfo): TFpDbgSymbolScope; override;
//class function CreateProcSymbol(ACompilationUnit: TDwarfCompilationUnit;
// AInfo: PDwarfAddressInfo; AAddress: TDbgPtr): TDbgDwarfSymbolBase; override;
end;
{%EndRegion }
{%Region * ***** Context ***** *}
{ TFpDwarfFreePascalSymbolScope }
TFpDwarfFreePascalSymbolScope = class(TFpDwarfInfoSymbolScope)
private
FOuterNestContext: TFpDbgSymbolScope;
FOuterNotFound: Boolean;
protected
function FindLocalSymbol(const AName: String; const ANameInfo: TNameSearchInfo;
InfoEntry: TDwarfInformationEntry; out ADbgValue: TFpValue): Boolean; override;
public
destructor Destroy; override;
end;
{%EndRegion }
{%Region * ***** Value & Types ***** *}
(* *** Class vs ^Record vs ^Object *** *)
{ TFpSymbolDwarfFreePascalTypeDeclaration }
TFpSymbolDwarfFreePascalTypeDeclaration = class(TFpSymbolDwarfTypeDeclaration)
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: TFpSymbolDwarfType; override;
end;
{ TFpSymbolDwarfFreePascalTypePointer }
TFpSymbolDwarfFreePascalTypePointer = class(TFpSymbolDwarfTypePointer)
private
FIsInternalPointer: Boolean;
function GetIsInternalPointer: Boolean; inline;
function IsInternalDynArrayPointer: Boolean; inline;
protected
procedure TypeInfoNeeded; override;
procedure KindNeeded; override;
function DoReadStride(AValueObj: TFpValueDwarf; out AStride: TFpDbgValueSize): Boolean; override;
procedure ForwardToSymbolNeeded; override;
function GetNextTypeInfoForDataAddress(ATargetType: TFpSymbolDwarfType): TFpSymbolDwarfType; override;
function GetDataAddressNext(AValueObj: TFpValueDwarf; var AnAddress: TFpDbgMemLocation;
out ADoneWork: Boolean; ATargetType: TFpSymbolDwarfType): Boolean; override;
function DoReadDataSize(const AValueObj: TFpValue; out ADataSize: TFpDbgValueSize): Boolean; override;
public
function GetTypedValueObject(ATypeCast: Boolean; AnOuterType: TFpSymbolDwarfType = nil): TFpValueDwarf; override;
property IsInternalPointer: Boolean read GetIsInternalPointer write FIsInternalPointer; // Class (also DynArray, but DynArray is handled without this)
end;
{ TFpSymbolDwarfFreePascalTypeStructure }
TFpSymbolDwarfFreePascalTypeStructure = class(TFpSymbolDwarfTypeStructure)
protected
procedure KindNeeded; override;
//function GetInstanceClass(AValueObj: TFpValueDwarf): TFpSymbolDwarf; override;
class function GetInstanceClassNameFromPVmt(APVmt: TDbgPtr;
AContext: TFpDbgLocationContext; ASizeOfAddr: Integer;
out AClassName: String; out AnError: TFpError): boolean;
public
function GetInstanceClassName(AValueObj: TFpValue; out
AClassName: String): boolean; override;
end;
(* *** Record vs ShortString *** *)
{ TFpSymbolDwarfV2FreePascalTypeStructure }
TFpSymbolDwarfV2FreePascalTypeStructure = class(TFpSymbolDwarfFreePascalTypeStructure)
private
FIsShortString: (issUnknown, issShortString, issStructure);
function IsShortString: Boolean;
protected
procedure KindNeeded; override;
function GetNestedSymbolCount: Integer; override;
//function GetNestedSymbolByName(AIndex: String): TFpSymbol; override;
public
function GetTypedValueObject(ATypeCast: Boolean; AnOuterType: TFpSymbolDwarfType = nil): TFpValueDwarf; override;
end;
{ TFpValueDwarfV2FreePascalShortString }
TFpValueDwarfV2FreePascalShortString = class(TFpValueDwarf)
protected
function IsValidTypeCast: Boolean; override;
function GetInternMemberByName(const AIndex: String): TFpValue;
procedure Reset; override;
private
FValue: String;
FValueDone: Boolean;
protected
function GetFieldFlags: TFpValueFieldFlags; override;
function GetAsString: AnsiString; override;
function GetAsWideString: WideString; override;
end;
(* *** "Open Array" in params *** *)
{ TFpSymbolDwarfFreePascalSymbolTypeArray }
TFpSymbolDwarfFreePascalSymbolTypeArray = class(TFpSymbolDwarfTypeArray)
public
function GetTypedValueObject(ATypeCast: Boolean; AnOuterType: TFpSymbolDwarfType = nil): TFpValueDwarf; override;
end;
{ TFpValueDwarfFreePascalArray }
TFpValueDwarfFreePascalArray = class(TFpValueDwarfArray)
protected
function GetKind: TDbgSymbolKind; override;
function GetMemberCount: Integer; override;
function DoGetStride(out AStride: TFpDbgValueSize): Boolean; override;
function DoGetMainStride(out AStride: TFpDbgValueSize): Boolean; override;
function DoGetDimStride(AnIndex: integer; out AStride: TFpDbgValueSize): Boolean; override;
end;
(* *** Array vs AnsiString *** *)
{ TFpSymbolDwarfV3FreePascalSymbolTypeArray }
TFpSymbolDwarfV3FreePascalSymbolTypeArray = class(TFpSymbolDwarfFreePascalSymbolTypeArray)
private type
TArrayOrStringType = (iasUnknown, iasArray, iasShortString, iasAnsiString, iasUnicodeString);
private
FArrayOrStringType: TArrayOrStringType;
function GetInternalStringType: TArrayOrStringType;
protected
procedure KindNeeded; override;
function DoReadSize(const AValueObj: TFpValue; out ASize: TFpDbgValueSize): Boolean; override;
public
function GetTypedValueObject(ATypeCast: Boolean; AnOuterType: TFpSymbolDwarfType = nil): TFpValueDwarf; override;
end;
{ TFpValueDwarfV3FreePascalString }
TFpValueDwarfV3FreePascalString = class(TFpValueDwarf) // short & ansi...
private
FValue: String;
FValueDone: Boolean;
function GetDynamicCodePage(Addr: TFpDbgMemLocation; out Codepage: TSystemCodePage): Boolean;
protected
function IsValidTypeCast: Boolean; override;
procedure Reset; override;
function GetFieldFlags: TFpValueFieldFlags; override;
function GetAsString: AnsiString; override;
function GetAsWideString: WideString; override;
end;
{%EndRegion }
implementation
uses
FpDbgCommon;
var
FPDBG_DWARF_VERBOSE: PLazLoggerLogGroup;
{ TFpDwarfFreePascalSymbolClassMap }
function TFpDwarfFreePascalSymbolClassMap.CanHandleCompUnit(
ACU: TDwarfCompilationUnit; AHelperData: Pointer): Boolean;
begin
Result := (FCompilerVersion = PtrUInt(AHelperData)) and
inherited CanHandleCompUnit(ACU, AHelperData);
end;
class function TFpDwarfFreePascalSymbolClassMap.GetExistingClassMap: PFpDwarfSymbolClassMap;
begin
Result := @ExistingClassMap;
end;
class function TFpDwarfFreePascalSymbolClassMap.GetInstanceForCompUnit(
ACU: TDwarfCompilationUnit): TFpSymbolDwarfClassMap;
var
s: String;
i, j, AVersion: Integer;
begin
AVersion := 0;
s := ACU.Producer+' ';
i := PosI('free pascal', s) + 11;
if i > 11 then begin
while (i < Length(s)) and (s[i] in [' ', #9]) do
inc(i);
delete(s, 1, i - 1);
i := pos('.', s);
if (i > 1) then begin
j := StrToIntDef(copy(s, 1, i - 1), 0);
if (j >= 0) then
AVersion := j * $10000;
delete(s, 1, i);
end;
if (AVersion > 0) then begin
i := pos('.', s);
if (i > 1) then begin
j := StrToIntDef(copy(s, 1, i - 1), 0);
if (j >= 0) and (j < 99) then
AVersion := AVersion + j * $100
else
AVersion := 0;
delete(s, 1, i);
end;
end;
if (AVersion > 0) then begin
i := pos(' ', s);
if (i > 1) then begin
j := StrToIntDef(copy(s, 1, i - 1), 0);
if (j >= 0) and (j < 99) then
AVersion := AVersion + j
else
AVersion := 0;
end;
end;
end;
Result := DoGetInstanceForCompUnit(ACU, Pointer(PtrUInt(AVersion)));
end;
class function TFpDwarfFreePascalSymbolClassMap.ClassCanHandleCompUnit(ACU: TDwarfCompilationUnit): Boolean;
begin
Result := PosI('free pascal', ACU.Producer) > 0;
end;
var
LastInfo: TDbgInfo = nil;
FoundMap: TFpDwarfFreePascalSymbolClassMap = nil;
class function TFpDwarfFreePascalSymbolClassMap.GetInstanceForDbgInfo(
ADbgInfo: TDbgInfo): TFpDwarfFreePascalSymbolClassMap;
var
i: Integer;
begin
if ADbgInfo <> LastInfo then begin
FoundMap := nil;
LastInfo := nil;
end;
Result := FoundMap;
if LastInfo <> nil then
exit;
if not (ADbgInfo is TFpDwarfInfo) then
exit;
for i := 0 to TFpDwarfInfo(ADbgInfo).CompilationUnitsCount - 1 do
if TFpDwarfInfo(ADbgInfo).CompilationUnits[i].DwarfSymbolClassMap is TFpDwarfFreePascalSymbolClassMap
then begin
FoundMap := TFpDwarfFreePascalSymbolClassMap(TFpDwarfInfo(ADbgInfo).CompilationUnits[i].DwarfSymbolClassMap);
end;
Result := FoundMap;
LastInfo := ADbgInfo;
end;
constructor TFpDwarfFreePascalSymbolClassMap.Create(ACU: TDwarfCompilationUnit;
AHelperData: Pointer);
begin
FCompilerVersion := PtrUInt(AHelperData);
inherited Create(ACU, AHelperData);
end;
function TFpDwarfFreePascalSymbolClassMap.GetDwarfSymbolClass(
ATag: Cardinal): TDbgDwarfSymbolBaseClass;
begin
case ATag of
DW_TAG_typedef: Result := TFpSymbolDwarfFreePascalTypeDeclaration;
DW_TAG_pointer_type: Result := TFpSymbolDwarfFreePascalTypePointer;
DW_TAG_structure_type,
DW_TAG_class_type: Result := TFpSymbolDwarfFreePascalTypeStructure;
DW_TAG_array_type: Result := TFpSymbolDwarfFreePascalSymbolTypeArray;
else Result := inherited GetDwarfSymbolClass(ATag);
end;
end;
function TFpDwarfFreePascalSymbolClassMap.CreateScopeForSymbol(
ALocationContext: TFpDbgLocationContext; ASymbol: TFpSymbol;
ADwarf: TFpDwarfInfo): TFpDbgSymbolScope;
begin
Result := TFpDwarfFreePascalSymbolScope.Create(ALocationContext, ASymbol, ADwarf);
end;
function TFpDwarfFreePascalSymbolClassMap.GetInstanceClassNameFromPVmt(
APVmt: TDbgPtr; AContext: TFpDbgLocationContext; ASizeOfAddr: Integer; out
AClassName: String; out AnError: TFpError): boolean;
begin
Result := TFpSymbolDwarfFreePascalTypeStructure.GetInstanceClassNameFromPVmt(APVmt,
AContext, ASizeOfAddr, AClassName, AnError);
end;
{ TFpDwarfFreePascalSymbolClassMapDwarf2 }
class function TFpDwarfFreePascalSymbolClassMapDwarf2.GetExistingClassMap: PFpDwarfSymbolClassMap;
begin
Result := @ExistingClassMap;
end;
class function TFpDwarfFreePascalSymbolClassMapDwarf2.ClassCanHandleCompUnit(
ACU: TDwarfCompilationUnit): Boolean;
begin
Result := inherited ClassCanHandleCompUnit(ACU);
Result := Result and (ACU.Version < 3);
end;
function TFpDwarfFreePascalSymbolClassMapDwarf2.GetDwarfSymbolClass(
ATag: Cardinal): TDbgDwarfSymbolBaseClass;
begin
case ATag of
DW_TAG_structure_type:
Result := TFpSymbolDwarfV2FreePascalTypeStructure; // maybe record
// // TODO:
// //DW_TAG_reference_type: Result := TFpSymbolDwarfTypeRef;
// //DW_TAG_typedef: Result := TFpSymbolDwarfTypeDeclaration;
// //DW_TAG_pointer_type: Result := TFpSymbolDwarfTypePointer;
// //
// //DW_TAG_base_type: Result := TFpSymbolDwarfTypeBasic;
// //DW_TAG_subrange_type: Result := TFpSymbolDwarfTypeSubRange;
// //DW_TAG_enumeration_type: Result := TFpSymbolDwarfTypeEnum;
// //DW_TAG_enumerator: Result := TFpSymbolDwarfDataEnumMember;
// //DW_TAG_array_type: Result := TFpSymbolDwarfTypeArray;
// ////
// //DW_TAG_compile_unit: Result := TFpSymbolDwarfUnit;
//
else
Result := inherited GetDwarfSymbolClass(ATag);
end;
end;
{ TFpDwarfFreePascalSymbolClassMapDwarf3 }
class function TFpDwarfFreePascalSymbolClassMapDwarf3.GetExistingClassMap: PFpDwarfSymbolClassMap;
begin
Result := @ExistingClassMap;
end;
class function TFpDwarfFreePascalSymbolClassMapDwarf3.ClassCanHandleCompUnit(
ACU: TDwarfCompilationUnit): Boolean;
begin
Result := inherited ClassCanHandleCompUnit(ACU);
Result := Result and (ACU.Version >= 3);
end;
function TFpDwarfFreePascalSymbolClassMapDwarf3.GetDwarfSymbolClass(
ATag: Cardinal): TDbgDwarfSymbolBaseClass;
begin
case ATag of
DW_TAG_array_type:
Result := TFpSymbolDwarfV3FreePascalSymbolTypeArray;
// DW_TAG_structure_type:
// Result := TFpSymbolDwarfV2FreePascalTypeStructure; // maybe record
// // TODO:
// //DW_TAG_reference_type: Result := TFpSymbolDwarfTypeRef;
// //DW_TAG_typedef: Result := TFpSymbolDwarfTypeDeclaration;
// //DW_TAG_pointer_type: Result := TFpSymbolDwarfTypePointer;
// //
// //DW_TAG_base_type: Result := TFpSymbolDwarfTypeBasic;
// //DW_TAG_subrange_type: Result := TFpSymbolDwarfTypeSubRange;
// //DW_TAG_enumeration_type: Result := TFpSymbolDwarfTypeEnum;
// //DW_TAG_enumerator: Result := TFpSymbolDwarfDataEnumMember;
// //DW_TAG_array_type: Result := TFpSymbolDwarfTypeArray;
// ////
// //DW_TAG_compile_unit: Result := TFpSymbolDwarfUnit;
//
else
Result := inherited GetDwarfSymbolClass(ATag);
end;
end;
type
{ TFpDbgDwarfSimpleLocationContext }
TFpDbgDwarfSimpleLocationContext = class(TFpDbgSimpleLocationContext)
protected
FStackFrame: Integer;
function GetStackFrame: Integer; override;
public
constructor Create(AMemManager: TFpDbgMemManager; AnAddress: TDbgPtr;
AnSizeOfAddr, AThreadId: Integer; AStackFrame: Integer);
end;
{ TFpDbgDwarfSimpleLocationContext }
constructor TFpDbgDwarfSimpleLocationContext.Create(
AMemManager: TFpDbgMemManager; AnAddress: TDbgPtr; AnSizeOfAddr,
AThreadId: Integer; AStackFrame: Integer);
begin
inherited Create(AMemManager, AnAddress, AnSizeOfAddr, AThreadId, AStackFrame);
FStackFrame := AStackFrame;
end;
function TFpDbgDwarfSimpleLocationContext.GetStackFrame: Integer;
begin
Result := FStackFrame;
end;
{ TFpDwarfFreePascalSymbolScope }
var
ParentFpLowerNameInfo, ParentFp2LowerNameInfo: TNameSearchInfo; // case sensitive
function TFpDwarfFreePascalSymbolScope.FindLocalSymbol(const AName: String;
const ANameInfo: TNameSearchInfo; InfoEntry: TDwarfInformationEntry; out
ADbgValue: TFpValue): Boolean;
const
selfname = 'self';
// TODO: get reg num via memreader name-to-num
RegFp64 = 6;
RegPc64 = 16;
RegFp32 = 5;
RegPc32 = 8;
var
StartScopeIdx, RegFp, RegPc: Integer;
ParentFpVal: TFpValue;
SearchCtx: TFpDbgDwarfSimpleLocationContext;
par_fp, cur_fp, prev_fp, pc: TDbgPtr;
d, i: Integer;
ParentFpSym: TFpSymbolDwarf;
Ctx: TFpDbgSimpleLocationContext;
begin
Result := False;
if not(Symbol is TFpSymbolDwarfDataProc) then
exit;
if Dwarf.TargetInfo.bitness = b64 then begin
RegFP := RegFp64;
RegPc := RegPc64;
end
else begin
RegFP := RegFp32;
RegPc := RegPc32;
end;
if (Length(AName) = length(selfname)) and (CompareUtf8BothCase(PChar(ANameInfo.NameUpper), PChar(ANameInfo.NameLower), @selfname[1])) then begin
ADbgValue := GetSelfParameter;
if ADbgValue <> nil then begin
ADbgValue.AddReference;
Result := True;
exit;
end;
end;
StartScopeIdx := InfoEntry.ScopeIndex;
Result := inherited FindLocalSymbol(AName, ANameInfo, InfoEntry, ADbgValue);
if Result then
exit;
if FOuterNotFound then
exit;
if FOuterNestContext <> nil then begin
ADbgValue := FOuterNestContext.FindSymbol(AName); // TODO: pass upper/lower
Result := True; // self, global was done by outer
exit;
end;
InfoEntry.ScopeIndex := StartScopeIdx;
if not InfoEntry.GoNamedChildEx(ParentFpLowerNameInfo) then begin
InfoEntry.ScopeIndex := StartScopeIdx;
if not InfoEntry.GoNamedChildEx(ParentFp2LowerNameInfo) then begin
FOuterNotFound := True;
exit;
end;
end;
ParentFpSym := TFpSymbolDwarf.CreateSubClass(AName, InfoEntry);
ParentFpVal := ParentFpSym.Value;
if ParentFpVal = nil then begin
Result := False;
exit;
end;
ApplyContext(ParentFpVal);
if not (svfOrdinal in ParentFpVal.FieldFlags) then begin
DebugLn(FPDBG_DWARF_VERBOSE, 'no ordinal for parentfp');
ParentFpSym.ReleaseReference;
ParentFpVal.ReleaseReference;
FOuterNotFound := True;
exit;
end;
par_fp := ParentFpVal.AsCardinal;
ParentFpVal.ReleaseReference;
ParentFpSym.ReleaseReference;
if par_fp = 0 then begin
DebugLn(FPDBG_DWARF_VERBOSE, 'no ordinal for parentfp');
FOuterNotFound := True;
exit;
end;
// TODO: FindCallStackEntryByBasePointer, once all evaluates run in thread.
i := LocationContext.StackFrame + 1;
SearchCtx := TFpDbgDwarfSimpleLocationContext.Create(MemManager, 0, SizeOfAddress, LocationContext.ThreadId, i);
cur_fp := 0;
if LocationContext.ReadRegister(RegFp, cur_fp) then begin
if cur_fp > par_fp then
d := -1 // cur_fp must go down
else
d := 1; // cur_fp must go up
while not (cur_fp = par_fp) do begin
SearchCtx.FStackFrame := i;
// TODO: get reg num via memreader name-to-num
prev_fp := cur_fp;
if not SearchCtx.ReadRegister(RegFp, cur_fp) then
break;
inc(i);
if (cur_fp = prev_fp) or ((cur_fp < prev_fp) xor (d = -1)) then
break; // wrong direction
if i > LocationContext.StackFrame + 200 then break; // something wrong? // TODO better check
end;
dec(i);
end;
if (par_fp <> cur_fp) or (cur_fp = 0) or
(i <= 0) or
not SearchCtx.ReadRegister(RegPc, pc)
then begin
FOuterNotFound := True;
SearchCtx.ReleaseReference;
exit;
end;
SearchCtx.ReleaseReference;
Ctx := TFpDbgSimpleLocationContext.Create(MemManager, pc, SizeOfAddress, LocationContext.ThreadId, i);
FOuterNestContext := Dwarf.FindSymbolScope(Ctx, pc);
Ctx.ReleaseReference;
ADbgValue := FOuterNestContext.FindSymbol(AName); // TODO: pass upper/lower
Result := True; // self, global was done by outer
end;
destructor TFpDwarfFreePascalSymbolScope.Destroy;
begin
FOuterNestContext.ReleaseReference;
inherited Destroy;
end;
{ TFpSymbolDwarfV2FreePascalTypeStructure }
function TFpSymbolDwarfV2FreePascalTypeStructure.IsShortString: Boolean;
var
LenSym, StSym, StSymType: TFpSymbol;
begin
if FIsShortString <> issUnknown then
exit(FIsShortString = issShortString);
Result := False;
FIsShortString := issStructure;
if (inherited NestedSymbolCount <> 2) then
exit;
if (Name <> 'ShortString') and (Name <> 'LongString') then // DWARF-2 => user types are all caps
exit;
LenSym := inherited NestedSymbolByName['length'];
if (LenSym = nil) or (LenSym.Kind <> skCardinal) // or (LenSym.Size <> 1) // not implemented yet
then
exit;
StSym := inherited NestedSymbolByName['st'];
if (StSym = nil) then
exit;
StSymType := StSym.TypeInfo;
if (StSymType = nil) or (StSymType.Kind <> skArray) or not (StSymType is TFpSymbolDwarfTypeArray) then
exit;
FIsShortString := issShortString;
Result := True;
end;
function TFpSymbolDwarfV2FreePascalTypeStructure.GetTypedValueObject(
ATypeCast: Boolean; AnOuterType: TFpSymbolDwarfType): TFpValueDwarf;
begin
if AnOuterType = nil then
AnOuterType := Self;
if not IsShortString then
Result := inherited GetTypedValueObject(ATypeCast, AnOuterType)
else
Result := TFpValueDwarfV2FreePascalShortString.Create(AnOuterType);
end;
procedure TFpSymbolDwarfV2FreePascalTypeStructure.KindNeeded;
begin
if not IsShortString then
inherited KindNeeded
else
SetKind(skString);
end;
function TFpSymbolDwarfV2FreePascalTypeStructure.GetNestedSymbolCount: Integer;
begin
if IsShortString then
Result := 0
else
Result := inherited GetNestedSymbolCount;
end;
{ TFpSymbolDwarfFreePascalTypeDeclaration }
function TFpSymbolDwarfFreePascalTypeDeclaration.DoGetNestedTypeInfo: TFpSymbolDwarfType;
var
ti: TFpSymbolDwarfType;
begin
Result := inherited DoGetNestedTypeInfo;
// Is internal class pointer?
// Do not trigged any cached property of the pointer
if (Result = nil) or
not (Result is TFpSymbolDwarfFreePascalTypePointer)
then
exit;
ti := TFpSymbolDwarfFreePascalTypePointer(Result).NestedTypeInfo;
// only if it is NOT a declaration
if ti is TFpSymbolDwarfTypeStructure then
TFpSymbolDwarfFreePascalTypePointer(Result).IsInternalPointer := True;
end;
{ TFpSymbolDwarfFreePascalTypePointer }
function TFpSymbolDwarfFreePascalTypePointer.GetIsInternalPointer: Boolean;
begin
Result := FIsInternalPointer or IsInternalDynArrayPointer;
end;
function TFpSymbolDwarfFreePascalTypePointer.IsInternalDynArrayPointer: Boolean;
var
ti: TFpSymbol;
begin
Result := False;
ti := NestedTypeInfo; // Same as TypeInfo, but does not try to be forwarded
Result := ti is TFpSymbolDwarfTypeArray;
if Result then
Result := (sfDynArray in ti.Flags);
end;
procedure TFpSymbolDwarfFreePascalTypePointer.TypeInfoNeeded;
var
p: TFpSymbol;
begin
p := NestedTypeInfo;
if IsInternalPointer and (p <> nil) then
p := p.TypeInfo;
SetTypeInfo(p);
end;
procedure TFpSymbolDwarfFreePascalTypePointer.KindNeeded;
var
k: TDbgSymbolKind;
begin
if IsInternalPointer then begin
k := NestedTypeInfo.Kind;
if k in [skObject, skRecord] then // TODO
SetKind(skInterface)
else
SetKind(k);
end
else
inherited;
end;
function TFpSymbolDwarfFreePascalTypePointer.DoReadStride(
AValueObj: TFpValueDwarf; out AStride: TFpDbgValueSize): Boolean;
begin
if IsInternalPointer then
Result := NestedTypeInfo.ReadStride(AValueObj, AStride)
else
Result := inherited DoReadStride(AValueObj, AStride);
end;
procedure TFpSymbolDwarfFreePascalTypePointer.ForwardToSymbolNeeded;
begin
if IsInternalPointer then
SetForwardToSymbol(NestedTypeInfo) // Same as TypeInfo, but does not try to be forwarded
else
SetForwardToSymbol(nil); // inherited ForwardToSymbolNeeded;
end;
function TFpSymbolDwarfFreePascalTypePointer.GetNextTypeInfoForDataAddress(
ATargetType: TFpSymbolDwarfType): TFpSymbolDwarfType;
begin
if IsInternalPointer then
Result := NestedTypeInfo
else
Result := inherited;
end;
function TFpSymbolDwarfFreePascalTypePointer.GetDataAddressNext(
AValueObj: TFpValueDwarf; var AnAddress: TFpDbgMemLocation; out
ADoneWork: Boolean; ATargetType: TFpSymbolDwarfType): Boolean;
begin
if (not IsInternalPointer) and (ATargetType = nil) then exit(True);
Result := inherited GetDataAddressNext(AValueObj, AnAddress, ADoneWork, ATargetType);
if (not Result) or ADoneWork then
exit;
Result := AValueObj.MemManager <> nil;
if not Result then
exit;
AnAddress := AValueObj.Context.ReadAddress(AnAddress, SizeVal(CompilationUnit.AddressSize));
Result := IsValidLoc(AnAddress);
if (not Result) and
IsError(AValueObj.Context.LastMemError)
then
SetLastError(AValueObj, AValueObj.Context.LastMemError);
end;
function TFpSymbolDwarfFreePascalTypePointer.GetTypedValueObject(
ATypeCast: Boolean; AnOuterType: TFpSymbolDwarfType): TFpValueDwarf;
begin
if AnOuterType = nil then
AnOuterType := Self;
if IsInternalPointer then
Result := NestedTypeInfo.GetTypedValueObject(ATypeCast, AnOuterType)
else
Result := inherited GetTypedValueObject(ATypeCast, AnOuterType);
end;
function TFpSymbolDwarfFreePascalTypePointer.DoReadDataSize(
const AValueObj: TFpValue; out ADataSize: TFpDbgValueSize): Boolean;
begin
if Kind = skClass then begin
// TODO: get/adjust a value object to have the deref address // see ConstRefOrExprFromAttrData
Result := NestedTypeInfo.ReadSize(AValueObj, ADataSize);
if not Result then
ADataSize := ZeroSize;
end
else
Result := inherited DoReadDataSize(AValueObj, ADataSize);
end;
{ TFpSymbolDwarfFreePascalTypeStructure }
procedure TFpSymbolDwarfFreePascalTypeStructure.KindNeeded;
var
t: TDbgSymbolKind;
begin
(* DW_TAG_structure_type
- Is either objec or record.
- Except: fpc < 3.0 => can be class or interface too
DW_TAG_class_type
- Is either class, interface, or object (object only with virtual methods)
tested up to fpc 3.2 beta
*)
if (InformationEntry.AbbrevTag = DW_TAG_interface_type) then begin
SetKind(skInterface);
end
else
if TypeInfo <> nil then begin // inheritance
t := TypeInfo.Kind;
if t = skRecord then
t := skObject; // could be skInterface
SetKind(t); // skClass, skInterface or skObject
end
else
begin
if NestedSymbolByName['_vptr$TOBJECT'] <> nil then
SetKind(skClass)
else
if NestedSymbolByName['_vptr$'+Name] <> nil then // vptr is only present for skObject with virtual methods/Constructor
SetKind(skObject)
else
if (InformationEntry.AbbrevTag = DW_TAG_class_type) then
SetKind(skObject) // could be skInterface // fix in TFpSymbolDwarfFreePascalTypePointer.KindNeeded
else
SetKind(skRecord); // could be skObject(?) or skInterface // fix in TFpSymbolDwarfFreePascalTypePointer.KindNeeded
end;
end;
function TFpSymbolDwarfFreePascalTypeStructure.GetInstanceClassName(
AValueObj: TFpValue; out AClassName: String): boolean;
var
AnErr: TFpError;
begin
Result := AValueObj is TFpValueDwarf;
if not Result then
exit;
Result := GetInstanceClassNameFromPVmt(LocToAddrOrNil(AValueObj.DataAddress),
TFpValueDwarf(AValueObj).Context, TFpValueDwarf(AValueObj).Context.SizeOfAddress, AClassName, AnErr);
if not Result then
SetLastError(AValueObj, AnErr);
end;
class function TFpSymbolDwarfFreePascalTypeStructure.GetInstanceClassNameFromPVmt
(APVmt: TDbgPtr; AContext: TFpDbgLocationContext; ASizeOfAddr: Integer; out
AClassName: String; out AnError: TFpError): boolean;
var
VmtAddr, ClassNameAddr: TFpDbgMemLocation;
NameLen: QWord;
begin
Result := False;
AnError := NoError;
AClassName := '';
if not AContext.ReadAddress(TargetLoc(APVmt), SizeVal(ASizeOfAddr), VmtAddr) then begin
AnError := AContext.LastMemError;
exit;
end;
if not IsReadableMem(VmtAddr) then begin
AnError := CreateError(fpErrCanNotReadMemAtAddr, [VmtAddr.Address]);
exit;
end;
{$PUSH}{$Q-}
VmtAddr.Address := VmtAddr.Address + TDBGPtr(3 * ASizeOfAddr);
{$POP}
if not AContext.ReadAddress(VmtAddr, SizeVal(ASizeOfAddr), ClassNameAddr) then begin
AnError := AContext.LastMemError;
exit;
end;
if not IsReadableMem(ClassNameAddr) then begin
AnError := CreateError(fpErrCanNotReadMemAtAddr, [ClassNameAddr.Address]);
exit;
end;
if not AContext.ReadUnsignedInt(ClassNameAddr, SizeVal(1), NameLen) then begin
AnError := AContext.LastMemError;
exit;
end;
if NameLen = 0 then begin
AnError := CreateError(fpErrAnyError, ['No name found']);
exit;
end;
if not AContext.MemManager.SetLength(AClassName, NameLen) then begin
AnError := AContext.LastMemError;
exit;
end;
ClassNameAddr.Address := ClassNameAddr.Address + 1;
Result := AContext.ReadMemory(ClassNameAddr, SizeVal(NameLen), @AClassName[1]);
if not Result then
AnError := AContext.LastMemError;
end;
{ TFpValueDwarfV2FreePascalShortString }
function TFpValueDwarfV2FreePascalShortString.IsValidTypeCast: Boolean;
begin
// currently only allow this / used by array access
Result := TypeCastSourceValue is TFpValueConstAddress;
end;
function TFpValueDwarfV2FreePascalShortString.GetInternMemberByName(
const AIndex: String): TFpValue;
begin
if HasTypeCastInfo then begin
Result := TypeInfo.GetNestedValueByName(AIndex);
TFpValueDwarf(Result).StructureValue := Self;
if (TFpValueDwarf(Result).Context = nil) then
TFpValueDwarf(Result).Context := Context;
end
else
Result := MemberByName[AIndex];
end;
procedure TFpValueDwarfV2FreePascalShortString.Reset;
begin
inherited Reset;
FValueDone := False;
end;
function TFpValueDwarfV2FreePascalShortString.GetFieldFlags: TFpValueFieldFlags;
begin
Result := inherited GetFieldFlags;
Result := Result + [svfString];
end;
function TFpValueDwarfV2FreePascalShortString.GetAsString: AnsiString;
var
len: QWord;
Size: TFpDbgValueSize;
LenSym, StSym: TFpValueDwarf;
begin
if FValueDone then
exit(FValue);
LenSym := TFpValueDwarf(GetInternMemberByName('length'));
assert(LenSym is TFpValueDwarf, 'LenSym is TFpValueDwarf');
len := LenSym.AsCardinal;
LenSym.ReleaseReference;
if not GetSize(Size) then begin;
SetLastError(CreateError(fpErrAnyError));
exit('');
end;
if (Size < len) then begin
SetLastError(CreateError(fpErrAnyError));
exit('');
end;
if not MemManager.SetLength(Result, len) then begin
SetLastError(MemManager.LastError);
exit;
end;
StSym := TFpValueDwarf(GetInternMemberByName('st'));
assert(StSym is TFpValueDwarf, 'StSym is TFpValueDwarf');
if len > 0 then
if not Context.ReadMemory(StSym.DataAddress, SizeVal(len), @Result[1]) then begin
Result := ''; // TODO: error
SetLastError(Context.LastMemError);
StSym.ReleaseReference;
exit;
end;
StSym.ReleaseReference;
FValue := Result;
FValueDone := True;
end;
function TFpValueDwarfV2FreePascalShortString.GetAsWideString: WideString;
begin
Result := GetAsString;
end;
{ TFpSymbolDwarfFreePascalSymbolTypeArray }
function TFpSymbolDwarfFreePascalSymbolTypeArray.GetTypedValueObject(
ATypeCast: Boolean; AnOuterType: TFpSymbolDwarfType): TFpValueDwarf;
begin
if AnOuterType = nil then
AnOuterType := Self;
Result := TFpValueDwarfFreePascalArray.Create(AnOuterType, Self);
end;
{ TFpValueDwarfFreePascalArray }
function TFpValueDwarfFreePascalArray.GetKind: TDbgSymbolKind;
begin
if TypeInfo <> nil then
Result := TypeInfo.Kind
else
Result := inherited GetKind;
end;
function TFpValueDwarfFreePascalArray.GetMemberCount: Integer;
var
t, t2: TFpSymbol;
Info: TDwarfInformationEntry;
n: AnsiString;
UpperBoundSym: TFpSymbolDwarf;
val: TFpValue;
l, h: Int64;
Addr: TFpDbgMemLocation;
begin
Result := 0;
t := TypeInfo;
if (t.Kind <> skArray) or (t.NestedSymbolCount < 1) then // IndexTypeCount;
exit(inherited GetMemberCount);
t2 := t.NestedSymbol[0]; // IndexType[0];
if not (t2 is TFpSymbolDwarfTypeSubRange) then
exit(inherited GetMemberCount);
TFpSymbolDwarfTypeSubRange(t2).GetValueBounds(Self, l, h);
if (l <> 0) or
(TFpSymbolDwarfTypeSubRange(t2).LowBoundState <> rfConst) or
(TFpSymbolDwarfTypeSubRange(t2).HighBoundState <> rfNotFound) or
(TFpSymbolDwarfTypeSubRange(t2).CountState <> rfNotFound)
then
exit(inherited GetMemberCount);
// Check for open array param
if (t is TFpSymbolDwarfTypeArray) and
(DbgSymbol is TFpSymbolDwarfDataParameter) // open array exists only as param
then begin
Info := TFpSymbolDwarfDataParameter(DbgSymbol).InformationEntry.Clone;
Info.GoNext;
if Info.HasValidScope and
Info.HasAttrib(DW_AT_location) and // the high param must have a location / cannot be a constant
Info.ReadName(n)
then begin
if (n <> '') and (n[1] = '$') then // dwarf3 // TODO: make required in dwarf3
delete(n, 1, 1);
if (copy(n,1,4) = 'high')
and (CompareText(copy(n, 5, length(n)), DbgSymbol.Name) = 0) then begin
UpperBoundSym := TFpSymbolDwarf.CreateSubClass('', Info);
if UpperBoundSym <> nil then begin
val := UpperBoundSym.Value;
if val <> nil then begin
TFpValueDwarf(val).Context := Context;
h := Val.AsInteger;
val.ReleaseReference;
if (h >= 0) and (h < maxLongint) then begin
Result := h + 1;
end
else
Result := 0;
// TODO h < -1 => Error
Info.ReleaseReference;
UpperBoundSym.ReleaseReference;
exit;
end;
end;
end;
end;
Info.ReleaseReference;
end;
// dynamic array
if (sfDynArray in t.Flags) and (AsCardinal <> 0) and GetDwarfDataAddress(Addr) then begin
if not (IsReadableMem(Addr) and (LocToAddr(Addr) > AddressSize)) then
exit(0); // dyn array, but bad data
Addr.Address := Addr.Address - AddressSize;
if Context.ReadSignedInt(Addr, SizeVal(AddressSize), h) then begin
// TODO h < -1 => Error
if (h >= 0) and (h < maxLongint) then
Result := h+1;
exit;
end
else
SetLastError(Context.LastMemError);
Result := 0;
exit;
end;
// Should not be here. There is no knowledeg how many members there are
Result := inherited GetMemberCount;
end;
function TFpValueDwarfFreePascalArray.DoGetStride(out AStride: TFpDbgValueSize
): Boolean;
begin
if (TFpDwarfFreePascalSymbolClassMap(TypeInfo.CompilationUnit.DwarfSymbolClassMap).FCompilerVersion >= $030300)
then
Result := inherited DoGetStride(AStride)
else
Result := TFpSymbolDwarfType(TypeInfo.NestedSymbol[0]).ReadStride(Self, AStride);
end;
function TFpValueDwarfFreePascalArray.DoGetMainStride(out
AStride: TFpDbgValueSize): Boolean;
begin
if (TFpDwarfFreePascalSymbolClassMap(TypeInfo.CompilationUnit.DwarfSymbolClassMap).FCompilerVersion >= $030300)
then
Result := inherited DoGetMainStride(AStride)
else
Result := GetMemberSize(AStride);
end;
function TFpValueDwarfFreePascalArray.DoGetDimStride(AnIndex: integer; out
AStride: TFpDbgValueSize): Boolean;
begin
if (TFpDwarfFreePascalSymbolClassMap(TypeInfo.CompilationUnit.DwarfSymbolClassMap).FCompilerVersion >= $030300)
then
Result := inherited DoGetDimStride(AnIndex, AStride)
else
begin
Result := True;
AStride := ZeroSize;
end;
end;
{ TFpSymbolDwarfV3FreePascalSymbolTypeArray }
function TFpSymbolDwarfV3FreePascalSymbolTypeArray.GetInternalStringType: TArrayOrStringType;
var
Info: TDwarfInformationEntry;
t: Cardinal;
t2: TFpSymbol;
CharSize: TFpDbgValueSize;
LocData: array of byte;
begin
Result := FArrayOrStringType;
if Result <> iasUnknown then
exit;
FArrayOrStringType := iasArray;
Result := FArrayOrStringType;
t2 := TypeInfo;
if (t2 = nil) or (t2.Kind <> skChar) then
exit;
// TODO: check lowbound = 1 (const)
Info := InformationEntry.FirstChild;
if Info = nil then
exit;
while Info.HasValidScope do begin
t := Info.AbbrevTag;
if (t = DW_TAG_enumeration_type) then
break;
if (t = DW_TAG_subrange_type) then begin
if Info.HasAttrib(DW_AT_byte_stride) or Info.HasAttrib(DW_AT_type) then
break;
// TODO: check the location parser, if it is a reference
if InformationEntry.ReadValue(DW_AT_data_location, LocData) then begin
if (Length(LocData) = 3) and
(LocData[0] = $97) and
(LocData[1] = $31) and
(LocData[2] = $22)
then begin
FArrayOrStringType := iasShortString;
break;
end;
end;
if not t2.ReadSize(nil, CharSize) then
CharSize := ZeroSize; // TODO: error
if (CharSize.Size = 2) then
FArrayOrStringType := iasUnicodeString
else
FArrayOrStringType := iasAnsiString;
break;
end;
Info.GoNext;
end;
Info.ReleaseReference;
Result := FArrayOrStringType;
end;
function TFpSymbolDwarfV3FreePascalSymbolTypeArray.GetTypedValueObject(
ATypeCast: Boolean; AnOuterType: TFpSymbolDwarfType): TFpValueDwarf;
begin
if AnOuterType = nil then
AnOuterType := Self;
if GetInternalStringType in [iasShortString, iasAnsiString, iasUnicodeString] then
Result := TFpValueDwarfV3FreePascalString.Create(AnOuterType)
else
Result := inherited GetTypedValueObject(ATypeCast, AnOuterType);
end;
procedure TFpSymbolDwarfV3FreePascalSymbolTypeArray.KindNeeded;
begin
case GetInternalStringType of
iasShortString:
SetKind(skString);
iasAnsiString:
SetKind(skString); // TODO skAnsiString
iasUnicodeString:
SetKind(skWideString);
else
inherited KindNeeded;
end;
end;
function TFpSymbolDwarfV3FreePascalSymbolTypeArray.DoReadSize(
const AValueObj: TFpValue; out ASize: TFpDbgValueSize): Boolean;
begin
if GetInternalStringType in [iasAnsiString, iasUnicodeString] then begin
ASize := ZeroSize;
ASize.Size := CompilationUnit.AddressSize;
Result := True;
end
else begin
Result := inherited DoReadSize(AValueObj, ASize);
if (not Result) and (GetInternalStringType = iasArray) then begin
ASize := ZeroSize;
ASize.Size := CompilationUnit.AddressSize;
Result := True;
end;
end;
end;
{ TFpValueDwarfV3FreePascalString }
function TFpValueDwarfV3FreePascalString.IsValidTypeCast: Boolean;
var
f: TFpValueFieldFlags;
begin
Result := HasTypeCastInfo;
If not Result then
exit;
assert(TypeInfo.Kind in [skString, skWideString], 'TFpValueDwarfArray.IsValidTypeCast: TypeInfo.Kind = skArray');
f := TypeCastSourceValue.FieldFlags;
if (f * [svfAddress, svfSize, svfSizeOfPointer] = [svfAddress]) or
(svfOrdinal in f)
then
exit;
//if sfDynArray in TypeInfo.Flags then begin
// // dyn array
// if (svfOrdinal in f)then
// exit;
// if (f * [svfAddress, svfSize] = [svfAddress, svfSize]) and
// (TypeCastSourceValue.Size = TypeInfo.CompilationUnit.AddressSize)
// then
// exit;
// if (f * [svfAddress, svfSizeOfPointer] = [svfAddress, svfSizeOfPointer]) then
// exit;
//end
//else begin
// // stat array
// if (f * [svfAddress, svfSize] = [svfAddress, svfSize]) and
// (TypeCastSourceValue.Size = TypeInfo.Size)
// then
// exit;
//end;
Result := False;
end;
procedure TFpValueDwarfV3FreePascalString.Reset;
begin
inherited Reset;
FValueDone := False;
end;
function TFpValueDwarfV3FreePascalString.GetFieldFlags: TFpValueFieldFlags;
begin
Result := inherited GetFieldFlags;
case TypeInfo.Kind of
skWideString: Result := Result + [svfWideString];
else Result := Result + [svfString];
end;
end;
function TFpValueDwarfV3FreePascalString.GetAsString: AnsiString;
var
t, t2: TFpSymbol;
LowBound, HighBound, i: Int64;
Addr, Addr2: TFpDbgMemLocation;
WResult: WideString;
RResult: RawByteString;
AttrData: TDwarfAttribData;
Codepage: TSystemCodePage;
begin
if FValueDone then
exit(FValue);
// TODO: error handling
FValue := '';
Result := '';
FValueDone := True;
// get length
t := TypeInfo;
if t.NestedSymbolCount < 1 then // subrange type
exit;
t2 := t.NestedSymbol[0]; // subrange type
if not( (t2 is TFpSymbolDwarfType) and TFpSymbolDwarfType(t2).GetValueBounds(self, LowBound, HighBound) )
then
exit;
GetDwarfDataAddress(Addr);
if (not IsValidLoc(Addr)) and (svfOrdinal in TypeCastSourceValue.FieldFlags) then
Addr := TargetLoc(TypeCastSourceValue.AsCardinal);
if not IsReadableLoc(Addr) then
exit;
assert((TypeInfo <> nil) and (TypeInfo.CompilationUnit <> nil) and (TypeInfo.CompilationUnit.DwarfSymbolClassMap is TFpDwarfFreePascalSymbolClassMapDwarf3), 'TFpValueDwarfV3FreePascalString.GetAsString: (Owner <> nil) and (Owner.CompilationUnit <> nil) and (TypeInfo.CompilationUnit.DwarfSymbolClassMap is TFpDwarfFreePascalSymbolClassMapDwarf3)');
if (TFpDwarfFreePascalSymbolClassMapDwarf3(TypeInfo.CompilationUnit.DwarfSymbolClassMap).FCompilerVersion > 0) and
(TFpDwarfFreePascalSymbolClassMapDwarf3(TypeInfo.CompilationUnit.DwarfSymbolClassMap).FCompilerVersion < $030100)
then begin
if t.Kind = skWideString then begin
if (t2 is TFpSymbolDwarfTypeSubRange) and (LowBound = 1) then begin
if (TFpSymbolDwarfTypeSubRange(t2).InformationEntry.GetAttribData(DW_AT_upper_bound, AttrData)) and
(TFpSymbolDwarfTypeSubRange(t2).InformationEntry.AttribForm[AttrData.Idx] = DW_FORM_block1) and
(IsReadableMem(Addr) and (LocToAddr(Addr) > AddressSize))
then begin
// fpc issue 0035359
// read data and check for DW_OP_shr ?
Addr2 := Addr;
Addr2.Address := Addr2.Address - AddressSize;
if Context.ReadSignedInt(Addr2, SizeVal(AddressSize), i) then begin
if (i shr 1) = HighBound then
HighBound := i;
end
end;
end;
end;
end;
if HighBound < LowBound then
exit; // empty string
if MemManager.MemLimits.MaxStringLen > 0 then begin
{$PUSH}{$Q-}
if QWord(HighBound - LowBound) > MemManager.MemLimits.MaxStringLen then
HighBound := LowBound + MemManager.MemLimits.MaxStringLen;
{$POP}
end;
if t.Kind = skWideString then begin
if not MemManager.SetLength(WResult, HighBound-LowBound+1) then begin
WResult := '';
SetLastError(MemManager.LastError);
end
else
if not Context.ReadMemory(Addr, SizeVal((HighBound-LowBound+1)*2), @WResult[1]) then begin
WResult := '';
SetLastError(Context.LastMemError);
end;
Result := WResult;
end else
if Addr.Address = Address.Address + 1 then begin
// shortstring
if not MemManager.SetLength(Result, HighBound-LowBound+1) then begin
Result := '';
SetLastError(MemManager.LastError);
end
else
if not Context.ReadMemory(Addr, SizeVal(HighBound-LowBound+1), @Result[1]) then begin
Result := '';
SetLastError(Context.LastMemError);
end;
end
else begin
if not MemManager.SetLength(RResult, HighBound-LowBound+1) then begin
Result := '';
SetLastError(MemManager.LastError);
end
else
if not Context.ReadMemory(Addr, SizeVal(HighBound-LowBound+1), @RResult[1]) then begin
Result := '';
SetLastError(Context.LastMemError);
end else begin
if GetDynamicCodePage(Addr, Codepage) then
SetCodePage(RResult, Codepage, False);
Result := RResult;
end;
end;
FValue := Result;
end;
function TFpValueDwarfV3FreePascalString.GetAsWideString: WideString;
begin
// todo: widestring, but currently that is encoded as PWideChar
Result := GetAsString;
end;
function TFpValueDwarfV3FreePascalString.GetDynamicCodePage(Addr: TFpDbgMemLocation; out
Codepage: TSystemCodePage): Boolean;
var
CodepageOffset: SmallInt;
begin
// Only call this function for non-empty strings!
Result := False;
if not IsTargetNotNil(Addr) then
exit;
// Only AnsiStrings in fpc 3.0.0 and higher have a dynamic codepage.
if (TypeInfo.Kind = skString) and (TFpDwarfFreePascalSymbolClassMapDwarf3(TypeInfo.CompilationUnit.DwarfSymbolClassMap).FCompilerVersion >= $030000) then begin
// Too bad the debug-information does not deliver this information. So we
// use these hardcoded information, and hope that FPC does not change and
// we never reach this point for a compilationunit that is not compiled by
// fpc.
if TFpDwarfFreePascalSymbolClassMapDwarf3(TypeInfo.CompilationUnit.DwarfSymbolClassMap).FCompilerVersion >= $030300{$030301} then
CodepageOffset := AddressSize + SizeOf(Longint) + SizeOf(Word) + SizeOf(Word)
else
CodepageOffset := AddressSize * 3;
Addr.Address := Addr.Address - CodepageOffset;
if Context.ReadMemory(Addr, SizeVal(2), @Codepage) then
Result := CodePageToCodePageName(Codepage) <> '';
end;
end;
initialization
DwarfSymbolClassMapList.AddMap(TFpDwarfFreePascalSymbolClassMapDwarf2);
DwarfSymbolClassMapList.AddMap(TFpDwarfFreePascalSymbolClassMapDwarf3);
FPDBG_DWARF_VERBOSE := DebugLogger.FindOrRegisterLogGroup('FPDBG_DWARF_VERBOSE' {$IFDEF FPDBG_DWARF_VERBOSE} , True {$ENDIF} );
ParentFpLowerNameInfo := NameInfoForSearch('parentfp');
ParentFp2LowerNameInfo := NameInfoForSearch('$parentfp');
end.