blob: f0088bd4a81b3bc248d7c83cdf2de4cd384e083c [file] [log] [blame]
// Copyright (c) 2010 The Chromium OS Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
// The kernel collector reports kernel panics or other kernel-level issues that
// caused machine reboot, like EFI crashes and BIOS crashes.
// The kernel collector runs on boot, via the crash-boot-collect service.
#ifndef CRASH_REPORTER_KERNEL_COLLECTOR_H_
#define CRASH_REPORTER_KERNEL_COLLECTOR_H_
#include <string>
#include <vector>
#include <base/files/file_path.h>
#include <base/macros.h>
#include <gtest/gtest_prod.h> // for FRIEND_TEST
#include "crash-reporter/crash_collector.h"
#include "crash-reporter/kernel_util.h"
// Kernel crash collector.
class KernelCollector : public CrashCollector {
public:
KernelCollector();
KernelCollector(const KernelCollector&) = delete;
KernelCollector& operator=(const KernelCollector&) = delete;
~KernelCollector() override;
void OverrideEventLogPath(const base::FilePath& file_path);
void OverrideBiosLogPath(const base::FilePath& file_path);
void OverridePreservedDumpPath(const base::FilePath& file_path);
// Enable collection.
bool Enable();
// Returns true if the kernel collection currently enabled.
bool is_enabled() const { return is_enabled_; }
// Collect any preserved kernel crash dump. Returns true if there was
// a dump (even if there were problems storing the dump), false otherwise.
bool Collect();
// Set the architecture of the crash dumps we are looking at.
void set_arch(kernel_util::ArchKind arch) { arch_ = arch; }
kernel_util::ArchKind arch() const { return arch_; }
private:
// This class represents single EFI crash.
class EfiCrash {
public:
explicit EfiCrash(uint64_t id, const KernelCollector& collector)
: id_(id),
timestamp_(GetTimestamp(id)),
max_part_(GetPart(id)),
crash_count_(GetCrashCount(id)),
collector_(collector) {}
bool Load(std::string* contents) const;
bool GetType(std::string* crash_type) const;
void Remove() const;
// Returns efi crash id.
uint64_t GetId() const { return id_; }
// Updates part from crash id iff it's greater.
void UpdateMaxPart(uint64_t id) {
uint32_t part = GetPart(id);
if (part > max_part_) {
max_part_ = part;
}
}
constexpr uint64_t GetIdForPart(uint32_t part) const {
return GenerateId(timestamp_, part, crash_count_);
}
// Helper functions for parsing and generating efi crash id.
// Get efi crash id for given part.
static constexpr uint64_t GetIdForPart(uint64_t id, uint32_t part) {
return GenerateId(GetTimestamp(id), part, GetCrashCount(id));
}
// Get crash count from efi crash id.
static constexpr uint32_t GetCrashCount(uint64_t id) {
return id % kMaxDumpRecord;
}
// Get part number from efi crash id.
static constexpr uint32_t GetPart(uint64_t id) {
return (id / kMaxDumpRecord) % kMaxPart;
}
// Get timestamp from efi crash id.
static constexpr uint64_t GetTimestamp(uint64_t id) {
return (id / (kMaxDumpRecord * kMaxPart));
}
// Generates efi crash id from timestamp, part, crash count.
// EFI File name is of format dmesg-efi-<crash_id>. Since one kernel crash
// is split into multiple parts, <crash_id> is derived by
// crash_id = (timestamp * 100 + part) * 1000 + crash_count.
// See efi-pstore driver (https://goo.gl/1YBeCD) for more information.
// e.g. File "dmesg-efi-150989600314002" represents part 14 of crash 2.
static constexpr uint64_t GenerateId(uint64_t timestamp,
uint32_t part,
uint32_t crash_count) {
return (timestamp * kMaxPart + part) * kMaxDumpRecord + crash_count;
}
private:
static constexpr size_t kMaxDumpRecord = 1000;
static constexpr size_t kMaxPart = 100;
uint64_t id_;
uint64_t timestamp_;
uint32_t max_part_;
uint32_t crash_count_;
const KernelCollector& collector_;
base::FilePath GetFilePath(uint32_t part) const;
};
friend class KernelCollectorTest;
FRIEND_TEST(KernelCollectorTest, LoadPreservedDump);
FRIEND_TEST(KernelCollectorTest, LoadBiosLog);
FRIEND_TEST(KernelCollectorTest, CollectOK);
FRIEND_TEST(KernelCollectorTest, ParseEfiCrashId);
FRIEND_TEST(KernelCollectorTest, GetEfiCrashType);
FRIEND_TEST(KernelCollectorTest, LoadEfiCrash);
virtual bool DumpDirMounted();
bool LoadPreservedDump(std::string* contents);
bool LoadLastBootBiosLog(std::string* contents);
bool LastRebootWasBiosCrash(const std::string& dump);
bool LastRebootWasWatchdog();
bool LoadConsoleRamoops(std::string* contents);
base::FilePath GetDumpRecordPath(const char* type,
const char* driver,
size_t record);
base::FilePath GetDumpRecordOldPath(const char* type, const char* driver);
bool LoadParameters();
bool HasMoreRecords();
// Read a record to string, modified from file_utils since that didn't
// provide a way to restrict the read length.
// Return value indicates (only) error state:
// * false when we get an error (can't read from dump location).
// * true if no error occured.
// Not finding a valid record is not an error state and is signaled by the
// record_found output parameter.
bool ReadRecordToString(std::string* contents,
size_t current_record,
bool* record_found);
bool HandleCrash(const std::string& kernel_dump,
const std::string& bios_dump,
const std::string& signature);
// Collects ramoops crash.
bool CollectRamoopsCrash();
// Collects efi crash.
bool CollectEfiCrash();
std::vector<EfiCrash> FindEfiCrashes() const;
bool is_enabled_;
base::FilePath eventlog_path_;
base::FilePath dump_path_;
base::FilePath bios_log_path_;
size_t records_;
// The architecture of kernel dump strings we are working with.
kernel_util::ArchKind arch_;
};
#endif // CRASH_REPORTER_KERNEL_COLLECTOR_H_