type.c revision 56abb870555ae16ecffaa12373a0d72328e19514
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 58 case ARGTYPE_ARRAY: 59 case ARGTYPE_ENUM: 60 case ARGTYPE_STRUCT: 61 case ARGTYPE_POINTER: 62 assert(!"Not a simple type!"); 63 }; 64 abort(); 65} 66 67struct enum_entry { 68 char *key; 69 int own_key; 70 int value; 71}; 72 73void 74type_init_enum(struct arg_type_info *info) 75{ 76 info->type = ARGTYPE_ENUM; 77 VECT_INIT(&info->u.entries, struct enum_entry); 78} 79 80int 81type_enum_add(struct arg_type_info *info, 82 const char *key, int own_key, int value) 83{ 84 assert(info->type == ARGTYPE_ENUM); 85 struct enum_entry entry = { (char *)key, own_key, value }; 86 return VECT_PUSHBACK(&info->u.entries, &entry); 87} 88 89size_t 90type_enum_size(struct arg_type_info *info) 91{ 92 assert(info->type == ARGTYPE_ENUM); 93 return vect_size(&info->u.entries); 94} 95 96const char * 97type_enum_get(struct arg_type_info *info, int value) 98{ 99 assert(info->type == ARGTYPE_ENUM); 100 size_t i; 101 for (i = 0; i < vect_size(&info->u.entries); ++i) { 102 struct enum_entry *entry = VECT_ELEMENT(&info->u.entries, 103 struct enum_entry, i); 104 if (value == entry->value) 105 return entry->key; 106 } 107 return NULL; 108} 109 110static void 111enum_entry_dtor(struct enum_entry *entry, void *data) 112{ 113 if (entry->own_key) 114 free(entry->key); 115} 116 117static void 118type_enum_destroy(struct arg_type_info *info) 119{ 120 VECT_DESTROY(&info->u.entries, struct enum_entry, 121 enum_entry_dtor, NULL); 122} 123 124struct struct_field { 125 struct arg_type_info *info; 126 int own_info; 127}; 128 129void 130type_init_struct(struct arg_type_info *info) 131{ 132 info->type = ARGTYPE_STRUCT; 133 VECT_INIT(&info->u.entries, struct struct_field); 134} 135 136int 137type_struct_add(struct arg_type_info *info, 138 struct arg_type_info *field_info, int own) 139{ 140 assert(info->type == ARGTYPE_STRUCT); 141 struct struct_field field = { field_info, own }; 142 return VECT_PUSHBACK(&info->u.entries, &field); 143} 144 145struct arg_type_info * 146type_struct_get(struct arg_type_info *info, size_t idx) 147{ 148 assert(info->type == ARGTYPE_STRUCT); 149 struct struct_field *field = VECT_ELEMENT(&info->u.entries, 150 struct struct_field, idx); 151 if (field == NULL) 152 return NULL; 153 return field->info; 154} 155 156size_t 157type_struct_size(struct arg_type_info *info) 158{ 159 assert(info->type == ARGTYPE_STRUCT); 160 return vect_size(&info->u.entries); 161} 162 163static void 164struct_field_dtor(struct struct_field *field, void *data) 165{ 166 if (field->own_info) { 167 type_destroy(field->info); 168 free(field->info); 169 } 170} 171 172static void 173type_struct_destroy(struct arg_type_info *info) 174{ 175 VECT_DESTROY(&info->u.entries, struct struct_field, 176 struct_field_dtor, NULL); 177} 178 179static int 180layout_struct(struct Process *proc, struct arg_type_info *info, 181 size_t *sizep, size_t *alignmentp, size_t *offsetofp) 182{ 183 size_t sz = 0; 184 size_t max_alignment = 0; 185 size_t i; 186 size_t offsetof_field = (size_t)-1; 187 if (offsetofp != NULL) 188 offsetof_field = *offsetofp; 189 190 assert(info->type == ARGTYPE_STRUCT); 191 for (i = 0; i < vect_size(&info->u.entries); ++i) { 192 struct struct_field *field 193 = VECT_ELEMENT(&info->u.entries, 194 struct struct_field, i); 195 196 size_t alignment = type_alignof(proc, field->info); 197 if (alignment == (size_t)-1) 198 return -1; 199 200 /* Add padding to SZ to align the next element. */ 201 sz = align(sz, alignment); 202 if (i == offsetof_field) { 203 *offsetofp = sz; 204 if (sizep == NULL && alignmentp == NULL) 205 return 0; 206 } 207 208 size_t size = type_sizeof(proc, field->info); 209 if (size == (size_t)-1) 210 return -1; 211 sz += size; 212 213 if (alignment > max_alignment) 214 max_alignment = alignment; 215 } 216 217 if (max_alignment > 0) 218 sz = align(sz, max_alignment); 219 220 if (sizep != NULL) 221 *sizep = sz; 222 223 if (alignmentp != NULL) 224 *alignmentp = max_alignment; 225 226 return 0; 227} 228 229void 230type_init_array(struct arg_type_info *info, 231 struct arg_type_info *element_info, int own_info, 232 struct expr_node *length, int own_length) 233{ 234 info->type = ARGTYPE_ARRAY; 235 info->u.array_info.elt_type = element_info; 236 info->u.array_info.own_info = own_info; 237 info->u.array_info.length = length; 238 info->u.array_info.own_length = own_length; 239} 240 241void 242type_init_string(struct arg_type_info *info, 243 struct expr_node *length, int own_length) 244{ 245 info->type = ARGTYPE_STRING_N; 246 info->u.string_n_info.length = length; 247 info->u.string_n_info.own_length = own_length; 248} 249 250static void 251type_array_destroy(struct arg_type_info *info) 252{ 253 if (info->u.array_info.own_info) { 254 type_destroy(info->u.array_info.elt_type); 255 free(info->u.array_info.elt_type); 256 } 257 if (info->u.array_info.own_length) { 258 expr_destroy(info->u.array_info.length); 259 free(info->u.array_info.length); 260 } 261} 262 263static void 264type_string_n_destroy(struct arg_type_info *info) 265{ 266 if (info->u.array_info.own_length) { 267 expr_destroy(info->u.string_n_info.length); 268 free(info->u.string_n_info.length); 269 } 270} 271 272void 273type_init_pointer(struct arg_type_info *info, 274 struct arg_type_info *pointee_info, int own_info) 275{ 276 info->type = ARGTYPE_POINTER; 277 info->u.ptr_info.info = pointee_info; 278 info->u.ptr_info.own_info = own_info; 279} 280 281static void 282type_pointer_destroy(struct arg_type_info *info) 283{ 284 if (info->u.ptr_info.own_info) { 285 type_destroy(info->u.ptr_info.info); 286 free(info->u.ptr_info.info); 287 } 288} 289 290void 291type_destroy(struct arg_type_info *info) 292{ 293 if (info == NULL) 294 return; 295 296 switch (info->type) { 297 case ARGTYPE_ENUM: 298 return type_enum_destroy(info); 299 300 case ARGTYPE_STRUCT: 301 type_struct_destroy(info); 302 break; 303 304 case ARGTYPE_ARRAY: 305 type_array_destroy(info); 306 break; 307 308 case ARGTYPE_POINTER: 309 type_pointer_destroy(info); 310 break; 311 312 case ARGTYPE_STRING_N: 313 type_string_n_destroy(info); 314 315 case ARGTYPE_UNKNOWN: 316 case ARGTYPE_VOID: 317 case ARGTYPE_INT: 318 case ARGTYPE_UINT: 319 case ARGTYPE_LONG: 320 case ARGTYPE_ULONG: 321 case ARGTYPE_OCTAL: 322 case ARGTYPE_CHAR: 323 case ARGTYPE_SHORT: 324 case ARGTYPE_USHORT: 325 case ARGTYPE_FLOAT: 326 case ARGTYPE_DOUBLE: 327 break; 328 329 case ARGTYPE_FORMAT: 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 return -1; 442 } 443 444 abort(); 445} 446 447#undef alignof 448#define alignof(field,st) ((size_t) ((char*) &st.field - (char*) &st)) 449 450size_t 451type_alignof(struct Process *proc, struct arg_type_info *type) 452{ 453 size_t arch_alignment = arch_type_alignof(proc, type); 454 if (arch_alignment != (size_t)-2) 455 return arch_alignment; 456 457 struct { char c; char C; } cC; 458 struct { char c; short s; } cs; 459 struct { char c; int i; } ci; 460 struct { char c; long l; } cl; 461 struct { char c; void* p; } cp; 462 struct { char c; float f; } cf; 463 struct { char c; double d; } cd; 464 465 static size_t char_alignment = alignof(C, cC); 466 static size_t short_alignment = alignof(s, cs); 467 static size_t int_alignment = alignof(i, ci); 468 static size_t long_alignment = alignof(l, cl); 469 static size_t ptr_alignment = alignof(p, cp); 470 static size_t float_alignment = alignof(f, cf); 471 static size_t double_alignment = alignof(d, cd); 472 473 switch (type->type) { 474 size_t alignment; 475 case ARGTYPE_LONG: 476 case ARGTYPE_ULONG: 477 return long_alignment; 478 case ARGTYPE_CHAR: 479 return char_alignment; 480 case ARGTYPE_SHORT: 481 case ARGTYPE_USHORT: 482 return short_alignment; 483 case ARGTYPE_FLOAT: 484 return float_alignment; 485 case ARGTYPE_DOUBLE: 486 return double_alignment; 487 case ARGTYPE_POINTER: 488 return ptr_alignment; 489 490 case ARGTYPE_ARRAY: 491 return type_alignof(proc, type->u.array_info.elt_type); 492 493 case ARGTYPE_STRUCT: 494 if (layout_struct(proc, type, NULL, &alignment, NULL) < 0) 495 return (size_t)-1; 496 return alignment; 497 498 default: 499 return int_alignment; 500 } 501} 502 503size_t 504type_offsetof(struct Process *proc, struct arg_type_info *type, size_t emt) 505{ 506 assert(type->type == ARGTYPE_STRUCT 507 || type->type == ARGTYPE_ARRAY 508 /* XXX Temporary, this will be removed. */ 509 || type->type == ARGTYPE_STRING_N); 510 511 switch (type->type) { 512 size_t alignment; 513 size_t size; 514 case ARGTYPE_ARRAY: 515 alignment = type_alignof(proc, type->u.array_info.elt_type); 516 if (alignment == (size_t)-1) 517 return (size_t)-1; 518 519 size = type_sizeof(proc, type->u.array_info.elt_type); 520 if (size == (size_t)-1) 521 return (size_t)-1; 522 523 return emt * align(size, alignment); 524 525 case ARGTYPE_STRING_N: 526 return emt; 527 528 case ARGTYPE_STRUCT: 529 if (layout_struct(proc, type, NULL, NULL, &emt) < 0) 530 return (size_t)-1; 531 return emt; 532 533 default: 534 abort (); 535 } 536} 537 538struct arg_type_info * 539type_element(struct arg_type_info *info, size_t emt) 540{ 541 assert(info->type == ARGTYPE_STRUCT 542 || info->type == ARGTYPE_ARRAY 543 /* XXX Temporary, this will be removed. */ 544 || info->type == ARGTYPE_STRING_N); 545 546 switch (info->type) { 547 case ARGTYPE_ARRAY: 548 return info->u.array_info.elt_type; 549 550 case ARGTYPE_STRUCT: 551 assert(emt < type_struct_size(info)); 552 return type_struct_get(info, emt); 553 554 case ARGTYPE_STRING_N: 555 return type_get_simple(ARGTYPE_CHAR); 556 557 default: 558 abort (); 559 } 560} 561