diff options
| -rw-r--r-- | pkg/symbolizer/nm.go | 84 |
1 files changed, 23 insertions, 61 deletions
diff --git a/pkg/symbolizer/nm.go b/pkg/symbolizer/nm.go index 626d08fd8..109df212b 100644 --- a/pkg/symbolizer/nm.go +++ b/pkg/symbolizer/nm.go @@ -4,11 +4,9 @@ package symbolizer import ( - "bufio" - "bytes" - "strconv" + "debug/elf" + "fmt" - "github.com/google/syzkaller/pkg/osutil" "github.com/google/syzkaller/sys/targets" ) @@ -19,80 +17,44 @@ type Symbol struct { // ReadTextSymbols returns list of text symbols in the binary bin. func (s *Symbolizer) ReadTextSymbols(bin string) (map[string][]Symbol, error) { - return read(s.target, bin, "t", "T") + return read(s.target, bin, true) } // ReadRodataSymbols returns list of rodata symbols in the binary bin. func (s *Symbolizer) ReadRodataSymbols(bin string) (map[string][]Symbol, error) { - return read(s.target, bin, "r", "R") + return read(s.target, bin, false) } -func read(target *targets.Target, bin string, types ...string) (map[string][]Symbol, error) { - if len(types) != 2 || len(types[0]) != 1 || len(types[1]) != 1 { - // We assume these things below. - panic("bad types") - } - nm := "nm" - if target != nil && target.Triple != "" { - nm = target.Triple + "-" + nm - } - cmd := osutil.Command(nm, "-Ptx", bin) - stdout, err := cmd.StdoutPipe() +func read(target *targets.Target, bin string, text bool) (map[string][]Symbol, error) { + file, err := elf.Open(bin) if err != nil { return nil, err } - defer stdout.Close() - if err := cmd.Start(); err != nil { - return nil, err + allSymbols, err := file.Symbols() + if err != nil { + return nil, fmt.Errorf("failed to read ELF symbols: %v", err) } - defer cmd.Wait() symbols := make(map[string][]Symbol) - s := bufio.NewScanner(stdout) - var tt [][]byte - for _, typ := range types { - tt = append(tt, []byte(" "+typ+" ")) - } - for s.Scan() { - // A line looks as: "snb_uncore_msr_enable_box t ffffffff8104db90 0000000000000059" - ln := s.Bytes() - if !bytes.Contains(ln, tt[0]) && !bytes.Contains(ln, tt[1]) { - continue - } - - sp1 := bytes.IndexByte(ln, ' ') - if sp1 == -1 { - continue - } - if !bytes.HasPrefix(ln[sp1:], tt[0]) && !bytes.HasPrefix(ln[sp1:], tt[1]) { - continue - } - - sp2 := sp1 + len(tt[0]) - sp3 := bytes.IndexByte(ln[sp2:], ' ') - if sp3 == -1 { - continue - } - sp3 += sp2 - - addr, err := strconv.ParseUint(string(ln[sp2:sp3]), 16, 64) - if err != nil { + for _, symb := range allSymbols { + if symb.Size == 0 || symb.Section < 0 || int(symb.Section) >= len(file.Sections) { continue } - - size, err := strconv.ParseUint(string(ln[sp3+1:]), 16, 64) - if err != nil || size == 0 { + sect := file.Sections[symb.Section] + isText := sect.Type == elf.SHT_PROGBITS && + sect.Flags&(elf.SHF_WRITE|elf.SHF_ALLOC|elf.SHF_EXECINSTR) == (elf.SHF_ALLOC|elf.SHF_EXECINSTR) + // Note: x86_64 vmlinux .rodata is marked as writable and according to flags it looks like .data, + // so we look at the name. + if text && !isText || !text && sect.Name != ".rodata" { continue } - - name := string(ln[:sp1]) - - // Note: sizes reported by kernel do not match nm. + // Note: function sizes reported by kernel do not match symbol tables. // Kernel probably subtracts address of this symbol from address of the next symbol. // We could do the same, but for now we just round up size to 16. - symbols[name] = append(symbols[name], Symbol{addr, int(size+15) / 16 * 16}) - } - if err := s.Err(); err != nil { - return nil, err + size := int(symb.Size) + if text { + size = (size + 15) / 16 * 16 + } + symbols[symb.Name] = append(symbols[symb.Name], Symbol{symb.Value, size}) } return symbols, nil } |
