blob: 46d9011e12629d049ea047434c38d5a118a94d69 [file]
// Copyright 2017 The ChromiumOS Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
// Package crash can be used by local tests to interact with on-device crash reports.
package crash
import (
"context"
"os"
"path/filepath"
"strings"
"go.chromium.org/tast/core/fsutil"
"go.chromium.org/tast/core/internal/logging"
)
const (
// DefaultCrashDir contains the directory where the kernel writes core and minidump files.
DefaultCrashDir = "/var/spool/crash"
// ChromeCrashDir contains the directory where Chrome writes minidump files.
// Tests configure Chrome to write crashes to this location/ by setting the BREAKPAD_DUMP_LOCATION
// environment variable. This overrides the default /home/chronos/user/crash location, which is in
// the user's cryptohome and hence is only accessible while they are logged in.
ChromeCrashDir = "/home/chronos/crash"
// BIOSExt is the extension for bios crash files.
BIOSExt = ".bios_log"
// CoreExt is the extension for core files.
CoreExt = ".core"
// MinidumpExt is the extension for minidump crash files.
MinidumpExt = ".dmp"
// LogExt is the extension for log files containing additional information that are written by crash_reporter.
LogExt = ".log"
// InfoExt is the extention for info files.
InfoExt = ".info"
// ProclogExt is the extention for proclog files.
ProclogExt = ".proclog"
// KCrashExt is the extension for log files created by kernel warnings and crashes.
KCrashExt = ".kcrash"
// GPUStateExt is the extension for GPU state files written by crash_reporter.
GPUStateExt = ".i915_error_state.log.xz"
// MetadataExt is the extension for metadata files written by crash collectors and read by crash_sender.
MetadataExt = ".meta"
// CompressedTxtExt is an extension on the compressed log files written by crash_reporter.
CompressedTxtExt = ".txt.gz"
// CompressedLogExt is an extension on the compressed log files written by crash_reporter.
CompressedLogExt = ".log.gz"
lsbReleasePath = "/etc/lsb-release"
)
// DefaultDirs returns all standard directories to which crashes are written.
func DefaultDirs() []string {
return []string{DefaultCrashDir, ChromeCrashDir}
}
// isCrashFile returns true if filename could be the name of a file generated by
// crashes or crash_reporter.
func isCrashFile(filename string) bool {
knownExts := []string{
BIOSExt,
CoreExt,
MinidumpExt,
LogExt,
ProclogExt,
InfoExt,
KCrashExt,
GPUStateExt,
MetadataExt,
CompressedTxtExt,
CompressedLogExt,
}
for _, ext := range knownExts {
if strings.HasSuffix(filename, ext) {
return true
}
}
return false
}
// GetCrashes returns the paths of all files in dirs generated in response to crashes.
// Nonexistent directories are skipped.
func GetCrashes(dirs ...string) ([]string, error) {
var crashFiles []string
for _, dir := range dirs {
df, err := os.Open(dir)
if os.IsNotExist(err) {
continue
} else if err != nil {
return nil, err
}
files, err := df.Readdirnames(-1)
df.Close()
if err != nil {
return nil, err
}
for _, fn := range files {
if isCrashFile(fn) {
crashFiles = append(crashFiles, filepath.Join(dir, fn))
}
}
}
return crashFiles, nil
}
// CopyNewFiles copies paths that are present in newPaths but not in oldPaths into dstDir.
// If maxPerExec is positive, it limits the maximum number of files that will be copied
// for each base executable. The returned warnings map contains non-fatal errors keyed by
// crash file paths.
func CopyNewFiles(ctx context.Context, dstDir string, newPaths, oldPaths []string) error {
oldMap := make(map[string]struct{}, len(oldPaths))
for _, p := range oldPaths {
oldMap[p] = struct{}{}
}
for _, sp := range newPaths {
if _, ok := oldMap[sp]; ok {
continue
}
// Core dumps (.core) are often too large, do not copy them.
// Minidumps (.dmp) are usually sufficient.
if strings.HasSuffix(sp, ".core") {
continue
}
if err := fsutil.CopyFile(sp, filepath.Join(dstDir, filepath.Base(sp))); err != nil {
logging.Infof(ctx, "%s: %v", sp, err)
}
}
return nil
}
// CopySystemInfo copies system information relevant to crash dumps (e.g. lsb-release) into dstDir.
func CopySystemInfo(dstDir string) error {
return fsutil.CopyFile(lsbReleasePath, filepath.Join(dstDir, filepath.Base(lsbReleasePath)))
}