svn commit: r278587 - head/sys/cddl/dev/fbt/arm

George V. Neville-Neil gnn at FreeBSD.org
Wed Feb 11 17:27:38 UTC 2015


Author: gnn
Date: Wed Feb 11 17:27:37 2015
New Revision: 278587
URL: https://svnweb.freebsd.org/changeset/base/278587

Log:
  Clean up machine dependent code for DTrace on ARM.
  
  Submitted by:	markj

Modified:
  head/sys/cddl/dev/fbt/arm/fbt_isa.c

Modified: head/sys/cddl/dev/fbt/arm/fbt_isa.c
==============================================================================
--- head/sys/cddl/dev/fbt/arm/fbt_isa.c	Wed Feb 11 17:25:23 2015	(r278586)
+++ head/sys/cddl/dev/fbt/arm/fbt_isa.c	Wed Feb 11 17:27:37 2015	(r278587)
@@ -33,114 +33,21 @@
 
 #include <sys/cdefs.h>
 #include <sys/param.h>
-#include <sys/systm.h>
-#include <sys/conf.h>
-#include <sys/cpuvar.h>
-#include <sys/fcntl.h>
-#include <sys/filio.h>
-#include <sys/kdb.h>
-#include <sys/kernel.h>
-#include <sys/kmem.h>
-#include <sys/kthread.h>
-#include <sys/limits.h>
-#include <sys/linker.h>
-#include <sys/lock.h>
-#include <sys/malloc.h>
-#include <sys/module.h>
-#include <sys/mutex.h>
-#include <sys/pcpu.h>
-#include <sys/poll.h>
-#include <sys/proc.h>
-#include <sys/selinfo.h>
-#include <sys/smp.h>
-#include <sys/syscall.h>
-#include <sys/sysent.h>
-#include <sys/sysproto.h>
-#include <sys/uio.h>
-#include <sys/unistd.h>
-#include <machine/frame.h>
-#include <machine/md_var.h>
-#include <machine/stdarg.h>
 
 #include <sys/dtrace.h>
-#include <sys/dtrace_bsd.h>
 
-static MALLOC_DEFINE(M_FBT, "fbt", "Function Boundary Tracing");
+#include "fbt.h"
 
-#define FBT_PATCHVAL		0xe06a0cfe // illegal instruction
+#define	FBT_PATCHVAL		0xe06a0cfe /* illegal instruction */
 
-#define FBT_PUSHM		0xe92d0000
-#define FBT_POPM		0xe8bd0000
-#define FBT_JUMP		0xea000000
-
-static d_open_t	fbt_open;
-static int	fbt_unload(void);
-static void	fbt_getargdesc(void *, dtrace_id_t, void *, dtrace_argdesc_t *);
-static void	fbt_provide_module(void *, modctl_t *);
-static void	fbt_destroy(void *, dtrace_id_t, void *);
-static void	fbt_enable(void *, dtrace_id_t, void *);
-static void	fbt_disable(void *, dtrace_id_t, void *);
-static void	fbt_load(void *);
-static void	fbt_suspend(void *, dtrace_id_t, void *);
-static void	fbt_resume(void *, dtrace_id_t, void *);
+#define	FBT_PUSHM		0xe92d0000
+#define	FBT_POPM		0xe8bd0000
+#define	FBT_JUMP		0xea000000
 
 #define	FBT_ENTRY	"entry"
 #define	FBT_RETURN	"return"
-#define	FBT_ADDR2NDX(addr)	((((uintptr_t)(addr)) >> 4) & fbt_probetab_mask)
-#define	FBT_PROBETAB_SIZE	0x8000		/* 32k entries -- 128K total */
 
-static struct cdevsw fbt_cdevsw = {
-	.d_version	= D_VERSION,
-	.d_open		= fbt_open,
-	.d_name		= "fbt",
-};
-
-static dtrace_pattr_t fbt_attr = {
-{ DTRACE_STABILITY_EVOLVING, DTRACE_STABILITY_EVOLVING, DTRACE_CLASS_COMMON },
-{ DTRACE_STABILITY_PRIVATE, DTRACE_STABILITY_PRIVATE, DTRACE_CLASS_UNKNOWN },
-{ DTRACE_STABILITY_PRIVATE, DTRACE_STABILITY_PRIVATE, DTRACE_CLASS_ISA },
-{ DTRACE_STABILITY_EVOLVING, DTRACE_STABILITY_EVOLVING, DTRACE_CLASS_COMMON },
-{ DTRACE_STABILITY_PRIVATE, DTRACE_STABILITY_PRIVATE, DTRACE_CLASS_ISA },
-};
-
-static dtrace_pops_t fbt_pops = {
-	NULL,
-	fbt_provide_module,
-	fbt_enable,
-	fbt_disable,
-	fbt_suspend,
-	fbt_resume,
-	fbt_getargdesc,
-	NULL,
-	NULL,
-	fbt_destroy
-};
-
-typedef struct fbt_probe {
-	struct fbt_probe *fbtp_hashnext;
-	uint32_t	*fbtp_patchpoint;
-	int8_t		fbtp_rval;
-	uint32_t	fbtp_patchval;
-	uint32_t	fbtp_savedval;
-	uintptr_t	fbtp_roffset;
-	dtrace_id_t	fbtp_id;
-	const char	*fbtp_name;
-	modctl_t	*fbtp_ctl;
-	int		fbtp_loadcnt;
-	int		fbtp_primary;
-	int		fbtp_invop_cnt;
-	int		fbtp_symindx;
-	struct fbt_probe *fbtp_next;
-} fbt_probe_t;
-
-static struct cdev		*fbt_cdev;
-static dtrace_provider_id_t	fbt_id;
-static fbt_probe_t		**fbt_probetab;
-static int			fbt_probetab_size;
-static int			fbt_probetab_mask;
-static int			fbt_verbose = 0;
-
-static int
+int
 fbt_invop(uintptr_t addr, uintptr_t *stack, uintptr_t rval)
 {
 	struct trapframe *frame = (struct trapframe *)stack;
@@ -152,9 +59,10 @@ fbt_invop(uintptr_t addr, uintptr_t *sta
 			fbt->fbtp_invop_cnt++;
 			cpu->cpu_dtrace_caller = addr;
 
+			/* TODO: Need 5th parameter from stack */
 			dtrace_probe(fbt->fbtp_id, frame->tf_r0,
 			    frame->tf_r1, frame->tf_r2,
-			    frame->tf_r3, 0); // TODO: Need 5th parameter from stack
+			    frame->tf_r3, 0);
 
 			cpu->cpu_dtrace_caller = 0;
 
@@ -165,15 +73,23 @@ fbt_invop(uintptr_t addr, uintptr_t *sta
 	return (0);
 }
 
-static int
+void
+fbt_patch_tracepoint(fbt_probe_t *fbt, fbt_patchval_t val)
+{
+
+	*fbt->fbtp_patchpoint = val;
+	cpu_icache_sync_range((vm_offset_t)fbt->fbtp_patchpoint, 4);
+}
+
+int
 fbt_provide_module_function(linker_file_t lf, int symindx,
     linker_symval_t *symval, void *opaque)
 {
 	char *modname = opaque;
 	const char *name = symval->name;
 	fbt_probe_t *fbt, *retfbt;
+	uint32_t *instr, *limit;
 	int popm;
-	u_int32_t *instr, *limit;
 
 	if (strncmp(name, "dtrace_", 7) == 0 &&
 	    strncmp(name, "dtrace_safe_", 12) != 0) {
@@ -189,11 +105,12 @@ fbt_provide_module_function(linker_file_
 	if (name[0] == '_' && name[1] == '_')
 		return (0);
 
-	instr = (u_int32_t *) symval->value;
-	limit = (u_int32_t *)(symval->value + symval->size);
+	instr = (uint32_t *)symval->value;
+	limit = (uint32_t *)(symval->value + symval->size);
 
 	for (; instr < limit; instr++)
-		if ((*instr & 0xffff0000) == FBT_PUSHM && (*instr & 0x4000) != 0)
+		if ((*instr & 0xffff0000) == FBT_PUSHM &&
+		    (*instr & 0x4000) != 0)
 			break;
 
 	if (instr >= limit)
@@ -218,25 +135,23 @@ fbt_provide_module_function(linker_file_
 
 	popm = FBT_POPM | ((*instr) & 0x3FFF) | 0x8000;
 
-
 	retfbt = NULL;
-again:	
-	for(; instr < limit; instr++)
-	{
-		if  (*instr == popm)
+again:
+	for (; instr < limit; instr++) {
+		if (*instr == popm)
 			break;
-		else if ((*instr & 0xff000000) == FBT_JUMP)
-		{
+		else if ((*instr & 0xff000000) == FBT_JUMP) {
+			uint32_t *target, *start;
 			int offset;
-			u_int32_t *target, *start;
+
 			offset = (*instr & 0xffffff);
 			offset <<= 8;
 			offset /= 64;
 			target = instr + (2 + offset);
-			start = (u_int32_t *) symval->value;
+			start = (uint32_t *)symval->value;
 			if (target >= limit || target < start)
 				break;
-			instr++; //skip delay slot
+			instr++; /* skip delay slot */
 		}
 	}
 
@@ -263,7 +178,7 @@ again:	
 	fbt->fbtp_symindx = symindx;
 	if ((*instr & 0xff000000) == FBT_JUMP)
 		fbt->fbtp_rval = DTRACE_INVOP_B;
-	else	
+	else
 		fbt->fbtp_rval = DTRACE_INVOP_POPM;
 	fbt->fbtp_savedval = *instr;
 	fbt->fbtp_patchval = FBT_PATCHVAL;
@@ -275,1029 +190,3 @@ again:	
 	instr++;
 	goto again;
 }
-
-static void
-fbt_provide_module(void *arg, modctl_t *lf)
-{
-	char modname[MAXPATHLEN];
-	int i;
-	size_t len;
-
-	strlcpy(modname, lf->filename, sizeof(modname));
-	len = strlen(modname);
-	if (len > 3 && strcmp(modname + len - 3, ".ko") == 0)
-		modname[len - 3] = '\0';
-
-	/*
-	 * Employees of dtrace and their families are ineligible.  Void
-	 * where prohibited.
-	 */
-	if (strcmp(modname, "dtrace") == 0)
-		return;
-
-	/*
-	 * The cyclic timer subsystem can be built as a module and DTrace
-	 * depends on that, so it is ineligible too.
-	 */
-	if (strcmp(modname, "cyclic") == 0)
-		return;
-
-	/*
-	 * To register with DTrace, a module must list 'dtrace' as a
-	 * dependency in order for the kernel linker to resolve
-	 * symbols like dtrace_register(). All modules with such a
-	 * dependency are ineligible for FBT tracing.
-	 */
-	for (i = 0; i < lf->ndeps; i++)
-		if (strncmp(lf->deps[i]->filename, "dtrace", 6) == 0)
-			return;
-
-	if (lf->fbt_nentries) {
-		/*
-		 * This module has some FBT entries allocated; we're afraid
-		 * to screw with it.
-		 */
-		return;
-	}
-
-	/*
-	 * List the functions in the module and the symbol values.
-	 */
-	(void) linker_file_function_listall(lf, fbt_provide_module_function, modname);
-}
-
-static void
-fbt_destroy(void *arg, dtrace_id_t id, void *parg)
-{
-	fbt_probe_t *fbt = parg, *next, *hash, *last;
-	modctl_t *ctl;
-	int ndx;
-
-	do {
-		ctl = fbt->fbtp_ctl;
-
-		ctl->fbt_nentries--;
-
-		/*
-		 * Now we need to remove this probe from the fbt_probetab.
-		 */
-		ndx = FBT_ADDR2NDX(fbt->fbtp_patchpoint);
-		last = NULL;
-		hash = fbt_probetab[ndx];
-
-		while (hash != fbt) {
-			ASSERT(hash != NULL);
-			last = hash;
-			hash = hash->fbtp_hashnext;
-		}
-
-		if (last != NULL) {
-			last->fbtp_hashnext = fbt->fbtp_hashnext;
-		} else {
-			fbt_probetab[ndx] = fbt->fbtp_hashnext;
-		}
-
-		next = fbt->fbtp_next;
-		free(fbt, M_FBT);
-
-		fbt = next;
-	} while (fbt != NULL);
-}
-
-static void
-fbt_enable(void *arg, dtrace_id_t id, void *parg)
-{
-	fbt_probe_t *fbt = parg;
-	modctl_t *ctl = fbt->fbtp_ctl;
-
-	ctl->nenabled++;
-
-	/*
-	 * Now check that our modctl has the expected load count.  If it
-	 * doesn't, this module must have been unloaded and reloaded -- and
-	 * we're not going to touch it.
-	 */
-	if (ctl->loadcnt != fbt->fbtp_loadcnt) {
-		if (fbt_verbose) {
-			printf("fbt is failing for probe %s "
-			    "(module %s reloaded)",
-			    fbt->fbtp_name, ctl->filename);
-		}
-
-		return;
-	}
-
-	for (; fbt != NULL; fbt = fbt->fbtp_next) {
-		*fbt->fbtp_patchpoint = fbt->fbtp_patchval;
-		cpu_icache_sync_range((vm_offset_t)fbt->fbtp_patchpoint, 4);
-	}
-}
-
-static void
-fbt_disable(void *arg, dtrace_id_t id, void *parg)
-{
-	fbt_probe_t *fbt = parg;
-	modctl_t *ctl = fbt->fbtp_ctl;
-
-	ASSERT(ctl->nenabled > 0);
-	ctl->nenabled--;
-
-	if ((ctl->loadcnt != fbt->fbtp_loadcnt))
-		return;
-
-	for (; fbt != NULL; fbt = fbt->fbtp_next) {
-		*fbt->fbtp_patchpoint = fbt->fbtp_savedval;
-		cpu_icache_sync_range((vm_offset_t)fbt->fbtp_patchpoint, 4);
-	}
-}
-
-static void
-fbt_suspend(void *arg, dtrace_id_t id, void *parg)
-{
-	fbt_probe_t *fbt = parg;
-	modctl_t *ctl = fbt->fbtp_ctl;
-
-	ASSERT(ctl->nenabled > 0);
-
-	if ((ctl->loadcnt != fbt->fbtp_loadcnt))
-		return;
-
-	for (; fbt != NULL; fbt = fbt->fbtp_next) {
-		*fbt->fbtp_patchpoint = fbt->fbtp_savedval;
-		cpu_icache_sync_range((vm_offset_t)fbt->fbtp_patchpoint, 4);
-	}
-}
-
-static void
-fbt_resume(void *arg, dtrace_id_t id, void *parg)
-{
-	fbt_probe_t *fbt = parg;
-	modctl_t *ctl = fbt->fbtp_ctl;
-
-	ASSERT(ctl->nenabled > 0);
-
-	if ((ctl->loadcnt != fbt->fbtp_loadcnt))
-		return;
-
-	for (; fbt != NULL; fbt = fbt->fbtp_next) {
-		*fbt->fbtp_patchpoint = fbt->fbtp_patchval;
-		cpu_icache_sync_range((vm_offset_t)fbt->fbtp_patchpoint, 4);
-	}
-}
-
-static int
-fbt_ctfoff_init(modctl_t *lf, linker_ctf_t *lc)
-{
-	const Elf_Sym *symp = lc->symtab;;
-	const ctf_header_t *hp = (const ctf_header_t *) lc->ctftab;
-	const uint8_t *ctfdata = lc->ctftab + sizeof(ctf_header_t);
-	int i;
-	uint32_t *ctfoff;
-	uint32_t objtoff = hp->cth_objtoff;
-	uint32_t funcoff = hp->cth_funcoff;
-	ushort_t info;
-	ushort_t vlen;
-
-	/* Sanity check. */
-	if (hp->cth_magic != CTF_MAGIC) {
-		printf("Bad magic value in CTF data of '%s'\n",lf->pathname);
-		return (EINVAL);
-	}
-
-	if (lc->symtab == NULL) {
-		printf("No symbol table in '%s'\n",lf->pathname);
-		return (EINVAL);
-	}
-
-	if ((ctfoff = malloc(sizeof(uint32_t) * lc->nsym, M_LINKER, M_WAITOK)) == NULL)
-		return (ENOMEM);
-
-	*lc->ctfoffp = ctfoff;
-
-	for (i = 0; i < lc->nsym; i++, ctfoff++, symp++) {
-		if (symp->st_name == 0 || symp->st_shndx == SHN_UNDEF) {
-			*ctfoff = 0xffffffff;
-			continue;
-		}
-
-		switch (ELF_ST_TYPE(symp->st_info)) {
-		case STT_OBJECT:
-			if (objtoff >= hp->cth_funcoff ||
-			    (symp->st_shndx == SHN_ABS && symp->st_value == 0)) {
-				*ctfoff = 0xffffffff;
-				break;
-			}
-
-			*ctfoff = objtoff;
-			objtoff += sizeof (ushort_t);
-			break;
-
-		case STT_FUNC:
-			if (funcoff >= hp->cth_typeoff) {
-				*ctfoff = 0xffffffff;
-				break;
-			}
-
-			*ctfoff = funcoff;
-
-			info = *((const ushort_t *)(ctfdata + funcoff));
-			vlen = CTF_INFO_VLEN(info);
-
-			/*
-			 * If we encounter a zero pad at the end, just skip it.
-			 * Otherwise skip over the function and its return type
-			 * (+2) and the argument list (vlen).
-			 */
-			if (CTF_INFO_KIND(info) == CTF_K_UNKNOWN && vlen == 0)
-				funcoff += sizeof (ushort_t); /* skip pad */
-			else
-				funcoff += sizeof (ushort_t) * (vlen + 2);
-			break;
-
-		default:
-			*ctfoff = 0xffffffff;
-			break;
-		}
-	}
-
-	return (0);
-}
-
-static ssize_t
-fbt_get_ctt_size(uint8_t version, const ctf_type_t *tp, ssize_t *sizep,
-    ssize_t *incrementp)
-{
-	ssize_t size, increment;
-
-	if (version > CTF_VERSION_1 &&
-	    tp->ctt_size == CTF_LSIZE_SENT) {
-		size = CTF_TYPE_LSIZE(tp);
-		increment = sizeof (ctf_type_t);
-	} else {
-		size = tp->ctt_size;
-		increment = sizeof (ctf_stype_t);
-	}
-
-	if (sizep)
-		*sizep = size;
-	if (incrementp)
-		*incrementp = increment;
-
-	return (size);
-}
-
-static int
-fbt_typoff_init(linker_ctf_t *lc)
-{
-	const ctf_header_t *hp = (const ctf_header_t *) lc->ctftab;
-	const ctf_type_t *tbuf;
-	const ctf_type_t *tend;
-	const ctf_type_t *tp;
-	const uint8_t *ctfdata = lc->ctftab + sizeof(ctf_header_t);
-	int ctf_typemax = 0;
-	uint32_t *xp;
-	ulong_t pop[CTF_K_MAX + 1] = { 0 };
-
-
-	/* Sanity check. */
-	if (hp->cth_magic != CTF_MAGIC)
-		return (EINVAL);
-
-	tbuf = (const ctf_type_t *) (ctfdata + hp->cth_typeoff);
-	tend = (const ctf_type_t *) (ctfdata + hp->cth_stroff);
-
-	int child = hp->cth_parname != 0;
-
-	/*
-	 * We make two passes through the entire type section.  In this first
-	 * pass, we count the number of each type and the total number of types.
-	 */
-	for (tp = tbuf; tp < tend; ctf_typemax++) {
-		ushort_t kind = CTF_INFO_KIND(tp->ctt_info);
-		ulong_t vlen = CTF_INFO_VLEN(tp->ctt_info);
-		ssize_t size, increment;
-
-		size_t vbytes;
-		uint_t n;
-
-		(void) fbt_get_ctt_size(hp->cth_version, tp, &size, &increment);
-
-		switch (kind) {
-		case CTF_K_INTEGER:
-		case CTF_K_FLOAT:
-			vbytes = sizeof (uint_t);
-			break;
-		case CTF_K_ARRAY:
-			vbytes = sizeof (ctf_array_t);
-			break;
-		case CTF_K_FUNCTION:
-			vbytes = sizeof (ushort_t) * (vlen + (vlen & 1));
-			break;
-		case CTF_K_STRUCT:
-		case CTF_K_UNION:
-			if (size < CTF_LSTRUCT_THRESH) {
-				ctf_member_t *mp = (ctf_member_t *)
-				    ((uintptr_t)tp + increment);
-
-				vbytes = sizeof (ctf_member_t) * vlen;
-				for (n = vlen; n != 0; n--, mp++)
-					child |= CTF_TYPE_ISCHILD(mp->ctm_type);
-			} else {
-				ctf_lmember_t *lmp = (ctf_lmember_t *)
-				    ((uintptr_t)tp + increment);
-
-				vbytes = sizeof (ctf_lmember_t) * vlen;
-				for (n = vlen; n != 0; n--, lmp++)
-					child |=
-					    CTF_TYPE_ISCHILD(lmp->ctlm_type);
-			}
-			break;
-		case CTF_K_ENUM:
-			vbytes = sizeof (ctf_enum_t) * vlen;
-			break;
-		case CTF_K_FORWARD:
-			/*
-			 * For forward declarations, ctt_type is the CTF_K_*
-			 * kind for the tag, so bump that population count too.
-			 * If ctt_type is unknown, treat the tag as a struct.
-			 */
-			if (tp->ctt_type == CTF_K_UNKNOWN ||
-			    tp->ctt_type >= CTF_K_MAX)
-				pop[CTF_K_STRUCT]++;
-			else
-				pop[tp->ctt_type]++;
-			/*FALLTHRU*/
-		case CTF_K_UNKNOWN:
-			vbytes = 0;
-			break;
-		case CTF_K_POINTER:
-		case CTF_K_TYPEDEF:
-		case CTF_K_VOLATILE:
-		case CTF_K_CONST:
-		case CTF_K_RESTRICT:
-			child |= CTF_TYPE_ISCHILD(tp->ctt_type);
-			vbytes = 0;
-			break;
-		default:
-			printf("%s(%d): detected invalid CTF kind -- %u\n", __func__, __LINE__, kind);
-			return (EIO);
-		}
-		tp = (ctf_type_t *)((uintptr_t)tp + increment + vbytes);
-		pop[kind]++;
-	}
-
-	/* account for a sentinel value below */
-	ctf_typemax++;
-	*lc->typlenp = ctf_typemax;
-
-	if ((xp = malloc(sizeof(uint32_t) * ctf_typemax, M_LINKER, M_ZERO | M_WAITOK)) == NULL)
-		return (ENOMEM);
-
-	*lc->typoffp = xp;
-
-	/* type id 0 is used as a sentinel value */
-	*xp++ = 0;
-
-	/*
-	 * In the second pass, fill in the type offset.
-	 */
-	for (tp = tbuf; tp < tend; xp++) {
-		ushort_t kind = CTF_INFO_KIND(tp->ctt_info);
-		ulong_t vlen = CTF_INFO_VLEN(tp->ctt_info);
-		ssize_t size, increment;
-
-		size_t vbytes;
-		uint_t n;
-
-		(void) fbt_get_ctt_size(hp->cth_version, tp, &size, &increment);
-
-		switch (kind) {
-		case CTF_K_INTEGER:
-		case CTF_K_FLOAT:
-			vbytes = sizeof (uint_t);
-			break;
-		case CTF_K_ARRAY:
-			vbytes = sizeof (ctf_array_t);
-			break;
-		case CTF_K_FUNCTION:
-			vbytes = sizeof (ushort_t) * (vlen + (vlen & 1));
-			break;
-		case CTF_K_STRUCT:
-		case CTF_K_UNION:
-			if (size < CTF_LSTRUCT_THRESH) {
-				ctf_member_t *mp = (ctf_member_t *)
-				    ((uintptr_t)tp + increment);
-
-				vbytes = sizeof (ctf_member_t) * vlen;
-				for (n = vlen; n != 0; n--, mp++)
-					child |= CTF_TYPE_ISCHILD(mp->ctm_type);
-			} else {
-				ctf_lmember_t *lmp = (ctf_lmember_t *)
-				    ((uintptr_t)tp + increment);
-
-				vbytes = sizeof (ctf_lmember_t) * vlen;
-				for (n = vlen; n != 0; n--, lmp++)
-					child |=
-					    CTF_TYPE_ISCHILD(lmp->ctlm_type);
-			}
-			break;
-		case CTF_K_ENUM:
-			vbytes = sizeof (ctf_enum_t) * vlen;
-			break;
-		case CTF_K_FORWARD:
-		case CTF_K_UNKNOWN:
-			vbytes = 0;
-			break;
-		case CTF_K_POINTER:
-		case CTF_K_TYPEDEF:
-		case CTF_K_VOLATILE:
-		case CTF_K_CONST:
-		case CTF_K_RESTRICT:
-			vbytes = 0;
-			break;
-		default:
-			printf("%s(%d): detected invalid CTF kind -- %u\n", __func__, __LINE__, kind);
-			return (EIO);
-		}
-		*xp = (uint32_t)((uintptr_t) tp - (uintptr_t) ctfdata);
-		tp = (ctf_type_t *)((uintptr_t)tp + increment + vbytes);
-	}
-
-	return (0);
-}
-
-/*
- * CTF Declaration Stack
- *
- * In order to implement ctf_type_name(), we must convert a type graph back
- * into a C type declaration.  Unfortunately, a type graph represents a storage
- * class ordering of the type whereas a type declaration must obey the C rules
- * for operator precedence, and the two orderings are frequently in conflict.
- * For example, consider these CTF type graphs and their C declarations:
- *
- * CTF_K_POINTER -> CTF_K_FUNCTION -> CTF_K_INTEGER  : int (*)()
- * CTF_K_POINTER -> CTF_K_ARRAY -> CTF_K_INTEGER     : int (*)[]
- *
- * In each case, parentheses are used to raise operator * to higher lexical
- * precedence, so the string form of the C declaration cannot be constructed by
- * walking the type graph links and forming the string from left to right.
- *
- * The functions in this file build a set of stacks from the type graph nodes
- * corresponding to the C operator precedence levels in the appropriate order.
- * The code in ctf_type_name() can then iterate over the levels and nodes in
- * lexical precedence order and construct the final C declaration string.
- */
-typedef struct ctf_list {
-	struct ctf_list *l_prev; /* previous pointer or tail pointer */
-	struct ctf_list *l_next; /* next pointer or head pointer */
-} ctf_list_t;
-
-#define	ctf_list_prev(elem)	((void *)(((ctf_list_t *)(elem))->l_prev))
-#define	ctf_list_next(elem)	((void *)(((ctf_list_t *)(elem))->l_next))
-
-typedef enum {
-	CTF_PREC_BASE,
-	CTF_PREC_POINTER,
-	CTF_PREC_ARRAY,
-	CTF_PREC_FUNCTION,
-	CTF_PREC_MAX
-} ctf_decl_prec_t;
-
-typedef struct ctf_decl_node {
-	ctf_list_t cd_list;			/* linked list pointers */
-	ctf_id_t cd_type;			/* type identifier */
-	uint_t cd_kind;				/* type kind */
-	uint_t cd_n;				/* type dimension if array */
-} ctf_decl_node_t;
-
-typedef struct ctf_decl {
-	ctf_list_t cd_nodes[CTF_PREC_MAX];	/* declaration node stacks */
-	int cd_order[CTF_PREC_MAX];		/* storage order of decls */
-	ctf_decl_prec_t cd_qualp;		/* qualifier precision */
-	ctf_decl_prec_t cd_ordp;		/* ordered precision */
-	char *cd_buf;				/* buffer for output */
-	char *cd_ptr;				/* buffer location */
-	char *cd_end;				/* buffer limit */
-	size_t cd_len;				/* buffer space required */
-	int cd_err;				/* saved error value */
-} ctf_decl_t;
-
-/*
- * Simple doubly-linked list append routine.  This implementation assumes that
- * each list element contains an embedded ctf_list_t as the first member.
- * An additional ctf_list_t is used to store the head (l_next) and tail
- * (l_prev) pointers.  The current head and tail list elements have their
- * previous and next pointers set to NULL, respectively.
- */
-static void
-ctf_list_append(ctf_list_t *lp, void *new)
-{
-	ctf_list_t *p = lp->l_prev;	/* p = tail list element */
-	ctf_list_t *q = new;		/* q = new list element */
-
-	lp->l_prev = q;
-	q->l_prev = p;
-	q->l_next = NULL;
-
-	if (p != NULL)
-		p->l_next = q;
-	else
-		lp->l_next = q;
-}
-
-/*
- * Prepend the specified existing element to the given ctf_list_t.  The
- * existing pointer should be pointing at a struct with embedded ctf_list_t.
- */
-static void
-ctf_list_prepend(ctf_list_t *lp, void *new)
-{
-	ctf_list_t *p = new;		/* p = new list element */
-	ctf_list_t *q = lp->l_next;	/* q = head list element */
-
-	lp->l_next = p;
-	p->l_prev = NULL;
-	p->l_next = q;
-
-	if (q != NULL)
-		q->l_prev = p;
-	else
-		lp->l_prev = p;
-}
-
-static void
-ctf_decl_init(ctf_decl_t *cd, char *buf, size_t len)
-{
-	int i;
-
-	bzero(cd, sizeof (ctf_decl_t));
-
-	for (i = CTF_PREC_BASE; i < CTF_PREC_MAX; i++)
-		cd->cd_order[i] = CTF_PREC_BASE - 1;
-
-	cd->cd_qualp = CTF_PREC_BASE;
-	cd->cd_ordp = CTF_PREC_BASE;
-
-	cd->cd_buf = buf;
-	cd->cd_ptr = buf;
-	cd->cd_end = buf + len;
-}
-
-static void
-ctf_decl_fini(ctf_decl_t *cd)
-{
-	ctf_decl_node_t *cdp, *ndp;
-	int i;
-
-	for (i = CTF_PREC_BASE; i < CTF_PREC_MAX; i++) {
-		for (cdp = ctf_list_next(&cd->cd_nodes[i]);
-		    cdp != NULL; cdp = ndp) {
-			ndp = ctf_list_next(cdp);
-			free(cdp, M_FBT);
-		}
-	}
-}
-
-static const ctf_type_t *
-ctf_lookup_by_id(linker_ctf_t *lc, ctf_id_t type)
-{
-	const ctf_type_t *tp;
-	uint32_t offset;
-	uint32_t *typoff = *lc->typoffp;
-
-	if (type >= *lc->typlenp) {
-		printf("%s(%d): type %d exceeds max %ld\n",__func__,__LINE__,(int) type,*lc->typlenp);
-		return(NULL);
-	}
-
-	/* Check if the type isn't cross-referenced. */
-	if ((offset = typoff[type]) == 0) {
-		printf("%s(%d): type %d isn't cross referenced\n",__func__,__LINE__, (int) type);
-		return(NULL);
-	}
-
-	tp = (const ctf_type_t *)(lc->ctftab + offset + sizeof(ctf_header_t));
-
-	return (tp);
-}
-
-static void
-fbt_array_info(linker_ctf_t *lc, ctf_id_t type, ctf_arinfo_t *arp)
-{
-	const ctf_header_t *hp = (const ctf_header_t *) lc->ctftab;
-	const ctf_type_t *tp;
-	const ctf_array_t *ap;
-	ssize_t increment;
-
-	bzero(arp, sizeof(*arp));
-
-	if ((tp = ctf_lookup_by_id(lc, type)) == NULL)
-		return;
-
-	if (CTF_INFO_KIND(tp->ctt_info) != CTF_K_ARRAY)
-		return;
-
-	(void) fbt_get_ctt_size(hp->cth_version, tp, NULL, &increment);
-
-	ap = (const ctf_array_t *)((uintptr_t)tp + increment);
-	arp->ctr_contents = ap->cta_contents;
-	arp->ctr_index = ap->cta_index;
-	arp->ctr_nelems = ap->cta_nelems;
-}
-
-static const char *
-ctf_strptr(linker_ctf_t *lc, int name)
-{
-	const ctf_header_t *hp = (const ctf_header_t *) lc->ctftab;;
-	const char *strp = "";
-
-	if (name < 0 || name >= hp->cth_strlen)
-		return (strp);
-
-	strp = (const char *)(lc->ctftab + hp->cth_stroff + name + sizeof(ctf_header_t));
-
-	return (strp);
-}
-
-static void
-ctf_decl_push(ctf_decl_t *cd, linker_ctf_t *lc, ctf_id_t type)
-{
-	ctf_decl_node_t *cdp;
-	ctf_decl_prec_t prec;
-	uint_t kind, n = 1;
-	int is_qual = 0;
-
-	const ctf_type_t *tp;
-	ctf_arinfo_t ar;
-
-	if ((tp = ctf_lookup_by_id(lc, type)) == NULL) {
-		cd->cd_err = ENOENT;
-		return;
-	}
-
-	switch (kind = CTF_INFO_KIND(tp->ctt_info)) {
-	case CTF_K_ARRAY:
-		fbt_array_info(lc, type, &ar);
-		ctf_decl_push(cd, lc, ar.ctr_contents);
-		n = ar.ctr_nelems;
-		prec = CTF_PREC_ARRAY;
-		break;
-
-	case CTF_K_TYPEDEF:
-		if (ctf_strptr(lc, tp->ctt_name)[0] == '\0') {
-			ctf_decl_push(cd, lc, tp->ctt_type);
-			return;
-		}
-		prec = CTF_PREC_BASE;
-		break;
-
-	case CTF_K_FUNCTION:
-		ctf_decl_push(cd, lc, tp->ctt_type);
-		prec = CTF_PREC_FUNCTION;
-		break;
-
-	case CTF_K_POINTER:
-		ctf_decl_push(cd, lc, tp->ctt_type);
-		prec = CTF_PREC_POINTER;
-		break;
-
-	case CTF_K_VOLATILE:
-	case CTF_K_CONST:
-	case CTF_K_RESTRICT:
-		ctf_decl_push(cd, lc, tp->ctt_type);
-		prec = cd->cd_qualp;
-		is_qual++;
-		break;
-
-	default:
-		prec = CTF_PREC_BASE;
-	}
-
-	if ((cdp = malloc(sizeof (ctf_decl_node_t), M_FBT, M_WAITOK)) == NULL) {
-		cd->cd_err = EAGAIN;
-		return;
-	}
-
-	cdp->cd_type = type;
-	cdp->cd_kind = kind;
-	cdp->cd_n = n;
-
-	if (ctf_list_next(&cd->cd_nodes[prec]) == NULL)
-		cd->cd_order[prec] = cd->cd_ordp++;
-
-	/*
-	 * Reset cd_qualp to the highest precedence level that we've seen so
-	 * far that can be qualified (CTF_PREC_BASE or CTF_PREC_POINTER).
-	 */
-	if (prec > cd->cd_qualp && prec < CTF_PREC_ARRAY)
-		cd->cd_qualp = prec;
-
-	/*
-	 * C array declarators are ordered inside out so prepend them.  Also by
-	 * convention qualifiers of base types precede the type specifier (e.g.
-	 * const int vs. int const) even though the two forms are equivalent.
-	 */
-	if (kind == CTF_K_ARRAY || (is_qual && prec == CTF_PREC_BASE))
-		ctf_list_prepend(&cd->cd_nodes[prec], cdp);
-	else
-		ctf_list_append(&cd->cd_nodes[prec], cdp);
-}
-
-static void
-ctf_decl_sprintf(ctf_decl_t *cd, const char *format, ...)
-{
-	size_t len = (size_t)(cd->cd_end - cd->cd_ptr);
-	va_list ap;
-	size_t n;
-
-	va_start(ap, format);
-	n = vsnprintf(cd->cd_ptr, len, format, ap);
-	va_end(ap);
-
-	cd->cd_ptr += MIN(n, len);
-	cd->cd_len += n;
-}
-
-static ssize_t
-fbt_type_name(linker_ctf_t *lc, ctf_id_t type, char *buf, size_t len)
-{
-	ctf_decl_t cd;
-	ctf_decl_node_t *cdp;
-	ctf_decl_prec_t prec, lp, rp;
-	int ptr, arr;
-	uint_t k;
-
-	if (lc == NULL && type == CTF_ERR)
-		return (-1); /* simplify caller code by permitting CTF_ERR */
-
-	ctf_decl_init(&cd, buf, len);
-	ctf_decl_push(&cd, lc, type);
-
-	if (cd.cd_err != 0) {
-		ctf_decl_fini(&cd);
-		return (-1);
-	}
-
-	/*
-	 * If the type graph's order conflicts with lexical precedence order
-	 * for pointers or arrays, then we need to surround the declarations at
-	 * the corresponding lexical precedence with parentheses.  This can
-	 * result in either a parenthesized pointer (*) as in int (*)() or
-	 * int (*)[], or in a parenthesized pointer and array as in int (*[])().
-	 */
-	ptr = cd.cd_order[CTF_PREC_POINTER] > CTF_PREC_POINTER;
-	arr = cd.cd_order[CTF_PREC_ARRAY] > CTF_PREC_ARRAY;
-
-	rp = arr ? CTF_PREC_ARRAY : ptr ? CTF_PREC_POINTER : -1;
-	lp = ptr ? CTF_PREC_POINTER : arr ? CTF_PREC_ARRAY : -1;
-

*** DIFF OUTPUT TRUNCATED AT 1000 LINES ***


More information about the svn-src-head mailing list