#97 try to separate inferior output from gdb output + fix CLI scanning

+ parse ^error,msg=
This commit is contained in:
Basile Burg 2016-09-22 18:16:13 +02:00
parent c38ffa76f0
commit a6e8f00f2b
No known key found for this signature in database
GPG Key ID: 1868039F415CB8CF
1 changed files with 83 additions and 18 deletions

View File

@ -169,6 +169,7 @@ type
fAutoGetVariables: boolean; fAutoGetVariables: boolean;
fCommandsHistory: TStringList; fCommandsHistory: TStringList;
fIgnoredSignals: TStringList; fIgnoredSignals: TStringList;
fShowGdbOutput: boolean;
fShowOutput: boolean; fShowOutput: boolean;
procedure setIgnoredSignals(value: TStringList); procedure setIgnoredSignals(value: TStringList);
procedure setCommandsHistory(value: TStringList); procedure setCommandsHistory(value: TStringList);
@ -179,6 +180,7 @@ type
property autoGetVariables: boolean read fAutoGetVariables write fAutoGetVariables; property autoGetVariables: boolean read fAutoGetVariables write fAutoGetVariables;
property commandsHistory: TStringList read fCommandsHistory write setCommandsHistory; property commandsHistory: TStringList read fCommandsHistory write setCommandsHistory;
property ignoredSignals: TStringList read fIgnoredSignals write setIgnoredSignals; property ignoredSignals: TStringList read fIgnoredSignals write setIgnoredSignals;
property showGdbOutput: boolean read fShowGdbOutput write fShowGdbOutput;
property showOutput: boolean read fShowOutput write fShowOutput; property showOutput: boolean read fShowOutput write fShowOutput;
public public
constructor create(aOwner: TComponent); override; constructor create(aOwner: TComponent); override;
@ -252,7 +254,7 @@ type
procedure gdboutJsonize(sender: TObject); procedure gdboutJsonize(sender: TObject);
procedure interpretJson; procedure interpretJson;
// GDB commands & actions // GDB commands & actions
procedure gdbCommand(aCommand: string; gdboutProcessor: TNotifyEvent = nil); procedure gdbCommand(aCommand: string; gdbOutProcessor: TNotifyEvent = nil);
procedure infoRegs; procedure infoRegs;
procedure infoStack; procedure infoStack;
procedure sendCustomCommand; procedure sendCustomCommand;
@ -293,7 +295,7 @@ begin
fAutoGetCallStack:= true; fAutoGetCallStack:= true;
fAutoGetRegisters:= true; fAutoGetRegisters:= true;
fAutoGetVariables:= true; fAutoGetVariables:= true;
fShowOutput:=true; fShowGdbOutput:=true;
fIgnoredSignals := TStringList.Create; fIgnoredSignals := TStringList.Create;
fCommandsHistory := TStringList.Create; fCommandsHistory := TStringList.Create;
end; end;
@ -326,6 +328,7 @@ begin
fAutoGetCallStack:=src.fAutoGetCallStack; fAutoGetCallStack:=src.fAutoGetCallStack;
fAutoGetRegisters:=src.fAutoGetRegisters; fAutoGetRegisters:=src.fAutoGetRegisters;
fAutoGetVariables:=src.autoGetVariables; fAutoGetVariables:=src.autoGetVariables;
fShowGdbOutput:=src.fShowGdbOutput;
fShowOutput:=src.fShowOutput; fShowOutput:=src.fShowOutput;
fIgnoredSignals.Assign(src.fIgnoredSignals); fIgnoredSignals.Assign(src.fIgnoredSignals);
fCommandsHistory.Assign(src.fCommandsHistory); fCommandsHistory.Assign(src.fCommandsHistory);
@ -690,6 +693,7 @@ end;
procedure TCEGdbWidget.startDebugging; procedure TCEGdbWidget.startDebugging;
var var
str: string; str: string;
gdb: string;
i: integer; i: integer;
begin begin
// protect // protect
@ -700,13 +704,21 @@ begin
str := fProj.outputFilename; str := fProj.outputFilename;
if not str.fileExists then if not str.fileExists then
exit; exit;
gdb := exeFullName('gdb');
if not gdb.fileExists then
exit;
subjDebugStart(fSubj, self as ICEDebugger); subjDebugStart(fSubj, self as ICEDebugger);
// gdb process // gdb process
killGdb; killGdb;
fGdb := TCEProcess.create(nil); fGdb := TCEProcess.create(nil);
fGdb.Executable:= 'gdb' + exeExt; fGdb.Executable:= gdb;
fgdb.Options:= [poUsePipes, poStderrToOutPut]; fgdb.Options:= [poUsePipes, poStderrToOutPut];
fgdb.Parameters.Add(str); fgdb.Parameters.Add(str);
//TODO-cGDB: debugee environment
//TODO-cGDB: debugee command line
//TODO-cGDB: pass input to debugee
fgdb.Parameters.Add('--interpreter=mi'); fgdb.Parameters.Add('--interpreter=mi');
fGdb.OnReadData:= @gdboutQuiet; fGdb.OnReadData:= @gdboutQuiet;
fGdb.OnTerminate:= @gdboutJsonize; fGdb.OnTerminate:= @gdboutJsonize;
@ -797,11 +809,27 @@ procedure parseGdbout(const str: string; var json: TJSONObject);
begin begin
r^.popFront; r^.popFront;
if r^.front = #10 then if r^.front = #10 then
begin
r^.popFront;
break; break;
end;
end; end;
end; end;
end; end;
procedure parseInferior(node: TJSONObject; r: PStringRange);
begin
while true do
begin
// TODO-cGDB: detect invalid command after GDB prefix, maybe inferior output
if r^.empty or (r^.front in ['~','^','*','=','&',(*'+',*)'@']) then
break;
node.Arrays['OUT'].Add(r^.takeUntil(#10).yield);
if not r^.empty then
r^.popFront;
end;
end;
procedure parseProperty(node: TJSONArray; r: PStringRange); procedure parseProperty(node: TJSONArray; r: PStringRange);
var var
c: char; c: char;
@ -835,6 +863,11 @@ procedure parseGdbout(const str: string; var json: TJSONObject);
exit; exit;
end; end;
',': r^.popFront; ',': r^.popFront;
#10:
begin
r^.popFront;
exit;
end;
end; end;
end; end;
end; end;
@ -898,8 +931,9 @@ begin
json.Clear; json.Clear;
if str.length = 0 then if str.length = 0 then
exit; exit;
json.Arrays['CLI'] := TJSONArray.Create;
rng.init(str); rng.init(str);
json.Arrays['OUT'] := TJSONArray.Create;
json.Arrays['CLI'] := TJSONArray.Create;
while true do while true do
begin begin
if rng.empty then if rng.empty then
@ -920,11 +954,29 @@ begin
begin begin
parseCLI(json, rng.popFront); parseCLI(json, rng.popFront);
end; end;
// internal gdb messages
'&':
begin
rng.popUntil(#10);
if not rng.empty then
rng.popFront;
end;
// async notify / status / out stream when remote (@)
'=', (*'+',*)'@':
begin
rng.popUntil(#10);
if not rng.empty then
rng.popFront;
end
else
begin
if rng.startsWith('(gdb)') then
rng.popFrontN(7)
// empty line, inferior output
else
parseInferior(json, @rng);
end;
end; end;
// else line is not interesting
rng.popUntil(#10);
if not rng.empty then
rng.popFront;
end; end;
end; end;
@ -948,7 +1000,6 @@ var
line: integer = -1; line: integer = -1;
// registers data // registers data
number: integer = 0; number: integer = 0;
gprval: PtrUInt = 0;
// signal data // signal data
sigmean: string; sigmean: string;
signame: string; signame: string;
@ -983,6 +1034,7 @@ begin
infoRegs; infoRegs;
subjDebugBreak(fSubj, fullname, line, brkreason); subjDebugBreak(fSubj, fullname, line, brkreason);
end; end;
end end
else if reason = 'signal-received' then else if reason = 'signal-received' then
@ -1043,6 +1095,12 @@ begin
end; end;
val := fJson.Find('msg');
if val.isNotNil then
begin
fMsg.message(val.AsString, nil, amcMisc, amkAuto);
end;
val := fJson.Find('register-values'); val := fJson.Find('register-values');
if val.isNotNil and (val.JSONType = jtArray) then if val.isNotNil and (val.JSONType = jtArray) then
begin begin
@ -1107,7 +1165,7 @@ begin
fStackItems.assignToList(lstCallStack); fStackItems.assignToList(lstCallStack);
end; end;
if fOptions.showOutput then if fOptions.showGdbOutput then
begin begin
arr := TJSONArray(fJson.Find('CLI')); arr := TJSONArray(fJson.Find('CLI'));
if arr.isNotNil then if arr.isNotNil then
@ -1115,6 +1173,14 @@ begin
fMsg.message(arr.Strings[i], nil, amcMisc, amkBub); fMsg.message(arr.Strings[i], nil, amcMisc, amkBub);
end; end;
if fOptions.showOutput then
begin
arr := TJSONArray(fJson.Find('OUT'));
if arr.isNotNil then
for i := 0 to arr.Count-1 do
fMsg.message(arr.Strings[i], nil, amcMisc, amkBub);
end;
end; end;
procedure TCEGdbWidget.gdboutJsonize(sender: TObject); procedure TCEGdbWidget.gdboutJsonize(sender: TObject);
@ -1127,8 +1193,8 @@ begin
fLog.Clear; fLog.Clear;
fGdb.getFullLines(fLog); fGdb.getFullLines(fLog);
for str in fLog do //for str in fLog do
fMsg.message(str, nil, amcMisc, amkAuto); // fMsg.message(str, nil, amcMisc, amkAuto);
if flog.Text.isEmpty then if flog.Text.isEmpty then
exit; exit;
@ -1155,14 +1221,13 @@ end;
{$ENDREGION} {$ENDREGION}
{$REGIOn GDB commands & actions ------------------------------------------------} {$REGIOn GDB commands & actions ------------------------------------------------}
procedure TCEGdbWidget.gdbCommand(aCommand: string; gdboutProcessor: TNotifyEvent = nil); procedure TCEGdbWidget.gdbCommand(aCommand: string; gdbOutProcessor: TNotifyEvent = nil);
begin begin
if fGdb = nil then exit; if fGdb.isNil or not fGdb.Running then
if not fGdb.Running then exit; exit;
//
aCommand += #10; aCommand += #10;
if assigned(gdboutProcessor) then if assigned(gdbOutProcessor) then
fGdb.OnReadData := gdboutProcessor; fGdb.OnReadData := gdbOutProcessor;
fGdb.Input.Write(aCommand[1], aCommand.length); fGdb.Input.Write(aCommand[1], aCommand.length);
end; end;