/*
* 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));
}