/* * 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