summaryrefslogtreecommitdiffstats
path: root/gnu
diff options
context:
space:
mode:
authoriedowse <iedowse@FreeBSD.org>2003-03-21 00:30:53 +0000
committeriedowse <iedowse@FreeBSD.org>2003-03-21 00:30:53 +0000
commit2c7df26ff68fffa33e908dde9f23c21843e909c1 (patch)
tree9017d433e325550c546ea24b5a1017aa7b1c752d /gnu
parent18bbff56056cc6fd3c51a8a21a50f257c2ef1fcd (diff)
downloadFreeBSD-src-2c7df26ff68fffa33e908dde9f23c21843e909c1.zip
FreeBSD-src-2c7df26ff68fffa33e908dde9f23c21843e909c1.tar.gz
Attempt to automatically read in kernel module symbols when a live
or dead kernel core is loaded into gdb. This extends gdb's existing shared library support, so the "info sharedlibrary", "sharedlibrary" and "nosharedlibrary" commands can be used to view and change the list of loaded symbol files. The current implementation is more than a kludge however, and it will not always manage to find the .ko.debug file corresponding to the loaded module. In particular, for modules whose build directory cannot be easily guessed from the module name such as all the netgraph modules, the debug version of the .ko will not be found automatically. The logic for finding the module file first attempts to guess at the module build directory by parsing the version[] string. Then using that directory ($DIR), it tries the following paths in turn: ./<module>.ko.debug ./<module>.ko $DIR/<module>.ko.debug $DIR/<module>.ko /boot/kernel/<module>.ko.debug /boot/kernel/<module>.ko Approved by: obrien, mp
Diffstat (limited to 'gnu')
-rw-r--r--gnu/usr.bin/binutils/gdb/Makefile2
-rw-r--r--gnu/usr.bin/binutils/gdb/fbsd-kgdb.h1
-rw-r--r--gnu/usr.bin/binutils/gdb/kvm-fbsd.c31
-rw-r--r--gnu/usr.bin/binutils/gdb/solib-fbsd-kld.c298
4 files changed, 330 insertions, 2 deletions
diff --git a/gnu/usr.bin/binutils/gdb/Makefile b/gnu/usr.bin/binutils/gdb/Makefile
index aebd002..f30885a 100644
--- a/gnu/usr.bin/binutils/gdb/Makefile
+++ b/gnu/usr.bin/binutils/gdb/Makefile
@@ -39,7 +39,7 @@ XSRCS= annotate.c arch-utils.c ax-general.c ax-gdb.c bcache.c \
scm-exp.c scm-lang.c scm-valprint.c \
coffread.c dbxread.c dwarfread.c dwarf2read.c elfread.c \
solib.c solib-svr4.c solib-legacy.c
-XSRCS+= freebsd-uthread.c kvm-fbsd.c
+XSRCS+= freebsd-uthread.c kvm-fbsd.c solib-fbsd-kld.c
SRCS= init.c ${XSRCS} nm.h tm.h xm.h gdbversion.c xregex.h
.if exists(${.CURDIR}/Makefile.${TARGET_ARCH})
diff --git a/gnu/usr.bin/binutils/gdb/fbsd-kgdb.h b/gnu/usr.bin/binutils/gdb/fbsd-kgdb.h
index e5dbf5f..e774436 100644
--- a/gnu/usr.bin/binutils/gdb/fbsd-kgdb.h
+++ b/gnu/usr.bin/binutils/gdb/fbsd-kgdb.h
@@ -7,6 +7,7 @@
extern int kernel_debugging;
extern int kernel_writablecore;
+extern struct target_so_ops kgdb_so_ops;
#define ADDITIONAL_OPTIONS \
{"kernel", no_argument, &kernel_debugging, 1}, \
diff --git a/gnu/usr.bin/binutils/gdb/kvm-fbsd.c b/gnu/usr.bin/binutils/gdb/kvm-fbsd.c
index 23dbeaf..a9d85e8 100644
--- a/gnu/usr.bin/binutils/gdb/kvm-fbsd.c
+++ b/gnu/usr.bin/binutils/gdb/kvm-fbsd.c
@@ -56,6 +56,7 @@ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
#include "bfd.h"
#include "target.h"
#include "gdbcore.h"
+#include "solist.h"
static void
kcore_files_info (struct target_ops *);
@@ -73,6 +74,10 @@ xfer_mem (CORE_ADDR, char *, int, int, struct mem_attrib *,
static int
xfer_umem (CORE_ADDR, char *, int, int);
+#ifdef SOLIB_ADD
+static int kcore_solib_add_stub (PTR);
+#endif
+
static char *core_file;
static kvm_t *core_kd;
static struct pcb cur_pcb;
@@ -210,6 +215,12 @@ kcore_close (int quitting)
inferior_ptid = null_ptid; /* Avoid confusion from thread stuff. */
+ /* Clear out solib state while the bfd is still open. See
+ comments in clear_solib in solib.c. */
+#ifdef CLEAR_SOLIB
+ CLEAR_SOLIB ();
+#endif
+
if (core_kd)
{
kvm_close (core_kd);
@@ -306,7 +317,16 @@ kcore_open (char *filename /* the core file */, int from_tty)
printf ("---\n");
}
- if (!ontop)
+ if (ontop)
+ {
+ /* Add symbols and section mappings for any kernel modules. */
+#ifdef SOLIB_ADD
+ current_target_so_ops = &kgdb_so_ops;
+ catch_errors (kcore_solib_add_stub, &from_tty, (char *) 0,
+ RETURN_MASK_ALL);
+#endif
+ }
+ else
{
warning ("you won't be able to access this core file until you terminate\n"
"your %s; do ``info files''", target_longname);
@@ -712,6 +732,15 @@ set_proc_cmd (char *arg, int from_tty)
error ("invalid proc address");
}
+#ifdef SOLIB_ADD
+static int
+kcore_solib_add_stub (PTR from_ttyp)
+{
+ SOLIB_ADD (NULL, *(int *) from_ttyp, &current_target, auto_solib_add);
+ return 0;
+}
+#endif /* SOLIB_ADD */
+
void
_initialize_kcorelow (void)
{
diff --git a/gnu/usr.bin/binutils/gdb/solib-fbsd-kld.c b/gnu/usr.bin/binutils/gdb/solib-fbsd-kld.c
new file mode 100644
index 0000000..72d4807
--- /dev/null
+++ b/gnu/usr.bin/binutils/gdb/solib-fbsd-kld.c
@@ -0,0 +1,298 @@
+/* Handle FreeBSD kernel modules as shared libraries.
+ Copyright 1990, 1991, 1992, 1993, 1994, 1995, 1996, 1998, 1999, 2000,
+ 2001
+ Free Software Foundation, Inc.
+
+ This file is part of GDB.
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 59 Temple Place - Suite 330,
+ Boston, MA 02111-1307, USA. */
+
+/* $FreeBSD$ */
+
+#include <sys/param.h>
+#include <sys/queue.h>
+#include <sys/stat.h>
+#define _KERNEL
+#include <sys/linker.h>
+#undef _KERNEL
+
+/* XXX, kludge to avoid duplicate definitions while sys/linker.h is used. */
+#define _ELF_COMMON_H
+
+#include "defs.h"
+#include "symtab.h"
+#include "bfd.h"
+#include "symfile.h"
+#include "objfiles.h"
+#include "gdbcore.h"
+#include "target.h"
+#include "inferior.h"
+
+#include "solist.h"
+
+struct lm_info
+ {
+ CORE_ADDR address;
+ };
+
+static int try_modpath (char *buf, int buflen, char *fmt, ...);
+static char *guess_modpath (char *modname);
+
+static void
+kgdb_relocate_section_addresses (struct so_list *so,
+ struct section_table *sec)
+{
+ sec->addr += so->lm_info->address;
+ sec->endaddr += so->lm_info->address;
+}
+
+static int
+kgdb_open_symbol_file_object (void *from_ttyp)
+{
+ warning ("kgdb_open_symbol_file_object called\n");
+ return 0;
+}
+
+static struct so_list *
+kgdb_current_sos (void)
+{
+ linker_file_list_t linker_files;
+ struct linker_file lfile;
+ struct minimal_symbol *msymbol;
+ struct linker_file *lfilek;
+ struct so_list *head = NULL;
+ struct so_list **link_ptr = &head;
+
+ CORE_ADDR lfiles_addr;
+
+ msymbol = lookup_minimal_symbol ("linker_files", NULL, symfile_objfile);
+ if (msymbol == NULL || SYMBOL_VALUE_ADDRESS (msymbol) == 0)
+ {
+ warning ("failed to find linker_files symbol\n");
+ return 0;
+ }
+ lfiles_addr = SYMBOL_VALUE_ADDRESS (msymbol);
+ if (target_read_memory (lfiles_addr, (char *)&linker_files,
+ sizeof (linker_files)))
+ {
+ warning ("failed to read linker_files data\n");
+ return 0;
+ }
+ for (lfilek = TAILQ_FIRST (&linker_files); lfilek != NULL;
+ lfilek = TAILQ_NEXT (&lfile, link))
+ {
+ struct so_list *new;
+ struct cleanup *old_chain;
+ char *buf;
+ int errcode;
+
+ if (target_read_memory ((CORE_ADDR) lfilek, (char *) &lfile,
+ sizeof (lfile)))
+ {
+ warning ("failed to read linker file data at %p\n", lfilek);
+ return 0;
+ }
+ target_read_string ((CORE_ADDR) lfile.filename, &buf,
+ SO_NAME_MAX_PATH_SIZE - 1, &errcode);
+ if (errcode != 0)
+ {
+ warning ("cannot read linker file pathname: %s\n",
+ safe_strerror (errcode));
+ return 0;
+ }
+ if (strlen (buf) < 3 || strcmp (&buf[strlen (buf) - 3], ".ko") != 0)
+ {
+ xfree (buf);
+ continue;
+ }
+
+ new = (struct so_list *) xmalloc (sizeof (struct so_list));
+ old_chain = make_cleanup (xfree, new);
+
+ memset (new, 0, sizeof (*new));
+
+ new->lm_info = xmalloc (sizeof (struct lm_info));
+ make_cleanup (xfree, new->lm_info);
+
+ new->lm_info->address = (CORE_ADDR) lfile.address;
+
+ strncpy (new->so_original_name, buf, SO_NAME_MAX_PATH_SIZE - 1);
+ new->so_original_name[SO_NAME_MAX_PATH_SIZE - 1] = '\0';
+ xfree (buf);
+ snprintf (new->so_name, SO_NAME_MAX_PATH_SIZE, "%s",
+ guess_modpath (new->so_original_name));
+
+ new->next = NULL;
+ *link_ptr = new;
+ link_ptr = &new->next;
+
+ discard_cleanups (old_chain);
+ }
+ return head;
+}
+
+static int
+kgdb_in_dynsym_resolve_code (CORE_ADDR pc)
+{
+ warning ("kgdb_in_dynsym_resolve_code called\n");
+ return 0;
+}
+
+static void
+kgdb_special_symbol_handling (void)
+{
+}
+
+static void
+kgdb_solib_create_inferior_hook (void)
+{
+ warning ("kgdb_solib_create_inferior_hook called\n");
+}
+
+static void
+kgdb_clear_solib (void)
+{
+}
+
+static void
+kgdb_free_so (struct so_list *so)
+{
+ xfree (so->lm_info);
+}
+
+static int
+try_modpath (char *buf, int buflen, char *fmt, ...)
+{
+ struct stat sb;
+ va_list ap;
+
+ va_start (ap, fmt);
+ vsnprintf (buf, buflen, fmt, ap);
+ va_end(ap);
+
+ return (stat (buf, &sb) == 0);
+}
+
+static char *
+guess_modpath (char *modname)
+{
+ static char buf[2048], moddir[128], syspath[1024];
+ struct minimal_symbol *msymbol;
+ char *kernpath, *objpath, *p, *version;
+ int errcode, n, syspathlen;
+
+ /* Set default module location */
+ snprintf (buf, sizeof (buf), "/boot/kernel/%s", modname);
+
+ /* Guess at the subdirectory off sys/modules. XXX, only sometimes correct */
+ n = strlen (modname);
+ if (n > 3 && strcmp (&modname[n - 3], ".ko") == 0)
+ n -= 3;
+ snprintf (moddir, sizeof (moddir), "%.*s", n, modname);
+
+ /* Try to locate the kernel compile location from version[] */
+ msymbol = lookup_minimal_symbol ("version", NULL, symfile_objfile);
+ if (msymbol == NULL || SYMBOL_VALUE_ADDRESS (msymbol) == 0)
+ {
+ warning("cannot find `version' symbol; using default module path\n");
+ return buf;
+ }
+ target_read_string (SYMBOL_VALUE_ADDRESS (msymbol), &version, 2048, &errcode);
+ if (errcode != 0)
+ {
+ warning ("cannot read `version' string; using default module path: %s\n",
+ safe_strerror (errcode));
+ return buf;
+ }
+
+ /* Find the kernel build path after user@host: on the second line. */
+ if ((p = strchr (version, '\n')) == NULL ||
+ (kernpath = strchr (p, ':')) == NULL ||
+ (p = strchr (kernpath, '\n')) == NULL)
+ {
+ warning ("cannot parse version[]; using default module path\n");
+ xfree (version);
+ return buf;
+ }
+ kernpath++;
+ *p = '\0';
+
+ /*
+ * Find the absolute path to src/sys by skipping back over path
+ * components until we find a "/sys/".
+ */
+ syspathlen = 0;
+ while (p > kernpath && syspathlen == 0)
+ {
+ while (p > kernpath && *p != '/')
+ p--;
+ if (strncmp (p, "/sys/", 5) == 0)
+ syspathlen = p - kernpath + 4;
+ else if (p > kernpath)
+ p--;
+ }
+ if (syspathlen == 0)
+ {
+ warning ("cannot find /sys/ in `%s'; using default module path\n",
+ kernpath);
+ xfree (version);
+ return buf;
+ }
+ /*
+ * For kernels compiled with buildkernel, the object path will have
+ * been prepended to the /sys/ path in `kernpath'.
+ */
+ objpath = getenv ("MAKEOBJDIRPREFIX");
+ if (objpath == NULL)
+ objpath = "/usr/obj";
+ n = strlen (objpath);
+ if (syspathlen > n + 1 && strncmp (kernpath, objpath, n) == 0 &&
+ kernpath[n] == '/')
+ snprintf (syspath, sizeof (syspath), "%.*s", syspathlen - n, kernpath + n);
+ else
+ snprintf (syspath, sizeof (syspath), "%.*s", syspathlen, kernpath);
+
+ /* Now try to find the module file */
+ if (!try_modpath (buf, sizeof (buf), "./%s.debug", modname) &&
+ !try_modpath (buf, sizeof (buf), "./%s", modname) && !try_modpath (buf,
+ sizeof (buf), "%s/modules%s/modules/%s/%s.debug", kernpath, syspath,
+ moddir, modname) && !try_modpath (buf, sizeof (buf),
+ "%s/modules%s/modules/%s/%s", kernpath, syspath, moddir, modname) &&
+ !try_modpath (buf, sizeof (buf), "/boot/kernel/%s.debug", modname) &&
+ !try_modpath (buf, sizeof (buf), "/boot/kernel/%s", modname))
+ {
+ warning ("cannot find file for module %s\n", modname);
+ snprintf (buf, sizeof (buf), "%s", modname);
+ }
+ xfree (version);
+
+ return buf;
+}
+
+struct target_so_ops kgdb_so_ops;
+
+void
+_initialize_kgdb_solib (void)
+{
+ kgdb_so_ops.relocate_section_addresses = kgdb_relocate_section_addresses;
+ kgdb_so_ops.free_so = kgdb_free_so;
+ kgdb_so_ops.clear_solib = kgdb_clear_solib;
+ kgdb_so_ops.solib_create_inferior_hook = kgdb_solib_create_inferior_hook;
+ kgdb_so_ops.special_symbol_handling = kgdb_special_symbol_handling;
+ kgdb_so_ops.current_sos = kgdb_current_sos;
+ kgdb_so_ops.open_symbol_file_object = kgdb_open_symbol_file_object;
+ kgdb_so_ops.in_dynsym_resolve_code = kgdb_in_dynsym_resolve_code;
+}
OpenPOWER on IntegriCloud