1 /* 2 * CDDL HEADER START 3 * 4 * The contents of this file are subject to the terms of the 5 * Common Development and Distribution License, Version 1.0 only 6 * (the "License"). You may not use this file except in compliance 7 * with the License. 8 * 9 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 10 * or http://www.opensolaris.org/os/licensing. 11 * See the License for the specific language governing permissions 12 * and limitations under the License. 13 * 14 * When distributing Covered Code, include this CDDL HEADER in each 15 * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 16 * If applicable, add the following below this CDDL HEADER, with the 17 * fields enclosed by brackets "[]" replaced with your own identifying 18 * information: Portions Copyright [yyyy] [name of copyright owner] 19 * 20 * CDDL HEADER END 21 */ 22 /* 23 * Copyright (c) 1994, by Sun Microsytems, Inc. 24 */ 25 26 #pragma ident "%Z%%M% %I% %E% SMI" 27 28 #include "libtnf.h" 29 30 /* 31 * Operations based on ABI bootstrap assumptions 32 */ 33 34 #define _GET_TAG(tnf, p) \ 35 _GET_REF32(tnf, p) 36 37 #define _GET_TAG_ARG(tnf, p) \ 38 _GET_REF16(tnf, p) 39 40 #define _GET_SELF_SIZE(tnf, p) \ 41 _GET_UINT32(tnf, &((struct tnf_array_hdr *)(p))->self_size) 42 43 #define _GET_NAME(tnf, p) \ 44 _GET_REF32(tnf, &((struct tnf_type_hdr *)(p))->name) 45 46 #define _GET_PROPERTIES(tnf, p) \ 47 _GET_REF32(tnf, &((struct tnf_type_hdr *)(p))->properties) 48 49 #define _GET_SLOT_TYPES(tnf, p) \ 50 _GET_REF32(tnf, &((struct tnf_struct_type_hdr *)(p))->slot_types) 51 52 #define _GET_TYPE_SIZE(tnf, p) \ 53 _GET_UINT32(tnf, &((struct tnf_struct_type_hdr *)(p))->type_size) 54 55 #define _GET_HEADER_SIZE(tnf, p) \ 56 _GET_UINT32(tnf, &((struct tnf_array_type_hdr *)(p))->header_size) 57 58 #define _GET_DERIVED_BASE(tnf, p) \ 59 _GET_REF32(tnf, &((struct tnf_derived_type_hdr *)(p))->derived_base) 60 61 /* 62 * Static declarations 63 */ 64 65 static caddr_t fetch_slot(TNF *, caddr_t, tnf_ref32_t *); 66 67 /* 68 * retrieve tag slot from a record 69 */ 70 71 tnf_ref32_t * 72 _tnf_get_tag(TNF *tnf, tnf_ref32_t *record) 73 { 74 return (_GET_TAG(tnf, record)); 75 } 76 77 /* 78 * Retrieve tag_arg from tag slot of a record 79 */ 80 81 tnf_ref32_t * 82 _tnf_get_tag_arg(TNF *tnf, tnf_ref32_t *record) 83 { 84 return (_GET_TAG_ARG(tnf, record)); 85 } 86 87 /* 88 * Retrieve the self_size slot of an ABI array record 89 */ 90 91 size_t 92 _tnf_get_self_size(TNF *tnf, tnf_ref32_t *array) 93 { 94 return (_GET_SELF_SIZE(tnf, array)); 95 } 96 97 /* 98 * Calculate the number of elements in ABI array record 99 */ 100 101 unsigned 102 _tnf_get_element_count(TNF *tnf, tnf_ref32_t *array, unsigned eltsize) 103 { 104 size_t size, hdrsize; 105 #ifdef INFINITE_RECURSION_ARRAY 106 tnf_ref32_t *base_tag; 107 108 size = _tnf_get_self_size(tnf, array); 109 base_tag = _tnf_get_base_tag(tnf, _tnf_get_tag(tnf, array)); 110 hdrsize = _tnf_get_header_size(tnf, base_tag); 111 return (((size - hdrsize) / eltsize)); 112 #else 113 size = _tnf_get_self_size(tnf, array); 114 hdrsize = sizeof (struct tnf_array_hdr); 115 return (((size - hdrsize) / eltsize)); 116 #endif 117 } 118 119 /* 120 * Retrieve the base pointer of an ABI array record 121 */ 122 123 caddr_t 124 /* ARGSUSED */ 125 _tnf_get_elements(TNF *tnf, tnf_ref32_t *array) 126 { 127 #ifdef INFINITE_RECURSION_ARRAY 128 size_t hdrsize; 129 tnf_ref32_t *base_tag; 130 131 base_tag = _tnf_get_base_tag(tnf, _tnf_get_tag(tnf, array)); 132 hdrsize = _tnf_get_header_size(tnf, base_tag); 133 return ((caddr_t)((char *)array + hdrsize)); 134 #else 135 return ((caddr_t)((char *)array + sizeof (struct tnf_array_hdr))); 136 #endif 137 } 138 139 /* 140 * Retrieve the chars in an ABI string record 141 */ 142 143 char * 144 _tnf_get_chars(TNF *tnf, tnf_ref32_t *string) 145 { 146 return ((char *)_tnf_get_elements(tnf, string)); 147 } 148 149 /* 150 * Retrieve the string in the name slot of a type record 151 */ 152 153 char * 154 _tnf_get_name(TNF *tnf, tnf_ref32_t *tag) 155 { 156 return (_tnf_get_chars(tnf, _GET_NAME(tnf, tag))); 157 } 158 159 /* 160 * Retrieve the properties array slot of a type record 161 */ 162 163 tnf_ref32_t * 164 _tnf_get_properties(TNF *tnf, tnf_ref32_t *tag) 165 { 166 return (_GET_PROPERTIES(tnf, tag)); 167 } 168 169 /* 170 * Retrieve the slot_types slot of struct_type or array_type record 171 */ 172 173 tnf_ref32_t * 174 _tnf_get_slot_types(TNF *tnf, tnf_ref32_t *tag) 175 { 176 return (_GET_SLOT_TYPES(tnf, tag)); 177 } 178 179 /* 180 * Retrieve the header_size slot of an array_type record 181 */ 182 183 size_t 184 _tnf_get_header_size(TNF *tnf, tnf_ref32_t *tag) 185 { 186 return (_GET_HEADER_SIZE(tnf, tag)); 187 } 188 189 /* 190 * Retrieve the derived_base slot of a derived_type record 191 */ 192 193 tnf_ref32_t * 194 _tnf_get_derived_base(TNF *tnf, tnf_ref32_t *tag) 195 { 196 return (_GET_DERIVED_BASE(tnf, tag)); 197 } 198 199 200 /* 201 * Find the root (self-tagged) type record 202 */ 203 204 tnf_ref32_t * 205 _tnf_get_root_tag(TNF *tnf, tnf_ref32_t *record) 206 { 207 if (tnf->root_tag) 208 return (tnf->root_tag); 209 else { 210 tnf_ref32_t *p1, *p2; 211 p1 = record; 212 while ((p2 = _tnf_get_tag(tnf, p1)) != p1) 213 p1 = p2; 214 tnf->root_tag = p2; 215 return (p2); 216 } 217 } 218 219 /* 220 * Search ABI type array for a type named name 221 */ 222 223 tnf_ref32_t * 224 _tnf_get_element_named(TNF *tnf, tnf_ref32_t *array, char *name) 225 { 226 unsigned count, i; 227 tnf_ref32_t *elts; 228 229 count = _tnf_get_element_count(tnf, array, sizeof (tnf_ref32_t)); 230 /* LINTED pointer cast may result in improper alignment */ 231 elts = (tnf_ref32_t *)_tnf_get_elements(tnf, array); 232 233 for (i = 0; i < count; i++) { 234 tnf_ref32_t *type_elt; 235 236 if ((type_elt = _GET_REF32(tnf, &elts[i])) == TNF_NULL) { 237 /* Can't have missing type records */ 238 _tnf_error(tnf, TNF_ERR_BADTNF); 239 return (TNF_NULL); 240 } 241 242 if (strcmp(name, _tnf_get_name(tnf, type_elt)) == 0) 243 /* Found a type record named name */ 244 return (type_elt); 245 } 246 return (TNF_NULL); 247 } 248 249 /* 250 * Look in type record's properties for named type. 251 * Recursively look at derived_base properties as well. 252 */ 253 254 tnf_ref32_t * 255 _tnf_get_property(TNF *tnf, tnf_ref32_t *tag, char *name) 256 { 257 tnf_ref32_t *properties, *property; 258 259 if (strcmp(name, _tnf_get_name(tnf, tag)) == 0) 260 /* name is type name */ 261 return (tag); 262 263 if ((properties = _tnf_get_properties(tnf, tag)) == TNF_NULL) 264 /* no properties */ 265 return (TNF_NULL); 266 267 if ((property = _tnf_get_element_named(tnf, properties, name)) 268 != TNF_NULL) 269 /* found property named name */ 270 return (property); 271 272 /* 273 * Recursively check base type of derived types 274 */ 275 if (_tnf_get_element_named(tnf, properties, TNF_N_DERIVED) 276 != TNF_NULL) { 277 /* tag is a derived type: check its derived_base */ 278 tnf_ref32_t *base_tag; 279 280 base_tag = _tnf_get_derived_base(tnf, tag); 281 /* tnf_derived has derived_base == TNF_NULL */ 282 if (base_tag != TNF_NULL) 283 return (_tnf_get_property(tnf, base_tag, name)); 284 } 285 286 return (TNF_NULL); 287 } 288 289 /* 290 * Get the ultimate base type of a type record 291 */ 292 293 tnf_ref32_t * 294 _tnf_get_base_tag(TNF *tnf, tnf_ref32_t *tag) 295 { 296 tnf_ref32_t *properties; 297 298 if ((properties = _tnf_get_properties(tnf, tag)) == TNF_NULL) 299 /* no properties */ 300 return (tag); 301 302 if (_tnf_get_element_named(tnf, properties, TNF_N_DERIVED) 303 != TNF_NULL) { 304 tnf_ref32_t *base_tag; 305 306 if ((base_tag = _tnf_get_derived_base(tnf, tag)) != TNF_NULL) 307 return (_tnf_get_base_tag(tnf, base_tag)); 308 } 309 310 return (tag); 311 } 312 313 /* 314 * Calculate the reference size of an object with type==tag 315 */ 316 317 size_t 318 _tnf_get_ref_size(TNF *tnf, tnf_ref32_t *tag) 319 { 320 if (HAS_PROPERTY(tnf, tag, TNF_N_TAGGED)) { 321 /* Tagged objects occupy 4 bytes for reference */ 322 return ((sizeof (tnf_ref32_t))); 323 } else if (HAS_PROPERTY(tnf, tag, TNF_N_INLINE)) { 324 /* Inline slots cannot be self sized */ 325 return (_tnf_get_storage_size(tnf, tag)); 326 } else { 327 /* Illegal to have references to abstract objects */ 328 _tnf_error(tnf, TNF_ERR_BADTNF); 329 return ((0)); 330 } 331 } 332 333 /* 334 * Calculate storage size of an object with type==tag 335 */ 336 337 size_t 338 _tnf_get_storage_size(TNF *tnf, tnf_ref32_t *tag) 339 { 340 if (_tnf_get_tag(tnf, tag) == _tnf_get_root_tag(tnf, tag)) 341 return (_GET_TYPE_SIZE(tnf, tag)); 342 else { 343 tnf_ref32_t *base_tag; /* implementation tag */ 344 caddr_t sizep; 345 tnf_ref32_t *slot_types; 346 347 #ifndef INFINITE_RECURSION_SIZE 348 char *base_name; 349 static struct n2s { 350 char *name; 351 size_t size; 352 } n2s[] = { 353 { TNF_N_CHAR, sizeof (tnf_char_t) }, 354 { TNF_N_INT8, sizeof (tnf_int8_t) }, 355 { TNF_N_INT16, sizeof (tnf_int16_t) }, 356 { TNF_N_INT32, sizeof (tnf_int32_t) }, 357 { TNF_N_UINT8, sizeof (tnf_uint8_t) }, 358 { TNF_N_UINT16, sizeof (tnf_uint16_t) }, 359 { TNF_N_UINT32, sizeof (tnf_uint32_t) }, 360 { TNF_N_INT64, sizeof (tnf_int64_t) }, 361 { TNF_N_UINT64, sizeof (tnf_uint64_t) }, 362 { TNF_N_FLOAT32, sizeof (tnf_float32_t) }, 363 { TNF_N_FLOAT64, sizeof (tnf_float64_t) }, 364 { NULL, 0 } 365 }; 366 struct n2s *p; 367 #endif 368 369 base_tag = _tnf_get_base_tag(tnf, tag); 370 371 #ifndef INFINITE_RECURSION_SIZE 372 base_name = _tnf_get_name(tnf, base_tag); 373 374 /* XXX Why are we in this mess? */ 375 p = n2s; 376 while (p->name) { 377 if (strcmp(p->name, base_name) == 0) 378 return (p->size); 379 p++; 380 } 381 #endif 382 383 sizep = _tnf_get_slot_typed(tnf, base_tag, TNF_N_TYPE_SIZE); 384 if (sizep) 385 /* Type sized */ 386 /* LINTED pointer cast may result in improper alignment */ 387 return (_GET_UINT32(tnf, (tnf_uint32_t *)sizep)); 388 389 slot_types = (tnf_ref32_t *) 390 /* LINTED pointer cast may result in improper alignment */ 391 _tnf_get_slot_typed(tnf, base_tag, TNF_N_SLOT_TYPES); 392 if (slot_types && 393 _tnf_get_element_named(tnf, slot_types, TNF_N_SELF_SIZE)) 394 /* Self sized */ 395 return ((size_t)-1); 396 else 397 /* Abstract */ 398 return (0); 399 } 400 } 401 402 /* 403 * Return the alignment restriction for any tag 404 */ 405 406 unsigned 407 _tnf_get_align(TNF *tnf, tnf_ref32_t *tag) 408 { 409 if (HAS_PROPERTY(tnf, tag, TNF_N_SCALAR)) { 410 tnf_ref32_t *base_tag; 411 caddr_t alignp; 412 413 base_tag = _tnf_get_base_tag(tnf, tag); 414 alignp = _tnf_get_slot_typed(tnf, base_tag, TNF_N_ALIGN); 415 if (alignp) 416 /* LINTED pointer cast may result in improper alignment */ 417 return (_GET_UINT32(tnf, (tnf_uint32_t *)alignp)); 418 } 419 /* default: word alignment */ 420 return ((4)); 421 } 422 423 /* 424 * Only works for records 425 * Doesn't check for slot_names in tag 426 * Tag records, for example, never have named slots 427 */ 428 429 caddr_t 430 _tnf_get_slot_typed(TNF *tnf, tnf_ref32_t *record, char *name) 431 { 432 tnf_ref32_t *tag, *base_tag; 433 tnf_ref32_t *slot_types, *types; 434 unsigned count, i; 435 unsigned offset; 436 437 tag = _tnf_get_tag(tnf, record); 438 base_tag = _tnf_get_base_tag(tnf, tag); 439 440 /* 441 * The position of slot_types is ABI fixed 442 * XXX Assume it is present in tag 443 */ 444 slot_types = _tnf_get_slot_types(tnf, base_tag); 445 count = _tnf_get_element_count(tnf, slot_types, sizeof (tnf_ref32_t)); 446 /* LINTED pointer cast may result in improper alignment */ 447 types = (tnf_ref32_t *)_tnf_get_elements(tnf, slot_types); 448 449 offset = 0; 450 451 for (i = 0; i < count; i++) { 452 tnf_ref32_t *type_elt; 453 size_t ref_size, align; 454 455 /* Find the type record for slot */ 456 if ((type_elt = _GET_REF32(tnf, &types[i])) == TNF_NULL) { 457 /* Can't have missing type records */ 458 _tnf_error(tnf, TNF_ERR_BADTNF); 459 return ((caddr_t)NULL); 460 } 461 462 /* See similar hack in init_slots() */ 463 464 /* Calculate reference size */ 465 ref_size = _tnf_get_ref_size(tnf, type_elt); 466 467 /* 468 * Calculate alignment 469 * XXX Prevent infinite recursion by assuming that 470 * a reference size of 4 implies word alignment 471 */ 472 align = (ref_size == 4)? 4: _tnf_get_align(tnf, type_elt); 473 474 /* Adjust offset to account for alignment, if needed */ 475 offset = ALIGN(offset, align); 476 477 /* Check whether name corresponds to type name */ 478 if (strcmp(name, _tnf_get_name(tnf, type_elt)) == 0) 479 /* Found the slot */ 480 return (fetch_slot(tnf, (caddr_t)record + offset, 481 type_elt)); 482 483 /* Bump offset by reference size */ 484 offset += ref_size; 485 } 486 487 return ((caddr_t)NULL); 488 } 489 490 /* 491 * Only works for records 492 */ 493 494 caddr_t 495 _tnf_get_slot_named(TNF *tnf, tnf_ref32_t *record, char *name) 496 { 497 tnf_ref32_t *tag, *base_tag; 498 tnf_ref32_t *slot_types, *slot_names, *types, *names; 499 unsigned count, i; 500 unsigned offset; 501 502 tag = _tnf_get_tag(tnf, record); 503 base_tag = _tnf_get_base_tag(tnf, tag); 504 505 /* 506 * slot_names are optional 507 */ 508 slot_names = (tnf_ref32_t *) 509 /* LINTED pointer cast may result in improper alignment */ 510 _tnf_get_slot_typed(tnf, base_tag, TNF_N_SLOT_NAMES); 511 512 /* no slot_names; use _tnf_get_slot_typed() */ 513 if (slot_names == TNF_NULL) 514 return (_tnf_get_slot_typed(tnf, record, name)); 515 516 /* 517 * The position of slot_types is ABI fixed 518 * XXX Assume it is present in tag 519 */ 520 slot_types = _tnf_get_slot_types(tnf, base_tag); 521 count = _tnf_get_element_count(tnf, slot_types, sizeof (tnf_ref32_t)); 522 /* LINTED pointer cast may result in improper alignment */ 523 types = (tnf_ref32_t *)_tnf_get_elements(tnf, slot_types); 524 /* LINTED pointer cast may result in improper alignment */ 525 names = (tnf_ref32_t *)_tnf_get_elements(tnf, slot_names); 526 527 offset = 0; 528 529 for (i = 0; i < count; i++) { 530 tnf_ref32_t *type_elt, *name_elt; 531 size_t ref_size, align; 532 533 /* Find the type record for slot */ 534 if ((type_elt = _GET_REF32(tnf, &types[i])) == TNF_NULL) { 535 /* Can't have missing type records */ 536 _tnf_error(tnf, TNF_ERR_BADTNF); 537 return ((caddr_t)NULL); 538 } 539 540 /* XXX Keep consistent with init_slots() */ 541 542 /* Calculate reference size */ 543 ref_size = _tnf_get_ref_size(tnf, type_elt); 544 545 /* 546 * Calculate alignment 547 * XXX Prevent infinite recursion by assuming that 548 * a reference size of 4 implies word alignment 549 */ 550 align = (ref_size == 4)? 4: _tnf_get_align(tnf, type_elt); 551 552 /* Adjust offset to account for alignment, if needed */ 553 offset = ALIGN(offset, align); 554 555 /* First check slot name, then type name */ 556 if ((((name_elt = _GET_REF32(tnf, &names[i])) != TNF_NULL) && 557 (strcmp(name, _tnf_get_chars(tnf, name_elt)) == 0)) || 558 (strcmp(name, _tnf_get_name(tnf, type_elt)) == 0)) 559 /* Found slot */ 560 return (fetch_slot(tnf, (caddr_t)record + offset, 561 type_elt)); 562 563 /* Bump offset by reference size */ 564 offset += ref_size; 565 } 566 567 return ((caddr_t)NULL); 568 } 569 570 static caddr_t 571 fetch_slot(TNF *tnf, caddr_t p, tnf_ref32_t *tag) 572 { 573 if (HAS_PROPERTY(tnf, tag, TNF_N_INLINE)) 574 return (p); 575 else /* XXX assume tagged */ 576 /* LINTED pointer cast may result in improper alignment */ 577 return ((caddr_t)_GET_REF32(tnf, (tnf_ref32_t *)p)); 578 } 579