Source code of Windows XP (NT5)
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

580 lines
14 KiB

  1. /*++
  2. Copyright (c) 1992-2001 Microsoft Corporation
  3. Module Name:
  4. callswin.cpp
  5. Abstract:
  6. This module contains the main line code for display of calls window.
  7. Environment:
  8. Win32, User Mode
  9. --*/
  10. #include "precomp.hxx"
  11. #pragma hdrstop
  12. #define MIN_FRAMES 10
  13. #define MORE_LESS 10
  14. #define CALLS_CONTEXT_ID_BASE 0x100
  15. #define TBB_MORE 9
  16. #define TBB_LESS 10
  17. // The IDs of the buttons are the bit shift of the
  18. // corresponding flag.
  19. TBBUTTON g_CallsTbButtons[] =
  20. {
  21. TEXT_TB_BTN(0, "Args", BTNS_CHECK),
  22. TEXT_TB_BTN(1, "Func info", BTNS_CHECK),
  23. TEXT_TB_BTN(2, "Source", BTNS_CHECK),
  24. TEXT_TB_BTN(3, "Addrs", BTNS_CHECK),
  25. TEXT_TB_BTN(4, "Headings", BTNS_CHECK),
  26. TEXT_TB_BTN(5, "Nonvolatile regs", BTNS_CHECK),
  27. TEXT_TB_BTN(6, "Frame nums", BTNS_CHECK),
  28. TEXT_TB_BTN(7, "Arg types", BTNS_CHECK),
  29. SEP_TB_BTN(),
  30. TEXT_TB_BTN(TBB_MORE, "More", 0),
  31. TEXT_TB_BTN(TBB_LESS, "Less", 0),
  32. SEP_TB_BTN(),
  33. TEXT_TB_BTN(ID_SHOW_TOOLBAR, "Toolbar", 0),
  34. };
  35. #define NUM_CALLS_MENU_BUTTONS \
  36. (sizeof(g_CallsTbButtons) / sizeof(g_CallsTbButtons[0]))
  37. #define NUM_CALLS_TB_BUTTONS \
  38. (NUM_CALLS_MENU_BUTTONS - 2)
  39. HMENU CALLSWIN_DATA::s_ContextMenu;
  40. //
  41. //
  42. //
  43. CALLSWIN_DATA::CALLSWIN_DATA()
  44. : SINGLE_CHILDWIN_DATA(1024)
  45. {
  46. m_enumType = CALLS_WINDOW;
  47. m_Flags = 0;
  48. m_Frames = 20;
  49. m_FramesFound = 0;
  50. m_TextOffset = 0;
  51. }
  52. void
  53. CALLSWIN_DATA::Validate()
  54. {
  55. SINGLE_CHILDWIN_DATA::Validate();
  56. Assert(CALLS_WINDOW == m_enumType);
  57. }
  58. HRESULT
  59. CALLSWIN_DATA::ReadState(void)
  60. {
  61. HRESULT Status;
  62. Empty();
  63. //
  64. // Record the raw frame data first.
  65. //
  66. // Preallocate space to record the raw frames.
  67. if (AddData(sizeof(DEBUG_STACK_FRAME) * m_Frames) == NULL)
  68. {
  69. return E_OUTOFMEMORY;
  70. }
  71. // Allocate a separate buffer to hold the frames while
  72. // calling OutputStackTrace on them. We can't just pass
  73. // in the state buffer pointer as resizing of the state
  74. // buffer may cause the data pointer to change.
  75. PDEBUG_STACK_FRAME RawFrames = (PDEBUG_STACK_FRAME)malloc(m_DataUsed);
  76. if (RawFrames == NULL)
  77. {
  78. return E_OUTOFMEMORY;
  79. }
  80. Status = g_pDbgControl->GetStackTrace(0, 0, 0, RawFrames, m_Frames,
  81. &m_FramesFound);
  82. if (Status != S_OK)
  83. {
  84. free(RawFrames);
  85. return Status;
  86. }
  87. m_TextOffset = m_DataUsed;
  88. g_OutStateBuf.SetBuffer(this);
  89. if ((Status = g_OutStateBuf.Start(FALSE)) != S_OK)
  90. {
  91. return Status;
  92. }
  93. // If nonvolatile registers were requested we can't use just
  94. // our saved frames as they require full context information.
  95. Status = g_pOutCapControl->
  96. OutputStackTrace(DEBUG_OUTCTL_THIS_CLIENT |
  97. DEBUG_OUTCTL_OVERRIDE_MASK |
  98. DEBUG_OUTCTL_NOT_LOGGED,
  99. (m_Flags & DEBUG_STACK_NONVOLATILE_REGISTERS) ?
  100. NULL : RawFrames, m_FramesFound, m_Flags);
  101. if (Status == S_OK)
  102. {
  103. Status = g_OutStateBuf.End(TRUE);
  104. if (Status == S_OK)
  105. {
  106. g_OutStateBuf.ReplaceChar('\n', 0);
  107. }
  108. }
  109. else
  110. {
  111. g_OutStateBuf.End(TRUE);
  112. }
  113. // Now that the state buffer is stable put the raw frame
  114. // data in.
  115. memcpy(m_Data, RawFrames, m_TextOffset);
  116. free(RawFrames);
  117. return Status;
  118. }
  119. void
  120. CALLSWIN_DATA::Copy()
  121. {
  122. LRESULT Line = SendMessage(m_hwndChild, LB_GETCURSEL, 0, 0);
  123. Assert(Line != LB_ERR);
  124. LRESULT Len = SendMessage(m_hwndChild, LB_GETTEXTLEN, Line, 0);
  125. if (Len <= 0)
  126. {
  127. return;
  128. }
  129. Len++;
  130. PSTR Text = (PSTR)malloc(Len);
  131. if (!Text)
  132. {
  133. return;
  134. }
  135. SendMessage(m_hwndChild, LB_GETTEXT, Line, (LPARAM)Text);
  136. Text[Len - 1] = 0;
  137. CopyToClipboard(Text);
  138. free (Text);
  139. return;
  140. }
  141. HMENU
  142. CALLSWIN_DATA::GetContextMenu(void)
  143. {
  144. ULONG i;
  145. //
  146. // We only keep one menu around for all call windows
  147. // so apply the menu check state for this particular
  148. // window.
  149. // In reality there's only one calls window anyway,
  150. // but this is a good example of how to handle
  151. // multi-instance windows.
  152. //
  153. for (i = 0; i < NUM_CALLS_TB_BUTTONS; i++)
  154. {
  155. CheckMenuItem(s_ContextMenu, i + CALLS_CONTEXT_ID_BASE,
  156. MF_BYCOMMAND | ((m_Flags & (1 << i)) ? MF_CHECKED : 0));
  157. }
  158. CheckMenuItem(s_ContextMenu, ID_SHOW_TOOLBAR + CALLS_CONTEXT_ID_BASE,
  159. MF_BYCOMMAND | (m_ShowToolbar ? MF_CHECKED : 0));
  160. return s_ContextMenu;
  161. }
  162. void
  163. CALLSWIN_DATA::OnContextMenuSelection(UINT Item)
  164. {
  165. Item -= CALLS_CONTEXT_ID_BASE;
  166. switch(Item)
  167. {
  168. case TBB_MORE:
  169. m_Frames += MORE_LESS;
  170. break;
  171. case TBB_LESS:
  172. if (m_Frames >= MIN_FRAMES + MORE_LESS)
  173. {
  174. m_Frames -= MORE_LESS;
  175. }
  176. break;
  177. case ID_SHOW_TOOLBAR:
  178. SetShowToolbar(!m_ShowToolbar);
  179. break;
  180. default:
  181. m_Flags ^= 1 << Item;
  182. SyncUiWithFlags(1 << Item);
  183. break;
  184. }
  185. if (g_Workspace != NULL)
  186. {
  187. g_Workspace->AddDirty(WSPF_DIRTY_WINDOWS);
  188. }
  189. UiRequestRead();
  190. }
  191. BOOL
  192. CALLSWIN_DATA::CodeExprAtCaret(PSTR Expr, PULONG64 Offset)
  193. {
  194. BOOL Succ = FALSE;
  195. LRESULT Line = SendMessage(m_hwndChild, LB_GETCURSEL, 0, 0);
  196. // If the column headers are on ignore that line.
  197. if (m_Flags & DEBUG_STACK_COLUMN_NAMES)
  198. {
  199. if (Line == 0)
  200. {
  201. return Succ;
  202. }
  203. else
  204. {
  205. Line--;
  206. }
  207. }
  208. if (Line >= 0 && (ULONG)Line < m_FramesFound)
  209. {
  210. if (UiLockForRead() == S_OK)
  211. {
  212. PDEBUG_STACK_FRAME RawFrames = (PDEBUG_STACK_FRAME)m_Data;
  213. if (Expr != NULL)
  214. {
  215. sprintf(Expr, "0x%I64x", RawFrames[Line].InstructionOffset);
  216. }
  217. if (Offset != NULL)
  218. {
  219. *Offset = RawFrames[Line].InstructionOffset;
  220. }
  221. Succ = TRUE;
  222. UnlockStateBuffer(this);
  223. }
  224. }
  225. return Succ;
  226. }
  227. HRESULT
  228. CALLSWIN_DATA::
  229. StackFrameAtCaret(PDEBUG_STACK_FRAME pFrame)
  230. {
  231. LRESULT Line = SendMessage(m_hwndChild, LB_GETCURSEL, 0, 0);
  232. // If the column headers are on ignore that line.
  233. if (m_Flags & DEBUG_STACK_COLUMN_NAMES)
  234. {
  235. if (Line == 0)
  236. {
  237. return E_INVALIDARG;
  238. }
  239. else
  240. {
  241. Line--;
  242. }
  243. }
  244. if (Line >= 0 && (ULONG)Line < m_FramesFound && pFrame)
  245. {
  246. if (UiLockForRead() == S_OK)
  247. {
  248. PDEBUG_STACK_FRAME RawFrames = (PDEBUG_STACK_FRAME)m_Data;
  249. *pFrame = RawFrames[Line];
  250. UnlockStateBuffer(this);
  251. }
  252. }
  253. return S_OK;
  254. }
  255. BOOL
  256. CALLSWIN_DATA::OnCreate(void)
  257. {
  258. if (s_ContextMenu == NULL)
  259. {
  260. s_ContextMenu = CreateContextMenuFromToolbarButtons
  261. (NUM_CALLS_MENU_BUTTONS, g_CallsTbButtons, CALLS_CONTEXT_ID_BASE);
  262. if (s_ContextMenu == NULL)
  263. {
  264. return FALSE;
  265. }
  266. }
  267. m_Toolbar = CreateWindowEx(0, TOOLBARCLASSNAME, NULL,
  268. WS_CHILD | WS_VISIBLE |
  269. TBSTYLE_WRAPABLE | TBSTYLE_LIST | CCS_TOP,
  270. 0, 0, m_Size.cx, 0, m_Win, (HMENU)ID_TOOLBAR,
  271. g_hInst, NULL);
  272. if (m_Toolbar == NULL)
  273. {
  274. return FALSE;
  275. }
  276. SendMessage(m_Toolbar, TB_BUTTONSTRUCTSIZE, sizeof(TBBUTTON), 0);
  277. SendMessage(m_Toolbar, TB_ADDBUTTONS, NUM_CALLS_TB_BUTTONS,
  278. (LPARAM)&g_CallsTbButtons);
  279. SendMessage(m_Toolbar, TB_AUTOSIZE, 0, 0);
  280. RECT Rect;
  281. GetClientRect(m_Toolbar, &Rect);
  282. m_ToolbarHeight = Rect.bottom - Rect.top;
  283. m_ShowToolbar = TRUE;
  284. m_hwndChild = CreateWindowEx(
  285. WS_EX_CLIENTEDGE, // Extended style
  286. _T("LISTBOX"), // class name
  287. NULL, // title
  288. WS_CHILD | WS_VISIBLE
  289. | WS_MAXIMIZE
  290. | WS_HSCROLL | WS_VSCROLL
  291. | LBS_NOTIFY | LBS_WANTKEYBOARDINPUT
  292. | LBS_NOINTEGRALHEIGHT, // style
  293. 0, // x
  294. m_ToolbarHeight, // y
  295. m_Size.cx, // width
  296. m_Size.cy - m_ToolbarHeight, // height
  297. m_Win, // parent
  298. 0, // control id
  299. g_hInst, // hInstance
  300. NULL // user defined data
  301. );
  302. if (m_hwndChild != NULL)
  303. {
  304. SetFont( FONT_FIXED );
  305. return TRUE;
  306. }
  307. else
  308. {
  309. return FALSE;
  310. }
  311. }
  312. LRESULT
  313. CALLSWIN_DATA::OnCommand(
  314. WPARAM wParam,
  315. LPARAM lParam
  316. )
  317. {
  318. if (HIWORD(wParam) == LBN_DBLCLK)
  319. {
  320. ULONG64 Offset;
  321. if (CodeExprAtCaret(NULL, &Offset) &&
  322. Offset != DEBUG_INVALID_OFFSET)
  323. {
  324. UIC_DISPLAY_CODE_DATA* DispCode =
  325. StartStructCommand(UIC_DISPLAY_CODE);
  326. if (DispCode != NULL)
  327. {
  328. DispCode->Offset = Offset;
  329. FinishCommand();
  330. }
  331. }
  332. DEBUG_STACK_FRAME StkFrame;
  333. if (StackFrameAtCaret(&StkFrame) == S_OK)
  334. {
  335. UIC_SET_SCOPE_DATA* SetScope =
  336. StartStructCommand(UIC_SET_SCOPE);
  337. if (SetScope != NULL)
  338. {
  339. SetScope->StackFrame = StkFrame;
  340. FinishCommand();
  341. }
  342. }
  343. return 0;
  344. }
  345. if ((HWND)lParam == m_Toolbar)
  346. {
  347. OnContextMenuSelection(LOWORD(wParam) + CALLS_CONTEXT_ID_BASE);
  348. return 0;
  349. }
  350. return 0;
  351. }
  352. LRESULT
  353. CALLSWIN_DATA::OnVKeyToItem(
  354. WPARAM wParam,
  355. LPARAM lParam
  356. )
  357. {
  358. if (LOWORD(wParam) == VK_RETURN)
  359. {
  360. ULONG64 Offset;
  361. if (CodeExprAtCaret(NULL, &Offset) &&
  362. Offset != DEBUG_INVALID_OFFSET)
  363. {
  364. UIC_DISPLAY_CODE_DATA* DispCode =
  365. StartStructCommand(UIC_DISPLAY_CODE);
  366. if (DispCode != NULL)
  367. {
  368. DispCode->Offset = Offset;
  369. FinishCommand();
  370. }
  371. }
  372. DEBUG_STACK_FRAME StkFrame;
  373. if (StackFrameAtCaret(&StkFrame) == S_OK)
  374. {
  375. UIC_SET_SCOPE_DATA* SetScope =
  376. StartStructCommand(UIC_SET_SCOPE);
  377. if (SetScope != NULL)
  378. {
  379. SetScope->StackFrame = StkFrame;
  380. FinishCommand();
  381. }
  382. }
  383. }
  384. else if (_T('G') == LOWORD(wParam))
  385. {
  386. ULONG64 Offset;
  387. if (CodeExprAtCaret(NULL, &Offset) &&
  388. Offset != DEBUG_INVALID_OFFSET)
  389. {
  390. PrintStringCommand(UIC_EXECUTE, "g 0x%I64x", Offset);
  391. }
  392. }
  393. else if (_T('R') == LOWORD(wParam))
  394. {
  395. OnUpdate(UPDATE_BUFFER);
  396. }
  397. else
  398. {
  399. // Default behavior.
  400. return -1;
  401. }
  402. // Keystroke processed.
  403. return -2;
  404. }
  405. void
  406. CALLSWIN_DATA::OnUpdate(
  407. UpdateType Type
  408. )
  409. {
  410. if (Type != UPDATE_BUFFER)
  411. {
  412. return;
  413. }
  414. LRESULT lbItem;
  415. int nFrameCount;
  416. HRESULT Status;
  417. lbItem = SendMessage( m_hwndChild, LB_GETCURSEL, 0, 0 );
  418. SendMessage( m_hwndChild, WM_SETREDRAW, FALSE, 0L );
  419. SendMessage( m_hwndChild, LB_RESETCONTENT, 0, 0 );
  420. Status = UiLockForRead();
  421. if (Status == S_OK)
  422. {
  423. PSTR Buf = (PSTR)m_Data + m_TextOffset;
  424. // Ignore final terminator.
  425. PSTR End = (PSTR)m_Data + m_DataUsed - 1;
  426. ULONG Width = 0;
  427. nFrameCount = 0;
  428. while (Buf < End)
  429. {
  430. ULONG Len = strlen(Buf) + 1;
  431. ULONG StrWidth = (Len - 1) * m_Font->Metrics.tmAveCharWidth;
  432. SendMessage(m_hwndChild, LB_ADDSTRING, 0, (LPARAM)Buf);
  433. Buf += Len;
  434. if (StrWidth > Width)
  435. {
  436. Width = StrWidth;
  437. }
  438. nFrameCount++;
  439. }
  440. SendMessage(m_hwndChild, LB_SETHORIZONTALEXTENT, Width, 0);
  441. UnlockStateBuffer(this);
  442. }
  443. else
  444. {
  445. SendLockStatusMessage(m_hwndChild, LB_ADDSTRING, Status);
  446. nFrameCount = 1;
  447. }
  448. SendMessage( m_hwndChild, LB_SETCURSEL,
  449. (lbItem > nFrameCount) ? 0 : lbItem, 0 );
  450. SendMessage( m_hwndChild, WM_SETREDRAW, TRUE, 0L );
  451. }
  452. ULONG
  453. CALLSWIN_DATA::GetWorkspaceSize(void)
  454. {
  455. return SINGLE_CHILDWIN_DATA::GetWorkspaceSize() + 2 * sizeof(ULONG);
  456. }
  457. PUCHAR
  458. CALLSWIN_DATA::SetWorkspace(PUCHAR Data)
  459. {
  460. Data = SINGLE_CHILDWIN_DATA::SetWorkspace(Data);
  461. *(PULONG)Data = m_Flags;
  462. Data += sizeof(ULONG);
  463. *(PULONG)Data = m_Frames;
  464. Data += sizeof(ULONG);
  465. return Data;
  466. }
  467. PUCHAR
  468. CALLSWIN_DATA::ApplyWorkspace1(PUCHAR Data, PUCHAR End)
  469. {
  470. Data = SINGLE_CHILDWIN_DATA::ApplyWorkspace1(Data, End);
  471. if (End - Data >= 2 * sizeof(ULONG))
  472. {
  473. m_Flags = *(PULONG)Data;
  474. Data += sizeof(ULONG);
  475. m_Frames = *(PULONG)Data;
  476. Data += sizeof(ULONG);
  477. SyncUiWithFlags(0xffffffff);
  478. UiRequestRead();
  479. }
  480. return Data;
  481. }
  482. void
  483. CALLSWIN_DATA::SyncUiWithFlags(ULONG Changed)
  484. {
  485. ULONG i;
  486. //
  487. // Set toolbar button state from flags.
  488. //
  489. for (i = 0; i < NUM_CALLS_TB_BUTTONS; i++)
  490. {
  491. if (Changed & (1 << i))
  492. {
  493. SendMessage(m_Toolbar, TB_SETSTATE, g_CallsTbButtons[i].idCommand,
  494. TBSTATE_ENABLED |
  495. ((m_Flags & (1 << i)) ? TBSTATE_CHECKED : 0));
  496. }
  497. }
  498. }