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.

582 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 < SIZEOF_ARRAY(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_CONTEXT_INDEX(sf) ((sf).Reserved[2])
  282. BOOL
  283. WalkIa64Init(
  284. HANDLE hProcess,
  285. LPSTACKFRAME64 StackFrame,
  286. PIA64_CONTEXT Context,
  287. PREAD_PROCESS_MEMORY_ROUTINE64 ReadMemory,
  288. PFUNCTION_TABLE_ACCESS_ROUTINE64 FunctionTableAccess,
  289. PGET_MODULE_BASE_ROUTINE64 GetModuleBase
  290. )
  291. {
  292. IA64_KSWITCH_FRAME SwitchFrame;
  293. IA64_CONTEXT ContextSave;
  294. DWORD64 PcOffset;
  295. DWORD64 StackOffset;
  296. DWORD64 FrameOffset;
  297. DWORD cb;
  298. BOOL result;
  299. UINT iContext = (UINT)
  300. (WALKI64_CONTEXT_INDEX(*StackFrame) = Vwndia64NewContext());
  301. ZeroMemory( StackFrame, FIELD_OFFSET( STACKFRAME64, KdHelp ) );
  302. // TF-XXXXXX: ZeroMemory( StackFrame, sizeof(*StackFrame) );
  303. StackFrame->Virtual = TRUE;
  304. if (!StackFrame->AddrPC.Offset)
  305. {
  306. StackFrame->AddrPC.Offset = Ia64InsertIPSlotNumber(
  307. (Context->StIIP & ~(ULONGLONG)0xf),
  308. ((Context->StIPSR >> PSR_RI) & 0x3));
  309. StackFrame->AddrPC.Mode = AddrModeFlat;
  310. }
  311. if (!StackFrame->AddrStack.Offset)
  312. {
  313. StackFrame->AddrStack.Offset = Context->IntSp;
  314. StackFrame->AddrStack.Mode = AddrModeFlat;
  315. }
  316. if (!StackFrame->AddrFrame.Offset)
  317. {
  318. if (StackFrame->AddrBStore.Offset)
  319. {
  320. StackFrame->AddrFrame = StackFrame->AddrBStore;
  321. }
  322. else
  323. {
  324. StackFrame->AddrFrame.Offset = Context->RsBSP;
  325. StackFrame->AddrFrame.Mode = AddrModeFlat;
  326. }
  327. }
  328. StackFrame->AddrBStore = StackFrame->AddrFrame;
  329. if ((StackFrame->AddrPC.Mode != AddrModeFlat) ||
  330. (StackFrame->AddrStack.Mode != AddrModeFlat) ||
  331. (StackFrame->AddrFrame.Mode != AddrModeFlat) ||
  332. (StackFrame->AddrBStore.Mode != AddrModeFlat))
  333. {
  334. return FALSE;
  335. }
  336. WALKI64_CONTEXT_INDEX(*StackFrame) = iContext;
  337. ContextSave = *Context;
  338. PcOffset = StackFrame->AddrPC.Offset;
  339. StackOffset = StackFrame->AddrStack.Offset;
  340. FrameOffset = StackFrame->AddrFrame.Offset;
  341. if (!GetStackFrameIa64( hProcess,
  342. &PcOffset,
  343. &StackOffset,
  344. &FrameOffset,
  345. &ContextSave,
  346. ReadMemory,
  347. FunctionTableAccess,
  348. GetModuleBase,
  349. iContext) )
  350. {
  351. StackFrame->AddrReturn.Offset = Context->BrRp;
  352. } else {
  353. StackFrame->AddrReturn.Offset = PcOffset;
  354. }
  355. StackFrame->AddrReturn.Mode = AddrModeFlat;
  356. result = ReadFunctionArgumentsFromContext( ReadMemory,
  357. hProcess,
  358. Context,
  359. StackFrame->Params
  360. );
  361. if ( !result ) {
  362. StackFrame->Params[0] =
  363. StackFrame->Params[1] =
  364. StackFrame->Params[2] =
  365. StackFrame->Params[3] = 0;
  366. }
  367. return TRUE;
  368. }
  369. BOOL
  370. WalkIa64Next(
  371. HANDLE hProcess,
  372. LPSTACKFRAME64 StackFrame,
  373. PIA64_CONTEXT Context,
  374. PREAD_PROCESS_MEMORY_ROUTINE64 ReadMemory,
  375. PFUNCTION_TABLE_ACCESS_ROUTINE64 FunctionTableAccess,
  376. PGET_MODULE_BASE_ROUTINE64 GetModuleBase
  377. )
  378. {
  379. DWORD cb;
  380. IA64_CONTEXT ContextSave;
  381. BOOL rval = TRUE;
  382. BOOL result;
  383. DWORD64 StackAddress;
  384. DWORD64 BStoreAddress;
  385. PIMAGE_IA64_RUNTIME_FUNCTION_ENTRY rf;
  386. DWORD64 fp = (DWORD64)0;
  387. DWORD64 bsp = (DWORD64)0;
  388. UINT iContext = (UINT)WALKI64_CONTEXT_INDEX(*StackFrame);
  389. if (!Vwndia64ValidateContext(&iContext))
  390. {
  391. WALKI64_CONTEXT_INDEX(*StackFrame) = iContext;
  392. }
  393. if (!GetStackFrameIa64( hProcess,
  394. &StackFrame->AddrPC.Offset,
  395. &StackFrame->AddrStack.Offset,
  396. &StackFrame->AddrFrame.Offset,
  397. Context,
  398. ReadMemory,
  399. FunctionTableAccess,
  400. GetModuleBase,
  401. iContext) )
  402. {
  403. rval = FALSE;
  404. //
  405. // If the frame could not be unwound or is terminal, see if
  406. // there is a callback frame:
  407. //
  408. if (g.AppVersion.Revision >= 4 && CALLBACK_STACK(StackFrame)) {
  409. DWORD64 imageBase;
  410. if (CALLBACK_STACK(StackFrame) & 0x80000000) {
  411. //
  412. // it is the pointer to the stack frame that we want
  413. //
  414. StackAddress = CALLBACK_STACK(StackFrame);
  415. } else {
  416. //
  417. // if it is a positive integer, it is the offset to
  418. // the address in the thread.
  419. // Look up the pointer:
  420. //
  421. rval = ReadMemory(hProcess,
  422. (CALLBACK_THREAD(StackFrame) +
  423. CALLBACK_STACK(StackFrame)),
  424. &StackAddress,
  425. sizeof(DWORD64),
  426. &cb);
  427. if (!rval || StackAddress == 0) {
  428. StackAddress = (DWORD64)-1;
  429. CALLBACK_STACK(StackFrame) = (DWORD)-1;
  430. }
  431. }
  432. if ( (StackAddress == (DWORD64)-1) ||
  433. ( !(rf = (PIMAGE_IA64_RUNTIME_FUNCTION_ENTRY)
  434. FunctionTableAccess(hProcess, CALLBACK_FUNC(StackFrame))) || !( imageBase = GetModuleBase(hProcess, CALLBACK_FUNC(StackFrame)) ) ) ) {
  435. rval = FALSE;
  436. } else {
  437. ReadMemory(hProcess,
  438. (StackAddress + CALLBACK_NEXT(StackFrame)),
  439. &CALLBACK_STACK(StackFrame),
  440. sizeof(DWORD64),
  441. &cb);
  442. StackFrame->AddrPC.Offset = imageBase + rf->BeginAddress;
  443. StackFrame->AddrStack.Offset = StackAddress;
  444. Context->IntSp = StackAddress;
  445. rval = TRUE;
  446. }
  447. }
  448. }
  449. StackFrame->AddrBStore = StackFrame->AddrFrame;
  450. //
  451. // get the return address
  452. //
  453. ContextSave = *Context;
  454. StackFrame->AddrReturn.Offset = StackFrame->AddrPC.Offset;
  455. if (!GetStackFrameIa64( hProcess,
  456. &StackFrame->AddrReturn.Offset,
  457. &fp,
  458. &bsp,
  459. &ContextSave,
  460. ReadMemory,
  461. FunctionTableAccess,
  462. GetModuleBase, iContext) )
  463. {
  464. // rval = FALSE;
  465. StackFrame->AddrReturn.Offset = 0;
  466. }
  467. result = ReadFunctionArgumentsFromContext( ReadMemory,
  468. hProcess,
  469. Context,
  470. StackFrame->Params
  471. );
  472. if ( !result ) {
  473. StackFrame->Params[0] =
  474. StackFrame->Params[1] =
  475. StackFrame->Params[2] =
  476. StackFrame->Params[3] = 0;
  477. }
  478. return rval;
  479. }