1 unit FpDbgDwarfFreePascal;
2 
3 {$mode objfpc}{$H+}
4 {$TYPEDADDRESS on}
5 
6 interface
7 
8 uses
9   Classes, SysUtils, Types, math,
10   FpDbgDwarfDataClasses, FpDbgDwarf, FpDbgInfo,
11   FpDbgUtil, FpDbgDwarfConst, FpErrorMessages, FpdMemoryTools,
12   DbgIntfBaseTypes,
13   {$ifdef FORCE_LAZLOGGER_DUMMY} LazLoggerDummy {$else} LazLoggerBase {$endif}, LazStringUtils;
14 
15 type
16 
17   {%Region * ***** SymbolClassMap ***** *}
18 
19   { TFpDwarfFreePascalSymbolClassMap }
20 
21   TFpDwarfFreePascalSymbolClassMap = class(TFpDwarfDefaultSymbolClassMap)
22   strict private
23     class var ExistingClassMap: TFpSymbolDwarfClassMap;
24   private
25     FCompilerVersion: Cardinal;
26   protected
CanHandleCompUnitnull27     function CanHandleCompUnit(ACU: TDwarfCompilationUnit; AHelperData: Pointer): Boolean; override;
GetExistingClassMapnull28     class function GetExistingClassMap: PFpDwarfSymbolClassMap; override;
29   public
GetInstanceForCompUnitnull30     class function GetInstanceForCompUnit(ACU: TDwarfCompilationUnit): TFpSymbolDwarfClassMap; override;
ClassCanHandleCompUnitnull31     class function ClassCanHandleCompUnit(ACU: TDwarfCompilationUnit): Boolean; override;
32 
GetInstanceForDbgInfonull33     class function GetInstanceForDbgInfo(ADbgInfo: TDbgInfo):TFpDwarfFreePascalSymbolClassMap;
34   public
35     constructor Create(ACU: TDwarfCompilationUnit; AHelperData: Pointer); override;
GetDwarfSymbolClassnull36     function GetDwarfSymbolClass(ATag: Cardinal): TDbgDwarfSymbolBaseClass; override;
CreateScopeForSymbolnull37     function CreateScopeForSymbol(ALocationContext: TFpDbgLocationContext; ASymbol: TFpSymbol;
38       ADwarf: TFpDwarfInfo): TFpDbgSymbolScope; override;
CreateProcSymbolnull39     //class function CreateProcSymbol(ACompilationUnit: TDwarfCompilationUnit;
40     //  AInfo: PDwarfAddressInfo; AAddress: TDbgPtr): TDbgDwarfSymbolBase; override;
41 
42     function GetInstanceClassNameFromPVmt(APVmt: TDbgPtr;
43       AContext: TFpDbgLocationContext; ASizeOfAddr: Integer;
44       out AClassName: String; out AnError: TFpError): boolean;
45   end;
46 
47   { TFpDwarfFreePascalSymbolClassMapDwarf2 }
48 
49   TFpDwarfFreePascalSymbolClassMapDwarf2 = class(TFpDwarfFreePascalSymbolClassMap)
50   strict private
51     class var ExistingClassMap: TFpSymbolDwarfClassMap;
52   protected
GetExistingClassMapnull53     class function GetExistingClassMap: PFpDwarfSymbolClassMap; override;
54   public
ClassCanHandleCompUnitnull55     class function ClassCanHandleCompUnit(ACU: TDwarfCompilationUnit): Boolean; override;
56   public
GetDwarfSymbolClassnull57     function GetDwarfSymbolClass(ATag: Cardinal): TDbgDwarfSymbolBaseClass; override;
CreateSymbolScopenull58     //class function CreateSymbolScope(AThreadId, AStackFrame: Integer; AnAddress: TDBGPtr; ASymbol: TFpSymbol;
59     //  ADwarf: TFpDwarfInfo): TFpDbgSymbolScope; override;
60     //class function CreateProcSymbol(ACompilationUnit: TDwarfCompilationUnit;
61     //  AInfo: PDwarfAddressInfo; AAddress: TDbgPtr): TDbgDwarfSymbolBase; override;
62   end;
63 
64   { TFpDwarfFreePascalSymbolClassMapDwarf3 }
65 
66   TFpDwarfFreePascalSymbolClassMapDwarf3 = class(TFpDwarfFreePascalSymbolClassMap)
67   strict private
68     class var ExistingClassMap: TFpSymbolDwarfClassMap;
69   protected
GetExistingClassMapnull70     class function GetExistingClassMap: PFpDwarfSymbolClassMap; override;
71   public
ClassCanHandleCompUnitnull72     class function ClassCanHandleCompUnit(ACU: TDwarfCompilationUnit): Boolean; override;
73   public
GetDwarfSymbolClassnull74     function GetDwarfSymbolClass(ATag: Cardinal): TDbgDwarfSymbolBaseClass; override;
CreateSymbolScopenull75     //class function CreateSymbolScope(AThreadId, AStackFrame: Integer; AnAddress: TDBGPtr; ASymbol: TFpSymbol;
76     //  ADwarf: TFpDwarfInfo): TFpDbgSymbolScope; override;
77     //class function CreateProcSymbol(ACompilationUnit: TDwarfCompilationUnit;
78     //  AInfo: PDwarfAddressInfo; AAddress: TDbgPtr): TDbgDwarfSymbolBase; override;
79   end;
80 
81   {%EndRegion }
82 
83   {%Region * ***** Context ***** *}
84 
85   { TFpDwarfFreePascalSymbolScope }
86 
87   TFpDwarfFreePascalSymbolScope = class(TFpDwarfInfoSymbolScope)
88   private
89     FOuterNestContext: TFpDbgSymbolScope;
90     FOuterNotFound: Boolean;
91   protected
FindLocalSymbolnull92     function FindLocalSymbol(const AName: String; const ANameInfo: TNameSearchInfo;
93       InfoEntry: TDwarfInformationEntry; out ADbgValue: TFpValue): Boolean; override;
94   public
95     destructor Destroy; override;
96   end;
97 
98   {%EndRegion }
99 
100   {%Region * ***** Value & Types ***** *}
101 
102   (* *** Class vs ^Record vs ^Object *** *)
103 
104   { TFpSymbolDwarfFreePascalTypeDeclaration }
105 
106   TFpSymbolDwarfFreePascalTypeDeclaration = class(TFpSymbolDwarfTypeDeclaration)
107   protected
108    // fpc encodes classes as pointer, not ref (so Obj1 = obj2 compares the pointers)
109    // typedef > pointer > srtuct
110    // while a pointer to class/object: pointer > typedef > ....
DoGetNestedTypeInfonull111     function DoGetNestedTypeInfo: TFpSymbolDwarfType; override;
112   end;
113 
114   { TFpSymbolDwarfFreePascalTypePointer }
115 
116   TFpSymbolDwarfFreePascalTypePointer = class(TFpSymbolDwarfTypePointer)
117   private
118     FIsInternalPointer: Boolean;
GetIsInternalPointernull119     function GetIsInternalPointer: Boolean; inline;
IsInternalDynArrayPointernull120     function IsInternalDynArrayPointer: Boolean; inline;
121   protected
122     procedure TypeInfoNeeded; override;
123     procedure KindNeeded; override;
DoReadStridenull124     function DoReadStride(AValueObj: TFpValueDwarf; out AStride: TFpDbgValueSize): Boolean; override;
125     procedure ForwardToSymbolNeeded; override;
GetNextTypeInfoForDataAddressnull126     function GetNextTypeInfoForDataAddress(ATargetType: TFpSymbolDwarfType): TFpSymbolDwarfType; override;
GetDataAddressNextnull127     function GetDataAddressNext(AValueObj: TFpValueDwarf; var AnAddress: TFpDbgMemLocation;
128       out ADoneWork: Boolean; ATargetType: TFpSymbolDwarfType): Boolean; override;
DoReadDataSizenull129     function DoReadDataSize(const AValueObj: TFpValue; out ADataSize: TFpDbgValueSize): Boolean; override;
130   public
GetTypedValueObjectnull131     function GetTypedValueObject(ATypeCast: Boolean; AnOuterType: TFpSymbolDwarfType = nil): TFpValueDwarf; override;
132     property IsInternalPointer: Boolean read GetIsInternalPointer write FIsInternalPointer; // Class (also DynArray, but DynArray is handled without this)
133   end;
134 
135   { TFpSymbolDwarfFreePascalTypeStructure }
136 
137   TFpSymbolDwarfFreePascalTypeStructure = class(TFpSymbolDwarfTypeStructure)
138   protected
139     procedure KindNeeded; override;
GetInstanceClassnull140     //function GetInstanceClass(AValueObj: TFpValueDwarf): TFpSymbolDwarf; override;
141     class function GetInstanceClassNameFromPVmt(APVmt: TDbgPtr;
142       AContext: TFpDbgLocationContext; ASizeOfAddr: Integer;
143       out AClassName: String; out AnError: TFpError): boolean;
144   public
GetInstanceClassNamenull145     function GetInstanceClassName(AValueObj: TFpValue; out
146       AClassName: String): boolean; override;
147   end;
148 
149   (* *** Record vs ShortString *** *)
150 
151   { TFpSymbolDwarfV2FreePascalTypeStructure }
152 
153   TFpSymbolDwarfV2FreePascalTypeStructure = class(TFpSymbolDwarfFreePascalTypeStructure)
154   private
155     FIsShortString: (issUnknown, issShortString, issStructure);
IsShortStringnull156     function IsShortString: Boolean;
157   protected
158     procedure KindNeeded; override;
GetNestedSymbolCountnull159     function GetNestedSymbolCount: Integer; override;
GetNestedSymbolByNamenull160     //function GetNestedSymbolByName(AIndex: String): TFpSymbol; override;
161   public
162     function GetTypedValueObject(ATypeCast: Boolean; AnOuterType: TFpSymbolDwarfType = nil): TFpValueDwarf; override;
163   end;
164 
165   { TFpValueDwarfV2FreePascalShortString }
166 
167   TFpValueDwarfV2FreePascalShortString = class(TFpValueDwarf)
168   protected
IsValidTypeCastnull169     function IsValidTypeCast: Boolean; override;
GetInternMemberByNamenull170     function GetInternMemberByName(const AIndex: String): TFpValue;
171     procedure Reset; override;
172   private
173     FValue: String;
174     FValueDone: Boolean;
175   protected
GetFieldFlagsnull176     function GetFieldFlags: TFpValueFieldFlags; override;
GetAsStringnull177     function GetAsString: AnsiString; override;
GetAsWideStringnull178     function GetAsWideString: WideString; override;
179   end;
180 
181   (* *** "Open Array" in params *** *)
182 
183   { TFpSymbolDwarfFreePascalSymbolTypeArray }
184 
185   TFpSymbolDwarfFreePascalSymbolTypeArray = class(TFpSymbolDwarfTypeArray)
186   public
GetTypedValueObjectnull187     function GetTypedValueObject(ATypeCast: Boolean; AnOuterType: TFpSymbolDwarfType = nil): TFpValueDwarf; override;
188   end;
189 
190   { TFpValueDwarfFreePascalArray }
191 
192   TFpValueDwarfFreePascalArray = class(TFpValueDwarfArray)
193   protected
GetKindnull194     function GetKind: TDbgSymbolKind; override;
GetMemberCountnull195     function GetMemberCount: Integer; override;
DoGetStridenull196     function DoGetStride(out AStride: TFpDbgValueSize): Boolean; override;
DoGetMainStridenull197     function DoGetMainStride(out AStride: TFpDbgValueSize): Boolean; override;
DoGetDimStridenull198     function DoGetDimStride(AnIndex: integer; out AStride: TFpDbgValueSize): Boolean; override;
199   end;
200 
201   (* *** Array vs AnsiString *** *)
202 
203   { TFpSymbolDwarfV3FreePascalSymbolTypeArray }
204 
205   TFpSymbolDwarfV3FreePascalSymbolTypeArray = class(TFpSymbolDwarfFreePascalSymbolTypeArray)
206   private type
207     TArrayOrStringType = (iasUnknown, iasArray, iasShortString, iasAnsiString, iasUnicodeString);
208   private
209     FArrayOrStringType: TArrayOrStringType;
GetInternalStringTypenull210     function GetInternalStringType: TArrayOrStringType;
211   protected
212     procedure KindNeeded; override;
DoReadSizenull213     function DoReadSize(const AValueObj: TFpValue; out ASize: TFpDbgValueSize): Boolean; override;
214   public
GetTypedValueObjectnull215     function GetTypedValueObject(ATypeCast: Boolean; AnOuterType: TFpSymbolDwarfType = nil): TFpValueDwarf; override;
216   end;
217 
218   { TFpValueDwarfV3FreePascalString }
219 
220   TFpValueDwarfV3FreePascalString = class(TFpValueDwarf) // short & ansi...
221   private
222     FValue: String;
223     FValueDone: Boolean;
GetDynamicCodePagenull224     function GetDynamicCodePage(Addr: TFpDbgMemLocation; out Codepage: TSystemCodePage): Boolean;
225   protected
IsValidTypeCastnull226     function IsValidTypeCast: Boolean; override;
227     procedure Reset; override;
GetFieldFlagsnull228     function GetFieldFlags: TFpValueFieldFlags; override;
GetAsStringnull229     function GetAsString: AnsiString; override;
GetAsWideStringnull230     function GetAsWideString: WideString; override;
231   end;
232 
233   {%EndRegion }
234 
235 implementation
236 
237 uses
238   FpDbgCommon;
239 
240 var
241   FPDBG_DWARF_VERBOSE: PLazLoggerLogGroup;
242 
243 { TFpDwarfFreePascalSymbolClassMap }
244 
CanHandleCompUnitnull245 function TFpDwarfFreePascalSymbolClassMap.CanHandleCompUnit(
246   ACU: TDwarfCompilationUnit; AHelperData: Pointer): Boolean;
247 begin
248   Result := (FCompilerVersion = PtrUInt(AHelperData)) and
249             inherited CanHandleCompUnit(ACU, AHelperData);
250 end;
251 
TFpDwarfFreePascalSymbolClassMap.GetExistingClassMapnull252 class function TFpDwarfFreePascalSymbolClassMap.GetExistingClassMap: PFpDwarfSymbolClassMap;
253 begin
254   Result := @ExistingClassMap;
255 end;
256 
TFpDwarfFreePascalSymbolClassMap.GetInstanceForCompUnitnull257 class function TFpDwarfFreePascalSymbolClassMap.GetInstanceForCompUnit(
258   ACU: TDwarfCompilationUnit): TFpSymbolDwarfClassMap;
259 var
260   s: String;
261   i, j, AVersion: Integer;
262 begin
263   AVersion := 0;
264   s := ACU.Producer+' ';
265   i := PosI('free pascal', s) + 11;
266 
267   if i > 11 then begin
268     while (i < Length(s)) and (s[i] in [' ', #9]) do
269       inc(i);
270     delete(s, 1, i - 1);
271     i := pos('.', s);
272     if (i > 1) then begin
273       j := StrToIntDef(copy(s, 1, i - 1), 0);
274       if (j >= 0) then
275         AVersion := j * $10000;
276       delete(s, 1, i);
277     end;
278     if (AVersion > 0) then begin
279       i := pos('.', s);
280       if (i > 1) then begin
281         j := StrToIntDef(copy(s, 1, i - 1), 0);
282         if (j >= 0) and (j < 99) then
283           AVersion := AVersion + j * $100
284         else
285           AVersion := 0;
286         delete(s, 1, i);
287       end;
288     end;
289     if (AVersion > 0) then begin
290       i := pos(' ', s);
291       if (i > 1) then begin
292         j := StrToIntDef(copy(s, 1, i - 1), 0);
293         if (j >= 0) and (j < 99) then
294           AVersion := AVersion + j
295         else
296           AVersion := 0;
297       end;
298     end;
299   end;
300 
301   Result := DoGetInstanceForCompUnit(ACU, Pointer(PtrUInt(AVersion)));
302 end;
303 
TFpDwarfFreePascalSymbolClassMap.ClassCanHandleCompUnitnull304 class function TFpDwarfFreePascalSymbolClassMap.ClassCanHandleCompUnit(ACU: TDwarfCompilationUnit): Boolean;
305 begin
306   Result := PosI('free pascal', ACU.Producer) > 0;
307 end;
308 
309 var
310   LastInfo: TDbgInfo = nil;
311   FoundMap: TFpDwarfFreePascalSymbolClassMap = nil;
312 
TFpDwarfFreePascalSymbolClassMap.GetInstanceForDbgInfonull313 class function TFpDwarfFreePascalSymbolClassMap.GetInstanceForDbgInfo(
314   ADbgInfo: TDbgInfo): TFpDwarfFreePascalSymbolClassMap;
315 var
316   i: Integer;
317 begin
318   if ADbgInfo <> LastInfo then begin
319     FoundMap := nil;
320     LastInfo := nil;
321   end;
322 
323   Result := FoundMap;
324   if LastInfo <> nil then
325     exit;
326 
327   if not (ADbgInfo is TFpDwarfInfo) then
328     exit;
329 
330   for i := 0 to TFpDwarfInfo(ADbgInfo).CompilationUnitsCount - 1 do
331     if TFpDwarfInfo(ADbgInfo).CompilationUnits[i].DwarfSymbolClassMap is TFpDwarfFreePascalSymbolClassMap
332     then begin
333       FoundMap := TFpDwarfFreePascalSymbolClassMap(TFpDwarfInfo(ADbgInfo).CompilationUnits[i].DwarfSymbolClassMap);
334     end;
335 
336   Result := FoundMap;
337   LastInfo := ADbgInfo;
338 end;
339 
340 constructor TFpDwarfFreePascalSymbolClassMap.Create(ACU: TDwarfCompilationUnit;
341   AHelperData: Pointer);
342 begin
343   FCompilerVersion := PtrUInt(AHelperData);
344   inherited Create(ACU, AHelperData);
345 end;
346 
GetDwarfSymbolClassnull347 function TFpDwarfFreePascalSymbolClassMap.GetDwarfSymbolClass(
348   ATag: Cardinal): TDbgDwarfSymbolBaseClass;
349 begin
350   case ATag of
351     DW_TAG_typedef:          Result := TFpSymbolDwarfFreePascalTypeDeclaration;
352     DW_TAG_pointer_type:     Result := TFpSymbolDwarfFreePascalTypePointer;
353     DW_TAG_structure_type,
354     DW_TAG_class_type:       Result := TFpSymbolDwarfFreePascalTypeStructure;
355     DW_TAG_array_type:       Result := TFpSymbolDwarfFreePascalSymbolTypeArray;
356     else                     Result := inherited GetDwarfSymbolClass(ATag);
357   end;
358 end;
359 
TFpDwarfFreePascalSymbolClassMap.CreateScopeForSymbolnull360 function TFpDwarfFreePascalSymbolClassMap.CreateScopeForSymbol(
361   ALocationContext: TFpDbgLocationContext; ASymbol: TFpSymbol;
362   ADwarf: TFpDwarfInfo): TFpDbgSymbolScope;
363 begin
364   Result := TFpDwarfFreePascalSymbolScope.Create(ALocationContext, ASymbol, ADwarf);
365 end;
366 
GetInstanceClassNameFromPVmtnull367 function TFpDwarfFreePascalSymbolClassMap.GetInstanceClassNameFromPVmt(
368   APVmt: TDbgPtr; AContext: TFpDbgLocationContext; ASizeOfAddr: Integer; out
369   AClassName: String; out AnError: TFpError): boolean;
370 begin
371   Result := TFpSymbolDwarfFreePascalTypeStructure.GetInstanceClassNameFromPVmt(APVmt,
372     AContext, ASizeOfAddr, AClassName, AnError);
373 end;
374 
375 { TFpDwarfFreePascalSymbolClassMapDwarf2 }
376 
TFpDwarfFreePascalSymbolClassMapDwarf2.GetExistingClassMapnull377 class function TFpDwarfFreePascalSymbolClassMapDwarf2.GetExistingClassMap: PFpDwarfSymbolClassMap;
378 begin
379   Result := @ExistingClassMap;
380 end;
381 
TFpDwarfFreePascalSymbolClassMapDwarf2.ClassCanHandleCompUnitnull382 class function TFpDwarfFreePascalSymbolClassMapDwarf2.ClassCanHandleCompUnit(
383   ACU: TDwarfCompilationUnit): Boolean;
384 begin
385   Result := inherited ClassCanHandleCompUnit(ACU);
386   Result := Result and (ACU.Version < 3);
387 end;
388 
GetDwarfSymbolClassnull389 function TFpDwarfFreePascalSymbolClassMapDwarf2.GetDwarfSymbolClass(
390   ATag: Cardinal): TDbgDwarfSymbolBaseClass;
391 begin
392   case ATag of
393     DW_TAG_structure_type:
394       Result := TFpSymbolDwarfV2FreePascalTypeStructure; // maybe record
395   //  // TODO:
396   //  //DW_TAG_reference_type:   Result := TFpSymbolDwarfTypeRef;
397   //  //DW_TAG_typedef:          Result := TFpSymbolDwarfTypeDeclaration;
398   //  //DW_TAG_pointer_type:     Result := TFpSymbolDwarfTypePointer;
399   //  //
400   //  //DW_TAG_base_type:        Result := TFpSymbolDwarfTypeBasic;
401   //  //DW_TAG_subrange_type:    Result := TFpSymbolDwarfTypeSubRange;
402   //  //DW_TAG_enumeration_type: Result := TFpSymbolDwarfTypeEnum;
403   //  //DW_TAG_enumerator:       Result := TFpSymbolDwarfDataEnumMember;
404   //  //DW_TAG_array_type:       Result := TFpSymbolDwarfTypeArray;
405   //  ////
406   //  //DW_TAG_compile_unit:     Result := TFpSymbolDwarfUnit;
407   //
408     else
409       Result := inherited GetDwarfSymbolClass(ATag);
410   end;
411 end;
412 
413 { TFpDwarfFreePascalSymbolClassMapDwarf3 }
414 
TFpDwarfFreePascalSymbolClassMapDwarf3.GetExistingClassMapnull415 class function TFpDwarfFreePascalSymbolClassMapDwarf3.GetExistingClassMap: PFpDwarfSymbolClassMap;
416 begin
417   Result := @ExistingClassMap;
418 end;
419 
TFpDwarfFreePascalSymbolClassMapDwarf3.ClassCanHandleCompUnitnull420 class function TFpDwarfFreePascalSymbolClassMapDwarf3.ClassCanHandleCompUnit(
421   ACU: TDwarfCompilationUnit): Boolean;
422 begin
423   Result := inherited ClassCanHandleCompUnit(ACU);
424   Result := Result and (ACU.Version >= 3);
425 end;
426 
GetDwarfSymbolClassnull427 function TFpDwarfFreePascalSymbolClassMapDwarf3.GetDwarfSymbolClass(
428   ATag: Cardinal): TDbgDwarfSymbolBaseClass;
429 begin
430   case ATag of
431     DW_TAG_array_type:
432       Result := TFpSymbolDwarfV3FreePascalSymbolTypeArray;
433   //  DW_TAG_structure_type:
434   //    Result := TFpSymbolDwarfV2FreePascalTypeStructure; // maybe record
435   //  // TODO:
436   //  //DW_TAG_reference_type:   Result := TFpSymbolDwarfTypeRef;
437   //  //DW_TAG_typedef:          Result := TFpSymbolDwarfTypeDeclaration;
438   //  //DW_TAG_pointer_type:     Result := TFpSymbolDwarfTypePointer;
439   //  //
440   //  //DW_TAG_base_type:        Result := TFpSymbolDwarfTypeBasic;
441   //  //DW_TAG_subrange_type:    Result := TFpSymbolDwarfTypeSubRange;
442   //  //DW_TAG_enumeration_type: Result := TFpSymbolDwarfTypeEnum;
443   //  //DW_TAG_enumerator:       Result := TFpSymbolDwarfDataEnumMember;
444   //  //DW_TAG_array_type:       Result := TFpSymbolDwarfTypeArray;
445   //  ////
446   //  //DW_TAG_compile_unit:     Result := TFpSymbolDwarfUnit;
447   //
448     else
449       Result := inherited GetDwarfSymbolClass(ATag);
450   end;
451 end;
452 
453 type
454 
455   { TFpDbgDwarfSimpleLocationContext }
456 
457   TFpDbgDwarfSimpleLocationContext = class(TFpDbgSimpleLocationContext)
458   protected
459     FStackFrame: Integer;
GetStackFramenull460     function GetStackFrame: Integer; override;
461   public
462     constructor Create(AMemManager: TFpDbgMemManager; AnAddress: TDbgPtr;
463       AnSizeOfAddr, AThreadId: Integer; AStackFrame: Integer);
464   end;
465 
466 { TFpDbgDwarfSimpleLocationContext }
467 
468 constructor TFpDbgDwarfSimpleLocationContext.Create(
469   AMemManager: TFpDbgMemManager; AnAddress: TDbgPtr; AnSizeOfAddr,
470   AThreadId: Integer; AStackFrame: Integer);
471 begin
472   inherited Create(AMemManager, AnAddress, AnSizeOfAddr, AThreadId, AStackFrame);
473   FStackFrame := AStackFrame;
474 end;
475 
GetStackFramenull476 function TFpDbgDwarfSimpleLocationContext.GetStackFrame: Integer;
477 begin
478   Result := FStackFrame;
479 end;
480 
481 { TFpDwarfFreePascalSymbolScope }
482 
483 var
484   ParentFpLowerNameInfo, ParentFp2LowerNameInfo: TNameSearchInfo; // case sensitive
FindLocalSymbolnull485 function TFpDwarfFreePascalSymbolScope.FindLocalSymbol(const AName: String;
486   const ANameInfo: TNameSearchInfo; InfoEntry: TDwarfInformationEntry; out
487   ADbgValue: TFpValue): Boolean;
488 const
489   selfname = 'self';
490   // TODO: get reg num via memreader name-to-num
491   RegFp64 = 6;
492   RegPc64 = 16;
493   RegFp32 = 5;
494   RegPc32 = 8;
495 var
496   StartScopeIdx, RegFp, RegPc: Integer;
497   ParentFpVal: TFpValue;
498   SearchCtx: TFpDbgDwarfSimpleLocationContext;
499   par_fp, cur_fp, prev_fp, pc: TDbgPtr;
500   d, i: Integer;
501   ParentFpSym: TFpSymbolDwarf;
502   Ctx: TFpDbgSimpleLocationContext;
503 begin
504   Result := False;
505   if not(Symbol is TFpSymbolDwarfDataProc) then
506     exit;
507 
508   if Dwarf.TargetInfo.bitness = b64 then begin
509     RegFP := RegFp64;
510     RegPc := RegPc64;
511   end
512   else begin
513     RegFP := RegFp32;
514     RegPc := RegPc32;
515   end;
516   if (Length(AName) = length(selfname)) and (CompareUtf8BothCase(PChar(ANameInfo.NameUpper), PChar(ANameInfo.NameLower), @selfname[1])) then begin
517     ADbgValue := GetSelfParameter;
518     if ADbgValue <> nil then begin
519       ADbgValue.AddReference;
520       Result := True;
521       exit;
522     end;
523   end;
524 
525   StartScopeIdx := InfoEntry.ScopeIndex;
526   Result := inherited FindLocalSymbol(AName, ANameInfo, InfoEntry, ADbgValue);
527   if Result then
528     exit;
529 
530   if FOuterNotFound then
531     exit;
532 
533   if FOuterNestContext <> nil then begin
534     ADbgValue := FOuterNestContext.FindSymbol(AName); // TODO: pass upper/lower
535     Result := True; // self, global was done by outer
536     exit;
537   end;
538 
539 
540   InfoEntry.ScopeIndex := StartScopeIdx;
541   if not InfoEntry.GoNamedChildEx(ParentFpLowerNameInfo) then begin
542     InfoEntry.ScopeIndex := StartScopeIdx;
543     if not InfoEntry.GoNamedChildEx(ParentFp2LowerNameInfo) then begin
544       FOuterNotFound := True;
545       exit;
546     end;
547   end;
548 
549   ParentFpSym := TFpSymbolDwarf.CreateSubClass(AName, InfoEntry);
550   ParentFpVal := ParentFpSym.Value;
551   if ParentFpVal = nil then begin
552     Result := False;
553     exit;
554   end;
555   ApplyContext(ParentFpVal);
556   if not (svfOrdinal in ParentFpVal.FieldFlags) then begin
557     DebugLn(FPDBG_DWARF_VERBOSE, 'no ordinal for parentfp');
558     ParentFpSym.ReleaseReference;
559     ParentFpVal.ReleaseReference;
560     FOuterNotFound := True;
561     exit;
562   end;
563 
564   par_fp := ParentFpVal.AsCardinal;
565   ParentFpVal.ReleaseReference;
566   ParentFpSym.ReleaseReference;
567   if par_fp = 0 then begin
568     DebugLn(FPDBG_DWARF_VERBOSE, 'no ordinal for parentfp');
569     FOuterNotFound := True;
570     exit;
571   end;
572 
573   // TODO: FindCallStackEntryByBasePointer, once all evaluates run in thread.
574   i := LocationContext.StackFrame + 1;
575   SearchCtx := TFpDbgDwarfSimpleLocationContext.Create(MemManager, 0, SizeOfAddress, LocationContext.ThreadId, i);
576 
577   cur_fp := 0;
578   if LocationContext.ReadRegister(RegFp, cur_fp) then begin
579     if cur_fp > par_fp then
580       d := -1  // cur_fp must go down
581     else
582       d := 1;  // cur_fp must go up
583     while not (cur_fp = par_fp) do begin
584       SearchCtx.FStackFrame := i;
585       // TODO: get reg num via memreader name-to-num
586       prev_fp := cur_fp;
587       if not SearchCtx.ReadRegister(RegFp, cur_fp) then
588         break;
589       inc(i);
590       if (cur_fp = prev_fp) or ((cur_fp < prev_fp) xor (d = -1)) then
591         break;  // wrong direction
592       if i > LocationContext.StackFrame + 200 then break; // something wrong? // TODO better check
593     end;
594     dec(i);
595   end;
596 
597   if (par_fp <> cur_fp) or (cur_fp = 0) or
598      (i <= 0) or
599      not SearchCtx.ReadRegister(RegPc, pc)
600   then begin
601     FOuterNotFound := True;
602     SearchCtx.ReleaseReference;
603     exit;
604   end;
605 
606   SearchCtx.ReleaseReference;
607 
608   Ctx := TFpDbgSimpleLocationContext.Create(MemManager, pc, SizeOfAddress, LocationContext.ThreadId, i);
609   FOuterNestContext := Dwarf.FindSymbolScope(Ctx, pc);
610   Ctx.ReleaseReference;
611 
612   ADbgValue := FOuterNestContext.FindSymbol(AName); // TODO: pass upper/lower
613   Result := True; // self, global was done by outer
614 end;
615 
616 destructor TFpDwarfFreePascalSymbolScope.Destroy;
617 begin
618   FOuterNestContext.ReleaseReference;
619   inherited Destroy;
620 end;
621 
622 { TFpSymbolDwarfV2FreePascalTypeStructure }
623 
TFpSymbolDwarfV2FreePascalTypeStructure.IsShortStringnull624 function TFpSymbolDwarfV2FreePascalTypeStructure.IsShortString: Boolean;
625 var
626   LenSym, StSym, StSymType: TFpSymbol;
627 begin
628   if FIsShortString <> issUnknown then
629     exit(FIsShortString = issShortString);
630 
631   Result := False;
632   FIsShortString := issStructure;
633   if (inherited NestedSymbolCount <> 2) then
634     exit;
635 
636   if (Name <> 'ShortString') and (Name <> 'LongString') then  // DWARF-2 => user types are all caps
637     exit;
638 
639   LenSym := inherited NestedSymbolByName['length'];
640   if (LenSym = nil) or (LenSym.Kind <> skCardinal) // or (LenSym.Size <> 1) // not implemented yet
641   then
642     exit;
643 
644   StSym := inherited NestedSymbolByName['st'];
645   if (StSym = nil) then
646     exit;
647   StSymType := StSym.TypeInfo;
648   if (StSymType = nil) or (StSymType.Kind <> skArray) or not (StSymType is TFpSymbolDwarfTypeArray) then
649     exit;
650 
651   FIsShortString := issShortString;
652   Result := True;
653 end;
654 
TFpSymbolDwarfV2FreePascalTypeStructure.GetTypedValueObjectnull655 function TFpSymbolDwarfV2FreePascalTypeStructure.GetTypedValueObject(
656   ATypeCast: Boolean; AnOuterType: TFpSymbolDwarfType): TFpValueDwarf;
657 begin
658   if AnOuterType = nil then
659     AnOuterType := Self;
660   if not IsShortString then
661     Result := inherited GetTypedValueObject(ATypeCast, AnOuterType)
662   else
663     Result := TFpValueDwarfV2FreePascalShortString.Create(AnOuterType);
664 end;
665 
666 procedure TFpSymbolDwarfV2FreePascalTypeStructure.KindNeeded;
667 begin
668   if not IsShortString then
669     inherited KindNeeded
670   else
671     SetKind(skString);
672 end;
673 
GetNestedSymbolCountnull674 function TFpSymbolDwarfV2FreePascalTypeStructure.GetNestedSymbolCount: Integer;
675 begin
676   if IsShortString then
677     Result := 0
678   else
679     Result := inherited GetNestedSymbolCount;
680 end;
681 
682 { TFpSymbolDwarfFreePascalTypeDeclaration }
683 
TFpSymbolDwarfFreePascalTypeDeclaration.DoGetNestedTypeInfonull684 function TFpSymbolDwarfFreePascalTypeDeclaration.DoGetNestedTypeInfo: TFpSymbolDwarfType;
685 var
686   ti: TFpSymbolDwarfType;
687 begin
688   Result := inherited DoGetNestedTypeInfo;
689 
690   // Is internal class pointer?
691   // Do not trigged any cached property of the pointer
692   if (Result = nil) or
693      not (Result is TFpSymbolDwarfFreePascalTypePointer)
694   then
695     exit;
696 
697   ti := TFpSymbolDwarfFreePascalTypePointer(Result).NestedTypeInfo;
698   // only if it is NOT a declaration
699   if ti is TFpSymbolDwarfTypeStructure then
700     TFpSymbolDwarfFreePascalTypePointer(Result).IsInternalPointer := True;
701 end;
702 
703 { TFpSymbolDwarfFreePascalTypePointer }
704 
TFpSymbolDwarfFreePascalTypePointer.GetIsInternalPointernull705 function TFpSymbolDwarfFreePascalTypePointer.GetIsInternalPointer: Boolean;
706 begin
707   Result := FIsInternalPointer or IsInternalDynArrayPointer;
708 end;
709 
IsInternalDynArrayPointernull710 function TFpSymbolDwarfFreePascalTypePointer.IsInternalDynArrayPointer: Boolean;
711 var
712   ti: TFpSymbol;
713 begin
714   Result := False;
715   ti := NestedTypeInfo;  // Same as TypeInfo, but does not try to be forwarded
716   Result := ti is TFpSymbolDwarfTypeArray;
717   if Result then
718     Result := (sfDynArray in ti.Flags);
719 end;
720 
721 procedure TFpSymbolDwarfFreePascalTypePointer.TypeInfoNeeded;
722 var
723   p: TFpSymbol;
724 begin
725   p := NestedTypeInfo;
726   if IsInternalPointer and (p <> nil) then
727     p := p.TypeInfo;
728   SetTypeInfo(p);
729 end;
730 
731 procedure TFpSymbolDwarfFreePascalTypePointer.KindNeeded;
732 var
733   k: TDbgSymbolKind;
734 begin
735   if IsInternalPointer then begin
736       k := NestedTypeInfo.Kind;
737       if k in [skObject, skRecord] then   // TODO
738         SetKind(skInterface)
739       else
740         SetKind(k);
741   end
742   else
743     inherited;
744 end;
745 
DoReadStridenull746 function TFpSymbolDwarfFreePascalTypePointer.DoReadStride(
747   AValueObj: TFpValueDwarf; out AStride: TFpDbgValueSize): Boolean;
748 begin
749   if IsInternalPointer then
750     Result := NestedTypeInfo.ReadStride(AValueObj, AStride)
751   else
752     Result := inherited DoReadStride(AValueObj, AStride);
753 end;
754 
755 procedure TFpSymbolDwarfFreePascalTypePointer.ForwardToSymbolNeeded;
756 begin
757   if IsInternalPointer then
758     SetForwardToSymbol(NestedTypeInfo) // Same as TypeInfo, but does not try to be forwarded
759   else
760     SetForwardToSymbol(nil); // inherited ForwardToSymbolNeeded;
761 end;
762 
TFpSymbolDwarfFreePascalTypePointer.GetNextTypeInfoForDataAddressnull763 function TFpSymbolDwarfFreePascalTypePointer.GetNextTypeInfoForDataAddress(
764   ATargetType: TFpSymbolDwarfType): TFpSymbolDwarfType;
765 begin
766   if IsInternalPointer then
767     Result := NestedTypeInfo
768   else
769     Result := inherited;
770 end;
771 
GetDataAddressNextnull772 function TFpSymbolDwarfFreePascalTypePointer.GetDataAddressNext(
773   AValueObj: TFpValueDwarf; var AnAddress: TFpDbgMemLocation; out
774   ADoneWork: Boolean; ATargetType: TFpSymbolDwarfType): Boolean;
775 begin
776   if (not IsInternalPointer) and (ATargetType = nil) then exit(True);
777 
778   Result := inherited GetDataAddressNext(AValueObj, AnAddress, ADoneWork, ATargetType);
779   if (not Result) or ADoneWork then
780     exit;
781 
782   Result := AValueObj.MemManager <> nil;
783   if not Result then
784     exit;
785   AnAddress := AValueObj.Context.ReadAddress(AnAddress, SizeVal(CompilationUnit.AddressSize));
786   Result := IsValidLoc(AnAddress);
787 
788   if (not Result) and
789      IsError(AValueObj.Context.LastMemError)
790   then
791     SetLastError(AValueObj, AValueObj.Context.LastMemError);
792 end;
793 
TFpSymbolDwarfFreePascalTypePointer.GetTypedValueObjectnull794 function TFpSymbolDwarfFreePascalTypePointer.GetTypedValueObject(
795   ATypeCast: Boolean; AnOuterType: TFpSymbolDwarfType): TFpValueDwarf;
796 begin
797   if AnOuterType = nil then
798     AnOuterType := Self;
799   if IsInternalPointer then
800     Result := NestedTypeInfo.GetTypedValueObject(ATypeCast, AnOuterType)
801   else
802     Result := inherited GetTypedValueObject(ATypeCast, AnOuterType);
803 end;
804 
DoReadDataSizenull805 function TFpSymbolDwarfFreePascalTypePointer.DoReadDataSize(
806   const AValueObj: TFpValue; out ADataSize: TFpDbgValueSize): Boolean;
807 begin
808   if Kind = skClass then begin
809     // TODO: get/adjust a value object to have the deref address // see ConstRefOrExprFromAttrData
810     Result := NestedTypeInfo.ReadSize(AValueObj, ADataSize);
811     if not Result then
812       ADataSize := ZeroSize;
813   end
814   else
815     Result := inherited DoReadDataSize(AValueObj, ADataSize);
816 end;
817 
818 { TFpSymbolDwarfFreePascalTypeStructure }
819 
820 procedure TFpSymbolDwarfFreePascalTypeStructure.KindNeeded;
821 var
822   t: TDbgSymbolKind;
823 begin
824   (* DW_TAG_structure_type
825      - Is either objec or record.
826      - Except: fpc < 3.0 => can be class or interface too
827      DW_TAG_class_type
828      - Is either class, interface, or object (object only with virtual methods)
829 
830      tested up to fpc 3.2 beta
831   *)
832   if (InformationEntry.AbbrevTag = DW_TAG_interface_type) then begin
833     SetKind(skInterface);
834   end
835   else
836   if TypeInfo <> nil then begin // inheritance
837     t := TypeInfo.Kind;
838     if t = skRecord then
839       t := skObject; // could be skInterface
840     SetKind(t); // skClass, skInterface or skObject
841   end
842   else
843   begin
844     if NestedSymbolByName['_vptr$TOBJECT'] <> nil then
845       SetKind(skClass)
846     else
847     if NestedSymbolByName['_vptr$'+Name] <> nil then // vptr is only present for skObject with virtual methods/Constructor
848       SetKind(skObject)
849     else
850     if (InformationEntry.AbbrevTag = DW_TAG_class_type) then
851       SetKind(skObject)   // could be skInterface  // fix in TFpSymbolDwarfFreePascalTypePointer.KindNeeded
852     else
853       SetKind(skRecord);  // could be skObject(?) or skInterface   // fix in TFpSymbolDwarfFreePascalTypePointer.KindNeeded
854   end;
855 end;
856 
GetInstanceClassNamenull857 function TFpSymbolDwarfFreePascalTypeStructure.GetInstanceClassName(
858   AValueObj: TFpValue; out AClassName: String): boolean;
859 var
860   AnErr: TFpError;
861 begin
862   Result := AValueObj is TFpValueDwarf;
863   if not Result then
864     exit;
865   Result := GetInstanceClassNameFromPVmt(LocToAddrOrNil(AValueObj.DataAddress),
866     TFpValueDwarf(AValueObj).Context, TFpValueDwarf(AValueObj).Context.SizeOfAddress, AClassName, AnErr);
867   if not Result then
868     SetLastError(AValueObj, AnErr);
869 end;
870 
TFpSymbolDwarfFreePascalTypeStructure.GetInstanceClassNameFromPVmtnull871 class function TFpSymbolDwarfFreePascalTypeStructure.GetInstanceClassNameFromPVmt
872   (APVmt: TDbgPtr; AContext: TFpDbgLocationContext; ASizeOfAddr: Integer; out
873   AClassName: String; out AnError: TFpError): boolean;
874 var
875   VmtAddr, ClassNameAddr: TFpDbgMemLocation;
876   NameLen: QWord;
877 begin
878   Result := False;
879   AnError := NoError;
880   AClassName := '';
881   if not AContext.ReadAddress(TargetLoc(APVmt), SizeVal(ASizeOfAddr), VmtAddr) then begin
882     AnError := AContext.LastMemError;
883     exit;
884   end;
885   if not IsReadableMem(VmtAddr) then begin
886     AnError := CreateError(fpErrCanNotReadMemAtAddr, [VmtAddr.Address]);
887     exit;
888   end;
889   {$PUSH}{$Q-}
890   VmtAddr.Address := VmtAddr.Address + TDBGPtr(3 * ASizeOfAddr);
891   {$POP}
892 
893   if not AContext.ReadAddress(VmtAddr, SizeVal(ASizeOfAddr), ClassNameAddr) then begin
894     AnError := AContext.LastMemError;
895     exit;
896   end;
897   if not IsReadableMem(ClassNameAddr) then begin
898     AnError := CreateError(fpErrCanNotReadMemAtAddr, [ClassNameAddr.Address]);
899     exit;
900   end;
901   if not AContext.ReadUnsignedInt(ClassNameAddr, SizeVal(1), NameLen) then begin
902     AnError := AContext.LastMemError;
903     exit;
904   end;
905   if NameLen = 0 then begin
906     AnError := CreateError(fpErrAnyError, ['No name found']);
907     exit;
908   end;
909   if not AContext.MemManager.SetLength(AClassName, NameLen) then begin
910     AnError := AContext.LastMemError;
911     exit;
912   end;
913 
914   ClassNameAddr.Address := ClassNameAddr.Address + 1;
915   Result := AContext.ReadMemory(ClassNameAddr, SizeVal(NameLen), @AClassName[1]);
916   if not Result then
917     AnError := AContext.LastMemError;
918 end;
919 
920 { TFpValueDwarfV2FreePascalShortString }
921 
TFpValueDwarfV2FreePascalShortString.IsValidTypeCastnull922 function TFpValueDwarfV2FreePascalShortString.IsValidTypeCast: Boolean;
923 begin
924   // currently only allow this / used by array access
925   Result := TypeCastSourceValue is TFpValueConstAddress;
926 end;
927 
GetInternMemberByNamenull928 function TFpValueDwarfV2FreePascalShortString.GetInternMemberByName(
929   const AIndex: String): TFpValue;
930 begin
931   if HasTypeCastInfo then begin
932     Result := TypeInfo.GetNestedValueByName(AIndex);
933     TFpValueDwarf(Result).StructureValue := Self;
934     if (TFpValueDwarf(Result).Context = nil) then
935       TFpValueDwarf(Result).Context := Context;
936   end
937   else
938     Result := MemberByName[AIndex];
939 end;
940 
941 procedure TFpValueDwarfV2FreePascalShortString.Reset;
942 begin
943   inherited Reset;
944   FValueDone := False;
945 end;
946 
TFpValueDwarfV2FreePascalShortString.GetFieldFlagsnull947 function TFpValueDwarfV2FreePascalShortString.GetFieldFlags: TFpValueFieldFlags;
948 begin
949   Result := inherited GetFieldFlags;
950   Result := Result + [svfString];
951 end;
952 
TFpValueDwarfV2FreePascalShortString.GetAsStringnull953 function TFpValueDwarfV2FreePascalShortString.GetAsString: AnsiString;
954 var
955   len: QWord;
956   Size: TFpDbgValueSize;
957   LenSym, StSym: TFpValueDwarf;
958 begin
959   if FValueDone then
960     exit(FValue);
961 
962   LenSym := TFpValueDwarf(GetInternMemberByName('length'));
963   assert(LenSym is TFpValueDwarf, 'LenSym is TFpValueDwarf');
964   len := LenSym.AsCardinal;
965   LenSym.ReleaseReference;
966 
967   if not GetSize(Size) then begin;
968     SetLastError(CreateError(fpErrAnyError));
969     exit('');
970   end;
971   if (Size < len) then begin
972     SetLastError(CreateError(fpErrAnyError));
973     exit('');
974   end;
975 
976   if not MemManager.SetLength(Result, len) then begin
977     SetLastError(MemManager.LastError);
978     exit;
979   end;
980 
981   StSym := TFpValueDwarf(GetInternMemberByName('st'));
982   assert(StSym is TFpValueDwarf, 'StSym is TFpValueDwarf');
983 
984   if len > 0 then
985     if not Context.ReadMemory(StSym.DataAddress, SizeVal(len), @Result[1]) then begin
986       Result := ''; // TODO: error
987       SetLastError(Context.LastMemError);
988       StSym.ReleaseReference;
989       exit;
990     end;
991   StSym.ReleaseReference;
992 
993   FValue := Result;
994   FValueDone := True;
995 end;
996 
GetAsWideStringnull997 function TFpValueDwarfV2FreePascalShortString.GetAsWideString: WideString;
998 begin
999   Result := GetAsString;
1000 end;
1001 
1002 { TFpSymbolDwarfFreePascalSymbolTypeArray }
1003 
TFpSymbolDwarfFreePascalSymbolTypeArray.GetTypedValueObjectnull1004 function TFpSymbolDwarfFreePascalSymbolTypeArray.GetTypedValueObject(
1005   ATypeCast: Boolean; AnOuterType: TFpSymbolDwarfType): TFpValueDwarf;
1006 begin
1007   if AnOuterType = nil then
1008     AnOuterType := Self;
1009   Result := TFpValueDwarfFreePascalArray.Create(AnOuterType, Self);
1010 end;
1011 
1012 { TFpValueDwarfFreePascalArray }
1013 
GetKindnull1014 function TFpValueDwarfFreePascalArray.GetKind: TDbgSymbolKind;
1015 begin
1016   if TypeInfo <> nil then
1017     Result := TypeInfo.Kind
1018   else
1019     Result := inherited GetKind;
1020 end;
1021 
GetMemberCountnull1022 function TFpValueDwarfFreePascalArray.GetMemberCount: Integer;
1023 var
1024   t, t2: TFpSymbol;
1025   Info: TDwarfInformationEntry;
1026   n: AnsiString;
1027   UpperBoundSym: TFpSymbolDwarf;
1028   val: TFpValue;
1029   l, h: Int64;
1030   Addr: TFpDbgMemLocation;
1031 begin
1032   Result := 0;
1033   t := TypeInfo;
1034   if (t.Kind <> skArray) or (t.NestedSymbolCount < 1) then // IndexTypeCount;
1035     exit(inherited GetMemberCount);
1036 
1037   t2 := t.NestedSymbol[0]; // IndexType[0];
1038   if not (t2 is TFpSymbolDwarfTypeSubRange) then
1039     exit(inherited GetMemberCount);
1040 
1041 
1042   TFpSymbolDwarfTypeSubRange(t2).GetValueBounds(Self, l, h);
1043   if (l <> 0) or
1044      (TFpSymbolDwarfTypeSubRange(t2).LowBoundState <> rfConst) or
1045      (TFpSymbolDwarfTypeSubRange(t2).HighBoundState <> rfNotFound) or
1046      (TFpSymbolDwarfTypeSubRange(t2).CountState <> rfNotFound)
1047   then
1048     exit(inherited GetMemberCount);
1049 
1050   // Check for open array param
1051   if (t is TFpSymbolDwarfTypeArray) and
1052      (DbgSymbol is TFpSymbolDwarfDataParameter) // open array exists only as param
1053   then begin
1054     Info := TFpSymbolDwarfDataParameter(DbgSymbol).InformationEntry.Clone;
1055     Info.GoNext;
1056     if Info.HasValidScope and
1057        Info.HasAttrib(DW_AT_location) and  // the high param must have a location / cannot be a constant
1058        Info.ReadName(n)
1059     then begin
1060       if (n <> '') and (n[1] = '$') then // dwarf3 // TODO: make required in dwarf3
1061         delete(n, 1, 1);
1062       if (copy(n,1,4) = 'high')
1063       and (CompareText(copy(n, 5, length(n)), DbgSymbol.Name) = 0) then begin
1064         UpperBoundSym := TFpSymbolDwarf.CreateSubClass('', Info);
1065         if UpperBoundSym <> nil then begin
1066           val := UpperBoundSym.Value;
1067           if val <> nil then begin
1068             TFpValueDwarf(val).Context := Context;
1069             h := Val.AsInteger;
1070             val.ReleaseReference;
1071             if (h >= 0) and (h < maxLongint) then begin
1072               Result := h + 1;
1073             end
1074             else
1075               Result := 0;
1076   // TODO h < -1  => Error
1077             Info.ReleaseReference;
1078             UpperBoundSym.ReleaseReference;
1079             exit;
1080           end;
1081         end;
1082       end;
1083     end;
1084     Info.ReleaseReference;
1085   end;
1086 
1087   // dynamic array
1088   if (sfDynArray in t.Flags) and (AsCardinal <> 0) and GetDwarfDataAddress(Addr) then begin
1089     if not (IsReadableMem(Addr) and (LocToAddr(Addr) > AddressSize)) then
1090       exit(0); // dyn array, but bad data
1091     Addr.Address := Addr.Address - AddressSize;
1092     if Context.ReadSignedInt(Addr, SizeVal(AddressSize), h) then begin
1093 // TODO h < -1  => Error
1094       if (h >= 0) and (h < maxLongint) then
1095         Result := h+1;
1096       exit;
1097     end
1098     else
1099       SetLastError(Context.LastMemError);
1100     Result := 0;
1101     exit;
1102   end;
1103 
1104   // Should not be here. There is no knowledeg how many members there are
1105   Result := inherited GetMemberCount;
1106 end;
1107 
DoGetStridenull1108 function TFpValueDwarfFreePascalArray.DoGetStride(out AStride: TFpDbgValueSize
1109   ): Boolean;
1110 begin
1111   if (TFpDwarfFreePascalSymbolClassMap(TypeInfo.CompilationUnit.DwarfSymbolClassMap).FCompilerVersion >= $030300)
1112   then
1113     Result := inherited DoGetStride(AStride)
1114   else
1115     Result := TFpSymbolDwarfType(TypeInfo.NestedSymbol[0]).ReadStride(Self, AStride);
1116 end;
1117 
TFpValueDwarfFreePascalArray.DoGetMainStridenull1118 function TFpValueDwarfFreePascalArray.DoGetMainStride(out
1119   AStride: TFpDbgValueSize): Boolean;
1120 begin
1121   if (TFpDwarfFreePascalSymbolClassMap(TypeInfo.CompilationUnit.DwarfSymbolClassMap).FCompilerVersion >= $030300)
1122   then
1123     Result := inherited DoGetMainStride(AStride)
1124   else
1125     Result := GetMemberSize(AStride);
1126 end;
1127 
TFpValueDwarfFreePascalArray.DoGetDimStridenull1128 function TFpValueDwarfFreePascalArray.DoGetDimStride(AnIndex: integer; out
1129   AStride: TFpDbgValueSize): Boolean;
1130 begin
1131   if (TFpDwarfFreePascalSymbolClassMap(TypeInfo.CompilationUnit.DwarfSymbolClassMap).FCompilerVersion >= $030300)
1132   then
1133     Result := inherited DoGetDimStride(AnIndex, AStride)
1134   else
1135   begin
1136     Result := True;
1137     AStride := ZeroSize;
1138   end;
1139 end;
1140 
1141 { TFpSymbolDwarfV3FreePascalSymbolTypeArray }
1142 
TFpSymbolDwarfV3FreePascalSymbolTypeArray.GetInternalStringTypenull1143 function TFpSymbolDwarfV3FreePascalSymbolTypeArray.GetInternalStringType: TArrayOrStringType;
1144 var
1145   Info: TDwarfInformationEntry;
1146   t: Cardinal;
1147   t2: TFpSymbol;
1148   CharSize: TFpDbgValueSize;
1149   LocData: array of byte;
1150 begin
1151   Result := FArrayOrStringType;
1152   if Result <> iasUnknown then
1153     exit;
1154 
1155   FArrayOrStringType := iasArray;
1156   Result := FArrayOrStringType;
1157 
1158   t2 := TypeInfo;
1159   if (t2 = nil) or (t2.Kind <> skChar) then
1160     exit;
1161 
1162   // TODO: check lowbound = 1 (const)
1163 
1164   Info := InformationEntry.FirstChild;
1165   if Info = nil then
1166     exit;
1167 
1168   while Info.HasValidScope do begin
1169     t := Info.AbbrevTag;
1170     if (t = DW_TAG_enumeration_type) then
1171       break;
1172     if (t = DW_TAG_subrange_type) then begin
1173       if Info.HasAttrib(DW_AT_byte_stride) or Info.HasAttrib(DW_AT_type) then
1174         break;
1175 
1176       // TODO: check the location parser, if it is a reference
1177 
1178       if InformationEntry.ReadValue(DW_AT_data_location, LocData) then begin
1179         if (Length(LocData) = 3) and
1180            (LocData[0] = $97) and
1181            (LocData[1] = $31) and
1182            (LocData[2] = $22)
1183         then begin
1184           FArrayOrStringType := iasShortString;
1185           break;
1186         end;
1187       end;
1188 
1189       if not t2.ReadSize(nil, CharSize) then
1190         CharSize := ZeroSize; // TODO: error
1191       if (CharSize.Size = 2) then
1192         FArrayOrStringType := iasUnicodeString
1193       else
1194         FArrayOrStringType := iasAnsiString;
1195       break;
1196     end;
1197     Info.GoNext;
1198   end;
1199 
1200   Info.ReleaseReference;
1201   Result := FArrayOrStringType;
1202 end;
1203 
TFpSymbolDwarfV3FreePascalSymbolTypeArray.GetTypedValueObjectnull1204 function TFpSymbolDwarfV3FreePascalSymbolTypeArray.GetTypedValueObject(
1205   ATypeCast: Boolean; AnOuterType: TFpSymbolDwarfType): TFpValueDwarf;
1206 begin
1207   if AnOuterType = nil then
1208     AnOuterType := Self;
1209   if GetInternalStringType in [iasShortString, iasAnsiString, iasUnicodeString] then
1210     Result := TFpValueDwarfV3FreePascalString.Create(AnOuterType)
1211   else
1212     Result := inherited GetTypedValueObject(ATypeCast, AnOuterType);
1213 end;
1214 
1215 procedure TFpSymbolDwarfV3FreePascalSymbolTypeArray.KindNeeded;
1216 begin
1217   case GetInternalStringType of
1218     iasShortString:
1219       SetKind(skString);
1220     iasAnsiString:
1221       SetKind(skString); // TODO skAnsiString
1222     iasUnicodeString:
1223       SetKind(skWideString);
1224     else
1225       inherited KindNeeded;
1226   end;
1227 end;
1228 
DoReadSizenull1229 function TFpSymbolDwarfV3FreePascalSymbolTypeArray.DoReadSize(
1230   const AValueObj: TFpValue; out ASize: TFpDbgValueSize): Boolean;
1231 begin
1232   if GetInternalStringType in [iasAnsiString, iasUnicodeString] then begin
1233     ASize := ZeroSize;
1234     ASize.Size := CompilationUnit.AddressSize;
1235     Result := True;
1236   end
1237   else begin
1238     Result := inherited DoReadSize(AValueObj, ASize);
1239     if (not Result) and (GetInternalStringType = iasArray) then begin
1240       ASize := ZeroSize;
1241       ASize.Size := CompilationUnit.AddressSize;
1242       Result := True;
1243     end;
1244   end;
1245 end;
1246 
1247 { TFpValueDwarfV3FreePascalString }
1248 
IsValidTypeCastnull1249 function TFpValueDwarfV3FreePascalString.IsValidTypeCast: Boolean;
1250 var
1251   f: TFpValueFieldFlags;
1252 begin
1253   Result := HasTypeCastInfo;
1254   If not Result then
1255     exit;
1256 
1257   assert(TypeInfo.Kind in [skString, skWideString], 'TFpValueDwarfArray.IsValidTypeCast: TypeInfo.Kind = skArray');
1258 
1259   f := TypeCastSourceValue.FieldFlags;
1260   if (f * [svfAddress, svfSize, svfSizeOfPointer] = [svfAddress]) or
1261      (svfOrdinal in f)
1262   then
1263     exit;
1264 
1265   //if sfDynArray in TypeInfo.Flags then begin
1266   //  // dyn array
1267   //  if (svfOrdinal in f)then
1268   //    exit;
1269   //  if (f * [svfAddress, svfSize] = [svfAddress, svfSize]) and
1270   //     (TypeCastSourceValue.Size = TypeInfo.CompilationUnit.AddressSize)
1271   //  then
1272   //    exit;
1273   //  if (f * [svfAddress, svfSizeOfPointer] = [svfAddress, svfSizeOfPointer]) then
1274   //    exit;
1275   //end
1276   //else begin
1277   //  // stat array
1278   //  if (f * [svfAddress, svfSize] = [svfAddress, svfSize]) and
1279   //     (TypeCastSourceValue.Size = TypeInfo.Size)
1280   //  then
1281   //    exit;
1282   //end;
1283   Result := False;
1284 end;
1285 
1286 procedure TFpValueDwarfV3FreePascalString.Reset;
1287 begin
1288   inherited Reset;
1289   FValueDone := False;
1290 end;
1291 
TFpValueDwarfV3FreePascalString.GetFieldFlagsnull1292 function TFpValueDwarfV3FreePascalString.GetFieldFlags: TFpValueFieldFlags;
1293 begin
1294   Result := inherited GetFieldFlags;
1295   case TypeInfo.Kind of
1296     skWideString: Result := Result + [svfWideString];
1297     else          Result := Result + [svfString];
1298   end;
1299 end;
1300 
GetAsStringnull1301 function TFpValueDwarfV3FreePascalString.GetAsString: AnsiString;
1302 var
1303   t, t2: TFpSymbol;
1304   LowBound, HighBound, i: Int64;
1305   Addr, Addr2: TFpDbgMemLocation;
1306   WResult: WideString;
1307   RResult: RawByteString;
1308   AttrData: TDwarfAttribData;
1309   Codepage: TSystemCodePage;
1310 begin
1311   if FValueDone then
1312     exit(FValue);
1313 
1314   // TODO: error handling
1315   FValue := '';
1316   Result := '';
1317   FValueDone := True;
1318 
1319   // get length
1320   t := TypeInfo;
1321   if t.NestedSymbolCount < 1 then // subrange type
1322     exit;
1323 
1324   t2 := t.NestedSymbol[0]; // subrange type
1325   if not( (t2 is TFpSymbolDwarfType) and TFpSymbolDwarfType(t2).GetValueBounds(self, LowBound, HighBound) )
1326   then
1327     exit;
1328 
1329   GetDwarfDataAddress(Addr);
1330   if (not IsValidLoc(Addr)) and (svfOrdinal in TypeCastSourceValue.FieldFlags) then
1331     Addr := TargetLoc(TypeCastSourceValue.AsCardinal);
1332   if not IsReadableLoc(Addr) then
1333     exit;
1334 
1335   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)');
1336   if (TFpDwarfFreePascalSymbolClassMapDwarf3(TypeInfo.CompilationUnit.DwarfSymbolClassMap).FCompilerVersion > 0) and
1337      (TFpDwarfFreePascalSymbolClassMapDwarf3(TypeInfo.CompilationUnit.DwarfSymbolClassMap).FCompilerVersion < $030100)
1338   then begin
1339     if t.Kind = skWideString then begin
1340       if (t2 is TFpSymbolDwarfTypeSubRange) and (LowBound = 1) then begin
1341         if (TFpSymbolDwarfTypeSubRange(t2).InformationEntry.GetAttribData(DW_AT_upper_bound, AttrData)) and
1342            (TFpSymbolDwarfTypeSubRange(t2).InformationEntry.AttribForm[AttrData.Idx] = DW_FORM_block1) and
1343            (IsReadableMem(Addr) and (LocToAddr(Addr) > AddressSize))
1344         then begin
1345           // fpc issue 0035359
1346           // read data and check for DW_OP_shr ?
1347           Addr2 := Addr;
1348           Addr2.Address := Addr2.Address - AddressSize;
1349           if Context.ReadSignedInt(Addr2, SizeVal(AddressSize), i) then begin
1350             if (i shr 1) = HighBound then
1351               HighBound := i;
1352           end
1353         end;
1354       end;
1355     end;
1356   end;
1357 
1358   if HighBound < LowBound then
1359     exit; // empty string
1360 
1361   if MemManager.MemLimits.MaxStringLen > 0 then begin
1362     {$PUSH}{$Q-}
1363     if QWord(HighBound - LowBound) > MemManager.MemLimits.MaxStringLen then
1364       HighBound := LowBound + MemManager.MemLimits.MaxStringLen;
1365     {$POP}
1366   end;
1367 
1368   if t.Kind = skWideString then begin
1369     if not MemManager.SetLength(WResult, HighBound-LowBound+1) then begin
1370       WResult := '';
1371       SetLastError(MemManager.LastError);
1372     end
1373     else
1374     if not Context.ReadMemory(Addr, SizeVal((HighBound-LowBound+1)*2), @WResult[1]) then begin
1375       WResult := '';
1376       SetLastError(Context.LastMemError);
1377     end;
1378 
1379     Result := WResult;
1380   end else
1381   if Addr.Address = Address.Address + 1 then begin
1382     // shortstring
1383     if not MemManager.SetLength(Result, HighBound-LowBound+1) then begin
1384       Result := '';
1385       SetLastError(MemManager.LastError);
1386     end
1387     else
1388     if not Context.ReadMemory(Addr, SizeVal(HighBound-LowBound+1), @Result[1]) then begin
1389       Result := '';
1390       SetLastError(Context.LastMemError);
1391     end;
1392   end
1393   else begin
1394     if not MemManager.SetLength(RResult, HighBound-LowBound+1) then begin
1395       Result := '';
1396       SetLastError(MemManager.LastError);
1397     end
1398     else
1399     if not Context.ReadMemory(Addr, SizeVal(HighBound-LowBound+1), @RResult[1]) then begin
1400       Result := '';
1401       SetLastError(Context.LastMemError);
1402     end else begin
1403       if GetDynamicCodePage(Addr, Codepage) then
1404         SetCodePage(RResult, Codepage, False);
1405       Result := RResult;
1406     end;
1407   end;
1408 
1409   FValue := Result;
1410 end;
1411 
GetAsWideStringnull1412 function TFpValueDwarfV3FreePascalString.GetAsWideString: WideString;
1413 begin
1414   // todo: widestring, but currently that is encoded as PWideChar
1415   Result := GetAsString;
1416 end;
1417 
GetDynamicCodePagenull1418 function TFpValueDwarfV3FreePascalString.GetDynamicCodePage(Addr: TFpDbgMemLocation; out
1419   Codepage: TSystemCodePage): Boolean;
1420 var
1421   CodepageOffset: SmallInt;
1422 begin
fornull1423   // Only call this function for non-empty strings!
1424   Result := False;
1425   if not IsTargetNotNil(Addr) then
1426     exit;
1427 
1428   // Only AnsiStrings in fpc 3.0.0 and higher have a dynamic codepage.
1429   if (TypeInfo.Kind = skString) and (TFpDwarfFreePascalSymbolClassMapDwarf3(TypeInfo.CompilationUnit.DwarfSymbolClassMap).FCompilerVersion >= $030000) then begin
1430     // Too bad the debug-information does not deliver this information. So we
1431     // use these hardcoded information, and hope that FPC does not change and
1432     // we never reach this point for a compilationunit that is not compiled by
1433     // fpc.
1434     CodepageOffset := AddressSize * 3;
1435     Addr.Address := Addr.Address - CodepageOffset;
1436     if Context.ReadMemory(Addr, SizeVal(2), @Codepage) then
1437       Result := CodePageToCodePageName(Codepage) <> '';
1438   end;
1439 end;
1440 
1441 initialization
1442   DwarfSymbolClassMapList.AddMap(TFpDwarfFreePascalSymbolClassMapDwarf2);
1443   DwarfSymbolClassMapList.AddMap(TFpDwarfFreePascalSymbolClassMapDwarf3);
1444 
1445   FPDBG_DWARF_VERBOSE       := DebugLogger.FindOrRegisterLogGroup('FPDBG_DWARF_VERBOSE' {$IFDEF FPDBG_DWARF_VERBOSE} , True {$ENDIF} );
1446 
1447   ParentFpLowerNameInfo := NameInfoForSearch('parentfp');
1448   ParentFp2LowerNameInfo := NameInfoForSearch('$parentfp');
1449 end.
1450 
1451