904 lines
34 KiB
C++
904 lines
34 KiB
C++
/*
|
|
* Copyright 2016 The Android Open Source Project
|
|
*
|
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
* you may not use this file except in compliance with the License.
|
|
* You may obtain a copy of the License at
|
|
*
|
|
* http://www.apache.org/licenses/LICENSE-2.0
|
|
*
|
|
* Unless required by applicable law or agreed to in writing, software
|
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
* See the License for the specific language governing permissions and
|
|
* limitations under the License.
|
|
*/
|
|
|
|
#include "code_gen/driver/HalCodeGen.h"
|
|
|
|
#include <iostream>
|
|
#include <string>
|
|
|
|
#include "VtsCompilerUtils.h"
|
|
#include "test/vts/proto/ComponentSpecificationMessage.pb.h"
|
|
#include "utils/InterfaceSpecUtil.h"
|
|
#include "utils/StringUtil.h"
|
|
|
|
using namespace std;
|
|
using namespace android;
|
|
|
|
namespace android {
|
|
namespace vts {
|
|
|
|
const char* const HalCodeGen::kInstanceVariableName = "device_";
|
|
|
|
void HalCodeGen::GenerateCppBodyInterfaceImpl(
|
|
Formatter& out, const ComponentSpecificationMessage& message,
|
|
const string& fuzzer_extended_class_name) {
|
|
bool first_callback = true;
|
|
|
|
for (int i = 0; i < message.interface().attribute_size(); i++) {
|
|
const VariableSpecificationMessage& attribute = message.interface().attribute(i);
|
|
if (attribute.type() != TYPE_FUNCTION_POINTER || !attribute.is_callback()) {
|
|
continue;
|
|
}
|
|
string name =
|
|
"vts_callback_" + fuzzer_extended_class_name + "_" + attribute.name();
|
|
if (first_callback) {
|
|
out << "static string callback_socket_name_;" << "\n";
|
|
first_callback = false;
|
|
}
|
|
out << "\n";
|
|
out << "class " << name << " : public DriverCallbackBase {"
|
|
<< "\n";
|
|
out << " public:" << "\n";
|
|
out.indent();
|
|
out << name << "(const string& callback_socket_name) {" << "\n";
|
|
out.indent();
|
|
out << "callback_socket_name_ = callback_socket_name;" << "\n";
|
|
out.unindent();
|
|
out << "}" << "\n";
|
|
|
|
int primitive_format_index = 0;
|
|
for (const FunctionPointerSpecificationMessage& func_pt_spec :
|
|
attribute.function_pointer()) {
|
|
const string& callback_name = func_pt_spec.function_name();
|
|
// TODO: callback's return value is assumed to be 'void'.
|
|
out << "\n";
|
|
out << "static ";
|
|
bool has_return_value = false;
|
|
if (!func_pt_spec.has_return_type() ||
|
|
!func_pt_spec.return_type().has_type() ||
|
|
func_pt_spec.return_type().type() == TYPE_VOID) {
|
|
out << "void" << "\n";
|
|
} else if (func_pt_spec.return_type().type() == TYPE_PREDEFINED) {
|
|
out << func_pt_spec.return_type().predefined_type();
|
|
has_return_value = true;
|
|
} else {
|
|
cerr << __func__ << ":" << __LINE__ << " ERROR unknown type "
|
|
<< func_pt_spec.return_type().type() << "\n";
|
|
exit(-1);
|
|
}
|
|
out << " " << callback_name << "(";
|
|
int primitive_type_index;
|
|
primitive_type_index = 0;
|
|
for (const auto& arg : func_pt_spec.arg()) {
|
|
if (primitive_type_index != 0) {
|
|
out << ", ";
|
|
}
|
|
if (arg.is_const()) {
|
|
out << "const ";
|
|
}
|
|
if (arg.type() == TYPE_SCALAR) {
|
|
/*
|
|
if (arg.scalar_type() == "pointer") {
|
|
out << definition.aggregate_value(
|
|
primitive_format_index).primitive_name(primitive_type_index)
|
|
<< " ";
|
|
} */
|
|
if (arg.scalar_type() == "char_pointer") {
|
|
out << "char* ";
|
|
} else if (arg.scalar_type() == "uchar_pointer") {
|
|
out << "unsigned char* ";
|
|
} else if (arg.scalar_type() == "bool_t") {
|
|
out << "bool ";
|
|
} else if (arg.scalar_type() == "int8_t" ||
|
|
arg.scalar_type() == "uint8_t" ||
|
|
arg.scalar_type() == "int16_t" ||
|
|
arg.scalar_type() == "uint16_t" ||
|
|
arg.scalar_type() == "int32_t" ||
|
|
arg.scalar_type() == "uint32_t" ||
|
|
arg.scalar_type() == "size_t" ||
|
|
arg.scalar_type() == "int64_t" ||
|
|
arg.scalar_type() == "uint64_t") {
|
|
out << arg.scalar_type() << " ";
|
|
} else if (arg.scalar_type() == "void_pointer") {
|
|
out << "void*";
|
|
} else {
|
|
cerr << __func__ << " unsupported scalar type " << arg.scalar_type()
|
|
<< "\n";
|
|
exit(-1);
|
|
}
|
|
} else if (arg.type() == TYPE_PREDEFINED) {
|
|
out << arg.predefined_type() << " ";
|
|
} else {
|
|
cerr << __func__ << " unsupported type" << "\n";
|
|
exit(-1);
|
|
}
|
|
out << "arg" << primitive_type_index;
|
|
primitive_type_index++;
|
|
}
|
|
out << ") {" << "\n";
|
|
out.indent();
|
|
#if USE_VAARGS
|
|
out << " const char fmt[] = \""
|
|
<< definition.primitive_format(primitive_format_index) << "\";"
|
|
<< "\n";
|
|
out << " va_list argp;" << "\n";
|
|
out << " const char* p;" << "\n";
|
|
out << " int i;" << "\n";
|
|
out << " char* s;" << "\n";
|
|
out << " char fmtbuf[256];" << "\n";
|
|
out << "\n";
|
|
out << " va_start(argp, fmt);" << "\n";
|
|
out << "\n";
|
|
out << " for (p = fmt; *p != '\\0'; p++) {" << "\n";
|
|
out << " if (*p != '%') {" << "\n";
|
|
out << " putchar(*p);" << "\n";
|
|
out << " continue;" << "\n";
|
|
out << " }" << "\n";
|
|
out << " switch (*++p) {" << "\n";
|
|
out << " case 'c':" << "\n";
|
|
out << " i = va_arg(argp, int);" << "\n";
|
|
out << " putchar(i);" << "\n";
|
|
out << " break;" << "\n";
|
|
out << " case 'd':" << "\n";
|
|
out << " i = va_arg(argp, int);" << "\n";
|
|
out << " s = itoa(i, fmtbuf, 10);" << "\n";
|
|
out << " fputs(s, stdout);" << "\n";
|
|
out << " break;" << "\n";
|
|
out << " case 's':" << "\n";
|
|
out << " s = va_arg(argp, char *);" << "\n";
|
|
out << " fputs(s, stdout);" << "\n";
|
|
out << " break;" << "\n";
|
|
// out << " case 'p':
|
|
out << " case '%':" << "\n";
|
|
out << " putchar('%');" << "\n";
|
|
out << " break;" << "\n";
|
|
out << " }" << "\n";
|
|
out << " }" << "\n";
|
|
out << " va_end(argp);" << "\n";
|
|
#endif
|
|
// TODO: check whether bytes is set and handle properly if not.
|
|
out << "AndroidSystemCallbackRequestMessage callback_message;"
|
|
<< "\n";
|
|
out << "callback_message.set_id(GetCallbackID(\"" << callback_name
|
|
<< "\"));" << "\n";
|
|
|
|
primitive_type_index = 0;
|
|
for (const auto& arg : func_pt_spec.arg()) {
|
|
out << "VariableSpecificationMessage* var_msg" << primitive_type_index
|
|
<< " = callback_message.add_arg();" << "\n";
|
|
if (arg.type() == TYPE_SCALAR) {
|
|
out << "var_msg" << primitive_type_index << "->set_type("
|
|
<< "TYPE_SCALAR);" << "\n";
|
|
out << "var_msg" << primitive_type_index << "->set_scalar_type(\""
|
|
<< arg.scalar_type() << "\");" << "\n";
|
|
out << "var_msg" << primitive_type_index << "->mutable_scalar_value()";
|
|
if (arg.scalar_type() == "bool_t") {
|
|
out << "->set_" << arg.scalar_type() << "("
|
|
<< arg.scalar_value().bool_t() << ");" << "\n";
|
|
} else if (arg.scalar_type() == "int8_t") {
|
|
out << "->set_" << arg.scalar_type() << "("
|
|
<< arg.scalar_value().int8_t() << ");" << "\n";
|
|
} else if (arg.scalar_type() == "uint8_t") {
|
|
out << "->set_" << arg.scalar_type() << "("
|
|
<< arg.scalar_value().uint8_t() << ");" << "\n";
|
|
} else if (arg.scalar_type() == "int16_t") {
|
|
out << "->set_" << arg.scalar_type() << "("
|
|
<< arg.scalar_value().int16_t() << ");" << "\n";
|
|
} else if (arg.scalar_type() == "uint16_t") {
|
|
out << "->set_" << arg.scalar_type() << "("
|
|
<< arg.scalar_value().uint16_t() << ");" << "\n";
|
|
} else if (arg.scalar_type() == "int32_t") {
|
|
out << "->set_" << arg.scalar_type() << "("
|
|
<< arg.scalar_value().int32_t() << ");" << "\n";
|
|
} else if (arg.scalar_type() == "uint32_t") {
|
|
out << "->set_" << arg.scalar_type() << "("
|
|
<< arg.scalar_value().uint32_t() << ");" << "\n";
|
|
} else if (arg.scalar_type() == "size_t") {
|
|
out << "->set_uint32_t("
|
|
<< arg.scalar_value().uint32_t() << ");" << "\n";
|
|
} else if (arg.scalar_type() == "int64_t") {
|
|
out << "->set_" << arg.scalar_type() << "("
|
|
<< arg.scalar_value().int64_t() << ");" << "\n";
|
|
} else if (arg.scalar_type() == "uint64_t") {
|
|
out << "->set_" << arg.scalar_type() << "("
|
|
<< arg.scalar_value().uint64_t() << ");" << "\n";
|
|
} else if (arg.scalar_type() == "char_pointer") {
|
|
// pointer value is not meaning when it is passed to another machine.
|
|
out << "->set_" << arg.scalar_type() << "("
|
|
<< arg.scalar_value().char_pointer() << ");" << "\n";
|
|
} else if (arg.scalar_type() == "uchar_pointer") {
|
|
// pointer value is not meaning when it is passed to another machine.
|
|
out << "->set_" << arg.scalar_type() << "("
|
|
<< arg.scalar_value().uchar_pointer() << ");" << "\n";
|
|
} else if (arg.scalar_type() == "void_pointer") {
|
|
// pointer value is not meaning when it is passed to another machine.
|
|
out << "->set_" << arg.scalar_type() << "("
|
|
<< arg.scalar_value().void_pointer() << ");" << "\n";
|
|
} else {
|
|
cerr << __func__ << " unsupported scalar type " << arg.scalar_type()
|
|
<< "\n";
|
|
exit(-1);
|
|
}
|
|
} else if (arg.type() == TYPE_PREDEFINED) {
|
|
out << "var_msg" << primitive_type_index << "->set_type("
|
|
<< "TYPE_PREDEFINED);" << "\n";
|
|
// TODO: actually handle such case.
|
|
} else {
|
|
cerr << __func__ << " unsupported type" << "\n";
|
|
exit(-1);
|
|
}
|
|
primitive_type_index++;
|
|
}
|
|
out << "RpcCallToAgent(callback_message, callback_socket_name_);"
|
|
<< "\n";
|
|
if (has_return_value) {
|
|
// TODO: consider actual return type.
|
|
out << "return NULL;";
|
|
}
|
|
out.unindent();
|
|
out << "}" << "\n";
|
|
out << "\n";
|
|
|
|
primitive_format_index++;
|
|
}
|
|
out << "\n";
|
|
out.unindent();
|
|
out << " private:" << "\n";
|
|
out << "};" << "\n";
|
|
out << "\n";
|
|
}
|
|
}
|
|
|
|
void HalCodeGen::GenerateCppBodyFuzzFunction(
|
|
Formatter& out, const ComponentSpecificationMessage& message,
|
|
const string& fuzzer_extended_class_name) {
|
|
for (auto const& sub_struct : message.interface().sub_struct()) {
|
|
GenerateCppBodyFuzzFunction(out, sub_struct, fuzzer_extended_class_name,
|
|
message.original_data_structure_name(),
|
|
sub_struct.is_pointer() ? "->" : ".");
|
|
}
|
|
|
|
out << "bool " << fuzzer_extended_class_name << "::Fuzz(" << "\n";
|
|
out << " FunctionSpecificationMessage* func_msg," << "\n";
|
|
out << " void** result, const string& callback_socket_name) {" << "\n";
|
|
out.indent();
|
|
out << "const char* func_name = func_msg->name().c_str();" << "\n";
|
|
out << "LOG(INFO) << \" '\" << func_name << \"'\";"
|
|
<< "\n";
|
|
|
|
// to call another function if it's for a sub_struct
|
|
if (message.interface().sub_struct().size() > 0) {
|
|
out << "if (func_msg->parent_path().length() > 0) {" << "\n";
|
|
out.indent();
|
|
for (auto const& sub_struct : message.interface().sub_struct()) {
|
|
GenerateSubStructFuzzFunctionCall(out, sub_struct, "");
|
|
}
|
|
out.unindent();
|
|
out << "}" << "\n";
|
|
}
|
|
|
|
out << message.original_data_structure_name()
|
|
<< "* local_device = ";
|
|
out << "reinterpret_cast<" << message.original_data_structure_name()
|
|
<< "*>(" << kInstanceVariableName << ");" << "\n";
|
|
|
|
out << "if (local_device == NULL) {" << "\n";
|
|
out.indent();
|
|
out << "LOG(INFO) << \"use hmi \" << (uint64_t)hmi_;"
|
|
<< "\n";
|
|
out << "local_device = reinterpret_cast<"
|
|
<< message.original_data_structure_name() << "*>(hmi_);\n";
|
|
out.unindent();
|
|
out << "}" << "\n";
|
|
out << "if (local_device == NULL) {" << "\n";
|
|
out.indent();
|
|
out << "LOG(ERROR) << \"both device_ and hmi_ are NULL.\";\n";
|
|
out << "return false;" << "\n";
|
|
out.unindent();
|
|
out << "}" << "\n";
|
|
|
|
for (auto const& api : message.interface().api()) {
|
|
out << "if (!strcmp(func_name, \"" << api.name() << "\")) {" << "\n";
|
|
out.indent();
|
|
out << "LOG(INFO) << \"match\" <<;\n";
|
|
// args - definition;
|
|
int arg_count = 0;
|
|
for (auto const& arg : api.arg()) {
|
|
if (arg.is_callback()) { // arg.type() isn't always TYPE_FUNCTION_POINTER
|
|
string name = "vts_callback_" + fuzzer_extended_class_name + "_" +
|
|
arg.predefined_type(); // TODO - check to make sure name
|
|
// is always correct
|
|
if (name.back() == '*') name.pop_back();
|
|
out << name << "* arg" << arg_count << "callback = new ";
|
|
out << name << "(callback_socket_name);" << "\n";
|
|
out << "arg" << arg_count << "callback->Register(func_msg->arg("
|
|
<< arg_count << "));" << "\n";
|
|
|
|
out << GetCppVariableType(arg) << " ";
|
|
out << "arg" << arg_count << " = (" << GetCppVariableType(arg)
|
|
<< ") malloc(sizeof(" << GetCppVariableType(arg) << "));"
|
|
<< "\n";
|
|
// TODO: think about how to free the malloced callback data structure.
|
|
// find the spec.
|
|
bool found = false;
|
|
cout << name << "\n";
|
|
for (auto const& attribute : message.interface().attribute()) {
|
|
if (attribute.type() == TYPE_FUNCTION_POINTER &&
|
|
attribute.is_callback()) {
|
|
string target_name = "vts_callback_" + fuzzer_extended_class_name +
|
|
"_" + attribute.name();
|
|
cout << "compare" << "\n";
|
|
cout << target_name << "\n";
|
|
if (name == target_name) {
|
|
if (attribute.function_pointer_size() > 1) {
|
|
for (auto const& func_pt : attribute.function_pointer()) {
|
|
out << "arg" << arg_count << "->"
|
|
<< func_pt.function_name() << " = arg" << arg_count
|
|
<< "callback->" << func_pt.function_name() << ";"
|
|
<< "\n";
|
|
}
|
|
} else {
|
|
out << "arg" << arg_count << " = arg" << arg_count
|
|
<< "callback->" << attribute.name() << ";" << "\n";
|
|
}
|
|
found = true;
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
if (!found) {
|
|
cerr << __func__ << " ERROR callback definition missing for " << name
|
|
<< " of " << api.name() << "\n";
|
|
exit(-1);
|
|
}
|
|
} else {
|
|
out << GetCppVariableType(arg) << " ";
|
|
out << "arg" << arg_count << " = ";
|
|
if (arg_count == 0 && arg.type() == TYPE_PREDEFINED &&
|
|
!strncmp(arg.predefined_type().c_str(),
|
|
message.original_data_structure_name().c_str(),
|
|
message.original_data_structure_name().length())) {
|
|
out << "reinterpret_cast<" << GetCppVariableType(arg) << ">("
|
|
<< kInstanceVariableName << ")";
|
|
} else {
|
|
std::stringstream msg_ss;
|
|
msg_ss << "func_msg->arg(" << arg_count << ")";
|
|
string msg = msg_ss.str();
|
|
|
|
if (arg.type() == TYPE_SCALAR) {
|
|
out << "(" << msg << ".type() == TYPE_SCALAR)? ";
|
|
if (arg.scalar_type() == "pointer" ||
|
|
arg.scalar_type() == "pointer_pointer" ||
|
|
arg.scalar_type() == "char_pointer" ||
|
|
arg.scalar_type() == "uchar_pointer" ||
|
|
arg.scalar_type() == "void_pointer" ||
|
|
arg.scalar_type() == "function_pointer") {
|
|
out << "reinterpret_cast<" << GetCppVariableType(arg) << ">";
|
|
}
|
|
out << "(" << msg << ".scalar_value()";
|
|
|
|
if (arg.scalar_type() == "bool_t" ||
|
|
arg.scalar_type() == "int32_t" ||
|
|
arg.scalar_type() == "uint32_t" ||
|
|
arg.scalar_type() == "int64_t" ||
|
|
arg.scalar_type() == "uint64_t" ||
|
|
arg.scalar_type() == "int16_t" ||
|
|
arg.scalar_type() == "uint16_t" ||
|
|
arg.scalar_type() == "int8_t" ||
|
|
arg.scalar_type() == "uint8_t" ||
|
|
arg.scalar_type() == "float_t" ||
|
|
arg.scalar_type() == "double_t") {
|
|
out << "." << arg.scalar_type() << "() ";
|
|
} else if (arg.scalar_type() == "pointer" ||
|
|
arg.scalar_type() == "char_pointer" ||
|
|
arg.scalar_type() == "uchar_pointer" ||
|
|
arg.scalar_type() == "void_pointer") {
|
|
out << ".pointer() ";
|
|
} else {
|
|
cerr << __func__ << " ERROR unsupported scalar type "
|
|
<< arg.scalar_type() << "\n";
|
|
exit(-1);
|
|
}
|
|
out << ") : ";
|
|
} else {
|
|
cerr << __func__ << " unknown type " << msg << "\n";
|
|
}
|
|
|
|
out << "( (" << msg << ".type() == TYPE_PREDEFINED || " << msg
|
|
<< ".type() == TYPE_STRUCT || " << msg
|
|
<< ".type() == TYPE_SCALAR)? ";
|
|
out << GetCppInstanceType(arg, msg);
|
|
out << " : " << GetCppInstanceType(arg) << " )";
|
|
// TODO: use the given message and call a lib function which converts
|
|
// a message to a C/C++ struct.
|
|
}
|
|
out << ";" << "\n";
|
|
}
|
|
out << "LOG(INFO) << \"arg" << arg_count << " = \" << arg" << arg_count
|
|
<< ";\n";
|
|
arg_count++;
|
|
}
|
|
|
|
// actual function call
|
|
GenerateCodeToStartMeasurement(out);
|
|
out << "LOG(INFO) << \"hit2.\" << device_;\n";
|
|
|
|
// checks whether the function is actually defined.
|
|
out << "if (reinterpret_cast<"
|
|
<< message.original_data_structure_name() << "*>(local_device)->"
|
|
<< api.name() << " == NULL" << ") {" << "\n";
|
|
out.indent();
|
|
out << "LOG(ERROR) << \"api not set.\";\n";
|
|
// todo: consider throwing an exception at least a way to tell more
|
|
// specifically to the caller.
|
|
out << "return false;" << "\n";
|
|
out.unindent();
|
|
out << "}" << "\n";
|
|
|
|
out << "LOG(INFO) << \"Call an API.\";\n";
|
|
out << "LOG(INFO) << \"local_device = \" << local_device;\n";
|
|
|
|
if (!api.has_return_type() || api.return_type().type() == TYPE_VOID) {
|
|
out << "*result = NULL;" << "\n";
|
|
} else {
|
|
out << "*result = const_cast<void*>(reinterpret_cast<const void*>(";
|
|
}
|
|
out << "local_device->" << api.name() << "(";
|
|
if (arg_count > 0) out << "\n";
|
|
|
|
for (int index = 0; index < arg_count; index++) {
|
|
out << "arg" << index;
|
|
if (index != (arg_count - 1)) {
|
|
out << "," << "\n";
|
|
}
|
|
}
|
|
|
|
if (api.has_return_type() && api.return_type().type() != TYPE_VOID) {
|
|
out << "))";
|
|
}
|
|
out << ");" << "\n";
|
|
GenerateCodeToStopMeasurement(out);
|
|
out << "LOG(INFO) << \"called\";\n";
|
|
|
|
// Copy the output (call by pointer or reference cases).
|
|
arg_count = 0;
|
|
for (auto const& arg : api.arg()) {
|
|
if (arg.is_output()) {
|
|
// TODO check the return value
|
|
out << GetConversionToProtobufFunctionName(arg) << "(arg"
|
|
<< arg_count << ", "
|
|
<< "func_msg->mutable_arg(" << arg_count << "));" << "\n";
|
|
}
|
|
arg_count++;
|
|
}
|
|
|
|
out << "return true;" << "\n";
|
|
out.unindent();
|
|
out << "}" << "\n";
|
|
}
|
|
// TODO: if there were pointers, free them.
|
|
out << "LOG(ERROR) << \"func not found\";\n";
|
|
out << "return false;" << "\n";
|
|
out.unindent();
|
|
out << "}" << "\n";
|
|
}
|
|
|
|
void HalCodeGen::GenerateCppBodyFuzzFunction(
|
|
Formatter& out, const StructSpecificationMessage& message,
|
|
const string& fuzzer_extended_class_name,
|
|
const string& original_data_structure_name, const string& parent_path) {
|
|
for (auto const& sub_struct : message.sub_struct()) {
|
|
GenerateCppBodyFuzzFunction(
|
|
out, sub_struct, fuzzer_extended_class_name,
|
|
original_data_structure_name,
|
|
parent_path + message.name() + (sub_struct.is_pointer() ? "->" : "."));
|
|
}
|
|
|
|
string parent_path_printable(parent_path);
|
|
ReplaceSubString(parent_path_printable, "->", "_");
|
|
replace(parent_path_printable.begin(), parent_path_printable.end(), '.', '_');
|
|
|
|
out << "bool " << fuzzer_extended_class_name << "::Fuzz_"
|
|
<< parent_path_printable + message.name() << "(" << "\n";
|
|
out << "FunctionSpecificationMessage* func_msg," << "\n";
|
|
out << "void** result, const string& callback_socket_name) {" << "\n";
|
|
out.indent();
|
|
out << "const char* func_name = func_msg->name().c_str();" << "\n";
|
|
out << "LOG(INFO) << func_name;\n";
|
|
|
|
bool is_open;
|
|
for (auto const& api : message.api()) {
|
|
is_open = false;
|
|
if ((parent_path_printable + message.name()) == "_common_methods" &&
|
|
api.name() == "open") {
|
|
is_open = true;
|
|
}
|
|
|
|
out << "if (!strcmp(func_name, \"" << api.name() << "\")) {" << "\n";
|
|
out.indent();
|
|
|
|
out << original_data_structure_name << "* local_device = ";
|
|
out << "reinterpret_cast<" << original_data_structure_name << "*>("
|
|
<< kInstanceVariableName << ");" << "\n";
|
|
|
|
out << "if (local_device == NULL) {" << "\n";
|
|
out.indent();
|
|
out << "LOG(INFO) << \"use hmi\";\n";
|
|
out << "local_device = reinterpret_cast<"
|
|
<< original_data_structure_name << "*>(hmi_);" << "\n";
|
|
out.unindent();
|
|
out << "}" << "\n";
|
|
out << "if (local_device == NULL) {" << "\n";
|
|
out.indent();
|
|
out << "LOG(ERROR) << \"both device_ and hmi_ are NULL.\";\n";
|
|
out << "return false;" << "\n";
|
|
out.unindent();
|
|
out << "}" << "\n";
|
|
|
|
// args - definition;
|
|
int arg_count = 0;
|
|
for (auto const& arg : api.arg()) {
|
|
out << GetCppVariableType(arg) << " ";
|
|
out << "arg" << arg_count << " = ";
|
|
if (arg_count == 0 && arg.type() == TYPE_PREDEFINED &&
|
|
!strncmp(arg.predefined_type().c_str(),
|
|
original_data_structure_name.c_str(),
|
|
original_data_structure_name.length())) {
|
|
out << "reinterpret_cast<" << GetCppVariableType(arg) << ">("
|
|
<< kInstanceVariableName << ")";
|
|
} else {
|
|
std::stringstream msg_ss;
|
|
msg_ss << "func_msg->arg(" << arg_count << ")";
|
|
string msg = msg_ss.str();
|
|
|
|
if (arg.type() == TYPE_SCALAR) {
|
|
out << "(" << msg << ".type() == TYPE_SCALAR && " << msg
|
|
<< ".scalar_value()";
|
|
if (arg.scalar_type() == "pointer" ||
|
|
arg.scalar_type() == "char_pointer" ||
|
|
arg.scalar_type() == "uchar_pointer" ||
|
|
arg.scalar_type() == "void_pointer" ||
|
|
arg.scalar_type() == "function_pointer") {
|
|
out << ".has_pointer())? ";
|
|
out << "reinterpret_cast<" << GetCppVariableType(arg) << ">";
|
|
} else {
|
|
out << ".has_" << arg.scalar_type() << "())? ";
|
|
}
|
|
out << "(" << msg << ".scalar_value()";
|
|
|
|
if (arg.scalar_type() == "int32_t" ||
|
|
arg.scalar_type() == "uint32_t" ||
|
|
arg.scalar_type() == "int64_t" ||
|
|
arg.scalar_type() == "uint64_t" ||
|
|
arg.scalar_type() == "int16_t" ||
|
|
arg.scalar_type() == "uint16_t" ||
|
|
arg.scalar_type() == "int8_t" || arg.scalar_type() == "uint8_t" ||
|
|
arg.scalar_type() == "float_t" ||
|
|
arg.scalar_type() == "double_t") {
|
|
out << "." << arg.scalar_type() << "() ";
|
|
} else if (arg.scalar_type() == "pointer" ||
|
|
arg.scalar_type() == "char_pointer" ||
|
|
arg.scalar_type() == "uchar_pointer" ||
|
|
arg.scalar_type() == "function_pointer" ||
|
|
arg.scalar_type() == "void_pointer") {
|
|
out << ".pointer() ";
|
|
} else {
|
|
cerr << __func__ << " ERROR unsupported type " << arg.scalar_type()
|
|
<< "\n";
|
|
exit(-1);
|
|
}
|
|
out << ") : ";
|
|
}
|
|
|
|
if (is_open) {
|
|
if (arg_count == 0) {
|
|
out << "hmi_;" << "\n";
|
|
} else if (arg_count == 1) {
|
|
out << "((hmi_) ? const_cast<char*>(hmi_->name) : NULL)" << "\n";
|
|
} else if (arg_count == 2) {
|
|
out << "(struct hw_device_t**) &device_" << "\n";
|
|
} else {
|
|
cerr << __func__ << " ERROR additional args for open " << arg_count
|
|
<< "\n";
|
|
exit(-1);
|
|
}
|
|
} else {
|
|
out << "( (" << msg << ".type() == TYPE_PREDEFINED || " << msg
|
|
<< ".type() == TYPE_STRUCT || " << msg
|
|
<< ".type() == TYPE_SCALAR)? ";
|
|
out << GetCppInstanceType(arg, msg);
|
|
out << " : " << GetCppInstanceType(arg) << " )";
|
|
// TODO: use the given message and call a lib function which converts
|
|
// a message to a C/C++ struct.
|
|
}
|
|
}
|
|
out << ";" << "\n";
|
|
out << "LOG(INFO) << \"arg" << arg_count << " = \" << arg" << arg_count
|
|
<< "\n\n";
|
|
arg_count++;
|
|
}
|
|
|
|
// actual function call
|
|
GenerateCodeToStartMeasurement(out);
|
|
out << "LOG(INFO) << \"hit2.\" << device_;\n";
|
|
|
|
out << "if (reinterpret_cast<" << original_data_structure_name
|
|
<< "*>(local_device)" << parent_path << message.name() << "->"
|
|
<< api.name() << " == NULL";
|
|
out << ") {" << "\n";
|
|
out.indent();
|
|
out << "LOG(ERROR) << \"api not set.\";\n";
|
|
// todo: consider throwing an exception at least a way to tell more
|
|
// specifically to the caller.
|
|
out << "return false;" << "\n";
|
|
out.unindent();
|
|
out << "}" << "\n";
|
|
|
|
out << "LOG(INFO) << \"Call an API.\";\n";
|
|
if (!api.has_return_type() || api.return_type().type() == TYPE_VOID) {
|
|
out << "*result = NULL;" << "\n";
|
|
} else {
|
|
out << "*result = const_cast<void*>(reinterpret_cast<const void*>(";
|
|
}
|
|
out << "local_device" << parent_path << message.name() << "->"
|
|
<< api.name() << "(";
|
|
if (arg_count > 0) out << "\n";
|
|
|
|
for (int index = 0; index < arg_count; index++) {
|
|
out << "arg" << index;
|
|
if (index != (arg_count - 1)) {
|
|
out << "," << "\n";
|
|
}
|
|
}
|
|
if (api.has_return_type() && api.return_type().type() != TYPE_VOID) {
|
|
out << "))";
|
|
}
|
|
out << ");" << "\n";
|
|
GenerateCodeToStopMeasurement(out);
|
|
out << "LOG(INFO) << \"called\";\n";
|
|
|
|
// Copy the output (call by pointer or reference cases).
|
|
arg_count = 0;
|
|
for (auto const& arg : api.arg()) {
|
|
if (arg.is_output()) {
|
|
// TODO check the return value
|
|
out << GetConversionToProtobufFunctionName(arg) << "(arg"
|
|
<< arg_count << ", "
|
|
<< "func_msg->mutable_arg(" << arg_count << "));" << "\n";
|
|
}
|
|
arg_count++;
|
|
}
|
|
|
|
out << "return true;" << "\n";
|
|
out.unindent();
|
|
out << "}" << "\n";
|
|
}
|
|
// TODO: if there were pointers, free them.
|
|
out << "return false;" << "\n";
|
|
out.unindent();
|
|
out << "}" << "\n";
|
|
}
|
|
|
|
void HalCodeGen::GenerateCppBodyGetAttributeFunction(
|
|
Formatter& out, const ComponentSpecificationMessage& message,
|
|
const string& fuzzer_extended_class_name) {
|
|
for (auto const& sub_struct : message.interface().sub_struct()) {
|
|
GenerateCppBodyGetAttributeFunction(
|
|
out, sub_struct, fuzzer_extended_class_name,
|
|
message.original_data_structure_name(),
|
|
sub_struct.is_pointer() ? "->" : ".");
|
|
}
|
|
|
|
out << "bool " << fuzzer_extended_class_name << "::GetAttribute(" << "\n";
|
|
out << " FunctionSpecificationMessage* func_msg," << "\n";
|
|
out << " void** result) {" << "\n";
|
|
out.indent();
|
|
out << "const char* func_name = func_msg->name().c_str();" << "\n";
|
|
out << "LOG(INFO) << \" '\" << func_name << \"'\";\n";
|
|
|
|
// to call another function if it's for a sub_struct
|
|
if (message.interface().sub_struct().size() > 0) {
|
|
out << " if (func_msg->parent_path().length() > 0) {" << "\n";
|
|
out.indent();
|
|
for (auto const& sub_struct : message.interface().sub_struct()) {
|
|
GenerateSubStructGetAttributeFunctionCall(out, sub_struct, "");
|
|
}
|
|
out.unindent();
|
|
out << "}" << "\n";
|
|
}
|
|
|
|
out << message.original_data_structure_name()
|
|
<< "* local_device = ";
|
|
out << "reinterpret_cast<" << message.original_data_structure_name()
|
|
<< "*>(" << kInstanceVariableName << ");" << "\n";
|
|
|
|
out << "if (local_device == NULL) {" << "\n";
|
|
out.indent();
|
|
out << "LOG(INFO) << \"use hmi \" << (uint64_t)hmi_;\n";
|
|
out << "local_device = reinterpret_cast<"
|
|
<< message.original_data_structure_name() << "*>(hmi_);" << "\n";
|
|
out.unindent();
|
|
out << "}" << "\n";
|
|
out << "if (local_device == NULL) {" << "\n";
|
|
out.indent();
|
|
out << "LOG(ERROR) << \"both device_ and hmi_ are NULL.\";\n";
|
|
out << "return false;" << "\n";
|
|
out.unindent();
|
|
out << "}" << "\n";
|
|
|
|
for (auto const& attribute : message.interface().attribute()) {
|
|
if (attribute.type() == TYPE_SUBMODULE ||
|
|
attribute.type() == TYPE_SCALAR) {
|
|
out << "if (!strcmp(func_name, \"" << attribute.name() << "\")) {" << "\n";
|
|
out.indent();
|
|
out << "LOG(INFO) << \"match\";\n";
|
|
|
|
// actual function call
|
|
out << "LOG(INFO) << \"hit2.\" << device_ ;\n";
|
|
|
|
out << "LOG(INFO) << \"ok. let's read attribute.\";\n";
|
|
out << "*result = const_cast<void*>(reinterpret_cast<const void*>(";
|
|
out << "local_device->" << attribute.name();
|
|
out << "));" << "\n";
|
|
|
|
out << "LOG(INFO) << \"got\";\n";
|
|
|
|
out << "return true;" << "\n";
|
|
out.unindent();
|
|
out << "}" << "\n";
|
|
}
|
|
}
|
|
// TODO: if there were pointers, free them.
|
|
out << "LOG(ERROR) << \"attribute not found\";\n";
|
|
out << "return false;" << "\n";
|
|
out.unindent();
|
|
out << "}" << "\n";
|
|
}
|
|
|
|
void HalCodeGen::GenerateCppBodyGetAttributeFunction(
|
|
Formatter& out, const StructSpecificationMessage& message,
|
|
const string& fuzzer_extended_class_name,
|
|
const string& original_data_structure_name, const string& parent_path) {
|
|
for (auto const& sub_struct : message.sub_struct()) {
|
|
GenerateCppBodyGetAttributeFunction(
|
|
out, sub_struct, fuzzer_extended_class_name,
|
|
original_data_structure_name,
|
|
parent_path + message.name() + (sub_struct.is_pointer() ? "->" : "."));
|
|
}
|
|
|
|
string parent_path_printable(parent_path);
|
|
ReplaceSubString(parent_path_printable, "->", "_");
|
|
replace(parent_path_printable.begin(), parent_path_printable.end(), '.', '_');
|
|
|
|
out << "bool " << fuzzer_extended_class_name << "::GetAttribute_"
|
|
<< parent_path_printable + message.name() << "(" << "\n";
|
|
out << " FunctionSpecificationMessage* func_msg," << "\n";
|
|
out << " void** result) {" << "\n";
|
|
out.indent();
|
|
out << "const char* func_name = func_msg->name().c_str();" << "\n";
|
|
out << "LOG(INFO) << func_name;\n";
|
|
|
|
out << original_data_structure_name
|
|
<< "* local_device = ";
|
|
out << "reinterpret_cast<" << original_data_structure_name
|
|
<< "*>(" << kInstanceVariableName << ");" << "\n";
|
|
|
|
out << "if (local_device == NULL) {" << "\n";
|
|
out.indent();
|
|
out << " LOG(INFO) << \"use hmi \" << (uint64_t)hmi_;\n";
|
|
out << " local_device = reinterpret_cast<"
|
|
<< original_data_structure_name << "*>(hmi_);" << "\n";
|
|
out.unindent();
|
|
out << "}" << "\n";
|
|
out << "if (local_device == NULL) {" << "\n";
|
|
out.indent();
|
|
out << "LOG(ERROR) << \"both device_ and hmi_ are NULL.\";\n";
|
|
out << "return false;" << "\n";
|
|
out.unindent();
|
|
out << "}" << "\n";
|
|
|
|
for (auto const& attribute : message.attribute()) {
|
|
if (attribute.type() == TYPE_SUBMODULE ||
|
|
attribute.type() == TYPE_SCALAR) {
|
|
out << "if (!strcmp(func_name, \"" << attribute.name() << "\")) {" << "\n";
|
|
out.indent();
|
|
out << "LOG(INFO) << \"match\";\n";
|
|
|
|
// actual function call
|
|
out << "LOG(INFO) << \"hit2.\" << device_;\n";
|
|
|
|
out << "LOG(INFO) << \"ok. let's read attribute.\";\n";
|
|
out << "*result = const_cast<void*>(reinterpret_cast<const void*>(";
|
|
out << "local_device" << parent_path << message.name() << ".";
|
|
// TODO: use parent's is_pointer()
|
|
out << attribute.name();
|
|
out << "));" << "\n";
|
|
|
|
out << "LOG(INFO) << \"got\";\n";
|
|
|
|
out << "return true;" << "\n";
|
|
out.unindent();
|
|
out << "}" << "\n";
|
|
}
|
|
}
|
|
// TODO: if there were pointers, free them.
|
|
out << "LOG(ERROR) << \"attribute not found\";\n";
|
|
out << "return false;" << "\n";
|
|
out.unindent();
|
|
out << "}" << "\n";
|
|
}
|
|
|
|
void HalCodeGen::GenerateClassConstructionFunction(Formatter& out,
|
|
const ComponentSpecificationMessage& /*message*/,
|
|
const string& fuzzer_extended_class_name) {
|
|
out << fuzzer_extended_class_name << "() : DriverBase(HAL_CONVENTIONAL) {}\n";
|
|
}
|
|
|
|
void HalCodeGen::GenerateSubStructFuzzFunctionCall(
|
|
Formatter& out, const StructSpecificationMessage& message,
|
|
const string& parent_path) {
|
|
string current_path(parent_path);
|
|
if (current_path.length() > 0) {
|
|
current_path += ".";
|
|
}
|
|
current_path += message.name();
|
|
|
|
string current_path_printable(current_path);
|
|
replace(current_path_printable.begin(), current_path_printable.end(), '.',
|
|
'_');
|
|
|
|
out << "if (func_msg->parent_path() == \"" << current_path << "\") {"
|
|
<< "\n";
|
|
out.indent();
|
|
out << "return Fuzz__" << current_path_printable
|
|
<< "(func_msg, result, callback_socket_name);" << "\n";
|
|
out.unindent();
|
|
out << "}" << "\n";
|
|
|
|
for (auto const& sub_struct : message.sub_struct()) {
|
|
GenerateSubStructFuzzFunctionCall(out, sub_struct, current_path);
|
|
}
|
|
}
|
|
|
|
void HalCodeGen::GenerateSubStructGetAttributeFunctionCall(
|
|
Formatter& out, const StructSpecificationMessage& message,
|
|
const string& parent_path) {
|
|
string current_path(parent_path);
|
|
if (current_path.length() > 0) {
|
|
current_path += ".";
|
|
}
|
|
current_path += message.name();
|
|
|
|
string current_path_printable(current_path);
|
|
replace(current_path_printable.begin(), current_path_printable.end(), '.',
|
|
'_');
|
|
|
|
out << "if (func_msg->parent_path() == \"" << current_path << "\") {"
|
|
<< "\n";
|
|
out.indent();
|
|
out << " return GetAttribute__" << current_path_printable
|
|
<< "(func_msg, result);" << "\n";
|
|
out.unindent();
|
|
out << "}" << "\n";
|
|
|
|
for (auto const& sub_struct : message.sub_struct()) {
|
|
GenerateSubStructGetAttributeFunctionCall(out, sub_struct, current_path);
|
|
}
|
|
}
|
|
|
|
} // namespace vts
|
|
} // namespace android
|