summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJason King <jason.king@joyent.com>2018-09-16 04:21:25 +0000
committerJason King <jason.king@joyent.com>2018-11-27 21:37:31 +0000
commitb118ac96296ecb7740c933bfe013b565a00b56c5 (patch)
treef3304a40debafc0fe589ab3ebdde7227d51b2d35
parent6466dea896ec0283655f3eb5820688dd3a3e7ff2 (diff)
downloadillumos-joyent-mdb-union.tar.gz
OS-7345 Add support to mdb for anonymous/unnamed structs and unions.mdb-union
Reviewed by: Robert Mustacchi <rm@joyent.com> Reviewed by: Dan McDonald <danmcd@joyent.com> Approved by: Dan McDonald <danmcd@joyent.com>
-rw-r--r--usr/src/cmd/mdb/common/mdb/mdb_ctf.c58
-rw-r--r--usr/src/cmd/mdb/common/mdb/mdb_print.c55
2 files changed, 108 insertions, 5 deletions
diff --git a/usr/src/cmd/mdb/common/mdb/mdb_ctf.c b/usr/src/cmd/mdb/common/mdb/mdb_ctf.c
index 534c92f5dc..4e8f1a161f 100644
--- a/usr/src/cmd/mdb/common/mdb/mdb_ctf.c
+++ b/usr/src/cmd/mdb/common/mdb/mdb_ctf.c
@@ -838,6 +838,7 @@ static int
member_info_cb(const char *name, mdb_ctf_id_t id, ulong_t off, void *data)
{
mbr_info_t *mbrp = data;
+ int kind, ret;
if (strcmp(name, mbrp->mbr_member) == 0) {
if (mbrp->mbr_offp != NULL)
@@ -848,7 +849,46 @@ member_info_cb(const char *name, mdb_ctf_id_t id, ulong_t off, void *data)
return (1);
}
- return (0);
+ /*
+ * C11 as well as earlier GNU extensions allow an embedded struct
+ * or union to be unnamed as long as there are no unambiguous member
+ * names. If we encounter a SOU member with a 0-length name,
+ * recurse into it and see if any of them match.
+ */
+ if (strlen(name) != 0)
+ return (0);
+
+ kind = mdb_ctf_type_kind(id);
+ if (kind == CTF_ERR)
+ return (-1);
+ if (kind != CTF_K_STRUCT && kind != CTF_K_UNION)
+ return (0);
+
+ /*
+ * Search the unnamed SOU for mbrp->mbr_member, possibly recursing if
+ * it also contains unnamed members. If the desired member is found.
+ * *mbrp->mbr_offp will contain the offset of the member relative to
+ * this unnamed SOU (if the offset was requested) -- i.e.
+ * we effectively have *mbrp->mbr_offp == offsetof("", member). We want
+ * unnamed SOUs to act as members of the enclosing SOUs, so we need to
+ * return the offset as relative to the outer SOU. Since 'off' is
+ * the offset of the unnamed SOU relative to the enclosing SOU (i.e.
+ * off == offsetof(outer, "")), we add the two together to produce the
+ * desired offset. This can recurse as necessary -- the compiler
+ * prevents any ambiguities from occurring (or else it wouldn't be
+ * able to compile the code), and the result will be relative to
+ * the start of the SOU given in the mdb_ctf_member_info() call.
+ */
+ ret = mdb_ctf_member_iter(id, member_info_cb, mbrp);
+ if (ret == -1)
+ return (-1);
+ if (ret == 0)
+ return (0);
+
+ if (mbrp->mbr_offp != NULL)
+ *(mbrp->mbr_offp) += off;
+
+ return (1);
}
int
@@ -856,10 +896,21 @@ mdb_ctf_member_info(mdb_ctf_id_t id, const char *member, ulong_t *offp,
mdb_ctf_id_t *typep)
{
mbr_info_t mbr;
+ /*
+ * We want the resulting offset (if requested -- offp != NULL) to
+ * be relative to the start of _this_ SOU. If we have to search any
+ * embedded unnamed SOUs, instead of merely assigning the resulting
+ * offset value to mbr_offp, we will have to add the offsets of
+ * any nested SOUs along the way (see comments in member_info_cb()).
+ * Therefore, initialize off to 0 here so we do not need to worry about
+ * recursion depth in member_info_cb (otherwise we would need to set
+ * mbr_offp when depth = 1, and add when depth > 1).
+ */
+ ulong_t off = 0;
int rc;
mbr.mbr_member = member;
- mbr.mbr_offp = offp;
+ mbr.mbr_offp = &off;
mbr.mbr_typep = typep;
rc = mdb_ctf_member_iter(id, member_info_cb, &mbr);
@@ -872,6 +923,9 @@ mdb_ctf_member_info(mdb_ctf_id_t id, const char *member, ulong_t *offp,
if (rc == 0)
return (set_errno(EMDB_CTFNOMEMB));
+ if (offp != NULL)
+ *offp = off;
+
return (0);
}
diff --git a/usr/src/cmd/mdb/common/mdb/mdb_print.c b/usr/src/cmd/mdb/common/mdb/mdb_print.c
index fe74265b68..e91bf7a2fc 100644
--- a/usr/src/cmd/mdb/common/mdb/mdb_print.c
+++ b/usr/src/cmd/mdb/common/mdb/mdb_print.c
@@ -25,7 +25,7 @@
/*
* Copyright (c) 2012, 2014 by Delphix. All rights reserved.
- * Copyright 2015 Joyent, Inc.
+ * Copyright 2018 Joyent, Inc.
* Copyright (c) 2014 Nexenta Systems, Inc. All rights reserved.
*/
@@ -1681,6 +1681,52 @@ elt_print(const char *name, mdb_ctf_id_t id, mdb_ctf_id_t base,
mdb_printf("%s%s", pap->pa_prefix,
(depth == 0) ? "" : pap->pa_suffix);
mdb_printf("%s", name);
+
+ /*
+ * When no name is present (i.e. an unnamed struct or union),
+ * display '(anon)' instead only when no prefix is present.
+ * When printing out a struct or union (sou), prefixes are
+ * only present (i.e. !NULL or non-empty) when printing
+ * individual members of that sou, e.g.
+ * `::print struct foo f_member`. When printing an entire sou,
+ * the prefix will be NULL or empty. We end up with:
+ *
+ * > ::print struct foo
+ * {
+ * ...
+ * f_member = 0xabcd
+ * (anon) = {
+ * anon_member = 0x1234
+ * ....
+ * }
+ * ...
+ * }
+ *
+ * and
+ *
+ * > ::print struct foo anon_member
+ * anon_member = 0x1234
+ *
+ * instead of:
+ *
+ * > ::print struct foo
+ * {
+ * ...
+ * f_member = 0xabcd
+ * = {
+ * anon_member = 0x1234
+ * }
+ * ...
+ * }
+ *
+ * and
+ *
+ * > ::print struct foo anon_member
+ * anon_member(anon) = 0x1234
+ */
+ if (depth > 0 && strlen(name) == 0 &&
+ (pap->pa_prefix == NULL || strlen(pap->pa_prefix) == 0))
+ mdb_printf("(anon)");
}
if ((pap->pa_flags & PA_SHOWTYPE) && kind == CTF_K_INTEGER) {
@@ -1699,8 +1745,9 @@ elt_print(const char *name, mdb_ctf_id_t id, mdb_ctf_id_t base,
}
if (depth != 0 ||
- ((pap->pa_flags & PA_SHOWNAME) && pap->pa_prefix != NULL))
+ ((pap->pa_flags & PA_SHOWNAME) && pap->pa_prefix != NULL)) {
mdb_printf("%s ", pap->pa_flags & PA_SHOWVAL ? " =" : "");
+ }
if (depth == 0 && pap->pa_prefix != NULL)
name = pap->pa_prefix;
@@ -2420,8 +2467,10 @@ cmd_print(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv)
kind = mdb_ctf_type_kind(rid);
if (last_deref && IS_SOU(kind)) {
char *end;
+ size_t len = strlen(member);
(void) mdb_snprintf(buf, sizeof (buf),
- "%s", member);
+ "%s", (len == 0) ?
+ "<anon>" : member);
end = strrchr(buf, '[');
*end = '\0';
pa.pa_suffix = "->";