Debugger: Display errors on run/step to user, with a choice to continue; instead of "error state"

git-svn-id: trunk@30416 -
This commit is contained in:
martin 2011-04-21 16:05:08 +00:00
parent e6f053d841
commit 5b1fca573b
7 changed files with 245 additions and 4 deletions

2
.gitattributes vendored
View File

@ -2695,6 +2695,8 @@ debugger/evaluatedlg.lfm svneol=native#text/plain
debugger/evaluatedlg.pp svneol=native#text/pascal debugger/evaluatedlg.pp svneol=native#text/pascal
debugger/exceptiondlg.lfm svneol=native#text/plain debugger/exceptiondlg.lfm svneol=native#text/plain
debugger/exceptiondlg.pas svneol=native#text/pascal debugger/exceptiondlg.pas svneol=native#text/pascal
debugger/feedbackdlg.lfm svneol=native#text/plain
debugger/feedbackdlg.pp svneol=native#text/pascal
debugger/fpdebug/dbgclasses.pp svneol=native#text/pascal debugger/fpdebug/dbgclasses.pp svneol=native#text/pascal
debugger/fpdebug/dbgdisasx86.pp svneol=native#text/plain debugger/fpdebug/dbgdisasx86.pp svneol=native#text/plain
debugger/fpdebug/dbgdwarf.pas svneol=native#text/pascal debugger/fpdebug/dbgdwarf.pas svneol=native#text/pascal

View File

@ -1481,6 +1481,10 @@ type
ecDebugger); // debugger errors and warnings ecDebugger); // debugger errors and warnings
TDBGEventCategories = set of TDBGEventCategory; TDBGEventCategories = set of TDBGEventCategory;
TDBGFeedbackType = (ftWarning, ftError);
TDBGFeedbackResult = (frOk, frStop);
TDBGFeedbackResults = set of TDBGFeedbackResult;
TDBGEventNotify = procedure(Sender: TObject; const ACategory: TDBGEventCategory; TDBGEventNotify = procedure(Sender: TObject; const ACategory: TDBGEventCategory;
const AText: String) of object; const AText: String) of object;
@ -1496,6 +1500,10 @@ type
const AExceptionText: String; const AExceptionText: String;
out AContinue: Boolean) of object; out AContinue: Boolean) of object;
TDBGFeedbackEvent = function(Sender: TObject; const AText, AInfo: String;
AType: TDBGFeedbackType; AButtons: TDBGFeedbackResults
): TDBGFeedbackResult of object;
TDebuggerNotifyReason = (dnrDestroy); TDebuggerNotifyReason = (dnrDestroy);
{ TDebuggerProperties } { TDebuggerProperties }
@ -1525,6 +1533,7 @@ type
FLocals: TDBGLocals; FLocals: TDBGLocals;
FLineInfo: TDBGLineInfo; FLineInfo: TDBGLineInfo;
FOnConsoleOutput: TDBGOutputEvent; FOnConsoleOutput: TDBGOutputEvent;
FOnFeedback: TDBGFeedbackEvent;
FRegisters: TDBGRegisters; FRegisters: TDBGRegisters;
FShowConsole: Boolean; FShowConsole: Boolean;
FSignals: TDBGSignals; FSignals: TDBGSignals;
@ -1647,6 +1656,7 @@ type
property OnState: TDebuggerStateChangedEvent read FOnState write FOnState; // Fires when the current state of the debugger changes property OnState: TDebuggerStateChangedEvent read FOnState write FOnState; // Fires when the current state of the debugger changes
property OnBreakPointHit: TDebuggerBreakPointHitEvent read FOnBreakPointHit write FOnBreakPointHit; // Fires when the program is paused at a breakpoint property OnBreakPointHit: TDebuggerBreakPointHitEvent read FOnBreakPointHit write FOnBreakPointHit; // Fires when the program is paused at a breakpoint
property OnConsoleOutput: TDBGOutputEvent read FOnConsoleOutput write FOnConsoleOutput; // Passes Application Console Output property OnConsoleOutput: TDBGOutputEvent read FOnConsoleOutput write FOnConsoleOutput; // Passes Application Console Output
property OnFeedback: TDBGFeedbackEvent read FOnFeedback write FOnFeedback;
end; end;
TDebuggerClass = class of TDebugger; TDebuggerClass = class of TDebugger;

68
debugger/feedbackdlg.lfm Normal file
View File

@ -0,0 +1,68 @@
object DbgFeedbackDlg: TDbgFeedbackDlg
Left = 480
Height = 212
Top = 140
Width = 605
AutoSize = True
BorderIcons = [biSystemMenu]
BorderStyle = bsDialog
Caption = 'DbgFeedbackDlg'
ClientHeight = 212
ClientWidth = 605
Position = poScreenCenter
LCLVersion = '0.9.31'
object ButtonPanel1: TButtonPanel
Left = 6
Height = 34
Top = 172
Width = 593
OKButton.Name = 'OKButton'
OKButton.Caption = '&OK'
HelpButton.Name = 'HelpButton'
HelpButton.Caption = '&Help'
HelpButton.OnClick = HelpButtonClick
CloseButton.Name = 'CloseButton'
CloseButton.Caption = '&Close'
CloseButton.Enabled = False
CancelButton.Name = 'CancelButton'
CancelButton.Caption = 'Stop'
TabOrder = 0
ShowButtons = [pbOK, pbCancel, pbHelp]
ShowGlyphs = [pbOK, pbCancel]
end
object Panel1: TPanel
Left = 0
Height = 166
Top = 0
Width = 605
Align = alClient
BevelOuter = bvNone
ClientHeight = 166
ClientWidth = 605
TabOrder = 1
object lblMsg: TLabel
Left = 5
Height = 61
Top = 5
Width = 595
Align = alClient
BorderSpacing.Around = 5
Caption = 'lblMsg'
ParentColor = False
end
object Memo1: TMemo
Left = 5
Height = 90
Top = 71
Width = 595
Align = alBottom
BorderSpacing.Around = 5
Lines.Strings = (
'Memo1'
)
ReadOnly = True
TabOrder = 0
Visible = False
end
end
end

102
debugger/feedbackdlg.pp Normal file
View File

@ -0,0 +1,102 @@
unit FeedbackDlg;
{$mode objfpc}{$H+}
interface
uses
Forms, Controls, ButtonPanel, StdCtrls, ExtCtrls, Debugger, LazarusIDEStrConsts;
type
{ TDbgFeedbackDlg }
TDbgFeedbackDlg = class(TForm)
ButtonPanel1: TButtonPanel;
lblMsg: TLabel;
Memo1: TMemo;
Panel1: TPanel;
procedure HelpButtonClick(Sender: TObject);
private
{ private declarations }
public
{ public declarations }
function Execute(const AText, AInfo: String;
AType: TDBGFeedbackType; AButtons: TDBGFeedbackResults
): TDBGFeedbackResult;
end;
var
DbgFeedbackDlg: TDbgFeedbackDlg;
function ExecuteFeedbackDialog(const AText, AInfo: String;
AType: TDBGFeedbackType; AButtons: TDBGFeedbackResults
): TDBGFeedbackResult;
implementation
function ExecuteFeedbackDialog(const AText, AInfo: String; AType: TDBGFeedbackType;
AButtons: TDBGFeedbackResults): TDBGFeedbackResult;
var
ADialog: TDbgFeedbackDlg;
begin
ADialog := TDbgFeedbackDlg.Create(Application);
try
Result := ADialog.Execute(AText, AInfo, AType, AButtons);
finally
ADialog.Free;
end;
end;
{ TDbgFeedbackDlg }
procedure TDbgFeedbackDlg.HelpButtonClick(Sender: TObject);
begin
AutoSize := False;
Memo1.Visible := not Memo1.Visible;
if Memo1.Visible then
ButtonPanel1.HelpButton.Caption := lisDebuggerFeedbackLess
else
ButtonPanel1.HelpButton.Caption := lisDebuggerFeedbackMore;
AutoSize := True;
end;
function TDbgFeedbackDlg.Execute(const AText, AInfo: String; AType: TDBGFeedbackType;
AButtons: TDBGFeedbackResults): TDBGFeedbackResult;
begin
case AType of
ftWarning: begin
Caption := lisDebuggerFeedbackWarning;
end;
ftError: begin
Caption := lisDebuggerFeedbackError;
end;
end;
lblMsg.Caption := AText;
memo1.Text := AInfo;
memo1.Visible := False;
if AInfo <> '' then begin
ButtonPanel1.HelpButton.Caption := lisDebuggerFeedbackMore;
ButtonPanel1.HelpButton.Visible := True;
end
else begin
ButtonPanel1.HelpButton.Visible := False;
end;
ButtonPanel1.OKButton.Visible := frOk in AButtons;
ButtonPanel1.CancelButton.Visible := frStop in AButtons;
ButtonPanel1.OKButton.Caption := lisDebuggerFeedbackOk;
ButtonPanel1.CancelButton.Caption := lisDebuggerFeedbackStop;
case ShowModal of
mrOk: Result := frOk;
mrCancel: Result := frStop;
end;
end;
{$R *.lfm}
end.

View File

@ -399,6 +399,14 @@ type
procedure TestCmd(const ACommand: String); override; procedure TestCmd(const ACommand: String); override;
end; end;
resourcestring
gdbmiErrorOnRunCommand = 'The debugger encountered an error when trying to '
+ 'run/step the application:%0:s%0:s%1:s%0:s%0:s'
+ 'Press "Ok" to continue debugging (paused), '
+ 'and correct the problem, or choose an alternative run command%0:s'
+ 'Press "Stop" to end the debug session';
gdbmiErrorOnRunCommandWithWarning = '%0:s%0:sIn addition to the Error the following '
+ 'warning was encountered:%0:s%0:s%1:s';
implementation implementation
@ -514,6 +522,7 @@ type
FExecType: TGDBMIExecCommandType; FExecType: TGDBMIExecCommandType;
FCommand: String; FCommand: String;
FCanKillNow, FDidKillNow: Boolean; FCanKillNow, FDidKillNow: Boolean;
FLogWarnings: String;
protected protected
procedure DoLockQueueExecute; override; procedure DoLockQueueExecute; override;
procedure DoUnockQueueExecute; override; procedure DoUnockQueueExecute; override;
@ -2903,7 +2912,6 @@ function TGDBMIDebuggerCommandStartDebugging.DoExecute: Boolean;
FTheDebugger.FMainAddr := StrToQWordDef(ResultList.Values['addr'], 0); FTheDebugger.FMainAddr := StrToQWordDef(ResultList.Values['addr'], 0);
ResultList.Free; ResultList.Free;
end; end;
var var
R: TGDBMIExecResult; R: TGDBMIExecResult;
FileType, EntryPoint: String; FileType, EntryPoint: String;
@ -3167,6 +3175,8 @@ begin
end; end;
function TGDBMIDebuggerCommandExecute.ProcessRunning(var AStoppedParams: String): Boolean; function TGDBMIDebuggerCommandExecute.ProcessRunning(var AStoppedParams: String): Boolean;
var
InLogWarning: Boolean;
function DoExecAsync(var Line: String): Boolean; function DoExecAsync(var Line: String): Boolean;
var var
@ -3222,8 +3232,16 @@ function TGDBMIDebuggerCommandExecute.ProcessRunning(var AStoppedParams: String)
end; end;
procedure DoLogStream(const Line: String); procedure DoLogStream(const Line: String);
const
LogWarning = '&"Warning:\n"';
begin begin
DebugLn('[Debugger] Log output: ', Line); DebugLn('[Debugger] Log output: ', Line);
if copy(Line, 1, length(LogWarning)) = LogWarning then
InLogWarning := True;
if InLogWarning then
FLogWarnings := FLogWarnings + copy(Line, 3, length(Line)-5) + LineEnding;
if copy(Line, 1, length(LogWarning)) = '&"\n"' then
InLogWarning := False;
end; end;
var var
@ -3231,6 +3249,8 @@ var
idx: Integer; idx: Integer;
begin begin
Result := True; Result := True;
InLogWarning := False;
FLogWarnings := '';
while FTheDebugger.DebugProcessRunning do while FTheDebugger.DebugProcessRunning do
begin begin
S := FTheDebugger.ReadLine; S := FTheDebugger.ReadLine;
@ -3631,9 +3651,10 @@ end;
function TGDBMIDebuggerCommandExecute.DoExecute: Boolean; function TGDBMIDebuggerCommandExecute.DoExecute: Boolean;
var var
StoppedParams: String; StoppedParams, s, s2: String;
ContinueExecution: Boolean; ContinueExecution: Boolean;
NextExecCmdObj: TGDBMIDebuggerCommandExecute; NextExecCmdObj: TGDBMIDebuggerCommandExecute;
List: TGDBMINameValueList;
begin begin
Result := True; Result := True;
FCanKillNow := False; FCanKillNow := False;
@ -3646,8 +3667,31 @@ begin
if not ExecuteCommand(FCommand, FResult) if not ExecuteCommand(FCommand, FResult)
then exit; then exit;
if (FResult.State = dsError) and assigned(FTheDebugger.OnFeedback) then begin
List := TGDBMINameValueList.Create(FResult);
s := List.Values['msg'];
FreeAndNil(List);
if FLogWarnings <> ''
then s2 := Format(gdbmiErrorOnRunCommandWithWarning, [LineEnding, FLogWarnings])
else s2 := '';
FLogWarnings := '';
if s <> '' then begin
case FTheDebugger.OnFeedback(self,
Format(gdbmiErrorOnRunCommand, [LineEnding, s]) + s2,
FResult.Values, ftError, [frOk, frStop]
) of
frOk: FResult.State := dsPause;
frStop: begin
FTheDebugger.Stop;
FResult.State := dsStop;
exit;
end;
end;
end
end;
if (FResult.State <> dsNone) if (FResult.State <> dsNone)
then SetDebuggerState(FResult.State); then SetDebuggerState(FResult.State);
// if ContinueExecution will be true, the we ignore dsError.. // if ContinueExecution will be true, the we ignore dsError..
// TODO: chack for cancelled // TODO: chack for cancelled

View File

@ -56,7 +56,7 @@ uses
SourceMarks, SourceMarks,
DebuggerDlg, Watchesdlg, BreakPointsdlg, BreakPropertyDlg, LocalsDlg, WatchPropertyDlg, DebuggerDlg, Watchesdlg, BreakPointsdlg, BreakPropertyDlg, LocalsDlg, WatchPropertyDlg,
CallStackDlg, EvaluateDlg, RegistersDlg, AssemblerDlg, DebugOutputForm, ExceptionDlg, CallStackDlg, EvaluateDlg, RegistersDlg, AssemblerDlg, DebugOutputForm, ExceptionDlg,
InspectDlg, DebugEventsForm, PseudoTerminalDlg, InspectDlg, DebugEventsForm, PseudoTerminalDlg, FeedbackDlg,
GDBMIDebugger, SSHGDBMIDebugger, ProcessDebugger, GDBMIDebugger, SSHGDBMIDebugger, ProcessDebugger,
BaseDebugManager; BaseDebugManager;
@ -80,6 +80,8 @@ type
procedure DebuggerOutput(Sender: TObject; const AText: String); procedure DebuggerOutput(Sender: TObject; const AText: String);
procedure DebuggerEvent(Sender: TObject; const ACategory: TDBGEventCategory; const AText: String); procedure DebuggerEvent(Sender: TObject; const ACategory: TDBGEventCategory; const AText: String);
procedure DebuggerConsoleOutput(Sender: TObject; const AText: String); procedure DebuggerConsoleOutput(Sender: TObject; const AText: String);
function DebuggerFeedback(Sender: TObject; const AText, AInfo: String;
AType: TDBGFeedbackType; AButtons: TDBGFeedbackResults): TDBGFeedbackResult;
procedure DebuggerException(Sender: TObject; procedure DebuggerException(Sender: TObject;
const AExceptionType: TDBGExceptionType; const AExceptionType: TDBGExceptionType;
const AExceptionClass, AExceptionText: String; const AExceptionClass, AExceptionText: String;
@ -1487,6 +1489,12 @@ begin
TPseudoConsoleDlg(FDialogs[ddtPseudoTerminal]).AddOutput(AText); TPseudoConsoleDlg(FDialogs[ddtPseudoTerminal]).AddOutput(AText);
end; end;
function TDebugManager.DebuggerFeedback(Sender: TObject; const AText, AInfo: String;
AType: TDBGFeedbackType; AButtons: TDBGFeedbackResults): TDBGFeedbackResult;
begin
Result := ExecuteFeedbackDialog(AText, AInfo, AType, AButtons);
end;
procedure TDebugManager.BreakAutoContinueTimer(Sender: TObject); procedure TDebugManager.BreakAutoContinueTimer(Sender: TObject);
begin begin
FAutoContinueTimer.Enabled := False; FAutoContinueTimer.Enabled := False;
@ -2611,7 +2619,8 @@ begin
FDebugger.OnDbgOutput := @DebuggerOutput; FDebugger.OnDbgOutput := @DebuggerOutput;
FDebugger.OnDbgEvent := @DebuggerEvent; FDebugger.OnDbgEvent := @DebuggerEvent;
FDebugger.OnException := @DebuggerException; FDebugger.OnException := @DebuggerException;
FDebugger.OnConsoleOutput :=@DebuggerConsoleOutput; FDebugger.OnConsoleOutput := @DebuggerConsoleOutput;
FDebugger.OnFeedback := @DebuggerFeedback;
if FDebugger.State = dsNone if FDebugger.State = dsNone
then begin then begin

View File

@ -5251,6 +5251,12 @@ resourcestring
lisFileNotFound3 = 'file %s not found'; lisFileNotFound3 = 'file %s not found';
lisFileNotFound4 = 'file not found'; lisFileNotFound4 = 'file not found';
lisISDDirectoryNotFound = 'directory not found'; lisISDDirectoryNotFound = 'directory not found';
lisDebuggerFeedbackWarning = 'Debugger Warning';
lisDebuggerFeedbackError = 'Debugger Error';
lisDebuggerFeedbackStop = 'Stop';
lisDebuggerFeedbackLess = 'Less';
lisDebuggerFeedbackMore = 'More';
lisDebuggerFeedbackOk = 'Ok';
implementation implementation