GNU Binutils with patches for OS216
Revision | bd8469f2d9317347e8b52dde987d672baf98454c (tree) |
---|---|
Zeit | 2004-03-24 13:10:01 |
Autor | Elena Zannoni <ezannoni@kwik...> |
Commiter | Elena Zannoni |
2004-03-23 Elena Zannoni <ezannoni@redhat.com>
@@ -1,3 +1,59 @@ | ||
1 | +2004-03-23 Elena Zannoni <ezannoni@redhat.com> | |
2 | + | |
3 | + * solib-svr4.c (svr4_solib_create_inferior_hook): Disable | |
4 | + breakpoints at startup. | |
5 | + (elf_locate_base): Find out where the entry point for the program | |
6 | + is, using the auxv vector, if possible. Compute the address of | |
7 | + .dynamic using it. | |
8 | + (svr4_current_sos): Don't ignore the first entry if we have PIE, | |
9 | + it's our main program. Delete code that was skipping over the | |
10 | + solib entry for main executable. | |
11 | + | |
12 | + * solist.h (struct so_list): Add fields main and main_relocated. | |
13 | + (add_to_target_sections): Export. | |
14 | + | |
15 | + * solib.c (symbol_add_stub): Handle main executable in shared | |
16 | + library list. Ignore it if it has been relocated already. Add it | |
17 | + as the main symbol file, otherwise. | |
18 | + | |
19 | + * infrun.c (handle_inferior_event): Re-enable startup breakpoints. | |
20 | + * solib-svr4.c (elf_locate_base, first_link_map_member) | |
21 | + svr4_current_sos, enable_break): Add debugging output. | |
22 | + | |
23 | + * solist.h (debug_solib): Export. | |
24 | + | |
25 | + * solib.c (debug_solib): New variable to enable debugging output. | |
26 | + (symbol_add_stub, update_solib_list, update_solib_list) | |
27 | + (add_to_target_sections): Add debugging output. | |
28 | + (_initialize_solib): Add new comand to enable printing of | |
29 | + debugging output. | |
30 | + (add_to_target_sections): New function. Factored out from | |
31 | + update_solib_list. | |
32 | + (update_solib_list): Call add_to_target_sections. | |
33 | + | |
34 | + * varobj.h (varobj_refresh): New prototype. | |
35 | + * varobj.c (varobj_refresh): New function. | |
36 | + * symfile.c (reread_symbols): Make sure that we recompute the | |
37 | + entry point for the program. | |
38 | + (symbol_file_clear): Clear the solibs as well, if we change symbol | |
39 | + files. | |
40 | + (clear_symtab_users): Refresh the varobjs that depend on the symtabs | |
41 | + we are clearing. | |
42 | + * objfiles.c (entry_point_address): Rewrite, to fetch entry point | |
43 | + from auxv vector, if possible. | |
44 | + Add include of elf/common.h. | |
45 | + * breakpoint.h (enum bptype): Add bp type bp_startup_disabled. | |
46 | + (re_enable_breakpoints_at_startup) | |
47 | + (disable_breakpoints_at_startup): Add prototypes | |
48 | + * breakpoint.c (re_enable_breakpoints_at_startup) | |
49 | + (disable_breakpoints_at_startup): New functions. | |
50 | + (describe_other_breakpoints, delete_breakpoint) | |
51 | + (breakpoint_re_set_one): Handle new bp type. | |
52 | + * auxv.h (target_auxv_parse, target_auxv_search): Update. | |
53 | + * auxv.c (target_auxv_parse, target_auxv_search) | |
54 | + (fprint_target_auxv): Use ULONGEST instead of CORE_ADDR for | |
55 | + variable. Change variable name to at_type. | |
56 | + | |
1 | 57 | 2004-03-23 Andrew Cagney <cagney@redhat.com> |
2 | 58 | |
3 | 59 | * MAINTAINERS (Past Maintainers): Add Mark Salter and Fernando |
@@ -2412,7 +2412,7 @@ symfile.o: symfile.c $(defs_h) $(bfdlink_h) $(symtab_h) $(gdbtypes_h) \ | ||
2412 | 2412 | $(complaints_h) $(demangle_h) $(inferior_h) $(filenames_h) \ |
2413 | 2413 | $(gdb_stabs_h) $(gdb_obstack_h) $(completer_h) $(bcache_h) \ |
2414 | 2414 | $(hashtab_h) $(readline_h) $(gdb_assert_h) $(block_h) \ |
2415 | - $(gdb_string_h) $(gdb_stat_h) | |
2415 | + $(gdb_string_h) $(gdb_stat_h) $(varobj_h) | |
2416 | 2416 | symmisc.o: symmisc.c $(defs_h) $(symtab_h) $(gdbtypes_h) $(bfd_h) \ |
2417 | 2417 | $(symfile_h) $(objfiles_h) $(breakpoint_h) $(command_h) \ |
2418 | 2418 | $(gdb_obstack_h) $(language_h) $(bcache_h) $(block_h) $(gdb_regex_h) \ |
@@ -119,7 +119,7 @@ target_auxv_read (struct target_ops *ops, char **data) | ||
119 | 119 | Return 1 if an entry was read into *TYPEP and *VALP. */ |
120 | 120 | int |
121 | 121 | target_auxv_parse (struct target_ops *ops, char **readptr, char *endptr, |
122 | - CORE_ADDR *typep, CORE_ADDR *valp) | |
122 | + ULONGEST *typep, CORE_ADDR *valp) | |
123 | 123 | { |
124 | 124 | const int sizeof_auxv_field = TYPE_LENGTH (builtin_type_void_data_ptr); |
125 | 125 | char *ptr = *readptr; |
@@ -144,9 +144,10 @@ target_auxv_parse (struct target_ops *ops, char **readptr, char *endptr, | ||
144 | 144 | an error getting the information. On success, return 1 after |
145 | 145 | storing the entry's value field in *VALP. */ |
146 | 146 | int |
147 | -target_auxv_search (struct target_ops *ops, CORE_ADDR match, CORE_ADDR *valp) | |
147 | +target_auxv_search (struct target_ops *ops, ULONGEST match, CORE_ADDR *valp) | |
148 | 148 | { |
149 | - CORE_ADDR type, val; | |
149 | + CORE_ADDR val; | |
150 | + ULONGEST at_type; | |
150 | 151 | char *data; |
151 | 152 | int n = target_auxv_read (ops, &data); |
152 | 153 | char *ptr = data; |
@@ -156,10 +157,10 @@ target_auxv_search (struct target_ops *ops, CORE_ADDR match, CORE_ADDR *valp) | ||
156 | 157 | return n; |
157 | 158 | |
158 | 159 | while (1) |
159 | - switch (target_auxv_parse (ops, &ptr, data + n, &type, &val)) | |
160 | + switch (target_auxv_parse (ops, &ptr, data + n, &at_type, &val)) | |
160 | 161 | { |
161 | 162 | case 1: /* Here's an entry, check it. */ |
162 | - if (type == match) | |
163 | + if (at_type == match) | |
163 | 164 | { |
164 | 165 | xfree (data); |
165 | 166 | *valp = val; |
@@ -182,7 +183,8 @@ target_auxv_search (struct target_ops *ops, CORE_ADDR match, CORE_ADDR *valp) | ||
182 | 183 | int |
183 | 184 | fprint_target_auxv (struct ui_file *file, struct target_ops *ops) |
184 | 185 | { |
185 | - CORE_ADDR type, val; | |
186 | + CORE_ADDR val; | |
187 | + ULONGEST at_type; | |
186 | 188 | char *data; |
187 | 189 | int len = target_auxv_read (ops, &data); |
188 | 190 | char *ptr = data; |
@@ -191,14 +193,14 @@ fprint_target_auxv (struct ui_file *file, struct target_ops *ops) | ||
191 | 193 | if (len <= 0) |
192 | 194 | return len; |
193 | 195 | |
194 | - while (target_auxv_parse (ops, &ptr, data + len, &type, &val) > 0) | |
196 | + while (target_auxv_parse (ops, &ptr, data + len, &at_type, &val) > 0) | |
195 | 197 | { |
196 | 198 | extern int addressprint; |
197 | 199 | const char *name = "???"; |
198 | 200 | const char *description = ""; |
199 | 201 | enum { dec, hex, str } flavor = hex; |
200 | 202 | |
201 | - switch (type) | |
203 | + switch (at_type) | |
202 | 204 | { |
203 | 205 | #define TAG(tag, text, kind) \ |
204 | 206 | case tag: name = #tag; description = text; flavor = kind; break |
@@ -249,7 +251,7 @@ fprint_target_auxv (struct ui_file *file, struct target_ops *ops) | ||
249 | 251 | } |
250 | 252 | |
251 | 253 | fprintf_filtered (file, "%-4s %-20s %-30s ", |
252 | - paddr_d (type), name, description); | |
254 | + paddr_d (at_type), name, description); | |
253 | 255 | switch (flavor) |
254 | 256 | { |
255 | 257 | case dec: |
@@ -43,14 +43,14 @@ extern LONGEST target_auxv_read (struct target_ops *ops, char **data); | ||
43 | 43 | Return 1 if an entry was read into *TYPEP and *VALP. */ |
44 | 44 | extern int target_auxv_parse (struct target_ops *ops, |
45 | 45 | char **readptr, char *endptr, |
46 | - CORE_ADDR *typep, CORE_ADDR *valp); | |
46 | + ULONGEST *typep, CORE_ADDR *valp); | |
47 | 47 | |
48 | 48 | /* Extract the auxiliary vector entry with a_type matching MATCH. |
49 | 49 | Return zero if no such entry was found, or -1 if there was |
50 | 50 | an error getting the information. On success, return 1 after |
51 | 51 | storing the entry's value field in *VALP. */ |
52 | 52 | extern int target_auxv_search (struct target_ops *ops, |
53 | - CORE_ADDR match, CORE_ADDR *valp); | |
53 | + ULONGEST match, CORE_ADDR *valp); | |
54 | 54 | |
55 | 55 | /* Print the contents of the target's AUXV on the specified file. */ |
56 | 56 | extern int fprint_target_auxv (struct ui_file *file, struct target_ops *ops); |
@@ -3793,6 +3793,7 @@ describe_other_breakpoints (CORE_ADDR pc, asection *section) | ||
3793 | 3793 | b->number, |
3794 | 3794 | ((b->enable_state == bp_disabled || |
3795 | 3795 | b->enable_state == bp_shlib_disabled || |
3796 | + b->enable_state == bp_startup_disabled || | |
3796 | 3797 | b->enable_state == bp_call_disabled) |
3797 | 3798 | ? " (disabled)" |
3798 | 3799 | : b->enable_state == bp_permanent |
@@ -4427,6 +4428,62 @@ re_enable_breakpoints_in_shlibs (void) | ||
4427 | 4428 | |
4428 | 4429 | #endif |
4429 | 4430 | |
4431 | +void | |
4432 | +disable_breakpoints_at_startup (int silent) | |
4433 | +{ | |
4434 | + struct breakpoint *b; | |
4435 | + int disabled_startup_breaks = 0; | |
4436 | + | |
4437 | + if (bfd_get_start_address (exec_bfd) != entry_point_address ()) | |
4438 | + { | |
4439 | + ALL_BREAKPOINTS (b) | |
4440 | + { | |
4441 | + if (((b->type == bp_breakpoint) || | |
4442 | + (b->type == bp_hardware_breakpoint)) && | |
4443 | + b->enable_state == bp_enabled && | |
4444 | + !b->loc->duplicate) | |
4445 | + { | |
4446 | + b->enable_state = bp_startup_disabled; | |
4447 | + if (!silent) | |
4448 | + { | |
4449 | + if (!disabled_startup_breaks) | |
4450 | + { | |
4451 | + target_terminal_ours_for_output (); | |
4452 | + warning ("Temporarily disabling breakpoints:"); | |
4453 | + } | |
4454 | + disabled_startup_breaks = 1; | |
4455 | + warning ("breakpoint #%d addr 0x%s", b->number, paddr_nz(b->loc->address)); | |
4456 | + } | |
4457 | + } | |
4458 | + } | |
4459 | + } | |
4460 | +} | |
4461 | + | |
4462 | +/* Try to reenable any breakpoints after startup. */ | |
4463 | +void | |
4464 | +re_enable_breakpoints_at_startup (void) | |
4465 | +{ | |
4466 | + struct breakpoint *b; | |
4467 | + | |
4468 | + if (bfd_get_start_address (exec_bfd) != entry_point_address ()) | |
4469 | + { | |
4470 | + ALL_BREAKPOINTS (b) | |
4471 | + if (b->enable_state == bp_startup_disabled) | |
4472 | + { | |
4473 | + char buf[1]; | |
4474 | + | |
4475 | + /* Do not reenable the breakpoint if the shared library | |
4476 | + is still not mapped in. */ | |
4477 | + if (target_read_memory (b->loc->address, buf, 1) == 0) | |
4478 | + { | |
4479 | + /*printf ("enabling breakpoint at 0x%s\n", paddr_nz(b->loc->address));*/ | |
4480 | + b->enable_state = bp_enabled; | |
4481 | + } | |
4482 | + } | |
4483 | + } | |
4484 | +} | |
4485 | + | |
4486 | + | |
4430 | 4487 | static void |
4431 | 4488 | solib_load_unload_1 (char *hookname, int tempflag, char *dll_pathname, |
4432 | 4489 | char *cond_string, enum bptype bp_kind) |
@@ -6940,6 +6997,7 @@ delete_breakpoint (struct breakpoint *bpt) | ||
6940 | 6997 | && !b->loc->duplicate |
6941 | 6998 | && b->enable_state != bp_disabled |
6942 | 6999 | && b->enable_state != bp_shlib_disabled |
7000 | + && b->enable_state != bp_startup_disabled | |
6943 | 7001 | && !b->pending |
6944 | 7002 | && b->enable_state != bp_call_disabled) |
6945 | 7003 | { |
@@ -7151,7 +7209,8 @@ breakpoint_re_set_one (void *bint) | ||
7151 | 7209 | break; |
7152 | 7210 | |
7153 | 7211 | save_enable = b->enable_state; |
7154 | - if (b->enable_state != bp_shlib_disabled) | |
7212 | + if (b->enable_state != bp_shlib_disabled | |
7213 | + || b->enable_state != bp_shlib_disabled) | |
7155 | 7214 | b->enable_state = bp_disabled; |
7156 | 7215 | |
7157 | 7216 | set_language (b->language); |
@@ -159,6 +159,7 @@ enum enable_state | ||
159 | 159 | automatically enabled and reset when the call |
160 | 160 | "lands" (either completes, or stops at another |
161 | 161 | eventpoint). */ |
162 | + bp_startup_disabled, | |
162 | 163 | bp_permanent /* There is a breakpoint instruction hard-wired into |
163 | 164 | the target's code. Don't try to write another |
164 | 165 | breakpoint instruction on top of it, or restore |
@@ -771,8 +772,12 @@ extern void remove_thread_event_breakpoints (void); | ||
771 | 772 | |
772 | 773 | extern void disable_breakpoints_in_shlibs (int silent); |
773 | 774 | |
775 | +extern void disable_breakpoints_at_startup (int silent); | |
776 | + | |
774 | 777 | extern void re_enable_breakpoints_in_shlibs (void); |
775 | 778 | |
779 | +void re_enable_breakpoints_at_startup (void); | |
780 | + | |
776 | 781 | extern void create_solib_load_event_breakpoint (char *, int, char *, char *); |
777 | 782 | |
778 | 783 | extern void create_solib_unload_event_breakpoint (char *, int, |
@@ -2355,6 +2355,11 @@ process_event_stop_test: | ||
2355 | 2355 | code segments in shared libraries might be mapped in now. */ |
2356 | 2356 | re_enable_breakpoints_in_shlibs (); |
2357 | 2357 | |
2358 | + /* For PIE executables, we dont really know where the | |
2359 | + breakpoints are going to be until we start up the | |
2360 | + inferior. */ | |
2361 | + re_enable_breakpoints_at_startup (); | |
2362 | + | |
2358 | 2363 | /* If requested, stop when the dynamic linker notifies |
2359 | 2364 | gdb of events. This allows the user to get control |
2360 | 2365 | and place breakpoints in initializer routines for |
@@ -46,6 +46,8 @@ | ||
46 | 46 | #include "block.h" |
47 | 47 | #include "dictionary.h" |
48 | 48 | |
49 | +#include "elf/common.h" | |
50 | + | |
49 | 51 | /* Prototypes for local functions */ |
50 | 52 | |
51 | 53 | static void objfile_alloc_data (struct objfile *objfile); |
@@ -263,7 +265,19 @@ init_entry_point_info (struct objfile *objfile) | ||
263 | 265 | CORE_ADDR |
264 | 266 | entry_point_address (void) |
265 | 267 | { |
266 | - return symfile_objfile ? symfile_objfile->ei.entry_point : 0; | |
268 | + int ret; | |
269 | + CORE_ADDR entry_addr; | |
270 | + | |
271 | + /* Find the address of the entry point of the program from the | |
272 | + auxv vector. */ | |
273 | + ret = target_auxv_search (¤t_target, AT_ENTRY, &entry_addr); | |
274 | + if (ret == 1) | |
275 | + return entry_addr; | |
276 | + /*if (ret == 0 || ret == -1)*/ | |
277 | + else | |
278 | + { | |
279 | + return symfile_objfile ? symfile_objfile->ei.entry_point : 0; | |
280 | + } | |
267 | 281 | } |
268 | 282 | |
269 | 283 | /* Create the terminating entry of OBJFILE's minimal symbol table. |
@@ -179,7 +179,9 @@ static CORE_ADDR breakpoint_addr; /* Address where end bkpt is set */ | ||
179 | 179 | |
180 | 180 | /* Local function prototypes */ |
181 | 181 | |
182 | +#if 0 | |
182 | 183 | static int match_main (char *); |
184 | +#endif | |
183 | 185 | |
184 | 186 | static CORE_ADDR bfd_lookup_symbol (bfd *, char *, flagword); |
185 | 187 |
@@ -428,22 +430,79 @@ elf_locate_base (void) | ||
428 | 430 | { |
429 | 431 | struct bfd_section *dyninfo_sect; |
430 | 432 | int dyninfo_sect_size; |
431 | - CORE_ADDR dyninfo_addr; | |
433 | + CORE_ADDR dyninfo_addr, relocated_dyninfo_addr, entry_addr; | |
432 | 434 | char *buf; |
433 | 435 | char *bufend; |
434 | 436 | int arch_size; |
437 | + int ret; | |
438 | + | |
439 | + /* Find the address of the entry point of the program from the | |
440 | + auxv vector. */ | |
441 | + ret = target_auxv_search (¤t_target, AT_ENTRY, &entry_addr); | |
442 | + | |
443 | + if (ret == 0 || ret == -1) | |
444 | + { | |
445 | + /* No auxv info, maybe an older kernel. Fake our way through. */ | |
446 | + entry_addr = bfd_get_start_address (exec_bfd); | |
447 | + | |
448 | + if (debug_solib) | |
449 | + fprintf_unfiltered (gdb_stdlog, | |
450 | + "elf_locate_base: program entry address not found. Using bfd's 0x%s for %s\n", | |
451 | + paddr_nz (entry_addr), exec_bfd->filename); | |
452 | + } | |
453 | + else | |
454 | + { | |
455 | + if (debug_solib) | |
456 | + fprintf_unfiltered (gdb_stdlog, | |
457 | + "elf_locate_base: found program entry address 0x%s for %s\n", | |
458 | + paddr_nz (entry_addr), exec_bfd->filename); | |
459 | + } | |
435 | 460 | |
436 | 461 | /* Find the start address of the .dynamic section. */ |
437 | 462 | dyninfo_sect = bfd_get_section_by_name (exec_bfd, ".dynamic"); |
438 | 463 | if (dyninfo_sect == NULL) |
439 | - return 0; | |
464 | + { | |
465 | + if (debug_solib) | |
466 | + fprintf_unfiltered (gdb_stdlog, | |
467 | + "elf_locate_base: .dynamic section not found in %s -- return now\n", | |
468 | + exec_bfd->filename); | |
469 | + return 0; | |
470 | + } | |
471 | + else | |
472 | + { | |
473 | + if (debug_solib) | |
474 | + fprintf_unfiltered (gdb_stdlog, | |
475 | + "elf_locate_base: .dynamic section found in %s\n", | |
476 | + exec_bfd->filename); | |
477 | + } | |
478 | + | |
440 | 479 | dyninfo_addr = bfd_section_vma (exec_bfd, dyninfo_sect); |
480 | + if (debug_solib) | |
481 | + fprintf_unfiltered (gdb_stdlog, | |
482 | + "elf_locate_base: unrelocated .dynamic addr 0x%s\n", | |
483 | + paddr_nz (dyninfo_addr)); | |
484 | + | |
485 | + relocated_dyninfo_addr = dyninfo_addr | |
486 | + + entry_addr - bfd_get_start_address(exec_bfd); | |
487 | + if (debug_solib) | |
488 | + fprintf_unfiltered (gdb_stdlog, | |
489 | + "elf_locate_base: relocated .dyn addr 0x%s for %s\n", | |
490 | + paddr_nz(relocated_dyninfo_addr), exec_bfd->filename); | |
441 | 491 | |
442 | 492 | /* Read in .dynamic section, silently ignore errors. */ |
443 | 493 | dyninfo_sect_size = bfd_section_size (exec_bfd, dyninfo_sect); |
444 | 494 | buf = alloca (dyninfo_sect_size); |
445 | - if (target_read_memory (dyninfo_addr, buf, dyninfo_sect_size)) | |
446 | - return 0; | |
495 | + if (debug_solib) | |
496 | + fprintf_unfiltered (gdb_stdlog, | |
497 | + "elf_locate_base: read in .dynamic section\n"); | |
498 | + if (target_read_memory (relocated_dyninfo_addr, buf, dyninfo_sect_size)) | |
499 | + { | |
500 | + if (debug_solib) | |
501 | + fprintf_unfiltered (gdb_stdlog, | |
502 | + "elf_locate_base: couldn't read .dynamic section at 0x%s -- return now\n", | |
503 | + paddr_nz (relocated_dyninfo_addr)); | |
504 | + return 0; | |
505 | + } | |
447 | 506 | |
448 | 507 | /* Find the DT_DEBUG entry in the the .dynamic section. |
449 | 508 | For mips elf we look for DT_MIPS_RLD_MAP, mips elf apparently has |
@@ -470,6 +529,10 @@ elf_locate_base (void) | ||
470 | 529 | { |
471 | 530 | dyn_ptr = bfd_h_get_32 (exec_bfd, |
472 | 531 | (bfd_byte *) x_dynp->d_un.d_ptr); |
532 | + if (debug_solib) | |
533 | + fprintf_unfiltered (gdb_stdlog, | |
534 | + "elf_locate_base: DT_DEBUG entry has value 0x%s -- return now\n", | |
535 | + paddr_nz (dyn_ptr)); | |
473 | 536 | return dyn_ptr; |
474 | 537 | } |
475 | 538 | else if (dyn_tag == DT_MIPS_RLD_MAP) |
@@ -613,6 +676,10 @@ first_link_map_member (void) | ||
613 | 676 | char *r_map_buf = xmalloc (lmo->r_map_size); |
614 | 677 | struct cleanup *cleanups = make_cleanup (xfree, r_map_buf); |
615 | 678 | |
679 | + if (debug_solib) | |
680 | + fprintf_unfiltered (gdb_stdlog, | |
681 | + "first_link_map_member: read at 0x%s\n", | |
682 | + paddr_nz (debug_base + lmo->r_map_offset)); | |
616 | 683 | read_memory (debug_base + lmo->r_map_offset, r_map_buf, lmo->r_map_size); |
617 | 684 | |
618 | 685 | /* Assume that the address is unsigned. */ |
@@ -726,6 +793,10 @@ svr4_current_sos (void) | ||
726 | 793 | CORE_ADDR lm; |
727 | 794 | struct so_list *head = 0; |
728 | 795 | struct so_list **link_ptr = &head; |
796 | + if (debug_solib) | |
797 | + fprintf_unfiltered (gdb_stdlog, | |
798 | + "svr4_current_sos: exec_bfd %s\n", | |
799 | + exec_bfd->filename); | |
729 | 800 | |
730 | 801 | /* Make sure we've looked up the inferior's dynamic linker's base |
731 | 802 | structure. */ |
@@ -736,12 +807,22 @@ svr4_current_sos (void) | ||
736 | 807 | /* If we can't find the dynamic linker's base structure, this |
737 | 808 | must not be a dynamically linked executable. Hmm. */ |
738 | 809 | if (! debug_base) |
739 | - return 0; | |
810 | + { | |
811 | + if (debug_solib) | |
812 | + fprintf_unfiltered (gdb_stdlog, | |
813 | + "svr4_current_sos: no DT_DEBUG found in %s -- return now\n", | |
814 | + exec_bfd->filename); | |
815 | + return 0; | |
816 | + } | |
740 | 817 | } |
741 | 818 | |
742 | 819 | /* Walk the inferior's link map list, and build our list of |
743 | 820 | `struct so_list' nodes. */ |
744 | - lm = first_link_map_member (); | |
821 | + if (debug_solib) | |
822 | + fprintf_unfiltered (gdb_stdlog, | |
823 | + "svr4_current_sos: walk link map in %s\n", | |
824 | + exec_bfd->filename); | |
825 | + lm = first_link_map_member (); | |
745 | 826 | while (lm) |
746 | 827 | { |
747 | 828 | struct link_map_offsets *lmo = SVR4_FETCH_LINK_MAP_OFFSETS (); |
@@ -758,54 +839,133 @@ svr4_current_sos (void) | ||
758 | 839 | make_cleanup (xfree, new->lm_info->lm); |
759 | 840 | memset (new->lm_info->lm, 0, lmo->link_map_size); |
760 | 841 | |
842 | + if (debug_solib) | |
843 | + fprintf_unfiltered (gdb_stdlog, | |
844 | + "svr4_current_sos: read lm at 0x%s\n", paddr_nz(lm)); | |
761 | 845 | read_memory (lm, new->lm_info->lm, lmo->link_map_size); |
762 | 846 | |
763 | 847 | lm = LM_NEXT (new); |
764 | 848 | |
849 | + if (debug_solib) | |
850 | + fprintf_unfiltered (gdb_stdlog, | |
851 | + "svr4_current_sos: is first link entry? %d\n", | |
852 | + IGNORE_FIRST_LINK_MAP_ENTRY (new)); | |
853 | + | |
765 | 854 | /* For SVR4 versions, the first entry in the link map is for the |
766 | 855 | inferior executable, so we must ignore it. For some versions of |
767 | 856 | SVR4, it has no name. For others (Solaris 2.3 for example), it |
768 | 857 | does have a name, so we can no longer use a missing name to |
769 | 858 | decide when to ignore it. */ |
770 | 859 | if (IGNORE_FIRST_LINK_MAP_ENTRY (new)) |
771 | - free_so (new); | |
860 | + { | |
861 | + | |
862 | + if (bfd_get_start_address (exec_bfd) == entry_point_address ()) | |
863 | + { | |
864 | + free_so (new); | |
865 | + } | |
866 | + else | |
867 | + { | |
868 | + struct so_list *gdb_solib; | |
869 | + if (debug_solib) | |
870 | + fprintf_unfiltered (gdb_stdlog, | |
871 | + "svr4_current_sos: Processing first link map entry\n"); | |
872 | + strncpy (new->so_name, exec_bfd->filename, | |
873 | + SO_NAME_MAX_PATH_SIZE - 1); | |
874 | + new->so_name[SO_NAME_MAX_PATH_SIZE - 1] = '\0'; | |
875 | + strcpy (new->so_original_name, new->so_name); | |
876 | + /*new->main = 1;*/ | |
877 | + new->main_relocated = 0; | |
878 | + | |
879 | + if (debug_solib) | |
880 | + { | |
881 | + fprintf_unfiltered (gdb_stdlog, | |
882 | + "svr4_current_sos: Processing nameless DSO\n"); | |
883 | + fprintf_unfiltered (gdb_stdlog, | |
884 | + "svr4_current_sos: adding name %s\n", | |
885 | + new->so_name); | |
886 | + } | |
887 | + | |
888 | + for (gdb_solib = master_so_list (); gdb_solib; gdb_solib = gdb_solib->next) | |
889 | + { | |
890 | + if (debug_solib) | |
891 | + fprintf_unfiltered (gdb_stdlog, | |
892 | + "svr4_current_sos: compare gdb %s and new %s\n", | |
893 | + gdb_solib->so_name, new->so_name); | |
894 | + if (!strcmp (gdb_solib->so_name, new->so_name)) | |
895 | + if (gdb_solib->main_relocated) | |
896 | + { | |
897 | + if (debug_solib) | |
898 | + fprintf_unfiltered (gdb_stdlog, | |
899 | + "svr4_current_sos: found main relocated\n"); | |
900 | + break; | |
901 | + } | |
902 | + } | |
903 | + | |
904 | + if ((gdb_solib && !gdb_solib->main_relocated) || (!gdb_solib)) | |
905 | + { | |
906 | + add_to_target_sections (0 /*from_tty*/, ¤t_target, new); | |
907 | + new->main = 1; | |
908 | + } | |
909 | + /* We need this in the list of shared libs we return because | |
910 | + solib_add_stub will loop through it and add the symbol file. */ | |
911 | + new->next = 0; | |
912 | + *link_ptr = new; | |
913 | + link_ptr = &new->next; | |
914 | + } | |
915 | + } | |
772 | 916 | else |
773 | 917 | { |
774 | 918 | int errcode; |
775 | 919 | char *buffer; |
776 | 920 | |
777 | 921 | /* Extract this shared object's name. */ |
922 | + if (debug_solib) | |
923 | + fprintf_unfiltered (gdb_stdlog, | |
924 | + "svr4_current_sos: read LM_NAME\n"); | |
925 | + | |
778 | 926 | target_read_string (LM_NAME (new), &buffer, |
779 | 927 | SO_NAME_MAX_PATH_SIZE - 1, &errcode); |
780 | 928 | if (errcode != 0) |
781 | 929 | { |
782 | - warning ("current_sos: Can't read pathname for load map: %s\n", | |
930 | + warning ("svr4_current_sos: Can't read pathname for load map: %s\n", | |
783 | 931 | safe_strerror (errcode)); |
784 | 932 | } |
785 | 933 | else |
786 | 934 | { |
935 | + if (debug_solib) | |
936 | + fprintf_unfiltered (gdb_stdlog, | |
937 | + "svr4_current_sos: LM_NAME is <%s>\n", | |
938 | + buffer); | |
939 | + | |
787 | 940 | strncpy (new->so_name, buffer, SO_NAME_MAX_PATH_SIZE - 1); |
788 | 941 | new->so_name[SO_NAME_MAX_PATH_SIZE - 1] = '\0'; |
789 | 942 | xfree (buffer); |
790 | 943 | strcpy (new->so_original_name, new->so_name); |
944 | + if (debug_solib) | |
945 | + { | |
946 | + fprintf_unfiltered (gdb_stdlog, | |
947 | + "svr4_current_sos: Processing DSO: %s\n", | |
948 | + new->so_name); | |
949 | + fprintf_unfiltered (gdb_stdlog, | |
950 | + "svr4_current_sos: first link entry %d\n", | |
951 | + IGNORE_FIRST_LINK_MAP_ENTRY (new)); | |
952 | + } | |
791 | 953 | } |
792 | 954 | |
793 | - /* If this entry has no name, or its name matches the name | |
794 | - for the main executable, don't include it in the list. */ | |
795 | - if (! new->so_name[0] | |
796 | - || match_main (new->so_name)) | |
797 | - free_so (new); | |
798 | - else | |
799 | - { | |
800 | - new->next = 0; | |
801 | - *link_ptr = new; | |
802 | - link_ptr = &new->next; | |
803 | - } | |
955 | + new->next = 0; | |
956 | + *link_ptr = new; | |
957 | + link_ptr = &new->next; | |
958 | + | |
804 | 959 | } |
805 | 960 | |
806 | 961 | discard_cleanups (old_chain); |
807 | 962 | } |
808 | 963 | |
964 | + if (debug_solib) | |
965 | + fprintf_unfiltered (gdb_stdlog, | |
966 | + "svr4_current_sos: ENDS %s\n", | |
967 | + exec_bfd->filename); | |
968 | + | |
809 | 969 | return head; |
810 | 970 | } |
811 | 971 |
@@ -824,7 +984,7 @@ svr4_fetch_objfile_link_map (struct objfile *objfile) | ||
824 | 984 | return 0; /* failed somehow... */ |
825 | 985 | |
826 | 986 | /* Position ourselves on the first link map. */ |
827 | - lm = first_link_map_member (); | |
987 | + lm = first_link_map_member (); | |
828 | 988 | while (lm) |
829 | 989 | { |
830 | 990 | /* Get info on the layout of the r_debug and link_map structures. */ |
@@ -885,7 +1045,7 @@ svr4_fetch_objfile_link_map (struct objfile *objfile) | ||
885 | 1045 | /* On some systems, the only way to recognize the link map entry for |
886 | 1046 | the main executable file is by looking at its name. Return |
887 | 1047 | non-zero iff SONAME matches one of the known main executable names. */ |
888 | - | |
1048 | +#if 0 | |
889 | 1049 | static int |
890 | 1050 | match_main (char *soname) |
891 | 1051 | { |
@@ -899,6 +1059,7 @@ match_main (char *soname) | ||
899 | 1059 | |
900 | 1060 | return (0); |
901 | 1061 | } |
1062 | +#endif | |
902 | 1063 | |
903 | 1064 | /* Return 1 if PC lies in the dynamic symbol resolution code of the |
904 | 1065 | SVR4 run time loader. */ |
@@ -998,6 +1159,11 @@ enable_break (void) | ||
998 | 1159 | /* Find the .interp section; if not found, warn the user and drop |
999 | 1160 | into the old breakpoint at symbol code. */ |
1000 | 1161 | interp_sect = bfd_get_section_by_name (exec_bfd, ".interp"); |
1162 | + | |
1163 | + if (debug_solib) | |
1164 | + fprintf_unfiltered (gdb_stdlog, | |
1165 | + "enable_break: search for .interp in %s\n", | |
1166 | + exec_bfd->filename); | |
1001 | 1167 | if (interp_sect) |
1002 | 1168 | { |
1003 | 1169 | unsigned int interp_sect_size; |
@@ -1031,6 +1197,9 @@ enable_break (void) | ||
1031 | 1197 | if (tmp_fd >= 0) |
1032 | 1198 | tmp_bfd = bfd_fdopenr (tmp_pathname, gnutarget, tmp_fd); |
1033 | 1199 | |
1200 | + if (debug_solib) | |
1201 | + fprintf_unfiltered (gdb_stdlog, | |
1202 | + "enable_break: opening %s\n", tmp_pathname); | |
1034 | 1203 | if (tmp_bfd == NULL) |
1035 | 1204 | goto bkpt_at_symbol; |
1036 | 1205 |
@@ -1112,6 +1281,9 @@ enable_break (void) | ||
1112 | 1281 | if (sym_addr != 0) |
1113 | 1282 | { |
1114 | 1283 | create_solib_event_breakpoint (load_addr + sym_addr); |
1284 | + if (debug_solib) | |
1285 | + fprintf_unfiltered (gdb_stdlog, | |
1286 | + "enable_break: solib bp set\n"); | |
1115 | 1287 | return 1; |
1116 | 1288 | } |
1117 | 1289 |
@@ -1371,6 +1543,8 @@ svr4_solib_create_inferior_hook (void) | ||
1371 | 1543 | while (stop_signal != TARGET_SIGNAL_TRAP); |
1372 | 1544 | stop_soon = NO_STOP_QUIETLY; |
1373 | 1545 | #endif /* defined(_SCO_DS) */ |
1546 | + | |
1547 | + disable_breakpoints_at_startup (1); | |
1374 | 1548 | } |
1375 | 1549 | |
1376 | 1550 | static void |
@@ -46,6 +46,8 @@ | ||
46 | 46 | |
47 | 47 | /* external data declarations */ |
48 | 48 | |
49 | +int debug_solib; | |
50 | + | |
49 | 51 | /* FIXME: gdbarch needs to control this variable */ |
50 | 52 | struct target_so_ops *current_target_so_ops; |
51 | 53 |
@@ -68,6 +70,8 @@ static char *solib_absolute_prefix = NULL; | ||
68 | 70 | and LD_LIBRARY_PATH. */ |
69 | 71 | static char *solib_search_path = NULL; |
70 | 72 | |
73 | +void add_to_target_sections (int, struct target_ops *, struct so_list *); | |
74 | + | |
71 | 75 | /* |
72 | 76 | |
73 | 77 | GLOBAL FUNCTION |
@@ -340,7 +344,6 @@ master_so_list (void) | ||
340 | 344 | return so_list_head; |
341 | 345 | } |
342 | 346 | |
343 | - | |
344 | 347 | /* A small stub to get us past the arg-passing pinhole of catch_errors. */ |
345 | 348 | |
346 | 349 | static int |
@@ -352,15 +355,40 @@ symbol_add_stub (void *arg) | ||
352 | 355 | /* Have we already loaded this shared object? */ |
353 | 356 | ALL_OBJFILES (so->objfile) |
354 | 357 | { |
355 | - if (strcmp (so->objfile->name, so->so_name) == 0) | |
358 | + /* Found an already loaded shared library. */ | |
359 | + if (strcmp (so->objfile->name, so->so_name) == 0 | |
360 | + && !so->main) | |
356 | 361 | return 1; |
362 | + /* Found an already loaded main executable. This could happen in | |
363 | + two circumstances. | |
364 | + First case: the main file has already been read in | |
365 | + as the first thing that gdb does at startup, and the file | |
366 | + hasn't been relocated properly yet. Therefor we need to read | |
367 | + it in with the proper section info. | |
368 | + Second case: it has been read in with the correct relocation, | |
369 | + and therefore we need to skip it. */ | |
370 | + if (strcmp (so->objfile->name, so->so_name) == 0 | |
371 | + && so->main | |
372 | + && so->main_relocated) | |
373 | + return 1; | |
357 | 374 | } |
358 | 375 | |
359 | 376 | sap = build_section_addr_info_from_section_table (so->sections, |
360 | 377 | so->sections_end); |
361 | 378 | |
362 | - so->objfile = symbol_file_add (so->so_name, so->from_tty, | |
363 | - sap, 0, OBJF_SHARED); | |
379 | + if (so->main) | |
380 | + { | |
381 | + if (debug_solib) | |
382 | + fprintf_unfiltered (gdb_stdlog, | |
383 | + "symbol_add_stub: adding symbols for main\n"); | |
384 | + so->objfile = symbol_file_add (so->so_name, /*so->from_tty*/ 0, | |
385 | + sap, 1, 0); | |
386 | + so->main_relocated = 1; | |
387 | + } | |
388 | + else | |
389 | + so->objfile = symbol_file_add (so->so_name, so->from_tty, | |
390 | + sap, 0, OBJF_SHARED); | |
391 | + | |
364 | 392 | free_section_addr_info (sap); |
365 | 393 | |
366 | 394 | return (1); |
@@ -455,6 +483,10 @@ update_solib_list (int from_tty, struct target_ops *target) | ||
455 | 483 | the inferior's current list. */ |
456 | 484 | while (i) |
457 | 485 | { |
486 | + if (debug_solib) | |
487 | + fprintf_unfiltered (gdb_stdlog, | |
488 | + "update_solib_list: compare gdb:%s and inferior:%s\n", | |
489 | + gdb->so_original_name, i->so_original_name); | |
458 | 490 | if (! strcmp (gdb->so_original_name, i->so_original_name)) |
459 | 491 | break; |
460 | 492 |
@@ -504,32 +536,46 @@ update_solib_list (int from_tty, struct target_ops *target) | ||
504 | 536 | /* Fill in the rest of each of the `struct so_list' nodes. */ |
505 | 537 | for (i = inferior; i; i = i->next) |
506 | 538 | { |
507 | - i->from_tty = from_tty; | |
508 | - | |
509 | - /* Fill in the rest of the `struct so_list' node. */ | |
510 | - catch_errors (solib_map_sections, i, | |
511 | - "Error while mapping shared library sections:\n", | |
512 | - RETURN_MASK_ALL); | |
513 | - | |
514 | - /* If requested, add the shared object's sections to the TARGET's | |
515 | - section table. Do this immediately after mapping the object so | |
516 | - that later nodes in the list can query this object, as is needed | |
517 | - in solib-osf.c. */ | |
518 | - if (target) | |
519 | - { | |
520 | - int count = (i->sections_end - i->sections); | |
521 | - if (count > 0) | |
522 | - { | |
523 | - int space = target_resize_to_sections (target, count); | |
524 | - memcpy (target->to_sections + space, | |
525 | - i->sections, | |
526 | - count * sizeof (i->sections[0])); | |
527 | - } | |
528 | - } | |
539 | + add_to_target_sections (from_tty, target, i); | |
529 | 540 | } |
530 | 541 | } |
531 | 542 | } |
532 | 543 | |
544 | +void | |
545 | +add_to_target_sections (int from_tty, struct target_ops *target, struct so_list *solib) | |
546 | +{ | |
547 | + /* If this is set, then the sections have been already added to the | |
548 | + target list. */ | |
549 | + if (solib->main) | |
550 | + return; | |
551 | + | |
552 | + solib->from_tty = from_tty; | |
553 | + | |
554 | + /* Fill in the rest of the `struct so_list' node. */ | |
555 | + catch_errors (solib_map_sections, solib, | |
556 | + "Error while mapping shared library sections:\n", | |
557 | + RETURN_MASK_ALL); | |
558 | + | |
559 | + /* If requested, add the shared object's sections to the TARGET's | |
560 | + section table. Do this immediately after mapping the object so | |
561 | + that later nodes in the list can query this object, as is needed | |
562 | + in solib-osf.c. */ | |
563 | + if (target) | |
564 | + { | |
565 | + int count = (solib->sections_end - solib->sections); | |
566 | + if (count > 0) | |
567 | + { | |
568 | + int space = target_resize_to_sections (target, count); | |
569 | + if (debug_solib) | |
570 | + fprintf_unfiltered (gdb_stdlog, | |
571 | + "add_to_target_sections: add %s to to_sections\n", | |
572 | + solib->so_original_name); | |
573 | + memcpy (target->to_sections + space, | |
574 | + solib->sections, | |
575 | + count * sizeof (solib->sections[0])); | |
576 | + } | |
577 | + } | |
578 | +} | |
533 | 579 | |
534 | 580 | /* GLOBAL FUNCTION |
535 | 581 |
@@ -917,4 +963,10 @@ This takes precedence over the environment variables PATH and LD_LIBRARY_PATH.", | ||
917 | 963 | add_show_from_set (c, &showlist); |
918 | 964 | set_cmd_cfunc (c, reload_shared_libraries); |
919 | 965 | set_cmd_completer (c, filename_completer); |
966 | + | |
967 | + add_show_from_set (add_set_cmd ("solib", no_class, var_zinteger, | |
968 | + (char *) &debug_solib, | |
969 | + "Set debugging of GNU/Linux shlib module.\n\ | |
970 | +Enables printf debugging output.\n", &setdebuglist), &showdebuglist); | |
971 | + | |
920 | 972 | } |
@@ -62,6 +62,8 @@ struct so_list | ||
62 | 62 | bfd *abfd; |
63 | 63 | char symbols_loaded; /* flag: symbols read in yet? */ |
64 | 64 | char from_tty; /* flag: print msgs? */ |
65 | + char main; /* flag: is this the main executable? */ | |
66 | + char main_relocated; /* flag: has it been relocated yet? */ | |
65 | 67 | struct objfile *objfile; /* objfile for loaded lib */ |
66 | 68 | struct section_table *sections; |
67 | 69 | struct section_table *sections_end; |
@@ -113,9 +115,15 @@ void free_so (struct so_list *so); | ||
113 | 115 | /* Return address of first so_list entry in master shared object list. */ |
114 | 116 | struct so_list *master_so_list (void); |
115 | 117 | |
118 | +/* Return address of first so_list entry in master shared object list. */ | |
119 | +struct so_list *master_so_list (void); | |
120 | + | |
116 | 121 | /* Find solib binary file and open it. */ |
117 | 122 | extern int solib_open (char *in_pathname, char **found_pathname); |
118 | 123 | |
124 | +/* Add the list of sections in so_list to the target to_sections. */ | |
125 | +extern void add_to_target_sections (int, struct target_ops *, struct so_list *); | |
126 | + | |
119 | 127 | /* FIXME: gdbarch needs to control this variable */ |
120 | 128 | extern struct target_so_ops *current_target_so_ops; |
121 | 129 |
@@ -135,4 +143,6 @@ extern struct target_so_ops *current_target_so_ops; | ||
135 | 143 | #define TARGET_SO_FIND_AND_OPEN_SOLIB \ |
136 | 144 | (current_target_so_ops->find_and_open_solib) |
137 | 145 | |
146 | +/* Controls the printing of debugging output. */ | |
147 | +extern int debug_solib; | |
138 | 148 | #endif |
@@ -48,6 +48,7 @@ | ||
48 | 48 | #include "readline/readline.h" |
49 | 49 | #include "gdb_assert.h" |
50 | 50 | #include "block.h" |
51 | +#include "varobj.h" | |
51 | 52 | |
52 | 53 | #include <sys/types.h> |
53 | 54 | #include <fcntl.h> |
@@ -573,7 +574,7 @@ syms_from_objfile (struct objfile *objfile, | ||
573 | 574 | |
574 | 575 | We no longer warn if the lowest section is not a text segment (as |
575 | 576 | happens for the PA64 port. */ |
576 | - if (!mainline && addrs && addrs->other[0].name) | |
577 | + if (/*!mainline &&*/ addrs && addrs->other[0].name) | |
577 | 578 | { |
578 | 579 | asection *lower_sect; |
579 | 580 | asection *sect; |
@@ -960,6 +961,10 @@ symbol_file_clear (int from_tty) | ||
960 | 961 | && !query ("Discard symbol table from `%s'? ", |
961 | 962 | symfile_objfile->name)) |
962 | 963 | error ("Not confirmed."); |
964 | +#ifdef CLEAR_SOLIB | |
965 | + CLEAR_SOLIB (); | |
966 | +#endif | |
967 | + | |
963 | 968 | free_all_objfiles (); |
964 | 969 | |
965 | 970 | /* solib descriptors may have handles to objfiles. Since their |
@@ -1957,6 +1962,8 @@ reread_symbols (void) | ||
1957 | 1962 | /* Discard cleanups as symbol reading was successful. */ |
1958 | 1963 | discard_cleanups (old_cleanups); |
1959 | 1964 | |
1965 | + init_entry_point_info (objfile); | |
1966 | + | |
1960 | 1967 | /* If the mtime has changed between the time we set new_modtime |
1961 | 1968 | and now, we *want* this to be out of date, so don't call stat |
1962 | 1969 | again now. */ |
@@ -2312,6 +2319,7 @@ clear_symtab_users (void) | ||
2312 | 2319 | clear_pc_function_cache (); |
2313 | 2320 | if (target_new_objfile_hook) |
2314 | 2321 | target_new_objfile_hook (NULL); |
2322 | + varobj_refresh(); | |
2315 | 2323 | } |
2316 | 2324 | |
2317 | 2325 | static void |
@@ -854,6 +854,62 @@ varobj_list (struct varobj ***varlist) | ||
854 | 854 | return rootcount; |
855 | 855 | } |
856 | 856 | |
857 | +void | |
858 | +varobj_refresh (void) | |
859 | +{ | |
860 | + struct varobj *var; | |
861 | + struct varobj_root *croot; | |
862 | + int mycount = rootcount; | |
863 | + char * name; | |
864 | + | |
865 | + croot = rootlist; | |
866 | + while ((croot != NULL) && (mycount > 0)) | |
867 | + { | |
868 | + var = croot->rootvar; | |
869 | + | |
870 | + /* Get rid of the memory for the old expression. This also | |
871 | + leaves var->root->exp == NULL, which is ok for the parsing | |
872 | + below. */ | |
873 | + free_current_contents ((char **) &var->root->exp); | |
874 | + | |
875 | + value_free (var->value); | |
876 | + var->type = NULL; | |
877 | + | |
878 | + name = xstrdup (var->name); | |
879 | + | |
880 | + /* Reparse the expression. Wrap the call to parse expression, | |
881 | + so we can return a sensible error. */ | |
882 | + if (!gdb_parse_exp_1 (&name, var->root->valid_block, 0, &var->root->exp)) | |
883 | + { | |
884 | + return; | |
885 | + } | |
886 | + | |
887 | + /* We definitively need to catch errors here. | |
888 | + If evaluate_expression succeeds we got the value we wanted. | |
889 | + But if it fails, we still go on with a call to evaluate_type() */ | |
890 | + if (gdb_evaluate_expression (var->root->exp, &var->value)) | |
891 | + { | |
892 | + /* no error */ | |
893 | + release_value (var->value); | |
894 | + if (VALUE_LAZY (var->value)) | |
895 | + gdb_value_fetch_lazy (var->value); | |
896 | + } | |
897 | + else | |
898 | + var->value = evaluate_type (var->root->exp); | |
899 | + | |
900 | + var->type = VALUE_TYPE (var->value); | |
901 | + | |
902 | + mycount--; | |
903 | + croot = croot->next; | |
904 | + } | |
905 | + | |
906 | + if (mycount || (croot != NULL)) | |
907 | + warning | |
908 | + ("varobj_refresh: assertion failed - wrong tally of root vars (%d:%d)", | |
909 | + rootcount, mycount); | |
910 | +} | |
911 | + | |
912 | + | |
857 | 913 | /* Update the values for a variable and its children. This is a |
858 | 914 | two-pronged attack. First, re-parse the value for the root's |
859 | 915 | expression to see if it's changed. Then go all the way |
@@ -97,4 +97,6 @@ extern int varobj_list (struct varobj ***rootlist); | ||
97 | 97 | |
98 | 98 | extern int varobj_update (struct varobj **varp, struct varobj ***changelist); |
99 | 99 | |
100 | +extern void varobj_refresh(void); | |
101 | + | |
100 | 102 | #endif /* VAROBJ_H */ |