diff options
author | Philipp Rudo <prudo@linux.vnet.ibm.com> | 2017-02-07 14:17:05 +0100 |
---|---|---|
committer | Andreas Arnez <arnez@linux.vnet.ibm.com> | 2017-02-07 16:25:54 +0100 |
commit | fc83f37b41084a8aeae0338b16039db8c0870f04 (patch) | |
tree | b2f62bfeb8f9b514f16e99728c0de3d42a395b42 | |
parent | 757186093b40ad3b37962c34294d032b0d88739f (diff) | |
download | gdb-fc83f37b41084a8aeae0338b16039db8c0870f04.zip gdb-fc83f37b41084a8aeae0338b16039db8c0870f04.tar.gz gdb-fc83f37b41084a8aeae0338b16039db8c0870f04.tar.bz2 |
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.
(COMMON_OBS): Add lk-modules.o.
-rw-r--r-- | gdb/Makefile.in | 4 | ||||
-rw-r--r-- | gdb/lk-low.c | 101 | ||||
-rw-r--r-- | gdb/lk-low.h | 24 | ||||
-rw-r--r-- | gdb/lk-modules.c | 412 | ||||
-rw-r--r-- | gdb/lk-modules.h | 29 | ||||
-rw-r--r-- | gdb/solib.c | 8 | ||||
-rw-r--r-- | gdb/solib.h | 5 |
7 files changed, 583 insertions, 0 deletions
diff --git a/gdb/Makefile.in b/gdb/Makefile.in index 41dcd4a..b907705 100644 --- a/gdb/Makefile.in +++ b/gdb/Makefile.in @@ -1095,6 +1095,7 @@ SFILES = \ linespec.c \ lk-lists.c \ lk-low.c \ + lk-modules.c \ location.c \ m2-exp.y \ m2-lang.c \ @@ -1344,6 +1345,7 @@ HFILES_NO_SRCDIR = \ linux-tdep.h \ lk-lists.h \ lk-low.h \ + lk-modules.h \ location.h \ m2-lang.h \ m32r-tdep.h \ @@ -1705,6 +1707,7 @@ COMMON_OBS = $(DEPFILES) $(CONFIG_OBS) $(YYOBJ) \ language.o \ linespec.o \ lk-lists.o \ + lk-modules.o \ location.o \ m2-lang.o \ m2-typeprint.o \ @@ -2539,6 +2542,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/lk-low.c b/gdb/lk-low.c index a26373b..20206e9 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" @@ -563,6 +564,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. */ @@ -598,6 +639,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 () { @@ -618,10 +662,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 */ @@ -720,12 +815,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. */ @@ -838,6 +938,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 e644ffe..b544f09 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 @@ -203,6 +205,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. */ @@ -217,6 +232,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. */ |