FpDebug: split TBreakLocationMap. Make TFpBreakPointTargetHandler a separate class.

This commit is contained in:
Martin 2024-02-15 20:33:34 +01:00
parent f6ccc8d26d
commit c6d52ae4b7

View File

@ -33,6 +33,7 @@
} }
unit FpDbgClasses; unit FpDbgClasses;
{$mode objfpc}{$H+} {$mode objfpc}{$H+}
{$ModeSwitch typehelpers }
{$TYPEDADDRESS on} {$TYPEDADDRESS on}
{$IFDEF INLINE_OFF}{$INLINE OFF}{$ENDIF} {$IFDEF INLINE_OFF}{$INLINE OFF}{$ENDIF}
{$IF FPC_Fullversion=30202}{$Optimization NOPEEPHOLE}{$ENDIF} {$IF FPC_Fullversion=30202}{$Optimization NOPEEPHOLE}{$ENDIF}
@ -411,65 +412,87 @@ type
end; end;
TFpInternalBreakpointArray = array of TFpInternalBreakpoint; TFpInternalBreakpointArray = array of TFpInternalBreakpoint;
TFpBreakPointTargetHandler = class;
TFpBreakPointTargetHandlerData = record end;
PFpBreakPointTargetHandlerDataPointer = ^TFpBreakPointTargetHandlerData;
{ TFpBreakPointMap } { TFpBreakPointMap }
TFpBreakPointMap = class abstract(TMap) TFpBreakPointMap = class(TMap)
{strict} protected type strict protected type
{ TFpBreakPointMapEntry } { TFpBreakPointMapEntry }
TFpBreakPointMapEntry = packed record TFpBreakPointMapEntry = record
InternalBreakPoint: Pointer; // TFpInternalBreakpoint or TFpInternalBreakpointArray InternalBreakPoint: Pointer; // TFpInternalBreakpoint or TFpInternalBreakpointArray
IsBreakList: ByteBool; IsBreakList: ByteBool;
TargetHandlerData: TFpBreakPointTargetHandlerData; // must be last
end; end;
PFpBreakPointMapEntry = ^TFpBreakPointMapEntry; PFpBreakPointMapEntry = ^TFpBreakPointMapEntry;
{strict} protected type public type
{ TFpBreakPointMapLocDataPair } { TFpBreakPointMapEnumerationData }
TFpBreakPointMapLocDataPair = record TFpBreakPointMapEnumerationData = record
Location: TDBGPtr; Location: TDBGPtr;
Data: PFpBreakPointMapEntry; MapDataPtr: PFpBreakPointMapEntry;
TargetHandlerDataPtr: PFpBreakPointTargetHandlerDataPointer;
end; end;
strict protected type { TFpBreakPointMapEnumerator }
{ TFpBreakPointMapEnumeratorEnumerator }
TFpBreakPointMapEnumerator = class(TMapIterator) TFpBreakPointMapEnumerator = class(TMapIterator)
private private
FDoneFirst: Boolean; FDoneFirst: Boolean;
function GetCurrent: TFpBreakPointMapLocDataPair; function GetCurrent: TFpBreakPointMapEnumerationData;
public public
function MoveNext: Boolean; function MoveNext: Boolean;
property Current: TFpBreakPointMapLocDataPair read GetCurrent; property Current: TFpBreakPointMapEnumerationData read GetCurrent;
end; end;
strict private strict private
FProcess: TDbgProcess; FProcess: TDbgProcess;
FTargetHandler: TFpBreakPointTargetHandler;
private FDataSize: integer;
class var DBG__VERBOSE, DBG__WARNINGS, DBG__BREAKPOINTS: PLazLoggerLogGroup; FTmpDataPtr: PFpBreakPointMapEntry;
strict protected strict protected
procedure NewMapEntry(out ALocData: PFpBreakPointMapEntry); virtual; abstract;
procedure DisposeMapEntry(ALocData: PFpBreakPointMapEntry); virtual; abstract;
procedure DoAddedNewLocation(const ALocation: TDBGPtr; const AInternalBreak: TFpInternalBreakpoint; AnEntry: PFpBreakPointMapEntry); virtual; abstract;
procedure DoRemovingLocation(const ALocation: TDBGPtr; const AInternalBreak: TFpInternalBreakpoint; AnEntry: PFpBreakPointMapEntry); virtual; abstract;
property Process: TDbgProcess read FProcess; property Process: TDbgProcess read FProcess;
property TargetHandler: TFpBreakPointTargetHandler read FTargetHandler;
public public
constructor Create(AProcess: TDbgProcess; ADataSize: Cardinal); constructor Create(AProcess: TDbgProcess; ATargetHandler: TFpBreakPointTargetHandler);
destructor Destroy; override; destructor Destroy; override;
procedure Clear; reintroduce; procedure Clear; reintroduce;
procedure AddLocation (const ALocation: TDBGPtr; const AInternalBreak: TFpInternalBreakpoint; AnIgnoreIfExists: Boolean = True); procedure AddLocation (const ALocation: TDBGPtr; const AInternalBreak: TFpInternalBreakpoint; AnIgnoreIfExists: Boolean = True);
procedure RemoveLocation(const ALocation: TDBGPtr; const AInternalBreak: TFpInternalBreakpoint); procedure RemoveLocation(const ALocation: TDBGPtr; const AInternalBreak: TFpInternalBreakpoint);
function HasInsertedBreakInstructionAtLocation(const ALocation: TDBGPtr): Boolean;
function GetInternalBreaksAtLocation(const ALocation: TDBGPtr): TFpInternalBreakpointArray; function GetInternalBreaksAtLocation(const ALocation: TDBGPtr): TFpInternalBreakpointArray;
function GetDataPtr(const AId): PFpBreakPointMapEntry; reintroduce; inline;
function GetTargetDataPtr(const AId): PFpBreakPointTargetHandlerDataPointer;
function GetEnumerator: TFpBreakPointMapEnumerator; function GetEnumerator: TFpBreakPointMapEnumerator;
end;
{ TFpBreakPointTargetHandler }
TFpBreakPointTargetHandler = class abstract
private
class var DBG__VERBOSE, DBG__WARNINGS, DBG__BREAKPOINTS: PLazLoggerLogGroup;
strict private
FProcess: TDbgProcess;
FBreakMap: TFpBreakPointMap;
protected
property Process: TDbgProcess read FProcess;
property BreakMap: TFpBreakPointMap read FBreakMap write FBreakMap;
public
constructor Create(AProcess: TDbgProcess);
function GetDataSize: integer; virtual; abstract;
procedure InsertBreakInstructionCode(const ALocation: TDBGPtr; const AInternalBreak: TFpInternalBreakpoint; AnEntry: PFpBreakPointTargetHandlerDataPointer); virtual; abstract;
procedure RemoveBreakInstructionCode(const ALocation: TDBGPtr; const AInternalBreak: TFpInternalBreakpoint; AnEntry: PFpBreakPointTargetHandlerDataPointer); virtual; abstract;
// When the debugger modifies the debuggee's code, it might be that the // When the debugger modifies the debuggee's code, it might be that the
// original value underneeth the breakpoint has to be changed. This function // original value underneeth the breakpoint has to be changed. This function
// makes this possible. // makes this possible.
procedure UpdateMapForNewTargetCode(const AAdress: TDbgPtr; const ASize: Cardinal; const AData); virtual; abstract; procedure UpdateMapForNewTargetCode(const AAdress: TDbgPtr; const ASize: Cardinal; const AData); virtual; abstract;
function HasInsertedBreakInstructionAtLocation(const ALocation: TDBGPtr): Boolean; virtual; abstract;
function IsHardcodeBreakPoint(const ALocation: TDBGPtr): Boolean; virtual; abstract; function IsHardcodeBreakPoint(const ALocation: TDBGPtr): Boolean; virtual; abstract;
procedure TempRemoveBreakInstructionCode(const ALocation: TDBGPtr); virtual; abstract; procedure TempRemoveBreakInstructionCode(const ALocation: TDBGPtr); virtual; abstract;
@ -477,13 +500,12 @@ type
procedure MaskBreakpointsInReadData(const AAdress: TDbgPtr; const ASize: Cardinal; var AData); virtual; abstract; procedure MaskBreakpointsInReadData(const AAdress: TDbgPtr; const ASize: Cardinal; var AData); virtual; abstract;
end; end;
{ TGenericBreakLocationMap } { TGenericBreakPointTargetHandler }
generic TGenericBreakLocationMap<_BRK_STORE, _BREAK> = class(TFpBreakPointMap) generic TGenericBreakPointTargetHandler<_BRK_STORE, _BREAK> = class(TFpBreakPointTargetHandler)
strict protected type strict protected type
{ TInternalBreakLocationEntry } { TInternalBreakLocationEntry }
TInternalBreakLocationEntry = packed record TInternalBreakLocationEntry = packed record
BaseMapEntry: TFpBreakPointMapEntry;
OrigValue: _BRK_STORE; OrigValue: _BRK_STORE;
ErrorSetting: ByteBool; ErrorSetting: ByteBool;
end; end;
@ -492,26 +514,22 @@ type
private private
FTmpRemovedBreaks: array of TDBGPtr; FTmpRemovedBreaks: array of TDBGPtr;
class function OrigByteFromPointer(AData: Pointer): _BRK_STORE;{$IF FPC_Fullversion=30301}static;{$ENDIF} // Work around for https://gitlab.com/freepascal.org/fpc/source/-/issues/40641 strict protected
class function ErrorSettingFromPointer(AData: Pointer): ByteBool;{$IF FPC_Fullversion=30301}static;{$ENDIF} function HPtr(Src: PFpBreakPointTargetHandlerDataPointer): PInternalBreakLocationEntry; inline;
strict private
function GetOrigValueAtLocation(const ALocation: TDBGPtr): _BRK_STORE; // returns Int3, if there is no break at this location function GetOrigValueAtLocation(const ALocation: TDBGPtr): _BRK_STORE; // returns Int3, if there is no break at this location
procedure AdaptOriginalValueAtLocation(const ALocation: TDBGPtr; const NewOrigValue: _BRK_STORE); procedure AdaptOriginalValueAtLocation(const ALocation: TDBGPtr; const NewOrigValue: _BRK_STORE);
strict protected
procedure NewMapEntry(out ALocData: PFpBreakPointMapEntry); override;
procedure DisposeMapEntry(ALocData: PFpBreakPointMapEntry); override;
procedure DoAddedNewLocation(const ALocation: TDBGPtr; const AInternalBreak: TFpInternalBreakpoint; AnEntry: PFpBreakPointMapEntry); override;
procedure DoRemovingLocation(const ALocation: TDBGPtr; const AInternalBreak: TFpInternalBreakpoint; AnEntry: PFpBreakPointMapEntry); override;
public public
constructor Create(AProcess: TDbgProcess); function GetDataSize: integer; override;
procedure InsertBreakInstructionCode(const ALocation: TDBGPtr; const AInternalBreak: TFpInternalBreakpoint; AnEntry: PFpBreakPointTargetHandlerDataPointer); override;
procedure RemoveBreakInstructionCode(const ALocation: TDBGPtr; const AInternalBreak: TFpInternalBreakpoint; AnEntry: PFpBreakPointTargetHandlerDataPointer); override;
// When the debugger modifies the debuggee's code, it might be that the // When the debugger modifies the debuggee's code, it might be that the
// original value underneeth the breakpoint has to be changed. This function // original value underneeth the breakpoint has to be changed. This function
// makes this possible. // makes this possible.
procedure UpdateMapForNewTargetCode(const AAdress: TDbgPtr; const ASize: Cardinal; const AData); override; procedure UpdateMapForNewTargetCode(const AAdress: TDbgPtr; const ASize: Cardinal; const AData); override;
function HasInsertedBreakInstructionAtLocation(const ALocation: TDBGPtr): Boolean; override;
function IsHardcodeBreakPoint(const ALocation: TDBGPtr): Boolean; override; function IsHardcodeBreakPoint(const ALocation: TDBGPtr): Boolean; override;
procedure TempRemoveBreakInstructionCode(const ALocation: TDBGPtr); override; procedure TempRemoveBreakInstructionCode(const ALocation: TDBGPtr); override;
@ -524,7 +542,7 @@ type
_CODE: Byte = $CC; _CODE: Byte = $CC;
end; end;
TBreakLocationMap = specialize TGenericBreakLocationMap<Byte, TBreakInfoX86>; TBreakPointTargetHandler = specialize TGenericBreakPointTargetHandler<Byte, TBreakInfoX86>;
{ TFpDbgBreakpoint } { TFpDbgBreakpoint }
@ -840,7 +858,8 @@ type
FThreadMap: TThreadMap; // map ThreadID -> ThreadObject FThreadMap: TThreadMap; // map ThreadID -> ThreadObject
FLibMap: TLibraryMap; // map LibAddr -> LibObject FLibMap: TLibraryMap; // map LibAddr -> LibObject
FBreakMap: TBreakLocationMap; // map BreakAddr -> BreakObject FBreakMap: TFpBreakPointMap; // map BreakAddr -> BreakObject
FBreakTargetHandler: TFpBreakPointTargetHandler;
FPauseRequested: longint; FPauseRequested: longint;
FMainThread: TDbgThread; FMainThread: TDbgThread;
@ -1302,9 +1321,10 @@ end;
{ TFpBreakPointMap.TFpBreakPointMapEnumerator } { TFpBreakPointMap.TFpBreakPointMapEnumerator }
function TFpBreakPointMap.TFpBreakPointMapEnumerator.GetCurrent: TFpBreakPointMapLocDataPair; function TFpBreakPointMap.TFpBreakPointMapEnumerator.GetCurrent: TFpBreakPointMapEnumerationData;
begin begin
Result.Data := DataPtr; Result.MapDataPtr := DataPtr;
Result.TargetHandlerDataPtr := @Result.MapDataPtr^.TargetHandlerData;
GetID(Result.Location); GetID(Result.Location);
end; end;
@ -1320,26 +1340,32 @@ end;
{ TFpBreakPointMap } { TFpBreakPointMap }
constructor TFpBreakPointMap.Create(AProcess: TDbgProcess; ADataSize: Cardinal); constructor TFpBreakPointMap.Create(AProcess: TDbgProcess;
ATargetHandler: TFpBreakPointTargetHandler);
begin begin
FProcess := AProcess; FProcess := AProcess;
inherited Create(itu8, ADataSize); FTargetHandler := ATargetHandler;
ATargetHandler.BreakMap := Self;
FDataSize := SizeOf(TFpBreakPointMapEntry) + ATargetHandler.GetDataSize;
FTmpDataPtr := AllocMem(FDataSize);
inherited Create(itu8, FDataSize);
end; end;
destructor TFpBreakPointMap.Destroy; destructor TFpBreakPointMap.Destroy;
begin begin
Clear; Clear;
Freemem(FTmpDataPtr);
inherited Destroy; inherited Destroy;
end; end;
procedure TFpBreakPointMap.Clear; procedure TFpBreakPointMap.Clear;
var var
LocDataPair: TFpBreakPointMapLocDataPair; MapEnumData: TFpBreakPointMap.TFpBreakPointMapEnumerationData;
begin begin
debugln(DBG_VERBOSE or DBG_BREAKPOINTS, ['TGenericBreakLocationMap.Clear ']); debugln(DBG_VERBOSE or DBG_BREAKPOINTS, ['TGenericBreakPointTargetHandler.Clear ']);
for LocDataPair in Self do begin for MapEnumData in Self do begin
if LocDataPair.Data^.IsBreakList then if MapEnumData.MapDataPtr^.IsBreakList then
TFpInternalBreakpointArray(LocDataPair.Data^.InternalBreakPoint) := nil; TFpInternalBreakpointArray(MapEnumData.MapDataPtr^.InternalBreakPoint) := nil;
end; end;
inherited Clear; inherited Clear;
end; end;
@ -1351,7 +1377,7 @@ var
Len, i: Integer; Len, i: Integer;
BList: TFpInternalBreakpointArray; BList: TFpInternalBreakpointArray;
begin begin
{$IFDEF FPDEBUG_THREAD_CHECK}AssertFpDebugThreadIdNotMain('TGenericBreakLocationMap.AddLocation');{$ENDIF} {$IFDEF FPDEBUG_THREAD_CHECK}AssertFpDebugThreadIdNotMain('TGenericBreakPointTargetHandler.AddLocation');{$ENDIF}
MapEntryPtr := GetDataPtr(ALocation); MapEntryPtr := GetDataPtr(ALocation);
if MapEntryPtr <> nil then begin if MapEntryPtr <> nil then begin
@ -1384,15 +1410,14 @@ begin
end; end;
NewMapEntry(MapEntryPtr); FillByte(FTmpDataPtr^, FDataSize, 0);
MapEntryPtr^.IsBreakList := False; FTmpDataPtr^.IsBreakList := False;
MapEntryPtr^.InternalBreakPoint := AInternalBreak; FTmpDataPtr^.InternalBreakPoint := AInternalBreak;
FProcess.DoBeforeBreakLocationMapChange; // Only if a new breakpoint is set => memory changed FProcess.DoBeforeBreakLocationMapChange; // Only if a new breakpoint is set => memory changed
DoAddedNewLocation(ALocation, AInternalBreak, MapEntryPtr); TargetHandler.InsertBreakInstructionCode(ALocation, AInternalBreak, @FTmpDataPtr^.TargetHandlerData);
Add(ALocation, MapEntryPtr^); Add(ALocation, FTmpDataPtr^);
DisposeMapEntry(MapEntryPtr);
end; end;
procedure TFpBreakPointMap.RemoveLocation(const ALocation: TDBGPtr; procedure TFpBreakPointMap.RemoveLocation(const ALocation: TDBGPtr;
@ -1401,7 +1426,7 @@ var
MapEntryPtr: PFpBreakPointMapEntry; MapEntryPtr: PFpBreakPointMapEntry;
Len, i: Integer; Len, i: Integer;
begin begin
{$IFDEF FPDEBUG_THREAD_CHECK}AssertFpDebugThreadIdNotMain('TGenericBreakLocationMap.RemoveLocation');{$ENDIF} {$IFDEF FPDEBUG_THREAD_CHECK}AssertFpDebugThreadIdNotMain('TGenericBreakPointTargetHandler.RemoveLocation');{$ENDIF}
MapEntryPtr := GetDataPtr(ALocation); MapEntryPtr := GetDataPtr(ALocation);
if MapEntryPtr = nil then begin if MapEntryPtr = nil then begin
DebugLn(DBG_WARNINGS or DBG_BREAKPOINTS, ['Missing breakpoint for loc ', FormatAddress(ALocation)]); DebugLn(DBG_WARNINGS or DBG_BREAKPOINTS, ['Missing breakpoint for loc ', FormatAddress(ALocation)]);
@ -1434,10 +1459,16 @@ begin
end; end;
FProcess.DoBeforeBreakLocationMapChange; // Only if a breakpoint is removed => memory changed FProcess.DoBeforeBreakLocationMapChange; // Only if a breakpoint is removed => memory changed
DoRemovingLocation(ALocation, AInternalBreak, MapEntryPtr); TargetHandler.RemoveBreakInstructionCode(ALocation, AInternalBreak, @MapEntryPtr^.TargetHandlerData);
Delete(ALocation); Delete(ALocation);
end; end;
function TFpBreakPointMap.HasInsertedBreakInstructionAtLocation(
const ALocation: TDBGPtr): Boolean;
begin
Result := GetDataPtr(ALocation) <> nil;
end;
function TFpBreakPointMap.GetInternalBreaksAtLocation(const ALocation: TDBGPtr): TFpInternalBreakpointArray; function TFpBreakPointMap.GetInternalBreaksAtLocation(const ALocation: TDBGPtr): TFpInternalBreakpointArray;
var var
MapEntryPtr: PFpBreakPointMapEntry; MapEntryPtr: PFpBreakPointMapEntry;
@ -1458,46 +1489,59 @@ begin
end; end;
end; end;
function TFpBreakPointMap.GetDataPtr(const AId): PFpBreakPointMapEntry;
begin
Result := inherited GetDataPtr(AId);
end;
function TFpBreakPointMap.GetTargetDataPtr(const AId): PFpBreakPointTargetHandlerDataPointer;
var
r: PFpBreakPointMapEntry;
begin
r := GetDataPtr(AId);
if r = nil then
Result := nil
else
Result := @GetDataPtr(AId)^.TargetHandlerData;
end;
function TFpBreakPointMap.GetEnumerator: TFpBreakPointMapEnumerator; function TFpBreakPointMap.GetEnumerator: TFpBreakPointMapEnumerator;
begin begin
{$IFDEF FPDEBUG_THREAD_CHECK}AssertFpDebugThreadId('TGenericBreakLocationMap.GetEnumerator');{$ENDIF} {$IFDEF FPDEBUG_THREAD_CHECK}AssertFpDebugThreadId('TGenericBreakPointTargetHandler.GetEnumerator');{$ENDIF}
Result := TFpBreakPointMapEnumerator.Create(Self); Result := TFpBreakPointMapEnumerator.Create(Self);
end; end;
{ TGenericBreakLocationMap } { TFpBreakPointTargetHandler }
class function TGenericBreakLocationMap.OrigByteFromPointer(AData: Pointer): _BRK_STORE; constructor TFpBreakPointTargetHandler.Create(AProcess: TDbgProcess);
begin begin
Result := PInternalBreakLocationEntry(AData)^.OrigValue; FProcess := AProcess;
inherited Create;
end; end;
class function TGenericBreakLocationMap.ErrorSettingFromPointer(AData: Pointer { TGenericBreakPointTargetHandler }
): ByteBool;
function TGenericBreakPointTargetHandler.GetDataSize: integer;
begin begin
Result := PInternalBreakLocationEntry(AData)^.ErrorSetting; Result := SizeOf(TInternalBreakLocationEntry);
end; end;
constructor TGenericBreakLocationMap.Create(AProcess: TDbgProcess); procedure TGenericBreakPointTargetHandler.UpdateMapForNewTargetCode(const AAdress: TDbgPtr;
begin
inherited Create(AProcess, SizeOf(TInternalBreakLocationEntry));
end;
procedure TGenericBreakLocationMap.UpdateMapForNewTargetCode(const AAdress: TDbgPtr;
const ASize: Cardinal; const AData); const ASize: Cardinal; const AData);
var var
i: Integer; i: Integer;
begin begin
for i := 0 to ASize -1 do for i := 0 to ASize -1 do
if HasInsertedBreakInstructionAtLocation(AAdress+i) then if BreakMap.HasInsertedBreakInstructionAtLocation(AAdress+i) then
AdaptOriginalValueAtLocation(AAdress+i, PByte(@AData+i)^); AdaptOriginalValueAtLocation(AAdress+i, PByte(@AData+i)^);
end; end;
function TGenericBreakLocationMap.GetOrigValueAtLocation(const ALocation: TDBGPtr function TGenericBreakPointTargetHandler.GetOrigValueAtLocation(const ALocation: TDBGPtr
): _BRK_STORE; ): _BRK_STORE;
var var
LocData: PInternalBreakLocationEntry; LocData: PInternalBreakLocationEntry;
begin begin
LocData := GetDataPtr(ALocation); LocData := HPtr(BreakMap.GetTargetDataPtr(ALocation));
if LocData = nil then begin if LocData = nil then begin
DebugLn(DBG__WARNINGS or DBG__BREAKPOINTS, ['Missing breakpoint for loc ', FormatAddress(ALocation)]); DebugLn(DBG__WARNINGS or DBG__BREAKPOINTS, ['Missing breakpoint for loc ', FormatAddress(ALocation)]);
Result := _BREAK._CODE; Result := _BREAK._CODE;
@ -1506,19 +1550,13 @@ begin
Result := LocData^.OrigValue; Result := LocData^.OrigValue;
end; end;
function TGenericBreakLocationMap.HasInsertedBreakInstructionAtLocation( function TGenericBreakPointTargetHandler.IsHardcodeBreakPoint(const ALocation: TDBGPtr
const ALocation: TDBGPtr): Boolean;
begin
Result := GetDataPtr(ALocation) <> nil;
end;
function TGenericBreakLocationMap.IsHardcodeBreakPoint(const ALocation: TDBGPtr
): Boolean; ): Boolean;
begin begin
Result := GetOrigValueAtLocation(ALocation) = _BREAK._CODE; Result := GetOrigValueAtLocation(ALocation) = _BREAK._CODE;
end; end;
procedure TGenericBreakLocationMap.TempRemoveBreakInstructionCode( procedure TGenericBreakPointTargetHandler.TempRemoveBreakInstructionCode(
const ALocation: TDBGPtr); const ALocation: TDBGPtr);
var var
OVal: _BRK_STORE; OVal: _BRK_STORE;
@ -1540,7 +1578,7 @@ begin
DebugLn(DBG__VERBOSE or DBG__BREAKPOINTS, ['<<< TempRemoveBreakInstructionCode']); DebugLn(DBG__VERBOSE or DBG__BREAKPOINTS, ['<<< TempRemoveBreakInstructionCode']);
end; end;
procedure TGenericBreakLocationMap.RestoreTempBreakInstructionCodes; procedure TGenericBreakPointTargetHandler.RestoreTempBreakInstructionCodes;
var var
OVal: _BRK_STORE; OVal: _BRK_STORE;
t: array of TDBGPtr; t: array of TDBGPtr;
@ -1552,45 +1590,40 @@ begin
t := FTmpRemovedBreaks; t := FTmpRemovedBreaks;
FTmpRemovedBreaks := nil; FTmpRemovedBreaks := nil;
for i := 0 to length(t) - 1 do for i := 0 to length(t) - 1 do
if HasId(t[i]) then // may have been removed if BreakMap.HasId(t[i]) then // may have been removed
Process.InsertBreakInstructionCode(t[i], OVal, False); Process.InsertBreakInstructionCode(t[i], OVal, False);
DebugLnExit(DBG__VERBOSE or DBG__BREAKPOINTS, ['<<< RestoreTempBreakInstructionCodes']); DebugLnExit(DBG__VERBOSE or DBG__BREAKPOINTS, ['<<< RestoreTempBreakInstructionCodes']);
end; end;
procedure TGenericBreakLocationMap.MaskBreakpointsInReadData(const AAdress: TDbgPtr; procedure TGenericBreakPointTargetHandler.MaskBreakpointsInReadData(const AAdress: TDbgPtr;
const ASize: Cardinal; var AData); const ASize: Cardinal; var AData);
var var
Brk: TFpBreakPointMapLocDataPair; MapEnumData: TFpBreakPointMap.TFpBreakPointMapEnumerationData;
begin begin
for Brk in Self do begin for MapEnumData in BreakMap do begin
if not ErrorSettingFromPointer(Brk.Data) and (Brk.Location >= AAdress) and (Brk.Location < (AAdress+ASize)) then if not HPtr(MapEnumData.TargetHandlerDataPtr)^.ErrorSetting and (MapEnumData.Location >= AAdress) and (MapEnumData.Location < (AAdress+ASize)) then
PByte(@AData)[Brk.Location-AAdress] := OrigByteFromPointer(Brk.Data); PByte(@AData)[MapEnumData.Location-AAdress] := HPtr(MapEnumData.TargetHandlerDataPtr)^.OrigValue;
end; end;
end; end;
procedure TGenericBreakLocationMap.AdaptOriginalValueAtLocation(const ALocation: TDBGPtr; const NewOrigValue: _BRK_STORE); procedure TGenericBreakPointTargetHandler.AdaptOriginalValueAtLocation(const ALocation: TDBGPtr; const NewOrigValue: _BRK_STORE);
var var
LocData: PInternalBreakLocationEntry; LocData: PInternalBreakLocationEntry;
begin begin
LocData := GetDataPtr(ALocation); LocData := HPtr(BreakMap.GetTargetDataPtr(ALocation));
if Assigned(LocData) then if Assigned(LocData) then
LocData^.OrigValue := NewOrigValue; LocData^.OrigValue := NewOrigValue;
end; end;
procedure TGenericBreakLocationMap.NewMapEntry(out ALocData: PFpBreakPointMapEntry); function TGenericBreakPointTargetHandler.HPtr(Src: PFpBreakPointTargetHandlerDataPointer): PInternalBreakLocationEntry;
begin begin
New(PInternalBreakLocationEntry(ALocData)); Result := PInternalBreakLocationEntry(Src);
end; end;
procedure TGenericBreakLocationMap.DisposeMapEntry(ALocData: PFpBreakPointMapEntry); procedure TGenericBreakPointTargetHandler.InsertBreakInstructionCode(const ALocation: TDBGPtr;
begin const AInternalBreak: TFpInternalBreakpoint; AnEntry: PFpBreakPointTargetHandlerDataPointer);
Dispose(PInternalBreakLocationEntry(ALocData));
end;
procedure TGenericBreakLocationMap.DoAddedNewLocation(const ALocation: TDBGPtr;
const AInternalBreak: TFpInternalBreakpoint; AnEntry: PFpBreakPointMapEntry);
var var
MapEntryPtr: PInternalBreakLocationEntry absolute AnEntry; LocData: PInternalBreakLocationEntry absolute AnEntry;
IsTempRemoved: Boolean; IsTempRemoved: Boolean;
i: Integer; i: Integer;
begin begin
@ -1601,16 +1634,16 @@ begin
break; break;
end; end;
MapEntryPtr^.ErrorSetting := not Process.InsertBreakInstructionCode(ALocation, MapEntryPtr^.OrigValue, IsTempRemoved); LocData^.ErrorSetting := not Process.InsertBreakInstructionCode(ALocation, LocData^.OrigValue, IsTempRemoved);
end; end;
procedure TGenericBreakLocationMap.DoRemovingLocation(const ALocation: TDBGPtr; procedure TGenericBreakPointTargetHandler.RemoveBreakInstructionCode(const ALocation: TDBGPtr;
const AInternalBreak: TFpInternalBreakpoint; AnEntry: PFpBreakPointMapEntry); const AInternalBreak: TFpInternalBreakpoint; AnEntry: PFpBreakPointTargetHandlerDataPointer);
var var
MapEntryPtr: PInternalBreakLocationEntry absolute AnEntry; LocData: PInternalBreakLocationEntry absolute AnEntry;
begin begin
if not MapEntryPtr^.ErrorSetting then if not LocData^.ErrorSetting then
Process.RemoveBreakInstructionCode(ALocation, MapEntryPtr^.OrigValue); Process.RemoveBreakInstructionCode(ALocation, LocData^.OrigValue);
end; end;
{ TDbgCallstackEntry } { TDbgCallstackEntry }
@ -2329,7 +2362,9 @@ begin
FThreadMap := TThreadMap.Create(itu4, SizeOf(TDbgThread)); FThreadMap := TThreadMap.Create(itu4, SizeOf(TDbgThread));
FLibMap := TLibraryMap.Create(MAP_ID_SIZE, SizeOf(TDbgLibrary)); FLibMap := TLibraryMap.Create(MAP_ID_SIZE, SizeOf(TDbgLibrary));
FWatchPointData := CreateWatchPointData; FWatchPointData := CreateWatchPointData;
FBreakMap := TBreakLocationMap.Create(Self); FBreakTargetHandler := TBreakPointTargetHandler.Create(Self);
FBreakMap := TFpBreakPointMap.Create(Self, FBreakTargetHandler);
FBreakTargetHandler.BreakMap := FBreakMap;
FCurrentBreakpoint := nil; FCurrentBreakpoint := nil;
FCurrentWatchpoint := nil; FCurrentWatchpoint := nil;
@ -2386,7 +2421,9 @@ begin
FLibMap.ClearAddedAndRemovedLibraries; FLibMap.ClearAddedAndRemovedLibraries;
FreeAndNil(FWatchPointData); FreeAndNil(FWatchPointData);
FBreakTargetHandler.BreakMap := nil;
FreeAndNil(FBreakMap); FreeAndNil(FBreakMap);
FreeAndNil(FBreakTargetHandler);
FreeAndNil(FThreadMap); FreeAndNil(FThreadMap);
FreeAndNil(FLibMap); FreeAndNil(FLibMap);
FreeAndNil(FSymInstances); FreeAndNil(FSymInstances);
@ -3077,12 +3114,12 @@ end;
procedure TDbgProcess.TempRemoveBreakInstructionCode(const ALocation: TDBGPtr); procedure TDbgProcess.TempRemoveBreakInstructionCode(const ALocation: TDBGPtr);
begin begin
FBreakMap.TempRemoveBreakInstructionCode(ALocation); FBreakTargetHandler.TempRemoveBreakInstructionCode(ALocation);
end; end;
procedure TDbgProcess.RestoreTempBreakInstructionCodes; procedure TDbgProcess.RestoreTempBreakInstructionCodes;
begin begin
FBreakMap.RestoreTempBreakInstructionCodes; FBreakTargetHandler.RestoreTempBreakInstructionCodes;
end; end;
function TDbgProcess.HasInsertedBreakInstructionAtLocation( function TDbgProcess.HasInsertedBreakInstructionAtLocation(
@ -3099,8 +3136,8 @@ end;
procedure TDbgProcess.MaskBreakpointsInReadData(const AAdress: TDbgPtr; const ASize: Cardinal; var AData); procedure TDbgProcess.MaskBreakpointsInReadData(const AAdress: TDbgPtr; const ASize: Cardinal; var AData);
begin begin
if FBreakMap <> nil then if FBreakTargetHandler <> nil then
FBreakMap.MaskBreakpointsInReadData(AAdress, ASize, AData); FBreakTargetHandler.MaskBreakpointsInReadData(AAdress, ASize, AData);
end; end;
function TDbgProcess.CreateWatchPointData: TFpWatchPointData; function TDbgProcess.CreateWatchPointData: TFpWatchPointData;
@ -3132,7 +3169,7 @@ end;
function TDbgProcess.WriteInstructionCode(const AAdress: TDbgPtr; const ASize: Cardinal; const AData): Boolean; function TDbgProcess.WriteInstructionCode(const AAdress: TDbgPtr; const ASize: Cardinal; const AData): Boolean;
begin begin
FBreakMap.UpdateMapForNewTargetCode(AAdress, ASize, AData); FBreakTargetHandler.UpdateMapForNewTargetCode(AAdress, ASize, AData);
BeforeChangingInstructionCode(AAdress, ASize); BeforeChangingInstructionCode(AAdress, ASize);
Result := WriteData(AAdress, ASize, AData); Result := WriteData(AAdress, ASize, AData);
AfterChangingInstructionCode(AAdress, ASize); AfterChangingInstructionCode(AAdress, ASize);
@ -3929,7 +3966,7 @@ begin
Result := False; Result := False;
assert(FProcess<>nil, 'TFpInternalBreakpoint.Hit: FProcess<>nil'); assert(FProcess<>nil, 'TFpInternalBreakpoint.Hit: FProcess<>nil');
if //FProcess.FBreakMap.HasId(ABreakpointAddress) and if //FProcess.FBreakMap.HasId(ABreakpointAddress) and
(FProcess.FBreakMap.IsHardcodeBreakPoint(ABreakpointAddress)) (FProcess.FBreakTargetHandler.IsHardcodeBreakPoint(ABreakpointAddress))
then then
exit; // breakpoint on a hardcoded breakpoint exit; // breakpoint on a hardcoded breakpoint
// no need to jump back and restore instruction // no need to jump back and restore instruction
@ -4259,9 +4296,9 @@ initialization
DBG_BREAKPOINTS := DebugLogger.FindOrRegisterLogGroup('DBG_BREAKPOINTS' {$IFDEF DBG_BREAKPOINTS} , True {$ENDIF} ); DBG_BREAKPOINTS := DebugLogger.FindOrRegisterLogGroup('DBG_BREAKPOINTS' {$IFDEF DBG_BREAKPOINTS} , True {$ENDIF} );
FPDBG_COMMANDS := DebugLogger.FindOrRegisterLogGroup('FPDBG_COMMANDS' {$IFDEF FPDBG_COMMANDS} , True {$ENDIF} ); FPDBG_COMMANDS := DebugLogger.FindOrRegisterLogGroup('FPDBG_COMMANDS' {$IFDEF FPDBG_COMMANDS} , True {$ENDIF} );
TFpBreakPointMap.DBG__VERBOSE := DBG_VERBOSE; TFpBreakPointTargetHandler.DBG__VERBOSE := DBG_VERBOSE;
TFpBreakPointMap.DBG__WARNINGS := DBG_WARNINGS; TFpBreakPointTargetHandler.DBG__WARNINGS := DBG_WARNINGS;
TFpBreakPointMap.DBG__BREAKPOINTS := DBG_BREAKPOINTS; TFpBreakPointTargetHandler.DBG__BREAKPOINTS := DBG_BREAKPOINTS;
finalization finalization
if assigned(RegisteredDbgProcessClasses) then if assigned(RegisteredDbgProcessClasses) then