Debugger: GDB improve launching app by stepping (F8). break at main

git-svn-id: trunk@47574 -
This commit is contained in:
martin 2015-01-31 13:55:47 +00:00
parent 2315bd655d
commit e99fe3257d
3 changed files with 230 additions and 75 deletions

View File

@ -569,13 +569,15 @@ type
TGDBMIInternalBreakPoint = class TGDBMIInternalBreakPoint = class
private type private type
TClearOpt = (coClearIfSet, coKeepIfSet); TClearOpt = (coClearIfSet, coKeepIfSet);
TInternalBreakLocation = (iblNamed, iblAddrOfNamed, iblCustomAddr, iblAddOffset); TBlockOpt = (boNone, boBlock, boUnblock);
TInternalBreakLocation = (iblNamed, iblAddrOfNamed, iblCustomAddr,
iblAddOffset, iblFileLine);
TInternalBreakData = record TInternalBreakData = record
BreakGdbId: Integer; BreakGdbId: Integer;
BreakAddr: TDBGPtr; BreakAddr: TDBGPtr;
BreakFunction: String; BreakFunction: String;
//BreakFile: String; BreakFile: String;
//BreakLine: Integer; BreakLine: String;
end; end;
private private
FBreaks: array[TInternalBreakLocation] of TInternalBreakData; FBreaks: array[TInternalBreakLocation] of TInternalBreakData;
@ -585,23 +587,35 @@ type
FName: string; // The (function) name of the location "main" or "FPC_RAISE" FName: string; // The (function) name of the location "main" or "FPC_RAISE"
FMainAddrFound: TDBGPtr; // The address found for this named location FMainAddrFound: TDBGPtr; // The address found for this named location
FUseForceFlag: Boolean; FUseForceFlag: Boolean;
procedure Clear(ACmd: TGDBMIDebuggerCommand; ALoc: TInternalBreakLocation;
ABlock: Boolean = False);
function BreakSet(ACmd: TGDBMIDebuggerCommand; ABreakLoc: String; function BreakSet(ACmd: TGDBMIDebuggerCommand; ABreakLoc: String;
ALoc: TInternalBreakLocation; ALoc: TInternalBreakLocation;
AClearIfSet: TClearOpt): Boolean; AClearIfSet: TClearOpt): Boolean;
function GetBreakAddr(ALoc: TInternalBreakLocation): TDBGPtr;
function GetBreakFile(ALoc: TInternalBreakLocation): String;
function GetBreakId(ALoc: TInternalBreakLocation): Integer;
function GetBreakLine(ALoc: TInternalBreakLocation): String;
function GetInfoAddr(ACmd: TGDBMIDebuggerCommand): TDBGPtr; function GetInfoAddr(ACmd: TGDBMIDebuggerCommand): TDBGPtr;
function HasBreakAtAddr(AnAddr: TDBGPtr): Boolean; function HasBreakAtAddr(AnAddr: TDBGPtr): Boolean;
function HasBreakWithId(AnId: Integer): Boolean; function HasBreakWithId(AnId: Integer): Boolean;
procedure InternalSetAddr(ACmd: TGDBMIDebuggerCommand; ALoc: TInternalBreakLocation; procedure InternalSetAddr(ACmd: TGDBMIDebuggerCommand; ALoc: TInternalBreakLocation;
AnAddr: TDBGPtr); AnAddr: TDBGPtr);
protected
procedure Clear(ACmd: TGDBMIDebuggerCommand; ALoc: TInternalBreakLocation;
ABlock: TBlockOpt = boNone);
property BreakId[ALoc: TInternalBreakLocation]: Integer read GetBreakId;
property BreakAddr[ALoc: TInternalBreakLocation]: TDBGPtr read GetBreakAddr;
property BreakFile[ALoc: TInternalBreakLocation]: String read GetBreakFile;
property BreakLine[ALoc: TInternalBreakLocation]: String read GetBreakLine;
public public
constructor Create(AName: string); constructor Create(AName: string);
procedure SetBoth(ACmd: TGDBMIDebuggerCommand); procedure SetBoth(ACmd: TGDBMIDebuggerCommand);
procedure SetByName(ACmd: TGDBMIDebuggerCommand); procedure SetByName(ACmd: TGDBMIDebuggerCommand);
procedure SetByAddr(ACmd: TGDBMIDebuggerCommand; SetNamedOnFail: Boolean = False); procedure SetByAddr(ACmd: TGDBMIDebuggerCommand; SetNamedOnFail: Boolean = False);
procedure SetAtCustomAddr(ACmd: TGDBMIDebuggerCommand; AnAddr: TDBGPtr); procedure SetAtCustomAddr(ACmd: TGDBMIDebuggerCommand; AnAddr: TDBGPtr);
procedure SetAtLineOffs(ACmd: TGDBMIDebuggerCommand; AnOffset: integer); procedure SetAtLineOffs(ACmd: TGDBMIDebuggerCommand; AnOffset: integer);
procedure SetAtFileLine(ACmd: TGDBMIDebuggerCommand; AFile, ALine: String);
procedure Clear(ACmd: TGDBMIDebuggerCommand); procedure Clear(ACmd: TGDBMIDebuggerCommand);
function ClearId(ACmd: TGDBMIDebuggerCommand; AnId: Integer): Boolean; function ClearId(ACmd: TGDBMIDebuggerCommand; AnId: Integer): Boolean;
// a blocked id can not be set, until after the next clear (clear all) // a blocked id can not be set, until after the next clear (clear all)
@ -614,7 +628,6 @@ type
procedure Enable(ACmd: TGDBMIDebuggerCommand); procedure Enable(ACmd: TGDBMIDebuggerCommand);
procedure Disable(ACmd: TGDBMIDebuggerCommand); procedure Disable(ACmd: TGDBMIDebuggerCommand);
property MainAddrFound: TDBGPtr read FMainAddrFound; property MainAddrFound: TDBGPtr read FMainAddrFound;
// property LineOffsFunction: string read FBreaks[iblAddOffset].BreakFunction;
property UseForceFlag: Boolean read FUseForceFlag write FUseForceFlag; property UseForceFlag: Boolean read FUseForceFlag write FUseForceFlag;
property Enabled: Boolean read FEnabled; property Enabled: Boolean read FEnabled;
end; end;
@ -4808,25 +4821,26 @@ function TGDBMIDebuggerCommandStartDebugging.DoExecute: Boolean;
end; end;
{$ENDIF} {$ENDIF}
var
FndOffsFile, FndOffsLine: String;
StoppedFile, StoppedLine: String;
StoppedAddr: TDBGPtr;
StoppedAtEntryPoint: Boolean;
const
MIN_RELOC_ADDRESS = $4000;
procedure RunToMain(EntryPoint: String); procedure RunToMain(EntryPoint: String);
type type
TRunToMainType = (mtMain, mtMainAddr, mtEntry, mtAddZero); TRunToMainType = (mtMain, mtMainAddr, mtEntry, mtAddZero);
TRunToMainState = (
msNone, // no more ways to try setting the breakpoint
msDefault, msMainAddr, msMain, msAddZero, msEntryPoint,
msTryNameZero, msTryZero, msTryEntryName, msTryName
);
var var
RunToMainState: TRunToMainState;
EntryPointNum: TDBGPtr; EntryPointNum: TDBGPtr;
function SetMainBrk: boolean; function SetMainBrk: boolean;
procedure MaybeAddMainBrk(AType: TRunToMainType; AnSkipIfCntGreater: Integer; procedure MaybeAddMainBrk(AType: TRunToMainType; AnSkipIfCntGreater: Integer;
ACheckEntryPoinReloc: Boolean = false); ACheckEntryPoinReloc: Boolean = false);
begin begin
//RunToMainState := ANextState;
// Check if the Entrypoint looks promising (if it looks like it matches the relocated address) // Check if the Entrypoint looks promising (if it looks like it matches the relocated address)
if ACheckEntryPoinReloc and not(EntryPointNum > $4000) then if ACheckEntryPoinReloc and not(EntryPointNum > MIN_RELOC_ADDRESS) then
exit; exit;
// Check amount of already set breakpoints // Check amount of already set breakpoints
if (AnSkipIfCntGreater >= 0) and (FTheDebugger.FMainAddrBreak.BreakSetCount > AnSkipIfCntGreater) then if (AnSkipIfCntGreater >= 0) and (FTheDebugger.FMainAddrBreak.BreakSetCount > AnSkipIfCntGreater) then
@ -4837,6 +4851,12 @@ function TGDBMIDebuggerCommandStartDebugging.DoExecute: Boolean;
mtEntry: FTheDebugger.FMainAddrBreak.SetAtCustomAddr(Self, StrToQWordDef(EntryPoint, 0)); mtEntry: FTheDebugger.FMainAddrBreak.SetAtCustomAddr(Self, StrToQWordDef(EntryPoint, 0));
mtAddZero: FTheDebugger.FMainAddrBreak.SetAtLineOffs(Self, 0); mtAddZero: FTheDebugger.FMainAddrBreak.SetAtLineOffs(Self, 0);
end; end;
if (AType = mtAddZero) and (FndOffsFile = '') then begin
FndOffsLine := FTheDebugger.FMainAddrBreak.BreakLine[iblAddOffset];
if (FndOffsLine <> '') then
FndOffsFile := FTheDebugger.FMainAddrBreak.BreakFile[iblAddOffset];
end;
end; end;
var var
bcnt: Integer; bcnt: Integer;
@ -4908,6 +4928,36 @@ function TGDBMIDebuggerCommandStartDebugging.DoExecute: Boolean;
Result := StrToIntDef(s, 0); Result := StrToIntDef(s, 0);
end; end;
function ParseStopped(AParam: String): Integer;
var
List: TGDBMINameValueList;
Reason: String;
begin
Result := -1; // no id found
List := nil;
try
List := TGDBMINameValueList.Create(AParam);
Reason := List.Values['reason'];
if (Reason = 'exited-normally') or (Reason = 'exited') or
(Reason = 'exited-signalled')
then
Result := -2;
// if Reason = 'signal-received' // Pause ?
if Reason = 'breakpoint-hit' then begin
Result := StrToIntDef(List.Values['bkptno'], -1);
StoppedAtEntryPoint := Result = FTheDebugger.FMainAddrBreak.BreakId[iblCustomAddr];
List.SetPath('frame');
StoppedAddr := StrToInt64Def(List.Values['addr'], -1);
StoppedFile := List.Values['fullname'];
if StoppedFile = '' then
StoppedFile := List.Values['file'];
StoppedLine := List.Values['line'];
end;
except
end;
List.Free;
end;
var var
R: TGDBMIExecResult; R: TGDBMIExecResult;
Cmd, s, s2, rval: String; Cmd, s, s2, rval: String;
@ -4918,15 +4968,6 @@ function TGDBMIDebuggerCommandStartDebugging.DoExecute: Boolean;
EntryPointNum := StrToQWordDef(EntryPoint, 0); EntryPointNum := StrToQWordDef(EntryPoint, 0);
TargetInfo^.TargetPID := 0; TargetInfo^.TargetPID := 0;
FDidKillNow := False; FDidKillNow := False;
RunToMainState := msEntryPoint;
case DebuggerProperties.InternalStartBreak of
gdsbDefault: RunToMainState := msDefault;
gdsbEntry: RunToMainState := msEntryPoint;
gdsbMainAddr: RunToMainState := msMainAddr;
gdsbMain: RunToMainState := msMain;
gdsbAddZero: RunToMainState := msAddZero;
else assert(false, 'RunToMain missing init');
end;
// TODO: async // TODO: async
Cmd := GdbRunCommand;// '-exec-run'; Cmd := GdbRunCommand;// '-exec-run';
@ -4973,7 +5014,8 @@ function TGDBMIDebuggerCommandStartDebugging.DoExecute: Boolean;
ProcessRunning(s2, R); ProcessRunning(s2, R);
FCanKillNow := False; FCanKillNow := False;
FTheDebugger.FCurrentCmdIsAsync := False; FTheDebugger.FCurrentCmdIsAsync := False;
if (pos('reason="exited-normally"', s2) > 0) or FDidKillNow then begin j := ParseStopped(s2);
if (j = -2) or (pos('reason="exited-normally"', s2) > 0) or FDidKillNow then begin
// app has already run // app has already run
R.State := dsStop; R.State := dsStop;
break; break;
@ -5137,6 +5179,7 @@ var
FileType, EntryPoint: String; FileType, EntryPoint: String;
List: TGDBMINameValueList; List: TGDBMINameValueList;
CanContinue: Boolean; CanContinue: Boolean;
s, s2: String;
begin begin
Result := True; Result := True;
FSuccess := False; FSuccess := False;
@ -5260,12 +5303,42 @@ begin
end end
else CanContinue := True; else CanContinue := True;
if StoppedAtEntryPoint and CanContinue and (FContinueCommand = nil) then begin
// try to step to pascal code
if (FndOffsFile <> '') and (FndOffsLine <> '') and
( (FndOffsFile <> StoppedFile) or (FndOffsLine <> StoppedLine) )
then begin
FTheDebugger.FMainAddrBreak.SetAtFileLine(Self, FndOffsFile, FndOffsLine);
if (FTheDebugger.FMainAddrBreak.BreakAddr[iblFileLine] < MIN_RELOC_ADDRESS) or
(FTheDebugger.FMainAddrBreak.BreakAddr[iblFileLine] = StoppedAddr)
then
FTheDebugger.FMainAddrBreak.Clear(Self, iblFileLine);
end;
FTheDebugger.FMainAddrBreak.SetByName(Self);
if (FTheDebugger.FMainAddrBreak.BreakAddr[iblNamed] < MIN_RELOC_ADDRESS) or
(FTheDebugger.FMainAddrBreak.BreakAddr[iblNamed] = StoppedAddr) or
(FTheDebugger.FMainAddrBreak.BreakFile[iblNamed] = '') or
(FTheDebugger.FMainAddrBreak.BreakLine[iblNamed] = '') or
( (FTheDebugger.FMainAddrBreak.BreakFile[iblNamed] = StoppedFile) and
(FTheDebugger.FMainAddrBreak.BreakFile[iblNamed] = StoppedLine) )
then
FTheDebugger.FMainAddrBreak.Clear(Self, iblNamed);
if FTheDebugger.FMainAddrBreak.IsBreakSet then begin
FContinueCommand := TGDBMIDebuggerCommandExecute.Create(FTheDebugger, ectContinue);
end;
end;
if CanContinue and (FContinueCommand <> nil) if CanContinue and (FContinueCommand <> nil)
then begin then begin
FTheDebugger.QueueCommand(FContinueCommand); FTheDebugger.QueueCommand(FContinueCommand);
FContinueCommand := nil; FContinueCommand := nil;
end else end
else begin
SetDebuggerState(dsPause); SetDebuggerState(dsPause);
end;
if DebuggerState = dsPause if DebuggerState = dsPause
then ProcessFrame; then ProcessFrame;
@ -6041,6 +6114,14 @@ begin
Exit; Exit;
end; end;
if FTheDebugger.FMainAddrBreak.MatchId(BreakID)
then begin
FTheDebugger.FMainAddrBreak.Clear(Self); // done with launch
SetDebuggerState(dsPause);
ProcessFrame(FTheDebugger.FCurrentLocation );
Exit;
end;
if (FStepBreakPoint > 0) and (BreakID = FStepBreakPoint) if (FStepBreakPoint > 0) and (BreakID = FStepBreakPoint)
then begin then begin
SetDebuggerState(dsPause); SetDebuggerState(dsPause);
@ -6131,41 +6212,29 @@ const
WatchErrMsg = 'not insert hardware watchpoint '; WatchErrMsg = 'not insert hardware watchpoint ';
function HandleBreakPointError(var ARes: TGDBMIExecResult; AError: String): Boolean; function HandleBreakPointError(var ARes: TGDBMIExecResult; AError: String): Boolean;
function ErrPos(s: string): integer;
var
i: SizeInt;
begin
Result := pos(BreaKErrMsg, s);
if Result > 0
then Result := Result + length(BreaKErrMsg);
i := pos(WatchErrMsg, s);
if (i > 0) and ( (i < Result) or (Result < 1) )
then Result := i + length(WatchErrMsg);
end;
var var
c, i: Integer; c, i: Integer;
bp: Array of Integer; bp: Array of Integer;
s, s2: string; s, s2: string;
b: TGDBMIBreakPoint; b: TGDBMIBreakPoint;
begin begin
// TODO while ParseBreakInsertError()
Result := False; Result := False;
s := AError; s := AError;
c := 0; c := 0;
i := ErrPos(s); while ParseBreakInsertError(s, i) do begin
while i > 0 do begin if FTheDebugger.FMainAddrBreak.ClearId(Self, i) then begin
s := copy(s, i, length(s)); Result := True;
i := 1; ARes.State := dsRun;
while (i <= length(s)) and (s[i] in ['0'..'9']) do inc(i); continue;
if i > 1 then begin
SetLength(bp, c+1);
bp[c] := StrToIntDef(copy(s, 1, i-1), -1);
if bp[c] >= 0 then inc(c);
end; end;
i := ErrPos(s); SetLength(bp, c+1);
bp[c] := i;
if bp[c] >= 0 then inc(c);
end; end;
if Result and not FTheDebugger.FMainAddrBreak.IsBreakSet then
ARes.State := dsPause; // no break left
if c = 0 then exit; if c = 0 then exit;
Result := True; Result := True;
@ -6582,11 +6651,13 @@ begin
if FDidKillNow or CheckResultForError(R) if FDidKillNow or CheckResultForError(R)
then exit; then exit;
if HandleBreakPointError(FResult, RunWarnings + LineEnding + FLogWarnings) then begin
if FResult.State = dsStop then exit;
end;
ContinueExecution := False; ContinueExecution := False;
if HandleBreakPointError(FResult, RunWarnings + LineEnding + FLogWarnings) then begin
if FResult.State = dsStop then exit;
ContinueExecution := FResult.State = dsRun; // no user interaction => FMainAddrBreak
end;
ContinueStep := False; ContinueStep := False;
if StoppedParams <> '' if StoppedParams <> ''
then ContinueExecution := ProcessStopped(StoppedParams, FTheDebugger.PauseWaitState = pwsInternal); then ContinueExecution := ProcessStopped(StoppedParams, FTheDebugger.PauseWaitState = pwsInternal);
@ -6617,6 +6688,7 @@ begin
FStepBreakPoint := -1; FStepBreakPoint := -1;
FTheDebugger.FPopExceptStack.Disable(Self); FTheDebugger.FPopExceptStack.Disable(Self);
FTheDebugger.FCatchesBreak.Disable(Self); FTheDebugger.FCatchesBreak.Disable(Self);
FTheDebugger.FMainAddrBreak.Clear(Self);
end; end;
if (not ContinueExecution) and (DebuggerState = dsRun) and if (not ContinueExecution) and (DebuggerState = dsRun) and
@ -11427,19 +11499,26 @@ end;
{ TGDBMIInternalBreakPoint } { TGDBMIInternalBreakPoint }
procedure TGDBMIInternalBreakPoint.Clear(ACmd: TGDBMIDebuggerCommand; procedure TGDBMIInternalBreakPoint.Clear(ACmd: TGDBMIDebuggerCommand;
ALoc: TInternalBreakLocation; ABlock: Boolean); ALoc: TInternalBreakLocation; ABlock: TBlockOpt);
begin begin
if FBreaks[ALoc].BreakGdbId < 0 then exit; if (FBreaks[ALoc].BreakGdbId = -2) and (ABlock <> boUnblock) then exit;
ACmd.ExecuteCommand('-break-delete %d', [FBreaks[ALoc].BreakGdbId], [cfCheckError]); if (FBreaks[ALoc].BreakGdbId = -1) then exit;
if ABlock then
if (FBreaks[ALoc].BreakGdbId >= 0) then
ACmd.ExecuteCommand('-break-delete %d', [FBreaks[ALoc].BreakGdbId], [cfCheckError]);
if ABlock = boBlock then
FBreaks[ALoc].BreakGdbId := -2 FBreaks[ALoc].BreakGdbId := -2
else else
FBreaks[ALoc].BreakGdbId := -1; FBreaks[ALoc].BreakGdbId := -1;
FBreaks[ALoc].BreakAddr := 0; FBreaks[ALoc].BreakAddr := 0;
FBreaks[ALoc].BreakFunction := '';
FBreaks[ALoc].BreakFile := '';
FBreaks[ALoc].BreakLine := '';
FEnabled := FEnabled and IsBreakSet; FEnabled := FEnabled and IsBreakSet;
if ALoc = iblAddrOfNamed then FMainAddrFound := 0; if ALoc = iblAddrOfNamed then FMainAddrFound := 0;
if ALoc = iblAddOffset then FBreaks[iblAddOffset].BreakFunction := '';
end; end;
function TGDBMIInternalBreakPoint.BreakSet(ACmd: TGDBMIDebuggerCommand; ABreakLoc: String; function TGDBMIInternalBreakPoint.BreakSet(ACmd: TGDBMIDebuggerCommand; ABreakLoc: String;
@ -11476,9 +11555,33 @@ begin
FBreaks[ALoc].BreakGdbId := StrToIntDef(ResultList.Values['number'], -1); FBreaks[ALoc].BreakGdbId := StrToIntDef(ResultList.Values['number'], -1);
FBreaks[ALoc].BreakAddr := StrToQWordDef(ResultList.Values['addr'], 0); FBreaks[ALoc].BreakAddr := StrToQWordDef(ResultList.Values['addr'], 0);
FBreaks[ALoc].BreakFunction := ResultList.Values['func']; FBreaks[ALoc].BreakFunction := ResultList.Values['func'];
FBreaks[ALoc].BreakFile := ResultList.Values['fullname'];
if FBreaks[ALoc].BreakFile = '' then
FBreaks[ALoc].BreakFile := ResultList.Values['file'];
FBreaks[ALoc].BreakLine := ResultList.Values['line'];
ResultList.Free; ResultList.Free;
end; end;
function TGDBMIInternalBreakPoint.GetBreakAddr(ALoc: TInternalBreakLocation): TDBGPtr;
begin
Result := FBreaks[ALoc].BreakAddr;
end;
function TGDBMIInternalBreakPoint.GetBreakFile(ALoc: TInternalBreakLocation): String;
begin
Result := FBreaks[ALoc].BreakFile;
end;
function TGDBMIInternalBreakPoint.GetBreakId(ALoc: TInternalBreakLocation): Integer;
begin
Result := FBreaks[ALoc].BreakGdbId;
end;
function TGDBMIInternalBreakPoint.GetBreakLine(ALoc: TInternalBreakLocation): String;
begin
Result := FBreaks[ALoc].BreakLine;
end;
function TGDBMIInternalBreakPoint.GetInfoAddr(ACmd: TGDBMIDebuggerCommand): TDBGPtr; function TGDBMIInternalBreakPoint.GetInfoAddr(ACmd: TGDBMIDebuggerCommand): TDBGPtr;
var var
R: TGDBMIExecResult; R: TGDBMIExecResult;
@ -11591,15 +11694,20 @@ begin
BreakSet(ACmd, Format('+%d', [AnOffset]), iblAddOffset, coClearIfSet); BreakSet(ACmd, Format('+%d', [AnOffset]), iblAddOffset, coClearIfSet);
end; end;
procedure TGDBMIInternalBreakPoint.SetAtFileLine(ACmd: TGDBMIDebuggerCommand; AFile,
ALine: String);
begin
AFile := StringReplace(AFile, '\', '/', [rfReplaceAll]);
BreakSet(ACmd, Format(' "\"%s\":%s"', [AFile, ALine]), iblFileLine, coKeepIfSet);
end;
procedure TGDBMIInternalBreakPoint.Clear(ACmd: TGDBMIDebuggerCommand); procedure TGDBMIInternalBreakPoint.Clear(ACmd: TGDBMIDebuggerCommand);
var var
i: TInternalBreakLocation; i: TInternalBreakLocation;
begin begin
if ACmd.DebuggerState = dsError then Exit; if ACmd.DebuggerState = dsError then Exit;
for i := low(TInternalBreakLocation) to high(TInternalBreakLocation) do begin for i := low(TInternalBreakLocation) to high(TInternalBreakLocation) do
Clear(ACmd, i); Clear(ACmd, i, boUnblock);
FBreaks[i].BreakGdbId := -1; // unblock
end;
FEnabled := False; FEnabled := False;
end; end;
@ -11624,7 +11732,7 @@ begin
Result := False; Result := False;
for i := low(TInternalBreakLocation) to high(TInternalBreakLocation) do for i := low(TInternalBreakLocation) to high(TInternalBreakLocation) do
if (AnId = FBreaks[i].BreakGdbId) then begin if (AnId = FBreaks[i].BreakGdbId) then begin
Clear(ACmd, i, True); Clear(ACmd, i, boBlock);
Result := True; Result := True;
break; break;
end; end;

View File

@ -22,7 +22,7 @@ begin
end; end;
begin begin
//nodrv := StripFileDrive(s); {$IFDEF CALL_ALL} StripFileDrive('11'); {$ENDIF}
WriteLnIpc('drive="%s", dir="%s", path="%s", nodrv=%s.'); WriteLnIpc('drive="%s", dir="%s", path="%s", nodrv=%s.');
CalcNextUpdTime(1); CalcNextUpdTime(1);
WriteLnIpc('Now = '); WriteLnIpc('Now = ');

View File

@ -35,12 +35,14 @@ type
// Due to a linker error breakpoints can point to invalid addresses // Due to a linker error breakpoints can point to invalid addresses
procedure TestStartMethod; procedure TestStartMethod;
procedure TestStartMethodBadLinker; // not called prog in front of MAIN // causes bad linker with dwarf procedure TestStartMethodBadLinker; // not called prog in front of MAIN // causes bad linker with dwarf
procedure TestStartMethodStep;
procedure TestBadAddrBreakpoint; procedure TestBadAddrBreakpoint;
procedure TestInteruptWhilePaused; procedure TestInteruptWhilePaused;
end; end;
const const
BREAK_LINE_BREAKPROG = 28; BREAK_LINE_BREAKPROG = 28;
BREAK_LINE_BREAKPROG_MAIN = 24; /// ..26
implementation implementation
@ -159,6 +161,48 @@ begin
AssertTestErrors; AssertTestErrors;
end; end;
procedure TTestBreakPoint.TestStartMethodStep;
var
dbg: TGDBMIDebugger;
TestExeName, s: string;
i: TGDBMIDebuggerStartBreak;
IgnoreRes: String;
begin
if SkipTest then exit;
if not TestControlForm.CheckListBox1.Checked[TestControlForm.CheckListBox1.Items.IndexOf('TTestBreakPoint')] then exit;
if not TestControlForm.CheckListBox1.Checked[TestControlForm.CheckListBox1.Items.IndexOf(' TTestBreakPoint.StartMethod')] then exit;
ClearTestErrors;
FBrkErr := nil;
TestCompile(AppDir + 'breakprog.pas', TestExeName, '_callall', ' -dCALL_ALL ');
for i := Low(TGDBMIDebuggerStartBreak) to high(TGDBMIDebuggerStartBreak) do begin
WriteStr(s, i);
try
dbg := StartGDB(AppDir, TestExeName);
dbg.OnCurrent := @DoCurrent;
TGDBMIDebuggerProperties(dbg.GetProperties).InternalStartBreak := i;
dbg.StepOver;
IgnoreRes := '';
if i = gdsbAddZero then IgnoreRes:= 'launch with step does not work with gdsbAddZero';
TestTrue(s+' not in error state 1', dbg.State <> dsError, 0, IgnoreRes);
TestTrue(s+' at break', (FCurLine >= BREAK_LINE_BREAKPROG_MAIN) AND (FCurLine <= BREAK_LINE_BREAKPROG_MAIN + 2),
0, IgnoreRes);
TGDBMIDebuggerProperties(dbg.GetProperties).InternalStartBreak := gdsbDefault;
finally
dbg.Done;
CleanGdb;
dbg.Free;
end;
end;
AssertTestErrors;
end;
function TTestBreakPoint.DoGetFeedBack(Sender: TObject; const AText, AInfo: String; function TTestBreakPoint.DoGetFeedBack(Sender: TObject; const AText, AInfo: String;
AType: TDBGFeedbackType; AButtons: TDBGFeedbackResults): TDBGFeedbackResult; AType: TDBGFeedbackType; AButtons: TDBGFeedbackResults): TDBGFeedbackResult;
begin begin
@ -237,6 +281,20 @@ begin
if not TestControlForm.CheckListBox1.Checked[TestControlForm.CheckListBox1.Items.IndexOf('TTestBreakPoint')] then exit; if not TestControlForm.CheckListBox1.Checked[TestControlForm.CheckListBox1.Items.IndexOf('TTestBreakPoint')] then exit;
if not TestControlForm.CheckListBox1.Checked[TestControlForm.CheckListBox1.Items.IndexOf(' TTestBreakPoint.BadInterrupt')] then exit; if not TestControlForm.CheckListBox1.Checked[TestControlForm.CheckListBox1.Items.IndexOf(' TTestBreakPoint.BadInterrupt')] then exit;
IgnoreRes := '';
case DebuggerInfo.Version of
0..069999: IgnoreRes:= 'all gdb 6.x may or may not fail';
070000: IgnoreRes:= 'gdb 7.0.0 may or may not fail';
// 7.0.50 seems to always pass
// 7.1.x seems to always pass
// 7.2.x seems to always pass
070300..070399: IgnoreRes:= 'gdb 7.3.x may or may not fail';
070400..070499: IgnoreRes:= 'gdb 7.4.x may or may not fail';
070500..070599: IgnoreRes:= 'gdb 7.5.x may or may not fail';
070600..070699: IgnoreRes:= 'gdb 7.6.x may or may not fail';
070700..070700: IgnoreRes:= 'gdb 7.7.0 may or may not fail';
end;
(* Trigger a InterruptTarget while paused. (* Trigger a InterruptTarget while paused.
Test if the app can continue, and reach it normal exit somehow (even if multiply interupts must be skipped) Test if the app can continue, and reach it normal exit somehow (even if multiply interupts must be skipped)
*) *)
@ -454,17 +512,6 @@ begin
dbg.Free; dbg.Free;
end; end;
end; end;
IgnoreRes := '';
case DebuggerInfo.Version of
0..069999: IgnoreRes:= 'all gdb 6.x may or may not fail';
070000: IgnoreRes:= 'gdb 7.0.0 may or may not fail';
// 7.0.50 seems to always pass
// 7.1.x seems to always pass
// 7.2.x seems to always pass
070300..070399: IgnoreRes:= 'gdb 7.3.x may or may not fail';
070400..070499: IgnoreRes:= 'gdb 7.4.x may or may not fail';
070500..070599: IgnoreRes:= 'gdb 7.5.x may or may not fail';
end;
TestEquals('Passed none-pause run', '', Err, 0, IgnoreRes); TestEquals('Passed none-pause run', '', Err, 0, IgnoreRes);
@ -523,7 +570,7 @@ begin
if dbg.State <> dsStop if dbg.State <> dsStop
then Err := Err + 'Never reached final stop'; then Err := Err + 'Never reached final stop';
finally finally
TestEquals('Passed none-pause run with steps', '', Err); TestEquals('Passed none-pause run with steps', '', Err, 0, IgnoreRes);
dbg.Done; dbg.Done;
CleanGdb; CleanGdb;
dbg.Free; dbg.Free;