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, ©);
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