mirror of
https://gitlab.com/freepascal.org/lazarus/lazarus.git
synced 2025-08-06 01:06:01 +02:00
FpDebug: Partial implement WatchPoints.
- No local watches yet. Always global scope. - Break on Write is the same Read/Write - Info pop up has no old/new value - No feedback (in some cases) if watch failed to set git-svn-id: trunk@61990 -
This commit is contained in:
parent
4020102b98
commit
5ff6c5c0c1
@ -292,7 +292,8 @@ type
|
|||||||
TDBGWatchPointKind = (
|
TDBGWatchPointKind = (
|
||||||
wpkWrite,
|
wpkWrite,
|
||||||
wpkRead,
|
wpkRead,
|
||||||
wpkReadWrite
|
wpkReadWrite,
|
||||||
|
wkpExec
|
||||||
);
|
);
|
||||||
|
|
||||||
{ TBaseBreakPoint }
|
{ TBaseBreakPoint }
|
||||||
|
@ -117,6 +117,7 @@ type
|
|||||||
TDbgCallstackEntryList = specialize TFPGObjectList<TDbgCallstackEntry>;
|
TDbgCallstackEntryList = specialize TFPGObjectList<TDbgCallstackEntry>;
|
||||||
|
|
||||||
TDbgProcess = class;
|
TDbgProcess = class;
|
||||||
|
TFpWatchPointData = class;
|
||||||
|
|
||||||
{ TDbgMemReader }
|
{ TDbgMemReader }
|
||||||
|
|
||||||
@ -140,7 +141,6 @@ type
|
|||||||
FProcess: TDbgProcess;
|
FProcess: TDbgProcess;
|
||||||
FID: Integer;
|
FID: Integer;
|
||||||
FHandle: THandle;
|
FHandle: THandle;
|
||||||
|
|
||||||
FPausedAtRemovedBreakPointState: (rbUnknown, rbNone, rbFound{, rbFoundAndDec});
|
FPausedAtRemovedBreakPointState: (rbUnknown, rbNone, rbFound{, rbFoundAndDec});
|
||||||
FPausedAtRemovedBreakPointAddress: TDBGPtr;
|
FPausedAtRemovedBreakPointAddress: TDBGPtr;
|
||||||
|
|
||||||
@ -163,9 +163,8 @@ type
|
|||||||
function HasInsertedBreakInstructionAtLocation(const ALocation: TDBGPtr): Boolean; // include removed breakpoints that (may have) already triggered
|
function HasInsertedBreakInstructionAtLocation(const ALocation: TDBGPtr): Boolean; // include removed breakpoints that (may have) already triggered
|
||||||
procedure CheckAndResetInstructionPointerAfterBreakpoint;
|
procedure CheckAndResetInstructionPointerAfterBreakpoint;
|
||||||
procedure BeforeContinue; virtual;
|
procedure BeforeContinue; virtual;
|
||||||
function AddWatchpoint(AnAddr: TDBGPtr): integer; virtual;
|
procedure ApplyWatchPoints(AWatchPointData: TFpWatchPointData); virtual;
|
||||||
function RemoveWatchpoint(AnId: integer): boolean; virtual;
|
function DetectHardwareWatchpoint: Pointer; virtual;
|
||||||
function DetectHardwareWatchpoint: integer; virtual;
|
|
||||||
|
|
||||||
function GetInstructionPointerRegisterValue: TDbgPtr; virtual; abstract;
|
function GetInstructionPointerRegisterValue: TDbgPtr; virtual; abstract;
|
||||||
function GetStackBasePointerRegisterValue: TDbgPtr; virtual; abstract;
|
function GetStackBasePointerRegisterValue: TDbgPtr; virtual; abstract;
|
||||||
@ -260,15 +259,26 @@ type
|
|||||||
procedure ResetBreak; virtual; abstract;
|
procedure ResetBreak; virtual; abstract;
|
||||||
end;
|
end;
|
||||||
|
|
||||||
{ TFpInternalBreakpoint }
|
{ TFpInternalBreakBase }
|
||||||
|
|
||||||
TFpInternalBreakpoint = class(TFpDbgBreakpoint)
|
TFpInternalBreakBase = class(TFpDbgBreakpoint)
|
||||||
private
|
private
|
||||||
FProcess: TDbgProcess;
|
FProcess: TDbgProcess;
|
||||||
|
protected
|
||||||
|
property Process: TDbgProcess read FProcess;
|
||||||
|
public
|
||||||
|
constructor Create(const AProcess: TDbgProcess); virtual;
|
||||||
|
end;
|
||||||
|
|
||||||
|
TFpInternalBreakpointList = specialize TFPGObjectList<TFpInternalBreakBase>;
|
||||||
|
|
||||||
|
{ TFpInternalBreakpoint }
|
||||||
|
|
||||||
|
TFpInternalBreakpoint = class(TFpInternalBreakBase)
|
||||||
|
private
|
||||||
FLocation: TDBGPtrArray;
|
FLocation: TDBGPtrArray;
|
||||||
FInternal: Boolean;
|
FInternal: Boolean;
|
||||||
protected
|
protected
|
||||||
property Process: TDbgProcess read FProcess;
|
|
||||||
property Location: TDBGPtrArray read FLocation;
|
property Location: TDBGPtrArray read FLocation;
|
||||||
public
|
public
|
||||||
constructor Create(const AProcess: TDbgProcess; const ALocation: TDBGPtrArray); virtual;
|
constructor Create(const AProcess: TDbgProcess; const ALocation: TDBGPtrArray); virtual;
|
||||||
@ -281,8 +291,34 @@ type
|
|||||||
end;
|
end;
|
||||||
TFpInternalBreakpointClass = class of TFpInternalBreakpoint;
|
TFpInternalBreakpointClass = class of TFpInternalBreakpoint;
|
||||||
|
|
||||||
TFpInternalBreakpointList = specialize TFPGObjectList<TFpInternalBreakpoint>;
|
{ TFpInternalWatchpoint }
|
||||||
|
|
||||||
|
TFpInternalWatchpoint = class(TFpInternalBreakBase)
|
||||||
|
private
|
||||||
|
FLocation: TDBGPtr;
|
||||||
|
FSize: Cardinal;
|
||||||
|
FReadWrite: TDBGWatchPointKind;
|
||||||
|
FScope: TDBGWatchPointScope;
|
||||||
|
|
||||||
|
FOtherWatchCount: Integer;
|
||||||
|
FFirstWatchLocation: TDBGPtr;
|
||||||
|
FFirstWatchSize,
|
||||||
|
FOtherWatchesSize,
|
||||||
|
FLastWatchSize: Integer;
|
||||||
|
protected
|
||||||
|
property Location: TDBGPtr read FLocation;
|
||||||
|
property Size: Cardinal read FSize;
|
||||||
|
property ReadWrite: TDBGWatchPointKind read FReadWrite;
|
||||||
|
property Scope: TDBGWatchPointScope read FScope;
|
||||||
|
public
|
||||||
|
constructor Create(const AProcess: TDbgProcess; const ALocation: TDBGPtr; ASize: Cardinal; AReadWrite: TDBGWatchPointKind;
|
||||||
|
AScope: TDBGWatchPointScope); virtual;
|
||||||
|
destructor Destroy; override;
|
||||||
|
|
||||||
|
procedure SetBreak; override;
|
||||||
|
procedure ResetBreak; override;
|
||||||
|
end;
|
||||||
|
TFpInternalWatchpointClass = class of TFpInternalWatchpoint;
|
||||||
|
|
||||||
{ TDbgInstance }
|
{ TDbgInstance }
|
||||||
|
|
||||||
@ -342,15 +378,16 @@ type
|
|||||||
FGotExitProcess: Boolean;
|
FGotExitProcess: Boolean;
|
||||||
FProcessID: Integer;
|
FProcessID: Integer;
|
||||||
FThreadID: Integer;
|
FThreadID: Integer;
|
||||||
|
FWatchPointData: TFpWatchPointData;
|
||||||
|
|
||||||
function GetPauseRequested: boolean;
|
function GetPauseRequested: boolean;
|
||||||
procedure SetPauseRequested(AValue: boolean);
|
procedure SetPauseRequested(AValue: boolean);
|
||||||
procedure ThreadDestroyed(const AThread: TDbgThread);
|
procedure ThreadDestroyed(const AThread: TDbgThread);
|
||||||
protected
|
protected
|
||||||
FBreakpointList: TFpInternalBreakpointList;
|
FBreakpointList, FWatchPointList: TFpInternalBreakpointList;
|
||||||
FCurrentBreakpoint: TFpInternalBreakpoint; // set if we are executing the code at the break
|
FCurrentBreakpoint: TFpInternalBreakpoint; // set if we are executing the code at the break
|
||||||
// if the singlestep is done, set the break again
|
// if the singlestep is done, set the break again
|
||||||
FCurrentWatchpoint: integer;
|
FCurrentWatchpoint: Pointer; // Indicates the owner
|
||||||
FReEnableBreakStep: Boolean; // Set when we are reenabling a breakpoint
|
FReEnableBreakStep: Boolean; // Set when we are reenabling a breakpoint
|
||||||
// We need a single step, so the IP is after the break to set
|
// We need a single step, so the IP is after the break to set
|
||||||
|
|
||||||
@ -380,6 +417,8 @@ type
|
|||||||
function CreateThread(AthreadIdentifier: THandle; out IsMainThread: boolean): TDbgThread; virtual; abstract;
|
function CreateThread(AthreadIdentifier: THandle; out IsMainThread: boolean): TDbgThread; virtual; abstract;
|
||||||
// Should analyse why the debugger has stopped.
|
// Should analyse why the debugger has stopped.
|
||||||
function AnalyseDebugEvent(AThread: TDbgThread): TFPDEvent; virtual; abstract;
|
function AnalyseDebugEvent(AThread: TDbgThread): TFPDEvent; virtual; abstract;
|
||||||
|
|
||||||
|
function CreateWatchPointData: TFpWatchPointData; virtual;
|
||||||
public
|
public
|
||||||
class function StartInstance(AFileName: string; AParams, AnEnvironment: TStrings; AWorkingDirectory, AConsoleTty: string; AFlags: TStartInstanceFlags): TDbgProcess; virtual;
|
class function StartInstance(AFileName: string; AParams, AnEnvironment: TStrings; AWorkingDirectory, AConsoleTty: string; AFlags: TStartInstanceFlags): TDbgProcess; virtual;
|
||||||
class function AttachToInstance(AFileName: string; APid: Integer): TDbgProcess; virtual;
|
class function AttachToInstance(AFileName: string; APid: Integer): TDbgProcess; virtual;
|
||||||
@ -389,6 +428,9 @@ type
|
|||||||
function AddInternalBreak(const ALocation: TDBGPtrArray): TFpInternalBreakpoint; overload;
|
function AddInternalBreak(const ALocation: TDBGPtrArray): TFpInternalBreakpoint; overload;
|
||||||
function AddBreak(const ALocation: TDBGPtr): TFpInternalBreakpoint; overload;
|
function AddBreak(const ALocation: TDBGPtr): TFpInternalBreakpoint; overload;
|
||||||
function AddBreak(const ALocation: TDBGPtrArray): TFpInternalBreakpoint; overload;
|
function AddBreak(const ALocation: TDBGPtrArray): TFpInternalBreakpoint; overload;
|
||||||
|
function AddWatch(const ALocation: TDBGPtr; ASize: Cardinal; AReadWrite: TDBGWatchPointKind;
|
||||||
|
AScope: TDBGWatchPointScope): TFpInternalWatchpoint;
|
||||||
|
property WatchPointData: TFpWatchPointData read FWatchPointData;
|
||||||
function FindProcSymbol(const AName: String): TFpSymbol;
|
function FindProcSymbol(const AName: String): TFpSymbol;
|
||||||
function FindProcSymbol(AAdress: TDbgPtr): TFpSymbol;
|
function FindProcSymbol(AAdress: TDbgPtr): TFpSymbol;
|
||||||
function FindContext(AThreadId, AStackFrame: Integer): TFpDbgInfoContext;
|
function FindContext(AThreadId, AStackFrame: Integer): TFpDbgInfoContext;
|
||||||
@ -438,7 +480,7 @@ type
|
|||||||
property ThreadID: integer read FThreadID;
|
property ThreadID: integer read FThreadID;
|
||||||
property ExitCode: DWord read FExitCode;
|
property ExitCode: DWord read FExitCode;
|
||||||
property CurrentBreakpoint: TFpInternalBreakpoint read FCurrentBreakpoint;
|
property CurrentBreakpoint: TFpInternalBreakpoint read FCurrentBreakpoint;
|
||||||
property CurrentWatchpoint: integer read FCurrentWatchpoint;
|
property CurrentWatchpoint: Pointer read FCurrentWatchpoint;
|
||||||
property PauseRequested: boolean read GetPauseRequested write SetPauseRequested;
|
property PauseRequested: boolean read GetPauseRequested write SetPauseRequested;
|
||||||
function GetAndClearPauseRequested: Boolean;
|
function GetAndClearPauseRequested: Boolean;
|
||||||
|
|
||||||
@ -452,10 +494,40 @@ type
|
|||||||
end;
|
end;
|
||||||
TDbgProcessClass = class of TDbgProcess;
|
TDbgProcessClass = class of TDbgProcess;
|
||||||
|
|
||||||
|
{ TFpWatchPointData }
|
||||||
|
|
||||||
|
TFpWatchPointData = class
|
||||||
|
private
|
||||||
|
FChanged: Boolean;
|
||||||
|
public
|
||||||
|
function AddOwnedWatchpoint(AnOwner: Pointer; AnAddr: TDBGPtr; ASize: Cardinal; AReadWrite: TDBGWatchPointKind): boolean; virtual;
|
||||||
|
function RemoveOwnedWatchpoint(AnOwner: Pointer): boolean; virtual;
|
||||||
|
property Changed: Boolean read FChanged write FChanged;
|
||||||
|
end;
|
||||||
|
|
||||||
|
{ TFpIntelWatchPointData }
|
||||||
|
|
||||||
|
TFpIntelWatchPointData = class(TFpWatchPointData)
|
||||||
|
private
|
||||||
|
// For Intel: Dr0..Dr3
|
||||||
|
FOwners: array [0..3] of Pointer;
|
||||||
|
FDr03: array [0..3] of TDBGPtr;
|
||||||
|
FDr7: DWord;
|
||||||
|
function GetDr03(AnIndex: Integer): TDBGPtr; inline;
|
||||||
|
function GetOwner(AnIndex: Integer): Pointer; inline;
|
||||||
|
public
|
||||||
|
function AddOwnedWatchpoint(AnOwner: Pointer; AnAddr: TDBGPtr; ASize: Cardinal; AReadWrite: TDBGWatchPointKind): boolean; override;
|
||||||
|
function RemoveOwnedWatchpoint(AnOwner: Pointer): boolean; override;
|
||||||
|
property Dr03[AnIndex: Integer]: TDBGPtr read GetDr03;
|
||||||
|
property Dr7: DWord read FDr7;
|
||||||
|
property Owner[AnIndex: Integer]: Pointer read GetOwner;
|
||||||
|
end;
|
||||||
|
|
||||||
TOSDbgClasses = class
|
TOSDbgClasses = class
|
||||||
public
|
public
|
||||||
DbgThreadClass : TDbgThreadClass;
|
DbgThreadClass : TDbgThreadClass;
|
||||||
DbgBreakpointClass : TFpInternalBreakpointClass;
|
DbgBreakpointClass : TFpInternalBreakpointClass;
|
||||||
|
DbgWatchpointClass : TFpInternalWatchpointClass;
|
||||||
DbgProcessClass : TDbgProcessClass;
|
DbgProcessClass : TDbgProcessClass;
|
||||||
end;
|
end;
|
||||||
|
|
||||||
@ -498,6 +570,7 @@ begin
|
|||||||
GOSDbgClasses := TOSDbgClasses.create;
|
GOSDbgClasses := TOSDbgClasses.create;
|
||||||
GOSDbgClasses.DbgThreadClass := TDbgThread;
|
GOSDbgClasses.DbgThreadClass := TDbgThread;
|
||||||
GOSDbgClasses.DbgBreakpointClass := TFpInternalBreakpoint;
|
GOSDbgClasses.DbgBreakpointClass := TFpInternalBreakpoint;
|
||||||
|
GOSDbgClasses.DbgWatchpointClass := TFpInternalWatchpoint;
|
||||||
GOSDbgClasses.DbgProcessClass := TDbgProcess;
|
GOSDbgClasses.DbgProcessClass := TDbgProcess;
|
||||||
{$ifdef windows}
|
{$ifdef windows}
|
||||||
RegisterDbgClasses;
|
RegisterDbgClasses;
|
||||||
@ -1105,6 +1178,13 @@ begin
|
|||||||
end;
|
end;
|
||||||
end;
|
end;
|
||||||
|
|
||||||
|
function TDbgProcess.AddWatch(const ALocation: TDBGPtr; ASize: Cardinal;
|
||||||
|
AReadWrite: TDBGWatchPointKind; AScope: TDBGWatchPointScope
|
||||||
|
): TFpInternalWatchpoint;
|
||||||
|
begin
|
||||||
|
Result := OSDbgClasses.DbgWatchpointClass.Create(Self, ALocation, ASize, AReadWrite, AScope);
|
||||||
|
end;
|
||||||
|
|
||||||
constructor TDbgProcess.Create(const AFileName: string; const AProcessID,
|
constructor TDbgProcess.Create(const AFileName: string; const AProcessID,
|
||||||
AThreadID: Integer);
|
AThreadID: Integer);
|
||||||
const
|
const
|
||||||
@ -1118,11 +1198,13 @@ begin
|
|||||||
FThreadID := AThreadID;
|
FThreadID := AThreadID;
|
||||||
|
|
||||||
FBreakpointList := TFpInternalBreakpointList.Create(False);
|
FBreakpointList := TFpInternalBreakpointList.Create(False);
|
||||||
|
FWatchPointList := TFpInternalBreakpointList.Create(False);
|
||||||
FThreadMap := TThreadMap.Create(itu4, SizeOf(TDbgThread));
|
FThreadMap := TThreadMap.Create(itu4, SizeOf(TDbgThread));
|
||||||
FLibMap := TMap.Create(MAP_ID_SIZE, SizeOf(TDbgLibrary));
|
FLibMap := TMap.Create(MAP_ID_SIZE, SizeOf(TDbgLibrary));
|
||||||
|
FWatchPointData := CreateWatchPointData;
|
||||||
FBreakMap := TBreakLocationMap.Create(Self);
|
FBreakMap := TBreakLocationMap.Create(Self);
|
||||||
FCurrentBreakpoint := nil;
|
FCurrentBreakpoint := nil;
|
||||||
FCurrentWatchpoint := -1;
|
FCurrentWatchpoint := nil;
|
||||||
|
|
||||||
FSymInstances := TList.Create;
|
FSymInstances := TList.Create;
|
||||||
|
|
||||||
@ -1159,12 +1241,16 @@ begin
|
|||||||
|
|
||||||
for i := 0 to FBreakpointList.Count - 1 do
|
for i := 0 to FBreakpointList.Count - 1 do
|
||||||
FBreakpointList[i].FProcess := nil;
|
FBreakpointList[i].FProcess := nil;
|
||||||
|
for i := 0 to FWatchPointList.Count - 1 do
|
||||||
|
FWatchPointList[i].FProcess := nil;
|
||||||
FreeAndNil(FBreakpointList);
|
FreeAndNil(FBreakpointList);
|
||||||
|
FreeAndNil(FWatchPointList);
|
||||||
//Assert(FBreakMap.Count=0, 'No breakpoints left');
|
//Assert(FBreakMap.Count=0, 'No breakpoints left');
|
||||||
//FreeItemsInMap(FBreakMap);
|
//FreeItemsInMap(FBreakMap);
|
||||||
FreeItemsInMap(FThreadMap);
|
FreeItemsInMap(FThreadMap);
|
||||||
FreeItemsInMap(FLibMap);
|
FreeItemsInMap(FLibMap);
|
||||||
|
|
||||||
|
FreeAndNil(FWatchPointData);
|
||||||
FreeAndNil(FBreakMap);
|
FreeAndNil(FBreakMap);
|
||||||
FreeAndNil(FThreadMap);
|
FreeAndNil(FThreadMap);
|
||||||
FreeAndNil(FLibMap);
|
FreeAndNil(FLibMap);
|
||||||
@ -1326,6 +1412,8 @@ begin
|
|||||||
// Determine the address where the execution has stopped
|
// Determine the address where the execution has stopped
|
||||||
CurrentAddr:=AThread.GetInstructionPointerRegisterValue;
|
CurrentAddr:=AThread.GetInstructionPointerRegisterValue;
|
||||||
FCurrentWatchpoint:=AThread.DetectHardwareWatchpoint;
|
FCurrentWatchpoint:=AThread.DetectHardwareWatchpoint;
|
||||||
|
if (FCurrentWatchpoint <> nil) and (FWatchPointList.IndexOf(TFpInternalWatchpoint(FCurrentWatchpoint)) < 0) then
|
||||||
|
FCurrentWatchpoint := Pointer(-1);
|
||||||
FCurrentBreakpoint:=nil;
|
FCurrentBreakpoint:=nil;
|
||||||
AThread.NextIsSingleStep:=false;
|
AThread.NextIsSingleStep:=false;
|
||||||
|
|
||||||
@ -1364,6 +1452,7 @@ begin
|
|||||||
assert(FMainThread=nil);
|
assert(FMainThread=nil);
|
||||||
FMainThread := result;
|
FMainThread := result;
|
||||||
end;
|
end;
|
||||||
|
Result.ApplyWatchPoints(FWatchPointData);
|
||||||
end
|
end
|
||||||
else
|
else
|
||||||
DebugLn(DBG_WARNINGS, 'Unknown thread ID %u for process %u', [AThreadIdentifier, ProcessID]);
|
DebugLn(DBG_WARNINGS, 'Unknown thread ID %u for process %u', [AThreadIdentifier, ProcessID]);
|
||||||
@ -1403,12 +1492,15 @@ begin
|
|||||||
while not Iterator.EOM do
|
while not Iterator.EOM do
|
||||||
begin
|
begin
|
||||||
Iterator.GetData(Thread);
|
Iterator.GetData(Thread);
|
||||||
|
if FWatchPointData.Changed then
|
||||||
|
Thread.ApplyWatchPoints(FWatchPointData);
|
||||||
Thread.BeforeContinue;
|
Thread.BeforeContinue;
|
||||||
iterator.Next;
|
iterator.Next;
|
||||||
end;
|
end;
|
||||||
finally
|
finally
|
||||||
Iterator.Free;
|
Iterator.Free;
|
||||||
end;
|
end;
|
||||||
|
FWatchPointData.Changed := False;
|
||||||
end;
|
end;
|
||||||
|
|
||||||
procedure TDbgProcess.ThreadsClearCallStack;
|
procedure TDbgProcess.ThreadsClearCallStack;
|
||||||
@ -1603,8 +1695,8 @@ end;
|
|||||||
|
|
||||||
procedure TDbgProcess.RemoveAllBreakPoints;
|
procedure TDbgProcess.RemoveAllBreakPoints;
|
||||||
var
|
var
|
||||||
b: TFpInternalBreakpoint;
|
|
||||||
i: LongInt;
|
i: LongInt;
|
||||||
|
b: TFpInternalBreakBase;
|
||||||
begin
|
begin
|
||||||
i := FBreakpointList.Count - 1;
|
i := FBreakpointList.Count - 1;
|
||||||
while i >= 0 do begin
|
while i >= 0 do begin
|
||||||
@ -1614,6 +1706,14 @@ begin
|
|||||||
FBreakpointList.Delete(i);
|
FBreakpointList.Delete(i);
|
||||||
dec(i);
|
dec(i);
|
||||||
end;
|
end;
|
||||||
|
i := FWatchPointList.Count - 1;
|
||||||
|
while i >= 0 do begin
|
||||||
|
b := FWatchPointList[i];
|
||||||
|
b.ResetBreak;
|
||||||
|
b.FProcess := nil;
|
||||||
|
FWatchPointList.Delete(i);
|
||||||
|
dec(i);
|
||||||
|
end;
|
||||||
assert(FBreakMap.Count = 0, 'TDbgProcess.RemoveAllBreakPoints: FBreakMap.Count = 0');
|
assert(FBreakMap.Count = 0, 'TDbgProcess.RemoveAllBreakPoints: FBreakMap.Count = 0');
|
||||||
end;
|
end;
|
||||||
|
|
||||||
@ -1697,6 +1797,11 @@ begin
|
|||||||
end;
|
end;
|
||||||
end;
|
end;
|
||||||
|
|
||||||
|
function TDbgProcess.CreateWatchPointData: TFpWatchPointData;
|
||||||
|
begin
|
||||||
|
Result := TFpWatchPointData.Create;
|
||||||
|
end;
|
||||||
|
|
||||||
function TDbgProcess.WriteData(const AAdress: TDbgPtr; const ASize: Cardinal; const AData): Boolean;
|
function TDbgProcess.WriteData(const AAdress: TDbgPtr; const ASize: Cardinal; const AData): Boolean;
|
||||||
begin
|
begin
|
||||||
result := false;
|
result := false;
|
||||||
@ -1860,21 +1965,14 @@ begin
|
|||||||
FPausedAtRemovedBreakPointAddress := 0;
|
FPausedAtRemovedBreakPointAddress := 0;
|
||||||
end;
|
end;
|
||||||
|
|
||||||
function TDbgThread.AddWatchpoint(AnAddr: TDBGPtr): integer;
|
procedure TDbgThread.ApplyWatchPoints(AWatchPointData: TFpWatchPointData);
|
||||||
begin
|
begin
|
||||||
DebugLn(DBG_VERBOSE, 'Hardware watchpoints are not available.');
|
//
|
||||||
result := -1;
|
|
||||||
end;
|
end;
|
||||||
|
|
||||||
function TDbgThread.RemoveWatchpoint(AnId: integer): boolean;
|
function TDbgThread.DetectHardwareWatchpoint: Pointer;
|
||||||
begin
|
begin
|
||||||
DebugLn(DBG_VERBOSE, 'Hardware watchpoints are not available: '+self.classname);
|
result := nil;
|
||||||
result := false;
|
|
||||||
end;
|
|
||||||
|
|
||||||
function TDbgThread.DetectHardwareWatchpoint: integer;
|
|
||||||
begin
|
|
||||||
result := -1;
|
|
||||||
end;
|
end;
|
||||||
|
|
||||||
procedure TDbgThread.PrepareCallStackEntryList(AFrameRequired: Integer);
|
procedure TDbgThread.PrepareCallStackEntryList(AFrameRequired: Integer);
|
||||||
@ -1969,15 +2067,102 @@ begin
|
|||||||
inherited;
|
inherited;
|
||||||
end;
|
end;
|
||||||
|
|
||||||
|
{ TFpWatchPointData }
|
||||||
|
|
||||||
|
function TFpWatchPointData.AddOwnedWatchpoint(AnOwner: Pointer;
|
||||||
|
AnAddr: TDBGPtr; ASize: Cardinal; AReadWrite: TDBGWatchPointKind): boolean;
|
||||||
|
begin
|
||||||
|
Result := False;
|
||||||
|
end;
|
||||||
|
|
||||||
|
function TFpWatchPointData.RemoveOwnedWatchpoint(AnOwner: Pointer): boolean;
|
||||||
|
begin
|
||||||
|
Result := True;
|
||||||
|
end;
|
||||||
|
|
||||||
|
{ TFpIntelWatchPointData }
|
||||||
|
|
||||||
|
function TFpIntelWatchPointData.GetDr03(AnIndex: Integer): TDBGPtr;
|
||||||
|
begin
|
||||||
|
Result := FDr03[AnIndex];
|
||||||
|
end;
|
||||||
|
|
||||||
|
function TFpIntelWatchPointData.GetOwner(AnIndex: Integer): Pointer;
|
||||||
|
begin
|
||||||
|
Result := FOwners[AnIndex];
|
||||||
|
end;
|
||||||
|
|
||||||
|
function TFpIntelWatchPointData.AddOwnedWatchpoint(AnOwner: Pointer;
|
||||||
|
AnAddr: TDBGPtr; ASize: Cardinal; AReadWrite: TDBGWatchPointKind): boolean;
|
||||||
|
var
|
||||||
|
SizeBits, ModeBits: DWord;
|
||||||
|
idx: Integer;
|
||||||
|
begin
|
||||||
|
Result := False;
|
||||||
|
case ASize of
|
||||||
|
1: SizeBits := $00000 shl 2;
|
||||||
|
2: SizeBits := $10000 shl 2;
|
||||||
|
4: SizeBits := $30000 shl 2;
|
||||||
|
8: SizeBits := $20000 shl 2; // Only certain cpu / must be 8byte aligned
|
||||||
|
else exit;
|
||||||
|
end;
|
||||||
|
case AReadWrite of
|
||||||
|
wpkWrite: ModeBits := $10000;
|
||||||
|
wpkRead: ModeBits := $30000; // caller must check
|
||||||
|
wpkReadWrite: ModeBits := $30000;
|
||||||
|
wkpExec: ModeBits := $00000; // Size must be 1 (SizeBits=0)
|
||||||
|
end;
|
||||||
|
|
||||||
|
for idx := 0 to 3 do begin
|
||||||
|
if (FDr7 and (1 shl (idx * 2))) = 0 then begin
|
||||||
|
FDr7 := FDr7 or (1 shl (idx*2))
|
||||||
|
or (ModeBits shl (idx*4)) // read/write
|
||||||
|
or (SizeBits shl (idx*4)); // size
|
||||||
|
FDr03[idx] := AnAddr;
|
||||||
|
FOwners[idx] := AnOwner;
|
||||||
|
Changed := True;
|
||||||
|
Result := True;
|
||||||
|
break;
|
||||||
|
end;
|
||||||
|
end;
|
||||||
|
end;
|
||||||
|
|
||||||
|
function TFpIntelWatchPointData.RemoveOwnedWatchpoint(AnOwner: Pointer
|
||||||
|
): boolean;
|
||||||
|
var
|
||||||
|
idx: Integer;
|
||||||
|
begin
|
||||||
|
Result := False;
|
||||||
|
for idx := 0 to 3 do begin
|
||||||
|
if FOwners[idx] = AnOwner then begin
|
||||||
|
FDr7 := FDr7 and not (
|
||||||
|
(DWord(3) shl (idx*2)) or
|
||||||
|
(DWord($F0000) shl (idx*4))
|
||||||
|
);
|
||||||
|
FDr03[idx] := 0;
|
||||||
|
FOwners[idx] := nil;
|
||||||
|
Changed := True;
|
||||||
|
Result := True;
|
||||||
|
end;
|
||||||
|
end;
|
||||||
|
end;
|
||||||
|
|
||||||
|
{ TFpInternalBreakBase }
|
||||||
|
|
||||||
|
constructor TFpInternalBreakBase.Create(const AProcess: TDbgProcess);
|
||||||
|
begin
|
||||||
|
inherited Create;
|
||||||
|
FProcess := AProcess;
|
||||||
|
end;
|
||||||
|
|
||||||
{ TDbgBreak }
|
{ TDbgBreak }
|
||||||
|
|
||||||
constructor TFpInternalBreakpoint.Create(const AProcess: TDbgProcess;
|
constructor TFpInternalBreakpoint.Create(const AProcess: TDbgProcess;
|
||||||
const ALocation: TDBGPtrArray);
|
const ALocation: TDBGPtrArray);
|
||||||
begin
|
begin
|
||||||
FProcess := AProcess;
|
inherited Create(AProcess);
|
||||||
FProcess.FBreakpointList.Add(Self);
|
FProcess.FBreakpointList.Add(Self);
|
||||||
FLocation := ALocation;
|
FLocation := ALocation;
|
||||||
inherited Create;
|
|
||||||
SetBreak;
|
SetBreak;
|
||||||
end;
|
end;
|
||||||
|
|
||||||
@ -2035,6 +2220,132 @@ begin
|
|||||||
FProcess.FBreakMap.AddLocotion(FLocation[i], Self, True);
|
FProcess.FBreakMap.AddLocotion(FLocation[i], Self, True);
|
||||||
end;
|
end;
|
||||||
|
|
||||||
|
{ TFpInternalWatchpoint }
|
||||||
|
|
||||||
|
constructor TFpInternalWatchpoint.Create(const AProcess: TDbgProcess;
|
||||||
|
const ALocation: TDBGPtr; ASize: Cardinal; AReadWrite: TDBGWatchPointKind;
|
||||||
|
AScope: TDBGWatchPointScope);
|
||||||
|
(* FROM INTEL DOCS / About 8 byte watchpoints
|
||||||
|
For Pentium® 4 and Intel® Xeon® processors with a CPUID signature corresponding to family 15 (model 3, 4, and 6),
|
||||||
|
break point conditions permit specifying 8-byte length on data read/write with an of encoding 10B in the LENn field.
|
||||||
|
Encoding 10B is also supported in processors based on Intel Core microarchitecture or
|
||||||
|
enhanced Intel Core microarchitecture, the respective CPUID signatures corresponding to family 6, model 15,
|
||||||
|
and family 6, DisplayModel value 23 (see CPUID instruction in Chapter 3,
|
||||||
|
“Instruction Set Reference, A-L” in the Intel® 64 and IA-32 Architectures Software Developer’s Manual, Volume 2A).
|
||||||
|
The Encoding 10B is supported in processors based on Intel® Atom™ microarchitecture,
|
||||||
|
with CPUID signature of family 6, DisplayModel value 1CH. The encoding 10B is undefined for other processors
|
||||||
|
*)
|
||||||
|
const
|
||||||
|
MAX_WATCH_SIZE = 8;
|
||||||
|
SIZE_TO_BOUNDMASK: array[1..8] of TDBGPtr = (
|
||||||
|
0, // Size=1
|
||||||
|
1, 0, // Size=2
|
||||||
|
3, 0,0,0, // Size=4
|
||||||
|
7 // Size=8
|
||||||
|
);
|
||||||
|
SIZE_TO_WATCHSIZE: array[0..8] of Integer = (0, 1, 2, 4, 4, 8, 8, 8, 8);
|
||||||
|
var
|
||||||
|
MaxWatchSize: Integer;
|
||||||
|
BoundaryOffset, S, HalfSize: Integer;
|
||||||
|
begin
|
||||||
|
inherited Create(AProcess);
|
||||||
|
FProcess.FWatchPointList.Add(Self);
|
||||||
|
FLocation := ALocation;
|
||||||
|
FSize := ASize;
|
||||||
|
FReadWrite := AReadWrite;
|
||||||
|
FScope := AScope;
|
||||||
|
|
||||||
|
MaxWatchSize := MAX_WATCH_SIZE;
|
||||||
|
// Wach at 13FFC20:4 TO First 13FFC18:8 Other 0 (0) Last 0
|
||||||
|
|
||||||
|
FFirstWatchSize := MaxWatchSize;
|
||||||
|
BoundaryOffset := Integer(FLocation and SIZE_TO_BOUNDMASK[FFirstWatchSize]);
|
||||||
|
// As long as the full first half of the watch is unused, use the next smaller watch-size
|
||||||
|
HalfSize := FFirstWatchSize div 2;
|
||||||
|
while (FFirstWatchSize > 1) and
|
||||||
|
( (BoundaryOffset >= HalfSize) or
|
||||||
|
(FSize <= HalfSize)
|
||||||
|
)
|
||||||
|
do begin
|
||||||
|
FFirstWatchSize := HalfSize;
|
||||||
|
HalfSize := FFirstWatchSize div 2;
|
||||||
|
BoundaryOffset := Integer(FLocation and SIZE_TO_BOUNDMASK[FFirstWatchSize]);
|
||||||
|
end;
|
||||||
|
FFirstWatchLocation := FLocation - BoundaryOffset;
|
||||||
|
|
||||||
|
FOtherWatchesSize := 0;
|
||||||
|
FOtherWatchCount := 0;
|
||||||
|
FLastWatchSize := 0;
|
||||||
|
|
||||||
|
S := FSize - FFirstWatchSize + BoundaryOffset; // remainder size
|
||||||
|
if S > 0 then begin
|
||||||
|
FOtherWatchCount := (S - 1) div MaxWatchSize;
|
||||||
|
if FOtherWatchCount > 0 then
|
||||||
|
FOtherWatchesSize := MaxWatchSize;
|
||||||
|
|
||||||
|
S := S - FOtherWatchCount * FOtherWatchesSize;
|
||||||
|
assert(S >= 0, 'TFpInternalWatchpoint.Create: S >= 0');
|
||||||
|
|
||||||
|
FLastWatchSize := SIZE_TO_WATCHSIZE[S];
|
||||||
|
end;
|
||||||
|
debugln(DBG_VERBOSE, 'Wach at %x:%d TO First %x:%d Other %d (%d) Last %d',
|
||||||
|
[FLocation, FSize, FFirstWatchLocation, FFirstWatchSize, FOtherWatchCount, FOtherWatchesSize, FLastWatchSize]);
|
||||||
|
|
||||||
|
SetBreak;
|
||||||
|
end;
|
||||||
|
|
||||||
|
destructor TFpInternalWatchpoint.Destroy;
|
||||||
|
begin
|
||||||
|
if FProcess <> nil then
|
||||||
|
FProcess.FWatchPointList.Remove(Self);
|
||||||
|
ResetBreak;
|
||||||
|
inherited Destroy;
|
||||||
|
end;
|
||||||
|
|
||||||
|
procedure TFpInternalWatchpoint.SetBreak;
|
||||||
|
var
|
||||||
|
a: TDBGPtr;
|
||||||
|
wd: TFpWatchPointData;
|
||||||
|
R: Boolean;
|
||||||
|
i: Integer;
|
||||||
|
begin
|
||||||
|
if FProcess = nil then
|
||||||
|
exit;
|
||||||
|
//TODO: read current mem content. So in case of overlap it can be checked
|
||||||
|
|
||||||
|
wd := FProcess.WatchPointData;
|
||||||
|
|
||||||
|
a := FFirstWatchLocation;
|
||||||
|
R := wd.AddOwnedWatchpoint(Self, a, FFirstWatchSize, FReadWrite);
|
||||||
|
if not R then begin
|
||||||
|
ResetBreak;
|
||||||
|
exit;
|
||||||
|
end;
|
||||||
|
|
||||||
|
a := a + FFirstWatchSize;
|
||||||
|
for i := 0 to FOtherWatchCount - 1 do begin
|
||||||
|
R := wd.AddOwnedWatchpoint(Self, a, FOtherWatchesSize, FReadWrite);
|
||||||
|
if not R then begin
|
||||||
|
ResetBreak;
|
||||||
|
exit;
|
||||||
|
end;
|
||||||
|
a := a + FOtherWatchesSize;
|
||||||
|
end;
|
||||||
|
|
||||||
|
if FLastWatchSize > 0 then
|
||||||
|
R := wd.AddOwnedWatchpoint(Self, a, FLastWatchSize, FReadWrite);
|
||||||
|
if not R then
|
||||||
|
ResetBreak;
|
||||||
|
end;
|
||||||
|
|
||||||
|
procedure TFpInternalWatchpoint.ResetBreak;
|
||||||
|
begin
|
||||||
|
if FProcess = nil then
|
||||||
|
exit;
|
||||||
|
|
||||||
|
FProcess.WatchPointData.RemoveOwnedWatchpoint(Self);
|
||||||
|
end;
|
||||||
|
|
||||||
initialization
|
initialization
|
||||||
GOSDbgClasses := nil;
|
GOSDbgClasses := nil;
|
||||||
|
|
||||||
|
@ -10,7 +10,7 @@ uses
|
|||||||
SysUtils,
|
SysUtils,
|
||||||
Maps,
|
Maps,
|
||||||
LazLoggerBase,
|
LazLoggerBase,
|
||||||
DbgIntfBaseTypes,
|
DbgIntfBaseTypes, DbgIntfDebuggerBase,
|
||||||
FpDbgDisasX86,
|
FpDbgDisasX86,
|
||||||
FpDbgClasses;
|
FpDbgClasses;
|
||||||
|
|
||||||
@ -949,6 +949,7 @@ begin
|
|||||||
deBreakpoint: begin
|
deBreakpoint: begin
|
||||||
b := FCurrentProcess.GetAndClearPauseRequested;
|
b := FCurrentProcess.GetAndClearPauseRequested;
|
||||||
AExit := (FCurrentProcess.CurrentBreakpoint <> nil) or
|
AExit := (FCurrentProcess.CurrentBreakpoint <> nil) or
|
||||||
|
( (FCurrentProcess.CurrentWatchpoint <> nil) and (FCurrentProcess.CurrentWatchpoint <> Pointer(-1)) ) or
|
||||||
(b and (InterLockedExchangeAdd(FPauseRequest, 0) = 1))
|
(b and (InterLockedExchangeAdd(FPauseRequest, 0) = 1))
|
||||||
end;
|
end;
|
||||||
{ deLoadLibrary :
|
{ deLoadLibrary :
|
||||||
@ -974,9 +975,14 @@ end;
|
|||||||
procedure TDbgController.SendEvents(out continue: boolean);
|
procedure TDbgController.SendEvents(out continue: boolean);
|
||||||
var
|
var
|
||||||
HasPauseRequest: Boolean;
|
HasPauseRequest: Boolean;
|
||||||
|
CurWatch: TFpInternalWatchpoint;
|
||||||
begin
|
begin
|
||||||
// reset pause request. If Pause() is called after this, it will be seen in the next loop
|
// reset pause request. If Pause() is called after this, it will be seen in the next loop
|
||||||
HasPauseRequest := InterLockedExchange(FPauseRequest, 0) = 1;
|
HasPauseRequest := InterLockedExchange(FPauseRequest, 0) = 1;
|
||||||
|
CurWatch := nil;
|
||||||
|
if (FCurrentProcess.CurrentWatchpoint <> nil) and (FCurrentProcess.CurrentWatchpoint <> Pointer(-1)) then
|
||||||
|
CurWatch := TFpInternalWatchpoint(FCurrentProcess.CurrentWatchpoint);
|
||||||
|
|
||||||
case FPDEvent of
|
case FPDEvent of
|
||||||
deCreateProcess:
|
deCreateProcess:
|
||||||
begin
|
begin
|
||||||
@ -993,28 +999,35 @@ begin
|
|||||||
end;
|
end;
|
||||||
deFinishedStep:
|
deFinishedStep:
|
||||||
begin
|
begin
|
||||||
continue:=false;
|
if assigned(OnHitBreakpointEvent) then begin
|
||||||
// if there is a breakpoint at the stepping end, execute its actions
|
// if there is a breakpoint at the stepping end, execute its actions
|
||||||
if assigned(OnHitBreakpointEvent) and assigned(FCurrentProcess.CurrentBreakpoint) then
|
continue:=false;
|
||||||
|
if (CurWatch <> nil) and assigned(OnHitBreakpointEvent) then
|
||||||
|
OnHitBreakpointEvent(continue, CurWatch);
|
||||||
|
continue:=false;
|
||||||
|
if assigned(FCurrentProcess.CurrentBreakpoint) then
|
||||||
OnHitBreakpointEvent(continue, FCurrentProcess.CurrentBreakpoint);
|
OnHitBreakpointEvent(continue, FCurrentProcess.CurrentBreakpoint);
|
||||||
if continue or not assigned(FCurrentProcess.CurrentBreakpoint) then begin
|
|
||||||
// TODO: dedicated event to set pause and location
|
// TODO: dedicated event to set pause and location
|
||||||
// ensure state = dsPause and location is set
|
// ensure state = dsPause and location is set
|
||||||
continue:=false;
|
continue:=false;
|
||||||
OnHitBreakpointEvent(continue, nil);
|
OnHitBreakpointEvent(continue, nil);
|
||||||
end;
|
|
||||||
// but do not continue
|
|
||||||
HasPauseRequest := False;
|
HasPauseRequest := False;
|
||||||
|
end;
|
||||||
continue:=false;
|
continue:=false;
|
||||||
end;
|
end;
|
||||||
deBreakpoint:
|
deBreakpoint:
|
||||||
begin
|
begin
|
||||||
// If there is no breakpoint AND no pause-request then this is a deferred, allready handled pause request
|
// If there is no breakpoint AND no pause-request then this is a deferred, allready handled pause request
|
||||||
continue := (FCurrentProcess.CurrentBreakpoint = nil) and (not HasPauseRequest);
|
continue := (FCurrentProcess.CurrentBreakpoint = nil) and (CurWatch = nil) and (not HasPauseRequest);
|
||||||
if (not continue) and assigned(OnHitBreakpointEvent) then
|
if (not continue) and assigned(OnHitBreakpointEvent) then begin
|
||||||
|
if (CurWatch <> nil) then
|
||||||
|
OnHitBreakpointEvent(continue, CurWatch);
|
||||||
|
if assigned(FCurrentProcess.CurrentBreakpoint) then
|
||||||
OnHitBreakpointEvent(continue, FCurrentProcess.CurrentBreakpoint);
|
OnHitBreakpointEvent(continue, FCurrentProcess.CurrentBreakpoint);
|
||||||
HasPauseRequest := False;
|
HasPauseRequest := False;
|
||||||
end;
|
end;
|
||||||
|
end;
|
||||||
deExitProcess:
|
deExitProcess:
|
||||||
begin
|
begin
|
||||||
(* Only events for the main process get here / See ProcessLoop *)
|
(* Only events for the main process get here / See ProcessLoop *)
|
||||||
|
@ -13,7 +13,7 @@ uses
|
|||||||
process,
|
process,
|
||||||
FpDbgClasses,
|
FpDbgClasses,
|
||||||
FpDbgLoader,
|
FpDbgLoader,
|
||||||
DbgIntfBaseTypes,
|
DbgIntfBaseTypes, DbgIntfDebuggerBase,
|
||||||
FpDbgLinuxExtra,
|
FpDbgLinuxExtra,
|
||||||
FpDbgDwarfDataClasses,
|
FpDbgDwarfDataClasses,
|
||||||
FpImgReaderMacho,
|
FpImgReaderMacho,
|
||||||
@ -113,9 +113,10 @@ type
|
|||||||
function ReadDebugState: boolean;
|
function ReadDebugState: boolean;
|
||||||
public
|
public
|
||||||
function ResetInstructionPointerAfterBreakpoint: boolean; override;
|
function ResetInstructionPointerAfterBreakpoint: boolean; override;
|
||||||
function AddWatchpoint(AnAddr: TDBGPtr): integer; override;
|
function AddWatchpoint(AnAddr: TDBGPtr; ASize: Cardinal; AReadWrite: TDBGWatchPointKind): integer; override;
|
||||||
function RemoveWatchpoint(AnId: integer): boolean; override;
|
function RemoveWatchpoint(AnId: integer): boolean; override;
|
||||||
function DetectHardwareWatchpoint: integer; override;
|
procedure ApplyWatchPoints(AWatchPointData: TFpWatchPointData); override;
|
||||||
|
function DetectHardwareWatchpoint: Pointer; override;
|
||||||
procedure BeforeContinue; override;
|
procedure BeforeContinue; override;
|
||||||
procedure LoadRegisterValues; override;
|
procedure LoadRegisterValues; override;
|
||||||
|
|
||||||
@ -144,6 +145,7 @@ type
|
|||||||
procedure InitializeLoaders; override;
|
procedure InitializeLoaders; override;
|
||||||
function CreateThread(AthreadIdentifier: THandle; out IsMainThread: boolean): TDbgThread; override;
|
function CreateThread(AthreadIdentifier: THandle; out IsMainThread: boolean): TDbgThread; override;
|
||||||
function AnalyseDebugEvent(AThread: TDbgThread): TFPDEvent; override;
|
function AnalyseDebugEvent(AThread: TDbgThread): TFPDEvent; override;
|
||||||
|
function CreateWatchPointData: TFpWatchPointData; override;
|
||||||
public
|
public
|
||||||
class function StartInstance(AFileName: string; AParams, AnEnvironment: TStrings; AWorkingDirectory, AConsoleTty: string; AFlags: TStartInstanceFlags): TDbgProcess; override;
|
class function StartInstance(AFileName: string; AParams, AnEnvironment: TStrings; AWorkingDirectory, AConsoleTty: string; AFlags: TStartInstanceFlags): TDbgProcess; override;
|
||||||
constructor Create(const AName: string; const AProcessID, AThreadID: Integer); override;
|
constructor Create(const AName: string; const AProcessID, AThreadID: Integer); override;
|
||||||
@ -382,128 +384,64 @@ type
|
|||||||
TDr32bitArr = array[0..4] of cuint32;
|
TDr32bitArr = array[0..4] of cuint32;
|
||||||
TDr64bitArr = array[0..4] of cuint64;
|
TDr64bitArr = array[0..4] of cuint64;
|
||||||
|
|
||||||
function TDbgDarwinThread.AddWatchpoint(AnAddr: TDBGPtr): integer;
|
procedure TDbgDarwinThread.ApplyWatchPoints(AWatchPointData: TFpWatchPointData);
|
||||||
|
procedure UpdateWatches32;
|
||||||
function SetBreakpoint32(ind: byte): boolean;
|
|
||||||
var
|
var
|
||||||
drArr: ^TDr32bitArr;
|
drArr: ^TDr32bitArr;
|
||||||
|
i: Integer;
|
||||||
|
r: boolean;
|
||||||
|
addr: cuint32;
|
||||||
begin
|
begin
|
||||||
drArr := @FDebugState32.__dr0;
|
drArr := @FDebugState32.__dr0;
|
||||||
if (drArr^[ind]=0) and ((FDebugState32.__dr7 and (1 shl ind))=0) then
|
|
||||||
begin
|
r := True;
|
||||||
FDebugState32.__dr7 := FDebugState32.__dr7 or (1 shl (ind*2));
|
for i := 0 to 3 do begin
|
||||||
FDebugState32.__dr7 := FDebugState32.__dr7 or ($30000 shl (ind*4));
|
addr := cuint32(TFpIntelWatchPointData(AWatchPointData).Dr03[i]);
|
||||||
drArr^[ind]:=AnAddr;
|
drArr^[i]:=addr;
|
||||||
FDebugStateChanged:=true;
|
|
||||||
Result := True;
|
|
||||||
end
|
|
||||||
else
|
|
||||||
begin
|
|
||||||
result := False;
|
|
||||||
end;
|
end;
|
||||||
|
FDebugState32.__dr7 := (FDebugState32.__dr7 and $0000FF00);
|
||||||
|
if r then
|
||||||
|
FDebugState32.__dr7 := FDebugState32.__dr7 or cuint32(TFpIntelWatchPointData(AWatchPointData).Dr7);
|
||||||
end;
|
end;
|
||||||
|
|
||||||
function SetBreakpoint64(ind: byte): boolean;
|
procedure UpdateWatches64;
|
||||||
var
|
var
|
||||||
drArr: ^TDr64bitArr;
|
drArr: ^TDr64bitArr;
|
||||||
|
i: Integer;
|
||||||
|
r: boolean;
|
||||||
|
addr: cuint64;
|
||||||
begin
|
begin
|
||||||
drArr := @FDebugState64.__dr0;
|
drArr := @FDebugState64.__dr0;
|
||||||
if (drArr^[ind]=0) and ((FDebugState64.__dr7 and (1 shl ind))=0) then
|
|
||||||
begin
|
|
||||||
FDebugState64.__dr7 := FDebugState64.__dr7 or (1 shl (ind*2));
|
|
||||||
FDebugState64.__dr7 := FDebugState64.__dr7 or ($30000 shl (ind*4));
|
|
||||||
drArr^[ind]:=AnAddr;
|
|
||||||
FDebugStateChanged:=true;
|
|
||||||
Result := True;
|
|
||||||
end
|
|
||||||
else
|
|
||||||
begin
|
|
||||||
result := False;
|
|
||||||
end;
|
|
||||||
end;
|
|
||||||
|
|
||||||
var
|
r := True;
|
||||||
i: integer;
|
for i := 0 to 3 do begin
|
||||||
begin
|
addr := cuint64(TFpIntelWatchPointData(AWatchPointData).Dr03[i]);
|
||||||
result := -1;
|
drArr^[i]:=addr;
|
||||||
if ID<0 then
|
|
||||||
Exit;
|
|
||||||
if not ReadDebugState then
|
|
||||||
exit;
|
|
||||||
|
|
||||||
i := 0;
|
|
||||||
if Process.Mode=dm32 then
|
|
||||||
while (i<4) and not SetBreakpoint32(i) do
|
|
||||||
inc(i)
|
|
||||||
else
|
|
||||||
while (i<4) and not SetBreakpoint64(i) do
|
|
||||||
inc(i);
|
|
||||||
if i=4 then
|
|
||||||
debugln(DBG_WARNINGS, 'No hardware breakpoint available.')
|
|
||||||
else
|
|
||||||
result := i;
|
|
||||||
end;
|
|
||||||
|
|
||||||
function TDbgDarwinThread.RemoveWatchpoint(AnId: integer): boolean;
|
|
||||||
|
|
||||||
function RemoveBreakpoint32(ind: byte): boolean;
|
|
||||||
var
|
|
||||||
drArr: ^TDr32bitArr;
|
|
||||||
begin
|
|
||||||
drArr := @FDebugState32.__dr0;
|
|
||||||
if (drArr^[ind]<>0) and ((FDebugState32.__dr7 and (1 shl (ind*2)))<>0) then
|
|
||||||
begin
|
|
||||||
FDebugState32.__dr7 := FDebugState32.__dr7 xor (1 shl (ind*2));
|
|
||||||
FDebugState32.__dr7 := FDebugState32.__dr7 xor ($30000 shl (ind*4));
|
|
||||||
drArr^[ind]:=0;
|
|
||||||
FDebugStateChanged:=true;
|
|
||||||
Result := True;
|
|
||||||
end
|
|
||||||
else
|
|
||||||
begin
|
|
||||||
result := False;
|
|
||||||
debugln(DBG_WARNINGS, 'HW watchpoint %d is not set.',[ind]);
|
|
||||||
end;
|
|
||||||
end;
|
|
||||||
|
|
||||||
function RemoveBreakpoint64(ind: byte): boolean;
|
|
||||||
var
|
|
||||||
drArr: ^TDr64bitArr;
|
|
||||||
begin
|
|
||||||
drArr := @FDebugState64.__dr0;
|
|
||||||
if (drArr^[ind]<>0) and ((FDebugState64.__dr7 and (1 shl (ind*2)))<>0) then
|
|
||||||
begin
|
|
||||||
FDebugState64.__dr7 := FDebugState64.__dr7 xor (1 shl (ind*2));
|
|
||||||
FDebugState64.__dr7 := FDebugState64.__dr7 xor ($30000 shl (ind*4));
|
|
||||||
drArr^[ind]:=0;
|
|
||||||
FDebugStateChanged:=true;
|
|
||||||
Result := True;
|
|
||||||
end
|
|
||||||
else
|
|
||||||
begin
|
|
||||||
result := False;
|
|
||||||
debugln(DBG_WARNINGS, 'HW watchpoint %d is not set.',[ind]);
|
|
||||||
end;
|
end;
|
||||||
|
FDebugState32.__dr7 := (FDebugState32.__dr7 and $0000FF00);
|
||||||
|
if r then
|
||||||
|
FDebugState32.__dr7 := FDebugState32.__dr7 or cuint64(TFpIntelWatchPointData(AWatchPointData).Dr7);
|
||||||
end;
|
end;
|
||||||
|
|
||||||
begin
|
begin
|
||||||
result := false;
|
|
||||||
if ID<0 then
|
if ID<0 then
|
||||||
Exit;
|
Exit;
|
||||||
if not ReadDebugState then
|
if not ReadDebugState then
|
||||||
exit;
|
exit;
|
||||||
|
|
||||||
if Process.Mode=dm32 then
|
if Process.Mode=dm32 then
|
||||||
result := RemoveBreakpoint32(AnId)
|
result := UpdateWatches32
|
||||||
else
|
else
|
||||||
result := RemoveBreakpoint64(AnId);
|
result := UpdateWatches64;
|
||||||
|
FDebugStateChanged:=true;
|
||||||
end;
|
end;
|
||||||
|
|
||||||
function TDbgDarwinThread.DetectHardwareWatchpoint: integer;
|
function TDbgDarwinThread.DetectHardwareWatchpoint: Pointer;
|
||||||
var
|
var
|
||||||
dr6: DWord;
|
dr6: DWord;
|
||||||
|
wd: TFpIntelWatchPointData;
|
||||||
begin
|
begin
|
||||||
result := -1;
|
result := nil;
|
||||||
if ID<0 then
|
if ID<0 then
|
||||||
Exit;
|
Exit;
|
||||||
if ReadDebugState then
|
if ReadDebugState then
|
||||||
@ -513,10 +451,13 @@ begin
|
|||||||
else
|
else
|
||||||
dr6 := lo(FDebugState64.__dr6);
|
dr6 := lo(FDebugState64.__dr6);
|
||||||
|
|
||||||
if dr6 and 1 = 1 then result := 0
|
wd := TFpIntelWatchPointData(Process.WatchPointData);
|
||||||
else if dr6 and 2 = 2 then result := 1
|
if dr6 and 1 = 1 then result := wd.Owner[0]
|
||||||
else if dr6 and 4 = 4 then result := 2
|
else if dr6 and 2 = 2 then result := wd.Owner[1]
|
||||||
else if dr6 and 8 = 8 then result := 3;
|
else if dr6 and 4 = 4 then result := wd.Owner[2]
|
||||||
|
else if dr6 and 8 = 8 then result := wd.Owner[3];
|
||||||
|
if (Result = nil) and ((dr6 and 15) <> 0) then
|
||||||
|
Result := Pointer(-1); // not owned watchpoint
|
||||||
end;
|
end;
|
||||||
end;
|
end;
|
||||||
|
|
||||||
@ -526,7 +467,7 @@ var
|
|||||||
old_StateCnt: mach_msg_Type_number_t;
|
old_StateCnt: mach_msg_Type_number_t;
|
||||||
begin
|
begin
|
||||||
inherited;
|
inherited;
|
||||||
if Process.CurrentWatchpoint>-1 then
|
if Process.CurrentWatchpoint <> nil then
|
||||||
begin
|
begin
|
||||||
if Process.Mode=dm32 then
|
if Process.Mode=dm32 then
|
||||||
FDebugState32.__dr6:=0
|
FDebugState32.__dr6:=0
|
||||||
@ -680,6 +621,11 @@ begin
|
|||||||
result := TDbgDarwinThread.Create(Self, AthreadIdentifier, AthreadIdentifier)
|
result := TDbgDarwinThread.Create(Self, AthreadIdentifier, AthreadIdentifier)
|
||||||
end;
|
end;
|
||||||
|
|
||||||
|
function TDbgDarwinProcess.CreateWatchPointData: TFpWatchPointData;
|
||||||
|
begin
|
||||||
|
Result := TFpIntelWatchPointData.Create;
|
||||||
|
end;
|
||||||
|
|
||||||
constructor TDbgDarwinProcess.Create(const AName: string; const AProcessID,
|
constructor TDbgDarwinProcess.Create(const AName: string; const AProcessID,
|
||||||
AThreadID: Integer);
|
AThreadID: Integer);
|
||||||
var
|
var
|
||||||
|
@ -15,7 +15,7 @@ uses
|
|||||||
process,
|
process,
|
||||||
FpDbgClasses,
|
FpDbgClasses,
|
||||||
FpDbgLoader,
|
FpDbgLoader,
|
||||||
DbgIntfBaseTypes,
|
DbgIntfBaseTypes, DbgIntfDebuggerBase,
|
||||||
FpDbgLinuxExtra,
|
FpDbgLinuxExtra,
|
||||||
FpDbgInfo,
|
FpDbgInfo,
|
||||||
FpDbgUtil,
|
FpDbgUtil,
|
||||||
@ -261,9 +261,8 @@ type
|
|||||||
procedure ResetPauseStates;
|
procedure ResetPauseStates;
|
||||||
public
|
public
|
||||||
function ResetInstructionPointerAfterBreakpoint: boolean; override;
|
function ResetInstructionPointerAfterBreakpoint: boolean; override;
|
||||||
function AddWatchpoint(AnAddr: TDBGPtr): integer; override;
|
procedure ApplyWatchPoints(AWatchPointData: TFpWatchPointData); override;
|
||||||
function RemoveWatchpoint(AnId: integer): boolean; override;
|
function DetectHardwareWatchpoint: Pointer; override;
|
||||||
function DetectHardwareWatchpoint: integer; override;
|
|
||||||
procedure BeforeContinue; override;
|
procedure BeforeContinue; override;
|
||||||
procedure LoadRegisterValues; override;
|
procedure LoadRegisterValues; override;
|
||||||
|
|
||||||
@ -290,6 +289,7 @@ type
|
|||||||
procedure InitializeLoaders; override;
|
procedure InitializeLoaders; override;
|
||||||
function CreateThread(AthreadIdentifier: THandle; out IsMainThread: boolean): TDbgThread; override;
|
function CreateThread(AthreadIdentifier: THandle; out IsMainThread: boolean): TDbgThread; override;
|
||||||
function AnalyseDebugEvent(AThread: TDbgThread): TFPDEvent; override;
|
function AnalyseDebugEvent(AThread: TDbgThread): TFPDEvent; override;
|
||||||
|
function CreateWatchPointData: TFpWatchPointData; override;
|
||||||
public
|
public
|
||||||
class function StartInstance(AFileName: string; AParams, AnEnvironment: TStrings;
|
class function StartInstance(AFileName: string; AParams, AnEnvironment: TStrings;
|
||||||
AWorkingDirectory, AConsoleTty: string; AFlags: TStartInstanceFlags): TDbgProcess; override;
|
AWorkingDirectory, AConsoleTty: string; AFlags: TStartInstanceFlags): TDbgProcess; override;
|
||||||
@ -558,76 +558,42 @@ begin
|
|||||||
FUserRegsChanged:=true;
|
FUserRegsChanged:=true;
|
||||||
end;
|
end;
|
||||||
|
|
||||||
function TDbgLinuxThread.AddWatchpoint(AnAddr: TDBGPtr): integer;
|
procedure TDbgLinuxThread.ApplyWatchPoints(AWatchPointData: TFpWatchPointData);
|
||||||
var
|
|
||||||
dr7: PtrUInt;
|
|
||||||
|
|
||||||
function SetHWBreakpoint(ind: byte): boolean;
|
|
||||||
var
|
|
||||||
Addr: PtrUInt;
|
|
||||||
begin
|
|
||||||
result := false;
|
|
||||||
if ((dr7 and (1 shl ind))=0) then
|
|
||||||
begin
|
|
||||||
if not ReadDebugReg(ind, Addr) or (Addr<>0) then
|
|
||||||
Exit;
|
|
||||||
|
|
||||||
dr7 := dr7 or (1 shl (ind*2));
|
|
||||||
dr7 := dr7 or ($30000 shl (ind*4));
|
|
||||||
if WriteDebugReg(7, dr7) and WriteDebugReg(ind, AnAddr) then
|
|
||||||
result := true;
|
|
||||||
end;
|
|
||||||
end;
|
|
||||||
|
|
||||||
var
|
var
|
||||||
i: integer;
|
i: integer;
|
||||||
begin
|
r: boolean;
|
||||||
result := -1;
|
|
||||||
if not ReadDebugReg(7, dr7) then
|
|
||||||
Exit;
|
|
||||||
|
|
||||||
i := 0;
|
|
||||||
while (i<4) and not SetHWBreakpoint(i) do
|
|
||||||
inc(i);
|
|
||||||
if i=4 then
|
|
||||||
DebugLn(DBG_WARNINGS, 'No hardware breakpoint available.')
|
|
||||||
else
|
|
||||||
result := i;
|
|
||||||
end;
|
|
||||||
|
|
||||||
function TDbgLinuxThread.RemoveWatchpoint(AnId: integer): boolean;
|
|
||||||
var
|
|
||||||
dr7: PtrUInt;
|
dr7: PtrUInt;
|
||||||
addr: PtrUInt;
|
addr: PtrUInt;
|
||||||
begin
|
begin
|
||||||
result := false;
|
if not ReadDebugReg(7, dr7) then
|
||||||
if not ReadDebugReg(7, dr7) or not ReadDebugReg(AnId, addr) then
|
|
||||||
Exit;
|
Exit;
|
||||||
|
|
||||||
if (addr<>0) and ((dr7 and (1 shl (AnId*2)))<>0) then
|
r := True;
|
||||||
begin
|
for i := 0 to 3 do begin
|
||||||
dr7 := dr7 xor (1 shl (AnId*2));
|
addr := PtrUInt(TFpIntelWatchPointData(AWatchPointData).Dr03[i]);
|
||||||
dr7 := dr7 xor ($30000 shl (AnId*4));
|
r := r and WriteDebugReg(i, addr);
|
||||||
if WriteDebugReg(AnId, 0) and WriteDebugReg(7, dr7) then
|
|
||||||
Result := True;
|
|
||||||
end
|
|
||||||
else
|
|
||||||
begin
|
|
||||||
DebugLn(DBG_WARNINGS, 'HW watchpoint %d is not set.',[AnId]);
|
|
||||||
end;
|
end;
|
||||||
|
Dr7 := (Dr7 and $0000FF00);
|
||||||
|
if r then
|
||||||
|
Dr7 := Dr7 or PtrUInt(TFpIntelWatchPointData(AWatchPointData).Dr7);
|
||||||
|
WriteDebugReg(7, dr7);
|
||||||
end;
|
end;
|
||||||
|
|
||||||
function TDbgLinuxThread.DetectHardwareWatchpoint: integer;
|
function TDbgLinuxThread.DetectHardwareWatchpoint: Pointer;
|
||||||
var
|
var
|
||||||
dr6: PtrUInt;
|
dr6: PtrUInt;
|
||||||
|
wd: TFpIntelWatchPointData;
|
||||||
begin
|
begin
|
||||||
result := -1;
|
result := nil;
|
||||||
if ReadDebugReg(6, dr6) then
|
if ReadDebugReg(6, dr6) then
|
||||||
begin
|
begin
|
||||||
if dr6 and 1 = 1 then result := 0
|
wd := TFpIntelWatchPointData(Process.WatchPointData);
|
||||||
else if dr6 and 2 = 2 then result := 1
|
if dr6 and 1 = 1 then result := wd.Owner[0]
|
||||||
else if dr6 and 4 = 4 then result := 2
|
else if dr6 and 2 = 2 then result := wd.Owner[1]
|
||||||
else if dr6 and 8 = 8 then result := 3;
|
else if dr6 and 4 = 4 then result := wd.Owner[2]
|
||||||
|
else if dr6 and 8 = 8 then result := wd.Owner[3];
|
||||||
|
if (Result = nil) and ((dr6 and 15) <> 0) then
|
||||||
|
Result := Pointer(-1); // not owned watchpoint
|
||||||
end;
|
end;
|
||||||
end;
|
end;
|
||||||
|
|
||||||
@ -639,7 +605,7 @@ begin
|
|||||||
exit;
|
exit;
|
||||||
|
|
||||||
inherited;
|
inherited;
|
||||||
if Process.CurrentWatchpoint>-1 then
|
if Process.CurrentWatchpoint <> nil then
|
||||||
WriteDebugReg(6, 0);
|
WriteDebugReg(6, 0);
|
||||||
|
|
||||||
if FUserRegsChanged then
|
if FUserRegsChanged then
|
||||||
@ -761,6 +727,11 @@ begin
|
|||||||
result := nil;
|
result := nil;
|
||||||
end;
|
end;
|
||||||
|
|
||||||
|
function TDbgLinuxProcess.CreateWatchPointData: TFpWatchPointData;
|
||||||
|
begin
|
||||||
|
Result := TFpIntelWatchPointData.Create;
|
||||||
|
end;
|
||||||
|
|
||||||
constructor TDbgLinuxProcess.Create(const AName: string; const AProcessID,
|
constructor TDbgLinuxProcess.Create(const AName: string; const AProcessID,
|
||||||
AThreadID: Integer);
|
AThreadID: Integer);
|
||||||
begin
|
begin
|
||||||
|
@ -117,7 +117,7 @@ uses
|
|||||||
strutils,
|
strutils,
|
||||||
FpDbgInfo,
|
FpDbgInfo,
|
||||||
FpDbgLoader,
|
FpDbgLoader,
|
||||||
DbgIntfBaseTypes,
|
DbgIntfBaseTypes, DbgIntfDebuggerBase,
|
||||||
LazLoggerBase, UTF8Process;
|
LazLoggerBase, UTF8Process;
|
||||||
|
|
||||||
type
|
type
|
||||||
@ -146,8 +146,8 @@ type
|
|||||||
procedure SetSingleStepOverBreakPoint;
|
procedure SetSingleStepOverBreakPoint;
|
||||||
procedure EndSingleStepOverBreakPoint;
|
procedure EndSingleStepOverBreakPoint;
|
||||||
procedure SetSingleStep;
|
procedure SetSingleStep;
|
||||||
function AddWatchpoint(AnAddr: TDBGPtr): integer; override;
|
procedure ApplyWatchPoints(AWatchPointData: TFpWatchPointData); override;
|
||||||
function RemoveWatchpoint(AnId: integer): boolean; override;
|
function DetectHardwareWatchpoint: Pointer; override;
|
||||||
procedure BeforeContinue; override;
|
procedure BeforeContinue; override;
|
||||||
function ResetInstructionPointerAfterBreakpoint: boolean; override;
|
function ResetInstructionPointerAfterBreakpoint: boolean; override;
|
||||||
function ReadThreadState: boolean;
|
function ReadThreadState: boolean;
|
||||||
@ -175,6 +175,7 @@ type
|
|||||||
function GetHandle: THandle; override;
|
function GetHandle: THandle; override;
|
||||||
function GetLastEventProcessIdentifier: THandle; override;
|
function GetLastEventProcessIdentifier: THandle; override;
|
||||||
procedure InitializeLoaders; override;
|
procedure InitializeLoaders; override;
|
||||||
|
function CreateWatchPointData: TFpWatchPointData; override;
|
||||||
public
|
public
|
||||||
constructor Create(const AFileName: string; const AProcessID, AThreadID: Integer); override;
|
constructor Create(const AFileName: string; const AProcessID, AThreadID: Integer); override;
|
||||||
destructor Destroy; override;
|
destructor Destroy; override;
|
||||||
@ -476,6 +477,11 @@ begin
|
|||||||
TDbgImageLoader.Create(FInfo.hFile).AddToLoaderList(LoaderList);
|
TDbgImageLoader.Create(FInfo.hFile).AddToLoaderList(LoaderList);
|
||||||
end;
|
end;
|
||||||
|
|
||||||
|
function TDbgWinProcess.CreateWatchPointData: TFpWatchPointData;
|
||||||
|
begin
|
||||||
|
Result := TFpIntelWatchPointData.Create;
|
||||||
|
end;
|
||||||
|
|
||||||
constructor TDbgWinProcess.Create(const AFileName: string; const AProcessID,
|
constructor TDbgWinProcess.Create(const AFileName: string; const AProcessID,
|
||||||
AThreadID: Integer);
|
AThreadID: Integer);
|
||||||
begin
|
begin
|
||||||
@ -812,7 +818,7 @@ begin
|
|||||||
DebugLn([dbgs(MDebugEvent), ' ', Result]);
|
DebugLn([dbgs(MDebugEvent), ' ', Result]);
|
||||||
for TDbgThread(t) in FThreadMap do begin
|
for TDbgThread(t) in FThreadMap do begin
|
||||||
if t.ReadThreadState then
|
if t.ReadThreadState then
|
||||||
DebugLn('Thr.Id:%d %x SSTep %s EF %s DR6:%x WP:%x RegAcc: %d, SStep: %d Task: %d, ExcBrk: %d', [t.ID, t.GetInstructionPointerRegisterValue, dbgs(t.FCurrentContext^.def.EFlags and FLAG_TRACE_BIT), dbghex(t.FCurrentContext^.def.EFlags), t.FCurrentContext^.def.Dr6, t.FCurrentContext^.def.Dr6 and 15, t.FCurrentContext^.def.Dr6 and (1<< 13), t.FCurrentContext^.def.Dr6 and (1<< 14), t.FCurrentContext^.def.Dr6 and (1<< 15), t.FCurrentContext^.def.Dr6 and (1<< 16)]);
|
DebugLn('Thr.Id:%d %x SSTep %s EF %s DR6:%x DR7:%x WP:%x RegAcc: %d, SStep: %d Task: %d, ExcBrk: %d', [t.ID, t.GetInstructionPointerRegisterValue, dbgs(t.FCurrentContext^.def.EFlags and FLAG_TRACE_BIT), dbghex(t.FCurrentContext^.def.EFlags), t.FCurrentContext^.def.Dr6, t.FCurrentContext^.def.Dr7, t.FCurrentContext^.def.Dr6 and 15, t.FCurrentContext^.def.Dr6 and (1<< 13), t.FCurrentContext^.def.Dr6 and (1<< 14), t.FCurrentContext^.def.Dr6 and (1<< 15), t.FCurrentContext^.def.Dr6 and (1<< 16)]);
|
||||||
end;
|
end;
|
||||||
{$ENDIF}
|
{$ENDIF}
|
||||||
|
|
||||||
@ -1481,141 +1487,71 @@ begin
|
|||||||
FThreadContextChanged:=true;
|
FThreadContextChanged:=true;
|
||||||
end;
|
end;
|
||||||
|
|
||||||
function TDbgWinThread.AddWatchpoint(AnAddr: TDBGPtr): integer;
|
procedure TDbgWinThread.ApplyWatchPoints(AWatchPointData: TFpWatchPointData);
|
||||||
|
|
||||||
function SetBreakpoint(var Dr, Dr7: DWORD; ind: byte): boolean;
|
|
||||||
begin
|
begin
|
||||||
if (Dr=0) and ((Dr7 and (1 shl ind))=0) then
|
|
||||||
begin
|
|
||||||
Dr7 := Dr7 or (1 shl (ind*2));
|
|
||||||
Dr7 := Dr7 or ($30000 shl (ind*4));
|
|
||||||
Dr:=AnAddr;
|
|
||||||
FThreadContextChanged:=true;
|
|
||||||
Result := True;
|
|
||||||
end
|
|
||||||
else
|
|
||||||
Result := False;
|
|
||||||
end;
|
|
||||||
function SetBreakpoint(var Dr, Dr7: DWORD64; ind: byte): boolean;
|
|
||||||
begin
|
|
||||||
if (Dr=0) and ((Dr7 and (1 shl ind))=0) then
|
|
||||||
begin
|
|
||||||
Dr7 := Dr7 or (1 shl (ind*2));
|
|
||||||
Dr7 := Dr7 or ($30000 shl (ind*4));
|
|
||||||
Dr:=AnAddr;
|
|
||||||
FThreadContextChanged:=true;
|
|
||||||
Result := True;
|
|
||||||
end
|
|
||||||
else
|
|
||||||
Result := False;
|
|
||||||
end;
|
|
||||||
|
|
||||||
begin
|
|
||||||
result := -1;
|
|
||||||
if FCurrentContext = nil then
|
if FCurrentContext = nil then
|
||||||
if not ReadThreadState then
|
if not ReadThreadState then
|
||||||
exit;
|
exit;
|
||||||
{$ifdef cpux86_64}
|
{$ifdef cpux86_64}
|
||||||
if (TDbgWinProcess(Process).FBitness = b32) then begin
|
if (TDbgWinProcess(Process).FBitness = b32) then begin
|
||||||
with FCurrentContext^.WOW do
|
with FCurrentContext^.WOW do begin
|
||||||
if SetBreakpoint(Dr0, DR7, 0) then
|
Dr0 := DWORD(TFpIntelWatchPointData(AWatchPointData).Dr03[0]);
|
||||||
result := 0
|
Dr1 := DWORD(TFpIntelWatchPointData(AWatchPointData).Dr03[1]);
|
||||||
else if SetBreakpoint(Dr1, DR7, 1) then
|
Dr2 := DWORD(TFpIntelWatchPointData(AWatchPointData).Dr03[2]);
|
||||||
result := 1
|
Dr3 := DWORD(TFpIntelWatchPointData(AWatchPointData).Dr03[3]);
|
||||||
else if SetBreakpoint(Dr2, DR7, 2) then
|
Dr7 := (Dr7 and $0000FF00) or DWORD(TFpIntelWatchPointData(AWatchPointData).Dr7);
|
||||||
result := 2
|
DebugLn('### WATCH ADDED dr0 %x dr1 %x dr2 %x dr3 %x dr7 %x', [ dr0,dr1,dr2,dr3, dr7]);
|
||||||
else if SetBreakpoint(Dr3, DR7, 3) then
|
end;
|
||||||
result := 3
|
|
||||||
else
|
|
||||||
DebugLn(DBG_WARNINGS ,'No hardware breakpoint available.');
|
|
||||||
end
|
end
|
||||||
else begin
|
else begin
|
||||||
{$endif}
|
{$endif}
|
||||||
with FCurrentContext^.def do
|
with FCurrentContext^.def do begin
|
||||||
if SetBreakpoint(Dr0, DR7, 0) then
|
Dr0 := TFpIntelWatchPointData(AWatchPointData).Dr03[0];
|
||||||
result := 0
|
Dr1 := TFpIntelWatchPointData(AWatchPointData).Dr03[1];
|
||||||
else if SetBreakpoint(Dr1, DR7, 1) then
|
Dr2 := TFpIntelWatchPointData(AWatchPointData).Dr03[2];
|
||||||
result := 1
|
Dr3 := TFpIntelWatchPointData(AWatchPointData).Dr03[3];
|
||||||
else if SetBreakpoint(Dr2, DR7, 2) then
|
Dr7 := (Dr7 and $0000FF00) or TFpIntelWatchPointData(AWatchPointData).Dr7;
|
||||||
result := 2
|
DebugLn('### WATCH ADDED dr0 %x dr1 %x dr2 %x dr3 %x dr7 %x', [ dr0,dr1,dr2,dr3, dr7]);
|
||||||
else if SetBreakpoint(Dr3, DR7, 3) then
|
end;
|
||||||
result := 3
|
|
||||||
else
|
|
||||||
DebugLn(DBG_WARNINGS ,'No hardware breakpoint available.');
|
|
||||||
{$ifdef cpux86_64}
|
{$ifdef cpux86_64}
|
||||||
end;
|
end;
|
||||||
{$endif}
|
{$endif}
|
||||||
end;
|
|
||||||
|
|
||||||
function TDbgWinThread.RemoveWatchpoint(AnId: integer): boolean;
|
|
||||||
|
|
||||||
function RemoveBreakpoint(var Dr, Dr7: DWORD; ind: byte): boolean;
|
|
||||||
begin
|
|
||||||
if (Dr<>0) and ((Dr7 and (1 shl (ind*2)))<>0) then
|
|
||||||
begin
|
|
||||||
Dr7 := Dr7 xor (1 shl (ind*2));
|
|
||||||
Dr7 := Dr7 xor ($30000 shl (ind*4));
|
|
||||||
Dr:=0;
|
|
||||||
FThreadContextChanged:=true;
|
FThreadContextChanged:=true;
|
||||||
Result := True;
|
|
||||||
end
|
|
||||||
else
|
|
||||||
begin
|
|
||||||
result := False;
|
|
||||||
DebugLn(DBG_WARNINGS ,'HW watchpoint is not set.');
|
|
||||||
end;
|
|
||||||
end;
|
|
||||||
function RemoveBreakpoint(var Dr, Dr7: DWORD64; ind: byte): boolean;
|
|
||||||
begin
|
|
||||||
if (Dr<>0) and ((Dr7 and (1 shl (ind*2)))<>0) then
|
|
||||||
begin
|
|
||||||
Dr7 := Dr7 xor (1 shl (ind*2));
|
|
||||||
Dr7 := Dr7 xor ($30000 shl (ind*4));
|
|
||||||
Dr:=0;
|
|
||||||
FThreadContextChanged:=true;
|
|
||||||
Result := True;
|
|
||||||
end
|
|
||||||
else
|
|
||||||
begin
|
|
||||||
result := False;
|
|
||||||
DebugLn(DBG_WARNINGS ,'HW watchpoint is not set.');
|
|
||||||
end;
|
|
||||||
end;
|
end;
|
||||||
|
|
||||||
|
function TDbgWinThread.DetectHardwareWatchpoint: Pointer;
|
||||||
|
var
|
||||||
|
Dr6: DWORD64;
|
||||||
|
wd: TFpIntelWatchPointData;
|
||||||
begin
|
begin
|
||||||
Result := False;
|
result := nil;
|
||||||
if FCurrentContext = nil then
|
if FCurrentContext = nil then
|
||||||
if not ReadThreadState then
|
if not ReadThreadState then
|
||||||
exit;
|
exit;
|
||||||
|
|
||||||
{$ifdef cpux86_64}
|
{$ifdef cpux86_64}
|
||||||
if (TDbgWinProcess(Process).FBitness = b32) then begin
|
if (TDbgWinProcess(Process).FBitness = b32) then begin
|
||||||
with FCurrentContext^.WOW do
|
Dr6 := DWORD64(FCurrentContext^.WOW.Dr6);
|
||||||
case AnId of
|
|
||||||
0: result := RemoveBreakpoint(Dr0, DR7, 0);
|
|
||||||
1: result := RemoveBreakpoint(Dr1, DR7, 1);
|
|
||||||
2: result := RemoveBreakpoint(Dr2, DR7, 2);
|
|
||||||
3: result := RemoveBreakpoint(Dr3, DR7, 3);
|
|
||||||
end
|
|
||||||
end
|
end
|
||||||
else begin
|
else begin
|
||||||
{$endif}
|
{$endif}
|
||||||
with FCurrentContext^.def do
|
Dr6 := FCurrentContext^.def.Dr6;
|
||||||
case AnId of
|
|
||||||
0: result := RemoveBreakpoint(Dr0, DR7, 0);
|
|
||||||
1: result := RemoveBreakpoint(Dr1, DR7, 1);
|
|
||||||
2: result := RemoveBreakpoint(Dr2, DR7, 2);
|
|
||||||
3: result := RemoveBreakpoint(Dr3, DR7, 3);
|
|
||||||
end
|
|
||||||
{$ifdef cpux86_64}
|
{$ifdef cpux86_64}
|
||||||
end;
|
end;
|
||||||
{$endif}
|
{$endif}
|
||||||
|
|
||||||
|
wd := TFpIntelWatchPointData(Process.WatchPointData);
|
||||||
|
if dr6 and 1 = 1 then result := wd.Owner[0]
|
||||||
|
else if dr6 and 2 = 2 then result := wd.Owner[1]
|
||||||
|
else if dr6 and 4 = 4 then result := wd.Owner[2]
|
||||||
|
else if dr6 and 8 = 8 then result := wd.Owner[3];
|
||||||
|
if (Result = nil) and ((dr6 and 15) <> 0) then
|
||||||
|
Result := Pointer(-1); // not owned watchpoint
|
||||||
end;
|
end;
|
||||||
|
|
||||||
procedure TDbgWinThread.BeforeContinue;
|
procedure TDbgWinThread.BeforeContinue;
|
||||||
begin
|
begin
|
||||||
if ID <> MDebugEvent.dwThreadId then
|
if ID = MDebugEvent.dwThreadId then begin
|
||||||
exit;
|
|
||||||
|
|
||||||
inherited;
|
inherited;
|
||||||
|
|
||||||
{$ifdef cpux86_64}
|
{$ifdef cpux86_64}
|
||||||
@ -1638,6 +1574,7 @@ begin
|
|||||||
{$ifdef cpux86_64}
|
{$ifdef cpux86_64}
|
||||||
end;
|
end;
|
||||||
{$endif}
|
{$endif}
|
||||||
|
end;
|
||||||
|
|
||||||
if FThreadContextChanged then
|
if FThreadContextChanged then
|
||||||
begin
|
begin
|
||||||
|
@ -95,6 +95,8 @@ type
|
|||||||
FCacheLocation: TDBGPtr;
|
FCacheLocation: TDBGPtr;
|
||||||
FCacheBoolean: boolean;
|
FCacheBoolean: boolean;
|
||||||
FCachePointer: pointer;
|
FCachePointer: pointer;
|
||||||
|
FCacheReadWrite: TDBGWatchPointKind;
|
||||||
|
FCacheScope: TDBGWatchPointScope;
|
||||||
FCacheThreadId, FCacheStackFrame: Integer;
|
FCacheThreadId, FCacheStackFrame: Integer;
|
||||||
FCacheContext: TFpDbgInfoContext;
|
FCacheContext: TFpDbgInfoContext;
|
||||||
{$endif linux}
|
{$endif linux}
|
||||||
@ -152,6 +154,7 @@ type
|
|||||||
FCallStackEntryListFrameRequired: Integer;
|
FCallStackEntryListFrameRequired: Integer;
|
||||||
procedure DoAddBreakLine;
|
procedure DoAddBreakLine;
|
||||||
procedure DoAddBreakLocation;
|
procedure DoAddBreakLocation;
|
||||||
|
procedure DoAddBWatch;
|
||||||
procedure DoReadData;
|
procedure DoReadData;
|
||||||
procedure DoPrepareCallStackEntryList;
|
procedure DoPrepareCallStackEntryList;
|
||||||
procedure DoFreeBreakpoint;
|
procedure DoFreeBreakpoint;
|
||||||
@ -159,6 +162,8 @@ type
|
|||||||
{$endif linux}
|
{$endif linux}
|
||||||
function AddBreak(const ALocation: TDbgPtr): TFpDbgBreakpoint; overload;
|
function AddBreak(const ALocation: TDbgPtr): TFpDbgBreakpoint; overload;
|
||||||
function AddBreak(const AFileName: String; ALine: Cardinal): TFpDbgBreakpoint; overload;
|
function AddBreak(const AFileName: String; ALine: Cardinal): TFpDbgBreakpoint; overload;
|
||||||
|
function AddWatch(const ALocation: TDBGPtr; ASize: Cardinal; AReadWrite: TDBGWatchPointKind;
|
||||||
|
AScope: TDBGWatchPointScope): TFpDbgBreakpoint;
|
||||||
procedure FreeBreakpoint(const ABreakpoint: 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): Boolean; inline;
|
||||||
function ReadAddress(const AAdress: TDbgPtr; out AData: TDBGPtr): Boolean;
|
function ReadAddress(const AAdress: TDbgPtr; out AData: TDBGPtr): Boolean;
|
||||||
@ -861,19 +866,38 @@ begin
|
|||||||
end;
|
end;
|
||||||
|
|
||||||
procedure TFPBreakpoint.SetBreak;
|
procedure TFPBreakpoint.SetBreak;
|
||||||
|
var
|
||||||
|
CurThreadId, CurStackFrame: Integer;
|
||||||
|
CurContext: TFpDbgInfoContext;
|
||||||
|
WatchPasExpr: TFpPascalExpression;
|
||||||
|
R: TFpValue;
|
||||||
|
s: QWord;
|
||||||
begin
|
begin
|
||||||
assert(FInternalBreakpoint=nil);
|
assert(FInternalBreakpoint=nil);
|
||||||
debuglnEnter(DBG_BREAKPOINTS, ['>> TFPBreakpoint.SetBreak ADD ',FSource,':',FLine,'/',dbghex(Address),' ' ]);
|
debuglnEnter(DBG_BREAKPOINTS, ['>> TFPBreakpoint.SetBreak ADD ',FSource,':',FLine,'/',dbghex(Address),' ' ]);
|
||||||
case Kind of
|
case Kind of
|
||||||
bpkAddress: FInternalBreakpoint := TFpDebugDebugger(Debugger).AddBreak(Address);
|
bpkAddress: FInternalBreakpoint := TFpDebugDebugger(Debugger).AddBreak(Address);
|
||||||
bpkSource: FInternalBreakpoint := TFpDebugDebugger(Debugger).AddBreak(Source, cardinal(Line));
|
bpkSource: FInternalBreakpoint := TFpDebugDebugger(Debugger).AddBreak(Source, cardinal(Line));
|
||||||
else
|
bpkData: begin
|
||||||
Raise Exception.Create('Breakpoints of this kind are not suported.');
|
TFpDebugDebugger(Debugger).GetCurrentThreadAndStackFrame(CurThreadId, CurStackFrame);
|
||||||
|
CurContext := TFpDebugDebugger(Debugger).GetContextForEvaluate(CurThreadId, CurStackFrame);
|
||||||
|
if CurContext <> nil then begin
|
||||||
|
WatchPasExpr := TFpPascalExpression.Create(WatchData, CurContext);
|
||||||
|
R := WatchPasExpr.ResultValue; // Address and Size
|
||||||
|
// TODO: Cache current value
|
||||||
|
if WatchPasExpr.Valid and IsTargetNotNil(R.Address) and R.GetSize(s) then begin
|
||||||
|
// pass context
|
||||||
|
FInternalBreakpoint := TFpDebugDebugger(Debugger).AddWatch(R.Address.Address, s, WatchKind, WatchScope);
|
||||||
|
end;
|
||||||
|
WatchPasExpr.Free;
|
||||||
|
CurContext.ReleaseReference;
|
||||||
|
end;
|
||||||
|
end;
|
||||||
end;
|
end;
|
||||||
debuglnExit(DBG_BREAKPOINTS, ['<< TFPBreakpoint.SetBreak ' ]);
|
debuglnExit(DBG_BREAKPOINTS, ['<< TFPBreakpoint.SetBreak ' ]);
|
||||||
FIsSet:=true;
|
FIsSet:=true;
|
||||||
if not assigned(FInternalBreakpoint) then
|
if not assigned(FInternalBreakpoint) then
|
||||||
FValid:=vsInvalid
|
FValid:=vsInvalid // pending?
|
||||||
else
|
else
|
||||||
FValid:=vsValid;
|
FValid:=vsValid;
|
||||||
end;
|
end;
|
||||||
@ -1741,6 +1765,14 @@ begin
|
|||||||
|
|
||||||
if assigned(ABreakPoint) then
|
if assigned(ABreakPoint) then
|
||||||
ABreakPoint.Hit(&continue);
|
ABreakPoint.Hit(&continue);
|
||||||
|
|
||||||
|
if (not &continue) and (ABreakPoint.Kind = bpkData) and (OnFeedback <> nil) then begin
|
||||||
|
// For message use location(Address - 1)
|
||||||
|
OnFeedback(self,
|
||||||
|
Format('The Watchpoint for "%1:s" was triggered.%0:s%0:s', // 'Old value: %2:s%0:sNew value: %3:s',
|
||||||
|
[LineEnding, ABreakPoint.WatchData{, AOldVal, ANewVal}]),
|
||||||
|
'', ftInformation, [frOk]);
|
||||||
|
end;
|
||||||
end;
|
end;
|
||||||
end
|
end
|
||||||
else if FQuickPause then
|
else if FQuickPause then
|
||||||
@ -1754,8 +1786,10 @@ begin
|
|||||||
ALocationAddr := GetLocation;
|
ALocationAddr := GetLocation;
|
||||||
|
|
||||||
// if &continue then SetState(dsInternalPause) else
|
// if &continue then SetState(dsInternalPause) else
|
||||||
|
if State <> dsPause then begin
|
||||||
SetState(dsPause);
|
SetState(dsPause);
|
||||||
DoCurrent(ALocationAddr);
|
DoCurrent(ALocationAddr);
|
||||||
|
end;
|
||||||
|
|
||||||
if &continue then begin
|
if &continue then begin
|
||||||
// wait for any watches for Snapshots
|
// wait for any watches for Snapshots
|
||||||
@ -2056,6 +2090,11 @@ begin
|
|||||||
FCacheBreakpoint := FDbgController.CurrentProcess.AddBreak(FCacheLocation);
|
FCacheBreakpoint := FDbgController.CurrentProcess.AddBreak(FCacheLocation);
|
||||||
end;
|
end;
|
||||||
|
|
||||||
|
procedure TFpDebugDebugger.DoAddBWatch;
|
||||||
|
begin
|
||||||
|
FCacheBreakpoint := FDbgController.CurrentProcess.AddWatch(FCacheLocation, FCacheLine, FCacheReadWrite, FCacheScope);
|
||||||
|
end;
|
||||||
|
|
||||||
procedure TFpDebugDebugger.DoReadData;
|
procedure TFpDebugDebugger.DoReadData;
|
||||||
begin
|
begin
|
||||||
FCacheBoolean:=FDbgController.CurrentProcess.ReadData(FCacheLocation, FCacheLine, FCachePointer^);
|
FCacheBoolean:=FDbgController.CurrentProcess.ReadData(FCacheLocation, FCacheLine, FCachePointer^);
|
||||||
@ -2103,6 +2142,22 @@ begin
|
|||||||
{$endif linux}
|
{$endif linux}
|
||||||
end;
|
end;
|
||||||
|
|
||||||
|
function TFpDebugDebugger.AddWatch(const ALocation: TDBGPtr; ASize: Cardinal;
|
||||||
|
AReadWrite: TDBGWatchPointKind; AScope: TDBGWatchPointScope
|
||||||
|
): TFpDbgBreakpoint;
|
||||||
|
begin
|
||||||
|
{$ifdef linux}
|
||||||
|
FCacheLocation:=ALocation;
|
||||||
|
FCacheLine:=ASize;
|
||||||
|
FCacheReadWrite:=AReadWrite;
|
||||||
|
FCacheScope:=AScope;
|
||||||
|
ExecuteInDebugThread(@DoAddBWatch);
|
||||||
|
result := FCacheBreakpoint;
|
||||||
|
{$else linux}
|
||||||
|
result := FDbgController.CurrentProcess.AddWatch(ALocation, ASize, AReadWrite, AScope);
|
||||||
|
{$endif linux}
|
||||||
|
end;
|
||||||
|
|
||||||
procedure TFpDebugDebugger.FreeBreakpoint(
|
procedure TFpDebugDebugger.FreeBreakpoint(
|
||||||
const ABreakpoint: TFpDbgBreakpoint);
|
const ABreakpoint: TFpDbgBreakpoint);
|
||||||
begin
|
begin
|
||||||
|
Loading…
Reference in New Issue
Block a user