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 <inttypes.h>
6#include <link.h>
7#include <stdbool.h>
8#include <stdlib.h>
9#include <string.h>
10
11#include <fbl/algorithm.h>
12#include <launchpad/launchpad.h>
13#include <launchpad/vmo.h>
14#include <test-utils/test-utils.h>
15#include <unittest/unittest.h>
16#include <zircon/compiler.h>
17#include <zircon/process.h>
18#include <zircon/processargs.h>
19#include <zircon/syscalls.h>
20#include <zircon/syscalls/debug.h>
21#include <zircon/syscalls/object.h>
22#include <zircon/syscalls/port.h>
23
24#include "utils.h"
25
26// argv[0]
27const char* program_path;
28
29static const uint64_t exception_port_key = 0x6b6579; // "key"
30
31uint32_t get_uint32(char* buf) {
32    uint32_t value = 0;
33    memcpy(&value, buf, sizeof(value));
34    return value;
35}
36
37uint64_t get_uint64(char* buf) {
38    uint64_t value = 0;
39    memcpy(&value, buf, sizeof(value));
40    return value;
41}
42
43void set_uint64(char* buf, uint64_t value) {
44    memcpy(buf, &value, sizeof(value));
45}
46
47uint32_t get_uint32_property(zx_handle_t handle, uint32_t prop) {
48    uint32_t value;
49    zx_status_t status = zx_object_get_property(handle, prop, &value, sizeof(value));
50    if (status != ZX_OK)
51        tu_fatal("zx_object_get_property failed", status);
52    return value;
53}
54
55void send_msg(zx_handle_t handle, message msg) {
56    uint64_t data = msg;
57    unittest_printf("sending message %d on handle %u\n", msg, handle);
58    tu_channel_write(handle, 0, &data, sizeof(data), NULL, 0);
59}
60
61// This returns "bool" because it uses ASSERT_*.
62
63bool recv_msg(zx_handle_t handle, message* msg) {
64    BEGIN_HELPER;
65
66    uint64_t data;
67    uint32_t num_bytes = sizeof(data);
68
69    unittest_printf("waiting for message on handle %u\n", handle);
70
71    ASSERT_TRUE(tu_channel_wait_readable(handle), "peer closed while trying to read message");
72
73    tu_channel_read(handle, 0, &data, &num_bytes, NULL, 0);
74    ASSERT_EQ(num_bytes, sizeof(data), "unexpected message size");
75
76    *msg = static_cast<message>(data);
77    unittest_printf("received message %d\n", *msg);
78
79    END_HELPER;
80}
81
82void dump_gregs(zx_handle_t thread_handle, const zx_thread_state_general_regs_t* regs) {
83    unittest_printf("Registers for thread %d\n", thread_handle);
84
85#define DUMP_NAMED_REG(name)                                                                       \
86    unittest_printf("  %8s      %24ld  0x%lx\n", #name, (long)regs->name, (long)regs->name)
87
88#if defined(__x86_64__)
89
90    DUMP_NAMED_REG(rax);
91    DUMP_NAMED_REG(rbx);
92    DUMP_NAMED_REG(rcx);
93    DUMP_NAMED_REG(rdx);
94    DUMP_NAMED_REG(rsi);
95    DUMP_NAMED_REG(rdi);
96    DUMP_NAMED_REG(rbp);
97    DUMP_NAMED_REG(rsp);
98    DUMP_NAMED_REG(r8);
99    DUMP_NAMED_REG(r9);
100    DUMP_NAMED_REG(r10);
101    DUMP_NAMED_REG(r11);
102    DUMP_NAMED_REG(r12);
103    DUMP_NAMED_REG(r13);
104    DUMP_NAMED_REG(r14);
105    DUMP_NAMED_REG(r15);
106    DUMP_NAMED_REG(rip);
107    DUMP_NAMED_REG(rflags);
108
109#elif defined(__aarch64__)
110
111    for (int i = 0; i < 30; i++) {
112        unittest_printf("  r[%2d]     %24ld  0x%lx\n", i, (long)regs->r[i], (long)regs->r[i]);
113    }
114    DUMP_NAMED_REG(lr);
115    DUMP_NAMED_REG(sp);
116    DUMP_NAMED_REG(pc);
117    DUMP_NAMED_REG(cpsr);
118
119#endif
120
121#undef DUMP_NAMED_REG
122}
123
124void dump_inferior_regs(zx_handle_t thread) {
125    zx_thread_state_general_regs_t regs;
126    read_inferior_gregs(thread, &regs);
127    dump_gregs(thread, &regs);
128}
129
130// N.B. It is assumed |buf_size| is large enough.
131
132void read_inferior_gregs(zx_handle_t thread, zx_thread_state_general_regs_t* in) {
133    zx_status_t status = zx_thread_read_state(
134        thread, ZX_THREAD_STATE_GENERAL_REGS, in, sizeof(zx_thread_state_general_regs_t));
135    // It's easier to just terminate if this fails.
136    if (status != ZX_OK)
137        tu_fatal("read_inferior_gregs: zx_thread_read_state", status);
138}
139
140void write_inferior_gregs(zx_handle_t thread, const zx_thread_state_general_regs_t* out) {
141    zx_status_t status = zx_thread_write_state(thread, ZX_THREAD_STATE_GENERAL_REGS, out,
142                                               sizeof(zx_thread_state_general_regs_t));
143    // It's easier to just terminate if this fails.
144    if (status != ZX_OK)
145        tu_fatal("write_inferior_gregs: zx_thread_write_state", status);
146}
147
148size_t read_inferior_memory(zx_handle_t proc, uintptr_t vaddr, void* buf, size_t len) {
149    zx_status_t status = zx_process_read_memory(proc, vaddr, buf, len, &len);
150    if (status < 0)
151        tu_fatal("read_inferior_memory", status);
152    return len;
153}
154
155size_t write_inferior_memory(zx_handle_t proc, uintptr_t vaddr, const void* buf, size_t len) {
156    zx_status_t status = zx_process_write_memory(proc, vaddr, buf, len, &len);
157    if (status < 0)
158        tu_fatal("write_inferior_memory", status);
159    return len;
160}
161
162// This does everything that launchpad_launch_fdio_etc does except
163// start the inferior. We want to attach to it first.
164// TODO(dje): Are there other uses of such a wrapper? Move to launchpad?
165// Plus there's a fair bit of code here. IWBN to not have to update it as
166// launchpad_launch_fdio_etc changes.
167
168zx_status_t create_inferior(const char* name, int argc, const char* const* argv,
169                            const char* const* envp, size_t hnds_count, zx_handle_t* handles,
170                            uint32_t* ids, launchpad_t** out_launchpad) {
171    launchpad_t* lp = NULL;
172
173    const char* filename = argv[0];
174    if (name == NULL)
175        name = filename;
176
177    zx_status_t status;
178    launchpad_create(0u, name, &lp);
179    launchpad_load_from_file(lp, filename);
180    launchpad_set_args(lp, argc, argv);
181    launchpad_set_environ(lp, envp);
182    launchpad_clone(lp, LP_CLONE_FDIO_ALL);
183    status = launchpad_add_handles(lp, hnds_count, handles, ids);
184
185    if (status < 0) {
186        launchpad_destroy(lp);
187    } else {
188        *out_launchpad = lp;
189    }
190    return status;
191}
192
193bool setup_inferior(const char* name, launchpad_t** out_lp, zx_handle_t* out_inferior,
194                    zx_handle_t* out_channel) {
195    BEGIN_HELPER;
196
197    zx_status_t status;
198    zx_handle_t channel1, channel2;
199    tu_channel_create(&channel1, &channel2);
200
201    const char verbosity_string[] = {'v', '=', static_cast<char>(utest_verbosity_level + '0'),
202                                     '\0'};
203    const char* test_child_path = program_path;
204    const char* const argv[] = {test_child_path, name, verbosity_string};
205    zx_handle_t handles[1] = {channel2};
206    uint32_t handle_ids[1] = {PA_USER0};
207
208    launchpad_t* lp;
209    unittest_printf("Creating process \"%s\"\n", name);
210    status = create_inferior(name, fbl::count_of(argv), argv, NULL, fbl::count_of(handles),
211                             handles, handle_ids, &lp);
212    ASSERT_EQ(status, ZX_OK, "failed to create inferior");
213
214    // Note: |inferior| is a borrowed handle here.
215    zx_handle_t inferior = launchpad_get_process_handle(lp);
216    ASSERT_NE(inferior, ZX_HANDLE_INVALID, "can't get launchpad process handle");
217
218    zx_info_handle_basic_t process_info;
219    tu_handle_get_basic_info(inferior, &process_info);
220    unittest_printf("Inferior pid = %llu\n", (long long)process_info.koid);
221
222    // |inferior| is given to the child by launchpad_go.
223    // We need our own copy, and launchpad_go will give us one, but we need
224    // it before we call launchpad_go in order to attach to the debugging
225    // exception port. We could leave this to our caller to do, but since every
226    // caller needs this for convenience sake we do this here.
227    status = zx_handle_duplicate(inferior, ZX_RIGHT_SAME_RIGHTS, &inferior);
228    ASSERT_EQ(status, ZX_OK, "zx_handle_duplicate failed");
229
230    *out_lp = lp;
231    *out_inferior = inferior;
232    *out_channel = channel1;
233
234    END_HELPER;
235}
236
237// While this should perhaps take a launchpad_t* argument instead of the
238// inferior's handle, we later want to test attaching to an already running
239// inferior.
240// |max_threads| is the maximum number of threads the process is expected
241// to have in its lifetime. A real debugger would be more flexible of course.
242// N.B. |inferior| cannot be the result of launchpad_get_process_handle().
243// That handle is passed to the inferior when started and thus is lost to us.
244// Returns a boolean indicating success.
245
246inferior_data_t* attach_inferior(zx_handle_t inferior, zx_handle_t eport, size_t max_threads) {
247    // Fetch all current threads and attach async-waiters to them.
248    // N.B. We assume threads aren't being created as we're running.
249    // This is just a testcase so we can assume that. A real debugger
250    // would not have this assumption.
251    zx_koid_t* thread_koids = static_cast<zx_koid_t*>(tu_malloc(max_threads * sizeof(zx_koid_t)));
252    size_t num_threads = tu_process_get_threads(inferior, thread_koids, max_threads);
253    // For now require |max_threads| to be big enough.
254    if (num_threads > max_threads)
255        tu_fatal(__func__, ZX_ERR_BUFFER_TOO_SMALL);
256
257    tu_set_exception_port(inferior, eport, exception_port_key, ZX_EXCEPTION_PORT_DEBUGGER);
258    tu_object_wait_async(inferior, eport, ZX_PROCESS_TERMINATED);
259
260    inferior_data_t* data = static_cast<inferior_data_t*>(tu_malloc(sizeof(*data)));
261    data->threads = static_cast<thread_data_t*>(tu_calloc(max_threads, sizeof(data->threads[0])));
262    data->inferior = inferior;
263    data->eport = eport;
264    data->max_num_threads = max_threads;
265
266    // Notification of thread termination and suspension is delivered by
267    // signals. So that we can continue to only have to wait on |eport|
268    // for inferior status change notification, install async-waiters
269    // for each thread.
270    size_t j = 0;
271    zx_signals_t thread_signals = ZX_THREAD_TERMINATED | ZX_THREAD_RUNNING | ZX_THREAD_SUSPENDED;
272    for (size_t i = 0; i < num_threads; ++i) {
273        zx_handle_t thread = tu_process_get_thread(inferior, thread_koids[i]);
274        if (thread != ZX_HANDLE_INVALID) {
275            data->threads[j].tid = thread_koids[i];
276            data->threads[j].handle = thread;
277            tu_object_wait_async(thread, eport, thread_signals);
278            ++j;
279        }
280    }
281    free(thread_koids);
282
283    unittest_printf("Attached to inferior\n");
284    return data;
285}
286
287void detach_inferior(inferior_data_t* data, bool unbind_eport) {
288    if (unbind_eport) {
289        tu_set_exception_port(data->inferior, ZX_HANDLE_INVALID, exception_port_key,
290                              ZX_EXCEPTION_PORT_DEBUGGER);
291    }
292    for (size_t i = 0; i < data->max_num_threads; ++i) {
293        if (data->threads[i].handle != ZX_HANDLE_INVALID)
294            tu_handle_close(data->threads[i].handle);
295    }
296    free(data->threads);
297    free(data);
298}
299
300bool start_inferior(launchpad_t* lp) {
301    zx_handle_t dup_inferior = tu_launch_fdio_fini(lp);
302    unittest_printf("Inferior started\n");
303    // launchpad_go returns a dup of |inferior|. The original inferior
304    // handle is given to the child. However we don't need it, we already
305    // created one so that we could attach to the inferior before starting it.
306    tu_handle_close(dup_inferior);
307    return true;
308}
309
310bool verify_inferior_running(zx_handle_t channel) {
311    BEGIN_HELPER;
312
313    enum message msg;
314    send_msg(channel, MSG_PING);
315    if (!recv_msg(channel, &msg))
316        return false;
317    EXPECT_EQ(msg, MSG_PONG, "unexpected response from ping");
318
319    END_HELPER;
320}
321
322static bool recv_msg_handle(zx_handle_t channel, message expected_msg, zx_handle_t* handle) {
323    BEGIN_HELPER;
324
325    unittest_printf("waiting for message on channel %u\n", channel);
326    ASSERT_TRUE(tu_channel_wait_readable(channel), "peer closed while trying to read message");
327
328    uint64_t data;
329    uint32_t num_bytes = sizeof(data);
330    uint32_t num_handles = 1;
331    tu_channel_read(channel, 0, &data, &num_bytes, handle, &num_handles);
332    ASSERT_EQ(num_bytes, sizeof(data));
333    ASSERT_EQ(num_handles, 1u);
334
335    message msg = static_cast<message>(data);
336    ASSERT_EQ(msg, expected_msg);
337
338    unittest_printf("received handle %d\n", *handle);
339
340    END_HELPER;
341}
342
343bool get_inferior_thread_handle(zx_handle_t channel, zx_handle_t* thread) {
344    BEGIN_HELPER;
345
346    send_msg(channel, MSG_GET_THREAD_HANDLE);
347    ASSERT_TRUE(recv_msg_handle(channel, MSG_THREAD_HANDLE, thread));
348
349    END_HELPER;
350}
351
352bool resume_inferior(zx_handle_t inferior, zx_koid_t tid) {
353    BEGIN_HELPER;
354
355    zx_handle_t thread;
356    zx_status_t status = zx_object_get_child(inferior, tid, ZX_RIGHT_SAME_RIGHTS, &thread);
357    if (status == ZX_ERR_NOT_FOUND) {
358        // If the process has exited then the kernel may have reaped the
359        // thread already. Check.
360        if (tu_process_has_exited(inferior))
361            return true;
362    }
363    ASSERT_EQ(status, ZX_OK, "zx_object_get_child failed");
364
365    unittest_printf("Resuming inferior ...\n");
366    status = zx_task_resume(thread, ZX_RESUME_EXCEPTION);
367    if (status == ZX_ERR_BAD_STATE) {
368        // If the process has exited then the thread may have exited
369        // ExceptionHandlerExchange already. Check.
370        if (tu_thread_is_dying_or_dead(thread)) {
371            tu_handle_close(thread);
372            return true;
373        }
374    }
375    tu_handle_close(thread);
376    ASSERT_EQ(status, ZX_OK, "zx_task_resume failed");
377
378    END_HELPER;
379}
380
381bool shutdown_inferior(zx_handle_t channel, zx_handle_t inferior) {
382    BEGIN_HELPER;
383
384    unittest_printf("Shutting down inferior\n");
385
386    send_msg(channel, MSG_DONE);
387
388    tu_process_wait_signaled(inferior);
389    EXPECT_EQ(tu_process_get_return_code(inferior), 1234, "unexpected inferior return code");
390
391    END_HELPER;
392}
393
394// Wait for and read an exception/signal on |eport|.
395
396bool read_exception(zx_handle_t eport, zx_port_packet_t* packet) {
397    BEGIN_HELPER;
398
399    unittest_printf("Waiting for exception/signal on eport %d\n", eport);
400    ASSERT_EQ(zx_port_wait(eport, ZX_TIME_INFINITE, packet), ZX_OK, "zx_port_wait failed");
401
402    if (ZX_PKT_IS_EXCEPTION(packet->type))
403        ASSERT_EQ(packet->key, exception_port_key);
404
405    unittest_printf("read_exception: got exception/signal %d\n", packet->type);
406
407    END_HELPER;
408}
409
410// Wait for the thread to suspend
411// We could get a thread exit report from a previous test, so
412// we need to handle that, but no other exceptions are expected.
413//
414// The thread is assumed to be wait-async'd on |eport|. While we could just
415// wait on the |thread| for the appropriate signal, the signal will also be
416// sent to |eport| which our caller would then have to deal with. Keep things
417// simpler by doing all waiting via |eport|. It also makes us exercise doing
418// things this way, which is generally what debuggers will do.
419
420bool wait_thread_suspended(zx_handle_t proc, zx_handle_t thread, zx_handle_t eport) {
421    BEGIN_HELPER;
422
423    zx_koid_t tid = tu_get_koid(thread);
424
425    while (true) {
426        zx_port_packet_t packet;
427        zx_status_t status = zx_port_wait(eport, zx_deadline_after(ZX_SEC(1)), &packet);
428        if (status == ZX_ERR_TIMED_OUT) {
429            // This shouldn't really happen unless the system is really loaded.
430            // Just flag it and try again. The watchdog will catch failures.
431            unittest_printf("%s: timed out???\n", __func__);
432            continue;
433        }
434        ASSERT_EQ(status, ZX_OK);
435        if (ZX_PKT_IS_SIGNAL_REP(packet.type)) {
436            ASSERT_EQ(packet.key, tid);
437            if (packet.signal.observed & ZX_THREAD_SUSPENDED)
438                break;
439            ASSERT_TRUE(packet.signal.observed & ZX_THREAD_RUNNING);
440        } else {
441            ASSERT_TRUE(ZX_PKT_IS_EXCEPTION(packet.type));
442            zx_koid_t report_tid = packet.exception.tid;
443            ASSERT_NE(report_tid, tid);
444            ASSERT_EQ(packet.type, (uint32_t)ZX_EXCP_THREAD_EXITING);
445            // Note the thread may be completely gone by now.
446            zx_handle_t other_thread;
447            zx_status_t status =
448                zx_object_get_child(proc, report_tid, ZX_RIGHT_SAME_RIGHTS, &other_thread);
449            if (status == ZX_OK) {
450                // And even if it's not gone it may be dead now.
451                status = zx_task_resume(other_thread, ZX_RESUME_EXCEPTION);
452                if (status == ZX_ERR_BAD_STATE)
453                    ASSERT_TRUE(tu_thread_is_dying_or_dead(other_thread));
454                else
455                    ASSERT_EQ(status, ZX_OK);
456                tu_handle_close(other_thread);
457            }
458        }
459    }
460
461    // Verify thread is suspended
462    zx_info_thread_t info = tu_thread_get_info(thread);
463    ASSERT_EQ(info.state, ZX_THREAD_STATE_SUSPENDED);
464    ASSERT_EQ(info.wait_exception_port_type, ZX_EXCEPTION_PORT_TYPE_NONE);
465
466    END_HELPER;
467}
468
469static int phdr_info_callback(dl_phdr_info* info, size_t size, void* data) {
470    dl_phdr_info* key = static_cast<dl_phdr_info*>(data);
471    if (info->dlpi_addr == key->dlpi_addr) {
472        *key = *info;
473        return 1;
474    }
475    return 0;
476}
477
478// Fetch the [inclusive] range of the executable segment of the vdso.
479
480bool get_vdso_exec_range(uintptr_t* start, uintptr_t* end) {
481    BEGIN_HELPER;
482
483    char msg[128];
484
485    uintptr_t prop_vdso_base;
486    zx_status_t status =
487        zx_object_get_property(zx_process_self(), ZX_PROP_PROCESS_VDSO_BASE_ADDRESS,
488                               &prop_vdso_base, sizeof(prop_vdso_base));
489    snprintf(msg, sizeof(msg), "zx_object_get_property failed: %d", status);
490    ASSERT_EQ(status, 0, msg);
491
492    dl_phdr_info info;
493    info.dlpi_addr = prop_vdso_base;
494    int ret = dl_iterate_phdr(&phdr_info_callback, &info);
495    ASSERT_EQ(ret, 1, "dl_iterate_phdr didn't see vDSO?");
496
497    uintptr_t vdso_code_start = 0;
498    size_t vdso_code_len = 0;
499    for (unsigned i = 0; i < info.dlpi_phnum; ++i) {
500        if (info.dlpi_phdr[i].p_type == PT_LOAD && (info.dlpi_phdr[i].p_flags & PF_X)) {
501            vdso_code_start = info.dlpi_addr + info.dlpi_phdr[i].p_vaddr;
502            vdso_code_len = info.dlpi_phdr[i].p_memsz;
503            break;
504        }
505    }
506    ASSERT_NE(vdso_code_start, 0u, "vDSO has no code segment?");
507    ASSERT_NE(vdso_code_len, 0u, "vDSO has no code segment?");
508
509    *start = vdso_code_start;
510    *end = vdso_code_start + vdso_code_len - 1;
511
512    END_HELPER;
513}
514