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.

566 lines
19 KiB

  1. /*++
  2. Copyright (c) 1995-1999 Microsoft Corporation
  3. Module Name:
  4. dbgtrace.cxx
  5. Abstract:
  6. NTSD extension commands for the WMI Tracing mechanism.
  7. Author:
  8. Jason Andre (jasandre) Jan-1999
  9. Revision History:
  10. --*/
  11. #include "inetdbgp.h"
  12. #ifndef _NO_TRACING_
  13. #define VALID_SIG(Sig) \
  14. if (SGuidList::TRACESIG != Sig) { \
  15. char *pSig = (char *) &Sig; \
  16. dprintf("Corrupt list, wrong signature found (%c%c%c%c)\n", \
  17. pSig[0], pSig[1], pSig[2], pSig[3]); \
  18. break; \
  19. }
  20. #define MAX_ARG_SIZE 80
  21. #define MAX_NUM_ARGS 10
  22. // List of arguments, arbitrarily selected maximum of 10 arguments
  23. struct {
  24. char szArg[MAX_ARG_SIZE];
  25. int iArg;
  26. } ArgList[MAX_NUM_ARGS];
  27. int SplitParameters(char *lpArgumentString)
  28. /*++
  29. This function takes a string of arguments separated by spaces or tabs and
  30. splits them apart, arbitrarily set to a max of 10 arguments.
  31. Arguments:
  32. lpArgumentString pointer to the argument string.
  33. Returns:
  34. int number of arguments added to list.
  35. --*/
  36. {
  37. BOOL fFinished = FALSE;
  38. int iArgCount = 0;
  39. // Ensure that the argument list is empty
  40. RtlZeroMemory(ArgList, sizeof(ArgList));
  41. // Iterate throught the argument string until we run out of characters
  42. while (*lpArgumentString && !fFinished && (iArgCount < MAX_NUM_ARGS)) {
  43. // Skip any leading whitespace, returning if we run out of characters
  44. while (*lpArgumentString && isspace(*lpArgumentString)) {
  45. ++lpArgumentString;
  46. }
  47. if (!*lpArgumentString)
  48. break;
  49. // Look for the end of the current argument
  50. char *lpStart = lpArgumentString;
  51. while (*lpArgumentString && !isspace(*lpArgumentString)) {
  52. ++lpArgumentString;
  53. }
  54. // Determine if this is the last parameter in the string
  55. if (!*lpArgumentString)
  56. fFinished = TRUE;
  57. else
  58. *lpArgumentString = '\0';
  59. // Copy the argument to the list
  60. strncpy(ArgList[iArgCount].szArg, lpStart, MAX_ARG_SIZE);
  61. // On the off chance this is a number try and convert it, assume it is
  62. // in hex
  63. ArgList[iArgCount].iArg = strtoul(ArgList[iArgCount].szArg, NULL, 16);
  64. // Next
  65. ++lpArgumentString;
  66. ++iArgCount;
  67. };
  68. return iArgCount;
  69. }
  70. void DisableTracing(LIST_ENTRY *pListHead)
  71. /*++
  72. This function iterates through the list of known modules and masks out all
  73. the flags other than ODS and Initialize.
  74. Arguments:
  75. pListHead pointer to the start of the list of modules.
  76. Returns:
  77. --*/
  78. {
  79. LIST_ENTRY *pListEntry;
  80. LIST_ENTRY leListHead;
  81. SGuidList *pGE;
  82. SGuidList sglGE;
  83. int fErrorFlag;
  84. move(leListHead, pListHead);
  85. for (pListEntry = leListHead.Flink;
  86. pListEntry != pListHead;)
  87. {
  88. pGE = CONTAINING_RECORD(pListEntry,
  89. SGuidList,
  90. m_leEntry);
  91. move(sglGE, pGE);
  92. VALID_SIG(sglGE.dwSig);
  93. if (sglGE.m_dpData.m_piErrorFlags) {
  94. move(fErrorFlag, sglGE.m_dpData.m_piErrorFlags);
  95. // If the error handle is set then we are debugging
  96. if (fErrorFlag & DEBUG_FLAGS_ANY) {
  97. // Disable tracing for this module, but not ODS
  98. fErrorFlag &= DEBUG_FLAG_ODS;
  99. if (!fErrorFlag)
  100. sglGE.m_dpData.m_iControlFlag = 0;
  101. // Write the new value back to memory
  102. WriteMemory(sglGE.m_dpData.m_piErrorFlags, &fErrorFlag, sizeof(fErrorFlag), NULL);
  103. if (!fErrorFlag)
  104. WriteMemory(pGE, &sglGE, sizeof(SGuidList), NULL);
  105. }
  106. }
  107. move(pListEntry, &pListEntry->Flink);
  108. }
  109. }
  110. void SetODS(LIST_ENTRY *pListHead, BOOL fProcessAll, BOOL bEnableODS)
  111. /*++
  112. This function iterates through the list of known modules and sets the
  113. ODS flag for each module.
  114. Arguments:
  115. pListHead pointer to the start of the list of modules.
  116. Returns:
  117. --*/
  118. {
  119. LIST_ENTRY *pListEntry;
  120. LIST_ENTRY leListHead;
  121. SGuidList *pGE;
  122. SGuidList sglGE;
  123. int fErrorFlag;
  124. move(leListHead, pListHead);
  125. for (pListEntry = leListHead.Flink;
  126. pListEntry != pListHead;)
  127. {
  128. pGE = CONTAINING_RECORD(pListEntry,
  129. SGuidList,
  130. m_leEntry);
  131. move(sglGE, pGE);
  132. VALID_SIG(sglGE.dwSig);
  133. if (sglGE.m_dpData.m_piErrorFlags) {
  134. if (fProcessAll || !_strcmpi(ArgList[1].szArg, sglGE.m_dpData.m_rgchLabel)) {
  135. // Load the error flag into useable memory and change it
  136. move(fErrorFlag, sglGE.m_dpData.m_piErrorFlags);
  137. if (bEnableODS) {
  138. fErrorFlag |= DEBUG_FLAG_ODS;
  139. dprintf("%15s: Enabled ODS\n", sglGE.m_dpData.m_rgchLabel);
  140. }
  141. else {
  142. fErrorFlag &= ~DEBUG_FLAG_ODS;
  143. dprintf("%15s: Disabled ODS\n", sglGE.m_dpData.m_rgchLabel);
  144. }
  145. // Write the new value back to memory
  146. WriteMemory(sglGE.m_dpData.m_piErrorFlags, &fErrorFlag, sizeof(fErrorFlag), NULL);
  147. }
  148. }
  149. move(pListEntry, &pListEntry->Flink);
  150. }
  151. }
  152. void ShowStatus(LIST_ENTRY *pListHead, BOOL fProcessAll)
  153. /*++
  154. This function iterates through the list of known modules and displays
  155. status information for each/a module.
  156. Arguments:
  157. pListHead pointer to the start of the list of modules.
  158. fProcessAll boolean specifying whether to show status for all
  159. modules. If this is FALSE then the module we are
  160. after is in ArgList[1]
  161. Returns:
  162. --*/
  163. {
  164. LIST_ENTRY *pListEntry;
  165. LIST_ENTRY leListHead;
  166. SGuidList *pGE;
  167. SGuidList sglGE;
  168. int fErrorFlag = 0;
  169. move(leListHead, pListHead);
  170. for (pListEntry = leListHead.Flink;
  171. pListEntry != pListHead;)
  172. {
  173. pGE = CONTAINING_RECORD(pListEntry,
  174. SGuidList,
  175. m_leEntry);
  176. move(sglGE, pGE);
  177. VALID_SIG(sglGE.dwSig);
  178. if (fProcessAll || !_strcmpi(ArgList[1].szArg, sglGE.m_dpData.m_rgchLabel)) {
  179. if (sglGE.m_dpData.m_piErrorFlags)
  180. move(fErrorFlag, sglGE.m_dpData.m_piErrorFlags);
  181. dprintf("%15s: ", sglGE.m_dpData.m_rgchLabel);
  182. if (sglGE.m_iInitializeFlags & DEBUG_FLAG_INITIALIZE)
  183. dprintf("State = Not Started, ");
  184. else if (sglGE.m_iInitializeFlags & DEBUG_FLAG_DEFERRED_START)
  185. dprintf("State = Deferred Start, ");
  186. else if (!sglGE.m_dpData.m_piErrorFlags)
  187. dprintf("State = Not Loaded, ");
  188. else
  189. dprintf("State = %14s, ",
  190. (fErrorFlag & DEBUG_FLAGS_ANY) ? "Tracing" : "Not Tracing");
  191. dprintf("Level = %d, ",
  192. fErrorFlag & DEBUG_FLAG_INFO ? DEBUG_LEVEL_INFO :
  193. fErrorFlag & DEBUG_FLAG_WARN ? DEBUG_LEVEL_WARN :
  194. fErrorFlag & DEBUG_FLAG_ERROR ? DEBUG_LEVEL_ERROR : 0);
  195. dprintf("Flags = %08X, ", sglGE.m_dpData.m_iControlFlag);
  196. if (sglGE.m_dpData.m_piErrorFlags)
  197. dprintf("ODS = %s\n", fErrorFlag & DEBUG_FLAG_ODS ? "TRUE" : "FALSE");
  198. else
  199. dprintf("ODS = FALSE\n");
  200. }
  201. move(pListEntry, &pListEntry->Flink);
  202. }
  203. }
  204. void SetActive(LIST_ENTRY *pListHead, BOOL fProcessAll, int iLevel, int iFlags)
  205. /*++
  206. This function iterates through the list of known modules and sets the
  207. level and control flags for each/a module.
  208. Arguments:
  209. pListHead pointer to the start of the list of modules.
  210. fProcessAll boolean specifying whether to toggle the state for all
  211. modules. If this is FALSE then the module we are
  212. after is in ArgList[1]
  213. iLevel the new error level setting for the module
  214. iFlags the new control flags for the module
  215. Returns:
  216. --*/
  217. {
  218. LIST_ENTRY *pListEntry;
  219. LIST_ENTRY leListHead;
  220. SGuidList *pGE;
  221. SGuidList sglGE;
  222. int fErrorFlag = 0;
  223. move(leListHead, pListHead);
  224. for (pListEntry = leListHead.Flink;
  225. pListEntry != pListHead;)
  226. {
  227. pGE = CONTAINING_RECORD(pListEntry,
  228. SGuidList,
  229. m_leEntry);
  230. move(sglGE, pGE);
  231. VALID_SIG(sglGE.dwSig);
  232. if (sglGE.m_dpData.m_piErrorFlags) {
  233. if (fProcessAll || !_strcmpi(ArgList[1].szArg, sglGE.m_dpData.m_rgchLabel)) {
  234. move(fErrorFlag, sglGE.m_dpData.m_piErrorFlags);
  235. dprintf("%15s: %sabling tracing... ",
  236. sglGE.m_dpData.m_rgchLabel,
  237. (iLevel == 0) ? "Dis" : "En");
  238. // Clear everything except the ODS flag
  239. fErrorFlag &= DEBUG_FLAG_ODS;
  240. // Enable tracing for this module
  241. switch (iLevel) {
  242. case 0: break;
  243. case DEBUG_LEVEL_ERROR: fErrorFlag |= DEBUG_FLAG_ERROR; break;
  244. case DEBUG_LEVEL_WARN: fErrorFlag |= DEBUG_FLAG_WARN; break;
  245. default:
  246. case DEBUG_LEVEL_INFO: fErrorFlag |= DEBUG_FLAG_INFO; break;
  247. }
  248. sglGE.m_dpData.m_iControlFlag = iFlags;
  249. // Write the new values back to memory
  250. WriteMemory(sglGE.m_dpData.m_piErrorFlags, &fErrorFlag, sizeof(fErrorFlag), NULL);
  251. WriteMemory(pGE, &sglGE, sizeof(SGuidList), NULL);
  252. dprintf("Done!\n");
  253. }
  254. }
  255. move(pListEntry, &pListEntry->Flink);
  256. }
  257. }
  258. void SetFlags(LIST_ENTRY *pListHead, BOOL fProcessAll, int iControlFlags)
  259. /*++
  260. This function iterates through the list of known modules and sets the
  261. control flags for each/a module.
  262. Arguments:
  263. pListHead pointer to the start of the list of modules.
  264. fProcessAll boolean specifying whether to set the flags for all
  265. modules. If this is FALSE then the module we are
  266. after is in ArgList[1]
  267. iControlFlags the new control flags for the module
  268. Returns:
  269. --*/
  270. {
  271. LIST_ENTRY *pListEntry;
  272. LIST_ENTRY leListHead;
  273. SGuidList *pGE;
  274. SGuidList sglGE;
  275. int fErrorFlag = 0;
  276. move(leListHead, pListHead);
  277. for (pListEntry = leListHead.Flink;
  278. pListEntry != pListHead;)
  279. {
  280. pGE = CONTAINING_RECORD(pListEntry,
  281. SGuidList,
  282. m_leEntry);
  283. move(sglGE, pGE);
  284. VALID_SIG(sglGE.dwSig);
  285. if (fProcessAll || !_strcmpi(ArgList[1].szArg, sglGE.m_dpData.m_rgchLabel)) {
  286. // Set the new value for the control flag
  287. sglGE.m_dpData.m_iControlFlag = iControlFlags;
  288. // Write the new value back to memory
  289. WriteMemory(pGE, &sglGE, sizeof(SGuidList), NULL);
  290. dprintf("%15s: Flag = %08X\n",
  291. sglGE.m_dpData.m_rgchLabel, iControlFlags);
  292. }
  293. move(pListEntry, &pListEntry->Flink);
  294. }
  295. }
  296. #endif
  297. DECLARE_API( trace )
  298. /*++
  299. Routine Description:
  300. This function is called as an NTSD extension to ...
  301. Arguments:
  302. hCurrentProcess - Supplies a handle to the current process (at the
  303. time the extension was called).
  304. hCurrentThread - Supplies a handle to the current thread (at the
  305. time the extension was called).
  306. CurrentPc - Supplies the current pc at the time the extension is
  307. called.
  308. lpExtensionApis - Supplies the address of the functions callable
  309. by this extension.
  310. lpArgumentString - Supplies the asciiz string that describes the
  311. ansi string to be dumped.
  312. Return Value:
  313. None.
  314. --*/
  315. {
  316. INIT_API();
  317. #ifndef _NO_TRACING_
  318. // Load all the arguments into the ArgumentLst
  319. int ArgCount = SplitParameters(lpArgumentString);
  320. // Make sure we have a - something as the first parameters
  321. if( ArgList[0].szArg[0] != '-' ) {
  322. PrintUsage( "trace" );
  323. return;
  324. }
  325. // We need to have access to the GuidList before we can do anything so
  326. // attempt to load it first
  327. LIST_ENTRY *pGuidList = (LIST_ENTRY *) GetExpression("IisRTL!g_pGuidList");
  328. if (!pGuidList) {
  329. dprintf("inetdbg.trace: Unable to access the IISRTL Guid list\n");
  330. return;
  331. }
  332. // Determine which request we have and process it
  333. switch (tolower(ArgList[0].szArg[1]))
  334. {
  335. // !trace -o <LoggerName> <LoggerFileName> Toggle tracing active state
  336. case 'o':
  337. {
  338. struct {
  339. EVENT_TRACE_PROPERTIES Header;
  340. char LogFileName[MAX_PATH];
  341. } Properties;
  342. PEVENT_TRACE_PROPERTIES LoggerInfo = &Properties.Header;
  343. TRACEHANDLE LoggerHandle = 0;
  344. // Make sure we have the correct number of parameters
  345. if (ArgCount < 3) {
  346. PrintUsage( "trace" );
  347. break;
  348. }
  349. // We want to create a trace session, so set up all the control buffers
  350. RtlZeroMemory(&Properties, sizeof(Properties));
  351. LoggerInfo->Wnode.BufferSize = sizeof(Properties);
  352. LoggerInfo->Wnode.Flags = WNODE_FLAG_TRACED_GUID;
  353. // LoggerInfo.LogFileName = ArgList[2].szArg;
  354. // LoggerInfo.LoggerName = ArgList[1].szArg;
  355. // See if there is already a session with that name
  356. ULONG Status = QueryTrace(0, ArgList[1].szArg, LoggerInfo);
  357. if (ERROR_SUCCESS == Status) {
  358. // There was a session of that name already existing, so stop it
  359. LoggerHandle = LoggerInfo->Wnode.HistoricalContext;
  360. Status = StopTrace((TRACEHANDLE) 0, ArgList[1].szArg, LoggerInfo);
  361. // And if successful iterate through all the modules and disable
  362. // tracing, but not ODS
  363. if (ERROR_SUCCESS == Status) {
  364. DisableTracing(pGuidList);
  365. }
  366. }
  367. else if (ERROR_WMI_INSTANCE_NOT_FOUND == Status) {
  368. if (ArgList[2].szArg != NULL) {
  369. strcpy(&Properties.LogFileName[0], ArgList[2].szArg);
  370. }
  371. LoggerInfo->LogFileNameOffset = sizeof(EVENT_TRACE_PROPERTIES);
  372. // There was no sesion of that name, so start one
  373. Status = StartTrace(&LoggerHandle, ArgList[1].szArg, LoggerInfo);
  374. }
  375. if (ERROR_SUCCESS != Status)
  376. dprintf("Failure processing Logger request, Status returned was %d\n", Status);
  377. else
  378. dprintf("Toggled Active state of Trace %s\n", ArgList[1].szArg);
  379. }
  380. break;
  381. // !trace -d <Module_Name|all> 0|1 Set OutputDebugString generation state
  382. case 'd':
  383. {
  384. // Determine if we are processing one or all modules
  385. BOOL fProcessAll = !_strcmpi(ArgList[1].szArg, "all");
  386. // Make sure we have the correct number of parameters
  387. if (ArgCount < 2) {
  388. PrintUsage( "trace" );
  389. break;
  390. }
  391. // Look for the relevant modules and process them
  392. SetODS(pGuidList, fProcessAll, (ArgList[2].szArg[0] == '1') ? TRUE : FALSE);
  393. }
  394. break;
  395. // !trace -s [Module_Name] List module status
  396. case 's':
  397. {
  398. // Determine if we are processing one or all modules
  399. BOOL fProcessAll = (1 == ArgCount) ? TRUE : !_strcmpi(ArgList[1].szArg, "all");
  400. // Look for the relevant modules and process them
  401. ShowStatus(pGuidList, fProcessAll);
  402. }
  403. break;
  404. // !trace -a <Module_Name|all> <LoggerName> [Level] [Flags] Set active state of specified module
  405. case 'a':
  406. {
  407. EVENT_TRACE_PROPERTIES LoggerInfo;
  408. TRACEHANDLE LoggerHandle = 0;
  409. // char LogFileName[_MAX_PATH];
  410. int iLevel = 0;
  411. int iFlags = 0;
  412. // Make sure we have the correct number of parameters
  413. if (ArgCount < 3) {
  414. PrintUsage( "trace" );
  415. break;
  416. }
  417. if (ArgCount > 3)
  418. iLevel = ArgList[3].iArg;
  419. if (ArgCount > 4)
  420. iFlags = ArgList[4].iArg;
  421. // Determine if we are processing one or all modules
  422. BOOL fProcessAll = !_strcmpi(ArgList[1].szArg, "all");
  423. // Set up the logger info buffer so that we can get the logger handle
  424. // for the specified logger
  425. RtlZeroMemory(&LoggerInfo, sizeof(EVENT_TRACE_PROPERTIES));
  426. LoggerInfo.Wnode.BufferSize = sizeof(LoggerInfo);
  427. LoggerInfo.Wnode.Flags = WNODE_FLAG_TRACED_GUID;
  428. // RtlZeroMemory(&LogFileName[0], _MAX_PATH);
  429. // LoggerInfo.LogFileName = &LogFileName[0];
  430. // LoggerInfo.LoggerName = ArgList[2].szArg;
  431. // Jason: no need to pass in if you do not need the names return
  432. // Try to get the logger handle
  433. ULONG Status = QueryTrace(0, ArgList[2].szArg, &LoggerInfo);
  434. if (Status == ERROR_SUCCESS)
  435. LoggerHandle = LoggerInfo.Wnode.HistoricalContext;
  436. else if (ERROR_WMI_INSTANCE_NOT_FOUND == Status) {
  437. dprintf("Failed to find the Logger %s\n"
  438. "Please start this logger before activating modules which use it\n",
  439. ArgList[2].szArg);
  440. break;
  441. }
  442. else {
  443. dprintf("Failed to find the Logger %s\n"
  444. "Status returned was %d\n",
  445. ArgList[2].szArg, Status);
  446. break;
  447. }
  448. // Look for the relevant modules and process them
  449. SetActive(pGuidList, fProcessAll, iLevel, iFlags);
  450. }
  451. break;
  452. // !trace -f <Module_Name|all> <Flag> Set control flag for a specific module
  453. case 'f':
  454. {
  455. // Make sure we have the correct number of parameters
  456. if (ArgCount != 3) {
  457. PrintUsage( "trace" );
  458. break;
  459. }
  460. // Determine if we are processing one or all modules
  461. BOOL fProcessAll = !_strcmpi(ArgList[1].szArg, "all");
  462. // And then get the control flag to use
  463. int iControlFlags = ArgList[2].iArg;
  464. // Now go through all the modules and make the appropriate changes
  465. SetFlags(pGuidList, fProcessAll, iControlFlags);
  466. }
  467. break;
  468. default:
  469. PrintUsage( "trace" );
  470. break;
  471. };
  472. #else
  473. dprintf("This feature not supported in this build.\n"
  474. "Please rebuild without the build flag _NO_TRACING_\n");
  475. #endif
  476. } // DECLARE_API( trace )