golang.org/toolchain@v0.0.1-go1.9rc2.windows-amd64/src/cmd/vendor/github.com/google/pprof/internal/symbolz/symbolz.go (about) 1 // Copyright 2014 Google Inc. All Rights Reserved. 2 // 3 // Licensed under the Apache License, Version 2.0 (the "License"); 4 // you may not use this file except in compliance with the License. 5 // You may obtain a copy of the License at 6 // 7 // http://www.apache.org/licenses/LICENSE-2.0 8 // 9 // Unless required by applicable law or agreed to in writing, software 10 // distributed under the License is distributed on an "AS IS" BASIS, 11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 // See the License for the specific language governing permissions and 13 // limitations under the License. 14 15 // Package symbolz symbolizes a profile using the output from the symbolz 16 // service. 17 package symbolz 18 19 import ( 20 "bytes" 21 "fmt" 22 "io" 23 "net/url" 24 "path" 25 "regexp" 26 "strconv" 27 "strings" 28 29 "github.com/google/pprof/internal/plugin" 30 "github.com/google/pprof/profile" 31 ) 32 33 var ( 34 symbolzRE = regexp.MustCompile(`(0x[[:xdigit:]]+)\s+(.*)`) 35 ) 36 37 // Symbolize symbolizes profile p by parsing data returned by a 38 // symbolz handler. syms receives the symbolz query (hex addresses 39 // separated by '+') and returns the symbolz output in a string. It 40 // symbolizes all locations based on their addresses, regardless of 41 // mapping. 42 func Symbolize(sources plugin.MappingSources, syms func(string, string) ([]byte, error), p *profile.Profile, ui plugin.UI) error { 43 for _, m := range p.Mapping { 44 if m.HasFunctions { 45 continue 46 } 47 mappingSources := sources[m.File] 48 if m.BuildID != "" { 49 mappingSources = append(mappingSources, sources[m.BuildID]...) 50 } 51 for _, source := range mappingSources { 52 if symz := symbolz(source.Source); symz != "" { 53 if err := symbolizeMapping(symz, int64(source.Start)-int64(m.Start), syms, m, p); err != nil { 54 return err 55 } 56 m.HasFunctions = true 57 break 58 } 59 } 60 } 61 62 return nil 63 } 64 65 // symbolz returns the corresponding symbolz source for a profile URL. 66 func symbolz(source string) string { 67 if url, err := url.Parse(source); err == nil && url.Host != "" { 68 if strings.Contains(url.Path, "/") { 69 if dir := path.Dir(url.Path); dir == "/debug/pprof" { 70 // For Go language profile handlers in net/http/pprof package. 71 url.Path = "/debug/pprof/symbol" 72 } else { 73 url.Path = "/symbolz" 74 } 75 url.RawQuery = "" 76 return url.String() 77 } 78 } 79 80 return "" 81 } 82 83 // symbolizeMapping symbolizes locations belonging to a Mapping by querying 84 // a symbolz handler. An offset is applied to all addresses to take care of 85 // normalization occured for merged Mappings. 86 func symbolizeMapping(source string, offset int64, syms func(string, string) ([]byte, error), m *profile.Mapping, p *profile.Profile) error { 87 // Construct query of addresses to symbolize. 88 var a []string 89 for _, l := range p.Location { 90 if l.Mapping == m && l.Address != 0 && len(l.Line) == 0 { 91 // Compensate for normalization. 92 addr := int64(l.Address) + offset 93 if addr < 0 { 94 return fmt.Errorf("unexpected negative adjusted address, mapping %v source %d, offset %d", l.Mapping, l.Address, offset) 95 } 96 a = append(a, fmt.Sprintf("%#x", addr)) 97 } 98 } 99 100 if len(a) == 0 { 101 // No addresses to symbolize. 102 return nil 103 } 104 105 lines := make(map[uint64]profile.Line) 106 functions := make(map[string]*profile.Function) 107 108 b, err := syms(source, strings.Join(a, "+")) 109 if err != nil { 110 return err 111 } 112 113 buf := bytes.NewBuffer(b) 114 for { 115 l, err := buf.ReadString('\n') 116 117 if err != nil { 118 if err == io.EOF { 119 break 120 } 121 return err 122 } 123 124 if symbol := symbolzRE.FindStringSubmatch(l); len(symbol) == 3 { 125 addr, err := strconv.ParseInt(symbol[1], 0, 64) 126 if err != nil { 127 return fmt.Errorf("unexpected parse failure %s: %v", symbol[1], err) 128 } 129 if addr < 0 { 130 return fmt.Errorf("unexpected negative adjusted address, source %s, offset %d", symbol[1], offset) 131 } 132 // Reapply offset expected by the profile. 133 addr -= offset 134 135 name := symbol[2] 136 fn := functions[name] 137 if fn == nil { 138 fn = &profile.Function{ 139 ID: uint64(len(p.Function) + 1), 140 Name: name, 141 SystemName: name, 142 } 143 functions[name] = fn 144 p.Function = append(p.Function, fn) 145 } 146 147 lines[uint64(addr)] = profile.Line{Function: fn} 148 } 149 } 150 151 for _, l := range p.Location { 152 if l.Mapping != m { 153 continue 154 } 155 if line, ok := lines[l.Address]; ok { 156 l.Line = []profile.Line{line} 157 } 158 } 159 160 return nil 161 }