#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,
ce_common, ce_interfaces, ce_widget, ce_processes, ce_observer, ce_synmemo,
ce_sharedres, ce_stringrange, ce_dsgncontrols, ce_dialogs, ce_dbgitf,
ce_ddemangle;
ce_ddemangle, ce_writableComponent;
type
@ -151,13 +151,40 @@ type
procedure clear;
end;
TCEDebugWidgetOptions = class
fDemangle: boolean;
fShowCLI: boolean;
// TODO-cGDB: shortcuts
TCEDebugOptionsBase = class(TWritableLfmTextComponent)
private
fAutoDemangle: boolean;
fAutoGetCallStack: boolean;
fAutoGetRegisters: boolean;
fAutoGetVariables: boolean;
fIgnoredSignals: TStringList;
fAutoDumpStack: boolean;
fAutoDumpRegisters: boolean;
fAutoDumpLocals: boolean;
fShowOutput: boolean;
procedure setIgnoredSignals(value: TStringList);
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;
{ TCEGdbWidget }
@ -200,9 +227,9 @@ type
fMsg: ICEMessagesDisplay;
fGdb: TCEProcess;
fInspState: TInspectableState;
fShowCLI: boolean;
fStackItems: TStackItems;
fCatchPause: boolean;
fOptions: TCEDebugOptions;
//
procedure startDebugging;
procedure pauseDebugee;
@ -242,6 +269,97 @@ type
implementation
{$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 ------------------------------------------------}
procedure TStackItem.setProperties(addr: PtrUint; fname, nme: string; lne: integer);
begin
@ -382,8 +500,9 @@ begin
fJson := TJsonObject.Create;
fStackItems := TStackItems.create;
fSubj:= TCEDebugObserverSubject.Create;
fShowCLI := true;
fOptions:= TCEDebugOptions.create(self);
//
// TODO-cGDB: add command history
AssignPng(btnSendCom, 'ACCEPT');
end;
@ -534,7 +653,6 @@ begin
str := fProj.outputFilename;
if not str.fileExists then
exit;
// TODO-cGDB: detect finish event and notifiy the observers.
subjDebugStart(fSubj, self as ICEDebugger);
// gdb process
killGdb;
@ -814,11 +932,14 @@ begin
line := val.AsInteger;
if fDocHandler.findDocument(fullname).isNil then
fDocHandler.openDocument(fullname);
if fOptions.autoGetCallStack then
infoStack;
if fOptions.autoGetRegisters then
infoRegs;
subjDebugBreak(fSubj, fullname, line, brkreason);
end;
end
//TODO-cGDB: in the settings, option to automatically ignore particular signals.
else if reason = 'signal-received' then
begin
signame := 'unknown signal';
@ -826,6 +947,9 @@ begin
val := fJson.Find('signal-name');
if val.isNotNil then
signame := val.AsString;
if (fOptions.ignoredSignals.Count <> 0) and
(fOptions.ignoredSignals.IndexOf(signame) <> -1) then
exit;
val := fJson.Find('signal-meaning');
if val.isNotNil then
sigmean := val.AsString;
@ -844,6 +968,10 @@ begin
fCatchPause := false;
if fDocHandler.findDocument(fullname).isNil then
fDocHandler.openDocument(fullname);
if fOptions.autoGetCallStack then
infoStack;
if fOptions.autoGetRegisters then
infoRegs;
subjDebugBreak(fSubj, fullname, line, dbSignal);
end
else
@ -856,10 +984,17 @@ begin
begin
if not fDocHandler.findDocument(fullname).isNil then
fDocHandler.openDocument(fullname);
if fOptions.autoGetCallStack then
infoStack;
if fOptions.autoGetRegisters then
infoRegs;
subjDebugBreak(fSubj, fullname, line, dbSignal);
end;
end;
end;
end
else if (reason = 'exited-normally') or (reason = 'exited-signalled') then
subjDebugStop(fSubj);
end;
@ -880,14 +1015,9 @@ begin
val := obj.Find('value');
if val.isNotNil then
begin
{$IFDEF CPU64}
if (0 <= number) and (TCpuRegister(number) <= high(TCpuRegister)) then
fInspState.CPU.setRegister(TCpuRegister(number), val.AsInt64);
{$ENDIF}
{$IFDEF CPU32}
if (0 <= number) and (number <= high(TCpuRegister)) then
fInspState.GPR.setRegister(TCpuRegister(number), val.AsInteger);
{$ENDIF}
fInspState.CPU.setRegister(TCpuRegister(number),
{$IFDEF CPU64}val.AsInt64{$ELSE}val.AsInteger{$ENDIF});
end;
@ -913,10 +1043,14 @@ begin
val := obj.Find('fullname');
if val.isNotNil then
fullname:= val.AsString;
// TODO-cGDB: demangle function name.
val := obj.Find('func');
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');
if val.isNotNil then
addr := val.AsInt64;
@ -928,7 +1062,7 @@ begin
fStackItems.assignToList(lstCallStack);
end;
if fShowCLI then
if fOptions.showOutput then
begin
arr := TJSONArray(fJson.Find('CLI'));
if arr.isNotNil then
@ -959,7 +1093,7 @@ begin
//lst := TStringList.Create;
//try
// str := fGdbMessage.json.FormatJSON(DefaultFormat,2);
// str := fJson.FormatJSON(DefaultFormat,2);
// lst.Text:= str;
// lst.SaveToFile('/home/basile/gdbmessage.json');
//finally
@ -1033,6 +1167,7 @@ procedure TCEGdbWidget.btnStopClick(Sender: TObject);
begin
pauseDebugee;
gdbCommand('kill', @gdboutJsonize);
subjDebugStop(fSubj);
end;
procedure TCEGdbWidget.btnSendComClick(Sender: TObject);