FpDebug: Set breakpoints in libraries (dll/so). Update existing breakpoints when library is loaded. Add state (ok, fail, pending) to breakpoints.

This commit is contained in:
Martin 2023-02-15 18:35:26 +01:00
parent 5d091f5d5b
commit 04b384b34d
7 changed files with 382 additions and 85 deletions

View File

@ -416,14 +416,23 @@ type
{ TFpDbgBreakpoint }
TFpDbgBreakpoint = class;
TFpDbgBreakpointState = (bksUnknown, bksOk, bksFailed, bksPending);
TFpDbgBreakpointStateChangeEvent = procedure(Sender: TFpDbgBreakpoint; ANewState: TFpDbgBreakpointState) of object;
TFpDbgBreakpoint = class(TObject)
private
FFreeByDbgProcess: Boolean;
FEnabled: boolean;
FOn_Thread_StateChange: TFpDbgBreakpointStateChangeEvent;
protected
procedure SetEnabled(AValue: boolean);
function GetState: TFpDbgBreakpointState; virtual;
public
function Hit(const AThreadID: Integer; ABreakpointAddress: 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 RemoveAddress(const ALocation: TDBGPtr); virtual; abstract;
@ -434,6 +443,10 @@ type
// FreeByDbgProcess: The breakpoint will be freed by TDbgProcess.Destroy
property FreeByDbgProcess: Boolean read FFreeByDbgProcess write FFreeByDbgProcess;
property Enabled: boolean read FEnabled write SetEnabled;
property State: TFpDbgBreakpointState read GetState;
// Event runs in dbg-thread
property On_Thread_StateChange: TFpDbgBreakpointStateChangeEvent read FOn_Thread_StateChange write FOn_Thread_StateChange;
end;
{ TFpInternalBreakBase }
@ -442,6 +455,8 @@ type
private
FProcess: TDbgProcess;
protected
procedure UpdateForLibraryLoaded(ALib: TDbgLibrary); virtual;
procedure UpdateForLibrareUnloaded(ALib: TDbgLibrary); virtual;
property Process: TDbgProcess read FProcess;
public
constructor Create(const AProcess: TDbgProcess); virtual;
@ -455,21 +470,27 @@ type
private
FLocation: TDBGPtrArray;
FInternal: Boolean;
FState: TFpDbgBreakpointState;
protected
function GetState: TFpDbgBreakpointState; override;
procedure SetState(AState: TFpDbgBreakpointState);
procedure UpdateState; virtual;
procedure UpdateForLibrareUnloaded(ALib: TDbgLibrary); override;
property Location: TDBGPtrArray read FLocation;
public
constructor Create(const AProcess: TDbgProcess; const ALocation: TDBGPtrArray; AnEnabled: Boolean); virtual;
destructor Destroy; override;
function Hit(const AThreadID: Integer; ABreakpointAddress: 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 ALocations: TDBGPtrArray);
procedure RemoveAddress(const ALocation: TDBGPtr); override;
procedure RemoveAllAddresses; override;
procedure SetBreak; override;
procedure ResetBreak; override;
end;
{ TFpInternalBreakpointAtSymbol }
@ -477,6 +498,10 @@ type
TFpInternalBreakpointAtSymbol = class(TFpInternalBreakpoint)
private
FFuncName: String;
FSymInstance: TDbgInstance;
protected
procedure UpdateState; override;
procedure UpdateForLibraryLoaded(ALib: TDbgLibrary); override;
public
constructor Create(const AProcess: TDbgProcess; const AFuncName: String; AnEnabled: Boolean; ASymInstance: TDbgInstance = nil); virtual;
end;
@ -487,6 +512,11 @@ type
private
FFileName: String;
FLine: Cardinal;
FSymInstance: TDbgInstance;
FFoundFileWithoutLine: Boolean;
protected
procedure UpdateState; override;
procedure UpdateForLibraryLoaded(ALib: TDbgLibrary); override;
public
constructor Create(const AProcess: TDbgProcess; const AFileName: String; ALine: Cardinal; AnEnabled: Boolean; ASymInstance: TDbgInstance = nil); virtual;
end;
@ -514,7 +544,6 @@ type
constructor Create(const AProcess: TDbgProcess; const ALocation: TDBGPtr; ASize: Cardinal; AReadWrite: TDBGWatchPointKind;
AScope: TDBGWatchPointScope); virtual;
destructor Destroy; override;
function BelongsToInstance(const AnInstance: TDbgInstance): Boolean; override;
procedure SetBreak; override;
procedure ResetBreak; override;
@ -534,6 +563,7 @@ type
FProcess: TDbgProcess;
FSymbolTableInfo: TFpSymbolInfo;
FLoaderList: TDbgImageLoaderList;
FLastLineAddressesFoundFile: Boolean;
function GetOSDbgClasses: TOSDbgClasses;
function GetPointerSize: Integer;
@ -578,6 +608,7 @@ type
TDbgLibrary = class(TDbgInstance)
private
FModuleHandle: THandle;
FBreakUpdateDone: Boolean;
public
constructor Create(const AProcess: TDbgProcess; const ADefaultName: String; const AModuleHandle: THandle);
property Name: String read FFileName;
@ -674,6 +705,7 @@ type
function DoBreak(BreakpointAddress: TDBGPtr; AThreadID: integer): Boolean;
procedure SetLastLibraryUnloaded(ALib: TDbgLibrary);
procedure SetLastLibraryUnloadedNil(ALib: TDbgLibrary);
procedure AddLibrary(ALib: TDbgLibrary; AnID: TDbgPtr);
function GetRequiresExecutionInDebuggerThread: boolean; virtual;
function InsertBreakInstructionCode(const ALocation: TDBGPtr; out OrigValue: Byte; AMakeTempRemoved: Boolean): Boolean; virtual;
@ -721,6 +753,7 @@ type
*)
function FindProcSymbol(const AName: String): TFpSymbol; overload; // deprecated 'backward compatible / use FindProcSymbol(AName, TheDbgProcess)';
function FindProcSymbol(const AName: String; ASymInstance: TDbgInstance): TFpSymbol; overload;
procedure FindProcSymbol(const AName: String; ASymInstance: TDbgInstance; out ASymList: TFpSymbolArray);
function FindProcSymbol(const AName, ALibraryName: String; IsFullLibName: Boolean = True): TFpSymbol; overload;
function FindProcSymbol(AAdress: TDbgPtr): TFpSymbol; overload;
function FindSymbolScope(AThreadId, AStackFrame: Integer): TFpDbgSymbolScope;
@ -731,6 +764,8 @@ type
function GetLib(const AHandle: THandle; out ALib: TDbgLibrary): Boolean;
property LastLibrariesLoaded: TDbgLibraryArr read GetLastLibrariesLoaded;
property LastLibrariesUnloaded: TDbgLibraryArr read GetLastLibrariesUnloaded;
procedure UpdateBreakpointsForLibraryLoaded(ALib: TDbgLibrary);
procedure UpdateBreakpointsForLibraryUnloaded(ALib: TDbgLibrary);
function GetThread(const AID: Integer; out AThread: TDbgThread): Boolean;
procedure RemoveBreak(const ABreakPoint: TFpDbgBreakpoint);
procedure DoBeforeBreakLocationMapChange;
@ -760,7 +795,7 @@ type
// 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);
procedure RemoveAllBreakPoints;
function CheckForConsoleOutput(ATimeOutMs: integer): integer; virtual;
function GetConsoleOutput: string; virtual;
@ -908,6 +943,21 @@ begin
RegisteredDbgProcessClasses.Add(ADbgOsClasses);
end;
{ TFpDbgBreakpoint }
function TFpDbgBreakpoint.GetState: TFpDbgBreakpointState;
begin
Result := bksUnknown;
end;
procedure TFpDbgBreakpoint.SetEnabled(AValue: boolean);
begin
if AValue then
SetBreak
else
ResetBreak;
end;
{ TDbgCallstackEntryList }
procedure TDbgCallstackEntryList.SetHasReadAllAvailableFrames;
@ -1840,9 +1890,11 @@ begin
end;
function TDbgInstance.GetLineAddresses(AFileName: String; ALine: Cardinal; var AResultList: TDBGPtrArray): Boolean;
var
FoundLine: Integer;
begin
if Assigned(DbgInfo) and DbgInfo.HasInfo then
Result := DbgInfo.GetLineAddresses(AFileName, ALine, AResultList)
Result := DbgInfo.GetLineAddresses(AFileName, ALine, AResultList, fsNone, @FoundLine, @FLastLineAddressesFoundFile)
else
Result := False;
end;
@ -1999,6 +2051,38 @@ begin
end;
end;
procedure TDbgProcess.FindProcSymbol(const AName: String;
ASymInstance: TDbgInstance; out ASymList: TFpSymbolArray);
var
Lib: TDbgLibrary;
Sym: TFpSymbol;
begin
// TODO: find multiple symbols within the same DbgInfo
ASymList := nil;
if ASymInstance <> nil then begin
Sym := ASymInstance.FindProcSymbol(AName);
if Sym <> nil then begin
SetLength(ASymList, 1);
ASymList[0] := Sym;
end;
end
else begin
Sym := FindProcSymbol(AName);
if Sym <> nil then begin
SetLength(ASymList, 1);
ASymList[0] := Sym;
end;
for Lib in FLibMap do begin
Sym := Lib.FindProcSymbol(AName);
if Sym <> nil then begin
SetLength(ASymList, 1);
ASymList[0] := Sym;
end;
end;
end;
end;
function TDbgProcess.FindProcSymbol(const AName: String): TFpSymbol;
begin
Result := inherited FindProcSymbol(AName);
@ -2203,17 +2287,23 @@ var
Lib: TDbgLibrary;
begin
if ASymInstance <> nil then begin
if ASymInstance = self then
Result := inherited GetLineAddresses(AFileName, ALine, AResultList)
else
if ASymInstance = self then begin
Result := inherited GetLineAddresses(AFileName, ALine, AResultList);
end
else begin
Result := ASymInstance.GetLineAddresses(AFileName, ALine, AResultList);
FLastLineAddressesFoundFile := ASymInstance.FLastLineAddressesFoundFile;
end;
exit;
end;
Result := inherited GetLineAddresses(AFileName, ALine, AResultList);
for Lib in FLibMap do
for Lib in FLibMap do begin
if Lib.GetLineAddresses(AFileName, ALine, AResultList) then
Result := True;
if Lib.FLastLineAddressesFoundFile then
FLastLineAddressesFoundFile := True;
end;
end;
function TDbgProcess.ContextFromProc(AThreadId, AStackFrame: Integer;
@ -2227,6 +2317,46 @@ begin
Result := FLibMap.GetLib(AHandle, ALib);
end;
procedure TDbgProcess.UpdateBreakpointsForLibraryLoaded(ALib: TDbgLibrary);
var
i: Integer;
begin
if (ALib.DbgInfo.HasInfo) or (ALib.SymbolTableInfo.HasInfo) then begin
debugln(DBG_VERBOSE and (ALib.FBreakUpdateDone), ['TDbgProcess.UpdateBreakpointsForLibraryLoaded: Called twice for ', ALib.Name]);
assert(not ALib.FBreakUpdateDone, 'TDbgProcess.UpdateBreakpointsForLibraryLoaded: not ALib.FBreakUpdateDone');
if ALib.FBreakUpdateDone then
exit;
ALib.FBreakUpdateDone := True;
debuglnEnter(DBG_BREAKPOINTS,['> TDbgProcess.UpdateBreakpointsForLibraryLoaded ',ALib.Name ]); try
for i := 0 to FBreakpointList.Count - 1 do
FBreakpointList[i].UpdateForLibraryLoaded(ALib);
finally debuglnExit(DBG_BREAKPOINTS,['< TDbgProcess.UpdateBreakpointsForLibraryLoaded ' ]); end;
end;
end;
procedure TDbgProcess.UpdateBreakpointsForLibraryUnloaded(ALib: TDbgLibrary);
var
i: LongInt;
b: TFpInternalBreakBase;
begin
// The library is unloaded by the OS, so all breakpoints are already gone.
// This is more to update our administration and free some memory.
debuglnEnter(DBG_BREAKPOINTS, ['> TDbgProcess.UpdateBreakpointsForLibraryUnloaded ' ]); try if ALib <> nil then debugln(DBG_BREAKPOINTS, [ALib.Name]);
i := FBreakpointList.Count - 1;
while i >= 0 do begin
b := FBreakpointList[i];
b.UpdateForLibrareUnloaded(ALib);
dec(i);
end;
i := FWatchPointList.Count - 1;
while i >= 0 do begin
b := FWatchPointList[i];
b.UpdateForLibrareUnloaded(ALib);
dec(i);
end;
finally debuglnExit(DBG_BREAKPOINTS,['< TDbgProcess.UpdateBreakpointsForLibraryUnloaded ' ]); end;
end;
function TDbgProcess.GetThread(const AID: Integer; out AThread: TDbgThread): Boolean;
var
Thread: TDbgThread;
@ -2620,6 +2750,14 @@ begin
SetLastLibraryUnloaded(nil);
end;
procedure TDbgProcess.AddLibrary(ALib: TDbgLibrary; AnID: TDbgPtr);
begin
FLibMap.Add(AnID, ALib);
if (ALib.DbgInfo.HasInfo) or (ALib.SymbolTableInfo.HasInfo) then
FSymInstances.Add(ALib);
end;
function TDbgProcess.InsertBreakInstructionCode(const ALocation: TDBGPtr; out
OrigValue: Byte; AMakeTempRemoved: Boolean): Boolean;
var
@ -2661,7 +2799,7 @@ begin
AfterChangingInstructionCode(ALocation, 1);
end;
procedure TDbgProcess.RemoveAllBreakPoints(const OnlyForLibrary: TDbgLibrary = nil);
procedure TDbgProcess.RemoveAllBreakPoints;
var
i: LongInt;
b: TFpInternalBreakBase;
@ -2669,24 +2807,19 @@ begin
i := FBreakpointList.Count - 1;
while i >= 0 do begin
b := FBreakpointList[i];
if not Assigned(OnlyForLibrary) or b.BelongsToInstance(OnlyForLibrary) then begin
b.ResetBreak;
b.FProcess := nil;
FBreakpointList.Delete(i);
end;
b.ResetBreak;
b.FProcess := nil;
FBreakpointList.Delete(i);
dec(i);
end;
i := FWatchPointList.Count - 1;
while i >= 0 do begin
b := FWatchPointList[i];
if not Assigned(OnlyForLibrary) or b.BelongsToInstance(OnlyForLibrary) then begin
b.ResetBreak;
b.FProcess := nil;
FWatchPointList.Delete(i);
end;
b.ResetBreak;
b.FProcess := nil;
FWatchPointList.Delete(i);
dec(i);
end;
assert(Assigned(OnlyForLibrary) or (FBreakMap.Count = 0), 'TDbgProcess.RemoveAllBreakPoints: FBreakMap.Count = 0');
end;
procedure TDbgProcess.BeforeChangingInstructionCode(const ALocation: TDBGPtr; ACount: Integer);
@ -3503,6 +3636,16 @@ end;
{ TFpInternalBreakBase }
procedure TFpInternalBreakBase.UpdateForLibraryLoaded(ALib: TDbgLibrary);
begin
//
end;
procedure TFpInternalBreakBase.UpdateForLibrareUnloaded(ALib: TDbgLibrary);
begin
//
end;
constructor TFpInternalBreakBase.Create(const AProcess: TDbgProcess);
begin
inherited Create;
@ -3511,18 +3654,64 @@ end;
{ TDbgBreak }
function TFpInternalBreakpoint.GetState: TFpDbgBreakpointState;
begin
Result := FState;
end;
procedure TFpInternalBreakpoint.SetState(AState: TFpDbgBreakpointState);
begin
if AState = FState then
exit;
FState := AState;
if FOn_Thread_StateChange <> nil then
FOn_Thread_StateChange(Self, AState);
end;
procedure TFpInternalBreakpoint.UpdateState;
begin
if Length(FLocation) > 0 then
SetState(bksOk)
else
SetState(bksFailed);
end;
procedure TFpInternalBreakpoint.UpdateForLibrareUnloaded(ALib: TDbgLibrary);
var
i, j: Integer;
a: TDBGPtr;
begin
j := 0;
for i := 0 to Length(FLocation) - 1 do begin
a := FLocation[i];
FLocation[j] := a;
if ALib.EnclosesAddressRange(a, a) then
FProcess.FBreakMap.RemoveLocation(a, Self)
else
inc(j);
end;
if j < Length(FLocation) then begin
SetLength(FLocation, j);
UpdateState;
end;
end;
constructor TFpInternalBreakpoint.Create(const AProcess: TDbgProcess;
const ALocation: TDBGPtrArray; AnEnabled: Boolean);
begin
inherited Create(AProcess);
FProcess.FBreakpointList.Add(Self);
FLocation := ALocation;
FEnabled := AnEnabled;
FState := bksUnknown;
if AnEnabled then
SetBreak;
UpdateState;
end;
destructor TFpInternalBreakpoint.Destroy;
begin
On_Thread_StateChange := nil;
if FProcess <> nil then
FProcess.FBreakpointList.Remove(Self);
ResetBreak;
@ -3555,30 +3744,6 @@ begin
Result := False;
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);
var
l: Integer;
@ -3586,6 +3751,29 @@ begin
l := Length(FLocation);
SetLength(FLocation, l+1);
FLocation[l] := ALocation;
if Enabled then
FProcess.FBreakMap.AddLocation(ALocation, Self, True);
UpdateState;
end;
procedure TFpInternalBreakpoint.AddAddress(const ALocations: TDBGPtrArray);
var
l, i: Integer;
begin
l := Length(FLocation);
SetLength(FLocation, l + Length(ALocations));
if Enabled then begin
for i := 0 to Length(ALocations) - 1 do begin
FLocation[l + i] := ALocations[i];
FProcess.FBreakMap.AddLocation(ALocations[i], Self, True);
end;
end
else begin
for i := 0 to Length(ALocations) - 1 do
FLocation[l + i] := ALocations[i];
end;
UpdateState;
end;
procedure TFpInternalBreakpoint.RemoveAddress(const ALocation: TDBGPtr);
@ -3601,12 +3789,14 @@ begin
FLocation[i] := FLocation[l];
SetLength(FLocation, l);
FProcess.FBreakMap.RemoveLocation(ALocation, Self);
UpdateState;
end;
procedure TFpInternalBreakpoint.RemoveAllAddresses;
begin
ResetBreak;
SetLength(FLocation, 0);
UpdateState;
end;
procedure TFpInternalBreakpoint.ResetBreak;
@ -3616,6 +3806,8 @@ begin
{$IFDEF FPDEBUG_THREAD_CHECK}AssertFpDebugThreadId('TFpInternalBreakpoint.ResetBreak');{$ENDIF}
if FProcess = nil then
exit;
FEnabled := False;
for i := 0 to High(FLocation) do
FProcess.FBreakMap.RemoveLocation(FLocation[i], Self);
end;
@ -3627,26 +3819,57 @@ begin
{$IFDEF FPDEBUG_THREAD_CHECK}AssertFpDebugThreadId('TFpInternalBreakpoint.SetBreak');{$ENDIF}
if FProcess = nil then
exit;
FEnabled := True;
for i := 0 to High(FLocation) do
FProcess.FBreakMap.AddLocation(FLocation[i], Self, True);
end;
{ TFpInternalBreakpointAtSymbol }
procedure TFpInternalBreakpointAtSymbol.UpdateState;
begin
if Length(FLocation) > 0 then
SetState(bksOk)
else
SetState(bksPending);
end;
procedure TFpInternalBreakpointAtSymbol.UpdateForLibraryLoaded(ALib: TDbgLibrary
);
var
a: TDBGPtrArray;
AProcList: TFpSymbolArray;
i: Integer;
begin
if FSymInstance <> nil then // Can not be the newly created ...
exit;
FProcess.FindProcSymbol(FFuncName, ALib, AProcList);
SetLength(a, Length(AProcList));
for i := 0 to Length(AProcList) - 1 do begin
a[i] := AProcList[i].Address.Address;
AProcList[i].ReleaseReference;
end;
AddAddress(a);
end;
constructor TFpInternalBreakpointAtSymbol.Create(const AProcess: TDbgProcess;
const AFuncName: String; AnEnabled: Boolean; ASymInstance: TDbgInstance);
var
a: TDBGPtrArray;
AProc: TFpSymbol;
AProcList: TFpSymbolArray;
i: Integer;
begin
FFuncName := AFuncName;
FSymInstance := ASymInstance;
a := nil;
AProc := AProcess.FindProcSymbol(AFuncName, ASymInstance);
if AProc <> nil then begin
SetLength(a, 1);
a[0] := AProc.Address.Address;
AProc.ReleaseReference;
AProcess.FindProcSymbol(AFuncName, ASymInstance, AProcList);
SetLength(a, Length(AProcList));
for i := 0 to Length(AProcList) - 1 do begin
a[i] := AProcList[i].Address.Address;
AProcList[i].ReleaseReference;
end;
inherited Create(AProcess, a, AnEnabled);
@ -3654,6 +3877,32 @@ end;
{ TFpInternalBreakpointAtFileLine }
procedure TFpInternalBreakpointAtFileLine.UpdateState;
begin
if Length(FLocation) > 0 then
SetState(bksOk)
else
if FFoundFileWithoutLine then
SetState(bksFailed)
else
SetState(bksPending);
end;
procedure TFpInternalBreakpointAtFileLine.UpdateForLibraryLoaded(
ALib: TDbgLibrary);
var
addr: TDBGPtrArray;
begin
if FSymInstance <> nil then // Can not be the newly created ...
exit;
addr := nil;
FProcess.GetLineAddresses(FFileName, FLine, addr, ALib);
if FProcess.FLastLineAddressesFoundFile and (Length(addr) = 0) then
FFoundFileWithoutLine := True;
AddAddress(addr);
end;
constructor TFpInternalBreakpointAtFileLine.Create(const AProcess: TDbgProcess;
const AFileName: String; ALine: Cardinal; AnEnabled: Boolean;
ASymInstance: TDbgInstance);
@ -3662,9 +3911,11 @@ var
begin
FFileName := AFileName;
FLine := ALine;
FSymInstance := ASymInstance;
addr := nil;
AProcess.GetLineAddresses(AFileName, ALine, addr, ASymInstance);
FFoundFileWithoutLine := AProcess.FLastLineAddressesFoundFile and (Length(addr) = 0);
inherited Create(AProcess, addr, AnEnabled);
end;
@ -3750,12 +4001,6 @@ begin
inherited Destroy;
end;
function TFpInternalWatchpoint.BelongsToInstance(const AnInstance: TDbgInstance
): Boolean;
begin
Result := False;
end;
procedure TFpInternalWatchpoint.SetBreak;
var
a: TDBGPtr;

View File

@ -1750,7 +1750,7 @@ var
EventProcess: TDbgProcess;
DummyThread: TDbgThread;
CurCmd: TDbgControllerCmd;
ALib: TDbgLibrary;
begin
AExit:=false;
if FCurrentProcess = nil then begin
@ -1886,6 +1886,15 @@ begin
if MaybeDetach then
break;
case FPDEvent of
deLoadLibrary:
for ALib in EventProcess.LastLibrariesLoaded do
EventProcess.UpdateBreakpointsForLibraryLoaded(ALib);
deUnloadLibrary:
for ALib in EventProcess.LastLibrariesUnloaded do
EventProcess.UpdateBreakpointsForLibraryUnloaded(ALib);
end;
IsFinished:=false;
if FPDEvent=deExitProcess then begin
FreeAndNil(FCommand);
@ -2061,10 +2070,6 @@ begin
continue:=true;
if assigned(OnLibraryUnloadedEvent) and (Length(FCurrentProcess.LastLibrariesUnloaded)>0) then
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;
deInternalContinue:
begin

View File

@ -731,7 +731,7 @@ type
function GetDefinition(AAbbrevPtr: Pointer; out ADefinition: TDwarfAbbrev): Boolean; inline;
function GetLineAddressMap(const AFileName: String): PDWarfLineMap;
function GetLineAddresses(const AFileName: String; ALine: Cardinal; var AResultList: TDBGPtrArray;
AFindSibling: TGetLineAddrFindSibling = fsNone; AFoundLine: PInteger = nil): boolean;
AFindSibling: TGetLineAddrFindSibling = fsNone; AFoundLine: PInteger = nil; AFoundFilename: PBoolean = nil): boolean;
procedure BuildLineInfo(AAddressInfo: PDwarfAddressInfo; ADoAll: Boolean);
// On Darwin it could be that the debug-information is not included into the executable by the linker.
// This function is to map object-file addresses into the corresponding addresses in the executable.
@ -808,7 +808,7 @@ type
//function FindSymbol(const AName: String): TDbgSymbol; override; overload;
function GetLineAddresses(const AFileName: String; ALine: Cardinal; var AResultList: TDBGPtrArray;
AFindSibling: TGetLineAddrFindSibling = fsNone; AFoundLine: PInteger = nil): Boolean; override;
AFindSibling: TGetLineAddrFindSibling = fsNone; AFoundLine: PInteger = nil; AFoundFilename: PBoolean = nil): Boolean; override;
function GetLineAddressMap(const AFileName: String): PDWarfLineMap;
procedure LoadCallFrameInstructions;
function LoadCompilationUnits: Integer;
@ -3891,7 +3891,8 @@ end;
function TFpDwarfInfo.GetLineAddresses(const AFileName: String;
ALine: Cardinal; var AResultList: TDBGPtrArray;
AFindSibling: TGetLineAddrFindSibling; AFoundLine: PInteger): Boolean;
AFindSibling: TGetLineAddrFindSibling; AFoundLine: PInteger;
AFoundFilename: PBoolean): Boolean;
var
n: Integer;
CU: TDwarfCompilationUnit;
@ -3901,7 +3902,7 @@ begin
begin
CU := TDwarfCompilationUnit(FCompilationUnits[n]);
CU.WaitForScopeScan;
Result := CU.GetLineAddresses(AFileName, ALine, AResultList, AFindSibling, AFoundLine) or Result;
Result := CU.GetLineAddresses(AFileName, ALine, AResultList, AFindSibling, AFoundLine, AFoundFilename) or Result;
end;
end;
@ -5140,13 +5141,18 @@ end;
function TDwarfCompilationUnit.GetLineAddresses(const AFileName: String;
ALine: Cardinal; var AResultList: TDBGPtrArray;
AFindSibling: TGetLineAddrFindSibling; AFoundLine: PInteger): boolean;
AFindSibling: TGetLineAddrFindSibling; AFoundLine: PInteger;
AFoundFilename: PBoolean): boolean;
var
Map: PDWarfLineMap;
begin
Result := False;
Map := GetLineAddressMap(AFileName);
if Map = nil then exit;
if Map = nil then
exit;
if AFoundFilename <> nil then
AFoundFilename^ := True;
Result := Map^.GetAddressesForLine(ALine, AResultList, False, AFindSibling, AFoundLine);
end;

View File

@ -495,6 +495,8 @@ type
function CreateSymbolScope(ALocationContext: TFpDbgLocationContext): TFpDbgSymbolScope; virtual;
end;
TFpSymbolArray = array of TFpSymbol;
{ TFpSymbolForwarder }
TFpSymbolForwarder = class(TFpSymbol)
@ -648,7 +650,7 @@ type
property HasInfo: Boolean read FHasInfo;
function GetLineAddresses(const AFileName: String; ALine: Cardinal; var AResultList: TDBGPtrArray;
AFindSibling: TGetLineAddrFindSibling = fsNone; AFoundLine: PInteger = nil): Boolean; virtual;
AFindSibling: TGetLineAddrFindSibling = fsNone; AFoundLine: PInteger = nil; AFoundFilename: PBoolean = nil): Boolean; virtual;
//property MemManager: TFpDbgMemReaderBase read GetMemManager write SetMemManager;
property TargetInfo: TTargetDescriptor read FTargetInfo write FTargetInfo;
property MemManager: TFpDbgMemManager read FMemManager;
@ -1969,7 +1971,7 @@ end;
function TDbgInfo.GetLineAddresses(const AFileName: String; ALine: Cardinal;
var AResultList: TDBGPtrArray; AFindSibling: TGetLineAddrFindSibling;
AFoundLine: PInteger): Boolean;
AFoundLine: PInteger; AFoundFilename: PBoolean): Boolean;
begin
Result := False;
end;

View File

@ -1127,13 +1127,8 @@ begin
end;
procedure TDbgLinuxProcess.AddLib(const ALibrary: tDbgLinuxLibrary);
var
ID: TDbgPtr;
begin
ID := ALibrary.FLoadedTargetImageAddr;
FLibMap.Add(ID, ALibrary);
if (ALibrary.DbgInfo.HasInfo) or (ALibrary.SymbolTableInfo.HasInfo) then
FSymInstances.Add(ALibrary);
AddLibrary(ALibrary, ALibrary.FLoadedTargetImageAddr);
end;
constructor TDbgLinuxProcess.Create(const AFileName: string;

View File

@ -1474,14 +1474,9 @@ begin
end;
function TDbgWinProcess.AddLib(const AInfo: TLoadDLLDebugInfo): TDbgLibrary;
var
ID: TDbgPtr;
begin
Result := TDbgWinLibrary.Create(Self, HexValue(AInfo.lpBaseOfDll, SizeOf(Pointer), [hvfIncludeHexchar]), AInfo.hFile, AInfo);
ID := TDbgPtr(AInfo.lpBaseOfDll);
FLibMap.Add(ID, Result);
if (Result.DbgInfo.HasInfo) or (Result.SymbolTableInfo.HasInfo)
then FSymInstances.Add(Result);
AddLibrary(Result, TDbgPtr(AInfo.lpBaseOfDll));
end;
procedure TDbgWinProcess.RemoveLib(const AInfo: TUnloadDLLDebugInfo);

View File

@ -315,6 +315,12 @@ type
// procedure ClearState;
end;
TBreakPointUpdateInfo = record
InternalBreak: TFpDbgBreakpoint;
NewState: TFpDbgBreakpointState;
end;
TBreakPointUpdateList = specialize TLazThreadedQueue<TBreakPointUpdateInfo>;
TThreadIdList = specialize TFPGList<Integer>;
{ TFpDebugDebugger }
@ -346,6 +352,7 @@ type
FCachePointer: pointer;
FCacheThreadId, FCacheStackFrame: Integer;
FCacheContext: TFpDbgSymbolScope;
FBreakUpdateList: TBreakPointUpdateList;
FFpDebugOutputQueue: TFpDebugStringQueue;
FFpDebugOutputAsync: integer;
//
@ -360,6 +367,9 @@ type
// HandleRunError: Software called RuntimeError
procedure HandleRunError(var continue: boolean);
procedure FreeDebugThread;
procedure Do_Thread_BreakStateChanged(Sender: TFpDbgBreakpoint; ANewState: TFpDbgBreakpointState);
procedure DoBreakStateChanged(Data: PtrInt);
procedure FDbgControllerHitBreakpointEvent(var continue: boolean;
const Breakpoint: TFpDbgBreakpoint; AnEventType: TFPDEvent; AMoreHitEventsPending: Boolean);
procedure EnterPause(ALocationAddr: TDBGLocationRec; AnInternalPause: Boolean = False);
@ -1131,8 +1141,15 @@ begin
FDbgBreakPoint.FInternalBreakpoint := InternalBreakpoint;
if not assigned(InternalBreakpoint) then
FDbgBreakPoint.Validity := vsInvalid // pending?
else
FDbgBreakPoint.Validity := vsValid;
else begin
case InternalBreakpoint.State of
bksUnknown: FDbgBreakPoint.Validity := vsUnknown;
bksOk: FDbgBreakPoint.Validity := vsValid;
bksFailed: FDbgBreakPoint.Validity := vsInvalid;
bksPending: FDbgBreakPoint.Validity := vsPending;
end;
InternalBreakpoint.On_Thread_StateChange := @TFpDebugDebugger(FDebugger).Do_Thread_BreakStateChanged;
end;
end;
UnQueue_DecRef;
@ -1920,6 +1937,7 @@ begin
// freed. And so are the corresponding InternalBreakpoint's.
if assigned(Debugger) and assigned(FInternalBreakpoint) then
begin
FInternalBreakpoint.On_Thread_StateChange := nil;
debuglnEnter(DBG_BREAKPOINTS, ['>> TFPBreakpoint.ResetBreak REMOVE ',FSource,':',FLine,'/',dbghex(Address),' ' ]);
WorkItem := TFpThreadWorkerBreakPointRemoveUpdate.Create(TFpDebugDebugger(Debugger), Self);
TFpDebugDebugger(Debugger).FWorkQueue.PushItem(WorkItem);
@ -2018,6 +2036,8 @@ end;
destructor TFPBreakpoint.Destroy;
begin
if FInternalBreakpoint <> nil then
FInternalBreakpoint.On_Thread_StateChange := nil;
(* No need to request a pause. This will run, as soon as the debugger gets to the next pause.
If the next pause is a hit on this breakpoint, then it will be ignored
*)
@ -3680,6 +3700,33 @@ begin
DoProcessMessages // run the AsyncMethods
end;
procedure TFpDebugDebugger.Do_Thread_BreakStateChanged(
Sender: TFpDbgBreakpoint; ANewState: TFpDbgBreakpointState);
var
Info: TBreakPointUpdateInfo;
begin
Info.InternalBreak := Sender;
Info.NewState := ANewState;
FBreakUpdateList.PushItem(Info);
Application.QueueAsyncCall(@DoBreakStateChanged, 0);
end;
procedure TFpDebugDebugger.DoBreakStateChanged(Data: PtrInt);
var
Info: TBreakPointUpdateInfo;
ABreakPoint: TDBGBreakPoint;
begin
while FBreakUpdateList.PopItemTimeout(Info, 0) = wrSignaled do begin
ABreakPoint := TFPBreakpoints(BreakPoints).Find(Info.InternalBreak);
case Info.NewState of
bksUnknown: TFPBreakpoint(ABreakPoint).Validity := vsUnknown;
bksOk: TFPBreakpoint(ABreakPoint).Validity := vsValid;
bksFailed: TFPBreakpoint(ABreakPoint).Validity := vsInvalid;
bksPending: TFPBreakpoint(ABreakPoint).Validity := vsPending;
end;
end;
end;
procedure TFpDebugDebugger.FDbgControllerHitBreakpointEvent(
var continue: boolean; const Breakpoint: TFpDbgBreakpoint;
AnEventType: TFPDEvent; AMoreHitEventsPending: Boolean);
@ -4453,6 +4500,7 @@ begin
FWorkQueue := TFpThreadPriorityWorkerQueue.Create(100);
FWorkQueue.OnQueueIdle := @CheckAndRunIdle;
FFpDebugOutputQueue := TFpDebugStringQueue.create(100);
FBreakUpdateList := TBreakPointUpdateList.create();
FExceptionStepper := TFpDebugExceptionStepping.Create(Self);
FPrettyPrinter := TFpPascalPrettyPrinter.Create(sizeof(pointer));
FMemReader := TFpDbgMemReader.Create(self);
@ -4495,6 +4543,7 @@ begin
Application.RemoveAsyncCalls(Self);
FreeAndNil(FFpDebugOutputQueue);
FreeAndNil(FBreakUpdateList);
FreeAndNil(FDbgController);
FreeAndNil(FPrettyPrinter);
FreeAndNil(FMemManager);