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.

3693 lines
105 KiB

  1. /*++
  2. Copyright (c) 1992-1999 Microsoft Corporation
  3. Module Name:
  4. process.c
  5. Abstract:
  6. WinDbg Extension Api
  7. Environment:
  8. User Mode.
  9. Revision History:
  10. Kshitiz K. Sharma (kksharma)
  11. Using debugger type info.
  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. DeferredReady
  24. } KTHREAD_STATE;
  25. extern ULONG64 STeip, STebp, STesp;
  26. #if 0 // MAKE IT BUILD
  27. static PHANDLE_TABLE PspCidTable;
  28. static HANDLE_TABLE CapturedPspCidTable;
  29. #endif
  30. ULONG64 ProcessLastDump;
  31. ULONG64 ThreadLastDump;
  32. ULONG TotalProcessCommit;
  33. CHAR * SecImpLevel[] = {
  34. "Anonymous",
  35. "Identification",
  36. "Impersonation",
  37. "Delegation" };
  38. #define SecImpLevels(x) (x < sizeof( SecImpLevel ) / sizeof( PSTR ) ? \
  39. SecImpLevel[ x ] : "Illegal Value" )
  40. typedef BOOLEAN (WINAPI *PENUM_PROCESS_CALLBACK)(PVOID ProcessAddress, PVOID Process, PVOID ThreadAddress, PVOID Thread);
  41. PSTR
  42. GetThreadWaitReasonName(
  43. ULONG dwWatiReason
  44. )
  45. {
  46. #define MAX_WAITREASONS 40
  47. static char WaitReasonDescs[MAX_WAITREASONS][50] = {0};
  48. if (dwWatiReason >= MAX_WAITREASONS)
  49. {
  50. return "Invalid WaitReason";
  51. } else if (WaitReasonDescs[dwWatiReason][0] != '\0')
  52. {
  53. return WaitReasonDescs[dwWatiReason];
  54. } else
  55. {
  56. ULONG wrTypeId;
  57. ULONG64 Module;
  58. CHAR Name[MAX_PATH];
  59. if (g_ExtSymbols->GetSymbolTypeId("nt!_KWAIT_REASON", &wrTypeId, &Module) == S_OK &&
  60. g_ExtSymbols->GetConstantName(Module, wrTypeId, dwWatiReason,
  61. Name, sizeof(Name), NULL) == S_OK)
  62. {
  63. StringCchCopy(WaitReasonDescs[dwWatiReason], sizeof(WaitReasonDescs[dwWatiReason]),
  64. Name);
  65. return WaitReasonDescs[dwWatiReason];
  66. }
  67. }
  68. return "Unknown";
  69. }
  70. BOOLEAN
  71. GetTheSystemTime (
  72. OUT PLARGE_INTEGER Time
  73. )
  74. {
  75. BYTE readTime[20]={0};
  76. PCHAR SysTime;
  77. ULONG err;
  78. ZeroMemory( Time, sizeof(*Time) );
  79. SysTime = "SystemTime";
  80. if (err = GetFieldValue(MM_SHARED_USER_DATA_VA, "nt!_KUSER_SHARED_DATA", SysTime, readTime)) {
  81. if (err == MEMORY_READ_ERROR) {
  82. dprintf( "unable to read memory @ %lx\n",
  83. MM_SHARED_USER_DATA_VA);
  84. } else {
  85. dprintf("type nt!_KUSER_SHARED_DATA not found.\n");
  86. }
  87. return FALSE;
  88. }
  89. *Time = *(LARGE_INTEGER UNALIGNED *)&readTime[0];
  90. return TRUE;
  91. }
  92. VOID
  93. dumpSymbolicAddress(
  94. ULONG64 Address,
  95. PCHAR Buffer,
  96. BOOL AlwaysShowHex
  97. )
  98. {
  99. ULONG64 displacement;
  100. PCHAR s;
  101. Buffer[0] = '!';
  102. GetSymbol((ULONG64)Address, Buffer, &displacement);
  103. s = (PCHAR) Buffer + strlen( (PCHAR) Buffer );
  104. if (s == (PCHAR) Buffer) {
  105. sprintf( s, (IsPtr64() ? "0x%016I64x" : "0x%08x"), Address );
  106. }
  107. else {
  108. if (displacement != 0) {
  109. sprintf( s, (IsPtr64() ? "+0x%016I64x" : "+0x%08x"), displacement );
  110. }
  111. if (AlwaysShowHex) {
  112. sprintf( s, (IsPtr64() ? " (0x%016I64x)" : " (0x%08x)"), Address );
  113. }
  114. }
  115. return;
  116. }
  117. BOOL
  118. GetProcessHead(PULONG64 Head, PULONG64 First)
  119. {
  120. ULONG64 List_Flink = 0;
  121. *Head = GetNtDebuggerData( PsActiveProcessHead );
  122. if (!*Head) {
  123. dprintf("Unable to get value of PsActiveProcessHead\n");
  124. return FALSE;
  125. }
  126. if (GetFieldValue(*Head, "nt!_LIST_ENTRY", "Flink", List_Flink)) {
  127. dprintf("Unable to read _LIST_ENTRY @ %p \n", *Head);
  128. return FALSE;
  129. }
  130. if (List_Flink == 0) {
  131. dprintf("NULL value in PsActiveProcess List\n");
  132. return FALSE;
  133. }
  134. *First = List_Flink;
  135. return TRUE;
  136. }
  137. ULONG64
  138. LookupProcessByName(PCSTR Name, BOOL Verbose)
  139. {
  140. ULONG64 ProcessHead, Process;
  141. ULONG64 ProcessNext;
  142. ULONG Off;
  143. if (!GetProcessHead(&ProcessHead, &ProcessNext)) {
  144. return 0;
  145. }
  146. //
  147. // Walk through the list and find the process with the desired name.
  148. //
  149. if (GetFieldOffset("nt!_EPROCESS", "ActiveProcessLinks", &Off)) {
  150. dprintf("Unable to get EPROCESS.ActiveProcessLinks offset\n");
  151. return 0;
  152. }
  153. while (ProcessNext != 0 && ProcessNext != ProcessHead) {
  154. char ImageFileName[64];
  155. Process = ProcessNext - Off;
  156. if (GetFieldValue(Process, "nt!_EPROCESS", "ImageFileName",
  157. ImageFileName)) {
  158. dprintf("Cannot read EPROCESS at %p\n", Process);
  159. } else {
  160. if (Verbose) {
  161. dprintf(" Checking process %s\n", ImageFileName);
  162. }
  163. if (!_strcmpi(Name, ImageFileName)) {
  164. return Process;
  165. }
  166. }
  167. if (!ReadPointer(ProcessNext, &ProcessNext)) {
  168. dprintf("Cannot read EPROCESS at %p\n", Process);
  169. return 0;
  170. }
  171. if (CheckControlC()) {
  172. return 0;
  173. }
  174. }
  175. return 0;
  176. }
  177. HRESULT
  178. WaitForExceptionEvent(ULONG Code, ULONG FirstChance, ULONG64 Process)
  179. {
  180. HRESULT Status;
  181. Status = g_ExtControl->WaitForEvent(DEBUG_WAIT_DEFAULT, INFINITE);
  182. if (Status != S_OK) {
  183. dprintf("Unable to wait, 0x%X\n", Status);
  184. return Status;
  185. }
  186. //
  187. // Got some kind of event. Make sure it's the right kind.
  188. //
  189. ULONG Type, ProcId, ThreadId;
  190. DEBUG_LAST_EVENT_INFO_EXCEPTION ExInfo;
  191. if ((Status = g_ExtControl->
  192. GetLastEventInformation(&Type, &ProcId, &ThreadId,
  193. &ExInfo, sizeof(ExInfo), NULL,
  194. NULL, 0, NULL)) != S_OK) {
  195. dprintf("Unable to get event information\n");
  196. return Status;
  197. }
  198. if (Type != DEBUG_EVENT_EXCEPTION ||
  199. (ULONG)ExInfo.ExceptionRecord.ExceptionCode != Code ||
  200. ExInfo.FirstChance != FirstChance) {
  201. dprintf("Unexpected event occurred\n");
  202. return E_UNEXPECTED;
  203. }
  204. if (Process) {
  205. ULONG Processor;
  206. ULONG64 EventProcess;
  207. if (!GetCurrentProcessor(g_ExtClient, &Processor, NULL)) {
  208. Processor = 0;
  209. }
  210. GetCurrentProcessAddr(Processor, 0, &EventProcess);
  211. if (EventProcess != Process) {
  212. dprintf("Event occurred in wrong process\n");
  213. return E_UNEXPECTED;
  214. }
  215. }
  216. return S_OK;
  217. }
  218. HRESULT
  219. WaitForSingleStep(ULONG64 Process)
  220. {
  221. HRESULT Status;
  222. Status = g_ExtControl->WaitForEvent(DEBUG_WAIT_DEFAULT, INFINITE);
  223. if (Status != S_OK) {
  224. dprintf("Unable to wait, 0x%X\n", Status);
  225. return Status;
  226. }
  227. //
  228. // Got some kind of event. Make sure it's the right kind.
  229. //
  230. ULONG Type, ProcId, ThreadId;
  231. if ((Status = g_ExtControl->
  232. GetLastEventInformation(&Type, &ProcId, &ThreadId,
  233. NULL, 0, NULL,
  234. NULL, 0, NULL)) != S_OK) {
  235. dprintf("Unable to get event information\n");
  236. return Status;
  237. }
  238. if (Type != 0) {
  239. dprintf("Unexpected event occurred\n");
  240. return E_UNEXPECTED;
  241. }
  242. if (Process) {
  243. ULONG Processor;
  244. ULONG64 EventProcess;
  245. if (!GetCurrentProcessor(g_ExtClient, &Processor, NULL)) {
  246. Processor = 0;
  247. }
  248. GetCurrentProcessAddr(Processor, 0, &EventProcess);
  249. if (EventProcess != Process) {
  250. dprintf("Event occurred in wrong process\n");
  251. return E_UNEXPECTED;
  252. }
  253. }
  254. return S_OK;
  255. }
  256. DECLARE_API( bpid )
  257. /*++
  258. Routine Description:
  259. Uses winlogon to cause a user-mode break in the given process.
  260. Arguments:
  261. None.
  262. Return Value:
  263. None.
  264. --*/
  265. {
  266. INIT_API();
  267. if (BuildNo < 2195) {
  268. dprintf("bpid only works on 2195 or above\n");
  269. goto Exit;
  270. }
  271. if (TargetMachine != IMAGE_FILE_MACHINE_I386 &&
  272. TargetMachine != IMAGE_FILE_MACHINE_IA64) {
  273. dprintf("bpid is only implemented for x86 and IA64\n");
  274. goto Exit;
  275. }
  276. BOOL StopInWinlogon;
  277. BOOL Verbose;
  278. BOOL WritePidToMemory;
  279. ULONG WhichGlobal;
  280. PSTR WhichGlobalName;
  281. StopInWinlogon = FALSE;
  282. Verbose = FALSE;
  283. WritePidToMemory = FALSE;
  284. WhichGlobal = 1;
  285. WhichGlobalName = "Breakin";
  286. for (;;)
  287. {
  288. while (*args == ' ' || *args == '\t')
  289. {
  290. args++;
  291. }
  292. if (*args == '-' || *args == '/')
  293. {
  294. switch(*++args)
  295. {
  296. case 'a':
  297. // Set g_AttachProcessId instead of
  298. // g_BreakinProcessId.
  299. WhichGlobal = 2;
  300. WhichGlobalName = "Attach";
  301. break;
  302. case 's':
  303. StopInWinlogon = TRUE;
  304. break;
  305. case 'v':
  306. Verbose = TRUE;
  307. break;
  308. case 'w':
  309. WritePidToMemory = TRUE;
  310. break;
  311. default:
  312. dprintf("Unknown option '%c'\n", *args);
  313. goto Exit;
  314. }
  315. args++;
  316. }
  317. else
  318. {
  319. break;
  320. }
  321. }
  322. ULONG64 Pid;
  323. if (!GetExpressionEx(args, &Pid, &args)) {
  324. dprintf("Usage: bpid <pid>\n");
  325. goto Exit;
  326. }
  327. ULONG64 Winlogon;
  328. ULONG64 WinlToken;
  329. dprintf("Finding winlogon...\n");
  330. Winlogon = LookupProcessByName("winlogon.exe", Verbose);
  331. if (Winlogon == 0) {
  332. dprintf("Unable to find winlogon\n");
  333. goto Exit;
  334. }
  335. if (GetFieldValue(Winlogon, "nt!_EPROCESS", "Token", WinlToken)) {
  336. dprintf("Unable to read winlogon process token\n");
  337. goto Exit;
  338. }
  339. // Low bits of the token value are flags. Mask off to get pointer.
  340. if (IsPtr64()) {
  341. WinlToken &= ~15;
  342. } else {
  343. WinlToken = (ULONG64)(LONG64)(LONG)(WinlToken & ~7);
  344. }
  345. ULONG ExpOff;
  346. //
  347. // winlogon checks its token expiration time. If it's
  348. // zero it breaks in and checks a few things, one of which is whether
  349. // it should inject a DebugBreak into a process. First,
  350. // set the token expiration to zero so that winlogon breaks in.
  351. //
  352. if (GetFieldOffset("nt!_TOKEN", "ExpirationTime", &ExpOff)) {
  353. dprintf("Unable to get TOKEN.ExpirationTime offset\n");
  354. goto Exit;
  355. }
  356. WinlToken += ExpOff;
  357. ULONG64 Expiration, Zero;
  358. ULONG Done;
  359. // Save the expiration time.
  360. if (!ReadMemory(WinlToken, &Expiration, sizeof(Expiration), &Done) ||
  361. Done != sizeof(Expiration)) {
  362. dprintf("Unable to read token expiration\n");
  363. goto Exit;
  364. }
  365. // Zero it.
  366. Zero = 0;
  367. if (!WriteMemory(WinlToken, &Zero, sizeof(Zero), &Done) ||
  368. Done != sizeof(Zero)) {
  369. dprintf("Unable to write token expiration\n");
  370. goto Exit;
  371. }
  372. HRESULT Hr;
  373. // Get things running.
  374. if (g_ExtControl->SetExecutionStatus(DEBUG_STATUS_GO) != S_OK) {
  375. dprintf("Unable to go\n");
  376. goto RestoreExp;
  377. }
  378. // Wait for a breakin.
  379. dprintf("Waiting for winlogon to break. "
  380. "This can take a couple of minutes...\n");
  381. Hr = WaitForExceptionEvent(STATUS_BREAKPOINT, TRUE, Winlogon);
  382. if (Hr != S_OK) {
  383. goto RestoreExp;
  384. }
  385. //
  386. // We broke into winlogon.
  387. // We need to set winlogon!g_[Breakin|Attach]ProcessId to
  388. // the process we want to break into. Relying on symbols
  389. // is pretty fragile as the image header may be paged out
  390. // or the symbol path may be wrong. Even if we had good symbols
  391. // the variable itself may not be paged in at this point.
  392. // The approach taken here is to single-step out to where
  393. // the global is checked and insert the value at that
  394. // point. winlogon currently checks two globals after the
  395. // DebugBreak. g_BreakinProcessId is the first one and
  396. // g_AttachProcessId is the second.
  397. //
  398. ULONG Steps;
  399. ULONG Globals;
  400. ULONG64 BpiAddr;
  401. ULONG64 UserProbeAddress;
  402. PSTR RegDst;
  403. dprintf("Stepping to g_%sProcessId check...\n", WhichGlobalName);
  404. Steps = 0;
  405. Globals = 0;
  406. UserProbeAddress = GetNtDebuggerDataPtrValue(MmUserProbeAddress);
  407. while (Globals < WhichGlobal)
  408. {
  409. if (CheckControlC()) {
  410. goto RestoreExp;
  411. }
  412. if (g_ExtControl->SetExecutionStatus(DEBUG_STATUS_STEP_OVER) != S_OK) {
  413. dprintf("Unable to start step\n");
  414. goto RestoreExp;
  415. }
  416. Hr = WaitForSingleStep(Winlogon);
  417. if (Hr != S_OK) {
  418. goto RestoreExp;
  419. }
  420. char DisStr[128];
  421. int DisStrLen;
  422. ULONG64 Pc;
  423. // Check whether this is a global load.
  424. if (g_ExtRegisters->GetInstructionOffset(&Pc) != S_OK ||
  425. g_ExtControl->Disassemble(Pc, 0, DisStr, sizeof(DisStr),
  426. NULL, &Pc) != S_OK) {
  427. dprintf("Unable to check step\n");
  428. goto RestoreExp;
  429. }
  430. // Remove newline at end.
  431. DisStrLen = strlen(DisStr);
  432. if (DisStrLen > 0 && DisStr[DisStrLen - 1] == '\n') {
  433. DisStr[--DisStrLen] = 0;
  434. }
  435. if (Verbose) {
  436. dprintf(" Step to '%s'\n", DisStr);
  437. }
  438. BpiAddr = 0;
  439. RegDst = NULL;
  440. PSTR OffStr;
  441. switch(TargetMachine) {
  442. case IMAGE_FILE_MACHINE_I386:
  443. if (strstr(DisStr, "mov") != NULL &&
  444. strstr(DisStr, " eax,[") != NULL &&
  445. DisStr[DisStrLen - 1] == ']' &&
  446. (OffStr = strchr(DisStr, '[')) != NULL) {
  447. RegDst = "eax";
  448. //
  449. // Found a load. Parse the offset.
  450. //
  451. PSTR SymTailStr = strchr(OffStr + 1, '(');
  452. if (SymTailStr != NULL) {
  453. // There's a symbol name in the reference. We
  454. // can't check the actual symbol name as symbols
  455. // aren't necessarily correct, so just skip
  456. // to the open paren.
  457. OffStr = SymTailStr + 1;
  458. }
  459. for (;;) {
  460. OffStr++;
  461. if (*OffStr >= '0' && *OffStr <= '9') {
  462. BpiAddr = BpiAddr * 16 + (*OffStr - '0');
  463. } else if (*OffStr >= 'a' && *OffStr <= 'f') {
  464. BpiAddr = BpiAddr * 16 + (*OffStr - 'a');
  465. } else {
  466. BpiAddr = (ULONG64)(LONG64)(LONG)BpiAddr;
  467. break;
  468. }
  469. }
  470. if (*OffStr != ']' && *OffStr != ')') {
  471. BpiAddr = 0;
  472. }
  473. }
  474. break;
  475. case IMAGE_FILE_MACHINE_IA64:
  476. if (strstr(DisStr, "ld4") != NULL &&
  477. (OffStr = strchr(DisStr, '[')) != NULL) {
  478. // Extract destination register name.
  479. RegDst = OffStr - 1;
  480. if (*RegDst != '=') {
  481. break;
  482. }
  483. *RegDst-- = 0;
  484. while (RegDst > DisStr && *RegDst != ' ') {
  485. RegDst--;
  486. }
  487. if (*RegDst != ' ') {
  488. break;
  489. }
  490. RegDst++;
  491. // Extract source register name and value.
  492. PSTR RegSrc = ++OffStr;
  493. while (*OffStr && *OffStr != ']') {
  494. OffStr++;
  495. }
  496. if (*OffStr == ']') {
  497. *OffStr = 0;
  498. DEBUG_VALUE RegVal;
  499. ULONG RegIdx;
  500. if (g_ExtRegisters->GetIndexByName(RegSrc,
  501. &RegIdx) == S_OK &&
  502. g_ExtRegisters->GetValue(RegIdx, &RegVal) == S_OK &&
  503. RegVal.Type == DEBUG_VALUE_INT64) {
  504. BpiAddr = RegVal.I64;
  505. }
  506. }
  507. }
  508. break;
  509. }
  510. if (RegDst != NULL &&
  511. BpiAddr >= 0x10000 && BpiAddr < UserProbeAddress) {
  512. // Looks like a reasonable global load.
  513. Globals++;
  514. }
  515. if (++Steps > 30) {
  516. dprintf("Unable to find g_%sProcessId load\n", WhichGlobalName);
  517. goto RestoreExp;
  518. }
  519. }
  520. //
  521. // We're at the mov eax,[g_BreakinProcessId] instruction.
  522. // Execute the instruction to accomplish two things:
  523. // 1. The page will be made available so we can write
  524. // to it if we need to.
  525. // 2. If we don't want to write the actual memory we
  526. // can just set eax to do a one-time break.
  527. //
  528. if (g_ExtControl->SetExecutionStatus(DEBUG_STATUS_STEP_OVER) != S_OK) {
  529. dprintf("Unable to start step\n");
  530. goto RestoreExp;
  531. }
  532. Hr = WaitForSingleStep(Winlogon);
  533. if (Hr != S_OK) {
  534. goto RestoreExp;
  535. }
  536. char RegCmd[64];
  537. //
  538. // Update the register and write memory if necessary.
  539. //
  540. sprintf(RegCmd, "r %s=0x0`%x", RegDst, (ULONG)Pid);
  541. if (g_ExtControl->Execute(DEBUG_OUTCTL_IGNORE, RegCmd,
  542. DEBUG_EXECUTE_NOT_LOGGED |
  543. DEBUG_EXECUTE_NO_REPEAT) != S_OK) {
  544. goto RestoreExp;
  545. }
  546. if (WritePidToMemory) {
  547. if (!WriteMemory(BpiAddr, &Pid, sizeof(ULONG), &Done) ||
  548. Done != sizeof(ULONG)) {
  549. dprintf("Unable to write pid to g_%sProcessId, continuing\n",
  550. WhichGlobalName);
  551. }
  552. }
  553. // Everything is set. Resume execution and the break should
  554. // occur.
  555. dprintf("Break into process %x set. "
  556. "The next break should be in the desired process.\n",
  557. (ULONG)Pid);
  558. if (!StopInWinlogon) {
  559. if (g_ExtControl->SetExecutionStatus(DEBUG_STATUS_GO) != S_OK) {
  560. dprintf("Unable to go\n");
  561. }
  562. } else {
  563. dprintf("Stopping in winlogon\n");
  564. }
  565. RestoreExp:
  566. if (!WriteMemory(WinlToken, &Expiration, sizeof(Expiration), &Done) ||
  567. Done != sizeof(Expiration)) {
  568. dprintf("Unable to restore token expiration\n");
  569. }
  570. Exit:
  571. EXIT_API();
  572. return S_OK;
  573. }
  574. LPWSTR
  575. GetFullImageName(
  576. ULONG64 Process
  577. )
  578. //
  579. // retrives the actual image name for process, this is useful
  580. // since EPROCESS.ImageName could be truncated
  581. //
  582. {
  583. static WCHAR s_ImageNameRead[MAX_PATH+1];
  584. ULONG64 ImageNameStr = 0;
  585. if (!GetFieldValue(Process, "nt!_EPROCESS", "SeAuditProcessCreationInfo.ImageFileName",
  586. ImageNameStr) &&
  587. (ImageNameStr != 0))
  588. {
  589. ULONG Length, res;
  590. ULONG64 Buffer;
  591. if (!GetFieldValue(ImageNameStr, "nt!_OBJECT_NAME_INFORMATION", "Name.Length",
  592. Length) &&
  593. !GetFieldValue(ImageNameStr, "nt!_OBJECT_NAME_INFORMATION", "Name.Buffer",
  594. Buffer))
  595. {
  596. ZeroMemory(s_ImageNameRead, sizeof(s_ImageNameRead));
  597. if (Length > (sizeof(s_ImageNameRead)-sizeof(WCHAR)))
  598. {
  599. Length = sizeof(s_ImageNameRead) - sizeof(WCHAR);
  600. }
  601. if (ReadMemory(Buffer, s_ImageNameRead, Length, &res))
  602. {
  603. LPWSTR filename = wcsrchr(s_ImageNameRead, L'\\');
  604. if (filename)
  605. {
  606. return (filename+1);
  607. }
  608. }
  609. }
  610. }
  611. return NULL;
  612. }
  613. BOOL
  614. GetProcessSessionId(ULONG64 Process, PULONG SessionId)
  615. {
  616. *SessionId = 0;
  617. if (BuildNo && BuildNo < 2280) {
  618. GetFieldValue(Process, "nt!_EPROCESS", "SessionId", *SessionId);
  619. } else {
  620. ULONG64 SessionPointer;
  621. if (GetFieldValue(Process, "nt!_EPROCESS", "Session", SessionPointer)) {
  622. return FALSE;
  623. }
  624. if (SessionPointer != 0) {
  625. if (GetFieldValue(SessionPointer, "nt!_MM_SESSION_SPACE",
  626. "SessionId", *SessionId)) {
  627. // dprintf("Could not find Session Id at %p.\n", SessionPointer);
  628. return FALSE;
  629. }
  630. }
  631. }
  632. return TRUE;
  633. }
  634. BOOL
  635. DumpProcess(
  636. IN char * pad,
  637. IN ULONG64 RealProcessBase,
  638. IN ULONG Flags,
  639. IN OPTIONAL PCHAR ImageFileName
  640. )
  641. {
  642. LARGE_INTEGER RunTime;
  643. BOOL LongAddrs = IsPtr64();
  644. TIME_FIELDS Times;
  645. ULONG TimeIncrement;
  646. LPWSTR FullImageName;
  647. STRING string1, string2;
  648. ULONG64 ThreadListHead_Flink=0, ActiveProcessLinks_Flink=0;
  649. ULONG64 UniqueProcessId=0, Peb=0, InheritedFromUniqueProcessId=0, NumberOfHandles=0;
  650. ULONG64 ObjectTable=0, NumberOfPrivatePages=0, ModifiedPageCount=0, NumberOfLockedPages=0;
  651. ULONG64 NVads = 0;
  652. ULONG64 VadRoot=0, CloneRoot=0, DeviceMap=0, Token=0;
  653. ULONG64 CreateTime_QuadPart=0, Pcb_UserTime=0, Pcb_KernelTime=0;
  654. ULONG64 Vm_WorkingSetSize=0, Vm_MinimumWorkingSetSize=0, Vm_MaximumWorkingSetSize=0;
  655. ULONG64 Vm_PeakWorkingSetSize=0, VirtualSize=0, PeakVirtualSize=0, Vm_PageFaultCount=0;
  656. ULONG64 Vm_MemoryPriority=0, Pcb_BasePriority=0, CommitCharge=0, DebugPort=0, Job=0;
  657. ULONG SessionId, Pcb_Header_Type=0;
  658. CHAR Pcb_DirectoryTableBase[16]={0}, QuotaPoolUsage[32]={0}, ImageFileName_Read[32] = {0};
  659. TCHAR procType[] = "_EPROCESS";
  660. if (GetFieldValue(RealProcessBase, "nt!_EPROCESS", "UniqueProcessId", UniqueProcessId)) {
  661. dprintf("Could not find _EPROCESS type at %p.\n", RealProcessBase);
  662. return FALSE;
  663. }
  664. if (!GetProcessSessionId(RealProcessBase, &SessionId))
  665. {
  666. dprintf("Could not find Session Id for process.\n");
  667. }
  668. GetFieldValue(RealProcessBase, "nt!_EPROCESS", "Peb", Peb);
  669. GetFieldValue(RealProcessBase, "nt!_EPROCESS", "InheritedFromUniqueProcessId",InheritedFromUniqueProcessId);
  670. GetFieldValue(RealProcessBase, "nt!_EPROCESS", "Pcb.DirectoryTableBase", Pcb_DirectoryTableBase);
  671. GetFieldValue(RealProcessBase, "nt!_EPROCESS", "Pcb.Header.Type", Pcb_Header_Type);
  672. GetFieldValue(RealProcessBase, "nt!_EPROCESS", "ObjectTable", ObjectTable);
  673. GetFieldValue(RealProcessBase, "nt!_EPROCESS", "ImageFileName", ImageFileName_Read);
  674. if (GetFieldValue(RealProcessBase, "nt!_EPROCESS", "NumberOfVads", NVads)) {
  675. if (GetFieldValue(RealProcessBase, "nt!_EPROCESS", "VadRoot.NumberGenericTableElements", NVads)) {
  676. dprintf ("failed for AVL nvads\n");
  677. return FALSE;
  678. }
  679. if (GetFieldValue(RealProcessBase, "nt!_EPROCESS", "VadRoot.BalancedRoot.RightChild", VadRoot)) {
  680. dprintf ("failed for new vadroot\n");
  681. }
  682. }
  683. else {
  684. GetFieldValue(RealProcessBase, "nt!_EPROCESS", "VadRoot", VadRoot);
  685. }
  686. GetFieldValue(RealProcessBase, "nt!_EPROCESS", "CloneRoot", CloneRoot);
  687. GetFieldValue(RealProcessBase, "nt!_EPROCESS", "NumberOfPrivatePages", NumberOfPrivatePages);
  688. GetFieldValue(RealProcessBase, "nt!_EPROCESS", "ModifiedPageCount", ModifiedPageCount);
  689. GetFieldValue(RealProcessBase, "nt!_EPROCESS", "NumberOfLockedPages", NumberOfLockedPages);
  690. GetFieldValue(RealProcessBase, "nt!_EPROCESS", "DeviceMap", DeviceMap);
  691. GetFieldValue(RealProcessBase, "nt!_EPROCESS", "Token", Token);
  692. if (IsPtr64()) {
  693. Token = Token & ~(ULONG64)15;
  694. } else {
  695. Token = Token & ~(ULONG64)7;
  696. }
  697. GetFieldValue(RealProcessBase, "nt!_EPROCESS", "CreateTime.QuadPart", CreateTime_QuadPart);
  698. GetFieldValue(RealProcessBase, "nt!_EPROCESS", "Pcb.UserTime", Pcb_UserTime);
  699. GetFieldValue(RealProcessBase, "nt!_EPROCESS", "Pcb.KernelTime", Pcb_KernelTime);
  700. GetFieldValue(RealProcessBase, "nt!_EPROCESS", "Vm.WorkingSetSize", Vm_WorkingSetSize);
  701. GetFieldValue(RealProcessBase, "nt!_EPROCESS", "Vm.MinimumWorkingSetSize",Vm_MinimumWorkingSetSize);
  702. GetFieldValue(RealProcessBase, "nt!_EPROCESS", "Vm.MaximumWorkingSetSize",Vm_MaximumWorkingSetSize);
  703. GetFieldValue(RealProcessBase, "nt!_EPROCESS", "Vm.PeakWorkingSetSize", Vm_PeakWorkingSetSize);
  704. GetFieldValue(RealProcessBase, "nt!_EPROCESS", "VirtualSize", VirtualSize);
  705. GetFieldValue(RealProcessBase, "nt!_EPROCESS", "PeakVirtualSize", PeakVirtualSize);
  706. GetFieldValue(RealProcessBase, "nt!_EPROCESS", "Vm.PageFaultCount", Vm_PageFaultCount);
  707. GetFieldValue(RealProcessBase, "nt!_EPROCESS", "Vm.MemoryPriority", Vm_MemoryPriority);
  708. GetFieldValue(RealProcessBase, "nt!_EPROCESS", "Pcb.BasePriority", Pcb_BasePriority);
  709. GetFieldValue(RealProcessBase, "nt!_EPROCESS", "CommitCharge", CommitCharge);
  710. GetFieldValue(RealProcessBase, "nt!_EPROCESS", "DebugPort", DebugPort);
  711. GetFieldValue(RealProcessBase, "nt!_EPROCESS", "Job", Job);
  712. GetFieldValue(RealProcessBase, "nt!_EPROCESS", "Pcb.ThreadListHead.Flink",ThreadListHead_Flink);
  713. GetFieldValue(RealProcessBase, "nt!_EPROCESS", "ActiveProcessLinks.Flink",ActiveProcessLinks_Flink);
  714. GetFieldValue(ObjectTable, "nt!_HANDLE_TABLE", "HandleCount", NumberOfHandles);
  715. if (BuildNo < 2462) { // prior to XP Beta2
  716. GetFieldValue(RealProcessBase, "nt!_EPROCESS", "QuotaPoolUsage", QuotaPoolUsage);
  717. } else {
  718. GetFieldValue(RealProcessBase, "nt!_EPROCESS", "QuotaUsage", QuotaPoolUsage);
  719. }
  720. // dprintf( " Proc list Next:%I64x, ProceDump:%I64x, Head:%I64x...\n", Next, ProcessToDump, ProcessHead);
  721. if (Pcb_Header_Type != ProcessObject) {
  722. dprintf("TYPE mismatch for process object at %p\n", RealProcessBase);
  723. return FALSE;
  724. }
  725. //
  726. // Get the image file name
  727. //
  728. if (ImageFileName_Read[0] == 0 ) {
  729. strcpy(ImageFileName_Read,"System Process");
  730. }
  731. if (ImageFileName != NULL) {
  732. RtlInitString(&string1, ImageFileName);
  733. RtlInitString(&string2, ImageFileName_Read);
  734. if (RtlCompareString(&string1, &string2, TRUE) != 0) {
  735. return TRUE;
  736. }
  737. }
  738. dprintf("%sPROCESS %08p", pad, RealProcessBase);
  739. dprintf("%s%sSessionId: %u Cid: %04I64x Peb: %08I64x ParentCid: %04I64x\n",
  740. (LongAddrs ? "\n " : " "),
  741. (LongAddrs ? pad : " "),
  742. SessionId,
  743. UniqueProcessId,
  744. Peb,
  745. InheritedFromUniqueProcessId
  746. );
  747. if (LongAddrs) {
  748. dprintf("%s DirBase: %08I64lx ObjectTable: %08p TableSize: %3u.\n",
  749. pad,
  750. *((ULONG64 *) &Pcb_DirectoryTableBase[ 0 ]),
  751. ObjectTable,
  752. (ULONG) NumberOfHandles
  753. );
  754. } else {
  755. dprintf("%s DirBase: %08lx ObjectTable: %08p TableSize: %3u.\n",
  756. pad,
  757. *((ULONG *) &Pcb_DirectoryTableBase[ 0 ]),
  758. ObjectTable,
  759. (ULONG) NumberOfHandles
  760. );
  761. }
  762. dprintf("%s Image: ", pad);
  763. FullImageName = GetFullImageName(RealProcessBase);
  764. if (FullImageName != NULL && *FullImageName != 0)
  765. {
  766. dprintf("%ws\n", FullImageName);
  767. } else
  768. {
  769. dprintf("%s\n",ImageFileName_Read);
  770. }
  771. if (!(Flags & 1)) {
  772. dprintf("\n");
  773. return TRUE;
  774. }
  775. dprintf("%s VadRoot %p Vads %I64ld Clone %1p Private %I64ld. Modified %I64ld. Locked %I64ld.\n",
  776. pad,
  777. VadRoot,
  778. NVads,
  779. CloneRoot,
  780. NumberOfPrivatePages,
  781. ModifiedPageCount,
  782. NumberOfLockedPages);
  783. dprintf("%s DeviceMap %p\n", pad, DeviceMap );
  784. //
  785. // Primary token
  786. //
  787. dprintf("%s Token %p\n", pad, Token);
  788. //
  789. // Get the time increment value which is used to compute runtime.
  790. //
  791. TimeIncrement = GetNtDebuggerDataValue( KeTimeIncrement );
  792. GetTheSystemTime (&RunTime);
  793. RunTime.QuadPart -= CreateTime_QuadPart;
  794. RtlTimeToElapsedTimeFields ( &RunTime, &Times);
  795. dprintf("%s ElapsedTime %3ld:%02ld:%02ld.%04ld\n",
  796. pad,
  797. Times.Hour,
  798. Times.Minute,
  799. Times.Second,
  800. Times.Milliseconds);
  801. RunTime.QuadPart = UInt32x32To64(Pcb_UserTime, TimeIncrement);
  802. RtlTimeToElapsedTimeFields ( &RunTime, &Times);
  803. dprintf("%s UserTime %3ld:%02ld:%02ld.%04ld\n",
  804. pad,
  805. Times.Hour,
  806. Times.Minute,
  807. Times.Second,
  808. Times.Milliseconds);
  809. RunTime.QuadPart = UInt32x32To64(Pcb_KernelTime, TimeIncrement);
  810. RtlTimeToElapsedTimeFields ( &RunTime, &Times);
  811. dprintf("%s KernelTime %3ld:%02ld:%02ld.%04ld\n",
  812. pad,
  813. Times.Hour,
  814. Times.Minute,
  815. Times.Second,
  816. Times.Milliseconds);
  817. if (!LongAddrs) {
  818. dprintf("%s QuotaPoolUsage[PagedPool] %ld\n", pad,*((ULONG *) &QuotaPoolUsage[PagedPool*4]) );
  819. dprintf("%s QuotaPoolUsage[NonPagedPool] %ld\n", pad,*((ULONG *) &QuotaPoolUsage[NonPagedPool*4]) );
  820. } else {
  821. dprintf("%s QuotaPoolUsage[PagedPool] %I64ld\n", pad,*((ULONG64 *) &QuotaPoolUsage[PagedPool*8]) );
  822. dprintf("%s QuotaPoolUsage[NonPagedPool] %I64ld\n", pad,*((ULONG64 *) &QuotaPoolUsage[NonPagedPool*8]) );
  823. }
  824. dprintf("%s Working Set Sizes (now,min,max) (%I64ld, %I64ld, %I64ld) (%I64ldKB, %I64ldKB, %I64ldKB)\n",
  825. pad,
  826. Vm_WorkingSetSize,
  827. Vm_MinimumWorkingSetSize,
  828. Vm_MaximumWorkingSetSize,
  829. _KB*Vm_WorkingSetSize,
  830. _KB*Vm_MinimumWorkingSetSize,
  831. _KB*Vm_MaximumWorkingSetSize
  832. );
  833. dprintf("%s PeakWorkingSetSize %I64ld\n", pad, Vm_PeakWorkingSetSize );
  834. dprintf("%s VirtualSize %I64ld Mb\n", pad, VirtualSize /(1024*1024) );
  835. dprintf("%s PeakVirtualSize %I64ld Mb\n", pad, PeakVirtualSize/(1024*1024) );
  836. dprintf("%s PageFaultCount %I64ld\n", pad, Vm_PageFaultCount );
  837. dprintf("%s MemoryPriority %s\n", pad, Vm_MemoryPriority ? "FOREGROUND" : "BACKGROUND" );
  838. dprintf("%s BasePriority %I64ld\n", pad, Pcb_BasePriority);
  839. dprintf("%s CommitCharge %I64ld\n", pad, CommitCharge );
  840. if ( DebugPort ) {
  841. dprintf("%s DebugPort %p\n", pad, DebugPort );
  842. }
  843. if ( Job ) {
  844. dprintf("%s Job %p\n", pad, Job );
  845. }
  846. dprintf("\n");
  847. //
  848. // If the object table is NULL, the process is being destroyed and
  849. // there are no threads
  850. //
  851. return (ObjectTable != 0) ? 1 : -1;
  852. }
  853. //
  854. // This is to be called from .c file extensions which do not do INIT_API
  855. // that is they do not set g_ExtControl needed for stacktrace in DumpThread
  856. //
  857. // It will set the globals needed to dump stacktrace and call DumpThread
  858. //
  859. BOOL
  860. DumpThreadEx (
  861. IN ULONG Processor,
  862. IN char *Pad,
  863. IN ULONG64 RealThreadBase,
  864. IN ULONG Flags,
  865. IN PDEBUG_CLIENT pDbgClient
  866. )
  867. {
  868. BOOL retval = FALSE;
  869. if (pDbgClient &&
  870. (ExtQuery(pDbgClient) == S_OK)) {
  871. retval = DumpThread(Processor, Pad, RealThreadBase, Flags);
  872. ExtRelease();
  873. }
  874. return retval;
  875. }
  876. BOOL
  877. DumpThread (
  878. IN ULONG Processor,
  879. IN char *Pad,
  880. IN ULONG64 RealThreadBase,
  881. IN ULONG64 Flags
  882. )
  883. {
  884. #define MAX_STACK_FRAMES 40
  885. TIME_FIELDS Times;
  886. LARGE_INTEGER RunTime;
  887. ULONG64 Address;
  888. ULONG WaitOffset;
  889. ULONG64 Process;
  890. CHAR Buffer[256];
  891. ULONG TimeIncrement;
  892. ULONG frames = 0;
  893. ULONG i;
  894. ULONG err;
  895. ULONG64 displacement;
  896. DEBUG_STACK_FRAME stk[MAX_STACK_FRAMES];
  897. BOOL LongAddrs = IsPtr64();
  898. ULONG Tcb_Alertable = 0, Tcb_Proc;
  899. ULONG64 ActiveImpersonationInfo=0, Cid_UniqueProcess=0, Cid_UniqueThread=0, ImpersonationInfo=0,
  900. ImpersonationInfo_ImpersonationLevel=0, ImpersonationInfo_Token=0, IrpList_Flink=0,
  901. IrpList_Blink=0, LpcReceivedMessageId=0, LpcReceivedMsgIdValid=0, LpcReplyMessage=0, LpcReplyMessageId=0,
  902. PerformanceCountHigh=0, PerformanceCountLow=0, StartAddress=0, Tcb_ApcState_Process=0,
  903. Tcb_BasePriority=0, Tcb_CallbackStack=0, Tcb_ContextSwitches=0, Tcb_DecrementCount=0, Tcb_EnableStackSwap=0,
  904. Tcb_FreezeCount=0, Tcb_Header_Type=0, Tcb_InitialStack=0, Tcb_KernelStack=0, Tcb_KernelStackResident=0,
  905. Tcb_KernelTime=0, Tcb_LargeStack=0, Tcb_NextProcessor=0, Tcb_Priority=0, Tcb_PriorityDecrement=0,
  906. Tcb_StackBase=0, Tcb_StackLimit=0, Tcb_State=0, Tcb_SuspendCount=0, Tcb_Teb=0, Tcb_UserTime=0,
  907. Tcb_WaitBlockList=0, Tcb_WaitMode=0, Tcb_WaitReason=0, Tcb_WaitTime=0,
  908. Tcb_Win32Thread=0, Win32StartAddress=0, ObpLUIDDeviceMapsEnabled=0;
  909. ULONG IrpListOffset;
  910. TCHAR threadTyp[] = "nt!_ETHREAD";
  911. if (!IsPtr64())
  912. {
  913. RealThreadBase = (ULONG64) (LONG64) (LONG) RealThreadBase;
  914. }
  915. if (GetFieldOffset(threadTyp, "IrpList", &IrpListOffset))
  916. {
  917. dprintf("Cannot find nt!_ETHREAD type.\n");
  918. return FALSE;
  919. }
  920. if (CheckControlC()) {
  921. return FALSE;
  922. }
  923. if (InitTypeRead(RealThreadBase, nt!_ETHREAD))
  924. {
  925. dprintf("%s*** Error in in reading nt!_ETHREAD @ %p\n", Pad, RealThreadBase);
  926. return FALSE;
  927. }
  928. Tcb_Header_Type = ReadField(Tcb.Header.Type);
  929. Cid_UniqueProcess = ReadField(Cid.UniqueProcess);
  930. Cid_UniqueThread = ReadField(Cid.UniqueThread);
  931. Tcb_Teb = ReadField(Tcb.Teb);
  932. Tcb_Win32Thread = ReadField(Tcb.Win32Thread);
  933. Tcb_State = ReadField(Tcb.State);
  934. Tcb_WaitReason = ReadField(Tcb.WaitReason);
  935. Tcb_WaitMode = ReadField(Tcb.WaitMode);
  936. Tcb_Alertable = (ULONG) ReadField(Tcb.Alertable);
  937. if (Tcb_Header_Type != ThreadObject) {
  938. dprintf("TYPE mismatch for thread object at %p\n",RealThreadBase);
  939. return FALSE;
  940. }
  941. dprintf("%sTHREAD %p Cid %1p.%1p Teb: %p %s%sWin32Thread: %p ",
  942. Pad, RealThreadBase,
  943. Cid_UniqueProcess,
  944. Cid_UniqueThread,
  945. Tcb_Teb,
  946. (LongAddrs ? "\n" : ""),
  947. (LongAddrs ? Pad : ""),
  948. Tcb_Win32Thread);
  949. switch (Tcb_State) {
  950. case Initialized:
  951. dprintf("%s\n","INITIALIZED");break;
  952. case Ready:
  953. dprintf("%s\n","READY");break;
  954. case Running:
  955. dprintf("%s%s%s on processor %lx\n",
  956. (!LongAddrs ? "\n" : ""),
  957. (!LongAddrs ? Pad : ""),
  958. "RUNNING", Tcb_Proc = (ULONG) ReadField(Tcb.NextProcessor));
  959. break;
  960. case Standby:
  961. dprintf("%s\n","STANDBY");break;
  962. case Terminated:
  963. dprintf("%s\n","TERMINATED");break;
  964. case Waiting:
  965. dprintf("%s","WAIT");break;
  966. case Transition:
  967. dprintf("%s\n","TRANSITION");break;
  968. case DeferredReady:
  969. dprintf("%s\n","DEFERREDREADY");break;
  970. }
  971. if (!(Flags & 2)) {
  972. dprintf("\n");
  973. return TRUE;
  974. }
  975. Tcb_SuspendCount = ReadField(Tcb.SuspendCount);
  976. Tcb_FreezeCount = ReadField(Tcb.FreezeCount);
  977. Tcb_WaitBlockList = ReadField(Tcb.WaitBlockList);
  978. LpcReplyMessageId = ReadField(LpcReplyMessageId);
  979. LpcReplyMessage = ReadField(LpcReplyMessage);
  980. IrpList_Flink = ReadField(IrpList.Flink);
  981. IrpList_Blink = ReadField(IrpList.Blink);
  982. ActiveImpersonationInfo = ReadField(ActiveImpersonationInfo);
  983. ImpersonationInfo = ReadField(ImpersonationInfo);
  984. Tcb_ApcState_Process = ReadField(Tcb.ApcState.Process);
  985. Tcb_WaitTime = ReadField(Tcb.WaitTime);
  986. Tcb_ContextSwitches = ReadField(Tcb.ContextSwitches);
  987. Tcb_EnableStackSwap = ReadField(Tcb.EnableStackSwap);
  988. Tcb_LargeStack = ReadField(Tcb.LargeStack);
  989. Tcb_UserTime = ReadField(Tcb.UserTime);
  990. Tcb_KernelTime = ReadField(Tcb.KernelTime);
  991. PerformanceCountHigh = ReadField(PerformanceCountHigh);
  992. PerformanceCountLow = ReadField(PerformanceCountLow);
  993. StartAddress = ReadField(StartAddress);
  994. Win32StartAddress = ReadField(Win32StartAddress);
  995. LpcReceivedMsgIdValid = ReadField(LpcReceivedMsgIdValid);
  996. LpcReceivedMessageId = ReadField(LpcReceivedMessageId);
  997. Tcb_InitialStack = ReadField(Tcb.InitialStack);
  998. Tcb_KernelStack = ReadField(Tcb.KernelStack);
  999. Tcb_StackBase = ReadField(Tcb.StackBase);
  1000. Tcb_StackLimit = ReadField(Tcb.StackLimit);
  1001. Tcb_CallbackStack = ReadField(Tcb.CallbackStack);
  1002. Tcb_Priority = ReadField(Tcb.Priority);
  1003. Tcb_BasePriority = ReadField(Tcb.BasePriority);
  1004. Tcb_PriorityDecrement = ReadField(Tcb.PriorityDecrement);
  1005. Tcb_KernelStackResident = ReadField(Tcb.KernelStackResident);
  1006. Tcb_NextProcessor = ReadField(Tcb.NextProcessor);
  1007. if (BuildNo < 3648)
  1008. {
  1009. Tcb_DecrementCount = ReadField(Tcb.DecrementCount);
  1010. }
  1011. if (Tcb_State == Waiting) {
  1012. ULONG64 WaitBlock_Object=0, WaitBlock_NextWaitBlock=0;
  1013. dprintf(": (%s) %s %s\n",
  1014. GetThreadWaitReasonName((ULONG)Tcb_WaitReason),
  1015. (Tcb_WaitMode==0) ? "KernelMode" : "UserMode", Tcb_Alertable ? "Alertable" : "Non-Alertable");
  1016. if ( Tcb_SuspendCount ) {
  1017. dprintf("SuspendCount %lx\n",Tcb_SuspendCount);
  1018. }
  1019. if ( Tcb_FreezeCount ) {
  1020. dprintf("FreezeCount %lx\n",Tcb_FreezeCount);
  1021. }
  1022. WaitOffset = (ULONG) (Tcb_WaitBlockList - RealThreadBase);
  1023. if (err = GetFieldValue(Tcb_WaitBlockList, "nt!_KWAIT_BLOCK", "Object", WaitBlock_Object)) {
  1024. dprintf("%sCannot read nt!_KWAIT_BLOCK at %p - error %lx\n", Pad, Tcb_WaitBlockList, err);
  1025. goto BadWaitBlock;
  1026. }
  1027. GetFieldValue(Tcb_WaitBlockList, "nt!_KWAIT_BLOCK", "NextWaitBlock", WaitBlock_NextWaitBlock);
  1028. do {
  1029. TCHAR MutantListEntry[16]={0};
  1030. ULONG64 OwnerThread=0, Header_Type=0;
  1031. dprintf("%s %p ",Pad, WaitBlock_Object);
  1032. GetFieldValue(WaitBlock_Object, "nt!_KMUTANT", "Header.Type", Header_Type);
  1033. GetFieldValue(WaitBlock_Object, "nt!_KMUTANT", "MutantListEntry", MutantListEntry);
  1034. GetFieldValue(WaitBlock_Object, "nt!_KMUTANT", "OwnerThread", OwnerThread);
  1035. switch (Header_Type) {
  1036. case EventNotificationObject:
  1037. dprintf("NotificationEvent\n");
  1038. break;
  1039. case EventSynchronizationObject:
  1040. dprintf("SynchronizationEvent\n");
  1041. break;
  1042. case SemaphoreObject:
  1043. dprintf("Semaphore Limit 0x%lx\n",
  1044. *((ULONG *) &MutantListEntry[0]));
  1045. break;
  1046. case ThreadObject:
  1047. dprintf("Thread\n");
  1048. break;
  1049. case TimerNotificationObject:
  1050. dprintf("NotificationTimer\n");
  1051. break;
  1052. case TimerSynchronizationObject:
  1053. dprintf("SynchronizationTimer\n");
  1054. break;
  1055. case EventPairObject:
  1056. dprintf("EventPair\n");
  1057. break;
  1058. case ProcessObject:
  1059. dprintf("ProcessObject\n");
  1060. break;
  1061. case MutantObject:
  1062. dprintf("Mutant - owning thread %lp\n",
  1063. OwnerThread);
  1064. break;
  1065. default:
  1066. dprintf("Unknown\n");
  1067. // goto BadWaitBlock;
  1068. break;
  1069. }
  1070. if ( WaitBlock_NextWaitBlock == Tcb_WaitBlockList) {
  1071. break;
  1072. goto BadWaitBlock;
  1073. }
  1074. if (err = GetFieldValue(WaitBlock_NextWaitBlock, "nt!_KWAIT_BLOCK", "Object", WaitBlock_Object)) {
  1075. dprintf("%sCannot read nt!_KWAIT_BLOCK at %p - error %lx\n", Pad, WaitBlock_NextWaitBlock, err);
  1076. goto BadWaitBlock;
  1077. }
  1078. GetFieldValue(WaitBlock_NextWaitBlock, "nt!_KWAIT_BLOCK", "NextWaitBlock", WaitBlock_NextWaitBlock);
  1079. if (CheckControlC()) {
  1080. return FALSE;
  1081. }
  1082. } while ( TRUE );
  1083. }
  1084. BadWaitBlock:
  1085. if (!(Flags & 4)) {
  1086. dprintf("\n");
  1087. return TRUE;
  1088. }
  1089. if (LpcReplyMessageId != 0) {
  1090. dprintf("%sWaiting for reply to LPC MessageId %08p:\n",Pad,LpcReplyMessageId);
  1091. }
  1092. if (LpcReplyMessage) {
  1093. if (LpcReplyMessage & 1) {
  1094. dprintf("%sCurrent LPC port %08lp\n",Pad, (LpcReplyMessage & ~((ULONG64)1)));
  1095. } else {
  1096. ULONG64 Entry_Flink, Entry_Blink;
  1097. dprintf("%sPending LPC Reply Message:\n",Pad);
  1098. Address = (ULONG64) LpcReplyMessage;
  1099. GetFieldValue(Address, "nt!_LPCP_MESSAGE", "Entry.Flink", Entry_Flink);
  1100. GetFieldValue(Address, "nt!_LPCP_MESSAGE", "Entry.Blink", Entry_Blink);
  1101. dprintf("%s %08lp: [%08lp,%08lp]\n",
  1102. Pad,
  1103. Address,
  1104. Entry_Blink,
  1105. Entry_Flink
  1106. );
  1107. }
  1108. }
  1109. if (IrpList_Flink && (IrpList_Flink != IrpList_Blink ||
  1110. IrpList_Flink != (RealThreadBase + IrpListOffset))
  1111. ) {
  1112. ULONG64 IrpListHead = RealThreadBase + IrpListOffset;
  1113. ULONG64 Next;
  1114. ULONG Counter = 0;
  1115. ULONG ThreadListEntryOffset;
  1116. Next = IrpList_Flink;
  1117. if (!GetFieldOffset("nt!_IRP", "ThreadListEntry", &ThreadListEntryOffset))
  1118. {
  1119. dprintf("%sIRP List:\n",Pad);
  1120. while (Next && (Next != IrpListHead) && (Counter < 17)) {
  1121. ULONG Irp_Type=0, Irp_Size=0, Irp_Flags=0;
  1122. ULONG64 Irp_MdlAddress=0;
  1123. Counter += 1;
  1124. // subtract threadlistentry offset
  1125. Address = Next - ThreadListEntryOffset;
  1126. Next=0;
  1127. if (GetFieldValue(Address, "nt!_IRP", "Type", Irp_Type))
  1128. {
  1129. dprintf("%s Unable to read nt!_IRP @ %p\n", Pad, Address);
  1130. break;
  1131. }
  1132. GetFieldValue(Address, "nt!_IRP", "Size", Irp_Size);
  1133. GetFieldValue(Address, "nt!_IRP", "Flags", Irp_Flags);
  1134. GetFieldValue(Address, "nt!_IRP", "MdlAddress", Irp_MdlAddress);
  1135. GetFieldValue(Address, "nt!_IRP", "ThreadListEntry.Flink", Next);
  1136. dprintf("%s %08p: (%04x,%04x) Flags: %08lx Mdl: %08lp\n",
  1137. Pad,Address,Irp_Type,Irp_Size,Irp_Flags,Irp_MdlAddress);
  1138. }
  1139. }
  1140. }
  1141. //
  1142. // Impersonation information
  1143. //
  1144. if (ActiveImpersonationInfo) {
  1145. InitTypeRead(ImpersonationInfo, nt!_PS_IMPERSONATION_INFORMATION);
  1146. ImpersonationInfo_Token = ReadField(Token);
  1147. ImpersonationInfo_ImpersonationLevel = ReadField(ImpersonationLevel);
  1148. if (ImpersonationInfo_Token) {
  1149. dprintf("%sImpersonation token: %p (Level %s)\n",
  1150. Pad, ImpersonationInfo_Token,
  1151. SecImpLevels( ImpersonationInfo_ImpersonationLevel ) );
  1152. }
  1153. else
  1154. {
  1155. dprintf("%sUnable to read Impersonation Information at %x\n",
  1156. Pad, ImpersonationInfo );
  1157. }
  1158. } else {
  1159. dprintf("%sNot impersonating\n", Pad);
  1160. }
  1161. //
  1162. // DeviceMap information
  1163. //
  1164. // check to see if per-LUID devicemaps are turned on
  1165. ULONG64 ObpLUIDDeviceMapsEnabledAddress;
  1166. ObpLUIDDeviceMapsEnabledAddress = GetExpression("nt!ObpLUIDDeviceMapsEnabled");
  1167. if (ObpLUIDDeviceMapsEnabledAddress) {
  1168. ObpLUIDDeviceMapsEnabled = GetUlongFromAddress(ObpLUIDDeviceMapsEnabled);
  1169. } else {
  1170. ObpLUIDDeviceMapsEnabled = 0;
  1171. }
  1172. if (((ULONG)ObpLUIDDeviceMapsEnabled) != 0) {
  1173. //
  1174. // If we're impersonating, get the DeviceMap information
  1175. // from the token.
  1176. //
  1177. if (ActiveImpersonationInfo) {
  1178. ImpersonationInfo_Token = ReadField(Token);
  1179. // get the LUID from the token
  1180. ULONG64 AuthenticationId = 0;
  1181. GetFieldValue(ImpersonationInfo_Token,
  1182. "nt!_TOKEN",
  1183. "AuthenticationId",
  1184. AuthenticationId);
  1185. // find the devmap directory object
  1186. UCHAR Path[64];
  1187. ULONG64 DeviceMapDirectory = 0;
  1188. sprintf((PCHAR)Path, "\\Sessions\\0\\DosDevices\\%08x-%08x",
  1189. (ULONG)((AuthenticationId >> 32) & 0xffffffff),
  1190. (ULONG)(AuthenticationId & 0xffffffff)
  1191. );
  1192. DeviceMapDirectory = FindObjectByName(Path, 0);
  1193. if(DeviceMapDirectory != 0) {
  1194. // get the device map itself
  1195. ULONG64 DeviceMap = 0;
  1196. GetFieldValue(DeviceMapDirectory,
  1197. "nt!_OBJECT_DIRECTORY",
  1198. "DeviceMap",
  1199. DeviceMap);
  1200. if(DeviceMap != 0) {
  1201. dprintf("%sDeviceMap %p\n", Pad, DeviceMap);
  1202. }
  1203. }
  1204. //
  1205. // Else, we're not impersonating, so just return the
  1206. // DeviceMap from our parent process.
  1207. //
  1208. } else if (Tcb_ApcState_Process != 0) {
  1209. // get the devicemap from the process
  1210. ULONG64 DeviceMap = 0;
  1211. GetFieldValue(Tcb_ApcState_Process,
  1212. "nt!_EPROCESS",
  1213. "DeviceMap",
  1214. DeviceMap);
  1215. if (DeviceMap != 0) {
  1216. dprintf("%sDeviceMap %p\n", Pad, DeviceMap);
  1217. }
  1218. }
  1219. }
  1220. // Process = CONTAINING_RECORD(Tcb_ApcState_Process,EPROCESS,Pcb);
  1221. // Pcb is the 1st element
  1222. Process = Tcb_ApcState_Process;
  1223. dprintf("%sOwning Process %lp\n", Pad, Process);
  1224. GetTheSystemTime (&RunTime);
  1225. dprintf("%sWaitTime (ticks) %ld\n",
  1226. Pad,
  1227. Tcb_WaitTime);
  1228. dprintf("%sContext Switch Count %ld",
  1229. Pad,
  1230. Tcb_ContextSwitches);
  1231. if (!Tcb_EnableStackSwap) {
  1232. dprintf(" NoStackSwap");
  1233. } else {
  1234. dprintf(" ");
  1235. }
  1236. if (Tcb_LargeStack) {
  1237. dprintf(" LargeStack");
  1238. }
  1239. dprintf ("\n");
  1240. //
  1241. // Get the time increment value which is used to compute runtime.
  1242. //
  1243. TimeIncrement = GetNtDebuggerDataValue( KeTimeIncrement );
  1244. RunTime.QuadPart = UInt32x32To64(Tcb_UserTime, TimeIncrement);
  1245. RtlTimeToElapsedTimeFields ( &RunTime, &Times);
  1246. dprintf("%sUserTime %3ld:%02ld:%02ld.%04ld\n",
  1247. Pad,
  1248. Times.Hour,
  1249. Times.Minute,
  1250. Times.Second,
  1251. Times.Milliseconds);
  1252. RunTime.QuadPart = UInt32x32To64(Tcb_KernelTime, TimeIncrement);
  1253. RtlTimeToElapsedTimeFields ( &RunTime, &Times);
  1254. dprintf("%sKernelTime %3ld:%02ld:%02ld.%04ld\n",
  1255. Pad,
  1256. Times.Hour,
  1257. Times.Minute,
  1258. Times.Second,
  1259. Times.Milliseconds);
  1260. if (PerformanceCountHigh != 0) {
  1261. dprintf("%sPerfCounterHigh 0x%lx %08lx\n",
  1262. Pad,
  1263. PerformanceCountHigh,
  1264. PerformanceCountHigh);
  1265. } else if (PerformanceCountLow != 0) {
  1266. dprintf("%sPerfCounter %lu\n",Pad,PerformanceCountLow);
  1267. }
  1268. dumpSymbolicAddress(StartAddress, Buffer, TRUE);
  1269. dprintf("%sStart Address %s\n",
  1270. Pad,
  1271. Buffer
  1272. );
  1273. if (Win32StartAddress)
  1274. if (LpcReceivedMsgIdValid)
  1275. {
  1276. dprintf("%sLPC Server thread working on message Id %x\n",
  1277. Pad,
  1278. LpcReceivedMessageId
  1279. );
  1280. }
  1281. else
  1282. {
  1283. dumpSymbolicAddress(Win32StartAddress, Buffer, TRUE);
  1284. dprintf("%sWin32 Start Address %s\n",
  1285. Pad,
  1286. Buffer
  1287. );
  1288. }
  1289. dprintf("%sStack Init %lp Current %lp%s%sBase %lp Limit %lp Call %lp\n",
  1290. Pad,
  1291. Tcb_InitialStack,
  1292. Tcb_KernelStack,
  1293. (LongAddrs ? "\n" : ""),
  1294. (LongAddrs ? Pad : " " ),
  1295. Tcb_StackBase,
  1296. Tcb_StackLimit,
  1297. Tcb_CallbackStack
  1298. );
  1299. if (BuildNo < 3648)
  1300. {
  1301. dprintf("%sPriority %I64ld BasePriority %I64ld PriorityDecrement %I64ld DecrementCount %I64ld\n",
  1302. Pad,
  1303. Tcb_Priority,
  1304. Tcb_BasePriority,
  1305. Tcb_PriorityDecrement,
  1306. Tcb_DecrementCount
  1307. );
  1308. } else
  1309. {
  1310. dprintf("%sPriority %I64ld BasePriority %I64ld PriorityDecrement %I64ld\n",
  1311. Pad,
  1312. Tcb_Priority,
  1313. Tcb_BasePriority,
  1314. Tcb_PriorityDecrement
  1315. );
  1316. }
  1317. if (!Tcb_KernelStackResident) {
  1318. dprintf("%sKernel stack not resident.\n", Pad);
  1319. // dprintf("\n");
  1320. // return TRUE;
  1321. // Try getting the stack even in this case - this might still be paged in
  1322. }
  1323. if (// (Tcb_State == Running && Processor == Tcb_Proc) || // Set thread context for everything
  1324. Ioctl(IG_SET_THREAD, &RealThreadBase, sizeof(ULONG64))) {
  1325. g_ExtControl->GetStackTrace(0, 0, 0, stk, MAX_STACK_FRAMES, &frames );
  1326. if (frames) {
  1327. ULONG OutFlags;
  1328. OutFlags = (DEBUG_STACK_COLUMN_NAMES | DEBUG_STACK_FUNCTION_INFO |
  1329. DEBUG_STACK_FRAME_ADDRESSES | DEBUG_STACK_SOURCE_LINE);
  1330. if (!(Flags & 0x8))
  1331. {
  1332. OutFlags |= DEBUG_STACK_ARGUMENTS;
  1333. }
  1334. // if (Flags & 0x10)
  1335. // {
  1336. // OutFlags |= DEBUG_STACK_FRAME_ADDRESSES_RA_ONLY;
  1337. // }
  1338. g_ExtClient->SetOutputLinePrefix(Pad);
  1339. g_ExtControl->OutputStackTrace(DEBUG_OUTCTL_AMBIENT, stk, frames, OutFlags);
  1340. g_ExtClient->SetOutputLinePrefix(NULL);
  1341. }
  1342. }
  1343. dprintf("\n");
  1344. return TRUE;
  1345. }
  1346. /**
  1347. Routine to get address of the record containing a field on a debugee machine.
  1348. Returns size of the type on success.
  1349. ULONG
  1350. GetContainingRecord (
  1351. IN OUT PULONG64 pAddr,
  1352. IN LPSTR Type,
  1353. IN LPSTR Field
  1354. )
  1355. {
  1356. ULONG64 off;
  1357. ULONG sz;
  1358. sz = GetFieldOffset(Type, Field, &off);
  1359. *pAddr -= off;
  1360. return sz;
  1361. }
  1362. **/
  1363. typedef struct THREAD_LIST_DUMP {
  1364. ULONG dwProcessor;
  1365. LPSTR pad;
  1366. ULONG Flags;
  1367. } THREAD_LIST_DUMP;
  1368. ULONG
  1369. ThreadListCallback (
  1370. PFIELD_INFO NextThrd,
  1371. PVOID Context
  1372. )
  1373. {
  1374. THREAD_LIST_DUMP *Thread = (THREAD_LIST_DUMP *) Context;
  1375. return (!DumpThread(Thread->dwProcessor, Thread->pad, NextThrd->address, Thread->Flags));
  1376. }
  1377. typedef struct PROCESS_DUMP_CONTEXT {
  1378. ULONG dwProcessor;
  1379. PCHAR Pad;
  1380. ULONG Flag;
  1381. PCHAR ImageFileName;
  1382. BOOL DumpCid;
  1383. ULONG64 Cid;
  1384. ULONG SessionId;
  1385. } PROCESS_DUMP_CONTEXT;
  1386. ULONG
  1387. ProcessListCallback(
  1388. PFIELD_INFO listElement,
  1389. PVOID Context
  1390. )
  1391. {
  1392. PROCESS_DUMP_CONTEXT *ProcDumpInfo = (PROCESS_DUMP_CONTEXT *) Context;
  1393. // address field contains the address of this process
  1394. ULONG64 ProcAddress=listElement->address;
  1395. ULONG ret;
  1396. //
  1397. // Dump the process for which this routine is called
  1398. //
  1399. if (ProcDumpInfo->DumpCid) {
  1400. ULONG64 UniqId;
  1401. GetFieldValue(ProcAddress, "nt!_EPROCESS", "UniqueProcessId", UniqId);
  1402. if (UniqId != ProcDumpInfo->Cid) {
  1403. return FALSE;
  1404. }
  1405. }
  1406. // Limit dump to a single session if so requested.
  1407. if (ProcDumpInfo->SessionId != -1) {
  1408. ULONG SessionId;
  1409. if (!GetProcessSessionId(ProcAddress, &SessionId) ||
  1410. SessionId != ProcDumpInfo->SessionId) {
  1411. return FALSE;
  1412. }
  1413. }
  1414. if (ret = DumpProcess(ProcDumpInfo->Pad, listElement->address, ProcDumpInfo->Flag, ProcDumpInfo->ImageFileName)) {
  1415. ULONG64 ProcFlink=0;
  1416. if ((ProcDumpInfo->Flag & 6) && ret != -1) {
  1417. //
  1418. // Dump the threads
  1419. //
  1420. ULONG64 ThreadListHead_Flink=0;
  1421. THREAD_LIST_DUMP Context = {ProcDumpInfo->dwProcessor, " ", ProcDumpInfo->Flag};
  1422. GetFieldValue(ProcAddress, "nt!_EPROCESS", "Pcb.ThreadListHead.Flink", ThreadListHead_Flink);
  1423. // dprintf("Listing threads, threadlist.flnik %p\n", ThreadListHead_Flink);
  1424. // dprintf("Dumping threads from %I64x to %I64x + %x.\n", Next, RealProcessBase , ThreadListHeadOffset);
  1425. ListType("nt!_ETHREAD", ThreadListHead_Flink, 1, "Tcb.ThreadListEntry.Flink", (PVOID) &Context, &ThreadListCallback);
  1426. if (CheckControlC()) {
  1427. return TRUE;
  1428. }
  1429. }
  1430. if (CheckControlC()) {
  1431. return TRUE;
  1432. }
  1433. GetFieldValue(ProcAddress, "nt!_EPROCESS", "ActiveProcessLinks.Flink", ProcFlink);
  1434. // dprintf("Next proc flink %p, this addr %p\n", ProcFlink, listElement->address);
  1435. return FALSE;
  1436. }
  1437. return TRUE;
  1438. }
  1439. DECLARE_API( process )
  1440. /*++
  1441. Routine Description:
  1442. Dumps the active process list.
  1443. Arguments:
  1444. None.
  1445. Return Value:
  1446. None.
  1447. --*/
  1448. {
  1449. ULONG64 ProcessToDump;
  1450. ULONG Flags = -1;
  1451. ULONG64 Next;
  1452. ULONG64 ProcessHead;
  1453. ULONG64 Process;
  1454. ULONG64 UserProbeAddress;
  1455. PCHAR ImageFileName;
  1456. CHAR Buf[256];
  1457. ULONG64 ActiveProcessLinksOffset=0;
  1458. ULONG64 UniqueProcessId=0;
  1459. PROCESS_DUMP_CONTEXT Proc={0, "", Flags, NULL, 0, 0};
  1460. ULONG dwProcessor=0;
  1461. HANDLE hCurrentThread=NULL;
  1462. ULONG64 Expr;
  1463. INIT_API();
  1464. if (!GetCurrentProcessor(Client, &dwProcessor, &hCurrentThread)) {
  1465. dwProcessor = 0;
  1466. hCurrentThread = 0;
  1467. }
  1468. Proc.dwProcessor = dwProcessor;
  1469. ProcessToDump = (ULONG64) -1;
  1470. Proc.SessionId = -1;
  1471. for (;;) {
  1472. while (*args == ' ' || *args == '\t') {
  1473. args++;
  1474. }
  1475. if (*args == '/') {
  1476. switch(*(++args)) {
  1477. case 's':
  1478. args++;
  1479. if (!GetExpressionEx(args, &Expr, &args)) {
  1480. dprintf("Invalid argument to /s\n");
  1481. } else {
  1482. Proc.SessionId = (ULONG)Expr;
  1483. }
  1484. break;
  1485. default:
  1486. dprintf("Unknown option '%c'\n", *args);
  1487. args++;
  1488. break;
  1489. }
  1490. } else {
  1491. break;
  1492. }
  1493. }
  1494. RtlZeroMemory(Buf, 256);
  1495. if (GetExpressionEx(args,&ProcessToDump, &args)) {
  1496. if (sscanf(args, "%lx %255s", &Flags, Buf) != 2) {
  1497. Buf[0] = 0;
  1498. }
  1499. }
  1500. if (Buf[0] != '\0') {
  1501. Proc.ImageFileName = Buf;
  1502. ImageFileName = Buf;
  1503. } else {
  1504. ImageFileName = NULL;
  1505. }
  1506. if (ProcessToDump == (ULONG64) -1) {
  1507. GetCurrentProcessAddr( dwProcessor, 0, &ProcessToDump );
  1508. if (ProcessToDump == 0) {
  1509. dprintf("Unable to get current process pointer.\n");
  1510. goto processExit;
  1511. }
  1512. if (Flags == -1) {
  1513. Flags = 3;
  1514. }
  1515. }
  1516. if (!IsPtr64()) {
  1517. ProcessToDump = (ULONG64) (LONG64) (LONG) ProcessToDump;
  1518. }
  1519. if ((ProcessToDump == 0) && (ImageFileName == NULL)) {
  1520. dprintf("**** NT ACTIVE PROCESS DUMP ****\n");
  1521. if (Flags == -1) {
  1522. Flags = 3;
  1523. }
  1524. }
  1525. UserProbeAddress = GetNtDebuggerDataPtrValue(MmUserProbeAddress);
  1526. if (!GetExpression("NT!PsActiveProcessHead")) {
  1527. dprintf("NT symbols are incorrect, please fix symbols\n");
  1528. goto processExit;
  1529. }
  1530. if (ProcessToDump < UserProbeAddress) {
  1531. if (!GetProcessHead(&ProcessHead, &Next)) {
  1532. goto processExit;
  1533. }
  1534. if (ProcessToDump != 0) {
  1535. dprintf("Searching for Process with Cid == %I64lx\n", ProcessToDump);
  1536. Proc.Cid = ProcessToDump; Proc.DumpCid = TRUE;
  1537. }
  1538. }
  1539. else {
  1540. Next = 0;
  1541. ProcessHead = 1;
  1542. }
  1543. Proc.Flag = Flags;
  1544. if (Next != 0) {
  1545. //
  1546. // Dump the process List
  1547. //
  1548. ListType("nt!_EPROCESS", Next, 1, "ActiveProcessLinks.Flink", &Proc, &ProcessListCallback);
  1549. goto processExit;
  1550. }
  1551. else {
  1552. Process = ProcessToDump;
  1553. }
  1554. #if 0
  1555. dprintf("Next: %I64x, \tProcess: %I64x, \n\tProcHead: %I64x\n",
  1556. Next, Process, ProcessHead);
  1557. #endif
  1558. if (GetFieldValue(Process, "nt!_EPROCESS", "UniqueProcessId", UniqueProcessId)) {
  1559. dprintf("Error in reading nt!_EPROCESS at %p\n", Process);
  1560. goto processExit;
  1561. }
  1562. if (ProcessToDump < UserProbeAddress && ProcessToDump == UniqueProcessId ||
  1563. ProcessToDump >= UserProbeAddress && ProcessToDump == Process
  1564. ) {
  1565. FIELD_INFO dummyForCallback = {(PUCHAR) "", NULL, 0, 0, Process, NULL};
  1566. ProcessListCallback(&dummyForCallback, &Proc);
  1567. goto processExit;
  1568. }
  1569. processExit:
  1570. EXIT_API();
  1571. return S_OK;
  1572. }
  1573. typedef struct _THREAD_FIND {
  1574. ULONG64 StackPointer;
  1575. ULONG Cid;
  1576. ULONG64 Thread;
  1577. } THREAD_FIND, *PTHREAD_FIND;
  1578. ULONG
  1579. FindThreadCallback(
  1580. PFIELD_INFO pAddrInfo,
  1581. PVOID Context
  1582. )
  1583. {
  1584. ULONG64 stackBaseValue=0, stackLimitValue=0;
  1585. ULONG64 thread = pAddrInfo->address;
  1586. THREAD_FIND *pThreadInfo = (THREAD_FIND *) Context;
  1587. dprintf("Now checking thread 0x%p\r", thread);
  1588. if (pThreadInfo->Cid != 0)
  1589. {
  1590. ULONG64 UniqueThread;
  1591. if (!GetFieldValue(thread, "nt!_ETHREAD", "Cid.UniqueThread", UniqueThread))
  1592. {
  1593. if (UniqueThread == pThreadInfo->Cid)
  1594. {
  1595. pThreadInfo->Thread = thread;
  1596. return TRUE;
  1597. }
  1598. }
  1599. } else if (pThreadInfo->StackPointer != 0)
  1600. {
  1601. //
  1602. // We need two values from the thread structure: the kernel thread
  1603. // base and the kernel thread limit.
  1604. //
  1605. if (GetFieldValue(thread, "nt!_ETHREAD", "Tcb.StackBase", stackBaseValue))
  1606. {
  1607. dprintf("Unable to get value of stack base of thread(0x%08p)\n",
  1608. thread);
  1609. return TRUE;
  1610. }
  1611. if (pThreadInfo->StackPointer <= stackBaseValue)
  1612. {
  1613. if (GetFieldValue(thread, "nt!_ETHREAD", "Tcb.StackLimit", stackLimitValue))
  1614. {
  1615. dprintf("Unable to get value of stack limit\n");
  1616. return TRUE;
  1617. }
  1618. if (pThreadInfo->StackPointer > stackLimitValue)
  1619. {
  1620. //
  1621. // We have found our thread.
  1622. //
  1623. pThreadInfo->Thread = thread;
  1624. return TRUE;
  1625. }
  1626. }
  1627. }
  1628. //
  1629. // Look at the next thread
  1630. //
  1631. return FALSE; // Continue list
  1632. }
  1633. ULONG64
  1634. FindThreadInProcess(
  1635. PTHREAD_FIND pFindThreadParam,
  1636. ULONG64 Process
  1637. )
  1638. {
  1639. LIST_ENTRY64 listValue={0};
  1640. //
  1641. // Read the ThreadListHead within Process structure
  1642. //
  1643. GetFieldValue(Process, "nt!_EPROCESS", "ThreadListHead.Flink", listValue.Flink);
  1644. GetFieldValue(Process, "nt!_EPROCESS", "ThreadListHead.Blink", listValue.Blink);
  1645. //
  1646. // Go through thread list, and try to find thread
  1647. //
  1648. ListType("nt!_ETHREAD", listValue.Flink, 1, "ThreadListEntry.Flink", (PVOID) pFindThreadParam, &FindThreadCallback);
  1649. return pFindThreadParam->Thread;
  1650. }
  1651. ULONG64
  1652. FindThreadFromStackPointerThisProcess(
  1653. ULONG64 StackPointer,
  1654. ULONG64 Process
  1655. )
  1656. {
  1657. LIST_ENTRY64 listValue={0};
  1658. THREAD_FIND ThreadFindContext = {0};
  1659. ThreadFindContext.StackPointer = StackPointer;
  1660. ThreadFindContext.Thread = 0;
  1661. //
  1662. // Read the ThreadListHead within Process structure
  1663. //
  1664. GetFieldValue(Process, "nt!_EPROCESS", "ThreadListHead.Flink", listValue.Flink);
  1665. GetFieldValue(Process, "nt!_EPROCESS", "ThreadListHead.Blink", listValue.Blink);
  1666. //
  1667. // Go through thread list, and try to find thread
  1668. //
  1669. ListType("nt!_ETHREAD", listValue.Flink, 1, "ThreadListEntry.Flink", (PVOID) &ThreadFindContext, &FindThreadCallback);
  1670. return ThreadFindContext.Thread;
  1671. }
  1672. ULONG64
  1673. FindThread(
  1674. PTHREAD_FIND pFindThreadParam
  1675. )
  1676. {
  1677. ULONG64 processHead;
  1678. ULONG64 list;
  1679. LIST_ENTRY64 listValue={0};
  1680. ULONG64 next;
  1681. ULONG64 process=0;
  1682. ULONG64 thread;
  1683. ULONG ActiveProcessLinksOffset=0;
  1684. //
  1685. // First check the idle process, which is not included in the PS
  1686. // process list.
  1687. //
  1688. process = GetExpression( "NT!KeIdleProcess" );
  1689. if (process != 0) {
  1690. if (ReadPointer( process,
  1691. &process)) {
  1692. thread = FindThreadInProcess( pFindThreadParam,
  1693. process );
  1694. if (thread != 0) {
  1695. return thread;
  1696. }
  1697. }
  1698. }
  1699. //
  1700. // Now check the PS process list.
  1701. //
  1702. list = GetNtDebuggerData( PsActiveProcessHead );
  1703. if (list == 0) {
  1704. dprintf("Unable to get address of PsActiveProcessHead\n");
  1705. return 0;
  1706. }
  1707. if (!ReadPointer( list,
  1708. &listValue.Flink)) {
  1709. dprintf("Unable to read @ %p\n", list);
  1710. return 0;
  1711. }
  1712. next = listValue.Flink;
  1713. processHead = list;
  1714. //
  1715. // Get Offset of ProcessLinks
  1716. //
  1717. GetFieldOffset("nt!_EPROCESS", "ActiveProcessLinks", &ActiveProcessLinksOffset);
  1718. while (next != processHead) {
  1719. if (CheckControlC()) {
  1720. return 0;
  1721. }
  1722. //
  1723. // Derive a pointer to the process structure
  1724. //
  1725. process = next - ActiveProcessLinksOffset;
  1726. thread = FindThreadInProcess( pFindThreadParam,
  1727. process );
  1728. if (thread != 0) {
  1729. //
  1730. // We have found the thread which matches pFindThreadParam parameters
  1731. //
  1732. return thread;
  1733. }
  1734. //
  1735. // Get a pointer to the next process
  1736. //
  1737. if (!ReadPointer(next, &listValue.Flink) ||
  1738. !listValue.Flink)
  1739. {
  1740. dprintf("Unable to read next process from process list\n");
  1741. return 0;
  1742. }
  1743. next = listValue.Flink;
  1744. }
  1745. return 0;
  1746. }
  1747. DECLARE_API( thread )
  1748. /*++
  1749. Routine Description:
  1750. Dumps the specified thread.
  1751. Arguments:
  1752. None.
  1753. Return Value:
  1754. None.
  1755. --*/
  1756. {
  1757. ULONG64 Address, Tcb_Header_Type=0;
  1758. ULONG64 Flags;
  1759. ULONG64 Thread;
  1760. ULONG64 UserProbeAddress;
  1761. ULONG dwProcessor;
  1762. HANDLE hCurrentThread;
  1763. CHAR Token[100];
  1764. BOOL DumpByCid = FALSE;
  1765. THREAD_FIND ThreadFind = {0};
  1766. INIT_API();
  1767. if (!GetCurrentProcessor(Client, &dwProcessor, &hCurrentThread)) {
  1768. dwProcessor = 0;
  1769. hCurrentThread = 0;
  1770. }
  1771. while ((*args == ' ' || *args == '\t') && *args != '-') ++args;
  1772. if (*args == '-')
  1773. {
  1774. ++args;
  1775. switch (*args)
  1776. {
  1777. case 't':
  1778. {
  1779. DumpByCid = TRUE;
  1780. break;
  1781. }
  1782. default:
  1783. {
  1784. dprintf("Bad argument -%s\n", args);
  1785. goto threadExit;
  1786. }
  1787. }
  1788. ++args;
  1789. }
  1790. if (!GetExpressionEx(args, &Address, &args))
  1791. {
  1792. Address = (ULONG64)-1;
  1793. }
  1794. if (!GetExpressionEx(args, &Flags, &args))
  1795. {
  1796. Flags = 6;
  1797. }
  1798. if (Address == (ULONG64)-1) {
  1799. GetCurrentThreadAddr( dwProcessor, &Address );
  1800. }
  1801. UserProbeAddress = GetNtDebuggerDataPtrValue(MmUserProbeAddress);
  1802. Thread = Address;
  1803. if (DumpByCid)
  1804. {
  1805. ThreadFind.Cid = (ULONG) Address;
  1806. dprintf("Looking for thread Cid = %p ...\n", ThreadFind.Cid);
  1807. Thread = FindThread(&ThreadFind);
  1808. }
  1809. if (GetFieldValue(Thread, "nt!_ETHREAD", "Tcb.Header.Type", Tcb_Header_Type)) {
  1810. dprintf("%08lp: Unable to get thread contents\n", Thread );
  1811. goto threadExit;
  1812. }
  1813. if (Tcb_Header_Type != ThreadObject &&
  1814. Address > UserProbeAddress) {
  1815. ULONG64 stackThread;
  1816. //
  1817. // What was passed in was not a thread. Maybe it was a kernel stack
  1818. // pointer. Search the thread stack ranges to find out.
  1819. //
  1820. dprintf("%p is not a thread object, interpreting as stack value...\n",Address);
  1821. ThreadFind.StackPointer = Address;
  1822. ThreadFind.Cid = 0;
  1823. stackThread = FindThread( &ThreadFind );
  1824. if (stackThread != 0) {
  1825. Thread = stackThread;
  1826. }
  1827. }
  1828. DumpThread (dwProcessor,"", Thread, Flags);
  1829. EXPRLastDump = Thread;
  1830. ThreadLastDump = Thread;
  1831. threadExit:
  1832. EXIT_API();
  1833. return S_OK;
  1834. }
  1835. DECLARE_API( processfields )
  1836. /*++
  1837. Routine Description:
  1838. Displays the field offsets for EPROCESS type.
  1839. Arguments:
  1840. None.
  1841. Return Value:
  1842. None.
  1843. --*/
  1844. {
  1845. dprintf(" EPROCESS structure offsets: (use 'dt nt!_EPROCESS')\n\n");
  1846. return S_OK;
  1847. }
  1848. DECLARE_API( threadfields )
  1849. /*++
  1850. Routine Description:
  1851. Displays the field offsets for ETHREAD type.
  1852. Arguments:
  1853. None.
  1854. Return Value:
  1855. None.
  1856. --*/
  1857. {
  1858. dprintf(" ETHREAD structure offsets: (use 'dt ETHREAD')\n\n");
  1859. return S_OK;
  1860. }
  1861. //+---------------------------------------------------------------------------
  1862. //
  1863. // Function: GetHandleTableAddress
  1864. //
  1865. // Synopsis: Return the address of the handle table given a thread handle
  1866. //
  1867. // Arguments: [Processor] -- processor number
  1868. // [hCurrentThread] -- thread handle
  1869. //
  1870. // Returns: address of handle table or null
  1871. //
  1872. // History: 9-23-1998 benl Created
  1873. //
  1874. // Notes:
  1875. //
  1876. //----------------------------------------------------------------------------
  1877. ULONG64 GetHandleTableAddress(
  1878. USHORT Processor,
  1879. HANDLE hCurrentThread
  1880. )
  1881. {
  1882. ULONG64 pThread;
  1883. ULONG64 pProcess = 0, pObjTable;
  1884. GetCurrentThreadAddr( Processor, &pThread );
  1885. if (pThread) {
  1886. GetCurrentProcessAddr( Processor, pThread, &pProcess );
  1887. }
  1888. if (pProcess) {
  1889. if (GetFieldValue(pProcess, "nt!_EPROCESS", "ObjectTable", pObjTable) ) {
  1890. dprintf("%08p: Unable to read _EPROCESS\n", pProcess );
  1891. return 0;
  1892. }
  1893. return pObjTable;
  1894. } else
  1895. {
  1896. return 0;
  1897. }
  1898. } // GetHandleTableAddress
  1899. #if 0
  1900. BOOLEAN
  1901. FetchProcessStructureVariables(
  1902. VOID
  1903. )
  1904. {
  1905. ULONG Result;
  1906. ULONG64 t;
  1907. static BOOLEAN HavePspVariables = FALSE;
  1908. if (HavePspVariables) {
  1909. return TRUE;
  1910. }
  1911. t=GetNtDebuggerData( PspCidTable );
  1912. PspCidTable = (PHANDLE_TABLE) t;
  1913. if ( !PspCidTable ||
  1914. !ReadMemory((DWORD)PspCidTable,
  1915. &PspCidTable,
  1916. sizeof(PspCidTable),
  1917. &Result) ) {
  1918. dprintf("%08lx: Unable to get value of PspCidTable\n",PspCidTable);
  1919. return FALSE;
  1920. }
  1921. HavePspVariables = TRUE;
  1922. return TRUE;
  1923. }
  1924. PVOID
  1925. LookupUniqueId(
  1926. HANDLE UniqueId
  1927. )
  1928. {
  1929. return NULL;
  1930. }
  1931. #endif
  1932. int
  1933. __cdecl
  1934. CmpFunc(
  1935. const void *pszElem1,
  1936. const void *pszElem2
  1937. )
  1938. {
  1939. PPROCESS_COMMIT_USAGE p1, p2;
  1940. p1 = (PPROCESS_COMMIT_USAGE)pszElem1;
  1941. p2 = (PPROCESS_COMMIT_USAGE)pszElem2;
  1942. if (p2->CommitCharge == p1->CommitCharge) {
  1943. ((char*)p2->ClientId - (char*)p1->ClientId);
  1944. }
  1945. return (ULONG) (p2->CommitCharge - p1->CommitCharge);
  1946. }
  1947. PPROCESS_COMMIT_USAGE
  1948. GetProcessCommit (
  1949. PULONG64 TotalCommitCharge,
  1950. PULONG NumberOfProcesses
  1951. )
  1952. {
  1953. PPROCESS_COMMIT_USAGE p, oldp;
  1954. ULONG n;
  1955. ULONG64 Next;
  1956. ULONG64 ProcessHead;
  1957. ULONG64 Process;
  1958. ULONG64 Total;
  1959. ULONG Result;
  1960. ULONG ActiveProcessLinksOffset;
  1961. *TotalCommitCharge = 0;
  1962. *NumberOfProcesses = 0;
  1963. // Get the offset of ActiveProcessLinks in _EPROCESS
  1964. if (GetFieldOffset("nt!_EPROCESS", "ActiveProcessLinks", &ActiveProcessLinksOffset)) {
  1965. return NULL;
  1966. }
  1967. Total = 0;
  1968. n = 0;
  1969. p = (PPROCESS_COMMIT_USAGE) HeapAlloc( GetProcessHeap(), 0, 1 );
  1970. if (p == NULL) {
  1971. dprintf("Unable to allocate memory\n");
  1972. return NULL;
  1973. }
  1974. ProcessHead = GetNtDebuggerData( PsActiveProcessHead );
  1975. if (!ProcessHead) {
  1976. dprintf("Unable to get value of PsActiveProcessHead\n");
  1977. HeapFree(GetProcessHeap(), 0, p);
  1978. return NULL;
  1979. }
  1980. if (GetFieldValue( ProcessHead, "nt!_LIST_ENTRY", "Flink", Next ) ||
  1981. !Next)
  1982. {
  1983. dprintf("Unable to read/NULL value _LIST_ENTRY @ %p\n", ProcessHead);
  1984. HeapFree(GetProcessHeap(), 0, p);
  1985. return NULL;
  1986. }
  1987. while(Next != ProcessHead) {
  1988. ULONG64 CommitCharge=0, NumberOfPrivatePages=0, NumberOfLockedPages=0;
  1989. Process = Next - ActiveProcessLinksOffset;
  1990. if (GetFieldValue( Process, "nt!_EPROCESS", "CommitCharge", CommitCharge )) {
  1991. dprintf("Unable to read _EPROCESS at %p\n",Process);
  1992. HeapFree(GetProcessHeap(), 0, p);
  1993. return NULL;
  1994. }
  1995. Total += CommitCharge;
  1996. n += 1;
  1997. oldp = p;
  1998. p = (PPROCESS_COMMIT_USAGE) HeapReAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY, oldp, n * sizeof( *p ) );
  1999. if (p == NULL) {
  2000. HeapFree(GetProcessHeap(), 0, oldp);
  2001. dprintf("Unable to allocate memory\n");
  2002. return NULL;
  2003. }
  2004. p[n-1].ProcessAddress = Process;
  2005. GetFieldValue( Process, "nt!_EPROCESS", "ImageFileName",
  2006. p[ n-1 ].ImageFileName );
  2007. GetFieldValue( Process, "nt!_EPROCESS", "NumberOfPrivatePages",
  2008. p[ n-1 ].NumberOfPrivatePages );
  2009. GetFieldValue( Process, "nt!_EPROCESS", "NumberOfLockedPages",
  2010. p[ n-1 ].NumberOfLockedPages );
  2011. GetFieldValue( Process, "nt!_EPROCESS", "UniqueProcessId",
  2012. p[ n-1 ].ClientId );
  2013. p[ n-1 ].CommitCharge = CommitCharge;
  2014. GetFieldValue(Process, "nt!_EPROCESS", "ActiveProcessLinks.Flink", Next);
  2015. if (CheckControlC()) {
  2016. HeapFree(GetProcessHeap(), 0, p);
  2017. return NULL;
  2018. }
  2019. }
  2020. qsort( p, n, sizeof( *p ), CmpFunc );
  2021. *TotalCommitCharge = Total;
  2022. *NumberOfProcesses = n;
  2023. return p;
  2024. }
  2025. BOOL
  2026. DumpJob(
  2027. ULONG64 RealJobBase,
  2028. ULONG Flags
  2029. )
  2030. {
  2031. ULONG64 ProcessListHead_Flink=0, TotalPageFaultCount=0, TotalProcesses=0, ActiveProcesses=0,
  2032. TotalTerminatedProcesses=0, LimitFlags=0, MinimumWorkingSetSize=0,
  2033. MaximumWorkingSetSize=0, ActiveProcessLimit=0, PriorityClass=0,
  2034. UIRestrictionsClass=0, SecurityLimitFlags=0, Token=0, Filter=0;
  2035. ULONG64 Filter_SidCount=0, Filter_Sids=0, Filter_SidsLength=0, Filter_GroupCount=0,
  2036. Filter_Groups=0, Filter_GroupsLength=0, Filter_PrivilegeCount=0, Filter_Privileges=0,
  2037. Filter_PrivilegesLength=0;
  2038. ULONG ProcessListHeadOffset;
  2039. GetFieldValue(RealJobBase, "nt!_EJOB", "ActiveProcesses", ActiveProcesses);
  2040. GetFieldValue(RealJobBase, "nt!_EJOB", "ActiveProcessLimit", ActiveProcessLimit);
  2041. GetFieldValue(RealJobBase, "nt!_EJOB", "Filter", Filter);
  2042. GetFieldValue(RealJobBase, "nt!_EJOB", "LimitFlags", LimitFlags);
  2043. GetFieldValue(RealJobBase, "nt!_EJOB", "MinimumWorkingSetSize", MinimumWorkingSetSize);
  2044. GetFieldValue(RealJobBase, "nt!_EJOB", "MaximumWorkingSetSize", MaximumWorkingSetSize);
  2045. GetFieldValue(RealJobBase, "nt!_EJOB", "PriorityClass", PriorityClass);
  2046. GetFieldValue(RealJobBase, "nt!_EJOB", "ProcessListHead.Flink", ProcessListHead_Flink);
  2047. GetFieldValue(RealJobBase, "nt!_EJOB", "SecurityLimitFlags", SecurityLimitFlags);
  2048. GetFieldValue(RealJobBase, "nt!_EJOB", "Token", Token);
  2049. GetFieldValue(RealJobBase, "nt!_EJOB", "TotalPageFaultCount", TotalPageFaultCount);
  2050. GetFieldValue(RealJobBase, "nt!_EJOB", "TotalProcesses", TotalProcesses);
  2051. GetFieldValue(RealJobBase, "nt!_EJOB", "TotalTerminatedProcesses", TotalTerminatedProcesses);
  2052. GetFieldValue(RealJobBase, "nt!_EJOB", "UIRestrictionsClass", UIRestrictionsClass);
  2053. if (GetFieldOffset("_EJOB", "ProcessListHead", &ProcessListHeadOffset)) {
  2054. dprintf("Can't read job at %p\n", RealJobBase);
  2055. }
  2056. if ( Flags & 1 )
  2057. {
  2058. dprintf("Job at %p\n", RealJobBase );
  2059. dprintf(" TotalPageFaultCount %x\n", TotalPageFaultCount );
  2060. dprintf(" TotalProcesses %x\n", TotalProcesses );
  2061. dprintf(" ActiveProcesses %x\n", ActiveProcesses );
  2062. dprintf(" TotalTerminatedProcesses %x\n", TotalTerminatedProcesses );
  2063. dprintf(" LimitFlags %x\n", LimitFlags );
  2064. dprintf(" MinimumWorkingSetSize %I64x\n", MinimumWorkingSetSize );
  2065. dprintf(" MaximumWorkingSetSize %I64x\n", MaximumWorkingSetSize );
  2066. dprintf(" ActiveProcessLimit %x\n", ActiveProcessLimit );
  2067. dprintf(" PriorityClass %x\n", PriorityClass );
  2068. dprintf(" UIRestrictionsClass %x\n", UIRestrictionsClass );
  2069. dprintf(" SecurityLimitFlags %x\n", SecurityLimitFlags );
  2070. dprintf(" Token %p\n", Token );
  2071. if ( Filter )
  2072. {
  2073. GetFieldValue(Filter, "nt!_PS_JOB_TOKEN_FILTER", "CapturedSidCount", Filter_SidCount );
  2074. GetFieldValue(Filter, "nt!_PS_JOB_TOKEN_FILTER", "CapturedSids", Filter_Sids );
  2075. GetFieldValue(Filter, "nt!_PS_JOB_TOKEN_FILTER", "CapturedSidsLength", Filter_SidsLength);
  2076. GetFieldValue(Filter, "nt!_PS_JOB_TOKEN_FILTER", "CapturedGroupCount", Filter_GroupCount);
  2077. GetFieldValue(Filter, "nt!_PS_JOB_TOKEN_FILTER", "CapturedGroups", Filter_Groups);
  2078. GetFieldValue(Filter, "nt!_PS_JOB_TOKEN_FILTER", "CapturedGroupsLength", Filter_GroupsLength);
  2079. GetFieldValue(Filter, "nt!_PS_JOB_TOKEN_FILTER", "CapturedPrivilegeCount", Filter_PrivilegeCount);
  2080. GetFieldValue(Filter, "nt!_PS_JOB_TOKEN_FILTER", "CapturedPrivileges", Filter_Privileges);
  2081. GetFieldValue(Filter, "nt!_PS_JOB_TOKEN_FILTER", "CapturedPrivilegesLength",Filter_PrivilegesLength);
  2082. dprintf(" Filter\n");
  2083. dprintf(" CapturedSidCount %I64x\n", Filter_SidCount );
  2084. dprintf(" CapturedSids %p\n", Filter_Sids );
  2085. dprintf(" CapturedSidsLength %I64x\n", Filter_SidsLength );
  2086. dprintf(" CapturedGroupCount %I64x\n", Filter_GroupCount );
  2087. dprintf(" CapturedGroups %p\n", Filter_Groups );
  2088. dprintf(" CapturedGroupsLength %I64x\n", Filter_GroupsLength );
  2089. dprintf(" CapturedPrivCount %I64x\n", Filter_PrivilegeCount );
  2090. dprintf(" CapturedPrivs %p\n", Filter_Privileges );
  2091. dprintf(" CapturedPrivLength %I64x\n", Filter_PrivilegesLength );
  2092. }
  2093. }
  2094. if ( Flags & 2 )
  2095. {
  2096. //
  2097. // Walk the process list for all the processes in the job
  2098. //
  2099. ULONG64 Scan, End;
  2100. ULONG offset ;
  2101. ULONG64 ProcessBase, NextPrc=0 ;
  2102. dprintf(" Processes assigned to this job:\n" );
  2103. Scan = ProcessListHead_Flink ;
  2104. End = ProcessListHeadOffset + RealJobBase;
  2105. if (!GetFieldOffset("nt!_EPROCESS", "JobLinks", &offset)) {
  2106. while ( Scan != End )
  2107. {
  2108. ProcessBase = Scan - offset;
  2109. DumpProcess( " ", ProcessBase, 0, NULL);
  2110. if (!GetFieldValue(ProcessBase, "nt!_EPROCESS", "JobLinks.Flink", NextPrc)) {
  2111. Scan = NextPrc;
  2112. } else {
  2113. Scan = End;
  2114. }
  2115. }
  2116. }
  2117. }
  2118. return TRUE ;
  2119. }
  2120. DECLARE_API( job )
  2121. /*++
  2122. Routine Description:
  2123. Dumps the specified thread.
  2124. Arguments:
  2125. None.
  2126. Return Value:
  2127. None.
  2128. --*/
  2129. {
  2130. ULONG64 Address, JobAddress=0;
  2131. ULONG Flags;
  2132. ULONG dwProcessor;
  2133. HANDLE hCurrentThread;
  2134. INIT_API();
  2135. if (!GetCurrentProcessor(Client, &dwProcessor, &hCurrentThread)) {
  2136. dwProcessor = 0;
  2137. hCurrentThread = 0;
  2138. }
  2139. Address = 0;
  2140. Flags = 1;
  2141. if (GetExpressionEx(args,&Address,&args)) {
  2142. Flags = (ULONG) GetExpression(args);
  2143. if (!Flags) {
  2144. Flags = 1;
  2145. }
  2146. }
  2147. if (Address == 0) {
  2148. GetCurrentProcessAddr( dwProcessor, 0, &Address );
  2149. if (Address == 0) {
  2150. dprintf("Unable to get current process pointer.\n");
  2151. goto jobExit;
  2152. }
  2153. if (GetFieldValue(Address, "nt!_EPROCESS", "Job", JobAddress)) {
  2154. dprintf("%08p: Unable to get process contents\n", Address );
  2155. goto jobExit;
  2156. }
  2157. Address = JobAddress;
  2158. if ( Address == 0 )
  2159. {
  2160. dprintf("Process not part of a job.\n" );
  2161. goto jobExit;
  2162. }
  2163. }
  2164. DumpJob( Address, Flags );
  2165. jobExit:
  2166. EXIT_API();
  2167. return S_OK;
  2168. }
  2169. DECLARE_API( running )
  2170. /*++
  2171. Routine Description:
  2172. This routine dumps lists the running threads in the system.
  2173. Arguments:
  2174. -i include idle processors
  2175. -t print stack trace for each processor
  2176. Return Value:
  2177. None.
  2178. --*/
  2179. {
  2180. #define LOCK_ENTRIES 16
  2181. ULONG64 Address;
  2182. ULONG64 ActiveProcessors = 0;
  2183. ULONG64 IdleProcessors = 0;
  2184. ULONG i;
  2185. ULONG64 j;
  2186. ULONG l;
  2187. ULONG n;
  2188. ULONG64 Prcb;
  2189. ULONG64 CurrentThread;
  2190. ULONG64 NextThread;
  2191. ULONG64 KiProcessorBlock;
  2192. ULONG SizeofPointer;
  2193. ULONG SizeofLockEntry;
  2194. ULONG LockQueueOffset;
  2195. UCHAR LockState[LOCK_ENTRIES+1];
  2196. ULONG64 Lock;
  2197. BOOLEAN DoIdle = FALSE;
  2198. BOOLEAN DoTrace = FALSE;
  2199. char * PointerPadd = "";
  2200. UCHAR c;
  2201. BOOLEAN ParseError = FALSE;
  2202. BOOLEAN DashSeen = FALSE;
  2203. CHAR TraceCommand[5];
  2204. INIT_API();
  2205. //
  2206. // Parse arguments.
  2207. //
  2208. // Allow -t and/or -i, allow to be run together, "-" is not required.
  2209. //
  2210. while (((c = *args++) != '\0') && (ParseError == FALSE)) {
  2211. switch (c) {
  2212. case '-':
  2213. if (DashSeen) {
  2214. ParseError = TRUE;
  2215. break;
  2216. }
  2217. DashSeen = TRUE;
  2218. break;
  2219. case 't':
  2220. case 'T':
  2221. if (DoTrace) {
  2222. ParseError = TRUE;
  2223. break;
  2224. }
  2225. DoTrace = TRUE;
  2226. break;
  2227. case 'i':
  2228. case 'I':
  2229. if (DoIdle) {
  2230. ParseError = TRUE;
  2231. break;
  2232. }
  2233. DoIdle = TRUE;
  2234. break;
  2235. case ' ':
  2236. case '\t':
  2237. DashSeen = FALSE;
  2238. break;
  2239. default:
  2240. ParseError = TRUE;
  2241. break;
  2242. }
  2243. }
  2244. if (ParseError) {
  2245. dprintf("usage: !running [-t] [-i]\n");
  2246. goto runningExit;
  2247. }
  2248. //
  2249. // Get KeActiveProcessors and KiIdleSummary.
  2250. //
  2251. Address = GetExpression("nt!KeActiveProcessors");
  2252. if (!Address) {
  2253. dprintf("Could not get processor configuration, exiting.\n");
  2254. goto runningExit;
  2255. }
  2256. if (!ReadPointer(Address, &ActiveProcessors) || (ActiveProcessors == 0)) {
  2257. dprintf("Unable to get active processor set. Cannot continue.\n");
  2258. goto runningExit;
  2259. }
  2260. Address = GetExpression("nt!KiIdleSummary");
  2261. if ((Address == 0) ||
  2262. (!ReadPointer(Address, &IdleProcessors))) {
  2263. dprintf("Could not get idle processor set, exiting.\n");
  2264. goto runningExit;
  2265. }
  2266. dprintf("\n");
  2267. dprintf("System Processors %I64x (affinity mask)\n", ActiveProcessors);
  2268. dprintf(" Idle Processors %I64x\n", IdleProcessors);
  2269. if (ActiveProcessors == IdleProcessors) {
  2270. dprintf("All processors idle.\n");
  2271. if (!DoIdle) {
  2272. goto runningExit;
  2273. }
  2274. }
  2275. //
  2276. // Get the address of KiProcessorBlock which is an array of pointers
  2277. // to the PRCB for each processor.
  2278. //
  2279. KiProcessorBlock = GetExpression("nt!KiProcessorBlock");
  2280. if (KiProcessorBlock == 0) {
  2281. dprintf("Could not get address of KiProcessorBlock, exiting.\n");
  2282. goto runningExit;
  2283. }
  2284. //
  2285. // Is the target 64 bits or 32?
  2286. //
  2287. SizeofPointer = DBG_PTR_SIZE;
  2288. if ((SizeofPointer != 8) && (SizeofPointer != 4)) {
  2289. dprintf("Could not determine size of pointer on target system.\n");
  2290. goto runningExit;
  2291. }
  2292. //
  2293. // Get the size of a Prcb->LockQueue entry, and the offset to the
  2294. // LockQueue in the PRCB.
  2295. //
  2296. SizeofLockEntry = GetTypeSize("nt!KSPIN_LOCK_QUEUE");
  2297. if (!SizeofLockEntry) {
  2298. dprintf("Could not determine size of KSPIN_LOCK_QUEUE on target.\n");
  2299. goto runningExit;
  2300. }
  2301. GetFieldOffset("nt!_KPRCB", "LockQueue", &LockQueueOffset);
  2302. if (!LockQueueOffset) {
  2303. dprintf("Couldn't determine offset of LockQueue field in KPRCB.\n");
  2304. goto runningExit;
  2305. }
  2306. //
  2307. // Print header. If 64 bit target, add 8 blanks spacing.
  2308. //
  2309. if (SizeofPointer == 8) {
  2310. PointerPadd = " ";
  2311. }
  2312. dprintf("\n Prcb %s", PointerPadd);
  2313. dprintf(" Current %s", PointerPadd);
  2314. dprintf(" Next %s", PointerPadd);
  2315. dprintf("\n");
  2316. //
  2317. // Put terminating NULL in lock state string.
  2318. //
  2319. LockState[LOCK_ENTRIES] = '\0';
  2320. //
  2321. // For each processor in the system.
  2322. //
  2323. for (i = 0, j = 1; ActiveProcessors; i++, j <<= 1UI64) {
  2324. //
  2325. // Does this processor exist?
  2326. //
  2327. if ((ActiveProcessors & j) != 0) {
  2328. //
  2329. // Remove it from the list of processors to be examined.
  2330. //
  2331. ActiveProcessors ^= j;
  2332. //
  2333. // If not listing idle processors, skip this guy if it's idle.
  2334. //
  2335. if ((DoIdle == FALSE) &&
  2336. (IdleProcessors & j)) {
  2337. continue;
  2338. }
  2339. //
  2340. // Get the PRCB for this processor, then get the CurrentThread
  2341. // and NextThread fields.
  2342. //
  2343. if ((!ReadPointer(KiProcessorBlock + (i * SizeofPointer), &Prcb)) ||
  2344. (Prcb == 0)) {
  2345. dprintf("Couldn't get PRCB for processor %d.\n", i);
  2346. goto runningExit;
  2347. }
  2348. GetFieldValue(Prcb, "nt!_KPRCB", "CurrentThread", CurrentThread);
  2349. GetFieldValue(Prcb, "nt!_KPRCB", "NextThread", NextThread);
  2350. //
  2351. // For each queued spinlock in the PRCB, summarize state.
  2352. //
  2353. Address = Prcb + LockQueueOffset;
  2354. for (l = 0; l < LOCK_ENTRIES; l++) {
  2355. GetFieldValue(Address + (l * SizeofLockEntry),
  2356. "nt!KSPIN_LOCK_QUEUE",
  2357. "Lock",
  2358. Lock);
  2359. n = (ULONG)(Lock & 0x3);
  2360. switch (n) {
  2361. case 0: LockState[l] = '.'; break;
  2362. case 1: LockState[l] = 'W'; break;
  2363. case 2: LockState[l] = 'O'; break;
  2364. default: LockState[l] = '?'; break;
  2365. }
  2366. }
  2367. if (SizeofPointer == 4) {
  2368. //
  2369. // Trim sign extended addresses.
  2370. //
  2371. Prcb &= 0xffffffff;
  2372. CurrentThread &= 0xffffffff;
  2373. NextThread &= 0xffffffff;
  2374. }
  2375. dprintf("%3d %I64x %I64x ",
  2376. i,
  2377. Prcb,
  2378. CurrentThread);
  2379. if (NextThread) {
  2380. dprintf("%I64x ", NextThread);
  2381. } else {
  2382. dprintf(" %s", PointerPadd);
  2383. }
  2384. dprintf("%s", LockState);
  2385. dprintf("\n");
  2386. if (DoTrace) {
  2387. dprintf("\n");
  2388. sprintf(TraceCommand, "%dk", i);
  2389. ExecuteCommand(Client, TraceCommand);
  2390. dprintf("\n");
  2391. }
  2392. }
  2393. }
  2394. if (!DoTrace) {
  2395. dprintf("\n");
  2396. }
  2397. runningExit:
  2398. EXIT_API();
  2399. return S_OK;
  2400. }
  2401. ULONG64 ZombieCount;
  2402. ULONG64 ZombiePool;
  2403. ULONG64 ZombieCommit;
  2404. ULONG64 ZombieResidentAvailable;
  2405. #define BLOB_LONGS 32
  2406. BOOLEAN WINAPI
  2407. CheckForZombieProcess(
  2408. IN PCHAR Tag,
  2409. IN PCHAR Filter,
  2410. IN ULONG Flags,
  2411. IN ULONG64 PoolHeader,
  2412. IN ULONG64 BlockSize,
  2413. IN ULONG64 Data,
  2414. IN PVOID Context
  2415. )
  2416. {
  2417. ULONG result;
  2418. // EPROCESS ProcessContents;
  2419. ULONG64 Process;
  2420. ULONG64 KProcess;
  2421. //OBJECT_HEADER ObjectHeaderContents;
  2422. ULONG64 ObjectHeader;
  2423. ULONG64 Blob[BLOB_LONGS];
  2424. ULONG i;
  2425. ULONG PoolIndex, PoolBlockSize, SizeOfKprocess;
  2426. ULONG HandleCount, PointerCount;
  2427. ULONG64 UniqueProcessId;
  2428. UNREFERENCED_PARAMETER (Flags);
  2429. UNREFERENCED_PARAMETER (BlockSize);
  2430. UNREFERENCED_PARAMETER (Context);
  2431. if (PoolHeader == 0) {
  2432. return FALSE;
  2433. }
  2434. if (GetFieldValue(PoolHeader, "nt!_POOL_HEADER", "PoolIndex", PoolIndex) ||
  2435. GetFieldValue(PoolHeader, "nt!_POOL_HEADER", "BlockSize", PoolBlockSize)) {
  2436. dprintf("Cannot read nt!_POOL_HEADER at %p.\n", PoolHeader);
  2437. return FALSE;
  2438. }
  2439. if ((PoolIndex & 0x80) == 0) {
  2440. return FALSE;
  2441. }
  2442. if (!CheckSingleFilter (Tag, Filter)) {
  2443. return FALSE;
  2444. }
  2445. if ((PoolBlockSize << POOL_BLOCK_SHIFT) < sizeof(Blob)) {
  2446. return FALSE;
  2447. }
  2448. //
  2449. // There must be a better way to find the object header given the start
  2450. // of a pool block ?
  2451. //
  2452. if (!ReadMemory (Data,
  2453. &Blob[0],
  2454. sizeof(Blob),
  2455. &result)) {
  2456. dprintf ("Could not read process blob at %p\n", Data);
  2457. return FALSE;
  2458. }
  2459. SizeOfKprocess = GetTypeSize("nt!_KPROCESS");
  2460. for (i = 0; i < BLOB_LONGS; i += 1) {
  2461. ULONG Type, Size;
  2462. GetFieldValue(Data + i*sizeof(ULONG), "nt!_KPROCESS", "Header.Type", Type);
  2463. GetFieldValue(Data + i*sizeof(ULONG), "nt!_KPROCESS", "Header.Size", Size);
  2464. if ((Type == ProcessObject) &&
  2465. (Size == SizeOfKprocess / sizeof(LONG))) {
  2466. break;
  2467. }
  2468. }
  2469. if (i == BLOB_LONGS) {
  2470. return FALSE;
  2471. }
  2472. ObjectHeader = KD_OBJECT_TO_OBJECT_HEADER (Data + i*sizeof(LONG));
  2473. Process = Data + i*sizeof(LONG);
  2474. if (GetFieldValue(ObjectHeader, "nt!_OBJECT_HEADER", "HandleCount",HandleCount) ||
  2475. GetFieldValue(ObjectHeader, "nt!_OBJECT_HEADER", "PointerCount",PointerCount) ) {
  2476. dprintf ("Could not read process object header at %p\n", ObjectHeader);
  2477. return FALSE;
  2478. }
  2479. if (GetFieldValue( Process,
  2480. "nt!_EPROCESS",
  2481. "UniqueProcessId",
  2482. UniqueProcessId)) {
  2483. dprintf ("Could not read process data at %p\n", Process);
  2484. return FALSE;
  2485. }
  2486. //
  2487. // Skip the system process and the idle process.
  2488. //
  2489. if ((UniqueProcessId == 0) ||
  2490. (UniqueProcessId == 8)) {
  2491. return FALSE;
  2492. }
  2493. //
  2494. // Display any terminated process regardless of object pointer/handle
  2495. // counts. This is so leaked process handles don't result in processes
  2496. // not getting displayed when they should.
  2497. //
  2498. // A nulled object table with a non-zero create time indicates a process
  2499. // that has finished creation.
  2500. //
  2501. InitTypeRead(Process, nt!_EPROCESS);
  2502. if ((ReadField(ObjectTable) == 0) &&
  2503. (ReadField(CreateTime.QuadPart) != 0)) {
  2504. dprintf ("HandleCount: %u PointerCount: %u\n",
  2505. HandleCount, PointerCount);
  2506. DumpProcess ("", Process, 0, NULL);
  2507. ZombieCount += 1;
  2508. ZombiePool += ((ULONG64) PoolBlockSize << POOL_BLOCK_SHIFT);
  2509. ZombieCommit += (7 * PageSize); // MM_PROCESS_COMMIT_CHARGE
  2510. ZombieResidentAvailable += (9 * PageSize); // MM_PROCESS_CREATE_CHARGE
  2511. }
  2512. return TRUE;
  2513. }
  2514. BOOLEAN WINAPI
  2515. CheckForZombieThread(
  2516. IN PCHAR Tag,
  2517. IN PCHAR Filter,
  2518. IN ULONG Flags,
  2519. IN ULONG64 PoolHeader,
  2520. IN ULONG64 BlockSize,
  2521. IN ULONG64 Data,
  2522. IN PVOID Context
  2523. )
  2524. {
  2525. ULONG result;
  2526. ULONG64 Thread;
  2527. ULONG64 KThread;
  2528. ULONG64 ObjectHeader;
  2529. ULONG Blob[BLOB_LONGS];
  2530. ULONG i;
  2531. ULONG64 StackBase;
  2532. ULONG64 StackLimit;
  2533. ULONG PoolIndex, PoolBlockSize, SizeOfKthread;
  2534. ULONG HandleCount, PointerCount;
  2535. UNREFERENCED_PARAMETER (Flags);
  2536. UNREFERENCED_PARAMETER (BlockSize);
  2537. UNREFERENCED_PARAMETER (Context);
  2538. if (PoolHeader == 0) {
  2539. return FALSE;
  2540. }
  2541. if (GetFieldValue(PoolHeader, "nt!_POOL_HEADER", "PoolIndex", PoolIndex) ||
  2542. GetFieldValue(PoolHeader, "nt!_POOL_HEADER", "BlockSize", PoolBlockSize)) {
  2543. dprintf("Cannot read POOL_HEADER at %p.\n", PoolHeader);
  2544. return FALSE;
  2545. }
  2546. if ((PoolIndex & 0x80) == 0) {
  2547. return FALSE;
  2548. }
  2549. if (!CheckSingleFilter (Tag, Filter)) {
  2550. return FALSE;
  2551. }
  2552. if ((PoolBlockSize << POOL_BLOCK_SHIFT) < sizeof(Blob)) {
  2553. return FALSE;
  2554. }
  2555. //
  2556. // There must be a better way to find the object header given the start
  2557. // of a pool block ?
  2558. //
  2559. if (!ReadMemory ((ULONG) Data,
  2560. &Blob[0],
  2561. sizeof(Blob),
  2562. &result)) {
  2563. dprintf ("Could not read process blob at %p\n", Data);
  2564. return FALSE;
  2565. }
  2566. SizeOfKthread = GetTypeSize("nt!_KTHREAD");
  2567. for (i = 0; i < BLOB_LONGS; i += 1) {
  2568. ULONG Type, Size;
  2569. GetFieldValue(Data + i*sizeof(ULONG), "nt!_KTHREAD", "Header.Type", Type);
  2570. GetFieldValue(Data + i*sizeof(ULONG), "nt!_KTHREAD", "Header.Size", Size);
  2571. if ((Type == ThreadObject) &&
  2572. (Size == SizeOfKthread / sizeof(LONG))) {
  2573. break;
  2574. }
  2575. }
  2576. if (i == BLOB_LONGS) {
  2577. return FALSE;
  2578. }
  2579. ObjectHeader = KD_OBJECT_TO_OBJECT_HEADER (Data + i*sizeof(LONG));
  2580. Thread = Data + i*sizeof(LONG);
  2581. if (GetFieldValue(ObjectHeader, "nt!_OBJECT_HEADER", "HandleCount",HandleCount) ||
  2582. GetFieldValue(ObjectHeader, "nt!_OBJECT_HEADER", "PointerCount",PointerCount) ) {
  2583. dprintf ("Could not read process object header at %p\n", ObjectHeader);
  2584. return FALSE;
  2585. }
  2586. if (GetFieldValue( Thread,
  2587. "nt!_ETHREAD",
  2588. "Tcb.StackLimit",
  2589. StackLimit)) {
  2590. dprintf ("Could not read thread data at %p\n", Thread);
  2591. return FALSE;
  2592. }
  2593. InitTypeRead(Thread, KTHREAD);
  2594. if ((ULONG) ReadField(State) != Terminated) {
  2595. return FALSE;
  2596. }
  2597. ZombieCount += 1;
  2598. ZombiePool += ((ULONG64) PoolBlockSize << POOL_BLOCK_SHIFT);
  2599. ZombieCommit += (ReadField(StackBase) - StackLimit);
  2600. StackBase = (ReadField(StackBase) - 1);
  2601. dprintf ("HandleCount: %u PointerCount: %u\n",
  2602. HandleCount, PointerCount);
  2603. DumpThread (0, "", Thread, 7);
  2604. while (StackBase >= StackLimit) {
  2605. if (GetAddressState(StackBase) == ADDRESS_VALID) {
  2606. ZombieResidentAvailable += PageSize;
  2607. }
  2608. StackBase = (StackBase - PageSize);
  2609. }
  2610. return TRUE;
  2611. }
  2612. DECLARE_API( zombies )
  2613. /*++
  2614. Routine Description:
  2615. Finds zombie processes and threads in non-paged pool.
  2616. Arguments:
  2617. None.
  2618. Return Value:
  2619. None.
  2620. --*/
  2621. {
  2622. ULONG Flags;
  2623. ULONG64 RestartAddress;
  2624. ULONG TagName;
  2625. ULONG64 ZombieProcessCount;
  2626. ULONG64 ZombieProcessPool;
  2627. ULONG64 ZombieProcessCommit;
  2628. ULONG64 ZombieProcessResidentAvailable;
  2629. ULONG64 tmp;
  2630. INIT_API();
  2631. Flags = 1;
  2632. RestartAddress = 0;
  2633. if (GetExpressionEx(args,&tmp, &args)) {
  2634. RestartAddress = GetExpression(args);
  2635. Flags = (ULONG) tmp;
  2636. }
  2637. if ((Flags & 0x3) == 0) {
  2638. dprintf("Invalid parameter for !zombies\n");
  2639. EXIT_API();
  2640. return E_INVALIDARG;
  2641. }
  2642. if (Flags & 0x1) {
  2643. dprintf("Looking for zombie processes...");
  2644. TagName = '?orP';
  2645. ZombieCount = 0;
  2646. ZombiePool = 0;
  2647. ZombieCommit = 0;
  2648. ZombieResidentAvailable = 0;
  2649. SearchPool (TagName, 0, RestartAddress, &CheckForZombieProcess, NULL);
  2650. SearchPool (TagName, 2, RestartAddress, &CheckForZombieProcess, NULL);
  2651. ZombieProcessCount = ZombieCount;
  2652. ZombieProcessPool = ZombiePool;
  2653. ZombieProcessCommit = ZombieCommit;
  2654. ZombieProcessResidentAvailable = ZombieResidentAvailable;
  2655. }
  2656. if (Flags & 0x2) {
  2657. dprintf("Looking for zombie threads...");
  2658. TagName = '?rhT';
  2659. ZombieCount = 0;
  2660. ZombiePool = 0;
  2661. ZombieCommit = 0;
  2662. ZombieResidentAvailable = 0;
  2663. SearchPool (TagName, 0, RestartAddress, &CheckForZombieThread, NULL);
  2664. SearchPool (TagName, 2, RestartAddress, &CheckForZombieThread, NULL);
  2665. }
  2666. //
  2667. // Print summary statistics last so they don't get lost on screen scroll.
  2668. //
  2669. if (Flags & 0x1) {
  2670. if (ZombieProcessCount == 0) {
  2671. dprintf ("\n\n************ NO zombie processes found ***********\n");
  2672. }
  2673. else {
  2674. dprintf ("\n\n************ %d zombie processes found ***********\n", ZombieProcessCount);
  2675. dprintf (" Resident page cost : %8ld Kb\n",
  2676. ZombieProcessResidentAvailable / 1024);
  2677. dprintf (" Commit cost : %8ld Kb\n",
  2678. ZombieProcessCommit / 1024);
  2679. dprintf (" Pool cost : %8ld bytes\n",
  2680. ZombieProcessPool);
  2681. }
  2682. dprintf ("\n");
  2683. }
  2684. if (Flags & 0x2) {
  2685. if (ZombieCount == 0) {
  2686. dprintf ("\n\n************ NO zombie threads found ***********\n");
  2687. }
  2688. else {
  2689. dprintf ("\n\n************ %d zombie threads found ***********\n", ZombieCount);
  2690. dprintf (" Resident page cost : %8ld Kb\n",
  2691. ZombieResidentAvailable / 1024);
  2692. dprintf (" Commit cost : %8ld Kb\n",
  2693. ZombieCommit / 1024);
  2694. dprintf (" Pool cost : %8ld bytes\n",
  2695. ZombiePool);
  2696. }
  2697. }
  2698. EXIT_API();
  2699. return S_OK;
  2700. }
  2701. VOID
  2702. DumpMmThreads (
  2703. VOID
  2704. )
  2705. /*++
  2706. Routine Description:
  2707. Finds and dumps the interesting memory management threads.
  2708. Arguments:
  2709. None.
  2710. Return Value:
  2711. None.
  2712. --*/
  2713. {
  2714. ULONG i;
  2715. ULONG MemoryMaker;
  2716. ULONG64 ProcessToDump;
  2717. ULONG Flags;
  2718. ULONG64 Next;
  2719. ULONG64 ProcessHead;
  2720. ULONG64 Process;
  2721. ULONG64 Thread;
  2722. CHAR Buf[256];
  2723. STRING string1, string2;
  2724. ULONG64 InterestingThreads[4];
  2725. ULONG ActvOffset, PcbThListOffset, TcbThListOffset;
  2726. ProcessToDump = (ULONG64) -1;
  2727. Flags = 0xFFFFFFFF;
  2728. ProcessHead = GetNtDebuggerData( PsActiveProcessHead );
  2729. if (!ProcessHead) {
  2730. dprintf("Unable to get value of PsActiveProcessHead\n");
  2731. return;
  2732. }
  2733. if (GetFieldValue( ProcessHead, "nt!_LIST_ENTRY", "Flink", Next )) {
  2734. dprintf("Unable to read nt!_LIST_ENTRY @ %p\n", ProcessHead);
  2735. return;
  2736. }
  2737. if (Next == 0) {
  2738. dprintf("PsActiveProcessHead is NULL!\n");
  2739. return;
  2740. }
  2741. InterestingThreads[0] = GetExpression ("nt!MiModifiedPageWriter");
  2742. InterestingThreads[1] = GetExpression ("nt!MiMappedPageWriter");
  2743. InterestingThreads[2] = GetExpression ("nt!MiDereferenceSegmentThread");
  2744. InterestingThreads[3] = GetExpression ("nt!KeBalanceSetManager");
  2745. RtlInitString(&string1, "System");
  2746. GetFieldOffset("nt!_EPROCESS", "ActiveProcessLinks", &ActvOffset);
  2747. GetFieldOffset("nt!_EPROCESS", "Pcb.ThreadListHead", &PcbThListOffset);
  2748. GetFieldOffset("nt!_KTHREAD", "ThreadListEntry", &TcbThListOffset);
  2749. while(Next != ProcessHead) {
  2750. Process = Next - ActvOffset;
  2751. if (GetFieldValue( Process, "nt!_EPROCESS", "ImageFileName", Buf )) {
  2752. dprintf("Unable to read _EPROCESS at %p\n",Process);
  2753. return;
  2754. }
  2755. // strcpy((PCHAR)Buf,(PCHAR)ProcessContents.ImageFileName);
  2756. RtlInitString(&string2, (PCSZ) Buf);
  2757. if (RtlCompareString(&string1, &string2, TRUE) == 0) {
  2758. //
  2759. // Find the threads.
  2760. //
  2761. GetFieldValue( Process, "nt!_EPROCESS", "Pcb.ThreadListHead.Flink", Next);
  2762. while ( Next != Process + PcbThListOffset) {
  2763. ULONG64 StartAddress;
  2764. Thread = Next - TcbThListOffset;
  2765. if (GetFieldValue(Thread,
  2766. "nt!_ETHREAD",
  2767. "StartAddress",
  2768. StartAddress)) {
  2769. dprintf("Unable to read _ETHREAD at %p\n",Thread);
  2770. break;
  2771. }
  2772. if (GetFieldValue(Thread,
  2773. "nt!_ETHREAD",
  2774. "MemoryMaker",
  2775. MemoryMaker)) {
  2776. for (i = 0; i < 4; i += 1) {
  2777. if (StartAddress == InterestingThreads[i]) {
  2778. DumpThread (0," ", Thread, 7);
  2779. break;
  2780. }
  2781. }
  2782. }
  2783. else if (MemoryMaker & 0x1) {
  2784. DumpThread (0," ", Thread, 7);
  2785. }
  2786. GetFieldValue(Thread, "nt!_KTHREAD","ThreadListEntry.Flink", Next);
  2787. if (CheckControlC()) {
  2788. return;
  2789. }
  2790. }
  2791. dprintf("\n");
  2792. break;
  2793. }
  2794. GetFieldValue( Process, "nt!_EPROCESS", "ActiveProcessLinks.Flink", Next);
  2795. if (CheckControlC()) {
  2796. return;
  2797. }
  2798. }
  2799. return;
  2800. }
  2801. HRESULT
  2802. DumpApc(
  2803. PCHAR Pad,
  2804. ULONG64 Kapc
  2805. )
  2806. {
  2807. CHAR Buffer[MAX_PATH];
  2808. ULONG64 KernelRoutine;
  2809. ULONG64 RundownRoutine;
  2810. ULONG64 disp;
  2811. if (InitTypeRead(Kapc, nt!_KAPC))
  2812. {
  2813. dprintf("%sCannot read nt!_KAPC @ %p\n", Kapc);
  2814. return E_FAIL;
  2815. }
  2816. dprintf("%sKAPC @ %p\n", Pad, Kapc);
  2817. dprintf("%s Type %lx\n", Pad, ReadField(Type));
  2818. KernelRoutine = ReadField(KernelRoutine);
  2819. GetSymbol(KernelRoutine, Buffer, &disp);
  2820. dprintf("%s KernelRoutine %p %s+%I64lx\n", Pad, KernelRoutine, Buffer, disp);
  2821. RundownRoutine = ReadField(RundownRoutine);
  2822. GetSymbol(RundownRoutine, Buffer, &disp);
  2823. dprintf("%s RundownRoutine %p %s+%I64lx\n", Pad, RundownRoutine, Buffer, disp);
  2824. return S_OK;
  2825. }
  2826. HRESULT
  2827. EnumerateThreadApcs(
  2828. PCHAR Pad,
  2829. ULONG64 Thread
  2830. )
  2831. {
  2832. ULONG Header_Type;
  2833. ULONG ApcStateIndex;
  2834. ULONG ApcListHeadOffset;
  2835. ULONG KapcListOffset;
  2836. ULONG64 ApcListHead;
  2837. ULONG64 Flink;
  2838. if (InitTypeRead(Thread, nt!_KTHREAD))
  2839. {
  2840. dprintf("%sCannot read nt!_KTHREAD @ %p\n", Thread);
  2841. return E_FAIL;
  2842. }
  2843. Header_Type = (ULONG) ReadField(Header.Type);
  2844. if (Header_Type != ThreadObject)
  2845. {
  2846. dprintf("TYPE mismatch for thread object at %p\n",Thread);
  2847. return FALSE;
  2848. }
  2849. Flink = ReadField(ApcState.ApcListHead.Flink);
  2850. ApcStateIndex = (ULONG) ReadField(ApcStateIndex);
  2851. GetFieldOffset("nt!_KTHREAD", "ApcState.ApcListHead", &ApcListHeadOffset);
  2852. if (GetFieldOffset("nt!_KAPC", "ApcListEntry", &KapcListOffset))
  2853. {
  2854. dprintf("%sCannot find nt!_KAPC.ApcListEntry\n");
  2855. return E_FAIL;
  2856. }
  2857. ApcListHead = Thread+ApcListHeadOffset;
  2858. if (!strlen(Pad) ||
  2859. (Flink && (ApcListHead != Flink)))
  2860. {
  2861. dprintf("%sThread %p ApcStateIndex %lx ApcListHead %p\n",
  2862. Pad, Thread, ApcStateIndex, ApcListHead);
  2863. } else
  2864. {
  2865. dprintf("%sThread %p\r",
  2866. Pad, Thread, ApcStateIndex, ApcListHead);
  2867. }
  2868. while (Flink && (ApcListHead != Flink))
  2869. {
  2870. ULONG64 Next;
  2871. CHAR Pad2[20];
  2872. if (!ReadPointer(Flink, &Next))
  2873. {
  2874. break;
  2875. }
  2876. if (CheckControlC())
  2877. {
  2878. return E_FAIL;
  2879. }
  2880. StringCchCopy(Pad2, sizeof(Pad2), Pad);
  2881. StringCchCat(Pad2, sizeof(Pad2), " ");
  2882. if (DumpApc(Pad2, Flink - KapcListOffset) != S_OK)
  2883. {
  2884. break;
  2885. }
  2886. Flink = Next;
  2887. }
  2888. return S_OK;
  2889. }
  2890. ULONG
  2891. ThrdApcsCallback(
  2892. PFIELD_INFO listElement,
  2893. PVOID Context
  2894. )
  2895. {
  2896. ULONG64 Thread = listElement->address;
  2897. if (FAILED(EnumerateThreadApcs(" ", Thread)))
  2898. {
  2899. return TRUE;
  2900. }
  2901. return FALSE;
  2902. }
  2903. HRESULT
  2904. EnumerateProcApcs(
  2905. PCHAR Pad,
  2906. ULONG64 Process
  2907. )
  2908. {
  2909. ULONG64 ThreadListHead_Flink=0;
  2910. ULONG64 Pcb_Header_Type;
  2911. ULONG64 Next;
  2912. CHAR ImageFileName[20];
  2913. GetFieldValue(Process, "nt!_EPROCESS", "Pcb.Header.Type", Pcb_Header_Type);
  2914. if (Pcb_Header_Type != ProcessObject)
  2915. {
  2916. dprintf("TYPE mismatch for process object at %p\n", Pad, Process);
  2917. return S_FALSE;
  2918. }
  2919. GetFieldValue(Process, "nt!_EPROCESS", "ImageFileName", ImageFileName);
  2920. dprintf("%sProcess %p %s\n", Pad, Process, ImageFileName);
  2921. if (GetFieldValue(Process, "nt!_EPROCESS", "Pcb.ThreadListHead.Flink", ThreadListHead_Flink))
  2922. {
  2923. return S_FALSE;
  2924. }
  2925. if (!ReadPointer(ThreadListHead_Flink, &Next) ||
  2926. (Next == ThreadListHead_Flink))
  2927. {
  2928. return S_OK;
  2929. }
  2930. if (ListType("nt!_ETHREAD", ThreadListHead_Flink, 1,
  2931. "Tcb.ThreadListEntry.Flink", (PVOID) Pad, &ThrdApcsCallback))
  2932. {
  2933. return E_FAIL;
  2934. }
  2935. return S_OK;
  2936. }
  2937. ULONG
  2938. ProcApcsCallback(
  2939. PFIELD_INFO listElement,
  2940. PVOID Context
  2941. )
  2942. {
  2943. ULONG64 Process=listElement->address;
  2944. if (FAILED(EnumerateProcApcs("", Process)))
  2945. {
  2946. return TRUE;
  2947. }
  2948. return FALSE;
  2949. }
  2950. HRESULT
  2951. EnumerateAllApcs(
  2952. void
  2953. )
  2954. {
  2955. ULONG64 ProcessHead, Next;
  2956. if (!GetProcessHead(&ProcessHead, &Next))
  2957. {
  2958. return E_FAIL;
  2959. }
  2960. ListType("nt!_EPROCESS", Next, 1, "ActiveProcessLinks.Flink", NULL, &ProcApcsCallback);
  2961. return S_OK;
  2962. }
  2963. DECLARE_API( apc )
  2964. {
  2965. HRESULT Hr;
  2966. ULONG64 Process = 0;
  2967. ULONG64 Thread = 0;
  2968. ULONG64 Kapc = 0;
  2969. INIT_API();
  2970. while (*args && ((*args == ' ') || (*args == '\t'))) ++args;
  2971. if (!_strnicmp(args, "proc", 4))
  2972. {
  2973. while (*args && (*args != ' ') && (*args != '\t')) ++args;
  2974. Process = GetExpression(args);
  2975. EnumerateProcApcs("", Process);
  2976. }
  2977. else if (!_strnicmp(args, "thre", 4))
  2978. {
  2979. while (*args && (*args != ' ') && (*args != '\t')) ++args;
  2980. Thread = GetExpression(args);
  2981. EnumerateThreadApcs("", Thread);
  2982. } else if (*args)
  2983. {
  2984. if (!isxdigit(*args))
  2985. {
  2986. dprintf("Usage !apc [Proc <process>]|[Thre <thread]|[<kapc>]\n\n");
  2987. EXIT_API();
  2988. return S_OK;
  2989. }
  2990. Kapc = GetExpression(args);
  2991. DumpApc("", Kapc);
  2992. } else
  2993. {
  2994. dprintf("*** Enumerating APCs in all processes\n");
  2995. EnumerateAllApcs();
  2996. }
  2997. // erase any leftover output from \r printing
  2998. dprintf(" \n");
  2999. EXIT_API();
  3000. return S_OK;
  3001. }