Module Name: src
Committed By: mrg
Date: Thu Oct 29 00:27:08 UTC 2015
Modified Files:
src/share/man/man4: options.4
src/sys/kern: init_main.c kern_history.c kern_xxx.c
src/sys/sys: kernhist.h systm.h
Log Message:
introduce a new way of handling SYSCALL_DEBUG messages -- send them to
a kernel history, settable via the SCDEBUG_KERNHIST flag.
this requires a fairly significantly different set of messages than the
normal debug as histories are restricted:
- each message can take one literal format string and upto 4
arguments
- the arguments can not be strings if you want vmstat -u to
work (this could be fixed, and i might, as it would be nice
if we could print syscall names as well as numbers.)
introduce SCDEBUG_DEFAULT that is settable in the kernel config.
fix a problem in kernhist_dump_histories() where it would crash when a
history with no allocated entries was found.
extend kernhist_dumpmask() to handle the usbhist and scdebughist.
To generate a diff of this commit:
cvs rdiff -u -r1.449 -r1.450 src/share/man/man4/options.4
cvs rdiff -u -r1.471 -r1.472 src/sys/kern/init_main.c
cvs rdiff -u -r1.1 -r1.2 src/sys/kern/kern_history.c
cvs rdiff -u -r1.72 -r1.73 src/sys/kern/kern_xxx.c
cvs rdiff -u -r1.9 -r1.10 src/sys/sys/kernhist.h
cvs rdiff -u -r1.268 -r1.269 src/sys/sys/systm.h
Please note that diffs are not public domain; they are subject to the
copyright notices on the relevant files.
Modified files:
Index: src/share/man/man4/options.4
diff -u src/share/man/man4/options.4:1.449 src/share/man/man4/options.4:1.450
--- src/share/man/man4/options.4:1.449 Thu Aug 20 11:05:06 2015
+++ src/share/man/man4/options.4 Thu Oct 29 00:27:08 2015
@@ -1,4 +1,4 @@
-.\" $NetBSD: options.4,v 1.449 2015/08/20 11:05:06 wiz Exp $
+.\" $NetBSD: options.4,v 1.450 2015/10/29 00:27:08 mrg Exp $
.\"
.\" Copyright (c) 1996
.\" Perry E. Metzger. All rights reserved.
@@ -30,7 +30,7 @@
.\" THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
.\"
.\"
-.Dd August 20, 2015
+.Dd October 28, 2015
.Dt OPTIONS 4
.Os
.Sh NAME
@@ -668,7 +668,9 @@ These logs can be displayed by using
from DDB.
See the kernel source file
.Pa sys/kern/kern_history.c
-for details.
+and the
+.Xr kernhist 9
+manual for details.
.It Cd options KERNHIST_PRINT
Prints the kernel history logs on the system console as entries are added.
Note that the output is
@@ -1508,6 +1510,36 @@ See
for details.
.Em NOTE :
not available on all architectures.
+.It Cd options SCDEBUG_DEFAULT
+Used with the
+.Cd options SYSCALL_DEBUG
+described below to choose which types of events are displayed.
+.Pp
+.Bl -tag -width "SCDEBUG_KERNHIST" -compact -offset indent
+.It Dv SCDEBUG_CALLS
+Show system call entry points.
+.It Dv SCDEBUG_RETURNS
+Show system call exit points.
+.It Dv SCDEBUG_ALL
+Show all system call requestes, including unimplemented calls.
+.It Dv SCDEBUG_SHOWARGS
+Show the arguments provided.
+.It Dv SCDEBUG_KERNHIST
+Store a restricted form of the system call debug in a kernel history
+instead of printing it to the console. This option relies upon
+.Cd options KERNHIST .
+.El
+.Pp
+The default value is
+.Dv (SCDEBUG_CALLS|SCDEBUG_RETURNS|SCDEBUG_SHOWARGS) .
+.It Cd options SYSCALL_DEBUG
+Useful for debugging system call issues, usually in early single user bringup.
+By default, writes entries to the system console for most system call events.
+Can be configured with the
+.Cd options SCDEBUG_DEFAULT
+option to to use the
+.Cd options KERNHIST
+facility instead.
.It Cd options SYSCALL_STATS
Count the number of times each system call number is called.
The values can be read through the sysctl interface and displayed using
@@ -2733,7 +2765,8 @@ bolded
.Xr quotaon 8 ,
.Xr rpc.rquotad 8 ,
.Xr sysctl 8 ,
-.Xr in_getifa 9
+.Xr in_getifa 9 ,
+.Xr kernhist 9
.Sh HISTORY
The
.Nm
Index: src/sys/kern/init_main.c
diff -u src/sys/kern/init_main.c:1.471 src/sys/kern/init_main.c:1.472
--- src/sys/kern/init_main.c:1.471 Sat Oct 17 13:52:52 2015
+++ src/sys/kern/init_main.c Thu Oct 29 00:27:08 2015
@@ -1,4 +1,4 @@
-/* $NetBSD: init_main.c,v 1.471 2015/10/17 13:52:52 jmcneill Exp $ */
+/* $NetBSD: init_main.c,v 1.472 2015/10/29 00:27:08 mrg Exp $ */
/*-
* Copyright (c) 2008, 2009 The NetBSD Foundation, Inc.
@@ -97,7 +97,7 @@
*/
#include <sys/cdefs.h>
-__KERNEL_RCSID(0, "$NetBSD: init_main.c,v 1.471 2015/10/17 13:52:52 jmcneill Exp $");
+__KERNEL_RCSID(0, "$NetBSD: init_main.c,v 1.472 2015/10/29 00:27:08 mrg Exp $");
#include "opt_ddb.h"
#include "opt_ipsec.h"
@@ -601,6 +601,8 @@ main(void)
procinit_sysctl();
+ scdebug_init();
+
/*
* Create process 1 (init(8)). We do this now, as Unix has
* historically had init be process 1, and changing this would
Index: src/sys/kern/kern_history.c
diff -u src/sys/kern/kern_history.c:1.1 src/sys/kern/kern_history.c:1.2
--- src/sys/kern/kern_history.c:1.1 Tue May 17 04:18:06 2011
+++ src/sys/kern/kern_history.c Thu Oct 29 00:27:08 2015
@@ -1,4 +1,4 @@
-/* $NetBSD: kern_history.c,v 1.1 2011/05/17 04:18:06 mrg Exp $ */
+/* $NetBSD: kern_history.c,v 1.2 2015/10/29 00:27:08 mrg Exp $ */
/*
* Copyright (c) 1997 Charles D. Cranor and Washington University.
@@ -33,18 +33,30 @@
*/
#include <sys/cdefs.h>
-__KERNEL_RCSID(0, "$NetBSD: kern_history.c,v 1.1 2011/05/17 04:18:06 mrg Exp $");
+__KERNEL_RCSID(0, "$NetBSD: kern_history.c,v 1.2 2015/10/29 00:27:08 mrg Exp $");
#include "opt_kernhist.h"
-#include "opt_uvmhist.h"
#include "opt_ddb.h"
+#include "opt_uvmhist.h"
+#include "opt_usb.h"
+#include "opt_syscall_debug.h"
#include <sys/param.h>
#include <sys/systm.h>
#include <sys/cpu.h>
#include <sys/kernhist.h>
+#ifdef UVMHIST
#include <uvm/uvm.h>
+#endif
+
+#ifdef USB_DEBUG
+#include <dev/usb/usbhist.h>
+#endif
+
+#ifdef SYSCALL_DEBUG
+KERNHIST_DECL(scdebughist);
+#endif
/*
* globals
@@ -112,6 +124,8 @@ kernhist_dump_histories(struct kern_hist
restart:
if (cur[lcv] == -1)
continue;
+ if (!hists[lcv]->e)
+ continue;
/*
* if the format is empty, go to the next entry
@@ -174,6 +188,16 @@ kernhist_dumpmask(u_int32_t bitmask) /*
hists[i++] = &loanhist;
#endif
+#ifdef USB_DEBUG
+ if ((bitmask & KERNHIST_USBHIST) || bitmask == 0)
+ hists[i++] = &usbhist;
+#endif
+
+#ifdef SYSCALL_DEBUG
+ if ((bitmask & KERNHIST_SCDEBUGHIST) || bitmask == 0)
+ hists[i++] = &scdebughist;
+#endif
+
hists[i] = NULL;
kernhist_dump_histories(hists);
Index: src/sys/kern/kern_xxx.c
diff -u src/sys/kern/kern_xxx.c:1.72 src/sys/kern/kern_xxx.c:1.73
--- src/sys/kern/kern_xxx.c:1.72 Thu Sep 1 18:25:44 2011
+++ src/sys/kern/kern_xxx.c Thu Oct 29 00:27:08 2015
@@ -1,4 +1,4 @@
-/* $NetBSD: kern_xxx.c,v 1.72 2011/09/01 18:25:44 matt Exp $ */
+/* $NetBSD: kern_xxx.c,v 1.73 2015/10/29 00:27:08 mrg Exp $ */
/*
* Copyright (c) 1982, 1986, 1989, 1993
@@ -32,10 +32,11 @@
*/
#include <sys/cdefs.h>
-__KERNEL_RCSID(0, "$NetBSD: kern_xxx.c,v 1.72 2011/09/01 18:25:44 matt Exp $");
+__KERNEL_RCSID(0, "$NetBSD: kern_xxx.c,v 1.73 2015/10/29 00:27:08 mrg Exp $");
#ifdef _KERNEL_OPT
#include "opt_syscall_debug.h"
+#include "opt_kernhist.h"
#endif
#include <sys/param.h>
@@ -49,6 +50,7 @@ __KERNEL_RCSID(0, "$NetBSD: kern_xxx.c,v
#include <sys/syscall.h>
#include <sys/syscallargs.h>
#include <sys/kauth.h>
+#include <sys/kernhist.h>
/* ARGSUSED */
int
@@ -102,42 +104,134 @@ sys_reboot(struct lwp *l, const struct s
#ifdef SYSCALL_DEBUG
#define SCDEBUG_CALLS 0x0001 /* show calls */
#define SCDEBUG_RETURNS 0x0002 /* show returns */
-#define SCDEBUG_ALL 0x0004 /* even syscalls that are implemented */
+#define SCDEBUG_ALL 0x0004 /* even syscalls that are not implemented */
#define SCDEBUG_SHOWARGS 0x0008 /* show arguments to calls */
+#define SCDEBUG_KERNHIST 0x0010 /* use kernhist instead of printf */
-#if 0
-int scdebug = SCDEBUG_CALLS|SCDEBUG_RETURNS|SCDEBUG_SHOWARGS;
+#ifndef SCDEBUG_DEFAULT
+#define SCDEBUG_DEFAULT (SCDEBUG_CALLS|SCDEBUG_RETURNS|SCDEBUG_SHOWARGS)
+#endif
+
+int scdebug = SCDEBUG_DEFAULT;
+
+#ifdef KERNHIST
+KERNHIST_DEFINE(scdebughist);
+#define SCDEBUG_KERNHIST_FUNC(a) KERNHIST_FUNC(a)
+#define SCDEBUG_KERNHIST_CALLED(a) KERNHIST_CALLED(a)
+#define SCDEBUG_KERNHIST_LOG(a,b,c,d,e,f) KERNHIST_LOG(a,b,c,d,e,f)
+#else
+#define SCDEBUG_KERNHIST_FUNC(a) /* nothing */
+#define SCDEBUG_KERNHIST_CALLED(a) /* nothing */
+#define SCDEBUG_KERNHIST_LOG(a,b,c,d,e,f) /* nothing */
+/* The non-kernhist support version can elide all this code easily. */
+#undef SCDEBUG_KERNHIST
+#define SCDEBUG_KERNHIST 0
+#endif
+
+#ifdef __HAVE_MINIMAL_EMUL
+#define CODE_NOT_OK(code, em) ((int)(code) < 0)
#else
-int scdebug = SCDEBUG_CALLS|SCDEBUG_RETURNS|SCDEBUG_SHOWARGS|SCDEBUG_ALL;
+#define CODE_NOT_OK(code, em) (((int)(code) < 0) || \
+ ((int)(code) >= (em)->e_nsysent))
#endif
void
scdebug_call(register_t code, const register_t args[])
{
+ SCDEBUG_KERNHIST_FUNC("scdebug_call");
struct lwp *l = curlwp;
struct proc *p = l->l_proc;
const struct sysent *sy;
const struct emul *em;
int i;
- if (!(scdebug & SCDEBUG_CALLS))
+ if ((scdebug & SCDEBUG_CALLS) == 0)
return;
+ if (scdebug & SCDEBUG_KERNHIST)
+ SCDEBUG_KERNHIST_CALLED(scdebughist);
+
em = p->p_emul;
sy = &em->e_sysent[code];
- if (!(scdebug & SCDEBUG_ALL || (int)code < 0
-#ifndef __HAVE_MINIMAL_EMUL
- || code >= em->e_nsysent
-#endif
- || sy->sy_call == sys_nosys))
+
+ if ((scdebug & SCDEBUG_ALL) == 0 &&
+ (CODE_NOT_OK(code, em) || sy->sy_call == sys_nosys)) {
+ if (scdebug & SCDEBUG_KERNHIST)
+ SCDEBUG_KERNHIST_LOG(scdebughist, "", 0, 0, 0, 0);
+ return;
+ }
+
+ /*
+ * The kernhist version of scdebug needs to restrict the usage
+ * compared to the normal version. histories must avoid these
+ * sorts of usage:
+ *
+ * - the format string *must* be literal, as it is used
+ * at display time in the kernel or userland
+ * - strings in the format will cause vmstat -u to crash
+ * so avoid using %s formats
+ *
+ * to avoid these, we have a fairly long block to print args
+ * as the format needs to change for each, and we can't just
+ * call printf() on each argument until we're done.
+ */
+ if (scdebug & SCDEBUG_KERNHIST) {
+ if (CODE_NOT_OK(code, em)) {
+ SCDEBUG_KERNHIST_LOG(scdebughist,
+ "pid %d:%d: OUT OF RANGE (%ld)",
+ p->p_pid, l->l_lid, code, 0);
+ } else {
+ SCDEBUG_KERNHIST_LOG(scdebughist,
+ "pid %d:%d: num %d call %p",
+ p->p_pid, l->l_lid, code, sy->sy_call);
+ if ((scdebug & SCDEBUG_SHOWARGS) == 0)
+ return;
+
+ if (sy->sy_narg > 7) {
+ SCDEBUG_KERNHIST_LOG(scdebughist,
+ "args[4-7]: (%lx, %lx, %lx, %lx, ...)",
+ (long)args[4], (long)args[5],
+ (long)args[6], (long)args[7]);
+ } else if (sy->sy_narg > 6) {
+ SCDEBUG_KERNHIST_LOG(scdebughist,
+ "args[4-6]: (%lx, %lx, %lx)",
+ (long)args[4], (long)args[5],
+ (long)args[6], 0);
+ } else if (sy->sy_narg > 5) {
+ SCDEBUG_KERNHIST_LOG(scdebughist,
+ "args[4-5]: (%lx, %lx)",
+ (long)args[4], (long)args[5], 0, 0);
+ } else if (sy->sy_narg == 5) {
+ SCDEBUG_KERNHIST_LOG(scdebughist,
+ "args[4]: (%lx)",
+ (long)args[4], 0, 0, 0);
+ }
+
+ if (sy->sy_narg > 3) {
+ SCDEBUG_KERNHIST_LOG(scdebughist,
+ "args[0-3]: (%lx, %lx, %lx, %lx, ...)",
+ (long)args[0], (long)args[1],
+ (long)args[2], (long)args[3]);
+ } else if (sy->sy_narg > 2) {
+ SCDEBUG_KERNHIST_LOG(scdebughist,
+ "args[0-2]: (%lx, %lx, %lx)",
+ (long)args[0], (long)args[1],
+ (long)args[2], 0);
+ } else if (sy->sy_narg > 1) {
+ SCDEBUG_KERNHIST_LOG(scdebughist,
+ "args[0-1]: (%lx, %lx)",
+ (long)args[0], (long)args[1], 0, 0);
+ } else if (sy->sy_narg == 1) {
+ SCDEBUG_KERNHIST_LOG(scdebughist,
+ "args[0]: (%lx)",
+ (long)args[0], 0, 0, 0);
+ }
+ }
return;
+ }
printf("proc %d (%s): %s num ", p->p_pid, p->p_comm, em->e_name);
- if ((int)code < 0
-#ifndef __HAVE_MINIMAL_EMUL
- || code >= em->e_nsysent
-#endif
- )
+ if (CODE_NOT_OK(code, em))
printf("OUT OF RANGE (%ld)", (long)code);
else {
printf("%ld call: %s", (long)code, em->e_syscallnames[code]);
@@ -155,29 +249,45 @@ scdebug_call(register_t code, const regi
void
scdebug_ret(register_t code, int error, const register_t retval[])
{
+ SCDEBUG_KERNHIST_FUNC("scdebug_ret");
struct lwp *l = curlwp;
struct proc *p = l->l_proc;
const struct sysent *sy;
const struct emul *em;
- if (!(scdebug & SCDEBUG_RETURNS))
+ if ((scdebug & SCDEBUG_RETURNS) == 0)
return;
+ if (scdebug & SCDEBUG_KERNHIST)
+ SCDEBUG_KERNHIST_CALLED(scdebughist);
+
em = p->p_emul;
sy = &em->e_sysent[code];
- if (!(scdebug & SCDEBUG_ALL || (int)code < 0
-#ifndef __HAVE_MINIMAL_EMUL
- || (int)code >= em->e_nsysent
-#endif
- || sy->sy_call == sys_nosys))
+ if ((scdebug & SCDEBUG_ALL) == 0 &&
+ (CODE_NOT_OK(code, em) || sy->sy_call == sys_nosys)) {
+ if (scdebug & SCDEBUG_KERNHIST)
+ SCDEBUG_KERNHIST_LOG(scdebughist, "", 0, 0, 0, 0);
+ return;
+ }
+
+ if (scdebug & SCDEBUG_KERNHIST) {
+ if (CODE_NOT_OK(code, em)) {
+ SCDEBUG_KERNHIST_LOG(scdebughist,
+ "pid %d:%d: OUT OF RANGE (%ld)",
+ p->p_pid, l->l_lid, code, 0);
+ } else {
+ SCDEBUG_KERNHIST_LOG(scdebughist,
+ "pid %d:%d: num %ld",
+ p->p_pid, l->l_lid, code, 0);
+ SCDEBUG_KERNHIST_LOG(scdebughist,
+ "ret: err = %d, rv = 0x%lx,0x%lx",
+ error, (long)retval[0], (long)retval[1], 0);
+ }
return;
+ }
printf("proc %d (%s): %s num ", p->p_pid, p->p_comm, em->e_name);
- if ((int)code < 0
-#ifndef __HAVE_MINIMAL_EMUL
- || code >= em->e_nsysent
-#endif
- )
+ if (CODE_NOT_OK(code, em))
printf("OUT OF RANGE (%ld)", (long)code);
else
printf("%ld ret %s: err = %d, rv = 0x%lx,0x%lx", (long)code,
@@ -186,3 +296,16 @@ scdebug_ret(register_t code, int error,
printf("\n");
}
#endif /* SYSCALL_DEBUG */
+
+#ifndef SCDEBUG_KERNHIST_SIZE
+#define SCDEBUG_KERNHIST_SIZE 500
+#endif
+
+void
+scdebug_init(void)
+{
+#if defined(SYSCALL_DEBUG) && defined(KERNHIST)
+ /* Setup scdebughist kernel history */
+ KERNHIST_INIT(scdebughist, SCDEBUG_KERNHIST_SIZE);
+#endif
+}
Index: src/sys/sys/kernhist.h
diff -u src/sys/sys/kernhist.h:1.9 src/sys/sys/kernhist.h:1.10
--- src/sys/sys/kernhist.h:1.9 Sun Mar 30 15:53:37 2014
+++ src/sys/sys/kernhist.h Thu Oct 29 00:27:08 2015
@@ -1,4 +1,4 @@
-/* $NetBSD: kernhist.h,v 1.9 2014/03/30 15:53:37 matt Exp $ */
+/* $NetBSD: kernhist.h,v 1.10 2015/10/29 00:27:08 mrg Exp $ */
/*
* Copyright (c) 1997 Charles D. Cranor and Washington University.
@@ -85,6 +85,8 @@ LIST_HEAD(kern_history_head, kern_histor
#define KERNHIST_UVMPDHIST 0x00000002 /* pdhist */
#define KERNHIST_UVMUBCHIST 0x00000004 /* ubchist */
#define KERNHIST_UVMLOANHIST 0x00000008 /* loanhist */
+#define KERNHIST_USBHIST 0x00000010 /* usbhist */
+#define KERNHIST_SCDEBUGHIST 0x00000020 /* scdebughist */
#ifdef _KERNEL
Index: src/sys/sys/systm.h
diff -u src/sys/sys/systm.h:1.268 src/sys/sys/systm.h:1.269
--- src/sys/sys/systm.h:1.268 Fri Aug 28 07:18:40 2015
+++ src/sys/sys/systm.h Thu Oct 29 00:27:08 2015
@@ -1,4 +1,4 @@
-/* $NetBSD: systm.h,v 1.268 2015/08/28 07:18:40 knakahara Exp $ */
+/* $NetBSD: systm.h,v 1.269 2015/10/29 00:27:08 mrg Exp $ */
/*-
* Copyright (c) 1982, 1988, 1991, 1993
@@ -489,6 +489,7 @@ extern int db_fromconsole; /* XXX ddb/dd
#endif /* _KERNEL */
/* For SYSCALL_DEBUG */
+void scdebug_init(void);
void scdebug_call(register_t, const register_t[]);
void scdebug_ret(register_t, int, const register_t[]);