mirror of
https://gitlab.com/freepascal.org/lazarus/lazarus.git
synced 2025-04-06 01:18:14 +02:00
595 lines
17 KiB
ObjectPascal
595 lines
17 KiB
ObjectPascal
unit FpImgReaderBase;
|
|
|
|
{$mode objfpc}{$H+}
|
|
{$IFDEF INLINE_OFF}{$INLINE OFF}{$ENDIF}
|
|
{$modeswitch advancedrecords}
|
|
|
|
interface
|
|
{$ifdef CD_Cocoa}{$DEFINE MacOS}{$ENDIF}
|
|
{$IFDEF Darwin}{$DEFINE MacOS}{$ENDIF}
|
|
|
|
uses
|
|
{$ifdef windows}
|
|
Windows, // After LCLType
|
|
{$endif}
|
|
fgl, LazFglHash, LazFileUtils, {$ifdef FORCE_LAZLOGGER_DUMMY} LazLoggerDummy {$else} LazLoggerBase {$endif},
|
|
fpDbgSymTable,
|
|
Classes, SysUtils, DbgIntfBaseTypes, contnrs,
|
|
FpDbgCommon, crc;
|
|
|
|
type
|
|
TDbgImageSection = record
|
|
RawData: Pointer;
|
|
Size: QWord;
|
|
VirtualAddress: QWord;
|
|
// Use this flag to identify sections that should be uploaded via RSP
|
|
// This is probably only relevant for uploads to low level targets (embedded, FreeRTOS...)
|
|
IsLoadable: Boolean;
|
|
Name: String;
|
|
end;
|
|
PDbgImageSection = ^TDbgImageSection;
|
|
|
|
TDbgImageSectionEx = record
|
|
Sect: TDbgImageSection;
|
|
Offs: QWord;
|
|
Loaded: Boolean;
|
|
end;
|
|
PDbgImageSectionEx = ^TDbgImageSectionEx;
|
|
|
|
type
|
|
TDbgAddressMap = record
|
|
OrgAddr: QWord;
|
|
Length: QWord;
|
|
NewAddr: QWord;
|
|
class operator =(r1,r2: TDbgAddressMap) : boolean;
|
|
end;
|
|
PDbgAddressMap = ^TDbgAddressMap;
|
|
TDbgAddressMapList = specialize TFPGList<TDbgAddressMap>;
|
|
|
|
{ TDbgAddressMapHashList }
|
|
|
|
TDbgAddressMapHashList = class(specialize TLazFPGHashTable<TDbgAddressMap>)
|
|
public
|
|
function ItemFromNode(ANode: THTCustomNode): TDbgAddressMap;
|
|
function ItemPointerFromNode(ANode: THTCustomNode): PDbgAddressMap;
|
|
end;
|
|
|
|
{ TDbgAddressMapPointerHashList }
|
|
|
|
TDbgAddressMapPointerHashList = class(specialize TLazFPGHashTable<PDbgAddressMap>)
|
|
public
|
|
function ItemPointerFromNode(ANode: THTCustomNode): PDbgAddressMap;
|
|
end;
|
|
|
|
{ TDbgFileLoader }
|
|
{$ifdef windows}
|
|
{$define USE_WIN_FILE_MAPPING}
|
|
{$endif}
|
|
|
|
TDbgFileLoader = class(TObject)
|
|
private
|
|
{$ifdef USE_WIN_FILE_MAPPING}
|
|
FFileHandle: THandle;
|
|
FMapHandle: THandle;
|
|
FModulePtr: Pointer;
|
|
{$endif}
|
|
FStream: TStream;
|
|
FList: TList;
|
|
FFileName: String;
|
|
|
|
function GetFileName: String;
|
|
procedure OpenStream;
|
|
public
|
|
constructor Create(AFileName: String);
|
|
{$ifdef USE_WIN_FILE_MAPPING}
|
|
constructor Create(AFileHandle: THandle);
|
|
{$endif}
|
|
destructor Destroy; override;
|
|
procedure Close;
|
|
function Read(AOffset, ASize: QWord; AMem: Pointer): QWord;
|
|
function LoadMemory(AOffset, ASize: QWord; out AMem: Pointer): QWord;
|
|
procedure UnloadMemory({%H-}AMem: Pointer);
|
|
property FileName: String read GetFileName;
|
|
end;
|
|
|
|
{ TDbgImageReader }
|
|
|
|
TDbgImageReader = class(TObject) // executable parser
|
|
private
|
|
FImageBase: QWord;
|
|
FImageSize: QWord;
|
|
FRelocationOffset: QWord;
|
|
FLoadedTargetImageAddr: TDBGPtr;
|
|
FReaderErrors: String;
|
|
FUUID: TGuid;
|
|
protected
|
|
FTargetInfo: TTargetDescriptor;
|
|
function GetSubFiles: TStrings; virtual;
|
|
function GetAddressMapList: TDbgAddressMapList; virtual;
|
|
function GetSection(const AName: String): PDbgImageSection; virtual; abstract;
|
|
function GetSection(const ID: integer): PDbgImageSection; virtual; abstract;
|
|
procedure SetUUID(AGuid: TGuid);
|
|
procedure SetImageBase(ABase: QWord);
|
|
procedure SetImageSize(ASize: QWord);
|
|
procedure SetRelocationOffset(AnOffset: QWord);
|
|
procedure AddReaderError(AnError: String);
|
|
function ReadGnuDebugLinkSection(out AFileName: String; out ACrc: Cardinal): Boolean;
|
|
function LoadGnuDebugLink(ASearchPath, AFileName: String; ACrc: Cardinal): TDbgFileLoader;
|
|
property LoadedTargetImageAddr: TDBGPtr read FLoadedTargetImageAddr;
|
|
public
|
|
class function isValid(ASource: TDbgFileLoader): Boolean; virtual; abstract;
|
|
class function UserName: AnsiString; virtual; abstract;
|
|
procedure ParseSymbolTable(AFpSymbolInfo: TfpSymbolList); virtual;
|
|
procedure ParseLibrarySymbolTable(AFpSymbolInfo: TfpSymbolList); virtual;
|
|
// The LoadedTargetImageAddr is the start-address of the data of the binary
|
|
// once loaded into memory.
|
|
// On Linux it is 0 for executables, and had another value for libraries
|
|
// which are relocated into another position.
|
|
// On Windows it is the same as the ImageBase, except when the binary has
|
|
// been relocated. This only happens if two libraries with the same ImageBase
|
|
// are loaded. In that case, one of them is being relocated to another
|
|
// LoadedTargetImageAddr.
|
|
constructor Create({%H-}ASource: TDbgFileLoader; {%H-}ADebugMap: TObject; ALoadedTargetImageAddr: TDbgPtr; OwnSource: Boolean); virtual;
|
|
procedure AddSubFilesToLoaderList(ALoaderList: TObject; PrimaryLoader: TObject); virtual;
|
|
function EnclosesAddressRange(AStartAddress, AnEndAddress: TDBGPtr): Boolean; virtual;
|
|
// The ImageBase is the address at which the linker assumed the binary will be
|
|
// loaded at. So it is stored inside the binary itself and all addresses inside
|
|
// the binary assume that once loaded into memory, it is loaded at this
|
|
// address. (Which is not the case for relocated libraries, see the comments
|
|
// for the LoadedTargetImageAddr)
|
|
// On Linux it is always 0, on Windows it is set by the linker/compiler.
|
|
property ImageBase: QWord read FImageBase;
|
|
property ImageSize: QWord read FImageSize;
|
|
// The RelocationOffset is the offset between the addresses as they are encoded
|
|
// into the binary, and their real addresses once loaded in memory.
|
|
// On linux it is equal to the LoadedTargetImageAddr.
|
|
// On Windows it is 0, except for libraries which are re-located. In that
|
|
// case the offset is LoadedTargetImageAddr-ImageBase.
|
|
property RelocationOffset: QWord read FRelocationOffset;
|
|
|
|
property TargetInfo: TTargetDescriptor read FTargetInfo;
|
|
|
|
property UUID: TGuid read FUUID;
|
|
property Section[const AName: String]: PDbgImageSection read GetSection;
|
|
property SectionByID[const ID: integer]: PDbgImageSection read GetSection;
|
|
property SubFiles: TStrings read GetSubFiles;
|
|
property AddressMapList: TDbgAddressMapList read GetAddressMapList;
|
|
property ReaderErrors: String read FReaderErrors;
|
|
end;
|
|
TDbgImageReaderClass = class of TDbgImageReader;
|
|
|
|
function GetImageReader(ASource: TDbgFileLoader; ADebugMap: TObject; ALoadedTargetImageAddr: TDbgPtr; OwnSource: Boolean): TDbgImageReader; overload;
|
|
procedure RegisterImageReaderClass(DataSource: TDbgImageReaderClass);
|
|
|
|
implementation
|
|
|
|
var
|
|
DBG_WARNINGS: PLazLoggerLogGroup;
|
|
|
|
const
|
|
// Symbol-map section name
|
|
_gnu_dbg_link = '.gnu_debuglink';
|
|
|
|
var
|
|
RegisteredImageReaderClasses : TFPList;
|
|
|
|
{ TDbgAddressMapPointerHashList }
|
|
|
|
function TDbgAddressMapPointerHashList.ItemPointerFromNode(ANode: THTCustomNode
|
|
): PDbgAddressMap;
|
|
begin
|
|
Result := THTGNode(ANode).Data;
|
|
end;
|
|
|
|
{ TDbgAddressMapHashList }
|
|
|
|
function TDbgAddressMapHashList.ItemFromNode(ANode: THTCustomNode
|
|
): TDbgAddressMap;
|
|
begin
|
|
Result := THTGNode(ANode).Data;
|
|
end;
|
|
|
|
function TDbgAddressMapHashList.ItemPointerFromNode(ANode: THTCustomNode
|
|
): PDbgAddressMap;
|
|
begin
|
|
Result := @THTGNode(ANode).Data;
|
|
end;
|
|
|
|
class operator TDbgAddressMap.=(r1,r2: TDbgAddressMap) : boolean;
|
|
begin
|
|
result := (r1.OrgAddr=r2.OrgAddr) and (r1.Length=r2.Length) and (r1.NewAddr=r2.NewAddr);
|
|
end;
|
|
|
|
function GetImageReader(ASource: TDbgFileLoader; ADebugMap: TObject; ALoadedTargetImageAddr: TDbgPtr; OwnSource: Boolean): TDbgImageReader;
|
|
var
|
|
i : Integer;
|
|
cls : TDbgImageReaderClass;
|
|
begin
|
|
Result := nil;
|
|
if not Assigned(ASource) then Exit;
|
|
|
|
for i := 0 to RegisteredImageReaderClasses.Count - 1 do begin
|
|
cls := TDbgImageReaderClass(RegisteredImageReaderClasses[i]);
|
|
try
|
|
if cls.isValid(ASource) then begin
|
|
Result := cls.Create(ASource, ADebugMap, ALoadedTargetImageAddr, OwnSource);
|
|
ASource.Close;
|
|
Exit;
|
|
end
|
|
else
|
|
;
|
|
except
|
|
on e: exception do begin
|
|
//writeln('exception! WHY? ', e.Message);
|
|
end;
|
|
end;
|
|
end;
|
|
ASource.Close;
|
|
Result := nil;
|
|
end;
|
|
|
|
procedure RegisterImageReaderClass( DataSource: TDbgImageReaderClass);
|
|
begin
|
|
if Assigned(DataSource) and (RegisteredImageReaderClasses.IndexOf(DataSource) < 0) then
|
|
RegisteredImageReaderClasses.Add(DataSource)
|
|
end;
|
|
|
|
|
|
{$ifdef USE_WIN_FILE_MAPPING}
|
|
type
|
|
TGetFinalPathNameByHandle = function(hFile: THandle; lpszFilePath: PWideChar; cchFilePath, dwFlags: DWORD): DWORD; stdcall;
|
|
var
|
|
GetFinalPathNameByHandle: TGetFinalPathNameByHandle = nil;
|
|
function GetFinalPathNameByHandleDummy(hFile: THandle; lpszFilePath: PWideChar; cchFilePath, dwFlags: DWORD): DWORD; stdcall;
|
|
begin
|
|
Result := 0;
|
|
end;
|
|
function FileHandleToFileName(Handle : THandle): string;
|
|
var
|
|
U: WideString;
|
|
hmod: HMODULE;
|
|
begin
|
|
if not Assigned(GetFinalPathNameByHandle) then
|
|
begin
|
|
hmod := GetModuleHandle('kernel32');
|
|
if hmod <> 0 then
|
|
Pointer(GetFinalPathNameByHandle) := GetProcAddress(hmod,'GetFinalPathNameByHandleW');
|
|
if not Assigned(GetFinalPathNameByHandle) then
|
|
GetFinalPathNameByHandle := @GetFinalPathNameByHandleDummy;
|
|
end;
|
|
|
|
SetLength(U, MAX_PATH+1);
|
|
SetLength(U, GetFinalPathNameByHandle(Handle, @U[1], Length(U), 0));
|
|
// if Copy(U, 1, 4)='\\?\' then
|
|
// Delete(U, 1, 4);
|
|
Result := U;
|
|
end;
|
|
{$endif}
|
|
|
|
{ TDbgFileLoader }
|
|
|
|
{$ifdef USE_WIN_FILE_MAPPING}
|
|
function CreateFileW(lpFileName:LPCWSTR; dwDesiredAccess:DWORD; dwShareMode:DWORD; lpSecurityAttributes:LPSECURITY_ATTRIBUTES; dwCreationDisposition:DWORD;dwFlagsAndAttributes:DWORD; hTemplateFile:HANDLE):HANDLE; stdcall; external 'kernel32' name 'CreateFileW';
|
|
{$ENDIF}
|
|
|
|
function TDbgFileLoader.GetFileName: String;
|
|
begin
|
|
{$ifdef USE_WIN_FILE_MAPPING}
|
|
if (FFileName = '') and (FFileHandle <> 0) then begin
|
|
FFileName := FileHandleToFileName(FFileHandle);
|
|
end;
|
|
{$endif}
|
|
Result := FFileName;
|
|
end;
|
|
|
|
constructor TDbgFileLoader.Create(AFileName: String);
|
|
{$IFDEF MacOS}
|
|
var
|
|
s: String;
|
|
{$ENDIF}
|
|
{$ifdef USE_WIN_FILE_MAPPING}
|
|
var
|
|
s: UnicodeString;
|
|
{$ENDIF}
|
|
begin
|
|
{$ifdef USE_WIN_FILE_MAPPING}
|
|
FFileName := AFileName;
|
|
s := UTF8Decode(AFileName);
|
|
FFileHandle := CreateFileW(PWideChar(s), GENERIC_READ, FILE_SHARE_READ, nil, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, 0);
|
|
Create(FFileHandle);
|
|
{$else}
|
|
FList := TList.Create;
|
|
{$IFDEF MacOS}
|
|
if (RightStr(AFileName,4) = '.app') then begin
|
|
s := ExtractFileName(AFileName);
|
|
s := AFileName + PathDelim + 'Contents' + PathDelim + 'MacOS' + PathDelim + copy(s, 1, Length(s) - 4);
|
|
if (FileExists(s)) then AFileName := s
|
|
end;
|
|
{$ENDIF}
|
|
FFileName := AFileName;
|
|
FStream := TFileStream.Create(AFileName, fmOpenRead or fmShareDenyNone);
|
|
inherited Create;
|
|
{$endif}
|
|
end;
|
|
|
|
{$ifdef USE_WIN_FILE_MAPPING}
|
|
constructor TDbgFileLoader.Create(AFileHandle: THandle);
|
|
begin
|
|
FFileHandle := AFileHandle;
|
|
if FFileHandle = INVALID_HANDLE_VALUE
|
|
then begin
|
|
raise Exception.Create('Invalid file handle');
|
|
end;
|
|
|
|
FMapHandle := CreateFileMapping(FFileHandle, nil, PAGE_READONLY{ or SEC_IMAGE}, 0, 0, nil);
|
|
if FMapHandle = 0
|
|
then begin
|
|
if GetLastError = 8 then begin // not enough memory, use a stream instead
|
|
FList := TList.Create;
|
|
FStream := THandleStream.Create(AFileHandle);
|
|
inherited Create;
|
|
exit;
|
|
end;
|
|
|
|
raise Exception.CreateFmt('Could not create module mapping, error %d', [GetLastError]);
|
|
Exit;
|
|
end;
|
|
|
|
FModulePtr := MapViewOfFile(FMapHandle, FILE_MAP_READ, 0, 0, 0);
|
|
if FModulePtr = nil
|
|
then begin
|
|
if GetLastError = 8 then begin // not enough memory, use a stream instead
|
|
CloseHandle(FMapHandle);
|
|
FMapHandle := 0;
|
|
FList := TList.Create;
|
|
FStream := THandleStream.Create(AFileHandle);
|
|
inherited Create;
|
|
exit;
|
|
end;
|
|
raise Exception.Create('Could not map view: ' + IntToStr(GetLastOSError));
|
|
Exit;
|
|
end;
|
|
|
|
inherited Create;
|
|
end;
|
|
{$endif}
|
|
|
|
destructor TDbgFileLoader.Destroy;
|
|
begin
|
|
{$ifdef USE_WIN_FILE_MAPPING}
|
|
if FModulePtr <> nil
|
|
then UnmapViewOfFile(FModulePtr);
|
|
if FMapHandle <> 0
|
|
then CloseHandle(FMapHandle);
|
|
if FFileHandle <> INVALID_HANDLE_VALUE
|
|
then CloseHandle(FFileHandle);
|
|
{$endif}
|
|
if FList <> nil then
|
|
while FList.Count > 0 do
|
|
UnloadMemory(FList[0]);
|
|
FreeAndNil(FList);
|
|
FreeAndNil(FStream);
|
|
inherited Destroy;
|
|
end;
|
|
|
|
procedure TDbgFileLoader.OpenStream;
|
|
begin
|
|
if FStream <> nil then
|
|
exit;
|
|
if FFileName <> '' then
|
|
FStream := TFileStream.Create(FFileName, fmOpenRead or fmShareDenyNone)
|
|
{$ifdef USE_WIN_FILE_MAPPING}
|
|
else
|
|
FStream := THandleStream.Create(FFileHandle)
|
|
{$endif}
|
|
;
|
|
end;
|
|
|
|
procedure TDbgFileLoader.Close;
|
|
begin
|
|
FreeAndNil(FStream);
|
|
end;
|
|
|
|
function TDbgFileLoader.Read(AOffset, ASize: QWord; AMem: Pointer): QWord;
|
|
begin
|
|
{$ifdef USE_WIN_FILE_MAPPING}
|
|
if FMapHandle <> 0 then begin
|
|
move((FModulePtr + AOffset)^, AMem^, ASize);
|
|
Result := ASize;
|
|
exit;
|
|
end;
|
|
{$endif}
|
|
Result := 0;
|
|
if AMem = nil then
|
|
exit;
|
|
if FStream = nil then
|
|
OpenStream;
|
|
FStream.Position := AOffset;
|
|
Result := FStream.Read(AMem^, ASize);
|
|
end;
|
|
|
|
function TDbgFileLoader.LoadMemory(AOffset, ASize: QWord; out AMem: Pointer): QWord;
|
|
begin
|
|
{$ifdef USE_WIN_FILE_MAPPING}
|
|
if FMapHandle <> 0 then begin
|
|
AMem := FModulePtr + AOffset;
|
|
Result := ASize;
|
|
exit;
|
|
end;
|
|
{$endif}
|
|
Result := 0;
|
|
AMem := AllocMem(ASize);
|
|
if AMem = nil then
|
|
exit;
|
|
if FStream = nil then
|
|
OpenStream;
|
|
FList.Add(AMem);
|
|
FStream.Position := AOffset;
|
|
Result := FStream.Read(AMem^, ASize);
|
|
end;
|
|
|
|
procedure TDbgFileLoader.UnloadMemory(AMem: Pointer);
|
|
begin
|
|
if FList = nil then
|
|
exit;
|
|
FList.Remove(AMem);
|
|
Freemem(AMem);
|
|
end;
|
|
|
|
{ TDbgImageReader }
|
|
|
|
function TDbgImageReader.GetAddressMapList: TDbgAddressMapList;
|
|
begin
|
|
result := nil;
|
|
end;
|
|
|
|
function TDbgImageReader.GetSubFiles: TStrings;
|
|
begin
|
|
result := nil;
|
|
end;
|
|
|
|
procedure TDbgImageReader.SetUUID(AGuid: TGuid);
|
|
begin
|
|
FUUID := AGuid;
|
|
end;
|
|
|
|
procedure TDbgImageReader.SetImageBase(ABase: QWord);
|
|
begin
|
|
FImageBase := ABase;
|
|
if FLoadedTargetImageAddr = 0 then
|
|
FLoadedTargetImageAddr := ABase;
|
|
end;
|
|
|
|
procedure TDbgImageReader.SetImageSize(ASize: QWord);
|
|
begin
|
|
FImageSize := ASize;
|
|
end;
|
|
|
|
procedure TDbgImageReader.SetRelocationOffset(AnOffset: QWord);
|
|
begin
|
|
FRelocationOffset := AnOffset;
|
|
end;
|
|
|
|
procedure TDbgImageReader.AddReaderError(AnError: String);
|
|
begin
|
|
if FReaderErrors <> '' then
|
|
FReaderErrors := FReaderErrors + LineEnding;
|
|
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(DBG_WARNINGS and (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
|
|
// platform. That's why parsing the data is done in TDbgImageReader.
|
|
end;
|
|
|
|
procedure TDbgImageReader.ParseLibrarySymbolTable(AFpSymbolInfo: TfpSymbolList);
|
|
begin
|
|
//
|
|
end;
|
|
|
|
constructor TDbgImageReader.Create(ASource: TDbgFileLoader; ADebugMap: TObject; ALoadedTargetImageAddr: TDbgPtr; OwnSource: Boolean);
|
|
begin
|
|
inherited Create;
|
|
FLoadedTargetImageAddr := ALoadedTargetImageAddr;
|
|
end;
|
|
|
|
procedure TDbgImageReader.AddSubFilesToLoaderList(ALoaderList: TObject;
|
|
PrimaryLoader: TObject);
|
|
begin
|
|
//
|
|
end;
|
|
|
|
function TDbgImageReader.EnclosesAddressRange(AStartAddress, AnEndAddress: TDBGPtr): Boolean;
|
|
begin
|
|
Result := False;
|
|
end;
|
|
|
|
procedure InitDebugInfoLists;
|
|
begin
|
|
RegisteredImageReaderClasses := TFPList.Create;
|
|
end;
|
|
|
|
procedure ReleaseDebugInfoLists;
|
|
begin
|
|
FreeAndNil(RegisteredImageReaderClasses);
|
|
end;
|
|
|
|
initialization
|
|
DBG_WARNINGS := DebugLogger.FindOrRegisterLogGroup('DBG_WARNINGS' {$IFDEF DBG_WARNINGS} , True {$ENDIF} );
|
|
|
|
InitDebugInfoLists;
|
|
|
|
finalization
|
|
ReleaseDebugInfoLists;
|
|
|
|
end.
|
|
|