mirror of
https://gitlab.com/freepascal.org/lazarus/lazarus.git
synced 2025-08-10 07:36:19 +02:00
FpDebug: Remove breakpoints bound to a specific library when this library gets unloaded
This commit is contained in:
parent
947a183c9c
commit
4e4c402b62
@ -88,6 +88,7 @@ type
|
|||||||
{ TDbgCallstackEntry }
|
{ TDbgCallstackEntry }
|
||||||
TDbgThread = class;
|
TDbgThread = class;
|
||||||
TFPDThreadArray = array of TDbgThread;
|
TFPDThreadArray = array of TDbgThread;
|
||||||
|
TDbgInstance = class;
|
||||||
TDbgLibrary = class;
|
TDbgLibrary = class;
|
||||||
TOSDbgClasses = class;
|
TOSDbgClasses = class;
|
||||||
TDbgAsmInstruction = class;
|
TDbgAsmInstruction = class;
|
||||||
@ -366,6 +367,8 @@ type
|
|||||||
public
|
public
|
||||||
function Hit(const AThreadID: Integer; ABreakpointAddress: TDBGPtr): Boolean; virtual; abstract;
|
function Hit(const AThreadID: Integer; ABreakpointAddress: TDBGPtr): Boolean; virtual; abstract;
|
||||||
function HasLocation(const ALocation: TDBGPtr): Boolean; virtual; abstract;
|
function HasLocation(const ALocation: TDBGPtr): Boolean; virtual; abstract;
|
||||||
|
// A breakpoint could also be inside/part of a library.
|
||||||
|
function BelongsToInstance(const AnInstance: TDbgInstance): Boolean; virtual; abstract;
|
||||||
|
|
||||||
procedure AddAddress(const ALocation: TDBGPtr); virtual; abstract;
|
procedure AddAddress(const ALocation: TDBGPtr); virtual; abstract;
|
||||||
procedure RemoveAddress(const ALocation: TDBGPtr); virtual; abstract;
|
procedure RemoveAddress(const ALocation: TDBGPtr); virtual; abstract;
|
||||||
@ -404,6 +407,7 @@ type
|
|||||||
destructor Destroy; override;
|
destructor Destroy; override;
|
||||||
function Hit(const AThreadID: Integer; ABreakpointAddress: TDBGPtr): Boolean; override;
|
function Hit(const AThreadID: Integer; ABreakpointAddress: TDBGPtr): Boolean; override;
|
||||||
function HasLocation(const ALocation: TDBGPtr): Boolean; override;
|
function HasLocation(const ALocation: TDBGPtr): Boolean; override;
|
||||||
|
function BelongsToInstance(const AnInstance: TDbgInstance): Boolean; override;
|
||||||
|
|
||||||
procedure AddAddress(const ALocation: TDBGPtr); override;
|
procedure AddAddress(const ALocation: TDBGPtr); override;
|
||||||
procedure RemoveAddress(const ALocation: TDBGPtr); override;
|
procedure RemoveAddress(const ALocation: TDBGPtr); override;
|
||||||
@ -481,6 +485,11 @@ type
|
|||||||
function FindProcSymbol(AAdress: TDbgPtr): TFpSymbol; overload;
|
function FindProcSymbol(AAdress: TDbgPtr): TFpSymbol; overload;
|
||||||
function FindProcStartEndPC(AAdress: TDbgPtr; out AStartPC, AEndPC: TDBGPtr): boolean;
|
function FindProcStartEndPC(AAdress: TDbgPtr; out AStartPC, AEndPC: TDBGPtr): boolean;
|
||||||
|
|
||||||
|
// Check if a certain (range of) address(es) belongs to a specific Instance
|
||||||
|
// (for example a library)
|
||||||
|
function EnclosesAddress(AnAddress: TDBGPtr): Boolean;
|
||||||
|
function EnclosesAddressRange(AStartAddress, AnEndAddress: TDBGPtr): Boolean;
|
||||||
|
|
||||||
procedure LoadInfo; virtual;
|
procedure LoadInfo; virtual;
|
||||||
|
|
||||||
property Process: TDbgProcess read FProcess;
|
property Process: TDbgProcess read FProcess;
|
||||||
@ -599,7 +608,6 @@ type
|
|||||||
|
|
||||||
function InsertBreakInstructionCode(const ALocation: TDBGPtr; out OrigValue: Byte): Boolean; virtual;
|
function InsertBreakInstructionCode(const ALocation: TDBGPtr; out OrigValue: Byte): Boolean; virtual;
|
||||||
function RemoveBreakInstructionCode(const ALocation: TDBGPtr; const OrigValue: Byte): Boolean; virtual;
|
function RemoveBreakInstructionCode(const ALocation: TDBGPtr; const OrigValue: Byte): Boolean; virtual;
|
||||||
procedure RemoveAllBreakPoints;
|
|
||||||
procedure BeforeChangingInstructionCode(const ALocation: TDBGPtr; ACount: Integer); virtual;
|
procedure BeforeChangingInstructionCode(const ALocation: TDBGPtr; ACount: Integer); virtual;
|
||||||
procedure AfterChangingInstructionCode(const ALocation: TDBGPtr; ACount: Integer); virtual;
|
procedure AfterChangingInstructionCode(const ALocation: TDBGPtr; ACount: Integer); virtual;
|
||||||
|
|
||||||
@ -671,6 +679,11 @@ type
|
|||||||
function WaitForDebugEvent(out ProcessIdentifier, ThreadIdentifier: THandle): boolean; virtual; abstract;
|
function WaitForDebugEvent(out ProcessIdentifier, ThreadIdentifier: THandle): boolean; virtual; abstract;
|
||||||
function ResolveDebugEvent(AThread: TDbgThread): TFPDEvent; virtual;
|
function ResolveDebugEvent(AThread: TDbgThread): TFPDEvent; virtual;
|
||||||
|
|
||||||
|
// Remove (and free if applicable) all breakpoints for this process. When a
|
||||||
|
// library is specified as OnlyForLibrary, only breakpoints that belong to this
|
||||||
|
// library are cleared.
|
||||||
|
procedure RemoveAllBreakPoints(const OnlyForLibrary: TDbgLibrary = nil);
|
||||||
|
|
||||||
function CheckForConsoleOutput(ATimeOutMs: integer): integer; virtual;
|
function CheckForConsoleOutput(ATimeOutMs: integer): integer; virtual;
|
||||||
function GetConsoleOutput: string; virtual;
|
function GetConsoleOutput: string; virtual;
|
||||||
procedure SendConsoleInput(AString: string); virtual;
|
procedure SendConsoleInput(AString: string); virtual;
|
||||||
@ -1676,6 +1689,16 @@ begin
|
|||||||
Result := FDbgInfo.FindProcStartEndPC(AAdress, AStartPC, AEndPC);
|
Result := FDbgInfo.FindProcStartEndPC(AAdress, AStartPC, AEndPC);
|
||||||
end;
|
end;
|
||||||
|
|
||||||
|
function TDbgInstance.EnclosesAddress(AnAddress: TDBGPtr): Boolean;
|
||||||
|
begin
|
||||||
|
EnclosesAddressRange(AnAddress, AnAddress);
|
||||||
|
end;
|
||||||
|
|
||||||
|
function TDbgInstance.EnclosesAddressRange(AStartAddress, AnEndAddress: TDBGPtr): Boolean;
|
||||||
|
begin
|
||||||
|
Result := FLoaderList.EnclosesAddressRange(AStartAddress, AnEndAddress);
|
||||||
|
end;
|
||||||
|
|
||||||
procedure TDbgInstance.LoadInfo;
|
procedure TDbgInstance.LoadInfo;
|
||||||
begin
|
begin
|
||||||
InitializeLoaders;
|
InitializeLoaders;
|
||||||
@ -2410,7 +2433,7 @@ begin
|
|||||||
AfterChangingInstructionCode(ALocation, 1);
|
AfterChangingInstructionCode(ALocation, 1);
|
||||||
end;
|
end;
|
||||||
|
|
||||||
procedure TDbgProcess.RemoveAllBreakPoints;
|
procedure TDbgProcess.RemoveAllBreakPoints(const OnlyForLibrary: TDbgLibrary = nil);
|
||||||
var
|
var
|
||||||
i: LongInt;
|
i: LongInt;
|
||||||
b: TFpInternalBreakBase;
|
b: TFpInternalBreakBase;
|
||||||
@ -2418,20 +2441,24 @@ begin
|
|||||||
i := FBreakpointList.Count - 1;
|
i := FBreakpointList.Count - 1;
|
||||||
while i >= 0 do begin
|
while i >= 0 do begin
|
||||||
b := FBreakpointList[i];
|
b := FBreakpointList[i];
|
||||||
|
if not Assigned(OnlyForLibrary) or b.BelongsToInstance(OnlyForLibrary) then begin
|
||||||
b.ResetBreak;
|
b.ResetBreak;
|
||||||
b.FProcess := nil;
|
b.FProcess := nil;
|
||||||
FBreakpointList.Delete(i);
|
FBreakpointList.Delete(i);
|
||||||
|
end;
|
||||||
dec(i);
|
dec(i);
|
||||||
end;
|
end;
|
||||||
i := FWatchPointList.Count - 1;
|
i := FWatchPointList.Count - 1;
|
||||||
while i >= 0 do begin
|
while i >= 0 do begin
|
||||||
b := FWatchPointList[i];
|
b := FWatchPointList[i];
|
||||||
|
if not Assigned(OnlyForLibrary) or b.BelongsToInstance(OnlyForLibrary) then begin
|
||||||
b.ResetBreak;
|
b.ResetBreak;
|
||||||
b.FProcess := nil;
|
b.FProcess := nil;
|
||||||
FWatchPointList.Delete(i);
|
FWatchPointList.Delete(i);
|
||||||
|
end;
|
||||||
dec(i);
|
dec(i);
|
||||||
end;
|
end;
|
||||||
assert(FBreakMap.Count = 0, 'TDbgProcess.RemoveAllBreakPoints: FBreakMap.Count = 0');
|
assert(Assigned(OnlyForLibrary) or (FBreakMap.Count = 0), 'TDbgProcess.RemoveAllBreakPoints: FBreakMap.Count = 0');
|
||||||
end;
|
end;
|
||||||
|
|
||||||
procedure TDbgProcess.BeforeChangingInstructionCode(const ALocation: TDBGPtr; ACount: Integer);
|
procedure TDbgProcess.BeforeChangingInstructionCode(const ALocation: TDBGPtr; ACount: Integer);
|
||||||
@ -3219,6 +3246,30 @@ begin
|
|||||||
Result := False;
|
Result := False;
|
||||||
end;
|
end;
|
||||||
|
|
||||||
|
function TFpInternalBreakpoint.BelongsToInstance(const AnInstance: TDbgInstance): Boolean;
|
||||||
|
var
|
||||||
|
i: Integer;
|
||||||
|
Hi: TDBGPtr;
|
||||||
|
Lo: TDBGPtr;
|
||||||
|
begin
|
||||||
|
if Length(FLocation) = 0 then
|
||||||
|
Exit(False);
|
||||||
|
|
||||||
|
// Search for the lowest and higest locations
|
||||||
|
Lo := FLocation[0];
|
||||||
|
Hi := FLocation[0];
|
||||||
|
for i := 0 to High(FLocation) do
|
||||||
|
begin
|
||||||
|
if FLocation[i] > Hi then
|
||||||
|
Hi := FLocation[i]
|
||||||
|
else if FLocation[i] < Lo then
|
||||||
|
Lo := FLocation[i];
|
||||||
|
end;
|
||||||
|
// Check if the range between the lowest and highest location belongs to (fits into)
|
||||||
|
// the instance
|
||||||
|
Result := AnInstance.EnclosesAddressRange(Lo, Hi);
|
||||||
|
end;
|
||||||
|
|
||||||
procedure TFpInternalBreakpoint.AddAddress(const ALocation: TDBGPtr);
|
procedure TFpInternalBreakpoint.AddAddress(const ALocation: TDBGPtr);
|
||||||
var
|
var
|
||||||
l: Integer;
|
l: Integer;
|
||||||
|
@ -1778,6 +1778,7 @@ procedure TDbgController.SendEvents(out continue: boolean);
|
|||||||
var
|
var
|
||||||
HasPauseRequest: Boolean;
|
HasPauseRequest: Boolean;
|
||||||
CurWatch: TFpInternalWatchpoint;
|
CurWatch: TFpInternalWatchpoint;
|
||||||
|
i: Integer;
|
||||||
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;
|
||||||
@ -1881,6 +1882,10 @@ begin
|
|||||||
continue:=true;
|
continue:=true;
|
||||||
if assigned(OnLibraryUnloadedEvent) and (Length(FCurrentProcess.LastLibrariesUnloaded)>0) then
|
if assigned(OnLibraryUnloadedEvent) and (Length(FCurrentProcess.LastLibrariesUnloaded)>0) then
|
||||||
OnLibraryUnloadedEvent(continue, FCurrentProcess.LastLibrariesUnloaded);
|
OnLibraryUnloadedEvent(continue, FCurrentProcess.LastLibrariesUnloaded);
|
||||||
|
// The library is unloaded by the OS, so all breakpoints are already gone.
|
||||||
|
// This is more to update our administration and free some memory.
|
||||||
|
for i := 0 to High(FCurrentProcess.LastLibrariesUnloaded) do
|
||||||
|
FCurrentProcess.RemoveAllBreakPoints(FCurrentProcess.LastLibrariesUnloaded[i]);
|
||||||
end;
|
end;
|
||||||
deInternalContinue:
|
deInternalContinue:
|
||||||
begin
|
begin
|
||||||
|
@ -84,6 +84,8 @@ type
|
|||||||
procedure CloseFileLoader;
|
procedure CloseFileLoader;
|
||||||
procedure AddToLoaderList(ALoaderList: TDbgImageLoaderList);
|
procedure AddToLoaderList(ALoaderList: TDbgImageLoaderList);
|
||||||
function IsValid: Boolean;
|
function IsValid: Boolean;
|
||||||
|
function EnclosesAddressRange(AStartAddress, AnEndAddress: TDBGPtr): Boolean;
|
||||||
|
|
||||||
property FileName: String read FFileName; // Empty if using USE_WIN_FILE_MAPPING
|
property FileName: String read FFileName; // Empty if using USE_WIN_FILE_MAPPING
|
||||||
property ImageBase: QWord read GetImageBase;
|
property ImageBase: QWord read GetImageBase;
|
||||||
property RelocationOffset: TDBGPtrOffset read GetRelocationOffset;
|
property RelocationOffset: TDBGPtrOffset read GetRelocationOffset;
|
||||||
@ -118,6 +120,8 @@ type
|
|||||||
function GetItem(Index: Integer): TDbgImageLoader;
|
function GetItem(Index: Integer): TDbgImageLoader;
|
||||||
procedure SetItem(Index: Integer; AValue: TDbgImageLoader);
|
procedure SetItem(Index: Integer; AValue: TDbgImageLoader);
|
||||||
public
|
public
|
||||||
|
function EnclosesAddressRange(AStartAddress, AnEndAddress: TDBGPtr): Boolean;
|
||||||
|
|
||||||
property Items[Index: Integer]: TDbgImageLoader read GetItem write SetItem; default;
|
property Items[Index: Integer]: TDbgImageLoader read GetItem write SetItem; default;
|
||||||
property ImageBase: QWord read GetImageBase;
|
property ImageBase: QWord read GetImageBase;
|
||||||
property RelocationOffset: TDBGPtrOffset read GetRelocationOffset;
|
property RelocationOffset: TDBGPtrOffset read GetRelocationOffset;
|
||||||
@ -165,6 +169,16 @@ begin
|
|||||||
inherited SetItem(Index, AValue);
|
inherited SetItem(Index, AValue);
|
||||||
end;
|
end;
|
||||||
|
|
||||||
|
function TDbgImageLoaderList.EnclosesAddressRange(AStartAddress, AnEndAddress: TDBGPtr): Boolean;
|
||||||
|
var
|
||||||
|
i: Integer;
|
||||||
|
begin
|
||||||
|
for i := 0 to Count -1 do
|
||||||
|
if Items[0].EnclosesAddressRange(AStartAddress, AnEndAddress) then
|
||||||
|
Exit(True);
|
||||||
|
Result := False;
|
||||||
|
end;
|
||||||
|
|
||||||
{ TDbgImageLoaderLibrary }
|
{ TDbgImageLoaderLibrary }
|
||||||
|
|
||||||
procedure TDbgImageLoaderLibrary.ParseSymbolTable(AFpSymbolInfo: TfpSymbolList);
|
procedure TDbgImageLoaderLibrary.ParseSymbolTable(AFpSymbolInfo: TfpSymbolList);
|
||||||
@ -305,5 +319,13 @@ begin
|
|||||||
Result := FImgReader <> nil;
|
Result := FImgReader <> nil;
|
||||||
end;
|
end;
|
||||||
|
|
||||||
|
function TDbgImageLoader.EnclosesAddressRange(AStartAddress, AnEndAddress: TDBGPtr): Boolean;
|
||||||
|
begin
|
||||||
|
Result := False;
|
||||||
|
if not IsValid then
|
||||||
|
Exit;
|
||||||
|
Result := FImgReader.EnclosesAddressRange(AStartAddress, AnEndAddress);
|
||||||
|
end;
|
||||||
|
|
||||||
end.
|
end.
|
||||||
|
|
||||||
|
@ -130,6 +130,7 @@ type
|
|||||||
// LoadedTargetImageAddr.
|
// LoadedTargetImageAddr.
|
||||||
constructor Create({%H-}ASource: TDbgFileLoader; {%H-}ADebugMap: TObject; ALoadedTargetImageAddr: TDbgPtr; OwnSource: Boolean); virtual;
|
constructor Create({%H-}ASource: TDbgFileLoader; {%H-}ADebugMap: TObject; ALoadedTargetImageAddr: TDbgPtr; OwnSource: Boolean); virtual;
|
||||||
procedure AddSubFilesToLoaderList(ALoaderList: TObject; PrimaryLoader: TObject); virtual;
|
procedure AddSubFilesToLoaderList(ALoaderList: TObject; PrimaryLoader: TObject); virtual;
|
||||||
|
function EnclosesAddressRange(AStartAddress, AnEndAddress: TDBGPtr): Boolean; virtual;
|
||||||
// The ImageBase is the address at which the linker assumed the binary will be
|
// The ImageBase is the address at which the linker assumed the binary will be
|
||||||
// loaded at. So it is stored inside the binary itself and all addresses inside
|
// loaded at. So it is stored inside the binary itself and all addresses inside
|
||||||
// the binary assume that once loaded into memory, it is loaded at this
|
// the binary assume that once loaded into memory, it is loaded at this
|
||||||
@ -535,6 +536,10 @@ begin
|
|||||||
//
|
//
|
||||||
end;
|
end;
|
||||||
|
|
||||||
|
function TDbgImageReader.EnclosesAddressRange(AStartAddress, AnEndAddress: TDBGPtr): Boolean;
|
||||||
|
begin
|
||||||
|
Result := False;
|
||||||
|
end;
|
||||||
|
|
||||||
procedure InitDebugInfoLists;
|
procedure InitDebugInfoLists;
|
||||||
begin
|
begin
|
||||||
|
@ -65,6 +65,7 @@ type
|
|||||||
public
|
public
|
||||||
class function isValid(ASource: TDbgFileLoader): Boolean; override;
|
class function isValid(ASource: TDbgFileLoader): Boolean; override;
|
||||||
class function UserName: AnsiString; override;
|
class function UserName: AnsiString; override;
|
||||||
|
function EnclosesAddressRange(AStartAddress, AnEndAddress: TDBGPtr): Boolean; override;
|
||||||
public
|
public
|
||||||
constructor Create(ASource: TDbgFileLoader; ADebugMap: TObject; ALoadedTargetImageAddr: TDbgPtr; OwnSource: Boolean); override;
|
constructor Create(ASource: TDbgFileLoader; ADebugMap: TObject; ALoadedTargetImageAddr: TDbgPtr; OwnSource: Boolean); override;
|
||||||
destructor Destroy; override;
|
destructor Destroy; override;
|
||||||
@ -527,6 +528,22 @@ begin
|
|||||||
Result:='PE file';
|
Result:='PE file';
|
||||||
end;
|
end;
|
||||||
|
|
||||||
|
function TPEFileSource.EnclosesAddressRange(AStartAddress, AnEndAddress: TDBGPtr): Boolean;
|
||||||
|
var
|
||||||
|
i: Integer;
|
||||||
|
ex: PDbgImageSectionEx;
|
||||||
|
s: PDbgImageSection;
|
||||||
|
begin
|
||||||
|
for i := 0 to FSections.Count - 1 do
|
||||||
|
begin
|
||||||
|
ex := PDbgImageSectionEx(FSections.Objects[i]);
|
||||||
|
s := @ex^.Sect;
|
||||||
|
if (s^.VirtualAddress+LoadedTargetImageAddr <= AStartAddress) and
|
||||||
|
(s^.VirtualAddress + s^.Size + LoadedTargetImageAddr >= AnEndAddress) then
|
||||||
|
Exit(True);
|
||||||
|
end;
|
||||||
|
Result := False;
|
||||||
|
end;
|
||||||
|
|
||||||
initialization
|
initialization
|
||||||
DBG_WARNINGS := DebugLogger.FindOrRegisterLogGroup('DBG_WARNINGS' {$IFDEF DBG_WARNINGS} , True {$ENDIF} );
|
DBG_WARNINGS := DebugLogger.FindOrRegisterLogGroup('DBG_WARNINGS' {$IFDEF DBG_WARNINGS} , True {$ENDIF} );
|
||||||
|
Loading…
Reference in New Issue
Block a user