Date: Wed, 11 Feb 2015 17:27:38 +0000 (UTC) From: "George V. Neville-Neil" <gnn@FreeBSD.org> To: src-committers@freebsd.org, svn-src-all@freebsd.org, svn-src-head@freebsd.org Subject: svn commit: r278587 - head/sys/cddl/dev/fbt/arm Message-ID: <201502111727.t1BHRcGX013297@svn.freebsd.org>
next in thread | raw e-mail | index | archive | help
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 ***
Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?201502111727.t1BHRcGX013297>