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
scdebug_call(register_t code,const register_t args[])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
scdebug_ret(register_t code,int error,const register_t retval[])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
scdebug_init(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