]>
Commit | Line | Data |
---|---|---|
bd5635a1 RP |
1 | /* Copyright (C) 1990 Free Software Foundation, Inc. |
2 | ||
3 | This file is part of GDB. | |
4 | ||
bdbd5f50 | 5 | This program is free software; you can redistribute it and/or modify |
bd5635a1 | 6 | it under the terms of the GNU General Public License as published by |
bdbd5f50 JG |
7 | the Free Software Foundation; either version 2 of the License, or |
8 | (at your option) any later version. | |
bd5635a1 | 9 | |
bdbd5f50 | 10 | This program is distributed in the hope that it will be useful, |
bd5635a1 RP |
11 | but WITHOUT ANY WARRANTY; without even the implied warranty of |
12 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |
13 | GNU General Public License for more details. | |
14 | ||
15 | You should have received a copy of the GNU General Public License | |
bdbd5f50 JG |
16 | along with this program; if not, write to the Free Software |
17 | Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */ | |
bd5635a1 RP |
18 | |
19 | /* | |
20 | ** symbol definitions | |
21 | */ | |
22 | #include <sys/types.h> | |
23 | #include <string.h> | |
24 | #include <link.h> | |
d0237a54 JK |
25 | #include <sys/param.h> |
26 | #include <fcntl.h> | |
27 | #include <stdio.h> | |
bd5635a1 RP |
28 | #include "defs.h" |
29 | #include "param.h" | |
30 | #include "symtab.h" | |
31 | #include "gdbcore.h" | |
32 | #include "command.h" | |
b3fdaf3d | 33 | #include "target.h" |
2403f49b | 34 | #include "frame.h" |
bdbd5f50 JG |
35 | #include "regex.h" |
36 | #include "inferior.h" | |
37 | ||
38 | extern char *getenv(); | |
bd5635a1 RP |
39 | |
40 | /* | |
41 | ** local data declarations | |
42 | */ | |
43 | #define MAX_PATH_SIZE 256 | |
44 | struct so_list { | |
45 | struct link_map inferior_lm; /* inferior link map */ | |
46 | struct link_map *inferior_lm_add; | |
47 | long ld_text; | |
48 | char inferior_so_name[MAX_PATH_SIZE]; /* Shared Object Library Name */ | |
49 | struct so_list *next; /* Next Structure */ | |
bdbd5f50 JG |
50 | char symbols_loaded; /* Flag: loaded? */ |
51 | char from_tty; /* Flag: print msgs? */ | |
d0237a54 | 52 | bfd *so_bfd; |
bdbd5f50 JG |
53 | struct section_table *sections; |
54 | struct section_table *sections_end; | |
bd5635a1 RP |
55 | }; |
56 | ||
57 | static struct so_list *so_list_head = 0; | |
58 | ||
d0237a54 JK |
59 | /* |
60 | ** Build a section map for a shared library, record its text size in | |
61 | ** the so_list structure and set up the text section of the shared lib. | |
62 | */ | |
63 | static void | |
64 | solib_map_sections(so) | |
65 | struct so_list *so; | |
66 | { | |
67 | char *filename; | |
68 | char *scratch_pathname; | |
69 | int scratch_chan; | |
70 | struct section_table *p; | |
71 | ||
72 | filename = tilde_expand (so->inferior_so_name); | |
73 | make_cleanup (free, filename); | |
74 | ||
75 | scratch_chan = openp (getenv ("PATH"), 1, filename, O_RDONLY, 0, | |
76 | &scratch_pathname); | |
77 | if (scratch_chan < 0) | |
78 | scratch_chan = openp (getenv ("LD_LIBRARY_PATH"), 1, filename, O_RDONLY, 0, | |
79 | &scratch_pathname); | |
80 | if (scratch_chan < 0) | |
81 | perror_with_name (filename); | |
82 | ||
83 | so->so_bfd = bfd_fdopenr (scratch_pathname, NULL, scratch_chan); | |
84 | if (!so->so_bfd) | |
85 | error ("Could not open `%s' as an executable file: %s", | |
86 | scratch_pathname, bfd_errmsg (bfd_error)); | |
87 | if (!bfd_check_format (so->so_bfd, bfd_object)) | |
88 | error ("\"%s\": not in executable format: %s.", | |
89 | scratch_pathname, bfd_errmsg (bfd_error)); | |
bdbd5f50 | 90 | if (build_section_table (so->so_bfd, &so->sections, &so->sections_end)) |
d0237a54 JK |
91 | error ("Can't find the file sections in `%s': %s", |
92 | exec_bfd->filename, bfd_errmsg (bfd_error)); | |
93 | ||
bdbd5f50 | 94 | for (p = so->sections; p < so->sections_end; p++) |
d0237a54 JK |
95 | { |
96 | if (strcmp (bfd_section_name (so->so_bfd, p->sec_ptr), ".text") == 0) | |
97 | { | |
98 | /* Determine length of text section and relocate it. */ | |
99 | so->ld_text = p->endaddr - p->addr; | |
100 | p->addr += (CORE_ADDR)so->inferior_lm.lm_addr; | |
101 | p->endaddr += (CORE_ADDR)so->inferior_lm.lm_addr; | |
102 | } | |
103 | else | |
104 | /* All other sections are ignored for now. */ | |
105 | p->addr = p->endaddr = 0; | |
106 | } | |
107 | } | |
108 | ||
bd5635a1 RP |
109 | /*=======================================================================*/ |
110 | ||
111 | /* find_solib | |
112 | ** | |
113 | **Description: | |
114 | ** | |
115 | ** This module contains the routine which finds the names of any loaded | |
116 | ** "images" in the current process. The argument in must be NULL on the | |
117 | ** first call, and then the returned value must be passed in on | |
118 | ** subsequent calls. This provides the capability to "step" down the | |
119 | ** list of loaded objects. On the last object, a NULL value is returned. | |
120 | ** The arg and return value are "struct link_map" pointers, as defined | |
121 | ** in <link.h>. | |
122 | ** | |
123 | ** NOTE: This only works under SunOS4.0. | |
124 | */ | |
125 | ||
126 | struct so_list *find_solib(so_list_ptr) | |
127 | struct so_list *so_list_ptr; /* so_list_head position ptr */ | |
128 | { | |
129 | struct so_list *so_list_next = 0; | |
bd5635a1 RP |
130 | struct link_map *inferior_lm = 0; |
131 | struct link_dynamic inferior_dynamic_cpy; | |
132 | struct link_dynamic_2 inferior_ld_2_cpy; | |
133 | struct so_list *new; | |
134 | int i; | |
135 | ||
136 | if (!so_list_ptr) { | |
137 | if (!(so_list_next = so_list_head)) { | |
bdbd5f50 JG |
138 | i = lookup_misc_func ("_DYNAMIC"); |
139 | if (i >= 0) { | |
140 | read_memory(misc_function_vector[i].address, | |
141 | &inferior_dynamic_cpy, | |
142 | sizeof(struct link_dynamic)); | |
bd5635a1 RP |
143 | if (inferior_dynamic_cpy.ld_version == 3) { |
144 | read_memory((CORE_ADDR)inferior_dynamic_cpy.ld_un.ld_2, | |
145 | &inferior_ld_2_cpy, | |
146 | sizeof(struct link_dynamic_2)); | |
147 | inferior_lm = inferior_ld_2_cpy.ld_loaded; | |
148 | } | |
149 | } | |
150 | } | |
151 | } else { | |
152 | /* | |
153 | ** Advance to next local abbreviated load_map structure | |
154 | */ | |
155 | if (!(inferior_lm = so_list_ptr->inferior_lm.lm_next)) { | |
b3fdaf3d JK |
156 | /* See if any were added, but be quiet if we can't read |
157 | from the target any more. */ | |
158 | int status; | |
159 | ||
160 | status = target_read_memory ( | |
161 | (CORE_ADDR)so_list_ptr->inferior_lm_add, | |
e1ce8aa5 | 162 | (char *)&so_list_ptr->inferior_lm, |
b3fdaf3d JK |
163 | sizeof(struct link_map)); |
164 | if (status == 0) | |
165 | inferior_lm = so_list_ptr->inferior_lm.lm_next; | |
166 | else | |
167 | inferior_lm = 0; | |
bd5635a1 RP |
168 | } |
169 | so_list_next = so_list_ptr->next; | |
170 | } | |
171 | if ((!so_list_next) && inferior_lm) { | |
172 | /* | |
173 | ** Get Next LM Structure from inferior image and build | |
174 | ** an local abbreviated load_map structure | |
175 | */ | |
176 | new = (struct so_list *) xmalloc(sizeof(struct so_list)); | |
177 | new->inferior_lm_add = inferior_lm; | |
178 | read_memory((CORE_ADDR)inferior_lm, | |
179 | &new->inferior_lm, | |
180 | sizeof(struct link_map)); | |
181 | ||
182 | read_memory((CORE_ADDR)new->inferior_lm.lm_name, | |
183 | new->inferior_so_name, | |
184 | MAX_PATH_SIZE - 1); | |
185 | new->inferior_so_name[MAX_PATH_SIZE - 1] = 0; | |
186 | /* Zero everything after the first terminating null */ | |
187 | strncpy(new->inferior_so_name, new->inferior_so_name, MAX_PATH_SIZE); | |
188 | ||
d0237a54 JK |
189 | #if 0 |
190 | /* This doesn't work for core files, so instead get ld_text | |
191 | using solib_map_sections (below). */ | |
bd5635a1 RP |
192 | read_memory((CORE_ADDR)new->inferior_lm.lm_ld, |
193 | &inferior_dynamic_cpy, | |
194 | sizeof(struct link_dynamic)); | |
195 | read_memory((CORE_ADDR)inferior_dynamic_cpy.ld_un.ld_2, | |
196 | &inferior_ld_2_cpy, | |
197 | sizeof(struct link_dynamic_2)); | |
198 | new->ld_text = inferior_ld_2_cpy.ld_text; | |
d0237a54 JK |
199 | #endif |
200 | ||
bd5635a1 RP |
201 | new->next = 0; |
202 | new->symbols_loaded = 0; | |
d0237a54 | 203 | new->so_bfd = NULL; |
bdbd5f50 | 204 | new->sections = NULL; |
bd5635a1 RP |
205 | if (so_list_ptr) |
206 | so_list_ptr->next = new; | |
207 | else | |
208 | so_list_head = new; | |
d0237a54 JK |
209 | |
210 | solib_map_sections (new); | |
211 | ||
bd5635a1 RP |
212 | so_list_next = new; |
213 | } | |
214 | return(so_list_next); | |
215 | } | |
d0237a54 | 216 | |
bdbd5f50 JG |
217 | /* A small stub to get us past the arg-passing pinhole of catch_errors. */ |
218 | ||
219 | static int | |
220 | symbol_add_stub (arg) | |
221 | char *arg; | |
d0237a54 | 222 | { |
bdbd5f50 | 223 | register struct so_list *so = (struct so_list *)arg; /* catch_errs bogon */ |
d0237a54 | 224 | |
bdbd5f50 JG |
225 | symbol_file_add (so->inferior_so_name, so->from_tty, |
226 | (unsigned int)so->inferior_lm.lm_addr, 0); | |
227 | return 1; | |
d0237a54 | 228 | } |
bd5635a1 | 229 | |
bdbd5f50 JG |
230 | /* The real work of adding a shared library file to the symtab and |
231 | the section list. */ | |
232 | ||
233 | void | |
234 | solib_add (arg_string, from_tty, target) | |
235 | char *arg_string; | |
236 | int from_tty; | |
237 | struct target_ops *target; | |
bd5635a1 | 238 | { |
bdbd5f50 JG |
239 | register struct so_list *so = 0; /* link map state variable */ |
240 | char *val; | |
241 | int count, old; | |
242 | struct section_table *sec; | |
243 | ||
244 | if (arg_string == 0) | |
245 | re_comp ("."); | |
246 | else if (val = (char *) re_comp (arg_string)) { | |
247 | error ("Invalid regexp: %s", val); | |
248 | } | |
bd5635a1 | 249 | |
bdbd5f50 JG |
250 | /* Getting new symbols may change our opinion about what is |
251 | frameless. */ | |
252 | reinit_frame_cache (); | |
2403f49b | 253 | |
bdbd5f50 JG |
254 | if (from_tty) { |
255 | printf_filtered ("Shared libraries"); | |
bd5635a1 RP |
256 | if (arg_string) |
257 | printf_filtered (" matching regular expresion \"%s\"", arg_string); | |
258 | printf_filtered (":\n"); | |
bdbd5f50 JG |
259 | } |
260 | ||
261 | dont_repeat(); | |
262 | ||
263 | while (so = find_solib(so)) { | |
264 | if (re_exec(so->inferior_so_name)) { | |
265 | if (so->symbols_loaded) { | |
266 | if (from_tty) | |
267 | printf("Symbols already loaded for %s\n", so->inferior_so_name); | |
268 | } else { | |
269 | so->symbols_loaded = 1; | |
270 | so->from_tty = from_tty; | |
271 | catch_errors (symbol_add_stub, (char *)so, | |
06b6c733 | 272 | "Error while reading shared library symbols:\n"); |
bdbd5f50 JG |
273 | } |
274 | } | |
275 | } | |
bd5635a1 | 276 | |
bdbd5f50 JG |
277 | /* Now add the shared library sections to the section table of the |
278 | specified target, if any. */ | |
279 | if (target) { | |
280 | /* Count how many new section_table entries there are. */ | |
281 | so = 0; | |
282 | count = 0; | |
283 | while (0 != (so = find_solib (so))) { | |
284 | count += so->sections_end - so->sections; | |
bd5635a1 | 285 | } |
bdbd5f50 JG |
286 | |
287 | if (count) { | |
288 | /* Reallocate the target's section table including the new size. */ | |
289 | if (target->sections) { | |
290 | old = target->sections_end - target->sections; | |
291 | target->sections = (struct section_table *) | |
292 | realloc ((char *)target->sections, | |
293 | (sizeof (struct section_table)) * (count + old)); | |
294 | } else { | |
295 | old = 0; | |
296 | target->sections = (struct section_table *) | |
297 | malloc ((sizeof (struct section_table)) * count); | |
298 | } | |
299 | target->sections_end = target->sections + (count + old); | |
300 | ||
301 | /* Add these section table entries to the target's table. */ | |
302 | while (0 != (so = find_solib (so))) { | |
303 | count = so->sections_end - so->sections; | |
304 | bcopy (so->sections, (char *)(target->sections + old), | |
305 | (sizeof (struct section_table)) * count); | |
306 | old += count; | |
307 | } | |
308 | } | |
309 | } | |
bd5635a1 | 310 | } |
bdbd5f50 | 311 | |
bd5635a1 RP |
312 | /*=======================================================================*/ |
313 | ||
314 | static void solib_info() | |
315 | { | |
316 | register struct so_list *so = 0; /* link map state variable */ | |
317 | ||
318 | while (so = find_solib(so)) { | |
319 | if (so == so_list_head) { | |
bdbd5f50 | 320 | printf(" Address Range Syms Read Shared Object Library\n"); |
bd5635a1 RP |
321 | } |
322 | printf(" 0x%08x - 0x%08x %s %s\n", | |
323 | so->inferior_lm.lm_addr, | |
324 | so->inferior_lm.lm_addr + so->ld_text - 1, | |
325 | (so->symbols_loaded ? "Yes" : "No "), | |
326 | so->inferior_so_name); | |
327 | } | |
328 | if (!so_list_head) { | |
329 | printf("No shared libraries loaded at this time.\n"); | |
330 | } | |
331 | } | |
332 | ||
333 | /* | |
334 | ** Called by Insert Breakpoint to see if Address is Shared Library Address | |
335 | */ | |
336 | int | |
337 | solib_address(address) | |
338 | CORE_ADDR address; | |
339 | { | |
340 | register struct so_list *so = 0; /* link map state variable */ | |
341 | ||
342 | while (so = find_solib(so)) { | |
343 | if ((address >= (CORE_ADDR) so->inferior_lm.lm_addr) && | |
344 | (address < (CORE_ADDR) so->inferior_lm.lm_addr + so->ld_text)) | |
345 | return 1; | |
346 | } | |
347 | return 0; | |
348 | } | |
349 | ||
350 | /* | |
351 | ** Called by free_all_symtabs | |
352 | */ | |
353 | void | |
354 | clear_solib() | |
355 | { | |
356 | struct so_list *next; | |
357 | ||
358 | while (so_list_head) { | |
bdbd5f50 JG |
359 | if (so_list_head->sections) |
360 | free (so_list_head->sections); | |
d0237a54 JK |
361 | if (so_list_head->so_bfd) |
362 | bfd_close (so_list_head->so_bfd); | |
bd5635a1 RP |
363 | next = so_list_head->next; |
364 | free(so_list_head); | |
365 | so_list_head = next; | |
366 | } | |
bdbd5f50 JG |
367 | } |
368 | ||
369 | /* Called by child_create_inferior when the inferior is stopped at its | |
370 | first instruction. */ | |
371 | ||
372 | void | |
373 | solib_create_inferior_hook() | |
374 | { | |
375 | struct link_dynamic inferior_dynamic_cpy; | |
376 | CORE_ADDR inferior_debug_addr; | |
377 | struct ld_debug inferior_debug_cpy; | |
378 | int in_debugger; | |
379 | CORE_ADDR in_debugger_addr; | |
380 | CORE_ADDR breakpoint_addr; | |
06b6c733 | 381 | int i, j; |
bdbd5f50 JG |
382 | |
383 | /* FIXME: We should look around in the executable code to find _DYNAMIC, | |
384 | if it isn't in the symbol table. It's not that hard to find... | |
385 | Then we can debug stripped executables using shared library symbols. */ | |
386 | i = lookup_misc_func ("_DYNAMIC"); | |
387 | if (i < 0) /* Can't find shared lib ptr. */ | |
388 | return; | |
06b6c733 JG |
389 | if (misc_function_vector[i].address == 0) /* statically linked program */ |
390 | return; | |
bdbd5f50 JG |
391 | |
392 | /* Get link_dynamic structure */ | |
06b6c733 | 393 | j = target_read_memory(misc_function_vector[i].address, |
bdbd5f50 JG |
394 | &inferior_dynamic_cpy, |
395 | sizeof(struct link_dynamic)); | |
06b6c733 JG |
396 | if (j) /* unreadable */ |
397 | return; | |
398 | ||
bdbd5f50 JG |
399 | /* Calc address of debugger interface structure */ |
400 | inferior_debug_addr = (CORE_ADDR)inferior_dynamic_cpy.ldd; | |
401 | /* Calc address of `in_debugger' member of debugger interface structure */ | |
402 | in_debugger_addr = inferior_debug_addr + (CORE_ADDR)((char *)&inferior_debug_cpy.ldd_in_debugger - (char *)&inferior_debug_cpy); | |
403 | /* Write a value of 1 to this member. */ | |
404 | in_debugger = 1; | |
405 | write_memory(in_debugger_addr, &in_debugger, sizeof(in_debugger)); | |
406 | ||
407 | /* Now run the target. Seeing `in_debugger' set, it will set a | |
408 | breakpoint at some convenient place, remember the original contents | |
409 | of that place, and eventually take a SIGTRAP when it runs into the | |
410 | breakpoint. We handle this by restoring the contents of the | |
411 | breakpointed location (which is only known after it stops), | |
412 | chasing around to locate the shared libraries that have been | |
413 | loaded, then resuming. */ | |
414 | ||
415 | clear_proceed_status (); | |
416 | stop_soon_quietly = 1; | |
417 | target_resume (0, 0); | |
418 | wait_for_inferior (); | |
419 | while (stop_signal != SIGTRAP) | |
420 | { | |
421 | /* FIXME, what if child has exit()ed? Must exit loop somehow */ | |
422 | target_resume (0, stop_signal); | |
423 | wait_for_inferior (); | |
424 | } | |
425 | stop_soon_quietly = 0; | |
426 | ||
427 | /* Set `in_debugger' to zero now. WHY, is this needed? */ | |
428 | in_debugger = 0; | |
429 | write_memory(in_debugger_addr, &in_debugger, sizeof(in_debugger)); | |
430 | read_memory(inferior_debug_addr, &inferior_debug_cpy, sizeof(inferior_debug_cpy)); | |
431 | /* FIXME: maybe we should add the common symbols from the ldd_cp chain | |
432 | * to the misc_function_vector ? | |
433 | */ | |
434 | breakpoint_addr = (CORE_ADDR)inferior_debug_cpy.ldd_bp_addr; | |
435 | if (stop_pc - DECR_PC_AFTER_BREAK == breakpoint_addr) | |
436 | { | |
437 | write_memory(breakpoint_addr, &inferior_debug_cpy.ldd_bp_inst, sizeof(inferior_debug_cpy.ldd_bp_inst)); | |
438 | if (DECR_PC_AFTER_BREAK) | |
439 | { | |
440 | stop_pc -= DECR_PC_AFTER_BREAK; | |
441 | write_register (PC_REGNUM, stop_pc); | |
442 | } | |
443 | } | |
444 | solib_add ((char *)0, 0, (struct target_ops *)0); | |
445 | } | |
446 | ||
447 | void | |
448 | sharedlibrary_command (args, from_tty) | |
449 | { | |
450 | solib_add (args, from_tty, (struct target_ops *)0); | |
bd5635a1 RP |
451 | } |
452 | ||
453 | void | |
454 | _initialize_solib() | |
455 | { | |
456 | ||
bdbd5f50 | 457 | add_com("sharedlibrary", class_files, sharedlibrary_command, |
bd5635a1 RP |
458 | "Load shared object library symbols for files matching REGEXP."); |
459 | add_info("sharedlibrary", solib_info, | |
460 | "Status of loaded shared object libraries"); | |
bd5635a1 | 461 | } |