FPDebug: start porting macho reader from duby

git-svn-id: trunk@43239 -
This commit is contained in:
martin 2013-10-13 14:00:01 +00:00
parent 7185e1ba7d
commit 3a38088ecf
8 changed files with 2155 additions and 5 deletions

4
.gitattributes vendored
View File

@ -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

View 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/

View File

@ -41,7 +41,7 @@ interface
uses
LCLType,
FpImgReaderBase, FpImgReaderWinPE, FpImgReaderElf,
FpImgReaderBase, FpImgReaderWinPE, FpImgReaderElf, FpImgReaderMacho,
Classes, SysUtils, FpDbgPETypes, LazUTF8Classes;
type

View File

@ -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">

View File

@ -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

View 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.

View 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

File diff suppressed because it is too large Load Diff