mirror of
				https://gitlab.com/freepascal.org/lazarus/lazarus.git
				synced 2025-10-31 21:09:28 +01:00 
			
		
		
		
	
		
			
				
	
	
		
			1017 lines
		
	
	
		
			32 KiB
		
	
	
	
		
			ObjectPascal
		
	
	
	
	
	
			
		
		
	
	
			1017 lines
		
	
	
		
			32 KiB
		
	
	
	
		
			ObjectPascal
		
	
	
	
	
	
| unit GDBMIDebugInstructions;
 | |
| 
 | |
| {$mode objfpc}{$H+}
 | |
| 
 | |
| interface
 | |
| 
 | |
| uses
 | |
|   Classes, SysUtils, math, CmdLineDebugger, GDBMIMiscClasses, LazLoggerBase, LazClasses;
 | |
| 
 | |
| type
 | |
| 
 | |
|   { TGDBMICmdLineDebugger }
 | |
| 
 | |
|   TGDBMICmdLineDebugger = class(TCmdLineDebugger)
 | |
|   protected
 | |
|     FErrorHandlingFlags: set of (ehfDeferReadWriteError, ehfGotReadError, ehfGotWriteError);
 | |
|     procedure DoReadError; override;
 | |
|     procedure DoWriteError; override;
 | |
|   end;
 | |
| 
 | |
|   { TGDBInstruction }
 | |
| 
 | |
|   TGDBInstructionFlag = (
 | |
|     ifRequiresThread,
 | |
|     ifRequiresStackFrame
 | |
|   );
 | |
|   TGDBInstructionFlags = set of TGDBInstructionFlag;
 | |
| 
 | |
|   TGDBInstructionResultFlag = (
 | |
|     ifrComleted,
 | |
|     ifrFailed
 | |
|   );
 | |
|   TGDBInstructionResultFlags = set of TGDBInstructionResultFlag;
 | |
| 
 | |
|   TGDBInstructionErrorFlag = (
 | |
|     ifeContentError,  // the imput from gdb was not in the expected format
 | |
|     ifeWriteError,    // writing to gdb (pipe) failed
 | |
|     ifeReadError,
 | |
|     ifeGdbNotRunning,
 | |
|     ifeTimedOut,
 | |
|     ifeRecoveredTimedOut, // not an error
 | |
|     ifeInvalidStackFrame,
 | |
|     ifeInvalidThreadId,
 | |
|     ifeQueueContextError  // The thread or stack command went ok, but something else interfered with setting th econtext
 | |
|   );
 | |
|   TGDBInstructionErrorFlags = set of TGDBInstructionErrorFlag;
 | |
| 
 | |
|   TGDBInstructionQueue = class;
 | |
| 
 | |
|   { TGDBInstruction }
 | |
| 
 | |
|   TGDBInstruction = class(TRefCountedObject)
 | |
|   private
 | |
|     FCommand: String;
 | |
|     FFlags: TGDBInstructionFlags;
 | |
|     FStackFrame: Integer;
 | |
|     FThreadId: Integer;
 | |
|   protected
 | |
|     FResultFlags: TGDBInstructionResultFlags;
 | |
|     FErrorFlags: TGDBInstructionErrorFlags;
 | |
|     FTimeOut: Integer;
 | |
|     procedure SendCommandDataToGDB(AQueue: TGDBInstructionQueue); virtual;
 | |
|     function  ProcessInputFromGdb(const AData: String): Boolean; virtual; abstract; // True if data was handled
 | |
| 
 | |
|     function  GetTimeOutVerifier: TGDBInstruction; virtual;
 | |
|     procedure Init; virtual;
 | |
|     procedure InternalCreate(ACommand: String;
 | |
|                              AThread, AFrame: Integer; // ifRequiresThread, ifRequiresStackFrame will always be included
 | |
|                              AFlags: TGDBInstructionFlags;
 | |
|                              ATimeOut: Integer
 | |
|                             );
 | |
|   public
 | |
|     constructor Create(ACommand: String;
 | |
|                        AFlags: TGDBInstructionFlags = [];
 | |
|                        ATimeOut: Integer = 0
 | |
|                       );
 | |
|     constructor Create(ACommand: String;
 | |
|                        AThread: Integer;         // ifRequiresThread will always be included
 | |
|                        AOtherFlags: TGDBInstructionFlags = [];
 | |
|                        ATimeOut: Integer = 0
 | |
|                       );
 | |
|     constructor Create(ACommand: String;
 | |
|                        AThread, AFrame: Integer; // ifRequiresThread, ifRequiresStackFrame will always be included
 | |
|                        AOtherFlags: TGDBInstructionFlags = [];
 | |
|                        ATimeOut: Integer = 0
 | |
|                       );
 | |
|     function IsSuccess: Boolean;
 | |
|     function IsCompleted: boolean; virtual;                                        // No more InputFromGdb required
 | |
| 
 | |
|     procedure MarkAsSuccess;
 | |
|     procedure HandleWriteError({%H-}ASender: TGDBInstruction); virtual;
 | |
|     procedure HandleReadError; virtual;
 | |
|     procedure HandleTimeOut; virtual;
 | |
|     procedure HandleRecoveredTimeOut; virtual;
 | |
|     procedure HandleNoGdbRunning; virtual;
 | |
|     procedure HandleContentError; virtual;
 | |
|     procedure HandleError(AnError: TGDBInstructionErrorFlag; AMarkAsFailed: Boolean = True); virtual;
 | |
|     function  DebugText: String;
 | |
| 
 | |
|     property Command: String read FCommand;
 | |
|     property ThreadId: Integer read FThreadId;
 | |
|     property StackFrame: Integer read FStackFrame;
 | |
|     property Flags: TGDBInstructionFlags read FFlags;
 | |
|     property ResultFlags: TGDBInstructionResultFlags read FResultFlags;
 | |
|     property ErrorFlags: TGDBInstructionErrorFlags read FErrorFlags;
 | |
|     property TimeOut: Integer read FTimeOut;
 | |
|   end;
 | |
| 
 | |
|   { TGDBInstructionVerifyTimeOut }
 | |
| 
 | |
|   TGDBInstructionVerifyTimeOutState = (
 | |
|     vtSent, vtError,
 | |
|     vtGotPrompt,
 | |
|     vtGotPrompt7, vtGotPrompt7gdb, vtGotPrompt7and7, vtGotPrompt7and7gdb,
 | |
|     vtGotPrompt1, vtGotPrompt1gdb,
 | |
|     vtGot7, vtGot7gdb, vtGot7and7, vtGot7and7gdb, vtGot1, vtGot1gdb
 | |
|   );
 | |
| 
 | |
|   TGDBInstructionVerifyTimeOut = class(TGDBInstruction)
 | |
|   private
 | |
|     FRunnigInstruction: TGDBInstruction;
 | |
|     FList: TGDBMINameValueList;
 | |
|     FPromptAfterErrorCount: Integer;
 | |
|     FVal7Data: String;
 | |
|     FState: TGDBInstructionVerifyTimeOutState;
 | |
|   protected
 | |
|     procedure SendCommandDataToGDB(AQueue: TGDBInstructionQueue); override;
 | |
|     function ProcessInputFromGdb(const AData: String): Boolean; override;
 | |
| 
 | |
|     function GetTimeOutVerifier: TGDBInstruction; override;
 | |
|     function DebugText: String;
 | |
|   public
 | |
|     constructor Create(ARunnigInstruction: TGDBInstruction);
 | |
|     destructor Destroy; override;
 | |
| 
 | |
|     procedure HandleWriteError(ASender: TGDBInstruction); override;
 | |
|     procedure HandleReadError; override;
 | |
|     procedure HandleTimeOut; override;
 | |
|     procedure HandleNoGdbRunning; override;
 | |
|   end;
 | |
| 
 | |
|   { TGDBInstructionChangeThread }
 | |
| 
 | |
|   TGDBInstructionChangeThread = class(TGDBInstruction)
 | |
|   private
 | |
|     FSelThreadId: Integer;
 | |
|     FQueue: TGDBInstructionQueue;
 | |
|     FDone: Boolean;
 | |
|   protected
 | |
|     procedure SendCommandDataToGDB(AQueue: TGDBInstructionQueue); override;
 | |
|     function ProcessInputFromGdb(const AData: String): Boolean; override;
 | |
|     function DebugText: String;
 | |
|   public
 | |
|     constructor Create(AQueue: TGDBInstructionQueue; AThreadId: Integer);
 | |
| 
 | |
|     procedure HandleError(AnError: TGDBInstructionErrorFlag; AMarkAsFailed: Boolean = True);
 | |
|       override;
 | |
|   end;
 | |
| 
 | |
|   { TGDBInstructionChangeStackFrame }
 | |
| 
 | |
|   TGDBInstructionChangeStackFrame = class(TGDBInstruction)
 | |
|   private
 | |
|     FSelStackFrame: Integer;
 | |
|     FQueue: TGDBInstructionQueue;
 | |
|     FDone: Boolean;
 | |
|   protected
 | |
|     procedure SendCommandDataToGDB(AQueue: TGDBInstructionQueue); override;
 | |
|     function ProcessInputFromGdb(const AData: String): Boolean; override;
 | |
|     function DebugText: String;
 | |
|   public
 | |
|     constructor Create(AQueue: TGDBInstructionQueue; AFrame: Integer);
 | |
|     procedure HandleError(AnError: TGDBInstructionErrorFlag; AMarkAsFailed: Boolean = True);
 | |
|       override;
 | |
|   end;
 | |
| 
 | |
|   { TGDBInstructionQueue }
 | |
| 
 | |
|   TGDBInstructionQueueFlag = (
 | |
|     ifqValidThread,
 | |
|     ifqValidStackFrame
 | |
|   );
 | |
|   TGDBInstructionQueueFlags = set of TGDBInstructionQueueFlag;
 | |
| 
 | |
|   TGDBInstructionQueue = class
 | |
|   private
 | |
|     FCurrentInstruction: TGDBInstruction;
 | |
|     FCurrentStackFrame: Integer;
 | |
|     FCurrentThreadId: Integer;
 | |
|     FExeCurInstructionStamp: Int64;
 | |
|     FDebugger: TGDBMICmdLineDebugger;
 | |
|     FFlags: TGDBInstructionQueueFlags;
 | |
| 
 | |
|     procedure ExecuteCurrentInstruction;
 | |
|     procedure FinishCurrentInstruction;
 | |
|     procedure SetCurrentInstruction(AnInstruction: TGDBInstruction);
 | |
|     function  HasCorrectThreadIdFor(AnInstruction: TGDBInstruction): Boolean;
 | |
|     function  HasCorrectFrameFor(AnInstruction: TGDBInstruction): Boolean;
 | |
|   protected
 | |
|     function SendDataToGDB(ASender: TGDBInstruction; AData: String): Boolean;
 | |
|     function SendDataToGDB(ASender: TGDBInstruction; AData: String; const AValues: array of const): Boolean;
 | |
|     procedure HandleGdbDataBeforeInstruction(var {%H-}AData: String; var {%H-}SkipData: Boolean;
 | |
|                                              const {%H-}TheInstruction: TGDBInstruction); virtual;
 | |
|     procedure HandleGdbDataAfterInstruction(var {%H-}AData: String; const {%H-}Handled: Boolean;
 | |
|                                              const {%H-}TheInstruction: TGDBInstruction); virtual;
 | |
|     function GetSelectThreadInstruction(AThreadId: Integer): TGDBInstruction; virtual;
 | |
|     function GetSelectFrameInstruction(AFrame: Integer): TGDBInstruction; virtual;
 | |
| 
 | |
|     property Debugger: TGDBMICmdLineDebugger read FDebugger;
 | |
|   public
 | |
|     constructor Create(ADebugger: TGDBMICmdLineDebugger);
 | |
|     procedure InvalidateThredAndFrame(AStackFrameOnly: Boolean = False);
 | |
|     procedure SetKnownThread(AThread: Integer);
 | |
|     procedure SetKnownThreadAndFrame(AThread, AFrame: Integer);
 | |
|     procedure RunInstruction(AnInstruction: TGDBInstruction); // Wait for instruction to be finished, not queuing
 | |
|     property CurrentThreadId: Integer read FCurrentThreadId;
 | |
|     property CurrentStackFrame: Integer read FCurrentStackFrame;
 | |
|     property Flags: TGDBInstructionQueueFlags read FFlags;
 | |
|   end;
 | |
| 
 | |
| function dbgs(AState: TGDBInstructionVerifyTimeOutState): String; overload;
 | |
| function dbgs(AFlag: TGDBInstructionQueueFlag): String; overload;
 | |
| function dbgs(AFlags: TGDBInstructionQueueFlags): String; overload;
 | |
| function dbgs(AFlag: TGDBInstructionFlag): String; overload;
 | |
| function dbgs(AFlags: TGDBInstructionFlags): String; overload;
 | |
| 
 | |
| implementation
 | |
| 
 | |
| var
 | |
|   DBGMI_TIMEOUT_DEBUG, DBG_THREAD_AND_FRAME, DBG_VERBOSE: PLazLoggerLogGroup;
 | |
| 
 | |
| const
 | |
|   TIMEOUT_AFTER_WRITE_ERROR          = 50;
 | |
|   TIMEOUT_FOR_QUEUE_INSTR      = 50; // select thread/frame
 | |
|   TIMEOUT_FOR_SYNC_AFTER_TIMEOUT     = 2500; // extra timeout, while trying to recover from a suspected timeout
 | |
|   TIMEOUT_FOR_SYNC_AFTER_TIMEOUT_MAX = 3000; // upper limit, when using 2*original_timeout
 | |
| 
 | |
| function dbgs(AState: TGDBInstructionVerifyTimeOutState): String; overload;
 | |
| begin
 | |
|   writestr(Result{%H-}, AState);
 | |
| end;
 | |
| 
 | |
| function dbgs(AFlag: TGDBInstructionQueueFlag): String;
 | |
| begin
 | |
|   writestr(Result{%H-}, AFlag);
 | |
| end;
 | |
| 
 | |
| function dbgs(AFlags: TGDBInstructionQueueFlags): String;
 | |
| var
 | |
|   i: TGDBInstructionQueueFlag;
 | |
| begin
 | |
|   Result := '';
 | |
|   for i := low(TGDBInstructionQueueFlags) to high(TGDBInstructionQueueFlags) do
 | |
|     if i in AFlags then
 | |
|       if Result = '' then
 | |
|         Result := Result + dbgs(i)
 | |
|       else
 | |
|         Result := Result + ', ' +dbgs(i);
 | |
|   if Result <> '' then
 | |
|     Result := '[' + Result + ']';
 | |
| end;
 | |
| 
 | |
| function dbgs(AFlag: TGDBInstructionFlag): String;
 | |
| begin
 | |
|   writestr(Result{%H-}, AFlag);
 | |
| end;
 | |
| 
 | |
| function dbgs(AFlags: TGDBInstructionFlags): String;
 | |
| var
 | |
|   i: TGDBInstructionFlag;
 | |
| begin
 | |
|   Result := '';
 | |
|   for i := low(TGDBInstructionFlags) to high(TGDBInstructionFlags) do
 | |
|     if i in AFlags then
 | |
|       if Result = '' then
 | |
|         Result := Result + dbgs(i)
 | |
|       else
 | |
|         Result := Result + ', ' +dbgs(i);
 | |
|   if Result <> '' then
 | |
|     Result := '[' + Result + ']';
 | |
| end;
 | |
| 
 | |
| { TGDBMICmdLineDebugger }
 | |
| 
 | |
| procedure TGDBMICmdLineDebugger.DoReadError;
 | |
| begin
 | |
|   include(FErrorHandlingFlags, ehfGotReadError);
 | |
|   if not(ehfDeferReadWriteError in FErrorHandlingFlags)
 | |
|   then inherited DoReadError;
 | |
| end;
 | |
| 
 | |
| procedure TGDBMICmdLineDebugger.DoWriteError;
 | |
| begin
 | |
|   include(FErrorHandlingFlags, ehfGotWriteError);
 | |
|   if not(ehfDeferReadWriteError in FErrorHandlingFlags)
 | |
|   then inherited DoWriteError;
 | |
| end;
 | |
| 
 | |
| { TGDBInstruction }
 | |
| 
 | |
| procedure TGDBInstruction.SendCommandDataToGDB(AQueue: TGDBInstructionQueue);
 | |
| begin
 | |
|   AQueue.SendDataToGDB(Self, FCommand);
 | |
| end;
 | |
| 
 | |
| function TGDBInstruction.IsCompleted: boolean;
 | |
| begin
 | |
|   Result := FResultFlags * [ifrComleted, ifrFailed] <> [];
 | |
| end;
 | |
| 
 | |
| procedure TGDBInstruction.MarkAsSuccess;
 | |
| begin
 | |
|   Include(FResultFlags, ifrComleted);
 | |
| end;
 | |
| 
 | |
| procedure TGDBInstruction.HandleWriteError(ASender: TGDBInstruction);
 | |
| begin
 | |
|   HandleError(ifeWriteError, False);
 | |
|   if (FTimeOut = 0) or (FTimeOut > TIMEOUT_AFTER_WRITE_ERROR) then
 | |
|     FTimeOut := TIMEOUT_AFTER_WRITE_ERROR;
 | |
| end;
 | |
| 
 | |
| procedure TGDBInstruction.HandleReadError;
 | |
| begin
 | |
|   HandleError(ifeReadError, True);
 | |
| end;
 | |
| 
 | |
| procedure TGDBInstruction.HandleTimeOut;
 | |
| begin
 | |
|   HandleError(ifeTimedOut, True);
 | |
| end;
 | |
| 
 | |
| procedure TGDBInstruction.HandleRecoveredTimeOut;
 | |
| begin
 | |
|   Include(FErrorFlags, ifeRecoveredTimedOut);
 | |
| end;
 | |
| 
 | |
| procedure TGDBInstruction.HandleNoGdbRunning;
 | |
| begin
 | |
|   HandleError(ifeGdbNotRunning, True);
 | |
| end;
 | |
| 
 | |
| procedure TGDBInstruction.HandleContentError;
 | |
| begin
 | |
|   HandleError(ifeContentError, True);
 | |
| end;
 | |
| 
 | |
| procedure TGDBInstruction.HandleError(AnError: TGDBInstructionErrorFlag;
 | |
|   AMarkAsFailed: Boolean = True);
 | |
| begin
 | |
|   if AMarkAsFailed then
 | |
|     Include(FResultFlags, ifrFailed);
 | |
|   Include(FErrorFlags,  AnError);
 | |
| end;
 | |
| 
 | |
| function TGDBInstruction.GetTimeOutVerifier: TGDBInstruction;
 | |
| begin
 | |
|   if (ifeWriteError in ErrorFlags) then
 | |
|     Result := nil
 | |
|   else
 | |
|     Result := TGDBInstructionVerifyTimeOut.Create(Self);
 | |
| end;
 | |
| 
 | |
| function TGDBInstruction.DebugText: String;
 | |
| begin
 | |
|   Result := ClassName + ': "' + FCommand + '", ' + dbgs(FFlags);
 | |
|   if ifRequiresThread in FFlags then
 | |
|     Result := Result + ' Thr=' + IntToStr(FThreadId);
 | |
|   if ifRequiresStackFrame in FFlags then
 | |
|     Result := Result + ' Frm=' + IntToStr(FStackFrame);
 | |
| end;
 | |
| 
 | |
| procedure TGDBInstruction.Init;
 | |
| begin
 | |
|   //
 | |
| end;
 | |
| 
 | |
| procedure TGDBInstruction.InternalCreate(ACommand: String; AThread, AFrame: Integer;
 | |
|   AFlags: TGDBInstructionFlags; ATimeOut: Integer);
 | |
| begin
 | |
|   FCommand := ACommand;
 | |
|   FThreadId   := AThread;
 | |
|   FStackFrame := AFrame;
 | |
|   FFlags := AFlags;
 | |
|   FTimeOut := ATimeOut;
 | |
| end;
 | |
| 
 | |
| constructor TGDBInstruction.Create(ACommand: String; AFlags: TGDBInstructionFlags;
 | |
|   ATimeOut: Integer = 0);
 | |
| begin
 | |
|   InternalCreate(ACommand, -1, -1, AFlags, ATimeOut);
 | |
|   Init;
 | |
| end;
 | |
| 
 | |
| constructor TGDBInstruction.Create(ACommand: String; AThread: Integer;
 | |
|   AOtherFlags: TGDBInstructionFlags; ATimeOut: Integer = 0);
 | |
| begin
 | |
|   InternalCreate(ACommand, AThread, -1,
 | |
|                  AOtherFlags + [ifRequiresThread], ATimeOut);
 | |
|   Init;
 | |
| end;
 | |
| 
 | |
| constructor TGDBInstruction.Create(ACommand: String; AThread, AFrame: Integer;
 | |
|   AOtherFlags: TGDBInstructionFlags; ATimeOut: Integer = 0);
 | |
| begin
 | |
|   InternalCreate(ACommand, AThread, AFrame,
 | |
|                  AOtherFlags + [ifRequiresThread, ifRequiresStackFrame], ATimeOut);
 | |
|   Init;
 | |
| end;
 | |
| 
 | |
| function TGDBInstruction.IsSuccess: Boolean;
 | |
| begin
 | |
|   Result := ResultFlags * [ifrComleted, ifrFailed] = [ifrComleted]
 | |
| end;
 | |
| 
 | |
| { TGDBInstructionVerifyTimeOut }
 | |
| 
 | |
| procedure TGDBInstructionVerifyTimeOut.SendCommandDataToGDB(AQueue: TGDBInstructionQueue);
 | |
| begin
 | |
|   AQueue.SendDataToGDB(Self, '-data-evaluate-expression 7');
 | |
|   AQueue.SendDataToGDB(Self, '-data-evaluate-expression 1');
 | |
|   FState := vtSent;
 | |
| end;
 | |
| 
 | |
| function TGDBInstructionVerifyTimeOut.ProcessInputFromGdb(const AData: String): Boolean;
 | |
| type
 | |
|   TLineDataTipe = (ldOther, ldGdb, ldValue7, ldValue1);
 | |
| 
 | |
|   function CheckData(const ALineData: String): TLineDataTipe;
 | |
|   begin
 | |
|     Result := ldOther;
 | |
|     if ALineData= '(gdb) ' then begin
 | |
|       Result := ldGdb;
 | |
|       exit;
 | |
|     end;
 | |
|     if (copy(AData, 1, 6) = '^done,') or (AData = '^done') then begin
 | |
|       if FList = nil then
 | |
|         FList := TGDBMINameValueList.Create(ALineData)
 | |
|       else
 | |
|         FList.Init(ALineData);
 | |
|       if FList.Values['value'] = '7' then
 | |
|         Result := ldValue7
 | |
|       else
 | |
|       if FList.Values['value'] = '1' then
 | |
|         Result := ldValue1
 | |
|     end;
 | |
|   end;
 | |
| 
 | |
|   procedure SetError(APromptCount: Integer);
 | |
|   begin
 | |
|     FState := vtError;
 | |
|     FPromptAfterErrorCount := APromptCount; // prompt for val7 and val1 needed
 | |
|     FRunnigInstruction.HandleTimeOut;
 | |
|     if FPromptAfterErrorCount <= 0 then
 | |
|       FTimeOut := 50; // wait for timeout
 | |
|   end;
 | |
| 
 | |
| begin
 | |
|   Result := True;
 | |
|   if FState = vtError then begin
 | |
|     dec(FPromptAfterErrorCount);
 | |
|     if FPromptAfterErrorCount <= 0 then
 | |
|       FTimeOut := 50; // wait for timeout
 | |
|     exit;
 | |
|   end;
 | |
| 
 | |
|   case CheckData(AData) of
 | |
|     ldOther: begin
 | |
|         debugln(DBGMI_TIMEOUT_DEBUG, ['GDBMI TimeOut(', dbgs(FState), '): Got other data']);
 | |
|         Result := FRunnigInstruction.ProcessInputFromGdb(AData);
 | |
|       end;
 | |
|     ldGdb:
 | |
|       case FState of
 | |
|         vtSent: begin
 | |
|             debugln(DBGMI_TIMEOUT_DEBUG, ['GDBMI TimeOut(', dbgs(FState), '): Got prompt in order']);
 | |
|             FState := vtGotPrompt;
 | |
|             Result := FRunnigInstruction.ProcessInputFromGdb(AData);
 | |
|             if not FRunnigInstruction.IsCompleted then begin
 | |
|               debugln(DBGMI_TIMEOUT_DEBUG, ['GDBMI TimeOut(', dbgs(FState), '): Prompt was not accepted']);
 | |
|               SetError(2); // prompt for val=7 and val=1 needed
 | |
|             end;
 | |
|           end;
 | |
|         vtGotPrompt7:     FState := vtGotPrompt7gdb;
 | |
|         vtGotPrompt7and7: FState := vtGotPrompt7and7gdb;
 | |
|         vtGotPrompt1:     FState := vtGotPrompt1gdb;
 | |
|         vtGot7:           FState := vtGot7gdb;
 | |
|         vtGot7and7:       FState := vtGot7and7gdb;
 | |
|         vtGot1:           FState := vtGot1gdb;
 | |
|         else begin
 | |
|             debugln(DBGMI_TIMEOUT_DEBUG, ['GDBMI TimeOut(', dbgs(FState), '): Extra Prompt ']);
 | |
|             if FState = vtGotPrompt
 | |
|             then SetError(1)  // prompt val=1 needed
 | |
|             else SetError(0); // no more prompt needed
 | |
|           end;
 | |
|       end;
 | |
|     ldValue7:
 | |
|       case FState of
 | |
|         vtSent, vtGotPrompt: begin
 | |
|             debugln(DBGMI_TIMEOUT_DEBUG, ['GDBMI TimeOut(', dbgs(FState), '): Got value 7']);
 | |
|             FVal7Data := AData;
 | |
|             if FState = vtSent
 | |
|             then FState := vtGot7
 | |
|             else FState := vtGotPrompt7;
 | |
|           end;
 | |
|         vtGotPrompt7gdb, vtGot7gdb: begin
 | |
|             debugln(DBGMI_TIMEOUT_DEBUG, ['GDBMI TimeOut(', dbgs(FState), '): Got value 7 twice. Original Result?']);
 | |
|             Result := FRunnigInstruction.ProcessInputFromGdb(FVal7Data);
 | |
|             if FState = vtGotPrompt7gdb
 | |
|             then FState := vtGotPrompt7and7
 | |
|             else FState := vtGot7and7;
 | |
|           end;
 | |
|         else begin
 | |
|           debugln(DBGMI_TIMEOUT_DEBUG, ['GDBMI TimeOut(', dbgs(FState), '): Extra VAlue 7']);
 | |
|           if FState in [vtGotPrompt7, vtGot7]
 | |
|           then SetError(1)  // prompt val=1 needed
 | |
|           else SetError(0); // no more prompt needed
 | |
|         end;
 | |
|       end;
 | |
|     ldValue1:
 | |
|       case FState of
 | |
|         vtSent: begin
 | |
|           debugln(DBGMI_TIMEOUT_DEBUG, ['GDBMI TimeOut(', dbgs(FState), '): Got other data']);
 | |
|           Result := FRunnigInstruction.ProcessInputFromGdb(AData);
 | |
|         end;
 | |
|         vtGotPrompt7gdb:     FState := vtGotPrompt1;
 | |
|         vtGotPrompt7and7gdb: FState := vtGotPrompt1;
 | |
|         vtGot7gdb:           FState := vtGot1;
 | |
|         vtGot7and7gdb:       FState := vtGot1;
 | |
|         else begin
 | |
|           debugln(DBGMI_TIMEOUT_DEBUG, ['GDBMI TimeOut(', dbgs(FState), '): Wrong Value 1']);
 | |
|           SetError(0);
 | |
|         end;
 | |
|       end;
 | |
|   end;
 | |
| 
 | |
|   if FState = vtGot1gdb then begin
 | |
|     // timeout, but recovored
 | |
|     debugln(DBGMI_TIMEOUT_DEBUG, ['GDBMI TimeOut(', dbgs(FState), '): Recovered']);
 | |
|     FRunnigInstruction.ProcessInputFromGdb('(gdb) '); // simulate prompt
 | |
|     FRunnigInstruction.HandleRecoveredTimeOut;
 | |
|   end;
 | |
|   if FState in [vtGot1gdb, vtGotPrompt1gdb] then begin
 | |
|     debugln(DBGMI_TIMEOUT_DEBUG, ['GDBMI TimeOut(', dbgs(FState), '): All done: original Instruction completed=',dbgs(FRunnigInstruction.IsCompleted)]);
 | |
|     Include(FResultFlags, ifrComleted);
 | |
|     if not FRunnigInstruction.IsCompleted then
 | |
|       FRunnigInstruction.HandleTimeOut;
 | |
|   end;
 | |
| 
 | |
| end;
 | |
| 
 | |
| procedure TGDBInstructionVerifyTimeOut.HandleWriteError(ASender: TGDBInstruction);
 | |
| begin
 | |
|   inherited HandleWriteError(ASender);
 | |
|   FRunnigInstruction.HandleWriteError(ASender);
 | |
| end;
 | |
| 
 | |
| procedure TGDBInstructionVerifyTimeOut.HandleReadError;
 | |
| begin
 | |
|   inherited HandleReadError;
 | |
|   FRunnigInstruction.HandleReadError;
 | |
| end;
 | |
| 
 | |
| procedure TGDBInstructionVerifyTimeOut.HandleTimeOut;
 | |
| begin
 | |
|   inherited HandleTimeOut;
 | |
|   FRunnigInstruction.HandleTimeOut;
 | |
| end;
 | |
| 
 | |
| procedure TGDBInstructionVerifyTimeOut.HandleNoGdbRunning;
 | |
| begin
 | |
|   inherited HandleNoGdbRunning;
 | |
|   FRunnigInstruction.HandleNoGdbRunning;
 | |
| end;
 | |
| 
 | |
| function TGDBInstructionVerifyTimeOut.GetTimeOutVerifier: TGDBInstruction;
 | |
| begin
 | |
|   Result := nil;
 | |
| end;
 | |
| 
 | |
| function TGDBInstructionVerifyTimeOut.DebugText: String;
 | |
| begin
 | |
|   Result := ClassName + ': for "' + FRunnigInstruction.DebugText;
 | |
| end;
 | |
| 
 | |
| constructor TGDBInstructionVerifyTimeOut.Create(ARunnigInstruction: TGDBInstruction);
 | |
| var
 | |
|   t: Integer;
 | |
| begin
 | |
|   FRunnigInstruction := ARunnigInstruction;
 | |
|   FRunnigInstruction.AddReference;
 | |
|   t := FRunnigInstruction.TimeOut;
 | |
|   t := max(TIMEOUT_FOR_SYNC_AFTER_TIMEOUT, Min(TIMEOUT_FOR_SYNC_AFTER_TIMEOUT_MAX, t * 2));
 | |
|   inherited Create('', FRunnigInstruction.ThreadId, FRunnigInstruction.StackFrame,
 | |
|                    FRunnigInstruction.Flags * [ifRequiresThread, ifRequiresStackFrame],
 | |
|                    t);
 | |
| end;
 | |
| 
 | |
| destructor TGDBInstructionVerifyTimeOut.Destroy;
 | |
| begin
 | |
|   inherited Destroy;
 | |
|   FreeAndNil(FList);
 | |
|   if (FRunnigInstruction <> nil) then
 | |
|     FRunnigInstruction.ReleaseReference;
 | |
| end;
 | |
| 
 | |
| { TGDBInstructionChangeThread }
 | |
| 
 | |
| procedure TGDBInstructionChangeThread.SendCommandDataToGDB(AQueue: TGDBInstructionQueue);
 | |
| begin
 | |
|   AQueue.SendDataToGDB(Self, '-thread-select %d', [FSelThreadId]);
 | |
| end;
 | |
| 
 | |
| function TGDBInstructionChangeThread.ProcessInputFromGdb(const AData: String): Boolean;
 | |
| begin
 | |
| //  "-thread-select 2"
 | |
| //  "^done,new-thread-id="2",frame={level="0",addr="0x7707878f",func="ntdll!DbgUiConvertStateChangeStructure",args=[],from="C:\\Windows\\system32\\ntdll.dll"}"
 | |
| //  "(gdb) "
 | |
| 
 | |
|   Result := False;
 | |
|   if (copy(AData, 1, 6) = '^done,') or (AData = '^done') then begin
 | |
|     Result := True;
 | |
|     if FDone then
 | |
|       HandleContentError;
 | |
|     FDone := True;
 | |
|   end
 | |
| 
 | |
|   else
 | |
|   if (AData = '(gdb) ') then begin
 | |
|     Result := True;
 | |
|     if not FDone then begin
 | |
|       HandleContentError;
 | |
|     end
 | |
|     else begin
 | |
|       MarkAsSuccess;
 | |
|       FQueue.FCurrentThreadId := FSelThreadId;
 | |
|       FQueue.FFlags := FQueue.FFlags + [ifqValidThread];
 | |
|     end;
 | |
|   end
 | |
| 
 | |
|   else
 | |
|   begin
 | |
|     debugln(DBG_VERBOSE, ['GDBMI TGDBInstructionChangeThread ignoring: ', AData]);
 | |
|   end;
 | |
| end;
 | |
| 
 | |
| procedure TGDBInstructionChangeThread.HandleError(AnError: TGDBInstructionErrorFlag;
 | |
|   AMarkAsFailed: Boolean);
 | |
| begin
 | |
|   inherited HandleError(AnError, AMarkAsFailed);
 | |
|   FQueue.InvalidateThredAndFrame;
 | |
| end;
 | |
| 
 | |
| function TGDBInstructionChangeThread.DebugText: String;
 | |
| begin
 | |
|   Result := ClassName;
 | |
| end;
 | |
| 
 | |
| constructor TGDBInstructionChangeThread.Create(AQueue: TGDBInstructionQueue;
 | |
|   AThreadId: Integer);
 | |
| begin
 | |
|   inherited Create('', [], TIMEOUT_FOR_QUEUE_INSTR);
 | |
|   FQueue := AQueue;
 | |
|   FDone := False;
 | |
|   FSelThreadId := AThreadId;
 | |
| end;
 | |
| 
 | |
| { TGDBInstructionChangeStackFrame }
 | |
| 
 | |
| procedure TGDBInstructionChangeStackFrame.SendCommandDataToGDB(AQueue: TGDBInstructionQueue);
 | |
| begin
 | |
|   AQueue.SendDataToGDB(Self, '-stack-select-frame %d', [FSelStackFrame]);
 | |
| end;
 | |
| 
 | |
| function TGDBInstructionChangeStackFrame.ProcessInputFromGdb(const AData: String): Boolean;
 | |
| begin
 | |
| //  "-stack-select-frame 0"
 | |
| //  "^done"
 | |
| //  "(gdb) "
 | |
| //OR ^error => keep selected ?
 | |
| 
 | |
|   Result := False;
 | |
|   if (copy(AData, 1, 6) = '^done,') or (AData = '^done') then begin
 | |
|     Result := True;
 | |
|     if FDone then
 | |
|       HandleContentError;
 | |
|     FDone := True;
 | |
|   end
 | |
| 
 | |
|   else
 | |
|   if (AData = '(gdb) ') then begin
 | |
|     Result := True;
 | |
|     if not FDone then begin
 | |
|       HandleContentError;
 | |
|     end
 | |
|     else begin
 | |
|       MarkAsSuccess;
 | |
|       FQueue.FCurrentStackFrame := FSelStackFrame;
 | |
|       FQueue.FFlags := FQueue.FFlags + [ifqValidStackFrame];
 | |
|     end;
 | |
|   end
 | |
| 
 | |
|   else
 | |
|   begin
 | |
|     debugln(DBG_VERBOSE, ['GDBMI TGDBInstructionChangeStackFrame ignoring: ', AData]);
 | |
|   end;
 | |
| end;
 | |
| 
 | |
| procedure TGDBInstructionChangeStackFrame.HandleError(AnError: TGDBInstructionErrorFlag;
 | |
|   AMarkAsFailed: Boolean);
 | |
| begin
 | |
|   inherited HandleError(AnError, AMarkAsFailed);
 | |
|   FQueue.InvalidateThredAndFrame(True);
 | |
| end;
 | |
| 
 | |
| function TGDBInstructionChangeStackFrame.DebugText: String;
 | |
| begin
 | |
|   Result := ClassName;
 | |
| end;
 | |
| 
 | |
| constructor TGDBInstructionChangeStackFrame.Create(AQueue: TGDBInstructionQueue;
 | |
|   AFrame: Integer);
 | |
| begin
 | |
|   inherited Create('', [], TIMEOUT_FOR_QUEUE_INSTR);
 | |
|   FQueue := AQueue;
 | |
|   FDone := False;
 | |
|   FSelStackFrame := AFrame;
 | |
| end;
 | |
| 
 | |
| { TGDBInstructionQueue }
 | |
| 
 | |
| procedure TGDBInstructionQueue.ExecuteCurrentInstruction;
 | |
| var
 | |
|   ExeInstr, HelpInstr: TGDBInstruction;
 | |
|   CurStamp: Int64;
 | |
| begin
 | |
|   if FCurrentInstruction = nil then
 | |
|     exit;
 | |
| 
 | |
|   if FExeCurInstructionStamp = high(FExeCurInstructionStamp) then
 | |
|     FExeCurInstructionStamp := low(FExeCurInstructionStamp)
 | |
|   else
 | |
|     inc(FExeCurInstructionStamp);
 | |
| 
 | |
|   ExeInstr := FCurrentInstruction;
 | |
|   ExeInstr.AddReference;
 | |
|   try
 | |
|     while true do begin
 | |
|       CurStamp := FExeCurInstructionStamp;
 | |
| 
 | |
|       if not HasCorrectThreadIdFor(ExeInstr) then begin
 | |
|         HelpInstr := GetSelectThreadInstruction(ExeInstr.ThreadId);
 | |
|         DebugLn(DBG_THREAD_AND_FRAME, ['TGDB_IQ: Changing Thread from: ', FCurrentThreadId, ' - ', dbgs(FFlags),
 | |
|           ' to ', ExeInstr.ThreadId, ' using [', HelpInstr.DebugText, '] for [', ExeInstr.DebugText, ']']);
 | |
|         HelpInstr.AddReference;
 | |
|         try
 | |
|           FCurrentInstruction := HelpInstr;
 | |
|           FCurrentInstruction.SendCommandDataToGDB(Self);
 | |
|           FinishCurrentInstruction;
 | |
|           if not HelpInstr.IsSuccess then begin
 | |
|             DebugLn(DBG_THREAD_AND_FRAME, ['TGDB_IQ: Changing Thread FAILED']);
 | |
|             ExeInstr.HandleError(ifeInvalidThreadId);
 | |
|             exit;
 | |
|           end;
 | |
|         finally
 | |
|           HelpInstr.ReleaseReference;
 | |
|         end;
 | |
|       end;
 | |
| 
 | |
|       if not HasCorrectThreadIdFor(ExeInstr) then begin
 | |
|         if CurStamp = FExeCurInstructionStamp then begin
 | |
|           DebugLn(DBG_THREAD_AND_FRAME, ['TGDB_IQ: Thread was interuppted, FAILING']);
 | |
|           ExeInstr.HandleError(ifeQueueContextError);
 | |
|           exit;
 | |
|         end;
 | |
| 
 | |
|         DebugLn(DBG_THREAD_AND_FRAME, ['TGDB_IQ: Thread was interuppted, repeating']);
 | |
|         continue;
 | |
|       end;
 | |
| 
 | |
| 
 | |
|       if not HasCorrectFrameFor(ExeInstr) then begin
 | |
|         HelpInstr := GetSelectFrameInstruction(ExeInstr.StackFrame);
 | |
|         DebugLn(DBG_THREAD_AND_FRAME, ['TGDB_IQ: Changing Stack from: ', FCurrentStackFrame, ' - ', dbgs(FFlags),
 | |
|           ' to ', ExeInstr.StackFrame, ' using [', HelpInstr.DebugText, '] for [', ExeInstr.DebugText, ']']);
 | |
|         HelpInstr.AddReference;
 | |
|         try
 | |
|           FCurrentInstruction := HelpInstr;
 | |
|           FCurrentInstruction.SendCommandDataToGDB(Self);
 | |
|           FinishCurrentInstruction;
 | |
|           if not HelpInstr.IsSuccess then begin
 | |
|             DebugLn(DBG_THREAD_AND_FRAME, ['TGDB_IQ: Changing Stackframe FAILED']);
 | |
|             ExeInstr.HandleError(ifeInvalidStackFrame);
 | |
|             exit;
 | |
|           end;
 | |
|         finally
 | |
|           HelpInstr.ReleaseReference;
 | |
|         end;
 | |
|       end;
 | |
| 
 | |
|       if not (HasCorrectThreadIdFor(ExeInstr) and HasCorrectFrameFor(ExeInstr)) then begin
 | |
|         if CurStamp = FExeCurInstructionStamp then begin
 | |
|           DebugLn(DBG_THREAD_AND_FRAME, ['TGDB_IQ: Stack was interuppted, FAILING']);
 | |
|           ExeInstr.HandleError(ifeQueueContextError);
 | |
|           exit;
 | |
|         end;
 | |
| 
 | |
|         DebugLn(DBG_THREAD_AND_FRAME, ['TGDB_IQ: Stack was interuppted, repeating']);
 | |
|         continue;
 | |
|       end;
 | |
| 
 | |
|       break;
 | |
|     end; // while true
 | |
|   finally
 | |
|     if (ExeInstr.RefCount > 1) and (not ExeInstr.IsCompleted) then
 | |
|       FCurrentInstruction := ExeInstr
 | |
|     else
 | |
|       FCurrentInstruction := nil;
 | |
|     ExeInstr.ReleaseReference;
 | |
|   end;
 | |
| 
 | |
|   if FCurrentInstruction <> nil then
 | |
|     FCurrentInstruction.SendCommandDataToGDB(Self);
 | |
| end;
 | |
| 
 | |
| procedure TGDBInstructionQueue.FinishCurrentInstruction;
 | |
| var
 | |
|   S: String;
 | |
|   NewInstr, ExeInstr: TGDBInstruction;
 | |
|   Skip: Boolean;
 | |
|   Handled: Boolean;
 | |
| begin
 | |
|   if FCurrentInstruction = nil then exit;
 | |
|   ExeInstr := FCurrentInstruction;
 | |
|   ExeInstr.AddReference;
 | |
|   try
 | |
|     while (FCurrentInstruction <> nil) and
 | |
|           (not FCurrentInstruction.IsCompleted)
 | |
|     do begin
 | |
|       if not FDebugger.DebugProcessRunning then begin
 | |
|         FCurrentInstruction.HandleNoGdbRunning;
 | |
|         break;
 | |
|       end;
 | |
| 
 | |
|       S := FDebugger.ReadLine(FCurrentInstruction.TimeOut);
 | |
|       // Readline, may go into Application.ProcessMessages.
 | |
|       // If it does, it has not (yet) read any data.
 | |
|       // Therefore, if it does, another nested call to readline will work, and data will be returned in the correct order.
 | |
|       // If a nested readline reads all data, then the outer will have nothing to return.
 | |
| 
 | |
|       if (FCurrentInstruction = nil) or (FCurrentInstruction.IsCompleted) then begin
 | |
|         if s <> '' then  // Should not happen
 | |
|           DebugLn(DBG_VERBOSE, ['TGDB_IQ: Got Data, but command was finished. Cmd: ', ExeInstr.DebugText, ' Data: ', S]);
 | |
|         if not FDebugger.ReadLineWasAbortedByNested then
 | |
|           DebugLn(DBG_VERBOSE, ['TGDB_IQ: Missing instruction. Not flagged as nested. Cmd: ', ExeInstr.DebugText, ' Data: ', S]);
 | |
|         break;
 | |
|       end;
 | |
| 
 | |
|       if FDebugger.ReadLineWasAbortedByNested and (S = '') then
 | |
|         Continue;
 | |
| 
 | |
|       Skip := False;
 | |
|       HandleGdbDataBeforeInstruction(S, Skip, FCurrentInstruction);
 | |
|       // HandleGdbDataBeforeInstruction may execune other Instructions
 | |
|       if (FCurrentInstruction = nil) or (FCurrentInstruction.IsCompleted) then
 | |
|         break;
 | |
| 
 | |
|       if (not Skip) and
 | |
|          ( (not FDebugger.ReadLineTimedOut) or (S <> '') )
 | |
|       then
 | |
|         Handled := FCurrentInstruction.ProcessInputFromGdb(S);
 | |
| 
 | |
|       HandleGdbDataAfterInstruction(S, Handled, FCurrentInstruction);
 | |
| 
 | |
|       if (ehfGotReadError in FDebugger.FErrorHandlingFlags) then begin
 | |
|         FCurrentInstruction.HandleReadError;
 | |
|         break;
 | |
|       end;
 | |
|       if FDebugger.ReadLineTimedOut then begin
 | |
|         NewInstr := FCurrentInstruction.GetTimeOutVerifier;
 | |
|         if NewInstr <> nil then begin
 | |
|           NewInstr.AddReference;
 | |
|           ExeInstr.ReleaseReference;
 | |
|           ExeInstr := NewInstr;
 | |
|           // TODO: Run NewInstr;
 | |
|           FCurrentInstruction := NewInstr;
 | |
|           FCurrentInstruction.SendCommandDataToGDB(Self); // ExecuteCurrentInstruction;
 | |
| 
 | |
|         end
 | |
|         else begin
 | |
|           FCurrentInstruction.HandleTimeOut;
 | |
|           break;
 | |
|         end;
 | |
|       end;
 | |
| 
 | |
|     end; // while
 | |
|     FCurrentInstruction := nil;
 | |
|   finally
 | |
|     ExeInstr.ReleaseReference;
 | |
|   end;
 | |
| end;
 | |
| 
 | |
| procedure TGDBInstructionQueue.SetCurrentInstruction(AnInstruction: TGDBInstruction);
 | |
| begin
 | |
|   FinishCurrentInstruction;
 | |
|   FCurrentInstruction := AnInstruction;
 | |
| end;
 | |
| 
 | |
| function TGDBInstructionQueue.HasCorrectThreadIdFor(AnInstruction: TGDBInstruction): Boolean;
 | |
| begin
 | |
|   Result := not(ifRequiresThread in AnInstruction.Flags);
 | |
|   if Result then
 | |
|     exit;
 | |
|   Result := (ifqValidThread in Flags) and (CurrentThreadId = AnInstruction.ThreadId);
 | |
| end;
 | |
| 
 | |
| function TGDBInstructionQueue.HasCorrectFrameFor(AnInstruction: TGDBInstruction): Boolean;
 | |
| begin
 | |
|   Result := not(ifRequiresStackFrame in AnInstruction.Flags);
 | |
|   if Result then
 | |
|     exit;
 | |
|   Result := (ifqValidStackFrame in Flags) and (CurrentStackFrame = AnInstruction.StackFrame);
 | |
| end;
 | |
| 
 | |
| function TGDBInstructionQueue.SendDataToGDB(ASender: TGDBInstruction; AData: String): Boolean;
 | |
| begin
 | |
|   Result := True;
 | |
|   FDebugger.FErrorHandlingFlags := FDebugger.FErrorHandlingFlags
 | |
|     + [ehfDeferReadWriteError] - [ehfGotReadError, ehfGotWriteError];
 | |
| 
 | |
|   FDebugger.SendCmdLn(AData);
 | |
| 
 | |
|   if ehfGotWriteError in FDebugger.FErrorHandlingFlags then begin
 | |
|     Result := False;
 | |
| // TODO try reading, but ensure timeout
 | |
|     if FCurrentInstruction <> nil then
 | |
|       FCurrentInstruction.HandleWriteError(ASender)
 | |
|     else
 | |
|     if ASender <> nil then
 | |
|       ASender.HandleWriteError(ASender);
 | |
|   end;
 | |
| end;
 | |
| 
 | |
| function TGDBInstructionQueue.SendDataToGDB(ASender: TGDBInstruction; AData: String;
 | |
|   const AValues: array of const): Boolean;
 | |
| begin
 | |
|   Result := SendDataToGDB(ASender, Format(AData, AValues));
 | |
| end;
 | |
| 
 | |
| procedure TGDBInstructionQueue.HandleGdbDataBeforeInstruction(var AData: String;
 | |
|   var SkipData: Boolean; const TheInstruction: TGDBInstruction);
 | |
| begin
 | |
|   //
 | |
| end;
 | |
| 
 | |
| procedure TGDBInstructionQueue.HandleGdbDataAfterInstruction(var AData: String;
 | |
|   const Handled: Boolean; const TheInstruction: TGDBInstruction);
 | |
| begin
 | |
|   //
 | |
| end;
 | |
| 
 | |
| function TGDBInstructionQueue.GetSelectThreadInstruction(AThreadId: Integer): TGDBInstruction;
 | |
| begin
 | |
|   Result := TGDBInstructionChangeThread.Create(Self, AThreadId);
 | |
| end;
 | |
| 
 | |
| function TGDBInstructionQueue.GetSelectFrameInstruction(AFrame: Integer): TGDBInstruction;
 | |
| begin
 | |
|   Result := TGDBInstructionChangeStackFrame.Create(Self, AFrame);
 | |
| end;
 | |
| 
 | |
| constructor TGDBInstructionQueue.Create(ADebugger: TGDBMICmdLineDebugger);
 | |
| begin
 | |
|   FDebugger := ADebugger;
 | |
| end;
 | |
| 
 | |
| procedure TGDBInstructionQueue.InvalidateThredAndFrame(AStackFrameOnly: Boolean = False);
 | |
| begin
 | |
|   if AStackFrameOnly then begin
 | |
|     DebugLn(DBG_THREAD_AND_FRAME, ['TGDB_IQ: Invalidating queue''s stack only. Was: ', dbgs(FFlags), ' Thr=', FCurrentThreadId, ' Frm=', FCurrentStackFrame]);
 | |
|     FFlags := FFlags - [ifqValidStackFrame];
 | |
|   end
 | |
|   else begin
 | |
|     DebugLn(DBG_THREAD_AND_FRAME, ['TGDB_IQ: Invalidating queue''s current thread and stack. Was: ', dbgs(FFlags), ' Thr=', FCurrentThreadId, ' Frm=', FCurrentStackFrame]);
 | |
|     FFlags := FFlags - [ifqValidThread, ifqValidStackFrame];
 | |
|   end;
 | |
| end;
 | |
| 
 | |
| procedure TGDBInstructionQueue.SetKnownThread(AThread: Integer);
 | |
| begin
 | |
|   DebugLn(DBG_THREAD_AND_FRAME, ['TGDB_IQ: Setting queue''s current thread and stack. New: Thr=', AThread, ' Was: ', dbgs(FFlags), ' Thr=', FCurrentThreadId, ' Frm=', FCurrentStackFrame]);
 | |
|   FCurrentThreadId := AThread;
 | |
|   FFlags := FFlags + [ifqValidThread] - [ifqValidStackFrame];
 | |
| end;
 | |
| 
 | |
| procedure TGDBInstructionQueue.SetKnownThreadAndFrame(AThread, AFrame: Integer);
 | |
| begin
 | |
|   DebugLn(DBG_THREAD_AND_FRAME, ['TGDB_IQ: Setting queue''s current thread and stack. New: Thr=', AThread, ' Frm=', AFrame,' Was: ', dbgs(FFlags), ' Thr=', FCurrentThreadId, ' Frm=', FCurrentStackFrame]);
 | |
|   FCurrentThreadId := AThread;
 | |
|   FCurrentStackFrame := AFrame;
 | |
|   FFlags := FFlags + [ifqValidThread, ifqValidStackFrame];
 | |
| end;
 | |
| 
 | |
| procedure TGDBInstructionQueue.RunInstruction(AnInstruction: TGDBInstruction);
 | |
| begin
 | |
|   SetCurrentInstruction(AnInstruction);
 | |
|   ExecuteCurrentInstruction;
 | |
|   FinishCurrentInstruction;
 | |
| end;
 | |
| 
 | |
| initialization
 | |
|   DBGMI_TIMEOUT_DEBUG := DebugLogger.RegisterLogGroup('DBGMI_TIMEOUT_DEBUG' {$IFDEF DBGMI_TIMEOUT_DEBUG} , True {$ENDIF} );
 | |
|   DBG_THREAD_AND_FRAME := DebugLogger.FindOrRegisterLogGroup('DBG_THREAD_AND_FRAME' {$IFDEF DBG_THREAD_AND_FRAME} , True {$ENDIF} );
 | |
|   DBG_VERBOSE := DebugLogger.FindOrRegisterLogGroup('DBG_VERBOSE' {$IFDEF DBG_VERBOSE} , True {$ENDIF} );
 | |
| 
 | |
| end.
 | |
| 
 | 
