xref: /netbsd-src/sys/kern/kern_scdebug.c (revision f31867506b3d03104824848de4007d9c967e81b2)
1 /*	$NetBSD: kern_scdebug.c,v 1.2 2019/03/14 19:51:49 palle Exp $	*/
2 
3 /*
4  * Copyright (c) 2015 Matthew R. Green
5  * All rights reserved.
6  *
7  * Redistribution and use in source and binary forms, with or without
8  * modification, are permitted provided that the following conditions
9  * are met:
10  * 1. Redistributions of source code must retain the above copyright
11  *    notice, this list of conditions and the following disclaimer.
12  * 2. Redistributions in binary form must reproduce the above copyright
13  *    notice, this list of conditions and the following disclaimer in the
14  *    documentation and/or other materials provided with the distribution.
15  *
16  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
17  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
18  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
19  * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
20  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
21  * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
22  * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
23  * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
24  * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
25  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
26  * SUCH DAMAGE.
27  */
28 
29 /*
30  * Copyright (c) 1982, 1986, 1989, 1993
31  *	The Regents of the University of California.  All rights reserved.
32  *
33  * Redistribution and use in source and binary forms, with or without
34  * modification, are permitted provided that the following conditions
35  * are met:
36  * 1. Redistributions of source code must retain the above copyright
37  *    notice, this list of conditions and the following disclaimer.
38  * 2. Redistributions in binary form must reproduce the above copyright
39  *    notice, this list of conditions and the following disclaimer in the
40  *    documentation and/or other materials provided with the distribution.
41  * 3. Neither the name of the University nor the names of its contributors
42  *    may be used to endorse or promote products derived from this software
43  *    without specific prior written permission.
44  *
45  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
46  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
47  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
48  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
49  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
50  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
51  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
52  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
53  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
54  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
55  * SUCH DAMAGE.
56  *
57  *	@(#)kern_xxx.c	8.3 (Berkeley) 2/14/95
58  *	from: NetBSD: kern_xxx.c,v 1.74 2017/10/28 00:37:11 pgoyette Exp
59  */
60 
61 #include <sys/cdefs.h>
62 __KERNEL_RCSID(0, "$NetBSD: kern_scdebug.c,v 1.2 2019/03/14 19:51:49 palle Exp $");
63 
64 #ifdef _KERNEL_OPT
65 #include "opt_syscall_debug.h"
66 #include "opt_kernhist.h"
67 #endif
68 
69 #include <sys/param.h>
70 #include <sys/systm.h>
71 #include <sys/kernel.h>
72 #include <sys/proc.h>
73 #include <sys/sysctl.h>
74 #include <sys/mount.h>
75 #include <sys/syscall.h>
76 #include <sys/syscallargs.h>
77 #include <sys/kernhist.h>
78 
79 /*
80  * Pull in the indirect syscall functions here.
81  * They are only actually used if the ports syscall entry code
82  * doesn't special-case SYS_SYSCALL and SYS___SYSCALL
83  *
84  * In some cases the generated code for the two functions is identical,
85  * but there isn't a MI way of determining that - so we don't try.
86  */
87 
88 #define SYS_SYSCALL sys_syscall
89 #include "sys_syscall.c"
90 #undef SYS_SYSCALL
91 
92 #define SYS_SYSCALL sys___syscall
93 #include "sys_syscall.c"
94 #undef SYS_SYSCALL
95 
96 #ifdef SYSCALL_DEBUG
97 #define	SCDEBUG_CALLS		0x0001	/* show calls */
98 #define	SCDEBUG_RETURNS		0x0002	/* show returns */
99 #define	SCDEBUG_ALL		0x0004	/* even syscalls that are not implemented */
100 #define	SCDEBUG_SHOWARGS	0x0008	/* show arguments to calls */
101 #define	SCDEBUG_KERNHIST	0x0010	/* use kernhist instead of printf */
102 
103 #ifndef SCDEBUG_DEFAULT
104 #define SCDEBUG_DEFAULT (SCDEBUG_CALLS|SCDEBUG_RETURNS|SCDEBUG_SHOWARGS)
105 #endif
106 
107 int	scdebug = SCDEBUG_DEFAULT;
108 
109 #ifdef KERNHIST
110 KERNHIST_DEFINE(scdebughist);
111 #define SCDEBUG_KERNHIST_FUNC(a)		KERNHIST_FUNC(a)
112 #define SCDEBUG_KERNHIST_CALLED(a)		KERNHIST_CALLED(a)
113 #define SCDEBUG_KERNHIST_LOG(a,b,c,d,e,f)	KERNHIST_LOG(a,b,c,d,e,f)
114 #else
115 #define SCDEBUG_KERNHIST_FUNC(a)		{} /* nothing */
116 #define SCDEBUG_KERNHIST_CALLED(a)		{} /* nothing */
117 #define SCDEBUG_KERNHIST_LOG(a,b,c,d,e,f)	{} /* nothing */
118 /* The non-kernhist support version can elide all this code easily. */
119 #undef	SCDEBUG_KERNHIST
120 #define	SCDEBUG_KERNHIST 0
121 #endif
122 
123 #ifdef __HAVE_MINIMAL_EMUL
124 #define CODE_NOT_OK(code, em)	((int)(code) < 0)
125 #else
126 #define CODE_NOT_OK(code, em)	(((int)(code) < 0) || \
127 				 ((int)(code) >= (em)->e_nsysent))
128 #endif
129 
130 void
131 scdebug_call(register_t code, const register_t args[])
132 {
133 	SCDEBUG_KERNHIST_FUNC("scdebug_call");
134 	struct lwp *l = curlwp;
135 	struct proc *p = l->l_proc;
136 	const struct sysent *sy;
137 	const struct emul *em;
138 	int i;
139 
140 	if ((scdebug & SCDEBUG_CALLS) == 0)
141 		return;
142 
143 	if (scdebug & SCDEBUG_KERNHIST)
144 		SCDEBUG_KERNHIST_CALLED(scdebughist);
145 
146 	em = p->p_emul;
147 	sy = &em->e_sysent[code];
148 
149 	if ((scdebug & SCDEBUG_ALL) == 0 &&
150 	    (CODE_NOT_OK(code, em) || sy->sy_call == sys_nosys)) {
151 		if (scdebug & SCDEBUG_KERNHIST)
152 			SCDEBUG_KERNHIST_LOG(scdebughist, "", 0, 0, 0, 0);
153 		return;
154 	}
155 
156 	/*
157 	 * The kernhist version of scdebug needs to restrict the usage
158 	 * compared to the normal version.  histories must avoid these
159 	 * sorts of usage:
160 	 *
161 	 *	- the format string *must* be literal, as it is used
162 	 *	  at display time in the kernel or userland
163 	 *	- strings in the format will cause vmstat -u to crash
164 	 *	  so avoid using %s formats
165 	 *
166 	 * to avoid these, we have a fairly long block to print args
167 	 * as the format needs to change for each, and we can't just
168 	 * call printf() on each argument until we're done.
169 	 */
170 	if (scdebug & SCDEBUG_KERNHIST) {
171 		if (CODE_NOT_OK(code, em)) {
172 			SCDEBUG_KERNHIST_LOG(scdebughist,
173 			    "pid %jd:%jd: OUT OF RANGE (%jd)",
174 			    p->p_pid, l->l_lid, code, 0);
175 		} else {
176 			SCDEBUG_KERNHIST_LOG(scdebughist,
177 			    "pid %jd:%jd: num %jd call %#jx",
178 			    p->p_pid, l->l_lid, code, (uintptr_t)sy->sy_call);
179 			if ((scdebug & SCDEBUG_SHOWARGS) == 0)
180 				return;
181 
182 			if (sy->sy_narg > 7) {
183 				SCDEBUG_KERNHIST_LOG(scdebughist,
184 				    "args[4-7]: (%jx, %jx, %jx, %jx, ...)",
185 				    (long)args[4], (long)args[5],
186 				    (long)args[6], (long)args[7]);
187 			} else if (sy->sy_narg > 6) {
188 				SCDEBUG_KERNHIST_LOG(scdebughist,
189 				    "args[4-6]: (%jx, %jx, %jx)",
190 				    (long)args[4], (long)args[5],
191 				    (long)args[6], 0);
192 			} else if (sy->sy_narg > 5) {
193 				SCDEBUG_KERNHIST_LOG(scdebughist,
194 				    "args[4-5]: (%jx, %jx)",
195 				    (long)args[4], (long)args[5], 0, 0);
196 			} else if (sy->sy_narg == 5) {
197 				SCDEBUG_KERNHIST_LOG(scdebughist,
198 				    "args[4]: (%jx)",
199 				    (long)args[4], 0, 0, 0);
200 			}
201 
202 			if (sy->sy_narg > 3) {
203 				SCDEBUG_KERNHIST_LOG(scdebughist,
204 				    "args[0-3]: (%jx, %jx, %jx, %jx, ...)",
205 				    (long)args[0], (long)args[1],
206 				    (long)args[2], (long)args[3]);
207 			} else if (sy->sy_narg > 2) {
208 				SCDEBUG_KERNHIST_LOG(scdebughist,
209 				    "args[0-2]: (%jx, %jx, %jx)",
210 				    (long)args[0], (long)args[1],
211 				    (long)args[2], 0);
212 			} else if (sy->sy_narg > 1) {
213 				SCDEBUG_KERNHIST_LOG(scdebughist,
214 				    "args[0-1]: (%jx, %jx)",
215 				    (long)args[0], (long)args[1], 0, 0);
216 			} else if (sy->sy_narg == 1) {
217 				SCDEBUG_KERNHIST_LOG(scdebughist,
218 				    "args[0]: (%jx)",
219 				    (long)args[0], 0, 0, 0);
220 			}
221 		}
222 		return;
223 	}
224 
225 	printf("proc %d (%s): %s num ", p->p_pid, p->p_comm, em->e_name);
226 	if (CODE_NOT_OK(code, em))
227 		printf("OUT OF RANGE (%ld)", (long)code);
228 	else {
229 		printf("%ld call: %s", (long)code, em->e_syscallnames[code]);
230 		if (scdebug & SCDEBUG_SHOWARGS) {
231 			printf("(");
232 			for (i = 0; i < sy->sy_argsize/sizeof(register_t); i++)
233 				printf("%s0x%lx", i == 0 ? "" : ", ",
234 				    (long)args[i]);
235 			printf(")");
236 		}
237 	}
238 	printf("\n");
239 }
240 
241 void
242 scdebug_ret(register_t code, int error, const register_t retval[])
243 {
244 	SCDEBUG_KERNHIST_FUNC("scdebug_ret");
245 	struct lwp *l = curlwp;
246 	struct proc *p = l->l_proc;
247 	const struct sysent *sy;
248 	const struct emul *em;
249 
250 	if ((scdebug & SCDEBUG_RETURNS) == 0)
251 		return;
252 
253 	if (scdebug & SCDEBUG_KERNHIST)
254 		SCDEBUG_KERNHIST_CALLED(scdebughist);
255 
256 	em = p->p_emul;
257 	sy = &em->e_sysent[code];
258 	if ((scdebug & SCDEBUG_ALL) == 0 &&
259 	    (CODE_NOT_OK(code, em) || sy->sy_call == sys_nosys)) {
260 		if (scdebug & SCDEBUG_KERNHIST)
261 			SCDEBUG_KERNHIST_LOG(scdebughist, "", 0, 0, 0, 0);
262 		return;
263 	}
264 
265 	if (scdebug & SCDEBUG_KERNHIST) {
266 		if (CODE_NOT_OK(code, em)) {
267 			SCDEBUG_KERNHIST_LOG(scdebughist,
268 			    "pid %jd:%jd: OUT OF RANGE (%jd)",
269 			    p->p_pid, l->l_lid, code, 0);
270 		} else {
271 			SCDEBUG_KERNHIST_LOG(scdebughist,
272 			    "pid %jd:%jd: num %jd",
273 			    p->p_pid, l->l_lid, code, 0);
274 			SCDEBUG_KERNHIST_LOG(scdebughist,
275 			    "ret: err = %jd, rv = 0x%jx,0x%jx",
276 			    error, (long)retval[0], (long)retval[1], 0);
277 		}
278 		return;
279 	}
280 
281 	printf("proc %d (%s): %s num ", p->p_pid, p->p_comm, em->e_name);
282 	if (CODE_NOT_OK(code, em))
283 		printf("OUT OF RANGE (%ld)", (long)code);
284 	else
285 		printf("%ld ret %s: err = %d, rv = 0x%lx,0x%lx", (long)code,
286 		    em->e_syscallnames[code], error,
287 		    (long)retval[0], (long)retval[1]);
288 	printf("\n");
289 }
290 #endif /* SYSCALL_DEBUG */
291 
292 #ifndef SCDEBUG_KERNHIST_SIZE
293 #define SCDEBUG_KERNHIST_SIZE 500
294 #endif
295 
296 void
297 scdebug_init(void)
298 {
299 #if defined(SYSCALL_DEBUG) && defined(KERNHIST)
300 	/* Setup scdebughist kernel history */
301 	KERNHIST_INIT(scdebughist, SCDEBUG_KERNHIST_SIZE);
302 #endif
303 }
304