aboutsummaryrefslogtreecommitdiffstats
path: root/devel
diff options
context:
space:
mode:
authorjhb <jhb@FreeBSD.org>2015-10-07 02:52:58 +0800
committerjhb <jhb@FreeBSD.org>2015-10-07 02:52:58 +0800
commitc5e97b6910004a9247539e4fc39e89e2093c0d89 (patch)
tree3560d9f53b5090054def488a50cef01c6fbfe2d0 /devel
parent784245cf177421c9c43326815dd493b0b81cc095 (diff)
downloadfreebsd-ports-gnome-c5e97b6910004a9247539e4fc39e89e2093c0d89.tar.gz
freebsd-ports-gnome-c5e97b6910004a9247539e4fc39e89e2093c0d89.tar.zst
freebsd-ports-gnome-c5e97b6910004a9247539e4fc39e89e2093c0d89.zip
Add a new KGDB option to the devel/gdb port. This adds a forward port
of the kernel-specific bits of kgdb to recent gdb. It only supports amd64, i386, powerpc, powerpc64, and sparc64. PR: 203299 Reviewed by: bdrewery Glanced at by: emaste, jilles, luca.pizzamiglio@gmail.com (maintainer) Differential Revision: https://reviews.freebsd.org/D3727
Diffstat (limited to 'devel')
-rw-r--r--devel/gdb/Makefile25
-rw-r--r--devel/gdb/files/extrapatch-kgdb226
-rw-r--r--devel/gdb/files/extrapatch-kgdb-configure.tgt-plain50
-rw-r--r--devel/gdb/files/extrapatch-kgdb-configure.tgt-threads50
-rw-r--r--devel/gdb/files/kgdb/amd64fbsd-kern.c304
-rw-r--r--devel/gdb/files/kgdb/fbsd-kld.c591
-rw-r--r--devel/gdb/files/kgdb/fbsd-kthr.c351
-rw-r--r--devel/gdb/files/kgdb/fbsd-kvm.c588
-rw-r--r--devel/gdb/files/kgdb/i386fbsd-kern.c561
-rw-r--r--devel/gdb/files/kgdb/kgdb-main.c413
-rw-r--r--devel/gdb/files/kgdb/kgdb.h67
-rw-r--r--devel/gdb/files/kgdb/ppcfbsd-kern.c254
-rw-r--r--devel/gdb/files/kgdb/sparc64fbsd-kern.c319
-rw-r--r--devel/gdb/pkg-plist2
14 files changed, 3798 insertions, 3 deletions
diff --git a/devel/gdb/Makefile b/devel/gdb/Makefile
index f36d61ce602a..a9a6410e770e 100644
--- a/devel/gdb/Makefile
+++ b/devel/gdb/Makefile
@@ -32,7 +32,7 @@ PLIST_SUB= VER=${VER}
ONLY_FOR_ARCHS= i386 amd64 powerpc powerpc64 # untested elsewhere, might work
-OPTIONS_DEFINE= DEBUG EXPAT GDB_LINK GUILE PYTHON THREADS TUI
+OPTIONS_DEFINE= DEBUG EXPAT GDB_LINK GUILE KGDB PYTHON THREADS TUI
OPTIONS_DEFAULT= GDB_LINK THREADS TUI PORT_READLINE
@@ -40,6 +40,7 @@ OPTIONS_SINGLE= READLINE
OPTIONS_SINGLE_READLINE= BASE_READLINE BUNDLED_READLINE PORT_READLINE
GDB_LINK_DESC= Create ${PREFIX}/bin/gdb symlink
+KGDB_DESC= Kernel Debugging Support
BASE_READLINE_DESC= from base system (experimental)
BUNDLED_READLINE_DESC= from gdb distfile
PORT_READLINE_DESC= from devel/readline port
@@ -76,10 +77,21 @@ CONFIGURE_TARGET= x86_64-portbld-freebsd${OSREL}
post-patch:
@${REINPLACE_CMD} -e 's|$$| [GDB v${PORTVERSION} for FreeBSD]|' \
${WRKSRC}/gdb/version.in
-
-post-patch-THREADS-on:
+.if ${PORT_OPTIONS:MTHREADS}
@${CP} ${FILESDIR}/fbsd-threads.c ${WRKSRC}/gdb/
@${PATCH} ${PATCH_ARGS} < ${FILESDIR}/extrapatch-threads
+.endif
+.if ${PORT_OPTIONS:MKGDB}
+ @${CP} -r ${FILESDIR}/kgdb/*.[ch] ${WRKSRC}/gdb/
+ @${PATCH} ${PATCH_ARGS} < ${FILESDIR}/extrapatch-kgdb
+.if ${PORT_OPTIONS:MTHREADS}
+ @${PATCH} ${PATCH_ARGS} < \
+ ${FILESDIR}/extrapatch-kgdb-configure.tgt-threads
+.else
+ @${PATCH} ${PATCH_ARGS} < \
+ ${FILESDIR}/extrapatch-kgdb-configure.tgt-plain
+.endif
+.endif
do-install:
${INSTALL_PROGRAM} ${WRKSRC}/gdb/gdb \
@@ -87,11 +99,18 @@ do-install:
${INSTALL_MAN} ${WRKSRC}/gdb/doc/gdb.1 \
${STAGEDIR}${MAN1PREFIX}/man/man1/gdb${VER}.1
+do-install-KGDB-on:
+ ${INSTALL_PROGRAM} ${WRKSRC}/gdb/kgdb \
+ ${STAGEDIR}${PREFIX}/bin/kgdb${VER}
+
do-install-TUI-on:
${LN} -sf gdb${VER} ${STAGEDIR}${PREFIX}/bin/gdbtui${VER}
do-install-GDB_LINK-on:
${LN} -sf gdb${VER} ${STAGEDIR}${PREFIX}/bin/gdb
+.if ${PORT_OPTIONS:MKGDB}
+ ${LN} -sf kgdb${VER} ${STAGEDIR}${PREFIX}/bin/kgdb
+.endif
do-install-PYTHON-on:
(cd ${WRKSRC}/gdb; ${SETENV} ${MAKE_ENV} ${MAKE_CMD} ${MAKE_ARGS} install-python )
diff --git a/devel/gdb/files/extrapatch-kgdb b/devel/gdb/files/extrapatch-kgdb
new file mode 100644
index 000000000000..93621d0c6dcd
--- /dev/null
+++ b/devel/gdb/files/extrapatch-kgdb
@@ -0,0 +1,226 @@
+diff --git gdb/Makefile.in gdb/Makefile.in
+index dfaa8a3..182d875 100644
+--- gdb/Makefile.in
++++ gdb/Makefile.in
+@@ -650,7 +650,8 @@ ALL_64_TARGET_OBS = \
+ ia64-linux-tdep.o ia64-vms-tdep.o ia64-tdep.o \
+ mips64obsd-tdep.o \
+ sparc64fbsd-tdep.o sparc64-linux-tdep.o sparc64nbsd-tdep.o \
+- sparc64obsd-tdep.o sparc64-sol2-tdep.o sparc64-tdep.o
++ sparc64obsd-tdep.o sparc64-sol2-tdep.o sparc64-tdep.o \
++ amd64fbsd-kern.o sparc64fbsd-kern.o
+
+ # All other target-dependent objects files (used with --enable-targets=all).
+ ALL_TARGET_OBS = \
+@@ -672,6 +673,7 @@ ALL_TARGET_OBS = \
+ i386-sol2-tdep.o i386-tdep.o i387-tdep.o \
+ i386-dicos-tdep.o i386-darwin-tdep.o \
+ iq2000-tdep.o \
++ fbsd-kld.o fbsd-kthr.o fbsd-kvm.o i386fbsd-kern.o ppcfbsd-kern.o \
+ linux-tdep.o \
+ lm32-tdep.o \
+ m32c-tdep.o \
+@@ -1123,7 +1125,7 @@ generated_files = config.h observer.h observer.inc ada-lex.c jit-reader.h \
+ $(COMPILE) $<
+ $(POSTCOMPILE)
+
+-all: gdb$(EXEEXT) $(CONFIG_ALL)
++all: gdb$(EXEEXT) kgdb$(EXEEXT) $(CONFIG_ALL)
+ @$(MAKE) $(FLAGS_TO_PASS) DO=all "DODIRS=`echo $(SUBDIRS) | sed 's/testsuite//'`" subdir_do
+
+ installcheck:
+@@ -1393,6 +1395,12 @@ gdb$(EXEEXT): gdb.o $(LIBGDB_OBS) $(ADD_DEPS) $(CDEPS) $(TDEPLIBS)
+ -o gdb$(EXEEXT) gdb.o $(LIBGDB_OBS) \
+ $(TDEPLIBS) $(TUI_LIBRARY) $(CLIBS) $(LOADLIBES)
+
++kgdb$(EXEEXT): kgdb-main.o $(LIBGDB_OBS) $(ADD_DEPS) $(CDEPS) $(TDEPLIBS)
++ rm -f kgdb$(EXEEXT)
++ $(CC_LD) $(INTERNAL_LDFLAGS) $(WIN32LDAPP) \
++ -o kgdb$(EXEEXT) kgdb-main.o $(LIBGDB_OBS) \
++ $(TDEPLIBS) $(TUI_LIBRARY) $(CLIBS) $(LOADLIBES)
++
+ # Convenience rule to handle recursion.
+ $(LIBGNU) $(GNULIB_H): all-lib
+ all-lib: $(GNULIB_BUILDDIR)/Makefile
+@@ -1437,7 +1445,7 @@ clean mostlyclean: $(CONFIG_CLEAN)
+ @$(MAKE) $(FLAGS_TO_PASS) DO=clean "DODIRS=$(CLEANDIRS)" subdir_do
+ rm -f *.o *.a $(ADD_FILES) *~ init.c-tmp init.l-tmp version.c-tmp
+ rm -f init.c version.c observer.h observer.inc
+- rm -f gdb$(EXEEXT) core make.log
++ rm -f gdb$(EXEEXT) core make.log kgdb$(EXEEXT)
+ rm -f gdb[0-9]$(EXEEXT)
+ rm -f test-cp-name-parser$(EXEEXT)
+ rm -f xml-builtin.c stamp-xml
+@@ -1667,6 +1675,9 @@ ALLDEPFILES = \
+ core-regset.c \
+ dcache.c dicos-tdep.c darwin-nat.c \
+ exec.c \
++ fbsd-kld.c fbsd-kthr.c fbsd-kvm.c \
++ amd64fbsd-kern.c i386fbsd-kern.c ppcfbsd-kern.c \
++ sparc64fbsd-kern.c \
+ fbsd-nat.c \
+ fbsd-tdep.c \
+ fork-child.c \
+diff --git gdb/config.in gdb/config.in
+index 9ef53b3..c55c01b 100644
+--- gdb/config.in
++++ gdb/config.in
+@@ -216,6 +216,9 @@
+ /* Define to 1 if your system has the kinfo_getvmmap function. */
+ #undef HAVE_KINFO_GETVMMAP
+
++/* Define to 1 if your system has the kvm_open2 function. */
++#undef HAVE_KVM_OPEN2
++
+ /* Define if you have <langinfo.h> and nl_langinfo(CODESET). */
+ #undef HAVE_LANGINFO_CODESET
+
+diff --git gdb/configure gdb/configure
+index 48acfe5..f0cd958 100755
+--- gdb/configure
++++ gdb/configure
+@@ -7104,6 +7104,66 @@ $as_echo "#define HAVE_KINFO_GETVMMAP 1" >>confdefs.h
+ fi
+
+
++# kgdb needs kvm_open2 for cross-debugging
++{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for library containing kvm_open2" >&5
++$as_echo_n "checking for library containing kvm_open2... " >&6; }
++if test "${ac_cv_search_kvm_open2+set}" = set; then :
++ $as_echo_n "(cached) " >&6
++else
++ ac_func_search_save_LIBS=$LIBS
++cat confdefs.h - <<_ACEOF >conftest.$ac_ext
++/* end confdefs.h. */
++
++/* Override any GCC internal prototype to avoid an error.
++ Use char because int might match the return type of a GCC
++ builtin and then its argument prototype would still apply. */
++#ifdef __cplusplus
++extern "C"
++#endif
++char kvm_open2 ();
++int
++main ()
++{
++return kvm_open2 ();
++ ;
++ return 0;
++}
++_ACEOF
++for ac_lib in '' kvm; do
++ if test -z "$ac_lib"; then
++ ac_res="none required"
++ else
++ ac_res=-l$ac_lib
++ LIBS="-l$ac_lib $ac_func_search_save_LIBS"
++ fi
++ if ac_fn_c_try_link "$LINENO"; then :
++ ac_cv_search_kvm_open2=$ac_res
++fi
++rm -f core conftest.err conftest.$ac_objext \
++ conftest$ac_exeext
++ if test "${ac_cv_search_kvm_open2+set}" = set; then :
++ break
++fi
++done
++if test "${ac_cv_search_kvm_open2+set}" = set; then :
++
++else
++ ac_cv_search_kvm_open2=no
++fi
++rm conftest.$ac_ext
++LIBS=$ac_func_search_save_LIBS
++fi
++{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_search_kvm_open2" >&5
++$as_echo "$ac_cv_search_kvm_open2" >&6; }
++ac_res=$ac_cv_search_kvm_open2
++if test "$ac_res" != no; then :
++ test "$ac_res" = "none required" || LIBS="$ac_res $LIBS"
++
++$as_echo "#define HAVE_KVM_OPEN2 1" >>confdefs.h
++
++fi
++
++
+
+
+
+diff --git gdb/configure.ac gdb/configure.ac
+index a40860a..9035d48 100644
+--- gdb/configure.ac
++++ gdb/configure.ac
+@@ -539,6 +539,11 @@ AC_SEARCH_LIBS(kinfo_getvmmap, util,
+ [AC_DEFINE(HAVE_KINFO_GETVMMAP, 1,
+ [Define to 1 if your system has the kinfo_getvmmap function. ])])
+
++# kgdb needs kvm_open2 for cross-debugging
++AC_SEARCH_LIBS(kvm_open2, kvm,
++ [AC_DEFINE(HAVE_KVM_OPEN2, 1,
++ [Define to 1 if your system has the kvm_open2 function. ])])
++
+ AM_ICONV
+
+ # GDB may fork/exec the iconv program to get the list of supported character
+diff --git gdb/defs.h gdb/defs.h
+index ccdab18..499944f 100644
+--- gdb/defs.h
++++ gdb/defs.h
+@@ -549,6 +549,7 @@ enum gdb_osabi
+ GDB_OSABI_LINUX,
+ GDB_OSABI_FREEBSD_AOUT,
+ GDB_OSABI_FREEBSD_ELF,
++ GDB_OSABI_FREEBSD_ELF_KERNEL,
+ GDB_OSABI_NETBSD_AOUT,
+ GDB_OSABI_NETBSD_ELF,
+ GDB_OSABI_OPENBSD_ELF,
+diff --git gdb/osabi.c gdb/osabi.c
+index 3581eb3..d12656e 100644
+--- gdb/osabi.c
++++ gdb/osabi.c
+@@ -66,6 +66,7 @@ static const struct osabi_names gdb_osabi_names[] =
+ { "GNU/Linux", "linux(-gnu)?" },
+ { "FreeBSD a.out", NULL },
+ { "FreeBSD ELF", NULL },
++ { "FreeBSD ELF kernel", NULL },
+ { "NetBSD a.out", NULL },
+ { "NetBSD ELF", NULL },
+ { "OpenBSD ELF", NULL },
+diff --git gdb/regcache.c gdb/regcache.c
+index 86e648a..26a0fd5 100644
+--- gdb/regcache.c
++++ gdb/regcache.c
+@@ -1065,6 +1065,20 @@ regcache_raw_supply (struct regcache *regcache, int regnum, const void *buf)
+ }
+ }
+
++void
++regcache_raw_supply_unsigned (struct regcache *regcache, int regnum,
++ ULONGEST val)
++{
++ void *buf;
++
++ gdb_assert (regcache != NULL);
++ gdb_assert (regnum >=0 && regnum < regcache->descr->nr_raw_registers);
++ buf = alloca (regcache->descr->sizeof_register[regnum]);
++ store_unsigned_integer (buf, regcache->descr->sizeof_register[regnum],
++ gdbarch_byte_order (regcache->descr->gdbarch), val);
++ regcache_raw_supply (regcache, regnum, buf);
++}
++
+ /* Collect register REGNUM from REGCACHE and store its contents in BUF. */
+
+ void
+diff --git gdb/regcache.h gdb/regcache.h
+index a9fb44b..a156918 100644
+--- gdb/regcache.h
++++ gdb/regcache.h
+@@ -147,6 +147,8 @@ extern void regcache_write_pc (struct regcache *regcache, CORE_ADDR pc);
+
+ extern void regcache_raw_supply (struct regcache *regcache,
+ int regnum, const void *buf);
++extern void regcache_raw_supply_unsigned (struct regcache *regcache,
++ int regnum, ULONGEST val);
+ extern void regcache_raw_collect (const struct regcache *regcache,
+ int regnum, void *buf);
+
diff --git a/devel/gdb/files/extrapatch-kgdb-configure.tgt-plain b/devel/gdb/files/extrapatch-kgdb-configure.tgt-plain
new file mode 100644
index 000000000000..72d1ac657419
--- /dev/null
+++ b/devel/gdb/files/extrapatch-kgdb-configure.tgt-plain
@@ -0,0 +1,50 @@
+diff --git gdb/configure.tgt gdb/configure.tgt
+index 4e4d6a9..57e4b3a 100644
+--- gdb/configure.tgt
++++ gdb/configure.tgt
+@@ -185,7 +185,13 @@ i[34567]86-*-dicos*)
+ i[34567]86-*-freebsd* | i[34567]86-*-kfreebsd*-gnu)
+ # Target: FreeBSD/i386
+ gdb_target_obs="i386-tdep.o i387-tdep.o i386bsd-tdep.o i386fbsd-tdep.o \
+- bsd-uthread.o fbsd-tdep.o solib-svr4.o"
++ bsd-uthread.o fbsd-tdep.o solib-svr4.o \
++ fbsd-kld.o fbsd-kthr.o fbsd-kvm.o i386fbsd-kern.o"
++ if test "x$enable_64_bit_bfd" = "xyes"; then
++ # Target: FreeBSD amd64
++ gdb_target_obs="amd64-tdep.o amd64fbsd-tdep.o amd64fbsd-kern.o \
++ ${gdb_target_obs}"
++ fi
+ ;;
+ i[34567]86-*-netbsd* | i[34567]86-*-knetbsd*-gnu)
+ # Target: NetBSD/i386
+@@ -405,7 +411,8 @@ powerpc*-*-freebsd*)
+ # Target: FreeBSD/powerpc
+ gdb_target_obs="rs6000-tdep.o ppc-sysv-tdep.o ppc64-tdep.o \
+ ppcfbsd-tdep.o fbsd-tdep.o solib-svr4.o \
+- ravenscar-thread.o ppc-ravenscar-thread.o"
++ ravenscar-thread.o ppc-ravenscar-thread.o \
++ fbsd-kld.o fbsd-kthr.o fbsd-kvm.o ppcfbsd-kern.o"
+ ;;
+
+ powerpc-*-netbsd* | powerpc-*-knetbsd*-gnu)
+@@ -534,7 +541,8 @@ sparc*-*-freebsd* | sparc*-*-kfreebsd*-gnu)
+ # Target: FreeBSD/sparc64
+ gdb_target_obs="sparc-tdep.o sparc64-tdep.o sparc64fbsd-tdep.o \
+ fbsd-tdep.o solib-svr4.o \
+- ravenscar-thread.o sparc-ravenscar-thread.o"
++ ravenscar-thread.o sparc-ravenscar-thread.o \
++ fbsd-kld.o fbsd-kthr.o fbsd-kvm.o sparc64fbsd-kern.o"
+ ;;
+ sparc-*-netbsd* | sparc-*-knetbsd*-gnu)
+ # Target: NetBSD/sparc
+@@ -662,7 +670,9 @@ x86_64-*-freebsd* | x86_64-*-kfreebsd*-gnu)
+ # Target: FreeBSD/amd64
+ gdb_target_obs="amd64-tdep.o amd64fbsd-tdep.o i386-tdep.o \
+ i387-tdep.o i386bsd-tdep.o i386fbsd-tdep.o \
+- bsd-uthread.o fbsd-tdep.o solib-svr4.o"
++ bsd-uthread.o fbsd-tdep.o solib-svr4.o \
++ fbsd-kld.o fbsd-kthr.o fbsd-kvm.o amd64fbsd-kern.o \
++ i386fbsd-kern.o"
+ ;;
+ x86_64-*-mingw* | x86_64-*-cygwin*)
+ # Target: MingW/amd64
diff --git a/devel/gdb/files/extrapatch-kgdb-configure.tgt-threads b/devel/gdb/files/extrapatch-kgdb-configure.tgt-threads
new file mode 100644
index 000000000000..f0f541889a1a
--- /dev/null
+++ b/devel/gdb/files/extrapatch-kgdb-configure.tgt-threads
@@ -0,0 +1,50 @@
+diff --git gdb/configure.tgt gdb/configure.tgt
+index 4e4d6a9..57e4b3a 100644
+--- gdb/configure.tgt
++++ gdb/configure.tgt
+@@ -185,7 +185,13 @@ i[34567]86-*-dicos*)
+ i[34567]86-*-freebsd* | i[34567]86-*-kfreebsd*-gnu)
+ # Target: FreeBSD/i386
+ gdb_target_obs="i386-tdep.o i387-tdep.o i386bsd-tdep.o i386fbsd-tdep.o \
+- fbsd-threads.o fbsd-tdep.o solib-svr4.o"
++ fbsd-threads.o fbsd-tdep.o solib-svr4.o \
++ fbsd-kld.o fbsd-kthr.o fbsd-kvm.o i386fbsd-kern.o"
++ if test "x$enable_64_bit_bfd" = "xyes"; then
++ # Target: FreeBSD amd64
++ gdb_target_obs="amd64-tdep.o amd64fbsd-tdep.o amd64fbsd-kern.o \
++ ${gdb_target_obs}"
++ fi
+ ;;
+ i[34567]86-*-netbsd* | i[34567]86-*-knetbsd*-gnu)
+ # Target: NetBSD/i386
+@@ -405,7 +411,8 @@ powerpc*-*-freebsd*)
+ # Target: FreeBSD/powerpc
+ gdb_target_obs="rs6000-tdep.o ppc-sysv-tdep.o ppc64-tdep.o \
+ ppcfbsd-tdep.o fbsd-threads.o fbsd-tdep.o solib-svr4.o \
+- ravenscar-thread.o ppc-ravenscar-thread.o"
++ ravenscar-thread.o ppc-ravenscar-thread.o \
++ fbsd-kld.o fbsd-kthr.o fbsd-kvm.o ppcfbsd-kern.o"
+ ;;
+
+ powerpc-*-netbsd* | powerpc-*-knetbsd*-gnu)
+@@ -534,7 +541,8 @@ sparc*-*-freebsd* | sparc*-*-kfreebsd*-gnu)
+ # Target: FreeBSD/sparc64
+ gdb_target_obs="sparc-tdep.o sparc64-tdep.o sparc64fbsd-tdep.o \
+ fbsd-tdep.o solib-svr4.o \
+- ravenscar-thread.o sparc-ravenscar-thread.o"
++ ravenscar-thread.o sparc-ravenscar-thread.o \
++ fbsd-kld.o fbsd-kthr.o fbsd-kvm.o sparc64fbsd-kern.o"
+ ;;
+ sparc-*-netbsd* | sparc-*-knetbsd*-gnu)
+ # Target: NetBSD/sparc
+@@ -662,7 +670,9 @@ x86_64-*-freebsd* | x86_64-*-kfreebsd*-gnu)
+ # Target: FreeBSD/amd64
+ gdb_target_obs="amd64-tdep.o amd64fbsd-tdep.o i386-tdep.o \
+ i387-tdep.o i386bsd-tdep.o i386fbsd-tdep.o \
+- fbsd-threads.o fbsd-tdep.o solib-svr4.o"
++ fbsd-threads.o fbsd-tdep.o solib-svr4.o \
++ fbsd-kld.o fbsd-kthr.o fbsd-kvm.o amd64fbsd-kern.o \
++ i386fbsd-kern.o"
+ ;;
+ x86_64-*-mingw* | x86_64-*-cygwin*)
+ # Target: MingW/amd64
diff --git a/devel/gdb/files/kgdb/amd64fbsd-kern.c b/devel/gdb/files/kgdb/amd64fbsd-kern.c
new file mode 100644
index 000000000000..5c9355a555a9
--- /dev/null
+++ b/devel/gdb/files/kgdb/amd64fbsd-kern.c
@@ -0,0 +1,304 @@
+/*
+ * Copyright (c) 2004 Marcel Moolenaar
+ * 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 AUTHORS ``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 AUTHORS 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$");
+
+#include <sys/types.h>
+#ifdef __amd64__
+#include <machine/pcb.h>
+#include <machine/frame.h>
+#endif
+#include <string.h>
+
+#include <defs.h>
+#include <frame-unwind.h>
+#include "gdbcore.h"
+#include "osabi.h"
+#include <regcache.h>
+#include "solib.h"
+#include "stack.h"
+#include "symtab.h"
+#include "trad-frame.h"
+#include <amd64-tdep.h>
+
+#include "kgdb.h"
+
+static const int amd64fbsd_pcb_offset[] = {
+ -1, /* %rax */
+ 6 * 8, /* %rbx */
+ -1, /* %rcx */
+ -1, /* %rdx */
+ -1, /* %rsi */
+ -1, /* %rdi */
+ 4 * 8, /* %rbp */
+ 5 * 8, /* %rsp */
+ -1, /* %r8 ... */
+ -1,
+ -1,
+ -1,
+ 3 * 8,
+ 2 * 8,
+ 1 * 8,
+ 0 * 8, /* ... %r15 */
+ 7 * 8, /* %rip */
+ -1, /* %eflags */
+ -1, /* %cs */
+ -1, /* %ss */
+ -1, /* %ds */
+ -1, /* %es */
+ -1, /* %fs */
+ -1 /* %gs */
+};
+
+#define CODE_SEL (4 << 3)
+#define DATA_SEL (5 << 3)
+
+static void
+amd64fbsd_supply_pcb(struct regcache *regcache, CORE_ADDR pcb_addr)
+{
+ gdb_byte buf[8];
+ int i;
+
+ for (i = 0; i < ARRAY_SIZE (amd64fbsd_pcb_offset); i++)
+ if (amd64fbsd_pcb_offset[i] != -1) {
+ if (target_read_memory(pcb_addr + amd64fbsd_pcb_offset[i], buf,
+ sizeof buf) != 0)
+ continue;
+ regcache_raw_supply(regcache, i, buf);
+ }
+
+ regcache_raw_supply_unsigned(regcache, AMD64_CS_REGNUM, CODE_SEL);
+ regcache_raw_supply_unsigned(regcache, AMD64_SS_REGNUM, DATA_SEL);
+}
+
+static const int amd64fbsd_trapframe_offset[] = {
+ 6 * 8, /* %rax */
+ 7 * 8, /* %rbx */
+ 3 * 8, /* %rcx */
+ 2 * 8, /* %rdx */
+ 1 * 8, /* %rsi */
+ 0 * 8, /* %rdi */
+ 8 * 8, /* %rbp */
+ 22 * 8, /* %rsp */
+ 4 * 8, /* %r8 ... */
+ 5 * 8,
+ 9 * 8,
+ 10 * 8,
+ 11 * 8,
+ 12 * 8,
+ 13 * 8,
+ 14 * 8, /* ... %r15 */
+ 19 * 8, /* %rip */
+ 21 * 8, /* %eflags */
+ 20 * 8, /* %cs */
+ 23 * 8, /* %ss */
+ -1, /* %ds */
+ -1, /* %es */
+ -1, /* %fs */
+ -1 /* %gs */
+};
+
+#define TRAPFRAME_SIZE 192
+
+static struct trad_frame_cache *
+amd64fbsd_trapframe_cache (struct frame_info *this_frame, void **this_cache)
+{
+ struct gdbarch *gdbarch = get_frame_arch (this_frame);
+ enum bfd_endian byte_order = gdbarch_byte_order (gdbarch);
+ struct trad_frame_cache *cache;
+ CORE_ADDR addr, func, pc, sp;
+ const char *name;
+ int i;
+
+ if (*this_cache != NULL)
+ return (*this_cache);
+
+ cache = trad_frame_cache_zalloc (this_frame);
+ *this_cache = cache;
+
+ func = get_frame_func (this_frame);
+ sp = get_frame_register_unsigned (this_frame, AMD64_RSP_REGNUM);
+
+ find_pc_partial_function (func, &name, NULL, NULL);
+ if (strcmp(name, "fork_trampoline") == 0 && get_frame_pc (this_frame) == func)
+ {
+ /* fork_exit hasn't been called (kthread has never run), so %rsp
+ in the pcb points to the trapframe. GDB has auto-adjusted
+ %rsp for this frame to account for the "call" into
+ fork_trampoline, so "undo" the adjustment. */
+ sp += 8;
+ }
+
+ for (i = 0; i < ARRAY_SIZE (amd64fbsd_trapframe_offset); i++)
+ if (amd64fbsd_trapframe_offset[i] != -1)
+ trad_frame_set_reg_addr (cache, i, sp + amd64fbsd_trapframe_offset[i]);
+
+ /* Read %rip from trap frame. */
+ addr = sp + amd64fbsd_trapframe_offset[AMD64_RIP_REGNUM];
+ pc = read_memory_unsigned_integer (addr, 8, byte_order);
+
+ if (pc == 0 && strcmp(name, "fork_trampoline") == 0)
+ {
+ /* Initial frame of a kthread; terminate backtrace. */
+ trad_frame_set_id (cache, outer_frame_id);
+ }
+ else
+ {
+ /* Construct the frame ID using the function start. */
+ trad_frame_set_id (cache, frame_id_build (sp + TRAPFRAME_SIZE, func));
+ }
+
+ return cache;
+}
+
+static void
+amd64fbsd_trapframe_this_id (struct frame_info *this_frame,
+ void **this_cache, struct frame_id *this_id)
+{
+ struct trad_frame_cache *cache =
+ amd64fbsd_trapframe_cache (this_frame, this_cache);
+
+ trad_frame_get_id (cache, this_id);
+}
+
+static struct value *
+amd64fbsd_trapframe_prev_register (struct frame_info *this_frame,
+ void **this_cache, int regnum)
+{
+ struct trad_frame_cache *cache =
+ amd64fbsd_trapframe_cache (this_frame, this_cache);
+
+ return trad_frame_get_register (cache, this_frame, regnum);
+}
+
+static int
+amd64fbsd_trapframe_sniffer (const struct frame_unwind *self,
+ struct frame_info *this_frame,
+ void **this_prologue_cache)
+{
+ const char *name;
+
+ find_pc_partial_function (get_frame_func (this_frame), &name, NULL, NULL);
+ return (name && ((strcmp (name, "calltrap") == 0)
+ || (strcmp (name, "fork_trampoline") == 0)
+ || (strcmp (name, "nmi_calltrap") == 0)
+ || (name[0] == 'X' && name[1] != '_')));
+}
+
+static const struct frame_unwind amd64fbsd_trapframe_unwind = {
+ NORMAL_FRAME,
+ default_frame_unwind_stop_reason,
+ amd64fbsd_trapframe_this_id,
+ amd64fbsd_trapframe_prev_register,
+ NULL,
+ amd64fbsd_trapframe_sniffer
+};
+
+static void
+amd64fbsd_kernel_init_abi(struct gdbarch_info info, struct gdbarch *gdbarch)
+{
+
+ amd64_init_abi(info, gdbarch);
+
+ frame_unwind_prepend_unwinder(gdbarch, &amd64fbsd_trapframe_unwind);
+
+ set_solib_ops(gdbarch, &kld_so_ops);
+
+ fbsd_vmcore_set_supply_pcb(gdbarch, amd64fbsd_supply_pcb);
+ fbsd_vmcore_set_cpu_pcb_addr(gdbarch, kgdb_trgt_stop_pcb);
+}
+
+void _initialize_amd64_kgdb_tdep(void);
+
+void
+_initialize_amd64_kgdb_tdep(void)
+{
+ gdbarch_register_osabi (bfd_arch_i386, bfd_mach_x86_64,
+ GDB_OSABI_FREEBSD_ELF_KERNEL, amd64fbsd_kernel_init_abi);
+
+#ifdef __amd64__
+ gdb_assert(offsetof(struct pcb, pcb_rbx)
+ == amd64fbsd_pcb_offset[AMD64_RBX_REGNUM]);
+ gdb_assert(offsetof(struct pcb, pcb_rbp)
+ == amd64fbsd_pcb_offset[AMD64_RBP_REGNUM]);
+ gdb_assert(offsetof(struct pcb, pcb_rsp)
+ == amd64fbsd_pcb_offset[AMD64_RSP_REGNUM]);
+ gdb_assert(offsetof(struct pcb, pcb_r12)
+ == amd64fbsd_pcb_offset[AMD64_R12_REGNUM]);
+ gdb_assert(offsetof(struct pcb, pcb_r13)
+ == amd64fbsd_pcb_offset[AMD64_R13_REGNUM]);
+ gdb_assert(offsetof(struct pcb, pcb_r14)
+ == amd64fbsd_pcb_offset[AMD64_R14_REGNUM]);
+ gdb_assert(offsetof(struct pcb, pcb_r15)
+ == amd64fbsd_pcb_offset[AMD64_R15_REGNUM]);
+ gdb_assert(offsetof(struct pcb, pcb_rip)
+ == amd64fbsd_pcb_offset[AMD64_RIP_REGNUM]);
+ gdb_assert(CODE_SEL == GSEL(GCODE_SEL, SEL_KPL));
+ gdb_assert(DATA_SEL == GSEL(GDATA_SEL, SEL_KPL));
+ gdb_assert(sizeof(struct trapframe) == TRAPFRAME_SIZE);
+ gdb_assert(offsetof(struct trapframe, tf_rax)
+ == amd64fbsd_trapframe_offset[AMD64_RAX_REGNUM]);
+ gdb_assert(offsetof(struct trapframe, tf_rbx)
+ == amd64fbsd_trapframe_offset[AMD64_RBX_REGNUM]);
+ gdb_assert(offsetof(struct trapframe, tf_rcx)
+ == amd64fbsd_trapframe_offset[AMD64_RCX_REGNUM]);
+ gdb_assert(offsetof(struct trapframe, tf_rdx)
+ == amd64fbsd_trapframe_offset[AMD64_RDX_REGNUM]);
+ gdb_assert(offsetof(struct trapframe, tf_rsi)
+ == amd64fbsd_trapframe_offset[AMD64_RSI_REGNUM]);
+ gdb_assert(offsetof(struct trapframe, tf_rdi)
+ == amd64fbsd_trapframe_offset[AMD64_RDI_REGNUM]);
+ gdb_assert(offsetof(struct trapframe, tf_rbp)
+ == amd64fbsd_trapframe_offset[AMD64_RBP_REGNUM]);
+ gdb_assert(offsetof(struct trapframe, tf_rsp)
+ == amd64fbsd_trapframe_offset[AMD64_RSP_REGNUM]);
+ gdb_assert(offsetof(struct trapframe, tf_r8)
+ == amd64fbsd_trapframe_offset[AMD64_R8_REGNUM]);
+ gdb_assert(offsetof(struct trapframe, tf_r9)
+ == amd64fbsd_trapframe_offset[AMD64_R9_REGNUM]);
+ gdb_assert(offsetof(struct trapframe, tf_r10)
+ == amd64fbsd_trapframe_offset[AMD64_R10_REGNUM]);
+ gdb_assert(offsetof(struct trapframe, tf_r11)
+ == amd64fbsd_trapframe_offset[AMD64_R11_REGNUM]);
+ gdb_assert(offsetof(struct trapframe, tf_r12)
+ == amd64fbsd_trapframe_offset[AMD64_R12_REGNUM]);
+ gdb_assert(offsetof(struct trapframe, tf_r13)
+ == amd64fbsd_trapframe_offset[AMD64_R13_REGNUM]);
+ gdb_assert(offsetof(struct trapframe, tf_r14)
+ == amd64fbsd_trapframe_offset[AMD64_R14_REGNUM]);
+ gdb_assert(offsetof(struct trapframe, tf_r15)
+ == amd64fbsd_trapframe_offset[AMD64_R15_REGNUM]);
+ gdb_assert(offsetof(struct trapframe, tf_rip)
+ == amd64fbsd_trapframe_offset[AMD64_RIP_REGNUM]);
+ gdb_assert(offsetof(struct trapframe, tf_rflags)
+ == amd64fbsd_trapframe_offset[AMD64_EFLAGS_REGNUM]);
+ gdb_assert(offsetof(struct trapframe, tf_cs)
+ == amd64fbsd_trapframe_offset[AMD64_CS_REGNUM]);
+ gdb_assert(offsetof(struct trapframe, tf_ss)
+ == amd64fbsd_trapframe_offset[AMD64_SS_REGNUM]);
+#endif
+}
diff --git a/devel/gdb/files/kgdb/fbsd-kld.c b/devel/gdb/files/kgdb/fbsd-kld.c
new file mode 100644
index 000000000000..f5c1a3c52f1c
--- /dev/null
+++ b/devel/gdb/files/kgdb/fbsd-kld.c
@@ -0,0 +1,591 @@
+/*
+ * Copyright (c) 2004 Marcel Moolenaar
+ * 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 ``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 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$");
+
+#include <sys/param.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+#include <libgen.h>
+
+#include <defs.h>
+#include <command.h>
+#include <completer.h>
+#include <environ.h>
+#include <exec.h>
+#include <frame-unwind.h>
+#include <inferior.h>
+#include <objfiles.h>
+#include <gdbcore.h>
+#include <language.h>
+#include "solib.h"
+#include <solist.h>
+
+#include "kgdb.h"
+
+struct lm_info {
+ CORE_ADDR base_address;
+};
+
+struct kld_info {
+ /* Offsets of fields in linker_file structure. */
+ CORE_ADDR off_address, off_filename, off_pathname, off_next;
+
+ /* KVA of 'linker_path' which corresponds to the kern.module_path sysctl .*/
+ CORE_ADDR module_path_addr;
+ CORE_ADDR linker_files_addr;
+ CORE_ADDR kernel_file_addr;
+};
+
+struct target_so_ops kld_so_ops;
+
+/* Per-program-space data key. */
+static const struct program_space_data *kld_pspace_data;
+
+static void
+kld_pspace_data_cleanup (struct program_space *pspace, void *arg)
+{
+ struct kld_info *info = arg;
+
+ xfree (info);
+}
+
+/* Get the current kld data. If none is found yet, add it now. This
+ function always returns a valid object. */
+
+static struct kld_info *
+get_kld_info (void)
+{
+ struct kld_info *info;
+
+ info = program_space_data (current_program_space, kld_pspace_data);
+ if (info != NULL)
+ return info;
+
+ info = XCNEW (struct kld_info);
+ set_program_space_data (current_program_space, kld_pspace_data, info);
+ return info;
+}
+
+static int
+kld_ok (char *path)
+{
+ struct stat sb;
+
+ if (stat(path, &sb) == 0 && S_ISREG(sb.st_mode))
+ return (1);
+ return (0);
+}
+
+/*
+ * Look for a matching file checking for debug suffixes before the raw file:
+ * - filename + ".debug" (e.g. foo.ko.debug)
+ * - filename (e.g. foo.ko)
+ */
+static const char *kld_suffixes[] = {
+ ".debug",
+ ".symbols",
+ "",
+ NULL
+};
+
+static int
+check_kld_path (char *path, size_t path_size)
+{
+ const char **suffix;
+ char *ep;
+
+ ep = path + strlen(path);
+ suffix = kld_suffixes;
+ while (*suffix != NULL) {
+ if (strlcat(path, *suffix, path_size) < path_size) {
+ if (kld_ok(path))
+ return (1);
+ }
+
+ /* Restore original path to remove suffix. */
+ *ep = '\0';
+ suffix++;
+ }
+ return (0);
+}
+
+/*
+ * Try to find the path for a kld by looking in the kernel's directory and
+ * in the various paths in the module path.
+ */
+static int
+find_kld_path (char *filename, char *path, size_t path_size)
+{
+ struct kld_info *info;
+ struct cleanup *cleanup;
+ char *module_path;
+ char *kernel_dir, *module_dir, *cp;
+ int error;
+
+ info = get_kld_info();
+ if (exec_bfd) {
+ kernel_dir = dirname(bfd_get_filename(exec_bfd));
+ if (kernel_dir != NULL) {
+ snprintf(path, path_size, "%s/%s", kernel_dir,
+ filename);
+ if (check_kld_path(path, path_size))
+ return (1);
+ }
+ }
+ if (info->module_path_addr != 0) {
+ target_read_string(info->module_path_addr, &module_path,
+ PATH_MAX, &error);
+ if (error == 0) {
+ cleanup = make_cleanup(xfree, module_path);
+ cp = module_path;
+ while ((module_dir = strsep(&cp, ";")) != NULL) {
+ snprintf(path, path_size, "%s/%s", module_dir,
+ filename);
+ if (check_kld_path(path, path_size)) {
+ do_cleanups(cleanup);
+ return (1);
+ }
+ }
+ do_cleanups(cleanup);
+ }
+ }
+ return (0);
+}
+
+/*
+ * Read a kernel pointer given a KVA in 'address'.
+ */
+static CORE_ADDR
+read_pointer (CORE_ADDR address)
+{
+ struct type *ptr_type;
+ gdb_byte ptr_buf[8];
+ int arch_size;
+
+ arch_size = bfd_get_arch_size (exec_bfd);
+ if (arch_size == -1)
+ return (0);
+ ptr_type = builtin_type (target_gdbarch ())->builtin_data_ptr;
+ if (target_read_memory(address, ptr_buf, arch_size / 8) != 0)
+ return (0);
+ return (extract_typed_address (ptr_buf, ptr_type));
+}
+
+/*
+ * Try to find this kld in the kernel linker's list of linker files.
+ */
+static int
+find_kld_address (char *arg, CORE_ADDR *address)
+{
+ struct kld_info *info;
+ CORE_ADDR kld;
+ char *kld_filename;
+ char *filename;
+ int error;
+
+ info = get_kld_info();
+ if (info->linker_files_addr == 0 || info->off_address == 0 ||
+ info->off_filename == 0 || info->off_next == 0)
+ return (0);
+
+ filename = basename(arg);
+ for (kld = read_pointer(info->linker_files_addr); kld != 0;
+ kld = read_pointer(kld + info->off_next)) {
+ /* Try to read this linker file's filename. */
+ target_read_string(read_pointer(kld + info->off_filename),
+ &kld_filename, PATH_MAX, &error);
+ if (error)
+ continue;
+
+ /* Compare this kld's filename against our passed in name. */
+ if (strcmp(kld_filename, filename) != 0) {
+ xfree(kld_filename);
+ continue;
+ }
+ xfree(kld_filename);
+
+ /*
+ * We found a match, use its address as the base
+ * address if we can read it.
+ */
+ *address = read_pointer(kld + info->off_address);
+ if (*address == 0)
+ return (0);
+ return (1);
+ }
+ return (0);
+}
+
+static void
+adjust_section_address (struct target_section *sec, CORE_ADDR *curr_base)
+{
+ struct bfd_section *asect = sec->the_bfd_section;
+ bfd *abfd = asect->owner;
+
+ if ((abfd->flags & (EXEC_P | DYNAMIC)) != 0) {
+ sec->addr += *curr_base;
+ sec->endaddr += *curr_base;
+ return;
+ }
+
+ *curr_base = align_power(*curr_base,
+ bfd_get_section_alignment(abfd, asect));
+ sec->addr = *curr_base;
+ sec->endaddr = sec->addr + bfd_section_size(abfd, asect);
+ *curr_base = sec->endaddr;
+}
+
+static void
+load_kld (char *path, CORE_ADDR base_addr, int from_tty)
+{
+ struct section_addr_info *sap;
+ struct target_section *sections = NULL, *sections_end = NULL, *s;
+ struct cleanup *cleanup;
+ bfd *bfd;
+ CORE_ADDR curr_addr;
+ int add_flags, i;
+
+ /* Open the kld. */
+ bfd = bfd_openr(path, gnutarget);
+ if (bfd == NULL)
+ error("\"%s\": can't open: %s", path,
+ bfd_errmsg(bfd_get_error()));
+ cleanup = make_cleanup_bfd_unref(bfd);
+
+ if (!bfd_check_format(bfd, bfd_object))
+ error("\%s\": not an object file", path);
+
+ /* Make sure we have a .text section. */
+ if (bfd_get_section_by_name (bfd, ".text") == NULL)
+ error("\"%s\": can't find text section", path);
+
+ /* Build a section table from the bfd and relocate the sections. */
+ if (build_section_table (bfd, &sections, &sections_end))
+ error("\"%s\": can't find file sections", path);
+ make_cleanup(xfree, sections);
+ curr_addr = base_addr;
+ for (s = sections; s < sections_end; s++)
+ adjust_section_address(s, &curr_addr);
+
+ /* Build a section addr info to pass to symbol_file_add(). */
+ sap = build_section_addr_info_from_section_table (sections,
+ sections_end);
+ make_cleanup((make_cleanup_ftype *)free_section_addr_info, sap);
+
+ printf_unfiltered("add symbol table from file \"%s\" at\n", path);
+ for (i = 0; i < sap->num_sections; i++)
+ printf_unfiltered("\t%s_addr = %s\n", sap->other[i].name,
+ paddress(target_gdbarch(), sap->other[i].addr));
+
+ if (from_tty && (!query("%s", "")))
+ error("Not confirmed.");
+
+ add_flags = 0;
+ if (from_tty)
+ add_flags |= SYMFILE_VERBOSE;
+ symbol_file_add(path, add_flags, sap, OBJF_USERLOADED);
+
+ do_cleanups(cleanup);
+}
+
+static void
+kgdb_add_kld_cmd (char *arg, int from_tty)
+{
+ char path[PATH_MAX];
+ CORE_ADDR base_addr;
+
+ if (!exec_bfd)
+ error("No kernel symbol file");
+
+ /* Try to open the raw path to handle absolute paths first. */
+ snprintf(path, sizeof(path), "%s", arg);
+ if (!check_kld_path(path, sizeof(path))) {
+
+ /*
+ * If that didn't work, look in the various possible
+ * paths for the module.
+ */
+ if (!find_kld_path(arg, path, sizeof(path))) {
+ error("Unable to locate kld");
+ return;
+ }
+ }
+
+ if (!find_kld_address(arg, &base_addr)) {
+ error("Unable to find kld in kernel");
+ return;
+ }
+
+ load_kld(path, base_addr, from_tty);
+
+ reinit_frame_cache();
+}
+
+static void
+kld_relocate_section_addresses (struct so_list *so, struct target_section *sec)
+{
+ static CORE_ADDR curr_addr;
+
+ if (sec == so->sections)
+ curr_addr = so->lm_info->base_address;
+
+ adjust_section_address(sec, &curr_addr);
+}
+
+static void
+kld_free_so (struct so_list *so)
+{
+
+ xfree(so->lm_info);
+}
+
+static void
+kld_clear_so (struct so_list *so)
+{
+ if (so->lm_info != NULL)
+ so->lm_info->base_address = 0;
+}
+
+static void
+kld_clear_solib (void)
+{
+ struct kld_info *info;
+
+ info = get_kld_info();
+
+ memset(info, 0, sizeof(*info));
+}
+
+static void
+kld_solib_create_inferior_hook (int from_tty)
+{
+ struct kld_info *info;
+
+ if (!have_partial_symbols())
+ return;
+
+ info = get_kld_info();
+
+ /*
+ * Compute offsets of relevant members in struct linker_file
+ * and the addresses of global variables. Newer kernels
+ * include constants we can use without requiring debug
+ * symbols. If those aren't present, fall back to using
+ * home-grown offsetof() equivalents.
+ */
+ TRY {
+ info->off_address = parse_and_eval_long("kld_off_address");
+ info->off_filename = parse_and_eval_long("kld_off_filename");
+ info->off_pathname = parse_and_eval_long("kld_off_pathname");
+ info->off_next = parse_and_eval_long("kld_off_next");
+ } CATCH(e, RETURN_MASK_ERROR) {
+ TRY {
+ info->off_address = parse_and_eval_address(
+ "&((struct linker_file *)0)->address");
+ info->off_filename = parse_and_eval_address(
+ "&((struct linker_file *)0)->filename");
+ info->off_pathname = parse_and_eval_address(
+ "&((struct linker_file *)0)->pathname");
+ info->off_next = parse_and_eval_address(
+ "&((struct linker_file *)0)->link.tqe_next");
+ } CATCH(e, RETURN_MASK_ERROR) {
+ return;
+ }
+ END_CATCH
+ }
+ END_CATCH
+
+ TRY {
+ info->module_path_addr = parse_and_eval_address("linker_path");
+ info->linker_files_addr = kgdb_lookup("linker_files");
+ info->kernel_file_addr = kgdb_lookup("linker_kernel_file");
+ } CATCH(e, RETURN_MASK_ERROR) {
+ return;
+ }
+ END_CATCH
+
+ solib_add(NULL, 1, &current_target, auto_solib_add);
+}
+
+static void
+kld_special_symbol_handling (void)
+{
+}
+
+static struct so_list *
+kld_current_sos (void)
+{
+ struct so_list *head, **prev, *new;
+ struct kld_info *info;
+ CORE_ADDR kld, kernel;
+ char *path;
+ int error;
+
+ info = get_kld_info();
+ if (info->linker_files_addr == 0 || info->kernel_file_addr == 0 ||
+ info->off_address == 0 || info->off_filename == 0 ||
+ info->off_next == 0)
+ return (NULL);
+
+ head = NULL;
+ prev = &head;
+
+ /*
+ * Walk the list of linker files creating so_list entries for
+ * each non-kernel file.
+ */
+ kernel = read_pointer(info->kernel_file_addr);
+ for (kld = read_pointer(info->linker_files_addr); kld != 0;
+ kld = read_pointer(kld + info->off_next)) {
+ /* Skip the main kernel file. */
+ if (kld == kernel)
+ continue;
+
+ new = xmalloc(sizeof(*new));
+ memset(new, 0, sizeof(*new));
+
+ new->lm_info = xmalloc(sizeof(*new->lm_info));
+ new->lm_info->base_address = 0;
+
+ /* Read the base filename and store it in so_original_name. */
+ target_read_string(read_pointer(kld + info->off_filename),
+ &path, sizeof(new->so_original_name), &error);
+ if (error != 0) {
+ warning("kld_current_sos: Can't read filename: %s\n",
+ safe_strerror(error));
+ free_so(new);
+ continue;
+ }
+ strlcpy(new->so_original_name, path,
+ sizeof(new->so_original_name));
+ xfree(path);
+
+ /*
+ * Try to read the pathname (if it exists) and store
+ * it in so_name.
+ */
+ if (find_kld_path(new->so_original_name, new->so_name,
+ sizeof(new->so_name))) {
+ /* we found the kld */;
+ } else if (info->off_pathname != 0) {
+ target_read_string(read_pointer(kld +
+ info->off_pathname),
+ &path, sizeof(new->so_name), &error);
+ if (error != 0) {
+ warning(
+ "kld_current_sos: Can't read pathname for \"%s\": %s\n",
+ new->so_original_name,
+ safe_strerror(error));
+ strlcpy(new->so_name, new->so_original_name,
+ sizeof(new->so_name));
+ } else {
+ strlcpy(new->so_name, path,
+ sizeof(new->so_name));
+ xfree(path);
+ }
+ } else
+ strlcpy(new->so_name, new->so_original_name,
+ sizeof(new->so_name));
+
+ /* Read this kld's base address. */
+ new->lm_info->base_address = read_pointer(kld +
+ info->off_address);
+ if (new->lm_info->base_address == 0) {
+ warning(
+ "kld_current_sos: Invalid address for kld \"%s\"",
+ new->so_original_name);
+ free_so(new);
+ continue;
+ }
+
+ /* Append to the list. */
+ *prev = new;
+ prev = &new->next;
+ }
+
+ return (head);
+}
+
+static int
+kld_open_symbol_file_object (void *from_ttyp)
+{
+
+ return (0);
+}
+
+static int
+kld_in_dynsym_resolve_code (CORE_ADDR pc)
+{
+
+ return (0);
+}
+
+static int
+kld_find_and_open_solib (char *solib, unsigned o_flags, char **temp_pathname)
+{
+ char path[PATH_MAX];
+ int fd;
+
+ *temp_pathname = NULL;
+ if (!find_kld_path(solib, path, sizeof(path))) {
+ errno = ENOENT;
+ return (-1);
+ }
+ fd = open(path, o_flags, 0);
+ if (fd >= 0)
+ *temp_pathname = xstrdup(path);
+ return (fd);
+}
+
+void _initialize_kld_target(void);
+
+void
+_initialize_kld_target(void)
+{
+ struct cmd_list_element *c;
+
+ kld_so_ops.relocate_section_addresses = kld_relocate_section_addresses;
+ kld_so_ops.free_so = kld_free_so;
+ kld_so_ops.clear_so = kld_clear_so;
+ kld_so_ops.clear_solib = kld_clear_solib;
+ kld_so_ops.solib_create_inferior_hook = kld_solib_create_inferior_hook;
+ kld_so_ops.special_symbol_handling = kld_special_symbol_handling;
+ kld_so_ops.current_sos = kld_current_sos;
+ kld_so_ops.open_symbol_file_object = kld_open_symbol_file_object;
+ kld_so_ops.in_dynsym_resolve_code = kld_in_dynsym_resolve_code;
+ kld_so_ops.bfd_open = solib_bfd_open;
+ kld_so_ops.find_and_open_solib = kld_find_and_open_solib;
+
+ c = add_com("add-kld", class_files, kgdb_add_kld_cmd,
+ "Usage: add-kld FILE\n\
+Load the symbols from the kernel loadable module FILE.");
+ set_cmd_completer(c, filename_completer);
+
+ kld_pspace_data = register_program_space_data_with_cleanup (NULL,
+ kld_pspace_data_cleanup);
+}
diff --git a/devel/gdb/files/kgdb/fbsd-kthr.c b/devel/gdb/files/kgdb/fbsd-kthr.c
new file mode 100644
index 000000000000..d624f49a4c27
--- /dev/null
+++ b/devel/gdb/files/kgdb/fbsd-kthr.c
@@ -0,0 +1,351 @@
+/*
+ * Copyright (c) 2004 Marcel Moolenaar
+ * 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 AUTHORS ``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 AUTHORS 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$");
+
+#include <sys/param.h>
+#include <sys/proc.h>
+#include <stdbool.h>
+
+#include <defs.h>
+#include "gdbcore.h"
+#include "objfiles.h"
+#include "value.h"
+
+#include "kgdb.h"
+
+static CORE_ADDR dumppcb;
+static LONGEST dumptid;
+
+static CORE_ADDR stopped_cpus;
+static LONGEST mp_maxid;
+
+static struct kthr *first;
+struct kthr *curkthr;
+
+static int proc_off_p_pid, proc_off_p_comm, proc_off_p_list, proc_off_p_threads;
+static int thread_off_td_tid, thread_off_td_oncpu, thread_off_td_pcb;
+static int thread_off_td_name, thread_off_td_plist;
+static int thread_oncpu_size;
+
+CORE_ADDR
+kgdb_lookup(const char *sym)
+{
+ struct bound_minimal_symbol msym;
+
+ msym = lookup_minimal_symbol(sym, NULL, NULL);
+ if (msym.minsym == NULL)
+ return (0);
+ return (BMSYMBOL_VALUE_ADDRESS(msym));
+}
+
+/*
+ * Perform the equivalent of CPU_ISSET() to see if 'cpu' is set in the
+ * kernel's stopped_cpus set. The set contains an array of longs.
+ * This function determines the specific long to read and tests the
+ * necessary bit in the long.
+ */
+static bool
+cpu_stopped(int cpu)
+{
+ struct gdbarch *gdbarch = target_gdbarch ();
+ CORE_ADDR addr;
+ ULONGEST mask;
+ int bit, long_bytes, word;
+
+ if (cpu < 0 || cpu > mp_maxid || stopped_cpus == 0)
+ return (false);
+ bit = cpu % gdbarch_long_bit (gdbarch);
+ word = cpu / gdbarch_long_bit (gdbarch);
+ long_bytes = gdbarch_long_bit (gdbarch) / 8;
+ addr = stopped_cpus + word * long_bytes;
+ mask = read_memory_unsigned_integer (addr, long_bytes,
+ gdbarch_byte_order (gdbarch));
+ return (mask & ((ULONGEST)1 << bit)) != 0;
+}
+
+struct kthr *
+kgdb_thr_first(void)
+{
+ return (first);
+}
+
+static void
+kgdb_thr_add_procs(CORE_ADDR paddr, CORE_ADDR (*cpu_pcb_addr) (u_int))
+{
+ struct gdbarch *gdbarch = target_gdbarch ();
+ struct type *ptr_type = builtin_type (gdbarch)->builtin_data_ptr;
+ enum bfd_endian byte_order = gdbarch_byte_order (gdbarch);
+ struct kthr *kt;
+ CORE_ADDR pcb, pnext, tdaddr, tdnext;
+ ULONGEST oncpu;
+ LONGEST pid, tid;
+
+ while (paddr != 0) {
+ TRY {
+ tdaddr = read_memory_typed_address (paddr +
+ proc_off_p_threads, ptr_type);
+ pid = read_memory_integer (paddr + proc_off_p_pid, 4,
+ byte_order);
+ pnext = read_memory_typed_address (paddr +
+ proc_off_p_list, ptr_type);
+ } CATCH(e, RETURN_MASK_ERROR) {
+ break;
+ } END_CATCH
+ while (tdaddr != 0) {
+ TRY {
+ tid = read_memory_integer (tdaddr +
+ thread_off_td_tid, 4, byte_order);
+ oncpu = read_memory_unsigned_integer (tdaddr +
+ thread_off_td_oncpu, thread_oncpu_size,
+ byte_order);
+ pcb = read_memory_typed_address (tdaddr +
+ thread_off_td_pcb, ptr_type);
+ tdnext = read_memory_typed_address (tdaddr +
+ thread_off_td_plist, ptr_type);
+ } CATCH(e, RETURN_MASK_ERROR) {
+ break;
+ } END_CATCH
+ kt = malloc(sizeof(*kt));
+ kt->next = first;
+ kt->kaddr = tdaddr;
+ if (tid == dumptid)
+ kt->pcb = dumppcb;
+ else if (cpu_stopped(oncpu))
+ kt->pcb = cpu_pcb_addr(oncpu);
+ else
+ kt->pcb = pcb;
+ kt->tid = tid;
+ kt->pid = pid;
+ kt->paddr = paddr;
+ kt->cpu = oncpu;
+ first = kt;
+ tdaddr = tdnext;
+ }
+ paddr = pnext;
+ }
+}
+
+struct kthr *
+kgdb_thr_init(CORE_ADDR (*cpu_pcb_addr) (u_int))
+{
+ struct gdbarch *gdbarch = target_gdbarch ();
+ struct type *ptr_type = builtin_type (gdbarch)->builtin_data_ptr;
+ enum bfd_endian byte_order = gdbarch_byte_order (gdbarch);
+ struct kthr *kt;
+ CORE_ADDR addr, paddr;
+
+ while (first != NULL) {
+ kt = first;
+ first = kt->next;
+ free(kt);
+ }
+
+ addr = kgdb_lookup("allproc");
+ if (addr == 0)
+ return (NULL);
+ TRY {
+ paddr = read_memory_typed_address (addr, ptr_type);
+ } CATCH(e, RETURN_MASK_ERROR) {
+ return (NULL);
+ } END_CATCH
+
+ dumppcb = kgdb_lookup("dumppcb");
+ if (dumppcb == 0)
+ return (NULL);
+
+#if 1
+ TRY {
+ dumptid = parse_and_eval_long("dumptid");
+ } CATCH(e, RETURN_MASK_ERROR) {
+ dumptid = -1;
+ } END_CATCH
+#else
+ addr = kgdb_lookup("dumptid");
+ if (addr != 0) {
+ TRY {
+ dumptid = read_memory_integer (addr, 4, byte_order);
+ } CATCH(e, RETURN_MASK_ERROR) {
+ dumptid = -1;
+ } END_CATCH
+ } else
+ dumptid = -1;
+#endif
+
+ TRY {
+ mp_maxid = parse_and_eval_long("mp_maxid");
+ } CATCH(e, RETURN_MASK_ERROR) {
+ mp_maxid = 0;
+ } END_CATCH
+ stopped_cpus = kgdb_lookup("stopped_cpus");
+
+ /*
+ * Newer kernels export a set of global variables with the offsets
+ * of certain members in struct proc and struct thread. For older
+ * kernels, try to extract these offsets using debug symbols. If
+ * that fails, use native values.
+ */
+ TRY {
+ proc_off_p_pid = parse_and_eval_long("proc_off_p_pid");
+ proc_off_p_comm = parse_and_eval_long("proc_off_p_comm");
+ proc_off_p_list = parse_and_eval_long("proc_off_p_list");
+ proc_off_p_threads = parse_and_eval_long("proc_off_p_threads");
+ thread_off_td_tid = parse_and_eval_long("thread_off_td_tid");
+ thread_off_td_name = parse_and_eval_long("thread_off_td_name");
+ thread_off_td_oncpu = parse_and_eval_long("thread_off_td_oncpu");
+ thread_off_td_pcb = parse_and_eval_long("thread_off_td_pcb");
+ thread_off_td_plist = parse_and_eval_long("thread_off_td_plist");
+ thread_oncpu_size = 4;
+ } CATCH(e, RETURN_MASK_ERROR) {
+ TRY {
+ proc_off_p_pid = parse_and_eval_address(
+ "&((struct proc *)0)->p_pid");
+ proc_off_p_comm = parse_and_eval_address(
+ "&((struct proc *)0)->p_comm");
+ proc_off_p_list = parse_and_eval_address(
+ "&((struct proc *)0)->p_list");
+ proc_off_p_threads = parse_and_eval_address(
+ "&((struct proc *)0)->p_threads");
+ thread_off_td_tid = parse_and_eval_address(
+ "&((struct thread *)0)->td_tid");
+ thread_off_td_name = parse_and_eval_address(
+ "&((struct thread *)0)->td_name");
+ thread_off_td_oncpu = parse_and_eval_address(
+ "&((struct thread *)0)->td_oncpu");
+ thread_off_td_pcb = parse_and_eval_address(
+ "&((struct thread *)0)->td_pcb");
+ thread_off_td_plist = parse_and_eval_address(
+ "&((struct thread *)0)->td_plist");
+ thread_oncpu_size = parse_and_eval_long(
+ "sizeof(((struct thread *)0)->td_oncpu)");
+ } CATCH(e, RETURN_MASK_ERROR) {
+ proc_off_p_pid = offsetof(struct proc, p_pid);
+ proc_off_p_comm = offsetof(struct proc, p_comm);
+ proc_off_p_list = offsetof(struct proc, p_list);
+ proc_off_p_threads = offsetof(struct proc, p_threads);
+ thread_off_td_tid = offsetof(struct thread, td_tid);
+ thread_off_td_name = offsetof(struct thread, td_name);
+ thread_off_td_oncpu = offsetof(struct thread, td_oncpu);
+ thread_off_td_pcb = offsetof(struct thread, td_pcb);
+ thread_off_td_plist = offsetof(struct thread, td_plist);
+ thread_oncpu_size =
+ sizeof(((struct thread *)0)->td_oncpu);
+ } END_CATCH
+ } END_CATCH
+
+ kgdb_thr_add_procs(paddr, cpu_pcb_addr);
+ addr = kgdb_lookup("zombproc");
+ if (addr != 0) {
+ TRY {
+ paddr = read_memory_typed_address (addr, ptr_type);
+ kgdb_thr_add_procs(paddr, cpu_pcb_addr);
+ } CATCH(e, RETURN_MASK_ERROR) {
+ } END_CATCH
+ }
+ curkthr = kgdb_thr_lookup_tid(dumptid);
+ if (curkthr == NULL)
+ curkthr = first;
+ return (first);
+}
+
+struct kthr *
+kgdb_thr_lookup_tid(int tid)
+{
+ struct kthr *kt;
+
+ kt = first;
+ while (kt != NULL && kt->tid != tid)
+ kt = kt->next;
+ return (kt);
+}
+
+struct kthr *
+kgdb_thr_lookup_taddr(uintptr_t taddr)
+{
+ struct kthr *kt;
+
+ kt = first;
+ while (kt != NULL && kt->kaddr != taddr)
+ kt = kt->next;
+ return (kt);
+}
+
+struct kthr *
+kgdb_thr_lookup_pid(int pid)
+{
+ struct kthr *kt;
+
+ kt = first;
+ while (kt != NULL && kt->pid != pid)
+ kt = kt->next;
+ return (kt);
+}
+
+struct kthr *
+kgdb_thr_lookup_paddr(uintptr_t paddr)
+{
+ struct kthr *kt;
+
+ kt = first;
+ while (kt != NULL && kt->paddr != paddr)
+ kt = kt->next;
+ return (kt);
+}
+
+struct kthr *
+kgdb_thr_next(struct kthr *kt)
+{
+ return (kt->next);
+}
+
+char *
+kgdb_thr_extra_thread_info(int tid)
+{
+ char comm[MAXCOMLEN + 1];
+ char td_name[MAXCOMLEN + 1];
+ struct kthr *kt;
+ static char buf[64];
+
+ kt = kgdb_thr_lookup_tid(tid);
+ if (kt == NULL)
+ return (NULL);
+ snprintf(buf, sizeof(buf), "PID=%d", kt->pid);
+ TRY {
+ read_memory_string (kt->paddr + proc_off_p_comm, comm,
+ sizeof(comm));
+ strlcat(buf, ": ", sizeof(buf));
+ strlcat(buf, comm, sizeof(buf));
+ read_memory_string (kt->kaddr + thread_off_td_name, td_name,
+ sizeof(td_name));
+ if (strcmp(comm, td_name) != 0) {
+ strlcat(buf, "/", sizeof(buf));
+ strlcat(buf, td_name, sizeof(buf));
+ }
+ } CATCH(e, RETURN_MASK_ERROR) {
+ } END_CATCH
+ return (buf);
+}
diff --git a/devel/gdb/files/kgdb/fbsd-kvm.c b/devel/gdb/files/kgdb/fbsd-kvm.c
new file mode 100644
index 000000000000..1be599b87d0e
--- /dev/null
+++ b/devel/gdb/files/kgdb/fbsd-kvm.c
@@ -0,0 +1,588 @@
+/*
+ * Copyright (c) 2004 Marcel Moolenaar
+ * 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 ``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 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$");
+
+#include <sys/param.h>
+#include <sys/proc.h>
+#include <sys/sysctl.h>
+#include <sys/user.h>
+#include <err.h>
+#include <fcntl.h>
+#include <kvm.h>
+
+#include <defs.h>
+#include <readline/readline.h>
+#include <readline/tilde.h>
+#include <command.h>
+#include "elf-bfd.h"
+#include <exec.h>
+#include "filenames.h"
+#include <frame-unwind.h>
+#include <gdb.h>
+#include <gdbcore.h>
+#include <gdbthread.h>
+#include "gdb_obstack.h"
+#include <inferior.h>
+#include <language.h>
+#include "objfiles.h"
+#include <regcache.h>
+#include <solib.h>
+#include <target.h>
+#include <ui-out.h>
+
+#include "kgdb.h"
+
+static CORE_ADDR stoppcbs;
+static LONGEST pcb_size;
+
+static void kgdb_core_cleanup(void *);
+
+static char *vmcore;
+struct target_ops kgdb_trgt_ops;
+
+/* Per-architecture data key. */
+static struct gdbarch_data *fbsd_vmcore_data;
+
+struct fbsd_vmcore_ops
+{
+ /* Supply registers for a pcb to a register cache. */
+ void (*supply_pcb)(struct regcache *, CORE_ADDR);
+
+ /* Return address of pcb for thread running on a CPU. */
+ CORE_ADDR (*cpu_pcb_addr)(u_int);
+};
+
+static void *
+fbsd_vmcore_init (struct obstack *obstack)
+{
+ struct fbsd_vmcore_ops *ops;
+
+ ops = OBSTACK_ZALLOC (obstack, struct fbsd_vmcore_ops);
+ return ops;
+}
+
+/* Set the function that supplies registers from a pcb
+ for architecture GDBARCH to SUPPLY_PCB. */
+
+void
+fbsd_vmcore_set_supply_pcb (struct gdbarch *gdbarch,
+ void (*supply_pcb) (struct regcache *,
+ CORE_ADDR))
+{
+ struct fbsd_vmcore_ops *ops = gdbarch_data (gdbarch, fbsd_vmcore_data);
+ ops->supply_pcb = supply_pcb;
+}
+
+/* Set the function that returns the address of the pcb for a thread
+ running on a CPU for
+ architecture GDBARCH to CPU_PCB_ADDR. */
+
+void
+fbsd_vmcore_set_cpu_pcb_addr (struct gdbarch *gdbarch,
+ CORE_ADDR (*cpu_pcb_addr) (u_int))
+{
+ struct fbsd_vmcore_ops *ops = gdbarch_data (gdbarch, fbsd_vmcore_data);
+ ops->cpu_pcb_addr = cpu_pcb_addr;
+}
+
+static CORE_ADDR kernstart;
+static kvm_t *kvm;
+static char kvm_err[_POSIX2_LINE_MAX];
+int kgdb_quiet;
+
+static ptid_t
+fbsd_vmcore_ptid(int tid)
+{
+ if (kvm == NULL)
+ /*
+ * The remote target stores the 'tid' in the lwp
+ * field.
+ */
+ return ptid_build(ptid_get_pid(inferior_ptid), tid, 0);
+
+ /*
+ * This follows the model described in bsd-kvm.c except that
+ * in kernel tids are used as the tid of the ptid instead of a
+ * process ID.
+ */
+ return ptid_build(1, 1, tid);
+}
+
+#define MSGBUF_SEQ_TO_POS(size, seq) ((seq) % (size))
+
+static void
+kgdb_dmesg(void)
+{
+ CORE_ADDR bufp;
+ int size, rseq, wseq;
+ gdb_byte c;
+
+ /*
+ * Display the unread portion of the message buffer. This gives the
+ * user a some initial data to work from.
+ */
+ if (kgdb_quiet)
+ return;
+ TRY {
+ bufp = parse_and_eval_address("msgbufp->msg_ptr");
+ size = parse_and_eval_long("msgbufp->msg_size");
+ rseq = parse_and_eval_long("msgbufp->msg_rseq");
+ wseq = parse_and_eval_long("msgbufp->msg_wseq");
+ } CATCH(e, RETURN_MASK_ERROR) {
+ return;
+ } END_CATCH
+ rseq = MSGBUF_SEQ_TO_POS(size, rseq);
+ wseq = MSGBUF_SEQ_TO_POS(size, wseq);
+ if (rseq == wseq)
+ return;
+
+ printf("\nUnread portion of the kernel message buffer:\n");
+ while (rseq < wseq) {
+ read_memory(bufp + rseq, &c, 1);
+ putchar(c);
+ rseq++;
+ if (rseq == size)
+ rseq = 0;
+ }
+ if (c != '\n')
+ putchar('\n');
+ putchar('\n');
+}
+
+#define KERNEL_INTERP "/red/herring"
+
+enum gdb_osabi
+fbsd_kernel_osabi_sniffer(bfd *abfd)
+{
+ asection *s;
+ bfd_byte buf[sizeof(KERNEL_INTERP)];
+ bfd_byte *bufp;
+
+ /* FreeBSD ELF kernels have a FreeBSD/ELF OS ABI. */
+ if (elf_elfheader(abfd)->e_ident[EI_OSABI] != ELFOSABI_FREEBSD)
+ return (GDB_OSABI_UNKNOWN);
+
+ /* FreeBSD ELF kernels have an interpreter path of "/red/herring". */
+ bufp = buf;
+ s = bfd_get_section_by_name(abfd, ".interp");
+ if (s != NULL && bfd_section_size(abfd, s) == sizeof(buf) &&
+ bfd_get_full_section_contents(abfd, s, &bufp) &&
+ memcmp(buf, KERNEL_INTERP, sizeof(buf)) == 0)
+ return (GDB_OSABI_FREEBSD_ELF_KERNEL);
+
+ return (GDB_OSABI_UNKNOWN);
+}
+
+#define INKERNEL(x) ((x) >= kernstart)
+
+#ifdef HAVE_KVM_OPEN2
+static int
+kgdb_resolve_symbol(const char *name, kvaddr_t *kva)
+{
+ struct bound_minimal_symbol ms;
+
+ ms = lookup_minimal_symbol (name, NULL, NULL);
+ if (ms.minsym == NULL)
+ return (1);
+ *kva = BMSYMBOL_VALUE_ADDRESS (ms);
+ return (0);
+}
+#endif
+
+static void
+kgdb_trgt_open(const char *arg, int from_tty)
+{
+ struct fbsd_vmcore_ops *ops = gdbarch_data (target_gdbarch(),
+ fbsd_vmcore_data);
+ struct inferior *inf;
+ struct cleanup *old_chain;
+ struct thread_info *ti;
+ struct kthr *kt;
+ kvm_t *nkvm;
+ char *temp, *kernel, *filename;
+ int ontop;
+
+ if (ops == NULL || ops->supply_pcb == NULL || ops->cpu_pcb_addr == NULL)
+ error ("ABI doesn't support a vmcore target");
+
+ target_preopen (from_tty);
+ kernel = get_exec_file (1);
+ if (kernel == NULL)
+ error ("Can't open a vmcore without a kernel");
+
+ if (arg != NULL) {
+ filename = tilde_expand (arg);
+ if (!IS_ABSOLUTE_PATH (filename)) {
+ temp = concat (current_directory, "/", filename, NULL);
+ xfree(filename);
+ filename = temp;
+ }
+ } else
+ filename = NULL;
+
+ old_chain = make_cleanup (xfree, filename);
+
+#ifdef HAVE_KVM_OPEN2
+ nkvm = kvm_open2(kernel, filename,
+ write_files ? O_RDWR : O_RDONLY, kvm_err, kgdb_resolve_symbol);
+#else
+ nkvm = kvm_openfiles(kernel, filename, NULL,
+ write_files ? O_RDWR : O_RDONLY, kvm_err);
+#endif
+ if (nkvm == NULL)
+ error ("Failed to open vmcore: %s", kvm_err);
+
+ /* Don't free the filename now and close any previous vmcore. */
+ discard_cleanups(old_chain);
+ unpush_target(&kgdb_trgt_ops);
+
+ /*
+ * Determine the first address in KVA. Newer kernels export
+ * VM_MAXUSER_ADDRESS and the first kernel address can be
+ * determined by adding one. Older kernels do not provide a
+ * symbol that is valid on all platforms, but kernbase is close
+ * for most platforms.
+ */
+ TRY {
+ kernstart = parse_and_eval_address("vm_maxuser_address") + 1;
+ } CATCH(e, RETURN_MASK_ERROR) {
+ kernstart = kgdb_lookup("kernbase");
+ } END_CATCH
+
+ /*
+ * Lookup symbols needed for stoppcbs[] handling, but don't
+ * fail if they aren't present.
+ */
+ stoppcbs = kgdb_lookup("stoppcbs");
+ TRY {
+ pcb_size = parse_and_eval_long("pcb_size");
+ } CATCH(e, RETURN_MASK_ERROR) {
+ TRY {
+ pcb_size = parse_and_eval_long("sizeof(struct pcb)");
+ } CATCH(e, RETURN_MASK_ERROR) {
+#ifdef HAVE_KVM_OPEN2
+ if (kvm_native(nkvm))
+ pcb_size = sizeof(struct pcb);
+ else
+ pcb_size = 0;
+#else
+ pcb_size = sizeof(struct pcb);
+#endif
+ } END_CATCH
+ } END_CATCH
+
+ kvm = nkvm;
+ vmcore = filename;
+ old_chain = make_cleanup(kgdb_core_cleanup, NULL);
+
+ push_target (&kgdb_trgt_ops);
+ discard_cleanups (old_chain);
+
+ kgdb_dmesg();
+
+ inf = current_inferior();
+ if (inf->pid == 0) {
+ inferior_appeared(inf, 1);
+ inf->fake_pid_p = 1;
+ }
+ solib_create_inferior_hook(0);
+ init_thread_list();
+ kt = kgdb_thr_init(ops->cpu_pcb_addr);
+ while (kt != NULL) {
+ ti = add_thread_silent(fbsd_vmcore_ptid(kt->tid));
+ kt = kgdb_thr_next(kt);
+ }
+ if (curkthr != 0)
+ inferior_ptid = fbsd_vmcore_ptid(curkthr->tid);
+
+ target_fetch_registers (get_current_regcache (), -1);
+
+ reinit_frame_cache ();
+ print_stack_frame (get_selected_frame (NULL), 0, SRC_AND_LOC, 1);
+}
+
+static void
+kgdb_trgt_close(struct target_ops *self)
+{
+
+ if (kvm != NULL) {
+ clear_solib();
+ if (kvm_close(kvm) != 0)
+ warning("cannot close \"%s\": %s", vmcore,
+ kvm_geterr(kvm));
+ kvm = NULL;
+ xfree(vmcore);
+ vmcore = NULL;
+ }
+
+ inferior_ptid = null_ptid;
+}
+
+static void
+kgdb_core_cleanup(void *arg)
+{
+
+ kgdb_trgt_close(0);
+}
+
+static void
+kgdb_trgt_detach(struct target_ops *ops, const char *args, int from_tty)
+{
+
+ if (args)
+ error ("Too many arguments");
+ unpush_target(&kgdb_trgt_ops);
+ reinit_frame_cache();
+ if (from_tty)
+ printf_filtered("No vmcore file now.\n");
+}
+
+static char *
+kgdb_trgt_extra_thread_info(struct target_ops *ops, struct thread_info *ti)
+{
+
+ return (kgdb_thr_extra_thread_info(ptid_get_tid(ti->ptid)));
+}
+
+static void
+kgdb_trgt_files_info(struct target_ops *target)
+{
+
+ printf_filtered ("\t`%s', ", vmcore);
+ wrap_here (" ");
+ printf_filtered ("file type %s.\n", "FreeBSD kernel vmcore");
+}
+
+static void
+kgdb_trgt_update_thread_list(struct target_ops *ops)
+{
+ /*
+ * XXX: We should probably rescan the thread list here and update
+ * it if there are any changes. One nit though is that we'd have
+ * to detect exited threads.
+ */
+ gdb_assert(kvm != NULL);
+#if 0
+ prune_threads();
+#endif
+#if 0
+ struct target_ops *tb;
+
+ if (kvm != NULL)
+ return;
+
+ tb = find_target_beneath(ops);
+ if (tb->to_update_thread_list != NULL)
+ tb->to_update_thread_list(tb);
+#endif
+}
+
+static char *
+kgdb_trgt_pid_to_str(struct target_ops *ops, ptid_t ptid)
+{
+ static char buf[33];
+
+ snprintf(buf, sizeof(buf), "Thread %ld", ptid_get_tid(ptid));
+ return (buf);
+}
+
+static int
+kgdb_trgt_thread_alive(struct target_ops *ops, ptid_t ptid)
+{
+ return (kgdb_thr_lookup_tid(ptid_get_tid(ptid)) != NULL);
+}
+
+static void
+kgdb_trgt_fetch_registers(struct target_ops *tops,
+ struct regcache *regcache, int regnum)
+{
+ struct fbsd_vmcore_ops *ops = gdbarch_data (target_gdbarch(),
+ fbsd_vmcore_data);
+ struct kthr *kt;
+
+ if (ops->supply_pcb == NULL)
+ return;
+ kt = kgdb_thr_lookup_tid(ptid_get_tid(inferior_ptid));
+ if (kt == NULL)
+ return;
+ ops->supply_pcb(regcache, kt->pcb);
+}
+
+static enum target_xfer_status
+kgdb_trgt_xfer_partial(struct target_ops *ops, enum target_object object,
+ const char *annex, gdb_byte *readbuf,
+ const gdb_byte *writebuf,
+ ULONGEST offset, ULONGEST len, ULONGEST *xfered_len)
+{
+ ssize_t nbytes;
+
+ gdb_assert(kvm != NULL);
+ switch (object) {
+ case TARGET_OBJECT_MEMORY:
+ nbytes = len;
+ if (readbuf != NULL)
+#ifdef HAVE_KVM_OPEN2
+ nbytes = kvm_read2(kvm, offset, readbuf, len);
+#else
+ nbytes = kvm_read(kvm, offset, readbuf, len);
+#endif
+ if (writebuf != NULL && len > 0)
+ nbytes = kvm_write(kvm, offset, writebuf, len);
+ if (nbytes < 0)
+ return TARGET_XFER_E_IO;
+ if (nbytes == 0)
+ return TARGET_XFER_EOF;
+ *xfered_len = nbytes;
+ return TARGET_XFER_OK;
+ default:
+ return TARGET_XFER_E_IO;
+ }
+}
+
+static int
+kgdb_trgt_ignore_breakpoints(struct target_ops *ops, struct gdbarch *gdbarch,
+ struct bp_target_info *bp_tgt)
+{
+
+ return 0;
+}
+
+static void
+kgdb_switch_to_thread(int tid)
+{
+ char buf[16];
+ int thread_id;
+
+ thread_id = pid_to_thread_id(fbsd_vmcore_ptid(tid));
+ if (thread_id == 0)
+ error ("invalid tid");
+ snprintf(buf, sizeof(buf), "%d", thread_id);
+ gdb_thread_select(current_uiout, buf, NULL);
+}
+
+static void
+kgdb_set_proc_cmd (char *arg, int from_tty)
+{
+ CORE_ADDR addr;
+ struct kthr *thr;
+
+ if (!arg)
+ error_no_arg ("proc address for the new context");
+
+ if (kvm == NULL)
+ error ("only supported for core file target");
+
+ addr = parse_and_eval_address (arg);
+
+ if (!INKERNEL (addr)) {
+ thr = kgdb_thr_lookup_pid((int)addr);
+ if (thr == NULL)
+ error ("invalid pid");
+ } else {
+ thr = kgdb_thr_lookup_paddr(addr);
+ if (thr == NULL)
+ error("invalid proc address");
+ }
+ kgdb_switch_to_thread(thr->tid);
+}
+
+static void
+kgdb_set_tid_cmd (char *arg, int from_tty)
+{
+ CORE_ADDR addr;
+ struct kthr *thr;
+
+ if (!arg)
+ error_no_arg ("TID or thread address for the new context");
+
+ addr = (CORE_ADDR) parse_and_eval_address (arg);
+
+ if (kvm != NULL && INKERNEL (addr)) {
+ thr = kgdb_thr_lookup_taddr(addr);
+ if (thr == NULL)
+ error("invalid thread address");
+ addr = thr->tid;
+ }
+ kgdb_switch_to_thread(addr);
+}
+
+static int
+kgdb_trgt_return_one(struct target_ops *ops)
+{
+
+ return 1;
+}
+
+void _initialize_kgdb_target(void);
+
+void
+_initialize_kgdb_target(void)
+{
+
+ kgdb_trgt_ops.to_magic = OPS_MAGIC;
+ kgdb_trgt_ops.to_shortname = "vmcore";
+ kgdb_trgt_ops.to_longname = "kernel core dump file";
+ kgdb_trgt_ops.to_doc =
+ "Use a vmcore file as a target. Specify the filename of the vmcore file.";
+ kgdb_trgt_ops.to_stratum = process_stratum;
+ kgdb_trgt_ops.to_has_memory = kgdb_trgt_return_one;
+ kgdb_trgt_ops.to_has_registers = kgdb_trgt_return_one;
+ kgdb_trgt_ops.to_has_stack = kgdb_trgt_return_one;
+
+ kgdb_trgt_ops.to_open = kgdb_trgt_open;
+ kgdb_trgt_ops.to_close = kgdb_trgt_close;
+ kgdb_trgt_ops.to_detach = kgdb_trgt_detach;
+ kgdb_trgt_ops.to_extra_thread_info = kgdb_trgt_extra_thread_info;
+ kgdb_trgt_ops.to_fetch_registers = kgdb_trgt_fetch_registers;
+ kgdb_trgt_ops.to_files_info = kgdb_trgt_files_info;
+ kgdb_trgt_ops.to_update_thread_list = kgdb_trgt_update_thread_list;
+ kgdb_trgt_ops.to_pid_to_str = kgdb_trgt_pid_to_str;
+ kgdb_trgt_ops.to_thread_alive = kgdb_trgt_thread_alive;
+ kgdb_trgt_ops.to_xfer_partial = kgdb_trgt_xfer_partial;
+ kgdb_trgt_ops.to_insert_breakpoint = kgdb_trgt_ignore_breakpoints;
+ kgdb_trgt_ops.to_remove_breakpoint = kgdb_trgt_ignore_breakpoints;
+
+ add_target(&kgdb_trgt_ops);
+
+ fbsd_vmcore_data = gdbarch_data_register_pre_init(fbsd_vmcore_init);
+
+ add_com ("proc", class_obscure, kgdb_set_proc_cmd,
+ "Set current process context");
+ add_com ("tid", class_obscure, kgdb_set_tid_cmd,
+ "Set current thread context");
+}
+
+CORE_ADDR
+kgdb_trgt_stop_pcb(u_int cpuid)
+{
+
+ if (stoppcbs == 0 || pcb_size == 0)
+ return 0;
+
+ return (stoppcbs + pcb_size * cpuid);
+}
diff --git a/devel/gdb/files/kgdb/i386fbsd-kern.c b/devel/gdb/files/kgdb/i386fbsd-kern.c
new file mode 100644
index 000000000000..a621f54c5004
--- /dev/null
+++ b/devel/gdb/files/kgdb/i386fbsd-kern.c
@@ -0,0 +1,561 @@
+/*
+ * Copyright (c) 2004 Marcel Moolenaar
+ * 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 AUTHORS ``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 AUTHORS 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$");
+
+#include <sys/param.h>
+#include <sys/proc.h>
+#ifdef __i386__
+#include <machine/pcb.h>
+#include <machine/frame.h>
+#include <machine/segments.h>
+#include <machine/tss.h>
+#endif
+#include <string.h>
+
+#include <defs.h>
+#include <frame-unwind.h>
+#include "gdbcore.h"
+#include <inferior.h>
+#include "osabi.h"
+#include <regcache.h>
+#include "progspace.h"
+#include "solib.h"
+#include "trad-frame.h"
+#include <i386-tdep.h>
+
+#include "kgdb.h"
+
+struct i386fbsd_info {
+ int ofs_fix;
+};
+
+/* Per-program-space data key. */
+static const struct program_space_data *i386fbsd_pspace_data;
+
+static void
+i386fbsd_pspace_data_cleanup (struct program_space *pspace, void *arg)
+{
+ struct i386fbsd_info *info = arg;
+
+ xfree (info);
+}
+
+/* Get the current i386fbsd data. If none is found yet, add it now. This
+ function always returns a valid object. */
+
+static struct i386fbsd_info *
+get_i386fbsd_info (void)
+{
+ struct i386fbsd_info *info;
+
+ info = program_space_data (current_program_space, i386fbsd_pspace_data);
+ if (info != NULL)
+ return info;
+
+ info = XCNEW (struct i386fbsd_info);
+ set_program_space_data (current_program_space, i386fbsd_pspace_data, info);
+
+ /*
+ * In revision 1.117 of i386/i386/exception.S trap handlers
+ * were changed to pass trapframes by reference rather than
+ * by value. Detect this by seeing if the first instruction
+ * at the 'calltrap' label is a "push %esp" which has the
+ * opcode 0x54.
+ */
+ if (parse_and_eval_long("((char *)calltrap)[0]") == 0x54)
+ info->ofs_fix = 4;
+ else
+ info->ofs_fix = 0;
+ return info;
+}
+
+/*
+ * Even though the pcb contains fields for the segment selectors, only
+ * %gs is updated on each context switch. The other selectors are
+ * saved in stoppcbs[], but we just hardcode their known values rather
+ * than handling that special case.
+ */
+static const int i386fbsd_pcb_offset[] = {
+ -1, /* %eax */
+ -1, /* %ecx */
+ -1, /* %edx */
+ 4 * 4, /* %ebx */
+ 3 * 4, /* %esp */
+ 2 * 4, /* %ebp */
+ 1 * 4, /* %esi */
+ 0 * 4, /* %edi */
+ 5 * 4, /* %eip */
+ -1, /* %eflags */
+ -1, /* %cs */
+ -1, /* %ss */
+ -1, /* %ds */
+ -1, /* %es */
+ -1, /* %fs */
+ -1, /* %gs */
+};
+
+#define CODE_SEL (4 << 3)
+#define DATA_SEL (5 << 3)
+#define PRIV_SEL (1 << 3)
+
+static void
+i386fbsd_supply_pcb(struct regcache *regcache, CORE_ADDR pcb_addr)
+{
+ gdb_byte buf[4];
+ int i;
+
+ for (i = 0; i < ARRAY_SIZE (i386fbsd_pcb_offset); i++)
+ if (i386fbsd_pcb_offset[i] != -1) {
+ if (target_read_memory(pcb_addr + i386fbsd_pcb_offset[i], buf, sizeof buf)
+ != 0)
+ continue;
+ regcache_raw_supply(regcache, i, buf);
+ }
+ regcache_raw_supply_unsigned(regcache, I386_CS_REGNUM, CODE_SEL);
+ regcache_raw_supply_unsigned(regcache, I386_DS_REGNUM, DATA_SEL);
+ regcache_raw_supply_unsigned(regcache, I386_ES_REGNUM, DATA_SEL);
+ regcache_raw_supply_unsigned(regcache, I386_FS_REGNUM, PRIV_SEL);
+ regcache_raw_supply_unsigned(regcache, I386_GS_REGNUM, DATA_SEL);
+ regcache_raw_supply_unsigned(regcache, I386_SS_REGNUM, DATA_SEL);
+}
+
+#ifdef __i386__
+/* TODO: Make this cross-debugger friendly. */
+static const int i386fbsd_tss_offset[] = {
+ 10 * 4, /* %eax */
+ 11 * 4, /* %ecx */
+ 12 * 4, /* %edx */
+ 13 * 4, /* %ebx */
+ 14 * 4, /* %esp */
+ 15 * 4, /* %ebp */
+ 16 * 4, /* %esi */
+ 17 * 4, /* %edi */
+ 8 * 4, /* %eip */
+ 9 * 4, /* %eflags */
+ 19 * 4, /* %cs */
+ 20 * 4, /* %ss */
+ 21 * 4, /* %ds */
+ 18 * 4, /* %es */
+ 22 * 4, /* %fs */
+ 23 * 4, /* %gs */
+};
+
+/*
+ * If the current thread is executing on a CPU, fetch the common_tss
+ * for that CPU.
+ *
+ * This is painful because 'struct pcpu' is variant sized, so we can't
+ * use it. Instead, we lookup the GDT selector for this CPU and
+ * extract the base of the TSS from there.
+ */
+static CORE_ADDR
+i386fbsd_fetch_tss(void)
+{
+ struct kthr *kt;
+ struct segment_descriptor sd;
+ CORE_ADDR addr, cpu0prvpage, tss;
+
+ kt = kgdb_thr_lookup_tid(ptid_get_tid(inferior_ptid));
+ if (kt == NULL || kt->cpu == NOCPU || kt->cpu < 0)
+ return (0);
+
+ addr = kgdb_lookup("gdt");
+ if (addr == 0)
+ return (0);
+ addr += (kt->cpu * NGDT + GPROC0_SEL) * sizeof(sd);
+ if (target_read_memory(addr, (void *)&sd, sizeof(sd)) != 0)
+ return (0);
+ if (sd.sd_type != SDT_SYS386BSY) {
+ warning ("descriptor is not a busy TSS");
+ return (0);
+ }
+ tss = sd.sd_hibase << 24 | sd.sd_lobase;
+
+ /*
+ * In SMP kernels, the TSS is stored as part of the per-CPU
+ * data. On older kernels, the CPU0's private page
+ * is stored at an address that isn't mapped in minidumps.
+ * However, the data is mapped at the alternate cpu0prvpage
+ * address. Thus, if the TSS is at the invalid address,
+ * change it to be relative to cpu0prvpage instead.
+ */
+ if (trunc_page(tss) == 0xffc00000) {
+ TRY {
+ cpu0prvpage = parse_and_eval_address("cpu0prvpage");
+ } CATCH(e, RETURN_MASK_ERROR) {
+ return (0);
+ } END_CATCH
+ tss = cpu0prvpage + (tss & PAGE_MASK);
+ }
+ return (tss);
+}
+
+static struct trad_frame_cache *
+i386fbsd_dblfault_cache (struct frame_info *this_frame, void **this_cache)
+{
+ struct gdbarch *gdbarch = get_frame_arch (this_frame);
+ enum bfd_endian byte_order = gdbarch_byte_order (gdbarch);
+ struct trad_frame_cache *cache;
+ CORE_ADDR addr, func, tss;
+ int i;
+
+ if (*this_cache != NULL)
+ return (*this_cache);
+
+ cache = trad_frame_cache_zalloc (this_frame);
+ *this_cache = cache;
+
+ func = get_frame_func (this_frame);
+ tss = i386fbsd_fetch_tss ();
+
+ for (i = 0; i < ARRAY_SIZE (i386fbsd_tss_offset); i++)
+ if (i386fbsd_tss_offset[i] != -1)
+ trad_frame_set_reg_addr (cache, i, tss + i386fbsd_tss_offset[i]);
+
+ /* Construct the frame ID using the function start. */
+ /* XXX: Stack address should be dbfault_stack + PAGE_SIZE. */
+ trad_frame_set_id (cache, frame_id_build (tss + sizeof(struct i386tss),
+ func));
+
+ return cache;
+}
+
+static void
+i386fbsd_dblfault_this_id (struct frame_info *this_frame,
+ void **this_cache, struct frame_id *this_id)
+{
+ struct trad_frame_cache *cache =
+ i386fbsd_dblfault_cache (this_frame, this_cache);
+
+ trad_frame_get_id (cache, this_id);
+}
+
+static struct value *
+i386fbsd_dblfault_prev_register (struct frame_info *this_frame,
+ void **this_cache, int regnum)
+{
+ struct trad_frame_cache *cache =
+ i386fbsd_dblfault_cache (this_frame, this_cache);
+
+ return trad_frame_get_register (cache, this_frame, regnum);
+}
+
+static int
+i386fbsd_dblfault_sniffer (const struct frame_unwind *self,
+ struct frame_info *this_frame,
+ void **this_prologue_cache)
+{
+ const char *name;
+
+ find_pc_partial_function (get_frame_func (this_frame), &name, NULL, NULL);
+ return (name && strcmp (name, "dblfault_handler") == 0);
+}
+
+static const struct frame_unwind i386fbsd_dblfault_unwind = {
+ NORMAL_FRAME,
+ default_frame_unwind_stop_reason,
+ i386fbsd_dblfault_this_id,
+ i386fbsd_dblfault_prev_register,
+ NULL,
+ i386fbsd_dblfault_sniffer
+};
+#endif
+
+static const int i386fbsd_trapframe_offset[] = {
+ 10 * 4, /* %eax */
+ 9 * 4, /* %ecx */
+ 8 * 4, /* %edx */
+ 7 * 4, /* %ebx */
+ 16 * 4, /* %esp */
+ 5 * 4, /* %ebp */
+ 4 * 4, /* %esi */
+ 3 * 4, /* %edi */
+ 13 * 4, /* %eip */
+ 15 * 4, /* %eflags */
+ 14 * 4, /* %cs */
+ 17 * 4, /* %ss */
+ 2 * 4, /* %ds */
+ 1 * 4, /* %es */
+ 0 * 4, /* %fs */
+ -1 /* %gs */
+};
+
+#define TRAPFRAME_SIZE 72
+
+static struct trad_frame_cache *
+i386fbsd_trapframe_cache (struct frame_info *this_frame, void **this_cache)
+{
+ struct gdbarch *gdbarch = get_frame_arch (this_frame);
+ enum bfd_endian byte_order = gdbarch_byte_order (gdbarch);
+ struct trad_frame_cache *cache;
+ struct i386fbsd_info *info;
+ CORE_ADDR addr, cs, func, pc, sp;
+ const char *name;
+ int i;
+
+ if (*this_cache != NULL)
+ return (*this_cache);
+
+ info = get_i386fbsd_info();
+ cache = trad_frame_cache_zalloc (this_frame);
+ *this_cache = cache;
+
+ func = get_frame_func (this_frame);
+ sp = get_frame_register_unsigned (this_frame, I386_ESP_REGNUM);
+
+ find_pc_partial_function (func, &name, NULL, NULL);
+ if (strcmp(name, "calltrap") == 0 ||
+ strcmp(name, "Xlcall_syscall") == 0 ||
+ strcmp(name, "Xint0x80_syscall") == 0)
+ /* Traps in later kernels pass the trap frame by reference. */
+ sp += info->ofs_fix;
+ else if (strcmp(name, "Xtimerint") == 0)
+ /* Timer interrupts also pass the trap frame by reference. */
+ sp += info->ofs_fix;
+ else if (strcmp(name, "Xcpustop") == 0 ||
+ strcmp(name, "Xrendezvous") == 0 ||
+ strcmp(name, "Xipi_intr_bitmap_handler") == 0 ||
+ strcmp(name, "Xlazypmap") == 0)
+ /* These handlers push a trap frame only. */
+ ;
+ else if (strcmp(name, "fork_trampoline") == 0)
+ if (get_frame_pc (this_frame) == func)
+ {
+ /* fork_exit hasn't been called (kthread has never run), so
+ %esp in the pcb points to the word above the trapframe. */
+ sp += 4;
+ }
+ else
+ {
+ /* fork_exit has been called, so %esp in fork_exit's
+ frame is &tf - 12. */
+ sp += 12;
+ }
+ else {
+ /* Interrupt frames pass the IDT vector in addition to the trap frame. */
+ sp += info->ofs_fix + 4;
+ }
+
+ addr = sp + i386fbsd_trapframe_offset[I386_CS_REGNUM];
+ cs = read_memory_unsigned_integer (addr, 4, byte_order);
+ for (i = 0; i < ARRAY_SIZE (i386fbsd_trapframe_offset); i++)
+ {
+ /* %ss/%esp are only present in the trapframe for a trap from
+ userland. */
+ if ((cs & I386_SEL_RPL) == I386_SEL_KPL)
+ {
+ if (i == I386_SS_REGNUM)
+ continue;
+ if (i == I386_ESP_REGNUM)
+ {
+ trad_frame_set_reg_value (cache, i, sp + TRAPFRAME_SIZE - 8);
+ continue;
+ }
+ }
+ if (i386fbsd_trapframe_offset[i] != -1)
+ trad_frame_set_reg_addr (cache, i, sp + i386fbsd_trapframe_offset[i]);
+ }
+
+ /* Read %eip from trap frame. */
+ addr = sp + i386fbsd_trapframe_offset[I386_EIP_REGNUM];
+ pc = read_memory_unsigned_integer (addr, 4, byte_order);
+
+ if (pc == 0 && strcmp(name, "fork_trampoline") == 0)
+ {
+ /* Initial frame of a kthread; terminate backtrace. */
+ trad_frame_set_id (cache, outer_frame_id);
+ }
+ else
+ {
+ /* Construct the frame ID using the function start. */
+ sp += TRAPFRAME_SIZE;
+ if ((cs & I386_SEL_RPL) == I386_SEL_KPL)
+ sp -= 8;
+ trad_frame_set_id (cache, frame_id_build (sp, func));
+ }
+
+ return cache;
+}
+
+static void
+i386fbsd_trapframe_this_id (struct frame_info *this_frame,
+ void **this_cache, struct frame_id *this_id)
+{
+ struct trad_frame_cache *cache =
+ i386fbsd_trapframe_cache (this_frame, this_cache);
+
+ trad_frame_get_id (cache, this_id);
+}
+
+static struct value *
+i386fbsd_trapframe_prev_register (struct frame_info *this_frame,
+ void **this_cache, int regnum)
+{
+ struct trad_frame_cache *cache =
+ i386fbsd_trapframe_cache (this_frame, this_cache);
+
+ return trad_frame_get_register (cache, this_frame, regnum);
+}
+
+static int
+i386fbsd_trapframe_sniffer (const struct frame_unwind *self,
+ struct frame_info *this_frame,
+ void **this_prologue_cache)
+{
+ const char *name;
+
+ find_pc_partial_function (get_frame_func (this_frame), &name, NULL, NULL);
+ return (name && ((strcmp (name, "calltrap") == 0)
+ || (strcmp (name, "fork_trampoline") == 0)
+ || (name[0] == 'X' && name[1] != '_')));
+}
+
+static const struct frame_unwind i386fbsd_trapframe_unwind = {
+ NORMAL_FRAME,
+ default_frame_unwind_stop_reason,
+ i386fbsd_trapframe_this_id,
+ i386fbsd_trapframe_prev_register,
+ NULL,
+ i386fbsd_trapframe_sniffer
+};
+
+static void
+i386fbsd_kernel_init_abi(struct gdbarch_info info, struct gdbarch *gdbarch)
+{
+
+ i386_elf_init_abi(info, gdbarch);
+
+#ifdef __i386__
+ frame_unwind_prepend_unwinder(gdbarch, &i386fbsd_dblfault_unwind);
+#endif
+ frame_unwind_prepend_unwinder(gdbarch, &i386fbsd_trapframe_unwind);
+
+ set_solib_ops(gdbarch, &kld_so_ops);
+
+ fbsd_vmcore_set_supply_pcb(gdbarch, i386fbsd_supply_pcb);
+ fbsd_vmcore_set_cpu_pcb_addr(gdbarch, kgdb_trgt_stop_pcb);
+}
+
+void _initialize_i386_kgdb_tdep(void);
+
+void
+_initialize_i386_kgdb_tdep(void)
+{
+ /* This is used for both i386 and amd64, but amd64 always
+ includes this target, so just include it here. */
+ gdbarch_register_osabi_sniffer(bfd_arch_i386,
+ bfd_target_elf_flavour,
+ fbsd_kernel_osabi_sniffer);
+ gdbarch_register_osabi (bfd_arch_i386, 0,
+ GDB_OSABI_FREEBSD_ELF_KERNEL, i386fbsd_kernel_init_abi);
+
+ i386fbsd_pspace_data = register_program_space_data_with_cleanup (NULL,
+ i386fbsd_pspace_data_cleanup);
+
+#ifdef __i386__
+ gdb_assert(offsetof(struct pcb, pcb_ebx)
+ == i386fbsd_pcb_offset[I386_EBX_REGNUM]);
+ gdb_assert(offsetof(struct pcb, pcb_esp)
+ == i386fbsd_pcb_offset[I386_ESP_REGNUM]);
+ gdb_assert(offsetof(struct pcb, pcb_ebp)
+ == i386fbsd_pcb_offset[I386_EBP_REGNUM]);
+ gdb_assert(offsetof(struct pcb, pcb_esi)
+ == i386fbsd_pcb_offset[I386_ESI_REGNUM]);
+ gdb_assert(offsetof(struct pcb, pcb_edi)
+ == i386fbsd_pcb_offset[I386_EDI_REGNUM]);
+ gdb_assert(offsetof(struct pcb, pcb_eip)
+ == i386fbsd_pcb_offset[I386_EIP_REGNUM]);
+ gdb_assert(CODE_SEL == GSEL(GCODE_SEL, SEL_KPL));
+ gdb_assert(DATA_SEL == GSEL(GDATA_SEL, SEL_KPL));
+ gdb_assert(PRIV_SEL == GSEL(GPRIV_SEL, SEL_KPL));
+ gdb_assert(sizeof(struct trapframe) == TRAPFRAME_SIZE);
+ gdb_assert(offsetof(struct trapframe, tf_eax)
+ == i386fbsd_trapframe_offset[I386_EAX_REGNUM]);
+ gdb_assert(offsetof(struct trapframe, tf_ecx)
+ == i386fbsd_trapframe_offset[I386_ECX_REGNUM]);
+ gdb_assert(offsetof(struct trapframe, tf_edx)
+ == i386fbsd_trapframe_offset[I386_EDX_REGNUM]);
+ gdb_assert(offsetof(struct trapframe, tf_ebx)
+ == i386fbsd_trapframe_offset[I386_EBX_REGNUM]);
+ gdb_assert(offsetof(struct trapframe, tf_esp)
+ == i386fbsd_trapframe_offset[I386_ESP_REGNUM]);
+ gdb_assert(offsetof(struct trapframe, tf_ebp)
+ == i386fbsd_trapframe_offset[I386_EBP_REGNUM]);
+ gdb_assert(offsetof(struct trapframe, tf_esi)
+ == i386fbsd_trapframe_offset[I386_ESI_REGNUM]);
+ gdb_assert(offsetof(struct trapframe, tf_edi)
+ == i386fbsd_trapframe_offset[I386_EDI_REGNUM]);
+ gdb_assert(offsetof(struct trapframe, tf_eip)
+ == i386fbsd_trapframe_offset[I386_EIP_REGNUM]);
+ gdb_assert(offsetof(struct trapframe, tf_eflags)
+ == i386fbsd_trapframe_offset[I386_EFLAGS_REGNUM]);
+ gdb_assert(offsetof(struct trapframe, tf_cs)
+ == i386fbsd_trapframe_offset[I386_CS_REGNUM]);
+ gdb_assert(offsetof(struct trapframe, tf_ss)
+ == i386fbsd_trapframe_offset[I386_SS_REGNUM]);
+ gdb_assert(offsetof(struct trapframe, tf_ds)
+ == i386fbsd_trapframe_offset[I386_DS_REGNUM]);
+ gdb_assert(offsetof(struct trapframe, tf_es)
+ == i386fbsd_trapframe_offset[I386_ES_REGNUM]);
+ gdb_assert(offsetof(struct trapframe, tf_fs)
+ == i386fbsd_trapframe_offset[I386_FS_REGNUM]);
+
+ gdb_assert(offsetof(struct i386tss, tss_eax)
+ == i386fbsd_tss_offset[I386_EAX_REGNUM]);
+ gdb_assert(offsetof(struct i386tss, tss_ecx)
+ == i386fbsd_tss_offset[I386_ECX_REGNUM]);
+ gdb_assert(offsetof(struct i386tss, tss_edx)
+ == i386fbsd_tss_offset[I386_EDX_REGNUM]);
+ gdb_assert(offsetof(struct i386tss, tss_ebx)
+ == i386fbsd_tss_offset[I386_EBX_REGNUM]);
+ gdb_assert(offsetof(struct i386tss, tss_esp)
+ == i386fbsd_tss_offset[I386_ESP_REGNUM]);
+ gdb_assert(offsetof(struct i386tss, tss_ebp)
+ == i386fbsd_tss_offset[I386_EBP_REGNUM]);
+ gdb_assert(offsetof(struct i386tss, tss_esi)
+ == i386fbsd_tss_offset[I386_ESI_REGNUM]);
+ gdb_assert(offsetof(struct i386tss, tss_edi)
+ == i386fbsd_tss_offset[I386_EDI_REGNUM]);
+ gdb_assert(offsetof(struct i386tss, tss_eip)
+ == i386fbsd_tss_offset[I386_EIP_REGNUM]);
+ gdb_assert(offsetof(struct i386tss, tss_eflags)
+ == i386fbsd_tss_offset[I386_EFLAGS_REGNUM]);
+ gdb_assert(offsetof(struct i386tss, tss_cs)
+ == i386fbsd_tss_offset[I386_CS_REGNUM]);
+ gdb_assert(offsetof(struct i386tss, tss_ss)
+ == i386fbsd_tss_offset[I386_SS_REGNUM]);
+ gdb_assert(offsetof(struct i386tss, tss_ds)
+ == i386fbsd_tss_offset[I386_DS_REGNUM]);
+ gdb_assert(offsetof(struct i386tss, tss_es)
+ == i386fbsd_tss_offset[I386_ES_REGNUM]);
+ gdb_assert(offsetof(struct i386tss, tss_fs)
+ == i386fbsd_tss_offset[I386_FS_REGNUM]);
+ gdb_assert(offsetof(struct i386tss, tss_gs)
+ == i386fbsd_tss_offset[I386_GS_REGNUM]);
+#endif
+}
diff --git a/devel/gdb/files/kgdb/kgdb-main.c b/devel/gdb/files/kgdb/kgdb-main.c
new file mode 100644
index 000000000000..a99fc57971d7
--- /dev/null
+++ b/devel/gdb/files/kgdb/kgdb-main.c
@@ -0,0 +1,413 @@
+/*
+ * Copyright (c) 2004 Marcel Moolenaar
+ * 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 ``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 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$");
+
+#include <sys/param.h>
+#include <sys/stat.h>
+#include <sys/types.h>
+#include <sys/ioctl.h>
+#include <sys/resource.h>
+#include <sys/select.h>
+#include <sys/time.h>
+#include <sys/wait.h>
+#include <errno.h>
+#include <err.h>
+#include <inttypes.h>
+#include <kvm.h>
+#include <limits.h>
+#include <paths.h>
+
+/* libgdb stuff. */
+#include <defs.h>
+#include <frame.h>
+#include <frame-unwind.h>
+#include <inferior.h>
+#include <interps.h>
+#include <cli-out.h>
+#include <main.h>
+#include <objfiles.h>
+#include "observer.h"
+#include <target.h>
+#include <top.h>
+#include <ui-file.h>
+#include <bfd.h>
+#include <gdbcore.h>
+
+#include <unistd.h>
+
+#include "kgdb.h"
+
+static int dumpnr;
+static int verbose;
+
+static char crashdir[PATH_MAX];
+static char *kernel;
+static char *remote;
+static char *vmcore;
+
+/*
+ * TODO:
+ * - test remote kgdb (see if threads and klds work)
+ * - possibly split kthr.c out into a separate thread_stratum target that
+ * uses new_objfile test to push itself when a FreeBSD kernel is loaded
+ * (check for kernel osabi) (probably don't bother with this)
+ * + test alternate kgdb_lookup()
+ * + fix kgdb build on amd64 to include i386 cross-debug support
+ * - propose expanded libkvm interface that supports cross-debug and moves
+ * MD bits of kgdb into the library (examining PCB's and exporting a
+ * stable-ABI struct of registers, similarly for trapframe handling and
+ * stop-pcb stuff
+ * + use tid's as lwp IDs instead of PIDs in ptid's
+ */
+
+static void
+usage(void)
+{
+
+ fprintf(stderr,
+ "usage: %s [-afqvw] [-b rate] [-d crashdir] [-c core | -n dumpnr | -r device]\n"
+ "\t[kernel [core]]\n", getprogname());
+ exit(1);
+}
+
+static void
+kernel_from_dumpnr(int nr)
+{
+ char line[PATH_MAX], path[PATH_MAX];
+ FILE *info;
+ char *dir;
+ struct stat st;
+ int l;
+
+ /*
+ * If there's a kernel image right here in the crash directory, then
+ * use it. The kernel image is either called kernel.<nr> or is in a
+ * subdirectory kernel.<nr> and called kernel. The latter allows us
+ * to collect the modules in the same place.
+ */
+ snprintf(path, sizeof(path), "%s/kernel.%d", crashdir, nr);
+ if (stat(path, &st) == 0) {
+ if (S_ISREG(st.st_mode)) {
+ kernel = strdup(path);
+ return;
+ }
+ if (S_ISDIR(st.st_mode)) {
+ snprintf(path, sizeof(path), "%s/kernel.%d/kernel",
+ crashdir, nr);
+ if (stat(path, &st) == 0 && S_ISREG(st.st_mode)) {
+ kernel = strdup(path);
+ return;
+ }
+ }
+ }
+
+ /*
+ * No kernel image here. Parse the dump header. The kernel object
+ * directory can be found there and we probably have the kernel
+ * image still in it. The object directory may also have a kernel
+ * with debugging info (called either kernel.full or kernel.debug).
+ * If we have a debug kernel, use it.
+ */
+ snprintf(path, sizeof(path), "%s/info.%d", crashdir, nr);
+ info = fopen(path, "r");
+ if (info == NULL) {
+ warn("%s", path);
+ return;
+ }
+ while (fgets(line, sizeof(line), info) != NULL) {
+ l = strlen(line);
+ if (l > 0 && line[l - 1] == '\n')
+ line[--l] = '\0';
+ if (strncmp(line, " ", 4) == 0) {
+ fclose(info);
+ dir = strchr(line, ':');
+ dir = (dir == NULL) ? line + 4 : dir + 1;
+
+ /*
+ * Check for kernel.full first as if it exists
+ * kernel.debug will also exist, but will only
+ * contain debug symbols and not be recognized
+ * as a valid kernel by the osabi sniffer.
+ */
+ snprintf(path, sizeof(path), "%s/kernel.full", dir);
+ if (stat(path, &st) == 0 && S_ISREG(st.st_mode)) {
+ kernel = strdup(path);
+ return;
+ }
+ snprintf(path, sizeof(path), "%s/kernel.debug", dir);
+ if (stat(path, &st) == 0 && S_ISREG(st.st_mode)) {
+ kernel = strdup(path);
+ return;
+ }
+ snprintf(path, sizeof(path), "%s/kernel", dir);
+ if (stat(path, &st) == 0 && S_ISREG(st.st_mode)) {
+ kernel = strdup(path);
+ return;
+ }
+ return;
+ }
+ }
+ fclose(info);
+}
+
+/*
+ * Remote targets can support any number of syntaxes and we want to
+ * support them all with one addition: we support specifying a device
+ * node for a serial device without the "/dev/" prefix.
+ *
+ * What we do is to stat(2) the existing remote target first. If that
+ * fails, we try it with "/dev/" prepended. If that succeeds we use
+ * the resulting path, otherwise we use the original target. If
+ * either stat(2) succeeds make sure the file is either a character
+ * device or a FIFO.
+ */
+static void
+verify_remote(void)
+{
+ char path[PATH_MAX];
+ struct stat st;
+
+ if (stat(remote, &st) != 0) {
+ snprintf(path, sizeof(path), "/dev/%s", remote);
+ if (stat(path, &st) != 0)
+ return;
+ free(remote);
+ remote = strdup(path);
+ }
+ if (!S_ISCHR(st.st_mode) && !S_ISFIFO(st.st_mode))
+ errx(1, "%s: not a special file, FIFO or socket", remote);
+}
+
+static void
+add_arg(struct captured_main_args *args, char *arg)
+{
+
+ args->argc++;
+ args->argv = reallocf(args->argv, (args->argc + 1) * sizeof(char *));
+ if (args->argv == NULL)
+ err(1, "Out of memory building argument list");
+ args->argv[args->argc] = arg;
+}
+
+int
+main(int argc, char *argv[])
+{
+ char path[PATH_MAX];
+ struct stat st;
+ struct captured_main_args args;
+ char *s;
+ int a, ch;
+
+ dumpnr = -1;
+
+ strlcpy(crashdir, "/var/crash", sizeof(crashdir));
+ s = getenv("KGDB_CRASH_DIR");
+ if (s != NULL)
+ strlcpy(crashdir, s, sizeof(crashdir));
+
+ /* Convert long options into short options. */
+ for (a = 1; a < argc; a++) {
+ s = argv[a];
+ if (s[0] == '-') {
+ s++;
+ /* Long options take either 1 or 2 dashes. */
+ if (s[0] == '-')
+ s++;
+ if (strcmp(s, "quiet") == 0)
+ argv[a] = "-q";
+ else if (strcmp(s, "fullname") == 0)
+ argv[a] = "-f";
+ }
+ }
+
+ kgdb_quiet = 0;
+ memset (&args, 0, sizeof args);
+ args.interpreter_p = INTERP_CONSOLE;
+ args.argv = malloc(sizeof(char *));
+ args.argv[0] = argv[0];
+
+ while ((ch = getopt(argc, argv, "ab:c:d:fn:qr:vw")) != -1) {
+ switch (ch) {
+ case 'a':
+ annotation_level++;
+ break;
+ case 'b': {
+ int i;
+ char *p;
+
+ i = strtol(optarg, &p, 0);
+ if (*p != '\0' || p == optarg)
+ warnx("warning: could not set baud rate to `%s'.\n",
+ optarg);
+ else
+ baud_rate = i;
+ break;
+ }
+ case 'c': /* use given core file. */
+ if (vmcore != NULL) {
+ warnx("option %c: can only be specified once",
+ optopt);
+ usage();
+ /* NOTREACHED */
+ }
+ vmcore = strdup(optarg);
+ break;
+ case 'd': /* lookup dumps in given directory. */
+ strlcpy(crashdir, optarg, sizeof(crashdir));
+ break;
+ case 'f':
+ annotation_level = 1;
+ break;
+ case 'n': /* use dump with given number. */
+ dumpnr = strtol(optarg, &s, 0);
+ if (dumpnr < 0 || *s != '\0') {
+ warnx("option %c: invalid kernel dump number",
+ optopt);
+ usage();
+ /* NOTREACHED */
+ }
+ break;
+ case 'q':
+ kgdb_quiet = 1;
+ add_arg(&args, "-q");
+ break;
+ case 'r': /* use given device for remote session. */
+ if (remote != NULL) {
+ warnx("option %c: can only be specified once",
+ optopt);
+ usage();
+ /* NOTREACHED */
+ }
+ remote = strdup(optarg);
+ break;
+ case 'v': /* increase verbosity. */
+ verbose++;
+ break;
+ case 'w': /* core file is writeable. */
+ add_arg(&args, "--write");
+ break;
+ case '?':
+ default:
+ usage();
+ }
+ }
+
+ if (((vmcore != NULL) ? 1 : 0) + ((dumpnr >= 0) ? 1 : 0) +
+ ((remote != NULL) ? 1 : 0) > 1) {
+ warnx("options -c, -n and -r are mutually exclusive");
+ usage();
+ /* NOTREACHED */
+ }
+
+ if (verbose > 1)
+ warnx("using %s as the crash directory", crashdir);
+
+ if (argc > optind)
+ kernel = strdup(argv[optind++]);
+
+ if (argc > optind && (dumpnr >= 0 || remote != NULL)) {
+ warnx("options -n and -r do not take a core file. Ignored");
+ optind = argc;
+ }
+
+ if (dumpnr >= 0) {
+ snprintf(path, sizeof(path), "%s/vmcore.%d", crashdir, dumpnr);
+ if (stat(path, &st) == -1)
+ err(1, "%s", path);
+ if (!S_ISREG(st.st_mode))
+ errx(1, "%s: not a regular file", path);
+ vmcore = strdup(path);
+ } else if (remote != NULL) {
+ verify_remote();
+ } else if (argc > optind) {
+ if (vmcore == NULL)
+ vmcore = strdup(argv[optind++]);
+ if (argc > optind)
+ warnx("multiple core files specified. Ignored");
+ } else if (vmcore == NULL && kernel == NULL) {
+ vmcore = strdup(_PATH_MEM);
+ kernel = strdup(getbootfile());
+ }
+
+ if (verbose) {
+ if (vmcore != NULL)
+ warnx("core file: %s", vmcore);
+ if (remote != NULL)
+ warnx("device file: %s", remote);
+ if (kernel != NULL)
+ warnx("kernel image: %s", kernel);
+ }
+
+ /* A remote target requires an explicit kernel argument. */
+ if (remote != NULL && kernel == NULL) {
+ warnx("remote debugging requires a kernel");
+ usage();
+ /* NOTREACHED */
+ }
+
+ /* If we don't have a kernel image yet, try to find one. */
+ if (kernel == NULL) {
+ if (dumpnr >= 0)
+ kernel_from_dumpnr(dumpnr);
+
+ if (kernel == NULL)
+ errx(1, "couldn't find a suitable kernel image");
+ if (verbose)
+ warnx("kernel image: %s", kernel);
+ }
+
+ /* Set an alternate prompt. */
+ add_arg(&args, "-iex");
+ add_arg(&args, "set prompt (kgdb) ");
+
+ /* Open the vmcore if requested. */
+ if (vmcore != NULL) {
+ add_arg(&args, "-ex");
+ if (asprintf(&s, "target vmcore %s", vmcore) < 0)
+ err(1, "couldn't build command line");
+ add_arg(&args, s);
+ }
+
+ /* Open the remote target if requested. */
+ if (remote != NULL) {
+ add_arg(&args, "-ex");
+ if (asprintf(&s, "target remote %s", remote) < 0)
+ err(1, "couldn't build command line");
+ add_arg(&args, s);
+ }
+
+ add_arg(&args, kernel);
+
+ /* The libgdb code uses optind too. Reset it... */
+ optind = 0;
+
+ /* Terminate argv list. */
+ add_arg(&args, NULL);
+
+ return (gdb_main(&args));
+}
diff --git a/devel/gdb/files/kgdb/kgdb.h b/devel/gdb/files/kgdb/kgdb.h
new file mode 100644
index 000000000000..6f37bf28f290
--- /dev/null
+++ b/devel/gdb/files/kgdb/kgdb.h
@@ -0,0 +1,67 @@
+/*
+ * Copyright (c) 2004 Marcel Moolenaar
+ * 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 ``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 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$
+ */
+
+#ifndef _KGDB_H_
+#define _KGDB_H_
+
+struct kthr {
+ struct kthr *next;
+ CORE_ADDR paddr;
+ CORE_ADDR kaddr;
+ CORE_ADDR pcb;
+ int tid;
+ int pid;
+ int cpu;
+};
+
+extern struct kthr *curkthr;
+extern struct target_so_ops kld_so_ops;
+extern struct target_ops kgdb_trgt_ops;
+extern int kgdb_quiet;
+
+CORE_ADDR kgdb_trgt_stop_pcb(u_int);
+
+struct kthr *kgdb_thr_first(void);
+struct kthr *kgdb_thr_init(CORE_ADDR (*cpu_pcb_addr) (u_int));
+struct kthr *kgdb_thr_lookup_tid(int);
+struct kthr *kgdb_thr_lookup_pid(int);
+struct kthr *kgdb_thr_lookup_paddr(uintptr_t);
+struct kthr *kgdb_thr_lookup_taddr(uintptr_t);
+struct kthr *kgdb_thr_next(struct kthr *);
+char *kgdb_thr_extra_thread_info(int);
+
+enum gdb_osabi fbsd_kernel_osabi_sniffer(bfd *abfd);
+void fbsd_vmcore_set_supply_pcb (struct gdbarch *gdbarch,
+ void (*supply_pcb) (struct regcache *,
+ CORE_ADDR));
+void fbsd_vmcore_set_cpu_pcb_addr (struct gdbarch *gdbarch,
+ CORE_ADDR (*cpu_pcb_addr) (u_int));
+
+CORE_ADDR kgdb_lookup(const char *sym);
+
+#endif /* _KGDB_H_ */
diff --git a/devel/gdb/files/kgdb/ppcfbsd-kern.c b/devel/gdb/files/kgdb/ppcfbsd-kern.c
new file mode 100644
index 000000000000..30feafeb2bc6
--- /dev/null
+++ b/devel/gdb/files/kgdb/ppcfbsd-kern.c
@@ -0,0 +1,254 @@
+/*-
+ * Copyright (c) 2006 Marcel Moolenaar
+ * 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 ``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 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$");
+
+#include <sys/types.h>
+#ifdef __powerpc__
+#include <machine/pcb.h>
+#include <machine/frame.h>
+#endif
+#include <string.h>
+
+#include <defs.h>
+#include <frame-unwind.h>
+#include "gdbcore.h"
+#include "osabi.h"
+#include "regcache.h"
+#include "solib.h"
+#include "symtab.h"
+#include "trad-frame.h"
+
+#include <ppc-tdep.h>
+#include "ppc64-tdep.h"
+
+#include "kgdb.h"
+
+#ifdef __powerpc__
+static void
+ppcfbsd_supply_pcb(struct regcache *regcache, CORE_ADDR pcb_addr)
+{
+ struct pcb pcb;
+ struct gdbarch_tdep *tdep;
+ int i;
+
+ tdep = gdbarch_tdep (target_gdbarch());
+
+ if (target_read_memory(pcb_addr, &pcb, sizeof(pcb)) != 0)
+ memset(&pcb, 0, sizeof(pcb));
+
+ /*
+ * r14-r31 are saved in the pcb
+ */
+ for (i = 14; i <= 31; i++) {
+ regcache_raw_supply(regcache, tdep->ppc_gp0_regnum + i,
+ (char *)&pcb.pcb_context[i]);
+ }
+
+ /* r1 is saved in the sp field */
+ regcache_raw_supply(regcache, tdep->ppc_gp0_regnum + 1,
+ (char *)&pcb.pcb_sp);
+ if (tdep->wordsize == 8)
+ /* r2 is saved in the toc field */
+ regcache_raw_supply(regcache, tdep->ppc_gp0_regnum + 2,
+ (char *)&pcb.pcb_toc);
+
+ regcache_raw_supply(regcache, tdep->ppc_lr_regnum, (char *)&pcb.pcb_lr);
+ regcache_raw_supply(regcache, tdep->ppc_cr_regnum, (char *)&pcb.pcb_cr);
+}
+#endif
+
+#define OFF_FIXREG 0
+#define OFF_LR 32
+#define OFF_CR 33
+#define OFF_XER 34
+#define OFF_CTR 35
+#define OFF_SRR0 36
+#define TRAPFRAME_SIZE 42
+
+#ifdef __powerpc__
+_Static_assert(sizeof(struct trapframe) == TRAPFRAME_SIZE * sizeof(register_t),
+ "trapframe size");
+_Static_assert(offsetof(struct trapframe, fixreg)
+ == OFF_FIXREG * sizeof(register_t), "fixreg offset");
+_Static_assert(offsetof(struct trapframe, lr) == OFF_LR * sizeof(register_t),
+ "lr offset");
+_Static_assert(offsetof(struct trapframe, cr) == OFF_CR * sizeof(register_t),
+ "cr offset");
+_Static_assert(offsetof(struct trapframe, xer) == OFF_XER * sizeof(register_t),
+ "xer offset");
+_Static_assert(offsetof(struct trapframe, ctr) == OFF_CTR * sizeof(register_t),
+ "ctr offset");
+_Static_assert(offsetof(struct trapframe, srr0)
+ == OFF_SRR0 * sizeof(register_t), "srr0 offset");
+#endif
+
+static struct trad_frame_cache *
+ppcfbsd_trapframe_cache (struct frame_info *this_frame, void **this_cache)
+{
+ struct gdbarch *gdbarch = get_frame_arch (this_frame);
+ struct gdbarch_tdep *tdep = gdbarch_tdep (gdbarch);
+ enum bfd_endian byte_order = gdbarch_byte_order (gdbarch);
+ struct trad_frame_cache *cache;
+ CORE_ADDR base;
+ int i, regnum;
+
+ if (*this_cache)
+ return *this_cache;
+
+ cache = trad_frame_cache_zalloc (this_frame);
+ *this_cache = cache;
+
+ base = get_frame_register_unsigned (this_frame, gdbarch_sp_regnum (gdbarch));
+ if (tdep->wordsize == 8)
+ base += 48;
+ else
+ base += 8;
+
+ for (i = 0; i < ppc_num_gprs; i++)
+ trad_frame_set_reg_addr (cache, tdep->ppc_gp0_regnum + i, base
+ + (OFF_FIXREG + i) * tdep->wordsize);
+ trad_frame_set_reg_addr (cache, tdep->ppc_lr_regnum, base
+ + OFF_LR * tdep->wordsize);
+ trad_frame_set_reg_addr (cache, tdep->ppc_cr_regnum, base
+ + OFF_CR * tdep->wordsize);
+ trad_frame_set_reg_addr (cache, tdep->ppc_xer_regnum, base
+ + OFF_XER * tdep->wordsize);
+ trad_frame_set_reg_addr (cache, tdep->ppc_ctr_regnum, base
+ + OFF_CTR * tdep->wordsize);
+ /* SRR0? */
+ trad_frame_set_reg_addr (cache, gdbarch_pc_regnum (gdbarch), base
+ + OFF_SRR0 * tdep->wordsize);
+
+ /* Construct the frame ID using the function start. */
+ trad_frame_set_id (cache, frame_id_build (base, get_frame_func (this_frame)));
+
+ return cache;
+}
+
+static void
+ppcfbsd_trapframe_this_id (struct frame_info *this_frame,
+ void **this_cache, struct frame_id *this_id)
+{
+ struct trad_frame_cache *cache =
+ ppcfbsd_trapframe_cache (this_frame, this_cache);
+
+ trad_frame_get_id (cache, this_id);
+}
+
+static struct value *
+ppcfbsd_trapframe_prev_register (struct frame_info *this_frame,
+ void **this_cache, int regnum)
+{
+ struct trad_frame_cache *cache =
+ ppcfbsd_trapframe_cache (this_frame, this_cache);
+
+ return trad_frame_get_register (cache, this_frame, regnum);
+}
+
+static int
+ppcfbsd_trapframe_sniffer (const struct frame_unwind *self,
+ struct frame_info *this_frame,
+ void **this_cache)
+{
+ CORE_ADDR pc;
+ const char *name;
+
+ pc = get_frame_func (this_frame);
+ find_pc_partial_function (pc, &name, NULL, NULL);
+ if (name && (strcmp(name, "asttrapexit") == 0
+ || strcmp(name, "trapexit") == 0))
+ return 1;
+
+ return 0;
+}
+
+static const struct frame_unwind ppcfbsd_trapframe_unwind =
+{
+ NORMAL_FRAME,
+ default_frame_unwind_stop_reason,
+ ppcfbsd_trapframe_this_id,
+ ppcfbsd_trapframe_prev_register,
+ NULL,
+ ppcfbsd_trapframe_sniffer
+};
+
+static void
+ppcfbsd_kernel_init_abi(struct gdbarch_info info, struct gdbarch *gdbarch)
+{
+ struct gdbarch_tdep *tdep = gdbarch_tdep (gdbarch);
+
+ frame_unwind_prepend_unwinder(gdbarch, &ppcfbsd_trapframe_unwind);
+
+ set_solib_ops(gdbarch, &kld_so_ops);
+
+#ifdef __powerpc__
+ if (tdep->wordsize == sizeof(register_t))
+ {
+ fbsd_vmcore_set_supply_pcb(gdbarch, ppcfbsd_supply_pcb);
+ fbsd_vmcore_set_cpu_pcb_addr(gdbarch, kgdb_trgt_stop_pcb);
+ }
+#endif
+
+ /* FreeBSD doesn't support the 128-bit `long double' from the psABI. */
+ set_gdbarch_long_double_bit (gdbarch, 64);
+ set_gdbarch_long_double_format (gdbarch, floatformats_ieee_double);
+
+ if (tdep->wordsize == 4)
+ {
+ set_gdbarch_return_value (gdbarch, ppc_sysv_abi_broken_return_value);
+ }
+
+ if (tdep->wordsize == 8)
+ {
+ set_gdbarch_convert_from_func_ptr_addr
+ (gdbarch, ppc64_convert_from_func_ptr_addr);
+ set_gdbarch_elf_make_msymbol_special (gdbarch,
+ ppc64_elf_make_msymbol_special);
+ }
+}
+
+void _initialize_ppc_kgdb_tdep(void);
+
+void
+_initialize_ppc_kgdb_tdep(void)
+{
+ gdbarch_register_osabi_sniffer(bfd_arch_powerpc,
+ bfd_target_elf_flavour,
+ fbsd_kernel_osabi_sniffer);
+ gdbarch_register_osabi (bfd_arch_powerpc, bfd_mach_ppc,
+ GDB_OSABI_FREEBSD_ELF_KERNEL, ppcfbsd_kernel_init_abi);
+ gdbarch_register_osabi (bfd_arch_powerpc, bfd_mach_ppc64,
+ GDB_OSABI_FREEBSD_ELF_KERNEL, ppcfbsd_kernel_init_abi);
+
+ /* Not sure about this one. */
+ gdbarch_register_osabi_sniffer(bfd_arch_rs6000,
+ bfd_target_elf_flavour,
+ fbsd_kernel_osabi_sniffer);
+ gdbarch_register_osabi (bfd_arch_rs6000, 0,
+ GDB_OSABI_FREEBSD_ELF_KERNEL, ppcfbsd_kernel_init_abi);
+}
diff --git a/devel/gdb/files/kgdb/sparc64fbsd-kern.c b/devel/gdb/files/kgdb/sparc64fbsd-kern.c
new file mode 100644
index 000000000000..57b0387a240c
--- /dev/null
+++ b/devel/gdb/files/kgdb/sparc64fbsd-kern.c
@@ -0,0 +1,319 @@
+/*
+ * Copyright (c) 2004 Marcel Moolenaar
+ * 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 AUTHORS ``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 AUTHORS 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$");
+
+#include <sys/types.h>
+#ifdef __sparc64__
+#include <machine/asm.h>
+#include <machine/pcb.h>
+#include <machine/frame.h>
+#endif
+#include <string.h>
+
+#include <defs.h>
+#include "gdbcore.h"
+#include "osabi.h"
+#include "regcache.h"
+#include <target.h>
+#include <frame-unwind.h>
+#include "solib.h"
+#include "trad-frame.h"
+
+#include <sparc-tdep.h>
+#include <sparc64-tdep.h>
+
+#include "kgdb.h"
+
+#ifdef __sparc64__
+static void
+sparc64fbsd_supply_pcb(struct regcache *regcache, CORE_ADDR pcb_addr)
+{
+ struct pcb pcb;
+
+ if (target_read_memory(pcb_addr, &pcb, sizeof(pcb)) != 0)
+ memset(&pcb, 0, sizeof(pcb));
+
+ regcache_raw_supply(regcache, SPARC_SP_REGNUM, (char *)&pcb.pcb_sp);
+ sparc_supply_rwindow(regcache, pcb.pcb_sp, -1);
+ regcache_raw_supply(regcache, SPARC64_PC_REGNUM, (char *)&pcb.pcb_pc);
+ pcb.pcb_pc += 4;
+ regcache_raw_supply(regcache, SPARC64_NPC_REGNUM, (char *)&pcb.pcb_pc);
+}
+#endif
+
+#define OFF_TF_SP (14 * 8)
+#define OFF_TF_TPC (25 * 8)
+#define OFF_TF_TNPC (24 * 8)
+#define OFF_TF_OUT (8 * 8)
+#define TRAPFRAME_SIZE (32 * 8)
+
+#ifdef __sparc64__
+_Static_assert(sizeof(struct trapframe) == TRAPFRAME_SIZE, "trapframe size");
+_Static_assert(offsetof(struct trapframe, tf_sp) == OFF_TF_SP, "tf_sp offset");
+_Static_assert(offsetof(struct trapframe, tf_tpc) == OFF_TF_TPC,
+ "tf_tpc offset");
+_Static_assert(offsetof(struct trapframe, tf_tnpc) == OFF_TF_TNPC,
+ "tf_tnpc offset");
+_Static_assert(offsetof(struct trapframe, tf_out) == OFF_TF_OUT,
+ "tf_out offset");
+#endif
+
+static struct sparc_frame_cache *
+sparc64fbsd_trapframe_cache (struct frame_info *this_frame, void **this_cache)
+{
+ struct sparc_frame_cache *cache;
+ CORE_ADDR fp, sp, trapframe_addr;
+ int regnum;
+
+ if (*this_cache)
+ return *this_cache;
+
+ cache = sparc_frame_cache (this_frame, this_cache);
+ gdb_assert (cache == *this_cache);
+
+ fp = get_frame_register_unsigned (this_frame, SPARC_FP_REGNUM);
+ trapframe_addr = fp + BIAS - TRAPFRAME_SIZE;
+ sp = get_frame_register_unsigned (this_frame, SPARC_SP_REGNUM);
+
+ cache->saved_regs = trad_frame_alloc_saved_regs (this_frame);
+
+ cache->saved_regs[SPARC_SP_REGNUM].addr = trapframe_addr + OFF_TF_SP;
+#ifdef notyet
+ cache->saved_regs[SPARC64_STATE_REGNUM].addr = trapframe_addr + OFF_TF_TSTATE;
+#endif
+ cache->saved_regs[SPARC64_PC_REGNUM].addr = trapframe_addr + OFF_TF_TPC;
+ cache->saved_regs[SPARC64_NPC_REGNUM].addr = trapframe_addr + OFF_TF_TNPC;
+ for (regnum = SPARC_O0_REGNUM; regnum <= SPARC_O7_REGNUM; regnum++)
+ cache->saved_regs[regnum].addr =
+ trapframe_addr + OFF_TF_OUT + (regnum - SPARC_O0_REGNUM) * 8;
+ for (regnum = SPARC_L0_REGNUM; regnum <= SPARC_I7_REGNUM; regnum++)
+ cache->saved_regs[regnum].addr =
+ sp + BIAS + (regnum - SPARC_L0_REGNUM) * 8;
+
+ return cache;
+}
+
+static void
+sparc64fbsd_trapframe_this_id (struct frame_info *this_frame,
+ void **this_cache, struct frame_id *this_id)
+{
+ struct sparc_frame_cache *cache =
+ sparc64fbsd_trapframe_cache (this_frame, this_cache);
+
+ (*this_id) = frame_id_build (cache->base, cache->pc);
+}
+
+static struct value *
+sparc64fbsd_trapframe_prev_register (struct frame_info *this_frame,
+ void **this_cache, int regnum)
+{
+ struct sparc_frame_cache *cache =
+ sparc64fbsd_trapframe_cache (this_frame, this_cache);
+
+ return trad_frame_get_prev_register (this_frame, cache->saved_regs, regnum);
+}
+
+static int
+sparc64fbsd_trapframe_sniffer (const struct frame_unwind *self,
+ struct frame_info *this_frame,
+ void **this_cache)
+{
+ CORE_ADDR pc;
+ const char *name;
+
+ pc = get_frame_address_in_block (this_frame);
+ find_pc_partial_function (pc, &name, NULL, NULL);
+ if (name && (strcmp(name, "tl0_intr") == 0
+ || strcmp(name, "tl0_trap") == 0
+ || strcmp(name, "tl1_intr") == 0
+ || strcmp(name, "tl1_trap") == 0))
+ return 1;
+
+ return 0;
+}
+
+static const struct frame_unwind sparc64fbsd_trapframe_unwind =
+{
+ NORMAL_FRAME,
+ default_frame_unwind_stop_reason,
+ sparc64fbsd_trapframe_this_id,
+ sparc64fbsd_trapframe_prev_register,
+ NULL,
+ sparc64fbsd_trapframe_sniffer
+};
+
+#if 0
+struct kgdb_frame_cache {
+ CORE_ADDR pc;
+ CORE_ADDR sp;
+ CORE_ADDR fp;
+};
+
+static struct kgdb_frame_cache *
+kgdb_trgt_frame_cache(struct frame_info *next_frame, void **this_cache)
+{
+ char buf[MAX_REGISTER_SIZE];
+ struct kgdb_frame_cache *cache;
+
+ cache = *this_cache;
+ if (cache == NULL) {
+ cache = FRAME_OBSTACK_ZALLOC(struct kgdb_frame_cache);
+ *this_cache = cache;
+ cache->pc = frame_func_unwind(next_frame);
+ frame_unwind_register(next_frame, SPARC_SP_REGNUM, buf);
+ cache->sp = extract_unsigned_integer(buf,
+ register_size(current_gdbarch, SPARC_SP_REGNUM));
+ frame_unwind_register(next_frame, SPARC_FP_REGNUM, buf);
+ cache->fp = extract_unsigned_integer(buf,
+ register_size(current_gdbarch, SPARC_FP_REGNUM));
+ cache->fp += BIAS - sizeof(struct trapframe);
+ }
+ return (cache);
+}
+
+static void
+kgdb_trgt_trapframe_this_id(struct frame_info *next_frame, void **this_cache,
+ struct frame_id *this_id)
+{
+ struct kgdb_frame_cache *cache;
+
+ cache = kgdb_trgt_frame_cache(next_frame, this_cache);
+ *this_id = frame_id_build(cache->sp, cache->pc);
+}
+
+static void
+kgdb_trgt_trapframe_prev_register(struct frame_info *next_frame,
+ void **this_cache, int regnum, int *optimizedp, enum lval_type *lvalp,
+ CORE_ADDR *addrp, int *realnump, void *valuep)
+{
+ char dummy_valuep[MAX_REGISTER_SIZE];
+ struct kgdb_frame_cache *cache;
+ int ofs, regsz;
+
+ regsz = register_size(current_gdbarch, regnum);
+
+ if (valuep == NULL)
+ valuep = dummy_valuep;
+ memset(valuep, 0, regsz);
+ *optimizedp = 0;
+ *addrp = 0;
+ *lvalp = not_lval;
+ *realnump = -1;
+
+ cache = kgdb_trgt_frame_cache(next_frame, this_cache);
+
+ switch (regnum) {
+ case SPARC_SP_REGNUM:
+ ofs = offsetof(struct trapframe, tf_sp);
+ break;
+ case SPARC64_PC_REGNUM:
+ ofs = offsetof(struct trapframe, tf_tpc);
+ break;
+ case SPARC64_NPC_REGNUM:
+ ofs = offsetof(struct trapframe, tf_tnpc);
+ break;
+ case SPARC_O0_REGNUM:
+ case SPARC_O1_REGNUM:
+ case SPARC_O2_REGNUM:
+ case SPARC_O3_REGNUM:
+ case SPARC_O4_REGNUM:
+ case SPARC_O5_REGNUM:
+ case SPARC_O7_REGNUM:
+ ofs = offsetof(struct trapframe, tf_out) +
+ (regnum - SPARC_O0_REGNUM) * 8;
+ break;
+ default:
+ if (regnum >= SPARC_L0_REGNUM && regnum <= SPARC_I7_REGNUM) {
+ ofs = (regnum - SPARC_L0_REGNUM) * 8;
+ *addrp = cache->sp + BIAS + ofs;
+ *lvalp = lval_memory;
+ target_read_memory(*addrp, valuep, regsz);
+ }
+ return;
+ }
+
+ *addrp = cache->fp + ofs;
+ *lvalp = lval_memory;
+ target_read_memory(*addrp, valuep, regsz);
+}
+
+static const struct frame_unwind kgdb_trgt_trapframe_unwind = {
+ UNKNOWN_FRAME,
+ &kgdb_trgt_trapframe_this_id,
+ &kgdb_trgt_trapframe_prev_register
+};
+
+const struct frame_unwind *
+kgdb_trgt_trapframe_sniffer(struct frame_info *next_frame)
+{
+ char *pname;
+ CORE_ADDR pc;
+
+ pc = frame_func_unwind(next_frame);
+ pname = NULL;
+ find_pc_partial_function(pc, &pname, NULL, NULL);
+ if (pname == NULL)
+ return (NULL);
+ if (strcmp(pname, "tl0_intr") == 0 ||
+ strcmp(pname, "tl0_trap") == 0 ||
+ strcmp(pname, "tl1_intr") == 0 ||
+ strcmp(pname, "tl1_trap") == 0)
+ return (&kgdb_trgt_trapframe_unwind);
+ /* printf("%s: %lx =%s\n", __func__, pc, pname); */
+ return (NULL);
+}
+#endif
+
+static void
+sparc64fbsd_kernel_init_abi(struct gdbarch_info info, struct gdbarch *gdbarch)
+{
+
+ sparc64_init_abi(info, gdbarch);
+
+ frame_unwind_prepend_unwinder(gdbarch, &sparc64fbsd_trapframe_unwind);
+
+ set_solib_ops(gdbarch, &kld_so_ops);
+
+#ifdef __sparc64__
+ fbsd_vmcore_set_supply_pcb(gdbarch, sparc64fbsd_supply_pcb);
+ fbsd_vmcore_set_cpu_pcb_addr(gdbarch, kgdb_trgt_stop_pcb);
+#endif
+}
+
+void _initialize_sparc64_kgdb_tdep(void);
+
+void
+_initialize_sparc64_kgdb_tdep(void)
+{
+ gdbarch_register_osabi_sniffer(bfd_arch_sparc,
+ bfd_target_elf_flavour,
+ fbsd_kernel_osabi_sniffer);
+ gdbarch_register_osabi (bfd_arch_sparc, bfd_mach_sparc_v9,
+ GDB_OSABI_FREEBSD_ELF_KERNEL, sparc64fbsd_kernel_init_abi);
+}
+
diff --git a/devel/gdb/pkg-plist b/devel/gdb/pkg-plist
index 542a9bc4dbfc..64a3fe2a0ee2 100644
--- a/devel/gdb/pkg-plist
+++ b/devel/gdb/pkg-plist
@@ -1,6 +1,8 @@
%%GDB_LINK%%bin/gdb
+%%GDB_LINK%%%%KGDB%%bin/kgdb
bin/gdb%%VER%%
%%TUI%%bin/gdbtui%%VER%%
+%%KGDB%%bin/kgdb%%VER%%
man/man1/gdb%%VER%%.1.gz
%%PYTHON%%%%DATADIR%%%%VER%%/python/gdb/__init__.py
%%PYTHON%%%%DATADIR%%%%VER%%/python/gdb/FrameDecorator.py