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