forked from Imagelibrary/binutils-gdb
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.
This commit is contained in:
committed by
Andreas Arnez
parent
60a2f03784
commit
699e91f4e1
@@ -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 \
|
||||
|
||||
@@ -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.
|
||||
|
||||
|
||||
101
gdb/lk-low.c
101
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;
|
||||
|
||||
24
gdb/lk-low.h
24
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;
|
||||
|
||||
412
gdb/lk-modules.c
Normal file
412
gdb/lk-modules.c
Normal file
@@ -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 ();
|
||||
}
|
||||
29
gdb/lk-modules.h
Normal file
29
gdb/lk-modules.h
Normal file
@@ -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__ */
|
||||
@@ -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
|
||||
|
||||
@@ -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. */
|
||||
|
||||
|
||||
Reference in New Issue
Block a user