blob: b9c537ca5c8436dde473dfecb78bb1658dab88dc [file] [log] [blame]
// Copyright 2024 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 <lib/zx/exception.h>
#include <lib/zx/job.h>
#include <lib/zx/process.h>
#include <zircon/errors.h>
#include <zircon/syscalls.h>
#include <zircon/syscalls/exception.h>
#include <thread>
#include <zxtest/zxtest.h>
namespace {
TEST(UserExceptionsTest, InvalidArgs) {
zx_exception_context_t context = {};
zx_status_t status = zx_thread_raise_exception(0, ZX_EXCP_USER, &context);
EXPECT_EQ(ZX_ERR_INVALID_ARGS, status);
status = zx_thread_raise_exception(ZX_EXCEPTION_TARGET_JOB_DEBUGGER, ZX_EXCP_THREAD_STARTING,
&context);
EXPECT_EQ(ZX_ERR_INVALID_ARGS, status);
status = zx_thread_raise_exception(ZX_EXCEPTION_TARGET_JOB_DEBUGGER, ZX_EXCP_USER, nullptr);
EXPECT_EQ(ZX_ERR_INVALID_ARGS, status);
}
TEST(UserExceptionsTest, NonFatal) {
zx_exception_context_t context = {};
EXPECT_OK(zx_thread_raise_exception(ZX_EXCEPTION_TARGET_JOB_DEBUGGER, ZX_EXCP_USER, &context));
}
TEST(UserExceptionsTest, Delivered) {
zx::channel exception_channel;
ASSERT_OK(zx::job::default_job()->create_exception_channel(ZX_EXCEPTION_CHANNEL_DEBUGGER,
&exception_channel));
zx_status_t raise_result = ZX_ERR_INTERNAL;
auto raise = std::thread([&raise_result]() {
zx_exception_context_t context = {};
context.synth_code = ZX_EXCP_USER_CODE_USER0;
context.synth_data = 42;
raise_result =
zx_thread_raise_exception(ZX_EXCEPTION_TARGET_JOB_DEBUGGER, ZX_EXCP_USER, &context);
});
zx_signals_t pending;
ASSERT_OK(exception_channel.wait_one(ZX_CHANNEL_READABLE | ZX_CHANNEL_PEER_CLOSED,
zx::time::infinite(), &pending));
ASSERT_NE(0, pending & ZX_CHANNEL_READABLE, "exception channel peer closed (pending 0x%08x)",
pending);
zx::exception exception;
zx_exception_info_t exception_info = {};
uint32_t byte_count = 0;
uint32_t handle_count = 0;
ASSERT_OK(exception_channel.read(0, &exception_info, exception.reset_and_get_address(),
sizeof(exception_info), 1, &byte_count, &handle_count));
ASSERT_EQ(sizeof(exception_info), byte_count);
ASSERT_EQ(1, handle_count);
ASSERT_EQ(ZX_EXCP_USER, exception_info.type);
zx::thread thread;
ASSERT_OK(exception.get_thread(&thread));
zx_exception_report_t report = {};
ASSERT_OK(
thread.get_info(ZX_INFO_THREAD_EXCEPTION_REPORT, &report, sizeof(report), nullptr, nullptr));
ASSERT_EQ(ZX_EXCP_USER_CODE_USER0, report.context.synth_code);
ASSERT_EQ(42, report.context.synth_data);
uint32_t value = ZX_EXCEPTION_STATE_HANDLED;
ASSERT_OK(exception.set_property(ZX_PROP_EXCEPTION_STATE, &value, sizeof(value)));
exception.reset();
exception_channel.reset();
raise.join();
ASSERT_OK(raise_result);
}
} // namespace