/
maps.go
169 lines (145 loc) · 3.52 KB
/
maps.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
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
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
// +build linux,amd64
// Package proc provides parsing of procfs mappings.
package proc
import (
"errors"
"fmt"
"os"
"strconv"
"strings"
"golang.org/x/sys/unix"
)
const proc = "/proc/"
var (
prefix = proc + strconv.Itoa(os.Getpid())
defaultProcess = Process{
prefix: prefix,
maps: prefix + "/maps",
exe: prefix + "/exe",
}
)
// mmaped region protections and flags.
const (
None Perms = 0x0
Read Perms = 0x1
Write Perms = 0x2
Exec Perms = 0x4
Priv Perms = 0x8
Shared Perms = 0x10
)
// Map is a mapped memory region, found in /proc/$$/maps
// See: mmap(2)
type Map struct {
Start uintptr // Beginning memory address.
End uintptr // Ending memory address.
Perms Perms // Memory protection bitmask.
Offset uintptr // Offset where mapping begins.
Maj uint64 // Major device number.
Min uint64 // Minor device number.
Inode uint64 // If mapped from a file, the file's inode.
// If mapped from a file, the file's path. Special values
// include [stack], [heap], and [vsdo]. See related methods.
Path string
Type Type // Type of the region. Depends on the Path member.
}
func (m Map) String() string {
return fmt.Sprintf("%0.8x-%0.8x %s %0.8x %d:%d %d %s",
m.Start, m.End, m.Perms, m.Offset,
m.Maj, m.Min, m.Inode, m.Path,
)
}
func (m Map) IsPrivate() bool { return m.Perms&Priv != 0 }
// ErrVersion indicates the mapping does not have a thread ID.
// (Usually means the linux version is too old.)
var ErrVersion = errors.New("thread ID needs linux >= 3.4")
// ErrNotStack is returned if the mapping is not a stack.
var ErrNotStack = errors.New("mapping is not a stack")
// ThreadID returns the thread (mapping) ID that corresponds
// to the /proc/$$/task/[id] path. It returns an error if the
// mapping is either not a stack or does not have a thread id.
func (m Map) ThreadID() (int, error) {
if m.Type&Stack == 0 {
return 0, ErrNotStack
}
i := strings.IndexByte(m.Path, ':')
if i < 0 {
return 0, ErrVersion
}
return strconv.Atoi(m.Path[i+1 : len(m.Path)-1])
}
// ParseMaps parses /proc/$$/maps into a useable data structure.
func ParseMaps() (maps Mapping, err error) {
return defaultProcess.ParseMaps()
}
// Find searches through /proc/$$/maps to the find the range that holds
// pc. It returns the Map and a boolean indicating whether the Map was found.
func Find(pc uintptr) (m Map, ok bool) {
return defaultProcess.Find(pc)
}
// Mprotect calls mprotect(2) on the mmapped region.
func (m Map) Mprotect(prot Perms) (err error) {
_, _, e1 := unix.Syscall(
unix.SYS_MPROTECT,
uintptr(m.Start),
uintptr(m.End-m.Start),
uintptr(prot),
)
if e1 != 0 {
return e1
}
return
}
// Perms are mmap(2)'s memory prot bitmask.
type Perms uint8
func (p Perms) String() string {
b := [4]byte{'-', '-', '-', 's'}
if p&None == 0 {
if p&Read != 0 {
b[0] = 'r'
}
if p&Write != 0 {
b[1] = 'w'
}
if p&Exec != 0 {
b[2] = 'x'
}
}
if p&Priv != 0 {
b[3] = 'p'
}
return string(b[:])
}
// Type indicates the type of mmaped region.
type Type uint8
const (
Unknown Type = iota
Data
Exe
Heap
Lib
Stack
VSDO
VSyscall
VVar
)
// ParseType parses s into a Type.
func ParseType(s string) Type {
return defaultProcess.ParseType(s)
}
func (t Type) String() string {
if int(t) < len(typeStrings) {
return typeStrings[t]
}
return typeStrings[0] // unknown
}
var typeStrings = [...]string{
Unknown: "unknown",
Data: "data",
Exe: "exe",
Heap: "[heap]",
Lib: "lib",
Stack: "[stack]",
VSDO: "[vsdo]",
VSyscall: "[vsyscall]",
VVar: "[vvar]",
}