Use backtrace on windows. Updated backtrace API

This commit is contained in:
Christoffer Lerno
2023-11-13 23:30:00 +01:00
committed by Christoffer Lerno
parent 587d5578ab
commit 81c93e3488
15 changed files with 641 additions and 103 deletions

View File

@@ -41,6 +41,7 @@ jobs:
..\build\${{ matrix.build_type }}\c3c.exe compile-run examples\load_world.c3
..\build\${{ matrix.build_type }}\c3c.exe compile-run examples\process.c3
..\build\${{ matrix.build_type }}\c3c.exe compile --test -g -O0 --threads 1 --target macos-x64 examples\constants.c3
..\build\${{ matrix.build_type }}\c3c.exe compile-run msvc_stack.c3
- name: Build testproject
run: |

View File

@@ -91,7 +91,10 @@ fn bool print_backtrace(String message, int backtraces_to_ignore) @if(env::NATIV
{
@pool()
{
BacktraceList! backtrace = backtrace::backtrace_load(mem::temp());
void*[256] buffer;
void*[] backtraces = backtrace::capture_current(&buffer);
backtraces_to_ignore++;
BacktraceList! backtrace = backtrace::symbolize_backtrace(backtraces, mem::temp());
if (catch backtrace) return false;
if (backtrace.len() <= backtraces_to_ignore) return false;
io::eprint("\nERROR: '");

View File

@@ -132,7 +132,7 @@ const MemoryEnvironment MEMORY_ENV = (MemoryEnvironment)$$MEMORY_ENVIRONMENT;
const bool TRACK_MEMORY = DEBUG_SYMBOLS && (COMPILER_SAFE_MODE || TESTING);
const bool X86_64 = ARCH_TYPE == X86_64;
const bool AARCH64 = ARCH_TYPE == AARCH64;
const bool NATIVE_STACKTRACE = LINUX || DARWIN;
const bool NATIVE_STACKTRACE = LINUX || DARWIN || WIN32;
const bool LINUX = LIBC && OS_TYPE == LINUX;
const bool DARWIN = LIBC && os_is_darwin();
const bool WIN32 = LIBC && OS_TYPE == WIN32;

View File

@@ -1,4 +1,5 @@
module std::os::backtrace;
import std::collections::list;
fault BacktraceFault
{
@@ -6,6 +7,7 @@ fault BacktraceFault
EXECUTABLE_PATH_NOT_FOUND,
IMAGE_NOT_FOUND,
NO_BACKTRACE_SYMBOLS,
RESOLUTION_FAILED,
}
const Backtrace BACKTRACE_UNKNOWN = { 0, "", "", "", 0, null };
@@ -20,6 +22,7 @@ struct Backtrace (Printable)
Allocator* allocator;
}
fn bool Backtrace.has_file(&self)
{
return self.file.len > 0;
@@ -50,12 +53,9 @@ fn void Backtrace.free(&self)
self.allocator.free(self.file);
}
def backtrace_load = darwin::backtrace_load @if(env::DARWIN);
def backtrace_load = linux::backtrace_load @if(env::LINUX);
fn Backtrace* Backtrace.init(&self, uptr offset, String function, String object_file, String file = "", uint line = 0, Allocator* using = mem::heap())
fn Backtrace* Backtrace.init(&self, uptr offset, String function, String object_file, String file = "", uint line = 0, Allocator* allocator)
{
if (!using)
if (!allocator)
{
self.offset = offset;
self.function = function;
@@ -66,11 +66,31 @@ fn Backtrace* Backtrace.init(&self, uptr offset, String function, String object_
return self;
}
self.offset = offset;
self.function = function.copy(using);
self.object_file = object_file.copy(using);
self.file = file.copy(using);
self.allocator = using;
self.function = function.copy(allocator);
self.object_file = object_file.copy(allocator);
self.file = file.copy(allocator);
self.allocator = allocator;
self.line = line;
return self;
}
fn void*[] capture_current(void*[] buffer) @if(env::POSIX || env::WIN32)
{
if (!buffer.len) return buffer[:0];
$switch
$case env::POSIX:
CInt len = posix::backtrace(buffer.ptr, buffer.len);
return buffer[:len];
$case env::WIN32:
Win32_WORD len = win32::rtlCaptureStackBackTrace(0, buffer.len, buffer.ptr, null);
return buffer[:len];
$default:
return buffer[:0];
$endswitch
}
def BacktraceList = List(<Backtrace>);
def symbolize_backtrace = linux::symbolize_backtrace @if(env::LINUX);
def symbolize_backtrace = win32::symbolize_backtrace @if(env::WIN32);
def symbolize_backtrace = darwin::symbolize_backtrace @if(env::DARWIN);

View File

@@ -28,7 +28,7 @@ import std::os::win32;
fn uint num_cpu()
{
SystemInfo info;
win32::get_system_info(&info);
Win32_SYSTEM_INFO info;
win32::getSystemInfo(&info);
return info.dwNumberOfProcessors;
}

View File

@@ -6,8 +6,6 @@ import std::collections::list;
extern fn isz readlink(ZString path, char* buf, usz bufsize);
def BacktraceList = List(<Backtrace>);
const PT_PHDR = 6;
const EI_NIDENT = 16;
def Elf32_Half = ushort;
@@ -153,7 +151,8 @@ fn Backtrace! backtrace_load_element(void* addr, Allocator* allocator = mem::hea
.object_file = info.dli_fname.copy(allocator),
.offset = (uptr)addr,
.file = "".copy(allocator),
.line = 0
.line = 0,
.allocator = allocator
};
}
uint line = 0;
@@ -174,13 +173,10 @@ fn Backtrace! backtrace_load_element(void* addr, Allocator* allocator = mem::hea
};
}
fn BacktraceList! backtrace_load(Allocator* allocator)
fn BacktraceList! symbolize_backtrace(void*[] backtrace, Allocator* allocator)
{
void*[256] bt_buffer;
CInt size = posix::backtrace(&bt_buffer, 256);
io::printfn("Backtrace list %s", size);
BacktraceList list;
list.init_new(size, allocator);
list.init_new(backtrace.len, allocator);
defer catch
{
foreach (trace : list)
@@ -191,9 +187,9 @@ fn BacktraceList! backtrace_load(Allocator* allocator)
}
@pool(allocator)
{
for (usz i = 0; i < size; i++)
foreach (addr : backtrace)
{
Backtrace trace = backtrace_load_element(bt_buffer[i], allocator)!;
Backtrace trace = backtrace_load_element(addr, allocator)!;
list.append(trace);
}
};

View File

@@ -76,8 +76,6 @@ fn String! executable_path(Allocator *allocator)
return ((ZString)&path).copy(allocator);
}
def BacktraceList = List(<Backtrace>);
fn uptr! load_address() @local
{
Darwin_segment_command_64* cmd = darwin::getsegbyname("__TEXT");
@@ -128,18 +126,17 @@ fn Backtrace! backtrace_load_element(String execpath, void* buffer, void* load_a
.function = info.dli_sname ? info.dli_sname.copy(allocator) : "???".copy(allocator),
.object_file = info.dli_fname.copy(allocator),
.file = "".copy(allocator),
.line = 0
.line = 0,
.allocator = allocator
};
};
}
fn BacktraceList! backtrace_load(Allocator* allocator)
fn BacktraceList! symbolize_backtrace(void*[] backtrace, Allocator* allocator)
{
void*[256] bt_buffer;
CInt size = posix::backtrace(&bt_buffer, 256);
void *load_addr = (void *)load_address()!;
BacktraceList list;
list.init_new(size, allocator);
list.init_new(backtrace.len, allocator);
defer catch
{
foreach (trace : list)
@@ -151,11 +148,9 @@ fn BacktraceList! backtrace_load(Allocator* allocator)
@pool(allocator)
{
String execpath = executable_path(mem::temp())!;
for (usz i = 1; i < size; i++)
foreach (addr : backtrace)
{
void* buffer = bt_buffer[i];
Backtrace trace = backtrace_load_element(execpath, buffer, load_addr, allocator)!;
list.append(trace);
list.append(backtrace_load_element(execpath, addr, load_addr, allocator) ?? backtrace::BACKTRACE_UNKNOWN);
}
};
return list;

View File

@@ -28,7 +28,22 @@ 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;
extern fn void initializeCriticalSection(Win32_CRITICAL_SECTION* section) @extern("InitializeCriticalSection");
extern fn void deleteCriticalSection(Win32_CRITICAL_SECTION* section) @extern("DeleteCriticalSection");
@@ -47,70 +62,136 @@ extern fn Win32_DWORD sleepEx(Win32_DWORD ms, Win32_BOOL alertable) @extern("Sle
extern fn Win32_HANDLE createThread(void* attributes, usz stack, ThreadFn func, void* arg, uint flags, uint* thread_id) @extern("CreateThread");
extern fn Win32_BOOL getExitCodeThread(Win32_HANDLE handle, uint* exit_code) @extern("GetExitCodeThread");
extern fn Win32_BOOL getExitCodeProcess(Win32_HANDLE hProcess, Win32_LPDWORD lpExitCode) @extern("GetExitCodeProcess");
extern fn uint getThreadId(Win32_HANDLE) @extern("GetThreadId");
extern fn void exitThread(uint res) @noreturn @extern("ExitThread");
extern fn Win32_DWORD getThreadId(Win32_HANDLE) @extern("GetThreadId");
extern fn void exitThread(Win32_DWORD dwExitCode) @noreturn @extern("ExitThread");
extern fn Win32_HANDLE getCurrentThread() @extern("GetCurrentThread");
extern fn Win32_BOOL terminateProcess(Win32_HANDLE hProcess, Win32_UINT uExitCode) @extern("TerminateProcess");
extern fn Win32_DWORD getCurrentProcessId() @extern("GetCurrentProcessId");
extern fn Win32_HANDLE getCurrentProcess() @extern("GetCurrentProcess");
extern fn Win32_DWORD getCurrentThreadId() @extern("GetCurrentThreadId");
extern fn Win32_BOOL setHandleInformation(Win32_HANDLE hObject, Win32_DWORD dwMask, Win32_DWORD dwFlags) @extern("SetHandleInformation");
extern fn Win32_HANDLE createEventA(
Win32_LPSECURITY_ATTRIBUTES lpEventAttributes,
Win32_BOOL bManualReset,
Win32_BOOL bInitialState,
Win32_LPCSTR lpName
) @extern("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
) @extern("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
) @extern("CreateNamedPipeA");
extern fn Win32_BOOL getOverlappedResult(
Win32_HANDLE hFile,
Win32_LPOVERLAPPED lpOverlapped,
Win32_LPDWORD lpNumberOfBytesTransferred,
Win32_BOOL bWait
) @extern("GetOverlappedResult");
extern fn Win32_DWORD getEnvironmentVariableW(
Win32_LPCWSTR lpName,
Win32_LPWSTR lpBuffer,
Win32_DWORD nSize
) @extern("GetEnvironmentVariableW");
extern fn Win32_BOOL setEnvironmentVariableW(
Win32_LPCWSTR lpName,
Win32_LPCWSTR lpValue
) @extern("SetEnvironmentVariableW");
extern fn Win32_HANDLE createEventA(Win32_LPSECURITY_ATTRIBUTES lpEventAttributes, Win32_BOOL bManualReset, Win32_BOOL bInitialState, Win32_LPCSTR lpName) @extern("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) @extern("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) @extern("CreateNamedPipeA");
extern fn Win32_BOOL getOverlappedResult(Win32_HANDLE hFile, Win32_LPOVERLAPPED lpOverlapped, Win32_LPDWORD lpNumberOfBytesTransferred, Win32_BOOL bWait) @extern("GetOverlappedResult");
extern fn Win32_DWORD getEnvironmentVariableW(Win32_LPCWSTR lpName, Win32_LPWSTR lpBuffer, Win32_DWORD nSize) @extern("GetEnvironmentVariableW");
extern fn Win32_BOOL setEnvironmentVariableW(Win32_LPCWSTR lpName, Win32_LPCWSTR lpValue) @extern("SetEnvironmentVariableW");
extern fn void getSystemInfo(Win32_LPSYSTEM_INFO lpSystemInfo) @extern("GetSystemInfo");
extern fn Win32_BOOL enumProcessModules(Win32_HANDLE hProcess, Win32_HMODULE* lphModule, Win32_DWORD cb, Win32_LPDWORD lpcbNeeded) @extern("K32EnumProcessModules");
extern fn Win32_BOOL getModuleInformation(Win32_HANDLE hProcess, Win32_HMODULE hModule, Win32_LPMODULEINFO lpmodinfo, Win32_DWORD cb) @extern("K32GetModuleInformation");
extern fn Win32_DWORD symAddrIncludeInlineTrace(Win32_HANDLE hProcess, Win32_DWORD64 address) @extern("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) @extern("SymQueryInlineTrace");
extern fn Win32_BOOL symFromInlineContext(Win32_HANDLE hProcess, Win32_DWORD64 address, Win32_ULONG inlineContext, Win32_PDWORD64 displacement, Win32_PSYMBOL_INFO symbol) @extern("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) @extern("SymGetLineFromInlineContext");
extern fn Win32_ULONG rtlWalkFrameChain(Win32_PVOID*, Win32_ULONG, Win32_ULONG) @extern("RtlWalkFrameChain");
extern fn Win32_BOOL symInitialize(Win32_HANDLE hProcess, Win32_PCSTR userSearchPath, Win32_BOOL fInvadeProcess) @extern("SymInitialize");
extern fn Win32_BOOL symCleanup(Win32_HANDLE hProcess) @extern("SymCleanup");
extern fn Win32_DWORD getModuleFileNameA(Win32_HMODULE hModule, Win32_LPSTR lpFilename, Win32_DWORD nSize) @extern("GetModuleFileNameA");
extern fn Win32_DWORD getModuleFileNameExA(Win32_HANDLE hProcess, Win32_HMODULE hModule, Win32_LPSTR lpFilename, Win32_DWORD nSize) @extern("GetModuleFileNameExA");
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) @extern("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) @extern("StackWalk64");
extern fn void rtlCaptureContext(Win32_PCONTEXT contextRecord) @extern("RtlCaptureContext");
extern fn void* symFunctionTableAccess64(Win32_HANDLE hProcess, Win32_DWORD64 addrBase) @extern("SymFunctionTableAccess64");
extern fn Win32_DWORD64 symGetModuleBase64(Win32_HANDLE hProcess, Win32_DWORD64 qwAddr) @extern("SymGetModuleBase64");
extern fn Win32_DWORD getModuleBaseNameA(Win32_HANDLE hProcess, Win32_HMODULE hModule, Win32_LPSTR lpBaseName, Win32_DWORD nSize) @extern("K32GetModuleBaseNameA");
extern fn Win32_DWORD symGetOptions() @extern("SymGetOptions");
extern fn Win32_DWORD symSetOptions(Win32_DWORD symOptions) @extern("SymSetOptions");
extern fn Win32_PIMAGE_NT_HEADERS imageNtHeader(Win32_PVOID base) @extern("ImageNtHeader");
extern fn Win32_DWORD unDecorateSymbolName(Win32_PCSTR name, Win32_PSTR outputString, Win32_DWORD maxStringLength, Win32_DWORD flags) @extern("UnDecorateSymbolName");
extern fn Win32_BOOL symFromAddr(Win32_HANDLE hProcess, Win32_DWORD64 address, Win32_PDWORD64 displacement, Win32_PSYMBOL_INFO symbol) @extern("SymFromAddr");
extern fn Win32_BOOL symGetLineFromAddr64(Win32_HANDLE hProcess, Win32_DWORD64 dwAddr, Win32_PDWORD pdwDisplacement, Win32_PIMAGEHLP_LINE64 line) @extern("SymGetLineFromAddr64");
extern fn Win32_WORD rtlCaptureStackBackTrace(Win32_DWORD framesToSkip, Win32_DWORD framesToCapture, Win32_PVOID *backTrace, Win32_PDWORD backTraceHash) @extern("RtlCaptureStackBackTrace");
extern fn Win32_BOOL symGetModuleInfo64(Win32_HANDLE hProcess, Win32_DWORD64 qwAddr, Win32_PIMAGEHLP_MODULE64 moduleInfo) @extern("SymGetModuleInfo64");
struct SystemInfo
fn Win32_DWORD! load_modules()
{
union {
uint dwOemId;
struct {
ushort wProcessorArchitecture;
ushort wReserved;
}
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 BacktraceFault.RESOLUTION_FAILED?;
}
uint dwPageSize;
void* lpMinimumApplicationAddress;
void* lpMaximumApplicationAddress;
usz dwActiveProcessorMask;
uint dwNumberOfProcessors;
uint dwProcessorType;
uint dwAllocationGranularity;
ushort wProcessorLevel;
ushort wProcessorRevision;
if (needed > mod_buffer.len) return BacktraceFault.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 BacktraceFault.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 BacktraceFault.IMAGE_NOT_FOUND?;
Win32_IMAGE_NT_HEADERS* h = imageNtHeader(base);
return h.fileHeader.machine;
}
extern fn CInt get_system_info(SystemInfo*) @extern("GetSystemInfo");
struct Symbol
{
inline Win32_SYMBOL_INFO sym;
char[256] buffer;
}
Win32_DWORD64 displacement;
fn BacktraceList! symbolize_backtrace(void*[] backtrace, Allocator* allocator)
{
BacktraceList list;
list.init_new(backtrace.len, allocator);
Win32_HANDLE process = getCurrentProcess();
symInitialize(process, null, 1);
defer symCleanup(process);
foreach (addr : backtrace)
{
list.append(resolve_backtrace(addr, process, allocator) ?? backtrace::BACKTRACE_UNKNOWN);
}
return list;
}
fn Backtrace! resolve_backtrace(void* addr, Win32_HANDLE process, Allocator* allocator)
{
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 BacktraceFault.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 BacktraceFault.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((uptr)addr, .function = zname.str_view(), .object_file = module_name.str_view(), .allocator = allocator);
return backtrace;
}
String filename = ((ZString)line.fileName).str_view();
backtrace.init((uptr)addr, .function = zname.str_view(), .object_file = module_name.str_view(), .file = filename, .line = line.lineNumber, .allocator = allocator);
return backtrace;
}

View File

@@ -266,3 +266,431 @@ struct Win32_PROCESS_INFORMATION
def Win32_PPROCESS_INFORMATION = Win32_PROCESS_INFORMATION*;
def Win32_LPPROCESS_INFORMATION = Win32_PROCESS_INFORMATION*;
struct Win32_SYSTEM_INFO
{
union
{
Win32_DWORD dwOemId;
struct
{
Win32_WORD wProcessorArchitecture;
Win32_WORD wReserved;
}
}
Win32_DWORD dwPageSize;
Win32_LPVOID lpMinimumApplicationAddress;
Win32_LPVOID lpMaximumApplicationAddress;
Win32_DWORD_PTR dwActiveProcessorMask;
Win32_DWORD dwNumberOfProcessors;
Win32_DWORD dwProcessorType;
Win32_DWORD dwAllocationGranularity;
Win32_WORD wProcessorLevel;
Win32_WORD wProcessorRevision;
}
def Win32_LPSYSTEM_INFO = Win32_SYSTEM_INFO*;
struct Win32_MODULEINFO
{
Win32_LPVOID lpBaseOfDll;
Win32_DWORD sizeOfImage;
Win32_LPVOID entryPoint;
}
struct Win32_IMAGEHLP_LINE64
{
Win32_DWORD sizeOfStruct;
Win32_PVOID key;
Win32_DWORD lineNumber;
Win32_PCHAR fileName;
Win32_DWORD64 address;
}
enum Win32_SYM_TYPE
{
SYM_NONE,
SYM_COFF,
SYM_CV,
SYM_PDB,
SYM_EXPORT,
SYM_DEFERRED,
SYM_SYM,
SYM_DIA,
SYM_VIRTUAL
}
struct Win32_GUID
{
CULong data1;
CUShort data2;
CUShort data3;
char[8] data4;
}
struct Win32_IMAGEHLP_MODULE64
{
Win32_DWORD sizeOfStruct;
Win32_DWORD64 baseOfImage;
Win32_DWORD imageSize;
Win32_DWORD timeDateStamp;
Win32_DWORD checkSum;
Win32_DWORD numSyms;
Win32_SYM_TYPE symType;
Win32_CHAR[32] moduleName;
Win32_CHAR[256] imageName;
Win32_CHAR[256] loadedImageName;
Win32_CHAR[256] loadedPdbName;
Win32_DWORD cVSig;
Win32_CHAR** cVData;
Win32_DWORD pdbSig;
Win32_GUID pdbSig70;
Win32_DWORD pdbAge;
Win32_BOOL pdbUnmatched;
Win32_BOOL dbgUnmatched;
Win32_BOOL lineNumbers;
Win32_BOOL globalSymbols;
Win32_BOOL typeInfo;
Win32_BOOL sourceIndexed;
Win32_BOOL publics;
Win32_DWORD machineType;
Win32_DWORD reserved;
}
def Win32_PIMAGEHLP_MODULE64 = Win32_IMAGEHLP_MODULE64*;
struct Win32_ARM64_NT_CONTEXT @align(16)
{
Win32_DWORD contextFlags;
Win32_DWORD cpsr;
union
{
struct
{
Win32_DWORD64 x0;
Win32_DWORD64 x1;
Win32_DWORD64 x2;
Win32_DWORD64 x3;
Win32_DWORD64 x4;
Win32_DWORD64 x5;
Win32_DWORD64 x6;
Win32_DWORD64 x7;
Win32_DWORD64 x8;
Win32_DWORD64 x9;
Win32_DWORD64 x10;
Win32_DWORD64 x11;
Win32_DWORD64 x12;
Win32_DWORD64 x13;
Win32_DWORD64 x14;
Win32_DWORD64 x15;
Win32_DWORD64 x16;
Win32_DWORD64 x17;
Win32_DWORD64 x18;
Win32_DWORD64 x19;
Win32_DWORD64 x20;
Win32_DWORD64 x21;
Win32_DWORD64 x22;
Win32_DWORD64 x23;
Win32_DWORD64 x24;
Win32_DWORD64 x25;
Win32_DWORD64 x26;
Win32_DWORD64 x27;
Win32_DWORD64 x28;
Win32_DWORD64 fp;
Win32_DWORD64 lr;
}
Win32_DWORD64[31] x;
}
Win32_DWORD64 sp;
Win32_DWORD64 pc;
Win32_ARM64_NT_NEON128[32] v;
Win32_DWORD fpcr;
Win32_DWORD fpsr;
Win32_DWORD[ARM64_MAX_BREAKPOINTS] bcr;
Win32_DWORD64[ARM64_MAX_BREAKPOINTS] bvr;
Win32_DWORD[ARM64_MAX_WATCHPOINTS] wcr;
Win32_DWORD64[ARM64_MAX_WATCHPOINTS] wvr;
}
const ARM64_MAX_BREAKPOINTS = 8;
const ARM64_MAX_WATCHPOINTS = 2;
struct Win32_ARM64_NT_NEON128
{
Win32_ULONGLONG low;
Win32_LONGLONG high;
}
struct Win32_XMM_SAVE_AREA32
{
Win32_USHORT controlWord;
Win32_USHORT statusWord;
Win32_UCHAR tagWord;
Win32_UCHAR reserved1;
Win32_USHORT errorOpcode;
Win32_ULONG errrorOffset;
Win32_USHORT errorSelector;
Win32_USHORT reserved2;
Win32_ULONG dataOffset;
Win32_USHORT dataSelector;
Win32_USHORT reserved3;
Win32_ULONG mxCsr;
Win32_ULONG mxCsr_Mask;
Win32_M128A[8] floatRegisters;
Win32_M128A[16] xmmRegisters;
Win32_UCHAR[96] reserved4;
}
struct Win32_AMD64_CONTEXT @align(16)
{
Win32_DWORD64 p1Home;
Win32_DWORD64 p2Home;
Win32_DWORD64 p3Home;
Win32_DWORD64 p4Home;
Win32_DWORD64 p5Home;
Win32_DWORD64 p6Home;
Win32_DWORD contextFlags;
Win32_DWORD mxCsr;
Win32_WORD segCs;
Win32_WORD segDs;
Win32_WORD segEs;
Win32_WORD segFs;
Win32_WORD segGs;
Win32_WORD segSs;
Win32_DWORD eFlags;
Win32_DWORD64 dr0;
Win32_DWORD64 dr1;
Win32_DWORD64 dr2;
Win32_DWORD64 dr3;
Win32_DWORD64 dr6;
Win32_DWORD64 dr7;
Win32_DWORD64 rax;
Win32_DWORD64 rcx;
Win32_DWORD64 rdx;
Win32_DWORD64 rbx;
Win32_DWORD64 rsp;
Win32_DWORD64 rbp;
Win32_DWORD64 rsi;
Win32_DWORD64 rdi;
Win32_DWORD64 r8;
Win32_DWORD64 r9;
Win32_DWORD64 r10;
Win32_DWORD64 r11;
Win32_DWORD64 r12;
Win32_DWORD64 r13;
Win32_DWORD64 r14;
Win32_DWORD64 r15;
Win32_DWORD64 rip;
union
{
Win32_XMM_SAVE_AREA32 fltSave;
//Win32_NEON128[16] q;
Win32_ULONGLONG[32] d;
struct
{
Win32_M128A[2] header;
Win32_M128A[8] legacy;
Win32_M128A xmm0;
Win32_M128A xmm1;
Win32_M128A xmm2;
Win32_M128A xmm3;
Win32_M128A xmm4;
Win32_M128A xmm5;
Win32_M128A xmm6;
Win32_M128A xmm7;
Win32_M128A xmm8;
Win32_M128A xmm9;
Win32_M128A xmm10;
Win32_M128A xmm11;
Win32_M128A xmm12;
Win32_M128A xmm13;
Win32_M128A xmm14;
Win32_M128A xmm15;
}
Win32_DWORD[32] s;
}
Win32_M128A[26] vectorRegister;
Win32_DWORD64 vectorControl;
Win32_DWORD64 debugControl;
Win32_DWORD64 lastBranchToRip;
Win32_DWORD64 lastBranchFromRip;
Win32_DWORD64 lastExceptionToRip;
Win32_DWORD64 lastExceptionFromRip;
}
const CONTEXT_AMD64 = 0x00100000;
const CONTEXT_AMD64_CONTROL = CONTEXT_AMD64 | 0x0001;
const CONTEXT_AMD64_INTEGER = CONTEXT_AMD64 | 0x0002;
const CONTEXT_AMD64_SEGMENTS = CONTEXT_AMD64 | 0x0004;
const CONTEXT_AMD64_FLOATING_POINT = CONTEXT_AMD64 | 0x0008;
const CONTEXT_AMD64_DEBUG_REGISTERS = CONTEXT_AMD64 | 0x0010;
const CONTEXT_AMD64_FULL = CONTEXT_AMD64_CONTROL | CONTEXT_AMD64_INTEGER | CONTEXT_AMD64_FLOATING_POINT;
const CONTEXT_AMD64_ALL = CONTEXT_AMD64_CONTROL | CONTEXT_AMD64_INTEGER | CONTEXT_AMD64_SEGMENTS | CONTEXT_AMD64_FLOATING_POINT | CONTEXT_AMD64_DEBUG_REGISTERS;
def CONTEXT_CONTROL = CONTEXT_AMD64_CONTROL;
def CONTEXT_FULL = CONTEXT_AMD64_FULL;
def CONTEXT_ALL = CONTEXT_AMD64_ALL;
def Win32_CONTEXT = Win32_AMD64_CONTEXT;
def Win32_PCONTEXT = Win32_CONTEXT*;
struct Win32_M128A @align(16)
{
Win32_ULONGLONG low;
Win32_LONGLONG high;
}
struct Win32_IMAGE_DATA_DIRECTORY
{
Win32_ULONG virtualAddress;
Win32_ULONG size;
}
struct Win32_IMAGE_OPTIONAL_HEADER64
{
Win32_WORD magic;
Win32_BYTE majorLinkerVersion;
Win32_BYTE minorLinkerVersion;
Win32_DWORD sizeOfCode;
Win32_DWORD sizeOfInitializedData;
Win32_DWORD sizeOfUninitializedData;
Win32_DWORD addressOfEntryPoint;
Win32_DWORD baseOfCode;
Win32_ULONGLONG imageBase;
Win32_DWORD sectionAlignment;
Win32_DWORD fileAlignment;
Win32_WORD majorOperatingSystemVersion;
Win32_WORD minorOperatingSystemVersion;
Win32_WORD majorImageVersion;
Win32_WORD minorImageVersion;
Win32_WORD majorSubsystemVersion;
Win32_WORD minorSubsystemVersion;
Win32_DWORD win32VersionValue;
Win32_DWORD sizeOfImage;
Win32_DWORD sizeOfHeaders;
Win32_DWORD checkSum;
Win32_WORD subsystem;
Win32_WORD dllCharacteristics;
Win32_ULONGLONG sizeOfStackReserve;
Win32_ULONGLONG sizeOfStackCommit;
Win32_ULONGLONG sizeOfHeapReserve;
Win32_ULONGLONG sizeOfHeapCommit;
Win32_DWORD loaderFlags;
Win32_DWORD numberOfRvaAndSizes;
Win32_IMAGE_DATA_DIRECTORY[16] dataDirectory;
}
def Win32_PIMAGE_OPTIONAL_HEADER64 = Win32_IMAGE_OPTIONAL_HEADER64*;
struct Win32_IMAGE_FILE_HEADER
{
Win32_WORD machine;
Win32_WORD numberOfSections;
Win32_DWORD timeDateStamp;
Win32_DWORD pointerToSymbolTable;
Win32_DWORD numberOfSymbols;
Win32_WORD sizeOfOptionalHeader;
Win32_WORD characteristics;
}
def Win32_PIMAGE_FILE_HEADER = Win32_IMAGE_FILE_HEADER*;
struct Win32_IMAGE_NT_HEADERS
{
Win32_DWORD signature;
Win32_IMAGE_FILE_HEADER fileHeader;
Win32_IMAGE_OPTIONAL_HEADER64 optionalHeader;
}
def Win32_PIMAGE_NT_HEADERS = Win32_IMAGE_NT_HEADERS*;
struct Win32_SYMBOL_INFO
{
Win32_ULONG sizeOfStruct;
Win32_ULONG typeIndex;
Win32_ULONG64[2] reserved;
Win32_ULONG index;
Win32_ULONG size;
Win32_ULONG64 modBase;
Win32_ULONG flags;
Win32_ULONG64 value;
Win32_ULONG64 address;
Win32_ULONG register;
Win32_ULONG scope;
Win32_ULONG tag;
Win32_ULONG nameLen;
Win32_ULONG maxNameLen;
Win32_CHAR[1] name;
}
def Win32_PSYMBOL_INFO = Win32_SYMBOL_INFO*;
struct Win32_MODLOAD_DATA
{
Win32_DWORD ssize;
Win32_DWORD ssig;
Win32_PVOID data;
Win32_DWORD size;
Win32_DWORD flags;
}
enum Win32_ADDRESS_MODE
{
ADDR_MODE_1616,
ADDR_MODE_1632,
ADDR_MODE_REAL,
ADDR_MODE_FLAT,
}
struct Win32_ADDRESS64
{
Win32_DWORD64 offset;
Win32_WORD segment;
Win32_ADDRESS_MODE mode;
}
struct Win32_KDHELP64
{
Win32_DWORD64 thread;
Win32_DWORD thCallbackStack;
Win32_DWORD thCallbackBStore;
Win32_DWORD nextCallback;
Win32_DWORD framePointer;
Win32_DWORD64 kiCallUserMode;
Win32_DWORD64 keUserCallbackDispatcher;
Win32_DWORD64 systemRangeStart;
Win32_DWORD64 kiUserExceptionDispatcher;
Win32_DWORD64 stackBase;
Win32_DWORD64 stackLimit;
Win32_DWORD buildVersion;
Win32_DWORD retpolineStubFunctionTableSize;
Win32_DWORD64 retpolineStubFunctionTable;
Win32_DWORD retpolineStubOffset;
Win32_DWORD retpolineStubSize;
Win32_DWORD64[2] reserved0;
}
struct Win32_STACKFRAME64
{
Win32_ADDRESS64 addrPC;
Win32_ADDRESS64 addrReturn;
Win32_ADDRESS64 addrFrame;
Win32_ADDRESS64 addrStack;
Win32_ADDRESS64 addrBStore;
Win32_PVOID funcTableEntry;
Win32_DWORD64[4] params;
Win32_BOOL far;
Win32_BOOL virtual;
Win32_DWORD64[3] reserved;
Win32_KDHELP64 kdHelp;
}
def Win32_PREAD_PROCESS_MEMORY_ROUTINE64 = fn Win32_BOOL(Win32_HANDLE hProcess, Win32_DWORD64 qwBaseAddress, Win32_PVOID lpBuffer, Win32_DWORD nSize, Win32_LPDWORD lpNumberOfBytesRead);
def Win32_PFUNCTION_TABLE_ACCESS_ROUTINE64 = fn Win32_PVOID(Win32_HANDLE ahProcess, Win32_DWORD64 addrBase);
def Win32_PGET_MODULE_BASE_ROUTINE64 = fn Win32_DWORD64(Win32_HANDLE hProcess, Win32_DWORD64 address);
def Win32_PTRANSLATE_ADDRESS_ROUTINE64 = fn Win32_DWORD64(Win32_HANDLE hProcess, Win32_HANDLE hThread, Win32_LPADDRESS64 lpaddr);
def Win32_PKDHELP64 = Win32_KDHELP64*;
def Win32_LPADDRESS64 = Win32_ADDRESS64*;
def Win32_LPSTACKFRAME64 = Win32_STACKFRAME64*;
def Win32_PMODLOAD_DATA = Win32_MODLOAD_DATA*;
def Win32_PIMAGEHLP_LINE64 = Win32_IMAGEHLP_LINE64*;
def Win32_LPMODULEINFO = Win32_MODULEINFO*;

View File

@@ -30,7 +30,7 @@
- New generic syntax.
- Slice initialization.
- `$feature` for feature flags.
- Improved stack trace.
- Native stacktrace for Linux, MacOS and Windows.
- Macro ref parameters are now of pointer type and ref parameters are not assignable.
- Added `nextcase default`.
- Added `$embed` to embed binary data.

View File

@@ -5,11 +5,7 @@ import std::os;
fn void! test2()
{
BacktraceList list = linux::backtrace_load(mem::heap())!;
foreach (Backtrace trace : list)
{
io::printfn("%s", trace);
}
builtin::print_backtrace("hello", 1);
}
fn void test1()

18
resources/msvc_stack.c3 Normal file
View File

@@ -0,0 +1,18 @@
module test;
import std::io;
import std::collections::map;
import std::os;
fn void test1()
{
builtin::print_backtrace("hello", 1);
int x = 1;
return;
}
fn void main()
{
test1();
}

View File

@@ -78,6 +78,7 @@ static const char *string_esc(const char *str)
static void linker_setup_windows(const char ***args_ref, LinkerType linker_type, const char ***additional_linked_ref)
{
add_arg(active_target.win.use_win_subsystem ? "/SUBSYSTEM:WINDOWS" : "/SUBSYSTEM:CONSOLE");
vec_add(*additional_linked_ref, "dbghelp");
if (linker_type == LINKER_CC) return;
//add_arg("/MACHINE:X64");
bool is_debug = false;
@@ -382,8 +383,9 @@ static const char *find_linux_crt_begin(void)
return NULL;
}
static void linker_setup_linux(const char ***args_ref, LinkerType linker_type)
static void linker_setup_linux(const char ***args_ref, LinkerType linker_type, const char ***additional_linked_ref)
{
vec_add(*additional_linked_ref, "dl");
if (linker_type == LINKER_CC)
{
if (!link_libc())
@@ -391,7 +393,6 @@ static void linker_setup_linux(const char ***args_ref, LinkerType linker_type)
add_arg("-nostdlib");
return;
}
vec_add(active_target.linker_libs, "dl");
if (active_target.debug_info == DEBUG_INFO_FULL)
{
add_arg("-rdynamic");
@@ -438,7 +439,6 @@ static void linker_setup_linux(const char ***args_ref, LinkerType linker_type)
add_arg2("-L", crt_dir);
add_arg("-L");
add_arg("/usr/lib/x86_64-linux-gnu/libdl.so");
add_arg("-ldl");
add_arg("--dynamic-linker=/lib64/ld-linux-x86-64.so.2");
add_arg("-lm");
add_arg("-lpthread");
@@ -583,7 +583,7 @@ static bool linker_setup(const char ***args_ref, const char **files_to_link, uns
linker_setup_freebsd(args_ref, linker_type);
break;
case OS_TYPE_LINUX:
linker_setup_linux(args_ref, linker_type);
linker_setup_linux(args_ref, linker_type, &additional_linked);
break;
case OS_TYPE_UNKNOWN:
if (link_libc())

View File

@@ -34,7 +34,7 @@ int target_alloca_addr_space()
bool os_supports_stacktrace(OsType os_type)
{
return os_type == OS_TYPE_LINUX || os_is_apple(os_type);
return os_type == OS_TYPE_LINUX || os_is_apple(os_type) || os_type == OS_TYPE_WIN32;
}
bool os_is_apple(OsType os_type)
{

View File

@@ -1 +1 @@
#define COMPILER_VERSION "0.4.703"
#define COMPILER_VERSION "0.4.704"