mirror of
https://github.com/8damon/Blackbird-Platform
synced 2026-06-21 13:41:12 +00:00
702 lines
25 KiB
C#
702 lines
25 KiB
C#
using System;
|
|
using System.Collections.Generic;
|
|
using System.Diagnostics;
|
|
using System.Linq;
|
|
using System.Runtime.InteropServices;
|
|
using System.Runtime.Versioning;
|
|
|
|
namespace BlackbirdInterface
|
|
{
|
|
[SupportedOSPlatform("windows")]
|
|
internal static class ThreadStackResolver
|
|
{
|
|
private const uint THREAD_SUSPEND_RESUME = 0x0002;
|
|
private const uint THREAD_GET_CONTEXT = 0x0008;
|
|
private const uint THREAD_QUERY_INFORMATION = 0x0040;
|
|
private const uint PROCESS_QUERY_INFORMATION = 0x0400;
|
|
private const uint PROCESS_VM_READ = 0x0010;
|
|
|
|
private const uint CONTEXT_AMD64 = 0x00100000;
|
|
private const uint CONTEXT_CONTROL = CONTEXT_AMD64 | 0x00000001;
|
|
private const uint CONTEXT_INTEGER = CONTEXT_AMD64 | 0x00000002;
|
|
private const uint CONTEXT_FULL = CONTEXT_CONTROL | CONTEXT_INTEGER;
|
|
|
|
private const uint IMAGE_FILE_MACHINE_AMD64 = 0x8664;
|
|
private const uint AddrModeFlat = 3;
|
|
private const int MaxFrames = 192;
|
|
private const int MaxSymbolName = 1024;
|
|
|
|
private const uint SYMOPT_UNDNAME = 0x00000002;
|
|
private const uint SYMOPT_DEFERRED_LOADS = 0x00000004;
|
|
private const uint SYMOPT_LOAD_LINES = 0x00000010;
|
|
|
|
private static readonly FunctionTableAccessRoutine64 s_functionTableAccess = SymFunctionTableAccess64;
|
|
private static readonly GetModuleBaseRoutine64 s_getModuleBase = SymGetModuleBase64;
|
|
|
|
public static ThreadStackResolveResult Resolve(int pid, int tid, string state)
|
|
{
|
|
if (!Environment.Is64BitProcess)
|
|
return new ThreadStackResolveResult(new List<StackFrameRow>(), "", 0, 0, 0, null, 0, null);
|
|
|
|
if (tid == GetCurrentThreadId())
|
|
return ResolveCurrentThreadManaged(pid, tid, state);
|
|
|
|
IntPtr hProcess = IntPtr.Zero;
|
|
IntPtr hThread = IntPtr.Zero;
|
|
bool closeProcess = false;
|
|
bool threadSuspended = false;
|
|
bool symbolsReady = false;
|
|
|
|
try
|
|
{
|
|
hProcess = Kernel32Native.OpenProcess(
|
|
PROCESS_QUERY_INFORMATION | PROCESS_VM_READ,
|
|
false,
|
|
unchecked((uint)pid));
|
|
if (hProcess == IntPtr.Zero)
|
|
{
|
|
if (pid != Environment.ProcessId)
|
|
{
|
|
return new ThreadStackResolveResult(new List<StackFrameRow>(), "Process handle unavailable.", 0, 0, 0, null, 0, null);
|
|
}
|
|
|
|
hProcess = GetCurrentProcess();
|
|
}
|
|
else
|
|
closeProcess = true;
|
|
|
|
hThread = OpenThread(THREAD_QUERY_INFORMATION | THREAD_GET_CONTEXT | THREAD_SUSPEND_RESUME, false, (uint)tid);
|
|
if (hThread == IntPtr.Zero)
|
|
return new ThreadStackResolveResult(new List<StackFrameRow>(), "", 0, 0, 0, null, 0, null);
|
|
|
|
TryReadThreadMetadata(hProcess, hThread, out ulong tebAddress, out ulong stackBase, out ulong stackTop, out ushort? tebFlags);
|
|
|
|
SymSetOptions(SYMOPT_UNDNAME | SYMOPT_DEFERRED_LOADS | SYMOPT_LOAD_LINES);
|
|
symbolsReady = SymInitialize(hProcess, null, true);
|
|
|
|
if (SuspendThread(hThread) != uint.MaxValue)
|
|
threadSuspended = true;
|
|
|
|
var context = new CONTEXT64
|
|
{
|
|
ContextFlags = CONTEXT_FULL,
|
|
DUMMYUNIONNAME = new XMM_SAVE_AREA32
|
|
{
|
|
FloatRegisters = new M128A[8],
|
|
XmmRegisters = new M128A[16],
|
|
Reserved4 = new byte[96]
|
|
},
|
|
VectorRegister = new M128A[26]
|
|
};
|
|
|
|
if (!GetThreadContext(hThread, ref context))
|
|
return new ThreadStackResolveResult(new List<StackFrameRow>(), "", tebAddress, stackBase, stackTop, tebFlags, 0, null);
|
|
|
|
var moduleRanges = BuildModuleRanges(pid);
|
|
var frames = WalkFrames(hProcess, hThread, ref context, moduleRanges, symbolsReady);
|
|
return new ThreadStackResolveResult(frames, "", tebAddress, stackBase, stackTop, tebFlags, context.Rsp, BuildSnapshot(context));
|
|
}
|
|
catch
|
|
{
|
|
return new ThreadStackResolveResult(new List<StackFrameRow>(), "", 0, 0, 0, null, 0, null);
|
|
}
|
|
finally
|
|
{
|
|
if (threadSuspended)
|
|
_ = ResumeThread(hThread);
|
|
if (hThread != IntPtr.Zero)
|
|
_ = Kernel32Native.CloseHandle(hThread);
|
|
if (symbolsReady)
|
|
_ = SymCleanup(hProcess);
|
|
if (closeProcess && hProcess != IntPtr.Zero)
|
|
_ = Kernel32Native.CloseHandle(hProcess);
|
|
}
|
|
}
|
|
|
|
private static ThreadStackResolveResult ResolveCurrentThreadManaged(int pid, int tid, string state)
|
|
{
|
|
var frames = new List<StackFrameRow>();
|
|
var st = new StackTrace(true);
|
|
var stackFrames = st.GetFrames() ?? Array.Empty<StackFrame>();
|
|
int idx = 0;
|
|
|
|
foreach (var f in stackFrames)
|
|
{
|
|
var m = f.GetMethod();
|
|
string module = m?.DeclaringType?.FullName ?? "<managed>";
|
|
string symbol = m == null ? "<unknown>" : $"{m.Name}()";
|
|
string source = f.GetFileName() ?? "";
|
|
int line = f.GetFileLineNumber();
|
|
if (!string.IsNullOrWhiteSpace(source) && line > 0)
|
|
symbol += $" ({source}:{line})";
|
|
|
|
frames.Add(new StackFrameRow
|
|
{
|
|
Index = idx++,
|
|
Address = "managed",
|
|
Module = module,
|
|
Symbol = symbol
|
|
});
|
|
}
|
|
|
|
return new ThreadStackResolveResult(frames, "", 0, 0, 0, null, 0, null);
|
|
}
|
|
|
|
private static ThreadContextSnapshot BuildSnapshot(CONTEXT64 context)
|
|
{
|
|
return new ThreadContextSnapshot
|
|
{
|
|
Rip = context.Rip,
|
|
Rsp = context.Rsp,
|
|
Rbp = context.Rbp,
|
|
Rax = context.Rax,
|
|
Rbx = context.Rbx,
|
|
Rcx = context.Rcx,
|
|
Rdx = context.Rdx,
|
|
Rsi = context.Rsi,
|
|
Rdi = context.Rdi,
|
|
R8 = context.R8,
|
|
R9 = context.R9,
|
|
R10 = context.R10,
|
|
R11 = context.R11,
|
|
R12 = context.R12,
|
|
R13 = context.R13,
|
|
R14 = context.R14,
|
|
R15 = context.R15,
|
|
Dr0 = context.Dr0,
|
|
Dr1 = context.Dr1,
|
|
Dr2 = context.Dr2,
|
|
Dr3 = context.Dr3,
|
|
Dr6 = context.Dr6,
|
|
Dr7 = context.Dr7,
|
|
EFlags = context.EFlags
|
|
};
|
|
}
|
|
|
|
private static void TryReadThreadMetadata(
|
|
IntPtr hProcess,
|
|
IntPtr hThread,
|
|
out ulong tebAddress,
|
|
out ulong stackBase,
|
|
out ulong stackTop,
|
|
out ushort? tebFlags)
|
|
{
|
|
tebAddress = 0;
|
|
stackBase = 0;
|
|
stackTop = 0;
|
|
tebFlags = null;
|
|
|
|
try
|
|
{
|
|
int status = NtQueryInformationThread(
|
|
hThread,
|
|
0,
|
|
out THREAD_BASIC_INFORMATION tbi,
|
|
Marshal.SizeOf<THREAD_BASIC_INFORMATION>(),
|
|
out _);
|
|
if (status != 0 || tbi.TebBaseAddress == IntPtr.Zero)
|
|
return;
|
|
|
|
tebAddress = (ulong)tbi.TebBaseAddress.ToInt64();
|
|
|
|
int tibSize = Marshal.SizeOf<NT_TIB64>();
|
|
byte[] tibBuf = new byte[tibSize];
|
|
if (ReadProcessMemory(hProcess, tbi.TebBaseAddress, tibBuf, tibBuf.Length, out IntPtr bytesRead) &&
|
|
bytesRead.ToInt64() >= tibSize)
|
|
{
|
|
GCHandle handle = GCHandle.Alloc(tibBuf, GCHandleType.Pinned);
|
|
try
|
|
{
|
|
var tib = Marshal.PtrToStructure<NT_TIB64>(handle.AddrOfPinnedObject());
|
|
stackBase = tib.StackBase;
|
|
stackTop = tib.StackLimit;
|
|
}
|
|
finally
|
|
{
|
|
handle.Free();
|
|
}
|
|
}
|
|
|
|
// Best-effort read of SameTebFlags (x64 common offset 0x17EE).
|
|
byte[] flags = new byte[2];
|
|
nint flagsAddress = (nint)(tebAddress + 0x17EE);
|
|
if (ReadProcessMemory(hProcess, (IntPtr)flagsAddress, flags, flags.Length, out IntPtr flagsRead) &&
|
|
flagsRead.ToInt64() == 2)
|
|
{
|
|
tebFlags = BitConverter.ToUInt16(flags, 0);
|
|
}
|
|
}
|
|
catch
|
|
{
|
|
}
|
|
}
|
|
|
|
private static List<StackFrameRow> WalkFrames(IntPtr hProcess, IntPtr hThread, ref CONTEXT64 context, List<ModuleRange> modules, bool symbolsReady)
|
|
{
|
|
var rows = new List<StackFrameRow>();
|
|
|
|
var frame = new STACKFRAME64
|
|
{
|
|
AddrPC = new ADDRESS64 { Offset = context.Rip, Mode = AddrModeFlat },
|
|
AddrFrame = new ADDRESS64 { Offset = context.Rbp, Mode = AddrModeFlat },
|
|
AddrStack = new ADDRESS64 { Offset = context.Rsp, Mode = AddrModeFlat }
|
|
};
|
|
|
|
for (int i = 0; i < MaxFrames; i++)
|
|
{
|
|
bool ok = StackWalk64(
|
|
IMAGE_FILE_MACHINE_AMD64,
|
|
hProcess,
|
|
hThread,
|
|
ref frame,
|
|
ref context,
|
|
IntPtr.Zero,
|
|
s_functionTableAccess,
|
|
s_getModuleBase,
|
|
IntPtr.Zero);
|
|
|
|
if (!ok)
|
|
break;
|
|
|
|
ulong addr = frame.AddrPC.Offset;
|
|
if (addr == 0)
|
|
break;
|
|
|
|
ResolveFrame(hProcess, addr, modules, symbolsReady, out var module, out var symbol);
|
|
|
|
rows.Add(new StackFrameRow
|
|
{
|
|
Index = rows.Count,
|
|
Address = $"0x{addr:X}",
|
|
Module = module,
|
|
Symbol = symbol,
|
|
InstructionPointerRaw = addr,
|
|
FramePointerRaw = frame.AddrFrame.Offset
|
|
});
|
|
}
|
|
|
|
return rows;
|
|
}
|
|
|
|
private static void ResolveFrame(IntPtr hProcess, ulong address, List<ModuleRange> modules, bool symbolsReady, out string module, out string symbol)
|
|
{
|
|
module = ResolveModule(modules, address);
|
|
symbol = module + "+0x0";
|
|
|
|
if (!symbolsReady)
|
|
return;
|
|
|
|
if (TryResolveSymbol(hProcess, address, out var symText))
|
|
symbol = symText;
|
|
|
|
if (TryResolveLine(hProcess, address, out var fileLine))
|
|
symbol = $"{symbol} ({fileLine})";
|
|
}
|
|
|
|
private static string ResolveModule(List<ModuleRange> modules, ulong address)
|
|
{
|
|
foreach (var m in modules)
|
|
{
|
|
if (address >= m.Start && address < m.End)
|
|
return m.Name;
|
|
}
|
|
|
|
return "<unknown>";
|
|
}
|
|
|
|
private static bool TryResolveSymbol(IntPtr hProcess, ulong address, out string symbol)
|
|
{
|
|
symbol = "";
|
|
int headerSize = Marshal.SizeOf<SYMBOL_INFO>();
|
|
IntPtr mem = Marshal.AllocHGlobal(headerSize + MaxSymbolName);
|
|
try
|
|
{
|
|
var info = new SYMBOL_INFO
|
|
{
|
|
SizeOfStruct = (uint)headerSize,
|
|
MaxNameLen = MaxSymbolName,
|
|
Reserved = new ulong[2]
|
|
};
|
|
Marshal.StructureToPtr(info, mem, false);
|
|
|
|
if (!SymFromAddr(hProcess, address, out ulong displacement, mem))
|
|
return false;
|
|
|
|
int nameOffset = Marshal.OffsetOf<SYMBOL_INFO>(nameof(SYMBOL_INFO.Name)).ToInt32();
|
|
string name = Marshal.PtrToStringAnsi(IntPtr.Add(mem, nameOffset)) ?? "";
|
|
symbol = displacement > 0 ? $"{name}+0x{displacement:X}" : name;
|
|
return !string.IsNullOrWhiteSpace(name);
|
|
}
|
|
finally
|
|
{
|
|
Marshal.FreeHGlobal(mem);
|
|
}
|
|
}
|
|
|
|
private static bool TryResolveLine(IntPtr hProcess, ulong address, out string fileLine)
|
|
{
|
|
fileLine = "";
|
|
var line = new IMAGEHLP_LINE64
|
|
{
|
|
SizeOfStruct = (uint)Marshal.SizeOf<IMAGEHLP_LINE64>()
|
|
};
|
|
|
|
if (!SymGetLineFromAddr64(hProcess, address, out uint displacement, ref line))
|
|
return false;
|
|
|
|
if (line.FileName == IntPtr.Zero)
|
|
return false;
|
|
|
|
string file = Marshal.PtrToStringAnsi(line.FileName) ?? "";
|
|
if (string.IsNullOrWhiteSpace(file))
|
|
return false;
|
|
|
|
fileLine = displacement > 0
|
|
? $"{file}:{line.LineNumber}+0x{displacement:X}"
|
|
: $"{file}:{line.LineNumber}";
|
|
return true;
|
|
}
|
|
|
|
private static List<ModuleRange> BuildModuleRanges(int pid)
|
|
{
|
|
var list = new List<ModuleRange>();
|
|
try
|
|
{
|
|
using var p = Process.GetProcessById(pid);
|
|
foreach (ProcessModule m in p.Modules)
|
|
{
|
|
ulong start = (ulong)m.BaseAddress.ToInt64();
|
|
ulong end = start + (ulong)m.ModuleMemorySize;
|
|
list.Add(new ModuleRange(m.ModuleName, start, end));
|
|
}
|
|
}
|
|
catch
|
|
{
|
|
}
|
|
|
|
return list.OrderBy(x => x.Start).ToList();
|
|
}
|
|
|
|
private readonly record struct ModuleRange(string Name, ulong Start, ulong End);
|
|
|
|
[StructLayout(LayoutKind.Sequential)]
|
|
private struct ADDRESS64
|
|
{
|
|
public ulong Offset;
|
|
public ushort Segment;
|
|
public uint Mode;
|
|
}
|
|
|
|
[StructLayout(LayoutKind.Sequential)]
|
|
private struct KDHELP64
|
|
{
|
|
public ulong Thread;
|
|
public uint ThCallbackStack;
|
|
public uint ThCallbackBStore;
|
|
public uint NextCallback;
|
|
public uint FramePointer;
|
|
public ulong KiCallUserMode;
|
|
public ulong KeUserCallbackDispatcher;
|
|
public ulong SystemRangeStart;
|
|
public ulong KiUserExceptionDispatcher;
|
|
public ulong StackBase;
|
|
public ulong StackLimit;
|
|
public ulong Reserved0;
|
|
public ulong Reserved1;
|
|
public ulong Reserved2;
|
|
public ulong Reserved3;
|
|
public ulong Reserved4;
|
|
}
|
|
|
|
[StructLayout(LayoutKind.Sequential)]
|
|
private struct STACKFRAME64
|
|
{
|
|
public ADDRESS64 AddrPC;
|
|
public ADDRESS64 AddrReturn;
|
|
public ADDRESS64 AddrFrame;
|
|
public ADDRESS64 AddrStack;
|
|
public ADDRESS64 AddrBStore;
|
|
public IntPtr FuncTableEntry;
|
|
[MarshalAs(UnmanagedType.ByValArray, SizeConst = 4)]
|
|
public ulong[] Params;
|
|
public bool Far;
|
|
public bool Virtual;
|
|
[MarshalAs(UnmanagedType.ByValArray, SizeConst = 3)]
|
|
public ulong[] Reserved;
|
|
public KDHELP64 KdHelp;
|
|
}
|
|
|
|
[StructLayout(LayoutKind.Sequential)]
|
|
private struct M128A
|
|
{
|
|
public ulong High;
|
|
public long Low;
|
|
}
|
|
|
|
[StructLayout(LayoutKind.Sequential, Pack = 16)]
|
|
private struct XMM_SAVE_AREA32
|
|
{
|
|
public ushort ControlWord;
|
|
public ushort StatusWord;
|
|
public byte TagWord;
|
|
public byte Reserved1;
|
|
public ushort ErrorOpcode;
|
|
public uint ErrorOffset;
|
|
public ushort ErrorSelector;
|
|
public ushort Reserved2;
|
|
public uint DataOffset;
|
|
public ushort DataSelector;
|
|
public ushort Reserved3;
|
|
public uint MxCsr;
|
|
public uint MxCsr_Mask;
|
|
[MarshalAs(UnmanagedType.ByValArray, SizeConst = 8)]
|
|
public M128A[] FloatRegisters;
|
|
[MarshalAs(UnmanagedType.ByValArray, SizeConst = 16)]
|
|
public M128A[] XmmRegisters;
|
|
[MarshalAs(UnmanagedType.ByValArray, SizeConst = 96)]
|
|
public byte[] Reserved4;
|
|
}
|
|
|
|
[StructLayout(LayoutKind.Sequential, Pack = 16)]
|
|
private struct CONTEXT64
|
|
{
|
|
public ulong P1Home;
|
|
public ulong P2Home;
|
|
public ulong P3Home;
|
|
public ulong P4Home;
|
|
public ulong P5Home;
|
|
public ulong P6Home;
|
|
|
|
public uint ContextFlags;
|
|
public uint MxCsr;
|
|
|
|
public ushort SegCs;
|
|
public ushort SegDs;
|
|
public ushort SegEs;
|
|
public ushort SegFs;
|
|
public ushort SegGs;
|
|
public ushort SegSs;
|
|
public uint EFlags;
|
|
|
|
public ulong Dr0;
|
|
public ulong Dr1;
|
|
public ulong Dr2;
|
|
public ulong Dr3;
|
|
public ulong Dr6;
|
|
public ulong Dr7;
|
|
|
|
public ulong Rax;
|
|
public ulong Rcx;
|
|
public ulong Rdx;
|
|
public ulong Rbx;
|
|
public ulong Rsp;
|
|
public ulong Rbp;
|
|
public ulong Rsi;
|
|
public ulong Rdi;
|
|
public ulong R8;
|
|
public ulong R9;
|
|
public ulong R10;
|
|
public ulong R11;
|
|
public ulong R12;
|
|
public ulong R13;
|
|
public ulong R14;
|
|
public ulong R15;
|
|
|
|
public ulong Rip;
|
|
|
|
public XMM_SAVE_AREA32 DUMMYUNIONNAME;
|
|
|
|
[MarshalAs(UnmanagedType.ByValArray, SizeConst = 26)]
|
|
public M128A[] VectorRegister;
|
|
public ulong VectorControl;
|
|
|
|
public ulong DebugControl;
|
|
public ulong LastBranchToRip;
|
|
public ulong LastBranchFromRip;
|
|
public ulong LastExceptionToRip;
|
|
public ulong LastExceptionFromRip;
|
|
}
|
|
|
|
[StructLayout(LayoutKind.Sequential, CharSet = CharSet.Ansi)]
|
|
private struct SYMBOL_INFO
|
|
{
|
|
public uint SizeOfStruct;
|
|
public uint TypeIndex;
|
|
[MarshalAs(UnmanagedType.ByValArray, SizeConst = 2)]
|
|
public ulong[] Reserved;
|
|
public uint Index;
|
|
public uint Size;
|
|
public ulong ModBase;
|
|
public uint Flags;
|
|
public ulong Value;
|
|
public ulong Address;
|
|
public uint Register;
|
|
public uint Scope;
|
|
public uint Tag;
|
|
public uint NameLen;
|
|
public uint MaxNameLen;
|
|
public byte Name;
|
|
}
|
|
|
|
[StructLayout(LayoutKind.Sequential, CharSet = CharSet.Ansi)]
|
|
private struct IMAGEHLP_LINE64
|
|
{
|
|
public uint SizeOfStruct;
|
|
public IntPtr Key;
|
|
public uint LineNumber;
|
|
public IntPtr FileName;
|
|
public ulong Address;
|
|
}
|
|
|
|
[StructLayout(LayoutKind.Sequential)]
|
|
private struct THREAD_BASIC_INFORMATION
|
|
{
|
|
public int ExitStatus;
|
|
public IntPtr TebBaseAddress;
|
|
public IntPtr ClientIdUniqueProcess;
|
|
public IntPtr ClientIdUniqueThread;
|
|
public IntPtr AffinityMask;
|
|
public int Priority;
|
|
public int BasePriority;
|
|
}
|
|
|
|
[StructLayout(LayoutKind.Sequential)]
|
|
private struct NT_TIB64
|
|
{
|
|
public ulong ExceptionList;
|
|
public ulong StackBase;
|
|
public ulong StackLimit;
|
|
public ulong SubSystemTib;
|
|
public ulong FiberData;
|
|
public ulong ArbitraryUserPointer;
|
|
public ulong Self;
|
|
}
|
|
|
|
private delegate IntPtr FunctionTableAccessRoutine64(IntPtr hProcess, ulong AddrBase);
|
|
private delegate ulong GetModuleBaseRoutine64(IntPtr hProcess, ulong Address);
|
|
|
|
[DllImport("kernel32.dll")]
|
|
private static extern IntPtr GetCurrentProcess();
|
|
|
|
[DllImport("kernel32.dll", SetLastError = true)]
|
|
private static extern IntPtr OpenThread(uint dwDesiredAccess, bool bInheritHandle, uint dwThreadId);
|
|
|
|
[DllImport("kernel32.dll", SetLastError = true)]
|
|
private static extern uint SuspendThread(IntPtr hThread);
|
|
|
|
[DllImport("kernel32.dll", SetLastError = true)]
|
|
private static extern uint ResumeThread(IntPtr hThread);
|
|
|
|
[DllImport("kernel32.dll", SetLastError = true)]
|
|
private static extern bool GetThreadContext(IntPtr hThread, ref CONTEXT64 lpContext);
|
|
|
|
[DllImport("kernel32.dll", SetLastError = true)]
|
|
private static extern bool ReadProcessMemory(IntPtr hProcess, IntPtr baseAddress, byte[] buffer, int size, out IntPtr bytesRead);
|
|
|
|
[DllImport("kernel32.dll")]
|
|
private static extern int GetCurrentThreadId();
|
|
|
|
[DllImport("ntdll.dll")]
|
|
private static extern int NtQueryInformationThread(
|
|
IntPtr threadHandle,
|
|
int threadInformationClass,
|
|
out THREAD_BASIC_INFORMATION threadInformation,
|
|
int threadInformationLength,
|
|
out int returnLength);
|
|
|
|
[DllImport("dbghelp.dll", SetLastError = true)]
|
|
private static extern bool SymInitialize(IntPtr hProcess, string? UserSearchPath, bool fInvadeProcess);
|
|
|
|
[DllImport("dbghelp.dll", SetLastError = true)]
|
|
private static extern bool SymCleanup(IntPtr hProcess);
|
|
|
|
[DllImport("dbghelp.dll", SetLastError = true)]
|
|
private static extern uint SymSetOptions(uint SymOptions);
|
|
|
|
[DllImport("dbghelp.dll", SetLastError = true)]
|
|
private static extern IntPtr SymFunctionTableAccess64(IntPtr hProcess, ulong AddrBase);
|
|
|
|
[DllImport("dbghelp.dll", SetLastError = true)]
|
|
private static extern ulong SymGetModuleBase64(IntPtr hProcess, ulong qwAddr);
|
|
|
|
[DllImport("dbghelp.dll", SetLastError = true, CharSet = CharSet.Ansi)]
|
|
private static extern bool SymFromAddr(IntPtr hProcess, ulong Address, out ulong Displacement, IntPtr Symbol);
|
|
|
|
[DllImport("dbghelp.dll", SetLastError = true, CharSet = CharSet.Ansi)]
|
|
private static extern bool SymGetLineFromAddr64(IntPtr hProcess, ulong qwAddr, out uint pdwDisplacement, ref IMAGEHLP_LINE64 Line64);
|
|
|
|
[DllImport("dbghelp.dll", SetLastError = true)]
|
|
private static extern bool StackWalk64(
|
|
uint MachineType,
|
|
IntPtr hProcess,
|
|
IntPtr hThread,
|
|
ref STACKFRAME64 StackFrame,
|
|
ref CONTEXT64 ContextRecord,
|
|
IntPtr ReadMemoryRoutine,
|
|
FunctionTableAccessRoutine64 FunctionTableAccessRoutine,
|
|
GetModuleBaseRoutine64 GetModuleBaseRoutine,
|
|
IntPtr TranslateAddress);
|
|
}
|
|
|
|
internal sealed class ThreadStackResolveResult
|
|
{
|
|
public IReadOnlyList<StackFrameRow> Frames { get; }
|
|
public string Note { get; }
|
|
public ulong TebAddress { get; }
|
|
public ulong StackBase { get; }
|
|
public ulong StackTop { get; }
|
|
public ushort? TebFlags { get; }
|
|
public ulong StackPointer { get; }
|
|
public ThreadContextSnapshot? ContextSnapshot { get; }
|
|
|
|
public ThreadStackResolveResult(
|
|
IReadOnlyList<StackFrameRow> frames,
|
|
string note,
|
|
ulong tebAddress,
|
|
ulong stackBase,
|
|
ulong stackTop,
|
|
ushort? tebFlags,
|
|
ulong stackPointer,
|
|
ThreadContextSnapshot? contextSnapshot)
|
|
{
|
|
Frames = frames;
|
|
Note = note;
|
|
TebAddress = tebAddress;
|
|
StackBase = stackBase;
|
|
StackTop = stackTop;
|
|
TebFlags = tebFlags;
|
|
StackPointer = stackPointer;
|
|
ContextSnapshot = contextSnapshot;
|
|
}
|
|
}
|
|
|
|
public sealed class ThreadContextSnapshot
|
|
{
|
|
public ulong Rip { get; set; }
|
|
public ulong Rsp { get; set; }
|
|
public ulong Rbp { get; set; }
|
|
public ulong Rax { get; set; }
|
|
public ulong Rbx { get; set; }
|
|
public ulong Rcx { get; set; }
|
|
public ulong Rdx { get; set; }
|
|
public ulong Rsi { get; set; }
|
|
public ulong Rdi { get; set; }
|
|
public ulong R8 { get; set; }
|
|
public ulong R9 { get; set; }
|
|
public ulong R10 { get; set; }
|
|
public ulong R11 { get; set; }
|
|
public ulong R12 { get; set; }
|
|
public ulong R13 { get; set; }
|
|
public ulong R14 { get; set; }
|
|
public ulong R15 { get; set; }
|
|
public ulong Dr0 { get; set; }
|
|
public ulong Dr1 { get; set; }
|
|
public ulong Dr2 { get; set; }
|
|
public ulong Dr3 { get; set; }
|
|
public ulong Dr6 { get; set; }
|
|
public ulong Dr7 { get; set; }
|
|
public uint EFlags { get; set; }
|
|
}
|
|
}
|
|
|