FpDebug: Fixed reading memory for #0 terminated string data

git-svn-id: trunk@63391 -
This commit is contained in:
martin 2020-06-18 18:06:26 +00:00
parent cffa67bd52
commit f59a294a01
4 changed files with 148 additions and 21 deletions

View File

@ -127,7 +127,8 @@ type
function GetDbgProcess: TDbgProcess; virtual; abstract;
function GetDbgThread(AContext: TFpDbgAddressContext): TDbgThread; virtual;
public
function ReadMemory(AnAddress: TDbgPtr; ASize: Cardinal; ADest: Pointer): Boolean; override;
function ReadMemory(AnAddress: TDbgPtr; ASize: Cardinal; ADest: Pointer): Boolean; override; overload;
function ReadMemory(AnAddress: TDbgPtr; ASize: Cardinal; ADest: Pointer; out ABytesRead: Cardinal): Boolean; override; overload;
function ReadMemoryEx(AnAddress, AnAddressSpace: TDbgPtr; ASize: Cardinal; ADest: Pointer): Boolean; override;
function ReadRegister(ARegNum: Cardinal; out AValue: TDbgPtr; AContext: TFpDbgAddressContext): Boolean; override;
function RegisterSize(ARegNum: Cardinal): Integer; override;
@ -1183,6 +1184,12 @@ begin
result := GetDbgProcess.ReadData(AnAddress, ASize, ADest^);
end;
function TDbgMemReader.ReadMemory(AnAddress: TDbgPtr; ASize: Cardinal;
ADest: Pointer; out ABytesRead: Cardinal): Boolean;
begin
result := GetDbgProcess.ReadData(AnAddress, ASize, ADest^, ABytesRead);
end;
function TDbgMemReader.ReadMemoryEx(AnAddress, AnAddressSpace: TDbgPtr; ASize: Cardinal; ADest: Pointer): Boolean;
begin
Assert(AnAddressSpace>0,'TDbgMemReader.ReadMemoryEx ignores AddressSpace');

View File

@ -2075,7 +2075,7 @@ end;
function TFpValueDwarfPointer.GetAsString: AnsiString;
var
t: TFpSymbol;
i: Integer;
i: Cardinal;
Size: TFpDbgValueSize;
begin
Result := '';
@ -2096,13 +2096,14 @@ begin
if (MemManager <> nil) and (t <> nil) and (t.Kind = skChar) and IsReadableMem(GetDerefAddress) then begin // pchar
SetLength(Result, 2000);
i := 2000;
while (i > 0) and (not MemManager.ReadMemory(GetDerefAddress, SizeVal(i), @Result[1])) do
i := i div 2;
if i = 0 then begin
if not MemManager.ReadMemory(GetDerefAddress, SizeVal(i), @Result[1], nil, [mmfPartialRead]) then begin
Result := '';
SetLastError(MemManager.LastError);
exit;
end;
i := MemManager.PartialReadResultLenght;
SetLength(Result,i);
i := pos(#0, Result);
if i > 0 then
@ -2115,7 +2116,7 @@ end;
function TFpValueDwarfPointer.GetAsWideString: WideString;
var
t: TFpSymbol;
i: Integer;
i: Cardinal;
begin
t := TypeInfo;
if (t <> nil) then t := t.TypeInfo;
@ -2123,13 +2124,14 @@ begin
if (MemManager <> nil) and (t <> nil) and (t.Kind = skChar) and IsReadableMem(GetDerefAddress) then begin // pchar
SetLength(Result, 2000);
i := 4000; // 2000 * 16 bit
while (i > 0) and (not MemManager.ReadMemory(GetDerefAddress, SizeVal(i), @Result[1])) do
i := i div 2;
if i = 0 then begin
if not MemManager.ReadMemory(GetDerefAddress, SizeVal(i), @Result[1], nil, [mmfPartialRead]) then begin
Result := '';
SetLastError(MemManager.LastError);
exit;
end;
i := MemManager.PartialReadResultLenght;
SetLength(Result, i div 2);
i := pos(#0, Result);
if i > 0 then

View File

@ -78,9 +78,13 @@ type
end;
{ TFpDbgMemReaderBase }
TFpDbgMemReaderBase = class
public
function ReadMemory(AnAddress: TDbgPtr; ASize: Cardinal; ADest: Pointer): Boolean; virtual; abstract;
function ReadMemory(AnAddress: TDbgPtr; ASize: Cardinal; ADest: Pointer): Boolean; virtual; abstract; overload;
// inherited Memreaders should implement partial size ReadMemory, and forward it to the TDbgProcess class
function ReadMemory(AnAddress: TDbgPtr; ASize: Cardinal; ADest: Pointer; out ABytesRead: Cardinal): Boolean; virtual; overload;
function ReadMemoryEx(AnAddress, AnAddressSpace: TDbgPtr; ASize: Cardinal; ADest: Pointer): Boolean; virtual; abstract;
// ReadRegister may need TargetMemConvertor
// Register with reduced size are treated as unsigned
@ -225,7 +229,8 @@ type
function AddCacheEx(AnAddress, AnAddressSpace: TDbgPtr; ASize: Cardinal): TFpDbgMemCacheBase; virtual;
procedure RemoveCache(ACache: TFpDbgMemCacheBase); virtual;
function ReadMemory(AnAddress: TDbgPtr; ASize: Cardinal; ADest: Pointer): Boolean; virtual;
function ReadMemory(AnAddress: TDbgPtr; ASize: Cardinal; ADest: Pointer): Boolean; virtual; overload;
function ReadMemory(AnAddress: TDbgPtr; ASize: Cardinal; ADest: Pointer; ABytesRead: Cardinal): Boolean; virtual; overload;
function ReadMemoryEx(AnAddress, AnAddressSpace: TDbgPtr; ASize: Cardinal; ADest: Pointer): Boolean; virtual;
end;
@ -258,7 +263,9 @@ type
destructor Destroy; override;
function HasMemory(AnAddress: TDbgPtr; ASize: Cardinal): Boolean;
function ReadMemory(AnAddress: TDbgPtr; ASize: Cardinal; ADest: Pointer): Boolean; override;
function ReadMemory(AnAddress: TDbgPtr; ASize: Cardinal; ADest: Pointer): Boolean; override; overload;
function ReadMemory(AnAddress: TDbgPtr; ASize: Cardinal; ADest: Pointer;
ABytesRead: Cardinal): Boolean; override; overload;
function AddCache(AnAddress: TDbgPtr; ASize: Cardinal): TFpDbgMemCacheBase;
override;
@ -280,6 +287,9 @@ type
* TODO: allow to pre-read and cache Target mem (e.g. before reading all fields of a record
*)
TFpDbgMemManagerFlag = (mmfPartialRead);
TFpDbgMemManagerFlags = set of TFpDbgMemManagerFlag;
{ TFpDbgMemManager }
TFpDbgMemManager = class
@ -290,6 +300,7 @@ type
FDefaultContext: TFpDbgAddressContext;
FLastError: TFpError;
FMemReader: TFpDbgMemReaderBase;
FPartialReadResultLenght: QWord;
FTmpMem: array[0..(TMP_MEM_SIZE div 8)+1] of qword; // MUST have at least ONE extra byte
FTargetMemConvertor: TFpDbgMemConvertor;
FSelfMemConvertor: TFpDbgMemConvertor; // used when resizing constants (or register values, which are already in self format)
@ -298,7 +309,8 @@ type
protected
function ReadMemory(AReadDataType: TFpDbgMemReadDataType;
const ASourceLocation: TFpDbgMemLocation; const ASourceSize: TFpDbgValueSize;
const ADest: Pointer; const ADestSize: QWord; AContext: TFpDbgAddressContext
const ADest: Pointer; const ADestSize: QWord; AContext: TFpDbgAddressContext;
const AFlags: TFpDbgMemManagerFlags = []
): Boolean;
public
procedure SetCacheManager(ACacheMgr: TFpDbgMemCacheManagerBase);
@ -310,7 +322,8 @@ type
procedure ClearLastError;
function ReadMemory(const ASourceLocation: TFpDbgMemLocation; const ASize: TFpDbgValueSize;
const ADest: Pointer; AContext: TFpDbgAddressContext = nil
const ADest: Pointer; AContext: TFpDbgAddressContext = nil;
const AFlags: TFpDbgMemManagerFlags = []
): Boolean; inline;
function ReadMemoryEx(const ASourceLocation: TFpDbgMemLocation; AnAddressSpace: TDbgPtr; ASize: TFpDbgValueSize; ADest: Pointer; AContext: TFpDbgAddressContext = nil): Boolean;
(* ReadRegister needs a Context, to get the thread/stackframe
@ -359,6 +372,7 @@ type
property TargetMemConvertor: TFpDbgMemConvertor read FTargetMemConvertor;
property SelfMemConvertor: TFpDbgMemConvertor read FSelfMemConvertor;
property PartialReadResultLenght: QWord read FPartialReadResultLenght;
property LastError: TFpError read FLastError;
property DefaultContext: TFpDbgAddressContext read FDefaultContext write FDefaultContext;
end;
@ -762,6 +776,41 @@ begin
WriteStr(Result, AReadDataType);
end;
{ TFpDbgMemReaderBase }
function TFpDbgMemReaderBase.ReadMemory(AnAddress: TDbgPtr; ASize: Cardinal;
ADest: Pointer; out ABytesRead: Cardinal): Boolean;
var
SizeRemaining, sz: Cardinal;
Offs: Integer;
begin
ABytesRead := ASize;
Result := ReadMemory(AnAddress, ASize, ADest);
if Result then
exit;
SizeRemaining := ASize;
Offs := 0;
ABytesRead := 0;
while SizeRemaining > 0 do begin
Result := False;
sz := SizeRemaining;
while (not Result) and (sz > 1) do begin
sz := sz div 2;
Result := ReadMemory(AnAddress, sz, Pointer(PByte(ADest) + Offs));
end;
if not Result then
break;
ABytesRead := ABytesRead + sz;
Offs := Offs + sz;
SizeRemaining := SizeRemaining - sz;
end;
Result := ABytesRead > 0;
end;
{ TFpDbgMemConvertorLittleEndian }
function TFpDbgMemConvertorLittleEndian.PrepareTargetRead(
@ -937,6 +986,12 @@ begin
Result := FMemReader.ReadMemory(AnAddress, ASize, ADest);
end;
function TFpDbgMemCacheManagerBase.ReadMemory(AnAddress: TDbgPtr;
ASize: Cardinal; ADest: Pointer; ABytesRead: Cardinal): Boolean;
begin
Result := FMemReader.ReadMemory(AnAddress, ASize, ADest, ABytesRead);
end;
function TFpDbgMemCacheManagerBase.ReadMemoryEx(AnAddress, AnAddressSpace: TDbgPtr;
ASize: Cardinal; ADest: Pointer): Boolean;
begin
@ -1061,6 +1116,30 @@ begin
Result := inherited ReadMemory(AnAddress, ASize, ADest);
end;
function TFpDbgMemCacheManagerSimple.ReadMemory(AnAddress: TDbgPtr;
ASize: Cardinal; ADest: Pointer; ABytesRead: Cardinal): Boolean;
var
Node: TAVLTreeNode;
begin
Node := FCaches.FindNearestKey(@AnAddress, @CompareKey);
if Node = nil then
exit(inherited ReadMemory(AnAddress, ASize, ADest, ABytesRead));
if TFpDbgMemCacheSimple(Node.Data).CacheAddress > AnAddress then
Node := Node.Precessor;;
if Node = nil then
exit(inherited ReadMemory(AnAddress, ASize, ADest, ABytesRead));
// TODO: Allow to cache partial mem reads
if TFpDbgMemCacheSimple(Node.Data).ContainsMemory(AnAddress, ASize) then begin
ABytesRead := ASize;
Result := TFpDbgMemCacheSimple(Node.Data).ReadMemory(AnAddress, ASize, ADest);
exit;
end;
Result := inherited ReadMemory(AnAddress, ASize, ADest, ABytesRead);
end;
function TFpDbgMemCacheManagerSimple.AddCache(AnAddress: TDbgPtr;
ASize: Cardinal): TFpDbgMemCacheBase;
begin
@ -1115,8 +1194,8 @@ end;
function TFpDbgMemManager.ReadMemory(AReadDataType: TFpDbgMemReadDataType;
const ASourceLocation: TFpDbgMemLocation; const ASourceSize: TFpDbgValueSize;
const ADest: Pointer; const ADestSize: QWord; AContext: TFpDbgAddressContext
): Boolean;
const ADest: Pointer; const ADestSize: QWord; AContext: TFpDbgAddressContext;
const AFlags: TFpDbgMemManagerFlags): Boolean;
var
ConvData: TFpDbgMemConvData;
ReadData, ReadData2: Pointer;
@ -1125,6 +1204,7 @@ var
SourceReadSize, SourceFullSize: QWord;
begin
Result := False;
FPartialReadResultLenght := SizeToFullBytes(ASourceSize);
DebugLn(FPDBG_VERBOSE_MEM, ['$ReadMem: ', dbgs(AReadDataType),' ', dbgs(ASourceLocation), ' ', dbgs(ASourceSize), ' Dest ', ADestSize]);
if (ASourceLocation.MType in [mlfInvalid, mlfUninitialized]) or
(ASourceSize <= 0)
@ -1190,7 +1270,10 @@ begin
if SourceReadSize <= ConvData.DestSize then begin
// full read to ADest
ReadData := ADest;
Result := CacheManager.ReadMemory(ConvData.SourceLocation.Address, SourceReadSize, ADest);
if mmfPartialRead in AFlags then
Result := CacheManager.ReadMemory(ConvData.SourceLocation.Address, SourceReadSize, ADest, FPartialReadResultLenght)
else
Result := CacheManager.ReadMemory(ConvData.SourceLocation.Address, SourceReadSize, ADest);
end
else
if SourceReadSize <= TMP_MEM_SIZE then begin
@ -1198,6 +1281,7 @@ begin
// This is the ONLY read that has ReadData <> ADest
// *** FinishTargetRead must copy the data ***
ReadData := @FTmpMem[0];
// TODO: partial reads for bit shifting?
Result := CacheManager.ReadMemory(ConvData.SourceLocation.Address, SourceReadSize, ReadData);
end
else begin
@ -1207,6 +1291,7 @@ begin
assert(BitOffset <> 0, 'TFpDbgMemManager.ReadMemory: BitOffset <> 0');
ReadData := ADest;
ReadData2 := @FTmpMem[0];
// TODO: partial reads for bit shifting?
Result := CacheManager.ReadMemory(ConvData.SourceLocation.Address, ConvData.DestSize, ADest);
if Result then
Result := CacheManager.ReadMemory(ConvData.SourceLocation.Address + ConvData.DestSize, SourceReadSize - ConvData.DestSize, ReadData2);
@ -1354,9 +1439,9 @@ end;
function TFpDbgMemManager.ReadMemory(const ASourceLocation: TFpDbgMemLocation;
const ASize: TFpDbgValueSize; const ADest: Pointer;
AContext: TFpDbgAddressContext): Boolean;
AContext: TFpDbgAddressContext; const AFlags: TFpDbgMemManagerFlags): Boolean;
begin
Result := ReadMemory(rdtRawRead, ASourceLocation, ASize, ADest, ASize.Size, AContext);
Result := ReadMemory(rdtRawRead, ASourceLocation, ASize, ADest, ASize.Size, AContext, AFlags);
end;
function TFpDbgMemManager.ReadMemoryEx(

View File

@ -214,7 +214,7 @@ type
FExceptionStepper: TFpDebugExceptionStepping;
FConsoleOutputThread: TThread;
// Helper vars to run in debug-thread
FCacheLine: cardinal;
FCacheLine, FCacheBytesRead: cardinal;
FCacheFileName: string;
FCacheLib: TDbgLibrary;
FCacheBreakpoint: TFpDbgBreakpoint;
@ -295,6 +295,7 @@ type
procedure DoAddBreakLocation;
procedure DoAddBWatch;
procedure DoReadData;
procedure DoReadPartialData;
procedure DoPrepareCallStackEntryList;
procedure DoFreeBreakpoint;
procedure DoFindContext;
@ -308,6 +309,7 @@ type
AScope: TDBGWatchPointScope): TFpDbgBreakpoint;
procedure FreeBreakpoint(const ABreakpoint: TFpDbgBreakpoint);
function ReadData(const AAdress: TDbgPtr; const ASize: Cardinal; out AData): Boolean; inline;
function ReadData(const AAdress: TDbgPtr; const ASize: Cardinal; out AData; out ABytesRead: Cardinal): Boolean; inline;
function ReadAddress(const AAdress: TDbgPtr; out AData: TDBGPtr): Boolean;
procedure PrepareCallStackEntryList(AFrameRequired: Integer = -1; AThread: TDbgThread = nil); inline;
function FindContext(AThreadId, AStackFrame: Integer): TFpDbgInfoContext; inline;
@ -495,7 +497,9 @@ type
function GetDbgThread(AContext: TFpDbgAddressContext): TDbgThread; override;
public
constructor create(AFpDebugDebuger: TFpDebugDebugger);
function ReadMemory(AnAddress: TDbgPtr; ASize: Cardinal; ADest: Pointer): Boolean; override;
function ReadMemory(AnAddress: TDbgPtr; ASize: Cardinal; ADest: Pointer): Boolean; override; overload;
function ReadMemory(AnAddress: TDbgPtr; ASize: Cardinal; ADest: Pointer;
out ABytesRead: Cardinal): Boolean; override; overload;
function ReadMemoryEx(AnAddress, AnAddressSpace: TDbgPtr; ASize: Cardinal; ADest: Pointer): Boolean; override;
function ReadRegister(ARegNum: Cardinal; out AValue: TDbgPtr;
AContext: TFpDbgAddressContext): Boolean; override;
@ -841,6 +845,12 @@ begin
result := FFpDebugDebugger.ReadData(AnAddress, ASize, ADest^);
end;
function TFpDbgMemReader.ReadMemory(AnAddress: TDbgPtr; ASize: Cardinal;
ADest: Pointer; out ABytesRead: Cardinal): Boolean;
begin
result := FFpDebugDebugger.ReadData(AnAddress, ASize, ADest^, ABytesRead);
end;
function TFpDbgMemReader.ReadMemoryEx(AnAddress, AnAddressSpace: TDbgPtr; ASize: Cardinal; ADest: Pointer): Boolean;
begin
Assert(AnAddressSpace>0,'TFpDbgMemReader.ReadMemoryEx ignores AddressSpace');
@ -3206,6 +3216,11 @@ begin
FCacheBoolean:=FDbgController.CurrentProcess.ReadData(FCacheLocation, FCacheLine, FCachePointer^);
end;
procedure TFpDebugDebugger.DoReadPartialData;
begin
FCacheBoolean:=FDbgController.CurrentProcess.ReadData(FCacheLocation, FCacheLine, FCachePointer^, FCacheBytesRead);
end;
procedure TFpDebugDebugger.DoPrepareCallStackEntryList;
begin
FCallStackEntryListThread.PrepareCallStackEntryList(FCallStackEntryListFrameRequired);
@ -3332,6 +3347,24 @@ begin
result:=FDbgController.CurrentProcess.ReadData(AAdress, ASize, AData);
end;
function TFpDebugDebugger.ReadData(const AAdress: TDbgPtr;
const ASize: Cardinal; out AData; out ABytesRead: Cardinal): Boolean;
begin
if FDbgController.CurrentProcess.RequiresExecutionInDebuggerThread then
begin
FCacheLocation := AAdress;
FCacheLine:=ASize;
FCachePointer := @AData;
FCacheBoolean := False;
FCacheBytesRead := 0;
ExecuteInDebugThread(@DoReadPartialData);
result := FCacheBoolean;
ABytesRead := FCacheBytesRead;
end
else
result:=FDbgController.CurrentProcess.ReadData(AAdress, ASize, AData, ABytesRead);
end;
function TFpDebugDebugger.ReadAddress(const AAdress: TDbgPtr; out AData: TDBGPtr): Boolean;
var
dw: DWord;