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.

758 lines
17 KiB

  1. /*++
  2. Copyright (C) Microsoft Corporation, 1992 - 1999
  3. Module Name:
  4. util.c
  5. Abstract:
  6. Utility library used for the various debugger extensions in this library.
  7. Author:
  8. Peter Wieland (peterwie) 16-Oct-1995
  9. Environment:
  10. User Mode.
  11. Revision History:
  12. --*/
  13. #include "pch.h"
  14. #include "classkd.h" // routines that are useful for all class drivers
  15. PUCHAR devicePowerStateNames[] = {
  16. "PowerDeviceUnspecified",
  17. "PowerDeviceD0",
  18. "PowerDeviceD1",
  19. "PowerDeviceD2",
  20. "PowerDeviceD3",
  21. "PowerDeviceMaximum",
  22. "Invalid"
  23. };
  24. FLAG_NAME SrbFlags[] = {
  25. FLAG_NAME(SRB_FLAGS_QUEUE_ACTION_ENABLE),
  26. FLAG_NAME(SRB_FLAGS_DISABLE_DISCONNECT),
  27. FLAG_NAME(SRB_FLAGS_DISABLE_SYNCH_TRANSFER),
  28. FLAG_NAME(SRB_FLAGS_BYPASS_FROZEN_QUEUE),
  29. FLAG_NAME(SRB_FLAGS_DISABLE_AUTOSENSE),
  30. FLAG_NAME(SRB_FLAGS_DATA_IN),
  31. FLAG_NAME(SRB_FLAGS_DATA_OUT),
  32. FLAG_NAME(SRB_FLAGS_NO_DATA_TRANSFER),
  33. FLAG_NAME(SRB_FLAGS_UNSPECIFIED_DIRECTION),
  34. FLAG_NAME(SRB_FLAGS_NO_QUEUE_FREEZE),
  35. FLAG_NAME(SRB_FLAGS_ADAPTER_CACHE_ENABLE),
  36. FLAG_NAME(SRB_FLAGS_IS_ACTIVE),
  37. FLAG_NAME(SRB_FLAGS_ALLOCATED_FROM_ZONE),
  38. FLAG_NAME(SRB_FLAGS_SGLIST_FROM_POOL),
  39. FLAG_NAME(SRB_FLAGS_BYPASS_LOCKED_QUEUE),
  40. FLAG_NAME(SRB_FLAGS_NO_KEEP_AWAKE),
  41. {0,0}
  42. };
  43. char *g_genericErrorHelpStr = "\n" \
  44. "**************************************************************** \n" \
  45. " Make sure you have _private_ symbols for classpnp.sys loaded.\n" \
  46. " The FDO parameter should be the upper AttachedDevice of the disk/cdrom/etc PDO\n" \
  47. " as returned by '!devnode 0 1 {disk|cdrom|4mmdat|etc}'.\n" \
  48. "**************************************************************** \n\n" \
  49. ;
  50. VOID
  51. GetAddress(
  52. IN PCSTR Args,
  53. OUT PULONG64 Address
  54. )
  55. {
  56. UCHAR addressBuffer[256];
  57. addressBuffer[0] = '\0';
  58. sscanf(Args, "%s", addressBuffer);
  59. addressBuffer[255] = '\0';
  60. *Address = 0;
  61. if (addressBuffer[0] != '\0') {
  62. //
  63. // they provided an address
  64. //
  65. *Address = GetExpression(addressBuffer);
  66. //
  67. // if that still doesn't parse, print an error
  68. //
  69. if (*Address==0) {
  70. dprintf("An error occured trying to evaluate the address\n");
  71. *Address = 0;
  72. return;
  73. }
  74. }
  75. return;
  76. }
  77. VOID
  78. GetAddressAndDetailLevel(
  79. IN PCSTR Args,
  80. OUT PULONG64 Address,
  81. OUT PLONG Detail
  82. )
  83. {
  84. UCHAR addressBuffer[256];
  85. UCHAR detailBuffer[256];
  86. addressBuffer[0] = '\0';
  87. detailBuffer[0] = '\0';
  88. sscanf(Args, "%s %s", addressBuffer, detailBuffer);
  89. addressBuffer[255] = '\0';
  90. detailBuffer[255] = '\0';
  91. *Address = 0;
  92. *Detail = 0;
  93. if (addressBuffer[0] != '\0') {
  94. //
  95. // they provided an address
  96. //
  97. *Address = GetExpression(addressBuffer);
  98. //
  99. // if that still doesn't parse, print an error
  100. //
  101. if (*Address==0) {
  102. dprintf("An error occured trying to evaluate the address\n");
  103. *Address = 0;
  104. *Detail = 0;
  105. return;
  106. }
  107. //
  108. // if they provided a detail level get it.
  109. //
  110. if (detailBuffer[0] == '\0') {
  111. *Detail = 0;
  112. } else {
  113. *Detail = (ULONG)GetExpression(detailBuffer);
  114. }
  115. }
  116. return;
  117. }
  118. VOID
  119. GetAddressAndDetailLevel64(
  120. IN PCSTR Args,
  121. OUT PULONG64 Address,
  122. OUT PLONG Detail
  123. )
  124. {
  125. UCHAR addressBuffer[256];
  126. UCHAR detailBuffer[256];
  127. addressBuffer[0] = '\0';
  128. detailBuffer[0] = '\0';
  129. sscanf(Args, "%s %s", addressBuffer, detailBuffer);
  130. addressBuffer[255] = '\0';
  131. detailBuffer[255] = '\0';
  132. *Address = 0;
  133. *Detail = 0;
  134. if (addressBuffer[0] != '\0') {
  135. //
  136. // they provided an address
  137. //
  138. *Address = GetExpression(addressBuffer);
  139. //
  140. // if that still doesn't parse, print an error
  141. //
  142. if (*Address==0) {
  143. dprintf("An error occured trying to evaluate the address\n");
  144. *Address = 0;
  145. *Detail = 0;
  146. return;
  147. }
  148. //
  149. // if they provided a detail level get it.
  150. //
  151. if (detailBuffer[0] == '\0') {
  152. *Detail = 0;
  153. } else {
  154. *Detail = (ULONG)GetExpression(detailBuffer);
  155. }
  156. }
  157. return;
  158. }
  159. PUCHAR
  160. DevicePowerStateToString(
  161. IN DEVICE_POWER_STATE State
  162. )
  163. {
  164. if(State > PowerDeviceMaximum) {
  165. return devicePowerStateNames[PowerDeviceMaximum + 1];
  166. } else {
  167. return devicePowerStateNames[(UCHAR) State];
  168. }
  169. }
  170. //
  171. // Translates various printf formats to account for the target platform.
  172. //
  173. // This looks for %p type format and truncates the top 4 bytes of the ULONG64
  174. // address argument if the debugee is a 32 bit machine.
  175. // The %p is replaced by %I64x in format string.
  176. //
  177. BOOL
  178. TranslateFormat(
  179. LPSTR formatOut,
  180. LPCSTR format,
  181. va_list args,
  182. ULONG formatOutSize
  183. )
  184. {
  185. #define Duplicate(j,i) (formatOut[j++] = format[i++])
  186. ULONG minSize = strlen(format), i = 0, j = 0;
  187. CHAR c;
  188. BOOL TypeFormat = FALSE;
  189. BOOL FormatChanged = FALSE;
  190. do
  191. {
  192. c = format[i];
  193. if (c=='%')
  194. {
  195. TypeFormat = !TypeFormat;
  196. }
  197. if (TypeFormat)
  198. {
  199. switch (c)
  200. {
  201. case 'c': case 'C': case 'i': case 'd':
  202. case 'o': case 'u': case 'x': case 'X':
  203. Duplicate(j,i);
  204. va_arg(args, int);
  205. TypeFormat = FALSE;
  206. break;
  207. case 'e': case 'E': case 'f': case 'g':
  208. case 'G':
  209. Duplicate(j,i);
  210. va_arg(args, double);
  211. TypeFormat = FALSE;
  212. break;
  213. case 'n':
  214. Duplicate(j,i);
  215. va_arg(args, int*);
  216. TypeFormat = FALSE;
  217. break;
  218. case 'N':
  219. // Native pointer, turns into %p.
  220. formatOut[j++] = 'p';
  221. FormatChanged = TRUE;
  222. i++;
  223. va_arg(args, void*);
  224. TypeFormat = FALSE;
  225. break;
  226. case 's': case 'S':
  227. Duplicate(j,i);
  228. va_arg(args, char*);
  229. TypeFormat = FALSE;
  230. break;
  231. case 'I':
  232. if ((format[i+1] == '6') && (format[i+2] == '4'))
  233. {
  234. Duplicate(j,i);
  235. Duplicate(j,i);
  236. va_arg(args, ULONG64);
  237. TypeFormat = FALSE;
  238. }
  239. // dprintf("I64 a0 %lx, off %lx\n", args.a0, args.offset);
  240. Duplicate(j,i);
  241. break;
  242. case 'z': case 'Z':
  243. // unicode string
  244. Duplicate(j,i);
  245. va_arg(args, void*);
  246. TypeFormat = FALSE;
  247. break;
  248. case 'p':
  249. case 'P':
  250. minSize +=3;
  251. if (format[i-1] == '%')
  252. {
  253. minSize++;
  254. if (IsPtr64())
  255. {
  256. minSize += 2;
  257. if (minSize > formatOutSize)
  258. {
  259. return FALSE;
  260. }
  261. formatOut[j++] = '0';
  262. formatOut[j++] = '1';
  263. formatOut[j++] = '6';
  264. }
  265. else
  266. {
  267. if (minSize > formatOutSize)
  268. {
  269. return FALSE;
  270. }
  271. formatOut[j++] = '0';
  272. formatOut[j++] = '8';
  273. }
  274. }
  275. if (minSize > formatOutSize)
  276. {
  277. return FALSE;
  278. }
  279. formatOut[j++] = 'I';
  280. formatOut[j++] = '6';
  281. formatOut[j++] = '4';
  282. formatOut[j++] = (c == 'p') ? 'x' : 'X'; ++i;
  283. FormatChanged = TRUE;
  284. if (!IsPtr64())
  285. {
  286. PULONG64 Arg;
  287. #ifdef _M_ALPHA
  288. Arg = (PULONG64) ((args.a0)+args.offset);
  289. //dprintf("a0 %lx, off %lx\n", args.a0, args.offset);
  290. #else
  291. Arg = (PULONG64) (args);
  292. #endif
  293. //
  294. // Truncate signextended addresses
  295. //
  296. *Arg = (ULONG64) (ULONG) *Arg;
  297. }
  298. va_arg(args, ULONG64);
  299. TypeFormat = FALSE;
  300. break;
  301. default:
  302. Duplicate(j,i);
  303. } /* switch */
  304. }
  305. else
  306. {
  307. Duplicate(j,i);
  308. }
  309. }
  310. while (format[i] != '\0');
  311. formatOut[j] = '\0';
  312. return FormatChanged;
  313. #undef Duplicate
  314. }
  315. /*
  316. * xdprintf
  317. *
  318. * Prints formatted text with leading spaces.
  319. *
  320. * WARNING: DOES NOT HANDLE ULONG64 PROPERLY.
  321. */
  322. VOID
  323. xdprintf(
  324. ULONG Depth,
  325. PCCHAR Format,
  326. ...
  327. )
  328. {
  329. va_list args;
  330. ULONG i;
  331. CCHAR DebugBuffer[256];
  332. for (i=0; i<Depth; i++) {
  333. dprintf (" ");
  334. }
  335. va_start(args, Format);
  336. _vsnprintf(DebugBuffer, 255, Format, args);
  337. dprintf (DebugBuffer);
  338. va_end(args);
  339. }
  340. VOID
  341. DumpFlags(
  342. ULONG Depth,
  343. PUCHAR Name,
  344. ULONG Flags,
  345. PFLAG_NAME FlagTable
  346. )
  347. {
  348. ULONG i;
  349. ULONG mask = 0;
  350. ULONG count = 0;
  351. UCHAR prolog[64];
  352. sprintf(prolog, "%s (0x%08x): ", Name, Flags);
  353. xdprintf(Depth, "%s", prolog);
  354. if(Flags == 0) {
  355. dprintf("\n");
  356. return;
  357. }
  358. memset(prolog, ' ', strlen(prolog));
  359. for(i = 0; FlagTable[i].Name != 0; i++) {
  360. PFLAG_NAME flag = &(FlagTable[i]);
  361. mask |= flag->Flag;
  362. if((Flags & flag->Flag) == flag->Flag) {
  363. //
  364. // print trailing comma
  365. //
  366. if(count != 0) {
  367. dprintf(", ");
  368. //
  369. // Only print two flags per line.
  370. //
  371. if((count % 2) == 0) {
  372. dprintf("\n");
  373. xdprintf(Depth, "%s", prolog);
  374. }
  375. }
  376. dprintf("%s", flag->Name);
  377. count++;
  378. }
  379. }
  380. dprintf("\n");
  381. if((Flags & (~mask)) != 0) {
  382. xdprintf(Depth, "%sUnknown flags %#010lx\n", prolog, (Flags & (~mask)));
  383. }
  384. return;
  385. }
  386. BOOLEAN
  387. GetAnsiString(
  388. IN ULONG64 Address,
  389. IN PUCHAR Buffer,
  390. IN OUT PULONG Length
  391. )
  392. {
  393. ULONG i = 0;
  394. //
  395. // Grab the string in 64 character chunks until we find a NULL or the
  396. // read fails.
  397. //
  398. while((i < *Length) && (!CheckControlC())) {
  399. ULONG transferSize;
  400. ULONG result;
  401. if(*Length - i < 128) {
  402. transferSize = *Length - i;
  403. } else {
  404. transferSize = 128;
  405. }
  406. if(!ReadMemory(Address + i,
  407. Buffer + i,
  408. transferSize,
  409. &result)) {
  410. //
  411. // read failed and we didn't find the NUL the last time. Don't
  412. // expect to find it this time.
  413. //
  414. *Length = i;
  415. return FALSE;
  416. } else {
  417. ULONG j;
  418. //
  419. // Scan from where we left off looking for that NUL character.
  420. //
  421. for(j = 0; j < transferSize; j++) {
  422. if(Buffer[i + j] == '\0') {
  423. *Length = i + j;
  424. return TRUE;
  425. }
  426. }
  427. }
  428. i += transferSize;
  429. }
  430. //
  431. // We never found the NUL. Don't need to update Length since it's currently
  432. // equal to i.
  433. //
  434. return FALSE;
  435. }
  436. PCHAR
  437. GuidToString(
  438. GUID* Guid
  439. )
  440. {
  441. static CHAR Buffer [64];
  442. sprintf (Buffer,
  443. "{%08lx-%04x-%04x-%02x%02x-%02x%02x%02x%02x%02x%02x}",
  444. Guid->Data1,
  445. Guid->Data2,
  446. Guid->Data3,
  447. Guid->Data4[0],
  448. Guid->Data4[1],
  449. Guid->Data4[2],
  450. Guid->Data4[3],
  451. Guid->Data4[4],
  452. Guid->Data4[5],
  453. Guid->Data4[6],
  454. Guid->Data4[7]
  455. );
  456. return Buffer;
  457. }
  458. ULONG64
  459. GetDeviceExtension(
  460. ULONG64 address
  461. )
  462. /*++
  463. Routine Description:
  464. The function accepts the address of either a device object or a device
  465. extension. If the supplied address is that of a device object, the
  466. device extension is retrieved and returned. If the address is that of
  467. a device extension, the address is returned unmodified.
  468. Arguments:
  469. Address - address of a device extension or a device object
  470. Return Value:
  471. The address of the device extension or 0 if an error occurs.
  472. --*/
  473. {
  474. ULONG result;
  475. CSHORT Type;
  476. ULONG64 Address = address;
  477. //
  478. // The supplied address may be either the address of a device object or the
  479. // address of a device extension. To distinguish which, we treat the
  480. // address as a device object and read what would be its type field. If
  481. // the
  482. //
  483. result = GetFieldData(Address,
  484. "scsiport!_DEVICE_OBJECT",
  485. "Type",
  486. sizeof(CSHORT),
  487. &Type
  488. );
  489. if (result) {
  490. SCSIKD_PRINT_ERROR(result);
  491. return 0;
  492. }
  493. //
  494. // See if the supplied address holds a device object. If it does, read the
  495. // address of the device extension. Otherwise, we assume the supplied
  496. // addres holds a device extension and we use it directly.
  497. //
  498. if (Type == IO_TYPE_DEVICE) {
  499. result = GetFieldData(Address,
  500. "scsiport!_DEVICE_OBJECT",
  501. "DeviceExtension",
  502. sizeof(ULONG64),
  503. &Address
  504. );
  505. if (result) {
  506. SCSIKD_PRINT_ERROR(result);
  507. return 0;
  508. }
  509. }
  510. return Address;
  511. }
  512. /*
  513. * GetULONGField
  514. *
  515. * Return the field or -1 in case of error.
  516. * Yes, it screws up if the field is actually -1.
  517. */
  518. ULONG64 GetULONGField(ULONG64 StructAddr, LPCSTR StructType, LPCSTR FieldName)
  519. {
  520. ULONG64 result;
  521. ULONG dbgStat;
  522. dbgStat = GetFieldData(StructAddr, StructType, FieldName, sizeof(ULONG64), &result);
  523. if (dbgStat != 0){
  524. dprintf("\n GetULONGField: GetFieldData failed with %xh retrieving field '%s' of struct '%s', returning bogus field value %08xh.\n", dbgStat, FieldName, StructType, BAD_VALUE);
  525. dprintf(g_genericErrorHelpStr);
  526. result = BAD_VALUE;
  527. }
  528. return result;
  529. }
  530. /*
  531. * GetUSHORTField
  532. *
  533. * Return the field or -1 in case of error.
  534. * Yes, it screws up if the field is actually -1.
  535. */
  536. USHORT GetUSHORTField(ULONG64 StructAddr, LPCSTR StructType, LPCSTR FieldName)
  537. {
  538. USHORT result;
  539. ULONG dbgStat;
  540. dbgStat = GetFieldData(StructAddr, StructType, FieldName, sizeof(USHORT), &result);
  541. if (dbgStat != 0){
  542. dprintf("\n GetUSHORTField: GetFieldData failed with %xh retrieving field '%s' of struct '%s', returning bogus field value %08xh.\n", dbgStat, FieldName, StructType, BAD_VALUE);
  543. dprintf(g_genericErrorHelpStr);
  544. result = (USHORT)BAD_VALUE;
  545. }
  546. return result;
  547. }
  548. /*
  549. * GetUCHARField
  550. *
  551. * Return the field or -1 in case of error.
  552. * Yes, it screws up if the field is actually -1.
  553. */
  554. UCHAR GetUCHARField(ULONG64 StructAddr, LPCSTR StructType, LPCSTR FieldName)
  555. {
  556. UCHAR result;
  557. ULONG dbgStat;
  558. dbgStat = GetFieldData(StructAddr, StructType, FieldName, sizeof(UCHAR), &result);
  559. if (dbgStat != 0){
  560. dprintf("\n GetUCHARField: GetFieldData failed with %xh retrieving field '%s' of struct '%s', returning bogus field value %08xh.\n", dbgStat, FieldName, StructType, BAD_VALUE);
  561. dprintf(g_genericErrorHelpStr);
  562. result = (UCHAR)BAD_VALUE;
  563. }
  564. return result;
  565. }
  566. ULONG64 GetFieldAddr(ULONG64 StructAddr, LPCSTR StructType, LPCSTR FieldName)
  567. {
  568. ULONG64 result;
  569. ULONG offset;
  570. ULONG dbgStat;
  571. dbgStat = GetFieldOffset(StructType, FieldName, &offset);
  572. if (dbgStat == 0){
  573. result = StructAddr+offset;
  574. }
  575. else {
  576. dprintf("\n GetFieldAddr: GetFieldOffset failed with %xh retrieving offset of struct '%s' field '%s'.\n", dbgStat, StructType, FieldName);
  577. dprintf(g_genericErrorHelpStr);
  578. result = BAD_VALUE;
  579. }
  580. return result;
  581. }
  582. ULONG64 GetContainingRecord(ULONG64 FieldAddr, LPCSTR StructType, LPCSTR FieldName)
  583. {
  584. ULONG64 result;
  585. ULONG offset;
  586. ULONG dbgStat;
  587. dbgStat = GetFieldOffset(StructType, FieldName, &offset);
  588. if (dbgStat == 0){
  589. result = FieldAddr-offset;
  590. }
  591. else {
  592. dprintf("\n GetContainingRecord: GetFieldOffset failed with %xh retrieving offset of struct '%s' field '%s', returning bogus address %08xh.\n", dbgStat, StructType, FieldName, BAD_VALUE);
  593. dprintf(g_genericErrorHelpStr);
  594. result = BAD_VALUE;
  595. }
  596. return result;
  597. }