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.

1127 lines
50 KiB

  1. /*++
  2. Copyright (C) Microsoft Corporation, 1992 - 1999
  3. Module Name:
  4. classkd.c
  5. Abstract:
  6. Debugger Extension Api for interpretting scsiport structures
  7. Author:
  8. Peter Wieland (peterwie) 16-Oct-1995
  9. johnstra
  10. ervinp
  11. Environment:
  12. User Mode.
  13. Revision History:
  14. --*/
  15. #include "pch.h"
  16. #include "classpnp.h" // #defines ALLOCATE_SRB_FROM_POOL as needed
  17. #include "classp.h" // Classpnp's private definitions
  18. #include "cdrom.h"
  19. #include "classkd.h" // routines that are useful for all class drivers
  20. DECLARE_API(classext)
  21. /*++
  22. Routine Description:
  23. Dumps the device extension for a given device object, or dumps the
  24. given device extension
  25. Arguments:
  26. args - string containing the address of the device object or device
  27. extension
  28. Return Value:
  29. none
  30. --*/
  31. {
  32. ULONG64 devObjAddr = 0;
  33. ULONG64 detail = 0;
  34. ReloadSymbols("classpnp.sys");
  35. if (GetExpressionEx(args, &devObjAddr, &args))
  36. {
  37. GetExpressionEx(args, &detail, &args);
  38. }
  39. /*
  40. * Read the device object and extension into the debugger's address space.
  41. */
  42. if (devObjAddr == 0){
  43. /*
  44. * If this is the server version of classpnp with the global AllFdosList, display all class FDOs.
  45. */
  46. ClassTryShowAllFDOs((ULONG)detail);
  47. xdprintf(0, "\n usage: !classext <class fdo> <level [0-2]>\n\n");
  48. }
  49. else {
  50. CSHORT objType = GetUSHORTField(devObjAddr, "nt!_DEVICE_OBJECT", "Type");
  51. if (objType == IO_TYPE_DEVICE){
  52. ULONG64 devExtAddr;
  53. devExtAddr = GetULONGField(devObjAddr, "nt!_DEVICE_OBJECT", "DeviceExtension");
  54. if (devExtAddr != BAD_VALUE){
  55. ULONG64 commonExtAddr = devExtAddr;
  56. ULONG64 tmpDevObjAddr;
  57. BOOLEAN isFdo;
  58. /*
  59. * To sanity-check our device context, check that the 'DeviceObject' field matches our device object.
  60. */
  61. tmpDevObjAddr = GetULONGField(devExtAddr, "classpnp!_FUNCTIONAL_DEVICE_EXTENSION", "DeviceObject");
  62. isFdo = GetUCHARField(commonExtAddr, "classpnp!_COMMON_DEVICE_EXTENSION", "IsFdo");
  63. if ((tmpDevObjAddr == devObjAddr) && isFdo && (isFdo != BAD_VALUE)){
  64. ULONG64 fdoDataAddr;
  65. fdoDataAddr = GetULONGField(devExtAddr, "classpnp!_FUNCTIONAL_DEVICE_EXTENSION", "PrivateFdoData");
  66. if (fdoDataAddr != BAD_VALUE){
  67. ClassDumpFdoExtensionInternal(fdoDataAddr, (ULONG)detail, 0);
  68. ClassDumpFdoExtensionExternal(devExtAddr, (ULONG)detail, 0);
  69. }
  70. }
  71. else {
  72. dprintf("%08p is not a storage class FDO (for PDO information, use !classext on the parent FDO) \n", devObjAddr);
  73. dprintf(g_genericErrorHelpStr);
  74. }
  75. }
  76. }
  77. else {
  78. dprintf("Error: 0x%08p is not a device object\n", devObjAddr);
  79. dprintf(g_genericErrorHelpStr);
  80. }
  81. }
  82. return S_OK;
  83. }
  84. BOOLEAN ClassTryShowAllFDOs(ULONG Detail)
  85. {
  86. ULONG64 allFdosListAddr;
  87. BOOLEAN found = FALSE;
  88. allFdosListAddr = GetExpression("classpnp!AllFdosList");
  89. if (allFdosListAddr){
  90. ULONG64 listEntryAddr = GetULONGField(allFdosListAddr, "nt!_LIST_ENTRY", "Flink");
  91. dprintf("\n");
  92. if (listEntryAddr == BAD_VALUE){
  93. }
  94. else if (listEntryAddr == allFdosListAddr){
  95. dprintf(" No class FDOs found\n");
  96. }
  97. else {
  98. found = TRUE;
  99. do {
  100. ULONG64 fdoDataAddr = GetContainingRecord(listEntryAddr, "classpnp!_CLASS_PRIVATE_FDO_DATA", "AllFdosListEntry");
  101. if (fdoDataAddr == BAD_VALUE){
  102. break;
  103. }
  104. else {
  105. /*
  106. * We got the private FDO data struct.
  107. * Get the actual FDO from one of the TRANSFER_PACKETS.
  108. */
  109. ULONG numPackets = (ULONG)GetULONGField(fdoDataAddr, "classpnp!_CLASS_PRIVATE_FDO_DATA", "NumTotalTransferPackets");
  110. if ((numPackets != BAD_VALUE) && (numPackets > 0)){
  111. ULONG64 xferPktListHeadAddr = GetFieldAddr(fdoDataAddr, "classpnp!_CLASS_PRIVATE_FDO_DATA", "AllTransferPacketsList");
  112. if (xferPktListHeadAddr == BAD_VALUE){
  113. break;
  114. }
  115. else {
  116. ULONG64 pktListEntryAddr = GetULONGField(xferPktListHeadAddr, "nt!_LIST_ENTRY", "Flink");
  117. if (pktListEntryAddr == BAD_VALUE){
  118. break;
  119. }
  120. else {
  121. ULONG64 pktAddr = GetContainingRecord(pktListEntryAddr, "classpnp!_TRANSFER_PACKET", "AllPktsListEntry");
  122. if (pktAddr == BAD_VALUE){
  123. break;
  124. }
  125. else {
  126. ULONG64 fdoAddr = GetULONGField(pktAddr, "classpnp!_TRANSFER_PACKET", "Fdo");
  127. if (fdoAddr == BAD_VALUE){
  128. break;
  129. }
  130. else {
  131. /*
  132. * Got the FDO. Figure out if its a paging device.
  133. */
  134. BOOLEAN isPagingDevice = FALSE;
  135. ULONG64 devExtAddr = GetULONGField(fdoAddr, "nt!_DEVICE_OBJECT", "DeviceExtension");
  136. if (devExtAddr != BAD_VALUE)
  137. {
  138. ULONG64 commonExtAddr = devExtAddr;
  139. ULONG pagingPathCount = (ULONG)GetULONGField(commonExtAddr, "classpnp!_COMMON_DEVICE_EXTENSION", "PagingPathCount");
  140. if ((pagingPathCount != BAD_VALUE) && (pagingPathCount > 0))
  141. {
  142. isPagingDevice = TRUE;
  143. }
  144. }
  145. dprintf(" ' !scsikd.classext %08p ' (%c) ", fdoAddr, ((isPagingDevice) ? 'p' : ' '));
  146. ClassDumpIds(fdoAddr, 1);
  147. }
  148. }
  149. }
  150. }
  151. }
  152. else {
  153. break;
  154. }
  155. }
  156. listEntryAddr = GetULONGField(listEntryAddr, "nt!_LIST_ENTRY", "Flink");
  157. }
  158. while ((listEntryAddr != allFdosListAddr) && (listEntryAddr != BAD_VALUE));
  159. }
  160. }
  161. return found;
  162. }
  163. VOID
  164. ClassDumpFdoExtensionExternal(
  165. IN ULONG64 FdoExtAddr,
  166. IN ULONG Detail,
  167. IN ULONG Depth
  168. )
  169. {
  170. ULONG64 commonExtAddr = FdoExtAddr;
  171. ULONG64 mediaChangeInfoAddr;
  172. ULONG64 childPdoExtAddr;
  173. ULONG isRemoved;
  174. UCHAR isInitialized;
  175. ULONG removeLock;
  176. UCHAR currentState, previousState;
  177. ULONG64 lowerDevObjAddr;
  178. ULONG64 classDriverDataAddr;
  179. classDriverDataAddr = GetULONGField(commonExtAddr, "classpnp!_COMMON_DEVICE_EXTENSION", "DriverData");
  180. xdprintf(Depth, "\n");
  181. xdprintf(Depth, ""), dprintf("Classpnp _EXTERNAL_ data (ext=%08p, class DriverData=%08p):\n\n", FdoExtAddr, classDriverDataAddr);
  182. /*
  183. * Print the media change information (which only exists for removable media like cdrom)
  184. */
  185. mediaChangeInfoAddr = GetULONGField(FdoExtAddr, "classpnp!_FUNCTIONAL_DEVICE_EXTENSION", "MediaChangeDetectionInfo");
  186. if (mediaChangeInfoAddr != BAD_VALUE){
  187. if (mediaChangeInfoAddr){
  188. ULONG64 mediaChangeIrpAddr = GetULONGField(mediaChangeInfoAddr, "classpnp!_MEDIA_CHANGE_DETECTION_INFO", "MediaChangeIrp");
  189. UCHAR gesnSupported = GetUCHARField(mediaChangeInfoAddr, "classpnp!_MEDIA_CHANGE_DETECTION_INFO", "Gesn.Supported");
  190. xdprintf(Depth+1, ""), dprintf("MEDIA_CHANGE_DETECTION_INFO @ %08p:\n", mediaChangeInfoAddr);
  191. if (gesnSupported){
  192. xdprintf(Depth+2, "GESN is supported\n");
  193. }
  194. else {
  195. xdprintf(Depth+2, "GESN is NOT supported\n");
  196. }
  197. xdprintf(Depth+2, ""), dprintf("MediaChangeIrp = %08p\n", mediaChangeIrpAddr);
  198. xdprintf(Depth+2, ""), dprintf("(for more info, use 'dt classpnp!_MEDIA_CHANGE_DETECTION_INFO %08p')\n", mediaChangeInfoAddr);
  199. dprintf("\n");
  200. }
  201. else {
  202. xdprintf(Depth+1, "MediaChangeDetectionInfo is NULL\n");
  203. }
  204. }
  205. /*
  206. * Print the media type and geometry information
  207. */
  208. {
  209. ULONG64 geometryInfoAddr = GetFieldAddr(FdoExtAddr, "classpnp!_FUNCTIONAL_DEVICE_EXTENSION", "DiskGeometry");
  210. if (geometryInfoAddr != BAD_VALUE){
  211. ULONG64 numCylinders = GetULONGField(geometryInfoAddr, "classpnp!_DISK_GEOMETRY", "Cylinders");
  212. ULONG mediaType = (ULONG)GetULONGField(geometryInfoAddr, "classpnp!_DISK_GEOMETRY", "MediaType");
  213. ULONG64 tracksPerCylinder = GetULONGField(geometryInfoAddr, "classpnp!_DISK_GEOMETRY", "TracksPerCylinder");
  214. ULONG64 sectorsPerTrack = GetULONGField(geometryInfoAddr, "classpnp!_DISK_GEOMETRY", "SectorsPerTrack");
  215. ULONG64 bytesPerSector = GetULONGField(geometryInfoAddr, "classpnp!_DISK_GEOMETRY", "BytesPerSector");
  216. if ((numCylinders != BAD_VALUE) && (mediaType != BAD_VALUE) && (tracksPerCylinder != BAD_VALUE) && (sectorsPerTrack != BAD_VALUE) && (bytesPerSector != BAD_VALUE)){
  217. ULONG64 totalVolume = numCylinders*tracksPerCylinder*sectorsPerTrack*bytesPerSector;
  218. xdprintf(Depth+1, ""), dprintf("Media type: %s(%xh)\n", DbgGetMediaTypeStr(mediaType), mediaType);
  219. xdprintf(Depth+1, ""), dprintf("Geometry: %d(%xh)cyl x %d(%xh)tracks x %d(%xh)sectors x %d(%xh)bytes\n",
  220. (ULONG)numCylinders, (ULONG)numCylinders,
  221. (ULONG)tracksPerCylinder, (ULONG)tracksPerCylinder,
  222. (ULONG)sectorsPerTrack, (ULONG)sectorsPerTrack,
  223. (ULONG)bytesPerSector, (ULONG)bytesPerSector);
  224. xdprintf(Depth+1+4, ""), dprintf("= %x'%xh", (ULONG)(totalVolume>>32), (ULONG)totalVolume);
  225. if (totalVolume > (((ULONG64)1) << 30)){
  226. dprintf(" = ~%d GB\n", (ULONG)(totalVolume >> 30));
  227. }
  228. else {
  229. dprintf(" = ~%d MB\n", (ULONG)(totalVolume >> 20));
  230. }
  231. }
  232. }
  233. }
  234. /*
  235. * Print 'IsInitialized' state.
  236. */
  237. isInitialized = GetUCHARField(commonExtAddr, "classpnp!_COMMON_DEVICE_EXTENSION", "IsInitialized");
  238. xdprintf(Depth+1, "IsInitialized = %d\n", isInitialized);
  239. /*
  240. * Print the 'IsRemoved' state.
  241. */
  242. isRemoved = (ULONG)GetULONGField(commonExtAddr, "classpnp!_COMMON_DEVICE_EXTENSION", "IsRemoved");
  243. removeLock = (ULONG)GetULONGField(commonExtAddr, "classpnp!_COMMON_DEVICE_EXTENSION", "RemoveLock");
  244. xdprintf(Depth+1, "Remove lock count = %d\n", removeLock);
  245. switch (isRemoved){
  246. #undef MAKE_CASE
  247. #define MAKE_CASE(remCase) case remCase: xdprintf(Depth+1, "IsRemoved = " #remCase "(%d)\n", isRemoved); break;
  248. MAKE_CASE(NO_REMOVE)
  249. MAKE_CASE(REMOVE_PENDING)
  250. MAKE_CASE(REMOVE_COMPLETE)
  251. }
  252. /*
  253. * Print the PnP state.
  254. */
  255. currentState = GetUCHARField(commonExtAddr, "classpnp!_COMMON_DEVICE_EXTENSION", "CurrentState");
  256. previousState = GetUCHARField(commonExtAddr, "classpnp!_COMMON_DEVICE_EXTENSION", "PreviousState");
  257. xdprintf(Depth+1, "PnP state: CurrentState:");
  258. switch (currentState){
  259. #undef MAKE_CASE
  260. #define MAKE_CASE(pnpCase) case pnpCase: xdprintf(0, #pnpCase "(%xh)", pnpCase); break;
  261. MAKE_CASE(IRP_MN_START_DEVICE)
  262. MAKE_CASE(IRP_MN_STOP_DEVICE)
  263. MAKE_CASE(IRP_MN_REMOVE_DEVICE)
  264. MAKE_CASE(IRP_MN_QUERY_STOP_DEVICE)
  265. MAKE_CASE(IRP_MN_QUERY_REMOVE_DEVICE)
  266. MAKE_CASE(IRP_MN_CANCEL_STOP_DEVICE)
  267. MAKE_CASE(IRP_MN_CANCEL_REMOVE_DEVICE)
  268. default: xdprintf(0, "???(%xh)", currentState); break;
  269. }
  270. xdprintf(0, " PreviousState:");
  271. switch (previousState){
  272. #undef MAKE_CASE
  273. #define MAKE_CASE(pnpCase) case pnpCase: xdprintf(0, #pnpCase "(%xh)", pnpCase); break;
  274. MAKE_CASE(IRP_MN_START_DEVICE)
  275. MAKE_CASE(IRP_MN_STOP_DEVICE)
  276. MAKE_CASE(IRP_MN_REMOVE_DEVICE)
  277. MAKE_CASE(IRP_MN_QUERY_STOP_DEVICE)
  278. MAKE_CASE(IRP_MN_QUERY_REMOVE_DEVICE)
  279. MAKE_CASE(IRP_MN_CANCEL_STOP_DEVICE)
  280. MAKE_CASE(IRP_MN_CANCEL_REMOVE_DEVICE)
  281. case 0x0FF: xdprintf(0, "(None)"); break;
  282. default: xdprintf(0, "???(%xh)", previousState); break;
  283. }
  284. xdprintf(0, "\n");
  285. /*
  286. * Print target device
  287. */
  288. lowerDevObjAddr = GetULONGField(commonExtAddr, "classpnp!_COMMON_DEVICE_EXTENSION", "LowerDeviceObject");
  289. xdprintf(Depth+1, ""), dprintf("Target device=%08p\n", lowerDevObjAddr);
  290. /*
  291. * Dump child PDO list
  292. */
  293. xdprintf(Depth+1, "Child PDOs:\n");
  294. childPdoExtAddr = GetULONGField(commonExtAddr, "classpnp!_COMMON_DEVICE_EXTENSION", "ChildList");
  295. while (childPdoExtAddr && (childPdoExtAddr != BAD_VALUE)){
  296. ULONG64 pdoAddr = GetULONGField(childPdoExtAddr, "classpnp!_PHYSICAL_DEVICE_EXTENSION", "DeviceObject");
  297. UCHAR isEnumerated = GetUCHARField(childPdoExtAddr, "classpnp!_PHYSICAL_DEVICE_EXTENSION", "IsEnumerated");
  298. UCHAR isMissing = GetUCHARField(childPdoExtAddr, "classpnp!_PHYSICAL_DEVICE_EXTENSION", "IsMissing");
  299. xdprintf(Depth+2, ""), dprintf("PDO=%08p IsEnumerated=%d IsMissing=%d\n", pdoAddr, isEnumerated, isMissing);
  300. childPdoExtAddr = GetULONGField(childPdoExtAddr, "classpnp!_PHYSICAL_DEVICE_EXTENSION", "CommonExtension.ChildList");
  301. }
  302. dprintf("\n");
  303. dprintf("\n");
  304. xdprintf(Depth+2, ""), dprintf("(for more info use 'dt classpnp!_FUNCTIONAL_DEVICE_EXTENSION %08p')\n", FdoExtAddr);
  305. xdprintf(0, "\n");
  306. }
  307. VOID
  308. ClassDumpFdoExtensionInternal(
  309. IN ULONG64 FdoDataAddr,
  310. IN ULONG Detail,
  311. IN ULONG Depth
  312. )
  313. {
  314. ULONG64 keTickCountAddr;
  315. ULONG keTickCount;
  316. ULONG len;
  317. dprintf("\n");
  318. xdprintf(Depth, ""), dprintf("Classpnp _INTERNAL_ data (%08p):\n", FdoDataAddr);
  319. /*
  320. * Dump TRANSFER_PACKET lists
  321. */
  322. ClassDumpTransferPacketLists(FdoDataAddr, Detail, Depth+1);
  323. /*
  324. * Dump private error logs
  325. */
  326. ClassDumpPrivateErrorLogs(FdoDataAddr, Detail, Depth+1);
  327. /*
  328. * Show time at trap (for comparison with error log timestamps)
  329. */
  330. keTickCountAddr = GetExpression("nt!KeTickCount");
  331. if (ReadMemory(keTickCountAddr, &keTickCount, sizeof(ULONG), &len)){
  332. dprintf("\n");
  333. xdprintf(Depth+1, ""), dprintf("KeTickCount at trap time: %d.%d (%04xh)\n", (ULONG)(keTickCount/1000), (ULONG)(keTickCount%1000), keTickCount);
  334. }
  335. /*
  336. * For full details on debug target, show the packet log
  337. */
  338. if (Detail >= 2) {
  339. ClassDumpPrivatePacketLogs(FdoDataAddr, Detail, Depth+1);
  340. }
  341. dprintf("\n");
  342. xdprintf(Depth+2, ""), dprintf("(for more info use 'dt classpnp!_CLASS_PRIVATE_FDO_DATA %08p')\n", FdoDataAddr);
  343. }
  344. VOID ClassDumpTransferPacketLists(ULONG64 FdoDataAddr, ULONG Detail, ULONG Depth)
  345. {
  346. ULONG64 allxferPktsListAddr;
  347. /*
  348. * Print transfer packet lists
  349. */
  350. allxferPktsListAddr = GetFieldAddr(FdoDataAddr, "classpnp!_CLASS_PRIVATE_FDO_DATA", "AllTransferPacketsList");
  351. if (allxferPktsListAddr != BAD_VALUE){
  352. ULONG64 listEntryAddr;
  353. ULONG numTotalXferPkts = (ULONG)GetULONGField(FdoDataAddr, "classpnp!_CLASS_PRIVATE_FDO_DATA", "NumTotalTransferPackets");
  354. ULONG numFreeXferPkts = (ULONG)GetULONGField(FdoDataAddr, "classpnp!_CLASS_PRIVATE_FDO_DATA", "NumFreeTransferPackets");
  355. ULONG numPackets;
  356. char *extraSpaces = IsPtr64() ? " " : "";
  357. /*
  358. * Walk AllTransferPacketsList and print only the outstanding packets with full SRB info.
  359. */
  360. xdprintf(Depth, "\n");
  361. xdprintf(Depth, "Outstanding transfer packets: (out of %d total)\n", numTotalXferPkts);
  362. xdprintf(Depth, "\n");
  363. xdprintf(Depth+1, " packet %s irp %s srb %s sense %s status \n", extraSpaces, extraSpaces, extraSpaces, extraSpaces);
  364. xdprintf(Depth+1, "--------%s --------%s --------%s --------%s -------- \n", extraSpaces, extraSpaces, extraSpaces, extraSpaces);
  365. numPackets = 0;
  366. listEntryAddr = GetULONGField(allxferPktsListAddr, "nt!_LIST_ENTRY", "Flink");
  367. while ((listEntryAddr != allxferPktsListAddr) && (listEntryAddr != BAD_VALUE)){
  368. ULONG64 pktAddr;
  369. pktAddr = GetContainingRecord(listEntryAddr, "classpnp!_TRANSFER_PACKET", "AllPktsListEntry");
  370. if (pktAddr == BAD_VALUE){
  371. break;
  372. }
  373. else {
  374. ClassDumpTransferPacket(pktAddr, TRUE, FALSE, TRUE, Depth+1);
  375. numPackets++;
  376. listEntryAddr = GetULONGField(listEntryAddr, "nt!_LIST_ENTRY", "Flink");
  377. }
  378. }
  379. if (numPackets != numTotalXferPkts){
  380. xdprintf(Depth, "*** Warning: NumTotalTransferPackets(%d) doesn't match length of queue(%d) ***\n", numTotalXferPkts, numPackets);
  381. }
  382. if (Detail > 0){
  383. ULONG64 slistEntryAddr;
  384. /*
  385. * Print all transfer packets
  386. */
  387. xdprintf(Depth, "\n");
  388. xdprintf(Depth, "All transfer packets: (%d total, %d free)\n", numTotalXferPkts, numFreeXferPkts);
  389. xdprintf(Depth, "\n");
  390. xdprintf(Depth+1, " packet %s irp %s srb %s sense %s status \n", extraSpaces, extraSpaces, extraSpaces, extraSpaces);
  391. xdprintf(Depth+1, "--------%s --------%s --------%s --------%s -------- \n", extraSpaces, extraSpaces, extraSpaces, extraSpaces);
  392. numPackets = 0;
  393. listEntryAddr = GetULONGField(allxferPktsListAddr, "nt!_LIST_ENTRY", "Flink");
  394. while ((listEntryAddr != allxferPktsListAddr) && (listEntryAddr != BAD_VALUE)){
  395. ULONG64 pktAddr;
  396. pktAddr = GetContainingRecord(listEntryAddr, "classpnp!_TRANSFER_PACKET", "AllPktsListEntry");
  397. if (pktAddr == BAD_VALUE){
  398. break;
  399. }
  400. else {
  401. ClassDumpTransferPacket(pktAddr, TRUE, TRUE, FALSE, Depth+1);
  402. listEntryAddr = GetULONGField(listEntryAddr, "nt!_LIST_ENTRY", "Flink");
  403. }
  404. }
  405. /*
  406. * Print free packets sList
  407. */
  408. xdprintf(Depth, "\n");
  409. xdprintf(Depth, "Free transfer packets in fast SLIST: (%d free)\n", numFreeXferPkts);
  410. if (IsPtr64()){
  411. xdprintf(Depth, "(Cannot display fast SLIST on 64-bit system)\n");
  412. }
  413. else {
  414. xdprintf(Depth+1, " packet %s irp %s srb %s sense %s status \n", extraSpaces, extraSpaces, extraSpaces, extraSpaces);
  415. xdprintf(Depth+1, "--------%s --------%s --------%s --------%s -------- \n", extraSpaces, extraSpaces, extraSpaces, extraSpaces);
  416. numPackets = 0;
  417. slistEntryAddr = GetULONGField(FdoDataAddr, "classpnp!_CLASS_PRIVATE_FDO_DATA", "FreeTransferPacketsList.Next.Next");
  418. while (slistEntryAddr && (slistEntryAddr != BAD_VALUE)){
  419. ULONG64 pktAddr;
  420. pktAddr = GetContainingRecord(slistEntryAddr, "classpnp!_TRANSFER_PACKET", "SlistEntry");
  421. if (pktAddr == BAD_VALUE){
  422. break;
  423. }
  424. else {
  425. ClassDumpTransferPacket(pktAddr, TRUE, TRUE, FALSE, Depth+1);
  426. numPackets++;
  427. slistEntryAddr = GetULONGField(pktAddr, "classpnp!_TRANSFER_PACKET", "SlistEntry.Next");
  428. }
  429. }
  430. if (numPackets != numFreeXferPkts){
  431. xdprintf(Depth, "*** Warning: NumFreeTransferPackets(%d) doesn't match length of queue(%d) ***\n", numFreeXferPkts, numPackets);
  432. }
  433. }
  434. }
  435. }
  436. }
  437. /*
  438. * ClassDumpTransferPacket
  439. *
  440. * Dump TRANSFER_PACKET contents under the following heading:
  441. *
  442. * " packet irp srb sense status "
  443. * " -------- -------- -------- -------- -------- "
  444. *
  445. */
  446. VOID ClassDumpTransferPacket(
  447. ULONG64 PktAddr,
  448. BOOLEAN DumpPendingPkts,
  449. BOOLEAN DumpFreePkts,
  450. BOOLEAN DumpFullInfo,
  451. ULONG Depth)
  452. {
  453. ULONG64 irpAddr = GetULONGField(PktAddr, "classpnp!_TRANSFER_PACKET", "Irp");
  454. ULONG64 srbAddr = GetFieldAddr(PktAddr, "classpnp!_TRANSFER_PACKET", "Srb");
  455. ULONG64 senseAddr = GetFieldAddr(PktAddr, "classpnp!_TRANSFER_PACKET", "SrbErrorSenseData");
  456. if ((irpAddr == BAD_VALUE) || (srbAddr == BAD_VALUE) || (senseAddr == BAD_VALUE)){
  457. dprintf("\n ClassDumpTransferPacket: error retrieving contents of packet %08p.\n", PktAddr);
  458. }
  459. else {
  460. UCHAR currentStackLoc = GetUCHARField(irpAddr, "nt!_IRP", "CurrentLocation");
  461. UCHAR stackCount = GetUCHARField(irpAddr, "nt!_IRP", "StackCount");
  462. BOOLEAN isPending;
  463. isPending = (currentStackLoc != stackCount+1);
  464. if ((isPending && DumpPendingPkts) || (!isPending && DumpFreePkts)){
  465. /*
  466. * Print the transfer packet description line
  467. */
  468. xdprintf(Depth, "");
  469. dprintf("%08p", PktAddr);
  470. dprintf(" %08p", irpAddr);
  471. dprintf(" %08p", srbAddr);
  472. dprintf(" %08p", senseAddr);
  473. if (isPending){
  474. xdprintf(0, " pending*");
  475. }
  476. else {
  477. xdprintf(0, " (free)");
  478. }
  479. xdprintf(0, "\n");
  480. if (DumpFullInfo){
  481. ULONG64 bufLen = GetULONGField(srbAddr, "classpnp!_SCSI_REQUEST_BLOCK", "DataTransferLength");
  482. ULONG64 cdbAddr = GetFieldAddr(srbAddr, "classpnp!_SCSI_REQUEST_BLOCK", "Cdb");
  483. ULONG64 origIrpAddr = GetULONGField(PktAddr, "classpnp!_TRANSFER_PACKET", "OriginalIrp");
  484. ULONG64 mdlAddr = GetULONGField(origIrpAddr, "nt!_IRP", "MdlAddress");
  485. UCHAR scsiOp = GetUCHARField(cdbAddr, "classpnp!_CDB", "CDB6GENERIC.OperationCode");
  486. UCHAR srbStat = GetUCHARField(srbAddr, "classpnp!_SCSI_REQUEST_BLOCK", "SrbStatus");
  487. ULONG64 bufAddr;
  488. /*
  489. * The the buffer address from the MDL if possible;
  490. * else from the SRB (which may not be valid).
  491. */
  492. bufAddr = GetULONGField(srbAddr, "classpnp!_SCSI_REQUEST_BLOCK", "DataBuffer");
  493. if (mdlAddr && (mdlAddr != BAD_VALUE)){
  494. ULONG mdlFlags = (ULONG)GetULONGField(mdlAddr, "nt!_MDL", "MdlFlags");
  495. if ((mdlFlags != BAD_VALUE) && (mdlFlags & MDL_PAGES_LOCKED)){
  496. bufAddr = GetULONGField(mdlAddr, "nt!_MDL", "MappedSystemVa");
  497. }
  498. }
  499. else {
  500. /*
  501. * There's no MDL, so bufAddr should be the actual kernel-space pointer.
  502. * Sanity-check it.
  503. */
  504. if (!IsPtr64() && !(bufAddr & 0x80000000)){
  505. bufAddr = BAD_VALUE;
  506. }
  507. }
  508. /*
  509. * Print the SRB description line
  510. */
  511. xdprintf(Depth+1, "(");
  512. dprintf("%s ", DbgGetScsiOpStr(scsiOp));
  513. dprintf("status=%s ", DbgGetSrbStatusStr(srbStat));
  514. if (mdlAddr && (mdlAddr != BAD_VALUE)){
  515. if (bufAddr == BAD_VALUE){
  516. dprintf("mdl=%08p ", mdlAddr);
  517. }
  518. else {
  519. dprintf("mdl+%08p ", bufAddr);
  520. }
  521. }
  522. else if (bufAddr == BAD_VALUE){
  523. dprintf("buf=??? ");
  524. }
  525. else {
  526. dprintf("buf=%08p ", bufAddr);
  527. }
  528. dprintf("len=%08lx", bufLen);
  529. dprintf(")\n");
  530. /*
  531. * Print a line with original irp if appropriate
  532. */
  533. if (cdbAddr != BAD_VALUE){
  534. scsiOp = GetUCHARField(cdbAddr, "classpnp!_CDB", "CDB6GENERIC.OperationCode");
  535. if ((scsiOp == SCSIOP_READ) || (scsiOp == SCSIOP_WRITE)){
  536. xdprintf(Depth+1, ""), dprintf("(OriginalIrp=%08p)\n", origIrpAddr);
  537. }
  538. }
  539. }
  540. }
  541. }
  542. }
  543. VOID ClassDumpPrivateErrorLogs(ULONG64 FdoDataAddr, ULONG Detail, ULONG Depth)
  544. {
  545. ULONG64 errLogsAddr;
  546. errLogsAddr = GetFieldAddr(FdoDataAddr, "classpnp!_CLASS_PRIVATE_FDO_DATA", "ErrorLogs");
  547. if (errLogsAddr != BAD_VALUE){
  548. ULONG errLogSize = GetTypeSize("classpnp!_CLASS_ERROR_LOG_DATA");
  549. if (errLogSize != BAD_VALUE){
  550. ULONG nextErrLogIndex, firstErrLogIndex, lastErrLogIndex;
  551. /*
  552. * Find what should be the index of the last error log (if there were any error logs)
  553. * See if it is valid by checking for a non-zero timestamp.
  554. */
  555. nextErrLogIndex = (ULONG)GetULONGField(FdoDataAddr, "classpnp!_CLASS_PRIVATE_FDO_DATA", "ErrorLogNextIndex");
  556. if (nextErrLogIndex != BAD_VALUE){
  557. ULONG64 tickCount;
  558. lastErrLogIndex = (nextErrLogIndex+NUM_ERROR_LOG_ENTRIES-1) % NUM_ERROR_LOG_ENTRIES;
  559. tickCount = GetULONGField(errLogsAddr+lastErrLogIndex*errLogSize, "classpnp!_CLASS_ERROR_LOG_DATA", "TickCount");
  560. if (tickCount == BAD_VALUE){
  561. }
  562. else if (tickCount == 0){
  563. /*
  564. * The "latest" error log is not initialized, so there are no error logs
  565. */
  566. dprintf("\n"), xdprintf(Depth, "No Error Logs:\n");
  567. }
  568. else {
  569. /*
  570. * Search forward through the circular list for the first valid error log.
  571. */
  572. for (firstErrLogIndex = (lastErrLogIndex+1)%NUM_ERROR_LOG_ENTRIES;
  573. firstErrLogIndex != lastErrLogIndex;
  574. firstErrLogIndex = (firstErrLogIndex+1)%NUM_ERROR_LOG_ENTRIES){
  575. ULONG64 thisErrLogAddr = errLogsAddr+firstErrLogIndex*errLogSize;
  576. tickCount = GetULONGField(thisErrLogAddr, "classpnp!_CLASS_ERROR_LOG_DATA", "TickCount");
  577. if (tickCount == BAD_VALUE){
  578. /*
  579. * something's screwed up; abort
  580. */
  581. break;
  582. }
  583. else if (tickCount != 0){
  584. /*
  585. * found the earliest of the recorded error logs, break
  586. */
  587. break;
  588. }
  589. }
  590. if (tickCount != BAD_VALUE){
  591. /*
  592. * Now that we've found the valid range of error logs, print them out.
  593. */
  594. ULONG numErrLogs = (lastErrLogIndex >= firstErrLogIndex) ?
  595. lastErrLogIndex-firstErrLogIndex+1 :
  596. lastErrLogIndex+NUM_ERROR_LOG_ENTRIES-firstErrLogIndex+1;
  597. dprintf("\n\n"), xdprintf(Depth, "ERROR LOGS (%d):\n", numErrLogs);
  598. xdprintf(Depth, "---------------------------------------------------\n");
  599. do {
  600. ULONG64 thisErrLogAddr = errLogsAddr+firstErrLogIndex*errLogSize;
  601. ULONG64 senseDataAddr = GetFieldAddr(thisErrLogAddr, "classpnp!_CLASS_ERROR_LOG_DATA", "SenseData");
  602. ULONG64 srbAddr = GetFieldAddr(thisErrLogAddr, "classpnp!_CLASS_ERROR_LOG_DATA", "Srb");
  603. ULONG64 cdbAddr;
  604. tickCount = GetFieldAddr(thisErrLogAddr, "classpnp!_CLASS_ERROR_LOG_DATA", "TickCount");
  605. // GetFieldOffset of an embedded struct gets the wrong address for some reason,
  606. // so do this manually.
  607. #if 0
  608. cdbAddr = GetFieldAddr(thisErrLogAddr, "classpnp!_SCSI_REQUEST_BLOCK", "Cdb");
  609. #else
  610. cdbAddr = (srbAddr == BAD_VALUE) ? BAD_VALUE :
  611. IsPtr64() ? srbAddr + 0x48 :
  612. srbAddr + 0x30;
  613. #endif
  614. if ((thisErrLogAddr != BAD_VALUE) && (srbAddr != BAD_VALUE) && (senseDataAddr != BAD_VALUE) && (cdbAddr != BAD_VALUE)){
  615. UCHAR scsiOp = GetUCHARField(cdbAddr, "classpnp!_CDB", "CDB6GENERIC.OperationCode");
  616. UCHAR srbStat = GetUCHARField(srbAddr, "classpnp!_SCSI_REQUEST_BLOCK", "SrbStatus");
  617. UCHAR scsiStat = GetUCHARField(srbAddr, "classpnp!_SCSI_REQUEST_BLOCK", "ScsiStatus");
  618. UCHAR isPaging = GetUCHARField(thisErrLogAddr, "classpnp!_CLASS_ERROR_LOG_DATA", "ErrorPaging");
  619. UCHAR isRetried = GetUCHARField(thisErrLogAddr, "classpnp!_CLASS_ERROR_LOG_DATA", "ErrorRetried");
  620. UCHAR isUnhandled = GetUCHARField(thisErrLogAddr, "classpnp!_CLASS_ERROR_LOG_DATA", "ErrorUnhandled");
  621. tickCount = GetULONGField(thisErrLogAddr, "classpnp!_CLASS_ERROR_LOG_DATA", "TickCount");
  622. if ((scsiOp != BAD_VALUE) && (tickCount != BAD_VALUE)){
  623. xdprintf(Depth+1, "");
  624. dprintf("<tick %d.%d>: ", (ULONG)(tickCount/1000), (ULONG)(tickCount%1000));
  625. dprintf("%s(%xh)\n",
  626. DbgGetScsiOpStr(scsiOp),
  627. (ULONG)scsiOp);
  628. xdprintf(Depth+2, "");
  629. dprintf("srbStat=%s(%xh) scsiStat=%xh \n",
  630. DbgGetSrbStatusStr(srbStat),
  631. (ULONG)srbStat,
  632. (ULONG)scsiStat
  633. );
  634. xdprintf(Depth+2, "");
  635. dprintf("SenseData = %s/%s/%s \n",
  636. DbgGetSenseCodeStr(srbStat, senseDataAddr),
  637. DbgGetAdditionalSenseCodeStr(srbStat, senseDataAddr),
  638. DbgGetAdditionalSenseCodeQualifierStr(srbStat, senseDataAddr));
  639. xdprintf(Depth+2, "");
  640. if (isPaging) dprintf("Paging; "); else dprintf("(not paging); ");
  641. if (isRetried) dprintf("Retried; "); else dprintf("(not retried); ");
  642. if (isUnhandled) dprintf("Unhandled; ");
  643. if ((scsiOp == SCSIOP_READ) || (scsiOp == SCSIOP_WRITE)){
  644. UCHAR lbaBytes[4], numBlocksBytes[4] = {0};
  645. ULONG lba, numBlocks;
  646. lbaBytes[3] = GetUCHARField(cdbAddr, "classpnp!_CDB", "CDB10.LogicalBlockByte0");
  647. lbaBytes[2] = GetUCHARField(cdbAddr, "classpnp!_CDB", "CDB10.LogicalBlockByte1");
  648. lbaBytes[1] = GetUCHARField(cdbAddr, "classpnp!_CDB", "CDB10.LogicalBlockByte2");
  649. lbaBytes[0] = GetUCHARField(cdbAddr, "classpnp!_CDB", "CDB10.LogicalBlockByte3");
  650. lba = *(PULONG)(PUCHAR)lbaBytes;
  651. numBlocksBytes[0] = GetUCHARField(cdbAddr, "classpnp!_CDB", "CDB10.TransferBlocksLsb");
  652. numBlocksBytes[1] = GetUCHARField(cdbAddr, "classpnp!_CDB", "CDB10.TransferBlocksMsb");
  653. numBlocks = *(PULONG)(PUCHAR)numBlocksBytes;
  654. dprintf("LBA=%xh; blocks=%xh;", lba, numBlocks);
  655. }
  656. dprintf("\n");
  657. xdprintf(Depth+2, "");
  658. dprintf("(for more info, use 'dt classpnp!_CLASS_ERROR_LOG_DATA %08p'\n\n", thisErrLogAddr);
  659. firstErrLogIndex = (firstErrLogIndex+1)%NUM_ERROR_LOG_ENTRIES;
  660. }
  661. else {
  662. break;
  663. }
  664. }
  665. else {
  666. break;
  667. }
  668. } while (firstErrLogIndex != (lastErrLogIndex+1)%NUM_ERROR_LOG_ENTRIES);
  669. xdprintf(Depth, "---------------------------------------------------\n");
  670. }
  671. }
  672. }
  673. }
  674. }
  675. }
  676. VOID ClassDumpPrivatePacketLogs(ULONG64 FdoDataAddr, ULONG Detail, ULONG Depth)
  677. {
  678. ULONG fieldMissing;
  679. ULONG offset;
  680. /*
  681. * The packet log only exists for debug targets, and only for Whistler server ~beta 3 builds and up.
  682. * Don't complain if its missing.
  683. */
  684. fieldMissing = GetFieldOffset("classpnp!_CLASS_PRIVATE_FDO_DATA", "DbgPacketLogs", &offset);
  685. if (!fieldMissing){
  686. ULONG64 pktLogsAddr;
  687. pktLogsAddr = GetFieldAddr(FdoDataAddr, "classpnp!_CLASS_PRIVATE_FDO_DATA", "DbgPacketLogs");
  688. if (pktLogsAddr != BAD_VALUE){
  689. ULONG pktSize = GetTypeSize("classpnp!_TRANSFER_PACKET");
  690. if (pktSize != BAD_VALUE){
  691. ULONG nextPktIndex, firstPktIndex, lastPktIndex;
  692. /*
  693. * Find what should be the index of the last pkt (if there were any pkt logs)
  694. * See if it is valid by checking for a non-zero Fdo.
  695. */
  696. nextPktIndex = (ULONG)GetULONGField(FdoDataAddr, "classpnp!_CLASS_PRIVATE_FDO_DATA", "DbgPacketLogNextIndex");
  697. if (nextPktIndex != BAD_VALUE){
  698. ULONG64 fdoAddr;
  699. lastPktIndex = (nextPktIndex+DBG_NUM_PACKET_LOG_ENTRIES-1) % DBG_NUM_PACKET_LOG_ENTRIES;
  700. fdoAddr = GetULONGField(pktLogsAddr+lastPktIndex*pktSize, "classpnp!_TRANSFER_PACKET", "Fdo");
  701. if (fdoAddr == BAD_VALUE){
  702. }
  703. else if (fdoAddr == 0){
  704. /*
  705. * The "latest" pkt log is not initialized, so there are no pkt logs
  706. */
  707. dprintf("\n"), xdprintf(Depth, "No Packet Logs:\n");
  708. }
  709. else {
  710. /*
  711. * Search forward through the circular list for the first valid pkt log.
  712. */
  713. for (firstPktIndex = (lastPktIndex+1)%DBG_NUM_PACKET_LOG_ENTRIES;
  714. firstPktIndex != lastPktIndex;
  715. firstPktIndex = (firstPktIndex+1)%DBG_NUM_PACKET_LOG_ENTRIES){
  716. ULONG64 thisPktAddr = pktLogsAddr+firstPktIndex*pktSize;
  717. fdoAddr = GetULONGField(thisPktAddr, "classpnp!_TRANSFER_PACKET", "Fdo");
  718. if (fdoAddr == BAD_VALUE){
  719. /*
  720. * something's screwed up; abort
  721. */
  722. break;
  723. }
  724. else if (fdoAddr != 0){
  725. /*
  726. * found the earliest of the recorded pkt logs, break
  727. */
  728. break;
  729. }
  730. }
  731. if (fdoAddr != BAD_VALUE){
  732. /*
  733. * Now that we've found the valid range of pkt logs, print them out.
  734. */
  735. ULONG numPktLogs = (lastPktIndex >= firstPktIndex) ?
  736. lastPktIndex-firstPktIndex+1 :
  737. lastPktIndex+DBG_NUM_PACKET_LOG_ENTRIES-firstPktIndex+1;
  738. dprintf("\n\n"), xdprintf(Depth, "PACKET LOGS (%d):\n", numPktLogs);
  739. xdprintf(Depth, "---------------------------------------------------\n");
  740. do {
  741. ULONG64 thisPktAddr = pktLogsAddr+firstPktIndex*pktSize;
  742. ULONG64 srbAddr = GetFieldAddr(thisPktAddr, "classpnp!_TRANSFER_PACKET", "Srb");
  743. ULONG64 cdbAddr;
  744. // GetFieldOffset of an embedded struct gets the wrong address for some reason,
  745. // so do this manually.
  746. #if 0
  747. cdbAddr = GetFieldAddr(thisPktAddr, "classpnp!_SCSI_REQUEST_BLOCK", "Cdb");
  748. #else
  749. cdbAddr = (srbAddr == BAD_VALUE) ? BAD_VALUE :
  750. IsPtr64() ? srbAddr + 0x48 :
  751. srbAddr + 0x30;
  752. #endif
  753. if ((thisPktAddr != BAD_VALUE) && (srbAddr != BAD_VALUE) && (cdbAddr != BAD_VALUE)){
  754. UCHAR scsiOp = GetUCHARField(cdbAddr, "classpnp!_CDB", "CDB6GENERIC.OperationCode");
  755. ULONG srbFlags = (ULONG)GetULONGField(srbAddr, "classpnp!_SCSI_REQUEST_BLOCK", "SrbFlags");
  756. ULONG pktId = (ULONG)GetULONGField(thisPktAddr, "classpnp!_TRANSFER_PACKET", "DbgPktId");
  757. ULONG64 timeSent = GetULONGField(thisPktAddr, "classpnp!_TRANSFER_PACKET", "DbgTimeSent");
  758. ULONG64 timeReturned = GetULONGField(thisPktAddr, "classpnp!_TRANSFER_PACKET", "DbgTimeReturned");
  759. if ((scsiOp != BAD_VALUE) && (srbFlags != BAD_VALUE) && (timeSent != BAD_VALUE) && (timeReturned != BAD_VALUE) && (pktId != BAD_VALUE)){
  760. UCHAR directionIndicator = (timeReturned == 0) ? '>' : '<';
  761. xdprintf(Depth, "");
  762. dprintf("%c #%04x @%d.%d %s ",
  763. directionIndicator,
  764. pktId,
  765. (ULONG)(timeReturned ? timeReturned/1000 : timeSent/1000),
  766. (ULONG)(timeReturned ? timeReturned%1000 : timeSent%1000),
  767. DbgGetScsiOpStr(scsiOp));
  768. dprintf("(");
  769. if (srbFlags & SRB_CLASS_FLAGS_PAGING) dprintf("Paging;");
  770. if ((scsiOp == SCSIOP_READ) || (scsiOp == SCSIOP_WRITE)){
  771. ULONG numRetries = (ULONG)GetULONGField(thisPktAddr, "classpnp!_TRANSFER_PACKET", "NumRetries");
  772. if ((numRetries != BAD_VALUE) && (numRetries < MAXIMUM_RETRIES)){
  773. dprintf("I/O Retry %d/%d;", MAXIMUM_RETRIES-numRetries, MAXIMUM_RETRIES);
  774. }
  775. }
  776. dprintf(")\n");
  777. xdprintf(Depth, "");
  778. dprintf("%27s ' dt classpnp!_TRANSFER_PACKET %08p '\n", "", thisPktAddr);
  779. firstPktIndex = (firstPktIndex+1)%DBG_NUM_PACKET_LOG_ENTRIES;
  780. }
  781. else {
  782. break;
  783. }
  784. }
  785. else {
  786. break;
  787. }
  788. } while (firstPktIndex != (lastPktIndex+1)%DBG_NUM_PACKET_LOG_ENTRIES);
  789. xdprintf(Depth, "---------------------------------------------------\n");
  790. }
  791. }
  792. }
  793. }
  794. }
  795. }
  796. }
  797. VOID
  798. ClassDumpIds(
  799. ULONG64 devObjAddr,
  800. ULONG detail
  801. )
  802. /*++
  803. Routine Description:
  804. Dumps the vendor, model, firmware and serial number for a given
  805. device object. Accepts either a FDO or PDO that belongs to a
  806. CLASSPNP driver (disk, cdrom, tape)
  807. Arguments:
  808. args - string containing the address of the device object
  809. Return Value:
  810. none
  811. --*/
  812. {
  813. /*
  814. * Read the device object and extension into the debugger's address space.
  815. */
  816. if (devObjAddr == 0){
  817. /*
  818. * If this is the server version of classpnp with the global AllFdosList, display all class FDOs.
  819. */
  820. ClassTryShowAllFDOs(detail);
  821. xdprintf(0, "\n usage: !classid <class fdo/pdo> [0|1]\n\n");
  822. }
  823. else {
  824. CSHORT objType = GetUSHORTField(devObjAddr, "nt!_DEVICE_OBJECT", "Type");
  825. if (objType == IO_TYPE_DEVICE){
  826. ULONG64 devExtAddr;
  827. devExtAddr = GetULONGField(devObjAddr, "nt!_DEVICE_OBJECT", "DeviceExtension");
  828. if (devExtAddr != BAD_VALUE){
  829. ULONG64 partitionZeroExtension = BAD_VALUE;
  830. ULONG64 deviceDescriptor = BAD_VALUE;
  831. ULONG64 tmpDevObjAddr = BAD_VALUE;
  832. BOOLEAN isFdo;
  833. /*
  834. * To sanity-check our device context, check that the 'DeviceObject' field matches our device object.
  835. */
  836. tmpDevObjAddr = GetULONGField(devExtAddr, "classpnp!_COMMON_DEVICE_EXTENSION", "DeviceObject");
  837. isFdo = GetUCHARField(devExtAddr, "classpnp!_COMMON_DEVICE_EXTENSION", "IsFdo");
  838. if ((tmpDevObjAddr == devObjAddr) && (isFdo != BAD_VALUE)) {
  839. partitionZeroExtension = GetULONGField(devExtAddr, "classpnp!_COMMON_DEVICE_EXTENSION", "PartitionZeroExtension");
  840. }
  841. if (partitionZeroExtension != BAD_VALUE) {
  842. deviceDescriptor = GetULONGField(devExtAddr, "classpnp!_FUNCTIONAL_DEVICE_EXTENSION", "DeviceDescriptor");
  843. }
  844. if (deviceDescriptor != BAD_VALUE) {
  845. // get and dump the real info
  846. ULONG64 vendorIdOffset = BAD_VALUE;
  847. ULONG64 productIdOffset = BAD_VALUE;
  848. ULONG64 productRevisionOffset = BAD_VALUE;
  849. ULONG64 serialNumberOffset = BAD_VALUE;
  850. UCHAR vendorId[256] = {0};
  851. UCHAR productId[256] = {0};
  852. UCHAR productRevision[256] = {0};
  853. UCHAR serialNumber[256] = {0};
  854. vendorIdOffset = GetULONGField(deviceDescriptor, "classpnp!_STORAGE_DEVICE_DESCRIPTOR", "VendorIdOffset");
  855. productIdOffset = GetULONGField(deviceDescriptor, "classpnp!_STORAGE_DEVICE_DESCRIPTOR", "ProductIdOffset");
  856. productRevisionOffset = GetULONGField(deviceDescriptor, "classpnp!_STORAGE_DEVICE_DESCRIPTOR", "ProductRevisionOffset");
  857. serialNumberOffset = GetULONGField(deviceDescriptor, "classpnp!_STORAGE_DEVICE_DESCRIPTOR", "SerialNumberOffset");
  858. if ((vendorIdOffset != 0) && (vendorIdOffset != BAD_VALUE)) {
  859. ULONG t = (sizeof(vendorId) / sizeof (UCHAR)) - 1; // always keep a NULL
  860. GetAnsiString(deviceDescriptor + vendorIdOffset, vendorId, &t);
  861. }
  862. if ((productIdOffset != 0) && (productIdOffset != BAD_VALUE)) {
  863. ULONG t = (sizeof(productId) / sizeof (UCHAR)) - 1; // always keep a NULL
  864. GetAnsiString(deviceDescriptor + productIdOffset, productId, &t);
  865. }
  866. if ((productRevisionOffset != 0) && (productRevisionOffset != BAD_VALUE)) {
  867. ULONG t = (sizeof(productRevision) / sizeof (UCHAR)) - 1; // always keep a NULL
  868. GetAnsiString(deviceDescriptor + productRevisionOffset, productRevision, &t);
  869. }
  870. if ((serialNumberOffset != 0) && (serialNumberOffset != BAD_VALUE)) {
  871. ULONG t = (sizeof(serialNumber) / sizeof (UCHAR)) - 1; // always keep a NULL
  872. GetAnsiString(deviceDescriptor + serialNumberOffset, serialNumber, &t);
  873. }
  874. if (detail == 1)
  875. {
  876. // print it all on one line
  877. dprintf("| %s | %s | %s | %s |\n", vendorId, productId, productRevision, serialNumber);
  878. }
  879. else
  880. {
  881. // print it with labels and such
  882. dprintf(" Device Object: %p\n"
  883. " Is Fdo: %s\n"
  884. " Vendor Id: \"%s\"\n"
  885. " Product Id: \"%s\"\n"
  886. "Product Revision: \"%s\"\n"
  887. " Serial Number: \"%s\"\n",
  888. devExtAddr,
  889. (isFdo ? "Yes" : "No"),
  890. vendorId,
  891. productId,
  892. productRevision,
  893. serialNumber);
  894. }
  895. }
  896. else {
  897. dprintf("%08p - could not retrieve requested information\n", devObjAddr);
  898. dprintf(g_genericErrorHelpStr);
  899. }
  900. }
  901. }
  902. else {
  903. dprintf("Error: 0x%08p is not a device object\n", devObjAddr);
  904. dprintf(g_genericErrorHelpStr);
  905. }
  906. }
  907. return;
  908. }
  909. DECLARE_API(classid)
  910. /*++
  911. Routine Description:
  912. Dumps the vendor, model, firmware and serial number for a given
  913. device object. Accepts either a FDO or PDO that belongs to a
  914. CLASSPNP driver (disk, cdrom, tape)
  915. Arguments:
  916. args - string containing the address of the device object
  917. Return Value:
  918. none
  919. --*/
  920. {
  921. ULONG64 devObjAddr = 0;
  922. ULONG64 detail = 0;
  923. ReloadSymbols("classpnp.sys");
  924. if (GetExpressionEx(args, &devObjAddr, &args))
  925. {
  926. GetExpressionEx(args, &detail, &args);
  927. }
  928. ClassDumpIds( devObjAddr, (ULONG)detail );
  929. return S_OK;
  930. }