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.

735 lines
19 KiB

  1. /*++
  2. Copyright (c) 1992 Microsoft Corporation
  3. Module Name:
  4. FilmonKd.c
  5. Abstract:
  6. KD Extension Api for examining FileSpy specific data structures.
  7. Note: While this extension can only build in the Windows XP and Server 2003
  8. environments, it can still be used to debug a version of this FileSpy
  9. sample built for Windows 2000.
  10. // @@BEGIN_DDKSPLIT
  11. Author:
  12. Molly Brown [MollyBro] 29-Apr-99
  13. Revision History:
  14. Port to platform independent -
  15. Ravisankar Pudipeddi [ravisp] 3-March-01
  16. // @@END_DDKSPLIT
  17. Environment:
  18. User Mode.
  19. --*/
  20. #include "pch.h"
  21. //
  22. // Windows.h doesn't include this definition
  23. //
  24. typedef struct _UNICODE_STRING {
  25. USHORT Length;
  26. USHORT MaximumLength;
  27. PWSTR Buffer;
  28. } UNICODE_STRING, *PUNICODE_STRING;
  29. #ifndef MAX
  30. #define MAX(a,b) (((a) > (b))?(a):(b))
  31. #endif
  32. /****************************************************************************
  33. Typedefs and constants
  34. ****************************************************************************/
  35. typedef PVOID (*PSTRUCT_DUMP_ROUTINE)(
  36. IN ULONG64 Address,
  37. IN LONG Options,
  38. USHORT Processor,
  39. HANDLE hCurrentThread
  40. );
  41. //
  42. // The help strings printed out
  43. //
  44. static LPSTR Extensions[] = {
  45. "FileSpy Debugger Extensions:\n",
  46. "attachments [1|2] Dump all the devices FileSpy is attached to ",
  47. "devext [address] [1|2] Dump FileSpy device extension",
  48. "filenames [1|2] Dumps all the file names cached",
  49. 0
  50. };
  51. /******************************************************************************
  52. Function prototypes
  53. ******************************************************************************/
  54. VOID
  55. PrintHelp (
  56. VOID
  57. );
  58. /******************************************************************************
  59. Useful macros
  60. ******************************************************************************/
  61. #define xGetFieldValue(Address, Type, Field, Value) \
  62. { \
  63. if (GetFieldValue(Address, Type, Field, Value)) { \
  64. dprintf("\nCould not read field %s of %s from address: %08p\n", \
  65. (Field), (Type), (Address)); \
  66. return; \
  67. } \
  68. }
  69. #define xGetFieldOffset(Type, Field, Offset) \
  70. { \
  71. if (GetFieldOffset(Type, Field, Offset)) { \
  72. dprintf("\nCould not read offset of field %s from type %s\n", \
  73. (Field), (Type)); \
  74. return; \
  75. } \
  76. }
  77. /*++
  78. /****************************************************************************
  79. Entry points, parameter parsers, etc. below
  80. ****************************************************************************/
  81. VOID
  82. DumpDeviceExtension (
  83. IN ULONG64 Address,
  84. IN LONG Options,
  85. USHORT Processor,
  86. HANDLE hCurrentThread
  87. )
  88. /*++
  89. Routine Description:
  90. Dump a specific device extension.
  91. Arguments:
  92. Address - Gives the address of the device extension to dump
  93. Return Value:
  94. None
  95. --*/
  96. {
  97. ULONG64 pointer, pName;
  98. UNICODE_STRING string1, string2;
  99. PUCHAR buffer;
  100. USHORT length;
  101. ULONG offset, offset2;
  102. ULONG result;
  103. BOOLEAN boolean;
  104. UNREFERENCED_PARAMETER( Processor );
  105. UNREFERENCED_PARAMETER( hCurrentThread );
  106. dprintf( "\nFileSpy device extension: %08p", Address );
  107. //
  108. // Dump the interesting parts of the device extension
  109. //
  110. if (Options <= 1) {
  111. //
  112. // Get the device name length
  113. //
  114. xGetFieldValue(Address, "FileSpy!_FILESPY_DEVICE_EXTENSION", "DeviceNames.Length", length);
  115. // Get offset, and addres of string
  116. //
  117. xGetFieldOffset("FileSpy!_FILESPY_DEVICE_EXTENSION", "DeviceNamesBuffer", &offset);
  118. pName = Address+offset;
  119. //
  120. // Allocate buffer to hold string.
  121. // We should not call any xGet* macros before freeing the buffer
  122. // as they might just return from the function on failure
  123. //
  124. buffer = LocalAlloc(LPTR, length);
  125. if (buffer == NULL) {
  126. return;
  127. }
  128. //
  129. // Read in the string: assuming it's NULL terminated here..
  130. //
  131. if (ReadMemory(pName,
  132. buffer,
  133. (ULONG) length,
  134. &result) && (result == (ULONG) length)) {
  135. string1.Length = string1.MaximumLength = length;
  136. string1.Buffer = (PWSTR) buffer;
  137. dprintf( "\n\t(%3x) %s %wZ",
  138. offset,
  139. "DeviceNames ",
  140. &string1);
  141. }
  142. //
  143. // Free the buffer
  144. //
  145. LocalFree(buffer);
  146. buffer = NULL;
  147. xGetFieldOffset("FileSpy!_FILESPY_DEVICE_EXTENSION", "LogThisDevice", &offset);
  148. xGetFieldValue(Address, "FileSpy!_FILESPY_DEVICE_EXTENSION", "LogThisDevice", boolean);
  149. dprintf( "\n\t(%3x) %s %s",
  150. offset,
  151. "LogThisDevice ",
  152. (boolean ? "TRUE" : "FALSE") );
  153. } else if (Options == 2) {
  154. dprintf( "\n\t(OFF) %s",
  155. "FIELD NAME VALUE");
  156. dprintf( "\n\t%s",
  157. "----------------------------------------------");
  158. xGetFieldOffset("FileSpy!_FILESPY_DEVICE_EXTENSION", "AttachedToDeviceObject", &offset);
  159. xGetFieldValue(Address, "FileSpy!_FILESPY_DEVICE_EXTENSION", "AttachedToDeviceObject", pointer);
  160. dprintf( "\n\t(%3x) %s %08p",
  161. offset,
  162. "AttachedToDeviceObject ",
  163. pointer);
  164. xGetFieldOffset("FileSpy!_FILESPY_DEVICE_EXTENSION", "DiskDeviceObject", &offset);
  165. xGetFieldValue(Address, "FileSpy!_FILESPY_DEVICE_EXTENSION", "DiskDeviceObject", pointer);
  166. dprintf( "\n\t(%3x) %s %08p",
  167. offset,
  168. "DiskDeviceObject ",
  169. pointer);
  170. xGetFieldOffset("FileSpy!_FILESPY_DEVICE_EXTENSION", "LogThisDevice", &offset);
  171. xGetFieldValue(Address, "FileSpy!_FILESPY_DEVICE_EXTENSION", "LogThisDevice", boolean);
  172. dprintf( "\n\t(%3x) %s %s",
  173. offset,
  174. "LogThisDevice ",
  175. (boolean ? "TRUE" : "FALSE") );
  176. xGetFieldOffset("FileSpy!_FILESPY_DEVICE_EXTENSION", "DeviceNames.Length", &offset);
  177. xGetFieldValue(Address, "FileSpy!_FILESPY_DEVICE_EXTENSION", "DeviceNames.Length", length);
  178. dprintf( "\n\t(%3x) %s %04x",
  179. offset,
  180. "DeviceNames.Length(bytes) ",
  181. length);
  182. //
  183. // Save buffersize, since we need it later to print the string
  184. //
  185. string1.Length = string1.MaximumLength = length;
  186. xGetFieldOffset("FileSpy!_FILESPY_DEVICE_EXTENSION", "DeviceNames.MaximumLength", &offset);
  187. xGetFieldValue(Address, "FileSpy!_FILESPY_DEVICE_EXTENSION", "DeviceNames.MaximumLength", length);
  188. dprintf( "\n\t(%3x) %s %04x",
  189. offset,
  190. "DeviceNames.MaximumLength(bytes) ",
  191. length);
  192. xGetFieldOffset("FileSpy!_FILESPY_DEVICE_EXTENSION", "DeviceNames.Buffer", &offset);
  193. xGetFieldValue(Address, "FileSpy!_FILESPY_DEVICE_EXTENSION", "DeviceNames.Buffer", pointer);
  194. dprintf( "\n\t(%3x) %s %08p",
  195. offset,
  196. "DeviceNames.Buffer ",
  197. pointer);
  198. xGetFieldOffset("FileSpy!_FILESPY_DEVICE_EXTENSION", "UserNames.Length", &offset);
  199. xGetFieldValue(Address, "FileSpy!_FILESPY_DEVICE_EXTENSION", "UserNames.Length", length);
  200. dprintf( "\n\t(%3x) %s %04x",
  201. offset,
  202. "UserNames.Length(bytes) ",
  203. length);
  204. //
  205. // Update size of buffer needed
  206. //
  207. string2.Length = string2.MaximumLength = length;
  208. xGetFieldOffset("FileSpy!_FILESPY_DEVICE_EXTENSION", "UserNames.MaximumLength", &offset);
  209. xGetFieldValue(Address, "FileSpy!_FILESPY_DEVICE_EXTENSION", "UserNames.MaximumLength", length);
  210. dprintf( "\n\t(%3x) %s %04x",
  211. offset,
  212. "UserNames.MaximumLength(bytes) ",
  213. length);
  214. xGetFieldOffset("FileSpy!_FILESPY_DEVICE_EXTENSION", "UserNames.Buffer", &offset);
  215. xGetFieldValue(Address, "FileSpy!_FILESPY_DEVICE_EXTENSION", "UserNames.Buffer", pointer);
  216. dprintf( "\n\t(%3x) %s %08p",
  217. offset,
  218. "UserNames.Buffer ",
  219. pointer);
  220. //
  221. // Get the device names buffer offset
  222. //
  223. xGetFieldOffset("FileSpy!_FILESPY_DEVICE_EXTENSION", "DeviceNamesBuffer", &offset);
  224. pName = Address+offset;
  225. //
  226. // Get the user names buffer offset
  227. //
  228. xGetFieldOffset("FileSpy!_FILESPY_DEVICE_EXTENSION", "UserNamesBuffer", &offset2);
  229. //
  230. // Allocate buffer large enough to hold the largest string
  231. // we will serialize access to it
  232. //
  233. buffer = LocalAlloc(LPTR, MAX(string1.MaximumLength,
  234. string2.MaximumLength));
  235. if (buffer == NULL) {
  236. return;
  237. }
  238. string1.Buffer = string2.Buffer = (PWSTR) buffer;
  239. if (ReadMemory(pName,
  240. buffer,
  241. string1.Length,
  242. &result) && (result == string1.Length)) {
  243. dprintf( "\n\t(%3x) %s %wZ",
  244. offset,
  245. "DeviceNames ",
  246. &string1);
  247. }
  248. pName = Address+offset2;
  249. if (ReadMemory(pName,
  250. buffer,
  251. string2.Length,
  252. &result) && (result == string2.Length)) {
  253. dprintf( "\n\t(%3x) %s %wZ",
  254. offset2,
  255. "UserNames ",
  256. &string2);
  257. }
  258. LocalFree(buffer);
  259. buffer = NULL;
  260. } else {
  261. dprintf ("\nNot a valid option");
  262. }
  263. dprintf( "\n" );
  264. }
  265. VOID
  266. DumpAttachments (
  267. IN LONG Options,
  268. USHORT Processor,
  269. HANDLE hCurrentThread
  270. )
  271. /*++
  272. Routine Description:
  273. Dump the list of attached devices that is global to FileSpy.
  274. Arguments:
  275. Options - Ignored for now
  276. Return Value:
  277. None
  278. --*/
  279. {
  280. ULONG64 address, next;
  281. ULONG64 deviceExtensionAddress;
  282. ULONG linkOffset;
  283. UNREFERENCED_PARAMETER( Processor );
  284. UNREFERENCED_PARAMETER( hCurrentThread );
  285. address = GetExpression( "FileSpy!gSpyDeviceExtensionList" );
  286. dprintf( "\nAttachedDeviceList: %08p", address );
  287. //
  288. // Establish offset of the linking entry..
  289. //
  290. xGetFieldOffset("FileSpy!_FILESPY_DEVICE_EXTENSION", "NextFileSpyDeviceLink", &linkOffset);
  291. xGetFieldValue(address, "nt!_LIST_ENTRY", "Flink", next);
  292. while (next != address) {
  293. deviceExtensionAddress = (next - linkOffset);
  294. // i.e., CONTAINING_RECORD( next, _FILESPY_DEVICE_EXTENSION, NextFileSpyDeviceLink );
  295. DumpDeviceExtension(
  296. deviceExtensionAddress,
  297. Options,
  298. Processor,
  299. hCurrentThread );
  300. if (CheckControlC()) {
  301. return;
  302. }
  303. xGetFieldValue(next, "nt!_LIST_ENTRY", "Flink", next);
  304. }
  305. }
  306. VOID
  307. DumpFileNameCache (
  308. IN LONG Options,
  309. USHORT Processor,
  310. HANDLE hCurrentThread
  311. )
  312. /*++
  313. Routine Description:
  314. Dump all the fileObjects and file names that are currently in the
  315. file name cache
  316. Arguments:
  317. Options - 1 dumps just the file objects and file names
  318. 2 dumps the hash bucket labels along with the file objects
  319. and file names
  320. Return Value:
  321. None
  322. --*/
  323. {
  324. ULONG64 address;
  325. ULONG64 next;
  326. ULONG64 pName;
  327. ULONG64 fileObject;
  328. ULONG64 pHashEntry;
  329. ULONG length;
  330. ULONG result;
  331. ULONG linkOffset;
  332. UNICODE_STRING string;
  333. LIST_ENTRY64 listEntry;
  334. PUCHAR buffer;
  335. INT i;
  336. ULONG nameCount = 0;
  337. UNREFERENCED_PARAMETER( Processor );
  338. UNREFERENCED_PARAMETER( hCurrentThread );
  339. address = GetExpression( "FileSpy!gHashTable" );
  340. dprintf( "\nHashTable: %08p\n", address);
  341. dprintf( " FileObject Length FileName\n" );
  342. dprintf( " -----------------------------------------\n" );
  343. xGetFieldOffset("FileSpy!_HASH_ENTRY", "List", &linkOffset);
  344. for (i=0; i < HASH_SIZE; i++) {
  345. if (!ReadListEntry(address, &listEntry)) {
  346. dprintf("Can't read hash table\n");
  347. return;
  348. }
  349. if (Options > 1) {
  350. dprintf ("Hash Bucket[%3d]\n", i);
  351. }
  352. next = listEntry.Flink;
  353. while (next != address) {
  354. pHashEntry = next - linkOffset;// CONTAINING_RECORD( next, HASH_ENTRY, List );
  355. xGetFieldValue(pHashEntry, "FileSpy!_HASH_ENTRY", "FileObject", fileObject);
  356. xGetFieldValue(pHashEntry, "FileSpy!_HASH_ENTRY", "Name.Length", length);
  357. //
  358. // Get the names buffer pointer
  359. //
  360. xGetFieldValue(pHashEntry, "FileSpy!_HASH_ENTRY", "Name.Buffer", pName);
  361. //
  362. // Allocate buffer to hold the string
  363. //
  364. buffer = LocalAlloc(LPTR, length);
  365. if (buffer != NULL) {
  366. string.MaximumLength = string.Length = (USHORT) length;
  367. string.Buffer = (PWSTR) buffer;
  368. if (ReadMemory(pName,
  369. buffer,
  370. length,
  371. &result) && (result == length)) {
  372. dprintf (
  373. " %08p %4d %wZ\n",
  374. fileObject,
  375. length/sizeof(WCHAR),
  376. &string);
  377. }
  378. //
  379. // Free the buffer
  380. //
  381. LocalFree(buffer);
  382. buffer = NULL;
  383. } else {
  384. dprintf("\nCould not allocate buffer to hold filename\n");
  385. }
  386. nameCount ++;
  387. if (CheckControlC()) {
  388. dprintf("%u Names in cache\n", nameCount);
  389. return;
  390. }
  391. if (!ReadListEntry(next, &listEntry)) {
  392. dprintf("Can't read hash table\n");
  393. return;
  394. }
  395. next = listEntry.Flink;
  396. }
  397. //
  398. // Advance address to next hash entry
  399. //
  400. if (IsPtr64()) {
  401. address += sizeof(LIST_ENTRY64);
  402. } else {
  403. address += sizeof(LIST_ENTRY);
  404. }
  405. }
  406. dprintf("%u Names in cache\n", nameCount);
  407. }
  408. VOID
  409. ParseAndDump (
  410. IN PCSTR args,
  411. IN PSTRUCT_DUMP_ROUTINE DumpFunction,
  412. USHORT Processor,
  413. HANDLE hCurrentThread
  414. )
  415. /*++
  416. Routine Description:
  417. Parse command line arguments and dump an ntfs structure.
  418. Arguments:
  419. Args - String of arguments to parse.
  420. DumpFunction - Function to call with parsed arguments.
  421. Return Value:
  422. None
  423. --*/
  424. {
  425. UCHAR StringStructToDump[1024]; // See other kd routines for size
  426. ULONG64 StructToDump = 0;
  427. LONG Options = 0;
  428. //
  429. // If the caller specified an address then that's the item we dump
  430. //
  431. if (args) {
  432. StructToDump = 0;
  433. Options = 0;
  434. StringStructToDump[0] = '\0';
  435. (VOID) sscanf(args,"%s %lx", StringStructToDump, &Options );
  436. StructToDump = GetExpression( StringStructToDump );
  437. if (StructToDump == 0){
  438. dprintf("unable to get expression %s\n",StringStructToDump);
  439. return;
  440. }
  441. (*DumpFunction) ( StructToDump, Options, Processor, hCurrentThread );
  442. dprintf( "\n" );
  443. } else {
  444. PrintHelp();
  445. }
  446. }
  447. VOID
  448. PrintHelp (
  449. VOID
  450. )
  451. /*++
  452. Routine Description:
  453. Dump out one line of help for each DECLARE_API
  454. Arguments:
  455. None
  456. Return Value:
  457. None
  458. --*/
  459. {
  460. int i;
  461. for( i=0; Extensions[i]; i++ )
  462. dprintf( " %s\n", Extensions[i] );
  463. }
  464. DECLARE_API( devext )
  465. /*++
  466. Routine Description:
  467. Dump device extension struct
  468. Arguments:
  469. arg - [Address] [options]
  470. Return Value:
  471. None
  472. --*/
  473. {
  474. UNREFERENCED_PARAMETER( dwCurrentPc );
  475. UNREFERENCED_PARAMETER( hCurrentProcess );
  476. ParseAndDump(
  477. args,
  478. (PSTRUCT_DUMP_ROUTINE) DumpDeviceExtension,
  479. (USHORT)dwProcessor,
  480. hCurrentThread );
  481. }
  482. DECLARE_API( attachments )
  483. /*++
  484. Routine Description:
  485. Dumps the list of devices we are currently attached to
  486. Arguments:
  487. arg - [options]
  488. Return Value:
  489. None
  490. --*/
  491. {
  492. LONG options = 0;
  493. UNREFERENCED_PARAMETER( dwCurrentPc );
  494. UNREFERENCED_PARAMETER( hCurrentProcess );
  495. (VOID)sscanf(args,"%lx", &options );
  496. DumpAttachments( options, (USHORT)dwProcessor, hCurrentThread );
  497. dprintf( "\n" );
  498. }
  499. DECLARE_API( filenames )
  500. /*++
  501. Routine Description:
  502. Dumps all the entries in the file name cache
  503. Arguments:
  504. arg -
  505. Return Value:
  506. None
  507. --*/
  508. {
  509. LONG options = 0;
  510. UNREFERENCED_PARAMETER( dwCurrentPc );
  511. UNREFERENCED_PARAMETER( hCurrentProcess );
  512. (VOID)sscanf(args,"%lx", &options );
  513. DumpFileNameCache(options, (USHORT)dwProcessor, hCurrentThread );
  514. }
  515. DECLARE_API( help )
  516. /*++
  517. Routine Description:
  518. Dump the help for this debugger extension module.
  519. Arguments:
  520. arg - None
  521. Return Value:
  522. None
  523. --*/
  524. {
  525. UNREFERENCED_PARAMETER( args );
  526. UNREFERENCED_PARAMETER( dwCurrentPc );
  527. UNREFERENCED_PARAMETER( hCurrentProcess );
  528. UNREFERENCED_PARAMETER( hCurrentThread );
  529. UNREFERENCED_PARAMETER( dwProcessor );
  530. PrintHelp();
  531. }