resetting manifest requested domain to floor
[platform/upstream/ltrace.git] / type.c
1 /*
2  * This file is part of ltrace.
3  * Copyright (C) 2011,2012 Petr Machata, Red Hat Inc.
4  * Copyright (C) 2007,2008 Juan Cespedes
5  *
6  * This program is free software; you can redistribute it and/or
7  * modify it under the terms of the GNU General Public License as
8  * published by the Free Software Foundation; either version 2 of the
9  * License, or (at your option) any later version.
10  *
11  * This program is distributed in the hope that it will be useful, but
12  * WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
14  * General Public License for more details.
15  *
16  * You should have received a copy of the GNU General Public License
17  * along with this program; if not, write to the Free Software
18  * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
19  * 02110-1301 USA
20  */
21
22 #include <assert.h>
23 #include <stdlib.h>
24 #include <limits.h>
25
26 #include "type.h"
27 #include "sysdep.h"
28 #include "expr.h"
29 #include "lens.h"
30
31 struct arg_type_info *
32 type_get_simple(enum arg_type type)
33 {
34 #define HANDLE(T) {                                     \
35                 static struct arg_type_info t = { T };  \
36         case T:                                         \
37                 return &t;                              \
38         }
39
40         switch (type) {
41         HANDLE(ARGTYPE_VOID)
42         HANDLE(ARGTYPE_INT)
43         HANDLE(ARGTYPE_UINT)
44         HANDLE(ARGTYPE_LONG)
45         HANDLE(ARGTYPE_ULONG)
46         HANDLE(ARGTYPE_CHAR)
47         HANDLE(ARGTYPE_SHORT)
48         HANDLE(ARGTYPE_USHORT)
49         HANDLE(ARGTYPE_FLOAT)
50         HANDLE(ARGTYPE_DOUBLE)
51
52 #undef HANDLE
53
54         case ARGTYPE_ARRAY:
55         case ARGTYPE_STRUCT:
56         case ARGTYPE_POINTER:
57                 assert(!"Not a simple type!");
58         };
59         abort();
60 }
61
62 static void
63 type_init_common(struct arg_type_info *info, enum arg_type type)
64 {
65         info->type = type;
66         info->lens = NULL;
67         info->own_lens = 0;
68 }
69
70 struct struct_field {
71         struct arg_type_info *info;
72         int own_info;
73 };
74
75 void
76 type_init_struct(struct arg_type_info *info)
77 {
78         type_init_common(info, ARGTYPE_STRUCT);
79         VECT_INIT(&info->u.entries, struct struct_field);
80 }
81
82 int
83 type_struct_add(struct arg_type_info *info,
84                 struct arg_type_info *field_info, int own)
85 {
86         assert(info->type == ARGTYPE_STRUCT);
87         struct struct_field field = { field_info, own };
88         return VECT_PUSHBACK(&info->u.entries, &field);
89 }
90
91 struct arg_type_info *
92 type_struct_get(struct arg_type_info *info, size_t idx)
93 {
94         assert(info->type == ARGTYPE_STRUCT);
95         struct struct_field *field = VECT_ELEMENT(&info->u.entries,
96                                                   struct struct_field, idx);
97         if (field == NULL)
98                 return NULL;
99         return field->info;
100 }
101
102 size_t
103 type_struct_size(struct arg_type_info *info)
104 {
105         assert(info->type == ARGTYPE_STRUCT);
106         return vect_size(&info->u.entries);
107 }
108
109 static void
110 struct_field_dtor(struct struct_field *field, void *data)
111 {
112         if (field->own_info) {
113                 type_destroy(field->info);
114                 free(field->info);
115         }
116 }
117
118 static void
119 type_struct_destroy(struct arg_type_info *info)
120 {
121         VECT_DESTROY(&info->u.entries, struct struct_field,
122                      struct_field_dtor, NULL);
123 }
124
125 static int
126 layout_struct(struct Process *proc, struct arg_type_info *info,
127               size_t *sizep, size_t *alignmentp, size_t *offsetofp)
128 {
129         size_t sz = 0;
130         size_t max_alignment = 0;
131         size_t i;
132         size_t offsetof_field = (size_t)-1;
133         if (offsetofp != NULL)
134                 offsetof_field = *offsetofp;
135
136         assert(info->type == ARGTYPE_STRUCT);
137         for (i = 0; i < vect_size(&info->u.entries); ++i) {
138                 struct struct_field *field
139                         = VECT_ELEMENT(&info->u.entries,
140                                        struct struct_field, i);
141
142                 size_t alignment = type_alignof(proc, field->info);
143                 if (alignment == (size_t)-1)
144                         return -1;
145
146                 /* Add padding to SZ to align the next element.  */
147                 sz = align(sz, alignment);
148                 if (i == offsetof_field) {
149                         *offsetofp = sz;
150                         if (sizep == NULL && alignmentp == NULL)
151                                 return 0;
152                 }
153
154                 size_t size = type_sizeof(proc, field->info);
155                 if (size == (size_t)-1)
156                         return -1;
157                 sz += size;
158
159                 if (alignment > max_alignment)
160                         max_alignment = alignment;
161         }
162
163         if (max_alignment > 0)
164                 sz = align(sz, max_alignment);
165
166         if (sizep != NULL)
167                 *sizep = sz;
168
169         if (alignmentp != NULL)
170                 *alignmentp = max_alignment;
171
172         return 0;
173 }
174
175 void
176 type_init_array(struct arg_type_info *info,
177                 struct arg_type_info *element_info, int own_info,
178                 struct expr_node *length_expr, int own_length)
179 {
180         type_init_common(info, ARGTYPE_ARRAY);
181         info->u.array_info.elt_type = element_info;
182         info->u.array_info.own_info = own_info;
183         info->u.array_info.length = length_expr;
184         info->u.array_info.own_length = own_length;
185 }
186
187 static void
188 type_array_destroy(struct arg_type_info *info)
189 {
190         if (info->u.array_info.own_info) {
191                 type_destroy(info->u.array_info.elt_type);
192                 free(info->u.array_info.elt_type);
193         }
194         if (info->u.array_info.own_length) {
195                 expr_destroy(info->u.array_info.length);
196                 free(info->u.array_info.length);
197         }
198 }
199
200 void
201 type_init_pointer(struct arg_type_info *info,
202                   struct arg_type_info *pointee_info, int own_info)
203 {
204         type_init_common(info, ARGTYPE_POINTER);
205         info->u.ptr_info.info = pointee_info;
206         info->u.ptr_info.own_info = own_info;
207 }
208
209 static void
210 type_pointer_destroy(struct arg_type_info *info)
211 {
212         if (info->u.ptr_info.own_info) {
213                 type_destroy(info->u.ptr_info.info);
214                 free(info->u.ptr_info.info);
215         }
216 }
217
218 void
219 type_destroy(struct arg_type_info *info)
220 {
221         if (info == NULL)
222                 return;
223
224         switch (info->type) {
225         case ARGTYPE_STRUCT:
226                 type_struct_destroy(info);
227                 break;
228
229         case ARGTYPE_ARRAY:
230                 type_array_destroy(info);
231                 break;
232
233         case ARGTYPE_POINTER:
234                 type_pointer_destroy(info);
235                 break;
236
237         case ARGTYPE_VOID:
238         case ARGTYPE_INT:
239         case ARGTYPE_UINT:
240         case ARGTYPE_LONG:
241         case ARGTYPE_ULONG:
242         case ARGTYPE_CHAR:
243         case ARGTYPE_SHORT:
244         case ARGTYPE_USHORT:
245         case ARGTYPE_FLOAT:
246         case ARGTYPE_DOUBLE:
247                 break;
248         }
249
250         if (info->own_lens) {
251                 lens_destroy(info->lens);
252                 free(info->lens);
253         }
254 }
255
256 #ifdef ARCH_HAVE_SIZEOF
257 size_t arch_type_sizeof(struct Process *proc, struct arg_type_info * arg);
258 #else
259 size_t
260 arch_type_sizeof(struct Process *proc, struct arg_type_info * arg)
261 {
262         /* Use default value.  */
263         return (size_t)-2;
264 }
265 #endif
266
267 #ifdef ARCH_HAVE_ALIGNOF
268 size_t arch_type_alignof(struct Process *proc, struct arg_type_info * arg);
269 #else
270 size_t
271 arch_type_alignof(struct Process *proc, struct arg_type_info * arg)
272 {
273         /* Use default value.  */
274         return (size_t)-2;
275 }
276 #endif
277
278 /* We need to support alignments that are not power of two.  E.g. long
279  * double on x86 has alignment of 12.  */
280 size_t
281 align(size_t sz, size_t alignment)
282 {
283         assert(alignment != 0);
284
285         if ((sz % alignment) != 0)
286                 sz = ((sz / alignment) + 1) * alignment;
287
288         return sz;
289 }
290
291 size_t
292 type_sizeof(struct Process *proc, struct arg_type_info *type)
293 {
294         size_t arch_size = arch_type_sizeof(proc, type);
295         if (arch_size != (size_t)-2)
296                 return arch_size;
297
298         switch (type->type) {
299                 size_t size;
300         case ARGTYPE_CHAR:
301                 return sizeof(char);
302
303         case ARGTYPE_SHORT:
304         case ARGTYPE_USHORT:
305                 return sizeof(short);
306
307         case ARGTYPE_INT:
308         case ARGTYPE_UINT:
309                 return sizeof(int);
310
311         case ARGTYPE_LONG:
312         case ARGTYPE_ULONG:
313                 return sizeof(long);
314
315         case ARGTYPE_FLOAT:
316                 return sizeof(float);
317
318         case ARGTYPE_DOUBLE:
319                 return sizeof(double);
320
321         case ARGTYPE_STRUCT:
322                 if (layout_struct(proc, type, &size, NULL, NULL) < 0)
323                         return (size_t)-1;
324                 return size;
325
326         case ARGTYPE_POINTER:
327                 return sizeof(void *);
328
329         case ARGTYPE_ARRAY:
330                 if (expr_is_compile_constant(type->u.array_info.length)) {
331                         long l;
332                         if (expr_eval_constant(type->u.array_info.length,
333                                                &l) < 0)
334                                 return -1;
335
336                         struct arg_type_info *elt_ti
337                                 = type->u.array_info.elt_type;
338
339                         size_t elt_size = type_sizeof(proc, elt_ti);
340                         if (elt_size == (size_t)-1)
341                                 return (size_t)-1;
342
343                         return ((size_t)l) * elt_size;
344
345                 } else {
346                         /* Flexible arrays don't count into the
347                          * sizeof.  */
348                         return 0;
349                 }
350
351         case ARGTYPE_VOID:
352                 return 0;
353         }
354
355         abort();
356 }
357
358 #undef alignof
359 #define alignof(field,st) ((size_t) ((char*) &st.field - (char*) &st))
360
361 size_t
362 type_alignof(struct Process *proc, struct arg_type_info *type)
363 {
364         size_t arch_alignment = arch_type_alignof(proc, type);
365         if (arch_alignment != (size_t)-2)
366                 return arch_alignment;
367
368         struct { char c; char C; } cC;
369         struct { char c; short s; } cs;
370         struct { char c; int i; } ci;
371         struct { char c; long l; } cl;
372         struct { char c; void* p; } cp;
373         struct { char c; float f; } cf;
374         struct { char c; double d; } cd;
375
376         static size_t char_alignment = alignof(C, cC);
377         static size_t short_alignment = alignof(s, cs);
378         static size_t int_alignment = alignof(i, ci);
379         static size_t long_alignment = alignof(l, cl);
380         static size_t ptr_alignment = alignof(p, cp);
381         static size_t float_alignment = alignof(f, cf);
382         static size_t double_alignment = alignof(d, cd);
383
384         switch (type->type) {
385                 size_t alignment;
386         case ARGTYPE_LONG:
387         case ARGTYPE_ULONG:
388                 return long_alignment;
389         case ARGTYPE_CHAR:
390                 return char_alignment;
391         case ARGTYPE_SHORT:
392         case ARGTYPE_USHORT:
393                 return short_alignment;
394         case ARGTYPE_FLOAT:
395                 return float_alignment;
396         case ARGTYPE_DOUBLE:
397                 return double_alignment;
398         case ARGTYPE_POINTER:
399                 return ptr_alignment;
400
401         case ARGTYPE_ARRAY:
402                 return type_alignof(proc, type->u.array_info.elt_type);
403
404         case ARGTYPE_STRUCT:
405                 if (layout_struct(proc, type, NULL, &alignment, NULL) < 0)
406                         return (size_t)-1;
407                 return alignment;
408
409         default:
410                 return int_alignment;
411         }
412 }
413
414 size_t
415 type_offsetof(struct Process *proc, struct arg_type_info *type, size_t emt)
416 {
417         assert(type->type == ARGTYPE_STRUCT
418                || type->type == ARGTYPE_ARRAY);
419
420         switch (type->type) {
421                 size_t alignment;
422                 size_t size;
423         case ARGTYPE_ARRAY:
424                 alignment = type_alignof(proc, type->u.array_info.elt_type);
425                 if (alignment == (size_t)-1)
426                         return (size_t)-1;
427
428                 size = type_sizeof(proc, type->u.array_info.elt_type);
429                 if (size == (size_t)-1)
430                         return (size_t)-1;
431
432                 return emt * align(size, alignment);
433
434         case ARGTYPE_STRUCT:
435                 if (layout_struct(proc, type, NULL, NULL, &emt) < 0)
436                         return (size_t)-1;
437                 return emt;
438
439         default:
440                 abort();
441         }
442 }
443
444 struct arg_type_info *
445 type_element(struct arg_type_info *info, size_t emt)
446 {
447         assert(info->type == ARGTYPE_STRUCT
448                || info->type == ARGTYPE_ARRAY);
449
450         switch (info->type) {
451         case ARGTYPE_ARRAY:
452                 return info->u.array_info.elt_type;
453
454         case ARGTYPE_STRUCT:
455                 assert(emt < type_struct_size(info));
456                 return type_struct_get(info, emt);
457
458         default:
459                 abort();
460         }
461 }
462
463 size_t
464 type_aggregate_size(struct arg_type_info *info)
465 {
466         assert(info->type == ARGTYPE_STRUCT
467                || info->type == ARGTYPE_ARRAY);
468
469         switch (info->type) {
470                 long ret;
471         case ARGTYPE_ARRAY:
472                 if (expr_eval_constant(info->u.array_info.length, &ret) < 0)
473                         return (size_t)-1;
474                 return (size_t)ret;
475
476         case ARGTYPE_STRUCT:
477                 return type_struct_size(info);
478
479         default:
480                 abort();
481         }
482 }
483
484 int
485 type_is_integral(enum arg_type type)
486 {
487         switch (type) {
488         case ARGTYPE_INT:
489         case ARGTYPE_UINT:
490         case ARGTYPE_LONG:
491         case ARGTYPE_ULONG:
492         case ARGTYPE_CHAR:
493         case ARGTYPE_SHORT:
494         case ARGTYPE_USHORT:
495                 return 1;
496
497         case ARGTYPE_VOID:
498         case ARGTYPE_FLOAT:
499         case ARGTYPE_DOUBLE:
500         case ARGTYPE_ARRAY:
501         case ARGTYPE_STRUCT:
502         case ARGTYPE_POINTER:
503                 return 0;
504         }
505         abort();
506 }
507
508 int
509 type_is_signed(enum arg_type type)
510 {
511         assert(type_is_integral(type));
512
513         switch (type) {
514         case ARGTYPE_CHAR:
515                 return CHAR_MIN != 0;
516
517         case ARGTYPE_SHORT:
518         case ARGTYPE_INT:
519         case ARGTYPE_LONG:
520                 return 1;
521
522         case ARGTYPE_UINT:
523         case ARGTYPE_ULONG:
524         case ARGTYPE_USHORT:
525                 return 0;
526
527         case ARGTYPE_VOID:
528         case ARGTYPE_FLOAT:
529         case ARGTYPE_DOUBLE:
530         case ARGTYPE_ARRAY:
531         case ARGTYPE_STRUCT:
532         case ARGTYPE_POINTER:
533                 abort();
534         }
535         abort();
536 }
537
538 struct arg_type_info *
539 type_get_fp_equivalent(struct arg_type_info *info)
540 {
541         /* Extract innermost structure.  Give up early if any
542          * component has more than one element.  */
543         while (info->type == ARGTYPE_STRUCT) {
544                 if (type_struct_size(info) != 1)
545                         return NULL;
546                 info = type_element(info, 0);
547         }
548
549         switch (info->type) {
550         case ARGTYPE_CHAR:
551         case ARGTYPE_SHORT:
552         case ARGTYPE_INT:
553         case ARGTYPE_LONG:
554         case ARGTYPE_UINT:
555         case ARGTYPE_ULONG:
556         case ARGTYPE_USHORT:
557         case ARGTYPE_VOID:
558         case ARGTYPE_ARRAY:
559         case ARGTYPE_POINTER:
560                 return NULL;
561
562         case ARGTYPE_FLOAT:
563         case ARGTYPE_DOUBLE:
564                 return info;
565
566         case ARGTYPE_STRUCT:
567                 abort();
568         }
569         abort();
570 }