1 /*
2  * CDDL HEADER START
3  *
4  * The contents of this file are subject to the terms of the
5  * Common Development and Distribution License (the "License").
6  * You may not use this file except in compliance with the License.
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 /*
23  * Copyright 2007 Sun Microsystems, Inc.  All rights reserved.
24  * Use is subject to license terms.
25  */
26 
27 /*
28  * Display group information and walk all elements of a group
29  */
30 
31 #include "group.h"
32 
33 #include <mdb/mdb_modapi.h>
34 #include <sys/group.h>
35 
36 /*
37  * Display group information
38  */
39 
40 /* ARGSUSED */
41 int
42 group(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv)
43 {
44 	group_t	group;
45 	int	opt_q = 0; /* display only address. */
46 
47 	/* Should provide an address */
48 	if (!(flags & DCMD_ADDRSPEC))
49 		return (DCMD_USAGE);
50 
51 	if (mdb_getopts(argc, argv,
52 	    'q', MDB_OPT_SETBITS, TRUE, &opt_q,
53 		NULL) != argc)
54 		return (DCMD_USAGE);
55 
56 	if (flags & DCMD_PIPE_OUT)
57 		opt_q = B_TRUE;
58 
59 	if (DCMD_HDRSPEC(flags) && !opt_q) {
60 		mdb_printf("%?s %6s %9s %?s\n",
61 		    "ADDR",
62 		    "SIZE",
63 		    "CAPACITY",
64 		    "SET");
65 	}
66 
67 	if (mdb_vread(&group, sizeof (struct group), addr) == -1) {
68 		mdb_warn("unable to read 'group' at %p", addr);
69 		return (DCMD_ERR);
70 	}
71 
72 	if (opt_q) {
73 		mdb_printf("%0?p\n", addr);
74 		return (DCMD_OK);
75 	}
76 
77 	mdb_printf("%?p %6d %9d %?p\n",
78 	    addr, group.grp_size, group.grp_capacity, group.grp_set);
79 
80 	return (DCMD_OK);
81 }
82 
83 /*
84  * Walk all elements in the group set.
85  */
86 
87 typedef struct group_walk {
88 	uintptr_t *gw_set;
89 	int gw_size;
90 	int gw_pos;
91 	int gw_initialized;
92 } group_walk_t;
93 
94 
95 /*
96  * Initialize the walk structure with the copy of a group set, its size and the
97  * initial pointer position.
98  */
99 int
100 group_walk_init(mdb_walk_state_t *wsp)
101 {
102 	group_walk_t	*gw;
103 	group_t		group;
104 
105 	gw = mdb_alloc(sizeof (group_walk_t), UM_SLEEP | UM_GC);
106 
107 	if (mdb_vread(&group, sizeof (struct group), wsp->walk_addr) == -1) {
108 		mdb_warn("couldn't read 'group' at %p", wsp->walk_addr);
109 		return (WALK_ERR);
110 	}
111 
112 	gw->gw_size = group.grp_size;
113 	gw->gw_initialized = 0;
114 	gw->gw_pos = 0;
115 
116 	if (gw->gw_size < 0) {
117 		mdb_warn("invalid group at %p", wsp->walk_addr);
118 		return (WALK_ERR);
119 	}
120 
121 	if (gw->gw_size == 0)
122 		return (WALK_DONE);
123 
124 	/*
125 	 * Allocate space for the set and copy all set entries.
126 	 */
127 	gw->gw_set = mdb_alloc(group.grp_size * sizeof (uintptr_t),
128 	    UM_SLEEP | UM_GC);
129 
130 	if (mdb_vread(gw->gw_set, group.grp_size * sizeof (uintptr_t),
131 	    (uintptr_t)group.grp_set) == -1) {
132 		mdb_warn("couldn't read 'group set' at %p", group.grp_set);
133 		return (WALK_ERR);
134 	}
135 
136 	wsp->walk_data = gw;
137 	wsp->walk_addr = gw->gw_set[0];
138 	gw->gw_pos = 0;
139 
140 	return (WALK_NEXT);
141 }
142 
143 /*
144  * Print element of the set and advance the pointer.
145  */
146 int
147 group_walk_step(mdb_walk_state_t *wsp)
148 {
149 	group_walk_t *gw = (group_walk_t *)wsp->walk_data;
150 	int status;
151 
152 	/*
153 	 * Already visited all valid elements, nothing else to do.
154 	 */
155 	if (gw->gw_size < 0)
156 		return (WALK_DONE);
157 
158 	/*
159 	 * Print non-NULL elements
160 	 */
161 	status = wsp->walk_addr == 0 ?
162 	    WALK_NEXT :
163 	    wsp->walk_callback(wsp->walk_addr, wsp->walk_data,
164 		wsp->walk_cbdata);
165 
166 	/*
167 	 * Adjust walk_addr to point to the next element
168 	 */
169 	gw->gw_size--;
170 
171 	if (gw->gw_size > 0)
172 		wsp->walk_addr = gw->gw_set[++gw->gw_pos];
173 	else
174 		status = WALK_DONE;
175 
176 	return (status);
177 }
178