Page Menu
Home
FreeBSD
Search
Configure Global Search
Log In
Files
F108238294
D3727.diff
No One
Temporary
Actions
View File
Edit File
Delete File
View Transforms
Subscribe
Mute Notifications
Flag For Later
Award Token
Size
113 KB
Referenced Files
None
Subscribers
None
D3727.diff
View Options
Index: head/devel/gdb/Makefile
===================================================================
--- head/devel/gdb/Makefile
+++ head/devel/gdb/Makefile
@@ -32,7 +32,7 @@
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= 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 @@
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 @@
${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 )
Index: head/devel/gdb/files/extrapatch-kgdb
===================================================================
--- head/devel/gdb/files/extrapatch-kgdb
+++ head/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);
+
Index: head/devel/gdb/files/extrapatch-kgdb-configure.tgt-plain
===================================================================
--- head/devel/gdb/files/extrapatch-kgdb-configure.tgt-plain
+++ head/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
Index: head/devel/gdb/files/extrapatch-kgdb-configure.tgt-threads
===================================================================
--- head/devel/gdb/files/extrapatch-kgdb-configure.tgt-threads
+++ head/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
Index: head/devel/gdb/files/kgdb/amd64fbsd-kern.c
===================================================================
--- head/devel/gdb/files/kgdb/amd64fbsd-kern.c
+++ head/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
+}
Index: head/devel/gdb/files/kgdb/fbsd-kld.c
===================================================================
--- head/devel/gdb/files/kgdb/fbsd-kld.c
+++ head/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, §ions, §ions_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, ¤t_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);
+}
Index: head/devel/gdb/files/kgdb/fbsd-kthr.c
===================================================================
--- head/devel/gdb/files/kgdb/fbsd-kthr.c
+++ head/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);
+}
Index: head/devel/gdb/files/kgdb/fbsd-kvm.c
===================================================================
--- head/devel/gdb/files/kgdb/fbsd-kvm.c
+++ head/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);
+}
Index: head/devel/gdb/files/kgdb/i386fbsd-kern.c
===================================================================
--- head/devel/gdb/files/kgdb/i386fbsd-kern.c
+++ head/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
+}
Index: head/devel/gdb/files/kgdb/kgdb-main.c
===================================================================
--- head/devel/gdb/files/kgdb/kgdb-main.c
+++ head/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));
+}
Index: head/devel/gdb/files/kgdb/kgdb.h
===================================================================
--- head/devel/gdb/files/kgdb/kgdb.h
+++ head/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_ */
Index: head/devel/gdb/files/kgdb/ppcfbsd-kern.c
===================================================================
--- head/devel/gdb/files/kgdb/ppcfbsd-kern.c
+++ head/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);
+}
Index: head/devel/gdb/files/kgdb/sparc64fbsd-kern.c
===================================================================
--- head/devel/gdb/files/kgdb/sparc64fbsd-kern.c
+++ head/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);
+}
+
Index: head/devel/gdb/pkg-plist
===================================================================
--- head/devel/gdb/pkg-plist
+++ head/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
File Metadata
Details
Attached
Mime Type
text/plain
Expires
Thu, Jan 23, 11:51 PM (20 h, 25 m)
Storage Engine
blob
Storage Format
Raw Data
Storage Handle
16068074
Default Alt Text
D3727.diff (113 KB)
Attached To
Mode
D3727: Add a KGDB option to the devel/gdb port.
Attached
Detach File
Event Timeline
Log In to Comment