1 // Copyright 2017 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 "crash-list.h"
6
7 #include <stdlib.h>
8 #include <threads.h>
9
10 #include <unittest/unittest.h>
11 #include <zircon/listnode.h>
12 #include <zircon/status.h>
13 #include <zircon/syscalls/object.h>
14
15 // Details of process or thread registered as expected to crash.
16 struct crash_proc_t {
17 zx_handle_t handle;
18 zx_koid_t koid;
19 // Node stored in crash handler list.
20 list_node_t node;
21 };
22
23 struct crash_list {
24 // The list may be accessed by the main test thread and crash handler thread.
25 mtx_t mutex;
26 // Head of list containing crash_proc_t.
27 list_node_t should_crash_procs;
28 };
29
crash_list_new()30 crash_list_t crash_list_new() {
31 crash_list_t crash_list = static_cast<crash_list_t>(malloc(sizeof(struct crash_list)));
32 if (crash_list == nullptr) {
33 UNITTEST_FAIL_TRACEF("FATAL: could not malloc crash list\n");
34 exit(ZX_ERR_INTERNAL);
35 }
36 int ret = mtx_init(&crash_list->mutex, mtx_plain);
37 if (ret != thrd_success) {
38 UNITTEST_FAIL_TRACEF("FATAL: could not create crash list mutex : error %s\n",
39 zx_status_get_string(ret));
40 exit(ZX_ERR_INTERNAL);
41 }
42 crash_list->should_crash_procs =
43 (list_node_t)LIST_INITIAL_VALUE(crash_list->should_crash_procs);
44 return crash_list;
45 }
46
crash_list_register(crash_list_t crash_list,zx_handle_t handle)47 void crash_list_register(crash_list_t crash_list, zx_handle_t handle) {
48 if (crash_list == nullptr) {
49 UNITTEST_FAIL_TRACEF(
50 "FATAL: crash list was NULL, run test with RUN_TEST_ENABLE_CRASH_HANDLER\n");
51 exit(ZX_ERR_INTERNAL);
52 }
53 zx_info_handle_basic_t info;
54 zx_status_t status =
55 zx_object_get_info(handle, ZX_INFO_HANDLE_BASIC, &info, sizeof(info), nullptr, nullptr);
56 if (status != ZX_OK) {
57 UNITTEST_FAIL_TRACEF("FATAL: could not get handle info : error %s\n",
58 zx_status_get_string(status));
59 exit(ZX_ERR_INTERNAL);
60 }
61 zx_handle_t copy;
62 status = zx_handle_duplicate(handle, ZX_RIGHT_SAME_RIGHTS, ©);
63 if (status != ZX_OK) {
64 UNITTEST_FAIL_TRACEF("FATAL: could not duplicate handle : error %s\n",
65 zx_status_get_string(status));
66 exit(ZX_ERR_INTERNAL);
67 }
68 crash_proc_t* crash_proc = static_cast<crash_proc_t*>(malloc(sizeof(crash_proc_t)));
69 if (crash_list == nullptr) {
70 UNITTEST_FAIL_TRACEF("FATAL: could not malloc crash proc\n");
71 exit(ZX_ERR_INTERNAL);
72 }
73 crash_proc->handle = copy;
74 crash_proc->koid = info.koid;
75
76 mtx_lock(&crash_list->mutex);
77 list_add_head(&crash_list->should_crash_procs, &crash_proc->node);
78 mtx_unlock(&crash_list->mutex);
79 }
80
crash_list_lookup_koid(crash_list_t crash_list,zx_koid_t koid)81 zx_handle_t crash_list_lookup_koid(crash_list_t crash_list, zx_koid_t koid) {
82 if (crash_list == nullptr) {
83 UNITTEST_FAIL_TRACEF(
84 "FATAL: crash list was NULL, run test with RUN_TEST_ENABLE_CRASH_HANDLER\n");
85 exit(ZX_ERR_INTERNAL);
86 }
87 zx_handle_t proc = ZX_HANDLE_INVALID;
88 crash_proc_t* cur = nullptr;
89
90 mtx_lock(&crash_list->mutex);
91 list_for_every_entry (&crash_list->should_crash_procs, cur, crash_proc_t, node) {
92 if (cur->koid == koid) {
93 proc = cur->handle;
94 break;
95 }
96 }
97 mtx_unlock(&crash_list->mutex);
98 return proc;
99 }
100
crash_list_delete_koid(crash_list_t crash_list,zx_koid_t koid)101 zx_handle_t crash_list_delete_koid(crash_list_t crash_list, zx_koid_t koid) {
102 if (crash_list == nullptr) {
103 UNITTEST_FAIL_TRACEF(
104 "FATAL: crash list was NULL, run test with RUN_TEST_ENABLE_CRASH_HANDLER\n");
105 exit(ZX_ERR_INTERNAL);
106 }
107 zx_handle_t deleted_proc = ZX_HANDLE_INVALID;
108 crash_proc_t* cur = nullptr;
109 crash_proc_t* tmp = nullptr;
110
111 mtx_lock(&crash_list->mutex);
112 list_for_every_entry_safe (&crash_list->should_crash_procs, cur, tmp, crash_proc_t, node) {
113 if (cur->koid == koid) {
114 deleted_proc = cur->handle;
115 list_delete(&cur->node);
116 free(cur);
117 break;
118 }
119 }
120 mtx_unlock(&crash_list->mutex);
121 return deleted_proc;
122 }
123
crash_list_delete(crash_list_t crash_list)124 bool crash_list_delete(crash_list_t crash_list) {
125 if (crash_list == nullptr) {
126 UNITTEST_FAIL_TRACEF(
127 "FATAL: crash list was NULL, run test with RUN_TEST_ENABLE_CRASH_HANDLER\n");
128 exit(ZX_ERR_INTERNAL);
129 }
130 crash_proc_t* cur = nullptr;
131 crash_proc_t* tmp = nullptr;
132
133 bool deleted = false;
134 list_for_every_entry_safe (&crash_list->should_crash_procs, cur, tmp, crash_proc_t, node) {
135 zx_handle_close(cur->handle);
136 deleted = true;
137 list_delete(&cur->node);
138 free(cur);
139 }
140 mtx_destroy(&crash_list->mutex);
141 free(crash_list);
142 return deleted;
143 }
144