/debugger/registersdlg.pp

http://github.com/graemeg/lazarus · Puppet · 469 lines · 408 code · 61 blank · 0 comment · 32 complexity · 5420d4519d66d77061c76eafcbb5b7f4 MD5 · raw file

  1. { $Id$ }
  2. { ----------------------------------------------
  3. registersdlg.pp - Overview of registers
  4. ----------------------------------------------
  5. @created(Sun Nov 16th WET 2008)
  6. @lastmod($Date$)
  7. @author(Marc Weustink <marc@@dommelstein.net>)
  8. This unit contains the registers 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 RegistersDlg;
  29. {$mode objfpc}{$H+}
  30. interface
  31. uses
  32. SysUtils, Classes, Controls, Forms, Clipbrd,
  33. BaseDebugManager, IDEWindowIntf, DebuggerStrConst,
  34. ComCtrls, ActnList, Menus, Debugger, DebuggerDlg,
  35. LazarusIDEStrConsts, IDEImagesIntf, DbgIntfDebuggerBase;
  36. type
  37. { TRegistersDlg }
  38. TRegistersDlg = class(TDebuggerDlg)
  39. actCopyName: TAction;
  40. actCopyValue: TAction;
  41. actPower: TAction;
  42. ActionList1: TActionList;
  43. ImageList1: TImageList;
  44. lvRegisters: TListView;
  45. DispDefault: TMenuItem;
  46. DispHex: TMenuItem;
  47. DispBin: TMenuItem;
  48. DispOct: TMenuItem;
  49. DispDec: TMenuItem;
  50. DispRaw: TMenuItem;
  51. PopDispDefault: TMenuItem;
  52. PopDispHex: TMenuItem;
  53. PopDispBin: TMenuItem;
  54. PopDispOct: TMenuItem;
  55. PopDispDec: TMenuItem;
  56. PopDispRaw: TMenuItem;
  57. popCopyValue: TMenuItem;
  58. popCopyName: TMenuItem;
  59. popFormat: TMenuItem;
  60. popL1: TMenuItem;
  61. PopupDispType: TPopupMenu;
  62. PopupMenu1: TPopupMenu;
  63. ToolBar1: TToolBar;
  64. ToolButton1: TToolButton;
  65. ToolButtonDispType: TToolButton;
  66. ToolButtonPower: TToolButton;
  67. procedure actCopyNameExecute(Sender: TObject);
  68. procedure actCopyValueExecute(Sender: TObject);
  69. procedure actPowerExecute(Sender: TObject);
  70. procedure DispDefaultClick(Sender: TObject);
  71. procedure lvRegistersSelectItem(Sender: TObject; Item: TListItem; {%H-}Selected: Boolean);
  72. procedure ToolButtonDispTypeClick(Sender: TObject);
  73. function GetCurrentRegisters: TRegisters;
  74. private
  75. FNeedUpdateAgain: Boolean;
  76. FPowerImgIdx, FPowerImgIdxGrey: Integer;
  77. procedure RegistersChanged(Sender: TObject);
  78. protected
  79. procedure DoRegistersChanged; override;
  80. procedure DoBeginUpdate; override;
  81. procedure DoEndUpdate; override;
  82. function ColSizeGetter(AColId: Integer; var ASize: Integer): Boolean;
  83. procedure ColSizeSetter(AColId: Integer; ASize: Integer);
  84. public
  85. constructor Create(AOwner: TComponent); override;
  86. destructor Destroy; override;
  87. property RegistersMonitor;
  88. property ThreadsMonitor;
  89. property CallStackMonitor;
  90. //property SnapshotManager;
  91. end;
  92. implementation
  93. {$R *.lfm}
  94. var
  95. RegisterDlgWindowCreator: TIDEWindowCreator;
  96. const
  97. COL_REGISTER_NAME = 1;
  98. COL_REGISTER_VALUE = 2;
  99. COL_WIDTHS: Array[0..1] of integer = ( 150, 50);
  100. function RegisterDlgColSizeGetter(AForm: TCustomForm; AColId: Integer; var ASize: Integer): Boolean;
  101. begin
  102. Result := AForm is TRegistersDlg;
  103. if Result then
  104. Result := TRegistersDlg(AForm).ColSizeGetter(AColId, ASize);
  105. end;
  106. procedure RegisterDlgColSizeSetter(AForm: TCustomForm; AColId: Integer; ASize: Integer);
  107. begin
  108. if AForm is TRegistersDlg then
  109. TRegistersDlg(AForm).ColSizeSetter(AColId, ASize);
  110. end;
  111. { TRegistersDlg }
  112. constructor TRegistersDlg.Create(AOwner: TComponent);
  113. var
  114. i: Integer;
  115. begin
  116. inherited Create(AOwner);
  117. ThreadsNotification.OnCurrent := @RegistersChanged;
  118. CallstackNotification.OnCurrent := @RegistersChanged;
  119. RegistersNotification.OnChange := @RegistersChanged;
  120. Caption:= lisRegisters;
  121. lvRegisters.Columns[0].Caption:= lisName;
  122. lvRegisters.Columns[1].Caption:= lisValue;
  123. ActionList1.Images := IDEImages.Images_16;
  124. ToolBar1.Images := IDEImages.Images_16;
  125. FPowerImgIdx := IDEImages.LoadImage(16, 'debugger_power');
  126. FPowerImgIdxGrey := IDEImages.LoadImage(16, 'debugger_power_grey');
  127. actPower.ImageIndex := FPowerImgIdx;
  128. //actPower.Caption := lisDbgWinPower;
  129. actPower.Hint := lisDbgWinPowerHint;
  130. actCopyName.Caption := lisLocalsDlgCopyName;
  131. actCopyValue.Caption := lisLocalsDlgCopyValue;
  132. ToolButtonDispType.Hint := regdlgDisplayTypeForSelectedRegisters;
  133. DispDefault.Caption := dlgPasStringKeywordsOptDefault;
  134. DispHex.Caption := regdlgHex;
  135. DispBin.Caption := regdlgBinary;
  136. DispOct.Caption := regdlgOctal;
  137. DispDec.Caption := regdlgDecimal;
  138. DispRaw.Caption := regdlgRaw;
  139. DispDefault.Tag := ord(rdDefault);
  140. DispHex.Tag := ord(rdHex);
  141. DispBin.Tag := ord(rdBinary);
  142. DispOct.Tag := ord(rdOctal);
  143. DispDec.Tag := ord(rdDecimal);
  144. DispRaw.Tag := ord(rdRaw);
  145. PopDispDefault.Caption := dlgPasStringKeywordsOptDefault;
  146. PopDispHex.Caption := regdlgHex;
  147. PopDispBin.Caption := regdlgBinary;
  148. PopDispOct.Caption := regdlgOctal;
  149. PopDispDec.Caption := regdlgDecimal;
  150. PopDispRaw.Caption := regdlgRaw;
  151. PopDispDefault.Tag := ord(rdDefault);
  152. PopDispHex.Tag := ord(rdHex);
  153. PopDispBin.Tag := ord(rdBinary);
  154. PopDispOct.Tag := ord(rdOctal);
  155. PopDispDec.Tag := ord(rdDecimal);
  156. PopDispRaw.Tag := ord(rdRaw);
  157. popFormat.Caption := regdlgFormat;
  158. actCopyName.Caption := lisLocalsDlgCopyName;
  159. actCopyValue.Caption := lisLocalsDlgCopyValue;
  160. for i := low(COL_WIDTHS) to high(COL_WIDTHS) do
  161. lvRegisters.Column[i].Width := COL_WIDTHS[i];
  162. end;
  163. destructor TRegistersDlg.Destroy;
  164. begin
  165. inherited Destroy;
  166. end;
  167. procedure TRegistersDlg.actPowerExecute(Sender: TObject);
  168. begin
  169. if ToolButtonPower.Down
  170. then begin
  171. actPower.ImageIndex := FPowerImgIdx;
  172. ToolButtonPower.ImageIndex := FPowerImgIdx;
  173. RegistersChanged(nil);
  174. end
  175. else begin
  176. actPower.ImageIndex := FPowerImgIdxGrey;
  177. ToolButtonPower.ImageIndex := FPowerImgIdxGrey;
  178. end;
  179. end;
  180. procedure TRegistersDlg.actCopyNameExecute(Sender: TObject);
  181. begin
  182. Clipboard.Open;
  183. Clipboard.AsText := lvRegisters.Selected.Caption;
  184. Clipboard.Close;
  185. end;
  186. procedure TRegistersDlg.actCopyValueExecute(Sender: TObject);
  187. begin
  188. Clipboard.Open;
  189. Clipboard.AsText := lvRegisters.Selected.SubItems[0];
  190. Clipboard.Close;
  191. end;
  192. procedure TRegistersDlg.DispDefaultClick(Sender: TObject);
  193. var
  194. n: Integer;
  195. Item: TListItem;
  196. Reg: TRegisters;
  197. RegVal: TRegisterValue;
  198. begin
  199. ToolButtonPower.Down := True;
  200. Reg := GetCurrentRegisters;
  201. if Reg = nil then exit;
  202. for n := 0 to lvRegisters.Items.Count -1 do
  203. begin
  204. Item := lvRegisters.Items[n];
  205. if Item.Selected then begin
  206. RegVal := Reg.EntriesByName[Item.Caption];
  207. if RegVal <> nil then
  208. RegVal.DisplayFormat := TRegisterDisplayFormat(TMenuItem(Sender).Tag);
  209. end;
  210. end;
  211. lvRegistersSelectItem(nil, nil, True);
  212. end;
  213. procedure TRegistersDlg.lvRegistersSelectItem(Sender: TObject; Item: TListItem;
  214. Selected: Boolean);
  215. var
  216. n, j: Integer;
  217. SelFormat: TRegisterDisplayFormat;
  218. MultiFormat: Boolean;
  219. Reg: TRegisters;
  220. RegVal: TRegisterValue;
  221. begin
  222. j := 0;
  223. MultiFormat := False;
  224. SelFormat := rdDefault;
  225. Reg := GetCurrentRegisters;
  226. if Reg = nil then exit;
  227. for n := 0 to lvRegisters.Items.Count -1 do
  228. begin
  229. Item := lvRegisters.Items[n];
  230. if Item.Selected then begin
  231. RegVal := Reg.EntriesByName[Item.Caption];
  232. if RegVal <> nil then begin
  233. if j = 0
  234. then SelFormat := RegVal.DisplayFormat;
  235. inc(j);
  236. if SelFormat <> RegVal.DisplayFormat then begin
  237. MultiFormat := True;
  238. break;
  239. end;
  240. end;
  241. end;
  242. end;
  243. ToolButtonDispType.Enabled := j > 0;
  244. popFormat.Enabled := j > 0;
  245. actCopyName.Enabled := j > 0;
  246. actCopyValue.Enabled := j > 0;
  247. PopDispDefault.Checked := False;
  248. PopDispHex.Checked := False;
  249. PopDispBin.Checked := False;
  250. PopDispOct.Checked := False;
  251. PopDispDec.Checked := False;
  252. PopDispRaw.Checked := False;
  253. if MultiFormat
  254. then ToolButtonDispType.Caption := '...'
  255. else begin
  256. case SelFormat of
  257. rdDefault: begin
  258. ToolButtonDispType.Caption := DispDefault.Caption;
  259. PopDispDefault.Checked := True;
  260. end;
  261. rdHex: begin
  262. ToolButtonDispType.Caption := DispHex.Caption;
  263. PopDispHex.Checked := True;
  264. end;
  265. rdBinary: begin
  266. ToolButtonDispType.Caption := DispBin.Caption;
  267. PopDispBin.Checked := True;
  268. end;
  269. rdOctal: begin
  270. ToolButtonDispType.Caption := DispOct.Caption;
  271. PopDispOct.Checked := True;
  272. end;
  273. rdDecimal: begin
  274. ToolButtonDispType.Caption := DispDec.Caption;
  275. PopDispDec.Checked := True;
  276. end;
  277. rdRaw: begin
  278. ToolButtonDispType.Caption := DispRaw.Caption;
  279. PopDispRaw.Checked := True;
  280. end;
  281. end;
  282. end;
  283. end;
  284. procedure TRegistersDlg.ToolButtonDispTypeClick(Sender: TObject);
  285. begin
  286. ToolButtonDispType.CheckMenuDropdown;
  287. end;
  288. function TRegistersDlg.GetCurrentRegisters: TRegisters;
  289. var
  290. CurThreadId, CurStackFrame: Integer;
  291. begin
  292. Result := nil;
  293. if (ThreadsMonitor = nil) or
  294. (ThreadsMonitor.CurrentThreads = nil) or
  295. (CallStackMonitor = nil) or
  296. (CallStackMonitor.CurrentCallStackList = nil) or
  297. (RegistersMonitor = nil)
  298. then
  299. exit;
  300. CurThreadId := ThreadsMonitor.CurrentThreads.CurrentThreadId;
  301. if (CallStackMonitor.CurrentCallStackList.EntriesForThreads[CurThreadId] = nil) then
  302. exit;
  303. CurStackFrame := CallStackMonitor.CurrentCallStackList.EntriesForThreads[CurThreadId].CurrentIndex;
  304. Result := RegistersMonitor.CurrentRegistersList[CurThreadId, CurStackFrame];
  305. end;
  306. procedure TRegistersDlg.RegistersChanged(Sender: TObject);
  307. var
  308. n, idx, Cnt: Integer;
  309. List: TStringList;
  310. Item: TListItem;
  311. S: String;
  312. Reg: TRegisters;
  313. begin
  314. if (not ToolButtonPower.Down) then exit;
  315. if IsUpdating then begin
  316. FNeedUpdateAgain := True;
  317. exit;
  318. end;
  319. FNeedUpdateAgain := False;
  320. Reg := GetCurrentRegisters;
  321. if Reg = nil then begin
  322. lvRegisters.Items.Clear;
  323. exit;
  324. end;
  325. List := TStringList.Create;
  326. try
  327. BeginUpdate;
  328. try
  329. //Get existing items
  330. for n := 0 to lvRegisters.Items.Count - 1 do
  331. begin
  332. Item := lvRegisters.Items[n];
  333. S := Item.Caption;
  334. S := UpperCase(S);
  335. List.AddObject(S, Item);
  336. end;
  337. // add/update entries
  338. Cnt := Reg.Count; // Count may trigger changes
  339. FNeedUpdateAgain := False; // changes after this point, and we must update again
  340. for n := 0 to Cnt - 1 do
  341. begin
  342. idx := List.IndexOf(Uppercase(Reg[n].Name));
  343. if idx = -1
  344. then begin
  345. // New entry
  346. Item := lvRegisters.Items.Add;
  347. Item.Caption := Reg[n].Name;
  348. Item.SubItems.Add(Reg[n].Value);
  349. end
  350. else begin
  351. // Existing entry
  352. Item := TListItem(List.Objects[idx]);
  353. Item.SubItems[0] := Reg[n].Value;
  354. List.Delete(idx);
  355. end;
  356. if Reg[n].Modified
  357. then Item.ImageIndex := 0
  358. else Item.ImageIndex := -1;
  359. end;
  360. // remove obsolete entries
  361. for n := 0 to List.Count - 1 do
  362. lvRegisters.Items.Delete(TListItem(List.Objects[n]).Index);
  363. finally
  364. EndUpdate;
  365. end;
  366. finally
  367. List.Free;
  368. end;
  369. lvRegistersSelectItem(nil, nil, True);
  370. end;
  371. procedure TRegistersDlg.DoRegistersChanged;
  372. begin
  373. RegistersChanged(nil);
  374. end;
  375. procedure TRegistersDlg.DoBeginUpdate;
  376. begin
  377. lvRegisters.BeginUpdate;
  378. end;
  379. procedure TRegistersDlg.DoEndUpdate;
  380. begin
  381. lvRegisters.EndUpdate;
  382. if FNeedUpdateAgain then RegistersChanged(nil);
  383. end;
  384. function TRegistersDlg.ColSizeGetter(AColId: Integer; var ASize: Integer): Boolean;
  385. begin
  386. if (AColId - 1 >= 0) and (AColId - 1 < lvRegisters.ColumnCount) then begin
  387. ASize := lvRegisters.Column[AColId - 1].Width;
  388. Result := ASize <> COL_WIDTHS[AColId - 1];
  389. end
  390. else
  391. Result := False;
  392. end;
  393. procedure TRegistersDlg.ColSizeSetter(AColId: Integer; ASize: Integer);
  394. begin
  395. case AColId of
  396. COL_REGISTER_NAME: lvRegisters.Column[0].Width := ASize;
  397. COL_REGISTER_VALUE: lvRegisters.Column[1].Width := ASize;
  398. end;
  399. end;
  400. initialization
  401. RegisterDlgWindowCreator := IDEWindowCreators.Add(DebugDialogNames[ddtRegisters]);
  402. RegisterDlgWindowCreator.OnCreateFormProc := @CreateDebugDialog;
  403. RegisterDlgWindowCreator.OnSetDividerSize := @RegisterDlgColSizeSetter;
  404. RegisterDlgWindowCreator.OnGetDividerSize := @RegisterDlgColSizeGetter;
  405. RegisterDlgWindowCreator.DividerTemplate.Add('RegisterName', COL_REGISTER_NAME, @drsColWidthName);
  406. RegisterDlgWindowCreator.DividerTemplate.Add('RegisterValue', COL_REGISTER_VALUE, @drsColWidthValue);
  407. RegisterDlgWindowCreator.CreateSimpleLayout;
  408. end.