blob: 254db11f7679db5fa3a4b562f74e5ec02f36deec [file] [log] [blame]
// Copyright 2018 The Fuchsia Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "report_attachments.h"
#include <memory>
#include <string>
#include <fuchsia/mem/cpp/fidl.h>
#include <lib/fxl/files/file.h>
#include <lib/fxl/files/path.h>
#include <lib/fxl/strings/concatenate.h>
#include <lib/fxl/strings/trim.h>
#include <lib/syslog/cpp/logger.h>
#include <lib/zx/debuglog.h>
#include <third_party/crashpad/minidump/minidump_file_writer.h>
#include <third_party/crashpad/util/file/file_writer.h>
#include <zircon/errors.h>
#include <zircon/status.h>
#include <zircon/syscalls/log.h>
#include <zircon/types.h>
namespace fuchsia {
namespace crash {
const char kAttachmentKernelLog[] = "kernel_log";
const char kAttachmentBuildInfoSnapshot[] = "build.snapshot";
std::string WriteKernelLogToFile(const std::string& dir) {
std::string filename =
files::SimplifyPath(fxl::Concatenate({dir, "/kernel_log.XXXXXX"}));
base::ScopedFD fd(mkstemp(filename.data()));
if (fd.get() < 0) {
FX_LOGS(ERROR) << "could not create temp file";
return std::string();
}
zx::debuglog log;
zx_status_t status =
zx::debuglog::create(zx::resource(), ZX_LOG_FLAG_READABLE, &log);
if (status != ZX_OK) {
FX_LOGS(ERROR) << "zx::debuglog::create failed " << status;
return std::string();
}
char buf[ZX_LOG_RECORD_MAX + 1];
zx_log_record_t* rec = (zx_log_record_t*)buf;
while (log.read(/*options=*/0, /*buffer=*/rec,
/*buffer_size=*/ZX_LOG_RECORD_MAX) > 0) {
if (rec->datalen && (rec->data[rec->datalen - 1] == '\n')) {
rec->datalen--;
}
rec->data[rec->datalen] = 0;
dprintf(fd.get(), "[%05d.%03d] %05" PRIu64 ".%05" PRIu64 "> %s\n",
(int)(rec->timestamp / 1000000000ULL),
(int)((rec->timestamp / 1000000ULL) % 1000ULL), rec->pid, rec->tid,
rec->data);
}
return filename;
}
namespace {
zx_status_t WriteVMO(crashpad::FileWriter* writer,
const fuchsia::mem::Buffer vmo) {
// TODO(frousseau): make crashpad::FileWriter VMO-aware.
std::unique_ptr<void, decltype(&free)> buffer(malloc(vmo.size), &free);
zx_status_t status = vmo.vmo.read(buffer.get(), 0u, vmo.size);
if (status != ZX_OK) {
return ZX_ERR_INTERNAL;
}
writer->Write(buffer.get(), vmo.size);
return ZX_OK;
}
zx_status_t AddAttachment(crashpad::CrashReportDatabase::NewReport* report,
const std::string& attachment_filename,
fuchsia::mem::Buffer content_buffer,
const std::string& debug_name) {
crashpad::FileWriter* writer = report->AddAttachment(attachment_filename);
if (!writer) {
return ZX_ERR_INTERNAL;
}
if (zx_status_t status = WriteVMO(writer, std::move(content_buffer));
status != ZX_OK) {
FX_LOGS(ERROR) << "error writing " << debug_name
<< " to file: " << zx_status_get_string(status);
return ZX_ERR_INTERNAL;
}
return ZX_OK;
}
zx_status_t AddAttachment(crashpad::CrashReportDatabase::NewReport* report,
const std::string& attachment_filename,
const std::string& content_filepath) {
crashpad::FileWriter* writer = report->AddAttachment(attachment_filename);
if (!writer) {
return ZX_ERR_INTERNAL;
}
std::string content;
if (!files::ReadFileToString(content_filepath, &content)) {
FX_LOGS(ERROR) << "Failed to read content from '" << content_filepath
<< "'.";
return ZX_ERR_INTERNAL;
}
content = fxl::TrimString(content, "\r\n").ToString();
writer->Write(content.data(), content.size());
return ZX_OK;
}
} // namespace
zx_status_t AddManagedRuntimeExceptionAttachments(
crashpad::CrashReportDatabase::NewReport* report,
ManagedRuntimeLanguage language, fuchsia::mem::Buffer stack_trace) {
const std::string& stack_trace_filename =
(language == ManagedRuntimeLanguage::DART)
? "DartError" // the crash server expects a specific name for Dart.
: "stack_trace";
AddAttachment(report, stack_trace_filename, std::move(stack_trace),
"stack trace");
AddAttachment(report, kAttachmentBuildInfoSnapshot,
"/config/build-info/snapshot");
// TODO(DX-581): attach syslog as well.
// TODO(DX-748): attach kernel log as well.
return ZX_OK;
}
zx_status_t AddKernelPanicAttachments(
crashpad::CrashReportDatabase::NewReport* report,
fuchsia::mem::Buffer crashlog) {
AddAttachment(report, "log", std::move(crashlog), "kernel panic crashlog");
AddAttachment(report, kAttachmentBuildInfoSnapshot,
"/config/build-info/snapshot");
return ZX_OK;
}
} // namespace crash
} // namespace fuchsia