Sign in Join
Wiki copytemporary

TDebuggerIntf: what changed

Revision 1 to 2. Removed lines have a minus sign; added lines have a plus sign.

OldNewLine
11**TDebuggerIntf** is the base class of implementing a debugger as Lazarus-IDE plugin package. The package must have DebuggerIntf package as it's requirements. Any debugger plug-in must implement the class and register via **RegisterDebugger** (called at **Register** of registering unit).
22
33Implementation notes:
44
55- the class is designed to act as asynchronous object. The interaction is implemented in form of commands sent to the class.
66- the command should be put (or not put) into an execution queue. The information about acceptance or denial of the command should be returned as soon as possible.
77
88
99Command request is sent from the Main Thread. Thus any actual debugging job should be implemented in a separate thread NOT to impact the user experience.
1010
1111- once a command has been handled from the queue, the corresponding event should be called and/or debugger state changed
1212
1313## Debugger Workflow
1414
1515### Initialization
1616
1717IDE does following steps via TDebuggerIntf methods:
1818
1919- allocate (external debugger executable name is provided) (the state is expected **dsNone**)
2020- allocate debug objects (Breakpoints, watches) within TDebuggerIntf
2121- assign debugger properties
2222- .Init() (as a result of Init method, the debugger should be in **dsIdle** state)
2323- assigning environment
2424- assigning debugged process information (WorkingDir, FileName, Arguments, etc...)
2525
2626### Breakpoints
2727
2828In order to set a break-point there should be a new sub-class of **TGDBBreakPoint** provided.
2929
3030The list of break-points is stored and managed at TDBGBreakPoints class. The class constructor requires to specify the class of **TGDBBreakPoint** to be created (which should be the new sub-class) TDBGBreakPoints is created via protected **CreateBreakPoints** method. The method needs to be overridden and the code to allocate TDBGBreakPoints with the proper sub-class used.
3131
3232#### Validation
3333
3434IDE allows to create a breakpoint on any address and or source line. However, the source line where the breakpoint is created might not contain any code or debugging information. In order to indicate if the breakpoint could be stopped at **TGDBBreakPoint** class provides **Valid** property of enumeration **TValidState** type. The property is a public read-only property, however, it could be changed via the protected method **SetValid()**.
3535
3636- vsUnknown - this is the initial value of Valid property. Once the debugger verifies, if the requested break point is a valid point, it should change the value to either Valid or Invalid.
3737- vsValid - the breakpoint is a valid breakpoint, and the execution could stop on it.
3838- vsInvalid - the breakpoint requested is at the invalid location or debugging information doesn't exist.
3939
4040#### Hit
4141
4242Whenever breakpoint is hit, **TGDBBreakPoint.Hit()** method should be called.
4343
4444### Execution Address
4545
4646The execution address or execution line should be shown whenever the debugger is stopped or paused. This could occur whenever the debugger stops on a breakpoint, paused or an error occurs in the debugged process.
4747
4848The debugger should call (protected) method **DoCurrent()**, to specify where location of the instructions be executed. The method accepts one parameter, where address and source line of code is specified. At least address field should be populated. It's understood that source line information might not be available, if so Line should be set to 0.
4949
5050### Threads Information
5151
5252The information about threads and each thread call stack is an additional information about debugged process. **TDebuggerIntf** should either populate it whenever the information is available or whenever the information is explicitly requested.
5353
5454In order to populate the information the debugger should update **Threads** property (type **TThreadsSupplier**). The property is a list of threads. The list could be cleaned every time before population.
5555
5656The list should be populated using **Add** method. **TThreadEntity** class could be either allocated explicitly, or **CreateEntity** method of **Threads** could be used. It is important to remember that **Add** methods allocates a copy of **TThreadEntity**, thus right after the call to **Add** the added object could be freed (and must be freed eventually).
5757
5858Once the list of threads is added to **Threads**, it's necessary to validate the data by calling **SetValidity** method, passing **ddsValid** as a parameter.
5959
6060Finally, whenever a debugged process is stopped, it's desired to identify the "current" event thread by assinging ID of the thread to **CurrentThreadId** property of **Threads** object.
6161
6262**TThreadsSupplier** should be sub-classed in order to get the notification when thread information is needed. (The sub-class should be created in **CreateThreads** of TDebuggerIntf sub-class) The sub-class must override and implement **RequestMasterData** method. The method is called whenever IDE needs the up-to-date information about threads. Similar to **RequestCommand** the method is expected to behave asynchronously and doesn't have to update threads information immediately.
6363
6464## Minimal Implementation
6565
6666The following methods must be implemented for TDebbugerIntf
6767
6868- **GetSupportedCommands** (or **GetCommands**) - returns the set of formats that a debugger can perform
6969- **RequestCommand** - the method actually performing commands. Only commands returned by **GetSupportedCommands** would be passed to this method
7070- **Caption** - the method return user-friendly name of the debugger
7171
7272```delphi
7373type
7474 TMiniDebugger = class(TDebuggerIntf)
7575 protected
7676 function RequestCommand(const ACommand: TDBGCommand; const AParams: array of const): Boolean; override;
7777 function GetSupportedCommands: TDBGCommands; override;
7878 public
7979 class function Caption: String; override;
8080 end;
8181
8282procedure Register;
8383
8484implementation
8585
8686procedure Register;
8787begin
8888 RegisterDebugger(TMiniDebugger);
8989end;
9090
9191class function TMiniDebugger.Caption: String;
9292begin
9393 Result:='Initial Debugger Plug-in';
9494end;
9595
9696function TMiniDebugger.GetSupportedCommands: TDBGCommands;
9797begin
9898 Result := [dcRun, dcStop];
9999end;
100100
101101function TMiniDebugger.RequestCommand(const ACommand: TDBGCommand;
102102 const AParams: array of const): Boolean;
103103begin
104104 case ACommand of
105105 dcRun: begin // the debugger was requested to run
106106 Result:=true; // typically it should set the state into dsIdle (to get more data from IDE)
107107 SetState(dsRun); // the debugger replies as if it started immediately
108108 end;
109109 dcStop: begin // the debugger was requested to stop
110110 Result:=true;
111111 SetState(dsStop); // the debugger replied as if it stopped immediately
112112 end;
113113 else
114114 Result:=false;
115115 end;
116116end;
117117```
118118
119119## Reference
120120
121121### RequestCommand
122122
123123The method should return **false**, if the command cannot be executed.
124124
125125### property Environment
126126
127127```delphi
128128 property Environment: TStrings read write
129129```
130130
131131Environment variables that should be passed (or updated) in a debugged project. Assigning values to Environment triggers dcEnvironment command.
132132
133133## Commands
134134
135135The following commands are called via **RequestCommand** method.
136136
137-<table>
138-<thead>
139-<tr>
140-<th><p>Command</p></th>
141-<th><p>Explanation</p></th>
142-<th><p>Parameters</p></th>
143-</tr>
144-</thead>
145-<tbody>
146-<tr>
147-<td><p>dcRun</p></td>
148-<td><p>Starts (or Restarts) or Resumes the execution of a debugged process.</p>
149-<p>The debugged process executable and arguments to be used are available through <strong>FileName</strong> and <strong>Arguments</strong> properties of TDebuggerIntf object.</p></td>
150-<td><p>no parameters</p></td>
151-</tr>
152-<tr>
153-<td><p>dcPause</p></td>
154-<td></td>
155-<td><p>no parameters</p></td>
156-</tr>
157-<tr>
158-<td><p>dcStop</p></td>
159-<td></td>
160-<td><p>no parameters</p></td>
161-</tr>
162-<tr>
163-<td><p>dcStepOver</p></td>
164-<td></td>
165-<td><p>no parameters</p></td>
166-</tr>
167-<tr>
168-<td><p>dcStepInto</p></td>
169-<td></td>
170-<td><p>no parameters</p></td>
171-</tr>
172-<tr>
173-<td><p>dcStepOut</p></td>
174-<td></td>
175-<td><p>no parameters</p></td>
176-</tr>
177-<tr>
178-<td><p>dcRunTo</p></td>
179-<td></td>
180-<td><p>0 - AnsiString - file name of the source code to run to</p>
181-<p>1 - Integer - Line number to run to</p></td>
182-</tr>
183-<tr>
184-<td><p>dcJumpto</p></td>
185-<td></td>
186-<td><p>0 - AnsiString - file name of the source code to jump to</p>
187-<p>1 - Integer - Line number to run to</p></td>
188-</tr>
189-<tr>
190-<td><p>dcAttach</p></td>
191-<td></td>
192-<td><p>0 - AnsiString - process ID to attach-to.</p></td>
193-</tr>
194-<tr>
195-<td><p>dcDetach</p></td>
196-<td></td>
197-<td><p>no parameters</p></td>
198-</tr>
199-<tr>
200-<td><p>dcBreak</p></td>
201-<td></td>
202-<td></td>
203-</tr>
204-<tr>
205-<td><p>dcWatch</p></td>
206-<td></td>
207-<td></td>
208-</tr>
209-<tr>
210-<td><p>dcLocal</p></td>
211-<td></td>
212-<td></td>
213-</tr>
214-<tr>
215-<td><div id=#dcEvaluate>
216-</div>
217-<p>dcEvaluate</p></td>
218-<td></td>
219-<td><p>0 - AnsiString - expression to be evaluated</p>
220-<p>1 - pointer to AnsiString - the string where the result should be saved into</p>
221-<p>2 - pointer to TDBGType - the reference where the information about the result type should be saved to</p>
222-<p>3 - Integer - TDBGEvaluateFlags casted into Integer</p></td>
223-</tr>
224-<tr>
225-<td><p>dcModify</p></td>
226-<td><p>Modifies the given expression / Assigns a value to a variable/field/property</p></td>
227-<td><p>0 - AnsiString - identified expression</p>
228-<p>1 - AnsiString - value to be assigned</p></td>
229-</tr>
230-<tr>
231-<td><div id=dcEnvironment>
232-</div>
233-<p>dcEnvironment</p></td>
234-<td><p>Prepares/updates an environmental variable for a debugged process.</p></td>
235-<td><p>0 - AnsiString - environment variable in %name%=%value% format</p>
236-<p>1 - Boolean - the flag, if "true" then the variable needs to be set, "false" if needs to be removed</p></td>
237-</tr>
238-<tr>
239-<td><p>dcSetStackFrame</p></td>
240-<td></td>
241-<td></td>
242-</tr>
243-<tr>
244-<td><p>dcDisassemble</p></td>
245-<td></td>
246-<td></td>
247-</tr>
248-<tr>
249-<td><p>dcStepOverInstr</p></td>
250-<td></td>
251-<td></td>
252-</tr>
253-<tr>
254-<td><p>dcStepIntoInstr</p></td>
255-<td></td>
256-<td></td>
257-</tr>
258-<tr>
259-<td><p>dcSendConsoleInput</p></td>
260-<td></td>
261-<td></td>
262-</tr>
263-</tbody>
264-</table>
137+**Command**
138+
139+**Explanation**
140+
141+**Parameters**
142+
143+dcRun
144+
145+Starts (or Restarts) or Resumes the execution of a debugged process.
146+
147+The debugged process executable and arguments to be used are available through **FileName** and **Arguments** properties of TDebuggerIntf object.
148+
149+no parameters
150+
151+dcPause
152+
153+no parameters
154+
155+dcStop
156+
157+no parameters
158+
159+dcStepOver
160+
161+no parameters
162+
163+dcStepInto
164+
165+no parameters
166+
167+dcStepOut
168+
169+no parameters
170+
171+dcRunTo
172+
173+0 - AnsiString - file name of the source code to run to
174+
175+1 - Integer - Line number to run to
176+
177+dcJumpto
178+
179+0 - AnsiString - file name of the source code to jump to
180+
181+1 - Integer - Line number to run to
182+
183+dcAttach
184+
185+0 - AnsiString - process ID to attach-to.
186+
187+dcDetach
188+
189+no parameters
190+
191+dcBreak
192+
193+dcWatch
194+
195+dcLocal
196+
197+dcEvaluate
198+
199+0 - AnsiString - expression to be evaluated
200+
201+1 - pointer to AnsiString - the string where the result should be saved into
202+
203+2 - pointer to TDBGType - the reference where the information about the result type should be saved to
204+
205+3 - Integer - TDBGEvaluateFlags casted into Integer
206+
207+dcModify
208+
209+Modifies the given expression / Assigns a value to a variable/field/property
210+
211+0 - AnsiString - identified expression
212+
213+1 - AnsiString - value to be assigned
214+
215+dcEnvironment
216+
217+Prepares/updates an environmental variable for a debugged process.
218+
219+0 - AnsiString - environment variable in %name%=%value% format
220+
221+1 - Boolean - the flag, if "true" then the variable needs to be set, "false" if needs to be removed
222+
223+dcSetStackFrame
224+
225+dcDisassemble
226+
227+dcStepOverInstr
228+
229+dcStepIntoInstr
230+
231+dcSendConsoleInput
265232
266233## Development Hints
267234
268235- it might be helpful to recompile DebuggerIntf package, adding the following Custom Options to the compiler options of the package
269236
270237
271238
272239-dDBG_STATE
273240
274241-dDBG_EVENTS
275242
276243-dDBG_VERBOSE
277244
278245-dDBG_WARNINGS
279246
280247-dDBG_DATA_MONITORS
281248
282249-dDBG_DISASSEMBLER
283250
284251these defines provide more logging output of TDebuggerIntf
285252
286253- it might be helpful to rebuild IDE adding the following defines into build Options:
287254
288255
289256
290257-dVerboseDebugger
291258
292259**VerboseDebugger** logs messages debugging calls from IDE itself
293260
294261## See Also
295262
296263- [[FpGdbmiDebugger]] - debugger plug-in, that works over the external GDB debugger, but has a better understanding of Pascal expressions and types
297264
298265---
299266*From the Free Pascal wiki, page "TDebuggerIntf", as it stood on 2017-10-30 after a change by Skalogryz, out of the wiki's dump of 2024-05-26. Copyright stays with the author who wrote it, according to the old wiki's [[Licensing]] page. If you have concerns about this material, [message the admin](/wiki-contact).*
300267Category: Debugging

Back to history