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 #include <android-base/stringprintf.h>
18 #include <array>
19 #include <getopt.h>
20 #include <inttypes.h>
21 #include <memory>
22 #include <stdbool.h>
23 #include <stdio.h>
24 #include <string.h>
25 #include <trusty/line-coverage/coverage.h>
26 #include <trusty/tipc.h>
27 #include <vector>
28 
29 #include "controller.h"
30 
31 #define READ_ONCE(x) (*((volatile __typeof__(x) *) &(x)))
32 #define WRITE_ONCE(x, val) (*((volatile __typeof__(val) *) &(x)) = (val))
33 
34 namespace android {
35 namespace trusty {
36 namespace controller {
37 
38 using ::android::trusty::line_coverage::CoverageRecord;
39 
run(std::string output_dir)40 void Controller::run(std::string output_dir) {
41     connectCoverageServer();
42     struct control *control;
43     uint64_t complete_cnt = 0, start_cnt = 0, flags;
44 
45     while(1) {
46         setUpShm();
47 
48         for (int index = 0; index < record_list_.size(); index++) {
49             control = (struct control *)record_list_[index]->getShm();
50             start_cnt = READ_ONCE((control->write_buffer_start_count));
51             complete_cnt = READ_ONCE(control->write_buffer_complete_count);
52             flags = READ_ONCE(control->cntrl_flags);
53 
54             if (complete_cnt != counters[index] && start_cnt == complete_cnt) {
55                 WRITE_ONCE(control->cntrl_flags, FLAG_NONE);
56                 std::string filename;
57                 filename = android::base::StringPrintf("/%s.%" PRIu64 ".profraw",
58                                                     uuid_list_[index].c_str(),
59                                                     counters[index]);
60                 filename.insert(0, output_dir);
61                 android::base::Result<void> res = record_list_[index]->SaveFile(filename);
62                 counters[index]++;
63                 WRITE_ONCE(control->read_buffer_cnt, counters[index]);
64             }
65             if(complete_cnt == counters[index] &&
66                 !(flags & FLAG_RUN)) {
67                 flags |= FLAG_RUN;
68                 WRITE_ONCE(control->cntrl_flags, flags);
69             }
70         }
71     }
72 }
73 
connectCoverageServer()74 void Controller::connectCoverageServer() {
75     coverage_srv_fd = tipc_connect(TIPC_DEV, LINE_COVERAGE_CLIENT_PORT);
76     if (coverage_srv_fd < 0) {
77         fprintf(stderr, \
78                 "Error: Failed to connect to Trusty coverage server: %d\n", coverage_srv_fd);
79         return;
80     }
81 }
82 
setUpShm()83 void Controller::setUpShm() {
84     struct line_coverage_client_req req;
85     struct line_coverage_client_resp resp;
86     uint32_t cur_index = record_list_.size();
87     struct uuid zero_uuid = {0, 0, 0, { 0 }};
88     char uuid_str[UUID_STR_SIZE];
89     req.hdr.cmd = LINE_COVERAGE_CLIENT_CMD_SEND_LIST;
90     int rc = write(coverage_srv_fd, &req, sizeof(req));
91         if (rc != (int)sizeof(req)) {
92             fprintf(stderr, "failed to send request to coverage server: %d\n", rc);
93             return;
94     }
95 
96     while(1) {
97         rc = read(coverage_srv_fd, &resp, sizeof(resp));
98         if (rc != (int)sizeof(resp)) {
99             fprintf(stderr, "failed to read reply from coverage server:: %d\n", rc);
100         }
101 
102         if (resp.hdr.cmd == (req.hdr.cmd | LINE_COVERAGE_CLIENT_CMD_RESP_BIT)) {
103             if (!memcmp(&resp.send_list_args.uuid, &zero_uuid, sizeof(struct uuid))) {
104                 break;
105             }
106             if(uuid_set_.find(resp.send_list_args.uuid) == uuid_set_.end()) {
107                 uuid_set_.insert(resp.send_list_args.uuid);
108                 sprintf(uuid_str,
109                     "%08" PRIx32 "-%04" PRIx16 "-%04" PRIx16 "-%02" PRIx8 "%02" PRIx8
110                     "-%02" PRIx8 "%02" PRIx8 "%02" PRIx8 "%02" PRIx8 "%02" PRIx8 "%02" PRIx8,
111                     resp.send_list_args.uuid.time_low,
112                     resp.send_list_args.uuid.time_mid,
113                     resp.send_list_args.uuid.time_hi_and_version,
114                     resp.send_list_args.uuid.clock_seq_and_node[0],
115                     resp.send_list_args.uuid.clock_seq_and_node[1],
116                     resp.send_list_args.uuid.clock_seq_and_node[2],
117                     resp.send_list_args.uuid.clock_seq_and_node[3],
118                     resp.send_list_args.uuid.clock_seq_and_node[4],
119                     resp.send_list_args.uuid.clock_seq_and_node[5],
120                     resp.send_list_args.uuid.clock_seq_and_node[6],
121                     resp.send_list_args.uuid.clock_seq_and_node[7]);
122                 uuid_list_.push_back(uuid_str);
123                 record_list_.push_back(std::make_unique<CoverageRecord>(TIPC_DEV,
124                                                                     &resp.send_list_args.uuid));
125                 counters.push_back(0);
126             }
127         }
128         else {
129             fprintf(stderr, "Unknown response header\n");
130         }
131         cur_index++;
132         req.hdr.cmd = LINE_COVERAGE_CLIENT_CMD_SEND_LIST;
133         req.send_list_args.index = cur_index;
134         int rc = write(coverage_srv_fd, &req, sizeof(req));
135         if (rc != (int)sizeof(req)) {
136             fprintf(stderr, "failed to send request to coverage server: %d\n", rc);
137         }
138     }
139 
140     for(int ind = 0 ; ind < record_list_.size() ; ind++) {
141         record_list_[ind]->Open(coverage_srv_fd);
142     }
143 }
144 
145 
146 }  // namespace controller
147 }  // namespace trusty
148 }  // namespace android
149 
main(int argc,char * argv[])150 int main(int argc, char* argv[]) {
151 
152     std::string optarg = "";
153     do {
154         int c;
155         c = getopt(argc, argv, "o");
156 
157         if (c == -1) {
158             break;
159         }
160 
161         switch (c) {
162         case 'o':
163             break;
164         default:
165             fprintf(stderr, "usage: %s -o [output_directory]\n", argv[0]);
166             exit(EXIT_FAILURE);
167         }
168     } while (1);
169 
170     if (argc > optind + 1) {
171         fprintf(stderr, "%s: too many arguments\n", argv[0]);
172         exit(EXIT_FAILURE);
173     }
174 
175     if (argc > optind) {
176         optarg = argv[optind];
177     }
178     if (optarg.size()==0) {
179         optarg = "data/local/tmp";
180     }
181 
182     android::trusty::controller::Controller cur;
183     cur.run(optarg);
184 
185     return EXIT_SUCCESS;
186 }