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.

1709 lines
29 KiB

  1. /*++
  2. Copyright (c) 1999 Microsoft Corporation
  3. Module Name:
  4. dbgrm.c - DbgExtension Structure information specific to RM APIs
  5. Abstract:
  6. Revision History:
  7. Who When What
  8. -------- -------- ----------------------------------------------
  9. josephj 03-01-99 Created
  10. Notes:
  11. --*/
  12. #ifdef TESTPROGRAM
  13. #include "c.h"
  14. #else
  15. #include "precomp.h"
  16. #endif
  17. #include "util.h"
  18. #include "parse.h"
  19. #include "dbgrm.h"
  20. enum
  21. {
  22. typeid_NULL,
  23. typeid_RM_OBJECT_HEADER,
  24. typeid_RM_TASK,
  25. typeid_RM_ASSOCIATIONS,
  26. typeid_RM_GROUP,
  27. typeid_RM_STACK_RECORD,
  28. typeid_RM_OBJECT_LOG,
  29. typeid_RM_OBJECT_TREE
  30. };
  31. //
  32. // STRUCTURES CONCERNING TYPE "OBJECT_HEADER"
  33. //
  34. // Actually handles dumping of object info.
  35. //
  36. void
  37. RmDumpObj(
  38. struct _TYPE_INFO *pType,
  39. UINT_PTR uAddr,
  40. char *szFieldSpec,
  41. UINT uFlags
  42. );
  43. // Actually handles dumping of task info.
  44. //
  45. void
  46. RmDumpTask(
  47. struct _TYPE_INFO *pType,
  48. UINT_PTR uAddr,
  49. char *szFieldSpec,
  50. UINT uFlags
  51. );
  52. // Actually handles dumping of task info.
  53. //
  54. void
  55. RmDumpGroup(
  56. struct _TYPE_INFO *pType,
  57. UINT_PTR uAddr,
  58. char *szFieldSpec,
  59. UINT uFlags
  60. );
  61. // Actually handles dumping of task info.
  62. //
  63. void
  64. RmDumpAssociations(
  65. struct _TYPE_INFO *pType,
  66. UINT_PTR uAddr,
  67. char *szFieldSpec,
  68. UINT uFlags
  69. );
  70. // Actually handles dumping of task info.
  71. //
  72. void
  73. RmDumpStackRecord(
  74. struct _TYPE_INFO *pType,
  75. UINT_PTR uAddr,
  76. char *szFieldSpec,
  77. UINT uFlags
  78. );
  79. // Actually handles dumping of object log info.
  80. //
  81. void
  82. RmDumpObjectLog(
  83. struct _TYPE_INFO *pType,
  84. UINT_PTR uAddr,
  85. char *szFieldSpec,
  86. UINT uFlags
  87. );
  88. // Actually handles dumping of object decendents tree
  89. //
  90. void
  91. RmDumpObjectTree(
  92. struct _TYPE_INFO *pType,
  93. UINT_PTR uAddr,
  94. char *szFieldSpec,
  95. UINT uFlags
  96. );
  97. // Node function for dumping one node of the list of children.
  98. //
  99. ULONG
  100. NodeFunc_DumpObjectTree (
  101. UINT_PTR uNodeAddr,
  102. UINT uIndex,
  103. void *pvContext
  104. );
  105. BITFIELD_INFO rgRM_OBJECT_STATE[] =
  106. {
  107. {
  108. "O_ALLOC",
  109. RMOBJSTATE_ALLOCMASK,
  110. RMOBJSTATE_ALLOCATED
  111. },
  112. {
  113. "O_DEALLOC",
  114. RMOBJSTATE_ALLOCMASK,
  115. RMOBJSTATE_DEALLOCATED
  116. },
  117. #if 0 // don't want this -- as it gets displayed for non-task, looking wierd.
  118. {
  119. "T_IDLE",
  120. RMTSKSTATE_MASK,
  121. RMTSKSTATE_IDLE
  122. },
  123. #endif // 0
  124. {
  125. "T_STARTING",
  126. RMTSKSTATE_MASK,
  127. RMTSKSTATE_STARTING
  128. },
  129. {
  130. "T_ACTIVE",
  131. RMTSKSTATE_MASK,
  132. RMTSKSTATE_ACTIVE
  133. },
  134. {
  135. "T_PENDING",
  136. RMTSKSTATE_MASK,
  137. RMTSKSTATE_PENDING
  138. },
  139. {
  140. "T_ENDING",
  141. RMTSKSTATE_MASK,
  142. RMTSKSTATE_ENDING
  143. },
  144. {
  145. "T_DELAYED",
  146. RMTSKDELSTATE_MASK,
  147. RMTSKDELSTATE_DELAYED
  148. },
  149. {
  150. "T_ABORT_DELAY",
  151. RMTSKABORTSTATE_MASK,
  152. RMTSKABORTSTATE_ABORT_DELAY
  153. },
  154. {
  155. NULL
  156. }
  157. };
  158. TYPE_INFO type_RM_OBJECT_HEADER = {
  159. "RM_OBJECT_HEADER",
  160. "obj",
  161. typeid_RM_OBJECT_HEADER,
  162. 0, //fTYPEINFO_ISLIST, // Flags
  163. sizeof(RM_OBJECT_HEADER),
  164. NULL, // FIELD_INFO
  165. 0, // offset to next object.
  166. NULL, // rgBitFieldInfo
  167. RmDumpObj // pfnSpecializedDump
  168. };
  169. TYPE_INFO type_RM_TASK = {
  170. "RM_TASK",
  171. "tsk",
  172. typeid_RM_TASK,
  173. 0, //fTYPEINFO_ISLIST, // Flags
  174. sizeof(RM_TASK),
  175. NULL, // FIELD_INFO
  176. 0, // offset to next object.
  177. NULL, // rgBitFieldInfo
  178. RmDumpTask // pfnSpecializedDump
  179. };
  180. TYPE_INFO type_RM_GROUP = {
  181. "RM_GROUP",
  182. "grp",
  183. typeid_RM_GROUP,
  184. 0, //fTYPEINFO_ISLIST, // Flags
  185. sizeof(RM_GROUP),
  186. NULL, // FIELD_INFO
  187. 0, // offset to next object.
  188. NULL, // rgBitFieldInfo
  189. RmDumpGroup // pfnSpecializedDump
  190. };
  191. TYPE_INFO type_RM_ASSOCIATIONS = {
  192. "RM_ASSOCIATIONS",
  193. "asc",
  194. typeid_RM_ASSOCIATIONS,
  195. 0, //fTYPEINFO_ISLIST, // Flags
  196. 1, //This is not really an object, but we must have nonzero size.
  197. NULL, // FIELD_INFO
  198. 0, // offset to next object.
  199. NULL, // rgBitFieldInfo
  200. RmDumpAssociations // pfnSpecializedDump
  201. };
  202. TYPE_INFO type_RM_STACK_RECORD = {
  203. "RM_STACK_RECORD",
  204. "sr",
  205. typeid_RM_STACK_RECORD,
  206. 0, //fTYPEINFO_ISLIST, // Flags
  207. sizeof(RM_STACK_RECORD),
  208. NULL, // FIELD_INFO
  209. 0, // offset to next object.
  210. NULL, // rgBitFieldInfo
  211. RmDumpStackRecord // pfnSpecializedDump
  212. };
  213. TYPE_INFO type_RM_OBJECT_LOG = {
  214. "RM_OBJECT_LOG",
  215. "log",
  216. //typeid_RM_STACK_RECORD,
  217. typeid_RM_OBJECT_LOG,
  218. 0, //fTYPEINFO_ISLIST, // Flags
  219. 1, //This is not really an object, but we must have nonzero size.
  220. NULL, // FIELD_INFO
  221. 0, // offset to next object.
  222. NULL, // rgBitFieldInfo
  223. RmDumpObjectLog // pfnSpecializedDump
  224. };
  225. TYPE_INFO type_RM_OBJECT_TREE = {
  226. "RM_OBJECT_TREE",
  227. "tree",
  228. typeid_RM_OBJECT_TREE,
  229. 0, //fTYPEINFO_ISLIST, // Flags
  230. 1, //This is not really an object, but we must have nonzero size.
  231. NULL, // FIELD_INFO
  232. 0, // offset to next object.
  233. NULL, // rgBitFieldInfo
  234. RmDumpObjectTree // pfnSpecializedDump
  235. };
  236. TYPE_INFO *g_rgRM_Types[] =
  237. {
  238. &type_RM_OBJECT_HEADER,
  239. &type_RM_TASK,
  240. &type_RM_GROUP,
  241. &type_RM_ASSOCIATIONS,
  242. &type_RM_STACK_RECORD,
  243. &type_RM_OBJECT_LOG,
  244. &type_RM_OBJECT_TREE,
  245. NULL
  246. };
  247. UINT_PTR
  248. RM_ResolveAddress(
  249. TYPE_INFO *pType
  250. );
  251. NAMESPACE RM_NameSpace = {
  252. g_rgRM_Types,
  253. NULL, // g_rgRM_Globals,
  254. RM_ResolveAddress
  255. };
  256. UINT_PTR
  257. RM_ResolveAddress(
  258. TYPE_INFO *pType
  259. )
  260. {
  261. return 0;
  262. }
  263. void
  264. do_rm(PCSTR args)
  265. {
  266. DBGCOMMAND *pCmd = Parse(args, &RM_NameSpace);
  267. if (pCmd)
  268. {
  269. DumpCommand(pCmd);
  270. DoCommand(pCmd, NULL);
  271. FreeCommand(pCmd);
  272. pCmd = NULL;
  273. }
  274. return;
  275. }
  276. void
  277. do_help(PCSTR args)
  278. {
  279. return;
  280. }
  281. void
  282. dump_object_fields(UINT_PTR uAddr, PRM_OBJECT_HEADER pObj);
  283. // Actually handles dumping of object info.
  284. //
  285. void
  286. RmDumpObj(
  287. struct _TYPE_INFO *pType,
  288. UINT_PTR uAddr,
  289. char *szFieldSpec,
  290. UINT uFlags
  291. )
  292. /*++
  293. !rm obj 0x838c7560
  294. Object 0x838c7560 (LocalIP)
  295. Hdr
  296. Sig :A13L State:0xc4db69b3 Refs:990
  297. pLock: 0x838c7560 pSIinfo:0xfdd0a965 pDInfo :0xd54d947c
  298. pParent: 0x2995941a pRoot:0x060af4a8 pHLink :0xce4294fe
  299. HdrSize: 0x123 Assoc:909
  300. --*/
  301. {
  302. RM_OBJECT_HEADER Obj;
  303. bool fRet;
  304. do
  305. {
  306. char rgDescriptionBuf[256];
  307. // First let's read the pObj structure.
  308. //
  309. fRet = dbgextReadMemory(
  310. uAddr,
  311. &Obj,
  312. sizeof(Obj),
  313. "RM_OBJECT_HEADER"
  314. );
  315. if (!fRet) break;
  316. // Try to read the object's description.
  317. //
  318. fRet = dbgextReadSZ(
  319. (UINT_PTR) Obj.szDescription,
  320. rgDescriptionBuf,
  321. sizeof(rgDescriptionBuf),
  322. "Obj.szDescription"
  323. );
  324. if (!fRet) break;
  325. MyDbgPrintf("\nObject 0x%p (%s)\n", uAddr, rgDescriptionBuf);
  326. dump_object_fields(uAddr, &Obj);
  327. } while(FALSE);
  328. }
  329. // Actually handles dumping of task info.
  330. //
  331. void
  332. RmDumpTask(
  333. struct _TYPE_INFO *pType,
  334. UINT_PTR uAddr,
  335. char *szFieldSpec,
  336. UINT uFlags
  337. )
  338. {
  339. RM_TASK Task;
  340. bool fRet;
  341. do
  342. {
  343. char rgDescriptionBuf[256];
  344. // First let's read the pObj structure.
  345. //
  346. fRet = dbgextReadMemory(
  347. uAddr,
  348. &Task,
  349. sizeof(Task),
  350. "RM_OBJECT_HEADER"
  351. );
  352. if (!fRet) break;
  353. // Try to read the object's description.
  354. //
  355. fRet = dbgextReadSZ(
  356. (UINT_PTR) Task.Hdr.szDescription,
  357. rgDescriptionBuf,
  358. sizeof(rgDescriptionBuf),
  359. "Task.Hdr.szDescription"
  360. );
  361. if (!fRet) break;
  362. // Dump the object header
  363. //
  364. {
  365. MyDbgPrintf("\nTask 0x%p (%s)\n", uAddr, rgDescriptionBuf);
  366. dump_object_fields(uAddr, &Task.Hdr);
  367. }
  368. //
  369. // Now Dump the task-specific fields...
  370. //
  371. {
  372. /*
  373. TskHdr
  374. pfn: 0x5399424c State:0x812d7211(IDLE) SCtxt:0x050eefc4
  375. pBlkTsk:0x377c74bc lnkFellows:0x2b88126f
  376. Pending Tasks
  377. 0x84215fa5 0xb51f9e9e 0x9e954e81 0x696095b9
  378. 0x0c07aeff
  379. */
  380. MyDbgPrintf(
  381. " TaskHdr:\n"
  382. " pfn:0x%p SCtxt:0x%08lx\n",
  383. Task.pfnHandler,
  384. Task.SuspendContext
  385. );
  386. MyDbgPrintf(
  387. " pBlkTsk:0x%p lnkFellows:0x%p\n",
  388. Task.pTaskIAmPendingOn,
  389. &(((PRM_TASK) uAddr)->linkFellowPendingTasks)
  390. );
  391. // Note we can't use IsListEmpty because of the different address space.
  392. //
  393. if (Task.listTasksPendingOnMe.Flink == Task.listTasksPendingOnMe.Blink)
  394. {
  395. MyDbgPrintf(" No pending tasks.\n");
  396. }
  397. else
  398. {
  399. MyDbgPrintf(" Pending tasks:\n");
  400. dbgextDumpDLlist(
  401. (UINT_PTR) &(((PRM_TASK) uAddr)->listTasksPendingOnMe),
  402. FIELD_OFFSET(RM_TASK, linkFellowPendingTasks),
  403. "Pending tasks list"
  404. );
  405. }
  406. }
  407. } while(FALSE);
  408. }
  409. void
  410. dbg_walk_rm_hash_table(
  411. PRM_HASH_TABLE pTable,
  412. UINT uContainingOffset,
  413. char *szDescription
  414. );
  415. #if RM_EXTRA_CHECKING
  416. void
  417. dbg_print_rm_associations(
  418. PRM_HASH_TABLE pRmAssociationHashTable,
  419. UINT MaxToPrint
  420. );
  421. void
  422. dbg_print_object_log_entries(
  423. UINT_PTR uObjectListOffset,
  424. UINT MaxToPrint
  425. );
  426. #endif // RM_EXTRA_CHECKING
  427. // Actually handles dumping of task info.
  428. //
  429. void
  430. RmDumpGroup(
  431. struct _TYPE_INFO *pType,
  432. UINT_PTR uAddr,
  433. char *szFieldSpec,
  434. UINT uFlags
  435. )
  436. /*
  437. !rm grp 0x838c7560
  438. Group 0x4d650b98 (LocalIP Group) of object 0x11eafd78 (Interface)
  439. Num:11 State:ENABLED pSInfo: 0x944b6d1b pULTsk: 0x8c312bca
  440. Members:
  441. 0x8db3267c 0xa639f663 0x8f3530a6 0xa4bfe0b9
  442. 0x995dd9bf 0x61e1344b 0xd6323f50 0x606339fd
  443. 0x2e8ed2a4 0x62e52f27 0xa82b59ab
  444. */
  445. {
  446. RM_GROUP Group;
  447. bool fRet;
  448. do
  449. {
  450. char rgDescriptionBuf[256];
  451. char rgOwningObjectDescriptionBuf[256];
  452. // First let's read the Group structure.
  453. //
  454. fRet = dbgextReadMemory(
  455. uAddr,
  456. &Group,
  457. sizeof(Group),
  458. "RM_GROUP"
  459. );
  460. if (!fRet) break;
  461. // Try to read the group's description.
  462. //
  463. fRet = dbgextReadSZ(
  464. (UINT_PTR) Group.szDescription,
  465. rgDescriptionBuf,
  466. sizeof(rgDescriptionBuf),
  467. "Obj.szDescription"
  468. );
  469. if (!fRet) break;
  470. // Try to read the owning object's description.
  471. //
  472. do {
  473. UINT_PTR uAddress;
  474. fRet = dbgextReadUINT_PTR(
  475. (UINT_PTR) &(Group.pOwningObject->szDescription),
  476. &uAddress,
  477. "Owning Obj.szDescription ptr"
  478. );
  479. if (!fRet) break;
  480. fRet = dbgextReadSZ(
  481. uAddress,
  482. rgOwningObjectDescriptionBuf,
  483. sizeof(rgOwningObjectDescriptionBuf),
  484. "Owning Obj.szDescription"
  485. );
  486. } while (FALSE);
  487. if (!fRet)
  488. {
  489. *rgOwningObjectDescriptionBuf = 0;
  490. }
  491. MyDbgPrintf(
  492. "\nGroup 0x%p (%s) of object 0x%p (%s)\n",
  493. uAddr,
  494. rgDescriptionBuf,
  495. Group.pOwningObject,
  496. rgOwningObjectDescriptionBuf
  497. );
  498. MyDbgPrintf(
  499. " Num:0x%08x State:%s pSInfo:0x%08x\n",
  500. Group.HashTable.NumItems,
  501. (Group.fEnabled) ? "ENABLED " : "DISABLED",
  502. Group.pStaticInfo
  503. );
  504. MyDbgPrintf(
  505. " pULTsk:0x%08x\n",
  506. Group.pUnloadTask
  507. );
  508. if (Group.HashTable.NumItems==0)
  509. {
  510. MyDbgPrintf(" No members.\n");
  511. }
  512. else
  513. {
  514. MyDbgPrintf(" Members:\n");
  515. dbg_walk_rm_hash_table(
  516. &Group.HashTable,
  517. FIELD_OFFSET(RM_OBJECT_HEADER, HashLink),
  518. "Group members"
  519. );
  520. }
  521. } while(FALSE);
  522. }
  523. // Actually handles dumping of task info.
  524. //
  525. void
  526. RmDumpAssociations(
  527. struct _TYPE_INFO *pType,
  528. UINT_PTR uAddr,
  529. char *szFieldSpec,
  530. UINT uFlags
  531. )
  532. {
  533. /*
  534. !rm asc 0x9ba265f8
  535. Associations for object 0x838c7560 (LocalIP):
  536. Child of 0x010091A0 (Globals)
  537. Parent of 0x00073558 (Task2)
  538. Parent of 0x00073920 (Task3a)
  539. Parent of 0x000739F8 (Task3b)
  540. */
  541. RM_OBJECT_HEADER Obj;
  542. bool fRet;
  543. UINT uNumAssociations = -1;
  544. do
  545. {
  546. char rgDescriptionBuf[256];
  547. // First let's read the pObj structure.
  548. //
  549. fRet = dbgextReadMemory(
  550. uAddr,
  551. &Obj,
  552. sizeof(Obj),
  553. "RM_OBJECT_HEADER"
  554. );
  555. if (!fRet) break;
  556. // Try to read the object's description.
  557. //
  558. fRet = dbgextReadSZ(
  559. (UINT_PTR) Obj.szDescription,
  560. rgDescriptionBuf,
  561. sizeof(rgDescriptionBuf),
  562. "Obj.szDescription"
  563. );
  564. if (!fRet) break;
  565. // Try to get the number of associations field in the diag info struct.
  566. //
  567. if (Obj.pDiagInfo != NULL)
  568. {
  569. bool fRet;
  570. UINT_PTR uNumItemsOffset =
  571. (UINT_PTR) &(Obj.pDiagInfo->AssociationTable.NumItems);
  572. fRet = dbgextReadUINT(
  573. uNumItemsOffset,
  574. &uNumAssociations,
  575. "pDiagInfo->AssociationTable.NumItems"
  576. );
  577. if (!fRet)
  578. {
  579. uNumAssociations = (UINT) -1;
  580. }
  581. }
  582. if (uNumAssociations == 0)
  583. {
  584. MyDbgPrintf(
  585. "\nObject 0x%p (%s) has no associations.\n",
  586. uAddr,
  587. rgDescriptionBuf
  588. );
  589. }
  590. else if (uNumAssociations == (UINT)-1)
  591. {
  592. MyDbgPrintf(
  593. "\nObject 0x%p (%s) associations are not available.\n",
  594. uAddr,
  595. rgDescriptionBuf
  596. );
  597. }
  598. else
  599. {
  600. #if RM_EXTRA_CHECKING
  601. // Get the association hash table table.
  602. //
  603. RM_HASH_TABLE AssociationTable;
  604. MyDbgPrintf(
  605. "\nAssociations (50 max) for 0x%p (%s):\n",
  606. uAddr,
  607. rgDescriptionBuf
  608. );
  609. fRet = dbgextReadMemory(
  610. (UINT_PTR) &(Obj.pDiagInfo->AssociationTable),
  611. &AssociationTable,
  612. sizeof(AssociationTable),
  613. "Association Table"
  614. );
  615. if (!fRet) break;
  616. dbg_print_rm_associations(
  617. &AssociationTable,
  618. 50
  619. );
  620. #endif // RM_EXTRA_CHECKING
  621. }
  622. } while(FALSE);
  623. }
  624. // Actually handles dumping of task info.
  625. //
  626. void
  627. RmDumpStackRecord(
  628. struct _TYPE_INFO *pType,
  629. UINT_PTR uAddr,
  630. char *szFieldSpec,
  631. UINT uFlags
  632. )
  633. {
  634. /*
  635. !rm sr 0x838c7560
  636. Stack Record 0x838c7560
  637. TmpRefs: 2
  638. HeldLocks:
  639. 0xe916a45f 0x23d8d2d3 0x5f47a2f2
  640. */
  641. RM_STACK_RECORD sr;
  642. bool fRet;
  643. do
  644. {
  645. // First let's read the RM_STACK_RECORD structure.
  646. //
  647. fRet = dbgextReadMemory(
  648. uAddr,
  649. &sr,
  650. sizeof(sr),
  651. "RM_STACK_RECORD"
  652. );
  653. if (!fRet) break;
  654. MyDbgPrintf( "\nStack Record 0x%p\n", uAddr);
  655. MyDbgPrintf(
  656. " TmpRefs:0x%08x LockLevel:0x%08lx pFirst:0x%08lx NumHeld=%lu\n",
  657. sr.TmpRefs,
  658. sr.LockInfo.CurrentLevel,
  659. sr.LockInfo.pFirst,
  660. sr.LockInfo.pNextFree-sr.LockInfo.pFirst
  661. );
  662. // Display held locks.
  663. //
  664. if (sr.LockInfo.CurrentLevel==0)
  665. {
  666. MyDbgPrintf(" No held locks.\n");
  667. }
  668. else
  669. {
  670. // MyDbgPrintf(" Held locks:<unimplemented>\n");
  671. }
  672. } while(FALSE);
  673. }
  674. // Actually handles dumping of the object log
  675. //
  676. void
  677. RmDumpObjectLog(
  678. struct _TYPE_INFO *pType,
  679. UINT_PTR uAddr,
  680. char *szFieldSpec,
  681. UINT uFlags
  682. )
  683. {
  684. /*
  685. !rm log 0x9ba265f8
  686. Log for object 0x838c7560 (LocalIP):
  687. Added association X
  688. Deleted association Y
  689. ...
  690. */
  691. RM_OBJECT_HEADER Obj;
  692. bool fRet;
  693. UINT uNumEntries = 0;
  694. do
  695. {
  696. char rgDescriptionBuf[256];
  697. // First let's read the pObj structure.
  698. //
  699. fRet = dbgextReadMemory(
  700. uAddr,
  701. &Obj,
  702. sizeof(Obj),
  703. "RM_OBJECT_HEADER"
  704. );
  705. if (!fRet) break;
  706. // Try to read the object's description.
  707. //
  708. fRet = dbgextReadSZ(
  709. (UINT_PTR) Obj.szDescription,
  710. rgDescriptionBuf,
  711. sizeof(rgDescriptionBuf),
  712. "Obj.szDescription"
  713. );
  714. if (!fRet) break;
  715. // Try to get the number of log entries field in the diag info struct.
  716. //
  717. if (Obj.pDiagInfo != NULL)
  718. {
  719. bool fRet;
  720. UINT_PTR uNumItemsOffset =
  721. (UINT_PTR) &(Obj.pDiagInfo->NumObjectLogEntries);
  722. fRet = dbgextReadUINT(
  723. uNumItemsOffset,
  724. &uNumEntries,
  725. "pDiagInfo->NumObjectLogEntries"
  726. );
  727. if (!fRet)
  728. {
  729. uNumEntries = (UINT) -1;
  730. }
  731. }
  732. if (uNumEntries == 0)
  733. {
  734. MyDbgPrintf(
  735. "\nObject 0x%p (%s) has no log entries.\n",
  736. uAddr,
  737. rgDescriptionBuf
  738. );
  739. }
  740. else if (uNumEntries == (UINT)-1)
  741. {
  742. MyDbgPrintf(
  743. "\nObject 0x%p (%s) log entries are not available.\n",
  744. uAddr,
  745. rgDescriptionBuf
  746. );
  747. }
  748. else
  749. {
  750. #if RM_EXTRA_CHECKING
  751. UINT uNumToDump = uNumEntries;
  752. if (uNumToDump > 50)
  753. {
  754. uNumToDump = 50;
  755. }
  756. MyDbgPrintf(
  757. "\nLog entries for 0x%p (%s) (%lu of %lu):\n",
  758. uAddr,
  759. rgDescriptionBuf,
  760. uNumToDump,
  761. uNumEntries
  762. );
  763. dbg_print_object_log_entries(
  764. (UINT_PTR) &(Obj.pDiagInfo->listObjectLog),
  765. uNumToDump
  766. );
  767. #endif // RM_EXTRA_CHECKING
  768. }
  769. } while(FALSE);
  770. }
  771. // Actually handles dumping of the object tree
  772. //
  773. void
  774. RmDumpObjectTree(
  775. struct _TYPE_INFO *pType,
  776. UINT_PTR uAddr,
  777. char *szFieldSpec,
  778. UINT uFlags
  779. )
  780. {
  781. /*
  782. !rm tree 0x9ba265f8
  783. Tree for object 0x838c7560 (LocalIP) (Parent 0x82222222)
  784. Display sample:
  785. 0x2222222(RemoteIp)
  786. |---0x22222222(Dest)
  787. |---|---0x22222222(Dest)
  788. |---|---|---0x22222222(Dest)
  789. |---|---0x22222222(pTask)
  790. |---0x11111111(RemoteIp)
  791. */
  792. RM_OBJECT_HEADER Obj;
  793. RM_OBJECT_HEADER ParentObj;
  794. bool fRet;
  795. UINT uNumEntries = 0;
  796. do
  797. {
  798. char rgDescriptionBuf[256];
  799. char rgParentDescriptionBuf[256];
  800. // First let's read the pObj structure.
  801. //
  802. fRet = dbgextReadMemory(
  803. uAddr,
  804. &Obj,
  805. sizeof(Obj),
  806. "RM_OBJECT_HEADER"
  807. );
  808. if (!fRet) break;
  809. // Try to read the object's description.
  810. //
  811. fRet = dbgextReadSZ(
  812. (UINT_PTR) Obj.szDescription,
  813. rgDescriptionBuf,
  814. sizeof(rgDescriptionBuf),
  815. "Obj.szDescription"
  816. );
  817. if (!fRet) break;
  818. // Try to read the parent's object.
  819. //
  820. if (Obj.pParentObject!=NULL && (UINT_PTR) Obj.pParentObject != uAddr)
  821. {
  822. fRet = dbgextReadMemory(
  823. (UINT_PTR) Obj.pParentObject,
  824. &ParentObj,
  825. sizeof(ParentObj),
  826. "RM_OBJECT_HEADER"
  827. );
  828. if (!fRet) break;
  829. // Try to get pParent's description.
  830. //
  831. fRet = dbgextReadSZ(
  832. (UINT_PTR) ParentObj.szDescription,
  833. rgParentDescriptionBuf,
  834. sizeof(rgParentDescriptionBuf),
  835. "ParentObj.szDescription"
  836. );
  837. if (!fRet) break;
  838. }
  839. else
  840. {
  841. strcpy(rgParentDescriptionBuf, "<root>");
  842. }
  843. MyDbgPrintf(
  844. "\nObject Tree for 0x%p(%s) with parent 0x%p(%s):\n",
  845. uAddr,
  846. rgDescriptionBuf,
  847. Obj.pParentObject,
  848. rgParentDescriptionBuf
  849. );
  850. NodeFunc_DumpObjectTree(
  851. (UINT_PTR) &(((PRM_OBJECT_HEADER)uAddr)->linkSiblings),
  852. 0, // Index (unused)
  853. (void *)0 // pvContext == level
  854. );
  855. } while(FALSE);
  856. }
  857. void
  858. dump_object_fields(UINT_PTR uAddr, PRM_OBJECT_HEADER pObj)
  859. {
  860. UINT uNumAssociations = (UINT) -1;
  861. // Try to get the number of associations field in the diag info struct.
  862. //
  863. if (pObj->pDiagInfo != NULL)
  864. {
  865. bool fRet;
  866. UINT_PTR uNumItemsOffset =
  867. (UINT_PTR) &(pObj->pDiagInfo->AssociationTable.NumItems);
  868. fRet = dbgextReadUINT(
  869. uNumItemsOffset,
  870. &uNumAssociations,
  871. "pDiagInfo->AssociationTable.NumItems"
  872. );
  873. if (!fRet)
  874. {
  875. uNumAssociations = (UINT) -1;
  876. }
  877. }
  878. MyDbgPrintf(
  879. " Hdr:\n"
  880. " Sig:0x%08x State:0x%08x Refs:0x%08x\n",
  881. pObj->Sig,
  882. pObj->State,
  883. pObj->TotRefs
  884. );
  885. MyDbgPrintf(
  886. " pLock:0x%p pSInfo:0x%p pDInfo:0x%p\n",
  887. pObj->pLock,
  888. pObj->pStaticInfo,
  889. pObj->pDiagInfo
  890. );
  891. MyDbgPrintf(
  892. " pParent:0x%p pRoot:0x%p pHLink:0x%p\n",
  893. pObj->pParentObject,
  894. pObj->pRootObject,
  895. &(((PRM_OBJECT_HEADER) uAddr)->HashLink)
  896. );
  897. MyDbgPrintf(
  898. " HdrSize:0x%08lx Assoc:%d\n",
  899. sizeof(*pObj),
  900. uNumAssociations
  901. );
  902. MyDbgPrintf( " RmState: ");
  903. DumpBitFields(
  904. pObj->RmState,
  905. rgRM_OBJECT_STATE
  906. );
  907. MyDbgPrintf( "\n");
  908. }
  909. void
  910. dbg_walk_rm_hash_table(
  911. PRM_HASH_TABLE pRmHashTable,
  912. UINT uContainingOffset,
  913. char *szDescription
  914. )
  915. {
  916. // For now, we get the whole hash table array in one fell swoop...
  917. //
  918. PRM_HASH_LINK rgTable[512];
  919. UINT TableLength = pRmHashTable->TableLength;
  920. bool fRet;
  921. do
  922. {
  923. // Sanity check.
  924. //
  925. if (TableLength > sizeof(rgTable)/sizeof(*rgTable))
  926. {
  927. MyDbgPrintf(
  928. " HashTable length %lu too large\n",
  929. TableLength
  930. );
  931. break;
  932. }
  933. // Read the whole hash table.
  934. //
  935. fRet = dbgextReadMemory(
  936. (UINT_PTR) pRmHashTable->pTable,
  937. rgTable,
  938. TableLength * sizeof(*rgTable),
  939. "Hash Table"
  940. );
  941. if (!fRet) break;
  942. // Now go through the table visiting each list...
  943. //
  944. {
  945. PRM_HASH_LINK *ppLink, *ppLinkEnd;
  946. UINT uCount = 0;
  947. UINT uMax = 15;
  948. ppLink = rgTable;
  949. ppLinkEnd = ppLink + TableLength;
  950. for ( ; ppLink < ppLinkEnd; ppLink++)
  951. {
  952. PRM_HASH_LINK pLink = *ppLink;
  953. for (;pLink != NULL; uCount++)
  954. {
  955. char *szPrefix;
  956. char *szSuffix;
  957. RM_HASH_LINK Link;
  958. szPrefix = " ";
  959. szSuffix = "";
  960. if (uCount%4)
  961. {
  962. szPrefix = " ";
  963. if ((uCount%4)==3)
  964. {
  965. szSuffix = "\n";
  966. }
  967. }
  968. if (uCount >= uMax) break;
  969. MyDbgPrintf(
  970. "%s0x%p%s",
  971. szPrefix,
  972. ((char *) pLink) - uContainingOffset,
  973. szSuffix
  974. );
  975. // Let's try to read this link.
  976. //
  977. fRet = dbgextReadMemory(
  978. (UINT_PTR) pLink,
  979. &Link,
  980. sizeof(Link),
  981. "Hash Link"
  982. );
  983. if (!fRet) break;
  984. pLink = Link.pNext;
  985. }
  986. if (!fRet || (uCount >= uMax)) break;
  987. }
  988. {
  989. MyDbgPrintf("\n");
  990. }
  991. if (uCount < pRmHashTable->NumItems)
  992. {
  993. MyDbgPrintf(" ...\n");
  994. }
  995. }
  996. } while (FALSE);
  997. }
  998. #if RM_EXTRA_CHECKING
  999. void
  1000. dbg_dump_one_association(
  1001. RM_PRIVATE_DBG_ASSOCIATION *pAssoc
  1002. );
  1003. void
  1004. dbg_print_rm_associations(
  1005. PRM_HASH_TABLE pRmAssociationHashTable,
  1006. UINT MaxToPrint
  1007. )
  1008. {
  1009. // For now, we get the whole hash table array in one fell swoop...
  1010. //
  1011. PRM_HASH_LINK rgTable[512];
  1012. UINT TableLength = pRmAssociationHashTable->TableLength;
  1013. bool fRet;
  1014. do
  1015. {
  1016. // Sanity check.
  1017. //
  1018. if (TableLength > sizeof(rgTable)/sizeof(*rgTable))
  1019. {
  1020. MyDbgPrintf(
  1021. " HashTable length %lu too large\n",
  1022. TableLength
  1023. );
  1024. break;
  1025. }
  1026. // Read the whole hash table.
  1027. //
  1028. fRet = dbgextReadMemory(
  1029. (UINT_PTR) pRmAssociationHashTable->pTable,
  1030. rgTable,
  1031. TableLength * sizeof(*rgTable),
  1032. "Hash Table"
  1033. );
  1034. if (!fRet) break;
  1035. // Now go through the table visiting each list...
  1036. //
  1037. {
  1038. PRM_HASH_LINK *ppLink, *ppLinkEnd;
  1039. UINT uCount = 0;
  1040. UINT uMax = MaxToPrint;
  1041. ppLink = rgTable;
  1042. ppLinkEnd = ppLink + TableLength;
  1043. for ( ; ppLink < ppLinkEnd; ppLink++)
  1044. {
  1045. PRM_HASH_LINK pLink = *ppLink;
  1046. for (;pLink != NULL; uCount++)
  1047. {
  1048. RM_PRIVATE_DBG_ASSOCIATION Assoc;
  1049. UINT_PTR uAssocOffset =
  1050. (UINT_PTR) CONTAINING_RECORD(
  1051. pLink,
  1052. RM_PRIVATE_DBG_ASSOCIATION,
  1053. HashLink
  1054. );
  1055. if (uCount >= uMax) break;
  1056. // Let's try to read this association...
  1057. //
  1058. fRet = dbgextReadMemory(
  1059. uAssocOffset,
  1060. &Assoc,
  1061. sizeof(Assoc),
  1062. "Association"
  1063. );
  1064. if (!fRet) break;
  1065. dbg_dump_one_association(&Assoc);
  1066. pLink = Assoc.HashLink.pNext;
  1067. }
  1068. if (!fRet || (uCount >= uMax)) break;
  1069. }
  1070. if (uCount < pRmAssociationHashTable->NumItems)
  1071. {
  1072. MyDbgPrintf(" ...\n");
  1073. }
  1074. }
  1075. } while (FALSE);
  1076. }
  1077. void
  1078. dbg_dump_one_association(
  1079. RM_PRIVATE_DBG_ASSOCIATION *pAssoc
  1080. )
  1081. /*++
  1082. Dump the information on the specific association.
  1083. pAssoc is valid memory, however anything it points to is not in
  1084. our address space.
  1085. Since the association contains a format string, which may have
  1086. "%s"s in it, we need scan this format string and read any strings
  1087. referenced.
  1088. All this effort is well worth it. Check out the sample output!
  1089. Associations for 0x01023A40 (Globals):
  1090. Owns group 0x01023AC4 (O1 Group)
  1091. Parent of 0x00073240 (O2)
  1092. Parent of 0x00073488 (O2)
  1093. Associations for 0x000736D0 (Task3a):
  1094. Child of 0x00073240 (O2)
  1095. Pending on 0x000732C8 (TaskO2)
  1096. --*/
  1097. {
  1098. char rgFormatString[256];
  1099. char rgStrings[3][256];
  1100. char *szFormatString;
  1101. ULONG_PTR Args[3];
  1102. char *szDefaultFormatString = "\tAssociation (E1=0x%x, E2=0x%x, T=0x%x)\n";
  1103. bool fRet = FALSE;
  1104. do
  1105. {
  1106. // Try to read the format string.
  1107. //
  1108. {
  1109. fRet = dbgextReadSZ(
  1110. (UINT_PTR) pAssoc->szFormatString,
  1111. rgFormatString,
  1112. sizeof(rgFormatString),
  1113. "Association format"
  1114. );
  1115. if (fRet)
  1116. {
  1117. szFormatString = rgFormatString;
  1118. }
  1119. else
  1120. {
  1121. break;
  1122. }
  1123. }
  1124. // Now run through the format string, looking for "%s"s.
  1125. // and munging as required.
  1126. //
  1127. {
  1128. char *pc = rgFormatString;
  1129. UINT uCount=0;
  1130. Args[0] = pAssoc->Entity1;
  1131. Args[1] = pAssoc->Entity2;
  1132. Args[2] = pAssoc->AssociationID;
  1133. while (uCount<3 && pc[0]!=0 && pc[1]!=0)
  1134. {
  1135. if (pc[0]=='%')
  1136. {
  1137. if (pc[1]=='s')
  1138. {
  1139. // pc[1]='p';
  1140. fRet = dbgextReadSZ(
  1141. (UINT_PTR) Args[uCount],
  1142. rgStrings[uCount],
  1143. sizeof(rgStrings[uCount]),
  1144. "Association format"
  1145. );
  1146. if (fRet)
  1147. {
  1148. Args[uCount] = (ULONG_PTR) rgStrings[uCount];
  1149. }
  1150. else
  1151. {
  1152. break;
  1153. }
  1154. }
  1155. pc++; // we want to end up skipping past both chars.
  1156. uCount++;
  1157. }
  1158. pc++;
  1159. }
  1160. }
  1161. }
  1162. while (FALSE);
  1163. if (!fRet)
  1164. {
  1165. // Back off to the defaults..
  1166. //
  1167. szFormatString = szDefaultFormatString;
  1168. Args[0] = pAssoc->Entity1;
  1169. Args[1] = pAssoc->Entity2;
  1170. Args[2] = pAssoc->AssociationID;
  1171. }
  1172. MyDbgPrintf(
  1173. szFormatString,
  1174. Args[0],
  1175. Args[1],
  1176. Args[2]
  1177. );
  1178. }
  1179. ULONG
  1180. NodeFunc_DumpObjectLogFromObjectLink (
  1181. UINT_PTR uNodeAddr,
  1182. UINT uIndex,
  1183. void *pvContext
  1184. )
  1185. {
  1186. RM_DBG_LOG_ENTRY LE;
  1187. LIST_ENTRY *pLink = (LIST_ENTRY*) uNodeAddr;
  1188. UINT_PTR uLEOffset = (UINT_PTR) CONTAINING_RECORD(
  1189. pLink,
  1190. RM_DBG_LOG_ENTRY,
  1191. linkObjectLog
  1192. );
  1193. char rgPrefixString[256];
  1194. char rgFormatString[256];
  1195. char rgStrings[4][256];
  1196. char *szPrefixString;
  1197. char *szFormatString;
  1198. ULONG_PTR Args[4];
  1199. char *szDefaultFormatString =
  1200. "Log Entry (P1=%p, P2=%p, P3=%p, P4=%p, szFmt=%p)\n";
  1201. bool fRet = FALSE;
  1202. // Read the containing record.
  1203. //
  1204. fRet = dbgextReadMemory(
  1205. uLEOffset,
  1206. &LE,
  1207. sizeof(LE),
  1208. "Log Entry"
  1209. );
  1210. if (!fRet) return 0; // EARLY RETURN;
  1211. #if 0
  1212. if (LE.pfnDumpEntry != NULL)
  1213. {
  1214. //
  1215. // TODO we need to get the corresponding function to dump this
  1216. // specialized entry.
  1217. //
  1218. MyDbgPrintf(
  1219. "Specialized (pfn=%p szFmt=%p, P1=%p, P2=%p, P3=%p, P4=%p)\n",
  1220. LE.pfnDumpEntry,
  1221. LE.szFormatString,
  1222. LE.Param1,
  1223. LE.Param2,
  1224. LE.Param3,
  1225. LE.Param4
  1226. );
  1227. return 0; // EARLY RETURN
  1228. }
  1229. #else
  1230. //
  1231. // Above check is invalid, because in all cases there is a pfnDump function.
  1232. //
  1233. #endif
  1234. //
  1235. // TODO -- following code is very similar to the dump-association code --
  1236. // move common stuff to some utility function.
  1237. //
  1238. do
  1239. {
  1240. // Try to read the prefix string.
  1241. //
  1242. {
  1243. fRet = FALSE;
  1244. if (LE.szPrefix != NULL)
  1245. {
  1246. fRet = dbgextReadSZ(
  1247. (UINT_PTR) LE.szPrefix,
  1248. rgPrefixString,
  1249. sizeof(rgPrefixString),
  1250. "Prefix String"
  1251. );
  1252. }
  1253. if (fRet)
  1254. {
  1255. szPrefixString = rgPrefixString;
  1256. }
  1257. else
  1258. {
  1259. szPrefixString = "";
  1260. }
  1261. }
  1262. // Try to read the format string.
  1263. //
  1264. {
  1265. fRet = dbgextReadSZ(
  1266. (UINT_PTR) LE.szFormatString,
  1267. rgFormatString,
  1268. sizeof(rgFormatString),
  1269. "Log entry format"
  1270. );
  1271. if (fRet)
  1272. {
  1273. szFormatString = rgFormatString;
  1274. }
  1275. else
  1276. {
  1277. break;
  1278. }
  1279. }
  1280. // Now run through the format string, looking for "%s"s.
  1281. // and munging as required.
  1282. //
  1283. {
  1284. char *pc = rgFormatString;
  1285. UINT uCount=0;
  1286. Args[0] = LE.Param1;
  1287. Args[1] = LE.Param2;
  1288. Args[2] = LE.Param3;
  1289. Args[3] = LE.Param4;
  1290. while (uCount<4 && pc[0]!=0 && pc[1]!=0)
  1291. {
  1292. if (pc[0]=='%')
  1293. {
  1294. if (pc[1]=='s')
  1295. {
  1296. // pc[1]='p';
  1297. fRet = dbgextReadSZ(
  1298. (UINT_PTR) Args[uCount],
  1299. rgStrings[uCount],
  1300. sizeof(rgStrings[uCount]),
  1301. "Log entry param"
  1302. );
  1303. if (fRet)
  1304. {
  1305. Args[uCount] = (ULONG_PTR) rgStrings[uCount];
  1306. }
  1307. else
  1308. {
  1309. break;
  1310. }
  1311. }
  1312. pc++; // we want to end up skipping past both chars.
  1313. uCount++;
  1314. }
  1315. pc++;
  1316. }
  1317. }
  1318. } while (FALSE);
  1319. if (!fRet)
  1320. {
  1321. // Back off to the defaults..
  1322. //
  1323. szPrefixString = "";
  1324. szFormatString = szDefaultFormatString;
  1325. Args[0] = LE.Param1;
  1326. Args[1] = LE.Param2;
  1327. Args[2] = LE.Param3;
  1328. Args[3] = LE.Param4;
  1329. }
  1330. MyDbgPrintf(szPrefixString);
  1331. MyDbgPrintf(
  1332. szFormatString,
  1333. Args[0],
  1334. Args[1],
  1335. Args[2],
  1336. Args[3],
  1337. LE.szFormatString
  1338. );
  1339. return 0;
  1340. }
  1341. void
  1342. dbg_print_object_log_entries(
  1343. UINT_PTR uObjectListOffset,
  1344. UINT MaxToPrint
  1345. )
  1346. {
  1347. WalkDLlist(
  1348. uObjectListOffset,
  1349. 0, //uOffsetStartLink
  1350. NULL, // pvContext
  1351. NodeFunc_DumpObjectLogFromObjectLink,
  1352. MaxToPrint,
  1353. "Object log"
  1354. );
  1355. }
  1356. #endif // RM_EXTRA_CHECKING
  1357. char szDumpTreePrefix[] = "|---|---|---|---|---|---|---|---|---|---"
  1358. "|---|---|---|---|---|---|---|---|---|---";
  1359. ULONG
  1360. NodeFunc_DumpObjectTree (
  1361. UINT_PTR uNodeAddr,
  1362. UINT uIndex,
  1363. void *pvContext
  1364. )
  1365. {
  1366. bool fRet = FALSE;
  1367. do
  1368. {
  1369. char rgDescriptionBuf[256];
  1370. LIST_ENTRY *pLink = (LIST_ENTRY*) uNodeAddr;
  1371. UINT_PTR uObjOffset = (UINT_PTR) CONTAINING_RECORD(
  1372. pLink,
  1373. RM_OBJECT_HEADER,
  1374. linkSiblings
  1375. );
  1376. UINT Level = (UINT) (UINT_PTR) pvContext; // we put the level in the context.
  1377. RM_OBJECT_HEADER Obj;
  1378. char *szPrefix;
  1379. // First make szPrefix point to the end (trailing zero) of the prefix string.
  1380. //
  1381. szPrefix = szDumpTreePrefix + sizeof(szDumpTreePrefix)-1;
  1382. // Now back up "Level" times.
  1383. //
  1384. if (Level < ((sizeof(szDumpTreePrefix)-1)/4))
  1385. {
  1386. szPrefix -= Level*4;
  1387. }
  1388. else
  1389. {
  1390. // Level is too large -- don't display anything.
  1391. //
  1392. MyDbgPrintf("Dump Tree depth(%d) is too large.\n", Level);
  1393. break;
  1394. }
  1395. // Read the containing record.
  1396. //
  1397. fRet = dbgextReadMemory(
  1398. uObjOffset,
  1399. &Obj,
  1400. sizeof(Obj),
  1401. "Object"
  1402. );
  1403. if (!fRet) break;
  1404. // Try to read the object's description.
  1405. //
  1406. fRet = dbgextReadSZ(
  1407. (UINT_PTR) Obj.szDescription,
  1408. rgDescriptionBuf,
  1409. sizeof(rgDescriptionBuf),
  1410. "Obj.szDescription"
  1411. );
  1412. if (!fRet) break;
  1413. // Display the object info.
  1414. //
  1415. MyDbgPrintf(
  1416. "%s%p(%s)\n",
  1417. szPrefix,
  1418. uObjOffset,
  1419. rgDescriptionBuf
  1420. );
  1421. //
  1422. // Now walk the list of children, displaying each of them.
  1423. //
  1424. WalkDLlist(
  1425. (UINT_PTR) &(((PRM_OBJECT_HEADER)uObjOffset)->listChildren),
  1426. 0, //uOffsetStartLink
  1427. (void*) (Level+1), // pvContext
  1428. NodeFunc_DumpObjectTree,
  1429. 50, // Max children per node to dump
  1430. "Object children"
  1431. );
  1432. } while (FALSE);
  1433. return 0;
  1434. }