mirror of
https://gitlab.com/freepascal.org/lazarus/lazarus.git
synced 2025-04-08 02:19:57 +02:00
FPDebug: start porting macho reader from duby
git-svn-id: trunk@43239 -
This commit is contained in:
parent
7185e1ba7d
commit
3a38088ecf
4
.gitattributes
vendored
4
.gitattributes
vendored
@ -1212,6 +1212,7 @@ components/fpcunit/languages/guitestrunner.ru.po svneol=native#text/plain
|
||||
components/fpcunit/languages/guitestrunner.uk.po svneol=native#text/plain
|
||||
components/fpcunit/lib/README.txt svneol=native#text/plain
|
||||
components/fpdebug/README_DUBY.txt svneol=native#text/pascal
|
||||
components/fpdebug/README_macho.txt svneol=native#text/pascal
|
||||
components/fpdebug/app/fpd/README.txt svneol=native#text/plain
|
||||
components/fpdebug/app/fpd/fpd.lpi svneol=native#text/pascal
|
||||
components/fpdebug/app/fpd/fpd.lpr svneol=native#text/pascal
|
||||
@ -1236,9 +1237,12 @@ components/fpdebug/fpdebug.pas svneol=native#text/pascal
|
||||
components/fpdebug/fpimgreaderbase.pas svneol=native#text/pascal
|
||||
components/fpdebug/fpimgreaderelf.pas svneol=native#text/pascal
|
||||
components/fpdebug/fpimgreaderelftypes.pas svneol=native#text/pascal
|
||||
components/fpdebug/fpimgreadermacho.pas svneol=native#text/pascal
|
||||
components/fpdebug/fpimgreadermachofile.pas svneol=native#text/pascal
|
||||
components/fpdebug/fpimgreaderwinpe.pas svneol=native#text/pascal
|
||||
components/fpdebug/fpimgreaderwinpetypes.pas svneol=native#text/pascal
|
||||
components/fpdebug/fppascalparser.pas svneol=native#text/pascal
|
||||
components/fpdebug/macho.pas svneol=native#text/pascal
|
||||
components/fpdebug/test/FpTest.lpi svneol=native#text/pascal
|
||||
components/fpdebug/test/FpTest.lpr svneol=native#text/pascal
|
||||
components/fpdebug/test/asmtest.lpi svneol=native#text/plain
|
||||
|
25
components/fpdebug/README_macho.txt
Normal file
25
components/fpdebug/README_macho.txt
Normal file
@ -0,0 +1,25 @@
|
||||
The file macho.pas has the following license
|
||||
|
||||
* Copyright (c) 1999-2008 Apple Inc. All Rights Reserved.
|
||||
*
|
||||
* @APPLE_LICENSE_HEADER_START@
|
||||
*
|
||||
* This file contains Original Code and/or Modifications of Original Code
|
||||
* as defined in and that are subject to the Apple Public Source License
|
||||
* Version 2.0 (the 'License'). You may not use this file except in
|
||||
* compliance with the License. Please obtain a copy of the License at
|
||||
* http://www.opensource.apple.com/apsl/ and read it before using this
|
||||
* file.
|
||||
*
|
||||
* The Original Code and all software distributed under the License are
|
||||
* distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
|
||||
* EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
|
||||
* INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
|
||||
* Please see the License for the specific language governing rights and
|
||||
* limitations under the License.
|
||||
*
|
||||
* @APPLE_LICENSE_HEADER_END@
|
||||
|
||||
This file was ported from DUBY:
|
||||
http://sourceforge.net/projects/duby/
|
@ -41,7 +41,7 @@ interface
|
||||
|
||||
uses
|
||||
LCLType,
|
||||
FpImgReaderBase, FpImgReaderWinPE, FpImgReaderElf,
|
||||
FpImgReaderBase, FpImgReaderWinPE, FpImgReaderElf, FpImgReaderMacho,
|
||||
Classes, SysUtils, FpDbgPETypes, LazUTF8Classes;
|
||||
|
||||
type
|
||||
|
@ -8,6 +8,7 @@
|
||||
<Version Value="11"/>
|
||||
<PathDelim Value="\"/>
|
||||
<SearchPaths>
|
||||
<OtherUnitFiles Value="."/>
|
||||
<UnitOutputDirectory Value="lib\$(TargetCPU)-$(TargetOS)"/>
|
||||
</SearchPaths>
|
||||
<Other>
|
||||
@ -24,8 +25,16 @@ Based on:
|
||||
2) Duby by Dmitry Boyarintsev
|
||||
|
||||
Extended by Martin Friebe"/>
|
||||
<License Value="GPL"/>
|
||||
<Files Count="14">
|
||||
<License Value="All Files except those listed below: GPL
|
||||
|
||||
File(s) with other licenses (see also header in file(s):
|
||||
|
||||
* macho.pas
|
||||
This file contains Original Code and/or Modifications of Original Code as defined in and that are subject to the Apple Public Source License Version 2.0 (the 'License'). You may not use this file except in compliance with the License. Please obtain a copy of the License at http://www.opensource.apple.com/apsl/ and read it before using this file.
|
||||
|
||||
(Any modifications/translations of this file are from duby)
|
||||
"/>
|
||||
<Files Count="17">
|
||||
<Item1>
|
||||
<Filename Value="fpdbgclasses.pp"/>
|
||||
<UnitName Value="FpDbgClasses"/>
|
||||
@ -80,8 +89,20 @@ Extended by Martin Friebe"/>
|
||||
</Item13>
|
||||
<Item14>
|
||||
<Filename Value="fppascalparser.pas"/>
|
||||
<UnitName Value="fppascalparser"/>
|
||||
<UnitName Value="FpPascalParser"/>
|
||||
</Item14>
|
||||
<Item15>
|
||||
<Filename Value="macho.pas"/>
|
||||
<UnitName Value="macho"/>
|
||||
</Item15>
|
||||
<Item16>
|
||||
<Filename Value="fpimgreadermachofile.pas"/>
|
||||
<UnitName Value="FpImgReaderMachoFile"/>
|
||||
</Item16>
|
||||
<Item17>
|
||||
<Filename Value="fpimgreadermacho.pas"/>
|
||||
<UnitName Value="FpImgReaderMacho"/>
|
||||
</Item17>
|
||||
</Files>
|
||||
<Type Value="RunAndDesignTime"/>
|
||||
<RequiredPkgs Count="2">
|
||||
|
@ -9,7 +9,8 @@ interface
|
||||
uses
|
||||
FpDbgClasses, FpDbgDisasX86, FpDbgDwarf, FpDbgDwarfConst, FpDbgLoader, FpDbgPETypes,
|
||||
FpDbgSymbols, FpDbgUtil, FpDbgWinExtra, FpImgReaderWinPE, FpImgReaderElf,
|
||||
FpImgReaderElfTypes, FpImgReaderBase, FpPascalParser, LazarusPackageIntf;
|
||||
FpImgReaderElfTypes, FpImgReaderBase, FpPascalParser, macho, FpImgReaderMachoFile,
|
||||
FpImgReaderMacho, LazarusPackageIntf;
|
||||
|
||||
implementation
|
||||
|
||||
|
335
components/fpdebug/fpimgreadermacho.pas
Normal file
335
components/fpdebug/fpimgreadermacho.pas
Normal file
@ -0,0 +1,335 @@
|
||||
unit FpImgReaderMacho;
|
||||
|
||||
{$mode objfpc}{$H+}
|
||||
|
||||
interface
|
||||
|
||||
uses
|
||||
Classes, SysUtils, macho, FpImgReaderMachoFile, FpImgReaderBase, LazLoggerBase; //, stabs;
|
||||
|
||||
type
|
||||
|
||||
{ TDbgMachoDataSource }
|
||||
|
||||
TDbgMachoDataSource = class(TDbgImageReader)
|
||||
private
|
||||
fSource : TDbgFileLoader;
|
||||
FSections: TStringList;
|
||||
fOwnSource : Boolean;
|
||||
fFile : TMachoFile;
|
||||
isStabs : Boolean;
|
||||
StabsCmd : symtab_command;
|
||||
fileRead : Boolean;
|
||||
function GetSectionInfo(const SectionName: AnsiString; var Size: int64): Boolean;
|
||||
function GetSectionData(const SectionName: AnsiString; Offset, Size: Int64; var Buf: array of byte): Int64;
|
||||
protected
|
||||
procedure ReadFile;
|
||||
function GetStabSectionInfo(StabStr: Boolean; var SectionOffset, SectionSize: Int64): Boolean;
|
||||
function GetSectionIndex(const SectionName: AnsiString): Integer;
|
||||
|
||||
function GetSection(const AName: String): PDbgImageSection; override;
|
||||
public
|
||||
class function isValid(ASource: TDbgFileLoader): Boolean; override;
|
||||
class function UserName: AnsiString; override;
|
||||
public
|
||||
constructor Create(ASource: TDbgFileLoader; OwnSource: Boolean); override;
|
||||
destructor Destroy; override;
|
||||
end;
|
||||
|
||||
implementation
|
||||
|
||||
const
|
||||
//StabSectoinName
|
||||
_stab = '.stab';
|
||||
_stabstr = '.stabstr';
|
||||
|
||||
|
||||
function isValidMachoStream(ASource: TDbgFileLoader): Boolean;
|
||||
var
|
||||
header : mach_header;
|
||||
begin
|
||||
try
|
||||
Result := Assigned(ASource);
|
||||
if not Result then Exit;
|
||||
//Result := stream.Read(header, sizeof(header)) = sizeof(header);
|
||||
Result := ASource.Read(0, sizeof(header), @header) = sizeof(header);
|
||||
if not Result then Exit;
|
||||
Result := (header.magic = MH_CIGAM) or (header.magic = MH_MAGIC);
|
||||
except
|
||||
Result := false;
|
||||
end;
|
||||
end;
|
||||
|
||||
function FixMachoName(const macsectionname: String): String;
|
||||
begin
|
||||
if Copy(macsectionName, 1, 2) = '__' then
|
||||
Result:= '.'+Copy(macsectionName, 3, length(macsectionName)-2)
|
||||
else
|
||||
Result := macsectionname;
|
||||
end;
|
||||
|
||||
|
||||
|
||||
{ TDbgMachoDataSource }
|
||||
|
||||
class function TDbgMachoDataSource.isValid(ASource: TDbgFileLoader): Boolean;
|
||||
begin
|
||||
Result := isValidMachoStream(ASource);
|
||||
end;
|
||||
|
||||
class function TDbgMachoDataSource.UserName: AnsiString;
|
||||
begin
|
||||
Result:='mach-o file';
|
||||
end;
|
||||
|
||||
procedure TDbgMachoDataSource.ReadFile;
|
||||
var
|
||||
i : Integer;
|
||||
begin
|
||||
if Assigned(fFile) then fFile.Free;
|
||||
fFile:=TMachOFile.Create;
|
||||
fFile.LoadFromFile(fSource);
|
||||
for i := 0 to fFile.header.ncmds - 1 do begin
|
||||
isStabs := fFile.commands[i]^.cmd = LC_SYMTAB;
|
||||
if isStabs then begin
|
||||
StabsCmd := psymtab_command(fFile.commands[i])^;
|
||||
Break;
|
||||
end;
|
||||
end;
|
||||
fileRead := true;
|
||||
end;
|
||||
|
||||
function TDbgMachoDataSource.GetStabSectionInfo(StabStr: Boolean; var SectionOffset, SectionSize: Int64): Boolean;
|
||||
begin
|
||||
exit(false);
|
||||
(*
|
||||
Result := isStabs;
|
||||
if not Result then Exit;
|
||||
if StabStr then begin
|
||||
SectionOffset := StabsCmd.stroff;
|
||||
SectionSize := StabsCmd.strsize;
|
||||
end else begin
|
||||
SectionOffset := StabsCmd.symoff;
|
||||
SectionSize := Int64(StabsCmd.nsyms * sizeof(TStabSym));
|
||||
end;
|
||||
*)
|
||||
end;
|
||||
|
||||
function TDbgMachoDataSource.GetSectionIndex(const SectionName: AnsiString): Integer;
|
||||
var
|
||||
i : Integer;
|
||||
Name : AnsiString;
|
||||
begin
|
||||
//todo: hash-table
|
||||
for i := 0 to fFile.Sections.Count - 1 do begin
|
||||
with TMachoSection(fFile.sections[i]) do
|
||||
if is32
|
||||
then Name := FixMachoName(sec32.sectname)
|
||||
else Name := FixMachoName(sec64.sectname);
|
||||
if Name = SectionName then begin
|
||||
Result := i;
|
||||
Exit;
|
||||
end;
|
||||
end;
|
||||
Result := -1;
|
||||
end;
|
||||
|
||||
function TDbgMachoDataSource.GetSection(const AName: String): PDbgImageSection;
|
||||
var
|
||||
i: Integer;
|
||||
ex: PDbgImageSectionEx;
|
||||
begin
|
||||
Result := nil;
|
||||
i := FSections.IndexOf(AName);
|
||||
if i < 0 then
|
||||
exit;
|
||||
ex := PDbgImageSectionEx(FSections.Objects[i]);
|
||||
Result := @ex^.Sect;
|
||||
if ex^.Loaded then
|
||||
exit;
|
||||
ex^.Loaded := True;
|
||||
fSource.LoadMemory(ex^.Offs, Result^.Size, Result^.RawData);
|
||||
end;
|
||||
|
||||
constructor TDbgMachoDataSource.Create(ASource: TDbgFileLoader; OwnSource: Boolean);
|
||||
var
|
||||
p: PDbgImageSectionEx;
|
||||
fs: TMachOsection;
|
||||
i: Integer;
|
||||
Name: String;
|
||||
begin
|
||||
fSource := ASource;
|
||||
fOwnSource := OwnSource;
|
||||
|
||||
ReadFile;
|
||||
|
||||
FSections := TStringList.Create;
|
||||
FSections.Sorted := True;
|
||||
//FSections.Duplicates := dupError;
|
||||
FSections.CaseSensitive := False;
|
||||
|
||||
for i := 0 to fFile.sections.Count - 1 do begin
|
||||
fs := TMachoSection(fFile.sections[i]);
|
||||
New(p);
|
||||
|
||||
if fs.is32 then begin
|
||||
Name := FixMachoName(fs.sec32.sectname);
|
||||
P^.Offs := fs.sec32.offset;
|
||||
p^.Sect.Size := fs.sec32.size;
|
||||
end
|
||||
else begin
|
||||
Name := FixMachoName(fs.sec64.sectname);
|
||||
P^.Offs := fs.sec64.offset;
|
||||
p^.Sect.Size := fs.sec64.size;
|
||||
end;
|
||||
DebugLn(Name);
|
||||
|
||||
p^.Sect.VirtualAdress := 0; // Todo?
|
||||
p^.Loaded := False;
|
||||
FSections.AddObject(Name, TObject(p));
|
||||
end;
|
||||
|
||||
inherited Create(ASource, OwnSource);
|
||||
end;
|
||||
|
||||
destructor TDbgMachoDataSource.Destroy;
|
||||
begin
|
||||
if Assigned(fFile) then fFile.Free;
|
||||
if fOwnSource then fSource.Free;
|
||||
while FSections.Count > 0 do begin
|
||||
Freemem(FSections.Objects[0]);
|
||||
FSections.Delete(0);
|
||||
end;
|
||||
FreeAndNil(FSections);
|
||||
inherited Destroy;
|
||||
end;
|
||||
|
||||
{function TDbgMachoDataSource.SectionsCount: Integer;
|
||||
begin
|
||||
if not Assigned(fFile) then ReadFile;
|
||||
Result := fFile.Sections.Count;
|
||||
if isStabs then inc(Result, 2);
|
||||
end;
|
||||
|
||||
function TDbgMachoDataSource.GetSection(Index: Integer; var Name: AnsiString; var Size: Int64): Boolean;
|
||||
var
|
||||
cnt : Integer;
|
||||
sstr : Boolean;
|
||||
const
|
||||
StabSectionName : array [Boolean] of AnsiString = (_stab, _stabstr);
|
||||
begin
|
||||
if not Assigned(fFile) then ReadFile;
|
||||
cnt := fFile.Sections.Count;
|
||||
if isStabs then inc(cnt, 2);
|
||||
Result := (Index >= 0) and (Index < cnt);
|
||||
if not Result then Exit;
|
||||
|
||||
if Index < fFile.Sections.Count then begin
|
||||
with TMachoSection(fFile.sections[index]) do
|
||||
if is32 then begin
|
||||
Name := FixMachoName(sec32.sectname);
|
||||
Size := sec32.size;
|
||||
end else begin
|
||||
Name := FixMachoName(sec64.sectname);
|
||||
Size := sec64.size;
|
||||
end;
|
||||
end else begin
|
||||
sstr := Index = cnt - 1;
|
||||
Name := StabSectionName[sstr];
|
||||
Result := GetStabSectionInfo(sstr, Size);
|
||||
end;
|
||||
end;
|
||||
|
||||
function TDbgMachoDataSource.GetSectionData(index: Integer; outStream: TStream): Boolean;
|
||||
var
|
||||
ofs : Int64;
|
||||
sz : Int64;
|
||||
begin
|
||||
//todo: method will be removed
|
||||
if not Assigned(outStream) then begin
|
||||
Result := false;
|
||||
Exit;
|
||||
end;
|
||||
if not Assigned(fFile) then ReadFile;
|
||||
Result := (Index >= 0) and (Index < fFile.Sections.Count);
|
||||
if not Result then Exit;
|
||||
|
||||
with TMachOsection(fFile.sections[index]) do begin
|
||||
if is32 then begin
|
||||
ofs := sec32.offset;
|
||||
sz := sec32.size;
|
||||
end else begin
|
||||
ofs := sec64.offset;
|
||||
sz := sec64.size;
|
||||
end;
|
||||
end;
|
||||
if ofs > 0 then begin
|
||||
fSource.Position:=ofs;
|
||||
outStream.CopyFrom(fSource, sz);
|
||||
end;
|
||||
end;}
|
||||
|
||||
function TDbgMachoDataSource.GetSectionInfo(const SectionName: AnsiString; var Size: int64): Boolean;
|
||||
var
|
||||
idx : integer;
|
||||
stabstr : Boolean;
|
||||
dummy : int64;
|
||||
begin
|
||||
if not fileRead then ReadFile;
|
||||
|
||||
stabstr := (SectionName = _stabstr);
|
||||
if stabstr or (SectionName = _stab) then
|
||||
Result := GetStabSectionInfo(stabstr, dummy, Size)
|
||||
else begin
|
||||
idx := GetSectionIndex(SectionName);
|
||||
Result := idx >= 0;
|
||||
if not Result then Exit;
|
||||
|
||||
with TMachOsection(fFile.sections[idx]) do
|
||||
if is32
|
||||
then Size := sec32.size
|
||||
else Size := sec64.size;
|
||||
end;
|
||||
end;
|
||||
|
||||
function TDbgMachoDataSource.GetSectionData(const SectionName: AnsiString; Offset, Size: Int64; var Buf: array of byte): Int64;
|
||||
var
|
||||
idx : Integer;
|
||||
sofs : int64;
|
||||
ssize : int64;
|
||||
stabstr : Boolean;
|
||||
sz : Int64;
|
||||
s : TMachOsection;
|
||||
begin
|
||||
if not fileRead then ReadFile;
|
||||
|
||||
Result := 0;
|
||||
stabstr := SectionName = _stabstr;
|
||||
if stabstr or (SectionName = _stab) then begin
|
||||
if not GetStabSectionInfo(stabstr, sofs, ssize) then
|
||||
Exit;
|
||||
end else begin
|
||||
idx := GetSectionIndex(SectionName);
|
||||
s := TMachOsection(fFile.sections[idx]);
|
||||
if s.is32 then begin
|
||||
ssize := s.sec32.size;
|
||||
sofs := s.sec32.offset;
|
||||
end else begin
|
||||
sofs := s.sec64.offset;
|
||||
ssize := s.sec64.size;
|
||||
end;
|
||||
end;
|
||||
|
||||
sz := ssize - Offset;
|
||||
if sz < 0 then Exit;
|
||||
|
||||
//fSource.Position := sofs + Offset;
|
||||
//Result := fSource.Read(Buf[0], sz);
|
||||
Result := fSource.Read(sofs + Offset, sz, @Buf[0]);
|
||||
end;
|
||||
|
||||
initialization
|
||||
RegisterImageReaderClass( TDbgMachoDataSource );
|
||||
|
||||
end.
|
||||
|
93
components/fpdebug/fpimgreadermachofile.pas
Normal file
93
components/fpdebug/fpimgreadermachofile.pas
Normal file
@ -0,0 +1,93 @@
|
||||
unit FpImgReaderMachoFile;
|
||||
|
||||
{$mode objfpc}{$H+}
|
||||
|
||||
interface
|
||||
|
||||
//todo: powerpc, x86_64
|
||||
|
||||
uses
|
||||
Classes, SysUtils, macho, FpImgReaderBase;
|
||||
|
||||
type
|
||||
TMachOsection = class(TObject)
|
||||
is32 : Boolean;
|
||||
sec32 : section;
|
||||
sec64 : section_64;
|
||||
end;
|
||||
|
||||
{ TMachOFile }
|
||||
|
||||
TMachOFile = class(TObject)
|
||||
private
|
||||
cmdbuf : array of byte;
|
||||
public
|
||||
header : mach_header;
|
||||
commands : array of pload_command;
|
||||
sections : TFPList;
|
||||
constructor Create;
|
||||
destructor Destroy; override;
|
||||
function LoadFromFile(ALoader: TDbgFileLoader): Boolean;
|
||||
end;
|
||||
|
||||
|
||||
implementation
|
||||
|
||||
|
||||
{ TMachOFile }
|
||||
|
||||
constructor TMachOFile.Create;
|
||||
begin
|
||||
sections := TFPList.Create;
|
||||
end;
|
||||
|
||||
destructor TMachOFile.Destroy;
|
||||
var
|
||||
i : integer;
|
||||
begin
|
||||
for i := 0 to sections.Count - 1 do TMachOsection(sections[i]).Free;
|
||||
sections.Free;
|
||||
inherited Destroy;
|
||||
end;
|
||||
|
||||
function TMachOFile.LoadFromFile(ALoader: TDbgFileLoader): Boolean;
|
||||
var
|
||||
i : Integer;
|
||||
j : Integer;
|
||||
ofs : Integer;
|
||||
sc : psection;
|
||||
s : TMachOsection;
|
||||
begin
|
||||
//Stream.Read(header, sizeof(header));
|
||||
Result := ALoader.Read(0, sizeof(header), @header) = sizeof(header);
|
||||
if not Result then Exit;
|
||||
Result := (header.magic = MH_MAGIC) or (header.magic = MH_CIGAM);
|
||||
|
||||
SetLength(cmdbuf, header.sizeofcmds);
|
||||
//Stream.Read(cmdbuf[0], header.sizeofcmds);
|
||||
ALoader.Read(0, header.sizeofcmds, @cmdbuf[0]);
|
||||
|
||||
SetLength(commands, header.ncmds);
|
||||
ofs := 0;
|
||||
for i := 0 to header.ncmds - 1 do begin
|
||||
commands[i] := @cmdbuf[ofs];
|
||||
|
||||
if commands[i]^.cmd = LC_SEGMENT then begin
|
||||
sc := @cmdbuf[ofs+sizeof(segment_command)];
|
||||
for j := 0 to psegment_command(commands[i])^.nsects- 1 do begin
|
||||
s := TMachOSection.Create;
|
||||
s.is32:=true;
|
||||
s.sec32:=sc^;
|
||||
sections.add(s);
|
||||
inc(sc);
|
||||
end;
|
||||
|
||||
end;
|
||||
inc(ofs, commands[i]^.cmdsize);
|
||||
end;
|
||||
|
||||
end;
|
||||
|
||||
|
||||
end.
|
||||
|
1671
components/fpdebug/macho.pas
Normal file
1671
components/fpdebug/macho.pas
Normal file
File diff suppressed because it is too large
Load Diff
Loading…
Reference in New Issue
Block a user