This is the mail archive of the gdb-patches@sourceware.org mailing list for the GDB project.


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]
Other format: [Raw text]

[RFC v3 4/8] Add kernel module support for linux-kernel target


This patch implements module support for the new linux-kernel target by
adding a target_so_ops. In addition this patch adds handling for kernel
virtual addresses. This is necessary because kernel modules, unlike
task_structs, live in kernel virtual address space. Thus addresses need
to be translated before they can be read from. We achieve this by adding
an implementation for the targets to_xfer_partial hook, which translates
the addresses before passing them down to the target beneath.

gdb/ChangeLog:

    * lk-modules.h: New file.
    * lk-modules.c: New file.
    * lk-low.h (lk_hook_is_kvaddr, lk_hook_vtop)
    (lk_hook_get_module_text_offset): New arch dependent hooks.
    (sturct lk_private_hooks): Add new hooks.
    (LK_MODULES_NAME_LEN, LK_UTS_NAME_LEN): New define.
    * lk-low.c (lk-modules.h): New include.
    (lk_kvtop, restore_current_target, lk_xfer_partial): New functions.
    (lk_init_private_data): Declare needed debug symbols.
    (lk_try_push_target): Assert for new hooks and set solib_ops.
    (init_linux_kernel_ops): Add implementation for to_xfer_partial.
    * solib.c (get_solib_search_path): New function.
    * solib.h (get_solib_search_path): New export.
    * Makefile.in (SFILES, ALLDEPFILES): Add lk-modules.c.
    (HFILES_NO_SRCDIR): Add lk-modules.h.
    (ALL_TARGET_OBS): Add lk-modules.o.
    * configure.tgt (lk_target_obs): Add lk-modules.o.
---
 gdb/Makefile.in   |   4 +
 gdb/configure.tgt |   2 +-
 gdb/lk-low.c      | 101 +++++++++++++
 gdb/lk-low.h      |  24 ++++
 gdb/lk-modules.c  | 412 ++++++++++++++++++++++++++++++++++++++++++++++++++++++
 gdb/lk-modules.h  |  29 ++++
 gdb/solib.c       |   8 ++
 gdb/solib.h       |   5 +
 8 files changed, 584 insertions(+), 1 deletion(-)
 create mode 100644 gdb/lk-modules.c
 create mode 100644 gdb/lk-modules.h

diff --git a/gdb/Makefile.in b/gdb/Makefile.in
index 9387c66..251143b 100644
--- a/gdb/Makefile.in
+++ b/gdb/Makefile.in
@@ -819,6 +819,7 @@ ALL_TARGET_OBS = \
 	linux-tdep.o \
 	lk-lists.o \
 	lk-low.o \
+	lk-modules.o \
 	lm32-tdep.o \
 	m32c-tdep.o \
 	m32r-linux-tdep.o \
@@ -1107,6 +1108,7 @@ SFILES = \
 	linespec.c \
 	lk-lists.c \
 	lk-low.c \
+	lk-modules.c \
 	location.c \
 	m2-exp.y \
 	m2-lang.c \
@@ -1356,6 +1358,7 @@ HFILES_NO_SRCDIR = \
 	linux-tdep.h \
 	lk-lists.h \
 	lk-low.h \
+	lk-modules.h \
 	location.h \
 	m2-lang.h \
 	m32r-tdep.h \
@@ -2555,6 +2558,7 @@ ALLDEPFILES = \
 	linux-tdep.c \
 	lk-lists.c \
 	lk-low.c \
+	lk-modules.c \
 	lm32-tdep.c \
 	m32r-linux-nat.c \
 	m32r-linux-tdep.c \
diff --git a/gdb/configure.tgt b/gdb/configure.tgt
index 8d87fea..a16ccd7 100644
--- a/gdb/configure.tgt
+++ b/gdb/configure.tgt
@@ -36,7 +36,7 @@ esac
 
 # List of objectfiles for Linux kernel support.  To be included into *-linux*
 # targets wich support Linux kernel debugging.
-lk_target_obs="lk-lists.o lk-low.o"
+lk_target_obs="lk-lists.o lk-low.o lk-modules.o"
 
 # map target info into gdb names.
 
diff --git a/gdb/lk-low.c b/gdb/lk-low.c
index 768f228..c10f884 100644
--- a/gdb/lk-low.c
+++ b/gdb/lk-low.c
@@ -29,6 +29,7 @@
 #include "inferior.h"
 #include "lk-lists.h"
 #include "lk-low.h"
+#include "lk-modules.h"
 #include "objfiles.h"
 #include "observer.h"
 #include "solib.h"
@@ -536,6 +537,46 @@ lk_thread_name (struct target_ops *target, struct thread_info *ti)
   return buf;
 }
 
+/* Translate a kernel virtual address ADDR to a physical address.  */
+
+CORE_ADDR
+lk_kvtop (CORE_ADDR addr)
+{
+  CORE_ADDR pgd = lk_read_addr (LK_ADDR (init_mm)
+				+ LK_OFFSET (mm_struct, pgd));
+  return LK_HOOK->vtop (pgd, addr);
+}
+
+/* Restore current_target to TARGET.  */
+static void
+restore_current_target (void *target)
+{
+  current_target.beneath = (struct target_ops *) target;
+}
+
+/* Function for targets to_xfer_partial hook.  */
+
+enum target_xfer_status
+lk_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)
+{
+  enum target_xfer_status ret_val;
+  struct cleanup *old_chain = make_cleanup (restore_current_target, ops);
+
+  current_target.beneath = ops->beneath;
+
+  if (LK_HOOK->is_kvaddr (offset))
+    offset = lk_kvtop (offset);
+
+  ret_val =  ops->beneath->to_xfer_partial (ops->beneath, object, annex,
+					    readbuf, writebuf, offset, len,
+					    xfered_len);
+  do_cleanups (old_chain);
+  return ret_val;
+}
+
 /* Functions to initialize and free target_ops and its private data.  As well
    as functions for targets to_open/close/detach hooks.  */
 
@@ -571,6 +612,9 @@ lk_init_private ()
 /* Initialize architecture independent private data.  Must be called
    _after_ symbol tables were initialized.  */
 
+/* FIXME: throw error more fine-grained.  */
+/* FIXME: make independent of compile options.  */
+
 static void
 lk_init_private_data ()
 {
@@ -591,10 +635,61 @@ lk_init_private_data ()
 
   LK_DECLARE_FIELD (cpumask, bits);
 
+  LK_DECLARE_FIELD (mm_struct, pgd);
+
+  LK_DECLARE_FIELD (pgd_t, pgd);
+
+  LK_DECLARE_FIELD (module, list);
+  LK_DECLARE_FIELD (module, name);
+  LK_DECLARE_FIELD (module, source_list);
+  LK_DECLARE_FIELD (module, arch);
+  LK_DECLARE_FIELD (module, init);
+  LK_DECLARE_FIELD (module, percpu);
+  LK_DECLARE_FIELD (module, percpu_size);
+
+  /* Module offset moved to new struct module_layout with linux 4.5.
+     It must be checked in code which of this fields exist.  */
+  if (LK_DECLARE_FIELD_SILENT (module_layout, base)) /* linux 4.5+ */
+    {
+      LK_DECLARE_FIELD (module, init_layout);
+      LK_DECLARE_FIELD (module, core_layout);
+
+      LK_DECLARE_FIELD (module_layout, size);
+      LK_DECLARE_FIELD (module_layout, text_size);
+      LK_DECLARE_FIELD (module_layout, ro_size);
+    }
+  else if (LK_DECLARE_FIELD_SILENT (module, module_core)) /* linux -4.4 */
+    {
+      LK_DECLARE_FIELD (module, init_size);
+      LK_DECLARE_FIELD (module, core_size);
+
+      LK_DECLARE_FIELD (module, core_text_size);
+      LK_DECLARE_FIELD (module, core_ro_size);
+    }
+  else
+    {
+      error (_("Could not find module base.  Aborting."));
+    }
+
+  LK_DECLARE_FIELD (module_use, source_list);
+  LK_DECLARE_FIELD (module_use, source);
+
+  LK_DECLARE_FIELD (uts_namespace, name);
+
+  LK_DECLARE_STRUCT_ALIAS (new_utsname, utsname);
+  LK_DECLARE_STRUCT_ALIAS (old_utsname, utsname);
+  LK_DECLARE_STRUCT_ALIAS (oldold_utsname, utsname);
+  if (LK_STRUCT (utsname) == NULL)
+    error (_("Could not find struct utsname.  Aborting."));
+  LK_DECLARE_FIELD (utsname, version);
+  LK_DECLARE_FIELD (utsname, release);
+
   LK_DECLARE_ADDR (init_task);
   LK_DECLARE_ADDR (runqueues);
   LK_DECLARE_ADDR (__per_cpu_offset);
   LK_DECLARE_ADDR (init_mm);
+  LK_DECLARE_ADDR (modules);
+  LK_DECLARE_ADDR (init_uts_ns);
 
   LK_DECLARE_ADDR_ALIAS (__cpu_online_mask, cpu_online_mask);	/* linux 4.5+ */
   LK_DECLARE_ADDR_ALIAS (cpu_online_bits, cpu_online_mask);	/* linux -4.4 */
@@ -693,12 +788,17 @@ lk_try_push_target ()
   gdbarch_lk_init_private (gdbarch);
   /* Check for required arch hooks.  */
   gdb_assert (LK_HOOK->get_registers);
+  gdb_assert (LK_HOOK->is_kvaddr);
+  gdb_assert (LK_HOOK->vtop);
+  gdb_assert (LK_HOOK->get_module_text_offset);
 
   lk_init_ptid_map ();
   lk_update_thread_list (linux_kernel_ops);
 
   if (!target_is_pushed (linux_kernel_ops))
     push_target (linux_kernel_ops);
+
+  set_solib_ops (gdbarch, lk_modules_so_ops);
 }
 
 /* Function for targets to_open hook.  */
@@ -811,6 +911,7 @@ init_linux_kernel_ops (void)
   t->to_update_thread_list = lk_update_thread_list;
   t->to_pid_to_str = lk_pid_to_str;
   t->to_thread_name = lk_thread_name;
+  t->to_xfer_partial = lk_xfer_partial;
 
   t->to_stratum = thread_stratum;
   t->to_magic = OPS_MAGIC;
diff --git a/gdb/lk-low.h b/gdb/lk-low.h
index 292ef97..1d6e053 100644
--- a/gdb/lk-low.h
+++ b/gdb/lk-low.h
@@ -27,6 +27,8 @@ extern struct target_ops *linux_kernel_ops;
 /* Copy constants defined in Linux kernel.  */
 #define LK_TASK_COMM_LEN 16
 #define LK_BITS_PER_BYTE 8
+#define LK_MODULE_NAME_LEN 56
+#define LK_UTS_NAME_LEN 64
 
 /* Definitions used in linux kernel target.  */
 #define LK_CPU_INVAL -1U
@@ -204,6 +206,19 @@ typedef void (*lk_hook_get_registers) (CORE_ADDR task,
 				       struct regcache *regcache,
 				       int regnum);
 
+/* Hook to check if address ADDR is a kernel virtual address.
+   NOTE: This hook is called in the context of target beneath.  */
+typedef int (*lk_hook_is_kvaddr) (CORE_ADDR addr);
+
+/* Hook to translate virtual adress ADDR to a pysical address using page
+   table located at PGD.
+   NOTE: This hook is called in the context of target beneath.  */
+typedef CORE_ADDR (*lk_hook_vtop) (CORE_ADDR addr, CORE_ADDR pgd);
+
+/* Hook to get the offset between a modules base and the start of its
+   .text section.  */
+typedef CORE_ADDR (*lk_hook_get_module_text_offset) (CORE_ADDR mod);
+
 /* Hook to return the per_cpu_offset of cpu CPU.  Only architectures that
    do not use the __per_cpu_offset array to determin the offset have to
    supply this hook.  */
@@ -218,6 +233,15 @@ struct lk_private_hooks
   /* required */
   lk_hook_get_registers get_registers;
 
+  /* required */
+  lk_hook_is_kvaddr is_kvaddr;
+
+  /* required */
+  lk_hook_vtop vtop;
+
+  /* reqired */
+  lk_hook_get_module_text_offset get_module_text_offset;
+
   /* optional, required if __per_cpu_offset array is not used to determine
      offset.  */
   lk_hook_get_percpu_offset get_percpu_offset;
diff --git a/gdb/lk-modules.c b/gdb/lk-modules.c
new file mode 100644
index 0000000..f3c559d
--- /dev/null
+++ b/gdb/lk-modules.c
@@ -0,0 +1,412 @@
+/* Handle Linux kernel modules as shared libraries.
+
+   Copyright (C) 2016 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 3 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, see <http://www.gnu.org/licenses/>.  */
+
+#include "defs.h"
+
+#include "common/filestuff.h"
+#include "filenames.h"
+#include "gdbcmd.h"
+#include "gdbcore.h"
+#include "gdb_regex.h"
+#include "lk-lists.h"
+#include "lk-low.h"
+#include "lk-modules.h"
+#include "objfiles.h"
+#include "observer.h"
+#include "readline/readline.h"
+#include "solib.h"
+#include "solist.h"
+#include "utils.h"
+
+#include <unordered_map>
+#include <string>
+
+struct target_so_ops *lk_modules_so_ops = NULL;
+
+/* Info for single section type.  */
+
+struct lm_info_sec
+{
+  CORE_ADDR start;
+  CORE_ADDR offset;
+  unsigned int size;
+};
+
+/* Link map info to include in an allocated so_list entry.  */
+
+struct lm_info
+{
+  CORE_ADDR base;
+  unsigned int size;
+
+  struct lm_info_sec text;
+  struct lm_info_sec init_text;
+  struct lm_info_sec ro_data;
+  struct lm_info_sec rw_data;
+  struct lm_info_sec percpu;
+};
+
+/* Check if debug info for module NAME are loaded.  */
+
+bool
+lk_modules_debug_info_loaded (const std::string &name)
+{
+  struct so_list *so;
+
+  for (so = master_so_list (); so; so = so->next)
+    {
+      if (name == so->so_original_name)
+	return (so->symbols_loaded && objfile_has_symbols (so->objfile));
+    }
+
+  return false;
+}
+
+/* Replace tags, like '$release', with corresponding data in
+   solib_search_path.
+
+   Known tags:
+   $release	Linux kernel release, same as 'uname -r'
+
+   Returns the expanded path.  */
+
+static std::string
+lk_modules_expand_search_path ()
+{
+  char release[LK_UTS_NAME_LEN + 1];
+  CORE_ADDR utsname;
+
+  utsname = LK_ADDR (init_uts_ns) + LK_OFFSET (uts_namespace, name);
+  read_memory_string (utsname + LK_OFFSET (utsname, release),
+		      release, LK_UTS_NAME_LEN);
+  release[LK_UTS_NAME_LEN] = '\0';
+
+  std::string search_path = get_solib_search_path ();
+  substitute_path_component (search_path, "$release", release);
+
+  return search_path;
+}
+
+/* With kernel modules there is the problem that the kernel only stores
+   the modules name but not the path from wich it was loaded from.
+   Thus we need to map the name to a path GDB can read from.  We use file
+   modules.order to do so.  It is created by kbuild containing the order in
+   which the modules appear in the Makefile and is also used by modprobe.
+   The drawback of this method is that it needs the modules.order file and
+   all relative paths, starting from <solib-search-path>, must be exactly the
+   same as decribed in it.  */
+
+/* Open file <solib-search-path>/modules.order and return its file
+   pointer.  */
+
+FILE *
+lk_modules_open_mod_order ()
+{
+  FILE *mod_order;
+  std::string filename = concat_path (lk_modules_expand_search_path (),
+				      "modules.order");
+  mod_order = gdb_fopen_cloexec (filename.c_str (), "r");
+
+  if (!mod_order)
+    {
+      error (_("\
+Can not find file module.order at %s \
+to load module symbol files.\n\
+Please check if solib-search-path is set correctly."),
+	     filename.c_str ());
+    }
+
+  return mod_order;
+}
+
+/* Build map between module name and path to binary file by reading file
+   modules.order.  Returns unordered_map with module name as key and its
+   path as value.  */
+
+std::unordered_map<std::string, std::string>
+lk_modules_build_path_map ()
+{
+  std::unordered_map<std::string, std::string> umap;
+  FILE *mod_order;
+  struct cleanup *old_chain;
+  char line[SO_NAME_MAX_PATH_SIZE + 1];
+
+  mod_order = lk_modules_open_mod_order ();
+  old_chain = make_cleanup_fclose (mod_order);
+
+  line[SO_NAME_MAX_PATH_SIZE] = '\0';
+  std::string search_path = lk_modules_expand_search_path ();
+  while (fgets (line, SO_NAME_MAX_PATH_SIZE, mod_order))
+    {
+      /* Remove trailing newline.  */
+      line[strlen (line) - 1] = '\0';
+
+      std::string name = lbasename (line);
+
+      /* 3 = strlen (".ko").  */
+      if (!endswith (name.c_str (), ".ko")
+	  || name.length () >= LK_MODULE_NAME_LEN + 3)
+	continue;
+
+      name = name.substr (0, name.length () - 3);
+
+      /* Kernel modules are named after the files they are stored in with
+	 all minus '-' replaced by underscore '_'.  Do the same to enable
+	 mapping.  */
+      for (size_t p = name.find('-'); p != std::string::npos;
+	   p = name.find ('-', p + 1))
+	name[p] = '_';
+
+      umap[name] = concat_path(search_path, line);
+    }
+
+  do_cleanups (old_chain);
+  return umap;
+}
+
+/* Allocate and fill a copy of struct lm_info for module at address MOD.  */
+
+struct lm_info *
+lk_modules_read_lm_info (CORE_ADDR mod)
+{
+  struct lm_info *lmi = XNEW (struct lm_info);
+  struct cleanup *old_chain = make_cleanup (xfree, lmi);
+
+  if (LK_FIELD (module, module_core)) /* linux -4.4 */
+    {
+      lmi->base = lk_read_addr (mod + LK_OFFSET (module, module_core));
+      lmi->size = lk_read_addr (mod + LK_OFFSET (module, core_size));
+
+      lmi->text.start = lmi->base;
+      lmi->text.offset = LK_HOOK->get_module_text_offset (mod);
+      lmi->text.size = lk_read_uint (mod + LK_OFFSET (module, core_text_size));
+
+      lmi->ro_data.start = lmi->base + lmi->text.size;
+      lmi->ro_data.offset = 0;
+      lmi->ro_data.size =  lk_read_uint (mod + LK_OFFSET (module,
+							  core_ro_size));
+    }
+  else /* linux 4.5+ */
+    {
+      CORE_ADDR mod_core = mod + LK_OFFSET (module, core_layout);
+
+      lmi->base = lk_read_addr (mod_core
+				+ LK_OFFSET (module_layout, base));
+      lmi->size = lk_read_uint (mod_core
+				+ LK_OFFSET (module_layout, size));
+
+      lmi->text.start = lmi->base;
+      lmi->text.offset = LK_HOOK->get_module_text_offset (mod);
+      lmi->text.size = lk_read_uint (mod_core
+				     + LK_OFFSET (module_layout, text_size));
+
+      lmi->ro_data.start = lmi->base + lmi->text.size;
+      lmi->ro_data.offset = 0;
+      lmi->ro_data.size =  lk_read_uint (mod_core
+					 + LK_OFFSET (module_layout, ro_size));
+    }
+
+  lmi->rw_data.start = lmi->base + lmi->ro_data.size;
+  lmi->rw_data.offset = 0;
+  lmi->rw_data.size = lmi->size - lmi->ro_data.size;
+
+  lmi->init_text.start = lk_read_addr (mod + LK_OFFSET (module, init));
+  lmi->init_text.offset = 0;
+
+  lmi->percpu.start = lk_read_addr (mod + LK_OFFSET (module, percpu));
+  lmi->percpu.size = lk_read_uint (mod + LK_OFFSET (module, percpu_size));
+  lmi->percpu.offset = 0;
+
+  discard_cleanups (old_chain);
+  return lmi;
+}
+
+/* Function for current_sos hook.  */
+
+struct so_list *
+lk_modules_current_sos (void)
+{
+  CORE_ADDR modules, next;
+  FILE *mod_order;
+  struct so_list *list = NULL;
+  std::unordered_map<std::string, std::string> umap;
+
+  umap = lk_modules_build_path_map ();
+  modules = LK_ADDR (modules);
+  lk_list_for_each (next, modules, module, list)
+    {
+      char name[LK_MODULE_NAME_LEN];
+      CORE_ADDR mod, name_addr;
+
+      mod = LK_CONTAINER_OF (next, module, list);
+      name_addr = mod + LK_OFFSET (module, name);
+      read_memory_string (name_addr, name, LK_MODULE_NAME_LEN);
+
+      if (umap.count (name))
+	{
+	  struct so_list *newso = XCNEW (struct so_list);
+
+	  newso->next = list;
+	  list = newso;
+	  newso->lm_info = lk_modules_read_lm_info (mod);
+	  strncpy (newso->so_original_name, name, SO_NAME_MAX_PATH_SIZE);
+	  strncpy (newso->so_name, umap[name].c_str (), SO_NAME_MAX_PATH_SIZE);
+	  newso->pspace = current_program_space;
+	}
+    }
+
+  return list;
+}
+
+/* Relocate target_section SEC to section type LMI_SEC.  Helper function for
+   lk_modules_relocate_section_addresses.  */
+
+void
+lk_modules_relocate_sec (struct target_section *sec,
+			 struct lm_info_sec *lmi_sec)
+{
+  unsigned int alignment = 1;
+
+ alignment = 1 << sec->the_bfd_section->alignment_power;
+
+  /* Adjust offset to section alignment.  */
+  if (lmi_sec->offset % alignment != 0)
+    lmi_sec->offset += alignment - (lmi_sec->offset % alignment);
+
+  sec->addr += lmi_sec->start + lmi_sec->offset;
+  sec->endaddr += lmi_sec->start + lmi_sec->offset;
+  lmi_sec->offset += sec->endaddr - sec->addr;
+}
+
+/* Function for relocate_section_addresses hook.  */
+
+void
+lk_modules_relocate_section_addresses (struct so_list *so,
+				       struct target_section *sec)
+{
+  struct lm_info *lmi = so->lm_info;
+  unsigned int flags = sec->the_bfd_section->flags;
+  const char *name = sec->the_bfd_section->name;
+
+  if (streq (name, ".modinfo") || streq (name, "__versions"))
+      return;
+
+  /* FIXME: Make dependent on module state, i.e. only map .init sections if
+   * state is MODULE_STATE_COMING.  */
+  if (startswith (name, ".init"))
+    lk_modules_relocate_sec (sec, &lmi->init_text);
+  else if (endswith (name, ".percpu"))
+    lk_modules_relocate_sec (sec, &lmi->percpu);
+  else if (flags & SEC_CODE)
+    lk_modules_relocate_sec (sec, &lmi->text);
+  else if (flags & SEC_READONLY)
+    lk_modules_relocate_sec (sec, &lmi->ro_data);
+  else if (flags & SEC_ALLOC)
+    lk_modules_relocate_sec (sec, &lmi->rw_data);
+
+  /* Set address range to be displayed with info shared.
+     size = text + (ro + rw) data without .init sections.  */
+  if (so->addr_low == so->addr_high)
+    {
+      so->addr_low = lmi->base;
+      so->addr_high = lmi->base + lmi->size;
+    }
+}
+
+/* Function for free_so hook.  */
+
+void
+lk_modules_free_so (struct so_list *so)
+{
+  xfree (so->lm_info);
+}
+
+/* Function for clear_so hook.  */
+
+void
+lk_modules_clear_so (struct so_list *so)
+{
+  if (so->lm_info != NULL)
+    memset (so->lm_info, 0, sizeof (struct lm_info));
+}
+
+/* Function for clear_solib hook.  */
+
+void
+lk_modules_clear_solib ()
+{
+  /* Nothing to do.  */
+}
+
+/* Function for clear_create_inferior_hook hook.  */
+
+void
+lk_modules_create_inferior_hook (int from_tty)
+{
+  /* Nothing to do.  */
+}
+
+/* Function for clear_create_inferior_hook hook.  */
+
+int
+lk_modules_in_dynsym_resolve_code (CORE_ADDR pc)
+{
+  return 0;
+}
+
+/* Function for same hook.  */
+
+int
+lk_modules_same (struct so_list *gdb, struct so_list *inf)
+{
+  return streq (gdb->so_name, inf->so_name);
+}
+
+/* Initialize linux modules solib target.  */
+
+void
+init_lk_modules_so_ops (void)
+{
+  struct target_so_ops *t;
+
+  if (lk_modules_so_ops != NULL)
+    return;
+
+  t = XCNEW (struct target_so_ops);
+  t->relocate_section_addresses = lk_modules_relocate_section_addresses;
+  t->free_so = lk_modules_free_so;
+  t->clear_so = lk_modules_clear_so;
+  t->clear_solib = lk_modules_clear_solib;
+  t->solib_create_inferior_hook = lk_modules_create_inferior_hook;
+  t->current_sos = lk_modules_current_sos;
+  t->bfd_open = solib_bfd_open;
+  t->in_dynsym_resolve_code = lk_modules_in_dynsym_resolve_code;
+  t->same = lk_modules_same;
+
+  lk_modules_so_ops = t;
+}
+
+/* Provide a prototype to silence -Wmissing-prototypes.  */
+extern initialize_file_ftype _initialize_lk_modules;
+
+void
+_initialize_lk_modules (void)
+{
+  init_lk_modules_so_ops ();
+}
diff --git a/gdb/lk-modules.h b/gdb/lk-modules.h
new file mode 100644
index 0000000..47e6dde
--- /dev/null
+++ b/gdb/lk-modules.h
@@ -0,0 +1,29 @@
+/* Handle kernel modules as shared libraries.
+
+   Copyright (C) 2016 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 3 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, see <http://www.gnu.org/licenses/>.  */
+
+#ifndef __LK_MODULES_H__
+#define __LK_MODULES_H__
+
+extern struct target_so_ops *lk_modules_so_ops;
+
+/* Check if debug info for module NAME are loaded.  Needed by lsmod command.  */
+
+extern bool lk_modules_debug_info_loaded (const std::string &name);
+
+#endif /*  __LK_MODULES_H__  */
diff --git a/gdb/solib.c b/gdb/solib.c
index fc45133..595828a 100644
--- a/gdb/solib.c
+++ b/gdb/solib.c
@@ -107,6 +107,14 @@ show_solib_search_path (struct ui_file *file, int from_tty,
 		    value);
 }
 
+/* see solib.h.  */
+
+const char *
+get_solib_search_path ()
+{
+  return solib_search_path ? solib_search_path : "";
+}
+
 /* Same as HAVE_DOS_BASED_FILE_SYSTEM, but useable as an rvalue.  */
 #if (HAVE_DOS_BASED_FILE_SYSTEM)
 #  define DOS_BASED_FILE_SYSTEM 1
diff --git a/gdb/solib.h b/gdb/solib.h
index dd07636..99b5cda 100644
--- a/gdb/solib.h
+++ b/gdb/solib.h
@@ -28,6 +28,11 @@ struct program_space;
 
 #include "symfile-add-flags.h"
 
+/* Returns the solib_search_path.  The returned string is malloc'ed and must be
+   freed by the caller.  */
+
+extern const char *get_solib_search_path ();
+
 /* Called when we free all symtabs, to free the shared library information
    as well.  */
 
-- 
2.8.4


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]