Index: share/man/man9/Makefile
===================================================================
RCS file: /home/data/fbsd-cvs/ncvs/src/share/man/man9/Makefile,v
retrieving revision 1.310.2.2
diff -u -r1.310.2.2 Makefile
--- share/man/man9/Makefile	15 Feb 2008 10:28:46 -0000	1.310.2.2
+++ share/man/man9/Makefile	20 Feb 2008 16:38:07 -0000
@@ -1056,6 +1056,7 @@
 	stack.9 stack_put.9 \
 	stack.9 stack_save.9 \
 	stack.9 stack_sbuf_print.9 \
+	stack.9 stack_sbuf_print_ddb.9 \
 	stack.9 stack_zero.9
 MLINKS+=store.9 subyte.9 \
 	store.9 suswintr.9 \
Index: share/man/man9/stack.9
===================================================================
RCS file: /home/data/fbsd-cvs/ncvs/src/share/man/man9/stack.9,v
retrieving revision 1.5.2.1
diff -u -r1.5.2.1 stack.9
--- share/man/man9/stack.9	4 Dec 2007 15:22:31 -0000	1.5.2.1
+++ share/man/man9/stack.9	17 Jan 2008 17:05:04 -0000
@@ -36,9 +36,9 @@
 .Sh SYNOPSIS
 .In sys/param.h>
 .In sys/stack.h
-.Pp
-In kernel configuration files:
+In the kernel configuration file:
 .Cd "options DDB"
+.Cd "options STACK"
 .Ft struct stack *
 .Fn stack_create "void"
 .Ft void
@@ -54,6 +54,8 @@
 .Ft void
 .Fn stack_sbuf_print "struct sbuf sb*" "struct stack *st"
 .Ft void
+.Fn stack_sbuf_print_ddb "struct sbuf sb*" "struct stack *st"
+.Ft void
 .Fn stack_save "struct stack *st"
 .Sh DESCRIPTION
 The
@@ -61,12 +63,11 @@
 KPI allows querying of kernel stack trace information and the automated
 generation of kernel stack trace strings for the purposes of debugging and
 tracing.
-.Nm
-relies on the presence of
-.Xr DDB 4 ,
-and all use of these functions must be made conditional on
-.Nm DDB
-being compiled in the kernel.
+To use the KPI, at least one of
+.Cd "options DDB"
+and
+.Cd "options STACK"
+must be compiled into the kernel.
 .Pp
 Each stack trace is described by a
 .Vt "struct stack" .
@@ -74,7 +75,7 @@
 must be allocated with
 .Fn stack_create ,
 which may sleep.
-Memory associated with a trace may be freed by calling
+Memory associated with a trace is freed by calling
 .Fn stack_destroy .
 .Pp
 A trace of the current kernel thread's call stack may be captured using
@@ -82,7 +83,16 @@
 .Pp
 .Fn stack_print
 may be used to print a stack trace using the kernel
-.Xr printf 9 .
+.Xr printf 9 ,
+and may sleep as a result of acquiring
+.Xr sx 9
+locks in the kernel linker while looking up symbol names.
+In locking-sensitive environments, the unsynchronized
+.Fn stack_print_ddb
+variant may be invoked.
+This function bypasses kernel linker locking, making it usable in
+.Xr ddb 4 ,
+but not in a live system where linker data structures may change.
 .Pp
 .Fn stack_sbuf_print
 may be used to construct a human-readable string, including conversion (where
@@ -96,7 +106,13 @@
 .Xr sbuf 9 .
 This function may sleep if an auto-extending
 .Dv struct sbuf
-is used.
+is used, or due to kernel linker locking.
+In locking-sensitive environments, such as
+.Xr ddb 4 ,
+the unsynchronized
+.Fn stack_sbuf_print_ddb
+variant may be invoked to avoid kernel linker locking; it should be used with
+a fixed-length sbuf.
 .Pp
 The utility functions
 .Nm stack_zero ,
@@ -105,15 +121,18 @@
 .Nm stack_put
 may be used to manipulate stack data structures directly.
 .Sh SEE ALSO
-.Xr DDB 4 ,
+.Xr ddb 4 ,
 .Xr printf 9 ,
-.Xr sbuf 9
+.Xr sbuf 9 ,
+.Xr sx 9
 .Sh AUTHORS
 .An -nosplit
 The
 .Xr stack 9
 function suite was created by
 .An Antoine Brodin .
-.Pp
-This manual page was written by
-.An Robert Watson .
+.Xr stack 9
+was extended by
+.An Robert Watson
+for general-purpose use outside of
+.Xr ddb 4 .
Index: sys/amd64/amd64/db_trace.c
===================================================================
RCS file: /home/data/fbsd-cvs/ncvs/src/sys/amd64/amd64/db_trace.c,v
retrieving revision 1.80.2.1
diff -u -r1.80.2.1 db_trace.c
--- sys/amd64/amd64/db_trace.c	21 Nov 2007 16:38:54 -0000	1.80.2.1
+++ sys/amd64/amd64/db_trace.c	17 Jan 2008 17:06:03 -0000
@@ -38,6 +38,7 @@
 #include <machine/md_var.h>
 #include <machine/pcb.h>
 #include <machine/reg.h>
+#include <machine/stack.h>
 
 #include <vm/vm.h>
 #include <vm/vm_param.h>
@@ -177,18 +178,6 @@
 	return (1);
 }
 
-/*
- * Stack trace.
- */
-#define	INKERNEL(va) (((va) >= DMAP_MIN_ADDRESS && (va) < DMAP_MAX_ADDRESS) \
-	    || ((va) >= KERNBASE && (va) < VM_MAX_KERNEL_ADDRESS))
-
-struct amd64_frame {
-	struct amd64_frame	*f_frame;
-	long			f_retaddr;
-	long			f_arg0;
-};
-
 #define NORMAL		0
 #define	TRAP		1
 #define	INTERRUPT	2
@@ -505,32 +494,6 @@
 		    ctx->pcb_rip, count));
 }
 
-void
-stack_save(struct stack *st)
-{
-	struct amd64_frame *frame;
-	vm_offset_t callpc;
-	register_t rbp;
-
-	stack_zero(st);
-	__asm __volatile("movq %%rbp,%0" : "=r" (rbp));
-	frame = (struct amd64_frame *)rbp;
-	while (1) {
-		if (!INKERNEL((long)frame))
-			break;
-		callpc = frame->f_retaddr;
-		if (!INKERNEL(callpc))
-			break;
-		if (stack_put(st, callpc) == -1)
-			break;
-		if (frame->f_frame <= frame ||
-		    (vm_offset_t)frame->f_frame >=
-		    (vm_offset_t)rbp + KSTACK_PAGES * PAGE_SIZE)
-			break;
-		frame = frame->f_frame;
-	}
-}
-
 int
 amd64_set_watch(watchnum, watchaddr, size, access, d)
 	int watchnum;
Index: sys/amd64/amd64/stack_machdep.c
===================================================================
RCS file: sys/amd64/amd64/stack_machdep.c
diff -N sys/amd64/amd64/stack_machdep.c
--- /dev/null	1 Jan 1970 00:00:00 -0000
+++ sys/amd64/amd64/stack_machdep.c	17 Jan 2008 18:33:02 -0000
@@ -0,0 +1,87 @@
+/*-
+ * Copyright (c) 2005 Antoine Brodin
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD: src/sys/amd64/amd64/stack_machdep.c,v 1.1 2007/12/02 20:40:30 rwatson Exp $");
+
+#include <sys/param.h>
+#include <sys/systm.h>
+#include <sys/proc.h>
+#include <sys/stack.h>
+
+#include <machine/pcb.h>
+#include <machine/stack.h>
+
+#include <vm/vm.h>
+#include <vm/vm_param.h>
+#include <vm/pmap.h>
+
+static void
+stack_capture(struct stack *st, register_t rbp)
+{
+	struct amd64_frame *frame;
+	vm_offset_t callpc;
+
+	stack_zero(st);
+	frame = (struct amd64_frame *)rbp;
+	while (1) {
+		if (!INKERNEL((long)frame))
+			break;
+		callpc = frame->f_retaddr;
+		if (!INKERNEL(callpc))
+			break;
+		if (stack_put(st, callpc) == -1)
+			break;
+		if (frame->f_frame <= frame ||
+		    (vm_offset_t)frame->f_frame >=
+		    (vm_offset_t)rbp + KSTACK_PAGES * PAGE_SIZE)
+			break;
+		frame = frame->f_frame;
+	}
+}
+
+void
+stack_save_td(struct stack *st, struct thread *td)
+{
+	register_t rbp;
+
+	if (TD_IS_SWAPPED(td))
+		panic("stack_save_td: swapped");
+	if (TD_IS_RUNNING(td))
+		panic("stack_save_td: running");
+
+	rbp = td->td_pcb->pcb_rbp;
+	stack_capture(st, rbp);
+}
+
+void
+stack_save(struct stack *st)
+{
+	register_t rbp;
+
+	__asm __volatile("movq %%rbp,%0" : "=r" (rbp));
+	stack_capture(st, rbp);
+}
Index: sys/amd64/include/stack.h
===================================================================
RCS file: sys/amd64/include/stack.h
diff -N sys/amd64/include/stack.h
--- /dev/null	1 Jan 1970 00:00:00 -0000
+++ sys/amd64/include/stack.h	17 Jan 2008 18:33:21 -0000
@@ -0,0 +1,44 @@
+/*-
+ * Mach Operating System
+ * Copyright (c) 1991,1990 Carnegie Mellon University
+ * All Rights Reserved.
+ *
+ * Permission to use, copy, modify and distribute this software and its
+ * documentation is hereby granted, provided that both the copyright
+ * notice and this permission notice appear in all copies of the
+ * software, derivative works or modified versions, and any portions
+ * thereof, and that both notices appear in supporting documentation.
+ *
+ * CARNEGIE MELLON ALLOWS FREE USE OF THIS SOFTWARE IN ITS
+ * CONDITION.  CARNEGIE MELLON DISCLAIMS ANY LIABILITY OF ANY KIND FOR
+ * ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE.
+ *
+ * Carnegie Mellon requests users of this software to return to
+ *
+ *  Software Distribution Coordinator  or  Software.Distribution@CS.CMU.EDU
+ *  School of Computer Science
+ *  Carnegie Mellon University
+ *  Pittsburgh PA 15213-3890
+ *
+ * any improvements or extensions that they make and grant Carnegie the
+ * rights to redistribute these changes.
+ *
+ * $FreeBSD: src/sys/amd64/include/stack.h,v 1.1 2007/12/02 20:40:31 rwatson Exp $
+ */
+
+#ifndef _MACHINE_STACK_H_
+#define	_MACHINE_STACK_H_
+
+/*
+ * Stack trace.
+ */
+#define	INKERNEL(va) (((va) >= DMAP_MIN_ADDRESS && (va) < DMAP_MAX_ADDRESS) \
+	    || ((va) >= KERNBASE && (va) < VM_MAX_KERNEL_ADDRESS))
+
+struct amd64_frame {
+	struct amd64_frame	*f_frame;
+	long			f_retaddr;
+	long			f_arg0;
+};
+
+#endif /* !_MACHINE_STACK_H_ */
Index: sys/arm/arm/db_trace.c
===================================================================
RCS file: /home/data/fbsd-cvs/ncvs/src/sys/arm/arm/db_trace.c,v
retrieving revision 1.13
diff -u -r1.13 db_trace.c
--- sys/arm/arm/db_trace.c	12 Jul 2006 21:22:42 -0000	1.13
+++ sys/arm/arm/db_trace.c	17 Jan 2008 18:33:59 -0000
@@ -43,14 +43,13 @@
 #include <machine/cpufunc.h>
 #include <machine/db_machdep.h>
 #include <machine/pcb.h>
+#include <machine/stack.h>
 #include <machine/vmparam.h>
 #include <ddb/ddb.h>
 #include <ddb/db_access.h>
 #include <ddb/db_sym.h>
 #include <ddb/db_output.h>
 
-#define INKERNEL(va)	(((vm_offset_t)(va)) >= VM_MIN_KERNEL_ADDRESS)
-
 /*
  * APCS stack frames are awkward beasts, so I don't think even trying to use
  * a structure to represent them is a good idea.
@@ -79,11 +78,6 @@
  * fields are actually present.
  */
 
-#define FR_SCP	(0)
-#define FR_RLV	(-1)
-#define FR_RSP	(-2)
-#define FR_RFP	(-3)
-
 static void
 db_stack_trace_cmd(db_expr_t addr, db_expr_t count)
 {
@@ -215,21 +209,3 @@
 {
 	db_trace_thread(curthread, -1);
 }
-
-void
-stack_save(struct stack *st)
-{
-	vm_offset_t callpc;
-	u_int32_t *frame;
-
-	stack_zero(st);
-	frame = (u_int32_t *)__builtin_frame_address(0);
-	while (1) {
-		if (!INKERNEL(frame))
-			break;
-		callpc = frame[FR_SCP];
-		if (stack_put(st, callpc) == -1)
-			break;
-		frame = (u_int32_t *)(frame[FR_RFP]);
-	}
-}
Index: sys/arm/arm/stack_machdep.c
===================================================================
RCS file: sys/arm/arm/stack_machdep.c
diff -N sys/arm/arm/stack_machdep.c
--- /dev/null	1 Jan 1970 00:00:00 -0000
+++ sys/arm/arm/stack_machdep.c	17 Jan 2008 18:34:19 -0000
@@ -0,0 +1,76 @@
+/*-
+ * Copyright (c) 2005 Antoine Brodin
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD: src/sys/arm/arm/stack_machdep.c,v 1.1 2007/12/02 20:40:31 rwatson Exp $");
+
+#include <sys/systm.h>
+#include <sys/param.h>
+#include <sys/proc.h>
+#include <sys/stack.h>
+
+#include <machine/vmparam.h>
+#include <machine/pcb.h>
+#include <machine/stack.h>
+
+static void
+stack_capture(struct stack *st, u_int32_t *frame)
+{
+	vm_offset_t callpc;
+
+	stack_zero(st);
+	while (1) {
+		if (!INKERNEL(frame))
+			break;
+		callpc = frame[FR_SCP];
+		if (stack_put(st, callpc) == -1)
+			break;
+		frame = (u_int32_t *)(frame[FR_RFP]);
+	}
+}
+
+void
+stack_save_td(struct stack *st, struct thread *td)
+{
+	u_int32_t *frame;
+
+	if (TD_IS_SWAPPED(td))
+		panic("stack_save_td: swapped");
+	if (TD_IS_RUNNING(td))
+		panic("stack_save_td: running");
+
+	frame = (u_int32_t *)td->td_pcb->un_32.pcb32_r11;
+	stack_capture(st, frame);
+}
+
+void
+stack_save(struct stack *st)
+{
+	u_int32_t *frame;
+
+	frame = (u_int32_t *)__builtin_frame_address(0);
+	stack_capture(st, frame);
+}
Index: sys/arm/include/stack.h
===================================================================
RCS file: sys/arm/include/stack.h
diff -N sys/arm/include/stack.h
--- /dev/null	1 Jan 1970 00:00:00 -0000
+++ sys/arm/include/stack.h	17 Jan 2008 18:34:30 -0000
@@ -0,0 +1,42 @@
+/*-
+ * Copyright (c) 2000, 2001 Ben Harris
+ * Copyright (c) 1996 Scott K. Stevens
+ *
+ * Mach Operating System
+ * Copyright (c) 1991,1990 Carnegie Mellon University
+ * All Rights Reserved.
+ * 
+ * Permission to use, copy, modify and distribute this software and its
+ * documentation is hereby granted, provided that both the copyright
+ * notice and this permission notice appear in all copies of the
+ * software, derivative works or modified versions, and any portions
+ * thereof, and that both notices appear in supporting documentation.
+ * 
+ * CARNEGIE MELLON ALLOWS FREE USE OF THIS SOFTWARE IN ITS "AS IS"
+ * CONDITION.  CARNEGIE MELLON DISCLAIMS ANY LIABILITY OF ANY KIND FOR
+ * ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE.
+ * 
+ * Carnegie Mellon requests users of this software to return to
+ * 
+ *  Software Distribution Coordinator  or  Software.Distribution@CS.CMU.EDU
+ *  School of Computer Science
+ *  Carnegie Mellon University
+ *  Pittsburgh PA 15213-3890
+ * 
+ * any improvements or extensions that they make and grant Carnegie the
+ * rights to redistribute these changes.
+ *
+ * $FreeBSD: src/sys/arm/include/stack.h,v 1.1 2007/12/02 20:40:31 rwatson Exp $
+ */
+
+#ifndef _MACHINE_STACK_H_
+#define	_MACHINE_STACK_H_
+
+#define INKERNEL(va)	(((vm_offset_t)(va)) >= VM_MIN_KERNEL_ADDRESS)
+
+#define FR_SCP	(0)
+#define FR_RLV	(-1)
+#define FR_RSP	(-2)
+#define FR_RFP	(-3)
+
+#endif /* !_MACHINE_STACK_H_ */
Index: sys/conf/NOTES
===================================================================
RCS file: /home/data/fbsd-cvs/ncvs/src/sys/conf/NOTES,v
retrieving revision 1.1454
diff -u -r1.1454 NOTES
--- sys/conf/NOTES	26 Sep 2007 21:14:17 -0000	1.1454
+++ sys/conf/NOTES	17 Jan 2008 18:34:57 -0000
@@ -471,6 +471,13 @@
 #
 options 	COMPILING_LINT
 
+#
+# STACK enables the stack(9) facility, allowing the capture of kernel stack
+# for the purpose of procinfo(1), etc.  stack(9) will also be compiled in
+# automatically if DDB(4) is compiled into the kernel.
+#
+options 	STACK
+
 
 #####################################################################
 # PERFORMANCE MONITORING OPTIONS
Index: sys/conf/files
===================================================================
RCS file: /home/data/fbsd-cvs/ncvs/src/sys/conf/files,v
retrieving revision 1.1243.2.4
diff -u -r1.1243.2.4 files
--- sys/conf/files	14 Feb 2008 18:33:49 -0000	1.1243.2.4
+++ sys/conf/files	20 Feb 2008 16:38:36 -0000
@@ -1503,7 +1503,7 @@
 kern/subr_scanf.c		standard
 kern/subr_sleepqueue.c		standard
 kern/subr_smp.c			standard
-kern/subr_stack.c		optional ddb
+kern/subr_stack.c		optional ddb | stack
 kern/subr_taskqueue.c		standard
 kern/subr_trap.c		standard
 kern/subr_turnstile.c		standard
Index: sys/conf/files.amd64
===================================================================
RCS file: /home/data/fbsd-cvs/ncvs/src/sys/conf/files.amd64,v
retrieving revision 1.107.2.5
diff -u -r1.107.2.5 files.amd64
--- sys/conf/files.amd64	3 Feb 2008 07:28:38 -0000	1.107.2.5
+++ sys/conf/files.amd64	20 Feb 2008 16:38:36 -0000
@@ -121,6 +121,7 @@
 amd64/amd64/pmap.c		standard
 amd64/amd64/prof_machdep.c	optional	profiling-routine
 amd64/amd64/sigtramp.S		standard
+amd64/amd64/stack_machdep.c	optional	ddb | stack
 amd64/amd64/support.S		standard
 amd64/amd64/sys_machdep.c	standard
 amd64/amd64/trap.c		standard
Index: sys/conf/files.arm
===================================================================
RCS file: /home/data/fbsd-cvs/ncvs/src/sys/conf/files.arm,v
retrieving revision 1.15
diff -u -r1.15 files.arm
--- sys/conf/files.arm	3 Jul 2007 12:13:42 -0000	1.15
+++ sys/conf/files.arm	17 Jan 2008 18:35:49 -0000
@@ -38,6 +38,7 @@
 arm/arm/pmap.c			standard
 arm/arm/setcpsr.S		standard
 arm/arm/setstack.s		standard
+arm/arm/stack_machdep.c		optional	ddb | stack
 arm/arm/support.S		standard
 arm/arm/swtch.S			standard
 arm/arm/sys_machdep.c		standard
Index: sys/conf/files.i386
===================================================================
RCS file: /home/data/fbsd-cvs/ncvs/src/sys/conf/files.i386,v
retrieving revision 1.580.2.5
diff -u -r1.580.2.5 files.i386
--- sys/conf/files.i386	3 Feb 2008 07:28:38 -0000	1.580.2.5
+++ sys/conf/files.i386	20 Feb 2008 16:38:36 -0000
@@ -298,6 +298,7 @@
 i386/i386/perfmon.c		optional perfmon
 i386/i386/pmap.c		standard
 i386/i386/ptrace_machdep.c	standard
+i386/i386/stack_machdep.c	optional ddb | stack
 i386/i386/support.s		standard
 i386/i386/swtch.s		standard
 i386/i386/sys_machdep.c		standard
Index: sys/conf/files.ia64
===================================================================
RCS file: /home/data/fbsd-cvs/ncvs/src/sys/conf/files.ia64,v
retrieving revision 1.92
diff -u -r1.92 files.ia64
--- sys/conf/files.ia64	3 Jul 2007 12:13:42 -0000	1.92
+++ sys/conf/files.ia64	17 Jan 2008 18:58:06 -0000
@@ -98,6 +98,7 @@
 ia64/ia64/setjmp.S		standard
 ia64/ia64/ssc.c			optional	ski
 ia64/ia64/sscdisk.c		optional	ski
+ia64/ia64/stack_machdep.c	optional	ddb | stack
 ia64/ia64/support.S		standard
 ia64/ia64/sys_machdep.c		standard
 ia64/ia64/syscall.S		standard
Index: sys/conf/files.pc98
===================================================================
RCS file: /home/data/fbsd-cvs/ncvs/src/sys/conf/files.pc98,v
retrieving revision 1.356
diff -u -r1.356 files.pc98
--- sys/conf/files.pc98	3 Jul 2007 12:13:42 -0000	1.356
+++ sys/conf/files.pc98	17 Jan 2008 19:31:23 -0000
@@ -177,6 +177,7 @@
 i386/i386/perfmon.c		optional perfmon
 i386/i386/pmap.c		standard
 i386/i386/ptrace_machdep.c	standard
+i386/i386/stack_machdep.c	optional ddb | stack
 i386/i386/support.s		standard
 i386/i386/swtch.s		standard
 i386/i386/sys_machdep.c		standard
Index: sys/conf/files.powerpc
===================================================================
RCS file: /home/data/fbsd-cvs/ncvs/src/sys/conf/files.powerpc,v
retrieving revision 1.65
diff -u -r1.65 files.powerpc
--- sys/conf/files.powerpc	3 Jul 2007 12:13:42 -0000	1.65
+++ sys/conf/files.powerpc	17 Jan 2008 18:58:21 -0000
@@ -61,6 +61,7 @@
 powerpc/powerpc/sc_machdep.c	optional	sc
 powerpc/powerpc/setjmp.S	standard
 powerpc/powerpc/sigcode.S	standard
+powerpc/powerpc/stack_machdep.c	optional	ddb | stack
 powerpc/powerpc/suswintr.c	standard
 powerpc/powerpc/syncicache.c	standard
 powerpc/powerpc/sys_machdep.c	standard
Index: sys/conf/files.sparc64
===================================================================
RCS file: /home/data/fbsd-cvs/ncvs/src/sys/conf/files.sparc64,v
retrieving revision 1.92
diff -u -r1.92 files.sparc64
--- sys/conf/files.sparc64	3 Jul 2007 12:13:42 -0000	1.92
+++ sys/conf/files.sparc64	17 Jan 2008 18:58:30 -0000
@@ -124,6 +124,7 @@
 sparc64/sparc64/rwindow.c	standard
 sparc64/sparc64/sc_machdep.c	optional	sc
 sparc64/sparc64/spitfire.c	standard
+sparc64/sparc64/stack_machdep.c	optional	ddb | stack
 sparc64/sparc64/support.S	standard
 sparc64/sparc64/sys_machdep.c	standard
 sparc64/sparc64/swtch.S		standard
Index: sys/conf/files.sun4v
===================================================================
RCS file: /home/data/fbsd-cvs/ncvs/src/sys/conf/files.sun4v,v
retrieving revision 1.11
diff -u -r1.11 files.sun4v
--- sys/conf/files.sun4v	3 Jul 2007 12:13:42 -0000	1.11
+++ sys/conf/files.sun4v	17 Jan 2008 19:00:35 -0000
@@ -74,6 +74,7 @@
 sparc64/sparc64/rwindow.c		standard
 sun4v/sun4v/rtc.c		standard
 sun4v/sun4v/simdisk.c		optional	simulator
+sun4v/sun4v/stack_machdep.c	optional	ddb | stack
 sun4v/sun4v/support.S		standard
 sparc64/sparc64/sys_machdep.c	standard
 sun4v/sun4v/swtch.S		standard
Index: sys/conf/options
===================================================================
RCS file: /home/data/fbsd-cvs/ncvs/src/sys/conf/options,v
retrieving revision 1.608
diff -u -r1.608 options
--- sys/conf/options	23 Sep 2007 07:34:23 -0000	1.608
+++ sys/conf/options	17 Jan 2008 19:00:48 -0000
@@ -141,6 +141,7 @@
 SLEEPQUEUE_PROFILING
 SLHCI_DEBUG	opt_slhci.h
 SPX_HACK
+STACK		opt_stack.h
 SUIDDIR
 MSGMNB		opt_sysvipc.h
 MSGMNI		opt_sysvipc.h
Index: sys/i386/conf/GENERIC
===================================================================
RCS file: /home/data/fbsd-cvs/ncvs/src/sys/i386/conf/GENERIC,v
retrieving revision 1.474.2.3
diff -u -r1.474.2.3 GENERIC
--- sys/i386/conf/GENERIC	3 Feb 2008 07:28:37 -0000	1.474.2.3
+++ sys/i386/conf/GENERIC	20 Feb 2008 16:39:33 -0000
@@ -54,6 +54,7 @@
 options 	COMPAT_FREEBSD6		# Compatible with FreeBSD6
 options 	SCSI_DELAY=5000		# Delay (in ms) before probing SCSI
 options 	KTRACE			# ktrace(1) support
+options 	STACK			# stack(9) support
 options 	SYSVSHM			# SYSV-style shared memory
 options 	SYSVMSG			# SYSV-style message queues
 options 	SYSVSEM			# SYSV-style semaphores
Index: sys/i386/i386/db_trace.c
===================================================================
RCS file: /home/data/fbsd-cvs/ncvs/src/sys/i386/i386/db_trace.c,v
retrieving revision 1.79
diff -u -r1.79 db_trace.c
--- sys/i386/i386/db_trace.c	19 Feb 2007 10:57:47 -0000	1.79
+++ sys/i386/i386/db_trace.c	17 Jan 2008 19:02:34 -0000
@@ -31,13 +31,13 @@
 #include <sys/systm.h>
 #include <sys/kdb.h>
 #include <sys/proc.h>
-#include <sys/stack.h>
 #include <sys/sysent.h>
 
 #include <machine/cpu.h>
 #include <machine/md_var.h>
 #include <machine/pcb.h>
 #include <machine/reg.h>
+#include <machine/stack.h>
 
 #include <vm/vm.h>
 #include <vm/vm_param.h>
@@ -166,18 +166,6 @@
 	return (1);
 }
 
-/*
- * Stack trace.
- */
-#define	INKERNEL(va)	(((vm_offset_t)(va)) >= USRSTACK && \
-	    ((vm_offset_t)(va)) < VM_MAX_KERNEL_ADDRESS)
-
-struct i386_frame {
-	struct i386_frame	*f_frame;
-	int			f_retaddr;
-	int			f_arg0;
-};
-
 #define NORMAL		0
 #define	TRAP		1
 #define	INTERRUPT	2
@@ -537,32 +525,6 @@
 		    ctx->pcb_eip, count));
 }
 
-void
-stack_save(struct stack *st)
-{
-	struct i386_frame *frame;
-	vm_offset_t callpc;
-	register_t ebp;
-
-	stack_zero(st);
-	__asm __volatile("movl %%ebp,%0" : "=r" (ebp));
-	frame = (struct i386_frame *)ebp;
-	while (1) {
-		if (!INKERNEL(frame))
-			break;
-		callpc = frame->f_retaddr;
-		if (!INKERNEL(callpc))
-			break;
-		if (stack_put(st, callpc) == -1)
-			break;
-		if (frame->f_frame <= frame ||
-		    (vm_offset_t)frame->f_frame >=
-		    (vm_offset_t)ebp + KSTACK_PAGES * PAGE_SIZE)
-			break;
-		frame = frame->f_frame;
-	}
-}
-
 int
 i386_set_watch(watchnum, watchaddr, size, access, d)
 	int watchnum;
Index: sys/i386/i386/stack_machdep.c
===================================================================
RCS file: sys/i386/i386/stack_machdep.c
diff -N sys/i386/i386/stack_machdep.c
--- /dev/null	1 Jan 1970 00:00:00 -0000
+++ sys/i386/i386/stack_machdep.c	17 Jan 2008 19:28:20 -0000
@@ -0,0 +1,87 @@
+/*-
+ * Copyright (c) 2005 Antoine Brodin
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD: src/sys/i386/i386/stack_machdep.c,v 1.2 2007/12/02 21:07:49 rwatson Exp $");
+
+#include <sys/param.h>
+#include <sys/systm.h>
+#include <sys/proc.h>
+#include <sys/stack.h>
+
+#include <machine/pcb.h>
+#include <machine/stack.h>
+
+#include <vm/vm.h>
+#include <vm/vm_param.h>
+#include <vm/pmap.h>
+
+static void
+stack_capture(struct stack *st, register_t ebp)
+{
+	struct i386_frame *frame;
+	vm_offset_t callpc;
+
+	stack_zero(st);
+	frame = (struct i386_frame *)ebp;
+	while (1) {
+		if (!INKERNEL(frame))
+			break;
+		callpc = frame->f_retaddr;
+		if (!INKERNEL(callpc))
+			break;
+		if (stack_put(st, callpc) == -1)
+			break;
+		if (frame->f_frame <= frame ||
+		    (vm_offset_t)frame->f_frame >=
+		    (vm_offset_t)ebp + KSTACK_PAGES * PAGE_SIZE)
+			break;
+		frame = frame->f_frame;
+	}
+}
+
+void
+stack_save_td(struct stack *st, struct thread *td)
+{
+	register_t ebp;
+
+	if (TD_IS_SWAPPED(td))
+		panic("stack_save_td: swapped");
+	if (TD_IS_RUNNING(td))
+		panic("stack_save_td: running");
+
+	ebp = td->td_pcb->pcb_ebp;
+	stack_capture(st, ebp);
+}
+
+void
+stack_save(struct stack *st)
+{
+	register_t ebp;
+
+	__asm __volatile("movl %%ebp,%0" : "=r" (ebp));
+	stack_capture(st, ebp);
+}
Index: sys/i386/include/stack.h
===================================================================
RCS file: sys/i386/include/stack.h
diff -N sys/i386/include/stack.h
--- /dev/null	1 Jan 1970 00:00:00 -0000
+++ sys/i386/include/stack.h	17 Jan 2008 19:03:12 -0000
@@ -0,0 +1,44 @@
+/*-
+ * Mach Operating System
+ * Copyright (c) 1991,1990 Carnegie Mellon University
+ * All Rights Reserved.
+ *
+ * Permission to use, copy, modify and distribute this software and its
+ * documentation is hereby granted, provided that both the copyright
+ * notice and this permission notice appear in all copies of the
+ * software, derivative works or modified versions, and any portions
+ * thereof, and that both notices appear in supporting documentation.
+ *
+ * CARNEGIE MELLON ALLOWS FREE USE OF THIS SOFTWARE IN ITS
+ * CONDITION.  CARNEGIE MELLON DISCLAIMS ANY LIABILITY OF ANY KIND FOR
+ * ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE.
+ *
+ * Carnegie Mellon requests users of this software to return to
+ *
+ *  Software Distribution Coordinator  or  Software.Distribution@CS.CMU.EDU
+ *  School of Computer Science
+ *  Carnegie Mellon University
+ *  Pittsburgh PA 15213-3890
+ *
+ * any improvements or extensions that they make and grant Carnegie the
+ * rights to redistribute these changes.
+ *
+ * $FreeBSD: src/sys/i386/include/stack.h,v 1.1 2007/12/02 20:40:32 rwatson Exp $
+ */
+
+#ifndef _MACHINE_STACK_H_
+#define	_MACHINE_STACK_H_
+
+/*
+ * Stack trace.
+ */
+#define INKERNEL(va)	(((vm_offset_t)(va)) >= USRSTACK && \
+	    ((vm_offset_t)(va)) < VM_MAX_KERNEL_ADDRESS)
+
+struct i386_frame {
+	struct i386_frame	*f_frame;
+	int			 f_retaddr;
+	int			 f_arg0;
+};
+
+#endif /* !_MACHINE_STACK_H_ */
Index: sys/ia64/conf/GENERIC
===================================================================
RCS file: /home/data/fbsd-cvs/ncvs/src/sys/ia64/conf/GENERIC,v
retrieving revision 1.92
diff -u -r1.92 GENERIC
--- sys/ia64/conf/GENERIC	26 Sep 2007 20:05:07 -0000	1.92
+++ sys/ia64/conf/GENERIC	17 Jan 2008 19:03:33 -0000
@@ -50,6 +50,7 @@
 options 	SMP		# Symmetric Multi-Processor support
 options 	SOFTUPDATES	# Enable FFS soft updates support
 options 	UFS_GJOURNAL	# Enable gjournal-based UFS journaling
+options 	STACK		# stack(9) support
 options 	SYSVMSG		# SYSV-style message queues
 options 	SYSVSEM		# SYSV-style semaphores
 options 	SYSVSHM		# SYSV-style shared memory
Index: sys/ia64/ia64/db_machdep.c
===================================================================
RCS file: /home/data/fbsd-cvs/ncvs/src/sys/ia64/ia64/db_machdep.c,v
retrieving revision 1.4
diff -u -r1.4 db_machdep.c
--- sys/ia64/ia64/db_machdep.c	30 Jul 2007 22:42:33 -0000	1.4
+++ sys/ia64/ia64/db_machdep.c	17 Jan 2008 19:07:39 -0000
@@ -595,18 +595,6 @@
 	return (db_backtrace(td, ctx, count));
 }
 
-void
-stack_save(struct stack *st)
-{
-
-	stack_zero(st);
-	/*
-	 * Nothing for now.
-	 * Is libuwx reentrant?
-	 * Can unw_create* sleep?
-	 */
-}
-
 #ifdef EXCEPTION_TRACING
 
 extern long xtrace[];
Index: sys/ia64/ia64/stack_machdep.c
===================================================================
RCS file: sys/ia64/ia64/stack_machdep.c
diff -N sys/ia64/ia64/stack_machdep.c
--- /dev/null	1 Jan 1970 00:00:00 -0000
+++ sys/ia64/ia64/stack_machdep.c	17 Jan 2008 19:07:53 -0000
@@ -0,0 +1,57 @@
+/*-
+ * Copyright (c) 2005 Antoine Brodin
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD: src/sys/ia64/ia64/stack_machdep.c,v 1.1 2007/12/02 20:40:33 rwatson Exp $");
+
+#include <sys/param.h>
+#include <sys/systm.h>
+#include <sys/proc.h>
+#include <sys/stack.h>
+
+void
+stack_save_td(struct stack *st, struct thread *td)
+{
+
+	if (TD_IS_SWAPPED(td))
+		panic("stack_save_td: swapped");
+	if (TD_IS_RUNNING(td))
+		panic("stack_save_td: running");
+
+	stack_zero(st);
+}
+
+void
+stack_save(struct stack *st)
+{
+
+	stack_zero(st);
+	/*
+	 * Nothing for now.
+	 * Is libuwx reentrant?
+	 * Can unw_create* sleep?
+	 */
+}
Index: sys/kern/kern_descrip.c
===================================================================
RCS file: /home/data/fbsd-cvs/ncvs/src/sys/kern/kern_descrip.c,v
retrieving revision 1.313.2.1
diff -u -r1.313.2.1 kern_descrip.c
--- sys/kern/kern_descrip.c	14 Feb 2008 11:44:59 -0000	1.313.2.1
+++ sys/kern/kern_descrip.c	20 Feb 2008 16:39:45 -0000
@@ -44,6 +44,7 @@
 #include <sys/systm.h>
 
 #include <sys/conf.h>
+#include <sys/domain.h>
 #include <sys/fcntl.h>
 #include <sys/file.h>
 #include <sys/filedesc.h>
@@ -59,6 +60,7 @@
 #include <sys/namei.h>
 #include <sys/priv.h>
 #include <sys/proc.h>
+#include <sys/protosw.h>
 #include <sys/resourcevar.h>
 #include <sys/signalvar.h>
 #include <sys/socketvar.h>
@@ -68,6 +70,7 @@
 #include <sys/sysctl.h>
 #include <sys/sysproto.h>
 #include <sys/unistd.h>
+#include <sys/user.h>
 #include <sys/vnode.h>
 
 #include <security/audit/audit.h>
@@ -2405,7 +2408,7 @@
 }
 
 /*
- * Get file structures.
+ * Get file structures globally.
  */
 static int
 sysctl_kern_file(SYSCTL_HANDLER_ARGS)
@@ -2488,6 +2491,182 @@
 SYSCTL_PROC(_kern, KERN_FILE, file, CTLTYPE_OPAQUE|CTLFLAG_RD,
     0, 0, sysctl_kern_file, "S,xfile", "Entire file table");
 
+/*
+ * Get per-process file descriptors for use by procstat(1), et al.
+ */
+static int
+sysctl_kern_proc_filedesc(SYSCTL_HANDLER_ARGS)
+{
+	char *fullpath, *freepath;
+	struct kinfo_file *kif;
+	struct filedesc *fdp;
+	int error, i, *name;
+	struct socket *so;
+	struct vnode *vp;
+	struct file *fp;
+	struct proc *p;
+	int vfslocked;
+
+	name = (int *)arg1;
+	if ((p = pfind((pid_t)name[0])) == NULL)
+		return (ESRCH);
+	if ((error = p_candebug(curthread, p))) {
+		PROC_UNLOCK(p);
+		return (error);
+	}
+	fdp = fdhold(p);
+	PROC_UNLOCK(p);
+	kif = malloc(sizeof(*kif), M_TEMP, M_WAITOK);
+	FILEDESC_SLOCK(fdp);
+	for (i = 0; i < fdp->fd_nfiles; i++) {
+		if ((fp = fdp->fd_ofiles[i]) == NULL)
+			continue;
+		bzero(kif, sizeof(*kif));
+		kif->kf_structsize = sizeof(*kif);
+		FILE_LOCK(fp);
+		vp = NULL;
+		so = NULL;
+		kif->kf_fd = i;
+		switch (fp->f_type) {
+		case DTYPE_VNODE:
+			kif->kf_type = KF_TYPE_VNODE;
+			vp = fp->f_vnode;
+			vref(vp);
+			break;
+
+		case DTYPE_SOCKET:
+			kif->kf_type = KF_TYPE_SOCKET;
+			so = fp->f_data;
+			break;
+
+		case DTYPE_PIPE:
+			kif->kf_type = KF_TYPE_PIPE;
+			break;
+
+		case DTYPE_FIFO:
+			kif->kf_type = KF_TYPE_FIFO;
+			vp = fp->f_vnode;
+			vref(vp);
+			break;
+
+		case DTYPE_KQUEUE:
+			kif->kf_type = KF_TYPE_KQUEUE;
+			break;
+
+		case DTYPE_CRYPTO:
+			kif->kf_type = KF_TYPE_CRYPTO;
+			break;
+
+		case DTYPE_MQUEUE:
+			kif->kf_type = KF_TYPE_MQUEUE;
+			break;
+
+		default:
+			kif->kf_type = KF_TYPE_UNKNOWN;
+			break;
+		}
+		kif->kf_ref_count = fp->f_count;
+		if (fp->f_flag & FREAD)
+			kif->kf_flags |= KF_FLAG_READ;
+		if (fp->f_flag & FWRITE)
+			kif->kf_flags |= KF_FLAG_WRITE;
+		if (fp->f_flag & FAPPEND)
+			kif->kf_flags |= KF_FLAG_APPEND;
+		if (fp->f_flag & FASYNC)
+			kif->kf_flags |= KF_FLAG_ASYNC;
+		if (fp->f_flag & FFSYNC)
+			kif->kf_flags |= KF_FLAG_FSYNC;
+		if (fp->f_flag & FNONBLOCK)
+			kif->kf_flags |= KF_FLAG_NONBLOCK;
+		if (fp->f_flag & O_DIRECT)
+			kif->kf_flags |= KF_FLAG_DIRECT;
+		if (fp->f_flag & FHASLOCK)
+			kif->kf_flags |= KF_FLAG_HASLOCK;
+		kif->kf_offset = fp->f_offset;
+		FILE_UNLOCK(fp);
+		if (vp != NULL) {
+			switch (vp->v_type) {
+			case VNON:
+				kif->kf_vnode_type = KF_VTYPE_VNON;
+				break;
+			case VREG:
+				kif->kf_vnode_type = KF_VTYPE_VREG;
+				break;
+			case VDIR:
+				kif->kf_vnode_type = KF_VTYPE_VDIR;
+				break;
+			case VBLK:
+				kif->kf_vnode_type = KF_VTYPE_VBLK;
+				break;
+			case VCHR:
+				kif->kf_vnode_type = KF_VTYPE_VCHR;
+				break;
+			case VLNK:
+				kif->kf_vnode_type = KF_VTYPE_VLNK;
+				break;
+			case VSOCK:
+				kif->kf_vnode_type = KF_VTYPE_VSOCK;
+				break;
+			case VFIFO:
+				kif->kf_vnode_type = KF_VTYPE_VFIFO;
+				break;
+			case VBAD:
+				kif->kf_vnode_type = KF_VTYPE_VBAD;
+				break;
+			default:
+				kif->kf_vnode_type = KF_VTYPE_UNKNOWN;
+				break;
+			}
+			/*
+			 * It is OK to drop the filedesc lock here as we will
+			 * re-validate and re-evaluate its properties when
+			 * the loop continues.
+			 */
+			freepath = NULL;
+			fullpath = "-";
+			FILEDESC_SUNLOCK(fdp);
+			vfslocked = VFS_LOCK_GIANT(vp->v_mount);
+			vn_lock(vp, LK_EXCLUSIVE | LK_RETRY, curthread);
+			vn_fullpath(curthread, vp, &fullpath, &freepath);
+			vput(vp);
+			VFS_UNLOCK_GIANT(vfslocked);
+			strlcpy(kif->kf_path, fullpath,
+			    sizeof(kif->kf_path));
+			if (freepath != NULL)
+				free(freepath, M_TEMP);
+			FILEDESC_SLOCK(fdp);
+		}
+		if (so != NULL) {
+			struct sockaddr *sa;
+
+			if (so->so_proto->pr_usrreqs->pru_sockaddr(so, &sa)
+			    == 0 && sa->sa_len <= sizeof(kif->kf_sa_local)) {
+				bcopy(sa, &kif->kf_sa_local, sa->sa_len);
+				free(sa, M_SONAME);
+			}
+			if (so->so_proto->pr_usrreqs->pru_peeraddr(so, &sa)
+			    == 00 && sa->sa_len <= sizeof(kif->kf_sa_peer)) {
+				bcopy(sa, &kif->kf_sa_peer, sa->sa_len);
+				free(sa, M_SONAME);
+			}
+			kif->kf_sock_domain =
+			    so->so_proto->pr_domain->dom_family;
+			kif->kf_sock_type = so->so_type;
+			kif->kf_sock_protocol = so->so_proto->pr_protocol;
+		}
+		error = SYSCTL_OUT(req, kif, sizeof(*kif));
+		if (error)
+			break;
+	}
+	FILEDESC_SUNLOCK(fdp);
+	fddrop(fdp);
+	free(kif, M_TEMP);
+	return (0);
+}
+
+static SYSCTL_NODE(_kern_proc, KERN_PROC_FILEDESC, filedesc, CTLFLAG_RD,
+    sysctl_kern_proc_filedesc, "Process filedesc entries");
+
 #ifdef DDB
 /*
  * For the purposes of debugging, generate a human-readable string for the
Index: sys/kern/kern_linker.c
===================================================================
RCS file: /home/data/fbsd-cvs/ncvs/src/sys/kern/kern_linker.c,v
retrieving revision 1.149
diff -u -r1.149 kern_linker.c
--- sys/kern/kern_linker.c	31 May 2007 11:51:51 -0000	1.149
+++ sys/kern/kern_linker.c	17 Jan 2008 17:01:30 -0000
@@ -767,18 +767,18 @@
 	return (0);
 }
 
-#ifdef DDB
 /*
- * DDB Helpers.  DDB has to look across multiple files with their own symbol
- * tables and string tables.
+ * Both DDB and stack(9) rely on the kernel linker to provide forward and
+ * backward lookup of symbols.  However, DDB and sometimes stack(9) need to
+ * do this in a lockfree manner.  We provide a set of internal helper
+ * routines to perform these operations without locks, and then wrappers that
+ * optionally lock.
  *
- * Note that we do not obey list locking protocols here.  We really don't need
- * DDB to hang because somebody's got the lock held.  We'll take the chance
- * that the files list is inconsistant instead.
+ * linker_debug_lookup() is ifdef DDB as currently it's only used by DDB.
  */
-
-int
-linker_ddb_lookup(const char *symstr, c_linker_sym_t *sym)
+#ifdef DDB
+static int
+linker_debug_lookup(const char *symstr, c_linker_sym_t *sym)
 {
 	linker_file_t lf;
 
@@ -788,9 +788,10 @@
 	}
 	return (ENOENT);
 }
+#endif
 
-int
-linker_ddb_search_symbol(caddr_t value, c_linker_sym_t *sym, long *diffp)
+static int
+linker_debug_search_symbol(caddr_t value, c_linker_sym_t *sym, long *diffp)
 {
 	linker_file_t lf;
 	c_linker_sym_t best, es;
@@ -820,8 +821,8 @@
 	}
 }
 
-int
-linker_ddb_symbol_values(c_linker_sym_t sym, linker_symval_t *symval)
+static int
+linker_debug_symbol_values(c_linker_sym_t sym, linker_symval_t *symval)
 {
 	linker_file_t lf;
 
@@ -831,9 +832,82 @@
 	}
 	return (ENOENT);
 }
+
+static int
+linker_debug_search_symbol_name(caddr_t value, char *buf, u_int buflen,
+    long *offset)
+{
+	linker_symval_t symval;
+	c_linker_sym_t sym;
+	int error;
+
+	*offset = 0;
+	error = linker_debug_search_symbol(value, &sym, offset);
+	if (error)
+		return (error);
+	error = linker_debug_symbol_values(sym, &symval);
+	if (error)
+		return (error);
+	strlcpy(buf, symval.name, buflen);
+	return (0);
+}
+
+#ifdef DDB
+/*
+ * DDB Helpers.  DDB has to look across multiple files with their own symbol
+ * tables and string tables.
+ *
+ * Note that we do not obey list locking protocols here.  We really don't need
+ * DDB to hang because somebody's got the lock held.  We'll take the chance
+ * that the files list is inconsistant instead.
+ */
+int
+linker_ddb_lookup(const char *symstr, c_linker_sym_t *sym)
+{
+
+	return (linker_debug_lookup(symstr, sym));
+}
+
+int
+linker_ddb_search_symbol(caddr_t value, c_linker_sym_t *sym, long *diffp)
+{
+
+	return (linker_debug_search_symbol(value, sym, diffp));
+}
+
+int
+linker_ddb_symbol_values(c_linker_sym_t sym, linker_symval_t *symval)
+{
+
+	return (linker_debug_symbol_values(sym, symval));
+}
+
+int
+linker_ddb_search_symbol_name(caddr_t value, char *buf, u_int buflen,
+    long *offset)
+{
+
+	return (linker_debug_search_symbol_name(value, buf, buflen, offset));
+}
 #endif
 
 /*
+ * stack(9) helper for non-debugging environemnts.  Unlike DDB helpers, we do
+ * obey locking protocols, and offer a significantly less complex interface.
+ */
+int
+linker_search_symbol_name(caddr_t value, char *buf, u_int buflen,
+    long *offset)
+{
+	int error;
+
+	KLD_LOCK();
+	error = linker_debug_search_symbol_name(value, buf, buflen, offset);
+	KLD_UNLOCK();
+	return (error);
+}
+
+/*
  * Syscalls.
  */
 int
Index: sys/kern/kern_lock.c
===================================================================
RCS file: /home/data/fbsd-cvs/ncvs/src/sys/kern/kern_lock.c,v
retrieving revision 1.110
diff -u -r1.110 kern_lock.c
--- sys/kern/kern_lock.c	18 May 2007 15:04:59 -0000	1.110
+++ sys/kern/kern_lock.c	17 Jan 2008 17:02:30 -0000
@@ -644,7 +644,7 @@
 	if (lkp->lk_waitcount > 0)
 		printf(" with %d pending", lkp->lk_waitcount);
 #ifdef DEBUG_LOCKS
-	stack_print(&lkp->lk_stack);
+	stack_print_ddb(&lkp->lk_stack);
 #endif
 }
 
Index: sys/kern/kern_proc.c
===================================================================
RCS file: /home/data/fbsd-cvs/ncvs/src/sys/kern/kern_proc.c,v
retrieving revision 1.252.2.3
diff -u -r1.252.2.3 kern_proc.c
--- sys/kern/kern_proc.c	18 Jan 2008 10:02:51 -0000	1.252.2.3
+++ sys/kern/kern_proc.c	31 Jan 2008 08:55:50 -0000
@@ -32,20 +32,25 @@
 #include <sys/cdefs.h>
 __FBSDID("$FreeBSD: src/sys/kern/kern_proc.c,v 1.252.2.3 2008/01/18 10:02:51 kib Exp $");
 
+#include "opt_ddb.h"
 #include "opt_ktrace.h"
 #include "opt_kstack_pages.h"
+#include "opt_stack.h"
 
 #include <sys/param.h>
 #include <sys/systm.h>
 #include <sys/kernel.h>
 #include <sys/lock.h>
 #include <sys/malloc.h>
+#include <sys/mount.h>
 #include <sys/mutex.h>
 #include <sys/proc.h>
 #include <sys/refcount.h>
+#include <sys/sbuf.h>
 #include <sys/sysent.h>
 #include <sys/sched.h>
 #include <sys/smp.h>
+#include <sys/stack.h>
 #include <sys/sysctl.h>
 #include <sys/filedesc.h>
 #include <sys/tty.h>
@@ -60,10 +65,15 @@
 #include <sys/ktrace.h>
 #endif
 
+#ifdef DDB
+#include <ddb/ddb.h>
+#endif
+
 #include <vm/vm.h>
 #include <vm/vm_extern.h>
 #include <vm/pmap.h>
 #include <vm/vm_map.h>
+#include <vm/vm_object.h>
 #include <vm/uma.h>
 
 MALLOC_DEFINE(M_PGRP, "pgrp", "process group header");
@@ -1285,8 +1295,264 @@
 	return (sysctl_handle_string(oidp, sv_name, 0, req));
 }
 
+static int
+sysctl_kern_proc_vmmap(SYSCTL_HANDLER_ARGS)
+{
+	vm_map_entry_t entry, tmp_entry;
+	unsigned int last_timestamp;
+	char *fullpath, *freepath;
+	struct kinfo_vmentry *kve;
+	int error, *name;
+	struct vnode *vp;
+	struct proc *p;
+	vm_map_t map;
+
+	name = (int *)arg1;
+	if ((p = pfind((pid_t)name[0])) == NULL)
+		return (ESRCH);
+	/* XXXRW: Not clear ESRCH is the right error during proc execve(). */
+	if (p->p_flag & P_WEXIT || p->p_flag & P_INEXEC) {
+		PROC_UNLOCK(p);
+		return (ESRCH);
+	}
+	if ((error = p_candebug(curthread, p))) {
+		PROC_UNLOCK(p);
+		return (error);
+	}
+	_PHOLD(p);
+	PROC_UNLOCK(p);
+
+	kve = malloc(sizeof(*kve), M_TEMP, M_WAITOK);
+
+	map = &p->p_vmspace->vm_map;	/* XXXRW: More locking required? */
+	vm_map_lock_read(map);
+	for (entry = map->header.next; entry != &map->header;
+	    entry = entry->next) {
+		vm_object_t obj, tobj, lobj;
+		vm_offset_t addr;
+		int vfslocked;
+
+		if (entry->eflags & MAP_ENTRY_IS_SUB_MAP)
+			continue;
+
+		bzero(kve, sizeof(*kve));
+		kve->kve_structsize = sizeof(*kve);
+
+		kve->kve_private_resident = 0;
+		obj = entry->object.vm_object;
+		if (obj != NULL) {
+			VM_OBJECT_LOCK(obj);
+			if (obj->shadow_count == 1)
+				kve->kve_private_resident =
+				    obj->resident_page_count;
+		}
+		kve->kve_resident = 0;
+		addr = entry->start;
+		while (addr < entry->end) {
+			if (pmap_extract(map->pmap, addr))
+				kve->kve_resident++;
+			addr += PAGE_SIZE;
+		}
+
+		for (lobj = tobj = obj; tobj; tobj = tobj->backing_object) {
+			if (tobj != obj)
+				VM_OBJECT_LOCK(tobj);
+			if (lobj != obj)
+				VM_OBJECT_UNLOCK(lobj);
+			lobj = tobj;
+		}
+
+		freepath = NULL;
+		fullpath = "";
+		if (lobj) {
+			vp = NULL;
+			switch(lobj->type) {
+			case OBJT_DEFAULT:
+				kve->kve_type = KVME_TYPE_DEFAULT;
+				break;
+			case OBJT_VNODE:
+				kve->kve_type = KVME_TYPE_VNODE;
+				vp = lobj->handle;
+				vref(vp);
+				break;
+			case OBJT_SWAP:
+				kve->kve_type = KVME_TYPE_SWAP;
+				break;
+			case OBJT_DEVICE:
+				kve->kve_type = KVME_TYPE_DEVICE;
+				break;
+			case OBJT_PHYS:
+				kve->kve_type = KVME_TYPE_PHYS;
+				break;
+			case OBJT_DEAD:
+				kve->kve_type = KVME_TYPE_DEAD;
+				break;
+			default:
+				kve->kve_type = KVME_TYPE_UNKNOWN;
+				break;
+			}
+			if (lobj != obj)
+				VM_OBJECT_UNLOCK(lobj);
+
+			kve->kve_ref_count = obj->ref_count;
+			kve->kve_shadow_count = obj->shadow_count;
+			VM_OBJECT_UNLOCK(obj);
+			if (vp != NULL) {
+				vfslocked = VFS_LOCK_GIANT(vp->v_mount);
+				vn_lock(vp, LK_EXCLUSIVE | LK_RETRY,
+				    curthread);
+				vn_fullpath(curthread, vp, &fullpath,
+				    &freepath);
+				vput(vp);
+				VFS_UNLOCK_GIANT(vfslocked);
+			}
+		} else {
+			kve->kve_type = KVME_TYPE_NONE;
+			kve->kve_ref_count = 0;
+			kve->kve_shadow_count = 0;
+		}
 
-static SYSCTL_NODE(_kern, KERN_PROC, proc, CTLFLAG_RD,  0, "Process table");
+		kve->kve_start = (void*)entry->start;
+		kve->kve_end = (void*)entry->end;
+
+		if (entry->protection & VM_PROT_READ)
+			kve->kve_protection |= KVME_PROT_READ;
+		if (entry->protection & VM_PROT_WRITE)
+			kve->kve_protection |= KVME_PROT_WRITE;
+		if (entry->protection & VM_PROT_EXECUTE)
+			kve->kve_protection |= KVME_PROT_EXEC;
+
+		if (entry->eflags & MAP_ENTRY_COW)
+			kve->kve_flags |= KVME_FLAG_COW;
+		if (entry->eflags & MAP_ENTRY_NEEDS_COPY)
+			kve->kve_flags |= KVME_FLAG_NEEDS_COPY;
+
+		strlcpy(kve->kve_path, fullpath, sizeof(kve->kve_path));
+		if (freepath != NULL)
+			free(freepath, M_TEMP);
+
+		last_timestamp = map->timestamp;
+		vm_map_unlock_read(map);
+		error = SYSCTL_OUT(req, kve, sizeof(*kve));
+		vm_map_lock_read(map);
+		if (error)
+			break;
+		if (last_timestamp + 1 != map->timestamp) {
+			vm_map_lookup_entry(map, addr - 1, &tmp_entry);
+			entry = tmp_entry;
+		}
+	}
+	vm_map_unlock_read(map);
+	PRELE(p);
+	free(kve, M_TEMP);
+	return (error);
+}
+
+#if defined(STACK) || defined(DDB)
+static int
+sysctl_kern_proc_kstack(SYSCTL_HANDLER_ARGS)
+{
+	struct kinfo_kstack *kkstp;
+	int error, i, *name, numthreads;
+	lwpid_t *lwpidarray;
+	struct thread *td;
+	struct stack *st;
+	struct sbuf sb;
+	struct proc *p;
+
+	name = (int *)arg1;
+	if ((p = pfind((pid_t)name[0])) == NULL)
+		return (ESRCH);
+	/* XXXRW: Not clear ESRCH is the right error during proc execve(). */
+	if (p->p_flag & P_WEXIT || p->p_flag & P_INEXEC) {
+		PROC_UNLOCK(p);
+		return (ESRCH);
+	}
+	if ((error = p_candebug(curthread, p))) {
+		PROC_UNLOCK(p);
+		return (error);
+	}
+	_PHOLD(p);
+	PROC_UNLOCK(p);
+
+	kkstp = malloc(sizeof(*kkstp), M_TEMP, M_WAITOK);
+	st = stack_create();
+
+	lwpidarray = NULL;
+	numthreads = 0;
+	PROC_SLOCK(p);
+repeat:
+	if (numthreads < p->p_numthreads) {
+		if (lwpidarray != NULL) {
+			free(lwpidarray, M_TEMP);
+			lwpidarray = NULL;
+		}
+		numthreads = p->p_numthreads;
+		PROC_SUNLOCK(p);
+		lwpidarray = malloc(sizeof(*lwpidarray) * numthreads, M_TEMP,
+		    M_WAITOK | M_ZERO);
+		PROC_SLOCK(p);
+		goto repeat;
+	}
+	PROC_SUNLOCK(p);
+	i = 0;
+
+	/*
+	 * XXXRW: During the below loop, execve(2) and countless other sorts
+	 * of changes could have taken place.  Should we check to see if the
+	 * vmspace has been replaced, or the like, in order to prevent
+	 * giving a snapshot that spans, say, execve(2), with some threads
+	 * before and some after?  Among other things, the credentials could
+	 * have changed, in which case the right to extract debug info might
+	 * no longer be assured.
+	 */
+	PROC_LOCK(p);
+	FOREACH_THREAD_IN_PROC(p, td) {
+		KASSERT(i < numthreads,
+		    ("sysctl_kern_proc_kstack: numthreads"));
+		lwpidarray[i] = td->td_tid;
+		i++;
+	}
+	numthreads = i;
+	for (i = 0; i < numthreads; i++) {
+		td = thread_find(p, lwpidarray[i]);
+		if (td == NULL) {
+			continue;
+		}
+		bzero(kkstp, sizeof(*kkstp));
+		(void)sbuf_new(&sb, kkstp->kkst_trace,
+		    sizeof(kkstp->kkst_trace), SBUF_FIXEDLEN);
+		thread_lock(td);
+		kkstp->kkst_tid = td->td_tid;
+		if (TD_IS_SWAPPED(td))
+			kkstp->kkst_state = KKST_STATE_SWAPPED;
+		else if (TD_IS_RUNNING(td))
+			kkstp->kkst_state = KKST_STATE_RUNNING;
+		else {
+			kkstp->kkst_state = KKST_STATE_STACKOK;
+			stack_save_td(st, td);
+		}
+		thread_unlock(td);
+		PROC_UNLOCK(p);
+		stack_sbuf_print(&sb, st);
+		sbuf_finish(&sb);
+		sbuf_delete(&sb);
+		error = SYSCTL_OUT(req, kkstp, sizeof(*kkstp));
+		PROC_LOCK(p);
+		if (error)
+			break;
+	}
+	_PRELE(p);
+	PROC_UNLOCK(p);
+	if (lwpidarray != NULL)
+		free(lwpidarray, M_TEMP);
+	stack_destroy(st);
+	free(kkstp, M_TEMP);
+	return (error);
+}
+#endif
+
+SYSCTL_NODE(_kern, KERN_PROC, proc, CTLFLAG_RD,  0, "Process table");
 
 SYSCTL_PROC(_kern_proc, KERN_PROC_ALL, all, CTLFLAG_RD|CTLTYPE_STRUCT,
 	0, 0, sysctl_kern_proc, "S,proc", "Return entire process table");
@@ -1354,3 +1620,11 @@
 
 static SYSCTL_NODE(_kern_proc, (KERN_PROC_PROC | KERN_PROC_INC_THREAD), proc_td,
 	CTLFLAG_RD, sysctl_kern_proc, "Return process table, no threads");
+
+static SYSCTL_NODE(_kern_proc, KERN_PROC_VMMAP, vmmap, CTLFLAG_RD,
+	sysctl_kern_proc_vmmap, "Process vm map entries");
+
+#if defined(STACK) || defined(DDB)
+static SYSCTL_NODE(_kern_proc, KERN_PROC_KSTACK, kstack, CTLFLAG_RD,
+	sysctl_kern_proc_kstack, "Process kernel stacks");
+#endif
Index: sys/kern/subr_stack.c
===================================================================
RCS file: /home/data/fbsd-cvs/ncvs/src/sys/kern/subr_stack.c,v
retrieving revision 1.3
diff -u -r1.3 subr_stack.c
--- sys/kern/subr_stack.c	28 May 2006 22:15:28 -0000	1.3
+++ sys/kern/subr_stack.c	17 Jan 2008 19:31:50 -0000
@@ -24,6 +24,8 @@
  * SUCH DAMAGE.
  */
 
+#include "opt_ddb.h"
+
 #include <sys/cdefs.h>
 __FBSDID("$FreeBSD: src/sys/kern/subr_stack.c,v 1.3 2006/05/28 22:15:28 kris Exp $");
 
@@ -40,7 +42,12 @@
 
 MALLOC_DEFINE(M_STACK, "stack", "Stack Traces");
 
-static void stack_symbol(vm_offset_t pc, const char **name, long *offset);
+static void stack_symbol(vm_offset_t pc, char *namebuf, u_int buflen,
+	    long *offset);
+#ifdef DDB
+static void stack_symbol_ddb(vm_offset_t pc, char *namebuf, u_int buflen,
+	    long *offset);
+#endif
 
 struct stack *
 stack_create(void)
@@ -86,30 +93,69 @@
 void
 stack_print(struct stack *st)
 {
-	const char *name;
+	char namebuf[64];
 	long offset;
 	int i;
 
 	KASSERT(st->depth <= STACK_MAX, ("bogus stack"));
 	for (i = 0; i < st->depth; i++) {
-		stack_symbol(st->pcs[i], &name, &offset);
+		stack_symbol(st->pcs[i], namebuf, sizeof(namebuf), &offset);
 		printf("#%d %p at %s+%#lx\n", i, (void *)st->pcs[i],
-		    name, offset);
+		    namebuf, offset);
 	}
 }
 
+#ifdef DDB
+void
+stack_print_ddb(struct stack *st)
+{
+	char namebuf[64];
+	long offset;
+	int i;
+
+	KASSERT(st->depth <= STACK_MAX, ("bogus stack"));
+	for (i = 0; i < st->depth; i++) {
+		stack_symbol_ddb(st->pcs[i], namebuf, sizeof(namebuf),
+		    &offset);
+		printf("#%d %p at %s+%#lx\n", i, (void *)st->pcs[i],
+		    namebuf, offset);
+	}
+}
+#endif
+
+/*
+ * Two print routines -- one for use from DDB and DDB-like contexts, the
+ * other for use in the live kernel.
+ */
 void
 stack_sbuf_print(struct sbuf *sb, struct stack *st)
 {
-	const char *name;
+	char namebuf[64];
 	long offset;
 	int i;
 
 	KASSERT(st->depth <= STACK_MAX, ("bogus stack"));
 	for (i = 0; i < st->depth; i++) {
-		stack_symbol(st->pcs[i], &name, &offset);
+		stack_symbol(st->pcs[i], namebuf, sizeof(namebuf), &offset);
 		sbuf_printf(sb, "#%d %p at %s+%#lx\n", i, (void *)st->pcs[i],
-		    name, offset);
+		    namebuf, offset);
+	}
+}
+
+#ifdef DDB
+void
+stack_sbuf_print_ddb(struct sbuf *sb, struct stack *st)
+{
+	char namebuf[64];
+	long offset;
+	int i;
+
+	KASSERT(st->depth <= STACK_MAX, ("bogus stack"));
+	for (i = 0; i < st->depth; i++) {
+		stack_symbol_ddb(st->pcs[i], namebuf, sizeof(namebuf),
+		    &offset);
+		sbuf_printf(sb, "#%d %p at %s+%#lx\n", i, (void *)st->pcs[i],
+		    namebuf, offset);
 	}
 }
 
@@ -118,7 +164,7 @@
 stack_ktr(u_int mask, const char *file, int line, struct stack *st, u_int depth,
     int cheap)
 {
-	const char *name;
+	char namebuf[64];
 	long offset;
 	int i;
 
@@ -141,29 +187,40 @@
 		if (depth == 0 || st->depth < depth)
 			depth = st->depth;
 		for (i = 0; i < depth; i++) {
-			stack_symbol(st->pcs[i], &name, &offset);
+			stack_symbol_ddb(st->pcs[i], namebuf,
+			    sizeof(namebuf), &offset);
 			ktr_tracepoint(mask, file, line, "#%d %p at %s+%#lx",
-			    i, st->pcs[i], (u_long)name, offset, 0, 0);
+			    i, st->pcs[i], (u_long)namebuf, offset, 0, 0);
 		}
 	}
 }
 #endif
+#endif
+
+/*
+ * Two variants of stack symbol lookup -- one that uses the DDB interfaces
+ * and bypasses linker locking, and the other that doesn't.
+ */
+static void
+stack_symbol(vm_offset_t pc, char *namebuf, u_int buflen, long *offset)
+{
 
+	if (linker_search_symbol_name((caddr_t)pc, namebuf, buflen,
+	    offset) != 0) {
+		*offset = 0;
+		strlcpy(namebuf, "??", buflen);
+	}
+}
+
+#ifdef DDB
 static void
-stack_symbol(vm_offset_t pc, const char **name, long *offset)
+stack_symbol_ddb(vm_offset_t pc, char *namebuf, u_int buflen, long *offset)
 {
-	linker_symval_t symval;
-	c_linker_sym_t sym;
 
-	if (linker_ddb_search_symbol((caddr_t)pc, &sym, offset) != 0)
-		goto out;
-	if (linker_ddb_symbol_values(sym, &symval) != 0)
-		goto out;
-	if (symval.name != NULL) {
-		*name = symval.name;
-		return;
-	}
-out:
-	*offset = 0;
-	*name = "Unknown func";
+	if (linker_ddb_search_symbol_name((caddr_t)pc, namebuf, buflen,
+	    offset) != 0) {
+		*offset = 0;
+		strlcpy(namebuf, "??", buflen);
+	};
 }
+#endif
Index: sys/pc98/conf/GENERIC
===================================================================
RCS file: /home/data/fbsd-cvs/ncvs/src/sys/pc98/conf/GENERIC,v
retrieving revision 1.297.2.1
diff -u -r1.297.2.1 GENERIC
--- sys/pc98/conf/GENERIC	11 Oct 2007 06:20:27 -0000	1.297.2.1
+++ sys/pc98/conf/GENERIC	17 Jan 2008 19:08:30 -0000
@@ -57,6 +57,7 @@
 #options 	EPSON_MEMWIN		# EPSON memory window support
 #options 	LINE30
 options 	KTRACE			# ktrace(1) support
+options 	STACK			# stack(9) support
 options 	SYSVSHM			# SYSV-style shared memory
 options 	SYSVMSG			# SYSV-style message queues
 options 	SYSVSEM			# SYSV-style semaphores
Index: sys/pc98/include/stack.h
===================================================================
RCS file: sys/pc98/include/stack.h
diff -N sys/pc98/include/stack.h
--- /dev/null	1 Jan 1970 00:00:00 -0000
+++ sys/pc98/include/stack.h	17 Jan 2008 19:31:34 -0000
@@ -0,0 +1,6 @@
+/*-
+ * This file is in the public domain.
+ */
+/* $FreeBSD: src/sys/pc98/include/stack.h,v 1.1 2007/12/03 11:38:28 rwatson Exp $ */
+
+#include <i386/stack.h>
Index: sys/powerpc/conf/GENERIC
===================================================================
RCS file: /home/data/fbsd-cvs/ncvs/src/sys/powerpc/conf/GENERIC,v
retrieving revision 1.71.2.2
diff -u -r1.71.2.2 GENERIC
--- sys/powerpc/conf/GENERIC	29 Oct 2007 00:07:03 -0000	1.71.2.2
+++ sys/powerpc/conf/GENERIC	17 Jan 2008 19:20:14 -0000
@@ -55,6 +55,7 @@
 options 	COMPAT_FREEBSD6		#Compatible with FreeBSD6
 options 	SCSI_DELAY=5000		#Delay (in ms) before probing SCSI 
 options 	KTRACE			#ktrace(1) syscall trace support
+options 	STACK			#stack(9) support
 options 	SYSVSHM			#SYSV-style shared memory
 options 	SYSVMSG			#SYSV-style message queues
 options 	SYSVSEM			#SYSV-style semaphores
Index: sys/powerpc/include/stack.h
===================================================================
RCS file: sys/powerpc/include/stack.h
diff -N sys/powerpc/include/stack.h
--- /dev/null	1 Jan 1970 00:00:00 -0000
+++ sys/powerpc/include/stack.h	17 Jan 2008 19:20:26 -0000
@@ -0,0 +1,36 @@
+/*-
+ * Mach Operating System
+ * Copyright (c) 1992 Carnegie Mellon University
+ * All Rights Reserved.
+ *
+ * Permission to use, copy, modify and distribute this software and its
+ * documentation is hereby granted, provided that both the copyright
+ * notice and this permission notice appear in all copies of the
+ * software, derivative works or modified versions, and any portions
+ * thereof, and that both notices appear in supporting documentation.
+ *
+ * CARNEGIE MELLON ALLOWS FREE USE OF THIS SOFTWARE IN ITS "AS IS"
+ * CONDITION.  CARNEGIE MELLON DISCLAIMS ANY LIABILITY OF ANY KIND FOR
+ * ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE.
+ *
+ * Carnegie Mellon requests users of this software to return to
+ *
+ *  Software Distribution Coordinator  or  Software.Distribution@CS.CMU.EDU
+ *  School of Computer Science
+ *  Carnegie Mellon University
+ *  Pittsburgh PA 15213-3890
+ *
+ * any improvements or extensions that they make and grant Carnegie Mellon
+ * the rights to redistribute these changes.
+ *
+ * $FreeBSD: src/sys/powerpc/include/stack.h,v 1.1 2007/12/02 20:40:34 rwatson Exp $
+ */
+
+#ifndef _MACHINE_STACK_H_
+#define	_MACHINE_STACK_H_
+
+extern int trapexit[];
+extern int asttrapexit[];
+extern int end[];
+
+#endif /* !_MACHINE_STACK_H_ */
Index: sys/powerpc/powerpc/db_trace.c
===================================================================
RCS file: /home/data/fbsd-cvs/ncvs/src/sys/powerpc/powerpc/db_trace.c,v
retrieving revision 1.13
diff -u -r1.13 db_trace.c
--- sys/powerpc/powerpc/db_trace.c	12 Jul 2006 21:22:44 -0000	1.13
+++ sys/powerpc/powerpc/db_trace.c	17 Jan 2008 19:23:14 -0000
@@ -41,6 +41,7 @@
 #include <machine/db_machdep.h>
 #include <machine/pcb.h>
 #include <machine/spr.h>
+#include <machine/stack.h>
 #include <machine/trap.h>
 
 #include <ddb/ddb.h>
@@ -96,10 +97,6 @@
 };
 struct db_variable *db_eregs = db_regs + sizeof (db_regs)/sizeof (db_regs[0]);
 
-extern int trapexit[];
-extern int asttrapexit[];
-extern int end[];
-
 /*
  * register variable handling
  */
@@ -287,37 +284,3 @@
 	ctx = kdb_thr_ctx(td);
 	return (db_backtrace(td, (db_addr_t)ctx->pcb_sp, count));
 }
-
-void
-stack_save(struct stack *st)
-{
-	vm_offset_t callpc;
-	db_addr_t stackframe;
-
-	stack_zero(st);
-	stackframe = (db_addr_t)__builtin_frame_address(1);
-	if (stackframe < PAGE_SIZE)
-		return;
-	while (1) {
-		stackframe = *(db_addr_t *)stackframe;
-		if (stackframe < PAGE_SIZE)
-			break;
-		callpc = *(vm_offset_t *)(stackframe + 4) - 4;
-		if ((callpc & 3) || (callpc < 0x100))
-			break;
-
-		/*
-		 * Don't bother traversing trap-frames - there should
-		 * be enough info down to the frame to work out where
-		 * things are going wrong. Plus, prevents this shortened
-		 * version of code from accessing user-space frames
-		 */
-		if (callpc + 4 == (db_addr_t) &trapexit ||
-		    callpc + 4 == (db_addr_t) &asttrapexit)
-			break;
-
-		if (stack_put(st, callpc) == -1)
-			break;
-	}
-}
-
Index: sys/powerpc/powerpc/stack_machdep.c
===================================================================
RCS file: sys/powerpc/powerpc/stack_machdep.c
diff -N sys/powerpc/powerpc/stack_machdep.c
--- /dev/null	1 Jan 1970 00:00:00 -0000
+++ sys/powerpc/powerpc/stack_machdep.c	17 Jan 2008 19:23:25 -0000
@@ -0,0 +1,97 @@
+/*-
+ * Copyright (c) 2005 Antoine Brodin
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD: src/sys/powerpc/powerpc/stack_machdep.c,v 1.1 2007/12/02 20:40:34 rwatson Exp $");
+
+#include <sys/param.h>
+#include <sys/proc.h>
+#include <sys/stack.h>
+#include <sys/systm.h>
+
+#include <vm/vm.h>
+#include <vm/pmap.h>
+#include <vm/vm_extern.h>
+
+#include <machine/db_machdep.h>
+#include <machine/pcb.h>
+#include <machine/spr.h>
+#include <machine/stack.h>
+#include <machine/trap.h>
+
+static void
+stack_capture(struct stack *st, register_t frame)
+{
+	vm_offset_t callpc;
+
+	stack_zero(st);
+	if (frame < PAGE_SIZE)
+		return;
+	while (1) {
+		frame = *(register_t *)frame;
+		if (frame < PAGE_SIZE)
+			break;
+		callpc = *(vm_offset_t *)(frame + 4) - 4;
+		if ((callpc & 3) || (callpc < 0x100))
+			break;
+
+		/*
+		 * Don't bother traversing trap-frames - there should
+		 * be enough info down to the frame to work out where
+		 * things are going wrong. Plus, prevents this shortened
+		 * version of code from accessing user-space frames
+		 */
+		if (callpc + 4 == (register_t) &trapexit ||
+		    callpc + 4 == (register_t) &asttrapexit)
+			break;
+
+		if (stack_put(st, callpc) == -1)
+			break;
+	}
+}
+
+void
+stack_save_td(struct stack *st, struct thread *td)
+{
+	register_t frame;
+
+	if (TD_IS_SWAPPED(td))
+		panic("stack_save_td: swapped");
+	if (TD_IS_RUNNING(td))
+		panic("stack_save_td: running");
+
+	frame = td->td_pcb->pcb_sp;
+	stack_capture(st, frame);
+}
+
+void
+stack_save(struct stack *st)
+{
+	register_t frame;
+
+	frame = (register_t)__builtin_frame_address(1);
+	stack_capture(st, frame);
+}
Index: sys/sparc64/conf/GENERIC
===================================================================
RCS file: /home/data/fbsd-cvs/ncvs/src/sys/sparc64/conf/GENERIC,v
retrieving revision 1.127.2.1
diff -u -r1.127.2.1 GENERIC
--- sys/sparc64/conf/GENERIC	11 Oct 2007 06:20:27 -0000	1.127.2.1
+++ sys/sparc64/conf/GENERIC	17 Jan 2008 19:24:20 -0000
@@ -56,6 +56,7 @@
 options 	COMPAT_FREEBSD6		# Compatible with FreeBSD6
 options 	SCSI_DELAY=5000		# Delay (in ms) before probing SCSI
 options 	KTRACE			# ktrace(1) support
+options 	STACK			# stack(9) support
 options 	SYSVSHM			# SYSV-style shared memory
 options 	SYSVMSG			# SYSV-style message queues
 options 	SYSVSEM			# SYSV-style semaphores
Index: sys/sparc64/include/stack.h
===================================================================
RCS file: sys/sparc64/include/stack.h
diff -N sys/sparc64/include/stack.h
--- /dev/null	1 Jan 1970 00:00:00 -0000
+++ sys/sparc64/include/stack.h	17 Jan 2008 19:24:53 -0000
@@ -0,0 +1,40 @@
+/*-
+ * Copyright (c) 2001 Jake Burkholder.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * $FreeBSD: src/sys/sparc64/include/stack.h,v 1.1 2007/12/02 20:40:34 rwatson Exp $
+ */
+
+#ifndef _MACHINE_STACK_H_
+#define	_MACHINE_STACK_H_
+
+extern char tl_trap_begin[];
+extern char tl_trap_end[];
+extern char tl_text_begin[];
+extern char tl_text_end[];
+
+#define	INKERNEL(va) \
+	((va) >= VM_MIN_KERNEL_ADDRESS && (va) <= VM_MAX_KERNEL_ADDRESS)
+
+#endif /* !_MACHINE_STACK_H_ */
Index: sys/sparc64/sparc64/db_trace.c
===================================================================
RCS file: /home/data/fbsd-cvs/ncvs/src/sys/sparc64/sparc64/db_trace.c,v
retrieving revision 1.26
diff -u -r1.26 db_trace.c
--- sys/sparc64/sparc64/db_trace.c	12 Jul 2006 21:22:44 -0000	1.26
+++ sys/sparc64/sparc64/db_trace.c	17 Jan 2008 19:25:16 -0000
@@ -41,6 +41,7 @@
 
 #include <machine/cpu.h>
 #include <machine/pcb.h>
+#include <machine/stack.h>
 #include <machine/trap.h>
 #include <machine/vmparam.h>
 
@@ -50,14 +51,6 @@
 #include <ddb/db_variables.h>
 #include <ddb/db_watch.h>
 
-extern char tl_trap_begin[];
-extern char tl_trap_end[];
-extern char tl_text_begin[];
-extern char tl_text_end[];
-
-#define	INKERNEL(va) \
-	((va) >= VM_MIN_KERNEL_ADDRESS && (va) <= VM_MAX_KERNEL_ADDRESS)
-
 static db_varfcn_t db_frame;
 
 #define	DB_OFFSET(x)	(db_expr_t *)offsetof(struct trapframe, x)
@@ -297,29 +290,3 @@
 	ctx = kdb_thr_ctx(td);
 	return (db_backtrace(td, (struct frame*)(ctx->pcb_sp + SPOFF), count));
 }
-
-void
-stack_save(struct stack *st)
-{
-	struct frame *fp;
-	db_expr_t addr;
-	vm_offset_t callpc;
-
-	stack_zero(st);
-	addr = (db_expr_t)__builtin_frame_address(1);
-	fp = (struct frame *)(addr + SPOFF);
-	while (1) {
-		callpc = fp->fr_pc;
-		if (!INKERNEL(callpc))
-			break;
-		/* Don't bother traversing trap frames. */
-		if ((callpc > (u_long)tl_trap_begin &&
-		    callpc < (u_long)tl_trap_end) ||
-		    (callpc > (u_long)tl_text_begin &&
-		    callpc < (u_long)tl_text_end))
-			break;
-		if (stack_put(st, callpc) == -1)
-			break;
-		fp = (struct frame *)(fp->fr_fp + SPOFF);
-	}
-}
Index: sys/sparc64/sparc64/stack_machdep.c
===================================================================
RCS file: sys/sparc64/sparc64/stack_machdep.c
diff -N sys/sparc64/sparc64/stack_machdep.c
--- /dev/null	1 Jan 1970 00:00:00 -0000
+++ sys/sparc64/sparc64/stack_machdep.c	17 Jan 2008 19:25:27 -0000
@@ -0,0 +1,90 @@
+/*-
+ * Copyright (c) 2005 Antoine Brodin
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD: src/sys/sparc64/sparc64/stack_machdep.c,v 1.1 2007/12/02 20:40:34 rwatson Exp $");
+
+#include <sys/param.h>
+#include <sys/proc.h>
+#include <sys/stack.h>
+#include <sys/systm.h>
+
+#include <vm/vm.h>
+#include <vm/vm_page.h>
+#include <vm/vm_map.h>
+
+#include <machine/cpu.h>
+#include <machine/pcb.h>
+#include <machine/stack.h>
+#include <machine/trap.h>
+#include <machine/vmparam.h>
+
+static void
+stack_capture(struct stack *st, uint64_t addr)
+{
+	struct frame *fp;
+	vm_offset_t callpc;
+
+	stack_zero(st);
+	fp = (struct frame *)(addr + SPOFF);
+	while (1) {
+		callpc = fp->fr_pc;
+		if (!INKERNEL(callpc))
+			break;
+		/* Don't bother traversing trap frames. */
+		if ((callpc > (uint64_t)tl_trap_begin &&
+		    callpc < (uint64_t)tl_trap_end) ||
+		    (callpc > (uint64_t)tl_text_begin &&
+		    callpc < (uint64_t)tl_text_end))
+			break;
+		if (stack_put(st, callpc) == -1)
+			break;
+		fp = (struct frame *)(fp->fr_fp + SPOFF);
+	}
+}
+
+void
+stack_save_td(struct stack *st, struct thread *td)
+{
+	uint64_t addr;
+
+	if (TD_IS_SWAPPED(td))
+		panic("stack_save_td: swapped");
+	if (TD_IS_RUNNING(td))
+		panic("stack_save_td: running");
+
+	addr = td->td_pcb->pcb_sp;
+	stack_capture(st, addr);
+}
+
+void
+stack_save(struct stack *st)
+{
+	uint64_t addr;
+
+	addr = (uint64_t)__builtin_frame_address(1);
+	stack_capture(st, addr);
+}
Index: sys/sun4v/conf/GENERIC
===================================================================
RCS file: /home/data/fbsd-cvs/ncvs/src/sys/sun4v/conf/GENERIC,v
retrieving revision 1.14.2.1
diff -u -r1.14.2.1 GENERIC
--- sys/sun4v/conf/GENERIC	11 Oct 2007 06:20:27 -0000	1.14.2.1
+++ sys/sun4v/conf/GENERIC	17 Jan 2008 19:26:30 -0000
@@ -55,6 +55,7 @@
 options 	COMPAT_FREEBSD5		# Compatible with FreeBSD5
 options 	SCSI_DELAY=5000		# Delay (in ms) before probing SCSI
 options 	KTRACE			# ktrace(1) support
+options 	STACK			# stack(9) support
 options 	SYSVSHM			# SYSV-style shared memory
 options 	SYSVMSG			# SYSV-style message queues
 options 	SYSVSEM			# SYSV-style semaphores
Index: sys/sun4v/include/stack.h
===================================================================
RCS file: sys/sun4v/include/stack.h
diff -N sys/sun4v/include/stack.h
--- /dev/null	1 Jan 1970 00:00:00 -0000
+++ sys/sun4v/include/stack.h	17 Jan 2008 19:26:43 -0000
@@ -0,0 +1,35 @@
+/*-
+ * Copyright (c) 2001 Jake Burkholder.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * $FreeBSD: src/sys/sun4v/include/stack.h,v 1.1 2007/12/02 20:40:35 rwatson Exp $
+ */
+
+#ifndef _MACHINE_STACK_H_
+#define	_MACHINE_STACK_H_
+
+#define	INKERNEL(va) \
+	((va) >= VM_MIN_KERNEL_ADDRESS && (va) <= VM_MAX_KERNEL_ADDRESS)
+
+#endif /* !_MACHINE_STACK_H_ */
Index: sys/sun4v/sun4v/db_trace.c
===================================================================
RCS file: /home/data/fbsd-cvs/ncvs/src/sys/sun4v/sun4v/db_trace.c,v
retrieving revision 1.1
diff -u -r1.1 db_trace.c
--- sys/sun4v/sun4v/db_trace.c	5 Oct 2006 06:14:28 -0000	1.1
+++ sys/sun4v/sun4v/db_trace.c	17 Jan 2008 19:27:33 -0000
@@ -40,6 +40,7 @@
 
 #include <machine/cpu.h>
 #include <machine/pcb.h>
+#include <machine/stack.h>
 #include <machine/trap.h>
 #include <machine/vmparam.h>
 
@@ -49,9 +50,6 @@
 #include <ddb/db_variables.h>
 #include <ddb/db_watch.h>
 
-#define	INKERNEL(va) \
-	((va) >= VM_MIN_KERNEL_ADDRESS && (va) <= VM_MAX_KERNEL_ADDRESS)
-
 static db_varfcn_t db_frame;
 
 #define	DB_OFFSET(x)	(db_expr_t *)offsetof(struct trapframe, x)
@@ -304,23 +302,3 @@
 	ctx = kdb_thr_ctx(td);
 	return (db_backtrace(td, (struct frame*)(ctx->pcb_sp + SPOFF), count));
 }
-
-void
-stack_save(struct stack *st)
-{
-	struct frame *fp;
-	db_expr_t addr;
-	vm_offset_t callpc;
-
-	stack_zero(st);
-	addr = (db_expr_t)__builtin_frame_address(1);
-	fp = (struct frame *)(addr + SPOFF);
-	while (1) {
-		callpc = fp->fr_pc;
-		if (!INKERNEL(callpc))
-			break;
-		if (stack_put(st, callpc) == -1)
-			break;
-		fp = (struct frame *)(fp->fr_fp + SPOFF);
-	}
-}
Index: sys/sun4v/sun4v/stack_machdep.c
===================================================================
RCS file: sys/sun4v/sun4v/stack_machdep.c
diff -N sys/sun4v/sun4v/stack_machdep.c
--- /dev/null	1 Jan 1970 00:00:00 -0000
+++ sys/sun4v/sun4v/stack_machdep.c	17 Jan 2008 19:27:46 -0000
@@ -0,0 +1,85 @@
+/*-
+ * Copyright (c) 2005 Antoine Brodin
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD: src/sys/sun4v/sun4v/stack_machdep.c,v 1.1 2007/12/02 20:40:35 rwatson Exp $");
+
+#include <sys/param.h>
+#include <sys/proc.h>
+#include <sys/stack.h>
+#include <sys/systm.h>
+
+#include <vm/vm.h>
+#include <vm/vm_page.h>
+#include <vm/vm_map.h>
+
+#include <machine/cpu.h>
+#include <machine/pcb.h>
+#include <machine/stack.h>
+#include <machine/trap.h>
+#include <machine/vmparam.h>
+
+static void
+stack_capture(struct stack *st, uint64_t addr)
+{
+	struct frame *fp;
+	vm_offset_t callpc;
+
+	stack_zero(st);
+	fp = (struct frame *)(addr + SPOFF);
+	while (1) {
+		callpc = fp->fr_pc;
+		if (!INKERNEL(callpc))
+			break;
+		if (stack_put(st, callpc) == -1)
+			break;
+		fp = (struct frame *)(fp->fr_fp + SPOFF);
+	}
+
+}
+
+void
+stack_save_td(struct stack *st, struct thread *td)
+{
+	uint64_t addr;
+
+	if (TD_IS_SWAPPED(td))
+		panic("stack_save_td: swapped");
+	if (TD_IS_RUNNING(td))
+		panic("stack_save_td: running");
+
+	addr = td->td_pcb->pcb_sp;
+	stack_capture(st, addr);
+}
+
+void
+stack_save(struct stack *st)
+{
+	uint64_t addr;
+
+	addr = (uint64_t)__builtin_frame_address(1);
+	stack_capture(st, addr);
+}
Index: sys/sys/linker.h
===================================================================
RCS file: /home/data/fbsd-cvs/ncvs/src/sys/sys/linker.h,v
retrieving revision 1.46
diff -u -r1.46 linker.h
--- sys/sys/linker.h	20 Jun 2006 20:59:55 -0000	1.46
+++ sys/sys/linker.h	17 Jan 2008 17:01:41 -0000
@@ -155,6 +155,14 @@
 int linker_ddb_search_symbol(caddr_t _value, c_linker_sym_t *_sym,
 			     long *_diffp);
 int linker_ddb_symbol_values(c_linker_sym_t _sym, linker_symval_t *_symval);
+int linker_ddb_search_symbol_name(caddr_t value, char *buf, u_int buflen,
+				  long *offset);
+
+/*
+ * stack(9) helper for situations where kernel locking is required.
+ */
+int linker_search_symbol_name(caddr_t value, char *buf, u_int buflen,
+    long *offset);
 
 
 /* HWPMC helper */
Index: sys/sys/stack.h
===================================================================
RCS file: /home/data/fbsd-cvs/ncvs/src/sys/sys/stack.h,v
retrieving revision 1.2
diff -u -r1.2 stack.h
--- sys/sys/stack.h	29 Aug 2005 11:34:08 -0000	1.2
+++ sys/sys/stack.h	17 Jan 2008 19:27:58 -0000
@@ -45,7 +45,9 @@
 void		 stack_copy(struct stack *, struct stack *);
 void		 stack_zero(struct stack *);
 void		 stack_print(struct stack *);
+void		 stack_print_ddb(struct stack *);
 void		 stack_sbuf_print(struct sbuf *, struct stack *);
+void		 stack_sbuf_print_ddb(struct sbuf *, struct stack *);
 #ifdef KTR
 void		 stack_ktr(u_int, const char *, int, struct stack *, u_int, int);
 #define	CTRSTACK(m, st, depth, cheap) do {				\
@@ -57,6 +59,8 @@
 #endif
 
 /* MD Routine. */
+struct thread;
 void		 stack_save(struct stack *);
+void		 stack_save_td(struct stack *, struct thread *);
 
 #endif
Index: sys/sys/sysctl.h
===================================================================
RCS file: /home/data/fbsd-cvs/ncvs/src/sys/sys/sysctl.h,v
retrieving revision 1.148
diff -u -r1.148 sysctl.h
--- sys/sys/sysctl.h	4 Jun 2007 18:14:28 -0000	1.148
+++ sys/sys/sysctl.h	17 Jan 2008 19:28:45 -0000
@@ -456,6 +456,9 @@
 #define	KERN_PROC_RGID		10	/* by real group id */
 #define	KERN_PROC_GID		11	/* by effective group id */
 #define	KERN_PROC_PATHNAME	12	/* path to executable */
+#define	KERN_PROC_VMMAP		13	/* VM map entries for process */
+#define	KERN_PROC_FILEDESC	14	/* File descriptors for process */
+#define	KERN_PROC_KSTACK	15	/* Kernel stacks for process */
 #define	KERN_PROC_INC_THREAD	0x10	/*
 					 * modifier for pid, pgrp, tty,
 					 * uid, ruid, gid, rgid and proc
@@ -618,6 +621,7 @@
 extern struct sysctl_oid_list sysctl__children;
 SYSCTL_DECL(_kern);
 SYSCTL_DECL(_kern_ipc);
+SYSCTL_DECL(_kern_proc);
 SYSCTL_DECL(_sysctl);
 SYSCTL_DECL(_vm);
 SYSCTL_DECL(_vm_stats);
Index: sys/sys/user.h
===================================================================
RCS file: /home/data/fbsd-cvs/ncvs/src/sys/sys/user.h,v
retrieving revision 1.70
diff -u -r1.70 user.h
--- sys/sys/user.h	17 Sep 2007 05:27:21 -0000	1.70
+++ sys/sys/user.h	17 Jan 2008 16:53:30 -0000
@@ -1,6 +1,8 @@
 /*-
  * Copyright (c) 1982, 1986, 1989, 1991, 1993
- *	The Regents of the University of California.  All rights reserved.
+ *	The Regents of the University of California.
+ * Copyright (c) 2007 Robert N. M. Watson
+ * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
  * modification, are permitted provided that the following conditions
@@ -56,6 +58,9 @@
 #ifndef _SYS_SIGNALVAR_H_
 #include <sys/signalvar.h>
 #endif
+#ifndef _SYS_SOCKET_VAR_H_
+#include <sys/socket.h>
+#endif
 
 /*
  * KERN_PROC subtype ops return arrays of selected proc structure entries:
@@ -228,4 +233,109 @@
 	struct	kinfo_proc u_kproc;	/* eproc */
 };
 
+/*
+ * The KERN_PROC_FILE sysctl allows a process to dumpt the file descriptor
+ * array of another process.
+ */
+#define	KF_TYPE_NONE	0
+#define	KF_TYPE_VNODE	1
+#define	KF_TYPE_SOCKET	2
+#define	KF_TYPE_PIPE	3
+#define	KF_TYPE_FIFO	4
+#define	KF_TYPE_KQUEUE	5
+#define	KF_TYPE_CRYPTO	6
+#define	KF_TYPE_MQUEUE	7
+#define	KF_TYPE_UNKNOWN	255
+
+#define	KF_VTYPE_VNON	0
+#define	KF_VTYPE_VREG	1
+#define	KF_VTYPE_VDIR	2
+#define	KF_VTYPE_VBLK	3
+#define	KF_VTYPE_VCHR	4
+#define	KF_VTYPE_VLNK	5
+#define	KF_VTYPE_VSOCK	6
+#define	KF_VTYPE_VFIFO	7
+#define	KF_VTYPE_VBAD	8
+#define	KF_VTYPE_UNKNOWN	255
+
+#define	KF_FLAG_READ		0x00000001
+#define	KF_FLAG_WRITE		0x00000002
+#define	KF_FLAG_APPEND		0x00000004
+#define	KF_FLAG_ASYNC		0x00000008
+#define	KF_FLAG_FSYNC		0x00000010
+#define	KF_FLAG_NONBLOCK	0x00000020
+#define	KF_FLAG_DIRECT		0x00000040
+#define	KF_FLAG_HASLOCK		0x00000080
+
+struct kinfo_file {
+	int	kf_structsize;			/* Size of kinfo_file. */
+	int	kf_type;			/* Descriptor type. */
+	int	kf_fd;				/* Array index. */
+	int	kf_ref_count;			/* Reference count. */
+	int	kf_flags;			/* Flags. */
+	off_t	kf_offset;			/* Seek location. */
+	int	kf_vnode_type;			/* Vnode type. */
+	int	kf_sock_domain;			/* Socket domain. */
+	int	kf_sock_type;			/* Socket type. */
+	int	kf_sock_protocol;		/* Socket protocol. */
+	char	kf_path[PATH_MAX];		/* Path to file, if any. */
+	struct sockaddr_storage kf_sa_local;	/* Socket address. */
+	struct sockaddr_storage	kf_sa_peer;	/* Peer address. */
+};
+
+/*
+ * The KERN_PROC_VMMAP sysctl allows a process to dump the VM layout of
+ * another process as a series of entries.
+ */
+#define	KVME_TYPE_NONE		0
+#define	KVME_TYPE_DEFAULT	1
+#define	KVME_TYPE_VNODE		2
+#define	KVME_TYPE_SWAP		3
+#define	KVME_TYPE_DEVICE	4
+#define	KVME_TYPE_PHYS		5
+#define	KVME_TYPE_DEAD		6
+#define	KVME_TYPE_UNKNOWN	255
+
+#define	KVME_PROT_READ		0x00000001
+#define	KVME_PROT_WRITE		0x00000002
+#define	KVME_PROT_EXEC		0x00000004
+
+#define	KVME_FLAG_COW		0x00000001
+#define	KVME_FLAG_NEEDS_COPY	0x00000002
+
+struct kinfo_vmentry {
+	int	 kve_structsize;		/* Size of kinfo_vmmapentry. */
+	int	 kve_type;			/* Type of map entry. */
+	void	*kve_start;			/* Starting pointer. */
+	void	*kve_end;			/* Finishing pointer. */
+	int	 kve_flags;			/* Flags on map entry. */
+	int	 kve_resident;			/* Number of resident pages. */
+	int	 kve_private_resident;		/* Number of private pages. */
+	int	 kve_protection;		/* Protection bitmask. */
+	int	 kve_ref_count;			/* VM obj ref count. */
+	int	 kve_shadow_count;		/* VM obj shadow count. */
+	char	 kve_path[PATH_MAX];		/* Path to VM obj, if any. */
+	void	*_kve_pspare[8];		/* Space for more stuff. */
+	int	 _kve_ispare[8];		/* Space for more stuff. */
+};
+
+/*
+ * The KERN_PROC_KSTACK sysctl allows a process to dump the kernel stacks of
+ * another process as a series of entries.  Each stack is represented by a
+ * series of symbol names and offsets as generated by stack_sbuf_print(9).
+ */
+#define	KKST_MAXLEN	1024
+
+#define	KKST_STATE_STACKOK	0		/* Stack is valid. */
+#define	KKST_STATE_SWAPPED	1		/* Stack swapped out. */
+#define	KKST_STATE_RUNNING	2		/* Stack ephemeral. */
+
+struct kinfo_kstack {
+	lwpid_t	 kkst_tid;			/* ID of thread. */
+	int	 kkst_state;			/* Validity of stack. */
+	char	 kkst_trace[KKST_MAXLEN];	/* String representing stack. */
+	void	*_kkst_pspare[8];		/* Space for more stuff. */
+	int	 _kkst_ispare[8];		/* Space for more stuff. */
+};
+
 #endif
Index: sys/vm/redzone.c
===================================================================
RCS file: /home/data/fbsd-cvs/ncvs/src/sys/vm/redzone.c,v
retrieving revision 1.1
diff -u -r1.1 redzone.c
--- sys/vm/redzone.c	31 Jan 2006 11:09:20 -0000	1.1
+++ sys/vm/redzone.c	17 Jan 2008 17:03:21 -0000
@@ -152,10 +152,10 @@
 		    "corrupted before %p (%lu bytes allocated).\n",
 		    ncorruptions, ncorruptions == 1 ? "" : "s", naddr, nsize);
 		printf("Allocation backtrace:\n");
-		stack_print(&ast);
+		stack_print_ddb(&ast);
 		printf("Free backtrace:\n");
 		stack_save(&fst);
-		stack_print(&fst);
+		stack_print_ddb(&fst);
 		if (redzone_panic)
 			panic("Stopping here.");
 	}
@@ -171,10 +171,10 @@
 		    "after %p (%lu bytes allocated).\n", ncorruptions,
 		    ncorruptions == 1 ? "" : "s", naddr + nsize, nsize);
 		printf("Allocation backtrace:\n");
-		stack_print(&ast);
+		stack_print_ddb(&ast);
 		printf("Free backtrace:\n");
 		stack_save(&fst);
-		stack_print(&fst);
+		stack_print_ddb(&fst);
 		if (redzone_panic)
 			panic("Stopping here.");
 	}
Index: usr.bin/Makefile
===================================================================
RCS file: /home/data/fbsd-cvs/ncvs/src/usr.bin/Makefile,v
retrieving revision 1.303
diff -u -r1.303 Makefile
--- usr.bin/Makefile	9 Oct 2007 23:31:11 -0000	1.303
+++ usr.bin/Makefile	17 Jan 2008 19:31:01 -0000
@@ -149,6 +149,7 @@
 	pr \
 	printenv \
 	printf \
+	procstat \
 	quota \
 	renice \
 	rev \
Index: usr.bin/procstat/Makefile
===================================================================
RCS file: usr.bin/procstat/Makefile
diff -N usr.bin/procstat/Makefile
--- /dev/null	1 Jan 1970 00:00:00 -0000
+++ usr.bin/procstat/Makefile	17 Jan 2008 19:30:45 -0000
@@ -0,0 +1,15 @@
+# $FreeBSD: src/usr.bin/procstat/Makefile,v 1.1 2007/12/02 23:31:45 rwatson Exp $
+
+PROG=	procstat
+MAN=	procstat.1
+SRCS=	procstat.c		\
+	procstat_args.c		\
+	procstat_basic.c	\
+	procstat_bin.c		\
+	procstat_cred.c		\
+	procstat_files.c	\
+	procstat_kstack.c	\
+	procstat_threads.c	\
+	procstat_vm.c
+
+.include <bsd.prog.mk>
Index: usr.bin/procstat/procstat.1
===================================================================
RCS file: usr.bin/procstat/procstat.1
diff -N usr.bin/procstat/procstat.1
--- /dev/null	1 Jan 1970 00:00:00 -0000
+++ usr.bin/procstat/procstat.1	17 Jan 2008 19:30:45 -0000
@@ -0,0 +1,114 @@
+.\"-
+.\" Copyright (c) 2007 Robert N. M. Watson
+.\" All rights reserved.
+.\"
+.\" Redistribution and use in source and binary forms, with or without
+.\" modification, are permitted provided that the following conditions
+.\" are met:
+.\" 1. Redistributions of source code must retain the above copyright
+.\"    notice, this list of conditions and the following disclaimer.
+.\" 2. Redistributions in binary form must reproduce the above copyright
+.\"    notice, this list of conditions and the following disclaimer in the
+.\"    documentation and/or other materials provided with the distribution.
+.\"
+.\" THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+.\" ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+.\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+.\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+.\" SUCH DAMAGE.
+.\"
+.\" $FreeBSD: src/usr.bin/procstat/procstat.1,v 1.1 2007/12/02 23:31:45 rwatson Exp $
+.\"
+.Dd October 30, 2007
+.Dt PROCSTAT 1
+.Os
+.Sh NAME
+.Nm procstat
+.Nd get detailed process information
+.Sh SYNOPSIS
+.Nm
+.Op Fl h
+.Op Fl w Ar interval
+.Op Fl b | c | f | k | s | t | v
+.Op Fl a | Ar pid ...
+.Sh DESCRIPTION
+The
+.Nm
+utility displays detailed information about the processes identified by the
+.Ar pid
+arguments, or if the
+.Fl a
+flag is used, all processes.
+.Pp
+By default, basic process statistics are printed; one of the following
+options may be specified in order to select more detailed process information
+for printing:
+.Bl -tag -width indent
+.It Fl b
+Display binary information for the process.
+.It Fl c 
+Display command line arguments for the process.
+.It Fl f
+Display file descriptor information for the process.
+.It Fl k
+Display the stacks of kernel threads in the process, excluding stacks of
+threads currently running on a CPU and threads with stacks swapped to disk.
+If the flag is repeated, function offsets as well as function names are
+printed.
+This feature requires
+.Cd "options STACK"
+or
+.Cd "options DDB"
+to be compiled into the kernel.
+.It Fl s
+Display security credential information for the process.
+.It Fl t
+Display thread information for the process.
+.It Fl v
+Display virtual memory mappings for the process.
+.El
+.Pp
+All options generate output in the format of a table, the first field of
+which is the process ID to which the row of information corresponds.
+The
+.Fl h
+flag may be used to suppress table headers.
+.Pp
+The
+.Fl w
+flag may be used to specify a wait interval at which to repeat the printing
+of the requested process information.
+If the
+.Fl w
+flag is not specified, the output will not repeat.
+.Pp
+Some information, such as VM and file descriptor information, is available
+only to the owner of a process or the superuser.
+.Sh EXIT STATUS
+.Ex -std
+.Sh SEE ALSO
+.Xr fstat 1 ,
+.Xr ps 1 ,
+.Xr sockstat 1 ,
+.Xr DDB 4 ,
+.Xr stack 9
+.Sh AUTHORS
+.An Robert N M Watson
+.Sh BUGS
+Some field values may include spaces, which limits the extent to which the
+output of
+.Nm
+may be mechanically parsed.
+.Pp
+The display of open file or memory mapping pathnames is implemented using the
+kernel's name cache.
+It therefore does not work for file systems
+that do not use the name cache, such as
+.Xr devfs 4 ,
+or if the name is not present in the cache due to removal.
Index: usr.bin/procstat/procstat.c
===================================================================
RCS file: usr.bin/procstat/procstat.c
diff -N usr.bin/procstat/procstat.c
--- /dev/null	1 Jan 1970 00:00:00 -0000
+++ usr.bin/procstat/procstat.c	17 Jan 2008 19:30:45 -0000
@@ -0,0 +1,252 @@
+/*-
+ * Copyright (c) 2007 Robert N. M. Watson
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * $FreeBSD: src/usr.bin/procstat/procstat.c,v 1.1 2007/12/02 23:31:45 rwatson Exp $
+ */
+
+#include <sys/types.h>
+#include <sys/sysctl.h>
+#include <sys/user.h>
+
+#include <err.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <sysexits.h>
+#include <unistd.h>
+
+#include "procstat.h"
+
+static int aflag, bflag, cflag, fflag, kflag, sflag, tflag, vflag;
+int	hflag;
+
+static void
+usage(void)
+{
+
+	fprintf(stderr, "usage: procstat [-h] [-w interval] [-b | -c | -f | "
+	    "-k | -s | -t | -v]\n");
+	fprintf(stderr, "                [-a | pid ...]\n");
+	exit(EX_USAGE);
+}
+
+static void
+procstat(pid_t pid, struct kinfo_proc *kipp)
+{
+
+	if (bflag)
+		procstat_bin(pid, kipp);
+	else if (cflag)
+		procstat_args(pid, kipp);
+	else if (fflag)
+		procstat_files(pid, kipp);
+	else if (kflag)
+		procstat_kstack(pid, kipp, kflag);
+	else if (sflag)
+		procstat_cred(pid, kipp);
+	else if (tflag)
+		procstat_threads(pid, kipp);
+	else if (vflag)
+		procstat_vm(pid, kipp);
+	else
+		procstat_basic(pid, kipp);
+}
+
+/*
+ * Sort processes first by pid and then tid.
+ */
+static int
+kinfo_proc_compare(const void *a, const void *b)
+{
+	int i;
+
+	i = ((struct kinfo_proc *)a)->ki_pid -
+	    ((struct kinfo_proc *)b)->ki_pid;
+	if (i != 0)
+		return (i);
+	i = ((struct kinfo_proc *)a)->ki_tid -
+	    ((struct kinfo_proc *)b)->ki_tid;
+	return (i);
+}
+
+void
+kinfo_proc_sort(struct kinfo_proc *kipp, int count)
+{
+
+	qsort(kipp, count, sizeof(*kipp), kinfo_proc_compare);
+}
+
+int
+main(int argc, char *argv[])
+{
+	int ch, i, interval, name[4], tmp;
+	struct kinfo_proc *kipp;
+	size_t len;
+	long l;
+	pid_t pid;
+	char *dummy;
+
+	interval = 0;
+	while ((ch = getopt(argc, argv, "abcfkhstvw:")) != -1) {
+		switch (ch) {
+		case 'a':
+			aflag++;
+			break;
+
+		case 'b':
+			bflag++;
+			break;
+
+		case 'c':
+			cflag++;
+			break;
+
+		case 'f':
+			fflag++;
+			break;
+
+		case 'k':
+			kflag++;
+			break;
+
+		case 'h':
+			hflag++;
+			break;
+
+		case 's':
+			sflag++;
+			break;
+
+		case 't':
+			tflag++;
+			break;
+
+		case 'v':
+			vflag++;
+			break;
+
+		case 'w':
+			l = strtol(optarg, &dummy, 10);
+			if (*dummy != '\0')
+				usage();
+			if (l < 1 || l > INT_MAX)
+				usage();
+			interval = l;
+			break;
+
+		case '?':
+		default:
+			usage();
+		}
+
+	}
+	argc -= optind;
+	argv += optind;
+
+	/* We require that either 0 or 1 mode flags be set. */
+	tmp = bflag + cflag + fflag + (kflag ? 1 : 0) + sflag + tflag + vflag;
+	if (!(tmp == 0 || tmp == 1))
+		usage();
+
+	/* We allow -k to be specified up to twice, but not more. */
+	if (kflag > 2)
+		usage();
+
+	/* Must specify either the -a flag or a list of pids. */
+	if (!(aflag == 1 && argc == 0) && !(aflag == 0 && argc > 0))
+		usage();
+
+	do {
+		if (aflag) {
+			name[0] = CTL_KERN;
+			name[1] = KERN_PROC;
+			name[2] = KERN_PROC_PROC;
+
+			len = 0;
+			if (sysctl(name, 3, NULL, &len, NULL, 0) < 0)
+				err(-1, "sysctl: kern.proc.all");
+
+			kipp = malloc(len);
+			if (kipp == NULL)
+				err(-1, "malloc");
+
+			if (sysctl(name, 3, kipp, &len, NULL, 0) < 0) {
+				free(kipp);
+				err(-1, "sysctl: kern.proc.all");
+			}
+			if (len % sizeof(*kipp) != 0)
+				err(-1, "kinfo_proc mismatch");
+			if (kipp->ki_structsize != sizeof(*kipp))
+				err(-1, "kinfo_proc structure mismatch");
+			kinfo_proc_sort(kipp, len / sizeof(*kipp));
+			for (i = 0; i < len / sizeof(*kipp); i++) {
+				procstat(kipp[i].ki_pid, &kipp[i]);
+
+				/* Suppress header after first process. */
+				hflag = 1;
+			}
+			free(kipp);
+		}
+		for (i = 0; i < argc; i++) {
+			l = strtol(argv[i], &dummy, 10);
+			if (*dummy != '\0')
+				usage();
+			if (l < 0)
+				usage();
+			pid = l;
+
+			name[0] = CTL_KERN;
+			name[1] = KERN_PROC;
+			name[2] = KERN_PROC_PID;
+			name[3] = pid;
+
+			len = 0;
+			if (sysctl(name, 4, NULL, &len, NULL, 0) < 0)
+				err(-1, "sysctl: kern.proc.pid: %d", pid);
+
+			kipp = malloc(len);
+			if (kipp == NULL)
+				err(-1, "malloc");
+
+			if (sysctl(name, 4, kipp, &len, NULL, 0) < 0) {
+				free(kipp);
+				err(-1, "sysctl: kern.proc.pid: %d", pid);
+			}
+			if (len != sizeof(*kipp))
+				err(-1, "kinfo_proc mismatch");
+			if (kipp->ki_structsize != sizeof(*kipp))
+				errx(-1, "kinfo_proc structure mismatch");
+			if (kipp->ki_pid != pid)
+				errx(-1, "kinfo_proc pid mismatch");
+			procstat(pid, kipp);
+			free(kipp);
+
+			/* Suppress header after first process. */
+			hflag = 1;
+		}
+		if (interval)
+			sleep(interval);
+	} while (interval);
+	exit(0);
+}
Index: usr.bin/procstat/procstat.h
===================================================================
RCS file: usr.bin/procstat/procstat.h
diff -N usr.bin/procstat/procstat.h
--- /dev/null	1 Jan 1970 00:00:00 -0000
+++ usr.bin/procstat/procstat.h	17 Jan 2008 19:30:46 -0000
@@ -0,0 +1,46 @@
+/*-
+ * Copyright (c) 2007 Robert N. M. Watson
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * $FreeBSD: src/usr.bin/procstat/procstat.h,v 1.1 2007/12/02 23:31:45 rwatson Exp $
+ */
+
+#ifndef PROCSTAT_H
+#define	PROCSTAT_H
+
+extern int	hflag;
+
+struct kinfo_proc;
+void	kinfo_proc_sort(struct kinfo_proc *kipp, int count);
+
+void	procstat_args(pid_t pid, struct kinfo_proc *kipp);
+void	procstat_basic(pid_t pid, struct kinfo_proc *kipp);
+void	procstat_bin(pid_t pid, struct kinfo_proc *kipp);
+void	procstat_cred(pid_t pid, struct kinfo_proc *kipp);
+void	procstat_files(pid_t pid, struct kinfo_proc *kipp);
+void	procstat_kstack(pid_t pid, struct kinfo_proc *kipp, int kflag);
+void	procstat_threads(pid_t pid, struct kinfo_proc *kipp);
+void	procstat_vm(pid_t pid, struct kinfo_proc *kipp);
+
+#endif /* !PROCSTAT_H */
Index: usr.bin/procstat/procstat_args.c
===================================================================
RCS file: usr.bin/procstat/procstat_args.c
diff -N usr.bin/procstat/procstat_args.c
--- /dev/null	1 Jan 1970 00:00:00 -0000
+++ usr.bin/procstat/procstat_args.c	17 Jan 2008 19:30:46 -0000
@@ -0,0 +1,76 @@
+/*-
+ * Copyright (c) 2007 Robert N. M. Watson
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * $FreeBSD: src/usr.bin/procstat/procstat_args.c,v 1.2 2007/12/10 20:55:43 rwatson Exp $
+ */
+
+#include <sys/types.h>
+#include <sys/sysctl.h>
+#include <sys/user.h>
+
+#include <err.h>
+#include <errno.h>
+#include <limits.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include "procstat.h"
+
+static char args[ARG_MAX];
+
+void
+procstat_args(pid_t pid, struct kinfo_proc *kipp)
+{
+	int error, name[4];
+	size_t len;
+	char *cp;
+
+	if (!hflag)
+		printf("%5s %-16s %-53s\n", "PID", "COMM", "ARGS");
+
+	name[0] = CTL_KERN;
+	name[1] = KERN_PROC;
+	name[2] = KERN_PROC_ARGS;
+	name[3] = pid;
+	len = sizeof(args);
+	error = sysctl(name, 4, args, &len, NULL, 0);
+	if (error < 0 && errno != ESRCH) {
+		warn("sysctl: kern.proc.args: %d", pid);
+		return;
+	}
+	if (error < 0)
+		return;
+	if (len == 0 || strlen(args) == 0) {
+		strcpy(args, "-");
+		len = strlen(args) + 1;
+	}
+
+	printf("%5d ", pid);
+	printf("%-16s ", kipp->ki_comm);
+	for (cp = args; cp < args + len; cp += strlen(cp) + 1)
+		printf("%s%s", cp != args ? " " : "", cp);
+	printf("\n");
+}
Index: usr.bin/procstat/procstat_basic.c
===================================================================
RCS file: usr.bin/procstat/procstat_basic.c
diff -N usr.bin/procstat/procstat_basic.c
--- /dev/null	1 Jan 1970 00:00:00 -0000
+++ usr.bin/procstat/procstat_basic.c	17 Jan 2008 19:30:46 -0000
@@ -0,0 +1,64 @@
+/*-
+ * Copyright (c) 2007 Robert N. M. Watson
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * $FreeBSD: src/usr.bin/procstat/procstat_basic.c,v 1.1 2007/12/02 23:31:45 rwatson Exp $
+ */
+
+#include <sys/types.h>
+#include <sys/sysctl.h>
+#include <sys/user.h>
+
+#include <err.h>
+#include <stdio.h>
+#include <string.h>
+
+#include "procstat.h"
+
+void
+procstat_basic(pid_t pid, struct kinfo_proc *kipp)
+{
+
+	if (!hflag)
+		printf("%5s %5s %5s %5s %5s %3s %-8s %-9s %-13s %-12s\n",
+		    "PID", "PPID", "PGID", "SID", "TSID", "THR", "LOGIN",
+		    "WCHAN", "EMUL", "COMM");
+
+	printf("%5d ", kipp->ki_pid);
+	printf("%5d ", kipp->ki_ppid);
+	printf("%5d ", kipp->ki_pgid);
+	printf("%5d ", kipp->ki_sid);
+	printf("%5d ", kipp->ki_tsid);
+	printf("%3d ", kipp->ki_numthreads);
+	printf("%-8s ", strlen(kipp->ki_login) ? kipp->ki_login : "-");
+	if (kipp->ki_kiflag & KI_LOCKBLOCK) {
+		printf("*%-8s ", strlen(kipp->ki_lockname) ?
+		    kipp->ki_lockname : "-");
+	} else {
+		printf("%-9s ", strlen(kipp->ki_wmesg) ?
+		    kipp->ki_wmesg : "-");
+	}
+	printf("%-13s ", strcmp(kipp->ki_emul, "null") ? kipp->ki_emul : "-");
+	printf("%-12s\n", kipp->ki_comm);
+}
Index: usr.bin/procstat/procstat_bin.c
===================================================================
RCS file: usr.bin/procstat/procstat_bin.c
diff -N usr.bin/procstat/procstat_bin.c
--- /dev/null	1 Jan 1970 00:00:00 -0000
+++ usr.bin/procstat/procstat_bin.c	17 Jan 2008 19:30:46 -0000
@@ -0,0 +1,70 @@
+/*-
+ * Copyright (c) 2007 Robert N. M. Watson
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * $FreeBSD: src/usr.bin/procstat/procstat_bin.c,v 1.2 2007/12/10 20:55:43 rwatson Exp $
+ */
+
+#include <sys/types.h>
+#include <sys/sysctl.h>
+#include <sys/user.h>
+
+#include <err.h>
+#include <errno.h>
+#include <limits.h>
+#include <stdio.h>
+#include <string.h>
+
+#include "procstat.h"
+
+void
+procstat_bin(pid_t pid, struct kinfo_proc *kipp)
+{
+	char pathname[PATH_MAX];
+	int error, name[4];
+	size_t len;
+
+	if (!hflag)
+		printf("%5s %-16s %-53s\n", "PID", "COMM", "PATH");
+
+	name[0] = CTL_KERN;
+	name[1] = KERN_PROC;
+	name[2] = KERN_PROC_PATHNAME;
+	name[3] = pid;
+
+	len = sizeof(pathname);
+	error = sysctl(name, 4, pathname, &len, NULL, 0);
+	if (error < 0 && errno != ESRCH) {
+		warn("sysctl: kern.proc.pathname: %d", pid);
+		return;
+	}
+	if (error < 0)
+		return;
+	if (len == 0 || strlen(pathname) == 0)
+		strcpy(pathname, "-");
+
+	printf("%5d ", pid);
+	printf("%-16s ", kipp->ki_comm);
+	printf("%s\n", pathname);
+}
Index: usr.bin/procstat/procstat_cred.c
===================================================================
RCS file: usr.bin/procstat/procstat_cred.c
diff -N usr.bin/procstat/procstat_cred.c
--- /dev/null	1 Jan 1970 00:00:00 -0000
+++ usr.bin/procstat/procstat_cred.c	17 Jan 2008 19:30:46 -0000
@@ -0,0 +1,59 @@
+/*-
+ * Copyright (c) 2007 Robert N. M. Watson
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * $FreeBSD: src/usr.bin/procstat/procstat_cred.c,v 1.2 2007/12/10 20:55:43 rwatson Exp $
+ */
+
+#include <sys/types.h>
+#include <sys/sysctl.h>
+#include <sys/user.h>
+
+#include <err.h>
+#include <stdio.h>
+
+#include "procstat.h"
+
+void
+procstat_cred(pid_t pid, struct kinfo_proc *kipp)
+{
+	int i;
+
+	if (!hflag)
+		printf("%5s %-16s %5s %5s %5s %5s %5s %5s %-20s\n", "PID",
+		    "COMM", "EUID", "RUID", "SVUID", "EGID", "RGID", "SVGID",
+		    "GROUPS");
+
+	printf("%5d ", pid);
+	printf("%-16s ", kipp->ki_comm);
+	printf("%5d ", kipp->ki_uid);
+	printf("%5d ", kipp->ki_ruid);
+	printf("%5d ", kipp->ki_svuid);
+	printf("%5d ", kipp->ki_groups[0]);
+	printf("%5d ", kipp->ki_rgid);
+	printf("%5d ", kipp->ki_svgid);
+	for (i = 0; i < kipp->ki_ngroups; i++)
+		printf("%s%d", (i > 0) ? "," : "", kipp->ki_groups[i]);
+	printf("\n");
+}
Index: usr.bin/procstat/procstat_files.c
===================================================================
RCS file: usr.bin/procstat/procstat_files.c
diff -N usr.bin/procstat/procstat_files.c
--- /dev/null	1 Jan 1970 00:00:00 -0000
+++ usr.bin/procstat/procstat_files.c	17 Jan 2008 19:30:46 -0000
@@ -0,0 +1,306 @@
+/*-
+ * Copyright (c) 2007 Robert N. M. Watson
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * $FreeBSD: src/usr.bin/procstat/procstat_files.c,v 1.2 2007/12/10 20:55:43 rwatson Exp $
+ */
+
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <sys/sysctl.h>
+#include <sys/un.h>
+#include <sys/user.h>
+
+#include <netinet/in.h>
+
+#include <arpa/inet.h>
+
+#include <err.h>
+#include <inttypes.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include "procstat.h"
+
+static const char *
+protocol_to_string(int domain, int type, int protocol)
+{
+
+	switch (domain) {
+	case AF_INET:
+	case AF_INET6:
+		switch (protocol) {
+		case IPPROTO_TCP:
+			return ("TCP");
+		case IPPROTO_UDP:
+			return ("UDP");
+		case IPPROTO_ICMP:
+			return ("ICM");
+		case IPPROTO_RAW:
+			return ("RAW");
+		case IPPROTO_SCTP:
+			return ("SCT");
+		case IPPROTO_DIVERT:
+			return ("IPD");
+		default:
+			return ("IP?");
+		}
+
+	case AF_LOCAL:
+		switch (type) {
+		case SOCK_STREAM:
+			return ("UDS");
+		case SOCK_DGRAM:
+			return ("UDD");
+		default:
+			return ("UD?");
+		}
+	default:
+		return ("?");
+	}
+}
+
+static void
+addr_to_string(struct sockaddr_storage *ss, char *buffer, int buflen)
+{
+	char buffer2[INET6_ADDRSTRLEN];
+	struct sockaddr_in6 *sin6;
+	struct sockaddr_in *sin;
+	struct sockaddr_un *sun;
+
+	switch (ss->ss_family) {
+	case AF_LOCAL:
+		sun = (struct sockaddr_un *)ss;
+		if (strlen(sun->sun_path) == 0)
+			strlcpy(buffer, "-", buflen);
+		else
+			strlcpy(buffer, sun->sun_path, buflen);
+		break;
+
+	case AF_INET:
+		sin = (struct sockaddr_in *)ss;
+		snprintf(buffer, buflen, "%s:%d", inet_ntoa(sin->sin_addr),
+		    ntohs(sin->sin_port));
+		break;
+
+	case AF_INET6:
+		sin6 = (struct sockaddr_in6 *)ss;
+		if (inet_ntop(AF_INET6, &sin6->sin6_addr, buffer2,
+		    sizeof(buffer2)) != NULL)
+			snprintf(buffer, buflen, "%s.%d", buffer2,
+			    ntohs(sin6->sin6_port));
+		else
+			strlcpy(buffer, "-", sizeof(buffer));
+		break;
+
+	default:
+		strlcpy(buffer, "", buflen);
+		break;
+	}
+}
+
+static void
+print_address(struct sockaddr_storage *ss)
+{
+	char addr[PATH_MAX];
+
+	addr_to_string(ss, addr, sizeof(addr));
+	printf("%s", addr);
+}
+
+void
+procstat_files(pid_t pid, struct kinfo_proc *kipp)
+{
+	struct kinfo_file *freep, *kif;
+	int error, i, name[4];
+	const char *str;
+	size_t len;
+
+	if (!hflag)
+		printf("%5s %-16s %3s %1s %1s %-8s %3s %7s %-3s %-12s\n",
+		    "PID", "COMM", "FD", "T", "V", "FLAGS", "REF", "OFFSET",
+		    "PRO", "NAME");
+
+	name[0] = CTL_KERN;
+	name[1] = KERN_PROC;
+	name[2] = KERN_PROC_FILEDESC;
+	name[3] = pid;
+
+	error = sysctl(name, 4, NULL, &len, NULL, 0);
+	if (error < 0 && errno != ESRCH && errno != EPERM) {
+		warn("sysctl: kern.proc.filedesc: %d", pid);
+		return;
+	}
+	if (error < 0)
+		return;
+
+	freep = kif = malloc(len);
+	if (kif == NULL)
+		err(-1, "malloc");
+
+	if (sysctl(name, 4, kif, &len, NULL, 0) < 0) {
+		warn("sysctl: kern.proc.filedesc %d", pid);
+		free(freep);
+		return;
+	}
+
+	for (i = 0; i < len / sizeof(*kif); i++, kif++) {
+		if (kif->kf_structsize != sizeof(*kif))
+			errx(-1, "kinfo_file mismatch");
+		printf("%5d ", pid);
+		printf("%-16s ", kipp->ki_comm);
+		printf("%3d ", kif->kf_fd);
+		switch (kif->kf_type) {
+		case KF_TYPE_VNODE:
+			str = "v";
+			break;
+
+		case KF_TYPE_SOCKET:
+			str = "s";
+			break;
+
+		case KF_TYPE_PIPE:
+			str = "p";
+			break;
+
+		case KF_TYPE_FIFO:
+			str = "f";
+			break;
+
+		case KF_TYPE_KQUEUE:
+			str = "k";
+			break;
+
+		case KF_TYPE_CRYPTO:
+			str = "c";
+			break;
+
+		case KF_TYPE_MQUEUE:
+			str = "m";
+			break;
+
+		case KF_TYPE_NONE:
+		case KF_TYPE_UNKNOWN:
+		default:
+			str = "?";
+			break;
+		}
+		printf("%1s ", str);
+		str = "-";
+		if (kif->kf_type == KF_TYPE_VNODE) {
+			switch (kif->kf_vnode_type) {
+			case KF_VTYPE_VREG:
+				str = "r";
+				break;
+
+			case KF_VTYPE_VDIR:
+				str = "d";
+				break;
+
+			case KF_VTYPE_VBLK:
+				str = "b";
+				break;
+
+			case KF_VTYPE_VCHR:
+				str = "c";
+				break;
+
+			case KF_VTYPE_VLNK:
+				str = "l";
+				break;
+
+			case KF_VTYPE_VSOCK:
+				str = "s";
+				break;
+
+			case KF_VTYPE_VFIFO:
+				str = "f";
+				break;
+
+			case KF_VTYPE_VBAD:
+				str = "x";
+				break;
+
+			case KF_VTYPE_VNON:
+			case KF_VTYPE_UNKNOWN:
+			default:
+				str = "?";
+				break;
+			}
+		}
+		printf("%1s ", str);
+		printf("%s", kif->kf_flags & KF_FLAG_READ ? "r" : "-");
+		printf("%s", kif->kf_flags & KF_FLAG_WRITE ? "w" : "-");
+		printf("%s", kif->kf_flags & KF_FLAG_APPEND ? "a" : "-");
+		printf("%s", kif->kf_flags & KF_FLAG_ASYNC ? "s" : "-");
+		printf("%s", kif->kf_flags & KF_FLAG_FSYNC ? "f" : "-");
+		printf("%s", kif->kf_flags & KF_FLAG_NONBLOCK ? "n" : "-");
+		printf("%s", kif->kf_flags & KF_FLAG_DIRECT ? "d" : "-");
+		printf("%s ", kif->kf_flags & KF_FLAG_HASLOCK ? "l" : "-");
+		printf("%3d ", kif->kf_ref_count);
+		printf("%7jd ", (intmax_t)kif->kf_offset);
+
+		switch (kif->kf_type) {
+		case KF_TYPE_VNODE:
+		case KF_TYPE_FIFO:
+			printf("%-3s ", "-");
+			printf("%-18s", kif->kf_path);
+			break;
+
+		case KF_TYPE_SOCKET:
+			printf("%-3s ",
+			    protocol_to_string(kif->kf_sock_domain,
+			    kif->kf_sock_type, kif->kf_sock_protocol));
+			/*
+			 * While generally we like to print two addresses,
+			 * local and peer, for sockets, it turns out to be
+			 * more useful to print the first non-nul address for
+			 * local sockets, as typically they aren't bound and
+			 *  connected, and the path strings can get long.
+			 */
+			if (kif->kf_sock_domain == AF_LOCAL) {
+				struct sockaddr_un *sun =
+				    (struct sockaddr_un *)&kif->kf_sa_local;
+
+				if (sun->sun_path[0] != 0)
+					print_address(&kif->kf_sa_local);
+				else
+					print_address(&kif->kf_sa_peer);
+			} else {
+				print_address(&kif->kf_sa_local);
+				printf(" ");
+				print_address(&kif->kf_sa_peer);
+			}
+			break;
+
+		default:
+			printf("%-3s ", "-");
+			printf("%-18s", "-");
+		}
+
+		printf("\n");
+	}
+	free(freep);
+}
Index: usr.bin/procstat/procstat_kstack.c
===================================================================
RCS file: usr.bin/procstat/procstat_kstack.c
diff -N usr.bin/procstat/procstat_kstack.c
--- /dev/null	1 Jan 1970 00:00:00 -0000
+++ usr.bin/procstat/procstat_kstack.c	17 Jan 2008 19:30:46 -0000
@@ -0,0 +1,245 @@
+/*-
+ * Copyright (c) 2007 Robert N. M. Watson
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * $FreeBSD: src/usr.bin/procstat/procstat_kstack.c,v 1.2 2007/12/03 21:21:15 rwatson Exp $
+ */
+
+#include <sys/types.h>
+#include <sys/sysctl.h>
+#include <sys/user.h>
+
+#include <err.h>
+#include <errno.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include "procstat.h"
+
+/*
+ * Walk the stack trace provided by the kernel and reduce it to what we
+ * actually want to print.  This involves stripping true instruction pointers,
+ * frame numbers, and carriage returns as generated by stack(9).  If -kk is
+ * specified, print the function and offset, otherwise just the function.
+ */
+enum trace_state { TS_FRAMENUM, TS_PC, TS_AT, TS_FUNC, TS_OFF };
+
+static enum trace_state
+kstack_nextstate(enum trace_state ts)
+{
+
+	switch (ts) {
+	case TS_FRAMENUM:
+		return (TS_PC);
+
+	case TS_PC:
+		return (TS_AT);
+
+	case TS_AT:
+		return (TS_FUNC);
+
+	case TS_FUNC:
+		return (TS_OFF);
+
+	case TS_OFF:
+		return TS_FRAMENUM;
+
+	default:
+		errx(-1, "kstack_nextstate");
+	}
+}
+
+static void
+kstack_cleanup(const char *old, char *new, int kflag)
+{
+	enum trace_state old_ts, ts;
+	const char *cp_old;
+	char *cp_new;
+
+	ts = TS_FRAMENUM;
+	for (cp_old = old, cp_new = new; *cp_old != '\0'; cp_old++) {
+		switch (*cp_old) {
+		case ' ':
+		case '\n':
+		case '+':
+			old_ts = ts;
+			ts = kstack_nextstate(old_ts);
+			if (old_ts == TS_OFF) {
+				*cp_new = ' ';
+				cp_new++;
+			}
+			if (kflag > 1 && old_ts == TS_FUNC) {
+				*cp_new = '+';
+				cp_new++;
+			}
+			continue;
+		}
+		if (ts == TS_FUNC || (kflag > 1 && ts == TS_OFF)) {
+			*cp_new = *cp_old;
+			cp_new++;
+		}
+	}
+	*cp_new = '\0';
+}
+
+/*
+ * Sort threads by tid.
+ */
+static int
+kinfo_kstack_compare(const void *a, const void *b)
+{
+
+        return ((struct kinfo_kstack *)a)->kkst_tid -
+            ((struct kinfo_kstack *)b)->kkst_tid;
+}
+
+static void
+kinfo_kstack_sort(struct kinfo_kstack *kkstp, int count)
+{
+
+        qsort(kkstp, count, sizeof(*kkstp), kinfo_kstack_compare);
+}
+
+
+void
+procstat_kstack(pid_t pid, struct kinfo_proc *kipp, int kflag)
+{
+	struct kinfo_kstack *kkstp, *kkstp_free;
+	struct kinfo_proc *kip, *kip_free;
+	char trace[KKST_MAXLEN];
+	int error, i, j, name[4];
+	size_t kip_len, kstk_len;
+
+	if (!hflag)
+		printf("%5s %6s %-16s %-16s %-29s\n", "PID", "TID", "COMM",
+		    "TDNAME", "KSTACK");
+
+	name[0] = CTL_KERN;
+	name[1] = KERN_PROC;
+	name[2] = KERN_PROC_KSTACK;
+	name[3] = pid;
+
+	kstk_len = 0;
+	error = sysctl(name, 4, NULL, &kstk_len, NULL, 0);
+	if (error < 0 && errno != ESRCH && errno != EPERM && errno != ENOENT) {
+		warn("sysctl: kern.proc.kstack: %d", pid);
+		return;
+	}
+	if (error < 0 && errno == ENOENT) {
+		warnx("sysctl: kern.proc.kstack unavailable");
+		errx(-1, "options DDB or options STACK required in kernel");
+	}
+	if (error < 0)
+		return;
+
+	kkstp = kkstp_free = malloc(kstk_len);
+	if (kkstp == NULL)
+		err(-1, "malloc");
+
+	if (sysctl(name, 4, kkstp, &kstk_len, NULL, 0) < 0) {
+		warn("sysctl: kern.proc.pid: %d", pid);
+		free(kkstp);
+		return;
+	}
+
+	/*
+	 * We need to re-query for thread information, so don't use *kipp.
+	 */
+	name[0] = CTL_KERN;
+	name[1] = KERN_PROC;
+	name[2] = KERN_PROC_PID | KERN_PROC_INC_THREAD;
+	name[3] = pid;
+
+	kip_len = 0;
+	error = sysctl(name, 4, NULL, &kip_len, NULL, 0);
+	if (error < 0 && errno != ESRCH) {
+		warn("sysctl: kern.proc.pid: %d", pid);
+		return;
+	}
+	if (error < 0)
+		return;
+
+	kip = kip_free = malloc(kip_len);
+	if (kip == NULL)
+		err(-1, "malloc");
+
+	if (sysctl(name, 4, kip, &kip_len, NULL, 0) < 0) {
+		warn("sysctl: kern.proc.pid: %d", pid);
+		free(kip);
+		return;
+	}
+
+	kinfo_kstack_sort(kkstp, kstk_len / sizeof(*kkstp));
+	for (i = 0; i < kstk_len / sizeof(*kkstp); i++) {
+		kkstp = &kkstp_free[i];
+
+		/*
+		 * Look up the specific thread using its tid so we can
+		 * display the per-thread command line.
+		 */
+		kipp = NULL;
+		for (j = 0; j < kip_len / sizeof(*kipp); j++) {
+			kipp = &kip_free[j];
+			if (kkstp->kkst_tid == kipp->ki_tid)
+				break;
+		}
+		if (kipp == NULL)
+			continue;
+
+		printf("%5d ", pid);
+		printf("%6d ", kkstp->kkst_tid);
+		printf("%-16s ", kipp->ki_comm);
+		printf("%-16s ", (strlen(kipp->ki_ocomm) &&
+		    (strcmp(kipp->ki_comm, kipp->ki_ocomm) != 0)) ?
+		    kipp->ki_ocomm : "-");
+
+		switch (kkstp->kkst_state) {
+		case KKST_STATE_RUNNING:
+			printf("%-29s\n", "<running>");
+			continue;
+
+		case KKST_STATE_SWAPPED:
+			printf("%-29s\n", "<swapped>");
+			continue;
+
+		case KKST_STATE_STACKOK:
+			break;
+
+		default:
+			printf("%-29s\n", "<unknown>");
+			continue;
+		}
+
+		/*
+		 * The kernel generates a trace with carriage returns between
+		 * entries, but for a more compact view, we convert carriage
+		 * returns to spaces.
+		 */
+		kstack_cleanup(kkstp->kkst_trace, trace, kflag);
+		printf("%-29s\n", trace);
+	}
+	free(kip_free);
+	free(kkstp_free);
+}
Index: usr.bin/procstat/procstat_threads.c
===================================================================
RCS file: usr.bin/procstat/procstat_threads.c
diff -N usr.bin/procstat/procstat_threads.c
--- /dev/null	1 Jan 1970 00:00:00 -0000
+++ usr.bin/procstat/procstat_threads.c	17 Jan 2008 19:30:46 -0000
@@ -0,0 +1,141 @@
+/*-
+ * Copyright (c) 2007 Robert N. M. Watson
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * $FreeBSD: src/usr.bin/procstat/procstat_threads.c,v 1.2 2007/12/03 21:21:15 rwatson Exp $
+ */
+
+#include <sys/types.h>
+#include <sys/sysctl.h>
+#include <sys/user.h>
+
+#include <err.h>
+#include <errno.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include "procstat.h"
+
+void
+procstat_threads(pid_t pid, struct kinfo_proc *kipp)
+{
+	struct kinfo_proc *kip;
+	int error, i, name[4];
+	const char *str;
+	size_t len;
+
+	if (!hflag)
+		printf("%5s %6s %-16s %-16s %2s %4s %-7s %-9s\n", "PID",
+		    "TID", "COMM", "TDNAME", "CPU", "PRI", "STATE", "WCHAN");
+
+	/*
+	 * We need to re-query for thread information, so don't use *kipp.
+	 */
+	name[0] = CTL_KERN;
+	name[1] = KERN_PROC;
+	name[2] = KERN_PROC_PID | KERN_PROC_INC_THREAD;
+	name[3] = pid;
+
+	len = 0;
+	error = sysctl(name, 4, NULL, &len, NULL, 0);
+	if (error < 0 && errno != ESRCH) {
+		warn("sysctl: kern.proc.pid: %d", pid);
+		return;
+	}
+	if (error < 0)
+		return;
+
+	kip = malloc(len);
+	if (kip == NULL)
+		err(-1, "malloc");
+
+	if (sysctl(name, 4, kip, &len, NULL, 0) < 0) {
+		warn("sysctl: kern.proc.pid: %d", pid);
+		free(kip);
+		return;
+	}
+
+	kinfo_proc_sort(kip, len / sizeof(*kipp));
+	for (i = 0; i < len / sizeof(*kipp); i++) {
+		kipp = &kip[i];
+		printf("%5d ", pid);
+		printf("%6d ", kipp->ki_tid);
+		printf("%-16s ", strlen(kipp->ki_comm) ?
+		    kipp->ki_comm : "-");
+		printf("%-16s ", (strlen(kipp->ki_ocomm) &&
+		    (strcmp(kipp->ki_comm, kipp->ki_ocomm) != 0)) ?
+		    kipp->ki_ocomm : "-");
+		if (kipp->ki_oncpu != 255)
+			printf("%3d ", kipp->ki_oncpu);
+		else if (kipp->ki_lastcpu != 255)
+			printf("%3d ", kipp->ki_lastcpu);
+		else
+			printf("%3s ", "-");
+		printf("%4d ", kipp->ki_pri.pri_level);
+		switch (kipp->ki_stat) {
+		case SRUN:
+			str = "run";
+			break;
+
+		case SSTOP:
+			str = "stop";
+			break;
+
+		case SSLEEP:
+			str = "sleep";
+			break;
+
+		case SLOCK:
+			str = "lock";
+			break;
+
+		case SWAIT:
+			str = "wait";
+			break;
+
+		case SZOMB:
+			str = "zomb";
+			break;
+
+		case SIDL:
+			str = "idle";
+			break;
+
+		default:
+			str = "??";
+			break;
+		}
+		printf("%-7s ", str);
+		if (kipp->ki_kiflag & KI_LOCKBLOCK) {
+			printf("*%-8s ", strlen(kipp->ki_lockname) ?
+			    kipp->ki_lockname : "-");
+		} else {
+			printf("%-9s ", strlen(kipp->ki_wmesg) ?
+			    kipp->ki_wmesg : "-");
+		}
+		printf("\n");
+	}
+	free(kip);
+}
Index: usr.bin/procstat/procstat_vm.c
===================================================================
RCS file: usr.bin/procstat/procstat_vm.c
diff -N usr.bin/procstat/procstat_vm.c
--- /dev/null	1 Jan 1970 00:00:00 -0000
+++ usr.bin/procstat/procstat_vm.c	17 Jan 2008 19:30:46 -0000
@@ -0,0 +1,130 @@
+/*-
+ * Copyright (c) 2007 Robert N. M. Watson
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * $FreeBSD: src/usr.bin/procstat/procstat_vm.c,v 1.1 2007/12/02 23:31:45 rwatson Exp $
+ */
+
+#include <sys/types.h>
+#include <sys/sysctl.h>
+#include <sys/user.h>
+
+#include <err.h>
+#include <errno.h>
+#include <stdio.h>
+#include <stdlib.h>
+
+#include "procstat.h"
+
+void
+procstat_vm(pid_t pid, struct kinfo_proc *kipp)
+{
+	struct kinfo_vmentry *freep, *kve;
+	int error, i, name[4], ptrwidth;
+	const char *str;
+	size_t len;
+
+	ptrwidth = 2*sizeof(void *) + 2;
+	if (!hflag)
+		printf("%5s %*s %*s %3s %4s %4s %3s %3s %2s %-2s %-s\n",
+		    "PID", ptrwidth, "START", ptrwidth, "END", "PRT", "RES",
+		    "PRES", "REF", "SHD", "FL", "TP", "PATH");
+
+	name[0] = CTL_KERN;
+	name[1] = KERN_PROC;
+	name[2] = KERN_PROC_VMMAP;
+	name[3] = pid;
+
+	len = 0;
+	error = sysctl(name, 4, NULL, &len, NULL, 0);
+	if (error < 0 && errno != ESRCH && errno != EPERM) {
+		warn("sysctl: kern.proc.vmmap: %d", pid);
+		return;
+	}
+	if (error < 0)
+		return;
+
+	/*
+	 * Especially if running procstat -sv, we may need room for more
+	 * mappings when printing than were present when we queried, so pad
+	 * out the allocation a bit.
+	 */
+	len += sizeof(*kve) * 3;
+	freep = kve = malloc(len);
+	if (kve == NULL)
+		err(-1, "malloc");
+	if (sysctl(name, 4, kve, &len, NULL, 0) < 0) {
+		warn("sysctl: kern.proc.vmmap: %d", pid);
+		free(freep);
+		return;
+	}
+
+	for (i = 0; i < (len / sizeof(*kve)); i++, kve++) {
+		if (kve->kve_structsize != sizeof(*kve))
+			errx(-1, "kinfo_vmentry structure mismatch");
+		printf("%5d ", pid);
+		printf("%*p ", ptrwidth, kve->kve_start);
+		printf("%*p ", ptrwidth, kve->kve_end);
+		printf("%s", kve->kve_protection & KVME_PROT_READ ? "r" : "-");
+		printf("%s", kve->kve_protection & KVME_PROT_WRITE ? "w" : "-");
+		printf("%s ", kve->kve_protection & KVME_PROT_EXEC ? "x" : "-");
+		printf("%4d ", kve->kve_resident);
+		printf("%4d ", kve->kve_private_resident);
+		printf("%3d ", kve->kve_ref_count);
+		printf("%3d ", kve->kve_shadow_count);
+		printf("%-1s", kve->kve_flags & KVME_FLAG_COW ? "C" : "-");
+		printf("%-1s ", kve->kve_flags & KVME_FLAG_NEEDS_COPY ? "N" :
+		    "-");
+		switch (kve->kve_type) {
+		case KVME_TYPE_NONE:
+			str = "--";
+			break;
+		case KVME_TYPE_DEFAULT:
+			str = "df";
+			break;
+		case KVME_TYPE_VNODE:
+			str = "vn";
+			break;
+		case KVME_TYPE_SWAP:
+			str = "sw";
+			break;
+		case KVME_TYPE_DEVICE:
+			str = "dv";
+			break;
+		case KVME_TYPE_PHYS:
+			str = "ph";
+			break;
+		case KVME_TYPE_DEAD:
+			str = "dd";
+			break;
+		case KVME_TYPE_UNKNOWN:
+		default:
+			str = "??";
+			break;
+		}
+		printf("%-2s ", str);
+		printf("%-s\n", kve->kve_path);
+	}
+	free(freep);
+}
