summaryrefslogtreecommitdiff
path: root/usr/src/common/ctf
diff options
context:
space:
mode:
Diffstat (limited to 'usr/src/common/ctf')
-rw-r--r--usr/src/common/ctf/ctf_create.c2
-rw-r--r--usr/src/common/ctf/ctf_hash.c160
-rw-r--r--usr/src/common/ctf/ctf_impl.h6
-rw-r--r--usr/src/common/ctf/ctf_types.c64
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);
+}