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-all
mailing list