This repository was archived by the owner on Aug 19, 2026. It is now read-only.
Repository navigation
Expand file tree
/
Copy pathback_windows.odin
More file actions
140 lines (115 loc) · 3.94 KB
/
Copy pathback_windows.odin
File metadata and controls
140 lines (115 loc) · 3.94 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
#+vet explicit-allocators
#+private
package back
@require import "base:intrinsics"
@require import "base:runtime"
@require import "core:io"
@require import "core:strings"
@require import "core:sync"
@require import "core:unicode/utf16"
@require import win "core:sys/windows"
when !USE_FALLBACK {
SYMOPT_DEFERRED_LOADS :: 0x00000004
_Trace_Entry :: uintptr
_trace :: #force_no_inline proc(buf: Trace) -> (n: int) {
frame_count := win.RtlCaptureStackBackTrace(2, u32(len(buf)), ([^]rawptr)(raw_data(buf)), nil)
for &frame in buf[:frame_count] {
// 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.
frame -= 1
}
return int(frame_count)
}
_lines_destroy :: proc(lines: []Line, allocator: runtime.Allocator) {
for line in lines {
delete(line.location, allocator)
if line.symbol != "??" && line.symbol != "??OOM" {
delete(line.symbol, allocator)
}
}
delete(lines, allocator)
}
_lines :: proc(bt: Trace, allocator, temp_allocator: runtime.Allocator) -> (out: []Line, err: Lines_Error) {
// Debug info is needed, if we call with out-of-date debug symbols it will return out-of-date info, so better to short-circuit right away.
when !ODIN_DEBUG {
out = make([]Line, len(bt), allocator)
for &line, i in out {
line.symbol = "??"
location := strings.builder_make(allocator)
strings.write_string(&location, "0x")
strings.write_i64 (&location, i64(bt[i]), 16)
line.location = strings.to_string(location)
}
return
}
out = make([]Line, len(bt), allocator)
defer if err != nil { _lines_destroy(out, allocator) }
process := win.GetCurrentProcess()
sync.guard(&_win32_dbghelp_mutex)
if !win.SymInitialize(process, nil, true) {
err = .Info_Not_Found
return
}
defer win.SymCleanup(process)
win.SymSetOptions(win.SYMOPT_LOAD_LINES|SYMOPT_DEFERRED_LOADS)
data: [size_of(win.SYMBOL_INFOW) + size_of([256]win.WCHAR)]byte
symbol := (^win.SYMBOL_INFOW)(&data[0])
// The value of SizeOfStruct must be the size of the whole struct,
// not just the size of the pointer
symbol.SizeOfStruct = size_of(symbol^)
symbol.MaxNameLen = 255
for &line, i in out {
if win.SymFromAddrW(process, win.DWORD64(bt[i]), nil, symbol) {
symbol, mem_err := win.wstring_to_utf8(cstring16(&symbol.Name[0]), int(symbol.NameLen), allocator)
if mem_err != nil {
line.symbol = "??OOM"
} else if symbol == "??" {
delete(symbol, allocator)
line.symbol = "??"
} else {
line.symbol = symbol
}
} else {
line.symbol = "??"
}
lineInfo: win.IMAGEHLP_LINE64
lineInfo.SizeOfStruct = size_of(lineInfo)
if win.SymGetLineFromAddrW64(process, win.DWORD64(bt[i]), &{}, &lineInfo) {
location := strings.builder_make(allocator)
write_string16(&location, string16(lineInfo.FileName))
when ODIN_ERROR_POS_STYLE == .Default {
strings.write_byte(&location, '(')
strings.write_int (&location, int(lineInfo.LineNumber))
strings.write_byte(&location, ')')
} else when ODIN_ERROR_POS_STYLE == .Unix {
strings.write_byte(&location, ':')
strings.write_int (&location, int(lineInfo.LineNumber))
} else {
#panic("unhandled ODIN_ERROR_POS_STYLE")
}
line.location = strings.to_string(location)
} else {
location := strings.builder_make(allocator)
strings.write_string(&location, "0x")
strings.write_i64 (&location, i64(bt[i]), 16)
line.location = strings.to_string(location)
}
}
return
}
write_string16 :: proc(b: ^strings.Builder, s: string16, loc := #caller_location) -> (n: int, err: io.Error) {
for i := 0; i < len(s); i += 1 {
r := rune(utf16.REPLACEMENT_CHAR)
switch c := s[i]; {
case c < utf16._surr1, utf16._surr3 <= c:
r = rune(c)
case utf16._surr1 <= c && c < utf16._surr2 && i+1 < len(s) &&
utf16._surr2 <= s[i+1] && s[i+1] < utf16._surr3:
r = utf16.decode_surrogate_pair(rune(c), rune(s[i+1]))
i += 1
}
n += strings.write_rune(b, rune(r)) or_return
}
return
}
}