1 /*
2 * Copyright (C) 2023 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17 #define TLOG_TAG "cov-shm"
18
19 #include <lib/coverage/common/cov_shm.h>
20 #include <interface/line-coverage/aggregator.h>
21 #include <interface/line-coverage/client.h>
22 #include <lib/coverage/common/ipc.h>
23 #include <lib/line-coverage/shm.h>
24 #include <lib/tipc/tipc.h>
25 #include <lk/macros.h>
26 #include <lk/compiler.h>
27 #include <stdio.h>
28 #include <stdlib.h>
29 #include <string.h>
30 #include <sys/auxv.h>
31 #include <sys/mman.h>
32 #include <trusty/memref.h>
33 #include <trusty_log.h>
34 #include <uapi/err.h>
35
36 #ifdef UNITTEST_COVERAGE
37 #define PAGE_SIZE getauxval(AT_PAGESZ)
38 static struct cov_ctx ctx;
39 /*
40 This symbol is exported to each instrumented shared library and
41 exectuable to instruct the linker to skip loading the object which
42 contains the profiling runtime's static initialiser
43 */
44
45 int __llvm_profile_runtime;
46
47 /*
48 These functions have to be forward declared and then called
49 when we want profiling runtime without static initialisers
50 */
51 uint64_t __llvm_profile_get_size_for_buffer(void);
52 int __llvm_profile_write_buffer(char *Buffer);
53 void __llvm_profile_reset_counters(void);
54
dump_shm(void)55 void dump_shm(void) {
56 if (!cov_shm_is_mapped(&ctx.data)) {
57 return;
58 }
59 struct control *control = (struct control *)ctx.data.base;
60 uint64_t flags = READ_ONCE(control->cntrl_flags);
61 uint64_t read_cnt = READ_ONCE(control->read_buffer_cnt);
62 if ( ((flags & FLAG_RUN) != 0) && (read_cnt == control->write_buffer_start_count) ) {
63 uint64_t count = control->write_buffer_start_count + 1;
64 WRITE_ONCE(control->write_buffer_start_count, count);
65 __llvm_profile_write_buffer((char *)control + sizeof(struct control));
66 __llvm_profile_reset_counters();
67 WRITE_ONCE(control->write_buffer_complete_count, count);
68 }
69 }
70
setup_shm(void)71 int setup_shm(void) {
72 int rc;
73 handle_t memref;
74 struct coverage_aggregator_req cov_req;
75 struct coverage_aggregator_resp cov_resp;
76 size_t shm_len;
77
78 if(ctx.mailbox.base == NULL) {
79 // For aggregator and client, mailbox is expected to be NULL
80 // Skip print for such cases
81 if(!ctx.skip_mailbox) {
82 TLOGE("Mailbox not setup\n");
83 }
84 return -1;
85 }
86
87 int* app_mailbox = (int*)(ctx.mailbox.base) + ctx.idx;
88 int event = READ_ONCE(*app_mailbox);
89
90 if (event != COVERAGE_MAILBOX_RECORD_READY) {
91 TLOGE("NS memory not shared yet\n");
92 return -1;
93 }
94 if (cov_shm_is_mapped(&ctx.data)) {
95 TLOGD("SHM already setup\n");
96 return NO_ERROR;
97 }
98
99 memset(&cov_req, 0, sizeof(struct coverage_aggregator_req));
100 cov_req.hdr.cmd = COVERAGE_AGGREGATOR_CMD_GET_RECORD;
101
102 rc = coverage_aggregator_rpc(ctx.coverage_srv, &cov_req, NULL, &cov_resp, &memref);
103 if (rc != NO_ERROR) {
104 TLOGE("failed (%d) coverage aggregator RPC\n", rc);
105 return rc;
106 }
107 shm_len = cov_resp.get_record_args.shm_len;
108
109 if (shm_len < ctx.record_len) {
110 TLOGE("not enough shared memory, received: %zu, need at least: %zu\n",
111 shm_len, ctx.record_len);
112 rc = ERR_BAD_LEN;
113 return rc;
114 }
115
116 rc = cov_shm_mmap(&ctx.data, memref, cov_resp.get_record_args.shm_len);
117 if (rc != NO_ERROR) {
118 TLOGE("failed to mmap() coverage record shared memory\n");
119 return rc;
120 }
121 return NO_ERROR;
122 }
123
setup_mailbox(const struct tipc_port * ports,uint32_t num_ports)124 int setup_mailbox(const struct tipc_port* ports, uint32_t num_ports) {
125 uint64_t buf_len = __llvm_profile_get_size_for_buffer();
126 int rc;
127 uint32_t i;
128 handle_t chan;
129 handle_t memref;
130 struct coverage_aggregator_req req;
131 struct coverage_aggregator_resp resp;
132
133 ctx.skip_mailbox = false;
134
135 for (i = 0; i < num_ports; i++) {
136 // Skip for coverage aggregator and client
137 if (strcmp(ports[i].name, LINE_COVERAGE_AGGREGATOR_PORT) == 0 ||
138 strcmp(ports[i].name, LINE_COVERAGE_CLIENT_PORT) == 0) {
139 ctx.skip_mailbox = true;
140 ctx.coverage_srv = INVALID_IPC_HANDLE;
141 ctx.mailbox.base = NULL;
142 return -1;
143 }
144 }
145
146 rc = tipc_connect(&chan, LINE_COVERAGE_AGGREGATOR_PORT);
147 if (rc != NO_ERROR) {
148 TLOGE("failed (%d) to connect to coverage aggregator service\n", rc);
149 return rc;
150 }
151
152 memset(&req, 0, sizeof(struct coverage_aggregator_req));
153 req.hdr.cmd = COVERAGE_AGGREGATOR_CMD_REGISTER;
154 req.register_args.record_len = round_up(buf_len + sizeof(struct control), PAGE_SIZE);
155
156 rc = coverage_aggregator_rpc(chan, &req, NULL, &resp, &memref);
157 if (rc != NO_ERROR) {
158 TLOGE("sys_state: failed (%d) coverage aggregator RPC\n", rc);
159 close(chan);
160 return rc;
161 }
162
163 rc = cov_shm_mmap(&(ctx.mailbox), memref, resp.register_args.mailbox_len);
164 if (rc != NO_ERROR) {
165 TLOGE("failed to mmap() mailbox shared memory\n");
166 close(memref);
167 close(chan);
168 return rc;
169 }
170
171 ctx.record_len = buf_len + sizeof(struct control);
172 ctx.coverage_srv = chan;
173 ctx.idx = resp.register_args.idx;
174
175 close(memref);
176 return NO_ERROR;
177 }
178
179 #else
dump_shm(void)180 void dump_shm(void) {
181 return;
182 }
183
setup_shm(void)184 int setup_shm(void) {
185 return NO_ERROR;
186 }
187
setup_mailbox(const struct tipc_port * ports,uint32_t num_ports)188 int setup_mailbox(const struct tipc_port* ports, uint32_t num_ports) {
189 return NO_ERROR;
190 }
191 #endif
192