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 | ||
3dca2276 PP |
31 | #define BT_LOG_TAG "CTF-WRITER-SERIALIZE" |
32 | #include <babeltrace/lib-logging-internal.h> | |
33 | ||
0fbb9a9f | 34 | #include <stdlib.h> |
dc3fffef PP |
35 | #include <stdio.h> |
36 | #include <stdint.h> | |
3dca2276 PP |
37 | #include <babeltrace/ctf-writer/fields.h> |
38 | #include <babeltrace/ctf-writer/field-types.h> | |
dc3fffef | 39 | #include <babeltrace/ctf-writer/serialize-internal.h> |
3dca2276 PP |
40 | #include <babeltrace/ctf-ir/utils-internal.h> |
41 | #include <babeltrace/ctf-ir/fields-internal.h> | |
42 | #include <babeltrace/ctf-ir/field-types-internal.h> | |
3d9990ac PP |
43 | #include <babeltrace/align-internal.h> |
44 | #include <babeltrace/mmap-align-internal.h> | |
45 | #include <babeltrace/endian-internal.h> | |
46 | #include <babeltrace/bitfield-internal.h> | |
47 | #include <babeltrace/compat/fcntl-internal.h> | |
c55a9f58 | 48 | #include <babeltrace/types.h> |
108e5a1e | 49 | #include <babeltrace/common-internal.h> |
dc3fffef PP |
50 | #include <glib.h> |
51 | ||
dc3fffef PP |
52 | #if (FLT_RADIX != 2) |
53 | # error "Unsupported floating point radix" | |
54 | #endif | |
55 | ||
56 | union intval { | |
57 | int64_t signd; | |
58 | uint64_t unsignd; | |
59 | }; | |
60 | ||
61 | /* | |
62 | * The aligned read/write functions are expected to be faster than the | |
63 | * bitfield variants. They will be enabled eventually as an | |
64 | * optimisation. | |
65 | */ | |
66 | static | |
3dca2276 PP |
67 | int aligned_integer_write(struct bt_ctf_stream_pos *pos, union intval value, |
68 | unsigned int alignment, unsigned int size, bt_bool is_signed, | |
69 | enum bt_ctf_byte_order byte_order) | |
dc3fffef | 70 | { |
50842bdc | 71 | bt_bool rbo = (byte_order != BT_MY_BYTE_ORDER); /* reverse byte order */ |
dc3fffef | 72 | |
3dca2276 | 73 | if (!bt_ctf_stream_pos_align(pos, alignment)) |
dc3fffef PP |
74 | return -EFAULT; |
75 | ||
3dca2276 | 76 | if (!bt_ctf_stream_pos_access_ok(pos, size)) |
dc3fffef PP |
77 | return -EFAULT; |
78 | ||
f6ccaed9 | 79 | BT_ASSERT(!(pos->offset % CHAR_BIT)); |
dc3fffef PP |
80 | if (!is_signed) { |
81 | switch (size) { | |
82 | case 8: | |
83 | { | |
84 | uint8_t v = value.unsignd; | |
85 | ||
3dca2276 | 86 | memcpy(bt_ctf_stream_pos_get_addr(pos), &v, sizeof(v)); |
dc3fffef PP |
87 | break; |
88 | } | |
89 | case 16: | |
90 | { | |
91 | uint16_t v = value.unsignd; | |
92 | ||
93 | if (rbo) | |
94 | v = GUINT16_SWAP_LE_BE(v); | |
3dca2276 | 95 | memcpy(bt_ctf_stream_pos_get_addr(pos), &v, sizeof(v)); |
dc3fffef PP |
96 | break; |
97 | } | |
98 | case 32: | |
99 | { | |
100 | uint32_t v = value.unsignd; | |
101 | ||
102 | if (rbo) | |
103 | v = GUINT32_SWAP_LE_BE(v); | |
3dca2276 | 104 | memcpy(bt_ctf_stream_pos_get_addr(pos), &v, sizeof(v)); |
dc3fffef PP |
105 | break; |
106 | } | |
107 | case 64: | |
108 | { | |
109 | uint64_t v = value.unsignd; | |
110 | ||
111 | if (rbo) | |
112 | v = GUINT64_SWAP_LE_BE(v); | |
3dca2276 | 113 | memcpy(bt_ctf_stream_pos_get_addr(pos), &v, sizeof(v)); |
dc3fffef PP |
114 | break; |
115 | } | |
116 | default: | |
0fbb9a9f | 117 | abort(); |
dc3fffef PP |
118 | } |
119 | } else { | |
120 | switch (size) { | |
121 | case 8: | |
122 | { | |
123 | uint8_t v = value.signd; | |
124 | ||
3dca2276 | 125 | memcpy(bt_ctf_stream_pos_get_addr(pos), &v, sizeof(v)); |
dc3fffef PP |
126 | break; |
127 | } | |
128 | case 16: | |
129 | { | |
130 | int16_t v = value.signd; | |
131 | ||
132 | if (rbo) | |
133 | v = GUINT16_SWAP_LE_BE(v); | |
3dca2276 | 134 | memcpy(bt_ctf_stream_pos_get_addr(pos), &v, sizeof(v)); |
dc3fffef PP |
135 | break; |
136 | } | |
137 | case 32: | |
138 | { | |
139 | int32_t v = value.signd; | |
140 | ||
141 | if (rbo) | |
142 | v = GUINT32_SWAP_LE_BE(v); | |
3dca2276 | 143 | memcpy(bt_ctf_stream_pos_get_addr(pos), &v, sizeof(v)); |
dc3fffef PP |
144 | break; |
145 | } | |
146 | case 64: | |
147 | { | |
148 | int64_t v = value.signd; | |
149 | ||
150 | if (rbo) | |
151 | v = GUINT64_SWAP_LE_BE(v); | |
3dca2276 | 152 | memcpy(bt_ctf_stream_pos_get_addr(pos), &v, sizeof(v)); |
dc3fffef PP |
153 | break; |
154 | } | |
155 | default: | |
0fbb9a9f | 156 | abort(); |
dc3fffef PP |
157 | } |
158 | } | |
159 | ||
3dca2276 | 160 | if (!bt_ctf_stream_pos_move(pos, size)) |
dc3fffef PP |
161 | return -EFAULT; |
162 | return 0; | |
163 | } | |
164 | ||
165 | static | |
3dca2276 | 166 | int integer_write(struct bt_ctf_stream_pos *pos, union intval value, |
c55a9f58 | 167 | unsigned int alignment, unsigned int size, bt_bool is_signed, |
3dca2276 | 168 | enum bt_ctf_byte_order byte_order) |
dc3fffef PP |
169 | { |
170 | if (!(alignment % CHAR_BIT) | |
171 | && !(size % CHAR_BIT)) { | |
172 | return aligned_integer_write(pos, value, alignment, | |
173 | size, is_signed, byte_order); | |
174 | } | |
175 | ||
3dca2276 | 176 | if (!bt_ctf_stream_pos_align(pos, alignment)) |
dc3fffef PP |
177 | return -EFAULT; |
178 | ||
3dca2276 | 179 | if (!bt_ctf_stream_pos_access_ok(pos, size)) |
dc3fffef PP |
180 | return -EFAULT; |
181 | ||
182 | if (!is_signed) { | |
3dca2276 | 183 | if (byte_order == BT_CTF_BYTE_ORDER_LITTLE_ENDIAN) |
dc3fffef PP |
184 | bt_bitfield_write_le(mmap_align_addr(pos->base_mma) + |
185 | pos->mmap_base_offset, unsigned char, | |
186 | pos->offset, size, value.unsignd); | |
187 | else | |
188 | bt_bitfield_write_be(mmap_align_addr(pos->base_mma) + | |
189 | pos->mmap_base_offset, unsigned char, | |
190 | pos->offset, size, value.unsignd); | |
191 | } else { | |
3dca2276 | 192 | if (byte_order == BT_CTF_BYTE_ORDER_LITTLE_ENDIAN) |
dc3fffef PP |
193 | bt_bitfield_write_le(mmap_align_addr(pos->base_mma) + |
194 | pos->mmap_base_offset, unsigned char, | |
195 | pos->offset, size, value.signd); | |
196 | else | |
197 | bt_bitfield_write_be(mmap_align_addr(pos->base_mma) + | |
198 | pos->mmap_base_offset, unsigned char, | |
199 | pos->offset, size, value.signd); | |
200 | } | |
201 | ||
3dca2276 | 202 | if (!bt_ctf_stream_pos_move(pos, size)) |
dc3fffef PP |
203 | return -EFAULT; |
204 | return 0; | |
205 | } | |
206 | ||
207 | BT_HIDDEN | |
3dca2276 PP |
208 | int bt_ctf_field_integer_write(struct bt_field_common *field, |
209 | struct bt_ctf_stream_pos *pos, | |
210 | enum bt_ctf_byte_order native_byte_order) | |
dc3fffef | 211 | { |
3dca2276 PP |
212 | struct bt_field_type_common_integer *int_type = |
213 | BT_FROM_COMMON(field->type); | |
214 | struct bt_field_common_integer *int_field = BT_FROM_COMMON(field); | |
215 | enum bt_ctf_byte_order byte_order; | |
dc3fffef PP |
216 | union intval value; |
217 | ||
3dca2276 | 218 | byte_order = (int) int_type->user_byte_order; |
50842bdc | 219 | if (byte_order == BT_BYTE_ORDER_NATIVE) { |
dc3fffef PP |
220 | byte_order = native_byte_order; |
221 | } | |
222 | ||
223 | value.signd = int_field->payload.signd; | |
224 | value.unsignd = int_field->payload.unsignd; | |
3dca2276 | 225 | return integer_write(pos, value, int_type->common.alignment, |
dc3fffef PP |
226 | int_type->size, int_type->is_signed, |
227 | byte_order); | |
228 | } | |
229 | ||
230 | BT_HIDDEN | |
3dca2276 PP |
231 | int bt_ctf_field_floating_point_write( |
232 | struct bt_field_common *field, | |
233 | struct bt_ctf_stream_pos *pos, | |
234 | enum bt_ctf_byte_order native_byte_order) | |
dc3fffef | 235 | { |
3dca2276 PP |
236 | struct bt_field_type_common_floating_point *flt_type = |
237 | BT_FROM_COMMON(field->type); | |
238 | struct bt_field_common_floating_point *flt_field = BT_FROM_COMMON(field); | |
239 | enum bt_ctf_byte_order byte_order; | |
dc3fffef PP |
240 | union intval value; |
241 | unsigned int size; | |
242 | ||
3dca2276 | 243 | byte_order = (int) flt_type->user_byte_order; |
50842bdc | 244 | if (byte_order == BT_BYTE_ORDER_NATIVE) { |
dc3fffef PP |
245 | byte_order = native_byte_order; |
246 | } | |
247 | ||
248 | if (flt_type->mant_dig == FLT_MANT_DIG) { | |
249 | union u32f { | |
250 | uint32_t u; | |
251 | float f; | |
252 | } u32f; | |
253 | ||
254 | u32f.f = (float) flt_field->payload; | |
255 | value.unsignd = u32f.u; | |
256 | size = 32; | |
257 | } else if (flt_type->mant_dig == DBL_MANT_DIG) { | |
258 | union u64d { | |
259 | uint64_t u; | |
260 | double d; | |
261 | } u64d; | |
262 | ||
263 | u64d.d = flt_field->payload; | |
264 | value.unsignd = u64d.u; | |
265 | size = 64; | |
266 | } else { | |
267 | return -EINVAL; | |
268 | } | |
269 | ||
3dca2276 PP |
270 | return integer_write(pos, value, flt_type->common.alignment, |
271 | size, BT_FALSE, byte_order); | |
dc3fffef PP |
272 | } |
273 | ||
274 | BT_HIDDEN | |
3dca2276 | 275 | void bt_ctf_stream_pos_packet_seek(struct bt_ctf_stream_pos *pos, size_t index, |
dc3fffef PP |
276 | int whence) |
277 | { | |
278 | int ret; | |
279 | ||
f6ccaed9 | 280 | BT_ASSERT(whence == SEEK_CUR && index == 0); |
dc3fffef PP |
281 | |
282 | if (pos->base_mma) { | |
283 | /* unmap old base */ | |
284 | ret = munmap_align(pos->base_mma); | |
285 | if (ret) { | |
0fbb9a9f PP |
286 | // FIXME: this can legitimately fail? |
287 | abort(); | |
dc3fffef PP |
288 | } |
289 | pos->base_mma = NULL; | |
290 | } | |
291 | ||
292 | /* The writer will add padding */ | |
293 | pos->mmap_offset += pos->packet_size / CHAR_BIT; | |
108e5a1e | 294 | pos->packet_size = PACKET_LEN_INCREMENT; |
dc3fffef PP |
295 | do { |
296 | ret = bt_posix_fallocate(pos->fd, pos->mmap_offset, | |
297 | pos->packet_size / CHAR_BIT); | |
298 | } while (ret == EINTR); | |
f6ccaed9 | 299 | BT_ASSERT(ret == 0); |
dc3fffef PP |
300 | pos->offset = 0; |
301 | ||
302 | /* map new base. Need mapping length from header. */ | |
303 | pos->base_mma = mmap_align(pos->packet_size / CHAR_BIT, pos->prot, | |
304 | pos->flags, pos->fd, pos->mmap_offset); | |
305 | if (pos->base_mma == MAP_FAILED) { | |
0fbb9a9f PP |
306 | // FIXME: this can legitimately fail? |
307 | abort(); | |
dc3fffef PP |
308 | } |
309 | } |