text: /*
   * 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 1994, 2003 Sun Microsystems, Inc.  All rights reserved.
   * Use is subject to license terms.
   */
  
  #pragma ident	"%Z%%M%	%I%	%E% SMI"
  
  #include <sys/types.h>
  #include <sys/param.h>
  #include <sys/systm.h>
  #include <sys/ddi.h>		/* strchr */
  #include <sys/sunddi.h>		/* strchr */
  #include <sys/tnf_com.h>
  #include <sys/tnf_writer.h>
  #include <sys/tnf_probe.h>
  #include <sys/debug.h>
  
  #include "tnf_buf.h"
  #include "tnf_types.h"
  #include "tnf_trace.h"
  
  /*
   * New derived types for probes
   */
  
  TNF_STD_DERIVED_TAG(tnf_probe_event, tnf_tag,
  		tnf_derived_properties, TNF_OPAQUE);
  
  TNF_STD_DERIVED_TAG(tnf_time_base, tnf_int64,
  		tnf_derived_properties, TNF_INT64);
  
  TNF_STD_DERIVED_TAG(tnf_time_delta, tnf_uint32,
  		tnf_derived_properties, TNF_UINT32);
  
  TNF_STD_DERIVED_TAG(tnf_pid, tnf_int32,
  		tnf_derived_properties, TNF_INT32);
  
  TNF_STD_DERIVED_TAG(tnf_lwpid, tnf_uint32,
  		tnf_derived_properties, TNF_UINT32);
  
  TNF_STD_DERIVED_TAG(tnf_kthread_id, tnf_opaque,
  		tnf_derived_properties, TNF_OPAQUE);
  
  TNF_STD_DERIVED_TAG(tnf_cpuid, tnf_int32,
  		tnf_derived_properties, TNF_INT32);
  
  TNF_STD_DERIVED_TAG(tnf_device, tnf_ulong,
  		tnf_derived_properties, TNF_ULONG);
  
  TNF_STD_DERIVED_TAG(tnf_symbol, tnf_opaque,
  		tnf_derived_properties, TNF_OPAQUE);
  
  TNF_STD_ARRAY_TAG(tnf_symbols, tnf_symbol, TNF_ARRAY);
  
  TNF_STD_DERIVED_TAG(tnf_sysnum, tnf_int16,
  		tnf_derived_properties, TNF_INT32);
  
  TNF_STD_DERIVED_TAG(tnf_microstate, tnf_int32,
  		tnf_derived_properties, TNF_INT32);
  
  TNF_STD_DERIVED_TAG(tnf_offset, tnf_int64,
  		tnf_derived_properties, TNF_INT64);
  
  TNF_STD_DERIVED_TAG(tnf_fault_type, tnf_int32,
  		tnf_derived_properties, TNF_INT32);
  
  TNF_STD_DERIVED_TAG(tnf_seg_access, tnf_int32,
  		tnf_derived_properties, TNF_INT32);
  
  TNF_STD_DERIVED_TAG(tnf_bioflags, tnf_int32,
  		tnf_derived_properties, TNF_INT32);
  
  TNF_STD_DERIVED_TAG(tnf_diskaddr, tnf_int64,
  		tnf_derived_properties, TNF_INT64);
  
  static char	*kernel_schedule_slot_names[] = {
  	TNF_N_TAG,
  	TNF_N_TID,
  	TNF_N_LWPID,
  	TNF_N_PID,
  	TNF_N_TIME_BASE,
  	"cpuid",		/* XXX */
  	0};
  
  static tnf_tag_data_t	**kernel_schedule_slots[] = {
  	&TAG_DATA(tnf_tag),
  	&TAG_DATA(tnf_kthread_id),
  	&TAG_DATA(tnf_lwpid),
  	&TAG_DATA(tnf_pid),
  	&TAG_DATA(tnf_time_base),
  	&TAG_DATA(tnf_cpuid),
  	0};
  
  TNF_STD_STRUCT_TAG(tnf_kernel_schedule,
  		kernel_schedule_slots,
  		kernel_schedule_slot_names,
  		sizeof (tnf_schedule_prototype_t));
  
  /*
   * Probe type record (metatag)
   */
  
  static tnf_tag_data_t	**probe_type_slots[] = {
  	&TAG_DATA(tnf_tag),
  	&TAG_DATA(tnf_name),
  	&TAG_DATA(tnf_properties),
  	&TAG_DATA(tnf_slot_types),
  	&TAG_DATA(tnf_type_size),
  	&TAG_DATA(tnf_slot_names),
  	&TAG_DATA(tnf_string),  	/* detail */
  	0};
  
  TNF_METATAG(tnf_probe_type, tnf_type_properties,
      probe_type_slots, tnf_struct_tag_1);
  
  /*
   * Write a kernel schedule record
   * Can only be written in reusable data space.
   */
  
  tnf_record_p
  tnf_kernel_schedule(tnf_ops_t *ops, tnf_schedule_t *sched)
  {
  	tnf_tag_data_t *metatag_data;
  	tnf_record_p metatag_index;
  	tnf_schedule_prototype_t *buffer;
  	kthread_t *t;
  
  	t = curthread;
  
  	/* Cannot be called when writing into tag space */
  	ASSERT(ops->mode == TNF_ALLOC_REUSABLE);
  
  	ALLOC(ops, sizeof (*buffer), buffer, sched->record_p,
  	    TNF_ALLOC_REUSABLE); /* XXX see comment above */
  
  	metatag_data = TAG_DATA(tnf_kernel_schedule);
  	metatag_index = metatag_data->tag_index ?
  		metatag_data->tag_index :
  		metatag_data->tag_desc(ops, metatag_data);
  
  	ASSIGN(buffer,	tag, 		metatag_index);
  	ASSIGN2(buffer, tid, 		t,		kthread_id);
  	ASSIGN(buffer,	lwpid, 		t->t_tid);
  	ASSIGN(buffer,	pid, 		ttoproc(t)->p_pid);
  	ASSIGN(buffer,	time_base, 	sched->time_base);
  	ASSIGN(buffer,	cpuid, 		sched->cpuid);
  
  	/*
  	 * Remember schedule record generation number so the distance
  	 * in virtual space can be calculated from an event record
  	 */
  	sched->record_gen = ((tnf_block_header_t *)
  	    ((uintptr_t)buffer & TNF_BLOCK_MASK))->generation;
  	/* Cannot have been written into tag space */
  	ASSERT(sched->record_gen != TNF_TAG_GENERATION_NUM);
  
  	return ((tnf_record_p)buffer);
  }
  
  /*
   * Array of addresses and derivatives
   */
  
  tnf_reference_t
  tnf_opaque_array_1(tnf_ops_t *ops, tnf_opaque_t *opaques,
  	tnf_record_p reference, tnf_tag_data_t *tag_data)
  {
  	tnf_record_p 	tag_index;
  	size_t		record_size;
  	tnf_opaque_t	*tmp;
  	tnf_opaque_t	*ref_p;
  	tnf_array_header_t 	*bufhdr;
  
  	tag_index = tag_data->tag_index ? tag_data->tag_index :
  		tag_data->tag_desc(ops, tag_data);
  
  	if (!opaques)
  		return (TNF_NULL);
  
  	record_size = sizeof (*bufhdr);
  	tmp = opaques;
  	while (*tmp++)
  		record_size += sizeof (*ref_p);
  
  	ALLOC2(ops, record_size, bufhdr, ops->mode);
  
  	ASSIGN(bufhdr, tag, 		tag_index);
  	/* LINTED assignment of 64-bit integer to 32-bit integer */
  	ASSIGN(bufhdr, self_size, 	record_size);
  
  	tmp = opaques;
  	/* LINTED pointer cast may result in improper alignment */
  	ref_p = (tnf_opaque_t *)((char *)bufhdr + sizeof (*bufhdr));
  	while (*tmp) {
  		*ref_p = tnf_opaque(ops, *tmp, (tnf_reference_t *)ref_p);
  		tmp++;
  		ref_p++;
  	}
  
  	return (tnf_ref32(ops, (tnf_record_p) bufhdr, reference));
  }
  
  #ifdef __sparc
  
  tnf_reference_t
  tnf_opaque32_array_1(tnf_ops_t *ops, tnf_uint32_t *opaques,
  	tnf_record_p reference, tnf_tag_data_t *tag_data)
  {
  	tnf_record_p 	tag_index;
  	size_t		record_size;
  	tnf_uint32_t	*tmp;
  	tnf_uint32_t	*ref_p;
  	tnf_array_header_t 	*bufhdr;
  
  	tag_index = tag_data->tag_index ? tag_data->tag_index :
  		tag_data->tag_desc(ops, tag_data);
  
  	if (!opaques)
  		return (TNF_NULL);
  
  	record_size = sizeof (*bufhdr);
  	tmp = opaques;
  	while (*tmp++)
  		record_size += sizeof (*ref_p);
  
  	ALLOC2(ops, record_size, bufhdr, ops->mode);
  
  	ASSIGN(bufhdr, tag, 		tag_index);
  	/* LINTED assignment of 64-bit integer to 32-bit integer */
  	ASSIGN(bufhdr, self_size, 	record_size);
  
  	tmp = opaques;
  	/* LINTED pointer cast may result in improper alignment */
  	ref_p = (tnf_uint32_t *)((char *)bufhdr + sizeof (*bufhdr));
  	while (*tmp) {
  		*ref_p = tnf_uint32(ops, *tmp, (tnf_reference_t *)ref_p);
  		tmp++;
  		ref_p++;
  	}
  
  	return (tnf_ref32(ops, (tnf_record_p) bufhdr, reference));
  }
  
  #endif /* __sparc */
  
  /*
   * Tag initializer
   */
  
  void
  tnf_tag_trace_init(void)
  {
  
  	TAG_SNAP(tnf_probe_event);
  	TAG_SNAP(tnf_time_base);
  	TAG_SNAP(tnf_time_delta);
  	TAG_SNAP(tnf_pid);
  	TAG_SNAP(tnf_lwpid);
  
  	TAG_SNAP(tnf_kthread_id);
  	TAG_SNAP(tnf_cpuid);
  	TAG_SNAP(tnf_device);
  	TAG_SNAP(tnf_symbol);
  	TAG_SNAP(tnf_symbols);
  	TAG_SNAP(tnf_sysnum);
  	TAG_SNAP(tnf_microstate);
  	TAG_SNAP(tnf_offset);
  	TAG_SNAP(tnf_fault_type);
  	TAG_SNAP(tnf_seg_access);
  	TAG_SNAP(tnf_bioflags);
  	TAG_SNAP(tnf_diskaddr);
  	TAG_SNAP(tnf_kernel_schedule);
  
  	TAG_SNAP(tnf_probe_type);
  
  }
  