type.c revision 982cbca34b2b49a158086ff5f43eb9bba89edead
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 62static void 63type_init_common(struct arg_type_info *info, enum arg_type type) 64{ 65 info->type = type; 66 info->lens = NULL; 67 info->own_lens = 0; 68} 69 70struct struct_field { 71 struct arg_type_info *info; 72 int own_info; 73}; 74 75void 76type_init_struct(struct arg_type_info *info) 77{ 78 type_init_common(info, ARGTYPE_STRUCT); 79 VECT_INIT(&info->u.entries, struct struct_field); 80} 81 82int 83type_struct_add(struct arg_type_info *info, 84 struct arg_type_info *field_info, int own) 85{ 86 assert(info->type == ARGTYPE_STRUCT); 87 struct struct_field field = { field_info, own }; 88 return VECT_PUSHBACK(&info->u.entries, &field); 89} 90 91struct arg_type_info * 92type_struct_get(struct arg_type_info *info, size_t idx) 93{ 94 assert(info->type == ARGTYPE_STRUCT); 95 return VECT_ELEMENT(&info->u.entries, struct struct_field, idx)->info; 96} 97 98size_t 99type_struct_size(struct arg_type_info *info) 100{ 101 assert(info->type == ARGTYPE_STRUCT); 102 return vect_size(&info->u.entries); 103} 104 105static void 106struct_field_dtor(struct struct_field *field, void *data) 107{ 108 if (field->own_info) { 109 type_destroy(field->info); 110 free(field->info); 111 } 112} 113 114static void 115type_struct_destroy(struct arg_type_info *info) 116{ 117 VECT_DESTROY(&info->u.entries, struct struct_field, 118 struct_field_dtor, NULL); 119} 120 121static int 122layout_struct(struct process *proc, struct arg_type_info *info, 123 size_t *sizep, size_t *alignmentp, size_t *offsetofp) 124{ 125 size_t sz = 0; 126 size_t max_alignment = 0; 127 size_t i; 128 size_t offsetof_field = (size_t)-1; 129 if (offsetofp != NULL) 130 offsetof_field = *offsetofp; 131 132 assert(info->type == ARGTYPE_STRUCT); 133 for (i = 0; i < vect_size(&info->u.entries); ++i) { 134 struct struct_field *field 135 = VECT_ELEMENT(&info->u.entries, 136 struct struct_field, i); 137 138 size_t alignment = type_alignof(proc, field->info); 139 if (alignment == (size_t)-1) 140 return -1; 141 142 /* Add padding to SZ to align the next element. */ 143 sz = align(sz, alignment); 144 if (i == offsetof_field) { 145 *offsetofp = sz; 146 if (sizep == NULL && alignmentp == NULL) 147 return 0; 148 } 149 150 size_t size = type_sizeof(proc, field->info); 151 if (size == (size_t)-1) 152 return -1; 153 sz += size; 154 155 if (alignment > max_alignment) 156 max_alignment = alignment; 157 } 158 159 if (max_alignment > 0) 160 sz = align(sz, max_alignment); 161 162 if (sizep != NULL) 163 *sizep = sz; 164 165 if (alignmentp != NULL) 166 *alignmentp = max_alignment; 167 168 return 0; 169} 170 171void 172type_init_array(struct arg_type_info *info, 173 struct arg_type_info *element_info, int own_info, 174 struct expr_node *length_expr, int own_length) 175{ 176 type_init_common(info, ARGTYPE_ARRAY); 177 info->u.array_info.elt_type = element_info; 178 info->u.array_info.own_info = own_info; 179 info->u.array_info.length = length_expr; 180 info->u.array_info.own_length = own_length; 181} 182 183static void 184type_array_destroy(struct arg_type_info *info) 185{ 186 if (info->u.array_info.own_info) { 187 type_destroy(info->u.array_info.elt_type); 188 free(info->u.array_info.elt_type); 189 } 190 if (info->u.array_info.own_length) { 191 expr_destroy(info->u.array_info.length); 192 free(info->u.array_info.length); 193 } 194} 195 196void 197type_init_pointer(struct arg_type_info *info, 198 struct arg_type_info *pointee_info, int own_info) 199{ 200 type_init_common(info, ARGTYPE_POINTER); 201 info->u.ptr_info.info = pointee_info; 202 info->u.ptr_info.own_info = own_info; 203} 204 205static void 206type_pointer_destroy(struct arg_type_info *info) 207{ 208 if (info->u.ptr_info.own_info) { 209 type_destroy(info->u.ptr_info.info); 210 free(info->u.ptr_info.info); 211 } 212} 213 214void 215type_destroy(struct arg_type_info *info) 216{ 217 if (info == NULL) 218 return; 219 220 switch (info->type) { 221 case ARGTYPE_STRUCT: 222 type_struct_destroy(info); 223 break; 224 225 case ARGTYPE_ARRAY: 226 type_array_destroy(info); 227 break; 228 229 case ARGTYPE_POINTER: 230 type_pointer_destroy(info); 231 break; 232 233 case ARGTYPE_VOID: 234 case ARGTYPE_INT: 235 case ARGTYPE_UINT: 236 case ARGTYPE_LONG: 237 case ARGTYPE_ULONG: 238 case ARGTYPE_CHAR: 239 case ARGTYPE_SHORT: 240 case ARGTYPE_USHORT: 241 case ARGTYPE_FLOAT: 242 case ARGTYPE_DOUBLE: 243 break; 244 } 245 246 if (info->own_lens) { 247 lens_destroy(info->lens); 248 free(info->lens); 249 } 250} 251 252#ifdef ARCH_HAVE_SIZEOF 253size_t arch_type_sizeof(struct process *proc, struct arg_type_info *arg); 254#else 255size_t 256arch_type_sizeof(struct process *proc, struct arg_type_info *arg) 257{ 258 /* Use default value. */ 259 return (size_t)-2; 260} 261#endif 262 263#ifdef ARCH_HAVE_ALIGNOF 264size_t arch_type_alignof(struct process *proc, struct arg_type_info *arg); 265#else 266size_t 267arch_type_alignof(struct process *proc, struct arg_type_info *arg) 268{ 269 /* Use default value. */ 270 return (size_t)-2; 271} 272#endif 273 274/* We need to support alignments that are not power of two. E.g. long 275 * double on x86 has alignment of 12. */ 276size_t 277align(size_t sz, size_t alignment) 278{ 279 assert(alignment != 0); 280 281 if ((sz % alignment) != 0) 282 sz = ((sz / alignment) + 1) * alignment; 283 284 return sz; 285} 286 287size_t 288type_sizeof(struct process *proc, struct arg_type_info *type) 289{ 290 size_t arch_size = arch_type_sizeof(proc, type); 291 if (arch_size != (size_t)-2) 292 return arch_size; 293 294 switch (type->type) { 295 size_t size; 296 case ARGTYPE_CHAR: 297 return sizeof(char); 298 299 case ARGTYPE_SHORT: 300 case ARGTYPE_USHORT: 301 return sizeof(short); 302 303 case ARGTYPE_INT: 304 case ARGTYPE_UINT: 305 return sizeof(int); 306 307 case ARGTYPE_LONG: 308 case ARGTYPE_ULONG: 309 return sizeof(long); 310 311 case ARGTYPE_FLOAT: 312 return sizeof(float); 313 314 case ARGTYPE_DOUBLE: 315 return sizeof(double); 316 317 case ARGTYPE_STRUCT: 318 if (layout_struct(proc, type, &size, NULL, NULL) < 0) 319 return (size_t)-1; 320 return size; 321 322 case ARGTYPE_POINTER: 323 return sizeof(void *); 324 325 case ARGTYPE_ARRAY: 326 if (expr_is_compile_constant(type->u.array_info.length)) { 327 long l; 328 if (expr_eval_constant(type->u.array_info.length, 329 &l) < 0) 330 return -1; 331 332 struct arg_type_info *elt_ti 333 = type->u.array_info.elt_type; 334 335 size_t elt_size = type_sizeof(proc, elt_ti); 336 if (elt_size == (size_t)-1) 337 return (size_t)-1; 338 339 return ((size_t)l) * elt_size; 340 341 } else { 342 /* Flexible arrays don't count into the 343 * sizeof. */ 344 return 0; 345 } 346 347 case ARGTYPE_VOID: 348 return 0; 349 } 350 351 abort(); 352} 353 354#undef alignof 355#define alignof(field,st) ((size_t) ((char*) &st.field - (char*) &st)) 356 357size_t 358type_alignof(struct process *proc, struct arg_type_info *type) 359{ 360 size_t arch_alignment = arch_type_alignof(proc, type); 361 if (arch_alignment != (size_t)-2) 362 return arch_alignment; 363 364 struct { char c; char C; } cC; 365 struct { char c; short s; } cs; 366 struct { char c; int i; } ci; 367 struct { char c; long l; } cl; 368 struct { char c; void* p; } cp; 369 struct { char c; float f; } cf; 370 struct { char c; double d; } cd; 371 372 static size_t char_alignment = alignof(C, cC); 373 static size_t short_alignment = alignof(s, cs); 374 static size_t int_alignment = alignof(i, ci); 375 static size_t long_alignment = alignof(l, cl); 376 static size_t ptr_alignment = alignof(p, cp); 377 static size_t float_alignment = alignof(f, cf); 378 static size_t double_alignment = alignof(d, cd); 379 380 switch (type->type) { 381 size_t alignment; 382 case ARGTYPE_LONG: 383 case ARGTYPE_ULONG: 384 return long_alignment; 385 case ARGTYPE_CHAR: 386 return char_alignment; 387 case ARGTYPE_SHORT: 388 case ARGTYPE_USHORT: 389 return short_alignment; 390 case ARGTYPE_FLOAT: 391 return float_alignment; 392 case ARGTYPE_DOUBLE: 393 return double_alignment; 394 case ARGTYPE_POINTER: 395 return ptr_alignment; 396 397 case ARGTYPE_ARRAY: 398 return type_alignof(proc, type->u.array_info.elt_type); 399 400 case ARGTYPE_STRUCT: 401 if (layout_struct(proc, type, NULL, &alignment, NULL) < 0) 402 return (size_t)-1; 403 return alignment; 404 405 default: 406 return int_alignment; 407 } 408} 409 410size_t 411type_offsetof(struct process *proc, struct arg_type_info *type, size_t emt) 412{ 413 assert(type->type == ARGTYPE_STRUCT 414 || type->type == ARGTYPE_ARRAY); 415 416 switch (type->type) { 417 size_t alignment; 418 size_t size; 419 case ARGTYPE_ARRAY: 420 alignment = type_alignof(proc, type->u.array_info.elt_type); 421 if (alignment == (size_t)-1) 422 return (size_t)-1; 423 424 size = type_sizeof(proc, type->u.array_info.elt_type); 425 if (size == (size_t)-1) 426 return (size_t)-1; 427 428 return emt * align(size, alignment); 429 430 case ARGTYPE_STRUCT: 431 if (layout_struct(proc, type, NULL, NULL, &emt) < 0) 432 return (size_t)-1; 433 return emt; 434 435 default: 436 abort(); 437 } 438} 439 440struct arg_type_info * 441type_element(struct arg_type_info *info, size_t emt) 442{ 443 assert(info->type == ARGTYPE_STRUCT 444 || info->type == ARGTYPE_ARRAY); 445 446 switch (info->type) { 447 case ARGTYPE_ARRAY: 448 return info->u.array_info.elt_type; 449 450 case ARGTYPE_STRUCT: 451 assert(emt < type_struct_size(info)); 452 return type_struct_get(info, emt); 453 454 default: 455 abort(); 456 } 457} 458 459size_t 460type_aggregate_size(struct arg_type_info *info) 461{ 462 assert(info->type == ARGTYPE_STRUCT 463 || info->type == ARGTYPE_ARRAY); 464 465 switch (info->type) { 466 long ret; 467 case ARGTYPE_ARRAY: 468 if (expr_eval_constant(info->u.array_info.length, &ret) < 0) 469 return (size_t)-1; 470 return (size_t)ret; 471 472 case ARGTYPE_STRUCT: 473 return type_struct_size(info); 474 475 default: 476 abort(); 477 } 478} 479 480int 481type_is_integral(enum arg_type type) 482{ 483 switch (type) { 484 case ARGTYPE_INT: 485 case ARGTYPE_UINT: 486 case ARGTYPE_LONG: 487 case ARGTYPE_ULONG: 488 case ARGTYPE_CHAR: 489 case ARGTYPE_SHORT: 490 case ARGTYPE_USHORT: 491 return 1; 492 493 case ARGTYPE_VOID: 494 case ARGTYPE_FLOAT: 495 case ARGTYPE_DOUBLE: 496 case ARGTYPE_ARRAY: 497 case ARGTYPE_STRUCT: 498 case ARGTYPE_POINTER: 499 return 0; 500 } 501 abort(); 502} 503 504int 505type_is_signed(enum arg_type type) 506{ 507 assert(type_is_integral(type)); 508 509 switch (type) { 510 case ARGTYPE_CHAR: 511 return CHAR_MIN != 0; 512 513 case ARGTYPE_SHORT: 514 case ARGTYPE_INT: 515 case ARGTYPE_LONG: 516 return 1; 517 518 case ARGTYPE_UINT: 519 case ARGTYPE_ULONG: 520 case ARGTYPE_USHORT: 521 return 0; 522 523 case ARGTYPE_VOID: 524 case ARGTYPE_FLOAT: 525 case ARGTYPE_DOUBLE: 526 case ARGTYPE_ARRAY: 527 case ARGTYPE_STRUCT: 528 case ARGTYPE_POINTER: 529 abort(); 530 } 531 abort(); 532} 533 534struct arg_type_info * 535type_get_fp_equivalent(struct arg_type_info *info) 536{ 537 /* Extract innermost structure. Give up early if any 538 * component has more than one element. */ 539 while (info->type == ARGTYPE_STRUCT) { 540 if (type_struct_size(info) != 1) 541 return NULL; 542 info = type_element(info, 0); 543 } 544 545 switch (info->type) { 546 case ARGTYPE_CHAR: 547 case ARGTYPE_SHORT: 548 case ARGTYPE_INT: 549 case ARGTYPE_LONG: 550 case ARGTYPE_UINT: 551 case ARGTYPE_ULONG: 552 case ARGTYPE_USHORT: 553 case ARGTYPE_VOID: 554 case ARGTYPE_ARRAY: 555 case ARGTYPE_POINTER: 556 return NULL; 557 558 case ARGTYPE_FLOAT: 559 case ARGTYPE_DOUBLE: 560 return info; 561 562 case ARGTYPE_STRUCT: 563 abort(); 564 } 565 abort(); 566} 567 568struct arg_type_info * 569type_get_hfa_type(struct arg_type_info *info, size_t *countp) 570{ 571 assert(info != NULL); 572 if (info->type != ARGTYPE_STRUCT 573 && info->type != ARGTYPE_ARRAY) 574 return NULL; 575 576 size_t n = type_aggregate_size(info); 577 if (n == (size_t)-1) 578 return NULL; 579 580 struct arg_type_info *ret = NULL; 581 *countp = 0; 582 583 while (n-- > 0) { 584 struct arg_type_info *emt = type_element(info, n); 585 586 size_t emt_count = 1; 587 if (emt->type == ARGTYPE_STRUCT || emt->type == ARGTYPE_ARRAY) 588 emt = type_get_hfa_type(emt, &emt_count); 589 if (emt == NULL) 590 return NULL; 591 if (ret == NULL) { 592 if (emt->type != ARGTYPE_FLOAT 593 && emt->type != ARGTYPE_DOUBLE) 594 return NULL; 595 ret = emt; 596 } 597 if (emt->type != ret->type) 598 return NULL; 599 *countp += emt_count; 600 } 601 return ret; 602} 603