Ejemplo n.º 1
0
func main() {
	flag.Parse()
	data, err := ioutil.ReadFile(*flagProg)
	if err != nil {
		fmt.Fprintf(os.Stderr, "failed to read prog file: %v\n", err)
		os.Exit(1)
	}
	p, err := prog.Deserialize(data)
	if err != nil {
		fmt.Fprintf(os.Stderr, "failed to deserialize the program: %v\n", err)
		os.Exit(1)
	}
	var flags uint64
	if *flagThreaded {
		flags |= ipc.FlagThreaded
	}
	if *flagDebug {
		flags |= ipc.FlagDebug
	}
	if *flagStrace {
		flags |= ipc.FlagStrace
	}
	if *flagCover != "" {
		flags |= ipc.FlagCover
	}
	if *flagDedup {
		flags |= ipc.FlagDedupCover
	}
	env, err := ipc.MakeEnv(*flagExecutor, *flagTimeout, flags)
	if err != nil {
		fmt.Fprintf(os.Stderr, "failed to create execution environment: %v\n", err)
		os.Exit(1)
	}
	defer env.Close()
	output, strace, cov, failed, hanged, err := env.Exec(p)
	fmt.Printf("result: failed=%v hanged=%v err=%v\n\n%s", failed, hanged, err, output)
	if *flagStrace {
		fmt.Printf("strace output:\n%s", strace)
	}
	// Coverage is dumped in sanitizer format.
	// github.com/google/sanitizers/tools/sancov command can be used to dump PCs,
	// then they can be piped via addr2line to symbolize.
	for i, c := range cov {
		fmt.Printf("call #%v: coverage %v\n", i, len(c))
		if len(c) == 0 {
			continue
		}
		buf := new(bytes.Buffer)
		binary.Write(buf, binary.LittleEndian, uint64(0xC0BFFFFFFFFFFF64))
		for _, pc := range c {
			binary.Write(buf, binary.LittleEndian, cover.RestorePC(pc))
		}
		err := ioutil.WriteFile(fmt.Sprintf("%v.%v", *flagCover, i), buf.Bytes(), 0660)
		if err != nil {
			fmt.Fprintf(os.Stderr, "failed to write coverage file: %v\n", err)
			os.Exit(1)
		}
	}
}
Ejemplo n.º 2
0
func symbolize(vmlinux string, cov []uint32) error {
	cmd := exec.Command("addr2line", "-a", "-i", "-e", vmlinux)
	stdin, err := cmd.StdinPipe()
	if err != nil {
		return err
	}
	defer stdin.Close()
	stdout, err := cmd.StdoutPipe()
	if err != nil {
		return err
	}
	defer stdout.Close()
	if err := cmd.Start(); err != nil {
		return err
	}
	defer cmd.Wait()
	go func() {
		for _, pc := range cov {
			fmt.Fprintf(stdin, "0x%x\n", cover.RestorePC(pc)-1)
		}
		stdin.Close()
	}()
	s := bufio.NewScanner(stdout)
	var pc uint32
	for s.Scan() {
		ln := s.Text()
		if len(ln) > 3 && ln[0] == '0' && ln[1] == 'x' {
			v, err := strconv.ParseUint(ln, 0, 64)
			if err != nil {
				return fmt.Errorf("failed to parse pc in addr2line output: %v", err)
			}
			pc = uint32(v) + 1
			continue
		}
		colon := strings.IndexByte(ln, ':')
		if colon == -1 {
			continue
		}
		file := ln[:colon]
		line, err := strconv.Atoi(ln[colon+1:])
		if err != nil || pc == 0 || file == "" || file == "??" || line <= 0 {
			continue
		}
		pcLines[pc] = append(pcLines[pc], LineInfo{file, line})
	}
	if err := s.Err(); err != nil {
		return err
	}
	return nil
}
Ejemplo n.º 3
0
func symbolize(vmlinux string, cov []uint32) ([]LineInfo, string, error) {
	cmd := exec.Command("addr2line", "-a", "-i", "-e", vmlinux)
	stdin, err := cmd.StdinPipe()
	if err != nil {
		return nil, "", err
	}
	defer stdin.Close()
	stdout, err := cmd.StdoutPipe()
	if err != nil {
		return nil, "", err
	}
	defer stdout.Close()
	if err := cmd.Start(); err != nil {
		return nil, "", err
	}
	defer cmd.Wait()
	go func() {
		for _, pc := range cov {
			fmt.Fprintf(stdin, "0x%x\n", cover.RestorePC(pc)-1)
		}
		stdin.Close()
	}()
	var info []LineInfo
	prefix := ""
	s := bufio.NewScanner(stdout)
	var pc uint32
	for s.Scan() {
		ln := s.Text()
		if len(ln) > 3 && ln[0] == '0' && ln[1] == 'x' {
			v, err := strconv.ParseUint(ln, 0, 64)
			if err != nil {
				return nil, "", fmt.Errorf("failed to parse pc in addr2line output: %v", err)
			}
			pc = uint32(v) + 1
			continue
		}
		colon := strings.IndexByte(ln, ':')
		if colon == -1 {
			continue
		}
		file := ln[:colon]
		line, err := strconv.Atoi(ln[colon+1:])
		if err != nil || pc == 0 || file == "" || file == "??" || line <= 0 {
			continue
		}
		info = append(info, LineInfo{file, line})
		if prefix == "" {
			prefix = file
		} else {
			i := 0
			for ; i < len(prefix) && i < len(file); i++ {
				if prefix[i] != file[i] {
					break
				}
			}
			prefix = prefix[:i]
		}
	}
	if err := s.Err(); err != nil {
		return nil, "", err
	}
	return info, prefix, nil
}
Ejemplo n.º 4
0
func main() {
	flag.Parse()
	if len(flag.Args()) == 0 {
		fmt.Fprintf(os.Stderr, "usage: execprog [flags] file-with-programs+\n")
		flag.PrintDefaults()
		os.Exit(1)
	}

	var progs []*prog.Prog
	for _, fn := range flag.Args() {
		data, err := ioutil.ReadFile(fn)
		if err != nil {
			Fatalf("failed to read log file: %v", err)
		}
		entries := prog.ParseLog(data)
		for _, ent := range entries {
			progs = append(progs, ent.P)
		}
	}
	Logf(0, "parsed %v programs", len(progs))
	if len(progs) == 0 {
		return
	}

	flags, timeout, err := ipc.DefaultFlags()
	if err != nil {
		Fatalf("%v", err)
	}
	if *flagCoverFile != "" {
		flags |= ipc.FlagCover
		flags &= ^ipc.FlagDedupCover
	}

	var wg sync.WaitGroup
	wg.Add(*flagProcs)
	var posMu, logMu sync.Mutex
	gate := ipc.NewGate(2**flagProcs, nil)
	var pos int
	var lastPrint time.Time
	var shutdown uint32
	for p := 0; p < *flagProcs; p++ {
		pid := p
		go func() {
			defer wg.Done()
			env, err := ipc.MakeEnv(*flagExecutor, timeout, flags, pid)
			if err != nil {
				Fatalf("failed to create ipc env: %v", err)
			}
			defer env.Close()
			for {
				if !func() bool {
					// Limit concurrency window.
					ticket := gate.Enter()
					defer gate.Leave(ticket)

					posMu.Lock()
					idx := pos
					pos++
					if idx%len(progs) == 0 && time.Since(lastPrint) > 5*time.Second {
						Logf(0, "executed programs: %v", idx)
						lastPrint = time.Now()
					}
					posMu.Unlock()
					if *flagRepeat > 0 && idx >= len(progs)**flagRepeat {
						return false
					}
					p := progs[idx%len(progs)]
					switch *flagOutput {
					case "stdout":
						data := p.Serialize()
						logMu.Lock()
						Logf(0, "executing program %v:\n%s", pid, data)
						logMu.Unlock()
					}
					output, cov, _, failed, hanged, err := env.Exec(p)
					if atomic.LoadUint32(&shutdown) != 0 {
						return false
					}
					if failed {
						fmt.Printf("BUG: executor-detected bug:\n%s", output)
					}
					if flags&ipc.FlagDebug != 0 || err != nil {
						fmt.Printf("result: failed=%v hanged=%v err=%v\n\n%s", failed, hanged, err, output)
					}
					if *flagCoverFile != "" {
						// Coverage is dumped in sanitizer format.
						// github.com/google/sanitizers/tools/sancov command can be used to dump PCs,
						// then they can be piped via addr2line to symbolize.
						for i, c := range cov {
							fmt.Printf("call #%v: coverage %v\n", i, len(c))
							if len(c) == 0 {
								continue
							}
							buf := new(bytes.Buffer)
							binary.Write(buf, binary.LittleEndian, uint64(0xC0BFFFFFFFFFFF64))
							for _, pc := range c {
								binary.Write(buf, binary.LittleEndian, cover.RestorePC(pc, 0xffffffff))
							}
							err := ioutil.WriteFile(fmt.Sprintf("%v.%v", *flagCoverFile, i), buf.Bytes(), 0660)
							if err != nil {
								Fatalf("failed to write coverage file: %v", err)
							}
						}
					}
					return true
				}() {
					return
				}
			}
		}()
	}

	go func() {
		c := make(chan os.Signal, 2)
		signal.Notify(c, syscall.SIGINT)
		<-c
		Logf(0, "shutting down...")
		atomic.StoreUint32(&shutdown, 1)
		<-c
		Fatalf("terminating")
	}()

	wg.Wait()
}
Ejemplo n.º 5
0
func generateCoverHtml(w io.Writer, vmlinux string, cov []uint32) error {
	if len(cov) == 0 {
		return fmt.Errorf("No coverage data available")
	}

	base, err := getVmOffset(vmlinux)
	if err != nil {
		return err
	}
	pcs := make([]uint64, len(cov))
	for i, pc := range cov {
		pcs[i] = cover.RestorePC(pc, base) - 1
	}
	allPcs, err := allPcsInFuncs(vmlinux, pcs)
	if err != nil {
		return err
	}

	frames, prefix, err := symbolize(vmlinux, pcs)
	if err != nil {
		return err
	}
	if len(frames) == 0 {
		return fmt.Errorf("'%s' does not have debug info (set CONFIG_DEBUG_INFO=y)", vmlinux)
	}

	allFrames, prefix, err := symbolize(vmlinux, allPcs)
	if err != nil {
		return err
	}

	var d templateData
	for f, covered := range fileSet(frames, allFrames) {
		lines, err := parseFile(f)
		if err != nil {
			return err
		}
		coverage := 0
		var buf bytes.Buffer
		for i, ln := range lines {
			if len(covered) > 0 && covered[0].line == i+1 {
				if covered[0].covered {
					buf.Write([]byte("<span id='covered'>"))
					buf.Write(ln)
					buf.Write([]byte("</span> /*covered*/\n"))
					coverage++
				} else {
					buf.Write([]byte("<span id='uncovered'>"))
					buf.Write(ln)
					buf.Write([]byte("</span>\n"))
				}
				covered = covered[1:]
			} else {
				buf.Write(ln)
				buf.Write([]byte{'\n'})
			}
		}
		if len(f) > len(prefix) {
			f = f[len(prefix):]
		}
		d.Files = append(d.Files, &templateFile{
			Name:     f,
			Body:     template.HTML(buf.String()),
			Coverage: coverage,
		})
	}

	sort.Sort(templateFileArray(d.Files))
	if err := coverTemplate.Execute(w, d); err != nil {
		return err
	}
	return nil
}
Ejemplo n.º 6
0
func main() {
	flag.Parse()
	if len(flag.Args()) == 0 {
		fmt.Fprintf(os.Stderr, "usage: execprog [flags] file-with-programs+\n")
		flag.PrintDefaults()
		os.Exit(1)
	}

	var progs []*prog.Prog
	for _, fn := range flag.Args() {
		data, err := ioutil.ReadFile(fn)
		if err != nil {
			log.Fatalf("failed to read log file: %v", err)
		}
		entries := prog.ParseLog(data)
		for _, ent := range entries {
			progs = append(progs, ent.P)
		}
	}
	log.Printf("parsed %v programs", len(progs))
	if len(progs) == 0 {
		return
	}

	flags, timeout := ipc.DefaultFlags()
	if *flagCoverFile != "" {
		flags |= ipc.FlagCover
		flags &= ^ipc.FlagDedupCover
	}

	var wg sync.WaitGroup
	wg.Add(*flagProcs)
	var posMu sync.Mutex
	var pos int
	var lastPrint time.Time
	for p := 0; p < *flagProcs; p++ {
		go func() {
			env, err := ipc.MakeEnv(*flagExecutor, timeout, flags)
			if err != nil {
				log.Fatalf("failed to create ipc env: %v", err)
			}
			for {
				posMu.Lock()
				idx := pos
				pos++
				if idx%len(progs) == 0 && time.Since(lastPrint) > 5*time.Second {
					log.Printf("executed %v programs\n", idx)
					lastPrint = time.Now()
				}
				posMu.Unlock()
				if *flagRepeat > 0 && idx >= len(progs)**flagRepeat {
					env.Close()
					wg.Done()
					return
				}
				p := progs[idx%len(progs)]
				output, cov, _, failed, hanged, err := env.Exec(p)
				if failed {
					fmt.Printf("BUG: executor-detected bug:\n%s", output)
				}
				if flags&ipc.FlagDebug != 0 || err != nil {
					fmt.Printf("result: failed=%v hanged=%v err=%v\n\n%s", failed, hanged, err, output)
				}
				if *flagCoverFile != "" {
					// Coverage is dumped in sanitizer format.
					// github.com/google/sanitizers/tools/sancov command can be used to dump PCs,
					// then they can be piped via addr2line to symbolize.
					for i, c := range cov {
						fmt.Printf("call #%v: coverage %v\n", i, len(c))
						if len(c) == 0 {
							continue
						}
						buf := new(bytes.Buffer)
						binary.Write(buf, binary.LittleEndian, uint64(0xC0BFFFFFFFFFFF64))
						for _, pc := range c {
							binary.Write(buf, binary.LittleEndian, cover.RestorePC(pc))
						}
						err := ioutil.WriteFile(fmt.Sprintf("%v.%v", *flagCoverFile, i), buf.Bytes(), 0660)
						if err != nil {
							log.Fatalf("failed to write coverage file: %v", err)
						}
					}
				}
			}
		}()
	}
	wg.Wait()
}
Ejemplo n.º 7
0
func main() {
	flag.Parse()
	if len(flag.Args()) == 0 {
		fmt.Fprintf(os.Stderr, "usage: execprog [flags] file-with-programs*\n")
		flag.PrintDefaults()
		os.Exit(1)
	}

	var progs []*prog.Prog
	for _, fn := range flag.Args() {
		progs = append(progs, parseFile(fn)...)
	}
	log.Printf("parsed %v programs", len(progs))
	if len(progs) == 0 {
		return
	}

	var flags uint64
	if *flagThreaded {
		flags |= ipc.FlagThreaded
	}
	if *flagCollide {
		flags |= ipc.FlagCollide
	}
	if *flagDebug {
		flags |= ipc.FlagDebug
	}
	if *flagStrace {
		flags |= ipc.FlagStrace
	}
	if *flagCover || *flagCoverFile != "" {
		flags |= ipc.FlagCover
	}
	if *flagDedup {
		flags |= ipc.FlagDedupCover
	}
	if *flagNobody {
		flags |= ipc.FlagDropPrivs
	}

	var wg sync.WaitGroup
	wg.Add(*flagProcs)
	var pos uint32
	for p := 0; p < *flagProcs; p++ {
		go func() {
			env, err := ipc.MakeEnv(*flagExecutor, *flagTimeout, flags)
			if err != nil {
				log.Fatalf("failed to create ipc env: %v", err)
			}
			for {
				idx := int(atomic.AddUint32(&pos, 1) - 1)
				if idx%len(progs) == 0 {
					log.Printf("executed %v programs\n", idx)
				}
				if !*flagLoop && idx >= len(progs) {
					env.Close()
					wg.Done()
					return
				}
				p := progs[idx%len(progs)]
				output, strace, cov, failed, hanged, err := env.Exec(p)
				if *flagDebug || err != nil {
					fmt.Printf("result: failed=%v hanged=%v err=%v\n\n%s", failed, hanged, err, output)
				}
				if *flagStrace {
					fmt.Printf("strace output:\n%s", strace)
				}
				if *flagCoverFile != "" {
					// Coverage is dumped in sanitizer format.
					// github.com/google/sanitizers/tools/sancov command can be used to dump PCs,
					// then they can be piped via addr2line to symbolize.
					for i, c := range cov {
						fmt.Printf("call #%v: coverage %v\n", i, len(c))
						if len(c) == 0 {
							continue
						}
						buf := new(bytes.Buffer)
						binary.Write(buf, binary.LittleEndian, uint64(0xC0BFFFFFFFFFFF64))
						for _, pc := range c {
							binary.Write(buf, binary.LittleEndian, cover.RestorePC(pc))
						}
						err := ioutil.WriteFile(fmt.Sprintf("%v.%v", *flagCoverFile, i), buf.Bytes(), 0660)
						if err != nil {
							log.Fatalf("failed to write coverage file: %v", err)
						}
					}
				}
			}
		}()
	}
	wg.Wait()
}