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