mirror of
				https://gitlab.com/freepascal.org/lazarus/lazarus.git
				synced 2025-11-04 14:29:25 +01:00 
			
		
		
		
	
		
			
				
	
	
		
			6137 lines
		
	
	
		
			184 KiB
		
	
	
	
		
			ObjectPascal
		
	
	
	
	
	
			
		
		
	
	
			6137 lines
		
	
	
		
			184 KiB
		
	
	
	
		
			ObjectPascal
		
	
	
	
	
	
{ $Id$ }
 | 
						|
{                  -------------------------------------------
 | 
						|
                    DebuggerBase.pp  -  Debugger base classes
 | 
						|
                   -------------------------------------------
 | 
						|
 | 
						|
 @author(Marc Weustink <marc@@dommelstein.net>)
 | 
						|
 @author(Martin Friebe)
 | 
						|
 | 
						|
 This unit contains the base class definitions of the debugger. These
 | 
						|
 classes are only definitions. Implemented debuggers should be
 | 
						|
 derived from these.
 | 
						|
 | 
						|
 ***************************************************************************
 | 
						|
 *                                                                         *
 | 
						|
 *   This source is free software; you can redistribute it and/or modify   *
 | 
						|
 *   it under the terms of the GNU General Public License as published by  *
 | 
						|
 *   the Free Software Foundation; either version 2 of the License, or     *
 | 
						|
 *   (at your option) any later version.                                   *
 | 
						|
 *                                                                         *
 | 
						|
 *   This code is distributed in the hope that it will be useful, but      *
 | 
						|
 *   WITHOUT ANY WARRANTY; without even the implied warranty of            *
 | 
						|
 *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU     *
 | 
						|
 *   General Public License for more details.                              *
 | 
						|
 *                                                                         *
 | 
						|
 *   A copy of the GNU General Public License is available on the World    *
 | 
						|
 *   Wide Web at <http://www.gnu.org/copyleft/gpl.html>. You can also      *
 | 
						|
 *   obtain it by writing to the Free Software Foundation,                 *
 | 
						|
 *   Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.        *
 | 
						|
 *                                                                         *
 | 
						|
 ***************************************************************************
 | 
						|
}
 | 
						|
unit DbgIntfDebuggerBase;
 | 
						|
 | 
						|
{$mode objfpc}{$H+}
 | 
						|
 | 
						|
{$ifndef VER2}
 | 
						|
  {$define disassemblernestedproc}
 | 
						|
{$endif VER2}
 | 
						|
 | 
						|
{$ifdef disassemblernestedproc}
 | 
						|
  {$modeswitch nestedprocvars}
 | 
						|
{$endif disassemblernestedproc}
 | 
						|
 | 
						|
interface
 | 
						|
 | 
						|
uses DbgIntfBaseTypes, DbgIntfMiscClasses, LazClasses, LazLoggerBase, LazFileUtils,
 | 
						|
  maps, LCLProc, Classes, sysutils, math, contnrs, LazMethodList;
 | 
						|
 | 
						|
const
 | 
						|
  DebuggerIntfVersion = 0;
 | 
						|
 | 
						|
type
 | 
						|
  EDebuggerException = class(Exception);
 | 
						|
  EDBGExceptions = class(EDebuggerException);
 | 
						|
 | 
						|
  TDBGCommand = (
 | 
						|
    dcRun,
 | 
						|
    dcPause,
 | 
						|
    dcStop,
 | 
						|
    dcStepOver,
 | 
						|
    dcStepInto,
 | 
						|
    dcStepOut,
 | 
						|
    dcRunTo,
 | 
						|
    dcJumpto,
 | 
						|
    dcAttach,
 | 
						|
    dcDetach,
 | 
						|
    dcBreak,
 | 
						|
    dcWatch,
 | 
						|
    dcLocal,
 | 
						|
    dcEvaluate,
 | 
						|
    dcModify,
 | 
						|
    dcEnvironment,
 | 
						|
    dcSetStackFrame,
 | 
						|
    dcDisassemble,
 | 
						|
    dcStepOverInstr,
 | 
						|
    dcStepIntoInstr,
 | 
						|
    dcSendConsoleInput
 | 
						|
    );
 | 
						|
  TDBGCommands = set of TDBGCommand;
 | 
						|
 | 
						|
  { Debugger states
 | 
						|
    --------------------------------------------------------------------------
 | 
						|
    dsNone:
 | 
						|
      The debug object is created, but no instance of an external debugger
 | 
						|
      exists.
 | 
						|
      Initial state, leave with Init, enter with Done
 | 
						|
 | 
						|
    dsIdle:
 | 
						|
      The external debugger is started, but no filename (or no other params
 | 
						|
      required to start) were given.
 | 
						|
 | 
						|
    dsStop:
 | 
						|
      (Optional) The execution of the target is stopped
 | 
						|
      The external debugger is loaded and ready to (re)start the execution
 | 
						|
      of the target.
 | 
						|
      Breakpoints, watches etc can be defined
 | 
						|
 | 
						|
    dsPause:
 | 
						|
      The debugger has paused the target. Target variables can be examined
 | 
						|
 | 
						|
    dsInternalPause:
 | 
						|
      Pause, not visible to user.
 | 
						|
      For examble auto continue breakpoint: Allow collection of Snapshot data
 | 
						|
 | 
						|
    dsInit:
 | 
						|
      (Optional, Internal) The debugger is about to run
 | 
						|
 | 
						|
    dsRun:
 | 
						|
      The target is running.
 | 
						|
 | 
						|
    dsError:
 | 
						|
      Something unforseen has happened. A shutdown of the debugger is in
 | 
						|
      most cases needed.
 | 
						|
 | 
						|
    -dsDestroying
 | 
						|
      The debugger is about to be destroyed.
 | 
						|
      Should normally happen immediate on calling Release.
 | 
						|
      But the debugger may be in nested calls, and has to exit them first.
 | 
						|
    --------------------------------------------------------------------------
 | 
						|
  }
 | 
						|
  TDBGState = (
 | 
						|
    dsNone,
 | 
						|
    dsIdle,
 | 
						|
    dsStop,
 | 
						|
    dsPause,
 | 
						|
    dsInternalPause,
 | 
						|
    dsInit,
 | 
						|
    dsRun,
 | 
						|
    dsError,
 | 
						|
    dsDestroying
 | 
						|
    );
 | 
						|
 | 
						|
  TDBGLocationRec = record
 | 
						|
    Address: TDBGPtr;
 | 
						|
    FuncName: String;
 | 
						|
    SrcFile: String;
 | 
						|
    SrcFullName: String;
 | 
						|
    SrcLine: Integer;
 | 
						|
  end;
 | 
						|
 | 
						|
  TDBGExceptionType = (
 | 
						|
    deInternal,
 | 
						|
    deExternal,
 | 
						|
    deRunError
 | 
						|
  );
 | 
						|
 | 
						|
  TDebuggerDataState = (ddsUnknown,                    //
 | 
						|
                        ddsRequested, ddsEvaluating,   //
 | 
						|
                        ddsValid,                      // Got a valid value
 | 
						|
                        ddsInvalid,                    // Does not have a value
 | 
						|
                        ddsError                       // Error, but got some Value to display (e.g. error msg)
 | 
						|
                       );
 | 
						|
 | 
						|
  (* TValidState: State for breakpoints *)
 | 
						|
  TValidState = (vsUnknown, vsValid, vsInvalid);
 | 
						|
 | 
						|
const
 | 
						|
  DebuggerDataStateStr : array[TDebuggerDataState] of string = (
 | 
						|
    'Unknown',
 | 
						|
    'Requested',
 | 
						|
    'Evaluating',
 | 
						|
    'Valid',
 | 
						|
    'Invalid',
 | 
						|
    'Error');
 | 
						|
 | 
						|
type
 | 
						|
  TDBGEvaluateFlag =
 | 
						|
    (defNoTypeInfo,        // No Typeinfo object will be returned
 | 
						|
     defSimpleTypeInfo,    // Returns: Kind (skSimple, skClass, ..); TypeName (but does make no attempt to avoid an alias)
 | 
						|
     defFullTypeInfo,      // Get all typeinfo, resolve all anchestors
 | 
						|
     defClassAutoCast      // Find real class of instance, and use, instead of declared class of variable
 | 
						|
    );
 | 
						|
  TDBGEvaluateFlags = set of TDBGEvaluateFlag;
 | 
						|
 | 
						|
  { TRunningProcessInfo
 | 
						|
    Used to enumerate running processes.
 | 
						|
  }
 | 
						|
 | 
						|
  TRunningProcessInfo = class
 | 
						|
  public
 | 
						|
    PID: Cardinal;
 | 
						|
    ImageName: string;
 | 
						|
    constructor Create(APID: Cardinal; const AImageName: string);
 | 
						|
  end;
 | 
						|
 | 
						|
  TRunningProcessInfoList = TObjectList;
 | 
						|
 | 
						|
  (* TDebuggerDataMonitor / TDebuggerDataSupplier
 | 
						|
     - TDebuggerDataMonitor
 | 
						|
       used by the IDE to receive/request updates on all data objects
 | 
						|
     - TDebuggerDataSupplier
 | 
						|
       used by the debugger to provide updates on all data objects
 | 
						|
  *)
 | 
						|
 | 
						|
  TDebuggerIntf = class;
 | 
						|
  TDebuggerDataSupplier = class;
 | 
						|
 | 
						|
  { TDebuggerDataHandler }
 | 
						|
 | 
						|
  TDebuggerDataHandler = class
 | 
						|
  private
 | 
						|
    FNotifiedState: TDBGState;
 | 
						|
    FOldState: TDBGState;
 | 
						|
    FUpdateCount: Integer;
 | 
						|
  protected
 | 
						|
    //procedure DoModified; virtual;                                              // user-modified / xml-storable data modified
 | 
						|
    procedure DoStateEnterPause; virtual;
 | 
						|
    procedure DoStateLeavePause; virtual;
 | 
						|
    procedure DoStateLeavePauseClean; virtual;
 | 
						|
    procedure DoStateChangeEx(const AOldState, ANewState: TDBGState); virtual;
 | 
						|
    property  NotifiedState: TDBGState read FNotifiedState;                     // The last state seen by DoStateChange
 | 
						|
    property  OldState: TDBGState read FOldState;                               // The state before last DoStateChange
 | 
						|
 | 
						|
    procedure DoBeginUpdate; virtual;
 | 
						|
    procedure DoEndUpdate; virtual;
 | 
						|
  public
 | 
						|
    //destructor Destroy; override;
 | 
						|
    procedure BeginUpdate;
 | 
						|
    procedure EndUpdate;
 | 
						|
    function  IsUpdating: Boolean;
 | 
						|
  end;
 | 
						|
 | 
						|
  { TDebuggerDataMonitor }
 | 
						|
 | 
						|
  TDebuggerDataMonitor = class(TDebuggerDataHandler)
 | 
						|
  private
 | 
						|
    FSupplier: TDebuggerDataSupplier;
 | 
						|
    procedure SetSupplier(const AValue: TDebuggerDataSupplier);
 | 
						|
  protected
 | 
						|
    procedure DoModified; virtual;                                              // user-modified / xml-storable data modified
 | 
						|
    procedure DoNewSupplier; virtual;
 | 
						|
    property  Supplier: TDebuggerDataSupplier read FSupplier write SetSupplier;
 | 
						|
  public
 | 
						|
    destructor Destroy; override;
 | 
						|
  end;
 | 
						|
 | 
						|
  { TDebuggerDataSupplier }
 | 
						|
 | 
						|
  TDebuggerDataSupplier = class(TDebuggerDataHandler)
 | 
						|
  private
 | 
						|
    FDebugger: TDebuggerIntf;
 | 
						|
    FMonitor: TDebuggerDataMonitor;
 | 
						|
    procedure SetMonitor(const AValue: TDebuggerDataMonitor);
 | 
						|
  protected
 | 
						|
    procedure DoNewMonitor; virtual;
 | 
						|
    property  Debugger: TDebuggerIntf read FDebugger write FDebugger;
 | 
						|
  protected
 | 
						|
    property  Monitor: TDebuggerDataMonitor read FMonitor write SetMonitor;
 | 
						|
 | 
						|
    procedure DoStateLeavePauseClean; override;
 | 
						|
    procedure DoStateChange(const AOldState: TDBGState); virtual;
 | 
						|
 | 
						|
    property  NotifiedState: TDBGState read FNotifiedState;                     // The last state seen by DoStateChange
 | 
						|
    property  OldState: TDBGState read FOldState;                               // The state before last DoStateChange
 | 
						|
    procedure DoBeginUpdate; override;
 | 
						|
    procedure DoEndUpdate; override;
 | 
						|
  public
 | 
						|
    constructor Create(const ADebugger: TDebuggerIntf);
 | 
						|
    destructor  Destroy; override;
 | 
						|
  end;
 | 
						|
 | 
						|
{$region Breakpoints **********************************************************}
 | 
						|
(******************************************************************************)
 | 
						|
(**                                                                          **)
 | 
						|
(**   B R E A K P O I N T S                                                  **)
 | 
						|
(**                                                                          **)
 | 
						|
(** Note: This part of the interface may/will still change to the            **)
 | 
						|
(**       monitor/supplier concept                                         **)
 | 
						|
(**                                                                          **)
 | 
						|
(******************************************************************************)
 | 
						|
(******************************************************************************)
 | 
						|
 | 
						|
  TDBGBreakPointKind = (
 | 
						|
    bpkSource,  // source breakpoint
 | 
						|
    bpkAddress, // address breakpoint
 | 
						|
    bpkData     // data/watchpoint
 | 
						|
  );
 | 
						|
 | 
						|
  TDBGWatchPointScope = (
 | 
						|
    wpsLocal,
 | 
						|
    wpsGlobal
 | 
						|
  );
 | 
						|
 | 
						|
  TDBGWatchPointKind = (
 | 
						|
    wpkWrite,
 | 
						|
    wpkRead,
 | 
						|
    wpkReadWrite
 | 
						|
  );
 | 
						|
 | 
						|
  { TBaseBreakPoint }
 | 
						|
 | 
						|
  TBaseBreakPoint = class(TRefCountedColectionItem)
 | 
						|
  protected
 | 
						|
    FAddress: TDBGPtr;
 | 
						|
    FWatchData: String;
 | 
						|
    FEnabled: Boolean;
 | 
						|
    FExpression: String;
 | 
						|
    FHitCount: Integer;      // Current counter
 | 
						|
    FBreakHitCount: Integer; // The user configurable value
 | 
						|
    FKind: TDBGBreakPointKind;
 | 
						|
    FLine: Integer;
 | 
						|
    FWatchScope: TDBGWatchPointScope;
 | 
						|
    FWatchKind: TDBGWatchPointKind;
 | 
						|
    FSource: String;
 | 
						|
    FValid: TValidState;
 | 
						|
    FInitialEnabled: Boolean;
 | 
						|
  protected
 | 
						|
    procedure AssignLocationTo(Dest: TPersistent); virtual;
 | 
						|
    procedure AssignTo(Dest: TPersistent); override;
 | 
						|
    procedure DoBreakHitCountChange; virtual;
 | 
						|
    procedure DoExpressionChange; virtual;
 | 
						|
    procedure DoEnableChange; virtual;
 | 
						|
    procedure DoHit(const ACount: Integer; var {%H-}AContinue: Boolean); virtual;
 | 
						|
    procedure SetHitCount(const AValue: Integer);
 | 
						|
    procedure DoKindChange; virtual;
 | 
						|
    procedure SetValid(const AValue: TValidState);
 | 
						|
  protected
 | 
						|
    // virtual properties
 | 
						|
    function GetAddress: TDBGPtr; virtual;
 | 
						|
    function GetBreakHitCount: Integer; virtual;
 | 
						|
    function GetEnabled: Boolean; virtual;
 | 
						|
    function GetExpression: String; virtual;
 | 
						|
    function GetHitCount: Integer; virtual;
 | 
						|
    function GetKind: TDBGBreakPointKind; virtual;
 | 
						|
    function GetLine: Integer; virtual;
 | 
						|
    function GetSource: String; virtual;
 | 
						|
    function GetWatchData: String; virtual;
 | 
						|
    function GetWatchScope: TDBGWatchPointScope; virtual;
 | 
						|
    function GetWatchKind: TDBGWatchPointKind; virtual;
 | 
						|
    function GetValid: TValidState; virtual;
 | 
						|
 | 
						|
    procedure SetAddress(const AValue: TDBGPtr); virtual;
 | 
						|
    procedure SetBreakHitCount(const AValue: Integer); virtual;
 | 
						|
    procedure SetEnabled(const AValue: Boolean); virtual;
 | 
						|
    procedure SetExpression(const AValue: String); virtual;
 | 
						|
    procedure SetInitialEnabled(const AValue: Boolean); virtual;
 | 
						|
    procedure SetKind(const AValue: TDBGBreakPointKind); virtual;
 | 
						|
  public
 | 
						|
    constructor Create(ACollection: TCollection); override;
 | 
						|
    // PublicProtectedFix ide/debugmanager.pas(867,32) Error: identifier idents no member "SetLocation"
 | 
						|
    property BreakHitCount: Integer read GetBreakHitCount write SetBreakHitCount;
 | 
						|
    property Enabled: Boolean read GetEnabled write SetEnabled;
 | 
						|
    property Expression: String read GetExpression write SetExpression;
 | 
						|
    property HitCount: Integer read GetHitCount;
 | 
						|
    property InitialEnabled: Boolean read FInitialEnabled write SetInitialEnabled;
 | 
						|
    property Kind: TDBGBreakPointKind read GetKind write SetKind;
 | 
						|
    property Valid: TValidState read GetValid;
 | 
						|
  public
 | 
						|
    procedure SetLocation(const ASource: String; const ALine: Integer); virtual;
 | 
						|
    procedure SetWatch(const AData: String; const AScope: TDBGWatchPointScope;
 | 
						|
                       const AKind: TDBGWatchPointKind); virtual;
 | 
						|
    // bpkAddress
 | 
						|
    property Address: TDBGPtr read GetAddress write SetAddress;
 | 
						|
    // bpkSource
 | 
						|
    //   TDBGBreakPoint: Line is the line-number as stored in the debug info
 | 
						|
    //   TIDEBreakPoint: Line is the location in the Source (potentially modified Source)
 | 
						|
    property Line: Integer read GetLine;
 | 
						|
    property Source: String read GetSource;
 | 
						|
    // bpkData
 | 
						|
    property WatchData: String read GetWatchData;
 | 
						|
    property WatchScope: TDBGWatchPointScope read GetWatchScope;
 | 
						|
    property WatchKind: TDBGWatchPointKind read GetWatchKind;
 | 
						|
  end;
 | 
						|
  TBaseBreakPointClass = class of TBaseBreakPoint;
 | 
						|
 | 
						|
  { TDBGBreakPoint }
 | 
						|
 | 
						|
  TDBGBreakPoint = class(TBaseBreakPoint)
 | 
						|
  private
 | 
						|
    FSlave: TBaseBreakPoint;
 | 
						|
    function GetDebugger: TDebuggerIntf;
 | 
						|
    procedure SetSlave(const ASlave : TBaseBreakPoint);
 | 
						|
  protected
 | 
						|
    procedure SetEnabled(const AValue: Boolean); override;
 | 
						|
    procedure DoChanged; override;
 | 
						|
    procedure DoStateChange(const AOldState: TDBGState); virtual;
 | 
						|
    property  Debugger: TDebuggerIntf read GetDebugger;
 | 
						|
  public
 | 
						|
    constructor Create(ACollection: TCollection); override;
 | 
						|
    destructor Destroy; override;
 | 
						|
    procedure Hit(var ACanContinue: Boolean);
 | 
						|
    property Slave: TBaseBreakPoint read FSlave write SetSlave;
 | 
						|
 | 
						|
    procedure DoLogMessage(const AMessage: String); virtual;
 | 
						|
    procedure DoLogCallStack(const {%H-}Limit: Integer); virtual;
 | 
						|
    procedure DoLogExpression(const {%H-}AnExpression: String); virtual; // implemented in TGDBMIBreakpoint
 | 
						|
  end;
 | 
						|
  TDBGBreakPointClass = class of TDBGBreakPoint;
 | 
						|
 | 
						|
  { TBaseBreakPoints }
 | 
						|
 | 
						|
  TBaseBreakPoints = class(TCollection)
 | 
						|
  private
 | 
						|
  protected
 | 
						|
  public
 | 
						|
    constructor Create(const ABreakPointClass: TBaseBreakPointClass);
 | 
						|
    destructor Destroy; override;
 | 
						|
    procedure Clear; reintroduce;
 | 
						|
    function Add(const ASource: String; const ALine: Integer): TBaseBreakPoint; overload;
 | 
						|
    function Add(const AAddress: TDBGPtr): TBaseBreakPoint; overload;
 | 
						|
    function Add(const AData: String; const AScope: TDBGWatchPointScope;
 | 
						|
                 const AKind: TDBGWatchPointKind): TBaseBreakPoint; overload;
 | 
						|
    function Find(const ASource: String; const ALine: Integer): TBaseBreakPoint; overload;
 | 
						|
    function Find(const ASource: String; const ALine: Integer; const AIgnore: TBaseBreakPoint): TBaseBreakPoint; overload;
 | 
						|
    function Find(const AAddress: TDBGPtr): TBaseBreakPoint; overload;
 | 
						|
    function Find(const AAddress: TDBGPtr; const AIgnore: TBaseBreakPoint): TBaseBreakPoint; overload;
 | 
						|
    function Find(const AData: String; const AScope: TDBGWatchPointScope;
 | 
						|
                  const AKind: TDBGWatchPointKind): TBaseBreakPoint; overload;
 | 
						|
    function Find(const AData: String; const AScope: TDBGWatchPointScope;
 | 
						|
                  const AKind: TDBGWatchPointKind; const AIgnore: TBaseBreakPoint): TBaseBreakPoint; overload;
 | 
						|
    // no items property needed, it is "overridden" anyhow
 | 
						|
  end;
 | 
						|
 | 
						|
  { TDBGBreakPoints }
 | 
						|
 | 
						|
  TDBGBreakPoints = class(TBaseBreakPoints)
 | 
						|
  private
 | 
						|
    FDebugger: TDebuggerIntf;  // reference to our debugger
 | 
						|
    function GetItem(const AnIndex: Integer): TDBGBreakPoint;
 | 
						|
    procedure SetItem(const AnIndex: Integer; const AValue: TDBGBreakPoint);
 | 
						|
  protected
 | 
						|
    procedure DoStateChange(const AOldState: TDBGState); virtual;
 | 
						|
    property  Debugger: TDebuggerIntf read FDebugger write FDebugger;
 | 
						|
  public
 | 
						|
    constructor Create(const ADebugger: TDebuggerIntf;
 | 
						|
                       const ABreakPointClass: TDBGBreakPointClass);
 | 
						|
    function Add(const ASource: String; const ALine: Integer): TDBGBreakPoint; overload;
 | 
						|
    function Add(const AAddress: TDBGPtr): TDBGBreakPoint; overload;
 | 
						|
    function Add(const AData: String; const AScope: TDBGWatchPointScope;
 | 
						|
                 const AKind: TDBGWatchPointKind): TDBGBreakPoint; overload;
 | 
						|
    function Find(const ASource: String; const ALine: Integer): TDBGBreakPoint; overload;
 | 
						|
    function Find(const ASource: String; const ALine: Integer; const AIgnore: TDBGBreakPoint): TDBGBreakPoint; overload;
 | 
						|
    function Find(const AAddress: TDBGPtr): TDBGBreakPoint; overload;
 | 
						|
    function Find(const AAddress: TDBGPtr; const {%H-}AIgnore: TDBGBreakPoint): TDBGBreakPoint; overload;
 | 
						|
    function Find(const AData: String; const AScope: TDBGWatchPointScope;
 | 
						|
                  const AKind: TDBGWatchPointKind): TDBGBreakPoint; overload;
 | 
						|
    function Find(const AData: String; const AScope: TDBGWatchPointScope;
 | 
						|
                  const AKind: TDBGWatchPointKind; const AIgnore: TDBGBreakPoint): TDBGBreakPoint; overload;
 | 
						|
 | 
						|
    property Items[const AnIndex: Integer]: TDBGBreakPoint read GetItem write SetItem; default;
 | 
						|
  end;
 | 
						|
 | 
						|
{%endregion   ^^^^^  Breakpoints  ^^^^^   }
 | 
						|
 | 
						|
{$region Debug Info ***********************************************************}
 | 
						|
(******************************************************************************)
 | 
						|
(**                                                                          **)
 | 
						|
(**   D E B U G   I N F O R M A T I O N                                      **)
 | 
						|
(**                                                                          **)
 | 
						|
(** Note: This part of the interface may/will still change.                  **)
 | 
						|
(**                                                                          **)
 | 
						|
(******************************************************************************)
 | 
						|
(******************************************************************************)
 | 
						|
 | 
						|
  TDBGSymbolAttribute = (saRefParam,        // var, const, constref passed by reference
 | 
						|
                         saInternalPointer, // PointerToObject
 | 
						|
                         saArray, saDynArray
 | 
						|
                        );
 | 
						|
  TDBGSymbolAttributes = set of TDBGSymbolAttribute;
 | 
						|
  TDBGFieldLocation = (flPrivate, flProtected, flPublic, flPublished);
 | 
						|
  TDBGFieldFlag = (ffVirtual,ffConstructor,ffDestructor);
 | 
						|
  TDBGFieldFlags = set of TDBGFieldFlag;
 | 
						|
 | 
						|
  TDBGType = class;
 | 
						|
 | 
						|
  TDBGValue = record
 | 
						|
    AsString: ansistring;
 | 
						|
    case integer of
 | 
						|
      0: (As8Bits: BYTE);
 | 
						|
      1: (As16Bits: WORD);
 | 
						|
      2: (As32Bits: DWORD);
 | 
						|
      3: (As64Bits: QWORD);
 | 
						|
      4: (AsSingle: Single);
 | 
						|
      5: (AsDouble: Double);
 | 
						|
      6: (AsPointer: Pointer);
 | 
						|
  end;
 | 
						|
 | 
						|
  { TDBGField }
 | 
						|
 | 
						|
  TDBGField = class(TObject)
 | 
						|
  private
 | 
						|
    FRefCount: Integer;
 | 
						|
  protected
 | 
						|
    FName: String;
 | 
						|
    FFlags: TDBGFieldFlags;
 | 
						|
    FLocation: TDBGFieldLocation;
 | 
						|
    FDBGType: TDBGType;
 | 
						|
    FClassName: String;
 | 
						|
    procedure IncRefCount;
 | 
						|
    procedure DecRefCount;
 | 
						|
    property RefCount: Integer read FRefCount;
 | 
						|
  public
 | 
						|
    constructor Create(const AName: String; ADBGType: TDBGType;
 | 
						|
                       ALocation: TDBGFieldLocation; AFlags: TDBGFieldFlags = [];
 | 
						|
                       AClassName: String = '');
 | 
						|
    destructor Destroy; override;
 | 
						|
    property Name: String read FName;
 | 
						|
    property DBGType: TDBGType read FDBGType;
 | 
						|
    property Location: TDBGFieldLocation read FLocation;
 | 
						|
    property Flags: TDBGFieldFlags read FFlags;
 | 
						|
    property ClassName: String read FClassName; // the class in which the field was declared
 | 
						|
  end;
 | 
						|
 | 
						|
  { TDBGFields }
 | 
						|
 | 
						|
  TDBGFields = class(TObject)
 | 
						|
  private
 | 
						|
    FList: TList;
 | 
						|
    function GetField(const AIndex: Integer): TDBGField;
 | 
						|
    function GetCount: Integer;
 | 
						|
  protected
 | 
						|
  public
 | 
						|
    constructor Create;
 | 
						|
    destructor Destroy; override;
 | 
						|
    property Count: Integer read GetCount;
 | 
						|
    property Items[const AIndex: Integer]: TDBGField read GetField; default;
 | 
						|
    procedure Add(const AField: TDBGField);
 | 
						|
  end;
 | 
						|
 | 
						|
  TDBGTypes = class(TObject)
 | 
						|
  private
 | 
						|
    function GetType(const AIndex: Integer): TDBGType;
 | 
						|
    function GetCount: Integer;
 | 
						|
  protected
 | 
						|
    FList: TList;
 | 
						|
  public
 | 
						|
    constructor Create;
 | 
						|
    destructor Destroy; override;
 | 
						|
    property Count: Integer read GetCount;
 | 
						|
    property Items[const AIndex: Integer]: TDBGType read GetType; default;
 | 
						|
  end;
 | 
						|
 | 
						|
  { TDBGType }
 | 
						|
 | 
						|
  TDBGType = class(TObject)
 | 
						|
  private
 | 
						|
    function GetFields: TDBGFields;
 | 
						|
  protected
 | 
						|
    FAncestor: String;
 | 
						|
    FResult: TDBGType;
 | 
						|
    FResultString: String;
 | 
						|
    FArguments: TDBGTypes;
 | 
						|
    FAttributes: TDBGSymbolAttributes;
 | 
						|
    FFields: TDBGFields;
 | 
						|
    FKind: TDBGSymbolKind;
 | 
						|
    FMembers: TStrings;
 | 
						|
    FTypeName: String;
 | 
						|
    FTypeDeclaration: String;
 | 
						|
    FDBGValue: TDBGValue;
 | 
						|
    FBoundHigh: Integer;
 | 
						|
    FBoundLow: Integer;
 | 
						|
    FLen: Integer;
 | 
						|
    procedure Init; virtual;
 | 
						|
  public
 | 
						|
    Value: TDBGValue;
 | 
						|
    constructor Create(AKind: TDBGSymbolKind; const ATypeName: String);
 | 
						|
    constructor Create(AKind: TDBGSymbolKind; const AArguments: TDBGTypes; AResult: TDBGType = nil);
 | 
						|
    destructor Destroy; override;
 | 
						|
    property Ancestor: String read FAncestor write FAncestor;
 | 
						|
    property Arguments: TDBGTypes read FArguments;
 | 
						|
    property Fields: TDBGFields read GetFields;
 | 
						|
    property Kind: TDBGSymbolKind read FKind;
 | 
						|
    property Attributes: TDBGSymbolAttributes read FAttributes;
 | 
						|
    property TypeName: String read FTypeName;               // Name/Alias as in type section. One pascal token, or empty
 | 
						|
    property TypeDeclaration: String read FTypeDeclaration; // Declaration (for array, set, enum, ..)
 | 
						|
    property Members: TStrings read FMembers;               // Set & ENUM
 | 
						|
    property Len: Integer read FLen;                        // Array
 | 
						|
    property BoundLow: Integer read FBoundLow;              // Array
 | 
						|
    property BoundHigh: Integer read FBoundHigh;            // Array
 | 
						|
    property Result: TDBGType read FResult;
 | 
						|
  end;
 | 
						|
 | 
						|
{%endregion   ^^^^^  Debug Info  ^^^^^   }
 | 
						|
 | 
						|
{%region Watches **************************************************************
 | 
						|
 ******************************************************************************
 | 
						|
 **                                                                          **
 | 
						|
 **   W A T C H E S                                                          **
 | 
						|
 **                                                                          **
 | 
						|
 ******************************************************************************
 | 
						|
 ******************************************************************************}
 | 
						|
 | 
						|
  TWatchDisplayFormat =
 | 
						|
    (wdfDefault,
 | 
						|
     wdfStructure,
 | 
						|
     wdfChar, wdfString,
 | 
						|
     wdfDecimal, wdfUnsigned, wdfFloat, wdfHex,
 | 
						|
     wdfPointer,
 | 
						|
     wdfMemDump
 | 
						|
    );
 | 
						|
 | 
						|
  TWatch = class;
 | 
						|
  TWatchesMonitor = class;
 | 
						|
 | 
						|
  { TWatchValue }
 | 
						|
 | 
						|
  TWatchValue = class(TFreeNotifyingObject)
 | 
						|
  private
 | 
						|
    FTypeInfo: TDBGType;
 | 
						|
    FValue: String;
 | 
						|
    FValidity: TDebuggerDataState;
 | 
						|
    FWatch: TWatch;
 | 
						|
 | 
						|
    procedure SetValidity(AValue: TDebuggerDataState); virtual;
 | 
						|
    procedure SetValue(AValue: String);
 | 
						|
    procedure SetTypeInfo(AValue: TDBGType);
 | 
						|
    function GetWatch: TWatch;
 | 
						|
  protected
 | 
						|
    FDisplayFormat: TWatchDisplayFormat;
 | 
						|
    FEvaluateFlags: TDBGEvaluateFlags;
 | 
						|
    FRepeatCount: Integer;
 | 
						|
    FStackFrame: Integer;
 | 
						|
    FThreadId: Integer;
 | 
						|
    procedure DoDataValidityChanged({%H-}AnOldValidity: TDebuggerDataState); virtual;
 | 
						|
 | 
						|
    function GetExpression: String; virtual;
 | 
						|
    function GetTypeInfo: TDBGType; virtual;
 | 
						|
    function GetValue: String; virtual;
 | 
						|
  public
 | 
						|
    constructor Create(AOwnerWatch: TWatch);
 | 
						|
    destructor Destroy; override;
 | 
						|
    procedure Assign(AnOther: TWatchValue); virtual;
 | 
						|
    property DisplayFormat: TWatchDisplayFormat read FDisplayFormat;
 | 
						|
    property EvaluateFlags: TDBGEvaluateFlags read FEvaluateFlags;
 | 
						|
    property RepeatCount: Integer read FRepeatCount;
 | 
						|
    property ThreadId: Integer read FThreadId;
 | 
						|
    property StackFrame: Integer read FStackFrame;
 | 
						|
    property Expression: String read GetExpression;
 | 
						|
    property Watch: TWatch read GetWatch;
 | 
						|
  public
 | 
						|
    property Validity: TDebuggerDataState read FValidity write SetValidity;
 | 
						|
    property Value: String read GetValue write SetValue;
 | 
						|
    property TypeInfo: TDBGType read GetTypeInfo write SetTypeInfo;
 | 
						|
  end;
 | 
						|
 | 
						|
  { TWatchValueList }
 | 
						|
 | 
						|
  TWatchValueList = class
 | 
						|
  private
 | 
						|
    FList: TList;
 | 
						|
    FWatch: TWatch;
 | 
						|
    function GetEntry(const AThreadId: Integer; const AStackFrame: Integer): TWatchValue;
 | 
						|
    function GetEntryByIdx(AnIndex: integer): TWatchValue;
 | 
						|
  protected
 | 
						|
    function CreateEntry(const {%H-}AThreadId: Integer; const {%H-}AStackFrame: Integer): TWatchValue; virtual;
 | 
						|
    function CopyEntry(AnEntry: TWatchValue): TWatchValue; virtual;
 | 
						|
  public
 | 
						|
    procedure Assign(AnOther: TWatchValueList);
 | 
						|
    constructor Create(AOwnerWatch: TWatch);
 | 
						|
    destructor Destroy; override;
 | 
						|
    procedure Add(AnEntry: TWatchValue);
 | 
						|
    procedure Clear;
 | 
						|
    function Count: Integer;
 | 
						|
    property EntriesByIdx[AnIndex: integer]: TWatchValue read GetEntryByIdx;
 | 
						|
    property Entries[const AThreadId: Integer; const AStackFrame: Integer]: TWatchValue
 | 
						|
             read GetEntry; default;
 | 
						|
    property Watch: TWatch read FWatch;
 | 
						|
  end;
 | 
						|
 | 
						|
  { TWatch }
 | 
						|
 | 
						|
  TWatch = class(TDelayedUdateItem)
 | 
						|
  private
 | 
						|
 | 
						|
    procedure SetDisplayFormat(AValue: TWatchDisplayFormat);
 | 
						|
    procedure SetEnabled(AValue: Boolean);
 | 
						|
    procedure SetEvaluateFlags(AValue: TDBGEvaluateFlags);
 | 
						|
    procedure SetExpression(AValue: String);
 | 
						|
    procedure SetRepeatCount(AValue: Integer);
 | 
						|
    function GetValue(const AThreadId: Integer; const AStackFrame: Integer): TWatchValue;
 | 
						|
  protected
 | 
						|
    FEnabled: Boolean;
 | 
						|
    FEvaluateFlags: TDBGEvaluateFlags;
 | 
						|
    FExpression: String;
 | 
						|
    FDisplayFormat: TWatchDisplayFormat;
 | 
						|
    FRepeatCount: Integer;
 | 
						|
    FValueList: TWatchValueList;
 | 
						|
 | 
						|
    procedure DoModified; virtual;  // user-storable data: expression, enabled, display-format
 | 
						|
    procedure DoEnableChange; virtual;
 | 
						|
    procedure DoExpressionChange; virtual;
 | 
						|
    procedure DoDisplayFormatChanged; virtual;
 | 
						|
    procedure AssignTo(Dest: TPersistent); override;
 | 
						|
    function CreateValueList: TWatchValueList; virtual;
 | 
						|
  public
 | 
						|
    constructor Create(ACollection: TCollection); override;
 | 
						|
    destructor Destroy; override;
 | 
						|
    procedure ClearValues; virtual;
 | 
						|
  public
 | 
						|
    property Enabled: Boolean read FEnabled write SetEnabled;
 | 
						|
    property Expression: String read FExpression write SetExpression;
 | 
						|
    property DisplayFormat: TWatchDisplayFormat read FDisplayFormat write SetDisplayFormat;
 | 
						|
    property EvaluateFlags: TDBGEvaluateFlags read FEvaluateFlags write SetEvaluateFlags;
 | 
						|
    property RepeatCount: Integer read FRepeatCount write SetRepeatCount;
 | 
						|
    property Values[const AThreadId: Integer; const AStackFrame: Integer]: TWatchValue
 | 
						|
             read GetValue;
 | 
						|
  end;
 | 
						|
  TWatchClass = class of TWatch;
 | 
						|
 | 
						|
  { TWatches }
 | 
						|
 | 
						|
  TWatches = class(TCollection)
 | 
						|
  protected
 | 
						|
    function GetItemBase(const AnIndex: Integer): TWatch;
 | 
						|
    procedure SetItemBase(const AnIndex: Integer; const AValue: TWatch);
 | 
						|
    function WatchClass: TWatchClass; virtual;
 | 
						|
  public
 | 
						|
    constructor Create;
 | 
						|
    procedure ClearValues;
 | 
						|
    function Find(const AExpression: String): TWatch;
 | 
						|
    property Items[const AnIndex: Integer]: TWatch read GetItemBase write SetItemBase; default;
 | 
						|
  end;
 | 
						|
 | 
						|
  { TWatchesSupplier }
 | 
						|
 | 
						|
  TWatchesSupplier = class(TDebuggerDataSupplier)
 | 
						|
  private
 | 
						|
    function GetCurrentWatches: TWatches;
 | 
						|
    function GetMonitor: TWatchesMonitor;
 | 
						|
    procedure SetMonitor(AValue: TWatchesMonitor);
 | 
						|
  protected
 | 
						|
    procedure DoStateChange(const AOldState: TDBGState); override; // workaround for state changes during TWatchValue.GetValue
 | 
						|
    procedure InternalRequestData(AWatchValue: TWatchValue); virtual;
 | 
						|
  public
 | 
						|
    constructor Create(const ADebugger: TDebuggerIntf);
 | 
						|
    procedure RequestData(AWatchValue: TWatchValue);
 | 
						|
    property CurrentWatches: TWatches read GetCurrentWatches;
 | 
						|
    property Monitor: TWatchesMonitor read GetMonitor write SetMonitor;
 | 
						|
  end;
 | 
						|
 | 
						|
  { TWatchesMonitor }
 | 
						|
 | 
						|
  TWatchesMonitor = class(TDebuggerDataMonitor)
 | 
						|
  private
 | 
						|
    FWatches: TWatches;
 | 
						|
    function GetSupplier: TWatchesSupplier;
 | 
						|
    procedure SetSupplier(AValue: TWatchesSupplier);
 | 
						|
  protected
 | 
						|
    function CreateWatches: TWatches; virtual;
 | 
						|
  public
 | 
						|
    constructor Create;
 | 
						|
    destructor Destroy; override;
 | 
						|
    property Watches: TWatches read FWatches;
 | 
						|
    property Supplier: TWatchesSupplier read GetSupplier write SetSupplier;
 | 
						|
  end;
 | 
						|
 | 
						|
{%endregion   ^^^^^  Watches  ^^^^^   }
 | 
						|
 | 
						|
{%region Locals ***************************************************************
 | 
						|
 ******************************************************************************
 | 
						|
 **                                                                          **
 | 
						|
 **   L O C A L S                                                            **
 | 
						|
 **                                                                          **
 | 
						|
 ******************************************************************************
 | 
						|
 ******************************************************************************}
 | 
						|
 | 
						|
    // TODO: a more watch-like value object
 | 
						|
    TLocalsMonitor = class;
 | 
						|
 | 
						|
   { TLocalsValue }
 | 
						|
 | 
						|
   TLocalsValue = class(TDbgEntityValue)
 | 
						|
   private
 | 
						|
     FName: String;
 | 
						|
     FValue: String;
 | 
						|
   protected
 | 
						|
     procedure DoAssign(AnOther: TDbgEntityValue); override;
 | 
						|
   public
 | 
						|
     property Name: String read FName;
 | 
						|
     property Value: String read FValue;
 | 
						|
   end;
 | 
						|
 | 
						|
 { TLocals }
 | 
						|
 | 
						|
  TLocals = class(TDbgEntityValuesList)
 | 
						|
  private
 | 
						|
    function GetEntry(AnIndex: Integer): TLocalsValue;
 | 
						|
    function GetName(const AnIndex: Integer): String;
 | 
						|
    function GetValue(const AnIndex: Integer): String;
 | 
						|
  protected
 | 
						|
    function CreateEntry: TDbgEntityValue; override;
 | 
						|
  public
 | 
						|
    procedure Add(const AName, AValue: String);
 | 
						|
    procedure SetDataValidity({%H-}AValidity: TDebuggerDataState); virtual;
 | 
						|
  public
 | 
						|
    function Count: Integer;reintroduce; virtual;
 | 
						|
    property Entries[AnIndex: Integer]: TLocalsValue read GetEntry;
 | 
						|
    property Names[const AnIndex: Integer]: String read GetName;
 | 
						|
    property Values[const AnIndex: Integer]: String read GetValue;
 | 
						|
  end;
 | 
						|
 | 
						|
  { TLocalsList }
 | 
						|
 | 
						|
  TLocalsList = class(TDbgEntitiesThreadStackList)
 | 
						|
  private
 | 
						|
    function GetEntry(AThreadId, AStackFrame: Integer): TLocals;
 | 
						|
    function GetEntryByIdx(AnIndex: Integer): TLocals;
 | 
						|
  protected
 | 
						|
    //function CreateEntry(AThreadId, AStackFrame: Integer): TDbgEntityValuesList; override;
 | 
						|
  public
 | 
						|
    property EntriesByIdx[AnIndex: Integer]: TLocals read GetEntryByIdx;
 | 
						|
    property Entries[AThreadId, AStackFrame: Integer]: TLocals read GetEntry; default;
 | 
						|
  end;
 | 
						|
 | 
						|
  { TLocalsSupplier }
 | 
						|
 | 
						|
  TLocalsSupplier = class(TDebuggerDataSupplier)
 | 
						|
  private
 | 
						|
    function GetCurrentLocalsList: TLocalsList;
 | 
						|
    function GetMonitor: TLocalsMonitor;
 | 
						|
    procedure SetMonitor(AValue: TLocalsMonitor);
 | 
						|
  protected
 | 
						|
  public
 | 
						|
    procedure RequestData(ALocals: TLocals); virtual;
 | 
						|
    property  CurrentLocalsList: TLocalsList read GetCurrentLocalsList;
 | 
						|
    property  Monitor: TLocalsMonitor read GetMonitor write SetMonitor;
 | 
						|
  end;
 | 
						|
 | 
						|
  { TLocalsMonitor }
 | 
						|
 | 
						|
  TLocalsMonitor = class(TDebuggerDataMonitor)
 | 
						|
  private
 | 
						|
    FLocalsList: TLocalsList;
 | 
						|
    function GetSupplier: TLocalsSupplier;
 | 
						|
    procedure SetSupplier(AValue: TLocalsSupplier);
 | 
						|
  protected
 | 
						|
    function CreateLocalsList: TLocalsList; virtual;
 | 
						|
  public
 | 
						|
    constructor Create;
 | 
						|
    destructor Destroy; override;
 | 
						|
    property LocalsList: TLocalsList read FLocalsList;
 | 
						|
    property Supplier: TLocalsSupplier read GetSupplier write SetSupplier;
 | 
						|
  end;
 | 
						|
 | 
						|
{%endregion   ^^^^^  Locals  ^^^^^   }
 | 
						|
 | 
						|
{%region Line Info ************************************************************
 | 
						|
 ******************************************************************************
 | 
						|
 **                                                                          **
 | 
						|
 **   L I N E   I N F O                                                      **
 | 
						|
 **                                                                          **
 | 
						|
 ******************************************************************************
 | 
						|
 ******************************************************************************}
 | 
						|
 | 
						|
  TIDELineInfoEvent = procedure(const ASender: TObject; const ASource: String) of object;
 | 
						|
 | 
						|
  { TBaseLineInfo }
 | 
						|
 | 
						|
  TBaseLineInfo = class(TObject)
 | 
						|
  protected
 | 
						|
    function GetSource(const {%H-}AnIndex: integer): String; virtual;
 | 
						|
  public
 | 
						|
    constructor Create;
 | 
						|
    function Count: Integer; virtual;
 | 
						|
    function GetAddress(const {%H-}AIndex: Integer; const {%H-}ALine: Integer): TDbgPtr; virtual;
 | 
						|
    function GetAddress(const ASource: String; const ALine: Integer): TDbgPtr;
 | 
						|
    function GetInfo({%H-}AAddress: TDbgPtr; out {%H-}ASource, {%H-}ALine, {%H-}AOffset: Integer): Boolean; virtual;
 | 
						|
    function IndexOf(const {%H-}ASource: String): integer; virtual;
 | 
						|
    procedure Request(const {%H-}ASource: String); virtual;
 | 
						|
    procedure Cancel(const {%H-}ASource: String); virtual;
 | 
						|
  public
 | 
						|
    property Sources[const AnIndex: Integer]: String read GetSource;
 | 
						|
  end;
 | 
						|
 | 
						|
  { TDBGLineInfo }
 | 
						|
 | 
						|
  TDBGLineInfo = class(TBaseLineInfo)
 | 
						|
  private
 | 
						|
    FDebugger: TDebuggerIntf;  // reference to our debugger
 | 
						|
    FOnChange: TIDELineInfoEvent;
 | 
						|
  protected
 | 
						|
    procedure Changed(ASource: String); virtual;
 | 
						|
    procedure DoChange(ASource: String);
 | 
						|
    procedure DoStateChange(const {%H-}AOldState: TDBGState); virtual;
 | 
						|
    property Debugger: TDebuggerIntf read FDebugger write FDebugger;
 | 
						|
  public
 | 
						|
    constructor Create(const ADebugger: TDebuggerIntf);
 | 
						|
    property OnChange: TIDELineInfoEvent read FOnChange write FOnChange;
 | 
						|
  end;
 | 
						|
 | 
						|
{%endregion   ^^^^^  Line Info  ^^^^^   }
 | 
						|
 | 
						|
{%region Register *************************************************************
 | 
						|
 ******************************************************************************
 | 
						|
 **                                                                          **
 | 
						|
 **   R E G I S T E R S                                                      **
 | 
						|
 **                                                                          **
 | 
						|
 ******************************************************************************
 | 
						|
 ******************************************************************************}
 | 
						|
 | 
						|
  TRegisterDisplayFormat = (rdDefault, rdHex, rdBinary, rdOctal, rdDecimal, rdRaw);
 | 
						|
  TRegisterDisplayFormats = set of TRegisterDisplayFormat;
 | 
						|
  TRegistersMonitor = class;
 | 
						|
 | 
						|
   { TRegisterDisplayValue }
 | 
						|
 | 
						|
   TRegisterDisplayValue = class // Only created if ddsValid
 | 
						|
   private
 | 
						|
     FStringValue: String; // default, rdRaw is always in FStringValue
 | 
						|
     FNumValue: QWord;
 | 
						|
     FSize: Integer;   // 2, 4 or 8 bytes
 | 
						|
     FFlags: set of (rdvHasNum); // Calculate numeric values.
 | 
						|
     FSupportedDispFormats: TRegisterDisplayFormats;
 | 
						|
     function  GetValue(ADispFormat: TRegisterDisplayFormat): String;
 | 
						|
   public
 | 
						|
     procedure Assign(AnOther: TRegisterDisplayValue);
 | 
						|
     procedure SetAsNum(AValue: QWord; ASize: Integer);
 | 
						|
     procedure SetAsText(AValue: String);
 | 
						|
     procedure AddFormats(AFormats: TRegisterDisplayFormats);
 | 
						|
     property SupportedDispFormats: TRegisterDisplayFormats read FSupportedDispFormats;
 | 
						|
     property Value[ADispFormat: TRegisterDisplayFormat]: String read GetValue;
 | 
						|
   end;
 | 
						|
 | 
						|
   { TRegisterValue }
 | 
						|
 | 
						|
   TRegisterValue = class(TDbgEntityValue)
 | 
						|
   private
 | 
						|
     FDataValidity: TDebuggerDataState;
 | 
						|
     FDisplayFormat: TRegisterDisplayFormat;
 | 
						|
     FModified: Boolean;
 | 
						|
     FName: String;
 | 
						|
     FValues: Array of TRegisterDisplayValue;
 | 
						|
     function GetHasValue: Boolean;
 | 
						|
     function GetHasValueFormat(ADispFormat: TRegisterDisplayFormat): Boolean;
 | 
						|
     function GetValue: String;
 | 
						|
     function GetValueObj: TRegisterDisplayValue;
 | 
						|
     function GetValueObjFormat(ADispFormat: TRegisterDisplayFormat): TRegisterDisplayValue;
 | 
						|
     procedure SetDisplayFormat(AValue: TRegisterDisplayFormat);
 | 
						|
     procedure SetValue(AValue: String);
 | 
						|
     function GetValueObject(ACreateNew: Boolean = False): TRegisterDisplayValue;
 | 
						|
     function GetValueObject(ADispFormat: TRegisterDisplayFormat; ACreateNew: Boolean = False): TRegisterDisplayValue;
 | 
						|
     procedure SetDataValidity(AValidity: TDebuggerDataState);
 | 
						|
     procedure ClearDispValues;
 | 
						|
   protected
 | 
						|
     procedure DoAssign(AnOther: TDbgEntityValue); override;
 | 
						|
     procedure DoDataValidityChanged({%H-}AnOldValidity: TDebuggerDataState); virtual;
 | 
						|
     procedure DoDisplayFormatChanged({%H-}AnOldFormat: TRegisterDisplayFormat); virtual;
 | 
						|
     procedure DoValueNotEvaluated; virtual;
 | 
						|
   public
 | 
						|
     destructor Destroy; override;
 | 
						|
     property Name: String read FName;
 | 
						|
     property Value: String read GetValue write SetValue;
 | 
						|
     property DisplayFormat: TRegisterDisplayFormat read FDisplayFormat write SetDisplayFormat;
 | 
						|
     property Modified: Boolean read FModified write FModified;
 | 
						|
     property DataValidity: TDebuggerDataState read FDataValidity write SetDataValidity;
 | 
						|
     property ValueObj: TRegisterDisplayValue read GetValueObj; // Will create the object for current DispFormat. Only use for setting data.
 | 
						|
     property HasValue: Boolean read GetHasValue;
 | 
						|
     property ValueObjFormat[ADispFormat: TRegisterDisplayFormat]: TRegisterDisplayValue read GetValueObjFormat; // Will create the object for current DispFormat. Only use for setting data.
 | 
						|
     property HasValueFormat[ADispFormat: TRegisterDisplayFormat]: Boolean read GetHasValueFormat;
 | 
						|
   end;
 | 
						|
 | 
						|
  { TRegisters }
 | 
						|
 | 
						|
  TRegisters = class(TDbgEntityValuesList)
 | 
						|
  private
 | 
						|
    FDataValidity: TDebuggerDataState;
 | 
						|
    function GetEntry(AnIndex: Integer): TRegisterValue;
 | 
						|
    function GetEntryByName(const AName: String): TRegisterValue;
 | 
						|
    procedure SetDataValidity(AValue: TDebuggerDataState);
 | 
						|
  protected
 | 
						|
    function CreateEntry: TDbgEntityValue; override;
 | 
						|
     procedure DoDataValidityChanged({%H-}AnOldValidity: TDebuggerDataState); virtual;
 | 
						|
  public
 | 
						|
    function Count: Integer; reintroduce; virtual;
 | 
						|
    property Entries[AnIndex: Integer]: TRegisterValue read GetEntry; default;
 | 
						|
    property EntriesByName[const AName: String]: TRegisterValue read GetEntryByName; // autocreate
 | 
						|
    property DataValidity: TDebuggerDataState read FDataValidity write SetDataValidity;
 | 
						|
  end;
 | 
						|
 | 
						|
  { TRegistersList }
 | 
						|
 | 
						|
  TRegistersList = class(TDbgEntitiesThreadStackList)
 | 
						|
  private
 | 
						|
    function GetEntry(AThreadId, AStackFrame: Integer): TRegisters;
 | 
						|
    function GetEntryByIdx(AnIndex: Integer): TRegisters;
 | 
						|
  protected
 | 
						|
  public
 | 
						|
    property EntriesByIdx[AnIndex: Integer]: TRegisters read GetEntryByIdx;
 | 
						|
    property Entries[AThreadId, AStackFrame: Integer]: TRegisters read GetEntry; default;
 | 
						|
  end;
 | 
						|
 | 
						|
  { TRegisterSupplier }
 | 
						|
 | 
						|
  TRegisterSupplier = class(TDebuggerDataSupplier)
 | 
						|
  private
 | 
						|
    function GetCurrentRegistersList: TRegistersList;
 | 
						|
    function GetMonitor: TRegistersMonitor;
 | 
						|
    procedure SetMonitor(AValue: TRegistersMonitor);
 | 
						|
  protected
 | 
						|
  public
 | 
						|
    procedure RequestData(ARegisters: TRegisters); virtual;
 | 
						|
    property  CurrentRegistersList: TRegistersList read GetCurrentRegistersList;
 | 
						|
    property  Monitor: TRegistersMonitor read GetMonitor write SetMonitor;
 | 
						|
  end;
 | 
						|
 | 
						|
  { TRegistersMonitor }
 | 
						|
 | 
						|
  TRegistersMonitor = class(TDebuggerDataMonitor)
 | 
						|
  private
 | 
						|
    FRegistersList: TRegistersList;
 | 
						|
    function GetSupplier: TRegisterSupplier;
 | 
						|
    procedure SetSupplier(AValue: TRegisterSupplier);
 | 
						|
  protected
 | 
						|
    function CreateRegistersList: TRegistersList; virtual;
 | 
						|
  public
 | 
						|
    constructor Create;
 | 
						|
    destructor Destroy; override;
 | 
						|
    property RegistersList: TRegistersList read FRegistersList;
 | 
						|
    property Supplier: TRegisterSupplier read GetSupplier write SetSupplier;
 | 
						|
  end;
 | 
						|
 | 
						|
{%endregion   ^^^^^  Register  ^^^^^   }
 | 
						|
 | 
						|
{%region Callstack ************************************************************
 | 
						|
 ******************************************************************************
 | 
						|
 **                                                                          **
 | 
						|
 **   C A L L S T A C K                                                      **
 | 
						|
 **                                                                          **
 | 
						|
 ******************************************************************************
 | 
						|
 ******************************************************************************
 | 
						|
 * The entries for the callstack are created on demand. This way when the     *
 | 
						|
 * first entry is needed, it isn't required to create the whole stack         *
 | 
						|
 *                                                                            *
 | 
						|
 * TCallStackEntry needs to stay a readonly object so its data can be shared  *
 | 
						|
 ******************************************************************************}
 | 
						|
 | 
						|
  TCallStackMonitor = class;
 | 
						|
 | 
						|
  { TCallStackEntryBase }
 | 
						|
 | 
						|
  TCallStackEntry = class(TObject)
 | 
						|
  private
 | 
						|
    FValidity: TDebuggerDataState;
 | 
						|
    FIndex: Integer;
 | 
						|
    FAddress: TDbgPtr;
 | 
						|
    FFunctionName: String;
 | 
						|
    FLine: Integer;
 | 
						|
    FArguments: TStrings;
 | 
						|
  protected
 | 
						|
    //// for use in TThreadEntry ONLY
 | 
						|
    //function GetThreadId: Integer; virtual; abstract;
 | 
						|
    //function GetThreadName: String; virtual; abstract;
 | 
						|
    //function GetThreadState: String; virtual; abstract;
 | 
						|
    //procedure SetThreadState(AValue: String); virtual; abstract;
 | 
						|
    function GetArgumentCount: Integer;
 | 
						|
    function GetArgumentName(const AnIndex: Integer): String;
 | 
						|
    function GetArgumentValue(const AnIndex: Integer): String;
 | 
						|
  protected
 | 
						|
    property Arguments: TStrings read FArguments;
 | 
						|
    function GetFunctionName: String; virtual;
 | 
						|
    function GetSource: String; virtual;
 | 
						|
    function GetValidity: TDebuggerDataState; virtual;
 | 
						|
    procedure SetValidity(AValue: TDebuggerDataState); virtual;
 | 
						|
    procedure InitFields(const AIndex:Integer; const AnAddress: TDbgPtr;
 | 
						|
                         const AnArguments: TStrings; const AFunctionName: String;
 | 
						|
                         const ALine: Integer; AValidity: TDebuggerDataState);
 | 
						|
  public
 | 
						|
    constructor Create;
 | 
						|
    function CreateCopy: TCallStackEntry; virtual;
 | 
						|
    destructor Destroy; override;
 | 
						|
    procedure Assign(AnOther: TCallStackEntry); virtual;
 | 
						|
    procedure Init(const AnAddress: TDbgPtr;
 | 
						|
                   const AnArguments: TStrings; const AFunctionName: String;
 | 
						|
                   const {%H-}AUnitName, {%H-}AClassName, {%H-}AProcName, {%H-}AFunctionArgs: String;
 | 
						|
                   const ALine: Integer; AState: TDebuggerDataState = ddsValid); virtual;
 | 
						|
    procedure Init(const AnAddress: TDbgPtr;
 | 
						|
                   const AnArguments: TStrings; const AFunctionName: String;
 | 
						|
                   const {%H-}FileName, {%H-}FullName: String;
 | 
						|
                   const ALine: Integer; AState: TDebuggerDataState = ddsValid); virtual;
 | 
						|
    procedure ClearLocation; virtual; // TODO need a way to call Changed on TCallStack or TThreads // corrently done in SetThreadState
 | 
						|
    function GetFunctionWithArg: String;
 | 
						|
    //function IsCurrent: Boolean;
 | 
						|
    //procedure MakeCurrent;
 | 
						|
    property Address: TDbgPtr read FAddress;
 | 
						|
    property ArgumentCount: Integer read GetArgumentCount;
 | 
						|
    property ArgumentNames[const AnIndex: Integer]: String read GetArgumentName;
 | 
						|
    property ArgumentValues[const AnIndex: Integer]: String read GetArgumentValue;
 | 
						|
    property FunctionName: String read FFunctionName;
 | 
						|
    property Index: Integer read FIndex;
 | 
						|
    property Line: Integer read FLine;
 | 
						|
    property Source: String read GetSource;
 | 
						|
    property Validity: TDebuggerDataState read GetValidity write SetValidity;
 | 
						|
  public
 | 
						|
    //// for use in TThreadEntry ONLY
 | 
						|
    //property ThreadId: Integer read GetThreadId;
 | 
						|
    //property ThreadName: String read GetThreadName;
 | 
						|
    //property ThreadState: String read GetThreadState write SetThreadState;
 | 
						|
  end;
 | 
						|
 | 
						|
  { TCallStackBase }
 | 
						|
 | 
						|
  TCallStackBase = class(TFreeNotifyingObject)
 | 
						|
  protected
 | 
						|
    FCurrent: Integer;
 | 
						|
    FThreadId: Integer;
 | 
						|
    function GetNewCurrentIndex: Integer; virtual;
 | 
						|
    function GetEntryBase(AIndex: Integer): TCallStackEntry; virtual; abstract;
 | 
						|
    function GetCount: Integer; virtual;
 | 
						|
    procedure SetCount(AValue: Integer); virtual; abstract;
 | 
						|
    function GetCurrent: Integer; virtual;
 | 
						|
    procedure SetCurrent(AValue: Integer); virtual;
 | 
						|
    function GetHighestUnknown: Integer; virtual;
 | 
						|
    function GetLowestUnknown: Integer; virtual;
 | 
						|
    function GetRawEntries: TMap; virtual; abstract;
 | 
						|
  public
 | 
						|
    constructor Create;
 | 
						|
    function CreateCopy: TCallStackBase; virtual;
 | 
						|
    procedure Assign(AnOther: TCallStackBase); virtual;
 | 
						|
 | 
						|
    procedure PrepareRange({%H-}AIndex, {%H-}ACount: Integer); virtual; abstract;
 | 
						|
    procedure DoEntriesCreated; virtual; abstract;
 | 
						|
    procedure DoEntriesUpdated; virtual; abstract;
 | 
						|
    procedure SetCountValidity({%H-}AValidity: TDebuggerDataState); virtual;
 | 
						|
    procedure SetHasAtLeastCountInfo({%H-}AValidity: TDebuggerDataState; {%H-}AMinCount: Integer = -1); virtual;
 | 
						|
    procedure SetCurrentValidity({%H-}AValidity: TDebuggerDataState); virtual;
 | 
						|
    function CountLimited(ALimit: Integer): Integer; virtual; abstract;
 | 
						|
    property Count: Integer read GetCount write SetCount;
 | 
						|
    property CurrentIndex: Integer read GetCurrent write SetCurrent;
 | 
						|
    property Entries[AIndex: Integer]: TCallStackEntry read GetEntryBase;
 | 
						|
    property ThreadId: Integer read FThreadId write FThreadId;
 | 
						|
    property NewCurrentIndex: Integer read GetNewCurrentIndex;
 | 
						|
 | 
						|
    property RawEntries: TMap read GetRawEntries;
 | 
						|
    property LowestUnknown: Integer read GetLowestUnknown;
 | 
						|
    property HighestUnknown: Integer read GetHighestUnknown;
 | 
						|
  end;
 | 
						|
 | 
						|
  { TCallStackListBase }
 | 
						|
 | 
						|
  TCallStackList = class
 | 
						|
  private
 | 
						|
    FList: TList;
 | 
						|
    function GetEntry(const AIndex: Integer): TCallStackBase;
 | 
						|
    function GetEntryForThread(const AThreadId: Integer): TCallStackBase;
 | 
						|
  protected
 | 
						|
    function NewEntryForThread(const {%H-}AThreadId: Integer): TCallStackBase; virtual;
 | 
						|
  public
 | 
						|
    constructor Create;
 | 
						|
    destructor Destroy; override;
 | 
						|
    procedure Assign(AnOther: TCallStackList); virtual;
 | 
						|
    procedure Add(ACallStack: TCallStackBase);
 | 
						|
    procedure Clear; virtual;
 | 
						|
    function Count: Integer; virtual;    // Count of already requested CallStacks (via ThreadId)
 | 
						|
    property Entries[const AIndex: Integer]: TCallStackBase read GetEntry; default;
 | 
						|
    property EntriesForThreads[const AThreadId: Integer]: TCallStackBase read GetEntryForThread;
 | 
						|
  end;
 | 
						|
 | 
						|
  { TCallStackSupplier }
 | 
						|
 | 
						|
  TCallStackSupplier = class(TDebuggerDataSupplier)
 | 
						|
  private
 | 
						|
    function GetCurrentCallStackList: TCallStackList;
 | 
						|
    function GetMonitor: TCallStackMonitor;
 | 
						|
    procedure SetMonitor(AValue: TCallStackMonitor);
 | 
						|
  protected
 | 
						|
    //procedure CurrentChanged;
 | 
						|
    procedure Changed;
 | 
						|
  public
 | 
						|
    procedure RequestCount(ACallstack: TCallStackBase); virtual;
 | 
						|
    procedure RequestAtLeastCount(ACallstack: TCallStackBase; {%H-}ARequiredMinCount: Integer); virtual;
 | 
						|
    procedure RequestCurrent(ACallstack: TCallStackBase); virtual;
 | 
						|
    procedure RequestEntries(ACallstack: TCallStackBase); virtual;
 | 
						|
    procedure UpdateCurrentIndex; virtual;
 | 
						|
    property CurrentCallStackList: TCallStackList read GetCurrentCallStackList;
 | 
						|
    property Monitor: TCallStackMonitor read GetMonitor write SetMonitor;
 | 
						|
  end;
 | 
						|
 | 
						|
  { TCallStackMonitor }
 | 
						|
 | 
						|
  TCallStackMonitor = class(TDebuggerDataMonitor)
 | 
						|
  private
 | 
						|
    FCallStackList: TCallStackList;
 | 
						|
    function GetSupplier: TCallStackSupplier;
 | 
						|
    procedure SetSupplier(AValue: TCallStackSupplier);
 | 
						|
  protected
 | 
						|
    function CreateCallStackList: TCallStackList; virtual;
 | 
						|
  public
 | 
						|
    constructor Create;
 | 
						|
    destructor Destroy; override;
 | 
						|
    property CallStackList: TCallStackList read FCallStackList;
 | 
						|
    property Supplier: TCallStackSupplier read GetSupplier write SetSupplier;
 | 
						|
  end;
 | 
						|
 | 
						|
{%endregion   ^^^^^  Callstack  ^^^^^   }
 | 
						|
 | 
						|
{%region      *****  Disassembler  *****   }
 | 
						|
(******************************************************************************)
 | 
						|
(******************************************************************************)
 | 
						|
(**                                                                          **)
 | 
						|
(**   D I S A S S E M B L E R                                                **)
 | 
						|
(**                                                                          **)
 | 
						|
(******************************************************************************)
 | 
						|
(******************************************************************************)
 | 
						|
 | 
						|
(*  Some values to calculate how many bytes to disassemble for a given amount of lines
 | 
						|
    Those values are only guesses *)
 | 
						|
const
 | 
						|
  // DAssBytesPerCommandAvg: Average len: Used for LinesBefore/LinesAfter.
 | 
						|
  // (should rather be to big than to small)
 | 
						|
  DAssBytesPerCommandAvg = 8;
 | 
						|
  // If we have a range with more then DAssRangeOverFuncTreshold * DAssBytesPerCommandAvg
 | 
						|
  //  then prefer the Range-end as start, rather than the known func start
 | 
						|
  //  (otherwhise re-dissassemble the whole function, including the part already known)
 | 
						|
  // The assumption is, that no single *source* statement starting before this range,
 | 
						|
  //  will ever reach into the next statement (where the next statement already started / mixed addresses)
 | 
						|
  DAssRangeOverFuncTreshold = 15;
 | 
						|
  // Never dis-assemble more bytes in a single go (actually, max-offset before requested addr)
 | 
						|
  DAssMaxRangeSize = 4096;
 | 
						|
 | 
						|
type
 | 
						|
  PDisassemblerEntry = ^TDisassemblerEntry;
 | 
						|
  TDisassemblerEntry = record
 | 
						|
    Addr: TDbgPtr;                   // Address
 | 
						|
    Dump: String;                    // Raw Data
 | 
						|
    Statement: String;               // Asm
 | 
						|
    FuncName: String;                // Function, if avail
 | 
						|
    Offset: Integer;                 // Byte-Offest in Fonction
 | 
						|
    SrcFileName: String;             // SrcFile if avail
 | 
						|
    SrcFileLine: Integer;            // Line in SrcFile
 | 
						|
    SrcStatementIndex: SmallInt;     // Index of Statement, within list of Stmnt of the same SrcLine
 | 
						|
    SrcStatementCount: SmallInt;     // Count of Statements for this SrcLine
 | 
						|
  end;
 | 
						|
 | 
						|
  TDisassemblerAddressValidity =
 | 
						|
    (avFoundFunction, avFoundRange, avFoundStatement,  // known address
 | 
						|
     avGuessed,                                        // guessed
 | 
						|
     avExternRequest,                                  // As requested by external caller
 | 
						|
     avPadded                                          // Padded, because address was not known for sure
 | 
						|
    );
 | 
						|
  TDisassemblerAddress = record
 | 
						|
    Value, GuessedValue: TDBGPtr;
 | 
						|
    Offset: Integer;
 | 
						|
    Validity: TDisassemblerAddressValidity;
 | 
						|
  end;
 | 
						|
 | 
						|
 | 
						|
  { TBaseDisassembler }
 | 
						|
 | 
						|
  TBaseDisassembler = class(TObject)
 | 
						|
  private
 | 
						|
    FBaseAddr: TDbgPtr;
 | 
						|
    FCountAfter: Integer;
 | 
						|
    FCountBefore: Integer;
 | 
						|
    FChangedLockCount: Integer;
 | 
						|
    FIsChanged: Boolean;
 | 
						|
    function GetEntryPtr(AIndex: Integer): PDisassemblerEntry;
 | 
						|
    procedure IndexError(AIndex: Integer);
 | 
						|
    function GetEntry(AIndex: Integer): TDisassemblerEntry;
 | 
						|
  protected
 | 
						|
    function  InternalGetEntry({%H-}AIndex: Integer): TDisassemblerEntry; virtual;
 | 
						|
    function  InternalGetEntryPtr({%H-}AIndex: Integer): PDisassemblerEntry; virtual;
 | 
						|
    procedure DoChanged; virtual;
 | 
						|
    procedure Changed;
 | 
						|
    procedure LockChanged;
 | 
						|
    procedure UnlockChanged;
 | 
						|
    procedure InternalIncreaseCountBefore(ACount: Integer);
 | 
						|
    procedure InternalIncreaseCountAfter(ACount: Integer);
 | 
						|
    procedure SetCountBefore(ACount: Integer);
 | 
						|
    procedure SetCountAfter(ACount: Integer);
 | 
						|
    procedure SetBaseAddr(AnAddr: TDbgPtr);
 | 
						|
  public
 | 
						|
    constructor Create;
 | 
						|
    destructor Destroy; override;
 | 
						|
    procedure Clear; virtual;
 | 
						|
    // Returns "True", if the range is valid, if not a ChangeNotification will be triggered later
 | 
						|
    function PrepareRange({%H-}AnAddr: TDbgPtr; {%H-}ALinesBefore, {%H-}ALinesAfter: Integer): Boolean; virtual;
 | 
						|
    property BaseAddr: TDbgPtr read FBaseAddr;
 | 
						|
    property CountAfter: Integer read FCountAfter;
 | 
						|
    property CountBefore: Integer read FCountBefore;
 | 
						|
    property Entries[AIndex: Integer]: TDisassemblerEntry read GetEntry;
 | 
						|
    property EntriesPtr[Index: Integer]: PDisassemblerEntry read GetEntryPtr;
 | 
						|
  end;
 | 
						|
 | 
						|
  { TDBGDisassemblerEntryRange }
 | 
						|
 | 
						|
  TDBGDisassemblerEntryRange = class
 | 
						|
  private
 | 
						|
    FCount: Integer;
 | 
						|
    FEntries: array of TDisassemblerEntry;
 | 
						|
    FLastEntryEndAddr: TDBGPtr;
 | 
						|
    FRangeEndAddr: TDBGPtr;
 | 
						|
    FRangeStartAddr: TDBGPtr;
 | 
						|
    function GetCapacity: Integer;
 | 
						|
    function GetEntry(Index: Integer): TDisassemblerEntry;
 | 
						|
    function GetEntryPtr(Index: Integer): PDisassemblerEntry;
 | 
						|
    procedure SetCapacity(const AValue: Integer);
 | 
						|
    procedure SetCount(const AValue: Integer);
 | 
						|
  public
 | 
						|
    procedure Clear;
 | 
						|
    function Append(const AnEntryPtr: PDisassemblerEntry): Integer;
 | 
						|
    procedure Merge(const AnotherRange: TDBGDisassemblerEntryRange);
 | 
						|
    // Actual addresses on the ranges
 | 
						|
    function FirstAddr: TDbgPtr;
 | 
						|
    function LastAddr: TDbgPtr;
 | 
						|
    function ContainsAddr(const AnAddr: TDbgPtr; IncludeNextAddr: Boolean = False): Boolean;
 | 
						|
    function IndexOfAddr(const AnAddr: TDbgPtr): Integer;
 | 
						|
    function IndexOfAddrWithOffs(const AnAddr: TDbgPtr): Integer;
 | 
						|
    function IndexOfAddrWithOffs(const AnAddr: TDbgPtr; out AOffs: Integer): Integer;
 | 
						|
    property Count: Integer read FCount write SetCount;
 | 
						|
    property Capacity: Integer read GetCapacity write SetCapacity;
 | 
						|
    property Entries[Index: Integer]: TDisassemblerEntry read GetEntry;
 | 
						|
    property EntriesPtr[Index: Integer]: PDisassemblerEntry read GetEntryPtr;
 | 
						|
    // The first address behind last entry
 | 
						|
    property LastEntryEndAddr: TDBGPtr read FLastEntryEndAddr write FLastEntryEndAddr;
 | 
						|
    // The addresses for which the range was requested
 | 
						|
    // The range may bo more, than the entries, if there a gaps that cannot be retrieved.
 | 
						|
    property RangeStartAddr: TDBGPtr read FRangeStartAddr write FRangeStartAddr;
 | 
						|
    property RangeEndAddr: TDBGPtr read FRangeEndAddr write FRangeEndAddr;
 | 
						|
  end;
 | 
						|
 | 
						|
  { TDBGDisassemblerEntryMap }
 | 
						|
 | 
						|
  TDBGDisassemblerEntryMapMergeEvent
 | 
						|
    = procedure(MergeReceiver, MergeGiver: TDBGDisassemblerEntryRange) of object;
 | 
						|
 | 
						|
  { TDBGDisassemblerEntryMapIterator }
 | 
						|
  TDBGDisassemblerEntryMap = class;
 | 
						|
 | 
						|
  TDBGDisassemblerEntryMapIterator = class(TMapIterator)
 | 
						|
  public
 | 
						|
    function GetRangeForAddr(AnAddr: TDbgPtr; IncludeNextAddr: Boolean = False): TDBGDisassemblerEntryRange;
 | 
						|
    function NextRange: TDBGDisassemblerEntryRange;
 | 
						|
    function PreviousRange: TDBGDisassemblerEntryRange;
 | 
						|
  end;
 | 
						|
 | 
						|
  TDBGDisassemblerEntryMap = class(TMap)
 | 
						|
  private
 | 
						|
    FIterator: TDBGDisassemblerEntryMapIterator;
 | 
						|
    FOnDelete: TNotifyEvent;
 | 
						|
    FOnMerge: TDBGDisassemblerEntryMapMergeEvent;
 | 
						|
    FFreeItemLock: Boolean;
 | 
						|
  protected
 | 
						|
    procedure ReleaseData(ADataPtr: Pointer); override;
 | 
						|
  public
 | 
						|
    constructor Create(AIdType: TMapIdType; ADataSize: Cardinal);
 | 
						|
    destructor Destroy; override;
 | 
						|
    // AddRange, may destroy the object
 | 
						|
    procedure AddRange(const ARange: TDBGDisassemblerEntryRange); // Arange may be freed
 | 
						|
    function GetRangeForAddr(AnAddr: TDbgPtr; IncludeNextAddr: Boolean = False): TDBGDisassemblerEntryRange;
 | 
						|
    property OnDelete: TNotifyEvent read FOnDelete write FOnDelete;
 | 
						|
    property OnMerge: TDBGDisassemblerEntryMapMergeEvent
 | 
						|
             read FOnMerge write FOnMerge;
 | 
						|
  end;
 | 
						|
 | 
						|
  { TDBGDisassemblerRangeExtender }
 | 
						|
 | 
						|
  TDoDisassembleRangeProc = function(AnEntryRanges: TDBGDisassemblerEntryMap; AFirstAddr, ALastAddr: TDisassemblerAddress; StopAfterAddress: TDBGPtr; StopAfterNumLines: Integer): Boolean {$ifdef disassemblernestedproc} is nested {$else} of object{$endif};
 | 
						|
  TDisassembleCancelProc = function(): Boolean {$ifdef disassemblernestedproc} is nested {$else} of object {$endif};
 | 
						|
  TDisassembleAdjustToKnowFunctionStart = function (var AStartAddr: TDisassemblerAddress): Boolean {$ifdef disassemblernestedproc} is nested {$else} of object {$endif};
 | 
						|
 | 
						|
  TDBGDisassemblerRangeExtender = class
 | 
						|
  private
 | 
						|
    FOnAdjustToKnowFunctionStart: TDisassembleAdjustToKnowFunctionStart;
 | 
						|
    FOnCheckCancel: TDisassembleCancelProc;
 | 
						|
    FOnDoDisassembleRange: TDoDisassembleRangeProc;
 | 
						|
 | 
						|
    FEntryRangeMap: TDBGDisassemblerEntryMap;
 | 
						|
    FRangeIterator: TDBGDisassemblerEntryMapIterator;
 | 
						|
    function CheckIfCancelled: boolean;
 | 
						|
    function AdjustToRangeOrKnowFunctionStart(var AStartAddr: TDisassemblerAddress;
 | 
						|
      ARangeBefore: TDBGDisassemblerEntryRange): Boolean;
 | 
						|
    function InitAddress(AValue: TDBGPtr; AValidity: TDisassemblerAddressValidity;
 | 
						|
      AnOffset: Integer = -1): TDisassemblerAddress;
 | 
						|
  public
 | 
						|
    constructor Create(AnEntryRangeMap: TDBGDisassemblerEntryMap);
 | 
						|
    destructor Destroy; override;
 | 
						|
    function DisassembleRange(ALinesBefore,
 | 
						|
      ALinesAfter: integer; AStartAddr: TDBGPtr; AnEndAddr: TDBGPtr): boolean;
 | 
						|
    property OnDoDisassembleRange: TDoDisassembleRangeProc read FOnDoDisassembleRange write FOnDoDisassembleRange;
 | 
						|
    property OnCheckCancel: TDisassembleCancelProc read FOnCheckCancel write FOnCheckCancel;
 | 
						|
    property OnAdjustToKnowFunctionStart: TDisassembleAdjustToKnowFunctionStart read FOnAdjustToKnowFunctionStart write FOnAdjustToKnowFunctionStart;
 | 
						|
  end;
 | 
						|
 | 
						|
  { TDBGDisassembler }
 | 
						|
 | 
						|
  TDBGDisassembler = class(TBaseDisassembler)
 | 
						|
  private
 | 
						|
    FDebugger: TDebuggerIntf;
 | 
						|
    FOnChange: TNotifyEvent;
 | 
						|
 | 
						|
    FEntryRanges: TDBGDisassemblerEntryMap;
 | 
						|
    FCurrentRange: TDBGDisassemblerEntryRange;
 | 
						|
    procedure EntryRangesOnDelete(Sender: TObject);
 | 
						|
    procedure EntryRangesOnMerge(MergeReceiver, MergeGiver: TDBGDisassemblerEntryRange);
 | 
						|
    function FindRange(AnAddr: TDbgPtr; ALinesBefore, ALinesAfter: Integer): Boolean;
 | 
						|
  protected
 | 
						|
    procedure DoChanged; override;
 | 
						|
    procedure DoStateChange(const AOldState: TDBGState); virtual;
 | 
						|
    function  InternalGetEntry(AIndex: Integer): TDisassemblerEntry; override;
 | 
						|
    function  InternalGetEntryPtr(AIndex: Integer): PDisassemblerEntry; override;
 | 
						|
    // PrepareEntries returns True, if it already added some entries
 | 
						|
    function  PrepareEntries({%H-}AnAddr: TDbgPtr; {%H-}ALinesBefore, {%H-}ALinesAfter: Integer): boolean; virtual;
 | 
						|
    function  HandleRangeWithInvalidAddr(ARange: TDBGDisassemblerEntryRange;{%H-}AnAddr:
 | 
						|
                 TDbgPtr; var {%H-}ALinesBefore, {%H-}ALinesAfter: Integer): boolean; virtual;
 | 
						|
    property Debugger: TDebuggerIntf read FDebugger write FDebugger;
 | 
						|
    property EntryRanges: TDBGDisassemblerEntryMap read FEntryRanges;
 | 
						|
  public
 | 
						|
    constructor Create(const ADebugger: TDebuggerIntf);
 | 
						|
    destructor Destroy; override;
 | 
						|
    procedure Clear; override;
 | 
						|
    function PrepareRange(AnAddr: TDbgPtr; ALinesBefore, ALinesAfter: Integer): Boolean; override;
 | 
						|
    property OnChange: TNotifyEvent read FOnChange write FOnChange;
 | 
						|
  end;
 | 
						|
 | 
						|
{%endregion   ^^^^^  Disassembler  ^^^^^   }
 | 
						|
 | 
						|
{%region Threads **************************************************************
 | 
						|
 ******************************************************************************
 | 
						|
 **                                                                          **
 | 
						|
 **   T H R E A D S                                                          **
 | 
						|
 **                                                                          **
 | 
						|
 ******************************************************************************
 | 
						|
 ******************************************************************************}
 | 
						|
 | 
						|
 TThreadsMonitor = class;
 | 
						|
 | 
						|
  { TThreadEntry }
 | 
						|
 | 
						|
  TThreadEntry = class(TObject)
 | 
						|
  private
 | 
						|
    FTopFrame: TCallStackEntry;
 | 
						|
  protected
 | 
						|
    FThreadId: Integer;
 | 
						|
    FThreadName: String;
 | 
						|
    FThreadState: String;
 | 
						|
    procedure SetThreadState(AValue: String); virtual;
 | 
						|
    function CreateStackEntry: TCallStackEntry; virtual;
 | 
						|
  public
 | 
						|
    constructor Create;
 | 
						|
    constructor Create(const AnAdress: TDbgPtr;
 | 
						|
                       const AnArguments: TStrings; const AFunctionName: String;
 | 
						|
                       const FileName, FullName: String;
 | 
						|
                       const ALine: Integer;
 | 
						|
                       const AThreadId: Integer; const AThreadName: String;
 | 
						|
                       const AThreadState: String;
 | 
						|
                       AState: TDebuggerDataState = ddsValid);
 | 
						|
    function CreateCopy: TThreadEntry; virtual;
 | 
						|
    destructor Destroy; override;
 | 
						|
    procedure Assign(AnOther: TThreadEntry); virtual;
 | 
						|
  published
 | 
						|
    property ThreadId: Integer read FThreadId;
 | 
						|
    property ThreadName: String read FThreadName;
 | 
						|
    property ThreadState: String read FThreadState write SetThreadState;
 | 
						|
    property TopFrame: TCallStackEntry read FTopFrame;
 | 
						|
 end;
 | 
						|
 | 
						|
  { TThreadsBase }
 | 
						|
 | 
						|
  TThreads = class(TObject)
 | 
						|
  private
 | 
						|
    FCurrentThreadId: Integer;
 | 
						|
    FList: TList;
 | 
						|
    function GetEntry(const AnIndex: Integer): TThreadEntry;
 | 
						|
    function GetEntryById(const AnID: Integer): TThreadEntry;
 | 
						|
  protected
 | 
						|
    procedure SetCurrentThreadId(AValue: Integer); virtual;
 | 
						|
    property List: TList read FList;
 | 
						|
  public
 | 
						|
    constructor Create;
 | 
						|
    destructor Destroy; override;
 | 
						|
    procedure Assign(AnOther: TThreads); virtual;
 | 
						|
    function Count: Integer; virtual;
 | 
						|
    procedure Clear; virtual;
 | 
						|
    procedure Add(AThread: TThreadEntry); virtual;
 | 
						|
    procedure Remove(AThread: TThreadEntry); virtual;
 | 
						|
    function  CreateEntry(const AnAdress: TDbgPtr;
 | 
						|
                       const AnArguments: TStrings; const AFunctionName: String;
 | 
						|
                       const FileName, FullName: String;
 | 
						|
                       const ALine: Integer;
 | 
						|
                       const AThreadId: Integer; const AThreadName: String;
 | 
						|
                       const AThreadState: String;
 | 
						|
                       AState: TDebuggerDataState = ddsValid): TThreadEntry; virtual;
 | 
						|
    procedure SetValidity({%H-}AValidity: TDebuggerDataState); virtual;
 | 
						|
    property Entries[const AnIndex: Integer]: TThreadEntry read GetEntry; default;
 | 
						|
    property EntryById[const AnID: Integer]: TThreadEntry read GetEntryById;
 | 
						|
    property CurrentThreadId: Integer read FCurrentThreadId write SetCurrentThreadId;
 | 
						|
  end;
 | 
						|
 | 
						|
  { TThreadsSupplier }
 | 
						|
 | 
						|
  TThreadsSupplier = class(TDebuggerDataSupplier)
 | 
						|
  private
 | 
						|
    function GetCurrentThreads: TThreads;
 | 
						|
    function GetMonitor: TThreadsMonitor;
 | 
						|
    procedure SetMonitor(AValue: TThreadsMonitor);
 | 
						|
  protected
 | 
						|
    procedure DoStateChange(const AOldState: TDBGState); override;
 | 
						|
    procedure DoStateLeavePauseClean; override;
 | 
						|
    procedure DoCleanAfterPause; virtual;
 | 
						|
  public
 | 
						|
    procedure RequestMasterData; virtual;
 | 
						|
    procedure ChangeCurrentThread({%H-}ANewId: Integer); virtual;
 | 
						|
    procedure Changed; // TODO: needed because entries can not notify the monitor
 | 
						|
    property  CurrentThreads: TThreads read GetCurrentThreads;
 | 
						|
    property  Monitor: TThreadsMonitor read GetMonitor write SetMonitor;
 | 
						|
  end;
 | 
						|
 | 
						|
  { TThreadsMonitor }
 | 
						|
 | 
						|
  TThreadsMonitor = class(TDebuggerDataMonitor)
 | 
						|
  private
 | 
						|
    FThreads: TThreads;
 | 
						|
    function GetSupplier: TThreadsSupplier;
 | 
						|
    procedure SetSupplier(AValue: TThreadsSupplier);
 | 
						|
  protected
 | 
						|
    function CreateThreads: TThreads; virtual;
 | 
						|
  public
 | 
						|
    constructor Create;
 | 
						|
    destructor Destroy; override;
 | 
						|
    property Threads: TThreads read FThreads;
 | 
						|
    property Supplier: TThreadsSupplier read GetSupplier write SetSupplier;
 | 
						|
  end;
 | 
						|
 | 
						|
{%endregion   ^^^^^  Threads  ^^^^^   }
 | 
						|
 | 
						|
{%region Signals / Exceptions *************************************************}
 | 
						|
(******************************************************************************)
 | 
						|
(**                                                                          **)
 | 
						|
(**   S I G N A L S  and  E X C E P T I O N S                                **)
 | 
						|
(**                                                                          **)
 | 
						|
(******************************************************************************)
 | 
						|
(******************************************************************************)
 | 
						|
 | 
						|
  { TBaseSignal }
 | 
						|
 | 
						|
  TBaseSignal = class(TDelayedUdateItem)
 | 
						|
  private
 | 
						|
    FHandledByDebugger: Boolean;
 | 
						|
    FID: Integer;
 | 
						|
    FName: String;
 | 
						|
    FResumeHandled: Boolean;
 | 
						|
  protected
 | 
						|
    procedure AssignTo(Dest: TPersistent); override;
 | 
						|
    procedure SetHandledByDebugger(const AValue: Boolean); virtual;
 | 
						|
    procedure SetID(const AValue: Integer); virtual;
 | 
						|
    procedure SetName(const AValue: String); virtual;
 | 
						|
    procedure SetResumeHandled(const AValue: Boolean); virtual;
 | 
						|
  public
 | 
						|
    constructor Create(ACollection: TCollection); override;
 | 
						|
    property ID: Integer read FID write SetID;
 | 
						|
    property Name: String read FName write SetName;
 | 
						|
    property HandledByDebugger: Boolean read FHandledByDebugger write SetHandledByDebugger;
 | 
						|
    property ResumeHandled: Boolean read FResumeHandled write SetResumeHandled;
 | 
						|
  end;
 | 
						|
  TBaseSignalClass = class of TBaseSignal;
 | 
						|
 | 
						|
  { TDBGSignal }
 | 
						|
 | 
						|
  TDBGSignal = class(TBaseSignal)
 | 
						|
  private
 | 
						|
    function GetDebugger: TDebuggerIntf;
 | 
						|
  protected
 | 
						|
    property Debugger: TDebuggerIntf read GetDebugger;
 | 
						|
  public
 | 
						|
  end;
 | 
						|
  TDBGSignalClass = class of TDBGSignal;
 | 
						|
 | 
						|
  { TBaseSignals }
 | 
						|
  TBaseSignals = class(TCollection)
 | 
						|
  private
 | 
						|
  protected
 | 
						|
  public
 | 
						|
    constructor Create(const AItemClass: TBaseSignalClass);
 | 
						|
    procedure Reset; virtual;
 | 
						|
    function Add(const AName: String; AID: Integer): TBaseSignal;
 | 
						|
    function Find(const AName: String): TBaseSignal;
 | 
						|
  end;
 | 
						|
 | 
						|
  { TDBGSignals }
 | 
						|
 | 
						|
  TDBGSignals = class(TBaseSignals)
 | 
						|
  private
 | 
						|
    FDebugger: TDebuggerIntf;  // reference to our debugger
 | 
						|
    function GetItem(const AIndex: Integer): TDBGSignal;
 | 
						|
    procedure SetItem(const AIndex: Integer; const AValue: TDBGSignal);
 | 
						|
  protected
 | 
						|
  public
 | 
						|
    constructor Create(const ADebugger: TDebuggerIntf;
 | 
						|
                       const ASignalClass: TDBGSignalClass);
 | 
						|
    function Add(const AName: String; AID: Integer): TDBGSignal;
 | 
						|
    function Find(const AName: String): TDBGSignal;
 | 
						|
  public
 | 
						|
    property Items[const AIndex: Integer]: TDBGSignal read GetItem
 | 
						|
                                                      write SetItem; default;
 | 
						|
  end;
 | 
						|
 | 
						|
 | 
						|
 | 
						|
  { TBaseException }
 | 
						|
  TBaseException = class(TDelayedUdateItem)
 | 
						|
  private
 | 
						|
    procedure SetEnabled(AValue: Boolean);
 | 
						|
  protected
 | 
						|
    FEnabled: Boolean;
 | 
						|
    FName: String;
 | 
						|
    procedure AssignTo(Dest: TPersistent); override;
 | 
						|
    procedure SetName(const AValue: String); virtual;
 | 
						|
  public
 | 
						|
    constructor Create(ACollection: TCollection); override;
 | 
						|
  public
 | 
						|
    property Name: String read FName write SetName;
 | 
						|
    property Enabled: Boolean read FEnabled write SetEnabled; // ignored if enabled
 | 
						|
  end;
 | 
						|
  TBaseExceptionClass = class of TBaseException;
 | 
						|
 | 
						|
  { TDBGException }
 | 
						|
  TDBGException = class(TBaseException)
 | 
						|
  private
 | 
						|
  protected
 | 
						|
  public
 | 
						|
  end;
 | 
						|
  TDBGExceptionClass = class of TDBGException;
 | 
						|
 | 
						|
  { TBaseExceptions }
 | 
						|
  TBaseExceptions = class(TCollection)
 | 
						|
  private
 | 
						|
    function GetItem(const AIndex: Integer): TBaseException;
 | 
						|
    procedure SetItem(const AIndex: Integer; AValue: TBaseException);
 | 
						|
  protected
 | 
						|
    FIgnoreAll: Boolean;
 | 
						|
    procedure AssignTo(Dest: TPersistent); override;
 | 
						|
    procedure ClearExceptions; virtual;
 | 
						|
    procedure SetIgnoreAll(const AValue: Boolean); virtual;
 | 
						|
  public
 | 
						|
    constructor Create(const AItemClass: TBaseExceptionClass);
 | 
						|
    destructor Destroy; override;
 | 
						|
    procedure Reset; virtual;
 | 
						|
    function Add(const AName: String): TBaseException;
 | 
						|
    function Find(const AName: String): TBaseException;
 | 
						|
    property IgnoreAll: Boolean read FIgnoreAll write SetIgnoreAll;
 | 
						|
    property Items[const AIndex: Integer]: TBaseException read GetItem
 | 
						|
                                                        write SetItem; default;
 | 
						|
  end;
 | 
						|
 | 
						|
 | 
						|
{%endregion   ^^^^^  Signals / Exceptions  ^^^^^   }
 | 
						|
 | 
						|
(******************************************************************************)
 | 
						|
(******************************************************************************)
 | 
						|
(**                                                                          **)
 | 
						|
(**   D E B U G G E R                                                        **)
 | 
						|
(**                                                                          **)
 | 
						|
(******************************************************************************)
 | 
						|
(******************************************************************************)
 | 
						|
 | 
						|
  TDBGEventCategory = (
 | 
						|
    ecBreakpoint, // Breakpoint hit
 | 
						|
    ecProcess,    // Process start, process stop
 | 
						|
    ecThread,     // Thread creation, destruction, start, etc.
 | 
						|
    ecModule,     // Library load and unload
 | 
						|
    ecOutput,     // DebugOutput calls
 | 
						|
    ecWindows,    // Windows events
 | 
						|
    ecDebugger);  // debugger errors and warnings
 | 
						|
  TDBGEventCategories = set of TDBGEventCategory;
 | 
						|
 | 
						|
  TDBGEventType = (
 | 
						|
    etDefault,
 | 
						|
    // ecBreakpoint category
 | 
						|
    etBreakpointEvaluation,
 | 
						|
    etBreakpointHit,
 | 
						|
    etBreakpointMessage,
 | 
						|
    etBreakpointStackDump,
 | 
						|
    etExceptionRaised,
 | 
						|
    // ecModule category
 | 
						|
    etModuleLoad,
 | 
						|
    etModuleUnload,
 | 
						|
    // ecOutput category
 | 
						|
    etOutputDebugString,
 | 
						|
    // ecProcess category
 | 
						|
    etProcessExit,
 | 
						|
    etProcessStart,
 | 
						|
    // ecThread category
 | 
						|
    etThreadExit,
 | 
						|
    etThreadStart,
 | 
						|
    // ecWindows category
 | 
						|
    etWindowsMessagePosted,
 | 
						|
    etWindowsMessageSent
 | 
						|
  );
 | 
						|
 | 
						|
  TDBGFeedbackType = (ftInformation, ftWarning, ftError);
 | 
						|
  TDBGFeedbackResult = (frOk, frStop);
 | 
						|
  TDBGFeedbackResults = set of TDBGFeedbackResult;
 | 
						|
 | 
						|
  TDBGEventNotify = procedure(Sender: TObject;
 | 
						|
                              const ACategory: TDBGEventCategory;
 | 
						|
                              const AEventType: TDBGEventType;
 | 
						|
                              const AText: String) of object;
 | 
						|
 | 
						|
  TDebuggerStateChangedEvent = procedure(ADebugger: TDebuggerIntf;
 | 
						|
                                         AOldState: TDBGState) of object;
 | 
						|
  TDebuggerBreakPointHitEvent = procedure(ADebugger: TDebuggerIntf; ABreakPoint: TBaseBreakPoint;
 | 
						|
                                          var ACanContinue: Boolean) of object;
 | 
						|
  TDBGOutputEvent = procedure(Sender: TObject; const AText: String) of object;
 | 
						|
  TDBGCurrentLineEvent = procedure(Sender: TObject;
 | 
						|
                                   const ALocation: TDBGLocationRec) of object;
 | 
						|
  TDBGExceptionEvent = procedure(Sender: TObject; const AExceptionType: TDBGExceptionType;
 | 
						|
                                 const AExceptionClass: String;
 | 
						|
                                 const AExceptionLocation: TDBGLocationRec;
 | 
						|
                                 const AExceptionText: String;
 | 
						|
                                 out AContinue: Boolean) of object;
 | 
						|
 | 
						|
  TDBGFeedbackEvent = function(Sender: TObject; const AText, AInfo: String;
 | 
						|
                               AType: TDBGFeedbackType; AButtons: TDBGFeedbackResults
 | 
						|
                              ): TDBGFeedbackResult of object;
 | 
						|
 | 
						|
 | 
						|
  TDebuggerNotifyReason = (dnrDestroy);
 | 
						|
 | 
						|
  { TDebuggerProperties }
 | 
						|
 | 
						|
  TDebuggerProperties = class(TPersistent)
 | 
						|
  private
 | 
						|
  public
 | 
						|
    constructor Create; virtual;
 | 
						|
    procedure Assign({%H-}Source: TPersistent); override;
 | 
						|
  published
 | 
						|
  end;
 | 
						|
  TDebuggerPropertiesClass= class of TDebuggerProperties;
 | 
						|
 | 
						|
 | 
						|
  { TDebuggerIntf }
 | 
						|
 | 
						|
  TDebuggerIntf = class
 | 
						|
  private
 | 
						|
    FArguments: String;
 | 
						|
    FBreakPoints: TDBGBreakPoints;
 | 
						|
    FDebuggerEnvironment: TStrings;
 | 
						|
    FCurEnvironment: TStrings;
 | 
						|
    FDisassembler: TDBGDisassembler;
 | 
						|
    FEnvironment: TStrings;
 | 
						|
    FErrorStateInfo: String;
 | 
						|
    FErrorStateMessage: String;
 | 
						|
    FExceptions: TBaseExceptions;
 | 
						|
    FExitCode: Integer;
 | 
						|
    FExternalDebugger: String;
 | 
						|
    FFileName: String;
 | 
						|
    FLocals: TLocalsSupplier;
 | 
						|
    FLineInfo: TDBGLineInfo;
 | 
						|
    //FUnitInfoProvider, FInternalUnitInfoProvider: TDebuggerUnitInfoProvider;
 | 
						|
    FOnBeforeState: TDebuggerStateChangedEvent;
 | 
						|
    FOnConsoleOutput: TDBGOutputEvent;
 | 
						|
    FOnFeedback: TDBGFeedbackEvent;
 | 
						|
    FOnIdle: TNotifyEvent;
 | 
						|
    FRegisters: TRegisterSupplier;
 | 
						|
    FShowConsole: Boolean;
 | 
						|
    FSignals: TDBGSignals;
 | 
						|
    FState: TDBGState;
 | 
						|
    FCallStack: TCallStackSupplier;
 | 
						|
    FWatches: TWatchesSupplier;
 | 
						|
    FThreads: TThreadsSupplier;
 | 
						|
    FOnCurrent: TDBGCurrentLineEvent;
 | 
						|
    FOnException: TDBGExceptionEvent;
 | 
						|
    FOnOutput: TDBGOutputEvent;
 | 
						|
    FOnDbgOutput: TDBGOutputEvent;
 | 
						|
    FOnDbgEvent: TDBGEventNotify;
 | 
						|
    FOnState: TDebuggerStateChangedEvent;
 | 
						|
    FOnBreakPointHit: TDebuggerBreakPointHitEvent;
 | 
						|
    FWorkingDir: String;
 | 
						|
    FDestroyNotificationList: array [TDebuggerNotifyReason] of TMethodList;
 | 
						|
    procedure DebuggerEnvironmentChanged(Sender: TObject);
 | 
						|
    procedure EnvironmentChanged(Sender: TObject);
 | 
						|
    //function GetUnitInfoProvider: TDebuggerUnitInfoProvider;
 | 
						|
    function  GetState: TDBGState;
 | 
						|
    function  ReqCmd(const ACommand: TDBGCommand;
 | 
						|
                     const AParams: array of const): Boolean;
 | 
						|
    procedure SetDebuggerEnvironment (const AValue: TStrings );
 | 
						|
    procedure SetEnvironment(const AValue: TStrings);
 | 
						|
    procedure SetFileName(const AValue: String);
 | 
						|
  protected
 | 
						|
    procedure ResetStateToIdle; virtual;
 | 
						|
    function  CreateBreakPoints: TDBGBreakPoints; virtual;
 | 
						|
    function  CreateLocals: TLocalsSupplier; virtual;
 | 
						|
    function  CreateLineInfo: TDBGLineInfo; virtual;
 | 
						|
    function  CreateRegisters: TRegisterSupplier; virtual;
 | 
						|
    function  CreateCallStack: TCallStackSupplier; virtual;
 | 
						|
    function  CreateDisassembler: TDBGDisassembler; virtual;
 | 
						|
    function  CreateWatches: TWatchesSupplier; virtual;
 | 
						|
    function  CreateThreads: TThreadsSupplier; virtual;
 | 
						|
    function  CreateSignals: TDBGSignals; virtual;
 | 
						|
    procedure DoCurrent(const ALocation: TDBGLocationRec);
 | 
						|
    procedure DoDbgOutput(const AText: String);
 | 
						|
    procedure DoDbgEvent(const ACategory: TDBGEventCategory; const AEventType: TDBGEventType; const AText: String);
 | 
						|
    procedure DoException(const AExceptionType: TDBGExceptionType;
 | 
						|
                          const AExceptionClass: String;
 | 
						|
                          const AExceptionLocation: TDBGLocationRec;
 | 
						|
                          const AExceptionText: String;
 | 
						|
                          out AContinue: Boolean);
 | 
						|
    procedure DoOutput(const AText: String);
 | 
						|
    procedure DoBreakpointHit(const ABreakPoint: TBaseBreakPoint; var ACanContinue: Boolean);
 | 
						|
    procedure DoBeforeState(const OldState: TDBGState); virtual;
 | 
						|
    procedure DoState(const OldState: TDBGState); virtual;
 | 
						|
    function  ChangeFileName: Boolean; virtual;
 | 
						|
    function  GetCommands: TDBGCommands; virtual;
 | 
						|
    function  GetSupportedCommands: TDBGCommands; virtual;
 | 
						|
    function  GetTargetWidth: Byte; virtual;
 | 
						|
    function  GetWaiting: Boolean; virtual;
 | 
						|
    function  GetIsIdle: Boolean; virtual;
 | 
						|
    function  RequestCommand(const ACommand: TDBGCommand;
 | 
						|
                             const AParams: array of const): Boolean;
 | 
						|
                             virtual; abstract; // True if succesful
 | 
						|
    procedure SetExitCode(const AValue: Integer);
 | 
						|
    procedure SetState(const AValue: TDBGState);
 | 
						|
    procedure SetErrorState(const AMsg: String; const AInfo: String = '');
 | 
						|
    procedure DoRelease; virtual;
 | 
						|
  public
 | 
						|
    class function Caption: String; virtual;         // The name of the debugger as shown in the debuggeroptions
 | 
						|
    class function ExePaths: String; virtual;        // The default locations of the exe
 | 
						|
    class function HasExePath: boolean; virtual; deprecated; // use NeedsExePath instead
 | 
						|
    class function NeedsExePath: boolean; virtual;        // If the debugger needs to have an exe path
 | 
						|
    class function CanExternalDebugSymbolsFile: boolean; virtual; // If the debugger support the -Xg compiler option to store the debug info in an external file
 | 
						|
 | 
						|
    // debugger properties
 | 
						|
    class function CreateProperties: TDebuggerProperties; virtual;         // Creates debuggerproperties
 | 
						|
    class function GetProperties: TDebuggerProperties;                     // Get the current properties
 | 
						|
    class procedure SetProperties(const AProperties: TDebuggerProperties); // Set the current properties
 | 
						|
 | 
						|
    (* TODO:
 | 
						|
       This method is a workaround for http://bugs.freepascal.org/view.php?id=21834
 | 
						|
       See main.pp 12188 function TMainIDE.DoInitProjectRun: TModalResult;
 | 
						|
       See debugmanager function TDebugManager.InitDebugger: Boolean;
 | 
						|
       Checks could be performed in SetFileName, invalidating debuggerstate
 | 
						|
       Errors should also be reported by debugger
 | 
						|
    *)
 | 
						|
    class function  RequiresLocalExecutable: Boolean; virtual;
 | 
						|
  public
 | 
						|
    constructor Create(const AExternalDebugger: String); virtual;
 | 
						|
    destructor Destroy; override;
 | 
						|
 | 
						|
    procedure Init; virtual;                         // Initializes the debugger
 | 
						|
    procedure Done; virtual;                         // Kills the debugger
 | 
						|
    procedure Release;                               // Free/Destroy self
 | 
						|
    procedure Run;                                   // Starts / continues debugging
 | 
						|
    procedure Pause;                                 // Stops running
 | 
						|
    procedure Stop;                                  // quit debugging
 | 
						|
    procedure StepOver;
 | 
						|
    procedure StepInto;
 | 
						|
    procedure StepOverInstr;
 | 
						|
    procedure StepIntoInstr;
 | 
						|
    procedure StepOut;
 | 
						|
    procedure RunTo(const ASource: String; const ALine: Integer);                // Executes til a certain point
 | 
						|
    procedure JumpTo(const ASource: String; const ALine: Integer);               // No execute, only set exec point
 | 
						|
    procedure Attach(AProcessID: String);
 | 
						|
    procedure Detach;
 | 
						|
    procedure SendConsoleInput(AText: String);
 | 
						|
    function  Evaluate(const AExpression: String; var AResult: String;
 | 
						|
                       var ATypeInfo: TDBGType;
 | 
						|
                       EvalFlags: TDBGEvaluateFlags = []): Boolean;                     // Evaluates the given expression, returns true if valid
 | 
						|
    function GetProcessList({%H-}AList: TRunningProcessInfoList): boolean; virtual;
 | 
						|
    function  Modify(const AExpression, AValue: String): Boolean;                // Modifies the given expression, returns true if valid
 | 
						|
    function  Disassemble(AAddr: TDbgPtr; ABackward: Boolean; out ANextAddr: TDbgPtr;
 | 
						|
                          out ADump, AStatement, AFile: String; out ALine: Integer): Boolean; deprecated;
 | 
						|
    function GetLocation: TDBGLocationRec; virtual;
 | 
						|
    procedure LockCommandProcessing; virtual;
 | 
						|
    procedure UnLockCommandProcessing; virtual;
 | 
						|
    function  NeedReset: Boolean; virtual;
 | 
						|
    procedure AddNotifyEvent(AReason: TDebuggerNotifyReason; AnEvent: TNotifyEvent);
 | 
						|
    procedure RemoveNotifyEvent(AReason: TDebuggerNotifyReason; AnEvent: TNotifyEvent);
 | 
						|
  public
 | 
						|
    property Arguments: String read FArguments write FArguments;                 // Arguments feed to the program
 | 
						|
    property BreakPoints: TDBGBreakPoints read FBreakPoints;                     // list of all breakpoints
 | 
						|
    property CallStack: TCallStackSupplier read FCallStack;
 | 
						|
    property Disassembler: TDBGDisassembler read FDisassembler;
 | 
						|
    property Commands: TDBGCommands read GetCommands;                            // All current available commands of the debugger
 | 
						|
    property DebuggerEnvironment: TStrings read FDebuggerEnvironment
 | 
						|
                                           write SetDebuggerEnvironment;         // The environment passed to the debugger process
 | 
						|
    property Environment: TStrings read FEnvironment write SetEnvironment;       // The environment passed to the debuggee
 | 
						|
    property Exceptions: TBaseExceptions read FExceptions write FExceptions;      // A list of exceptions we should ignore
 | 
						|
    property ExitCode: Integer read FExitCode;
 | 
						|
    property ExternalDebugger: String read FExternalDebugger;                    // The name of the debugger executable
 | 
						|
    property FileName: String read FFileName write SetFileName;                  // The name of the exe to be debugged
 | 
						|
    property Locals: TLocalsSupplier read FLocals;                                    // list of all localvars etc
 | 
						|
    property LineInfo: TDBGLineInfo read FLineInfo;                              // list of all source LineInfo
 | 
						|
    property Registers: TRegisterSupplier read FRegisters;                           // list of all registers
 | 
						|
    property Signals: TDBGSignals read FSignals;                                 // A list of actions for signals we know
 | 
						|
    property ShowConsole: Boolean read FShowConsole write FShowConsole;          // Indicates if the debugger should create a console for the debuggee
 | 
						|
    property State: TDBGState read FState;                                       // The current state of the debugger
 | 
						|
    property SupportedCommands: TDBGCommands read GetSupportedCommands;          // All available commands of the debugger
 | 
						|
    property TargetWidth: Byte read GetTargetWidth;                              // Currently only 32 or 64
 | 
						|
    property Waiting: Boolean read GetWaiting;                                   // Set when the debugger is wating for a command to complete
 | 
						|
    property Watches: TWatchesSupplier read FWatches;                                 // list of all watches etc
 | 
						|
    property Threads: TThreadsSupplier read FThreads;
 | 
						|
    property WorkingDir: String read FWorkingDir write FWorkingDir;              // The working dir of the exe being debugged
 | 
						|
    property IsIdle: Boolean read GetIsIdle;                                     // Nothing queued
 | 
						|
    property ErrorStateMessage: String read FErrorStateMessage;
 | 
						|
    property ErrorStateInfo: String read FErrorStateInfo;
 | 
						|
    //property UnitInfoProvider: TDebuggerUnitInfoProvider                        // Provided by DebugBoss, to map files to packages or project
 | 
						|
    //         read GetUnitInfoProvider write FUnitInfoProvider;
 | 
						|
    // Events
 | 
						|
    property OnCurrent: TDBGCurrentLineEvent read FOnCurrent write FOnCurrent;   // Passes info about the current line being debugged
 | 
						|
    property OnDbgOutput: TDBGOutputEvent read FOnDbgOutput write FOnDbgOutput;  // Passes all debuggeroutput
 | 
						|
    property OnDbgEvent: TDBGEventNotify read FOnDbgEvent write FOnDbgEvent;     // Passes recognized debugger events, like library load or unload
 | 
						|
    property OnException: TDBGExceptionEvent read FOnException write FOnException;  // Fires when the debugger received an exeption
 | 
						|
    property OnOutput: TDBGOutputEvent read FOnOutput write FOnOutput;           // Passes all output of the debugged target
 | 
						|
    property OnBeforeState: TDebuggerStateChangedEvent read FOnBeforeState write FOnBeforeState;   // Fires when the current state of the debugger changes
 | 
						|
    property OnState: TDebuggerStateChangedEvent read FOnState write FOnState;   // Fires when the current state of the debugger changes
 | 
						|
    property OnBreakPointHit: TDebuggerBreakPointHitEvent read FOnBreakPointHit write FOnBreakPointHit;   // Fires when the program is paused at a breakpoint
 | 
						|
    property OnConsoleOutput: TDBGOutputEvent read FOnConsoleOutput write FOnConsoleOutput;  // Passes Application Console Output
 | 
						|
    property OnFeedback: TDBGFeedbackEvent read FOnFeedback write FOnFeedback;
 | 
						|
    property OnIdle: TNotifyEvent read FOnIdle write FOnIdle;                    // Called if all outstanding requests are processed (queue empty)
 | 
						|
  end;
 | 
						|
  TDebuggerClass = class of TDebuggerIntf;
 | 
						|
 | 
						|
  TBaseDebugManagerIntf = class(TComponent)
 | 
						|
  protected
 | 
						|
    function GetDebuggerClass(const AIndex: Integer): TDebuggerClass;
 | 
						|
    function FindDebuggerClass(const Astring: String): TDebuggerClass;
 | 
						|
  public
 | 
						|
    function DebuggerCount: Integer;
 | 
						|
  end;
 | 
						|
 | 
						|
procedure RegisterDebugger(const ADebuggerClass: TDebuggerClass);
 | 
						|
 | 
						|
function dbgs(AState: TDBGState): String; overload;
 | 
						|
function dbgs(ADataState: TDebuggerDataState): String; overload;
 | 
						|
function dbgs(AKind: TDBGSymbolKind): String; overload;
 | 
						|
function dbgs(AnAttribute: TDBGSymbolAttribute): String; overload;
 | 
						|
function dbgs(AnAttributes: TDBGSymbolAttributes): String; overload;
 | 
						|
function dbgs(ADisassRange: TDBGDisassemblerEntryRange): String; overload;
 | 
						|
function dbgs(const AnAddr: TDisassemblerAddress): string; overload;
 | 
						|
function dbgs(ACategory: TDBGEventCategory): String; overload;
 | 
						|
function dbgs(AFlag: TDBGEvaluateFlag): String; overload;
 | 
						|
function dbgs(AFlags: TDBGEvaluateFlags): String; overload;
 | 
						|
function dbgs(AName: TDBGCommand): String; overload;
 | 
						|
 | 
						|
var
 | 
						|
  DbgStateChangeCounter: Integer = 0;  // workaround for state changes during TWatchValue.GetValue
 | 
						|
 | 
						|
implementation
 | 
						|
 | 
						|
var
 | 
						|
  DBG_STATE, DBG_EVENTS, DBG_STATE_EVENT, DBG_DATA_MONITORS,
 | 
						|
  DBG_VERBOSE, DBG_WARNINGS, DBG_DISASSEMBLER: PLazLoggerLogGroup;
 | 
						|
 | 
						|
const
 | 
						|
  COMMANDMAP: array[TDBGState] of TDBGCommands = (
 | 
						|
  {dsNone } [],
 | 
						|
  {dsIdle } [dcEnvironment],
 | 
						|
  {dsStop } [dcRun, dcStepOver, dcStepInto, dcStepOverInstr, dcStepIntoInstr,
 | 
						|
             dcAttach, dcBreak, dcWatch, dcEvaluate, dcEnvironment,
 | 
						|
             dcSendConsoleInput],
 | 
						|
  {dsPause} [dcRun, dcStop, dcStepOver, dcStepInto, dcStepOverInstr, dcStepIntoInstr,
 | 
						|
             dcStepOut, dcRunTo, dcJumpto, dcDetach, dcBreak, dcWatch, dcLocal, dcEvaluate, dcModify,
 | 
						|
             dcEnvironment, dcSetStackFrame, dcDisassemble, dcSendConsoleInput],
 | 
						|
  {dsInternalPause} // same as run, so not really used
 | 
						|
            [dcStop, dcBreak, dcWatch, dcEnvironment, dcSendConsoleInput],
 | 
						|
  {dsInit } [],
 | 
						|
  {dsRun  } [dcPause, dcStop, dcDetach, dcBreak, dcWatch, dcEnvironment, dcSendConsoleInput],
 | 
						|
  {dsError} [dcStop],
 | 
						|
  {dsDestroying} []
 | 
						|
  );
 | 
						|
 | 
						|
var
 | 
						|
  MDebuggerPropertiesList: TStringlist = nil;
 | 
						|
  MDebuggerClasses: TStringList;
 | 
						|
 | 
						|
procedure RegisterDebugger(const ADebuggerClass: TDebuggerClass);
 | 
						|
begin
 | 
						|
  MDebuggerClasses.AddObject(ADebuggerClass.ClassName, TObject(Pointer(ADebuggerClass)));
 | 
						|
end;
 | 
						|
 | 
						|
procedure DoFinalization;
 | 
						|
var
 | 
						|
  n: Integer;
 | 
						|
begin
 | 
						|
  if MDebuggerPropertiesList <> nil
 | 
						|
  then begin
 | 
						|
    for n := 0 to MDebuggerPropertiesList.Count - 1 do
 | 
						|
      MDebuggerPropertiesList.Objects[n].Free;
 | 
						|
    FreeAndNil(MDebuggerPropertiesList);
 | 
						|
  end;
 | 
						|
end;
 | 
						|
 | 
						|
function dbgs(AState: TDBGState): String; overload;
 | 
						|
begin
 | 
						|
  Result := '';
 | 
						|
  WriteStr(Result, AState);
 | 
						|
end;
 | 
						|
 | 
						|
function dbgs(ADataState: TDebuggerDataState): String;
 | 
						|
begin
 | 
						|
  writestr(Result{%H-}, ADataState);
 | 
						|
end;
 | 
						|
 | 
						|
function dbgs(AKind: TDBGSymbolKind): String;
 | 
						|
begin
 | 
						|
  writestr(Result{%H-}, AKind);
 | 
						|
end;
 | 
						|
 | 
						|
function dbgs(AnAttribute: TDBGSymbolAttribute): String;
 | 
						|
begin
 | 
						|
  writestr(Result{%H-}, AnAttribute);
 | 
						|
end;
 | 
						|
 | 
						|
function dbgs(AnAttributes: TDBGSymbolAttributes): String;
 | 
						|
var
 | 
						|
  i: TDBGSymbolAttribute;
 | 
						|
begin
 | 
						|
  Result:='';
 | 
						|
  for i := low(TDBGSymbolAttributes) to high(TDBGSymbolAttributes) do
 | 
						|
    if i in AnAttributes then begin
 | 
						|
      if Result <> '' then Result := Result + ', ';
 | 
						|
      Result := Result + dbgs(i);
 | 
						|
    end;
 | 
						|
  if Result <> '' then Result := '[' + Result + ']';
 | 
						|
end;
 | 
						|
 | 
						|
function dbgs(ACategory: TDBGEventCategory): String;
 | 
						|
begin
 | 
						|
  writestr(Result{%H-}, ACategory);
 | 
						|
end;
 | 
						|
 | 
						|
function dbgs(AFlag: TDBGEvaluateFlag): String;
 | 
						|
begin
 | 
						|
  Result := '';
 | 
						|
  WriteStr(Result, AFlag);
 | 
						|
end;
 | 
						|
 | 
						|
function dbgs(AFlags: TDBGEvaluateFlags): String;
 | 
						|
var
 | 
						|
  i: TDBGEvaluateFlag;
 | 
						|
begin
 | 
						|
  Result:='';
 | 
						|
  for i := low(TDBGEvaluateFlags) to high(TDBGEvaluateFlags) do
 | 
						|
    if i in AFlags then begin
 | 
						|
      if Result <> '' then Result := Result + ', ';
 | 
						|
      Result := Result + dbgs(i);
 | 
						|
    end;
 | 
						|
  Result := '[' + Result + ']';
 | 
						|
end;
 | 
						|
 | 
						|
function dbgs(AName: TDBGCommand): String;
 | 
						|
begin
 | 
						|
  Result := '';
 | 
						|
  WriteStr(Result, AName);
 | 
						|
end;
 | 
						|
 | 
						|
function dbgs(ADisassRange: TDBGDisassemblerEntryRange): String; overload;
 | 
						|
var
 | 
						|
  fo: Integer;
 | 
						|
begin
 | 
						|
  if (ADisassRange = nil)
 | 
						|
  then begin
 | 
						|
    Result := 'Range(nil)'
 | 
						|
  end
 | 
						|
  else begin
 | 
						|
    if (ADisassRange.Count > 0)
 | 
						|
    then fo := ADisassRange.EntriesPtr[0]^.Offset
 | 
						|
    else fo := 0;
 | 
						|
    {$PUSH}{$RANGECHECKS OFF}
 | 
						|
    with ADisassRange do
 | 
						|
      Result := Format('Range(%u)=[[ Cnt=%d, Capac=%d, [0].Addr=%u, RFirst=%u, [Cnt].Addr=%u, RLast=%u, REnd=%u, FirstOfs=%d ]]',
 | 
						|
        [PtrUInt(ADisassRange), Count, Capacity, FirstAddr, RangeStartAddr, LastAddr, RangeEndAddr, LastEntryEndAddr, fo]);
 | 
						|
    {$POP}
 | 
						|
  end;
 | 
						|
end;
 | 
						|
 | 
						|
function Dbgs(const AnAddr: TDisassemblerAddress): string;
 | 
						|
const
 | 
						|
  ValidityName: array [TDisassemblerAddressValidity] of string =
 | 
						|
    ('FoundFunction', 'FoundRange', 'FoundStatemnet', 'Guessed', 'ExternRequest', 'Padded');
 | 
						|
begin
 | 
						|
  Result := Format('[[ Value=%u, Guessed=%u, Offset=%d, Validity=%s ]]',
 | 
						|
                   [AnAddr.Value, AnAddr.GuessedValue, AnAddr.Offset, ValidityName[AnAddr.Validity]]);
 | 
						|
end;
 | 
						|
 | 
						|
{ TDBGDisassemblerRangeExtender }
 | 
						|
 | 
						|
function TDBGDisassemblerRangeExtender.InitAddress(AValue: TDBGPtr;
 | 
						|
  AValidity: TDisassemblerAddressValidity; AnOffset: Integer): TDisassemblerAddress;
 | 
						|
begin
 | 
						|
  Result.Value          := AValue;
 | 
						|
  Result.GuessedValue   := AValue;;
 | 
						|
  Result.Offset   := AnOffset;
 | 
						|
  Result.Validity := AValidity;
 | 
						|
end;
 | 
						|
 | 
						|
constructor TDBGDisassemblerRangeExtender.Create(AnEntryRangeMap: TDBGDisassemblerEntryMap);
 | 
						|
begin
 | 
						|
  FEntryRangeMap := AnEntryRangeMap;
 | 
						|
  FRangeIterator:= TDBGDisassemblerEntryMapIterator.Create(FEntryRangeMap);
 | 
						|
end;
 | 
						|
 | 
						|
destructor TDBGDisassemblerRangeExtender.Destroy;
 | 
						|
begin
 | 
						|
  FRangeIterator.Free;
 | 
						|
  inherited;
 | 
						|
end;
 | 
						|
 | 
						|
function TDBGDisassemblerRangeExtender.CheckIfCancelled: boolean;
 | 
						|
begin
 | 
						|
  result := assigned(FOnCheckCancel) and FOnCheckCancel();
 | 
						|
end;
 | 
						|
 | 
						|
// Set Value, based on GuessedValue
 | 
						|
function TDBGDisassemblerRangeExtender.AdjustToRangeOrKnowFunctionStart(var AStartAddr: TDisassemblerAddress;
 | 
						|
  ARangeBefore: TDBGDisassemblerEntryRange): Boolean;
 | 
						|
begin
 | 
						|
  Result := False;
 | 
						|
  AStartAddr.Offset := -1;
 | 
						|
  AStartAddr.Validity := avGuessed;
 | 
						|
  if OnAdjustToKnowFunctionStart(AStartAddr)
 | 
						|
  then begin
 | 
						|
    // funtion found, check for range
 | 
						|
    if (ARangeBefore <> nil) and (ARangeBefore.LastAddr > AStartAddr.Value)
 | 
						|
    and (ARangeBefore.Count > DAssRangeOverFuncTreshold)
 | 
						|
    and (ARangeBefore.EntriesPtr[ARangeBefore.Count - 1]^.Offset > DAssRangeOverFuncTreshold  * DAssBytesPerCommandAvg)
 | 
						|
    then begin
 | 
						|
      // got a big overlap, don't redo the whole function
 | 
						|
      debugln(DBG_DISASSEMBLER, ['INFO: Restarting inside previous range for known function-start=', Dbgs(AStartAddr),'  and ARangeBefore=', dbgs(ARangeBefore)]);
 | 
						|
      // redo one statement
 | 
						|
      {$PUSH}{$IFnDEF DBGMI_WITH_DISASS_OVERFLOW}{$Q-}{$R-}{$ENDIF} // Overflow is allowed to occur
 | 
						|
      AStartAddr.Value  := ARangeBefore.EntriesPtr[ARangeBefore.Count - 1]^.Addr;
 | 
						|
      AStartAddr.Offset := ARangeBefore.EntriesPtr[ARangeBefore.Count - 1]^.Offset;
 | 
						|
      AStartAddr.Validity := avFoundRange;
 | 
						|
      //AStartAddr - ARangeBefore.EntriesPtr[ARangeBefore.Count - DAssRangeOverFuncTreshold]^.Addr ;
 | 
						|
      {$POP}
 | 
						|
    end
 | 
						|
  end
 | 
						|
  else begin
 | 
						|
    debugln(DBG_DISASSEMBLER, ['INFO: No known function-start for ', Dbgs(AStartAddr),'  ARangeBefore=', dbgs(ARangeBefore)]);
 | 
						|
    // no function found // check distance to previous range
 | 
						|
    // The distance of range before has been checked by the caller
 | 
						|
    if (ARangeBefore <> nil)
 | 
						|
    then begin
 | 
						|
      {$PUSH}{$IFnDEF DBGMI_WITH_DISASS_OVERFLOW}{$Q-}{$R-}{$ENDIF} // Overflow is allowed to occur
 | 
						|
      AStartAddr.Value := ARangeBefore.EntriesPtr[ARangeBefore.Count - 1]^.Addr;
 | 
						|
      AStartAddr.Offset := ARangeBefore.EntriesPtr[ARangeBefore.Count - 1]^.Offset;
 | 
						|
      AStartAddr.Validity := avFoundRange;
 | 
						|
      {$POP}
 | 
						|
    end
 | 
						|
    else begin
 | 
						|
      AStartAddr.Value := AStartAddr.GuessedValue;
 | 
						|
      AStartAddr.Offset := -1;
 | 
						|
      AStartAddr.Validity := avGuessed;
 | 
						|
    end;
 | 
						|
  end;
 | 
						|
end;
 | 
						|
 | 
						|
function TDBGDisassemblerRangeExtender.DisassembleRange(ALinesBefore,
 | 
						|
  ALinesAfter: integer; AStartAddr: TDBGPtr; AnEndAddr: TDBGPtr): boolean;
 | 
						|
var
 | 
						|
  TryStartAt, TryEndAt: TDisassemblerAddress;
 | 
						|
  TmpAddr: TDBGPtr;
 | 
						|
  GotCnt, LastGotCnt: Integer;
 | 
						|
  RngBefore, RngAfter: TDBGDisassemblerEntryRange;
 | 
						|
begin
 | 
						|
  result := true;
 | 
						|
  (* Try to find the boundaries for the unknown range containing FStartAddr
 | 
						|
     If FStartAddr already has known disassembler data, then this will return
 | 
						|
     the boundaries of the 1ast unknown section after FStartAddr
 | 
						|
  *)
 | 
						|
  // Guess the maximum Addr-Range which needs to be disassembled
 | 
						|
  TryStartAt := InitAddress(AStartAddr, avExternRequest, -1);
 | 
						|
  // Find the begin of the function at TryStartAt
 | 
						|
  // or the rng before (if not to far back)
 | 
						|
 | 
						|
  RngBefore := FRangeIterator.GetRangeForAddr(AStartAddr, True);
 | 
						|
  {$PUSH}{$IFnDEF DBGMI_WITH_DISASS_OVERFLOW}{$Q-}{$R-}{$ENDIF} // Overflow is allowed to occur
 | 
						|
  if (RngBefore <> nil)
 | 
						|
  and (TryStartAt.Value > RngBefore.EntriesPtr[RngBefore.Count - 1]^.Addr)
 | 
						|
  and (TryStartAt.Value - RngBefore.EntriesPtr[RngBefore.Count - 1]^.Addr > ALinesBefore * DAssBytesPerCommandAvg)
 | 
						|
  then RngBefore := nil;
 | 
						|
  {$POP}
 | 
						|
  TmpAddr := AStartAddr - Min(ALinesBefore * DAssBytesPerCommandAvg, DAssMaxRangeSize);
 | 
						|
  TryStartAt.GuessedValue := TmpAddr;
 | 
						|
  AdjustToRangeOrKnowFunctionStart(TryStartAt, RngBefore);
 | 
						|
  // check max size
 | 
						|
  if (TryStartAt.Value < AStartAddr - Min(AStartAddr, DAssMaxRangeSize))
 | 
						|
  then begin
 | 
						|
    DebugLn(DBG_DISASSEMBLER, ['INFO: Limit Range for Disass: FStartAddr=', AStartAddr, '  TryStartAt.Value=', TryStartAt.Value  ]);
 | 
						|
    TryStartAt := InitAddress(TmpAddr, avGuessed);
 | 
						|
  end;
 | 
						|
 | 
						|
  // Guess Maximum, will adjust later
 | 
						|
  if TryStartAt.Value > AnEndAddr then begin
 | 
						|
    if (RngBefore <> nil) then begin
 | 
						|
      GotCnt := RngBefore.IndexOfAddr(AnEndAddr);
 | 
						|
      LastGotCnt := RngBefore.IndexOfAddr(TryStartAt.Value);
 | 
						|
      if (GotCnt >= 0) and (LastGotCnt >= 0) and (LastGotCnt > GotCnt) then
 | 
						|
        ALinesAfter := Max(ALinesAfter - (LastGotCnt - GotCnt), 1);
 | 
						|
    end;
 | 
						|
    AnEndAddr := TryStartAt.Value; // WARNING: modifying FEndAddr
 | 
						|
  end;
 | 
						|
 | 
						|
  TryEndAt := InitAddress(AnEndAddr + ALinesAfter * DAssBytesPerCommandAvg, avGuessed);
 | 
						|
 | 
						|
  // Read as many unknown ranges, until LinesAfter is met
 | 
						|
  GotCnt := -1;
 | 
						|
  while(True)
 | 
						|
  do begin
 | 
						|
    // check if we need any LinesAfter
 | 
						|
    if CheckIfCancelled then break;
 | 
						|
    LastGotCnt:= GotCnt;
 | 
						|
    GotCnt := 0;
 | 
						|
    TmpAddr := AnEndAddr;
 | 
						|
    if TryStartAt.Value > AnEndAddr
 | 
						|
    then
 | 
						|
      TmpAddr := TryStartAt.Value;
 | 
						|
    if RngBefore <> nil
 | 
						|
    then begin
 | 
						|
      TmpAddr := RngBefore.RangeEndAddr;
 | 
						|
      if RngBefore.EntriesPtr[RngBefore.Count - 1]^.Addr > TmpAddr
 | 
						|
      then TmpAddr := RngBefore.EntriesPtr[RngBefore.Count - 1]^.Addr;
 | 
						|
      GotCnt := RngBefore.IndexOfAddrWithOffs(AnEndAddr);
 | 
						|
      if GotCnt >= 0 then begin
 | 
						|
        GotCnt := RngBefore.Count - 1 - GotCnt;  // the amount of LinesAfter, that are already known
 | 
						|
        if (GotCnt >= ALinesAfter)
 | 
						|
        then break;
 | 
						|
        // adjust end address
 | 
						|
        TryEndAt := InitAddress(RngBefore.RangeEndAddr + (ALinesAfter-GotCnt) * DAssBytesPerCommandAvg, avGuessed);
 | 
						|
      end
 | 
						|
      else GotCnt := 0;
 | 
						|
    end;
 | 
						|
    if LastGotCnt >= GotCnt
 | 
						|
    then begin
 | 
						|
      debugln(['Disassembler: *** Failure to get any more lines while scanning forward LastGotCnt=',LastGotCnt, ' now GotCnt=',GotCnt, ' Requested=',ALinesAfter]);
 | 
						|
      break;
 | 
						|
    end;
 | 
						|
 | 
						|
    if CheckIfCancelled then break;
 | 
						|
    RngAfter := FRangeIterator.NextRange;
 | 
						|
    // adjust TryEndAt
 | 
						|
    if (RngAfter <> nil) and (TryEndAt.Value >= RngAfter.RangeStartAddr)
 | 
						|
    then begin
 | 
						|
      TryEndAt.Value := RngAfter.RangeStartAddr;
 | 
						|
      TryEndAt.Validity := avFoundRange;
 | 
						|
    end;
 | 
						|
 | 
						|
    if CheckIfCancelled then break;
 | 
						|
    // Try to disassemble the range
 | 
						|
    if not OnDoDisassembleRange(FEntryRangeMap, TryStartAt, TryEndAt, TmpAddr, ALinesAfter-GotCnt)
 | 
						|
    then begin
 | 
						|
      // disassemble failed
 | 
						|
      debugln(['ERROR: Failed to disassemble from ', Dbgs(TryStartAt),' to ', Dbgs(TryEndAt)]);
 | 
						|
      break;
 | 
						|
    end;
 | 
						|
 | 
						|
    // prepare the next range
 | 
						|
    RngBefore := FRangeIterator.GetRangeForAddr(AStartAddr, True);
 | 
						|
    if (RngBefore = nil)
 | 
						|
    then begin
 | 
						|
      debugln(['INTERNAL ERROR: (linesafter) Missing the data, that was just  disassembled: from ', Dbgs(TryStartAt),' to ', Dbgs(TryEndAt)]);
 | 
						|
      break;
 | 
						|
    end;
 | 
						|
 | 
						|
    TryStartAt.Value := RngBefore.RangeEndAddr;
 | 
						|
    TryStartAt.Validity := avFoundRange;
 | 
						|
    TryEndAt := InitAddress(AnEndAddr + ALinesAfter * DAssBytesPerCommandAvg, avGuessed);
 | 
						|
  end;
 | 
						|
 | 
						|
  // Find LinesBefore
 | 
						|
  RngAfter := FRangeIterator.GetRangeForAddr(AStartAddr, True);
 | 
						|
  GotCnt := -1;
 | 
						|
  while(True)
 | 
						|
  do begin
 | 
						|
    if CheckIfCancelled then break;
 | 
						|
    LastGotCnt:= GotCnt;
 | 
						|
    if (RngAfter = nil)
 | 
						|
    then begin
 | 
						|
      debugln(['INTERNAL ERROR: (linesbefore) Missing the data, that was disassembled: from ', Dbgs(TryStartAt),' to ', Dbgs(TryEndAt)]);
 | 
						|
      break;
 | 
						|
    end;
 | 
						|
 | 
						|
    GotCnt := RngAfter.IndexOfAddrWithOffs(AStartAddr);  // already known before
 | 
						|
    if GotCnt >= ALinesBefore
 | 
						|
    then break;
 | 
						|
    if LastGotCnt >= GotCnt
 | 
						|
    then begin
 | 
						|
      debugln(['Disassembler: *** Failure to get any more lines while scanning backward LastGotCnt=',LastGotCnt, ' now GotCnt=',GotCnt, ' Requested=',ALinesBefore]);
 | 
						|
      break;
 | 
						|
    end;
 | 
						|
 | 
						|
    TryEndAt := InitAddress(RngAfter.RangeStartAddr, avFoundRange);
 | 
						|
    TmpAddr := TryEndAt.Value - Min((ALinesBefore - GotCnt) * DAssBytesPerCommandAvg, DAssMaxRangeSize);
 | 
						|
    TryStartAt := InitAddress(TryEndAt.Value - 1, avGuessed);
 | 
						|
    TryStartAt.GuessedValue := TmpAddr;
 | 
						|
    // and adjust
 | 
						|
    RngBefore := FRangeIterator.PreviousRange;
 | 
						|
    {$PUSH}{$IFnDEF DBGMI_WITH_DISASS_OVERFLOW}{$Q-}{$R-}{$ENDIF} // Overflow is allowed to occur
 | 
						|
    if (RngBefore <> nil)
 | 
						|
    and (TryStartAt.Value > RngBefore.EntriesPtr[RngBefore.Count - 1]^.Addr)
 | 
						|
    and (TryStartAt.Value - RngBefore.EntriesPtr[RngBefore.Count - 1]^.Addr > (ALinesBefore - GotCnt) * DAssBytesPerCommandAvg)
 | 
						|
    then RngBefore := nil;
 | 
						|
    {$POP}
 | 
						|
    AdjustToRangeOrKnowFunctionStart(TryStartAt, RngBefore);
 | 
						|
    if (TryStartAt.Value < TryEndAt.Value - Min(TryEndAt.Value, DAssMaxRangeSize))
 | 
						|
    then begin
 | 
						|
      DebugLn(DBG_DISASSEMBLER, ['INFO: Limit Range for Disass: TryEndAt.Value=', TryEndAt.Value, '  TryStartAt.Value=', TryStartAt.Value  ]);
 | 
						|
      TryStartAt := InitAddress(TmpAddr, avGuessed);
 | 
						|
    end;
 | 
						|
 | 
						|
    if CheckIfCancelled then break;
 | 
						|
    // Try to disassemble the range
 | 
						|
    if not OnDoDisassembleRange(FEntryRangeMap, TryStartAt, TryEndAt, 0, -1)
 | 
						|
    then begin
 | 
						|
      // disassemble failed
 | 
						|
      debugln(['ERROR: Failed to disassemble from ', Dbgs(TryStartAt),' to ', Dbgs(TryEndAt)]);
 | 
						|
      break;
 | 
						|
    end;
 | 
						|
 | 
						|
    RngAfter := FRangeIterator.GetRangeForAddr(AStartAddr, True);
 | 
						|
  end;
 | 
						|
end;
 | 
						|
 | 
						|
{ TThreadEntry }
 | 
						|
 | 
						|
procedure TThreadEntry.SetThreadState(AValue: String);
 | 
						|
begin
 | 
						|
  if FThreadState = AValue then Exit;
 | 
						|
  FThreadState := AValue;
 | 
						|
end;
 | 
						|
 | 
						|
function TThreadEntry.CreateStackEntry: TCallStackEntry;
 | 
						|
begin
 | 
						|
  Result := TCallStackEntry.Create;
 | 
						|
end;
 | 
						|
 | 
						|
constructor TThreadEntry.Create;
 | 
						|
begin
 | 
						|
  FTopFrame := CreateStackEntry;
 | 
						|
  inherited Create;
 | 
						|
end;
 | 
						|
 | 
						|
constructor TThreadEntry.Create(const AnAdress: TDbgPtr; const AnArguments: TStrings;
 | 
						|
  const AFunctionName: String; const FileName, FullName: String; const ALine: Integer;
 | 
						|
  const AThreadId: Integer; const AThreadName: String; const AThreadState: String;
 | 
						|
  AState: TDebuggerDataState);
 | 
						|
begin
 | 
						|
  Create;
 | 
						|
  TopFrame.Init(AnAdress, AnArguments, AFunctionName, FileName, FullName, ALine, AState);
 | 
						|
  FThreadId    := AThreadId;
 | 
						|
  FThreadName  := AThreadName;
 | 
						|
  FThreadState := AThreadState;
 | 
						|
end;
 | 
						|
 | 
						|
function TThreadEntry.CreateCopy: TThreadEntry;
 | 
						|
begin
 | 
						|
  Result := TThreadEntry.Create;
 | 
						|
  Result.Assign(Self);
 | 
						|
end;
 | 
						|
 | 
						|
destructor TThreadEntry.Destroy;
 | 
						|
begin
 | 
						|
  inherited Destroy;
 | 
						|
  FreeAndNil(FTopFrame);
 | 
						|
end;
 | 
						|
 | 
						|
procedure TThreadEntry.Assign(AnOther: TThreadEntry);
 | 
						|
begin
 | 
						|
  FTopFrame.Free;
 | 
						|
  FTopFrame    := AnOther.TopFrame.CreateCopy;
 | 
						|
  FThreadId    := AnOther.FThreadId;
 | 
						|
  FThreadName  := AnOther.FThreadName;
 | 
						|
  FThreadState := AnOther.FThreadState;
 | 
						|
end;
 | 
						|
 | 
						|
{ TThreads }
 | 
						|
 | 
						|
function TThreads.GetEntry(const AnIndex: Integer): TThreadEntry;
 | 
						|
begin
 | 
						|
  if (AnIndex < 0) or (AnIndex >= Count) then exit(nil);
 | 
						|
  Result := TThreadEntry(FList[AnIndex]);
 | 
						|
end;
 | 
						|
 | 
						|
function TThreads.GetEntryById(const AnID: Integer): TThreadEntry;
 | 
						|
var
 | 
						|
  i: Integer;
 | 
						|
begin
 | 
						|
  i := Count - 1;
 | 
						|
  while i >= 0 do begin
 | 
						|
    Result := Entries[i];
 | 
						|
    if Result.ThreadId = AnID then
 | 
						|
      exit;
 | 
						|
    dec(i);
 | 
						|
  end;
 | 
						|
  Result := nil;
 | 
						|
end;
 | 
						|
 | 
						|
procedure TThreads.SetCurrentThreadId(AValue: Integer);
 | 
						|
begin
 | 
						|
  if FCurrentThreadId = AValue then exit;
 | 
						|
  FCurrentThreadId := AValue;
 | 
						|
end;
 | 
						|
 | 
						|
constructor TThreads.Create;
 | 
						|
begin
 | 
						|
  FList := TList.Create;
 | 
						|
end;
 | 
						|
 | 
						|
destructor TThreads.Destroy;
 | 
						|
begin
 | 
						|
  Clear;
 | 
						|
  FreeAndNil(FList);
 | 
						|
  inherited Destroy;
 | 
						|
end;
 | 
						|
 | 
						|
procedure TThreads.Assign(AnOther: TThreads);
 | 
						|
var
 | 
						|
  i: Integer;
 | 
						|
begin
 | 
						|
  Clear;
 | 
						|
  FCurrentThreadId := AnOther.FCurrentThreadId;
 | 
						|
  for i := 0 to AnOther.FList.Count-1 do
 | 
						|
    FList.Add(TThreadEntry(AnOther.FList[i]).CreateCopy);
 | 
						|
end;
 | 
						|
 | 
						|
function TThreads.Count: Integer;
 | 
						|
begin
 | 
						|
  Result := FList.Count;
 | 
						|
end;
 | 
						|
 | 
						|
procedure TThreads.Clear;
 | 
						|
begin
 | 
						|
  while FList.Count > 0 do begin
 | 
						|
    TThreadEntry(Flist[0]).Free;
 | 
						|
    FList.Delete(0);
 | 
						|
  end;
 | 
						|
end;
 | 
						|
 | 
						|
procedure TThreads.Add(AThread: TThreadEntry);
 | 
						|
begin
 | 
						|
  FList.Add(AThread.CreateCopy);
 | 
						|
  if FList.Count = 1 then
 | 
						|
    FCurrentThreadId := AThread.ThreadId;
 | 
						|
end;
 | 
						|
 | 
						|
procedure TThreads.Remove(AThread: TThreadEntry);
 | 
						|
begin
 | 
						|
  FList.Remove(AThread);
 | 
						|
  if FCurrentThreadId = AThread.ThreadId then begin
 | 
						|
    if FList.Count > 0 then
 | 
						|
      FCurrentThreadId := Entries[0].ThreadId
 | 
						|
    else
 | 
						|
      FCurrentThreadId := 0;
 | 
						|
  end;
 | 
						|
  AThread.Free;
 | 
						|
end;
 | 
						|
 | 
						|
function TThreads.CreateEntry(const AnAdress: TDbgPtr; const AnArguments: TStrings;
 | 
						|
  const AFunctionName: String; const FileName, FullName: String; const ALine: Integer;
 | 
						|
  const AThreadId: Integer; const AThreadName: String; const AThreadState: String;
 | 
						|
  AState: TDebuggerDataState): TThreadEntry;
 | 
						|
begin
 | 
						|
  Result := TThreadEntry.Create(AnAdress, AnArguments, AFunctionName, FileName,
 | 
						|
    FullName, ALine, AThreadId, AThreadName, AThreadState, AState);
 | 
						|
end;
 | 
						|
 | 
						|
procedure TThreads.SetValidity(AValidity: TDebuggerDataState);
 | 
						|
begin
 | 
						|
  //
 | 
						|
end;
 | 
						|
 | 
						|
{ TThreadsMonitor }
 | 
						|
 | 
						|
function TThreadsMonitor.GetSupplier: TThreadsSupplier;
 | 
						|
begin
 | 
						|
  Result := TThreadsSupplier(inherited Supplier);
 | 
						|
end;
 | 
						|
 | 
						|
procedure TThreadsMonitor.SetSupplier(AValue: TThreadsSupplier);
 | 
						|
begin
 | 
						|
  inherited Supplier := AValue;
 | 
						|
end;
 | 
						|
 | 
						|
function TThreadsMonitor.CreateThreads: TThreads;
 | 
						|
begin
 | 
						|
  Result := TThreads.Create;
 | 
						|
end;
 | 
						|
 | 
						|
constructor TThreadsMonitor.Create;
 | 
						|
begin
 | 
						|
  FThreads := CreateThreads;
 | 
						|
  inherited Create;
 | 
						|
end;
 | 
						|
 | 
						|
destructor TThreadsMonitor.Destroy;
 | 
						|
begin
 | 
						|
  inherited Destroy;
 | 
						|
  FreeAndNil(FThreads);
 | 
						|
end;
 | 
						|
 | 
						|
{ TRegistersMonitor }
 | 
						|
 | 
						|
function TRegistersMonitor.GetSupplier: TRegisterSupplier;
 | 
						|
begin
 | 
						|
  Result := TRegisterSupplier(inherited Supplier);
 | 
						|
end;
 | 
						|
 | 
						|
procedure TRegistersMonitor.SetSupplier(AValue: TRegisterSupplier);
 | 
						|
begin
 | 
						|
  inherited Supplier := AValue;
 | 
						|
end;
 | 
						|
 | 
						|
function TRegistersMonitor.CreateRegistersList: TRegistersList;
 | 
						|
begin
 | 
						|
  Result := TRegistersList.Create;
 | 
						|
end;
 | 
						|
 | 
						|
constructor TRegistersMonitor.Create;
 | 
						|
begin
 | 
						|
  inherited Create;
 | 
						|
  FRegistersList := CreateRegistersList;
 | 
						|
  FRegistersList.AddReference;
 | 
						|
end;
 | 
						|
 | 
						|
destructor TRegistersMonitor.Destroy;
 | 
						|
begin
 | 
						|
  inherited Destroy;
 | 
						|
  ReleaseRefAndNil(FRegistersList);
 | 
						|
end;
 | 
						|
 | 
						|
{ TDebuggerDataHandler }
 | 
						|
 | 
						|
procedure TDebuggerDataHandler.DoStateEnterPause;
 | 
						|
begin
 | 
						|
  //
 | 
						|
end;
 | 
						|
 | 
						|
procedure TDebuggerDataHandler.DoStateLeavePause;
 | 
						|
begin
 | 
						|
  //
 | 
						|
end;
 | 
						|
 | 
						|
procedure TDebuggerDataHandler.DoStateLeavePauseClean;
 | 
						|
begin
 | 
						|
  //
 | 
						|
end;
 | 
						|
 | 
						|
procedure TDebuggerDataHandler.DoStateChangeEx(const AOldState, ANewState: TDBGState);
 | 
						|
begin
 | 
						|
  FNotifiedState := ANewState;
 | 
						|
  FOldState := AOldState;
 | 
						|
  DebugLnEnter(DBG_DATA_MONITORS, [ClassName, ': >>ENTER: ', ClassName, '.DoStateChange  New-State=', dbgs(FNotifiedState)]);
 | 
						|
 | 
						|
  if FNotifiedState in [dsPause, dsInternalPause]
 | 
						|
  then begin
 | 
						|
    // typical: Clear and reload data
 | 
						|
    if not(AOldState  in [dsPause, dsInternalPause] )
 | 
						|
    then DoStateEnterPause;
 | 
						|
  end
 | 
						|
  else
 | 
						|
  if (AOldState  in [dsPause, dsInternalPause, dsNone] )
 | 
						|
  then begin
 | 
						|
    // dsIdle happens after dsStop
 | 
						|
    if (FNotifiedState  in [dsRun, dsInit, dsIdle]) or (AOldState = dsNone)
 | 
						|
    then begin
 | 
						|
      // typical: finalize snapshot and clear data.
 | 
						|
      DoStateLeavePauseClean;
 | 
						|
    end
 | 
						|
    else begin
 | 
						|
      // typical: finalize snapshot
 | 
						|
      //          Do *not* clear data. Objects may be in use (e.g. dsError)
 | 
						|
      DoStateLeavePause;
 | 
						|
    end;
 | 
						|
  end
 | 
						|
  else
 | 
						|
  if (AOldState  in [dsStop]) and (FNotifiedState = dsIdle)
 | 
						|
  then begin
 | 
						|
    // stopped // typical: finalize snapshot and clear data.
 | 
						|
    DoStateLeavePauseClean;
 | 
						|
  end;
 | 
						|
  DebugLnExit(DBG_DATA_MONITORS, [ClassName, ': <<EXIT: ', ClassName, '.DoStateChange']);
 | 
						|
end;
 | 
						|
 | 
						|
procedure TDebuggerDataHandler.DoBeginUpdate;
 | 
						|
begin
 | 
						|
  //
 | 
						|
end;
 | 
						|
 | 
						|
procedure TDebuggerDataHandler.DoEndUpdate;
 | 
						|
begin
 | 
						|
  //
 | 
						|
end;
 | 
						|
 | 
						|
procedure TDebuggerDataHandler.BeginUpdate;
 | 
						|
begin
 | 
						|
  inc(FUpdateCount);
 | 
						|
  if FUpdateCount = 1 then
 | 
						|
    DoBeginUpdate;
 | 
						|
end;
 | 
						|
 | 
						|
procedure TDebuggerDataHandler.EndUpdate;
 | 
						|
begin
 | 
						|
  assert(FUpdateCount > 0, 'TDebuggerDataMonitor.EndUpdate: FUpdateCount > 0');
 | 
						|
  dec(FUpdateCount);
 | 
						|
  if FUpdateCount = 0 then
 | 
						|
    DoEndUpdate;
 | 
						|
end;
 | 
						|
 | 
						|
function TDebuggerDataHandler.IsUpdating: Boolean;
 | 
						|
begin
 | 
						|
  Result := FUpdateCount > 0;
 | 
						|
end;
 | 
						|
 | 
						|
{ TWatchValue }
 | 
						|
 | 
						|
procedure TWatchValue.SetValidity(AValue: TDebuggerDataState);
 | 
						|
var
 | 
						|
  OldValidity: TDebuggerDataState;
 | 
						|
begin
 | 
						|
  if FValidity = AValue then exit;
 | 
						|
  //DebugLn(DBG_DATA_MONITORS, ['DebugDataMonitor: TWatchValue.SetValidity: FThreadId=', FThreadId, '  FStackFrame=',FStackFrame, ' Expr=', Expression, ' AValidity=',dbgs(AValue)]);
 | 
						|
  DebugLn(DBG_DATA_MONITORS, ['DebugDataMonitor: TWatchValue.SetValidity:  Expr=', Expression, ' AValidity=',dbgs(AValue)]);
 | 
						|
  OldValidity := FValidity;
 | 
						|
  FValidity := AValue;
 | 
						|
  DoDataValidityChanged(OldValidity);
 | 
						|
end;
 | 
						|
 | 
						|
procedure TWatchValue.SetValue(AValue: String);
 | 
						|
begin
 | 
						|
  if FValue = AValue then exit;
 | 
						|
  //asser not immutable
 | 
						|
  FValue := AValue;
 | 
						|
end;
 | 
						|
 | 
						|
procedure TWatchValue.SetTypeInfo(AValue: TDBGType);
 | 
						|
begin
 | 
						|
  //assert(Self is TCurrentWatchValue, 'TWatchValue.SetTypeInfo');
 | 
						|
  FreeAndNil(FTypeInfo);
 | 
						|
  FTypeInfo := AValue;
 | 
						|
end;
 | 
						|
 | 
						|
procedure TWatchValue.DoDataValidityChanged(AnOldValidity: TDebuggerDataState);
 | 
						|
begin
 | 
						|
 | 
						|
end;
 | 
						|
 | 
						|
function TWatchValue.GetExpression: String;
 | 
						|
begin
 | 
						|
  Result := FWatch.Expression;
 | 
						|
end;
 | 
						|
 | 
						|
function TWatchValue.GetTypeInfo: TDBGType;
 | 
						|
begin
 | 
						|
  Result := FTypeInfo;
 | 
						|
end;
 | 
						|
 | 
						|
function TWatchValue.GetValue: String;
 | 
						|
begin
 | 
						|
  Result := FValue;
 | 
						|
end;
 | 
						|
 | 
						|
constructor TWatchValue.Create(AOwnerWatch: TWatch);
 | 
						|
begin
 | 
						|
  FWatch := AOwnerWatch;
 | 
						|
  inherited Create;
 | 
						|
end;
 | 
						|
 | 
						|
function TWatchValue.GetWatch: TWatch;
 | 
						|
begin
 | 
						|
  Result := FWatch;
 | 
						|
end;
 | 
						|
 | 
						|
destructor TWatchValue.Destroy;
 | 
						|
begin
 | 
						|
  inherited Destroy;
 | 
						|
  FreeAndNil(FTypeInfo);
 | 
						|
end;
 | 
						|
 | 
						|
procedure TWatchValue.Assign(AnOther: TWatchValue);
 | 
						|
begin
 | 
						|
  FreeAndNil(FTypeInfo);
 | 
						|
  //FTypeInfo    := TWatchValue(AnOther).FTypeInfo.cre;
 | 
						|
  FValue         := AnOther.FValue;
 | 
						|
  FValidity      := AnOther.FValidity;
 | 
						|
end;
 | 
						|
 | 
						|
{ TWatch }
 | 
						|
 | 
						|
procedure TWatch.SetDisplayFormat(AValue: TWatchDisplayFormat);
 | 
						|
begin
 | 
						|
  if AValue = FDisplayFormat then exit;
 | 
						|
  FDisplayFormat := AValue;
 | 
						|
  DoDisplayFormatChanged;
 | 
						|
end;
 | 
						|
 | 
						|
procedure TWatch.SetEnabled(AValue: Boolean);
 | 
						|
begin
 | 
						|
  if FEnabled <> AValue
 | 
						|
  then begin
 | 
						|
    FEnabled := AValue;
 | 
						|
    DoEnableChange;
 | 
						|
  end;
 | 
						|
end;
 | 
						|
 | 
						|
procedure TWatch.SetEvaluateFlags(AValue: TDBGEvaluateFlags);
 | 
						|
begin
 | 
						|
  if FEvaluateFlags = AValue then Exit;
 | 
						|
  FEvaluateFlags := AValue;
 | 
						|
  Changed;
 | 
						|
  DoModified;
 | 
						|
end;
 | 
						|
 | 
						|
procedure TWatch.SetExpression(AValue: String);
 | 
						|
begin
 | 
						|
  if AValue <> FExpression
 | 
						|
  then begin
 | 
						|
    FExpression := AValue;
 | 
						|
    FValueList.Clear;
 | 
						|
    DoExpressionChange;
 | 
						|
  end;
 | 
						|
end;
 | 
						|
 | 
						|
procedure TWatch.SetRepeatCount(AValue: Integer);
 | 
						|
begin
 | 
						|
  if FRepeatCount = AValue then Exit;
 | 
						|
  FRepeatCount := AValue;
 | 
						|
  Changed;
 | 
						|
  DoModified;
 | 
						|
end;
 | 
						|
 | 
						|
function TWatch.GetValue(const AThreadId: Integer;
 | 
						|
  const AStackFrame: Integer): TWatchValue;
 | 
						|
begin
 | 
						|
  Result := FValueList[AThreadId, AStackFrame];
 | 
						|
end;
 | 
						|
 | 
						|
procedure TWatch.DoModified;
 | 
						|
begin
 | 
						|
  //
 | 
						|
end;
 | 
						|
 | 
						|
procedure TWatch.DoEnableChange;
 | 
						|
begin
 | 
						|
  //
 | 
						|
end;
 | 
						|
 | 
						|
procedure TWatch.DoExpressionChange;
 | 
						|
begin
 | 
						|
  //
 | 
						|
end;
 | 
						|
 | 
						|
procedure TWatch.DoDisplayFormatChanged;
 | 
						|
begin
 | 
						|
  //
 | 
						|
end;
 | 
						|
 | 
						|
procedure TWatch.AssignTo(Dest: TPersistent);
 | 
						|
begin
 | 
						|
  if Dest is TWatch
 | 
						|
  then begin
 | 
						|
    TWatch(Dest).FExpression    := FExpression;
 | 
						|
    TWatch(Dest).FEnabled       := FEnabled;
 | 
						|
    TWatch(Dest).FDisplayFormat := FDisplayFormat;
 | 
						|
    TWatch(Dest).FRepeatCount   := FRepeatCount;
 | 
						|
    TWatch(Dest).FEvaluateFlags := FEvaluateFlags;
 | 
						|
    TWatch(Dest).FValueList.Assign(FValueList);
 | 
						|
  end
 | 
						|
  else inherited;
 | 
						|
end;
 | 
						|
 | 
						|
function TWatch.CreateValueList: TWatchValueList;
 | 
						|
begin
 | 
						|
  Result := TWatchValueList.Create(Self);
 | 
						|
end;
 | 
						|
 | 
						|
constructor TWatch.Create(ACollection: TCollection);
 | 
						|
begin
 | 
						|
  FEnabled := False;
 | 
						|
  FValueList := CreateValueList;
 | 
						|
  inherited Create(ACollection);
 | 
						|
end;
 | 
						|
 | 
						|
destructor TWatch.Destroy;
 | 
						|
begin
 | 
						|
  FValueList.Clear;
 | 
						|
  inherited Destroy;
 | 
						|
  FreeAndNil(FValueList);
 | 
						|
end;
 | 
						|
 | 
						|
procedure TWatch.ClearValues;
 | 
						|
begin
 | 
						|
  FValueList.Clear;
 | 
						|
end;
 | 
						|
 | 
						|
{ TWatchValueList }
 | 
						|
 | 
						|
function TWatchValueList.GetEntry(const AThreadId: Integer;
 | 
						|
  const AStackFrame: Integer): TWatchValue;
 | 
						|
var
 | 
						|
  i: Integer;
 | 
						|
begin
 | 
						|
  i := FList.Count - 1;
 | 
						|
  while i >= 0 do begin
 | 
						|
    Result := TWatchValue(FList[i]);
 | 
						|
    if (Result.ThreadId = AThreadId) and (Result.StackFrame = AStackFrame) and
 | 
						|
       (Result.DisplayFormat = FWatch.DisplayFormat) and
 | 
						|
       (Result.RepeatCount = FWatch.RepeatCount) and
 | 
						|
       (Result.EvaluateFlags = FWatch.EvaluateFlags)
 | 
						|
    then
 | 
						|
      exit;
 | 
						|
    dec(i);
 | 
						|
  end;
 | 
						|
  Result := CreateEntry(AThreadId, AStackFrame);
 | 
						|
end;
 | 
						|
 | 
						|
function TWatchValueList.GetEntryByIdx(AnIndex: integer): TWatchValue;
 | 
						|
begin
 | 
						|
  Result := TWatchValue(FList[AnIndex]);
 | 
						|
end;
 | 
						|
 | 
						|
function TWatchValueList.CreateEntry(const AThreadId: Integer;
 | 
						|
  const AStackFrame: Integer): TWatchValue;
 | 
						|
begin
 | 
						|
  Result := nil;
 | 
						|
end;
 | 
						|
 | 
						|
function TWatchValueList.CopyEntry(AnEntry: TWatchValue): TWatchValue;
 | 
						|
begin
 | 
						|
  Result := TWatchValue.Create(FWatch);
 | 
						|
  Result.Assign(AnEntry);
 | 
						|
end;
 | 
						|
 | 
						|
procedure TWatchValueList.Assign(AnOther: TWatchValueList);
 | 
						|
var
 | 
						|
  i: Integer;
 | 
						|
begin
 | 
						|
  Clear;
 | 
						|
  for i := 0 to AnOther.FList.Count - 1 do begin
 | 
						|
    FList.Add(CopyEntry(TWatchValue(AnOther.FList[i])));
 | 
						|
  end;
 | 
						|
end;
 | 
						|
 | 
						|
constructor TWatchValueList.Create(AOwnerWatch: TWatch);
 | 
						|
begin
 | 
						|
  assert(AOwnerWatch <> nil, 'TWatchValueList.Create without owner');
 | 
						|
  FList := TList.Create;
 | 
						|
  FWatch := AOwnerWatch;
 | 
						|
  inherited Create;
 | 
						|
end;
 | 
						|
 | 
						|
destructor TWatchValueList.Destroy;
 | 
						|
begin
 | 
						|
  Clear;
 | 
						|
  inherited Destroy;
 | 
						|
  FreeAndNil(FList);
 | 
						|
end;
 | 
						|
 | 
						|
procedure TWatchValueList.Add(AnEntry: TWatchValue);
 | 
						|
begin
 | 
						|
  Flist.Add(AnEntry);
 | 
						|
end;
 | 
						|
 | 
						|
procedure TWatchValueList.Clear;
 | 
						|
begin
 | 
						|
  while FList.Count > 0 do begin
 | 
						|
    TObject(FList[0]).Free;
 | 
						|
    FList.Delete(0);
 | 
						|
  end;
 | 
						|
end;
 | 
						|
 | 
						|
function TWatchValueList.Count: Integer;
 | 
						|
begin
 | 
						|
  Result := FList.Count;
 | 
						|
end;
 | 
						|
 | 
						|
{ TRegisterSupplier }
 | 
						|
 | 
						|
function TRegisterSupplier.GetCurrentRegistersList: TRegistersList;
 | 
						|
begin
 | 
						|
  Result := nil;
 | 
						|
  if Monitor <> nil then
 | 
						|
    Result := Monitor.RegistersList;
 | 
						|
end;
 | 
						|
 | 
						|
function TRegisterSupplier.GetMonitor: TRegistersMonitor;
 | 
						|
begin
 | 
						|
  Result := TRegistersMonitor(inherited Monitor);
 | 
						|
end;
 | 
						|
 | 
						|
procedure TRegisterSupplier.SetMonitor(AValue: TRegistersMonitor);
 | 
						|
begin
 | 
						|
  inherited Monitor := AValue;
 | 
						|
end;
 | 
						|
 | 
						|
procedure TRegisterSupplier.RequestData(ARegisters: TRegisters);
 | 
						|
begin
 | 
						|
  ARegisters.SetDataValidity(ddsInvalid);
 | 
						|
end;
 | 
						|
 | 
						|
{ TLocalsValue }
 | 
						|
 | 
						|
procedure TLocalsValue.DoAssign(AnOther: TDbgEntityValue);
 | 
						|
begin
 | 
						|
  inherited DoAssign(AnOther);
 | 
						|
  FName := TLocalsValue(AnOther).FName;
 | 
						|
  FValue := TLocalsValue(AnOther).FValue;
 | 
						|
end;
 | 
						|
 | 
						|
{ TLocalsListBase }
 | 
						|
 | 
						|
function TLocalsList.GetEntry(AThreadId, AStackFrame: Integer): TLocals;
 | 
						|
begin
 | 
						|
  Result := TLocals(inherited Entries[AThreadId, AStackFrame]);
 | 
						|
end;
 | 
						|
 | 
						|
function TLocalsList.GetEntryByIdx(AnIndex: Integer): TLocals;
 | 
						|
begin
 | 
						|
  Result := TLocals(inherited EntriesByIdx[AnIndex]);
 | 
						|
end;
 | 
						|
 | 
						|
{ TLocalsBase }
 | 
						|
 | 
						|
function TLocals.GetEntry(AnIndex: Integer): TLocalsValue;
 | 
						|
begin
 | 
						|
  Result := TLocalsValue(inherited Entries[AnIndex]);
 | 
						|
end;
 | 
						|
 | 
						|
function TLocals.GetName(const AnIndex: Integer): String;
 | 
						|
begin
 | 
						|
  Result := Entries[AnIndex].Name;
 | 
						|
end;
 | 
						|
 | 
						|
function TLocals.GetValue(const AnIndex: Integer): String;
 | 
						|
begin
 | 
						|
  Result := Entries[AnIndex].Value;
 | 
						|
end;
 | 
						|
 | 
						|
function TLocals.CreateEntry: TDbgEntityValue;
 | 
						|
begin
 | 
						|
  Result := TLocalsValue.Create;
 | 
						|
end;
 | 
						|
 | 
						|
procedure TLocals.Add(const AName, AValue: String);
 | 
						|
var
 | 
						|
  v: TLocalsValue;
 | 
						|
begin
 | 
						|
  assert(not Immutable, 'TLocalsBase.Add Immutable');
 | 
						|
  v := TLocalsValue(CreateEntry);
 | 
						|
  v.FName := AName;
 | 
						|
  v.FValue := AValue;
 | 
						|
  inherited Add(v);
 | 
						|
end;
 | 
						|
 | 
						|
procedure TLocals.SetDataValidity(AValidity: TDebuggerDataState);
 | 
						|
begin
 | 
						|
  //
 | 
						|
end;
 | 
						|
 | 
						|
function TLocals.Count: Integer;
 | 
						|
begin
 | 
						|
  Result := inherited Count;
 | 
						|
end;
 | 
						|
 | 
						|
{ TRegisterDisplayValue }
 | 
						|
 | 
						|
function TRegisterDisplayValue.GetValue(ADispFormat: TRegisterDisplayFormat): String;
 | 
						|
const Digits = '01234567';
 | 
						|
  function IntToBase(Val, Base: Integer): String;
 | 
						|
  var
 | 
						|
    M: Integer;
 | 
						|
  begin
 | 
						|
    Result := '';
 | 
						|
    case Base of
 | 
						|
      2: M := 1;
 | 
						|
      8: M := 7;
 | 
						|
    end;
 | 
						|
    while Val > 0 do begin
 | 
						|
      Result := Digits[1 + (Val and m)] + Result;
 | 
						|
      Val := Val div Base;
 | 
						|
    end;
 | 
						|
  end;
 | 
						|
begin
 | 
						|
  Result := '';
 | 
						|
  if not(ADispFormat in FSupportedDispFormats) then exit;
 | 
						|
  if (ADispFormat in [rdDefault, rdRaw]) or not (rdvHasNum in FFlags) then begin
 | 
						|
    Result := FStringValue;
 | 
						|
    exit;
 | 
						|
  end;
 | 
						|
  case ADispFormat of
 | 
						|
    rdHex:    Result := IntToHex(FNumValue, FSize * 2);
 | 
						|
    rdBinary: Result := IntToBase(FNumValue, 2);
 | 
						|
    rdOctal:  Result := IntToBase(FNumValue, 8);
 | 
						|
    rdDecimal: Result := IntToStr(FNumValue);
 | 
						|
  end;
 | 
						|
end;
 | 
						|
 | 
						|
procedure TRegisterDisplayValue.Assign(AnOther: TRegisterDisplayValue);
 | 
						|
begin
 | 
						|
  FStringValue          := AnOther.FStringValue;
 | 
						|
  FNumValue             := AnOther.FNumValue;
 | 
						|
  FFlags                := AnOther.FFlags;
 | 
						|
  FSize                 := AnOther.FSize;
 | 
						|
  FSupportedDispFormats := AnOther.FSupportedDispFormats;
 | 
						|
end;
 | 
						|
 | 
						|
procedure TRegisterDisplayValue.SetAsNum(AValue: QWord; ASize: Integer);
 | 
						|
begin
 | 
						|
  if FNumValue = AValue then Exit;
 | 
						|
  FNumValue := AValue;
 | 
						|
  FSize := ASize;
 | 
						|
  Include(FFlags, rdvHasNum);
 | 
						|
end;
 | 
						|
 | 
						|
procedure TRegisterDisplayValue.SetAsText(AValue: String);
 | 
						|
begin
 | 
						|
  FStringValue := AValue;
 | 
						|
end;
 | 
						|
 | 
						|
procedure TRegisterDisplayValue.AddFormats(AFormats: TRegisterDisplayFormats);
 | 
						|
begin
 | 
						|
  FSupportedDispFormats := FSupportedDispFormats + AFormats;
 | 
						|
end;
 | 
						|
 | 
						|
{ TRegisterValue }
 | 
						|
 | 
						|
function TRegisterValue.GetValue: String;
 | 
						|
var
 | 
						|
  v: TRegisterDisplayValue;
 | 
						|
begin
 | 
						|
  v :=  GetValueObject();
 | 
						|
  if v <> nil then begin
 | 
						|
    Result := v.Value[FDisplayFormat];
 | 
						|
    exit;
 | 
						|
  end;
 | 
						|
 | 
						|
  Result := '';
 | 
						|
  DoValueNotEvaluated;
 | 
						|
end;
 | 
						|
 | 
						|
function TRegisterValue.GetHasValue: Boolean;
 | 
						|
begin
 | 
						|
  Result := GetValueObject <> nil;
 | 
						|
end;
 | 
						|
 | 
						|
function TRegisterValue.GetHasValueFormat(ADispFormat: TRegisterDisplayFormat): Boolean;
 | 
						|
begin
 | 
						|
  Result := GetValueObject(ADispFormat) <> nil;
 | 
						|
end;
 | 
						|
 | 
						|
function TRegisterValue.GetValueObj: TRegisterDisplayValue;
 | 
						|
begin
 | 
						|
  Result := GetValueObject(True);
 | 
						|
end;
 | 
						|
 | 
						|
function TRegisterValue.GetValueObjFormat(ADispFormat: TRegisterDisplayFormat): TRegisterDisplayValue;
 | 
						|
begin
 | 
						|
  Result := GetValueObject(ADispFormat, True);
 | 
						|
end;
 | 
						|
 | 
						|
procedure TRegisterValue.SetDisplayFormat(AValue: TRegisterDisplayFormat);
 | 
						|
var
 | 
						|
  Old: TRegisterDisplayFormat;
 | 
						|
begin
 | 
						|
  assert(not Immutable, 'TRegisterValue.SetDisplayFormat: not Immutable');
 | 
						|
  if FDisplayFormat = AValue then Exit;
 | 
						|
  Old := FDisplayFormat;
 | 
						|
  FDisplayFormat := AValue;
 | 
						|
  DoDisplayFormatChanged(Old);
 | 
						|
end;
 | 
						|
 | 
						|
procedure TRegisterValue.SetValue(AValue: String);
 | 
						|
var
 | 
						|
  v: TRegisterDisplayValue;
 | 
						|
begin
 | 
						|
  assert(not Immutable, 'TRegisterValue.SetValue: not Immutable');
 | 
						|
  v :=  GetValueObject(True);
 | 
						|
  v.FStringValue := AValue;
 | 
						|
end;
 | 
						|
 | 
						|
function TRegisterValue.GetValueObject(ACreateNew: Boolean): TRegisterDisplayValue;
 | 
						|
begin
 | 
						|
  Result := GetValueObject(FDisplayFormat, ACreateNew);
 | 
						|
end;
 | 
						|
 | 
						|
function TRegisterValue.GetValueObject(ADispFormat: TRegisterDisplayFormat;
 | 
						|
  ACreateNew: Boolean): TRegisterDisplayValue;
 | 
						|
var
 | 
						|
  i: Integer;
 | 
						|
begin
 | 
						|
  for i := 0 to length(FValues) - 1 do
 | 
						|
    if ADispFormat in FValues[i].SupportedDispFormats then begin
 | 
						|
      Result := FValues[i];
 | 
						|
      exit;
 | 
						|
    end;
 | 
						|
 | 
						|
  if not ACreateNew then begin
 | 
						|
    Result := nil;
 | 
						|
    exit;
 | 
						|
  end;
 | 
						|
 | 
						|
  assert(not Immutable, 'TRegisterValue.GetValueObject: not Immutable');
 | 
						|
  Result := TRegisterDisplayValue.Create;
 | 
						|
  Result.FSupportedDispFormats := [ADispFormat];
 | 
						|
  i := length(FValues);
 | 
						|
  SetLength(FValues, i + 1);
 | 
						|
  FValues[i] := Result;
 | 
						|
end;
 | 
						|
 | 
						|
procedure TRegisterValue.SetDataValidity(AValidity: TDebuggerDataState);
 | 
						|
var
 | 
						|
  Old: TDebuggerDataState;
 | 
						|
begin
 | 
						|
  assert(not Immutable, 'TRegisterValue.SetDataValidity: not Immutable');
 | 
						|
  if FDataValidity = AValidity then exit;
 | 
						|
  Old := FDataValidity;
 | 
						|
  FDataValidity := AValidity;
 | 
						|
  DoDataValidityChanged(Old);
 | 
						|
end;
 | 
						|
 | 
						|
procedure TRegisterValue.ClearDispValues;
 | 
						|
var
 | 
						|
  i: Integer;
 | 
						|
begin
 | 
						|
  for i := 0 to Length(FValues) - 1 do
 | 
						|
    FValues[i].Free;
 | 
						|
  FValues := nil;
 | 
						|
end;
 | 
						|
 | 
						|
procedure TRegisterValue.DoAssign(AnOther: TDbgEntityValue);
 | 
						|
var
 | 
						|
  i: Integer;
 | 
						|
begin
 | 
						|
  inherited DoAssign(AnOther);
 | 
						|
  FDataValidity  :=  TRegisterValue(AnOther).FDataValidity;
 | 
						|
  FDisplayFormat :=  TRegisterValue(AnOther).FDisplayFormat;
 | 
						|
  FName          :=  TRegisterValue(AnOther).FName;
 | 
						|
  SetLength(FValues, length(TRegisterValue(AnOther).FValues));
 | 
						|
  for i := 0 to length(TRegisterValue(AnOther).FValues) - 1 do begin
 | 
						|
    FValues[i] := TRegisterDisplayValue.Create;
 | 
						|
    FValues[i].Assign(TRegisterValue(AnOther).FValues[i]);
 | 
						|
  end;
 | 
						|
end;
 | 
						|
 | 
						|
procedure TRegisterValue.DoDataValidityChanged(AnOldValidity: TDebuggerDataState);
 | 
						|
begin
 | 
						|
  //
 | 
						|
end;
 | 
						|
 | 
						|
procedure TRegisterValue.DoDisplayFormatChanged(AnOldFormat: TRegisterDisplayFormat);
 | 
						|
begin
 | 
						|
  //
 | 
						|
end;
 | 
						|
 | 
						|
procedure TRegisterValue.DoValueNotEvaluated;
 | 
						|
begin
 | 
						|
  //
 | 
						|
end;
 | 
						|
 | 
						|
destructor TRegisterValue.Destroy;
 | 
						|
begin
 | 
						|
  inherited Destroy;
 | 
						|
  ClearDispValues;
 | 
						|
end;
 | 
						|
 | 
						|
{ TRegisters }
 | 
						|
 | 
						|
function TRegisters.GetEntry(AnIndex: Integer): TRegisterValue;
 | 
						|
begin
 | 
						|
  Result := TRegisterValue(inherited Entries[AnIndex]);
 | 
						|
end;
 | 
						|
 | 
						|
function TRegisters.GetEntryByName(const AName: String): TRegisterValue;
 | 
						|
var
 | 
						|
  i: Integer;
 | 
						|
begin
 | 
						|
  for i := 0 to Count - 1 do begin
 | 
						|
    Result := Entries[i];
 | 
						|
    if Result.Name = AName then
 | 
						|
      exit;
 | 
						|
  end;
 | 
						|
 | 
						|
  assert(not Immutable, 'TRegisters.GetEntryByName: not Immutable');
 | 
						|
  Result := TRegisterValue(CreateEntry);
 | 
						|
  Result.FName := AName;
 | 
						|
  Add(Result);
 | 
						|
end;
 | 
						|
 | 
						|
procedure TRegisters.SetDataValidity(AValue: TDebuggerDataState);
 | 
						|
var
 | 
						|
  Old: TDebuggerDataState;
 | 
						|
begin
 | 
						|
  assert(not Immutable, 'TRegisters.SetDataValidity: not Immutable');
 | 
						|
  if FDataValidity = AValue then Exit;
 | 
						|
  Old := FDataValidity;
 | 
						|
  FDataValidity := AValue;
 | 
						|
  DoDataValidityChanged(Old);
 | 
						|
end;
 | 
						|
 | 
						|
function TRegisters.CreateEntry: TDbgEntityValue;
 | 
						|
begin
 | 
						|
  assert(not Immutable, 'TRegisters.CreateEntry: not Immutable');
 | 
						|
  Result := TRegisterValue.Create;
 | 
						|
end;
 | 
						|
 | 
						|
procedure TRegisters.DoDataValidityChanged(AnOldValidity: TDebuggerDataState);
 | 
						|
begin
 | 
						|
  //
 | 
						|
end;
 | 
						|
 | 
						|
function TRegisters.Count: Integer;
 | 
						|
begin
 | 
						|
  if FDataValidity = ddsValid then
 | 
						|
    Result := inherited Count
 | 
						|
  else
 | 
						|
    Result := 0;
 | 
						|
end;
 | 
						|
 | 
						|
{ TRegistersList }
 | 
						|
 | 
						|
function TRegistersList.GetEntry(AThreadId, AStackFrame: Integer): TRegisters;
 | 
						|
begin
 | 
						|
  Result := TRegisters(inherited Entries[AThreadId, AStackFrame]);
 | 
						|
end;
 | 
						|
 | 
						|
function TRegistersList.GetEntryByIdx(AnIndex: Integer): TRegisters;
 | 
						|
begin
 | 
						|
  Result := TRegisters(inherited EntriesByIdx[AnIndex]);
 | 
						|
end;
 | 
						|
 | 
						|
{ TWatchesBase }
 | 
						|
 | 
						|
function TWatches.GetItemBase(const AnIndex: Integer): TWatch;
 | 
						|
begin
 | 
						|
  Result := TWatch(inherited Items[AnIndex]);
 | 
						|
end;
 | 
						|
 | 
						|
procedure TWatches.SetItemBase(const AnIndex: Integer; const AValue: TWatch);
 | 
						|
begin
 | 
						|
  inherited Items[AnIndex] := AValue;
 | 
						|
end;
 | 
						|
 | 
						|
function TWatches.WatchClass: TWatchClass;
 | 
						|
begin
 | 
						|
  Result := TWatch;
 | 
						|
end;
 | 
						|
 | 
						|
constructor TWatches.Create;
 | 
						|
begin
 | 
						|
  inherited Create(WatchClass);
 | 
						|
end;
 | 
						|
 | 
						|
procedure TWatches.ClearValues;
 | 
						|
var
 | 
						|
  n: Integer;
 | 
						|
begin
 | 
						|
  for n := 0 to Count - 1 do
 | 
						|
    Items[n].ClearValues;
 | 
						|
end;
 | 
						|
 | 
						|
function TWatches.Find(const AExpression: String): TWatch;
 | 
						|
var
 | 
						|
  n: Integer;
 | 
						|
  S: String;
 | 
						|
begin
 | 
						|
  S := UpperCase(AExpression);
 | 
						|
  for n := 0 to Count - 1 do
 | 
						|
  begin
 | 
						|
    Result := TWatch(GetItem(n));
 | 
						|
    if UpperCase(Result.Expression) = S
 | 
						|
    then Exit;
 | 
						|
  end;
 | 
						|
  Result := nil;
 | 
						|
end;
 | 
						|
 | 
						|
{ TCallStackBase }
 | 
						|
 | 
						|
function TCallStackBase.GetNewCurrentIndex: Integer;
 | 
						|
begin
 | 
						|
  Result := 0;
 | 
						|
end;
 | 
						|
 | 
						|
function TCallStackBase.GetCount: Integer;
 | 
						|
begin
 | 
						|
  Result := 0;
 | 
						|
end;
 | 
						|
 | 
						|
function TCallStackBase.GetCurrent: Integer;
 | 
						|
begin
 | 
						|
  Result := FCurrent;
 | 
						|
end;
 | 
						|
 | 
						|
procedure TCallStackBase.SetCurrent(AValue: Integer);
 | 
						|
begin
 | 
						|
  FCurrent := AValue;
 | 
						|
end;
 | 
						|
 | 
						|
function TCallStackBase.GetHighestUnknown: Integer;
 | 
						|
begin
 | 
						|
  Result := -1;
 | 
						|
end;
 | 
						|
 | 
						|
function TCallStackBase.GetLowestUnknown: Integer;
 | 
						|
begin
 | 
						|
  Result := 0;
 | 
						|
end;
 | 
						|
 | 
						|
constructor TCallStackBase.Create;
 | 
						|
begin
 | 
						|
  FThreadId := -1;
 | 
						|
  FCurrent := -1;
 | 
						|
  inherited;
 | 
						|
end;
 | 
						|
 | 
						|
function TCallStackBase.CreateCopy: TCallStackBase;
 | 
						|
begin
 | 
						|
  Result := TCallStackBase.Create;
 | 
						|
  Result.Assign(Self);
 | 
						|
end;
 | 
						|
 | 
						|
procedure TCallStackBase.Assign(AnOther: TCallStackBase);
 | 
						|
begin
 | 
						|
  ThreadId := AnOther.ThreadId;
 | 
						|
  FCurrent := AnOther.FCurrent;
 | 
						|
end;
 | 
						|
 | 
						|
procedure TCallStackBase.SetCountValidity(AValidity: TDebuggerDataState);
 | 
						|
begin
 | 
						|
  //
 | 
						|
end;
 | 
						|
 | 
						|
procedure TCallStackBase.SetHasAtLeastCountInfo(AValidity: TDebuggerDataState;
 | 
						|
  AMinCount: Integer);
 | 
						|
begin
 | 
						|
  //
 | 
						|
end;
 | 
						|
 | 
						|
procedure TCallStackBase.SetCurrentValidity(AValidity: TDebuggerDataState);
 | 
						|
begin
 | 
						|
  //
 | 
						|
end;
 | 
						|
 | 
						|
{ TRunningProcessInfo }
 | 
						|
 | 
						|
constructor TRunningProcessInfo.Create(APID: Cardinal; const AImageName: string);
 | 
						|
begin
 | 
						|
  self.PID := APID;
 | 
						|
  self.ImageName := AImageName;
 | 
						|
end;
 | 
						|
 | 
						|
{ TDebuggerDataMonitor }
 | 
						|
 | 
						|
procedure TDebuggerDataMonitor.SetSupplier(const AValue: TDebuggerDataSupplier);
 | 
						|
begin
 | 
						|
  if FSupplier = AValue then exit;
 | 
						|
  Assert((FSupplier=nil) or (AValue=nil), 'TDebuggerDataMonitor.Supplier already set');
 | 
						|
  if FSupplier <> nil then FSupplier.Monitor := nil;
 | 
						|
  FSupplier := AValue;
 | 
						|
  if FSupplier <> nil then FSupplier.Monitor:= self;
 | 
						|
 | 
						|
  DoNewSupplier;
 | 
						|
end;
 | 
						|
 | 
						|
procedure TDebuggerDataMonitor.DoModified;
 | 
						|
begin
 | 
						|
  //
 | 
						|
end;
 | 
						|
 | 
						|
procedure TDebuggerDataMonitor.DoNewSupplier;
 | 
						|
begin
 | 
						|
  //
 | 
						|
end;
 | 
						|
 | 
						|
destructor TDebuggerDataMonitor.Destroy;
 | 
						|
begin
 | 
						|
  Supplier := nil;
 | 
						|
  inherited Destroy;
 | 
						|
end;
 | 
						|
 | 
						|
{ TDebuggerDataSupplier }
 | 
						|
 | 
						|
procedure TDebuggerDataSupplier.SetMonitor(const AValue: TDebuggerDataMonitor);
 | 
						|
begin
 | 
						|
  if FMonitor = AValue then exit;
 | 
						|
  Assert((FMonitor=nil) or (AValue=nil), 'TDebuggerDataSupplier.Monitor already set');
 | 
						|
  FMonitor := AValue;
 | 
						|
  DoNewMonitor;
 | 
						|
end;
 | 
						|
 | 
						|
procedure TDebuggerDataSupplier.DoNewMonitor;
 | 
						|
begin
 | 
						|
  //
 | 
						|
end;
 | 
						|
 | 
						|
procedure TDebuggerDataSupplier.DoStateLeavePauseClean;
 | 
						|
begin
 | 
						|
  DoStateLeavePause;
 | 
						|
end;
 | 
						|
 | 
						|
procedure TDebuggerDataSupplier.DoStateChange(const AOldState: TDBGState);
 | 
						|
begin
 | 
						|
  if (Debugger = nil) then Exit;
 | 
						|
  DoStateChangeEx(AOldState, Debugger.State);
 | 
						|
  if Monitor <> nil then
 | 
						|
    Monitor.DoStateChangeEx(AOldState, FDebugger.State);
 | 
						|
end;
 | 
						|
 | 
						|
constructor TDebuggerDataSupplier.Create(const ADebugger: TDebuggerIntf);
 | 
						|
begin
 | 
						|
  FDebugger := ADebugger;
 | 
						|
  inherited Create;
 | 
						|
end;
 | 
						|
 | 
						|
destructor TDebuggerDataSupplier.Destroy;
 | 
						|
begin
 | 
						|
  if FMonitor <> nil then FMonitor.Supplier := nil;
 | 
						|
  inherited Destroy;
 | 
						|
end;
 | 
						|
 | 
						|
procedure TDebuggerDataSupplier.DoBeginUpdate;
 | 
						|
begin
 | 
						|
  FMonitor.BeginUpdate;
 | 
						|
end;
 | 
						|
 | 
						|
procedure TDebuggerDataSupplier.DoEndUpdate;
 | 
						|
begin
 | 
						|
  FMonitor.EndUpdate;
 | 
						|
end;
 | 
						|
 | 
						|
{ ===========================================================================
 | 
						|
  TBaseBreakPoint
 | 
						|
  =========================================================================== }
 | 
						|
 | 
						|
function TBaseBreakPoint.GetAddress: TDBGPtr;
 | 
						|
begin
 | 
						|
  Result := FAddress;
 | 
						|
end;
 | 
						|
 | 
						|
function TBaseBreakPoint.GetKind: TDBGBreakPointKind;
 | 
						|
begin
 | 
						|
  Result := FKind;
 | 
						|
end;
 | 
						|
 | 
						|
procedure TBaseBreakPoint.SetKind(const AValue: TDBGBreakPointKind);
 | 
						|
begin
 | 
						|
  if FKind <> AValue
 | 
						|
  then begin
 | 
						|
    FKind := AValue;
 | 
						|
    DoKindChange;
 | 
						|
  end;
 | 
						|
end;
 | 
						|
 | 
						|
procedure TBaseBreakPoint.SetAddress(const AValue: TDBGPtr);
 | 
						|
begin
 | 
						|
  if FAddress <> AValue then
 | 
						|
  begin
 | 
						|
    FAddress := AValue;
 | 
						|
    Changed;
 | 
						|
  end;
 | 
						|
end;
 | 
						|
 | 
						|
function TBaseBreakPoint.GetWatchData: String;
 | 
						|
begin
 | 
						|
  Result := FWatchData;
 | 
						|
end;
 | 
						|
 | 
						|
function TBaseBreakPoint.GetWatchScope: TDBGWatchPointScope;
 | 
						|
begin
 | 
						|
  Result := FWatchScope;
 | 
						|
end;
 | 
						|
 | 
						|
function TBaseBreakPoint.GetWatchKind: TDBGWatchPointKind;
 | 
						|
begin
 | 
						|
  Result := FWatchKind;
 | 
						|
end;
 | 
						|
 | 
						|
procedure TBaseBreakPoint.AssignLocationTo(Dest: TPersistent);
 | 
						|
var
 | 
						|
  DestBreakPoint: TBaseBreakPoint absolute Dest;
 | 
						|
begin
 | 
						|
  DestBreakPoint.SetLocation(FSource, FLine);
 | 
						|
end;
 | 
						|
 | 
						|
procedure TBaseBreakPoint.AssignTo(Dest: TPersistent);
 | 
						|
var
 | 
						|
  DestBreakPoint: TBaseBreakPoint absolute Dest;
 | 
						|
begin
 | 
						|
  // updatelock is set in source.assignto
 | 
						|
  if Dest is TBaseBreakPoint
 | 
						|
  then begin
 | 
						|
    DestBreakPoint.SetKind(FKind);
 | 
						|
    DestBreakPoint.SetWatch(FWatchData, FWatchScope, FWatchKind);
 | 
						|
    DestBreakPoint.SetAddress(FAddress);
 | 
						|
    AssignLocationTo(DestBreakPoint);
 | 
						|
    DestBreakPoint.SetBreakHitCount(FBreakHitCount);
 | 
						|
    DestBreakPoint.SetExpression(FExpression);
 | 
						|
    DestBreakPoint.SetEnabled(FEnabled);
 | 
						|
    DestBreakPoint.InitialEnabled := FInitialEnabled;
 | 
						|
  end
 | 
						|
  else inherited;
 | 
						|
end;
 | 
						|
 | 
						|
constructor TBaseBreakPoint.Create(ACollection: TCollection);
 | 
						|
begin
 | 
						|
  FAddress := 0;
 | 
						|
  FSource := '';
 | 
						|
  FLine := -1;
 | 
						|
  FValid := vsUnknown;
 | 
						|
  FEnabled := False;
 | 
						|
  FHitCount := 0;
 | 
						|
  FBreakHitCount := 0;
 | 
						|
  FExpression := '';
 | 
						|
  FInitialEnabled := False;
 | 
						|
  FKind := bpkSource;
 | 
						|
  inherited Create(ACollection);
 | 
						|
  AddReference;
 | 
						|
end;
 | 
						|
 | 
						|
procedure TBaseBreakPoint.DoBreakHitCountChange;
 | 
						|
begin
 | 
						|
  Changed;
 | 
						|
end;
 | 
						|
 | 
						|
procedure TBaseBreakPoint.DoEnableChange;
 | 
						|
begin
 | 
						|
  Changed;
 | 
						|
end;
 | 
						|
 | 
						|
procedure TBaseBreakPoint.DoExpressionChange;
 | 
						|
begin
 | 
						|
  Changed;
 | 
						|
end;
 | 
						|
 | 
						|
procedure TBaseBreakPoint.DoHit(const ACount: Integer; var AContinue: Boolean );
 | 
						|
begin
 | 
						|
  SetHitCount(ACount);
 | 
						|
end;
 | 
						|
 | 
						|
function TBaseBreakPoint.GetBreakHitCount: Integer;
 | 
						|
begin
 | 
						|
  Result := FBreakHitCount;
 | 
						|
end;
 | 
						|
 | 
						|
function TBaseBreakPoint.GetEnabled: Boolean;
 | 
						|
begin
 | 
						|
  Result := FEnabled;
 | 
						|
end;
 | 
						|
 | 
						|
function TBaseBreakPoint.GetExpression: String;
 | 
						|
begin
 | 
						|
  Result := FExpression;
 | 
						|
end;
 | 
						|
 | 
						|
function TBaseBreakPoint.GetHitCount: Integer;
 | 
						|
begin
 | 
						|
  Result := FHitCount;
 | 
						|
end;
 | 
						|
 | 
						|
function TBaseBreakPoint.GetLine: Integer;
 | 
						|
begin
 | 
						|
  Result := FLine;
 | 
						|
end;
 | 
						|
 | 
						|
function TBaseBreakPoint.GetSource: String;
 | 
						|
begin
 | 
						|
  Result := FSource;
 | 
						|
end;
 | 
						|
 | 
						|
function TBaseBreakPoint.GetValid: TValidState;
 | 
						|
begin
 | 
						|
  Result := FValid;
 | 
						|
end;
 | 
						|
 | 
						|
procedure TBaseBreakPoint.SetBreakHitCount(const AValue: Integer);
 | 
						|
begin
 | 
						|
  if FBreakHitCount <> AValue
 | 
						|
  then begin
 | 
						|
    FBreakHitCount := AValue;
 | 
						|
    DoBreakHitCountChange;
 | 
						|
  end;
 | 
						|
end;
 | 
						|
 | 
						|
procedure TBaseBreakPoint.SetEnabled (const AValue: Boolean );
 | 
						|
begin
 | 
						|
  if FEnabled <> AValue
 | 
						|
  then begin
 | 
						|
    FEnabled := AValue;
 | 
						|
    DoEnableChange;
 | 
						|
  end;
 | 
						|
end;
 | 
						|
 | 
						|
procedure TBaseBreakPoint.SetExpression (const AValue: String );
 | 
						|
begin
 | 
						|
  if FExpression <> AValue
 | 
						|
  then begin
 | 
						|
    FExpression := AValue;
 | 
						|
    DoExpressionChange;
 | 
						|
  end;
 | 
						|
end;
 | 
						|
 | 
						|
procedure TBaseBreakPoint.SetHitCount (const AValue: Integer );
 | 
						|
begin
 | 
						|
  if FHitCount <> AValue
 | 
						|
  then begin
 | 
						|
    FHitCount := AValue;
 | 
						|
    Changed;
 | 
						|
  end;
 | 
						|
end;
 | 
						|
 | 
						|
procedure TBaseBreakPoint.DoKindChange;
 | 
						|
begin
 | 
						|
  Changed;
 | 
						|
end;
 | 
						|
 | 
						|
procedure TBaseBreakPoint.SetInitialEnabled(const AValue: Boolean);
 | 
						|
begin
 | 
						|
  if FInitialEnabled=AValue then exit;
 | 
						|
  FInitialEnabled:=AValue;
 | 
						|
end;
 | 
						|
 | 
						|
procedure TBaseBreakPoint.SetLocation (const ASource: String; const ALine: Integer );
 | 
						|
begin
 | 
						|
  if (FSource = ASource) and (FLine = ALine) then exit;
 | 
						|
  FSource := ASource;
 | 
						|
  FLine := ALine;
 | 
						|
  Changed;
 | 
						|
end;
 | 
						|
 | 
						|
procedure TBaseBreakPoint.SetWatch(const AData: String; const AScope: TDBGWatchPointScope;
 | 
						|
  const AKind: TDBGWatchPointKind);
 | 
						|
begin
 | 
						|
  if (AData = FWatchData) and (AScope = FWatchScope) and (AKind = FWatchKind) then exit;
 | 
						|
  FWatchData := AData;
 | 
						|
  FWatchScope := AScope;
 | 
						|
  FWatchKind := AKind;
 | 
						|
  Changed;
 | 
						|
end;
 | 
						|
 | 
						|
procedure TBaseBreakPoint.SetValid(const AValue: TValidState );
 | 
						|
begin
 | 
						|
  if FValid <> AValue
 | 
						|
  then begin
 | 
						|
    FValid := AValue;
 | 
						|
    Changed;
 | 
						|
  end;
 | 
						|
end;
 | 
						|
 | 
						|
{ =========================================================================== }
 | 
						|
{ TDBGBreakPoint }
 | 
						|
{ =========================================================================== }
 | 
						|
 | 
						|
constructor TDBGBreakPoint.Create (ACollection: TCollection );
 | 
						|
begin
 | 
						|
  FSlave := nil;
 | 
						|
  inherited Create(ACollection);
 | 
						|
end;
 | 
						|
 | 
						|
destructor TDBGBreakPoint.Destroy;
 | 
						|
var
 | 
						|
  SBP: TBaseBreakPoint;
 | 
						|
begin
 | 
						|
  SBP := FSlave;
 | 
						|
  FSlave := nil;
 | 
						|
  if SBP <> nil
 | 
						|
  then SBP.DoChanged;   // In case UpdateCount  0
 | 
						|
 | 
						|
  inherited Destroy;
 | 
						|
end;
 | 
						|
 | 
						|
procedure TDBGBreakPoint.Hit(var ACanContinue: Boolean);
 | 
						|
var
 | 
						|
  cnt: Integer;
 | 
						|
begin
 | 
						|
  cnt := HitCount + 1;
 | 
						|
  if BreakHitcount > 0
 | 
						|
  then ACanContinue := cnt < BreakHitcount;
 | 
						|
  DoHit(cnt, ACanContinue);
 | 
						|
  if Assigned(FSlave)
 | 
						|
  then FSlave.DoHit(cnt, ACanContinue);
 | 
						|
  Debugger.DoBreakpointHit(Self, ACanContinue)
 | 
						|
end;
 | 
						|
 | 
						|
procedure TDBGBreakPoint.DoChanged;
 | 
						|
begin
 | 
						|
  inherited DoChanged;
 | 
						|
  if FSlave <> nil
 | 
						|
  then FSlave.Changed;
 | 
						|
end;
 | 
						|
 | 
						|
procedure TDBGBreakPoint.DoStateChange(const AOldState: TDBGState);
 | 
						|
begin
 | 
						|
  if Debugger.State <> dsStop then Exit;
 | 
						|
  if not (AOldState in [dsIdle, dsNone]) then Exit;
 | 
						|
 | 
						|
  BeginUpdate;
 | 
						|
  try
 | 
						|
    SetLocation(FSource, Line);
 | 
						|
    Enabled := InitialEnabled;
 | 
						|
    SetHitCount(0);
 | 
						|
  finally
 | 
						|
    EndUpdate;
 | 
						|
  end;
 | 
						|
end;
 | 
						|
 | 
						|
procedure TDBGBreakPoint.DoLogMessage(const AMessage: String);
 | 
						|
begin
 | 
						|
  Debugger.DoDbgEvent(ecBreakpoint, etBreakpointMessage, 'Breakpoint Message: ' + AMessage);
 | 
						|
end;
 | 
						|
 | 
						|
procedure TDBGBreakPoint.DoLogCallStack(const Limit: Integer);
 | 
						|
const
 | 
						|
  Spacing = '    ';
 | 
						|
var
 | 
						|
  CallStack: TCallStackBase;
 | 
						|
  I, Count: Integer;
 | 
						|
  Entry: TCallStackEntry;
 | 
						|
  StackString: String;
 | 
						|
begin
 | 
						|
  Debugger.SetState(dsInternalPause);
 | 
						|
  CallStack := Debugger.CallStack.CurrentCallStackList.EntriesForThreads[Debugger.Threads.CurrentThreads.CurrentThreadId];
 | 
						|
  if Limit = 0 then
 | 
						|
  begin
 | 
						|
    Debugger.DoDbgEvent(ecBreakpoint, etBreakpointMessage, 'Breakpoint Call Stack: Log all stack frames');
 | 
						|
    Count := CallStack.Count;
 | 
						|
    CallStack.PrepareRange(0, Count);
 | 
						|
  end
 | 
						|
  else
 | 
						|
  begin
 | 
						|
    Debugger.DoDbgEvent(ecBreakpoint, etBreakpointMessage, Format('Breakpoint Call Stack: Log %d stack frames', [Limit]));
 | 
						|
    Count := CallStack.CountLimited(Limit);
 | 
						|
    CallStack.PrepareRange(0, Count);
 | 
						|
  end;
 | 
						|
 | 
						|
  for I := 0 to Count - 1 do
 | 
						|
  begin
 | 
						|
    Entry := CallStack.Entries[I];
 | 
						|
    StackString := Spacing + Entry.Source;
 | 
						|
    if Entry.Source = '' then // we do not have a source file => just show an adress
 | 
						|
      StackString := Spacing + ':' + IntToHex(Entry.Address, 8);
 | 
						|
    StackString := StackString + ' ' + Entry.GetFunctionWithArg;
 | 
						|
    if line > 0 then
 | 
						|
      StackString := StackString + ' line ' + IntToStr(Entry.Line);
 | 
						|
 | 
						|
    Debugger.DoDbgEvent(ecBreakpoint, etBreakpointStackDump, StackString);
 | 
						|
  end;
 | 
						|
end;
 | 
						|
 | 
						|
procedure TDBGBreakPoint.DoLogExpression(const AnExpression: String);
 | 
						|
begin
 | 
						|
  // will be called while Debgger.State = dsRun => can not call Evaluate
 | 
						|
end;
 | 
						|
 | 
						|
function TDBGBreakPoint.GetDebugger: TDebuggerIntf;
 | 
						|
begin
 | 
						|
  Result := TDBGBreakPoints(Collection).FDebugger;
 | 
						|
end;
 | 
						|
 | 
						|
procedure TDBGBreakPoint.SetSlave(const ASlave : TBaseBreakPoint);
 | 
						|
begin
 | 
						|
  Assert((FSlave = nil) or (ASlave = nil), 'TDBGBreakPoint.SetSlave already has a slave');
 | 
						|
  FSlave := ASlave;
 | 
						|
end;
 | 
						|
 | 
						|
procedure TDBGBreakPoint.SetEnabled(const AValue: Boolean);
 | 
						|
begin
 | 
						|
  if Enabled = AValue then exit;
 | 
						|
  inherited SetEnabled(AValue);
 | 
						|
  // feedback to IDEBreakPoint
 | 
						|
  if FSlave <> nil then FSlave.Enabled := AValue;
 | 
						|
end;
 | 
						|
 | 
						|
{ =========================================================================== }
 | 
						|
{ TBaseBreakPoints }
 | 
						|
{ =========================================================================== }
 | 
						|
 | 
						|
function TBaseBreakPoints.Add(const ASource: String; const ALine: Integer): TBaseBreakPoint;
 | 
						|
begin
 | 
						|
  Result := TBaseBreakPoint(inherited Add);
 | 
						|
  Result.SetKind(bpkSource);
 | 
						|
  Result.SetLocation(ASource, ALine);
 | 
						|
end;
 | 
						|
 | 
						|
function TBaseBreakPoints.Add(const AAddress: TDBGPtr): TBaseBreakPoint;
 | 
						|
begin
 | 
						|
  Result := TBaseBreakPoint(inherited Add);
 | 
						|
  Result.SetKind(bpkAddress);
 | 
						|
  Result.SetAddress(AAddress);
 | 
						|
end;
 | 
						|
 | 
						|
function TBaseBreakPoints.Add(const AData: String; const AScope: TDBGWatchPointScope;
 | 
						|
  const AKind: TDBGWatchPointKind): TBaseBreakPoint;
 | 
						|
begin
 | 
						|
  Result := TBaseBreakPoint(inherited Add);
 | 
						|
  Result.SetKind(bpkData);
 | 
						|
  Result.SetWatch(AData, AScope, AKind);
 | 
						|
end;
 | 
						|
 | 
						|
constructor TBaseBreakPoints.Create(const ABreakPointClass: TBaseBreakPointClass);
 | 
						|
begin
 | 
						|
  inherited Create(ABreakPointClass);
 | 
						|
end;
 | 
						|
 | 
						|
destructor TBaseBreakPoints.Destroy;
 | 
						|
begin
 | 
						|
  Clear;
 | 
						|
  inherited Destroy;
 | 
						|
end;
 | 
						|
 | 
						|
procedure TBaseBreakPoints.Clear;
 | 
						|
begin
 | 
						|
  while Count > 0 do TBaseBreakPoint(GetItem(0)).ReleaseReference;
 | 
						|
end;
 | 
						|
 | 
						|
function TBaseBreakPoints.Find(const ASource: String; const ALine: Integer): TBaseBreakPoint;
 | 
						|
begin
 | 
						|
  Result := Find(ASource, ALine, nil);
 | 
						|
end;
 | 
						|
 | 
						|
function TBaseBreakPoints.Find(const ASource: String; const ALine: Integer; const AIgnore: TBaseBreakPoint): TBaseBreakPoint;
 | 
						|
var
 | 
						|
  n: Integer;
 | 
						|
begin
 | 
						|
  for n := 0 to Count - 1 do
 | 
						|
  begin
 | 
						|
    Result := TBaseBreakPoint(GetItem(n));
 | 
						|
    if  (Result.Kind = bpkSource)
 | 
						|
    and (Result.Line = ALine)
 | 
						|
    and (AIgnore <> Result)
 | 
						|
    and (CompareFilenames(Result.Source, ASource) = 0)
 | 
						|
    then Exit;
 | 
						|
  end;
 | 
						|
  Result := nil;
 | 
						|
end;
 | 
						|
 | 
						|
function TBaseBreakPoints.Find(const AAddress: TDBGPtr): TBaseBreakPoint;
 | 
						|
begin
 | 
						|
  Result := Find(AAddress, nil);
 | 
						|
end;
 | 
						|
 | 
						|
function TBaseBreakPoints.Find(const AAddress: TDBGPtr; const AIgnore: TBaseBreakPoint): TBaseBreakPoint;
 | 
						|
var
 | 
						|
  n: Integer;
 | 
						|
begin
 | 
						|
  for n := 0 to Count - 1 do
 | 
						|
  begin
 | 
						|
    Result := TBaseBreakPoint(GetItem(n));
 | 
						|
    if  (Result.Kind = bpkAddress)
 | 
						|
    and (Result.Address = AAddress)
 | 
						|
    and (AIgnore <> Result)
 | 
						|
    then Exit;
 | 
						|
  end;
 | 
						|
  Result := nil;
 | 
						|
end;
 | 
						|
 | 
						|
function TBaseBreakPoints.Find(const AData: String; const AScope: TDBGWatchPointScope;
 | 
						|
  const AKind: TDBGWatchPointKind): TBaseBreakPoint;
 | 
						|
begin
 | 
						|
  Result := Find(AData, AScope, AKind, nil);
 | 
						|
end;
 | 
						|
 | 
						|
function TBaseBreakPoints.Find(const AData: String; const AScope: TDBGWatchPointScope;
 | 
						|
  const AKind: TDBGWatchPointKind; const AIgnore: TBaseBreakPoint): TBaseBreakPoint;
 | 
						|
var
 | 
						|
  n: Integer;
 | 
						|
begin
 | 
						|
  for n := 0 to Count - 1 do
 | 
						|
  begin
 | 
						|
    Result := TBaseBreakPoint(GetItem(n));
 | 
						|
    if  (Result.Kind = bpkData)
 | 
						|
    and (Result.WatchData = AData)
 | 
						|
    and (Result.WatchScope = AScope)
 | 
						|
    and (Result.WatchKind = AKind)
 | 
						|
    and (AIgnore <> Result)
 | 
						|
    then Exit;
 | 
						|
  end;
 | 
						|
  Result := nil;
 | 
						|
end;
 | 
						|
 | 
						|
{ =========================================================================== }
 | 
						|
{ TDBGBreakPoints }
 | 
						|
{ =========================================================================== }
 | 
						|
 | 
						|
function TDBGBreakPoints.Add (const ASource: String; const ALine: Integer ): TDBGBreakPoint;
 | 
						|
begin
 | 
						|
  Result := TDBGBreakPoint(inherited Add(ASource, ALine));
 | 
						|
end;
 | 
						|
 | 
						|
function TDBGBreakPoints.Add(const AAddress: TDBGPtr): TDBGBreakPoint;
 | 
						|
begin
 | 
						|
  Result := TDBGBreakPoint(inherited Add(AAddress));
 | 
						|
end;
 | 
						|
 | 
						|
function TDBGBreakPoints.Add(const AData: String; const AScope: TDBGWatchPointScope;
 | 
						|
  const AKind: TDBGWatchPointKind): TDBGBreakPoint;
 | 
						|
begin
 | 
						|
  Result := TDBGBreakPoint(inherited Add(AData, AScope, AKind));
 | 
						|
end;
 | 
						|
 | 
						|
constructor TDBGBreakPoints.Create(const ADebugger: TDebuggerIntf;
 | 
						|
  const ABreakPointClass: TDBGBreakPointClass);
 | 
						|
begin
 | 
						|
  FDebugger := ADebugger;
 | 
						|
  inherited Create(ABreakPointClass);
 | 
						|
end;
 | 
						|
 | 
						|
procedure TDBGBreakPoints.DoStateChange(const AOldState: TDBGState);
 | 
						|
var
 | 
						|
  n: Integer;
 | 
						|
begin
 | 
						|
  for n := 0 to Count - 1 do
 | 
						|
    GetItem(n).DoStateChange(AOldState);
 | 
						|
end;
 | 
						|
 | 
						|
function TDBGBreakPoints.Find(const ASource: String; const ALine: Integer): TDBGBreakPoint;
 | 
						|
begin
 | 
						|
  Result := TDBGBreakPoint(inherited Find(Asource, ALine, nil));
 | 
						|
end;
 | 
						|
 | 
						|
function TDBGBreakPoints.Find (const ASource: String; const ALine: Integer; const AIgnore: TDBGBreakPoint ): TDBGBreakPoint;
 | 
						|
begin
 | 
						|
  Result := TDBGBreakPoint(inherited Find(ASource, ALine, AIgnore));
 | 
						|
end;
 | 
						|
 | 
						|
function TDBGBreakPoints.Find(const AAddress: TDBGPtr): TDBGBreakPoint;
 | 
						|
begin
 | 
						|
  Result := TDBGBreakPoint(inherited Find(AAddress));
 | 
						|
end;
 | 
						|
 | 
						|
function TDBGBreakPoints.Find(const AAddress: TDBGPtr; const AIgnore: TDBGBreakPoint): TDBGBreakPoint;
 | 
						|
begin
 | 
						|
  Result := TDBGBreakPoint(inherited Find(AAddress, nil));
 | 
						|
end;
 | 
						|
 | 
						|
function TDBGBreakPoints.Find(const AData: String; const AScope: TDBGWatchPointScope;
 | 
						|
  const AKind: TDBGWatchPointKind): TDBGBreakPoint;
 | 
						|
begin
 | 
						|
  Result := TDBGBreakPoint(inherited Find(AData, AScope, AKind, nil));
 | 
						|
end;
 | 
						|
 | 
						|
function TDBGBreakPoints.Find(const AData: String; const AScope: TDBGWatchPointScope;
 | 
						|
  const AKind: TDBGWatchPointKind; const AIgnore: TDBGBreakPoint): TDBGBreakPoint;
 | 
						|
begin
 | 
						|
  Result := TDBGBreakPoint(inherited Find(AData, AScope, AKind, AIgnore));
 | 
						|
end;
 | 
						|
 | 
						|
function TDBGBreakPoints.GetItem (const AnIndex: Integer ): TDBGBreakPoint;
 | 
						|
begin
 | 
						|
  Result := TDBGBreakPoint(inherited GetItem(AnIndex));
 | 
						|
end;
 | 
						|
 | 
						|
procedure TDBGBreakPoints.SetItem (const AnIndex: Integer; const AValue: TDBGBreakPoint );
 | 
						|
begin
 | 
						|
  inherited SetItem(AnIndex, AValue);
 | 
						|
end;
 | 
						|
 | 
						|
{ TDBGField }
 | 
						|
 | 
						|
procedure TDBGField.IncRefCount;
 | 
						|
begin
 | 
						|
  inc(FRefCount);
 | 
						|
end;
 | 
						|
 | 
						|
procedure TDBGField.DecRefCount;
 | 
						|
begin
 | 
						|
  dec(FRefCount);
 | 
						|
  if FRefCount <= 0
 | 
						|
  then Self.Free;
 | 
						|
end;
 | 
						|
 | 
						|
constructor TDBGField.Create(const AName: String; ADBGType: TDBGType;
 | 
						|
  ALocation: TDBGFieldLocation; AFlags: TDBGFieldFlags; AClassName: String = '');
 | 
						|
begin
 | 
						|
  inherited Create;
 | 
						|
  FName := AName;
 | 
						|
  FLocation := ALocation;
 | 
						|
  FDBGType := ADBGType;
 | 
						|
  FFlags := AFlags;
 | 
						|
  FRefCount := 0;
 | 
						|
  FClassName := AClassName;
 | 
						|
end;
 | 
						|
 | 
						|
destructor TDBGField.Destroy;
 | 
						|
begin
 | 
						|
  FreeAndNil(FDBGType);
 | 
						|
  inherited Destroy;
 | 
						|
end;
 | 
						|
 | 
						|
{ TDBGFields }
 | 
						|
 | 
						|
constructor TDBGFields.Create;
 | 
						|
begin
 | 
						|
  FList := TList.Create;
 | 
						|
  inherited;
 | 
						|
end;
 | 
						|
 | 
						|
destructor TDBGFields.Destroy;
 | 
						|
var
 | 
						|
  n: Integer;
 | 
						|
begin
 | 
						|
  for n := 0 to Count - 1 do
 | 
						|
    Items[n].DecRefCount;
 | 
						|
 | 
						|
  FreeAndNil(FList);
 | 
						|
  inherited;
 | 
						|
end;
 | 
						|
 | 
						|
procedure TDBGFields.Add(const AField: TDBGField);
 | 
						|
begin
 | 
						|
  AField.IncRefCount;
 | 
						|
  FList.Add(AField);
 | 
						|
end;
 | 
						|
 | 
						|
function TDBGFields.GetCount: Integer;
 | 
						|
begin
 | 
						|
  Result := FList.Count;
 | 
						|
end;
 | 
						|
 | 
						|
function TDBGFields.GetField(const AIndex: Integer): TDBGField;
 | 
						|
begin
 | 
						|
  Result := TDBGField(FList[AIndex]);
 | 
						|
end;
 | 
						|
 | 
						|
{ TDBGPTypes }
 | 
						|
 | 
						|
constructor TDBGTypes.Create;
 | 
						|
begin
 | 
						|
  FList := TList.Create;
 | 
						|
  inherited;
 | 
						|
end;
 | 
						|
 | 
						|
destructor TDBGTypes.Destroy;
 | 
						|
var
 | 
						|
  n: Integer;
 | 
						|
begin
 | 
						|
  for n := 0 to Count - 1 do
 | 
						|
    Items[n].Free;
 | 
						|
 | 
						|
  FreeAndNil(FList);
 | 
						|
  inherited;
 | 
						|
end;
 | 
						|
 | 
						|
function TDBGTypes.GetCount: Integer;
 | 
						|
begin
 | 
						|
  Result := Flist.Count;
 | 
						|
end;
 | 
						|
 | 
						|
function TDBGTypes.GetType(const AIndex: Integer): TDBGType;
 | 
						|
begin
 | 
						|
  Result := TDBGType(FList[AIndex]);
 | 
						|
end;
 | 
						|
 | 
						|
{ TDBGPType }
 | 
						|
 | 
						|
function TDBGType.GetFields: TDBGFields;
 | 
						|
begin
 | 
						|
  if FFields = nil then
 | 
						|
    FFields := TDBGFields.Create;
 | 
						|
  Result := FFields;
 | 
						|
end;
 | 
						|
 | 
						|
procedure TDBGType.Init;
 | 
						|
begin
 | 
						|
  //
 | 
						|
end;
 | 
						|
 | 
						|
constructor TDBGType.Create(AKind: TDBGSymbolKind; const ATypeName: String);
 | 
						|
begin
 | 
						|
  FKind := AKind;
 | 
						|
  FTypeName := ATypeName;
 | 
						|
  Init;
 | 
						|
  inherited Create;
 | 
						|
end;
 | 
						|
 | 
						|
constructor TDBGType.Create(AKind: TDBGSymbolKind; const AArguments: TDBGTypes; AResult: TDBGType);
 | 
						|
begin
 | 
						|
  FKind := AKind;
 | 
						|
  FArguments := AArguments;
 | 
						|
  FResult := AResult;
 | 
						|
  Init;
 | 
						|
  inherited Create;
 | 
						|
end;
 | 
						|
 | 
						|
destructor TDBGType.Destroy;
 | 
						|
begin
 | 
						|
  FreeAndNil(FResult);
 | 
						|
  FreeAndNil(FArguments);
 | 
						|
  FreeAndNil(FFields);
 | 
						|
  FreeAndNil(FMembers);
 | 
						|
  inherited;
 | 
						|
end;
 | 
						|
 | 
						|
{ TWatchesSupplier }
 | 
						|
 | 
						|
procedure TWatchesSupplier.RequestData(AWatchValue: TWatchValue);
 | 
						|
begin
 | 
						|
  if FNotifiedState  in [dsPause, dsInternalPause]
 | 
						|
  then InternalRequestData(AWatchValue)
 | 
						|
  else AWatchValue.SetValidity(ddsInvalid);
 | 
						|
end;
 | 
						|
 | 
						|
function TWatchesSupplier.GetCurrentWatches: TWatches;
 | 
						|
begin
 | 
						|
  Result := Nil;
 | 
						|
  if Monitor <> nil then
 | 
						|
    Result := Monitor.Watches;
 | 
						|
end;
 | 
						|
 | 
						|
function TWatchesSupplier.GetMonitor: TWatchesMonitor;
 | 
						|
begin
 | 
						|
  Result := TWatchesMonitor(inherited Monitor);
 | 
						|
end;
 | 
						|
 | 
						|
procedure TWatchesSupplier.SetMonitor(AValue: TWatchesMonitor);
 | 
						|
begin
 | 
						|
  inherited Monitor := AValue;
 | 
						|
end;
 | 
						|
 | 
						|
procedure TWatchesSupplier.DoStateChange(const AOldState: TDBGState);
 | 
						|
begin
 | 
						|
  // workaround for state changes during TWatchValue.GetValue
 | 
						|
  inc(DbgStateChangeCounter);
 | 
						|
  if DbgStateChangeCounter = high(DbgStateChangeCounter) then DbgStateChangeCounter := 0;
 | 
						|
  inherited DoStateChange(AOldState);
 | 
						|
end;
 | 
						|
 | 
						|
procedure TWatchesSupplier.InternalRequestData(AWatchValue: TWatchValue);
 | 
						|
begin
 | 
						|
  AWatchValue.SetValidity(ddsInvalid);
 | 
						|
end;
 | 
						|
 | 
						|
constructor TWatchesSupplier.Create(const ADebugger: TDebuggerIntf);
 | 
						|
begin
 | 
						|
  inherited Create(ADebugger);
 | 
						|
  FNotifiedState := dsNone;
 | 
						|
end;
 | 
						|
 | 
						|
{ TWatchesMonitor }
 | 
						|
 | 
						|
function TWatchesMonitor.GetSupplier: TWatchesSupplier;
 | 
						|
begin
 | 
						|
  Result := TWatchesSupplier(inherited Supplier);
 | 
						|
end;
 | 
						|
 | 
						|
procedure TWatchesMonitor.SetSupplier(AValue: TWatchesSupplier);
 | 
						|
begin
 | 
						|
  inherited Supplier := AValue;
 | 
						|
end;
 | 
						|
 | 
						|
function TWatchesMonitor.CreateWatches: TWatches;
 | 
						|
begin
 | 
						|
  Result := TWatches.Create;
 | 
						|
end;
 | 
						|
 | 
						|
constructor TWatchesMonitor.Create;
 | 
						|
begin
 | 
						|
  FWatches := CreateWatches;
 | 
						|
  inherited Create;
 | 
						|
end;
 | 
						|
 | 
						|
destructor TWatchesMonitor.Destroy;
 | 
						|
begin
 | 
						|
  inherited Destroy;
 | 
						|
  FreeAndNil(FWatches);
 | 
						|
end;
 | 
						|
 | 
						|
{ TLocalsSupplier }
 | 
						|
 | 
						|
function TLocalsSupplier.GetCurrentLocalsList: TLocalsList;
 | 
						|
begin
 | 
						|
  Result := nil;
 | 
						|
  if Monitor <> nil then
 | 
						|
    Result := Monitor.LocalsList;
 | 
						|
end;
 | 
						|
 | 
						|
function TLocalsSupplier.GetMonitor: TLocalsMonitor;
 | 
						|
begin
 | 
						|
  Result := TLocalsMonitor(inherited Monitor);
 | 
						|
end;
 | 
						|
 | 
						|
procedure TLocalsSupplier.SetMonitor(AValue: TLocalsMonitor);
 | 
						|
begin
 | 
						|
  inherited Monitor := AValue;
 | 
						|
end;
 | 
						|
 | 
						|
procedure TLocalsSupplier.RequestData(ALocals: TLocals);
 | 
						|
begin
 | 
						|
  ALocals.SetDataValidity(ddsInvalid)
 | 
						|
end;
 | 
						|
 | 
						|
{ TLocalsMonitor }
 | 
						|
 | 
						|
function TLocalsMonitor.GetSupplier: TLocalsSupplier;
 | 
						|
begin
 | 
						|
  Result := TLocalsSupplier(inherited Supplier);
 | 
						|
end;
 | 
						|
 | 
						|
procedure TLocalsMonitor.SetSupplier(AValue: TLocalsSupplier);
 | 
						|
begin
 | 
						|
  inherited Supplier := AValue;
 | 
						|
end;
 | 
						|
 | 
						|
function TLocalsMonitor.CreateLocalsList: TLocalsList;
 | 
						|
begin
 | 
						|
  Result := TLocalsList.Create;
 | 
						|
end;
 | 
						|
 | 
						|
constructor TLocalsMonitor.Create;
 | 
						|
begin
 | 
						|
  FLocalsList := CreateLocalsList;
 | 
						|
  FLocalsList.AddReference;
 | 
						|
  inherited Create;
 | 
						|
end;
 | 
						|
 | 
						|
destructor TLocalsMonitor.Destroy;
 | 
						|
begin
 | 
						|
  inherited Destroy;
 | 
						|
  ReleaseRefAndNil(FLocalsList);
 | 
						|
end;
 | 
						|
 | 
						|
{ TBaseLineInfo }
 | 
						|
 | 
						|
function TBaseLineInfo.GetSource(const AnIndex: integer): String;
 | 
						|
begin
 | 
						|
  Result := '';
 | 
						|
end;
 | 
						|
 | 
						|
function TBaseLineInfo.IndexOf(const ASource: String): integer;
 | 
						|
begin
 | 
						|
  Result := -1;
 | 
						|
end;
 | 
						|
 | 
						|
constructor TBaseLineInfo.Create;
 | 
						|
begin
 | 
						|
  inherited Create;
 | 
						|
end;
 | 
						|
 | 
						|
function TBaseLineInfo.GetAddress(const AIndex: Integer; const ALine: Integer): TDbgPtr;
 | 
						|
begin
 | 
						|
  Result := 0;
 | 
						|
end;
 | 
						|
 | 
						|
function TBaseLineInfo.GetAddress(const ASource: String; const ALine: Integer): TDbgPtr;
 | 
						|
var
 | 
						|
  idx: Integer;
 | 
						|
begin
 | 
						|
  idx := IndexOf(ASource);
 | 
						|
  if idx = -1
 | 
						|
  then Result := 0
 | 
						|
  else Result := GetAddress(idx, ALine);
 | 
						|
end;
 | 
						|
 | 
						|
function TBaseLineInfo.GetInfo(AAddress: TDbgPtr; out ASource, ALine, AOffset: Integer): Boolean;
 | 
						|
begin
 | 
						|
  Result := False;
 | 
						|
end;
 | 
						|
 | 
						|
procedure TBaseLineInfo.Request(const ASource: String);
 | 
						|
begin
 | 
						|
end;
 | 
						|
 | 
						|
procedure TBaseLineInfo.Cancel(const ASource: String);
 | 
						|
begin
 | 
						|
 | 
						|
end;
 | 
						|
 | 
						|
function TBaseLineInfo.Count: Integer;
 | 
						|
begin
 | 
						|
  Result := 0;
 | 
						|
end;
 | 
						|
 | 
						|
{ TDBGLineInfo }
 | 
						|
 | 
						|
procedure TDBGLineInfo.Changed(ASource: String);
 | 
						|
begin
 | 
						|
  DoChange(ASource);
 | 
						|
end;
 | 
						|
 | 
						|
procedure TDBGLineInfo.DoChange(ASource: String);
 | 
						|
begin
 | 
						|
  if Assigned(FOnChange) then FOnChange(Self, ASource);
 | 
						|
end;
 | 
						|
 | 
						|
procedure TDBGLineInfo.DoStateChange(const AOldState: TDBGState);
 | 
						|
begin
 | 
						|
end;
 | 
						|
 | 
						|
constructor TDBGLineInfo.Create(const ADebugger: TDebuggerIntf);
 | 
						|
begin
 | 
						|
  inherited Create;
 | 
						|
  FDebugger := ADebugger;
 | 
						|
end;
 | 
						|
 | 
						|
{ TCallStackEntry }
 | 
						|
 | 
						|
function TCallStackEntry.GetArgumentCount: Integer;
 | 
						|
begin
 | 
						|
  Result := FArguments.Count;
 | 
						|
end;
 | 
						|
 | 
						|
function TCallStackEntry.GetArgumentName(const AnIndex: Integer): String;
 | 
						|
begin
 | 
						|
  Result := FArguments.Names[AnIndex];
 | 
						|
end;
 | 
						|
 | 
						|
function TCallStackEntry.GetArgumentValue(const AnIndex: Integer): String;
 | 
						|
begin
 | 
						|
  Result := FArguments[AnIndex];
 | 
						|
  Result := GetPart('=', '', Result);
 | 
						|
end;
 | 
						|
 | 
						|
function TCallStackEntry.GetFunctionName: String;
 | 
						|
begin
 | 
						|
  Result := FFunctionName;
 | 
						|
end;
 | 
						|
 | 
						|
function TCallStackEntry.GetSource: String;
 | 
						|
begin
 | 
						|
  Result := '';
 | 
						|
end;
 | 
						|
 | 
						|
function TCallStackEntry.GetValidity: TDebuggerDataState;
 | 
						|
begin
 | 
						|
  Result := FValidity;
 | 
						|
end;
 | 
						|
 | 
						|
procedure TCallStackEntry.SetValidity(AValue: TDebuggerDataState);
 | 
						|
begin
 | 
						|
  FValidity := AValue;
 | 
						|
end;
 | 
						|
 | 
						|
procedure TCallStackEntry.ClearLocation;
 | 
						|
begin
 | 
						|
  InitFields(0, 0, nil, '', 0, Validity);
 | 
						|
  if Arguments <> nil then
 | 
						|
    Arguments.Clear;
 | 
						|
end;
 | 
						|
 | 
						|
procedure TCallStackEntry.InitFields(const AIndex: Integer; const AnAddress: TDbgPtr;
 | 
						|
  const AnArguments: TStrings; const AFunctionName: String; const ALine: Integer;
 | 
						|
  AValidity: TDebuggerDataState);
 | 
						|
begin
 | 
						|
  FIndex        := AIndex;
 | 
						|
  FAddress      := AnAddress;
 | 
						|
  if AnArguments <> nil
 | 
						|
  then FArguments.Assign(AnArguments);
 | 
						|
  FFunctionName := AFunctionName;
 | 
						|
  FLine         := ALine;
 | 
						|
  FValidity     := AValidity;
 | 
						|
end;
 | 
						|
 | 
						|
constructor TCallStackEntry.Create;
 | 
						|
begin
 | 
						|
  inherited Create;
 | 
						|
  FArguments := TStringlist.Create;
 | 
						|
end;
 | 
						|
 | 
						|
function TCallStackEntry.CreateCopy: TCallStackEntry;
 | 
						|
begin
 | 
						|
  Result := TCallStackEntry.Create;
 | 
						|
  Result.Assign(Self);
 | 
						|
end;
 | 
						|
 | 
						|
destructor TCallStackEntry.Destroy;
 | 
						|
begin
 | 
						|
  inherited Destroy;
 | 
						|
  FreeAndNil(FArguments);
 | 
						|
end;
 | 
						|
 | 
						|
procedure TCallStackEntry.Assign(AnOther: TCallStackEntry);
 | 
						|
begin
 | 
						|
  FValidity     := AnOther.FValidity;
 | 
						|
  FIndex        := AnOther.FIndex;
 | 
						|
  FAddress      := AnOther.FAddress;
 | 
						|
  FFunctionName := AnOther.FFunctionName;
 | 
						|
  FLine         := AnOther.FLine;
 | 
						|
  FArguments.Assign(AnOther.FArguments);
 | 
						|
end;
 | 
						|
 | 
						|
procedure TCallStackEntry.Init(const AnAddress: TDbgPtr; const AnArguments: TStrings;
 | 
						|
  const AFunctionName: String; const AUnitName, AClassName, AProcName, AFunctionArgs: String;
 | 
						|
  const ALine: Integer; AState: TDebuggerDataState);
 | 
						|
begin
 | 
						|
  InitFields(FIndex, AnAddress, AnArguments, AFunctionName, ALine, AState);
 | 
						|
end;
 | 
						|
 | 
						|
procedure TCallStackEntry.Init(const AnAddress: TDbgPtr; const AnArguments: TStrings;
 | 
						|
  const AFunctionName: String; const FileName, FullName: String; const ALine: Integer;
 | 
						|
  AState: TDebuggerDataState);
 | 
						|
begin
 | 
						|
  InitFields(FIndex, AnAddress, AnArguments, AFunctionName, ALine, AState);
 | 
						|
end;
 | 
						|
 | 
						|
function TCallStackEntry.GetFunctionWithArg: String;
 | 
						|
var
 | 
						|
  S: String;
 | 
						|
  m: Integer;
 | 
						|
begin
 | 
						|
  S := '';
 | 
						|
  for m := 0 to ArgumentCount - 1 do
 | 
						|
  begin
 | 
						|
    if S <> '' then
 | 
						|
      S := S + ', ';
 | 
						|
    S := S + ArgumentValues[m];
 | 
						|
  end;
 | 
						|
  if S <> '' then
 | 
						|
    S := '(' + S + ')';
 | 
						|
  Result := FunctionName + S;
 | 
						|
end;
 | 
						|
 | 
						|
{ TCallStackList }
 | 
						|
 | 
						|
function TCallStackList.GetEntry(const AIndex: Integer): TCallStackBase;
 | 
						|
begin
 | 
						|
  Result := TCallStackBase(FList[AIndex]);
 | 
						|
end;
 | 
						|
 | 
						|
function TCallStackList.GetEntryForThread(const AThreadId: Integer): TCallStackBase;
 | 
						|
var
 | 
						|
  i: Integer;
 | 
						|
begin
 | 
						|
  i := Count - 1;
 | 
						|
  while (i >= 0) and (TCallStackBase(FList[i]).ThreadId <> AThreadId) do dec(i);
 | 
						|
  if i >= 0
 | 
						|
  then Result := TCallStackBase(FList[i])
 | 
						|
  else Result := NewEntryForThread(AThreadId);
 | 
						|
end;
 | 
						|
 | 
						|
function TCallStackList.NewEntryForThread(const AThreadId: Integer): TCallStackBase;
 | 
						|
begin
 | 
						|
  Result := nil;
 | 
						|
end;
 | 
						|
 | 
						|
constructor TCallStackList.Create;
 | 
						|
begin
 | 
						|
  FList := TList.Create;
 | 
						|
end;
 | 
						|
 | 
						|
destructor TCallStackList.Destroy;
 | 
						|
begin
 | 
						|
  inherited Destroy;
 | 
						|
  Clear;
 | 
						|
  FreeAndNil(FList);
 | 
						|
end;
 | 
						|
 | 
						|
procedure TCallStackList.Assign(AnOther: TCallStackList);
 | 
						|
var
 | 
						|
  i: Integer;
 | 
						|
begin
 | 
						|
  Clear;
 | 
						|
  for i := 0 to AnOther.FList.Count-1 do
 | 
						|
    FList.Add(TCallStackBase(AnOther.FList[i]).CreateCopy);
 | 
						|
end;
 | 
						|
 | 
						|
procedure TCallStackList.Add(ACallStack: TCallStackBase);
 | 
						|
begin
 | 
						|
  FList.Add(ACallStack);
 | 
						|
end;
 | 
						|
 | 
						|
procedure TCallStackList.Clear;
 | 
						|
begin
 | 
						|
  while FList.Count > 0 do begin
 | 
						|
    TObject(FList[0]).Free;
 | 
						|
    FList.Delete(0);
 | 
						|
  end;
 | 
						|
end;
 | 
						|
 | 
						|
function TCallStackList.Count: Integer;
 | 
						|
begin
 | 
						|
  Result := FList.Count;
 | 
						|
end;
 | 
						|
 | 
						|
{ TCallStackSupplier }
 | 
						|
 | 
						|
procedure TCallStackSupplier.Changed;
 | 
						|
begin
 | 
						|
  DebugLn(DBG_DATA_MONITORS, ['DebugDataMonitor: TCallStackSupplier.Changed']);
 | 
						|
  Monitor.DoModified;
 | 
						|
end;
 | 
						|
 | 
						|
function TCallStackSupplier.GetCurrentCallStackList: TCallStackList;
 | 
						|
begin
 | 
						|
  Result := nil;
 | 
						|
  if Monitor <> nil then
 | 
						|
    Result := Monitor.CallStackList;
 | 
						|
end;
 | 
						|
 | 
						|
function TCallStackSupplier.GetMonitor: TCallStackMonitor;
 | 
						|
begin
 | 
						|
  Result := TCallStackMonitor(inherited Monitor);
 | 
						|
end;
 | 
						|
 | 
						|
procedure TCallStackSupplier.SetMonitor(AValue: TCallStackMonitor);
 | 
						|
begin
 | 
						|
  inherited Monitor := AValue;
 | 
						|
end;
 | 
						|
 | 
						|
procedure TCallStackSupplier.RequestCount(ACallstack: TCallStackBase);
 | 
						|
begin
 | 
						|
  ACallstack.SetCountValidity(ddsInvalid);
 | 
						|
end;
 | 
						|
 | 
						|
procedure TCallStackSupplier.RequestAtLeastCount(ACallstack: TCallStackBase;
 | 
						|
  ARequiredMinCount: Integer);
 | 
						|
begin
 | 
						|
  RequestCount(ACallstack);
 | 
						|
end;
 | 
						|
 | 
						|
procedure TCallStackSupplier.RequestCurrent(ACallstack: TCallStackBase);
 | 
						|
begin
 | 
						|
  ACallstack.SetCurrentValidity(ddsInvalid);
 | 
						|
end;
 | 
						|
 | 
						|
procedure TCallStackSupplier.RequestEntries(ACallstack: TCallStackBase);
 | 
						|
var
 | 
						|
  e: TCallStackEntry;
 | 
						|
  It: TMapIterator;
 | 
						|
begin
 | 
						|
  DebugLn(DBG_DATA_MONITORS, ['DebugDataMonitor: TCallStackSupplier.RequestEntries']);
 | 
						|
  It := TMapIterator.Create(ACallstack.RawEntries);
 | 
						|
 | 
						|
  if not It.Locate(ACallstack.LowestUnknown )
 | 
						|
  then if not It.EOM
 | 
						|
  then It.Next;
 | 
						|
 | 
						|
  while (not IT.EOM) and (TCallStackEntry(It.DataPtr^).Index < ACallstack.HighestUnknown)
 | 
						|
  do begin
 | 
						|
    e := TCallStackEntry(It.DataPtr^);
 | 
						|
    if e.Validity = ddsRequested then e.Validity := ddsInvalid;
 | 
						|
    It.Next;
 | 
						|
  end;
 | 
						|
  It.Free;
 | 
						|
 | 
						|
  if Monitor <> nil
 | 
						|
  then Monitor.DoModified;
 | 
						|
end;
 | 
						|
 | 
						|
//procedure TCallStackSupplier.CurrentChanged;
 | 
						|
//begin
 | 
						|
//  DebugLn(DBG_DATA_MONITORS, ['DebugDataMonitor: TCallStackSupplier.CurrentChanged']);
 | 
						|
//  if Monitor <> nil
 | 
						|
//  then Monitor.NotifyCurrent;
 | 
						|
//end;
 | 
						|
 | 
						|
procedure TCallStackSupplier.UpdateCurrentIndex;
 | 
						|
begin
 | 
						|
  //
 | 
						|
end;
 | 
						|
 | 
						|
{ TCallStackMonitor }
 | 
						|
 | 
						|
function TCallStackMonitor.GetSupplier: TCallStackSupplier;
 | 
						|
begin
 | 
						|
  Result := TCallStackSupplier(inherited Supplier);
 | 
						|
end;
 | 
						|
 | 
						|
procedure TCallStackMonitor.SetSupplier(AValue: TCallStackSupplier);
 | 
						|
begin
 | 
						|
  inherited Supplier := AValue;
 | 
						|
end;
 | 
						|
 | 
						|
function TCallStackMonitor.CreateCallStackList: TCallStackList;
 | 
						|
begin
 | 
						|
  Result := TCallStackList.Create;
 | 
						|
end;
 | 
						|
 | 
						|
constructor TCallStackMonitor.Create;
 | 
						|
begin
 | 
						|
  FCallStackList := CreateCallStackList;
 | 
						|
  inherited Create;
 | 
						|
end;
 | 
						|
 | 
						|
destructor TCallStackMonitor.Destroy;
 | 
						|
begin
 | 
						|
  inherited Destroy;
 | 
						|
  FreeAndNil(FCallStackList);
 | 
						|
end;
 | 
						|
 | 
						|
{ TThreadsSupplier }
 | 
						|
 | 
						|
procedure TThreadsSupplier.Changed;
 | 
						|
begin
 | 
						|
  if Monitor <> nil
 | 
						|
  then Monitor.DoModified;
 | 
						|
end;
 | 
						|
 | 
						|
function TThreadsSupplier.GetCurrentThreads: TThreads;
 | 
						|
begin
 | 
						|
  Result := nil;
 | 
						|
  if Monitor <> nil then
 | 
						|
    Result := Monitor.Threads;
 | 
						|
end;
 | 
						|
 | 
						|
function TThreadsSupplier.GetMonitor: TThreadsMonitor;
 | 
						|
begin
 | 
						|
  Result := TThreadsMonitor(inherited Monitor);
 | 
						|
end;
 | 
						|
 | 
						|
procedure TThreadsSupplier.SetMonitor(AValue: TThreadsMonitor);
 | 
						|
begin
 | 
						|
  inherited Monitor := AValue;
 | 
						|
end;
 | 
						|
 | 
						|
procedure TThreadsSupplier.ChangeCurrentThread(ANewId: Integer);
 | 
						|
begin
 | 
						|
  //
 | 
						|
end;
 | 
						|
 | 
						|
procedure TThreadsSupplier.RequestMasterData;
 | 
						|
begin
 | 
						|
  //
 | 
						|
end;
 | 
						|
 | 
						|
procedure TThreadsSupplier.DoStateChange(const AOldState: TDBGState);
 | 
						|
begin
 | 
						|
  if (Debugger.State = dsStop) and (CurrentThreads <> nil) then
 | 
						|
    CurrentThreads.Clear;
 | 
						|
  inherited DoStateChange(AOldState);
 | 
						|
end;
 | 
						|
 | 
						|
procedure TThreadsSupplier.DoStateLeavePauseClean;
 | 
						|
begin
 | 
						|
  DoCleanAfterPause;
 | 
						|
end;
 | 
						|
 | 
						|
procedure TThreadsSupplier.DoCleanAfterPause;
 | 
						|
begin
 | 
						|
  if CurrentThreads <> nil then
 | 
						|
    CurrentThreads.Clear;
 | 
						|
  if Monitor <> nil then
 | 
						|
    Monitor.DoModified;
 | 
						|
end;
 | 
						|
 | 
						|
{ =========================================================================== }
 | 
						|
{ TBaseSignal }
 | 
						|
{ =========================================================================== }
 | 
						|
 | 
						|
procedure TBaseSignal.AssignTo(Dest: TPersistent);
 | 
						|
begin
 | 
						|
  if Dest is TBaseSignal
 | 
						|
  then begin
 | 
						|
    TBaseSignal(Dest).Name := FName;
 | 
						|
    TBaseSignal(Dest).ID := FID;
 | 
						|
    TBaseSignal(Dest).HandledByDebugger := FHandledByDebugger;
 | 
						|
    TBaseSignal(Dest).ResumeHandled := FResumeHandled;
 | 
						|
  end
 | 
						|
  else inherited AssignTo(Dest);
 | 
						|
end;
 | 
						|
 | 
						|
constructor TBaseSignal.Create(ACollection: TCollection);
 | 
						|
begin
 | 
						|
  FID := 0;
 | 
						|
  FHandledByDebugger := False;
 | 
						|
  FResumeHandled := True;
 | 
						|
  inherited Create(ACollection);
 | 
						|
end;
 | 
						|
 | 
						|
procedure TBaseSignal.SetHandledByDebugger(const AValue: Boolean);
 | 
						|
begin
 | 
						|
  if AValue = FHandledByDebugger then Exit;
 | 
						|
  FHandledByDebugger := AValue;
 | 
						|
  Changed;
 | 
						|
end;
 | 
						|
 | 
						|
procedure TBaseSignal.SetID (const AValue: Integer );
 | 
						|
begin
 | 
						|
  if FID = AValue then Exit;
 | 
						|
  FID := AValue;
 | 
						|
  Changed;
 | 
						|
end;
 | 
						|
 | 
						|
procedure TBaseSignal.SetName (const AValue: String );
 | 
						|
begin
 | 
						|
  if FName = AValue then Exit;
 | 
						|
  FName := AValue;
 | 
						|
  Changed;
 | 
						|
end;
 | 
						|
 | 
						|
procedure TBaseSignal.SetResumeHandled(const AValue: Boolean);
 | 
						|
begin
 | 
						|
  if FResumeHandled = AValue then Exit;
 | 
						|
  FResumeHandled := AValue;
 | 
						|
  Changed;
 | 
						|
end;
 | 
						|
 | 
						|
{ =========================================================================== }
 | 
						|
{ TDBGSignal }
 | 
						|
{ =========================================================================== }
 | 
						|
 | 
						|
function TDBGSignal.GetDebugger: TDebuggerIntf;
 | 
						|
begin
 | 
						|
  Result := TDBGSignals(Collection).FDebugger;
 | 
						|
end;
 | 
						|
 | 
						|
{ =========================================================================== }
 | 
						|
{ TBaseSignals }
 | 
						|
{ =========================================================================== }
 | 
						|
 | 
						|
function TBaseSignals.Add (const AName: String; AID: Integer ): TBaseSignal;
 | 
						|
begin
 | 
						|
  Result := TBaseSignal(inherited Add);
 | 
						|
  Result.BeginUpdate;
 | 
						|
  try
 | 
						|
    Result.Name := AName;
 | 
						|
    Result.ID := AID;
 | 
						|
  finally
 | 
						|
    Result.EndUpdate;
 | 
						|
  end;
 | 
						|
end;
 | 
						|
 | 
						|
constructor TBaseSignals.Create (const AItemClass: TBaseSignalClass );
 | 
						|
begin
 | 
						|
  inherited Create(AItemClass);
 | 
						|
end;
 | 
						|
 | 
						|
procedure TBaseSignals.Reset;
 | 
						|
begin
 | 
						|
  Clear;
 | 
						|
end;
 | 
						|
 | 
						|
function TBaseSignals.Find(const AName: String): TBaseSignal;
 | 
						|
var
 | 
						|
  n: Integer;
 | 
						|
  S: String;
 | 
						|
begin
 | 
						|
  S := UpperCase(AName);
 | 
						|
  for n := 0 to Count - 1 do
 | 
						|
  begin
 | 
						|
    Result := TBaseSignal(GetItem(n));
 | 
						|
    if UpperCase(Result.Name) = S
 | 
						|
    then Exit;
 | 
						|
  end;
 | 
						|
  Result := nil;
 | 
						|
end;
 | 
						|
 | 
						|
{ =========================================================================== }
 | 
						|
{ TDBGSignals }
 | 
						|
{ =========================================================================== }
 | 
						|
 | 
						|
function TDBGSignals.Add(const AName: String; AID: Integer): TDBGSignal;
 | 
						|
begin
 | 
						|
  Result := TDBGSignal(inherited Add(AName, AID));
 | 
						|
end;
 | 
						|
 | 
						|
constructor TDBGSignals.Create(const ADebugger: TDebuggerIntf;
 | 
						|
  const ASignalClass: TDBGSignalClass);
 | 
						|
begin
 | 
						|
  FDebugger := ADebugger;
 | 
						|
  inherited Create(ASignalClass);
 | 
						|
end;
 | 
						|
 | 
						|
function TDBGSignals.Find(const AName: String): TDBGSignal;
 | 
						|
begin
 | 
						|
  Result := TDBGSignal(inherited Find(ANAme));
 | 
						|
end;
 | 
						|
 | 
						|
function TDBGSignals.GetItem(const AIndex: Integer): TDBGSignal;
 | 
						|
begin
 | 
						|
  Result := TDBGSignal(inherited GetItem(AIndex));
 | 
						|
end;
 | 
						|
 | 
						|
procedure TDBGSignals.SetItem(const AIndex: Integer; const AValue: TDBGSignal);
 | 
						|
begin
 | 
						|
  inherited SetItem(AIndex, AValue);
 | 
						|
end;
 | 
						|
 | 
						|
{ =========================================================================== }
 | 
						|
{ TBaseException }
 | 
						|
{ =========================================================================== }
 | 
						|
 | 
						|
procedure TBaseException.SetEnabled(AValue: Boolean);
 | 
						|
begin
 | 
						|
  if FEnabled = AValue then Exit;
 | 
						|
  FEnabled := AValue;
 | 
						|
  Changed;
 | 
						|
end;
 | 
						|
 | 
						|
procedure TBaseException.AssignTo(Dest: TPersistent);
 | 
						|
begin
 | 
						|
  if Dest is TBaseException
 | 
						|
  then begin
 | 
						|
    TBaseException(Dest).Name := FName;
 | 
						|
  end
 | 
						|
  else inherited AssignTo(Dest);
 | 
						|
end;
 | 
						|
 | 
						|
constructor TBaseException.Create(ACollection: TCollection);
 | 
						|
begin
 | 
						|
  inherited Create(ACollection);
 | 
						|
end;
 | 
						|
 | 
						|
procedure TBaseException.SetName(const AValue: String);
 | 
						|
begin
 | 
						|
  if FName = AValue then exit;
 | 
						|
 | 
						|
  if TBaseExceptions(GetOwner).Find(AValue) <> nil
 | 
						|
  then raise EDBGExceptions.Create('Duplicate name: ' + AValue);
 | 
						|
 | 
						|
  FName := AValue;
 | 
						|
  Changed;
 | 
						|
end;
 | 
						|
 | 
						|
{ =========================================================================== }
 | 
						|
{ TBaseExceptions }
 | 
						|
{ =========================================================================== }
 | 
						|
 | 
						|
function TBaseExceptions.Add(const AName: String): TBaseException;
 | 
						|
begin
 | 
						|
  Result := TBaseException(inherited Add);
 | 
						|
  Result.Name := AName;
 | 
						|
end;
 | 
						|
 | 
						|
constructor TBaseExceptions.Create(const AItemClass: TBaseExceptionClass);
 | 
						|
begin
 | 
						|
  inherited Create(AItemClass);
 | 
						|
  FIgnoreAll := False;
 | 
						|
end;
 | 
						|
 | 
						|
destructor TBaseExceptions.Destroy;
 | 
						|
begin
 | 
						|
  ClearExceptions;
 | 
						|
  inherited Destroy;
 | 
						|
end;
 | 
						|
 | 
						|
procedure TBaseExceptions.Reset;
 | 
						|
begin
 | 
						|
  ClearExceptions;
 | 
						|
  FIgnoreAll := False;
 | 
						|
end;
 | 
						|
 | 
						|
function TBaseExceptions.Find(const AName: String): TBaseException;
 | 
						|
var
 | 
						|
  n: Integer;
 | 
						|
  S: String;
 | 
						|
begin
 | 
						|
  S := UpperCase(AName);
 | 
						|
  for n := 0 to Count - 1 do
 | 
						|
  begin
 | 
						|
    Result := TBaseException(GetItem(n));
 | 
						|
    if UpperCase(Result.Name) = S
 | 
						|
    then Exit;
 | 
						|
  end;
 | 
						|
  Result := nil;
 | 
						|
end;
 | 
						|
 | 
						|
function TBaseExceptions.GetItem(const AIndex: Integer): TBaseException;
 | 
						|
begin
 | 
						|
  Result := TBaseException(inherited GetItem(AIndex));
 | 
						|
end;
 | 
						|
 | 
						|
procedure TBaseExceptions.SetItem(const AIndex: Integer; AValue: TBaseException);
 | 
						|
begin
 | 
						|
  inherited SetItem(AIndex, AValue);
 | 
						|
end;
 | 
						|
 | 
						|
procedure TBaseExceptions.ClearExceptions;
 | 
						|
begin
 | 
						|
  while Count>0 do
 | 
						|
    TBaseException(GetItem(Count-1)).Free;
 | 
						|
end;
 | 
						|
 | 
						|
procedure TBaseExceptions.SetIgnoreAll(const AValue: Boolean);
 | 
						|
begin
 | 
						|
  if FIgnoreAll = AValue then exit;
 | 
						|
  FIgnoreAll := AValue;
 | 
						|
  Changed;
 | 
						|
end;
 | 
						|
 | 
						|
procedure TBaseExceptions.AssignTo(Dest: TPersistent);
 | 
						|
begin
 | 
						|
  if Dest is TBaseExceptions
 | 
						|
  then begin
 | 
						|
    TBaseExceptions(Dest).IgnoreAll := IgnoreAll;
 | 
						|
  end
 | 
						|
  else inherited AssignTo(Dest);
 | 
						|
end;
 | 
						|
 | 
						|
{ TBaseDisassembler }
 | 
						|
 | 
						|
procedure TBaseDisassembler.IndexError(AIndex: Integer);
 | 
						|
begin
 | 
						|
  raise EInvalidOperation.CreateFmt('Index out of range (%d)', [AIndex]);
 | 
						|
end;
 | 
						|
 | 
						|
function TBaseDisassembler.GetEntryPtr(AIndex: Integer): PDisassemblerEntry;
 | 
						|
begin
 | 
						|
  if (AIndex < -FCountBefore)
 | 
						|
  or (AIndex >= FCountAfter) then IndexError(Aindex);
 | 
						|
 | 
						|
  Result := InternalGetEntryPtr(AIndex);
 | 
						|
end;
 | 
						|
 | 
						|
function TBaseDisassembler.GetEntry(AIndex: Integer): TDisassemblerEntry;
 | 
						|
begin
 | 
						|
  if (AIndex < -FCountBefore)
 | 
						|
  or (AIndex >= FCountAfter) then IndexError(Aindex);
 | 
						|
 | 
						|
  Result := InternalGetEntry(AIndex);
 | 
						|
end;
 | 
						|
 | 
						|
function TBaseDisassembler.InternalGetEntry(AIndex: Integer): TDisassemblerEntry;
 | 
						|
begin
 | 
						|
  Result.Addr := 0;
 | 
						|
  Result.Offset := 0;
 | 
						|
  Result.SrcFileLine := 0;
 | 
						|
  Result.SrcStatementIndex := 0;
 | 
						|
  Result.SrcStatementCount := 0;
 | 
						|
end;
 | 
						|
 | 
						|
function TBaseDisassembler.InternalGetEntryPtr(AIndex: Integer): PDisassemblerEntry;
 | 
						|
begin
 | 
						|
  Result := nil;
 | 
						|
end;
 | 
						|
 | 
						|
procedure TBaseDisassembler.DoChanged;
 | 
						|
begin
 | 
						|
  // nothing
 | 
						|
end;
 | 
						|
 | 
						|
procedure TBaseDisassembler.Changed;
 | 
						|
begin
 | 
						|
  if FChangedLockCount > 0
 | 
						|
  then begin
 | 
						|
    FIsChanged := True;
 | 
						|
    exit;
 | 
						|
  end;
 | 
						|
  FIsChanged := False;
 | 
						|
  DoChanged;
 | 
						|
end;
 | 
						|
 | 
						|
procedure TBaseDisassembler.LockChanged;
 | 
						|
begin
 | 
						|
  inc(FChangedLockCount);
 | 
						|
end;
 | 
						|
 | 
						|
procedure TBaseDisassembler.UnlockChanged;
 | 
						|
begin
 | 
						|
  dec(FChangedLockCount);
 | 
						|
  if FIsChanged and (FChangedLockCount = 0)
 | 
						|
  then Changed;
 | 
						|
end;
 | 
						|
 | 
						|
procedure TBaseDisassembler.InternalIncreaseCountBefore(ACount: Integer);
 | 
						|
begin
 | 
						|
  // increase count withou change notification
 | 
						|
  if ACount < FCountBefore
 | 
						|
  then begin
 | 
						|
    debugln(DBG_DISASSEMBLER, ['WARNING: TBaseDisassembler.InternalIncreaseCountBefore will decrease was ', FCountBefore , ' new=',ACount]);
 | 
						|
    SetCountBefore(ACount);
 | 
						|
  end
 | 
						|
  else FCountBefore := ACount;
 | 
						|
end;
 | 
						|
 | 
						|
procedure TBaseDisassembler.InternalIncreaseCountAfter(ACount: Integer);
 | 
						|
begin
 | 
						|
  // increase count withou change notification
 | 
						|
  if ACount < FCountAfter
 | 
						|
  then begin
 | 
						|
    debugln(DBG_DISASSEMBLER, ['WARNING: TBaseDisassembler.InternalIncreaseCountAfter will decrease was ', FCountAfter , ' new=',ACount]);
 | 
						|
    SetCountAfter(ACount)
 | 
						|
  end
 | 
						|
  else FCountAfter := ACount;
 | 
						|
end;
 | 
						|
 | 
						|
procedure TBaseDisassembler.SetCountBefore(ACount: Integer);
 | 
						|
begin
 | 
						|
  if FCountBefore = ACount
 | 
						|
  then exit;
 | 
						|
  FCountBefore := ACount;
 | 
						|
  Changed;
 | 
						|
end;
 | 
						|
 | 
						|
procedure TBaseDisassembler.SetCountAfter(ACount: Integer);
 | 
						|
begin
 | 
						|
  if FCountAfter = ACount
 | 
						|
  then exit;
 | 
						|
  FCountAfter := ACount;
 | 
						|
  Changed;
 | 
						|
end;
 | 
						|
 | 
						|
procedure TBaseDisassembler.SetBaseAddr(AnAddr: TDbgPtr);
 | 
						|
begin
 | 
						|
  if FBaseAddr = AnAddr
 | 
						|
  then exit;
 | 
						|
  FBaseAddr := AnAddr;
 | 
						|
  Changed;
 | 
						|
end;
 | 
						|
 | 
						|
constructor TBaseDisassembler.Create;
 | 
						|
begin
 | 
						|
  Clear;
 | 
						|
  FChangedLockCount := 0;
 | 
						|
end;
 | 
						|
 | 
						|
destructor TBaseDisassembler.Destroy;
 | 
						|
begin
 | 
						|
  inherited Destroy;
 | 
						|
  Clear;
 | 
						|
end;
 | 
						|
 | 
						|
procedure TBaseDisassembler.Clear;
 | 
						|
begin
 | 
						|
  FCountAfter := 0;
 | 
						|
  FCountBefore := 0;
 | 
						|
  FBaseAddr := 0;
 | 
						|
end;
 | 
						|
 | 
						|
function TBaseDisassembler.PrepareRange(AnAddr: TDbgPtr; ALinesBefore,
 | 
						|
  ALinesAfter: Integer): Boolean;
 | 
						|
begin
 | 
						|
  Result := False;
 | 
						|
end;
 | 
						|
 | 
						|
{ TDBGDisassemblerEntryRange }
 | 
						|
 | 
						|
function TDBGDisassemblerEntryRange.GetEntry(Index: Integer): TDisassemblerEntry;
 | 
						|
begin
 | 
						|
  if (Index < 0) or (Index >= FCount)
 | 
						|
  then raise Exception.Create('Illegal Index');
 | 
						|
  Result := FEntries[Index];
 | 
						|
end;
 | 
						|
 | 
						|
function TDBGDisassemblerEntryRange.GetCapacity: Integer;
 | 
						|
begin
 | 
						|
  Result := length(FEntries);
 | 
						|
end;
 | 
						|
 | 
						|
function TDBGDisassemblerEntryRange.GetEntryPtr(Index: Integer): PDisassemblerEntry;
 | 
						|
begin
 | 
						|
  if (Index < 0) or (Index >= FCount)
 | 
						|
  then raise Exception.Create('Illegal Index');
 | 
						|
  Result := @FEntries[Index];
 | 
						|
end;
 | 
						|
 | 
						|
procedure TDBGDisassemblerEntryRange.SetCapacity(const AValue: Integer);
 | 
						|
begin
 | 
						|
  SetLength(FEntries, AValue);
 | 
						|
  if FCount >= AValue
 | 
						|
  then FCount := AValue - 1;
 | 
						|
end;
 | 
						|
 | 
						|
procedure TDBGDisassemblerEntryRange.SetCount(const AValue: Integer);
 | 
						|
begin
 | 
						|
  if FCount = AValue then exit;
 | 
						|
  if AValue >= Capacity
 | 
						|
  then Capacity := AValue + Max(20, AValue div 4);
 | 
						|
 | 
						|
  FCount := AValue;
 | 
						|
end;
 | 
						|
 | 
						|
procedure TDBGDisassemblerEntryRange.Clear;
 | 
						|
begin
 | 
						|
  SetCapacity(0);
 | 
						|
  FCount := 0;
 | 
						|
end;
 | 
						|
 | 
						|
function TDBGDisassemblerEntryRange.Append(const AnEntryPtr: PDisassemblerEntry): Integer;
 | 
						|
begin
 | 
						|
  if FCount >= Capacity
 | 
						|
  then Capacity := FCount + Max(20,FCount div 4);
 | 
						|
 | 
						|
  FEntries[FCount] := AnEntryPtr^;
 | 
						|
  Result := FCount;
 | 
						|
  inc(FCount);
 | 
						|
end;
 | 
						|
 | 
						|
procedure TDBGDisassemblerEntryRange.Merge(const AnotherRange: TDBGDisassemblerEntryRange);
 | 
						|
var
 | 
						|
  i, j: Integer;
 | 
						|
  a: TDBGPtr;
 | 
						|
begin
 | 
						|
  if AnotherRange.RangeStartAddr < RangeStartAddr then
 | 
						|
  begin
 | 
						|
    // merge before
 | 
						|
    i := AnotherRange.Count - 1;
 | 
						|
    a := FirstAddr;
 | 
						|
    while (i >= 0) and (AnotherRange.EntriesPtr[i]^.Addr >= a)
 | 
						|
    do dec(i);
 | 
						|
    inc(i);
 | 
						|
    debugln(DBG_DISASSEMBLER, ['INFO: TDBGDisassemblerEntryRange.Merge: Merged to START:   Other=', dbgs(AnotherRange), '  To other index=', i, ' INTO self=', dbgs(self) ]);
 | 
						|
    if Capacity < Count + i
 | 
						|
    then Capacity := Count + i;
 | 
						|
    for j := Count-1 downto 0 do
 | 
						|
      FEntries[j+i] := FEntries[j];
 | 
						|
    for j := 0 to i - 1 do
 | 
						|
      FEntries[j] := AnotherRange.FEntries[j];
 | 
						|
    FCount := FCount + i;
 | 
						|
    FRangeStartAddr := AnotherRange.FRangeStartAddr;
 | 
						|
  end
 | 
						|
  else begin
 | 
						|
    // merge after
 | 
						|
    a:= LastAddr;
 | 
						|
    i := 0;
 | 
						|
    while (i < AnotherRange.Count) and (AnotherRange.EntriesPtr[i]^.Addr <= a)
 | 
						|
    do inc(i);
 | 
						|
    debugln(DBG_DISASSEMBLER, ['INFO: TDBGDisassemblerEntryRange.Merge to END:   Other=', dbgs(AnotherRange), '  From other index=', i, ' INTO self=', dbgs(self) ]);
 | 
						|
    if Capacity < Count + AnotherRange.Count - i
 | 
						|
    then Capacity := Count + AnotherRange.Count - i;
 | 
						|
    for j := 0 to AnotherRange.Count - i - 1 do
 | 
						|
      FEntries[Count + j] := AnotherRange.FEntries[i + j];
 | 
						|
    FCount := FCount + AnotherRange.Count - i;
 | 
						|
    FRangeEndAddr := AnotherRange.FRangeEndAddr;
 | 
						|
    FLastEntryEndAddr := AnotherRange.FLastEntryEndAddr;
 | 
						|
    if FRangeStartAddr = 0 then
 | 
						|
      FRangeStartAddr := AnotherRange.FRangeStartAddr;
 | 
						|
  end;
 | 
						|
  debugln(DBG_DISASSEMBLER, ['INFO: TDBGDisassemblerEntryRange.Merge AFTER MERGE: ', dbgs(self) ]);
 | 
						|
end;
 | 
						|
 | 
						|
function TDBGDisassemblerEntryRange.FirstAddr: TDbgPtr;
 | 
						|
begin
 | 
						|
  if FCount = 0
 | 
						|
  then exit(0);
 | 
						|
  Result := FEntries[0].Addr;
 | 
						|
end;
 | 
						|
 | 
						|
function TDBGDisassemblerEntryRange.LastAddr: TDbgPtr;
 | 
						|
begin
 | 
						|
  if FCount = 0
 | 
						|
  then exit(0);
 | 
						|
  Result := FEntries[FCount-1].Addr;
 | 
						|
end;
 | 
						|
 | 
						|
function TDBGDisassemblerEntryRange.ContainsAddr(const AnAddr: TDbgPtr;
 | 
						|
  IncludeNextAddr: Boolean = False): Boolean;
 | 
						|
begin
 | 
						|
  if IncludeNextAddr
 | 
						|
  then  Result := (AnAddr >= RangeStartAddr) and (AnAddr <= RangeEndAddr)
 | 
						|
  else  Result := (AnAddr >= RangeStartAddr) and (AnAddr < RangeEndAddr);
 | 
						|
end;
 | 
						|
 | 
						|
function TDBGDisassemblerEntryRange.IndexOfAddr(const AnAddr: TDbgPtr): Integer;
 | 
						|
begin
 | 
						|
  Result := FCount - 1;
 | 
						|
  while Result >= 0 do begin
 | 
						|
    if FEntries[Result].Addr = AnAddr
 | 
						|
    then exit;
 | 
						|
    dec(Result);
 | 
						|
  end;
 | 
						|
end;
 | 
						|
 | 
						|
function TDBGDisassemblerEntryRange.IndexOfAddrWithOffs(const AnAddr: TDbgPtr): Integer;
 | 
						|
var
 | 
						|
  O: Integer;
 | 
						|
begin
 | 
						|
  Result := IndexOfAddrWithOffs(AnAddr, O);
 | 
						|
end;
 | 
						|
 | 
						|
function TDBGDisassemblerEntryRange.IndexOfAddrWithOffs(const AnAddr: TDbgPtr; out
 | 
						|
  AOffs: Integer): Integer;
 | 
						|
begin
 | 
						|
  Result := FCount - 1;
 | 
						|
  while Result >= 0 do begin
 | 
						|
    if FEntries[Result].Addr <= AnAddr
 | 
						|
    then break;
 | 
						|
    dec(Result);
 | 
						|
  end;
 | 
						|
  If Result < 0
 | 
						|
  then AOffs := 0
 | 
						|
  else AOffs := AnAddr - FEntries[Result].Addr;
 | 
						|
end;
 | 
						|
 | 
						|
{ TDBGDisassemblerEntryMapIterator }
 | 
						|
 | 
						|
function TDBGDisassemblerEntryMapIterator.GetRangeForAddr(AnAddr: TDbgPtr;
 | 
						|
  IncludeNextAddr: Boolean): TDBGDisassemblerEntryRange;
 | 
						|
begin
 | 
						|
  Result := nil;
 | 
						|
  if not Locate(AnAddr)
 | 
						|
  then if not BOM
 | 
						|
  then Previous;
 | 
						|
 | 
						|
  if BOM
 | 
						|
  then exit;
 | 
						|
 | 
						|
  GetData(Result);
 | 
						|
  if not Result.ContainsAddr(AnAddr, IncludeNextAddr)
 | 
						|
  then Result := nil;
 | 
						|
end;
 | 
						|
 | 
						|
function TDBGDisassemblerEntryMapIterator.NextRange: TDBGDisassemblerEntryRange;
 | 
						|
begin
 | 
						|
  Result := nil;
 | 
						|
  if EOM
 | 
						|
  then exit;
 | 
						|
 | 
						|
  Next;
 | 
						|
  if not EOM
 | 
						|
  then GetData(Result);
 | 
						|
end;
 | 
						|
 | 
						|
function TDBGDisassemblerEntryMapIterator.PreviousRange: TDBGDisassemblerEntryRange;
 | 
						|
begin
 | 
						|
  Result := nil;
 | 
						|
  if BOM
 | 
						|
  then exit;
 | 
						|
 | 
						|
  Previous;
 | 
						|
  if not BOM
 | 
						|
  then GetData(Result);
 | 
						|
end;
 | 
						|
 | 
						|
{ TDBGDisassemblerEntryMap }
 | 
						|
 | 
						|
procedure TDBGDisassemblerEntryMap.ReleaseData(ADataPtr: Pointer);
 | 
						|
type
 | 
						|
  PDBGDisassemblerEntryRange = ^TDBGDisassemblerEntryRange;
 | 
						|
begin
 | 
						|
  if FFreeItemLock
 | 
						|
  then exit;
 | 
						|
  if Assigned(FOnDelete)
 | 
						|
  then FOnDelete(PDBGDisassemblerEntryRange(ADataPtr)^);
 | 
						|
  PDBGDisassemblerEntryRange(ADataPtr)^.Free;
 | 
						|
end;
 | 
						|
 | 
						|
constructor TDBGDisassemblerEntryMap.Create(AIdType: TMapIdType; ADataSize: Cardinal);
 | 
						|
begin
 | 
						|
  inherited;
 | 
						|
  FIterator := TDBGDisassemblerEntryMapIterator.Create(Self);
 | 
						|
end;
 | 
						|
 | 
						|
destructor TDBGDisassemblerEntryMap.Destroy;
 | 
						|
begin
 | 
						|
  FreeAndNil(FIterator);
 | 
						|
  inherited Destroy;
 | 
						|
end;
 | 
						|
 | 
						|
procedure TDBGDisassemblerEntryMap.AddRange(const ARange: TDBGDisassemblerEntryRange);
 | 
						|
var
 | 
						|
  MergeRng, MergeRng2: TDBGDisassemblerEntryRange;
 | 
						|
  OldId: TDBGPtr;
 | 
						|
begin
 | 
						|
  debugln(DBG_DISASSEMBLER, ['INFO: TDBGDisassemblerEntryMap.AddRange ', dbgs(ARange), ' to map with count=', Count ]);
 | 
						|
  if ARange.Count = 0 then begin
 | 
						|
    ARange.Free;
 | 
						|
    exit;
 | 
						|
  end;
 | 
						|
 | 
						|
  MergeRng := GetRangeForAddr(ARange.RangeStartAddr, True);
 | 
						|
  if MergeRng <> nil then begin
 | 
						|
    // merge to end ( ARange.RangeStartAddr >= MergeRng.RangeStartAddr )
 | 
						|
    // MergeRng keeps it's ID;
 | 
						|
    MergeRng.Merge(ARange);
 | 
						|
    if assigned(FOnMerge)
 | 
						|
    then FOnMerge(MergeRng, ARange);
 | 
						|
    ARange.Free;
 | 
						|
 | 
						|
    MergeRng2 := GetRangeForAddr(MergeRng.RangeEndAddr, True);
 | 
						|
    if (MergeRng2 <> nil) and (MergeRng2 <> MergeRng) then begin
 | 
						|
      // MergeRng is located before MergeRng2
 | 
						|
      // MergeRng2 merges to end of MergeRng ( No ID changes )
 | 
						|
      MergeRng.Merge(MergeRng2);
 | 
						|
      if assigned(FOnMerge)
 | 
						|
      then FOnMerge(MergeRng, MergeRng2);
 | 
						|
      Delete(MergeRng2.RangeStartAddr);
 | 
						|
    end;
 | 
						|
    exit;
 | 
						|
  end;
 | 
						|
 | 
						|
  MergeRng := GetRangeForAddr(ARange.RangeEndAddr, True);
 | 
						|
  if MergeRng <> nil then begin
 | 
						|
    // merge to start ( ARange.RangeEndAddr is in MergeRng )
 | 
						|
    if MergeRng.ContainsAddr(ARange.RangeStartAddr)
 | 
						|
    then begin
 | 
						|
      debugln(['ERROR: New Range is completely inside existing ', dbgs(MergeRng)]);
 | 
						|
      exit;
 | 
						|
    end;
 | 
						|
    // MergeRng changes ID
 | 
						|
    OldId := MergeRng.RangeStartAddr;
 | 
						|
    MergeRng.Merge(ARange);
 | 
						|
    if assigned(FOnMerge)
 | 
						|
    then FOnMerge(ARange, MergeRng);
 | 
						|
    FFreeItemLock := True; // prevent destruction of MergeRng
 | 
						|
    Delete(OldId);
 | 
						|
    FFreeItemLock := False;
 | 
						|
    Add(MergeRng.RangeStartAddr, MergeRng);
 | 
						|
    ARange.Free;
 | 
						|
    exit;
 | 
						|
  end;
 | 
						|
 | 
						|
  Add(ARange.RangeStartAddr, ARange);
 | 
						|
end;
 | 
						|
 | 
						|
function TDBGDisassemblerEntryMap.GetRangeForAddr(AnAddr: TDbgPtr;
 | 
						|
  IncludeNextAddr: Boolean = False): TDBGDisassemblerEntryRange;
 | 
						|
begin
 | 
						|
  Result := FIterator.GetRangeForAddr(AnAddr, IncludeNextAddr);
 | 
						|
end;
 | 
						|
 | 
						|
{ TDBGDisassembler }
 | 
						|
 | 
						|
procedure TDBGDisassembler.EntryRangesOnDelete(Sender: TObject);
 | 
						|
begin
 | 
						|
  if FCurrentRange <> Sender
 | 
						|
  then exit;
 | 
						|
  LockChanged;
 | 
						|
  FCurrentRange := nil;
 | 
						|
  SetBaseAddr(0);
 | 
						|
  SetCountBefore(0);
 | 
						|
  SetCountAfter(0);
 | 
						|
  UnlockChanged;
 | 
						|
end;
 | 
						|
 | 
						|
procedure TDBGDisassembler.EntryRangesOnMerge(MergeReceiver,
 | 
						|
  MergeGiver: TDBGDisassemblerEntryRange);
 | 
						|
var
 | 
						|
  i: LongInt;
 | 
						|
  lb, la: Integer;
 | 
						|
begin
 | 
						|
  // no need to call changed, will be done by whoever triggered this
 | 
						|
  if FCurrentRange = MergeGiver
 | 
						|
  then FCurrentRange := MergeReceiver;
 | 
						|
 | 
						|
  if FCurrentRange = MergeReceiver
 | 
						|
  then begin
 | 
						|
    i := FCurrentRange.IndexOfAddrWithOffs(BaseAddr);
 | 
						|
    if i >= 0
 | 
						|
    then begin
 | 
						|
      InternalIncreaseCountBefore(i);
 | 
						|
      InternalIncreaseCountAfter(FCurrentRange.Count - 1 - i);
 | 
						|
      exit;
 | 
						|
    end
 | 
						|
    else if FCurrentRange.ContainsAddr(BaseAddr)
 | 
						|
    then begin
 | 
						|
      debugln(DBG_DISASSEMBLER, ['WARNING: TDBGDisassembler.OnMerge: Address at odd offset ',BaseAddr, ' before=',CountBefore, ' after=', CountAfter]);
 | 
						|
      lb := CountBefore;
 | 
						|
      la := CountAfter;
 | 
						|
      if HandleRangeWithInvalidAddr(FCurrentRange, BaseAddr, lb, la)
 | 
						|
      then begin
 | 
						|
        InternalIncreaseCountBefore(lb);
 | 
						|
        InternalIncreaseCountAfter(la);
 | 
						|
        exit;
 | 
						|
      end;
 | 
						|
    end;
 | 
						|
 | 
						|
    LockChanged;
 | 
						|
    SetBaseAddr(0);
 | 
						|
    SetCountBefore(0);
 | 
						|
    SetCountAfter(0);
 | 
						|
    UnlockChanged;
 | 
						|
  end;
 | 
						|
end;
 | 
						|
 | 
						|
function TDBGDisassembler.FindRange(AnAddr: TDbgPtr; ALinesBefore,
 | 
						|
  ALinesAfter: Integer): Boolean;
 | 
						|
var
 | 
						|
  i: LongInt;
 | 
						|
  NewRange: TDBGDisassemblerEntryRange;
 | 
						|
begin
 | 
						|
  LockChanged;
 | 
						|
  try
 | 
						|
    Result := False;
 | 
						|
    NewRange := FEntryRanges.GetRangeForAddr(AnAddr);
 | 
						|
 | 
						|
    if (NewRange <> nil)
 | 
						|
    and ( (NewRange.RangeStartAddr > AnAddr) or (NewRange.RangeEndAddr < AnAddr) )
 | 
						|
    then
 | 
						|
      NewRange := nil;
 | 
						|
 | 
						|
    if NewRange = nil
 | 
						|
    then begin
 | 
						|
      debugln(DBG_DISASSEMBLER, ['INFO: TDBGDisassembler.FindRange: Address not found ', AnAddr, ' wanted-before=',ALinesBefore,' wanted-after=',ALinesAfter,' in map with count=', FEntryRanges.Count ]);
 | 
						|
      exit;
 | 
						|
    end;
 | 
						|
 | 
						|
    i := NewRange.IndexOfAddr(AnAddr);
 | 
						|
    if i < 0
 | 
						|
    then begin
 | 
						|
      // address at incorrect offset
 | 
						|
      Result := HandleRangeWithInvalidAddr(NewRange, AnAddr, ALinesBefore, ALinesAfter);
 | 
						|
      debugln(DBG_DISASSEMBLER, ['WARNING: TDBGDisassembler.FindRange: Address at odd offset ',AnAddr,'  Result=', dbgs(result), ' before=',CountBefore, ' after=', CountAfter, ' wanted-before=',ALinesBefore,' wanted-after=',ALinesAfter,' in map with count=', FEntryRanges.Count]);
 | 
						|
      if Result
 | 
						|
      then begin
 | 
						|
        FCurrentRange := NewRange;
 | 
						|
        SetBaseAddr(AnAddr);
 | 
						|
        SetCountBefore(ALinesBefore);
 | 
						|
        SetCountAfter(ALinesAfter);
 | 
						|
      end;
 | 
						|
      exit;
 | 
						|
    end;
 | 
						|
 | 
						|
    FCurrentRange := NewRange;
 | 
						|
    SetBaseAddr(AnAddr);
 | 
						|
    SetCountBefore(i);
 | 
						|
    SetCountAfter(NewRange.Count - 1 - i);
 | 
						|
    Result := (i >= ALinesBefore) and (CountAfter >= ALinesAfter);
 | 
						|
    debugln(DBG_DISASSEMBLER, ['INFO: TDBGDisassembler.FindRange: Address found ',AnAddr,' Result=', dbgs(result), ' before=',CountBefore, ' after=', CountAfter, ' wanted-before=',ALinesBefore,' wanted-after=',ALinesAfter,' in map with count=', FEntryRanges.Count]);
 | 
						|
  finally
 | 
						|
    UnlockChanged;
 | 
						|
  end;
 | 
						|
end;
 | 
						|
 | 
						|
procedure TDBGDisassembler.DoChanged;
 | 
						|
begin
 | 
						|
  inherited DoChanged;
 | 
						|
  if assigned(FOnChange)
 | 
						|
  then FOnChange(Self);
 | 
						|
end;
 | 
						|
 | 
						|
procedure TDBGDisassembler.Clear;
 | 
						|
begin
 | 
						|
  debugln(DBG_DISASSEMBLER, ['INFO: TDBGDisassembler.Clear:  map had count=', FEntryRanges.Count ]);
 | 
						|
  FCurrentRange := nil;
 | 
						|
  FEntryRanges.Clear;
 | 
						|
  inherited Clear;
 | 
						|
  Changed;
 | 
						|
end;
 | 
						|
 | 
						|
procedure TDBGDisassembler.DoStateChange(const AOldState: TDBGState);
 | 
						|
begin
 | 
						|
  if FDebugger.State = dsPause
 | 
						|
  then begin
 | 
						|
    Changed;
 | 
						|
  end
 | 
						|
  else begin
 | 
						|
    if (AOldState = dsPause) or (AOldState = dsNone) { Force clear on initialisation }
 | 
						|
    then Clear;
 | 
						|
  end;
 | 
						|
end;
 | 
						|
 | 
						|
function TDBGDisassembler.InternalGetEntry(AIndex: Integer): TDisassemblerEntry;
 | 
						|
begin
 | 
						|
  Result := FCurrentRange.Entries[AIndex + CountBefore];
 | 
						|
end;
 | 
						|
 | 
						|
function TDBGDisassembler.InternalGetEntryPtr(AIndex: Integer): PDisassemblerEntry;
 | 
						|
begin
 | 
						|
  Result := FCurrentRange.EntriesPtr[AIndex + CountBefore];
 | 
						|
end;
 | 
						|
 | 
						|
function TDBGDisassembler.PrepareEntries(AnAddr: TDbgPtr; ALinesBefore,
 | 
						|
  ALinesAfter: Integer): boolean;
 | 
						|
begin
 | 
						|
  Result := False;
 | 
						|
end;
 | 
						|
 | 
						|
function TDBGDisassembler.HandleRangeWithInvalidAddr(ARange: TDBGDisassemblerEntryRange;
 | 
						|
  AnAddr: TDbgPtr; var ALinesBefore, ALinesAfter: Integer): boolean;
 | 
						|
begin
 | 
						|
  Result := False;
 | 
						|
  if ARange <> nil then
 | 
						|
    FEntryRanges.Delete(ARange.RangeStartAddr);
 | 
						|
end;
 | 
						|
 | 
						|
constructor TDBGDisassembler.Create(const ADebugger: TDebuggerIntf);
 | 
						|
begin
 | 
						|
  FDebugger := ADebugger;
 | 
						|
  FEntryRanges := TDBGDisassemblerEntryMap.Create(itu8, SizeOf(TDBGDisassemblerEntryRange));
 | 
						|
  FEntryRanges.OnDelete   := @EntryRangesOnDelete;
 | 
						|
  FEntryRanges.OnMerge   := @EntryRangesOnMerge;
 | 
						|
  inherited Create;
 | 
						|
end;
 | 
						|
 | 
						|
destructor TDBGDisassembler.Destroy;
 | 
						|
begin
 | 
						|
  inherited Destroy;
 | 
						|
  FEntryRanges.OnDelete := nil;
 | 
						|
  Clear;
 | 
						|
  FreeAndNil(FEntryRanges);
 | 
						|
end;
 | 
						|
 | 
						|
function TDBGDisassembler.PrepareRange(AnAddr: TDbgPtr; ALinesBefore,
 | 
						|
  ALinesAfter: Integer): Boolean;
 | 
						|
begin
 | 
						|
  Result := False;
 | 
						|
  if (Debugger = nil) or (Debugger.State <> dsPause) or (AnAddr = 0)
 | 
						|
  then exit;
 | 
						|
  if (ALinesBefore < 0) or (ALinesAfter < 0)
 | 
						|
  then raise Exception.Create('invalid PrepareRange request');
 | 
						|
 | 
						|
  // Do not LockChange, if FindRange changes something, then notification must be send to syncronize counts on IDE-object
 | 
						|
  Result:= FindRange(AnAddr, ALinesBefore, ALinesAfter);
 | 
						|
  if result then debugln(DBG_DISASSEMBLER, ['INFO: TDBGDisassembler.PrepareRange  found existing data  Addr=', AnAddr,' before=', ALinesBefore, ' After=', ALinesAfter ]);
 | 
						|
  if Result
 | 
						|
  then exit;
 | 
						|
 | 
						|
  if result then debugln(DBG_DISASSEMBLER, ['INFO: TDBGDisassembler.PrepareRange  calling PrepareEntries Addr=', AnAddr,' before=', ALinesBefore, ' After=', ALinesAfter ]);
 | 
						|
  if PrepareEntries(AnAddr, ALinesBefore, ALinesAfter)
 | 
						|
  then Result:= FindRange(AnAddr, ALinesBefore, ALinesAfter);
 | 
						|
  if result then debugln(DBG_DISASSEMBLER, ['INFO: TDBGDisassembler.PrepareRange  found data AFTER PrepareEntries Addr=', AnAddr,' before=', ALinesBefore, ' After=', ALinesAfter ]);
 | 
						|
end;
 | 
						|
 | 
						|
(******************************************************************************)
 | 
						|
(******************************************************************************)
 | 
						|
(**                                                                          **)
 | 
						|
(**   D E B U G G E R                                                        **)
 | 
						|
(**                                                                          **)
 | 
						|
(******************************************************************************)
 | 
						|
(******************************************************************************)
 | 
						|
 | 
						|
{ TDebuggerProperties }
 | 
						|
 | 
						|
constructor TDebuggerProperties.Create;
 | 
						|
begin
 | 
						|
  //
 | 
						|
end;
 | 
						|
 | 
						|
procedure TDebuggerProperties.Assign(Source: TPersistent);
 | 
						|
begin
 | 
						|
  //
 | 
						|
end;
 | 
						|
 | 
						|
{ =========================================================================== }
 | 
						|
{ TDebuggerIntf }
 | 
						|
{ =========================================================================== }
 | 
						|
 | 
						|
class function TDebuggerIntf.Caption: String;
 | 
						|
begin
 | 
						|
  Result := 'No caption set';
 | 
						|
end;
 | 
						|
 | 
						|
function TDebuggerIntf.ChangeFileName: Boolean;
 | 
						|
begin
 | 
						|
  Result := True;
 | 
						|
end;
 | 
						|
 | 
						|
constructor TDebuggerIntf.Create(const AExternalDebugger: String);
 | 
						|
var
 | 
						|
  list: TStringList;
 | 
						|
  nr: TDebuggerNotifyReason;
 | 
						|
begin
 | 
						|
  inherited Create;
 | 
						|
  for nr := low(TDebuggerNotifyReason) to high(TDebuggerNotifyReason) do
 | 
						|
    FDestroyNotificationList[nr] := TMethodList.Create;
 | 
						|
  FOnState := nil;
 | 
						|
  FOnCurrent := nil;
 | 
						|
  FOnOutput := nil;
 | 
						|
  FOnDbgOutput := nil;
 | 
						|
  FState := dsNone;
 | 
						|
  FArguments := '';
 | 
						|
  FFilename := '';
 | 
						|
  FExternalDebugger := AExternalDebugger;
 | 
						|
 | 
						|
  list := TStringList.Create;
 | 
						|
  list.OnChange := @DebuggerEnvironmentChanged;
 | 
						|
  FDebuggerEnvironment := list;
 | 
						|
 | 
						|
  list := TStringList.Create;
 | 
						|
  list.OnChange := @EnvironmentChanged;
 | 
						|
  FEnvironment := list;
 | 
						|
  FCurEnvironment := TStringList.Create;
 | 
						|
  //FInternalUnitInfoProvider := TDebuggerUnitInfoProvider.Create;
 | 
						|
 | 
						|
  FBreakPoints := CreateBreakPoints;
 | 
						|
  FLocals := CreateLocals;
 | 
						|
  FLineInfo := CreateLineInfo;
 | 
						|
  FRegisters := CreateRegisters;
 | 
						|
  FCallStack := CreateCallStack;
 | 
						|
  FDisassembler := CreateDisassembler;
 | 
						|
  FWatches := CreateWatches;
 | 
						|
  FThreads := CreateThreads;
 | 
						|
  FSignals := CreateSignals;
 | 
						|
  FExitCode := 0;
 | 
						|
end;
 | 
						|
 | 
						|
function TDebuggerIntf.CreateBreakPoints: TDBGBreakPoints;
 | 
						|
begin
 | 
						|
  Result := TDBGBreakPoints.Create(Self, TDBGBreakPoint);
 | 
						|
end;
 | 
						|
 | 
						|
function TDebuggerIntf.CreateCallStack: TCallStackSupplier;
 | 
						|
begin
 | 
						|
  Result := TCallStackSupplier.Create(Self);
 | 
						|
end;
 | 
						|
 | 
						|
function TDebuggerIntf.CreateDisassembler: TDBGDisassembler;
 | 
						|
begin
 | 
						|
  Result := TDBGDisassembler.Create(Self);
 | 
						|
end;
 | 
						|
 | 
						|
function TDebuggerIntf.CreateLocals: TLocalsSupplier;
 | 
						|
begin
 | 
						|
  Result := TLocalsSupplier.Create(Self);
 | 
						|
end;
 | 
						|
 | 
						|
function TDebuggerIntf.CreateLineInfo: TDBGLineInfo;
 | 
						|
begin
 | 
						|
  Result := TDBGLineInfo.Create(Self);
 | 
						|
end;
 | 
						|
 | 
						|
class function TDebuggerIntf.CreateProperties: TDebuggerProperties;
 | 
						|
begin
 | 
						|
  Result := TDebuggerProperties.Create;
 | 
						|
end;
 | 
						|
 | 
						|
function TDebuggerIntf.CreateRegisters: TRegisterSupplier;
 | 
						|
begin
 | 
						|
  Result := TRegisterSupplier.Create(Self);
 | 
						|
end;
 | 
						|
 | 
						|
function TDebuggerIntf.CreateSignals: TDBGSignals;
 | 
						|
begin
 | 
						|
  Result := TDBGSignals.Create(Self, TDBGSignal);
 | 
						|
end;
 | 
						|
 | 
						|
function TDebuggerIntf.CreateWatches: TWatchesSupplier;
 | 
						|
begin
 | 
						|
  Result := TWatchesSupplier.Create(Self);
 | 
						|
end;
 | 
						|
 | 
						|
function TDebuggerIntf.CreateThreads: TThreadsSupplier;
 | 
						|
begin
 | 
						|
  Result := TThreadsSupplier.Create(Self);
 | 
						|
end;
 | 
						|
 | 
						|
procedure TDebuggerIntf.DebuggerEnvironmentChanged (Sender: TObject );
 | 
						|
begin
 | 
						|
end;
 | 
						|
 | 
						|
destructor TDebuggerIntf.Destroy;
 | 
						|
var
 | 
						|
  nr: TDebuggerNotifyReason;
 | 
						|
begin
 | 
						|
  FDestroyNotificationList[dnrDestroy].CallNotifyEvents(Self);
 | 
						|
  for nr := low(TDebuggerNotifyReason) to high(TDebuggerNotifyReason) do
 | 
						|
    FreeAndNil(FDestroyNotificationList[nr]);
 | 
						|
  // don't call events
 | 
						|
  FOnState := nil;
 | 
						|
  FOnCurrent := nil;
 | 
						|
  FOnOutput := nil;
 | 
						|
  FOnDbgOutput := nil;
 | 
						|
 | 
						|
  if FState <> dsNone
 | 
						|
  then Done;
 | 
						|
 | 
						|
  FBreakPoints.Debugger := nil;
 | 
						|
  FLocals.Debugger := nil;
 | 
						|
  FLineInfo.Debugger := nil;
 | 
						|
  FRegisters.Debugger := nil;
 | 
						|
  FCallStack.Debugger := nil;
 | 
						|
  FDisassembler.Debugger := nil;
 | 
						|
  FWatches.Debugger := nil;
 | 
						|
  FThreads.Debugger := nil;
 | 
						|
 | 
						|
  //FreeAndNil(FInternalUnitInfoProvider);
 | 
						|
  FreeAndNil(FBreakPoints);
 | 
						|
  FreeAndNil(FLocals);
 | 
						|
  FreeAndNil(FLineInfo);
 | 
						|
  FreeAndNil(FRegisters);
 | 
						|
  FreeAndNil(FCallStack);
 | 
						|
  FreeAndNil(FDisassembler);
 | 
						|
  FreeAndNil(FWatches);
 | 
						|
  FreeAndNil(FThreads);
 | 
						|
  FreeAndNil(FDebuggerEnvironment);
 | 
						|
  FreeAndNil(FEnvironment);
 | 
						|
  FreeAndNil(FCurEnvironment);
 | 
						|
  FreeAndNil(FSignals);
 | 
						|
  inherited;
 | 
						|
end;
 | 
						|
 | 
						|
function TDebuggerIntf.Disassemble(AAddr: TDbgPtr; ABackward: Boolean; out ANextAddr: TDbgPtr; out ADump, AStatement, AFile: String; out ALine: Integer): Boolean;
 | 
						|
begin
 | 
						|
  Result := ReqCmd(dcDisassemble, [AAddr, ABackward, @ANextAddr, @ADump, @AStatement, @AFile, @ALine]);
 | 
						|
end;
 | 
						|
 | 
						|
function TDebuggerIntf.GetLocation: TDBGLocationRec;
 | 
						|
begin
 | 
						|
  Result.Address := 0;
 | 
						|
  Result.SrcLine := 0;
 | 
						|
end;
 | 
						|
 | 
						|
procedure TDebuggerIntf.LockCommandProcessing;
 | 
						|
begin
 | 
						|
  // nothing
 | 
						|
end;
 | 
						|
 | 
						|
procedure TDebuggerIntf.UnLockCommandProcessing;
 | 
						|
begin
 | 
						|
  // nothing
 | 
						|
end;
 | 
						|
 | 
						|
function TDebuggerIntf.NeedReset: Boolean;
 | 
						|
begin
 | 
						|
  Result := False;
 | 
						|
end;
 | 
						|
 | 
						|
procedure TDebuggerIntf.AddNotifyEvent(AReason: TDebuggerNotifyReason; AnEvent: TNotifyEvent);
 | 
						|
begin
 | 
						|
  FDestroyNotificationList[AReason].Add(TMethod(AnEvent));
 | 
						|
end;
 | 
						|
 | 
						|
procedure TDebuggerIntf.RemoveNotifyEvent(AReason: TDebuggerNotifyReason; AnEvent: TNotifyEvent);
 | 
						|
begin
 | 
						|
  FDestroyNotificationList[AReason].Remove(TMethod(AnEvent));
 | 
						|
end;
 | 
						|
 | 
						|
procedure TDebuggerIntf.Done;
 | 
						|
begin
 | 
						|
  SetState(dsNone);
 | 
						|
  FEnvironment.Clear;
 | 
						|
  FCurEnvironment.Clear;
 | 
						|
end;
 | 
						|
 | 
						|
procedure TDebuggerIntf.Release;
 | 
						|
begin
 | 
						|
  if Self <> nil
 | 
						|
  then Self.DoRelease;
 | 
						|
end;
 | 
						|
 | 
						|
procedure TDebuggerIntf.DoCurrent(const ALocation: TDBGLocationRec);
 | 
						|
begin
 | 
						|
  DebugLnEnter(DBG_EVENTS, ['DebugEvent: Enter >> DoCurrent (Location)  >>  State=', dbgs(FState)]);
 | 
						|
  if Assigned(FOnCurrent) then FOnCurrent(Self, ALocation);
 | 
						|
  DebugLnExit(DBG_EVENTS, ['DebugEvent: Exit  << DoCurrent (Location)  <<']);
 | 
						|
end;
 | 
						|
 | 
						|
procedure TDebuggerIntf.DoDbgOutput(const AText: String);
 | 
						|
begin
 | 
						|
  // WriteLN(' [TDebuggerIntf] ', AText);
 | 
						|
  if Assigned(FOnDbgOutput) then FOnDbgOutput(Self, AText);
 | 
						|
end;
 | 
						|
 | 
						|
procedure TDebuggerIntf.DoDbgEvent(const ACategory: TDBGEventCategory; const AEventType: TDBGEventType; const AText: String);
 | 
						|
begin
 | 
						|
  DebugLnEnter(DBG_EVENTS, ['DebugEvent: Enter >> DoDbgEvent >>  State=', dbgs(FState), ' Category=', dbgs(ACategory)]);
 | 
						|
  if Assigned(FOnDbgEvent) then FOnDbgEvent(Self, ACategory, AEventType, AText);
 | 
						|
  DebugLnExit(DBG_EVENTS, ['DebugEvent: Exit  << DoDbgEvent <<']);
 | 
						|
end;
 | 
						|
 | 
						|
procedure TDebuggerIntf.DoException(const AExceptionType: TDBGExceptionType;
 | 
						|
  const AExceptionClass: String; const AExceptionLocation: TDBGLocationRec; const AExceptionText: String; out AContinue: Boolean);
 | 
						|
begin
 | 
						|
  DebugLnEnter(DBG_EVENTS, ['DebugEvent: Enter >> DoException >>  State=', dbgs(FState)]);
 | 
						|
  if AExceptionType = deInternal then
 | 
						|
    DoDbgEvent(ecDebugger, etExceptionRaised,
 | 
						|
               Format('Exception class "%s" at $%.' + IntToStr(TargetWidth div 4) + 'x with message "%s"',
 | 
						|
                      [AExceptionClass, AExceptionLocation.Address, AExceptionText]));
 | 
						|
  if Assigned(FOnException) then
 | 
						|
    FOnException(Self, AExceptionType, AExceptionClass, AExceptionLocation, AExceptionText, AContinue)
 | 
						|
  else
 | 
						|
    AContinue := True;
 | 
						|
  DebugLnExit(DBG_EVENTS, ['DebugEvent: Exit  << DoException <<']);
 | 
						|
end;
 | 
						|
 | 
						|
procedure TDebuggerIntf.DoOutput(const AText: String);
 | 
						|
begin
 | 
						|
  if Assigned(FOnOutput) then FOnOutput(Self, AText);
 | 
						|
end;
 | 
						|
 | 
						|
procedure TDebuggerIntf.DoBreakpointHit(const ABreakPoint: TBaseBreakPoint; var ACanContinue: Boolean);
 | 
						|
begin
 | 
						|
  DebugLnEnter(DBG_EVENTS, ['DebugEvent: Enter >> DoBreakpointHit <<  State=', dbgs(FState)]);
 | 
						|
  if Assigned(FOnBreakpointHit)
 | 
						|
  then FOnBreakpointHit(Self, ABreakPoint, ACanContinue);
 | 
						|
  DebugLnExit(DBG_EVENTS, ['DebugEvent: Exit  >> DoBreakpointHit <<']);
 | 
						|
end;
 | 
						|
 | 
						|
procedure TDebuggerIntf.DoBeforeState(const OldState: TDBGState);
 | 
						|
begin
 | 
						|
  DebugLnEnter(DBG_STATE_EVENT, ['DebugEvent: Enter >> DoBeforeState <<  State=', dbgs(FState)]);
 | 
						|
  if Assigned(FOnBeforeState) then FOnBeforeState(Self, OldState);
 | 
						|
  DebugLnExit(DBG_STATE_EVENT, ['DebugEvent: Exit  >> DoBeforeState <<']);
 | 
						|
end;
 | 
						|
 | 
						|
procedure TDebuggerIntf.DoState(const OldState: TDBGState);
 | 
						|
begin
 | 
						|
  DebugLnEnter(DBG_STATE_EVENT, ['DebugEvent: Enter >> DoState <<  State=', dbgs(FState)]);
 | 
						|
  if Assigned(FOnState) then FOnState(Self, OldState);
 | 
						|
  DebugLnExit(DBG_STATE_EVENT, ['DebugEvent: Exit  >> DoState <<']);
 | 
						|
end;
 | 
						|
 | 
						|
procedure TDebuggerIntf.EnvironmentChanged(Sender: TObject);
 | 
						|
var
 | 
						|
  n, idx: integer;
 | 
						|
  S: String;
 | 
						|
  Env: TStringList;
 | 
						|
begin
 | 
						|
  // Createe local copy
 | 
						|
  if FState <> dsNone then
 | 
						|
  begin
 | 
						|
    Env := TStringList.Create;
 | 
						|
    try
 | 
						|
      Env.Assign(Environment);
 | 
						|
 | 
						|
      // Check for nonexisting and unchanged vars
 | 
						|
      for n := 0 to FCurEnvironment.Count - 1 do
 | 
						|
      begin
 | 
						|
        S := FCurEnvironment[n];
 | 
						|
        idx := Env.IndexOfName(GetPart([], ['='], S, False, False));
 | 
						|
        if idx = -1
 | 
						|
        then ReqCmd(dcEnvironment, [S, False])
 | 
						|
        else begin
 | 
						|
          if Env[idx] = S
 | 
						|
          then Env.Delete(idx);
 | 
						|
        end;
 | 
						|
      end;
 | 
						|
 | 
						|
      // Set the remaining
 | 
						|
      for n := 0 to Env.Count - 1 do
 | 
						|
      begin
 | 
						|
        S := Env[n];
 | 
						|
        //Skip functions etc.
 | 
						|
        if Pos('=()', S) <> 0 then Continue;
 | 
						|
        ReqCmd(dcEnvironment, [S, True]);
 | 
						|
      end;
 | 
						|
    finally
 | 
						|
      Env.Free;
 | 
						|
    end;
 | 
						|
  end;
 | 
						|
  FCurEnvironment.Assign(FEnvironment);
 | 
						|
end;
 | 
						|
 | 
						|
//function TDebuggerIntf.GetUnitInfoProvider: TDebuggerUnitInfoProvider;
 | 
						|
//begin
 | 
						|
//  Result := FUnitInfoProvider;
 | 
						|
//  if Result = nil then
 | 
						|
//    Result := FInternalUnitInfoProvider;
 | 
						|
//end;
 | 
						|
 | 
						|
function TDebuggerIntf.GetIsIdle: Boolean;
 | 
						|
begin
 | 
						|
  Result := False;
 | 
						|
end;
 | 
						|
 | 
						|
function TDebuggerIntf.Evaluate(const AExpression: String; var AResult: String;
 | 
						|
  var ATypeInfo: TDBGType; EvalFlags: TDBGEvaluateFlags = []): Boolean;
 | 
						|
begin
 | 
						|
  FreeAndNIL(ATypeInfo);
 | 
						|
  Result := ReqCmd(dcEvaluate, [AExpression, @AResult, @ATypeInfo, Integer(EvalFlags)]);
 | 
						|
end;
 | 
						|
 | 
						|
function TDebuggerIntf.GetProcessList(AList: TRunningProcessInfoList): boolean;
 | 
						|
begin
 | 
						|
  result := false;
 | 
						|
end;
 | 
						|
 | 
						|
class function TDebuggerIntf.ExePaths: String;
 | 
						|
begin
 | 
						|
  Result := '';
 | 
						|
end;
 | 
						|
 | 
						|
class function TDebuggerIntf.HasExePath: boolean;
 | 
						|
begin
 | 
						|
  Result := NeedsExePath;
 | 
						|
end;
 | 
						|
 | 
						|
class function TDebuggerIntf.NeedsExePath: boolean;
 | 
						|
begin
 | 
						|
  Result := true; // most debugger are external and have an exe path
 | 
						|
end;
 | 
						|
 | 
						|
class function TDebuggerIntf.CanExternalDebugSymbolsFile: boolean;
 | 
						|
begin
 | 
						|
  Result := false;
 | 
						|
end;
 | 
						|
 | 
						|
function TDebuggerIntf.GetCommands: TDBGCommands;
 | 
						|
begin
 | 
						|
  Result := COMMANDMAP[State] * GetSupportedCommands;
 | 
						|
end;
 | 
						|
 | 
						|
class function TDebuggerIntf.GetProperties: TDebuggerProperties;
 | 
						|
var
 | 
						|
  idx: Integer;
 | 
						|
begin
 | 
						|
  if MDebuggerPropertiesList = nil
 | 
						|
  then MDebuggerPropertiesList := TStringList.Create;
 | 
						|
  idx := MDebuggerPropertiesList.IndexOf(ClassName);
 | 
						|
  if idx = -1
 | 
						|
  then begin
 | 
						|
    Result := CreateProperties;
 | 
						|
    MDebuggerPropertiesList.AddObject(ClassName, Result)
 | 
						|
  end
 | 
						|
  else begin
 | 
						|
    Result := TDebuggerProperties(MDebuggerPropertiesList.Objects[idx]);
 | 
						|
  end;
 | 
						|
end;
 | 
						|
 | 
						|
function TDebuggerIntf.GetState: TDBGState;
 | 
						|
begin
 | 
						|
  Result := FState;
 | 
						|
end;
 | 
						|
 | 
						|
function TDebuggerIntf.GetSupportedCommands: TDBGCommands;
 | 
						|
begin
 | 
						|
  Result := [];
 | 
						|
end;
 | 
						|
 | 
						|
function TDebuggerIntf.GetTargetWidth: Byte;
 | 
						|
begin
 | 
						|
  Result := SizeOf(PtrInt)*8;
 | 
						|
end;
 | 
						|
 | 
						|
function TDebuggerIntf.GetWaiting: Boolean;
 | 
						|
begin
 | 
						|
  Result := False;
 | 
						|
end;
 | 
						|
 | 
						|
procedure TDebuggerIntf.Init;
 | 
						|
begin
 | 
						|
  FExitCode := 0;
 | 
						|
  FErrorStateMessage := '';
 | 
						|
  FErrorStateInfo := '';
 | 
						|
  SetState(dsIdle);
 | 
						|
end;
 | 
						|
 | 
						|
procedure TDebuggerIntf.JumpTo(const ASource: String; const ALine: Integer);
 | 
						|
begin
 | 
						|
  ReqCmd(dcJumpTo, [ASource, ALine]);
 | 
						|
end;
 | 
						|
 | 
						|
procedure TDebuggerIntf.Attach(AProcessID: String);
 | 
						|
begin
 | 
						|
  if State = dsIdle then SetState(dsStop);  // Needed, because no filename was set
 | 
						|
  ReqCmd(dcAttach, [AProcessID]);
 | 
						|
end;
 | 
						|
 | 
						|
procedure TDebuggerIntf.Detach;
 | 
						|
begin
 | 
						|
  ReqCmd(dcDetach, []);
 | 
						|
end;
 | 
						|
 | 
						|
procedure TDebuggerIntf.SendConsoleInput(AText: String);
 | 
						|
begin
 | 
						|
  ReqCmd(dcSendConsoleInput, [AText]);
 | 
						|
end;
 | 
						|
 | 
						|
function TDebuggerIntf.Modify(const AExpression, AValue: String): Boolean;
 | 
						|
begin
 | 
						|
  Result := ReqCmd(dcModify, [AExpression, AValue]);
 | 
						|
end;
 | 
						|
 | 
						|
procedure TDebuggerIntf.Pause;
 | 
						|
begin
 | 
						|
  ReqCmd(dcPause, []);
 | 
						|
end;
 | 
						|
 | 
						|
function TDebuggerIntf.ReqCmd(const ACommand: TDBGCommand;
 | 
						|
  const AParams: array of const): Boolean;
 | 
						|
begin
 | 
						|
  if FState = dsNone then Init;
 | 
						|
  if ACommand in Commands
 | 
						|
  then begin
 | 
						|
    Result := RequestCommand(ACommand, AParams);
 | 
						|
    if not Result then begin
 | 
						|
      DebugLn(DBG_WARNINGS, 'TDebuggerIntf.ReqCmd failed: ',dbgs(ACommand));
 | 
						|
    end;
 | 
						|
  end
 | 
						|
  else begin
 | 
						|
    DebugLn(DBG_WARNINGS, 'TDebuggerIntf.ReqCmd Command not supported: ',
 | 
						|
            dbgs(ACommand),' ClassName=',ClassName);
 | 
						|
    Result := False;
 | 
						|
  end;
 | 
						|
end;
 | 
						|
 | 
						|
procedure TDebuggerIntf.Run;
 | 
						|
begin
 | 
						|
  ReqCmd(dcRun, []);
 | 
						|
end;
 | 
						|
 | 
						|
procedure TDebuggerIntf.RunTo(const ASource: String; const ALine: Integer);
 | 
						|
begin
 | 
						|
  ReqCmd(dcRunTo, [ASource, ALine]);
 | 
						|
end;
 | 
						|
 | 
						|
procedure TDebuggerIntf.SetDebuggerEnvironment (const AValue: TStrings );
 | 
						|
begin
 | 
						|
  FDebuggerEnvironment.Assign(AValue);
 | 
						|
end;
 | 
						|
 | 
						|
procedure TDebuggerIntf.SetEnvironment(const AValue: TStrings);
 | 
						|
begin
 | 
						|
  FEnvironment.Assign(AValue);
 | 
						|
end;
 | 
						|
 | 
						|
procedure TDebuggerIntf.SetExitCode(const AValue: Integer);
 | 
						|
begin
 | 
						|
  FExitCode := AValue;
 | 
						|
end;
 | 
						|
 | 
						|
procedure TDebuggerIntf.SetFileName(const AValue: String);
 | 
						|
begin
 | 
						|
  if FFileName <> AValue
 | 
						|
  then begin
 | 
						|
    DebugLn(DBG_VERBOSE, '[TDebuggerIntf.SetFileName] "', AValue, '"');
 | 
						|
    if FState in [dsRun, dsPause]
 | 
						|
    then begin
 | 
						|
      Stop;
 | 
						|
      // check if stopped
 | 
						|
      if FState <> dsStop
 | 
						|
      then SetState(dsError);
 | 
						|
    end;
 | 
						|
 | 
						|
    if FState = dsStop
 | 
						|
    then begin
 | 
						|
      // Reset state
 | 
						|
      FFileName := '';
 | 
						|
      ResetStateToIdle;
 | 
						|
      ChangeFileName;
 | 
						|
    end;
 | 
						|
 | 
						|
    FFileName := AValue;
 | 
						|
    // TODO: Why?
 | 
						|
    if  (FFilename <> '') and (FState = dsIdle) and ChangeFileName
 | 
						|
    then SetState(dsStop);
 | 
						|
  end
 | 
						|
  else
 | 
						|
  if FileName = '' then
 | 
						|
    ResetStateToIdle;
 | 
						|
end;
 | 
						|
 | 
						|
procedure TDebuggerIntf.ResetStateToIdle;
 | 
						|
begin
 | 
						|
  SetState(dsIdle);
 | 
						|
end;
 | 
						|
 | 
						|
class procedure TDebuggerIntf.SetProperties(const AProperties: TDebuggerProperties);
 | 
						|
var
 | 
						|
  Props: TDebuggerProperties;
 | 
						|
begin
 | 
						|
  if AProperties = nil then Exit;
 | 
						|
  Props := GetProperties;
 | 
						|
  if Props = AProperties then Exit;
 | 
						|
 | 
						|
  if Props = nil then Exit; // they weren't created ?
 | 
						|
  Props.Assign(AProperties);
 | 
						|
end;
 | 
						|
 | 
						|
class function TDebuggerIntf.RequiresLocalExecutable: Boolean;
 | 
						|
begin
 | 
						|
  Result := True;
 | 
						|
end;
 | 
						|
 | 
						|
procedure TDebuggerIntf.SetState(const AValue: TDBGState);
 | 
						|
var
 | 
						|
  OldState: TDBGState;
 | 
						|
begin
 | 
						|
  // dsDestroying is final, do not unset
 | 
						|
  if FState = dsDestroying
 | 
						|
  then exit;
 | 
						|
 | 
						|
  // dsDestroying must be silent. The ide believes the debugger is gone already
 | 
						|
  if AValue = dsDestroying
 | 
						|
  then begin
 | 
						|
    FState := AValue;
 | 
						|
    exit;
 | 
						|
  end;
 | 
						|
 | 
						|
  if AValue <> FState
 | 
						|
  then begin
 | 
						|
    DebugLnEnter(DBG_STATE, ['DebuggerState: Setting to ', dbgs(AValue),', from ', dbgs(FState)]);
 | 
						|
    OldState := FState;
 | 
						|
    FState := AValue;
 | 
						|
    LockCommandProcessing;
 | 
						|
    try
 | 
						|
      DoBeforeState(OldState);
 | 
						|
      try
 | 
						|
        FThreads.DoStateChange(OldState);
 | 
						|
        FCallStack.DoStateChange(OldState);
 | 
						|
        FBreakpoints.DoStateChange(OldState);
 | 
						|
        FLocals.DoStateChange(OldState);
 | 
						|
        FLineInfo.DoStateChange(OldState);
 | 
						|
        FRegisters.DoStateChange(OldState);
 | 
						|
        FDisassembler.DoStateChange(OldState);
 | 
						|
        FWatches.DoStateChange(OldState);
 | 
						|
      finally
 | 
						|
        DoState(OldState);
 | 
						|
      end;
 | 
						|
    finally
 | 
						|
      UnLockCommandProcessing;
 | 
						|
      DebugLnExit(DBG_STATE, ['DebuggerState: Finished ', dbgs(AValue)]);
 | 
						|
    end;
 | 
						|
  end;
 | 
						|
end;
 | 
						|
 | 
						|
procedure TDebuggerIntf.SetErrorState(const AMsg: String; const AInfo: String = '');
 | 
						|
begin
 | 
						|
  if FErrorStateMessage = ''
 | 
						|
  then FErrorStateMessage := AMsg;
 | 
						|
  if FErrorStateInfo = ''
 | 
						|
  then FErrorStateInfo := AInfo;
 | 
						|
  SetState(dsError);
 | 
						|
end;
 | 
						|
 | 
						|
procedure TDebuggerIntf.DoRelease;
 | 
						|
begin
 | 
						|
  Self.Free;
 | 
						|
end;
 | 
						|
 | 
						|
procedure TDebuggerIntf.StepInto;
 | 
						|
begin
 | 
						|
  if ReqCmd(dcStepInto, []) then exit;
 | 
						|
  DebugLn(DBG_WARNINGS, 'TDebuggerIntf.StepInto Class=',ClassName,' failed.');
 | 
						|
end;
 | 
						|
 | 
						|
procedure TDebuggerIntf.StepOverInstr;
 | 
						|
begin
 | 
						|
  if ReqCmd(dcStepOverInstr, []) then exit;
 | 
						|
  DebugLn(DBG_WARNINGS, 'TDebuggerIntf.StepOverInstr Class=',ClassName,' failed.');
 | 
						|
end;
 | 
						|
 | 
						|
procedure TDebuggerIntf.StepIntoInstr;
 | 
						|
begin
 | 
						|
  if ReqCmd(dcStepIntoInstr, []) then exit;
 | 
						|
  DebugLn(DBG_WARNINGS, 'TDebuggerIntf.StepIntoInstr Class=',ClassName,' failed.');
 | 
						|
end;
 | 
						|
 | 
						|
procedure TDebuggerIntf.StepOut;
 | 
						|
begin
 | 
						|
  if ReqCmd(dcStepOut, []) then exit;
 | 
						|
  DebugLn(DBG_WARNINGS, 'TDebuggerIntf.StepOut Class=', ClassName, ' failed.');
 | 
						|
end;
 | 
						|
 | 
						|
procedure TDebuggerIntf.StepOver;
 | 
						|
begin
 | 
						|
  if ReqCmd(dcStepOver, []) then exit;
 | 
						|
  DebugLn(DBG_WARNINGS, 'TDebuggerIntf.StepOver Class=',ClassName,' failed.');
 | 
						|
end;
 | 
						|
 | 
						|
procedure TDebuggerIntf.Stop;
 | 
						|
begin
 | 
						|
  if ReqCmd(dcStop,[]) then exit;
 | 
						|
  DebugLn(DBG_WARNINGS, 'TDebuggerIntf.Stop Class=',ClassName,' failed.');
 | 
						|
end;
 | 
						|
 | 
						|
function TBaseDebugManagerIntf.DebuggerCount: Integer;
 | 
						|
begin
 | 
						|
  Result := MDebuggerClasses.Count;
 | 
						|
end;
 | 
						|
 | 
						|
function TBaseDebugManagerIntf.FindDebuggerClass(const AString: String): TDebuggerClass;
 | 
						|
var
 | 
						|
  idx: Integer;
 | 
						|
begin
 | 
						|
  idx := MDebuggerClasses.IndexOf(AString);
 | 
						|
  if idx = -1
 | 
						|
  then Result := nil
 | 
						|
  else Result := TDebuggerClass(MDebuggerClasses.Objects[idx]);
 | 
						|
end;
 | 
						|
 | 
						|
function TBaseDebugManagerIntf.GetDebuggerClass(const AIndex: Integer): TDebuggerClass;
 | 
						|
begin
 | 
						|
  Result := TDebuggerClass(MDebuggerClasses.Objects[AIndex]);
 | 
						|
end;
 | 
						|
 | 
						|
 | 
						|
initialization
 | 
						|
  MDebuggerPropertiesList := nil;
 | 
						|
  {$IFDEF DBG_STATE}  {$DEFINE DBG_STATE_EVENT} {$ENDIF}
 | 
						|
  {$IFDEF DBG_EVENTS} {$DEFINE DBG_STATE_EVENT} {$ENDIF}
 | 
						|
  DBG_VERBOSE := DebugLogger.FindOrRegisterLogGroup('DBG_VERBOSE' {$IFDEF DBG_VERBOSE} , True {$ENDIF} );
 | 
						|
  DBG_WARNINGS := DebugLogger.FindOrRegisterLogGroup('DBG_WARNINGS' {$IFDEF DBG_WARNINGS} , True {$ENDIF} );
 | 
						|
  DBG_STATE       := DebugLogger.FindOrRegisterLogGroup('DBG_STATE' {$IFDEF DBG_STATE} , True {$ENDIF} );
 | 
						|
  DBG_EVENTS      := DebugLogger.FindOrRegisterLogGroup('DBG_EVENTS' {$IFDEF DBG_EVENTS} , True {$ENDIF} );
 | 
						|
  DBG_STATE_EVENT := DebugLogger.FindOrRegisterLogGroup('DBG_STATE_EVENT' {$IFDEF DBG_STATE_EVENT} , True {$ENDIF} );
 | 
						|
  DBG_DATA_MONITORS := DebugLogger.FindOrRegisterLogGroup('DBG_DATA_MONITORS' {$IFDEF DBG_DATA_MONITORS} , True {$ENDIF} );
 | 
						|
  DBG_DISASSEMBLER := DebugLogger.FindOrRegisterLogGroup('DBG_DISASSEMBLER' {$IFDEF DBG_DISASSEMBLER} , True {$ENDIF} );
 | 
						|
 | 
						|
  MDebuggerClasses := TStringList.Create;
 | 
						|
  MDebuggerClasses.Sorted := True;
 | 
						|
  MDebuggerClasses.Duplicates := dupError;
 | 
						|
 | 
						|
finalization
 | 
						|
  DoFinalization;
 | 
						|
  FreeAndNil(MDebuggerClasses);
 | 
						|
 | 
						|
end.
 |