FpDebug: Allow breakpoints on lines without code (search up to N lines below).

This commit is contained in:
Martin 2024-04-21 13:54:12 +02:00
parent 3f1548052d
commit 0b2c6bd8fa
7 changed files with 263 additions and 46 deletions

View File

@ -654,7 +654,8 @@ type
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;
constructor Create(const AProcess: TDbgProcess; const AFileName: String; ALine: Cardinal;
AnEnabled: Boolean; ASymInstance: TDbgInstance = nil); virtual;
end;
{ TFpInternalWatchpoint }
@ -693,6 +694,7 @@ type
TDbgConfig = class
private
FBreakpointSearchMaxLines: integer;
// WindowBounds
FUseConsoleWinPos: boolean;
FUseConsoleWinSize: boolean;
@ -722,6 +724,8 @@ type
property FileOverwriteStdIn: Boolean read FFileOverwriteStdIn write FFileOverwriteStdIn;
property FileOverwriteStdOut: Boolean read FFileOverwriteStdOut write FFileOverwriteStdOut;
property FileOverwriteStdErr: Boolean read FFileOverwriteStdErr write FFileOverwriteStdErr;
// Breakpoints
property BreakpointSearchMaxLines: integer read FBreakpointSearchMaxLines write FBreakpointSearchMaxLines;
end;
{ TDbgInstance }
@ -739,7 +743,8 @@ type
function GetOSDbgClasses: TOSDbgClasses;
function GetPointerSize: Integer;
function GetLineAddresses(AFileName: String; ALine: Cardinal; var AResultList: TDBGPtrArray): Boolean;
function GetLineAddresses(AFileName: String; ALine: Cardinal; var AResultList: TDBGPtrArray;
AFindSibling: TGetLineAddrFindSibling = fsNone; AMaxSiblingDistance: integer = 0): Boolean;
function FindProcSymbol(const AName: String; AIgnoreCase: Boolean = False): TFpSymbol; overload;
function FindProcSymbol(AAdress: TDbgPtr): TFpSymbol; overload;
protected
@ -941,7 +946,8 @@ type
function FindSymbolScope(AThreadId, AStackFrame: Integer): TFpDbgSymbolScope;
function FindProcStartEndPC(const AAdress: TDbgPtr; out AStartPC, AEndPC: TDBGPtr): boolean;
function GetLineAddresses(AFileName: String; ALine: Cardinal; var AResultList: TDBGPtrArray; ASymInstance: TDbgInstance = nil): Boolean;
function GetLineAddresses(AFileName: String; ALine: Cardinal; var AResultList: TDBGPtrArray; ASymInstance: TDbgInstance = nil;
AFindSibling: TGetLineAddrFindSibling = fsNone; AMaxSiblingDistance: integer = 0): Boolean;
//function ContextFromProc(AThreadId, AStackFrame: Integer; AProcSym: TFpSymbol): TFpDbgLocationContext; inline; deprecated 'use TFpDbgSimpleLocationContext.Create';
function GetLib(const AHandle: THandle; out ALib: TDbgLibrary): Boolean;
property LibMap: TLibraryMap read FLibMap;
@ -2230,12 +2236,14 @@ begin
inherited;
end;
function TDbgInstance.GetLineAddresses(AFileName: String; ALine: Cardinal; var AResultList: TDBGPtrArray): Boolean;
function TDbgInstance.GetLineAddresses(AFileName: String; ALine: Cardinal;
var AResultList: TDBGPtrArray; AFindSibling: TGetLineAddrFindSibling;
AMaxSiblingDistance: integer): Boolean;
var
FoundLine: Integer;
begin
if Assigned(DbgInfo) and DbgInfo.HasInfo then
Result := DbgInfo.GetLineAddresses(AFileName, ALine, AResultList, fsNone, @FoundLine, @FLastLineAddressesFoundFile)
Result := DbgInfo.GetLineAddresses(AFileName, ALine, AResultList, AFindSibling, @FoundLine, @FLastLineAddressesFoundFile, AMaxSiblingDistance)
else
Result := False;
end;
@ -2628,24 +2636,25 @@ begin
end;
function TDbgProcess.GetLineAddresses(AFileName: String; ALine: Cardinal;
var AResultList: TDBGPtrArray; ASymInstance: TDbgInstance): Boolean;
var AResultList: TDBGPtrArray; ASymInstance: TDbgInstance;
AFindSibling: TGetLineAddrFindSibling; AMaxSiblingDistance: integer): Boolean;
var
Lib: TDbgLibrary;
begin
if ASymInstance <> nil then begin
if ASymInstance = self then begin
Result := inherited GetLineAddresses(AFileName, ALine, AResultList);
Result := inherited GetLineAddresses(AFileName, ALine, AResultList, AFindSibling, AMaxSiblingDistance);
end
else begin
Result := ASymInstance.GetLineAddresses(AFileName, ALine, AResultList);
Result := ASymInstance.GetLineAddresses(AFileName, ALine, AResultList, AFindSibling, AMaxSiblingDistance);
FLastLineAddressesFoundFile := ASymInstance.FLastLineAddressesFoundFile;
end;
exit;
end;
Result := inherited GetLineAddresses(AFileName, ALine, AResultList);
Result := inherited GetLineAddresses(AFileName, ALine, AResultList, AFindSibling, AMaxSiblingDistance);
for Lib in FLibMap do begin
if Lib.GetLineAddresses(AFileName, ALine, AResultList) then
if Lib.GetLineAddresses(AFileName, ALine, AResultList, AFindSibling, AMaxSiblingDistance) then
Result := True;
if Lib.FLastLineAddressesFoundFile then
FLastLineAddressesFoundFile := True;
@ -4197,29 +4206,38 @@ procedure TFpInternalBreakpointAtFileLine.UpdateForLibraryLoaded(
ALib: TDbgLibrary);
var
addr: TDBGPtrArray;
m: Integer;
begin
if FSymInstance <> nil then // Can not be the newly created ...
exit;
addr := nil;
Process.GetLineAddresses(FFileName, FLine, addr, ALib);
m := Process.Config.BreakpointSearchMaxLines;
if m > 0 then
Process.GetLineAddresses(FFileName, FLine, addr, ALib, fsNextFuncLazy, m)
else
Process.GetLineAddresses(FFileName, FLine, addr, ALib);
if Process.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);
const AFileName: String; ALine: Cardinal; AnEnabled: Boolean; ASymInstance: TDbgInstance);
var
addr: TDBGPtrArray;
m: Integer;
begin
FFileName := AFileName;
FLine := ALine;
FSymInstance := ASymInstance;
addr := nil;
AProcess.GetLineAddresses(AFileName, ALine, addr, ASymInstance);
m := AProcess.Config.BreakpointSearchMaxLines;
if m > 0 then
AProcess.GetLineAddresses(AFileName, ALine, addr, ASymInstance, fsNextFuncLazy, m)
else
AProcess.GetLineAddresses(AFileName, ALine, addr, ASymInstance);
FFoundFileWithoutLine := AProcess.FLastLineAddressesFoundFile and (Length(addr) = 0);
inherited Create(AProcess, addr, AnEnabled);
end;

View File

@ -492,8 +492,12 @@ type
procedure Init;
procedure SetAddressForLine(ALine: Cardinal; AnAddress: TDBGPtr); inline;
function GetAddressesForLine(ALine: Cardinal; var AResultList: TDBGPtrArray;
NoData: Boolean = False; AFindSibling: TGetLineAddrFindSibling = fsNone;
AFoundLine: PInteger = nil): Boolean; inline;
NoData: Boolean = False;
AFindSibling: TGetLineAddrFindSibling = fsNone;
AFoundLine: PInteger = nil;
AMaxSiblingDistance: integer = 0;
ACU: TDwarfCompilationUnit = nil
): Boolean; inline;
// NoData: only return True/False, but nothing in AResultList
procedure Compress;
end;
@ -737,7 +741,8 @@ 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; AFoundFilename: PBoolean = nil): boolean;
AFindSibling: TGetLineAddrFindSibling = fsNone; AFoundLine: PInteger = nil; AFoundFilename: PBoolean = nil;
AMaxSiblingDistance: integer = 0): 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.
@ -815,7 +820,8 @@ 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; AFoundFilename: PBoolean = nil): Boolean; override;
AFindSibling: TGetLineAddrFindSibling = fsNone; AFoundLine: PInteger = nil; AFoundFilename: PBoolean = nil;
AMaxSiblingDistance: integer = 0): Boolean; override;
function GetLineAddressMap(const AFileName: String): PDWarfLineMap;
procedure LoadCallFrameInstructions;
function LoadCompilationUnits: Integer;
@ -3541,19 +3547,18 @@ begin
Addresses[SectLen] := SectCnt + 1;
end;
function TDWarfLineMap.GetAddressesForLine(ALine: Cardinal;
var AResultList: TDBGPtrArray; NoData: Boolean;
AFindSibling: TGetLineAddrFindSibling; AFoundLine: PInteger): Boolean;
function TDWarfLineMap.GetAddressesForLine(ALine: Cardinal; var AResultList: TDBGPtrArray;
NoData: Boolean; AFindSibling: TGetLineAddrFindSibling; AFoundLine: PInteger;
AMaxSiblingDistance: integer; ACU: TDwarfCompilationUnit): Boolean;
var
idx, offset: TDBGPtr;
idx, offset, Addr1, Addr2: TDBGPtr;
LineOffsets: Array of Byte;
Addresses: Array of TDBGPtr;
o: Byte;
i, j, k, l, CurOffs: Integer;
TmpResList: TDBGPtrArray;
begin
Result := False;
if AFoundLine <> nil then
AFoundLine^ := ALine;
idx := ALine div 256;
offset := ALine mod 256;
if idx >= Length(FLineIndexList) then begin
@ -3579,7 +3584,7 @@ begin
offset := 255;
Continue;
end;
fsNext: begin
fsNext, fsNextFunc, fsNextFuncLazy: begin
inc(idx);
if idx >= Length(FLineIndexList) then
exit;
@ -3604,7 +3609,7 @@ begin
offset := 0; // found line before
end;
end;
fsNext: begin
fsNext, fsNextFunc, fsNextFuncLazy: begin
offset := 0; // found line after/next
end;
end;
@ -3623,6 +3628,33 @@ begin
else continue;
end;
until False;
l := 256 * idx + CurOffs;
if l <> ALine then
case AFindSibling of
fsBefore:
if (AMaxSiblingDistance > 0) and (ALine - l > AMaxSiblingDistance) then exit;
fsNext, fsNextFunc, fsNextFuncLazy: begin
if (AMaxSiblingDistance > 0) and (l - ALine > AMaxSiblingDistance) then exit;
if (AFindSibling = fsNextFunc) or
((AFindSibling = fsNextFuncLazy) and (l - ALine > 1))
then begin
// check same function
if ACU = nil then exit;
if not ACU.GetProcStartEnd(Addresses[i], Addr1, Addr2) then exit;
if GetAddressesForLine(ALine, TmpResList, False, fsBefore) then begin
if (Length(TmpResList) = 0) or (TmpResList[0] < Addr1) or (TmpResList[0] > Addr2) then
exit;
end;
end;
if (AFoundLine <> nil) and (AFoundLine^ <> -1) then begin
if (l > AFoundLine^) then exit; // already have better match
if (l < AFoundLine^) then
AResultList := nil; // found better match
end;
end;
end;
if AFoundLine <> nil then
AFoundLine^ := 256 * idx + CurOffs;
@ -3938,20 +3970,22 @@ begin
end;
end;
function TFpDwarfInfo.GetLineAddresses(const AFileName: String;
ALine: Cardinal; var AResultList: TDBGPtrArray;
AFindSibling: TGetLineAddrFindSibling; AFoundLine: PInteger;
AFoundFilename: PBoolean): Boolean;
function TFpDwarfInfo.GetLineAddresses(const AFileName: String; ALine: Cardinal;
var AResultList: TDBGPtrArray; AFindSibling: TGetLineAddrFindSibling; AFoundLine: PInteger;
AFoundFilename: PBoolean; AMaxSiblingDistance: integer): Boolean;
var
n: Integer;
CU: TDwarfCompilationUnit;
begin
Result := False;
if AFoundLine <> nil then
AFoundLine^ := -1;
for n := 0 to FCompilationUnits.Count - 1 do
begin
CU := TDwarfCompilationUnit(FCompilationUnits[n]);
CU.WaitForScopeScan;
Result := CU.GetLineAddresses(AFileName, ALine, AResultList, AFindSibling, AFoundLine, AFoundFilename) or Result;
Result := CU.GetLineAddresses(AFileName, ALine, AResultList, AFindSibling, AFoundLine, AFoundFilename, AMaxSiblingDistance)
or Result;
end;
end;
@ -5215,10 +5249,9 @@ begin
Result := PDWarfLineMap(FLineNumberMap.Objects[idx]);
end;
function TDwarfCompilationUnit.GetLineAddresses(const AFileName: String;
ALine: Cardinal; var AResultList: TDBGPtrArray;
AFindSibling: TGetLineAddrFindSibling; AFoundLine: PInteger;
AFoundFilename: PBoolean): boolean;
function TDwarfCompilationUnit.GetLineAddresses(const AFileName: String; ALine: Cardinal;
var AResultList: TDBGPtrArray; AFindSibling: TGetLineAddrFindSibling; AFoundLine: PInteger;
AFoundFilename: PBoolean; AMaxSiblingDistance: integer): boolean;
var
Map: PDWarfLineMap;
begin
@ -5229,7 +5262,7 @@ begin
if AFoundFilename <> nil then
AFoundFilename^ := True;
Result := Map^.GetAddressesForLine(ALine, AResultList, False, AFindSibling, AFoundLine);
Result := Map^.GetAddressesForLine(ALine, AResultList, False, AFindSibling, AFoundLine, AMaxSiblingDistance, Self);
end;
function TDwarfCompilationUnit.InitLocateAttributeList(AEntry: Pointer;

View File

@ -679,7 +679,7 @@ type
end;
{ TDbgInfo }
TGetLineAddrFindSibling = (fsNone, fsBefore, fsNext);
TGetLineAddrFindSibling = (fsNone, fsBefore, fsNext, fsNextFunc, fsNextFuncLazy);
TDbgInfo = class(TObject)
private
@ -705,7 +705,8 @@ type
property HasInfo: Boolean read FHasInfo;
function GetLineAddresses(const AFileName: String; ALine: Cardinal; var AResultList: TDBGPtrArray;
AFindSibling: TGetLineAddrFindSibling = fsNone; AFoundLine: PInteger = nil; AFoundFilename: PBoolean = nil): Boolean; virtual;
AFindSibling: TGetLineAddrFindSibling = fsNone; AFoundLine: PInteger = nil; AFoundFilename: PBoolean = nil;
AMaxSiblingDistance: integer = 0): Boolean; virtual;
//property MemManager: TFpDbgMemReaderBase read GetMemManager write SetMemManager;
property TargetInfo: TTargetDescriptor read FTargetInfo write FTargetInfo;
property MemManager: TFpDbgMemManager read FMemManager;
@ -2162,8 +2163,8 @@ begin
end;
function TDbgInfo.GetLineAddresses(const AFileName: String; ALine: Cardinal;
var AResultList: TDBGPtrArray; AFindSibling: TGetLineAddrFindSibling;
AFoundLine: PInteger; AFoundFilename: PBoolean): Boolean;
var AResultList: TDBGPtrArray; AFindSibling: TGetLineAddrFindSibling; AFoundLine: PInteger;
AFoundFilename: PBoolean; AMaxSiblingDistance: integer): Boolean;
begin
Result := False;
end;

View File

@ -4097,6 +4097,8 @@ begin
FDbgController.CurrentProcess.Config.StdErrRedirFile := FileNameStdErr;
FDbgController.CurrentProcess.Config.FileOverwriteStdErr := FileOverwriteStdErr;
FDbgController.CurrentProcess.Config.BreakpointSearchMaxLines := TFpDebugDebuggerProperties(GetProperties).BreakpointSearchMaxLines;
FDbgController.AttachToPid := 0;
if ACommand = dcAttach then begin
FDbgController.AttachToPid := StrToIntDef(String(AParams[0].VAnsiString), 0);

View File

@ -32,7 +32,7 @@ interface
uses
FpDbgUtil, FpdMemoryTools, FpPascalParser, FpErrorMessages,
{$ifdef FORCE_LAZLOGGER_DUMMY} LazLoggerDummy {$else} LazLoggerBase {$endif},
DbgIntfDebuggerBase, sysutils, Classes, syncobjs, Forms, FpDebugStringConstants;
DbgIntfDebuggerBase, sysutils, Classes, Math, syncobjs, Forms, FpDebugStringConstants;
type
@ -106,6 +106,7 @@ type
TFpDebugDebuggerProperties = class(TCommonDebuggerProperties)
private
FAutoDeref: Boolean;
FBreakpointSearchMaxLines: integer;
FConsoleTty: string;
{$ifdef windows}
FForceNewConsole: boolean;
@ -114,6 +115,7 @@ type
FIntrinsicPrefix: TFpIntrinsicPrefix;
FMemLimits: TFpDebugDebuggerPropertiesMemLimits;
FNextOnlyStopOnStartLine: boolean;
procedure SetBreakpointSearchMaxLines(AValue: integer);
procedure SetMemLimits(AValue: TFpDebugDebuggerPropertiesMemLimits);
public
constructor Create; override;
@ -133,6 +135,7 @@ type
property HandleDebugBreakInstruction: TFpInt3DebugBreakOptions read FHandleDebugBreakInstruction write FHandleDebugBreakInstruction default [dboIgnoreAll];
property IntrinsicPrefix: TFpIntrinsicPrefix read FIntrinsicPrefix write FIntrinsicPrefix default ipColon;
property AutoDeref: Boolean read FAutoDeref write FAutoDeref default False;
property BreakpointSearchMaxLines: integer read FBreakpointSearchMaxLines write SetBreakpointSearchMaxLines default 3;
property InternalExceptionBreakPoints;
end;
@ -401,6 +404,13 @@ begin
FMemLimits.Assign(AValue);
end;
procedure TFpDebugDebuggerProperties.SetBreakpointSearchMaxLines(AValue: integer);
begin
AValue := Max(0, Min(25, AValue));
if FBreakpointSearchMaxLines = AValue then Exit;
FBreakpointSearchMaxLines := AValue;
end;
constructor TFpDebugDebuggerProperties.Create;
begin
inherited Create;
@ -412,6 +422,7 @@ begin
FHandleDebugBreakInstruction := [dboIgnoreAll];
FIntrinsicPrefix := ipColon;
FAutoDeref := False;
FBreakpointSearchMaxLines := 3;
end;
destructor TFpDebugDebuggerProperties.Destroy;
@ -433,6 +444,7 @@ begin
FHandleDebugBreakInstruction:=TFpDebugDebuggerProperties(Source).FHandleDebugBreakInstruction;
FIntrinsicPrefix:=TFpDebugDebuggerProperties(Source).FIntrinsicPrefix;
FAutoDeref:=TFpDebugDebuggerProperties(Source).FAutoDeref;
FBreakpointSearchMaxLines:=TFpDebugDebuggerProperties(Source).FBreakpointSearchMaxLines;
end;
end;

View File

@ -29,11 +29,13 @@ begin
x := 1;
end;
Procedure StepOverEnd(a: integer);
Procedure StepOverEnd(a: integer); // USED FOR line lookup // do not add lines
var
b: integer;
begin
begin // TEST_BREAKPOINT=StepOverBegin
b := a;
// 3 empty lines in function (for line lookup test)
//
// end returns to the same line
if a < 1 then StepOverEnd(a+1); end; // TEST_BREAKPOINT=StepOverEnd

View File

@ -7,8 +7,8 @@ interface
uses
Classes, SysUtils, math, TestDbgControl, TestDbgTestSuites,
TTestWatchUtilities, TestCommonSources, TestDbgConfig, TTestDebuggerClasses,
LazDebuggerIntf, LazDebuggerIntfBaseTypes, DbgIntfDebuggerBase,
DbgIntfBaseTypes, LazLoggerBase, Forms;
LazDebuggerIntf, LazDebuggerIntfBaseTypes, FpDebugDebugger, DbgIntfDebuggerBase,
DbgIntfBaseTypes, LazLoggerBase, FPDbgController, FpDbgInfo, Forms;
type
@ -57,6 +57,7 @@ type
procedure TestLocation(ATestName, ABrkName: String; ABreakHitCount: Integer = 1);
procedure TestHitCnt(ATestName, ABrkName: String; ABreakHitCount: Integer);
published
procedure TestGetAddressForLine;
(* Ensure the debugger can correctly run/step after hidding a breakpoit
- the original instruction is executed
- the breakpoint can be hit again
@ -96,7 +97,7 @@ type
implementation
var
ControlTest, ControlTestBreak, ControlTestThreadNoSkip,
ControlTest, ControlTestGetAddressForLine, ControlTestBreak, ControlTestThreadNoSkip,
ControlTestThreadMove1, ControlTestThreadMove2, ControlTestThreadHit,
ControlTestThreadIgnoreOther: Pointer;
@ -118,6 +119,153 @@ begin
TestEquals(ATestName+' '+ABrkName+' HitCnt', Debugger.BreakPointByName(ABrkName).HitCount, ABreakHitCount);
end;
procedure TTestBreakPoint.TestGetAddressForLine;
var
ExeName: String;
FpDbg: TFpDebugDebugger;
Ctrl: TDbgController;
LNum1, LNum2: LongInt;
fs: TGetLineAddrFindSibling;
procedure TestLineExist(ALine: Cardinal; AFindSibling: TGetLineAddrFindSibling;
AMaxAfter: integer = 0; ExpFoundLine: Integer = -1);
var
AName: String;
ResLst: TDBGPtrArray;
FndLine: Integer;
FndFile, r: Boolean;
begin
AName := 'Found '+IntToStr(ALine);
if ExpFoundLine = -1 then ExpFoundLine := ALine;
r := Ctrl.CurrentProcess.DbgInfo.GetLineAddresses('StepOverPrg.pas',
ALine, ResLst, AFindSibling, @FndLine, @FndFile, AMaxAfter);
AssertTrue(AName, r);
AssertTrue(AName, FndFile);
AssertEquals(AName, ExpFoundLine, FndLine);
AssertTrue(AName, Length(ResLst) > 0);
AssertTrue(AName, ResLst[0] <> 0);
end;
procedure TestLineNotFound(ALine: Cardinal; AFindSibling: TGetLineAddrFindSibling;
AMaxAfter: integer = 0);
var
AName: String;
ResLst: TDBGPtrArray;
FndLine: Integer;
FndFile, r: Boolean;
begin
AName := 'Found '+IntToStr(ALine);
r := Ctrl.CurrentProcess.DbgInfo.GetLineAddresses('StepOverPrg.pas',
ALine, ResLst, AFindSibling, @FndLine, @FndFile, AMaxAfter);
AssertFalse(AName, r);
//AssertTrue(AName, FndFile);
end;
begin
if SkipTest then exit;
if not TestControlCanTest(ControlTestGetAddressForLine) then exit;
Src := GetCommonSourceFor(AppDir + 'StepOverPrg.pas');
TestCompile(Src, ExeName);
TestTrue('Start debugger', Debugger.StartDebugger(AppDir, ExeName));
dbg := Debugger.LazDebugger;
try
Debugger.SetBreakPoint(Src, 'BrkStart');
Debugger.RunToNextPause(dcRun);
FpDbg := dbg as TFpDebugDebugger;
Ctrl := FpDbg.DbgController;
LNum1 := Src.BreakPoints['StepOverBegin'];
LNum2 := Src.BreakPoints['StepOverEnd'];
for fs := low(TGetLineAddrFindSibling) to high(TGetLineAddrFindSibling) do begin
TestLineExist(LNum1, fs, 0, LNum1);
TestLineExist(LNum1+1, fs, 0, LNum1+1);
TestLineExist(LNum2, fs, 0, LNum2);
end;
// Before begin
TestLineNotFound(LNum1-1, fsNone);
TestLineNotFound(LNum1-1, fsNone, 9); // maxafter ignored
TestLineNotFound(LNum1-2, fsNone);
TestLineNotFound(LNum1-3, fsNext, 1);
TestLineNotFound(LNum1-2, fsNext, 1);
TestLineExist (LNum1-1, fsNext, 1, LNum1);
TestLineNotFound(LNum1-3, fsNext, 2);
TestLineExist (LNum1-2, fsNext, 2, LNum1);
TestLineExist (LNum1-1, fsNext, 2, LNum1);
TestLineExist (LNum1-3, fsNext, 0, LNum1);
TestLineExist (LNum1-2, fsNext, 0, LNum1);
TestLineExist (LNum1-1, fsNext, 0, LNum1);
TestLineNotFound(LNum1-2, fsNextFunc, 1);
TestLineNotFound(LNum1-2, fsNextFunc, 2);
TestLineNotFound(LNum1-2, fsNextFunc, 0);
TestLineNotFound(LNum1-1, fsNextFunc, 1);
TestLineNotFound(LNum1-1, fsNextFunc, 2);
TestLineNotFound(LNum1-1, fsNextFunc, 0);
TestLineNotFound(LNum1-2, fsNextFuncLazy, 1);
TestLineNotFound(LNum1-2, fsNextFuncLazy, 2);
TestLineNotFound(LNum1-2, fsNextFuncLazy, 0);
TestLineExist (LNum1-1, fsNextFuncLazy, 1, LNum1);
TestLineExist (LNum1-1, fsNextFuncLazy, 2, LNum1);
TestLineExist (LNum1-1, fsNextFuncLazy, 0, LNum1);
// mid function
TestLineNotFound(LNum2-1, fsNone);
TestLineNotFound(LNum2-1, fsNone, 9); // maxafter ignored
TestLineNotFound(LNum2-2, fsNone);
TestLineNotFound(LNum2-3, fsNext, 1);
TestLineNotFound(LNum2-2, fsNext, 1);
TestLineExist (LNum2-1, fsNext, 1, LNum2);
TestLineNotFound(LNum2-3, fsNext, 2);
TestLineExist (LNum2-2, fsNext, 2, LNum2);
TestLineExist (LNum2-1, fsNext, 2, LNum2);
TestLineExist (LNum2-3, fsNext, 0, LNum2);
TestLineExist (LNum2-2, fsNext, 0, LNum2);
TestLineExist (LNum2-1, fsNext, 0, LNum2);
TestLineNotFound(LNum2-2, fsNextFunc, 1);
TestLineExist (LNum2-2, fsNextFunc, 2, LNum2);
TestLineExist (LNum2-2, fsNextFunc, 0, LNum2);
TestLineExist (LNum2-1, fsNextFunc, 1, LNum2);
TestLineExist (LNum2-1, fsNextFunc, 2, LNum2);
TestLineExist (LNum2-1, fsNextFunc, 0, LNum2);
TestLineNotFound(LNum2-3, fsNextFuncLazy, 1);
TestLineNotFound(LNum2-3, fsNextFuncLazy, 2);
TestLineExist (LNum2-3, fsNextFuncLazy, 3, LNum2);
TestLineExist (LNum2-3, fsNextFuncLazy, 4, LNum2);
TestLineExist (LNum2-3, fsNextFuncLazy, 0, LNum2);
TestLineNotFound(LNum2-2, fsNextFuncLazy, 1);
TestLineExist (LNum2-2, fsNextFuncLazy, 2, LNum2);
TestLineExist (LNum2-2, fsNextFuncLazy, 0, LNum2);
TestLineExist (LNum2-1, fsNextFuncLazy, 1, LNum2);
TestLineExist (LNum2-1, fsNextFuncLazy, 2, LNum2);
TestLineExist (LNum2-1, fsNextFuncLazy, 0, LNum2);
dbg.Stop;
finally
Debugger.ClearDebuggerMonitors;
Debugger.FreeDebugger;
AssertTestErrors;
end;
end;
procedure TTestBreakPoint.TestBreakPoints;
var
ExeName: String;
@ -988,6 +1136,7 @@ initialization
RegisterDbgTest(TTestBreakPoint);
ControlTest := TestControlRegisterTest('TTestBreak');
ControlTestGetAddressForLine := TestControlRegisterTest('TestGetAddressForLine', ControlTest);
ControlTestBreak := TestControlRegisterTest('TTestBreakPoint', ControlTest);
ControlTestThreadNoSkip := TestControlRegisterTest('TTestBreakThreadNoSkip', ControlTest);
ControlTestThreadMove1 := TestControlRegisterTest('TTestBreakThreadMove1', ControlTest);