1 /*
2 * Copyright (C) 2023 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17 #ifndef CHRE_PLATFORM_SHARED_TRACING_UTIL_H_
18 #define CHRE_PLATFORM_SHARED_TRACING_UTIL_H_
19
20 #include "chre/util/macros.h"
21
22 namespace tracing_internal {
23
24 // Check to make sure pointer size macro is defined.
25 #ifndef __SIZEOF_POINTER__
26 #error "__SIZEOF_POINTER__ macro not defined - unsupported toolchain being used"
27 #endif
28
29 constexpr size_t kMaxTraceDataSize = 256;
30
31 template <typename T>
chreTraceGetSizeOf()32 inline constexpr std::size_t chreTraceGetSizeOf() {
33 if constexpr (std::is_pointer_v<T>) {
34 return __SIZEOF_POINTER__;
35 }
36
37 return sizeof(T);
38 }
39
40 /**
41 * Special case for strings.
42 *
43 * Due to how python struct unpacking works, reading strings requires the data
44 * format string to specify the length of buffer containing the string.
45 * PW_TRACE macros require the data format string to be a string literal, and we
46 * don't always know the str length at compile-time and thus opt to put all
47 * strings in a fixed size buffer of length CHRE_TRACE_MAX_STRING_SIZE. Using
48 * the pascal string option indicates the buffer's first byte contains the size
49 * of string, followed by the string characters.
50 */
51 template <>
52 inline constexpr std::size_t chreTraceGetSizeOf<const char *>() {
53 return CHRE_TRACE_STR_BUFFER_SIZE;
54 }
55 template <>
56 inline constexpr std::size_t chreTraceGetSizeOf<char *>() {
57 return chreTraceGetSizeOf<const char *>();
58 }
59
60 template <typename... Types>
chreTraceGetSizeOfVarArgs()61 constexpr std::size_t chreTraceGetSizeOfVarArgs() {
62 return (chreTraceGetSizeOf<std::decay_t<Types>>() + ...);
63 }
64
65 template <typename Data>
chreTraceInsertVar(uint8_t * buffer,Data data,std::size_t dataSize)66 inline void chreTraceInsertVar(uint8_t *buffer, Data data,
67 std::size_t dataSize) {
68 static_assert(std::is_integral_v<Data> || std::is_pointer_v<Data>,
69 "Unsupported data type");
70 memcpy(buffer, &data, dataSize);
71 }
72 template <>
73 inline void chreTraceInsertVar<const char *>(uint8_t *buffer, const char *data,
74 std::size_t) {
75 // Insert size byte metadata as the first byte of the pascal string.
76 *buffer = static_cast<uint8_t>(strnlen(data, CHRE_TRACE_MAX_STRING_SIZE));
77
78 // Insert string after size byte and zero out remainder of buffer.
79 strncpy(reinterpret_cast<char *>(buffer + 1), data,
80 CHRE_TRACE_MAX_STRING_SIZE);
81 }
82 template <>
83 inline void chreTraceInsertVar<char *>(uint8_t *buffer, char *data,
84 std::size_t dataSize) {
85 chreTraceInsertVar<const char *>(buffer, data, dataSize);
86 }
87
88 /**
89 * Populate the pre-allocated buffer with data passed in.
90 * Should only be called in the CHRE_TRACE_ALLOCATE_AND_POPULATE_DATA_BUFFER
91 * macro.
92 *
93 * Example Usage:
94 * uint_16_t data1; char data2; uint32_t data3;
95 * ... // define data
96 * chreTracePopulateBufferWithArgs(buf, data1, data2, data3);
97 *
98 * @param buffer A buffer to insert data into.
99 * Assumed to be large enough to hold all data since we use the
100 * same size logic to allocate space for the buffer.
101 * @param data Single piece of data to insert into the buffer. Assumed to
102 * have >= 1 data element to insert into the buffer. Strings
103 * assumed to be null-terminated or have length >=
104 * CHRE_TRACE_MAX_STRING_SIZE.
105 * @param args Variable length argument to hold the remainder of the data
106 * to insert into the buffer.
107 */
108 template <typename Data, typename... Types>
chreTracePopulateBufferWithArgs(uint8_t * buffer,Data data,Types...args)109 void chreTracePopulateBufferWithArgs(uint8_t *buffer, Data data,
110 Types... args) {
111 constexpr std::size_t dataSize = chreTraceGetSizeOf<Data>();
112 tracing_internal::chreTraceInsertVar(buffer, data, dataSize);
113 buffer += dataSize;
114
115 if constexpr (sizeof...(args) > 0) {
116 chreTracePopulateBufferWithArgs(buffer, args...);
117 }
118 }
119
120 // Create and populate the chreTraceDataBuffer. We allocate only the amount of
121 // space required to store all data.
122 // Unscoped to export the variables holding the buffer and data size.
123 #define CHRE_TRACE_ALLOCATE_AND_POPULATE_DATA_BUFFER(...) \
124 constexpr std::size_t chreTraceDataSize = \
125 tracing_internal::chreTraceGetSizeOfVarArgs<TYPE_LIST(__VA_ARGS__)>(); \
126 static_assert(chreTraceDataSize <= tracing_internal::kMaxTraceDataSize, \
127 "Trace data size too large"); \
128 uint8_t chreTraceDataBuffer[chreTraceDataSize]; \
129 tracing_internal::chreTracePopulateBufferWithArgs(chreTraceDataBuffer, \
130 __VA_ARGS__);
131
132 } // namespace tracing_internal
133
134 #endif // CHRE_PLATFORM_SHARED_TRACING_UTIL_H_