Leaked source code of windows server 2003
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.

684 lines
16 KiB

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