1 // Copyright 2018 The Fuchsia Authors. All rights reserved. 2 // Use of this source code is governed by a BSD-style license that can be 3 // found in the LICENSE file. 4 5 // Internal implementation of <trace/event_args.h>. 6 // This is not part of the public API: use <trace/event_args.h> instead. 7 // 8 // TODO(dje): The presence of NEW_ on macros everywhere here is to avoid 9 // collisions with external use of our internal macros. Remove "NEW_" when 10 // all external usage has been removed. 11 12 #ifndef TRACE_INTERNAL_EVENT_ARGS_H_ 13 #define TRACE_INTERNAL_EVENT_ARGS_H_ 14 15 #include <assert.h> 16 17 #include <zircon/compiler.h> 18 19 #include <trace-engine/context.h> 20 #include <trace-engine/types.h> 21 #include <trace/internal/pairs_internal.h> 22 23 // TODO(dje): Remove "NEW_". It exists for now to minimize changes to 24 // internal/event_internal.h. 25 #define TRACE_INTERNAL_NEW_NUM_ARGS(variable_name) \ 26 (sizeof(variable_name) / sizeof((variable_name)[0])) 27 28 // Note: Argument names are processed in two steps. The first step is here 29 // where we store the string in |name_ref.inline_string|. The second step is 30 // done by |trace_internal_complete_args()| which is normally called by the 31 // helper routines that finish recording the event. 32 33 #ifdef __cplusplus 34 35 #define TRACE_INTERNAL_NEW_SCOPE_ARG_LABEL(var_name, idx) \ 36 __trace_arg_##var_name##idx 37 38 #define TRACE_INTERNAL_NEW_HOLD_ARG(var_name, idx, name_literal, arg_value) \ 39 const auto& TRACE_INTERNAL_NEW_SCOPE_ARG_LABEL(var_name, idx) = (arg_value); 40 #define TRACE_INTERNAL_NEW_MAKE_ARG(var_name, idx, name_literal, arg_value) \ 41 { .name_ref = {.encoded_value = 0, .inline_string = (name_literal)}, \ 42 .value = ::trace::internal::MakeArgumentValue( \ 43 TRACE_INTERNAL_NEW_SCOPE_ARG_LABEL(var_name, idx)) } 44 45 #define TRACE_INTERNAL_NEW_DECLARE_ARGS(context, var_name, args...) \ 46 TRACE_INTERNAL_APPLY_PAIRWISE(TRACE_INTERNAL_NEW_HOLD_ARG, var_name, args) \ 47 trace_arg_t var_name[] = { \ 48 TRACE_INTERNAL_APPLY_PAIRWISE_CSV(TRACE_INTERNAL_NEW_MAKE_ARG, \ 49 var_name, args)}; \ 50 static_assert(TRACE_INTERNAL_NEW_NUM_ARGS(var_name) <= TRACE_MAX_ARGS, "too many args") 51 52 #else 53 54 #define TRACE_INTERNAL_NEW_MAKE_ARG(var_name, idx, name_literal, arg_value) \ 55 { .name_ref = {.encoded_value = 0, .inline_string = (name_literal)}, \ 56 .value = (arg_value) } 57 58 #define TRACE_INTERNAL_NEW_DECLARE_ARGS(context, var_name, args...) \ 59 trace_arg_t var_name[] = { \ 60 TRACE_INTERNAL_APPLY_PAIRWISE_CSV(TRACE_INTERNAL_NEW_MAKE_ARG, \ 61 var_name, args)}; \ 62 static_assert(TRACE_INTERNAL_NEW_NUM_ARGS(var_name) <= TRACE_MAX_ARGS, "too many args") 63 64 #endif // __cplusplus 65 66 __BEGIN_CDECLS 67 void trace_internal_complete_args(trace_context_t* context, 68 trace_arg_t* args, size_t num_args); 69 __END_CDECLS 70 71 #define TRACE_INTERNAL_COMPLETE_ARGS(context, args, num_args) \ 72 do { \ 73 trace_internal_complete_args((context), (args), (num_args)); \ 74 } while (0) 75 76 #ifdef __cplusplus 77 78 #include <fbl/string_traits.h> 79 #include <type_traits> 80 81 namespace trace { 82 namespace internal { 83 84 // Helps construct trace argument values using SFINAE to coerce types. 85 template <typename T, typename Enable = void> 86 struct ArgumentValueMaker; 87 88 template <> 89 struct ArgumentValueMaker<trace_arg_value_t> { 90 static trace_arg_value_t Make(trace_arg_value_t value) { 91 return value; 92 } 93 }; 94 95 template <> 96 struct ArgumentValueMaker<decltype(nullptr)> { 97 static trace_arg_value_t Make(decltype(nullptr) value) { 98 return trace_make_null_arg_value(); 99 } 100 }; 101 102 template <typename T> 103 struct ArgumentValueMaker< 104 T, 105 typename std::enable_if<std::is_signed<T>::value && 106 std::is_integral<T>::value && 107 (sizeof(T) <= sizeof(int32_t))>::type> { 108 static trace_arg_value_t Make(int32_t value) { 109 return trace_make_int32_arg_value(value); 110 } 111 }; 112 113 template <typename T> 114 struct ArgumentValueMaker< 115 T, 116 typename std::enable_if<std::is_unsigned<T>::value && 117 (sizeof(T) <= sizeof(uint32_t))>::type> { 118 static trace_arg_value_t Make(uint32_t value) { 119 return trace_make_uint32_arg_value(value); 120 } 121 }; 122 123 template <typename T> 124 struct ArgumentValueMaker< 125 T, 126 typename std::enable_if<std::is_signed<T>::value && 127 std::is_integral<T>::value && 128 (sizeof(T) > sizeof(int32_t)) && 129 (sizeof(T) <= sizeof(int64_t))>::type> { 130 static trace_arg_value_t Make(int64_t value) { 131 return trace_make_int64_arg_value(value); 132 } 133 }; 134 135 template <typename T> 136 struct ArgumentValueMaker< 137 T, 138 typename std::enable_if<std::is_unsigned<T>::value && 139 (sizeof(T) > sizeof(uint32_t)) && 140 (sizeof(T) <= sizeof(uint64_t))>::type> { 141 static trace_arg_value_t Make(uint64_t value) { 142 return trace_make_uint64_arg_value(value); 143 } 144 }; 145 146 template <typename T> 147 struct ArgumentValueMaker<T, typename std::enable_if<std::is_enum<T>::value>::type> { 148 using UnderlyingType = typename std::underlying_type<T>::type; 149 static trace_arg_value_t Make(UnderlyingType value) { 150 return ArgumentValueMaker<UnderlyingType>::Make(value); 151 } 152 }; 153 154 template <typename T> 155 struct ArgumentValueMaker< 156 T, 157 typename std::enable_if<std::is_floating_point<T>::value>::type> { 158 static trace_arg_value_t Make(double value) { 159 return trace_make_double_arg_value(value); 160 } 161 }; 162 163 template <size_t n> 164 struct ArgumentValueMaker<char[n]> { 165 static trace_arg_value_t Make(const char* value) { 166 return trace_make_string_arg_value( 167 trace_make_inline_string_ref(value, n)); 168 } 169 }; 170 171 template <> 172 struct ArgumentValueMaker<const char*> { 173 static trace_arg_value_t Make(const char* value) { 174 return trace_make_string_arg_value( 175 trace_make_inline_c_string_ref(value)); 176 } 177 }; 178 179 // Works with various string types including fbl::String, fbl::StringView, 180 // std::string, and std::string_view. 181 template <typename T> 182 struct ArgumentValueMaker<T, 183 typename std::enable_if<fbl::is_string_like<T>::value>::type> { 184 static trace_arg_value_t Make(const T& value) { 185 return trace_make_string_arg_value( 186 trace_make_inline_string_ref(fbl::GetStringData(value), 187 fbl::GetStringLength(value))); 188 } 189 }; 190 191 template <typename T> 192 struct ArgumentValueMaker<T*> { 193 static trace_arg_value_t Make(const T* pointer) { 194 return trace_make_pointer_arg_value(reinterpret_cast<uintptr_t>(pointer)); 195 } 196 }; 197 198 template <typename T> 199 trace_arg_value_t MakeArgumentValue(const T& value) { 200 return ArgumentValueMaker<T>::Make(value); 201 } 202 203 } // namespace internal 204 } // namespace trace 205 206 #endif // __cplusplus 207 208 #endif // TRACE_INTERNAL_EVENT_ARGS_H_ 209