trace_windows.odin 2.1 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768
  1. //+private
  2. //+build windows
  3. package debug_trace
  4. import "base:intrinsics"
  5. import "base:runtime"
  6. import win32 "core:sys/windows"
  7. import "core:fmt"
  8. _Context :: struct {
  9. hProcess: win32.HANDLE,
  10. lock: win32.SRWLOCK,
  11. }
  12. _init :: proc "contextless" (ctx: ^Context) -> (ok: bool) {
  13. defer if !ok { _destroy(ctx) }
  14. ctx.impl.hProcess = win32.GetCurrentProcess()
  15. win32.SymInitialize(ctx.impl.hProcess, nil, true) or_return
  16. win32.SymSetOptions(win32.SYMOPT_LOAD_LINES)
  17. return true
  18. }
  19. _destroy :: proc "contextless" (ctx: ^Context) -> bool {
  20. if ctx != nil {
  21. win32.SymCleanup(ctx.impl.hProcess)
  22. }
  23. return true
  24. }
  25. _frames :: proc "contextless" (ctx: ^Context, skip: uint, frames_buffer: []Frame) -> []Frame {
  26. frame_count := win32.RtlCaptureStackBackTrace(u32(skip) + 2, u32(len(frames_buffer)), ([^]rawptr)(&frames_buffer[0]), nil)
  27. for i in 0..<frame_count {
  28. // NOTE: Return address is one after the call instruction so subtract a byte to
  29. // end up back inside the call instruction which is needed for SymFromAddr.
  30. frames_buffer[i] -= 1
  31. }
  32. return frames_buffer[:frame_count]
  33. }
  34. _resolve :: proc(ctx: ^Context, frame: Frame, allocator: runtime.Allocator) -> (fl: Frame_Location) {
  35. intrinsics.atomic_store(&ctx.in_resolve, true)
  36. defer intrinsics.atomic_store(&ctx.in_resolve, false)
  37. // NOTE(bill): Dbghelp is not thread-safe
  38. win32.AcquireSRWLockExclusive(&ctx.impl.lock)
  39. defer win32.ReleaseSRWLockExclusive(&ctx.impl.lock)
  40. data: [size_of(win32.SYMBOL_INFOW) + size_of([256]win32.WCHAR)]byte
  41. symbol := (^win32.SYMBOL_INFOW)(&data[0])
  42. symbol.SizeOfStruct = size_of(symbol)
  43. symbol.MaxNameLen = 255
  44. if win32.SymFromAddrW(ctx.impl.hProcess, win32.DWORD64(frame), &{}, symbol) {
  45. fl.procedure, _ = win32.wstring_to_utf8(&symbol.Name[0], -1, allocator)
  46. } else {
  47. fl.procedure = fmt.aprintf("(procedure: 0x%x)", frame, allocator=allocator)
  48. }
  49. line: win32.IMAGEHLP_LINE64
  50. line.SizeOfStruct = size_of(line)
  51. if win32.SymGetLineFromAddrW64(ctx.impl.hProcess, win32.DWORD64(frame), &{}, &line) {
  52. fl.file_path, _ = win32.wstring_to_utf8(line.FileName, -1, allocator)
  53. fl.line = i32(line.LineNumber)
  54. }
  55. return
  56. }