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
_tnf_init_tags(TNF * tnf)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
_tnf_fini_tags(TNF * tnf)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 *
_tnf_get_info(TNF * tnf,tnf_ref32_t * tag)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 *
_tnf_record_info(TNF * tnf,tnf_ref32_t * record)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 *
add_info(TNF * tnf,tnf_ref32_t * tag)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 */
init_abstract_info(TNF * tnf,tnf_ref32_t * tag,struct taginfo * info)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 *
init_derived_info(TNF * tnf,tnf_ref32_t * tag,struct taginfo * info)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 */
init_scalar_info(TNF * tnf,tnf_ref32_t * tag,struct taginfo * info)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 *
init_struct_info(TNF * tnf,tnf_ref32_t * tag,struct taginfo * info)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 *
init_array_info(TNF * tnf,tnf_ref32_t * tag,struct taginfo * info)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
init_slots(TNF * tnf,tnf_ref32_t * tag,struct taginfo * info)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