mirror of https://gitlab.com/basile.b/dexed.git
#97, add options, detect exit, auto get regs and stack, handle ignored signals
This commit is contained in:
parent
559e006603
commit
0c634cce91
181
src/ce_gdb.pas
181
src/ce_gdb.pas
|
@ -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);
|
||||||
|
|
Loading…
Reference in New Issue