Skip site navigation (1)Skip section navigation (2)
Date:      Mon, 07 Oct 2002 17:09:39 +0100
From:      Ian Dowse <iedowse@maths.tcd.ie>
To:        hackers@freebsd.org
Subject:   gdb support for kernel modules
Message-ID:   <200210071709.aa25499@salmon.maths.tcd.ie>

next in thread | raw e-mail | index | archive | help

This is something I have been meaning to investigate for a while:
when gdb encounters a userland executable that uses shared libraries
it automatically adds the symbols from each library, so it seemed
likely that gdb could be made do the same thing with kernel modules.
I am aware of the existence of `gdbmods' etc, but it would be nicer
to have the support built in to gdb.

Anyway, below is a proof-of-concept patch that does the basics, but
among other things, its logic for locating the kernel module files
needs a lot of work - currently it just assumes /boot/kernel/<module>,
which is almost never what you actually want. It works for debugging
vmcores and live /dev/mem access, but I don't know if it can work
for remote debugging. Does anybody know gdb internals enough to
comment on how this is done or suggest improvements?

Ian

# gdb -k kernel.debug /dev/mem
...
This GDB was configured as "i386-undermydesk-freebsd"...
panic messages:
---
---

warning: skipping first file (kernel)

Reading symbols from /boot/kernel/ufs.ko...done.
Loaded symbols for /boot/kernel/ufs.ko
Reading symbols from /boot/kernel/md.ko...done.
Loaded symbols for /boot/kernel/md.ko
Reading symbols from /boot/kernel/vinum.ko...done.
Loaded symbols for /boot/kernel/vinum.ko
#0  mi_switch () at ../../../kern/kern_synch.c:849
849             td->td_kse->ke_oncpu = PCPU_GET(cpuid);
(kgdb) info sharedlibrary 
warning: skipping first file (kernel)

From        To          Syms Read   Shared Object Library
0xc1098dd0  0xc10bfc10  Yes         /boot/kernel/ufs.ko
0xc11e24d0  0xc11e4270  Yes         /boot/kernel/md.ko
0xc10cf940  0xc10ddc30  Yes         /boot/kernel/vinum.ko
(kgdb) proc 316
(kgdb) bt
#0  mi_switch () at ../../../kern/kern_synch.c:849
#1  0xc01b7d14 in msleep (ident=0xc1292e00, mtx=0x0, priority=76, wmesg=0x0, 
    timo=0) at ../../../kern/kern_synch.c:559
#2  0xc11e3052 in md_kthread (arg=0xc1292e00) at /usr/src/sys/dev/md/md.c:578
#3  0xc019d2e5 in fork_exit (callout=0xc11e2fd0 <md_kthread>, arg=0x0, 
    frame=0x0) at ../../../kern/kern_fork.c:853
(kgdb)


Index: Makefile
===================================================================
RCS file: /dump/FreeBSD-CVS/src/gnu/usr.bin/binutils/gdb/Makefile,v
retrieving revision 1.61
diff -u -r1.61 Makefile
--- Makefile	29 Jun 2002 03:16:10 -0000	1.61
+++ Makefile	7 Oct 2002 10:31:41 -0000
@@ -37,7 +37,7 @@
 	ui-file.c ui-out.c wrapper.c cli-out.c \
 	cli-cmds.c cli-cmds.h cli-decode.c cli-decode.h	cli-script.c	\
 	cli-script.h cli-setshow.c cli-setshow.h cli-utils.c cli-utils.h
-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})
Index: fbsd-kgdb.h
===================================================================
RCS file: /dump/FreeBSD-CVS/src/gnu/usr.bin/binutils/gdb/fbsd-kgdb.h,v
retrieving revision 1.3
diff -u -r1.3 fbsd-kgdb.h
--- fbsd-kgdb.h	18 Sep 2002 16:20:49 -0000	1.3
+++ fbsd-kgdb.h	6 Oct 2002 23:32:14 -0000
@@ -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}, \
Index: kvm-fbsd.c
===================================================================
RCS file: /dump/FreeBSD-CVS/src/gnu/usr.bin/binutils/gdb/kvm-fbsd.c,v
retrieving revision 1.42
diff -u -r1.42 kvm-fbsd.c
--- kvm-fbsd.c	18 Sep 2002 16:19:05 -0000	1.42
+++ kvm-fbsd.c	6 Oct 2002 23:41:56 -0000
@@ -56,6 +56,7 @@
 #include "bfd.h"
 #include "target.h"
 #include "gdbcore.h"
+#include "solist.h"
 
 static void
 kcore_files_info (struct target_ops *);
@@ -72,6 +73,10 @@
 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;
@@ -209,6 +214,12 @@
 
   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);
@@ -305,7 +316,16 @@
       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);
@@ -651,6 +671,15 @@
   if (set_context ((CORE_ADDR) val))
     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)
Index: solib-fbsd-kld.c
===================================================================
RCS file: solib-fbsd-kld.c
diff -N solib-fbsd-kld.c
--- /dev/null	1 Jan 1970 00:00:00 -0000
+++ solib-fbsd-kld.c	7 Oct 2002 10:39:48 -0000
@@ -0,0 +1,181 @@
+/* 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.  */
+
+#include <sys/param.h>
+#include <sys/queue.h>
+#define _KERNEL
+#include <sys/linker.h>
+#undef _KERNEL
+
+#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 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 (lfilek == TAILQ_FIRST (&linker_files)) /* XXX kernel always first? */
+	{
+	  warning ("skipping first file (%s)\n", buf);
+	  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, "/boot/kernel/%s",
+	        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);
+}
+
+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;
+}


To Unsubscribe: send mail to majordomo@FreeBSD.org
with "unsubscribe freebsd-hackers" in the body of the message




Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi? <200210071709.aa25499>