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 )
21
22 func TestVMInfo(t *testing.T) {
23 var begin, end, offset uint64
24 var filename string
25 first := true
26 machVMInfo(func(lo, hi, off uint64, file, buildID string) {
27 if first {
28 begin = lo
29 end = hi
30 offset = off
31 filename = file
32 }
33
34
35 first = false
36 })
37 lo, hi, err := useVMMapWithRetry(t)
38 if err != nil {
39 t.Fatal(err)
40 }
41 if got, want := begin, lo; got != want {
42 t.Errorf("got %x, want %x", got, want)
43 }
44 if got, want := end, hi; got != want {
45 t.Errorf("got %x, want %x", got, want)
46 }
47 if got, want := offset, uint64(0); got != want {
48 t.Errorf("got %x, want %x", got, want)
49 }
50 if !strings.HasSuffix(filename, "pprof.test") {
51 t.Errorf("got %s, want pprof.test", filename)
52 }
53 addr := uint64(abi.FuncPCABIInternal(TestVMInfo))
54 if addr < lo || addr > hi {
55 t.Errorf("%x..%x does not contain function %p (%x)", lo, hi, TestVMInfo, addr)
56 }
57 }
58
59 func useVMMapWithRetry(t *testing.T) (hi, lo uint64, err error) {
60 var retryable bool
61 for {
62 hi, lo, retryable, err = useVMMap(t)
63 if err == nil {
64 return hi, lo, nil
65 }
66 if !retryable {
67 return 0, 0, err
68 }
69 t.Logf("retrying vmmap after error: %v", err)
70 }
71 }
72
73 func useVMMap(t *testing.T) (hi, lo uint64, retryable bool, err error) {
74 pid := strconv.Itoa(os.Getpid())
75 testenv.MustHaveExecPath(t, "vmmap")
76 cmd := testenv.Command(t, "vmmap", pid)
77 out, cmdErr := cmd.Output()
78 if cmdErr != nil {
79 t.Logf("vmmap output: %s", out)
80 if ee, ok := cmdErr.(*exec.ExitError); ok && len(ee.Stderr) > 0 {
81 t.Logf("%v: %v\n%s", cmd, cmdErr, ee.Stderr)
82 if testing.Short() && strings.Contains(string(ee.Stderr), "No process corpse slots currently available, waiting to get one") {
83 t.Skipf("Skipping knwn flake in short test mode")
84 }
85 retryable = bytes.Contains(ee.Stderr, []byte("resource shortage"))
86 }
87 t.Logf("%v: %v\n", cmd, cmdErr)
88 if retryable {
89 return 0, 0, true, cmdErr
90 }
91 }
92
93
94
95 hi, lo, err = parseVmmap(out)
96 if err != nil {
97 if cmdErr != nil {
98 return 0, 0, false, fmt.Errorf("failed to parse vmmap output, vmmap reported an error: %v", err)
99 }
100 t.Logf("vmmap output: %s", out)
101 return 0, 0, false, fmt.Errorf("failed to parse vmmap output, vmmap did not report an error: %v", err)
102 }
103 return hi, lo, false, nil
104 }
105
106
107 func parseVmmap(data []byte) (hi, lo uint64, err error) {
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 banner := "==== Non-writable regions for process"
148 grabbing := false
149 sc := bufio.NewScanner(bytes.NewReader(data))
150 for sc.Scan() {
151 l := sc.Text()
152 if grabbing {
153 p := strings.Fields(l)
154 if len(p) > 7 && p[0] == "__TEXT" && p[7] == "r-x/rwx" {
155 locs := strings.Split(p[1], "-")
156 start, _ := strconv.ParseUint(locs[0], 16, 64)
157 end, _ := strconv.ParseUint(locs[1], 16, 64)
158 return start, end, nil
159 }
160 }
161 if strings.HasPrefix(l, banner) {
162 grabbing = true
163 }
164 }
165 return 0, 0, fmt.Errorf("vmmap no text segment found")
166 }
167
View as plain text