• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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