#97, add options, detect exit, auto get regs and stack, handle ignored signals

This commit is contained in:
Basile Burg 2016-09-21 23:09:38 +02:00
parent 559e006603
commit 0c634cce91
No known key found for this signature in database
GPG Key ID: 1868039F415CB8CF
1 changed files with 158 additions and 23 deletions

View File

@ -10,7 +10,7 @@ uses
StdCtrls, process, fpjson, StdCtrls, process, fpjson,
ce_common, ce_interfaces, ce_widget, ce_processes, ce_observer, ce_synmemo, ce_common, ce_interfaces, ce_widget, ce_processes, ce_observer, ce_synmemo,
ce_sharedres, ce_stringrange, ce_dsgncontrols, ce_dialogs, ce_dbgitf, ce_sharedres, ce_stringrange, ce_dsgncontrols, ce_dialogs, ce_dbgitf,
ce_ddemangle; ce_ddemangle, ce_writableComponent;
type type
@ -151,13 +151,40 @@ type
procedure clear; procedure clear;
end; end;
TCEDebugWidgetOptions = class // TODO-cGDB: shortcuts
fDemangle: boolean; TCEDebugOptionsBase = class(TWritableLfmTextComponent)
fShowCLI: boolean; private
fAutoDemangle: boolean;
fAutoGetCallStack: boolean;
fAutoGetRegisters: boolean;
fAutoGetVariables: boolean;
fIgnoredSignals: TStringList; fIgnoredSignals: TStringList;
fAutoDumpStack: boolean; fShowOutput: boolean;
fAutoDumpRegisters: boolean; procedure setIgnoredSignals(value: TStringList);
fAutoDumpLocals: boolean; published
property autoDemangle: boolean read fAutoDemangle write fAutoDemangle;
property autoGetCallStack: boolean read fAutoGetCallStack write fAutoGetCallStack;
property autoGetRegisters: boolean read fAutoGetRegisters write fAutoGetRegisters;
property autoGetVariables: boolean read fAutoGetVariables write fAutoGetVariables;
property ignoredSignals: TStringList read fIgnoredSignals write setIgnoredSignals;
property showOutput: boolean read fShowOutput write fShowOutput;
public
constructor create(aOwner: TComponent); override;
destructor destroy; override;
procedure assign(source: TPersistent); override;
end;
TCEDebugOptions = class(TCEDebugOptionsBase, ICEEditableOptions)
private
fBackup: TCEDebugOptionsBase;
function optionedWantCategory(): string;
function optionedWantEditorKind: TOptionEditorKind;
function optionedWantContainer: TPersistent;
procedure optionedEvent(event: TOptionEditorEvent);
function optionedOptionsModified: boolean;
public
constructor create(aOwner: TComponent); override;
destructor destroy; override;
end; end;
{ TCEGdbWidget } { TCEGdbWidget }
@ -200,9 +227,9 @@ type
fMsg: ICEMessagesDisplay; fMsg: ICEMessagesDisplay;
fGdb: TCEProcess; fGdb: TCEProcess;
fInspState: TInspectableState; fInspState: TInspectableState;
fShowCLI: boolean;
fStackItems: TStackItems; fStackItems: TStackItems;
fCatchPause: boolean; fCatchPause: boolean;
fOptions: TCEDebugOptions;
// //
procedure startDebugging; procedure startDebugging;
procedure pauseDebugee; procedure pauseDebugee;
@ -242,6 +269,97 @@ type
implementation implementation
{$R *.lfm} {$R *.lfm}
{$REGION TCEDebugOption --------------------------------------------------------}
const optFname = 'gdbcommander.txt';
constructor TCEDebugOptionsBase.create(aOwner: TComponent);
begin
inherited;
fAutoDemangle := true;
fAutoGetCallStack:= true;
fAutoGetRegisters:= true;
fAutoGetVariables:= true;
fShowOutput:=true;
fIgnoredSignals := TStringList.Create;
end;
destructor TCEDebugOptionsBase.destroy;
begin
fIgnoredSignals.Free;
inherited;
end;
procedure TCEDebugOptionsBase.setIgnoredSignals(value: TStringList);
begin
fIgnoredSignals.Assign(value);
end;
procedure TCEDebugOptionsBase.assign(source: TPersistent);
var
src: TCEDebugOptionsBase;
begin
if source is TCEDebugOptionsBase then
begin
src := TCEDebugOptionsBase(source);
fAutoDemangle:=src.fAutoDemangle;
fAutoGetCallStack:=src.fAutoGetCallStack;
fAutoGetRegisters:=src.fAutoGetRegisters;
fAutoGetVariables:=src.autoGetVariables;
fShowOutput:=src.fShowOutput;
fIgnoredSignals.Assign(src.fIgnoredSignals);
end
else inherited;
end;
constructor TCEDebugOptions.create(aOwner: TComponent);
var
fname: string;
begin
inherited;
fBackup := TCEDebugOptionsBase.create(self);
fname := getCoeditDocPath + optFname;
if fname.fileExists then
loadFromFile(fname);
EntitiesConnector.addObserver(self);
end;
destructor TCEDebugOptions.destroy;
begin
saveToFile(getCoeditDocPath + optFname);
EntitiesConnector.removeObserver(self);
inherited;
end;
function TCEDebugOptions.optionedWantCategory(): string;
begin
exit('Debugger');
end;
function TCEDebugOptions.optionedWantEditorKind: TOptionEditorKind;
begin
exit(oekGeneric);
end;
function TCEDebugOptions.optionedWantContainer: TPersistent;
begin
exit(self);
end;
procedure TCEDebugOptions.optionedEvent(event: TOptionEditorEvent);
begin
case event of
oeeSelectCat: fBackup.assign(self);
oeeCancel: assign(fBackup);
oeeAccept: fBackup.assign(self);
end;
end;
function TCEDebugOptions.optionedOptionsModified: boolean;
begin
exit(false);
end;
{$ENDREGION}
{$REGION TStackItem/TStackItems ------------------------------------------------} {$REGION TStackItem/TStackItems ------------------------------------------------}
procedure TStackItem.setProperties(addr: PtrUint; fname, nme: string; lne: integer); procedure TStackItem.setProperties(addr: PtrUint; fname, nme: string; lne: integer);
begin begin
@ -382,8 +500,9 @@ begin
fJson := TJsonObject.Create; fJson := TJsonObject.Create;
fStackItems := TStackItems.create; fStackItems := TStackItems.create;
fSubj:= TCEDebugObserverSubject.Create; fSubj:= TCEDebugObserverSubject.Create;
fShowCLI := true; fOptions:= TCEDebugOptions.create(self);
// //
// TODO-cGDB: add command history
AssignPng(btnSendCom, 'ACCEPT'); AssignPng(btnSendCom, 'ACCEPT');
end; end;
@ -534,7 +653,6 @@ begin
str := fProj.outputFilename; str := fProj.outputFilename;
if not str.fileExists then if not str.fileExists then
exit; exit;
// TODO-cGDB: detect finish event and notifiy the observers.
subjDebugStart(fSubj, self as ICEDebugger); subjDebugStart(fSubj, self as ICEDebugger);
// gdb process // gdb process
killGdb; killGdb;
@ -814,11 +932,14 @@ begin
line := val.AsInteger; line := val.AsInteger;
if fDocHandler.findDocument(fullname).isNil then if fDocHandler.findDocument(fullname).isNil then
fDocHandler.openDocument(fullname); fDocHandler.openDocument(fullname);
if fOptions.autoGetCallStack then
infoStack;
if fOptions.autoGetRegisters then
infoRegs;
subjDebugBreak(fSubj, fullname, line, brkreason); subjDebugBreak(fSubj, fullname, line, brkreason);
end; end;
end end
//TODO-cGDB: in the settings, option to automatically ignore particular signals.
else if reason = 'signal-received' then else if reason = 'signal-received' then
begin begin
signame := 'unknown signal'; signame := 'unknown signal';
@ -826,6 +947,9 @@ begin
val := fJson.Find('signal-name'); val := fJson.Find('signal-name');
if val.isNotNil then if val.isNotNil then
signame := val.AsString; signame := val.AsString;
if (fOptions.ignoredSignals.Count <> 0) and
(fOptions.ignoredSignals.IndexOf(signame) <> -1) then
exit;
val := fJson.Find('signal-meaning'); val := fJson.Find('signal-meaning');
if val.isNotNil then if val.isNotNil then
sigmean := val.AsString; sigmean := val.AsString;
@ -844,6 +968,10 @@ begin
fCatchPause := false; fCatchPause := false;
if fDocHandler.findDocument(fullname).isNil then if fDocHandler.findDocument(fullname).isNil then
fDocHandler.openDocument(fullname); fDocHandler.openDocument(fullname);
if fOptions.autoGetCallStack then
infoStack;
if fOptions.autoGetRegisters then
infoRegs;
subjDebugBreak(fSubj, fullname, line, dbSignal); subjDebugBreak(fSubj, fullname, line, dbSignal);
end end
else else
@ -856,10 +984,17 @@ begin
begin begin
if not fDocHandler.findDocument(fullname).isNil then if not fDocHandler.findDocument(fullname).isNil then
fDocHandler.openDocument(fullname); fDocHandler.openDocument(fullname);
if fOptions.autoGetCallStack then
infoStack;
if fOptions.autoGetRegisters then
infoRegs;
subjDebugBreak(fSubj, fullname, line, dbSignal); subjDebugBreak(fSubj, fullname, line, dbSignal);
end; end;
end; end;
end; end
else if (reason = 'exited-normally') or (reason = 'exited-signalled') then
subjDebugStop(fSubj);
end; end;
@ -880,14 +1015,9 @@ begin
val := obj.Find('value'); val := obj.Find('value');
if val.isNotNil then if val.isNotNil then
begin begin
{$IFDEF CPU64}
if (0 <= number) and (TCpuRegister(number) <= high(TCpuRegister)) then if (0 <= number) and (TCpuRegister(number) <= high(TCpuRegister)) then
fInspState.CPU.setRegister(TCpuRegister(number), val.AsInt64); fInspState.CPU.setRegister(TCpuRegister(number),
{$ENDIF} {$IFDEF CPU64}val.AsInt64{$ELSE}val.AsInteger{$ENDIF});
{$IFDEF CPU32}
if (0 <= number) and (number <= high(TCpuRegister)) then
fInspState.GPR.setRegister(TCpuRegister(number), val.AsInteger);
{$ENDIF}
end; end;
@ -913,10 +1043,14 @@ begin
val := obj.Find('fullname'); val := obj.Find('fullname');
if val.isNotNil then if val.isNotNil then
fullname:= val.AsString; fullname:= val.AsString;
// TODO-cGDB: demangle function name.
val := obj.Find('func'); val := obj.Find('func');
if val.isNotNil then if val.isNotNil then
func:= demangle(val.AsString); begin
if fOptions.autoDemangle then
func:= demangle(val.AsString)
else
func := val.AsString;
end;
val := obj.Find('addr'); val := obj.Find('addr');
if val.isNotNil then if val.isNotNil then
addr := val.AsInt64; addr := val.AsInt64;
@ -928,7 +1062,7 @@ begin
fStackItems.assignToList(lstCallStack); fStackItems.assignToList(lstCallStack);
end; end;
if fShowCLI then if fOptions.showOutput then
begin begin
arr := TJSONArray(fJson.Find('CLI')); arr := TJSONArray(fJson.Find('CLI'));
if arr.isNotNil then if arr.isNotNil then
@ -959,7 +1093,7 @@ begin
//lst := TStringList.Create; //lst := TStringList.Create;
//try //try
// str := fGdbMessage.json.FormatJSON(DefaultFormat,2); // str := fJson.FormatJSON(DefaultFormat,2);
// lst.Text:= str; // lst.Text:= str;
// lst.SaveToFile('/home/basile/gdbmessage.json'); // lst.SaveToFile('/home/basile/gdbmessage.json');
//finally //finally
@ -1033,6 +1167,7 @@ procedure TCEGdbWidget.btnStopClick(Sender: TObject);
begin begin
pauseDebugee; pauseDebugee;
gdbCommand('kill', @gdboutJsonize); gdbCommand('kill', @gdboutJsonize);
subjDebugStop(fSubj);
end; end;
procedure TCEGdbWidget.btnSendComClick(Sender: TObject); procedure TCEGdbWidget.btnSendComClick(Sender: TObject);