Print this page
11584 ::xcall would be useful
Reviewed by: Jerry Jelinek <jerry.jelinek@joyent.com>
Reviewed by: Robert Mustacchi <rm@joyent.com>


   7  *
   8  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
   9  * or http://www.opensolaris.org/os/licensing.
  10  * See the License for the specific language governing permissions
  11  * and limitations under the License.
  12  *
  13  * When distributing Covered Code, include this CDDL HEADER in each
  14  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
  15  * If applicable, add the following below this CDDL HEADER, with the
  16  * fields enclosed by brackets "[]" replaced with your own identifying
  17  * information: Portions Copyright [yyyy] [name of copyright owner]
  18  *
  19  * CDDL HEADER END
  20  */
  21 /*
  22  * Copyright 2009 Sun Microsystems, Inc.  All rights reserved.
  23  * Use is subject to license terms.
  24  */
  25 /*
  26  * Copyright (c) 2013, 2016 by Delphix. All rights reserved.
  27  * Copyright (c) 2015, Joyent, Inc.  All rights reserved.
  28  */
  29 
  30 #include <mdb/mdb_ctf.h>
  31 #include <mdb/mdb_ctf_impl.h>
  32 #include <mdb/mdb_err.h>
  33 #include <mdb/mdb_modapi.h>
  34 #include <mdb/mdb_string.h>
  35 #include <mdb/mdb.h>
  36 #include <mdb/mdb_debug.h>
  37 
  38 #include <libctf.h>
  39 #include <string.h>
  40 #include <limits.h>
  41 
  42 typedef struct tnarg {
  43         mdb_tgt_t *tn_tgt;              /* target to use for lookup */
  44         const char *tn_name;            /* query string to lookup */
  45         ctf_file_t *tn_fp;              /* CTF container from match */
  46         ctf_id_t tn_id;                 /* CTF type ID from match */
  47 } tnarg_t;


1219         uint_t          m_flags;
1220 } member_t;
1221 
1222 static int vread_helper(mdb_ctf_id_t, char *, mdb_ctf_id_t, char *,
1223     const char *, uint_t);
1224 
1225 static int
1226 member_cb(const char *name, mdb_ctf_id_t modmid, ulong_t modoff, void *data)
1227 {
1228         member_t *mp = data;
1229         char *modbuf = mp->m_modbuf;
1230         mdb_ctf_id_t tgtmid;
1231         char *tgtbuf = mp->m_tgtbuf;
1232         ulong_t tgtoff;
1233         char tgtname[128];
1234 
1235         (void) mdb_snprintf(tgtname, sizeof (tgtname),
1236             "member %s of type %s", name, mp->m_tgtname);
1237 
1238         if (mdb_ctf_member_info(mp->m_tgtid, name, &tgtoff, &tgtmid) != 0) {
1239                 mdb_ctf_warn(mp->m_flags,
1240                     "could not find %s\n", tgtname);

1241                 return (set_errno(EMDB_CTFNOMEMB));
1242         }
1243 
1244         return (vread_helper(modmid, modbuf + modoff / NBBY,
1245             tgtmid, tgtbuf + tgtoff / NBBY, tgtname, mp->m_flags));
1246 }
1247 
1248 typedef struct enum_value {
1249         int             *ev_modbuf;
1250         const char      *ev_name;
1251 } enum_value_t;
1252 
1253 static int
1254 enum_cb(const char *name, int value, void *data)
1255 {
1256         enum_value_t *ev = data;
1257 
1258         if (strcmp(name, ev->ev_name) == 0) {
1259                 *ev->ev_modbuf = value;
1260                 return (1);


1595  *         int io_error;
1596  * } mdb_zio_t;
1597  *
1598  * mdb_zio_t zio;
1599  * error = mdb_ctf_vread(&zio, "zio_t", "mdb_zio_t", zio_target_addr, 0);
1600  *
1601  * If a given MDB module has different dcmds or walkers that need to read
1602  * different members from the same struct, then different "mdb_" types
1603  * should be declared for each caller.  By convention, these types should
1604  * be named "mdb_<dcmd or walker>_<type>", e.g. mdb_findstack_kthread_t
1605  * for ::findstack.  If the MDB module is compiled from several source files,
1606  * one must be especially careful to not define different types with the
1607  * same name in different source files, because the compiler can not detect
1608  * this error.
1609  *
1610  * Enums will also be translated by name, so the mdb module will receive
1611  * the enum value it expects even if the target has renumbered the enum.
1612  * Warning: it will therefore only work with enums are only used to store
1613  * legitimate enum values (not several values or-ed together).
1614  *
1615  * By default, if mdb_ctf_vread() can not find any members or enum values,
1616  * it will print a descriptive message (with mdb_warn()) and fail.
1617  * Passing MDB_CTF_VREAD_QUIET in 'flags' will suppress the warning message.
1618  * Additional flags can be used to ignore specific types of translation
1619  * failure, but should be used with caution, because they will silently leave
1620  * the caller's buffer uninitialized.
1621  */
1622 int
1623 mdb_ctf_vread(void *modbuf, const char *target_typename,
1624     const char *mdb_typename, uintptr_t addr, uint_t flags)
1625 {
1626         ctf_file_t *mfp;
1627         ctf_id_t mid;
1628         void *tgtbuf;
1629         size_t size;
1630         mdb_ctf_id_t tgtid;
1631         mdb_ctf_id_t modid;
1632         mdb_module_t *mod;

1633 
1634         if ((mod = mdb_get_module()) == NULL || (mfp = mod->mod_ctfp) == NULL) {
1635                 mdb_ctf_warn(flags, "no ctf data found for mdb module %s\n",
1636                     mod->mod_name);
1637                 return (set_errno(EMDB_NOCTF));
1638         }
1639 
1640         if ((mid = ctf_lookup_by_name(mfp, mdb_typename)) == CTF_ERR) {
1641                 mdb_ctf_warn(flags, "couldn't find ctf data for "
1642                     "type %s in mdb module %s\n",
1643                     mdb_typename, mod->mod_name);
1644                 return (set_errno(ctf_to_errno(ctf_errno(mfp))));
1645         }
1646 
1647         set_ctf_id(&modid, mfp, mid);
1648 
1649         if (mdb_ctf_lookup_by_name(target_typename, &tgtid) != 0) {
1650                 mdb_ctf_warn(flags,
1651                     "couldn't find type %s in target's ctf data\n",
1652                     target_typename);
1653                 return (set_errno(EMDB_NOCTF));
1654         }
1655 
1656         /*
1657          * Read the data out of the target's address space.
1658          */
1659         if ((size = mdb_ctf_type_size(tgtid)) == -1UL) {
1660                 mdb_ctf_warn(flags, "couldn't determine size of type %s\n",
1661                     target_typename);
1662                 return (-1); /* errno is set for us */
1663         }
1664 
1665         tgtbuf = mdb_alloc(size, UM_SLEEP | UM_GC);
1666 
1667         if (mdb_vread(tgtbuf, size, addr) < 0) {
1668                 mdb_ctf_warn(flags, "couldn't read %s from %p\n",
1669                     target_typename, addr);

1670                 return (-1); /* errno is set for us */
1671         }
1672 
1673         return (vread_helper(modid, modbuf, tgtid, tgtbuf, NULL, flags));




1674 }
1675 
1676 /*
1677  * Note: mdb_ctf_readsym() doesn't take separate parameters for the name
1678  * of the target's type vs the mdb module's type.  Use with complicated
1679  * types (e.g. structs) may result in unnecessary failure if a member of
1680  * the struct has been changed in the target, but is not actually needed
1681  * by the mdb module.  Use mdb_lookup_by_name() + mdb_ctf_vread() to
1682  * avoid this problem.
1683  */
1684 int
1685 mdb_ctf_readsym(void *buf, const char *typename, const char *name, uint_t flags)
1686 {
1687         GElf_Sym sym;
1688 
1689         if (mdb_lookup_by_obj(MDB_TGT_OBJ_EVERY, name, &sym) != 0) {
1690                 mdb_ctf_warn(flags, "couldn't find symbol %s\n", name);
1691                 return (-1); /* errno is set for us */
1692         }
1693 




   7  *
   8  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
   9  * or http://www.opensolaris.org/os/licensing.
  10  * See the License for the specific language governing permissions
  11  * and limitations under the License.
  12  *
  13  * When distributing Covered Code, include this CDDL HEADER in each
  14  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
  15  * If applicable, add the following below this CDDL HEADER, with the
  16  * fields enclosed by brackets "[]" replaced with your own identifying
  17  * information: Portions Copyright [yyyy] [name of copyright owner]
  18  *
  19  * CDDL HEADER END
  20  */
  21 /*
  22  * Copyright 2009 Sun Microsystems, Inc.  All rights reserved.
  23  * Use is subject to license terms.
  24  */
  25 /*
  26  * Copyright (c) 2013, 2016 by Delphix. All rights reserved.
  27  * Copyright (c) 2018, Joyent, Inc.
  28  */
  29 
  30 #include <mdb/mdb_ctf.h>
  31 #include <mdb/mdb_ctf_impl.h>
  32 #include <mdb/mdb_err.h>
  33 #include <mdb/mdb_modapi.h>
  34 #include <mdb/mdb_string.h>
  35 #include <mdb/mdb.h>
  36 #include <mdb/mdb_debug.h>
  37 
  38 #include <libctf.h>
  39 #include <string.h>
  40 #include <limits.h>
  41 
  42 typedef struct tnarg {
  43         mdb_tgt_t *tn_tgt;              /* target to use for lookup */
  44         const char *tn_name;            /* query string to lookup */
  45         ctf_file_t *tn_fp;              /* CTF container from match */
  46         ctf_id_t tn_id;                 /* CTF type ID from match */
  47 } tnarg_t;


1219         uint_t          m_flags;
1220 } member_t;
1221 
1222 static int vread_helper(mdb_ctf_id_t, char *, mdb_ctf_id_t, char *,
1223     const char *, uint_t);
1224 
1225 static int
1226 member_cb(const char *name, mdb_ctf_id_t modmid, ulong_t modoff, void *data)
1227 {
1228         member_t *mp = data;
1229         char *modbuf = mp->m_modbuf;
1230         mdb_ctf_id_t tgtmid;
1231         char *tgtbuf = mp->m_tgtbuf;
1232         ulong_t tgtoff;
1233         char tgtname[128];
1234 
1235         (void) mdb_snprintf(tgtname, sizeof (tgtname),
1236             "member %s of type %s", name, mp->m_tgtname);
1237 
1238         if (mdb_ctf_member_info(mp->m_tgtid, name, &tgtoff, &tgtmid) != 0) {
1239                 if (mp->m_flags & MDB_CTF_VREAD_IGNORE_ABSENT)
1240                         return (0);
1241                 mdb_ctf_warn(mp->m_flags, "could not find %s\n", tgtname);
1242                 return (set_errno(EMDB_CTFNOMEMB));
1243         }
1244 
1245         return (vread_helper(modmid, modbuf + modoff / NBBY,
1246             tgtmid, tgtbuf + tgtoff / NBBY, tgtname, mp->m_flags));
1247 }
1248 
1249 typedef struct enum_value {
1250         int             *ev_modbuf;
1251         const char      *ev_name;
1252 } enum_value_t;
1253 
1254 static int
1255 enum_cb(const char *name, int value, void *data)
1256 {
1257         enum_value_t *ev = data;
1258 
1259         if (strcmp(name, ev->ev_name) == 0) {
1260                 *ev->ev_modbuf = value;
1261                 return (1);


1596  *         int io_error;
1597  * } mdb_zio_t;
1598  *
1599  * mdb_zio_t zio;
1600  * error = mdb_ctf_vread(&zio, "zio_t", "mdb_zio_t", zio_target_addr, 0);
1601  *
1602  * If a given MDB module has different dcmds or walkers that need to read
1603  * different members from the same struct, then different "mdb_" types
1604  * should be declared for each caller.  By convention, these types should
1605  * be named "mdb_<dcmd or walker>_<type>", e.g. mdb_findstack_kthread_t
1606  * for ::findstack.  If the MDB module is compiled from several source files,
1607  * one must be especially careful to not define different types with the
1608  * same name in different source files, because the compiler can not detect
1609  * this error.
1610  *
1611  * Enums will also be translated by name, so the mdb module will receive
1612  * the enum value it expects even if the target has renumbered the enum.
1613  * Warning: it will therefore only work with enums are only used to store
1614  * legitimate enum values (not several values or-ed together).
1615  *
1616  * Flags values:
1617  *
1618  * MDB_CTF_VREAD_QUIET: keep quiet about failures
1619  * MDB_CTF_VREAD_IGNORE_ABSENT: ignore any member that couldn't be found in the
1620  * target struct; be careful not to use an uninitialized result.

1621  */
1622 int
1623 mdb_ctf_vread(void *modbuf, const char *target_typename,
1624     const char *mdb_typename, uintptr_t addr, uint_t flags)
1625 {
1626         ctf_file_t *mfp;
1627         ctf_id_t mid;
1628         void *tgtbuf;
1629         size_t size;
1630         mdb_ctf_id_t tgtid;
1631         mdb_ctf_id_t modid;
1632         mdb_module_t *mod;
1633         int ret;
1634 
1635         if ((mod = mdb_get_module()) == NULL || (mfp = mod->mod_ctfp) == NULL) {
1636                 mdb_ctf_warn(flags, "no ctf data found for mdb module %s\n",
1637                     mod->mod_name);
1638                 return (set_errno(EMDB_NOCTF));
1639         }
1640 
1641         if ((mid = ctf_lookup_by_name(mfp, mdb_typename)) == CTF_ERR) {
1642                 mdb_ctf_warn(flags, "couldn't find ctf data for "
1643                     "type %s in mdb module %s\n",
1644                     mdb_typename, mod->mod_name);
1645                 return (set_errno(ctf_to_errno(ctf_errno(mfp))));
1646         }
1647 
1648         set_ctf_id(&modid, mfp, mid);
1649 
1650         if (mdb_ctf_lookup_by_name(target_typename, &tgtid) != 0) {
1651                 mdb_ctf_warn(flags,
1652                     "couldn't find type %s in target's ctf data\n",
1653                     target_typename);
1654                 return (set_errno(EMDB_NOCTF));
1655         }
1656 
1657         /*
1658          * Read the data out of the target's address space.
1659          */
1660         if ((size = mdb_ctf_type_size(tgtid)) == -1UL) {
1661                 mdb_ctf_warn(flags, "couldn't determine size of type %s\n",
1662                     target_typename);
1663                 return (-1); /* errno is set for us */
1664         }
1665 
1666         tgtbuf = mdb_alloc(size, UM_SLEEP);
1667 
1668         if (mdb_vread(tgtbuf, size, addr) < 0) {
1669                 mdb_ctf_warn(flags, "couldn't read %s from %p\n",
1670                     target_typename, addr);
1671                 mdb_free(tgtbuf, size);
1672                 return (-1); /* errno is set for us */
1673         }
1674 
1675         ret = vread_helper(modid, modbuf, tgtid, tgtbuf, NULL, flags);
1676 
1677         mdb_free(tgtbuf, size);
1678 
1679         return (ret);
1680 }
1681 
1682 /*
1683  * Note: mdb_ctf_readsym() doesn't take separate parameters for the name
1684  * of the target's type vs the mdb module's type.  Use with complicated
1685  * types (e.g. structs) may result in unnecessary failure if a member of
1686  * the struct has been changed in the target, but is not actually needed
1687  * by the mdb module.  Use mdb_lookup_by_name() + mdb_ctf_vread() to
1688  * avoid this problem.
1689  */
1690 int
1691 mdb_ctf_readsym(void *buf, const char *typename, const char *name, uint_t flags)
1692 {
1693         GElf_Sym sym;
1694 
1695         if (mdb_lookup_by_obj(MDB_TGT_OBJ_EVERY, name, &sym) != 0) {
1696                 mdb_ctf_warn(flags, "couldn't find symbol %s\n", name);
1697                 return (-1); /* errno is set for us */
1698         }
1699