GDBMI-Debugger: Option "gdbsNone" to start without internal start break.

This may not work on all platforms, depending on how gdb reports the target-PID.
This should work for all/any gdb-server session

git-svn-id: trunk@61588 -
This commit is contained in:
martin 2019-07-14 19:10:35 +00:00
parent 7925f988ef
commit 1caa4b3b33

View File

@ -94,6 +94,7 @@ type
TGDBMITargetFlag = ( TGDBMITargetFlag = (
tfHasSymbols, // Debug symbols are present tfHasSymbols, // Debug symbols are present
tfPidDetectionDone,
tfRTLUsesRegCall, // the RTL is compiled with RegCall calling convention tfRTLUsesRegCall, // the RTL is compiled with RegCall calling convention
tfClassIsPointer, // with dwarf class names are pointer. with stabs they are not tfClassIsPointer, // with dwarf class names are pointer. with stabs they are not
tfExceptionIsPointer, // Can happen, if stabs and dwarf are mixed tfExceptionIsPointer, // Can happen, if stabs and dwarf are mixed
@ -135,7 +136,7 @@ type
gdfeNone, gdfeDefault, gdfeEscSpace, gdfeQuote gdfeNone, gdfeDefault, gdfeEscSpace, gdfeQuote
); );
TGDBMIDebuggerStartBreak = ( TGDBMIDebuggerStartBreak = (
gdsbDefault, gdsbEntry, gdsbMainAddr, gdsbMain, gdsbAddZero gdsbDefault, gdbsNone, gdsbEntry, gdsbMainAddr, gdsbMain, gdsbAddZero
); );
TGDBMIUseNoneMiRunCmdsState = ( TGDBMIUseNoneMiRunCmdsState = (
gdnmNever, gdnmAlways, gdnmFallback gdnmNever, gdnmAlways, gdnmFallback
@ -818,6 +819,7 @@ type
FCommandProcessingLock: Integer; FCommandProcessingLock: Integer;
FMainAddrBreak: TGDBMIInternalBreakPoint; FMainAddrBreak: TGDBMIInternalBreakPoint;
FPasMainAddrBreak: TGDBMIInternalBreakPoint;
FBreakAtMain: TDBGBreakPoint; FBreakAtMain: TDBGBreakPoint;
FBreakErrorBreak: TGDBMIInternalBreakPoint; FBreakErrorBreak: TGDBMIInternalBreakPoint;
FRunErrorBreak: TGDBMIInternalBreakPoint; FRunErrorBreak: TGDBMIInternalBreakPoint;
@ -2166,9 +2168,10 @@ procedure TGDBMIDbgInstructionQueue.HandleGdbDataBeforeInstruction(var AData: St
// check internal error // check internal error
Debugger.CheckForInternalError(Line, TheInstruction.DebugText); Debugger.CheckForInternalError(Line, TheInstruction.DebugText);
end; end;
var
s: String;
begin begin
if AData <> '' if AData <> ''
then case AData[1] of then case AData[1] of
@ -2180,6 +2183,13 @@ begin
//'=': DoMsgAsync(AData); //'=': DoMsgAsync(AData);
end; end;
if not (tfPidDetectionDone in TGDBMIDebugger(Debugger).FTargetInfo.TargetFlags) then begin
s := GetPart(['Switching to process '], [' local', ']'], AData, True);
TGDBMIDebugger(Debugger).FTargetInfo.TargetPID := StrToIntDef(s, 0);
if TGDBMIDebugger(Debugger).FTargetInfo.TargetPID <> 0 then
Include(TGDBMIDebugger(Debugger).FTargetInfo.TargetFlags, tfPidDetectionDone);
end;
inherited HandleGdbDataBeforeInstruction(AData, SkipData, TheInstruction); inherited HandleGdbDataBeforeInstruction(AData, SkipData, TheInstruction);
end; end;
@ -2341,16 +2351,7 @@ function TGDBMIDebuggerInstruction.ProcessInputFromGdb(const AData: String): Boo
end; end;
procedure DoMsgAsync(Line: String); procedure DoMsgAsync(Line: String);
var
S: String;
begin begin
S := GetPart('=', ',', Line, False, False);
if s = 'thread-group-started' then begin // thread-group-started // needed in RunToMain
// Todo, store in seperate field
if FCmd is TGDBMIDebuggerCommandStartDebugging then
FLogWarnings := FLogWarnings + Line + LineEnding;
end;
FCmd.FTheDebugger.DoNotifyAsync(Line); FCmd.FTheDebugger.DoNotifyAsync(Line);
end; end;
@ -2716,8 +2717,12 @@ var
s: String; s: String;
List: TGDBMINameValueList; List: TGDBMINameValueList;
begin begin
if TargetInfo^.TargetPID <> 0 then if (TargetInfo^.TargetPID <> 0) or
(tfPidDetectionDone in TargetInfo^.TargetFlags)
then
exit; exit;
Include(TargetInfo^.TargetFlags, tfPidDetectionDone);
(* PID via "info program" (* PID via "info program"
Somme linux, gdb 7.1 Somme linux, gdb 7.1
@ -2942,7 +2947,7 @@ var
end; end;
var var
S: String; S, s2: String;
idx: Integer; idx: Integer;
{$IFDEF DBG_ASYNC_WAIT} {$IFDEF DBG_ASYNC_WAIT}
GotPrompt: integer; GotPrompt: integer;
@ -3026,6 +3031,13 @@ begin
DebugLn(DBG_VERBOSE, '[DBGTGT] ', S); DebugLn(DBG_VERBOSE, '[DBGTGT] ', S);
end; end;
end; end;
if not (tfPidDetectionDone in FTheDebugger.FTargetInfo.TargetFlags) then begin
s2 := GetPart(['Switching to process '], [' local', ']'], S, True);
FTheDebugger.FTargetInfo.TargetPID := StrToIntDef(s2, 0);
if FTheDebugger.FTargetInfo.TargetPID <> 0 then
Include(FTheDebugger.FTargetInfo.TargetFlags, tfPidDetectionDone);
end;
Break; Break;
end; end;
@ -5060,7 +5072,7 @@ function TGDBMIDebuggerCommandStartDebugging.DoExecute: Boolean;
MaybeAddMainBrk(mtEntry, 0, false); MaybeAddMainBrk(mtEntry, 0, false);
MaybeAddMainBrk(mtMainAddr, 0); MaybeAddMainBrk(mtMainAddr, 0);
end; end;
else begin // gdsbDefault gdsbDefault: begin
// SetByName: "main", this is the best aproach, unless any library also exports main. // SetByName: "main", this is the best aproach, unless any library also exports main.
MaybeAddMainBrk(mtMain, -1); MaybeAddMainBrk(mtMain, -1);
MaybeAddMainBrk(mtEntry, -1, true); // Previous versions used "+0" as 2nd in the list MaybeAddMainBrk(mtEntry, -1, true); // Previous versions used "+0" as 2nd in the list
@ -5069,6 +5081,7 @@ function TGDBMIDebuggerCommandStartDebugging.DoExecute: Boolean;
// set only, if no other is set (e.g. 2nd attempt) // set only, if no other is set (e.g. 2nd attempt)
MaybeAddMainBrk(mtEntry, 0, false); MaybeAddMainBrk(mtEntry, 0, false);
end; end;
else ;// gdbsNone
end; end;
Result := bcnt < FTheDebugger.FMainAddrBreak.BreakSetCount; // added new breaks Result := bcnt < FTheDebugger.FMainAddrBreak.BreakSetCount; // added new breaks
end; end;
@ -5077,14 +5090,6 @@ function TGDBMIDebuggerCommandStartDebugging.DoExecute: Boolean;
var var
s: String; s: String;
begin begin
s := GetPart(['=thread-group-started,'], [LineEnding], ALogTxt, True, False);
if s <> '' then
s := GetPart(['pid="'], ['"'], s, True, False);
if s <> '' then begin
Result := StrToIntDef(s, 0);
if Result <> 0 then exit;
end;
s := GetPart(['process '], [' local', ']'], ALogTxt, True); s := GetPart(['process '], [' local', ']'], ALogTxt, True);
Result := StrToIntDef(s, 0); Result := StrToIntDef(s, 0);
end; end;
@ -5127,7 +5132,6 @@ function TGDBMIDebuggerCommandStartDebugging.DoExecute: Boolean;
BrkErr: Boolean; BrkErr: Boolean;
begin begin
EntryPointNum := StrToQWordDef(EntryPoint, 0); EntryPointNum := StrToQWordDef(EntryPoint, 0);
TargetInfo^.TargetPID := 0;
FDidKillNow := False; FDidKillNow := False;
// TODO: async // TODO: async
@ -5160,8 +5164,11 @@ function TGDBMIDebuggerCommandStartDebugging.DoExecute: Boolean;
exit; exit;
end; end;
s := r.Values + FLogWarnings; s := r.Values + FLogWarnings;
if TargetInfo^.TargetPID = 0 then if TargetInfo^.TargetPID = 0 then begin
TargetInfo^.TargetPID := ParseLogForPid(s); TargetInfo^.TargetPID := ParseLogForPid(s);
if TargetInfo^.TargetPID <> 0 then
Include(TargetInfo^.TargetFlags, tfPidDetectionDone);
end;
s2 := ''; s2 := '';
if R.State = dsRun if R.State = dsRun
@ -5285,6 +5292,9 @@ function TGDBMIDebuggerCommandStartDebugging.DoExecute: Boolean;
exit; exit;
TargetInfo^.TargetPID := ParseLogForPid(rval); TargetInfo^.TargetPID := ParseLogForPid(rval);
if TargetInfo^.TargetPID <> 0 then
Include(TargetInfo^.TargetFlags, tfPidDetectionDone);
if TargetInfo^.TargetPID <> 0 then if TargetInfo^.TargetPID <> 0 then
exit; exit;
@ -5361,6 +5371,8 @@ begin
TargetInfo^.TargetCPU := ''; TargetInfo^.TargetCPU := '';
TargetInfo^.TargetOS := osUnknown; TargetInfo^.TargetOS := osUnknown;
Exclude(TargetInfo^.TargetFlags, tfPidDetectionDone);
TargetInfo^.TargetPID := 0;
// try to retrieve the filetype and program entry point // try to retrieve the filetype and program entry point
FileType := ''; FileType := '';
@ -5389,23 +5401,25 @@ begin
(* We need a breakpoint at entry-point or main, to continue initialization (* We need a breakpoint at entry-point or main, to continue initialization
"main" could map to more than one location, so we try entry point first "main" could map to more than one location, so we try entry point first
*) *)
RunToMain(EntryPoint); if DebuggerProperties.InternalStartBreak <> gdbsNone then begin
RunToMain(EntryPoint);
if DebuggerState = dsStop
then begin
Result := False;
FSuccess := False;
Exit;
end;
if DebuggerState = dsError
then begin
Result := False;
FSuccess := False;
Exit;
end;
end;
DefaultTimeOut := DebuggerProperties.TimeoutForEval; // Getting address for breakpoints may need timeout DefaultTimeOut := DebuggerProperties.TimeoutForEval; // Getting address for breakpoints may need timeout
if DebuggerState = dsStop
then begin
Result := False;
FSuccess := False;
Exit;
end;
if DebuggerState = dsError
then begin
Result := False;
FSuccess := False;
Exit;
end;
DebugLn(DBG_VERBOSE, '[Debugger] Target PID: %u', [TargetInfo^.TargetPID]); DebugLn(DBG_VERBOSE, '[Debugger] Target PID: %u', [TargetInfo^.TargetPID]);
Exclude(FTheDebugger.FDebuggerFlags, dfSetBreakFailed); Exclude(FTheDebugger.FDebuggerFlags, dfSetBreakFailed);
@ -5436,12 +5450,25 @@ begin
FTheDebugger.RunQueue; // run all the breakpoints FTheDebugger.RunQueue; // run all the breakpoints
Application.ProcessMessages; // workaround, allow source-editor to queue line info request (Async call) Application.ProcessMessages; // workaround, allow source-editor to queue line info request (Async call)
if FTheDebugger.FBreakAtMain <> nil if DebuggerProperties.InternalStartBreak = gdbsNone then begin
then begin if FContinueCommand = nil then begin
CanContinue := False; // set breakpoint for first line (Step-In/Over instead of run)
TGDBMIBreakPoint(FTheDebugger.FBreakAtMain).Hit(CanContinue); FTheDebugger.FPasMainAddrBreak.SetByName(Self);
end;
ReleaseRefAndNil(FContinueCommand);
FContinueCommand := TGDBMIDebuggerCommandExecute.Create(FTheDebugger, ectRun);
CanContinue := True;
StoppedAtEntryPoint := False;
end end
else CanContinue := True;
else begin
if FTheDebugger.FBreakAtMain <> nil
then begin
CanContinue := False;
TGDBMIBreakPoint(FTheDebugger.FBreakAtMain).Hit(CanContinue);
end
else CanContinue := True;
end;
//if FTheDebugger.DebuggerFlags * [dfSetBreakFailed, dfSetBreakPending] <> [] then begin //if FTheDebugger.DebuggerFlags * [dfSetBreakFailed, dfSetBreakPending] <> [] then begin
// if FTheDebugger.OnFeedback // if FTheDebugger.OnFeedback
@ -5616,9 +5643,13 @@ begin
NewPID := StrToIntDef(FProcessID, 0); NewPID := StrToIntDef(FProcessID, 0);
end; end;
TargetInfo^.TargetPID := NewPID; if NewPID <> 0 then
TargetInfo^.TargetPID := NewPID;
DetectTargetPid(True); if NewPID = 0 then
DetectTargetPid(True);
include(TargetInfo^.TargetFlags, tfPidDetectionDone);
if TargetInfo^.TargetPID = 0 then begin if TargetInfo^.TargetPID = 0 then begin
ExecuteCommand('detach', [], R); ExecuteCommand('detach', [], R);
SetDebuggerErrorState(Format(gdbmiCommandStartMainRunNoPIDError, [LineEnding])); SetDebuggerErrorState(Format(gdbmiCommandStartMainRunNoPIDError, [LineEnding]));
@ -6279,6 +6310,13 @@ begin
Exit; Exit;
end; end;
if FTheDebugger.FPasMainAddrBreak.MatchId(BreakID)
then begin
SetDebuggerState(dsPause); // after GetLocation => dsPause may run stack, watches etc
FTheDebugger.DoCurrent(FTheDebugger.FCurrentLocation);
exit;
end;
if FTheDebugger.FBreakErrorBreak.MatchId(BreakID) if FTheDebugger.FBreakErrorBreak.MatchId(BreakID)
then begin then begin
ProcessBreak; // will set dsPause / unless CanContinue ProcessBreak; // will set dsPause / unless CanContinue
@ -7787,6 +7825,7 @@ end;
constructor TGDBMIDebuggerBase.Create(const AExternalDebugger: String); constructor TGDBMIDebuggerBase.Create(const AExternalDebugger: String);
begin begin
FMainAddrBreak := TGDBMIInternalBreakPoint.Create('main'); FMainAddrBreak := TGDBMIInternalBreakPoint.Create('main');
FPasMainAddrBreak:= TGDBMIInternalBreakPoint.Create('pascalmain');
FBreakErrorBreak := TGDBMIInternalBreakPoint.Create('FPC_BREAK_ERROR'); FBreakErrorBreak := TGDBMIInternalBreakPoint.Create('FPC_BREAK_ERROR');
FRunErrorBreak := TGDBMIInternalBreakPoint.Create('FPC_RUNERROR'); FRunErrorBreak := TGDBMIInternalBreakPoint.Create('FPC_RUNERROR');
FExceptionBreak := TGDBMIInternalBreakPoint.Create('FPC_RAISEEXCEPTION'); FExceptionBreak := TGDBMIInternalBreakPoint.Create('FPC_RAISEEXCEPTION');
@ -7905,6 +7944,7 @@ begin
FreeAndNil(FTypeRequestCache); FreeAndNil(FTypeRequestCache);
FreeAndNil(FMaxLineForUnitCache); FreeAndNil(FMaxLineForUnitCache);
FreeAndNil(FMainAddrBreak); FreeAndNil(FMainAddrBreak);
FreeAndNil(FPasMainAddrBreak);
FreeAndNil(FBreakErrorBreak); FreeAndNil(FBreakErrorBreak);
FreeAndNil(FRunErrorBreak); FreeAndNil(FRunErrorBreak);
FreeAndNil(FExceptionBreak); FreeAndNil(FExceptionBreak);
@ -8204,10 +8244,25 @@ end;
procedure TGDBMIDebuggerBase.AddThreadGroup(const S: String); procedure TGDBMIDebuggerBase.AddThreadGroup(const S: String);
var var
List: TGDBMINameValueList; List: TGDBMINameValueList;
s1, s2: String;
p: LongInt;
begin begin
List := TGDBMINameValueList.Create(S); List := TGDBMINameValueList.Create(S);
FThreadGroups.Values[List.Values['id']] := List.Values['pid']; FThreadGroups.Values[List.Values['id']] := List.Values['pid'];
List.Free; List.Free;
if not (tfPidDetectionDone in FTargetInfo.TargetFlags) then begin
s1 := S;
s2 := GetPart(['=thread-group-started,'], [LineEnding], s1, True, False);
if s2 <> '' then begin
s2 := GetPart(['pid="'], ['"'], s2, True, False);
Include(FTargetInfo.TargetFlags, tfPidDetectionDone); // only consider the first one
if s2 <> '' then begin
p := StrToIntDef(s2, 0);
FTargetInfo.TargetPID := p;
end;
end;
end;
end; end;
procedure TGDBMIDebuggerBase.RemoveThreadGroup(const S: String); procedure TGDBMIDebuggerBase.RemoveThreadGroup(const S: String);
@ -8311,11 +8366,11 @@ begin
Threads.Changed; Threads.Changed;
end; end;
end; end;
2: DoDbgEvent(ecModule, etModuleLoad, Line); 2: DoDbgEvent(ecModule, etModuleLoad, Line); //shlibs
3: DoDbgEvent(ecModule, etModuleLoad, ParseLibraryLoaded(Line)); 3: DoDbgEvent(ecModule, etModuleLoad, ParseLibraryLoaded(Line));
4: DoDbgEvent(ecModule, etModuleUnload, ParseLibraryUnloaded(Line)); 4: DoDbgEvent(ecModule, etModuleUnload, ParseLibraryUnloaded(Line));
5: DoDbgEvent(ecModule, etDefault, Line); 5: DoDbgEvent(ecModule, etDefault, Line); //shlibs
6: AddThreadGroup(Line); 6: AddThreadGroup(Line); //thread-group-started
7: RemoveThreadGroup(Line); 7: RemoveThreadGroup(Line);
8: DoDbgEvent(ecThread, etThreadStart, ParseThread(Line, EventText)); 8: DoDbgEvent(ecThread, etThreadStart, ParseThread(Line, EventText));
9: DoDbgEvent(ecThread, etThreadExit, ParseThread(Line, EventText)); 9: DoDbgEvent(ecThread, etThreadExit, ParseThread(Line, EventText));