Loading system/gd/packet/parser/Android.bp +1 −0 Original line number Diff line number Diff line cc_binary_host { name: "bluetooth_packetgen", srcs: [ "fields/array_field.cc", "fields/body_field.cc", "fields/checksum_field.cc", "fields/checksum_start_field.cc", Loading system/gd/packet/parser/README +6 −0 Original line number Diff line number Diff line Loading @@ -34,6 +34,7 @@ Checksum types - Can't handle size for Body type fields yet since they might not be byte aligned. - Currently no arrays of custom types (might change later) ------- NOTES Loading @@ -51,3 +52,8 @@ One pdl file will result in one header file with all the packets Things to cover - Constraints Inheritence vs Contains Custom fields need the folowing functions: static void Serialize(const Type&, MutableView&); static std::optional<size_t> Size(Iterator); static Type Parse(Iterator); system/gd/packet/parser/fields/all_fields.h +1 −0 Original line number Diff line number Diff line Loading @@ -16,6 +16,7 @@ #pragma once #include "fields/array_field.h" #include "fields/body_field.h" #include "fields/checksum_field.h" #include "fields/checksum_start_field.h" Loading system/gd/packet/parser/fields/array_field.cc 0 → 100644 +205 −0 Original line number Diff line number Diff line /* * Copyright 2019 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 "fields/array_field.h" #include "util.h" ArrayField::ArrayField(std::string name, int element_size, std::string size_modifier, ParseLocation loc) : PacketField(loc, name), element_size_(element_size), size_modifier_(size_modifier) { // Make sure the element_size is a multiple of 8. if (element_size % 8 != 0) ERROR(this) << "Can only have arrays with elements that are byte aligned."; } ArrayField::ArrayField(std::string name, int element_size, int fixed_size, ParseLocation loc) : PacketField(loc, name), element_size_(element_size), fixed_size_(fixed_size) { // Make sure the element_size is a multiple of 8. if (element_size % 8 != 0) ERROR(this) << "Can only have arrays with elements that are byte aligned."; } ArrayField::ArrayField(std::string name, TypeDef* type_def, std::string size_modifier, ParseLocation loc) : PacketField(loc, name), element_size_(type_def->size_), type_def_(type_def), size_modifier_(size_modifier) { // If it is an enum array, make sure that the enum definition is byte aligned. if (type_def_->size_ % 8 != 0) ERROR(this) << "Can only have arrays with elements that are byte aligned."; } ArrayField::ArrayField(std::string name, TypeDef* type_def, int fixed_size, ParseLocation loc) : PacketField(loc, name), element_size_(type_def->size_), type_def_(type_def), fixed_size_(fixed_size) { // If it is an enum array, make sure that the enum definition is byte aligned. if (type_def_->size_ % 8 != 0) ERROR(this) << "Can only have arrays with elements that are byte aligned."; } PacketField::Type ArrayField::GetFieldType() const { return PacketField::Type::ARRAY; } Size ArrayField::GetSize() const { if (IsFixedSize() && element_size_ != -1) { return Size(fixed_size_ * element_size_); } // If there is no size field, then it is of unknown size. if (size_field_ == nullptr) { return Size(); } // size_field_ is of type SIZE if (size_field_->GetFieldType() == PacketField::Type::SIZE) { std::string ret = "Get" + util::UnderscoreToCamelCase(size_field_->GetName()) + "()"; if (!size_modifier_.empty()) ret += size_modifier_; return ret; } // size_field_ is of type COUNT and it is a scalar array if (!IsEnumArray() && !IsCustomFieldArray()) { return "(Get" + util::UnderscoreToCamelCase(size_field_->GetName()) + "() * " + std::to_string(element_size_ / 8) + ")"; } if (IsCustomFieldArray()) { return "(Get" + util::UnderscoreToCamelCase(size_field_->GetName()) + "() * " + std::to_string(type_def_->size_ / 8) + ")"; } // size_field_ is of type COUNT and it is an enum array return "(Get" + util::UnderscoreToCamelCase(size_field_->GetName()) + "() * " + std::to_string(type_def_->size_ / 8) + ")"; } std::string ArrayField::GetType() const { if (type_def_ != nullptr) { return "std::vector<" + type_def_->name_ + ">"; } return "std::vector<" + util::GetTypeForSize(element_size_) + ">"; } void ArrayField::GenGetter(std::ostream& s, Size start_offset, Size end_offset) const { if (start_offset.empty()) { ERROR(this) << "Can not have an array with an ambiguous start offset."; } if (start_offset.bits() % 8 != 0) { ERROR(this) << "Can not have an array that isn't byte aligned."; } if (GetSize().empty() && end_offset.empty()) { ERROR(this) << "Ambiguous end offset for array with no defined size."; } s << GetType(); s << " Get" << util::UnderscoreToCamelCase(GetName()) << "() {"; s << "ASSERT(was_validated_);"; s << "auto it = begin() + " << start_offset.bytes() << " + " << start_offset.dynamic_string() << ";"; if (!GetSize().empty()) { auto size = GetSize(); s << "auto array_end = it + " << size.bytes() << " /* bytes */ + " << size.dynamic_string() << ";"; } else { s << "auto array_end = end() - " << end_offset.bytes() << " /* bytes */ - " << end_offset.dynamic_string() << ";"; } // Add the element size so that we will extract as many elements as we can. s << GetType() << " ret;"; std::string type = type_def_->name_; s << "while (it + sizeof(" << type << ") <= array_end) {"; s << "ret.push_back(it.extract<" << type << ">());"; s << "}"; s << "return ret;"; s << "}\n"; } bool ArrayField::GenBuilderParameter(std::ostream& s) const { std::string element_type = ""; if (type_def_ != nullptr) { element_type = type_def_->GetTypeName(); } else { if (element_size_ > 64 || element_size_ < 0) ERROR(this) << __func__ << ": Not implemented for element size = " << element_size_; element_type = util::GetTypeForSize(element_size_); } s << "const std::vector<" << element_type << ">& " << GetName(); return true; } bool ArrayField::HasParameterValidator() const { if (fixed_size_ == -1) { // Does not have parameter validator yet. // TODO: See comment in GenParameterValidator return false; } return true; } void ArrayField::GenParameterValidator(std::ostream& s) const { if (fixed_size_ == -1) { // No Parameter validator if its dynamically size. // TODO: Maybe add a validator to ensure that the size isn't larger than what the size field can hold. return; } s << "ASSERT(" << GetName() << ".size() == " << fixed_size_ << ");"; } void ArrayField::GenInserter(std::ostream& s) const { s << "for (const auto& val : " << GetName() << "_) {"; if (IsEnumArray()) { s << "insert(static_cast<" << util::GetTypeForSize(type_def_->size_) << ">(val), i, " << type_def_->size_ << ");"; } else if (IsCustomFieldArray()) { s << "insert(val, i);"; } else { s << "insert(val, i, " << element_size_ << ");"; } s << "}\n"; } void ArrayField::GenValidator(std::ostream&) const { // NOTE: We could check if the element size divides cleanly into the array size, but we decided to forgo that // in favor of just returning as many elements as possible in a best effort style. // // Other than that there is nothing that arrays need to be validated on other than length so nothing needs to // be done here. } bool ArrayField::IsEnumArray() const { return type_def_ != nullptr && type_def_->GetDefinitionType() == TypeDef::Type::ENUM; } bool ArrayField::IsCustomFieldArray() const { return type_def_ != nullptr && type_def_->GetDefinitionType() == TypeDef::Type::CUSTOM; } bool ArrayField::IsFixedSize() const { return fixed_size_ != -1; } void ArrayField::SetSizeField(const SizeField* size_field) { if (size_field->GetFieldType() == PacketField::Type::COUNT && !size_modifier_.empty()) { ERROR(this, size_field) << "Can not use count field to describe array with a size modifier." << " Use size instead"; } if (IsFixedSize()) { ERROR(this, size_field) << "Can not use size field with a fixed size array."; } size_field_ = size_field; } const std::string& ArrayField::GetSizeModifier() const { return size_modifier_; } system/gd/packet/parser/fields/array_field.h 0 → 100644 +75 −0 Original line number Diff line number Diff line /* * Copyright 2019 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. */ #pragma once #include "custom_field_def.h" #include "enum_def.h" #include "fields/packet_field.h" #include "fields/size_field.h" #include "parse_location.h" //#include "struct_def.h" class ArrayField : public PacketField { public: ArrayField(std::string name, int element_size, std::string size_modifier, ParseLocation loc); ArrayField(std::string name, int element_size, int fixed_size, ParseLocation loc); ArrayField(std::string name, TypeDef* type_def, std::string size_modifier, ParseLocation loc); ArrayField(std::string name, TypeDef* type_def, int fixed_size, ParseLocation loc); virtual PacketField::Type GetFieldType() const override; virtual Size GetSize() const override; virtual std::string GetType() const override; virtual void GenGetter(std::ostream& s, Size start_offset, Size end_offset) const override; virtual bool GenBuilderParameter(std::ostream& s) const override; virtual bool HasParameterValidator() const override; virtual void GenParameterValidator(std::ostream& s) const override; virtual void GenInserter(std::ostream& s) const override; virtual void GenValidator(std::ostream&) const override; bool IsEnumArray() const; bool IsCustomFieldArray() const; bool IsFixedSize() const; void SetSizeField(const SizeField* size_field); const std::string& GetSizeModifier() const; const std::string name_; const int element_size_{-1}; // units is bits const TypeDef* type_def_{nullptr}; // Fixed size array or dynamic size, size is always in bytes, unless it is count. const int fixed_size_{-1}; const SizeField* size_field_{nullptr}; // Size modifier is only used when size_field_ is of type SIZE and is not used with COUNT. std::string size_modifier_{""}; }; Loading
system/gd/packet/parser/Android.bp +1 −0 Original line number Diff line number Diff line cc_binary_host { name: "bluetooth_packetgen", srcs: [ "fields/array_field.cc", "fields/body_field.cc", "fields/checksum_field.cc", "fields/checksum_start_field.cc", Loading
system/gd/packet/parser/README +6 −0 Original line number Diff line number Diff line Loading @@ -34,6 +34,7 @@ Checksum types - Can't handle size for Body type fields yet since they might not be byte aligned. - Currently no arrays of custom types (might change later) ------- NOTES Loading @@ -51,3 +52,8 @@ One pdl file will result in one header file with all the packets Things to cover - Constraints Inheritence vs Contains Custom fields need the folowing functions: static void Serialize(const Type&, MutableView&); static std::optional<size_t> Size(Iterator); static Type Parse(Iterator);
system/gd/packet/parser/fields/all_fields.h +1 −0 Original line number Diff line number Diff line Loading @@ -16,6 +16,7 @@ #pragma once #include "fields/array_field.h" #include "fields/body_field.h" #include "fields/checksum_field.h" #include "fields/checksum_start_field.h" Loading
system/gd/packet/parser/fields/array_field.cc 0 → 100644 +205 −0 Original line number Diff line number Diff line /* * Copyright 2019 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 "fields/array_field.h" #include "util.h" ArrayField::ArrayField(std::string name, int element_size, std::string size_modifier, ParseLocation loc) : PacketField(loc, name), element_size_(element_size), size_modifier_(size_modifier) { // Make sure the element_size is a multiple of 8. if (element_size % 8 != 0) ERROR(this) << "Can only have arrays with elements that are byte aligned."; } ArrayField::ArrayField(std::string name, int element_size, int fixed_size, ParseLocation loc) : PacketField(loc, name), element_size_(element_size), fixed_size_(fixed_size) { // Make sure the element_size is a multiple of 8. if (element_size % 8 != 0) ERROR(this) << "Can only have arrays with elements that are byte aligned."; } ArrayField::ArrayField(std::string name, TypeDef* type_def, std::string size_modifier, ParseLocation loc) : PacketField(loc, name), element_size_(type_def->size_), type_def_(type_def), size_modifier_(size_modifier) { // If it is an enum array, make sure that the enum definition is byte aligned. if (type_def_->size_ % 8 != 0) ERROR(this) << "Can only have arrays with elements that are byte aligned."; } ArrayField::ArrayField(std::string name, TypeDef* type_def, int fixed_size, ParseLocation loc) : PacketField(loc, name), element_size_(type_def->size_), type_def_(type_def), fixed_size_(fixed_size) { // If it is an enum array, make sure that the enum definition is byte aligned. if (type_def_->size_ % 8 != 0) ERROR(this) << "Can only have arrays with elements that are byte aligned."; } PacketField::Type ArrayField::GetFieldType() const { return PacketField::Type::ARRAY; } Size ArrayField::GetSize() const { if (IsFixedSize() && element_size_ != -1) { return Size(fixed_size_ * element_size_); } // If there is no size field, then it is of unknown size. if (size_field_ == nullptr) { return Size(); } // size_field_ is of type SIZE if (size_field_->GetFieldType() == PacketField::Type::SIZE) { std::string ret = "Get" + util::UnderscoreToCamelCase(size_field_->GetName()) + "()"; if (!size_modifier_.empty()) ret += size_modifier_; return ret; } // size_field_ is of type COUNT and it is a scalar array if (!IsEnumArray() && !IsCustomFieldArray()) { return "(Get" + util::UnderscoreToCamelCase(size_field_->GetName()) + "() * " + std::to_string(element_size_ / 8) + ")"; } if (IsCustomFieldArray()) { return "(Get" + util::UnderscoreToCamelCase(size_field_->GetName()) + "() * " + std::to_string(type_def_->size_ / 8) + ")"; } // size_field_ is of type COUNT and it is an enum array return "(Get" + util::UnderscoreToCamelCase(size_field_->GetName()) + "() * " + std::to_string(type_def_->size_ / 8) + ")"; } std::string ArrayField::GetType() const { if (type_def_ != nullptr) { return "std::vector<" + type_def_->name_ + ">"; } return "std::vector<" + util::GetTypeForSize(element_size_) + ">"; } void ArrayField::GenGetter(std::ostream& s, Size start_offset, Size end_offset) const { if (start_offset.empty()) { ERROR(this) << "Can not have an array with an ambiguous start offset."; } if (start_offset.bits() % 8 != 0) { ERROR(this) << "Can not have an array that isn't byte aligned."; } if (GetSize().empty() && end_offset.empty()) { ERROR(this) << "Ambiguous end offset for array with no defined size."; } s << GetType(); s << " Get" << util::UnderscoreToCamelCase(GetName()) << "() {"; s << "ASSERT(was_validated_);"; s << "auto it = begin() + " << start_offset.bytes() << " + " << start_offset.dynamic_string() << ";"; if (!GetSize().empty()) { auto size = GetSize(); s << "auto array_end = it + " << size.bytes() << " /* bytes */ + " << size.dynamic_string() << ";"; } else { s << "auto array_end = end() - " << end_offset.bytes() << " /* bytes */ - " << end_offset.dynamic_string() << ";"; } // Add the element size so that we will extract as many elements as we can. s << GetType() << " ret;"; std::string type = type_def_->name_; s << "while (it + sizeof(" << type << ") <= array_end) {"; s << "ret.push_back(it.extract<" << type << ">());"; s << "}"; s << "return ret;"; s << "}\n"; } bool ArrayField::GenBuilderParameter(std::ostream& s) const { std::string element_type = ""; if (type_def_ != nullptr) { element_type = type_def_->GetTypeName(); } else { if (element_size_ > 64 || element_size_ < 0) ERROR(this) << __func__ << ": Not implemented for element size = " << element_size_; element_type = util::GetTypeForSize(element_size_); } s << "const std::vector<" << element_type << ">& " << GetName(); return true; } bool ArrayField::HasParameterValidator() const { if (fixed_size_ == -1) { // Does not have parameter validator yet. // TODO: See comment in GenParameterValidator return false; } return true; } void ArrayField::GenParameterValidator(std::ostream& s) const { if (fixed_size_ == -1) { // No Parameter validator if its dynamically size. // TODO: Maybe add a validator to ensure that the size isn't larger than what the size field can hold. return; } s << "ASSERT(" << GetName() << ".size() == " << fixed_size_ << ");"; } void ArrayField::GenInserter(std::ostream& s) const { s << "for (const auto& val : " << GetName() << "_) {"; if (IsEnumArray()) { s << "insert(static_cast<" << util::GetTypeForSize(type_def_->size_) << ">(val), i, " << type_def_->size_ << ");"; } else if (IsCustomFieldArray()) { s << "insert(val, i);"; } else { s << "insert(val, i, " << element_size_ << ");"; } s << "}\n"; } void ArrayField::GenValidator(std::ostream&) const { // NOTE: We could check if the element size divides cleanly into the array size, but we decided to forgo that // in favor of just returning as many elements as possible in a best effort style. // // Other than that there is nothing that arrays need to be validated on other than length so nothing needs to // be done here. } bool ArrayField::IsEnumArray() const { return type_def_ != nullptr && type_def_->GetDefinitionType() == TypeDef::Type::ENUM; } bool ArrayField::IsCustomFieldArray() const { return type_def_ != nullptr && type_def_->GetDefinitionType() == TypeDef::Type::CUSTOM; } bool ArrayField::IsFixedSize() const { return fixed_size_ != -1; } void ArrayField::SetSizeField(const SizeField* size_field) { if (size_field->GetFieldType() == PacketField::Type::COUNT && !size_modifier_.empty()) { ERROR(this, size_field) << "Can not use count field to describe array with a size modifier." << " Use size instead"; } if (IsFixedSize()) { ERROR(this, size_field) << "Can not use size field with a fixed size array."; } size_field_ = size_field; } const std::string& ArrayField::GetSizeModifier() const { return size_modifier_; }
system/gd/packet/parser/fields/array_field.h 0 → 100644 +75 −0 Original line number Diff line number Diff line /* * Copyright 2019 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. */ #pragma once #include "custom_field_def.h" #include "enum_def.h" #include "fields/packet_field.h" #include "fields/size_field.h" #include "parse_location.h" //#include "struct_def.h" class ArrayField : public PacketField { public: ArrayField(std::string name, int element_size, std::string size_modifier, ParseLocation loc); ArrayField(std::string name, int element_size, int fixed_size, ParseLocation loc); ArrayField(std::string name, TypeDef* type_def, std::string size_modifier, ParseLocation loc); ArrayField(std::string name, TypeDef* type_def, int fixed_size, ParseLocation loc); virtual PacketField::Type GetFieldType() const override; virtual Size GetSize() const override; virtual std::string GetType() const override; virtual void GenGetter(std::ostream& s, Size start_offset, Size end_offset) const override; virtual bool GenBuilderParameter(std::ostream& s) const override; virtual bool HasParameterValidator() const override; virtual void GenParameterValidator(std::ostream& s) const override; virtual void GenInserter(std::ostream& s) const override; virtual void GenValidator(std::ostream&) const override; bool IsEnumArray() const; bool IsCustomFieldArray() const; bool IsFixedSize() const; void SetSizeField(const SizeField* size_field); const std::string& GetSizeModifier() const; const std::string name_; const int element_size_{-1}; // units is bits const TypeDef* type_def_{nullptr}; // Fixed size array or dynamic size, size is always in bytes, unless it is count. const int fixed_size_{-1}; const SizeField* size_field_{nullptr}; // Size modifier is only used when size_field_ is of type SIZE and is not used with COUNT. std::string size_modifier_{""}; };