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, ®s, sizeof(regs)), 1004 ZX_ERR_NOT_SUPPORTED, ""); 1005 EXPECT_EQ(zx_thread_write_state(thread, ZX_THREAD_STATE_GENERAL_REGS, ®s, 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