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.

1497 lines
46 KiB

  1. /*++
  2. Copyright (c) 1993 Microsoft Corporation
  3. Module Name:
  4. scexts.cxx
  5. Abstract:
  6. This function contains the eventlog ntsd debugger extensions
  7. Each DLL entry point is called with a handle to the process being
  8. debugged, as well as pointers to functions.
  9. This process cannot just _read data in the process being debugged.
  10. Therefore, some macros are defined that will copy data from
  11. the debuggee process into a location in this processes memory.
  12. The GET_DATA and GET_STRING macros (defined in this file) are used
  13. to _read memory in the process being debugged. The DebuggeeAddr is the
  14. address of the memory in the debuggee process. The LocalAddr is the
  15. address of memory in the debugger (this programs context) that data is
  16. to be copied into. Length describes the number of bytes to be copied.
  17. Author:
  18. Dan Lafferty (DanL) 12-Aug-1993
  19. Revision History:
  20. --*/
  21. #include <nt.h>
  22. #include <ntrtl.h>
  23. #include <nturtl.h>
  24. #include <windows.h>
  25. #include <ntsdexts.h>
  26. #include <stdio.h>
  27. #include <stdlib.h>
  28. #include <string.h>
  29. #include <malloc.h>
  30. #include <time.h>
  31. #include <winsvc.h>
  32. #include <dataman.h>
  33. #include <tstr.h>
  34. //#define DbgPrint(_x_) (lpOutputRoutine) _x_
  35. #define DbgPrint(_x_)
  36. #define MAX_NAME 256
  37. #define printf (lpOutputRoutine)
  38. #define GET_DATA(DebugeeAddr, LocalAddr, Length) \
  39. Status = ReadProcessMemory( \
  40. GlobalhCurrentProcess, \
  41. (LPVOID)DebugeeAddr, \
  42. LocalAddr, \
  43. Length, \
  44. NULL \
  45. );
  46. //
  47. // This macro copies a string from the debuggee
  48. // process, one character at a time into this
  49. // process's address space.
  50. //
  51. // CODEWORK: This macro should check the length
  52. // to make sure we don't overflow the LocalAddr
  53. // buffer. Perhaps this should be a function
  54. // rather than a macro.
  55. //
  56. #define GET_STRING(DebugeeAddr, LocalAddr, Length) \
  57. \
  58. { \
  59. WCHAR UnicodeChar; \
  60. LPWSTR pDest; \
  61. LPWSTR pSource; \
  62. pDest = LocalAddr; \
  63. pSource = DebugeeAddr; \
  64. do { \
  65. \
  66. Status = ReadProcessMemory( \
  67. GlobalhCurrentProcess, \
  68. (LPVOID)pSource, \
  69. &UnicodeChar, \
  70. sizeof(WCHAR), \
  71. NULL \
  72. ); \
  73. \
  74. *pDest = UnicodeChar; \
  75. pDest++; \
  76. pSource++; \
  77. } while (UnicodeChar != L'\0');}
  78. //=======================
  79. // Function Prototypes
  80. //=======================
  81. PNTSD_OUTPUT_ROUTINE lpOutputRoutine;
  82. PNTSD_GET_EXPRESSION lpGetExpressionRoutine;
  83. PNTSD_CHECK_CONTROL_C lpCheckControlCRoutine;
  84. VOID
  85. BackDepend(
  86. HANDLE hCurrentProcess,
  87. HANDLE hCurrentThread,
  88. DWORD dwCurrentPc,
  89. PNTSD_EXTENSION_APIS lpExtensionApis,
  90. LPSTR lpArgumentString
  91. );
  92. VOID
  93. DumpFwdDependentNames(
  94. LPSERVICE_RECORD pServiceRecord
  95. );
  96. VOID
  97. DumpBkwdDependentNames(
  98. LPSERVICE_RECORD pServiceRecord
  99. );
  100. LPIMAGE_RECORD
  101. DumpImageRecord(
  102. HANDLE hCurrentProcess,
  103. LPIMAGE_RECORD pImageRecord,
  104. LPDWORD NumBytes, // number of bytes in GroupRecord.
  105. BOOL JustSizeInfo
  106. );
  107. LPLOAD_ORDER_GROUP
  108. DumpGroupRecord(
  109. HANDLE hCurrentProcess,
  110. LPLOAD_ORDER_GROUP pGroupRecord,
  111. LPDWORD NumBytes, // number of bytes in GroupRecord.
  112. BOOL JustSizeInfo
  113. );
  114. LPSERVICE_RECORD
  115. DumpServiceRecord(
  116. HANDLE hCurrentProcess,
  117. LPSERVICE_RECORD pServiceRecord,
  118. LPDWORD NumBytes, // number of bytes in ServiceRecord.
  119. LPDWORD NumDependBytes, // number of bytes in DependRecords.
  120. BOOL JustSizeInfo
  121. );
  122. BOOL
  123. FindServiceRecordByName(
  124. LPSTR ServiceName,
  125. LPSERVICE_RECORD *pServiceRecord
  126. );
  127. VOID
  128. GetDependTreeSize(
  129. LPSERVICE_RECORD pServiceRecord,
  130. LPDWORD pNumDependStructs,
  131. LPDWORD pNumBytes,
  132. BOOL StartDepend
  133. );
  134. BOOL
  135. ConvertToUnicode(
  136. OUT LPWSTR *UnicodeOut,
  137. IN LPSTR AnsiIn
  138. );
  139. HANDLE GlobalhCurrentProcess;
  140. BOOL Status;
  141. //
  142. // Initialize the global function pointers
  143. //
  144. VOID
  145. InitFunctionPointers(
  146. HANDLE hCurrentProcess,
  147. PNTSD_EXTENSION_APIS lpExtensionApis
  148. )
  149. {
  150. //
  151. // Load these to speed access if we haven't already
  152. //
  153. if (!lpOutputRoutine) {
  154. lpOutputRoutine = lpExtensionApis->lpOutputRoutine;
  155. lpGetExpressionRoutine = lpExtensionApis->lpGetExpressionRoutine;
  156. lpCheckControlCRoutine = lpExtensionApis->lpCheckControlCRoutine;
  157. }
  158. //
  159. // Stick this in a global
  160. //
  161. GlobalhCurrentProcess = hCurrentProcess;
  162. }
  163. VOID
  164. ServiceRecord(
  165. HANDLE hCurrentProcess,
  166. HANDLE hCurrentThread,
  167. DWORD dwCurrentPc,
  168. PNTSD_EXTENSION_APIS lpExtensionApis,
  169. LPSTR lpArgumentString
  170. )
  171. /*++
  172. Routine Description:
  173. Dump Service Records.
  174. Arguments:
  175. hCurrentProcess - Handle for the process being debugged.
  176. hCurrentThread - Handle for the thread that has the debugger focus.
  177. dwCurrentPc - Current Program Counter?
  178. lpExtensionApis - Pointer to a structure that contains pointers to
  179. various routines. (see \nt\public\sdk\inc\ntsdexts.h)
  180. typedef struct _NTSD_EXTENSION_APIS {
  181. DWORD nSize;
  182. PNTSD_OUTPUT_ROUTINE lpOutputRoutine;
  183. PNTSD_GET_EXPRESSION lpGetExpressionRoutine;
  184. PNTSD_GET_SYMBOL lpGetSymbolRoutine;
  185. PNTSD_DISASM lpDisasmRoutine;
  186. PNTSD_CHECK_CONTROL_C lpCheckControlCRoutine;
  187. } NTSD_EXTENSION_APIS, *PNTSD_EXTENSION_APIS;
  188. lpArgumentString - This is a pointer to a string that contains
  189. space seperated arguments that are passed to debugger
  190. extension function.
  191. Return Value:
  192. none
  193. --*/
  194. {
  195. DWORD pDatabaseAnchor;
  196. SERVICE_RECORD ServiceRecord;
  197. LPSERVICE_RECORD pServiceRecord;
  198. DWORD numBytes=0;
  199. DWORD numDependBytes=0;
  200. DWORD numEntries=0;
  201. LPSTR pToken;
  202. InitFunctionPointers(hCurrentProcess, lpExtensionApis);
  203. printf("ArgumentString = %s\n\n",lpArgumentString);
  204. //
  205. // Get the address of the top of the Service Database.
  206. //
  207. pDatabaseAnchor = (lpGetExpressionRoutine)("ServiceDatabase");
  208. //
  209. // Get the first service record.
  210. // This is a dummy record that points to the first real record.
  211. //
  212. GET_DATA(pDatabaseAnchor, &ServiceRecord, sizeof(ServiceRecord))
  213. pServiceRecord = ServiceRecord.Next;
  214. if (_strnicmp(lpArgumentString, "mem", 3) == 0) {
  215. //--------------------------------------
  216. // Dump Memory Usage only.
  217. //--------------------------------------
  218. do {
  219. pServiceRecord = DumpServiceRecord(
  220. hCurrentProcess,
  221. pServiceRecord,
  222. &numBytes,
  223. &numDependBytes,
  224. TRUE);
  225. numEntries++;
  226. } while (pServiceRecord != NULL);
  227. printf("NumSRBytes = %d NumDependBytes = %d\n",numBytes,numDependBytes);
  228. printf("NumEntries = %d\n",numEntries);
  229. }
  230. else if (_strnicmp(lpArgumentString, "name=", 5) == 0) {
  231. //--------------------------------------
  232. // Find a particular Service Record
  233. // based on Name.
  234. //--------------------------------------
  235. pToken = strtok(lpArgumentString+6," ,\t\n");
  236. if (pToken == NULL) {
  237. printf("A Name was not given\n");
  238. return;
  239. }
  240. if (FindServiceRecordByName(pToken, &pServiceRecord)) {
  241. pServiceRecord = DumpServiceRecord(
  242. hCurrentProcess,
  243. pServiceRecord,
  244. &numBytes,
  245. &numDependBytes,
  246. FALSE);
  247. printf("NumSRBytes = %d NumDependBytes = %d\n",numBytes,numDependBytes);
  248. printf("NumEntries = %d\n",1);
  249. }
  250. else {
  251. printf("No service record found for \"%s\"\n", pToken);
  252. }
  253. }
  254. else if (_strnicmp(lpArgumentString, "address=", 8) == 0) {
  255. //--------------------------------------
  256. // Find a particular Service Record
  257. // based on Address.
  258. //--------------------------------------
  259. pToken = strtok(lpArgumentString+9," ,\t\n");
  260. if (pToken == NULL) {
  261. printf("An Address was not given\n");
  262. return;
  263. }
  264. else {
  265. LPSERVICE_RECORD ServiceAddress;
  266. LPSTR pMore;
  267. ServiceAddress = (LPSERVICE_RECORD)strtoul(pToken, &pMore, 16);
  268. printf("pToken = %s\n",pToken);
  269. printf("strtoul on Service Address yields %d(decimal) %x(hex)\n",
  270. ServiceAddress, ServiceAddress);
  271. pServiceRecord = DumpServiceRecord(
  272. hCurrentProcess,
  273. ServiceAddress,
  274. &numBytes,
  275. &numDependBytes,
  276. FALSE);
  277. printf("NumSRBytes = %d NumDependBytes = %d\n",numBytes,numDependBytes);
  278. printf("NumEntries = %d\n",1);
  279. }
  280. }
  281. else {
  282. //--------------------------------------
  283. // Dump All Service Records.
  284. //--------------------------------------
  285. do {
  286. pServiceRecord = DumpServiceRecord(
  287. hCurrentProcess,
  288. pServiceRecord,
  289. &numBytes,
  290. &numDependBytes,
  291. FALSE);
  292. numEntries++;
  293. } while (pServiceRecord != NULL);
  294. printf("NumSRBytes = %d NumDependBytes = %d\n",numBytes,numDependBytes);
  295. printf("NumEntries = %d\n",numEntries);
  296. }
  297. return;
  298. }
  299. VOID
  300. Dependencies(
  301. HANDLE hCurrentProcess,
  302. HANDLE hCurrentThread,
  303. DWORD dwCurrentPc,
  304. PNTSD_EXTENSION_APIS lpExtensionApis,
  305. LPSTR lpArgumentString
  306. )
  307. /*++
  308. Routine Description:
  309. Dump Service Record Dependencies.
  310. Arguments:
  311. hCurrentProcess - Handle for the process being debugged.
  312. hCurrentThread - Handle for the thread that has the debugger focus.
  313. dwCurrentPc - Current Program Counter?
  314. lpExtensionApis - Pointer to a structure that contains pointers to
  315. various routines. (see \nt\public\sdk\inc\ntsdexts.h)
  316. typedef struct _NTSD_EXTENSION_APIS {
  317. DWORD nSize;
  318. PNTSD_OUTPUT_ROUTINE lpOutputRoutine;
  319. PNTSD_GET_EXPRESSION lpGetExpressionRoutine;
  320. PNTSD_GET_SYMBOL lpGetSymbolRoutine;
  321. PNTSD_DISASM lpDisasmRoutine;
  322. PNTSD_CHECK_CONTROL_C lpCheckControlCRoutine;
  323. } NTSD_EXTENSION_APIS, *PNTSD_EXTENSION_APIS;
  324. lpArgumentString - This is a pointer to a string that contains
  325. space seperated arguments that are passed to debugger
  326. extension function.
  327. Return Value:
  328. none
  329. --*/
  330. {
  331. DWORD pDatabaseAnchor;
  332. SERVICE_RECORD ServiceRecord;
  333. LPSERVICE_RECORD pServiceRecord;
  334. DWORD numBytes=0;
  335. DWORD numEntries=0;
  336. LPSTR pToken;
  337. InitFunctionPointers(hCurrentProcess, lpExtensionApis);
  338. printf("ArgumentString = %s\n\n",lpArgumentString);
  339. //
  340. // Get the address of the top of the Service Database.
  341. //
  342. pDatabaseAnchor = (lpGetExpressionRoutine)("ServiceDatabase");
  343. //
  344. // Get the first service record.
  345. // This is a dummy record that points to the first real record.
  346. //
  347. GET_DATA(pDatabaseAnchor, &ServiceRecord, sizeof(ServiceRecord))
  348. pServiceRecord = ServiceRecord.Next;
  349. if (_strnicmp(lpArgumentString, "name=", 5) == 0) {
  350. //--------------------------------------
  351. // Find a particular Service Record
  352. // based on Name.
  353. //--------------------------------------
  354. pToken = strtok(lpArgumentString+6," ,\t\n");
  355. if (pToken == NULL) {
  356. printf("A Name was not given\n");
  357. return;
  358. }
  359. if (FindServiceRecordByName(pToken, &pServiceRecord)) {
  360. DumpFwdDependentNames(pServiceRecord);
  361. }
  362. }
  363. else if (_strnicmp(lpArgumentString, "address=", 8) == 0) {
  364. //--------------------------------------
  365. // Find a particular Service Record
  366. // based on Address.
  367. //--------------------------------------
  368. pToken = strtok(lpArgumentString+9," ,\t\n");
  369. if (pToken == NULL) {
  370. printf("An Address was not given\n");
  371. return;
  372. }
  373. else {
  374. LPSERVICE_RECORD ServiceAddress;
  375. LPSTR pMore;
  376. ServiceAddress = (LPSERVICE_RECORD)strtoul(pToken, &pMore, 16);
  377. printf("pToken = %s\n",pToken);
  378. printf("strtoul on Service Address yields %d(decimal) %x(hex)\n",
  379. ServiceAddress, ServiceAddress);
  380. DumpFwdDependentNames(ServiceAddress);
  381. }
  382. }
  383. return;
  384. }
  385. VOID
  386. BackDepend(
  387. HANDLE hCurrentProcess,
  388. HANDLE hCurrentThread,
  389. DWORD dwCurrentPc,
  390. PNTSD_EXTENSION_APIS lpExtensionApis,
  391. LPSTR lpArgumentString
  392. )
  393. /*++
  394. Routine Description:
  395. Dump Service Record Dependencies.
  396. Arguments:
  397. hCurrentProcess - Handle for the process being debugged.
  398. hCurrentThread - Handle for the thread that has the debugger focus.
  399. dwCurrentPc - Current Program Counter?
  400. lpExtensionApis - Pointer to a structure that contains pointers to
  401. various routines. (see \nt\public\sdk\inc\ntsdexts.h)
  402. typedef struct _NTSD_EXTENSION_APIS {
  403. DWORD nSize;
  404. PNTSD_OUTPUT_ROUTINE lpOutputRoutine;
  405. PNTSD_GET_EXPRESSION lpGetExpressionRoutine;
  406. PNTSD_GET_SYMBOL lpGetSymbolRoutine;
  407. PNTSD_DISASM lpDisasmRoutine;
  408. PNTSD_CHECK_CONTROL_C lpCheckControlCRoutine;
  409. } NTSD_EXTENSION_APIS, *PNTSD_EXTENSION_APIS;
  410. lpArgumentString - This is a pointer to a string that contains
  411. space seperated arguments that are passed to debugger
  412. extension function.
  413. Return Value:
  414. none
  415. --*/
  416. {
  417. DWORD pDatabaseAnchor;
  418. SERVICE_RECORD ServiceRecord;
  419. LPSERVICE_RECORD pServiceRecord;
  420. DWORD numBytes=0;
  421. DWORD numEntries=0;
  422. LPSTR pToken;
  423. InitFunctionPointers(hCurrentProcess, lpExtensionApis);
  424. printf("ArgumentString = %s\n\n",lpArgumentString);
  425. //
  426. // Get the address of the top of the Service Database.
  427. //
  428. pDatabaseAnchor = (lpGetExpressionRoutine)("ServiceDatabase");
  429. //
  430. // Get the first service record.
  431. // This is a dummy record that points to the first real record.
  432. //
  433. GET_DATA(pDatabaseAnchor, &ServiceRecord, sizeof(ServiceRecord))
  434. pServiceRecord = ServiceRecord.Next;
  435. if (_strnicmp(lpArgumentString, "name=", 5) == 0) {
  436. //--------------------------------------
  437. // Find a particular Service Record
  438. // based on Name.
  439. //--------------------------------------
  440. pToken = strtok(lpArgumentString+6," ,\t\n");
  441. if (pToken == NULL) {
  442. printf("A Name was not given\n");
  443. return;
  444. }
  445. if (FindServiceRecordByName(pToken, &pServiceRecord)) {
  446. printf("Backwards dependencies:\n");
  447. DumpBkwdDependentNames(pServiceRecord);
  448. }
  449. }
  450. else if (_strnicmp(lpArgumentString, "address=", 8) == 0) {
  451. //--------------------------------------
  452. // Find a particular Service Record
  453. // based on Address.
  454. //--------------------------------------
  455. pToken = strtok(lpArgumentString+9," ,\t\n");
  456. if (pToken == NULL) {
  457. printf("An Address was not given\n");
  458. return;
  459. }
  460. else {
  461. LPSERVICE_RECORD ServiceAddress;
  462. LPSTR pMore;
  463. ServiceAddress = (LPSERVICE_RECORD)strtoul(pToken, &pMore, 16);
  464. printf("pToken = %s\n",pToken);
  465. printf("strtoul on Service Address yields %d(decimal) %x(hex)\n",
  466. ServiceAddress, ServiceAddress);
  467. DumpBkwdDependentNames(ServiceAddress);
  468. }
  469. }
  470. return;
  471. }
  472. VOID
  473. ImageRecord(
  474. HANDLE hCurrentProcess,
  475. HANDLE hCurrentThread,
  476. DWORD dwCurrentPc,
  477. PNTSD_EXTENSION_APIS lpExtensionApis,
  478. LPSTR lpArgumentString
  479. )
  480. /*++
  481. Routine Description:
  482. Dump ImageRecords.
  483. Arguments:
  484. hCurrentProcess - Handle for the process being debugged.
  485. hCurrentThread - Handle for the thread that has the debugger focus.
  486. dwCurrentPc - Current Program Counter?
  487. lpExtensionApis - Pointer to a structure that contains pointers to
  488. various routines. (see \nt\public\sdk\inc\ntsdexts.h)
  489. typedef struct _NTSD_EXTENSION_APIS {
  490. DWORD nSize;
  491. PNTSD_OUTPUT_ROUTINE lpOutputRoutine;
  492. PNTSD_GET_EXPRESSION lpGetExpressionRoutine;
  493. PNTSD_GET_SYMBOL lpGetSymbolRoutine;
  494. PNTSD_DISASM lpDisasmRoutine;
  495. PNTSD_CHECK_CONTROL_C lpCheckControlCRoutine;
  496. } NTSD_EXTENSION_APIS, *PNTSD_EXTENSION_APIS;
  497. lpArgumentString - This is a pointer to a string that contains
  498. space seperated arguments that are passed to debugger
  499. extension function.
  500. Return Value:
  501. none
  502. --*/
  503. {
  504. DWORD pDatabaseAnchor;
  505. IMAGE_RECORD ImageRecord;
  506. LPIMAGE_RECORD pImageRecord;
  507. DWORD numBytes=0;
  508. DWORD numEntries=0;
  509. InitFunctionPointers(hCurrentProcess, lpExtensionApis);
  510. printf("ArgumentString = %s\n\n",lpArgumentString);
  511. //
  512. // Get the address of the top of the Service Database.
  513. //
  514. pDatabaseAnchor = (lpGetExpressionRoutine)("ImageDatabase");
  515. //
  516. // Get the first service record.
  517. // This is a dummy record that points to the first real record.
  518. //
  519. GET_DATA(pDatabaseAnchor, &ImageRecord, sizeof(ImageRecord))
  520. pImageRecord = ImageRecord.Next;
  521. if (_strnicmp(lpArgumentString, "mem", 3) == 0) {
  522. //--------------------------------------
  523. // Dump Memory Usage only.
  524. //--------------------------------------
  525. do {
  526. pImageRecord = DumpImageRecord(
  527. hCurrentProcess,
  528. pImageRecord,
  529. &numBytes,
  530. TRUE);
  531. numEntries++;
  532. } while (pImageRecord != NULL);
  533. printf("NumIRBytes = %d\n",numBytes);
  534. printf("NumEntries = %d\n",numEntries);
  535. }
  536. else if (_strnicmp(lpArgumentString, "name=", 5) == 0) {
  537. }
  538. else {
  539. //--------------------------------------
  540. // Dump All Image Records.
  541. //--------------------------------------
  542. do {
  543. pImageRecord = DumpImageRecord(
  544. hCurrentProcess,
  545. pImageRecord,
  546. &numBytes,
  547. FALSE);
  548. numEntries++;
  549. } while (pImageRecord != NULL);
  550. printf("NumIRBytes = %d\n",numBytes);
  551. printf("NumEntries = %d\n",numEntries);
  552. }
  553. return;
  554. }
  555. VOID
  556. GroupRecord(
  557. HANDLE hCurrentProcess,
  558. HANDLE hCurrentThread,
  559. DWORD dwCurrentPc,
  560. PNTSD_EXTENSION_APIS lpExtensionApis,
  561. LPSTR lpArgumentString
  562. )
  563. /*++
  564. Routine Description:
  565. Dump GroupRecords.
  566. Arguments:
  567. hCurrentProcess - Handle for the process being debugged.
  568. hCurrentThread - Handle for the thread that has the debugger focus.
  569. dwCurrentPc - Current Program Counter?
  570. lpExtensionApis - Pointer to a structure that contains pointers to
  571. various routines. (see \nt\public\sdk\inc\ntsdexts.h)
  572. typedef struct _NTSD_EXTENSION_APIS {
  573. DWORD nSize;
  574. PNTSD_OUTPUT_ROUTINE lpOutputRoutine;
  575. PNTSD_GET_EXPRESSION lpGetExpressionRoutine;
  576. PNTSD_GET_SYMBOL lpGetSymbolRoutine;
  577. PNTSD_DISASM lpDisasmRoutine;
  578. PNTSD_CHECK_CONTROL_C lpCheckControlCRoutine;
  579. } NTSD_EXTENSION_APIS, *PNTSD_EXTENSION_APIS;
  580. lpArgumentString - This is a pointer to a string that contains
  581. space seperated arguments that are passed to debugger
  582. extension function.
  583. Return Value:
  584. none
  585. --*/
  586. {
  587. DWORD pDatabaseAnchor;
  588. DWORD pStandaloneAnchor;
  589. LOAD_ORDER_GROUP StandaloneGroupRecord;
  590. LOAD_ORDER_GROUP GroupRecord;
  591. LPLOAD_ORDER_GROUP pStandaloneGroupRecord;
  592. LPLOAD_ORDER_GROUP pGroupRecord;
  593. DWORD numBytes=0;
  594. DWORD numEntries=0;
  595. InitFunctionPointers(hCurrentProcess, lpExtensionApis);
  596. printf("ArgumentString = %s\n\n",lpArgumentString);
  597. //
  598. // Get the address of the top of the Service Database.
  599. //
  600. pDatabaseAnchor = (lpGetExpressionRoutine)("OrderGroupList");
  601. pStandaloneAnchor = (lpGetExpressionRoutine)("StandaloneGroupList");
  602. //
  603. // Get the first service record.
  604. // This is a dummy record that points to the first real record.
  605. //
  606. GET_DATA(pDatabaseAnchor, &GroupRecord, sizeof(GroupRecord))
  607. pGroupRecord = GroupRecord.Next;
  608. GET_DATA(pStandaloneAnchor, &StandaloneGroupRecord, sizeof(GroupRecord))
  609. pStandaloneGroupRecord = StandaloneGroupRecord.Next;
  610. if (_strnicmp(lpArgumentString, "mem", 3) == 0) {
  611. //--------------------------------------
  612. // Dump Memory Usage only.
  613. //--------------------------------------
  614. printf("ORDER GROUP LIST:\n");
  615. do {
  616. pGroupRecord = DumpGroupRecord(
  617. hCurrentProcess,
  618. pGroupRecord,
  619. &numBytes,
  620. TRUE);
  621. numEntries++;
  622. } while (pGroupRecord != NULL);
  623. printf("STANDALONE GROUP LIST:\n");
  624. pGroupRecord = pStandaloneGroupRecord;
  625. do {
  626. pGroupRecord = DumpGroupRecord(
  627. hCurrentProcess,
  628. pGroupRecord,
  629. &numBytes,
  630. TRUE);
  631. numEntries++;
  632. } while (pGroupRecord != NULL);
  633. printf("NumGRBytes = %d\n",numBytes);
  634. printf("NumEntries = %d\n",numEntries);
  635. }
  636. else if (_strnicmp(lpArgumentString, "name=", 5) == 0) {
  637. }
  638. else {
  639. //--------------------------------------
  640. // Dump All Group Records.
  641. //--------------------------------------
  642. printf("ORDER GROUP LIST:\n");
  643. do {
  644. pGroupRecord = DumpGroupRecord(
  645. hCurrentProcess,
  646. pGroupRecord,
  647. &numBytes,
  648. FALSE);
  649. numEntries++;
  650. } while (pGroupRecord != NULL);
  651. printf("STANDALONE GROUP LIST:\n");
  652. pGroupRecord = pStandaloneGroupRecord;
  653. do {
  654. pGroupRecord = DumpGroupRecord(
  655. hCurrentProcess,
  656. pGroupRecord,
  657. &numBytes,
  658. FALSE);
  659. numEntries++;
  660. } while (pGroupRecord != NULL);
  661. printf("NumGRBytes = %d\n",numBytes);
  662. printf("NumEntries = %d\n",numEntries);
  663. }
  664. return;
  665. }
  666. BOOL
  667. FindServiceRecordByName(
  668. LPSTR ServiceName,
  669. LPSERVICE_RECORD *pServiceRecord
  670. )
  671. /*++
  672. Routine Description:
  673. Arguments:
  674. ServiceName - This is the name of the service that we are looking for.
  675. pServiceRecord - A pointer to a location to where the pointer to the
  676. service record is to be placed.
  677. Return Value:
  678. TRUE - Success
  679. FALSE - The name couldn't be found in any of the service records.
  680. --*/
  681. {
  682. SERVICE_RECORD ServiceRecord;
  683. WCHAR StringBuffer[200];
  684. LPWSTR uniNameString;
  685. if (!ConvertToUnicode(&uniNameString,ServiceName)) {
  686. printf("Could not convert to unicode\n");
  687. return(FALSE);
  688. }
  689. //
  690. // Find a Service Record that matches the name in the uniNameString.
  691. //
  692. do {
  693. //
  694. // Map the memory for the service record into our process.
  695. //
  696. GET_DATA(*pServiceRecord, &ServiceRecord, sizeof(ServiceRecord))
  697. //
  698. // Get the ServiceName String.
  699. //
  700. GET_STRING(ServiceRecord.ServiceName, StringBuffer, sizeof(StringBuffer))
  701. if (_wcsicmp(StringBuffer, uniNameString) == 0) {
  702. //
  703. // If a name match was found, return SUCCESS.
  704. //
  705. LocalFree(uniNameString);
  706. return(TRUE);
  707. }
  708. *pServiceRecord = ServiceRecord.Next;
  709. } while (*pServiceRecord != NULL);
  710. LocalFree(uniNameString);
  711. return(FALSE);
  712. }
  713. BOOL
  714. ConvertToUnicode(
  715. OUT LPWSTR *UnicodeOut,
  716. IN LPSTR AnsiIn
  717. )
  718. /*++
  719. Routine Description:
  720. This function translates an AnsiString into a Unicode string.
  721. A new string buffer is created by this function. If the call to
  722. this function is successful, the caller must take responsibility for
  723. the unicode string buffer that was allocated by this function.
  724. The allocated buffer should be free'd with a call to LocalFree.
  725. NOTE: This function allocates memory for the Unicode String.
  726. Arguments:
  727. AnsiIn - This is a pointer to an ansi string that is to be converted.
  728. UnicodeOut - This is a pointer to a location where the pointer to the
  729. unicode string is to be placed.
  730. Return Value:
  731. TRUE - The conversion was successful.
  732. FALSE - The conversion was unsuccessful. In this case a buffer for
  733. the unicode string was not allocated.
  734. --*/
  735. {
  736. NTSTATUS ntStatus;
  737. DWORD bufSize;
  738. UNICODE_STRING unicodeString;
  739. ANSI_STRING ansiString;
  740. //
  741. // Allocate a buffer for the unicode string.
  742. //
  743. bufSize = (strlen(AnsiIn)+1) * sizeof(WCHAR);
  744. *UnicodeOut = (LPWSTR)LocalAlloc(LMEM_ZEROINIT, (UINT)bufSize);
  745. if (*UnicodeOut == NULL) {
  746. printf("ScConvertToUnicode:LocalAlloc Failure %ld\n",GetLastError());
  747. return(FALSE);
  748. }
  749. //
  750. // Initialize the string structures
  751. //
  752. RtlInitAnsiString( &ansiString, AnsiIn);
  753. unicodeString.Buffer = *UnicodeOut;
  754. unicodeString.MaximumLength = (USHORT)bufSize;
  755. unicodeString.Length = 0;
  756. //
  757. // Call the conversion function.
  758. //
  759. ntStatus = RtlAnsiStringToUnicodeString (
  760. &unicodeString, // Destination
  761. &ansiString, // Source
  762. (BOOLEAN)FALSE); // Allocate the destination
  763. if (!NT_SUCCESS(ntStatus)) {
  764. printf("ScConvertToUnicode:RtlAnsiStringToUnicodeString Failure %lx\n",
  765. ntStatus);
  766. return(FALSE);
  767. }
  768. //
  769. // Fill in the pointer location with the unicode string buffer pointer.
  770. //
  771. *UnicodeOut = unicodeString.Buffer;
  772. return(TRUE);
  773. }
  774. LPSERVICE_RECORD
  775. DumpServiceRecord(
  776. HANDLE hCurrentProcess,
  777. LPSERVICE_RECORD pServiceRecord,
  778. LPDWORD NumBytes, // number of bytes in ServiceRecord.
  779. LPDWORD NumDependBytes, // number of bytes in DependRecords.
  780. BOOL JustSizeInfo
  781. )
  782. /*++
  783. Routine Description:
  784. Arguments:
  785. Return Value:
  786. --*/
  787. {
  788. SERVICE_RECORD ServiceRecord;
  789. WCHAR StringBuffer[200];
  790. DWORD NameStringSize;
  791. DWORD EntrySize=0;
  792. DWORD DependEntrySize=0;
  793. DWORD numDependStructs=0;
  794. //------------------------------------------
  795. // Dump Size information only.
  796. //------------------------------------------
  797. if (JustSizeInfo) {
  798. EntrySize += sizeof(SERVICE_RECORD);
  799. GET_DATA(pServiceRecord, &ServiceRecord, sizeof(ServiceRecord))
  800. GET_STRING(ServiceRecord.ServiceName, StringBuffer, sizeof(StringBuffer))
  801. NameStringSize = WCSSIZE(StringBuffer);
  802. EntrySize += NameStringSize;
  803. printf("\t\t\t\tAddress = 0x%lx\r%ws\n",pServiceRecord,StringBuffer);
  804. #ifdef remove
  805. if (NameStringSize < 22) {
  806. printf("\t");
  807. }
  808. #endif
  809. GET_STRING(ServiceRecord.DisplayName, StringBuffer, sizeof(StringBuffer))
  810. if (ServiceRecord.DisplayName != ServiceRecord.DisplayName) {
  811. EntrySize += WCSSIZE(StringBuffer);
  812. }
  813. if (ServiceRecord.Dependencies != NULL) {
  814. GET_STRING(ServiceRecord.Dependencies, StringBuffer, sizeof(StringBuffer))
  815. EntrySize += WCSSIZE(StringBuffer);
  816. }
  817. GetDependTreeSize(&ServiceRecord,&numDependStructs, &DependEntrySize, TRUE);
  818. GetDependTreeSize(&ServiceRecord,&numDependStructs, &DependEntrySize, FALSE);
  819. *NumBytes += EntrySize;
  820. printf(" SRBytes=%d DependBytes=%d TotalBytes=%d\n",
  821. EntrySize,
  822. DependEntrySize,
  823. *NumBytes);
  824. *NumDependBytes += DependEntrySize;
  825. return (ServiceRecord.Next);
  826. }
  827. //------------------------------------------
  828. // Dump other information.
  829. //------------------------------------------
  830. *NumBytes += sizeof(SERVICE_RECORD);
  831. //
  832. // Map the memory for the service record into our process.
  833. //
  834. GET_DATA(pServiceRecord, &ServiceRecord, sizeof(ServiceRecord))
  835. //
  836. // Get the ServiceName and DisplayName Strings.
  837. //
  838. GET_STRING(ServiceRecord.ServiceName, StringBuffer, sizeof(StringBuffer))
  839. NameStringSize = WCSSIZE(StringBuffer);
  840. *NumBytes += NameStringSize;
  841. printf("ServiceName : %ws (0x%lx)\n",StringBuffer,pServiceRecord);
  842. GET_STRING(ServiceRecord.DisplayName, StringBuffer, sizeof(StringBuffer))
  843. if (ServiceRecord.DisplayName != ServiceRecord.DisplayName) {
  844. *NumBytes += WCSSIZE(StringBuffer);
  845. }
  846. printf("DisplayName : %ws\n",StringBuffer);
  847. printf("ResumeNum : %d\t\t", ServiceRecord.ResumeNum);
  848. printf("ServerAnnounce : %d\n", ServiceRecord.ServerAnnounce);
  849. printf("Signature : 0x%lx\t", ServiceRecord.Signature);
  850. printf("UseCount : %d\n", ServiceRecord.UseCount);
  851. printf("StatusFlag : %d\t\t",ServiceRecord.StatusFlag);
  852. printf("pImageRecord : 0x%lx\n",ServiceRecord.ImageRecord);
  853. printf(" **** STATUS **** \n"
  854. " dwServiceType : 0x%lx\t",ServiceRecord.ServiceStatus.dwServiceType);
  855. printf("dwCurrentState : 0x%lx\n",ServiceRecord.ServiceStatus.dwCurrentState);
  856. printf(" dwControlsAccepted : 0x%lx\t",ServiceRecord.ServiceStatus.dwControlsAccepted);
  857. printf("dwWin32ExitCode : 0x%lx\n",ServiceRecord.ServiceStatus.dwWin32ExitCode);
  858. printf(" dwSpecificExitCode : 0x%lx\t",ServiceRecord.ServiceStatus.dwServiceSpecificExitCode);
  859. printf("dwCheckPoint : 0x%lx\n",ServiceRecord.ServiceStatus.dwCheckPoint);
  860. printf(" dwWaitHint : 0x%lx\n",ServiceRecord.ServiceStatus.dwWaitHint);
  861. printf("StartType : %d\t\t",ServiceRecord.StartType);
  862. printf("ErrorControl : %d\n",ServiceRecord.ErrorControl);
  863. printf("Tag : 0x%x\t\t",ServiceRecord.Tag);
  864. printf("StartDepend : 0x%lx\n",ServiceRecord.StartDepend);
  865. if (ServiceRecord.StopDepend > (LPDEPEND_RECORD)10) {
  866. printf("StopDepend : 0x%lx\t",ServiceRecord.StopDepend);
  867. }
  868. else {
  869. printf("StopDepend : 0x%lx\t\t",ServiceRecord.StopDepend);
  870. }
  871. if (ServiceRecord.Dependencies != NULL) {
  872. GET_STRING(ServiceRecord.Dependencies, StringBuffer, sizeof(StringBuffer))
  873. *NumBytes += WCSSIZE(StringBuffer);
  874. printf("Dependencies : %ws\n",StringBuffer);
  875. }
  876. else {
  877. printf("Dependencies : (none)\n");
  878. }
  879. printf("pServiceSd : 0x%lx\t",ServiceRecord.ServiceSd);
  880. printf("StartError : %d\n",ServiceRecord.StartError);
  881. printf("StartState : 0x%lx\t\t",ServiceRecord.StartState);
  882. printf("pMemberOfGroup : 0x%lx\n",ServiceRecord.MemberOfGroup);
  883. printf("pRegistryGroup : 0x%lx\n",ServiceRecord.RegistryGroup);
  884. printf("pCrashRecord : 0x%lx\n\n",ServiceRecord.CrashRecord);
  885. GetDependTreeSize(&ServiceRecord,&numDependStructs, NumBytes, TRUE);
  886. GetDependTreeSize(&ServiceRecord,&numDependStructs, NumBytes, FALSE);
  887. return (ServiceRecord.Next);
  888. }
  889. LPIMAGE_RECORD
  890. DumpImageRecord(
  891. HANDLE hCurrentProcess,
  892. LPIMAGE_RECORD pImageRecord,
  893. LPDWORD NumBytes, // number of bytes in ImageRecord.
  894. BOOL JustSizeInfo
  895. )
  896. /*++
  897. Routine Description:
  898. Arguments:
  899. Return Value:
  900. --*/
  901. {
  902. IMAGE_RECORD ImageRecord;
  903. WCHAR StringBuffer[200];
  904. DWORD NameStringSize;
  905. DWORD EntrySize=0;
  906. DWORD DependEntrySize=0;
  907. DWORD numDependStructs=0;
  908. //------------------------------------------
  909. // Dump Size information only.
  910. //------------------------------------------
  911. if (JustSizeInfo) {
  912. EntrySize += sizeof(IMAGE_RECORD);
  913. GET_DATA(pImageRecord, &ImageRecord, sizeof(ImageRecord))
  914. GET_STRING(ImageRecord.ImageName, StringBuffer, sizeof(StringBuffer))
  915. NameStringSize = WCSSIZE(StringBuffer);
  916. EntrySize += NameStringSize;
  917. printf("%ws \tAddress = 0x%lx\n",StringBuffer,pImageRecord);
  918. #ifdef remove
  919. if (NameStringSize < 22) {
  920. printf("\t");
  921. }
  922. #endif
  923. *NumBytes += EntrySize;
  924. printf(" IRBytes=%d TotalBytes=%d\n",EntrySize,*NumBytes);
  925. return (ImageRecord.Next);
  926. }
  927. //------------------------------------------
  928. // Dump other information.
  929. //------------------------------------------
  930. *NumBytes += sizeof(IMAGE_RECORD);
  931. //
  932. // Map the memory for the service record into our process.
  933. //
  934. GET_DATA(pImageRecord, &ImageRecord, sizeof(ImageRecord))
  935. //
  936. // Get the ImageName and DisplayName Strings.
  937. //
  938. GET_STRING(ImageRecord.ImageName, StringBuffer, sizeof(StringBuffer))
  939. NameStringSize = WCSSIZE(StringBuffer);
  940. *NumBytes += NameStringSize;
  941. printf("ImageName : %ws (0x%lx)\n",StringBuffer,pImageRecord);
  942. printf(" Pid : %d\t\t", ImageRecord.Pid);
  943. printf("ServiceCount : %d\n", ImageRecord.ServiceCount);
  944. printf(" PipeHandle : 0x%lx\t", ImageRecord.PipeHandle);
  945. printf("ProcessHandle : 0x%lx\n", ImageRecord.ProcessHandle);
  946. printf(" StatusFlag : 0x%lx\n",ImageRecord.TokenHandle);
  947. return (ImageRecord.Next);
  948. }
  949. LPLOAD_ORDER_GROUP
  950. DumpGroupRecord(
  951. HANDLE hCurrentProcess,
  952. LPLOAD_ORDER_GROUP pGroupRecord,
  953. LPDWORD NumBytes, // number of bytes in GroupRecord.
  954. BOOL JustSizeInfo
  955. )
  956. /*++
  957. Routine Description:
  958. Arguments:
  959. Return Value:
  960. --*/
  961. {
  962. LOAD_ORDER_GROUP GroupRecord;
  963. WCHAR StringBuffer[200];
  964. DWORD NameStringSize;
  965. DWORD EntrySize=0;
  966. DWORD DependEntrySize=0;
  967. DWORD numDependStructs=0;
  968. //------------------------------------------
  969. // Dump Size information only.
  970. //------------------------------------------
  971. if (JustSizeInfo) {
  972. EntrySize += sizeof(LOAD_ORDER_GROUP);
  973. GET_DATA(pGroupRecord, &GroupRecord, sizeof(GroupRecord))
  974. GET_STRING(GroupRecord.GroupName, StringBuffer, sizeof(StringBuffer))
  975. NameStringSize = WCSSIZE(StringBuffer);
  976. EntrySize += NameStringSize;
  977. printf("\t\t\t\tAddress = 0x%lx\r%ws\n",pGroupRecord,StringBuffer);
  978. *NumBytes += EntrySize;
  979. printf(" GRBytes=%d TotalBytes=%d\n",EntrySize,*NumBytes);
  980. return (GroupRecord.Next);
  981. }
  982. //------------------------------------------
  983. // Dump other information.
  984. //------------------------------------------
  985. *NumBytes += sizeof(LOAD_ORDER_GROUP);
  986. //
  987. // Map the memory for the service record into our process.
  988. //
  989. GET_DATA(pGroupRecord, &GroupRecord, sizeof(GroupRecord))
  990. //
  991. // Get the GroupName and DisplayName Strings.
  992. //
  993. GET_STRING(GroupRecord.GroupName, StringBuffer, sizeof(StringBuffer))
  994. NameStringSize = WCSSIZE(StringBuffer);
  995. *NumBytes += NameStringSize;
  996. printf("GroupName : %ws (0x%lx)\n",StringBuffer,pGroupRecord);
  997. printf(" RefCount : %d\n", GroupRecord.RefCount);
  998. return (GroupRecord.Next);
  999. }
  1000. VOID
  1001. GetDependTreeSize(
  1002. LPSERVICE_RECORD pServiceRecord,
  1003. LPDWORD pNumDependStructs,
  1004. LPDWORD pNumBytes,
  1005. BOOL StartDepend
  1006. )
  1007. /*++
  1008. Routine Description:
  1009. pServiceRecord - This is a pointer to a ServiceRecord that is already
  1010. mapped into our address space.
  1011. pNumDependStructs -
  1012. pNumBytes -
  1013. StartDepend - TRUE indicates to look through StartDepend list.
  1014. FALSE indicates to look through StopDepend list.
  1015. Arguments:
  1016. Return Value:
  1017. --*/
  1018. {
  1019. DEPEND_RECORD DependRecord;
  1020. BOOL MoreRecords=TRUE;
  1021. if (StartDepend) {
  1022. if (pServiceRecord->StartDepend == NULL) {
  1023. return;
  1024. }
  1025. printf(" StartDependRecordAddress = 0x%x\n",pServiceRecord->StartDepend);
  1026. GET_DATA(pServiceRecord->StartDepend, &DependRecord, sizeof(DependRecord))
  1027. }
  1028. else {
  1029. if (pServiceRecord->StopDepend == NULL) {
  1030. return;
  1031. }
  1032. printf(" StopDependRecordAddress = 0x%x\n",pServiceRecord->StopDepend);
  1033. GET_DATA(pServiceRecord->StopDepend, &DependRecord, sizeof(DependRecord))
  1034. }
  1035. if (pServiceRecord->StartDepend != NULL) {
  1036. do {
  1037. *pNumBytes += sizeof(DependRecord);
  1038. (*pNumDependStructs)++;
  1039. if (DependRecord.Next != NULL) {
  1040. printf(" DependRecordAddress = 0x%x\n",DependRecord.Next);
  1041. GET_DATA(DependRecord.Next, &DependRecord, sizeof(DependRecord))
  1042. }
  1043. else {
  1044. MoreRecords = FALSE;
  1045. }
  1046. } while ((MoreRecords) && (*pNumDependStructs < 50));
  1047. }
  1048. }
  1049. VOID
  1050. DumpFwdDependentNames(
  1051. LPSERVICE_RECORD pServiceRecord
  1052. )
  1053. /*++
  1054. Routine Description:
  1055. Arguments:
  1056. Return Value:
  1057. --*/
  1058. {
  1059. SERVICE_RECORD ServiceRecord;
  1060. DEPEND_RECORD DependRecord;
  1061. LOAD_ORDER_GROUP GroupRecord;
  1062. UNRESOLVED_DEPEND UnresolvedRecord;
  1063. WCHAR StringBuffer[200];
  1064. static CHAR LeadingSpaces[80]="";
  1065. BOOL MoreRecords=TRUE;
  1066. //
  1067. // Map the memory for the service record into our process.
  1068. //
  1069. GET_DATA(pServiceRecord, &ServiceRecord, sizeof(ServiceRecord))
  1070. //
  1071. // Get the ServiceName String.
  1072. //
  1073. GET_STRING(ServiceRecord.ServiceName, StringBuffer, sizeof(StringBuffer))
  1074. printf("%s%ws (service) depends on: \t\n",LeadingSpaces,StringBuffer);
  1075. strcat(LeadingSpaces," ");
  1076. if (ServiceRecord.StartDepend != NULL) {
  1077. GET_DATA(ServiceRecord.StartDepend, &DependRecord, sizeof(DependRecord))
  1078. do {
  1079. switch (DependRecord.DependType) {
  1080. case TypeDependOnService:
  1081. DumpFwdDependentNames(DependRecord.DependService);
  1082. break;
  1083. case TypeDependOnGroup:
  1084. GET_DATA(DependRecord.DependGroup, &GroupRecord, sizeof(GroupRecord))
  1085. GET_STRING(GroupRecord.GroupName, StringBuffer, sizeof(StringBuffer))
  1086. printf("%s%ws (group)\n", LeadingSpaces,StringBuffer);
  1087. break;
  1088. case TypeDependOnUnresolved:
  1089. GET_DATA(DependRecord.DependUnresolved, &UnresolvedRecord, sizeof(UnresolvedRecord))
  1090. GET_STRING(UnresolvedRecord.Name, StringBuffer, sizeof(StringBuffer))
  1091. printf("%s%ws (unresolved)\n", LeadingSpaces,StringBuffer);
  1092. break;
  1093. default:
  1094. printf("%s(Unknown Depend Type)\n",LeadingSpaces);
  1095. MoreRecords = FALSE;
  1096. break;
  1097. }
  1098. if (DependRecord.Next != NULL) {
  1099. GET_DATA(DependRecord.Next, &DependRecord, sizeof(DependRecord))
  1100. }
  1101. else {
  1102. MoreRecords = FALSE;
  1103. }
  1104. } while (MoreRecords);
  1105. }
  1106. else {
  1107. printf("%s(nothing)\n",LeadingSpaces);
  1108. }
  1109. LeadingSpaces[strlen(LeadingSpaces)-2] = '\0';
  1110. }
  1111. VOID
  1112. DumpBkwdDependentNames(
  1113. LPSERVICE_RECORD pServiceRecord
  1114. )
  1115. /*++
  1116. Routine Description:
  1117. Arguments:
  1118. Return Value:
  1119. --*/
  1120. {
  1121. SERVICE_RECORD ServiceRecord;
  1122. DEPEND_RECORD DependRecord;
  1123. LOAD_ORDER_GROUP GroupRecord;
  1124. UNRESOLVED_DEPEND UnresolvedRecord;
  1125. WCHAR StringBuffer[200];
  1126. static CHAR LeadingSpaces[80]="";
  1127. BOOL MoreRecords=TRUE;
  1128. //
  1129. // Map the memory for the service record into our process.
  1130. //
  1131. GET_DATA(pServiceRecord, &ServiceRecord, sizeof(ServiceRecord))
  1132. //
  1133. // Get the ServiceName String.
  1134. //
  1135. GET_STRING(ServiceRecord.ServiceName, StringBuffer, sizeof(StringBuffer))
  1136. printf("%s%ws (service): \t\n",LeadingSpaces,StringBuffer);
  1137. strcat(LeadingSpaces," ");
  1138. if (ServiceRecord.StopDepend != NULL) {
  1139. GET_DATA(ServiceRecord.StopDepend, &DependRecord, sizeof(DependRecord))
  1140. do {
  1141. switch (DependRecord.DependType) {
  1142. case TypeDependOnService:
  1143. DumpBkwdDependentNames(DependRecord.DependService);
  1144. break;
  1145. case TypeDependOnGroup:
  1146. GET_DATA(DependRecord.DependGroup, &GroupRecord, sizeof(GroupRecord))
  1147. GET_STRING(GroupRecord.GroupName, StringBuffer, sizeof(StringBuffer))
  1148. printf("%s%ws (group)\n", LeadingSpaces,StringBuffer);
  1149. break;
  1150. case TypeDependOnUnresolved:
  1151. GET_DATA(DependRecord.DependUnresolved, &UnresolvedRecord, sizeof(UnresolvedRecord))
  1152. GET_STRING(UnresolvedRecord.Name, StringBuffer, sizeof(StringBuffer))
  1153. printf("%s%ws (unresolved)\n", LeadingSpaces,StringBuffer);
  1154. break;
  1155. default:
  1156. printf("%s(Unknown Depend Type)\n",LeadingSpaces);
  1157. MoreRecords = FALSE;
  1158. break;
  1159. }
  1160. if (DependRecord.Next != NULL) {
  1161. GET_DATA(DependRecord.Next, &DependRecord, sizeof(DependRecord))
  1162. }
  1163. else {
  1164. MoreRecords = FALSE;
  1165. }
  1166. } while (MoreRecords);
  1167. }
  1168. else {
  1169. printf("%s(nothing)\n",LeadingSpaces);
  1170. }
  1171. LeadingSpaces[strlen(LeadingSpaces)-2] = '\0';
  1172. }
  1173. VOID
  1174. help(
  1175. HANDLE hCurrentProcess,
  1176. HANDLE hCurrentThread,
  1177. DWORD dwCurrentPc,
  1178. PNTSD_EXTENSION_APIS lpExtensionApis,
  1179. LPSTR lpArgumentString
  1180. )
  1181. /*++
  1182. Routine Description:
  1183. Provides online help for the user of this debugger extension.
  1184. Arguments:
  1185. hCurrentProcess - Handle for the process being debugged.
  1186. hCurrentThread - Handle for the thread that has the debugger focus.
  1187. dwCurrentPc - Current Program Counter?
  1188. lpExtensionApis - Pointer to a structure that contains pointers to
  1189. various routines. (see \nt\public\sdk\inc\ntsdexts.h)
  1190. typedef struct _NTSD_EXTENSION_APIS {
  1191. DWORD nSize;
  1192. PNTSD_OUTPUT_ROUTINE lpOutputRoutine;
  1193. PNTSD_GET_EXPRESSION lpGetExpressionRoutine;
  1194. PNTSD_GET_SYMBOL lpGetSymbolRoutine;
  1195. PNTSD_DISASM lpDisasmRoutine;
  1196. PNTSD_CHECK_CONTROL_C lpCheckControlCRoutine;
  1197. } NTSD_EXTENSION_APIS, *PNTSD_EXTENSION_APIS;
  1198. lpArgumentString - This is a pointer to a string that contains
  1199. space seperated arguments that are passed to debugger
  1200. extension function.
  1201. Return Value:
  1202. --*/
  1203. {
  1204. InitFunctionPointers(hCurrentProcess, lpExtensionApis);
  1205. printf("\nService Controller NTSD Extensions\n");
  1206. if (!lpArgumentString || *lpArgumentString == '\0' ||
  1207. *lpArgumentString == '\n' || *lpArgumentString == '\r')
  1208. {
  1209. printf("\tServiceRecord - dump a ServiceRecord structure\n");
  1210. printf("\tDependencies - dump a Service's Dependencies\n");
  1211. printf("\tBackDepend - dump a Service's that depend on this service\n");
  1212. printf("\tImageRecord - dump an ImageRecord structure\n");
  1213. printf("\tGroupRecord - dump a GroupRecord structure\n");
  1214. printf("\n\tEnter help <cmd> for detailed help on a command\n");
  1215. }
  1216. else if (!_stricmp(lpArgumentString, "ServiceRecord")) {
  1217. printf("\tServiceRecord <arg>, where <arg> can be one of:\n");
  1218. printf("\t\tno argument - dump all ServiceRecord structures\n");
  1219. printf("\t\tmem - dump ServiceRecord Address Info only\n");
  1220. printf("\t\tname= <name> - dump the ServiceRecord for <name>\n");
  1221. printf("\t\taddress= <address> - dump the ServiceRecord at specified address\n");
  1222. }
  1223. else if (!_stricmp(lpArgumentString, "Dependencies")) {
  1224. printf("\tDependencies <arg>, where <arg> can be one of:\n");
  1225. printf("\t\tname= <name> - dump the Dependency Chain for <name>\n");
  1226. printf("\t\taddress= <address> - dump the Dependency Chain for address\n");
  1227. }
  1228. else if (!_stricmp(lpArgumentString, "BackDepend")) {
  1229. printf("\tDependencies <arg>, where <arg> can be one of:\n");
  1230. printf("\t\tname= <name> - dump the Dependency Chain for <name>\n");
  1231. printf("\t\taddress= <address> - dump the Dependency Chain for address\n");
  1232. }
  1233. else if (!_stricmp(lpArgumentString, "ImageRecord")) {
  1234. printf("\t\tmem - dump ImageRecord Memory Info only\n");
  1235. }
  1236. else if (!_stricmp(lpArgumentString, "GroupRecord")) {
  1237. printf("\t\tmem - dump GroupRecord Memory Info only\n");
  1238. }
  1239. else {
  1240. printf("\tInvalid command [%s]\n", lpArgumentString);
  1241. }
  1242. }