blob: 14c449144e20cfc98cbe53c6b6625dfd83659e13 [file] [log] [blame]
// Copyright 2019 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/tests/crasher_wrapper.h"
#include <lib/fdio/spawn.h>
#include <lib/syslog/cpp/macros.h>
#include <zircon/status.h>
#include <zircon/syscalls/port.h>
#include "src/lib/fsl/handles/object_info.h"
namespace forensics {
namespace exceptions {
bool SpawnCrasher(ExceptionContext* pe) {
zx::unowned_job current_job(zx_job_default());
if (zx_status_t res = zx::job::create(*current_job, 0, &pe->job); res != ZX_OK) {
FX_PLOGS(ERROR, res) << "Coult not create current job handle.";
return false;
}
if (zx_status_t res = pe->job.create_exception_channel(0, &pe->exception_channel); res != ZX_OK) {
FX_PLOGS(ERROR, res) << "Could not create exception channel for job.";
return false;
}
if (zx_status_t res = zx::port::create(0, &pe->port); res != ZX_OK) {
FX_PLOGS(ERROR, res) << "Could not create a port.";
return false;
}
constexpr uint64_t kKey = 0x1234;
if (zx_status_t res = pe->exception_channel.wait_async(pe->port, kKey, ZX_CHANNEL_READABLE, 0);
res != ZX_OK) {
FX_PLOGS(ERROR, res) << "Could not wait async on exception channel.";
return false;
}
// Create the process.
const char* argv[] = {"crasher", nullptr};
constexpr char kCrasherPath[] = "/pkg/bin/exception_broker_crasher";
char err_msg[FDIO_SPAWN_ERR_MSG_MAX_LENGTH];
if (zx_status_t res =
fdio_spawn_etc(pe->job.get(), FDIO_SPAWN_CLONE_ALL, kCrasherPath, argv, nullptr, 0,
nullptr, pe->process.reset_and_get_address(), err_msg);
res != ZX_OK) {
FX_PLOGS(ERROR, res) << "Could not spawn crasher process: " << err_msg;
return false;
}
// Wait for the exception.
zx_port_packet_t packet;
if (zx_status_t res = pe->port.wait(zx::time::infinite(), &packet); res != ZX_OK) {
FX_PLOGS(ERROR, res) << "Could not wait on port.";
return false;
}
if ((packet.key != kKey) || (packet.type != ZX_PKT_TYPE_SIGNAL_ONE) ||
((packet.signal.observed & ZX_CHANNEL_READABLE) == 0)) {
FX_PLOGS(ERROR, ZX_ERR_WRONG_TYPE) << "Received wrong port packet.";
return false;
}
// Read the exception.
if (zx_status_t res =
pe->exception_channel.read(0, &pe->exception_info, pe->exception.reset_and_get_address(),
sizeof(pe->exception_info), 1, nullptr, nullptr);
res != ZX_OK) {
FX_PLOGS(ERROR, res) << "Could not read exception.";
return false;
}
if (zx_status_t res = pe->exception.get_process(&pe->process); res != ZX_OK) {
FX_PLOGS(ERROR, res) << "Could not get process for exception.";
return false;
}
pe->process_koid = fsl::GetKoid(pe->process.get());
pe->process_name = fsl::GetObjectName(pe->process.get());
if (zx_status_t res = pe->exception.get_thread(&pe->thread); res != ZX_OK) {
FX_PLOGS(ERROR, res) << "Could not get thread for exception.";
return false;
}
pe->thread_koid = fsl::GetKoid(pe->thread.get());
pe->thread_name = fsl::GetObjectName(pe->thread.get());
return true;
}
bool MarkExceptionAsHandled(ExceptionContext* pe) {
uint32_t state = ZX_EXCEPTION_STATE_HANDLED;
if (zx_status_t res = pe->exception.set_property(ZX_PROP_EXCEPTION_STATE, &state, sizeof(state));
res != ZX_OK) {
FX_PLOGS(ERROR, res) << "Could not set handled state to exception.";
return false;
}
return true;
}
} // namespace exceptions
} // namespace forensics