From 2acd13651847c08434e5f7267439a03317eb282e Mon Sep 17 00:00:00 2001 From: Martin Date: Wed, 29 Nov 2023 13:25:29 +0100 Subject: [PATCH] FpDebug: Implement location-lists (Dwarf 2/3) --- components/fpdebug/fpdbgclasses.pp | 12 +-- components/fpdebug/fpdbgdwarf.pas | 104 +++++++++++++++++-- components/fpdebug/fpdbgdwarfdataclasses.pas | 5 +- components/fpdebug/fperrormessages.pas | 3 + components/fpdebug/fppascalbuilder.pas | 2 +- 5 files changed, 110 insertions(+), 16 deletions(-) diff --git a/components/fpdebug/fpdbgclasses.pp b/components/fpdebug/fpdbgclasses.pp index c6ca7e7ea0..d6e8ea5020 100644 --- a/components/fpdebug/fpdbgclasses.pp +++ b/components/fpdebug/fpdbgclasses.pp @@ -814,7 +814,7 @@ type function FindProcStartEndPC(const AAdress: TDbgPtr; out AStartPC, AEndPC: TDBGPtr): boolean; function GetLineAddresses(AFileName: String; ALine: Cardinal; var AResultList: TDBGPtrArray; ASymInstance: TDbgInstance = nil): Boolean; - function ContextFromProc(AThreadId, AStackFrame: Integer; AProcSym: TFpSymbol): TFpDbgLocationContext; inline; deprecated 'use TFpDbgSimpleLocationContext.Create'; + //function ContextFromProc(AThreadId, AStackFrame: Integer; AProcSym: TFpSymbol): TFpDbgLocationContext; inline; deprecated 'use TFpDbgSimpleLocationContext.Create'; function GetLib(const AHandle: THandle; out ALib: TDbgLibrary): Boolean; property LibMap: TLibraryMap read FLibMap; property LastLibrariesLoaded: TDbgLibraryArr read GetLastLibrariesLoaded; @@ -2382,11 +2382,11 @@ begin end; end; -function TDbgProcess.ContextFromProc(AThreadId, AStackFrame: Integer; - AProcSym: TFpSymbol): TFpDbgLocationContext; -begin - Result := TFpDbgSimpleLocationContext.Create(MemManager, LocToAddrOrNil(AProcSym.Address), DBGPTRSIZE[Mode], AThreadId, AStackFrame); -end; +//function TDbgProcess.ContextFromProc(AThreadId, AStackFrame: Integer; +// AProcSym: TFpSymbol): TFpDbgLocationContext; +//begin +// Result := TFpDbgSimpleLocationContext.Create(MemManager, LocToAddrOrNil(AProcSym.Address), DBGPTRSIZE[Mode], AThreadId, AStackFrame); +//end; function TDbgProcess.GetLib(const AHandle: THandle; out ALib: TDbgLibrary): Boolean; begin diff --git a/components/fpdebug/fpdbgdwarf.pas b/components/fpdebug/fpdbgdwarf.pas index 0c83118b6c..fcc0fd3c01 100644 --- a/components/fpdebug/fpdbgdwarf.pas +++ b/components/fpdebug/fpdbgdwarf.pas @@ -580,6 +580,8 @@ type AValueObj: TFpValueDwarf; out AValue: Int64; AReadState: PFpDwarfAtEntryDataReadState = nil; ADataSymbol: PFpSymbolDwarfData = nil): Boolean; + function LocationExprFromLocationList(const AnAttribData: TDwarfAttribData; AValueObj: TFpValueDwarf; + out AValue: TByteDynArray): boolean; function LocationFromAttrData(const AnAttribData: TDwarfAttribData; AValueObj: TFpValueDwarf; var AnAddress: TFpDbgMemLocation; // kept, if tag does not exist AnInitLocParserData: PInitLocParserData = nil; @@ -4497,6 +4499,81 @@ begin AReadState^ := rfError; end; +function TFpSymbolDwarf.LocationExprFromLocationList( + const AnAttribData: TDwarfAttribData; AValueObj: TFpValueDwarf; out + AValue: TByteDynArray): boolean; +var + LocSect: TDwarfSectionInfo; + ValOffs: QWord; + LocList, LocListEnd: Pointer; + Sz, Len: Integer; + BaseAddr, PC: TDBGPtr; + LowBnd, HighBnd: TDBGPtr; +begin + Result := False; + LocSect := CompilationUnit.DebugFile^.Sections[dsLoc]; + if (LocSect.RawData = nil) then + exit; + + if InformationEntry.ReadValue(AnAttribData, ValOffs) then begin + Sz := AValueObj.Context.SizeOfAddress; + if ValOffs > LocSect.Size - 2 * Sz - 2 // need at least 1 pair of bounds an a 2 byte len + then + exit; + LocList := LocSect.RawData + ValOffs; + LocListEnd := LocList + LocSect.Size - 2 * Sz - 2; + + BaseAddr := 0; + if CompilationUnit.Version > 2 then + BaseAddr := CompilationUnit.BaseAddress; + PC := AValueObj.Context.Address; + + while LocList < LocListEnd do begin + case sz of + 4: begin + LowBnd := PDWord(LocList)^; + HighBnd := PDWord(LocList)[1]; + LocList := LocList + 2 * sz; + if LowBnd = high(DWORD) then begin + BaseAddr := HighBnd; + continue; + end; + end; + 8: begin + LowBnd := PQWord(LocList)^; + HighBnd := PQWord(LocList)[1]; + LocList := LocList + 2 * sz; + if LowBnd = high(QWORD) then begin + BaseAddr := HighBnd; + continue; + end; + end; + end; + + if (LowBnd = 0) and (HighBnd = 0) then + exit; // not found + + Len := PWord(LocList)^; + + LowBnd := LowBnd + BaseAddr; + HighBnd := HighBnd + BaseAddr; + + if (PC >= LowBnd) and (PC < HighBnd) then begin + // found + SetLength(AValue, Len); + if Len > 0 then + move((LocList+2)^, AValue[0], Len); + Result := True; + exit; + end; + + LocList := LocList + 2 * Len; + end; + + SetLastError(AValueObj, CreateError(fpErrAnyError)); + end; +end; + function TFpSymbolDwarf.LocationFromAttrData( const AnAttribData: TDwarfAttribData; AValueObj: TFpValueDwarf; var AnAddress: TFpDbgMemLocation; AnInitLocParserData: PInitLocParserData; @@ -4504,19 +4581,32 @@ function TFpSymbolDwarf.LocationFromAttrData( var Val: TByteDynArray; LocationParser: TDwarfLocationExpression; + AForm: Cardinal; begin //debugln(FPDBG_DWARF_VERBOSE, ['TDbgDwarfIdentifier.LocationFromAttrData', ClassName, ' ',Name, ' ', DwarfAttributeToString(ATag)]); Result := False; AnAddress := InvalidLoc; - //TODO: avoid copying data - // DW_AT_data_member_location in members [ block or const] - // DW_AT_location [block or reference] todo: const - if not InformationEntry.ReadValue(AnAttribData, Val) then begin - DebugLn(FPDBG_DWARF_VERBOSE, ['LocationFromAttrData: failed to read DW_AT_location']); - SetLastError(AValueObj, CreateError(fpErrAnyError)); - exit; + AForm := AnAttribData.InformationEntry.AttribForm[AnAttribData.Idx]; + if (AForm = DW_FORM_data4) or (AForm = DW_FORM_data8) then begin + // location list + if not LocationExprFromLocationList(AnAttribData, AValueObj, Val) then begin + DebugLn(FPDBG_DWARF_VERBOSE, ['LocationFromAttrData: failed to read DW_AT_location from loc-list']); + if not IsError(AValueObj.LastError) then + SetLastError(AValueObj, CreateError(fpErrAnyError)); + exit; + end; + end + else begin + //TODO: avoid copying data + // DW_AT_data_member_location in members [ block or const] + // DW_AT_location [block or reference] todo: const + if not InformationEntry.ReadValue(AnAttribData, Val) then begin + DebugLn(FPDBG_DWARF_VERBOSE, ['LocationFromAttrData: failed to read DW_AT_location']); + SetLastError(AValueObj, CreateError(fpErrAnyError)); + exit; + end; end; if Length(Val) = 0 then begin diff --git a/components/fpdebug/fpdbgdwarfdataclasses.pas b/components/fpdebug/fpdbgdwarfdataclasses.pas index 5c3008d128..b62fd27703 100644 --- a/components/fpdebug/fpdbgdwarfdataclasses.pas +++ b/components/fpdebug/fpdbgdwarfdataclasses.pas @@ -690,8 +690,8 @@ type FAddressMap: TMap; // Holds a key for each DW_TAG_subprogram / TFpSymbolDwarfDataProc, stores TDwarfAddressInfo FAddressMapBuild: Boolean; - FMinPC: QWord; // the min and max PC value found in this unit. - FMaxPC: QWord; // + FMinPC: TDBGPtr; // the min and max PC value found in this unit. + FMaxPC: TDBGPtr; // FFirstScope: TDwarfScopeInfo; FScopeList: TDwarfScopeList; FCompUnitScope: TDwarfScopeInfo; @@ -755,6 +755,7 @@ type property UnitName: String read GetUnitName; property IdentifierCase: Integer read FIdentifierCase; property Producer: String read FProducer; + property BaseAddress: TDBGPtr read FMinPC; property Version: Word read FVersion; //property AbbrevOffset: QWord read FAbbrevOffset; diff --git a/components/fpdebug/fperrormessages.pas b/components/fpdebug/fperrormessages.pas index 6087ec0a8c..25c7bafce2 100644 --- a/components/fpdebug/fperrormessages.pas +++ b/components/fpdebug/fperrormessages.pas @@ -71,6 +71,7 @@ resourcestring MsgfpErrLocationParserInit = 'Internal Error: Cannot calculate location (Init).'; MsgfpErrLocationParserMinStack = 'Not enough elements on stack.'; // internally used MsgfpErrLocationParserNoAddressOnStack = 'Not an address on stack'; // internally used + MsgfpErrLocationNotInList = 'Value not available at current code-location'; // 10000 Process/Control errors MsgfpErrCreateProcess = 'Failed to start process "%1:s".%0:sError message: %2:d "%3:s".%0:s%4:s'; @@ -109,6 +110,7 @@ const fpErrLocationParserInit = TFpErrorCode(202); fpErrLocationParserMinStack = TFpErrorCode(203); fpErrLocationParserNoAddressOnStack = TFpErrorCode(204); + fpErrLocationNotInList = TFpErrorCode(210); // 500 parser fpErrPasParserEmptyExpression = TFpErrorCode(500); @@ -312,6 +314,7 @@ begin fpErrLocationParserInit: Result := MsgfpErrLocationParserInit; fpErrLocationParserMinStack: Result := MsgfpErrLocationParserMinStack; fpErrLocationParserNoAddressOnStack: Result := MsgfpErrLocationParserNoAddressOnStack; + fpErrLocationNotInList: Result := MsgfpErrLocationNotInList; fpErrCreateProcess: Result := MsgfpErrCreateProcess; fpErrAttachProcess: Result := MsgfpErrAttachProcess; diff --git a/components/fpdebug/fppascalbuilder.pas b/components/fpdebug/fppascalbuilder.pas index 42104ba94f..6436bcb2cd 100644 --- a/components/fpdebug/fppascalbuilder.pas +++ b/components/fpdebug/fppascalbuilder.pas @@ -120,7 +120,7 @@ begin ProcVal := ProcSymbol.Value; if (ProcVal <> nil) then begin AContext := TFpDbgSimpleLocationContext.Create(AMemManager, - LocToAddrOrNil(ProcSymbol.Address), ATargetWidth div 8, AThread.ID, ADbgCallStack.Index); + LocToAddrOrNil(TargetLoc(ADbgCallStack.AnAddress)), ATargetWidth div 8, AThread.ID, ADbgCallStack.Index); if AContext <> nil then begin TFpValueDwarf(ProcVal).Context := AContext;