1 {
2 ---------------------------------------------------------------------------
3 FpDebugDebuggerWorkThreads
4 ---------------------------------------------------------------------------
5
6 ***************************************************************************
7 * *
8 * This source is free software; you can redistribute it and/or modify *
9 * it under the terms of the GNU General Public License as published by *
10 * the Free Software Foundation; either version 2 of the License, or *
11 * (at your option) any later version. *
12 * *
13 * This code is distributed in the hope that it will be useful, but *
14 * WITHOUT ANY WARRANTY; without even the implied warranty of *
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU *
16 * General Public License for more details. *
17 * *
18 * A copy of the GNU General Public License is available on the World *
19 * Wide Web at <http://www.gnu.org/copyleft/gpl.html>. You can also *
20 * obtain it by writing to the Free Software Foundation, *
21 * Inc., 51 Franklin Street - Fifth Floor, Boston, MA 02110-1335, USA. *
22 * *
23 ***************************************************************************
24 }
25
26 unit FpDebugDebuggerWorkThreads;
27
28 (*
29 This unit contains the classes for executing work in the worker thread:
30 - The general structure of the classes
31 - The code that is to be executed in the worker thread
32 procedure DoExecute;
33
34 - The classes are extended in the main FpDebugDebugger unit with any code
35 running in the main debugger thread.
36
37 This split accross the units should help with identifying what may be accessed
38 in the worker thread.
39 *)
40
41 {$mode objfpc}{$H+}
42 {$TYPEDADDRESS on}
43 {$ModeSwitch advancedrecords}
44
45 interface
46
47 uses
48 FpDebugDebuggerUtils, DbgIntfDebuggerBase, DbgIntfBaseTypes, FpDbgClasses,
49 FpDbgUtil, FPDbgController, FpPascalBuilder, FpdMemoryTools, FpDbgInfo,
50 FpPascalParser, FpErrorMessages, FpDbgCallContextInfo, FpDbgDwarf,
51 FpDbgDwarfDataClasses, Forms, fgl, math, Classes, sysutils, {$ifdef FORCE_LAZLOGGER_DUMMY} LazLoggerDummy {$else} LazLoggerBase {$endif};
52
53 type
54
55 TFpDbgAsyncMethod = procedure() of object;
56
57 TFpDebugDebuggerBase = class(TDebuggerIntf)
58 protected
59 FDbgController: TDbgController;
60 FMemManager: TFpDbgMemManager;
61 FMemReader: TDbgMemReader;
62 FMemConverter: TFpDbgMemConvertorLittleEndian;
63 FLockList: TFpDbgLockList;
64 FWorkQueue: TFpThreadPriorityWorkerQueue;
65 end;
66
67 { TFpDbgDebggerThreadWorkerItem }
68
69 TFpDbgDebggerThreadWorkerItem = class(TFpThreadPriorityWorkerItem)
70 protected type
71 THasQueued = (hqNotQueued, hqQueued, hqBlocked);
72 protected
73 FDebugger: TFpDebugDebuggerBase;
74 FHasQueued: THasQueued;
75 public
76 constructor Create(ADebugger: TFpDebugDebuggerBase; APriority: TFpThreadWorkerPriority);
77
78 procedure Queue(aMethod: TDataEvent; Data: PtrInt = 0);
79 (* Unqueue_DecRef also prevents new queuing
80 Unqueue_DecRef allows for destruction (no more access to object)
81 => therefor UnQueue_DecRef and ALL/most methods executing unqueue_DecRef are named *_DecRef
82 *)
83 procedure UnQueue_DecRef(ABlockQueuing: Boolean = True);
84 end;
85
86 { TFpDbgDebggerThreadWorkerLinkedItem }
87
88 TFpDbgDebggerThreadWorkerLinkedItem = class(TFpDbgDebggerThreadWorkerItem)
89 protected
90 FNextWorker: TFpDbgDebggerThreadWorkerLinkedItem; // linked list for use by TFPCallStackSupplier
91 procedure DoRemovedFromLinkedList; virtual;
92 end;
93
94 { TFpDbgDebggerThreadWorkerLinkedList }
95
96 TFpDbgDebggerThreadWorkerLinkedList = object
97 private
98 FNextWorker: TFpDbgDebggerThreadWorkerLinkedItem;
99 FLocked: Boolean;
100 public
101 procedure Add(AWorkItem: TFpDbgDebggerThreadWorkerLinkedItem); // Does not add ref / uses existing ref
102 procedure ClearFinishedWorkers;
103 procedure RequestStopForWorkers;
104 procedure WaitForWorkers(AStop: Boolean); // Only call in IDE thread (main thread)
105 end;
106
107 { TFpThreadWorkerControllerRun }
108
109 TFpThreadWorkerControllerRun = class(TFpDbgDebggerThreadWorkerItem)
110 private
111 FWorkerThreadId: TThreadID;
112 protected
113 FStartSuccessfull: boolean;
114 procedure DoExecute; override;
115 public
116 constructor Create(ADebugger: TFpDebugDebuggerBase);
117 property StartSuccesfull: boolean read FStartSuccessfull;
118 property WorkerThreadId: TThreadID read FWorkerThreadId;
119 end;
120
121 { TFpThreadWorkerRunLoop }
122
123 TFpThreadWorkerRunLoop = class(TFpDbgDebggerThreadWorkerItem)
124 protected
125 procedure LoopFinished_DecRef(Data: PtrInt = 0); virtual; abstract;
126 procedure DoExecute; override;
127 public
128 constructor Create(ADebugger: TFpDebugDebuggerBase);
129 end;
130
131 { TFpThreadWorkerRunLoopAfterIdle }
132
133 TFpThreadWorkerRunLoopAfterIdle = class(TFpDbgDebggerThreadWorkerItem)
134 protected
135 procedure CheckIdleOrRun_DecRef(Data: PtrInt = 0); virtual; abstract;
136 procedure DoExecute; override;
137 public
138 constructor Create(ADebugger: TFpDebugDebuggerBase);
139 end;
140
141 { TFpThreadWorkerAsyncMeth }
142
143 TFpThreadWorkerAsyncMeth = class(TFpDbgDebggerThreadWorkerItem)
144 protected
145 FAsyncMethod: TFpDbgAsyncMethod;
146 procedure DoExecute; override;
147 public
148 constructor Create(ADebugger: TFpDebugDebuggerBase; AnAsyncMethod: TFpDbgAsyncMethod);
149 end;
150
151 { TFpThreadWorkerPrepareCallStackEntryList }
152
153 TFpThreadWorkerPrepareCallStackEntryList = class(TFpDbgDebggerThreadWorkerLinkedItem)
154 (* Do not accesss CallStackEntryList.Items[] while this is running *)
155 protected
156 FRequiredMinCount: Integer;
157 FThread: TDbgThread;
158 procedure PrepareCallStackEntryList(AFrameRequired: Integer; AThread: TDbgThread);
159 procedure DoExecute; override;
160 public
161 constructor Create(ADebugger: TFpDebugDebuggerBase; ARequiredMinCount: Integer; APriority: TFpThreadWorkerPriority = twpStack);
162 constructor Create(ADebugger: TFpDebugDebuggerBase; ARequiredMinCount: Integer; AThread: TDbgThread);
163 end;
164
165 { TFpThreadWorkerCallStackCount }
166
167 TFpThreadWorkerCallStackCount = class(TFpThreadWorkerPrepareCallStackEntryList)
168 protected
169 procedure UpdateCallstack_DecRef(Data: PtrInt = 0); virtual; abstract;
170 procedure DoExecute; override;
171 end;
172
173 { TFpThreadWorkerCallEntry }
174
175 TFpThreadWorkerCallEntry = class(TFpThreadWorkerPrepareCallStackEntryList)
176 protected
177 FCallstackIndex: Integer;
178 FDbgCallStack: TDbgCallstackEntry;
179 FParamAsString: String;
180 procedure UpdateCallstackEntry_DecRef(Data: PtrInt = 0); virtual; abstract;
181 procedure DoExecute; override;
182 end;
183
184 { TFpThreadWorkerThreads }
185
186 TFpThreadWorkerThreads = class(TFpThreadWorkerPrepareCallStackEntryList)
187 protected
188 procedure UpdateThreads_DecRef(Data: PtrInt = 0); virtual; abstract;
189 procedure DoExecute; override;
190 public
191 constructor Create(ADebugger: TFpDebugDebuggerBase);
192 end;
193
194 { TFpThreadWorkerLocals }
195
196 TFpThreadWorkerLocals = class(TFpDbgDebggerThreadWorkerLinkedItem)
197 protected type
198 TResultEntry = record
199 Name, Value: String;
200 class operator = (a, b: TResultEntry): Boolean;
201 end;
202 TResultList = specialize TFPGList<TResultEntry>;
203 protected
204 FThreadId, FStackFrame: Integer;
205 FResults: TResultList;
206 procedure UpdateLocals_DecRef(Data: PtrInt = 0); virtual; abstract;
207 procedure DoExecute; override;
208 public
209 destructor Destroy; override;
210 end;
211
212 { TFpThreadWorkerModify }
213
214 TFpThreadWorkerModify = class(TFpDbgDebggerThreadWorkerLinkedItem)
215 private
216 FExpression, FNewVal: String;
217 FStackFrame, FThreadId: Integer;
218 FSuccess: Boolean;
219 protected
220 procedure DoCallback_DecRef(Data: PtrInt = 0); virtual; abstract;
221 procedure DoExecute; override;
222 property Success: Boolean read FSuccess;
223 public
224 constructor Create(ADebugger: TFpDebugDebuggerBase;
225 //APriority: TFpThreadWorkerPriority;
226 const AnExpression, ANewValue: String;
227 AStackFrame, AThreadId: Integer
228 );
DebugTextnull229 function DebugText: String; override;
230 end;
231
232 { TFpThreadWorkerEvaluate }
233
234 TFpThreadWorkerEvaluate = class(TFpDbgDebggerThreadWorkerLinkedItem)
235 private
236 FAllowFunctions: Boolean;
237 FExpressionScope: TFpDbgSymbolScope;
238
DoWatchFunctionCallnull239 function DoWatchFunctionCall(AnExpressionPart: TFpPascalExpressionPart;
240 AFunctionValue, ASelfValue: TFpValue; AParams: TFpPascalExpressionPartList;
241 out AResult: TFpValue; var AnError: TFpError): boolean;
242 protected
EvaluateExpressionnull243 function EvaluateExpression(const AnExpression: String;
244 AStackFrame, AThreadId: Integer;
245 ADispFormat: TWatchDisplayFormat;
246 ARepeatCnt: Integer;
247 AnEvalFlags: TDBGEvaluateFlags;
248 out AResText: String;
249 out ATypeInfo: TDBGType
250 ): Boolean;
251 public
252 end;
253
254 { TFpThreadWorkerEvaluateExpr }
255
256 TFpThreadWorkerEvaluateExpr = class(TFpThreadWorkerEvaluate)
257 private
258 FExpression: String;
259 FStackFrame, FThreadId: Integer;
260 FDispFormat: TWatchDisplayFormat;
261 FRepeatCnt: Integer;
262 FEvalFlags: TDBGEvaluateFlags;
263 protected
264 FRes: Boolean;
265 FResText: String;
266 FResDbgType: TDBGType;
267 procedure DoExecute; override;
268 public
269 constructor Create(ADebugger: TFpDebugDebuggerBase;
270 APriority: TFpThreadWorkerPriority;
271 const AnExpression: String;
272 AStackFrame, AThreadId: Integer;
273 ADispFormat: TWatchDisplayFormat;
274 ARepeatCnt: Integer;
275 AnEvalFlags: TDBGEvaluateFlags
276 );
DebugTextnull277 function DebugText: String; override;
278 end;
279
280 { TFpThreadWorkerCmdEval }
281
282 TFpThreadWorkerCmdEval = class(TFpThreadWorkerEvaluateExpr)
283 protected
284 FCallback: TDBGEvaluateResultCallback;
285 procedure DoCallback_DecRef(Data: PtrInt = 0);
286 procedure DoExecute; override;
287 public
288 constructor Create(ADebugger: TFpDebugDebuggerBase;
289 APriority: TFpThreadWorkerPriority;
290 const AnExpression: String;
291 AStackFrame, AThreadId: Integer;
292 AnEvalFlags: TDBGEvaluateFlags;
293 ACallback: TDBGEvaluateResultCallback
294 );
295 destructor Destroy; override;
296 procedure Abort;
297 end;
298
299 { TFpThreadWorkerWatchValueEval }
300
301 TFpThreadWorkerWatchValueEval = class(TFpThreadWorkerEvaluateExpr)
302 protected
303 procedure UpdateWatch_DecRef(Data: PtrInt = 0); virtual; abstract;
304 procedure DoExecute; override;
305 end;
306
307 { TFpThreadWorkerBreakPoint }
308
309 TFpThreadWorkerBreakPoint = class(TFpDbgDebggerThreadWorkerItem)
310 public
311 procedure RemoveBreakPoint_DecRef; virtual;
312 procedure AbortSetBreak; virtual;
313 end;
314
315 { TFpThreadWorkerBreakPointSet }
316
317 TFpThreadWorkerBreakPointSet = class(TFpThreadWorkerBreakPoint)
318 private
319 FInternalBreakpoint: FpDbgClasses.TFpDbgBreakpoint;
320 FKind: TDBGBreakPointKind;
321 FAddress: TDBGPtr;
322 FSource: String;
323 FLine: Integer;
324 FStackFrame, FThreadId: Integer;
325 FWatchData: String;
326 FWatchScope: TDBGWatchPointScope;
327 FWatchKind: TDBGWatchPointKind;
328 protected
329 FResetBreakPoint: Boolean;
330 procedure UpdateBrkPoint_DecRef(Data: PtrInt = 0); virtual; abstract;
331 procedure DoExecute; override;
332 public
333 constructor Create(ADebugger: TFpDebugDebuggerBase; AnAddress: TDBGPtr);
334 constructor Create(ADebugger: TFpDebugDebuggerBase; ASource: String; ALine: Integer);
335 constructor Create(ADebugger: TFpDebugDebuggerBase;
336 AWatchData: String; AWatchScope: TDBGWatchPointScope; AWatchKind: TDBGWatchPointKind;
337 AStackFrame, AThreadId: Integer);
338 property InternalBreakpoint: FpDbgClasses.TFpDbgBreakpoint read FInternalBreakpoint;
339 end;
340
341 { TFpThreadWorkerBreakPointRemove }
342
343 TFpThreadWorkerBreakPointRemove = class(TFpThreadWorkerBreakPoint)
344 protected
345 FInternalBreakpoint: FpDbgClasses.TFpDbgBreakpoint;
346 procedure DoExecute; override;
347 public
348 constructor Create(ADebugger: TFpDebugDebuggerBase; AnInternalBreakpoint: FpDbgClasses.TFpDbgBreakpoint);
349 property InternalBreakpoint: FpDbgClasses.TFpDbgBreakpoint read FInternalBreakpoint;
350 end;
351
352 implementation
353
354 { TFpDbgDebggerThreadWorkerItem }
355
356 constructor TFpDbgDebggerThreadWorkerItem.Create(ADebugger: TFpDebugDebuggerBase;
357 APriority: TFpThreadWorkerPriority);
358 begin
359 inherited Create(APriority);
360 FDebugger := ADebugger;
361 AddRef;
362 end;
363
364 procedure TFpDbgDebggerThreadWorkerItem.Queue(aMethod: TDataEvent; Data: PtrInt
365 );
366 begin
367 FDebugger.FLockList.Lock;
368 try
369 if (FHasQueued <> hqBlocked) then begin
370 assert(FHasQueued = hqNotQueued, 'TFpDbgDebggerThreadWorkerItem.Queue: FHasQueued = hqNotQueued');
371 FHasQueued := hqQueued;
372 AddRef;
373 Application.QueueAsyncCall(aMethod, 0);
374 end;
375 finally
376 FDebugger.FLockList.UnLock;
377 end;
378 end;
379
380 procedure TFpDbgDebggerThreadWorkerItem.UnQueue_DecRef(ABlockQueuing: Boolean);
381 var
382 HasQ: THasQueued;
383 begin
384 FDebugger.FLockList.Lock;
385 HasQ := FHasQueued;
386 if ABlockQueuing then begin
387 FHasQueued := hqBlocked;
388 FDebugger.FLockList.UnLock; // unlock first.
389 Application.RemoveAsyncCalls(Self);
390 end
391 else begin
392 FHasQueued := hqNotQueued;
393 try
394 Application.RemoveAsyncCalls(Self);
395 finally
396 FDebugger.FLockList.UnLock;
397 end;
398 end;
399
400 if HasQ = hqQueued then
401 DecRef; // may call destroy
402 end;
403
404 { TFpDbgDebggerThreadWorkerLinkedItem }
405
406 procedure TFpDbgDebggerThreadWorkerLinkedItem.DoRemovedFromLinkedList;
407 begin
408 UnQueue_DecRef;
409 end;
410
411 { TFpDbgDebggerThreadWorkerLinkedList }
412
413 procedure TFpDbgDebggerThreadWorkerLinkedList.Add(
414 AWorkItem: TFpDbgDebggerThreadWorkerLinkedItem);
415 begin
416 AWorkItem.FNextWorker := FNextWorker;
417 FNextWorker := AWorkItem;
418 end;
419
420 procedure TFpDbgDebggerThreadWorkerLinkedList.ClearFinishedWorkers;
421 var
422 WorkItem, w: TFpDbgDebggerThreadWorkerLinkedItem;
423 begin
424 assert(system.ThreadID = classes.MainThreadID, 'TFpDbgDebggerThreadWorkerLinkedList.ClearFinishedCountWorkers: system.ThreadID = classes.MainThreadID');
425 if FLocked then
426 exit;
427 FLocked := True;
428 WorkItem := FNextWorker;
429 while (WorkItem <> nil) and (WorkItem.RefCount = 1) do begin
430 w := WorkItem;
431 WorkItem := w.FNextWorker;
432 w.DoRemovedFromLinkedList;
433 w.DecRef;
434 end;
435 FNextWorker := WorkItem;
436 FLocked := False;
437 end;
438
439 procedure TFpDbgDebggerThreadWorkerLinkedList.RequestStopForWorkers;
440 var
441 WorkItem: TFpDbgDebggerThreadWorkerLinkedItem;
442 begin
443 WorkItem := FNextWorker;
444 while (WorkItem <> nil) do begin
445 WorkItem.RequestStop;
446 WorkItem := WorkItem.FNextWorker;
447 end;
448 end;
449
450 procedure TFpDbgDebggerThreadWorkerLinkedList.WaitForWorkers(AStop: Boolean);
451 var
452 WorkItem, w: TFpDbgDebggerThreadWorkerLinkedItem;
453 begin
454 assert(system.ThreadID = classes.MainThreadID, 'TFpDbgDebggerThreadWorkerLinkedList.WaitForWorkers: system.ThreadID = classes.MainThreadID');
455 assert(not FLocked, 'TFpDbgDebggerThreadWorkerLinkedList.WaitForWorkers: not FLocked');
456 if AStop then
457 RequestStopForWorkers;
458
459 FLocked := True;
460 WorkItem := FNextWorker;
461 FNextWorker := nil;
462 while (WorkItem <> nil) do begin
463 w := WorkItem;
464 WorkItem := w.FNextWorker;
465 if w.IsCancelled then
466 w.FDebugger.FWorkQueue.RemoveItem(w)
467 else
468 w.FDebugger.FWorkQueue.WaitForItem(w);
469 w.DoRemovedFromLinkedList;
470 w.DecRef;
471 end;
472 FLocked := False;
473 end;
474
475 { TFpThreadWorkerControllerRun }
476
477 procedure TFpThreadWorkerControllerRun.DoExecute;
478 begin
479 FStartSuccessfull := FDebugger.FDbgController.Run;
480 FWorkerThreadId := ThreadID;
481 end;
482
483 constructor TFpThreadWorkerControllerRun.Create(ADebugger: TFpDebugDebuggerBase);
484 begin
485 inherited Create(ADebugger, twpContinue);
486 end;
487
488 { TFpThreadWorkerRunLoop }
489
490 procedure TFpThreadWorkerRunLoop.DoExecute;
491 begin
492 FDebugger.FDbgController.ProcessLoop;
493 Queue(@LoopFinished_DecRef);
494 end;
495
496 constructor TFpThreadWorkerRunLoop.Create(ADebugger: TFpDebugDebuggerBase);
497 begin
498 inherited Create(ADebugger, twpContinue);
499 end;
500
501 { TFpThreadWorkerRunLoopAfterIdle }
502
503 procedure TFpThreadWorkerRunLoopAfterIdle.DoExecute;
504 begin
505 Queue(@CheckIdleOrRun_DecRef);
506 end;
507
508 constructor TFpThreadWorkerRunLoopAfterIdle.Create(ADebugger: TFpDebugDebuggerBase);
509 begin
510 inherited Create(ADebugger, twpContinue);
511 end;
512
513 { TFpThreadWorkerAsyncMeth }
514
515 procedure TFpThreadWorkerAsyncMeth.DoExecute;
516 begin
517 FAsyncMethod();
518 end;
519
520 constructor TFpThreadWorkerAsyncMeth.Create(ADebugger: TFpDebugDebuggerBase;
521 AnAsyncMethod: TFpDbgAsyncMethod);
522 begin
523 inherited Create(ADebugger, twpUser);
524 FAsyncMethod := AnAsyncMethod;
525 end;
526
527 { TFpThreadWorkerPrepareCallStackEntryList }
528
529 procedure TFpThreadWorkerPrepareCallStackEntryList.PrepareCallStackEntryList(
530 AFrameRequired: Integer; AThread: TDbgThread);
531 var
532 ThreadCallStack: TDbgCallstackEntryList;
533 CurCnt, ReqCnt: Integer;
534 begin
535 ThreadCallStack := AThread.CallStackEntryList;
536
537 if ThreadCallStack = nil then begin
538 AThread.PrepareCallStackEntryList(-2); // Only create the list
539 ThreadCallStack := AThread.CallStackEntryList;
540 if ThreadCallStack = nil then
541 exit;
542 end;
543
544 FDebugger.FLockList.GetLockFor(ThreadCallStack);
545 try
546 CurCnt := ThreadCallStack.Count;
547 while (not StopRequested) and (FRequiredMinCount > CurCnt) and
548 (not ThreadCallStack.HasReadAllAvailableFrames)
549 do begin
550 ReqCnt := Min(CurCnt + 5, FRequiredMinCount);
551 AThread.PrepareCallStackEntryList(ReqCnt);
552 CurCnt := ThreadCallStack.Count;
553 if CurCnt < ReqCnt then
554 exit;
555 end;
556 finally
557 FDebugger.FLockList.FreeLockFor(ThreadCallStack);
558 end;
559 end;
560
561 procedure TFpThreadWorkerPrepareCallStackEntryList.DoExecute;
562 var
563 t: TDbgThread;
564 begin
565 if FRequiredMinCount < 0 then
566 exit;
567 if FThread = nil then begin
568 for t in FDebugger.FDbgController.CurrentProcess.ThreadMap do begin
569 PrepareCallStackEntryList(FRequiredMinCount, t);
570 if StopRequested then
571 break;
572 end;
573 end
574 else
575 PrepareCallStackEntryList(FRequiredMinCount, FThread);
576 end;
577
578 constructor TFpThreadWorkerPrepareCallStackEntryList.Create(
579 ADebugger: TFpDebugDebuggerBase; ARequiredMinCount: Integer;
580 APriority: TFpThreadWorkerPriority);
581 begin
582 inherited Create(ADebugger, APriority);
583 FRequiredMinCount := ARequiredMinCount;
584 FThread := nil;
585 end;
586
587 constructor TFpThreadWorkerPrepareCallStackEntryList.Create(
588 ADebugger: TFpDebugDebuggerBase; ARequiredMinCount: Integer; AThread: TDbgThread);
589 begin
590 Create(ADebugger, ARequiredMinCount);
591 FThread := AThread;
592 end;
593
594 { TFpThreadWorkerCallStackCount }
595
596 procedure TFpThreadWorkerCallStackCount.DoExecute;
597 begin
598 inherited DoExecute;
599 Queue(@UpdateCallstack_DecRef);
600 end;
601
602 { TFpThreadWorkerCallEntry }
603
604 procedure TFpThreadWorkerCallEntry.DoExecute;
605 var
606 PrettyPrinter: TFpPascalPrettyPrinter;
607 Prop: TFpDebugDebuggerProperties;
608 begin
609 inherited DoExecute;
610
611 FDbgCallStack := FThread.CallStackEntryList[FCallstackIndex];
612 if (FDbgCallStack <> nil) and (not StopRequested) then begin
613 Prop := TFpDebugDebuggerProperties(FDebugger.GetProperties);
614 PrettyPrinter := TFpPascalPrettyPrinter.Create(DBGPTRSIZE[FDebugger.FDbgController.CurrentProcess.Mode]);
615 PrettyPrinter.Context := FDebugger.FDbgController.DefaultContext;
616
617 FDebugger.FMemManager.MemLimits.MaxArrayLen := Prop.MemLimits.MaxStackArrayLen;
618 FDebugger.FMemManager.MemLimits.MaxStringLen := Prop.MemLimits.MaxStackStringLen;
619 FDebugger.FMemManager.MemLimits.MaxNullStringSearchLen := Prop.MemLimits.MaxStackNullStringSearchLen;
620
621 FParamAsString := FDbgCallStack.GetParamsAsString(PrettyPrinter);
622 PrettyPrinter.Free;
623
624 FDebugger.FMemManager.MemLimits.MaxArrayLen := Prop.MemLimits.MaxArrayLen;
625 FDebugger.FMemManager.MemLimits.MaxStringLen := Prop.MemLimits.MaxStringLen;
626 FDebugger.FMemManager.MemLimits.MaxNullStringSearchLen := Prop.MemLimits.MaxNullStringSearchLen;
627 end;
628
629 Queue(@UpdateCallstackEntry_DecRef);
630 end;
631
632 { TFpThreadWorkerThreads }
633
634 procedure TFpThreadWorkerThreads.DoExecute;
635 begin
636 inherited DoExecute;
637 Queue(@UpdateThreads_DecRef);
638 end;
639
640 constructor TFpThreadWorkerThreads.Create(ADebugger: TFpDebugDebuggerBase);
641 begin
642 inherited Create(ADebugger, 1, twpThread);
643 end;
644
645 { TFpThreadWorkerLocals.TResultEntry }
646
647 class operator TFpThreadWorkerLocals.TResultEntry. = (a, b: TResultEntry
648 ): Boolean;
649 begin
650 Result := False;
651 assert(False, 'TFpThreadWorkerLocals.TResultEntry.=: False');
652 end;
653
654 { TFpThreadWorkerLocals }
655
656 procedure TFpThreadWorkerLocals.DoExecute;
657 var
658 LocalScope: TFpDbgSymbolScope;
659 ProcVal, m: TFpValue;
660 PrettyPrinter: TFpPascalPrettyPrinter;
661 i: Integer;
662 r: TResultEntry;
663 begin
664 LocalScope := FDebugger.FDbgController.CurrentProcess.FindSymbolScope(FThreadId, FStackFrame);
665 if (LocalScope = nil) or (LocalScope.SymbolAtAddress = nil) then begin
666 LocalScope.ReleaseReference;
667 exit;
668 end;
669
670 ProcVal := LocalScope.ProcedureAtAddress;
671 if (ProcVal = nil) then begin
672 LocalScope.ReleaseReference;
673 exit;
674 end;
675
676 PrettyPrinter := TFpPascalPrettyPrinter.Create(LocalScope.SizeOfAddress);
677 PrettyPrinter.Context := LocalScope.LocationContext;
678 // PrettyPrinter.MemManager.DefaultContext := LocalScope.LocationContext;
679
680 FResults := TResultList.Create;
681 for i := 0 to ProcVal.MemberCount - 1 do begin
682 m := ProcVal.Member[i];
683 if m <> nil then begin
684 if m.DbgSymbol <> nil then
685 r.Name := m.DbgSymbol.Name
686 else
687 r.Name := '';
688 //if not StopRequested then // finish getting all names?
689 PrettyPrinter.PrintValue(r.Value, m);
690 m.ReleaseReference;
691 FResults.Add(r);
692 end;
693 if StopRequested then
694 Break;
695 end;
696 PrettyPrinter.Free;
697 ProcVal.ReleaseReference;
698 LocalScope.ReleaseReference;
699
700 Queue(@UpdateLocals_DecRef);
701 end;
702
703 destructor TFpThreadWorkerLocals.Destroy;
704 begin
705 FResults.Free;
706 inherited Destroy;
707 end;
708
709 { TFpThreadWorkerModify }
710
711 procedure TFpThreadWorkerModify.DoExecute;
712 var
713 APasExpr: TFpPascalExpression;
714 ResValue: TFpValue;
715 ExpressionScope: TFpDbgSymbolScope;
716 i64: int64;
717 c64: QWord;
718 begin
719 FSuccess := False;
720 ExpressionScope := FDebugger.FDbgController.CurrentProcess.FindSymbolScope(FThreadId, FStackFrame);
721 if ExpressionScope = nil then
722 exit;
723
724 APasExpr := TFpPascalExpression.Create(FExpression, ExpressionScope);
725 try
726 APasExpr.ResultValue; // trigger full validation
727 if not APasExpr.Valid then
728 exit;
729
730 ResValue := APasExpr.ResultValue;
731 if ResValue = nil then
732 exit;
733
734 case ResValue.Kind of
735 skInteger: if TryStrToInt64(FNewVal, i64) then ResValue.AsInteger := i64;
736 skCardinal: if TryStrToQWord(FNewVal, c64) then ResValue.AsCardinal := c64;
737 skBoolean: case LowerCase(trim(FNewVal)) of
738 'true': ResValue.AsBool := True;
739 'false': ResValue.AsBool := False;
740 end;
741 skChar: ResValue.AsString := FNewVal;
742 skEnum: ResValue.AsString := FNewVal;
743 skSet: ResValue.AsString := FNewVal;
744 skPointer: if TryStrToQWord(FNewVal, c64) then ResValue.AsCardinal := c64;
745 skFloat: ;
746 skCurrency: ;
747 skVariant: ;
748 end;
749
750
751 finally
752 APasExpr.Free;
753 ExpressionScope.ReleaseReference;
754 Queue(@DoCallback_DecRef);
755 end;
756 end;
757
758 constructor TFpThreadWorkerModify.Create(ADebugger: TFpDebugDebuggerBase;
759 const AnExpression, ANewValue: String; AStackFrame, AThreadId: Integer);
760 begin
761 inherited Create(ADebugger, twpModify);
762 FExpression := AnExpression;
763 FNewVal := ANewValue;
764 FStackFrame := AStackFrame;
765 FThreadId := AThreadId;
766 end;
767
DebugTextnull768 function TFpThreadWorkerModify.DebugText: String;
769 begin
770 Result := inherited DebugText;
771 end;
772
773 { TFpThreadWorkerEvaluate }
774
DoWatchFunctionCallnull775 function TFpThreadWorkerEvaluate.DoWatchFunctionCall(
776 AnExpressionPart: TFpPascalExpressionPart; AFunctionValue,
777 ASelfValue: TFpValue; AParams: TFpPascalExpressionPartList; out
778 AResult: TFpValue; var AnError: TFpError): boolean;
779 var
780 FunctionSymbolData, FunctionSymbolType, FunctionResultSymbolType,
781 TempSymbol: TFpSymbol;
782 ParamSymbol, ExprParamVal: TFpValue;
783 ProcAddress: TFpDbgMemLocation;
784 FunctionResultDataSize: TFpDbgValueSize;
785 ParameterSymbolArr: array of TFpSymbol;
786 CallContext: TFpDbgInfoCallContext;
787 PCnt, i, FoundIdx, ItemsOffs: Integer;
788 rk: TDbgSymbolKind;
789 begin
790 Result := False;
791 if FExpressionScope = nil then
792 exit;
793 (*
794 AFunctionValue => TFpValueDwarfSubroutine // gotten from <== TFpSymbolDwarfDataProc.GetValueObject;
795 .DataSympol = TFpSymbolDwarfDataProc from which we were created
796 .TypeSymbol = TFpSymbolDwarfTypeProc.TypeInfo : TFpSymbolDwarfType
797
798 AFunctionFpSymbol => TFpSymbolDwarfTypeProc;
799 val
800 *)
801
802 FunctionSymbolData := AFunctionValue.DbgSymbol; // AFunctionValue . FDataSymbol
803 FunctionSymbolType := FunctionSymbolData.TypeInfo;
804 FunctionResultSymbolType := FunctionSymbolType.TypeInfo;
805
806 if not (FunctionResultSymbolType.Kind in [skInteger, skCurrency, skPointer, skEnum,
807 skCardinal, skBoolean, skChar, skClass])
808 then begin
809 DebugLn(['Error result kind ', dbgs(FunctionSymbolType.Kind)]);
810 AnError := CreateError(fpErrAnyError, ['Result type of function not supported']);
811 exit;
812 end;
813
814 // TODO: pass a value object
815 if (not FunctionResultSymbolType.ReadSize(nil, FunctionResultDataSize)) or
816 (FunctionResultDataSize > FDebugger.FMemManager.RegisterSize(0))
817 then begin
818 DebugLn(['Error result size', dbgs(FunctionResultDataSize)]);
819 //ReturnMessage := 'Unable to call function. The size of the function-result exceeds the content-size of a register.';
820 AnError := CreateError(fpErrAnyError, ['Result type of function not supported']);
821 exit;
822 end;
823
824 // check params
825
826 ProcAddress := AFunctionValue.DataAddress;
827 if not IsReadableLoc(ProcAddress) then begin
828 DebugLn(['Error proc addr']);
829 AnError := CreateError(fpErrAnyError, ['Unable to calculate function address']);
830 exit;
831 end;
832
833 PCnt := AParams.Count;
834 ItemsOffs := 0;
835 if ASelfValue <> nil then begin
836 inc(PCnt);
837 ItemsOffs := -1; // In the loop "i = 0" is the self object. So "i = 1" should be AParams[0]
838 end;
839
840 SetLength(ParameterSymbolArr, PCnt);
841 for i := 0 to High(ParameterSymbolArr) do
842 ParameterSymbolArr[i] := nil;
843 FoundIdx := 0;
844 try
845 for i := 0 to FunctionSymbolType.NestedSymbolCount - 1 do begin
846 TempSymbol := FunctionSymbolType.NestedSymbol[i];
847 if sfParameter in TempSymbol.Flags then begin
848 if FoundIdx >= PCnt then begin
849 DebugLn(['Error param count']);
850 AnError := CreateError(fpErrAnyError, ['wrong amount of parameters']);
851 exit;
852 //ReturnMessage := Format('Unable to call function%s. Not enough parameters supplied.', [OutputFunctionName]);
853 end;
854 // Type Compatibility
855 // TODO: more checks for type compatibility
856 if (ASelfValue <> nil) and (FoundIdx = 0) then begin
857 // TODO: check self param
858 end
859 else begin
860 ExprParamVal := AParams.Items[FoundIdx + ItemsOffs].ResultValue;
861 if (ExprParamVal = nil) then begin
862 DebugLn('Internal error for arg %d ', [FoundIdx]);
863 AnError := AnExpressionPart.Expression.Error;
864 if not IsError(AnError) then
865 AnError := CreateError(fpErrAnyError, ['internal error, computing parameter']);
866 exit;
867 end;
868 rk := ExprParamVal.Kind;
869 if not (rk in [skInteger, {skCurrency,} skPointer, skEnum, skCardinal, skBoolean, skChar, skClass]) then begin
870 DebugLn('Error not supported kind arg %d : %s ', [FoundIdx, dbgs(rk)]);
871 AnError := CreateError(fpErrAnyError, ['parameter type not supported']);
872 exit;
873 end;
874 if (TempSymbol.Kind <> rk) and
875 ( (TempSymbol.Kind in [skInteger, skCardinal]) <> (rk in [skInteger, skCardinal]) )
876 then begin
877 DebugLn('Error kind mismatch for arg %d : %s <> %s', [FoundIdx, dbgs(TempSymbol.Kind), dbgs(rk)]);
878 AnError := CreateError(fpErrAnyError, ['wrong type for parameter']);
879 exit;
880 end;
881 end;
882 if not IsTargetOrRegNotNil(FDebugger.FDbgController.CurrentProcess.CallParamDefaultLocation(FoundIdx)) then begin
883 DebugLn('error to many args / not supported / arg > %d ', [FoundIdx]);
884 AnError := CreateError(fpErrAnyError, ['too many parameter / not supported']);
885 exit;
886 end;
887 TempSymbol.AddReference;
888 ParameterSymbolArr[FoundIdx] := TempSymbol;
889 inc(FoundIdx)
890 end;
891 end;
892 if FoundIdx <> PCnt then begin
893 DebugLn(['Error param count']);
894 AnError := CreateError(fpErrAnyError, ['wrong amount of parameters']);
895 exit;
896 end;
897
898
899 CallContext := FDebugger.FDbgController.Call(ProcAddress, FExpressionScope.LocationContext,
900 FDebugger.FMemReader, FDebugger.FMemConverter);
901
902 try
903 for i := 0 to High(ParameterSymbolArr) do begin
904 ParamSymbol := CallContext.CreateParamSymbol(i, ParameterSymbolArr[i], FDebugger.FDbgController.CurrentProcess);
905 try
906 if (ASelfValue <> nil) and (i = 0) then
907 ParamSymbol.AsCardinal := ASelfValue.AsCardinal
908 else
909 ParamSymbol.AsCardinal := AParams.Items[i + ItemsOffs].ResultValue.AsCardinal;
910 if IsError(ParamSymbol.LastError) then begin
911 DebugLn('Internal error for arg %d ', [i]);
912 AnError := ParamSymbol.LastError;
913 exit;
914 end;
915 finally
916 ParamSymbol.ReleaseReference;
917 end;
918 end;
919
920 FDebugger.FDbgController.ProcessLoop;
921
922 if not CallContext.IsValid then begin
923 DebugLn(['Error in call ',CallContext.Message]);
924 //ReturnMessage := CallContext.Message;
925 exit;
926 end;
927
928 AResult := CallContext.CreateParamSymbol(-1, FunctionSymbolType,
929 FDebugger.FDbgController.CurrentProcess, FunctionSymbolData.Name);
930 Result := AResult <> nil;
931 finally
932 CallContext.ReleaseReference;
933 end;
934 finally
935 for i := 0 to High(ParameterSymbolArr) do
936 if ParameterSymbolArr[i] <> nil then
937 ParameterSymbolArr[i].ReleaseReference;
938 end;
939
940
941 end;
942
TFpThreadWorkerEvaluate.EvaluateExpressionnull943 function TFpThreadWorkerEvaluate.EvaluateExpression(const AnExpression: String;
944 AStackFrame, AThreadId: Integer; ADispFormat: TWatchDisplayFormat;
945 ARepeatCnt: Integer; AnEvalFlags: TDBGEvaluateFlags; out AResText: String;
946 out ATypeInfo: TDBGType): Boolean;
947 var
948 APasExpr, PasExpr2: TFpPascalExpression;
949 PrettyPrinter: TFpPascalPrettyPrinter;
950 ResValue: TFpValue;
951 CastName, ResText2: String;
952 begin
953 Result := False;
954 AResText := '';
955 ATypeInfo := nil;
956
957 FExpressionScope := FDebugger.FDbgController.CurrentProcess.FindSymbolScope(AThreadId, AStackFrame);
958 if FExpressionScope = nil then
959 exit;
960
961 PrettyPrinter := nil;
962 APasExpr := TFpPascalExpression.Create(AnExpression, FExpressionScope);
963 try
964 if FAllowFunctions and (dfEvalFunctionCalls in FDebugger.EnabledFeatures) then
965 APasExpr.OnFunctionCall := @DoWatchFunctionCall;
966 APasExpr.ResultValue; // trigger full validation
967 if not APasExpr.Valid then begin
968 AResText := ErrorHandler.ErrorAsString(APasExpr.Error);
969 exit;
970 end;
971
972 ResValue := APasExpr.ResultValue;
973 if ResValue = nil then begin
974 AResText := 'Error';
975 exit;
976 end;
977
978 if StopRequested then
979 exit;
980 if (ResValue.Kind = skClass) and (ResValue.AsCardinal <> 0) and
981 (not IsError(ResValue.LastError)) and (defClassAutoCast in AnEvalFlags)
982 then begin
983 if ResValue.GetInstanceClassName(CastName) then begin
984 PasExpr2 := TFpPascalExpression.Create(CastName+'('+AnExpression+')', FExpressionScope);
985 PasExpr2.ResultValue;
986 if PasExpr2.Valid then begin
987 APasExpr.Free;
988 APasExpr := PasExpr2;
989 ResValue := APasExpr.ResultValue;
990 end
991 else
992 PasExpr2.Free;
993 end
994 else begin
995 ResValue.ResetError; // in case GetInstanceClassName did set an error
996 // TODO: indicate that typecasting to instance failed
997 end;
998 end;
999
1000 if StopRequested then
1001 exit;
1002
1003 PrettyPrinter := TFpPascalPrettyPrinter.Create(FExpressionScope.SizeOfAddress);
1004 PrettyPrinter.Context := FExpressionScope.LocationContext;
1005
1006 if defNoTypeInfo in AnEvalFlags then
1007 Result := PrettyPrinter.PrintValue(AResText, ResValue, ADispFormat, ARepeatCnt)
1008 else
1009 Result := PrettyPrinter.PrintValue(AResText, ATypeInfo, ResValue, ADispFormat, ARepeatCnt);
1010
1011 // PCHAR/String
1012 if Result and APasExpr.HasPCharIndexAccess and not IsError(ResValue.LastError) then begin
1013 // TODO: Only dwarf 2
1014 APasExpr.FixPCharIndexAccess := True;
1015 APasExpr.ResetEvaluation;
1016 ResValue := APasExpr.ResultValue;
1017 if (ResValue=nil) or (not PrettyPrinter.PrintValue(ResText2, ResValue, ADispFormat, ARepeatCnt)) then
1018 ResText2 := 'Failed';
1019 AResText := 'PChar: '+AResText+ LineEnding + 'String: '+ResText2;
1020 end;
1021
1022 if Result then
1023 Result := not IsError(ResValue.LastError) // AResText should be set from Prettyprinter
1024 else
1025 AResText := 'Error';
1026
1027 if not Result then
1028 FreeAndNil(ATypeInfo);
1029 finally
1030 PrettyPrinter.Free;
1031 APasExpr.Free;
1032 FExpressionScope.ReleaseReference;
1033 end;
1034 end;
1035
1036 { TFpThreadWorkerEvaluateExpr }
1037
1038 procedure TFpThreadWorkerEvaluateExpr.DoExecute;
1039 begin
1040 FRes := EvaluateExpression(FExpression, FStackFrame, FThreadId,
1041 FDispFormat, FRepeatCnt, FEvalFlags, FResText, FResDbgType);
1042 end;
1043
1044 constructor TFpThreadWorkerEvaluateExpr.Create(ADebugger: TFpDebugDebuggerBase;
1045 APriority: TFpThreadWorkerPriority; const AnExpression: String; AStackFrame,
1046 AThreadId: Integer; ADispFormat: TWatchDisplayFormat; ARepeatCnt: Integer;
1047 AnEvalFlags: TDBGEvaluateFlags);
1048 begin
1049 inherited Create(ADebugger, APriority);
1050 FExpression := AnExpression;
1051 FStackFrame := AStackFrame;
1052 FThreadId := AThreadId;
1053 FDispFormat := ADispFormat;
1054 FRepeatCnt := ARepeatCnt;
1055 FEvalFlags := AnEvalFlags;
1056 if (defAllowFunctionCall in AnEvalFlags) then
1057 FAllowFunctions := True;
1058 FRes := False;
1059 end;
1060
DebugTextnull1061 function TFpThreadWorkerEvaluateExpr.DebugText: String;
1062 begin
1063 Result := inherited DebugText;
1064 if self = nil then exit;
1065 Result := Format('%s Expr: "%s" T: %s S: %s', [Result, FExpression, dbgs(FThreadId), dbgs(FStackFrame)]);
1066 end;
1067
1068 { TFpThreadWorkerCmdEval }
1069
1070 procedure TFpThreadWorkerCmdEval.DoCallback_DecRef(Data: PtrInt);
1071 var
1072 CB: TDBGEvaluateResultCallback;
1073 Dbg: TFpDebugDebuggerBase;
1074 Res: Boolean;
1075 ResText: String;
1076 ResDbgType: TDBGType;
1077 begin
1078 assert(system.ThreadID = classes.MainThreadID, 'TFpThreadWorkerCmdEval.DoCallback_DecRef: system.ThreadID = classes.MainThreadID');
1079 CB := nil;
1080 try
1081 if FEvalFlags * [defNoTypeInfo, defSimpleTypeInfo, defFullTypeInfo] = [defNoTypeInfo] then
1082 FreeAndNil(FResText);
1083
1084 if (FCallback <> nil) then begin
1085 // All to local vars, because SELF may be destroyed before/while the callback happens
1086 CB := FCallback;
1087 Dbg := FDebugger;
1088 Res := FRes;
1089 ResText := FResText;
1090 ResDbgType := FResDbgType;
1091 FResDbgType := nil; // prevent from being freed => will be freed in callback
1092 FCallback := nil; // Ensure callback is never called a 2nd time (e.g. if Self.Abort is called, while in Callback)
1093 (* We cannot call Callback here, because ABORT can be called, and prematurely call UnQueue_DecRef,
1094 removing the last ref to this object *)
1095 end;
1096 except
1097 end;
1098
1099 UnQueue_DecRef;
1100
1101 // Self may now be invalid, unless FDebugger.FEvalWorkItem still has a reference.
1102 // Abort may be called (during CB), removing this refence.
1103 // Abort would be called, if a new Evaluate Request is made. FEvalWorkItem<>nil
1104 if CB <> nil then
1105 CB(Dbg, Res, ResText, ResDbgType);
1106 end;
1107
1108 procedure TFpThreadWorkerCmdEval.DoExecute;
1109 begin
1110 inherited DoExecute;
1111 Queue(@DoCallback_DecRef);
1112 end;
1113
1114 constructor TFpThreadWorkerCmdEval.Create(ADebugger: TFpDebugDebuggerBase;
1115 APriority: TFpThreadWorkerPriority; const AnExpression: String; AStackFrame,
1116 AThreadId: Integer; AnEvalFlags: TDBGEvaluateFlags;
1117 ACallback: TDBGEvaluateResultCallback);
1118 begin
1119 inherited Create(ADebugger, APriority, AnExpression, AStackFrame, AThreadId, wdfDefault, 0,
1120 AnEvalFlags);
1121 FCallback := ACallback;
1122 end;
1123
1124 destructor TFpThreadWorkerCmdEval.Destroy;
1125 begin
1126 inherited Destroy;
1127 FreeAndNil(FResDbgType);
1128 end;
1129
1130 procedure TFpThreadWorkerCmdEval.Abort;
1131 begin
1132 RequestStop;
1133 FDebugger.FWorkQueue.RemoveItem(Self);
1134 DoCallback_DecRef;
1135 end;
1136
1137 { TFpThreadWorkerWatchValueEval }
1138
1139 procedure TFpThreadWorkerWatchValueEval.DoExecute;
1140 begin
1141 inherited DoExecute;
1142 Queue(@UpdateWatch_DecRef);
1143 end;
1144
1145 { TFpThreadWorkerBreakPoint }
1146
1147 procedure TFpThreadWorkerBreakPoint.RemoveBreakPoint_DecRef;
1148 begin
1149 //
1150 end;
1151
1152 procedure TFpThreadWorkerBreakPoint.AbortSetBreak;
1153 begin
1154 //
1155 end;
1156
1157 { TFpThreadWorkerBreakPointSet }
1158
1159 procedure TFpThreadWorkerBreakPointSet.DoExecute;
1160 var
1161 CurContext: TFpDbgSymbolScope;
1162 WatchPasExpr: TFpPascalExpression;
1163 R: TFpValue;
1164 s: TFpDbgValueSize;
1165 begin
1166 case FKind of
1167 bpkAddress:
1168 FInternalBreakpoint := FDebugger.FDbgController.CurrentProcess.AddBreak(FAddress, True);
1169 bpkSource:
1170 FInternalBreakpoint := FDebugger.FDbgController.CurrentProcess.AddBreak(FSource, FLine, True);
1171 bpkData: begin
1172 CurContext := FDebugger.FDbgController.CurrentProcess.FindSymbolScope(FThreadId, FStackFrame);
1173 if CurContext <> nil then begin
1174 WatchPasExpr := TFpPascalExpression.Create(FWatchData, CurContext);
1175 R := WatchPasExpr.ResultValue; // Address and Size
1176 // TODO: Cache current value
1177 if WatchPasExpr.Valid and IsTargetNotNil(R.Address) and R.GetSize(s) then begin
1178 // pass context
1179 FInternalBreakpoint := FDebugger.FDbgController.CurrentProcess.AddWatch(R.Address.Address, SizeToFullBytes(s), FWatchKind, FWatchScope);
1180 end;
1181 WatchPasExpr.Free;
1182 CurContext.ReleaseReference;
1183 end;
1184 end;
1185 end;
1186 if FResetBreakPoint then begin
1187 FDebugger.FDbgController.CurrentProcess.RemoveBreak(FInternalBreakpoint);
1188 FreeAndNil(FInternalBreakpoint);
1189 end;
1190 Queue(@UpdateBrkPoint_DecRef);
1191 end;
1192
1193 constructor TFpThreadWorkerBreakPointSet.Create(ADebugger: TFpDebugDebuggerBase; AnAddress: TDBGPtr);
1194 begin
1195 FKind := bpkAddress;
1196 FAddress := AnAddress;
1197 inherited Create(ADebugger, twpUser);
1198 end;
1199
1200 constructor TFpThreadWorkerBreakPointSet.Create(
1201 ADebugger: TFpDebugDebuggerBase; ASource: String; ALine: Integer);
1202 begin
1203 FKind := bpkSource;
1204 FSource := ASource;
1205 FLine := ALine;
1206 inherited Create(ADebugger, twpUser);
1207 end;
1208
1209 constructor TFpThreadWorkerBreakPointSet.Create(
1210 ADebugger: TFpDebugDebuggerBase; AWatchData: String;
1211 AWatchScope: TDBGWatchPointScope; AWatchKind: TDBGWatchPointKind;
1212 AStackFrame, AThreadId: Integer);
1213 begin
1214 FKind := bpkData;
1215 FWatchData := AWatchData;
1216 FWatchScope := AWatchScope;
1217 FWatchKind := AWatchKind;
1218 FStackFrame := AStackFrame;
1219 FThreadId := AThreadId;
1220 inherited Create(ADebugger, twpUser);
1221 end;
1222
1223 { TFpThreadWorkerBreakPointRemove }
1224
1225 procedure TFpThreadWorkerBreakPointRemove.DoExecute;
1226 begin
1227 if (FDebugger.FDbgController <> nil) and (FDebugger.FDbgController.CurrentProcess <> nil) then
1228 FDebugger.FDbgController.CurrentProcess.RemoveBreak(FInternalBreakpoint);
1229 FreeAndNil(FInternalBreakpoint);
1230 end;
1231
1232 constructor TFpThreadWorkerBreakPointRemove.Create(
1233 ADebugger: TFpDebugDebuggerBase;
1234 AnInternalBreakpoint: FpDbgClasses.TFpDbgBreakpoint);
1235 begin
1236 FInternalBreakpoint := AnInternalBreakpoint;
1237 inherited Create(ADebugger, twpUser);
1238 end;
1239
1240 end.
1241
1242