| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| |
|
| | package binutils |
| |
|
| | import ( |
| | "bytes" |
| | "io" |
| | "regexp" |
| | "strconv" |
| | "strings" |
| |
|
| | "github.com/google/pprof/internal/plugin" |
| | "github.com/ianlancetaylor/demangle" |
| | ) |
| |
|
| | var ( |
| | nmOutputRE = regexp.MustCompile(`^\s*([[:xdigit:]]+)\s+(.)\s+(.*)`) |
| | objdumpAsmOutputRE = regexp.MustCompile(`^\s*([[:xdigit:]]+):\s+(.*)`) |
| | objdumpOutputFileLine = regexp.MustCompile(`^;?\s?(.*):([0-9]+)`) |
| | objdumpOutputFunction = regexp.MustCompile(`^;?\s?(\S.*)\(\):`) |
| | objdumpOutputFunctionLLVM = regexp.MustCompile(`^([[:xdigit:]]+)?\s?(.*):`) |
| | ) |
| |
|
| | func findSymbols(syms []byte, file string, r *regexp.Regexp, address uint64) ([]*plugin.Sym, error) { |
| | |
| | |
| |
|
| | |
| | var symbols []*plugin.Sym |
| |
|
| | |
| | names, start := []string{}, uint64(0) |
| |
|
| | buf := bytes.NewBuffer(syms) |
| |
|
| | for { |
| | symAddr, name, err := nextSymbol(buf) |
| | if err == io.EOF { |
| | |
| | if len(names) != 0 { |
| | if match := matchSymbol(names, start, symAddr-1, r, address); match != nil { |
| | symbols = append(symbols, &plugin.Sym{Name: match, File: file, Start: start, End: symAddr - 1}) |
| | } |
| | } |
| |
|
| | |
| | return symbols, nil |
| | } |
| |
|
| | if err != nil { |
| | |
| | return nil, err |
| | } |
| |
|
| | |
| | if symAddr == start { |
| | names = append(names, name) |
| | continue |
| | } |
| |
|
| | |
| | if match := matchSymbol(names, start, symAddr-1, r, address); match != nil { |
| | symbols = append(symbols, &plugin.Sym{Name: match, File: file, Start: start, End: symAddr - 1}) |
| | } |
| |
|
| | |
| | names, start = []string{name}, symAddr |
| | } |
| | } |
| |
|
| | |
| | |
| | |
| | func matchSymbol(names []string, start, end uint64, r *regexp.Regexp, address uint64) []string { |
| | if address != 0 && address >= start && address <= end { |
| | return names |
| | } |
| | for _, name := range names { |
| | if r == nil || r.MatchString(name) { |
| | return []string{name} |
| | } |
| |
|
| | |
| | for _, o := range [][]demangle.Option{ |
| | {demangle.NoClones}, |
| | {demangle.NoParams, demangle.NoEnclosingParams}, |
| | {demangle.NoParams, demangle.NoEnclosingParams, demangle.NoTemplateParams}, |
| | } { |
| | if demangled, err := demangle.ToString(name, o...); err == nil && r.MatchString(demangled) { |
| | return []string{demangled} |
| | } |
| | } |
| | } |
| | return nil |
| | } |
| |
|
| | |
| | |
| | func disassemble(asm []byte) ([]plugin.Inst, error) { |
| | buf := bytes.NewBuffer(asm) |
| | function, file, line := "", "", 0 |
| | var assembly []plugin.Inst |
| | for { |
| | input, err := buf.ReadString('\n') |
| | if err != nil { |
| | if err != io.EOF { |
| | return nil, err |
| | } |
| | if input == "" { |
| | break |
| | } |
| | } |
| | input = strings.TrimSpace(input) |
| |
|
| | if fields := objdumpAsmOutputRE.FindStringSubmatch(input); len(fields) == 3 { |
| | if address, err := strconv.ParseUint(fields[1], 16, 64); err == nil { |
| | assembly = append(assembly, |
| | plugin.Inst{ |
| | Addr: address, |
| | Text: fields[2], |
| | Function: function, |
| | File: file, |
| | Line: line, |
| | }) |
| | continue |
| | } |
| | } |
| | if fields := objdumpOutputFileLine.FindStringSubmatch(input); len(fields) == 3 { |
| | if l, err := strconv.ParseUint(fields[2], 10, 32); err == nil { |
| | file, line = fields[1], int(l) |
| | } |
| | continue |
| | } |
| | if fields := objdumpOutputFunction.FindStringSubmatch(input); len(fields) == 2 { |
| | function = fields[1] |
| | continue |
| | } else { |
| | if fields := objdumpOutputFunctionLLVM.FindStringSubmatch(input); len(fields) == 3 { |
| | function = fields[2] |
| | continue |
| | } |
| | } |
| | |
| | function, file, line = "", "", 0 |
| | } |
| |
|
| | return assembly, nil |
| | } |
| |
|
| | |
| | |
| | func nextSymbol(buf *bytes.Buffer) (uint64, string, error) { |
| | for { |
| | line, err := buf.ReadString('\n') |
| | if err != nil { |
| | if err != io.EOF || line == "" { |
| | return 0, "", err |
| | } |
| | } |
| | line = strings.TrimSpace(line) |
| |
|
| | if fields := nmOutputRE.FindStringSubmatch(line); len(fields) == 4 { |
| | if address, err := strconv.ParseUint(fields[1], 16, 64); err == nil { |
| | return address, fields[3], nil |
| | } |
| | } |
| | } |
| | } |
| |
|