blob: 146aa8ecb5600199e3cd62c3000c69cdf358b261 [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/path.h>
#include <lib/fxl/strings/concatenate.h>
#include <lib/syslog/cpp/logger.h>
#include <sys/types.h>
#include <third_party/crashpad/minidump/minidump_file_writer.h>
#include <zircon/errors.h>
#include <zircon/status.h>
#include <zircon/syscalls/log.h>
namespace fuchsia {
namespace crash {
namespace {
std::string WriteKernelLogToFile(const std::string& tmp_dir) {
std::string filename =
files::SimplifyPath(fxl::Concatenate({tmp_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::log log;
zx_status_t status = zx::log::create(ZX_LOG_FLAG_READABLE, &log);
if (status != ZX_OK) {
FX_LOGS(ERROR) << "zx::log::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(ZX_LOG_RECORD_MAX, rec, 0) > 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;
}
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& filename,
fuchsia::mem::Buffer buffer,
const std::string& debug_name) {
crashpad::FileWriter* writer = report->AddAttachment(filename);
if (!writer) {
return ZX_ERR_INTERNAL;
}
if (zx_status_t status = WriteVMO(writer, std::move(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;
}
} // namespace
std::map<std::string, ScopedUnlink> MakeNativeExceptionAttachments(
const std::string& tmp_dir) {
std::map<std::string, ScopedUnlink> attachments;
const std::string tmp_kernel_log_filename = WriteKernelLogToFile(tmp_dir);
if (!tmp_kernel_log_filename.empty()) {
attachments["kernel_log"] = ScopedUnlink(tmp_kernel_log_filename);
}
// TODO(DX-581): attach syslog as well.
return attachments;
}
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");
// 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");
return ZX_OK;
}
} // namespace crash
} // namespace fuchsia