-
Notifications
You must be signed in to change notification settings - Fork 2
/
Copy pathmalloc.go
59 lines (54 loc) · 1.67 KB
/
malloc.go
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
package gotcha
import (
"C"
"os"
"strconv"
"unsafe"
"github.com/1pkg/golocal"
"github.com/1pkg/gomonkey"
)
// tp from `runtime._type`
type tp struct {
size uintptr
}
//go:linkname mallocgc runtime.mallocgc
func mallocgc(size uintptr, tp *tp, needzero bool) unsafe.Pointer
// init patches main mallocgc allocation runtime entrypoint
// it also sets goroutine local storage tracers capacity from env var
// note that pacthing will only work on amd64 arch.
func init() {
// set up local store for malloc
maxTracers := int64(golocal.DefaultCapacity)
if max, err := strconv.ParseInt(os.Getenv("GOTCHA_MAX_TRACERS"), 10, 64); err == nil {
maxTracers = max
}
ls := golocal.LStore(maxTracers)
// patch malloc with permanent decorator
gomonkey.PermanentDecorate(mallocgc, func(size uintptr, tp *tp, needzero bool) unsafe.Pointer {
// unfortunately we can't use local store direct calls here
// as it causes `unknown caller pc` stack fatal error.
id := ls.RLock()
gctxPtr, ok := ls.Store[id]
ls.RUnlock()
if ok {
// trace allocations for caller tracer goroutine.
bytes := int64(size)
objs := int64(1)
if tp != nil {
bytes = int64(tp.size)
objs = int64(size) / bytes
}
(*gotchactx)(unsafe.Pointer(gctxPtr)).Add(bytes, objs, 1)
}
return nil
}, 24, 53, []byte{
0x48, 0x83, 0xec, 0x28, // sub rsp,0x28
0x48, 0x8b, 0x44, 0x24, 0x30, // mov rax,QWORD PTR [rsp+0x30]
0x48, 0x89, 0x04, 0x24, // mov QWORD PTR [rsp],rax
0x48, 0x8b, 0x44, 0x24, 0x38, // mov rax,QWORD PTR [rsp+0x38]
0x48, 0x89, 0x44, 0x24, 0x08, // mov QWORD PTR [rsp],rax
}, []byte{
0x48, 0x83, 0xc4, 0x28, // add rsp,0x28
0x48, 0x81, 0xec, 0x98, 0x00, 0x00, 0x00, // sub rsp,0x98
})
}