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.

588 lines
14 KiB

  1. /****************************** Module Header ******************************\
  2. * Module Name: stdexts.c
  3. *
  4. * Copyright (c) Microsoft Corporation. All rights reserved.
  5. *
  6. * This module contains standard routines for creating sane debuging extensions.
  7. * It is meant to be included after stdexts.h in one of the files comprising
  8. * the debug extsnsions for a given product or module.
  9. *
  10. * History:
  11. * 11-Apr-1995 Sanfords Created
  12. \***************************************************************************/
  13. HANDLE hCurrentProcess;
  14. HANDLE hCurrentThread;
  15. DWORD dwCurrentPc;
  16. WINDBG_EXTENSION_APIS *lpExtensionApis;
  17. #ifdef KERNEL
  18. DWORD dwProcessor;
  19. #endif // KERNEL
  20. PSTR pszAccessViolation = "%s: Access violation on \"%s\".\n";
  21. PSTR pszMoveException = "%s: exception in moveBlock()\n";
  22. PSTR pszReadFailure = "%s: lpReadProcessMemoryRoutine failed!\n";
  23. PSTR pszCantContinue = "%s: Non-continuable exception.\n";
  24. BOOL fCtrlCHit = FALSE;
  25. /*
  26. * This function returns TRUE once the user has hit a Ctrl-C.
  27. * This allows proper operation of nested SAFEWHILE loops so
  28. * that all levels exit.
  29. *
  30. * The globall fCtrlCHit flag needs to be reset manually and
  31. * is done so in the CommandEP function.
  32. */
  33. BOOL IsCtrlCHit()
  34. {
  35. if ((lpExtensionApis->lpCheckControlCRoutine)()) {
  36. fCtrlCHit = TRUE;
  37. }
  38. return fCtrlCHit;
  39. }
  40. VOID moveBlock(
  41. PVOID pdst,
  42. PVOID src,
  43. DWORD size)
  44. {
  45. BOOL fSuccess = TRUE;
  46. ULONG Result;
  47. try {
  48. if (IsWinDbg()) {
  49. if (!ReadMem((DWORD_PTR)src, pdst, size, &Result)) {
  50. fSuccess = FALSE;
  51. }
  52. } else {
  53. if (!NT_SUCCESS(NtReadVirtualMemory(hCurrentProcess,
  54. src, pdst, size, NULL))) {
  55. fSuccess = FALSE;
  56. }
  57. }
  58. } except (EXCEPTION_EXECUTE_HANDLER) {
  59. Print(pszMoveException, pszExtName);
  60. fSuccess = FALSE;
  61. }
  62. if (!fSuccess) {
  63. DEBUGPRINT("%s: moveBlock(%p, %p, %x) failed.\n",
  64. pszExtName, pdst, src, size);
  65. OUTAHERE();
  66. }
  67. }
  68. BOOL tryMoveBlock(
  69. PVOID pdst,
  70. PVOID src,
  71. DWORD size)
  72. {
  73. BOOL fSuccess = TRUE;
  74. ULONG Result;
  75. try {
  76. if (IsWinDbg()) {
  77. if (!ReadMem((DWORD_PTR)src, pdst, size, &Result)) {
  78. DEBUGPRINT("%s: tryMoveBlock(%p, %p, %x) failed.\n", pszExtName, pdst, src, size);
  79. fSuccess = FALSE;
  80. }
  81. } else {
  82. if (!NT_SUCCESS(NtReadVirtualMemory(hCurrentProcess, src, pdst, size, NULL))) {
  83. DEBUGPRINT("%s: tryMoveBlock(%p, %p, %x) failed.\n", pszExtName, pdst, src, size);
  84. fSuccess = FALSE;
  85. }
  86. }
  87. } except (EXCEPTION_EXECUTE_HANDLER) {
  88. DEBUGPRINT("%s: tryMoveBlock(%p, %p, %x) faulted.\n", pszExtName, pdst, src, size);
  89. fSuccess = FALSE;
  90. }
  91. return(fSuccess);
  92. }
  93. VOID moveExp(
  94. PVOID pdst,
  95. LPSTR pszExp)
  96. {
  97. DWORD_PTR dwGlobal;
  98. BOOL fSuccess = TRUE;
  99. try {
  100. dwGlobal = (DWORD_PTR)EvalExp(pszExp);
  101. #ifndef KERNEL
  102. if (IsWinDbg()) {
  103. fSuccess = tryMoveBlock(&dwGlobal, (PVOID)dwGlobal, sizeof(DWORD));
  104. }
  105. #endif // !KERNEL
  106. *((PDWORD_PTR)pdst) = dwGlobal;
  107. } except (GetExceptionCode() == EXCEPTION_ACCESS_VIOLATION ?
  108. EXCEPTION_EXECUTE_HANDLER : EXCEPTION_CONTINUE_SEARCH) {
  109. Print(pszAccessViolation, pszExtName, pszExp);
  110. fSuccess = FALSE;
  111. }
  112. if (!fSuccess) {
  113. Print("%s: moveExp failed on %s.\n", pszExtName, pszExp);
  114. OUTAHERE();
  115. }
  116. }
  117. BOOL tryMoveExp(
  118. PVOID pdst,
  119. LPSTR pszExp)
  120. {
  121. DWORD_PTR dwGlobal;
  122. BOOL fSuccess = TRUE;
  123. try {
  124. dwGlobal = (DWORD_PTR)EvalExp(pszExp);
  125. #ifndef KERNEL
  126. if (IsWinDbg()) {
  127. if (!tryMove(dwGlobal, (PVOID)dwGlobal)) {
  128. DEBUGPRINT("%s: tryMoveExp(%p, %s) failed.\n", pszExtName, pdst, pszExp);
  129. fSuccess = FALSE;
  130. }
  131. }
  132. #endif // !KERNEL
  133. *((PDWORD_PTR)pdst) = dwGlobal;
  134. } except (GetExceptionCode() == EXCEPTION_ACCESS_VIOLATION ?
  135. EXCEPTION_EXECUTE_HANDLER : EXCEPTION_CONTINUE_SEARCH) {
  136. Print(pszAccessViolation, pszExtName, pszExp);
  137. DEBUGPRINT("%s: tryMoveExp(%p, %s) faulted.\n", pszExtName, pdst, pszExp);
  138. fSuccess = FALSE;
  139. }
  140. return(fSuccess);
  141. }
  142. VOID moveExpValue(
  143. PVOID pdst,
  144. LPSTR pszExp)
  145. {
  146. DWORD dw;
  147. DWORD_PTR addr;
  148. if (tryMoveExp(&addr, pszExp)) {
  149. if (tryMoveBlock(&dw, (PVOID)addr, sizeof(DWORD))) {
  150. *((PDWORD)pdst) = dw;
  151. return;
  152. }
  153. }
  154. Print("%s: moveExpValue failed on %s.\n", pszExtName, pszExp);
  155. OUTAHERE();
  156. }
  157. BOOL tryMoveExpValue(
  158. PVOID pdst,
  159. LPSTR pszExp)
  160. {
  161. DWORD dw;
  162. DWORD_PTR addr;
  163. if (tryMoveExp(&addr, pszExp)) {
  164. if (tryMove(dw, (PVOID)addr)) {
  165. *((PDWORD)pdst) = dw;
  166. return(TRUE);
  167. }
  168. }
  169. DEBUGPRINT("%s: tryMoveExpValue failed on %s.\n", pszExtName, pszExp);
  170. return(FALSE);
  171. }
  172. BOOL tryMoveExpPtr(
  173. PVOID pdst,
  174. LPSTR pszExp)
  175. {
  176. DWORD_PTR dwGlobal;
  177. BOOL fSuccess = TRUE;
  178. try {
  179. dwGlobal = (DWORD_PTR)EvalExp(pszExp);
  180. #ifndef KERNEL
  181. if (IsWinDbg()) {
  182. if (!tryMove(dwGlobal, (PVOID)dwGlobal)) {
  183. DEBUGPRINT("%s: tryMoveExpPtr(%p, %s) failed.\n", pszExtName, pdst, pszExp);
  184. fSuccess = FALSE;
  185. }
  186. }
  187. #endif // !KERNEL
  188. *((PDWORD_PTR)pdst) = dwGlobal;
  189. } except (GetExceptionCode() == EXCEPTION_ACCESS_VIOLATION ?
  190. EXCEPTION_EXECUTE_HANDLER : EXCEPTION_CONTINUE_SEARCH) {
  191. Print(pszAccessViolation, pszExtName, pszExp);
  192. DEBUGPRINT("%s: tryMoveExpPtr(%p, %s) faulted.\n", pszExtName, pdst, pszExp);
  193. fSuccess = FALSE;
  194. }
  195. return(fSuccess);
  196. }
  197. VOID moveExpValuePtr(
  198. PVOID pdst,
  199. LPSTR pszExp)
  200. {
  201. DWORD_PTR dw;
  202. if (tryMoveExpPtr(&dw, pszExp)) {
  203. if (tryMoveBlock(&dw, (PVOID)dw, sizeof(dw))) {
  204. *((PDWORD_PTR)pdst) = dw;
  205. return;
  206. }
  207. }
  208. Print("%s: moveExpValue failed on %s.\n", pszExtName, pszExp);
  209. OUTAHERE();
  210. }
  211. /***************************************************************************
  212. * Common command parsing stuff *
  213. ***************************************************************************/
  214. PVOID EvalExp(
  215. LPSTR psz)
  216. {
  217. PVOID p;
  218. p = (PVOID)(lpExtensionApis->lpGetExpressionRoutine)(psz);
  219. if (p == NULL) {
  220. Print("%s: EvalExp failed to evaluate %s.\n", pszExtName, psz);
  221. }
  222. return p;
  223. }
  224. PVOID OptEvalExp(
  225. LPSTR psz)
  226. {
  227. while (*psz == ' ')
  228. psz++;
  229. if (*psz == '\0') {
  230. return(NULL);
  231. }
  232. return(EvalExp(psz));
  233. }
  234. PVOID OptEvalExp2(
  235. LPSTR *ppsz)
  236. {
  237. LPSTR psz = *ppsz;
  238. PVOID dwRet = NULL;
  239. while (*psz == ' ')
  240. psz++;
  241. if (*psz != '\0') {
  242. dwRet = EvalExp(psz);
  243. while (*psz != '\0' && *psz != ' ') {
  244. psz++;
  245. }
  246. }
  247. *ppsz = psz;
  248. return(dwRet);
  249. }
  250. DWORD StringToOpts(
  251. LPSTR psz)
  252. {
  253. DWORD opts = 0;
  254. while (*psz != '\0' && *psz != ' ') {
  255. if (*psz >= 'a' && *psz <= 'z') {
  256. opts |= 1 << (*psz - 'a');
  257. } else if (*psz >= 'A' && *psz <= 'Z') {
  258. opts |= 1 << (*psz - 'A');
  259. } else {
  260. return(OPTS_ERROR); // any non-letter option is an error.
  261. }
  262. psz++;
  263. }
  264. return(opts);
  265. }
  266. /*
  267. * Function to convert an option string to a DWORD of flags. pszLegalArgs
  268. * is used to allow option validation at the same time.
  269. *
  270. * *ppszArgs is set to point to after the options on exit.
  271. * On error, returns OPTS_ERROR.
  272. */
  273. DWORD GetOpts(
  274. LPSTR *ppszArgs,
  275. LPSTR pszLegalArgs) // OPTIONAL
  276. {
  277. DWORD Opts = 0;
  278. LPSTR pszArgs = *ppszArgs;
  279. /*
  280. * Skip whitespace
  281. */
  282. while (*pszArgs == ' ') {
  283. pszArgs++;
  284. }
  285. /*
  286. * process '-' prepended options.
  287. */
  288. while (*pszArgs == '-') {
  289. pszArgs++;
  290. Opts = StringToOpts(pszArgs);
  291. /*
  292. * skip to whitespace or end.
  293. */
  294. while (*pszArgs != '\0' && *pszArgs != ' ') {
  295. pszArgs++;
  296. }
  297. /*
  298. * skip trailing whitespace.
  299. */
  300. while (*pszArgs == ' ') {
  301. pszArgs++;
  302. }
  303. *ppszArgs = pszArgs;
  304. /*
  305. * optionally validate against LegalArgs
  306. */
  307. if (pszLegalArgs != NULL && ((Opts & StringToOpts(pszLegalArgs)) != Opts)) {
  308. Opts = OPTS_ERROR;
  309. Print("Bad options.\n");
  310. return(Opts);
  311. }
  312. }
  313. return(Opts);
  314. }
  315. VOID PrintHuge(
  316. LPSTR psz)
  317. {
  318. /*
  319. * Looks like this is faulting these days - Print seems to be fixed
  320. * so I'm leaving this entry point for compatibility. (SAS)
  321. */
  322. #ifdef ITWORKS
  323. #define HUNK_SIZE 400
  324. int cch;
  325. CHAR chSave;
  326. /*
  327. * since dorky Print extension can't handle very long strings,
  328. * break it up into peices for it to chew.
  329. */
  330. cch = strlen(psz);
  331. while (cch > HUNK_SIZE) {
  332. chSave = psz[HUNK_SIZE];
  333. psz[HUNK_SIZE] = '\0';
  334. Print(psz);
  335. psz[HUNK_SIZE] = chSave;
  336. psz += HUNK_SIZE;
  337. cch -= HUNK_SIZE;
  338. }
  339. #endif
  340. Print(psz);
  341. }
  342. /*
  343. * Dispatcher function used by generated entrypoint functions.
  344. */
  345. VOID CommonEP(
  346. PVOID pFunction,
  347. LPSTR pszName,
  348. int type,
  349. LPSTR pszLegalOpts,
  350. HANDLE hcp,
  351. HANDLE hct,
  352. DWORD dwcp,
  353. #ifdef KERNEL
  354. DWORD dwp,
  355. #else // !KERNEL
  356. PWINDBG_EXTENSION_APIS lpea,
  357. #endif // !KERNEL
  358. LPSTR lpas)
  359. {
  360. BOOL dwOptions, fSuccess;
  361. PVOID param1, param2, param3;
  362. hCurrentProcess = hcp;
  363. hCurrentThread = hct;
  364. dwCurrentPc = dwcp;
  365. #ifdef KERNEL
  366. dwProcessor = dwp;
  367. lpExtensionApis = &ExtensionApis;
  368. #else // !KERNEL
  369. lpExtensionApis = lpea;
  370. #endif // !KERNLE
  371. #if 0
  372. DEBUGPRINT("CommonEP(%x, \"%s\", %d, \"%s\", %x, %x, %x, %x, \"%s\")\n",
  373. pFunction,
  374. pszName,
  375. type,
  376. pszLegalOpts,
  377. hcp,
  378. hct,
  379. dwcp,
  380. #ifdef KERNEL
  381. dwp,
  382. #else // !KERNLE
  383. lpea,
  384. #endif // !KERNEL
  385. lpas);
  386. #endif
  387. fCtrlCHit = FALSE; // reset this with each command. (SAFEWHILE fix)
  388. switch (type) {
  389. case NOARGS:
  390. fSuccess = ((TYPE_NOARGS)pFunction)();
  391. goto Exit;
  392. }
  393. dwOptions = GetOpts(&lpas, pszLegalOpts);
  394. if (dwOptions == OPTS_ERROR) {
  395. fSuccess = Ihelp(0, pszName);
  396. goto Exit;
  397. }
  398. try {
  399. switch (type) {
  400. case CUSTOM:
  401. fSuccess = ((TYPE_CUSTOM)pFunction)(dwOptions, lpas);
  402. break;
  403. case STDARGS0:
  404. fSuccess = ((TYPE_STDARGS0)pFunction)(dwOptions);
  405. break;
  406. case STDARGS1:
  407. fSuccess = ((TYPE_STDARGS1)pFunction)(dwOptions, OptEvalExp(lpas));
  408. break;
  409. case STDARGS2:
  410. param1 = OptEvalExp2(&lpas);
  411. fSuccess = ((TYPE_STDARGS2)pFunction)(dwOptions, param1, OptEvalExp(lpas));
  412. break;
  413. case STDARGS3:
  414. param1 = OptEvalExp2(&lpas);
  415. param2 = OptEvalExp2(&lpas);
  416. fSuccess = ((TYPE_STDARGS3)pFunction)(dwOptions, param1, param2, OptEvalExp(lpas));
  417. break;
  418. case STDARGS4:
  419. param1 = OptEvalExp2(&lpas);
  420. param2 = OptEvalExp2(&lpas);
  421. param3 = OptEvalExp2(&lpas);
  422. fSuccess = ((TYPE_STDARGS4)pFunction)(dwOptions, param1, param2, param3, OptEvalExp(lpas));
  423. break;
  424. default:
  425. Print("CommonEP: Don't recognize function type %d.\n", type);
  426. break;
  427. }
  428. } except (GetExceptionCode() == STATUS_NONCONTINUABLE_EXCEPTION ?
  429. EXCEPTION_EXECUTE_HANDLER : EXCEPTION_CONTINUE_SEARCH) {
  430. Print(pszCantContinue, pszExtName);
  431. }
  432. Exit:
  433. if (!fSuccess) {
  434. Print("%s failed.\n", pszName);
  435. Ihelp(0, pszName);
  436. }
  437. }
  438. /*
  439. * Entrypoint functions (generated from exts.h)
  440. */
  441. #ifdef KERNEL
  442. #define DOIT(name, h1, h2, opts, type) \
  443. VOID name##( \
  444. HANDLE hcp, \
  445. HANDLE hct, \
  446. DWORD dwcp, \
  447. DWORD dwp, \
  448. LPSTR lpas) \
  449. { \
  450. CommonEP(I##name, #name, type, opts, hcp, hct, dwcp, dwp, lpas); \
  451. }
  452. #else // !KERNEL
  453. #define DOIT(name, h1, h2, opts, type) \
  454. VOID name##( \
  455. HANDLE hcp, \
  456. HANDLE hct, \
  457. DWORD dwcp, \
  458. PWINDBG_EXTENSION_APIS lpea, \
  459. LPSTR lpas) \
  460. { \
  461. CommonEP(I##name, #name, type, opts, hcp, hct, dwcp, lpea, lpas); \
  462. }
  463. #endif // !KERNEL
  464. #include "exts.h"
  465. #undef DOIT
  466. /*
  467. * Standard help extension - present in all standard extensions.
  468. */
  469. BOOL Ihelp(
  470. DWORD opts,
  471. LPSTR lpas)
  472. {
  473. #define DOIT(name, help1, help2, opts, type) { #name, help1, help2 },
  474. static struct {
  475. LPSTR pszCmdName;
  476. LPSTR pszHelp1;
  477. LPSTR pszHelp2;
  478. } he[] = {
  479. #include "exts.h"
  480. };
  481. #undef DOIT
  482. int i;
  483. while (*lpas == ' ')
  484. lpas++;
  485. if (*lpas == '\0') {
  486. Print("-------------- %s Debug Extension help:--------------\n\n", pszExtName);
  487. for (i = 0; i < sizeof(he) / sizeof(he[0]); i++) {
  488. if (IsCtrlCHit()) {
  489. break;
  490. }
  491. Print(he[i].pszHelp1);
  492. if (opts & OFLAG(v)) {
  493. PrintHuge(he[i].pszHelp2);
  494. }
  495. }
  496. return(TRUE);
  497. } else {
  498. for (i = 0; i < sizeof(he) / sizeof(he[0]); i++) {
  499. if (IsCtrlCHit()) {
  500. break;
  501. }
  502. if (strcmp(lpas, he[i].pszCmdName) == 0) {
  503. Print(he[i].pszHelp1);
  504. PrintHuge(he[i].pszHelp2);
  505. return(TRUE);
  506. }
  507. }
  508. Print("%s is not supported.\n", lpas);
  509. }
  510. return(FALSE);
  511. }