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.

615 lines
15 KiB

  1. #include <nt.h>
  2. #include <ntrtl.h>
  3. #include <nturtl.h>
  4. #include <ntverp.h>
  5. #include <windef.h>
  6. #include <winbase.h>
  7. #include <stdio.h>
  8. #include <wdbgexts.h>
  9. //
  10. // globals
  11. //
  12. EXT_API_VERSION ApiVersion = {
  13. (VER_PRODUCTVERSION_W >> 8),
  14. (VER_PRODUCTVERSION_W & 0xff),
  15. EXT_API_VERSION_NUMBER64,
  16. 0
  17. };
  18. WINDBG_EXTENSION_APIS ExtensionApis;
  19. USHORT SavedMajorVersion;
  20. USHORT SavedMinorVersion;
  21. //
  22. // Names of interesting structures
  23. //
  24. CHAR * NDIS_PROTOCOL_BLOCK_NAME = "_NDIS_PROTOCOL_BLOCK";
  25. CHAR * NDIS_STRING_NAME = "_UNICODE_STRING";
  26. CHAR * NDIS_OPEN_BLOCK_NAME = "_NDIS_OPEN_BLOCK";
  27. CHAR * NDIS_MINIPORT_BLOCK_NAME = "_NDIS_MINIPORT_BLOCK";
  28. CHAR * NDIS_COMMON_OPEN_BLOCK_NAME = "_NDIS_COMMON_OPEN_BLOCK";
  29. DllInit(
  30. HANDLE hModule,
  31. DWORD dwReason,
  32. DWORD dwReserved
  33. )
  34. {
  35. if (dwReason == DLL_PROCESS_ATTACH) {
  36. DisableThreadLibraryCalls(hModule);
  37. }
  38. return TRUE;
  39. }
  40. VOID
  41. WinDbgExtensionDllInit(
  42. PWINDBG_EXTENSION_APIS64 lpExtensionApis,
  43. USHORT MajorVersion,
  44. USHORT MinorVersion
  45. )
  46. {
  47. ExtensionApis = *lpExtensionApis;
  48. SavedMajorVersion = MajorVersion;
  49. SavedMinorVersion = MinorVersion;
  50. return;
  51. }
  52. VOID
  53. CheckVersion(
  54. VOID
  55. )
  56. {
  57. return;
  58. }
  59. LPEXT_API_VERSION
  60. ExtensionApiVersion(
  61. VOID
  62. )
  63. {
  64. return &ApiVersion;
  65. }
  66. const char *retstr[] = {
  67. "?",
  68. "memory read error",
  69. "symbol type index not found",
  70. "symbol type info not found",
  71. "fields did not match",
  72. "null sym dump param",
  73. "null field name",
  74. "incorrect version info",
  75. "exit on controlc",
  76. "cannot allocate memory",
  77. "insufficient space to copy",
  78. };
  79. DECLARE_API( help )
  80. {
  81. dprintf("dtext debugger extension commands:\n\n");
  82. dprintf(" find <type> - Enumerate all objects of a given type\n");
  83. dprintf(" find <type> <field> <op> <value> - Search for object matching condition\n");
  84. dprintf(" refcounts - Dump refcounts for NDIS (TCPIP-only) and WANARP\n");
  85. return;
  86. }
  87. //
  88. // List of operators recognized by !find command
  89. //
  90. char *validops[] = {
  91. "==",
  92. "!=",
  93. "T",
  94. NULL
  95. };
  96. #define OP_EQUAL 0
  97. #define OP_NOT_EQUAL 1
  98. #define OP_TRUE 2
  99. //
  100. // List of types recognized by !find command
  101. //
  102. char *validtypes[] = {
  103. "ao",
  104. "IGMPAddr",
  105. "nte",
  106. NULL
  107. };
  108. #define TYP_AO 0
  109. #define TYP_IGMP_ADDR 1
  110. #define TYP_NTE 2
  111. void
  112. ProcessRecord(
  113. ULONG64 Addr,
  114. char *structstr,
  115. char *fieldstr,
  116. int op,
  117. ULONG64 value
  118. )
  119. {
  120. ULONG64 actual;
  121. int ret;
  122. char buff[80];
  123. SYM_DUMP_PARAM Sym = {
  124. sizeof(SYM_DUMP_PARAM),
  125. structstr,
  126. 0,
  127. Addr,
  128. NULL, NULL, NULL, 0, NULL
  129. };
  130. if (op != OP_TRUE) {
  131. GetFieldValue(Addr, structstr, fieldstr, actual);
  132. }
  133. switch (op) {
  134. case OP_EQUAL:
  135. if (actual != value)
  136. return;
  137. break;
  138. case OP_NOT_EQUAL:
  139. if (actual == value)
  140. return;
  141. break;
  142. case OP_TRUE:
  143. break;
  144. }
  145. //
  146. // Dump the type
  147. //
  148. dprintf("Found %p:\n", Addr);
  149. Ioctl(IG_DUMP_SYMBOL_INFO, &Sym, Sym.size);
  150. dprintf("\n");
  151. }
  152. //
  153. // Unfortunately, there's no way (that I know of) to tell
  154. // when this changes in tcpip.sys, so for now we hard code this.
  155. //
  156. #define IGMP_TABLE_SIZE 32
  157. void
  158. ForEachIGMPAddr(
  159. char *fieldstr,
  160. int op,
  161. ULONG64 value)
  162. {
  163. ULONG64 Table, Addr, NTE, NetTable;
  164. ULONG Offset;
  165. ULONG Size, i, j;
  166. ULONG Stride;
  167. char buff[80];
  168. ULONG NetTableSize;
  169. Size = IGMP_TABLE_SIZE;
  170. if ((op!=OP_TRUE) && GetFieldOffset("tcpip!IGMPAddr", fieldstr, &Offset) != 0) {
  171. dprintf("Can't get offset of %s in IGMPAddr block!\n", fieldstr);
  172. return;
  173. }
  174. Stride = GetTypeSize("PVOID");
  175. NetTableSize = (ULONG)GetExpression("poi(tcpip!NET_TABLE_SIZE)");
  176. //
  177. // Walk NTE list
  178. //
  179. NetTable = GetExpression("poi(tcpip!NewNetTableList)");
  180. for (j=0; j<NetTableSize; j++) {
  181. if (CheckControlC())
  182. break;
  183. sprintf(buff, "poi(%p)", NetTable + j * Stride);
  184. NTE = GetExpression(buff);
  185. while (NTE) {
  186. if (CheckControlC())
  187. break;
  188. GetFieldValue(NTE, "tcpip!NetTableEntry", "nte_igmplist", Table);
  189. for (i=0; i<Size; i++) {
  190. if (CheckControlC())
  191. break;
  192. //
  193. // Walk IGMPAddr list
  194. //
  195. sprintf(buff, "poi(%p)", Table + i * Stride);
  196. Addr = GetExpression(buff);
  197. while (Addr) {
  198. if (CheckControlC())
  199. break;
  200. ProcessRecord(Addr, "tcpip!IGMPAddr", fieldstr, op, value);
  201. GetFieldValue(Addr, "tcpip!IGMPAddr", "iga_next", Addr);
  202. }
  203. }
  204. GetFieldValue(NTE, "tcpip!NetTableEntry", "nte_next", NTE);
  205. }
  206. }
  207. }
  208. void
  209. ForEachNTE(
  210. char *fieldstr,
  211. int op,
  212. ULONG64 value
  213. )
  214. {
  215. ULONG64 Table, Addr, NTE, NetTable;
  216. ULONG Offset;
  217. ULONG i, j;
  218. ULONG Stride;
  219. char buff[80];
  220. ULONG NetTableSize;
  221. if ((op!=OP_TRUE) && GetFieldOffset("tcpip!NetTableEntry", fieldstr, &Offset) != 0) {
  222. dprintf("Can't get offset of %s in NetTableEntry block!\n", fieldstr);
  223. return;
  224. }
  225. Stride = GetTypeSize("PVOID");
  226. NetTableSize = (ULONG)GetExpression("poi(tcpip!NET_TABLE_SIZE)");
  227. //
  228. // Walk NTE list
  229. //
  230. NetTable = GetExpression("poi(tcpip!NewNetTableList)");
  231. for (j=0; j<NetTableSize; j++) {
  232. if (CheckControlC())
  233. break;
  234. sprintf(buff, "poi(%p)", NetTable + j * Stride);
  235. NTE = GetExpression(buff);
  236. while (NTE) {
  237. if (CheckControlC())
  238. break;
  239. ProcessRecord(NTE, "tcpip!NetTableEntry", fieldstr, op, value);
  240. GetFieldValue(NTE, "tcpip!NetTableEntry", "nte_next", NTE);
  241. }
  242. }
  243. }
  244. void
  245. ForEachAO(
  246. char *fieldstr,
  247. int op,
  248. ULONG64 value
  249. )
  250. {
  251. ULONG64 Table, Addr;
  252. ULONG Offset;
  253. ULONG Size, i;
  254. ULONG Stride;
  255. char buff[80];
  256. if ((op!=OP_TRUE) && GetFieldOffset("tcpip!AddrObj", fieldstr, &Offset) != 0) {
  257. dprintf("Can't get offset of %s in AddrObj block!\n", fieldstr);
  258. return;
  259. }
  260. Stride = GetTypeSize("PVOID");
  261. // Get tcpip!AddrObjTableSize
  262. Size = (ULONG)GetExpression("poi(tcpip!AddrObjTableSize)");
  263. // Get tcpip!AddrObjTable
  264. Table = GetExpression("poi(tcpip!AddrObjTable)");
  265. // for each table entry
  266. for (i=0; i<Size; i++) {
  267. if (CheckControlC())
  268. break;
  269. // Walk AO list
  270. sprintf(buff, "poi(%p)", Table + i * Stride);
  271. Addr = GetExpression(buff);
  272. while (Addr) {
  273. if (CheckControlC())
  274. break;
  275. ProcessRecord(Addr, "tcpip!AddrObj", fieldstr, op, value);
  276. GetFieldValue(Addr, "tcpip!AddrObj", "ao_next", Addr);
  277. }
  278. }
  279. }
  280. DECLARE_API( find )
  281. {
  282. char typestr[80], fieldstr[80], opstr[80], valuestr[80];
  283. int op, type;
  284. ULONG64 value;
  285. if (!args)
  286. return;
  287. if (sscanf(args, "%s%s%s%s", typestr, fieldstr, opstr, valuestr) != 4) {
  288. if (sscanf(args, "%s", typestr) != 1) {
  289. dprintf("usage: find <type> <field> <op> <value>\n");
  290. return;
  291. }
  292. op = OP_TRUE;
  293. } else {
  294. //
  295. // Validate op argument
  296. //
  297. for (op=0; validops[op]; op++) {
  298. if (!_stricmp(validops[op], opstr))
  299. break;
  300. }
  301. if (!validops[op]) {
  302. dprintf("Invalid <op> value. Valid values are:\n");
  303. for (op=0; validops[op]; op++)
  304. dprintf(" %s\n", validops[op]);
  305. return;
  306. }
  307. }
  308. //
  309. // Validate type argument
  310. //
  311. for (type=0; validtypes[type]; type++) {
  312. if (!_stricmp(validtypes[type], typestr))
  313. break;
  314. }
  315. if (!validtypes[type]) {
  316. dprintf("Invalid <type> value. Valid values are:\n");
  317. for (type=0; validtypes[type]; type++)
  318. dprintf(" %s\n", validtypes[type]);
  319. return;
  320. }
  321. //
  322. // Parse valuestr
  323. //
  324. value = GetExpression(valuestr);
  325. switch(type) {
  326. case TYP_AO:
  327. ForEachAO(fieldstr, op, value);
  328. break;
  329. case TYP_IGMP_ADDR:
  330. ForEachIGMPAddr(fieldstr, op, value);
  331. break;
  332. case TYP_NTE:
  333. ForEachNTE(fieldstr, op, value);
  334. break;
  335. }
  336. return;
  337. }
  338. //
  339. // Get 'size' bytes from the debuggee program at 'dwAddress' and place it
  340. // in our address space at 'ptr'. Use 'type' in an error printout if necessary
  341. //
  342. // This function was stolen from ndiskd
  343. //
  344. BOOL
  345. GetData(
  346. IN LPVOID ptr,
  347. IN ULONG64 dwAddress,
  348. IN ULONG size,
  349. IN PCSTR type
  350. )
  351. {
  352. BOOL b;
  353. ULONG BytesRead;
  354. ULONG count = size;
  355. while (size > 0) {
  356. if (count >= 3000)
  357. count = 3000;
  358. b = ReadMemory(dwAddress, ptr, count, &BytesRead );
  359. if (!b || BytesRead != count) {
  360. dprintf( "Unable to read %u bytes at %lX, for %s\n", size, dwAddress,
  361. type );
  362. return FALSE;
  363. }
  364. dwAddress += count;
  365. size -= count;
  366. ptr = (LPVOID)((ULONG_PTR)ptr + count);
  367. }
  368. return TRUE;
  369. }
  370. #define MAX_STRING_LENGTH 256
  371. //
  372. // This function was stolen from ndiskd
  373. //
  374. BOOL
  375. GetName(
  376. ULONG64 UnicodeStringAddr,
  377. UCHAR *abuf
  378. )
  379. {
  380. USHORT i;
  381. WCHAR ubuf[MAX_STRING_LENGTH];
  382. ULONG MaxChars;
  383. ULONG64 BufAddr;
  384. USHORT Length;
  385. USHORT MaximumLength;
  386. ULONG64 Val;
  387. GetFieldValue(UnicodeStringAddr, NDIS_STRING_NAME, "Buffer", Val);
  388. BufAddr = Val;
  389. GetFieldValue(UnicodeStringAddr, NDIS_STRING_NAME, "Length", Val);
  390. Length = (USHORT)Val;
  391. GetFieldValue(UnicodeStringAddr, NDIS_STRING_NAME, "MaximumLength", Val);
  392. MaximumLength = (USHORT)Val;
  393. //
  394. // Truncate so that we don't crash with bad data.
  395. //
  396. MaxChars = (Length > MAX_STRING_LENGTH)? MAX_STRING_LENGTH: Length;
  397. if (!GetData(ubuf, BufAddr, MaxChars, "STRING")) {
  398. return FALSE;
  399. }
  400. for (i = 0; i < Length/2; i++) {
  401. abuf[i] = (UCHAR)ubuf[i];
  402. }
  403. abuf[i] = 0;
  404. return TRUE;
  405. }
  406. //
  407. // This function was stolen from ndiskd
  408. //
  409. BOOL
  410. PrintName(
  411. ULONG64 UnicodeStringAddr
  412. )
  413. {
  414. UCHAR abuf[MAX_STRING_LENGTH+1];
  415. if (!GetName(UnicodeStringAddr, abuf))
  416. return FALSE;
  417. dprintf("%s", abuf);
  418. return TRUE;
  419. }
  420. DECLARE_API( refcounts )
  421. {
  422. ULONG64 Addr;
  423. LONG sent, done;
  424. ULONG ret, ret2;
  425. ULONG64 ProtocolListAddr;
  426. ULONG64 ProtocolAddr, ProtocolAddr2, OpenAddr, MiniportAddr;
  427. ULONG Offset;
  428. ULONG64 Val;
  429. ULONG64 Refs;
  430. UCHAR abuf[MAX_STRING_LENGTH+1];
  431. //
  432. // Check LANARP refcounts
  433. //
  434. if (!GetExpressionEx("ndis!ndisProtocolList", &ProtocolListAddr, NULL)) {
  435. dprintf("failed to locate ndis!ndisProtocolList\n");
  436. return;
  437. }
  438. ReadPtr(ProtocolListAddr, &ProtocolAddr);
  439. while (ProtocolAddr != 0) {
  440. if (CheckControlC())
  441. break;
  442. if (GetFieldOffset(NDIS_PROTOCOL_BLOCK_NAME,
  443. "ProtocolCharacteristics.Name", &Offset) != 0)
  444. {
  445. dprintf("Cant get offset of Name in Protocol block!");
  446. return;
  447. }
  448. //
  449. // Get protocol name
  450. //
  451. if (!GetName(ProtocolAddr + Offset, abuf)) {
  452. dprintf("Cant get Name in Protocol block!");
  453. return;
  454. }
  455. if (_stricmp(abuf, "TCPIP") && _stricmp(abuf, "TCPIP_WANARP")) {
  456. // dprintf("Skipping ndis protocol %s...\n", abuf);
  457. ret = GetFieldValue(ProtocolAddr, NDIS_PROTOCOL_BLOCK_NAME,
  458. "NextProtocol", ProtocolAddr);
  459. if (ret)
  460. dprintf("get NextProtocol failed, ret=%d\n", ret);
  461. continue;
  462. }
  463. dprintf("protocol %p: %s\n", ProtocolAddr, abuf);
  464. ret = GetFieldValue(ProtocolAddr, NDIS_PROTOCOL_BLOCK_NAME, "OpenQueue",
  465. OpenAddr);
  466. if (ret)
  467. dprintf("get OpenQueue failed, ret=%d\n", ret);
  468. while (OpenAddr) {
  469. if (CheckControlC())
  470. break;
  471. //
  472. // Sanity check back pointer
  473. //
  474. ret = GetFieldValue(OpenAddr, NDIS_COMMON_OPEN_BLOCK_NAME,
  475. "ProtocolHandle", ProtocolAddr2);
  476. if (ret)
  477. dprintf("get ProtocolHandle failed, ret=%d\n", ret);
  478. if (ProtocolAddr2 != ProtocolAddr) {
  479. dprintf("mopen linkage error protocol %p mopen %p protocol %p\n",
  480. ProtocolAddr, OpenAddr, ProtocolAddr2);
  481. break;
  482. }
  483. ret = GetFieldValue(OpenAddr, NDIS_COMMON_OPEN_BLOCK_NAME,
  484. "MiniportHandle", MiniportAddr);
  485. if (ret)
  486. dprintf("get MiniportHandle failed, ret=%d\n", ret);
  487. ret = GetFieldValue(MiniportAddr, NDIS_MINIPORT_BLOCK_NAME,
  488. "pAdapterInstanceName", Val);
  489. if (ret)
  490. dprintf("get pAdapterInstanceName failed, ret=%d\n", ret);
  491. dprintf(" miniport %p : ", MiniportAddr);
  492. PrintName(Val);
  493. ret = GetFieldValue(OpenAddr, NDIS_COMMON_OPEN_BLOCK_NAME,
  494. "References", Refs);
  495. if (ret)
  496. dprintf("get References failed, ret=%d\n", ret);
  497. dprintf("\n mopen %p references : %I64d\n", OpenAddr, Refs);
  498. ret = GetFieldValue(OpenAddr, NDIS_COMMON_OPEN_BLOCK_NAME,
  499. "ProtocolNextOpen", OpenAddr);
  500. if (ret)
  501. dprintf("get ProtocolNextOpen failed, ret=%d\n", ret);
  502. }
  503. ret = GetFieldValue(ProtocolAddr, NDIS_PROTOCOL_BLOCK_NAME,
  504. "NextProtocol", ProtocolAddr);
  505. if (ret)
  506. dprintf("get NextProtocol failed, ret=%d\n", ret);
  507. }
  508. //
  509. // Check WANARP refcounts
  510. //
  511. if (!GetExpressionEx("ndiswan!glsendcount", &Addr, NULL)) {
  512. dprintf("failed to locate ndiswan!glsendcount\n");
  513. return;
  514. }
  515. ReadMemory(Addr, &sent, sizeof(sent), NULL);
  516. Addr = GetExpression("ndiswan!glsendcompletecount");
  517. ReadMemory(Addr, &done, sizeof(done), NULL);
  518. dprintf("WANARP: references : %ld\n", sent-done);
  519. return;
  520. }