Leaked source code of windows server 2003
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.

727 lines
21 KiB

  1. /*++
  2. Copyright (c) 1990 Microsoft Corporation
  3. Module Name:
  4. elfexts.c
  5. Abstract:
  6. This function contains the eventlog ntsd debugger extensions
  7. Author:
  8. Dan Hinsley (DanHi) 22-May-1993
  9. IvanBrug 06 21 2001 converted to the latest debugger
  10. Revision History:
  11. --*/
  12. #include <elfmain.h>
  13. #include <stdio.h>
  14. #include <stdlib.h>
  15. #include <string.h>
  16. #include <malloc.h>
  17. #include <time.h>
  18. #include <elf.h>
  19. #include <elfdef.h>
  20. #include <elfcommn.h>
  21. #include <elfproto.h>
  22. #include <svcsp.h>
  23. #include <elfextrn.h>
  24. #define DbgPrint(_x_)
  25. #define MAX_NAME 256
  26. #define GET_DATA(DebugeeAddr, LocalAddr, Length) \
  27. Status = ReadMemory( \
  28. (MEMORY_ADDRESS)DebugeeAddr, \
  29. (PVOID)LocalAddr, \
  30. (ULONG)(Length), \
  31. NULL \
  32. );
  33. HANDLE GlobalhCurrentProcess;
  34. BOOL Status;
  35. LPWSTR
  36. GetUnicodeString(
  37. PUNICODE_STRING pUnicodeString
  38. )
  39. {
  40. MEMORY_ADDRESS Pointer;
  41. UNICODE_STRING UnicodeString;
  42. GET_DATA(pUnicodeString, &UnicodeString, sizeof(UNICODE_STRING))
  43. Pointer = (MEMORY_ADDRESS) UnicodeString.Buffer;
  44. UnicodeString.Buffer = (LPWSTR) LocalAlloc(LMEM_ZEROINIT,
  45. UnicodeString.Length + sizeof(WCHAR));
  46. GET_DATA(Pointer, UnicodeString.Buffer, UnicodeString.Length)
  47. return(UnicodeString.Buffer);
  48. }
  49. MEMORY_ADDRESS
  50. GetLogFileAddress(
  51. LPSTR LogFileName,
  52. PLOGFILE LogFile
  53. )
  54. {
  55. ANSI_STRING AnsiString;
  56. UNICODE_STRING UnicodeString;
  57. MEMORY_ADDRESS Pointer = 0;
  58. MEMORY_ADDRESS LogFileAnchor = 0;
  59. LPWSTR ModuleName = 0;
  60. //
  61. // Convert the string to UNICODE
  62. //
  63. RtlInitAnsiString(&AnsiString, LogFileName);
  64. RtlAnsiStringToUnicodeString(&UnicodeString, &AnsiString, TRUE);
  65. //
  66. // Walk the logfile list looking for a match
  67. //
  68. LogFileAnchor = (MEMORY_ADDRESS)GetExpression("eventlog!LogFilesHead");
  69. if (LogFileAnchor) {
  70. GET_DATA(LogFileAnchor, &Pointer, sizeof(MEMORY_ADDRESS));
  71. while (Pointer != LogFileAnchor) {
  72. GET_DATA(Pointer, LogFile, sizeof(LOGFILE))
  73. ModuleName = GetUnicodeString(LogFile->LogModuleName);
  74. if (!_wcsicmp(ModuleName, UnicodeString.Buffer)) {
  75. break;
  76. }
  77. LocalFree(ModuleName);
  78. Pointer = (MEMORY_ADDRESS) LogFile->FileList.Flink;
  79. }
  80. } else {
  81. dprintf("unable to resolve %s\n","eventlog!LogFilesHead");
  82. }
  83. RtlFreeUnicodeString(&UnicodeString);
  84. if (Pointer == LogFileAnchor) {
  85. return(0);
  86. }
  87. else {
  88. LocalFree(ModuleName);
  89. return(Pointer);
  90. }
  91. }
  92. //
  93. // Dump an individual record
  94. //
  95. MEMORY_ADDRESS
  96. DumpRecord(
  97. MEMORY_ADDRESS Record,
  98. DWORD RecordNumber,
  99. MEMORY_ADDRESS StartOfFile,
  100. MEMORY_ADDRESS EndOfFile
  101. )
  102. {
  103. MEMORY_ADDRESS BufferLen = 0;
  104. PCHAR TimeBuffer;
  105. PEVENTLOGRECORD EventLogRecord;
  106. LPWSTR Module;
  107. LPWSTR Computer;
  108. MEMORY_ADDRESS FirstPiece = 0;
  109. time_t TempAligned;
  110. GET_DATA(Record, &BufferLen, sizeof(DWORD));
  111. //
  112. // See if it's a ELF_SKIP_DWORD, and if it is, return the top of the
  113. // file
  114. //
  115. if (BufferLen == ELF_SKIP_DWORD) {
  116. return(StartOfFile + sizeof(ELF_LOGFILE_HEADER));
  117. }
  118. //
  119. // See if it's the EOF record
  120. //
  121. if (BufferLen == ELFEOFRECORDSIZE) {
  122. return(0);
  123. }
  124. BufferLen += sizeof(DWORD); // get room for length of next record
  125. EventLogRecord = (PEVENTLOGRECORD) LocalAlloc(LMEM_ZEROINIT, BufferLen);
  126. //
  127. // If the record wraps, grab it piecemeal
  128. //
  129. if (EndOfFile && BufferLen + Record > EndOfFile) {
  130. FirstPiece = EndOfFile - Record;
  131. GET_DATA(Record, EventLogRecord, FirstPiece);
  132. GET_DATA((StartOfFile + sizeof(ELF_LOGFILE_HEADER)),
  133. ((PBYTE) EventLogRecord + FirstPiece), BufferLen - FirstPiece);
  134. }
  135. else {
  136. GET_DATA(Record, EventLogRecord, BufferLen);
  137. }
  138. //
  139. // If it's greater than the starting record, print it out
  140. //
  141. if (EventLogRecord->RecordNumber >= RecordNumber) {
  142. dprintf("\nRecord %d is %d [0x%X] bytes long starting at %p\n",
  143. EventLogRecord->RecordNumber, EventLogRecord->Length,
  144. EventLogRecord->Length, Record);
  145. Module = (LPWSTR)(EventLogRecord+1);
  146. Computer = (LPWSTR)((PBYTE) Module + ((wcslen(Module) + 1) * sizeof(WCHAR)));
  147. dprintf("\tGenerated by %ws from system %ws\n", Module, Computer);
  148. TempAligned = EventLogRecord->TimeGenerated;
  149. TimeBuffer = ctime(&TempAligned);
  150. if (TimeBuffer) {
  151. dprintf("\tGenerated at %s", TimeBuffer);
  152. }
  153. else {
  154. dprintf("\tGenerated time field is blank\n");
  155. }
  156. TempAligned = EventLogRecord->TimeWritten;
  157. TimeBuffer = ctime(&TempAligned);
  158. if (TimeBuffer) {
  159. dprintf("\tWritten at %s", TimeBuffer);
  160. }
  161. else {
  162. dprintf("\tTime written field is blank\n");
  163. }
  164. dprintf("\tEvent Id = %d\n", EventLogRecord->EventID);
  165. dprintf("\tEventType = ");
  166. switch (EventLogRecord->EventType) {
  167. case EVENTLOG_SUCCESS:
  168. dprintf("Success\n");
  169. break;
  170. case EVENTLOG_ERROR_TYPE:
  171. dprintf("Error\n");
  172. break;
  173. case EVENTLOG_WARNING_TYPE:
  174. dprintf("Warning\n");
  175. break;
  176. case EVENTLOG_INFORMATION_TYPE:
  177. dprintf("Information\n");
  178. break;
  179. case EVENTLOG_AUDIT_SUCCESS:
  180. dprintf("Audit Success\n");
  181. break;
  182. case EVENTLOG_AUDIT_FAILURE:
  183. dprintf("Audit Failure\n");
  184. break;
  185. default:
  186. dprintf("Invalid value 0x%X\n", EventLogRecord->EventType);
  187. }
  188. dprintf("\t%d strings at offset 0x%X\n", EventLogRecord->NumStrings,
  189. EventLogRecord->StringOffset);
  190. dprintf("\t%d bytes of data at offset 0x%X\n", EventLogRecord->DataLength,
  191. EventLogRecord->DataOffset);
  192. }
  193. if (FirstPiece) {
  194. Record = StartOfFile + sizeof(ELF_LOGFILE_HEADER) + BufferLen -FirstPiece;
  195. }
  196. else {
  197. Record += EventLogRecord->Length;
  198. }
  199. LocalFree(EventLogRecord);
  200. return(Record);
  201. }
  202. //
  203. // Dump a record, or all records, or n records
  204. //
  205. DECLARE_API(record)
  206. {
  207. MEMORY_ADDRESS Pointer = 0;
  208. LOGFILE LogFile;
  209. MEMORY_ADDRESS StartOfFile;
  210. MEMORY_ADDRESS EndOfFile = 0;
  211. DWORD RecordNumber = 0;
  212. INIT_API();
  213. //
  214. // Evaluate the argument string to get the address of
  215. // the record to dump.
  216. //
  217. while (isspace(*lpArgumentString)) lpArgumentString++;
  218. if (lpArgumentString && *lpArgumentString) {
  219. if (*lpArgumentString == '.') {
  220. if (GetLogFileAddress(lpArgumentString+1, &LogFile) == 0) {
  221. dprintf("Logfile %s not found\n", lpArgumentString+1);
  222. return;
  223. }
  224. Pointer = ((MEMORY_ADDRESS ) (LogFile.BaseAddress)) + LogFile.BeginRecord;
  225. }
  226. else if (*lpArgumentString == '#') {
  227. RecordNumber = atoi(lpArgumentString + 1);
  228. dprintf("Dumping records starting at record #%d\n", RecordNumber);
  229. lpArgumentString = NULL;
  230. }
  231. else if (*lpArgumentString) {
  232. Pointer = GetExpression(lpArgumentString);
  233. }
  234. else {
  235. dprintf("Invalid lead character 0x%02X\n", *lpArgumentString);
  236. return;
  237. }
  238. }
  239. //if (!lpArgumentString || *lpArgumentString) {
  240. if (0 == Pointer){
  241. if (GetLogFileAddress("system", &LogFile) == 0) {
  242. dprintf("System Logfile not found\n");
  243. return;
  244. }
  245. Pointer = ((MEMORY_ADDRESS ) (LogFile.BaseAddress)) + LogFile.BeginRecord;
  246. }
  247. StartOfFile = (MEMORY_ADDRESS ) LogFile.BaseAddress;
  248. EndOfFile = (MEMORY_ADDRESS ) LogFile.BaseAddress + LogFile.ActualMaxFileSize;
  249. dprintf("%p %p %p\n",Pointer,StartOfFile,EndOfFile );
  250. //
  251. // Dump records starting wherever they told us to
  252. //
  253. while (Pointer < EndOfFile && Pointer && !CheckControlC()) {
  254. Pointer = DumpRecord(Pointer, RecordNumber, StartOfFile, EndOfFile);
  255. }
  256. return;
  257. }
  258. //
  259. // Dump a single LogModule structure if it matches MatchName (NULL matches
  260. // all)
  261. //
  262. PLIST_ENTRY
  263. DumpLogModule(
  264. MEMORY_ADDRESS pLogModule,
  265. LPWSTR MatchName
  266. )
  267. {
  268. LOGMODULE LogModule;
  269. WCHAR ModuleName[MAX_NAME / sizeof(WCHAR)];
  270. GET_DATA(pLogModule, &LogModule, sizeof(LogModule));
  271. GET_DATA(LogModule.ModuleName, &ModuleName, MAX_NAME);
  272. if (!MatchName || !_wcsicmp(MatchName, ModuleName)) {
  273. dprintf("\tModule Name %S\n", ModuleName);
  274. dprintf("\tModule Atom 0x%2x\n", LogModule.ModuleAtom);
  275. dprintf("\tPointer to LogFile %p\n", LogModule.LogFile);
  276. }
  277. return (LogModule.ModuleList.Flink);
  278. }
  279. //
  280. // Dump selected, or all, LogModule structures
  281. //
  282. DECLARE_API(logmodule)
  283. {
  284. MEMORY_ADDRESS pLogModule = 0;
  285. MEMORY_ADDRESS LogModuleAnchor = 0;
  286. LPWSTR wArgumentString = NULL;
  287. ANSI_STRING AnsiString;
  288. UNICODE_STRING UnicodeString;
  289. INIT_API();
  290. UnicodeString.Buffer = NULL;
  291. //
  292. // Evaluate the argument string to get the address of
  293. // the logmodule to dump. If no parm, dump them all.
  294. //
  295. while (isspace(*lpArgumentString)) lpArgumentString++;
  296. if (lpArgumentString && *lpArgumentString == '.') {
  297. lpArgumentString++;
  298. RtlInitAnsiString(&AnsiString, lpArgumentString);
  299. RtlAnsiStringToUnicodeString(&UnicodeString, &AnsiString, TRUE);
  300. }
  301. else if (lpArgumentString && *lpArgumentString) {
  302. pLogModule = GetExpression(lpArgumentString);
  303. DumpLogModule( pLogModule, NULL);
  304. return;
  305. }
  306. LogModuleAnchor = GetExpression("eventlog!LogModuleHead");
  307. if (LogModuleAnchor)
  308. {
  309. GET_DATA(LogModuleAnchor, &pLogModule, sizeof(MEMORY_ADDRESS));
  310. while (pLogModule != LogModuleAnchor && !CheckControlC()) {
  311. pLogModule =
  312. (MEMORY_ADDRESS) DumpLogModule( pLogModule,
  313. UnicodeString.Buffer);
  314. if (!UnicodeString.Buffer) {
  315. dprintf("\n");
  316. }
  317. }
  318. }
  319. else
  320. {
  321. dprintf("Unable ro resolve %s\n","eventlog!LogModuleHead");
  322. }
  323. if (UnicodeString.Buffer) {
  324. RtlFreeUnicodeString(&UnicodeString);
  325. }
  326. return;
  327. }
  328. //
  329. // Dump a single LogFile structure if it matches MatchName (NULL matches
  330. // all)
  331. //
  332. PLIST_ENTRY
  333. DumpLogFile(
  334. HANDLE hCurrentProcess,
  335. MEMORY_ADDRESS pLogFile,
  336. LPWSTR MatchName
  337. )
  338. {
  339. LOGFILE LogFile;
  340. LPWSTR UnicodeName;
  341. //
  342. // Get the fixed part of the structure
  343. //
  344. GET_DATA(pLogFile, &LogFile, sizeof(LogFile))
  345. //
  346. // Get the Default module name
  347. //
  348. UnicodeName = GetUnicodeString(LogFile.LogModuleName);
  349. //
  350. // See if we're just looking for a particular one. If we are and
  351. // this isn't it, bail out.
  352. //
  353. if (MatchName && _wcsicmp(MatchName, UnicodeName)) {
  354. LocalFree(UnicodeName);
  355. return (LogFile.FileList.Flink);
  356. }
  357. //
  358. // Otherwise print it out
  359. //
  360. dprintf("%ws", UnicodeName);
  361. LocalFree(UnicodeName);
  362. //
  363. // Now the file name of this logfile
  364. //
  365. UnicodeName = GetUnicodeString(LogFile.LogFileName);
  366. dprintf(" : %ws\n", UnicodeName);
  367. LocalFree(UnicodeName);
  368. if (LogFile.Notifiees.Flink == LogFile.Notifiees.Blink) {
  369. dprintf("\tNo active ChangeNotifies on this log\n");
  370. }
  371. else {
  372. dprintf("\tActive Change Notify! Dump of this list not implemented\n");
  373. }
  374. dprintf("\tReference Count: %d\n\tFlags: ", LogFile.RefCount);
  375. if (LogFile.Flags == 0) {
  376. dprintf("No flags set ");
  377. }
  378. else {
  379. if (LogFile.Flags & ELF_LOGFILE_HEADER_DIRTY) {
  380. dprintf("Dirty ");
  381. }
  382. if (LogFile.Flags & ELF_LOGFILE_HEADER_WRAP) {
  383. dprintf("Wrapped ");
  384. }
  385. if (LogFile.Flags & ELF_LOGFILE_LOGFULL_WRITTEN) {
  386. dprintf("Logfull Written ");
  387. }
  388. }
  389. dprintf("\n");
  390. dprintf("\tMax Files Sizes [Cfg:Curr:Next] 0x%X : 0x%X : 0x%X\n",
  391. LogFile.ConfigMaxFileSize, LogFile.ActualMaxFileSize,
  392. LogFile.NextClearMaxFileSize);
  393. dprintf("\tRecord Numbers [Oldest:Curr] %d : %d\n",
  394. LogFile.OldestRecordNumber, LogFile.CurrentRecordNumber);
  395. dprintf("\tRetention period in days: %d\n", LogFile.Retention / 86400);
  396. dprintf("\tBase Address: 0x%X\n", LogFile.BaseAddress);
  397. dprintf("\tView size: 0x%X\n", LogFile.ViewSize);
  398. dprintf("\tOffset of beginning record: 0x%X\n", LogFile.BeginRecord);
  399. dprintf("\tOffset of ending record: 0x%X\n", LogFile.EndRecord);
  400. return (LogFile.FileList.Flink);
  401. }
  402. //
  403. // Dump selected, or all, LogFile structures
  404. //
  405. DECLARE_API(logfile)
  406. {
  407. MEMORY_ADDRESS pLogFile;
  408. MEMORY_ADDRESS LogFileAnchor;
  409. LPWSTR wArgumentString = NULL;
  410. ANSI_STRING AnsiString;
  411. UNICODE_STRING UnicodeString;
  412. BOOL AllocateString = FALSE;
  413. INIT_API();
  414. UnicodeString.Buffer = NULL;
  415. //
  416. // Evaluate the argument string to get the address of
  417. // the logfile to dump. If no parm, dump them all.
  418. //
  419. while (isspace(*lpArgumentString)) lpArgumentString++;
  420. if (lpArgumentString && *lpArgumentString) {
  421. if(*lpArgumentString == '.') {
  422. lpArgumentString++;
  423. RtlInitAnsiString(&AnsiString, lpArgumentString);
  424. RtlAnsiStringToUnicodeString(&UnicodeString, &AnsiString, TRUE);
  425. }
  426. else {
  427. pLogFile = GetExpression(lpArgumentString);
  428. DumpLogFile(hCurrentProcess, pLogFile, NULL);
  429. return;
  430. }
  431. }
  432. LogFileAnchor = GetExpression("eventlog!LogFilesHead");
  433. GET_DATA(LogFileAnchor, &pLogFile, sizeof(MEMORY_ADDRESS))
  434. while (pLogFile != LogFileAnchor) {
  435. pLogFile =
  436. (MEMORY_ADDRESS) DumpLogFile(hCurrentProcess, pLogFile,
  437. UnicodeString.Buffer);
  438. if (!UnicodeString.Buffer) {
  439. dprintf("\n");
  440. }
  441. }
  442. if (UnicodeString.Buffer) {
  443. RtlFreeUnicodeString(&UnicodeString);
  444. }
  445. return;
  446. }
  447. //
  448. // Dump a request packet structure
  449. //
  450. DECLARE_API(request)
  451. {
  452. ELF_REQUEST_RECORD Request;
  453. MEMORY_ADDRESS Pointer;
  454. DWORD RecordSize;
  455. WRITE_PKT WritePkt;
  456. READ_PKT ReadPkt;
  457. CLEAR_PKT ClearPkt;
  458. BACKUP_PKT BackupPkt;
  459. LPWSTR FileName;
  460. CHAR Address[32];
  461. INIT_API();
  462. //
  463. // Evaluate the argument string to get the address of
  464. // the request packet to dump.
  465. //
  466. while (isspace(*lpArgumentString)) lpArgumentString++;
  467. if (lpArgumentString && *lpArgumentString) {
  468. Pointer = GetExpression(lpArgumentString);
  469. }
  470. else {
  471. dprintf("Must supply a request packet address\n");
  472. return;
  473. }
  474. GET_DATA(Pointer, &Request, sizeof(ELF_REQUEST_RECORD))
  475. switch (Request.Command ) {
  476. case ELF_COMMAND_READ:
  477. dprintf("\nRead packet\n");
  478. GET_DATA(Request.Pkt.ReadPkt, &ReadPkt, sizeof(READ_PKT))
  479. dprintf("\tLast Seek Position = %d\n", ReadPkt.LastSeekPos);
  480. dprintf("\tLast Seek Record = %d\n", ReadPkt.LastSeekRecord);
  481. dprintf("\tStart at record number %d\n", ReadPkt.RecordNumber);
  482. dprintf("\tRead %d bytes into buffer at 0x%X\n",
  483. ReadPkt.BufferSize, ReadPkt.Buffer);
  484. if (ReadPkt.Flags & ELF_IREAD_UNICODE) {
  485. dprintf("\tReturn in ANSI\n");
  486. }
  487. else {
  488. dprintf("\tReturn in UNICODE\n");
  489. }
  490. dprintf("\tRead flags: ");
  491. if (ReadPkt.ReadFlags & EVENTLOG_SEQUENTIAL_READ) {
  492. dprintf("Sequential ");
  493. }
  494. if (ReadPkt.ReadFlags & EVENTLOG_SEEK_READ) {
  495. dprintf("Seek ");
  496. }
  497. if (ReadPkt.ReadFlags & EVENTLOG_FORWARDS_READ) {
  498. dprintf("Forward ");
  499. }
  500. if (ReadPkt.ReadFlags & EVENTLOG_BACKWARDS_READ) {
  501. dprintf("Backwards ");
  502. }
  503. dprintf("\n");
  504. break;
  505. case ELF_COMMAND_WRITE:
  506. dprintf("\nWrite packet\n");
  507. if (Request.Flags == ELF_FORCE_OVERWRITE) {
  508. dprintf("with ELF_FORCE_OVERWRITE enabled\n");
  509. }
  510. else {
  511. dprintf("\n");
  512. }
  513. GET_DATA(Request.Pkt.WritePkt, &WritePkt, sizeof(WRITE_PKT))
  514. RecordSize = (WritePkt.Datasize);
  515. DumpRecord((MEMORY_ADDRESS)WritePkt.Buffer, 0, 0, 0);
  516. break;
  517. case ELF_COMMAND_CLEAR:
  518. dprintf("\nClear packet\n");
  519. GET_DATA(Request.Pkt.ClearPkt, &ClearPkt, sizeof(CLEAR_PKT))
  520. FileName = GetUnicodeString(ClearPkt.BackupFileName);
  521. dprintf("Backup filename = %ws\n", FileName);
  522. LocalFree(FileName);
  523. break;
  524. case ELF_COMMAND_BACKUP:
  525. dprintf("\nBackup packet\n");
  526. GET_DATA(Request.Pkt.BackupPkt, &BackupPkt, sizeof(BACKUP_PKT))
  527. FileName = GetUnicodeString(BackupPkt.BackupFileName);
  528. dprintf("Backup filename = %ws\n", FileName);
  529. LocalFree(FileName);
  530. break;
  531. case ELF_COMMAND_WRITE_QUEUED:
  532. dprintf("\nQueued Write packet\n");
  533. if (Request.Flags == ELF_FORCE_OVERWRITE) {
  534. dprintf("with ELF_FORCE_OVERWRITE enabled\n");
  535. }
  536. else {
  537. dprintf("\n");
  538. }
  539. dprintf("NtStatus = 0x%X\n", Request.Status);
  540. break;
  541. default:
  542. dprintf("\nInvalid packet\n");
  543. }
  544. dprintf("\nLogFile for this packet:\n\n");
  545. sprintf(Address,"%p",Request.LogFile);
  546. logfile(hCurrentProcess,
  547. hCurrentThread, dwCurrentPc, dwProcessor,
  548. Address);
  549. dprintf("\nLogModule for this packet:\n\n");
  550. sprintf(Address,"%p",Request.Module);
  551. logmodule(hCurrentProcess, hCurrentThread, dwCurrentPc, dwProcessor,
  552. Address);
  553. return;
  554. }
  555. //
  556. // Online help
  557. //
  558. DECLARE_API(help)
  559. {
  560. INIT_API();
  561. dprintf("\nEventlog debugger Extensions\n");
  562. if (!lpArgumentString || *lpArgumentString == '\0' ||
  563. *lpArgumentString == '\n' || *lpArgumentString == '\r') {
  564. dprintf("\tlogmodule - dump a logmodule structure\n");
  565. dprintf("\tlogfile - dump a logfile structure\n");
  566. dprintf("\trequest - dump a request record\n");
  567. dprintf("\trecord - dump a eventlog record\n");
  568. dprintf("\n\tEnter help <cmd> for detailed help on a command\n");
  569. }
  570. else {
  571. if (!_stricmp(lpArgumentString, "logmodule")) {
  572. dprintf("\tlogmodule <arg>, where <arg> can be one of:\n");
  573. dprintf("\t\tno argument - dump all logmodule structures\n");
  574. dprintf("\t\taddress - dump the logmodule at specified address\n");
  575. dprintf("\t\t.string - dump the logmodule with name string\n");
  576. }
  577. else if (!_stricmp(lpArgumentString, "logfile")) {
  578. dprintf("\tlogfile <arg>, where <arg> can be one of:\n");
  579. dprintf("\t\tno argument - dump all logfile structures\n");
  580. dprintf("\t\taddress - dump the logfile at specified address\n");
  581. dprintf("\t\t.string - dump the logfile with name string\n");
  582. }
  583. else if (!_stricmp(lpArgumentString, "record")) {
  584. dprintf("\trecord <arg>, where <arg> can be one of:\n");
  585. dprintf("\t\tno argument - dump all records in system log\n");
  586. dprintf("\t\taddress - dump records starting at specified address\n");
  587. dprintf("\t\t.string - dump all records in the <string> log\n");
  588. dprintf("\t\t#<nnn> - dumps records starting at nnn in system log\n");
  589. dprintf("\t\t#<nnn> .string - dumps records starting at nnn in <string> log\n");
  590. }
  591. else if (!_stricmp(lpArgumentString, "request")) {
  592. dprintf("\trequest - dump the request record at specified address\n");
  593. }
  594. else {
  595. dprintf("\tInvalid command [%s]\n", lpArgumentString);
  596. }
  597. }
  598. }