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 *
_tnf_get_tag(TNF * tnf,tnf_ref32_t * record)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 *
_tnf_get_tag_arg(TNF * tnf,tnf_ref32_t * record)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
_tnf_get_self_size(TNF * tnf,tnf_ref32_t * array)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
_tnf_get_element_count(TNF * tnf,tnf_ref32_t * array,unsigned eltsize)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 */
_tnf_get_elements(TNF * tnf,tnf_ref32_t * array)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 *
_tnf_get_chars(TNF * tnf,tnf_ref32_t * string)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 *
_tnf_get_name(TNF * tnf,tnf_ref32_t * tag)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 *
_tnf_get_properties(TNF * tnf,tnf_ref32_t * tag)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 *
_tnf_get_slot_types(TNF * tnf,tnf_ref32_t * tag)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
_tnf_get_header_size(TNF * tnf,tnf_ref32_t * tag)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 *
_tnf_get_derived_base(TNF * tnf,tnf_ref32_t * tag)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 *
_tnf_get_root_tag(TNF * tnf,tnf_ref32_t * record)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 *
_tnf_get_element_named(TNF * tnf,tnf_ref32_t * array,char * name)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 *
_tnf_get_property(TNF * tnf,tnf_ref32_t * tag,char * name)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 *
_tnf_get_base_tag(TNF * tnf,tnf_ref32_t * tag)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
_tnf_get_ref_size(TNF * tnf,tnf_ref32_t * tag)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
_tnf_get_storage_size(TNF * tnf,tnf_ref32_t * tag)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
_tnf_get_align(TNF * tnf,tnf_ref32_t * tag)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
_tnf_get_slot_typed(TNF * tnf,tnf_ref32_t * record,char * name)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
_tnf_get_slot_named(TNF * tnf,tnf_ref32_t * record,char * name)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
fetch_slot(TNF * tnf,caddr_t p,tnf_ref32_t * tag)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