private static extern bool StackWalkEx( ImageFileMachine MachineType, IntPtr hProcess, IntPtr hThread, ref STACKFRAME_EX StackFrame, IntPtr ContextRecord, ReadProcessMemoryProc64 ReadMemoryRoutine, FunctionTableAccessProc64 FunctionTableAccessRoutine, GetModuleBaseProc64 GetModuleBaseRoutine, TranslateAddressProc64 TranslateAddress, uint Flags);
private static extern IntPtr SymFunctionTableAccess64AccessRoutines( IntPtr hProcess, ulong AddrBase, ReadProcessMemoryProc64 ReadMemoryRoutine, GetModuleBaseProc64 GetModuleBaseRoutine);
/// <summary> /// Walks the call stack for the thread. /// </summary> /// <param name="parentProcess">A handle to the thread's parent process.</param> /// <param name="walkStackCallback">A callback to execute.</param> /// <param name="architecture"> /// The type of stack walk. On 32-bit systems, this value is ignored. /// On 64-bit systems, this value can be set to I386 to walk the /// 32-bit stack. /// </param> public unsafe void WalkStack(ProcessHandle parentProcess, WalkStackDelegate walkStackCallback, OSArch architecture) { bool suspended = false; // Suspend the thread to avoid inaccurate thread stacks. try { this.Suspend(); suspended = true; } catch (WindowsException) { suspended = false; } // Use KPH for reading memory if we can. ReadProcessMemoryProc64 readMemoryProc = null; if (KProcessHacker.Instance != null) { readMemoryProc = new ReadProcessMemoryProc64( delegate(IntPtr processHandle, ulong baseAddress, IntPtr buffer, int size, out int bytesRead) { return(KProcessHacker.Instance.KphReadVirtualMemorySafe( ProcessHandle.FromHandle(processHandle), (int)baseAddress, buffer, size, out bytesRead).IsSuccess()); }); } try { // x86/WOW64 stack walk. if (OSVersion.Architecture == OSArch.I386 || (OSVersion.Architecture == OSArch.Amd64 && architecture == OSArch.I386)) { Context context = new Context(); context.ContextFlags = ContextFlags.All; if (OSVersion.Architecture == OSArch.I386) { // Get the context. this.GetContext(ref context); } else { // Get the WOW64 x86 context. this.GetContextWow64(ref context); } // Set up the initial stack frame structure. var stackFrame = new StackFrame64(); stackFrame.AddrPC.Mode = AddressMode.AddrModeFlat; stackFrame.AddrPC.Offset = (ulong)context.Eip; stackFrame.AddrStack.Mode = AddressMode.AddrModeFlat; stackFrame.AddrStack.Offset = (ulong)context.Esp; stackFrame.AddrFrame.Mode = AddressMode.AddrModeFlat; stackFrame.AddrFrame.Offset = (ulong)context.Ebp; while (true) { using (Win32.DbgHelpLock.AcquireContext()) { if (!Win32.StackWalk64( MachineType.I386, parentProcess, this, ref stackFrame, ref context, readMemoryProc, Win32.SymFunctionTableAccess64, Win32.SymGetModuleBase64, IntPtr.Zero )) { break; } } // If we got an invalid eip, break. if (stackFrame.AddrPC.Offset == 0) { break; } // Execute the callback. if (!walkStackCallback(new ThreadStackFrame(ref stackFrame))) { break; } } } // x64 stack walk. else if (OSVersion.Architecture == OSArch.Amd64) { ContextAmd64 context = new ContextAmd64(); context.ContextFlags = ContextFlagsAmd64.All; // Get the context. this.GetContext(ref context); // Set up the initial stack frame structure. var stackFrame = new StackFrame64(); stackFrame.AddrPC.Mode = AddressMode.AddrModeFlat; stackFrame.AddrPC.Offset = (ulong)context.Rip; stackFrame.AddrStack.Mode = AddressMode.AddrModeFlat; stackFrame.AddrStack.Offset = (ulong)context.Rsp; stackFrame.AddrFrame.Mode = AddressMode.AddrModeFlat; stackFrame.AddrFrame.Offset = (ulong)context.Rbp; while (true) { using (Win32.DbgHelpLock.AcquireContext()) { if (!Win32.StackWalk64( MachineType.Amd64, parentProcess, this, ref stackFrame, ref context, readMemoryProc, Win32.SymFunctionTableAccess64, Win32.SymGetModuleBase64, IntPtr.Zero )) { break; } } // If we got an invalid rip, break. if (stackFrame.AddrPC.Offset == 0) { break; } // Execute the callback. if (!walkStackCallback(new ThreadStackFrame(ref stackFrame))) { break; } } } } finally { // If we suspended the thread before, resume it. if (suspended) { try { this.Resume(); } catch (WindowsException) { } } } }