diff options
Diffstat (limited to 'usr/src/common/ctf')
-rw-r--r-- | usr/src/common/ctf/ctf_create.c | 2 | ||||
-rw-r--r-- | usr/src/common/ctf/ctf_hash.c | 160 | ||||
-rw-r--r-- | usr/src/common/ctf/ctf_impl.h | 6 | ||||
-rw-r--r-- | usr/src/common/ctf/ctf_types.c | 64 |
4 files changed, 228 insertions, 4 deletions
diff --git a/usr/src/common/ctf/ctf_create.c b/usr/src/common/ctf/ctf_create.c index 239d166f44..f9feca81cf 100644 --- a/usr/src/common/ctf/ctf_create.c +++ b/usr/src/common/ctf/ctf_create.c @@ -574,7 +574,7 @@ ctf_dtd_lookup(ctf_file_t *fp, ctf_id_t type) int ctf_discard(ctf_file_t *fp) { - ctf_dtdef_t *dtd, *ntd; + ctf_dtdef_t *dtd, *ntd = NULL; if (!(fp->ctf_flags & LCTF_RDWR)) return (ctf_set_errno(fp, ECTF_RDONLY)); diff --git a/usr/src/common/ctf/ctf_hash.c b/usr/src/common/ctf/ctf_hash.c index b10a7618f6..e68fe8e516 100644 --- a/usr/src/common/ctf/ctf_hash.c +++ b/usr/src/common/ctf/ctf_hash.c @@ -25,9 +25,8 @@ * Use is subject to license terms. */ -#pragma ident "%Z%%M% %I% %E% SMI" - #include <ctf_impl.h> +#include <sys/debug.h> static const ushort_t _CTF_EMPTY[1] = { 0 }; @@ -176,3 +175,160 @@ ctf_hash_destroy(ctf_hash_t *hp) hp->h_chains = NULL; } } + +int +ctf_idhash_create(ctf_idhash_t *ihp, ulong_t nelems) +{ + if (nelems > USHRT_MAX) + return (EOVERFLOW); + + /* + * If the hash table is going to be empty, don't bother allocating any + * memory and make the only bucket point to a zero so lookups fail. + */ + if (nelems == 0) { + bzero(ihp, sizeof (ctf_idhash_t)); + ihp->ih_buckets = (ushort_t *)_CTF_EMPTY; + ihp->ih_nbuckets = 1; + return (0); + } + + ihp->ih_nbuckets = 211; /* use a prime number of hash buckets */ + ihp->ih_nelems = nelems + 1; /* we use index zero as a sentinel */ + ihp->ih_free = 1; /* first free element is index 1 */ + + ihp->ih_buckets = ctf_alloc(sizeof (ushort_t) * ihp->ih_nbuckets); + ihp->ih_chains = ctf_alloc(sizeof (ctf_ihelem_t) * ihp->ih_nelems); + + if (ihp->ih_buckets == NULL || ihp->ih_chains == NULL) { + ctf_idhash_destroy(ihp); + return (EAGAIN); + } + + bzero(ihp->ih_buckets, sizeof (ushort_t) * ihp->ih_nbuckets); + bzero(ihp->ih_chains, sizeof (ctf_ihelem_t) * ihp->ih_nelems); + + return (0); +} + +void +ctf_idhash_clear(ctf_idhash_t *ihp) +{ + /* Nothing to do for a sentinel hash */ + if (ihp->ih_nbuckets == 1) { + ASSERT(ihp->ih_buckets == (ushort_t *)_CTF_EMPTY); + return; + } + + ihp->ih_free = 1; + bzero(ihp->ih_buckets, sizeof (ushort_t) * ihp->ih_nbuckets); + bzero(ihp->ih_chains, sizeof (ctf_ihelem_t) * ihp->ih_nelems); +} + +uint_t +ctf_idhash_size(const ctf_idhash_t *hp) +{ + return (hp->ih_nelems ? hp->ih_nelems - 1 : 0); +} + +static ulong_t +ctf_idhash_compute(ctf_id_t id) +{ + return (id); +} + +int +ctf_idhash_insert(ctf_idhash_t *ihp, ushort_t type, ushort_t value) +{ + ctf_ihelem_t *ihep = &ihp->ih_chains[ihp->ih_free]; + ulong_t h; + + if (ihp->ih_free >= ihp->ih_nelems) + return (EOVERFLOW); + + ihep->ih_type = type; + ihep->ih_value = value; + h = ctf_idhash_compute(type) % ihp->ih_nbuckets; + ihep->ih_next = ihp->ih_buckets[h]; + ihp->ih_buckets[h] = ihp->ih_free++; + + return (0); +} + +int +ctf_idhash_define(ctf_idhash_t *ihp, ushort_t type, ushort_t value) +{ + ctf_ihelem_t *hep = ctf_idhash_lookup(ihp, type); + + if (hep == NULL) + return (ctf_idhash_insert(ihp, type, value)); + + hep->ih_value = value; + return (0); +} + + +ctf_ihelem_t * +ctf_idhash_lookup(ctf_idhash_t *ihp, ushort_t key) +{ + ctf_ihelem_t *ihep; + ushort_t i; + + ulong_t h = ctf_idhash_compute(key) % ihp->ih_nbuckets; + + for (i = ihp->ih_buckets[h]; i != 0; i = ihep->ih_next) { + ihep = &ihp->ih_chains[i]; + + if (ihep->ih_type == key) + return (ihep); + } + + return (NULL); +} + +void +ctf_idhash_destroy(ctf_idhash_t *ihp) +{ + if (ihp->ih_buckets != NULL && ihp->ih_nbuckets != 1) { + ctf_free(ihp->ih_buckets, sizeof (ushort_t) * ihp->ih_nbuckets); + ihp->ih_buckets = NULL; + } + + if (ihp->ih_chains != NULL) { + ctf_free(ihp->ih_chains, sizeof (ctf_helem_t) * ihp->ih_nelems); + ihp->ih_chains = NULL; + } +} + +/*ARGSUSED*/ +int +ctf_idhash_iter_init(ctf_idhash_t *ihp, ctf_idhash_iter_t **iterp) +{ + + *iterp = ctf_alloc(sizeof (ctf_idhash_iter_t)); + if (*iterp == NULL) + return (ENOMEM); + + if (ihp->ih_free == 0) + (*iterp)->cii_id = 0; + else + (*iterp)->cii_id = 1; + + return (0); +} + +const ctf_ihelem_t * +ctf_idhash_iter(ctf_idhash_t *ihp, ctf_idhash_iter_t *iter) +{ + if (iter->cii_id >= ihp->ih_free) + return (NULL); + + return (&ihp->ih_chains[iter->cii_id++]); +} + +/*ARGSUSED*/ +void +ctf_idhash_iter_fini(ctf_idhash_t *ihp, ctf_idhash_iter_t *iter) +{ + ctf_free(iter, sizeof (ctf_idhash_iter_t)); +} diff --git a/usr/src/common/ctf/ctf_impl.h b/usr/src/common/ctf/ctf_impl.h index f56fa6a005..42aec80a43 100644 --- a/usr/src/common/ctf/ctf_impl.h +++ b/usr/src/common/ctf/ctf_impl.h @@ -25,7 +25,7 @@ * Use is subject to license terms. */ /* - * Copyright (c) 2012, Joyent, Inc. All rights reserved. + * Copyright (c) 2014, Joyent, Inc. All rights reserved. */ #ifndef _CTF_IMPL_H @@ -77,6 +77,10 @@ typedef struct ctf_hash { uint_t h_free; /* index of next free hash element */ } ctf_hash_t; +struct ctf_idhash_iter { + int cii_id; /* Current iteration id */ +}; + typedef struct ctf_strs { const char *cts_strs; /* base address of string table */ size_t cts_len; /* size of string table in bytes */ diff --git a/usr/src/common/ctf/ctf_types.c b/usr/src/common/ctf/ctf_types.c index ab1b9ff14b..93168f25cb 100644 --- a/usr/src/common/ctf/ctf_types.c +++ b/usr/src/common/ctf/ctf_types.c @@ -26,6 +26,7 @@ */ #include <ctf_impl.h> +#include <sys/debug.h> ssize_t ctf_get_ctt_size(const ctf_file_t *fp, const ctf_type_t *tp, ssize_t *sizep, @@ -868,3 +869,66 @@ ctf_type_visit(ctf_file_t *fp, ctf_id_t type, ctf_visit_f *func, void *arg) { return (ctf_type_rvisit(fp, type, func, arg, "", 0, 0)); } + +int +ctf_func_info_by_id(ctf_file_t *fp, ctf_id_t type, ctf_funcinfo_t *fip) +{ + ctf_file_t *ofp = fp; + const ctf_type_t *tp; + const ushort_t *dp; + int nargs; + ssize_t increment; + + if ((tp = ctf_lookup_by_id(&fp, type)) == NULL) + return (CTF_ERR); /* errno is set for us */ + + if (LCTF_INFO_KIND(fp, tp->ctt_info) != CTF_K_FUNCTION) + return (ctf_set_errno(ofp, ECTF_NOTFUNC)); + + fip->ctc_return = tp->ctt_type; + nargs = LCTF_INFO_VLEN(fp, tp->ctt_info); + fip->ctc_argc = nargs; + fip->ctc_flags = 0; + + /* dp should now point to the first argument */ + if (nargs != 0) { + (void) ctf_get_ctt_size(fp, tp, NULL, &increment); + dp = (ushort_t *)((uintptr_t)fp->ctf_buf + + fp->ctf_txlate[CTF_TYPE_TO_INDEX(type)] + increment); + if (dp[nargs - 1] == 0) { + fip->ctc_flags |= CTF_FUNC_VARARG; + fip->ctc_argc--; + } + } + + return (0); +} + +int +ctf_func_args_by_id(ctf_file_t *fp, ctf_id_t type, uint_t argc, ctf_id_t *argv) +{ + ctf_file_t *ofp = fp; + const ctf_type_t *tp; + const ushort_t *dp; + int nargs; + ssize_t increment; + + if ((tp = ctf_lookup_by_id(&fp, type)) == NULL) + return (CTF_ERR); /* errno is set for us */ + + if (LCTF_INFO_KIND(fp, tp->ctt_info) != CTF_K_FUNCTION) + return (ctf_set_errno(ofp, ECTF_NOTFUNC)); + + nargs = LCTF_INFO_VLEN(fp, tp->ctt_info); + (void) ctf_get_ctt_size(fp, tp, NULL, &increment); + dp = (ushort_t *)((uintptr_t)fp->ctf_buf + + fp->ctf_txlate[CTF_TYPE_TO_INDEX(type)] + + increment); + if (nargs != 0 && dp[nargs - 1] == 0) + nargs--; + + for (nargs = MIN(argc, nargs); nargs != 0; nargs--) + *argv++ = *dp++; + + return (0); +} |