blob: abcb3acce5799953c913bfd329cf68b1f9ff3688 [file] [log] [blame]
// Copyright 2023 The ChromiumOS Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "crash-reporter/gsc_collector.h"
#include <string>
#include <vector>
#include <base/files/file_util.h>
#include <base/logging.h>
#include <base/memory/ref_counted.h>
#include <base/memory/scoped_refptr.h>
#include <brillo/process/process.h>
#include <metrics/metrics_library.h>
#include "crash-reporter/gsc_collector_base.h"
using brillo::ProcessImpl;
namespace {
const char kGscFirmwarePath[] = "/opt/google/ti50/firmware";
const char kGscToolPath[] = "/usr/sbin/gsctool";
// Ti50 crash log signature offset and length within |--clog| output, in bytes.
// Note that |--clog| outputs a string of hex values, with 2 chars per byte.
// https://b.corp.google.com/issues/265310865#comment40
// The 24 bytes starting at offset 40 in the crash dump can be used as a crash
// signature for UMA.
const int kCharsPerByte = 2;
const size_t kTi50SignatureStringOffset = 40 * kCharsPerByte;
const size_t kTi50SignatureStringSize = 24 * kCharsPerByte;
static bool IsTi50() {
return base::PathExists(base::FilePath(kGscFirmwarePath));
}
} // namespace
GscCollector::GscCollector(
const scoped_refptr<
base::RefCountedData<std::unique_ptr<MetricsLibraryInterface>>>&
metrics_lib)
: GscCollectorBase(metrics_lib) {}
GscCollectorBase::Status GscCollector::GetTi50Flog(std::string* flog_output) {
ProcessImpl gsctool;
gsctool.AddArg(kGscToolPath);
gsctool.AddArg("-a"); // spi/i2c AP-to-GSC interface
gsctool.AddArg("--dauntless"); // Communicate with Dauntless chip.
gsctool.AddArg("--flog"); // Retrieve contents of the flash log
// Combine stdout and stderr.
gsctool.RedirectOutputToMemory(true);
const int result = gsctool.Run();
*flog_output = gsctool.GetOutputString(STDOUT_FILENO);
if (result != 0) {
LOG(ERROR) << "Failed to get Ti50 gsctool flash log output. Error: '"
<< result << "'";
return Status::Fail;
}
return Status::Success;
}
GscCollectorBase::Status GscCollector::GetGscFlog(std::string* flog_output) {
if (IsTi50()) {
return GetTi50Flog(flog_output);
}
// TODO(b/291127335): Update with better language.
LOG(INFO) << "Unsupported GSC present on board. Unable to query GSC crashes.";
return Status::Fail;
}
GscCollectorBase::Status GscCollector::GetTi50Clog(std::string* clog_output) {
ProcessImpl gsctool;
gsctool.AddArg(kGscToolPath);
gsctool.AddArg("-a"); // spi/i2c AP-to-GSC interface
gsctool.AddArg("--dauntless"); // Communicate with Dauntless chip.
gsctool.AddArg("--clog"); // Retrieve contents of the crash log
// Combine stdout and stderr.
gsctool.RedirectOutputToMemory(true);
const int result = gsctool.Run();
*clog_output = gsctool.GetOutputString(STDOUT_FILENO);
if (result != 0) {
LOG(ERROR) << "Failed to get Ti50 gsctool crash log output. Error: '"
<< result << "'";
return Status::Fail;
}
return Status::Success;
}
GscCollectorBase::Status GscCollector::GetGscClog(std::string* clog_output) {
if (IsTi50()) {
return GetTi50Clog(clog_output);
}
// TODO(b/291127335): Update with better language.
LOG(INFO)
<< "Unsupported GSC present on board. Unable to query GSC crash log.";
return Status::Fail;
}
GscCollectorBase::Status GscCollector::GetGscCrashSignatureOffsetAndLength(
size_t* offset_out, size_t* size_out) {
if (IsTi50()) {
*offset_out = kTi50SignatureStringOffset;
*size_out = kTi50SignatureStringSize;
return Status::Success;
}
// TODO(b/291127335): Update with better language.
LOG(INFO) << "Unsupported GSC present on board. No crash signature "
"offset/size specified.";
return Status::Fail;
}