-
Notifications
You must be signed in to change notification settings - Fork 7
/
back_darwin.odin
148 lines (114 loc) · 4.1 KB
/
back_darwin.odin
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
141
142
143
144
145
146
147
148
#+private file
package back
@require import "core:strings"
when !USE_FALLBACK {
foreign import system "system:System.framework"
// NOTE: CoreSymbolication is a private framework, Apple is allowed to break it and doesn't provide
// headers, although the API has as of my knowledge been the same in the past 10 years at least.
@(extra_linker_flags="-iframework /System/Library/PrivateFrameworks")
foreign import symbolication "system:CoreSymbolication.framework"
@(private="package")
_Trace_Entry :: rawptr
@(private="package")
_trace :: proc(buf: Trace) -> (n: int) {
ctx: unw_context_t
cursor: unw_cursor_t
ret: i32
ret = unw_getcontext(&ctx)
assert(ret == 0)
ret = unw_init_local(&cursor, &ctx)
assert(ret == 0)
pc: uintptr
for ; unw_step(&cursor) > 0 && n < len(buf); n += 1 {
ret = unw_get_reg(&cursor, .IP, &pc)
assert(ret == 0)
buf[n] = rawptr(pc)
}
return
}
@(private="package")
_lines_destroy :: proc(lines: []Line) {
for line in lines {
delete(line.location)
delete(line.symbol)
}
delete(lines)
}
@(private="package")
_lines :: proc(bt: Trace) -> (out: []Line, err: Lines_Error) {
out = make([]Line, len(bt))
symbolicator := CSSymbolicatorCreateWithPid(getpid())
defer CSRelease(symbolicator)
for &msg, i in out {
symbol := CSSymbolicatorGetSymbolWithAddressAtTime(symbolicator, uintptr(bt[i]), CSNow)
info := CSSymbolicatorGetSourceInfoWithAddressAtTime(symbolicator, uintptr(bt[i]), CSNow)
msg.symbol = strings.clone_from(CSSymbolGetName(symbol))
// No debug info.
if CSIsNull(info) {
owner := CSSymbolGetSymbolOwner(symbol)
msg.location = strings.clone_from(CSSymbolOwnerGetPath(owner))
} else {
path := string(CSSourceInfoGetPath(info))
location := strings.builder_make(0, len(path)+6)
strings.write_string(&location, path)
strings.write_string(&location, ":")
strings.write_int(&location, int(CSSourceInfoGetLineNumber(info)))
msg.location = strings.to_string(location)
}
}
return
}
CSTypeRef :: struct {
csCppData: rawptr,
csCppObj: rawptr,
}
CSSymbolicatorRef :: distinct CSTypeRef
CSSymbolRef :: distinct CSTypeRef
CSSourceInfoRef :: distinct CSTypeRef
CSSymbolOwnerRef :: distinct CSTypeRef
CSNow :: 0x80000000
foreign symbolication {
@(link_name="CSIsNull")
_CSIsNull :: proc(ref: CSTypeRef) -> bool ---
@(link_name="CSRelease")
_CSRelease :: proc(ref: CSTypeRef) ---
CSSymbolicatorCreateWithPid :: proc(pid: pid_t) -> CSSymbolicatorRef ---
CSSymbolicatorGetSymbolWithAddressAtTime :: proc(symbolicator: CSSymbolicatorRef, addr: uintptr, time: u64) -> CSSymbolRef ---
CSSymbolicatorGetSourceInfoWithAddressAtTime :: proc(symbolicator: CSSymbolicatorRef, adrr: uintptr, time: u64) -> CSSourceInfoRef ---
CSSymbolGetName :: proc(symbol: CSSymbolRef) -> cstring ---
CSSymbolGetSymbolOwner :: proc(symbol: CSSymbolRef) -> CSSymbolOwnerRef ---
CSSourceInfoGetPath :: proc(info: CSSourceInfoRef) -> cstring ---
CSSourceInfoGetLineNumber :: proc(info: CSSourceInfoRef) -> i32 ---
CSSourceInfoGetSymbol :: proc(info: CSSourceInfoRef) -> CSSymbolRef ---
CSSymbolOwnerGetPath :: proc(owner: CSSymbolOwnerRef) -> cstring ---
}
CSRelease :: #force_inline proc(ref: $T) {
_CSRelease(CSTypeRef(ref))
}
CSIsNull :: #force_inline proc(ref: $T) -> bool {
return _CSIsNull(CSTypeRef(ref))
}
// These could actually be smaller, but then we would have to define and check the size on each
// architecture, the sizes here are the largest they can be.
_LIBUNWIND_CONTEXT_SIZE :: 167
_LIBUNWIND_CURSOR_SIZE :: 204
unw_context_t :: struct {
data: [_LIBUNWIND_CONTEXT_SIZE]u64,
}
unw_cursor_t :: struct {
data: [_LIBUNWIND_CURSOR_SIZE]u64,
}
// Cross-platform registers, each architecture has additional registers but these are enough for us.
Register :: enum i32 {
SP = -2,
IP = -1,
}
pid_t :: distinct i32
foreign system {
unw_getcontext :: proc(ctx: ^unw_context_t) -> i32 ---
unw_init_local :: proc(cursor: ^unw_cursor_t, ctx: ^unw_context_t) -> i32 ---
unw_get_reg :: proc(cursor: ^unw_cursor_t, name: Register, reg: ^uintptr) -> i32 ---
unw_step :: proc(cursor: ^unw_cursor_t) -> i32 ---
getpid :: proc() -> pid_t ---
}
}