blob: 5eccdc503d4337bc40e8f2279abb2ace0bf04932 [file] [log] [blame]
Tri Vo5b40e892020-11-01 13:01:29 -08001/*
2 * Copyright (C) 2020 The Android Open Sourete 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 LOG_TAG "coverage"
18
Stephen Crane0d671312021-01-13 14:05:41 -080019#include <BufferAllocator/BufferAllocator.h>
Stephen Cranee9629302020-11-16 18:00:53 -080020#include <android-base/file.h>
Tri Vo5b40e892020-11-01 13:01:29 -080021#include <android-base/logging.h>
22#include <android-base/unique_fd.h>
23#include <assert.h>
Stephen Crane6bd77df2021-01-13 14:05:41 -080024#include <log/log.h>
Stephen Cranee9629302020-11-16 18:00:53 -080025#include <stdio.h>
Tri Vo5b40e892020-11-01 13:01:29 -080026#include <sys/mman.h>
27#include <sys/uio.h>
28#include <trusty/coverage/coverage.h>
Stephen Cranee9629302020-11-16 18:00:53 -080029#include <trusty/coverage/record.h>
Tri Vo5b40e892020-11-01 13:01:29 -080030#include <trusty/coverage/tipc.h>
31#include <trusty/tipc.h>
32
33#define COVERAGE_CLIENT_PORT "com.android.trusty.coverage.client"
34
35namespace android {
36namespace trusty {
37namespace coverage {
38
39using android::base::ErrnoError;
40using android::base::Error;
41using std::string;
Tri Vo315967e2021-01-14 18:39:19 -080042using std::to_string;
Stephen Crane6bd77df2021-01-13 14:05:41 -080043using std::unique_ptr;
Tri Vo5b40e892020-11-01 13:01:29 -080044
45static inline uintptr_t RoundPageUp(uintptr_t val) {
46 return (val + (PAGE_SIZE - 1)) & ~(PAGE_SIZE - 1);
47}
48
49CoverageRecord::CoverageRecord(string tipc_dev, struct uuid* uuid)
50 : tipc_dev_(std::move(tipc_dev)),
51 coverage_srv_fd_(-1),
52 uuid_(*uuid),
Stephen Crane6bd77df2021-01-13 14:05:41 -080053 sancov_filename_(),
54 record_len_(0),
55 shm_(NULL),
56 shm_len_(0) {}
57
Tri Vo315967e2021-01-14 18:39:19 -080058CoverageRecord::CoverageRecord(string tipc_dev, struct uuid* uuid, string module_name)
Stephen Crane6bd77df2021-01-13 14:05:41 -080059 : tipc_dev_(std::move(tipc_dev)),
60 coverage_srv_fd_(-1),
61 uuid_(*uuid),
Tri Vo315967e2021-01-14 18:39:19 -080062 sancov_filename_(module_name + "." + to_string(getpid()) + ".sancov"),
Tri Vo5b40e892020-11-01 13:01:29 -080063 record_len_(0),
64 shm_(NULL),
65 shm_len_(0) {}
66
67CoverageRecord::~CoverageRecord() {
68 if (shm_) {
Stephen Crane6bd77df2021-01-13 14:05:41 -080069 if (sancov_filename_) {
70 auto res = SaveSancovFile(*sancov_filename_);
71 if (!res.ok()) {
72 ALOGE("Could not write sancov file for module: %s\n", sancov_filename_->c_str());
73 }
74 }
75
Tri Vo5b40e892020-11-01 13:01:29 -080076 munmap((void*)shm_, shm_len_);
77 }
78}
79
80Result<void> CoverageRecord::Rpc(coverage_client_req* req, int req_fd, coverage_client_resp* resp) {
81 int rc;
82
83 if (req_fd < 0) {
84 rc = write(coverage_srv_fd_, req, sizeof(*req));
85 } else {
86 iovec iov = {
87 .iov_base = req,
88 .iov_len = sizeof(*req),
89 };
90
91 trusty_shm shm = {
92 .fd = req_fd,
93 .transfer = TRUSTY_SHARE,
94 };
95
96 rc = tipc_send(coverage_srv_fd_, &iov, 1, &shm, 1);
97 }
98
99 if (rc != (int)sizeof(*req)) {
100 return ErrnoError() << "failed to send request to coverage server: ";
101 }
102
103 rc = read(coverage_srv_fd_, resp, sizeof(*resp));
104 if (rc != (int)sizeof(*resp)) {
105 return ErrnoError() << "failed to read reply from coverage server: ";
106 }
107
108 if (resp->hdr.cmd != (req->hdr.cmd | COVERAGE_CLIENT_CMD_RESP_BIT)) {
109 return ErrnoError() << "unknown response cmd: " << resp->hdr.cmd;
110 }
111
112 return {};
113}
114
115Result<void> CoverageRecord::Open() {
116 coverage_client_req req;
117 coverage_client_resp resp;
118
119 if (shm_) {
120 return {}; /* already initialized */
121 }
122
123 int fd = tipc_connect(tipc_dev_.c_str(), COVERAGE_CLIENT_PORT);
124 if (fd < 0) {
125 return ErrnoError() << "failed to connect to Trusty coverarge server: ";
126 }
127 coverage_srv_fd_.reset(fd);
128
129 req.hdr.cmd = COVERAGE_CLIENT_CMD_OPEN;
130 req.open_args.uuid = uuid_;
131 auto ret = Rpc(&req, -1, &resp);
132 if (!ret.ok()) {
133 return Error() << "failed to open coverage client: ";
134 }
135 record_len_ = resp.open_args.record_len;
136 shm_len_ = RoundPageUp(record_len_);
137
Stephen Crane0d671312021-01-13 14:05:41 -0800138 BufferAllocator allocator;
139
140 fd = allocator.Alloc("system", shm_len_);
Tri Vo5b40e892020-11-01 13:01:29 -0800141 if (fd < 0) {
Stephen Crane0d671312021-01-13 14:05:41 -0800142 return ErrnoError() << "failed to create dmabuf of size " << shm_len_
143 << " err code: " << fd;
Tri Vo5b40e892020-11-01 13:01:29 -0800144 }
Stephen Crane0d671312021-01-13 14:05:41 -0800145 unique_fd dma_buf(fd);
Tri Vo5b40e892020-11-01 13:01:29 -0800146
Stephen Crane0d671312021-01-13 14:05:41 -0800147 void* shm = mmap(0, shm_len_, PROT_READ | PROT_WRITE, MAP_SHARED, dma_buf, 0);
Tri Vo5b40e892020-11-01 13:01:29 -0800148 if (shm == MAP_FAILED) {
149 return ErrnoError() << "failed to map memfd: ";
150 }
151
152 req.hdr.cmd = COVERAGE_CLIENT_CMD_SHARE_RECORD;
153 req.share_record_args.shm_len = shm_len_;
Stephen Crane0d671312021-01-13 14:05:41 -0800154 ret = Rpc(&req, dma_buf, &resp);
Tri Vo5b40e892020-11-01 13:01:29 -0800155 if (!ret.ok()) {
156 return Error() << "failed to send shared memory: ";
157 }
158
159 shm_ = shm;
160 return {};
161}
162
Stephen Cranee9629302020-11-16 18:00:53 -0800163void CoverageRecord::ResetFullRecord() {
164 auto header_region = GetRegionBounds(COV_START);
Bernie Innocenti62ba2b12020-12-19 21:17:16 +0900165 if (!header_region.ok()) {
Stephen Cranee9629302020-11-16 18:00:53 -0800166 // If the header cannot be parsed, we can't reset the proper region yet.
167 return;
168 }
169
170 for (size_t i = header_region->second; i < shm_len_; i++) {
Tri Vo5b40e892020-11-01 13:01:29 -0800171 *((volatile uint8_t*)shm_ + i) = 0;
172 }
173}
174
Stephen Cranee9629302020-11-16 18:00:53 -0800175void CoverageRecord::ResetCounts() {
176 volatile uint8_t* begin = nullptr;
177 volatile uint8_t* end = nullptr;
178 GetRawCounts(&begin, &end);
179
180 for (volatile uint8_t* x = begin; x < end; x++) {
181 *x = 0;
182 }
183}
184
185void CoverageRecord::ResetPCs() {
186 volatile uintptr_t* begin = nullptr;
187 volatile uintptr_t* end = nullptr;
188 GetRawPCs(&begin, &end);
189
190 for (volatile uintptr_t* x = begin; x < end; x++) {
191 *x = 0;
192 }
193}
194
195Result<std::pair<size_t, size_t>> CoverageRecord::GetRegionBounds(uint32_t region_type) {
196 assert(shm_);
197
198 auto header = (volatile struct coverage_record_header*)shm_;
199
200 if (header->type != COV_START) {
201 return Error() << "Header not yet valid";
202 }
203
204 for (++header; header->type != COV_TOTAL_LENGTH; ++header) {
205 if (header->type == region_type) {
206 // Coverage record must end with a COV_TOTAL_LENGTH header entry, so
207 // it is always safe to read the next entry since we don't iterate
208 // over the COV_TOTAL_LENGTH entry.
209 return {{header->offset, (header + 1)->offset}};
210 }
211 }
212
213 return Error() << "Could not find coverage region type: " << region_type;
214}
215
Tri Vo5b40e892020-11-01 13:01:29 -0800216void CoverageRecord::GetRawData(volatile void** begin, volatile void** end) {
217 assert(shm_);
218
219 *begin = shm_;
220 *end = (uint8_t*)(*begin) + record_len_;
221}
222
Stephen Cranee9629302020-11-16 18:00:53 -0800223void CoverageRecord::GetRawCounts(volatile uint8_t** begin, volatile uint8_t** end) {
224 auto region = GetRegionBounds(COV_8BIT_COUNTERS);
Bernie Innocenti62ba2b12020-12-19 21:17:16 +0900225 if (!region.ok()) {
Stephen Cranee9629302020-11-16 18:00:53 -0800226 *begin = 0;
227 *end = 0;
228 return;
229 }
230
231 assert(region->second <= record_len_);
232
233 *begin = (volatile uint8_t*)shm_ + region->first;
234 *end = (volatile uint8_t*)shm_ + region->second;
235}
236
237void CoverageRecord::GetRawPCs(volatile uintptr_t** begin, volatile uintptr_t** end) {
238 auto region = GetRegionBounds(COV_INSTR_PCS);
Bernie Innocenti62ba2b12020-12-19 21:17:16 +0900239 if (!region.ok()) {
Stephen Cranee9629302020-11-16 18:00:53 -0800240 *begin = 0;
241 *end = 0;
242 return;
243 }
244
245 assert(region->second <= record_len_);
246
247 *begin = (volatile uintptr_t*)((volatile uint8_t*)shm_ + region->first);
248 *end = (volatile uintptr_t*)((volatile uint8_t*)shm_ + region->second);
249}
250
251uint64_t CoverageRecord::TotalEdgeCounts() {
Tri Vo5b40e892020-11-01 13:01:29 -0800252 assert(shm_);
253
254 uint64_t counter = 0;
255
256 volatile uint8_t* begin = NULL;
257 volatile uint8_t* end = NULL;
258
Stephen Cranee9629302020-11-16 18:00:53 -0800259 GetRawCounts(&begin, &end);
Tri Vo5b40e892020-11-01 13:01:29 -0800260
261 for (volatile uint8_t* x = begin; x < end; x++) {
262 counter += *x;
263 }
264
265 return counter;
266}
267
Stephen Cranee9629302020-11-16 18:00:53 -0800268Result<void> CoverageRecord::SaveSancovFile(const std::string& filename) {
269 android::base::unique_fd output_fd(TEMP_FAILURE_RETRY(creat(filename.c_str(), 00644)));
270 if (!output_fd.ok()) {
271 return ErrnoError() << "Could not open sancov file";
272 }
273
274 uint64_t magic;
275 if (sizeof(uintptr_t) == 8) {
276 magic = 0xC0BFFFFFFFFFFF64;
277 } else if (sizeof(uintptr_t) == 4) {
278 magic = 0xC0BFFFFFFFFFFF32;
279 }
280 WriteFully(output_fd, &magic, sizeof(magic));
281
282 volatile uintptr_t* begin = nullptr;
283 volatile uintptr_t* end = nullptr;
284
285 GetRawPCs(&begin, &end);
286
287 for (volatile uintptr_t* pc_ptr = begin; pc_ptr < end; pc_ptr++) {
288 uintptr_t pc = *pc_ptr;
289 if (pc) {
290 WriteFully(output_fd, &pc, sizeof(pc));
291 }
292 }
293
294 return {};
295}
296
Tri Vo5b40e892020-11-01 13:01:29 -0800297} // namespace coverage
298} // namespace trusty
299} // namespace android