• 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