diff options
author | Jason King <jason.king@joyent.com> | 2018-09-16 04:21:25 +0000 |
---|---|---|
committer | Jason King <jason.king@joyent.com> | 2018-11-27 21:37:31 +0000 |
commit | b118ac96296ecb7740c933bfe013b565a00b56c5 (patch) | |
tree | f3304a40debafc0fe589ab3ebdde7227d51b2d35 | |
parent | 6466dea896ec0283655f3eb5820688dd3a3e7ff2 (diff) | |
download | illumos-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.c | 58 | ||||
-rw-r--r-- | usr/src/cmd/mdb/common/mdb/mdb_print.c | 55 |
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 = "->"; |