FpDebug: fix for Line-To-AddressMap. Lines for one unit(file) can be split can be split across several CU (generics). Create global line maps. TODO: a single file can also occur in several libraries (separate TFpDwarfInfo) with different line ranges in use.

This commit is contained in:
Martin 2024-07-07 13:37:45 +02:00
parent 642cd1e58a
commit 68b94f6b72
3 changed files with 82 additions and 103 deletions

View File

@ -3670,7 +3670,7 @@ begin
begin begin
CU := TDbgDwarfSymbolBase(sym).CompilationUnit; CU := TDbgDwarfSymbolBase(sym).CompilationUnit;
Result := False; Result := False;
CU.GetLineAddresses(sym.FileName, sym.Line, a); CU.Owner.GetLineAddresses(sym.FileName, sym.Line, a);
for b in a do begin for b in a do begin
Result := b = AnAddr; Result := b = AnAddr;
if Result then break; if Result then break;

View File

@ -44,7 +44,7 @@ unit FpDbgDwarfDataClasses;
interface interface
uses uses
Classes, Types, SysUtils, Contnrs, Math, Classes, Types, SysUtils, Contnrs, Math, fgl,
// LazUtils // LazUtils
Maps, LazClasses, LazFileUtils, LazUTF8, LazCollections, Maps, LazClasses, LazFileUtils, LazUTF8, LazCollections,
{$ifdef FORCE_LAZLOGGER_DUMMY} LazLoggerDummy {$else} LazLoggerBase {$endif}, {$ifdef FORCE_LAZLOGGER_DUMMY} LazLoggerDummy {$else} LazLoggerBase {$endif},
@ -498,7 +498,7 @@ type
AFindSibling: TGetLineAddrFindSibling = fsNone; AFindSibling: TGetLineAddrFindSibling = fsNone;
AFoundLine: PInteger = nil; AFoundLine: PInteger = nil;
AMaxSiblingDistance: integer = 0; AMaxSiblingDistance: integer = 0;
ACU: TDwarfCompilationUnit = nil ADbgInfo: TFpDwarfInfo = nil
): Boolean; inline; ): Boolean; inline;
// NoData: only return True/False, but nothing in AResultList // NoData: only return True/False, but nothing in AResultList
procedure Compress; procedure Compress;
@ -698,8 +698,6 @@ type
{$IFDEF DwarfTestAccess} private {$ENDIF} {$IFDEF DwarfTestAccess} private {$ENDIF}
FInitialStateMachine: TDwarfLineInfoStateMachine; FInitialStateMachine: TDwarfLineInfoStateMachine;
FLineNumberMap: TStringListUTF8Fast;
FAddressMap: TMap; // Holds a key for each DW_TAG_subprogram / TFpSymbolDwarfDataProc, stores TDwarfAddressInfo FAddressMap: TMap; // Holds a key for each DW_TAG_subprogram / TFpSymbolDwarfDataProc, stores TDwarfAddressInfo
FAddressMapBuild: Boolean; FAddressMapBuild: Boolean;
@ -744,10 +742,6 @@ type
procedure WaitForScopeScan; inline; // MUST be called, before accessing the CU procedure WaitForScopeScan; inline; // MUST be called, before accessing the CU
procedure WaitForComputeHashes; inline; procedure WaitForComputeHashes; inline;
function GetDefinition(AAbbrevPtr: Pointer; out ADefinition: TDwarfAbbrev): Boolean; inline; function GetDefinition(AAbbrevPtr: Pointer; out ADefinition: TDwarfAbbrev): Boolean; inline;
function GetLineAddressMap(const AFileName: String): PDWarfLineMap;
function GetLineAddresses(const AFileName: String; ALine: Cardinal; var AResultList: TDBGPtrArray;
AFindSibling: TGetLineAddrFindSibling = fsNone; AFoundLine: PInteger = nil; AFoundFilename: PBoolean = nil;
AMaxSiblingDistance: integer = 0): boolean;
procedure BuildLineInfo(AAddressInfo: PDwarfAddressInfo; ADoAll: Boolean); procedure BuildLineInfo(AAddressInfo: PDwarfAddressInfo; ADoAll: Boolean);
// On Darwin it could be that the debug-information is not included into the executable by the linker. // On Darwin it could be that the debug-information is not included into the executable by the linker.
// This function is to map object-file addresses into the corresponding addresses in the executable. // This function is to map object-file addresses into the corresponding addresses in the executable.
@ -797,7 +791,9 @@ type
property AbbrevList: TDwarfAbbrevList read FAbbrevList; property AbbrevList: TDwarfAbbrevList read FAbbrevList;
property KnownNameHashes: PKnownNameHashesArray read GetKnownNameHashes; // Only for TOP-LEVEL entries property KnownNameHashes: PKnownNameHashesArray read GetKnownNameHashes; // Only for TOP-LEVEL entries
end; end;
TLineNumberFileMap = specialize TFPGMap<AnsiString, PDWarfLineMap>;
{ TFpDwarfInfo } { TFpDwarfInfo }
TFpDwarfInfo = class(TDbgInfo) TFpDwarfInfo = class(TDbgInfo)
@ -807,6 +803,8 @@ type
FWorkQueue: TFpGlobalThreadWorkerQueue; FWorkQueue: TFpGlobalThreadWorkerQueue;
FFiles: array of TDwarfDebugFile; FFiles: array of TDwarfDebugFile;
private private
FLineNumberMap: TLineNumberFileMap;
FLineNumberMapDone: Boolean;
FImageBase: QWord; FImageBase: QWord;
FRelocationOffset: QWord; FRelocationOffset: QWord;
function GetCompilationUnit(AIndex: Integer): TDwarfCompilationUnit; inline; function GetCompilationUnit(AIndex: Integer): TDwarfCompilationUnit; inline;
@ -3586,7 +3584,7 @@ end;
function TDWarfLineMap.GetAddressesForLine(ALine: Cardinal; var AResultList: TDBGPtrArray; function TDWarfLineMap.GetAddressesForLine(ALine: Cardinal; var AResultList: TDBGPtrArray;
NoData: Boolean; AFindSibling: TGetLineAddrFindSibling; AFoundLine: PInteger; NoData: Boolean; AFindSibling: TGetLineAddrFindSibling; AFoundLine: PInteger;
AMaxSiblingDistance: integer; ACU: TDwarfCompilationUnit): Boolean; AMaxSiblingDistance: integer; ADbgInfo: TFpDwarfInfo): Boolean;
var var
idx: integer; idx: integer;
offset, Addr1, Addr2: TDBGPtr; offset, Addr1, Addr2: TDBGPtr;
@ -3698,8 +3696,8 @@ begin
((AFindSibling = fsNextFuncLazy) and (ln - ALine > 1)) ((AFindSibling = fsNextFuncLazy) and (ln - ALine > 1))
then begin then begin
// check same function // check same function
if ACU = nil then exit; if ADbgInfo = nil then exit;
if not ACU.GetProcStartEnd(Addresses[i], Addr1, Addr2) then exit; if not ADbgInfo.FindProcStartEndPC(Addresses[i], Addr1, Addr2) then exit;
if GetAddressesForLine(ALine, TmpResList, False, fsBefore) then begin if GetAddressesForLine(ALine, TmpResList, False, fsBefore) then begin
if (Length(TmpResList) = 0) or (TmpResList[0] < Addr1) or (TmpResList[0] > Addr2) then if (Length(TmpResList) = 0) or (TmpResList[0] < Addr1) or (TmpResList[0] > Addr2) then
exit; exit;
@ -3759,6 +3757,7 @@ var
p: PDbgImageSection; p: PDbgImageSection;
i: Integer; i: Integer;
begin begin
FLineNumberMap := TLineNumberFileMap.Create;
FWorkQueue := FpDbgGlobalWorkerQueue; FWorkQueue := FpDbgGlobalWorkerQueue;
FWorkQueue.AddRef; FWorkQueue.AddRef;
@ -3787,6 +3786,17 @@ begin
end; end;
destructor TFpDwarfInfo.Destroy; destructor TFpDwarfInfo.Destroy;
procedure FreeLineNumberMap;
var
n: Integer;
begin
if FLineNumberMap = nil then
exit;
for n := 0 to FLineNumberMap.Count - 1 do
Dispose(FLineNumberMap.Data[n]);
FreeAndNil(FLineNumberMap);
end;
var var
n: integer; n: integer;
begin begin
@ -3795,6 +3805,7 @@ begin
TObject(FCompilationUnits[n]).Free; TObject(FCompilationUnits[n]).Free;
FreeAndNil(FCompilationUnits); FreeAndNil(FCompilationUnits);
FreeAndNil(FCallFrameInformationList); FreeAndNil(FCallFrameInformationList);
FreeLineNumberMap;
inherited Destroy; inherited Destroy;
end; end;
@ -4032,35 +4043,67 @@ function TFpDwarfInfo.GetLineAddresses(const AFileName: String; ALine: Cardinal;
var AResultList: TDBGPtrArray; AFindSibling: TGetLineAddrFindSibling; AFoundLine: PInteger; var AResultList: TDBGPtrArray; AFindSibling: TGetLineAddrFindSibling; AFoundLine: PInteger;
AFoundFilename: PBoolean; AMaxSiblingDistance: integer): Boolean; AFoundFilename: PBoolean; AMaxSiblingDistance: integer): Boolean;
var var
n: Integer; Map: PDWarfLineMap;
CU: TDwarfCompilationUnit;
begin begin
Result := False; Result := False;
if AFoundLine <> nil then if AFoundLine <> nil then
AFoundLine^ := -1; AFoundLine^ := -1;
for n := 0 to FCompilationUnits.Count - 1 do
begin Map := GetLineAddressMap(AFileName);
CU := TDwarfCompilationUnit(FCompilationUnits[n]); if Map = nil then
CU.WaitForScopeScan; exit;
Result := CU.GetLineAddresses(AFileName, ALine, AResultList, AFindSibling, AFoundLine, AFoundFilename, AMaxSiblingDistance)
or Result; if AFoundFilename <> nil then
end; AFoundFilename^ := True;
Result := Map^.GetAddressesForLine(ALine, AResultList, False, AFindSibling, AFoundLine, AMaxSiblingDistance, Self);
end; end;
function TFpDwarfInfo.GetLineAddressMap(const AFileName: String): PDWarfLineMap; function TFpDwarfInfo.GetLineAddressMap(const AFileName: String): PDWarfLineMap;
function FindIndex: Integer;
var
Name: String;
begin
// try fullname first
Result := FLineNumberMap.IndexOf(AFileName);
if Result <> -1 then Exit;
Name := ExtractFileName(AFileName);
Result := FLineNumberMap.IndexOf(Name);
if Result <> -1 then Exit;
for Result := 0 to FLineNumberMap.Count - 1 do
if AnsiCompareText(Name, ExtractFileName(FLineNumberMap.Keys[Result])) = 0 then
Exit;
Result := -1;
end;
var var
n: Integer; n, idx: Integer;
CU: TDwarfCompilationUnit; CU: TDwarfCompilationUnit;
begin begin
// TODO: Deal with line info split on 2 compilation units?
for n := 0 to FCompilationUnits.Count - 1 do
begin
CU := TDwarfCompilationUnit(FCompilationUnits[n]);
CU.WaitForScopeScan;
Result := CU.GetLineAddressMap(AFileName);
if Result <> nil then Exit;
end;
Result := nil; Result := nil;
if FLineNumberMap = nil then Exit;
if not FLineNumberMapDone then begin
// make sure all filenames are there
for n := 0 to FCompilationUnits.Count - 1 do
begin
CU := TDwarfCompilationUnit(FCompilationUnits[n]);
CU.WaitForScopeScan;
if CU.Valid then
CU.BuildLineInfo(nil, True);
end;
for n := 0 to FLineNumberMap.Count - 1 do
FLineNumberMap.Data[n]^.Compress;
FLineNumberMapDone := True;
end;
idx := FindIndex;
if idx = -1 then Exit;
Result := FLineNumberMap.Data[idx];
end; end;
procedure TFpDwarfInfo.LoadCallFrameInstructions; procedure TFpDwarfInfo.LoadCallFrameInstructions;
@ -4849,15 +4892,15 @@ begin
Line := FLineInfo.StateMachine.Line; Line := FLineInfo.StateMachine.Line;
if (idx < 0) or (CurrentFileName <> FLineInfo.StateMachine.FileName) then begin if (idx < 0) or (CurrentFileName <> FLineInfo.StateMachine.FileName) then begin
idx := FLineNumberMap.IndexOf(FLineInfo.StateMachine.FileName); idx := FOwner.FLineNumberMap.IndexOf(FLineInfo.StateMachine.FileName);
if idx = -1 if idx = -1
then begin then begin
LineMap := New(PDWarfLineMap); LineMap := New(PDWarfLineMap);
LineMap^.Init; LineMap^.Init;
FLineNumberMap.AddObject(FLineInfo.StateMachine.FileName, TObject(LineMap)); FOwner.FLineNumberMap.Add(FLineInfo.StateMachine.FileName, LineMap);
end end
else begin else begin
LineMap := PDWarfLineMap(FLineNumberMap.Objects[idx]); LineMap := FOwner.FLineNumberMap.Data[idx];
end; end;
CurrentFileName := FLineInfo.StateMachine.FileName; CurrentFileName := FLineInfo.StateMachine.FileName;
end; end;
@ -4895,8 +4938,9 @@ begin
Iter.Free; Iter.Free;
for Idx := 0 to FLineNumberMap.Count - 1 do if not ADoAll then
PDWarfLineMap(FLineNumberMap.Objects[idx])^.Compress; for Idx := 0 to FOwner.FLineNumberMap.Count - 1 do
FOwner.FLineNumberMap.Data[idx]^.Compress;
end; end;
function TDwarfCompilationUnit.GetAddressMap: TMap; function TDwarfCompilationUnit.GetAddressMap: TMap;
@ -5212,9 +5256,6 @@ begin
// use internally 64 bit target pointer // use internally 64 bit target pointer
FAddressMap := TMap.Create(itu8, SizeOf(TDwarfAddressInfo)); FAddressMap := TMap.Create(itu8, SizeOf(TDwarfAddressInfo));
FLineNumberMap := TStringListUTF8Fast.Create;
FLineNumberMap.Sorted := True;
FLineNumberMap.Duplicates := dupError;
FFirstScope.Init(nil); // invalid FFirstScope.Init(nil); // invalid
@ -5299,17 +5340,6 @@ begin
end; end;
destructor TDwarfCompilationUnit.Destroy; destructor TDwarfCompilationUnit.Destroy;
procedure FreeLineNumberMap;
var
n: Integer;
begin
if FLineNumberMap = nil then
exit;
for n := 0 to FLineNumberMap.Count - 1 do
Dispose(PDWarfLineMap(FLineNumberMap.Objects[n]));
FreeAndNil(FLineNumberMap);
end;
begin begin
FOwner.WorkQueue.RemoveItem(FComputeNameHashesWorker); FOwner.WorkQueue.RemoveItem(FComputeNameHashesWorker);
FOwner.WorkQueue.RemoveItem(FScanAllWorker); FOwner.WorkQueue.RemoveItem(FScanAllWorker);
@ -5318,7 +5348,6 @@ begin
FreeAndNil(FAbbrevList); FreeAndNil(FAbbrevList);
FreeAndNil(FAddressMap); FreeAndNil(FAddressMap);
FreeLineNumberMap;
FreeAndNil(FInitialStateMachine); FreeAndNil(FInitialStateMachine);
FreeAndNil(FLineInfo.StateMachines); FreeAndNil(FLineInfo.StateMachines);
FreeAndNil(FLineInfo.StateMachine); FreeAndNil(FLineInfo.StateMachine);
@ -5328,56 +5357,6 @@ begin
inherited Destroy; inherited Destroy;
end; end;
function TDwarfCompilationUnit.GetLineAddressMap(const AFileName: String): PDWarfLineMap;
function FindIndex: Integer;
var
Name: String;
begin
// try fullname first
Result := FLineNumberMap.IndexOf(AFileName);
if Result <> -1 then Exit;
Name := ExtractFileName(AFileName);
Result := FLineNumberMap.IndexOf(Name);
if Result <> -1 then Exit;
for Result := 0 to FLineNumberMap.Count - 1 do
if AnsiCompareText(Name, ExtractFileName(FLineNumberMap[Result])) = 0 then
Exit;
Result := -1;
end;
var
idx: Integer;
begin
Result := nil;
if not Valid then Exit;
// make sure all filenames are there
BuildLineInfo(nil, True);
idx := FindIndex;
if idx = -1 then Exit;
Result := PDWarfLineMap(FLineNumberMap.Objects[idx]);
end;
function TDwarfCompilationUnit.GetLineAddresses(const AFileName: String; ALine: Cardinal;
var AResultList: TDBGPtrArray; AFindSibling: TGetLineAddrFindSibling; AFoundLine: PInteger;
AFoundFilename: PBoolean; AMaxSiblingDistance: integer): boolean;
var
Map: PDWarfLineMap;
begin
Result := False;
Map := GetLineAddressMap(AFileName);
if Map = nil then
exit;
if AFoundFilename <> nil then
AFoundFilename^ := True;
Result := Map^.GetAddressesForLine(ALine, AResultList, False, AFindSibling, AFoundLine, AMaxSiblingDistance, Self);
end;
function TDwarfCompilationUnit.InitLocateAttributeList(AEntry: Pointer; function TDwarfCompilationUnit.InitLocateAttributeList(AEntry: Pointer;
var AList: TAttribPointerList): Boolean; var AList: TAttribPointerList): Boolean;
var var

View File

@ -2380,7 +2380,7 @@ begin
AnAddresses := nil; AnAddresses := nil;
if if
//(FndLine = HelpSymbol.Line) and //(FndLine = HelpSymbol.Line) and
HelpSymbol.CompilationUnit.GetLineAddresses(HelpSymbol.FileName, HelpSymbol.Line, AnAddresses, fsBefore, @FndLine) and HelpSymbol.CompilationUnit.Owner.GetLineAddresses(HelpSymbol.FileName, HelpSymbol.Line, AnAddresses, fsBefore, @FndLine) and
(Length(AnAddresses) > 1) // may be an internal finally on the begin/end line, sharing a line number (Length(AnAddresses) > 1) // may be an internal finally on the begin/end line, sharing a line number
then begin then begin
for i := 0 to Length(AnAddresses) - 1 do for i := 0 to Length(AnAddresses) - 1 do
@ -2401,7 +2401,7 @@ begin
end; end;
AnAddresses := nil; AnAddresses := nil;
if HelpSymbol.CompilationUnit.GetLineAddresses(HelpSymbol.FileName, HelpSymbol.Line-1, AnAddresses, fsBefore) if HelpSymbol.CompilationUnit.Owner.GetLineAddresses(HelpSymbol.FileName, HelpSymbol.Line-1, AnAddresses, fsBefore)
then begin then begin
TFpSymbol(HelpSymbol2) := DbgInfo.FindProcSymbol(AnAddresses[0]); TFpSymbol(HelpSymbol2) := DbgInfo.FindProcSymbol(AnAddresses[0]);
if (HelpSymbol2 <> nil) and (HelpSymbol2.CompilationUnit = CompilationUnit) and if (HelpSymbol2 <> nil) and (HelpSymbol2.CompilationUnit = CompilationUnit) and