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. 16struct 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 23struct 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 30crash_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 47void 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 81zx_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 101zx_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 124bool 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