mirror of
https://gitlab.com/freepascal.org/lazarus/lazarus.git
synced 2025-08-30 17:50:19 +02:00
FpDebug: refactor external debug info / Enable for Linux and Windows
(cherry picked from commit 1c87dc96eb
)
This commit is contained in:
parent
36f418134e
commit
05a6267205
@ -11,10 +11,10 @@ uses
|
|||||||
{$ifdef windows}
|
{$ifdef windows}
|
||||||
Windows, // After LCLType
|
Windows, // After LCLType
|
||||||
{$endif}
|
{$endif}
|
||||||
fgl, LazFglHash,
|
fgl, LazFglHash, LazFileUtils, LazLoggerBase,
|
||||||
fpDbgSymTable,
|
fpDbgSymTable,
|
||||||
Classes, SysUtils, DbgIntfBaseTypes, contnrs,
|
Classes, SysUtils, DbgIntfBaseTypes, contnrs,
|
||||||
FpDbgCommon;
|
FpDbgCommon, crc;
|
||||||
|
|
||||||
type
|
type
|
||||||
TDbgImageSection = record
|
TDbgImageSection = record
|
||||||
@ -105,6 +105,8 @@ type
|
|||||||
procedure SetImageBase(ABase: QWord);
|
procedure SetImageBase(ABase: QWord);
|
||||||
procedure SetImageSize(ASize: QWord);
|
procedure SetImageSize(ASize: QWord);
|
||||||
procedure AddReaderError(AnError: String);
|
procedure AddReaderError(AnError: String);
|
||||||
|
function ReadGnuDebugLinkSection(out AFileName: String; out ACrc: Cardinal): Boolean;
|
||||||
|
function LoadGnuDebugLink(ASearchPath, AFileName: String; ACrc: Cardinal): TDbgFileLoader;
|
||||||
public
|
public
|
||||||
class function isValid(ASource: TDbgFileLoader): Boolean; virtual; abstract;
|
class function isValid(ASource: TDbgFileLoader): Boolean; virtual; abstract;
|
||||||
class function UserName: AnsiString; virtual; abstract;
|
class function UserName: AnsiString; virtual; abstract;
|
||||||
@ -133,6 +135,10 @@ procedure RegisterImageReaderClass(DataSource: TDbgImageReaderClass);
|
|||||||
|
|
||||||
implementation
|
implementation
|
||||||
|
|
||||||
|
const
|
||||||
|
// Symbol-map section name
|
||||||
|
_gnu_dbg_link = '.gnu_debuglink';
|
||||||
|
|
||||||
var
|
var
|
||||||
RegisteredImageReaderClasses : TFPList;
|
RegisteredImageReaderClasses : TFPList;
|
||||||
|
|
||||||
@ -404,6 +410,73 @@ begin
|
|||||||
FReaderErrors := FReaderErrors + AnError;
|
FReaderErrors := FReaderErrors + AnError;
|
||||||
end;
|
end;
|
||||||
|
|
||||||
|
function TDbgImageReader.ReadGnuDebugLinkSection(out AFileName: String; out
|
||||||
|
ACrc: Cardinal): Boolean;
|
||||||
|
var
|
||||||
|
p: PDbgImageSectionEx;
|
||||||
|
i: Integer;
|
||||||
|
begin
|
||||||
|
p := PDbgImageSectionEx(Section[_gnu_dbg_link]);
|
||||||
|
Result := p <> nil;
|
||||||
|
if Result then
|
||||||
|
begin
|
||||||
|
i := IndexByte(p^.Sect.RawData^, p^.Sect.Size-4, 0);
|
||||||
|
Result := i > 0;
|
||||||
|
if Result then
|
||||||
|
begin
|
||||||
|
SetLength(AFileName, i);
|
||||||
|
move(PDbgImageSectionEx(p)^.Sect.RawData^, AFileName[1], i);
|
||||||
|
|
||||||
|
i := align(i+1, 4);
|
||||||
|
Result := (i+4) <= p^.Sect.Size;
|
||||||
|
if Result then
|
||||||
|
move((p^.Sect.RawData+i)^, ACrc, 4);
|
||||||
|
end;
|
||||||
|
end;
|
||||||
|
end;
|
||||||
|
|
||||||
|
function TDbgImageReader.LoadGnuDebugLink(ASearchPath, AFileName: String;
|
||||||
|
ACrc: Cardinal): TDbgFileLoader;
|
||||||
|
|
||||||
|
function LoadFile(AFullName: String): TDbgFileLoader;
|
||||||
|
var
|
||||||
|
i, j: Int64;
|
||||||
|
c: Cardinal;
|
||||||
|
mem: Pointer;
|
||||||
|
begin
|
||||||
|
Result := TDbgFileLoader.Create(AFullName);
|
||||||
|
|
||||||
|
i := FileSizeUtf8(AFullName) - 4096;
|
||||||
|
j := 0;
|
||||||
|
c:=0;
|
||||||
|
while j < i do begin
|
||||||
|
Result.LoadMemory(j, 4096, mem);
|
||||||
|
c:=Crc32(c, mem, 4096);
|
||||||
|
Result.UnloadMemory(mem);
|
||||||
|
inc(j, 4096)
|
||||||
|
end;
|
||||||
|
i := i - j + 4096;
|
||||||
|
Result.LoadMemory(j, i, mem);
|
||||||
|
c:=Crc32(c, mem, i);
|
||||||
|
Result.UnloadMemory(mem);
|
||||||
|
|
||||||
|
DebugLn(c <> ACrc, ['Invalid CRC for ext debug info: ', AFullName]);
|
||||||
|
if c <> ACrc then
|
||||||
|
FreeAndNil(Result);
|
||||||
|
end;
|
||||||
|
|
||||||
|
begin
|
||||||
|
Result := nil;
|
||||||
|
|
||||||
|
if FileExists(AppendPathDelim(ASearchPath) + AFileName) then
|
||||||
|
Result := LoadFile(AppendPathDelim(ASearchPath) + AFileName);
|
||||||
|
|
||||||
|
if (Result = nil) and
|
||||||
|
FileExists(AppendPathDelim(ASearchPath) + AppendPathDelim('.debug') + AFileName)
|
||||||
|
then
|
||||||
|
Result := LoadFile(AppendPathDelim(ASearchPath) + AppendPathDelim('.debug') + AFileName);
|
||||||
|
end;
|
||||||
|
|
||||||
procedure TDbgImageReader.ParseSymbolTable(AFpSymbolInfo: TfpSymbolList);
|
procedure TDbgImageReader.ParseSymbolTable(AFpSymbolInfo: TfpSymbolList);
|
||||||
begin
|
begin
|
||||||
// The format of the symbol-table-section(s) can be different on each
|
// The format of the symbol-table-section(s) can be different on each
|
||||||
|
@ -73,6 +73,8 @@ type
|
|||||||
fElfFile : TElfFile;
|
fElfFile : TElfFile;
|
||||||
protected
|
protected
|
||||||
function GetSection(const AName: String): PDbgImageSection; override;
|
function GetSection(const AName: String): PDbgImageSection; override;
|
||||||
|
procedure LoadSections;
|
||||||
|
procedure ClearSections;
|
||||||
public
|
public
|
||||||
class function isValid(ASource: TDbgFileLoader): Boolean; override;
|
class function isValid(ASource: TDbgFileLoader): Boolean; override;
|
||||||
class function UserName: AnsiString; override;
|
class function UserName: AnsiString; override;
|
||||||
@ -317,6 +319,34 @@ begin
|
|||||||
FFileLoader.LoadMemory(ex^.Offs, Result^.Size, Result^.RawData);
|
FFileLoader.LoadMemory(ex^.Offs, Result^.Size, Result^.RawData);
|
||||||
end;
|
end;
|
||||||
|
|
||||||
|
procedure TElfDbgSource.LoadSections;
|
||||||
|
var
|
||||||
|
p: PDbgImageSectionEx;
|
||||||
|
idx: integer;
|
||||||
|
i: Integer;
|
||||||
|
fs: TElfSection;
|
||||||
|
begin
|
||||||
|
for i := 0 to fElfFile.seccount - 1 do begin
|
||||||
|
fs := fElfFile.sections[i];
|
||||||
|
idx := FSections.AddObject(fs.name, nil);
|
||||||
|
New(p);
|
||||||
|
P^.Offs := fs.FileOfs;
|
||||||
|
p^.Sect.Size := fs.Size;
|
||||||
|
p^.Sect.VirtualAddress := 0; // Todo? fs.Address - ImageBase
|
||||||
|
p^.Loaded := False;
|
||||||
|
FSections.Objects[idx] := TObject(p);
|
||||||
|
end;
|
||||||
|
end;
|
||||||
|
|
||||||
|
procedure TElfDbgSource.ClearSections;
|
||||||
|
var
|
||||||
|
i: Integer;
|
||||||
|
begin
|
||||||
|
for i := 0 to FSections.Count-1 do
|
||||||
|
Freemem(FSections.Objects[i]);
|
||||||
|
FSections.Clear;
|
||||||
|
end;
|
||||||
|
|
||||||
class function TElfDbgSource.isValid(ASource: TDbgFileLoader): Boolean;
|
class function TElfDbgSource.isValid(ASource: TDbgFileLoader): Boolean;
|
||||||
var
|
var
|
||||||
buf : array [0..3+sizeof(Elf32_EHdr)] of byte;
|
buf : array [0..3+sizeof(Elf32_EHdr)] of byte;
|
||||||
@ -341,10 +371,9 @@ end;
|
|||||||
|
|
||||||
constructor TElfDbgSource.Create(ASource: TDbgFileLoader; ADebugMap: TObject; OwnSource: Boolean);
|
constructor TElfDbgSource.Create(ASource: TDbgFileLoader; ADebugMap: TObject; OwnSource: Boolean);
|
||||||
var
|
var
|
||||||
p: PDbgImageSectionEx;
|
DbgFileName, SourceFileName: String;
|
||||||
idx: integer;
|
crc: Cardinal;
|
||||||
i: Integer;
|
NewFileLoader: TDbgFileLoader;
|
||||||
fs: TElfSection;
|
|
||||||
begin
|
begin
|
||||||
FSections := TStringListUTF8Fast.Create;
|
FSections := TStringListUTF8Fast.Create;
|
||||||
FSections.Sorted := True;
|
FSections.Sorted := True;
|
||||||
@ -354,17 +383,30 @@ begin
|
|||||||
FFileLoader := ASource;
|
FFileLoader := ASource;
|
||||||
fOwnSource := OwnSource;
|
fOwnSource := OwnSource;
|
||||||
fElfFile := TElfFile.Create;
|
fElfFile := TElfFile.Create;
|
||||||
fElfFile.LoadFromFile(ASource);
|
fElfFile.LoadFromFile(FFileLoader);
|
||||||
|
|
||||||
for i := 0 to fElfFile.seccount - 1 do begin
|
LoadSections;
|
||||||
fs := fElfFile.sections[i];
|
// check external debug file
|
||||||
idx := FSections.AddObject(fs.name, nil);
|
if ReadGnuDebugLinkSection(DbgFileName, crc) then
|
||||||
New(p);
|
begin
|
||||||
P^.Offs := fs.FileOfs;
|
SourceFileName := ASource.FileName;
|
||||||
p^.Sect.Size := fs.Size;
|
if SourceFileName<>'' then
|
||||||
p^.Sect.VirtualAddress := 0; // Todo? fs.Address - ImageBase
|
SourceFileName := ExtractFilePath(SourceFileName);
|
||||||
p^.Loaded := False;
|
NewFileLoader := LoadGnuDebugLink(SourceFileName, DbgFileName, crc);
|
||||||
FSections.Objects[idx] := TObject(p);
|
if NewFileLoader <> nil then begin
|
||||||
|
if fOwnSource then
|
||||||
|
FFileLoader.Free;
|
||||||
|
|
||||||
|
FFileLoader := NewFileLoader;
|
||||||
|
fOwnSource := True;
|
||||||
|
|
||||||
|
fElfFile.Free;
|
||||||
|
fElfFile := TElfFile.Create;
|
||||||
|
fElfFile.LoadFromFile(FFileLoader);
|
||||||
|
|
||||||
|
ClearSections;
|
||||||
|
LoadSections;
|
||||||
|
end;
|
||||||
end;
|
end;
|
||||||
|
|
||||||
FTargetInfo := fElfFile.FTargetInfo;
|
FTargetInfo := fElfFile.FTargetInfo;
|
||||||
@ -376,10 +418,7 @@ destructor TElfDbgSource.Destroy;
|
|||||||
begin
|
begin
|
||||||
if fOwnSource then FFileLoader.Free;
|
if fOwnSource then FFileLoader.Free;
|
||||||
fElfFile.Free;
|
fElfFile.Free;
|
||||||
while FSections.Count > 0 do begin
|
ClearSections;
|
||||||
Freemem(FSections.Objects[0]);
|
|
||||||
FSections.Delete(0);
|
|
||||||
end;
|
|
||||||
FreeAndNil(FSections);
|
FreeAndNil(FSections);
|
||||||
inherited Destroy;
|
inherited Destroy;
|
||||||
end;
|
end;
|
||||||
|
@ -41,7 +41,7 @@ interface
|
|||||||
uses
|
uses
|
||||||
Classes, {$ifdef windows}windows,{$endif} SysUtils, math,
|
Classes, {$ifdef windows}windows,{$endif} SysUtils, math,
|
||||||
{$ifdef FORCE_LAZLOGGER_DUMMY} LazLoggerDummy {$else} LazLoggerBase {$endif}, LazUTF8,
|
{$ifdef FORCE_LAZLOGGER_DUMMY} LazLoggerDummy {$else} LazLoggerBase {$endif}, LazUTF8,
|
||||||
DbgIntfBaseTypes, LazFileUtils, crc,
|
DbgIntfBaseTypes, LazFileUtils,
|
||||||
FpImgReaderBase, FpImgReaderWinPETypes, fpDbgSymTable;
|
FpImgReaderBase, FpImgReaderWinPETypes, fpDbgSymTable;
|
||||||
|
|
||||||
type
|
type
|
||||||
@ -103,11 +103,8 @@ end;
|
|||||||
|
|
||||||
constructor TPEFileSource.Create(ASource: TDbgFileLoader; ADebugMap: TObject; OwnSource: Boolean);
|
constructor TPEFileSource.Create(ASource: TDbgFileLoader; ADebugMap: TObject; OwnSource: Boolean);
|
||||||
var
|
var
|
||||||
p: PDbgImageSectionEx;
|
crc: cardinal;
|
||||||
crc, c: cardinal;
|
|
||||||
DbgFileName, SourceFileName: String;
|
DbgFileName, SourceFileName: String;
|
||||||
i, j: Integer;
|
|
||||||
mem: Pointer;
|
|
||||||
NewFileLoader: TDbgFileLoader;
|
NewFileLoader: TDbgFileLoader;
|
||||||
begin
|
begin
|
||||||
FSections := TStringListUTF8Fast.Create;
|
FSections := TStringListUTF8Fast.Create;
|
||||||
@ -119,54 +116,23 @@ begin
|
|||||||
FOwnLoader:=OwnSource;
|
FOwnLoader:=OwnSource;
|
||||||
LoadSections;
|
LoadSections;
|
||||||
// check external debug file
|
// check external debug file
|
||||||
p := PDbgImageSectionEx(Section['.gnu_debuglink']);
|
if ReadGnuDebugLinkSection(DbgFileName, crc) then
|
||||||
if p <> nil then
|
|
||||||
begin
|
begin
|
||||||
if IndexByte(p^.Sect.RawData^, p^.Sect.Size-4, 0) < p^.Sect.Size then
|
SourceFileName := ASource.FileName;
|
||||||
begin
|
if SourceFileName<>'' then
|
||||||
DbgFileName := StrPas(PChar(PDbgImageSectionEx(p)^.Sect.RawData));
|
SourceFileName := ExtractFilePath(SourceFileName);
|
||||||
i := align(length(DbgFileName)+1, 4);
|
NewFileLoader := LoadGnuDebugLink(SourceFileName, DbgFileName, crc);
|
||||||
if (i+4) <= p^.Sect.Size then begin
|
if NewFileLoader <> nil then begin
|
||||||
move((p^.Sect.RawData+i)^, crc, 4);
|
if FOwnLoader then
|
||||||
|
FFileLoader.Free;
|
||||||
|
|
||||||
SourceFileName := ASource.FileName;
|
FFileLoader := NewFileLoader;
|
||||||
if SourceFileName<>'' then
|
FOwnLoader := True;
|
||||||
DbgFileName := ExtractFilePath(SourceFileName)+DbgFileName;
|
ClearSections;
|
||||||
if FileExists(DbgFileName) then
|
LoadSections;
|
||||||
begin
|
|
||||||
NewFileLoader := TDbgFileLoader.Create(DbgFileName);
|
|
||||||
|
|
||||||
i := FileSizeUtf8(DbgFileName) - 4096;
|
|
||||||
j := 0;
|
|
||||||
|
|
||||||
c:=0;
|
|
||||||
while j < i do begin
|
|
||||||
NewFileLoader.LoadMemory(j, 4096, mem);
|
|
||||||
c:=Crc32(c, mem, 4096);
|
|
||||||
NewFileLoader.UnloadMemory(mem);
|
|
||||||
inc(j, 4096)
|
|
||||||
end;
|
|
||||||
i := i - j + 4096;
|
|
||||||
NewFileLoader.LoadMemory(j, i, mem);
|
|
||||||
c:=Crc32(c, mem, i);
|
|
||||||
NewFileLoader.UnloadMemory(mem);
|
|
||||||
|
|
||||||
debugln(crc <> c, ['Invalid CRC for ext debug info']);
|
|
||||||
if crc = c then begin
|
|
||||||
if FOwnLoader then
|
|
||||||
FFileLoader.Free;
|
|
||||||
|
|
||||||
FFileLoader := NewFileLoader;
|
|
||||||
FOwnLoader := True;
|
|
||||||
ClearSections;
|
|
||||||
LoadSections;
|
|
||||||
end
|
|
||||||
else
|
|
||||||
NewFileLoader.Free;
|
|
||||||
end;
|
|
||||||
end;
|
|
||||||
end;
|
end;
|
||||||
end;
|
end;
|
||||||
|
|
||||||
inherited Create(ASource, ADebugMap, OwnSource);
|
inherited Create(ASource, ADebugMap, OwnSource);
|
||||||
end;
|
end;
|
||||||
|
|
||||||
|
@ -3876,7 +3876,7 @@ begin
|
|||||||
else
|
else
|
||||||
Result:=[dcrExternalDbgInfoOnly, dcrDwarfOnly]; // cocoa
|
Result:=[dcrExternalDbgInfoOnly, dcrDwarfOnly]; // cocoa
|
||||||
{$ELSE}
|
{$ELSE}
|
||||||
Result:=[dcrNoExternalDbgInfo, dcrDwarfOnly];
|
Result:=[dcrDwarfOnly];
|
||||||
{$ENDIF}
|
{$ENDIF}
|
||||||
end;
|
end;
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user