mirror of
https://github.com/reactos/syzkaller.git
synced 2024-11-28 13:50:52 +00:00
c4d43f4773
When manager is stopped there are sometimes runaway qemu processes still running. Set PDEATHSIG for all subprocesses. We never need child processes outliving parents.
194 lines
4.0 KiB
Go
194 lines
4.0 KiB
Go
// Copyright 2016 syzkaller project authors. All rights reserved.
|
|
// Use of this source code is governed by Apache 2 LICENSE that can be found in the LICENSE file.
|
|
|
|
// TODO: strip " (discriminator N)", "constprop", "isra" from function names
|
|
|
|
package symbolizer
|
|
|
|
import (
|
|
"bufio"
|
|
"fmt"
|
|
"io"
|
|
"os/exec"
|
|
"strconv"
|
|
"strings"
|
|
|
|
"github.com/google/syzkaller/pkg/osutil"
|
|
)
|
|
|
|
type Symbolizer struct {
|
|
subprocs map[string]*subprocess
|
|
}
|
|
|
|
type Frame struct {
|
|
PC uint64
|
|
Func string
|
|
File string
|
|
Line int
|
|
Inline bool
|
|
}
|
|
|
|
type subprocess struct {
|
|
cmd *exec.Cmd
|
|
stdin io.Closer
|
|
stdout io.Closer
|
|
input *bufio.Writer
|
|
scanner *bufio.Scanner
|
|
}
|
|
|
|
func NewSymbolizer() *Symbolizer {
|
|
return &Symbolizer{}
|
|
}
|
|
|
|
func (s *Symbolizer) Symbolize(bin string, pc uint64) ([]Frame, error) {
|
|
return s.SymbolizeArray(bin, []uint64{pc})
|
|
}
|
|
|
|
func (s *Symbolizer) SymbolizeArray(bin string, pcs []uint64) ([]Frame, error) {
|
|
sub, err := s.getSubprocess(bin)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
return symbolize(sub.input, sub.scanner, pcs)
|
|
}
|
|
|
|
func (s *Symbolizer) Close() {
|
|
for _, sub := range s.subprocs {
|
|
sub.stdin.Close()
|
|
sub.stdout.Close()
|
|
sub.cmd.Process.Kill()
|
|
sub.cmd.Wait()
|
|
}
|
|
}
|
|
|
|
func (s *Symbolizer) getSubprocess(bin string) (*subprocess, error) {
|
|
if sub := s.subprocs[bin]; sub != nil {
|
|
return sub, nil
|
|
}
|
|
cmd := osutil.Command("addr2line", "-afi", "-e", bin)
|
|
stdin, err := cmd.StdinPipe()
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
stdout, err := cmd.StdoutPipe()
|
|
if err != nil {
|
|
stdin.Close()
|
|
return nil, err
|
|
}
|
|
if err := cmd.Start(); err != nil {
|
|
stdin.Close()
|
|
stdout.Close()
|
|
return nil, err
|
|
}
|
|
sub := &subprocess{
|
|
cmd: cmd,
|
|
stdin: stdin,
|
|
stdout: stdout,
|
|
input: bufio.NewWriter(stdin),
|
|
scanner: bufio.NewScanner(stdout),
|
|
}
|
|
if s.subprocs == nil {
|
|
s.subprocs = make(map[string]*subprocess)
|
|
}
|
|
s.subprocs[bin] = sub
|
|
return sub, nil
|
|
}
|
|
|
|
func symbolize(input *bufio.Writer, scanner *bufio.Scanner, pcs []uint64) ([]Frame, error) {
|
|
var frames []Frame
|
|
done := make(chan error, 1)
|
|
go func() {
|
|
var err error
|
|
defer func() {
|
|
done <- err
|
|
}()
|
|
if !scanner.Scan() {
|
|
if err = scanner.Err(); err == nil {
|
|
err = io.EOF
|
|
}
|
|
return
|
|
}
|
|
for range pcs {
|
|
var frames1 []Frame
|
|
frames1, err = parse(scanner)
|
|
if err != nil {
|
|
return
|
|
}
|
|
frames = append(frames, frames1...)
|
|
}
|
|
for i := 0; i < 2; i++ {
|
|
scanner.Scan()
|
|
}
|
|
}()
|
|
|
|
for _, pc := range pcs {
|
|
if _, err := fmt.Fprintf(input, "0x%x\n", pc); err != nil {
|
|
return nil, err
|
|
}
|
|
}
|
|
// Write an invalid PC so that parse doesn't block reading input.
|
|
// We read out result for this PC at the end of the function.
|
|
if _, err := fmt.Fprintf(input, "0xffffffffffffffff\n"); err != nil {
|
|
return nil, err
|
|
}
|
|
input.Flush()
|
|
|
|
if err := <-done; err != nil {
|
|
return nil, err
|
|
}
|
|
return frames, nil
|
|
}
|
|
|
|
func parse(s *bufio.Scanner) ([]Frame, error) {
|
|
pc, err := strconv.ParseUint(s.Text(), 0, 64)
|
|
if err != nil {
|
|
return nil, fmt.Errorf("failed to parse pc '%v' in addr2line output: %v", s.Text(), err)
|
|
}
|
|
var frames []Frame
|
|
for {
|
|
if !s.Scan() {
|
|
break
|
|
}
|
|
ln := s.Text()
|
|
if len(ln) > 3 && ln[0] == '0' && ln[1] == 'x' {
|
|
break
|
|
}
|
|
fn := ln
|
|
if !s.Scan() {
|
|
err := s.Err()
|
|
if err == nil {
|
|
err = io.EOF
|
|
}
|
|
return nil, fmt.Errorf("failed to read file:line from addr2line: %v", err)
|
|
}
|
|
ln = s.Text()
|
|
colon := strings.LastIndexByte(ln, ':')
|
|
if colon == -1 {
|
|
return nil, fmt.Errorf("failed to parse file:line in addr2line output: %v", ln)
|
|
}
|
|
lineEnd := colon + 1
|
|
for lineEnd < len(ln) && ln[lineEnd] >= '0' && ln[lineEnd] <= '9' {
|
|
lineEnd++
|
|
}
|
|
file := ln[:colon]
|
|
line, err := strconv.Atoi(ln[colon+1 : lineEnd])
|
|
if err != nil || fn == "" || fn == "??" || file == "" || file == "??" || line <= 0 {
|
|
continue
|
|
}
|
|
frames = append(frames, Frame{
|
|
PC: pc,
|
|
Func: fn,
|
|
File: file,
|
|
Line: line,
|
|
Inline: true,
|
|
})
|
|
}
|
|
if err := s.Err(); err != nil {
|
|
return nil, err
|
|
}
|
|
if len(frames) != 0 {
|
|
frames[len(frames)-1].Inline = false
|
|
}
|
|
return frames, nil
|
|
}
|