17c478bd9Sstevel@tonic-gate /*
27c478bd9Sstevel@tonic-gate * CDDL HEADER START
37c478bd9Sstevel@tonic-gate *
47c478bd9Sstevel@tonic-gate * The contents of this file are subject to the terms of the
57c478bd9Sstevel@tonic-gate * Common Development and Distribution License, Version 1.0 only
67c478bd9Sstevel@tonic-gate * (the "License"). You may not use this file except in compliance
77c478bd9Sstevel@tonic-gate * with the License.
87c478bd9Sstevel@tonic-gate *
97c478bd9Sstevel@tonic-gate * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
107c478bd9Sstevel@tonic-gate * or http://www.opensolaris.org/os/licensing.
117c478bd9Sstevel@tonic-gate * See the License for the specific language governing permissions
127c478bd9Sstevel@tonic-gate * and limitations under the License.
137c478bd9Sstevel@tonic-gate *
147c478bd9Sstevel@tonic-gate * When distributing Covered Code, include this CDDL HEADER in each
157c478bd9Sstevel@tonic-gate * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
167c478bd9Sstevel@tonic-gate * If applicable, add the following below this CDDL HEADER, with the
177c478bd9Sstevel@tonic-gate * fields enclosed by brackets "[]" replaced with your own identifying
187c478bd9Sstevel@tonic-gate * information: Portions Copyright [yyyy] [name of copyright owner]
197c478bd9Sstevel@tonic-gate *
207c478bd9Sstevel@tonic-gate * CDDL HEADER END
217c478bd9Sstevel@tonic-gate */
227c478bd9Sstevel@tonic-gate /*
237c478bd9Sstevel@tonic-gate * Copyright 2004 Sun Microsystems, Inc. All rights reserved.
247c478bd9Sstevel@tonic-gate * Use is subject to license terms.
257c478bd9Sstevel@tonic-gate */
267c478bd9Sstevel@tonic-gate
277c478bd9Sstevel@tonic-gate #include <mdb/mdb_modapi.h>
287c478bd9Sstevel@tonic-gate #include <sys/rctl.h>
297c478bd9Sstevel@tonic-gate #include <sys/proc.h>
307c478bd9Sstevel@tonic-gate #include <sys/task.h>
317c478bd9Sstevel@tonic-gate #include <sys/project.h>
327c478bd9Sstevel@tonic-gate #include <sys/zone.h>
337c478bd9Sstevel@tonic-gate
347c478bd9Sstevel@tonic-gate static int
print_val(uintptr_t addr,rctl_val_t * val,uintptr_t * enforced)357c478bd9Sstevel@tonic-gate print_val(uintptr_t addr, rctl_val_t *val, uintptr_t *enforced)
367c478bd9Sstevel@tonic-gate {
377c478bd9Sstevel@tonic-gate char *priv;
387c478bd9Sstevel@tonic-gate static const mdb_bitmask_t val_localflag_bits[] = {
397c478bd9Sstevel@tonic-gate { "SIGNAL", RCTL_LOCAL_SIGNAL, RCTL_LOCAL_SIGNAL },
407c478bd9Sstevel@tonic-gate { "DENY", RCTL_LOCAL_DENY, RCTL_LOCAL_DENY },
417c478bd9Sstevel@tonic-gate { "MAX", RCTL_LOCAL_MAXIMAL, RCTL_LOCAL_MAXIMAL },
427c478bd9Sstevel@tonic-gate { NULL, 0, 0 }
437c478bd9Sstevel@tonic-gate };
447c478bd9Sstevel@tonic-gate
457c478bd9Sstevel@tonic-gate switch (val->rcv_privilege) {
467c478bd9Sstevel@tonic-gate case (RCPRIV_BASIC):
477c478bd9Sstevel@tonic-gate priv = "basic";
487c478bd9Sstevel@tonic-gate break;
497c478bd9Sstevel@tonic-gate case (RCPRIV_PRIVILEGED):
507c478bd9Sstevel@tonic-gate priv = "privileged";
517c478bd9Sstevel@tonic-gate break;
527c478bd9Sstevel@tonic-gate case (RCPRIV_SYSTEM):
537c478bd9Sstevel@tonic-gate priv = "system";
547c478bd9Sstevel@tonic-gate break;
557c478bd9Sstevel@tonic-gate default:
567c478bd9Sstevel@tonic-gate priv = "???";
577c478bd9Sstevel@tonic-gate break;
587c478bd9Sstevel@tonic-gate };
597c478bd9Sstevel@tonic-gate
607c478bd9Sstevel@tonic-gate mdb_printf("\t%s ", addr == *enforced ? "(cur)": " ");
617c478bd9Sstevel@tonic-gate
627c478bd9Sstevel@tonic-gate mdb_printf("%-#18llx %11s\tflags=<%b>\n",
637c478bd9Sstevel@tonic-gate val->rcv_value, priv, val->rcv_flagaction, val_localflag_bits);
647c478bd9Sstevel@tonic-gate
657c478bd9Sstevel@tonic-gate return (WALK_NEXT);
667c478bd9Sstevel@tonic-gate }
677c478bd9Sstevel@tonic-gate
687c478bd9Sstevel@tonic-gate int
rctl(uintptr_t addr,uint_t flags,int argc,const mdb_arg_t * argv)697c478bd9Sstevel@tonic-gate rctl(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv)
707c478bd9Sstevel@tonic-gate {
717c478bd9Sstevel@tonic-gate rctl_t rctl;
727c478bd9Sstevel@tonic-gate rctl_dict_entry_t dict;
737c478bd9Sstevel@tonic-gate char name[256];
747c478bd9Sstevel@tonic-gate rctl_hndl_t hndl;
757c478bd9Sstevel@tonic-gate
767c478bd9Sstevel@tonic-gate if (!(flags & DCMD_ADDRSPEC))
777c478bd9Sstevel@tonic-gate return (DCMD_USAGE);
787c478bd9Sstevel@tonic-gate
797c478bd9Sstevel@tonic-gate if (mdb_vread(&rctl, sizeof (rctl_t), addr) == -1) {
807c478bd9Sstevel@tonic-gate mdb_warn("failed to read rctl_t structure at %p", addr);
817c478bd9Sstevel@tonic-gate return (DCMD_ERR);
827c478bd9Sstevel@tonic-gate }
837c478bd9Sstevel@tonic-gate
847c478bd9Sstevel@tonic-gate if (argc != 0) {
857c478bd9Sstevel@tonic-gate const mdb_arg_t *argp = &argv[0];
867c478bd9Sstevel@tonic-gate
877c478bd9Sstevel@tonic-gate if (argp->a_type == MDB_TYPE_IMMEDIATE)
887c478bd9Sstevel@tonic-gate hndl = (rctl_hndl_t)argp->a_un.a_val;
897c478bd9Sstevel@tonic-gate else
907c478bd9Sstevel@tonic-gate hndl = (rctl_hndl_t)mdb_strtoull(argp->a_un.a_str);
917c478bd9Sstevel@tonic-gate
927c478bd9Sstevel@tonic-gate if (rctl.rc_id != hndl)
937c478bd9Sstevel@tonic-gate return (DCMD_OK);
947c478bd9Sstevel@tonic-gate }
957c478bd9Sstevel@tonic-gate
967c478bd9Sstevel@tonic-gate if (mdb_vread(&dict, sizeof (rctl_dict_entry_t),
977c478bd9Sstevel@tonic-gate (uintptr_t)rctl.rc_dict_entry) == -1) {
987c478bd9Sstevel@tonic-gate mdb_warn("failed to read dict entry for rctl_t %p at %p",
997c478bd9Sstevel@tonic-gate addr, rctl.rc_dict_entry);
1007c478bd9Sstevel@tonic-gate return (DCMD_ERR);
1017c478bd9Sstevel@tonic-gate }
1027c478bd9Sstevel@tonic-gate
1037c478bd9Sstevel@tonic-gate if (mdb_readstr(name, 256, (uintptr_t)(dict.rcd_name)) == -1) {
1047c478bd9Sstevel@tonic-gate mdb_warn("failed to read name for rctl_t %p", addr);
1057c478bd9Sstevel@tonic-gate return (DCMD_ERR);
1067c478bd9Sstevel@tonic-gate }
1077c478bd9Sstevel@tonic-gate
1087c478bd9Sstevel@tonic-gate mdb_printf("%0?p\t%3d : %s\n", addr, rctl.rc_id, name);
1097c478bd9Sstevel@tonic-gate
1107c478bd9Sstevel@tonic-gate if (mdb_pwalk("rctl_val", (mdb_walk_cb_t)print_val, &(rctl.rc_cursor),
1117c478bd9Sstevel@tonic-gate addr) == -1) {
1127c478bd9Sstevel@tonic-gate mdb_warn("failed to walk all values for rctl_t %p", addr);
1137c478bd9Sstevel@tonic-gate return (DCMD_ERR);
1147c478bd9Sstevel@tonic-gate }
1157c478bd9Sstevel@tonic-gate
1167c478bd9Sstevel@tonic-gate return (DCMD_OK);
1177c478bd9Sstevel@tonic-gate }
1187c478bd9Sstevel@tonic-gate
1197c478bd9Sstevel@tonic-gate int
rctl_dict(uintptr_t addr,uint_t flags,int argc,const mdb_arg_t * argv)1207c478bd9Sstevel@tonic-gate rctl_dict(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv)
1217c478bd9Sstevel@tonic-gate {
1227c478bd9Sstevel@tonic-gate rctl_dict_entry_t dict;
1237c478bd9Sstevel@tonic-gate char name[256], *type = NULL;
1247c478bd9Sstevel@tonic-gate
1257c478bd9Sstevel@tonic-gate if (!(flags & DCMD_ADDRSPEC)) {
1267c478bd9Sstevel@tonic-gate if (mdb_walk_dcmd("rctl_dict_list", "rctl_dict", argc,
1277c478bd9Sstevel@tonic-gate argv) == -1) {
1287c478bd9Sstevel@tonic-gate mdb_warn("failed to walk 'rctl_dict_list'");
1297c478bd9Sstevel@tonic-gate return (DCMD_ERR);
1307c478bd9Sstevel@tonic-gate }
1317c478bd9Sstevel@tonic-gate return (DCMD_OK);
1327c478bd9Sstevel@tonic-gate }
1337c478bd9Sstevel@tonic-gate
1347c478bd9Sstevel@tonic-gate if (DCMD_HDRSPEC(flags))
1357c478bd9Sstevel@tonic-gate mdb_printf("%<u>%2s %-27s %?s %7s %s%</u>\n",
1367c478bd9Sstevel@tonic-gate "ID", "NAME", "ADDR", "TYPE", "GLOBAL_FLAGS");
1377c478bd9Sstevel@tonic-gate
1387c478bd9Sstevel@tonic-gate if (mdb_vread(&dict, sizeof (dict), addr) == -1) {
1397c478bd9Sstevel@tonic-gate mdb_warn("failed to read rctl_dict at %p", addr);
1407c478bd9Sstevel@tonic-gate return (DCMD_ERR);
1417c478bd9Sstevel@tonic-gate }
1427c478bd9Sstevel@tonic-gate if (mdb_readstr(name, 256, (uintptr_t)(dict.rcd_name)) == -1) {
1437c478bd9Sstevel@tonic-gate mdb_warn("failed to read rctl_dict name for %p", addr);
1447c478bd9Sstevel@tonic-gate return (DCMD_ERR);
1457c478bd9Sstevel@tonic-gate }
1467c478bd9Sstevel@tonic-gate
1477c478bd9Sstevel@tonic-gate switch (dict.rcd_entity) {
1487c478bd9Sstevel@tonic-gate case RCENTITY_PROCESS:
1497c478bd9Sstevel@tonic-gate type = "process";
1507c478bd9Sstevel@tonic-gate break;
1517c478bd9Sstevel@tonic-gate case RCENTITY_TASK:
1527c478bd9Sstevel@tonic-gate type = "task";
1537c478bd9Sstevel@tonic-gate break;
1547c478bd9Sstevel@tonic-gate case RCENTITY_PROJECT:
1557c478bd9Sstevel@tonic-gate type = "project";
1567c478bd9Sstevel@tonic-gate break;
1577c478bd9Sstevel@tonic-gate case RCENTITY_ZONE:
1587c478bd9Sstevel@tonic-gate type = "zone";
1597c478bd9Sstevel@tonic-gate break;
1607c478bd9Sstevel@tonic-gate default:
1617c478bd9Sstevel@tonic-gate type = "unknown";
1627c478bd9Sstevel@tonic-gate break;
1637c478bd9Sstevel@tonic-gate }
1647c478bd9Sstevel@tonic-gate
1657c478bd9Sstevel@tonic-gate mdb_printf("%2d %-27s %0?p %7s 0x%08x", dict.rcd_id, name, addr,
1667c478bd9Sstevel@tonic-gate type, dict.rcd_flagaction);
1677c478bd9Sstevel@tonic-gate
1687c478bd9Sstevel@tonic-gate return (DCMD_OK);
1697c478bd9Sstevel@tonic-gate }
1707c478bd9Sstevel@tonic-gate
1717c478bd9Sstevel@tonic-gate typedef struct dict_data {
1727c478bd9Sstevel@tonic-gate rctl_hndl_t hndl;
1737c478bd9Sstevel@tonic-gate uintptr_t dict_addr;
1747c478bd9Sstevel@tonic-gate rctl_entity_t type;
1757c478bd9Sstevel@tonic-gate } dict_data_t;
1767c478bd9Sstevel@tonic-gate
1777c478bd9Sstevel@tonic-gate static int
hndl2dict(uintptr_t addr,rctl_dict_entry_t * entry,dict_data_t * data)1787c478bd9Sstevel@tonic-gate hndl2dict(uintptr_t addr, rctl_dict_entry_t *entry, dict_data_t *data)
1797c478bd9Sstevel@tonic-gate {
1807c478bd9Sstevel@tonic-gate if (data->hndl == entry->rcd_id) {
1817c478bd9Sstevel@tonic-gate data->dict_addr = addr;
1827c478bd9Sstevel@tonic-gate data->type = entry->rcd_entity;
1837c478bd9Sstevel@tonic-gate return (WALK_DONE);
1847c478bd9Sstevel@tonic-gate }
1857c478bd9Sstevel@tonic-gate
1867c478bd9Sstevel@tonic-gate return (WALK_NEXT);
1877c478bd9Sstevel@tonic-gate }
1887c478bd9Sstevel@tonic-gate
1897c478bd9Sstevel@tonic-gate /*
1907c478bd9Sstevel@tonic-gate * Print out all project, task, and process rctls for a given process.
1917c478bd9Sstevel@tonic-gate * If a handle is specified, print only the rctl matching that handle
1927c478bd9Sstevel@tonic-gate * for the process.
1937c478bd9Sstevel@tonic-gate */
1947c478bd9Sstevel@tonic-gate int
rctl_list(uintptr_t addr,uint_t flags,int argc,const mdb_arg_t * argv)1957c478bd9Sstevel@tonic-gate rctl_list(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv)
1967c478bd9Sstevel@tonic-gate {
1977c478bd9Sstevel@tonic-gate proc_t proc;
1987c478bd9Sstevel@tonic-gate uintptr_t set;
1997c478bd9Sstevel@tonic-gate task_t task;
2007c478bd9Sstevel@tonic-gate kproject_t proj;
2017c478bd9Sstevel@tonic-gate zone_t zone;
2027c478bd9Sstevel@tonic-gate dict_data_t rdict;
2037c478bd9Sstevel@tonic-gate int i;
2047c478bd9Sstevel@tonic-gate
205*892ad162SToomas Soome rdict.dict_addr = 0;
2067c478bd9Sstevel@tonic-gate
2077c478bd9Sstevel@tonic-gate if (!(flags & DCMD_ADDRSPEC))
2087c478bd9Sstevel@tonic-gate return (DCMD_USAGE);
2097c478bd9Sstevel@tonic-gate
2107c478bd9Sstevel@tonic-gate if (argc == 0)
2117c478bd9Sstevel@tonic-gate rdict.hndl = 0;
2127c478bd9Sstevel@tonic-gate else if (argc == 1) {
2137c478bd9Sstevel@tonic-gate /*
2147c478bd9Sstevel@tonic-gate * User specified a handle. Go find the rctl_dict_entity_t
2157c478bd9Sstevel@tonic-gate * structure so we know what type of rctl to look for.
2167c478bd9Sstevel@tonic-gate */
2177c478bd9Sstevel@tonic-gate const mdb_arg_t *argp = &argv[0];
2187c478bd9Sstevel@tonic-gate
2197c478bd9Sstevel@tonic-gate if (argp->a_type == MDB_TYPE_IMMEDIATE)
2207c478bd9Sstevel@tonic-gate rdict.hndl = (rctl_hndl_t)argp->a_un.a_val;
2217c478bd9Sstevel@tonic-gate else
2227c478bd9Sstevel@tonic-gate rdict.hndl =
2237c478bd9Sstevel@tonic-gate (rctl_hndl_t)mdb_strtoull(argp->a_un.a_str);
2247c478bd9Sstevel@tonic-gate
2257c478bd9Sstevel@tonic-gate if (mdb_walk("rctl_dict_list", (mdb_walk_cb_t)hndl2dict,
2267c478bd9Sstevel@tonic-gate &rdict) == -1) {
2277c478bd9Sstevel@tonic-gate mdb_warn("failed to walk rctl_dict_list");
2287c478bd9Sstevel@tonic-gate return (DCMD_ERR);
2297c478bd9Sstevel@tonic-gate }
2307c478bd9Sstevel@tonic-gate /* Couldn't find a rctl_dict_entry_t for this handle */
231*892ad162SToomas Soome if (rdict.dict_addr == 0)
2327c478bd9Sstevel@tonic-gate return (DCMD_ERR);
2337c478bd9Sstevel@tonic-gate } else
2347c478bd9Sstevel@tonic-gate return (DCMD_USAGE);
2357c478bd9Sstevel@tonic-gate
2367c478bd9Sstevel@tonic-gate
2377c478bd9Sstevel@tonic-gate if (mdb_vread(&proc, sizeof (proc_t), addr) == -1) {
2387c478bd9Sstevel@tonic-gate mdb_warn("failed to read proc at %p", addr);
2397c478bd9Sstevel@tonic-gate return (DCMD_ERR);
2407c478bd9Sstevel@tonic-gate }
2417c478bd9Sstevel@tonic-gate if (mdb_vread(&zone, sizeof (zone_t), (uintptr_t)proc.p_zone) == -1) {
2427c478bd9Sstevel@tonic-gate mdb_warn("failed to read zone at %p", proc.p_zone);
2437c478bd9Sstevel@tonic-gate return (DCMD_ERR);
2447c478bd9Sstevel@tonic-gate }
2457c478bd9Sstevel@tonic-gate if (mdb_vread(&task, sizeof (task_t), (uintptr_t)proc.p_task) == -1) {
2467c478bd9Sstevel@tonic-gate mdb_warn("failed to read task at %p", proc.p_task);
2477c478bd9Sstevel@tonic-gate return (DCMD_ERR);
2487c478bd9Sstevel@tonic-gate }
2497c478bd9Sstevel@tonic-gate if (mdb_vread(&proj, sizeof (kproject_t),
2507c478bd9Sstevel@tonic-gate (uintptr_t)task.tk_proj) == -1) {
2517c478bd9Sstevel@tonic-gate mdb_warn("failed to read proj at %p", task.tk_proj);
2527c478bd9Sstevel@tonic-gate return (DCMD_ERR);
2537c478bd9Sstevel@tonic-gate }
2547c478bd9Sstevel@tonic-gate
2557c478bd9Sstevel@tonic-gate for (i = 0; i <= RC_MAX_ENTITY; i++) {
2567c478bd9Sstevel@tonic-gate /*
2577c478bd9Sstevel@tonic-gate * If user didn't specify a handle, print rctls for all
2587c478bd9Sstevel@tonic-gate * types. Otherwise, we can walk the rctl_set for only the
2597c478bd9Sstevel@tonic-gate * entity specified by the handle.
2607c478bd9Sstevel@tonic-gate */
2617c478bd9Sstevel@tonic-gate if (rdict.hndl != 0 && rdict.type != i)
2627c478bd9Sstevel@tonic-gate continue;
2637c478bd9Sstevel@tonic-gate
2647c478bd9Sstevel@tonic-gate switch (i) {
2657c478bd9Sstevel@tonic-gate case (RCENTITY_PROCESS):
2667c478bd9Sstevel@tonic-gate set = (uintptr_t)proc.p_rctls;
2677c478bd9Sstevel@tonic-gate break;
2687c478bd9Sstevel@tonic-gate case (RCENTITY_TASK):
2697c478bd9Sstevel@tonic-gate set = (uintptr_t)task.tk_rctls;
2707c478bd9Sstevel@tonic-gate break;
2717c478bd9Sstevel@tonic-gate case (RCENTITY_PROJECT):
2727c478bd9Sstevel@tonic-gate set = (uintptr_t)proj.kpj_rctls;
2737c478bd9Sstevel@tonic-gate break;
2747c478bd9Sstevel@tonic-gate case (RCENTITY_ZONE):
2757c478bd9Sstevel@tonic-gate set = (uintptr_t)zone.zone_rctls;
2767c478bd9Sstevel@tonic-gate break;
2777c478bd9Sstevel@tonic-gate default:
2787c478bd9Sstevel@tonic-gate mdb_warn("Unknown rctl type %d", i);
2797c478bd9Sstevel@tonic-gate return (DCMD_ERR);
2807c478bd9Sstevel@tonic-gate }
2817c478bd9Sstevel@tonic-gate
2827c478bd9Sstevel@tonic-gate if (mdb_pwalk_dcmd("rctl_set", "rctl", argc, argv, set) == -1) {
2837c478bd9Sstevel@tonic-gate mdb_warn("failed to walk rctls in set %p", set);
2847c478bd9Sstevel@tonic-gate return (DCMD_ERR);
2857c478bd9Sstevel@tonic-gate }
2867c478bd9Sstevel@tonic-gate }
2877c478bd9Sstevel@tonic-gate
2887c478bd9Sstevel@tonic-gate return (DCMD_OK);
2897c478bd9Sstevel@tonic-gate }
2907c478bd9Sstevel@tonic-gate
2917c478bd9Sstevel@tonic-gate typedef struct dict_walk_data {
2927c478bd9Sstevel@tonic-gate int num_dicts;
2937c478bd9Sstevel@tonic-gate int num_cur;
2947c478bd9Sstevel@tonic-gate rctl_dict_entry_t **curdict;
2957c478bd9Sstevel@tonic-gate } dict_walk_data_t;
2967c478bd9Sstevel@tonic-gate
2977c478bd9Sstevel@tonic-gate int
rctl_dict_walk_init(mdb_walk_state_t * wsp)2987c478bd9Sstevel@tonic-gate rctl_dict_walk_init(mdb_walk_state_t *wsp)
2997c478bd9Sstevel@tonic-gate {
3007c478bd9Sstevel@tonic-gate uintptr_t ptr;
3017c478bd9Sstevel@tonic-gate int nlists;
3027c478bd9Sstevel@tonic-gate GElf_Sym sym;
3037c478bd9Sstevel@tonic-gate rctl_dict_entry_t **dicts;
3047c478bd9Sstevel@tonic-gate dict_walk_data_t *dwd;
3057c478bd9Sstevel@tonic-gate
3067c478bd9Sstevel@tonic-gate if (mdb_lookup_by_name("rctl_lists", &sym) == -1) {
3077c478bd9Sstevel@tonic-gate mdb_warn("failed to find 'rctl_lists'\n");
3087c478bd9Sstevel@tonic-gate return (WALK_ERR);
3097c478bd9Sstevel@tonic-gate }
3107c478bd9Sstevel@tonic-gate
3117c478bd9Sstevel@tonic-gate nlists = sym.st_size / sizeof (rctl_dict_entry_t *);
3127c478bd9Sstevel@tonic-gate ptr = (uintptr_t)sym.st_value;
3137c478bd9Sstevel@tonic-gate
3147c478bd9Sstevel@tonic-gate dicts = mdb_alloc(nlists * sizeof (rctl_dict_entry_t *), UM_SLEEP);
3157c478bd9Sstevel@tonic-gate mdb_vread(dicts, sym.st_size, ptr);
3167c478bd9Sstevel@tonic-gate
3177c478bd9Sstevel@tonic-gate dwd = mdb_alloc(sizeof (dict_walk_data_t), UM_SLEEP);
3187c478bd9Sstevel@tonic-gate dwd->num_dicts = nlists;
3197c478bd9Sstevel@tonic-gate dwd->num_cur = 0;
3207c478bd9Sstevel@tonic-gate dwd->curdict = dicts;
3217c478bd9Sstevel@tonic-gate
3227c478bd9Sstevel@tonic-gate wsp->walk_addr = 0;
3237c478bd9Sstevel@tonic-gate wsp->walk_data = dwd;
3247c478bd9Sstevel@tonic-gate
3257c478bd9Sstevel@tonic-gate return (WALK_NEXT);
3267c478bd9Sstevel@tonic-gate }
3277c478bd9Sstevel@tonic-gate
3287c478bd9Sstevel@tonic-gate int
rctl_dict_walk_step(mdb_walk_state_t * wsp)3297c478bd9Sstevel@tonic-gate rctl_dict_walk_step(mdb_walk_state_t *wsp)
3307c478bd9Sstevel@tonic-gate {
3317c478bd9Sstevel@tonic-gate dict_walk_data_t *dwd = wsp->walk_data;
3327c478bd9Sstevel@tonic-gate uintptr_t dp;
3337c478bd9Sstevel@tonic-gate rctl_dict_entry_t entry;
3347c478bd9Sstevel@tonic-gate int status;
3357c478bd9Sstevel@tonic-gate
3367c478bd9Sstevel@tonic-gate dp = (uintptr_t)((dwd->curdict)[dwd->num_cur]);
3377c478bd9Sstevel@tonic-gate
338*892ad162SToomas Soome while (dp != 0) {
3397c478bd9Sstevel@tonic-gate if (mdb_vread(&entry, sizeof (rctl_dict_entry_t), dp) == -1) {
3407c478bd9Sstevel@tonic-gate mdb_warn("failed to read rctl_dict_entry_t structure "
3417c478bd9Sstevel@tonic-gate "at %p", dp);
3427c478bd9Sstevel@tonic-gate return (WALK_ERR);
3437c478bd9Sstevel@tonic-gate }
3447c478bd9Sstevel@tonic-gate
3457c478bd9Sstevel@tonic-gate status = wsp->walk_callback(dp, &entry, wsp->walk_cbdata);
3467c478bd9Sstevel@tonic-gate if (status != WALK_NEXT)
3477c478bd9Sstevel@tonic-gate return (status);
3487c478bd9Sstevel@tonic-gate
3497c478bd9Sstevel@tonic-gate dp = (uintptr_t)entry.rcd_next;
3507c478bd9Sstevel@tonic-gate }
3517c478bd9Sstevel@tonic-gate
3527c478bd9Sstevel@tonic-gate dwd->num_cur++;
3537c478bd9Sstevel@tonic-gate
3547c478bd9Sstevel@tonic-gate if (dwd->num_cur == dwd->num_dicts)
3557c478bd9Sstevel@tonic-gate return (WALK_DONE);
3567c478bd9Sstevel@tonic-gate
3577c478bd9Sstevel@tonic-gate return (WALK_NEXT);
3587c478bd9Sstevel@tonic-gate }
3597c478bd9Sstevel@tonic-gate
3607c478bd9Sstevel@tonic-gate void
rctl_dict_walk_fini(mdb_walk_state_t * wsp)3617c478bd9Sstevel@tonic-gate rctl_dict_walk_fini(mdb_walk_state_t *wsp)
3627c478bd9Sstevel@tonic-gate {
3637c478bd9Sstevel@tonic-gate dict_walk_data_t *wd = wsp->walk_data;
3647c478bd9Sstevel@tonic-gate mdb_free(wd->curdict, wd->num_dicts * sizeof (rctl_dict_entry_t *));
3657c478bd9Sstevel@tonic-gate mdb_free(wd, sizeof (dict_walk_data_t));
3667c478bd9Sstevel@tonic-gate }
3677c478bd9Sstevel@tonic-gate
3687c478bd9Sstevel@tonic-gate typedef struct set_walk_data {
3697c478bd9Sstevel@tonic-gate uint_t hashsize;
3707c478bd9Sstevel@tonic-gate int hashcur;
3717c478bd9Sstevel@tonic-gate void **hashloc;
3727c478bd9Sstevel@tonic-gate } set_walk_data_t;
3737c478bd9Sstevel@tonic-gate
3747c478bd9Sstevel@tonic-gate int
rctl_set_walk_init(mdb_walk_state_t * wsp)3757c478bd9Sstevel@tonic-gate rctl_set_walk_init(mdb_walk_state_t *wsp)
3767c478bd9Sstevel@tonic-gate {
3777c478bd9Sstevel@tonic-gate rctl_set_t rset;
3787c478bd9Sstevel@tonic-gate uint_t hashsz;
3797c478bd9Sstevel@tonic-gate set_walk_data_t *swd;
3807c478bd9Sstevel@tonic-gate rctl_t **rctls;
3817c478bd9Sstevel@tonic-gate
3827c478bd9Sstevel@tonic-gate if (mdb_vread(&rset, sizeof (rctl_set_t), wsp->walk_addr) == -1) {
3837c478bd9Sstevel@tonic-gate mdb_warn("failed to read rset at %p", wsp->walk_addr);
3847c478bd9Sstevel@tonic-gate return (WALK_ERR);
3857c478bd9Sstevel@tonic-gate }
3867c478bd9Sstevel@tonic-gate
3877c478bd9Sstevel@tonic-gate if (mdb_readvar(&hashsz, "rctl_set_size") == -1 || hashsz == 0) {
3887c478bd9Sstevel@tonic-gate mdb_warn("rctl_set_size not found or invalid");
3897c478bd9Sstevel@tonic-gate return (WALK_ERR);
3907c478bd9Sstevel@tonic-gate }
3917c478bd9Sstevel@tonic-gate
3927c478bd9Sstevel@tonic-gate rctls = mdb_alloc(hashsz * sizeof (rctl_t *), UM_SLEEP);
3937c478bd9Sstevel@tonic-gate if (mdb_vread(rctls, hashsz * sizeof (rctl_t *),
3947c478bd9Sstevel@tonic-gate (uintptr_t)rset.rcs_ctls) == -1) {
3957c478bd9Sstevel@tonic-gate mdb_warn("cannot read rctl hash at %p", rset.rcs_ctls);
3967c478bd9Sstevel@tonic-gate mdb_free(rctls, hashsz * sizeof (rctl_t *));
3977c478bd9Sstevel@tonic-gate return (WALK_ERR);
3987c478bd9Sstevel@tonic-gate }
3997c478bd9Sstevel@tonic-gate
4007c478bd9Sstevel@tonic-gate swd = mdb_alloc(sizeof (set_walk_data_t), UM_SLEEP);
4017c478bd9Sstevel@tonic-gate swd->hashsize = hashsz;
4027c478bd9Sstevel@tonic-gate swd->hashcur = 0;
4037c478bd9Sstevel@tonic-gate swd->hashloc = (void **)rctls;
4047c478bd9Sstevel@tonic-gate
4057c478bd9Sstevel@tonic-gate wsp->walk_addr = 0;
4067c478bd9Sstevel@tonic-gate wsp->walk_data = swd;
4077c478bd9Sstevel@tonic-gate
4087c478bd9Sstevel@tonic-gate return (WALK_NEXT);
4097c478bd9Sstevel@tonic-gate }
4107c478bd9Sstevel@tonic-gate
4117c478bd9Sstevel@tonic-gate
4127c478bd9Sstevel@tonic-gate int
rctl_set_walk_step(mdb_walk_state_t * wsp)4137c478bd9Sstevel@tonic-gate rctl_set_walk_step(mdb_walk_state_t *wsp)
4147c478bd9Sstevel@tonic-gate {
4157c478bd9Sstevel@tonic-gate set_walk_data_t *swd = wsp->walk_data;
4167c478bd9Sstevel@tonic-gate rctl_t rctl;
4177c478bd9Sstevel@tonic-gate void **rhash = swd->hashloc;
4187c478bd9Sstevel@tonic-gate int status;
4197c478bd9Sstevel@tonic-gate
4207c478bd9Sstevel@tonic-gate if (swd->hashcur >= swd->hashsize)
4217c478bd9Sstevel@tonic-gate return (WALK_DONE);
4227c478bd9Sstevel@tonic-gate
423*892ad162SToomas Soome if (wsp->walk_addr == 0) {
4247c478bd9Sstevel@tonic-gate while (swd->hashcur < swd->hashsize) {
4257c478bd9Sstevel@tonic-gate if (rhash[swd->hashcur] != NULL) {
4267c478bd9Sstevel@tonic-gate break;
4277c478bd9Sstevel@tonic-gate }
4287c478bd9Sstevel@tonic-gate swd->hashcur++;
4297c478bd9Sstevel@tonic-gate }
4307c478bd9Sstevel@tonic-gate
4317c478bd9Sstevel@tonic-gate if (rhash[swd->hashcur] == NULL ||
4327c478bd9Sstevel@tonic-gate swd->hashcur >= swd->hashsize)
4337c478bd9Sstevel@tonic-gate return (WALK_DONE);
4347c478bd9Sstevel@tonic-gate
4357c478bd9Sstevel@tonic-gate wsp->walk_addr = (uintptr_t)rhash[swd->hashcur];
4367c478bd9Sstevel@tonic-gate swd->hashcur++;
4377c478bd9Sstevel@tonic-gate }
4387c478bd9Sstevel@tonic-gate
4397c478bd9Sstevel@tonic-gate if (mdb_vread(&rctl, sizeof (rctl_t), wsp->walk_addr) == -1) {
440*892ad162SToomas Soome wsp->walk_addr = 0;
4417c478bd9Sstevel@tonic-gate mdb_warn("unable to read from %#p", wsp->walk_addr);
4427c478bd9Sstevel@tonic-gate return (WALK_ERR);
4437c478bd9Sstevel@tonic-gate }
4447c478bd9Sstevel@tonic-gate
4457c478bd9Sstevel@tonic-gate status = wsp->walk_callback(wsp->walk_addr, &rctl, wsp->walk_cbdata);
4467c478bd9Sstevel@tonic-gate
4477c478bd9Sstevel@tonic-gate wsp->walk_addr = (uintptr_t)rctl.rc_next;
4487c478bd9Sstevel@tonic-gate
4497c478bd9Sstevel@tonic-gate return (status);
4507c478bd9Sstevel@tonic-gate }
4517c478bd9Sstevel@tonic-gate
4527c478bd9Sstevel@tonic-gate void
rctl_set_walk_fini(mdb_walk_state_t * wsp)4537c478bd9Sstevel@tonic-gate rctl_set_walk_fini(mdb_walk_state_t *wsp)
4547c478bd9Sstevel@tonic-gate {
4557c478bd9Sstevel@tonic-gate set_walk_data_t *sd = wsp->walk_data;
4567c478bd9Sstevel@tonic-gate
4577c478bd9Sstevel@tonic-gate mdb_free(sd->hashloc, sd->hashsize * sizeof (rctl_t *));
4587c478bd9Sstevel@tonic-gate mdb_free(sd, sizeof (set_walk_data_t));
4597c478bd9Sstevel@tonic-gate }
4607c478bd9Sstevel@tonic-gate
4617c478bd9Sstevel@tonic-gate int
rctl_val_walk_init(mdb_walk_state_t * wsp)4627c478bd9Sstevel@tonic-gate rctl_val_walk_init(mdb_walk_state_t *wsp)
4637c478bd9Sstevel@tonic-gate {
4647c478bd9Sstevel@tonic-gate rctl_t rctl;
4657c478bd9Sstevel@tonic-gate
4667c478bd9Sstevel@tonic-gate if (mdb_vread(&rctl, sizeof (rctl_t), wsp->walk_addr) == -1) {
4677c478bd9Sstevel@tonic-gate mdb_warn("failed to read rctl at %p", wsp->walk_addr);
4687c478bd9Sstevel@tonic-gate return (WALK_ERR);
4697c478bd9Sstevel@tonic-gate }
4707c478bd9Sstevel@tonic-gate wsp->walk_addr = (uintptr_t)rctl.rc_values;
4717c478bd9Sstevel@tonic-gate wsp->walk_data = rctl.rc_values;
4727c478bd9Sstevel@tonic-gate return (WALK_NEXT);
4737c478bd9Sstevel@tonic-gate }
4747c478bd9Sstevel@tonic-gate
4757c478bd9Sstevel@tonic-gate int
rctl_val_walk_step(mdb_walk_state_t * wsp)4767c478bd9Sstevel@tonic-gate rctl_val_walk_step(mdb_walk_state_t *wsp)
4777c478bd9Sstevel@tonic-gate {
4787c478bd9Sstevel@tonic-gate rctl_val_t val;
4797c478bd9Sstevel@tonic-gate int status;
4807c478bd9Sstevel@tonic-gate
4817c478bd9Sstevel@tonic-gate if (mdb_vread(&val, sizeof (rctl_val_t), wsp->walk_addr) == -1) {
4827c478bd9Sstevel@tonic-gate mdb_warn("failed to read rctl_val at %p", wsp->walk_addr);
4837c478bd9Sstevel@tonic-gate return (WALK_DONE);
4847c478bd9Sstevel@tonic-gate }
4857c478bd9Sstevel@tonic-gate
4867c478bd9Sstevel@tonic-gate status = wsp->walk_callback(wsp->walk_addr, &val, wsp->walk_cbdata);
4877c478bd9Sstevel@tonic-gate
488*892ad162SToomas Soome if ((wsp->walk_addr = (uintptr_t)val.rcv_next) == 0)
4897c478bd9Sstevel@tonic-gate return (WALK_DONE);
4907c478bd9Sstevel@tonic-gate
4917c478bd9Sstevel@tonic-gate return (status);
4927c478bd9Sstevel@tonic-gate }
4937c478bd9Sstevel@tonic-gate
4947c478bd9Sstevel@tonic-gate typedef struct rctl_val_seen {
4957c478bd9Sstevel@tonic-gate uintptr_t s_ptr;
4967c478bd9Sstevel@tonic-gate rctl_qty_t s_val;
4977c478bd9Sstevel@tonic-gate } rctl_val_seen_t;
4987c478bd9Sstevel@tonic-gate
4997c478bd9Sstevel@tonic-gate typedef struct rctl_validate_data {
5007c478bd9Sstevel@tonic-gate uintptr_t v_rctl_addr;
5017c478bd9Sstevel@tonic-gate rctl_val_t *v_cursor;
5027c478bd9Sstevel@tonic-gate uint_t v_flags;
5037c478bd9Sstevel@tonic-gate int v_bad_rctl;
5047c478bd9Sstevel@tonic-gate int v_cursor_valid;
5057c478bd9Sstevel@tonic-gate int v_circularity_detected;
5067c478bd9Sstevel@tonic-gate uint_t v_seen_size;
5077c478bd9Sstevel@tonic-gate uint_t v_seen_cnt;
5087c478bd9Sstevel@tonic-gate rctl_val_seen_t *v_seen;
5097c478bd9Sstevel@tonic-gate } rctl_validate_data_t;
5107c478bd9Sstevel@tonic-gate
5117c478bd9Sstevel@tonic-gate #define RCV_VERBOSE 0x1
5127c478bd9Sstevel@tonic-gate
5137c478bd9Sstevel@tonic-gate /*
5147c478bd9Sstevel@tonic-gate * rctl_val_validate()
5157c478bd9Sstevel@tonic-gate * Do validation on an individual rctl_val_t. This function is called
5167c478bd9Sstevel@tonic-gate * as part of the rctl_val walker, and helps perform the checks described
5177c478bd9Sstevel@tonic-gate * in the ::rctl_validate dcmd.
5187c478bd9Sstevel@tonic-gate */
5197c478bd9Sstevel@tonic-gate static int
rctl_val_validate(uintptr_t addr,rctl_val_t * val,rctl_validate_data_t * data)5207c478bd9Sstevel@tonic-gate rctl_val_validate(uintptr_t addr, rctl_val_t *val, rctl_validate_data_t *data)
5217c478bd9Sstevel@tonic-gate {
5227c478bd9Sstevel@tonic-gate int i;
5237c478bd9Sstevel@tonic-gate
5247c478bd9Sstevel@tonic-gate data->v_seen[data->v_seen_cnt].s_ptr = addr;
5257c478bd9Sstevel@tonic-gate
5267c478bd9Sstevel@tonic-gate if (addr == (uintptr_t)data->v_cursor)
5277c478bd9Sstevel@tonic-gate data->v_cursor_valid++;
5287c478bd9Sstevel@tonic-gate
5297c478bd9Sstevel@tonic-gate data->v_seen[data->v_seen_cnt].s_val = val->rcv_value;
5307c478bd9Sstevel@tonic-gate
5317c478bd9Sstevel@tonic-gate if (val->rcv_prev == (void *)0xbaddcafe ||
5327c478bd9Sstevel@tonic-gate val->rcv_next == (void *)0xbaddcafe ||
5337c478bd9Sstevel@tonic-gate val->rcv_prev == (void *)0xdeadbeef ||
5347c478bd9Sstevel@tonic-gate val->rcv_next == (void *)0xdeadbeef) {
5357c478bd9Sstevel@tonic-gate if (data->v_bad_rctl++ == 0)
5367c478bd9Sstevel@tonic-gate mdb_printf("%p ", data->v_rctl_addr);
5377c478bd9Sstevel@tonic-gate if (data->v_flags & RCV_VERBOSE)
5387c478bd9Sstevel@tonic-gate mdb_printf("/ uninitialized or previously "
5397c478bd9Sstevel@tonic-gate "freed link at %p ", addr);
5407c478bd9Sstevel@tonic-gate }
5417c478bd9Sstevel@tonic-gate
5427c478bd9Sstevel@tonic-gate if (data->v_seen_cnt == 0) {
5437c478bd9Sstevel@tonic-gate if (val->rcv_prev != NULL) {
5447c478bd9Sstevel@tonic-gate if (data->v_bad_rctl++ == 0)
5457c478bd9Sstevel@tonic-gate mdb_printf("%p ", data->v_rctl_addr);
5467c478bd9Sstevel@tonic-gate if (data->v_flags & RCV_VERBOSE)
5477c478bd9Sstevel@tonic-gate mdb_printf("/ bad prev pointer at "
5487c478bd9Sstevel@tonic-gate "head ");
5497c478bd9Sstevel@tonic-gate }
5507c478bd9Sstevel@tonic-gate } else {
5517c478bd9Sstevel@tonic-gate if ((uintptr_t)val->rcv_prev !=
5527c478bd9Sstevel@tonic-gate data->v_seen[data->v_seen_cnt - 1].s_ptr) {
5537c478bd9Sstevel@tonic-gate if (data->v_bad_rctl++ == 0)
5547c478bd9Sstevel@tonic-gate mdb_printf("%p ", data->v_rctl_addr);
5557c478bd9Sstevel@tonic-gate if (data->v_flags & RCV_VERBOSE)
5567c478bd9Sstevel@tonic-gate mdb_printf("/ bad prev pointer at %p ",
5577c478bd9Sstevel@tonic-gate addr);
5587c478bd9Sstevel@tonic-gate }
5597c478bd9Sstevel@tonic-gate
5607c478bd9Sstevel@tonic-gate if (data->v_seen[data->v_seen_cnt].s_val <
5617c478bd9Sstevel@tonic-gate data->v_seen[data->v_seen_cnt - 1].s_val) {
5627c478bd9Sstevel@tonic-gate if (data->v_bad_rctl++ == 0)
5637c478bd9Sstevel@tonic-gate mdb_printf("%p ", data->v_rctl_addr);
5647c478bd9Sstevel@tonic-gate if (data->v_flags & RCV_VERBOSE)
5657c478bd9Sstevel@tonic-gate mdb_printf("/ ordering error at %p ",
5667c478bd9Sstevel@tonic-gate addr);
5677c478bd9Sstevel@tonic-gate }
5687c478bd9Sstevel@tonic-gate }
5697c478bd9Sstevel@tonic-gate
5707c478bd9Sstevel@tonic-gate for (i = data->v_seen_cnt; i >= 0; i--) {
5717c478bd9Sstevel@tonic-gate if (data->v_seen[i].s_ptr == (uintptr_t)val->rcv_next) {
5727c478bd9Sstevel@tonic-gate if (data->v_bad_rctl++ == 0)
5737c478bd9Sstevel@tonic-gate mdb_printf("%p ", data->v_rctl_addr);
5747c478bd9Sstevel@tonic-gate if (data->v_flags & RCV_VERBOSE)
5757c478bd9Sstevel@tonic-gate mdb_printf("/ circular next pointer "
5767c478bd9Sstevel@tonic-gate "at %p ", addr);
5777c478bd9Sstevel@tonic-gate data->v_circularity_detected++;
5787c478bd9Sstevel@tonic-gate break;
5797c478bd9Sstevel@tonic-gate }
5807c478bd9Sstevel@tonic-gate }
5817c478bd9Sstevel@tonic-gate
5827c478bd9Sstevel@tonic-gate if (data->v_circularity_detected)
5837c478bd9Sstevel@tonic-gate return (WALK_DONE);
5847c478bd9Sstevel@tonic-gate
5857c478bd9Sstevel@tonic-gate data->v_seen_cnt++;
5867c478bd9Sstevel@tonic-gate if (data->v_seen_cnt >= data->v_seen_size) {
5877c478bd9Sstevel@tonic-gate uint_t new_seen_size = data->v_seen_size * 2;
5887c478bd9Sstevel@tonic-gate rctl_val_seen_t *tseen = mdb_zalloc(new_seen_size *
5897c478bd9Sstevel@tonic-gate sizeof (rctl_val_seen_t), UM_SLEEP | UM_GC);
5907c478bd9Sstevel@tonic-gate
5917c478bd9Sstevel@tonic-gate bcopy(data->v_seen, tseen, data->v_seen_size *
5927c478bd9Sstevel@tonic-gate sizeof (rctl_val_seen_t));
5937c478bd9Sstevel@tonic-gate
5947c478bd9Sstevel@tonic-gate data->v_seen = tseen;
5957c478bd9Sstevel@tonic-gate data->v_seen_size = new_seen_size;
5967c478bd9Sstevel@tonic-gate }
5977c478bd9Sstevel@tonic-gate
5987c478bd9Sstevel@tonic-gate return (WALK_NEXT);
5997c478bd9Sstevel@tonic-gate }
6007c478bd9Sstevel@tonic-gate
6017c478bd9Sstevel@tonic-gate /*
6027c478bd9Sstevel@tonic-gate * Validate a rctl pointer by checking:
6037c478bd9Sstevel@tonic-gate * - rctl_val_t's for that rctl form an ordered, non-circular list
6047c478bd9Sstevel@tonic-gate * - the cursor points to a rctl_val_t within that list
6057c478bd9Sstevel@tonic-gate * - there are no more than UINT64_MAX (or # specified by -n)
6067c478bd9Sstevel@tonic-gate * rctl_val_t's in the list
6077c478bd9Sstevel@tonic-gate */
6087c478bd9Sstevel@tonic-gate int
rctl_validate(uintptr_t addr,uint_t flags,int argc,const mdb_arg_t * argv)6097c478bd9Sstevel@tonic-gate rctl_validate(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv)
6107c478bd9Sstevel@tonic-gate {
6117c478bd9Sstevel@tonic-gate rctl_validate_data_t data;
6127c478bd9Sstevel@tonic-gate
6137c478bd9Sstevel@tonic-gate rctl_t r;
6147c478bd9Sstevel@tonic-gate
6157c478bd9Sstevel@tonic-gate uint64_t long_threshold = UINT64_MAX;
6167c478bd9Sstevel@tonic-gate
6177c478bd9Sstevel@tonic-gate /* Initialize validate data structure */
6187c478bd9Sstevel@tonic-gate data.v_rctl_addr = addr;
6197c478bd9Sstevel@tonic-gate data.v_flags = 0;
6207c478bd9Sstevel@tonic-gate data.v_bad_rctl = 0;
6217c478bd9Sstevel@tonic-gate data.v_seen_cnt = 0;
6227c478bd9Sstevel@tonic-gate data.v_cursor_valid = 0;
6237c478bd9Sstevel@tonic-gate data.v_circularity_detected = 0;
6247c478bd9Sstevel@tonic-gate data.v_seen_size = 1;
6257c478bd9Sstevel@tonic-gate data.v_seen = mdb_zalloc(data.v_seen_size * sizeof (rctl_val_seen_t),
6267c478bd9Sstevel@tonic-gate UM_SLEEP | UM_GC);
6277c478bd9Sstevel@tonic-gate
6287c478bd9Sstevel@tonic-gate if (!(flags & DCMD_ADDRSPEC))
6297c478bd9Sstevel@tonic-gate return (DCMD_USAGE);
6307c478bd9Sstevel@tonic-gate
6317c478bd9Sstevel@tonic-gate if (mdb_getopts(argc, argv,
6327c478bd9Sstevel@tonic-gate 'v', MDB_OPT_SETBITS, RCV_VERBOSE, &data.v_flags,
6337c478bd9Sstevel@tonic-gate 'n', MDB_OPT_UINT64, &long_threshold,
6347c478bd9Sstevel@tonic-gate NULL) != argc)
6357c478bd9Sstevel@tonic-gate return (DCMD_USAGE);
6367c478bd9Sstevel@tonic-gate
6377c478bd9Sstevel@tonic-gate if (mdb_vread(&r, sizeof (rctl_t), addr) != sizeof (rctl_t)) {
6387c478bd9Sstevel@tonic-gate mdb_warn("failed to read rctl structure at %p", addr);
6397c478bd9Sstevel@tonic-gate return (DCMD_ERR);
6407c478bd9Sstevel@tonic-gate }
6417c478bd9Sstevel@tonic-gate
6427c478bd9Sstevel@tonic-gate data.v_cursor = r.rc_cursor;
6437c478bd9Sstevel@tonic-gate
6447c478bd9Sstevel@tonic-gate if (data.v_cursor == NULL) {
6457c478bd9Sstevel@tonic-gate if (data.v_bad_rctl++ == 0)
6467c478bd9Sstevel@tonic-gate mdb_printf("%p ", addr);
6477c478bd9Sstevel@tonic-gate if (data.v_flags & RCV_VERBOSE)
6487c478bd9Sstevel@tonic-gate mdb_printf("/ NULL cursor seen ");
6497c478bd9Sstevel@tonic-gate } else if (data.v_cursor == (rctl_val_t *)0xbaddcafe) {
6507c478bd9Sstevel@tonic-gate if (data.v_bad_rctl++ == 0)
6517c478bd9Sstevel@tonic-gate mdb_printf("%p ", addr);
6527c478bd9Sstevel@tonic-gate if (data.v_flags & RCV_VERBOSE)
6537c478bd9Sstevel@tonic-gate mdb_printf("/ uninitialized cursor seen ");
6547c478bd9Sstevel@tonic-gate }
6557c478bd9Sstevel@tonic-gate
6567c478bd9Sstevel@tonic-gate /* Walk through each val in this rctl for individual validation. */
6577c478bd9Sstevel@tonic-gate if (mdb_pwalk("rctl_val", (mdb_walk_cb_t)rctl_val_validate, &data,
6587c478bd9Sstevel@tonic-gate addr) == -1) {
6597c478bd9Sstevel@tonic-gate mdb_warn("failed to walk all values for rctl_t %p", addr);
6607c478bd9Sstevel@tonic-gate return (DCMD_ERR);
6617c478bd9Sstevel@tonic-gate }
6627c478bd9Sstevel@tonic-gate
6637c478bd9Sstevel@tonic-gate if (data.v_seen_cnt >= long_threshold) {
6647c478bd9Sstevel@tonic-gate if (data.v_bad_rctl++ == 0)
6657c478bd9Sstevel@tonic-gate mdb_printf("%p ", addr);
6667c478bd9Sstevel@tonic-gate if (data.v_flags & RCV_VERBOSE)
6677c478bd9Sstevel@tonic-gate mdb_printf("/ sequence length = %d ",
6687c478bd9Sstevel@tonic-gate data.v_seen_cnt);
6697c478bd9Sstevel@tonic-gate }
6707c478bd9Sstevel@tonic-gate
6717c478bd9Sstevel@tonic-gate if (!data.v_cursor_valid) {
6727c478bd9Sstevel@tonic-gate if (data.v_bad_rctl++ == 0)
6737c478bd9Sstevel@tonic-gate mdb_printf("%p ", addr);
6747c478bd9Sstevel@tonic-gate if (data.v_flags & RCV_VERBOSE)
6757c478bd9Sstevel@tonic-gate mdb_printf("/ cursor outside sequence");
6767c478bd9Sstevel@tonic-gate }
6777c478bd9Sstevel@tonic-gate
6787c478bd9Sstevel@tonic-gate if (data.v_bad_rctl)
6797c478bd9Sstevel@tonic-gate mdb_printf("\n");
6807c478bd9Sstevel@tonic-gate
6817c478bd9Sstevel@tonic-gate if (data.v_circularity_detected)
6827c478bd9Sstevel@tonic-gate mdb_warn("circular list implies possible memory leak; "
6837c478bd9Sstevel@tonic-gate "recommend invoking ::findleaks");
6847c478bd9Sstevel@tonic-gate
6857c478bd9Sstevel@tonic-gate return (DCMD_OK);
6867c478bd9Sstevel@tonic-gate }
687