xref: /illumos-gate/usr/src/cmd/mdb/common/modules/hook/hook.c (revision 4eaa471005973e11a6110b69fe990530b3b95a38)
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 2008 Sun Microsystems, Inc.  All rights reserved.
23  * Use is subject to license terms.
24  */
25 
26 #include <sys/types.h>
27 #include <sys/rwlock.h>
28 #include <mdb/mdb_modapi.h>
29 #include <sys/queue.h>
30 #include <inet/ip.h>
31 #include <sys/hook.h>
32 #include <sys/hook_impl.h>
33 
34 #define	MAX_LENGTH 64
35 
36 /*
37  * List pfhooks hook list information.
38  */
39 /*ARGSUSED*/
40 int
41 hooklist(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv)
42 {
43 	hook_event_int_t hr;
44 	hook_int_t hl, *hlp;
45 	char hrstr[MAX_LENGTH];
46 	GElf_Sym sym;
47 	char buf[MDB_SYM_NAMLEN + 1];
48 	char *hintname;
49 	hook_t *h;
50 
51 	if (argc)
52 		return (DCMD_USAGE);
53 
54 	if (mdb_vread((void *)&hr, sizeof (hr), (uintptr_t)addr) == -1) {
55 		mdb_warn("couldn't read hook register at %p", addr);
56 		return (DCMD_ERR);
57 	}
58 
59 	mdb_printf("%<u>%?s %8s %20s %4s %24s %24s%</u>\n",
60 	    "ADDR", "FLAG", "FUNC", "HINT", "NAME", "HINTVALUE");
61 	h = &hl.hi_hook;
62 	hlp = TAILQ_FIRST(&hr.hei_head);
63 	while (hlp) {
64 		if (mdb_vread((void *)&hl, sizeof (hl),
65 		    (uintptr_t)hlp) == -1) {
66 			mdb_warn("couldn't read hook list at %p",
67 			    hlp);
68 			return (DCMD_ERR);
69 		}
70 		if (!h->h_name) {
71 			mdb_warn("hook list at %p has null role", h);
72 			return (DCMD_ERR);
73 		}
74 		if (mdb_readstr((char *)hrstr, sizeof (hrstr),
75 		    (uintptr_t)h->h_name) == -1) {
76 			mdb_warn("couldn't read list role at %p", h->h_name);
77 			return (DCMD_ERR);
78 		}
79 		switch (h->h_hint) {
80 		case HH_BEFORE :
81 		case HH_AFTER :
82 			hintname =  h->h_hintvalue ?
83 			    (char *)h->h_hintvalue : "";
84 			break;
85 		default :
86 			hintname = "";
87 			break;
88 		}
89 		if (mdb_lookup_by_addr((uintptr_t)h->h_func,
90 		    MDB_SYM_EXACT, buf, sizeof (buf), &sym) == -1)
91 			mdb_printf("%0?p %8x %0?p %4d %24s %24s\n",
92 			    hlp, h->h_flags, h->h_func,
93 			    h->h_hint, hrstr, hintname);
94 		else
95 			mdb_printf("%0?p %8x %20s %4d %24s %24s\n",
96 			    hlp, h->h_flags, buf,
97 			    h->h_hint, hrstr, hintname);
98 		hlp = TAILQ_NEXT(&hl, hi_entry);
99 	}
100 	return (DCMD_OK);
101 }
102 
103 /*
104  * List pfhooks event information.
105  * List the hooks information in verbose mode as well.
106  */
107 /*ARGSUSED*/
108 int
109 hookeventlist(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv)
110 {
111 	hook_family_int_t hf;
112 	hook_event_int_t hr, *hrp;
113 	hook_event_t hp;
114 	char hprstr[MAX_LENGTH];
115 
116 	if (argc)
117 		return (DCMD_USAGE);
118 
119 	if (mdb_vread((void *)&hf, sizeof (hf), (uintptr_t)addr) == -1) {
120 		mdb_warn("couldn't read hook family at %p", addr);
121 		return (DCMD_ERR);
122 	}
123 
124 	mdb_printf("%<u>%?s %10s %20s%</u>\n", "ADDR", "FLAG", "NAME");
125 	hrp = SLIST_FIRST(&hf.hfi_head);
126 	while (hrp) {
127 		if (mdb_vread((void *)&hr, sizeof (hr), (uintptr_t)hrp) == -1) {
128 			mdb_warn("couldn't read hook register at %p", hrp);
129 			return (DCMD_ERR);
130 		}
131 		if (!hr.hei_event) {
132 			mdb_warn("hook register at %p has no hook provider",
133 			    hrp);
134 			return (DCMD_ERR);
135 		}
136 		if (mdb_vread((void *)&hp, sizeof (hp),
137 		    (uintptr_t)hr.hei_event) == -1) {
138 			mdb_warn("hook provider at %p has null role",
139 			    hr.hei_event);
140 			return (DCMD_ERR);
141 		}
142 		if (!hp.he_name) {
143 			mdb_warn("hook provider at %p has null role",
144 			    hr.hei_event);
145 			return (DCMD_ERR);
146 		}
147 		if (mdb_readstr((char *)hprstr, sizeof (hprstr),
148 		    (uintptr_t)hp.he_name) == -1) {
149 			mdb_warn("couldn't read provider role at %p",
150 			    hp.he_name);
151 			return (DCMD_ERR);
152 		}
153 		mdb_printf("%0?p %10x %20s\n", hrp, hp.he_flags, hprstr);
154 		hrp = SLIST_NEXT(&hr, hei_entry);
155 	}
156 
157 	return (DCMD_OK);
158 }
159 
160 /*
161  * List pfhooks family information.
162  */
163 /*ARGSUSED*/
164 int
165 hookrootlist(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv)
166 {
167 	struct hook_stack *hks;
168 	hook_family_int_head_t hfh;
169 	hook_family_int_t hf, *hfp;
170 	char hrrstr[MAX_LENGTH];
171 
172 	if (argc)
173 		return (DCMD_USAGE);
174 
175 	if (mdb_vread((void *)&hks, sizeof (hks),
176 	    (uintptr_t)(addr + OFFSETOF(netstack_t, netstack_hook))) == -1) {
177 		mdb_warn("couldn't read netstack_hook");
178 		return (DCMD_ERR);
179 	}
180 
181 	if (mdb_vread((void *)&hfh, sizeof (hfh), (uintptr_t)((uintptr_t)hks +
182 	    OFFSETOF(hook_stack_t, hks_familylist))) == -1) {
183 		mdb_warn("couldn't read hook family head");
184 		return (DCMD_ERR);
185 	}
186 
187 	mdb_printf("%<u>%?s %10s%</u>\n", "ADDR", "FAMILY");
188 	hfp = SLIST_FIRST(&hfh);
189 	while (hfp) {
190 		if (mdb_vread((void *)&hf, sizeof (hf), (uintptr_t)hfp) == -1) {
191 			mdb_warn("couldn't read hook family at %p", hfp);
192 			return (DCMD_ERR);
193 		}
194 		if (!hf.hfi_family.hf_name) {
195 			mdb_warn("hook root at %p has null role",
196 			    hf.hfi_family);
197 			return (DCMD_ERR);
198 		}
199 		if (mdb_readstr((char *)hrrstr, sizeof (hrrstr),
200 		    (uintptr_t)hf.hfi_family.hf_name) == -1) {
201 			mdb_warn("couldn't read root role at %p",
202 			    hf.hfi_family.hf_name);
203 			return (DCMD_ERR);
204 		}
205 		mdb_printf("%0?p %10s\n", hfp, hrrstr);
206 		hfp = SLIST_NEXT(&hf, hfi_entry);
207 	}
208 
209 	return (DCMD_OK);
210 }
211 
212 
213 static int
214 hookevent_stack_walk_init(mdb_walk_state_t *wsp)
215 {
216 	hook_family_int_t hf;
217 
218 	if (wsp->walk_addr == NULL) {
219 		mdb_warn("global walk not supported\n");
220 		return (WALK_ERR);
221 	}
222 
223 	if (mdb_vread((void *)&hf, sizeof (hf),
224 	    (uintptr_t)wsp->walk_addr) == -1) {
225 		mdb_warn("couldn't read hook family at %p", wsp->walk_addr);
226 		return (DCMD_ERR);
227 	}
228 	wsp->walk_addr = (uintptr_t)SLIST_FIRST(&hf.hfi_head);
229 	return (wsp->walk_callback(wsp->walk_addr, wsp->walk_data,
230 	    wsp->walk_cbdata));
231 }
232 
233 static int
234 hookevent_stack_walk_step(mdb_walk_state_t *wsp)
235 {
236 	hook_event_int_t hr;
237 
238 	if (mdb_vread((void *)&hr, sizeof (hr),
239 	    (uintptr_t)wsp->walk_addr) == -1) {
240 		mdb_warn("couldn't read hook event at %p", wsp->walk_addr);
241 		return (DCMD_ERR);
242 	}
243 	wsp->walk_addr = (uintptr_t)SLIST_NEXT(&hr, hei_entry);
244 	if (wsp->walk_addr == NULL)
245 		return (WALK_DONE);
246 	return (wsp->walk_callback(wsp->walk_addr, wsp->walk_data,
247 	    wsp->walk_cbdata));
248 }
249 
250 static const mdb_dcmd_t dcmds[] = {
251 	{ "hookrootlist", "", "display hook family information", hookrootlist },
252 	{ "hookeventlist", "", "display hook event information",
253 		hookeventlist, NULL },
254 	{ "hooklist", "", "display hooks", hooklist },
255 	{ NULL }
256 };
257 
258 static const mdb_walker_t walkers[] = {
259 	{ "hookevent_stack", "walk list of hooks",
260 		hookevent_stack_walk_init, hookevent_stack_walk_step, NULL },
261 	{ NULL }
262 };
263 
264 static const mdb_modinfo_t modinfo = { MDB_API_VERSION, dcmds, walkers };
265 
266 const mdb_modinfo_t *
267 _mdb_init(void)
268 {
269 	return (&modinfo);
270 }
271