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.

1072 lines
26 KiB

  1. /*++
  2. Copyright (c) 1998 Microsoft Corporation
  3. Module Name:
  4. stacks.c
  5. Abstract:
  6. WinDbg Extension Api
  7. Author:
  8. Adrian J. Oney (adriao) 07-28-1998
  9. Environment:
  10. User Mode.
  11. Revision History:
  12. --*/
  13. #include "precomp.h"
  14. #pragma hdrstop
  15. typedef enum _KTHREAD_STATE {
  16. Initialized,
  17. Ready,
  18. Running,
  19. Standby,
  20. Terminated,
  21. Waiting,
  22. Transition
  23. } KTHREAD_STATE;
  24. typedef enum {
  25. NO_STACK_ACTION = 0,
  26. SKIP_FRAME,
  27. SKIP_THREAD
  28. } STACKS_ACTION, *PSTACKS_ACTION;
  29. #define ETHREAD_NOT_READABLE 1
  30. #define THREAD_VALID 2
  31. #define FIRST_THREAD_VALID 3
  32. #define NO_THREADS 4
  33. struct _BLOCKER_TREE ;
  34. typedef struct _BLOCKER_TREE BLOCKER_TREE, *PBLOCKER_TREE ;
  35. BOOL
  36. StacksValidateProcess(
  37. IN ULONG64 RealProcessBase
  38. );
  39. BOOL
  40. StacksValidateThread(
  41. IN ULONG64 RealThreadBase
  42. );
  43. VOID StacksDumpProcessAndThread(
  44. IN ULONG64 RealProcessBase,
  45. IN ULONG ThreadDesc,
  46. IN ULONG64 RealThreadBase,
  47. IN PBLOCKER_TREE BlockerTree,
  48. IN ULONG Verbosity,
  49. IN char * Filter
  50. );
  51. VOID StacksGetThreadStateName(
  52. IN ULONG ThreadState,
  53. OUT PCHAR Dest
  54. );
  55. VOID
  56. DumpThreadBlockageInfo (
  57. IN char *pad,
  58. IN ULONG64 RealThreadBase,
  59. IN ULONG Verbosity
  60. );
  61. typedef enum {
  62. STACK_WALK_DUMP_STARTING = 0,
  63. STACK_WALK_DUMP_NOT_RESIDENT,
  64. STACK_WALK_DUMP_ENTRY,
  65. STACK_WALK_DUMP_FINISHED
  66. } WALK_STAGE;
  67. typedef struct {
  68. ULONG Verbosity;
  69. BOOLEAN FirstEntry;
  70. char* ThreadState;
  71. char* ThreadBlocker;
  72. ULONG ProcessCid;
  73. ULONG ThreadCid;
  74. ULONG64 ThreadBlockerDisplacement;
  75. } STACK_DUMP_CONTEXT, *PSTACK_DUMP_CONTEXT;
  76. typedef BOOLEAN (*PFN_FRAME_WALK_CALLBACK)(
  77. IN WALK_STAGE WalkStage,
  78. IN ULONG64 RealThreadBase,
  79. IN PVOID Context,
  80. IN char * Buffer,
  81. IN ULONG64 Offset
  82. );
  83. VOID
  84. ForEachFrameOnThread(
  85. IN ULONG64 RealThreadBase,
  86. IN PFN_FRAME_WALK_CALLBACK Callback,
  87. IN PVOID Context
  88. );
  89. BOOLEAN
  90. StacksDumpStackCallback(
  91. IN WALK_STAGE WalkStage,
  92. IN ULONG64 RealThreadBase,
  93. IN PVOID Context,
  94. IN char * Buffer,
  95. IN ULONG64 Offset
  96. );
  97. extern ULONG64 STeip, STebp, STesp;
  98. static ULONG64 PspCidTable;
  99. ULONG64 ProcessLastDump;
  100. ULONG64 ThreadLastDump;
  101. ULONG TotalProcessCommit;
  102. struct _BLOCKER_TREE {
  103. char const *Symbolic ;
  104. STACKS_ACTION Action ;
  105. PBLOCKER_TREE Child ;
  106. PBLOCKER_TREE Sibling ;
  107. PBLOCKER_TREE Parent ;
  108. BOOL Nested ;
  109. } ;
  110. VOID
  111. AnalyzeThread(
  112. IN ULONG64 RealThreadBase,
  113. IN PBLOCKER_TREE BlockerTree,
  114. IN char * Filter,
  115. OUT PCHAR BlockSymbol,
  116. OUT ULONG64 *BlockDisplacement,
  117. OUT BOOLEAN *SkipThread
  118. );
  119. BOOL
  120. BlockerTreeWalk(
  121. IN OUT PBLOCKER_TREE *blockerHead,
  122. IN char *szSymbolic,
  123. IN STACKS_ACTION Action
  124. );
  125. PBLOCKER_TREE
  126. BlockerTreeBuild(
  127. VOID
  128. ) ;
  129. VOID
  130. BlockerTreeFree(
  131. IN PBLOCKER_TREE BlockerTree
  132. ) ;
  133. DECLARE_API( stacks )
  134. /*++
  135. Routine Description:
  136. Dumps the active process list.
  137. Arguments:
  138. None.
  139. Return Value:
  140. None.
  141. --*/
  142. {
  143. ULONG Result;
  144. ULONG64 Next;
  145. ULONG64 NextThread;
  146. ULONG64 ProcessHead;
  147. ULONG64 Process;
  148. ULONG64 Thread;
  149. ULONG64 UserProbeAddress;
  150. ULONG Verbosity = 0, ThreadCount = 0;
  151. ULONG ActProcOffset, ThrdListOffset, ThrdEntryOffset;
  152. PBLOCKER_TREE blockerTree ;
  153. char szFilter[256];
  154. blockerTree = BlockerTreeBuild() ;
  155. if (sscanf(args, "%x %s", &Verbosity, szFilter) < 2) {
  156. szFilter[0] = '\0';
  157. }
  158. dprintf("Proc.Thread .Thread ThreadState Blocker\n") ;
  159. UserProbeAddress = GetNtDebuggerDataValue(MmUserProbeAddress);
  160. ProcessHead = GetNtDebuggerData( PsActiveProcessHead );
  161. if (!ProcessHead) {
  162. dprintf("Unable to get value of PsActiveProcessHead!\n");
  163. goto Exit;
  164. }
  165. if (GetFieldValue( ProcessHead, "nt!_LIST_ENTRY", "Flink", Next )) {
  166. dprintf("Unable to get value of PsActiveProcessHead.Flink\n");
  167. goto Exit ;
  168. }
  169. if (Next == 0) {
  170. dprintf("PsActiveProcessHead is NULL!\n");
  171. goto Exit;
  172. }
  173. GetFieldOffset("nt!_EPROCESS", "ActiveProcessLinks", &ActProcOffset);
  174. GetFieldOffset("nt!_EPROCESS", "Pcb.ThreadListHead", &ThrdListOffset);
  175. GetFieldOffset("nt!_KTHREAD", "ThreadListEntry", &ThrdEntryOffset);
  176. while(Next != ProcessHead) {
  177. ULONG64 FirstThread;
  178. Process = Next - ActProcOffset;
  179. if (GetFieldValue( Process, "nt!_EPROCESS", "Pcb.ThreadListHead.Flink", FirstThread )) {
  180. dprintf("Unable to read nt!_EPROCESS at %p\n",Process);
  181. goto Exit;
  182. }
  183. NextThread = FirstThread;
  184. if (!StacksValidateProcess(Process)) {
  185. dprintf("Process list damaged, or maybe symbols are incorrect?\n%p\n",Process);
  186. goto Exit;
  187. }
  188. if (NextThread == Process + ThrdListOffset) {
  189. StacksDumpProcessAndThread(Process, NO_THREADS, 0, blockerTree, Verbosity, szFilter) ;
  190. } else {
  191. while ( NextThread != Process + ThrdListOffset) {
  192. ULONG64 ThreadFlink;
  193. Thread = NextThread - ThrdEntryOffset;
  194. if (GetFieldValue(Thread,
  195. "nt!_ETHREAD",
  196. "Tcb.ThreadListEntry.Flink",
  197. ThreadFlink)) {
  198. StacksDumpProcessAndThread(Process, ETHREAD_NOT_READABLE, 0, blockerTree, Verbosity, szFilter) ;
  199. dprintf("Unable to read _ETHREAD at %lx\n",Thread);
  200. break;
  201. }
  202. if (!StacksValidateThread(Thread)) {
  203. StacksDumpProcessAndThread( Process, ETHREAD_NOT_READABLE, 0, blockerTree, Verbosity, szFilter) ;
  204. } else if (NextThread == FirstThread) {
  205. ThreadCount++;
  206. StacksDumpProcessAndThread(Process, FIRST_THREAD_VALID, Thread, blockerTree, Verbosity, szFilter) ;
  207. } else {
  208. ThreadCount++;
  209. StacksDumpProcessAndThread(Process, THREAD_VALID, Thread, blockerTree, Verbosity, szFilter) ;
  210. }
  211. NextThread = ThreadFlink;
  212. if (CheckControlC()) {
  213. goto Exit;
  214. }
  215. }
  216. }
  217. EXPRLastDump = Process;
  218. ProcessLastDump = Process;
  219. dprintf("\n");
  220. GetFieldValue( Process, "nt!_EPROCESS", "ActiveProcessLinks.Flink", Next);
  221. if (CheckControlC()) {
  222. goto Exit;
  223. }
  224. }
  225. Exit:
  226. BlockerTreeFree(blockerTree) ;
  227. dprintf("\nThreads Processed: %d\n", ThreadCount);
  228. return S_OK;
  229. }
  230. BOOL
  231. StacksValidateProcess(
  232. IN ULONG64 RealProcessBase
  233. )
  234. {
  235. ULONG Type;
  236. GetFieldValue(RealProcessBase, "nt!_EPROCESS", "Pcb.Header.Type", Type);
  237. if (Type != ProcessObject) {
  238. dprintf("TYPE mismatch for process object at %p\n",RealProcessBase);
  239. return FALSE;
  240. }
  241. return TRUE ;
  242. }
  243. VOID StacksDumpProcessAndThread(
  244. IN ULONG64 RealProcessBase,
  245. IN ULONG ThreadDesc,
  246. IN ULONG64 RealThreadBase,
  247. IN PBLOCKER_TREE BlockerTree,
  248. IN ULONG Verbosity,
  249. IN char * Filter
  250. )
  251. {
  252. ULONG NumberOfHandles;
  253. ULONG Result;
  254. CHAR Buf[512];
  255. CHAR ThreadState[13] ;
  256. CHAR ThreadBlocker[256] ;
  257. UINT i ;
  258. ULONG64 ObjectTable, ThreadBlockerDisplacement;
  259. CHAR *ThreadStateName ;
  260. ULONG UniqueProcessCid;
  261. STACK_DUMP_CONTEXT dumpData;
  262. BOOLEAN SkipThread;
  263. NumberOfHandles = 0;
  264. GetFieldValue(RealProcessBase, "nt!_EPROCESS", "ImageFileName", Buf);
  265. InitTypeRead(RealProcessBase, nt!_EPROCESS);
  266. if (ObjectTable = ReadField(ObjectTable)) {
  267. GetFieldValue(ObjectTable, "nt!_HANDLE_TABLE", "HandleCount", NumberOfHandles);
  268. }
  269. if (Buf[0] == '\0' ) {
  270. strcpy((char *)Buf,"System Process");
  271. }
  272. UniqueProcessCid = (ULONG) ReadField(UniqueProcessId);
  273. if (!RealThreadBase) {
  274. switch(ThreadDesc) {
  275. case NO_THREADS:
  276. dprintf(" [%p %s]\n", RealProcessBase, Buf) ;
  277. if ((Verbosity > 0) && (Filter[0] == '\0')) {
  278. dprintf("%4lx.------ NOTHREADS\n",
  279. UniqueProcessCid
  280. );
  281. }
  282. break ;
  283. case ETHREAD_NOT_READABLE:
  284. dprintf("%4lx.------ NO ETHREAD DATA\n",
  285. UniqueProcessCid
  286. );
  287. break ;
  288. }
  289. return;
  290. }
  291. InitTypeRead(RealThreadBase, nt!_ETHREAD);
  292. ASSERT(((ULONG) ReadField(Cid.UniqueProcess)) == UniqueProcessCid);
  293. StacksGetThreadStateName((ULONG) ReadField(Tcb.State), ThreadState) ;
  294. i=strlen(ThreadState) ;
  295. while(i<11) ThreadState[i++]=' ' ;
  296. ThreadState[i]='\0' ;
  297. AnalyzeThread(
  298. RealThreadBase,
  299. BlockerTree,
  300. Filter,
  301. ThreadBlocker,
  302. &ThreadBlockerDisplacement,
  303. &SkipThread
  304. );
  305. if (ThreadDesc == FIRST_THREAD_VALID) {
  306. dprintf(" [%p %s]\n", RealProcessBase, Buf) ;
  307. }
  308. if (SkipThread && ((Verbosity == 0) || (Filter[0]))) {
  309. return;
  310. }
  311. dumpData.Verbosity = Verbosity;
  312. dumpData.ThreadState = ThreadState;
  313. dumpData.ThreadBlocker = ThreadBlocker;
  314. dumpData.ThreadBlockerDisplacement = ThreadBlockerDisplacement;
  315. dumpData.ProcessCid = UniqueProcessCid;
  316. dumpData.ThreadCid = (ULONG) ReadField(Cid.UniqueThread);
  317. ForEachFrameOnThread(
  318. RealThreadBase,
  319. StacksDumpStackCallback,
  320. (PVOID) &dumpData
  321. );
  322. }
  323. BOOLEAN
  324. StacksDumpStackCallback(
  325. IN WALK_STAGE WalkStage,
  326. IN ULONG64 RealThreadBase,
  327. IN PVOID Context,
  328. IN char * Buffer,
  329. IN ULONG64 Offset
  330. )
  331. {
  332. PSTACK_DUMP_CONTEXT dumpData = (PSTACK_DUMP_CONTEXT) Context;
  333. switch(WalkStage) {
  334. case STACK_WALK_DUMP_STARTING:
  335. dprintf("%4lx.%06lx %08p %s",
  336. dumpData->ProcessCid,
  337. dumpData->ThreadCid,
  338. RealThreadBase,
  339. dumpData->ThreadState
  340. );
  341. dumpData->FirstEntry = TRUE;
  342. return TRUE;
  343. case STACK_WALK_DUMP_FINISHED:
  344. dumpData->FirstEntry = FALSE;
  345. dprintf("\n");
  346. return TRUE;
  347. case STACK_WALK_DUMP_NOT_RESIDENT:
  348. case STACK_WALK_DUMP_ENTRY:
  349. if (dumpData->FirstEntry) {
  350. dumpData->FirstEntry = FALSE;
  351. } else {
  352. dprintf("\n ");
  353. }
  354. break;
  355. default:
  356. return FALSE;
  357. }
  358. if (WalkStage == STACK_WALK_DUMP_NOT_RESIDENT) {
  359. switch(dumpData->Verbosity) {
  360. case 0:
  361. case 1:
  362. case 2:
  363. dprintf("Stack paged out");
  364. break;
  365. }
  366. return FALSE;
  367. }
  368. switch(dumpData->Verbosity) {
  369. case 0:
  370. case 1:
  371. dprintf("%s", dumpData->ThreadBlocker);
  372. if (dumpData->ThreadBlockerDisplacement) {
  373. dprintf( "+0x%1p", dumpData->ThreadBlockerDisplacement );
  374. }
  375. dprintf("\n");
  376. return FALSE;
  377. case 2:
  378. dprintf("%s", Buffer);
  379. if (Offset) {
  380. dprintf( "+0x%1p", Offset );
  381. }
  382. break;
  383. }
  384. return TRUE;
  385. }
  386. UCHAR *StacksWaitReasonList[] = {
  387. "Executive",
  388. "FreePage",
  389. "PageIn",
  390. "PoolAllocation",
  391. "DelayExecution",
  392. "Suspended",
  393. "UserRequest",
  394. "WrExecutive",
  395. "WrFreePage",
  396. "WrPageIn",
  397. "WrPoolAllocation",
  398. "WrDelayExecution",
  399. "WrSuspended",
  400. "WrUserRequest",
  401. "WrEventPairHigh",
  402. "WrEventPairLow",
  403. "WrLpcReceive",
  404. "WrLpcReply",
  405. "WrVirtualMemory",
  406. "WrPageOut",
  407. "Spare1",
  408. "Spare2",
  409. "Spare3",
  410. "Spare4",
  411. "Spare5",
  412. "Spare6",
  413. "Spare7"};
  414. VOID StacksGetThreadStateName(
  415. IN ULONG ThreadState,
  416. OUT PCHAR Dest
  417. )
  418. {
  419. switch (ThreadState) {
  420. case Initialized: strcpy(Dest, "INITIALIZED"); break;
  421. case Ready: strcpy(Dest, "READY"); break;
  422. case Running: strcpy(Dest, "RUNNING"); break;
  423. case Standby: strcpy(Dest, "STANDBY"); break;
  424. case Terminated: strcpy(Dest, "TERMINATED"); break;
  425. case Waiting: strcpy(Dest, "Blocked"); break;
  426. case Transition: strcpy(Dest, "TRANSITION"); break;
  427. default: strcpy(Dest, "????") ; break ;
  428. }
  429. }
  430. BOOL
  431. StacksValidateThread (
  432. IN ULONG64 RealThreadBase
  433. )
  434. {
  435. ULONG Type;
  436. GetFieldValue(RealThreadBase, "nt!_ETHREAD", "Tcb.Header.Type", Type);
  437. if (Type != ThreadObject) {
  438. dprintf("TYPE mismatch for thread object at %p\n",RealThreadBase);
  439. return FALSE;
  440. }
  441. return TRUE ;
  442. }
  443. VOID
  444. DumpThreadBlockageInfo (
  445. IN char *Pad,
  446. IN ULONG64 RealThreadBase,
  447. IN ULONG Verbosity
  448. )
  449. {
  450. #define MAX_STACK_FRAMES 40
  451. TIME_FIELDS Times;
  452. LARGE_INTEGER RunTime;
  453. ULONG64 Address;
  454. ULONG Result;
  455. ULONG64 WaitBlock;
  456. ULONG WaitOffset;
  457. ULONG64 Process;
  458. CHAR Buffer[80];
  459. ULONG KeTimeIncrement;
  460. ULONG TimeIncrement;
  461. ULONG frames = 0;
  462. ULONG i;
  463. ULONG displacement;
  464. ULONG64 WaitBlockList;
  465. ULONG IrpOffset;
  466. InitTypeRead(RealThreadBase, nt!_ETHREAD);
  467. if ((ULONG) ReadField(Tcb.State) == Waiting) {
  468. dprintf("%s (%s) %s %s\n",
  469. Pad,
  470. StacksWaitReasonList[(ULONG) ReadField(Tcb.WaitReason)],
  471. ((ULONG) ReadField(Tcb.WaitMode)==KernelMode) ? "KernelMode" : "UserMode",(ULONG) ReadField(Tcb.Alertable) ? "Alertable" : "Non-Alertable");
  472. if ( ReadField(Tcb.SuspendCount) ) {
  473. dprintf("SuspendCount %lx\n",(ULONG) ReadField(Tcb.SuspendCount));
  474. }
  475. if ( ReadField(Tcb.FreezeCount) ) {
  476. dprintf("FreezeCount %lx\n",(ULONG) ReadField(Tcb.FreezeCount));
  477. }
  478. WaitBlockList = ReadField(Tcb.WaitBlockList);
  479. if (InitTypeRead(WaitBlockList,nt!KWAIT_BLOCK)) {
  480. dprintf("%sunable to get Wait object\n",Pad);
  481. goto BadWaitBlock;
  482. }
  483. do {
  484. ULONG64 Object, NextWaitBlock, OwnerThread;
  485. ULONG Limit;
  486. dprintf("%s %lx ",Pad, Object = ReadField(Object));
  487. NextWaitBlock = ReadField(NextWaitBlock);
  488. if (InitTypeRead(Object,nt!KMUTANT)) {
  489. dprintf("%sunable to get Wait object\n",Pad);
  490. break;
  491. }
  492. GetFieldValue(Object, "nt!KSEMAPHORE", "Limit", Limit);
  493. GetFieldValue(Object, "nt!KSEMAPHORE", "OwnerThread",OwnerThread);
  494. switch (ReadField(Header.Type)) {
  495. case EventNotificationObject:
  496. dprintf("NotificationEvent\n");
  497. break;
  498. case EventSynchronizationObject:
  499. dprintf("SynchronizationEvent\n");
  500. break;
  501. case SemaphoreObject:
  502. dprintf("Semaphore Limit 0x%p\n",
  503. Limit);
  504. break;
  505. case ThreadObject:
  506. dprintf("Thread\n");
  507. break;
  508. case TimerNotificationObject:
  509. dprintf("NotificationTimer\n");
  510. break;
  511. case TimerSynchronizationObject:
  512. dprintf("SynchronizationTimer\n");
  513. break;
  514. case EventPairObject:
  515. dprintf("EventPair\n");
  516. break;
  517. case ProcessObject:
  518. dprintf("ProcessObject\n");
  519. break;
  520. case MutantObject:
  521. dprintf("Mutant - owning thread %p\n",
  522. OwnerThread);
  523. break;
  524. default:
  525. dprintf("Unknown\n");
  526. break;
  527. }
  528. if (NextWaitBlock == WaitBlockList) {
  529. break;
  530. }
  531. if (InitTypeRead(NextWaitBlock,nt!KWAIT_BLOCK)) {
  532. dprintf("%sunable to get Wait object\n",Pad);
  533. break;
  534. }
  535. } while ( TRUE );
  536. }
  537. BadWaitBlock:
  538. //
  539. // Re-intialize thread read
  540. //
  541. InitTypeRead(RealThreadBase, nt!_ETHREAD);
  542. if ( ReadField(LpcReplyMessageId) != 0) {
  543. dprintf("%sWaiting for reply to LPC MessageId %08x:\n",Pad, (ULONG) ReadField(LpcReplyMessageId));
  544. }
  545. if (Address = ReadField(LpcReplyMessage)) {
  546. ULONG64 Entry_Flink, Entry_Blink;
  547. dprintf("%sPending LPC Reply Message:\n",Pad);
  548. if (GetFieldValue(Address, "nt!_LPCP_MESSAGE", "Entry.Blink", Entry_Blink)) {
  549. dprintf("unable to get LPC msg\n");
  550. } else {
  551. GetFieldValue(Address, "nt!_LPCP_MESSAGE", "Entry.Flink", Entry_Flink);
  552. dprintf("%s %08p: [%08p,%08p]\n",
  553. Pad, Address, Entry_Blink, Entry_Flink
  554. );
  555. }
  556. }
  557. GetFieldOffset("nt!_ETHREAD", "IrpList", &IrpOffset);
  558. if (ReadField(IrpList.Flink) != ReadField(IrpList.Blink) ||
  559. ReadField(IrpList.Flink) != RealThreadBase + IrpOffset
  560. ) {
  561. ULONG64 IrpListHead = RealThreadBase + IrpOffset;
  562. ULONG64 Next;
  563. ULONG Counter = 0;
  564. ULONG IrpThrdOff;
  565. Next = ReadField(IrpList.Flink);
  566. GetFieldOffset("nt!_IRP", "ThreadListEntry", &IrpThrdOff);
  567. dprintf("%sIRP List:\n",Pad);
  568. while ((Next != IrpListHead) && (Counter < 17)) {
  569. ULONG Irp_Type=0, Irp_Size=0, Irp_Flags=0;
  570. ULONG64 Irp_MdlAddress=0;
  571. Counter += 1;
  572. Address = Next - IrpThrdOff;
  573. GetFieldValue(Address, "nt!_IRP", "Type", Irp_Type);
  574. GetFieldValue(Address, "nt!_IRP", "Size", Irp_Size);
  575. GetFieldValue(Address, "nt!_IRP", "Flags", Irp_Flags);
  576. GetFieldValue(Address, "nt!_IRP", "MdlAddress", Irp_MdlAddress);
  577. GetFieldValue(Address, "nt!_IRP", "ThreadListEntry.Flink", Next);
  578. dprintf("%s %08p: (%04x,%04x) Flags: %08lx Mdl: %08lp\n",
  579. Pad,Address,Irp_Type,Irp_Size,Irp_Flags,Irp_MdlAddress);
  580. }
  581. }
  582. }
  583. VOID
  584. ForEachFrameOnThread(
  585. IN ULONG64 RealThreadBase,
  586. IN PFN_FRAME_WALK_CALLBACK Callback,
  587. IN PVOID Context
  588. )
  589. {
  590. #define MAX_STACK_FRAMES 40
  591. TIME_FIELDS Times;
  592. LARGE_INTEGER RunTime;
  593. ULONG Address;
  594. ULONG Result;
  595. CHAR Buffer[256];
  596. ULONG KeTimeIncrement;
  597. ULONG TimeIncrement;
  598. ULONG frames = 0;
  599. ULONG i;
  600. ULONG64 displacement, tcb_KernelStackResident;
  601. EXTSTACKTRACE64 stk[MAX_STACK_FRAMES];
  602. InitTypeRead(RealThreadBase, nt!_ETHREAD);
  603. tcb_KernelStackResident = ReadField(Tcb.KernelStackResident);
  604. if (!tcb_KernelStackResident) {
  605. if (Callback(STACK_WALK_DUMP_STARTING, RealThreadBase, Context, NULL, 0)) {
  606. Callback(STACK_WALK_DUMP_NOT_RESIDENT, RealThreadBase, Context, NULL, 0);
  607. Callback(STACK_WALK_DUMP_FINISHED, RealThreadBase, Context, NULL, 0);
  608. }
  609. return;
  610. }
  611. SetThreadForOperation64( &RealThreadBase );
  612. frames = StackTrace( 0, 0, 0, stk, MAX_STACK_FRAMES );
  613. if (!Callback(STACK_WALK_DUMP_STARTING, RealThreadBase, Context, NULL, 0)) {
  614. return;
  615. }
  616. for (i=0; i<frames; i++) {
  617. Buffer[0] = '!';
  618. GetSymbol(stk[i].ProgramCounter, Buffer, &displacement);
  619. if (!Callback(
  620. STACK_WALK_DUMP_ENTRY,
  621. RealThreadBase,
  622. Context,
  623. Buffer,
  624. displacement)) {
  625. return;
  626. }
  627. }
  628. Callback(STACK_WALK_DUMP_FINISHED, RealThreadBase, Context, NULL, 0);
  629. }
  630. VOID
  631. AnalyzeThread(
  632. IN ULONG64 RealThreadBase,
  633. IN PBLOCKER_TREE BlockerTree,
  634. IN char * Filter,
  635. OUT PCHAR BlockBuffer,
  636. OUT ULONG64 *BlockerDisplacement,
  637. OUT BOOLEAN *SkipThread
  638. )
  639. {
  640. #define MAX_STACK_FRAMES 40
  641. TIME_FIELDS Times;
  642. LARGE_INTEGER RunTime;
  643. ULONG Address;
  644. ULONG Result;
  645. ULONG WaitOffset;
  646. ULONG KeTimeIncrement;
  647. ULONG TimeIncrement;
  648. ULONG frames = 0;
  649. ULONG i;
  650. ULONG64 displacement, tcb_KernelStackResident;
  651. PBLOCKER_TREE blockerCur ;
  652. EXTSTACKTRACE64 stk[MAX_STACK_FRAMES];
  653. BOOLEAN filterMatch, blockerMatch;
  654. CHAR tempFrame[256], lcFilter[256], lcFrame[256];
  655. InitTypeRead(RealThreadBase, nt!_ETHREAD);
  656. tcb_KernelStackResident = ReadField(Tcb.KernelStackResident);
  657. if (!tcb_KernelStackResident) {
  658. *SkipThread = TRUE;
  659. *BlockerDisplacement = 0;
  660. BlockBuffer[0] = '\0';
  661. return;
  662. }
  663. SetThreadForOperation64( &RealThreadBase );
  664. frames = StackTrace( 0, 0, 0, stk, MAX_STACK_FRAMES );
  665. *SkipThread = FALSE;
  666. BlockBuffer[0] = '!';
  667. if (Filter[0]) {
  668. strcpy(lcFilter, Filter);
  669. _strlwr(lcFilter);
  670. }
  671. if (frames == 0) {
  672. strcpy(BlockBuffer, "?? Kernel stack not resident ??") ;
  673. *SkipThread = TRUE;
  674. } else {
  675. if (ReadField(Tcb.State) == Running) {
  676. GetSymbol(stk[0].ProgramCounter, BlockBuffer, &displacement);
  677. *BlockerDisplacement = displacement;
  678. } else {
  679. blockerMatch = FALSE;
  680. filterMatch = FALSE;
  681. for(i=0; i<frames; i++) {
  682. GetSymbol(stk[i].ProgramCounter, tempFrame, &displacement);
  683. if ((!filterMatch) && Filter[0]) {
  684. strcpy(lcFrame, tempFrame);
  685. _strlwr(lcFrame);
  686. if (strstr(lcFrame, lcFilter)) {
  687. filterMatch = TRUE;
  688. }
  689. }
  690. blockerCur = BlockerTree;
  691. if ((!blockerMatch) &&
  692. (!BlockerTreeWalk(&blockerCur, tempFrame, SKIP_FRAME))) {
  693. blockerMatch = TRUE;
  694. strcpy(BlockBuffer, tempFrame);
  695. *BlockerDisplacement = displacement;
  696. if (filterMatch || (Filter[0]=='\0')) {
  697. break;
  698. }
  699. }
  700. }
  701. blockerCur = BlockerTree;
  702. if (Filter[0]) {
  703. if (!filterMatch) {
  704. *SkipThread = TRUE;
  705. }
  706. } else {
  707. if (BlockerTreeWalk(&blockerCur, BlockBuffer, SKIP_THREAD)) {
  708. *SkipThread = TRUE;
  709. }
  710. }
  711. }
  712. }
  713. }
  714. #define BEGIN_TREE()
  715. #define END_TREE()
  716. #define DECLARE_ENTRY(foo, action) BlockerTreeDeclareEntry(foo, action)
  717. #define BEGIN_LIST() BlockerTreeListBegin()
  718. #define END_LIST() BlockerTreeListEnd()
  719. PBLOCKER_TREE gpCurrentBlocker ;
  720. VOID
  721. BlockerTreeListBegin(
  722. VOID
  723. )
  724. {
  725. //dprintf("Nest for %x\n", gpCurrentBlocker) ;
  726. ASSERT(!gpCurrentBlocker->Nested) ;
  727. gpCurrentBlocker->Nested = TRUE ;
  728. }
  729. VOID
  730. BlockerTreeListEnd(
  731. VOID
  732. )
  733. {
  734. //dprintf("Unnest for %x\n", gpCurrentBlocker) ;
  735. gpCurrentBlocker = gpCurrentBlocker->Parent ;
  736. ASSERT(gpCurrentBlocker->Nested) ;
  737. gpCurrentBlocker->Nested = FALSE ;
  738. }
  739. VOID
  740. BlockerTreeDeclareEntry(
  741. const char *szSymbolic,
  742. STACKS_ACTION StacksAction
  743. )
  744. {
  745. PBLOCKER_TREE blockerEntry ;
  746. blockerEntry = (PBLOCKER_TREE) malloc(sizeof(BLOCKER_TREE)) ;
  747. if (!blockerEntry) {
  748. return ;
  749. }
  750. memset(blockerEntry, 0, sizeof(BLOCKER_TREE)) ;
  751. blockerEntry->Symbolic = szSymbolic ;
  752. blockerEntry->Action = StacksAction;
  753. if (gpCurrentBlocker->Nested) {
  754. ASSERT(!gpCurrentBlocker->Child) ;
  755. //dprintf("Child %x for %x\n", blockerEntry, gpCurrentBlocker) ;
  756. blockerEntry->Parent = gpCurrentBlocker ;
  757. gpCurrentBlocker->Child = blockerEntry ;
  758. } else {
  759. ASSERT(!gpCurrentBlocker->Sibling) ;
  760. //dprintf("sibling %x for %x\n", blockerEntry, gpCurrentBlocker) ;
  761. blockerEntry->Parent = gpCurrentBlocker->Parent ;
  762. gpCurrentBlocker->Sibling = blockerEntry ;
  763. }
  764. gpCurrentBlocker = blockerEntry ;
  765. }
  766. PBLOCKER_TREE
  767. BlockerTreeBuild(
  768. VOID
  769. )
  770. {
  771. BLOCKER_TREE blockerHead ;
  772. memset(&blockerHead, 0, sizeof(BLOCKER_TREE)) ;
  773. gpCurrentBlocker = &blockerHead ;
  774. //
  775. // Generate the list...
  776. //
  777. #include "stacks.h"
  778. //
  779. // And return it.
  780. //
  781. return blockerHead.Sibling ;
  782. }
  783. VOID BlockerTreeFree(
  784. PBLOCKER_TREE BlockerHead
  785. )
  786. {
  787. PBLOCKER_TREE blockerCur, blockerNext ;
  788. for(blockerCur = BlockerHead; blockerCur; blockerCur = blockerNext) {
  789. if (blockerCur->Child) {
  790. BlockerTreeFree(blockerCur->Child) ;
  791. }
  792. blockerNext = blockerCur->Sibling ;
  793. free(blockerCur) ;
  794. }
  795. }
  796. BOOL
  797. BlockerTreeWalk(
  798. IN OUT PBLOCKER_TREE *blockerHead,
  799. IN char *szSymbolic,
  800. IN STACKS_ACTION Action
  801. )
  802. {
  803. PBLOCKER_TREE blockerCur ;
  804. const char *blockString, *curString, *strptr;
  805. char szStringCopy[512];
  806. for(blockerCur = *blockerHead; blockerCur; blockerCur = blockerCur->Sibling) {
  807. if (Action != blockerCur->Action) {
  808. continue;
  809. }
  810. blockString = blockerCur->Symbolic;
  811. curString = szSymbolic;
  812. strptr = strstr(curString, "!.");
  813. if (strptr) {
  814. //
  815. // This must be an ia64 symbol. Replace the !. with a nice simple !
  816. //
  817. strcpy(szStringCopy, curString);
  818. strcpy(szStringCopy + (strptr - curString) + 1, strptr + 2);
  819. curString = szStringCopy;
  820. }
  821. //
  822. // Special case "Our Kernel of Many Names"
  823. //
  824. if (!_strnicmp(blockString, "nt!", 3)) {
  825. if ((!_strnicmp(curString, "ntoskrnl!", 9)) ||
  826. (!_strnicmp(curString, "ntkrnlmp!", 9)) ||
  827. (!_strnicmp(curString, "ntkrpamp!", 9)) ||
  828. (!_strnicmp(curString, "ntkrnlpa!", 9))) {
  829. blockString += 3;
  830. curString += 9;
  831. }
  832. }
  833. if (!_strcmpi(blockString, curString)) {
  834. *blockerHead = blockerCur->Child;
  835. return TRUE;
  836. }
  837. }
  838. return FALSE;
  839. }