Module Name:    src
Committed By:   christos
Date:           Sun Apr 10 20:36:49 UTC 2011

Modified Files:
        src/sys/arch/amd64/amd64: db_disasm.c
        src/sys/arch/amd64/conf: files.amd64
        src/sys/arch/amd64/include: db_machdep.h
        src/sys/arch/i386/conf: files.i386
        src/sys/arch/i386/include: db_machdep.h
        src/sys/arch/x86/conf: files.x86
Added Files:
        src/sys/arch/amd64/amd64: db_machdep.c
        src/sys/arch/i386/i386: db_machdep.c
        src/sys/arch/x86/include: db_machdep.h
        src/sys/arch/x86/x86: db_trace.c
Removed Files:
        src/sys/arch/amd64/amd64: db_trace.c
        src/sys/arch/i386/i386: db_trace.c

Log Message:
Merge db_trace for x86. From: Vladimir Kirillov proger at wilab dot org dot ua


To generate a diff of this commit:
cvs rdiff -u -r1.14 -r1.15 src/sys/arch/amd64/amd64/db_disasm.c
cvs rdiff -u -r0 -r1.1 src/sys/arch/amd64/amd64/db_machdep.c
cvs rdiff -u -r1.18 -r0 src/sys/arch/amd64/amd64/db_trace.c
cvs rdiff -u -r1.71 -r1.72 src/sys/arch/amd64/conf/files.amd64
cvs rdiff -u -r1.9 -r1.10 src/sys/arch/amd64/include/db_machdep.h
cvs rdiff -u -r1.356 -r1.357 src/sys/arch/i386/conf/files.i386
cvs rdiff -u -r0 -r1.1 src/sys/arch/i386/i386/db_machdep.c
cvs rdiff -u -r1.66 -r0 src/sys/arch/i386/i386/db_trace.c
cvs rdiff -u -r1.27 -r1.28 src/sys/arch/i386/include/db_machdep.h
cvs rdiff -u -r1.66 -r1.67 src/sys/arch/x86/conf/files.x86
cvs rdiff -u -r0 -r1.1 src/sys/arch/x86/include/db_machdep.h
cvs rdiff -u -r0 -r1.1 src/sys/arch/x86/x86/db_trace.c

Please note that diffs are not public domain; they are subject to the
copyright notices on the relevant files.

Modified files:

Index: src/sys/arch/amd64/amd64/db_disasm.c
diff -u src/sys/arch/amd64/amd64/db_disasm.c:1.14 src/sys/arch/amd64/amd64/db_disasm.c:1.15
--- src/sys/arch/amd64/amd64/db_disasm.c:1.14	Fri Feb 18 13:00:52 2011
+++ src/sys/arch/amd64/amd64/db_disasm.c	Sun Apr 10 16:36:49 2011
@@ -1,4 +1,4 @@
-/*	$NetBSD: db_disasm.c,v 1.14 2011/02/18 18:00:52 drochner Exp $	*/
+/*	$NetBSD: db_disasm.c,v 1.15 2011/04/10 20:36:49 christos Exp $	*/
 
 /* 
  * Mach Operating System
@@ -33,10 +33,9 @@
  */
 
 #include <sys/cdefs.h>
-__KERNEL_RCSID(0, "$NetBSD: db_disasm.c,v 1.14 2011/02/18 18:00:52 drochner Exp $");
+__KERNEL_RCSID(0, "$NetBSD: db_disasm.c,v 1.15 2011/04/10 20:36:49 christos Exp $");
 
 #ifndef _KERNEL
-#include "stubs.h"
 #include <sys/types.h>
 #include <sys/time.h>
 #include <sys/ksyms.h>

Index: src/sys/arch/amd64/conf/files.amd64
diff -u src/sys/arch/amd64/conf/files.amd64:1.71 src/sys/arch/amd64/conf/files.amd64:1.72
--- src/sys/arch/amd64/conf/files.amd64:1.71	Mon Apr  4 17:35:31 2011
+++ src/sys/arch/amd64/conf/files.amd64	Sun Apr 10 16:36:49 2011
@@ -1,4 +1,4 @@
-#	$NetBSD: files.amd64,v 1.71 2011/04/04 21:35:31 dyoung Exp $
+#	$NetBSD: files.amd64,v 1.72 2011/04/10 20:36:49 christos Exp $
 #
 # new style config file for amd64 architecture
 #
@@ -34,9 +34,9 @@
 file	arch/amd64/amd64/cpu_in_cksum.S		(inet | inet6) & cpu_in_cksum
 file	arch/amd64/amd64/cpufunc.S
 file	arch/amd64/amd64/db_disasm.c		ddb
-file	arch/amd64/amd64/db_interface.c	ddb
+file	arch/amd64/amd64/db_interface.c		ddb
+file	arch/amd64/amd64/db_machdep.c		ddb
 file	arch/amd64/amd64/db_memrw.c		ddb | kgdb
-file	arch/amd64/amd64/db_trace.c		ddb
 file	arch/amd64/amd64/kobj_machdep.c		modular
 file	arch/amd64/amd64/kgdb_machdep.c		kgdb
 file	kern/subr_disk_mbr.c			disk

Index: src/sys/arch/amd64/include/db_machdep.h
diff -u src/sys/arch/amd64/include/db_machdep.h:1.9 src/sys/arch/amd64/include/db_machdep.h:1.10
--- src/sys/arch/amd64/include/db_machdep.h:1.9	Sat Mar 14 10:45:54 2009
+++ src/sys/arch/amd64/include/db_machdep.h	Sun Apr 10 16:36:49 2011
@@ -1,4 +1,4 @@
-/*	$NetBSD: db_machdep.h,v 1.9 2009/03/14 14:45:54 dsl Exp $	*/
+/*	$NetBSD: db_machdep.h,v 1.10 2011/04/10 20:36:49 christos Exp $	*/
 
 /* 
  * Mach Operating System
@@ -44,6 +44,13 @@
 typedef	long		db_expr_t;	/* expression - signed */
 
 typedef struct trapframe db_regs_t;
+
+struct x86_64_frame {
+	struct x86_64_frame	*f_frame;
+	long			f_retaddr;
+	long			f_arg0;
+};
+
 #ifndef MULTIPROCESSOR
 extern db_regs_t ddb_regs;	/* register state */
 #define	DDB_REGS	(&ddb_regs)
@@ -125,10 +132,12 @@
 
 int kdb_trap(int, int, db_regs_t *);
 
+#ifdef _KERNEL
 /*
  * We define some of our own commands
  */
 #define DB_MACHINE_COMMANDS
+#endif
 
 #define	DB_ELF_SYMBOLS
 #define	DB_ELFSIZE	64

Index: src/sys/arch/i386/conf/files.i386
diff -u src/sys/arch/i386/conf/files.i386:1.356 src/sys/arch/i386/conf/files.i386:1.357
--- src/sys/arch/i386/conf/files.i386:1.356	Thu Feb 24 05:56:01 2011
+++ src/sys/arch/i386/conf/files.i386	Sun Apr 10 16:36:48 2011
@@ -1,4 +1,4 @@
-#	$NetBSD: files.i386,v 1.356 2011/02/24 10:56:01 jruoho Exp $
+#	$NetBSD: files.i386,v 1.357 2011/04/10 20:36:48 christos Exp $
 #
 # new style config file for i386 architecture
 #
@@ -67,8 +67,8 @@
 file	arch/i386/i386/db_dbgreg.S	ddb | kstack_check_dr0
 file	arch/i386/i386/db_disasm.c	ddb
 file	arch/i386/i386/db_interface.c	ddb
+file	arch/i386/i386/db_machdep.c	ddb
 file	arch/i386/i386/db_memrw.c	ddb | kgdb
-file	arch/i386/i386/db_trace.c	ddb
 file	arch/i386/i386/dumpsys.c
 file	kern/subr_disk_mbr.c		disk
 file	kern/subr_spldebug.c		spldebug

Index: src/sys/arch/i386/include/db_machdep.h
diff -u src/sys/arch/i386/include/db_machdep.h:1.27 src/sys/arch/i386/include/db_machdep.h:1.28
--- src/sys/arch/i386/include/db_machdep.h:1.27	Sat Mar  7 17:02:16 2009
+++ src/sys/arch/i386/include/db_machdep.h	Sun Apr 10 16:36:48 2011
@@ -1,4 +1,4 @@
-/*	$NetBSD: db_machdep.h,v 1.27 2009/03/07 22:02:16 ad Exp $	*/
+/*	$NetBSD: db_machdep.h,v 1.28 2011/04/10 20:36:48 christos Exp $	*/
 
 /* 
  * Mach Operating System
@@ -44,6 +44,13 @@
 typedef	long		db_expr_t;	/* expression - signed */
 
 typedef struct trapframe db_regs_t;
+
+struct i386_frame {
+	struct i386_frame	*f_frame;
+	int			f_retaddr;
+	int			f_arg0;
+};
+
 #ifndef MULTIPROCESSOR
 extern db_regs_t ddb_regs;	/* register state */
 #define	DDB_REGS	(&ddb_regs)
@@ -142,4 +149,7 @@
 
 extern void cpu_debug_dump(void);
 
+/* i386/db_machdep.c */
+bool db_intrstack_p(const void *);
+
 #endif	/* _I386_DB_MACHDEP_H_ */

Index: src/sys/arch/x86/conf/files.x86
diff -u src/sys/arch/x86/conf/files.x86:1.66 src/sys/arch/x86/conf/files.x86:1.67
--- src/sys/arch/x86/conf/files.x86:1.66	Mon Apr  4 17:33:49 2011
+++ src/sys/arch/x86/conf/files.x86	Sun Apr 10 16:36:48 2011
@@ -1,4 +1,4 @@
-#	$NetBSD: files.x86,v 1.66 2011/04/04 21:33:49 dyoung Exp $
+#	$NetBSD: files.x86,v 1.67 2011/04/10 20:36:48 christos Exp $
 
 # options for MP configuration through the MP spec
 defflag opt_mpbios.h MPBIOS MPVERBOSE MPDEBUG MPBIOS_SCANPCI
@@ -67,6 +67,7 @@
 file	arch/x86/x86/consinit.c
 file	arch/x86/x86/core_machdep.c	coredump
 file	arch/x86/x86/cpu_topology.c
+file	arch/x86/x86/db_trace.c		ddb
 file	arch/x86/x86/errata.c
 file	arch/x86/x86/genfb_machdep.c
 file	arch/x86/x86/identcpu.c

Added files:

Index: src/sys/arch/amd64/amd64/db_machdep.c
diff -u /dev/null src/sys/arch/amd64/amd64/db_machdep.c:1.1
--- /dev/null	Sun Apr 10 16:36:50 2011
+++ src/sys/arch/amd64/amd64/db_machdep.c	Sun Apr 10 16:36:49 2011
@@ -0,0 +1,239 @@
+/*	$NetBSD: db_machdep.c,v 1.1 2011/04/10 20:36:49 christos Exp $	*/
+
+/* 
+ * 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.distribut...@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.
+ */
+#include <sys/cdefs.h>
+__KERNEL_RCSID(0, "$NetBSD: db_machdep.c,v 1.1 2011/04/10 20:36:49 christos Exp $");
+
+#include <sys/param.h>
+#include <sys/systm.h>
+#include <sys/proc.h>
+
+#include <machine/frame.h>
+#include <machine/trap.h>
+#include <machine/intrdefs.h>
+
+#include <machine/db_machdep.h>
+#include <ddb/db_sym.h>
+#include <ddb/db_access.h>
+#include <ddb/db_variables.h>
+#include <ddb/db_output.h>
+#include <ddb/db_interface.h>
+#include <ddb/db_user.h>
+#include <ddb/db_proc.h>
+#include <ddb/db_command.h>
+#include <x86/db_machdep.h>
+
+#define dbreg(xx) (long *)offsetof(db_regs_t, tf_ ## xx)
+
+/*
+ * Machine register set.
+ */
+const struct db_variable db_regs[] = {
+	{ "ds",		dbreg(ds),     db_x86_regop, NULL },
+	{ "es",		dbreg(es),     db_x86_regop, NULL },
+	{ "fs",		dbreg(fs),     db_x86_regop, NULL },
+	{ "gs",		dbreg(gs),     db_x86_regop, NULL },
+	{ "rdi",	dbreg(rdi),    db_x86_regop, NULL },
+	{ "rsi",	dbreg(rsi),    db_x86_regop, NULL },
+	{ "rbp",	dbreg(rbp),    db_x86_regop, NULL },
+	{ "rbx",	dbreg(rbx),    db_x86_regop, NULL },
+	{ "rdx",	dbreg(rdx),    db_x86_regop, NULL },
+	{ "rcx",	dbreg(rcx),    db_x86_regop, NULL },
+	{ "rax",	dbreg(rax),    db_x86_regop, NULL },
+	{ "r8",		dbreg(r8),     db_x86_regop, NULL },
+	{ "r9",		dbreg(r9),     db_x86_regop, NULL },
+	{ "r10",	dbreg(r10),    db_x86_regop, NULL },
+	{ "r11",	dbreg(r11),    db_x86_regop, NULL },
+	{ "r12",	dbreg(r12),    db_x86_regop, NULL },
+	{ "r13",	dbreg(r13),    db_x86_regop, NULL },
+	{ "r14",	dbreg(r14),    db_x86_regop, NULL },
+	{ "r15",	dbreg(r15),    db_x86_regop, NULL },
+	{ "rip",	dbreg(rip),    db_x86_regop, NULL },
+	{ "cs",		dbreg(cs),     db_x86_regop, NULL },
+	{ "rflags",	dbreg(rflags), db_x86_regop, NULL },
+	{ "rsp",	dbreg(rsp),    db_x86_regop, NULL },
+	{ "ss",		dbreg(ss),     db_x86_regop, NULL },
+};
+const struct db_variable * const db_eregs =
+	db_regs + sizeof(db_regs)/sizeof(db_regs[0]);
+
+/*
+ * Figure out how many arguments were passed into the frame at "fp".
+ * We can probably figure out how many arguments where passed above
+ * the first 6 (which are in registers), but since we can't
+ * reliably determine the values currently, just return 0.
+ */
+int
+db_numargs(long *retaddrp)
+{
+	return 0;
+}
+
+/* 
+ * Figure out the next frame up in the call stack.  
+ * For trap(), we print the address of the faulting instruction and 
+ *   proceed with the calling frame.  We return the ip that faulted.
+ *   If the trap was caused by jumping through a bogus pointer, then
+ *   the next line in the backtrace will list some random function as 
+ *   being called.  It should get the argument list correct, though.  
+ *   It might be possible to dig out from the next frame up the name
+ *   of the function that faulted, but that could get hairy.
+ */
+int
+db_nextframe(long **nextframe, long **retaddr, long **arg0, db_addr_t *ip,
+	     long *argp, int is_trap, void (*pr)(const char *, ...))
+{
+	struct trapframe *tf;
+	struct x86_64_frame *fp;
+	struct intrframe *ifp;
+	int traptype, trapno, err, i;
+
+	switch (is_trap) {
+	    case NONE:
+		*ip = (db_addr_t)
+			db_get_value((long)*retaddr, 8, false);
+		fp = (struct x86_64_frame *)
+			db_get_value((long)*nextframe, 8, false);
+		if (fp == NULL)
+			return 0;
+		*nextframe = (long *)&fp->f_frame;
+		*retaddr = (long *)&fp->f_retaddr;
+		*arg0 = (long *)&fp->f_arg0;
+		break;
+
+	    case TRAP:
+	    case SYSCALL:
+	    case INTERRUPT:
+	    default:
+
+		/* The only argument to trap() or syscall() is the trapframe. */
+		tf = *(struct trapframe **)argp;
+		switch (is_trap) {
+		case TRAP:
+			(*pr)("--- trap (number %d) ---\n", tf->tf_trapno);
+			break;
+		case SYSCALL:
+			(*pr)("--- syscall (number %ld) ---\n", tf->tf_rax);
+			break;
+		case INTERRUPT:
+			(*pr)("--- interrupt ---\n");
+			tf = (struct trapframe *)argp;
+			break;
+		}
+		*ip = (db_addr_t)tf->tf_rip;
+		fp = (struct x86_64_frame *)tf->tf_rbp;
+		if (fp == NULL)
+			return 0;
+		*nextframe = (long *)&fp->f_frame;
+		*retaddr = (long *)&fp->f_retaddr;
+		*arg0 = (long *)&fp->f_arg0;
+		break;
+	}
+
+	/*
+	 * A bit of a hack. Since %rbp may be used in the stub code,
+	 * walk the stack looking for a valid interrupt frame. Such
+	 * a frame can be recognized by always having
+	 * err 0 or IREENT_MAGIC and trapno T_ASTFLT.
+	 */
+	if (db_frame_info(*nextframe, (db_addr_t)*ip, NULL, NULL, &traptype,
+	    NULL) != (db_sym_t)0
+	    && traptype == INTERRUPT) {
+		for (i = 0; i < 4; i++) {
+			ifp = (struct intrframe *)(argp + i);
+			err = db_get_value((long)&ifp->if_tf.tf_err,
+			    sizeof(long), false);
+			trapno = db_get_value((long)&ifp->if_tf.tf_trapno,
+			    sizeof(long), false);
+			if ((err == 0 || err == IREENT_MAGIC)
+			    && trapno == T_ASTFLT) {
+				*nextframe = (long *)ifp - 1;
+				break;
+			}
+		}
+		if (i == 4) {
+			(*pr)("DDB lost frame for ");
+			db_printsym(*ip, DB_STGY_ANY, pr);
+			(*pr)(", trying %p\n",argp);
+			*nextframe = argp;
+		}
+	}
+	return 1;
+}
+
+db_sym_t
+db_frame_info(long *frame, db_addr_t callpc, const char **namep,
+	      db_expr_t *offp, int *is_trap, int *nargp)
+{
+	db_expr_t	offset;
+	db_sym_t	sym;
+	int narg;
+	const char *name;
+
+	sym = db_search_symbol(callpc, DB_STGY_ANY, &offset);
+	db_symbol_values(sym, &name, NULL);
+	if (sym == (db_sym_t)0)
+		return (db_sym_t)0;
+
+	*is_trap = NONE;
+	narg = 0;
+
+	if (INKERNEL((long)frame) && name) {
+		/*
+		 * XXX traps should be based off of the Xtrap*
+		 * locations rather than on trap, since some traps
+		 * (e.g., npxdna) don't go through trap()
+		 */
+		if (!strcmp(name, "trap")) {
+			*is_trap = TRAP;
+			narg = 0;
+		} else if (!strcmp(name, "syscall_plain") ||
+		           !strcmp(name, "syscall_fancy")) {
+			*is_trap = SYSCALL;
+			narg = 0;
+		} else if (name[0] == 'X') {
+			if (!strncmp(name, "Xintr", 5) ||
+			    !strncmp(name, "Xresume", 7) ||
+			    !strncmp(name, "Xstray", 6) ||
+			    !strncmp(name, "Xhold", 5) ||
+			    !strncmp(name, "Xrecurse", 8) ||
+			    !strcmp(name, "Xdoreti") ||
+			    !strncmp(name, "Xsoft", 5)) {
+				*is_trap = INTERRUPT;
+				narg = 0;
+			}
+		}
+	}
+
+	if (offp != NULL)
+		*offp = offset;
+	if (nargp != NULL)
+		*nargp = narg;
+	if (namep != NULL)
+		*namep = name;
+	return sym;
+}

Index: src/sys/arch/i386/i386/db_machdep.c
diff -u /dev/null src/sys/arch/i386/i386/db_machdep.c:1.1
--- /dev/null	Sun Apr 10 16:36:50 2011
+++ src/sys/arch/i386/i386/db_machdep.c	Sun Apr 10 16:36:48 2011
@@ -0,0 +1,325 @@
+/*	$NetBSD: db_machdep.c,v 1.1 2011/04/10 20:36:48 christos Exp $	*/
+
+/* 
+ * 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.distribut...@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.
+ */
+
+#include <sys/cdefs.h>
+__KERNEL_RCSID(0, "$NetBSD: db_machdep.c,v 1.1 2011/04/10 20:36:48 christos Exp $");
+
+#include <sys/param.h>
+#include <sys/systm.h>
+#include <sys/proc.h>
+
+#include <machine/frame.h>
+#include <machine/trap.h>
+#include <machine/intrdefs.h>
+
+#include <machine/db_machdep.h>
+#include <ddb/db_sym.h>
+#include <ddb/db_access.h>
+#include <ddb/db_variables.h>
+#include <ddb/db_output.h>
+#include <ddb/db_interface.h>
+#include <ddb/db_user.h>
+#include <ddb/db_proc.h>
+#include <ddb/db_command.h>
+#include <ddb/db_cpu.h>
+#include <x86/db_machdep.h>
+
+#define dbreg(xx) (long *)offsetof(db_regs_t, tf_ ## xx)
+
+const struct db_variable db_regs[] = {
+	{ "ds",		dbreg(ds),     db_x86_regop, NULL },
+	{ "es",		dbreg(es),     db_x86_regop, NULL },
+	{ "fs",		dbreg(fs),     db_x86_regop, NULL },
+	{ "gs",		dbreg(gs),     db_x86_regop, NULL },
+	{ "edi",	dbreg(edi),    db_x86_regop, NULL },
+	{ "esi",	dbreg(esi),    db_x86_regop, NULL },
+	{ "ebp",	dbreg(ebp),    db_x86_regop, NULL },
+	{ "ebx",	dbreg(ebx),    db_x86_regop, NULL },
+	{ "edx",	dbreg(edx),    db_x86_regop, NULL },
+	{ "ecx",	dbreg(ecx),    db_x86_regop, NULL },
+	{ "eax",	dbreg(eax),    db_x86_regop, NULL },
+	{ "eip",	dbreg(eip),    db_x86_regop, NULL },
+	{ "cs",		dbreg(cs),     db_x86_regop, NULL },
+	{ "eflags",	dbreg(eflags), db_x86_regop, NULL },
+	{ "esp",	dbreg(esp),    db_x86_regop, NULL },
+	{ "ss",		dbreg(ss),     db_x86_regop, NULL },
+};
+const struct db_variable * const db_eregs =
+    db_regs + sizeof(db_regs)/sizeof(db_regs[0]);
+
+/*
+ * Figure out how many arguments were passed into the frame at "fp".
+ */
+int
+db_numargs(long *retaddrp)
+{
+	int	*argp;
+	int	inst;
+	int	args;
+	extern char	etext[];
+
+	argp = (int *)db_get_value((int)retaddrp, 4, false);
+	if (argp < (int *)VM_MIN_KERNEL_ADDRESS || argp > (int *)etext) {
+		args = 10;
+	} else {
+		inst = db_get_value((int)argp, 4, false);
+		if ((inst & 0xff) == 0x59)	/* popl %ecx */
+			args = 1;
+		else if ((inst & 0xffff) == 0xc483)	/* addl %n, %esp */
+			args = ((inst >> 16) & 0xff) / 4;
+		else
+			args = 10;
+	}
+	return (args);
+}
+
+db_sym_t
+db_frame_info(long *frame, db_addr_t callpc, const char **namep, db_expr_t *offp,
+	      int *is_trap, int *nargp)
+{
+	db_expr_t	offset;
+	db_sym_t	sym;
+	int narg;
+	const char *name;
+
+	sym = db_search_symbol(callpc, DB_STGY_ANY, &offset);
+	db_symbol_values(sym, &name, NULL);
+	if (sym == (db_sym_t)0)
+		return (db_sym_t)0;
+
+	*is_trap = NONE;
+	narg = MAXNARG;
+
+	if (INKERNEL((int)frame) && name) {
+		/*
+		 * XXX traps should be based off of the Xtrap*
+		 * locations rather than on trap, since some traps
+		 * (e.g., npxdna) don't go through trap()
+		 */
+#ifdef __ELF__
+		if (!strcmp(name, "trap_tss")) {
+			*is_trap = TRAP_TSS;
+			narg = 0;
+		} else if (!strcmp(name, "trap")) {
+			*is_trap = TRAP;
+			narg = 0;
+		} else if (!strcmp(name, "syscall_plain") ||
+		           !strcmp(name, "syscall_fancy")) {
+			*is_trap = SYSCALL;
+			narg = 0;
+		} else if (name[0] == 'X') {
+			if (!strncmp(name, "Xintr", 5) ||
+			    !strncmp(name, "Xresume", 7) ||
+			    !strncmp(name, "Xstray", 6) ||
+			    !strncmp(name, "Xhold", 5) ||
+			    !strncmp(name, "Xrecurse", 8) ||
+			    !strcmp(name, "Xdoreti") ||
+			    !strncmp(name, "Xsoft", 5)) {
+				*is_trap = INTERRUPT;
+				narg = 0;
+			} else if (!strncmp(name, "Xtss_", 5)) {
+				*is_trap = INTERRUPT_TSS;
+				narg = 0;
+			}
+		}
+#else
+		if (!strcmp(name, "_trap_tss")) {
+			*is_trap = TRAP_TSS;
+			narg = 0;
+		} else if (!strcmp(name, "_trap")) {
+			*is_trap = TRAP;
+			narg = 0;
+		} else if (!strcmp(name, "_syscall")) {
+			*is_trap = SYSCALL;
+			narg = 0;
+		} else if (name[0] == '_' && name[1] == 'X') {
+			if (!strncmp(name, "_Xintr", 6) ||
+			    !strncmp(name, "_Xresume", 8) ||
+			    !strncmp(name, "_Xstray", 7) ||
+			    !strncmp(name, "_Xhold", 6) ||
+			    !strncmp(name, "_Xrecurse", 9) ||
+			    !strcmp(name, "_Xdoreti") ||
+			    !strncmp(name, "_Xsoft", 6)) {
+				*is_trap = INTERRUPT;
+				narg = 0;
+			} else if (!strncmp(name, "_Xtss_", 6)) {
+				*is_trap = INTERRUPT_TSS;
+				narg = 0;
+			}
+		}
+#endif /* __ELF__ */
+	}
+
+	if (offp != NULL)
+		*offp = offset;
+	if (nargp != NULL)
+		*nargp = narg;
+	if (namep != NULL)
+		*namep = name;
+	return sym;
+}
+
+/* 
+ * Figure out the next frame up in the call stack.  
+ * For trap(), we print the address of the faulting instruction and 
+ *   proceed with the calling frame.  We return the ip that faulted.
+ *   If the trap was caused by jumping through a bogus pointer, then
+ *   the next line in the backtrace will list some random function as 
+ *   being called.  It should get the argument list correct, though.  
+ *   It might be possible to dig out from the next frame up the name
+ *   of the function that faulted, but that could get hairy.
+ */
+
+int
+db_nextframe(
+    long **nextframe,	/* IN/OUT */
+    long **retaddr,	/* IN/OUT */
+    long **arg0,		/* OUT */
+    db_addr_t *ip,	/* OUT */
+    long *argp,		/* IN */
+    int is_trap, void (*pr)(const char *, ...))
+{
+	static struct trapframe tf;
+	static struct i386tss tss;
+	struct i386_frame *fp;
+	struct intrframe *ifp;
+	int traptype, trapno, err, i;
+	uintptr_t ptr;
+
+	switch (is_trap) {
+	    case NONE:
+		*ip = (db_addr_t)
+			db_get_value((int)*retaddr, 4, false);
+		fp = (struct i386_frame *)
+			db_get_value((int)*nextframe, 4, false);
+		if (fp == NULL)
+			return 0;
+		*nextframe = (long *)&fp->f_frame;
+		*retaddr = (long *)&fp->f_retaddr;
+		*arg0 = (long *)&fp->f_arg0;
+		break;
+
+	    case TRAP_TSS:
+	    case INTERRUPT_TSS:
+		ptr = db_get_value((int)argp, 4, false);
+		db_read_bytes((db_addr_t)ptr, sizeof(tss), (char *)&tss);
+		*ip = tss.__tss_eip;
+		fp = (struct i386_frame *)tss.tss_ebp;
+		if (fp == NULL)
+			return 0;
+		*nextframe = (long *)&fp->f_frame;
+		*retaddr = (long *)&fp->f_retaddr;
+		*arg0 = (long *)&fp->f_arg0;
+		if (is_trap == INTERRUPT_TSS)
+			(*pr)("--- interrupt via task gate ---\n");
+		else
+			(*pr)("--- trap via task gate ---\n");
+		break;
+
+	    case TRAP:
+	    case SYSCALL:
+	    case INTERRUPT:
+	    default:
+		/* The only argument to trap() or syscall() is the trapframe. */
+		ptr = db_get_value((int)argp, 4, false);
+		db_read_bytes((db_addr_t)ptr, sizeof(tf), (char *)&tf);
+		switch (is_trap) {
+		case TRAP:
+			(*pr)("--- trap (number %d) ---\n", tf.tf_trapno);
+			break;
+		case SYSCALL:
+			(*pr)("--- syscall (number %d) ---\n", tf.tf_eax);
+			break;
+		case INTERRUPT:
+			(*pr)("--- interrupt ---\n");
+			/*
+			 * Get intrframe address as saved when switching
+			 * to interrupt stack, and convert to trapframe
+			 * (add 4).  See frame.h.
+			 */
+			ptr = db_get_value((int)(argp - 1) + 4, 4, false);
+			db_read_bytes((db_addr_t)ptr, sizeof(tf), (char *)&tf);
+			break;
+		}
+		*ip = (db_addr_t)tf.tf_eip;
+		fp = (struct i386_frame *)tf.tf_ebp;
+		if (fp == NULL)
+			return 0;
+		*nextframe = (long *)&fp->f_frame;
+		*retaddr = (long *)&fp->f_retaddr;
+		*arg0 = (long *)&fp->f_arg0;
+		break;
+	}
+
+	/*
+	 * A bit of a hack. Since %ebp may be used in the stub code,
+	 * walk the stack looking for a valid interrupt frame. Such
+	 * a frame can be recognized by always having
+	 * err 0 or IREENT_MAGIC and trapno T_ASTFLT.
+	 */
+	if (db_frame_info(*nextframe, (db_addr_t)*ip, NULL, NULL, &traptype,
+	    NULL) != (db_sym_t)0
+	    && traptype == INTERRUPT) {
+		for (i = 0; i < 4; i++) {
+			ifp = (struct intrframe *)(argp + i);
+			err = db_get_value((int)&ifp->__if_err, 4, false);
+			trapno = db_get_value((int)&ifp->__if_trapno, 4, false);
+			if ((err == 0 || err == IREENT_MAGIC) && trapno == T_ASTFLT) {
+				*nextframe = (long *)ifp - 1;
+				break;
+			}
+		}
+		if (i == 4) {
+			(*pr)("DDB lost frame for ");
+			db_printsym(*ip, DB_STGY_ANY, pr);
+			(*pr)(", trying %p\n",argp);
+			*nextframe = argp;
+		}
+	}
+	return 1;
+}
+
+bool
+db_intrstack_p(const void *vp)
+{
+	struct cpu_info *ci;
+	const char *cp;
+
+	for (ci = db_cpu_first(); ci != NULL; ci = db_cpu_next(ci)) {
+		db_read_bytes((db_addr_t)&ci->ci_intrstack, sizeof(cp),
+		    (char *)&cp);
+		if (cp == NULL) {
+			continue;
+		}
+		if ((cp - INTRSTACKSIZE + 4) <= (const char *)vp &&
+		    (const char *)vp <= cp) {
+			return true;
+		}
+	}
+	return false;
+}

Index: src/sys/arch/x86/include/db_machdep.h
diff -u /dev/null src/sys/arch/x86/include/db_machdep.h:1.1
--- /dev/null	Sun Apr 10 16:36:50 2011
+++ src/sys/arch/x86/include/db_machdep.h	Sun Apr 10 16:36:48 2011
@@ -0,0 +1,40 @@
+/*	$NetBSD: db_machdep.h,v 1.1 2011/04/10 20:36:48 christos Exp $	*
+
+#ifndef _X86_DB_MACHDEP_H_
+#define _X86_DB_MACHDEP_H_
+
+#define	INKERNEL(va)	(((vaddr_t)(va)) >= VM_MIN_KERNEL_ADDRESS)
+
+#define NONE		0
+#define TRAP		1
+#define SYSCALL		2
+#define INTERRUPT	3
+#define INTERRUPT_TSS	4
+#define TRAP_TSS	5
+
+#define MAXNARG		16
+
+struct db_variable;
+
+#ifdef __x86_64__
+#define	tf_sp		tf_rsp
+#define	tf_ip		tf_rip
+#define	tf_bp		tf_rbp
+#define	pcb_bp		pcb_rbp
+#define	x86_frame	x86_64_frame
+#else
+#define	tf_sp		tf_esp
+#define	tf_ip		tf_eip
+#define	tf_bp		tf_ebp
+#define	pcb_bp		pcb_ebp
+#define	x86_frame	i386_frame
+#endif
+
+int db_x86_regop(const struct db_variable *, db_expr_t *, int);
+int db_numargs(long *);
+int db_nextframe(long **, long **, long **, db_addr_t *, long *, int,
+		 void (*) (const char *, ...));
+db_sym_t db_frame_info(long *, db_addr_t, const char **, db_expr_t *,
+                       int *, int *);
+
+#endif /* _X86_DB_MACHDEP_H_ */

Index: src/sys/arch/x86/x86/db_trace.c
diff -u /dev/null src/sys/arch/x86/x86/db_trace.c:1.1
--- /dev/null	Sun Apr 10 16:36:50 2011
+++ src/sys/arch/x86/x86/db_trace.c	Sun Apr 10 16:36:49 2011
@@ -0,0 +1,307 @@
+/*	$NetBSD: db_trace.c,v 1.1 2011/04/10 20:36:49 christos Exp $	*/
+
+/* 
+ * 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.distribut...@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.
+ */
+
+#include <sys/cdefs.h>
+__KERNEL_RCSID(0, "$NetBSD: db_trace.c,v 1.1 2011/04/10 20:36:49 christos Exp $");
+
+#include <sys/param.h>
+#include <sys/systm.h>
+#include <sys/proc.h>
+
+#include <machine/frame.h>
+#include <machine/trap.h>
+#include <machine/intrdefs.h>
+
+#include <machine/db_machdep.h>
+#include <ddb/db_sym.h>
+#include <ddb/db_access.h>
+#include <ddb/db_variables.h>
+#include <ddb/db_output.h>
+#include <ddb/db_interface.h>
+#include <ddb/db_user.h>
+#include <ddb/db_proc.h>
+#include <ddb/db_command.h>
+#include <x86/db_machdep.h>
+
+int
+db_x86_regop(const struct db_variable *vp, db_expr_t *val, int opcode)
+{
+        db_expr_t *regaddr =
+            (db_expr_t *)(((uint8_t *)DDB_REGS) + ((size_t)vp->valuep));
+        
+        switch (opcode) {
+        case DB_VAR_GET:
+                *val = *regaddr;
+                break;
+        case DB_VAR_SET:
+                *regaddr = *val;
+                break;
+        default:
+		db_printf("db_x86_regop: unknown op %d", opcode);
+		db_error(NULL);
+        }
+        return 0;
+}
+
+/*
+ * Stack trace.
+ */
+
+#if 0
+db_addr_t	db_trap_symbol_value = 0;
+db_addr_t	db_syscall_symbol_value = 0;
+db_addr_t	db_kdintr_symbol_value = 0;
+bool		db_trace_symbols_found = false;
+
+void db_find_trace_symbols(void);
+
+void
+db_find_trace_symbols(void)
+{
+	db_expr_t	value;
+
+	if (db_value_of_name("_trap", &value))
+		db_trap_symbol_value = (db_addr_t) value;
+	if (db_value_of_name("_kdintr", &value))
+		db_kdintr_symbol_value = (db_addr_t) value;
+	if (db_value_of_name("_syscall", &value))
+		db_syscall_symbol_value = (db_addr_t) value;
+	db_trace_symbols_found = true;
+}
+#endif
+
+void
+db_stack_trace_print(db_expr_t addr, bool have_addr, db_expr_t count,
+		     const char *modif, void (*pr)(const char *, ...))
+{
+	long		*frame, *lastframe;
+	long		*retaddr, *arg0;
+	long		*argp;
+	db_addr_t	 callpc;
+	int		 is_trap;
+	bool		 kernel_only = true;
+	bool		 trace_thread = false;
+	bool		 lwpaddr = false;
+
+#if 0
+	if (!db_trace_symbols_found)
+		db_find_trace_symbols();
+#endif
+
+	{
+		const char *cp = modif;
+		char c;
+
+		while ((c = *cp++) != 0) {
+			if (c == 'a') {
+				lwpaddr = true;
+				trace_thread = true;
+			}
+			if (c == 't')
+				trace_thread = true;
+			if (c == 'u')
+				kernel_only = false;
+		}
+	}
+
+#define set_frame_callpc() do {				\
+		frame = (long *)ddb_regs.tf_bp;		\
+		callpc = (db_addr_t)ddb_regs.tf_ip;	\
+	} while (/*CONSTCCOND*/0)
+
+	if (have_addr && trace_thread) {
+		struct pcb *pcb;
+		proc_t p;
+		lwp_t l;
+
+		if (lwpaddr) {
+			db_read_bytes(addr, sizeof(l),
+			    (char *)&l);
+			db_read_bytes((db_addr_t)l.l_proc,
+			    sizeof(p), (char *)&p);
+			(*pr)("trace: pid %d ", p.p_pid);
+		} else {
+			proc_t	*pp;
+
+			(*pr)("trace: pid %d ", (int)addr);
+			if ((pp = db_proc_find((pid_t)addr)) == 0) {
+				(*pr)("not found\n");
+				return;
+			}
+			db_read_bytes((db_addr_t)pp, sizeof(p), (char *)&p);
+			db_read_bytes((db_addr_t)p.p_lwps.lh_first,
+			    sizeof(l), (char *)&l);
+		}
+		(*pr)("lid %d ", l.l_lid);
+		pcb = lwp_getpcb(&l);
+#ifdef _KERNEL
+		if (l.l_proc == curproc && (lwp_t *)lwpaddr == curlwp)
+			set_frame_callpc();
+		else
+#endif
+		{
+			db_read_bytes((db_addr_t)&pcb->pcb_bp,
+			    sizeof(frame), (char *)&frame);
+			db_read_bytes((db_addr_t)(frame + 1),
+			    sizeof(callpc), (char *)&callpc);
+			db_read_bytes((db_addr_t)frame,
+			    sizeof(frame), (char *)&frame);
+		}
+		(*pr)("at %p\n", frame);
+	} else if (have_addr) {
+		frame = (long *)addr;
+		db_read_bytes((db_addr_t)(frame + 1),
+		    sizeof(callpc), (char *)&callpc);
+		db_read_bytes((db_addr_t)frame,
+		    sizeof(frame), (char *)&frame);
+	} else
+		set_frame_callpc();
+	retaddr = frame + 1;
+	arg0 = frame + 2;
+
+	lastframe = 0;
+	while (count && frame != 0) {
+		int		narg;
+		const char *	name;
+		db_expr_t	offset;
+		db_sym_t	sym;
+		char	*argnames[MAXNARG], **argnp = NULL;
+		db_addr_t	lastcallpc;
+
+		name = "?";
+		is_trap = NONE;
+		offset = 0;
+		sym = db_frame_info(frame, callpc, &name, &offset, &is_trap,
+				    &narg);
+
+		if (lastframe == 0 && sym == (db_sym_t)0 && callpc != 0) {
+			/* Symbol not found, peek at code */
+			u_long	instr = db_get_value(callpc, 4, false);
+
+			offset = 1;
+			if (
+#ifdef __x86_64__
+			    instr == 0xe5894855 ||
+					/* enter: pushq %rbp, movq %rsp, %rbp */
+			    (instr & 0x00ffffff) == 0x0048e589
+					/* enter+1: movq %rsp, %rbp */)
+#else
+			    (instr & 0x00ffffff) == 0x00e58955 ||
+					/* enter: pushl %ebp, movl %esp, %ebp */
+			    (instr & 0x0000ffff) == 0x0000e589
+					/* enter+1: movl %esp, %ebp */)
+#endif
+			{
+				offset = 0;
+			}
+		}
+
+		if (is_trap == NONE) {
+			if (db_sym_numargs(sym, &narg, argnames))
+				argnp = argnames;
+			else
+				narg = db_numargs(frame);
+		}
+
+		(*pr)("%s(", name);
+
+		if (lastframe == 0 && offset == 0 && !have_addr) {
+			/*
+			 * We have a breakpoint before the frame is set up
+			 * Use %[er]sp instead
+			 */
+			argp = (long *)&((struct x86_frame *)
+			    (ddb_regs.tf_sp-sizeof(long)))->f_arg0;
+		} else {
+			argp = frame + 2;
+		}
+
+		while (narg) {
+			if (argnp)
+				(*pr)("%s=", *argnp++);
+			(*pr)("%lx", db_get_value((long)argp, sizeof(long),
+			    false));
+			argp++;
+			if (--narg != 0)
+				(*pr)(",");
+		}
+		(*pr)(") at ");
+		db_printsym(callpc, DB_STGY_PROC, pr);
+		(*pr)("\n");
+
+		if (lastframe == 0 && offset == 0 && !have_addr) {
+			/* Frame really belongs to next callpc */
+			struct x86_frame *fp = (void *)
+			    (ddb_regs.tf_sp-sizeof(long));
+			lastframe = (long *)fp;
+			callpc = (db_addr_t)
+			    db_get_value((db_addr_t)&fp->f_retaddr,
+				sizeof(long), false);
+
+			continue;
+		}
+
+		lastframe = frame;
+		lastcallpc = callpc;
+		if (!db_nextframe(&frame, &retaddr, &arg0,
+		   &callpc, frame + 2, is_trap, pr))
+			break;
+
+		if (INKERNEL((long)frame)) {
+			/* staying in kernel */
+#ifdef __i386__
+			if (!db_intrstack_p(frame)
+			    && db_intrstack_p(lastframe)) {
+				(*pr)("--- switch to interrupt stack ---\n");
+			} else
+#endif
+			if (frame < lastframe ||
+			    (frame == lastframe && callpc == lastcallpc)) {
+				(*pr)("Bad frame pointer: %p\n", frame);
+				break;
+			}
+		} else if (INKERNEL((long)lastframe)) {
+			/* switch from user to kernel */
+			if (kernel_only)
+				break;	/* kernel stack only */
+		} else {
+			/* in user */
+			if (frame <= lastframe) {
+				(*pr)("Bad user frame pointer: %p\n", frame);
+				break;
+			}
+		}
+		--count;
+	}
+
+	if (count && is_trap != NONE) {
+		db_printsym(callpc, DB_STGY_XTRN, pr);
+		(*pr)(":\n");
+	}
+#undef set_frame_callpc
+}

Reply via email to