Exemple #1
0
static int
type_equals(mdb_ctf_id_t a, mdb_ctf_id_t b)
{
	size_t asz, bsz;
	int akind, bkind;
	mdb_ctf_arinfo_t aar, bar;

	/*
	 * Resolve both types down to their fundamental types, and make
	 * sure their sizes and kinds match.
	 */
	if (mdb_ctf_type_resolve(a, &a) != 0 ||
	    mdb_ctf_type_resolve(b, &b) != 0 ||
	    (asz = mdb_ctf_type_size(a)) == -1UL ||
	    (bsz = mdb_ctf_type_size(b)) == -1UL ||
	    (akind = mdb_ctf_type_kind(a)) == -1 ||
	    (bkind = mdb_ctf_type_kind(b)) == -1 ||
	    asz != bsz || akind != bkind) {
		return (0);
	}

	switch (akind) {
	case CTF_K_INTEGER:
	case CTF_K_FLOAT:
	case CTF_K_POINTER:
		/*
		 * For pointers we could be a little stricter and require
		 * both pointers to reference types which look vaguely
		 * similar (for example, we could insist that the two types
		 * have the same name). However, all we really care about
		 * here is that the structure of the two types are the same,
		 * and, in that regard, one pointer is as good as another.
		 */
		return (1);

	case CTF_K_UNION:
	case CTF_K_STRUCT:
		/*
		 * The test for the number of members is only strictly
		 * necessary for unions since we'll find other problems with
		 * structs. However, the extra check will do no harm.
		 */
		return (mdb_ctf_num_members(a) == mdb_ctf_num_members(b) &&
		    mdb_ctf_member_iter(a, type_equals_cb, &b) == 0);

	case CTF_K_ARRAY:
		return (mdb_ctf_array_info(a, &aar) == 0 &&
		    mdb_ctf_array_info(b, &bar) == 0 &&
		    aar.mta_nelems == bar.mta_nelems &&
		    type_equals(aar.mta_index, bar.mta_index) &&
		    type_equals(aar.mta_contents, bar.mta_contents));
	}

	return (0);
}
Exemple #2
0
static int
ttrace_ttr_size_check(void)
{
	mdb_ctf_id_t ttrtid;
	ssize_t ttr_size;

	if (mdb_ctf_lookup_by_name("trap_trace_rec_t", &ttrtid) != 0 ||
	    mdb_ctf_type_resolve(ttrtid, &ttrtid) != 0) {
		mdb_warn("failed to determine size of trap_trace_rec_t; "
		    "non-TRAPTRACE kernel?\n");
		return (0);
	}

	if ((ttr_size = mdb_ctf_type_size(ttrtid)) !=
	    sizeof (trap_trace_rec_t)) {
		/*
		 * On Intel machines, this will happen when TTR_STACK_DEPTH
		 * is changed.  This code could be smarter, and could
		 * dynamically adapt to different depths, but not until a
		 * need for such adaptation is demonstrated.
		 */
		mdb_warn("size of trap_trace_rec_t (%d bytes) doesn't "
		    "match expected %d\n", ttr_size, sizeof (trap_trace_rec_t));
		return (0);
	}

	return (1);
}
Exemple #3
0
int
mdb_ctf_enum_iter(mdb_ctf_id_t id, mdb_ctf_enum_f *cb, void *data)
{
	mdb_ctf_impl_t *idp = (mdb_ctf_impl_t *)&id;
	int ret;

	/* resolve the type in case there's a forward declaration */
	if ((ret = mdb_ctf_type_resolve(id, &id)) != 0)
		return (ret);

	return (ctf_enum_iter(idp->mci_fp, idp->mci_id, cb, data));
}
Exemple #4
0
const char *
mdb_ctf_enum_name(mdb_ctf_id_t id, int value)
{
	mdb_ctf_impl_t *idp = (mdb_ctf_impl_t *)&id;
	const char *ret;

	/* resolve the type in case there's a forward declaration */
	if (mdb_ctf_type_resolve(id, &id) != 0)
		return (NULL);

	if ((ret = ctf_enum_name(idp->mci_fp, idp->mci_id, value)) == NULL)
		(void) set_errno(ctf_to_errno(ctf_errno(idp->mci_fp)));

	return (ret);
}
Exemple #5
0
ssize_t
mdb_ctf_type_size(mdb_ctf_id_t id)
{
	mdb_ctf_impl_t *idp = (mdb_ctf_impl_t *)&id;
	ssize_t ret;

	/* resolve the type in case there's a forward declaration */
	if ((ret = mdb_ctf_type_resolve(id, &id)) != 0)
		return (ret);

	if ((ret = ctf_type_size(idp->mci_fp, idp->mci_id)) == CTF_ERR)
		return (set_errno(ctf_to_errno(ctf_errno(idp->mci_fp))));

	return (ret);
}
Exemple #6
0
/*
 * callback proxy for mdb_ctf_type_visit
 */
static int
type_cb(const char *name, ctf_id_t type, ulong_t off, int depth, void *arg)
{
	type_visit_t *tvp = arg;
	mdb_ctf_id_t id;
	mdb_ctf_id_t base;
	mdb_ctf_impl_t *basep = (mdb_ctf_impl_t *)&base;

	int ret;

	if (depth < tvp->tv_min_depth)
		return (0);

	off += tvp->tv_base_offset;
	depth += tvp->tv_base_depth;

	set_ctf_id(&id, tvp->tv_fp, type);

	(void) mdb_ctf_type_resolve(id, &base);
	if ((ret = tvp->tv_cb(name, id, base, off, depth, tvp->tv_arg)) != 0)
		return (ret);

	/*
	 * If the type resolves to a type in a different file, we must have
	 * followed a forward declaration.  We need to recurse into the
	 * new type.
	 */
	if (basep->mci_fp != tvp->tv_fp && mdb_ctf_type_valid(base)) {
		type_visit_t tv;

		tv.tv_cb = tvp->tv_cb;
		tv.tv_arg = tvp->tv_arg;
		tv.tv_fp = basep->mci_fp;

		tv.tv_base_offset = off;
		tv.tv_base_depth = depth;
		tv.tv_min_depth = 1;	/* depth = 0 has already been done */

		ret = ctf_type_visit(basep->mci_fp, basep->mci_id,
		    type_cb, &tv);
	}
	return (ret);
}
Exemple #7
0
/*
 * This function takes a ctf id and determines whether or not the associated
 * type should be considered as a potential match for the given tab
 * completion command. We verify that the type itself is valid
 * for completion given the current context of the command, resolve
 * its actual name, and then pass it off to mdb_tab_insert to determine
 * if it's an actual match.
 */
static int
tab_complete_type(mdb_ctf_id_t id, void *arg)
{
	int rkind;
	char buf[MDB_SYM_NAMLEN];
	mdb_ctf_id_t rid;
	mdb_tab_cookie_t *mcp = arg;
	uint_t flags = (uint_t)(uintptr_t)mcp->mtc_cba;

	/*
	 * CTF data includes types that mdb commands don't understand. Before
	 * we resolve the actual type prune any entry that is a type we
	 * don't care about.
	 */
	switch (mdb_ctf_type_kind(id)) {
	case CTF_K_CONST:
	case CTF_K_RESTRICT:
	case CTF_K_VOLATILE:
		return (0);
	}

	if (mdb_ctf_type_resolve(id, &rid) != 0)
		return (1);

	rkind = mdb_ctf_type_kind(rid);

	if ((flags & MDB_TABC_MEMBERS) && rkind != CTF_K_STRUCT &&
	    rkind != CTF_K_UNION)
		return (0);

	if ((flags & MDB_TABC_NOPOINT) && rkind == CTF_K_POINTER)
		return (0);

	if ((flags & MDB_TABC_NOARRAY) && rkind == CTF_K_ARRAY)
		return (0);

	(void) mdb_ctf_type_name(id, buf, sizeof (buf));

	mdb_tab_insert(mcp, buf);
	return (0);
}
Exemple #8
0
int
mdb_ctf_member_iter(mdb_ctf_id_t id, mdb_ctf_member_f *cb, void *data)
{
	mdb_ctf_impl_t *idp = (mdb_ctf_impl_t *)&id;
	member_iter_t mi;
	int ret;

	/* resolve the type in case there's a forward declaration */
	if ((ret = mdb_ctf_type_resolve(id, &id)) != 0)
		return (ret);

	mi.mi_cb = cb;
	mi.mi_arg = data;
	mi.mi_fp = idp->mci_fp;

	ret = ctf_member_iter(idp->mci_fp, idp->mci_id, member_iter_cb, &mi);

	if (ret == CTF_ERR)
		return (set_errno(ctf_to_errno(ctf_errno(idp->mci_fp))));

	return (ret);
}
Exemple #9
0
ssize_t
mdb_ctf_offset_to_name(mdb_ctf_id_t id, ulong_t off, char *buf, size_t len,
    int dot, mdb_ctf_id_t *midp, ulong_t *moffp)
{
	size_t size;
	size_t n;
	mbr_contains_t mbc;

	if (!mdb_ctf_type_valid(id))
		return (set_errno(EINVAL));

	/*
	 * Quick sanity check to make sure the given offset is within
	 * this scope of this type.
	 */
	if (mdb_ctf_type_size(id) * NBBY <= off)
		return (set_errno(EINVAL));

	mbc.mbc_bufp = &buf;
	mbc.mbc_lenp = &len;
	mbc.mbc_offp = &off;
	mbc.mbc_idp = &id;
	mbc.mbc_total = 0;

	*buf = '\0';

	for (;;) {
		/*
		 * Check for an exact match.
		 */
		if (off == 0)
			break;

		(void) mdb_ctf_type_resolve(id, &id);

		/*
		 * Find the member that contains this offset.
		 */
		switch (mdb_ctf_type_kind(id)) {
		case CTF_K_ARRAY: {
			mdb_ctf_arinfo_t ar;
			uint_t index;

			(void) mdb_ctf_array_info(id, &ar);
			size = mdb_ctf_type_size(ar.mta_contents) * NBBY;
			index = off / size;

			id = ar.mta_contents;
			off %= size;

			n = mdb_snprintf(buf, len, "[%u]", index);
			mbc.mbc_total += n;
			if (n > len)
				n = len;

			buf += n;
			len -= n;
			break;
		}

		case CTF_K_STRUCT: {
			int ret;

			/*
			 * Find the member that contains this offset
			 * and continue.
			 */

			if (dot) {
				mbc.mbc_total++;
				if (len != 0) {
					*buf++ = '.';
					*buf = '\0';
					len--;
				}
			}

			ret = mdb_ctf_member_iter(id, offset_to_name_cb, &mbc);
			if (ret == -1)
				return (-1); /* errno is set for us */

			/*
			 * If we did not find a member containing this offset
			 * (due to holes in the structure), return EINVAL.
			 */
			if (ret == 0)
				return (set_errno(EINVAL));

			break;
		}

		case CTF_K_UNION:
			/*
			 * Treat unions like atomic entities since we can't
			 * do more than guess which member of the union
			 * might be the intended one.
			 */
			goto done;

		case CTF_K_INTEGER:
		case CTF_K_FLOAT:
		case CTF_K_POINTER:
		case CTF_K_ENUM:
			goto done;

		default:
			return (set_errno(EINVAL));
		}

		dot = 1;
	}
done:
	if (midp != NULL)
		*midp = id;
	if (moffp != NULL)
		*moffp = off;

	return (mbc.mbc_total);
}
Exemple #10
0
static int
vread_helper(mdb_ctf_id_t modid, char *modbuf,
    mdb_ctf_id_t tgtid, char *tgtbuf, uint_t flags)
{
	size_t modsz, tgtsz;
	int modkind, tgtkind;
	member_t mbr;
	int ret;
	mdb_ctf_arinfo_t tar, mar;
	int i;

	/*
	 * Resolve the types to their canonical form.
	 */
	(void) mdb_ctf_type_resolve(modid, &modid);
	(void) mdb_ctf_type_resolve(tgtid, &tgtid);

	if ((modkind = mdb_ctf_type_kind(modid)) == -1)
		return (-1); /* errno is set for us */
	if ((tgtkind = mdb_ctf_type_kind(tgtid)) == -1)
		return (-1); /* errno is set for us */

	if (tgtkind != modkind)
		return (set_errno(EMDB_INCOMPAT));

	switch (modkind) {
	case CTF_K_INTEGER:
	case CTF_K_FLOAT:
	case CTF_K_POINTER:
		if ((modsz = mdb_ctf_type_size(modid)) == -1UL)
			return (-1); /* errno is set for us */

		if ((tgtsz = mdb_ctf_type_size(tgtid)) == -1UL)
			return (-1); /* errno is set for us */

		/*
		 * If the sizes don't match we need to be tricky to make
		 * sure that the caller gets the correct data.
		 */
		if (modsz < tgtsz) {
			if (!(flags & MDB_CTF_VREAD_IGNORE_GROW))
				return (set_errno(EMDB_INCOMPAT));
#ifdef _BIG_ENDIAN
			bcopy(tgtbuf + tgtsz - modsz, modbuf, modsz);
#else
			bcopy(tgtbuf, modbuf, modsz);
#endif
		} else if (modsz > tgtsz) {
			bzero(modbuf, modsz);
#ifdef _BIG_ENDIAN
			bcopy(tgtbuf, modbuf + modsz - tgtsz, tgtsz);
#else
			bcopy(tgtbuf, modbuf, tgtsz);
#endif
		} else {
			bcopy(tgtbuf, modbuf, modsz);
		}

		return (0);

	case CTF_K_STRUCT:
		mbr.m_modbuf = modbuf;
		mbr.m_tgtbuf = tgtbuf;
		mbr.m_tgtid = tgtid;
		mbr.m_flags = flags;

		return (mdb_ctf_member_iter(modid, member_cb, &mbr));

	case CTF_K_UNION:

		/*
		 * Unions are a little tricky. The only time it's truly
		 * safe to read in a union is if no part of the union or
		 * any of its component types have changed. We allow the
		 * consumer to ignore unions. The correct use of this
		 * feature is to read the containing structure, figure
		 * out which component of the union is valid, compute
		 * the location of that in the target and then read in
		 * that part of the structure.
		 */
		if (flags & MDB_CTF_VREAD_IGNORE_UNIONS)
			return (0);

		if (!type_equals(modid, tgtid))
			return (set_errno(EMDB_INCOMPAT));

		modsz = mdb_ctf_type_size(modid);
		tgtsz = mdb_ctf_type_size(tgtid);

		ASSERT(modsz == tgtsz);

		bcopy(tgtbuf, modbuf, modsz);

		return (0);

	case CTF_K_ARRAY:
		if (mdb_ctf_array_info(tgtid, &tar) != 0)
			return (-1); /* errno is set for us */
		if (mdb_ctf_array_info(modid, &mar) != 0)
			return (-1); /* errno is set for us */

		if (tar.mta_nelems != mar.mta_nelems)
			return (set_errno(EMDB_INCOMPAT));

		if ((modsz = mdb_ctf_type_size(mar.mta_contents)) == -1UL)
			return (-1); /* errno is set for us */

		if ((tgtsz = mdb_ctf_type_size(tar.mta_contents)) == -1UL)
			return (-1); /* errno is set for us */

		for (i = 0; i < tar.mta_nelems; i++) {
			ret = vread_helper(mar.mta_contents, modbuf + i * modsz,
			    tar.mta_contents, tgtbuf + i * tgtsz, flags);

			if (ret != 0)
				return (ret);
		}

		return (0);
	}

	return (set_errno(EMDB_INCOMPAT));
}