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