golang.org/toolchain@v0.0.1-go1.9rc2.windows-amd64/src/cmd/vendor/github.com/google/pprof/internal/binutils/disasm.go (about) 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 "bytes" 19 "io" 20 "regexp" 21 "strconv" 22 23 "github.com/google/pprof/internal/plugin" 24 "github.com/ianlancetaylor/demangle" 25 ) 26 27 var ( 28 nmOutputRE = regexp.MustCompile(`^\s*([[:xdigit:]]+)\s+(.)\s+(.*)`) 29 objdumpAsmOutputRE = regexp.MustCompile(`^\s*([[:xdigit:]]+):\s+(.*)`) 30 objdumpOutputFileLine = regexp.MustCompile(`^(.*):([0-9]+)`) 31 objdumpOutputFunction = regexp.MustCompile(`^(\S.*)\(\):`) 32 ) 33 34 func findSymbols(syms []byte, file string, r *regexp.Regexp, address uint64) ([]*plugin.Sym, error) { 35 // Collect all symbols from the nm output, grouping names mapped to 36 // the same address into a single symbol. 37 var symbols []*plugin.Sym 38 names, start := []string{}, uint64(0) 39 buf := bytes.NewBuffer(syms) 40 for symAddr, name, err := nextSymbol(buf); err == nil; symAddr, name, err = nextSymbol(buf) { 41 if err != nil { 42 return nil, err 43 } 44 if start == symAddr { 45 names = append(names, name) 46 continue 47 } 48 if match := matchSymbol(names, start, symAddr-1, r, address); match != nil { 49 symbols = append(symbols, &plugin.Sym{Name: match, File: file, Start: start, End: symAddr - 1}) 50 } 51 names, start = []string{name}, symAddr 52 } 53 54 return symbols, nil 55 } 56 57 // matchSymbol checks if a symbol is to be selected by checking its 58 // name to the regexp and optionally its address. It returns the name(s) 59 // to be used for the matched symbol, or nil if no match 60 func matchSymbol(names []string, start, end uint64, r *regexp.Regexp, address uint64) []string { 61 if address != 0 && address >= start && address <= end { 62 return names 63 } 64 for _, name := range names { 65 if r.MatchString(name) { 66 return []string{name} 67 } 68 69 // Match all possible demangled versions of the name. 70 for _, o := range [][]demangle.Option{ 71 {demangle.NoClones}, 72 {demangle.NoParams}, 73 {demangle.NoParams, demangle.NoTemplateParams}, 74 } { 75 if demangled, err := demangle.ToString(name, o...); err == nil && r.MatchString(demangled) { 76 return []string{demangled} 77 } 78 } 79 } 80 return nil 81 } 82 83 // disassemble parses the output of the objdump command and returns 84 // the assembly instructions in a slice. 85 func disassemble(asm []byte) ([]plugin.Inst, error) { 86 buf := bytes.NewBuffer(asm) 87 function, file, line := "", "", 0 88 var assembly []plugin.Inst 89 for { 90 input, err := buf.ReadString('\n') 91 if err != nil { 92 if err != io.EOF { 93 return nil, err 94 } 95 if input == "" { 96 break 97 } 98 } 99 100 if fields := objdumpAsmOutputRE.FindStringSubmatch(input); len(fields) == 3 { 101 if address, err := strconv.ParseUint(fields[1], 16, 64); err == nil { 102 assembly = append(assembly, 103 plugin.Inst{ 104 Addr: address, 105 Text: fields[2], 106 Function: function, 107 File: file, 108 Line: line, 109 }) 110 continue 111 } 112 } 113 if fields := objdumpOutputFileLine.FindStringSubmatch(input); len(fields) == 3 { 114 if l, err := strconv.ParseUint(fields[2], 10, 32); err == nil { 115 file, line = fields[1], int(l) 116 } 117 continue 118 } 119 if fields := objdumpOutputFunction.FindStringSubmatch(input); len(fields) == 2 { 120 function = fields[1] 121 continue 122 } 123 // Reset on unrecognized lines. 124 function, file, line = "", "", 0 125 } 126 127 return assembly, nil 128 } 129 130 // nextSymbol parses the nm output to find the next symbol listed. 131 // Skips over any output it cannot recognize. 132 func nextSymbol(buf *bytes.Buffer) (uint64, string, error) { 133 for { 134 line, err := buf.ReadString('\n') 135 if err != nil { 136 if err != io.EOF || line == "" { 137 return 0, "", err 138 } 139 } 140 141 if fields := nmOutputRE.FindStringSubmatch(line); len(fields) == 4 { 142 if address, err := strconv.ParseUint(fields[1], 16, 64); err == nil { 143 return address, fields[3], nil 144 } 145 } 146 } 147 }