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