Black Lives Matter. Support the Equal Justice Initiative.

Source file src/cmd/vendor/github.com/google/pprof/internal/binutils/addr2liner_nm.go

Documentation: cmd/vendor/github.com/google/pprof/internal/binutils

     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 binutils
    16  
    17  import (
    18  	"bufio"
    19  	"bytes"
    20  	"io"
    21  	"os/exec"
    22  	"strconv"
    23  	"strings"
    24  
    25  	"github.com/google/pprof/internal/plugin"
    26  )
    27  
    28  const (
    29  	defaultNM = "nm"
    30  )
    31  
    32  // addr2LinerNM is a connection to an nm command for obtaining address
    33  // information from a binary.
    34  type addr2LinerNM struct {
    35  	m []symbolInfo // Sorted list of addresses from binary.
    36  }
    37  
    38  type symbolInfo struct {
    39  	address uint64
    40  	name    string
    41  }
    42  
    43  //  newAddr2LinerNM starts the given nm command reporting information about the
    44  // given executable file. If file is a shared library, base should be
    45  // the address at which it was mapped in the program under
    46  // consideration.
    47  func newAddr2LinerNM(cmd, file string, base uint64) (*addr2LinerNM, error) {
    48  	if cmd == "" {
    49  		cmd = defaultNM
    50  	}
    51  	var b bytes.Buffer
    52  	c := exec.Command(cmd, "-n", file)
    53  	c.Stdout = &b
    54  	if err := c.Run(); err != nil {
    55  		return nil, err
    56  	}
    57  	return parseAddr2LinerNM(base, &b)
    58  }
    59  
    60  func parseAddr2LinerNM(base uint64, nm io.Reader) (*addr2LinerNM, error) {
    61  	a := &addr2LinerNM{
    62  		m: []symbolInfo{},
    63  	}
    64  
    65  	// Parse nm output and populate symbol map.
    66  	// Skip lines we fail to parse.
    67  	buf := bufio.NewReader(nm)
    68  	for {
    69  		line, err := buf.ReadString('\n')
    70  		if line == "" && err != nil {
    71  			if err == io.EOF {
    72  				break
    73  			}
    74  			return nil, err
    75  		}
    76  		line = strings.TrimSpace(line)
    77  		fields := strings.SplitN(line, " ", 3)
    78  		if len(fields) != 3 {
    79  			continue
    80  		}
    81  		address, err := strconv.ParseUint(fields[0], 16, 64)
    82  		if err != nil {
    83  			continue
    84  		}
    85  		a.m = append(a.m, symbolInfo{
    86  			address: address + base,
    87  			name:    fields[2],
    88  		})
    89  	}
    90  
    91  	return a, nil
    92  }
    93  
    94  // addrInfo returns the stack frame information for a specific program
    95  // address. It returns nil if the address could not be identified.
    96  func (a *addr2LinerNM) addrInfo(addr uint64) ([]plugin.Frame, error) {
    97  	if len(a.m) == 0 || addr < a.m[0].address || addr > a.m[len(a.m)-1].address {
    98  		return nil, nil
    99  	}
   100  
   101  	// Binary search. Search until low, high are separated by 1.
   102  	low, high := 0, len(a.m)
   103  	for low+1 < high {
   104  		mid := (low + high) / 2
   105  		v := a.m[mid].address
   106  		if addr == v {
   107  			low = mid
   108  			break
   109  		} else if addr > v {
   110  			low = mid
   111  		} else {
   112  			high = mid
   113  		}
   114  	}
   115  
   116  	// Address is between a.m[low] and a.m[high].
   117  	// Pick low, as it represents [low, high).
   118  	f := []plugin.Frame{
   119  		{
   120  			Func: a.m[low].name,
   121  		},
   122  	}
   123  	return f, nil
   124  }
   125  

View as plain text