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.

514 lines
14 KiB

  1. /*++
  2. Copyright (c) 1993 Microsoft Corporation
  3. Module Name:
  4. walk.c
  5. Abstract:
  6. This function implements the stack walking api.
  7. Author:
  8. Wesley Witt (wesw) 1-Oct-1993
  9. Environment:
  10. User Mode
  11. --*/
  12. #include <private.h>
  13. #include "globals.h"
  14. #ifndef PAGE_SIZE
  15. #if defined(_X86_) || defined(_AMD64_)
  16. #define PAGE_SIZE 0x1000
  17. #elif defined(_ALPHA_) || defined(_IA64_)
  18. #define PAGE_SIZE 0x2000
  19. #else
  20. #error Unknown processor architecture
  21. #endif
  22. #endif
  23. BOOL
  24. ReadMemoryRoutineLocal(
  25. HANDLE hProcess,
  26. DWORD64 qwBaseAddress,
  27. LPVOID lpBuffer,
  28. DWORD nSize,
  29. LPDWORD lpNumberOfBytesRead
  30. );
  31. LPVOID
  32. FunctionTableAccessRoutineLocal(
  33. HANDLE hProcess,
  34. DWORD64 AddrBase
  35. );
  36. DWORD64
  37. GetModuleBaseRoutineLocal(
  38. HANDLE hProcess,
  39. DWORD64 ReturnAddress
  40. );
  41. DWORD64
  42. TranslateAddressRoutineLocal(
  43. HANDLE hProcess,
  44. HANDLE hThread,
  45. LPADDRESS64 lpaddr
  46. );
  47. BOOL
  48. ImagepReadMemoryThunk(
  49. HANDLE hProcess,
  50. DWORD64 qwBaseAddress,
  51. LPVOID lpBuffer,
  52. DWORD nSize,
  53. LPDWORD lpNumberOfBytesRead
  54. )
  55. {
  56. PREAD_PROCESS_MEMORY_ROUTINE fnImagepUserReadMemory32;
  57. fnImagepUserReadMemory32 = tlsvar(ImagepUserReadMemory32);
  58. return fnImagepUserReadMemory32(
  59. hProcess,
  60. (DWORD)qwBaseAddress,
  61. lpBuffer,
  62. nSize,
  63. lpNumberOfBytesRead
  64. );
  65. }
  66. LPVOID
  67. ImagepFunctionTableAccessThunk(
  68. HANDLE hProcess,
  69. DWORD64 AddrBase
  70. )
  71. {
  72. PFUNCTION_TABLE_ACCESS_ROUTINE fnImagepUserFunctionTableAccess32;
  73. fnImagepUserFunctionTableAccess32 = tlsvar(ImagepUserFunctionTableAccess32);
  74. return fnImagepUserFunctionTableAccess32(
  75. hProcess,
  76. (DWORD)AddrBase
  77. );
  78. }
  79. PIMAGE_ALPHA64_RUNTIME_FUNCTION_ENTRY
  80. AlphaFunctionTableAccessThunk(
  81. HANDLE hProcess,
  82. DWORD64 AddrBase
  83. )
  84. {
  85. PIMAGE_ALPHA_RUNTIME_FUNCTION_ENTRY FunctionEntry32;
  86. PFUNCTION_TABLE_ACCESS_ROUTINE fnImagepUserFunctionTableAccess32;
  87. fnImagepUserFunctionTableAccess32 = tlsvar(ImagepUserFunctionTableAccess32);
  88. FunctionEntry32 = (PIMAGE_ALPHA_RUNTIME_FUNCTION_ENTRY)
  89. fnImagepUserFunctionTableAccess32(
  90. hProcess,
  91. (DWORD)AddrBase
  92. );
  93. if (FunctionEntry32) {
  94. ConvertAlphaRf32To64( FunctionEntry32, &tlsvar(Axp64FunctionEntry) );
  95. return &tlsvar(Axp64FunctionEntry);
  96. }
  97. return NULL;
  98. }
  99. DWORD64
  100. ImagepGetModuleBaseThunk(
  101. HANDLE hProcess,
  102. DWORD64 ReturnAddress
  103. )
  104. {
  105. PGET_MODULE_BASE_ROUTINE fnImagepUserGetModuleBase32;
  106. fnImagepUserGetModuleBase32 = tlsvar(ImagepUserGetModuleBase32);
  107. return (ULONG64)(LONG64)(LONG)fnImagepUserGetModuleBase32(
  108. hProcess,
  109. (DWORD)ReturnAddress
  110. );
  111. }
  112. DWORD64
  113. ImagepTranslateAddressThunk(
  114. HANDLE hProcess,
  115. HANDLE hThread,
  116. LPADDRESS64 lpaddr
  117. )
  118. {
  119. return 0;
  120. }
  121. void
  122. StackFrame32To64(
  123. LPSTACKFRAME StackFrame32,
  124. LPSTACKFRAME64 StackFrame64
  125. )
  126. {
  127. Address32To64(&StackFrame32->AddrPC, &StackFrame64->AddrPC );
  128. Address32To64(&StackFrame32->AddrReturn, &StackFrame64->AddrReturn );
  129. Address32To64(&StackFrame32->AddrFrame, &StackFrame64->AddrFrame );
  130. Address32To64(&StackFrame32->AddrStack, &StackFrame64->AddrStack );
  131. StackFrame64->FuncTableEntry = StackFrame32->FuncTableEntry;
  132. StackFrame64->Far = StackFrame32->Far;
  133. StackFrame64->Virtual = StackFrame32->Virtual;
  134. StackFrame64->Params[0] = StackFrame32->Params[0];
  135. StackFrame64->Params[1] = StackFrame32->Params[1];
  136. StackFrame64->Params[2] = StackFrame32->Params[2];
  137. StackFrame64->Params[3] = StackFrame32->Params[3];
  138. StackFrame64->Reserved[0] = StackFrame32->Reserved[0];
  139. StackFrame64->Reserved[1] = StackFrame32->Reserved[1];
  140. StackFrame64->Reserved[2] = StackFrame32->Reserved[2];
  141. KdHelp32To64(&StackFrame32->KdHelp, &StackFrame64->KdHelp);
  142. }
  143. void
  144. StackFrame64To32(
  145. LPSTACKFRAME64 StackFrame64,
  146. LPSTACKFRAME StackFrame32
  147. )
  148. {
  149. Address64To32(&StackFrame64->AddrPC, &StackFrame32->AddrPC );
  150. Address64To32(&StackFrame64->AddrReturn, &StackFrame32->AddrReturn );
  151. Address64To32(&StackFrame64->AddrFrame, &StackFrame32->AddrFrame );
  152. Address64To32(&StackFrame64->AddrStack, &StackFrame32->AddrStack );
  153. StackFrame32->FuncTableEntry = StackFrame64->FuncTableEntry;
  154. StackFrame32->Far = StackFrame64->Far;
  155. StackFrame32->Virtual = StackFrame64->Virtual;
  156. StackFrame32->Params[0] = (ULONG)StackFrame64->Params[0];
  157. StackFrame32->Params[1] = (ULONG)StackFrame64->Params[1];
  158. StackFrame32->Params[2] = (ULONG)StackFrame64->Params[2];
  159. StackFrame32->Params[3] = (ULONG)StackFrame64->Params[3];
  160. StackFrame32->Reserved[0] = (ULONG)StackFrame64->Reserved[0];
  161. StackFrame32->Reserved[1] = (ULONG)StackFrame64->Reserved[1];
  162. StackFrame32->Reserved[2] = (ULONG)StackFrame64->Reserved[2];
  163. }
  164. BOOL
  165. StackWalk(
  166. DWORD MachineType,
  167. HANDLE hProcess,
  168. HANDLE hThread,
  169. LPSTACKFRAME StackFrame32,
  170. LPVOID ContextRecord,
  171. PREAD_PROCESS_MEMORY_ROUTINE ReadMemory32,
  172. PFUNCTION_TABLE_ACCESS_ROUTINE FunctionTableAccess32,
  173. PGET_MODULE_BASE_ROUTINE GetModuleBase32,
  174. PTRANSLATE_ADDRESS_ROUTINE TranslateAddress32
  175. )
  176. {
  177. BOOL rval;
  178. BOOL UseSym = FALSE;
  179. PREAD_PROCESS_MEMORY_ROUTINE64 ReadMemory;
  180. PFUNCTION_TABLE_ACCESS_ROUTINE64 FunctionTableAccess;
  181. PGET_MODULE_BASE_ROUTINE64 GetModuleBase;
  182. PTRANSLATE_ADDRESS_ROUTINE64 TranslateAddress;
  183. STACKFRAME64 StackFrame;
  184. // Alpha stack walking no longer requires the FunctionTableAccess callback
  185. // except for backward compatability with debuggers that didn't specify
  186. // a GetModuleBase callback. If the GetModuleBase routine is provided
  187. // then set FunctionTableAccess to NULL to prevent a mixture of the
  188. // callback and read-from-image methods of accessing function table entries.
  189. if (MachineType == IMAGE_FILE_MACHINE_ALPHA) {
  190. if (GetModuleBase32 == NULL && FunctionTableAccess32) {
  191. FunctionTableAccess = (PFUNCTION_TABLE_ACCESS_ROUTINE64)AlphaFunctionTableAccessThunk;
  192. tlsvar(ImagepUserFunctionTableAccess32) = FunctionTableAccess32;
  193. } else {
  194. FunctionTableAccess = NULL;
  195. }
  196. } else {
  197. if (FunctionTableAccess32) {
  198. tlsvar(ImagepUserFunctionTableAccess32) = FunctionTableAccess32;
  199. FunctionTableAccess = ImagepFunctionTableAccessThunk;
  200. } else {
  201. FunctionTableAccess = FunctionTableAccessRoutineLocal;
  202. UseSym = TRUE;
  203. }
  204. }
  205. if (GetModuleBase32) {
  206. tlsvar(ImagepUserGetModuleBase32) = GetModuleBase32;
  207. GetModuleBase = ImagepGetModuleBaseThunk;
  208. } else {
  209. GetModuleBase = GetModuleBaseRoutineLocal;
  210. UseSym = TRUE;
  211. }
  212. if (ReadMemory32) {
  213. tlsvar(ImagepUserReadMemory32) = ReadMemory32;
  214. ReadMemory = ImagepReadMemoryThunk;
  215. } else {
  216. ReadMemory = ReadMemoryRoutineLocal;
  217. }
  218. if (TranslateAddress32) {
  219. tlsvar(ImagepUserTranslateAddress32) = TranslateAddress32;
  220. TranslateAddress = ImagepTranslateAddressThunk;
  221. } else {
  222. TranslateAddress = TranslateAddressRoutineLocal;
  223. }
  224. if (UseSym) {
  225. //
  226. // We are using the code in symbols.c
  227. // hProcess better be a real valid process handle
  228. //
  229. //
  230. // Always call syminitialize. It's a nop if process
  231. // is already loaded.
  232. //
  233. if (!SymInitialize( hProcess, NULL, FALSE )) {
  234. return FALSE;
  235. }
  236. }
  237. StackFrame32To64(StackFrame32, &StackFrame);
  238. switch (MachineType) {
  239. case IMAGE_FILE_MACHINE_I386:
  240. rval = WalkX86( hProcess,
  241. hThread,
  242. &StackFrame,
  243. ContextRecord,
  244. ReadMemory,
  245. FunctionTableAccess,
  246. GetModuleBase,
  247. TranslateAddress,
  248. 0
  249. );
  250. break;
  251. case IMAGE_FILE_MACHINE_ALPHA:
  252. rval = WalkAlpha( hProcess,
  253. &StackFrame,
  254. ContextRecord,
  255. ReadMemory,
  256. GetModuleBase,
  257. FunctionTableAccess,
  258. FALSE
  259. );
  260. break;
  261. case IMAGE_FILE_MACHINE_IA64:
  262. case IMAGE_FILE_MACHINE_ALPHA64:
  263. case IMAGE_FILE_MACHINE_AMD64:
  264. default:
  265. rval = FALSE;
  266. break;
  267. }
  268. if (rval) {
  269. StackFrame64To32(&StackFrame, StackFrame32);
  270. }
  271. return rval;
  272. }
  273. BOOL
  274. StackWalk64(
  275. DWORD MachineType,
  276. HANDLE hProcess,
  277. HANDLE hThread,
  278. LPSTACKFRAME64 StackFrame,
  279. LPVOID ContextRecord,
  280. PREAD_PROCESS_MEMORY_ROUTINE64 ReadMemory,
  281. PFUNCTION_TABLE_ACCESS_ROUTINE64 FunctionTableAccess,
  282. PGET_MODULE_BASE_ROUTINE64 GetModuleBase,
  283. PTRANSLATE_ADDRESS_ROUTINE64 TranslateAddress
  284. )
  285. {
  286. BOOL rval;
  287. BOOL UseSym = FALSE;
  288. g.MachineType = MachineType;
  289. if (!FunctionTableAccess) {
  290. FunctionTableAccess = FunctionTableAccessRoutineLocal;
  291. UseSym = TRUE;
  292. }
  293. if (!GetModuleBase) {
  294. GetModuleBase = GetModuleBaseRoutineLocal;
  295. UseSym = TRUE;
  296. }
  297. if (!ReadMemory) {
  298. ReadMemory = ReadMemoryRoutineLocal;
  299. }
  300. if (!TranslateAddress) {
  301. TranslateAddress = TranslateAddressRoutineLocal;
  302. }
  303. if (UseSym) {
  304. //
  305. // We are using the code in symbols.c
  306. // hProcess better be a real valid process handle
  307. //
  308. //
  309. // Always call syminitialize. It's a nop if process
  310. // is already loaded.
  311. //
  312. if (!SymInitialize( hProcess, NULL, FALSE )) {
  313. return FALSE;
  314. }
  315. }
  316. switch (MachineType) {
  317. case IMAGE_FILE_MACHINE_I386:
  318. rval = WalkX86( hProcess,
  319. hThread,
  320. StackFrame,
  321. ContextRecord,
  322. ReadMemory,
  323. FunctionTableAccess,
  324. GetModuleBase,
  325. TranslateAddress,
  326. WALK_FIX_FPO_EBP
  327. );
  328. break;
  329. case IMAGE_FILE_MACHINE_IA64:
  330. rval = WalkIa64( hProcess,
  331. StackFrame,
  332. ContextRecord,
  333. ReadMemory,
  334. FunctionTableAccess,
  335. GetModuleBase
  336. );
  337. break;
  338. case IMAGE_FILE_MACHINE_ALPHA:
  339. rval = WalkAlpha( hProcess,
  340. StackFrame,
  341. ContextRecord,
  342. ReadMemory,
  343. GetModuleBase,
  344. FunctionTableAccess,
  345. FALSE
  346. );
  347. break;
  348. case IMAGE_FILE_MACHINE_ALPHA64:
  349. rval = WalkAlpha( hProcess,
  350. StackFrame,
  351. ContextRecord,
  352. ReadMemory,
  353. GetModuleBase,
  354. FunctionTableAccess,
  355. TRUE
  356. );
  357. break;
  358. case IMAGE_FILE_MACHINE_AMD64:
  359. rval = WalkAmd64( hProcess,
  360. StackFrame,
  361. ContextRecord,
  362. ReadMemory,
  363. FunctionTableAccess,
  364. GetModuleBase
  365. );
  366. break;
  367. default:
  368. rval = FALSE;
  369. break;
  370. }
  371. return rval;
  372. }
  373. BOOL
  374. ReadMemoryRoutineLocal(
  375. HANDLE hProcess,
  376. DWORD64 qwBaseAddress,
  377. LPVOID lpBuffer,
  378. DWORD nSize,
  379. LPDWORD lpNumberOfBytesRead
  380. )
  381. {
  382. // ReadProcessMemory will fail if any part of the
  383. // region to read does not have read access. This
  384. // routine attempts to read the largest valid prefix
  385. // so it has to break up reads on page boundaries.
  386. BOOL Status = TRUE;
  387. SIZE_T TotalBytesRead = 0;
  388. SIZE_T Read;
  389. ULONG ReadSize;
  390. while (nSize > 0) {
  391. // Calculate bytes to read and don't let read cross
  392. // a page boundary.
  393. ReadSize = PAGE_SIZE - (ULONG)(qwBaseAddress & (PAGE_SIZE - 1));
  394. ReadSize = min(nSize, ReadSize);
  395. if (!ReadProcessMemory(hProcess, (PVOID)(ULONG_PTR)qwBaseAddress,
  396. lpBuffer, ReadSize, &Read)) {
  397. if (TotalBytesRead == 0) {
  398. // If we haven't read anything indicate failure.
  399. Status = FALSE;
  400. }
  401. break;
  402. }
  403. TotalBytesRead += Read;
  404. qwBaseAddress += Read;
  405. lpBuffer = (PVOID)((PUCHAR)lpBuffer + Read);
  406. nSize -= (DWORD)Read;
  407. }
  408. *lpNumberOfBytesRead = (DWORD)TotalBytesRead;
  409. return Status;
  410. }
  411. LPVOID
  412. FunctionTableAccessRoutineLocal(
  413. HANDLE hProcess,
  414. DWORD64 AddrBase
  415. )
  416. {
  417. return SymFunctionTableAccess64(hProcess, AddrBase);
  418. }
  419. DWORD64
  420. GetModuleBaseRoutineLocal(
  421. HANDLE hProcess,
  422. DWORD64 ReturnAddress
  423. )
  424. {
  425. IMAGEHLP_MODULE64 ModuleInfo = {0};
  426. ModuleInfo.SizeOfStruct = sizeof(ModuleInfo);
  427. if (SymGetModuleInfo64(hProcess, ReturnAddress, &ModuleInfo)) {
  428. return ModuleInfo.BaseOfImage;
  429. } else {
  430. return 0;
  431. }
  432. }
  433. DWORD64
  434. TranslateAddressRoutineLocal(
  435. HANDLE hProcess,
  436. HANDLE hThread,
  437. LPADDRESS64 paddr
  438. )
  439. {
  440. return 0;
  441. }