blob: 978b55a4da1b3764d2d672189d9a83b66a9692a0 [file] [log] [blame]
// Copyright 2018 The ChromiumOS Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
package symbolize
import (
"context"
"fmt"
"os"
"runtime"
"sync"
"sync/atomic"
"go.chromium.org/tast/core/cmd/tast/internal/symbolize/breakpad"
"go.chromium.org/tast/core/internal/logging"
)
// symbolFileInfo contains a module's path and corresponding Breakpad ID. See breakpad.ModuleInfo.
type symbolFileInfo struct{ path, id string }
// createSymbolFile attempts to create a symbol file within symDir for fi.
// Debug binaries should be located within buildRoot.
func createSymbolFile(fi *symbolFileInfo, symDir, buildRoot string) error {
bin := breakpad.GetDebugBinaryPath(buildRoot, fi.path)
if _, err := os.Stat(bin); os.IsNotExist(err) {
return fmt.Errorf("no debug file %v", bin)
}
if mi, err := breakpad.WriteSymbolFile(bin, symDir); err != nil {
return fmt.Errorf("failed to write symbol file: %v", err)
} else if mi.ID != fi.id {
return fmt.Errorf("wrote symbol file with ID %v (different build?)", mi.ID)
}
return nil
}
// createSymbolFiles attempts to create a symbol file within cfg.SymbolDir for each file listed in sf.
// Debug binaries should be located within cfg.BuildRoot.
// The number of symbol files that were successfully created is returned.
func createSymbolFiles(ctx context.Context, cfg *Config, sf breakpad.SymbolFileMap) (created int) {
ch := make(chan *symbolFileInfo) // passes work to goroutines
wg := sync.WaitGroup{} // used to wait for goroutines
var nc int32
// Start a fixed number of worker goroutines so we don't launch a zillion dump_syms processes at once.
for i := 0; i < runtime.NumCPU(); i++ {
wg.Add(1)
go func() {
for fi := range ch {
err := createSymbolFile(fi, cfg.SymbolDir, cfg.BuildRoot)
if err != nil {
logging.Debugf(ctx, "Failed to generate symbol file for %v with ID %v: %v", fi.path, fi.id, err)
} else {
logging.Debugf(ctx, "Generated symbol file for %v with ID %v", fi.path, fi.id)
atomic.AddInt32(&nc, 1)
}
}
wg.Done()
}()
}
// Enqueue work and wait for all of the goroutines to complete.
for path, id := range sf {
ch <- &symbolFileInfo{path, id}
}
close(ch)
wg.Wait()
return int(nc)
}