Fix: add stricter checks on packet boundaries
[babeltrace.git] / formats / ctf / types / float.c
... / ...
CommitLineData
1/*
2 * Common Trace Format
3 *
4 * Floating point read/write functions.
5 *
6 * Copyright 2010-2011 EfficiOS Inc. and Linux Foundation
7 *
8 * Author: Mathieu Desnoyers <mathieu.desnoyers@efficios.com>
9 *
10 * Permission is hereby granted, free of charge, to any person obtaining a copy
11 * of this software and associated documentation files (the "Software"), to deal
12 * in the Software without restriction, including without limitation the rights
13 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
14 * copies of the Software, and to permit persons to whom the Software is
15 * furnished to do so, subject to the following conditions:
16 *
17 * The above copyright notice and this permission notice shall be included in
18 * all copies or substantial portions of the Software.
19 *
20 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
21 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
22 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
23 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
24 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
25 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
26 * SOFTWARE.
27 *
28 * Reference: ISO C99 standard 5.2.4
29 */
30
31#include <babeltrace/ctf/types.h>
32#include <glib.h>
33#include <float.h> /* C99 floating point definitions */
34#include <limits.h> /* C99 limits */
35#include <babeltrace/endian.h>
36#include <pthread.h>
37
38/*
39 * This library is limited to binary representation of floating point values.
40 * We use hardware support for conversion between 32 and 64-bit floating
41 * point values.
42 */
43
44/*
45 * Aliasing float/double and unsigned long is not strictly permitted by strict
46 * aliasing, but in practice declaration prunning is well supported, and this permits
47 * us to use per-word read/writes rather than per-byte.
48 */
49
50#if defined(__GNUC__) || defined(__MINGW32__) || defined(_MSC_VER)
51#define HAS_TYPE_PRUNING
52#endif
53
54#if (FLT_RADIX != 2)
55
56#error "Unsupported floating point radix"
57
58#endif
59
60union doubleIEEE754 {
61 double vd;
62 float vf;
63#ifdef HAS_TYPE_PRUNING
64 unsigned long bits[(sizeof(double) + sizeof(unsigned long) - 1) / sizeof(unsigned long)];
65#else
66 unsigned char bits[sizeof(double)];
67#endif
68};
69
70/*
71 * This mutex protects the static temporary float and double
72 * declarations (static_float_declaration and static_double_declaration).
73 */
74static pthread_mutex_t float_mutex = PTHREAD_MUTEX_INITIALIZER;
75
76static struct declaration_float *static_float_declaration,
77 *static_double_declaration;
78
79struct pos_len {
80 size_t len;
81};
82
83static void float_lock(void)
84{
85 int ret;
86
87 ret = pthread_mutex_lock(&float_mutex);
88 assert(!ret);
89}
90
91static void float_unlock(void)
92{
93 int ret;
94
95 ret = pthread_mutex_unlock(&float_mutex);
96 assert(!ret);
97}
98
99static int _ctf_float_copy(struct bt_stream_pos *destp,
100 struct definition_float *dest_definition,
101 struct bt_stream_pos *srcp,
102 const struct definition_float *src_definition)
103{
104 int ret;
105
106 /* We only support copy of same-size floats for now */
107 assert(src_definition->declaration->sign->len ==
108 dest_definition->declaration->sign->len);
109 assert(src_definition->declaration->exp->len ==
110 dest_definition->declaration->exp->len);
111 assert(src_definition->declaration->mantissa->len ==
112 dest_definition->declaration->mantissa->len);
113 /* Read */
114 if (src_definition->declaration->byte_order == LITTLE_ENDIAN) {
115 ret = ctf_integer_read(srcp, &src_definition->mantissa->p);
116 if (ret)
117 return ret;
118 ret = ctf_integer_read(srcp, &src_definition->exp->p);
119 if (ret)
120 return ret;
121 ret = ctf_integer_read(srcp, &src_definition->sign->p);
122 if (ret)
123 return ret;
124 } else {
125 ret = ctf_integer_read(srcp, &src_definition->sign->p);
126 if (ret)
127 return ret;
128 ret = ctf_integer_read(srcp, &src_definition->exp->p);
129 if (ret)
130 return ret;
131 ret = ctf_integer_read(srcp, &src_definition->mantissa->p);
132 if (ret)
133 return ret;
134 }
135
136 dest_definition->mantissa->value._unsigned =
137 src_definition->mantissa->value._unsigned;
138 dest_definition->exp->value._signed =
139 src_definition->exp->value._signed;
140 dest_definition->sign->value._unsigned =
141 src_definition->sign->value._unsigned;
142
143 /* Write */
144 if (dest_definition->declaration->byte_order == LITTLE_ENDIAN) {
145 ret = ctf_integer_write(destp, &dest_definition->mantissa->p);
146 if (ret)
147 return ret;
148 ret = ctf_integer_write(destp, &dest_definition->exp->p);
149 if (ret)
150 return ret;
151 ret = ctf_integer_write(destp, &dest_definition->sign->p);
152 if (ret)
153 return ret;
154 } else {
155 ret = ctf_integer_write(destp, &dest_definition->sign->p);
156 if (ret)
157 return ret;
158 ret = ctf_integer_write(destp, &dest_definition->exp->p);
159 if (ret)
160 return ret;
161 ret = ctf_integer_write(destp, &dest_definition->mantissa->p);
162 if (ret)
163 return ret;
164 }
165 return 0;
166}
167
168int ctf_float_read(struct bt_stream_pos *ppos, struct bt_definition *definition)
169{
170 struct definition_float *float_definition =
171 container_of(definition, struct definition_float, p);
172 const struct declaration_float *float_declaration =
173 float_definition->declaration;
174 struct ctf_stream_pos *pos = ctf_pos(ppos);
175 union doubleIEEE754 u;
176 struct bt_definition *tmpdef;
177 struct definition_float *tmpfloat;
178 struct ctf_stream_pos destp;
179 struct mmap_align mma;
180 int ret;
181
182 float_lock();
183 switch (float_declaration->mantissa->len + 1) {
184 case FLT_MANT_DIG:
185 tmpdef = static_float_declaration->p.definition_new(
186 &static_float_declaration->p,
187 NULL, 0, 0, "__tmpfloat");
188 break;
189 case DBL_MANT_DIG:
190 tmpdef = static_double_declaration->p.definition_new(
191 &static_double_declaration->p,
192 NULL, 0, 0, "__tmpfloat");
193 break;
194 default:
195 ret = -EINVAL;
196 goto end;
197 }
198 tmpfloat = container_of(tmpdef, struct definition_float, p);
199 memset(&destp, 0, sizeof(destp));
200 ctf_init_pos(&destp, NULL, -1, O_RDWR);
201 mmap_align_set_addr(&mma, (char *) u.bits);
202 destp.base_mma = &mma;
203 destp.packet_size = sizeof(u) * CHAR_BIT;
204 if (!ctf_align_pos(pos, float_declaration->p.alignment)) {
205 ret = -EFAULT;
206 goto end_unref;
207 }
208 ret = _ctf_float_copy(&destp.parent, tmpfloat, ppos, float_definition);
209 switch (float_declaration->mantissa->len + 1) {
210 case FLT_MANT_DIG:
211 float_definition->value = u.vf;
212 break;
213 case DBL_MANT_DIG:
214 float_definition->value = u.vd;
215 break;
216 default:
217 ret = -EINVAL;
218 goto end_unref;
219 }
220
221end_unref:
222 bt_definition_unref(tmpdef);
223end:
224 float_unlock();
225 return ret;
226}
227
228int ctf_float_write(struct bt_stream_pos *ppos, struct bt_definition *definition)
229{
230 struct definition_float *float_definition =
231 container_of(definition, struct definition_float, p);
232 const struct declaration_float *float_declaration =
233 float_definition->declaration;
234 struct ctf_stream_pos *pos = ctf_pos(ppos);
235 union doubleIEEE754 u;
236 struct bt_definition *tmpdef;
237 struct definition_float *tmpfloat;
238 struct ctf_stream_pos srcp = { { 0 } };
239 struct mmap_align mma;
240 int ret;
241
242 float_lock();
243 switch (float_declaration->mantissa->len + 1) {
244 case FLT_MANT_DIG:
245 tmpdef = static_float_declaration->p.definition_new(
246 &static_float_declaration->p,
247 NULL, 0, 0, "__tmpfloat");
248 break;
249 case DBL_MANT_DIG:
250 tmpdef = static_double_declaration->p.definition_new(
251 &static_double_declaration->p,
252 NULL, 0, 0, "__tmpfloat");
253 break;
254 default:
255 ret = -EINVAL;
256 goto end;
257 }
258 tmpfloat = container_of(tmpdef, struct definition_float, p);
259 ctf_init_pos(&srcp, NULL, -1, O_RDONLY);
260 mmap_align_set_addr(&mma, (char *) u.bits);
261 srcp.base_mma = &mma;
262 srcp.packet_size = sizeof(u) * CHAR_BIT;
263 switch (float_declaration->mantissa->len + 1) {
264 case FLT_MANT_DIG:
265 u.vf = float_definition->value;
266 break;
267 case DBL_MANT_DIG:
268 u.vd = float_definition->value;
269 break;
270 default:
271 ret = -EINVAL;
272 goto end_unref;
273 }
274 if (!ctf_align_pos(pos, float_declaration->p.alignment)) {
275 ret = -EFAULT;
276 goto end_unref;
277 }
278 ret = _ctf_float_copy(ppos, float_definition, &srcp.parent, tmpfloat);
279
280end_unref:
281 bt_definition_unref(tmpdef);
282end:
283 float_unlock();
284 return ret;
285}
286
287static
288void __attribute__((constructor)) ctf_float_init(void)
289{
290 static_float_declaration =
291 bt_float_declaration_new(FLT_MANT_DIG,
292 sizeof(float) * CHAR_BIT - FLT_MANT_DIG,
293 BYTE_ORDER,
294 __alignof__(float));
295 static_double_declaration =
296 bt_float_declaration_new(DBL_MANT_DIG,
297 sizeof(double) * CHAR_BIT - DBL_MANT_DIG,
298 BYTE_ORDER,
299 __alignof__(double));
300}
301
302static
303void __attribute__((destructor)) ctf_float_fini(void)
304{
305 bt_declaration_unref(&static_float_declaration->p);
306 bt_declaration_unref(&static_double_declaration->p);
307}
This page took 0.023481 seconds and 4 git commands to generate.