diff --git a/components/fpdebug/fpimgreaderbase.pas b/components/fpdebug/fpimgreaderbase.pas index c82a7839a4..8d4d48da56 100644 --- a/components/fpdebug/fpimgreaderbase.pas +++ b/components/fpdebug/fpimgreaderbase.pas @@ -11,10 +11,10 @@ uses {$ifdef windows} Windows, // After LCLType {$endif} - fgl, LazFglHash, + fgl, LazFglHash, LazFileUtils, LazLoggerBase, fpDbgSymTable, Classes, SysUtils, DbgIntfBaseTypes, contnrs, - FpDbgCommon; + FpDbgCommon, crc; type TDbgImageSection = record @@ -105,6 +105,8 @@ type procedure SetImageBase(ABase: QWord); procedure SetImageSize(ASize: QWord); procedure AddReaderError(AnError: String); + function ReadGnuDebugLinkSection(out AFileName: String; out ACrc: Cardinal): Boolean; + function LoadGnuDebugLink(ASearchPath, AFileName: String; ACrc: Cardinal): TDbgFileLoader; public class function isValid(ASource: TDbgFileLoader): Boolean; virtual; abstract; class function UserName: AnsiString; virtual; abstract; @@ -133,6 +135,10 @@ procedure RegisterImageReaderClass(DataSource: TDbgImageReaderClass); implementation +const + // Symbol-map section name + _gnu_dbg_link = '.gnu_debuglink'; + var RegisteredImageReaderClasses : TFPList; @@ -404,6 +410,73 @@ begin FReaderErrors := FReaderErrors + AnError; 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); begin // The format of the symbol-table-section(s) can be different on each diff --git a/components/fpdebug/fpimgreaderelf.pas b/components/fpdebug/fpimgreaderelf.pas index 802c69d7ba..1314443937 100644 --- a/components/fpdebug/fpimgreaderelf.pas +++ b/components/fpdebug/fpimgreaderelf.pas @@ -73,6 +73,8 @@ type fElfFile : TElfFile; protected function GetSection(const AName: String): PDbgImageSection; override; + procedure LoadSections; + procedure ClearSections; public class function isValid(ASource: TDbgFileLoader): Boolean; override; class function UserName: AnsiString; override; @@ -317,6 +319,34 @@ begin FFileLoader.LoadMemory(ex^.Offs, Result^.Size, Result^.RawData); 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; var buf : array [0..3+sizeof(Elf32_EHdr)] of byte; @@ -341,10 +371,9 @@ end; constructor TElfDbgSource.Create(ASource: TDbgFileLoader; ADebugMap: TObject; OwnSource: Boolean); var - p: PDbgImageSectionEx; - idx: integer; - i: Integer; - fs: TElfSection; + DbgFileName, SourceFileName: String; + crc: Cardinal; + NewFileLoader: TDbgFileLoader; begin FSections := TStringListUTF8Fast.Create; FSections.Sorted := True; @@ -354,17 +383,30 @@ begin FFileLoader := ASource; fOwnSource := OwnSource; fElfFile := TElfFile.Create; - fElfFile.LoadFromFile(ASource); + fElfFile.LoadFromFile(FFileLoader); - 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); + LoadSections; + // check external debug file + if ReadGnuDebugLinkSection(DbgFileName, crc) then + begin + SourceFileName := ASource.FileName; + if SourceFileName<>'' then + SourceFileName := ExtractFilePath(SourceFileName); + NewFileLoader := LoadGnuDebugLink(SourceFileName, DbgFileName, crc); + 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; FTargetInfo := fElfFile.FTargetInfo; @@ -376,10 +418,7 @@ destructor TElfDbgSource.Destroy; begin if fOwnSource then FFileLoader.Free; fElfFile.Free; - while FSections.Count > 0 do begin - Freemem(FSections.Objects[0]); - FSections.Delete(0); - end; + ClearSections; FreeAndNil(FSections); inherited Destroy; end; diff --git a/components/fpdebug/fpimgreaderwinpe.pas b/components/fpdebug/fpimgreaderwinpe.pas index d718bb95f3..4bf8aa54c6 100644 --- a/components/fpdebug/fpimgreaderwinpe.pas +++ b/components/fpdebug/fpimgreaderwinpe.pas @@ -41,7 +41,7 @@ interface uses Classes, {$ifdef windows}windows,{$endif} SysUtils, math, {$ifdef FORCE_LAZLOGGER_DUMMY} LazLoggerDummy {$else} LazLoggerBase {$endif}, LazUTF8, - DbgIntfBaseTypes, LazFileUtils, crc, + DbgIntfBaseTypes, LazFileUtils, FpImgReaderBase, FpImgReaderWinPETypes, fpDbgSymTable; type @@ -103,11 +103,8 @@ end; constructor TPEFileSource.Create(ASource: TDbgFileLoader; ADebugMap: TObject; OwnSource: Boolean); var - p: PDbgImageSectionEx; - crc, c: cardinal; + crc: cardinal; DbgFileName, SourceFileName: String; - i, j: Integer; - mem: Pointer; NewFileLoader: TDbgFileLoader; begin FSections := TStringListUTF8Fast.Create; @@ -119,54 +116,23 @@ begin FOwnLoader:=OwnSource; LoadSections; // check external debug file - p := PDbgImageSectionEx(Section['.gnu_debuglink']); - if p <> nil then + if ReadGnuDebugLinkSection(DbgFileName, crc) then begin - if IndexByte(p^.Sect.RawData^, p^.Sect.Size-4, 0) < p^.Sect.Size then - begin - DbgFileName := StrPas(PChar(PDbgImageSectionEx(p)^.Sect.RawData)); - i := align(length(DbgFileName)+1, 4); - if (i+4) <= p^.Sect.Size then begin - move((p^.Sect.RawData+i)^, crc, 4); + SourceFileName := ASource.FileName; + if SourceFileName<>'' then + SourceFileName := ExtractFilePath(SourceFileName); + NewFileLoader := LoadGnuDebugLink(SourceFileName, DbgFileName, crc); + if NewFileLoader <> nil then begin + if FOwnLoader then + FFileLoader.Free; - SourceFileName := ASource.FileName; - if SourceFileName<>'' then - DbgFileName := ExtractFilePath(SourceFileName)+DbgFileName; - if FileExists(DbgFileName) then - 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; + FFileLoader := NewFileLoader; + FOwnLoader := True; + ClearSections; + LoadSections; end; end; + inherited Create(ASource, ADebugMap, OwnSource); end; diff --git a/components/lazdebuggers/lazdebuggerfp/fpdebugdebugger.pas b/components/lazdebuggers/lazdebuggerfp/fpdebugdebugger.pas index 3edf8c90ec..ea4fbee06a 100644 --- a/components/lazdebuggers/lazdebuggerfp/fpdebugdebugger.pas +++ b/components/lazdebuggers/lazdebuggerfp/fpdebugdebugger.pas @@ -3831,7 +3831,7 @@ begin else Result:=[dcrExternalDbgInfoOnly, dcrDwarfOnly]; // cocoa {$ELSE} - Result:=[dcrNoExternalDbgInfo, dcrDwarfOnly]; + Result:=[dcrDwarfOnly]; {$ENDIF} end;