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 <stdlib.h>
6#include <string.h>
7#include <launchpad/launchpad.h>
8#include <launchpad/vmo.h>
9#include <lib/zircon-internal/crashlogger.h>
10#include <zircon/process.h>
11#include <zircon/syscalls.h>
12#include <zircon/syscalls/port.h>
13#include <zircon/status.h>
14#include <runtime/thread.h>
15#include <test-utils/test-utils.h>
16#include <unittest/unittest.h>
17
18#define TU_FAIL_ERRCODE 10
19
20void* tu_malloc(size_t size)
21{
22    void* result = malloc(size);
23    if (result == NULL) {
24        // TODO(dje): printf may try to malloc too ...
25        unittest_printf_critical("out of memory trying to malloc(%zu)\n", size);
26        exit(TU_FAIL_ERRCODE);
27    }
28    return result;
29}
30
31void* tu_calloc(size_t nmemb, size_t size)
32{
33    void* result = calloc(nmemb, size);
34    if (result == NULL) {
35        // TODO(dje): printf may try to malloc too ...
36        unittest_printf_critical("out of memory trying to calloc(%zu, %zu)\n", nmemb, size);
37        exit(TU_FAIL_ERRCODE);
38    }
39    return result;
40}
41
42char* tu_strdup(const char* s)
43{
44    size_t len = strlen(s) + 1;
45    char* r = tu_malloc(len);
46    strcpy(r, s);
47    return r;
48}
49
50char* tu_asprintf(const char* fmt, ...)
51{
52    va_list args;
53    char* result;
54    va_start(args, fmt);
55    if (vasprintf(&result, fmt, args) < 0) {
56        unittest_printf_critical("out of memory trying to asprintf(%s)\n", fmt);
57        exit(TU_FAIL_ERRCODE);
58    }
59    va_end(args);
60    return result;
61}
62
63void tu_fatal(const char *what, zx_status_t status)
64{
65    const char* reason = zx_status_get_string(status);
66    unittest_printf_critical("\nFATAL: %s failed, rc %d (%s)\n", what, status, reason);
67
68    // Request a backtrace to assist debugging.
69    unittest_printf_critical("FATAL: backtrace follows:\n");
70    unittest_printf_critical("       (using sw breakpoint request to crashlogger)\n");
71    zx_crashlogger_request_backtrace();
72
73    unittest_printf_critical("FATAL: exiting process\n");
74    exit(TU_FAIL_ERRCODE);
75}
76
77void tu_handle_close(zx_handle_t handle)
78{
79    zx_status_t status = zx_handle_close(handle);
80    // TODO(dje): It's still an open question as to whether errors other than ZX_ERR_BAD_HANDLE are "advisory".
81    if (status < 0) {
82        tu_fatal(__func__, status);
83    }
84}
85
86zx_handle_t tu_handle_duplicate(zx_handle_t handle)
87{
88    zx_handle_t copy = ZX_HANDLE_INVALID;
89    zx_status_t status =
90        zx_handle_duplicate(handle, ZX_RIGHT_SAME_RIGHTS, &copy);
91    if (status < 0)
92        tu_fatal(__func__, status);
93    return copy;
94}
95
96// N.B. This creates a C11 thread.
97// See, e.g., musl/include/threads.h.
98
99void tu_thread_create_c11(thrd_t* t, thrd_start_t entry, void* arg,
100                          const char* name)
101{
102    int ret = thrd_create_with_name(t, entry, arg, name);
103    if (ret != thrd_success) {
104        // tu_fatal takes zx_status_t values.
105        // The translation doesn't have to be perfect.
106        switch (ret) {
107        case thrd_nomem:
108            tu_fatal(__func__, ZX_ERR_NO_MEMORY);
109        default:
110            tu_fatal(__func__, ZX_ERR_BAD_STATE);
111        }
112        __UNREACHABLE;
113    }
114}
115
116zx_status_t tu_wait(uint32_t num_objects,
117                    const zx_handle_t* handles,
118                    const zx_signals_t* signals,
119                    zx_signals_t* pending)
120{
121    zx_wait_item_t items[num_objects];
122    for (uint32_t n = 0; n < num_objects; n++) {
123        items[n].handle = handles[n];
124        items[n].waitfor = signals[n];
125    }
126    zx_status_t status = zx_object_wait_many(items, num_objects, ZX_TIME_INFINITE);
127    for (uint32_t n = 0; n < num_objects; n++) {
128        pending[n] = items[n].pending;
129    }
130    return status;
131}
132
133void tu_channel_create(zx_handle_t* handle0, zx_handle_t* handle1) {
134    zx_handle_t handles[2];
135    zx_status_t status = zx_channel_create(0, &handles[0], &handles[1]);
136    if (status < 0)
137        tu_fatal(__func__, status);
138    *handle0 = handles[0];
139    *handle1 = handles[1];
140}
141
142void tu_channel_write(zx_handle_t handle, uint32_t flags, const void* bytes, uint32_t num_bytes,
143                      const zx_handle_t* handles, uint32_t num_handles) {
144    zx_status_t status = zx_channel_write(handle, flags, bytes, num_bytes, handles, num_handles);
145    if (status < 0)
146        tu_fatal(__func__, status);
147}
148
149void tu_channel_read(zx_handle_t handle, uint32_t flags, void* bytes, uint32_t* num_bytes,
150                     zx_handle_t* handles, uint32_t* num_handles) {
151    zx_status_t status = zx_channel_read(handle, flags, bytes, handles,
152                                         num_bytes ? *num_bytes : 0, num_handles ? *num_handles : 0,
153                                         num_bytes, num_handles);
154    if (status < 0)
155        tu_fatal(__func__, status);
156}
157
158bool tu_channel_wait_readable(zx_handle_t channel)
159{
160    zx_signals_t signals = ZX_CHANNEL_READABLE | ZX_CHANNEL_PEER_CLOSED;
161    zx_signals_t pending;
162    zx_status_t result = tu_wait(1, &channel, &signals, &pending);
163    if (result != ZX_OK)
164        tu_fatal(__func__, result);
165    if ((pending & ZX_CHANNEL_READABLE) == 0) {
166        unittest_printf("%s: peer closed\n", __func__);
167        return false;
168    }
169    return true;
170}
171
172zx_handle_t tu_launch(zx_handle_t job, const char* name,
173                      int argc, const char* const* argv,
174                      const char* const* envp,
175                      size_t num_handles, zx_handle_t* handles,
176                      uint32_t* handle_ids)
177{
178    launchpad_t* lp;
179    launchpad_create(job, name, &lp);
180    launchpad_load_from_file(lp, argv[0]);
181    launchpad_set_args(lp, argc, argv);
182    launchpad_set_environ(lp, envp);
183    launchpad_add_handles(lp, num_handles, handles, handle_ids);
184
185    zx_status_t status;
186    zx_handle_t child;
187    status = launchpad_go(lp, &child, NULL);
188
189    if (status < 0)
190        tu_fatal("tu_launch", status);
191    return child;
192}
193
194launchpad_t* tu_launch_fdio_init(zx_handle_t job, const char* name,
195                                 int argc, const char* const* argv,
196                                 const char* const* envp,
197                                 size_t hnds_count, zx_handle_t* handles,
198                                 uint32_t* ids)
199{
200    // This is the first part of launchpad_launch_fdio_etc.
201    // It does everything except start the process running.
202    launchpad_t* lp;
203
204    const char* filename = argv[0];
205    if (name == NULL)
206        name = filename;
207
208    launchpad_create(job, name, &lp);
209    launchpad_load_from_file(lp, filename);
210    launchpad_set_args(lp, argc, argv);
211    launchpad_set_environ(lp, envp);
212    launchpad_clone(lp, LP_CLONE_FDIO_ALL);
213    launchpad_add_handles(lp, hnds_count, handles, ids);
214
215   return lp;
216}
217
218zx_handle_t tu_launch_fdio_fini(launchpad_t* lp)
219{
220    zx_handle_t proc;
221    zx_status_t status;
222    if ((status = launchpad_go(lp, &proc, NULL)) < 0)
223        tu_fatal("tu_launch_fdio_fini", status);
224    return proc;
225}
226
227void tu_process_wait_signaled(zx_handle_t process)
228{
229    zx_signals_t signals = ZX_PROCESS_TERMINATED;
230    zx_signals_t pending;
231    zx_status_t result = tu_wait(1, &process, &signals, &pending);
232    if (result != ZX_OK)
233        tu_fatal(__func__, result);
234    if ((pending & ZX_PROCESS_TERMINATED) == 0) {
235        unittest_printf_critical("%s: unexpected return from tu_wait\n", __func__);
236        exit(TU_FAIL_ERRCODE);
237    }
238}
239
240bool tu_process_has_exited(zx_handle_t process)
241{
242    zx_info_process_t info;
243    zx_status_t status;
244    if ((status = zx_object_get_info(process, ZX_INFO_PROCESS, &info,
245                                     sizeof(info), NULL, NULL)) < 0)
246        tu_fatal("get process info", status);
247    return info.exited;
248}
249
250int tu_process_get_return_code(zx_handle_t process)
251{
252    zx_info_process_t info;
253    zx_status_t status;
254    if ((status = zx_object_get_info(process, ZX_INFO_PROCESS, &info,
255                                     sizeof(info), NULL, NULL)) < 0)
256        tu_fatal("get process info", status);
257    if (!info.exited) {
258        unittest_printf_critical(
259                "attempt to read return code of non-exited process");
260        exit(TU_FAIL_ERRCODE);
261    }
262    return info.return_code;
263}
264
265int tu_process_wait_exit(zx_handle_t process)
266{
267    tu_process_wait_signaled(process);
268    return tu_process_get_return_code(process);
269}
270
271zx_handle_t tu_process_get_thread(zx_handle_t process, zx_koid_t tid)
272{
273    zx_handle_t thread;
274    zx_status_t status = zx_object_get_child(process, tid, ZX_RIGHT_SAME_RIGHTS, &thread);
275    if (status == ZX_ERR_NOT_FOUND)
276        return ZX_HANDLE_INVALID;
277    if (status < 0)
278        tu_fatal(__func__, status);
279    return thread;
280}
281
282size_t tu_process_get_threads(zx_handle_t process, zx_koid_t* threads, size_t max_threads)
283{
284    size_t num_threads;
285    size_t buf_size = max_threads * sizeof(threads[0]);
286    zx_status_t status = zx_object_get_info(process, ZX_INFO_PROCESS_THREADS,
287                                            threads, buf_size, &num_threads, NULL);
288    if (status < 0)
289        tu_fatal(__func__, status);
290    return num_threads;
291}
292
293zx_handle_t tu_job_create(zx_handle_t job)
294{
295    zx_handle_t child_job;
296    zx_status_t status = zx_job_create(job, 0, &child_job);
297    if (status < 0)
298        tu_fatal(__func__, status);
299    return child_job;
300}
301
302zx_handle_t tu_io_port_create(void)
303{
304    zx_handle_t handle;
305    zx_status_t status = zx_port_create(0, &handle);
306    if (status < 0)
307        tu_fatal(__func__, status);
308    return handle;
309}
310
311void tu_set_exception_port(zx_handle_t handle, zx_handle_t eport, uint64_t key, uint32_t options)
312{
313    if (handle == 0)
314        handle = zx_process_self();
315    zx_status_t status = zx_task_bind_exception_port(handle, eport, key, options);
316    if (status < 0)
317        tu_fatal(__func__, status);
318}
319
320void tu_object_wait_async(zx_handle_t handle, zx_handle_t port, zx_signals_t signals)
321{
322    uint64_t key = tu_get_koid(handle);
323    uint32_t options = ZX_WAIT_ASYNC_REPEATING;
324    zx_status_t status = zx_object_wait_async(handle, port, key, signals, options);
325    if (status < 0)
326        tu_fatal(__func__, status);
327}
328
329void tu_handle_get_basic_info(zx_handle_t handle, zx_info_handle_basic_t* info)
330{
331    zx_status_t status = zx_object_get_info(handle, ZX_INFO_HANDLE_BASIC,
332                                            info, sizeof(*info), NULL, NULL);
333    if (status < 0)
334        tu_fatal(__func__, status);
335}
336
337zx_koid_t tu_get_koid(zx_handle_t handle)
338{
339    zx_info_handle_basic_t info;
340    tu_handle_get_basic_info(handle, &info);
341    return info.koid;
342}
343
344zx_koid_t tu_get_related_koid(zx_handle_t handle)
345{
346    zx_info_handle_basic_t info;
347    tu_handle_get_basic_info(handle, &info);
348    return info.related_koid;
349}
350
351zx_handle_t tu_get_thread(zx_handle_t proc, zx_koid_t tid)
352{
353    zx_handle_t thread;
354    zx_status_t status = zx_object_get_child(proc, tid, ZX_RIGHT_SAME_RIGHTS, &thread);
355    if (status != ZX_OK)
356        tu_fatal(__func__, status);
357    return thread;
358}
359
360zx_info_thread_t tu_thread_get_info(zx_handle_t thread)
361{
362    zx_info_thread_t info;
363    zx_status_t status = zx_object_get_info(thread, ZX_INFO_THREAD, &info, sizeof(info), NULL, NULL);
364    if (status < 0)
365        tu_fatal("zx_object_get_info(ZX_INFO_THREAD)", status);
366    return info;
367}
368
369uint32_t tu_thread_get_state(zx_handle_t thread)
370{
371    zx_info_thread_t info = tu_thread_get_info(thread);
372    return info.state;
373}
374
375bool tu_thread_is_dying_or_dead(zx_handle_t thread)
376{
377    zx_info_thread_t info = tu_thread_get_info(thread);
378    return (info.state == ZX_THREAD_STATE_DYING ||
379            info.state == ZX_THREAD_STATE_DEAD);
380}
381
382void tu_task_kill(zx_handle_t task)
383{
384    zx_status_t status = zx_task_kill(task);
385    if (status < 0)
386        tu_fatal("zx_task_kill", status);
387}
388
389int tu_run_program(const char *progname, int argc, const char** argv)
390{
391    launchpad_t* lp;
392
393    unittest_printf("%s: running %s\n", __func__, progname);
394
395    launchpad_create(ZX_HANDLE_INVALID, progname, &lp);
396    launchpad_clone(lp, LP_CLONE_ALL);
397    launchpad_load_from_file(lp, argv[0]);
398    launchpad_set_args(lp, argc, argv);
399    zx_status_t status;
400    zx_handle_t child;
401    if ((status = launchpad_go(lp, &child, NULL)) < 0) {
402        tu_fatal(__func__, status);
403    }
404
405    int rc = tu_process_wait_exit(child);
406    tu_handle_close(child);
407    unittest_printf("%s: child returned %d\n", __func__, rc);
408    return rc;
409}
410
411int tu_run_command(const char* progname, const char* cmd)
412{
413    const char* argv[] = {
414        "/boot/bin/sh",
415        "-c",
416        cmd
417    };
418
419    return tu_run_program(progname, countof(argv), argv);
420}
421