blob: 2783b1579bdf38f614ed18333f53700c3be1d5f7 [file] [log] [blame]
// Copyright 2017 The Fuchsia Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#ifndef LIB_FIDL_INTERNAL_H_
#define LIB_FIDL_INTERNAL_H_
#include <assert.h>
#include <cstdint>
#include <lib/fidl/coding.h>
#include <zircon/syscalls/object.h>
#include <zircon/types.h>
// All sizes here are given as uint32_t. Fidl message sizes are bounded to well below UINT32_MAX.
// This also applies to arrays and vectors. For arrays, element_count * element_size will always fit
// with 32 bits. For vectors, max_count * element_size will always fit within 32 bits.
// Pointers to other type tables within a type are always nonnull, with the exception of vectors.
// In that case, a null pointer indicates that the element type of the vector has no interesting
// information to be decoded (i.e. no pointers or handles). The vector type still needs to be
// emitted as it contains the information about the size of its secondary object. Contrast this with
// arrays: being inline, ones with no interesting coding information can be elided, just like a
// uint32 field in a struct is elided.
namespace fidl {
enum FidlNullability : uint32_t {
kNonnullable = 0u,
kNullable = 1u,
};
constexpr inline uint64_t FidlAlign(uint32_t offset) {
constexpr uint64_t alignment_mask = FIDL_ALIGNMENT - 1;
return (offset + alignment_mask) & ~alignment_mask;
}
// Determine if the pointer is aligned to |FIDL_ALIGNMENT|.
inline bool IsAligned(uint8_t* ptr) {
auto uintptr = reinterpret_cast<std::uintptr_t>(ptr);
constexpr uintptr_t kAlignment = FIDL_ALIGNMENT;
return uintptr % kAlignment == 0;
}
// Add |size| to out-of-line |offset|, maintaining alignment. For example, a pointer to a struct
// that is 4 bytes still needs to advance the next out-of-line offset by 8 to maintain
// the aligned-to-FIDL_ALIGNMENT property.
// Returns false on overflow. Otherwise, resulting offset is stored in |out_offset|.
inline bool AddOutOfLine(uint32_t offset, uint32_t size, uint32_t* out_offset) {
constexpr uint32_t kMask = FIDL_ALIGNMENT - 1;
uint32_t new_offset = offset;
if (add_overflow(new_offset, size, &new_offset)
|| add_overflow(new_offset, kMask, &new_offset)) {
return false;
}
new_offset &= ~kMask;
*out_offset = new_offset;
return true;
}
struct FidlStructField {
const fidl_type* type;
uint32_t offset;
constexpr FidlStructField(const fidl_type* type, uint32_t offset)
: type(type), offset(offset) {}
};
// TODO(apang): Remove this backward-compatible typedef after all dependencies
// have been updated from FidlField to FidlStructField.
using FidlField = FidlStructField;
struct FidlTableField {
const fidl_type* type;
uint32_t ordinal;
constexpr FidlTableField(const fidl_type* type, uint32_t ordinal)
: type(type), ordinal(ordinal) {}
};
struct FidlXUnionField {
const fidl_type* type;
uint32_t ordinal;
constexpr FidlXUnionField(const fidl_type* type, uint32_t ordinal)
: type(type), ordinal(ordinal) {}
};
enum FidlTypeTag : uint32_t {
kFidlTypeStruct,
kFidlTypeStructPointer,
kFidlTypeUnion,
kFidlTypeUnionPointer,
kFidlTypeArray,
kFidlTypeString,
kFidlTypeHandle,
kFidlTypeVector,
kFidlTypeTable,
kFidlTypeTablePointer,
kFidlTypeXUnion,
kFidlTypeXUnionPointer,
};
// Though the |size| is implied by the fields, computing that information is not the purview of this
// library. It's easier for the compiler to stash it.
struct FidlCodedStruct {
const FidlStructField* const fields;
const uint32_t field_count;
const uint32_t size;
const char* name; // may be nullptr if omitted at compile time
constexpr FidlCodedStruct(const FidlStructField* fields, uint32_t field_count, uint32_t size,
const char* name)
: fields(fields), field_count(field_count), size(size), name(name) {}
};
struct FidlCodedStructPointer {
const FidlCodedStruct* const struct_type;
constexpr explicit FidlCodedStructPointer(const FidlCodedStruct* struct_type)
: struct_type(struct_type) {}
};
struct FidlCodedTable {
const FidlTableField* const fields;
const uint32_t field_count;
const char* name; // may be nullptr if omitted at compile time
constexpr FidlCodedTable(const FidlTableField* fields, uint32_t field_count,
const char* name)
: fields(fields), field_count(field_count), name(name) {}
};
struct FidlCodedTablePointer {
const FidlCodedTable* const table_type;
constexpr explicit FidlCodedTablePointer(const FidlCodedTable* table_type)
: table_type(table_type) {}
};
// Unlike structs, union members do not have different offsets, so this points
// to an array of |fidl_type*| rather than |FidlStructField|.
//
// On-the-wire unions begin with a tag which is an index into |types|.
// |data_offset| is the offset of the data in the wire format (tag + padding).
struct FidlCodedUnion {
const fidl_type* const* types;
const uint32_t type_count;
const uint32_t data_offset;
const uint32_t size;
const char* name; // may be nullptr if omitted at compile time
constexpr FidlCodedUnion(const fidl_type* const* types, uint32_t type_count,
uint32_t data_offset, uint32_t size, const char* name)
: types(types), type_count(type_count), data_offset(data_offset), size(size), name(name) {}
};
struct FidlCodedUnionPointer {
const FidlCodedUnion* const union_type;
constexpr explicit FidlCodedUnionPointer(const FidlCodedUnion* union_type)
: union_type(union_type) {}
};
struct FidlCodedXUnion {
const uint32_t field_count;
const FidlXUnionField* const fields;
const char* name; // may be nullptr if omitted at compile time
constexpr FidlCodedXUnion(uint32_t field_count, const FidlXUnionField* fields, const char* name)
: field_count(field_count), fields(fields), name(name) {}
};
struct FidlCodedXUnionPointer {
const FidlCodedXUnion* const xunion_type;
constexpr explicit FidlCodedXUnionPointer(const FidlCodedXUnion* xunion_type)
: xunion_type(xunion_type) {}
};
// An array is essentially a struct with |array_size / element_size| of the same field, named at
// |element|.
struct FidlCodedArray {
const fidl_type* const element;
const uint32_t array_size;
const uint32_t element_size;
constexpr FidlCodedArray(const fidl_type* element, uint32_t array_size, uint32_t element_size)
: element(element), array_size(array_size), element_size(element_size) {}
};
// Note: must keep in sync with fidlc types.h HandleSubtype.
enum FidlHandleSubtype : zx_obj_type_t {
// special case to indicate subtype is not specified.
kFidlHandleSubtypeHandle = ZX_OBJ_TYPE_NONE,
kFidlHandleSubtypeProcess = ZX_OBJ_TYPE_PROCESS,
kFidlHandleSubtypeThread = ZX_OBJ_TYPE_THREAD,
kFidlHandleSubtypeVmo = ZX_OBJ_TYPE_VMO,
kFidlHandleSubtypeChannel = ZX_OBJ_TYPE_CHANNEL,
kFidlHandleSubtypeEvent = ZX_OBJ_TYPE_EVENT,
kFidlHandleSubtypePort = ZX_OBJ_TYPE_PORT,
kFidlHandleSubtypeInterrupt = ZX_OBJ_TYPE_INTERRUPT,
kFidlHandleSubtypeLog = ZX_OBJ_TYPE_LOG,
kFidlHandleSubtypeSocket = ZX_OBJ_TYPE_SOCKET,
kFidlHandleSubtypeResource = ZX_OBJ_TYPE_RESOURCE,
kFidlHandleSubtypeEventpair = ZX_OBJ_TYPE_EVENTPAIR,
kFidlHandleSubtypeJob = ZX_OBJ_TYPE_JOB,
kFidlHandleSubtypeVmar = ZX_OBJ_TYPE_VMAR,
kFidlHandleSubtypeFifo = ZX_OBJ_TYPE_FIFO,
kFidlHandleSubtypeGuest = ZX_OBJ_TYPE_GUEST,
kFidlHandleSubtypeTimer = ZX_OBJ_TYPE_TIMER,
};
struct FidlCodedHandle {
const zx_obj_type_t handle_subtype;
const FidlNullability nullable;
constexpr FidlCodedHandle(uint32_t handle_subtype, FidlNullability nullable)
: handle_subtype(handle_subtype), nullable(nullable) {}
static_assert(ZX_OBJ_TYPE_LAST <= UINT32_MAX, "");
};
struct FidlCodedString {
const uint32_t max_size;
const FidlNullability nullable;
constexpr FidlCodedString(uint32_t max_size, FidlNullability nullable)
: max_size(max_size), nullable(nullable) {}
};
// Note that |max_count * element_size| is guaranteed to fit into a uint32_t. Unlike other types,
// the |element| pointer may be null. This occurs when the element type contains no interesting bits
// (i.e. pointers or handles).
struct FidlCodedVector {
const fidl_type* const element;
const uint32_t max_count;
const uint32_t element_size;
const FidlNullability nullable;
constexpr FidlCodedVector(const fidl_type* element, uint32_t max_count, uint32_t element_size,
FidlNullability nullable)
: element(element), max_count(max_count), element_size(element_size), nullable(nullable) {}
};
} // namespace fidl
struct fidl_type {
const fidl::FidlTypeTag type_tag;
const union {
const fidl::FidlCodedStruct coded_struct;
const fidl::FidlCodedStructPointer coded_struct_pointer;
const fidl::FidlCodedTable coded_table;
const fidl::FidlCodedTablePointer coded_table_pointer;
const fidl::FidlCodedUnion coded_union;
const fidl::FidlCodedUnionPointer coded_union_pointer;
const fidl::FidlCodedXUnion coded_xunion;
const fidl::FidlCodedXUnionPointer coded_xunion_pointer;
const fidl::FidlCodedHandle coded_handle;
const fidl::FidlCodedString coded_string;
const fidl::FidlCodedArray coded_array;
const fidl::FidlCodedVector coded_vector;
};
constexpr fidl_type(fidl::FidlCodedStruct coded_struct)
: type_tag(fidl::kFidlTypeStruct), coded_struct(coded_struct) {}
constexpr fidl_type(fidl::FidlCodedStructPointer coded_struct_pointer)
: type_tag(fidl::kFidlTypeStructPointer), coded_struct_pointer(coded_struct_pointer) {}
constexpr fidl_type(fidl::FidlCodedTable coded_table)
: type_tag(fidl::kFidlTypeTable), coded_table(coded_table) {}
constexpr fidl_type(fidl::FidlCodedTablePointer coded_table_pointer)
: type_tag(fidl::kFidlTypeTablePointer), coded_table_pointer(coded_table_pointer) {}
constexpr fidl_type(fidl::FidlCodedUnion coded_union)
: type_tag(fidl::kFidlTypeUnion), coded_union(coded_union) {}
constexpr fidl_type(fidl::FidlCodedUnionPointer coded_union_pointer)
: type_tag(fidl::kFidlTypeUnionPointer), coded_union_pointer(coded_union_pointer) {}
constexpr fidl_type(fidl::FidlCodedXUnion coded_xunion)
: type_tag(fidl::kFidlTypeXUnion), coded_xunion(coded_xunion) {}
constexpr fidl_type(fidl::FidlCodedXUnionPointer coded_xunion_pointer)
: type_tag(fidl::kFidlTypeXUnionPointer), coded_xunion_pointer(coded_xunion_pointer) {}
constexpr fidl_type(fidl::FidlCodedHandle coded_handle)
: type_tag(fidl::kFidlTypeHandle), coded_handle(coded_handle) {}
constexpr fidl_type(fidl::FidlCodedString coded_string)
: type_tag(fidl::kFidlTypeString), coded_string(coded_string) {}
constexpr fidl_type(fidl::FidlCodedArray coded_array)
: type_tag(fidl::kFidlTypeArray), coded_array(coded_array) {}
constexpr fidl_type(fidl::FidlCodedVector coded_vector)
: type_tag(fidl::kFidlTypeVector), coded_vector(coded_vector) {}
};
#endif // LIB_FIDL_INTERNAL_H_