diff options
author | Jason King <jason.king@joyent.com> | 2020-12-23 19:05:24 -0600 |
---|---|---|
committer | Jason King <jason.king@joyent.com> | 2021-03-10 01:27:46 -0600 |
commit | 089ef9c1879ed031043f7bb75bd1f472558dcbbf (patch) | |
tree | 40be54981374faff4bced71d96db8951ba2e31d4 | |
parent | f6c47fdeea63a9c5d1abefdffb93d3f87e12b7d0 (diff) | |
download | illumos-joyent-089ef9c1879ed031043f7bb75bd1f472558dcbbf.tar.gz |
13576 Add mdb ::linkerset command
Reviewed by: Richard Lowe <richlowe@richlowe.net>
Reviewed by: Toomas Soome <tsoome@me.com>
Approved by: Dan McDonald <danmcd@joyent.com>
-rw-r--r-- | usr/src/cmd/mdb/Makefile.kmdb.files | 8 | ||||
-rw-r--r-- | usr/src/cmd/mdb/Makefile.mdb | 4 | ||||
-rw-r--r-- | usr/src/cmd/mdb/common/mdb/mdb.c | 9 | ||||
-rw-r--r-- | usr/src/cmd/mdb/common/mdb/mdb_cmds.c | 5 | ||||
-rw-r--r-- | usr/src/cmd/mdb/common/mdb/mdb_linkerset.c | 500 | ||||
-rw-r--r-- | usr/src/cmd/mdb/common/mdb/mdb_linkerset.h | 42 | ||||
-rw-r--r-- | usr/src/cmd/mdb/common/mdb/mdb_walkers.c | 24 |
7 files changed, 585 insertions, 7 deletions
diff --git a/usr/src/cmd/mdb/Makefile.kmdb.files b/usr/src/cmd/mdb/Makefile.kmdb.files index ca10ca72a1..caf3050fee 100644 --- a/usr/src/cmd/mdb/Makefile.kmdb.files +++ b/usr/src/cmd/mdb/Makefile.kmdb.files @@ -25,7 +25,7 @@ # # Copyright (c) 2012 by Delphix. All rights reserved. -# Copyright (c) 2018 Joyent, Inc. All rights reserved. +# Copyright 2021 Joyent, Inc. # KMDBSRCS += \ @@ -60,6 +60,7 @@ KMDBSRCS += \ kmdb_kdi.c \ kmdb_kvm.c \ mdb_logio.c \ + mdb_linkerset.c \ mdb_list.c \ mdb_macalias.c \ kmdb_main.c \ @@ -88,6 +89,7 @@ KMDBSRCS += \ kmdb_umemglue.c \ mdb_value.c \ mdb_vcb.c \ + mdb_walkers.c \ mdb_wcb.c \ mdb_whatis.c \ kmdb_wr.c @@ -96,7 +98,7 @@ KMDBML += KMDBOBJS = $(KMDBSRCS:%.c=%.o) $(KMDBML:%.s=%.o) -PROMSRCS += +PROMSRCS += PROMOBJS = $(PROMSRCS:%.c=%.o) @@ -109,7 +111,7 @@ KCTLSRCS += \ kctl_string.c \ kctl_wr.c -KCTLML += +KCTLML += KCTLOBJS = $(KCTLSRCS:%.c=%.o) $(KCTLML:%.s=%.o) diff --git a/usr/src/cmd/mdb/Makefile.mdb b/usr/src/cmd/mdb/Makefile.mdb index 5eb6f4e977..5772bed1fd 100644 --- a/usr/src/cmd/mdb/Makefile.mdb +++ b/usr/src/cmd/mdb/Makefile.mdb @@ -26,7 +26,7 @@ # # Copyright 2011 Nexenta Systems, Inc. All rights reserved. # Copyright (c) 2012 by Delphix. All rights reserved. -# Copyright 2019 Joyent, Inc. +# Copyright 2021 Joyent, Inc. # Copyright 2018 Jason King # @@ -61,6 +61,7 @@ SRCS += \ mdb_kb_kvm.c \ mdb_kproc.c \ mdb_kvm.c \ + mdb_linkerset.c \ mdb_logio.c \ mdb_list.c \ mdb_macalias.c \ @@ -90,6 +91,7 @@ SRCS += \ mdb_umem.c \ mdb_value.c \ mdb_vcb.c \ + mdb_walkers.c \ mdb_wcb.c \ mdb_whatis.c diff --git a/usr/src/cmd/mdb/common/mdb/mdb.c b/usr/src/cmd/mdb/common/mdb/mdb.c index eb6b46083f..aafca64f3a 100644 --- a/usr/src/cmd/mdb/common/mdb/mdb.c +++ b/usr/src/cmd/mdb/common/mdb/mdb.c @@ -24,7 +24,7 @@ */ /* * Copyright (c) 2012 by Delphix. All rights reserved. - * Copyright (c) 2018, Joyent, Inc. + * Copyright 2021 Joyent, Inc. */ /* @@ -83,6 +83,7 @@ #define DCMD_ABORTED(x) ((x) == DCMD_USAGE || (x) == DCMD_ABORT) extern const mdb_dcmd_t mdb_dcmd_builtins[]; +extern const mdb_walker_t mdb_walker_builtins[]; extern mdb_dis_ctor_f *const mdb_dis_builtins[]; /* @@ -461,6 +462,7 @@ mdb_create(const char *execname, const char *arg0) static char rootdir[MAXPATHLEN]; const mdb_dcmd_t *dcp; + const mdb_walker_t *wcp; int i; bzero(&mdb, sizeof (mdb_t)); @@ -503,7 +505,7 @@ mdb_create(const char *execname, const char *arg0) mdb.m_rminfo.mi_dvers = MDB_API_VERSION; mdb.m_rminfo.mi_dcmds = mdb_dcmd_builtins; - mdb.m_rminfo.mi_walkers = NULL; + mdb.m_rminfo.mi_walkers = mdb_walker_builtins; (void) mdb_nv_create(&mdb.m_rmod.mod_walkers, UM_SLEEP); (void) mdb_nv_create(&mdb.m_rmod.mod_dcmds, UM_SLEEP); @@ -545,6 +547,9 @@ mdb_create(const char *execname, const char *arg0) for (dcp = &mdb_dcmd_builtins[0]; dcp->dc_name != NULL; dcp++) (void) mdb_module_add_dcmd(&mdb.m_rmod, dcp, 0); + for (wcp = &mdb_walker_builtins[0]; wcp->walk_name != NULL; wcp++) + (void) mdb_module_add_walker(&mdb.m_rmod, wcp, 0); + for (i = 0; mdb_dis_builtins[i] != NULL; i++) (void) mdb_dis_create(mdb_dis_builtins[i]); diff --git a/usr/src/cmd/mdb/common/mdb/mdb_cmds.c b/usr/src/cmd/mdb/common/mdb/mdb_cmds.c index 10c622443a..616f69e954 100644 --- a/usr/src/cmd/mdb/common/mdb/mdb_cmds.c +++ b/usr/src/cmd/mdb/common/mdb/mdb_cmds.c @@ -26,7 +26,7 @@ /* * Copyright (c) 2012 by Delphix. All rights reserved. - * Copyright (c) 2019 Joyent, Inc. All rights reserved. + * Copyright 2021 Joyent, Inc. * Copyright (c) 2013 Josef 'Jeff' Sipek <jeffpc@josefsipek.net> * Copyright (c) 2015, 2017 by Delphix. All rights reserved. * Copyright 2018 OmniOS Community Edition (OmniOSce) Association. @@ -71,6 +71,7 @@ #include <mdb/mdb_macalias.h> #include <mdb/mdb_tab.h> #include <mdb/mdb_typedef.h> +#include <mdb/mdb_linkerset.h> #ifdef _KMDB #include <kmdb/kmdb_kdi.h> #endif @@ -3130,6 +3131,8 @@ const mdb_dcmd_t mdb_dcmd_builtins[] = { head_help }, { "help", "[cmd]", "list commands/command help", cmd_help, NULL, cmd_help_tab }, + { "linkerset", "[name]", "display linkersets", cmd_linkerset, + linkerset_help, cmd_linkerset_tab }, { "list", "?type member [variable]", "walk list using member as link pointer", cmd_list, NULL, mdb_tab_complete_mt }, diff --git a/usr/src/cmd/mdb/common/mdb/mdb_linkerset.c b/usr/src/cmd/mdb/common/mdb/mdb_linkerset.c new file mode 100644 index 0000000000..771f8f1b95 --- /dev/null +++ b/usr/src/cmd/mdb/common/mdb/mdb_linkerset.c @@ -0,0 +1,500 @@ +/* + * This file and its contents are supplied under the terms of the + * Common Development and Distribution License ("CDDL"), version 1.0. + * You may only use this file in accordance with the terms of version + * 1.0 of the CDDL. + * + * A full copy of the text of the CDDL should have accompanied this + * source. A copy of the CDDL is also available via the Internet at + * http://www.illumos.org/license/CDDL. + */ + +/* + * Copyright 2021 Joyent, Inc. + */ + +#include <mdb/mdb_debug.h> +#include <mdb/mdb_errno.h> +#include <mdb/mdb_modapi.h> +#include <mdb/mdb_err.h> +#include <mdb/mdb_ctf.h> +#include <mdb/mdb_ctf_impl.h> +#include <mdb/mdb_target_impl.h> +#include <mdb/mdb.h> +#include <sys/errno.h> +#include <string.h> + +/* + * A linker set is an array of pointers. The start of the set will have a + * weak symbol of the form START_PREFIX + name that will have the address + * of the first element (pointer) and another weak symbol that points just + * past the end of the final element. E.g. for a linker set 'foo', the + * first element will have a symbol __start_set_foo, and all __stop_set_foo + * will have the address just after the last element (e.g. &(last_element + 1)) + */ +#define START_PREFIX "__start_set_" +#define STOP_PREFIX "__stop_set_" + +/* + * The pointers that comprise the linker set have names that follow + * the pattern __set_<setname>_sym_<objname>. + */ +#define SYM_PREFIX "__set_" +#define SYM_DELIM "_sym_" + +typedef struct ldset_info { + char ldsi_name[MDB_SYM_NAMLEN]; + uintptr_t ldsi_addr; + uintptr_t ldsi_endaddr; + size_t ldsi_ptrsize; + size_t ldsi_nelem; + ssize_t ldsi_elsize; +} ldset_info_t; + +/* + * Similar to ldset_name_from_start(), except that it uses a linker set item + * name (e.g. '__set_foo_set_sym_foo_item') and writes the set name ('foo_set') + * into buf. + */ +static int +ldset_name_from_item(const char *item_name, char *buf, size_t buflen) +{ + const char *startp; + const char *endp; + size_t setname_len; + + /* The item name must start with '__sym_' */ + if (strncmp(item_name, SYM_PREFIX, sizeof (SYM_PREFIX) - 1) != 0) { + return (set_errno(EINVAL)); + } + startp = item_name + sizeof (SYM_PREFIX) - 1; + + /* The item name must have stuff after '__sym_' */ + if (*startp == '\0') { + return (set_errno(EINVAL)); + } + + /* Find the start of '_sym_' after the prefix */ + endp = strstr(startp, SYM_DELIM); + if (endp == NULL) { + /* '_sym_' not in the name, not a valid item name */ + return (set_errno(EINVAL)); + } + + setname_len = (size_t)(endp - startp); + if (setname_len + 1 > buflen) { + return (set_errno(ENAMETOOLONG)); + } + + /* + * We've verified buf has enough room for the linker set name + NUL. + * For sanity, we guarantee any trailing bytes in buf are zero, and + * use strncpy() so we copy only the bytes from item_name that are + * a part of the linker set name. The result should always be NUL + * terminated as a result. + */ + (void) memset(buf, '\0', buflen); + (void) strncpy(buf, item_name + sizeof (SYM_PREFIX) - 1, setname_len); + + return (0); +} + +static int +ldset_get_sym(const char *prefix, const char *name, GElf_Sym *sym) +{ + char symname[MDB_SYM_NAMLEN] = { 0 }; + + if (mdb_snprintf(symname, sizeof (symname), "%s%s", prefix, name) > + sizeof (symname) - 1) { + return (set_errno(ENAMETOOLONG)); + } + + return (mdb_tgt_lookup_by_name(mdb.m_target, MDB_TGT_OBJ_EVERY, symname, + sym, NULL)); +} + +/* + * Given the address of a pointer in a linker set, return the address of the + * item in the set in *addrp. + */ +static int +ldset_get_entry(uintptr_t addr, uintptr_t *addrp, size_t ptrsize) +{ + union { + uint64_t u64; + uint32_t u32; + } val; + ssize_t n; + + switch (ptrsize) { + case sizeof (uint32_t): + n = mdb_vread(&val.u32, sizeof (uint32_t), addr); + *addrp = (uintptr_t)val.u32; + break; + case sizeof (uint64_t): + n = mdb_vread(&val.u64, sizeof (uint64_t), addr); + *addrp = (uintptr_t)val.u64; + break; + default: + return (set_errno(ENOTSUP)); + } + + if (n != ptrsize) { + /* XXX: Better error value? */ + return (set_errno(ENODATA)); + } + + return (0); +} + +static ssize_t +ldset_item_size(uintptr_t addr) +{ + mdb_ctf_id_t id; + int ret; + + ret = mdb_ctf_lookup_by_addr(addr, &id); + if (ret != 0) { + return ((ssize_t)ret); + } + + return (mdb_ctf_type_size(id)); +} + +static int +ldset_get_info(uintptr_t addr, ldset_info_t *ldsi) +{ + GElf_Sym start_sym = { 0 }; + GElf_Sym stop_sym = { 0 }; + char name[MDB_SYM_NAMLEN] = { 0 }; + uintptr_t item_addr; + int ret; + + switch (mdb_tgt_dmodel(mdb.m_target)) { + case MDB_TGT_MODEL_LP64: + ldsi->ldsi_ptrsize = sizeof (uint64_t); + break; + case MDB_TGT_MODEL_ILP32: + ldsi->ldsi_ptrsize = sizeof (uint32_t); + break; + default: + return (set_errno(ENOTSUP)); + } + + ret = mdb_tgt_lookup_by_addr(mdb.m_target, addr, MDB_TGT_SYM_EXACT, + name, sizeof (name), &start_sym, NULL); + if (ret != 0) { + return (ret); + } + + if (ldset_name_from_item(name, ldsi->ldsi_name, + sizeof (ldsi->ldsi_name)) != 0) { + return (-1); + } + + ret = ldset_get_sym(STOP_PREFIX, ldsi->ldsi_name, &stop_sym); + if (ret != 0) { + return (-1); + } + + if (stop_sym.st_value < addr) { + return (set_errno(EINVAL)); + } + + if (ldset_get_entry(addr, &item_addr, ldsi->ldsi_ptrsize) != 0) { + return (-1); + } + + ldsi->ldsi_addr = addr; + ldsi->ldsi_endaddr = stop_sym.st_value; + ldsi->ldsi_nelem = (stop_sym.st_value - addr) / ldsi->ldsi_ptrsize; + ldsi->ldsi_elsize = ldset_item_size(item_addr); + + return (0); +} + +static int +ldsets_init_cb(void *data, const GElf_Sym *sym, const char *name, + const mdb_syminfo_t *sip, const char *obj) +{ + mdb_nv_t *nv = data; + const char *ldset_name; + GElf_Sym stop_sym = { 0 }; + int ret; + + if (strncmp(name, START_PREFIX, sizeof (START_PREFIX) - 1) != 0) { + return (0); + } + + /* + * The name of the linker set should follow START_PREFIX. If there's + * nothing there, then it's not a linker set, so skip this symbol. + */ + ldset_name = name + sizeof (START_PREFIX) - 1; + if (*ldset_name == '\0') { + return (0); + } + + ret = ldset_get_sym(STOP_PREFIX, ldset_name, &stop_sym); + if (ret != 0) { + /* If there's no stop symbol, we just ignore */ + if (errno == ENOENT) { + errno = 0; + return (0); + } + return (-1); + } + + /* + * The stop symbol should be at the same or higher address than + * the start symbol. If not, we ignore. + */ + if (stop_sym.st_value < sym->st_value) { + return (0); + } + + if (mdb_nv_insert(nv, ldset_name, NULL, sym->st_value, + MDB_NV_RDONLY) == NULL) { + return (-1); + } + + return (0); +} + +/* + * Initialize an mdb_nv_t with the name/addr of all the linkersets found in + * the target. + */ +static int +ldsets_nv_init(mdb_nv_t *nv, uint_t flags) +{ + if (mdb_nv_create(nv, flags) == NULL) + return (-1); + + return (mdb_tgt_symbol_iter(mdb.m_target, MDB_TGT_OBJ_EVERY, + MDB_TGT_SYMTAB, MDB_TGT_BIND_ANY | MDB_TGT_TYPE_NOTYPE, + ldsets_init_cb, nv)); +} + +int +ldsets_walk_init(mdb_walk_state_t *wsp) +{ + mdb_nv_t *nv; + int ret; + + nv = mdb_zalloc(sizeof (*nv), UM_SLEEP | UM_GC); + ret = ldsets_nv_init(nv, UM_SLEEP | UM_GC); + if (ret != 0) { + return (ret); + } + + mdb_nv_rewind(nv); + wsp->walk_data = nv; + return (WALK_NEXT); +} + +int +ldsets_walk_step(mdb_walk_state_t *wsp) +{ + mdb_nv_t *nv = wsp->walk_data; + mdb_var_t *v = mdb_nv_advance(nv); + int status; + + if (v == NULL) { + return (WALK_DONE); + } + + wsp->walk_addr = mdb_nv_get_value(v); + status = wsp->walk_callback(wsp->walk_addr, NULL, wsp->walk_cbdata); + return (status); +} + +int +ldset_walk_init(mdb_walk_state_t *wsp) +{ + ldset_info_t *ldsi; + int ret; + + ldsi = mdb_zalloc(sizeof (*ldsi), UM_SLEEP | UM_GC); + + ret = ldset_get_info(wsp->walk_addr, ldsi); + if (ret != 0) + return (WALK_ERR); + + wsp->walk_data = ldsi; + return (WALK_NEXT); +} + +int +ldset_walk_step(mdb_walk_state_t *wsp) +{ + ldset_info_t *ldsi = wsp->walk_data; + uintptr_t addr; + int ret; + + if (wsp->walk_addr >= ldsi->ldsi_endaddr) { + return (WALK_DONE); + } + + ret = ldset_get_entry(wsp->walk_addr, &addr, ldsi->ldsi_ptrsize); + if (ret != 0) { + return (WALK_ERR); + } + + ret = wsp->walk_callback(addr, NULL, wsp->walk_cbdata); + + wsp->walk_addr += ldsi->ldsi_ptrsize; + return (ret); +} + +static int +linkerset_walk_cb(uintptr_t addr, const void *data, void *cbarg) +{ + mdb_printf("%lr\n", addr); + return (0); +} + +static int +linkersets_walk_cb(uintptr_t addr, const void *data, void *cbarg) +{ + ldset_info_t info = { 0 }; + int ret; + char buf[64]; /* big enough for element size in any radix */ + + ret = ldset_get_info(addr, &info); + if (ret != 0) + return (WALK_ERR); + + if (info.ldsi_elsize > 0) { + (void) mdb_snprintf(buf, sizeof (buf), "%#r", + info.ldsi_elsize); + } else { + (void) strlcpy(buf, "?", sizeof (buf)); + } + + mdb_printf("%-20s %8s %9u\n", info.ldsi_name, buf, info.ldsi_nelem); + return (WALK_NEXT); +} + +int +cmd_linkerset(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv) +{ + int ret; + + if (argc > 1) { + return (DCMD_USAGE); + } + + /* Walk a linkerset given by the first argument */ + if (argc == 1) { + const char *setname = argv->a_un.a_str; + GElf_Sym start_sym = { 0 }; + ldset_info_t info = { 0 }; + + if (argv->a_type != MDB_TYPE_STRING) { + return (DCMD_USAGE); + } + + ret = ldset_get_sym(START_PREFIX, setname, &start_sym); + if (ret != 0) { + mdb_warn("Failed to get address of linkerset"); + return (-1); + } + + ret = ldset_get_info((uintptr_t)start_sym.st_value, &info); + if (ret != 0) { + mdb_warn("Failed to get information on linkerset"); + return (-1); + } + + return (mdb_pwalk("linkerset", linkerset_walk_cb, NULL, + info.ldsi_addr)); + } + + /* Display all the known linkersets */ + if (DCMD_HDRSPEC(flags)) { + mdb_printf("%<b>%<u>%-20s %-8s %-9s%</u>%</b>\n", + "NAME", "ITEMSIZE", "ITEMCOUNT"); + } + + return (mdb_walk("linkersets", linkersets_walk_cb, NULL)); +} + +static int +ldset_complete(mdb_var_t *v, void *arg) +{ + mdb_tab_cookie_t *mcp = arg; + + mdb_tab_insert(mcp, mdb_nv_get_name(v)); + return (0); +} + +static int +ldset_tab_complete(mdb_tab_cookie_t *mcp, const char *ldset) +{ + mdb_nv_t nv = { 0 }; + int ret; + + ret = ldsets_nv_init(&nv, UM_GC | UM_SLEEP); + if (ret != 0) { + return (ret); + } + + if (ldset != NULL) { + mdb_tab_setmbase(mcp, ldset); + } + + mdb_nv_sort_iter(&nv, ldset_complete, mcp, UM_GC | UM_SLEEP); + return (1); +} + +int +cmd_linkerset_tab(mdb_tab_cookie_t *mcp, uint_t flags, int argc, + const mdb_arg_t *argv) +{ + if (argc > 1) + return (1); + + if (argc == 1) { + ASSERT(argv[0].a_type == MDB_TYPE_STRING); + return (ldset_tab_complete(mcp, argv[0].a_un.a_str)); + } + + if (argc == 0 && (flags & DCMD_TAB_SPACE) != 0) { + return (ldset_tab_complete(mcp, NULL)); + } + + return (1); +} + +void +linkerset_help(void) +{ + static const char ldset_desc[] = +"A linker set is an array of pointers to objects in a target that have been\n" +"collected by the linker. The start and end location of each linker set\n" +"is designated by weak symbols with well known strings prefixed to the\n" +"name of the linker set.\n" +"\n" +"When invoked without any arguments, the ::linkerset command will attempt to\n" +"enumerate all linker sets present in the target. For each linker set, the \n" +"name, number of objects in the set, as well as the size of each object (when\n" +"known) is displayed. The ::linkerset command uses the CTF information to\n" +"determine the size of each object. If the CTF data is unavailable for a\n" +"given linkerset, '?' will displayed instead of the size.\n" +"\n" +"The ::linkerset command can also be invoked with a single argument -- the\n" +"name of a specific linker set. In this invocation, the ::linkerset command\n" +"will display the addresses of each object in the set and can be used as\n" +"part of a command pipeline.\n"; + + static const char ldset_examples[] = +" ::linkerset\n" +" ::linkerset sysinit_set | ::print 'struct sysinit'\n"; + + mdb_printf("%s\n", ldset_desc); + (void) mdb_dec_indent(2); + mdb_printf("%<b>EXAMPLES%</b>\n"); + (void) mdb_inc_indent(2); + mdb_printf("%s\n", ldset_examples); +} diff --git a/usr/src/cmd/mdb/common/mdb/mdb_linkerset.h b/usr/src/cmd/mdb/common/mdb/mdb_linkerset.h new file mode 100644 index 0000000000..9cf6a46c20 --- /dev/null +++ b/usr/src/cmd/mdb/common/mdb/mdb_linkerset.h @@ -0,0 +1,42 @@ +/* + * This file and its contents are supplied under the terms of the + * Common Development and Distribution License ("CDDL"), version 1.0. + * You may only use this file in accordance with the terms of version + * 1.0 of the CDDL. + * + * A full copy of the text of the CDDL should have accompanied this + * source. A copy of the CDDL is also available via the Internet at + * http://www.illumos.org/license/CDDL. + */ + +/* + * Copyright 2021 Joyent, Inc. + */ + +#ifndef _MDB_LINKERSET_H +#define _MDB_LINKERSET_H + +#ifdef __cplusplus +extern "C" { +#endif + +#ifdef _MDB + +extern int ldsets_walk_init(mdb_walk_state_t *); +extern int ldsets_walk_step(mdb_walk_state_t *); + +extern int ldset_walk_init(mdb_walk_state_t *); +extern int ldset_walk_step(mdb_walk_state_t *); + +extern int cmd_linkerset(uintptr_t, uint_t, int, const mdb_arg_t *); +extern void linkerset_help(void); +extern int cmd_linkerset_tab(mdb_tab_cookie_t *, uint_t, int, + const mdb_arg_t *); + +#endif /* _MDB */ + +#ifdef __cplusplus +} +#endif + +#endif /* _MDB_LINKERSET_H */ diff --git a/usr/src/cmd/mdb/common/mdb/mdb_walkers.c b/usr/src/cmd/mdb/common/mdb/mdb_walkers.c new file mode 100644 index 0000000000..2daa1d2ea2 --- /dev/null +++ b/usr/src/cmd/mdb/common/mdb/mdb_walkers.c @@ -0,0 +1,24 @@ +/* + * This file and its contents are supplied under the terms of the + * Common Development and Distribution License ("CDDL"), version 1.0. + * You may only use this file in accordance with the terms of version + * 1.0 of the CDDL. + * + * A full copy of the text of the CDDL should have accompanied this + * source. A copy of the CDDL is also available via the Internet at + * http://www.illumos.org/license/CDDL. + */ + +/* + * Copyright 2021 Joyent, Inc. + */ + +#include <mdb/mdb_modapi.h> +#include <mdb/mdb_linkerset.h> + +const mdb_walker_t mdb_walker_builtins[] = { + { "linkerset", "walk a linkerset", ldset_walk_init, ldset_walk_step }, + { "linkersets", "walk all linkersets", ldsets_walk_init, + ldsets_walk_step }, + NULL +}; |