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.

211 lines
6.1 KiB

  1. // Removes duplicate call stacks (useful for thread pools,
  2. // when there are many threads all waiting for an event).
  3. //
  4. // Author: spenlow
  5. // Revisions:
  6. // 2002.04.07 martinc Removed dead code
  7. #include "precomp.h"
  8. #pragma hdrstop
  9. #include <malloc.h>
  10. #include <set>
  11. #include <string>
  12. class Frames
  13. {
  14. public:
  15. Frames (DEBUG_STACK_FRAME* rg, SIZE_T count)
  16. : m_rg (new DEBUG_STACK_FRAME [count]), m_count (count)
  17. {
  18. if (m_rg != NULL)
  19. {
  20. memcpy (m_rg, rg, count * sizeof (m_rg [0]));
  21. }
  22. }
  23. Frames (const Frames& orig)
  24. : m_rg (new DEBUG_STACK_FRAME [orig.m_count]), m_count (orig.m_count)
  25. {
  26. if (m_rg != NULL)
  27. {
  28. memcpy (m_rg, orig.m_rg, m_count * sizeof (m_rg [0]));
  29. }
  30. }
  31. ~Frames()
  32. {
  33. delete[] m_rg;
  34. }
  35. bool
  36. operator<(const Frames& other) const
  37. {
  38. int cmp = 0;
  39. for (SIZE_T i = 0; i < min(m_count, other.m_count); ++i)
  40. {
  41. cmp = m_rg[i].InstructionOffset - other.m_rg[i].InstructionOffset;
  42. if (cmp != 0)
  43. break;
  44. }
  45. if (cmp == 0)
  46. {
  47. cmp = m_count - other.m_count;
  48. }
  49. return cmp < 0;
  50. }
  51. private:
  52. operator=(const Frames&);
  53. DEBUG_STACK_FRAME* m_rg;
  54. SIZE_T m_count;
  55. };
  56. // uniqstack
  57. //
  58. //
  59. // Implementation Notes:
  60. // I'm too lazy to do return value checking all over the place like a moron
  61. // so I throw C++ exceptions on any error and use auto classes to clean stuff up.
  62. //
  63. HRESULT CALLBACK
  64. uniqstack(PDEBUG_CLIENT Client, PCSTR args)
  65. {
  66. PDEBUG_EXTENSION_CALL pfn = uniqstack;
  67. IDebugControl* pDbgCtrl = NULL;
  68. IDebugSystemObjects* pDbgSys = NULL;
  69. const ULONG threadIdInvalid = ~0;
  70. ULONG initialThreadId = 0;
  71. ULONG eventThreadId = 0;
  72. ULONG cthreads = 0;
  73. ULONG* rgThreadIds = NULL;
  74. DEBUG_STACK_FRAME rgFrames [100];
  75. std::set< Frames > framesSeen;
  76. std::set< ULONG > dups;
  77. std::string str;
  78. ULONG StackTraceFlags = 0;
  79. ULONG sysProcessId = 0;
  80. Client->QueryInterface (__uuidof (IDebugSystemObjects), (void**) &pDbgSys);
  81. Client->QueryInterface (__uuidof (IDebugControl), (void**) &pDbgCtrl);
  82. // In argument parsing, only allow one type of b,v,p but user may add in n.
  83. for (SIZE_T ich = 0; args[ich] != '\0'; ++ich)
  84. {
  85. CHAR ch = args[ich];
  86. if (ch == 'b' || ch == 'B')
  87. {
  88. StackTraceFlags = DEBUG_STACK_ARGUMENTS | (StackTraceFlags & DEBUG_STACK_FRAME_NUMBERS);
  89. if (pDbgCtrl->IsPointer64Bit () == S_OK)
  90. {
  91. StackTraceFlags |= DEBUG_STACK_FRAME_ADDRESSES_RA_ONLY;
  92. }
  93. }
  94. else if (ch == 'v' || ch == 'V')
  95. {
  96. StackTraceFlags = DEBUG_STACK_FUNCTION_INFO | DEBUG_STACK_ARGUMENTS | DEBUG_STACK_NONVOLATILE_REGISTERS | (StackTraceFlags & DEBUG_STACK_FRAME_NUMBERS);
  97. }
  98. else if (ch == 'p' || ch == 'P')
  99. {
  100. StackTraceFlags = DEBUG_STACK_PARAMETERS | (StackTraceFlags & DEBUG_STACK_FRAME_NUMBERS);
  101. }
  102. else if (ch == 'n' || ch == 'N')
  103. {
  104. StackTraceFlags |= DEBUG_STACK_FRAME_NUMBERS;
  105. }
  106. }
  107. pDbgSys->GetCurrentThreadId (&initialThreadId);
  108. if (S_OK != pDbgSys->GetEventThread (&eventThreadId))
  109. {
  110. eventThreadId = threadIdInvalid;
  111. }
  112. pDbgSys->GetNumberThreads (&cthreads);
  113. pDbgSys->GetCurrentProcessSystemId(&sysProcessId);
  114. rgThreadIds = (ULONG*)_alloca (sizeof (rgThreadIds [0]) * cthreads);
  115. pDbgSys->GetThreadIdsByIndex (0, cthreads, rgThreadIds, NULL);
  116. for (ULONG ithread = 0; ithread < cthreads; ++ithread)
  117. {
  118. pDbgSys->SetCurrentThreadId (rgThreadIds [ithread]);
  119. ULONG cFramesFilled = 0;
  120. pDbgCtrl->GetStackTrace (0, 0, 0, rgFrames, sizeof (rgFrames) / sizeof (rgFrames [0]), &cFramesFilled);
  121. Frames fr(rgFrames, cFramesFilled);
  122. std::set< Frames >::iterator i = framesSeen.find (fr);
  123. if (i == framesSeen.end ())
  124. {
  125. framesSeen.insert(fr);
  126. CHAR status;
  127. if (initialThreadId == rgThreadIds [ithread])
  128. {
  129. status = '.';
  130. }
  131. else if (eventThreadId == rgThreadIds [ithread])
  132. {
  133. status = '#';
  134. }
  135. else
  136. {
  137. status = ' ';
  138. }
  139. ULONG sysThreadId;
  140. ULONG64 teb;
  141. pDbgSys->GetCurrentThreadSystemId(&sysThreadId);
  142. pDbgSys->GetCurrentThreadDataOffset(&teb);
  143. dprintf ("\n%c%3ld id: 0x%lx.0x%lx Teb 0x%I64x\n",
  144. status,
  145. rgThreadIds [ithread],
  146. sysProcessId,
  147. sysThreadId,
  148. teb
  149. );
  150. pDbgCtrl->OutputStackTrace (
  151. DEBUG_OUTCTL_ALL_CLIENTS | // Flags on what to do with output
  152. DEBUG_OUTCTL_OVERRIDE_MASK |
  153. DEBUG_OUTCTL_NOT_LOGGED,
  154. rgFrames,
  155. cFramesFilled,
  156. DEBUG_STACK_COLUMN_NAMES |
  157. DEBUG_STACK_FRAME_ADDRESSES |
  158. DEBUG_STACK_SOURCE_LINE |
  159. StackTraceFlags);
  160. }
  161. else
  162. {
  163. dups.insert(rgThreadIds [ithread]);
  164. }
  165. }
  166. for (std::set< ULONG >::iterator i = dups.begin(); i != dups.end(); i++)
  167. {
  168. CHAR sz[20];
  169. sprintf(sz, i == dups.begin() ? "%d" : ", %d", *i);
  170. str.append (sz);
  171. }
  172. dprintf ("\nTotal threads: %d, Duplicate callstacks: %d (windbg thread #s follow):\n", cthreads, dups.size());
  173. dprintf ("%s\n", str.c_str ());
  174. pDbgSys->SetCurrentThreadId (initialThreadId);
  175. pDbgSys->Release ();
  176. pDbgCtrl->Release ();
  177. return S_OK;
  178. }