浏览代码

Begin work on `core:debug/trace`

gingerBill 1 年之前
父节点
当前提交
362aa82f59
共有 2 个文件被更改,包括 114 次插入0 次删除
  1. 44 0
      core/debug/trace/trace.odin
  2. 70 0
      core/debug/trace/trace_windows.odin

+ 44 - 0
core/debug/trace/trace.odin

@@ -0,0 +1,44 @@
+package debug_trace
+
+import "base:intrinsics"
+import "base:runtime"
+
+Frame :: distinct uintptr
+MAX_FRAMES :: 64
+
+Frame_Location :: runtime.Source_Code_Location
+
+delete_frame_location :: proc(loc: Frame_Location, allocator: runtime.Allocator) -> runtime.Allocator_Error {
+	delete(loc.procedure, allocator) or_return
+	delete(loc.file_path, allocator) or_return
+	return nil
+}
+
+Context :: struct {
+	in_resolve: bool, // atomic
+	impl: _Context,
+}
+
+init :: proc(ctx: ^Context) -> bool {
+	return _init(ctx)
+}
+
+destroy :: proc(ctx: ^Context) -> bool {
+	return _destroy(ctx)
+}
+
+@(require_results)
+frames :: proc(ctx: ^Context, skip: uint, allocator: runtime.Allocator) -> []Frame {
+	return _frames(ctx, skip, allocator)
+}
+
+@(require_results)
+resolve :: proc(ctx: ^Context, frame: Frame, allocator: runtime.Allocator) -> (result: Frame_Location) {
+	return _resolve(ctx, frame, allocator)
+}
+
+
+@(require_results)
+in_resolve :: proc "contextless" (ctx: ^Context) -> bool {
+	return intrinsics.atomic_load(&ctx.in_resolve)
+}

+ 70 - 0
core/debug/trace/trace_windows.odin

@@ -0,0 +1,70 @@
+//+private
+//+build windows
+package debug_trace
+
+import "base:intrinsics"
+import "base:runtime"
+
+import win32 "core:sys/windows"
+import "core:fmt"
+
+_Context :: struct {
+	hProcess: win32.HANDLE,
+	lock:     win32.SRWLOCK,
+}
+
+_init :: proc "contextless" (ctx: ^Context) -> (ok: bool) {
+	defer if !ok { _destroy(ctx) }
+	ctx.impl.hProcess = win32.GetCurrentProcess()
+	win32.SymInitialize(ctx.impl.hProcess, nil, true) or_return
+	win32.SymSetOptions(win32.SYMOPT_LOAD_LINES)
+	return true
+}
+
+_destroy :: proc "contextless" (ctx: ^Context) -> bool {
+	if ctx != nil {
+		win32.SymCleanup(ctx.impl.hProcess)
+	}
+	return true
+}
+
+_frames :: proc(ctx: ^Context, skip: uint, allocator: runtime.Allocator) -> []Frame {
+	buffer: [MAX_FRAMES]rawptr
+	frame_count := win32.RtlCaptureStackBackTrace(u32(skip) + 2, len(buffer), &buffer[0], nil)
+	frames := make([]Frame, frame_count, allocator)
+	for &f, i in frames {
+		// NOTE: Return address is one after the call instruction so subtract a byte to
+		// end up back inside the call instruction which is needed for SymFromAddr.
+		f = Frame(buffer[i]) - 1
+	}
+	return frames
+}
+
+
+_resolve :: proc(ctx: ^Context, frame: Frame, allocator: runtime.Allocator) -> (result: runtime.Source_Code_Location) {
+	intrinsics.atomic_store(&ctx.in_resolve, true)
+	defer intrinsics.atomic_store(&ctx.in_resolve, false)
+
+	// NOTE(bill): Dbghelp is not thread-safe
+	win32.AcquireSRWLockExclusive(&ctx.impl.lock)
+	defer win32.ReleaseSRWLockExclusive(&ctx.impl.lock)
+
+	data: [size_of(win32.SYMBOL_INFOW) + size_of([256]win32.WCHAR)]byte
+	symbol := (^win32.SYMBOL_INFOW)(&data[0])
+	symbol.SizeOfStruct = size_of(symbol)
+	symbol.MaxNameLen = 255
+	if win32.SymFromAddrW(ctx.impl.hProcess, win32.DWORD64(frame), &{}, symbol) {
+		result.procedure, _ = win32.wstring_to_utf8(&symbol.Name[0], -1, allocator)
+	} else {
+		result.procedure = fmt.aprintf("(procedure: 0x%x)", frame, allocator=allocator)
+	}
+
+	line: win32.IMAGEHLP_LINE64
+	line.SizeOfStruct = size_of(line)
+	if win32.SymGetLineFromAddrW64(ctx.impl.hProcess, win32.DWORD64(frame), &{}, &line) {
+		result.file_path, _ = win32.wstring_to_utf8(line.FileName, -1, allocator)
+		result.line = i32(line.LineNumber)
+	}
+
+	return result
+}