1
0

objects.c 28 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042
  1. /*++
  2. Copyright (c) 2012 Minoca Corp. All Rights Reserved
  3. Module Name:
  4. objects.c
  5. Abstract:
  6. This module implements Object Manager related debugger extensions.
  7. Author:
  8. Evan Green 11-Sep-2012
  9. Environment:
  10. Debug Client
  11. --*/
  12. //
  13. // ------------------------------------------------------------------- Includes
  14. //
  15. #include <minoca/kernel/driver.h>
  16. #include <minoca/debug/dbgext.h>
  17. #include <assert.h>
  18. #include <errno.h>
  19. #include <stdio.h>
  20. #include <stdlib.h>
  21. #include <string.h>
  22. //
  23. // ---------------------------------------------------------------- Definitions
  24. //
  25. #define MAX_OBJECT_NAME 512
  26. #define ROOT_OBJECT_NAME "kernel!ObRootObject"
  27. #define MALLOC(_x) malloc(_x)
  28. #define FREE(_x) free(_x)
  29. //
  30. // ------------------------------------------------------ Data Type Definitions
  31. //
  32. //
  33. // ----------------------------------------------- Internal Function Prototypes
  34. //
  35. INT
  36. ExtpHandleObjectCommand (
  37. PDEBUGGER_CONTEXT Context,
  38. PSTR Command,
  39. ULONGLONG Address
  40. );
  41. INT
  42. ExtpPrintObject (
  43. PDEBUGGER_CONTEXT Context,
  44. ULONG IndentationLevel,
  45. ULONGLONG ObjectAddress,
  46. BOOL OneLiner,
  47. BOOL FullPath,
  48. BOOL PrintChildren,
  49. BOOL FullyRecurse
  50. );
  51. VOID
  52. ExtpPrintIndentation (
  53. ULONG IndentationLevel
  54. );
  55. //
  56. // -------------------------------------------------------------------- Globals
  57. //
  58. //
  59. // ------------------------------------------------------------------ Functions
  60. //
  61. INT
  62. ExtObject (
  63. PDEBUGGER_CONTEXT Context,
  64. PSTR Command,
  65. ULONG ArgumentCount,
  66. PSTR *ArgumentValues
  67. )
  68. /*++
  69. Routine Description:
  70. This routine prints out the contents of an Object:
  71. Address - Supplies the address of the Object.
  72. Arguments:
  73. Context - Supplies a pointer to the debugger applicaton context, which is
  74. an argument to most of the API functions.
  75. Command - Supplies the subcommand entered. This parameter is unused.
  76. ArgumentCount - Supplies the number of arguments in the ArgumentValues
  77. array.
  78. ArgumentValues - Supplies the values of each argument. This memory will be
  79. reused when the function returns, so extensions must not touch this
  80. memory after returning from this call.
  81. Return Value:
  82. 0 if the debugger extension command was successful.
  83. Returns an error code if a failure occurred along the way.
  84. --*/
  85. {
  86. ULONG AddressSize;
  87. ULONG ArgumentIndex;
  88. ULONG BytesRead;
  89. ULONGLONG ObjectAddress;
  90. ULONGLONG RootObjectAddress;
  91. INT Status;
  92. AddressSize = DbgGetTargetPointerSize(Context);
  93. //
  94. // At least one parameter is required.
  95. //
  96. if (ArgumentCount < 2) {
  97. //
  98. // Attempt to find the root object.
  99. //
  100. Status = DbgEvaluate(Context, ROOT_OBJECT_NAME, &RootObjectAddress);
  101. if (Status == 0) {
  102. Status = DbgReadMemory(Context,
  103. TRUE,
  104. RootObjectAddress,
  105. AddressSize,
  106. &RootObjectAddress,
  107. &BytesRead);
  108. if ((Status != 0) || (BytesRead != AddressSize)) {
  109. DbgOut("Unable to find ObRootObject.\n");
  110. if (Status == 0) {
  111. Status = EINVAL;
  112. }
  113. return Status;
  114. }
  115. ExtpHandleObjectCommand(Context, Command, RootObjectAddress);
  116. } else {
  117. DbgOut("Error: Unable to evaluate %s.\n", ROOT_OBJECT_NAME);
  118. return Status;
  119. }
  120. }
  121. //
  122. // Loop through each argument, evaluate the address, and print the
  123. // namespace tree at that object.
  124. //
  125. for (ArgumentIndex = 1;
  126. ArgumentIndex < ArgumentCount;
  127. ArgumentIndex += 1) {
  128. Status = DbgEvaluate(Context,
  129. ArgumentValues[ArgumentIndex],
  130. &ObjectAddress);
  131. if (Status != 0) {
  132. DbgOut("Failed to evaluate address at \"%s\".\n",
  133. ArgumentValues[ArgumentIndex]);
  134. }
  135. ExtpHandleObjectCommand(Context, Command, ObjectAddress);
  136. if (ArgumentIndex != ArgumentCount - 1) {
  137. DbgOut("\n----\n");
  138. }
  139. }
  140. DbgOut("\n");
  141. return 0;
  142. }
  143. //
  144. // --------------------------------------------------------- Internal Functions
  145. //
  146. INT
  147. ExtpHandleObjectCommand (
  148. PDEBUGGER_CONTEXT Context,
  149. PSTR Command,
  150. ULONGLONG Address
  151. )
  152. /*++
  153. Routine Description:
  154. This routine handles an object command.
  155. Arguments:
  156. Context - Supplies a pointer to the application context.
  157. Command - Supplies a pointer to the command to handle.
  158. Address - Supplies the address of the object to print.
  159. Return Value:
  160. 0 on success.
  161. Returns an error code on failure.
  162. --*/
  163. {
  164. INT Success;
  165. if (Command == NULL) {
  166. Success = ExtpPrintObject(Context,
  167. 1,
  168. Address,
  169. FALSE,
  170. TRUE,
  171. FALSE,
  172. FALSE);
  173. } else if (strcmp(Command, "list") == 0) {
  174. Success = ExtpPrintObject(Context,
  175. 0,
  176. Address,
  177. TRUE,
  178. FALSE,
  179. TRUE,
  180. FALSE);
  181. } else if (strcmp(Command, "tree") == 0) {
  182. Success = ExtpPrintObject(Context,
  183. 0,
  184. Address,
  185. TRUE,
  186. FALSE,
  187. TRUE,
  188. TRUE);
  189. } else if (strcmp(Command, "help") == 0) {
  190. DbgOut("Valid subcommands are:\n "
  191. "!object - print an object.\n "
  192. "!object.list - print an object and its children.\n "
  193. "!object.tree - print the entire tree underneath "
  194. "the given object.\n");
  195. Success = 0;
  196. } else {
  197. DbgOut("Error: Invalid subcommand. Run !object.help for "
  198. "detailed usage.\n");
  199. Success = 0;
  200. }
  201. return Success;
  202. }
  203. INT
  204. ExtpPrintObject (
  205. PDEBUGGER_CONTEXT Context,
  206. ULONG IndentationLevel,
  207. ULONGLONG ObjectAddress,
  208. BOOL OneLiner,
  209. BOOL FullPath,
  210. BOOL PrintChildren,
  211. BOOL FullyRecurse
  212. )
  213. /*++
  214. Routine Description:
  215. This routine prints out an object.
  216. Arguments:
  217. Context - Supplies a pointer to the application context.
  218. IndentationLevel - Supplies the current indentation level that the object
  219. should be printed at.
  220. ObjectAddress - Supplies the virtual address (in the target) of the
  221. object to print.
  222. OneLiner - Supplies a boolean indicating that only one line of text should
  223. be printed.
  224. FullPath - Supplies a boolean indicating whether the full object path
  225. should be printed or not.
  226. PrintChildren - Supplies a boolean indicating whether or not the routine
  227. should recurse into printing the object's direct children.
  228. FullyRecurse - Supplies a boolean indicating whether or not the routine
  229. should fully recurse to all descendents of the object.
  230. Return Value:
  231. 0 on success.
  232. Returns an error code on failure.
  233. --*/
  234. {
  235. ULONG AddressSize;
  236. ULONG BytesRead;
  237. ULONGLONG ChildAddress;
  238. ULONGLONG ChildListHeadAddress;
  239. ULONG ChildListOffset;
  240. ULONGLONG CurrentListEntryAddress;
  241. PSTR CurrentName;
  242. ULONG CurrentNameSize;
  243. ULONGLONG CurrentObjectName;
  244. ULONGLONG CurrentObjectParent;
  245. PVOID Data;
  246. ULONG DataSize;
  247. ULONGLONG FirstChild;
  248. BOOL FirstWaiter;
  249. PSTR FullName;
  250. ULONG FullNameSize;
  251. PVOID ListEntryData;
  252. ULONG ListEntryDataSize;
  253. PTYPE_SYMBOL ListEntryType;
  254. ULONGLONG ListHeadAddress;
  255. ULONGLONG LockHeld;
  256. PSTR NewFullName;
  257. ULONGLONG NextObjectAddress;
  258. ULONGLONG NextSibling;
  259. PVOID ObjectData;
  260. ULONG ObjectDataSize;
  261. ULONGLONG ObjectParent;
  262. PTYPE_SYMBOL ObjectType;
  263. ULONGLONG ObjectTypeValue;
  264. ULONGLONG OwningThread;
  265. ULONGLONG RootObjectAddress;
  266. ULONG SiblingEntryOffset;
  267. INT Status;
  268. ULONGLONG WaitBlockEntryAddress;
  269. ULONG WaitBlockEntryListEntryOffset;
  270. PTYPE_SYMBOL WaitBlockEntryType;
  271. ULONG WaitersOffset;
  272. ULONG WaitQueueOffset;
  273. PTYPE_SYMBOL WaitQueueType;
  274. AddressSize = DbgGetTargetPointerSize(Context);
  275. CurrentName = NULL;
  276. Data = NULL;
  277. FullName = NULL;
  278. FullNameSize = 0;
  279. ListEntryData = NULL;
  280. ObjectData = NULL;
  281. RootObjectAddress = 0;
  282. ExtpPrintIndentation(IndentationLevel);
  283. //
  284. // Attempt to read the object header.
  285. //
  286. Status = DbgReadTypeByName(Context,
  287. ObjectAddress,
  288. "OBJECT_HEADER",
  289. &ObjectType,
  290. &ObjectData,
  291. &ObjectDataSize);
  292. if (Status != 0) {
  293. DbgOut("Error: Could not read object.\n");
  294. goto PrintObjectEnd;
  295. }
  296. Status = DbgReadIntegerMember(Context,
  297. ObjectType,
  298. "Type",
  299. ObjectAddress,
  300. ObjectData,
  301. ObjectDataSize,
  302. &ObjectTypeValue);
  303. if (Status != 0) {
  304. goto PrintObjectEnd;
  305. }
  306. Status = DbgReadIntegerMember(Context,
  307. ObjectType,
  308. "Name",
  309. ObjectAddress,
  310. ObjectData,
  311. ObjectDataSize,
  312. &CurrentObjectName);
  313. if (Status != 0) {
  314. goto PrintObjectEnd;
  315. }
  316. Status = DbgReadIntegerMember(Context,
  317. ObjectType,
  318. "Parent",
  319. ObjectAddress,
  320. ObjectData,
  321. ObjectDataSize,
  322. &ObjectParent);
  323. if (Status != 0) {
  324. goto PrintObjectEnd;
  325. }
  326. CurrentObjectParent = ObjectParent;
  327. if ((ObjectTypeValue == ObjectInvalid) ||
  328. (ObjectTypeValue >= ObjectMaxTypes)) {
  329. DbgOut("%08I64x probably not an object, has type %I64x.\n",
  330. ObjectAddress,
  331. ObjectTypeValue);
  332. Status = EINVAL;
  333. goto PrintObjectEnd;
  334. }
  335. //
  336. // If the full name should be printed, collect that now.
  337. //
  338. CurrentName = MALLOC(MAX_OBJECT_NAME);
  339. if (CurrentName == NULL) {
  340. DbgOut("Error: Memory allocation failure.\n");
  341. Status = ENOMEM;
  342. goto PrintObjectEnd;
  343. }
  344. if (FullPath != FALSE) {
  345. //
  346. // Attempt to find the root object.
  347. //
  348. Status = DbgEvaluate(Context, ROOT_OBJECT_NAME, &RootObjectAddress);
  349. if (Status == 0) {
  350. Status = DbgReadMemory(Context,
  351. TRUE,
  352. RootObjectAddress,
  353. AddressSize,
  354. &RootObjectAddress,
  355. &BytesRead);
  356. if ((Status != 0) || (BytesRead != sizeof(PVOID))) {
  357. DbgOut("Unable to find ObRootObject.\n");
  358. RootObjectAddress = 0;
  359. if (Status == 0) {
  360. Status = EINVAL;
  361. }
  362. goto PrintObjectEnd;
  363. }
  364. } else {
  365. RootObjectAddress = 0;
  366. }
  367. //
  368. // Iterate up through the tree towards the root, prepending the object
  369. // name at each step.
  370. //
  371. while (TRUE) {
  372. //
  373. // Read in the current object's name string, or at least as much of
  374. // it as this extension cares to read.
  375. //
  376. if (CurrentObjectName == 0) {
  377. strncpy(CurrentName, "<noname>", MAX_OBJECT_NAME);
  378. } else {
  379. Status = DbgReadMemory(Context,
  380. TRUE,
  381. CurrentObjectName,
  382. MAX_OBJECT_NAME,
  383. CurrentName,
  384. &BytesRead);
  385. if (Status != 0) {
  386. DbgOut("Error: Unable to read object name at 0x%08I64x.\n",
  387. CurrentObjectName);
  388. goto PrintObjectEnd;
  389. }
  390. //
  391. // Terminate the string.
  392. //
  393. if (BytesRead == MAX_OBJECT_NAME) {
  394. CurrentName[MAX_OBJECT_NAME - 1] = '\0';
  395. } else {
  396. CurrentName[BytesRead] = '\0';
  397. }
  398. }
  399. //
  400. // Create a new full path big enough to hold everything, and copy
  401. // it in.
  402. //
  403. CurrentNameSize = strlen(CurrentName);
  404. NewFullName = MALLOC(CurrentNameSize + FullNameSize + 2);
  405. if (NewFullName == NULL) {
  406. DbgOut("Error: Memory allocation failure for %d bytes.\n",
  407. CurrentNameSize + FullNameSize + 2);
  408. Status = ENOMEM;
  409. goto PrintObjectEnd;
  410. }
  411. strcpy(NewFullName, "/");
  412. strcat(NewFullName, CurrentName);
  413. if (FullName != NULL) {
  414. strcat(NewFullName, FullName);
  415. FREE(FullName);
  416. }
  417. FullName = NewFullName;
  418. FullNameSize += CurrentNameSize + 1;
  419. //
  420. // Find the parent, read it in, and loop.
  421. //
  422. if ((CurrentObjectParent == 0) ||
  423. (CurrentObjectParent == RootObjectAddress)) {
  424. break;
  425. }
  426. assert(Data == NULL);
  427. Status = DbgReadType(Context,
  428. CurrentObjectParent,
  429. ObjectType,
  430. &Data,
  431. &DataSize);
  432. if (Status != 0) {
  433. DbgOut("Error reading object at 0x%08I64x.\n",
  434. CurrentObjectParent);
  435. goto PrintObjectEnd;
  436. }
  437. Status = DbgReadIntegerMember(Context,
  438. ObjectType,
  439. "Name",
  440. ObjectAddress,
  441. Data,
  442. DataSize,
  443. &CurrentObjectName);
  444. if (Status != 0) {
  445. goto PrintObjectEnd;
  446. }
  447. Status = DbgReadIntegerMember(Context,
  448. ObjectType,
  449. "Parent",
  450. ObjectAddress,
  451. Data,
  452. DataSize,
  453. &CurrentObjectParent);
  454. if (Status != 0) {
  455. goto PrintObjectEnd;
  456. }
  457. free(Data);
  458. Data = NULL;
  459. }
  460. } else {
  461. //
  462. // Just read in this object's name.
  463. //
  464. if (CurrentObjectName == 0) {
  465. CurrentName[0] = '\0';
  466. } else {
  467. Status = DbgReadMemory(Context,
  468. TRUE,
  469. CurrentObjectName,
  470. MAX_OBJECT_NAME,
  471. CurrentName,
  472. &BytesRead);
  473. if (Status != 0) {
  474. DbgOut("Error: Unable to read object name at 0x%08I64x.\n",
  475. CurrentObjectName);
  476. goto PrintObjectEnd;
  477. }
  478. //
  479. // Terminate the string.
  480. //
  481. if (BytesRead == MAX_OBJECT_NAME) {
  482. CurrentName[MAX_OBJECT_NAME - 1] = '\0';
  483. } else {
  484. CurrentName[BytesRead] = '\0';
  485. }
  486. }
  487. FullName = CurrentName;
  488. CurrentName = NULL;
  489. }
  490. //
  491. // Get some attributes.
  492. //
  493. Status = DbgReadIntegerMember(Context,
  494. ObjectType,
  495. "SiblingEntry.Next",
  496. ObjectAddress,
  497. ObjectData,
  498. ObjectDataSize,
  499. &NextSibling);
  500. if (Status != 0) {
  501. goto PrintObjectEnd;
  502. }
  503. Status = DbgGetMemberOffset(ObjectType,
  504. "SiblingEntry",
  505. &SiblingEntryOffset,
  506. NULL);
  507. if (Status != 0) {
  508. goto PrintObjectEnd;
  509. }
  510. Status = DbgGetMemberOffset(ObjectType,
  511. "ChildListHead",
  512. &ChildListOffset,
  513. NULL);
  514. if (Status != 0) {
  515. goto PrintObjectEnd;
  516. }
  517. Status = DbgGetMemberOffset(ObjectType,
  518. "WaitQueue",
  519. &WaitQueueOffset,
  520. NULL);
  521. if (Status != 0) {
  522. goto PrintObjectEnd;
  523. }
  524. SiblingEntryOffset /= BITS_PER_BYTE;
  525. ChildListOffset /= BITS_PER_BYTE;
  526. WaitQueueOffset /= BITS_PER_BYTE;
  527. Status = DbgReadIntegerMember(Context,
  528. ObjectType,
  529. "ChildListHead.Next",
  530. ObjectAddress,
  531. ObjectData,
  532. ObjectDataSize,
  533. &FirstChild);
  534. if (Status != 0) {
  535. goto PrintObjectEnd;
  536. }
  537. Status = DbgGetTypeByName(Context, "LIST_ENTRY", &ListEntryType);
  538. if (Status != 0) {
  539. goto PrintObjectEnd;
  540. }
  541. //
  542. // Print out the one line version or the detailed version.
  543. //
  544. if (OneLiner != FALSE) {
  545. DbgOut("0x%08I64x ", ObjectAddress);
  546. DbgPrintTypeMember(Context,
  547. ObjectAddress,
  548. ObjectData,
  549. ObjectDataSize,
  550. ObjectType,
  551. "Type",
  552. 0,
  553. 0);
  554. DbgOut(" %s\n", FullName);
  555. } else {
  556. DbgOut("%20s : 0x%08I64x\n", "Object", ObjectAddress);
  557. ExtpPrintIndentation(IndentationLevel);
  558. DbgOut("%20s : ", "Type");
  559. DbgPrintTypeMember(Context,
  560. ObjectAddress,
  561. ObjectData,
  562. ObjectDataSize,
  563. ObjectType,
  564. "Type",
  565. 0,
  566. 0);
  567. DbgOut("\n");
  568. ExtpPrintIndentation(IndentationLevel);
  569. DbgOut("%20s : %s\n", "Name", FullName);
  570. ExtpPrintIndentation(IndentationLevel);
  571. Status = DbgReadIntegerMember(Context,
  572. ObjectType,
  573. "WaitQueue.Lock.LockHeld",
  574. ObjectAddress,
  575. ObjectData,
  576. ObjectDataSize,
  577. &LockHeld);
  578. if ((Status == 0) && (LockHeld != FALSE)) {
  579. Status = DbgReadIntegerMember(Context,
  580. ObjectType,
  581. "WaitQueue.Lock.OwningThread",
  582. ObjectAddress,
  583. ObjectData,
  584. ObjectDataSize,
  585. &OwningThread);
  586. if (Status == 0) {
  587. DbgOut("%20s : 0x%08x.\n", "Locked", OwningThread);
  588. ExtpPrintIndentation(IndentationLevel);
  589. }
  590. }
  591. //
  592. // Print various attributes of the object.
  593. //
  594. DbgOut("%20s : Parent 0x%08x Sibling ", "Relatives", ObjectParent);
  595. NextObjectAddress = NextSibling - SiblingEntryOffset;
  596. if (NextSibling == 0) {
  597. DbgOut("NULL");
  598. NextObjectAddress = 0;
  599. } else if (NextSibling == ObjectAddress + SiblingEntryOffset) {
  600. DbgOut("NONE");
  601. NextObjectAddress = 0;
  602. } else {
  603. DbgOut("0x%08I64x", NextObjectAddress);
  604. }
  605. DbgOut(" Child ");
  606. if (FirstChild == 0) {
  607. DbgOut("NULL\n");
  608. } else if (FirstChild == ObjectAddress + ChildListOffset) {
  609. DbgOut("NONE\n");
  610. } else {
  611. ChildAddress = FirstChild - ChildListOffset;
  612. DbgOut("0x%08I64x\n", ChildAddress);
  613. }
  614. ExtpPrintIndentation(IndentationLevel);
  615. DbgOut("%20s : ", "State");
  616. DbgPrintTypeMember(Context,
  617. ObjectAddress,
  618. ObjectData,
  619. ObjectDataSize,
  620. ObjectType,
  621. "WaitQueue.State",
  622. 0,
  623. 0);
  624. DbgOut("\n");
  625. ExtpPrintIndentation(IndentationLevel);
  626. DbgOut("%20s : ", "Ref Count");
  627. DbgPrintTypeMember(Context,
  628. ObjectAddress,
  629. ObjectData,
  630. ObjectDataSize,
  631. ObjectType,
  632. "ReferenceCount",
  633. 0,
  634. 0);
  635. DbgOut("\n");
  636. ExtpPrintIndentation(IndentationLevel);
  637. DbgOut("%20s : ", "Flags");
  638. DbgPrintTypeMember(Context,
  639. ObjectAddress,
  640. ObjectData,
  641. ObjectDataSize,
  642. ObjectType,
  643. "Flags",
  644. 0,
  645. 0);
  646. DbgOut("\n");
  647. ExtpPrintIndentation(IndentationLevel);
  648. //
  649. // Print a list of all threads waiting on this object.
  650. //
  651. DbgOut("%20s : ", "Waiters");
  652. Status = DbgGetTypeByName(Context, "WAIT_QUEUE", &WaitQueueType);
  653. if (Status != 0) {
  654. goto PrintObjectEnd;
  655. }
  656. Status = DbgGetMemberOffset(WaitQueueType,
  657. "Waiters",
  658. &WaitersOffset,
  659. NULL);
  660. if (Status != 0) {
  661. goto PrintObjectEnd;
  662. }
  663. WaitersOffset /= BITS_PER_BYTE;
  664. Status = DbgGetTypeByName(Context,
  665. "WAIT_BLOCK_ENTRY",
  666. &WaitBlockEntryType);
  667. if (Status != 0) {
  668. goto PrintObjectEnd;
  669. }
  670. Status = DbgGetMemberOffset(WaitBlockEntryType,
  671. "WaitListEntry",
  672. &WaitBlockEntryListEntryOffset,
  673. NULL);
  674. if (Status != 0) {
  675. goto PrintObjectEnd;
  676. }
  677. WaitBlockEntryListEntryOffset /= BITS_PER_BYTE;
  678. FirstWaiter = TRUE;
  679. ListHeadAddress = ObjectAddress + WaitQueueOffset + WaitersOffset;
  680. Status = DbgReadIntegerMember(Context,
  681. ObjectType,
  682. "WaitQueue.Waiters.Next",
  683. ObjectAddress,
  684. ObjectData,
  685. ObjectDataSize,
  686. &CurrentListEntryAddress);
  687. if (Status != 0) {
  688. goto PrintObjectEnd;
  689. }
  690. while (CurrentListEntryAddress != ListHeadAddress) {
  691. if (FirstWaiter == FALSE) {
  692. DbgOut(" : ");
  693. } else {
  694. FirstWaiter = FALSE;
  695. }
  696. WaitBlockEntryAddress = CurrentListEntryAddress -
  697. WaitBlockEntryListEntryOffset;
  698. DbgOut("0x%08I64x\n", WaitBlockEntryAddress);
  699. ExtpPrintIndentation(IndentationLevel);
  700. assert(ListEntryData == NULL);
  701. Status = DbgReadType(Context,
  702. CurrentListEntryAddress,
  703. ListEntryType,
  704. &ListEntryData,
  705. &ListEntryDataSize);
  706. if (Status != 0) {
  707. goto PrintObjectEnd;
  708. }
  709. Status = DbgReadIntegerMember(Context,
  710. ListEntryType,
  711. "Next",
  712. 0,
  713. ListEntryData,
  714. ListEntryDataSize,
  715. &CurrentListEntryAddress);
  716. if (Status != 0) {
  717. goto PrintObjectEnd;
  718. }
  719. free(ListEntryData);
  720. ListEntryData = NULL;
  721. }
  722. DbgOut("\n");
  723. }
  724. //
  725. // If children should be printed, go through their list.
  726. //
  727. if (PrintChildren != FALSE) {
  728. //
  729. // Get the first child and enumerate until no more siblings of that
  730. // child are found.
  731. //
  732. ChildListHeadAddress = ObjectAddress + ChildListOffset;
  733. ObjectAddress = FirstChild;
  734. while ((ObjectAddress != (INTN)NULL) &&
  735. (ObjectAddress != ChildListHeadAddress)) {
  736. Status = ExtpPrintObject(Context,
  737. IndentationLevel + 1,
  738. ObjectAddress - SiblingEntryOffset,
  739. TRUE,
  740. FALSE,
  741. FullyRecurse,
  742. FullyRecurse);
  743. if (Status != 0) {
  744. DbgOut("Failed to print child at 0x%I64x.\n", ObjectAddress);
  745. goto PrintObjectEnd;
  746. }
  747. assert(ListEntryData == NULL);
  748. Status = DbgReadType(Context,
  749. ObjectAddress,
  750. ListEntryType,
  751. &ListEntryData,
  752. &ListEntryDataSize);
  753. if (Status != 0) {
  754. DbgOut("Error: Could not read LIST_ENTRY at 0x%I64x.\n",
  755. ObjectAddress);
  756. goto PrintObjectEnd;
  757. }
  758. Status = DbgReadIntegerMember(Context,
  759. ListEntryType,
  760. "Next",
  761. 0,
  762. ListEntryData,
  763. ListEntryDataSize,
  764. &ObjectAddress);
  765. if (Status != 0) {
  766. goto PrintObjectEnd;
  767. }
  768. free(ListEntryData);
  769. ListEntryData = NULL;
  770. }
  771. }
  772. Status = 0;
  773. PrintObjectEnd:
  774. if (ObjectData != NULL) {
  775. free(ObjectData);
  776. }
  777. if (Data != NULL) {
  778. free(Data);
  779. }
  780. if (ListEntryData != NULL) {
  781. free(ListEntryData);
  782. }
  783. if (CurrentName != NULL) {
  784. FREE(CurrentName);
  785. }
  786. if (FullName != NULL) {
  787. FREE(FullName);
  788. }
  789. return Status;
  790. }
  791. VOID
  792. ExtpPrintIndentation (
  793. ULONG IndentationLevel
  794. )
  795. /*++
  796. Routine Description:
  797. This routine prints out some indentation spaces.
  798. Arguments:
  799. IndentationLevel - Supplies the current indentation level.
  800. Return Value:
  801. None.
  802. --*/
  803. {
  804. DbgOut("%*s", IndentationLevel, "");
  805. return;
  806. }