OpenSolaris_b135/lib/libtnf/abi.c

Compare this file to the similar file:
Show the results in this format:

/*
 * CDDL HEADER START
 *
 * The contents of this file are subject to the terms of the
 * Common Development and Distribution License, Version 1.0 only
 * (the "License").  You may not use this file except in compliance
 * with the License.
 *
 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
 * or http://www.opensolaris.org/os/licensing.
 * See the License for the specific language governing permissions
 * and limitations under the License.
 *
 * When distributing Covered Code, include this CDDL HEADER in each
 * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
 * If applicable, add the following below this CDDL HEADER, with the
 * fields enclosed by brackets "[]" replaced with your own identifying
 * information: Portions Copyright [yyyy] [name of copyright owner]
 *
 * CDDL HEADER END
 */
/*
 *	Copyright (c) 1994, by Sun Microsytems, Inc.
 */

#pragma	ident	"%Z%%M%	%I%	%E% SMI"

#include "libtnf.h"

/*
 * Operations based on ABI bootstrap assumptions
 */

#define	_GET_TAG(tnf, p)		\
	_GET_REF32(tnf, p)

#define	_GET_TAG_ARG(tnf, p)		\
	_GET_REF16(tnf, p)

#define	_GET_SELF_SIZE(tnf, p) 		\
	_GET_UINT32(tnf, &((struct tnf_array_hdr *)(p))->self_size)

#define	_GET_NAME(tnf, p)		\
	_GET_REF32(tnf, &((struct tnf_type_hdr *)(p))->name)

#define	_GET_PROPERTIES(tnf, p)		\
	_GET_REF32(tnf, &((struct tnf_type_hdr *)(p))->properties)

#define	_GET_SLOT_TYPES(tnf, p)		\
	_GET_REF32(tnf, &((struct tnf_struct_type_hdr *)(p))->slot_types)

#define	_GET_TYPE_SIZE(tnf, p)		\
	_GET_UINT32(tnf, &((struct tnf_struct_type_hdr *)(p))->type_size)

#define	_GET_HEADER_SIZE(tnf, p)	\
	_GET_UINT32(tnf, &((struct tnf_array_type_hdr *)(p))->header_size)

#define	_GET_DERIVED_BASE(tnf, p)	\
	_GET_REF32(tnf, &((struct tnf_derived_type_hdr *)(p))->derived_base)

/*
 * Static declarations
 */

static caddr_t	fetch_slot(TNF *, caddr_t, tnf_ref32_t *);

/*
 * retrieve tag slot from a record
 */

tnf_ref32_t *
_tnf_get_tag(TNF *tnf, tnf_ref32_t *record)
{
	return (_GET_TAG(tnf, record));
}

/*
 * Retrieve tag_arg from tag slot of a record
 */

tnf_ref32_t *
_tnf_get_tag_arg(TNF *tnf, tnf_ref32_t *record)
{
	return (_GET_TAG_ARG(tnf, record));
}

/*
 * Retrieve the self_size slot of an ABI array record
 */

size_t
_tnf_get_self_size(TNF *tnf, tnf_ref32_t *array)
{
	return (_GET_SELF_SIZE(tnf, array));
}

/*
 * Calculate the number of elements in ABI array record
 */

unsigned
_tnf_get_element_count(TNF *tnf, tnf_ref32_t *array, unsigned eltsize)
{
	size_t		size, hdrsize;
#ifdef INFINITE_RECURSION_ARRAY
	tnf_ref32_t	*base_tag;

	size 		= _tnf_get_self_size(tnf, array);
	base_tag 	= _tnf_get_base_tag(tnf, _tnf_get_tag(tnf, array));
	hdrsize		= _tnf_get_header_size(tnf, base_tag);
	return (((size - hdrsize) / eltsize));
#else
	size 		= _tnf_get_self_size(tnf, array);
	hdrsize		= sizeof (struct tnf_array_hdr);
	return (((size - hdrsize) / eltsize));
#endif
}

/*
 * Retrieve the base pointer of an ABI array record
 */

caddr_t
/* ARGSUSED */
_tnf_get_elements(TNF *tnf, tnf_ref32_t *array)
{
#ifdef INFINITE_RECURSION_ARRAY
	size_t		hdrsize;
	tnf_ref32_t	*base_tag;

	base_tag	= _tnf_get_base_tag(tnf, _tnf_get_tag(tnf, array));
	hdrsize		= _tnf_get_header_size(tnf, base_tag);
	return ((caddr_t)((char *)array + hdrsize));
#else
	return ((caddr_t)((char *)array + sizeof (struct tnf_array_hdr)));
#endif
}

/*
 * Retrieve the chars in an ABI string record
 */

char *
_tnf_get_chars(TNF *tnf, tnf_ref32_t *string)
{
	return ((char *)_tnf_get_elements(tnf, string));
}

/*
 * Retrieve the string in the name slot of a type record
 */

char *
_tnf_get_name(TNF *tnf, tnf_ref32_t *tag)
{
	return (_tnf_get_chars(tnf, _GET_NAME(tnf, tag)));
}

/*
 * Retrieve the properties array slot of a type record
 */

tnf_ref32_t *
_tnf_get_properties(TNF *tnf, tnf_ref32_t *tag)
{
	return (_GET_PROPERTIES(tnf, tag));
}

/*
 * Retrieve the slot_types slot of struct_type or array_type record
 */

tnf_ref32_t *
_tnf_get_slot_types(TNF *tnf, tnf_ref32_t *tag)
{
	return (_GET_SLOT_TYPES(tnf, tag));
}

/*
 * Retrieve the header_size slot of an array_type record
 */

size_t
_tnf_get_header_size(TNF *tnf, tnf_ref32_t *tag)
{
	return (_GET_HEADER_SIZE(tnf, tag));
}

/*
 * Retrieve the derived_base slot of a derived_type record
 */

tnf_ref32_t *
_tnf_get_derived_base(TNF *tnf, tnf_ref32_t *tag)
{
	return (_GET_DERIVED_BASE(tnf, tag));
}


/*
 * Find the root (self-tagged) type record
 */

tnf_ref32_t *
_tnf_get_root_tag(TNF *tnf, tnf_ref32_t *record)
{
	if (tnf->root_tag)
		return (tnf->root_tag);
	else {
		tnf_ref32_t	*p1, *p2;
		p1 = record;
		while ((p2 = _tnf_get_tag(tnf, p1)) != p1)
			p1 = p2;
		tnf->root_tag = p2;
		return (p2);
	}
}

/*
 * Search ABI type array for a type named name
 */

tnf_ref32_t *
_tnf_get_element_named(TNF *tnf, tnf_ref32_t *array, char *name)
{
	unsigned	count, i;
	tnf_ref32_t	*elts;

	count 	= _tnf_get_element_count(tnf, array, sizeof (tnf_ref32_t));
	/* LINTED pointer cast may result in improper alignment */
	elts	= (tnf_ref32_t *)_tnf_get_elements(tnf, array);

	for (i = 0; i < count; i++) {
		tnf_ref32_t	*type_elt;

		if ((type_elt = _GET_REF32(tnf, &elts[i])) == TNF_NULL) {
			/* Can't have missing type records */
			_tnf_error(tnf, TNF_ERR_BADTNF);
			return (TNF_NULL);
		}

		if (strcmp(name, _tnf_get_name(tnf, type_elt)) == 0)
			/* Found a type record named name */
			return (type_elt);
	}
	return (TNF_NULL);
}

/*
 * Look in type record's properties for named type.
 * Recursively look at derived_base properties as well.
 */

tnf_ref32_t *
_tnf_get_property(TNF *tnf, tnf_ref32_t *tag, char *name)
{
	tnf_ref32_t	*properties, *property;

	if (strcmp(name, _tnf_get_name(tnf, tag)) == 0)
		/* name is type name */
		return (tag);

	if ((properties = _tnf_get_properties(tnf, tag)) == TNF_NULL)
		/* no properties */
		return (TNF_NULL);

	if ((property = _tnf_get_element_named(tnf, properties, name))
	    != TNF_NULL)
		/* found property named name */
		return (property);

	/*
	 * Recursively check base type of derived types
	 */
	if (_tnf_get_element_named(tnf, properties, TNF_N_DERIVED)
	    != TNF_NULL) {
		/* tag is a derived type: check its derived_base */
		tnf_ref32_t	*base_tag;

		base_tag = _tnf_get_derived_base(tnf, tag);
		/* tnf_derived has derived_base == TNF_NULL */
		if (base_tag != TNF_NULL)
			return (_tnf_get_property(tnf, base_tag, name));
	}

	return (TNF_NULL);
}

/*
 * Get the ultimate base type of a type record
 */

tnf_ref32_t *
_tnf_get_base_tag(TNF *tnf, tnf_ref32_t *tag)
{
	tnf_ref32_t	*properties;

	if ((properties = _tnf_get_properties(tnf, tag)) == TNF_NULL)
		/* no properties */
		return (tag);

	if (_tnf_get_element_named(tnf, properties, TNF_N_DERIVED)
	    != TNF_NULL) {
		tnf_ref32_t	*base_tag;

		if ((base_tag = _tnf_get_derived_base(tnf, tag)) != TNF_NULL)
			return (_tnf_get_base_tag(tnf, base_tag));
	}

	return (tag);
}

/*
 * Calculate the reference size of an object with type==tag
 */

size_t
_tnf_get_ref_size(TNF *tnf, tnf_ref32_t *tag)
{
	if (HAS_PROPERTY(tnf, tag, TNF_N_TAGGED)) {
		/* Tagged objects occupy 4 bytes for reference */
		return ((sizeof (tnf_ref32_t)));
	} else if (HAS_PROPERTY(tnf, tag, TNF_N_INLINE)) {
		/* Inline slots cannot be self sized */
		return (_tnf_get_storage_size(tnf, tag));
	} else {
		/* Illegal to have references to abstract objects */
		_tnf_error(tnf, TNF_ERR_BADTNF);
		return ((0));
	}
}

/*
 * Calculate storage size of an object with type==tag
 */

size_t
_tnf_get_storage_size(TNF *tnf, tnf_ref32_t *tag)
{
	if (_tnf_get_tag(tnf, tag) == _tnf_get_root_tag(tnf, tag))
		return (_GET_TYPE_SIZE(tnf, tag));
	else {
		tnf_ref32_t	*base_tag; /* implementation tag */
		caddr_t		sizep;
		tnf_ref32_t	*slot_types;

#ifndef INFINITE_RECURSION_SIZE
		char		*base_name;
		static struct n2s {
			char	*name;
			size_t	size;
		} n2s[] = {
		{ TNF_N_CHAR, 		sizeof (tnf_char_t) },
		{ TNF_N_INT8,		sizeof (tnf_int8_t) },
		{ TNF_N_INT16,		sizeof (tnf_int16_t) },
		{ TNF_N_INT32,		sizeof (tnf_int32_t) },
		{ TNF_N_UINT8,		sizeof (tnf_uint8_t) },
		{ TNF_N_UINT16,		sizeof (tnf_uint16_t) },
		{ TNF_N_UINT32,		sizeof (tnf_uint32_t) },
		{ TNF_N_INT64,		sizeof (tnf_int64_t) },
		{ TNF_N_UINT64,		sizeof (tnf_uint64_t) },
		{ TNF_N_FLOAT32,	sizeof (tnf_float32_t) },
		{ TNF_N_FLOAT64,	sizeof (tnf_float64_t) },
		{ NULL,			0 }
		};
		struct n2s	*p;
#endif

		base_tag 	= _tnf_get_base_tag(tnf, tag);

#ifndef INFINITE_RECURSION_SIZE
		base_name 	= _tnf_get_name(tnf, base_tag);

		/* XXX Why are we in this mess? */
		p = n2s;
		while (p->name) {
			if (strcmp(p->name, base_name) == 0)
				return (p->size);
			p++;
		}
#endif

		sizep = _tnf_get_slot_typed(tnf, base_tag, TNF_N_TYPE_SIZE);
		if (sizep)
			/* Type sized */
		/* LINTED pointer cast may result in improper alignment */
			return (_GET_UINT32(tnf, (tnf_uint32_t *)sizep));

		slot_types = (tnf_ref32_t *)
		/* LINTED pointer cast may result in improper alignment */
		    _tnf_get_slot_typed(tnf, base_tag, TNF_N_SLOT_TYPES);
		if (slot_types &&
		    _tnf_get_element_named(tnf, slot_types, TNF_N_SELF_SIZE))
			/* Self sized */
			return ((size_t)-1);
		else
			/* Abstract */
			return (0);
	}
}

/*
 * Return the alignment restriction for any tag
 */

unsigned
_tnf_get_align(TNF *tnf, tnf_ref32_t *tag)
{
	if (HAS_PROPERTY(tnf, tag, TNF_N_SCALAR)) {
		tnf_ref32_t	*base_tag;
		caddr_t		alignp;

		base_tag = _tnf_get_base_tag(tnf, tag);
		alignp   = _tnf_get_slot_typed(tnf, base_tag, TNF_N_ALIGN);
		if (alignp)
		/* LINTED pointer cast may result in improper alignment */
			return (_GET_UINT32(tnf, (tnf_uint32_t *)alignp));
	}
	/* default: word alignment */
	return ((4));
}

/*
 * Only works for records
 * Doesn't check for slot_names in tag
 * Tag records, for example, never have named slots
 */

caddr_t
_tnf_get_slot_typed(TNF *tnf, tnf_ref32_t *record, char *name)
{
	tnf_ref32_t 	*tag, *base_tag;
	tnf_ref32_t	*slot_types, *types;
	unsigned	count, i;
	unsigned 	offset;

	tag 		= _tnf_get_tag(tnf, record);
	base_tag 	= _tnf_get_base_tag(tnf, tag);

	/*
	 * The position of slot_types is ABI fixed
	 * XXX Assume it is present in tag
	 */
	slot_types = _tnf_get_slot_types(tnf, base_tag);
	count = _tnf_get_element_count(tnf, slot_types, sizeof (tnf_ref32_t));
	/* LINTED pointer cast may result in improper alignment */
	types = (tnf_ref32_t *)_tnf_get_elements(tnf, slot_types);

	offset 	= 0;

	for (i = 0; i < count; i++) {
		tnf_ref32_t	*type_elt;
		size_t		ref_size, align;

		/* Find the type record for slot */
		if ((type_elt = _GET_REF32(tnf, &types[i])) == TNF_NULL) {
			/* Can't have missing type records */
			_tnf_error(tnf, TNF_ERR_BADTNF);
			return ((caddr_t)NULL);
		}

		/* See similar hack in init_slots() */

		/* Calculate reference size */
		ref_size = _tnf_get_ref_size(tnf, type_elt);

		/*
		 * Calculate alignment
		 * XXX Prevent infinite recursion by assuming that
		 * a reference size of 4 implies word alignment
		 */
		align = (ref_size == 4)? 4: _tnf_get_align(tnf, type_elt);

		/* Adjust offset to account for alignment, if needed */
		offset = ALIGN(offset, align);

		/* Check whether name corresponds to type name */
		if (strcmp(name, _tnf_get_name(tnf, type_elt)) == 0)
			/* Found the slot */
			return (fetch_slot(tnf, (caddr_t)record + offset,
					type_elt));

		/* Bump offset by reference size */
		offset += ref_size;
	}

	return ((caddr_t)NULL);
}

/*
 * Only works for records
 */

caddr_t
_tnf_get_slot_named(TNF *tnf, tnf_ref32_t *record, char *name)
{
	tnf_ref32_t 	*tag, *base_tag;
	tnf_ref32_t	*slot_types, *slot_names, *types, *names;
	unsigned	count, i;
	unsigned 	offset;

	tag 		= _tnf_get_tag(tnf, record);
	base_tag 	= _tnf_get_base_tag(tnf, tag);

	/*
	 * slot_names are optional
	 */
	slot_names = (tnf_ref32_t *)
		/* LINTED pointer cast may result in improper alignment */
	    _tnf_get_slot_typed(tnf, base_tag, TNF_N_SLOT_NAMES);

	/* no slot_names; use _tnf_get_slot_typed() */
	if (slot_names == TNF_NULL)
		return (_tnf_get_slot_typed(tnf, record, name));

	/*
	 * The position of slot_types is ABI fixed
	 * XXX Assume it is present in tag
	 */
	slot_types = _tnf_get_slot_types(tnf, base_tag);
	count = _tnf_get_element_count(tnf, slot_types, sizeof (tnf_ref32_t));
	/* LINTED pointer cast may result in improper alignment */
	types = (tnf_ref32_t *)_tnf_get_elements(tnf, slot_types);
	/* LINTED pointer cast may result in improper alignment */
	names = (tnf_ref32_t *)_tnf_get_elements(tnf, slot_names);

	offset 	= 0;

	for (i = 0; i < count; i++) {
		tnf_ref32_t	*type_elt, *name_elt;
		size_t		ref_size, align;

		/* Find the type record for slot */
		if ((type_elt = _GET_REF32(tnf, &types[i])) == TNF_NULL) {
			/* Can't have missing type records */
			_tnf_error(tnf, TNF_ERR_BADTNF);
			return ((caddr_t)NULL);
		}

		/* XXX Keep consistent with init_slots() */

		/* Calculate reference size */
		ref_size = _tnf_get_ref_size(tnf, type_elt);

		/*
		 * Calculate alignment
		 * XXX Prevent infinite recursion by assuming that
		 * a reference size of 4 implies word alignment
		 */
		align = (ref_size == 4)? 4: _tnf_get_align(tnf, type_elt);

		/* Adjust offset to account for alignment, if needed */
		offset = ALIGN(offset, align);

		/* First check slot name, then type name */
		if ((((name_elt = _GET_REF32(tnf, &names[i])) != TNF_NULL) &&
			(strcmp(name, _tnf_get_chars(tnf, name_elt)) == 0)) ||
			(strcmp(name, _tnf_get_name(tnf, type_elt)) == 0))
			/* Found slot */
			return (fetch_slot(tnf, (caddr_t)record + offset,
				    type_elt));

		/* Bump offset by reference size */
		offset += ref_size;
	}

	return ((caddr_t)NULL);
}

static caddr_t
fetch_slot(TNF *tnf, caddr_t p, tnf_ref32_t *tag)
{
	if (HAS_PROPERTY(tnf, tag, TNF_N_INLINE))
		return (p);
	else			/* XXX assume tagged */
		/* LINTED pointer cast may result in improper alignment */
		return ((caddr_t)_GET_REF32(tnf, (tnf_ref32_t *)p));
}