blob: ad06138627b8200b3076de0c24d387cee3c7421d [file] [log] [blame]
// Copyright 2020 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 "src/developer/forensics/exceptions/handler/report_builder.h"
#include <lib/syslog/cpp/macros.h>
#include "src/lib/fsl/handles/object_info.h"
#include "src/lib/fxl/strings/join_strings.h"
namespace forensics {
namespace exceptions {
namespace handler {
CrashReportBuilder& CrashReportBuilder::SetProcess(const zx::process& process) {
process_name_ = (process.is_valid()) ? fsl::GetObjectName(process.get()) : "unknown_process";
if (process.is_valid()) {
process_koid_ = fsl::GetKoid(process.get());
}
return *this;
}
CrashReportBuilder& CrashReportBuilder::SetThread(const zx::thread& thread) {
thread_name_ = (thread.is_valid()) ? fsl::GetObjectName(thread.get()) : "unknown_thread";
if (thread.is_valid()) {
thread_koid_ = fsl::GetKoid(thread.get());
}
return *this;
}
CrashReportBuilder& CrashReportBuilder::SetMinidump(zx::vmo minidump) {
FX_CHECK(minidump.is_valid());
minidump_ = std::move(minidump);
return *this;
}
CrashReportBuilder& CrashReportBuilder::SetComponentInfo(
const fuchsia::sys::internal::SourceIdentity& component_info) {
if (component_info.has_component_url()) {
component_url_ = component_info.component_url();
}
if (component_info.has_realm_path()) {
realm_path_ = "/" + fxl::JoinStrings(component_info.realm_path(), "/");
}
return *this;
}
CrashReportBuilder& CrashReportBuilder::SetExceptionExpired() {
exception_expired_ = true;
return *this;
}
CrashReportBuilder& CrashReportBuilder::SetProcessTerminated() {
process_already_terminated_ = true;
return *this;
}
fuchsia::feedback::CrashReport CrashReportBuilder::Consume() {
FX_CHECK(process_name_.has_value()) << "Need a process name";
FX_CHECK(thread_name_.has_value()) << "Need a thread name";
FX_CHECK(is_valid_) << "Consume can only be called once";
is_valid_ = false;
using namespace fuchsia::feedback;
CrashReport crash_report;
const std::string program_name =
(component_url_.has_value()) ? component_url_.value() : process_name_.value();
crash_report.set_program_name(program_name.substr(0, fuchsia::feedback::MAX_PROGRAM_NAME_LENGTH));
auto AddAnnotation = [&crash_report](const std::string& key, const std::string& value) {
crash_report.mutable_annotations()->push_back(Annotation{.key = key, .value = value});
};
AddAnnotation("crash.process.name", process_name_.value());
AddAnnotation("crash.thread.name", thread_name_.value());
if (process_koid_.has_value()) {
AddAnnotation("crash.process.koid", std::to_string(process_koid_.value()));
}
if (thread_koid_.has_value()) {
AddAnnotation("crash.thread.koid", std::to_string(thread_koid_.value()));
}
if (!component_url_.has_value()) {
AddAnnotation("debug.crash.component.url.set", "false");
}
if (realm_path_.has_value()) {
AddAnnotation("crash.realm-path", realm_path_.value());
}
FX_CHECK(minidump_.has_value() || exception_expired_ || process_already_terminated_);
if (minidump_.has_value()) {
NativeCrashReport native_crash_report;
fuchsia::mem::Buffer mem_buffer;
minidump_.value().get_size(&mem_buffer.size);
mem_buffer.vmo = std::move(minidump_.value());
minidump_ = std::nullopt;
native_crash_report.set_minidump(std::move(mem_buffer));
crash_report.set_specific_report(
SpecificCrashReport::WithNative(std::move(native_crash_report)));
} else {
GenericCrashReport generic_crash_report;
if (exception_expired_) {
generic_crash_report.set_crash_signature("fuchsia-no-minidump-exception-expired");
} else if (process_already_terminated_) {
generic_crash_report.set_crash_signature("fuchsia-no-minidump-process-terminated");
}
crash_report.set_specific_report(
SpecificCrashReport::WithGeneric(std::move(generic_crash_report)));
}
return crash_report;
}
} // namespace handler
} // namespace exceptions
} // namespace forensics