{ --------------------------------------------------------------------------- FpDbgDwarfCFI.pas - Native Freepascal debugger - Call Frame Information --------------------------------------------------------------------------- This unit contains classes to process the Dwarf Call Frame Information information --------------------------------------------------------------------------- @created(Wed Jun 16th WET 2022) @lastmod($Date$) @author(Joost van der Sluis ) *************************************************************************** * * * This source is free software; you can redistribute it and/or modify * * it under the terms of the GNU General Public License as published by * * the Free Software Foundation; either version 2 of the License, or * * (at your option) any later version. * * * * This code is distributed in the hope that it will be useful, but * * WITHOUT ANY WARRANTY; without even the implied warranty of * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * * General Public License for more details. * * * * A copy of the GNU General Public License is available on the World * * Wide Web at . You can also * * obtain it by writing to the Free Software Foundation, * * Inc., 51 Franklin Street - Fifth Floor, Boston, MA 02110-1335, USA. * * * *************************************************************************** } unit FpDbgDwarfCFI; {$mode objfpc}{$H+} interface uses Classes, SysUtils, // LazUtils Maps, {$ifdef FORCE_LAZLOGGER_DUMMY} LazLoggerDummy {$else} LazLoggerBase {$endif}, // DebuggerIntf DbgIntfBaseTypes, // FpDebug FpDbgCommon, FpDbgUtil, FpDbgDwarfConst, FpDbgClasses; type PDwarfCIEEntryHeader32 = ^TDwarfCIEEntryHeader32; TDwarfCIEEntryHeader32 = record Length: LongWord; CIEId: LongWord; Version: Byte; Augmentation: array[0..1023] of char; end; PDwarfCIEEntryHeader64 = ^TDwarfCIEEntryHeader64; TDwarfCIEEntryHeader64 = record Signature: LongWord; Length: QWord; CIEId: QWord; Version: Byte; Augmentation: array[0..1023] of char; end; PDwarfFDEEntryHeader32 = ^TDwarfFDEEntryHeader32; TDwarfFDEEntryHeader32 = record Length: LongWord; CIEPointer: LongWord; InitialLocation: LongWord; Initialrange: LongWord; end; PDwarfFDEEntryHeader64 = ^TDwarfFDEEntryHeader64; TDwarfFDEEntryHeader64 = record Signature: LongWord; Length: QWord; CIEPointer: QWord; InitialLocation: PQWord; end; TDwarfCallFrameInformationInstructions = array of Byte; { TDwarfCIE } TDwarfCIE = class private FAddressSize: Byte; FAugmentation: string; FCodeAlignmentFactor: QWord; FDataAlignmentFactor: Int64; FInitialInstructions: TDwarfCallFrameInformationInstructions; FReturnAddressRegister: QWord; FSegmentSize: Byte; FVersion: Byte; public constructor Create(AVersion: Byte; AnAugmentation: string); property Version: Byte read FVersion; property Augmentation: string read FAugmentation; property AddressSize: Byte read FAddressSize write FAddressSize; property SegmentSize: Byte read FSegmentSize write FSegmentSize; property CodeAlignmentFactor: QWord read FCodeAlignmentFactor write FCodeAlignmentFactor; property DataAlignmentFactor: Int64 read FDataAlignmentFactor write FDataAlignmentFactor; property ReturnAddressRegister: QWord read FReturnAddressRegister write FReturnAddressRegister; property InitialInstructions: TDwarfCallFrameInformationInstructions read FInitialInstructions write FInitialInstructions; end; TDwarfCallFrameInformationRegisterRule = ( cfiUndefined, cfiSameValue, cfiOffset, cfiValOffset, cfiRegister, cfiExpression, cfiValExpression, cfiArchitectural ); TDwarfCallFrameInformationCFARule = ( cfaUndefined, cfaRegister, cfaExpression ); { TDwarfCallFrameInformationRule } TDwarfCallFrameInformationRule = record Offset: Int64; &Register: QWord; // Dwarf-expressions are unsupported // Expression: TDwarfLocationExpression; case byte of 0: (RegisterRule: TDwarfCallFrameInformationRegisterRule); 1: (CFARule: TDwarfCallFrameInformationCFARule); end; TDwarfCallFrameInformationRow = record // The DWARF CFI specification defines the Location and CFARule as the // first two columns of the array. // By keeping them separate, the code is much cleaner though. Location: TDBGPtr; CFARule: TDwarfCallFrameInformationRule; RegisterArray: array of TDwarfCallFrameInformationRule; end; { TDwarfFDE } TDwarfFDE = class private FAddressRange: QWord; FCIEPointer: QWord; FInitialLocation: TDBGPtr; FInstructions: TDwarfCallFrameInformationInstructions; FSegmentSelector: TDBGPtr; public constructor Create(ACIEPointer: QWord; AnInitialLocation, ASegmentSelector: TDBGPtr; AnAddressRange: QWord); property CIEPointer: QWord read FCIEPointer; property InitialLocation: TDBGPtr read FInitialLocation; property SegmentSelector: TDBGPtr read FSegmentSelector; property AddressRange: QWord read FAddressRange; property Instructions: TDwarfCallFrameInformationInstructions read FInstructions write FInstructions; end; { TDwarfCallFrameInformation } TDwarfCallFrameInformation = class private FFDEMap: TMap; FCIEMap: TMap; FInitialInstructionsCache: TDwarfCallFrameInformationRow; FRowStack: array of TDwarfCallFrameInformationRow; protected function SetCallFrameInformationRegisterCell(var InformationRow: TDwarfCallFrameInformationRow; &Register: QWord; Rule: TDwarfCallFrameInformationRegisterRule; Offset: Int64; SourceRegister: Byte): Boolean; function SetCallFrameInformationCFACell(var InformationRow: TDwarfCallFrameInformationRow; Rule: TDwarfCallFrameInformationCFARule; &Register: Byte; Offset: Int64): Boolean; // Process Call Frame Instructions on a given (CFI) row. Return True if succesfull. // When False returned the InformationRow can not be trusted. function ProcessInstructions(const CIE: TDwarfCIE; var InformationRow: TDwarfCallFrameInformationRow; const Instructions: TDwarfCallFrameInformationInstructions; const InitialAddress, SearchAddress: TDBGPtr): Boolean; procedure InitializeABIRules(TargetInfo: TTargetDescriptor; var Row: TDwarfCallFrameInformationRow); function CloneRow(const SourceRow: TDwarfCallFrameInformationRow): TDwarfCallFrameInformationRow; public constructor Create; destructor Destroy; override; procedure AddCIE(AnOffset: QWord; ACIE: TDwarfCIE); procedure AddFDE(AFDE: TDwarfFDE); function FindFDEForAddress(AnAddress: TDBGPtr): TDwarfFDE; function FindCIEForOffset(AnOffset: QWord): TDwarfCIE; function GetRow(TargetInfo: TTargetDescriptor; AnAddress: TDBGPtr; out CIE: TDwarfCIE; out Row: TDwarfCallFrameInformationRow): Boolean; class function TryObtainNextCallFrame( CurrentCallStackEntry: TDbgCallstackEntry; CIE: TDwarfCIE; Size, NextIdx: Integer; Thread: TDbgThread; Row: TDwarfCallFrameInformationRow; Process: TDbgProcess; out NewCallStackEntry: TDbgCallstackEntry): Boolean; end; implementation var FPDBG_DWARF_CFI_WARNINGS: PLazLoggerLogGroup; type { TCFIMap } TCFIMap = class(TMap) protected procedure ReleaseData(ADataPtr: Pointer); override; end; { TCFIMap } procedure TCFIMap.ReleaseData(ADataPtr: Pointer); begin TObject(ADataPtr^).Free; inherited ReleaseData(ADataPtr); end; { TDwarfCallFrameInformation } function TDwarfCallFrameInformation.SetCallFrameInformationRegisterCell(var InformationRow: TDwarfCallFrameInformationRow; &Register: QWord; Rule: TDwarfCallFrameInformationRegisterRule; Offset: Int64; SourceRegister: Byte): Boolean; var Row: Byte; begin Result := True; if &Register > High(Byte) then begin DebugLn(FPDBG_DWARF_CFI_WARNINGS, ['Call frame instruction register-number out of bounds']); Exit(False); end; Row := &Register; if Length(InformationRow.RegisterArray) < Row+1 then SetLength(InformationRow.RegisterArray, Row+1); InformationRow.RegisterArray[Row].RegisterRule := Rule; InformationRow.RegisterArray[Row].&Register := SourceRegister; InformationRow.RegisterArray[Row].Offset := Offset; end; function TDwarfCallFrameInformation.SetCallFrameInformationCFACell(var InformationRow: TDwarfCallFrameInformationRow; Rule: TDwarfCallFrameInformationCFARule; &Register: Byte; Offset: Int64): Boolean; begin Result := True; InformationRow.CFARule.CFARule := Rule; InformationRow.CFARule.&Register := &Register; InformationRow.CFARule.Offset := Offset; end; function TDwarfCallFrameInformation.ProcessInstructions(const CIE: TDwarfCIE; var InformationRow: TDwarfCallFrameInformationRow; const Instructions: TDwarfCallFrameInformationInstructions; const InitialAddress, SearchAddress: TDBGPtr): Boolean; var p: PByte; pw: PWord absolute p; pl: PLongWord absolute p; Instruction: Byte; CurrentLocation: TDBGPtr; uparam1, uparam2: QWord; sparam: Int64; begin if Length(Instructions) = 0 then begin Result := True; Exit; end; Result := False; p := @Instructions[0]; CurrentLocation:=InitialAddress; while p < Length(Instructions)+@Instructions[0] do begin Instruction := p^; Inc(p); case Instruction of DW_CFA_nop: begin end; DW_CFA_set_loc: begin if not cie.AddressSize in [1, 2, 4, 8] then DebugLn(FPDBG_DWARF_CFI_WARNINGS, ['Unsupported address size']) else CurrentLocation := ReadUnsignedFromExpression(p, CIE.AddressSize); end; DW_CFA_advance_loc1: begin Inc(CurrentLocation, p^); if CurrentLocation>SearchAddress then Exit(True); Inc(p); end; DW_CFA_advance_loc2: begin Inc(CurrentLocation, pw^); if CurrentLocation>SearchAddress then Exit(True); Inc(p,2); end; DW_CFA_advance_loc4: begin Inc(CurrentLocation, pl^); if CurrentLocation>SearchAddress then Exit(True); Inc(p,4); end; DW_CFA_offset_extended: begin uparam1 := ULEB128toOrdinal(p); // Register number uparam2 := ULEB128toOrdinal(p); // Factored offset if not SetCallFrameInformationRegisterCell(InformationRow, uparam1, cfiOffset, uparam2*CIE.DataAlignmentFactor, 0) then Exit; end; DW_CFA_offset_extended_sf: begin uparam1 := ULEB128toOrdinal(p); // Register number sparam := SLEB128toOrdinal(p); // Factored offset if not SetCallFrameInformationRegisterCell(InformationRow, uparam1, cfiOffset, sparam*CIE.DataAlignmentFactor, 0) then Exit; end; DW_CFA_restore: begin uparam1 := ULEB128toOrdinal(p); // Register number if not SetCallFrameInformationRegisterCell(InformationRow, uparam1, FInitialInstructionsCache.RegisterArray[uparam1].RegisterRule, FInitialInstructionsCache.RegisterArray[uparam1].Offset, FInitialInstructionsCache.RegisterArray[uparam1].&Register) then Exit; end; DW_CFA_val_offset: begin uparam1 := ULEB128toOrdinal(p); // Register number uparam2 := ULEB128toOrdinal(p); // Factored offset if not SetCallFrameInformationRegisterCell(InformationRow, uparam1, cfiValOffset, uparam2*CIE.DataAlignmentFactor, 0) then Exit; end; DW_CFA_val_offset_sf: begin uparam1 := ULEB128toOrdinal(p); // Register number sparam := SLEB128toOrdinal(p); // Factored offset if not SetCallFrameInformationRegisterCell(InformationRow, uparam1, cfiValOffset, sparam*CIE.DataAlignmentFactor, 0) then Exit; end; DW_CFA_undefined: begin uparam1 := ULEB128toOrdinal(p); // Register number if not SetCallFrameInformationRegisterCell(InformationRow, uparam1, cfiUndefined, 0, 0) then Exit; end; DW_CFA_same_value: begin uparam1 := ULEB128toOrdinal(p); // Register number if not SetCallFrameInformationRegisterCell(InformationRow, uparam1, cfiSameValue, 0, 0) then Exit; end; DW_CFA_register: begin uparam1 := ULEB128toOrdinal(p); // Register number uparam2 := ULEB128toOrdinal(p); // Register number if not SetCallFrameInformationRegisterCell(InformationRow, uparam1, cfiRegister, 0, uparam2) then Exit; end; DW_CFA_remember_state: begin SetLength(FRowStack, Length(FRowStack) + 1); FRowStack[High(FRowStack)] := CloneRow(InformationRow); end; DW_CFA_restore_state: begin InformationRow := FRowStack[High(FRowStack)]; SetLength(FRowStack, Length(FRowStack) - 1); end; DW_CFA_def_cfa: begin uparam1 := ULEB128toOrdinal(p); // Register number uparam2 := ULEB128toOrdinal(p); // Non-factored offset if not SetCallFrameInformationCFACell(InformationRow, cfaRegister, uparam1, uparam2) then Exit; end; DW_CFA_def_cfa_sf: begin uparam1 := ULEB128toOrdinal(p); // Register number sparam := SLEB128toOrdinal(p); // Factored offset if not SetCallFrameInformationCFACell(InformationRow, cfaRegister, uparam1, sparam*CIE.DataAlignmentFactor) then Exit; end; DW_CFA_def_cfa_register: begin uparam1 := ULEB128toOrdinal(p); // Register if InformationRow.CFARule.CFARule = cfaRegister then begin if not SetCallFrameInformationCFACell(InformationRow, cfaRegister, uparam1, InformationRow.CFARule.Offset) then Exit; end else DebugLn(FPDBG_DWARF_CFI_WARNINGS, ['Invalid DW_CFA_def_cfa_register rule']); end; DW_CFA_def_cfa_offset: begin uparam1 := ULEB128toOrdinal(p); // Non-factored offset if InformationRow.CFARule.CFARule = cfaRegister then begin if not SetCallFrameInformationCFACell(InformationRow, cfaRegister, InformationRow.CFARule.&Register, uparam1) then Exit; end else DebugLn(FPDBG_DWARF_CFI_WARNINGS, ['Invalid DW_CFA_def_cfa_offset rule']); end; DW_CFA_def_cfa_offset_sf: begin sparam := SLEB128toOrdinal(p); // Factored offset if InformationRow.CFARule.CFARule = cfaRegister then begin if not SetCallFrameInformationCFACell(InformationRow, cfaRegister, InformationRow.CFARule.&Register, sparam*CIE.DataAlignmentFactor) then Exit; end else DebugLn(FPDBG_DWARF_CFI_WARNINGS, ['Invalid DW_CFA_def_cfa_offset_sf rule']); end; else begin case Instruction and $c0 of DW_CFA_advance_loc: begin Inc(CurrentLocation, (Instruction and $3f)*CIE.CodeAlignmentFactor); if CurrentLocation>SearchAddress then Exit(True); end; DW_CFA_offset: begin uparam1 := Instruction and $3f; // Register number uparam2 := ULEB128toOrdinal(p); // Factored offset if not SetCallFrameInformationRegisterCell(InformationRow, uparam1, cfiOffset, uparam2*CIE.DataAlignmentFactor, 0) then Exit; end; DW_CFA_restore: begin uparam1 := Instruction and $3f; // Register number if not SetCallFrameInformationRegisterCell(InformationRow, uparam1, FInitialInstructionsCache.RegisterArray[uparam1].RegisterRule, FInitialInstructionsCache.RegisterArray[uparam1].Offset, FInitialInstructionsCache.RegisterArray[uparam1].&Register) then Exit; end else DebugLn(FPDBG_DWARF_CFI_WARNINGS, ['Unsupported call frame instruction: ', Instruction]); Exit; end; end; end; end; // This function only proceeded if we reach this point. If the handling is aborted // for any reason, the result is unreliable and can not be used. Result := True; end; procedure TDwarfCallFrameInformation.InitializeABIRules(TargetInfo: TTargetDescriptor; var Row: TDwarfCallFrameInformationRow); begin if TargetInfo.machineType=mtX86_64 then begin // According to the x86_64 ABI the CFA (call frame address) is defined as // "the value of %rsp at the call site in the previous frame" // Register 7 is %rsp SetCallFrameInformationRegisterCell(Row, 7, cfiValOffset, 0, 0); // From the x86_64 ABI: // "Registers %rbp, %rbx and %r12 through %r15 “belong” to the calling // function and the called function is required to preserve their values." // Register 3 is %rbx and 6 is %rbp SetCallFrameInformationRegisterCell(Row, 3, cfiSameValue, 0, 0); SetCallFrameInformationRegisterCell(Row, 6, cfiSameValue, 0, 0); SetCallFrameInformationRegisterCell(Row, 12, cfiSameValue, 0, 0); SetCallFrameInformationRegisterCell(Row, 13, cfiSameValue, 0, 0); SetCallFrameInformationRegisterCell(Row, 14, cfiSameValue, 0, 0); SetCallFrameInformationRegisterCell(Row, 15, cfiSameValue, 0, 0); end else if TargetInfo.machineType=mt386 then begin SetCallFrameInformationRegisterCell(Row, 4, cfiValOffset, 0, 0); // The i386 ABI is not as clear as the x86_64 ABI. These are based on // some educated guesses: SetCallFrameInformationRegisterCell(Row, 3, cfiSameValue, 0, 0); SetCallFrameInformationRegisterCell(Row, 5, cfiSameValue, 0, 0); SetCallFrameInformationRegisterCell(Row, 6, cfiSameValue, 0, 0); SetCallFrameInformationRegisterCell(Row, 7, cfiSameValue, 0, 0); end else if TargetInfo.machineType=mtAVR8 then begin // Registers r2..r17, r28, r29 are call saved SetCallFrameInformationRegisterCell(Row, 2, cfiSameValue, 0, 0); SetCallFrameInformationRegisterCell(Row, 3, cfiSameValue, 0, 0); SetCallFrameInformationRegisterCell(Row, 4, cfiSameValue, 0, 0); SetCallFrameInformationRegisterCell(Row, 5, cfiSameValue, 0, 0); SetCallFrameInformationRegisterCell(Row, 6, cfiSameValue, 0, 0); SetCallFrameInformationRegisterCell(Row, 7, cfiSameValue, 0, 0); SetCallFrameInformationRegisterCell(Row, 8, cfiSameValue, 0, 0); SetCallFrameInformationRegisterCell(Row, 9, cfiSameValue, 0, 0); SetCallFrameInformationRegisterCell(Row, 10, cfiSameValue, 0, 0); SetCallFrameInformationRegisterCell(Row, 11, cfiSameValue, 0, 0); SetCallFrameInformationRegisterCell(Row, 12, cfiSameValue, 0, 0); SetCallFrameInformationRegisterCell(Row, 13, cfiSameValue, 0, 0); SetCallFrameInformationRegisterCell(Row, 14, cfiSameValue, 0, 0); SetCallFrameInformationRegisterCell(Row, 15, cfiSameValue, 0, 0); SetCallFrameInformationRegisterCell(Row, 16, cfiSameValue, 0, 0); SetCallFrameInformationRegisterCell(Row, 17, cfiSameValue, 0, 0); end; end; function TDwarfCallFrameInformation.CloneRow(const SourceRow: TDwarfCallFrameInformationRow): TDwarfCallFrameInformationRow; begin Result := SourceRow; // Create a deep-copy of the array. Result.RegisterArray := copy(SourceRow.RegisterArray, 0, Length(SourceRow.RegisterArray)); end; constructor TDwarfCallFrameInformation.Create; begin FFDEMap := TCFIMap.Create(itu8, SizeOf(Pointer)); FCIEMap := TCFIMap.Create(itu8, SizeOf(Pointer)); end; destructor TDwarfCallFrameInformation.Destroy; begin FFDEMap.Free; FCIEMap.Free; inherited Destroy; end; procedure TDwarfCallFrameInformation.AddCIE(AnOffset: QWord; ACIE: TDwarfCIE); begin FCIEMap.Add(AnOffset, ACIE); end; procedure TDwarfCallFrameInformation.AddFDE(AFDE: TDwarfFDE); begin FFDEMap.Add(AFDE.InitialLocation, AFDE); end; function TDwarfCallFrameInformation.FindFDEForAddress(AnAddress: TDBGPtr): TDwarfFDE; var Iter: TLockedMapIterator; FDE: TDwarfFDE; begin Result := nil; Iter := TLockedMapIterator.Create(FFDEMap); try if not Iter.Locate(AnAddress) then begin if not Iter.BOM then Iter.Previous; end; if not Iter.BOM then begin // iter is at the closest defined address before AAddress FDE := TDwarfFDE(Iter.DataPtr^); if AnAddress <= FDE.InitialLocation + FDE.AddressRange then begin Result := FDE; end; end; finally Iter.Free; end; end; function TDwarfCallFrameInformation.FindCIEForOffset(AnOffset: QWord): TDwarfCIE; var Iter: TLockedMapIterator; begin Result := nil; Iter := TLockedMapIterator.Create(FCIEMap); try if not Iter.Locate(AnOffset) then begin if not Iter.BOM then Iter.Previous; end; if not Iter.BOM then begin // iter is at the closest defined address before AAddress Result := TDwarfCIE(Iter.DataPtr^); end; finally Iter.Free; end; end; function TDwarfCallFrameInformation.GetRow(TargetInfo: TTargetDescriptor; AnAddress: TDBGPtr; out CIE: TDwarfCIE; out Row: TDwarfCallFrameInformationRow): Boolean; var FDE: TDwarfFDE; begin Result := False; FRowStack := []; Row := Default(TDwarfCallFrameInformationRow); FDE := FindFDEForAddress(AnAddress); if Assigned(FDE) then begin InitializeABIRules(TargetInfo, Row); CIE := FindCIEForOffset(FDE.CIEPointer); if ProcessInstructions(CIE, Row, CIE.InitialInstructions, FDE.InitialLocation, AnAddress) then begin FInitialInstructionsCache := CloneRow(Row); Result := ProcessInstructions(CIE, Row, FDE.Instructions, FDE.InitialLocation, AnAddress); end; end; end; class function TDwarfCallFrameInformation.TryObtainNextCallFrame( CurrentCallStackEntry: TDbgCallstackEntry; CIE: TDwarfCIE; Size, NextIdx: Integer; Thread: TDbgThread; Row: TDwarfCallFrameInformationRow; Process: TDbgProcess; out NewCallStackEntry: TDbgCallstackEntry): Boolean; function ProcessCFIColumn(Row: TDwarfCallFrameInformationRow; Column: Byte; CFA: QWord; AddressSize: Integer; Entry: TDbgCallstackEntry; out Value: TDbgPtr): Boolean; var Rule: TDwarfCallFrameInformationRule; Reg: TDbgRegisterValue; begin Result := True; Value := 0; Rule := Row.RegisterArray[Column]; case Rule.RegisterRule of cfiUndefined: begin Result := False; end; cfiSameValue: begin Reg := CurrentCallStackEntry.RegisterValueList.FindRegisterByDwarfIndex(Column); if Assigned(Reg) then Value := Reg.NumValue else Result := False; end; cfiOffset: begin {$PUSH}{$R-}{$Q-} Process.ReadData(CFA+TDBGPtr(Rule.Offset), AddressSize, Value); {$POP} end; cfiValOffset: begin {$PUSH}{$R-}{$Q-} Value := CFA+TDBGPtr(Rule.Offset); {$POP} end; cfiRegister: begin Reg := CurrentCallStackEntry.RegisterValueList.FindRegisterByDwarfIndex(Rule.&Register); if Assigned(Reg) then Value := Reg.NumValue else Result := False; end else begin DebugLn(FPDBG_DWARF_CFI_WARNINGS, 'Encountered unsupported CFI registerrule.'); Result := False; end; end; // case end; var Rule: TDwarfCallFrameInformationRule; Reg: TDbgRegisterValue; i: Integer; ReturnAddress, Value: TDbgPtr; FrameBase: TDBGPtr; RegName: String; begin Result := False; NewCallStackEntry := nil; // Get CFA (framebase) Rule := Row.CFARule; case Rule.CFARule of cfaRegister: begin Reg := CurrentCallStackEntry.RegisterValueList.FindRegisterByDwarfIndex(Rule.&Register); if Assigned(Reg) then begin FrameBase := Reg.NumValue; {$PUSH}{$R-}{$Q-} FrameBase := FrameBase + TDBGPtr(Rule.Offset); {$POP} end else begin DebugLn(FPDBG_DWARF_CFI_WARNINGS, 'CFI requested a register [' +IntToStr(Rule.&Register)+ '] that is not available.'); Exit; end; end; cfaExpression: begin DebugLn(FPDBG_DWARF_CFI_WARNINGS, 'CFI-expressions are not supported. Not possible to obtain the CFA.'); Exit; end; else begin DebugLn(FPDBG_DWARF_CFI_WARNINGS, 'CFI available but no rule to obtain the CFA.'); Exit; end; end; // case Result := True; // Get return ReturnAddress if not ProcessCFIColumn(Row, CIE.ReturnAddressRegister, FrameBase, Size, CurrentCallStackEntry, ReturnAddress) then // Yes, we were succesfull, but there is no return ReturnAddress, so keep // NewCallStackEntry nil begin Result := True; Exit; end; if ReturnAddress=0 then // Yes, we were succesfull, but there is no frame left, so keep // NewCallStackEntry nil begin Result := True; Exit; end; NewCallStackEntry := TDbgCallstackEntry.create(Thread, NextIdx, FrameBase, ReturnAddress); // Fill other registers for i := 0 to High(Row.RegisterArray) do begin if ProcessCFIColumn(Row, i, FrameBase, Size, CurrentCallStackEntry, Value) then begin Reg := CurrentCallStackEntry.RegisterValueList.FindRegisterByDwarfIndex(i); if Assigned(Reg) then RegName := Reg.Name else RegName := IntToStr(i); NewCallStackEntry.RegisterValueList.DbgRegisterAutoCreate[RegName].SetValue(Value, IntToStr(Value),Size, i); end; end; end; { TDwarfFDE } constructor TDwarfFDE.Create(ACIEPointer: QWord; AnInitialLocation, ASegmentSelector: TDBGPtr; AnAddressRange: QWord); begin FCIEPointer := ACIEPointer; FInitialLocation := AnInitialLocation; FSegmentSelector := ASegmentSelector; FAddressRange := AnAddressRange; end; { TDwarfCIE } constructor TDwarfCIE.Create(AVersion: Byte; AnAugmentation: string); begin FVersion := AVersion; FAugmentation := AnAugmentation; end; initialization FPDBG_DWARF_CFI_WARNINGS := DebugLogger.FindOrRegisterLogGroup('FPDBG_DWARF_CFI_WARNINGS' {$IFDEF FPDBG_DWARF_CFI_WARNINGS} , True {$ENDIF} ); end.