trace_windows.odin 2.2 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970
  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. // The value of SizeOfStruct must be the size of the whole struct,
  43. // not just the size of the pointer
  44. symbol.SizeOfStruct = size_of(symbol^)
  45. symbol.MaxNameLen = 255
  46. if win32.SymFromAddrW(ctx.impl.hProcess, win32.DWORD64(frame), &{}, symbol) {
  47. fl.procedure, _ = win32.wstring_to_utf8(cstring16(&symbol.Name[0]), -1, allocator)
  48. } else {
  49. fl.procedure = fmt.aprintf("(procedure: 0x%x)", frame, allocator=allocator)
  50. }
  51. line: win32.IMAGEHLP_LINE64
  52. line.SizeOfStruct = size_of(line)
  53. if win32.SymGetLineFromAddrW64(ctx.impl.hProcess, win32.DWORD64(frame), &{}, &line) {
  54. fl.file_path, _ = win32.wstring_to_utf8(line.FileName, -1, allocator)
  55. fl.line = i32(line.LineNumber)
  56. }
  57. return
  58. }