1*0Sstevel@tonic-gate /*
2*0Sstevel@tonic-gate * CDDL HEADER START
3*0Sstevel@tonic-gate *
4*0Sstevel@tonic-gate * The contents of this file are subject to the terms of the
5*0Sstevel@tonic-gate * Common Development and Distribution License, Version 1.0 only
6*0Sstevel@tonic-gate * (the "License"). You may not use this file except in compliance
7*0Sstevel@tonic-gate * with the License.
8*0Sstevel@tonic-gate *
9*0Sstevel@tonic-gate * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
10*0Sstevel@tonic-gate * or http://www.opensolaris.org/os/licensing.
11*0Sstevel@tonic-gate * See the License for the specific language governing permissions
12*0Sstevel@tonic-gate * and limitations under the License.
13*0Sstevel@tonic-gate *
14*0Sstevel@tonic-gate * When distributing Covered Code, include this CDDL HEADER in each
15*0Sstevel@tonic-gate * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
16*0Sstevel@tonic-gate * If applicable, add the following below this CDDL HEADER, with the
17*0Sstevel@tonic-gate * fields enclosed by brackets "[]" replaced with your own identifying
18*0Sstevel@tonic-gate * information: Portions Copyright [yyyy] [name of copyright owner]
19*0Sstevel@tonic-gate *
20*0Sstevel@tonic-gate * CDDL HEADER END
21*0Sstevel@tonic-gate */
22*0Sstevel@tonic-gate /*
23*0Sstevel@tonic-gate * Copyright 2004 Sun Microsystems, Inc. All rights reserved.
24*0Sstevel@tonic-gate * Use is subject to license terms.
25*0Sstevel@tonic-gate */
26*0Sstevel@tonic-gate
27*0Sstevel@tonic-gate #pragma ident "%Z%%M% %I% %E% SMI"
28*0Sstevel@tonic-gate
29*0Sstevel@tonic-gate #include <mdb/mdb_modapi.h>
30*0Sstevel@tonic-gate #include <sys/rctl.h>
31*0Sstevel@tonic-gate #include <sys/proc.h>
32*0Sstevel@tonic-gate #include <sys/task.h>
33*0Sstevel@tonic-gate #include <sys/project.h>
34*0Sstevel@tonic-gate #include <sys/zone.h>
35*0Sstevel@tonic-gate
36*0Sstevel@tonic-gate static int
print_val(uintptr_t addr,rctl_val_t * val,uintptr_t * enforced)37*0Sstevel@tonic-gate print_val(uintptr_t addr, rctl_val_t *val, uintptr_t *enforced)
38*0Sstevel@tonic-gate {
39*0Sstevel@tonic-gate char *priv;
40*0Sstevel@tonic-gate static const mdb_bitmask_t val_localflag_bits[] = {
41*0Sstevel@tonic-gate { "SIGNAL", RCTL_LOCAL_SIGNAL, RCTL_LOCAL_SIGNAL },
42*0Sstevel@tonic-gate { "DENY", RCTL_LOCAL_DENY, RCTL_LOCAL_DENY },
43*0Sstevel@tonic-gate { "MAX", RCTL_LOCAL_MAXIMAL, RCTL_LOCAL_MAXIMAL },
44*0Sstevel@tonic-gate { NULL, 0, 0 }
45*0Sstevel@tonic-gate };
46*0Sstevel@tonic-gate
47*0Sstevel@tonic-gate switch (val->rcv_privilege) {
48*0Sstevel@tonic-gate case (RCPRIV_BASIC):
49*0Sstevel@tonic-gate priv = "basic";
50*0Sstevel@tonic-gate break;
51*0Sstevel@tonic-gate case (RCPRIV_PRIVILEGED):
52*0Sstevel@tonic-gate priv = "privileged";
53*0Sstevel@tonic-gate break;
54*0Sstevel@tonic-gate case (RCPRIV_SYSTEM):
55*0Sstevel@tonic-gate priv = "system";
56*0Sstevel@tonic-gate break;
57*0Sstevel@tonic-gate default:
58*0Sstevel@tonic-gate priv = "???";
59*0Sstevel@tonic-gate break;
60*0Sstevel@tonic-gate };
61*0Sstevel@tonic-gate
62*0Sstevel@tonic-gate mdb_printf("\t%s ", addr == *enforced ? "(cur)": " ");
63*0Sstevel@tonic-gate
64*0Sstevel@tonic-gate mdb_printf("%-#18llx %11s\tflags=<%b>\n",
65*0Sstevel@tonic-gate val->rcv_value, priv, val->rcv_flagaction, val_localflag_bits);
66*0Sstevel@tonic-gate
67*0Sstevel@tonic-gate return (WALK_NEXT);
68*0Sstevel@tonic-gate }
69*0Sstevel@tonic-gate
70*0Sstevel@tonic-gate int
rctl(uintptr_t addr,uint_t flags,int argc,const mdb_arg_t * argv)71*0Sstevel@tonic-gate rctl(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv)
72*0Sstevel@tonic-gate {
73*0Sstevel@tonic-gate rctl_t rctl;
74*0Sstevel@tonic-gate rctl_dict_entry_t dict;
75*0Sstevel@tonic-gate char name[256];
76*0Sstevel@tonic-gate rctl_hndl_t hndl;
77*0Sstevel@tonic-gate
78*0Sstevel@tonic-gate if (!(flags & DCMD_ADDRSPEC))
79*0Sstevel@tonic-gate return (DCMD_USAGE);
80*0Sstevel@tonic-gate
81*0Sstevel@tonic-gate if (mdb_vread(&rctl, sizeof (rctl_t), addr) == -1) {
82*0Sstevel@tonic-gate mdb_warn("failed to read rctl_t structure at %p", addr);
83*0Sstevel@tonic-gate return (DCMD_ERR);
84*0Sstevel@tonic-gate }
85*0Sstevel@tonic-gate
86*0Sstevel@tonic-gate if (argc != 0) {
87*0Sstevel@tonic-gate const mdb_arg_t *argp = &argv[0];
88*0Sstevel@tonic-gate
89*0Sstevel@tonic-gate if (argp->a_type == MDB_TYPE_IMMEDIATE)
90*0Sstevel@tonic-gate hndl = (rctl_hndl_t)argp->a_un.a_val;
91*0Sstevel@tonic-gate else
92*0Sstevel@tonic-gate hndl = (rctl_hndl_t)mdb_strtoull(argp->a_un.a_str);
93*0Sstevel@tonic-gate
94*0Sstevel@tonic-gate if (rctl.rc_id != hndl)
95*0Sstevel@tonic-gate return (DCMD_OK);
96*0Sstevel@tonic-gate }
97*0Sstevel@tonic-gate
98*0Sstevel@tonic-gate if (mdb_vread(&dict, sizeof (rctl_dict_entry_t),
99*0Sstevel@tonic-gate (uintptr_t)rctl.rc_dict_entry) == -1) {
100*0Sstevel@tonic-gate mdb_warn("failed to read dict entry for rctl_t %p at %p",
101*0Sstevel@tonic-gate addr, rctl.rc_dict_entry);
102*0Sstevel@tonic-gate return (DCMD_ERR);
103*0Sstevel@tonic-gate }
104*0Sstevel@tonic-gate
105*0Sstevel@tonic-gate if (mdb_readstr(name, 256, (uintptr_t)(dict.rcd_name)) == -1) {
106*0Sstevel@tonic-gate mdb_warn("failed to read name for rctl_t %p", addr);
107*0Sstevel@tonic-gate return (DCMD_ERR);
108*0Sstevel@tonic-gate }
109*0Sstevel@tonic-gate
110*0Sstevel@tonic-gate mdb_printf("%0?p\t%3d : %s\n", addr, rctl.rc_id, name);
111*0Sstevel@tonic-gate
112*0Sstevel@tonic-gate if (mdb_pwalk("rctl_val", (mdb_walk_cb_t)print_val, &(rctl.rc_cursor),
113*0Sstevel@tonic-gate addr) == -1) {
114*0Sstevel@tonic-gate mdb_warn("failed to walk all values for rctl_t %p", addr);
115*0Sstevel@tonic-gate return (DCMD_ERR);
116*0Sstevel@tonic-gate }
117*0Sstevel@tonic-gate
118*0Sstevel@tonic-gate return (DCMD_OK);
119*0Sstevel@tonic-gate }
120*0Sstevel@tonic-gate
121*0Sstevel@tonic-gate int
rctl_dict(uintptr_t addr,uint_t flags,int argc,const mdb_arg_t * argv)122*0Sstevel@tonic-gate rctl_dict(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv)
123*0Sstevel@tonic-gate {
124*0Sstevel@tonic-gate rctl_dict_entry_t dict;
125*0Sstevel@tonic-gate char name[256], *type = NULL;
126*0Sstevel@tonic-gate
127*0Sstevel@tonic-gate if (!(flags & DCMD_ADDRSPEC)) {
128*0Sstevel@tonic-gate if (mdb_walk_dcmd("rctl_dict_list", "rctl_dict", argc,
129*0Sstevel@tonic-gate argv) == -1) {
130*0Sstevel@tonic-gate mdb_warn("failed to walk 'rctl_dict_list'");
131*0Sstevel@tonic-gate return (DCMD_ERR);
132*0Sstevel@tonic-gate }
133*0Sstevel@tonic-gate return (DCMD_OK);
134*0Sstevel@tonic-gate }
135*0Sstevel@tonic-gate
136*0Sstevel@tonic-gate if (DCMD_HDRSPEC(flags))
137*0Sstevel@tonic-gate mdb_printf("%<u>%2s %-27s %?s %7s %s%</u>\n",
138*0Sstevel@tonic-gate "ID", "NAME", "ADDR", "TYPE", "GLOBAL_FLAGS");
139*0Sstevel@tonic-gate
140*0Sstevel@tonic-gate if (mdb_vread(&dict, sizeof (dict), addr) == -1) {
141*0Sstevel@tonic-gate mdb_warn("failed to read rctl_dict at %p", addr);
142*0Sstevel@tonic-gate return (DCMD_ERR);
143*0Sstevel@tonic-gate }
144*0Sstevel@tonic-gate if (mdb_readstr(name, 256, (uintptr_t)(dict.rcd_name)) == -1) {
145*0Sstevel@tonic-gate mdb_warn("failed to read rctl_dict name for %p", addr);
146*0Sstevel@tonic-gate return (DCMD_ERR);
147*0Sstevel@tonic-gate }
148*0Sstevel@tonic-gate
149*0Sstevel@tonic-gate switch (dict.rcd_entity) {
150*0Sstevel@tonic-gate case RCENTITY_PROCESS:
151*0Sstevel@tonic-gate type = "process";
152*0Sstevel@tonic-gate break;
153*0Sstevel@tonic-gate case RCENTITY_TASK:
154*0Sstevel@tonic-gate type = "task";
155*0Sstevel@tonic-gate break;
156*0Sstevel@tonic-gate case RCENTITY_PROJECT:
157*0Sstevel@tonic-gate type = "project";
158*0Sstevel@tonic-gate break;
159*0Sstevel@tonic-gate case RCENTITY_ZONE:
160*0Sstevel@tonic-gate type = "zone";
161*0Sstevel@tonic-gate break;
162*0Sstevel@tonic-gate default:
163*0Sstevel@tonic-gate type = "unknown";
164*0Sstevel@tonic-gate break;
165*0Sstevel@tonic-gate }
166*0Sstevel@tonic-gate
167*0Sstevel@tonic-gate mdb_printf("%2d %-27s %0?p %7s 0x%08x", dict.rcd_id, name, addr,
168*0Sstevel@tonic-gate type, dict.rcd_flagaction);
169*0Sstevel@tonic-gate
170*0Sstevel@tonic-gate return (DCMD_OK);
171*0Sstevel@tonic-gate }
172*0Sstevel@tonic-gate
173*0Sstevel@tonic-gate typedef struct dict_data {
174*0Sstevel@tonic-gate rctl_hndl_t hndl;
175*0Sstevel@tonic-gate uintptr_t dict_addr;
176*0Sstevel@tonic-gate rctl_entity_t type;
177*0Sstevel@tonic-gate } dict_data_t;
178*0Sstevel@tonic-gate
179*0Sstevel@tonic-gate static int
hndl2dict(uintptr_t addr,rctl_dict_entry_t * entry,dict_data_t * data)180*0Sstevel@tonic-gate hndl2dict(uintptr_t addr, rctl_dict_entry_t *entry, dict_data_t *data)
181*0Sstevel@tonic-gate {
182*0Sstevel@tonic-gate if (data->hndl == entry->rcd_id) {
183*0Sstevel@tonic-gate data->dict_addr = addr;
184*0Sstevel@tonic-gate data->type = entry->rcd_entity;
185*0Sstevel@tonic-gate return (WALK_DONE);
186*0Sstevel@tonic-gate }
187*0Sstevel@tonic-gate
188*0Sstevel@tonic-gate return (WALK_NEXT);
189*0Sstevel@tonic-gate }
190*0Sstevel@tonic-gate
191*0Sstevel@tonic-gate /*
192*0Sstevel@tonic-gate * Print out all project, task, and process rctls for a given process.
193*0Sstevel@tonic-gate * If a handle is specified, print only the rctl matching that handle
194*0Sstevel@tonic-gate * for the process.
195*0Sstevel@tonic-gate */
196*0Sstevel@tonic-gate int
rctl_list(uintptr_t addr,uint_t flags,int argc,const mdb_arg_t * argv)197*0Sstevel@tonic-gate rctl_list(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv)
198*0Sstevel@tonic-gate {
199*0Sstevel@tonic-gate proc_t proc;
200*0Sstevel@tonic-gate uintptr_t set;
201*0Sstevel@tonic-gate task_t task;
202*0Sstevel@tonic-gate kproject_t proj;
203*0Sstevel@tonic-gate zone_t zone;
204*0Sstevel@tonic-gate dict_data_t rdict;
205*0Sstevel@tonic-gate int i;
206*0Sstevel@tonic-gate
207*0Sstevel@tonic-gate rdict.dict_addr = NULL;
208*0Sstevel@tonic-gate
209*0Sstevel@tonic-gate if (!(flags & DCMD_ADDRSPEC))
210*0Sstevel@tonic-gate return (DCMD_USAGE);
211*0Sstevel@tonic-gate
212*0Sstevel@tonic-gate if (argc == 0)
213*0Sstevel@tonic-gate rdict.hndl = 0;
214*0Sstevel@tonic-gate else if (argc == 1) {
215*0Sstevel@tonic-gate /*
216*0Sstevel@tonic-gate * User specified a handle. Go find the rctl_dict_entity_t
217*0Sstevel@tonic-gate * structure so we know what type of rctl to look for.
218*0Sstevel@tonic-gate */
219*0Sstevel@tonic-gate const mdb_arg_t *argp = &argv[0];
220*0Sstevel@tonic-gate
221*0Sstevel@tonic-gate if (argp->a_type == MDB_TYPE_IMMEDIATE)
222*0Sstevel@tonic-gate rdict.hndl = (rctl_hndl_t)argp->a_un.a_val;
223*0Sstevel@tonic-gate else
224*0Sstevel@tonic-gate rdict.hndl =
225*0Sstevel@tonic-gate (rctl_hndl_t)mdb_strtoull(argp->a_un.a_str);
226*0Sstevel@tonic-gate
227*0Sstevel@tonic-gate if (mdb_walk("rctl_dict_list", (mdb_walk_cb_t)hndl2dict,
228*0Sstevel@tonic-gate &rdict) == -1) {
229*0Sstevel@tonic-gate mdb_warn("failed to walk rctl_dict_list");
230*0Sstevel@tonic-gate return (DCMD_ERR);
231*0Sstevel@tonic-gate }
232*0Sstevel@tonic-gate /* Couldn't find a rctl_dict_entry_t for this handle */
233*0Sstevel@tonic-gate if (rdict.dict_addr == NULL)
234*0Sstevel@tonic-gate return (DCMD_ERR);
235*0Sstevel@tonic-gate } else
236*0Sstevel@tonic-gate return (DCMD_USAGE);
237*0Sstevel@tonic-gate
238*0Sstevel@tonic-gate
239*0Sstevel@tonic-gate if (mdb_vread(&proc, sizeof (proc_t), addr) == -1) {
240*0Sstevel@tonic-gate mdb_warn("failed to read proc at %p", addr);
241*0Sstevel@tonic-gate return (DCMD_ERR);
242*0Sstevel@tonic-gate }
243*0Sstevel@tonic-gate if (mdb_vread(&zone, sizeof (zone_t), (uintptr_t)proc.p_zone) == -1) {
244*0Sstevel@tonic-gate mdb_warn("failed to read zone at %p", proc.p_zone);
245*0Sstevel@tonic-gate return (DCMD_ERR);
246*0Sstevel@tonic-gate }
247*0Sstevel@tonic-gate if (mdb_vread(&task, sizeof (task_t), (uintptr_t)proc.p_task) == -1) {
248*0Sstevel@tonic-gate mdb_warn("failed to read task at %p", proc.p_task);
249*0Sstevel@tonic-gate return (DCMD_ERR);
250*0Sstevel@tonic-gate }
251*0Sstevel@tonic-gate if (mdb_vread(&proj, sizeof (kproject_t),
252*0Sstevel@tonic-gate (uintptr_t)task.tk_proj) == -1) {
253*0Sstevel@tonic-gate mdb_warn("failed to read proj at %p", task.tk_proj);
254*0Sstevel@tonic-gate return (DCMD_ERR);
255*0Sstevel@tonic-gate }
256*0Sstevel@tonic-gate
257*0Sstevel@tonic-gate for (i = 0; i <= RC_MAX_ENTITY; i++) {
258*0Sstevel@tonic-gate /*
259*0Sstevel@tonic-gate * If user didn't specify a handle, print rctls for all
260*0Sstevel@tonic-gate * types. Otherwise, we can walk the rctl_set for only the
261*0Sstevel@tonic-gate * entity specified by the handle.
262*0Sstevel@tonic-gate */
263*0Sstevel@tonic-gate if (rdict.hndl != 0 && rdict.type != i)
264*0Sstevel@tonic-gate continue;
265*0Sstevel@tonic-gate
266*0Sstevel@tonic-gate switch (i) {
267*0Sstevel@tonic-gate case (RCENTITY_PROCESS):
268*0Sstevel@tonic-gate set = (uintptr_t)proc.p_rctls;
269*0Sstevel@tonic-gate break;
270*0Sstevel@tonic-gate case (RCENTITY_TASK):
271*0Sstevel@tonic-gate set = (uintptr_t)task.tk_rctls;
272*0Sstevel@tonic-gate break;
273*0Sstevel@tonic-gate case (RCENTITY_PROJECT):
274*0Sstevel@tonic-gate set = (uintptr_t)proj.kpj_rctls;
275*0Sstevel@tonic-gate break;
276*0Sstevel@tonic-gate case (RCENTITY_ZONE):
277*0Sstevel@tonic-gate set = (uintptr_t)zone.zone_rctls;
278*0Sstevel@tonic-gate break;
279*0Sstevel@tonic-gate default:
280*0Sstevel@tonic-gate mdb_warn("Unknown rctl type %d", i);
281*0Sstevel@tonic-gate return (DCMD_ERR);
282*0Sstevel@tonic-gate }
283*0Sstevel@tonic-gate
284*0Sstevel@tonic-gate if (mdb_pwalk_dcmd("rctl_set", "rctl", argc, argv, set) == -1) {
285*0Sstevel@tonic-gate mdb_warn("failed to walk rctls in set %p", set);
286*0Sstevel@tonic-gate return (DCMD_ERR);
287*0Sstevel@tonic-gate }
288*0Sstevel@tonic-gate }
289*0Sstevel@tonic-gate
290*0Sstevel@tonic-gate return (DCMD_OK);
291*0Sstevel@tonic-gate }
292*0Sstevel@tonic-gate
293*0Sstevel@tonic-gate typedef struct dict_walk_data {
294*0Sstevel@tonic-gate int num_dicts;
295*0Sstevel@tonic-gate int num_cur;
296*0Sstevel@tonic-gate rctl_dict_entry_t **curdict;
297*0Sstevel@tonic-gate } dict_walk_data_t;
298*0Sstevel@tonic-gate
299*0Sstevel@tonic-gate int
rctl_dict_walk_init(mdb_walk_state_t * wsp)300*0Sstevel@tonic-gate rctl_dict_walk_init(mdb_walk_state_t *wsp)
301*0Sstevel@tonic-gate {
302*0Sstevel@tonic-gate uintptr_t ptr;
303*0Sstevel@tonic-gate int nlists;
304*0Sstevel@tonic-gate GElf_Sym sym;
305*0Sstevel@tonic-gate rctl_dict_entry_t **dicts;
306*0Sstevel@tonic-gate dict_walk_data_t *dwd;
307*0Sstevel@tonic-gate
308*0Sstevel@tonic-gate if (mdb_lookup_by_name("rctl_lists", &sym) == -1) {
309*0Sstevel@tonic-gate mdb_warn("failed to find 'rctl_lists'\n");
310*0Sstevel@tonic-gate return (WALK_ERR);
311*0Sstevel@tonic-gate }
312*0Sstevel@tonic-gate
313*0Sstevel@tonic-gate nlists = sym.st_size / sizeof (rctl_dict_entry_t *);
314*0Sstevel@tonic-gate ptr = (uintptr_t)sym.st_value;
315*0Sstevel@tonic-gate
316*0Sstevel@tonic-gate dicts = mdb_alloc(nlists * sizeof (rctl_dict_entry_t *), UM_SLEEP);
317*0Sstevel@tonic-gate mdb_vread(dicts, sym.st_size, ptr);
318*0Sstevel@tonic-gate
319*0Sstevel@tonic-gate dwd = mdb_alloc(sizeof (dict_walk_data_t), UM_SLEEP);
320*0Sstevel@tonic-gate dwd->num_dicts = nlists;
321*0Sstevel@tonic-gate dwd->num_cur = 0;
322*0Sstevel@tonic-gate dwd->curdict = dicts;
323*0Sstevel@tonic-gate
324*0Sstevel@tonic-gate wsp->walk_addr = 0;
325*0Sstevel@tonic-gate wsp->walk_data = dwd;
326*0Sstevel@tonic-gate
327*0Sstevel@tonic-gate return (WALK_NEXT);
328*0Sstevel@tonic-gate }
329*0Sstevel@tonic-gate
330*0Sstevel@tonic-gate int
rctl_dict_walk_step(mdb_walk_state_t * wsp)331*0Sstevel@tonic-gate rctl_dict_walk_step(mdb_walk_state_t *wsp)
332*0Sstevel@tonic-gate {
333*0Sstevel@tonic-gate dict_walk_data_t *dwd = wsp->walk_data;
334*0Sstevel@tonic-gate uintptr_t dp;
335*0Sstevel@tonic-gate rctl_dict_entry_t entry;
336*0Sstevel@tonic-gate int status;
337*0Sstevel@tonic-gate
338*0Sstevel@tonic-gate dp = (uintptr_t)((dwd->curdict)[dwd->num_cur]);
339*0Sstevel@tonic-gate
340*0Sstevel@tonic-gate while (dp != NULL) {
341*0Sstevel@tonic-gate if (mdb_vread(&entry, sizeof (rctl_dict_entry_t), dp) == -1) {
342*0Sstevel@tonic-gate mdb_warn("failed to read rctl_dict_entry_t structure "
343*0Sstevel@tonic-gate "at %p", dp);
344*0Sstevel@tonic-gate return (WALK_ERR);
345*0Sstevel@tonic-gate }
346*0Sstevel@tonic-gate
347*0Sstevel@tonic-gate status = wsp->walk_callback(dp, &entry, wsp->walk_cbdata);
348*0Sstevel@tonic-gate if (status != WALK_NEXT)
349*0Sstevel@tonic-gate return (status);
350*0Sstevel@tonic-gate
351*0Sstevel@tonic-gate dp = (uintptr_t)entry.rcd_next;
352*0Sstevel@tonic-gate }
353*0Sstevel@tonic-gate
354*0Sstevel@tonic-gate dwd->num_cur++;
355*0Sstevel@tonic-gate
356*0Sstevel@tonic-gate if (dwd->num_cur == dwd->num_dicts)
357*0Sstevel@tonic-gate return (WALK_DONE);
358*0Sstevel@tonic-gate
359*0Sstevel@tonic-gate return (WALK_NEXT);
360*0Sstevel@tonic-gate }
361*0Sstevel@tonic-gate
362*0Sstevel@tonic-gate void
rctl_dict_walk_fini(mdb_walk_state_t * wsp)363*0Sstevel@tonic-gate rctl_dict_walk_fini(mdb_walk_state_t *wsp)
364*0Sstevel@tonic-gate {
365*0Sstevel@tonic-gate dict_walk_data_t *wd = wsp->walk_data;
366*0Sstevel@tonic-gate mdb_free(wd->curdict, wd->num_dicts * sizeof (rctl_dict_entry_t *));
367*0Sstevel@tonic-gate mdb_free(wd, sizeof (dict_walk_data_t));
368*0Sstevel@tonic-gate }
369*0Sstevel@tonic-gate
370*0Sstevel@tonic-gate typedef struct set_walk_data {
371*0Sstevel@tonic-gate uint_t hashsize;
372*0Sstevel@tonic-gate int hashcur;
373*0Sstevel@tonic-gate void **hashloc;
374*0Sstevel@tonic-gate } set_walk_data_t;
375*0Sstevel@tonic-gate
376*0Sstevel@tonic-gate int
rctl_set_walk_init(mdb_walk_state_t * wsp)377*0Sstevel@tonic-gate rctl_set_walk_init(mdb_walk_state_t *wsp)
378*0Sstevel@tonic-gate {
379*0Sstevel@tonic-gate rctl_set_t rset;
380*0Sstevel@tonic-gate uint_t hashsz;
381*0Sstevel@tonic-gate set_walk_data_t *swd;
382*0Sstevel@tonic-gate rctl_t **rctls;
383*0Sstevel@tonic-gate
384*0Sstevel@tonic-gate if (mdb_vread(&rset, sizeof (rctl_set_t), wsp->walk_addr) == -1) {
385*0Sstevel@tonic-gate mdb_warn("failed to read rset at %p", wsp->walk_addr);
386*0Sstevel@tonic-gate return (WALK_ERR);
387*0Sstevel@tonic-gate }
388*0Sstevel@tonic-gate
389*0Sstevel@tonic-gate if (mdb_readvar(&hashsz, "rctl_set_size") == -1 || hashsz == 0) {
390*0Sstevel@tonic-gate mdb_warn("rctl_set_size not found or invalid");
391*0Sstevel@tonic-gate return (WALK_ERR);
392*0Sstevel@tonic-gate }
393*0Sstevel@tonic-gate
394*0Sstevel@tonic-gate rctls = mdb_alloc(hashsz * sizeof (rctl_t *), UM_SLEEP);
395*0Sstevel@tonic-gate if (mdb_vread(rctls, hashsz * sizeof (rctl_t *),
396*0Sstevel@tonic-gate (uintptr_t)rset.rcs_ctls) == -1) {
397*0Sstevel@tonic-gate mdb_warn("cannot read rctl hash at %p", rset.rcs_ctls);
398*0Sstevel@tonic-gate mdb_free(rctls, hashsz * sizeof (rctl_t *));
399*0Sstevel@tonic-gate return (WALK_ERR);
400*0Sstevel@tonic-gate }
401*0Sstevel@tonic-gate
402*0Sstevel@tonic-gate swd = mdb_alloc(sizeof (set_walk_data_t), UM_SLEEP);
403*0Sstevel@tonic-gate swd->hashsize = hashsz;
404*0Sstevel@tonic-gate swd->hashcur = 0;
405*0Sstevel@tonic-gate swd->hashloc = (void **)rctls;
406*0Sstevel@tonic-gate
407*0Sstevel@tonic-gate wsp->walk_addr = 0;
408*0Sstevel@tonic-gate wsp->walk_data = swd;
409*0Sstevel@tonic-gate
410*0Sstevel@tonic-gate return (WALK_NEXT);
411*0Sstevel@tonic-gate }
412*0Sstevel@tonic-gate
413*0Sstevel@tonic-gate
414*0Sstevel@tonic-gate int
rctl_set_walk_step(mdb_walk_state_t * wsp)415*0Sstevel@tonic-gate rctl_set_walk_step(mdb_walk_state_t *wsp)
416*0Sstevel@tonic-gate {
417*0Sstevel@tonic-gate set_walk_data_t *swd = wsp->walk_data;
418*0Sstevel@tonic-gate rctl_t rctl;
419*0Sstevel@tonic-gate void **rhash = swd->hashloc;
420*0Sstevel@tonic-gate int status;
421*0Sstevel@tonic-gate
422*0Sstevel@tonic-gate if (swd->hashcur >= swd->hashsize)
423*0Sstevel@tonic-gate return (WALK_DONE);
424*0Sstevel@tonic-gate
425*0Sstevel@tonic-gate if (wsp->walk_addr == NULL) {
426*0Sstevel@tonic-gate while (swd->hashcur < swd->hashsize) {
427*0Sstevel@tonic-gate if (rhash[swd->hashcur] != NULL) {
428*0Sstevel@tonic-gate break;
429*0Sstevel@tonic-gate }
430*0Sstevel@tonic-gate swd->hashcur++;
431*0Sstevel@tonic-gate }
432*0Sstevel@tonic-gate
433*0Sstevel@tonic-gate if (rhash[swd->hashcur] == NULL ||
434*0Sstevel@tonic-gate swd->hashcur >= swd->hashsize)
435*0Sstevel@tonic-gate return (WALK_DONE);
436*0Sstevel@tonic-gate
437*0Sstevel@tonic-gate wsp->walk_addr = (uintptr_t)rhash[swd->hashcur];
438*0Sstevel@tonic-gate swd->hashcur++;
439*0Sstevel@tonic-gate }
440*0Sstevel@tonic-gate
441*0Sstevel@tonic-gate if (mdb_vread(&rctl, sizeof (rctl_t), wsp->walk_addr) == -1) {
442*0Sstevel@tonic-gate wsp->walk_addr = NULL;
443*0Sstevel@tonic-gate mdb_warn("unable to read from %#p", wsp->walk_addr);
444*0Sstevel@tonic-gate return (WALK_ERR);
445*0Sstevel@tonic-gate }
446*0Sstevel@tonic-gate
447*0Sstevel@tonic-gate status = wsp->walk_callback(wsp->walk_addr, &rctl, wsp->walk_cbdata);
448*0Sstevel@tonic-gate
449*0Sstevel@tonic-gate wsp->walk_addr = (uintptr_t)rctl.rc_next;
450*0Sstevel@tonic-gate
451*0Sstevel@tonic-gate return (status);
452*0Sstevel@tonic-gate }
453*0Sstevel@tonic-gate
454*0Sstevel@tonic-gate void
rctl_set_walk_fini(mdb_walk_state_t * wsp)455*0Sstevel@tonic-gate rctl_set_walk_fini(mdb_walk_state_t *wsp)
456*0Sstevel@tonic-gate {
457*0Sstevel@tonic-gate set_walk_data_t *sd = wsp->walk_data;
458*0Sstevel@tonic-gate
459*0Sstevel@tonic-gate mdb_free(sd->hashloc, sd->hashsize * sizeof (rctl_t *));
460*0Sstevel@tonic-gate mdb_free(sd, sizeof (set_walk_data_t));
461*0Sstevel@tonic-gate }
462*0Sstevel@tonic-gate
463*0Sstevel@tonic-gate int
rctl_val_walk_init(mdb_walk_state_t * wsp)464*0Sstevel@tonic-gate rctl_val_walk_init(mdb_walk_state_t *wsp)
465*0Sstevel@tonic-gate {
466*0Sstevel@tonic-gate rctl_t rctl;
467*0Sstevel@tonic-gate
468*0Sstevel@tonic-gate if (mdb_vread(&rctl, sizeof (rctl_t), wsp->walk_addr) == -1) {
469*0Sstevel@tonic-gate mdb_warn("failed to read rctl at %p", wsp->walk_addr);
470*0Sstevel@tonic-gate return (WALK_ERR);
471*0Sstevel@tonic-gate }
472*0Sstevel@tonic-gate wsp->walk_addr = (uintptr_t)rctl.rc_values;
473*0Sstevel@tonic-gate wsp->walk_data = rctl.rc_values;
474*0Sstevel@tonic-gate return (WALK_NEXT);
475*0Sstevel@tonic-gate }
476*0Sstevel@tonic-gate
477*0Sstevel@tonic-gate int
rctl_val_walk_step(mdb_walk_state_t * wsp)478*0Sstevel@tonic-gate rctl_val_walk_step(mdb_walk_state_t *wsp)
479*0Sstevel@tonic-gate {
480*0Sstevel@tonic-gate rctl_val_t val;
481*0Sstevel@tonic-gate int status;
482*0Sstevel@tonic-gate
483*0Sstevel@tonic-gate if (mdb_vread(&val, sizeof (rctl_val_t), wsp->walk_addr) == -1) {
484*0Sstevel@tonic-gate mdb_warn("failed to read rctl_val at %p", wsp->walk_addr);
485*0Sstevel@tonic-gate return (WALK_DONE);
486*0Sstevel@tonic-gate }
487*0Sstevel@tonic-gate
488*0Sstevel@tonic-gate status = wsp->walk_callback(wsp->walk_addr, &val, wsp->walk_cbdata);
489*0Sstevel@tonic-gate
490*0Sstevel@tonic-gate if ((wsp->walk_addr = (uintptr_t)val.rcv_next) == NULL)
491*0Sstevel@tonic-gate return (WALK_DONE);
492*0Sstevel@tonic-gate
493*0Sstevel@tonic-gate return (status);
494*0Sstevel@tonic-gate }
495*0Sstevel@tonic-gate
496*0Sstevel@tonic-gate typedef struct rctl_val_seen {
497*0Sstevel@tonic-gate uintptr_t s_ptr;
498*0Sstevel@tonic-gate rctl_qty_t s_val;
499*0Sstevel@tonic-gate } rctl_val_seen_t;
500*0Sstevel@tonic-gate
501*0Sstevel@tonic-gate typedef struct rctl_validate_data {
502*0Sstevel@tonic-gate uintptr_t v_rctl_addr;
503*0Sstevel@tonic-gate rctl_val_t *v_cursor;
504*0Sstevel@tonic-gate uint_t v_flags;
505*0Sstevel@tonic-gate int v_bad_rctl;
506*0Sstevel@tonic-gate int v_cursor_valid;
507*0Sstevel@tonic-gate int v_circularity_detected;
508*0Sstevel@tonic-gate uint_t v_seen_size;
509*0Sstevel@tonic-gate uint_t v_seen_cnt;
510*0Sstevel@tonic-gate rctl_val_seen_t *v_seen;
511*0Sstevel@tonic-gate } rctl_validate_data_t;
512*0Sstevel@tonic-gate
513*0Sstevel@tonic-gate #define RCV_VERBOSE 0x1
514*0Sstevel@tonic-gate
515*0Sstevel@tonic-gate /*
516*0Sstevel@tonic-gate * rctl_val_validate()
517*0Sstevel@tonic-gate * Do validation on an individual rctl_val_t. This function is called
518*0Sstevel@tonic-gate * as part of the rctl_val walker, and helps perform the checks described
519*0Sstevel@tonic-gate * in the ::rctl_validate dcmd.
520*0Sstevel@tonic-gate */
521*0Sstevel@tonic-gate static int
rctl_val_validate(uintptr_t addr,rctl_val_t * val,rctl_validate_data_t * data)522*0Sstevel@tonic-gate rctl_val_validate(uintptr_t addr, rctl_val_t *val, rctl_validate_data_t *data)
523*0Sstevel@tonic-gate {
524*0Sstevel@tonic-gate int i;
525*0Sstevel@tonic-gate
526*0Sstevel@tonic-gate data->v_seen[data->v_seen_cnt].s_ptr = addr;
527*0Sstevel@tonic-gate
528*0Sstevel@tonic-gate if (addr == (uintptr_t)data->v_cursor)
529*0Sstevel@tonic-gate data->v_cursor_valid++;
530*0Sstevel@tonic-gate
531*0Sstevel@tonic-gate data->v_seen[data->v_seen_cnt].s_val = val->rcv_value;
532*0Sstevel@tonic-gate
533*0Sstevel@tonic-gate if (val->rcv_prev == (void *)0xbaddcafe ||
534*0Sstevel@tonic-gate val->rcv_next == (void *)0xbaddcafe ||
535*0Sstevel@tonic-gate val->rcv_prev == (void *)0xdeadbeef ||
536*0Sstevel@tonic-gate val->rcv_next == (void *)0xdeadbeef) {
537*0Sstevel@tonic-gate if (data->v_bad_rctl++ == 0)
538*0Sstevel@tonic-gate mdb_printf("%p ", data->v_rctl_addr);
539*0Sstevel@tonic-gate if (data->v_flags & RCV_VERBOSE)
540*0Sstevel@tonic-gate mdb_printf("/ uninitialized or previously "
541*0Sstevel@tonic-gate "freed link at %p ", addr);
542*0Sstevel@tonic-gate }
543*0Sstevel@tonic-gate
544*0Sstevel@tonic-gate if (data->v_seen_cnt == 0) {
545*0Sstevel@tonic-gate if (val->rcv_prev != NULL) {
546*0Sstevel@tonic-gate if (data->v_bad_rctl++ == 0)
547*0Sstevel@tonic-gate mdb_printf("%p ", data->v_rctl_addr);
548*0Sstevel@tonic-gate if (data->v_flags & RCV_VERBOSE)
549*0Sstevel@tonic-gate mdb_printf("/ bad prev pointer at "
550*0Sstevel@tonic-gate "head ");
551*0Sstevel@tonic-gate }
552*0Sstevel@tonic-gate } else {
553*0Sstevel@tonic-gate if ((uintptr_t)val->rcv_prev !=
554*0Sstevel@tonic-gate data->v_seen[data->v_seen_cnt - 1].s_ptr) {
555*0Sstevel@tonic-gate if (data->v_bad_rctl++ == 0)
556*0Sstevel@tonic-gate mdb_printf("%p ", data->v_rctl_addr);
557*0Sstevel@tonic-gate if (data->v_flags & RCV_VERBOSE)
558*0Sstevel@tonic-gate mdb_printf("/ bad prev pointer at %p ",
559*0Sstevel@tonic-gate addr);
560*0Sstevel@tonic-gate }
561*0Sstevel@tonic-gate
562*0Sstevel@tonic-gate if (data->v_seen[data->v_seen_cnt].s_val <
563*0Sstevel@tonic-gate data->v_seen[data->v_seen_cnt - 1].s_val) {
564*0Sstevel@tonic-gate if (data->v_bad_rctl++ == 0)
565*0Sstevel@tonic-gate mdb_printf("%p ", data->v_rctl_addr);
566*0Sstevel@tonic-gate if (data->v_flags & RCV_VERBOSE)
567*0Sstevel@tonic-gate mdb_printf("/ ordering error at %p ",
568*0Sstevel@tonic-gate addr);
569*0Sstevel@tonic-gate }
570*0Sstevel@tonic-gate }
571*0Sstevel@tonic-gate
572*0Sstevel@tonic-gate for (i = data->v_seen_cnt; i >= 0; i--) {
573*0Sstevel@tonic-gate if (data->v_seen[i].s_ptr == (uintptr_t)val->rcv_next) {
574*0Sstevel@tonic-gate if (data->v_bad_rctl++ == 0)
575*0Sstevel@tonic-gate mdb_printf("%p ", data->v_rctl_addr);
576*0Sstevel@tonic-gate if (data->v_flags & RCV_VERBOSE)
577*0Sstevel@tonic-gate mdb_printf("/ circular next pointer "
578*0Sstevel@tonic-gate "at %p ", addr);
579*0Sstevel@tonic-gate data->v_circularity_detected++;
580*0Sstevel@tonic-gate break;
581*0Sstevel@tonic-gate }
582*0Sstevel@tonic-gate }
583*0Sstevel@tonic-gate
584*0Sstevel@tonic-gate if (data->v_circularity_detected)
585*0Sstevel@tonic-gate return (WALK_DONE);
586*0Sstevel@tonic-gate
587*0Sstevel@tonic-gate data->v_seen_cnt++;
588*0Sstevel@tonic-gate if (data->v_seen_cnt >= data->v_seen_size) {
589*0Sstevel@tonic-gate uint_t new_seen_size = data->v_seen_size * 2;
590*0Sstevel@tonic-gate rctl_val_seen_t *tseen = mdb_zalloc(new_seen_size *
591*0Sstevel@tonic-gate sizeof (rctl_val_seen_t), UM_SLEEP | UM_GC);
592*0Sstevel@tonic-gate
593*0Sstevel@tonic-gate bcopy(data->v_seen, tseen, data->v_seen_size *
594*0Sstevel@tonic-gate sizeof (rctl_val_seen_t));
595*0Sstevel@tonic-gate
596*0Sstevel@tonic-gate data->v_seen = tseen;
597*0Sstevel@tonic-gate data->v_seen_size = new_seen_size;
598*0Sstevel@tonic-gate }
599*0Sstevel@tonic-gate
600*0Sstevel@tonic-gate return (WALK_NEXT);
601*0Sstevel@tonic-gate }
602*0Sstevel@tonic-gate
603*0Sstevel@tonic-gate /*
604*0Sstevel@tonic-gate * Validate a rctl pointer by checking:
605*0Sstevel@tonic-gate * - rctl_val_t's for that rctl form an ordered, non-circular list
606*0Sstevel@tonic-gate * - the cursor points to a rctl_val_t within that list
607*0Sstevel@tonic-gate * - there are no more than UINT64_MAX (or # specified by -n)
608*0Sstevel@tonic-gate * rctl_val_t's in the list
609*0Sstevel@tonic-gate */
610*0Sstevel@tonic-gate int
rctl_validate(uintptr_t addr,uint_t flags,int argc,const mdb_arg_t * argv)611*0Sstevel@tonic-gate rctl_validate(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv)
612*0Sstevel@tonic-gate {
613*0Sstevel@tonic-gate rctl_validate_data_t data;
614*0Sstevel@tonic-gate
615*0Sstevel@tonic-gate rctl_t r;
616*0Sstevel@tonic-gate
617*0Sstevel@tonic-gate uint64_t long_threshold = UINT64_MAX;
618*0Sstevel@tonic-gate
619*0Sstevel@tonic-gate /* Initialize validate data structure */
620*0Sstevel@tonic-gate data.v_rctl_addr = addr;
621*0Sstevel@tonic-gate data.v_flags = 0;
622*0Sstevel@tonic-gate data.v_bad_rctl = 0;
623*0Sstevel@tonic-gate data.v_seen_cnt = 0;
624*0Sstevel@tonic-gate data.v_cursor_valid = 0;
625*0Sstevel@tonic-gate data.v_circularity_detected = 0;
626*0Sstevel@tonic-gate data.v_seen_size = 1;
627*0Sstevel@tonic-gate data.v_seen = mdb_zalloc(data.v_seen_size * sizeof (rctl_val_seen_t),
628*0Sstevel@tonic-gate UM_SLEEP | UM_GC);
629*0Sstevel@tonic-gate
630*0Sstevel@tonic-gate if (!(flags & DCMD_ADDRSPEC))
631*0Sstevel@tonic-gate return (DCMD_USAGE);
632*0Sstevel@tonic-gate
633*0Sstevel@tonic-gate if (mdb_getopts(argc, argv,
634*0Sstevel@tonic-gate 'v', MDB_OPT_SETBITS, RCV_VERBOSE, &data.v_flags,
635*0Sstevel@tonic-gate 'n', MDB_OPT_UINT64, &long_threshold,
636*0Sstevel@tonic-gate NULL) != argc)
637*0Sstevel@tonic-gate return (DCMD_USAGE);
638*0Sstevel@tonic-gate
639*0Sstevel@tonic-gate if (mdb_vread(&r, sizeof (rctl_t), addr) != sizeof (rctl_t)) {
640*0Sstevel@tonic-gate mdb_warn("failed to read rctl structure at %p", addr);
641*0Sstevel@tonic-gate return (DCMD_ERR);
642*0Sstevel@tonic-gate }
643*0Sstevel@tonic-gate
644*0Sstevel@tonic-gate data.v_cursor = r.rc_cursor;
645*0Sstevel@tonic-gate
646*0Sstevel@tonic-gate if (data.v_cursor == NULL) {
647*0Sstevel@tonic-gate if (data.v_bad_rctl++ == 0)
648*0Sstevel@tonic-gate mdb_printf("%p ", addr);
649*0Sstevel@tonic-gate if (data.v_flags & RCV_VERBOSE)
650*0Sstevel@tonic-gate mdb_printf("/ NULL cursor seen ");
651*0Sstevel@tonic-gate } else if (data.v_cursor == (rctl_val_t *)0xbaddcafe) {
652*0Sstevel@tonic-gate if (data.v_bad_rctl++ == 0)
653*0Sstevel@tonic-gate mdb_printf("%p ", addr);
654*0Sstevel@tonic-gate if (data.v_flags & RCV_VERBOSE)
655*0Sstevel@tonic-gate mdb_printf("/ uninitialized cursor seen ");
656*0Sstevel@tonic-gate }
657*0Sstevel@tonic-gate
658*0Sstevel@tonic-gate /* Walk through each val in this rctl for individual validation. */
659*0Sstevel@tonic-gate if (mdb_pwalk("rctl_val", (mdb_walk_cb_t)rctl_val_validate, &data,
660*0Sstevel@tonic-gate addr) == -1) {
661*0Sstevel@tonic-gate mdb_warn("failed to walk all values for rctl_t %p", addr);
662*0Sstevel@tonic-gate return (DCMD_ERR);
663*0Sstevel@tonic-gate }
664*0Sstevel@tonic-gate
665*0Sstevel@tonic-gate if (data.v_seen_cnt >= long_threshold) {
666*0Sstevel@tonic-gate if (data.v_bad_rctl++ == 0)
667*0Sstevel@tonic-gate mdb_printf("%p ", addr);
668*0Sstevel@tonic-gate if (data.v_flags & RCV_VERBOSE)
669*0Sstevel@tonic-gate mdb_printf("/ sequence length = %d ",
670*0Sstevel@tonic-gate data.v_seen_cnt);
671*0Sstevel@tonic-gate }
672*0Sstevel@tonic-gate
673*0Sstevel@tonic-gate if (!data.v_cursor_valid) {
674*0Sstevel@tonic-gate if (data.v_bad_rctl++ == 0)
675*0Sstevel@tonic-gate mdb_printf("%p ", addr);
676*0Sstevel@tonic-gate if (data.v_flags & RCV_VERBOSE)
677*0Sstevel@tonic-gate mdb_printf("/ cursor outside sequence");
678*0Sstevel@tonic-gate }
679*0Sstevel@tonic-gate
680*0Sstevel@tonic-gate if (data.v_bad_rctl)
681*0Sstevel@tonic-gate mdb_printf("\n");
682*0Sstevel@tonic-gate
683*0Sstevel@tonic-gate if (data.v_circularity_detected)
684*0Sstevel@tonic-gate mdb_warn("circular list implies possible memory leak; "
685*0Sstevel@tonic-gate "recommend invoking ::findleaks");
686*0Sstevel@tonic-gate
687*0Sstevel@tonic-gate return (DCMD_OK);
688*0Sstevel@tonic-gate }
689