Home | History | Annotate | Download | only in ltrace
      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 *
     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 *
     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
     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
     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
     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 *
    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
    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
    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
    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
    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
    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
    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
    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
    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
    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
    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
    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
    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
    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
    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
    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
    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
    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
    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 *
    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
    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
    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
    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 *
    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 *
    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