GNU Binutils with patches for OS216
修訂 | 699e91f4e1d62b56ad9cce10c0220c7aae524ebb (tree) |
---|---|
時間 | 2017-03-17 01:01:48 |
作者 | Philipp Rudo <prudo@linu...> |
Commiter | Andreas Arnez |
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:
@@ -819,6 +819,7 @@ ALL_TARGET_OBS = \ | ||
819 | 819 | linux-tdep.o \ |
820 | 820 | lk-lists.o \ |
821 | 821 | lk-low.o \ |
822 | + lk-modules.o \ | |
822 | 823 | lm32-tdep.o \ |
823 | 824 | m32c-tdep.o \ |
824 | 825 | m32r-linux-tdep.o \ |
@@ -1107,6 +1108,7 @@ SFILES = \ | ||
1107 | 1108 | linespec.c \ |
1108 | 1109 | lk-lists.c \ |
1109 | 1110 | lk-low.c \ |
1111 | + lk-modules.c \ | |
1110 | 1112 | location.c \ |
1111 | 1113 | m2-exp.y \ |
1112 | 1114 | m2-lang.c \ |
@@ -1356,6 +1358,7 @@ HFILES_NO_SRCDIR = \ | ||
1356 | 1358 | linux-tdep.h \ |
1357 | 1359 | lk-lists.h \ |
1358 | 1360 | lk-low.h \ |
1361 | + lk-modules.h \ | |
1359 | 1362 | location.h \ |
1360 | 1363 | m2-lang.h \ |
1361 | 1364 | m32r-tdep.h \ |
@@ -2555,6 +2558,7 @@ ALLDEPFILES = \ | ||
2555 | 2558 | linux-tdep.c \ |
2556 | 2559 | lk-lists.c \ |
2557 | 2560 | lk-low.c \ |
2561 | + lk-modules.c \ | |
2558 | 2562 | lm32-tdep.c \ |
2559 | 2563 | m32r-linux-nat.c \ |
2560 | 2564 | m32r-linux-tdep.c \ |
@@ -36,7 +36,7 @@ esac | ||
36 | 36 | |
37 | 37 | # List of objectfiles for Linux kernel support. To be included into *-linux* |
38 | 38 | # targets wich support Linux kernel debugging. |
39 | -lk_target_obs="lk-lists.o lk-low.o" | |
39 | +lk_target_obs="lk-lists.o lk-low.o lk-modules.o" | |
40 | 40 | |
41 | 41 | # map target info into gdb names. |
42 | 42 |
@@ -29,6 +29,7 @@ | ||
29 | 29 | #include "inferior.h" |
30 | 30 | #include "lk-lists.h" |
31 | 31 | #include "lk-low.h" |
32 | +#include "lk-modules.h" | |
32 | 33 | #include "objfiles.h" |
33 | 34 | #include "observer.h" |
34 | 35 | #include "solib.h" |
@@ -536,6 +537,46 @@ lk_thread_name (struct target_ops *target, struct thread_info *ti) | ||
536 | 537 | return buf; |
537 | 538 | } |
538 | 539 | |
540 | +/* Translate a kernel virtual address ADDR to a physical address. */ | |
541 | + | |
542 | +CORE_ADDR | |
543 | +lk_kvtop (CORE_ADDR addr) | |
544 | +{ | |
545 | + CORE_ADDR pgd = lk_read_addr (LK_ADDR (init_mm) | |
546 | + + LK_OFFSET (mm_struct, pgd)); | |
547 | + return LK_HOOK->vtop (pgd, addr); | |
548 | +} | |
549 | + | |
550 | +/* Restore current_target to TARGET. */ | |
551 | +static void | |
552 | +restore_current_target (void *target) | |
553 | +{ | |
554 | + current_target.beneath = (struct target_ops *) target; | |
555 | +} | |
556 | + | |
557 | +/* Function for targets to_xfer_partial hook. */ | |
558 | + | |
559 | +enum target_xfer_status | |
560 | +lk_xfer_partial (struct target_ops *ops, enum target_object object, | |
561 | + const char *annex, gdb_byte *readbuf, | |
562 | + const gdb_byte *writebuf, ULONGEST offset, ULONGEST len, | |
563 | + ULONGEST *xfered_len) | |
564 | +{ | |
565 | + enum target_xfer_status ret_val; | |
566 | + struct cleanup *old_chain = make_cleanup (restore_current_target, ops); | |
567 | + | |
568 | + current_target.beneath = ops->beneath; | |
569 | + | |
570 | + if (LK_HOOK->is_kvaddr (offset)) | |
571 | + offset = lk_kvtop (offset); | |
572 | + | |
573 | + ret_val = ops->beneath->to_xfer_partial (ops->beneath, object, annex, | |
574 | + readbuf, writebuf, offset, len, | |
575 | + xfered_len); | |
576 | + do_cleanups (old_chain); | |
577 | + return ret_val; | |
578 | +} | |
579 | + | |
539 | 580 | /* Functions to initialize and free target_ops and its private data. As well |
540 | 581 | as functions for targets to_open/close/detach hooks. */ |
541 | 582 |
@@ -571,6 +612,9 @@ lk_init_private () | ||
571 | 612 | /* Initialize architecture independent private data. Must be called |
572 | 613 | _after_ symbol tables were initialized. */ |
573 | 614 | |
615 | +/* FIXME: throw error more fine-grained. */ | |
616 | +/* FIXME: make independent of compile options. */ | |
617 | + | |
574 | 618 | static void |
575 | 619 | lk_init_private_data () |
576 | 620 | { |
@@ -591,10 +635,61 @@ lk_init_private_data () | ||
591 | 635 | |
592 | 636 | LK_DECLARE_FIELD (cpumask, bits); |
593 | 637 | |
638 | + LK_DECLARE_FIELD (mm_struct, pgd); | |
639 | + | |
640 | + LK_DECLARE_FIELD (pgd_t, pgd); | |
641 | + | |
642 | + LK_DECLARE_FIELD (module, list); | |
643 | + LK_DECLARE_FIELD (module, name); | |
644 | + LK_DECLARE_FIELD (module, source_list); | |
645 | + LK_DECLARE_FIELD (module, arch); | |
646 | + LK_DECLARE_FIELD (module, init); | |
647 | + LK_DECLARE_FIELD (module, percpu); | |
648 | + LK_DECLARE_FIELD (module, percpu_size); | |
649 | + | |
650 | + /* Module offset moved to new struct module_layout with linux 4.5. | |
651 | + It must be checked in code which of this fields exist. */ | |
652 | + if (LK_DECLARE_FIELD_SILENT (module_layout, base)) /* linux 4.5+ */ | |
653 | + { | |
654 | + LK_DECLARE_FIELD (module, init_layout); | |
655 | + LK_DECLARE_FIELD (module, core_layout); | |
656 | + | |
657 | + LK_DECLARE_FIELD (module_layout, size); | |
658 | + LK_DECLARE_FIELD (module_layout, text_size); | |
659 | + LK_DECLARE_FIELD (module_layout, ro_size); | |
660 | + } | |
661 | + else if (LK_DECLARE_FIELD_SILENT (module, module_core)) /* linux -4.4 */ | |
662 | + { | |
663 | + LK_DECLARE_FIELD (module, init_size); | |
664 | + LK_DECLARE_FIELD (module, core_size); | |
665 | + | |
666 | + LK_DECLARE_FIELD (module, core_text_size); | |
667 | + LK_DECLARE_FIELD (module, core_ro_size); | |
668 | + } | |
669 | + else | |
670 | + { | |
671 | + error (_("Could not find module base. Aborting.")); | |
672 | + } | |
673 | + | |
674 | + LK_DECLARE_FIELD (module_use, source_list); | |
675 | + LK_DECLARE_FIELD (module_use, source); | |
676 | + | |
677 | + LK_DECLARE_FIELD (uts_namespace, name); | |
678 | + | |
679 | + LK_DECLARE_STRUCT_ALIAS (new_utsname, utsname); | |
680 | + LK_DECLARE_STRUCT_ALIAS (old_utsname, utsname); | |
681 | + LK_DECLARE_STRUCT_ALIAS (oldold_utsname, utsname); | |
682 | + if (LK_STRUCT (utsname) == NULL) | |
683 | + error (_("Could not find struct utsname. Aborting.")); | |
684 | + LK_DECLARE_FIELD (utsname, version); | |
685 | + LK_DECLARE_FIELD (utsname, release); | |
686 | + | |
594 | 687 | LK_DECLARE_ADDR (init_task); |
595 | 688 | LK_DECLARE_ADDR (runqueues); |
596 | 689 | LK_DECLARE_ADDR (__per_cpu_offset); |
597 | 690 | LK_DECLARE_ADDR (init_mm); |
691 | + LK_DECLARE_ADDR (modules); | |
692 | + LK_DECLARE_ADDR (init_uts_ns); | |
598 | 693 | |
599 | 694 | LK_DECLARE_ADDR_ALIAS (__cpu_online_mask, cpu_online_mask); /* linux 4.5+ */ |
600 | 695 | LK_DECLARE_ADDR_ALIAS (cpu_online_bits, cpu_online_mask); /* linux -4.4 */ |
@@ -693,12 +788,17 @@ lk_try_push_target () | ||
693 | 788 | gdbarch_lk_init_private (gdbarch); |
694 | 789 | /* Check for required arch hooks. */ |
695 | 790 | gdb_assert (LK_HOOK->get_registers); |
791 | + gdb_assert (LK_HOOK->is_kvaddr); | |
792 | + gdb_assert (LK_HOOK->vtop); | |
793 | + gdb_assert (LK_HOOK->get_module_text_offset); | |
696 | 794 | |
697 | 795 | lk_init_ptid_map (); |
698 | 796 | lk_update_thread_list (linux_kernel_ops); |
699 | 797 | |
700 | 798 | if (!target_is_pushed (linux_kernel_ops)) |
701 | 799 | push_target (linux_kernel_ops); |
800 | + | |
801 | + set_solib_ops (gdbarch, lk_modules_so_ops); | |
702 | 802 | } |
703 | 803 | |
704 | 804 | /* Function for targets to_open hook. */ |
@@ -811,6 +911,7 @@ init_linux_kernel_ops (void) | ||
811 | 911 | t->to_update_thread_list = lk_update_thread_list; |
812 | 912 | t->to_pid_to_str = lk_pid_to_str; |
813 | 913 | t->to_thread_name = lk_thread_name; |
914 | + t->to_xfer_partial = lk_xfer_partial; | |
814 | 915 | |
815 | 916 | t->to_stratum = thread_stratum; |
816 | 917 | t->to_magic = OPS_MAGIC; |
@@ -27,6 +27,8 @@ extern struct target_ops *linux_kernel_ops; | ||
27 | 27 | /* Copy constants defined in Linux kernel. */ |
28 | 28 | #define LK_TASK_COMM_LEN 16 |
29 | 29 | #define LK_BITS_PER_BYTE 8 |
30 | +#define LK_MODULE_NAME_LEN 56 | |
31 | +#define LK_UTS_NAME_LEN 64 | |
30 | 32 | |
31 | 33 | /* Definitions used in linux kernel target. */ |
32 | 34 | #define LK_CPU_INVAL -1U |
@@ -204,6 +206,19 @@ typedef void (*lk_hook_get_registers) (CORE_ADDR task, | ||
204 | 206 | struct regcache *regcache, |
205 | 207 | int regnum); |
206 | 208 | |
209 | +/* Hook to check if address ADDR is a kernel virtual address. | |
210 | + NOTE: This hook is called in the context of target beneath. */ | |
211 | +typedef int (*lk_hook_is_kvaddr) (CORE_ADDR addr); | |
212 | + | |
213 | +/* Hook to translate virtual adress ADDR to a pysical address using page | |
214 | + table located at PGD. | |
215 | + NOTE: This hook is called in the context of target beneath. */ | |
216 | +typedef CORE_ADDR (*lk_hook_vtop) (CORE_ADDR addr, CORE_ADDR pgd); | |
217 | + | |
218 | +/* Hook to get the offset between a modules base and the start of its | |
219 | + .text section. */ | |
220 | +typedef CORE_ADDR (*lk_hook_get_module_text_offset) (CORE_ADDR mod); | |
221 | + | |
207 | 222 | /* Hook to return the per_cpu_offset of cpu CPU. Only architectures that |
208 | 223 | do not use the __per_cpu_offset array to determin the offset have to |
209 | 224 | supply this hook. */ |
@@ -218,6 +233,15 @@ struct lk_private_hooks | ||
218 | 233 | /* required */ |
219 | 234 | lk_hook_get_registers get_registers; |
220 | 235 | |
236 | + /* required */ | |
237 | + lk_hook_is_kvaddr is_kvaddr; | |
238 | + | |
239 | + /* required */ | |
240 | + lk_hook_vtop vtop; | |
241 | + | |
242 | + /* reqired */ | |
243 | + lk_hook_get_module_text_offset get_module_text_offset; | |
244 | + | |
221 | 245 | /* optional, required if __per_cpu_offset array is not used to determine |
222 | 246 | offset. */ |
223 | 247 | lk_hook_get_percpu_offset get_percpu_offset; |
@@ -0,0 +1,412 @@ | ||
1 | +/* Handle Linux kernel modules as shared libraries. | |
2 | + | |
3 | + Copyright (C) 2016 Free Software Foundation, Inc. | |
4 | + | |
5 | + This file is part of GDB. | |
6 | + | |
7 | + This program is free software; you can redistribute it and/or modify | |
8 | + it under the terms of the GNU General Public License as published by | |
9 | + the Free Software Foundation; either version 3 of the License, or | |
10 | + (at your option) any later version. | |
11 | + | |
12 | + This program is distributed in the hope that it will be useful, | |
13 | + but WITHOUT ANY WARRANTY; without even the implied warranty of | |
14 | + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |
15 | + GNU General Public License for more details. | |
16 | + | |
17 | + You should have received a copy of the GNU General Public License | |
18 | + along with this program. If not, see <http://www.gnu.org/licenses/>. */ | |
19 | + | |
20 | +#include "defs.h" | |
21 | + | |
22 | +#include "common/filestuff.h" | |
23 | +#include "filenames.h" | |
24 | +#include "gdbcmd.h" | |
25 | +#include "gdbcore.h" | |
26 | +#include "gdb_regex.h" | |
27 | +#include "lk-lists.h" | |
28 | +#include "lk-low.h" | |
29 | +#include "lk-modules.h" | |
30 | +#include "objfiles.h" | |
31 | +#include "observer.h" | |
32 | +#include "readline/readline.h" | |
33 | +#include "solib.h" | |
34 | +#include "solist.h" | |
35 | +#include "utils.h" | |
36 | + | |
37 | +#include <unordered_map> | |
38 | +#include <string> | |
39 | + | |
40 | +struct target_so_ops *lk_modules_so_ops = NULL; | |
41 | + | |
42 | +/* Info for single section type. */ | |
43 | + | |
44 | +struct lm_info_sec | |
45 | +{ | |
46 | + CORE_ADDR start; | |
47 | + CORE_ADDR offset; | |
48 | + unsigned int size; | |
49 | +}; | |
50 | + | |
51 | +/* Link map info to include in an allocated so_list entry. */ | |
52 | + | |
53 | +struct lm_info | |
54 | +{ | |
55 | + CORE_ADDR base; | |
56 | + unsigned int size; | |
57 | + | |
58 | + struct lm_info_sec text; | |
59 | + struct lm_info_sec init_text; | |
60 | + struct lm_info_sec ro_data; | |
61 | + struct lm_info_sec rw_data; | |
62 | + struct lm_info_sec percpu; | |
63 | +}; | |
64 | + | |
65 | +/* Check if debug info for module NAME are loaded. */ | |
66 | + | |
67 | +bool | |
68 | +lk_modules_debug_info_loaded (const std::string &name) | |
69 | +{ | |
70 | + struct so_list *so; | |
71 | + | |
72 | + for (so = master_so_list (); so; so = so->next) | |
73 | + { | |
74 | + if (name == so->so_original_name) | |
75 | + return (so->symbols_loaded && objfile_has_symbols (so->objfile)); | |
76 | + } | |
77 | + | |
78 | + return false; | |
79 | +} | |
80 | + | |
81 | +/* Replace tags, like '$release', with corresponding data in | |
82 | + solib_search_path. | |
83 | + | |
84 | + Known tags: | |
85 | + $release Linux kernel release, same as 'uname -r' | |
86 | + | |
87 | + Returns the expanded path. */ | |
88 | + | |
89 | +static std::string | |
90 | +lk_modules_expand_search_path () | |
91 | +{ | |
92 | + char release[LK_UTS_NAME_LEN + 1]; | |
93 | + CORE_ADDR utsname; | |
94 | + | |
95 | + utsname = LK_ADDR (init_uts_ns) + LK_OFFSET (uts_namespace, name); | |
96 | + read_memory_string (utsname + LK_OFFSET (utsname, release), | |
97 | + release, LK_UTS_NAME_LEN); | |
98 | + release[LK_UTS_NAME_LEN] = '\0'; | |
99 | + | |
100 | + std::string search_path = get_solib_search_path (); | |
101 | + substitute_path_component (search_path, "$release", release); | |
102 | + | |
103 | + return search_path; | |
104 | +} | |
105 | + | |
106 | +/* With kernel modules there is the problem that the kernel only stores | |
107 | + the modules name but not the path from wich it was loaded from. | |
108 | + Thus we need to map the name to a path GDB can read from. We use file | |
109 | + modules.order to do so. It is created by kbuild containing the order in | |
110 | + which the modules appear in the Makefile and is also used by modprobe. | |
111 | + The drawback of this method is that it needs the modules.order file and | |
112 | + all relative paths, starting from <solib-search-path>, must be exactly the | |
113 | + same as decribed in it. */ | |
114 | + | |
115 | +/* Open file <solib-search-path>/modules.order and return its file | |
116 | + pointer. */ | |
117 | + | |
118 | +FILE * | |
119 | +lk_modules_open_mod_order () | |
120 | +{ | |
121 | + FILE *mod_order; | |
122 | + std::string filename = concat_path (lk_modules_expand_search_path (), | |
123 | + "modules.order"); | |
124 | + mod_order = gdb_fopen_cloexec (filename.c_str (), "r"); | |
125 | + | |
126 | + if (!mod_order) | |
127 | + { | |
128 | + error (_("\ | |
129 | +Can not find file module.order at %s \ | |
130 | +to load module symbol files.\n\ | |
131 | +Please check if solib-search-path is set correctly."), | |
132 | + filename.c_str ()); | |
133 | + } | |
134 | + | |
135 | + return mod_order; | |
136 | +} | |
137 | + | |
138 | +/* Build map between module name and path to binary file by reading file | |
139 | + modules.order. Returns unordered_map with module name as key and its | |
140 | + path as value. */ | |
141 | + | |
142 | +std::unordered_map<std::string, std::string> | |
143 | +lk_modules_build_path_map () | |
144 | +{ | |
145 | + std::unordered_map<std::string, std::string> umap; | |
146 | + FILE *mod_order; | |
147 | + struct cleanup *old_chain; | |
148 | + char line[SO_NAME_MAX_PATH_SIZE + 1]; | |
149 | + | |
150 | + mod_order = lk_modules_open_mod_order (); | |
151 | + old_chain = make_cleanup_fclose (mod_order); | |
152 | + | |
153 | + line[SO_NAME_MAX_PATH_SIZE] = '\0'; | |
154 | + std::string search_path = lk_modules_expand_search_path (); | |
155 | + while (fgets (line, SO_NAME_MAX_PATH_SIZE, mod_order)) | |
156 | + { | |
157 | + /* Remove trailing newline. */ | |
158 | + line[strlen (line) - 1] = '\0'; | |
159 | + | |
160 | + std::string name = lbasename (line); | |
161 | + | |
162 | + /* 3 = strlen (".ko"). */ | |
163 | + if (!endswith (name.c_str (), ".ko") | |
164 | + || name.length () >= LK_MODULE_NAME_LEN + 3) | |
165 | + continue; | |
166 | + | |
167 | + name = name.substr (0, name.length () - 3); | |
168 | + | |
169 | + /* Kernel modules are named after the files they are stored in with | |
170 | + all minus '-' replaced by underscore '_'. Do the same to enable | |
171 | + mapping. */ | |
172 | + for (size_t p = name.find('-'); p != std::string::npos; | |
173 | + p = name.find ('-', p + 1)) | |
174 | + name[p] = '_'; | |
175 | + | |
176 | + umap[name] = concat_path(search_path, line); | |
177 | + } | |
178 | + | |
179 | + do_cleanups (old_chain); | |
180 | + return umap; | |
181 | +} | |
182 | + | |
183 | +/* Allocate and fill a copy of struct lm_info for module at address MOD. */ | |
184 | + | |
185 | +struct lm_info * | |
186 | +lk_modules_read_lm_info (CORE_ADDR mod) | |
187 | +{ | |
188 | + struct lm_info *lmi = XNEW (struct lm_info); | |
189 | + struct cleanup *old_chain = make_cleanup (xfree, lmi); | |
190 | + | |
191 | + if (LK_FIELD (module, module_core)) /* linux -4.4 */ | |
192 | + { | |
193 | + lmi->base = lk_read_addr (mod + LK_OFFSET (module, module_core)); | |
194 | + lmi->size = lk_read_addr (mod + LK_OFFSET (module, core_size)); | |
195 | + | |
196 | + lmi->text.start = lmi->base; | |
197 | + lmi->text.offset = LK_HOOK->get_module_text_offset (mod); | |
198 | + lmi->text.size = lk_read_uint (mod + LK_OFFSET (module, core_text_size)); | |
199 | + | |
200 | + lmi->ro_data.start = lmi->base + lmi->text.size; | |
201 | + lmi->ro_data.offset = 0; | |
202 | + lmi->ro_data.size = lk_read_uint (mod + LK_OFFSET (module, | |
203 | + core_ro_size)); | |
204 | + } | |
205 | + else /* linux 4.5+ */ | |
206 | + { | |
207 | + CORE_ADDR mod_core = mod + LK_OFFSET (module, core_layout); | |
208 | + | |
209 | + lmi->base = lk_read_addr (mod_core | |
210 | + + LK_OFFSET (module_layout, base)); | |
211 | + lmi->size = lk_read_uint (mod_core | |
212 | + + LK_OFFSET (module_layout, size)); | |
213 | + | |
214 | + lmi->text.start = lmi->base; | |
215 | + lmi->text.offset = LK_HOOK->get_module_text_offset (mod); | |
216 | + lmi->text.size = lk_read_uint (mod_core | |
217 | + + LK_OFFSET (module_layout, text_size)); | |
218 | + | |
219 | + lmi->ro_data.start = lmi->base + lmi->text.size; | |
220 | + lmi->ro_data.offset = 0; | |
221 | + lmi->ro_data.size = lk_read_uint (mod_core | |
222 | + + LK_OFFSET (module_layout, ro_size)); | |
223 | + } | |
224 | + | |
225 | + lmi->rw_data.start = lmi->base + lmi->ro_data.size; | |
226 | + lmi->rw_data.offset = 0; | |
227 | + lmi->rw_data.size = lmi->size - lmi->ro_data.size; | |
228 | + | |
229 | + lmi->init_text.start = lk_read_addr (mod + LK_OFFSET (module, init)); | |
230 | + lmi->init_text.offset = 0; | |
231 | + | |
232 | + lmi->percpu.start = lk_read_addr (mod + LK_OFFSET (module, percpu)); | |
233 | + lmi->percpu.size = lk_read_uint (mod + LK_OFFSET (module, percpu_size)); | |
234 | + lmi->percpu.offset = 0; | |
235 | + | |
236 | + discard_cleanups (old_chain); | |
237 | + return lmi; | |
238 | +} | |
239 | + | |
240 | +/* Function for current_sos hook. */ | |
241 | + | |
242 | +struct so_list * | |
243 | +lk_modules_current_sos (void) | |
244 | +{ | |
245 | + CORE_ADDR modules, next; | |
246 | + FILE *mod_order; | |
247 | + struct so_list *list = NULL; | |
248 | + std::unordered_map<std::string, std::string> umap; | |
249 | + | |
250 | + umap = lk_modules_build_path_map (); | |
251 | + modules = LK_ADDR (modules); | |
252 | + lk_list_for_each (next, modules, module, list) | |
253 | + { | |
254 | + char name[LK_MODULE_NAME_LEN]; | |
255 | + CORE_ADDR mod, name_addr; | |
256 | + | |
257 | + mod = LK_CONTAINER_OF (next, module, list); | |
258 | + name_addr = mod + LK_OFFSET (module, name); | |
259 | + read_memory_string (name_addr, name, LK_MODULE_NAME_LEN); | |
260 | + | |
261 | + if (umap.count (name)) | |
262 | + { | |
263 | + struct so_list *newso = XCNEW (struct so_list); | |
264 | + | |
265 | + newso->next = list; | |
266 | + list = newso; | |
267 | + newso->lm_info = lk_modules_read_lm_info (mod); | |
268 | + strncpy (newso->so_original_name, name, SO_NAME_MAX_PATH_SIZE); | |
269 | + strncpy (newso->so_name, umap[name].c_str (), SO_NAME_MAX_PATH_SIZE); | |
270 | + newso->pspace = current_program_space; | |
271 | + } | |
272 | + } | |
273 | + | |
274 | + return list; | |
275 | +} | |
276 | + | |
277 | +/* Relocate target_section SEC to section type LMI_SEC. Helper function for | |
278 | + lk_modules_relocate_section_addresses. */ | |
279 | + | |
280 | +void | |
281 | +lk_modules_relocate_sec (struct target_section *sec, | |
282 | + struct lm_info_sec *lmi_sec) | |
283 | +{ | |
284 | + unsigned int alignment = 1; | |
285 | + | |
286 | + alignment = 1 << sec->the_bfd_section->alignment_power; | |
287 | + | |
288 | + /* Adjust offset to section alignment. */ | |
289 | + if (lmi_sec->offset % alignment != 0) | |
290 | + lmi_sec->offset += alignment - (lmi_sec->offset % alignment); | |
291 | + | |
292 | + sec->addr += lmi_sec->start + lmi_sec->offset; | |
293 | + sec->endaddr += lmi_sec->start + lmi_sec->offset; | |
294 | + lmi_sec->offset += sec->endaddr - sec->addr; | |
295 | +} | |
296 | + | |
297 | +/* Function for relocate_section_addresses hook. */ | |
298 | + | |
299 | +void | |
300 | +lk_modules_relocate_section_addresses (struct so_list *so, | |
301 | + struct target_section *sec) | |
302 | +{ | |
303 | + struct lm_info *lmi = so->lm_info; | |
304 | + unsigned int flags = sec->the_bfd_section->flags; | |
305 | + const char *name = sec->the_bfd_section->name; | |
306 | + | |
307 | + if (streq (name, ".modinfo") || streq (name, "__versions")) | |
308 | + return; | |
309 | + | |
310 | + /* FIXME: Make dependent on module state, i.e. only map .init sections if | |
311 | + * state is MODULE_STATE_COMING. */ | |
312 | + if (startswith (name, ".init")) | |
313 | + lk_modules_relocate_sec (sec, &lmi->init_text); | |
314 | + else if (endswith (name, ".percpu")) | |
315 | + lk_modules_relocate_sec (sec, &lmi->percpu); | |
316 | + else if (flags & SEC_CODE) | |
317 | + lk_modules_relocate_sec (sec, &lmi->text); | |
318 | + else if (flags & SEC_READONLY) | |
319 | + lk_modules_relocate_sec (sec, &lmi->ro_data); | |
320 | + else if (flags & SEC_ALLOC) | |
321 | + lk_modules_relocate_sec (sec, &lmi->rw_data); | |
322 | + | |
323 | + /* Set address range to be displayed with info shared. | |
324 | + size = text + (ro + rw) data without .init sections. */ | |
325 | + if (so->addr_low == so->addr_high) | |
326 | + { | |
327 | + so->addr_low = lmi->base; | |
328 | + so->addr_high = lmi->base + lmi->size; | |
329 | + } | |
330 | +} | |
331 | + | |
332 | +/* Function for free_so hook. */ | |
333 | + | |
334 | +void | |
335 | +lk_modules_free_so (struct so_list *so) | |
336 | +{ | |
337 | + xfree (so->lm_info); | |
338 | +} | |
339 | + | |
340 | +/* Function for clear_so hook. */ | |
341 | + | |
342 | +void | |
343 | +lk_modules_clear_so (struct so_list *so) | |
344 | +{ | |
345 | + if (so->lm_info != NULL) | |
346 | + memset (so->lm_info, 0, sizeof (struct lm_info)); | |
347 | +} | |
348 | + | |
349 | +/* Function for clear_solib hook. */ | |
350 | + | |
351 | +void | |
352 | +lk_modules_clear_solib () | |
353 | +{ | |
354 | + /* Nothing to do. */ | |
355 | +} | |
356 | + | |
357 | +/* Function for clear_create_inferior_hook hook. */ | |
358 | + | |
359 | +void | |
360 | +lk_modules_create_inferior_hook (int from_tty) | |
361 | +{ | |
362 | + /* Nothing to do. */ | |
363 | +} | |
364 | + | |
365 | +/* Function for clear_create_inferior_hook hook. */ | |
366 | + | |
367 | +int | |
368 | +lk_modules_in_dynsym_resolve_code (CORE_ADDR pc) | |
369 | +{ | |
370 | + return 0; | |
371 | +} | |
372 | + | |
373 | +/* Function for same hook. */ | |
374 | + | |
375 | +int | |
376 | +lk_modules_same (struct so_list *gdb, struct so_list *inf) | |
377 | +{ | |
378 | + return streq (gdb->so_name, inf->so_name); | |
379 | +} | |
380 | + | |
381 | +/* Initialize linux modules solib target. */ | |
382 | + | |
383 | +void | |
384 | +init_lk_modules_so_ops (void) | |
385 | +{ | |
386 | + struct target_so_ops *t; | |
387 | + | |
388 | + if (lk_modules_so_ops != NULL) | |
389 | + return; | |
390 | + | |
391 | + t = XCNEW (struct target_so_ops); | |
392 | + t->relocate_section_addresses = lk_modules_relocate_section_addresses; | |
393 | + t->free_so = lk_modules_free_so; | |
394 | + t->clear_so = lk_modules_clear_so; | |
395 | + t->clear_solib = lk_modules_clear_solib; | |
396 | + t->solib_create_inferior_hook = lk_modules_create_inferior_hook; | |
397 | + t->current_sos = lk_modules_current_sos; | |
398 | + t->bfd_open = solib_bfd_open; | |
399 | + t->in_dynsym_resolve_code = lk_modules_in_dynsym_resolve_code; | |
400 | + t->same = lk_modules_same; | |
401 | + | |
402 | + lk_modules_so_ops = t; | |
403 | +} | |
404 | + | |
405 | +/* Provide a prototype to silence -Wmissing-prototypes. */ | |
406 | +extern initialize_file_ftype _initialize_lk_modules; | |
407 | + | |
408 | +void | |
409 | +_initialize_lk_modules (void) | |
410 | +{ | |
411 | + init_lk_modules_so_ops (); | |
412 | +} |
@@ -0,0 +1,29 @@ | ||
1 | +/* Handle kernel modules as shared libraries. | |
2 | + | |
3 | + Copyright (C) 2016 Free Software Foundation, Inc. | |
4 | + | |
5 | + This file is part of GDB. | |
6 | + | |
7 | + This program is free software; you can redistribute it and/or modify | |
8 | + it under the terms of the GNU General Public License as published by | |
9 | + the Free Software Foundation; either version 3 of the License, or | |
10 | + (at your option) any later version. | |
11 | + | |
12 | + This program is distributed in the hope that it will be useful, | |
13 | + but WITHOUT ANY WARRANTY; without even the implied warranty of | |
14 | + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |
15 | + GNU General Public License for more details. | |
16 | + | |
17 | + You should have received a copy of the GNU General Public License | |
18 | + along with this program. If not, see <http://www.gnu.org/licenses/>. */ | |
19 | + | |
20 | +#ifndef __LK_MODULES_H__ | |
21 | +#define __LK_MODULES_H__ | |
22 | + | |
23 | +extern struct target_so_ops *lk_modules_so_ops; | |
24 | + | |
25 | +/* Check if debug info for module NAME are loaded. Needed by lsmod command. */ | |
26 | + | |
27 | +extern bool lk_modules_debug_info_loaded (const std::string &name); | |
28 | + | |
29 | +#endif /* __LK_MODULES_H__ */ |
@@ -107,6 +107,14 @@ show_solib_search_path (struct ui_file *file, int from_tty, | ||
107 | 107 | value); |
108 | 108 | } |
109 | 109 | |
110 | +/* see solib.h. */ | |
111 | + | |
112 | +const char * | |
113 | +get_solib_search_path () | |
114 | +{ | |
115 | + return solib_search_path ? solib_search_path : ""; | |
116 | +} | |
117 | + | |
110 | 118 | /* Same as HAVE_DOS_BASED_FILE_SYSTEM, but useable as an rvalue. */ |
111 | 119 | #if (HAVE_DOS_BASED_FILE_SYSTEM) |
112 | 120 | # define DOS_BASED_FILE_SYSTEM 1 |
@@ -28,6 +28,11 @@ struct program_space; | ||
28 | 28 | |
29 | 29 | #include "symfile-add-flags.h" |
30 | 30 | |
31 | +/* Returns the solib_search_path. The returned string is malloc'ed and must be | |
32 | + freed by the caller. */ | |
33 | + | |
34 | +extern const char *get_solib_search_path (); | |
35 | + | |
31 | 36 | /* Called when we free all symtabs, to free the shared library information |
32 | 37 | as well. */ |
33 | 38 |