lazarus/components/fpdebug/fpdmemorytools.pas
mattias 27e32c8bad lazdebuggerfp: clean up
git-svn-id: trunk@46944 -
2014-11-21 23:44:10 +00:00

764 lines
29 KiB
ObjectPascal

unit FpdMemoryTools;
{$mode objfpc}{$H+}
(* Tools to read data from Target or Own memory.
This is to deal in one place with all conversion of data from target format
to debugger format.
A typical read would involve the following steps:
The code calls MemoryManager with an Address, a Size and a space for the data.
If the data needs to be extended (SizeOf(data) > TargetSize), then
MemConvertor is called to decide where in the provided space the read data
should initially be stored.
Then the data is read using MemReader.
And finally MemConvertor is given a chance to extend or convert the data.
*)
interface
uses
Classes, SysUtils, math, DbgIntfBaseTypes, FpErrorMessages, LazClasses;
type
TFpDbgAddressContext = class(TRefCountedObject)
protected
function GetAddress: TDbgPtr; virtual; abstract;
function GetStackFrame: Integer; virtual; abstract;
function GetThreadId: Integer; virtual; abstract;
function GetSizeOfAddress: Integer; virtual; abstract;
public
property Address: TDbgPtr read GetAddress;
property ThreadId: Integer read GetThreadId;
property StackFrame: Integer read GetStackFrame;
property SizeOfAddress: Integer read GetSizeOfAddress;
end;
TFpDbgMemReaderBase = class
public
function ReadMemory(AnAddress: TDbgPtr; ASize: Cardinal; ADest: Pointer): Boolean; virtual; abstract;
function ReadMemoryEx(AnAddress, AnAddressSpace: TDbgPtr; ASize: Cardinal; ADest: Pointer): Boolean; virtual; abstract;
// ReadRegister may need TargetMemConvertor
// Register with reduced size are treated as unsigned
// TODO: ReadRegister should only take THREAD-ID, not context
function ReadRegister(ARegNum: Cardinal; out AValue: TDbgPtr; AContext: TFpDbgAddressContext): Boolean; virtual; abstract;
function RegisterSize(ARegNum: Cardinal): Integer; virtual; abstract;
// Registernum from name
end;
(* Options for all read operation // TODO *)
TFpDbgMemReadOptions = record
(* potential flags
target bit start/shift (method to map dwarf2/3 bit offse to dwarf 4
target bit size
target assume big/little endian
float precisson
AddressSpace
( rmBigEndian, rmLittleEndian, rmUseAddressSpace, UseBitSize)
AddressSpace, BitOffset, precission
*)
end;
TFpDbgMemReadDataType = (
rdtAddress, rdtSignedInt, rdtUnsignedInt, rdtfloat,
rdtEnum, rdtSet
);
TFpDbgMemConvData = record
NewTargetAddress: TDbgPtr;
NewDestAddress: Pointer;
NewReadSize: Cardinal;
PrivData1, PrivData2: Pointer;
end;
// Todo, cpu/language specific operations, endianess, sign extend, float .... default int value for bool
// convert from debugge format to debuger format and back
// TODO: currently it assumes target and own mem are in the same format
TFpDbgMemConvertor = class
public
(* PrepareTargetRead
called before every Read operation.
In case of reading from a bit-offset more memory may be needed, and must be allocated here
*)
function PrepareTargetRead(AReadDataType: TFpDbgMemReadDataType;
ATargetPointer: TDbgPtr; ADestPointer: Pointer;
ATargetSize, ADestSize: Cardinal;
out AConvertorData: TFpDbgMemConvData
): boolean; virtual; abstract;
{function PrepareTargetRead(AReadDataType: TFpDbgMemReadDataType;
ATargetPointer: TDbgPtr; ADestPointer: Pointer;
ATargetSize, ADestSize: Cardinal;
AnOpts: TFpDbgMemReadOptions;
out AConvertorData: TFpDbgMemConvData
): boolean; virtual; abstract;}
(* FinishTargetRead
called after every Read operation.
*)
function FinishTargetRead(AReadDataType: TFpDbgMemReadDataType;
ATargetPointer: TDbgPtr; ADestPointer: Pointer;
ATargetSize, ADestSize: Cardinal;
AConvertorData: TFpDbgMemConvData
): boolean; virtual; abstract;
{function FinishTargetRead(AReadDataType: TFpDbgMemReadDataType;
ATargetPointer: TDbgPtr; ADestPointer: Pointer;
ATargetSize, ADestSize: Cardinal;
AnOpts: TFpDbgMemReadOptions;
AConvertorData: TFpDbgMemConvData
): boolean; virtual; abstract;}
// just to free any data
procedure FailedTargetRead(AConvertorData: TFpDbgMemConvData); virtual; abstract;
(* AdjustIntPointer:
To copy a smaller int/cardinal (e.g. word) into a bigger (e.g. dword),
adjust ADestPointer so it points to the low value part of the dest
No conversion
*)
procedure AdjustIntPointer(var ADataPointer: Pointer; ADataSize, ANewSize: Cardinal); virtual; abstract;
//(* SignExtend:
// Expects a signed integer value of ASourceSize bytes in the low value end
// of the memory (total memory ADataPointer, ADestSize)
// Does zero fill the memory, if no sign extend is needed
//*)
//procedure SignExtend(ADataPointer: Pointer; ASourceSize, ADestSize: Cardinal); virtual; abstract;
//(* Expects an unsigned integer value of ASourceSize bytes in the low value end
// of the memory (total memory ADataPointer, ADestSize)
// Basically zero fill the memory
//*)
//procedure UnsignedExtend(ADataPointer: Pointer; ASourceSize, ADestSize: Cardinal); virtual; abstract;
end;
{ TFpDbgMemConvertorLittleEndian }
TFpDbgMemConvertorLittleEndian = class(TFpDbgMemConvertor)
public
function PrepareTargetRead(AReadDataType: TFpDbgMemReadDataType;
ATargetPointer: TDbgPtr; ADestPointer: Pointer;
ATargetSize, ADestSize: Cardinal;
out AConvertorData: TFpDbgMemConvData
): boolean; override;
function FinishTargetRead(AReadDataType: TFpDbgMemReadDataType;
{%H-}ATargetPointer: TDbgPtr; ADestPointer: Pointer;
ATargetSize, ADestSize: Cardinal;
{%H-}AConvertorData: TFpDbgMemConvData
): boolean; override;
procedure FailedTargetRead({%H-}AConvertorData: TFpDbgMemConvData); override;
procedure AdjustIntPointer(var {%H-}ADataPointer: Pointer; ADataSize, ANewSize: Cardinal); override;
//procedure SignExtend(ADataPointer: Pointer; ASourceSize, ADestSize: Cardinal); override;
//procedure UnsignedExtend(ADataPointer: Pointer; ASourceSize, ADestSize: Cardinal); override;
end;
(* TFpDbgMemManager
* allows to to pretend reading from the target, by using its own memory, or
a constant.
This is useful if an object expects to read data from the target, but the
caller needs to "fake" another value.
E.g. A TObject variable has the address of the (internal) pointer to the
object data:
SomeMethod expects "Address of variable". At that address in the target
memory it expects another address, the pointer to the object data.
But when doing "TObject(1234)" then 1234 is the pointer to the object data.
1234 can not be read from the target memory. MemManager will pretend.
* Provides access to TFpDbgMemConvertor
* TODO: allow to pre-read and cache Target mem (e.g. before reading all fields of a record
*)
TFpDbgMemLocationType = (
mlfUninitialized := 0, // like invalid, but not known // 0 means objet fields will start wint this
mlfInvalid,
mlfTargetMem, // an address in the target (debuggee) process
mlfSelfMem, // an address in this(the debuggers) process memory; the data is in TARGET format (endian, ...)
// the below will be mapped (and extended) according to endianess
mlfTargetRegister, // reads from the register
mlfConstant // an (up to) SizeOf(TDbgPtr) (=8) Bytes Value (endian in format of debug process)
);
TFpDbgMemLocation = record
Address: TDbgPtr;
MType: TFpDbgMemLocationType;
end;
{ TFpDbgMemManager }
TFpDbgMemManager = class
private
FDefaultContext: TFpDbgAddressContext;
FLastError: TFpError;
FMemReader: TFpDbgMemReaderBase;
FTargetMemConvertor: TFpDbgMemConvertor;
FSelfMemConvertor: TFpDbgMemConvertor; // used when resizing constants (or register values, which are already in self format)
protected
function ReadMemory(AReadDataType: TFpDbgMemReadDataType;
const ALocation: TFpDbgMemLocation; ATargetSize: Cardinal;
ADest: Pointer; ADestSize: Cardinal;
AContext: TFpDbgAddressContext = nil): Boolean;
public
constructor Create(AMemReader: TFpDbgMemReaderBase; AMemConvertor: TFpDbgMemConvertor);
constructor Create(AMemReader: TFpDbgMemReaderBase; ATargenMemConvertor, ASelfMemConvertor: TFpDbgMemConvertor);
procedure ClearLastError;
function ReadMemory(const ALocation: TFpDbgMemLocation; ASize: Cardinal;
ADest: Pointer; AContext: TFpDbgAddressContext = nil): Boolean;
function ReadMemoryEx(const ALocation: TFpDbgMemLocation; AnAddressSpace: TDbgPtr; ASize: Cardinal; ADest: Pointer; AContext: TFpDbgAddressContext = nil): Boolean;
(* ReadRegister needs a Context, to get the thread/stackframe
*)
function ReadRegister(ARegNum: Cardinal; out AValue: TDbgPtr; AContext: TFpDbgAddressContext {= nil}): Boolean;
// location will be invalid, if read failed
function ReadAddress(const ALocation: TFpDbgMemLocation; ASize: Cardinal;
AContext: TFpDbgAddressContext = nil): TFpDbgMemLocation;
function ReadAddressEx(const ALocation: TFpDbgMemLocation; AnAddressSpace: TDbgPtr;
ASize: Cardinal; AContext: TFpDbgAddressContext = nil): TFpDbgMemLocation;
// ALocation and AnAddress MUST NOT be the same variable on the callers side
function ReadAddress (const ALocation: TFpDbgMemLocation; ASize: Cardinal;
out AnAddress: TFpDbgMemLocation;
AContext: TFpDbgAddressContext = nil): Boolean; inline;
//function ReadAddress (const ALocation: TFpDbgMemLocation; ASize: Cardinal;
// out AnAddress: TFpDbgMemLocation;
// AnOpts: TFpDbgMemReadOptions; AContext: TFpDbgAddressContext = nil): Boolean;
function ReadUnsignedInt(const ALocation: TFpDbgMemLocation; ASize: Cardinal;
out AValue: QWord; AContext: TFpDbgAddressContext = nil): Boolean; inline;
//function ReadUnsignedInt(const ALocation: TFpDbgMemLocation; ASize: Cardinal;
// out AValue: QWord;
// AnOpts: TFpDbgMemReadOptions; AContext: TFpDbgAddressContext = nil): Boolean;
function ReadSignedInt (const ALocation: TFpDbgMemLocation; ASize: Cardinal;
out AValue: Int64; AContext: TFpDbgAddressContext = nil): Boolean; inline;
//function ReadSignedInt (const ALocation: TFpDbgMemLocation; ASize: Cardinal;
// out AValue: Int64;
// AnOpts: TFpDbgMemReadOptions; AContext: TFpDbgAddressContext = nil): Boolean;
// //enum/set: may need bitorder swapped
function ReadEnum (const ALocation: TFpDbgMemLocation; ASize: Cardinal;
out AValue: QWord; AContext: TFpDbgAddressContext = nil): Boolean; inline;
//function ReadEnum (const ALocation: TFpDbgMemLocation; ASize: Cardinal;
// out AValue: QWord;
// AnOpts: TFpDbgMemReadOptions; AContext: TFpDbgAddressContext = nil): Boolean;
function ReadSet (const ALocation: TFpDbgMemLocation; ASize: Cardinal;
out AValue: TBytes; AContext: TFpDbgAddressContext = nil): Boolean; inline;
//function ReadSet (const ALocation: TFpDbgMemLocation; ASize: Cardinal;
// out AValue: TBytes;
// AnOpts: TFpDbgMemReadOptions; AContext: TFpDbgAddressContext = nil): Boolean;
function ReadFloat (const ALocation: TFpDbgMemLocation; ASize: Cardinal;
out AValue: Extended; AContext: TFpDbgAddressContext = nil): Boolean; inline;
//function ReadFloat (const ALocation: TFpDbgMemLocation; ASize: Cardinal;
// out AValue: Extended;
// AnOpts: TFpDbgMemReadOptions; AContext: TFpDbgAddressContext = nil): Boolean;
property TargetMemConvertor: TFpDbgMemConvertor read FTargetMemConvertor;
property SelfMemConvertor: TFpDbgMemConvertor read FSelfMemConvertor;
property LastError: TFpError read FLastError;
property DefaultContext: TFpDbgAddressContext read FDefaultContext write FDefaultContext;
end;
function NilLoc: TFpDbgMemLocation; inline;
function InvalidLoc: TFpDbgMemLocation; inline;
function UnInitializedLoc: TFpDbgMemLocation; inline;
function TargetLoc(AnAddress: TDbgPtr): TFpDbgMemLocation; inline;
function RegisterLoc(ARegNum: Cardinal): TFpDbgMemLocation; inline;
function SelfLoc(AnAddress: TDbgPtr): TFpDbgMemLocation; inline;
function SelfLoc(AnAddress: Pointer): TFpDbgMemLocation; inline;
function ConstLoc(AValue: QWord): TFpDbgMemLocation; inline;
function IsTargetAddr(ALocation: TFpDbgMemLocation): Boolean; inline;
function IsInitializedLoc(ALocation: TFpDbgMemLocation): Boolean; inline;
function IsValidLoc(ALocation: TFpDbgMemLocation): Boolean; inline; // Valid, Nil allowed
function IsReadableLoc(ALocation: TFpDbgMemLocation): Boolean; inline; // Valid and not Nil // can be const or reg
function IsReadableMem(ALocation: TFpDbgMemLocation): Boolean; inline; // Valid and target or sel <> nil
function IsTargetNil(ALocation: TFpDbgMemLocation): Boolean; inline; // valid targed = nil
function IsTargetNotNil(ALocation: TFpDbgMemLocation): Boolean; inline; // valid targed <> nil
function LocToAddr(ALocation: TFpDbgMemLocation): TDbgPtr; inline; // does not check valid
function LocToAddrOrNil(ALocation: TFpDbgMemLocation): TDbgPtr; inline; // save version
function EmptyMemReadOpts:TFpDbgMemReadOptions;
function dbgs(ALocation: TFpDbgMemLocation): String; overload;
implementation
function NilLoc: TFpDbgMemLocation;
begin
Result.Address := 0;
Result.MType := mlfTargetMem;
end;
function InvalidLoc: TFpDbgMemLocation;
begin
Result.Address := 0;
Result.MType := mlfInvalid;
end;
function UnInitializedLoc: TFpDbgMemLocation;
begin
Result.Address := 0;
Result.MType := mlfUninitialized;
end;
function TargetLoc(AnAddress: TDbgPtr): TFpDbgMemLocation;
begin
Result.Address := AnAddress;
Result.MType := mlfTargetMem;
end;
function RegisterLoc(ARegNum: Cardinal): TFpDbgMemLocation;
begin
Result.Address := ARegNum;
Result.MType := mlfTargetRegister;
end;
function SelfLoc(AnAddress: TDbgPtr): TFpDbgMemLocation;
begin
Result.Address := AnAddress;
Result.MType := mlfSelfMem;
end;
function SelfLoc(AnAddress: Pointer): TFpDbgMemLocation;
begin
Result.Address := TDbgPtr(AnAddress);
Result.MType := mlfSelfMem;
end;
function ConstLoc(AValue: QWord): TFpDbgMemLocation;
begin
Result.Address := AValue;
Result.MType := mlfConstant;
end;
function IsTargetAddr(ALocation: TFpDbgMemLocation): Boolean;
begin
Result := ALocation.MType = mlfTargetMem;
end;
function IsInitializedLoc(ALocation: TFpDbgMemLocation): Boolean;
begin
Result := ALocation.MType <> mlfUninitialized;
end;
function IsValidLoc(ALocation: TFpDbgMemLocation): Boolean;
begin
Result := not(ALocation.MType in [mlfInvalid, mlfUninitialized]);
end;
function IsReadableLoc(ALocation: TFpDbgMemLocation): Boolean;
begin
Result := (not(ALocation.MType in [mlfInvalid, mlfUninitialized])) and
( (not(ALocation.MType in [mlfTargetMem, mlfSelfMem])) or
(ALocation.Address <> 0)
);
end;
function IsReadableMem(ALocation: TFpDbgMemLocation): Boolean;
begin
Result := (ALocation.MType in [mlfTargetMem, mlfSelfMem]) and
(ALocation.Address <> 0);
end;
function IsTargetNil(ALocation: TFpDbgMemLocation): Boolean;
begin
Result := (ALocation.MType = mlfTargetMem) and (ALocation.Address = 0);
end;
function IsTargetNotNil(ALocation: TFpDbgMemLocation): Boolean;
begin
Result := (ALocation.MType = mlfTargetMem) and (ALocation.Address <> 0);
end;
function LocToAddr(ALocation: TFpDbgMemLocation): TDbgPtr;
begin
assert(ALocation.MType = mlfTargetMem, 'LocToAddr for other than mlfTargetMem');
Result := ALocation.Address;
end;
function LocToAddrOrNil(ALocation: TFpDbgMemLocation): TDbgPtr;
begin
if (ALocation.MType = mlfTargetMem) then
Result := ALocation.Address
else
Result := 0;
end;
function {%H-}EmptyMemReadOpts: TFpDbgMemReadOptions;
begin
//
end;
function dbgs(ALocation: TFpDbgMemLocation): String;
begin
Result := '';
if not (ALocation.MType in [low(TFpDbgMemLocationType)..high(TFpDbgMemLocationType)]) then
Result := 'Location=out-of-range'
else
WriteStr(Result, 'Location=', ALocation.Address, ',', ALocation.MType)
end;
{ TFpDbgMemConvertorLittleEndian }
function TFpDbgMemConvertorLittleEndian.PrepareTargetRead(AReadDataType: TFpDbgMemReadDataType;
ATargetPointer: TDbgPtr; ADestPointer: Pointer; ATargetSize, ADestSize: Cardinal; out
AConvertorData: TFpDbgMemConvData): boolean;
begin
Result := ATargetSize <= ADestSize;
if not Result then
exit;
// just read to begin of data
AConvertorData.NewTargetAddress := ATargetPointer;
AConvertorData.NewDestAddress := ADestPointer;
AConvertorData.NewReadSize := Min(ATargetSize, ADestSize);
case AReadDataType of
rdtAddress, rdtSignedInt, rdtUnsignedInt,
rdtEnum, rdtSet: ;
rdtfloat:
Result := (ATargetSize = AConvertorData.NewReadSize) and
(ADestSize = SizeOf(Extended)) and // only can read to extended... TODO (if need more)
( (ATargetSize = SizeOf(Extended)) or
(ATargetSize = SizeOf(Double)) or
(ATargetSize = SizeOf(Single)) or
(ATargetSize = SizeOf(real48))
)
else begin
Assert(False, 'TFpDbgMemConvertorLittleEndian.PrepareTargetRead');
Result := False;
end;
end;
end;
function TFpDbgMemConvertorLittleEndian.FinishTargetRead(AReadDataType: TFpDbgMemReadDataType;
ATargetPointer: TDbgPtr; ADestPointer: Pointer; ATargetSize, ADestSize: Cardinal;
AConvertorData: TFpDbgMemConvData): boolean;
type
Preal48 = ^real48;
begin
Result := True;
case AReadDataType of
rdtAddress, rdtUnsignedInt, rdtEnum, rdtSet: begin
if ATargetSize < ADestSize then
FillByte((ADestPointer + ATargetSize)^, ADestSize-ATargetSize, $00)
end;
rdtSignedInt: begin
if ATargetSize < ADestSize then
if (ATargetSize > 0) and ((PByte(ADestPointer + ATargetSize - 1)^ and $80) <> 0)
then
FillByte((ADestPointer + ATargetSize)^, ADestSize-ATargetSize, $FF)
else
FillByte((ADestPointer + ATargetSize)^, ADestSize-ATargetSize, $00);
end;
rdtfloat: begin
assert((ADestSize = SizeOf(Extended)));
if (ATargetSize = SizeOf(Extended)) then
//
else
if (ATargetSize = SizeOf(Double)) then
PExtended(ADestPointer)^ := PDouble(ADestPointer)^
else
if (ATargetSize = SizeOf(real48)) then
PExtended(ADestPointer)^ := Preal48(ADestPointer)^
else
if (ATargetSize = SizeOf(Single)) then
PExtended(ADestPointer)^ := PSingle(ADestPointer)^
else
Result := False;
end;
else begin
Assert(False, 'TFpDbgMemConvertorLittleEndian.FailedTargetRead');
Result := False;
end;
end;
end;
procedure TFpDbgMemConvertorLittleEndian.FailedTargetRead(AConvertorData: TFpDbgMemConvData);
begin
//
end;
procedure TFpDbgMemConvertorLittleEndian.AdjustIntPointer(var ADataPointer: Pointer;
ADataSize, ANewSize: Cardinal);
begin
Assert(ANewSize <= ADataSize, 'TFpDbgMemConvertorLittleEndian.AdjustIntPointer');
// no adjustment needed
end;
//procedure TFpDbgMemConvertorLittleEndian.SignExtend(ADataPointer: Pointer; ASourceSize,
// ADestSize: Cardinal);
//begin
// Assert(ASourceSize > 0, 'TFpDbgMemConvertorLittleEndian.SignExtend');
// if ASourceSize >= ADestSize then
// exit;
//
// if (PByte(ADataPointer + ASourceSize - 1)^ and $80) <> 0 then
// FillByte((ADataPointer + ASourceSize)^, ADestSize-ASourceSize, $ff)
// else
// FillByte((ADataPointer + ASourceSize)^, ADestSize-ASourceSize, $00)
//end;
//
//procedure TFpDbgMemConvertorLittleEndian.UnsignedExtend(ADataPointer: Pointer;
// ASourceSize, ADestSize: Cardinal);
//begin
// Assert(ASourceSize > 0, 'TFpDbgMemConvertorLittleEndian.SignExtend');
// if ASourceSize >= ADestSize then
// exit;
//
// FillByte((ADataPointer + ASourceSize)^, ADestSize-ASourceSize, $00)
//end;
{ TFpDbgMemManager }
function TFpDbgMemManager.ReadMemory(AReadDataType: TFpDbgMemReadDataType;
const ALocation: TFpDbgMemLocation; ATargetSize: Cardinal; ADest: Pointer;
ADestSize: Cardinal; AContext: TFpDbgAddressContext): Boolean;
var
Addr2: Pointer;
i: Integer;
TmpVal: TDbgPtr;
ConvData: TFpDbgMemConvData;
begin
FLastError := NoError;
Result := False;
if AContext = nil then
AContext := FDefaultContext;
case ALocation.MType of
mlfInvalid, mlfUninitialized:
FLastError := CreateError(fpErrCanNotReadInvalidMem);
mlfTargetMem, mlfSelfMem: begin
Result := TargetMemConvertor.PrepareTargetRead(AReadDataType, ALocation.Address,
ADest, ATargetSize, ADestSize, ConvData);
if not Result then exit;
if ALocation.MType = mlfTargetMem then begin
Result := FMemReader.ReadMemory(ConvData.NewTargetAddress, ConvData.NewReadSize, ConvData.NewDestAddress);
if not Result then
FLastError := CreateError(fpErrCanNotReadMemAtAddr, [ALocation.Address]);
end
else
begin
try
move(Pointer(ConvData.NewTargetAddress)^, ConvData.NewDestAddress^, ConvData.NewReadSize);
Result := True;
except
Result := False;
end;
end;
if Result then
Result := TargetMemConvertor.FinishTargetRead(AReadDataType, ALocation.Address,
ADest, ATargetSize, ADestSize, ConvData)
else
TargetMemConvertor.FailedTargetRead(ConvData);
end;
mlfConstant, mlfTargetRegister:
begin
case ALocation.MType of
mlfConstant: begin
TmpVal := ALocation.Address;
i := SizeOf(ALocation.Address);
end;
mlfTargetRegister: begin
i := FMemReader.RegisterSize(Cardinal(ALocation.Address));
if i = 0 then
exit; // failed
if not FMemReader.ReadRegister(Cardinal(ALocation.Address), TmpVal, AContext) then
exit; // failed
end;
end;
if i > ATargetSize then
i := ATargetSize;
Addr2 := @TmpVal;
if SizeOf(TmpVal) <> i then
FSelfMemConvertor.AdjustIntPointer(Addr2, SizeOf(TmpVal), i);
Result := FSelfMemConvertor.PrepareTargetRead(AReadDataType, TDbgPtr(Addr2),
ADest, i, ADestSize, ConvData);
if not Result then exit;
move(Pointer(ConvData.NewTargetAddress)^, ConvData.NewDestAddress^, ConvData.NewReadSize);
Result := TargetMemConvertor.FinishTargetRead(AReadDataType, TDbgPtr(Addr2),
ADest, i, ADestSize, ConvData);
Result := True;
end;
end;
if (not Result) and (not IsError(FLastError)) then
FLastError := CreateError(fpErrFailedReadMem);
end;
constructor TFpDbgMemManager.Create(AMemReader: TFpDbgMemReaderBase;
AMemConvertor: TFpDbgMemConvertor);
begin
FMemReader := AMemReader;
FTargetMemConvertor := AMemConvertor;
FSelfMemConvertor := AMemConvertor;
end;
constructor TFpDbgMemManager.Create(AMemReader: TFpDbgMemReaderBase; ATargenMemConvertor,
ASelfMemConvertor: TFpDbgMemConvertor);
begin
FMemReader := AMemReader;
FTargetMemConvertor := ATargenMemConvertor;
FSelfMemConvertor := ASelfMemConvertor;
end;
procedure TFpDbgMemManager.ClearLastError;
begin
FLastError := NoError;
end;
function TFpDbgMemManager.ReadMemory(const ALocation: TFpDbgMemLocation; ASize: Cardinal;
ADest: Pointer; AContext: TFpDbgAddressContext): Boolean;
var
Addr2: Pointer;
i: Integer;
TmpVal: TDbgPtr;
ConvData: TFpDbgMemConvData;
begin
FLastError := NoError;
Result := False;
if AContext = nil then
AContext := FDefaultContext;
case ALocation.MType of
mlfInvalid, mlfUninitialized: ;
mlfTargetMem:
begin
Result := FMemReader.ReadMemory(ALocation.Address, ASize, ADest);
if not Result then
FLastError := CreateError(fpErrCanNotReadMemAtAddr, [ALocation.Address]);
end;
mlfSelfMem:
begin
move(Pointer(ALocation.Address)^, ADest^, ASize);
Result := True;
end;
mlfConstant, mlfTargetRegister:
begin
case ALocation.MType of
mlfConstant: begin
TmpVal := ALocation.Address;
i := SizeOf(ALocation.Address);
end;
mlfTargetRegister: begin
i := FMemReader.RegisterSize(Cardinal(ALocation.Address));
if i = 0 then
exit; // failed
if not FMemReader.ReadRegister(Cardinal(ALocation.Address), TmpVal, AContext) then
exit; // failed
end;
end;
Addr2 := @TmpVal;
if SizeOf(TmpVal) <> i then
FSelfMemConvertor.AdjustIntPointer(Addr2, SizeOf(TmpVal), i);
Result := FSelfMemConvertor.PrepareTargetRead(rdtUnsignedInt, TDbgPtr(Addr2),
ADest, i, ASize, ConvData);
if not Result then exit;
move(Pointer(ConvData.NewTargetAddress)^, ConvData.NewDestAddress^, ConvData.NewReadSize);
Result := TargetMemConvertor.FinishTargetRead(rdtUnsignedInt, TDbgPtr(Addr2),
ADest, i, ASize, ConvData);
Result := True;
end;
end;
if (not Result) and (not IsError(FLastError)) then
FLastError := CreateError(fpErrFailedReadMem);
end;
function TFpDbgMemManager.ReadMemoryEx(const ALocation: TFpDbgMemLocation;
AnAddressSpace: TDbgPtr; ASize: Cardinal; ADest: Pointer;
AContext: TFpDbgAddressContext): Boolean;
begin
FLastError := NoError;
// AnAddressSpace is ignored, when not actually reading from target address
case ALocation.MType of
mlfTargetMem: Result := FMemReader.ReadMemoryEx(ALocation.Address, AnAddressSpace, ASize, ADest);
else
Result := ReadMemory(ALocation, ASize, ADest, AContext);
end;
if (not Result) and (not IsError(FLastError)) then
FLastError := CreateError(fpErrFailedReadMem);
end;
function TFpDbgMemManager.ReadRegister(ARegNum: Cardinal; out AValue: TDbgPtr;
AContext: TFpDbgAddressContext): Boolean;
begin
FLastError := NoError;
// TODO: If stackframe <> 0 then get the register internally (unroll stack)
if AContext = nil then
AContext := FDefaultContext;
Result := FMemReader.ReadRegister(ARegNum, AValue, AContext);
end;
function TFpDbgMemManager.ReadAddress(const ALocation: TFpDbgMemLocation; ASize: Cardinal;
AContext: TFpDbgAddressContext): TFpDbgMemLocation;
begin
Result.MType := mlfTargetMem;
if not ReadMemory(rdtAddress, ALocation, ASize, @Result.Address, SizeOf(Result.Address), AContext) then
Result := InvalidLoc;
end;
function TFpDbgMemManager.ReadAddressEx(const ALocation: TFpDbgMemLocation;
AnAddressSpace: TDbgPtr; ASize: Cardinal; AContext: TFpDbgAddressContext): TFpDbgMemLocation;
begin
Result := InvalidLoc;
end;
function TFpDbgMemManager.ReadAddress(const ALocation: TFpDbgMemLocation; ASize: Cardinal; out
AnAddress: TFpDbgMemLocation; AContext: TFpDbgAddressContext): Boolean;
begin
Result := ReadMemory(rdtAddress, ALocation, ASize, @AnAddress.Address, SizeOf(AnAddress.Address), AContext);
if Result
then AnAddress.MType := mlfTargetMem
else AnAddress.MType := mlfInvalid;
end;
function TFpDbgMemManager.ReadUnsignedInt(const ALocation: TFpDbgMemLocation; ASize: Cardinal;
out AValue: QWord; AContext: TFpDbgAddressContext): Boolean;
begin
Result := ReadMemory(rdtUnsignedInt, ALocation, ASize, @AValue, SizeOf(AValue), AContext);
end;
function TFpDbgMemManager.ReadSignedInt(const ALocation: TFpDbgMemLocation; ASize: Cardinal;
out AValue: Int64; AContext: TFpDbgAddressContext): Boolean;
begin
Result := ReadMemory(rdtSignedInt, ALocation, ASize, @AValue, SizeOf(AValue), AContext);
end;
function TFpDbgMemManager.ReadEnum(const ALocation: TFpDbgMemLocation; ASize: Cardinal; out
AValue: QWord; AContext: TFpDbgAddressContext): Boolean;
begin
Result := ReadMemory(rdtEnum, ALocation, ASize, @AValue, SizeOf(AValue), AContext);
end;
function TFpDbgMemManager.ReadSet(const ALocation: TFpDbgMemLocation; ASize: Cardinal; out
AValue: TBytes; AContext: TFpDbgAddressContext): Boolean;
begin
SetLength(AValue, ASize);
Result := ASize > 0;
if Result then
Result := ReadMemory(rdtSet, ALocation, ASize, @AValue[0], ASize, AContext);
end;
function TFpDbgMemManager.ReadFloat(const ALocation: TFpDbgMemLocation; ASize: Cardinal; out
AValue: Extended; AContext: TFpDbgAddressContext): Boolean;
begin
Result := ReadMemory(rdtfloat, ALocation, ASize, @AValue, SizeOf(AValue), AContext);
end;
end.