blob: 9e6461a86daf273f209919612da36807f85e6da8 [file] [log] [blame]
Keun Soo Yim08400372016-03-03 13:28:51 -08001/*
2 * Copyright (C) 2016 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 "specification_parser/SpecificationBuilder.h"
18
19#include <dirent.h>
20
21#include <iostream>
Keun Soo Yim2ee90792016-04-27 14:53:54 -070022#include <queue>
Keun Soo Yim08400372016-03-03 13:28:51 -080023#include <string>
24
25#include "fuzz_tester/FuzzerBase.h"
26#include "fuzz_tester/FuzzerWrapper.h"
27#include "specification_parser/InterfaceSpecificationParser.h"
28
Keun Soo Yimf5185852016-06-01 19:37:10 -070029#include "test/vts/runners/host/proto/InterfaceSpecificationMessage.pb.h"
Keun Soo Yim34067de2016-05-17 09:46:37 -070030#include <google/protobuf/text_format.h>
Keun Soo Yim08400372016-03-03 13:28:51 -080031
32namespace android {
33namespace vts {
34
Keun Soo Yim8103c912016-04-22 20:07:13 -070035SpecificationBuilder::SpecificationBuilder(
36 const string dir_path, int epoch_count)
37 : dir_path_(dir_path),
Keun Soo Yimfeceb4d2016-05-11 20:01:00 -070038 epoch_count_(epoch_count),
Keun Soo Yim34067de2016-05-17 09:46:37 -070039 if_spec_msg_(NULL),
40 module_name_(NULL) {}
Keun Soo Yim08400372016-03-03 13:28:51 -080041
42
43vts::InterfaceSpecificationMessage*
44SpecificationBuilder::FindInterfaceSpecification(
45 const int target_class,
46 const int target_type,
Keun Soo Yim2ee90792016-04-27 14:53:54 -070047 const float target_version,
48 const string submodule_name) {
Keun Soo Yim08400372016-03-03 13:28:51 -080049 DIR* dir;
50 struct dirent* ent;
51
52 if (!(dir = opendir(dir_path_.c_str()))) {
53 cerr << __FUNCTION__ << ": Can't opendir " << dir_path_ << endl;
54 return NULL;
55 }
56
57 while ((ent = readdir(dir))) {
58 if (string(ent->d_name).find(SPEC_FILE_EXT) != std::string::npos) {
59 cout << __FUNCTION__ << ": Checking a file " << ent->d_name << endl;
60 const string file_path = string(dir_path_) + "/" + string(ent->d_name);
61 vts::InterfaceSpecificationMessage* message =
62 new vts::InterfaceSpecificationMessage();
63 if (InterfaceSpecificationParser::parse(file_path.c_str(), message)) {
Keun Soo Yim2ee90792016-04-27 14:53:54 -070064 if (message->component_type() == target_type
Keun Soo Yim08400372016-03-03 13:28:51 -080065 && message->component_type_version() == target_version) {
Keun Soo Yim2ee90792016-04-27 14:53:54 -070066 if (submodule_name.length() > 0) {
67 if (message->component_class() != HAL_SUBMODULE
68 || message->original_data_structure_name() != submodule_name) {
69 continue;
70 }
71 } else if (message->component_class() != target_class) continue;
Keun Soo Yim08400372016-03-03 13:28:51 -080072 closedir(dir);
73 return message;
74 }
75 }
76 delete message;
77 }
78 }
79 closedir(dir);
80 return NULL;
81}
82
83
Keun Soo Yim52f51662016-05-12 17:23:24 -070084FuzzerBase* SpecificationBuilder::GetFuzzerBase(
85 const vts::InterfaceSpecificationMessage& iface_spec_msg,
86 const char* dll_file_name,
87 const char* target_func_name) {
Keun Soo Yim6d944952016-05-31 16:30:56 -070088 cout << __func__ << ":" << __LINE__ << " " << "entry" << endl;
Keun Soo Yim52f51662016-05-12 17:23:24 -070089 FuzzerBase* fuzzer = wrapper_.GetFuzzer(iface_spec_msg);
90 if (!fuzzer) {
91 cerr << __FUNCTION__ << ": couldn't get a fuzzer base class" << endl;
92 return NULL;
93 }
Keun Soo Yim6d944952016-05-31 16:30:56 -070094
95 // TODO: don't load multiple times. reuse FuzzerBase*.
96 cout << __func__ << ":" << __LINE__ << " " << "got fuzzer" << endl;
97 if (!fuzzer->LoadTargetComponent(dll_file_name)) {
Keun Soo Yim34067de2016-05-17 09:46:37 -070098 cerr << __FUNCTION__ << ": couldn't load target component file, "
99 << dll_file_name << endl;
Keun Soo Yim072337b2016-05-13 15:58:26 -0700100 return NULL;
101 }
Keun Soo Yim6d944952016-05-31 16:30:56 -0700102 cout << __func__ << ":" << __LINE__ << " " << "loaded target comp" << endl;
103
Keun Soo Yim91d634a2016-06-02 11:38:00 -0700104 return fuzzer;
105 /*
106 * TODO: now always return the fuzzer. this change is due to the difficulty
107 * in checking nested apis although that's possible. need to check whether
108 * Fuzz() found the function, while still distinguishing the difference
109 * between that and defined but non-set api.
Keun Soo Yim6d944952016-05-31 16:30:56 -0700110 if (!strcmp(target_func_name, "#Open")) return fuzzer;
Keun Soo Yim52f51662016-05-12 17:23:24 -0700111
112 for (const vts::FunctionSpecificationMessage& func_msg : iface_spec_msg.api()) {
Keun Soo Yim072337b2016-05-13 15:58:26 -0700113 cout << "checking " << func_msg.name() << endl;
Keun Soo Yim52f51662016-05-12 17:23:24 -0700114 if (!strcmp(target_func_name, func_msg.name().c_str())) {
115 return fuzzer;
116 }
117 }
118 return NULL;
Keun Soo Yim91d634a2016-06-02 11:38:00 -0700119 */
Keun Soo Yim52f51662016-05-12 17:23:24 -0700120}
121
122
Keun Soo Yim2ee90792016-04-27 14:53:54 -0700123FuzzerBase* SpecificationBuilder::GetFuzzerBaseAndAddAllFunctionsToQueue(
124 const vts::InterfaceSpecificationMessage& iface_spec_msg,
125 const char* dll_file_name) {
126 FuzzerBase* fuzzer = wrapper_.GetFuzzer(iface_spec_msg);
127 if (!fuzzer) {
128 cerr << __FUNCTION__ << ": couldn't get a fuzzer base class" << endl;
129 return NULL;
130 }
131 if (!fuzzer->LoadTargetComponent(dll_file_name)) return NULL;
132
133 for (const vts::FunctionSpecificationMessage& func_msg : iface_spec_msg.api()) {
134 cout << "Add a job " << func_msg.name() << endl;
135 FunctionSpecificationMessage* func_msg_copy = func_msg.New();
136 func_msg_copy->CopyFrom(func_msg);
137 job_queue_.push(make_pair(func_msg_copy, fuzzer));
138 }
139 return fuzzer;
140}
141
142
Keun Soo Yimfeceb4d2016-05-11 20:01:00 -0700143bool SpecificationBuilder::LoadTargetComponent(
144 const char* dll_file_name,
145 const char* spec_lib_file_path,
146 int target_class,
147 int target_type,
Keun Soo Yim34067de2016-05-17 09:46:37 -0700148 float target_version,
149 const char* module_name) {
Keun Soo Yimfeceb4d2016-05-11 20:01:00 -0700150 if_spec_msg_ = FindInterfaceSpecification(
151 target_class, target_type, target_version);
152 if (!if_spec_msg_) {
153 cerr << __FUNCTION__ <<
154 ": no interface specification file found for "
155 << "class " << target_class
156 << " type " << target_type
157 << " version " << target_version << endl;
158 return false;
159 }
Keun Soo Yim52f51662016-05-12 17:23:24 -0700160 spec_lib_file_path_ = (char*) malloc(strlen(spec_lib_file_path) + 1);
161 strcpy(spec_lib_file_path_, spec_lib_file_path);
162
163 dll_file_name_ = (char*) malloc(strlen(dll_file_name) + 1);
164 strcpy(dll_file_name_, dll_file_name);
165
Keun Soo Yim8e07a092016-05-04 16:30:35 -0700166 // cout << "ifspec addr load at " << if_spec_msg_ << endl;
Keun Soo Yimfeceb4d2016-05-11 20:01:00 -0700167 string output;
168 if_spec_msg_->SerializeToString(&output);
Keun Soo Yim8e07a092016-05-04 16:30:35 -0700169 cout << "loaded ifspec length " << output.length() << endl;
170 // cout << "loaded text " << strlen(output.c_str()) << endl;
171 // cout << "loaded text " << output << endl;
Keun Soo Yim34067de2016-05-17 09:46:37 -0700172
173 module_name_ = (char*) malloc(strlen(module_name) + 1);
174 strcpy(module_name_, module_name);
Keun Soo Yim8e07a092016-05-04 16:30:35 -0700175 cout << __FUNCTION__ << ":" << __LINE__ << " module_name " << module_name_
176 << endl;
Keun Soo Yimfeceb4d2016-05-11 20:01:00 -0700177 return true;
178}
179
180
Keun Soo Yim34067de2016-05-17 09:46:37 -0700181const string empty_string = string();
182
Keun Soo Yim04431a92016-05-24 16:26:42 -0700183const string& SpecificationBuilder::CallFunction(
184 FunctionSpecificationMessage* func_msg) {
Keun Soo Yim52f51662016-05-12 17:23:24 -0700185 if (!wrapper_.LoadInterfaceSpecificationLibrary(spec_lib_file_path_)) {
Keun Soo Yim34067de2016-05-17 09:46:37 -0700186 return empty_string;
Keun Soo Yim52f51662016-05-12 17:23:24 -0700187 }
Keun Soo Yim7ad64922016-06-07 18:14:40 -0700188 cout << __func__ << " " << "loaded if_spec lib" << endl;
189 cout << __func__ << " " << dll_file_name_ << " " << func_msg->name() << endl;
Keun Soo Yim52f51662016-05-12 17:23:24 -0700190
191 FuzzerBase* func_fuzzer = GetFuzzerBase(
192 *if_spec_msg_, dll_file_name_, func_msg->name().c_str());
Keun Soo Yim6d944952016-05-31 16:30:56 -0700193 cout << __func__ << ":" << __LINE__ << endl;
Keun Soo Yim52f51662016-05-12 17:23:24 -0700194 if (!func_fuzzer) {
Keun Soo Yim072337b2016-05-13 15:58:26 -0700195 cerr << "can't find FuzzerBase for " << func_msg->name() << " using "
196 << dll_file_name_ << endl;
Keun Soo Yim34067de2016-05-17 09:46:37 -0700197 return empty_string;
Keun Soo Yim52f51662016-05-12 17:23:24 -0700198 }
199
Keun Soo Yim6d944952016-05-31 16:30:56 -0700200 if (func_msg->name() == "#Open") {
201 cout << __func__ << ":" << __LINE__ << endl;
202 if (func_msg->arg().size() > 0) {
203 cout << __func__ << " " << func_msg->arg(0).primitive_value(0).bytes().c_str() << endl;
204 func_fuzzer->OpenConventionalHal(
205 func_msg->arg(0).primitive_value(0).bytes().c_str());
206 } else {
207 cout << __func__ << " no arg" << endl;
208 func_fuzzer->OpenConventionalHal();
209 }
210 cout << __func__ << " opened" << endl;
211 // return the return value from open;
212 if (func_msg->return_type().primitive_type().size() > 0) {
Keun Soo Yim91d634a2016-06-02 11:38:00 -0700213 cout << __func__ << " return_type exists" << endl;
Keun Soo Yim6d944952016-05-31 16:30:56 -0700214 // TODO handle when the size > 1.
215 if (!strcmp(func_msg->return_type().primitive_type(0).c_str(), "int32_t")) {
Keun Soo Yim91d634a2016-06-02 11:38:00 -0700216 cout << __func__ << " return_type is int32_t" << endl;
Keun Soo Yim6d944952016-05-31 16:30:56 -0700217 func_msg->mutable_return_type()->mutable_primitive_value()->Add()->set_int32_t(0);
218 cout << "result " << endl;
219 // todo handle more types;
220 string* output = new string();
221 google::protobuf::TextFormat::PrintToString(*func_msg, output);
222 return *output;
223 }
224 }
Keun Soo Yim91d634a2016-06-02 11:38:00 -0700225 cerr << __func__ << " return_type unknown" << endl;
226 string* output = new string();
227 google::protobuf::TextFormat::PrintToString(*func_msg, output);
228 return *output;
Keun Soo Yim6d944952016-05-31 16:30:56 -0700229 }
230 cout << __func__ << ":" << __LINE__ << endl;
231
Keun Soo Yim52f51662016-05-12 17:23:24 -0700232 void* result;
Keun Soo Yim04431a92016-05-24 16:26:42 -0700233 func_fuzzer->FunctionCallBegin();
Keun Soo Yim6d944952016-05-31 16:30:56 -0700234 cout << __func__ << " Call Function " << func_msg->name() << endl;
Keun Soo Yimf5185852016-06-01 19:37:10 -0700235 if (!func_fuzzer->Fuzz(func_msg, &result)) {
Keun Soo Yim6d944952016-05-31 16:30:56 -0700236 cout << __func__ << " function not found - todo handle more explicitly" << endl;
237 return *(new string("error"));
238 }
239 cout << __func__ << ": called" << endl;
Keun Soo Yim04431a92016-05-24 16:26:42 -0700240
241 // set coverage data.
242 vector<unsigned>* coverage = func_fuzzer->FunctionCallEnd();
243 if (coverage && coverage->size() > 0) {
244 for (unsigned int index = 0; index < coverage->size(); index++) {
245 func_msg->mutable_coverage_data()->Add(coverage->at(index));
246 }
247 }
248
Keun Soo Yima8cf69a2016-05-18 18:11:37 -0700249 if (func_msg->return_type().aggregate_type().size() > 0) {
250 // TODO: actually handle this case.
Keun Soo Yim52f51662016-05-12 17:23:24 -0700251 if (result != NULL) {
252 // loads that interface spec and enqueues all functions.
Keun Soo Yim6d944952016-05-31 16:30:56 -0700253 cout << __func__ << " return type: "
Keun Soo Yima8cf69a2016-05-18 18:11:37 -0700254 << func_msg->return_type().aggregate_type(0) << endl;
Keun Soo Yim52f51662016-05-12 17:23:24 -0700255 } else {
Keun Soo Yim6d944952016-05-31 16:30:56 -0700256 cout << __func__ << " return value = NULL" << endl;
Keun Soo Yim52f51662016-05-12 17:23:24 -0700257 }
Keun Soo Yim6d944952016-05-31 16:30:56 -0700258 cerr << __func__ << " todo: support aggregate" << endl;
Keun Soo Yim04431a92016-05-24 16:26:42 -0700259 string* output = new string();
260 google::protobuf::TextFormat::PrintToString(*func_msg, output);
261 return *output;
Keun Soo Yima8cf69a2016-05-18 18:11:37 -0700262 } else if (func_msg->return_type().primitive_type().size() > 0) {
263 // TODO handle when the size > 1.
264 if (!strcmp(func_msg->return_type().primitive_type(0).c_str(), "int32_t")) {
265 func_msg->mutable_return_type()->mutable_primitive_value()->Add()->set_int32_t(
Keun Soo Yim34067de2016-05-17 09:46:37 -0700266 *((int*)(&result)));
267 cout << "result " << endl;
268 // todo handle more types;
269 string* output = new string();
Keun Soo Yim04431a92016-05-24 16:26:42 -0700270 google::protobuf::TextFormat::PrintToString(*func_msg, output);
Keun Soo Yim34067de2016-05-17 09:46:37 -0700271 return *output;
272 }
Keun Soo Yim52f51662016-05-12 17:23:24 -0700273 }
Keun Soo Yim34067de2016-05-17 09:46:37 -0700274 return *(new string("void"));
Keun Soo Yim52f51662016-05-12 17:23:24 -0700275}
276
277
Keun Soo Yim08400372016-03-03 13:28:51 -0800278bool SpecificationBuilder::Process(
279 const char* dll_file_name,
280 const char* spec_lib_file_path,
281 int target_class,
282 int target_type,
283 float target_version) {
284 vts::InterfaceSpecificationMessage* interface_specification_message =
285 FindInterfaceSpecification(target_class, target_type, target_version);
Keun Soo Yimfeceb4d2016-05-11 20:01:00 -0700286 cout << "ifspec addr " << interface_specification_message << endl;
287
Keun Soo Yim08400372016-03-03 13:28:51 -0800288 if (!interface_specification_message) {
289 cerr << __FUNCTION__ <<
290 ": no interface specification file found for "
291 << "class " << target_class
292 << " type " << target_type
293 << " version " << target_version << endl;
294 return false;
295 }
Keun Soo Yim08400372016-03-03 13:28:51 -0800296
Keun Soo Yim2ee90792016-04-27 14:53:54 -0700297 if (!wrapper_.LoadInterfaceSpecificationLibrary(spec_lib_file_path)) {
Keun Soo Yim08400372016-03-03 13:28:51 -0800298 return false;
299 }
Keun Soo Yim2ee90792016-04-27 14:53:54 -0700300
301 if (!GetFuzzerBaseAndAddAllFunctionsToQueue(
302 *interface_specification_message, dll_file_name)) return false;
303
Keun Soo Yim8103c912016-04-22 20:07:13 -0700304 for (int i = 0; i < epoch_count_; i++) {
Keun Soo Yim2ee90792016-04-27 14:53:54 -0700305 // by default, breath-first-searching is used.
306 if (job_queue_.empty()) {
307 cout << "no more job to process; stopping after epoch " << i << endl;
308 break;
309 }
310
311 pair<vts::FunctionSpecificationMessage*, FuzzerBase*> curr_job =
312 job_queue_.front();
313 job_queue_.pop();
314
315 vts::FunctionSpecificationMessage* func_msg = curr_job.first;
316 FuzzerBase* func_fuzzer = curr_job.second;
317
Keun Soo Yimc5d092a2016-04-28 16:51:56 +0000318 void* result;
Keun Soo Yim2ee90792016-04-27 14:53:54 -0700319 cout << "Iteration " << (i + 1) << " Function " << func_msg->name() << endl;
Keun Soo Yimf5185852016-06-01 19:37:10 -0700320 func_fuzzer->Fuzz(func_msg, &result);
Keun Soo Yima8cf69a2016-05-18 18:11:37 -0700321 if (func_msg->return_type().aggregate_type().size() > 0) {
Keun Soo Yim2ee90792016-04-27 14:53:54 -0700322 if (result != NULL) {
323 // loads that interface spec and enqueues all functions.
324 cout << __FUNCTION__ << " return type: "
Keun Soo Yima8cf69a2016-05-18 18:11:37 -0700325 << func_msg->return_type().aggregate_type(0) << endl;
326 // TODO: handle the case when size > 1
327 string submodule_name = func_msg->return_type().aggregate_type(0);
Keun Soo Yim2ee90792016-04-27 14:53:54 -0700328 while (!submodule_name.empty()
329 && (std::isspace(submodule_name.back())
Keun Soo Yima8cf69a2016-05-18 18:11:37 -0700330 || submodule_name.back() == '*')) {
Keun Soo Yim2ee90792016-04-27 14:53:54 -0700331 submodule_name.pop_back();
332 }
333 vts::InterfaceSpecificationMessage* iface_spec_msg =
334 FindInterfaceSpecification(
335 target_class, target_type, target_version, submodule_name);
336 if (iface_spec_msg) {
337 cout << __FUNCTION__ << " submodule found - " << submodule_name << endl;
338 if (!GetFuzzerBaseAndAddAllFunctionsToQueue(
339 *iface_spec_msg, dll_file_name)) {
340 return false;
341 }
342 } else {
343 cout << __FUNCTION__ << " submodule not found - " << submodule_name << endl;
344 }
345 } else {
346 cout << __FUNCTION__ << " return value = NULL" << endl;
347 }
348 }
Keun Soo Yim08400372016-03-03 13:28:51 -0800349 }
Keun Soo Yim2ee90792016-04-27 14:53:54 -0700350
Keun Soo Yim08400372016-03-03 13:28:51 -0800351 return true;
352}
353
Keun Soo Yimfeceb4d2016-05-11 20:01:00 -0700354
355vts::InterfaceSpecificationMessage*
356SpecificationBuilder::GetInterfaceSpecification() const {
357 cout << "ifspec addr get " << if_spec_msg_ << endl;
358 return if_spec_msg_;
359}
360
Keun Soo Yim08400372016-03-03 13:28:51 -0800361} // namespace vts
362} // namespace android