mirror of
https://github.com/c3lang/c3c.git
synced 2026-02-27 12:01:16 +00:00
214 lines
14 KiB
Plaintext
214 lines
14 KiB
Plaintext
module std::os::win32 @if(env::WIN32);
|
|
import std::thread, std::os::backtrace;
|
|
|
|
const Win32_DWORD STARTF_USESTDHANDLES = 0x00000100;
|
|
const Win32_DWORD CREATE_NO_WINDOW = 0x08000000;
|
|
const Win32_DWORD CREATE_PROTECTED_PROCESS = 0x00040000;
|
|
const Win32_DWORD CREATE_UNICODE_ENVIRONMENT = 0x00000400;
|
|
const uint WAIT_OBJECT_0 = 0;
|
|
const uint WAIT_ABANDONED = 128;
|
|
const uint WAIT_IO_COMPLETION = 192;
|
|
const uint WAIT_FAILED = (uint)-1;
|
|
const Win32_DWORD HANDLE_FLAG_INHERIT = 1;
|
|
const Win32_DWORD HANDLE_FLAG_PROTECT_FROM_CLOSE = 2;
|
|
const uint INFINITE = (uint)-1;
|
|
const Win32_DWORD PIPE_ACCESS_DUPLEX = 0x00000003;
|
|
const Win32_DWORD PIPE_ACCESS_INBOUND = 0x00000001;
|
|
const Win32_DWORD PIPE_ACCESS_OUTBOUND = 0x00000002;
|
|
const Win32_DWORD FILE_FLAG_FIRST_PIPE_INSTANCE = 0x00080000;
|
|
const Win32_DWORD FILE_FLAG_WRITE_THROUGH = 0x80000000;
|
|
const Win32_DWORD FILE_FLAG_OVERLAPPED = 0x40000000;
|
|
const Win32_DWORD WRITE_DAC = 0x00040000;
|
|
const Win32_DWORD WRITE_OWNER = 0x00080000;
|
|
const Win32_DWORD ACCESS_SYSTEM_SECURITY = 0x01000000;
|
|
const Win32_DWORD PIPE_TYPE_BYTE = 0;
|
|
const Win32_DWORD PIPE_TYPE_MESSAGE = 4;
|
|
const Win32_DWORD PIPE_READMODE_BYTE = 0;
|
|
const Win32_DWORD PIPE_READMODE_MESSAGE = 2;
|
|
const Win32_DWORD PIPE_WAIT = 0;
|
|
const Win32_DWORD PIPE_NOWAIT = 1;
|
|
const Win32_DWORD PIPE_ACCEPT_REMOTE_CLIENTS = 0;
|
|
const Win32_DWORD PIPE_REJECT_REMOTE_CLIENTS = 8;
|
|
const SYMOPT_CASE_INSENSITIVE = 0x01;
|
|
const SYMOPT_UNDNAME = 0x02;
|
|
const SYMOPT_DEFERRED_LOADS = 0x04;
|
|
const SYMOPT_NO_CPP = 0x08;
|
|
const SYMOPT_LOAD_LINES = 0x10;
|
|
const SYMOPT_OMAP_FIND_NEAREST = 0x20;
|
|
const SYMOPT_LOAD_ANYTHING = 0x40;
|
|
const SYMOPT_IGNORE_CVREC = 0x80;
|
|
|
|
const IMAGE_FILE_MACHINE_UNKNOWN = 0;
|
|
const IMAGE_FILE_MACHINE_TARGET_HOST = 1;
|
|
const IMAGE_FILE_MACHINE_I386 = 0x014c;
|
|
const IMAGE_FILE_MACHINE_IA64 = 0x0200;
|
|
const IMAGE_FILE_MACHINE_ARM64 = 0xAA64;
|
|
const IMAGE_FILE_MACHINE_AMD64 = 0x8664;
|
|
const UNDNAME_COMPLETE = 0x0000;
|
|
|
|
alias Win32_INIT_ONCE_FN = fn Win32_BOOL(Win32_INIT_ONCE* initOnce, void* parameter, void** context);
|
|
|
|
extern fn void initializeCriticalSection(Win32_CRITICAL_SECTION* section) @cname("InitializeCriticalSection");
|
|
extern fn void deleteCriticalSection(Win32_CRITICAL_SECTION* section) @cname("DeleteCriticalSection");
|
|
extern fn Win32_HANDLE createMutex(void*, Win32_BOOL, void*) @cname("CreateMutexA");
|
|
extern fn Win32_BOOL releaseMutex(Win32_HANDLE) @cname("ReleaseMutex");
|
|
extern fn void enterCriticalSection(Win32_CRITICAL_SECTION* section) @cname("EnterCriticalSection");
|
|
extern fn void leaveCriticalSection(Win32_CRITICAL_SECTION* section) @cname("LeaveCriticalSection");
|
|
extern fn Win32_BOOL tryEnterCriticalSection(Win32_CRITICAL_SECTION* section) @cname("TryEnterCriticalSection");
|
|
extern fn void initializeSRWLock(Win32_SRWLOCK* lock) @cname("InitializeSRWLock");
|
|
extern fn void acquireSRWLockExclusive(Win32_SRWLOCK* lock) @cname("AcquireSRWLockExclusive");
|
|
extern fn void acquireSRWLockShared(Win32_SRWLOCK* lock) @cname("AcquireSRWLockShared");
|
|
extern fn void releaseSRWLockExclusive(Win32_SRWLOCK* lock) @cname("ReleaseSRWLockExclusive");
|
|
extern fn void releaseSRWLockShared(Win32_SRWLOCK* lock) @cname("ReleaseSRWLockShared");
|
|
extern fn Win32_BOOL tryAcquireSRWLockExclusive(Win32_SRWLOCK* lock) @cname("TryAcquireSRWLockExclusive");
|
|
extern fn Win32_BOOL tryAcquireSRWLockShared(Win32_SRWLOCK* lock) @cname("TryAcquireSRWLockShared");
|
|
extern fn void initializeConditionVariable(Win32_CONDITION_VARIABLE* conditionVariable) @cname("InitializeConditionVariable");
|
|
extern fn void wakeConditionVariable(Win32_CONDITION_VARIABLE* conditionVariable) @cname("WakeConditionVariable");
|
|
extern fn void wakeAllConditionVariable(Win32_CONDITION_VARIABLE* conditionVariable) @cname("WakeAllConditionVariable");
|
|
extern fn Win32_BOOL sleepConditionVariableCS(Win32_CONDITION_VARIABLE* conditionVariable, Win32_CRITICAL_SECTION* section, Win32_DWORD dwMilliseconds) @cname("SleepConditionVariableCS");
|
|
extern fn Win32_BOOL sleepConditionVariableSRW(Win32_CONDITION_VARIABLE* conditionVariable, Win32_SRWLOCK* lock, Win32_DWORD dwMilliseconds, Win32_ULONG flags) @cname("SleepConditionVariableSRW");
|
|
extern fn Win32_BOOL initOnceExecuteOnce(Win32_INIT_ONCE* initOnce, Win32_INIT_ONCE_FN initFn, void* parameter, void** context) @cname("InitOnceExecuteOnce");
|
|
extern fn Win32_DWORD waitForSingleObject(Win32_HANDLE hHandle, Win32_DWORD dwMilliseconds) @cname("WaitForSingleObject");
|
|
extern fn Win32_DWORD waitForSingleObjectEx(Win32_HANDLE hHandle, Win32_DWORD dwMilliseconds, Win32_BOOL bAlertable) @cname("WaitForSingleObjectEx");
|
|
extern fn Win32_DWORD waitForMultipleObjects(Win32_DWORD nCount, Win32_HANDLE* lpHandles, Win32_BOOL bWaitAll, Win32_DWORD dwMilliseconds) @cname("WaitForMultipleObjects");
|
|
extern fn Win32_DWORD waitForMultipleObjectsEx(Win32_DWORD nCount, Win32_HANDLE* lpHandles, Win32_BOOL bWaitAll, Win32_DWORD dwMilliseconds, Win32_BOOL bAlertable) @cname("WaitForMultipleObjectsEx");
|
|
extern fn void sleep(uint ms) @cname("Sleep");
|
|
extern fn Win32_BOOL resetEvent(Win32_HANDLE event) @cname("ResetEvent");
|
|
extern fn Win32_BOOL setEvent(Win32_HANDLE handle) @cname("SetEvent");
|
|
extern fn long interlockedCompareExchange(int* dest, int exchange, int comperand) @cname("InterlockedCompareExchange");
|
|
extern fn Win32_DWORD sleepEx(Win32_DWORD ms, Win32_BOOL alertable) @cname("SleepEx");
|
|
extern fn Win32_HANDLE createThread(void* attributes, usz stack, ThreadFn func, Win32_LPVOID arg, Win32_DWORD flags, Win32_LPDWORD thread_id) @cname("CreateThread");
|
|
extern fn Win32_BOOL getExitCodeThread(Win32_HANDLE handle, Win32_LPDWORD exit_code) @cname("GetExitCodeThread");
|
|
extern fn Win32_BOOL getExitCodeProcess(Win32_HANDLE hProcess, Win32_LPDWORD lpExitCode) @cname("GetExitCodeProcess");
|
|
extern fn Win32_DWORD getThreadId(Win32_HANDLE) @cname("GetThreadId");
|
|
extern fn void exitThread(Win32_DWORD dwExitCode) @noreturn @cname("ExitThread");
|
|
extern fn Win32_HANDLE getCurrentThread() @cname("GetCurrentThread");
|
|
extern fn Win32_BOOL terminateProcess(Win32_HANDLE hProcess, Win32_UINT uExitCode) @cname("TerminateProcess");
|
|
extern fn Win32_DWORD getCurrentProcessId() @cname("GetCurrentProcessId");
|
|
extern fn Win32_HANDLE getCurrentProcess() @cname("GetCurrentProcess");
|
|
extern fn Win32_DWORD getCurrentThreadId() @cname("GetCurrentThreadId");
|
|
extern fn Win32_BOOL setHandleInformation(Win32_HANDLE hObject, Win32_DWORD dwMask, Win32_DWORD dwFlags) @cname("SetHandleInformation");
|
|
extern fn Win32_HANDLE createEventA(Win32_LPSECURITY_ATTRIBUTES lpEventAttributes, Win32_BOOL bManualReset, Win32_BOOL bInitialState, Win32_LPCSTR lpName) @cname("CreateEventA");
|
|
extern fn Win32_BOOL createProcessW(Win32_LPCWSTR lpApplicationName, Win32_LPWSTR lpCommandLine, Win32_LPSECURITY_ATTRIBUTES lpProcessAttributes, Win32_LPSECURITY_ATTRIBUTES lpThreadAttributes, Win32_BOOL bInheritHandles, Win32_DWORD dwCreationFlags, Win32_LPVOID lpEnvironment, Win32_LPCWSTR lpCurrentDirectory, Win32_LPSTARTUPINFOW lpStartupInfo, Win32_LPPROCESS_INFORMATION lpProcessInformation) @cname("CreateProcessW");
|
|
extern fn Win32_HANDLE createNamedPipeA(Win32_LPCSTR lpName, Win32_DWORD dwOpenMode, Win32_DWORD dwPipeMode, Win32_DWORD nMaxInstances, Win32_DWORD nOutBufferSize, Win32_DWORD nInBufferSize, Win32_DWORD nDefaultTimeOut, Win32_LPSECURITY_ATTRIBUTES lpSecurityAttributes) @cname("CreateNamedPipeA");
|
|
extern fn Win32_BOOL getOverlappedResult(Win32_HANDLE hFile, Win32_LPOVERLAPPED lpOverlapped, Win32_LPDWORD lpNumberOfBytesTransferred, Win32_BOOL bWait) @cname("GetOverlappedResult");
|
|
extern fn Win32_DWORD getEnvironmentVariableW(Win32_LPCWSTR lpName, Win32_LPWSTR lpBuffer, Win32_DWORD nSize) @cname("GetEnvironmentVariableW");
|
|
extern fn Win32_BOOL setEnvironmentVariableW(Win32_LPCWSTR lpName, Win32_LPCWSTR lpValue) @cname("SetEnvironmentVariableW");
|
|
extern fn void getSystemInfo(Win32_LPSYSTEM_INFO lpSystemInfo) @cname("GetSystemInfo");
|
|
extern fn Win32_BOOL enumProcessModules(Win32_HANDLE hProcess, Win32_HMODULE* lphModule, Win32_DWORD cb, Win32_LPDWORD lpcbNeeded) @cname("K32EnumProcessModules");
|
|
extern fn Win32_BOOL getModuleInformation(Win32_HANDLE hProcess, Win32_HMODULE hModule, Win32_LPMODULEINFO lpmodinfo, Win32_DWORD cb) @cname("K32GetModuleInformation");
|
|
extern fn Win32_DWORD symAddrIncludeInlineTrace(Win32_HANDLE hProcess, Win32_DWORD64 address) @cname("SymAddrIncludeInlineTrace");
|
|
extern fn Win32_BOOL symQueryInlineTrace(Win32_HANDLE hProcess, Win32_DWORD64 startAddress, Win32_DWORD startContext, Win32_DWORD64 startRetAddress, Win32_DWORD64 curAddress, Win32_LPDWORD curContext, Win32_LPDWORD curFrameIndex) @cname("SymQueryInlineTrace");
|
|
extern fn Win32_BOOL symFromInlineContext(Win32_HANDLE hProcess, Win32_DWORD64 address, Win32_ULONG inlineContext, Win32_PDWORD64 displacement, Win32_PSYMBOL_INFO symbol) @cname("SymFromInlineContext");
|
|
extern fn Win32_BOOL symGetLineFromInlineContext(Win32_HANDLE hProcess, Win32_DWORD64 qwAddr, Win32_ULONG inlineContext, Win32_DWORD64 qwModuleBaseAddress, Win32_PDWORD pdwDisplacement, Win32_PIMAGEHLP_LINE64 line64) @cname("SymGetLineFromInlineContext");
|
|
extern fn Win32_ULONG rtlWalkFrameChain(Win32_PVOID*, Win32_ULONG, Win32_ULONG) @cname("RtlWalkFrameChain");
|
|
extern fn Win32_BOOL symInitialize(Win32_HANDLE hProcess, Win32_PCSTR userSearchPath, Win32_BOOL fInvadeProcess) @cname("SymInitialize");
|
|
extern fn Win32_BOOL symCleanup(Win32_HANDLE hProcess) @cname("SymCleanup");
|
|
extern fn Win32_DWORD64 symLoadModuleEx(Win32_HANDLE hProcess, Win32_HANDLE hFile, Win32_PCSTR imageName, Win32_PCSTR moduleName, Win32_DWORD64 baseOfDll, Win32_DWORD dllSize, Win32_PMODLOAD_DATA data, Win32_DWORD flags) @cname("SymLoadModule");
|
|
extern fn Win32_BOOL stackWalk64(Win32_DWORD machineType, Win32_HANDLE hProcess, Win32_HANDLE hThread, Win32_LPSTACKFRAME64 stackFrame, Win32_PVOID contextRecord, Win32_PREAD_PROCESS_MEMORY_ROUTINE64 readMemoryRoutine, Win32_PFUNCTION_TABLE_ACCESS_ROUTINE64 functionTableAccessRoutine, Win32_PGET_MODULE_BASE_ROUTINE64 getModuleBaseRoutine, Win32_PTRANSLATE_ADDRESS_ROUTINE64 translateAddress) @cname("StackWalk64");
|
|
extern fn void rtlCaptureContext(Win32_PCONTEXT contextRecord) @cname("RtlCaptureContext");
|
|
extern fn void* symFunctionTableAccess64(Win32_HANDLE hProcess, Win32_DWORD64 addrBase) @cname("SymFunctionTableAccess64");
|
|
extern fn Win32_DWORD64 symGetModuleBase64(Win32_HANDLE hProcess, Win32_DWORD64 qwAddr) @cname("SymGetModuleBase64");
|
|
extern fn Win32_DWORD getModuleBaseNameA(Win32_HANDLE hProcess, Win32_HMODULE hModule, Win32_LPSTR lpBaseName, Win32_DWORD nSize) @cname("K32GetModuleBaseNameA");
|
|
extern fn Win32_DWORD symGetOptions() @cname("SymGetOptions");
|
|
extern fn Win32_DWORD symSetOptions(Win32_DWORD symOptions) @cname("SymSetOptions");
|
|
extern fn Win32_PIMAGE_NT_HEADERS imageNtHeader(Win32_PVOID base) @cname("ImageNtHeader");
|
|
extern fn Win32_DWORD unDecorateSymbolName(Win32_PCSTR name, Win32_PSTR outputString, Win32_DWORD maxStringLength, Win32_DWORD flags) @cname("UnDecorateSymbolName");
|
|
extern fn Win32_BOOL symFromAddr(Win32_HANDLE hProcess, Win32_DWORD64 address, Win32_PDWORD64 displacement, Win32_PSYMBOL_INFO symbol) @cname("SymFromAddr");
|
|
extern fn Win32_BOOL symGetLineFromAddr64(Win32_HANDLE hProcess, Win32_DWORD64 dwAddr, Win32_PDWORD pdwDisplacement, Win32_PIMAGEHLP_LINE64 line) @cname("SymGetLineFromAddr64");
|
|
extern fn Win32_WORD rtlCaptureStackBackTrace(Win32_DWORD framesToSkip, Win32_DWORD framesToCapture, Win32_PVOID *backTrace, Win32_PDWORD backTraceHash) @cname("RtlCaptureStackBackTrace");
|
|
extern fn Win32_BOOL symGetModuleInfo64(Win32_HANDLE hProcess, Win32_DWORD64 qwAddr, Win32_PIMAGEHLP_MODULE64 moduleInfo) @cname("SymGetModuleInfo64");
|
|
|
|
fn Win32_DWORD? load_modules()
|
|
{
|
|
Win32_HANDLE process = getCurrentProcess();
|
|
Win32_DWORD needed;
|
|
symInitialize(getCurrentProcess(), null, 1);
|
|
Win32_DWORD symOptions = symGetOptions();
|
|
symOptions |= SYMOPT_LOAD_LINES | SYMOPT_UNDNAME;
|
|
symSetOptions(symOptions);
|
|
Win32_HMODULE[1024] mod_buffer;
|
|
if (!enumProcessModules(process, &mod_buffer, mod_buffer.len, &needed))
|
|
{
|
|
return backtrace::RESOLUTION_FAILED~;
|
|
}
|
|
if (needed > mod_buffer.len) return backtrace::RESOLUTION_FAILED~;
|
|
Win32_HMODULE[] modules = mod_buffer[:needed];
|
|
void* base = null;
|
|
foreach (mod : modules)
|
|
{
|
|
Win32_MODULEINFO info;
|
|
if (!getModuleInformation(process, mod, &info, $sizeof(info)))
|
|
{
|
|
return backtrace::RESOLUTION_FAILED~;
|
|
}
|
|
if (!base) base = info.lpBaseOfDll;
|
|
Win32_DWORD load_size = info.sizeOfImage;
|
|
char[1024] char_buf;
|
|
Win32_DWORD len = getModuleFileNameA(mod, (Win32_LPSTR)&char_buf, char_buf.len - 1);
|
|
if (len < 1) continue;
|
|
char[1024] module_name;
|
|
Win32_DWORD len2 = getModuleBaseNameA(process, mod, (Win32_LPSTR)&module_name, 1021);
|
|
if (len2 < 1) continue;
|
|
Win32_DWORD64 base_addr = symLoadModuleEx(process, null, (Win32_PCSTR)&char_buf, (Win32_PCSTR)&module_name, (Win32_DWORD64)info.lpBaseOfDll, load_size, null, 0);
|
|
}
|
|
if (!base) return backtrace::IMAGE_NOT_FOUND~;
|
|
Win32_IMAGE_NT_HEADERS* h = imageNtHeader(base);
|
|
return h.fileHeader.machine;
|
|
}
|
|
|
|
struct Symbol
|
|
{
|
|
inline Win32_SYMBOL_INFO sym;
|
|
char[256] buffer;
|
|
}
|
|
|
|
Win32_DWORD64 displacement;
|
|
|
|
fn BacktraceList? symbolize_backtrace(Allocator allocator, void*[] backtrace)
|
|
{
|
|
BacktraceList list;
|
|
list.init(allocator, backtrace.len);
|
|
Win32_HANDLE process = getCurrentProcess();
|
|
symInitialize(process, null, 1);
|
|
defer symCleanup(process);
|
|
foreach (addr : backtrace)
|
|
{
|
|
list.push(resolve_backtrace(allocator, addr, process) ?? backtrace::BACKTRACE_UNKNOWN);
|
|
}
|
|
return list;
|
|
}
|
|
|
|
fn Backtrace? resolve_backtrace(Allocator allocator, void* addr, Win32_HANDLE process)
|
|
{
|
|
Symbol symbol;
|
|
//Win32_DWORD image_type = load_modules()!;
|
|
symbol.sizeOfStruct = Win32_SYMBOL_INFO.sizeof;
|
|
symbol.maxNameLen = 255;
|
|
if (!symFromAddr(process, (Win32_DWORD64)addr - 1, &displacement, &symbol))
|
|
{
|
|
return backtrace::NO_BACKTRACE_SYMBOLS~;
|
|
}
|
|
Win32_IMAGEHLP_MODULE64 module_info;
|
|
module_info.sizeOfStruct = Win32_IMAGEHLP_MODULE64.sizeof;
|
|
if (!symGetModuleInfo64(process, (Win32_DWORD64)addr - 1, &module_info))
|
|
{
|
|
return backtrace::NO_BACKTRACE_SYMBOLS~;
|
|
}
|
|
ZString module_name = (ZString)&module_info.imageName;
|
|
char[256] name;
|
|
unDecorateSymbolName(&symbol.name, (Win32_PSTR)&name, 256, UNDNAME_COMPLETE);
|
|
Win32_DWORD offset = 0;
|
|
Win32_IMAGEHLP_LINE64 line;
|
|
Backtrace backtrace;
|
|
ZString zname = (ZString)&name;
|
|
if (!symGetLineFromAddr64(process, (Win32_ULONG64)addr - 1, &offset, &line))
|
|
{
|
|
backtrace.init(allocator, (uptr)addr, zname.str_view(), module_name.str_view());
|
|
return backtrace;
|
|
}
|
|
String filename = ((ZString)line.fileName).str_view();
|
|
backtrace.init(allocator, (uptr)addr, zname.str_view(), module_name.str_view(), file: filename, line: line.lineNumber);
|
|
return backtrace;
|
|
}
|