kern_ktr.c revision 78784
165556Sjasone/*
265556Sjasone * Copyright (c) 2000
365556Sjasone *	John Baldwin <jhb@FreeBSD.org>.  All rights reserved.
465556Sjasone *
565556Sjasone * Redistribution and use in source and binary forms, with or without
665556Sjasone * modification, are permitted provided that the following conditions
765556Sjasone * are met:
865556Sjasone * 1. Redistributions of source code must retain the above copyright
965556Sjasone *    notice, this list of conditions and the following disclaimer.
1065556Sjasone * 2. Redistributions in binary form must reproduce the above copyright
1165556Sjasone *    notice, this list of conditions and the following disclaimer in the
1265556Sjasone *    documentation and/or other materials provided with the distribution.
1365556Sjasone * 4. Neither the name of the author nor the names of any co-contributors
1465556Sjasone *    may be used to endorse or promote products derived from this software
1565556Sjasone *    without specific prior written permission.
1665556Sjasone *
1769012Sjhb * THIS SOFTWARE IS PROVIDED BY JOHN BALDWIN AND CONTRIBUTORS ``AS IS'' AND
1865556Sjasone * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
1965556Sjasone * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
2069012Sjhb * ARE DISCLAIMED.  IN NO EVENT SHALL JOHN BALDWIN OR THE VOICES IN HIS HEAD
2165556Sjasone * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
2265556Sjasone * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
2365556Sjasone * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
2465556Sjasone * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
2565556Sjasone * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
2665556Sjasone * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
2765556Sjasone * THE POSSIBILITY OF SUCH DAMAGE.
2865556Sjasone *
2965556Sjasone * $FreeBSD: head/sys/kern/kern_ktr.c 78784 2001-06-25 23:09:31Z jhb $
3065556Sjasone */
3165556Sjasone
3265556Sjasone/*
3368420Sjhb * This module holds the global variables used by KTR and the ktr_tracepoint()
3468420Sjhb * function that does the actual tracing.
3565556Sjasone */
3665556Sjasone
3770035Sjhb#include "opt_ddb.h"
3868420Sjhb#include "opt_ktr.h"
3968420Sjhb
4070035Sjhb#include <sys/param.h>
4170035Sjhb#include <sys/cons.h>
4270705Sjhb#include <sys/kernel.h>
4365556Sjasone#include <sys/ktr.h>
4468420Sjhb#include <sys/libkern.h>
4565556Sjasone#include <sys/sysctl.h>
4668420Sjhb#include <sys/systm.h>
4778784Sjhb#include <sys/time.h>
4868584Sjhb#include <machine/globals.h>
4968420Sjhb#include <machine/stdarg.h>
5065556Sjasone
5170035Sjhb#include <ddb/ddb.h>
5270035Sjhb
5378784Sjhb#ifndef KTR_ENTRIES
5478784Sjhb#define	KTR_ENTRIES	1024
5578784Sjhb#endif
5678784Sjhb
5768420Sjhb#ifndef KTR_MASK
5868420Sjhb#define	KTR_MASK	(KTR_GEN)
5968420Sjhb#endif
6068420Sjhb
6168420Sjhb#ifndef KTR_CPUMASK
6268420Sjhb#define	KTR_CPUMASK	(~0)
6368420Sjhb#endif
6468420Sjhb
6568420Sjhb#ifdef SMP
6670861Sjake#define KTR_CPU		PCPU_GET(cpuid)
6768420Sjhb#else
6868420Sjhb#define KTR_CPU		0
6968420Sjhb#endif
7068420Sjhb
7165556Sjasone#ifdef KTR_EXTEND
7270705Sjhb#define KTR_EXTEND_DEFAULT	1
7370705Sjhb#else
7470705Sjhb#define KTR_EXTEND_DEFAULT	0
7570705Sjhb#endif
7670705Sjhb
7770705Sjhb#ifdef KTR_VERBOSE
7870705Sjhb#define KTR_VERBOSE_DEFAULT	1
7970705Sjhb#else
8070705Sjhb#define KTR_VERBOSE_DEFAULT	0
8170705Sjhb#endif
8270705Sjhb
8370705SjhbSYSCTL_NODE(_debug, OID_AUTO, ktr, CTLFLAG_RD, 0, "KTR options");
8470705Sjhb
8565556Sjasone/*
8665556Sjasone * This variable is used only by gdb to work out what fields are in
8765556Sjasone * ktr_entry.
8865556Sjasone */
8970705Sjhbint     ktr_extend = KTR_EXTEND_DEFAULT;
9070705SjhbSYSCTL_INT(_debug_ktr, OID_AUTO, extend, CTLFLAG_RD, &ktr_extend, 0, "");
9165556Sjasone
9277843Speterint	ktr_cpumask = KTR_CPUMASK;
9377900SpeterTUNABLE_INT("debug.ktr.cpumask", &ktr_cpumask);
9470705SjhbSYSCTL_INT(_debug_ktr, OID_AUTO, cpumask, CTLFLAG_RW, &ktr_cpumask, 0, "");
9565556Sjasone
9677843Speterint	ktr_mask = KTR_MASK;
9777900SpeterTUNABLE_INT("debug.ktr.mask", &ktr_mask);
9870705SjhbSYSCTL_INT(_debug_ktr, OID_AUTO, mask, CTLFLAG_RW, &ktr_mask, 0, "");
9965556Sjasone
10065556Sjasoneint	ktr_entries = KTR_ENTRIES;
10170705SjhbSYSCTL_INT(_debug_ktr, OID_AUTO, entries, CTLFLAG_RD, &ktr_entries, 0, "");
10265556Sjasone
10365556Sjasonevolatile int	ktr_idx = 0;
10465556Sjasonestruct	ktr_entry ktr_buf[KTR_ENTRIES];
10568420Sjhb
10677843Speterint	ktr_verbose = KTR_VERBOSE_DEFAULT;
10777900SpeterTUNABLE_INT("debug.ktr.verbose", &ktr_verbose);
10870705SjhbSYSCTL_INT(_debug_ktr, OID_AUTO, verbose, CTLFLAG_RW, &ktr_verbose, 0, "");
10968420Sjhb
11068420Sjhb#ifdef KTR
11168420Sjhb#ifdef KTR_EXTEND
11268420Sjhbvoid
11372761Sjhbktr_tracepoint(u_int mask, const char *filename, u_int line,
11472761Sjhb	       const char *format, ...)
11568420Sjhb#else
11668420Sjhbvoid
11772761Sjhbktr_tracepoint(u_int mask, const char *format, u_long arg1, u_long arg2,
11872761Sjhb	       u_long arg3, u_long arg4, u_long arg5)
11968420Sjhb#endif
12068420Sjhb{
12168420Sjhb	struct ktr_entry *entry;
12274903Sjhb	int newindex, saveindex;
12374903Sjhb	critical_t savecrit;
12468420Sjhb#ifdef KTR_EXTEND
12568420Sjhb	va_list ap;
12668420Sjhb#endif
12768420Sjhb
12869880Sjhb	if (panicstr)
12969880Sjhb		return;
13068420Sjhb	if ((ktr_mask & mask) == 0)
13168420Sjhb		return;
13278784Sjhb	savecrit = critical_enter();
13378784Sjhb	if (((1 << KTR_CPU) & ktr_cpumask) == 0) {
13478784Sjhb		critical_exit(savecrit);
13568420Sjhb		return;
13678784Sjhb	}
13778784Sjhb	atomic_clear_int(&ktr_cpumask, 1 << KTR_CPU);
13868420Sjhb	do {
13968420Sjhb		saveindex = ktr_idx;
14068420Sjhb		newindex = (saveindex + 1) & (KTR_ENTRIES - 1);
14168420Sjhb	} while (atomic_cmpset_rel_int(&ktr_idx, saveindex, newindex) == 0);
14268420Sjhb	entry = &ktr_buf[saveindex];
14378784Sjhb	/*
14478784Sjhb	 * XXX: The ktr_cpumask atomic ops should make this unnecessary.
14578784Sjhb	 */
14678784Sjhb	if ((ktr_mask & (KTR_LOCK | KTR_WITNESS)) != 0)
14770464Sgrog		getnanotime(&entry->ktr_tv);
14870464Sgrog	else
14970464Sgrog		nanotime(&entry->ktr_tv);
15078784Sjhb	atomic_set_int(&ktr_cpumask, 1 << KTR_CPU);
15178784Sjhb	entry->ktr_cpu = KTR_CPU;
15278784Sjhb	critical_exit(savecrit);
15368420Sjhb#ifdef KTR_EXTEND
15472761Sjhb	entry->ktr_filename = filename;
15568420Sjhb	entry->ktr_line = line;
15668420Sjhb	va_start(ap, format);
15768420Sjhb	vsnprintf(entry->ktr_desc, KTRDESCSIZE, format, ap);
15868420Sjhb	va_end(ap);
15968420Sjhb	if (ktr_verbose) {
16068782Sjhb#ifdef SMP
16168782Sjhb		printf("cpu%d ", entry->ktr_cpu);
16268782Sjhb#endif
16368782Sjhb		if (ktr_verbose > 1)
16468782Sjhb			printf("%s.%d\t", entry->ktr_filename, entry->ktr_line);
16568420Sjhb		va_start(ap, format);
16668420Sjhb		vprintf(format, ap);
16768420Sjhb		printf("\n");
16868420Sjhb		va_end(ap);
16968420Sjhb	}
17068420Sjhb#else
17168420Sjhb	entry->ktr_desc = format;
17268420Sjhb	entry->ktr_parm1 = arg1;
17368420Sjhb	entry->ktr_parm2 = arg2;
17468420Sjhb	entry->ktr_parm3 = arg3;
17568420Sjhb	entry->ktr_parm4 = arg4;
17668420Sjhb	entry->ktr_parm5 = arg5;
17768420Sjhb#endif
17868420Sjhb}
17970035Sjhb
18070035Sjhb#ifdef DDB
18170035Sjhb
18270035Sjhbstruct tstate {
18370035Sjhb	int	cur;
18470035Sjhb	int	first;
18570035Sjhb};
18670035Sjhbstatic	struct tstate tstate;
18770035Sjhbstatic	int db_ktr_verbose;
18870035Sjhbstatic	int db_mach_vtrace(void);
18970035Sjhb
19072755Sjhb#define	NUM_LINES_PER_PAGE	18
19172755Sjhb
19272755SjhbDB_SHOW_COMMAND(ktr, db_ktr_all)
19370035Sjhb{
19472755Sjhb	int	c, lines;
19570035Sjhb
19672755Sjhb	lines = NUM_LINES_PER_PAGE;
19770035Sjhb	tstate.cur = (ktr_idx - 1) & (KTR_ENTRIES - 1);
19870035Sjhb	tstate.first = -1;
19970035Sjhb	if (strcmp(modif, "v") == 0)
20070035Sjhb		db_ktr_verbose = 1;
20170035Sjhb	else
20270035Sjhb		db_ktr_verbose = 0;
20372755Sjhb	while (db_mach_vtrace())
20472755Sjhb		if (--lines == 0) {
20572755Sjhb			db_printf("--More--");
20672755Sjhb			c = cngetc();
20772755Sjhb			db_printf("\r");
20872755Sjhb			switch (c) {
20972755Sjhb			case '\n':	/* one more line */
21072755Sjhb				lines = 1;
21172755Sjhb				break;
21272755Sjhb			case ' ':	/* one more page */
21372755Sjhb				lines = NUM_LINES_PER_PAGE;
21472755Sjhb				break;
21572755Sjhb			default:
21672755Sjhb				db_printf("\n");
21772755Sjhb				return;
21872755Sjhb			}
21972755Sjhb		}
22070035Sjhb}
22170035Sjhb
22270035Sjhbstatic int
22370035Sjhbdb_mach_vtrace(void)
22470035Sjhb{
22570035Sjhb	struct ktr_entry	*kp;
22670035Sjhb
22770035Sjhb	if (tstate.cur == tstate.first) {
22870035Sjhb		db_printf("--- End of trace buffer ---\n");
22970035Sjhb		return (0);
23070035Sjhb	}
23170035Sjhb	kp = &ktr_buf[tstate.cur];
23270035Sjhb
23370035Sjhb	/* Skip over unused entries. */
23470035Sjhb#ifdef KTR_EXTEND
23572755Sjhb	if (kp->ktr_desc[0] == '\0') {
23670035Sjhb#else
23772755Sjhb	if (kp->ktr_desc == NULL) {
23870035Sjhb#endif
23972755Sjhb		db_printf("--- End of trace buffer ---\n");
24072755Sjhb		return (0);
24172755Sjhb	}
24272755Sjhb	db_printf("%d: ", tstate.cur);
24372755Sjhb	if (db_ktr_verbose)
24472755Sjhb		db_printf("%4ld.%06ld ", (long)kp->ktr_tv.tv_sec,
24572755Sjhb		    kp->ktr_tv.tv_nsec / 1000);
24670035Sjhb#ifdef KTR_EXTEND
24770035Sjhb#ifdef SMP
24872755Sjhb	db_printf("cpu%d ", kp->ktr_cpu);
24970035Sjhb#endif
25072755Sjhb	if (db_ktr_verbose)
25172755Sjhb		db_printf("%s.%d\t", kp->ktr_filename, kp->ktr_line);
25272755Sjhb	db_printf("%s", kp->ktr_desc);
25370035Sjhb#else
25472755Sjhb	db_printf(kp->ktr_desc, kp->ktr_parm1, kp->ktr_parm2, kp->ktr_parm3,
25572755Sjhb	    kp->ktr_parm4, kp->ktr_parm5);
25670035Sjhb#endif
25772755Sjhb	db_printf("\n");
25870035Sjhb
25970035Sjhb	if (tstate.first == -1)
26070035Sjhb		tstate.first = tstate.cur;
26170035Sjhb
26270035Sjhb	if (--tstate.cur < 0)
26370035Sjhb		tstate.cur = KTR_ENTRIES - 1;
26470035Sjhb
26570035Sjhb	return (1);
26670035Sjhb}
26770035Sjhb
26870035Sjhb#endif	/* DDB */
26968420Sjhb#endif	/* KTR */
270