FpDebug: Read the symbol-table on OS/X

git-svn-id: trunk@45038 -
This commit is contained in:
joost 2014-05-14 20:21:22 +00:00
parent 5829cc4e89
commit 69a51cde62
9 changed files with 276 additions and 25 deletions

2
.gitattributes vendored
View File

@ -1282,6 +1282,8 @@ components/fpdebug/fpdbginfo.pas svneol=native#text/pascal
components/fpdebug/fpdbgloader.pp svneol=native#text/pascal
components/fpdebug/fpdbgpetypes.pp svneol=native#text/pascal
components/fpdebug/fpdbgsymbols.pas svneol=native#text/pascal
components/fpdebug/fpdbgsymtable.pas svneol=native#text/plain
components/fpdebug/fpdbgsymtablecontext.pas svneol=native#text/plain
components/fpdebug/fpdbgutil.pp svneol=native#text/pascal
components/fpdebug/fpdbgwinclasses.pas svneol=native#text/pascal
components/fpdebug/fpdbgwinextra.pp svneol=native#text/pascal

View File

@ -40,6 +40,7 @@ uses
Classes, SysUtils, Maps, FpDbgDwarf, FpDbgUtil, FpDbgWinExtra, FpDbgLoader,
FpDbgInfo, FpdMemoryTools, LazLoggerBase, LazClasses, DbgIntfBaseTypes, fgl,
FpDbgDisasX86,
fpDbgSymTableContext,
FpDbgDwarfDataClasses;
type
@ -205,6 +206,7 @@ type
FOnDebugInfoLoaded: TNotifyEvent;
FProcess: TDbgProcess;
FDbgInfo: TDbgInfo;
FSymbolTableInfo: TFpSymbolInfo;
FLoader: TDbgImageLoader;
protected
@ -222,6 +224,7 @@ type
property Process: TDbgProcess read FProcess;
property DbgInfo: TDbgInfo read FDbgInfo;
property SymbolTableInfo: TFpSymbolInfo read FSymbolTableInfo;
property OnDebugInfoLoaded: TNotifyEvent read FOnDebugInfoLoaded write FOnDebugInfoLoaded;
end;
@ -601,6 +604,7 @@ end;
destructor TDbgInstance.Destroy;
begin
FreeAndNil(FDbgInfo);
FreeAndNil(FSymbolTableInfo);
FreeAndNil(FLoader);
inherited;
end;
@ -608,6 +612,8 @@ end;
function TDbgInstance.FindSymbol(AAdress: TDbgPtr): TFpDbgSymbol;
begin
Result := FDbgInfo.FindSymbol(AAdress + AddrOffset);
if not assigned(Result) then
result := FSymbolTableInfo.FindSymbol(AAdress + AddrOffset);
end;
procedure TDbgInstance.LoadInfo;
@ -615,6 +621,7 @@ begin
FLoader := InitializeLoader;
FDbgInfo := TFpDwarfInfo.Create(FLoader);
TFpDwarfInfo(FDbgInfo).LoadCompilationUnits;
FSymbolTableInfo := TFpSymbolInfo.Create(FLoader);
if Assigned(FOnDebugInfoLoaded) then
FOnDebugInfoLoaded(Self);
end;

View File

@ -42,6 +42,7 @@ interface
uses
LCLType,
FpImgReaderBase, FpImgReaderWinPE, FpImgReaderElf, FpImgReaderMacho,
fpDbgSymTable,
Classes, SysUtils;
type
@ -65,6 +66,7 @@ type
public
constructor Create; virtual;
constructor Create(AFileName: String);
procedure ParseSymbolTable(AFpSymbolInfo: TfpSymbolList);
{$ifdef USE_WIN_FILE_MAPPING}
constructor Create(AFileHandle: THandle);
{$endif}
@ -100,6 +102,11 @@ begin
FImgReader := GetImageReader(FFileLoader, True);
end;
procedure TDbgImageLoader.ParseSymbolTable(AFpSymbolInfo: TfpSymbolList);
begin
FImgReader.ParseSymbolTable(AFpSymbolInfo);
end;
{$ifdef USE_WIN_FILE_MAPPING}
constructor TDbgImageLoader.Create(AFileHandle: THandle);
begin

View File

@ -0,0 +1,16 @@
unit fpDbgSymTable;
{$mode objfpc}{$H+}
interface
uses
Classes;
type
TfpSymbolList= TStringList;
implementation
end.

View File

@ -0,0 +1,145 @@
unit fpDbgSymTableContext;
{$mode objfpc}{$H+}
interface
uses
Classes,
SysUtils,
FpDbgLoader,
FpImgReaderBase,
DbgIntfBaseTypes,
fpDbgSymTable,
FpdMemoryTools,
FpDbgInfo;
type
TFpSymbolInfo = class;
{ TFpSymbolContext }
TFpSymbolContext = class(TFpDbgInfoContext)
private
FFpSymbolInfo: TFpSymbolInfo;
protected
function GetAddress: TDbgPtr; override;
function GetStackFrame: Integer; override;
function GetThreadId: Integer; override;
function GetSizeOfAddress: Integer; override;
public
constructor Create(AFpSymbolInfo: TFpSymbolInfo);
function FindSymbol(const AName: String): TFpDbgValue; override;
end;
{ TFpSymbolInfo }
TFpSymbolInfo = class(TDbgInfo)
private
FSymbolList: TfpSymbolList;
FContext: TFpSymbolContext;
public
constructor Create(ALoader: TDbgImageLoader); override;
destructor Destroy; override;
function FindContext(AThreadId, AStackFrame: Integer; AAddress: TDbgPtr = 0): TFpDbgInfoContext; override;
function FindContext(AAddress: TDbgPtr): TFpDbgInfoContext; override;
function FindSymbol(AAddress: TDbgPtr): TFpDbgSymbol; override;
function FindSymbol(const AName: String): TFpDbgSymbol; override;
function GetLineAddress(const AFileName: String; ALine: Cardinal): TDbgPtr; override;
end;
implementation
{ TFpSymbolContext }
function TFpSymbolContext.GetAddress: TDbgPtr;
begin
result := 0;
end;
function TFpSymbolContext.GetStackFrame: Integer;
begin
result := 0;
end;
function TFpSymbolContext.GetThreadId: Integer;
begin
result := 1;
end;
function TFpSymbolContext.GetSizeOfAddress: Integer;
begin
result := 4;
end;
constructor TFpSymbolContext.Create(AFpSymbolInfo: TFpSymbolInfo);
begin
inherited create;
FFpSymbolInfo:=AFpSymbolInfo;
end;
function TFpSymbolContext.FindSymbol(const AName: String): TFpDbgValue;
var
i: integer;
val: TFpDbgMemLocation;
begin
i := FFpSymbolInfo.FSymbolList.IndexOf(AName);
if i > -1 then
begin
val.Address:=TDbgPtr(pointer(FFpSymbolInfo.FSymbolList.Objects[i]));
val.MType:=mlfTargetMem;
result := TFpDbgValueConstAddress.Create(val);
end
else
result := nil;
end;
{ TFpSymbolInfo }
constructor TFpSymbolInfo.Create(ALoader: TDbgImageLoader);
begin
inherited Create(ALoader);
FContext := TFpSymbolContext.Create(self);
FSymbolList := TfpSymbolList.Create;
ALoader.ParseSymbolTable(FSymbolList);
end;
destructor TFpSymbolInfo.Destroy;
begin
FSymbolList.Free;
FContext.Free;
inherited Destroy;
end;
function TFpSymbolInfo.FindContext(AThreadId, AStackFrame: Integer;
AAddress: TDbgPtr): TFpDbgInfoContext;
begin
Result:=FContext;
end;
function TFpSymbolInfo.FindContext(AAddress: TDbgPtr): TFpDbgInfoContext;
begin
Result:=FContext;
end;
function TFpSymbolInfo.FindSymbol(AAddress: TDbgPtr): TFpDbgSymbol;
begin
Result:=inherited FindSymbol(AAddress);
end;
function TFpSymbolInfo.FindSymbol(const AName: String): TFpDbgSymbol;
begin
result := nil;
//Result:=FContext.FindSymbol(AName);
end;
function TFpSymbolInfo.GetLineAddress(const AFileName: String; ALine: Cardinal): TDbgPtr;
begin
Result:=inherited GetLineAddress(AFileName, ALine);
end;
end.

View File

@ -34,7 +34,7 @@ File(s) with other licenses (see also header in file(s):
(Any modifications/translations of this file are from duby)
"/>
<Files Count="27">
<Files Count="29">
<Item1>
<Filename Value="fpdbgclasses.pp"/>
<UnitName Value="FpDbgClasses"/>
@ -144,8 +144,16 @@ File(s) with other licenses (see also header in file(s):
</Item26>
<Item27>
<Filename Value="fpdbgdwarffreepascal.pas"/>
<UnitName Value="fpdbgdwarffreepascal"/>
<UnitName Value="FpDbgDwarfFreePascal"/>
</Item27>
<Item28>
<Filename Value="fpdbgsymtablecontext.pas"/>
<UnitName Value="fpDbgSymTableContext"/>
</Item28>
<Item29>
<Filename Value="fpdbgsymtable.pas"/>
<UnitName Value="fpDbgSymTable"/>
</Item29>
</Files>
<Type Value="RunAndDesignTime"/>
<RequiredPkgs Count="3">

View File

@ -12,7 +12,8 @@ uses
FpImgReaderElfTypes, FpImgReaderBase, FpPascalParser, macho,
FpImgReaderMachoFile, FpImgReaderMacho, FpPascalBuilder, FpDbgInfo,
FpdMemoryTools, FpErrorMessages, FPDbgController, FpDbgDwarfVerbosePrinter,
FpDbgDwarfDataClasses, FpDbgDwarfFreePascal, LazarusPackageIntf;
FpDbgDwarfDataClasses, FpDbgDwarfFreePascal, fpDbgSymTableContext,
fpDbgSymTable, LazarusPackageIntf;
implementation

View File

@ -8,6 +8,7 @@ uses
{$ifdef windows}
Windows, // After LCLType
{$endif}
fpDbgSymTable,
Classes, SysUtils, LazUTF8Classes;
type
@ -64,6 +65,7 @@ type
public
class function isValid(ASource: TDbgFileLoader): Boolean; virtual; abstract;
class function UserName: AnsiString; virtual; abstract;
procedure ParseSymbolTable(AFpSymbolInfo: TfpSymbolList); virtual;
constructor Create({%H-}ASource: TDbgFileLoader; {%H-}OwnSource: Boolean); virtual;
property ImageBase: QWord read FImageBase;
@ -234,6 +236,12 @@ begin
FImage64Bit := AValue;
end;
procedure TDbgImageReader.ParseSymbolTable(AFpSymbolInfo: TfpSymbolList);
begin
// The format of the symbol-table-section(s) can be different on each
// platform. That's why parsing the data is done in TDbgImageReader.
end;
constructor TDbgImageReader.Create(ASource: TDbgFileLoader; OwnSource: Boolean);
begin
inherited Create;

View File

@ -5,7 +5,8 @@ unit FpImgReaderMacho;
interface
uses
Classes, SysUtils, macho, FpImgReaderMachoFile, FpImgReaderBase, LazLoggerBase; //, stabs;
Classes, SysUtils, macho, FpImgReaderMachoFile, FpImgReaderBase, LazLoggerBase,
fpDbgSymTable;
type
@ -17,20 +18,21 @@ type
FSections: TStringList;
fOwnSource : Boolean;
fFile : TMachoFile;
isStabs : Boolean;
hasSymTable : Boolean;
StabsCmd : symtab_command;
fileRead : Boolean;
function GetSectionInfo(const SectionName: AnsiString; var Size: int64): Boolean;
function GetSectionData(const SectionName: AnsiString; Offset, {%H-}Size: Int64; var Buf: array of byte): Int64;
protected
procedure ReadFile;
function GetStabSectionInfo({%H-}StabStr: Boolean; var {%H-}SectionOffset, {%H-}SectionSize: Int64): Boolean;
function GetSymTableSectionInfo({%H-}StabStr: Boolean; var {%H-}SectionOffset, {%H-}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;
procedure ParseSymbolTable(AfpSymbolInfo: TfpSymbolList); override;
public
constructor Create(ASource: TDbgFileLoader; OwnSource: Boolean); override;
destructor Destroy; override;
@ -38,10 +40,14 @@ type
implementation
type
PnlistArray = ^TnlistArray;
TnlistArray = array[0..maxSmallint] of nlist;
const
//StabSectoinName
_stab = '.stab';
_stabstr = '.stabstr';
// Symbol-map section name
_symbol = '.symbols';
_symbolstrings = '.symbolsstrings';
function isValidMachoStream(ASource: TDbgFileLoader): Boolean;
@ -82,6 +88,37 @@ begin
Result:='mach-o file';
end;
procedure TDbgMachoDataSource.ParseSymbolTable(AfpSymbolInfo: TfpSymbolList);
var
p: PDbgImageSection;
ps: PDbgImageSection;
SymbolArr: PnlistArray;
SymbolStr: pointer;
i: integer;
SymbolCount: integer;
begin
p := Section[_symbol];
ps := Section[_symbolstrings];
if assigned(p) and assigned(ps) then
begin
SymbolArr:=PDbgImageSectionEx(p)^.Sect.RawData;
SymbolStr:=PDbgImageSectionEx(ps)^.Sect.RawData;
SymbolCount := PDbgImageSectionEx(p)^.Sect.Size div sizeof(nlist);
for i := 0 to SymbolCount-1 do
begin
if (SymbolArr^[i].n_type and $e0)<>0 then
// This is a stabs-entry. Ignore.
Continue;
if (SymbolArr^[i].n_type and $0e)=$e then
begin
// Section-index is ignored for now...
AfpSymbolInfo.AddObject(pchar(SymbolStr+SymbolArr^[i].n_un.n_strx), TObject(SymbolArr^[i].n_value));
end
end;
end;
end;
procedure TDbgMachoDataSource.ReadFile;
var
i : Integer;
@ -90,8 +127,8 @@ begin
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
hasSymTable := fFile.commands[i]^.cmd = LC_SYMTAB;
if hasSymTable then begin
StabsCmd := psymtab_command(fFile.commands[i])^;
Break;
end;
@ -99,20 +136,18 @@ begin
fileRead := true;
end;
function TDbgMachoDataSource.GetStabSectionInfo(StabStr: Boolean; var SectionOffset, SectionSize: Int64): Boolean;
function TDbgMachoDataSource.GetSymTableSectionInfo(StabStr: Boolean;
var SectionOffset, SectionSize: Int64): Boolean;
begin
exit(false);
(*
Result := isStabs;
Result := hasSymTable;
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));
SectionSize := Int64(StabsCmd.nsyms * sizeof(nlist));
end;
*)
end;
function TDbgMachoDataSource.GetSectionIndex(const SectionName: AnsiString): Integer;
@ -152,11 +187,15 @@ begin
end;
constructor TDbgMachoDataSource.Create(ASource: TDbgFileLoader; OwnSource: Boolean);
const
SymbolsSectionName : array [Boolean] of AnsiString = (_symbol, _symbolstrings);
var
p: PDbgImageSectionEx;
fs: TMachOsection;
i: Integer;
Name: String;
soffset: int64;
ssize: int64;
begin
fSource := ASource;
fOwnSource := OwnSource;
@ -189,6 +228,24 @@ DebugLn(Name);
FSections.AddObject(Name, TObject(p));
end;
if GetSymTableSectionInfo(false, soffset, ssize) then begin
new(p);
p^.Offs:=soffset;
p^.Sect.Size:=ssize;
p^.Sect.VirtualAddress:=0;
p^.Loaded:=false;
FSections.AddObject(SymbolsSectionName[false], TObject(p));
end;
if GetSymTableSectionInfo(true, soffset, ssize) then begin
new(p);
p^.Offs:=soffset;
p^.Sect.Size:=ssize;
p^.Sect.VirtualAddress:=0;
p^.Loaded:=false;
FSections.AddObject(SymbolsSectionName[true], TObject(p));
end;
inherited Create(ASource, OwnSource);
end;
@ -272,14 +329,14 @@ end;}
function TDbgMachoDataSource.GetSectionInfo(const SectionName: AnsiString; var Size: int64): Boolean;
var
idx : integer;
stabstr : Boolean;
symtablestr : Boolean;
dummy : int64;
begin
if not fileRead then ReadFile;
stabstr := (SectionName = _stabstr);
if stabstr or (SectionName = _stab) then
Result := GetStabSectionInfo(stabstr, dummy, Size)
symtablestr := (SectionName = _symbolstrings);
if symtablestr or (SectionName = _symbol) then
Result := GetSymTableSectionInfo(symtablestr, dummy, Size)
else begin
idx := GetSectionIndex(SectionName);
Result := idx >= 0;
@ -297,16 +354,16 @@ var
idx : Integer;
sofs : int64;
ssize : int64;
stabstr : Boolean;
symstr : 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
symstr := SectionName = _symbolstrings;
if symstr or (SectionName = _symbol) then begin
if not GetSymTableSectionInfo(symstr, sofs, ssize) then
Exit;
end else begin
idx := GetSectionIndex(SectionName);