diff --git a/gnu/usr.bin/binutils/gdb/Makefile b/gnu/usr.bin/binutils/gdb/Makefile index aebd00230b2f..f30885ad5224 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 e5dbf5f57c7b..e7744363106f 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 23dbeaf6410c..a9d85e825c9b 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, ¤t_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 000000000000..72d4807fad8d --- /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 +#include +#include +#define _KERNEL +#include +#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; +}