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#include <assert.h>
6#include <inttypes.h>
7#include <link.h>
8#include <stdbool.h>
9#include <stdlib.h>
10#include <string.h>
11
12#include <fbl/atomic.h>
13#include <launchpad/launchpad.h>
14#include <launchpad/vmo.h>
15#include <lib/zircon-internal/crashlogger.h>
16#include <test-utils/test-utils.h>
17#include <unittest/unittest.h>
18#include <zircon/process.h>
19#include <zircon/processargs.h>
20#include <zircon/syscalls.h>
21#include <zircon/syscalls/debug.h>
22#include <zircon/syscalls/exception.h>
23#include <zircon/syscalls/object.h>
24#include <zircon/syscalls/port.h>
25#include <zircon/threads.h>
26
27#include "utils.h"
28
29namespace {
30
31typedef bool(wait_inferior_exception_handler_t)(zx_handle_t inferior, zx_handle_t port,
32                                                const zx_port_packet_t* packet, void* handler_arg);
33
34constexpr size_t kTestMemorySize = 8;
35constexpr uint8_t kTestDataAdjust = 0x10;
36
37// Do the segv recovery test a number of times to stress test the API.
38constexpr int kNumSegvTries = 4;
39
40constexpr int kNumExtraThreads = 4;
41
42// Produce a backtrace of sufficient size to be interesting but not excessive.
43constexpr int kTestSegfaultDepth = 4;
44
45const char test_inferior_child_name[] = "inferior";
46// The segfault child is not used by the test.
47// It exists for debugging purposes.
48const char test_segfault_child_name[] = "segfault";
49// Used for testing the s/w breakpoint insn.
50const char test_swbreak_child_name[] = "swbreak";
51
52fbl::atomic<int> extra_thread_count;
53
54uint64_t extract_pc_reg(const zx_thread_state_general_regs_t* regs) {
55#if defined(__x86_64__)
56    return regs->rip;
57#elif defined(__aarch64__)
58    return regs->pc;
59#endif
60}
61
62uint64_t extract_sp_reg(const zx_thread_state_general_regs_t* regs) {
63#if defined(__x86_64__)
64    return regs->rsp;
65#elif defined(__aarch64__)
66    return regs->sp;
67#endif
68}
69
70void test_memory_ops(zx_handle_t inferior, zx_handle_t thread) {
71    uint64_t test_data_addr = 0;
72    uint8_t test_data[kTestMemorySize];
73
74    zx_thread_state_general_regs_t regs;
75    read_inferior_gregs(thread, &regs);
76
77#if defined(__x86_64__)
78    test_data_addr = regs.r9;
79#elif defined(__aarch64__)
80    test_data_addr = regs.r[9];
81#endif
82
83    size_t size = read_inferior_memory(inferior, test_data_addr, test_data, sizeof(test_data));
84    EXPECT_EQ(size, sizeof(test_data), "read_inferior_memory: short read");
85
86    for (unsigned i = 0; i < sizeof(test_data); ++i) {
87        EXPECT_EQ(test_data[i], i, "test_memory_ops");
88    }
89
90    for (unsigned i = 0; i < sizeof(test_data); ++i) {
91        test_data[i] = static_cast<uint8_t>(test_data[i] + kTestDataAdjust);
92    }
93
94    size = write_inferior_memory(inferior, test_data_addr, test_data, sizeof(test_data));
95    EXPECT_EQ(size, sizeof(test_data), "write_inferior_memory: short write");
96
97    // Note: Verification of the write is done in the inferior.
98}
99
100void fix_inferior_segv(zx_handle_t thread) {
101    unittest_printf("Fixing inferior segv\n");
102
103    // The segv was because r8 == 0, change it to a usable value. See test_prep_and_segv.
104    zx_thread_state_general_regs_t regs;
105    read_inferior_gregs(thread, &regs);
106#if defined(__x86_64__)
107    regs.r8 = regs.rsp;
108#elif defined(__aarch64__)
109    regs.r[8] = regs.sp;
110#endif
111    write_inferior_gregs(thread, &regs);
112}
113
114bool test_segv_pc(zx_handle_t thread) {
115    zx_thread_state_general_regs_t regs;
116    read_inferior_gregs(thread, &regs);
117
118#if defined(__x86_64__)
119    ASSERT_EQ(regs.rip, regs.r10, "fault PC does not match r10");
120#elif defined(__aarch64__)
121    ASSERT_EQ(regs.pc, regs.r[10], "fault PC does not match x10");
122#endif
123    return true;
124}
125
126// A simpler exception handler.
127// All exceptions are passed on to |handler|.
128// Returns false if a test fails.
129// Otherwise waits for the inferior to exit and returns true.
130
131bool wait_inferior_thread_worker(inferior_data_t* inferior_data,
132                                 wait_inferior_exception_handler_t* handler, void* handler_arg) {
133    zx_handle_t inferior = inferior_data->inferior;
134    zx_koid_t pid = tu_get_koid(inferior);
135    zx_handle_t eport = inferior_data->eport;
136
137    while (true) {
138        zx_port_packet_t packet;
139        if (!read_exception(eport, &packet))
140            return false;
141
142        // Is the inferior gone?
143        if (ZX_PKT_IS_SIGNAL_REP(packet.type) && packet.key == pid &&
144            (packet.signal.observed & ZX_PROCESS_TERMINATED)) {
145            unittest_printf("wait-inf: inferior gone\n");
146            return true;
147        }
148
149        if (!handler(inferior, eport, &packet, handler_arg))
150            return false;
151    }
152}
153
154struct wait_inf_args_t {
155    inferior_data_t* inferior_data;
156    wait_inferior_exception_handler_t* handler;
157    void* handler_arg;
158};
159
160int wait_inferior_thread_func(void* arg) {
161    wait_inf_args_t* args = static_cast<wait_inf_args_t*>(arg);
162    inferior_data_t* inferior_data = args->inferior_data;
163    wait_inferior_exception_handler_t* handler = args->handler;
164    void* handler_arg = args->handler_arg;
165    free(args);
166
167    bool pass = wait_inferior_thread_worker(inferior_data, handler, handler_arg);
168
169    return pass ? 0 : -1;
170}
171
172thrd_t start_wait_inf_thread(inferior_data_t* inferior_data,
173                             wait_inferior_exception_handler_t* handler, void* handler_arg) {
174    wait_inf_args_t* args = static_cast<wait_inf_args_t*>(tu_calloc(1, sizeof(*args)));
175
176    // The proc handle is loaned to the thread.
177    // The caller of this function owns and must close it.
178    args->inferior_data = inferior_data;
179    args->handler = handler;
180    args->handler_arg = handler_arg;
181
182    thrd_t wait_inferior_thread;
183    tu_thread_create_c11(&wait_inferior_thread, wait_inferior_thread_func, args, "wait-inf thread");
184    return wait_inferior_thread;
185}
186
187void join_wait_inf_thread(thrd_t wait_inf_thread) {
188    unittest_printf("Waiting for wait-inf thread\n");
189    int thread_rc;
190    int ret = thrd_join(wait_inf_thread, &thread_rc);
191    EXPECT_EQ(ret, thrd_success, "thrd_join failed");
192    EXPECT_EQ(thread_rc, 0, "unexpected wait-inf return");
193    unittest_printf("wait-inf thread done\n");
194}
195
196bool expect_debugger_attached_eq(zx_handle_t inferior, bool expected, const char* msg) {
197    zx_info_process_t info;
198    // ZX_ASSERT returns false if the check fails.
199    ASSERT_EQ(zx_object_get_info(inferior, ZX_INFO_PROCESS, &info, sizeof(info), NULL, NULL), ZX_OK);
200    ASSERT_EQ(info.debugger_attached, expected, msg);
201    return true;
202}
203
204// This returns a bool as it's a unittest "helper" routine.
205// N.B. This runs on the wait-inferior thread.
206
207bool handle_thread_exiting(zx_handle_t inferior, const zx_port_packet_t* packet) {
208    BEGIN_HELPER;
209
210    zx_koid_t tid = packet->exception.tid;
211    zx_handle_t thread;
212    zx_status_t status = zx_object_get_child(inferior, tid, ZX_RIGHT_SAME_RIGHTS, &thread);
213    // If the process has exited then the kernel may have reaped the
214    // thread already. Check.
215    if (status == ZX_OK) {
216        zx_info_thread_t info = tu_thread_get_info(thread);
217        // The thread could still transition to DEAD here (if the
218        // process exits), so check for either DYING or DEAD.
219        EXPECT_TRUE(info.state == ZX_THREAD_STATE_DYING || info.state == ZX_THREAD_STATE_DEAD);
220        // If the state is DYING it would be nice to check that the
221        // value of |info.wait_exception_port_type| is DEBUGGER. Alas
222        // if the process has exited then the thread will get
223        // THREAD_SIGNAL_KILL which will cause
224        // UserThread::ExceptionHandlerExchange to exit before we've
225        // told the thread to "resume" from ZX_EXCP_THREAD_EXITING.
226        // The thread is still in the DYING state but it is no longer
227        // in an exception. Thus |info.wait_exception_port_type| can
228        // either be DEBUGGER or NONE.
229        EXPECT_TRUE(info.wait_exception_port_type == ZX_EXCEPTION_PORT_TYPE_NONE ||
230                        info.wait_exception_port_type == ZX_EXCEPTION_PORT_TYPE_DEBUGGER);
231        tu_handle_close(thread);
232    } else {
233        EXPECT_EQ(status, ZX_ERR_NOT_FOUND);
234        EXPECT_TRUE(tu_process_has_exited(inferior));
235    }
236    unittest_printf("wait-inf: thread %" PRId64 " exited\n", tid);
237    // A thread is gone, but we only care about the process.
238    if (!resume_inferior(inferior, tid))
239        return false;
240
241    END_HELPER;
242}
243
244// This returns a bool as it's a unittest "helper" routine.
245// N.B. This runs on the wait-inferior thread.
246
247bool handle_expected_page_fault(zx_handle_t inferior,
248                                zx_handle_t port,
249                                const zx_port_packet_t* packet,
250                                fbl::atomic<int>* segv_count) {
251    BEGIN_HELPER;
252
253    unittest_printf("wait-inf: got page fault exception\n");
254
255    zx_koid_t tid = packet->exception.tid;
256    zx_handle_t thread = tu_get_thread(inferior, tid);
257
258    dump_inferior_regs(thread);
259
260    // Verify that the fault is at the PC we expected.
261    if (!test_segv_pc(thread))
262        return false;
263
264    // Do some tests that require a suspended inferior.
265    test_memory_ops(inferior, thread);
266
267    fix_inferior_segv(thread);
268    // Useful for debugging, otherwise a bit too verbose.
269    // dump_inferior_regs(thread);
270
271    // Increment this before resuming the inferior in case the inferior
272    // sends MSG_RECOVERED_FROM_CRASH and the testcase processes the message
273    // before we can increment it.
274    atomic_fetch_add(segv_count, 1);
275
276    zx_status_t status = zx_task_resume_from_exception(thread, port, 0);
277    tu_handle_close(thread);
278    ASSERT_EQ(status, ZX_OK);
279
280    END_HELPER;
281}
282
283// N.B. This runs on the wait-inferior thread.
284
285bool debugger_test_exception_handler(zx_handle_t inferior, zx_handle_t port,
286                                     const zx_port_packet_t* packet,
287                                     void* handler_arg) {
288    BEGIN_HELPER;
289
290    // Note: This may be NULL if the test is not expecting a page fault.
291    fbl::atomic<int>* segv_count = static_cast<fbl::atomic<int>*>(handler_arg);
292
293    zx_koid_t pid = tu_get_koid(inferior);
294
295    if (ZX_PKT_IS_SIGNAL_REP(packet->type)) {
296        ASSERT_TRUE(packet->key != pid);
297        // Must be a signal on one of the threads.
298        // Here we're only expecting TERMINATED.
299        ASSERT_TRUE(packet->signal.observed & ZX_THREAD_TERMINATED);
300    } else {
301        ASSERT_TRUE(ZX_PKT_IS_EXCEPTION(packet->type));
302
303        zx_koid_t tid = packet->exception.tid;
304
305        switch (packet->type) {
306        case ZX_EXCP_THREAD_STARTING:
307            unittest_printf("wait-inf: inferior started\n");
308            if (!resume_inferior(inferior, tid))
309                return false;
310            break;
311
312        case ZX_EXCP_THREAD_EXITING:
313            // N.B. We could get thread exiting messages from previous
314            // tests.
315            EXPECT_TRUE(handle_thread_exiting(inferior, packet));
316            break;
317
318        case ZX_EXCP_FATAL_PAGE_FAULT:
319            ASSERT_NONNULL(segv_count);
320            ASSERT_TRUE(handle_expected_page_fault(inferior, port, packet, segv_count));
321            break;
322
323        default: {
324            char msg[128];
325            snprintf(msg, sizeof(msg), "unexpected packet type: 0x%x", packet->type);
326            ASSERT_TRUE(false, msg);
327            __UNREACHABLE;
328        }
329        }
330    }
331
332    END_HELPER;
333}
334
335bool debugger_test() {
336    BEGIN_TEST;
337
338    launchpad_t* lp;
339    zx_handle_t inferior, channel;
340    if (!setup_inferior(test_inferior_child_name, &lp, &inferior, &channel))
341        return false;
342
343    fbl::atomic<int> segv_count;
344
345    expect_debugger_attached_eq(inferior, false, "debugger should not appear attached");
346    zx_handle_t eport = tu_io_port_create();
347    size_t max_threads = 10;
348    inferior_data_t* inferior_data = attach_inferior(inferior, eport, max_threads);
349    thrd_t wait_inf_thread =
350        start_wait_inf_thread(inferior_data, debugger_test_exception_handler, &segv_count);
351    EXPECT_NE(eport, ZX_HANDLE_INVALID);
352    expect_debugger_attached_eq(inferior, true, "debugger should appear attached");
353
354    if (!start_inferior(lp))
355        return false;
356    if (!verify_inferior_running(channel))
357        return false;
358
359    segv_count.store(0);
360    enum message msg;
361    send_msg(channel, MSG_CRASH_AND_RECOVER_TEST);
362    if (!recv_msg(channel, &msg))
363        return false;
364    EXPECT_EQ(msg, MSG_RECOVERED_FROM_CRASH, "unexpected response from crash");
365    EXPECT_EQ(segv_count.load(), kNumSegvTries, "segv tests terminated prematurely");
366
367    if (!shutdown_inferior(channel, inferior))
368        return false;
369
370    // Stop the waiter thread before closing the eport that it's waiting on.
371    join_wait_inf_thread(wait_inf_thread);
372
373    detach_inferior(inferior_data, false);
374
375    expect_debugger_attached_eq(inferior, true, "debugger should still appear attached");
376    tu_handle_close(eport);
377    expect_debugger_attached_eq(inferior, false, "debugger should no longer appear attached");
378
379    tu_handle_close(channel);
380    tu_handle_close(inferior);
381
382    END_TEST;
383}
384
385bool debugger_thread_list_test() {
386    BEGIN_TEST;
387
388    launchpad_t* lp;
389    zx_handle_t inferior, channel;
390    if (!setup_inferior(test_inferior_child_name, &lp, &inferior, &channel))
391        return false;
392
393    zx_handle_t eport = tu_io_port_create();
394    size_t max_threads = 10;
395    inferior_data_t* inferior_data = attach_inferior(inferior, eport, max_threads);
396    thrd_t wait_inf_thread =
397        start_wait_inf_thread(inferior_data, debugger_test_exception_handler, NULL);
398    EXPECT_NE(eport, ZX_HANDLE_INVALID);
399
400    if (!start_inferior(lp))
401        return false;
402    if (!verify_inferior_running(channel))
403        return false;
404
405    enum message msg;
406    send_msg(channel, MSG_START_EXTRA_THREADS);
407    if (!recv_msg(channel, &msg))
408        return false;
409    EXPECT_EQ(msg, MSG_EXTRA_THREADS_STARTED, "unexpected response when starting extra threads");
410
411    // This doesn't use tu_process_get_threads() because here we're testing
412    // various aspects of ZX_INFO_PROCESS_THREADS.
413    uint32_t buf_size = 100 * sizeof(zx_koid_t);
414    size_t num_threads;
415    zx_koid_t* threads = static_cast<zx_koid_t*>(tu_malloc(buf_size));
416    zx_status_t status = zx_object_get_info(inferior, ZX_INFO_PROCESS_THREADS, threads, buf_size,
417                                            &num_threads, NULL);
418    ASSERT_EQ(status, ZX_OK);
419
420    // There should be at least 1+kNumExtraThreads threads in the result.
421    ASSERT_GE(num_threads, 1 + kNumExtraThreads, "zx_object_get_info failed");
422
423    // Verify each entry is valid.
424    for (uint32_t i = 0; i < num_threads; ++i) {
425        zx_koid_t koid = threads[i];
426        unittest_printf("Looking up thread %llu\n", (long long)koid);
427        zx_handle_t thread = tu_get_thread(inferior, koid);
428        zx_info_handle_basic_t info;
429        status = zx_object_get_info(thread, ZX_INFO_HANDLE_BASIC, &info, sizeof(info), NULL, NULL);
430        EXPECT_EQ(status, ZX_OK, "zx_object_get_info failed");
431        EXPECT_EQ(info.type, ZX_OBJ_TYPE_THREAD, "not a thread");
432    }
433
434    if (!shutdown_inferior(channel, inferior))
435        return false;
436
437    // Stop the waiter thread before closing the eport that it's waiting on.
438    join_wait_inf_thread(wait_inf_thread);
439
440    detach_inferior(inferior_data, true);
441
442    tu_handle_close(eport);
443    tu_handle_close(channel);
444    tu_handle_close(inferior);
445
446    END_TEST;
447}
448
449bool property_process_debug_addr_test() {
450    BEGIN_TEST;
451
452    zx_handle_t self = zx_process_self();
453
454    // We shouldn't be able to set it.
455    uintptr_t debug_addr = 42;
456    zx_status_t status =
457        zx_object_set_property(self, ZX_PROP_PROCESS_DEBUG_ADDR, &debug_addr, sizeof(debug_addr));
458    ASSERT_EQ(status, ZX_ERR_ACCESS_DENIED);
459
460    // Some minimal verification that the value is correct.
461
462    status =
463        zx_object_get_property(self, ZX_PROP_PROCESS_DEBUG_ADDR, &debug_addr, sizeof(debug_addr));
464    ASSERT_EQ(status, ZX_OK);
465
466    // These are all dsos we link with. See rules.mk.
467    const char* launchpad_so = "liblaunchpad.so";
468    bool found_launchpad = false;
469    const char* libc_so = "libc.so";
470    bool found_libc = false;
471    const char* test_utils_so = "libtest-utils.so";
472    bool found_test_utils = false;
473    const char* unittest_so = "libunittest.so";
474    bool found_unittest = false;
475
476    const r_debug* debug = (r_debug*)debug_addr;
477    const link_map* lmap = debug->r_map;
478
479    EXPECT_EQ(debug->r_state, r_debug::RT_CONSISTENT);
480
481    while (lmap != NULL) {
482        if (strcmp(lmap->l_name, launchpad_so) == 0)
483            found_launchpad = true;
484        else if (strcmp(lmap->l_name, libc_so) == 0)
485            found_libc = true;
486        else if (strcmp(lmap->l_name, test_utils_so) == 0)
487            found_test_utils = true;
488        else if (strcmp(lmap->l_name, unittest_so) == 0)
489            found_unittest = true;
490        lmap = lmap->l_next;
491    }
492
493    EXPECT_TRUE(found_launchpad);
494    EXPECT_TRUE(found_libc);
495    EXPECT_TRUE(found_test_utils);
496    EXPECT_TRUE(found_unittest);
497
498    END_TEST;
499}
500
501int write_text_segment_helper() __ALIGNED(8);
502int write_text_segment_helper() {
503    /* This function needs to be at least two bytes in size as we set a
504       breakpoint, figuratively speaking, on write_text_segment_helper + 1
505       to ensure the address is not page aligned. Returning some random value
506       will ensure that. */
507    return 42;
508}
509
510bool write_text_segment() {
511    BEGIN_TEST;
512
513    zx_handle_t self = zx_process_self();
514
515    // Exercise ZX-739
516    // Pretend we're writing a s/w breakpoint to the start of this function.
517
518    // write_text_segment_helper is suitably aligned, add 1 to ensure the
519    // byte we write is not page aligned.
520    uintptr_t addr = (uintptr_t)write_text_segment_helper + 1;
521    uint8_t previous_byte;
522    size_t size = read_inferior_memory(self, addr, &previous_byte, sizeof(previous_byte));
523    EXPECT_EQ(size, sizeof(previous_byte));
524
525    uint8_t byte_to_write = 0;
526    size = write_inferior_memory(self, addr, &byte_to_write, sizeof(byte_to_write));
527    EXPECT_EQ(size, sizeof(byte_to_write));
528
529    size = write_inferior_memory(self, addr, &previous_byte, sizeof(previous_byte));
530    EXPECT_EQ(size, sizeof(previous_byte));
531
532    END_TEST;
533}
534
535// These are "call-saved" registers used in the test.
536#if defined(__x86_64__)
537#define REG_ACCESS_TEST_REG r15
538#define REG_ACCESS_TEST_REG_NAME "r15"
539#elif defined(__aarch64__)
540#define REG_ACCESS_TEST_REG r[28]
541#define REG_ACCESS_TEST_REG_NAME "x28"
542#endif
543
544// Note: Neither of these can be zero.
545const uint64_t reg_access_initial_value = 0xee112233445566eeull;
546const uint64_t reg_access_write_test_value = 0xee665544332211eeull;
547
548struct suspended_reg_access_arg {
549    zx_handle_t channel;
550    uint64_t initial_value;
551    uint64_t result;
552    uint64_t pc, sp;
553};
554
555int reg_access_thread_func(void* arg_) {
556    suspended_reg_access_arg* arg = static_cast<suspended_reg_access_arg*>(arg_);
557
558    send_msg(arg->channel, MSG_PONG);
559
560    // The loop has to be written in assembler as we cannot control what
561    // the compiler does with our "reserved" registers outside of the asm;
562    // they're not really reserved in the way we need them to be: the compiler
563    // is free to do with them whatever it wants outside of the assembler.
564    // We do make the assumption that test_reg will not contain
565    // |reg_access_initial_value| until it is set by the assembler.
566
567    uint64_t initial_value = arg->initial_value;
568    uint64_t result = 0;
569    uint64_t pc = 0;
570    uint64_t sp = 0;
571
572// The maximum number of bytes in the assembly.
573// This doesn't have to be perfect. It's used to verify the value read for
574// $pc is within some reasonable range.
575#define REG_ACCESS_MAX_LOOP_SIZE 64
576
577#ifdef __x86_64__
578    __asm__("\
579        lea .(%%rip), %[pc]\n\
580        mov %%rsp, %[sp]\n\
581        mov %[initial_value], %%" REG_ACCESS_TEST_REG_NAME "\n\
582      2:\n\
583        pause\n\
584        cmp %[initial_value], %%" REG_ACCESS_TEST_REG_NAME "\n\
585        je 2b\n\
586        mov %%" REG_ACCESS_TEST_REG_NAME ", %[result]"
587            : [result] "=r"(result), [pc] "=&r"(pc), [sp] "=&r"(sp)
588            : [initial_value] "r"(initial_value)
589            : REG_ACCESS_TEST_REG_NAME);
590#endif
591
592#ifdef __aarch64__
593    __asm__("\
594        adr %[pc], .\n\
595        mov %[sp], sp\n\
596        mov " REG_ACCESS_TEST_REG_NAME ", %[initial_value]\n\
597      1:\n\
598        yield\n\
599        cmp %[initial_value], " REG_ACCESS_TEST_REG_NAME "\n\
600        b.eq 1b\n\
601        mov %[result], " REG_ACCESS_TEST_REG_NAME
602            : [result] "=r"(result), [pc] "=&r"(pc), [sp] "=&r"(sp)
603            : [initial_value] "r"(initial_value)
604            : REG_ACCESS_TEST_REG_NAME);
605#endif
606
607    arg->result = result;
608    arg->pc = pc;
609    arg->sp = sp;
610
611    tu_handle_close(arg->channel);
612
613    return 0;
614}
615
616bool suspended_reg_access_test() {
617    BEGIN_TEST;
618
619    zx_handle_t self_proc = zx_process_self();
620
621    thrd_t thread_c11;
622    suspended_reg_access_arg arg = {};
623    arg.initial_value = reg_access_initial_value;
624    zx_handle_t channel;
625    tu_channel_create(&channel, &arg.channel);
626    tu_thread_create_c11(&thread_c11, reg_access_thread_func, &arg, "reg-access thread");
627    // Get our own copy of the thread handle to avoid lifetime issues of
628    // thrd's copy.
629    zx_handle_t thread = tu_handle_duplicate(thrd_get_zx_handle(thread_c11));
630
631    // KISS: Don't attach until the thread is up and running so we don't see
632    // ZX_EXCP_THREAD_STARTING.
633    enum message msg;
634    recv_msg(channel, &msg);
635    // No need to send a ping.
636    ASSERT_EQ(msg, MSG_PONG);
637
638    // Set up waiting for the thread to suspend via a port (since this is
639    // what debuggers will typically do).
640    zx_handle_t eport = tu_io_port_create();
641    zx_signals_t signals = ZX_THREAD_TERMINATED | ZX_THREAD_RUNNING | ZX_THREAD_SUSPENDED;
642    tu_object_wait_async(thread, eport, signals);
643
644    // Keep looping until we know the thread is stopped in the assembler.
645    // This is the only place we can guarantee particular registers have
646    // particular values.
647    zx_handle_t suspend_token = ZX_HANDLE_INVALID;
648    zx_thread_state_general_regs_t regs;
649    uint64_t test_reg = 0;
650    while (true) {
651        zx_nanosleep(zx_deadline_after(ZX_USEC(1)));
652        ASSERT_EQ(zx_task_suspend_token(thread, &suspend_token), ZX_OK);
653        ASSERT_TRUE(wait_thread_suspended(self_proc, thread, eport));
654
655        read_inferior_gregs(thread, &regs);
656        test_reg = regs.REG_ACCESS_TEST_REG;
657
658        if (test_reg == reg_access_initial_value)
659            break;  // Keep thread suspended.
660
661        // Resume and try again.
662        zx_handle_close(suspend_token);
663    }
664
665    uint64_t pc_value = extract_pc_reg(&regs);
666    uint64_t sp_value = extract_sp_reg(&regs);
667    regs.REG_ACCESS_TEST_REG = reg_access_write_test_value;
668    write_inferior_gregs(thread, &regs);
669
670    ASSERT_EQ(zx_handle_close(suspend_token), ZX_OK);
671    thrd_join(thread_c11, NULL);
672    tu_handle_close(thread);
673
674    // We can't test the pc value exactly as we don't know on which instruction
675    // the thread will be suspended. But we can verify it is within some
676    // minimal range.
677    EXPECT_GE(pc_value, arg.pc);
678    EXPECT_LE(pc_value, arg.pc + REG_ACCESS_MAX_LOOP_SIZE);
679
680    EXPECT_EQ(sp_value, arg.sp);
681
682    EXPECT_EQ(reg_access_write_test_value, arg.result);
683
684    tu_handle_close(channel);
685    tu_handle_close(eport);
686    END_TEST;
687}
688
689struct suspended_in_syscall_reg_access_arg {
690    bool do_channel_call;
691    zx_handle_t syscall_handle;
692    fbl::atomic<uintptr_t> sp;
693};
694
695// "zx_channel_call treats the leading bytes of the payload as
696// a transaction id of type zx_txid_t"
697static_assert(sizeof(zx_txid_t) == sizeof(uint32_t), "");
698#define CHANNEL_CALL_PACKET_SIZE (sizeof(zx_txid_t) + sizeof("x"))
699
700int suspended_in_syscall_reg_access_thread_func(void* arg_) {
701    suspended_in_syscall_reg_access_arg* arg =
702        static_cast<suspended_in_syscall_reg_access_arg*>(arg_);
703
704    uint64_t sp;
705#ifdef __x86_64__
706    __asm__("\
707        mov %%rsp, %[sp]"
708            : [sp] "=r"(sp));
709#endif
710#ifdef __aarch64__
711    __asm__("\
712        mov %[sp], sp"
713            : [sp] "=r"(sp));
714#endif
715    arg->sp.store(sp);
716
717    if (arg->do_channel_call) {
718        uint8_t send_buf[CHANNEL_CALL_PACKET_SIZE] = "TXIDx";
719        uint8_t recv_buf[CHANNEL_CALL_PACKET_SIZE];
720        uint32_t actual_bytes, actual_handles;
721        zx_channel_call_args_t call_args = {
722            .wr_bytes = send_buf,
723            .wr_handles = NULL,
724            .rd_bytes = recv_buf,
725            .rd_handles = NULL,
726            .wr_num_bytes = sizeof(send_buf),
727            .wr_num_handles = 0,
728            .rd_num_bytes = sizeof(recv_buf),
729            .rd_num_handles = 0,
730        };
731        zx_status_t call_status = zx_channel_call(arg->syscall_handle, 0, ZX_TIME_INFINITE,
732                                                  &call_args, &actual_bytes, &actual_handles);
733        ASSERT_EQ(call_status, ZX_OK);
734        EXPECT_EQ(actual_bytes, sizeof(recv_buf));
735        EXPECT_EQ(memcmp(recv_buf + sizeof(zx_txid_t), "y", sizeof(recv_buf) - sizeof(zx_txid_t)), 0);
736    } else {
737        zx_signals_t pending;
738        zx_status_t status =
739            zx_object_wait_one(arg->syscall_handle, ZX_EVENT_SIGNALED, ZX_TIME_INFINITE, &pending);
740        ASSERT_EQ(status, ZX_OK);
741        EXPECT_NE(pending & ZX_EVENT_SIGNALED, 0u);
742    }
743
744    return 0;
745}
746
747// Channel calls are a little special in that they are a two part syscall,
748// with suspension possible in between the two parts.
749// If |do_channel_call| is true, test zx_channel_call. Otherwise test some
750// random syscall that can block, here we use zx_object_wait_one.
751//
752// The syscall entry point is the vdso, there's no bypassing this for test
753// purposes. Also, the kernel doesn't save userspace regs on entry, it only
754// saves them later if it needs to - at which point many don't necessarily
755// have any useful value. Putting these together means we can't easily test
756// random integer registers: there's no guarantee any value we set in the test
757// will be available when the syscall is suspended. All is not lost, we can
758// still at least test that reading $pc, $sp work.
759
760bool suspended_in_syscall_reg_access_worker(bool do_channel_call) {
761    zx_handle_t self_proc = zx_process_self();
762
763    uintptr_t vdso_start = 0, vdso_end = 0;
764    EXPECT_TRUE(get_vdso_exec_range(&vdso_start, &vdso_end));
765
766    suspended_in_syscall_reg_access_arg arg = {};
767    arg.do_channel_call = do_channel_call;
768
769    zx_handle_t syscall_handle;
770    if (do_channel_call) {
771        tu_channel_create(&arg.syscall_handle, &syscall_handle);
772    } else {
773        ASSERT_EQ(zx_event_create(0u, &syscall_handle), ZX_OK);
774        arg.syscall_handle = syscall_handle;
775    }
776
777    thrd_t thread_c11;
778    tu_thread_create_c11(&thread_c11, suspended_in_syscall_reg_access_thread_func, &arg,
779                         "reg-access thread");
780    // Get our own copy of the thread handle to avoid lifetime issues of
781    // thrd's copy.
782    zx_handle_t thread = tu_handle_duplicate(thrd_get_zx_handle(thread_c11));
783
784    // Busy-wait until thread is blocked inside the syscall.
785    zx_info_thread_t thread_info;
786    uint32_t expected_blocked_reason =
787        do_channel_call ? ZX_THREAD_STATE_BLOCKED_CHANNEL : ZX_THREAD_STATE_BLOCKED_WAIT_ONE;
788    do {
789        // Don't check too frequently here as it can blow up tracing output
790        // when debugging with kernel tracing turned on.
791        zx_nanosleep(zx_deadline_after(ZX_USEC(100)));
792        thread_info = tu_thread_get_info(thread);
793    } while (thread_info.state != expected_blocked_reason);
794    ASSERT_EQ(thread_info.wait_exception_port_type, ZX_EXCEPTION_PORT_TYPE_NONE);
795
796    // Extra sanity check for channels.
797    if (do_channel_call) {
798        EXPECT_TRUE(tu_channel_wait_readable(syscall_handle));
799    }
800
801    // Set up waiting for the thread to suspend via a port (since this is
802    // what debuggers will typically do).
803    zx_handle_t eport = tu_io_port_create();
804    zx_signals_t signals = ZX_THREAD_TERMINATED | ZX_THREAD_RUNNING | ZX_THREAD_SUSPENDED;
805    tu_object_wait_async(thread, eport, signals);
806
807    zx_handle_t token;
808    ASSERT_EQ(zx_task_suspend_token(thread, &token), ZX_OK);
809
810    ASSERT_TRUE(wait_thread_suspended(self_proc, thread, eport));
811
812    zx_thread_state_general_regs_t regs;
813    read_inferior_gregs(thread, &regs);
814
815    // Verify the pc is somewhere within the vdso.
816    uint64_t pc_value = extract_pc_reg(&regs);
817    EXPECT_GE(pc_value, vdso_start);
818    EXPECT_LE(pc_value, vdso_end);
819
820    // The stack pointer is somewhere within the syscall.
821    // Just verify the value we have is within range.
822    uint64_t sp_value = extract_sp_reg(&regs);
823    uint64_t arg_sp = arg.sp.load();
824    EXPECT_LE(sp_value, arg_sp);
825    EXPECT_GE(sp_value + 1024, arg_sp);
826
827    // wake the thread
828    if (do_channel_call) {
829        uint8_t buf[CHANNEL_CALL_PACKET_SIZE];
830        uint32_t actual_bytes;
831        ASSERT_EQ(
832            zx_channel_read(syscall_handle, 0, buf, NULL, sizeof(buf), 0, &actual_bytes, NULL),
833            ZX_OK);
834        EXPECT_EQ(actual_bytes, sizeof(buf));
835        EXPECT_EQ(memcmp(buf + sizeof(zx_txid_t), "x", sizeof(buf) - sizeof(zx_txid_t)), 0);
836
837        // write a reply
838        buf[sizeof(zx_txid_t)] = 'y';
839        ASSERT_EQ(zx_channel_write(syscall_handle, 0, buf, sizeof(buf), NULL, 0), ZX_OK);
840
841        // Make sure the remote channel didn't get signaled
842        EXPECT_EQ(zx_object_wait_one(arg.syscall_handle, ZX_CHANNEL_READABLE, 0, NULL),
843                  ZX_ERR_TIMED_OUT);
844
845        // Make sure we can't read from the remote channel (the message should have
846        // been reserved for the other thread, even though it is suspended).
847        EXPECT_EQ(
848            zx_channel_read(arg.syscall_handle, 0, buf, NULL, sizeof(buf), 0, &actual_bytes, NULL),
849            ZX_ERR_SHOULD_WAIT);
850    } else {
851        ASSERT_EQ(zx_object_signal(syscall_handle, 0u, ZX_EVENT_SIGNALED), ZX_OK);
852    }
853
854    ASSERT_EQ(zx_handle_close(token), ZX_OK);
855    thrd_join(thread_c11, NULL);
856    tu_handle_close(thread);
857
858    tu_handle_close(eport);
859    if (do_channel_call) {
860        tu_handle_close(arg.syscall_handle);
861    }
862    tu_handle_close(syscall_handle);
863
864    return true;
865}
866
867bool suspended_in_syscall_reg_access_test() {
868    BEGIN_TEST;
869
870    EXPECT_TRUE(suspended_in_syscall_reg_access_worker(false));
871
872    END_TEST;
873}
874
875bool suspended_in_channel_call_reg_access_test() {
876    BEGIN_TEST;
877
878    EXPECT_TRUE(suspended_in_syscall_reg_access_worker(true));
879
880    END_TEST;
881}
882
883struct suspend_in_exception_data {
884    fbl::atomic<int> segv_count;
885    fbl::atomic<int> suspend_count;
886    fbl::atomic<int> resume_count;
887    zx_handle_t thread_handle;
888    zx_koid_t process_id;
889    zx_koid_t thread_id;
890};
891
892// N.B. This runs on the wait-inferior thread.
893
894bool suspended_in_exception_handler(zx_handle_t inferior, zx_handle_t port,
895                                    const zx_port_packet_t* packet, void* handler_arg) {
896    BEGIN_HELPER;
897
898    suspend_in_exception_data* data = static_cast<suspend_in_exception_data*>(handler_arg);
899
900    if (ZX_PKT_IS_SIGNAL_REP(packet->type)) {
901        // Must be a signal on one of the threads.
902        ASSERT_TRUE(packet->key != data->process_id);
903        zx_koid_t pkt_tid = packet->key;
904
905        // The following signals are expected here.  Note that
906        // ZX_THREAD_RUNNING and ZX_THREAD_TERMINATED can be reported
907        // together in the same zx_port_packet_t.
908        if (packet->signal.observed & ZX_THREAD_TERMINATED) {
909            // Nothing to do.
910        }
911        if (packet->signal.observed & ZX_THREAD_RUNNING) {
912            ASSERT_EQ(pkt_tid, data->thread_id);
913            atomic_fetch_add(&data->resume_count, 1);
914        }
915        if (packet->signal.observed & ZX_THREAD_SUSPENDED) {
916            ASSERT_EQ(pkt_tid, data->thread_id);
917            atomic_fetch_add(&data->suspend_count, 1);
918            ASSERT_EQ(zx_task_resume(data->thread_handle, 0), ZX_OK);
919            // At this point we should get ZX_THREAD_RUNNING, we'll
920            // process it later.
921        }
922    } else {
923        ASSERT_TRUE(ZX_PKT_IS_EXCEPTION(packet->type));
924
925        zx_koid_t pkt_tid = packet->exception.tid;
926
927        switch (packet->type) {
928        case ZX_EXCP_THREAD_EXITING:
929            // N.B. We could get thread exiting messages from previous
930            // tests.
931            EXPECT_TRUE(handle_thread_exiting(inferior, packet));
932            break;
933
934        case ZX_EXCP_FATAL_PAGE_FAULT: {
935            unittest_printf("wait-inf: got page fault exception\n");
936
937            ASSERT_EQ(pkt_tid, data->thread_id);
938
939            // Verify that the fault is at the PC we expected.
940            if (!test_segv_pc(data->thread_handle))
941                return false;
942
943            // Suspend the thread before fixing the segv to verify register
944            // access works while the thread is in an exception and suspended.
945            zx_handle_t token;
946            ASSERT_EQ(zx_task_suspend_token(data->thread_handle, &token), ZX_OK);
947
948            // Waiting for the thread to suspend doesn't work here as the
949            // thread stays in the exception until we pass ZX_RESUME_EXCEPTION.
950            // Just give the scheduler a chance to run the thread and process
951            // the ZX_ERR_INTERNAL_INTR_RETRY in ExceptionHandlerExchange.
952            zx_nanosleep(zx_deadline_after(ZX_MSEC(1)));
953
954            // Do some tests that require a suspended inferior.
955            // This is required as the inferior does tests after it wakes up
956            // that assumes we've done this.
957            test_memory_ops(inferior, data->thread_handle);
958
959            // Now correct the issue and resume the inferior.
960            fix_inferior_segv(data->thread_handle);
961
962            atomic_fetch_add(&data->segv_count, 1);
963
964            ASSERT_EQ(zx_task_resume(data->thread_handle, ZX_RESUME_EXCEPTION), ZX_OK);
965            // At this point we should get ZX_THREAD_SUSPENDED, we'll
966            // process it later.
967
968            break;
969        }
970
971        default: {
972            char msg[128];
973            snprintf(msg, sizeof(msg), "unexpected packet type: 0x%x", packet->type);
974            ASSERT_TRUE(false, msg);
975            __UNREACHABLE;
976        }
977        }
978    }
979
980    END_HELPER;
981}
982
983bool suspended_in_exception_reg_access_test() {
984    BEGIN_TEST;
985
986    launchpad_t* lp;
987    zx_handle_t inferior, channel;
988    if (!setup_inferior(test_inferior_child_name, &lp, &inferior, &channel))
989        return false;
990
991    if (!start_inferior(lp))
992        return false;
993    if (!verify_inferior_running(channel))
994        return false;
995
996    suspend_in_exception_data data;
997    data.segv_count.store(0);
998    data.suspend_count.store(0);
999    data.resume_count.store(0);
1000    ASSERT_TRUE(get_inferior_thread_handle(channel, &data.thread_handle));
1001    data.process_id = tu_get_koid(inferior);
1002    data.thread_id = tu_get_koid(data.thread_handle);
1003
1004    // Defer attaching until after the inferior is running to test
1005    // attach_inferior's recording of existing threads. If that fails
1006    // it won't see thread suspended/running messages from the thread.
1007    zx_handle_t eport = tu_io_port_create();
1008    size_t max_threads = 10;
1009    inferior_data_t* inferior_data = attach_inferior(inferior, eport, max_threads);
1010    thrd_t wait_inf_thread =
1011        start_wait_inf_thread(inferior_data, suspended_in_exception_handler, &data);
1012    EXPECT_NE(eport, ZX_HANDLE_INVALID);
1013
1014    enum message msg;
1015    send_msg(channel, MSG_CRASH_AND_RECOVER_TEST);
1016    if (!recv_msg(channel, &msg)) {
1017        return false;
1018    }
1019    // wait_inf_thread will process the crash and resume the inferior.
1020    EXPECT_EQ(msg, MSG_RECOVERED_FROM_CRASH);
1021
1022    if (!shutdown_inferior(channel, inferior))
1023        return false;
1024
1025    // Stop the waiter thread before closing the eport that it's waiting on.
1026    join_wait_inf_thread(wait_inf_thread);
1027
1028    detach_inferior(inferior_data, true);
1029
1030    // Don't check these until now to ensure the resume_count has been
1031    // updated (we're guaranteed that ZX_THREAD_RUNNING will be signalled
1032    // and processed before the waiter thread exits.
1033    EXPECT_EQ(data.segv_count.load(), kNumSegvTries);
1034    EXPECT_EQ(data.suspend_count.load(), kNumSegvTries);
1035    // There's an initial "RUNNING" signal that the handler will see.
1036    // That is why we add one here.
1037    EXPECT_EQ(data.resume_count.load(), kNumSegvTries + 1);
1038
1039    tu_handle_close(data.thread_handle);
1040    tu_handle_close(eport);
1041    tu_handle_close(channel);
1042    tu_handle_close(inferior);
1043
1044    END_TEST;
1045}
1046
1047// This function is marked as no-inline to avoid duplicate label in case the
1048// function call is being inlined.
1049__NO_INLINE static bool test_prep_and_segv() {
1050    uint8_t test_data[kTestMemorySize];
1051    for (unsigned i = 0; i < sizeof(test_data); ++i)
1052        test_data[i] = static_cast<uint8_t>(i);
1053
1054#ifdef __x86_64__
1055    void* segv_pc;
1056    // Note: Fuchsia is always PIC.
1057    __asm__("leaq .Lsegv_here(%%rip),%0" : "=r"(segv_pc));
1058    unittest_printf("About to segv, pc %p\n", segv_pc);
1059
1060    // Set r9 to point to test_data so we can easily access it
1061    // from the parent process.  Likewise set r10 to segv_pc
1062    // so the parent process can verify it matches the fault PC.
1063    __asm__("\
1064        movq %[zero],%%r8\n\
1065        movq %[test_data],%%r9\n\
1066        movq %[pc],%%r10\n\
1067.Lsegv_here:\n\
1068        movq (%%r8),%%rax\
1069"
1070            :
1071            : [zero] "g"(0), [test_data] "g"(&test_data[0]), [pc] "g"(segv_pc)
1072            : "rax", "r8", "r9", "r10");
1073#endif
1074
1075#ifdef __aarch64__
1076    void* segv_pc;
1077    // Note: Fuchsia is always PIC.
1078    __asm__("adrp %0, .Lsegv_here\n"
1079            "add %0, %0, :lo12:.Lsegv_here"
1080            : "=r"(segv_pc));
1081    unittest_printf("About to segv, pc %p\n", segv_pc);
1082
1083    // Set r9 to point to test_data so we can easily access it
1084    // from the parent process.  Likewise set r10 to segv_pc
1085    // so the parent process can verify it matches the fault PC.
1086    __asm__("\
1087        mov x8,xzr\n\
1088        mov x9,%[test_data]\n\
1089        mov x10,%[pc]\n\
1090.Lsegv_here:\n\
1091        ldr x0,[x8]\
1092"
1093            :
1094            : [test_data] "r"(&test_data[0]), [pc] "r"(segv_pc)
1095            : "x0", "x8", "x9", "x10");
1096#endif
1097
1098    // On resumption test_data should have had kTestDataAdjust added to each element.
1099    // Note: This is the inferior process, it's not running under the test harness.
1100    for (unsigned i = 0; i < sizeof(test_data); ++i) {
1101        if (test_data[i] != i + kTestDataAdjust) {
1102            unittest_printf("test_prep_and_segv: bad data on resumption, test_data[%u] = 0x%x\n", i,
1103                            test_data[i]);
1104            return false;
1105        }
1106    }
1107
1108    unittest_printf("Inferior successfully resumed!\n");
1109
1110    return true;
1111}
1112
1113int extra_thread_func(void* arg) {
1114    atomic_fetch_add(&extra_thread_count, 1);
1115    unittest_printf("Extra thread started.\n");
1116    while (true)
1117        zx_nanosleep(zx_deadline_after(ZX_SEC(1)));
1118    return 0;
1119}
1120
1121// This returns a bool as it's a unittest "helper" routine.
1122
1123bool msg_loop(zx_handle_t channel) {
1124    BEGIN_HELPER; // Don't stomp on the main thread's current_test_info.
1125
1126    bool my_done_tests = false;
1127
1128    while (!my_done_tests) {
1129        enum message msg;
1130        ASSERT_TRUE(recv_msg(channel, &msg), "Error while receiving msg");
1131        switch (msg) {
1132        case MSG_DONE:
1133            my_done_tests = true;
1134            break;
1135        case MSG_PING:
1136            send_msg(channel, MSG_PONG);
1137            break;
1138        case MSG_CRASH_AND_RECOVER_TEST:
1139            for (int i = 0; i < kNumSegvTries; ++i) {
1140                if (!test_prep_and_segv())
1141                    exit(21);
1142            }
1143            send_msg(channel, MSG_RECOVERED_FROM_CRASH);
1144            break;
1145        case MSG_START_EXTRA_THREADS:
1146            for (int i = 0; i < kNumExtraThreads; ++i) {
1147                // For our purposes, we don't need to track the threads.
1148                // They'll be terminated when the process exits.
1149                thrd_t thread;
1150                tu_thread_create_c11(&thread, extra_thread_func, NULL, "extra-thread");
1151            }
1152            // Wait for all threads to be started.
1153            // Each will require an ZX_EXCP_THREAD_STARTING exchange with the "debugger".
1154            while (extra_thread_count.load() < kNumExtraThreads)
1155                zx_nanosleep(zx_deadline_after(ZX_USEC(1)));
1156            send_msg(channel, MSG_EXTRA_THREADS_STARTED);
1157            break;
1158        case MSG_GET_THREAD_HANDLE: {
1159            zx_handle_t self = zx_thread_self();
1160            zx_handle_t copy;
1161            zx_handle_duplicate(self, ZX_RIGHT_SAME_RIGHTS, &copy);
1162            // Note: The handle is transferred to the receiver.
1163            uint64_t data = MSG_THREAD_HANDLE;
1164            unittest_printf("sending handle %d message on channel %u\n", copy, channel);
1165            tu_channel_write(channel, 0, &data, sizeof(data), &copy, 1);
1166            break;
1167        }
1168        default:
1169            unittest_printf("unknown message received: %d\n", msg);
1170            break;
1171        }
1172    }
1173
1174    END_HELPER;
1175}
1176
1177void test_inferior() {
1178    zx_handle_t channel = zx_take_startup_handle(PA_USER0);
1179    unittest_printf("test_inferior: got handle %d\n", channel);
1180
1181    if (!msg_loop(channel))
1182        exit(20);
1183
1184    unittest_printf("Inferior done\n");
1185    exit(1234);
1186}
1187
1188// Compilers are getting too smart.
1189// These maintain the semantics we want even under optimization.
1190
1191volatile int* crashing_ptr = (int*)42;
1192volatile int crash_depth;
1193
1194// This is used to cause fp != sp when the crash happens on arm64.
1195int leaf_stack_size = 10;
1196
1197int __NO_INLINE test_segfault_doit2(int*);
1198
1199int __NO_INLINE test_segfault_leaf(int n, int* p) {
1200    volatile int x[n];
1201    x[0] = *p;
1202    *crashing_ptr = x[0];
1203    return 0;
1204}
1205
1206int __NO_INLINE test_segfault_doit1(int* p) {
1207    if (crash_depth > 0) {
1208        int n = crash_depth;
1209        int use_stack[n];
1210        memset(use_stack, 0x99, n * sizeof(int));
1211        --crash_depth;
1212        return test_segfault_doit2(use_stack) + 99;
1213    }
1214    return test_segfault_leaf(leaf_stack_size, p) + 99;
1215}
1216
1217int __NO_INLINE test_segfault_doit2(int* p) {
1218    return test_segfault_doit1(p) + *p;
1219}
1220
1221// Produce a crash with a moderately interesting backtrace.
1222int __NO_INLINE test_segfault() {
1223    crash_depth = kTestSegfaultDepth;
1224    int i = 0;
1225    return test_segfault_doit1(&i);
1226}
1227
1228// Invoke the s/w breakpoint insn using the crashlogger mechanism
1229// to request a backtrace but not terminate the process.
1230int __NO_INLINE test_swbreak() {
1231    unittest_printf("Invoking s/w breakpoint instruction\n");
1232    zx_crashlogger_request_backtrace();
1233    unittest_printf("Resumed after s/w breakpoint instruction\n");
1234    return 0;
1235}
1236
1237void scan_argv(int argc, char** argv) {
1238    for (int i = 1; i < argc; ++i) {
1239        if (strncmp(argv[i], "v=", 2) == 0) {
1240            int verbosity = atoi(argv[i] + 2);
1241            unittest_set_verbosity_level(verbosity);
1242        }
1243    }
1244}
1245
1246} // namespace
1247
1248BEGIN_TEST_CASE(debugger_tests)
1249RUN_TEST(debugger_test)
1250RUN_TEST(debugger_thread_list_test)
1251RUN_TEST(property_process_debug_addr_test)
1252RUN_TEST(write_text_segment)
1253RUN_TEST(suspended_reg_access_test)
1254RUN_TEST(suspended_in_syscall_reg_access_test)
1255RUN_TEST(suspended_in_channel_call_reg_access_test)
1256RUN_TEST(suspended_in_exception_reg_access_test)
1257END_TEST_CASE(debugger_tests)
1258
1259int main(int argc, char** argv) {
1260    program_path = argv[0];
1261    scan_argv(argc, argv);
1262
1263    if (argc >= 2 && strcmp(argv[1], test_inferior_child_name) == 0) {
1264        test_inferior();
1265        return 0;
1266    }
1267    if (argc >= 2 && strcmp(argv[1], test_segfault_child_name) == 0) {
1268        return test_segfault();
1269    }
1270    if (argc >= 2 && strcmp(argv[1], test_swbreak_child_name) == 0) {
1271        return test_swbreak();
1272    }
1273
1274    bool success = unittest_run_all_tests(argc, argv);
1275    return success ? 0 : -1;
1276}
1277