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
31struct arg_type_info *
32type_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
62struct arg_type_info *
63type_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
75static void
76type_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
83struct struct_field {
84	struct arg_type_info *info;
85	int own_info;
86};
87
88void
89type_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
95int
96type_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
104struct arg_type_info *
105type_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
111size_t
112type_struct_size(struct arg_type_info *info)
113{
114	assert(info->type == ARGTYPE_STRUCT);
115	return vect_size(&info->u.entries);
116}
117
118static void
119struct_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
127static void
128type_struct_destroy(struct arg_type_info *info)
129{
130	VECT_DESTROY(&info->u.entries, struct struct_field,
131		     struct_field_dtor, NULL);
132}
133
134static int
135layout_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
184void
185type_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
196static void
197type_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
209void
210type_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
218static void
219type_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
227void
228type_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
265static int
266type_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
280static enum callback_status
281clone_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
301int
302type_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
355size_t arch_type_sizeof(struct process *proc, struct arg_type_info *arg);
356#else
357size_t
358arch_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
366size_t arch_type_alignof(struct process *proc, struct arg_type_info *arg);
367#else
368size_t
369arch_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.  */
378size_t
379align(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
389size_t
390type_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
459size_t
460type_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
512size_t
513type_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
542struct arg_type_info *
543type_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
561size_t
562type_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
582int
583type_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
606int
607type_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
636struct arg_type_info *
637type_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
670struct arg_type_info *
671type_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