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 #define TAG_INDEX(x) (TNF_TAG16_ABS16(x) / sizeof (tnf_ref32_t)) 31 32 /* 33 * 34 */ 35 36 static struct taginfo * add_info(TNF *, tnf_ref32_t *); 37 38 static struct taginfo * 39 init_abstract_info(TNF *, tnf_ref32_t *, struct taginfo *); 40 41 static struct taginfo * 42 init_derived_info(TNF *, tnf_ref32_t *, struct taginfo *); 43 44 static struct taginfo * 45 init_scalar_info(TNF *, tnf_ref32_t *, struct taginfo *); 46 47 static struct taginfo * 48 init_struct_info(TNF *, tnf_ref32_t *, struct taginfo *); 49 50 static struct taginfo * 51 init_array_info(TNF *, tnf_ref32_t *, struct taginfo *); 52 53 static void init_slots(TNF *, tnf_ref32_t *, struct taginfo *); 54 55 /* 56 * Allocate tag table and directory 57 */ 58 59 tnf_errcode_t 60 _tnf_init_tags(TNF *tnf) 61 { 62 if ((tnf->tag_table = calloc(TAGTABCNT, sizeof (struct taginfo *))) 63 == NULL) 64 return (TNF_ERR_ALLOCFAIL); 65 if ((tnf->tag_directory = calloc(TAGDIRCNT(tnf->directory_size), 66 sizeof (struct taginfo *))) 67 == NULL) 68 return (TNF_ERR_ALLOCFAIL); 69 return (TNF_ERR_NONE); 70 } 71 72 /* 73 * Deallocate all taginfos and tables associated with TNF handle 74 */ 75 76 tnf_errcode_t 77 _tnf_fini_tags(TNF *tnf) 78 { 79 int i; 80 struct taginfo *info, *link; 81 82 /* 83 * free taginfos 84 */ 85 for (i = 0; i < TAGTABCNT; i++) { 86 info = tnf->tag_table[i]; 87 while (info) { 88 /* remember link */ 89 link = info->link; 90 /* free slot information */ 91 if (info->slotinfo) 92 free(info->slotinfo); 93 /* free taginfo */ 94 free(info); 95 /* next in hash chain */ 96 info = link; 97 } 98 } 99 /* 100 * free the tables 101 */ 102 free(tnf->tag_table); 103 tnf->tag_table = NULL; 104 free(tnf->tag_directory); 105 tnf->tag_directory = NULL; 106 107 return (TNF_ERR_NONE); 108 } 109 110 /* 111 * Get info for supplied tag 112 */ 113 114 struct taginfo * 115 _tnf_get_info(TNF *tnf, tnf_ref32_t *tag) 116 { 117 struct taginfo *bucket, *info; 118 119 bucket = tnf->tag_table[TAGHASH(tnf, tag)]; 120 for (info = bucket; info; info = info->link) 121 if (info->tag == tag) 122 return (info); /* found it */ 123 124 /* default: not there, create */ 125 return (add_info(tnf, tag)); 126 } 127 128 /* 129 * Get info for supplied record 130 * Use fast lookup, if possible 131 */ 132 133 struct taginfo * 134 _tnf_record_info(TNF *tnf, tnf_ref32_t *record) 135 { 136 tnf_ref32_t ref32; 137 tnf_ref16_t tag16; 138 tnf_abs16_t index; 139 struct taginfo *info; 140 141 ref32 = _GET_INT32(tnf, record); 142 143 index = 0; 144 if (TNF_REF32_IS_PAIR(ref32)) { 145 tag16 = TNF_REF32_TAG16(ref32); 146 if (TNF_TAG16_IS_ABS(tag16)) 147 index = TAG_INDEX(tag16); 148 } 149 150 if (index) { 151 if ((info = tnf->tag_directory[index]) != NULL) 152 return (info); 153 else { /* not in directory yet */ 154 info = _tnf_get_info(tnf, _tnf_get_tag(tnf, record)); 155 /* enter into tag directory */ 156 return ((tnf->tag_directory[index] = info)); 157 } 158 } 159 160 /* default: not referenced via index */ 161 return (_tnf_get_info(tnf, _tnf_get_tag(tnf, record))); 162 } 163 164 /* 165 * Add a new taginfo for tag 166 */ 167 168 static struct taginfo * 169 add_info(TNF *tnf, tnf_ref32_t *tag) 170 { 171 struct taginfo *info, *bucket; 172 unsigned hash; 173 tnf_ref32_t *meta; 174 175 info = (struct taginfo *)calloc(1, sizeof (struct taginfo)); 176 177 /* Initialize members */ 178 info->tnf = tnf; 179 info->tag = tag; 180 info->name = _tnf_get_name(tnf, tag); 181 info->props = _tnf_get_props(tnf, tag); 182 info->kind = _tnf_get_kind(tnf, tag); 183 info->size = _tnf_get_storage_size(tnf, tag); 184 info->align = _tnf_get_align(tnf, tag); 185 186 /* Add it to table */ 187 hash = TAGHASH(tnf, tag); 188 bucket = tnf->tag_table[hash]; 189 info->link = bucket; 190 tnf->tag_table[hash] = info; 191 192 /* Ensure meta info is available */ 193 meta = _tnf_get_tag(tnf, tag); 194 info->meta = _tnf_get_info(tnf, meta); 195 196 /* 197 * Initialize info 198 * Derived must be first clause due to property inheritance 199 */ 200 201 if (INFO_DERIVED(info)) 202 return (init_derived_info(tnf, tag, info)); 203 else if (INFO_STRUCT(info)) 204 return (init_struct_info(tnf, tag, info)); 205 else if (INFO_ARRAY(info)) 206 return (init_array_info(tnf, tag, info)); 207 else if (INFO_SCALAR(info)) 208 return (init_scalar_info(tnf, tag, info)); 209 else /* XXX assume abstract type */ 210 return (init_abstract_info(tnf, tag, info)); 211 } 212 213 214 /* 215 * Initialize info for an abstract tag 216 */ 217 218 static struct taginfo * 219 /* ARGSUSED */ 220 init_abstract_info(TNF *tnf, tnf_ref32_t *tag, struct taginfo *info) 221 { 222 if (INFO_SCALAR(info) || INFO_DERIVED(info) || 223 INFO_STRUCT(info) || INFO_ARRAY(info)) 224 _tnf_error(tnf, TNF_ERR_INTERNAL); 225 if (info->size == (size_t)-1) 226 _tnf_error(tnf, TNF_ERR_BADTNF); 227 return (info); 228 } 229 230 /* 231 * Initialize info for a derived tag 232 */ 233 234 static struct taginfo * 235 init_derived_info(TNF *tnf, tnf_ref32_t *tag, struct taginfo *info) 236 { 237 tnf_ref32_t *base_tag; 238 239 if (!INFO_DERIVED(info)) 240 _tnf_error(tnf, TNF_ERR_INTERNAL); 241 242 /* Ensure ultimate base information is available */ 243 base_tag = _tnf_get_base_tag(tnf, tag); 244 info->base = _tnf_get_info(tnf, base_tag); 245 246 return (info); 247 } 248 249 /* 250 * Initialize info for a scalar tag 251 */ 252 253 static struct taginfo * 254 /* ARGSUSED */ 255 init_scalar_info(TNF *tnf, tnf_ref32_t *tag, struct taginfo *info) 256 { 257 if ((!INFO_SCALAR(info)) || 258 (INFO_DERIVED(info) || INFO_ARRAY(info) || INFO_STRUCT(info))) 259 _tnf_error(tnf, TNF_ERR_INTERNAL); 260 if (info->size == (size_t)-1) 261 _tnf_error(tnf, TNF_ERR_BADTNF); 262 263 /* XXX alignment already done */ 264 265 return (info); 266 } 267 268 /* 269 * Initialize info for a struct tag 270 */ 271 272 static struct taginfo * 273 init_struct_info(TNF *tnf, tnf_ref32_t *tag, struct taginfo *info) 274 { 275 if ((!INFO_STRUCT(info)) || 276 (INFO_DERIVED(info) || INFO_ARRAY(info) || INFO_SCALAR(info))) 277 _tnf_error(tnf, TNF_ERR_INTERNAL); 278 if (info->size == (size_t)-1) 279 _tnf_error(tnf, TNF_ERR_BADTNF); 280 281 /* Get slot information */ 282 init_slots(tnf, tag, info); 283 284 return (info); 285 } 286 287 /* 288 * Initialize info for an array tag 289 */ 290 291 static struct taginfo * 292 init_array_info(TNF *tnf, tnf_ref32_t *tag, struct taginfo *info) 293 { 294 tnf_ref32_t *elt_tag; 295 int defeat; 296 297 if ((!INFO_ARRAY(info)) || 298 (INFO_DERIVED(info) || INFO_STRUCT(info) || INFO_SCALAR(info))) 299 _tnf_error(tnf, TNF_ERR_INTERNAL); 300 301 /* XXX special-case abstract array tag */ 302 defeat = (strcmp(info->name, TNF_N_ARRAY) == 0); 303 304 /* Require all arrays to be self-sized records */ 305 if (!(INFO_TAGGED(info) && (info->size == (size_t)-1))) 306 if (!defeat) 307 _tnf_error(tnf, TNF_ERR_BADTNF); 308 309 /* Store array header size */ 310 info->hdrsize = _tnf_get_header_size(tnf, tag); 311 /* XXX Temporary sanity check */ 312 if (info->hdrsize != sizeof (struct tnf_array_hdr)) 313 if (!defeat) 314 _tnf_error(tnf, TNF_ERR_BADTNF); 315 316 /* Get slot information */ 317 init_slots(tnf, tag, info); 318 319 /* Get info for element type */ 320 elt_tag = (tnf_ref32_t *)_tnf_get_slot_typed(tnf, tag, 321 /* LINTED pointer cast may result in improper alignment */ 322 TNF_N_ELEMENT_TYPE); 323 /* XXX tnf_array has element_type == NULL */ 324 info->base = elt_tag ? _tnf_get_info(tnf, elt_tag): NULL; 325 326 return (info); 327 } 328 329 /* 330 * Initialize slot information for aggregate tag 331 */ 332 333 static void 334 init_slots(TNF *tnf, tnf_ref32_t *tag, struct taginfo *info) 335 { 336 tnf_ref32_t *slot_types, *slot_names; 337 tnf_ref32_t *types, *names; 338 unsigned count, i, offset; 339 struct slotinfo *slotinfo; 340 341 slot_types = (tnf_ref32_t *) 342 /* LINTED pointer cast may result in improper alignment */ 343 _tnf_get_slot_typed(tnf, tag, TNF_N_SLOT_TYPES); 344 slot_names = (tnf_ref32_t *) 345 /* LINTED pointer cast may result in improper alignment */ 346 _tnf_get_slot_typed(tnf, tag, TNF_N_SLOT_NAMES); 347 348 /* abstract tags have no slots */ 349 if (slot_types == TNF_NULL) 350 return; 351 352 count = _tnf_get_element_count(tnf, slot_types, sizeof (tnf_ref32_t)); 353 /* LINTED pointer cast may result in improper alignment */ 354 types = (tnf_ref32_t *)_tnf_get_elements(tnf, slot_types); 355 names = ((slot_names == TNF_NULL) ? TNF_NULL : 356 /* LINTED pointer cast may result in improper alignment */ 357 (tnf_ref32_t *)_tnf_get_elements(tnf, slot_names)); 358 359 slotinfo = (struct slotinfo *) 360 calloc(1, sizeof (unsigned) + (count * sizeof (struct slot))); 361 if (slotinfo == (struct slotinfo *)NULL) 362 _tnf_error(tnf, TNF_ERR_ALLOCFAIL); 363 364 slotinfo->slot_count = count; 365 offset = 0; 366 367 for (i = 0; i < count; i++) { 368 tnf_ref32_t *type_elt, *name_elt; 369 struct taginfo *elt_info; 370 size_t ref_size, align; 371 372 /* XXX No checks here for missing tags */ 373 type_elt = _GET_REF32(tnf, &types[i]); 374 name_elt = names ? _GET_REF32(tnf, &names[i]) : TNF_NULL; 375 376 /* Resolve slot tag into taginfo */ 377 elt_info = _tnf_get_info(tnf, type_elt); 378 slotinfo->slots[i].slot_type = elt_info; 379 slotinfo->slots[i].slot_name = 380 ((name_elt != TNF_NULL) ? 381 _tnf_get_chars(tnf, name_elt) : 382 _tnf_get_name(tnf, type_elt)); 383 384 /* Get cached reference size */ 385 ref_size = INFO_REF_SIZE(elt_info); 386 387 /* Get cached alignment */ 388 align = INFO_ALIGN(elt_info); /* XXX */ 389 390 /* Adjust offset to account for alignment, if needed */ 391 offset = ALIGN(offset, align); 392 393 slotinfo->slots[i].slot_offset = offset; 394 395 /* Bump offset by reference size */ 396 offset += ref_size; 397 } 398 399 info->slotinfo = slotinfo; 400 } 401