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.

2706 lines
79 KiB

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