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