xref: /aosp_15_r20/system/chre/platform/shared/pw_trace/include/chre/target_platform/tracing_util.h (revision 84e339476a462649f82315436d70fd732297a399)
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_