1// Copyright 2016 syzkaller project authors. All rights reserved. 2// Use of this source code is governed by Apache 2 LICENSE that can be found in the LICENSE file. 3 4package symbolizer 5 6import ( 7 "bufio" 8 "bytes" 9 "strconv" 10 11 "github.com/google/syzkaller/pkg/osutil" 12) 13 14type Symbol struct { 15 Addr uint64 16 Size int 17} 18 19// ReadSymbols returns list of text symbols in the binary bin. 20func ReadSymbols(bin string) (map[string][]Symbol, error) { 21 cmd := osutil.Command("nm", "-nS", bin) 22 stdout, err := cmd.StdoutPipe() 23 if err != nil { 24 return nil, err 25 } 26 defer stdout.Close() 27 if err := cmd.Start(); err != nil { 28 return nil, err 29 } 30 defer cmd.Wait() 31 symbols := make(map[string][]Symbol) 32 s := bufio.NewScanner(stdout) 33 text := [][]byte{[]byte(" t "), []byte(" T ")} 34 for s.Scan() { 35 // A line looks as: "ffffffff8104db90 0000000000000059 t snb_uncore_msr_enable_box" 36 ln := s.Bytes() 37 if !bytes.Contains(ln, text[0]) && !bytes.Contains(ln, text[1]) { 38 continue 39 } 40 sp1 := bytes.IndexByte(ln, ' ') 41 if sp1 == -1 { 42 continue 43 } 44 sp2 := bytes.IndexByte(ln[sp1+1:], ' ') 45 if sp2 == -1 { 46 continue 47 } 48 sp2 += sp1 + 1 49 if !bytes.HasPrefix(ln[sp2:], text[0]) && !bytes.HasPrefix(ln[sp2:], text[1]) { 50 continue 51 } 52 addr, err := strconv.ParseUint(string(ln[:sp1]), 16, 64) 53 if err != nil { 54 continue 55 } 56 size, err := strconv.ParseUint(string(ln[sp1+1:sp2]), 16, 64) 57 if err != nil { 58 continue 59 } 60 name := string(ln[sp2+len(text[0]):]) 61 // Note: sizes reported by kernel do not match nm. 62 // Kernel probably subtracts address of this symbol from address of the next symbol. 63 // We could do the same, but for now we just round up size to 16. 64 symbols[name] = append(symbols[name], Symbol{addr, int(size+15) / 16 * 16}) 65 } 66 if err := s.Err(); err != nil { 67 return nil, err 68 } 69 return symbols, nil 70} 71