diff options
author | delphij <delphij@FreeBSD.org> | 2013-08-23 23:21:24 +0000 |
---|---|---|
committer | delphij <delphij@FreeBSD.org> | 2013-08-23 23:21:24 +0000 |
commit | 5017a032d282b2ecdd81495733cc73657ff2b8fb (patch) | |
tree | ad32c6f1bbf74e601fd4395f5a07217ce6a2de60 /cddl | |
parent | 2dbc95284850f1d96e8a2e075080a1b1c17986f5 (diff) | |
download | FreeBSD-src-5017a032d282b2ecdd81495733cc73657ff2b8fb.zip FreeBSD-src-5017a032d282b2ecdd81495733cc73657ff2b8fb.tar.gz |
MFV r254422:
Illumos DTrace issues:
3089 want ::typedef
3094 libctf should support removing a dynamic type
3095 libctf does not validate arrays correctly
3096 libctf does not validate function types correctly
Diffstat (limited to 'cddl')
-rw-r--r-- | cddl/contrib/opensolaris/common/ctf/ctf_create.c | 190 | ||||
-rw-r--r-- | cddl/contrib/opensolaris/common/ctf/ctf_error.c | 7 | ||||
-rw-r--r-- | cddl/contrib/opensolaris/common/ctf/ctf_impl.h | 10 | ||||
-rw-r--r-- | cddl/contrib/opensolaris/common/ctf/ctf_open.c | 13 |
4 files changed, 204 insertions, 16 deletions
diff --git a/cddl/contrib/opensolaris/common/ctf/ctf_create.c b/cddl/contrib/opensolaris/common/ctf/ctf_create.c index a4f3df3..239d166 100644 --- a/cddl/contrib/opensolaris/common/ctf/ctf_create.c +++ b/cddl/contrib/opensolaris/common/ctf/ctf_create.c @@ -24,13 +24,15 @@ * Copyright 2006 Sun Microsystems, Inc. All rights reserved. * Use is subject to license terms. */ - -#pragma ident "%Z%%M% %I% %E% SMI" +/* + * Copyright (c) 2013, Joyent, Inc. All rights reserved. + */ #include <sys/sysmacros.h> #include <sys/param.h> #include <sys/mman.h> #include <ctf_impl.h> +#include <sys/debug.h> /* * This static string is used as the template for initially populating a @@ -167,6 +169,51 @@ ctf_copy_membnames(ctf_dtdef_t *dtd, uchar_t *s) } /* + * Only types of dyanmic CTF containers contain reference counts. These + * containers are marked RD/WR. Because of that we basically make this a no-op + * for compatability with non-dynamic CTF sections. This is also a no-op for + * types which are not dynamic types. It is the responsibility of the caller to + * make sure it is a valid type. We help that caller out on debug builds. + * + * Note that the reference counts are not maintained for types that are not + * within this container. In other words if we have a type in a parent, that + * will not have its reference count increased. On the flip side, the parent + * will not be allowed to remove dynamic types if it has children. + */ +static void +ctf_ref_inc(ctf_file_t *fp, ctf_id_t tid) +{ + ctf_dtdef_t *dtd = ctf_dtd_lookup(fp, tid); + + if (dtd == NULL) + return; + + if (!(fp->ctf_flags & LCTF_RDWR)) + return; + + dtd->dtd_ref++; +} + +/* + * Just as with ctf_ref_inc, this is a no-op on non-writeable containers and the + * caller should ensure that this is already a valid type. + */ +static void +ctf_ref_dec(ctf_file_t *fp, ctf_id_t tid) +{ + ctf_dtdef_t *dtd = ctf_dtd_lookup(fp, tid); + + if (dtd == NULL) + return; + + if (!(fp->ctf_flags & LCTF_RDWR)) + return; + + ASSERT(dtd->dtd_ref >= 1); + dtd->dtd_ref--; +} + +/* * If the specified CTF container is writable and has been modified, reload * this container with the updated type definitions. In order to make this * code and the rest of libctf as simple as possible, we perform updates by @@ -180,6 +227,10 @@ ctf_copy_membnames(ctf_dtdef_t *dtd, uchar_t *s) * ctf_bufopen() will return a new ctf_file_t, but we want to keep the fp * constant for the caller, so after ctf_bufopen() returns, we use bcopy to * swap the interior of the old and new ctf_file_t's, and then free the old. + * + * Note that the lists of dynamic types stays around and the resulting container + * is still writeable. Furthermore, the reference counts that are on the dtd's + * are still valid. */ int ctf_update(ctf_file_t *fp) @@ -432,6 +483,7 @@ ctf_dtd_delete(ctf_file_t *fp, ctf_dtdef_t *dtd) ctf_dtdef_t *p, **q = &fp->ctf_dthash[h]; ctf_dmdef_t *dmd, *nmd; size_t len; + int kind, i; for (p = *q; p != NULL; p = p->dtd_hash) { if (p != dtd) @@ -443,7 +495,8 @@ ctf_dtd_delete(ctf_file_t *fp, ctf_dtdef_t *dtd) if (p != NULL) *q = p->dtd_hash; - switch (CTF_INFO_KIND(dtd->dtd_data.ctt_info)) { + kind = CTF_INFO_KIND(dtd->dtd_data.ctt_info); + switch (kind) { case CTF_K_STRUCT: case CTF_K_UNION: case CTF_K_ENUM: @@ -454,14 +507,33 @@ ctf_dtd_delete(ctf_file_t *fp, ctf_dtdef_t *dtd) ctf_free(dmd->dmd_name, len); fp->ctf_dtstrlen -= len; } + if (kind != CTF_K_ENUM) + ctf_ref_dec(fp, dmd->dmd_type); nmd = ctf_list_next(dmd); ctf_free(dmd, sizeof (ctf_dmdef_t)); } break; case CTF_K_FUNCTION: + ctf_ref_dec(fp, dtd->dtd_data.ctt_type); + for (i = 0; i < CTF_INFO_VLEN(dtd->dtd_data.ctt_info); i++) + if (dtd->dtd_u.dtu_argv[i] != 0) + ctf_ref_dec(fp, dtd->dtd_u.dtu_argv[i]); ctf_free(dtd->dtd_u.dtu_argv, sizeof (ctf_id_t) * CTF_INFO_VLEN(dtd->dtd_data.ctt_info)); break; + case CTF_K_ARRAY: + ctf_ref_dec(fp, dtd->dtd_u.dtu_arr.ctr_contents); + ctf_ref_dec(fp, dtd->dtd_u.dtu_arr.ctr_index); + break; + case CTF_K_TYPEDEF: + ctf_ref_dec(fp, dtd->dtd_data.ctt_type); + break; + case CTF_K_POINTER: + case CTF_K_VOLATILE: + case CTF_K_CONST: + case CTF_K_RESTRICT: + ctf_ref_dec(fp, dtd->dtd_data.ctt_type); + break; } if (dtd->dtd_name) { @@ -495,7 +567,9 @@ ctf_dtd_lookup(ctf_file_t *fp, ctf_id_t type) * Discard all of the dynamic type definitions that have been added to the * container since the last call to ctf_update(). We locate such types by * scanning the list and deleting elements that have type IDs greater than - * ctf_dtoldid, which is set by ctf_update(), above. + * ctf_dtoldid, which is set by ctf_update(), above. Note that to work properly + * with our reference counting schemes, we must delete the dynamic list in + * reverse. */ int ctf_discard(ctf_file_t *fp) @@ -508,11 +582,11 @@ ctf_discard(ctf_file_t *fp) if (!(fp->ctf_flags & LCTF_DIRTY)) return (0); /* no update required */ - for (dtd = ctf_list_next(&fp->ctf_dtdefs); dtd != NULL; dtd = ntd) { + for (dtd = ctf_list_prev(&fp->ctf_dtdefs); dtd != NULL; dtd = ntd) { if (dtd->dtd_type <= fp->ctf_dtoldid) continue; /* skip types that have been committed */ - ntd = ctf_list_next(dtd); + ntd = ctf_list_prev(dtd); ctf_dtd_delete(fp, dtd); } @@ -614,6 +688,8 @@ ctf_add_reftype(ctf_file_t *fp, uint_t flag, ctf_id_t ref, uint_t kind) if ((type = ctf_add_generic(fp, flag, NULL, &dtd)) == CTF_ERR) return (CTF_ERR); /* errno is set for us */ + ctf_ref_inc(fp, ref); + dtd->dtd_data.ctt_info = CTF_TYPE_INFO(kind, flag, 0); dtd->dtd_data.ctt_type = (ushort_t)ref; @@ -645,16 +721,29 @@ ctf_add_array(ctf_file_t *fp, uint_t flag, const ctf_arinfo_t *arp) { ctf_dtdef_t *dtd; ctf_id_t type; + ctf_file_t *fpd; if (arp == NULL) return (ctf_set_errno(fp, EINVAL)); + fpd = fp; + if (ctf_lookup_by_id(&fpd, arp->ctr_contents) == NULL && + ctf_dtd_lookup(fp, arp->ctr_contents) == NULL) + return (ctf_set_errno(fp, ECTF_BADID)); + + fpd = fp; + if (ctf_lookup_by_id(&fpd, arp->ctr_index) == NULL && + ctf_dtd_lookup(fp, arp->ctr_index) == NULL) + return (ctf_set_errno(fp, ECTF_BADID)); + if ((type = ctf_add_generic(fp, flag, NULL, &dtd)) == CTF_ERR) return (CTF_ERR); /* errno is set for us */ dtd->dtd_data.ctt_info = CTF_TYPE_INFO(CTF_K_ARRAY, flag, 0); dtd->dtd_data.ctt_size = 0; dtd->dtd_u.dtu_arr = *arp; + ctf_ref_inc(fp, arp->ctr_contents); + ctf_ref_inc(fp, arp->ctr_index); return (type); } @@ -662,6 +751,7 @@ ctf_add_array(ctf_file_t *fp, uint_t flag, const ctf_arinfo_t *arp) int ctf_set_array(ctf_file_t *fp, ctf_id_t type, const ctf_arinfo_t *arp) { + ctf_file_t *fpd; ctf_dtdef_t *dtd = ctf_dtd_lookup(fp, type); if (!(fp->ctf_flags & LCTF_RDWR)) @@ -670,8 +760,22 @@ ctf_set_array(ctf_file_t *fp, ctf_id_t type, const ctf_arinfo_t *arp) if (dtd == NULL || CTF_INFO_KIND(dtd->dtd_data.ctt_info) != CTF_K_ARRAY) return (ctf_set_errno(fp, ECTF_BADID)); + fpd = fp; + if (ctf_lookup_by_id(&fpd, arp->ctr_contents) == NULL && + ctf_dtd_lookup(fp, arp->ctr_contents) == NULL) + return (ctf_set_errno(fp, ECTF_BADID)); + + fpd = fp; + if (ctf_lookup_by_id(&fpd, arp->ctr_index) == NULL && + ctf_dtd_lookup(fp, arp->ctr_index) == NULL) + return (ctf_set_errno(fp, ECTF_BADID)); + + ctf_ref_dec(fp, dtd->dtd_u.dtu_arr.ctr_contents); + ctf_ref_dec(fp, dtd->dtd_u.dtu_arr.ctr_index); fp->ctf_flags |= LCTF_DIRTY; dtd->dtd_u.dtu_arr = *arp; + ctf_ref_inc(fp, arp->ctr_contents); + ctf_ref_inc(fp, arp->ctr_index); return (0); } @@ -683,7 +787,9 @@ ctf_add_function(ctf_file_t *fp, uint_t flag, ctf_dtdef_t *dtd; ctf_id_t type; uint_t vlen; + int i; ctf_id_t *vdat = NULL; + ctf_file_t *fpd; if (ctc == NULL || (ctc->ctc_flags & ~CTF_FUNC_VARARG) != 0 || (ctc->ctc_argc != 0 && argv == NULL)) @@ -696,6 +802,18 @@ ctf_add_function(ctf_file_t *fp, uint_t flag, if (vlen > CTF_MAX_VLEN) return (ctf_set_errno(fp, EOVERFLOW)); + fpd = fp; + if (ctf_lookup_by_id(&fpd, ctc->ctc_return) == NULL && + ctf_dtd_lookup(fp, ctc->ctc_return) == NULL) + return (ctf_set_errno(fp, ECTF_BADID)); + + for (i = 0; i < ctc->ctc_argc; i++) { + fpd = fp; + if (ctf_lookup_by_id(&fpd, argv[i]) == NULL && + ctf_dtd_lookup(fp, argv[i]) == NULL) + return (ctf_set_errno(fp, ECTF_BADID)); + } + if (vlen != 0 && (vdat = ctf_alloc(sizeof (ctf_id_t) * vlen)) == NULL) return (ctf_set_errno(fp, EAGAIN)); @@ -707,6 +825,10 @@ ctf_add_function(ctf_file_t *fp, uint_t flag, dtd->dtd_data.ctt_info = CTF_TYPE_INFO(CTF_K_FUNCTION, flag, vlen); dtd->dtd_data.ctt_type = (ushort_t)ctc->ctc_return; + ctf_ref_inc(fp, ctc->ctc_return); + for (i = 0; i < ctc->ctc_argc; i++) + ctf_ref_inc(fp, argv[i]); + bcopy(argv, vdat, sizeof (ctf_id_t) * ctc->ctc_argc); if (ctc->ctc_flags & CTF_FUNC_VARARG) vdat[vlen - 1] = 0; /* add trailing zero to indicate varargs */ @@ -825,8 +947,11 @@ ctf_add_typedef(ctf_file_t *fp, uint_t flag, const char *name, ctf_id_t ref) { ctf_dtdef_t *dtd; ctf_id_t type; + ctf_file_t *fpd; - if (ref == CTF_ERR || ref < 0 || ref > CTF_MAX_TYPE) + fpd = fp; + if (ref == CTF_ERR || (ctf_lookup_by_id(&fpd, ref) == NULL && + ctf_dtd_lookup(fp, ref) == NULL)) return (ctf_set_errno(fp, EINVAL)); if ((type = ctf_add_generic(fp, flag, name, &dtd)) == CTF_ERR) @@ -834,6 +959,7 @@ ctf_add_typedef(ctf_file_t *fp, uint_t flag, const char *name, ctf_id_t ref) dtd->dtd_data.ctt_info = CTF_TYPE_INFO(CTF_K_TYPEDEF, flag, 0); dtd->dtd_data.ctt_type = (ushort_t)ref; + ctf_ref_inc(fp, ref); return (type); } @@ -1008,6 +1134,45 @@ ctf_add_member(ctf_file_t *fp, ctf_id_t souid, const char *name, ctf_id_t type) if (s != NULL) fp->ctf_dtstrlen += strlen(s) + 1; + ctf_ref_inc(fp, type); + fp->ctf_flags |= LCTF_DIRTY; + return (0); +} + +/* + * This removes a type from the dynamic section. This will fail if the type is + * referenced by another type. Note that the CTF ID is never reused currently by + * CTF. Note that if this container is a parent container then we just outright + * refuse to remove the type. There currently is no notion of searching for the + * ctf_dtdef_t in parent containers. If there is, then this constraint could + * become finer grained. + */ +int +ctf_delete_type(ctf_file_t *fp, ctf_id_t type) +{ + ctf_file_t *fpd; + ctf_dtdef_t *dtd = ctf_dtd_lookup(fp, type); + + if (!(fp->ctf_flags & LCTF_RDWR)) + return (ctf_set_errno(fp, ECTF_RDONLY)); + + /* + * We want to give as useful an errno as possible. That means that we + * want to distinguish between a type which does not exist and one for + * which the type is not dynamic. + */ + fpd = fp; + if (ctf_lookup_by_id(&fpd, type) == NULL && + ctf_dtd_lookup(fp, type) == NULL) + return (CTF_ERR); /* errno is set for us */ + + if (dtd == NULL) + return (ctf_set_errno(fp, ECTF_NOTDYN)); + + if (dtd->dtd_ref != 0 || fp->ctf_refcnt > 1) + return (ctf_set_errno(fp, ECTF_REFERENCED)); + + ctf_dtd_delete(fp, dtd); fp->ctf_flags |= LCTF_DIRTY; return (0); } @@ -1103,6 +1268,9 @@ ctf_add_type(ctf_file_t *dst_fp, ctf_file_t *src_fp, ctf_id_t src_type) ctf_hash_t *hp; ctf_helem_t *hep; + if (dst_fp == src_fp) + return (src_type); + if (!(dst_fp->ctf_flags & LCTF_RDWR)) return (ctf_set_errno(dst_fp, ECTF_RDONLY)); @@ -1313,6 +1481,14 @@ ctf_add_type(ctf_file_t *dst_fp, ctf_file_t *src_fp, ctf_id_t src_type) if (errs) return (CTF_ERR); /* errno is set for us */ + + /* + * Now that we know that we can't fail, we go through and bump + * all the reference counts on the member types. + */ + for (dmd = ctf_list_next(&dtd->dtd_u.dtu_members); + dmd != NULL; dmd = ctf_list_next(dmd)) + ctf_ref_inc(dst_fp, dmd->dmd_type); break; } diff --git a/cddl/contrib/opensolaris/common/ctf/ctf_error.c b/cddl/contrib/opensolaris/common/ctf/ctf_error.c index 888c6c8..fe3d0de 100644 --- a/cddl/contrib/opensolaris/common/ctf/ctf_error.c +++ b/cddl/contrib/opensolaris/common/ctf/ctf_error.c @@ -23,8 +23,9 @@ * Copyright 2003 Sun Microsystems, Inc. All rights reserved. * Use is subject to license terms. */ - -#pragma ident "%Z%%M% %I% %E% SMI" +/* + * Copyright (c) 2012, Joyent, Inc. + */ #include <ctf_impl.h> @@ -73,6 +74,8 @@ static const char *const _ctf_errlist[] = { "Limit on number of dynamic types reached", /* ECTF_FULL */ "Duplicate member name definition", /* ECTF_DUPMEMBER */ "Conflicting type is already defined", /* ECTF_CONFLICT */ + "Type has outstanding references", /* ECTF_REFERENCED */ + "Type is not a dynamic type" /* ECTF_NOTDYN */ }; static const int _ctf_nerr = sizeof (_ctf_errlist) / sizeof (_ctf_errlist[0]); diff --git a/cddl/contrib/opensolaris/common/ctf/ctf_impl.h b/cddl/contrib/opensolaris/common/ctf/ctf_impl.h index 9999080..f56fa6a 100644 --- a/cddl/contrib/opensolaris/common/ctf/ctf_impl.h +++ b/cddl/contrib/opensolaris/common/ctf/ctf_impl.h @@ -24,12 +24,13 @@ * Copyright 2006 Sun Microsystems, Inc. All rights reserved. * Use is subject to license terms. */ +/* + * Copyright (c) 2012, Joyent, Inc. All rights reserved. + */ #ifndef _CTF_IMPL_H #define _CTF_IMPL_H -#pragma ident "%Z%%M% %I% %E% SMI" - #include <sys/types.h> #include <sys/errno.h> #include <sys/sysmacros.h> @@ -149,6 +150,7 @@ typedef struct ctf_dtdef { char *dtd_name; /* name associated with definition (if any) */ ctf_id_t dtd_type; /* type identifier for this definition */ ctf_type_t dtd_data; /* type node (see <sys/ctf.h>) */ + int dtd_ref; /* recfount for dyanmic types */ union { ctf_list_t dtu_members; /* struct, union, or enum */ ctf_arinfo_t dtu_arr; /* array */ @@ -269,7 +271,9 @@ enum { ECTF_DTFULL, /* CTF type is full (no more members allowed) */ ECTF_FULL, /* CTF container is full */ ECTF_DUPMEMBER, /* duplicate member name definition */ - ECTF_CONFLICT /* conflicting type definition present */ + ECTF_CONFLICT, /* conflicting type definition present */ + ECTF_REFERENCED, /* type has outstanding references */ + ECTF_NOTDYN /* type is not a dynamic type */ }; extern ssize_t ctf_get_ctt_size(const ctf_file_t *, const ctf_type_t *, diff --git a/cddl/contrib/opensolaris/common/ctf/ctf_open.c b/cddl/contrib/opensolaris/common/ctf/ctf_open.c index e49a4cb..2148389 100644 --- a/cddl/contrib/opensolaris/common/ctf/ctf_open.c +++ b/cddl/contrib/opensolaris/common/ctf/ctf_open.c @@ -24,8 +24,9 @@ * Copyright 2006 Sun Microsystems, Inc. All rights reserved. * Use is subject to license terms. */ - -#pragma ident "%Z%%M% %I% %E% SMI" +/* + * Copyright (c) 2012, Joyent, Inc. All rights reserved. + */ #include <ctf_impl.h> #include <sys/mman.h> @@ -810,8 +811,12 @@ ctf_close(ctf_file_t *fp) if (fp->ctf_parent != NULL) ctf_close(fp->ctf_parent); - for (dtd = ctf_list_next(&fp->ctf_dtdefs); dtd != NULL; dtd = ntd) { - ntd = ctf_list_next(dtd); + /* + * Note, to work properly with reference counting on the dynamic + * section, we must delete the list in reverse. + */ + for (dtd = ctf_list_prev(&fp->ctf_dtdefs); dtd != NULL; dtd = ntd) { + ntd = ctf_list_prev(dtd); ctf_dtd_delete(fp, dtd); } |