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