module std::os::backtrace; import std::collections::list, std::os, std::io; faultdef SEGMENT_NOT_FOUND, EXECUTABLE_PATH_NOT_FOUND, IMAGE_NOT_FOUND, NO_BACKTRACE_SYMBOLS, RESOLUTION_FAILED; const Backtrace BACKTRACE_UNKNOWN = { 0, "", "", "", 0, null, false }; struct Backtrace (Printable) { uptr offset; String function; String object_file; String file; uint line; Allocator allocator; bool is_inline; } fn bool Backtrace.has_file(&self) { return self.file.len > 0; } fn bool Backtrace.is_unknown(&self) { return !self.object_file.len; } fn usz? Backtrace.to_format(&self, Formatter* formatter) @dynamic { String inline_suffix = self.is_inline ? " [inline]" : ""; if (self.has_file()) { return formatter.printf("%s (in %s) (%s:%d)%s", self.function, self.object_file, self.file, self.line, inline_suffix); } if (self.is_unknown()) { return formatter.printf("??? (in unknown)%s", inline_suffix); } return formatter.printf("%s (in %s) (source unavailable)%s", self.function, self.object_file, inline_suffix); } fn void Backtrace.free(&self) { if (!self.allocator) return; allocator::free(self.allocator, self.function); allocator::free(self.allocator, self.object_file); allocator::free(self.allocator, self.file); } fn Backtrace* Backtrace.init(&self, Allocator allocator, uptr offset, String function, String object_file, String file = "", uint line = 0) { if (!allocator) { self.offset = offset; self.function = function; self.object_file = object_file; self.file = file; self.line = 0; self.allocator = null; return self; } self.offset = offset; 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 (!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 } alias BacktraceList = List{Backtrace}; alias symbolize_backtrace @if(env::LINUX) = linux::symbolize_backtrace; alias symbolize_backtrace @if(env::WIN32) = win32::symbolize_backtrace; alias symbolize_backtrace @if(env::DARWIN) = darwin::symbolize_backtrace; alias symbolize_backtrace @if(env::OPENBSD) = openbsd::symbolize_backtrace; fn BacktraceList? symbolize_backtrace(Allocator allocator, void*[] backtrace) @if(!env::NATIVE_STACKTRACE) { return {}; }