type.c revision 2fb2b8d877ae562374a89ad777ec24534522840e
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: 57 case ARGTYPE_STRING_N: 58 case ARGTYPE_COUNT: 59 60 case ARGTYPE_ARRAY: 61 case ARGTYPE_ENUM: 62 case ARGTYPE_STRUCT: 63 case ARGTYPE_POINTER: 64 assert(!"Not a simple type!"); 65 }; 66 abort(); 67} 68 69struct enum_entry { 70 char *key; 71 int own_key; 72 int value; 73}; 74 75void 76type_init_enum(struct arg_type_info *info) 77{ 78 info->type = ARGTYPE_ENUM; 79 VECT_INIT(&info->u.entries, struct enum_entry); 80} 81 82int 83type_enum_add(struct arg_type_info *info, 84 const char *key, int own_key, int value) 85{ 86 assert(info->type == ARGTYPE_ENUM); 87 struct enum_entry entry = { (char *)key, own_key, value }; 88 return VECT_PUSHBACK(&info->u.entries, &entry); 89} 90 91size_t 92type_enum_size(struct arg_type_info *info) 93{ 94 assert(info->type == ARGTYPE_ENUM); 95 return vect_size(&info->u.entries); 96} 97 98const char * 99type_enum_get(struct arg_type_info *info, int value) 100{ 101 assert(info->type == ARGTYPE_ENUM); 102 size_t i; 103 for (i = 0; i < info->u.enum_info.entries; ++i) { 104 if (value == info->u.enum_info.values[i]) 105 return info->u.enum_info.keys[i]; 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 241static void 242type_array_destroy(struct arg_type_info *info) 243{ 244 if (info->u.array_info.own_info) { 245 type_destroy(info->u.array_info.elt_type); 246 free(info->u.array_info.elt_type); 247 } 248 if (info->u.array_info.own_length) { 249 expr_destroy(info->u.array_info.length); 250 free(info->u.array_info.length); 251 } 252} 253 254static void 255type_string_n_destroy(struct arg_type_info *info) 256{ 257 if (info->u.array_info.own_length) { 258 expr_destroy(info->u.string_n_info.length); 259 free(info->u.string_n_info.length); 260 } 261} 262 263void 264type_init_pointer(struct arg_type_info *info, 265 struct arg_type_info *pointee_info, int own_info) 266{ 267 info->type = ARGTYPE_POINTER; 268 info->u.ptr_info.info = pointee_info; 269 info->u.ptr_info.own_info = own_info; 270} 271 272static void 273type_pointer_destroy(struct arg_type_info *info) 274{ 275 if (info->u.ptr_info.own_info) { 276 type_destroy(info->u.ptr_info.info); 277 free(info->u.ptr_info.info); 278 } 279} 280 281void 282type_destroy(struct arg_type_info *info) 283{ 284 if (info == NULL) 285 return; 286 287 switch (info->type) { 288 case ARGTYPE_ENUM: 289 return type_enum_destroy(info); 290 291 case ARGTYPE_STRUCT: 292 type_struct_destroy(info); 293 break; 294 295 case ARGTYPE_ARRAY: 296 type_array_destroy(info); 297 break; 298 299 case ARGTYPE_POINTER: 300 type_pointer_destroy(info); 301 break; 302 303 case ARGTYPE_STRING_N: 304 type_string_n_destroy(info); 305 306 case ARGTYPE_UNKNOWN: 307 case ARGTYPE_VOID: 308 case ARGTYPE_INT: 309 case ARGTYPE_UINT: 310 case ARGTYPE_LONG: 311 case ARGTYPE_ULONG: 312 case ARGTYPE_OCTAL: 313 case ARGTYPE_CHAR: 314 case ARGTYPE_SHORT: 315 case ARGTYPE_USHORT: 316 case ARGTYPE_FLOAT: 317 case ARGTYPE_DOUBLE: 318 break; 319 320 case ARGTYPE_FORMAT: 321 case ARGTYPE_STRING: 322 case ARGTYPE_COUNT: 323 break; 324 } 325} 326 327#ifdef ARCH_HAVE_SIZEOF 328size_t arch_type_sizeof(struct Process *proc, struct arg_type_info * arg); 329#else 330size_t 331arch_type_sizeof(struct Process *proc, struct arg_type_info * arg) 332{ 333 /* Use default value. */ 334 return (size_t)-2; 335} 336#endif 337 338#ifdef ARCH_HAVE_ALIGNOF 339size_t arch_type_alignof(struct Process *proc, struct arg_type_info * arg); 340#else 341size_t 342arch_type_alignof(struct Process *proc, struct arg_type_info * arg) 343{ 344 /* Use default value. */ 345 return (size_t)-2; 346} 347#endif 348 349/* We need to support alignments that are not power of two. E.g. long 350 * double on x86 has alignment of 12. */ 351size_t 352align(size_t sz, size_t alignment) 353{ 354 assert(alignment != 0); 355 356 if ((sz % alignment) != 0) 357 sz = ((sz / alignment) + 1) * alignment; 358 359 return sz; 360} 361 362size_t 363type_sizeof(struct Process *proc, struct arg_type_info *type) 364{ 365 size_t arch_size = arch_type_sizeof(proc, type); 366 if (arch_size != (size_t)-2) 367 return arch_size; 368 369 switch (type->type) { 370 size_t size; 371 case ARGTYPE_CHAR: 372 return sizeof(char); 373 374 case ARGTYPE_SHORT: 375 case ARGTYPE_USHORT: 376 return sizeof(short); 377 378 case ARGTYPE_INT: 379 case ARGTYPE_UINT: 380 case ARGTYPE_ENUM: 381 return sizeof(int); 382 383 case ARGTYPE_LONG: 384 case ARGTYPE_ULONG: 385 return sizeof(long); 386 387 case ARGTYPE_FLOAT: 388 return sizeof(float); 389 390 case ARGTYPE_DOUBLE: 391 return sizeof(double); 392 393 case ARGTYPE_STRUCT: 394 if (layout_struct(proc, type, &size, NULL, NULL) < 0) 395 return (size_t)-1; 396 return size; 397 398 case ARGTYPE_POINTER: 399 return sizeof(void *); 400 401 case ARGTYPE_ARRAY: 402 if (expr_is_compile_constant(type->u.array_info.length)) { 403 long l; 404 if (expr_eval_constant(type->u.array_info.length, 405 &l) < 0) 406 return -1; 407 408 struct arg_type_info *elt_ti 409 = type->u.array_info.elt_type; 410 411 size_t elt_size = type_sizeof(proc, elt_ti); 412 if (elt_size == (size_t)-1) 413 return (size_t)-1; 414 415 return ((size_t)l) * elt_size; 416 417 } else { 418 /* Flexible arrays don't count into the 419 * sizeof. */ 420 return 0; 421 } 422 423 case ARGTYPE_VOID: 424 return 0; 425 426 /* XXX these are in fact formatting conventions, not 427 * data types. They should be handled differently. */ 428 case ARGTYPE_OCTAL: 429 case ARGTYPE_UNKNOWN: 430 return sizeof(long); 431 432 case ARGTYPE_FORMAT: 433 case ARGTYPE_STRING: 434 case ARGTYPE_STRING_N: 435 case ARGTYPE_COUNT: 436 return -1; 437 } 438 439 abort(); 440} 441 442#undef alignof 443#define alignof(field,st) ((size_t) ((char*) &st.field - (char*) &st)) 444 445size_t 446type_alignof(struct Process *proc, struct arg_type_info *type) 447{ 448 size_t arch_alignment = arch_type_alignof(proc, type); 449 if (arch_alignment != (size_t)-2) 450 return arch_alignment; 451 452 struct { char c; char C; } cC; 453 struct { char c; short s; } cs; 454 struct { char c; int i; } ci; 455 struct { char c; long l; } cl; 456 struct { char c; void* p; } cp; 457 struct { char c; float f; } cf; 458 struct { char c; double d; } cd; 459 460 static size_t char_alignment = alignof(C, cC); 461 static size_t short_alignment = alignof(s, cs); 462 static size_t int_alignment = alignof(i, ci); 463 static size_t long_alignment = alignof(l, cl); 464 static size_t ptr_alignment = alignof(p, cp); 465 static size_t float_alignment = alignof(f, cf); 466 static size_t double_alignment = alignof(d, cd); 467 468 switch (type->type) { 469 size_t alignment; 470 case ARGTYPE_LONG: 471 case ARGTYPE_ULONG: 472 return long_alignment; 473 case ARGTYPE_CHAR: 474 return char_alignment; 475 case ARGTYPE_SHORT: 476 case ARGTYPE_USHORT: 477 return short_alignment; 478 case ARGTYPE_FLOAT: 479 return float_alignment; 480 case ARGTYPE_DOUBLE: 481 return double_alignment; 482 case ARGTYPE_POINTER: 483 return ptr_alignment; 484 485 case ARGTYPE_ARRAY: 486 return type_alignof(proc, type->u.array_info.elt_type); 487 488 case ARGTYPE_STRUCT: 489 if (layout_struct(proc, type, NULL, &alignment, NULL) < 0) 490 return (size_t)-1; 491 return alignment; 492 493 default: 494 return int_alignment; 495 } 496} 497 498size_t 499type_offsetof(struct Process *proc, struct arg_type_info *type, size_t emt) 500{ 501 assert(type->type == ARGTYPE_STRUCT 502 || type->type == ARGTYPE_ARRAY 503 /* XXX Temporary, this will be removed. */ 504 || type->type == ARGTYPE_STRING 505 || type->type == ARGTYPE_STRING_N); 506 507 switch (type->type) { 508 size_t alignment; 509 size_t size; 510 case ARGTYPE_ARRAY: 511 alignment = type_alignof(proc, type->u.array_info.elt_type); 512 if (alignment == (size_t)-1) 513 return (size_t)-1; 514 515 size = type_sizeof(proc, type->u.array_info.elt_type); 516 if (size == (size_t)-1) 517 return (size_t)-1; 518 519 return emt * align(size, alignment); 520 521 case ARGTYPE_STRING: 522 case ARGTYPE_STRING_N: 523 return emt; 524 525 case ARGTYPE_STRUCT: 526 if (layout_struct(proc, type, NULL, NULL, &emt) < 0) 527 return (size_t)-1; 528 return emt; 529 530 default: 531 abort (); 532 } 533} 534 535struct arg_type_info * 536type_element(struct arg_type_info *info, size_t emt) 537{ 538 assert(info->type == ARGTYPE_STRUCT 539 || info->type == ARGTYPE_ARRAY 540 /* XXX Temporary, this will be removed. */ 541 || info->type == ARGTYPE_STRING 542 || info->type == ARGTYPE_STRING_N); 543 544 switch (info->type) { 545 case ARGTYPE_ARRAY: 546 return info->u.array_info.elt_type; 547 548 case ARGTYPE_STRUCT: 549 assert(emt < type_struct_size(info)); 550 return type_struct_get(info, emt); 551 552 case ARGTYPE_STRING: 553 case ARGTYPE_STRING_N: 554 return type_get_simple(ARGTYPE_CHAR); 555 556 default: 557 abort (); 558 } 559} 560