blob: 3e1fc40a4e9c292d50d501b1947b7bc9cf070b57 [file] [log] [blame]
// Copyright 2019 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 SRC_LIB_FIDL_CODEC_WIRE_OBJECT_H_
#define SRC_LIB_FIDL_CODEC_WIRE_OBJECT_H_
#include <lib/fidl/cpp/message.h>
#include <lib/syslog/cpp/macros.h>
#include <map>
#include <memory>
#include <string_view>
#include <vector>
#include "src/lib/fidl_codec/library_loader.h"
#include "src/lib/fidl_codec/message_decoder.h"
namespace fidl_codec {
class FidlMessageValue;
class HandleValue;
class StringValue;
class StructValue;
class VectorValue;
class Visitor;
// Base class for all the values we can find within a message.
class Value {
public:
Value() = default;
virtual ~Value() = default;
virtual bool IsNull() const { return false; }
// Returns the uint8_t value of the value. If the value is not a uint8_t value this returns zero.
// This is used to eventually display a vector of uint8_t values as a string.
virtual uint8_t GetUint8Value() const { return 0; }
// Gets the integer value of the value. Returns false if the node can't compute an integer value.
// For floating point values, the floating point value is converted to the nearest integer
// value.
virtual bool GetIntegerValue(uint64_t* absolute, bool* negative) const { return false; }
// Gets the floating point value of the value. Returns false if the node can't compute a floating
// point value. For integer values, we can lost precision during the conversion.
virtual bool GetDoubleValue(double* result) const { return false; }
// Methods to downcast a value.
virtual const StringValue* AsStringValue() const { return nullptr; }
virtual const HandleValue* AsHandleValue() const { return nullptr; }
virtual StructValue* AsStructValue() { return nullptr; }
virtual const StructValue* AsStructValue() const { return nullptr; }
virtual const VectorValue* AsVectorValue() const { return nullptr; }
virtual const FidlMessageValue* AsFidlMessageValue() const { return nullptr; }
// Returns true if we need to load information about the handle (call to zx_object_get_info with
// ZX_INFO_HANDLE_TABLE). We need to load information about the handle if one of the handles of
// the value has an unknown koid.
virtual bool NeedsToLoadHandleInfo(int64_t timestamp, zx_koid_t tid,
semantic::HandleSemantic* handle_semantic) const {
return false;
}
// Returns the size needed to display the value. If the needed size is
// greater than |remaining_size|, the return value can be anything greater
// than |remaining_size| and the only useful information is that the value
// can't fit in |remaining_size|.
// Remaining size is just an optimization parameter. It avoids to compute the
// whole display size for an object: the computation is stopped as soon as we
// find that the object doesn't fit.
virtual size_t DisplaySize(const Type* for_type, size_t remaining_size) const = 0;
// Pretty print of the value.
virtual void PrettyPrint(const Type* for_type, PrettyPrinter& printer) const = 0;
// Use a visitor on this value;
virtual void Visit(Visitor* visitor, const Type* for_type) const = 0;
};
// An invalid value. This value can't be present in a valid object.
// It can only be found if we had an error while decoding a message.
class InvalidValue : public Value {
public:
InvalidValue() = default;
size_t DisplaySize(const Type* for_type, size_t remaining_size) const override {
constexpr int kInvalidSize = 7;
return kInvalidSize; // length of "invalid"
}
void PrettyPrint(const Type* for_type, PrettyPrinter& printer) const override {
printer << Red << "invalid" << ResetColor;
}
void Visit(Visitor* visitor, const Type* for_type) const override;
};
// A null value.
class NullValue : public Value {
public:
NullValue() = default;
bool IsNull() const override { return true; }
size_t DisplaySize(const Type* for_type, size_t remaining_size) const override {
constexpr int kNullSize = 4;
return kNullSize; // length of "null"
}
void PrettyPrint(const Type* for_type, PrettyPrinter& printer) const override {
printer << Red << "null" << ResetColor;
}
void Visit(Visitor* visitor, const Type* for_type) const override;
};
// A value with no known representation (we only print the raw data).
class RawValue : public Value {
public:
RawValue(const uint8_t* data, size_t size) : data_(data, data + size) {}
const std::vector<uint8_t>& data() const { return data_; }
size_t DisplaySize(const Type* for_type, size_t remaining_size) const override;
void PrettyPrint(const Type* for_type, PrettyPrinter& printer) const override;
void Visit(Visitor* visitor, const Type* for_type) const override;
private:
const std::vector<uint8_t> data_;
};
// A Boolean value.
class BoolValue : public Value {
public:
explicit BoolValue(uint8_t value) : value_(value) {}
uint8_t value() const { return value_; }
size_t DisplaySize(const Type* for_type, size_t remaining_size) const override;
void PrettyPrint(const Type* for_type, PrettyPrinter& printer) const override;
void Visit(Visitor* visitor, const Type* for_type) const override;
private:
const uint8_t value_;
};
class IntegerValue : public Value {
public:
IntegerValue(uint64_t absolute_value, bool negative)
: absolute_value_(absolute_value), negative_(negative) {}
explicit IntegerValue(int64_t value)
: absolute_value_((value < 0) ? -static_cast<uint64_t>(value) : value),
negative_(value < 0) {}
explicit IntegerValue(uint64_t value) : absolute_value_(value), negative_(false) {}
uint64_t absolute_value() const { return absolute_value_; }
bool negative() const { return negative_; }
uint8_t GetUint8Value() const override;
bool GetIntegerValue(uint64_t* absolute, bool* negative) const override {
*absolute = absolute_value_;
*negative = negative_;
return true;
}
bool GetDoubleValue(double* result) const override {
*result = static_cast<double>(absolute_value_);
if (negative_) {
*result = -(*result);
}
return true;
}
size_t DisplaySize(const Type* for_type, size_t remaining_size) const override;
void PrettyPrint(const Type* for_type, PrettyPrinter& printer) const override;
void Visit(Visitor* visitor, const Type* for_type) const override;
private:
const uint64_t absolute_value_;
const bool negative_;
};
class DoubleValue : public Value {
public:
explicit DoubleValue(double value) : value_(value) {}
double value() const { return value_; }
bool GetIntegerValue(uint64_t* absolute, bool* negative) const override {
if (value_ < 0) {
*absolute = static_cast<uint64_t>(-value_);
*negative = true;
} else {
*absolute = static_cast<uint64_t>(value_);
*negative = false;
}
return true;
}
bool GetDoubleValue(double* result) const override {
*result = value_;
return true;
}
size_t DisplaySize(const Type* for_type, size_t remaining_size) const override;
void PrettyPrint(const Type* for_type, PrettyPrinter& printer) const override;
void Visit(Visitor* visitor, const Type* for_type) const override;
private:
const double value_;
};
// A string value.
class StringValue : public Value {
public:
explicit StringValue(std::string_view string) : string_(string) {}
const std::string& string() const { return string_; }
const StringValue* AsStringValue() const override { return this; }
size_t DisplaySize(const Type* for_type, size_t remaining_size) const override;
void PrettyPrint(const Type* for_type, PrettyPrinter& printer) const override;
void Visit(Visitor* visitor, const Type* for_type) const override;
private:
const std::string string_;
};
// A handle.
class HandleValue : public Value {
public:
explicit HandleValue(const zx_handle_disposition_t& handle) : handle_(handle) {}
const zx_handle_disposition_t& handle() const { return handle_; }
const HandleValue* AsHandleValue() const override { return this; }
bool NeedsToLoadHandleInfo(int64_t timestamp, zx_koid_t tid,
semantic::HandleSemantic* handle_semantic) const override;
size_t DisplaySize(const Type* for_type, size_t remaining_size) const override;
void PrettyPrint(const Type* for_type, PrettyPrinter& printer) const override;
void Visit(Visitor* visitor, const Type* for_type) const override;
private:
const zx_handle_disposition_t handle_;
};
// An union.
class UnionValue : public Value {
public:
UnionValue(const UnionMember& member, std::unique_ptr<Value> value)
: member_(member), value_(std::move(value)) {}
const UnionMember& member() const { return member_; }
const std::unique_ptr<Value>& value() const { return value_; }
bool NeedsToLoadHandleInfo(int64_t timestamp, zx_koid_t tid,
semantic::HandleSemantic* handle_semantic) const override;
size_t DisplaySize(const Type* for_type, size_t remaining_size) const override;
void PrettyPrint(const Type* for_type, PrettyPrinter& printer) const override;
void Visit(Visitor* visitor, const Type* for_type) const override;
private:
const UnionMember& member_;
const std::unique_ptr<Value> value_;
};
// An instance of a Struct. This includes requests and responses which are also structs.
class StructValue : public Value {
public:
explicit StructValue(const Struct& struct_definition) : struct_definition_(struct_definition) {}
const Struct& struct_definition() const { return struct_definition_; }
const std::map<const StructMember*, std::unique_ptr<Value>>& fields() const { return fields_; }
void AddField(const StructMember* member, std::unique_ptr<Value> value) {
fields_.emplace(std::make_pair(member, std::move(value)));
}
void inline AddField(std::string_view name, std::unique_ptr<Value> value) {
AddField(name, 0, std::move(value));
}
void AddField(std::string_view name, uint32_t id, std::unique_ptr<Value> value);
StructValue* AsStructValue() override { return this; }
const StructValue* AsStructValue() const override { return this; }
std::pair<const Type*, const Value*> GetFieldValue(std::string_view field_name) const;
bool NeedsToLoadHandleInfo(int64_t timestamp, zx_koid_t tid,
semantic::HandleSemantic* handle_semantic) const override;
size_t DisplaySize(const Type* for_type, size_t remaining_size) const override;
void PrettyPrint(const Type* for_type, PrettyPrinter& printer) const override;
void Visit(Visitor* visitor, const Type* for_type) const override;
// Extract the JSON for this object.
void ExtractJson(rapidjson::Document::AllocatorType& allocator, rapidjson::Value& result) const;
private:
const Struct& struct_definition_;
std::map<const StructMember*, std::unique_ptr<Value>> fields_;
};
// A vector.
class VectorValue : public Value {
public:
VectorValue() = default;
const std::vector<std::unique_ptr<Value>>& values() const { return values_; }
void AddValue(std::unique_ptr<Value> value) {
if (value == nullptr) {
is_string_ = false;
} else {
uint8_t uvalue = value->GetUint8Value();
if (!std::isprint(uvalue)) {
if ((uvalue == '\r') || (uvalue == '\n')) {
has_new_line_ = true;
} else {
is_string_ = false;
}
}
}
values_.push_back(std::move(value));
}
const VectorValue* AsVectorValue() const override { return this; }
bool NeedsToLoadHandleInfo(int64_t timestamp, zx_koid_t tid,
semantic::HandleSemantic* handle_semantic) const override;
size_t DisplaySize(const Type* for_type, size_t remaining_size) const override;
void PrettyPrint(const Type* for_type, PrettyPrinter& printer) const override;
void Visit(Visitor* visitor, const Type* for_type) const override;
private:
std::vector<std::unique_ptr<Value>> values_;
bool is_string_ = true;
bool has_new_line_ = false;
};
// A table.
class TableValue : public Value {
public:
explicit TableValue(const Table& table_definition) : table_definition_(table_definition) {}
const Table& table_definition() const { return table_definition_; }
const std::map<const TableMember*, std::unique_ptr<Value>>& members() const { return members_; }
Ordinal32 highest_member() const { return highest_member_; }
void AddMember(const TableMember* member, std::unique_ptr<Value> value) {
members_.emplace(std::make_pair(member, std::move(value)));
if (member->ordinal() > highest_member_) {
highest_member_ = member->ordinal();
}
}
bool AddMember(std::string_view name, std::unique_ptr<Value> value);
bool NeedsToLoadHandleInfo(int64_t timestamp, zx_koid_t tid,
semantic::HandleSemantic* handle_semantic) const override;
size_t DisplaySize(const Type* for_type, size_t remaining_size) const override;
void PrettyPrint(const Type* for_type, PrettyPrinter& printer) const override;
void Visit(Visitor* visitor, const Type* for_type) const override;
private:
const Table& table_definition_;
std::map<const TableMember*, std::unique_ptr<Value>> members_;
Ordinal32 highest_member_ = 0;
};
// An instance of a FIDL message.
class FidlMessageValue : public Value {
public:
FidlMessageValue(fidl_codec::DecodedMessage* message, std::string global_errors,
const uint8_t* bytes, uint32_t num_bytes, const zx_handle_disposition_t* handles,
uint32_t num_handles);
FidlMessageValue(zx_txid_t txid, uint64_t ordinal, const std::string& global_errors,
const std::string& epitaph_error, bool received, bool is_request,
bool unknown_direction, const fidl_codec::InterfaceMethod* method,
const uint8_t* bytes, size_t byte_size, const std::string& request_errors,
const std::string& response_errors)
: txid_(txid),
ordinal_(ordinal),
global_errors_(global_errors),
epitaph_error_(epitaph_error),
received_(received),
is_request_(is_request),
unknown_direction_(unknown_direction),
method_(method),
bytes_(bytes, bytes + byte_size),
request_errors_(request_errors),
response_errors_(response_errors) {}
zx_txid_t txid() const { return txid_; }
uint64_t ordinal() const { return ordinal_; }
const std::string& global_errors() const { return global_errors_; }
const std::string& epitaph_error() const { return epitaph_error_; }
bool received() const { return received_; }
bool is_request() const { return is_request_; }
bool unknown_direction() const { return unknown_direction_; }
const fidl_codec::InterfaceMethod* method() const { return method_; }
const std::vector<uint8_t>& bytes() const { return bytes_; }
const std::vector<zx_handle_disposition_t>& handles() const { return handles_; }
void add_handle(const zx_handle_disposition_t& handle) { handles_.emplace_back(handle); }
const StructValue* decoded_request() const { return decoded_request_.get(); }
void set_decoded_request(std::unique_ptr<StructValue> decoded_request) {
decoded_request_ = std::move(decoded_request);
}
const std::string& request_errors() const { return request_errors_; }
const StructValue* decoded_response() const { return decoded_response_.get(); }
void set_decoded_response(std::unique_ptr<StructValue> decoded_response) {
decoded_response_ = std::move(decoded_response);
}
const std::string& response_errors() const { return response_errors_; }
bool matched_request() const { return (decoded_request_ != nullptr) && request_errors_.empty(); }
bool matched_response() const {
return (decoded_response_ != nullptr) && response_errors_.empty();
}
const FidlMessageValue* AsFidlMessageValue() const override { return this; }
bool NeedsToLoadHandleInfo(int64_t timestamp, zx_koid_t tid,
semantic::HandleSemantic* handle_semantic) const override;
size_t DisplaySize(const Type* for_type, size_t remaining_size) const override;
void PrettyPrint(const Type* for_type, PrettyPrinter& printer) const override;
void PrintMessage(PrettyPrinter& printer) const;
void PrintMessageBody(PrettyPrinter& printer) const;
void DumpMessage(PrettyPrinter& printer) const;
void Visit(Visitor* visitor, const Type* for_type) const override;
private:
// The transfer ID of the mesage.
const zx_txid_t txid_;
// The ordinal of the message.
const uint64_t ordinal_;
// Global errors for the message (errors before we can start decoding anything).
const std::string global_errors_;
// Text value of the error status of the epitaph.
const std::string epitaph_error_;
// True if the message was received.
const bool received_;
// True if the message is a request. False if the message is a response.
const bool is_request_;
// True if we haven't been able to select a request of a response (case where both can be
// decoded).
const bool unknown_direction_;
// The method associated with the ordinal.
const fidl_codec::InterfaceMethod* const method_;
// All the bytes of the message.
std::vector<uint8_t> bytes_;
// All the handles of the message.
std::vector<zx_handle_disposition_t> handles_;
// Value of the request we have been able to decode.
std::unique_ptr<StructValue> decoded_request_;
// Errors generated during the decoding of the request. If not empty, decoded_request_ holds only
// a partial result.
const std::string request_errors_;
// Value of the response we have been able to decode.
std::unique_ptr<StructValue> decoded_response_;
// Errors generated during the decoding of the response. If not empty, decoded_response_ holds
// only a partial result.
const std::string response_errors_;
};
} // namespace fidl_codec
#endif // SRC_LIB_FIDL_CODEC_WIRE_OBJECT_H_