Commit | Line | Data |
---|---|---|
dc3fffef PP |
1 | /* |
2 | * serialize.c | |
3 | * | |
4 | * Copyright 2010-2011 EfficiOS Inc. and Linux Foundation | |
5 | * Copyright 2013, 2014 Jérémie Galarneau <jeremie.galarneau@efficios.com> | |
6 | * Copyright 2017 Philippe Proulx <pproulx@efficios.com> | |
7 | * | |
8 | * The original author of the serialization functions for Babeltrace 1 | |
9 | * is Mathieu Desnoyers. Philippe Proulx modified the functions in 2017 | |
10 | * to use Babeltrace 2 objects. | |
11 | * | |
12 | * Permission is hereby granted, free of charge, to any person obtaining a copy | |
13 | * of this software and associated documentation files (the "Software"), to deal | |
14 | * in the Software without restriction, including without limitation the rights | |
15 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell | |
16 | * copies of the Software, and to permit persons to whom the Software is | |
17 | * furnished to do so, subject to the following conditions: | |
18 | * | |
19 | * The above copyright notice and this permission notice shall be included in | |
20 | * all copies or substantial portions of the Software. | |
21 | * | |
22 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR | |
23 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, | |
24 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE | |
25 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER | |
26 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, | |
27 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE | |
28 | * SOFTWARE. | |
29 | */ | |
30 | ||
0fbb9a9f | 31 | #include <stdlib.h> |
dc3fffef PP |
32 | #include <stdio.h> |
33 | #include <stdint.h> | |
dc3fffef PP |
34 | #include <babeltrace/ctf-ir/field-types.h> |
35 | #include <babeltrace/ctf-ir/field-types-internal.h> | |
36 | #include <babeltrace/ctf-ir/fields.h> | |
37 | #include <babeltrace/ctf-ir/fields-internal.h> | |
38 | #include <babeltrace/ctf-writer/serialize-internal.h> | |
3d9990ac PP |
39 | #include <babeltrace/align-internal.h> |
40 | #include <babeltrace/mmap-align-internal.h> | |
41 | #include <babeltrace/endian-internal.h> | |
42 | #include <babeltrace/bitfield-internal.h> | |
43 | #include <babeltrace/compat/fcntl-internal.h> | |
c55a9f58 | 44 | #include <babeltrace/types.h> |
108e5a1e | 45 | #include <babeltrace/common-internal.h> |
8b45963b | 46 | #include <babeltrace/assert-internal.h> |
dc3fffef PP |
47 | #include <glib.h> |
48 | ||
dc3fffef PP |
49 | #if (FLT_RADIX != 2) |
50 | # error "Unsupported floating point radix" | |
51 | #endif | |
52 | ||
53 | union intval { | |
54 | int64_t signd; | |
55 | uint64_t unsignd; | |
56 | }; | |
57 | ||
58 | /* | |
59 | * The aligned read/write functions are expected to be faster than the | |
60 | * bitfield variants. They will be enabled eventually as an | |
61 | * optimisation. | |
62 | */ | |
63 | static | |
839d52a5 | 64 | int aligned_integer_write(struct bt_stream_pos *pos, |
dc3fffef | 65 | union intval value, unsigned int alignment, unsigned int size, |
839d52a5 | 66 | bt_bool is_signed, enum bt_byte_order byte_order) |
dc3fffef | 67 | { |
839d52a5 | 68 | bt_bool rbo = (byte_order != BT_MY_BYTE_ORDER); /* reverse byte order */ |
dc3fffef | 69 | |
839d52a5 | 70 | if (!bt_stream_pos_align(pos, alignment)) |
dc3fffef PP |
71 | return -EFAULT; |
72 | ||
839d52a5 | 73 | if (!bt_stream_pos_access_ok(pos, size)) |
dc3fffef PP |
74 | return -EFAULT; |
75 | ||
8b45963b | 76 | BT_ASSERT(!(pos->offset % CHAR_BIT)); |
dc3fffef PP |
77 | if (!is_signed) { |
78 | switch (size) { | |
79 | case 8: | |
80 | { | |
81 | uint8_t v = value.unsignd; | |
82 | ||
839d52a5 | 83 | memcpy(bt_stream_pos_get_addr(pos), &v, sizeof(v)); |
dc3fffef PP |
84 | break; |
85 | } | |
86 | case 16: | |
87 | { | |
88 | uint16_t v = value.unsignd; | |
89 | ||
90 | if (rbo) | |
91 | v = GUINT16_SWAP_LE_BE(v); | |
839d52a5 | 92 | memcpy(bt_stream_pos_get_addr(pos), &v, sizeof(v)); |
dc3fffef PP |
93 | break; |
94 | } | |
95 | case 32: | |
96 | { | |
97 | uint32_t v = value.unsignd; | |
98 | ||
99 | if (rbo) | |
100 | v = GUINT32_SWAP_LE_BE(v); | |
839d52a5 | 101 | memcpy(bt_stream_pos_get_addr(pos), &v, sizeof(v)); |
dc3fffef PP |
102 | break; |
103 | } | |
104 | case 64: | |
105 | { | |
106 | uint64_t v = value.unsignd; | |
107 | ||
108 | if (rbo) | |
109 | v = GUINT64_SWAP_LE_BE(v); | |
839d52a5 | 110 | memcpy(bt_stream_pos_get_addr(pos), &v, sizeof(v)); |
dc3fffef PP |
111 | break; |
112 | } | |
113 | default: | |
0fbb9a9f | 114 | abort(); |
dc3fffef PP |
115 | } |
116 | } else { | |
117 | switch (size) { | |
118 | case 8: | |
119 | { | |
120 | uint8_t v = value.signd; | |
121 | ||
839d52a5 | 122 | memcpy(bt_stream_pos_get_addr(pos), &v, sizeof(v)); |
dc3fffef PP |
123 | break; |
124 | } | |
125 | case 16: | |
126 | { | |
127 | int16_t v = value.signd; | |
128 | ||
129 | if (rbo) | |
130 | v = GUINT16_SWAP_LE_BE(v); | |
839d52a5 | 131 | memcpy(bt_stream_pos_get_addr(pos), &v, sizeof(v)); |
dc3fffef PP |
132 | break; |
133 | } | |
134 | case 32: | |
135 | { | |
136 | int32_t v = value.signd; | |
137 | ||
138 | if (rbo) | |
139 | v = GUINT32_SWAP_LE_BE(v); | |
839d52a5 | 140 | memcpy(bt_stream_pos_get_addr(pos), &v, sizeof(v)); |
dc3fffef PP |
141 | break; |
142 | } | |
143 | case 64: | |
144 | { | |
145 | int64_t v = value.signd; | |
146 | ||
147 | if (rbo) | |
148 | v = GUINT64_SWAP_LE_BE(v); | |
839d52a5 | 149 | memcpy(bt_stream_pos_get_addr(pos), &v, sizeof(v)); |
dc3fffef PP |
150 | break; |
151 | } | |
152 | default: | |
0fbb9a9f | 153 | abort(); |
dc3fffef PP |
154 | } |
155 | } | |
156 | ||
839d52a5 | 157 | if (!bt_stream_pos_move(pos, size)) |
dc3fffef PP |
158 | return -EFAULT; |
159 | return 0; | |
160 | } | |
161 | ||
162 | static | |
839d52a5 | 163 | int integer_write(struct bt_stream_pos *pos, union intval value, |
c55a9f58 | 164 | unsigned int alignment, unsigned int size, bt_bool is_signed, |
839d52a5 | 165 | enum bt_byte_order byte_order) |
dc3fffef PP |
166 | { |
167 | if (!(alignment % CHAR_BIT) | |
168 | && !(size % CHAR_BIT)) { | |
169 | return aligned_integer_write(pos, value, alignment, | |
170 | size, is_signed, byte_order); | |
171 | } | |
172 | ||
839d52a5 | 173 | if (!bt_stream_pos_align(pos, alignment)) |
dc3fffef PP |
174 | return -EFAULT; |
175 | ||
839d52a5 | 176 | if (!bt_stream_pos_access_ok(pos, size)) |
dc3fffef PP |
177 | return -EFAULT; |
178 | ||
179 | if (!is_signed) { | |
839d52a5 | 180 | if (byte_order == BT_BYTE_ORDER_LITTLE_ENDIAN) |
dc3fffef PP |
181 | bt_bitfield_write_le(mmap_align_addr(pos->base_mma) + |
182 | pos->mmap_base_offset, unsigned char, | |
183 | pos->offset, size, value.unsignd); | |
184 | else | |
185 | bt_bitfield_write_be(mmap_align_addr(pos->base_mma) + | |
186 | pos->mmap_base_offset, unsigned char, | |
187 | pos->offset, size, value.unsignd); | |
188 | } else { | |
839d52a5 | 189 | if (byte_order == BT_BYTE_ORDER_LITTLE_ENDIAN) |
dc3fffef PP |
190 | bt_bitfield_write_le(mmap_align_addr(pos->base_mma) + |
191 | pos->mmap_base_offset, unsigned char, | |
192 | pos->offset, size, value.signd); | |
193 | else | |
194 | bt_bitfield_write_be(mmap_align_addr(pos->base_mma) + | |
195 | pos->mmap_base_offset, unsigned char, | |
196 | pos->offset, size, value.signd); | |
197 | } | |
198 | ||
839d52a5 | 199 | if (!bt_stream_pos_move(pos, size)) |
dc3fffef PP |
200 | return -EFAULT; |
201 | return 0; | |
202 | } | |
203 | ||
204 | BT_HIDDEN | |
839d52a5 PP |
205 | int bt_field_integer_write(struct bt_field_integer *int_field, |
206 | struct bt_stream_pos *pos, | |
207 | enum bt_byte_order native_byte_order) | |
dc3fffef | 208 | { |
839d52a5 PP |
209 | struct bt_field_type *type = int_field->parent.type; |
210 | struct bt_field_type_integer *int_type = (void *) type; | |
211 | enum bt_byte_order byte_order; | |
dc3fffef PP |
212 | union intval value; |
213 | ||
214 | byte_order = int_type->user_byte_order; | |
839d52a5 | 215 | if (byte_order == BT_BYTE_ORDER_NATIVE) { |
dc3fffef PP |
216 | byte_order = native_byte_order; |
217 | } | |
218 | ||
219 | value.signd = int_field->payload.signd; | |
220 | value.unsignd = int_field->payload.unsignd; | |
221 | return integer_write(pos, value, type->alignment, | |
222 | int_type->size, int_type->is_signed, | |
223 | byte_order); | |
224 | } | |
225 | ||
226 | BT_HIDDEN | |
839d52a5 PP |
227 | int bt_field_floating_point_write( |
228 | struct bt_field_floating_point *flt_field, | |
229 | struct bt_stream_pos *pos, | |
230 | enum bt_byte_order native_byte_order) | |
dc3fffef | 231 | { |
839d52a5 PP |
232 | struct bt_field_type *type = flt_field->parent.type; |
233 | struct bt_field_type_floating_point *flt_type = (void *) type; | |
234 | enum bt_byte_order byte_order; | |
dc3fffef PP |
235 | union intval value; |
236 | unsigned int size; | |
237 | ||
238 | byte_order = flt_type->user_byte_order; | |
839d52a5 | 239 | if (byte_order == BT_BYTE_ORDER_NATIVE) { |
dc3fffef PP |
240 | byte_order = native_byte_order; |
241 | } | |
242 | ||
243 | if (flt_type->mant_dig == FLT_MANT_DIG) { | |
244 | union u32f { | |
245 | uint32_t u; | |
246 | float f; | |
247 | } u32f; | |
248 | ||
249 | u32f.f = (float) flt_field->payload; | |
250 | value.unsignd = u32f.u; | |
251 | size = 32; | |
252 | } else if (flt_type->mant_dig == DBL_MANT_DIG) { | |
253 | union u64d { | |
254 | uint64_t u; | |
255 | double d; | |
256 | } u64d; | |
257 | ||
258 | u64d.d = flt_field->payload; | |
259 | value.unsignd = u64d.u; | |
260 | size = 64; | |
261 | } else { | |
262 | return -EINVAL; | |
263 | } | |
264 | ||
c55a9f58 | 265 | return integer_write(pos, value, type->alignment, size, BT_FALSE, |
dc3fffef PP |
266 | byte_order); |
267 | } | |
268 | ||
269 | BT_HIDDEN | |
839d52a5 | 270 | void bt_stream_pos_packet_seek(struct bt_stream_pos *pos, size_t index, |
dc3fffef PP |
271 | int whence) |
272 | { | |
273 | int ret; | |
274 | ||
8b45963b | 275 | BT_ASSERT(whence == SEEK_CUR && index == 0); |
dc3fffef PP |
276 | |
277 | if (pos->base_mma) { | |
278 | /* unmap old base */ | |
279 | ret = munmap_align(pos->base_mma); | |
280 | if (ret) { | |
0fbb9a9f PP |
281 | // FIXME: this can legitimately fail? |
282 | abort(); | |
dc3fffef PP |
283 | } |
284 | pos->base_mma = NULL; | |
285 | } | |
286 | ||
287 | /* The writer will add padding */ | |
288 | pos->mmap_offset += pos->packet_size / CHAR_BIT; | |
108e5a1e | 289 | pos->packet_size = PACKET_LEN_INCREMENT; |
dc3fffef PP |
290 | do { |
291 | ret = bt_posix_fallocate(pos->fd, pos->mmap_offset, | |
292 | pos->packet_size / CHAR_BIT); | |
293 | } while (ret == EINTR); | |
8b45963b | 294 | BT_ASSERT(ret == 0); |
dc3fffef PP |
295 | pos->offset = 0; |
296 | ||
297 | /* map new base. Need mapping length from header. */ | |
298 | pos->base_mma = mmap_align(pos->packet_size / CHAR_BIT, pos->prot, | |
299 | pos->flags, pos->fd, pos->mmap_offset); | |
300 | if (pos->base_mma == MAP_FAILED) { | |
0fbb9a9f PP |
301 | // FIXME: this can legitimately fail? |
302 | abort(); | |
dc3fffef PP |
303 | } |
304 | } |