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
This commit is contained in:
Ian Dowse 2003-03-21 00:30:53 +00:00
parent e3940ce7c3
commit ea0d04f36e
Notes: svn2git 2020-12-20 02:59:44 +00:00
svn path=/head/; revision=112454
4 changed files with 330 additions and 2 deletions

View File

@ -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})

View File

@ -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}, \

View File

@ -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)
{

View File

@ -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;
}