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.

641 lines
18 KiB

  1. /*++
  2. Copyright (c) 1995-1999 Microsoft Corporation
  3. Module Name:
  4. entrypt.c
  5. Abstract:
  6. Debugger extensions that give an entry point from either an
  7. intel address or a native address
  8. Author:
  9. 02-Aug-1995 Ori Gershony (t-orig)
  10. Revision History:
  11. --*/
  12. #define _WOW64CPUDBGAPI_
  13. #define DECLARE_CPU_DEBUGGER_INTERFACE
  14. #include <nt.h>
  15. #include <ntrtl.h>
  16. #include <nturtl.h>
  17. #include <windows.h>
  18. #include <imagehlp.h>
  19. #include <ntsdexts.h>
  20. #include "ntosdef.h"
  21. #include "v86emul.h"
  22. #include "ia64.h"
  23. #include "wow64.h"
  24. #include "wow64cpu.h"
  25. #include "threadst.h"
  26. #include "entrypt.h"
  27. extern HANDLE Process;
  28. extern HANDLE Thread;
  29. extern PNTSD_OUTPUT_ROUTINE OutputRoutine;
  30. extern PNTSD_GET_SYMBOL GetSymbolRoutine;
  31. extern PNTSD_GET_EXPRESSION GetExpression;
  32. extern PWOW64GETCPUDATA CpuGetData;
  33. extern LPSTR ArgumentString;
  34. #define DEBUGGERPRINT (*OutputRoutine)
  35. #define GETSYMBOL (*GetSymbolRoutine)
  36. #define GETEXPRESSION (*GetExpression)
  37. #define CPUGETDATA (*CpuGetData)
  38. extern THREADSTATE LocalCpuContext;
  39. extern BOOL ContextFetched;
  40. extern BOOL ContextDirty;
  41. #define DECLARE_EXTAPI(name) \
  42. VOID \
  43. name( \
  44. HANDLE hCurrentProcess, \
  45. HANDLE hCurrentThread, \
  46. DWORD64 dwCurrentPc, \
  47. PNTSD_EXTENSION_APIS lpExtensionApis, \
  48. LPSTR lpArgumentString \
  49. )
  50. #define INIT_EXTAPI \
  51. Process = hCurrentProcess; \
  52. Thread = hCurrentThread; \
  53. OutputRoutine = lpExtensionApis->lpOutputRoutine; \
  54. GetSymbolRoutine = lpExtensionApis->lpGetSymbolRoutine; \
  55. GetExpression = lpExtensionApis->lpGetExpressionRoutine; \
  56. ArgumentString = lpArgumentString;
  57. #if _ALPHA_
  58. #define EXCEPTIONDATA_SIGNATURE 0x01010101
  59. #else
  60. #define EXCEPTIONDATA_SIGNATURE 0x12341234
  61. #endif
  62. // Assume we can have at most 1/2 million entrypoints in a tree:
  63. // With 4MB Translation Cache, we can have 1 million RISC instructions
  64. // in the cache. Assume each Intel instruction requires 2 RISC instructions,
  65. // and that each Intel instruction has its own Entrypoint. In that case,
  66. // there can be at most 1/2 million entrypoints. Realistically, that number
  67. // should be much smaller (like 50,000).
  68. //
  69. // Also, since the Entrypoint tree is balanced (a property of Red-Black trees),
  70. // the required stack depth should be log2(500,000).
  71. //
  72. #define MAX_EPN_STACK_DEPTH 512*1024
  73. ULONG_PTR EPN_Stack[MAX_EPN_STACK_DEPTH];
  74. ULONG EPN_StackTop;
  75. ULONG EPN_MaxStackDepth;
  76. #define EPN_STACK_RESET() EPN_StackTop=0; EPN_MaxStackDepth=0
  77. #define EPN_PUSH(x) { \
  78. if (EPN_StackTop == MAX_EPN_STACK_DEPTH-1) { \
  79. DEBUGGERPRINT("Error: EPN stack overflow\n"); \
  80. goto Error; \
  81. } else { \
  82. EPN_Stack[EPN_StackTop] = x; \
  83. EPN_StackTop++; \
  84. if (EPN_StackTop > EPN_MaxStackDepth) EPN_MaxStackDepth=EPN_StackTop; \
  85. } \
  86. }
  87. #define EPN_POP(x) { \
  88. if (EPN_StackTop == 0) { \
  89. DEBUGGERPRINT("Error: EPN stack underflow\n"); \
  90. goto Error; \
  91. } else { \
  92. EPN_StackTop--; \
  93. x = EPN_Stack[EPN_StackTop]; \
  94. } \
  95. }
  96. NTSTATUS
  97. TryGetExpr(
  98. PSTR Expression,
  99. PULONG_PTR pValue
  100. );
  101. VOID
  102. findEPI(
  103. ULONG_PTR intelAddress,
  104. ULONG_PTR intelRoot
  105. )
  106. /*++
  107. Routine Description:
  108. This routine finds an entry point which contains intelAddress if in the
  109. tree under intelRoot.
  110. Arguments:
  111. intelAddress -- The intel address to be contained in the entry point
  112. intelRoot -- The root of the tree to use for the search
  113. Return Value:
  114. return-value - none
  115. --*/
  116. {
  117. EPNODE entrypoint;
  118. NTSTATUS Status;
  119. for (;;) {
  120. Status = NtReadVirtualMemory(Process, (PVOID)intelRoot, (PVOID) (&entrypoint), sizeof(EPNODE), NULL);
  121. if (!NT_SUCCESS(Status)) {
  122. DEBUGGERPRINT("Error: cannot read value of entry point at location %x\n", intelRoot);
  123. return;
  124. }
  125. if (intelRoot == (ULONG_PTR)entrypoint.intelLeft) {
  126. //
  127. // At a NIL node.
  128. //
  129. break;
  130. }
  131. if (intelAddress < (ULONG_PTR)entrypoint.ep.intelStart){
  132. intelRoot = (ULONG_PTR)entrypoint.intelLeft;
  133. } else if (intelAddress > (ULONG_PTR)entrypoint.ep.intelEnd) {
  134. intelRoot = (ULONG_PTR)entrypoint.intelRight;
  135. } else {
  136. DEBUGGERPRINT ("Entry point for intel address %x is at %x\n", intelAddress, intelRoot);
  137. DEBUGGERPRINT ("intelStart = %x, intelEnd = %x\n", entrypoint.ep.intelStart, entrypoint.ep.intelEnd);
  138. DEBUGGERPRINT ("nativeStart = %x, nativeEnd = %x\n", entrypoint.ep.nativeStart, entrypoint.ep.nativeEnd);
  139. return;
  140. }
  141. }
  142. DEBUGGERPRINT("Entry point corresponding to intel address %x is not in the tree.\n", intelAddress);
  143. }
  144. DECLARE_EXTAPI(epi)
  145. /*++
  146. Routine Description:
  147. This routine dumps the entry point information for an intel address
  148. Arguments:
  149. Return Value:
  150. return-value - none
  151. --*/
  152. {
  153. CHAR *pchCmd;
  154. ULONG_PTR intelAddress, pIntelRoot, intelRoot;
  155. NTSTATUS Status;
  156. INIT_EXTAPI;
  157. //
  158. // fetch the CpuContext for the current thread
  159. //
  160. if (!CpuDbgGetRemoteContext(CPUGETDATA(Process, Thread))) {
  161. return;
  162. }
  163. DEBUGGERPRINT ("Argument: %s\n", ArgumentString);
  164. //
  165. // advance to first token
  166. //
  167. pchCmd = ArgumentString;
  168. while (*pchCmd && isspace(*pchCmd)) {
  169. pchCmd++;
  170. }
  171. //
  172. // if exists must be intel address
  173. //
  174. if (*pchCmd) {
  175. Status = TryGetExpr(pchCmd, &intelAddress);
  176. if (!NT_SUCCESS(Status)) {
  177. DEBUGGERPRINT("Invalid Intel Address '%s' Status %x\n", pchCmd, Status);
  178. return;
  179. }
  180. } else {
  181. // Take the current eip value as the first argument
  182. intelAddress = LocalCpuContext.eipReg.i4;
  183. }
  184. Status = TryGetExpr("intelRoot", &pIntelRoot);
  185. if (!NT_SUCCESS(Status)) {
  186. DEBUGGERPRINT("Error: cannot evaluate intelRoot\n");
  187. return;
  188. }
  189. Status = NtReadVirtualMemory(Process, (PVOID)pIntelRoot, (PVOID) (&intelRoot), sizeof(intelRoot), NULL);
  190. if (!NT_SUCCESS(Status)) {
  191. DEBUGGERPRINT("Error: cannot read value of intelRoot\n");
  192. return;
  193. }
  194. findEPI(intelAddress, intelRoot);
  195. }
  196. ULONG_PTR
  197. findEPN(
  198. ULONG_PTR nativeAddress,
  199. ULONG_PTR intelRoot
  200. )
  201. /*++
  202. Routine Description:
  203. This routine finds an entry point which contains nativeAddress if in the
  204. tree under intelRoot.
  205. Arguments:
  206. nativeAddress -- The native address to be contained in the entry point
  207. intelRoot -- The root of the tree to use for the search
  208. Return Value:
  209. return-value - NULL - entrypoint not found
  210. non-NULL - ptr to ENTRYPOINT matching the native address
  211. --*/
  212. {
  213. EPNODE entrypoint;
  214. NTSTATUS Status;
  215. PVOID SubEP;
  216. EPN_STACK_RESET();
  217. EPN_PUSH(0);
  218. while (intelRoot != 0) {
  219. Status = NtReadVirtualMemory(Process, (PVOID)intelRoot, (PVOID) (&entrypoint), sizeof(EPNODE), NULL);
  220. if (!NT_SUCCESS(Status)) {
  221. DEBUGGERPRINT("Error: cannot read value of entry point at location %x\n", intelRoot);
  222. return 0;
  223. }
  224. if ((nativeAddress >= (ULONG_PTR)entrypoint.ep.nativeStart) &&
  225. (nativeAddress <= (ULONG_PTR)entrypoint.ep.nativeEnd)) {
  226. DEBUGGERPRINT ("Entry point for native address %x is at %x\n", nativeAddress, intelRoot);
  227. DEBUGGERPRINT ("intelStart = %x, intelEnd = %x\n", entrypoint.ep.intelStart, entrypoint.ep.intelEnd);
  228. DEBUGGERPRINT ("nativeStart = %x, nativeEnd = %x\n", entrypoint.ep.nativeStart, entrypoint.ep.nativeEnd);
  229. return intelRoot;
  230. }
  231. // If there are sub-entrypoints, search them, too.
  232. SubEP = (PVOID)entrypoint.ep.SubEP;
  233. while (SubEP) {
  234. ENTRYPOINT ep;
  235. Status = NtReadVirtualMemory(Process, SubEP, (PVOID)(&ep), sizeof(ENTRYPOINT), NULL);
  236. if (!NT_SUCCESS(Status)) {
  237. DEBUGGERPRINT("Error: cannot read value of sub-entry point at location %x\n", SubEP);
  238. return 0;
  239. }
  240. if ((nativeAddress >= (ULONG_PTR)ep.nativeStart) &&
  241. (nativeAddress <= (ULONG_PTR)ep.nativeEnd)) {
  242. DEBUGGERPRINT ("Entry point for native address %x is at %x\n", nativeAddress, intelRoot);
  243. DEBUGGERPRINT ("Sub-entrypoint actually containing the native address is %x\n", SubEP);
  244. DEBUGGERPRINT ("intelStart = %x, intelEnd = %x\n", ep.intelStart, ep.intelEnd);
  245. DEBUGGERPRINT ("nativeStart = %x, nativeEnd = %x\n", ep.nativeStart, ep.nativeEnd);
  246. return (ULONG_PTR)SubEP;
  247. }
  248. SubEP = ep.SubEP;
  249. }
  250. if ((ULONG_PTR)entrypoint.intelRight != intelRoot) {
  251. EPN_PUSH((ULONG_PTR)entrypoint.intelRight);
  252. }
  253. if ((ULONG_PTR)entrypoint.intelLeft != intelRoot) {
  254. EPN_PUSH((ULONG_PTR)entrypoint.intelLeft);
  255. }
  256. EPN_POP(intelRoot);
  257. }
  258. DEBUGGERPRINT("Entry point corresponding to native address %x is not in the tree.\n", nativeAddress);
  259. Error:
  260. return 0;
  261. }
  262. VOID
  263. FindEipFromNativeAddress(
  264. ULONG_PTR nativeAddress,
  265. ULONG_PTR pEP
  266. )
  267. {
  268. ENTRYPOINT EP;
  269. NTSTATUS Status;
  270. PVOID pUL;
  271. ULONG UL;
  272. ULONG RiscStart;
  273. ULONG RiscEnd;
  274. ULONG cEntryPoints;
  275. Status = NtReadVirtualMemory(Process, (PVOID)pEP, (PVOID)(&EP), sizeof(ENTRYPOINT), NULL);
  276. if (!NT_SUCCESS(Status)) {
  277. DEBUGGERPRINT("Error: cannot read value of entry point at location %x\n", pEP);
  278. return;
  279. }
  280. //
  281. // Search forward to the next EXCEPTIONDATA_SIGNATURE in the cache
  282. //
  283. pUL = (PVOID)(((ULONG_PTR)EP.nativeEnd+3) & ~3);
  284. do {
  285. Status = NtReadVirtualMemory(Process, pUL, &UL, sizeof(ULONG), NULL);
  286. if (!NT_SUCCESS(Status)) {
  287. DEBUGGERPRINT("Error: error reading from TC at %x\n", pUL);
  288. return;
  289. }
  290. pUL = (PVOID)( (PULONG)pUL + 1);
  291. } while (UL != EXCEPTIONDATA_SIGNATURE);
  292. //
  293. // Found the signature, get cEntryPoints
  294. //
  295. Status = NtReadVirtualMemory(Process, pUL, &cEntryPoints, sizeof(ULONG), NULL);
  296. if (!NT_SUCCESS(Status)) {
  297. DEBUGGERPRINT("Error: error reading from TC at %x\n", pUL);
  298. return;
  299. }
  300. pUL = (PVOID)( (PULONG)pUL + 1); // skip cEntryPoints
  301. while (1) {
  302. Status = NtReadVirtualMemory(Process, pUL, &UL, sizeof(ULONG), NULL);
  303. if (!NT_SUCCESS(Status)) {
  304. DEBUGGERPRINT("Error: error reading from TC at %x\n", pUL);
  305. return;
  306. }
  307. if (UL == (ULONG)pEP) {
  308. //
  309. // Found the right ENTRYPOINT pointer
  310. //
  311. break;
  312. }
  313. //
  314. // Skip over the pairs of (x86, risc) offsets
  315. //
  316. do {
  317. pUL = (PVOID)( (PULONG)pUL + 1);
  318. Status = NtReadVirtualMemory(Process, pUL, &UL, sizeof(ULONG), NULL);
  319. if (!NT_SUCCESS(Status)) {
  320. DEBUGGERPRINT("Error: error reading from TC at %x\n", pUL);
  321. return;
  322. }
  323. } while ((UL & 1) == 0);
  324. cEntryPoints--;
  325. if (cEntryPoints == 0) {
  326. DEBUGGERPRINT("Error: cEntryPoints went to 0 at %x\n", pUL);
  327. return;
  328. }
  329. pUL = (PVOID)( (PULONG)pUL + 1);
  330. }
  331. //
  332. // pUL points at the correct entrypoint pointer
  333. //
  334. nativeAddress -= (ULONG_PTR)EP.nativeStart; // Make relative to start of EP
  335. RiscStart = 0; // Also relative to start of EP
  336. while (1) {
  337. ULONG UL2;
  338. pUL = (PVOID)( (PULONG)pUL + 1);
  339. Status = NtReadVirtualMemory(Process, pUL, &UL, sizeof(ULONG), NULL);
  340. if (!NT_SUCCESS(Status)) {
  341. DEBUGGERPRINT("Error: error reading from TC at %x\n", pUL);
  342. return;
  343. }
  344. if (UL & 1) {
  345. break;
  346. }
  347. Status = NtReadVirtualMemory(Process, (PVOID)((PULONG)pUL+1), &UL2, sizeof(ULONG), NULL);
  348. if (!NT_SUCCESS(Status)) {
  349. DEBUGGERPRINT("Error: error reading from TC at %p\n", (ULONG_PTR)pUL+4);
  350. return;
  351. }
  352. RiscEnd = LOWORD(UL2) & 0xfffe; // RiscEnd = RiscStart of next instr
  353. if ((RiscStart <= nativeAddress && nativeAddress < RiscEnd)
  354. || (UL & 1)) {
  355. DEBUGGERPRINT("Corresponding EIP=%p\n", (ULONG_PTR)EP.intelStart + HIWORD(UL));
  356. return;
  357. }
  358. }
  359. return;
  360. }
  361. DECLARE_EXTAPI(epn)
  362. /*++
  363. Routine Description:
  364. This routine dumps the entry point information for a native address
  365. Arguments:
  366. Return Value:
  367. return-value - none
  368. --*/
  369. {
  370. CHAR *pchCmd;
  371. ULONG_PTR nativeAddress, pIntelRoot, intelRoot, EP;
  372. NTSTATUS Status;
  373. INIT_EXTAPI;
  374. //
  375. // fetch the CpuContext for the current thread
  376. //
  377. if (!CpuDbgGetRemoteContext(CPUGETDATA(Process, Thread))) {
  378. return;
  379. }
  380. //
  381. // advance to first token
  382. //
  383. pchCmd = ArgumentString;
  384. while (*pchCmd && isspace(*pchCmd)) {
  385. pchCmd++;
  386. }
  387. //
  388. // if exists must be intel address
  389. //
  390. if (*pchCmd) {
  391. Status = TryGetExpr(pchCmd, &nativeAddress);
  392. if (!NT_SUCCESS(Status)) {
  393. DEBUGGERPRINT("Invalid Native Address '%s' Status %x\n", pchCmd, Status);
  394. return;
  395. }
  396. } else {
  397. // Use the current pc as the host address
  398. CONTEXT context;
  399. if (!GetThreadContext(Thread, &context)){
  400. DEBUGGERPRINT("Error: cannot get thread context\n");
  401. return;
  402. }
  403. #if defined (_MIPS_) || defined (_ALPHA_)
  404. nativeAddress = (ULONG)context.Fir;
  405. #elif defined (_PPC_)
  406. nativeAddress = context.Iar;
  407. #endif
  408. }
  409. Status = TryGetExpr("intelRoot", &pIntelRoot);
  410. if (!NT_SUCCESS(Status)) {
  411. DEBUGGERPRINT("Error: cannot evaluate intelRoot\n");
  412. return;
  413. }
  414. Status = NtReadVirtualMemory(Process, (PVOID)pIntelRoot, (PVOID) (&intelRoot), sizeof(ULONG_PTR), NULL);
  415. if (!NT_SUCCESS(Status)) {
  416. DEBUGGERPRINT("Error: cannot read value of intelRoot\n");
  417. return;
  418. }
  419. EP = findEPN(nativeAddress, intelRoot);
  420. if (EP) {
  421. FindEipFromNativeAddress(nativeAddress, EP);
  422. }
  423. }
  424. DECLARE_EXTAPI(dumpep)
  425. /*++
  426. Routine Description:
  427. This routine dumps all entrypoints.
  428. Arguments:
  429. Return Value:
  430. return-value - none
  431. --*/
  432. {
  433. ULONG_PTR pIntelRoot, intelRoot;
  434. NTSTATUS Status;
  435. EPNODE entrypoint;
  436. INIT_EXTAPI;
  437. //
  438. // fetch the CpuContext for the current thread
  439. //
  440. if (!CpuDbgGetRemoteContext(CPUGETDATA(Process, Thread))) {
  441. return;
  442. }
  443. Status = TryGetExpr("intelRoot", &pIntelRoot);
  444. if (!NT_SUCCESS(Status)) {
  445. DEBUGGERPRINT("Error: cannot evaluate intelRoot\n");
  446. return;
  447. }
  448. Status = NtReadVirtualMemory(Process, (PVOID)pIntelRoot, (PVOID) (&intelRoot), sizeof(intelRoot), NULL);
  449. if (!NT_SUCCESS(Status)) {
  450. DEBUGGERPRINT("Error: cannot read value of intelRoot\n");
  451. return;
  452. }
  453. EPN_STACK_RESET();
  454. EPN_PUSH(0);
  455. DEBUGGERPRINT("Entrypt: iStart: iEnd: rStart: rEnd: SubEP: iLeft: iRight:\n");
  456. // xxxxxxxx xxxxxxxx xxxxxxxx xxxxxxxx xxxxxxxx xxxxxxxx xxxxxxxx xxxxxxxx
  457. while (intelRoot != 0) {
  458. PENTRYPOINT ep;
  459. Status = NtReadVirtualMemory(Process, (PVOID)intelRoot, (PVOID) (&entrypoint), sizeof(EPNODE), NULL);
  460. if (!NT_SUCCESS(Status)) {
  461. DEBUGGERPRINT("Error: cannot read value of entry point at location %x\n", intelRoot);
  462. return;
  463. }
  464. ep = &entrypoint.ep;
  465. //
  466. // Print all entrypoints except NIL.
  467. //
  468. if ((ULONG_PTR)entrypoint.intelLeft != intelRoot &&
  469. (ULONG_PTR)entrypoint.intelRight != intelRoot) {
  470. DEBUGGERPRINT("%8.8X %8.8X %8.8X %8.8X %8.8X %8.8X %8.8X %8.8X\n",
  471. intelRoot,
  472. ep->intelStart,
  473. ep->intelEnd,
  474. ep->nativeStart,
  475. ep->nativeEnd,
  476. ep->SubEP,
  477. entrypoint.intelLeft,
  478. entrypoint.intelRight
  479. );
  480. while (ep->SubEP) {
  481. PVOID SubEP;
  482. SubEP = (PVOID)ep->SubEP;
  483. Status = NtReadVirtualMemory(Process, SubEP, (PVOID)ep, sizeof(ENTRYPOINT), NULL);
  484. if (!NT_SUCCESS(Status)) {
  485. DEBUGGERPRINT("Error: cannot read value of sub-entry point at location %x\n", SubEP);
  486. return;
  487. }
  488. DEBUGGERPRINT("%8.8X %8.8X %8.8X %8.8X %8.8X %8.8X\n",
  489. SubEP,
  490. ep->intelStart,
  491. ep->intelEnd,
  492. ep->nativeStart,
  493. ep->nativeEnd,
  494. ep->SubEP
  495. );
  496. }
  497. }
  498. if ((ULONG_PTR)entrypoint.intelRight != intelRoot) {
  499. EPN_PUSH((ULONG_PTR)entrypoint.intelRight);
  500. }
  501. if ((ULONG_PTR)entrypoint.intelLeft != intelRoot) {
  502. EPN_PUSH((ULONG_PTR)entrypoint.intelLeft);
  503. }
  504. EPN_POP(intelRoot);
  505. }
  506. DEBUGGERPRINT("---- End of Entrypoint Dump ----\n");
  507. Error:
  508. return;
  509. }