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 * Copyright 2006 Sun Microsystems, Inc. All rights reserved.
23 * Use is subject to license terms.
24 */
25
26 #pragma ident "%Z%%M% %I% %E% SMI"
27
28 #include <sys/types.h>
29 #include <sys/tsol/tndb.h>
30 #include <sys/modhash_impl.h>
31
32 #include <mdb/mdb_modapi.h>
33 #include <mdb/mdb_ks.h>
34
35 #include "tsol.h"
36 #include "modhash.h"
37
38 /* ****************** tnrh ****************** */
39
40 typedef struct tnrh_walk_s {
41 tnrhc_hash_t **hptr;
42 int idx;
43 tnrhc_hash_t *tnrhc_table[TSOL_MASK_TABLE_SIZE];
44 tnrhc_hash_t *tnrhc_table_v6[TSOL_MASK_TABLE_SIZE_V6];
45 } tnrh_walk_t;
46
47 /*
48 * Free the mdb storage pointed to by the given per-prefix table.
49 */
50 static void
free_table(tnrhc_hash_t ** table,int ntable)51 free_table(tnrhc_hash_t **table, int ntable)
52 {
53 while (--ntable >= 0) {
54 if (*table != NULL)
55 mdb_free(*table, TNRHC_SIZE * sizeof (**table));
56 table++;
57 }
58 }
59
60 /*
61 * Read in a list of per-prefix-length hash tables. Allocate storage for the
62 * hashes that are present. On successful return, the table will contain
63 * pointers to mdb-resident storage, not kernel addresses. On failure, the
64 * contents will not point to any mdb storage.
65 */
66 static int
read_table(const char * symname,tnrhc_hash_t ** table,int ntable)67 read_table(const char *symname, tnrhc_hash_t **table, int ntable)
68 {
69 GElf_Sym tnrhc_hash;
70 tnrhc_hash_t **hp;
71 uintptr_t addr;
72
73 if (mdb_lookup_by_name(symname, &tnrhc_hash) == -1) {
74 mdb_warn("failed to read %s", symname);
75 return (-1);
76 }
77 if (mdb_vread(table, ntable * sizeof (*table),
78 tnrhc_hash.st_value) == -1) {
79 mdb_warn("can't read %s at %p", symname, tnrhc_hash.st_value);
80 return (-1);
81 }
82 for (hp = table; hp < table + ntable; hp++) {
83 if ((addr = (uintptr_t)*hp) != 0) {
84 *hp = mdb_alloc(TNRHC_SIZE * sizeof (**hp), UM_SLEEP);
85 if (mdb_vread(*hp, TNRHC_SIZE * sizeof (**hp),
86 addr) == -1) {
87 mdb_warn("can't read %s[%d] at %p", symname,
88 hp - table, addr);
89 free_table(table, (hp - table) + 1);
90 return (-1);
91 }
92 }
93 }
94 return (0);
95 }
96
97 int
tnrh_walk_init(mdb_walk_state_t * wsp)98 tnrh_walk_init(mdb_walk_state_t *wsp)
99 {
100 tnrh_walk_t *twp;
101
102 twp = mdb_alloc(sizeof (*twp), UM_SLEEP);
103
104 if (read_table("tnrhc_table", twp->tnrhc_table,
105 TSOL_MASK_TABLE_SIZE) == -1) {
106 mdb_free(twp, sizeof (*twp));
107 return (WALK_ERR);
108 }
109 if (read_table("tnrhc_table_v6", twp->tnrhc_table_v6,
110 TSOL_MASK_TABLE_SIZE_V6) == -1) {
111 free_table(twp->tnrhc_table, TSOL_MASK_TABLE_SIZE);
112 mdb_free(twp, sizeof (*twp));
113 return (WALK_ERR);
114 }
115
116 twp->hptr = twp->tnrhc_table;
117 twp->idx = 0;
118 wsp->walk_addr = 0;
119 wsp->walk_data = twp;
120
121 return (WALK_NEXT);
122 }
123
124 int
tnrh_walk_step(mdb_walk_state_t * wsp)125 tnrh_walk_step(mdb_walk_state_t *wsp)
126 {
127 tnrh_walk_t *twp = wsp->walk_data;
128 tsol_tnrhc_t tnrhc;
129 int status;
130
131 while (wsp->walk_addr == NULL) {
132 if (*twp->hptr == NULL || twp->idx >= TNRHC_SIZE) {
133 twp->hptr++;
134 if (twp->hptr == twp->tnrhc_table +
135 TSOL_MASK_TABLE_SIZE)
136 twp->hptr = twp->tnrhc_table_v6;
137 else if (twp->hptr == twp->tnrhc_table_v6 +
138 TSOL_MASK_TABLE_SIZE_V6)
139 return (WALK_DONE);
140 twp->idx = 0;
141 } else {
142 wsp->walk_addr = (uintptr_t)(*twp->hptr)[twp->idx++].
143 tnrh_list;
144 }
145 }
146
147 if (mdb_vread(&tnrhc, sizeof (tnrhc), wsp->walk_addr) == -1) {
148 mdb_warn("can't read tsol_tnrhc_t at %p", wsp->walk_addr);
149 return (WALK_ERR);
150 }
151
152 status = wsp->walk_callback(wsp->walk_addr, &tnrhc,
153 wsp->walk_cbdata);
154
155 wsp->walk_addr = (uintptr_t)tnrhc.rhc_next;
156 return (status);
157 }
158
159 void
tnrh_walk_fini(mdb_walk_state_t * wsp)160 tnrh_walk_fini(mdb_walk_state_t *wsp)
161 {
162 tnrh_walk_t *twp = wsp->walk_data;
163
164 free_table(twp->tnrhc_table, TSOL_MASK_TABLE_SIZE);
165 free_table(twp->tnrhc_table_v6, TSOL_MASK_TABLE_SIZE_V6);
166 mdb_free(twp, sizeof (*twp));
167 }
168
169 /* ****************** tnrhtp ****************** */
170
171 typedef struct tnrhtp_walk_data_s {
172 int (*old_callback)(uintptr_t, const void *, void *);
173 void *old_cbdata;
174 } tnrhtp_walk_data_t;
175
176 /* ARGSUSED */
177 static int
tnrhtp_walk_callback(uintptr_t addr,const void * data,void * private)178 tnrhtp_walk_callback(uintptr_t addr, const void *data, void *private)
179 {
180 const struct mod_hash_entry *mhe = data;
181 tnrhtp_walk_data_t *twd = private;
182 tsol_tpc_t tpc;
183
184 if (mdb_vread(&tpc, sizeof (tpc), (uintptr_t)mhe->mhe_val) == -1) {
185 mdb_warn("failed to read tsol_tpc_t at %p", mhe->mhe_val);
186 return (WALK_ERR);
187 } else {
188 return (twd->old_callback((uintptr_t)mhe->mhe_val, &tpc,
189 twd->old_cbdata));
190 }
191 }
192
193 int
tnrhtp_walk_init(mdb_walk_state_t * wsp)194 tnrhtp_walk_init(mdb_walk_state_t *wsp)
195 {
196 mod_hash_t *tpc_name_hash;
197
198 if (mdb_readvar(&tpc_name_hash, "tpc_name_hash") == -1) {
199 mdb_warn("failed to read tpc_name_hash");
200 return (WALK_ERR);
201 }
202
203 wsp->walk_addr = (uintptr_t)tpc_name_hash;
204
205 return (modent_walk_init(wsp));
206 }
207
208 int
tnrhtp_walk_step(mdb_walk_state_t * wsp)209 tnrhtp_walk_step(mdb_walk_state_t *wsp)
210 {
211 tnrhtp_walk_data_t twd;
212 int retv;
213
214 twd.old_callback = wsp->walk_callback;
215 twd.old_cbdata = wsp->walk_cbdata;
216 wsp->walk_callback = tnrhtp_walk_callback;
217 wsp->walk_cbdata = &twd;
218
219 retv = modent_walk_step(wsp);
220
221 wsp->walk_callback = twd.old_callback;
222 wsp->walk_cbdata = twd.old_cbdata;
223
224 return (retv);
225 }
226
227 void
tnrhtp_walk_fini(mdb_walk_state_t * wsp)228 tnrhtp_walk_fini(mdb_walk_state_t *wsp)
229 {
230 modent_walk_fini(wsp);
231 }
232