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.

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