github.com/razvanm/vanadium-go-1.3@v0.0.0-20160721203343-4a65068e5915/src/cmd/pprof/internal/symbolz/symbolz.go (about)

     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 *profile.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 failure %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.Function) + 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  }