"Fossies" - the Fresh Open Source Software Archive

Member "go/src/cmd/vendor/github.com/google/pprof/internal/binutils/addr2liner_nm.go" (9 Sep 2020, 2940 Bytes) of package /windows/misc/go1.14.9.windows-386.zip:


As a special service "Fossies" has tried to format the requested source page into HTML format using (guessed) Go source code syntax highlighting (style: standard) with prefixed line numbers and code folding option. Alternatively you can here view or download the uninterpreted source code file.

    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 }