xref: /illumos-gate/usr/src/lib/libtnf/abi.c (revision 7c478bd9)
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