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/backtrace-request/backtrace-request.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 
tu_malloc(size_t size)20 void* 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 
tu_calloc(size_t nmemb,size_t size)31 void* 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 
tu_strdup(const char * s)42 char* 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 
tu_asprintf(const char * fmt,...)50 char* 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 
tu_fatal(const char * what,zx_status_t status)63 void 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     backtrace_request();
72 
73     unittest_printf_critical("FATAL: exiting process\n");
74     exit(TU_FAIL_ERRCODE);
75 }
76 
tu_handle_close(zx_handle_t handle)77 void 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 
tu_handle_duplicate(zx_handle_t handle)86 zx_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 
tu_thread_create_c11(thrd_t * t,thrd_start_t entry,void * arg,const char * name)99 void 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 
tu_wait(uint32_t num_objects,const zx_handle_t * handles,const zx_signals_t * signals,zx_signals_t * pending)116 zx_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 
tu_channel_create(zx_handle_t * handle0,zx_handle_t * handle1)133 void 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 
tu_channel_write(zx_handle_t handle,uint32_t flags,const void * bytes,uint32_t num_bytes,const zx_handle_t * handles,uint32_t num_handles)142 void 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 
tu_channel_read(zx_handle_t handle,uint32_t flags,void * bytes,uint32_t * num_bytes,zx_handle_t * handles,uint32_t * num_handles)149 void 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 
tu_channel_wait_readable(zx_handle_t channel)158 bool 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 
tu_launch(zx_handle_t job,const char * name,int argc,const char * const * argv,const char * const * envp,size_t num_handles,zx_handle_t * handles,uint32_t * handle_ids)172 zx_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 
tu_launch_fdio_init(zx_handle_t job,const char * name,int argc,const char * const * argv,const char * const * envp,size_t hnds_count,zx_handle_t * handles,uint32_t * ids)194 launchpad_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 
tu_launch_fdio_fini(launchpad_t * lp)218 zx_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 
tu_process_wait_signaled(zx_handle_t process)227 void 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 
tu_process_has_exited(zx_handle_t process)240 bool 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 
tu_process_get_return_code(zx_handle_t process)250 int 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 
tu_process_wait_exit(zx_handle_t process)265 int 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 
tu_process_get_thread(zx_handle_t process,zx_koid_t tid)271 zx_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 
tu_process_get_threads(zx_handle_t process,zx_koid_t * threads,size_t max_threads)282 size_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 
tu_job_create(zx_handle_t job)293 zx_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 
tu_io_port_create(void)302 zx_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 
tu_set_exception_port(zx_handle_t handle,zx_handle_t eport,uint64_t key,uint32_t options)311 void 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 
tu_object_wait_async(zx_handle_t handle,zx_handle_t port,zx_signals_t signals)320 void 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 
tu_handle_get_basic_info(zx_handle_t handle,zx_info_handle_basic_t * info)329 void 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 
tu_get_koid(zx_handle_t handle)337 zx_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 
tu_get_related_koid(zx_handle_t handle)344 zx_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 
tu_get_thread(zx_handle_t proc,zx_koid_t tid)351 zx_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 
tu_thread_get_info(zx_handle_t thread)360 zx_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 
tu_thread_get_state(zx_handle_t thread)369 uint32_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 
tu_thread_is_dying_or_dead(zx_handle_t thread)375 bool 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 
tu_task_kill(zx_handle_t task)382 void 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 
tu_run_program(const char * progname,int argc,const char ** argv)389 int 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 
tu_run_command(const char * progname,const char * cmd)411 int 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