LEFT | RIGHT |
(no file at all) | |
| 1 // Copyright 2014 The Go Authors. All rights reserved. |
| 2 // Use of this source code is governed by a BSD-style |
| 3 // license that can be found in the LICENSE file. |
| 4 |
| 5 // Package symbolz symbolizes a profile using the output from the symbolz |
| 6 // service. |
| 7 package symbolz |
| 8 |
| 9 import ( |
| 10 "bytes" |
| 11 "fmt" |
| 12 "io" |
| 13 "net/url" |
| 14 "regexp" |
| 15 "strconv" |
| 16 "strings" |
| 17 |
| 18 "cmd/pprof/internal/profile" |
| 19 ) |
| 20 |
| 21 var ( |
| 22 symbolzRE = regexp.MustCompile(`(0x[[:xdigit:]]+)\s+(.*)`) |
| 23 ) |
| 24 |
| 25 // Symbolize symbolizes profile p by parsing data returned by a |
| 26 // symbolz handler. syms receives the symbolz query (hex addresses |
| 27 // separated by '+') and returns the symbolz output in a string. It |
| 28 // symbolizes all locations based on their addresses, regardless of |
| 29 // mapping. |
| 30 func Symbolize(source string, syms func(string, string) ([]byte, error), p *prof
ile.Profile) error { |
| 31 if source = symbolz(source, p); source == "" { |
| 32 // If the source is not a recognizable URL, do nothing. |
| 33 return nil |
| 34 } |
| 35 |
| 36 // Construct query of addresses to symbolize. |
| 37 var a []string |
| 38 for _, l := range p.Location { |
| 39 if l.Address != 0 && len(l.Line) == 0 { |
| 40 a = append(a, fmt.Sprintf("%#x", l.Address)) |
| 41 } |
| 42 } |
| 43 |
| 44 if len(a) == 0 { |
| 45 // No addresses to symbolize. |
| 46 return nil |
| 47 } |
| 48 lines := make(map[uint64]profile.Line) |
| 49 functions := make(map[string]*profile.Function) |
| 50 if b, err := syms(source, strings.Join(a, "+")); err == nil { |
| 51 buf := bytes.NewBuffer(b) |
| 52 for { |
| 53 l, err := buf.ReadString('\n') |
| 54 |
| 55 if err != nil { |
| 56 if err == io.EOF { |
| 57 break |
| 58 } |
| 59 return err |
| 60 } |
| 61 |
| 62 if symbol := symbolzRE.FindStringSubmatch(l); len(symbol
) == 3 { |
| 63 addr, err := strconv.ParseUint(symbol[1], 0, 64) |
| 64 if err != nil { |
| 65 return fmt.Errorf("unexpected parse fail
ure %s: %v", symbol[1], err) |
| 66 } |
| 67 |
| 68 name := symbol[2] |
| 69 fn := functions[name] |
| 70 if fn == nil { |
| 71 fn = &profile.Function{ |
| 72 ID: uint64(len(p.Functio
n) + 1), |
| 73 Name: name, |
| 74 SystemName: name, |
| 75 } |
| 76 functions[name] = fn |
| 77 p.Function = append(p.Function, fn) |
| 78 } |
| 79 |
| 80 lines[addr] = profile.Line{Function: fn} |
| 81 } |
| 82 } |
| 83 } |
| 84 |
| 85 for _, l := range p.Location { |
| 86 if line, ok := lines[l.Address]; ok { |
| 87 l.Line = []profile.Line{line} |
| 88 if l.Mapping != nil { |
| 89 l.Mapping.HasFunctions = true |
| 90 } |
| 91 } |
| 92 } |
| 93 |
| 94 return nil |
| 95 } |
| 96 |
| 97 // symbolz returns the corresponding symbolz source for a profile URL. |
| 98 func symbolz(source string, p *profile.Profile) string { |
| 99 if url, err := url.Parse(source); err == nil && url.Host != "" { |
| 100 if last := strings.LastIndex(url.Path, "/"); last != -1 { |
| 101 if strings.HasSuffix(url.Path[:last], "pprof") { |
| 102 url.Path = url.Path[:last] + "/symbol" |
| 103 } else { |
| 104 url.Path = url.Path[:last] + "/symbolz" |
| 105 } |
| 106 return url.String() |
| 107 } |
| 108 } |
| 109 |
| 110 return "" |
| 111 } |
LEFT | RIGHT |