Source file
src/runtime/pprof/vminfo_darwin_test.go
1
2
3
4
5
6
7 package pprof
8
9 import (
10 "bufio"
11 "bytes"
12 "fmt"
13 "internal/abi"
14 "internal/testenv"
15 "os"
16 "os/exec"
17 "strconv"
18 "strings"
19 "testing"
20 "time"
21 )
22
23 func TestVMInfo(t *testing.T) {
24 var begin, end, offset uint64
25 var filename string
26 first := true
27 machVMInfo(func(lo, hi, off uint64, file, buildID string) {
28 if first {
29 begin = lo
30 end = hi
31 offset = off
32 filename = file
33 }
34
35
36 first = false
37 })
38 lo, hi, err := useVMMapWithRetry(t)
39 if err != nil {
40 t.Fatal(err)
41 }
42 if got, want := begin, lo; got != want {
43 t.Errorf("got %x, want %x", got, want)
44 }
45 if got, want := end, hi; got != want {
46 t.Errorf("got %x, want %x", got, want)
47 }
48 if got, want := offset, uint64(0); got != want {
49 t.Errorf("got %x, want %x", got, want)
50 }
51 if !strings.HasSuffix(filename, "pprof.test") {
52 t.Errorf("got %s, want pprof.test", filename)
53 }
54 addr := uint64(abi.FuncPCABIInternal(TestVMInfo))
55 if addr < lo || addr > hi {
56 t.Errorf("%x..%x does not contain function %p (%x)", lo, hi, TestVMInfo, addr)
57 }
58 }
59
60 type mapping struct {
61 hi, lo uint64
62 err error
63 }
64
65 func useVMMapWithRetry(t *testing.T) (hi, lo uint64, err error) {
66 var retryable bool
67 ch := make(chan mapping)
68 go func() {
69 for {
70 hi, lo, retryable, err = useVMMap(t)
71 if err == nil {
72 ch <- mapping{hi, lo, nil}
73 return
74 }
75 if !retryable {
76 ch <- mapping{0, 0, err}
77 return
78 }
79 t.Logf("retrying vmmap after error: %v", err)
80 }
81 }()
82 select {
83 case m := <-ch:
84 return m.hi, m.lo, m.err
85 case <-time.After(time.Minute):
86 t.Skip("vmmap taking too long")
87 }
88 return 0, 0, fmt.Errorf("unreachable")
89 }
90
91 func useVMMap(t *testing.T) (hi, lo uint64, retryable bool, err error) {
92 pid := strconv.Itoa(os.Getpid())
93 testenv.MustHaveExecPath(t, "vmmap")
94 cmd := testenv.Command(t, "vmmap", pid)
95 out, cmdErr := cmd.Output()
96 if cmdErr != nil {
97 t.Logf("vmmap output: %s", out)
98 if ee, ok := cmdErr.(*exec.ExitError); ok && len(ee.Stderr) > 0 {
99 t.Logf("%v: %v\n%s", cmd, cmdErr, ee.Stderr)
100 if testing.Short() && (strings.Contains(string(ee.Stderr), "No process corpse slots currently available, waiting to get one") || strings.Contains(string(ee.Stderr), "Failed to generate corpse from the process")) {
101 t.Skipf("Skipping knwn flake in short test mode")
102 }
103 retryable = bytes.Contains(ee.Stderr, []byte("resource shortage"))
104 }
105 t.Logf("%v: %v\n", cmd, cmdErr)
106 if retryable {
107 return 0, 0, true, cmdErr
108 }
109 }
110
111
112
113 hi, lo, err = parseVmmap(out)
114 if err != nil {
115 if cmdErr != nil {
116 return 0, 0, false, fmt.Errorf("failed to parse vmmap output, vmmap reported an error: %v", err)
117 }
118 t.Logf("vmmap output: %s", out)
119 return 0, 0, false, fmt.Errorf("failed to parse vmmap output, vmmap did not report an error: %v", err)
120 }
121 return hi, lo, false, nil
122 }
123
124
125 func parseVmmap(data []byte) (hi, lo uint64, err error) {
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 banner := "==== Non-writable regions for process"
166 grabbing := false
167 sc := bufio.NewScanner(bytes.NewReader(data))
168 for sc.Scan() {
169 l := sc.Text()
170 if grabbing {
171 p := strings.Fields(l)
172 if len(p) > 7 && p[0] == "__TEXT" && p[7] == "r-x/rwx" {
173 locs := strings.Split(p[1], "-")
174 start, _ := strconv.ParseUint(locs[0], 16, 64)
175 end, _ := strconv.ParseUint(locs[1], 16, 64)
176 return start, end, nil
177 }
178 }
179 if strings.HasPrefix(l, banner) {
180 grabbing = true
181 }
182 }
183 return 0, 0, fmt.Errorf("vmmap no text segment found")
184 }
185
View as plain text