blob: ce5728838ce449bdbd598c694b0e5a68ae6d2643 [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 <fuchsia/crash/c/fidl.h>
#include <string.h>
#include <zircon/fidl.h>
#include <zircon/syscalls.h>
#include <unittest/unittest.h>
static int kContext = 42;
static size_t g_handle_exception_call_count = 0u;
static zx_status_t handle_exception(void* ctx, zx_handle_t process, zx_handle_t thread, zx_handle_t exception_port, fidl_txn_t* txn) {
++g_handle_exception_call_count;
EXPECT_EQ(&kContext, ctx, "");
EXPECT_NE(ZX_HANDLE_INVALID, process, "");
EXPECT_NE(ZX_HANDLE_INVALID, thread, "");
EXPECT_NE(ZX_HANDLE_INVALID, exception_port, "");
EXPECT_NE(NULL, txn, "");
zx_handle_close(process);
zx_handle_close(thread);
return ZX_OK;
}
static bool dispatch_test(void) {
BEGIN_TEST;
fuchsia_crash_Analyzer_ops_t ops = {
.HandleNativeException = handle_exception,
};
fuchsia_crash_AnalyzerHandleNativeExceptionRequest request;
memset(&request, 0, sizeof(request));
request.hdr.txid = 42;
request.hdr.ordinal = fuchsia_crash_AnalyzerHandleNativeExceptionOrdinal;
request.process = FIDL_HANDLE_PRESENT;
request.thread = FIDL_HANDLE_PRESENT;
request.exception_port = FIDL_HANDLE_PRESENT;
zx_handle_t handles[3];
fidl_msg_t msg = {
.bytes = &request,
.handles = handles,
.num_bytes = sizeof(request),
.num_handles = 3,
};
fidl_txn_t txn;
memset(&txn, 0, sizeof(txn));
// Success
zx_status_t status = zx_eventpair_create(0, &handles[0], &handles[1]);
ASSERT_EQ(ZX_OK, status, "");
status = zx_port_create(0, &handles[2]);
EXPECT_EQ(0u, g_handle_exception_call_count, "");
status = fuchsia_crash_Analyzer_dispatch(&kContext, &txn, &msg, &ops);
ASSERT_EQ(ZX_OK, status, "");
EXPECT_EQ(1u, g_handle_exception_call_count, "");
g_handle_exception_call_count = 0u;
// Bad ordinal (dispatch)
request.hdr.ordinal = 8949;
zx_handle_t canary0 = ZX_HANDLE_INVALID;
status = zx_eventpair_create(0, &handles[0], &canary0);
ASSERT_EQ(ZX_OK, status, "");
zx_handle_t canary1 = ZX_HANDLE_INVALID;
status = zx_eventpair_create(0, &handles[1], &canary1);
ASSERT_EQ(ZX_OK, status, "");
zx_handle_t canary2 = ZX_HANDLE_INVALID;
status = zx_eventpair_create(0, &handles[2], &canary2);
ASSERT_EQ(ZX_OK, status, "");
EXPECT_EQ(0u, g_handle_exception_call_count, "");
status = fuchsia_crash_Analyzer_dispatch(&kContext, &txn, &msg, &ops);
ASSERT_EQ(ZX_ERR_NOT_SUPPORTED, status, "");
EXPECT_EQ(0u, g_handle_exception_call_count, "");
g_handle_exception_call_count = 0u;
status = zx_object_signal_peer(canary0, 0, ZX_USER_SIGNAL_0);
ASSERT_EQ(ZX_ERR_PEER_CLOSED, status, "");
status = zx_object_signal_peer(canary1, 0, ZX_USER_SIGNAL_0);
ASSERT_EQ(ZX_ERR_PEER_CLOSED, status, "");
zx_handle_close(canary0);
zx_handle_close(canary1);
zx_handle_close(canary2);
// Bad ordinal (try_dispatch)
request.hdr.ordinal = 8949;
canary0 = ZX_HANDLE_INVALID;
status = zx_eventpair_create(0, &handles[0], &canary0);
ASSERT_EQ(ZX_OK, status, "");
canary1 = ZX_HANDLE_INVALID;
status = zx_eventpair_create(0, &handles[1], &canary1);
ASSERT_EQ(ZX_OK, status, "");
canary2 = ZX_HANDLE_INVALID;
status = zx_eventpair_create(0, &handles[2], &canary2);
ASSERT_EQ(ZX_OK, status, "");
EXPECT_EQ(0u, g_handle_exception_call_count, "");
status = fuchsia_crash_Analyzer_try_dispatch(&kContext, &txn, &msg, &ops);
ASSERT_EQ(ZX_ERR_NOT_SUPPORTED, status, "");
EXPECT_EQ(0u, g_handle_exception_call_count, "");
g_handle_exception_call_count = 0u;
status = zx_object_signal_peer(canary0, 0, ZX_USER_SIGNAL_0);
ASSERT_EQ(ZX_OK, status, "");
status = zx_object_signal_peer(canary1, 0, ZX_USER_SIGNAL_0);
ASSERT_EQ(ZX_OK, status, "");
zx_handle_close_many(handles, 3);
zx_handle_close(canary0);
zx_handle_close(canary1);
zx_handle_close(canary2);
END_TEST;
}
typedef struct my_connection {
fidl_txn_t txn;
size_t count;
} my_connection_t;
static zx_status_t reply_handler(fidl_txn_t* txn, const fidl_msg_t* msg) {
my_connection_t* my_txn = (my_connection_t*)txn;
EXPECT_EQ(sizeof(fuchsia_crash_AnalyzerHandleNativeExceptionResponse), msg->num_bytes, "");
EXPECT_EQ(0u, msg->num_handles, "");
++my_txn->count;
return ZX_OK;
}
static bool reply_test(void) {
BEGIN_TEST;
my_connection_t conn;
conn.txn.reply = reply_handler;
conn.count = 0u;
zx_status_t status = fuchsia_crash_AnalyzerHandleNativeException_reply(&conn.txn, ZX_OK);
ASSERT_EQ(ZX_OK, status, "");
EXPECT_EQ(1u, conn.count, "");
END_TEST;
}
static zx_status_t return_async(void* ctx, zx_handle_t process, zx_handle_t thread, zx_handle_t exception_port, fidl_txn_t* txn) {
zx_handle_close(process);
zx_handle_close(thread);
zx_handle_close(exception_port);
return ZX_ERR_ASYNC;
}
static bool error_test(void) {
BEGIN_TEST;
fuchsia_crash_Analyzer_ops_t ops = {
.HandleNativeException = return_async,
};
fuchsia_crash_AnalyzerHandleNativeExceptionRequest request;
memset(&request, 0, sizeof(request));
request.hdr.txid = 42;
request.hdr.ordinal = fuchsia_crash_AnalyzerHandleNativeExceptionOrdinal;
request.process = FIDL_HANDLE_PRESENT;
request.thread = FIDL_HANDLE_PRESENT;
request.exception_port = FIDL_HANDLE_PRESENT;
zx_handle_t handles[3];
fidl_msg_t msg = {
.bytes = &request,
.handles = handles,
.num_bytes = sizeof(request),
.num_handles = 3,
};
fidl_txn_t txn;
memset(&txn, 0, sizeof(txn));
zx_status_t status = zx_eventpair_create(0, &handles[0], &handles[1]);
ASSERT_EQ(ZX_OK, status, "");
status = zx_port_create(0, &handles[2]);
ASSERT_EQ(ZX_OK, status, "");
status = fuchsia_crash_Analyzer_try_dispatch(NULL, &txn, &msg, &ops);
ASSERT_EQ(ZX_ERR_ASYNC, status, "");
END_TEST;
}
BEGIN_TEST_CASE(server_tests)
RUN_NAMED_TEST("fuchsia.crash.Analyzer dispatch test", dispatch_test)
RUN_NAMED_TEST("fuchsia.crash.Analyzer reply test", reply_test)
RUN_NAMED_TEST("fuchsia.crash.Analyzer error test", error_test)
END_TEST_CASE(server_tests);