]>
Commit | Line | Data |
---|---|---|
5a03b7c3 MT |
1 | From: Gary Benson <gbenson@redhat.com> |
2 | To: Jan Kratochvil <jan.kratochvil@redhat.com> | |
3 | Message-ID: <20110810133605.GB7294@redhat.com> | |
4 | ||
5 | diff --git a/gdb/infrun.c b/gdb/infrun.c | |
6 | index 4296d3a..fd5e9c3 100644 | |
7 | --- a/gdb/infrun.c | |
8 | +++ b/gdb/infrun.c | |
9 | @@ -321,6 +323,13 @@ static struct symbol *step_start_function; | |
10 | /* Nonzero if we want to give control to the user when we're notified | |
11 | of shared library events by the dynamic linker. */ | |
12 | int stop_on_solib_events; | |
13 | + | |
14 | +static void | |
15 | +set_stop_on_solib_events (char *args, int from_tty, struct cmd_list_element *c) | |
16 | +{ | |
17 | + update_solib_breakpoints (); | |
18 | +} | |
19 | + | |
20 | static void | |
21 | show_stop_on_solib_events (struct ui_file *file, int from_tty, | |
22 | struct cmd_list_element *c, const char *value) | |
23 | @@ -7153,7 +7162,7 @@ Show stopping for shared library events."), _("\ | |
24 | If nonzero, gdb will give control to the user when the dynamic linker\n\ | |
25 | notifies gdb of shared library events. The most common event of interest\n\ | |
26 | to the user would be loading/unloading of a new library."), | |
27 | - NULL, | |
28 | + set_stop_on_solib_events, | |
29 | show_stop_on_solib_events, | |
30 | &setlist, &showlist); | |
31 | ||
32 | diff --git a/gdb/solib-svr4.c b/gdb/solib-svr4.c | |
33 | index dffc621..73cbe1c 100644 | |
34 | --- a/gdb/solib-svr4.c | |
35 | +++ b/gdb/solib-svr4.c | |
36 | @@ -48,6 +48,8 @@ | |
37 | #include "auxv.h" | |
38 | #include "exceptions.h" | |
39 | ||
40 | +#include "stap-probe.h" | |
41 | + | |
42 | static struct link_map_offsets *svr4_fetch_link_map_offsets (void); | |
43 | static int svr4_have_link_map_offsets (void); | |
44 | static void svr4_relocate_main_executable (void); | |
45 | @@ -92,6 +94,32 @@ static const char * const solib_break_names[] = | |
46 | NULL | |
47 | }; | |
48 | ||
49 | +/* A list of SystemTap probes which, if present in the dynamic linker, | |
50 | + allow more fine-grained breakpoints to be placed on shared library | |
51 | + events. */ | |
52 | + | |
53 | +struct probe_info | |
54 | + { | |
55 | + /* The name of the probe. */ | |
56 | + const char *name; | |
57 | + | |
58 | + /* Nonzero if this probe must be stopped at even when | |
59 | + stop-on-solib-events is off. */ | |
60 | + int mandatory; | |
61 | + }; | |
62 | + | |
63 | +static const struct probe_info probe_info[] = | |
64 | +{ | |
65 | + {"rtld_init_start", 0}, | |
66 | + {"rtld_init_complete", 1}, | |
67 | + {"rtld_map_start", 0}, | |
68 | + {"rtld_reloc_complete", 1}, | |
69 | + {"rtld_unmap_start", 0}, | |
70 | + {"rtld_unmap_complete", 1}, | |
71 | +}; | |
72 | + | |
73 | +#define NUM_PROBES (sizeof(probe_info) / sizeof(probe_info[0])) | |
74 | + | |
75 | static const char * const bkpt_names[] = | |
76 | { | |
77 | "_start", | |
78 | @@ -335,6 +363,12 @@ struct svr4_info | |
79 | CORE_ADDR interp_text_sect_high; | |
80 | CORE_ADDR interp_plt_sect_low; | |
81 | CORE_ADDR interp_plt_sect_high; | |
82 | + | |
83 | + /* SystemTap probes. */ | |
84 | + VEC (stap_probe_p) *probes[NUM_PROBES]; | |
85 | + | |
86 | + /* Nonzero if we are using the SystemTap interface. */ | |
87 | + int using_probes; | |
88 | }; | |
89 | ||
90 | /* Per-program-space data key. */ | |
91 | @@ -344,8 +378,15 @@ static void | |
92 | svr4_pspace_data_cleanup (struct program_space *pspace, void *arg) | |
93 | { | |
94 | struct svr4_info *info; | |
95 | + int i; | |
96 | ||
97 | info = program_space_data (pspace, solib_svr4_pspace_data); | |
98 | + if (info == NULL) | |
99 | + return; | |
100 | + | |
101 | + for (i = 0; i < NUM_PROBES; i++) | |
102 | + VEC_free (stap_probe_p, info->probes[i]); | |
103 | + | |
104 | xfree (info); | |
105 | } | |
106 | ||
107 | @@ -1321,6 +1362,126 @@ exec_entry_point (struct bfd *abfd, struct target_ops *targ) | |
108 | targ); | |
109 | } | |
110 | ||
111 | +/* Helper function for svr4_update_solib_event_breakpoints. */ | |
112 | + | |
113 | +static int | |
114 | +svr4_update_solib_event_breakpoint (struct breakpoint *b, void *arg) | |
115 | +{ | |
116 | + struct svr4_info *info = get_svr4_info (); | |
117 | + struct bp_location *loc; | |
118 | + | |
119 | + if (b->type != bp_shlib_event) | |
120 | + return 0; | |
121 | + | |
122 | + for (loc = b->loc; loc; loc = loc->next) | |
123 | + { | |
124 | + int i; | |
125 | + | |
126 | + for (i = 0; i < NUM_PROBES; i++) | |
127 | + { | |
128 | + if (!probe_info[i].mandatory) | |
129 | + { | |
130 | + const struct stap_probe *probe; | |
131 | + int ix; | |
132 | + | |
133 | + for (ix = 0; | |
134 | + VEC_iterate (stap_probe_p, info->probes[i], ix, probe); | |
135 | + ++ix) | |
136 | + { | |
137 | + if (loc->pspace == current_program_space | |
138 | + && loc->address == probe->address) | |
139 | + { | |
140 | + b->enable_state = | |
141 | + stop_on_solib_events ? bp_enabled : bp_disabled; | |
142 | + return 0; | |
143 | + } | |
144 | + } | |
145 | + } | |
146 | + } | |
147 | + } | |
148 | + | |
149 | + return 0; | |
150 | +} | |
151 | + | |
152 | +/* Enable or disable optional solib event breakpoints as appropriate. | |
153 | + Called whenever stop_on_solib_events is changed. */ | |
154 | + | |
155 | +static void | |
156 | +svr4_update_solib_event_breakpoints (void) | |
157 | +{ | |
158 | + struct svr4_info *info = get_svr4_info (); | |
159 | + | |
160 | + if (info->using_probes) | |
161 | + iterate_over_breakpoints (svr4_update_solib_event_breakpoint, NULL); | |
162 | +} | |
163 | + | |
164 | +/* Both the SunOS and the SVR4 dynamic linkers call a marker function | |
165 | + before and after mapping and unmapping shared libraries. The sole | |
166 | + purpose of this method is to allow debuggers to set a breakpoint so | |
167 | + they can track these changes. | |
168 | + | |
169 | + Some versions of the glibc dynamic linker contain SystemTap probes | |
170 | + to allow more fine grained stopping. Given the address of the | |
171 | + original marker function, this function attempts to find these | |
172 | + probes, and if found, sets breakpoints on those instead. If the | |
173 | + probes aren't found, a single breakpoint is set on the original | |
174 | + SVR4 marker function. */ | |
175 | + | |
176 | +static void | |
177 | +svr4_create_solib_event_breakpoints (struct gdbarch *gdbarch, CORE_ADDR address) | |
178 | +{ | |
179 | + struct svr4_info *info = get_svr4_info (); | |
180 | + struct obj_section *os; | |
181 | + | |
182 | + os = find_pc_section (address); | |
183 | + if (os != NULL) | |
184 | + { | |
185 | + int all_probes_found = 1; | |
186 | + int i; | |
187 | + | |
188 | + for (i = 0; i < NUM_PROBES; i++) | |
189 | + { | |
190 | + info->probes[i] = find_probes_in_objfile (os->objfile, "rtld", | |
191 | + probe_info[i].name); | |
192 | + | |
193 | + if (!VEC_length(stap_probe_p, info->probes[i])) | |
194 | + { | |
195 | + int j; | |
196 | + | |
197 | + for (j = i - 1; j >= 0; j--) | |
198 | + { | |
199 | + VEC_free (stap_probe_p, info->probes[j]); | |
200 | + info->probes[j] = NULL; | |
201 | + } | |
202 | + | |
203 | + all_probes_found = 0; | |
204 | + break; | |
205 | + } | |
206 | + } | |
207 | + | |
208 | + if (all_probes_found) | |
209 | + { | |
210 | + info->using_probes = 1; | |
211 | + | |
212 | + for (i = 0; i < NUM_PROBES; i++) | |
213 | + { | |
214 | + const struct stap_probe *probe; | |
215 | + int ix; | |
216 | + | |
217 | + for (ix = 0; | |
218 | + VEC_iterate (stap_probe_p, info->probes[i], ix, probe); | |
219 | + ++ix) | |
220 | + create_solib_event_breakpoint (gdbarch, probe->address); | |
221 | + } | |
222 | + | |
223 | + svr4_update_solib_event_breakpoints (); | |
224 | + return; | |
225 | + } | |
226 | + } | |
227 | + | |
228 | + create_solib_event_breakpoint (gdbarch, address); | |
229 | +} | |
230 | + | |
231 | /* | |
232 | ||
233 | LOCAL FUNCTION | |
234 | @@ -1372,10 +1533,18 @@ enable_break (struct svr4_info *info, int from_tty) | |
235 | asection *interp_sect; | |
236 | gdb_byte *interp_name; | |
237 | CORE_ADDR sym_addr; | |
238 | + int i; | |
239 | ||
240 | info->interp_text_sect_low = info->interp_text_sect_high = 0; | |
241 | info->interp_plt_sect_low = info->interp_plt_sect_high = 0; | |
242 | ||
243 | + for (i = 0; i < NUM_PROBES; i++) | |
244 | + { | |
245 | + VEC_free (stap_probe_p, info->probes[i]); | |
246 | + info->probes[i] = NULL; | |
247 | + } | |
248 | + info->using_probes = 0; | |
249 | + | |
250 | /* If we already have a shared library list in the target, and | |
251 | r_debug contains r_brk, set the breakpoint there - this should | |
252 | mean r_brk has already been relocated. Assume the dynamic linker | |
253 | @@ -1407,7 +1576,7 @@ enable_break (struct svr4_info *info, int from_tty) | |
254 | That knowledge is encoded in the address, if it's Thumb the low bit | |
255 | is 1. However, we've stripped that info above and it's not clear | |
256 | what all the consequences are of passing a non-addr_bits_remove'd | |
257 | - address to create_solib_event_breakpoint. The call to | |
258 | + address to svr4_create_solib_event_breakpoints. The call to | |
259 | find_pc_section verifies we know about the address and have some | |
260 | hope of computing the right kind of breakpoint to use (via | |
261 | symbol info). It does mean that GDB needs to be pointed at a | |
262 | @@ -1445,7 +1614,7 @@ enable_break (struct svr4_info *info, int from_tty) | |
263 | + bfd_section_size (tmp_bfd, interp_sect); | |
264 | } | |
265 | ||
266 | - create_solib_event_breakpoint (target_gdbarch, sym_addr); | |
267 | + svr4_create_solib_event_breakpoints (target_gdbarch, sym_addr); | |
268 | return 1; | |
269 | } | |
270 | } | |
271 | @@ -1599,7 +1768,8 @@ enable_break (struct svr4_info *info, int from_tty) | |
272 | ||
273 | if (sym_addr != 0) | |
274 | { | |
275 | - create_solib_event_breakpoint (target_gdbarch, load_addr + sym_addr); | |
276 | + svr4_create_solib_event_breakpoints (target_gdbarch, | |
277 | + load_addr + sym_addr); | |
278 | xfree (interp_name); | |
279 | return 1; | |
280 | } | |
281 | @@ -1625,7 +1795,7 @@ enable_break (struct svr4_info *info, int from_tty) | |
282 | sym_addr = gdbarch_convert_from_func_ptr_addr (target_gdbarch, | |
283 | sym_addr, | |
284 | ¤t_target); | |
285 | - create_solib_event_breakpoint (target_gdbarch, sym_addr); | |
286 | + svr4_create_solib_event_breakpoints (target_gdbarch, sym_addr); | |
287 | return 1; | |
288 | } | |
289 | } | |
290 | @@ -1641,7 +1811,7 @@ enable_break (struct svr4_info *info, int from_tty) | |
291 | sym_addr = gdbarch_convert_from_func_ptr_addr (target_gdbarch, | |
292 | sym_addr, | |
293 | ¤t_target); | |
294 | - create_solib_event_breakpoint (target_gdbarch, sym_addr); | |
295 | + svr4_create_solib_event_breakpoints (target_gdbarch, sym_addr); | |
296 | return 1; | |
297 | } | |
298 | } | |
299 | @@ -2470,4 +2640,5 @@ _initialize_svr4_solib (void) | |
300 | svr4_so_ops.lookup_lib_global_symbol = elf_lookup_lib_symbol; | |
301 | svr4_so_ops.same = svr4_same; | |
302 | svr4_so_ops.keep_data_in_core = svr4_keep_data_in_core; | |
303 | + svr4_so_ops.update_breakpoints = svr4_update_solib_event_breakpoints; | |
304 | } | |
305 | diff --git a/gdb/solib.c b/gdb/solib.c | |
306 | index 3296ed4..7ba70ce 100644 | |
307 | --- a/gdb/solib.c | |
308 | +++ b/gdb/solib.c | |
309 | @@ -1313,6 +1313,18 @@ no_shared_libraries (char *ignored, int from_tty) | |
310 | objfile_purge_solibs (); | |
311 | } | |
312 | ||
313 | +/* Enable or disable optional solib event breakpoints as appropriate. */ | |
314 | + | |
315 | +void | |
316 | +update_solib_breakpoints (void) | |
317 | +{ | |
318 | + struct target_so_ops *ops = solib_ops (target_gdbarch); | |
319 | + | |
320 | + if (ops->update_breakpoints != NULL) | |
321 | + ops->update_breakpoints (); | |
322 | +} | |
323 | + | |
324 | + | |
325 | /* Reload shared libraries, but avoid reloading the same symbol file | |
326 | we already have loaded. */ | |
327 | ||
328 | diff --git a/gdb/solib.h b/gdb/solib.h | |
329 | index c473d85..7b3881c 100644 | |
330 | --- a/gdb/solib.h | |
331 | +++ b/gdb/solib.h | |
332 | @@ -78,4 +78,8 @@ extern void set_solib_ops (struct gdbarch *gdbarch, | |
333 | ||
334 | extern int libpthread_name_p (const char *name); | |
335 | ||
336 | +/* Enable or disable optional solib event breakpoints as appropriate. */ | |
337 | + | |
338 | +extern void update_solib_breakpoints (void); | |
339 | + | |
340 | #endif /* SOLIB_H */ | |
341 | diff --git a/gdb/solist.h b/gdb/solist.h | |
342 | index dad11be..14ede10 100644 | |
343 | --- a/gdb/solist.h | |
344 | +++ b/gdb/solist.h | |
345 | @@ -137,6 +137,13 @@ struct target_so_ops | |
346 | core file (in particular, for readonly sections). */ | |
347 | int (*keep_data_in_core) (CORE_ADDR vaddr, | |
348 | unsigned long size); | |
349 | + | |
350 | + /* Enable or disable optional solib event breakpoints as | |
351 | + appropriate. This should be called whenever | |
352 | + stop_on_solib_events is changed. This pointer can be | |
353 | + NULL, in which case no enabling or disabling is necessary | |
354 | + for this target. */ | |
355 | + void (*update_breakpoints) (void); | |
356 | }; | |
357 | ||
358 | /* Free the memory associated with a (so_list *). */ |