1// Copyright 2016 The Fuchsia Authors. All rights reserved.
2// Use of this source code is governed by a BSD-style license that can be
3// found in the LICENSE file.
4
5// N.B. We can't fully test the system exception handler here as that would
6// interfere with the global crash logger.
7// TODO(dbort): A good place to test the system exception handler would be in
8// the "core" tests.
9
10#include <assert.h>
11#include <inttypes.h>
12#include <stdatomic.h>
13#include <stdbool.h>
14#include <stdio.h>
15#include <stdlib.h>
16#include <string.h>
17#include <unistd.h>
18#include <zircon/compiler.h>
19#include <zircon/process.h>
20#include <zircon/processargs.h>
21#include <zircon/syscalls.h>
22#include <zircon/syscalls/debug.h>
23#include <zircon/syscalls/exception.h>
24#include <zircon/syscalls/port.h>
25#include <zircon/threads.h>
26#include <test-utils/test-utils.h>
27#include <unittest/unittest.h>
28
29static int thread_func(void* arg);
30
31// argv[0]
32static char* program_path;
33
34// This is the key that is assigned to the port when bound.
35// This value appears in |packet.key| in all exception messages.
36static const uint64_t EXCEPTION_PORT_KEY = 0x6b6579; // "key"
37
38static const char test_child_name[] = "test-child";
39static const char exit_closing_excp_handle_child_name[] = "exit-closing-excp-handle";
40
41enum message {
42    // Make the type of this enum signed so that we don't get a compile failure
43    // later with things like EXPECT_EQ(msg, MSG_PONG) [unsigned vs signed
44    // comparison mismatch]
45    MSG_ENSURE_SIGNED = -1,
46    MSG_DONE,
47    MSG_CRASH,
48    MSG_PING,
49    MSG_PONG,
50    MSG_CREATE_AUX_THREAD,
51    MSG_AUX_THREAD_HANDLE,
52    MSG_CRASH_AUX_THREAD,
53    MSG_SHUTDOWN_AUX_THREAD
54};
55
56static void crash_me(void)
57{
58    unittest_printf("Attempting to crash.");
59    volatile int* p = 0;
60    *p = 42;
61}
62
63static void send_msg_new_thread_handle(zx_handle_t handle, zx_handle_t thread)
64{
65    // Note: The handle is transferred to the receiver.
66    uint64_t data = MSG_AUX_THREAD_HANDLE;
67    unittest_printf("sending new thread %d message on handle %u\n", thread, handle);
68    tu_channel_write(handle, 0, &data, sizeof(data), &thread, 1);
69}
70
71static void send_msg(zx_handle_t handle, enum message msg)
72{
73    uint64_t data = msg;
74    unittest_printf("sending message %d on handle %u\n", msg, handle);
75    tu_channel_write(handle, 0, &data, sizeof(data), NULL, 0);
76}
77
78static bool recv_msg(zx_handle_t handle, enum message* msg)
79{
80    uint64_t data;
81    uint32_t num_bytes = sizeof(data);
82
83    unittest_printf("waiting for message on handle %u\n", handle);
84
85    if (!tu_channel_wait_readable(handle)) {
86        unittest_printf("peer closed while trying to read message\n");
87        return false;
88    }
89
90    tu_channel_read(handle, 0, &data, &num_bytes, NULL, 0);
91    if (num_bytes != sizeof(data)) {
92        unittest_printf("recv_msg: unexpected message size, %u != %zu\n",
93                        num_bytes, sizeof(data));
94        return false;
95    }
96
97    *msg = data;
98    unittest_printf("received message %d\n", *msg);
99    return true;
100}
101
102// This returns "bool" because it uses ASSERT_*.
103
104static bool recv_msg_new_thread_handle(zx_handle_t handle, zx_handle_t* thread)
105{
106    uint64_t data;
107    uint32_t num_bytes = sizeof(data);
108
109    unittest_printf("waiting for message on handle %u\n", handle);
110
111    ASSERT_TRUE(tu_channel_wait_readable(handle), "peer closed while trying to read message");
112
113    uint32_t num_handles = 1;
114    tu_channel_read(handle, 0, &data, &num_bytes, thread, &num_handles);
115    ASSERT_EQ(num_bytes, sizeof(data), "unexpected message size");
116    ASSERT_EQ(num_handles, 1u, "expected one returned handle");
117
118    enum message msg = data;
119    ASSERT_EQ(msg, MSG_AUX_THREAD_HANDLE, "expected MSG_AUX_THREAD_HANDLE");
120
121    unittest_printf("received thread handle %d\n", *thread);
122    return true;
123}
124
125// "resume" here means "tell the kernel we're done"
126// This test assumes no presence of the "debugger API" and therefore we can't
127// resume from a segfault. Such a test is for the debugger API anyway.
128
129static void resume_thread_from_exception(zx_handle_t process, zx_koid_t tid,
130                                         uint32_t excp_port_type,
131                                         uint32_t flags)
132{
133    zx_handle_t thread;
134    zx_status_t status = zx_object_get_child(process, tid, ZX_RIGHT_SAME_RIGHTS, &thread);
135    if (status < 0)
136        tu_fatal("zx_object_get_child", status);
137
138    zx_info_thread_t info = tu_thread_get_info(thread);
139    EXPECT_EQ(info.state, ZX_THREAD_STATE_BLOCKED_EXCEPTION, "");
140    if (excp_port_type != ZX_EXCEPTION_PORT_TYPE_NONE) {
141        EXPECT_EQ(info.wait_exception_port_type, excp_port_type, "");
142    }
143
144    status = zx_task_resume(thread, ZX_RESUME_EXCEPTION | flags);
145    if (status < 0)
146        tu_fatal("resume_thread_from_exception", status);
147    zx_handle_close(thread);
148}
149
150// Wait for and receive an exception or signal on |eport|.
151
152static bool read_packet(zx_handle_t eport, zx_port_packet_t* packet)
153{
154    ASSERT_EQ(zx_port_wait(eport, ZX_TIME_INFINITE, packet), ZX_OK, "zx_port_wait failed");
155    if (ZX_PKT_IS_SIGNAL_REP(packet->type)) {
156        unittest_printf("signal received: key %" PRIu64 ", observed 0x%x\n",
157                        packet->key, packet->signal.observed);
158    } else {
159        ASSERT_TRUE(ZX_PKT_IS_EXCEPTION(packet->type), "");
160        ASSERT_EQ(packet->key, EXCEPTION_PORT_KEY, "bad report key");
161        ASSERT_EQ(packet->status, ZX_OK, "");
162        unittest_printf("exception received: pid %"
163                        PRIu64 ", tid %" PRIu64 ", type %d\n",
164                        packet->exception.pid, packet->exception.tid, packet->type);
165    }
166    return true;
167}
168
169// The bool result is because we use the unittest EXPECT/ASSERT macros.
170
171static bool verify_exception(const zx_port_packet_t* packet,
172                             zx_handle_t process,
173                             zx_excp_type_t expected_type)
174{
175    ASSERT_EQ(packet->type, expected_type, "");
176    EXPECT_EQ(packet->key, EXCEPTION_PORT_KEY, "");
177
178    // Verify the exception was from |process|.
179    if (process != ZX_HANDLE_INVALID) {
180        zx_koid_t pid = tu_get_koid(process);
181        EXPECT_EQ(pid, packet->exception.pid, "");
182    }
183
184    return true;
185}
186
187// The bool result is because we use the unittest EXPECT/ASSERT macros.
188
189static bool verify_signal(const zx_port_packet_t* packet,
190                          uint64_t key,
191                          zx_signals_t expected_signals)
192{
193    ASSERT_TRUE(ZX_PKT_IS_SIGNAL_ONE(packet->type) ||
194                ZX_PKT_IS_SIGNAL_REP(packet->type),
195                "");
196
197    if (key != 0u)
198        EXPECT_EQ(packet->key, key, "");
199    EXPECT_TRUE(packet->signal.observed & expected_signals, "");
200
201    return true;
202}
203
204static bool read_and_verify_exception(zx_handle_t eport,
205                                      zx_handle_t process,
206                                      zx_excp_type_t expected_type,
207                                      zx_koid_t* tid)
208{
209    zx_port_packet_t packet;
210    if (!read_packet(eport, &packet))
211        return false;
212    *tid = packet.exception.tid;
213    return verify_exception(&packet, process, expected_type);
214}
215
216// Wait for a process to exit, and while it's exiting verify we get the
217// expected exception reports.
218// The caller must have attached an async-wait for |process| to |eport|.
219// See start_test_child_with_eport().
220// We may receive thread-exit reports while the process is terminating but
221// any other kind of exception is an error.
222// This may be used when attached to the process or debugger exception port.
223// The bool result is because we use the unittest EXPECT/ASSERT macros.
224
225static bool wait_process_exit(zx_handle_t eport, zx_handle_t process) {
226    zx_port_packet_t packet;
227    zx_koid_t pid = tu_get_koid(process);
228
229    for (;;) {
230        unittest_printf("%s: calling read_packet\n", __func__);
231        if (!read_packet(eport, &packet))
232            return false;
233        unittest_printf("%s: read_packet done\n", __func__);
234        // If we get a process exit signal then all threads have exited.
235        // Any other signal packet is an error.
236        if (ZX_PKT_IS_SIGNAL_ONE(packet.type) ||
237            ZX_PKT_IS_SIGNAL_REP(packet.type)) {
238            if (packet.key == pid && (packet.signal.observed & ZX_PROCESS_TERMINATED))
239                break;
240            ASSERT_TRUE(false, "");
241        }
242        if (!verify_exception(&packet, process, ZX_EXCP_THREAD_EXITING))
243            return false;
244        // ZX_EXCP_THREAD_EXITING reports must normally be responded to.
245        // However, when the process exits it kills all threads which will
246        // kick them out of the ExceptionHandlerExchange. Thus there's no
247        // need to resume them here.
248    }
249
250    // This isn't necessary, but it tests being able to wait on the process
251    // handle directly, after having waited on it via |eport|.
252    tu_process_wait_signaled(process);
253    return true;
254}
255
256// Wait for a process to exit, and while it's exiting verify we get the
257// expected exception reports.
258// The caller must have attached an async-wait for |process| to |eport|.
259// See start_test_child_with_eport().
260// N.B. This is only for use when attached to the debugger exception port:
261// only it gets thread-exit reports.
262// A thread-exit report for |tid| is expected to be seen.
263// We may get other thread-exit reports, that's ok, we don't assume the child
264// is single-threaded. But it is an error to get any other kind of exception
265// report from a thread.
266// The bool result is because we use the unittest EXPECT/ASSERT macros.
267
268static bool wait_process_exit_from_debugger(zx_handle_t eport, zx_handle_t process, zx_koid_t tid) {
269    bool tid_seen = false;
270    zx_port_packet_t packet;
271    zx_koid_t pid = tu_get_koid(process);
272
273    ASSERT_NE(tid, ZX_KOID_INVALID, "invalid koid");
274
275    for (;;) {
276        unittest_printf("%s: calling read_packet\n", __func__);
277        if (!read_packet(eport, &packet))
278            return false;
279        unittest_printf("%s: read_packet done\n", __func__);
280        // If we get a process exit signal then all threads have exited.
281        // Any other signal packet is an error.
282        if (ZX_PKT_IS_SIGNAL_ONE(packet.type) ||
283            ZX_PKT_IS_SIGNAL_REP(packet.type)) {
284            if (packet.key == pid && (packet.signal.observed & ZX_PROCESS_TERMINATED))
285                break;
286            ASSERT_TRUE(false, "");
287        }
288        if (!verify_exception(&packet, process, ZX_EXCP_THREAD_EXITING))
289            return false;
290        if (packet.exception.tid == tid)
291            tid_seen = true;
292        // ZX_EXCP_THREAD_EXITING reports must normally be responded to.
293        // However, when the process exits it kills all threads which will
294        // kick them out of the ExceptionHandlerExchange. So send this thread
295        // on its way, but it's ok if the thread is gone.
296        zx_handle_t thread;
297        zx_status_t status = zx_object_get_child(process, tid, ZX_RIGHT_SAME_RIGHTS, &thread);
298        if (status == ZX_OK) {
299            status = zx_task_resume(thread, ZX_RESUME_EXCEPTION);
300            if (status < 0) {
301                // If the resume failed the thread must be dying or dead.
302                EXPECT_EQ(status, ZX_ERR_BAD_STATE, "");
303                EXPECT_TRUE(tu_thread_is_dying_or_dead(thread), "");
304            }
305            zx_handle_close(thread);
306        }
307    }
308
309    EXPECT_TRUE(tid_seen, "missing ZX_EXCP_THREAD_EXITING report");
310
311    // This isn't necessary, but it tests being able to wait on the process
312    // handle directly, after having waited on it via |eport|.
313    tu_process_wait_signaled(process);
314    return true;
315}
316
317static bool ensure_child_running(zx_handle_t channel) {
318    // Note: This function is called from external threads and thus does
319    // not use EXPECT_*/ASSERT_*.
320    enum message msg;
321    send_msg(channel, MSG_PING);
322    if (!recv_msg(channel, &msg)) {
323        unittest_printf("ensure_child_running: Error while receiving msg\n");
324        return false;
325    }
326    if (msg != MSG_PONG) {
327        unittest_printf("ensure_child_running: expecting PONG, got %d instead\n", msg);
328        return false;
329    }
330    return true;
331}
332
333static void msg_loop(zx_handle_t channel)
334{
335    bool my_done_tests = false;
336    zx_handle_t channel_to_thread = ZX_HANDLE_INVALID;
337
338    while (!my_done_tests)
339    {
340        enum message msg;
341        if (!recv_msg(channel, &msg)) {
342            unittest_printf("Error while receiving msg\n");
343            return;
344        }
345        switch (msg)
346        {
347        case MSG_DONE:
348            my_done_tests = true;
349            break;
350        case MSG_CRASH:
351            crash_me();
352            break;
353        case MSG_PING:
354            send_msg(channel, MSG_PONG);
355            break;
356        case MSG_CREATE_AUX_THREAD:
357            // Spin up a thread that we can talk to.
358            {
359                if (channel_to_thread != ZX_HANDLE_INVALID) {
360                    unittest_printf("previous thread connection not shutdown");
361                    return;
362                }
363                zx_handle_t channel_from_thread;
364                tu_channel_create(&channel_to_thread, &channel_from_thread);
365                thrd_t thread;
366                tu_thread_create_c11(&thread, thread_func, (void*) (uintptr_t) channel_from_thread, "msg-loop-subthread");
367                // Make sure the new thread is up and running before sending
368                // its handle back: this removes potential problems like
369                // needing to handle ZX_EXCP_THREAD_STARTING exceptions if the
370                // debugger exception port is bound later.
371                if (ensure_child_running(channel_to_thread)) {
372                    zx_handle_t thread_handle = thrd_get_zx_handle(thread);
373                    zx_handle_t copy = tu_handle_duplicate(thread_handle);
374                    send_msg_new_thread_handle(channel, copy);
375                } else {
376                    // We could terminate the thread or some such, but the
377                    // process will be killed by our "caller".
378                    send_msg_new_thread_handle(channel, ZX_HANDLE_INVALID);
379                    zx_handle_close(channel_to_thread);
380                    channel_to_thread = ZX_HANDLE_INVALID;
381                }
382            }
383            break;
384        case MSG_CRASH_AUX_THREAD:
385            send_msg(channel_to_thread, MSG_CRASH);
386            break;
387        case MSG_SHUTDOWN_AUX_THREAD:
388            send_msg(channel_to_thread, MSG_DONE);
389            zx_handle_close(channel_to_thread);
390            channel_to_thread = ZX_HANDLE_INVALID;
391            break;
392        default:
393            unittest_printf("unknown message received: %d\n", msg);
394            break;
395        }
396    }
397}
398
399static int thread_func(void* arg)
400{
401    unittest_printf("test thread starting\n");
402    zx_handle_t msg_channel = (zx_handle_t) (uintptr_t) arg;
403    msg_loop(msg_channel);
404    unittest_printf("test thread exiting\n");
405    tu_handle_close(msg_channel);
406    return 0;
407}
408
409static void __NO_RETURN test_child(void)
410{
411    unittest_printf("Test child starting.\n");
412    zx_handle_t channel = zx_take_startup_handle(PA_USER0);
413    if (channel == ZX_HANDLE_INVALID)
414        tu_fatal("zx_take_startup_handle", ZX_ERR_BAD_HANDLE - 1000);
415    msg_loop(channel);
416    unittest_printf("Test child exiting.\n");
417    exit(0);
418}
419
420static launchpad_t* setup_test_child(zx_handle_t job, const char* arg,
421                                     zx_handle_t* out_channel)
422{
423    unittest_printf("Starting test child %s.\n", arg);
424    zx_handle_t our_channel, their_channel;
425    tu_channel_create(&our_channel, &their_channel);
426    const char* test_child_path = program_path;
427    const char verbosity_string[] = { 'v', '=', utest_verbosity_level + '0', '\0' };
428    const char* const argv[] = {
429        test_child_path,
430        arg,
431        verbosity_string,
432    };
433    int argc = countof(argv);
434    zx_handle_t handles[1] = { their_channel };
435    uint32_t handle_ids[1] = { PA_USER0 };
436    *out_channel = our_channel;
437    launchpad_t* lp = tu_launch_fdio_init(job, test_child_name, argc, argv,
438                                          NULL, 1, handles, handle_ids);
439    unittest_printf("Test child setup.\n");
440    return lp;
441}
442
443static void start_test_child(zx_handle_t job, const char* arg,
444                             zx_handle_t* out_child, zx_handle_t* out_channel)
445{
446    launchpad_t* lp = setup_test_child(job, arg, out_channel);
447    *out_child = tu_launch_fdio_fini(lp);
448    unittest_printf("Test child started.\n");
449}
450
451static void start_test_child_with_eport(zx_handle_t job, const char* arg,
452                                        zx_handle_t* out_child,
453                                        zx_handle_t* out_eport,
454                                        zx_handle_t* out_channel)
455{
456    launchpad_t* lp = setup_test_child(zx_job_default(), arg, out_channel);
457    zx_handle_t eport = tu_io_port_create();
458    // Note: child is a borrowed handle, launchpad still owns it at this point.
459    zx_handle_t child = launchpad_get_process_handle(lp);
460    tu_set_exception_port(child, eport, EXCEPTION_PORT_KEY, ZX_EXCEPTION_PORT_DEBUGGER);
461    child = tu_launch_fdio_fini(lp);
462    // Now we own the child handle, and lp is destroyed.
463    // Note: This is a different handle, the previous child handle is gone at
464    // this point (transfered to the child process).
465    unittest_printf("child 0x%x, eport 0x%x\n", child, eport);
466    tu_object_wait_async(child, eport, ZX_PROCESS_TERMINATED);
467    *out_child = child;
468    *out_eport = eport;
469}
470
471// Tests binding and unbinding behavior.
472// |object| must be a valid job, process, or thread handle.
473// |debugger| must only be set if |object| is a process handle. If set,
474// tests the behavior of binding the debugger eport; otherwise, binds
475// the non-debugger exception port.
476// This returns "bool" because it uses ASSERT_*.
477static bool test_set_close_set(zx_handle_t object, bool debugger) {
478    ASSERT_NE(object, ZX_HANDLE_INVALID, "invalid handle");
479    uint32_t options = debugger ? ZX_EXCEPTION_PORT_DEBUGGER : 0;
480
481    // Bind an exception port to the object.
482    zx_handle_t eport = tu_io_port_create();
483    zx_status_t status;
484    status = zx_task_bind_exception_port(object, eport, 0, options);
485    ASSERT_EQ(status, ZX_OK, "error setting exception port");
486
487    // Try binding another exception port to the same object, which should fail.
488    zx_handle_t eport2 = tu_io_port_create();
489    status = zx_task_bind_exception_port(object, eport, 0, options);
490    ASSERT_EQ(status, ZX_ERR_ALREADY_BOUND,
491              "wrong result from setting already bound exception port");
492
493    // Close the ports.
494    tu_handle_close(eport2);
495    tu_handle_close(eport);
496
497    // Verify the close removed the previous handler by successfully
498    // adding a new one.
499    eport = tu_io_port_create();
500    status = zx_task_bind_exception_port(object, eport, 0, options);
501    ASSERT_EQ(status, ZX_OK, "error setting exception port (#2)");
502    tu_handle_close(eport);
503
504    // Try unbinding from an object without a bound port, which should fail.
505    status =
506        zx_task_bind_exception_port(object, ZX_HANDLE_INVALID, 0, options);
507    ASSERT_NE(status, ZX_OK,
508              "resetting unbound exception port errantly succeeded");
509
510    return true;
511}
512
513static bool job_set_close_set_test(void)
514{
515    BEGIN_TEST;
516    zx_handle_t job = tu_job_create(zx_job_default());
517    test_set_close_set(job, /* debugger */ false);
518    tu_handle_close(job);
519    END_TEST;
520}
521
522static bool process_set_close_set_test(void)
523{
524    BEGIN_TEST;
525    test_set_close_set(zx_process_self(), /* debugger */ false);
526    END_TEST;
527}
528
529static bool process_debugger_set_close_set_test(void)
530{
531    BEGIN_TEST;
532    test_set_close_set(zx_process_self(), /* debugger */ true);
533    END_TEST;
534}
535
536static bool thread_set_close_set_test(void)
537{
538    BEGIN_TEST;
539    zx_handle_t our_channel, their_channel;
540    tu_channel_create(&our_channel, &their_channel);
541    thrd_t thread;
542    tu_thread_create_c11(&thread, thread_func, (void*)(uintptr_t)their_channel,
543                         "thread-set-close-set");
544    zx_handle_t thread_handle = thrd_get_zx_handle(thread);
545    test_set_close_set(thread_handle, /* debugger */ false);
546    send_msg(our_channel, MSG_DONE);
547    // thrd_join doesn't provide a timeout, but we have the watchdog for that.
548    thrd_join(thread, NULL);
549    END_TEST;
550}
551
552typedef struct {
553    zx_handle_t proc;
554    zx_handle_t vmar;
555} proc_handles;
556
557// Creates but does not start a process, returning its handles in |*ph|.
558// Returns false if an assertion fails.
559static bool create_non_running_process(const char* name, proc_handles* ph) {
560    memset(ph, 0, sizeof(*ph));
561    zx_status_t status = zx_process_create(
562        zx_job_default(), name, strlen(name), 0, &ph->proc, &ph->vmar);
563    ASSERT_EQ(status, ZX_OK, "zx_process_create");
564    ASSERT_NE(ph->proc, ZX_HANDLE_INVALID, "proc handle");
565    return true;
566}
567
568// Closes any valid handles in |ph|.
569static void close_proc_handles(proc_handles *ph) {
570    if (ph->proc > 0) {
571        tu_handle_close(ph->proc);
572        ph->proc = ZX_HANDLE_INVALID;
573    }
574    if (ph->vmar > 0) {
575        tu_handle_close(ph->vmar);
576        ph->vmar = ZX_HANDLE_INVALID;
577    }
578}
579
580static bool non_running_process_set_close_set_test(void) {
581    BEGIN_TEST;
582
583    // Create but do not start a process.
584    proc_handles ph;
585    ASSERT_TRUE(create_non_running_process(__func__, &ph), "");
586
587    // Make sure binding and unbinding behaves.
588    test_set_close_set(ph.proc, /* debugger */ false);
589
590    close_proc_handles(&ph);
591    END_TEST;
592}
593
594static bool non_running_process_debugger_set_close_set_test(void) {
595    BEGIN_TEST;
596
597    // Create but do not start a process.
598    proc_handles ph;
599    ASSERT_TRUE(create_non_running_process(__func__, &ph), "");
600
601    // Make sure binding and unbinding behaves.
602    test_set_close_set(ph.proc, /* debugger */ true);
603
604    close_proc_handles(&ph);
605    END_TEST;
606}
607
608static bool non_running_thread_set_close_set_test(void) {
609    BEGIN_TEST;
610
611    // Create but do not start a process.
612    proc_handles ph;
613    ASSERT_TRUE(create_non_running_process(__func__, &ph), "");
614
615    // Create but do not start a thread in that process.
616    zx_handle_t thread = ZX_HANDLE_INVALID;
617    zx_status_t status =
618        zx_thread_create(ph.proc, __func__, sizeof(__func__)-1, 0, &thread);
619    ASSERT_EQ(status, ZX_OK, "zx_thread_create");
620    ASSERT_NE(thread, ZX_HANDLE_INVALID, "thread handle");
621
622    // Make sure binding and unbinding behaves.
623    test_set_close_set(thread, /* debugger */ false);
624
625    tu_handle_close(thread);
626    close_proc_handles(&ph);
627    END_TEST;
628}
629
630// Creates a process, possibly binds an eport to it (if |bind_while_alive| is set),
631// then tries to unbind the eport, checking for the expected status.
632static bool dead_process_unbind_helper(bool debugger, bool bind_while_alive) {
633    const uint32_t options = debugger ? ZX_EXCEPTION_PORT_DEBUGGER : 0;
634
635    // Start a new process.
636    zx_handle_t child, our_channel;
637    start_test_child(zx_job_default(), test_child_name, &child, &our_channel);
638
639    // Possibly bind an eport to it.
640    zx_handle_t eport = ZX_HANDLE_INVALID;
641    if (bind_while_alive) {
642        // If we're binding to the debugger exception port make sure the
643        // child is running first so that we don't have to process
644        // ZX_EXCP_THREAD_STARTING.
645        if (debugger) {
646            ASSERT_TRUE(ensure_child_running(our_channel), "");
647        }
648        eport = tu_io_port_create();
649        tu_set_exception_port(child, eport, EXCEPTION_PORT_KEY, options);
650        tu_object_wait_async(child, eport, ZX_PROCESS_TERMINATED);
651    }
652
653    // Tell the process to exit and wait for it.
654    send_msg(our_channel, MSG_DONE);
655    if (debugger && bind_while_alive) {
656        // If we bound a debugger port, the process won't die until we
657        // consume the exception reports.
658        ASSERT_TRUE(wait_process_exit(eport, child), "");
659    } else {
660        ASSERT_EQ(tu_process_wait_exit(child), 0, "non-zero exit code");
661    }
662
663    // Try unbinding.
664    zx_status_t status =
665        zx_task_bind_exception_port(child, ZX_HANDLE_INVALID, 0, options);
666    if (bind_while_alive) {
667        EXPECT_EQ(status, ZX_OK, "matched unbind should have succeeded");
668    } else {
669        EXPECT_NE(status, ZX_OK, "unmatched unbind should have failed");
670    }
671
672    // Clean up.
673    tu_handle_close(child);
674    if (eport != ZX_HANDLE_INVALID) {
675        tu_handle_close(eport);
676    }
677    tu_handle_close(our_channel);
678    return true;
679}
680
681static bool dead_process_matched_unbind_succeeds_test(void) {
682    BEGIN_TEST;
683    // If an eport is bound while a process is alive, it should be
684    // valid to unbind it after the process is dead.
685    ASSERT_TRUE(dead_process_unbind_helper(
686        /* debugger */ false, /* bind_while_alive */ true), "");
687    END_TEST;
688}
689
690static bool dead_process_mismatched_unbind_fails_test(void) {
691    BEGIN_TEST;
692    // If an eport was not bound while a process was alive, it should be
693    // invalid to unbind it after the process is dead.
694    ASSERT_TRUE(dead_process_unbind_helper(
695        /* debugger */ false, /* bind_while_alive */ false), "");
696    END_TEST;
697}
698
699static bool dead_process_debugger_matched_unbind_succeeds_test(void) {
700    BEGIN_TEST;
701    // If a debugger port is bound while a process is alive, it should be
702    // valid to unbind it after the process is dead.
703    ASSERT_TRUE(dead_process_unbind_helper(
704        /* debugger */ true, /* bind_while_alive */ true), "");
705    END_TEST;
706}
707
708static bool dead_process_debugger_mismatched_unbind_fails_test(void) {
709    BEGIN_TEST;
710    // If an eport was not bound while a process was alive, it should be
711    // invalid to unbind it after the process is dead.
712    ASSERT_TRUE(dead_process_unbind_helper(
713        /* debugger */ true, /* bind_while_alive */ false), "");
714    END_TEST;
715}
716
717// Creates a thread, possibly binds an eport to it (if |bind_while_alive| is set),
718// then tries to unbind the eport, checking for the expected status.
719static bool dead_thread_unbind_helper(bool bind_while_alive) {
720    // Start a new thread.
721    zx_handle_t our_channel, their_channel;
722    tu_channel_create(&our_channel, &their_channel);
723    thrd_t cthread;
724    tu_thread_create_c11(&cthread, thread_func, (void*)(uintptr_t)their_channel,
725                         "thread-set-close-set");
726    zx_handle_t thread = thrd_get_zx_handle(cthread);
727    ASSERT_NE(thread, ZX_HANDLE_INVALID, "failed to get thread handle");
728
729    // Duplicate the thread's handle. thrd_join() will close the |thread|
730    // handle, but we need to be able to refer to the thread after that.
731    zx_handle_t thread_copy = tu_handle_duplicate(thread);
732
733    // Possibly bind an eport to it.
734    zx_handle_t eport = ZX_HANDLE_INVALID;
735    if (bind_while_alive) {
736        eport = tu_io_port_create();
737        tu_set_exception_port(thread, eport, EXCEPTION_PORT_KEY, 0);
738    }
739
740    // Tell the thread to exit and wait for it.
741    send_msg(our_channel, MSG_DONE);
742    // thrd_join doesn't provide a timeout, but we have the watchdog for that.
743    thrd_join(cthread, NULL);
744
745    // Try unbinding.
746    zx_status_t status =
747        zx_task_bind_exception_port(thread_copy, ZX_HANDLE_INVALID, 0, 0);
748    if (bind_while_alive) {
749        EXPECT_EQ(status, ZX_OK, "matched unbind should have succeeded");
750    } else {
751        EXPECT_NE(status, ZX_OK, "unmatched unbind should have failed");
752    }
753
754    // Clean up. The |thread| and |their_channel| handles died
755    // along with the thread.
756    tu_handle_close(thread_copy);
757    if (eport != ZX_HANDLE_INVALID) {
758        tu_handle_close(eport);
759    }
760    tu_handle_close(our_channel);
761    return true;
762}
763
764static bool dead_thread_matched_unbind_succeeds_test(void) {
765    BEGIN_TEST;
766    // If an eport is bound while a thread is alive, it should be
767    // valid to unbind it after the thread is dead.
768    ASSERT_TRUE(dead_thread_unbind_helper(/* bind_while_alive */ true), "");
769    END_TEST;
770}
771
772static bool dead_thread_mismatched_unbind_fails_test(void) {
773    BEGIN_TEST;
774    // If an eport was not bound while a thread was alive, it should be
775    // invalid to unbind it after the thread is dead.
776    ASSERT_TRUE(dead_thread_unbind_helper(/* bind_while_alive */ false), "");
777    END_TEST;
778}
779
780static void finish_basic_test(zx_handle_t child,
781                              zx_handle_t eport, zx_handle_t our_channel,
782                              enum message crash_msg, uint32_t excp_port_type)
783{
784    send_msg(our_channel, crash_msg);
785
786    zx_koid_t tid;
787    if (read_and_verify_exception(eport, child, ZX_EXCP_FATAL_PAGE_FAULT, &tid)) {
788        resume_thread_from_exception(child, tid, excp_port_type, ZX_RESUME_TRY_NEXT);
789        tu_process_wait_signaled(child);
790    }
791
792    tu_handle_close(child);
793    tu_handle_close(eport);
794    tu_handle_close(our_channel);
795}
796
797static bool job_handler_test(void)
798{
799    BEGIN_TEST;
800
801    zx_handle_t job = tu_job_create(zx_job_default());
802    zx_handle_t child, our_channel;
803    start_test_child(job, test_child_name, &child, &our_channel);
804    zx_handle_t eport = tu_io_port_create();
805    tu_set_exception_port(job, eport, EXCEPTION_PORT_KEY, 0);
806    REGISTER_CRASH(child);
807
808    finish_basic_test(child, eport, our_channel, MSG_CRASH, ZX_EXCEPTION_PORT_TYPE_JOB);
809    tu_handle_close(job);
810    END_TEST;
811}
812
813bool job_debug_handler_test_helper(zx_handle_t job, zx_handle_t eport_job_handle)
814{
815    zx_handle_t child, our_channel;
816    zx_handle_t eport = tu_io_port_create();
817    tu_set_exception_port(eport_job_handle, eport, EXCEPTION_PORT_KEY, ZX_EXCEPTION_PORT_DEBUGGER);
818    start_test_child(job, test_child_name, &child, &our_channel);
819
820    zx_info_handle_basic_t child_info;
821    tu_handle_get_basic_info(child, &child_info);
822
823    zx_port_packet_t start_packet;
824    ASSERT_TRUE(read_packet(eport, &start_packet), "error reading start exception");
825    ASSERT_TRUE(verify_exception(&start_packet, child, ZX_EXCP_PROCESS_STARTING),
826                "unexpected exception");
827    zx_koid_t packet_pid = start_packet.exception.pid;
828    zx_koid_t packet_tid = start_packet.exception.tid;
829
830    EXPECT_EQ(child_info.koid, packet_pid, "packet pid mismatch");
831
832    // set exception on process
833    zx_handle_t eport_process = tu_io_port_create();
834    tu_set_exception_port(child, eport_process, EXCEPTION_PORT_KEY, ZX_EXCEPTION_PORT_DEBUGGER);
835    tu_object_wait_async(child, eport_process, ZX_PROCESS_TERMINATED);
836
837    // resume thread from job debugger
838    resume_thread_from_exception(child, packet_tid, ZX_EXCEPTION_PORT_TYPE_JOB_DEBUGGER, 0);
839
840    zx_port_packet_t start_packet_process;
841    ASSERT_TRUE(read_packet(eport_process, &start_packet_process), "error reading start exception");
842    ASSERT_TRUE(verify_exception(&start_packet_process, child, ZX_EXCP_THREAD_STARTING),
843                "unexpected exception");
844    packet_pid = start_packet.exception.pid;
845    packet_tid = start_packet.exception.tid;
846
847    EXPECT_EQ(child_info.koid, packet_pid, "packet pid mismatch");
848
849    send_msg(our_channel, MSG_DONE);
850    resume_thread_from_exception(child, packet_tid, ZX_EXCEPTION_PORT_TYPE_DEBUGGER, 0);
851    wait_process_exit_from_debugger(eport_process, child, packet_tid);
852
853    tu_handle_close(child);
854    tu_handle_close(eport);
855    tu_handle_close(our_channel);
856    return true;
857}
858
859static bool nested_job_debug_handler_test(void)
860{
861    BEGIN_TEST;
862
863    zx_handle_t job = tu_job_create(zx_job_default());
864    zx_handle_t nested_job = tu_job_create(job);
865    job_debug_handler_test_helper(nested_job, job);
866    tu_handle_close(nested_job);
867    tu_handle_close(job);
868
869    END_TEST;
870}
871
872static bool job_debug_handler_test(void)
873{
874    BEGIN_TEST;
875
876    zx_handle_t job = tu_job_create(zx_job_default());
877    job_debug_handler_test_helper(job, job);
878    tu_handle_close(job);
879
880    END_TEST;
881}
882
883static bool grandparent_job_handler_test(void)
884{
885    BEGIN_TEST;
886
887    zx_handle_t grandparent_job = tu_job_create(zx_job_default());
888    zx_handle_t parent_job = tu_job_create(grandparent_job);
889    zx_handle_t job = tu_job_create(parent_job);
890    zx_handle_t child, our_channel;
891    start_test_child(job, test_child_name, &child, &our_channel);
892    zx_handle_t eport = tu_io_port_create();
893    tu_set_exception_port(grandparent_job, eport, EXCEPTION_PORT_KEY, 0);
894    REGISTER_CRASH(child);
895
896    finish_basic_test(child, eport, our_channel, MSG_CRASH, ZX_EXCEPTION_PORT_TYPE_JOB);
897    tu_handle_close(job);
898    tu_handle_close(parent_job);
899    tu_handle_close(grandparent_job);
900    END_TEST;
901}
902
903static bool process_handler_test(void)
904{
905    BEGIN_TEST;
906    unittest_printf("process exception handler basic test\n");
907
908    zx_handle_t child, our_channel;
909    start_test_child(zx_job_default(), test_child_name, &child, &our_channel);
910    zx_handle_t eport = tu_io_port_create();
911    tu_set_exception_port(child, eport, EXCEPTION_PORT_KEY, 0);
912    REGISTER_CRASH(child);
913
914    finish_basic_test(child, eport, our_channel, MSG_CRASH, ZX_EXCEPTION_PORT_TYPE_PROCESS);
915    END_TEST;
916}
917
918static bool thread_handler_test(void)
919{
920    BEGIN_TEST;
921    unittest_printf("thread exception handler basic test\n");
922
923    zx_handle_t child, our_channel;
924    start_test_child(zx_job_default(), test_child_name, &child, &our_channel);
925    zx_handle_t eport = tu_io_port_create();
926    send_msg(our_channel, MSG_CREATE_AUX_THREAD);
927    zx_handle_t thread;
928    recv_msg_new_thread_handle(our_channel, &thread);
929    if (thread != ZX_HANDLE_INVALID) {
930        tu_set_exception_port(thread, eport, EXCEPTION_PORT_KEY, 0);
931        REGISTER_CRASH(child);
932        finish_basic_test(child, eport, our_channel, MSG_CRASH_AUX_THREAD, ZX_EXCEPTION_PORT_TYPE_THREAD);
933        tu_handle_close(thread);
934    } else {
935        zx_task_kill(child);
936        ASSERT_NE(thread, ZX_HANDLE_INVALID, "");
937    }
938
939    END_TEST;
940}
941
942static bool debugger_handler_test(void)
943{
944    BEGIN_TEST;
945    unittest_printf("debugger exception handler basic test\n");
946
947    zx_handle_t child, our_channel;
948    start_test_child(zx_job_default(), test_child_name, &child, &our_channel);
949
950    // We're binding to the debugger exception port so make sure the
951    // child is running first so that we don't have to process
952    // ZX_EXCP_THREAD_STARTING.
953    ASSERT_TRUE(ensure_child_running(our_channel), "");
954
955    zx_handle_t eport = tu_io_port_create();
956    tu_set_exception_port(child, eport, EXCEPTION_PORT_KEY, ZX_EXCEPTION_PORT_DEBUGGER);
957
958    finish_basic_test(child, eport, our_channel, MSG_CRASH, ZX_EXCEPTION_PORT_TYPE_DEBUGGER);
959    END_TEST;
960}
961
962static bool packet_pid_test(void)
963{
964    BEGIN_TEST;
965
966    zx_handle_t child, eport, our_channel;
967    start_test_child_with_eport(zx_job_default(), test_child_name,
968                                &child, &eport, &our_channel);
969
970    zx_info_handle_basic_t child_info;
971    tu_handle_get_basic_info(child, &child_info);
972
973    zx_port_packet_t start_packet;
974    ASSERT_TRUE(read_packet(eport, &start_packet), "error reading start exception");
975    ASSERT_TRUE(verify_exception(&start_packet, child, ZX_EXCP_THREAD_STARTING),
976                "unexpected exception");
977    zx_koid_t packet_pid = start_packet.exception.pid;
978    zx_koid_t packet_tid = start_packet.exception.tid;
979
980    EXPECT_EQ(child_info.koid, packet_pid, "packet pid mismatch");
981
982    send_msg(our_channel, MSG_DONE);
983    resume_thread_from_exception(child, packet_tid, ZX_EXCEPTION_PORT_TYPE_DEBUGGER, 0);
984    wait_process_exit_from_debugger(eport, child, packet_tid);
985
986    tu_handle_close(child);
987    tu_handle_close(eport);
988    tu_handle_close(our_channel);
989
990    END_TEST;
991}
992
993// Check that zx_thread_read_state() and zx_thread_write_state() both
994// return ZX_ERR_NOT_SUPPORTED.  This is used for testing the cases where a
995// thread is paused in the ZX_EXCP_THREAD_STARTING or or
996// ZX_EXCP_THREAD_EXITING states.
997static bool check_read_or_write_regs_is_rejected(zx_handle_t process,
998                                                 zx_handle_t tid)
999{
1000    zx_handle_t thread;
1001    ASSERT_EQ(zx_object_get_child(process, tid, ZX_RIGHT_SAME_RIGHTS, &thread), ZX_OK, "");
1002    zx_thread_state_general_regs_t regs;
1003    EXPECT_EQ(zx_thread_read_state(thread, ZX_THREAD_STATE_GENERAL_REGS, &regs, sizeof(regs)),
1004              ZX_ERR_NOT_SUPPORTED, "");
1005    EXPECT_EQ(zx_thread_write_state(thread, ZX_THREAD_STATE_GENERAL_REGS, &regs, sizeof(regs)),
1006              ZX_ERR_NOT_SUPPORTED, "");
1007    ASSERT_EQ(zx_handle_close(thread), ZX_OK, "");
1008    return true;
1009}
1010
1011// Test the behavior of zx_thread_read_state() and zx_thread_write_state()
1012// when a thread is paused in the ZX_EXCP_THREAD_STARTING or
1013// ZX_EXCP_THREAD_EXITING states.
1014//
1015// For ZX_EXCP_THREAD_EXITING, this tests the case where a thread is
1016// exiting without the whole process also exiting.
1017static bool thread_state_when_starting_or_exiting_test(void)
1018{
1019    BEGIN_TEST;
1020
1021    zx_handle_t child, eport, our_channel;
1022    start_test_child_with_eport(zx_job_default(), test_child_name,
1023                                &child, &eport, &our_channel);
1024
1025    // Wait for the ZX_EXCP_THREAD_STARTING message for the subprocess's
1026    // initial thread.
1027    zx_koid_t initial_tid;
1028    ASSERT_TRUE(read_and_verify_exception(eport, child, ZX_EXCP_THREAD_STARTING,
1029                                          &initial_tid), "");
1030    EXPECT_TRUE(check_read_or_write_regs_is_rejected(child, initial_tid), "");
1031    resume_thread_from_exception(child, initial_tid,
1032                                 ZX_EXCEPTION_PORT_TYPE_DEBUGGER, 0);
1033
1034    // Tell the subprocess to create a second thread.
1035    send_msg(our_channel, MSG_CREATE_AUX_THREAD);
1036    // Wait for the ZX_EXCP_THREAD_STARTING message about that thread.
1037    zx_koid_t tid;
1038    ASSERT_TRUE(read_and_verify_exception(eport, child, ZX_EXCP_THREAD_STARTING,
1039                                          &tid), "");
1040    EXPECT_NE(tid, initial_tid, "");
1041    EXPECT_TRUE(check_read_or_write_regs_is_rejected(child, tid), "");
1042    resume_thread_from_exception(child, tid, ZX_EXCEPTION_PORT_TYPE_DEBUGGER,
1043                                 0);
1044
1045    // Tell the second thread to exit.
1046    send_msg(our_channel, MSG_SHUTDOWN_AUX_THREAD);
1047    // Wait for the ZX_EXCP_THREAD_EXITING message about that thread.
1048    zx_koid_t tid2;
1049    ASSERT_TRUE(read_and_verify_exception(eport, child, ZX_EXCP_THREAD_EXITING,
1050                                          &tid2), "");
1051    EXPECT_EQ(tid2, tid, "");
1052    EXPECT_TRUE(check_read_or_write_regs_is_rejected(child, tid), "");
1053
1054    // Clean up: Resume the thread so that the process can exit.
1055    zx_handle_t thread;
1056    ASSERT_EQ(zx_object_get_child(child, tid, ZX_RIGHT_SAME_RIGHTS, &thread),
1057              ZX_OK, "");
1058    ASSERT_EQ(zx_task_resume(thread, ZX_RESUME_EXCEPTION), ZX_OK, "");
1059    tu_handle_close(thread);
1060    // Clean up: Tell the process to exit and wait for it to exit.
1061    send_msg(our_channel, MSG_DONE);
1062    tu_process_wait_signaled(child);
1063    tu_handle_close(child);
1064    tu_handle_close(eport);
1065    tu_handle_close(our_channel);
1066
1067    END_TEST;
1068}
1069
1070static bool process_start_test(void)
1071{
1072    BEGIN_TEST;
1073    unittest_printf("process start test\n");
1074
1075    zx_handle_t child, eport, our_channel;
1076    start_test_child_with_eport(zx_job_default(), test_child_name,
1077                                &child, &eport, &our_channel);
1078
1079    zx_koid_t tid;
1080    if (read_and_verify_exception(eport, child, ZX_EXCP_THREAD_STARTING, &tid)) {
1081        send_msg(our_channel, MSG_DONE);
1082        resume_thread_from_exception(child, tid, ZX_EXCEPTION_PORT_TYPE_DEBUGGER, 0);
1083        wait_process_exit_from_debugger(eport, child, tid);
1084    }
1085
1086    tu_handle_close(child);
1087    tu_handle_close(eport);
1088    tu_handle_close(our_channel);
1089
1090    END_TEST;
1091}
1092
1093// Verify ZX_PROCESS_TERMINATED comes through bound exception port
1094// via async wait.
1095
1096static bool process_exit_notification_test(void)
1097{
1098    BEGIN_TEST;
1099    unittest_printf("process exit notification test\n");
1100
1101    zx_handle_t child, our_channel;
1102    start_test_child(zx_job_default(), test_child_name, &child, &our_channel);
1103
1104    zx_handle_t eport = tu_io_port_create();
1105    tu_set_exception_port(child, eport, EXCEPTION_PORT_KEY, 0);
1106    tu_object_wait_async(child, eport, ZX_PROCESS_TERMINATED);
1107
1108    send_msg(our_channel, MSG_DONE);
1109
1110    wait_process_exit(eport, child);
1111
1112    tu_handle_close(child);
1113    tu_handle_close(eport);
1114    tu_handle_close(our_channel);
1115
1116    END_TEST;
1117}
1118
1119// Verify ZX_THREAD_TERMINATED comes through bound exception port
1120// via async wait.
1121
1122static bool thread_exit_notification_test(void)
1123{
1124    BEGIN_TEST;
1125    unittest_printf("thread exit notification test\n");
1126
1127    zx_handle_t our_channel, their_channel;
1128    tu_channel_create(&our_channel, &their_channel);
1129    zx_handle_t eport = tu_io_port_create();
1130    thrd_t thread;
1131    tu_thread_create_c11(&thread, thread_func, (void*) (uintptr_t) their_channel, "thread-gone-test-thread");
1132    zx_handle_t thread_handle = thrd_get_zx_handle(thread);
1133
1134    // |thread_handle| isn't usable to us, the thread exits before we're done
1135    // with the handle. So make a copy.
1136    zx_handle_t thread_handle_copy = tu_handle_duplicate(thread_handle);
1137
1138    // Attach to the thread exception report as we're testing for ZX_THREAD_TERMINATED
1139    // reports from the thread here.
1140    tu_set_exception_port(thread_handle_copy, eport, EXCEPTION_PORT_KEY, 0);
1141    tu_object_wait_async(thread_handle_copy, eport, ZX_THREAD_TERMINATED);
1142
1143    send_msg(our_channel, MSG_DONE);
1144
1145    zx_port_packet_t packet;
1146    ASSERT_TRUE(read_packet(eport, &packet), "");
1147    zx_koid_t tid = tu_get_koid(thread_handle_copy);
1148    ASSERT_TRUE(verify_signal(&packet, tid, ZX_THREAD_TERMINATED), "");
1149
1150    // thrd_join doesn't provide a timeout, but we have the watchdog for that.
1151    thrd_join(thread, NULL);
1152
1153    tu_handle_close(thread_handle_copy);
1154    tu_handle_close(eport);
1155    tu_handle_close(our_channel);
1156
1157    END_TEST;
1158}
1159
1160static void __NO_RETURN trigger_unsupported(void)
1161{
1162    unittest_printf("unsupported exception\n");
1163    // An unsupported exception is not a failure.
1164    // Generally it just means that support for the exception doesn't
1165    // exist yet on this particular architecture.
1166    exit(0);
1167}
1168
1169static void __NO_RETURN trigger_general(void)
1170{
1171#if defined(__x86_64__)
1172#elif defined(__aarch64__)
1173#endif
1174    trigger_unsupported();
1175}
1176
1177static void __NO_RETURN trigger_fatal_page_fault(void)
1178{
1179    *(volatile int*) 0 = 42;
1180    trigger_unsupported();
1181}
1182
1183static void __NO_RETURN trigger_undefined_insn(void)
1184{
1185#if defined(__x86_64__)
1186    __asm__("ud2");
1187#elif defined(__aarch64__)
1188    // An instruction not supported at this privilege level will do.
1189    // ARM calls these "unallocated instructions". Geez, "unallocated"?
1190    __asm__("mrs x0, elr_el1");
1191#endif
1192    trigger_unsupported();
1193}
1194
1195static void __NO_RETURN trigger_sw_bkpt(void)
1196{
1197#if defined(__x86_64__)
1198    __asm__("int3");
1199#elif defined(__aarch64__)
1200    __asm__("brk 0");
1201#endif
1202    trigger_unsupported();
1203}
1204
1205static void __NO_RETURN trigger_hw_bkpt(void)
1206{
1207#if defined(__x86_64__)
1208    // We can't set the debug regs from user space, support for setting the
1209    // debug regs via the debugger interface is work-in-progress, and we can't
1210    // use "int $1" here. So testing this will have to wait.
1211#elif defined(__aarch64__)
1212#endif
1213    trigger_unsupported();
1214}
1215
1216// ARM does not trap on integer divide-by-zero.
1217#if defined(__x86_64__)
1218static void __NO_RETURN trigger_integer_divide_by_zero(void)
1219{
1220    // Use an x86 division instruction (rather than doing division from C)
1221    // to ensure that the compiler does not convert the division into
1222    // something else.
1223    uint32_t result;
1224    __asm__ volatile("idivb %1"
1225                     : "=a"(result)
1226                     : "r"((uint8_t) 0), "a"((uint16_t) 1));
1227    trigger_unsupported();
1228}
1229
1230static void __NO_RETURN trigger_sse_divide_by_zero(void)
1231{
1232    // Unmask all exceptions for SSE operations.
1233    uint32_t mxcsr = 0;
1234    __asm__ volatile("ldmxcsr %0" : : "m"(mxcsr));
1235
1236    double a = 1;
1237    double b = 0;
1238    __asm__ volatile("divsd %1, %0" : "+x"(a) : "x"(b));
1239
1240    // QEMU's software emulation of x86 appears to have a bug where it does
1241    // not correctly emulate generating division-by-zero exceptions from
1242    // SSE instructions.  See https://bugs.launchpad.net/qemu/+bug/1668041.
1243    // So we will reach this point on non-KVM QEMU.  In this case, make the
1244    // test pass by generating a fault by other means.
1245    //
1246    // That means this test isn't requiring that "divsd" generates a fault.
1247    // It is only requiring that the fault is handled properly
1248    // (e.g. doesn't cause a kernel panic) if the instruction does fault
1249    // (as on real hardware).
1250    printf("trigger_sse_divide_by_zero: divsd did not fault; "
1251           "assume we are running under a buggy non-KVM QEMU\n");
1252    trigger_integer_divide_by_zero();
1253}
1254
1255static void __NO_RETURN trigger_x87_divide_by_zero(void)
1256{
1257    // Unmask all exceptions for x87 operations.
1258    uint16_t control_word = 0;
1259    __asm__ volatile("fldcw %0" : : "m"(control_word));
1260
1261    double a = 1;
1262    double b = 0;
1263    __asm__ volatile("fldl %0\n"
1264                     "fdivl %1\n"
1265                     // Check for the pending exception.
1266                     "fwait\n"
1267                     : : "m"(a), "m"(b));
1268    trigger_unsupported();
1269}
1270#endif
1271
1272static const struct {
1273    zx_excp_type_t type;
1274    const char* name;
1275    bool crashes;
1276    void __NO_RETURN (*trigger_function) (void);
1277} exceptions[] = {
1278    { ZX_EXCP_GENERAL, "general", false, trigger_general },
1279    { ZX_EXCP_FATAL_PAGE_FAULT, "page-fault", true, trigger_fatal_page_fault },
1280    { ZX_EXCP_UNDEFINED_INSTRUCTION, "undefined-insn", true, trigger_undefined_insn },
1281    { ZX_EXCP_SW_BREAKPOINT, "sw-bkpt", true, trigger_sw_bkpt },
1282    { ZX_EXCP_HW_BREAKPOINT, "hw-bkpt", false, trigger_hw_bkpt },
1283#if defined(__x86_64__)
1284    { ZX_EXCP_GENERAL, "integer-divide-by-zero", true, trigger_integer_divide_by_zero },
1285    { ZX_EXCP_GENERAL, "sse-divide-by-zero", true, trigger_sse_divide_by_zero },
1286    { ZX_EXCP_GENERAL, "x87-divide-by-zero", true, trigger_x87_divide_by_zero },
1287#endif
1288};
1289
1290static void __NO_RETURN trigger_exception(const char* excp_name)
1291{
1292    for (size_t i = 0; i < countof(exceptions); ++i)
1293    {
1294        if (strcmp(excp_name, exceptions[i].name) == 0)
1295        {
1296            exceptions[i].trigger_function();
1297        }
1298    }
1299    fprintf(stderr, "unknown exception: %s\n", excp_name);
1300    exit (1);
1301}
1302
1303static void __NO_RETURN test_child_trigger(const char* excp_name)
1304{
1305    unittest_printf("Exception trigger test child (%s) starting.\n", excp_name);
1306    trigger_exception(excp_name);
1307    /* NOTREACHED */
1308}
1309
1310static bool trigger_test(void)
1311{
1312    BEGIN_TEST;
1313    unittest_printf("exception trigger tests\n");
1314
1315    for (size_t i = 0; i < countof(exceptions); ++i) {
1316        zx_excp_type_t excp_type = exceptions[i].type;
1317        const char *excp_name = exceptions[i].name;
1318        zx_handle_t child, eport, our_channel;
1319        char* arg = tu_asprintf("trigger=%s", excp_name);
1320        start_test_child_with_eport(zx_job_default(), arg,
1321                                    &child, &eport, &our_channel);
1322        free(arg);
1323
1324        if (exceptions[i].crashes) {
1325            REGISTER_CRASH(child);
1326        }
1327
1328        zx_koid_t tid = ZX_KOID_INVALID;
1329        (void) read_and_verify_exception(eport, child, ZX_EXCP_THREAD_STARTING, &tid);
1330        resume_thread_from_exception(child, tid, ZX_EXCEPTION_PORT_TYPE_DEBUGGER, 0);
1331
1332        zx_port_packet_t packet;
1333        if (read_packet(eport, &packet)) {
1334            // ZX_EXCP_THREAD_EXITING reports must normally be responded to.
1335            // However, when the process exits it kills all threads which will
1336            // kick them out of the ExceptionHandlerExchange. Thus there's no
1337            // need to resume them here.
1338            ASSERT_TRUE(ZX_PKT_IS_EXCEPTION(packet.type), "");
1339            if (packet.type != ZX_EXCP_THREAD_EXITING) {
1340                tid = packet.exception.tid;
1341                verify_exception(&packet, child, excp_type);
1342                resume_thread_from_exception(child, tid,
1343                                             ZX_EXCEPTION_PORT_TYPE_DEBUGGER,
1344                                             ZX_RESUME_TRY_NEXT);
1345                zx_koid_t tid2;
1346                if (read_and_verify_exception(eport, child, ZX_EXCP_THREAD_EXITING, &tid2)) {
1347                    ASSERT_EQ(tid2, tid, "exiting tid mismatch");
1348                }
1349            } else {
1350                EXPECT_EQ(packet.exception.tid, tid, "");
1351                // Either the process exited cleanly because the exception
1352                // is unsupported, or it exited because exception processing
1353                // finished and the kernel killed the process. Either way
1354                // the process is dead thus there's no need to resume the
1355                // thread.
1356            }
1357
1358            // We've already seen tid's thread-exit report, so just skip that
1359            // test here.
1360            wait_process_exit(eport, child);
1361        }
1362
1363        tu_handle_close(child);
1364        tu_handle_close(eport);
1365        tu_handle_close(our_channel);
1366    }
1367
1368    END_TEST;
1369}
1370
1371typedef struct {
1372    // The walkthrough stops at the grandparent job as we don't want
1373    // crashlogger to see the exception: causes excessive noise in test output.
1374    // It doesn't stop at the parent job as we want to exercise finding threads
1375    // of processes of child jobs.
1376    zx_handle_t grandparent_job;
1377    zx_handle_t parent_job;
1378    zx_handle_t job;
1379
1380    // the test process
1381    zx_handle_t child;
1382
1383    // the test thread and its koid
1384    zx_handle_t thread;
1385    zx_koid_t tid;
1386
1387    zx_handle_t grandparent_job_eport;
1388    zx_handle_t parent_job_eport;
1389    zx_handle_t job_eport;
1390    zx_handle_t child_eport;
1391    zx_handle_t thread_eport;
1392    zx_handle_t debugger_eport;
1393
1394    // the communication channel to the test process
1395    zx_handle_t our_channel;
1396} walkthrough_state_t;
1397
1398static bool walkthrough_setup(walkthrough_state_t* state)
1399{
1400    memset(state, 0, sizeof(*state));
1401
1402    state->grandparent_job = tu_job_create(zx_job_default());
1403    state->parent_job = tu_job_create(state->grandparent_job);
1404    state->job = tu_job_create(state->parent_job);
1405
1406    state->grandparent_job_eport = tu_io_port_create();
1407    state->parent_job_eport = tu_io_port_create();
1408    state->job_eport = tu_io_port_create();
1409    state->child_eport = tu_io_port_create();
1410    state->thread_eport = tu_io_port_create();
1411    state->debugger_eport = tu_io_port_create();
1412
1413    start_test_child(state->job, test_child_name,
1414                     &state->child, &state->our_channel);
1415
1416    send_msg(state->our_channel, MSG_CREATE_AUX_THREAD);
1417    recv_msg_new_thread_handle(state->our_channel, &state->thread);
1418    ASSERT_NE(state->thread, ZX_HANDLE_INVALID, "");
1419    state->tid = tu_get_koid(state->thread);
1420
1421    tu_set_exception_port(state->grandparent_job, state->grandparent_job_eport, EXCEPTION_PORT_KEY, 0);
1422    tu_set_exception_port(state->parent_job, state->parent_job_eport, EXCEPTION_PORT_KEY, 0);
1423    tu_set_exception_port(state->job, state->job_eport, EXCEPTION_PORT_KEY, 0);
1424    tu_set_exception_port(state->child, state->child_eport, EXCEPTION_PORT_KEY, 0);
1425    tu_set_exception_port(state->thread, state->thread_eport, EXCEPTION_PORT_KEY, 0);
1426    tu_set_exception_port(state->child, state->debugger_eport, EXCEPTION_PORT_KEY, ZX_EXCEPTION_PORT_DEBUGGER);
1427
1428    // Non-debugger exception ports don't get synthetic exceptions like
1429    // ZX_EXCP_THREAD_STARTING. We have to trigger an architectural exception.
1430    send_msg(state->our_channel, MSG_CRASH_AUX_THREAD);
1431    return true;
1432}
1433
1434static void walkthrough_close(zx_handle_t* handle)
1435{
1436    if (*handle != ZX_HANDLE_INVALID) {
1437        tu_handle_close(*handle);
1438        *handle = ZX_HANDLE_INVALID;
1439    }
1440}
1441
1442static void walkthrough_teardown(walkthrough_state_t* state)
1443{
1444    zx_task_kill(state->child);
1445    tu_process_wait_signaled(state->child);
1446
1447    walkthrough_close(&state->thread);
1448    walkthrough_close(&state->child);
1449    walkthrough_close(&state->our_channel);
1450    walkthrough_close(&state->job);
1451    walkthrough_close(&state->parent_job);
1452    walkthrough_close(&state->grandparent_job);
1453
1454    walkthrough_close(&state->debugger_eport);
1455    walkthrough_close(&state->thread_eport);
1456    walkthrough_close(&state->child_eport);
1457    walkthrough_close(&state->job_eport);
1458    walkthrough_close(&state->parent_job_eport);
1459    walkthrough_close(&state->grandparent_job_eport);
1460}
1461
1462static void walkthrough_read_and_verify_exception(const walkthrough_state_t* state,
1463                                                  zx_handle_t eport)
1464{
1465    zx_koid_t exception_tid;
1466    if (read_and_verify_exception(eport, state->child, ZX_EXCP_FATAL_PAGE_FAULT, &exception_tid)) {
1467        EXPECT_EQ(exception_tid, state->tid, "");
1468    }
1469}
1470
1471// Set up every kind of handler (except the system, we can't touch it), and
1472// verify unbinding an exception port walks through each handler in the search
1473// list (except the system exception handler which we can't touch).
1474
1475static bool unbind_walkthrough_by_reset_test(void)
1476{
1477    BEGIN_TEST;
1478
1479    walkthrough_state_t state;
1480    if (!walkthrough_setup(&state))
1481        goto Fail;
1482
1483    walkthrough_read_and_verify_exception(&state, state.debugger_eport);
1484
1485    tu_set_exception_port(state.child, ZX_HANDLE_INVALID, 0, ZX_EXCEPTION_PORT_DEBUGGER);
1486    walkthrough_read_and_verify_exception(&state, state.thread_eport);
1487
1488    tu_set_exception_port(state.thread, ZX_HANDLE_INVALID, 0, 0);
1489    walkthrough_read_and_verify_exception(&state, state.child_eport);
1490
1491    tu_set_exception_port(state.child, ZX_HANDLE_INVALID, 0, 0);
1492    walkthrough_read_and_verify_exception(&state, state.job_eport);
1493
1494    tu_set_exception_port(state.job, ZX_HANDLE_INVALID, 0, 0);
1495    walkthrough_read_and_verify_exception(&state, state.parent_job_eport);
1496
1497    tu_set_exception_port(state.parent_job, ZX_HANDLE_INVALID, 0, 0);
1498    walkthrough_read_and_verify_exception(&state, state.grandparent_job_eport);
1499
1500Fail:
1501    walkthrough_teardown(&state);
1502
1503    END_TEST;
1504}
1505
1506// Set up every kind of handler (except the system, we can't touch it), and
1507// verify closing an exception port walks through each handler in the search
1508// list (except the system exception handler which we can't touch).
1509
1510static bool unbind_walkthrough_by_close_test(void)
1511{
1512    BEGIN_TEST;
1513
1514    walkthrough_state_t state;
1515    if (!walkthrough_setup(&state))
1516        goto Fail;
1517
1518    walkthrough_read_and_verify_exception(&state, state.debugger_eport);
1519
1520    walkthrough_close(&state.debugger_eport);
1521    walkthrough_read_and_verify_exception(&state, state.thread_eport);
1522
1523    walkthrough_close(&state.thread_eport);
1524    walkthrough_read_and_verify_exception(&state, state.child_eport);
1525
1526    walkthrough_close(&state.child_eport);
1527    walkthrough_read_and_verify_exception(&state, state.job_eport);
1528
1529    walkthrough_close(&state.job_eport);
1530    walkthrough_read_and_verify_exception(&state, state.parent_job_eport);
1531
1532    walkthrough_close(&state.parent_job_eport);
1533    walkthrough_read_and_verify_exception(&state, state.grandparent_job_eport);
1534
1535Fail:
1536    walkthrough_teardown(&state);
1537
1538    END_TEST;
1539}
1540
1541// This test is different than the walkthrough tests in that it tests
1542// successful resumption of the child after the debugger port closes.
1543
1544static bool unbind_while_stopped_test(void)
1545{
1546    BEGIN_TEST;
1547    unittest_printf("unbind_while_stopped tests\n");
1548
1549    zx_handle_t child, eport, our_channel;
1550    start_test_child_with_eport(zx_job_default(), test_child_name,
1551                                &child, &eport, &our_channel);
1552
1553    {
1554        zx_koid_t tid;
1555        (void) read_and_verify_exception(eport, child, ZX_EXCP_THREAD_STARTING, &tid);
1556    }
1557
1558    // Now unbind the exception port and wait for the child to cleanly exit.
1559    // If this doesn't work the thread will stay blocked, we'll timeout, and
1560    // the watchdog will trigger.
1561    tu_set_exception_port(child, ZX_HANDLE_INVALID, 0, ZX_EXCEPTION_PORT_DEBUGGER);
1562    send_msg(our_channel, MSG_DONE);
1563    tu_process_wait_signaled(child);
1564
1565    tu_handle_close(child);
1566    tu_handle_close(eport);
1567    tu_handle_close(our_channel);
1568
1569    END_TEST;
1570}
1571
1572static bool unbind_rebind_while_stopped_test(void)
1573{
1574    BEGIN_TEST;
1575    unittest_printf("unbind_rebind_while_stopped tests\n");
1576
1577    zx_handle_t child, eport, our_channel;
1578    start_test_child_with_eport(zx_job_default(), test_child_name,
1579                                &child, &eport, &our_channel);
1580
1581    zx_port_packet_t start_packet;
1582    // Assert reading the start packet succeeds because otherwise the rest
1583    // of the test is moot.
1584    ASSERT_TRUE(read_packet(eport, &start_packet), "error reading start exception");
1585    ASSERT_TRUE(verify_exception(&start_packet, child, ZX_EXCP_THREAD_STARTING),
1586                "unexpected exception");
1587    zx_koid_t tid = start_packet.exception.tid;
1588
1589    zx_handle_t thread;
1590    zx_status_t status = zx_object_get_child(child, tid, ZX_RIGHT_SAME_RIGHTS, &thread);
1591    if (status < 0)
1592        tu_fatal("zx_object_get_child", status);
1593
1594    // The thread may still be running: There's a window between sending the
1595    // exception report and the thread going to sleep that is exposed to us.
1596    // We want to verify the thread is still waiting for an exception after we
1597    // unbind, so wait for the thread to go to sleep before we unbind.
1598    // Note that there's no worry of this hanging due to our watchdog.
1599    zx_info_thread_t info;
1600    do {
1601        zx_nanosleep(zx_deadline_after(ZX_MSEC(1)));
1602        info = tu_thread_get_info(thread);
1603    } while (info.state != ZX_THREAD_STATE_BLOCKED_EXCEPTION);
1604
1605    // Unbind the exception port quietly, meaning to leave the thread
1606    // waiting for an exception response.
1607    tu_set_exception_port(child, ZX_HANDLE_INVALID, 0,
1608                          ZX_EXCEPTION_PORT_DEBUGGER | ZX_EXCEPTION_PORT_UNBIND_QUIETLY);
1609
1610    // Rebind and fetch the exception report, it should match the one
1611    // we just got.
1612
1613    tu_set_exception_port(child, eport, EXCEPTION_PORT_KEY, ZX_EXCEPTION_PORT_DEBUGGER);
1614
1615    // Verify exception report matches current exception.
1616    zx_exception_report_t report;
1617    status = zx_object_get_info(thread, ZX_INFO_THREAD_EXCEPTION_REPORT, &report, sizeof(report), NULL, NULL);
1618    if (status < 0)
1619        tu_fatal("zx_object_get_info(ZX_INFO_THREAD_EXCEPTION_REPORT)", status);
1620    EXPECT_EQ(report.header.type, start_packet.type, "type mismatch");
1621    // The "thread-start" report is a synthetic exception and doesn't contain
1622    // any arch info yet, so we can't test report.context.arch.
1623
1624    // Done verifying we got the same exception, send the child on its way
1625    // and tell it we're done.
1626    resume_thread_from_exception(child, tid, ZX_EXCEPTION_PORT_TYPE_DEBUGGER, 0);
1627    send_msg(our_channel, MSG_DONE);
1628
1629    wait_process_exit_from_debugger(eport, child, tid);
1630
1631    // We should still be able to get info on the thread.
1632    info = tu_thread_get_info(thread);
1633    EXPECT_EQ(info.state, ZX_THREAD_STATE_DEAD, "unexpected thread state");
1634    EXPECT_EQ(info.wait_exception_port_type, ZX_EXCEPTION_PORT_TYPE_NONE, "wrong exception port type at thread exit");
1635
1636    tu_handle_close(thread);
1637    tu_handle_close(child);
1638    tu_handle_close(eport);
1639    tu_handle_close(our_channel);
1640
1641    END_TEST;
1642}
1643
1644static bool kill_while_stopped_at_start_test(void)
1645{
1646    BEGIN_TEST;
1647    unittest_printf("kill_while_stopped_at_start tests\n");
1648
1649    zx_handle_t child, eport, our_channel;
1650    start_test_child_with_eport(zx_job_default(), test_child_name,
1651                                &child, &eport, &our_channel);
1652
1653    zx_koid_t tid;
1654    if (read_and_verify_exception(eport, child, ZX_EXCP_THREAD_STARTING, &tid)) {
1655        // Now kill the thread and wait for the child to exit.
1656        // This assumes the inferior only has the one thread.
1657        // If this doesn't work the thread will stay blocked, we'll timeout, and
1658        // the watchdog will trigger.
1659        zx_handle_t thread;
1660        zx_status_t status = zx_object_get_child(child, tid, ZX_RIGHT_SAME_RIGHTS, &thread);
1661        if (status < 0)
1662            tu_fatal("zx_object_get_child", status);
1663        zx_task_kill(thread);
1664        tu_process_wait_signaled(child);
1665
1666        // Keep the thread handle open until after we know the process has exited
1667        // to ensure the thread's handle lifetime doesn't affect process lifetime.
1668        tu_handle_close(thread);
1669    }
1670
1671    tu_handle_close(child);
1672    tu_handle_close(eport);
1673    tu_handle_close(our_channel);
1674
1675    END_TEST;
1676}
1677
1678static void write_to_addr(void* addr)
1679{
1680    *(int*) addr = 42;
1681}
1682
1683static bool death_test(void)
1684{
1685    BEGIN_TEST;
1686
1687    int* addr = 0;
1688    ASSERT_DEATH(write_to_addr, addr, "registered death: write to address 0x0");
1689
1690    END_TEST;
1691}
1692
1693static bool self_death_test(void)
1694{
1695    BEGIN_TEST;
1696
1697    REGISTER_CRASH(zx_thread_self());
1698    crash_me();
1699
1700    END_TEST;
1701}
1702
1703typedef struct thread_info {
1704    zx_handle_t our_channel, their_channel;
1705    zx_handle_t thread_handle;
1706} thread_info_t;
1707
1708static bool multiple_threads_registered_death_test(void)
1709{
1710    BEGIN_TEST;
1711
1712    const unsigned int num_threads = 5;
1713
1714    thread_info_t thread_info[num_threads];
1715
1716    // Create some threads and register them as expected to crash.
1717    // This tests the crash list can handle multiple registered
1718    // handles.
1719    for (unsigned int i = 0; i < num_threads; i++) {
1720        tu_channel_create(&thread_info[i].our_channel,
1721                          &thread_info[i].their_channel);
1722        thrd_t thread;
1723        tu_thread_create_c11(&thread, thread_func,
1724                             (void*)(uintptr_t)thread_info[i].their_channel,
1725                             "registered-death-thread");
1726        // Note: We're assuming the thread won't exit before we're done with
1727        // the result of thrd_get_zx_handle.
1728        thread_info[i].thread_handle = thrd_get_zx_handle(thread);
1729        REGISTER_CRASH(thread_info[i].thread_handle);
1730    }
1731
1732    // Make each thread crash. As they are registered, they will be
1733    // silently handled by the crash handler and the test should complete
1734    // without error.
1735    for (unsigned int i = 0; i < num_threads; i++) {
1736        send_msg(thread_info[i].our_channel, MSG_CRASH);
1737
1738        ASSERT_EQ(zx_object_wait_one(thread_info[i].thread_handle,
1739                                     ZX_THREAD_TERMINATED,
1740                                     zx_deadline_after(ZX_MSEC(500)), NULL),
1741                  ZX_OK, "failed to wait for thread termination");
1742
1743        tu_handle_close(thread_info[i].thread_handle);
1744        tu_handle_close(thread_info[i].our_channel);
1745        tu_handle_close(thread_info[i].their_channel);
1746    }
1747
1748    END_TEST;
1749}
1750
1751static void __NO_RETURN test_child_exit_closing_excp_handle(void)
1752{
1753    unittest_printf("Exit closing excp handle starting.\n");
1754
1755    // Test ZX-1544. Process termination closing the last handle of the eport
1756    // should not cause a panic.
1757    zx_handle_t eport = tu_io_port_create();
1758    tu_set_exception_port(zx_process_self(), eport, EXCEPTION_PORT_KEY, 0);
1759    exit(0);
1760
1761    /* NOTREACHED */
1762}
1763
1764static bool exit_closing_excp_handle_test(void)
1765{
1766    BEGIN_TEST;
1767
1768    unittest_printf("Starting test child.\n");
1769
1770    const char* test_child_path = program_path;
1771    const char verbosity_string[] = { 'v', '=', utest_verbosity_level + '0', '\0' };
1772    const char* const argv[] = {
1773        test_child_path,
1774        exit_closing_excp_handle_child_name,
1775        verbosity_string,
1776    };
1777    int argc = countof(argv);
1778
1779    launchpad_t* lp = tu_launch_fdio_init(zx_job_default(),
1780                                          exit_closing_excp_handle_child_name,
1781                                          argc, argv,
1782                                          NULL, 0, NULL, NULL);
1783    zx_handle_t child = tu_launch_fdio_fini(lp);
1784
1785    zx_signals_t signals = ZX_PROCESS_TERMINATED;
1786    zx_signals_t pending;
1787    zx_status_t result = tu_wait(1, &child, &signals, &pending);
1788    EXPECT_EQ(result, ZX_OK, "");
1789    EXPECT_TRUE(pending & ZX_PROCESS_TERMINATED, "");
1790
1791    EXPECT_EQ(tu_process_get_return_code(child), 0, "");
1792
1793    END_TEST;
1794}
1795
1796BEGIN_TEST_CASE(exceptions_tests)
1797RUN_TEST(job_set_close_set_test);
1798RUN_TEST(process_set_close_set_test);
1799RUN_TEST(process_debugger_set_close_set_test);
1800RUN_TEST(thread_set_close_set_test);
1801RUN_TEST(non_running_process_set_close_set_test);
1802RUN_TEST(non_running_process_debugger_set_close_set_test);
1803RUN_TEST(non_running_thread_set_close_set_test);
1804RUN_TEST(dead_process_matched_unbind_succeeds_test);
1805RUN_TEST(dead_process_mismatched_unbind_fails_test);
1806RUN_TEST(dead_process_debugger_matched_unbind_succeeds_test);
1807RUN_TEST(dead_process_debugger_mismatched_unbind_fails_test);
1808RUN_TEST(dead_thread_matched_unbind_succeeds_test);
1809RUN_TEST(dead_thread_mismatched_unbind_fails_test);
1810RUN_TEST_ENABLE_CRASH_HANDLER(job_handler_test);
1811RUN_TEST_ENABLE_CRASH_HANDLER(grandparent_job_handler_test);
1812RUN_TEST_ENABLE_CRASH_HANDLER(process_handler_test);
1813RUN_TEST_ENABLE_CRASH_HANDLER(thread_handler_test);
1814RUN_TEST(packet_pid_test);
1815RUN_TEST(job_debug_handler_test);
1816RUN_TEST(nested_job_debug_handler_test);
1817RUN_TEST(thread_state_when_starting_or_exiting_test);
1818RUN_TEST(process_start_test);
1819RUN_TEST(process_exit_notification_test);
1820RUN_TEST(thread_exit_notification_test);
1821RUN_TEST_ENABLE_CRASH_HANDLER(trigger_test);
1822RUN_TEST(unbind_walkthrough_by_reset_test);
1823RUN_TEST(unbind_walkthrough_by_close_test);
1824RUN_TEST(unbind_while_stopped_test);
1825RUN_TEST(unbind_rebind_while_stopped_test);
1826RUN_TEST(kill_while_stopped_at_start_test);
1827RUN_TEST(death_test);
1828RUN_TEST_ENABLE_CRASH_HANDLER(self_death_test);
1829RUN_TEST_ENABLE_CRASH_HANDLER(multiple_threads_registered_death_test);
1830RUN_TEST(exit_closing_excp_handle_test);
1831END_TEST_CASE(exceptions_tests)
1832
1833static void scan_argv(int argc, char** argv)
1834{
1835    for (int i = 1; i < argc; ++i) {
1836        if (strncmp(argv[i], "v=", 2) == 0) {
1837            int verbosity = atoi(argv[i] + 2);
1838            unittest_set_verbosity_level(verbosity);
1839        }
1840    }
1841}
1842
1843static const char* check_trigger(int argc, char** argv)
1844{
1845    static const char trigger[] = "trigger=";
1846    for (int i = 1; i < argc; ++i) {
1847        if (strncmp(argv[i], trigger, sizeof(trigger) - 1) == 0) {
1848            return argv[i] + sizeof(trigger) - 1;
1849        }
1850    }
1851    return NULL;
1852}
1853
1854int main(int argc, char **argv)
1855{
1856    program_path = argv[0];
1857    scan_argv(argc, argv);
1858
1859    if (argc >= 2) {
1860        const char* excp_name = check_trigger(argc, argv);
1861        if (excp_name) {
1862            test_child_trigger(excp_name);
1863            return 0;
1864        }
1865        if (strcmp(argv[1], test_child_name) == 0) {
1866            test_child();
1867            return 0;
1868        }
1869        if (strcmp(argv[1], exit_closing_excp_handle_child_name) == 0) {
1870            test_child_exit_closing_excp_handle();
1871            /* NOTREACHED */
1872        }
1873    }
1874
1875    bool success = unittest_run_all_tests(argc, argv);
1876    return success ? 0 : -1;
1877}
1878