"Fossies" - the Fresh Open Source Software Archive

Member "go/src/cmd/vendor/github.com/google/pprof/internal/binutils/addr2liner_llvm.go" (9 Sep 2020, 3923 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     "fmt"
   20     "io"
   21     "os/exec"
   22     "strconv"
   23     "strings"
   24     "sync"
   25 
   26     "github.com/google/pprof/internal/plugin"
   27 )
   28 
   29 const (
   30     defaultLLVMSymbolizer = "llvm-symbolizer"
   31 )
   32 
   33 // llvmSymbolizer is a connection to an llvm-symbolizer command for
   34 // obtaining address and line number information from a binary.
   35 type llvmSymbolizer struct {
   36     sync.Mutex
   37     filename string
   38     rw       lineReaderWriter
   39     base     uint64
   40 }
   41 
   42 type llvmSymbolizerJob struct {
   43     cmd *exec.Cmd
   44     in  io.WriteCloser
   45     out *bufio.Reader
   46 }
   47 
   48 func (a *llvmSymbolizerJob) write(s string) error {
   49     _, err := fmt.Fprint(a.in, s+"\n")
   50     return err
   51 }
   52 
   53 func (a *llvmSymbolizerJob) readLine() (string, error) {
   54     return a.out.ReadString('\n')
   55 }
   56 
   57 // close releases any resources used by the llvmSymbolizer object.
   58 func (a *llvmSymbolizerJob) close() {
   59     a.in.Close()
   60     a.cmd.Wait()
   61 }
   62 
   63 // newLlvmSymbolizer starts the given llvmSymbolizer command reporting
   64 // information about the given executable file. If file is a shared
   65 // library, base should be the address at which it was mapped in the
   66 // program under consideration.
   67 func newLLVMSymbolizer(cmd, file string, base uint64) (*llvmSymbolizer, error) {
   68     if cmd == "" {
   69         cmd = defaultLLVMSymbolizer
   70     }
   71 
   72     j := &llvmSymbolizerJob{
   73         cmd: exec.Command(cmd, "-inlining", "-demangle=false"),
   74     }
   75 
   76     var err error
   77     if j.in, err = j.cmd.StdinPipe(); err != nil {
   78         return nil, err
   79     }
   80 
   81     outPipe, err := j.cmd.StdoutPipe()
   82     if err != nil {
   83         return nil, err
   84     }
   85 
   86     j.out = bufio.NewReader(outPipe)
   87     if err := j.cmd.Start(); err != nil {
   88         return nil, err
   89     }
   90 
   91     a := &llvmSymbolizer{
   92         filename: file,
   93         rw:       j,
   94         base:     base,
   95     }
   96 
   97     return a, nil
   98 }
   99 
  100 func (d *llvmSymbolizer) readString() (string, error) {
  101     s, err := d.rw.readLine()
  102     if err != nil {
  103         return "", err
  104     }
  105     return strings.TrimSpace(s), nil
  106 }
  107 
  108 // readFrame parses the llvm-symbolizer output for a single address. It
  109 // returns a populated plugin.Frame and whether it has reached the end of the
  110 // data.
  111 func (d *llvmSymbolizer) readFrame() (plugin.Frame, bool) {
  112     funcname, err := d.readString()
  113     if err != nil {
  114         return plugin.Frame{}, true
  115     }
  116 
  117     switch funcname {
  118     case "":
  119         return plugin.Frame{}, true
  120     case "??":
  121         funcname = ""
  122     }
  123 
  124     fileline, err := d.readString()
  125     if err != nil {
  126         return plugin.Frame{Func: funcname}, true
  127     }
  128 
  129     linenumber := 0
  130     if fileline == "??:0" {
  131         fileline = ""
  132     } else {
  133         switch split := strings.Split(fileline, ":"); len(split) {
  134         case 1:
  135             // filename
  136             fileline = split[0]
  137         case 2, 3:
  138             // filename:line , or
  139             // filename:line:disc , or
  140             fileline = split[0]
  141             if line, err := strconv.Atoi(split[1]); err == nil {
  142                 linenumber = line
  143             }
  144         default:
  145             // Unrecognized, ignore
  146         }
  147     }
  148 
  149     return plugin.Frame{Func: funcname, File: fileline, Line: linenumber}, false
  150 }
  151 
  152 // addrInfo returns the stack frame information for a specific program
  153 // address. It returns nil if the address could not be identified.
  154 func (d *llvmSymbolizer) addrInfo(addr uint64) ([]plugin.Frame, error) {
  155     d.Lock()
  156     defer d.Unlock()
  157 
  158     if err := d.rw.write(fmt.Sprintf("%s 0x%x", d.filename, addr-d.base)); err != nil {
  159         return nil, err
  160     }
  161 
  162     var stack []plugin.Frame
  163     for {
  164         frame, end := d.readFrame()
  165         if end {
  166             break
  167         }
  168 
  169         if frame != (plugin.Frame{}) {
  170             stack = append(stack, frame)
  171         }
  172     }
  173 
  174     return stack, nil
  175 }