/debugger/callstackdlg.pp

http://github.com/graemeg/lazarus · Puppet · 876 lines · 772 code · 103 blank · 1 comment · 101 complexity · 4d66bdcbee73bdbd67526f48e3aa136b MD5 · raw file

  1. { $Id$ }
  2. { ----------------------------------------------
  3. callstackdlg.pp - Overview of the callstack
  4. ----------------------------------------------
  5. @created(Sun Apr 28th WET 2002)
  6. @lastmod($Date$)
  7. @author(Marc Weustink <marc@@dommelstein.net>)
  8. This unit contains the Call Stack debugger dialog.
  9. ***************************************************************************
  10. * *
  11. * This source is free software; you can redistribute it and/or modify *
  12. * it under the terms of the GNU General Public License as published by *
  13. * the Free Software Foundation; either version 2 of the License, or *
  14. * (at your option) any later version. *
  15. * *
  16. * This code is distributed in the hope that it will be useful, but *
  17. * WITHOUT ANY WARRANTY; without even the implied warranty of *
  18. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU *
  19. * General Public License for more details. *
  20. * *
  21. * A copy of the GNU General Public License is available on the World *
  22. * Wide Web at <http://www.gnu.org/copyleft/gpl.html>. You can also *
  23. * obtain it by writing to the Free Software Foundation, *
  24. * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. *
  25. * *
  26. ***************************************************************************
  27. }
  28. unit CallStackDlg;
  29. {$mode objfpc}{$H+}
  30. interface
  31. uses
  32. SysUtils, Classes, Controls, Forms, LCLProc, LazLoggerBase,
  33. IDEWindowIntf, DebuggerStrConst,
  34. ComCtrls, Debugger, DebuggerDlg, Menus, ClipBrd, ExtCtrls, StdCtrls,
  35. ActnList, IDEImagesIntf, IDECommands, EnvironmentOpts;
  36. type
  37. { TCallStackDlg }
  38. TCallStackDlg = class(TDebuggerDlg)
  39. aclActions: TActionList;
  40. actCopyAll: TAction;
  41. actShowDisass: TAction;
  42. actToggleBreakPoint: TAction;
  43. actViewBottom: TAction;
  44. actViewTop: TAction;
  45. actViewLimit: TAction;
  46. actViewGoto: TAction;
  47. actViewMore: TAction;
  48. actSetCurrent: TAction;
  49. actShow: TAction;
  50. popShowDisass: TMenuItem;
  51. popToggle: TMenuItem;
  52. ToolButtonPower: TToolButton;
  53. ToolButton2: TToolButton;
  54. ToolButtonTop: TToolButton;
  55. ToolButtonBottom: TToolButton;
  56. ToolButtonCopyAll: TToolButton;
  57. ToolButton8: TToolButton;
  58. ToolButton9: TToolButton;
  59. txtGoto: TEdit;
  60. lvCallStack: TListView;
  61. Panel1: TPanel;
  62. popLimit50: TMenuItem;
  63. popLimit25: TMenuItem;
  64. popLimit10: TMenuItem;
  65. popCopyAll: TMenuItem;
  66. N1: TMenuItem;
  67. popSetAsCurrent: TMenuItem;
  68. popShow: TMenuItem;
  69. mnuPopup: TPopupMenu;
  70. mnuLimit: TPopupMenu;
  71. ToolBar1: TToolBar;
  72. ToolButtonShow: TToolButton;
  73. ToolButtonCurrent: TToolButton;
  74. ToolButton4: TToolButton;
  75. ToolButtonMore: TToolButton;
  76. ToolButtonMax: TToolButton;
  77. ToolButtonGoto: TToolButton;
  78. procedure actShowDisassExecute(Sender: TObject);
  79. procedure actToggleBreakPointExecute(Sender: TObject);
  80. procedure actViewBottomExecute(Sender: TObject);
  81. procedure actViewGotoExecute(Sender: TObject);
  82. procedure actViewMoreExecute(Sender: TObject);
  83. procedure actViewLimitExecute(Sender: TObject);
  84. procedure actViewTopExecute(Sender: TObject);
  85. procedure FormCreate(Sender: TObject);
  86. procedure lvCallStackClick(Sender: TObject);
  87. procedure popCountClick(Sender: TObject);
  88. procedure ToolButtonPowerClick(Sender: TObject);
  89. procedure txtGotoKeyPress(Sender: TObject; var Key: char);
  90. procedure lvCallStackDBLCLICK(Sender: TObject);
  91. procedure actCopyAllClick(Sender: TObject);
  92. procedure actSetAsCurrentClick(Sender : TObject);
  93. procedure actShowClick(Sender: TObject);
  94. private
  95. FViewCount: Integer;
  96. FViewLimit: Integer;
  97. FViewStart: Integer;
  98. FPowerImgIdx, FPowerImgIdxGrey: Integer;
  99. FInUpdateView: Boolean;
  100. FUpdateFlags: set of (ufNeedUpdating);
  101. function GetImageIndex(Entry: TIdeCallStackEntry): Integer;
  102. procedure SetViewLimit(const AValue: Integer);
  103. procedure SetViewStart(AStart: Integer);
  104. procedure SetViewMax;
  105. procedure GotoIndex(AIndex: Integer);
  106. function GetCurrentEntry: TIdeCallStackEntry;
  107. function GetFunction(const Entry: TIdeCallStackEntry): string;
  108. procedure UpdateView;
  109. procedure JumpToSource;
  110. procedure CopyToClipBoard;
  111. procedure ToggleBreakpoint(Item: TListItem);
  112. protected
  113. procedure DoBeginUpdate; override;
  114. procedure DoEndUpdate; override;
  115. procedure DisableAllActions;
  116. procedure EnableAllActions;
  117. function GetSelectedSnapshot: TSnapshot;
  118. function GetSelectedThreads(Snap: TSnapshot): TIdeThreads;
  119. function GetSelectedCallstack: TIdeCallStack;
  120. procedure DoBreakPointsChanged; override;
  121. procedure BreakPointChanged(const ASender: TIDEBreakPoints; const {%H-}ABreakpoint: TIDEBreakPoint);
  122. procedure CallStackChanged(Sender: TObject);
  123. procedure CallStackCurrent(Sender: TObject);
  124. function ColSizeGetter(AColId: Integer; var ASize: Integer): Boolean;
  125. procedure ColSizeSetter(AColId: Integer; ASize: Integer);
  126. public
  127. constructor Create(AOwner: TComponent); override;
  128. property BreakPoints;
  129. property CallStackMonitor;
  130. property ThreadsMonitor;
  131. property SnapshotManager;
  132. property ViewLimit: Integer read FViewLimit write SetViewLimit;
  133. end;
  134. implementation
  135. {$R *.lfm}
  136. uses
  137. BaseDebugManager, LazarusIDEStrConsts;
  138. var
  139. DBG_DATA_MONITORS: PLazLoggerLogGroup;
  140. imgSourceLine: Integer;
  141. imgNoSourceLine: Integer;
  142. CallStackDlgWindowCreator: TIDEWindowCreator;
  143. const
  144. COL_STACK_BRKPOINT = 1;
  145. COL_STACK_INDEX = 2;
  146. COL_STACK_SOURCE = 3;
  147. COL_STACK_LINE = 4;
  148. COL_STACK_FUNC = 5;
  149. COL_WIDTHS: Array[0..4] of integer = ( 50, 0, 150, 50, 280);
  150. function CallStackDlgColSizeGetter(AForm: TCustomForm; AColId: Integer; var ASize: Integer): Boolean;
  151. begin
  152. Result := AForm is TCallStackDlg;
  153. if Result then
  154. Result := TCallStackDlg(AForm).ColSizeGetter(AColId, ASize);
  155. end;
  156. procedure CallStackDlgColSizeSetter(AForm: TCustomForm; AColId: Integer; ASize: Integer);
  157. begin
  158. if AForm is TCallStackDlg then
  159. TCallStackDlg(AForm).ColSizeSetter(AColId, ASize);
  160. end;
  161. { TCallStackDlg }
  162. constructor TCallStackDlg.Create(AOwner: TComponent);
  163. var
  164. i: Integer;
  165. begin
  166. inherited Create(AOwner);
  167. CallStackNotification.OnChange := @CallStackChanged;
  168. CallStackNotification.OnCurrent := @CallStackCurrent;
  169. BreakpointsNotification.OnAdd := @BreakPointChanged;
  170. BreakpointsNotification.OnUpdate := @BreakPointChanged;
  171. BreakpointsNotification.OnRemove := @BreakPointChanged;
  172. ThreadsNotification.OnCurrent := @CallStackChanged;
  173. SnapshotNotification.OnCurrent := @CallStackChanged;
  174. actToggleBreakPoint.ShortCut := IDECommandList.FindIDECommand(ecToggleBreakPoint).AsShortCut;
  175. for i := low(COL_WIDTHS) to high(COL_WIDTHS) do
  176. if COL_WIDTHS[i] > 0 then
  177. lvCallStack.Column[i].Width := COL_WIDTHS[i]
  178. else
  179. lvCallStack.Column[i].AutoSize := True;
  180. end;
  181. procedure TCallStackDlg.CallStackChanged(Sender: TObject);
  182. begin
  183. DebugLn(DBG_DATA_MONITORS, ['DebugDataWindow: TCallStackDlg.CallStackChanged from ', DbgSName(Sender), ' Upd:', IsUpdating]);
  184. if (not ToolButtonPower.Down) or FInUpdateView then exit;
  185. if FViewStart = 0
  186. then UpdateView
  187. else SetViewStart(0);
  188. SetViewMax;
  189. end;
  190. procedure TCallStackDlg.CallStackCurrent(Sender: TObject);
  191. begin
  192. DebugLn(DBG_DATA_MONITORS, ['DebugDataWindow: TCallStackDlg.CallStackCurrent from ', DbgSName(Sender), ' Upd:', IsUpdating]);
  193. if not ToolButtonPower.Down then exit;
  194. UpdateView;
  195. end;
  196. function TCallStackDlg.ColSizeGetter(AColId: Integer; var ASize: Integer): Boolean;
  197. begin
  198. if (AColId - 1 >= 0) and (AColId - 1 < lvCallStack.ColumnCount) then begin
  199. ASize := lvCallStack.Column[AColId - 1].Width;
  200. Result := (ASize <> COL_WIDTHS[AColId - 1]) and (not lvCallStack.Column[AColId - 1].AutoSize);
  201. end
  202. else
  203. Result := False;
  204. end;
  205. procedure TCallStackDlg.ColSizeSetter(AColId: Integer; ASize: Integer);
  206. begin
  207. case AColId of
  208. COL_STACK_BRKPOINT: lvCallStack.Column[0].Width := TWidth(ASize);
  209. COL_STACK_INDEX: lvCallStack.Column[1].Width := TWidth(ASize);
  210. COL_STACK_SOURCE: lvCallStack.Column[2].Width := TWidth(ASize);
  211. COL_STACK_LINE: lvCallStack.Column[3].Width := TWidth(ASize);
  212. COL_STACK_FUNC: lvCallStack.Column[4].Width := TWidth(ASize);
  213. end;
  214. end;
  215. function TCallStackDlg.GetImageIndex(Entry: TIdeCallStackEntry): Integer;
  216. function GetBreakPoint(Entry: TIdeCallStackEntry): TIDEBreakPoint; inline;
  217. var
  218. FileName: String;
  219. begin
  220. Result := nil;
  221. if BreakPoints = nil then Exit;
  222. if DebugBoss.GetFullFilename(Entry.UnitInfo, FileName, False)
  223. then Result := BreakPoints.Find(FileName, Entry.Line);
  224. end;
  225. begin
  226. Result := GetBreakPointImageIndex(GetBreakPoint(Entry), Entry.IsCurrent);
  227. if Result >= 0
  228. then exit;
  229. if Entry.Source = ''
  230. then Result := imgNoSourceLine
  231. else Result := imgSourceLine;
  232. end;
  233. procedure TCallStackDlg.UpdateView;
  234. function LastDelimPos(const FileName: string): Integer;
  235. begin
  236. Result := Length(FileName);
  237. if FileName[Result] in ['/', '\'] then
  238. exit(-1);
  239. while (Result > 0) and not (FileName[Result] in ['/', '\']) do
  240. Dec(Result);
  241. end;
  242. var
  243. i, n: Integer;
  244. Item: TListItem;
  245. Entry: TIdeCallStackEntry;
  246. First, Count, MaxCnt: Integer;
  247. Source: String;
  248. Snap: TSnapshot;
  249. CStack: TIdeCallStack;
  250. begin
  251. if (not ToolButtonPower.Down) or FInUpdateView then exit;
  252. if IsUpdating then begin
  253. DebugLn(DBG_DATA_MONITORS, ['DebugDataWindow: TCallStackDlg.UpdateView in IsUpdating']);
  254. Include(FUpdateFlags, ufNeedUpdating);
  255. exit;
  256. end;
  257. try DebugLnEnter(DBG_DATA_MONITORS, ['DebugDataWindow: >>ENTER: TCallStackDlg.UpdateView']);
  258. Exclude(FUpdateFlags, ufNeedUpdating);
  259. BeginUpdate;
  260. lvCallStack.BeginUpdate;
  261. try
  262. Snap := GetSelectedSnapshot;
  263. if Snap <> nil
  264. then Caption:= lisMenuViewCallStack + ' (' + Snap.LocationAsText + ')'
  265. else Caption:= lisMenuViewCallStack;
  266. FInUpdateView := True; // ignore change triggered by count, if there is a change event, then Count will be updated already
  267. CStack := GetSelectedCallstack;
  268. MaxCnt := FViewStart + FViewLimit + 1;
  269. if CStack <> nil then CStack.CountLimited(MaxCnt); // trigger the update-notification, if executed immediately
  270. FInUpdateView := False;
  271. // TODO: must make CStack ref-counted
  272. if CStack <> GetSelectedCallstack then exit; // Something changed, maybe debugger stopped
  273. if (CStack = nil) or ((Snap <> nil) and (CStack.CountLimited(MaxCnt) = 0)) then begin
  274. lvCallStack.Items.Clear;
  275. Item := lvCallStack.Items.Add;
  276. Item.SubItems.Add('');
  277. Item.SubItems.Add(lisCallStackNotEvaluated);
  278. Item.SubItems.Add('');
  279. Item.SubItems.Add('');
  280. exit;
  281. end;
  282. if (CStack.CountLimited(MaxCnt)=0)
  283. then begin
  284. txtGoto.Text:= '0';
  285. lvCallStack.Items.Clear;
  286. exit;
  287. end;
  288. if Snap <> nil then begin
  289. First := 0;
  290. Count := CStack.CountLimited(MaxCnt);
  291. end else begin
  292. First := FViewStart;
  293. if First + FViewLimit <= CStack.CountLimited(MaxCnt)
  294. then Count := FViewLimit
  295. else Count := CStack.Count - First;
  296. end;
  297. // Reuse entries, so add and remove only
  298. // Remove unneded
  299. for n := lvCallStack.Items.Count - 1 downto Count do
  300. lvCallStack.Items.Delete(n);
  301. // Add needed
  302. for n := lvCallStack.Items.Count to Count - 1 do
  303. begin
  304. Item := lvCallStack.Items.Add;
  305. Item.SubItems.Add('');
  306. Item.SubItems.Add('');
  307. Item.SubItems.Add('');
  308. Item.SubItems.Add('');
  309. end;
  310. FInUpdateView := True;
  311. CStack.PrepareRange(First, Count);
  312. // TODO: must make CStack ref-counted
  313. FInUpdateView := False;
  314. if CStack <> GetSelectedCallstack then exit; // Something changed, maybe debugger stopped
  315. for n := 0 to Count - 1 do
  316. begin
  317. Item := lvCallStack.Items[n];
  318. Entry := CStack.Entries[First + n];
  319. if Entry = nil
  320. then begin
  321. Item.Caption := '';
  322. Item.ImageIndex := imgNoSourceLine;
  323. Item.SubItems[0] := '????';
  324. Item.SubItems[1] := '';
  325. Item.SubItems[2] := '';
  326. Item.SubItems[3] := '';
  327. end
  328. else begin
  329. Item.ImageIndex := GetImageIndex(Entry);
  330. Item.SubItems[0] := IntToStr(Entry.Index);
  331. Source := Entry.Source;
  332. if (Source = '') and (Entry.UnitInfo <> nil) and (Entry.UnitInfo.LocationFullFile <> '') then
  333. Source := Entry.UnitInfo.LocationFullFile;
  334. if Source = '' then // we do not have a source file => just show an adress
  335. Source := ':' + IntToHex(Entry.Address, 8)
  336. else begin
  337. i := LastDelimPos(Source);
  338. if i > 1 then
  339. Source := copy(Source, i+1, length(Source)) + ' (' + copy(Source, 1, i) + ')'
  340. end;
  341. Item.SubItems[1] := Source;
  342. if (Entry.Line = 0) and (Entry.UnitInfo <> nil) and (Entry.UnitInfo.SrcLine > 0) then
  343. Item.SubItems[2] := '~'+IntToStr(Entry.UnitInfo.SrcLine)
  344. else
  345. if Entry.Line > 0 then
  346. Item.SubItems[2] := IntToStr(Entry.Line) // TODO: if editor is open, map line SrcEdit.DebugToSourceLine
  347. else
  348. Item.SubItems[2] := '-';
  349. Item.SubItems[3] := GetFunction(Entry);
  350. end;
  351. end;
  352. finally
  353. FInUpdateView := False;
  354. lvCallStack.EndUpdate;
  355. EndUpdate;
  356. end;
  357. finally DebugLnExit(DBG_DATA_MONITORS, ['DebugDataWindow: <<EXIT: TCallStackDlg.UpdateView']); end;
  358. end;
  359. procedure TCallStackDlg.DoBeginUpdate;
  360. begin
  361. DisableAllActions;
  362. lvCallStack.BeginUpdate;
  363. end;
  364. procedure TCallStackDlg.DoEndUpdate;
  365. begin
  366. if ufNeedUpdating in FUpdateFlags then UpdateView;
  367. lvCallStack.EndUpdate;
  368. EnableAllActions;
  369. end;
  370. procedure TCallStackDlg.DisableAllActions;
  371. var
  372. i: Integer;
  373. begin
  374. for i := 0 to aclActions.ActionCount - 1 do
  375. (aclActions.Actions[i] as TAction).Enabled := False;
  376. end;
  377. procedure TCallStackDlg.EnableAllActions;
  378. var
  379. i: Integer;
  380. Snap: TSnapshot;
  381. begin
  382. for i := 0 to aclActions.ActionCount - 1 do
  383. (aclActions.Actions[i] as TAction).Enabled := True;
  384. Snap := GetSelectedSnapshot;
  385. if snap <> nil then begin
  386. actViewLimit.Enabled := False;
  387. actViewMore.Enabled := False;
  388. end;
  389. ToolButtonPower.Enabled := Snap = nil;
  390. end;
  391. function TCallStackDlg.GetSelectedSnapshot: TSnapshot;
  392. begin
  393. Result := nil;
  394. if (SnapshotManager <> nil) and (SnapshotManager.SelectedEntry <> nil)
  395. then Result := SnapshotManager.SelectedEntry;
  396. end;
  397. function TCallStackDlg.GetSelectedThreads(Snap: TSnapshot): TIdeThreads;
  398. begin
  399. if ThreadsMonitor = nil then exit(nil);
  400. if Snap = nil
  401. then Result := ThreadsMonitor.CurrentThreads
  402. else Result := ThreadsMonitor.Snapshots[Snap];
  403. end;
  404. function TCallStackDlg.GetSelectedCallstack: TIdeCallStack;
  405. var
  406. Snap: TSnapshot;
  407. Threads: TIdeThreads;
  408. tid: LongInt;
  409. begin
  410. if (CallStackMonitor = nil) or (ThreadsMonitor = nil)
  411. then begin
  412. Result := nil;
  413. exit;
  414. end;
  415. Snap := GetSelectedSnapshot;
  416. Threads := GetSelectedThreads(Snap);
  417. // There should always be a thread object
  418. Assert(Threads<>nil, 'TCallStackDlg.GetSelectedCallstack missing thread object');
  419. if Threads <> nil
  420. then tid := Threads.CurrentThreadId
  421. else tid := 1;
  422. if (Snap <> nil)
  423. then Result := CallStackMonitor.Snapshots[Snap].EntriesForThreads[tid]
  424. else Result := CallStackMonitor.CurrentCallStackList.EntriesForThreads[tid];
  425. end;
  426. function TCallStackDlg.GetCurrentEntry: TIdeCallStackEntry;
  427. var
  428. CurItem: TListItem;
  429. idx: Integer;
  430. begin
  431. Result := nil;
  432. if GetSelectedCallstack = nil then Exit;
  433. CurItem := lvCallStack.Selected;
  434. if CurItem = nil then Exit;
  435. idx := FViewStart + CurItem.Index;
  436. if idx >= GetSelectedCallstack.CountLimited(idx+1) then Exit;
  437. Result := GetSelectedCallstack.Entries[idx];
  438. end;
  439. procedure TCallStackDlg.JumpToSource;
  440. var
  441. Entry: TIdeCallStackEntry;
  442. begin
  443. Entry := GetCurrentEntry;
  444. if Entry = nil then Exit;
  445. JumpToUnitSource(Entry.UnitInfo, Entry.Line);
  446. end;
  447. procedure TCallStackDlg.CopyToClipBoard;
  448. var
  449. n: integer;
  450. Entry: TIdeCallStackEntry;
  451. S: String;
  452. begin
  453. Clipboard.Clear;
  454. if (GetSelectedCallstack=nil) or (GetSelectedCallstack.Count=0) then exit;
  455. S := '';
  456. // GetSelectedCallstack.PrepareRange();
  457. for n:= 0 to GetSelectedCallstack.Count-1 do
  458. begin
  459. Entry:=GetSelectedCallstack.Entries[n];
  460. if Entry <> nil
  461. then S := S + format('#%d %s at %s:%d', [n, GetFunction(Entry), Entry.Source, Entry.Line])
  462. else S := S + format('#%d ????', [n]);
  463. S := S + LineEnding;
  464. end;
  465. ClipBoard.AsText := S;
  466. end;
  467. procedure TCallStackDlg.ToggleBreakpoint(Item: TListItem);
  468. var
  469. idx: Integer;
  470. Entry: TIdeCallStackEntry;
  471. BreakPoint: TIDEBreakPoint;
  472. FileName: String;
  473. Ctrl: Boolean;
  474. begin
  475. Ctrl := ssCtrl in GetKeyShiftState;
  476. try
  477. DisableAllActions;
  478. if (Item <> nil) and (BreakPoints <> nil) then
  479. begin
  480. GetSelectedCallstack.CountLimited(FViewStart + FViewLimit + 1); // get max limit
  481. idx := FViewStart + Item.Index;
  482. if idx >= GetSelectedCallstack.CountLimited(idx+1) then Exit;
  483. Entry := GetSelectedCallstack.Entries[idx];
  484. if Entry.Line <= 0 then exit;
  485. if not DebugBoss.GetFullFilename(Entry.UnitInfo, FileName, False) then
  486. Exit;
  487. BreakPoint := BreakPoints.Find(FileName, Entry.Line);
  488. if BreakPoint <> nil then begin
  489. if Ctrl
  490. then BreakPoint.Enabled := not BreakPoint.Enabled
  491. else DebugBoss.DoDeleteBreakPoint(BreakPoint.Source, BreakPoint.Line)
  492. end else begin
  493. DebugBoss.LockCommandProcessing;
  494. try
  495. DebugBoss.DoCreateBreakPoint(FileName, Entry.Line, False, BreakPoint);
  496. if Ctrl and (BreakPoint <> nil)
  497. then BreakPoint.Enabled := False;
  498. finally
  499. DebugBoss.UnLockCommandProcessing;
  500. end;
  501. end;
  502. end;
  503. finally
  504. EnableAllActions;
  505. end;
  506. end;
  507. procedure TCallStackDlg.DoBreakPointsChanged;
  508. begin
  509. UpdateView;
  510. end;
  511. procedure TCallStackDlg.lvCallStackDBLCLICK(Sender: TObject);
  512. begin
  513. JumpToSource;
  514. end;
  515. procedure TCallStackDlg.popCountClick(Sender: TObject);
  516. begin
  517. if FViewCount = TMenuItem(Sender).Tag then Exit;
  518. FViewCount := TMenuItem(Sender).Tag;
  519. ViewLimit := FViewCount;
  520. EnvironmentOptions.DebuggerConfig.DlgCallStackConfig.ViewCount := FViewCount;
  521. actViewLimit.Caption := TMenuItem(Sender).Caption;
  522. end;
  523. procedure TCallStackDlg.ToolButtonPowerClick(Sender: TObject);
  524. begin
  525. if ToolButtonPower.Down
  526. then begin
  527. ToolButtonPower.ImageIndex := FPowerImgIdx;
  528. UpdateView;
  529. end
  530. else ToolButtonPower.ImageIndex := FPowerImgIdxGrey;
  531. end;
  532. procedure TCallStackDlg.txtGotoKeyPress(Sender: TObject; var Key: char);
  533. begin
  534. case Key of
  535. '0'..'9', #8 : ;
  536. #13 : SetViewStart(StrToIntDef(txtGoto.Text, 0));
  537. else
  538. Key := #0;
  539. end;
  540. end;
  541. procedure TCallStackDlg.actCopyAllClick(Sender: TObject);
  542. begin
  543. CopyToClipBoard;
  544. end;
  545. procedure TCallStackDlg.actSetAsCurrentClick(Sender : TObject);
  546. var
  547. Entry: TIdeCallStackEntry;
  548. begin
  549. try
  550. DisableAllActions;
  551. Entry := GetCurrentEntry;
  552. if Entry = nil then Exit;
  553. GetSelectedCallstack.ChangeCurrentIndex(Entry.Index);
  554. if GetSelectedSnapshot <> nil
  555. then CallStackMonitor.NotifyCurrent; // TODO: move to snapshot callstack object
  556. finally
  557. EnableAllActions;
  558. end;
  559. end;
  560. procedure TCallStackDlg.actShowClick(Sender: TObject);
  561. begin
  562. JumpToSource;
  563. end;
  564. procedure TCallStackDlg.actViewBottomExecute(Sender: TObject);
  565. begin
  566. try
  567. DisableAllActions;
  568. if GetSelectedCallstack <> nil
  569. then SetViewStart(GetSelectedCallstack.Count - FViewLimit)
  570. else SetViewStart(0);
  571. finally
  572. EnableAllActions;
  573. end;
  574. end;
  575. procedure TCallStackDlg.actToggleBreakPointExecute(Sender: TObject);
  576. begin
  577. ToggleBreakpoint(lvCallStack.Selected);
  578. end;
  579. procedure TCallStackDlg.actShowDisassExecute(Sender: TObject);
  580. var
  581. Entry: TIdeCallStackEntry;
  582. begin
  583. Entry := GetCurrentEntry;
  584. if (Entry = nil) or (Entry.Address = 0) then Exit;
  585. DebugBoss.ViewDisassembler(Entry.Address);
  586. end;
  587. procedure TCallStackDlg.actViewGotoExecute(Sender: TObject);
  588. begin
  589. try
  590. DisableAllActions;
  591. SetViewStart(StrToIntDef(txtGoto.Text, 0));
  592. finally
  593. EnableAllActions;
  594. end;
  595. end;
  596. procedure TCallStackDlg.actViewMoreExecute(Sender: TObject);
  597. begin
  598. try
  599. DisableAllActions;
  600. ToolButtonPower.Down := True;
  601. ToolButtonPowerClick(nil);
  602. ViewLimit := ViewLimit + FViewCount;
  603. finally
  604. EnableAllActions;
  605. end;
  606. end;
  607. procedure TCallStackDlg.actViewTopExecute(Sender: TObject);
  608. begin
  609. try
  610. DisableAllActions;
  611. ToolButtonPower.Down := True;
  612. ToolButtonPowerClick(nil);
  613. SetViewStart(0);
  614. finally
  615. EnableAllActions;
  616. end;
  617. end;
  618. procedure TCallStackDlg.BreakPointChanged(const ASender: TIDEBreakPoints;
  619. const ABreakpoint: TIDEBreakPoint);
  620. var
  621. i, idx: Integer;
  622. Entry: TIdeCallStackEntry;
  623. Stack: TIdeCallStack;
  624. begin
  625. DebugLn(DBG_DATA_MONITORS, ['DebugDataWindow: TCallStackDlg.BreakPointChanged ', DbgSName(ASender), ' Upd:', IsUpdating]);
  626. Stack := GetSelectedCallstack;
  627. if (BreakPoints = nil) or (Stack = nil) then
  628. Exit;
  629. Stack.CountLimited(FViewStart + FViewLimit + 1);
  630. for i := 0 to lvCallStack.Items.Count - 1 do
  631. begin
  632. idx := FViewStart + lvCallStack.Items[i].Index;
  633. if idx >= Stack.CountLimited(idx+1) then
  634. Continue;
  635. Entry := Stack.Entries[idx];
  636. if Entry <> nil then
  637. lvCallStack.Items[i].ImageIndex := GetImageIndex(Entry)
  638. else
  639. lvCallStack.Items[i].ImageIndex := imgNoSourceLine;
  640. end;
  641. end;
  642. procedure TCallStackDlg.FormCreate(Sender: TObject);
  643. var
  644. i: integer;
  645. curPopLimit: TMenuItem;
  646. begin
  647. Caption := lisMenuViewCallStack;
  648. ToolButtonPower.Caption := lisDbgWinPower;
  649. ToolButtonPower.Hint := lisDbgWinPowerHint;
  650. for i:= 0 to mnuLimit.Items.Count-1 do
  651. mnuLimit.Items[i].Caption:= Format(lisMaxS, [mnuLimit.Items[i].Tag]);
  652. actViewMore.Caption := lisMore;
  653. actViewTop.Caption := lisCSTop;
  654. actViewBottom.Caption := lisCSBottom;
  655. actViewGoto.Caption := lisGotoSelected;
  656. actShow.Caption := lisViewSource;
  657. actShowDisass.Caption := lisViewSourceDisass;
  658. actToggleBreakPoint.Caption := uemToggleBreakpoint;
  659. actSetCurrent.Caption := lisCurrent;
  660. actCopyAll.Caption := lisCopyAll;
  661. FViewCount := EnvironmentOptions.DebuggerConfig.DlgCallStackConfig.ViewCount;
  662. curPopLimit := nil;
  663. for i := 0 to mnuLimit.Items.Count-1 do
  664. if mnuLimit.Items[i].Tag = FViewCount then
  665. begin
  666. curPopLimit := mnuLimit.Items[i];
  667. Break;
  668. end;
  669. if curPopLimit=nil then
  670. curPopLimit := popLimit10;
  671. FViewCount := curPopLimit.Tag;
  672. FViewLimit := FViewCount;
  673. FViewStart := 0;
  674. FInUpdateView := False;
  675. actViewLimit.Caption := curPopLimit.Caption;
  676. ToolButtonMax.Caption := actViewLimit.Caption;
  677. lvCallStack.Columns[1].Caption:= lisIndex;
  678. lvCallStack.Columns[2].Caption:= histdlgColumnLoc;
  679. lvCallStack.Columns[3].Caption:= dlgAddHiAttrGroupLine;
  680. lvCallStack.Columns[4].Caption:= lisFunction;
  681. ToolBar1.Images := IDEImages.Images_16;
  682. ToolButtonShow.ImageIndex := IDEImages.LoadImage(16, 'callstack_show');
  683. ToolButtonMore.ImageIndex := IDEImages.LoadImage(16, 'callstack_more');
  684. ToolButtonTop.ImageIndex := IDEImages.LoadImage(16, 'callstack_top');
  685. ToolButtonBottom.ImageIndex := IDEImages.LoadImage(16, 'callstack_bottom');
  686. ToolButtonGoto.ImageIndex := IDEImages.LoadImage(16, 'callstack_goto');
  687. ToolButtonCopyAll.ImageIndex := IDEImages.LoadImage(16, 'laz_copy');
  688. FPowerImgIdx := IDEImages.LoadImage(16, 'debugger_power');
  689. FPowerImgIdxGrey := IDEImages.LoadImage(16, 'debugger_power_grey');
  690. ToolButtonPower.ImageIndex := FPowerImgIdx;
  691. lvCallStack.SmallImages := IDEImages.Images_16;
  692. imgSourceLine := IDEImages.LoadImage(16, 'debugger_source_line');
  693. imgNoSourceLine := IDEImages.LoadImage(16, 'debugger_nosource_line');
  694. end;
  695. procedure TCallStackDlg.lvCallStackClick(Sender: TObject);
  696. var
  697. P: TPoint;
  698. Item: TListItem;
  699. begin
  700. // toggle breakpoint
  701. P := lvCallStack.ScreenToClient(Mouse.CursorPos);
  702. Item := lvCallStack.GetItemAt(P.X, P.Y);
  703. // if clicked on the first column of a valid item
  704. if (Item <> nil) and (P.X <= lvCallStack.Column[0].Width) then
  705. ToggleBreakPoint(Item);
  706. end;
  707. procedure TCallStackDlg.actViewLimitExecute(Sender: TObject);
  708. begin
  709. try
  710. DisableAllActions;
  711. ToolButtonPower.Down := True;
  712. ToolButtonPowerClick(nil);
  713. ViewLimit := FViewCount;
  714. finally
  715. EnableAllActions;
  716. end;
  717. end;
  718. procedure TCallStackDlg.SetViewStart(AStart: Integer);
  719. begin
  720. if GetSelectedCallstack = nil then Exit;
  721. ToolButtonPower.Down := True;
  722. ToolButtonPowerClick(nil);
  723. if (AStart > GetSelectedCallstack.CountLimited(AStart+FViewLimit+1) - FViewLimit)
  724. then AStart := GetSelectedCallstack.Count - FViewLimit;
  725. if AStart < 0 then AStart := 0;
  726. if FViewStart = AStart then Exit;
  727. FViewStart:= AStart;
  728. txtGoto.Text:= IntToStr(AStart);
  729. UpdateView;
  730. end;
  731. procedure TCallStackDlg.SetViewMax;
  732. begin
  733. // If GetSelectedCallstack = nil
  734. // then lblViewCnt.Caption:= '0'
  735. // else lblViewCnt.Caption:= IntToStr(GetSelectedCallstack.Count);
  736. end;
  737. procedure TCallStackDlg.SetViewLimit(const AValue: Integer);
  738. begin
  739. ToolButtonPower.Down := True;
  740. ToolButtonPowerClick(nil);
  741. if FViewLimit = AValue then Exit;
  742. if (GetSelectedCallstack <> nil)
  743. and (FViewStart + FViewLimit >= GetSelectedCallstack.CountLimited(FViewStart + FViewLimit+1))
  744. and (AValue > FViewLimit)
  745. then begin
  746. FViewStart := GetSelectedCallstack.Count - AValue;
  747. if FViewStart < 0 then FViewStart := 0;
  748. end;
  749. FViewLimit := AValue;
  750. UpdateView;
  751. end;
  752. function TCallStackDlg.GetFunction(const Entry: TIdeCallStackEntry): string;
  753. begin
  754. Result := Entry.GetFunctionWithArg;
  755. end;
  756. procedure TCallStackDlg.GotoIndex(AIndex: Integer);
  757. begin
  758. if AIndex < 0 then Exit;
  759. if AIndex >= GetSelectedCallstack.CountLimited(AIndex+1) then Exit;
  760. end;
  761. initialization
  762. CallStackDlgWindowCreator := IDEWindowCreators.Add(DebugDialogNames[ddtCallStack]);
  763. CallStackDlgWindowCreator.OnCreateFormProc := @CreateDebugDialog;
  764. CallStackDlgWindowCreator.OnSetDividerSize := @CallStackDlgColSizeSetter;
  765. CallStackDlgWindowCreator.OnGetDividerSize := @CallStackDlgColSizeGetter;
  766. CallStackDlgWindowCreator.DividerTemplate.Add('ColumnCStackBrkPoint', COL_STACK_BRKPOINT, @drsColWidthBrkPointImg);
  767. CallStackDlgWindowCreator.DividerTemplate.Add('ColumnCStackIndex', COL_STACK_INDEX, @drsColWidthIndex);
  768. CallStackDlgWindowCreator.DividerTemplate.Add('ColumnCStackSource', COL_STACK_SOURCE, @drsColWidthSource);
  769. CallStackDlgWindowCreator.DividerTemplate.Add('ColumnCStackLine', COL_STACK_LINE, @drsColWidthLine);
  770. CallStackDlgWindowCreator.DividerTemplate.Add('ColumnCStackFunc', COL_STACK_FUNC, @drsColWidthFunc);
  771. CallStackDlgWindowCreator.CreateSimpleLayout;
  772. DBG_DATA_MONITORS := DebugLogger.FindOrRegisterLogGroup('DBG_DATA_MONITORS' {$IFDEF DBG_DATA_MONITORS} , True {$ENDIF} );
  773. end.