Enforce ABI size checks
[libside.git] / include / side / macros.h
1 // SPDX-License-Identifier: MIT
2 /*
3 * Copyright 2022 Mathieu Desnoyers <mathieu.desnoyers@efficios.com>
4 */
5
6 #ifndef _SIDE_MACROS_H
7 #define _SIDE_MACROS_H
8
9 #include <stddef.h>
10 #include <limits.h>
11 #include <stdint.h>
12 #include <side/endian.h>
13
14 /* Helper macros */
15
16 #define SIDE_ARRAY_SIZE(arr) (sizeof(arr) / sizeof((arr)[0]))
17
18 /*
19 * Compound literals with static storage are needed by SIDE
20 * instrumentation.
21 * Compound literals are part of the C99 and C11 standards, but not
22 * part of the C++ standards. They are supported by most C++ compilers
23 * though.
24 *
25 * Example use:
26 * static struct mystruct *var = LTTNG_UST_COMPOUND_LITERAL(struct mystruct, { 1, 2, 3 });
27 */
28 #define SIDE_COMPOUND_LITERAL(type, ...) (type[]) { __VA_ARGS__ }
29
30 #define side_likely(x) __builtin_expect(!!(x), 1)
31 #define side_unlikely(x) __builtin_expect(!!(x), 0)
32
33 #define SIDE_PARAM(...) __VA_ARGS__
34
35 /*
36 * SIDE_PARAM_SELECT_ARG1
37 *
38 * Select second argument. Use inside macros to implement optional last
39 * macro argument, such as:
40 *
41 * #define macro(_a, _b, _c, _optional...) \
42 * SIDE_PARAM_SELECT_ARG1(_, ##_optional, do_default_macro())
43 *
44 * This macro is far from pretty, but attempts to create a cleaner layer
45 * on top fails for various reasons:
46 *
47 * - The libside API needs to use the default argument selection as an
48 * argument to itself (recursively), e.g. for fields and for types, so
49 * using the argument selection within an extra layer of macro fails
50 * because the extra layer cannot expand recursively.
51 * - Attempts to make the extra layer of macro support recursion through
52 * another layer of macros which expands all arguments failed because
53 * the optional argument may contain commas, and is therefore expanded
54 * into multiple arguments before argument selection, which fails to
55 * select the optional argument content after its first comma.
56 */
57 #define SIDE_PARAM_SELECT_ARG1(_arg0, _arg1, ...) _arg1
58
59 /*
60 * Compile time assertion.
61 * - predicate: boolean expression to evaluate,
62 * - msg: string to print to the user on failure when `static_assert()` is
63 * supported,
64 * - c_identifier_msg: message to be included in the typedef to emulate a
65 * static assertion. This parameter must be a valid C identifier as it will
66 * be used as a typedef name.
67 */
68 #ifdef __cplusplus
69 #define side_static_assert(predicate, msg, c_identifier_msg) \
70 static_assert(predicate, msg)
71 #elif defined(__STDC_VERSION__) && (__STDC_VERSION__ >= 201112L)
72 #define side_static_assert(predicate, msg, c_identifier_msg) \
73 _Static_assert(predicate, msg)
74 #else
75 /*
76 * Evaluates the predicate and emit a compilation error on failure.
77 *
78 * If the predicate evaluates to true, this macro emits a function
79 * prototype with an argument type which is an array of size 0.
80 *
81 * If the predicate evaluates to false, this macro emits a function
82 * prototype with an argument type which is an array of negative size
83 * which is invalid in C and forces a compiler error. The
84 * c_identifier_msg parameter is used as the argument identifier so it
85 * is printed to the user when the error is reported.
86 */
87 #define side_static_assert(predicate, msg, c_identifier_msg) \
88 void side_static_assert_proto(char c_identifier_msg[2*!!(predicate)-1])
89 #endif
90
91 /*
92 * side_container_of - Get the address of an object containing a field.
93 *
94 * @ptr: pointer to the field.
95 * @type: type of the object.
96 * @member: name of the field within the object.
97 */
98 #define side_container_of(ptr, type, member) \
99 __extension__ \
100 ({ \
101 const __typeof__(((type *) NULL)->member) * __ptr = (ptr); \
102 (type *)((char *)__ptr - offsetof(type, member)); \
103 })
104
105 #define side_struct_field_sizeof(_struct, _field) \
106 sizeof(((_struct * )NULL)->_field)
107
108 #define SIDE_PACKED __attribute__((packed))
109
110 #define side_padding(bytes) char padding[bytes]
111
112 #define side_check_size(_type, _len) \
113 side_static_assert(sizeof(_type) == (_len), \
114 "Unexpected size for type: `" #_type "`", \
115 unexpected_size_for_type_##_type)
116
117 #if (SIDE_BYTE_ORDER == SIDE_LITTLE_ENDIAN)
118 #define SIDE_ENDIAN_ORDER(_low, _high) _low, _high
119 #else
120 #define SIDE_ENDIAN_ORDER(_low, _high) _high, _low
121 #endif
122
123 /*
124 * The side_ptr macros allow defining a pointer type which is suitable
125 * for use by 32-bit, 64-bit and 128-bit kernels without compatibility
126 * code, while preserving information about the pointer type.
127 *
128 * Those pointers are stored as 128-bit integers, and the type of the
129 * actual pointer is kept alongside with the 128-bit pointer value in a
130 * 0-len array within a union.
131 */
132 #if (__SIZEOF_POINTER__ <= 8)
133 # define side_raw_ptr_t(_type) \
134 union { \
135 struct { \
136 uint64_t SIDE_ENDIAN_ORDER(low, high); \
137 } v; \
138 struct { \
139 _type t[0]; \
140 } SIDE_PACKED s; \
141 side_padding(16); \
142 }
143 # define side_ptr_get(_field) \
144 ((__typeof__((_field).s.t[0]))(uintptr_t)(_field).v.low)
145 # define side_ptr_set(_field, _ptr) \
146 do { \
147 (_field).v.low = (uint64_t)(uintptr_t)(_ptr); \
148 (_field).v.high = 0; \
149 } while (0)
150
151 /* Keep the correct field init order to make old g++ happy. */
152 # if (SIDE_BYTE_ORDER == SIDE_LITTLE_ENDIAN)
153 # define SIDE_PTR_INIT(...) \
154 { \
155 .v = { \
156 .low = (uintptr_t) (__VA_ARGS__), \
157 .high = 0, \
158 }, \
159 }
160 # else
161 # define SIDE_PTR_INIT(...) \
162 { \
163 .v = { \
164 .high = 0, \
165 .low = (uintptr_t) (__VA_ARGS__), \
166 }, \
167 }
168 # endif
169 #elif (__SIZEOF_POINTER__ == 16)
170 # define side_raw_ptr_t(_type) \
171 union { \
172 uintptr_t v; \
173 struct { \
174 _type t[0]; \
175 } SIDE_PACKED s; \
176 side_padding(16); \
177 }
178 # define side_ptr_get(_field) \
179 ((__typeof__((_field).s.t[0]))(_field).v)
180 # define side_ptr_set(_field, _ptr) \
181 do { \
182 (_field).v = (uintptr_t)(_ptr); \
183 } while (0)
184 # define SIDE_PTR_INIT(...) { .v = (uintptr_t) (__VA_ARGS__) }
185 #else
186 # error "Unsupported pointer size"
187 #endif
188
189 #define side_ptr_t(_type) side_raw_ptr_t(_type *)
190 #define side_func_ptr_t(_type) side_raw_ptr_t(_type)
191
192 side_static_assert(sizeof(side_ptr_t(int)) == 16,
193 "Unexpected size for side_ptr_t",
194 unexpected_size_side_ptr_t);
195
196 /*
197 * side_enum_t allows defining fixed-sized enumerations while preserving
198 * typing information.
199 */
200 #define side_enum_t(_enum_type, _size_type) \
201 union { \
202 _size_type v; \
203 struct { \
204 _enum_type t[0]; \
205 } SIDE_PACKED s; \
206 }
207
208 #define side_enum_get(_field) \
209 ((__typeof__((_field).s.t[0]))(_field).v)
210
211 #define side_enum_set(_field, _v) \
212 do { \
213 (_field).v = (_v); \
214 } while (0)
215
216 #define SIDE_ENUM_INIT(...) { .v = (__VA_ARGS__) }
217
218 #endif /* _SIDE_MACROS_H */
This page took 0.033141 seconds and 4 git commands to generate.