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.

587 lines
18 KiB

  1. /*++
  2. Copyright (c) 1996 Intel Corporation
  3. Copyright (c) 1993 Microsoft Corporation
  4. Module Name:
  5. walki64.c
  6. Abstract:
  7. This file implements the IA64 stack walking api.
  8. Author:
  9. Environment:
  10. User Mode
  11. --*/
  12. #define _IMAGEHLP_SOURCE_
  13. #define _IA64REG_
  14. #include <nt.h>
  15. #include <ntrtl.h>
  16. #include <nturtl.h>
  17. #include "private.h"
  18. #include "ia64inst.h"
  19. #define NOEXTAPI
  20. #include "wdbgexts.h"
  21. #include "ntdbg.h"
  22. #include "symbols.h"
  23. #include <stdlib.h>
  24. #include <globals.h>
  25. BOOL
  26. WalkIa64Init(
  27. HANDLE hProcess,
  28. LPSTACKFRAME64 StackFrame,
  29. PIA64_CONTEXT Context,
  30. PREAD_PROCESS_MEMORY_ROUTINE64 ReadMemoryRoutine,
  31. PFUNCTION_TABLE_ACCESS_ROUTINE64 FunctionTableAccessRoutine,
  32. PGET_MODULE_BASE_ROUTINE64 GetModuleBase
  33. );
  34. BOOL
  35. WalkIa64Next(
  36. HANDLE hProcess,
  37. LPSTACKFRAME64 StackFrame,
  38. PIA64_CONTEXT Context,
  39. PREAD_PROCESS_MEMORY_ROUTINE64 ReadMemoryRoutine,
  40. PFUNCTION_TABLE_ACCESS_ROUTINE64 FunctionTableAccessRoutine,
  41. PGET_MODULE_BASE_ROUTINE64 GetModuleBase
  42. );
  43. BOOL
  44. GetStackFrameIa64(
  45. HANDLE hProcess,
  46. PULONG64 ReturnAddress,
  47. PULONG64 FramePointer,
  48. PULONG64 BStorePointer,
  49. PIA64_CONTEXT Context,
  50. PREAD_PROCESS_MEMORY_ROUTINE64 ReadMemory,
  51. PFUNCTION_TABLE_ACCESS_ROUTINE64 FunctionTableAccess,
  52. PGET_MODULE_BASE_ROUTINE64 GetModuleBase,
  53. UINT iContext
  54. );
  55. #define CALLBACK_STACK(f) (f->KdHelp.ThCallbackStack)
  56. #define CALLBACK_BSTORE(f) (f->KdHelp.ThCallbackBStore)
  57. #define CALLBACK_NEXT(f) (f->KdHelp.NextCallback)
  58. #define CALLBACK_FUNC(f) (f->KdHelp.KiCallUserMode)
  59. #define CALLBACK_THREAD(f) (f->KdHelp.Thread)
  60. BOOL
  61. WalkIa64(
  62. HANDLE hProcess,
  63. LPSTACKFRAME64 StackFrame,
  64. PVOID ContextRecord,
  65. PREAD_PROCESS_MEMORY_ROUTINE64 ReadMemory,
  66. PFUNCTION_TABLE_ACCESS_ROUTINE64 FunctionTableAccess,
  67. PGET_MODULE_BASE_ROUTINE64 GetModuleBase
  68. )
  69. {
  70. BOOL rval;
  71. PIA64_CONTEXT Context = (PIA64_CONTEXT)ContextRecord;
  72. if (StackFrame->Virtual) {
  73. rval = WalkIa64Next( hProcess,
  74. StackFrame,
  75. Context,
  76. ReadMemory,
  77. FunctionTableAccess,
  78. GetModuleBase
  79. );
  80. } else {
  81. rval = WalkIa64Init( hProcess,
  82. StackFrame,
  83. Context,
  84. ReadMemory,
  85. FunctionTableAccess,
  86. GetModuleBase
  87. );
  88. } // iff
  89. return rval;
  90. } // WalkIa64()
  91. size_t
  92. Vwndia64InitFixupTable(UINT iContext);
  93. BOOL
  94. Vwndia64IsFixupIp(UINT iContext, ULONGLONG Ip);
  95. UINT
  96. Vwndia64NewContext();
  97. BOOL
  98. Vwndia64ValidateContext(UINT* iContextPtr);
  99. void
  100. Vwndia64ReportFailure(UINT iContext, LPCSTR szFormat, ...);
  101. ULONGLONG
  102. VirtualUnwindIa64 (
  103. HANDLE hProcess,
  104. ULONGLONG ImageBase,
  105. DWORD64 ControlPc,
  106. PIMAGE_IA64_RUNTIME_FUNCTION_ENTRY FunctionEntry,
  107. PIA64_CONTEXT ContextRecord,
  108. PREAD_PROCESS_MEMORY_ROUTINE64 ReadMemory,
  109. UINT iContext
  110. );
  111. BOOL
  112. GetStackFrameIa64(
  113. IN HANDLE hProcess,
  114. IN OUT PULONG64 ReturnAddress,
  115. IN OUT PULONG64 FramePointer,
  116. IN OUT PULONG64 BStorePointer,
  117. IN PIA64_CONTEXT Context, // Context members could be modified.
  118. IN PREAD_PROCESS_MEMORY_ROUTINE64 ReadMemory,
  119. IN PFUNCTION_TABLE_ACCESS_ROUTINE64 FunctionTableAccess,
  120. IN PGET_MODULE_BASE_ROUTINE64 GetModuleBase,
  121. IN UINT iContext
  122. )
  123. {
  124. ULONGLONG ImageBase;
  125. PIMAGE_IA64_RUNTIME_FUNCTION_ENTRY rf;
  126. ULONG64 dwRa = (ULONG64)Context->BrRp;
  127. BOOL rval = TRUE;
  128. rf = (PIMAGE_IA64_RUNTIME_FUNCTION_ENTRY) FunctionTableAccess( hProcess, *ReturnAddress );
  129. if (rf) {
  130. //
  131. // The Rp value coming out of mainCRTStartup is set by some run-time
  132. // routine to be 0; this serves to cause an error if someone actually
  133. // does a return from the mainCRTStartup frame.
  134. //
  135. ImageBase = GetModuleBase(hProcess, *ReturnAddress);
  136. dwRa = (ULONG64)VirtualUnwindIa64( hProcess, ImageBase,
  137. *ReturnAddress, rf, Context,
  138. ReadMemory, iContext);
  139. if (!dwRa) {
  140. rval = FALSE;
  141. }
  142. if ((dwRa == *ReturnAddress) &&
  143. // TF-CHKCHK 10/20/99: (*FramePointer == Context->IntSp) &&
  144. (*BStorePointer == Context->RsBSP)) {
  145. rval = FALSE;
  146. }
  147. *ReturnAddress = dwRa;
  148. *FramePointer = Context->IntSp;
  149. *BStorePointer = Context->RsBSP;
  150. } else {
  151. SHORT BsFrameSize;
  152. SHORT TempFrameSize;
  153. if (dwRa == *ReturnAddress)
  154. {
  155. if (dwRa)
  156. {
  157. Vwndia64ReportFailure(iContext,
  158. "Can't find runtime function entry info "
  159. "for %08x`%08x, "
  160. "results might be unreliable!\n",
  161. (ULONG)(*ReturnAddress >> 32),
  162. (ULONG)(*ReturnAddress));
  163. }
  164. if ((*FramePointer == Context->IntSp) &&
  165. (*BStorePointer == Context->RsBSP))
  166. {
  167. rval = FALSE;
  168. }
  169. }
  170. *ReturnAddress = Context->BrRp;
  171. *FramePointer = Context->IntSp;
  172. *BStorePointer = Context->RsBSP;
  173. Context->StIFS = Context->RsPFS;
  174. BsFrameSize = (SHORT)(Context->StIFS >> IA64_PFS_SIZE_SHIFT) & IA64_PFS_SIZE_MASK;
  175. TempFrameSize = BsFrameSize - (SHORT)((Context->RsBSP >> 3) & IA64_NAT_BITS_PER_RNAT_REG);
  176. while (TempFrameSize > 0) {
  177. BsFrameSize++;
  178. TempFrameSize -= IA64_NAT_BITS_PER_RNAT_REG;
  179. }
  180. Context->RsBSPSTORE = ( Context->RsBSP -= (BsFrameSize * sizeof(ULONGLONG)) );
  181. }
  182. //
  183. // The next code intend to fix stack unwind for __declspec(noreturn)
  184. // function calls (like KeBugCheck) where the return address points to
  185. // another (next) function. So changing the ReturnAddress to point to
  186. // calling instruction.
  187. //
  188. if (!Vwndia64IsFixupIp(iContext, *ReturnAddress))
  189. {
  190. ULONG64 CallerAddress = (*ReturnAddress) - 0x10;
  191. PIMAGE_IA64_RUNTIME_FUNCTION_ENTRY rfFix = (PIMAGE_IA64_RUNTIME_FUNCTION_ENTRY)
  192. FunctionTableAccess(hProcess, CallerAddress);
  193. if (rfFix) {
  194. IMAGE_IA64_RUNTIME_FUNCTION_ENTRY rfFixVal = *rfFix;
  195. rf = (PIMAGE_IA64_RUNTIME_FUNCTION_ENTRY)
  196. FunctionTableAccess(hProcess, *ReturnAddress);
  197. if (
  198. !(
  199. rf &&
  200. (rfFixVal.BeginAddress == rf->BeginAddress) &&
  201. (rfFixVal.EndAddress == rf->EndAddress) &&
  202. (rfFixVal.UnwindInfoAddress == rf->UnwindInfoAddress)
  203. )
  204. ){
  205. *ReturnAddress = CallerAddress;
  206. }
  207. }
  208. }
  209. return rval;
  210. }
  211. BOOL
  212. ReadFunctionArgumentsFromContext(
  213. PREAD_PROCESS_MEMORY_ROUTINE64 ReadMemory,
  214. HANDLE hProcess,
  215. PIA64_CONTEXT pContext,
  216. DWORD64 Params[] // WARNING - no runtime size check. 4 entries are assumed...
  217. )
  218. {
  219. BOOL result;
  220. ULONG index;
  221. DWORD cb;
  222. ULONGLONG rsBSP;
  223. // ASSERT( ReadMemory );
  224. // ASSERT( hProcess && (hProcess != INVALID_HANDLE_VALUE) );
  225. if ( !pContext || !Params ) {
  226. return FALSE;
  227. }
  228. //
  229. // IA64 Notes [for the curious reader...]:
  230. //
  231. // The register backing store is organized as a stack in memory that grows
  232. // from lower to higher addresses.
  233. // The Backing Store Pointer (BSP) register contains the address of the first
  234. // (lowest) memory location reserved for the current frame. This corresponds
  235. // to the location at which the GR32 register of the current frame will be spilled.
  236. // The BSPSTORE register contains the address at which the new RSE spill will
  237. // occur.
  238. // The BSP load pointer - address register which corresponds to the next RSE
  239. // fill operation - is not architectually visible.
  240. //
  241. // The RSE spills/fills the NaT bits corresponding to the stacked registers.
  242. // The NaT bits for the stacked registers are spilled/filled in groups of 63
  243. // corresponding to 63 consecutive physical stacked registers. When the RSE spills
  244. // a register to the backing store, the corresponding NaT bit is copied to the RNAT
  245. // register (RSE NaT collection register).
  246. // When BSPSTORE[8:3] bits are all one, RSE stores RNAT to the backing store. Meaning
  247. // that every 63 register values stored to the backing store are followed by a stored
  248. // RNAT. Note RNAT[63] bit is always written as zero.
  249. //
  250. // This explains the following code:
  251. //
  252. //
  253. // Check for spilled NaT collection register mixed w/ arguments.
  254. //
  255. rsBSP = pContext->RsBSP;
  256. index = (ULONG)(rsBSP & 0x1F8) >> 3;
  257. if (index > 59) {
  258. DWORD i, j;
  259. DWORD64 localParams[5];
  260. //
  261. // Read in memory, 4 arguments + 1 NaT collection register.
  262. //
  263. result = ReadMemory ( hProcess, rsBSP, localParams, sizeof(localParams), &cb );
  264. if (result) {
  265. j = 0;
  266. for (i = 0; i < DIMA(localParams) ; i++, index++) {
  267. if (index != 63) {
  268. Params[j++] = localParams[i];
  269. }
  270. }
  271. }
  272. } else {
  273. //
  274. // We do not have the NaT collection register mixed w/ function arguments.
  275. // Read the 4 arguments from backing store memory.
  276. //
  277. result = ReadMemory ( hProcess, rsBSP, Params, 4 * sizeof(Params[0]), &cb );
  278. }
  279. return( result );
  280. } // ReadFunctionArgumentsFromContext()
  281. #define WALKI64_SAVE_IFS(sf) ((sf).Reserved[0])
  282. #define WALKI64_CONTEXT_INDEX(sf) ((sf).Reserved[2])
  283. BOOL
  284. WalkIa64Init(
  285. HANDLE hProcess,
  286. LPSTACKFRAME64 StackFrame,
  287. PIA64_CONTEXT Context,
  288. PREAD_PROCESS_MEMORY_ROUTINE64 ReadMemory,
  289. PFUNCTION_TABLE_ACCESS_ROUTINE64 FunctionTableAccess,
  290. PGET_MODULE_BASE_ROUTINE64 GetModuleBase
  291. )
  292. {
  293. IA64_KSWITCH_FRAME SwitchFrame;
  294. IA64_CONTEXT ContextSave;
  295. DWORD64 PcOffset;
  296. DWORD64 StackOffset;
  297. DWORD64 FrameOffset;
  298. DWORD cb;
  299. BOOL result;
  300. UINT iContext = (UINT)
  301. (WALKI64_CONTEXT_INDEX(*StackFrame) = Vwndia64NewContext());
  302. ZeroMemory( StackFrame, FIELD_OFFSET( STACKFRAME64, KdHelp ) );
  303. // TF-XXXXXX: ZeroMemory( StackFrame, sizeof(*StackFrame) );
  304. StackFrame->Virtual = TRUE;
  305. if (!StackFrame->AddrPC.Offset)
  306. {
  307. StackFrame->AddrPC.Offset = Ia64InsertIPSlotNumber(
  308. (Context->StIIP & ~(ULONGLONG)0xf),
  309. ((Context->StIPSR >> PSR_RI) & 0x3));
  310. StackFrame->AddrPC.Mode = AddrModeFlat;
  311. }
  312. if (!StackFrame->AddrStack.Offset)
  313. {
  314. StackFrame->AddrStack.Offset = Context->IntSp;
  315. StackFrame->AddrStack.Mode = AddrModeFlat;
  316. }
  317. if (!StackFrame->AddrFrame.Offset)
  318. {
  319. if (StackFrame->AddrBStore.Offset)
  320. {
  321. StackFrame->AddrFrame = StackFrame->AddrBStore;
  322. }
  323. else
  324. {
  325. StackFrame->AddrFrame.Offset = Context->RsBSP;
  326. StackFrame->AddrFrame.Mode = AddrModeFlat;
  327. }
  328. }
  329. StackFrame->AddrBStore = StackFrame->AddrFrame;
  330. if ((StackFrame->AddrPC.Mode != AddrModeFlat) ||
  331. (StackFrame->AddrStack.Mode != AddrModeFlat) ||
  332. (StackFrame->AddrFrame.Mode != AddrModeFlat) ||
  333. (StackFrame->AddrBStore.Mode != AddrModeFlat))
  334. {
  335. return FALSE;
  336. }
  337. WALKI64_SAVE_IFS(*StackFrame) = Context->StIFS;
  338. WALKI64_CONTEXT_INDEX(*StackFrame) = iContext;
  339. ContextSave = *Context;
  340. PcOffset = StackFrame->AddrPC.Offset;
  341. StackOffset = StackFrame->AddrStack.Offset;
  342. FrameOffset = StackFrame->AddrFrame.Offset;
  343. if (!GetStackFrameIa64( hProcess,
  344. &PcOffset,
  345. &StackOffset,
  346. &FrameOffset,
  347. &ContextSave,
  348. ReadMemory,
  349. FunctionTableAccess,
  350. GetModuleBase,
  351. iContext) )
  352. {
  353. StackFrame->AddrReturn.Offset = Context->BrRp;
  354. } else {
  355. StackFrame->AddrReturn.Offset = PcOffset;
  356. }
  357. StackFrame->AddrReturn.Mode = AddrModeFlat;
  358. result = ReadFunctionArgumentsFromContext( ReadMemory,
  359. hProcess,
  360. Context,
  361. StackFrame->Params
  362. );
  363. if ( !result ) {
  364. StackFrame->Params[0] =
  365. StackFrame->Params[1] =
  366. StackFrame->Params[2] =
  367. StackFrame->Params[3] = 0;
  368. }
  369. return TRUE;
  370. }
  371. BOOL
  372. WalkIa64Next(
  373. HANDLE hProcess,
  374. LPSTACKFRAME64 StackFrame,
  375. PIA64_CONTEXT Context,
  376. PREAD_PROCESS_MEMORY_ROUTINE64 ReadMemory,
  377. PFUNCTION_TABLE_ACCESS_ROUTINE64 FunctionTableAccess,
  378. PGET_MODULE_BASE_ROUTINE64 GetModuleBase
  379. )
  380. {
  381. DWORD cb;
  382. IA64_CONTEXT ContextSave;
  383. BOOL rval = TRUE;
  384. BOOL result;
  385. DWORD64 StackAddress;
  386. DWORD64 BStoreAddress;
  387. PIMAGE_IA64_RUNTIME_FUNCTION_ENTRY rf;
  388. DWORD64 fp = (DWORD64)0;
  389. DWORD64 bsp = (DWORD64)0;
  390. UINT iContext = (UINT)WALKI64_CONTEXT_INDEX(*StackFrame);
  391. if (!Vwndia64ValidateContext(&iContext))
  392. {
  393. WALKI64_CONTEXT_INDEX(*StackFrame) = iContext;
  394. }
  395. if (!GetStackFrameIa64( hProcess,
  396. &StackFrame->AddrPC.Offset,
  397. &StackFrame->AddrStack.Offset,
  398. &StackFrame->AddrFrame.Offset,
  399. Context,
  400. ReadMemory,
  401. FunctionTableAccess,
  402. GetModuleBase,
  403. iContext) )
  404. {
  405. rval = FALSE;
  406. //
  407. // If the frame could not be unwound or is terminal, see if
  408. // there is a callback frame:
  409. //
  410. if (g.AppVersion.Revision >= 4 && CALLBACK_STACK(StackFrame)) {
  411. DWORD64 imageBase;
  412. if (CALLBACK_STACK(StackFrame) & 0x80000000) {
  413. //
  414. // it is the pointer to the stack frame that we want
  415. //
  416. StackAddress = CALLBACK_STACK(StackFrame);
  417. } else {
  418. //
  419. // if it is a positive integer, it is the offset to
  420. // the address in the thread.
  421. // Look up the pointer:
  422. //
  423. rval = ReadMemory(hProcess,
  424. (CALLBACK_THREAD(StackFrame) +
  425. CALLBACK_STACK(StackFrame)),
  426. &StackAddress,
  427. sizeof(DWORD64),
  428. &cb);
  429. if (!rval || StackAddress == 0) {
  430. StackAddress = (DWORD64)-1;
  431. CALLBACK_STACK(StackFrame) = (DWORD)-1;
  432. }
  433. }
  434. if ( (StackAddress == (DWORD64)-1) ||
  435. ( !(rf = (PIMAGE_IA64_RUNTIME_FUNCTION_ENTRY)
  436. FunctionTableAccess(hProcess, CALLBACK_FUNC(StackFrame))) || !( imageBase = GetModuleBase(hProcess, CALLBACK_FUNC(StackFrame)) ) ) ) {
  437. rval = FALSE;
  438. } else {
  439. ReadMemory(hProcess,
  440. (StackAddress + CALLBACK_NEXT(StackFrame)),
  441. &CALLBACK_STACK(StackFrame),
  442. sizeof(DWORD64),
  443. &cb);
  444. StackFrame->AddrPC.Offset = imageBase + rf->BeginAddress;
  445. StackFrame->AddrStack.Offset = StackAddress;
  446. Context->IntSp = StackAddress;
  447. WALKI64_SAVE_IFS(*StackFrame) = 0;
  448. rval = TRUE;
  449. }
  450. }
  451. } else {
  452. WALKI64_SAVE_IFS(*StackFrame) = Context->StIFS;
  453. }
  454. StackFrame->AddrBStore = StackFrame->AddrFrame;
  455. //
  456. // get the return address
  457. //
  458. ContextSave = *Context;
  459. StackFrame->AddrReturn.Offset = StackFrame->AddrPC.Offset;
  460. if (!GetStackFrameIa64( hProcess,
  461. &StackFrame->AddrReturn.Offset,
  462. &fp,
  463. &bsp,
  464. &ContextSave,
  465. ReadMemory,
  466. FunctionTableAccess,
  467. GetModuleBase, iContext) )
  468. {
  469. // rval = FALSE;
  470. StackFrame->AddrReturn.Offset = 0;
  471. }
  472. result = ReadFunctionArgumentsFromContext( ReadMemory,
  473. hProcess,
  474. Context,
  475. StackFrame->Params
  476. );
  477. if ( !result ) {
  478. StackFrame->Params[0] =
  479. StackFrame->Params[1] =
  480. StackFrame->Params[2] =
  481. StackFrame->Params[3] = 0;
  482. }
  483. return rval;
  484. }