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.

3003 lines
92 KiB

  1. /*++
  2. Copyright (c) 1993-2002 Microsoft Corporation
  3. Module Name:
  4. walkx86.c
  5. Abstract:
  6. This file implements the Intel x86 stack walking api. This api allows for
  7. the presence of "real mode" stack frames. This means that you can trace
  8. into WOW code.
  9. Author:
  10. Wesley Witt (wesw) 1-Oct-1993
  11. Environment:
  12. User Mode
  13. --*/
  14. #define _IMAGEHLP_SOURCE_
  15. #include <nt.h>
  16. #include <ntrtl.h>
  17. #include <nturtl.h>
  18. #include "private.h"
  19. #define NOEXTAPI
  20. #include "wdbgexts.h"
  21. #include "ntdbg.h"
  22. #include <objbase.h>
  23. #include <wx86dll.h>
  24. #include <symbols.h>
  25. #include <globals.h>
  26. #include "dia2.h"
  27. #define WDB(Args) SdbOut Args
  28. #define SAVE_EBP(f) (f->Reserved[0])
  29. #define IS_EBP_SAVED(f) (f->Reserved[0] && ((f->Reserved[0] >> 32) != 0xEB))
  30. #define TRAP_TSS(f) (f->Reserved[1])
  31. #define TRAP_EDITED(f) (f->Reserved[1])
  32. #define SAVE_TRAP(f) (f->Reserved[2])
  33. #define CALLBACK_STACK(f) (f->KdHelp.ThCallbackStack)
  34. #define CALLBACK_NEXT(f) (f->KdHelp.NextCallback)
  35. #define CALLBACK_FUNC(f) (f->KdHelp.KiCallUserMode)
  36. #define CALLBACK_THREAD(f) (f->KdHelp.Thread)
  37. #define CALLBACK_FP(f) (f->KdHelp.FramePointer)
  38. #define CALLBACK_DISPATCHER(f) (f->KdHelp.KeUserCallbackDispatcher)
  39. #define SYSTEM_RANGE_START(f) (f->KdHelp.SystemRangeStart)
  40. #define STACK_SIZE (sizeof(DWORD))
  41. #define FRAME_SIZE (STACK_SIZE * 2)
  42. #define STACK_SIZE16 (sizeof(WORD))
  43. #define FRAME_SIZE16 (STACK_SIZE16 * 2)
  44. #define FRAME_SIZE1632 (STACK_SIZE16 * 3)
  45. #define MAX_STACK_SEARCH 64 // in STACK_SIZE units
  46. #define MAX_JMP_CHAIN 64 // in STACK_SIZE units
  47. #define MAX_CALL 7 // in bytes
  48. #define MIN_CALL 2 // in bytes
  49. #define MAX_FUNC_PROLOGUE 64 // in bytes
  50. #define PUSHBP 0x55
  51. #define MOVBPSP 0xEC8B
  52. ULONG g_vc7fpo = 1;
  53. #define DoMemoryRead(addr,buf,sz,br) \
  54. ReadMemoryInternal( Process, Thread, addr, buf, sz, \
  55. br, ReadMemory, TranslateAddress, FALSE )
  56. #define DoMemoryReadAll(addr,buf,sz) \
  57. ReadMemoryInternal( Process, Thread, addr, buf, sz, \
  58. NULL, ReadMemory, TranslateAddress, TRUE )
  59. BOOL
  60. WalkX86Init(
  61. HANDLE Process,
  62. HANDLE Thread,
  63. LPSTACKFRAME64 StackFrame,
  64. PX86_CONTEXT ContextRecord,
  65. PREAD_PROCESS_MEMORY_ROUTINE64 ReadMemory,
  66. PFUNCTION_TABLE_ACCESS_ROUTINE64 FunctionTableAccess,
  67. PGET_MODULE_BASE_ROUTINE64 GetModuleBase,
  68. PTRANSLATE_ADDRESS_ROUTINE64 TranslateAddress
  69. );
  70. BOOL
  71. WalkX86Next(
  72. HANDLE Process,
  73. HANDLE Thread,
  74. LPSTACKFRAME64 StackFrame,
  75. PX86_CONTEXT ContextRecord,
  76. PREAD_PROCESS_MEMORY_ROUTINE64 ReadMemory,
  77. PFUNCTION_TABLE_ACCESS_ROUTINE64 FunctionTableAccess,
  78. PGET_MODULE_BASE_ROUTINE64 GetModuleBase,
  79. PTRANSLATE_ADDRESS_ROUTINE64 TranslateAddress
  80. );
  81. BOOL
  82. ReadMemoryInternal(
  83. HANDLE Process,
  84. HANDLE Thread,
  85. LPADDRESS64 lpBaseAddress,
  86. LPVOID lpBuffer,
  87. DWORD nSize,
  88. LPDWORD lpNumberOfBytesRead,
  89. PREAD_PROCESS_MEMORY_ROUTINE64 ReadMemory,
  90. PTRANSLATE_ADDRESS_ROUTINE64 TranslateAddress,
  91. BOOL MustReadAll
  92. );
  93. BOOL
  94. IsFarCall(
  95. HANDLE Process,
  96. HANDLE Thread,
  97. LPSTACKFRAME64 StackFrame,
  98. BOOL *Ok,
  99. PREAD_PROCESS_MEMORY_ROUTINE64 ReadMemory,
  100. PTRANSLATE_ADDRESS_ROUTINE64 TranslateAddress
  101. );
  102. BOOL
  103. ReadTrapFrame(
  104. HANDLE Process,
  105. DWORD64 TrapFrameAddress,
  106. PX86_KTRAP_FRAME TrapFrame,
  107. PREAD_PROCESS_MEMORY_ROUTINE64 ReadMemory
  108. );
  109. BOOL
  110. TaskGate2TrapFrame(
  111. HANDLE Process,
  112. USHORT TaskRegister,
  113. PX86_KTRAP_FRAME TrapFrame,
  114. PULONG64 off,
  115. PREAD_PROCESS_MEMORY_ROUTINE64 ReadMemory
  116. );
  117. DWORD64
  118. SearchForReturnAddress(
  119. HANDLE Process,
  120. DWORD64 uoffStack,
  121. DWORD64 funcAddr,
  122. DWORD funcSize,
  123. PREAD_PROCESS_MEMORY_ROUTINE64 ReadMemory,
  124. PGET_MODULE_BASE_ROUTINE64 GetModuleBase,
  125. BOOL AcceptUnreadableCallSite
  126. );
  127. //----------------------------------------------------------------------------
  128. //
  129. // DIA IDiaStackWalkFrame implementation.
  130. //
  131. //----------------------------------------------------------------------------
  132. class X86WalkFrame : public IDiaStackWalkFrame
  133. {
  134. public:
  135. X86WalkFrame(HANDLE Process,
  136. X86_CONTEXT* Context,
  137. PREAD_PROCESS_MEMORY_ROUTINE64 ReadMemory,
  138. PGET_MODULE_BASE_ROUTINE64 GetModuleBase,
  139. PFPO_DATA PreviousFpo)
  140. {
  141. m_Process = Process;
  142. m_Context = Context;
  143. m_ReadMemory = ReadMemory;
  144. m_GetModuleBase = GetModuleBase;
  145. m_Locals = 0;
  146. m_Params = 0;
  147. m_VirtFrame = Context->Ebp;
  148. m_PreviousFpo = PreviousFpo;
  149. m_EbpSet = FALSE;
  150. }
  151. // IUnknown.
  152. STDMETHOD(QueryInterface)(
  153. THIS_
  154. IN REFIID InterfaceId,
  155. OUT PVOID* Interface
  156. );
  157. STDMETHOD_(ULONG, AddRef)(
  158. THIS
  159. );
  160. STDMETHOD_(ULONG, Release)(
  161. THIS
  162. );
  163. // IDiaStackWalkFrame.
  164. STDMETHOD(get_registerValue)(DWORD reg, ULONGLONG* pValue);
  165. STDMETHOD(put_registerValue)(DWORD reg, ULONGLONG value);
  166. STDMETHOD(readMemory)(ULONGLONG va, DWORD cbData,
  167. DWORD* pcbData, BYTE* data);
  168. STDMETHOD(searchForReturnAddress)(IDiaFrameData* frame,
  169. ULONGLONG* pResult);
  170. STDMETHOD(searchForReturnAddressStart)(IDiaFrameData* frame,
  171. ULONGLONG startAddress,
  172. ULONGLONG* pResult);
  173. BOOL WasEbpSet(void)
  174. {
  175. return m_EbpSet;
  176. }
  177. private:
  178. HANDLE m_Process;
  179. X86_CONTEXT* m_Context;
  180. PREAD_PROCESS_MEMORY_ROUTINE64 m_ReadMemory;
  181. PGET_MODULE_BASE_ROUTINE64 m_GetModuleBase;
  182. ULONGLONG m_Locals;
  183. ULONGLONG m_Params;
  184. ULONGLONG m_VirtFrame;
  185. PFPO_DATA m_PreviousFpo;
  186. BOOL m_EbpSet;
  187. };
  188. STDMETHODIMP
  189. X86WalkFrame::QueryInterface(
  190. THIS_
  191. IN REFIID InterfaceId,
  192. OUT PVOID* Interface
  193. )
  194. {
  195. HRESULT Status;
  196. *Interface = NULL;
  197. Status = E_NOINTERFACE;
  198. if (IsEqualIID(InterfaceId, IID_IDiaStackWalkFrame)) {
  199. *Interface = (IDiaStackWalkFrame*)this;
  200. Status = S_OK;
  201. }
  202. return Status;
  203. }
  204. STDMETHODIMP_(ULONG)
  205. X86WalkFrame::AddRef(
  206. THIS
  207. )
  208. {
  209. // Stack allocated, no refcount.
  210. return 1;
  211. }
  212. STDMETHODIMP_(ULONG)
  213. X86WalkFrame::Release(
  214. THIS
  215. )
  216. {
  217. // Stack allocated, no refcount.
  218. return 0;
  219. }
  220. STDMETHODIMP
  221. X86WalkFrame::get_registerValue( DWORD reg, ULONGLONG* pVal )
  222. {
  223. switch( reg ) {
  224. // debug registers
  225. case CV_REG_DR0:
  226. *pVal = m_Context->Dr0;
  227. break;
  228. case CV_REG_DR1:
  229. *pVal = m_Context->Dr1;
  230. break;
  231. case CV_REG_DR2:
  232. *pVal = m_Context->Dr2;
  233. break;
  234. case CV_REG_DR3:
  235. *pVal = m_Context->Dr3;
  236. break;
  237. case CV_REG_DR6:
  238. *pVal = m_Context->Dr6;
  239. break;
  240. case CV_REG_DR7:
  241. *pVal = m_Context->Dr7;
  242. break;
  243. // segment registers
  244. case CV_REG_GS:
  245. *pVal = m_Context->SegGs;
  246. break;
  247. case CV_REG_FS:
  248. *pVal = m_Context->SegFs;
  249. break;
  250. case CV_REG_ES:
  251. *pVal = m_Context->SegEs;
  252. break;
  253. case CV_REG_DS:
  254. *pVal = m_Context->SegDs;
  255. break;
  256. // integer registers
  257. case CV_REG_EDI:
  258. *pVal = m_Context->Edi;
  259. break;
  260. case CV_REG_ESI:
  261. *pVal = m_Context->Esi;
  262. break;
  263. case CV_REG_EBX:
  264. *pVal = m_Context->Ebx;
  265. break;
  266. case CV_REG_EDX:
  267. *pVal = m_Context->Edx;
  268. break;
  269. case CV_REG_ECX:
  270. *pVal = m_Context->Ecx;
  271. break;
  272. case CV_REG_EAX:
  273. *pVal = m_Context->Eax;
  274. break;
  275. // control registers
  276. case CV_REG_EBP:
  277. *pVal = m_Context->Ebp;
  278. break;
  279. case CV_REG_EIP:
  280. *pVal = m_Context->Eip;
  281. break;
  282. case CV_REG_CS:
  283. *pVal = m_Context->SegCs;
  284. break;
  285. case CV_REG_EFLAGS:
  286. *pVal = m_Context->EFlags;
  287. break;
  288. case CV_REG_ESP:
  289. *pVal = m_Context->Esp;
  290. break;
  291. case CV_REG_SS:
  292. *pVal = m_Context->SegSs;
  293. break;
  294. case CV_ALLREG_LOCALS:
  295. *pVal = m_Locals;
  296. break;
  297. case CV_ALLREG_PARAMS:
  298. *pVal = m_Params;
  299. break;
  300. case CV_ALLREG_VFRAME:
  301. *pVal = m_VirtFrame;
  302. break;
  303. default:
  304. *pVal = 0;
  305. return E_FAIL;
  306. }
  307. return S_OK;
  308. }
  309. STDMETHODIMP
  310. X86WalkFrame::put_registerValue( DWORD reg, ULONGLONG LongVal )
  311. {
  312. ULONG val = (ULONG)LongVal;
  313. switch( reg ) {
  314. // debug registers
  315. case CV_REG_DR0:
  316. m_Context->Dr0 = val;
  317. break;
  318. case CV_REG_DR1:
  319. m_Context->Dr1 = val;
  320. break;
  321. case CV_REG_DR2:
  322. m_Context->Dr2 = val;
  323. break;
  324. case CV_REG_DR3:
  325. m_Context->Dr3 = val;
  326. break;
  327. case CV_REG_DR6:
  328. m_Context->Dr6 = val;
  329. break;
  330. case CV_REG_DR7:
  331. m_Context->Dr7 = val;
  332. break;
  333. // segment registers
  334. case CV_REG_GS:
  335. m_Context->SegGs = val;
  336. break;
  337. case CV_REG_FS:
  338. m_Context->SegFs = val;
  339. break;
  340. case CV_REG_ES:
  341. m_Context->SegEs = val;
  342. break;
  343. case CV_REG_DS:
  344. m_Context->SegDs = val;
  345. break;
  346. // integer registers
  347. case CV_REG_EDI:
  348. m_Context->Edi = val;
  349. break;
  350. case CV_REG_ESI:
  351. m_Context->Esi = val;
  352. break;
  353. case CV_REG_EBX:
  354. m_Context->Ebx = val;
  355. break;
  356. case CV_REG_EDX:
  357. m_Context->Edx = val;
  358. break;
  359. case CV_REG_ECX:
  360. m_Context->Ecx = val;
  361. break;
  362. case CV_REG_EAX:
  363. m_Context->Eax = val;
  364. break;
  365. // control registers
  366. case CV_REG_EBP:
  367. m_Context->Ebp = val;
  368. m_EbpSet = TRUE;
  369. break;
  370. case CV_REG_EIP:
  371. m_Context->Eip = val;
  372. break;
  373. case CV_REG_CS:
  374. m_Context->SegCs = val;
  375. break;
  376. case CV_REG_EFLAGS:
  377. m_Context->EFlags = val;
  378. break;
  379. case CV_REG_ESP:
  380. m_Context->Esp = val;
  381. break;
  382. case CV_REG_SS:
  383. m_Context->SegSs = val;
  384. break;
  385. case CV_ALLREG_LOCALS:
  386. m_Locals = val;
  387. break;
  388. case CV_ALLREG_PARAMS:
  389. m_Params = val;
  390. break;
  391. case CV_ALLREG_VFRAME:
  392. m_VirtFrame = val;
  393. break;
  394. default:
  395. return E_FAIL;
  396. }
  397. return S_OK;
  398. }
  399. STDMETHODIMP
  400. X86WalkFrame::readMemory(ULONGLONG va, DWORD cbData,
  401. DWORD* pcbData, BYTE* data)
  402. {
  403. return m_ReadMemory( m_Process, va, data, cbData, pcbData ) != 0 ?
  404. S_OK : E_FAIL;
  405. }
  406. STDMETHODIMP
  407. X86WalkFrame::searchForReturnAddress(IDiaFrameData* frame,
  408. ULONGLONG* pResult)
  409. {
  410. HRESULT Status;
  411. DWORD LenLocals, LenRegs;
  412. if ((Status = frame->get_lengthLocals(&LenLocals)) != S_OK ||
  413. (Status = frame->get_lengthSavedRegisters(&LenRegs)) != S_OK) {
  414. return Status;
  415. }
  416. return searchForReturnAddressStart(frame,
  417. EXTEND64(m_Context->Esp +
  418. LenLocals + LenRegs),
  419. pResult);
  420. }
  421. STDMETHODIMP
  422. X86WalkFrame::searchForReturnAddressStart(IDiaFrameData* DiaFrame,
  423. ULONGLONG StartAddress,
  424. ULONGLONG* Result)
  425. {
  426. HRESULT Status;
  427. BOOL HasSeh, IsFuncStart;
  428. IDiaFrameData* OrigFrame = DiaFrame;
  429. IDiaFrameData* NextFrame;
  430. DWORD LenLocals, LenRegs, LenParams = 0;
  431. if (m_PreviousFpo &&
  432. m_PreviousFpo->cbFrame != FRAME_TRAP &&
  433. m_PreviousFpo->cbFrame != FRAME_TSS) {
  434. //
  435. // if the previous frame had an fpo record, we can account
  436. // for its parameters
  437. //
  438. LenParams = m_PreviousFpo->cdwParams * STACK_SIZE;
  439. }
  440. if ((Status = DiaFrame->get_lengthLocals(&LenLocals)) != S_OK ||
  441. (Status = DiaFrame->get_lengthSavedRegisters(&LenRegs)) != S_OK ||
  442. (Status = DiaFrame->get_systemExceptionHandling(&HasSeh)) != S_OK ||
  443. (Status = DiaFrame->get_functionStart(&IsFuncStart)) != S_OK) {
  444. return Status;
  445. }
  446. if ((!HasSeh || IsFuncStart) &&
  447. m_Context->Esp + LenLocals + LenRegs + LenParams >
  448. (ULONG) StartAddress) {
  449. StartAddress =
  450. EXTEND64(m_Context->Esp + LenLocals + LenRegs + LenParams);
  451. }
  452. //
  453. // This frame data may be a subsidiary descriptor. Move up
  454. // the parent chain to the true function start.
  455. //
  456. while (DiaFrame->get_functionParent(&NextFrame) == S_OK) {
  457. if (DiaFrame != OrigFrame) {
  458. DiaFrame->Release();
  459. }
  460. DiaFrame = NextFrame;
  461. }
  462. ULONGLONG FuncStart;
  463. DWORD LenFunc;
  464. if ((Status = DiaFrame->get_virtualAddress(&FuncStart)) == S_OK) {
  465. Status = DiaFrame->get_lengthBlock(&LenFunc);
  466. }
  467. if (DiaFrame != OrigFrame) {
  468. DiaFrame->Release();
  469. }
  470. if (Status != S_OK) {
  471. return Status;
  472. }
  473. *Result = SearchForReturnAddress(m_Process,
  474. StartAddress,
  475. FuncStart,
  476. LenFunc,
  477. m_ReadMemory,
  478. m_GetModuleBase,
  479. TRUE);
  480. return *Result != 0 ? S_OK : E_FAIL;
  481. }
  482. //----------------------------------------------------------------------------
  483. //
  484. // Walk functions.
  485. //
  486. //----------------------------------------------------------------------------
  487. BOOL
  488. WalkX86(
  489. HANDLE Process,
  490. HANDLE Thread,
  491. LPSTACKFRAME64 StackFrame,
  492. PVOID ContextRecord,
  493. PREAD_PROCESS_MEMORY_ROUTINE64 ReadMemory,
  494. PFUNCTION_TABLE_ACCESS_ROUTINE64 FunctionTableAccess,
  495. PGET_MODULE_BASE_ROUTINE64 GetModuleBase,
  496. PTRANSLATE_ADDRESS_ROUTINE64 TranslateAddress,
  497. DWORD flags
  498. )
  499. {
  500. BOOL rval;
  501. WDB((2, "WalkX86 in: PC %X, SP %X, FP %X, RA %X\n",
  502. (ULONG)StackFrame->AddrPC.Offset,
  503. (ULONG)StackFrame->AddrStack.Offset,
  504. (ULONG)StackFrame->AddrFrame.Offset,
  505. (ULONG)StackFrame->AddrReturn.Offset));
  506. if (StackFrame->Virtual) {
  507. rval = WalkX86Next( Process,
  508. Thread,
  509. StackFrame,
  510. (PX86_CONTEXT)ContextRecord,
  511. ReadMemory,
  512. FunctionTableAccess,
  513. GetModuleBase,
  514. TranslateAddress
  515. );
  516. } else {
  517. rval = WalkX86Init( Process,
  518. Thread,
  519. StackFrame,
  520. (PX86_CONTEXT)ContextRecord,
  521. ReadMemory,
  522. FunctionTableAccess,
  523. GetModuleBase,
  524. TranslateAddress
  525. );
  526. }
  527. WDB((2, "WalkX86 out: PC %X, SP %X, FP %X, RA %X\n",
  528. (ULONG)StackFrame->AddrPC.Offset,
  529. (ULONG)StackFrame->AddrStack.Offset,
  530. (ULONG)StackFrame->AddrFrame.Offset,
  531. (ULONG)StackFrame->AddrReturn.Offset));
  532. // This hack fixes the fpo stack when ebp wasn't used.
  533. // Don't put this fix into StackWalk() or it will break MSDEV.
  534. #if 0
  535. if (rval && (flags & WALK_FIX_FPO_EBP)) {
  536. PFPO_DATA pFpo = (PFPO_DATA)StackFrame->FuncTableEntry;
  537. if (pFpo && !pFpo->fUseBP) {
  538. StackFrame->AddrFrame.Offset += 4;
  539. }
  540. }
  541. #endif
  542. return rval;
  543. }
  544. BOOL
  545. ReadMemoryInternal(
  546. HANDLE Process,
  547. HANDLE Thread,
  548. LPADDRESS64 lpBaseAddress,
  549. LPVOID lpBuffer,
  550. DWORD nSize,
  551. LPDWORD lpNumberOfBytesRead,
  552. PREAD_PROCESS_MEMORY_ROUTINE64 ReadMemory,
  553. PTRANSLATE_ADDRESS_ROUTINE64 TranslateAddress,
  554. BOOL MustReadAll
  555. )
  556. {
  557. ADDRESS64 addr;
  558. DWORD LocalBytesRead = 0;
  559. BOOL Succ;
  560. addr = *lpBaseAddress;
  561. if (addr.Mode != AddrModeFlat) {
  562. TranslateAddress( Process, Thread, &addr );
  563. }
  564. Succ = ReadMemory( Process,
  565. addr.Offset,
  566. lpBuffer,
  567. nSize,
  568. &LocalBytesRead
  569. );
  570. if (lpNumberOfBytesRead) {
  571. *lpNumberOfBytesRead = LocalBytesRead;
  572. }
  573. return (Succ && MustReadAll) ? (LocalBytesRead == nSize) : Succ;
  574. }
  575. DWORD64
  576. SearchForReturnAddress(
  577. HANDLE Process,
  578. DWORD64 uoffStack,
  579. DWORD64 funcAddr,
  580. DWORD funcSize,
  581. PREAD_PROCESS_MEMORY_ROUTINE64 ReadMemory,
  582. PGET_MODULE_BASE_ROUTINE64 GetModuleBase,
  583. BOOL AcceptUnreadableCallSite
  584. )
  585. {
  586. DWORD64 uoffRet;
  587. DWORD64 uoffBestGuess = 0;
  588. DWORD cdwIndex;
  589. DWORD cdwIndexMax;
  590. INT cbIndex;
  591. INT cbLimit;
  592. DWORD cBytes;
  593. DWORD cJmpChain = 0;
  594. DWORD64 uoffT;
  595. DWORD cb;
  596. BYTE jmpBuffer[ sizeof(WORD) + sizeof(DWORD) ];
  597. LPWORD lpwJmp = (LPWORD)&jmpBuffer[0];
  598. BYTE code[MAX_CALL];
  599. DWORD stack [ MAX_STACK_SEARCH ];
  600. BOPINSTR BopInstr;
  601. WDB((1, " SearchForReturnAddress: start %X\n", (ULONG)uoffStack));
  602. //
  603. // this function is necessary for 4 reasons:
  604. //
  605. // 1) random compiler bugs where regs are saved on the
  606. // stack but the fpo data does not account for them
  607. //
  608. // 2) inline asm code that does a push
  609. //
  610. // 3) any random code that does a push and it isn't
  611. // accounted for in the fpo data
  612. //
  613. // 4) non-void non-fpo functions
  614. // *** This case is not neccessary when the compiler
  615. // emits FPO records for non-FPO funtions. Unfortunately
  616. // only the NT group uses this feature.
  617. //
  618. if (!ReadMemory(Process,
  619. uoffStack,
  620. stack,
  621. sizeof(stack),
  622. &cb)) {
  623. WDB((1, " can't read stack\n"));
  624. return 0;
  625. }
  626. cdwIndexMax = cb / STACK_SIZE;
  627. if ( !cdwIndexMax ) {
  628. WDB((1, " can't read stack\n"));
  629. return 0;
  630. }
  631. for ( cdwIndex=0; cdwIndex<cdwIndexMax; cdwIndex++,uoffStack+=STACK_SIZE ) {
  632. uoffRet = (DWORD64)(LONG64)(LONG)stack[cdwIndex];
  633. //
  634. // Don't try looking for Code in the first 64K of an NT app.
  635. //
  636. if ( uoffRet < 0x00010000 ) {
  637. continue;
  638. }
  639. //
  640. // if it isn't part of any known address space it must be bogus
  641. //
  642. if (GetModuleBase( Process, uoffRet ) == 0) {
  643. continue;
  644. }
  645. //
  646. // Check for a BOP instruction.
  647. //
  648. if (ReadMemory(Process,
  649. uoffRet - sizeof(BOPINSTR),
  650. &BopInstr,
  651. sizeof(BOPINSTR),
  652. &cb)) {
  653. if (cb == sizeof(BOPINSTR) &&
  654. BopInstr.Instr1 == 0xc4 && BopInstr.Instr2 == 0xc4) {
  655. WDB((1, " BOP, use %X\n", (ULONG)uoffStack));
  656. return uoffStack;
  657. }
  658. }
  659. //
  660. // Read the maximum number of bytes a call could be from the istream
  661. //
  662. cBytes = MAX_CALL;
  663. if (!ReadMemory(Process,
  664. uoffRet - cBytes,
  665. code,
  666. cBytes,
  667. &cb)) {
  668. //
  669. // if page is not present, we will ALWAYS mess up by
  670. // continuing to search. If alloca was used also, we
  671. // are toast. Too Bad.
  672. //
  673. if (cdwIndex == 0 && AcceptUnreadableCallSite) {
  674. WDB((1, " unreadable call site, use %X\n",
  675. (ULONG)uoffStack));
  676. return uoffStack;
  677. } else {
  678. continue;
  679. }
  680. }
  681. //
  682. // With 32bit code that isn't FAR:32 we don't have to worry about
  683. // intersegment calls. Check here to see if we had a call within
  684. // segment. If it is we can later check it's full diplacement if
  685. // necessary and see if it calls the FPO function. We will also have
  686. // to check for thunks and see if maybe it called a JMP indirect which
  687. // called the FPO function. We will fail to find the caller if it was
  688. // a case of tail recursion where one function doesn't actually call
  689. // another but rather jumps to it. This will only happen when a
  690. // function who's parameter list is void calls another function who's
  691. // parameter list is void and the call is made as the last statement
  692. // in the first function. If the call to the first function was an
  693. // 0xE8 call we will fail to find it here because it didn't call the
  694. // FPO function but rather the FPO functions caller. If we don't get
  695. // specific about our 0xE8 checks we will potentially see things that
  696. // look like return addresses but aren't.
  697. //
  698. if (( cBytes >= 5 ) && ( code[ 2 ] == 0xE8 )) {
  699. // We do math on 32 bit so we can ignore carry, and then sign extended
  700. uoffT = EXTEND64((DWORD)uoffRet + *( (UNALIGNED DWORD *) &code[3] ));
  701. //
  702. // See if it calls the function directly, or into the function
  703. //
  704. if (( uoffT >= funcAddr) && ( uoffT < (funcAddr + funcSize) ) ) {
  705. WDB((1, " found function, use %X\n", (ULONG)uoffStack));
  706. return uoffStack;
  707. }
  708. while ( cJmpChain < MAX_JMP_CHAIN ) {
  709. if (!ReadMemory(Process,
  710. uoffT,
  711. jmpBuffer,
  712. sizeof(jmpBuffer),
  713. &cb)) {
  714. break;
  715. }
  716. if (cb != sizeof(jmpBuffer)) {
  717. break;
  718. }
  719. //
  720. // Now we are going to check if it is a call to a JMP, that may
  721. // jump to the function
  722. //
  723. // If it is a relative JMP then calculate the destination
  724. // and save it in uoffT. If it is an indirect JMP then read
  725. // the destination from where the JMP is inderecting through.
  726. //
  727. if ( *(LPBYTE)lpwJmp == 0xE9 ) {
  728. // We do math on 32 bit so we can ignore carry, and then
  729. // sign extended
  730. uoffT = EXTEND64 ((ULONG)uoffT +
  731. *(UNALIGNED DWORD *)( jmpBuffer + sizeof(BYTE) ) + 5);
  732. } else if ( *lpwJmp == 0x25FF ) {
  733. if ((!ReadMemory(Process,
  734. EXTEND64 (
  735. *(UNALIGNED DWORD *)
  736. ((LPBYTE)lpwJmp+sizeof(WORD))),
  737. &uoffT,
  738. sizeof(DWORD),
  739. &cb)) || (cb != sizeof(DWORD))) {
  740. uoffT = 0;
  741. break;
  742. }
  743. uoffT = EXTEND64(uoffT);
  744. } else {
  745. break;
  746. }
  747. //
  748. // If the destination is to the FPO function then we have
  749. // found the return address and thus the vEBP
  750. //
  751. if ( uoffT == funcAddr ) {
  752. WDB((1, " exact function, use %X\n",
  753. (ULONG)uoffStack));
  754. return uoffStack;
  755. }
  756. cJmpChain++;
  757. }
  758. //
  759. // We cache away the first 0xE8 call or 0xE9 jmp that we find in
  760. // the event we cant find anything else that looks like a return
  761. // address. This is meant to protect us in the tail recursion case.
  762. //
  763. if ( !uoffBestGuess ) {
  764. uoffBestGuess = uoffStack;
  765. }
  766. }
  767. //
  768. // Now loop backward through the bytes read checking for a multi
  769. // byte call type from Grp5. If we find an 0xFF then we need to
  770. // check the byte after that to make sure that the nnn bits of
  771. // the mod/rm byte tell us that it is a call. It it is a call
  772. // then we will assume that this one called us because we can
  773. // no longer accurately determine for sure whether this did
  774. // in fact call the FPO function. Since 0xFF calls are a guess
  775. // as well we will not check them if we already have an earlier guess.
  776. // It is more likely that the first 0xE8 called the function than
  777. // something higher up the stack that might be an 0xFF call.
  778. //
  779. if ( !uoffBestGuess && cBytes >= MIN_CALL ) {
  780. cbLimit = MAX_CALL - (INT)cBytes;
  781. for (cbIndex = MAX_CALL - MIN_CALL;
  782. cbIndex >= cbLimit; //MAX_CALL - (INT)cBytes;
  783. cbIndex--) {
  784. if ( ( code [ cbIndex ] == 0xFF ) &&
  785. ( ( code [ cbIndex + 1 ] & 0x30 ) == 0x10 )){
  786. WDB((1, " found call, use %X\n", (ULONG)uoffStack));
  787. return uoffStack;
  788. }
  789. }
  790. }
  791. }
  792. //
  793. // we found nothing that was 100% definite so we'll return the best guess
  794. //
  795. WDB((1, " best guess is %X\n", (ULONG)uoffBestGuess));
  796. return uoffBestGuess;
  797. }
  798. #define MRM_MOD(Mrm) (((Mrm) >> 6) & 3)
  799. #define MRM_REGOP(Mrm) (((Mrm) >> 3) & 7)
  800. #define MRM_RM(Mrm) (((Mrm) >> 0) & 7)
  801. #define SIB_SCALE(Sib) (((Sib) >> 6) & 3)
  802. #define SIB_INDEX(Sib) (((Sib) >> 3) & 7)
  803. #define SIB_BASE(Sib) (((Sib) >> 0) & 7)
  804. DWORD
  805. ModRmLen(BYTE ModRm)
  806. {
  807. BYTE Mod, Rm;
  808. Mod = MRM_MOD(ModRm);
  809. Rm = MRM_RM(ModRm);
  810. switch(Mod)
  811. {
  812. case 0:
  813. if (Rm == 4)
  814. {
  815. return 1;
  816. }
  817. else if (Rm == 5)
  818. {
  819. return 4;
  820. }
  821. break;
  822. case 1:
  823. return 1 + (Rm == 4 ? 1 : 0);
  824. case 2:
  825. return 4 + (Rm == 4 ? 1 : 0);
  826. }
  827. // No extra bytes.
  828. return 0;
  829. }
  830. BOOL
  831. GetEspRelModRm(BYTE* CodeMrm, ULONG Esp, PULONG EspRel)
  832. {
  833. BYTE Mrm, Sib;
  834. Mrm = CodeMrm[0];
  835. if (MRM_MOD(Mrm) == 3)
  836. {
  837. // Register-only form. Only handle
  838. // the case of an ESP reference.
  839. if (MRM_RM(Mrm) == 4)
  840. {
  841. *EspRel = Esp;
  842. return TRUE;
  843. }
  844. else
  845. {
  846. return FALSE;
  847. }
  848. }
  849. // Look for any ESP-relative R/M.
  850. if (MRM_RM(Mrm) != 4)
  851. {
  852. return FALSE;
  853. }
  854. Sib = CodeMrm[1];
  855. // Only simple displacements from ESP are supported.
  856. if (SIB_INDEX(Sib) != 4 ||
  857. SIB_BASE(Sib) != 4)
  858. {
  859. return FALSE;
  860. }
  861. switch(MRM_MOD(Mrm))
  862. {
  863. case 0:
  864. // [esp]
  865. *EspRel = Esp;
  866. break;
  867. case 1:
  868. // disp8[esp]
  869. *EspRel = Esp + (signed char)CodeMrm[2];
  870. break;
  871. case 2:
  872. // disp32[esp]
  873. *EspRel = Esp + *(ULONG UNALIGNED *)&CodeMrm[2];
  874. break;
  875. default:
  876. // Should never get here, MOD == 3 is handled above.
  877. return FALSE;
  878. }
  879. return TRUE;
  880. }
  881. DWORD64
  882. SearchForFramePointer(
  883. HANDLE Process,
  884. DWORD64 RegSaveAddr,
  885. DWORD64 RetEspAddr,
  886. DWORD NumRegs,
  887. DWORD64 FuncAddr,
  888. DWORD FuncSize,
  889. PREAD_PROCESS_MEMORY_ROUTINE64 ReadMemory
  890. )
  891. {
  892. BYTE Code[MAX_FUNC_PROLOGUE];
  893. DWORD CodeLen;
  894. DWORD i;
  895. DWORD Depth;
  896. DWORD64 DefAddr;
  897. DWORD Esp = (ULONG)RetEspAddr;
  898. BOOL EspValid = TRUE;
  899. BYTE Mrm;
  900. WDB((1, " SearchForFramePointer: regs %X, ret ESP %X, numregs %d\n",
  901. (ULONG)RegSaveAddr, (ULONG)RetEspAddr, NumRegs));
  902. // RetEspAddr is the first address beyond the end of
  903. // the frame, so it hopefully is the address of the return
  904. // address for the call. We don't really care about that
  905. // and are more interested in what the first push slot might
  906. // be, which is directly beneath the return address.
  907. RetEspAddr -= STACK_SIZE;
  908. //
  909. // The compiler does not push registers in a consistent
  910. // order and FPO information only indicates the total
  911. // number of registers pushed, not their order. This
  912. // function searches the stack locations where registers
  913. // are stored and tries to find which one is EBP.
  914. // It searches the function code for pushes and
  915. // tries to use that information to help the stack
  916. // analysis.
  917. //
  918. // If this routine fails it just returns the base
  919. // of the register save area. If the routine pushes
  920. // no registers, return the first possible push slot.
  921. //
  922. DefAddr = NumRegs ? RegSaveAddr : RetEspAddr;
  923. // Read the beginning of the function for code analysis.
  924. if (sizeof(Code) < FuncSize)
  925. {
  926. CodeLen = sizeof(Code);
  927. }
  928. else
  929. {
  930. CodeLen = FuncSize;
  931. }
  932. if (!ReadMemory(Process, FuncAddr, Code, CodeLen, &CodeLen))
  933. {
  934. WDB((1, " unable to read code, use %X\n", (ULONG)DefAddr));
  935. return DefAddr;
  936. }
  937. // Scan the code for normal prologue operations like
  938. // sub esp, push reg and mov reg. This code only
  939. // handles a very limited set of instructions.
  940. Depth = 0;
  941. for (i = 0; i < CodeLen; i++)
  942. {
  943. WDB((4, " %08X: Opcode %02X - ",
  944. (ULONG)FuncAddr + i, Code[i]));
  945. if (Code[i] == 0x83 && i + 3 <= CodeLen && Code[i + 1] == 0xec)
  946. {
  947. // sub esp, signed imm8
  948. Esp -= (signed char)Code[i + 2];
  949. WDB((4 | SDB_NO_PREFIX, "sub esp,0x%x, ESP %X (%s)\n",
  950. (signed char)Code[i + 2], Esp,
  951. EspValid ? "valid" : "invalid"));
  952. // Loop increment adds one.
  953. i += 2;
  954. }
  955. else if (Code[i] == 0x81 && i + 6 <= CodeLen && Code[i + 1] == 0xec)
  956. {
  957. // sub esp, imm32
  958. Esp -= *(ULONG UNALIGNED *)&Code[i + 2];
  959. WDB((4 | SDB_NO_PREFIX, "sub esp,0x%x, ESP %X (%s)\n",
  960. *(ULONG UNALIGNED *)&Code[i + 2], Esp,
  961. EspValid ? "valid" : "invalid"));
  962. // Loop increment adds one.
  963. i += 5;
  964. }
  965. else if (Code[i] == 0x89 && i + 2 <= CodeLen)
  966. {
  967. // mov r/m32, reg32
  968. Mrm = Code[i + 1];
  969. switch(MRM_REGOP(Mrm))
  970. {
  971. case 5:
  972. if (GetEspRelModRm(Code + 1, Esp, &Esp))
  973. {
  974. // mov [esp+offs], ebp
  975. WDB((4 | SDB_NO_PREFIX, "mov [%X],ebp\n", Esp));
  976. WDB((1, " moved ebp to stack at %X\n", Esp));
  977. return EXTEND64(Esp);
  978. }
  979. break;
  980. }
  981. WDB((4 | SDB_NO_PREFIX, "mov r/m32,reg32, skipped\n"));
  982. i += ModRmLen(Mrm) + 1;
  983. }
  984. else if (Code[i] == 0x8b && i + 2 <= CodeLen)
  985. {
  986. // mov reg32, r/m32
  987. Mrm = Code[i + 1];
  988. if (MRM_REGOP(Mrm) == 4)
  989. {
  990. // ESP was modified in a way we can't emulate.
  991. WDB((4 | SDB_NO_PREFIX, "ESP lost\n"));
  992. EspValid = FALSE;
  993. }
  994. else
  995. {
  996. WDB((4 | SDB_NO_PREFIX, "mov reg32,r/m32, skipped\n"));
  997. }
  998. i += ModRmLen(Mrm) + 1;
  999. }
  1000. else if (Code[i] == 0x8d && i + 2 <= CodeLen)
  1001. {
  1002. // lea reg32, r/m32
  1003. Mrm = Code[i + 1];
  1004. switch(MRM_REGOP(Mrm))
  1005. {
  1006. case 4:
  1007. if (GetEspRelModRm(Code + 1, Esp, &Esp))
  1008. {
  1009. WDB((4 | SDB_NO_PREFIX, "lea esp,[%X]\n", Esp));
  1010. }
  1011. else
  1012. {
  1013. // ESP was modified in a way we can't emulate.
  1014. WDB((4 | SDB_NO_PREFIX, "ESP lost\n"));
  1015. EspValid = FALSE;
  1016. }
  1017. break;
  1018. default:
  1019. WDB((4 | SDB_NO_PREFIX, "lea reg32,r/m32, skipped\n"));
  1020. break;
  1021. }
  1022. i += ModRmLen(Mrm) + 1;
  1023. }
  1024. else if (Code[i] >= 0x50 && Code[i] <= 0x57)
  1025. {
  1026. // push rd
  1027. Esp -= STACK_SIZE;
  1028. WDB((4 | SDB_NO_PREFIX, "push <reg>, ESP %X (%s)\n", Esp,
  1029. EspValid ? "valid" : "invalid"));
  1030. if (Code[i] == 0x55)
  1031. {
  1032. // push ebp
  1033. // Found it. If we trust the ESP we've
  1034. // been tracking just return it.
  1035. // Otherwise, if it's the first instruction
  1036. // of the routine then we should return the
  1037. // frame address, otherwise return the
  1038. // proper location in the register store area.
  1039. // If there is no register store area then
  1040. // just return the default address.
  1041. if (EspValid)
  1042. {
  1043. WDB((1, " push ebp at esp %X\n", Esp));
  1044. return EXTEND64(Esp);
  1045. }
  1046. else if (!NumRegs)
  1047. {
  1048. WDB((1, " found ebp but no regarea, return %X\n",
  1049. (ULONG)DefAddr));
  1050. return DefAddr;
  1051. }
  1052. else
  1053. {
  1054. RegSaveAddr += (NumRegs - Depth - 1) * STACK_SIZE;
  1055. WDB((1, " guess ebp at %X\n", (ULONG)RegSaveAddr));
  1056. return RegSaveAddr;
  1057. }
  1058. }
  1059. Depth++;
  1060. }
  1061. else
  1062. {
  1063. // Unhandled code, fail.
  1064. WDB((4 | SDB_NO_PREFIX, "unknown\n"));
  1065. WDB((1, " unknown code sequence %02X at %X\n",
  1066. Code[i], (ULONG)FuncAddr + i));
  1067. return DefAddr;
  1068. }
  1069. }
  1070. // Didn't find a push ebp, fail.
  1071. WDB((1, " no ebp, use %X\n", (ULONG)DefAddr));
  1072. return DefAddr;
  1073. }
  1074. BOOL
  1075. GetFpoFrameBase(
  1076. HANDLE Process,
  1077. LPSTACKFRAME64 StackFrame,
  1078. PFPO_DATA pFpoData,
  1079. PFPO_DATA PreviousFpoData,
  1080. BOOL fFirstFrame,
  1081. PREAD_PROCESS_MEMORY_ROUTINE64 ReadMemory,
  1082. PGET_MODULE_BASE_ROUTINE64 GetModuleBase
  1083. )
  1084. {
  1085. DWORD Addr32;
  1086. X86_KTRAP_FRAME TrapFrame;
  1087. DWORD64 OldFrameAddr;
  1088. DWORD64 FrameAddr;
  1089. DWORD64 StackAddr;
  1090. DWORD64 ModuleBase;
  1091. DWORD64 FuncAddr;
  1092. DWORD cb;
  1093. DWORD64 StoredEbp;
  1094. //
  1095. // calculate the address of the beginning of the function
  1096. //
  1097. ModuleBase = GetModuleBase( Process, StackFrame->AddrPC.Offset );
  1098. if (!ModuleBase) {
  1099. return FALSE;
  1100. }
  1101. FuncAddr = ModuleBase+pFpoData->ulOffStart;
  1102. WDB((1, " GetFpoFrameBase: PC %X, Func %X, first %d, FPO %p [%d,%d,%d]\n",
  1103. (ULONG)StackFrame->AddrPC.Offset, (ULONG)FuncAddr,
  1104. fFirstFrame, pFpoData, pFpoData->cdwParams, pFpoData->cdwLocals,
  1105. pFpoData->cbRegs));
  1106. //
  1107. // If this isn't the first/current frame then we can add back the count
  1108. // bytes of locals and register pushed before beginning to search for
  1109. // EBP. If we are beyond prolog we can add back the count bytes of locals
  1110. // and registers pushed as well. If it is the first frame and EIP is
  1111. // greater than the address of the function then the SUB for locals has
  1112. // been done so we can add them back before beginning the search. If we
  1113. // are right on the function then we will need to start our search at ESP.
  1114. //
  1115. if ( !fFirstFrame ) {
  1116. OldFrameAddr = StackFrame->AddrFrame.Offset;
  1117. FrameAddr = 0;
  1118. //
  1119. // if this is a non-fpo or trap frame, get the frame base now:
  1120. //
  1121. if (pFpoData->cbFrame != FRAME_FPO) {
  1122. if (!PreviousFpoData || PreviousFpoData->cbFrame == FRAME_NONFPO) {
  1123. //
  1124. // previous frame base is ebp and points to this frame's ebp
  1125. //
  1126. if (!ReadMemory(Process,
  1127. OldFrameAddr,
  1128. &Addr32,
  1129. sizeof(DWORD),
  1130. &cb) ||
  1131. cb != sizeof(DWORD)) {
  1132. FrameAddr = 0;
  1133. } else {
  1134. FrameAddr = (DWORD64)(LONG64)(LONG)Addr32;
  1135. }
  1136. }
  1137. //
  1138. // if that didn't work, try for a saved ebp
  1139. //
  1140. if (!FrameAddr && IS_EBP_SAVED(StackFrame) &&
  1141. (OldFrameAddr <= SAVE_EBP(StackFrame))) {
  1142. FrameAddr = SAVE_EBP(StackFrame);
  1143. WDB((1, " non-FPO using %X\n", (ULONG)FrameAddr));
  1144. }
  1145. //
  1146. // this is not an FPO frame, so the saved EBP can only have come
  1147. // from this or a lower frame.
  1148. //
  1149. SAVE_EBP(StackFrame) = 0;
  1150. }
  1151. //
  1152. // still no frame base - either this frame is fpo, or we couldn't
  1153. // follow the ebp chain.
  1154. //
  1155. if (FrameAddr == 0) {
  1156. FrameAddr = OldFrameAddr;
  1157. //
  1158. // skip over return address from prev frame
  1159. //
  1160. FrameAddr += FRAME_SIZE;
  1161. //
  1162. // skip over this frame's locals and saved regs
  1163. //
  1164. FrameAddr += ( pFpoData->cdwLocals * STACK_SIZE );
  1165. FrameAddr += ( pFpoData->cbRegs * STACK_SIZE );
  1166. if (PreviousFpoData) {
  1167. //
  1168. // if the previous frame had an fpo record, we can account
  1169. // for its parameters
  1170. //
  1171. FrameAddr += PreviousFpoData->cdwParams * STACK_SIZE;
  1172. }
  1173. }
  1174. //
  1175. // if this is an FPO frame
  1176. // and the previous frame was non-fpo,
  1177. // and this frame passed the inherited ebp to the previous frame,
  1178. // save its ebp
  1179. //
  1180. // (if this frame used ebp, SAVE_EBP will be set after verifying
  1181. // the frame base)
  1182. //
  1183. if (pFpoData->cbFrame == FRAME_FPO &&
  1184. (!PreviousFpoData || PreviousFpoData->cbFrame == FRAME_NONFPO) &&
  1185. !pFpoData->fUseBP) {
  1186. SAVE_EBP(StackFrame) = 0;
  1187. if (ReadMemory(Process,
  1188. OldFrameAddr,
  1189. &Addr32,
  1190. sizeof(DWORD),
  1191. &cb) &&
  1192. cb == sizeof(DWORD)) {
  1193. SAVE_EBP(StackFrame) = (DWORD64)(LONG64)(LONG)Addr32;
  1194. WDB((1, " pass-through FP %X\n", Addr32));
  1195. } else {
  1196. WDB((1, " clear ebp\n"));
  1197. }
  1198. }
  1199. } else {
  1200. OldFrameAddr = StackFrame->AddrFrame.Offset;
  1201. if (pFpoData->cbFrame == FRAME_FPO && !pFpoData->fUseBP) {
  1202. //
  1203. // this frame didn't use EBP, so it actually belongs
  1204. // to a non-FPO frame further up the stack. Stash
  1205. // it in the save area for the next frame.
  1206. //
  1207. SAVE_EBP(StackFrame) = StackFrame->AddrFrame.Offset;
  1208. WDB((1, " first non-ebp save %X\n", (ULONG)SAVE_EBP(StackFrame)));
  1209. }
  1210. if (pFpoData->cbFrame == FRAME_TRAP ||
  1211. pFpoData->cbFrame == FRAME_TSS) {
  1212. FrameAddr = StackFrame->AddrFrame.Offset;
  1213. } else if (StackFrame->AddrPC.Offset == FuncAddr) {
  1214. FrameAddr = StackFrame->AddrStack.Offset;
  1215. } else if (StackFrame->AddrPC.Offset >= FuncAddr+pFpoData->cbProlog) {
  1216. FrameAddr = StackFrame->AddrStack.Offset +
  1217. ( pFpoData->cdwLocals * STACK_SIZE ) +
  1218. ( pFpoData->cbRegs * STACK_SIZE );
  1219. } else {
  1220. FrameAddr = StackFrame->AddrStack.Offset +
  1221. ( pFpoData->cdwLocals * STACK_SIZE );
  1222. }
  1223. }
  1224. if (pFpoData->cbFrame == FRAME_TRAP) {
  1225. //
  1226. // read a kernel mode trap frame from the stack
  1227. //
  1228. if (!ReadTrapFrame( Process,
  1229. FrameAddr,
  1230. &TrapFrame,
  1231. ReadMemory )) {
  1232. return FALSE;
  1233. }
  1234. SAVE_TRAP(StackFrame) = FrameAddr;
  1235. TRAP_EDITED(StackFrame) = TrapFrame.SegCs & X86_FRAME_EDITED;
  1236. StackFrame->AddrReturn.Offset = (DWORD64)(LONG64)(LONG)(TrapFrame.Eip);
  1237. StackFrame->AddrReturn.Mode = AddrModeFlat;
  1238. StackFrame->AddrReturn.Segment = 0;
  1239. return TRUE;
  1240. }
  1241. if (pFpoData->cbFrame == FRAME_TSS) {
  1242. //
  1243. // translate a tss to a kernel mode trap frame
  1244. //
  1245. StackAddr = FrameAddr;
  1246. if (!TaskGate2TrapFrame( Process, X86_KGDT_TSS, &TrapFrame,
  1247. &StackAddr, ReadMemory )) {
  1248. return FALSE;
  1249. }
  1250. TRAP_TSS(StackFrame) = X86_KGDT_TSS;
  1251. SAVE_TRAP(StackFrame) = StackAddr;
  1252. StackFrame->AddrReturn.Offset = (DWORD64)(LONG64)(LONG)(TrapFrame.Eip);
  1253. StackFrame->AddrReturn.Mode = AddrModeFlat;
  1254. StackFrame->AddrReturn.Segment = 0;
  1255. return TRUE;
  1256. }
  1257. if ((pFpoData->cbFrame != FRAME_FPO) &&
  1258. (pFpoData->cbFrame != FRAME_NONFPO) ) {
  1259. //
  1260. // we either have a compiler or linker problem, or possibly
  1261. // just simple data corruption.
  1262. //
  1263. return FALSE;
  1264. }
  1265. //
  1266. // go look for a return address. this is done because, even though
  1267. // we have subtracted all that we can from the frame pointer it is
  1268. // possible that there is other unknown data on the stack. by
  1269. // searching for the return address we are able to find the base of
  1270. // the fpo frame.
  1271. //
  1272. FrameAddr = SearchForReturnAddress( Process,
  1273. FrameAddr,
  1274. FuncAddr,
  1275. pFpoData->cbProcSize,
  1276. ReadMemory,
  1277. GetModuleBase,
  1278. PreviousFpoData != NULL
  1279. );
  1280. if (!FrameAddr) {
  1281. return FALSE;
  1282. }
  1283. if (pFpoData->fUseBP && pFpoData->cbFrame == FRAME_FPO) {
  1284. //
  1285. // this function used ebp as a general purpose register, but
  1286. // before doing so it saved ebp on the stack.
  1287. //
  1288. // we must retrieve this ebp and save it for possible later
  1289. // use if we encounter a non-fpo frame
  1290. //
  1291. if (fFirstFrame && StackFrame->AddrPC.Offset < FuncAddr+pFpoData->cbProlog) {
  1292. SAVE_EBP(StackFrame) = OldFrameAddr;
  1293. WDB((1, " first use save FP %X\n", (ULONG)OldFrameAddr));
  1294. } else {
  1295. SAVE_EBP(StackFrame) = 0;
  1296. // FPO information doesn't indicate which of the saved
  1297. // registers is EBP and the compiler doesn't push in a
  1298. // consistent way. Scan the register slots of the
  1299. // stack for something that looks OK.
  1300. StackAddr = FrameAddr -
  1301. ( ( pFpoData->cbRegs + pFpoData->cdwLocals ) * STACK_SIZE );
  1302. StackAddr = SearchForFramePointer( Process,
  1303. StackAddr,
  1304. FrameAddr,
  1305. pFpoData->cbRegs,
  1306. FuncAddr,
  1307. pFpoData->cbProcSize,
  1308. ReadMemory
  1309. );
  1310. if (StackAddr &&
  1311. ReadMemory(Process,
  1312. StackAddr,
  1313. &Addr32,
  1314. sizeof(DWORD),
  1315. &cb) &&
  1316. cb == sizeof(DWORD)) {
  1317. SAVE_EBP(StackFrame) = (DWORD64)(LONG64)(LONG)Addr32;
  1318. WDB((1, " use search save %X from %X\n", Addr32,
  1319. (ULONG)StackAddr));
  1320. } else {
  1321. WDB((1, " use clear ebp\n"));
  1322. }
  1323. }
  1324. }
  1325. //
  1326. // subtract the size for an ebp register if one had
  1327. // been pushed. this is done because the frames that
  1328. // are virtualized need to appear as close to a real frame
  1329. // as possible.
  1330. //
  1331. StackFrame->AddrFrame.Offset = FrameAddr - STACK_SIZE;
  1332. return TRUE;
  1333. }
  1334. BOOL
  1335. ReadTrapFrame(
  1336. HANDLE Process,
  1337. DWORD64 TrapFrameAddress,
  1338. PX86_KTRAP_FRAME TrapFrame,
  1339. PREAD_PROCESS_MEMORY_ROUTINE64 ReadMemory
  1340. )
  1341. {
  1342. DWORD cb;
  1343. if (!ReadMemory(Process,
  1344. TrapFrameAddress,
  1345. TrapFrame,
  1346. sizeof(*TrapFrame),
  1347. &cb)) {
  1348. return FALSE;
  1349. }
  1350. if (cb < sizeof(*TrapFrame)) {
  1351. if (cb < sizeof(*TrapFrame) - 20) {
  1352. //
  1353. // shorter then the smallest possible frame type
  1354. //
  1355. return FALSE;
  1356. }
  1357. if ((TrapFrame->SegCs & 1) && cb < sizeof(*TrapFrame) - 16 ) {
  1358. //
  1359. // too small for inter-ring frame
  1360. //
  1361. return FALSE;
  1362. }
  1363. if (TrapFrame->EFlags & X86_EFLAGS_V86_MASK) {
  1364. //
  1365. // too small for V86 frame
  1366. //
  1367. return FALSE;
  1368. }
  1369. }
  1370. return TRUE;
  1371. }
  1372. BOOL
  1373. GetSelector(
  1374. HANDLE Process,
  1375. USHORT Processor,
  1376. PX86_DESCRIPTOR_TABLE_ENTRY pDescriptorTableEntry,
  1377. PREAD_PROCESS_MEMORY_ROUTINE64 ReadMemory
  1378. )
  1379. {
  1380. ULONG_PTR Address;
  1381. PVOID TableBase;
  1382. USHORT TableLimit;
  1383. ULONG Index;
  1384. X86_LDT_ENTRY Descriptor;
  1385. ULONG bytesread;
  1386. //
  1387. // Fetch the address and limit of the GDT
  1388. //
  1389. Address = (ULONG_PTR)&(((PX86_KSPECIAL_REGISTERS)0)->Gdtr.Base);
  1390. ReadMemory( Process, Address, &TableBase, sizeof(TableBase), (LPDWORD)-1 );
  1391. Address = (ULONG_PTR)&(((PX86_KSPECIAL_REGISTERS)0)->Gdtr.Limit);
  1392. ReadMemory( Process, Address, &TableLimit, sizeof(TableLimit), (LPDWORD)-1 );
  1393. //
  1394. // Find out whether this is a GDT or LDT selector
  1395. //
  1396. if (pDescriptorTableEntry->Selector & 0x4) {
  1397. //
  1398. // This is an LDT selector, so we reload the TableBase and TableLimit
  1399. // with the LDT's Base & Limit by loading the descriptor for the
  1400. // LDT selector.
  1401. //
  1402. if (!ReadMemory(Process,
  1403. (ULONG64)TableBase+X86_KGDT_LDT,
  1404. &Descriptor,
  1405. sizeof(Descriptor),
  1406. &bytesread)) {
  1407. return FALSE;
  1408. }
  1409. TableBase = (PVOID)(DWORD_PTR)((ULONG)Descriptor.BaseLow + // Sundown: zero-extension from ULONG to PVOID.
  1410. ((ULONG)Descriptor.HighWord.Bits.BaseMid << 16) +
  1411. ((ULONG)Descriptor.HighWord.Bytes.BaseHi << 24));
  1412. TableLimit = Descriptor.LimitLow; // LDT can't be > 64k
  1413. if(Descriptor.HighWord.Bits.Granularity) {
  1414. //
  1415. // I suppose it's possible, to have an
  1416. // LDT with page granularity.
  1417. //
  1418. TableLimit <<= X86_PAGE_SHIFT;
  1419. }
  1420. }
  1421. Index = (USHORT)(pDescriptorTableEntry->Selector) & ~0x7;
  1422. // Irrelevant bits
  1423. //
  1424. // Check to make sure that the selector is within the table bounds
  1425. //
  1426. if (Index >= TableLimit) {
  1427. //
  1428. // Selector is out of table's bounds
  1429. //
  1430. return FALSE;
  1431. }
  1432. if (!ReadMemory(Process,
  1433. (ULONG64)TableBase+Index,
  1434. &(pDescriptorTableEntry->Descriptor),
  1435. sizeof(pDescriptorTableEntry->Descriptor),
  1436. &bytesread)) {
  1437. return FALSE;
  1438. }
  1439. return TRUE;
  1440. }
  1441. BOOL
  1442. TaskGate2TrapFrame(
  1443. HANDLE Process,
  1444. USHORT TaskRegister,
  1445. PX86_KTRAP_FRAME TrapFrame,
  1446. PULONG64 off,
  1447. PREAD_PROCESS_MEMORY_ROUTINE64 ReadMemory
  1448. )
  1449. {
  1450. X86_DESCRIPTOR_TABLE_ENTRY desc;
  1451. ULONG bytesread;
  1452. struct {
  1453. ULONG r1[8];
  1454. ULONG Eip;
  1455. ULONG EFlags;
  1456. ULONG Eax;
  1457. ULONG Ecx;
  1458. ULONG Edx;
  1459. ULONG Ebx;
  1460. ULONG Esp;
  1461. ULONG Ebp;
  1462. ULONG Esi;
  1463. ULONG Edi;
  1464. ULONG Es;
  1465. ULONG Cs;
  1466. ULONG Ss;
  1467. ULONG Ds;
  1468. ULONG Fs;
  1469. ULONG Gs;
  1470. } TaskState;
  1471. //
  1472. // Get the task register
  1473. //
  1474. desc.Selector = TaskRegister;
  1475. if (!GetSelector(Process, 0, &desc, ReadMemory)) {
  1476. return FALSE;
  1477. }
  1478. if (desc.Descriptor.HighWord.Bits.Type != 9 &&
  1479. desc.Descriptor.HighWord.Bits.Type != 0xb) {
  1480. //
  1481. // not a 32bit task descriptor
  1482. //
  1483. return FALSE;
  1484. }
  1485. //
  1486. // Read in Task State Segment
  1487. //
  1488. *off = ((ULONG)desc.Descriptor.BaseLow +
  1489. ((ULONG)desc.Descriptor.HighWord.Bytes.BaseMid << 16) +
  1490. ((ULONG)desc.Descriptor.HighWord.Bytes.BaseHi << 24) );
  1491. if (!ReadMemory(Process,
  1492. EXTEND64(*off),
  1493. &TaskState,
  1494. sizeof(TaskState),
  1495. &bytesread)) {
  1496. return FALSE;
  1497. }
  1498. //
  1499. // Move fields from Task State Segment to TrapFrame
  1500. //
  1501. ZeroMemory( TrapFrame, sizeof(*TrapFrame) );
  1502. TrapFrame->Eip = TaskState.Eip;
  1503. TrapFrame->EFlags = TaskState.EFlags;
  1504. TrapFrame->Eax = TaskState.Eax;
  1505. TrapFrame->Ecx = TaskState.Ecx;
  1506. TrapFrame->Edx = TaskState.Edx;
  1507. TrapFrame->Ebx = TaskState.Ebx;
  1508. TrapFrame->Ebp = TaskState.Ebp;
  1509. TrapFrame->Esi = TaskState.Esi;
  1510. TrapFrame->Edi = TaskState.Edi;
  1511. TrapFrame->SegEs = TaskState.Es;
  1512. TrapFrame->SegCs = TaskState.Cs;
  1513. TrapFrame->SegDs = TaskState.Ds;
  1514. TrapFrame->SegFs = TaskState.Fs;
  1515. TrapFrame->SegGs = TaskState.Gs;
  1516. TrapFrame->HardwareEsp = TaskState.Esp;
  1517. TrapFrame->HardwareSegSs = TaskState.Ss;
  1518. return TRUE;
  1519. }
  1520. BOOL
  1521. ProcessTrapFrame(
  1522. HANDLE Process,
  1523. LPSTACKFRAME64 StackFrame,
  1524. PFPO_DATA pFpoData,
  1525. PFPO_DATA PreviousFpoData,
  1526. PREAD_PROCESS_MEMORY_ROUTINE64 ReadMemory,
  1527. PFUNCTION_TABLE_ACCESS_ROUTINE64 FunctionTableAccess
  1528. )
  1529. {
  1530. X86_KTRAP_FRAME TrapFrame;
  1531. DWORD64 StackAddr;
  1532. if (PreviousFpoData->cbFrame == FRAME_TSS) {
  1533. StackAddr = SAVE_TRAP(StackFrame);
  1534. TaskGate2TrapFrame( Process, X86_KGDT_TSS, &TrapFrame, &StackAddr, ReadMemory );
  1535. } else {
  1536. if (!ReadTrapFrame( Process,
  1537. SAVE_TRAP(StackFrame),
  1538. &TrapFrame,
  1539. ReadMemory)) {
  1540. SAVE_TRAP(StackFrame) = 0;
  1541. return FALSE;
  1542. }
  1543. }
  1544. pFpoData = (PFPO_DATA)
  1545. FunctionTableAccess(Process,
  1546. (DWORD64)(LONG64)(LONG)TrapFrame.Eip);
  1547. #if 0
  1548. // Remove this check since we are not using pFpoData anyway
  1549. if (!pFpoData) {
  1550. StackFrame->AddrFrame.Offset = (DWORD64)(LONG64)(LONG)TrapFrame.Ebp;
  1551. SAVE_EBP(StackFrame) = 0;
  1552. } else
  1553. #endif //0
  1554. {
  1555. if ((TrapFrame.SegCs & X86_MODE_MASK) ||
  1556. (TrapFrame.EFlags & X86_EFLAGS_V86_MASK)) {
  1557. //
  1558. // User-mode frame, real value of Esp is in HardwareEsp
  1559. //
  1560. StackFrame->AddrFrame.Offset = (DWORD64)(LONG64)(LONG)(TrapFrame.HardwareEsp - STACK_SIZE);
  1561. StackFrame->AddrStack.Offset = (DWORD64)(LONG64)(LONG)TrapFrame.HardwareEsp;
  1562. } else {
  1563. //
  1564. // We ignore if Esp has been edited for now, and we will print a
  1565. // separate line indicating this later.
  1566. //
  1567. // Calculate kernel Esp
  1568. //
  1569. if (PreviousFpoData->cbFrame == FRAME_TRAP) {
  1570. //
  1571. // plain trap frame
  1572. //
  1573. if ((TrapFrame.SegCs & X86_FRAME_EDITED) == 0) {
  1574. StackFrame->AddrStack.Offset = EXTEND64(TrapFrame.TempEsp);
  1575. } else {
  1576. StackFrame->AddrStack.Offset = EXTEND64(SAVE_TRAP(StackFrame))+
  1577. FIELD_OFFSET(X86_KTRAP_FRAME, HardwareEsp);
  1578. }
  1579. } else {
  1580. //
  1581. // tss converted to trap frame
  1582. //
  1583. StackFrame->AddrStack.Offset = EXTEND64(TrapFrame.HardwareEsp);
  1584. }
  1585. }
  1586. }
  1587. StackFrame->AddrFrame.Offset = EXTEND64(TrapFrame.Ebp);
  1588. StackFrame->AddrPC.Offset = EXTEND64(TrapFrame.Eip);
  1589. SAVE_TRAP(StackFrame) = 0;
  1590. StackFrame->FuncTableEntry = pFpoData;
  1591. return TRUE;
  1592. }
  1593. BOOL
  1594. IsFarCall(
  1595. HANDLE Process,
  1596. HANDLE Thread,
  1597. LPSTACKFRAME64 StackFrame,
  1598. BOOL *Ok,
  1599. PREAD_PROCESS_MEMORY_ROUTINE64 ReadMemory,
  1600. PTRANSLATE_ADDRESS_ROUTINE64 TranslateAddress
  1601. )
  1602. {
  1603. BOOL fFar = FALSE;
  1604. ULONG cb;
  1605. ADDRESS64 Addr;
  1606. *Ok = TRUE;
  1607. if (StackFrame->AddrFrame.Mode == AddrModeFlat) {
  1608. DWORD dwStk[ 3 ];
  1609. //
  1610. // If we are working with 32 bit offset stack pointers, we
  1611. // will say that the return address if far if the address
  1612. // treated as a FAR pointer makes any sense, if not then
  1613. // it must be a near return
  1614. //
  1615. if (StackFrame->AddrFrame.Offset &&
  1616. DoMemoryReadAll( &StackFrame->AddrFrame, dwStk, sizeof(dwStk) )) {
  1617. //
  1618. // See if segment makes sense
  1619. //
  1620. Addr.Offset = (DWORD64)(LONG64)(LONG)(dwStk[1]);
  1621. Addr.Segment = (WORD)dwStk[2];
  1622. Addr.Mode = AddrModeFlat;
  1623. if (TranslateAddress( Process, Thread, &Addr ) && Addr.Offset) {
  1624. fFar = TRUE;
  1625. }
  1626. } else {
  1627. *Ok = FALSE;
  1628. }
  1629. } else {
  1630. WORD wStk[ 3 ];
  1631. //
  1632. // For 16 bit (i.e. windows WOW code) we do the following tests
  1633. // to check to see if an address is a far return value.
  1634. //
  1635. // 1. if the saved BP register is odd then it is a far
  1636. // return values
  1637. // 2. if the address treated as a far return value makes sense
  1638. // then it is a far return value
  1639. // 3. else it is a near return value
  1640. //
  1641. if (StackFrame->AddrFrame.Offset &&
  1642. DoMemoryReadAll( &StackFrame->AddrFrame, wStk, 6 )) {
  1643. if ( wStk[0] & 0x0001 ) {
  1644. fFar = TRUE;
  1645. } else {
  1646. //
  1647. // See if segment makes sense
  1648. //
  1649. Addr.Offset = wStk[1];
  1650. Addr.Segment = wStk[2];
  1651. Addr.Mode = AddrModeFlat;
  1652. if (TranslateAddress( Process, Thread, &Addr ) && Addr.Offset) {
  1653. fFar = TRUE;
  1654. }
  1655. }
  1656. } else {
  1657. *Ok = FALSE;
  1658. }
  1659. }
  1660. return fFar;
  1661. }
  1662. BOOL
  1663. SetNonOff32FrameAddress(
  1664. HANDLE Process,
  1665. HANDLE Thread,
  1666. LPSTACKFRAME64 StackFrame,
  1667. PREAD_PROCESS_MEMORY_ROUTINE64 ReadMemory,
  1668. PFUNCTION_TABLE_ACCESS_ROUTINE64 FunctionTableAccess,
  1669. PGET_MODULE_BASE_ROUTINE64 GetModuleBase,
  1670. PTRANSLATE_ADDRESS_ROUTINE64 TranslateAddress
  1671. )
  1672. {
  1673. BOOL fFar;
  1674. WORD Stk[ 3 ];
  1675. ULONG cb;
  1676. BOOL Ok;
  1677. fFar = IsFarCall( Process, Thread, StackFrame, &Ok, ReadMemory, TranslateAddress );
  1678. if (!Ok) {
  1679. return FALSE;
  1680. }
  1681. if (!DoMemoryReadAll( &StackFrame->AddrFrame, Stk, (DWORD)(fFar ? FRAME_SIZE1632 : FRAME_SIZE16) )) {
  1682. return FALSE;
  1683. }
  1684. if (IS_EBP_SAVED(StackFrame) && (SAVE_EBP(StackFrame) > 0)) {
  1685. StackFrame->AddrFrame.Offset = SAVE_EBP(StackFrame) & 0xffff;
  1686. StackFrame->AddrPC.Offset = Stk[1];
  1687. if (fFar) {
  1688. StackFrame->AddrPC.Segment = Stk[2];
  1689. }
  1690. SAVE_EBP(StackFrame) = 0;
  1691. } else {
  1692. if (Stk[1] == 0) {
  1693. return FALSE;
  1694. } else {
  1695. StackFrame->AddrFrame.Offset = Stk[0];
  1696. StackFrame->AddrFrame.Offset &= 0xFFFFFFFE;
  1697. StackFrame->AddrPC.Offset = Stk[1];
  1698. if (fFar) {
  1699. StackFrame->AddrPC.Segment = Stk[2];
  1700. }
  1701. }
  1702. }
  1703. return TRUE;
  1704. }
  1705. VOID
  1706. X86ReadFunctionParameters(
  1707. HANDLE Process,
  1708. ULONG64 Offset,
  1709. LPSTACKFRAME64 Frame,
  1710. PREAD_PROCESS_MEMORY_ROUTINE64 ReadMemory
  1711. )
  1712. {
  1713. DWORD Params[4];
  1714. DWORD Done;
  1715. if (!ReadMemory(Process, Offset, Params, sizeof(Params), &Done)) {
  1716. Done = 0;
  1717. }
  1718. if (Done < sizeof(Params)) {
  1719. ZeroMemory((PUCHAR)Params + Done, sizeof(Params) - Done);
  1720. }
  1721. Frame->Params[0] = (DWORD64)(LONG64)(LONG)(Params[0]);
  1722. Frame->Params[1] = (DWORD64)(LONG64)(LONG)(Params[1]);
  1723. Frame->Params[2] = (DWORD64)(LONG64)(LONG)(Params[2]);
  1724. Frame->Params[3] = (DWORD64)(LONG64)(LONG)(Params[3]);
  1725. }
  1726. VOID
  1727. GetFunctionParameters(
  1728. HANDLE Process,
  1729. HANDLE Thread,
  1730. LPSTACKFRAME64 StackFrame,
  1731. PREAD_PROCESS_MEMORY_ROUTINE64 ReadMemory,
  1732. PGET_MODULE_BASE_ROUTINE64 GetModuleBase,
  1733. PTRANSLATE_ADDRESS_ROUTINE64 TranslateAddress
  1734. )
  1735. {
  1736. BOOL Ok;
  1737. ADDRESS64 ParmsAddr;
  1738. ParmsAddr = StackFrame->AddrFrame;
  1739. //
  1740. // calculate the frame size
  1741. //
  1742. if (StackFrame->AddrPC.Mode == AddrModeFlat) {
  1743. ParmsAddr.Offset += FRAME_SIZE;
  1744. } else
  1745. if ( IsFarCall( Process, Thread, StackFrame, &Ok,
  1746. ReadMemory, TranslateAddress ) ) {
  1747. StackFrame->Far = TRUE;
  1748. ParmsAddr.Offset += FRAME_SIZE1632;
  1749. } else {
  1750. StackFrame->Far = FALSE;
  1751. ParmsAddr.Offset += STACK_SIZE;
  1752. }
  1753. //
  1754. // read the memory
  1755. //
  1756. if (ParmsAddr.Mode != AddrModeFlat) {
  1757. TranslateAddress( Process, Thread, &ParmsAddr );
  1758. }
  1759. X86ReadFunctionParameters(Process, ParmsAddr.Offset, StackFrame,
  1760. ReadMemory);
  1761. }
  1762. VOID
  1763. GetReturnAddress(
  1764. HANDLE Process,
  1765. HANDLE Thread,
  1766. LPSTACKFRAME64 StackFrame,
  1767. PREAD_PROCESS_MEMORY_ROUTINE64 ReadMemory,
  1768. PGET_MODULE_BASE_ROUTINE64 GetModuleBase,
  1769. PTRANSLATE_ADDRESS_ROUTINE64 TranslateAddress,
  1770. PFUNCTION_TABLE_ACCESS_ROUTINE64 FunctionTableAccess
  1771. )
  1772. {
  1773. ULONG cb;
  1774. DWORD stack[1];
  1775. if (SAVE_TRAP(StackFrame)) {
  1776. //
  1777. // if a trap frame was encountered then
  1778. // the return address was already calculated
  1779. //
  1780. return;
  1781. }
  1782. WDB((1, " GetReturnAddress: SP %X, FP %X\n",
  1783. (ULONG)StackFrame->AddrStack.Offset,
  1784. (ULONG)StackFrame->AddrFrame.Offset));
  1785. if (StackFrame->AddrPC.Mode == AddrModeFlat) {
  1786. ULONG64 CallOffset;
  1787. PFPO_DATA CallFpo;
  1788. ADDRESS64 FrameRet;
  1789. FPO_DATA SaveCallFpo;
  1790. PFPO_DATA RetFpo;
  1791. //
  1792. // read the frame from the process's memory
  1793. //
  1794. FrameRet = StackFrame->AddrFrame;
  1795. FrameRet.Offset += STACK_SIZE;
  1796. FrameRet.Offset = EXTEND64(FrameRet.Offset);
  1797. if (!DoMemoryRead( &FrameRet, stack, STACK_SIZE, &cb ) ||
  1798. cb < STACK_SIZE) {
  1799. //
  1800. // if we could not read the memory then set
  1801. // the return address to zero so that the stack trace
  1802. // will terminate
  1803. //
  1804. stack[0] = 0;
  1805. }
  1806. StackFrame->AddrReturn.Offset = (DWORD64)(LONG64)(LONG)(stack[0]);
  1807. WDB((1, " read %X\n", stack[0]));
  1808. //
  1809. // Calls of __declspec(noreturn) functions may not have any
  1810. // code after them to return to since the compiler knows
  1811. // that the function will not return. This can confuse
  1812. // stack traces because the return address will lie outside
  1813. // of the function's address range and FPO data will not
  1814. // be looked up correctly. Check and see if the return
  1815. // address falls outside of the calling function and, if so,
  1816. // adjust the return address back by one byte. It'd be
  1817. // better to adjust it back to the call itself so that
  1818. // the return address points to valid code but
  1819. // backing up in X86 assembly is more or less impossible.
  1820. //
  1821. CallOffset = StackFrame->AddrReturn.Offset - 1;
  1822. CallFpo = (PFPO_DATA)FunctionTableAccess(Process, CallOffset);
  1823. if (CallFpo != NULL) {
  1824. SaveCallFpo = *CallFpo;
  1825. }
  1826. RetFpo = (PFPO_DATA)
  1827. FunctionTableAccess(Process, StackFrame->AddrReturn.Offset);
  1828. if (CallFpo != NULL) {
  1829. if (RetFpo == NULL ||
  1830. memcmp(&SaveCallFpo, RetFpo, sizeof(SaveCallFpo))) {
  1831. StackFrame->AddrReturn.Offset = CallOffset;
  1832. }
  1833. } else if (RetFpo != NULL) {
  1834. StackFrame->AddrReturn.Offset = CallOffset;
  1835. }
  1836. } else {
  1837. StackFrame->AddrReturn.Offset = StackFrame->AddrPC.Offset;
  1838. StackFrame->AddrReturn.Segment = StackFrame->AddrPC.Segment;
  1839. }
  1840. }
  1841. BOOL
  1842. WalkX86_Fpo_Fpo(
  1843. HANDLE Process,
  1844. HANDLE Thread,
  1845. PFPO_DATA pFpoData,
  1846. PFPO_DATA PreviousFpoData,
  1847. LPSTACKFRAME64 StackFrame,
  1848. PREAD_PROCESS_MEMORY_ROUTINE64 ReadMemory,
  1849. PFUNCTION_TABLE_ACCESS_ROUTINE64 FunctionTableAccess,
  1850. PGET_MODULE_BASE_ROUTINE64 GetModuleBase,
  1851. PTRANSLATE_ADDRESS_ROUTINE64 TranslateAddress
  1852. )
  1853. {
  1854. BOOL rval;
  1855. WDB((1, " WalkFF:\n"));
  1856. rval = GetFpoFrameBase( Process,
  1857. StackFrame,
  1858. pFpoData,
  1859. PreviousFpoData,
  1860. FALSE,
  1861. ReadMemory,
  1862. GetModuleBase );
  1863. StackFrame->FuncTableEntry = pFpoData;
  1864. return rval;
  1865. }
  1866. BOOL
  1867. WalkX86_Fpo_NonFpo(
  1868. HANDLE Process,
  1869. HANDLE Thread,
  1870. PFPO_DATA pFpoData,
  1871. PFPO_DATA PreviousFpoData,
  1872. LPSTACKFRAME64 StackFrame,
  1873. PX86_CONTEXT ContextRecord,
  1874. PREAD_PROCESS_MEMORY_ROUTINE64 ReadMemory,
  1875. PFUNCTION_TABLE_ACCESS_ROUTINE64 FunctionTableAccess,
  1876. PGET_MODULE_BASE_ROUTINE64 GetModuleBase,
  1877. PTRANSLATE_ADDRESS_ROUTINE64 TranslateAddress
  1878. )
  1879. {
  1880. DWORD stack[FRAME_SIZE+STACK_SIZE];
  1881. DWORD cb;
  1882. DWORD64 FrameAddr;
  1883. DWORD64 FuncAddr;
  1884. DWORD FuncSize;
  1885. BOOL AcceptUnreadableCallsite = FALSE;
  1886. WDB((1, " WalkFN:\n"));
  1887. //
  1888. // if the previous frame was an SEH frame then we must
  1889. // retrieve the "real" frame pointer for this frame.
  1890. // the SEH function pushed the frame pointer last.
  1891. //
  1892. if (PreviousFpoData->fHasSEH) {
  1893. if (DoMemoryReadAll( &StackFrame->AddrFrame, stack, FRAME_SIZE+STACK_SIZE )) {
  1894. StackFrame->AddrFrame.Offset = (DWORD64)(LONG64)(LONG)(stack[2]);
  1895. StackFrame->AddrStack.Offset = (DWORD64)(LONG64)(LONG)(stack[2]);
  1896. WalkX86Init(Process,
  1897. Thread,
  1898. StackFrame,
  1899. ContextRecord,
  1900. ReadMemory,
  1901. FunctionTableAccess,
  1902. GetModuleBase,
  1903. TranslateAddress);
  1904. return TRUE;
  1905. }
  1906. }
  1907. //
  1908. // If a prior frame has stored this frame's EBP, just use it.
  1909. // Do sanity check if the saved ebp looks like a valid ebp for current stack
  1910. //
  1911. if (IS_EBP_SAVED(StackFrame) &&
  1912. (StackFrame->AddrFrame.Offset <= SAVE_EBP(StackFrame)) &&
  1913. (StackFrame->AddrFrame.Offset + 0x4000 >= SAVE_EBP(StackFrame))) {
  1914. StackFrame->AddrFrame.Offset = SAVE_EBP(StackFrame);
  1915. FrameAddr = StackFrame->AddrFrame.Offset + 4;
  1916. AcceptUnreadableCallsite = TRUE;
  1917. WDB((1, " use %X\n", (ULONG)FrameAddr));
  1918. } else {
  1919. //
  1920. // Skip past the FPO frame base and parameters.
  1921. //
  1922. StackFrame->AddrFrame.Offset +=
  1923. (FRAME_SIZE + (PreviousFpoData->cdwParams * 4));
  1924. //
  1925. // Now this is pointing to the bottom of the non-FPO frame.
  1926. // If the frame has an fpo record, use it:
  1927. //
  1928. if (pFpoData) {
  1929. FrameAddr = StackFrame->AddrFrame.Offset +
  1930. 4* (pFpoData->cbRegs + pFpoData->cdwLocals);
  1931. AcceptUnreadableCallsite = TRUE;
  1932. } else {
  1933. //
  1934. // We don't know if the non-fpo frame has any locals, but
  1935. // skip past the EBP anyway.
  1936. //
  1937. FrameAddr = StackFrame->AddrFrame.Offset + 4;
  1938. }
  1939. WDB((1, " compute %X\n", (ULONG)FrameAddr));
  1940. }
  1941. //
  1942. // at this point we may not be sitting at the base of the frame
  1943. // so we now search for the return address and then subtract the
  1944. // size of the frame pointer and use that address as the new base.
  1945. //
  1946. if (pFpoData) {
  1947. FuncAddr = GetModuleBase(Process,StackFrame->AddrPC.Offset) + pFpoData->ulOffStart;
  1948. FuncSize = pFpoData->cbProcSize;
  1949. } else {
  1950. FuncAddr = StackFrame->AddrPC.Offset - MAX_CALL;
  1951. FuncSize = MAX_CALL;
  1952. }
  1953. FrameAddr = SearchForReturnAddress( Process,
  1954. FrameAddr,
  1955. FuncAddr,
  1956. FuncSize,
  1957. ReadMemory,
  1958. GetModuleBase,
  1959. AcceptUnreadableCallsite
  1960. );
  1961. if (FrameAddr) {
  1962. StackFrame->AddrFrame.Offset = FrameAddr - STACK_SIZE;
  1963. }
  1964. if (!DoMemoryReadAll( &StackFrame->AddrFrame, stack, FRAME_SIZE )) {
  1965. //
  1966. // a failure means that we likely have a bad address.
  1967. // returning zero will terminate that stack trace.
  1968. //
  1969. stack[0] = 0;
  1970. }
  1971. SAVE_EBP(StackFrame) = (DWORD64)(LONG64)(LONG)(stack[0]);
  1972. WDB((1, " save %X\n", stack[0]));
  1973. StackFrame->FuncTableEntry = pFpoData;
  1974. return TRUE;
  1975. }
  1976. BOOL
  1977. WalkX86_NonFpo_Fpo(
  1978. HANDLE Process,
  1979. HANDLE Thread,
  1980. PFPO_DATA pFpoData,
  1981. PFPO_DATA PreviousFpoData,
  1982. LPSTACKFRAME64 StackFrame,
  1983. PREAD_PROCESS_MEMORY_ROUTINE64 ReadMemory,
  1984. PFUNCTION_TABLE_ACCESS_ROUTINE64 FunctionTableAccess,
  1985. PGET_MODULE_BASE_ROUTINE64 GetModuleBase,
  1986. PTRANSLATE_ADDRESS_ROUTINE64 TranslateAddress
  1987. )
  1988. {
  1989. BOOL rval;
  1990. WDB((1, " WalkNF:\n"));
  1991. rval = GetFpoFrameBase( Process,
  1992. StackFrame,
  1993. pFpoData,
  1994. PreviousFpoData,
  1995. FALSE,
  1996. ReadMemory,
  1997. GetModuleBase );
  1998. StackFrame->FuncTableEntry = pFpoData;
  1999. return rval;
  2000. }
  2001. BOOL
  2002. WalkX86_NonFpo_NonFpo(
  2003. HANDLE Process,
  2004. HANDLE Thread,
  2005. PFPO_DATA pFpoData,
  2006. PFPO_DATA PreviousFpoData,
  2007. LPSTACKFRAME64 StackFrame,
  2008. PREAD_PROCESS_MEMORY_ROUTINE64 ReadMemory,
  2009. PFUNCTION_TABLE_ACCESS_ROUTINE64 FunctionTableAccess,
  2010. PGET_MODULE_BASE_ROUTINE64 GetModuleBase,
  2011. PTRANSLATE_ADDRESS_ROUTINE64 TranslateAddress
  2012. )
  2013. {
  2014. DWORD stack[FRAME_SIZE*4];
  2015. DWORD cb;
  2016. WDB((1, " WalkNN:\n"));
  2017. //
  2018. // a previous function in the call stack was a fpo function that used ebp as
  2019. // a general purpose register. ul contains the ebp value that was good before
  2020. // that function executed. it is that ebp that we want, not what was just read
  2021. // from the stack. what was just read from the stack is totally bogus.
  2022. //
  2023. if (IS_EBP_SAVED(StackFrame) &&
  2024. (StackFrame->AddrFrame.Offset <= SAVE_EBP(StackFrame))) {
  2025. StackFrame->AddrFrame.Offset = SAVE_EBP(StackFrame);
  2026. SAVE_EBP(StackFrame) = 0;
  2027. } else {
  2028. //
  2029. // read the first dword off the stack
  2030. //
  2031. if (!DoMemoryReadAll( &StackFrame->AddrFrame, stack, STACK_SIZE )) {
  2032. return FALSE;
  2033. }
  2034. StackFrame->AddrFrame.Offset = (DWORD64)(LONG64)(LONG)(stack[0]);
  2035. }
  2036. StackFrame->FuncTableEntry = pFpoData;
  2037. return TRUE;
  2038. }
  2039. BOOL
  2040. X86ApplyFrameData(
  2041. HANDLE Process,
  2042. LPSTACKFRAME64 StackFrame,
  2043. PX86_CONTEXT ContextRecord,
  2044. PFPO_DATA PreviousFpoData,
  2045. BOOL FirstFrame,
  2046. PREAD_PROCESS_MEMORY_ROUTINE64 ReadMemory,
  2047. PGET_MODULE_BASE_ROUTINE64 GetModuleBase
  2048. )
  2049. {
  2050. IDiaFrameData* DiaFrame;
  2051. BOOL Succ = FALSE;
  2052. // If we can get VC7-style frame data just execute
  2053. // the frame data program to unwind the stack.
  2054. // If weren't given a context record we cannot use
  2055. // the new VC7 unwind information as we have nowhere
  2056. // to save intermediate context values.
  2057. if (StackFrame->AddrPC.Mode != AddrModeFlat ||
  2058. !g_vc7fpo ||
  2059. !ContextRecord ||
  2060. !diaGetFrameData(Process, StackFrame->AddrPC.Offset, &DiaFrame))
  2061. {
  2062. return FALSE;
  2063. }
  2064. if (FirstFrame)
  2065. {
  2066. ContextRecord->Ebp = (ULONG)StackFrame->AddrFrame.Offset;
  2067. ContextRecord->Esp = (ULONG)StackFrame->AddrStack.Offset;
  2068. ContextRecord->Eip = (ULONG)StackFrame->AddrPC.Offset;
  2069. }
  2070. WDB((1, " Applying frame data program for PC %X SP %X FP %X\n",
  2071. ContextRecord->Eip, ContextRecord->Esp, ContextRecord->Ebp));
  2072. //
  2073. // execute() does not currently work when the PC is
  2074. // within the function prologue. This should only
  2075. // happen on calls from WalkX86Init, in which case the
  2076. // normal failure path here where the non-frame-data
  2077. // code will be executed is correct as that will handle
  2078. // normal prologue code.
  2079. //
  2080. X86WalkFrame WalkFrame(Process, ContextRecord,
  2081. ReadMemory, GetModuleBase,
  2082. PreviousFpoData);
  2083. Succ = DiaFrame->execute(&WalkFrame) == S_OK;
  2084. if (Succ) {
  2085. WDB((1, " Result PC %X SP %X FP %X\n",
  2086. ContextRecord->Eip, ContextRecord->Esp, ContextRecord->Ebp));
  2087. StackFrame->AddrStack.Mode = AddrModeFlat;
  2088. StackFrame->AddrStack.Offset = EXTEND64(ContextRecord->Esp);
  2089. StackFrame->AddrFrame.Mode = AddrModeFlat;
  2090. // The frame value we want to return is the frame value
  2091. // used for the function that was just unwound, not
  2092. // the current value of EBP. After the unwind the current
  2093. // value of EBP is the caller's EBP, not the callee's
  2094. // frame. Instead we always set the callee's frame to
  2095. // the offset beyond where the return address would be
  2096. // as that's where the frame will be in a normal non-FPO
  2097. // function and where we fake it as being for FPO functions.
  2098. //
  2099. // Separately, we save the true EBP away for future frame use.
  2100. // According to VinitD there's a compiler case where it
  2101. // doesn't generate proper unwind instructions for restoring
  2102. // EBP, so there are some times where EBP is not restored
  2103. // to a good value after the execute and we have to fall
  2104. // back on searching. If EBP wasn't set during the execute
  2105. // we do not save its value.
  2106. StackFrame->AddrFrame.Offset =
  2107. StackFrame->AddrStack.Offset - FRAME_SIZE;
  2108. StackFrame->AddrReturn.Offset = EXTEND64(ContextRecord->Eip);
  2109. // XXX drewb - This is causing some failures in the regression
  2110. // tests so don't enable it until we fully understand it.
  2111. #if 0
  2112. if (WalkFrame.WasEbpSet()) {
  2113. SAVE_EBP(StackFrame) = EXTEND64(ContextRecord->Ebp);
  2114. } else {
  2115. WDB((1, " * EBP not recovered\n"));
  2116. }
  2117. #else
  2118. SAVE_EBP(StackFrame) = EXTEND64(ContextRecord->Ebp);
  2119. #endif
  2120. // Caller may need to allocate this to allow alternate stackwalk with dbghelp code
  2121. StackFrame->FuncTableEntry = NULL;
  2122. X86ReadFunctionParameters(Process, StackFrame->AddrStack.Offset,
  2123. StackFrame, ReadMemory);
  2124. } else {
  2125. WDB((1, " Apply failed\n"));
  2126. }
  2127. DiaFrame->Release();
  2128. return Succ;
  2129. }
  2130. VOID
  2131. X86UpdateContextFromFrame(
  2132. HANDLE Process,
  2133. LPSTACKFRAME64 StackFrame,
  2134. PX86_CONTEXT ContextRecord,
  2135. PREAD_PROCESS_MEMORY_ROUTINE64 ReadMemory
  2136. )
  2137. {
  2138. ULONG Ebp;
  2139. ULONG Done;
  2140. if (StackFrame->AddrPC.Mode != AddrModeFlat ||
  2141. !ContextRecord) {
  2142. return;
  2143. }
  2144. ContextRecord->Esp = (ULONG)StackFrame->AddrFrame.Offset + FRAME_SIZE;
  2145. ContextRecord->Eip = (ULONG)StackFrame->AddrReturn.Offset;
  2146. if (IS_EBP_SAVED(StackFrame)) {
  2147. ContextRecord->Ebp = (ULONG)SAVE_EBP(StackFrame);
  2148. } else {
  2149. if (ReadMemory(Process, StackFrame->AddrFrame.Offset,
  2150. &Ebp, sizeof(Ebp), &Done) &&
  2151. Done == sizeof(Ebp)) {
  2152. ContextRecord->Ebp = Ebp;
  2153. }
  2154. }
  2155. if (StackFrame->FuncTableEntry) {
  2156. if (!IS_EBP_SAVED(StackFrame)) {
  2157. // Don't change Ebp
  2158. SAVE_EBP(StackFrame) = ((ULONG) StackFrame->AddrFrame.Offset + STACK_SIZE) +
  2159. 0xEB00000000; // Add this tag to top 32 bits for marking this as a frame value
  2160. // rather than FPO saved EBP
  2161. }
  2162. }
  2163. }
  2164. BOOL
  2165. WalkX86Next(
  2166. HANDLE Process,
  2167. HANDLE Thread,
  2168. LPSTACKFRAME64 StackFrame,
  2169. PX86_CONTEXT ContextRecord,
  2170. PREAD_PROCESS_MEMORY_ROUTINE64 ReadMemory,
  2171. PFUNCTION_TABLE_ACCESS_ROUTINE64 FunctionTableAccess,
  2172. PGET_MODULE_BASE_ROUTINE64 GetModuleBase,
  2173. PTRANSLATE_ADDRESS_ROUTINE64 TranslateAddress
  2174. )
  2175. {
  2176. PFPO_DATA pFpoData = NULL;
  2177. PFPO_DATA PrevFpoData = NULL;
  2178. FPO_DATA PrevFpoBuffer;
  2179. BOOL rVal = TRUE;
  2180. DWORD64 Address;
  2181. DWORD cb;
  2182. DWORD64 ThisPC;
  2183. DWORD64 ModuleBase;
  2184. DWORD64 SystemRangeStart;
  2185. WDB((1, "WalkNext: PC %X, SP %X, FP %X\n",
  2186. (ULONG)StackFrame->AddrReturn.Offset,
  2187. (ULONG)StackFrame->AddrStack.Offset,
  2188. (ULONG)StackFrame->AddrFrame.Offset));
  2189. StackFrame->AddrStack.Offset = EXTEND64(StackFrame->AddrStack.Offset);
  2190. StackFrame->AddrFrame.Offset = EXTEND64(StackFrame->AddrFrame.Offset);
  2191. // FunctionTableAccess often returns pointers to static
  2192. // data that gets overwritten on every call. Preserve
  2193. // the data of any previous FPO record for the duration
  2194. // of this routine so that FunctionTableAccess calls can
  2195. // be made without destroying previous FPO data.
  2196. if (StackFrame->FuncTableEntry) {
  2197. PrevFpoBuffer = *(PFPO_DATA)StackFrame->FuncTableEntry;
  2198. PrevFpoData = &PrevFpoBuffer;
  2199. }
  2200. if (g.AppVersion.Revision >= 6) {
  2201. SystemRangeStart = EXTEND64(SYSTEM_RANGE_START(StackFrame));
  2202. } else {
  2203. //
  2204. // This might not really work right with old debuggers, but it keeps
  2205. // us from looking off the end of the structure anyway.
  2206. //
  2207. SystemRangeStart = 0xFFFFFFFF80000000;
  2208. }
  2209. ThisPC = StackFrame->AddrPC.Offset;
  2210. //
  2211. // the previous frame's return address is this frame's pc
  2212. //
  2213. StackFrame->AddrPC = StackFrame->AddrReturn;
  2214. if (StackFrame->AddrPC.Mode != AddrModeFlat) {
  2215. //
  2216. // the call stack is from either WOW or a DOS app
  2217. //
  2218. SetNonOff32FrameAddress( Process,
  2219. Thread,
  2220. StackFrame,
  2221. ReadMemory,
  2222. FunctionTableAccess,
  2223. GetModuleBase,
  2224. TranslateAddress
  2225. );
  2226. goto exit;
  2227. }
  2228. //
  2229. // if the last frame was the usermode callback dispatcher,
  2230. // switch over to the kernel stack:
  2231. //
  2232. ModuleBase = GetModuleBase(Process, ThisPC);
  2233. if ((g.AppVersion.Revision >= 4) &&
  2234. (CALLBACK_STACK(StackFrame) != 0) &&
  2235. (pFpoData = PrevFpoData) &&
  2236. (CALLBACK_DISPATCHER(StackFrame) ==
  2237. ModuleBase + PrevFpoData->ulOffStart) ) {
  2238. NextCallback:
  2239. rVal = FALSE;
  2240. //
  2241. // find callout frame
  2242. //
  2243. if (EXTEND64(CALLBACK_STACK(StackFrame)) >= SystemRangeStart) {
  2244. //
  2245. // it is the pointer to the stack frame that we want,
  2246. // or -1.
  2247. Address = EXTEND64(CALLBACK_STACK(StackFrame));
  2248. } else {
  2249. //
  2250. // if it is below SystemRangeStart, it is the offset to
  2251. // the address in the thread.
  2252. // Look up the pointer:
  2253. //
  2254. rVal = ReadMemory(Process,
  2255. (CALLBACK_THREAD(StackFrame) +
  2256. CALLBACK_STACK(StackFrame)),
  2257. &Address,
  2258. sizeof(DWORD),
  2259. &cb);
  2260. Address = EXTEND64(Address);
  2261. if (!rVal || cb != sizeof(DWORD) || Address == 0) {
  2262. Address = 0xffffffff;
  2263. CALLBACK_STACK(StackFrame) = 0xffffffff;
  2264. }
  2265. }
  2266. if ((Address == 0xffffffff) ||
  2267. !(pFpoData = (PFPO_DATA)
  2268. FunctionTableAccess( Process, CALLBACK_FUNC(StackFrame))) ) {
  2269. rVal = FALSE;
  2270. } else {
  2271. StackFrame->FuncTableEntry = pFpoData;
  2272. StackFrame->AddrPC.Offset = CALLBACK_FUNC(StackFrame) +
  2273. pFpoData->cbProlog;
  2274. StackFrame->AddrStack.Offset = Address;
  2275. if (!ReadMemory(Process,
  2276. Address + CALLBACK_FP(StackFrame),
  2277. &StackFrame->AddrFrame.Offset,
  2278. sizeof(DWORD),
  2279. &cb) ||
  2280. cb != sizeof(DWORD)) {
  2281. return FALSE;
  2282. }
  2283. StackFrame->AddrFrame.Offset =
  2284. EXTEND64(StackFrame->AddrFrame.Offset);
  2285. if (!ReadMemory(Process,
  2286. Address + CALLBACK_NEXT(StackFrame),
  2287. &CALLBACK_STACK(StackFrame),
  2288. sizeof(DWORD),
  2289. &cb) ||
  2290. cb != sizeof(DWORD))
  2291. {
  2292. return FALSE;
  2293. }
  2294. SAVE_TRAP(StackFrame) = 0;
  2295. rVal = WalkX86Init(
  2296. Process,
  2297. Thread,
  2298. StackFrame,
  2299. ContextRecord,
  2300. ReadMemory,
  2301. FunctionTableAccess,
  2302. GetModuleBase,
  2303. TranslateAddress
  2304. );
  2305. }
  2306. return rVal;
  2307. }
  2308. //
  2309. // if there is a trap frame then handle it
  2310. //
  2311. if (SAVE_TRAP(StackFrame)) {
  2312. rVal = ProcessTrapFrame(
  2313. Process,
  2314. StackFrame,
  2315. pFpoData,
  2316. PrevFpoData,
  2317. ReadMemory,
  2318. FunctionTableAccess
  2319. );
  2320. if (!rVal) {
  2321. return rVal;
  2322. }
  2323. rVal = WalkX86Init(
  2324. Process,
  2325. Thread,
  2326. StackFrame,
  2327. ContextRecord,
  2328. ReadMemory,
  2329. FunctionTableAccess,
  2330. GetModuleBase,
  2331. TranslateAddress
  2332. );
  2333. return rVal;
  2334. }
  2335. //
  2336. // if the PC address is zero then we're at the end of the stack
  2337. //
  2338. //if (GetModuleBase(Process, StackFrame->AddrPC.Offset) == 0)
  2339. if (StackFrame->AddrPC.Offset < 65536) {
  2340. //
  2341. // if we ran out of stack, check to see if there is
  2342. // a callback stack chain
  2343. //
  2344. if (g.AppVersion.Revision >= 4 && CALLBACK_STACK(StackFrame) != 0) {
  2345. goto NextCallback;
  2346. }
  2347. return FALSE;
  2348. }
  2349. //
  2350. // If the frame, pc and return address are all identical, then we are
  2351. // at the top of the idle loop
  2352. //
  2353. if ((StackFrame->AddrPC.Offset == StackFrame->AddrReturn.Offset) &&
  2354. (StackFrame->AddrPC.Offset == StackFrame->AddrFrame.Offset))
  2355. {
  2356. return FALSE;
  2357. }
  2358. if (X86ApplyFrameData(Process, StackFrame, ContextRecord,
  2359. PrevFpoData, FALSE,
  2360. ReadMemory, GetModuleBase)) {
  2361. // copy FPO_DATA to allow alternating between dbghelp and DIA stackwalk
  2362. StackFrame->FuncTableEntry = FunctionTableAccess(Process, StackFrame->AddrPC.Offset);
  2363. return TRUE;
  2364. }
  2365. //
  2366. // check to see if the current frame is an fpo frame
  2367. //
  2368. pFpoData = (PFPO_DATA) FunctionTableAccess(Process, StackFrame->AddrPC.Offset);
  2369. if (pFpoData && pFpoData->cbFrame != FRAME_NONFPO) {
  2370. if (PrevFpoData && PrevFpoData->cbFrame != FRAME_NONFPO) {
  2371. rVal = WalkX86_Fpo_Fpo( Process,
  2372. Thread,
  2373. pFpoData,
  2374. PrevFpoData,
  2375. StackFrame,
  2376. ReadMemory,
  2377. FunctionTableAccess,
  2378. GetModuleBase,
  2379. TranslateAddress
  2380. );
  2381. } else {
  2382. rVal = WalkX86_NonFpo_Fpo( Process,
  2383. Thread,
  2384. pFpoData,
  2385. PrevFpoData,
  2386. StackFrame,
  2387. ReadMemory,
  2388. FunctionTableAccess,
  2389. GetModuleBase,
  2390. TranslateAddress
  2391. );
  2392. }
  2393. } else {
  2394. if (PrevFpoData && PrevFpoData->cbFrame != FRAME_NONFPO) {
  2395. rVal = WalkX86_Fpo_NonFpo( Process,
  2396. Thread,
  2397. pFpoData,
  2398. PrevFpoData,
  2399. StackFrame,
  2400. ContextRecord,
  2401. ReadMemory,
  2402. FunctionTableAccess,
  2403. GetModuleBase,
  2404. TranslateAddress
  2405. );
  2406. } else {
  2407. rVal = WalkX86_NonFpo_NonFpo( Process,
  2408. Thread,
  2409. pFpoData,
  2410. PrevFpoData,
  2411. StackFrame,
  2412. ReadMemory,
  2413. FunctionTableAccess,
  2414. GetModuleBase,
  2415. TranslateAddress
  2416. );
  2417. }
  2418. }
  2419. exit:
  2420. StackFrame->AddrFrame.Mode = StackFrame->AddrPC.Mode;
  2421. StackFrame->AddrReturn.Mode = StackFrame->AddrPC.Mode;
  2422. GetFunctionParameters( Process, Thread, StackFrame,
  2423. ReadMemory, GetModuleBase, TranslateAddress );
  2424. GetReturnAddress( Process, Thread, StackFrame,
  2425. ReadMemory, GetModuleBase, TranslateAddress,
  2426. FunctionTableAccess );
  2427. X86UpdateContextFromFrame(Process, StackFrame, ContextRecord, ReadMemory);
  2428. return rVal;
  2429. }
  2430. BOOL
  2431. WalkX86Init(
  2432. HANDLE Process,
  2433. HANDLE Thread,
  2434. LPSTACKFRAME64 StackFrame,
  2435. PX86_CONTEXT ContextRecord,
  2436. PREAD_PROCESS_MEMORY_ROUTINE64 ReadMemory,
  2437. PFUNCTION_TABLE_ACCESS_ROUTINE64 FunctionTableAccess,
  2438. PGET_MODULE_BASE_ROUTINE64 GetModuleBase,
  2439. PTRANSLATE_ADDRESS_ROUTINE64 TranslateAddress
  2440. )
  2441. {
  2442. UCHAR code[3];
  2443. DWORD stack[FRAME_SIZE*4];
  2444. PFPO_DATA pFpoData = NULL;
  2445. ULONG cb;
  2446. ULONG64 ModBase;
  2447. StackFrame->Virtual = TRUE;
  2448. StackFrame->Reserved[0] =
  2449. StackFrame->Reserved[1] =
  2450. StackFrame->Reserved[2] = 0;
  2451. StackFrame->AddrReturn = StackFrame->AddrPC;
  2452. if (StackFrame->AddrPC.Mode != AddrModeFlat) {
  2453. goto exit;
  2454. }
  2455. WDB((1, "WalkInit: PC %X, SP %X, FP %X\n",
  2456. (ULONG)StackFrame->AddrPC.Offset, (ULONG)StackFrame->AddrStack.Offset,
  2457. (ULONG)StackFrame->AddrFrame.Offset));
  2458. if (X86ApplyFrameData(Process, StackFrame, ContextRecord, NULL, TRUE,
  2459. ReadMemory, GetModuleBase)) {
  2460. // copy FPO_DATA to allow alternating between dbghelp and DIA stackwalk
  2461. StackFrame->FuncTableEntry = FunctionTableAccess(Process, StackFrame->AddrPC.Offset);
  2462. return TRUE;
  2463. }
  2464. StackFrame->FuncTableEntry = pFpoData = (PFPO_DATA)
  2465. FunctionTableAccess(Process, StackFrame->AddrPC.Offset);
  2466. if (pFpoData && pFpoData->cbFrame != FRAME_NONFPO) {
  2467. GetFpoFrameBase( Process,
  2468. StackFrame,
  2469. pFpoData,
  2470. pFpoData,
  2471. TRUE,
  2472. ReadMemory,
  2473. GetModuleBase );
  2474. goto exit;
  2475. } else if (!pFpoData &&
  2476. ((ModBase = GetModuleBase(Process, StackFrame->AddrPC.Offset)) == 0 ||
  2477. ModBase == MM_SHARED_USER_DATA_VA)) {
  2478. //
  2479. // We have no FPO data and the current IP isn't in
  2480. // any known module or the module is debuggers' madeup
  2481. // "shareduserdata" module. We'll assume this is a call
  2482. // to a bad address, so we expect that the return
  2483. // address should be the first DWORD on the stack.
  2484. //
  2485. if (DoMemoryReadAll( &StackFrame->AddrStack, stack, STACK_SIZE ) &&
  2486. GetModuleBase(Process, EXTEND64(stack[0]))) {
  2487. // The first DWORD is a code address. We probably
  2488. // found a call to a bad location.
  2489. SAVE_EBP(StackFrame) = StackFrame->AddrFrame.Offset;
  2490. StackFrame->AddrFrame.Offset =
  2491. StackFrame->AddrStack.Offset - STACK_SIZE;
  2492. goto exit;
  2493. }
  2494. }
  2495. //
  2496. // We couldn't figure out anything about the code at
  2497. // the current IP so we just assume it's a traditional
  2498. // EBP-framed routine.
  2499. //
  2500. // First check whether eip is in the function prolog
  2501. //
  2502. memset(code, 0xcc, sizeof(code));
  2503. if (!DoMemoryRead( &StackFrame->AddrPC, code, 3, &cb )) {
  2504. //
  2505. // Assume a call to a bad address if the memory read fails.
  2506. //
  2507. code[0] = PUSHBP;
  2508. }
  2509. if ((code[0] == PUSHBP) || (*(LPWORD)&code[0] == MOVBPSP)) {
  2510. SAVE_EBP(StackFrame) = StackFrame->AddrFrame.Offset;
  2511. StackFrame->AddrFrame.Offset = StackFrame->AddrStack.Offset;
  2512. if (StackFrame->AddrPC.Mode != AddrModeFlat) {
  2513. StackFrame->AddrFrame.Offset &= 0xffff;
  2514. }
  2515. if (code[0] == PUSHBP) {
  2516. if (StackFrame->AddrPC.Mode == AddrModeFlat) {
  2517. StackFrame->AddrFrame.Offset -= STACK_SIZE;
  2518. } else {
  2519. StackFrame->AddrFrame.Offset -= STACK_SIZE16;
  2520. }
  2521. }
  2522. } else {
  2523. //
  2524. // We're not in a prologue so assume we're in the middle
  2525. // of an EBP-framed function. Read the first dword off
  2526. // the stack at EBP and assume that it's the pushed EBP.
  2527. //
  2528. if (DoMemoryReadAll( &StackFrame->AddrFrame, stack, STACK_SIZE )) {
  2529. SAVE_EBP(StackFrame) = EXTEND64(stack[0]);
  2530. }
  2531. if (StackFrame->AddrPC.Mode != AddrModeFlat) {
  2532. StackFrame->AddrFrame.Offset &= 0x0000FFFF;
  2533. }
  2534. }
  2535. exit:
  2536. StackFrame->AddrFrame.Mode = StackFrame->AddrPC.Mode;
  2537. GetFunctionParameters( Process, Thread, StackFrame,
  2538. ReadMemory, GetModuleBase, TranslateAddress );
  2539. GetReturnAddress( Process, Thread, StackFrame,
  2540. ReadMemory, GetModuleBase, TranslateAddress,
  2541. FunctionTableAccess );
  2542. X86UpdateContextFromFrame(Process, StackFrame, ContextRecord, ReadMemory);
  2543. return TRUE;
  2544. }