1 /*
2 * This file is part of ltrace.
3 * Copyright (C) 2011,2012,2013 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 *
type_get_simple(enum arg_type type)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 struct arg_type_info *
type_get_voidptr(void)63 type_get_voidptr(void)
64 {
65 struct arg_type_info *void_info = type_get_simple(ARGTYPE_VOID);
66 static struct arg_type_info *ret;
67 if (ret == NULL) {
68 static struct arg_type_info ptr_info;
69 type_init_pointer(&ptr_info, void_info, 0);
70 ret = &ptr_info;
71 }
72 return ret;
73 }
74
75 static void
type_init_common(struct arg_type_info * info,enum arg_type type)76 type_init_common(struct arg_type_info *info, enum arg_type type)
77 {
78 info->type = type;
79 info->lens = NULL;
80 info->own_lens = 0;
81 }
82
83 struct struct_field {
84 struct arg_type_info *info;
85 int own_info;
86 };
87
88 void
type_init_struct(struct arg_type_info * info)89 type_init_struct(struct arg_type_info *info)
90 {
91 type_init_common(info, ARGTYPE_STRUCT);
92 VECT_INIT(&info->u.entries, struct struct_field);
93 }
94
95 int
type_struct_add(struct arg_type_info * info,struct arg_type_info * field_info,int own)96 type_struct_add(struct arg_type_info *info,
97 struct arg_type_info *field_info, int own)
98 {
99 assert(info->type == ARGTYPE_STRUCT);
100 struct struct_field field = { field_info, own };
101 return VECT_PUSHBACK(&info->u.entries, &field);
102 }
103
104 struct arg_type_info *
type_struct_get(struct arg_type_info * info,size_t idx)105 type_struct_get(struct arg_type_info *info, size_t idx)
106 {
107 assert(info->type == ARGTYPE_STRUCT);
108 return VECT_ELEMENT(&info->u.entries, struct struct_field, idx)->info;
109 }
110
111 size_t
type_struct_size(struct arg_type_info * info)112 type_struct_size(struct arg_type_info *info)
113 {
114 assert(info->type == ARGTYPE_STRUCT);
115 return vect_size(&info->u.entries);
116 }
117
118 static void
struct_field_dtor(struct struct_field * field,void * data)119 struct_field_dtor(struct struct_field *field, void *data)
120 {
121 if (field->own_info) {
122 type_destroy(field->info);
123 free(field->info);
124 }
125 }
126
127 static void
type_struct_destroy(struct arg_type_info * info)128 type_struct_destroy(struct arg_type_info *info)
129 {
130 VECT_DESTROY(&info->u.entries, struct struct_field,
131 struct_field_dtor, NULL);
132 }
133
134 static int
layout_struct(struct process * proc,struct arg_type_info * info,size_t * sizep,size_t * alignmentp,size_t * offsetofp)135 layout_struct(struct process *proc, struct arg_type_info *info,
136 size_t *sizep, size_t *alignmentp, size_t *offsetofp)
137 {
138 size_t sz = 0;
139 size_t max_alignment = 0;
140 size_t i;
141 size_t offsetof_field = (size_t)-1;
142 if (offsetofp != NULL)
143 offsetof_field = *offsetofp;
144
145 assert(info->type == ARGTYPE_STRUCT);
146 for (i = 0; i < vect_size(&info->u.entries); ++i) {
147 struct struct_field *field
148 = VECT_ELEMENT(&info->u.entries,
149 struct struct_field, i);
150
151 size_t alignment = type_alignof(proc, field->info);
152 if (alignment == (size_t)-1)
153 return -1;
154
155 /* Add padding to SZ to align the next element. */
156 sz = align(sz, alignment);
157 if (i == offsetof_field) {
158 *offsetofp = sz;
159 if (sizep == NULL && alignmentp == NULL)
160 return 0;
161 }
162
163 size_t size = type_sizeof(proc, field->info);
164 if (size == (size_t)-1)
165 return -1;
166 sz += size;
167
168 if (alignment > max_alignment)
169 max_alignment = alignment;
170 }
171
172 if (max_alignment > 0)
173 sz = align(sz, max_alignment);
174
175 if (sizep != NULL)
176 *sizep = sz;
177
178 if (alignmentp != NULL)
179 *alignmentp = max_alignment;
180
181 return 0;
182 }
183
184 void
type_init_array(struct arg_type_info * info,struct arg_type_info * element_info,int own_info,struct expr_node * length_expr,int own_length)185 type_init_array(struct arg_type_info *info,
186 struct arg_type_info *element_info, int own_info,
187 struct expr_node *length_expr, int own_length)
188 {
189 type_init_common(info, ARGTYPE_ARRAY);
190 info->u.array_info.elt_type = element_info;
191 info->u.array_info.own_info = own_info;
192 info->u.array_info.length = length_expr;
193 info->u.array_info.own_length = own_length;
194 }
195
196 static void
type_array_destroy(struct arg_type_info * info)197 type_array_destroy(struct arg_type_info *info)
198 {
199 if (info->u.array_info.own_info) {
200 type_destroy(info->u.array_info.elt_type);
201 free(info->u.array_info.elt_type);
202 }
203 if (info->u.array_info.own_length) {
204 expr_destroy(info->u.array_info.length);
205 free(info->u.array_info.length);
206 }
207 }
208
209 void
type_init_pointer(struct arg_type_info * info,struct arg_type_info * pointee_info,int own_info)210 type_init_pointer(struct arg_type_info *info,
211 struct arg_type_info *pointee_info, int own_info)
212 {
213 type_init_common(info, ARGTYPE_POINTER);
214 info->u.ptr_info.info = pointee_info;
215 info->u.ptr_info.own_info = own_info;
216 }
217
218 static void
type_pointer_destroy(struct arg_type_info * info)219 type_pointer_destroy(struct arg_type_info *info)
220 {
221 if (info->u.ptr_info.own_info) {
222 type_destroy(info->u.ptr_info.info);
223 free(info->u.ptr_info.info);
224 }
225 }
226
227 void
type_destroy(struct arg_type_info * info)228 type_destroy(struct arg_type_info *info)
229 {
230 if (info == NULL)
231 return;
232
233 switch (info->type) {
234 case ARGTYPE_STRUCT:
235 type_struct_destroy(info);
236 break;
237
238 case ARGTYPE_ARRAY:
239 type_array_destroy(info);
240 break;
241
242 case ARGTYPE_POINTER:
243 type_pointer_destroy(info);
244 break;
245
246 case ARGTYPE_VOID:
247 case ARGTYPE_INT:
248 case ARGTYPE_UINT:
249 case ARGTYPE_LONG:
250 case ARGTYPE_ULONG:
251 case ARGTYPE_CHAR:
252 case ARGTYPE_SHORT:
253 case ARGTYPE_USHORT:
254 case ARGTYPE_FLOAT:
255 case ARGTYPE_DOUBLE:
256 break;
257 }
258
259 if (info->own_lens) {
260 lens_destroy(info->lens);
261 free(info->lens);
262 }
263 }
264
265 static int
type_alloc_and_clone(struct arg_type_info ** retpp,struct arg_type_info * info,int own)266 type_alloc_and_clone(struct arg_type_info **retpp,
267 struct arg_type_info *info, int own)
268 {
269 *retpp = info;
270 if (own) {
271 *retpp = malloc(sizeof **retpp);
272 if (*retpp == NULL || type_clone(*retpp, info) < 0) {
273 free(*retpp);
274 return -1;
275 }
276 }
277 return 0;
278 }
279
280 static enum callback_status
clone_struct_add_field(const struct struct_field * field,void * data)281 clone_struct_add_field(const struct struct_field *field, void *data)
282 {
283 struct arg_type_info *retp = data;
284 struct arg_type_info *info;
285 if (type_alloc_and_clone(&info, field->info, field->own_info) < 0) {
286 fail:
287 if (info != field->info)
288 free(info);
289 return CBS_STOP;
290 }
291
292 if (type_struct_add(retp, info, field->own_info) < 0) {
293 if (field->own_info)
294 type_destroy(info);
295 goto fail;
296 }
297
298 return CBS_CONT;
299 }
300
301 int
type_clone(struct arg_type_info * retp,const struct arg_type_info * info)302 type_clone(struct arg_type_info *retp, const struct arg_type_info *info)
303 {
304 switch (info->type) {
305 case ARGTYPE_STRUCT:
306 type_init_struct(retp);
307 if (VECT_EACH_CST(&info->u.entries, struct struct_field, NULL,
308 clone_struct_add_field, retp) != NULL) {
309 type_destroy(retp);
310 return -1;
311 }
312 break;
313
314 case ARGTYPE_ARRAY:;
315 struct arg_type_info *elt_type;
316 if (type_alloc_and_clone(&elt_type, info->u.array_info.elt_type,
317 info->u.array_info.own_info) < 0)
318 return -1;
319
320 assert(!info->u.array_info.own_length); // XXXXXXX
321 type_init_array(retp, elt_type, info->u.array_info.own_info,
322 info->u.array_info.length,
323 info->u.array_info.own_length);
324 break;
325
326 case ARGTYPE_POINTER:;
327 struct arg_type_info *ninfo;
328 if (type_alloc_and_clone(&ninfo, info->u.ptr_info.info,
329 info->u.ptr_info.own_info) < 0)
330 return -1;
331 type_init_pointer(retp, ninfo, info->u.ptr_info.own_info);
332 break;
333
334 case ARGTYPE_VOID:
335 case ARGTYPE_INT:
336 case ARGTYPE_UINT:
337 case ARGTYPE_LONG:
338 case ARGTYPE_ULONG:
339 case ARGTYPE_CHAR:
340 case ARGTYPE_SHORT:
341 case ARGTYPE_USHORT:
342 case ARGTYPE_FLOAT:
343 case ARGTYPE_DOUBLE:
344 *retp = *info;
345 break;
346 }
347
348 assert(!info->own_lens);
349 retp->lens = info->lens;
350 retp->own_lens = info->own_lens;
351 return 0;
352 }
353
354 #ifdef ARCH_HAVE_SIZEOF
355 size_t arch_type_sizeof(struct process *proc, struct arg_type_info *arg);
356 #else
357 size_t
arch_type_sizeof(struct process * proc,struct arg_type_info * arg)358 arch_type_sizeof(struct process *proc, struct arg_type_info *arg)
359 {
360 /* Use default value. */
361 return (size_t)-2;
362 }
363 #endif
364
365 #ifdef ARCH_HAVE_ALIGNOF
366 size_t arch_type_alignof(struct process *proc, struct arg_type_info *arg);
367 #else
368 size_t
arch_type_alignof(struct process * proc,struct arg_type_info * arg)369 arch_type_alignof(struct process *proc, struct arg_type_info *arg)
370 {
371 /* Use default value. */
372 return (size_t)-2;
373 }
374 #endif
375
376 /* We need to support alignments that are not power of two. E.g. long
377 * double on x86 has alignment of 12. */
378 size_t
align(size_t sz,size_t alignment)379 align(size_t sz, size_t alignment)
380 {
381 assert(alignment != 0);
382
383 if ((sz % alignment) != 0)
384 sz = ((sz / alignment) + 1) * alignment;
385
386 return sz;
387 }
388
389 size_t
type_sizeof(struct process * proc,struct arg_type_info * type)390 type_sizeof(struct process *proc, struct arg_type_info *type)
391 {
392 size_t arch_size = arch_type_sizeof(proc, type);
393 if (arch_size != (size_t)-2)
394 return arch_size;
395
396 switch (type->type) {
397 size_t size;
398 case ARGTYPE_CHAR:
399 return sizeof(char);
400
401 case ARGTYPE_SHORT:
402 case ARGTYPE_USHORT:
403 return sizeof(short);
404
405 case ARGTYPE_INT:
406 case ARGTYPE_UINT:
407 return sizeof(int);
408
409 case ARGTYPE_LONG:
410 case ARGTYPE_ULONG:
411 return sizeof(long);
412
413 case ARGTYPE_FLOAT:
414 return sizeof(float);
415
416 case ARGTYPE_DOUBLE:
417 return sizeof(double);
418
419 case ARGTYPE_STRUCT:
420 if (layout_struct(proc, type, &size, NULL, NULL) < 0)
421 return (size_t)-1;
422 return size;
423
424 case ARGTYPE_POINTER:
425 return sizeof(void *);
426
427 case ARGTYPE_ARRAY:
428 if (expr_is_compile_constant(type->u.array_info.length)) {
429 long l;
430 if (expr_eval_constant(type->u.array_info.length,
431 &l) < 0)
432 return -1;
433
434 struct arg_type_info *elt_ti
435 = type->u.array_info.elt_type;
436
437 size_t elt_size = type_sizeof(proc, elt_ti);
438 if (elt_size == (size_t)-1)
439 return (size_t)-1;
440
441 return ((size_t)l) * elt_size;
442
443 } else {
444 /* Flexible arrays don't count into the
445 * sizeof. */
446 return 0;
447 }
448
449 case ARGTYPE_VOID:
450 return 0;
451 }
452
453 abort();
454 }
455
456 #undef alignof
457 #define alignof(field,st) ((size_t) ((char*) &st.field - (char*) &st))
458
459 size_t
type_alignof(struct process * proc,struct arg_type_info * type)460 type_alignof(struct process *proc, struct arg_type_info *type)
461 {
462 size_t arch_alignment = arch_type_alignof(proc, type);
463 if (arch_alignment != (size_t)-2)
464 return arch_alignment;
465
466 struct { char c; char C; } cC;
467 struct { char c; short s; } cs;
468 struct { char c; int i; } ci;
469 struct { char c; long l; } cl;
470 struct { char c; void* p; } cp;
471 struct { char c; float f; } cf;
472 struct { char c; double d; } cd;
473
474 static size_t char_alignment = alignof(C, cC);
475 static size_t short_alignment = alignof(s, cs);
476 static size_t int_alignment = alignof(i, ci);
477 static size_t long_alignment = alignof(l, cl);
478 static size_t ptr_alignment = alignof(p, cp);
479 static size_t float_alignment = alignof(f, cf);
480 static size_t double_alignment = alignof(d, cd);
481
482 switch (type->type) {
483 size_t alignment;
484 case ARGTYPE_LONG:
485 case ARGTYPE_ULONG:
486 return long_alignment;
487 case ARGTYPE_CHAR:
488 return char_alignment;
489 case ARGTYPE_SHORT:
490 case ARGTYPE_USHORT:
491 return short_alignment;
492 case ARGTYPE_FLOAT:
493 return float_alignment;
494 case ARGTYPE_DOUBLE:
495 return double_alignment;
496 case ARGTYPE_POINTER:
497 return ptr_alignment;
498
499 case ARGTYPE_ARRAY:
500 return type_alignof(proc, type->u.array_info.elt_type);
501
502 case ARGTYPE_STRUCT:
503 if (layout_struct(proc, type, NULL, &alignment, NULL) < 0)
504 return (size_t)-1;
505 return alignment;
506
507 default:
508 return int_alignment;
509 }
510 }
511
512 size_t
type_offsetof(struct process * proc,struct arg_type_info * type,size_t emt)513 type_offsetof(struct process *proc, struct arg_type_info *type, size_t emt)
514 {
515 assert(type->type == ARGTYPE_STRUCT
516 || type->type == ARGTYPE_ARRAY);
517
518 switch (type->type) {
519 size_t alignment;
520 size_t size;
521 case ARGTYPE_ARRAY:
522 alignment = type_alignof(proc, type->u.array_info.elt_type);
523 if (alignment == (size_t)-1)
524 return (size_t)-1;
525
526 size = type_sizeof(proc, type->u.array_info.elt_type);
527 if (size == (size_t)-1)
528 return (size_t)-1;
529
530 return emt * align(size, alignment);
531
532 case ARGTYPE_STRUCT:
533 if (layout_struct(proc, type, NULL, NULL, &emt) < 0)
534 return (size_t)-1;
535 return emt;
536
537 default:
538 abort();
539 }
540 }
541
542 struct arg_type_info *
type_element(struct arg_type_info * info,size_t emt)543 type_element(struct arg_type_info *info, size_t emt)
544 {
545 assert(info->type == ARGTYPE_STRUCT
546 || info->type == ARGTYPE_ARRAY);
547
548 switch (info->type) {
549 case ARGTYPE_ARRAY:
550 return info->u.array_info.elt_type;
551
552 case ARGTYPE_STRUCT:
553 assert(emt < type_struct_size(info));
554 return type_struct_get(info, emt);
555
556 default:
557 abort();
558 }
559 }
560
561 size_t
type_aggregate_size(struct arg_type_info * info)562 type_aggregate_size(struct arg_type_info *info)
563 {
564 assert(info->type == ARGTYPE_STRUCT
565 || info->type == ARGTYPE_ARRAY);
566
567 switch (info->type) {
568 long ret;
569 case ARGTYPE_ARRAY:
570 if (expr_eval_constant(info->u.array_info.length, &ret) < 0)
571 return (size_t)-1;
572 return (size_t)ret;
573
574 case ARGTYPE_STRUCT:
575 return type_struct_size(info);
576
577 default:
578 abort();
579 }
580 }
581
582 int
type_is_integral(enum arg_type type)583 type_is_integral(enum arg_type type)
584 {
585 switch (type) {
586 case ARGTYPE_INT:
587 case ARGTYPE_UINT:
588 case ARGTYPE_LONG:
589 case ARGTYPE_ULONG:
590 case ARGTYPE_CHAR:
591 case ARGTYPE_SHORT:
592 case ARGTYPE_USHORT:
593 return 1;
594
595 case ARGTYPE_VOID:
596 case ARGTYPE_FLOAT:
597 case ARGTYPE_DOUBLE:
598 case ARGTYPE_ARRAY:
599 case ARGTYPE_STRUCT:
600 case ARGTYPE_POINTER:
601 return 0;
602 }
603 abort();
604 }
605
606 int
type_is_signed(enum arg_type type)607 type_is_signed(enum arg_type type)
608 {
609 assert(type_is_integral(type));
610
611 switch (type) {
612 case ARGTYPE_CHAR:
613 return CHAR_MIN != 0;
614
615 case ARGTYPE_SHORT:
616 case ARGTYPE_INT:
617 case ARGTYPE_LONG:
618 return 1;
619
620 case ARGTYPE_UINT:
621 case ARGTYPE_ULONG:
622 case ARGTYPE_USHORT:
623 return 0;
624
625 case ARGTYPE_VOID:
626 case ARGTYPE_FLOAT:
627 case ARGTYPE_DOUBLE:
628 case ARGTYPE_ARRAY:
629 case ARGTYPE_STRUCT:
630 case ARGTYPE_POINTER:
631 abort();
632 }
633 abort();
634 }
635
636 struct arg_type_info *
type_get_fp_equivalent(struct arg_type_info * info)637 type_get_fp_equivalent(struct arg_type_info *info)
638 {
639 /* Extract innermost structure. Give up early if any
640 * component has more than one element. */
641 while (info->type == ARGTYPE_STRUCT) {
642 if (type_struct_size(info) != 1)
643 return NULL;
644 info = type_element(info, 0);
645 }
646
647 switch (info->type) {
648 case ARGTYPE_CHAR:
649 case ARGTYPE_SHORT:
650 case ARGTYPE_INT:
651 case ARGTYPE_LONG:
652 case ARGTYPE_UINT:
653 case ARGTYPE_ULONG:
654 case ARGTYPE_USHORT:
655 case ARGTYPE_VOID:
656 case ARGTYPE_ARRAY:
657 case ARGTYPE_POINTER:
658 return NULL;
659
660 case ARGTYPE_FLOAT:
661 case ARGTYPE_DOUBLE:
662 return info;
663
664 case ARGTYPE_STRUCT:
665 abort();
666 }
667 abort();
668 }
669
670 struct arg_type_info *
type_get_hfa_type(struct arg_type_info * info,size_t * countp)671 type_get_hfa_type(struct arg_type_info *info, size_t *countp)
672 {
673 assert(info != NULL);
674 if (info->type != ARGTYPE_STRUCT
675 && info->type != ARGTYPE_ARRAY)
676 return NULL;
677
678 size_t n = type_aggregate_size(info);
679 if (n == (size_t)-1)
680 return NULL;
681
682 struct arg_type_info *ret = NULL;
683 *countp = 0;
684
685 while (n-- > 0) {
686 struct arg_type_info *emt = type_element(info, n);
687
688 size_t emt_count = 1;
689 if (emt->type == ARGTYPE_STRUCT || emt->type == ARGTYPE_ARRAY)
690 emt = type_get_hfa_type(emt, &emt_count);
691 if (emt == NULL)
692 return NULL;
693 if (ret == NULL) {
694 if (emt->type != ARGTYPE_FLOAT
695 && emt->type != ARGTYPE_DOUBLE)
696 return NULL;
697 ret = emt;
698 }
699 if (emt->type != ret->type)
700 return NULL;
701 *countp += emt_count;
702 }
703 return ret;
704 }
705