Commit | Line | Data |
---|---|---|
9e7f0924 MD |
1 | #ifndef _BABELTRACE_BITFIELD_H |
2 | #define _BABELTRACE_BITFIELD_H | |
3 | ||
4 | /* | |
fa81c5df | 5 | * Copyright 2010-2019 - Mathieu Desnoyers <mathieu.desnoyers@efficios.com> |
9e7f0924 MD |
6 | * |
7 | * Permission is hereby granted, free of charge, to any person obtaining a copy | |
8 | * of this software and associated documentation files (the "Software"), to deal | |
9 | * in the Software without restriction, including without limitation the rights | |
10 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell | |
11 | * copies of the Software, and to permit persons to whom the Software is | |
12 | * furnished to do so, subject to the following conditions: | |
13 | * | |
14 | * The above copyright notice and this permission notice shall be included in | |
15 | * all copies or substantial portions of the Software. | |
d2428e87 MD |
16 | * |
17 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR | |
18 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, | |
19 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE | |
20 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER | |
21 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, | |
22 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE | |
23 | * SOFTWARE. | |
9e7f0924 MD |
24 | */ |
25 | ||
9f3fdbc6 MD |
26 | #include <stdint.h> /* C99 5.2.4.2 Numerical limits */ |
27 | #include <limits.h> /* C99 5.2.4.2 Numerical limits */ | |
2ae57758 | 28 | #include <lttng/ust-endian.h> /* Non-standard BIG_ENDIAN, LITTLE_ENDIAN, BYTE_ORDER */ |
9e7f0924 | 29 | |
fa81c5df MD |
30 | /* |
31 | * This header strictly follows the C99 standard, except for use of the | |
32 | * compiler-specific __typeof__. | |
33 | */ | |
34 | ||
35 | /* | |
36 | * This bitfield header requires the compiler representation of signed | |
37 | * integers to be two's complement. | |
38 | */ | |
39 | #if (-1 != ~0) | |
40 | #error "bitfield.h requires the compiler representation of signed integers to be two's complement." | |
41 | #endif | |
9e7f0924 | 42 | |
72914f82 | 43 | #define _bt_is_signed_type(type) ((type) -1 < (type) 0) |
9e7f0924 | 44 | |
fa81c5df MD |
45 | /* |
46 | * Produce a build-time error if the condition `cond` is non-zero. | |
47 | * Evaluates as a size_t expression. | |
48 | */ | |
49 | #define _BT_BUILD_ASSERT(cond) \ | |
50 | sizeof(struct { int f:(2 * !!(cond) - 1); }) | |
51 | ||
52 | /* | |
53 | * Cast value `v` to an unsigned integer of the same size as `v`. | |
54 | */ | |
55 | #define _bt_cast_value_to_unsigned(v) \ | |
56 | (sizeof(v) == sizeof(uint8_t) ? (uint8_t) (v) : \ | |
57 | sizeof(v) == sizeof(uint16_t) ? (uint16_t) (v) : \ | |
58 | sizeof(v) == sizeof(uint32_t) ? (uint32_t) (v) : \ | |
59 | sizeof(v) == sizeof(uint64_t) ? (uint64_t) (v) : \ | |
60 | _BT_BUILD_ASSERT(sizeof(v) <= sizeof(uint64_t))) | |
61 | ||
62 | /* | |
63 | * Cast value `v` to an unsigned integer type of the size of type `type` | |
64 | * *without* sign-extension. | |
65 | * | |
66 | * The unsigned cast ensures that we're not shifting a negative value, | |
67 | * which is undefined in C. However, this limits the maximum type size | |
68 | * of `type` to 64-bit. Generate a compile-time error if the size of | |
69 | * `type` is larger than 64-bit. | |
70 | */ | |
71 | #define _bt_cast_value_to_unsigned_type(type, v) \ | |
72 | (sizeof(type) == sizeof(uint8_t) ? \ | |
73 | (uint8_t) _bt_cast_value_to_unsigned(v) : \ | |
74 | sizeof(type) == sizeof(uint16_t) ? \ | |
75 | (uint16_t) _bt_cast_value_to_unsigned(v) : \ | |
76 | sizeof(type) == sizeof(uint32_t) ? \ | |
77 | (uint32_t) _bt_cast_value_to_unsigned(v) : \ | |
78 | sizeof(type) == sizeof(uint64_t) ? \ | |
79 | (uint64_t) _bt_cast_value_to_unsigned(v) : \ | |
80 | _BT_BUILD_ASSERT(sizeof(v) <= sizeof(uint64_t))) | |
81 | ||
82 | /* | |
83 | * _bt_fill_mask evaluates to a "type" integer with all bits set. | |
84 | */ | |
85 | #define _bt_fill_mask(type) ((type) ~(type) 0) | |
86 | ||
87 | /* | |
88 | * Left shift a value `v` of `shift` bits. | |
89 | * | |
90 | * The type of `v` can be signed or unsigned integer. | |
91 | * The value of `shift` must be less than the size of `v` (in bits), | |
92 | * otherwise the behavior is undefined. | |
93 | * Evaluates to the result of the shift operation. | |
94 | * | |
95 | * According to the C99 standard, left shift of a left hand-side signed | |
96 | * type is undefined if it has a negative value or if the result cannot | |
97 | * be represented in the result type. This bitfield header discards the | |
98 | * bits that are left-shifted beyond the result type representation, | |
99 | * which is the behavior of an unsigned type left shift operation. | |
100 | * Therefore, always perform left shift on an unsigned type. | |
101 | * | |
102 | * This macro should not be used if `shift` can be greater or equal than | |
103 | * the bitwidth of `v`. See `_bt_safe_lshift`. | |
104 | */ | |
105 | #define _bt_lshift(v, shift) \ | |
106 | ((__typeof__(v)) (_bt_cast_value_to_unsigned(v) << (shift))) | |
107 | ||
108 | /* | |
109 | * Generate a mask of type `type` with the `length` least significant bits | |
110 | * cleared, and the most significant bits set. | |
111 | */ | |
112 | #define _bt_make_mask_complement(type, length) \ | |
113 | _bt_lshift(_bt_fill_mask(type), length) | |
114 | ||
115 | /* | |
116 | * Generate a mask of type `type` with the `length` least significant bits | |
117 | * set, and the most significant bits cleared. | |
118 | */ | |
119 | #define _bt_make_mask(type, length) \ | |
120 | ((type) ~_bt_make_mask_complement(type, length)) | |
121 | ||
122 | /* | |
123 | * Right shift a value `v` of `shift` bits. | |
124 | * | |
125 | * The type of `v` can be signed or unsigned integer. | |
126 | * The value of `shift` must be less than the size of `v` (in bits), | |
127 | * otherwise the behavior is undefined. | |
128 | * Evaluates to the result of the shift operation. | |
129 | * | |
130 | * According to the C99 standard, right shift of a left hand-side signed | |
131 | * type which has a negative value is implementation defined. This | |
132 | * bitfield header relies on the right shift implementation carrying the | |
133 | * sign bit. If the compiler implementation has a different behavior, | |
134 | * emulate carrying the sign bit. | |
135 | * | |
136 | * This macro should not be used if `shift` can be greater or equal than | |
137 | * the bitwidth of `v`. See `_bt_safe_rshift`. | |
138 | */ | |
139 | #if ((-1 >> 1) == -1) | |
140 | #define _bt_rshift(v, shift) ((v) >> (shift)) | |
141 | #else | |
142 | #define _bt_rshift(v, shift) \ | |
143 | ((__typeof__(v)) ((_bt_cast_value_to_unsigned(v) >> (shift)) | \ | |
144 | ((v) < 0 ? _bt_make_mask_complement(__typeof__(v), \ | |
145 | sizeof(v) * CHAR_BIT - (shift)) : 0))) | |
146 | #endif | |
147 | ||
148 | /* | |
149 | * Right shift a signed or unsigned integer with `shift` value being an | |
150 | * arbitrary number of bits. `v` is modified by this macro. The shift | |
151 | * is transformed into a sequence of `_nr_partial_shifts` consecutive | |
152 | * shift operations, each of a number of bits smaller than the bitwidth | |
153 | * of `v`, ending with a shift of the number of left over bits. | |
154 | */ | |
155 | #define _bt_safe_rshift(v, shift) \ | |
156 | do { \ | |
157 | unsigned long _nr_partial_shifts = (shift) / (sizeof(v) * CHAR_BIT - 1); \ | |
158 | unsigned long _leftover_bits = (shift) % (sizeof(v) * CHAR_BIT - 1); \ | |
159 | \ | |
160 | for (; _nr_partial_shifts; _nr_partial_shifts--) \ | |
161 | (v) = _bt_rshift(v, sizeof(v) * CHAR_BIT - 1); \ | |
162 | (v) = _bt_rshift(v, _leftover_bits); \ | |
163 | } while (0) | |
164 | ||
165 | /* | |
166 | * Left shift a signed or unsigned integer with `shift` value being an | |
167 | * arbitrary number of bits. `v` is modified by this macro. The shift | |
168 | * is transformed into a sequence of `_nr_partial_shifts` consecutive | |
169 | * shift operations, each of a number of bits smaller than the bitwidth | |
170 | * of `v`, ending with a shift of the number of left over bits. | |
171 | */ | |
172 | #define _bt_safe_lshift(v, shift) \ | |
173 | do { \ | |
174 | unsigned long _nr_partial_shifts = (shift) / (sizeof(v) * CHAR_BIT - 1); \ | |
175 | unsigned long _leftover_bits = (shift) % (sizeof(v) * CHAR_BIT - 1); \ | |
176 | \ | |
177 | for (; _nr_partial_shifts; _nr_partial_shifts--) \ | |
178 | (v) = _bt_lshift(v, sizeof(v) * CHAR_BIT - 1); \ | |
179 | (v) = _bt_lshift(v, _leftover_bits); \ | |
180 | } while (0) | |
9e7f0924 MD |
181 | |
182 | /* | |
183 | * bt_bitfield_write - write integer to a bitfield in native endianness | |
184 | * | |
185 | * Save integer to the bitfield, which starts at the "start" bit, has "len" | |
186 | * bits. | |
187 | * The inside of a bitfield is from high bits to low bits. | |
188 | * Uses native endianness. | |
189 | * For unsigned "v", pad MSB with 0 if bitfield is larger than v. | |
190 | * For signed "v", sign-extend v if bitfield is larger than v. | |
191 | * | |
192 | * On little endian, bytes are placed from the less significant to the most | |
193 | * significant. Also, consecutive bitfields are placed from lower bits to higher | |
194 | * bits. | |
195 | * | |
196 | * On big endian, bytes are places from most significant to less significant. | |
197 | * Also, consecutive bitfields are placed from higher to lower bits. | |
198 | */ | |
199 | ||
200 | #define _bt_bitfield_write_le(_ptr, type, _start, _length, _v) \ | |
201 | do { \ | |
fa81c5df | 202 | __typeof__(_v) __v = (_v); \ |
9e7f0924 MD |
203 | type *__ptr = (void *) (_ptr); \ |
204 | unsigned long __start = (_start), __length = (_length); \ | |
205 | type mask, cmask; \ | |
206 | unsigned long ts = sizeof(type) * CHAR_BIT; /* type size */ \ | |
207 | unsigned long start_unit, end_unit, this_unit; \ | |
208 | unsigned long end, cshift; /* cshift is "complement shift" */ \ | |
209 | \ | |
210 | if (!__length) \ | |
211 | break; \ | |
212 | \ | |
213 | end = __start + __length; \ | |
214 | start_unit = __start / ts; \ | |
215 | end_unit = (end + (ts - 1)) / ts; \ | |
216 | \ | |
217 | /* Trim v high bits */ \ | |
218 | if (__length < sizeof(__v) * CHAR_BIT) \ | |
fa81c5df | 219 | __v &= _bt_make_mask(__typeof__(__v), __length); \ |
9e7f0924 MD |
220 | \ |
221 | /* We can now append v with a simple "or", shift it piece-wise */ \ | |
222 | this_unit = start_unit; \ | |
223 | if (start_unit == end_unit - 1) { \ | |
fa81c5df | 224 | mask = _bt_make_mask(type, __start % ts); \ |
9e7f0924 | 225 | if (end % ts) \ |
fa81c5df MD |
226 | mask |= _bt_make_mask_complement(type, end % ts); \ |
227 | cmask = _bt_lshift((type) (__v), __start % ts); \ | |
9e7f0924 MD |
228 | cmask &= ~mask; \ |
229 | __ptr[this_unit] &= mask; \ | |
230 | __ptr[this_unit] |= cmask; \ | |
231 | break; \ | |
232 | } \ | |
233 | if (__start % ts) { \ | |
234 | cshift = __start % ts; \ | |
fa81c5df MD |
235 | mask = _bt_make_mask(type, cshift); \ |
236 | cmask = _bt_lshift((type) (__v), cshift); \ | |
9e7f0924 MD |
237 | cmask &= ~mask; \ |
238 | __ptr[this_unit] &= mask; \ | |
239 | __ptr[this_unit] |= cmask; \ | |
fa81c5df | 240 | _bt_safe_rshift(__v, ts - cshift); \ |
9e7f0924 MD |
241 | __start += ts - cshift; \ |
242 | this_unit++; \ | |
243 | } \ | |
244 | for (; this_unit < end_unit - 1; this_unit++) { \ | |
245 | __ptr[this_unit] = (type) __v; \ | |
fa81c5df | 246 | _bt_safe_rshift(__v, ts); \ |
9e7f0924 MD |
247 | __start += ts; \ |
248 | } \ | |
249 | if (end % ts) { \ | |
fa81c5df | 250 | mask = _bt_make_mask_complement(type, end % ts); \ |
9e7f0924 MD |
251 | cmask = (type) __v; \ |
252 | cmask &= ~mask; \ | |
253 | __ptr[this_unit] &= mask; \ | |
254 | __ptr[this_unit] |= cmask; \ | |
255 | } else \ | |
256 | __ptr[this_unit] = (type) __v; \ | |
257 | } while (0) | |
258 | ||
259 | #define _bt_bitfield_write_be(_ptr, type, _start, _length, _v) \ | |
260 | do { \ | |
fa81c5df | 261 | __typeof__(_v) __v = (_v); \ |
9e7f0924 MD |
262 | type *__ptr = (void *) (_ptr); \ |
263 | unsigned long __start = (_start), __length = (_length); \ | |
264 | type mask, cmask; \ | |
265 | unsigned long ts = sizeof(type) * CHAR_BIT; /* type size */ \ | |
266 | unsigned long start_unit, end_unit, this_unit; \ | |
267 | unsigned long end, cshift; /* cshift is "complement shift" */ \ | |
268 | \ | |
269 | if (!__length) \ | |
270 | break; \ | |
271 | \ | |
272 | end = __start + __length; \ | |
273 | start_unit = __start / ts; \ | |
274 | end_unit = (end + (ts - 1)) / ts; \ | |
275 | \ | |
276 | /* Trim v high bits */ \ | |
277 | if (__length < sizeof(__v) * CHAR_BIT) \ | |
fa81c5df | 278 | __v &= _bt_make_mask(__typeof__(__v), __length); \ |
9e7f0924 MD |
279 | \ |
280 | /* We can now append v with a simple "or", shift it piece-wise */ \ | |
281 | this_unit = end_unit - 1; \ | |
282 | if (start_unit == end_unit - 1) { \ | |
fa81c5df | 283 | mask = _bt_make_mask(type, (ts - (end % ts)) % ts); \ |
9e7f0924 | 284 | if (__start % ts) \ |
fa81c5df MD |
285 | mask |= _bt_make_mask_complement(type, ts - (__start % ts)); \ |
286 | cmask = _bt_lshift((type) (__v), (ts - (end % ts)) % ts); \ | |
9e7f0924 MD |
287 | cmask &= ~mask; \ |
288 | __ptr[this_unit] &= mask; \ | |
289 | __ptr[this_unit] |= cmask; \ | |
290 | break; \ | |
291 | } \ | |
292 | if (end % ts) { \ | |
293 | cshift = end % ts; \ | |
fa81c5df MD |
294 | mask = _bt_make_mask(type, ts - cshift); \ |
295 | cmask = _bt_lshift((type) (__v), ts - cshift); \ | |
9e7f0924 MD |
296 | cmask &= ~mask; \ |
297 | __ptr[this_unit] &= mask; \ | |
298 | __ptr[this_unit] |= cmask; \ | |
fa81c5df | 299 | _bt_safe_rshift(__v, cshift); \ |
9e7f0924 MD |
300 | end -= cshift; \ |
301 | this_unit--; \ | |
302 | } \ | |
303 | for (; (long) this_unit >= (long) start_unit + 1; this_unit--) { \ | |
304 | __ptr[this_unit] = (type) __v; \ | |
fa81c5df | 305 | _bt_safe_rshift(__v, ts); \ |
9e7f0924 MD |
306 | end -= ts; \ |
307 | } \ | |
308 | if (__start % ts) { \ | |
fa81c5df | 309 | mask = _bt_make_mask_complement(type, ts - (__start % ts)); \ |
9e7f0924 MD |
310 | cmask = (type) __v; \ |
311 | cmask &= ~mask; \ | |
312 | __ptr[this_unit] &= mask; \ | |
313 | __ptr[this_unit] |= cmask; \ | |
314 | } else \ | |
315 | __ptr[this_unit] = (type) __v; \ | |
316 | } while (0) | |
317 | ||
318 | /* | |
319 | * bt_bitfield_write - write integer to a bitfield in native endianness | |
320 | * bt_bitfield_write_le - write integer to a bitfield in little endian | |
321 | * bt_bitfield_write_be - write integer to a bitfield in big endian | |
322 | */ | |
323 | ||
9f3fdbc6 | 324 | #if (BYTE_ORDER == LITTLE_ENDIAN) |
9e7f0924 MD |
325 | |
326 | #define bt_bitfield_write(ptr, type, _start, _length, _v) \ | |
327 | _bt_bitfield_write_le(ptr, type, _start, _length, _v) | |
328 | ||
329 | #define bt_bitfield_write_le(ptr, type, _start, _length, _v) \ | |
330 | _bt_bitfield_write_le(ptr, type, _start, _length, _v) | |
fa81c5df | 331 | |
9e7f0924 MD |
332 | #define bt_bitfield_write_be(ptr, type, _start, _length, _v) \ |
333 | _bt_bitfield_write_be(ptr, unsigned char, _start, _length, _v) | |
334 | ||
9f3fdbc6 | 335 | #elif (BYTE_ORDER == BIG_ENDIAN) |
9e7f0924 MD |
336 | |
337 | #define bt_bitfield_write(ptr, type, _start, _length, _v) \ | |
338 | _bt_bitfield_write_be(ptr, type, _start, _length, _v) | |
339 | ||
340 | #define bt_bitfield_write_le(ptr, type, _start, _length, _v) \ | |
341 | _bt_bitfield_write_le(ptr, unsigned char, _start, _length, _v) | |
fa81c5df | 342 | |
9e7f0924 MD |
343 | #define bt_bitfield_write_be(ptr, type, _start, _length, _v) \ |
344 | _bt_bitfield_write_be(ptr, type, _start, _length, _v) | |
345 | ||
346 | #else /* (BYTE_ORDER == PDP_ENDIAN) */ | |
347 | ||
348 | #error "Byte order not supported" | |
349 | ||
350 | #endif | |
351 | ||
352 | #define _bt_bitfield_read_le(_ptr, type, _start, _length, _vptr) \ | |
353 | do { \ | |
6423c313 | 354 | __typeof__(*(_vptr)) *__vptr = (_vptr); \ |
fa81c5df | 355 | __typeof__(*__vptr) __v; \ |
9e7f0924 MD |
356 | type *__ptr = (void *) (_ptr); \ |
357 | unsigned long __start = (_start), __length = (_length); \ | |
358 | type mask, cmask; \ | |
359 | unsigned long ts = sizeof(type) * CHAR_BIT; /* type size */ \ | |
360 | unsigned long start_unit, end_unit, this_unit; \ | |
361 | unsigned long end, cshift; /* cshift is "complement shift" */ \ | |
362 | \ | |
363 | if (!__length) { \ | |
364 | *__vptr = 0; \ | |
365 | break; \ | |
366 | } \ | |
367 | \ | |
368 | end = __start + __length; \ | |
369 | start_unit = __start / ts; \ | |
370 | end_unit = (end + (ts - 1)) / ts; \ | |
371 | \ | |
372 | this_unit = end_unit - 1; \ | |
6423c313 | 373 | if (_bt_is_signed_type(__typeof__(__v)) \ |
fa81c5df MD |
374 | && (__ptr[this_unit] & _bt_lshift((type) 1, (end % ts ? end % ts : ts) - 1))) \ |
375 | __v = ~(__typeof__(__v)) 0; \ | |
9e7f0924 MD |
376 | else \ |
377 | __v = 0; \ | |
378 | if (start_unit == end_unit - 1) { \ | |
379 | cmask = __ptr[this_unit]; \ | |
fa81c5df | 380 | cmask = _bt_rshift(cmask, __start % ts); \ |
9e7f0924 | 381 | if ((end - __start) % ts) { \ |
fa81c5df | 382 | mask = _bt_make_mask(type, end - __start); \ |
9e7f0924 MD |
383 | cmask &= mask; \ |
384 | } \ | |
fa81c5df MD |
385 | _bt_safe_lshift(__v, end - __start); \ |
386 | __v |= _bt_cast_value_to_unsigned_type(__typeof__(__v), cmask); \ | |
9e7f0924 MD |
387 | *__vptr = __v; \ |
388 | break; \ | |
389 | } \ | |
390 | if (end % ts) { \ | |
391 | cshift = end % ts; \ | |
fa81c5df | 392 | mask = _bt_make_mask(type, cshift); \ |
9e7f0924 MD |
393 | cmask = __ptr[this_unit]; \ |
394 | cmask &= mask; \ | |
fa81c5df MD |
395 | _bt_safe_lshift(__v, cshift); \ |
396 | __v |= _bt_cast_value_to_unsigned_type(__typeof__(__v), cmask); \ | |
9e7f0924 MD |
397 | end -= cshift; \ |
398 | this_unit--; \ | |
399 | } \ | |
400 | for (; (long) this_unit >= (long) start_unit + 1; this_unit--) { \ | |
fa81c5df MD |
401 | _bt_safe_lshift(__v, ts); \ |
402 | __v |= _bt_cast_value_to_unsigned_type(__typeof__(__v), __ptr[this_unit]); \ | |
9e7f0924 MD |
403 | end -= ts; \ |
404 | } \ | |
405 | if (__start % ts) { \ | |
fa81c5df | 406 | mask = _bt_make_mask(type, ts - (__start % ts)); \ |
9e7f0924 | 407 | cmask = __ptr[this_unit]; \ |
fa81c5df | 408 | cmask = _bt_rshift(cmask, __start % ts); \ |
9e7f0924 | 409 | cmask &= mask; \ |
fa81c5df MD |
410 | _bt_safe_lshift(__v, ts - (__start % ts)); \ |
411 | __v |= _bt_cast_value_to_unsigned_type(__typeof__(__v), cmask); \ | |
9e7f0924 | 412 | } else { \ |
fa81c5df MD |
413 | _bt_safe_lshift(__v, ts); \ |
414 | __v |= _bt_cast_value_to_unsigned_type(__typeof__(__v), __ptr[this_unit]); \ | |
9e7f0924 MD |
415 | } \ |
416 | *__vptr = __v; \ | |
417 | } while (0) | |
418 | ||
419 | #define _bt_bitfield_read_be(_ptr, type, _start, _length, _vptr) \ | |
420 | do { \ | |
6423c313 | 421 | __typeof__(*(_vptr)) *__vptr = (_vptr); \ |
fa81c5df | 422 | __typeof__(*__vptr) __v; \ |
9e7f0924 MD |
423 | type *__ptr = (void *) (_ptr); \ |
424 | unsigned long __start = (_start), __length = (_length); \ | |
425 | type mask, cmask; \ | |
426 | unsigned long ts = sizeof(type) * CHAR_BIT; /* type size */ \ | |
427 | unsigned long start_unit, end_unit, this_unit; \ | |
428 | unsigned long end, cshift; /* cshift is "complement shift" */ \ | |
429 | \ | |
430 | if (!__length) { \ | |
431 | *__vptr = 0; \ | |
432 | break; \ | |
433 | } \ | |
434 | \ | |
435 | end = __start + __length; \ | |
436 | start_unit = __start / ts; \ | |
437 | end_unit = (end + (ts - 1)) / ts; \ | |
438 | \ | |
439 | this_unit = start_unit; \ | |
6423c313 | 440 | if (_bt_is_signed_type(__typeof__(__v)) \ |
fa81c5df MD |
441 | && (__ptr[this_unit] & _bt_lshift((type) 1, ts - (__start % ts) - 1))) \ |
442 | __v = ~(__typeof__(__v)) 0; \ | |
9e7f0924 MD |
443 | else \ |
444 | __v = 0; \ | |
445 | if (start_unit == end_unit - 1) { \ | |
446 | cmask = __ptr[this_unit]; \ | |
fa81c5df | 447 | cmask = _bt_rshift(cmask, (ts - (end % ts)) % ts); \ |
9e7f0924 | 448 | if ((end - __start) % ts) { \ |
fa81c5df | 449 | mask = _bt_make_mask(type, end - __start); \ |
9e7f0924 MD |
450 | cmask &= mask; \ |
451 | } \ | |
fa81c5df MD |
452 | _bt_safe_lshift(__v, end - __start); \ |
453 | __v |= _bt_cast_value_to_unsigned_type(__typeof__(__v), cmask); \ | |
9e7f0924 MD |
454 | *__vptr = __v; \ |
455 | break; \ | |
456 | } \ | |
457 | if (__start % ts) { \ | |
458 | cshift = __start % ts; \ | |
fa81c5df | 459 | mask = _bt_make_mask(type, ts - cshift); \ |
9e7f0924 MD |
460 | cmask = __ptr[this_unit]; \ |
461 | cmask &= mask; \ | |
fa81c5df MD |
462 | _bt_safe_lshift(__v, ts - cshift); \ |
463 | __v |= _bt_cast_value_to_unsigned_type(__typeof__(__v), cmask); \ | |
9e7f0924 MD |
464 | __start += ts - cshift; \ |
465 | this_unit++; \ | |
466 | } \ | |
467 | for (; this_unit < end_unit - 1; this_unit++) { \ | |
fa81c5df MD |
468 | _bt_safe_lshift(__v, ts); \ |
469 | __v |= _bt_cast_value_to_unsigned_type(__typeof__(__v), __ptr[this_unit]); \ | |
9e7f0924 MD |
470 | __start += ts; \ |
471 | } \ | |
472 | if (end % ts) { \ | |
fa81c5df | 473 | mask = _bt_make_mask(type, end % ts); \ |
9e7f0924 | 474 | cmask = __ptr[this_unit]; \ |
fa81c5df | 475 | cmask = _bt_rshift(cmask, ts - (end % ts)); \ |
9e7f0924 | 476 | cmask &= mask; \ |
fa81c5df MD |
477 | _bt_safe_lshift(__v, end % ts); \ |
478 | __v |= _bt_cast_value_to_unsigned_type(__typeof__(__v), cmask); \ | |
9e7f0924 | 479 | } else { \ |
fa81c5df MD |
480 | _bt_safe_lshift(__v, ts); \ |
481 | __v |= _bt_cast_value_to_unsigned_type(__typeof__(__v), __ptr[this_unit]); \ | |
9e7f0924 MD |
482 | } \ |
483 | *__vptr = __v; \ | |
484 | } while (0) | |
485 | ||
486 | /* | |
487 | * bt_bitfield_read - read integer from a bitfield in native endianness | |
488 | * bt_bitfield_read_le - read integer from a bitfield in little endian | |
489 | * bt_bitfield_read_be - read integer from a bitfield in big endian | |
490 | */ | |
491 | ||
9f3fdbc6 | 492 | #if (BYTE_ORDER == LITTLE_ENDIAN) |
9e7f0924 MD |
493 | |
494 | #define bt_bitfield_read(_ptr, type, _start, _length, _vptr) \ | |
495 | _bt_bitfield_read_le(_ptr, type, _start, _length, _vptr) | |
496 | ||
497 | #define bt_bitfield_read_le(_ptr, type, _start, _length, _vptr) \ | |
498 | _bt_bitfield_read_le(_ptr, type, _start, _length, _vptr) | |
fa81c5df | 499 | |
9e7f0924 MD |
500 | #define bt_bitfield_read_be(_ptr, type, _start, _length, _vptr) \ |
501 | _bt_bitfield_read_be(_ptr, unsigned char, _start, _length, _vptr) | |
502 | ||
9f3fdbc6 | 503 | #elif (BYTE_ORDER == BIG_ENDIAN) |
9e7f0924 MD |
504 | |
505 | #define bt_bitfield_read(_ptr, type, _start, _length, _vptr) \ | |
506 | _bt_bitfield_read_be(_ptr, type, _start, _length, _vptr) | |
507 | ||
508 | #define bt_bitfield_read_le(_ptr, type, _start, _length, _vptr) \ | |
509 | _bt_bitfield_read_le(_ptr, unsigned char, _start, _length, _vptr) | |
fa81c5df | 510 | |
9e7f0924 MD |
511 | #define bt_bitfield_read_be(_ptr, type, _start, _length, _vptr) \ |
512 | _bt_bitfield_read_be(_ptr, type, _start, _length, _vptr) | |
513 | ||
9f3fdbc6 | 514 | #else /* (BYTE_ORDER == PDP_ENDIAN) */ |
9e7f0924 MD |
515 | |
516 | #error "Byte order not supported" | |
517 | ||
518 | #endif | |
519 | ||
520 | #endif /* _BABELTRACE_BITFIELD_H */ |