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