blob: 4da18e2bf122e66bfbc788e5cbedbf0ca600ef4c [file] [log] [blame]
// Copyright 2020 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_TRACE_H_
#define LIB_FIDL_TRACE_H_
#include <stdint.h>
#include <zircon/compiler.h>
__BEGIN_CDECLS
// This in C, not C++, since the FIDL C bindings call into this.
typedef struct fidl_type fidl_type_t;
typedef enum fidl_trigger_tag {
// Note that it's possible to split this enum into two: the type ("LLCPP
// encode" vs "LLCPP decode") and stage ("before"/"after", or "will/did"). We
// aggregate both those concepts into a single enum to reduce the total number
// of arguments passed to fidl_trace (by way of the fidl_trace_t struct), to
// try to ensure that at least the arguments are passed in registers. This is
// arguably premature optimization, but the API surface for fidl_trace is
// small, so the consequences of this design doesn't leak out past the
// immediate call sites.
// LLCPP
kFidlTriggerWillLLCPPInPlaceEncode,
kFidlTriggerDidLLCPPInPlaceEncode,
kFidlTriggerWillLLCPPLinearizeAndEncode,
kFidlTriggerDidLLCPPLinearizeAndEncode,
kFidlTriggerWillLLCPPDecode,
kFidlTriggerDidLLCPPDecode,
kFidlTriggerWillLLCPPChannelWrite,
kFidlTriggerDidLLCPPChannelWrite,
kFidlTriggerWillLLCPPChannelCall,
kFidlTriggerDidLLCPPChannelCall,
// LLCPP Async
kFidlTriggerWillLLCPPAsyncChannelRead,
kFidlTriggerDidLLCPPAsyncChannelRead,
// HLCPP
kFidlTriggerWillHLCPPEncode,
kFidlTriggerDidHLCPPEncode,
kFidlTriggerWillHLCPPDecode,
kFidlTriggerDidHLCPPDecode,
kFidlTriggerWillHLCPPValidate,
kFidlTriggerDidHLCPPValidate,
kFidlTriggerWillHLCPPChannelWrite,
kFidlTriggerDidHLCPPChannelWrite,
kFidlTriggerWillHLCPPChannelRead,
kFidlTriggerDidHLCPPChannelRead,
kFidlTriggerWillHLCPPChannelCall,
kFidlTriggerDidHLCPPChannelCall,
// C
kFidlTriggerWillCChannelRead,
kFidlTriggerDidCChannelRead,
kFidlTriggerWillCChannelWrite,
kFidlTriggerDidCChannelWrite,
} fidl_trigger_t;
typedef struct fidl_trace_tag {
fidl_trigger_t trigger;
uint16_t handle_count;
uint32_t size;
const void* data;
const fidl_type_t* type;
} fidl_trace_t;
// fidl_trace() is a convenience macro, so that call sites can call
// fidl_trace_impl() with one line, instead of needing to a build a fidl_trace_t
// at the call-site, which uses multiple lines and impedes readability. See
// <https://fuchsia-review.googlesource.com/c/fuchsia/+/405957/4/zircon/system/ulib/fidl/message.cc#60>
// for more context.
//
// The macro is "overloaded" on the number of arguments, and dispatches to
// FIDL_TRACE_n macros for n-number of arguments. See
// <https://stackoverflow.com/questions/11761703/overloading-macro-on-number-of-arguments>
// for a description of the technique.
#define FIDL_TRACE_GET_MACRO(_1, _2, _3, _4, _5, MACRO_NAME, ...) MACRO_NAME
#define fidl_trace(...) \
FIDL_TRACE_GET_MACRO(__VA_ARGS__, FIDL_TRACE_5 /* macro for 5 args */, \
FIDL_TRACE_INVALID_ARGS /* macro for 4 args */, \
FIDL_TRACE_INVALID_ARGS /* macro for 3 args */, \
FIDL_TRACE_INVALID_ARGS /* macro for 2 args */, \
FIDL_TRACE_1 /* macro for 1 arg */) \
(__VA_ARGS__)
#define FIDL_TRACE_INVALID_ARGS(...) INVALID_NUMBER_OF_ARGUMENTS_PASSED_TO_FIDL_TRACE_MACRO
#define FIDL_TRACE_1(trigger_name) \
FIDL_TRACE_5(trigger_name, NULL /* type */, NULL /* data */, 0 /* size */, 0 /* handle_count */)
#define FIDL_TRACE_5(trigger_name, type_, data_, size_, handle_count_) \
fidl_trace_impl((fidl_trace_t){ \
.trigger = kFidlTrigger##trigger_name, \
.handle_count = (uint16_t)handle_count_, \
.size = (uint32_t)size_, \
.data = data_, \
.type = type_, \
})
#ifndef FIDL_TRACE_LEVEL
// The build system is generally expected to define FIDL_TRACE_LEVEL for
// anything that uses FIDL, but this may not be possible if e.g. the Fuchsia SDK
// being used with other build systems. If FIDL_TRACE_LEVEL isn't defined, it's
// reasonable to assume that tracing isn't wanted.
#define FIDL_TRACE_LEVEL 0
#endif
#if FIDL_TRACE_LEVEL == 0
static inline void fidl_trace_impl(const fidl_trace_t trace_info) {
// This function is explicitly a no-op. Note that current compilers completely
// elide a call to this with any level of optimization (-O1, -O2, -Os etc), for
// both C & C++. See <https://godbolt.org/z/bEa6zG> for an example.
//
// Future implementations will replace this fidl_trace_impl() function with a
// version that may record the trace (e.g. via the Fuchsia Tracing System).
}
#elif FIDL_TRACE_LEVEL == 1
static inline void fidl_trace_impl(const fidl_trace_t trace_info) {
// We define this no-op implementation of fidl_trace_impl when
// FIDL_TRACE_LEVEL == 1, so that we can compile the Rust bindings with `fx
// set ... --args fidl_trace_level=1`. This no-op implementation will be
// replaced with a call to the Fuchsia Tracing System in the future.
}
#else
#error Unknown FIDL_TRACE_LEVEL.
#endif // FIDL_TRACE_LEVEL
__END_CDECLS
#endif // LIB_FIDL_TRACE_H_