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

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