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.

488 lines
13 KiB

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