mirror of
https://github.com/openbsd/src.git
synced 2025-01-10 06:47:55 -08:00
Enable support for debugging pie programs. Code from Elena Zannoni's
<ezannoni at redhat dot com> pie branch in gdb cvs, less extraneous parts and with some bug fixes. Debugging w/core files for pie programs isn't working yet since AUXV data isn't included in our core files at the moment. feedback and ok kettenis@
This commit is contained in:
parent
22c6a57d9b
commit
15135fad20
@ -2289,7 +2289,7 @@ objc-lang.o: objc-lang.c $(defs_h) $(symtab_h) $(gdbtypes_h) $(expression_h) \
|
||||
objfiles.o: objfiles.c $(defs_h) $(bfd_h) $(symtab_h) $(symfile_h) \
|
||||
$(objfiles_h) $(gdb_stabs_h) $(target_h) $(bcache_h) $(gdb_assert_h) \
|
||||
$(gdb_stat_h) $(gdb_obstack_h) $(gdb_string_h) $(hashtab_h) \
|
||||
$(breakpoint_h) $(block_h) $(dictionary_h)
|
||||
$(breakpoint_h) $(block_h) $(dictionary_h) $(auxv_h) $(elf_common_h)
|
||||
observer.o: observer.c $(defs_h) $(observer_h) $(command_h) $(gdbcmd_h) \
|
||||
$(observer_inc)
|
||||
obsd-tdep.o: obsd-tdep.c $(defs_h) $(frame_h) $(symtab_h) $(obsd_tdep_h)
|
||||
@ -2511,7 +2511,7 @@ solib-sunos.o: solib-sunos.c $(defs_h) $(gdb_string_h) $(symtab_h) $(bfd_h) \
|
||||
solib-svr4.o: solib-svr4.c $(defs_h) $(elf_external_h) $(elf_common_h) \
|
||||
$(elf_mips_h) $(symtab_h) $(bfd_h) $(symfile_h) $(objfiles_h) \
|
||||
$(gdbcore_h) $(target_h) $(inferior_h) $(solist_h) $(solib_svr4_h) \
|
||||
$(bfd_target_h) $(exec_h)
|
||||
$(bfd_target_h) $(exec_h) $(auxv_h) $(command_h)
|
||||
sol-thread.o: sol-thread.c $(defs_h) $(gdbthread_h) $(target_h) \
|
||||
$(inferior_h) $(gdb_stat_h) $(gdbcmd_h) $(gdbcore_h) $(regcache_h) \
|
||||
$(symfile_h) $(gdb_string_h) $(gregset_h)
|
||||
@ -2603,7 +2603,7 @@ symfile.o: symfile.c $(defs_h) $(bfdlink_h) $(symtab_h) $(gdbtypes_h) \
|
||||
$(complaints_h) $(demangle_h) $(inferior_h) $(filenames_h) \
|
||||
$(gdb_stabs_h) $(gdb_obstack_h) $(completer_h) $(bcache_h) \
|
||||
$(hashtab_h) $(readline_h) $(gdb_assert_h) $(block_h) \
|
||||
$(gdb_string_h) $(gdb_stat_h)
|
||||
$(gdb_string_h) $(gdb_stat_h) $(varobj_h)
|
||||
symfile-mem.o: symfile-mem.c $(defs_h) $(symtab_h) $(gdbcore_h) \
|
||||
$(objfiles_h) $(gdbcmd_h) $(target_h) $(value_h) $(symfile_h)
|
||||
symmisc.o: symmisc.c $(defs_h) $(symtab_h) $(gdbtypes_h) $(bfd_h) \
|
||||
|
@ -3783,6 +3783,7 @@ describe_other_breakpoints (CORE_ADDR pc, asection *section)
|
||||
b->number,
|
||||
((b->enable_state == bp_disabled ||
|
||||
b->enable_state == bp_shlib_disabled ||
|
||||
b->enable_state == bp_startup_disabled ||
|
||||
b->enable_state == bp_call_disabled)
|
||||
? " (disabled)"
|
||||
: b->enable_state == bp_permanent
|
||||
@ -4457,6 +4458,60 @@ re_enable_breakpoints_in_shlibs (void)
|
||||
|
||||
#endif
|
||||
|
||||
void
|
||||
disable_breakpoints_at_startup (int silent)
|
||||
{
|
||||
struct breakpoint *b;
|
||||
int disabled_startup_breaks = 0;
|
||||
|
||||
if (bfd_get_start_address (exec_bfd) != entry_point_address ())
|
||||
{
|
||||
ALL_BREAKPOINTS (b)
|
||||
{
|
||||
if (((b->type == bp_breakpoint) ||
|
||||
(b->type == bp_hardware_breakpoint)) &&
|
||||
b->enable_state == bp_enabled &&
|
||||
!b->loc->duplicate &&
|
||||
!b->pending)
|
||||
{
|
||||
b->enable_state = bp_startup_disabled;
|
||||
if (!silent)
|
||||
{
|
||||
if (!disabled_startup_breaks)
|
||||
{
|
||||
target_terminal_ours_for_output ();
|
||||
warning ("Temporarily disabling breakpoints:");
|
||||
}
|
||||
disabled_startup_breaks = 1;
|
||||
warning ("breakpoint #%d addr 0x%s", b->number, paddr_nz(b->loc->address));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* Try to reenable any breakpoints after startup. */
|
||||
void
|
||||
re_enable_breakpoints_at_startup (void)
|
||||
{
|
||||
struct breakpoint *b;
|
||||
|
||||
if (bfd_get_start_address (exec_bfd) != entry_point_address ())
|
||||
{
|
||||
ALL_BREAKPOINTS (b)
|
||||
if (b->enable_state == bp_startup_disabled)
|
||||
{
|
||||
char buf[1];
|
||||
|
||||
/* Do not reenable the breakpoint if the shared library
|
||||
is still not mapped in. */
|
||||
if (target_read_memory (b->loc->address, buf, 1) == 0)
|
||||
b->enable_state = bp_enabled;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
static void
|
||||
solib_load_unload_1 (char *hookname, int tempflag, char *dll_pathname,
|
||||
char *cond_string, enum bptype bp_kind)
|
||||
@ -6978,6 +7033,7 @@ delete_breakpoint (struct breakpoint *bpt)
|
||||
&& !b->loc->duplicate
|
||||
&& b->enable_state != bp_disabled
|
||||
&& b->enable_state != bp_shlib_disabled
|
||||
&& b->enable_state != bp_startup_disabled
|
||||
&& !b->pending
|
||||
&& b->enable_state != bp_call_disabled)
|
||||
{
|
||||
@ -7191,7 +7247,8 @@ breakpoint_re_set_one (void *bint)
|
||||
break;
|
||||
|
||||
save_enable = b->enable_state;
|
||||
if (b->enable_state != bp_shlib_disabled)
|
||||
if (b->enable_state != bp_shlib_disabled
|
||||
&& b->enable_state != bp_startup_disabled)
|
||||
b->enable_state = bp_disabled;
|
||||
else
|
||||
/* If resetting a shlib-disabled breakpoint, we don't want to
|
||||
|
@ -159,6 +159,7 @@ enum enable_state
|
||||
automatically enabled and reset when the call
|
||||
"lands" (either completes, or stops at another
|
||||
eventpoint). */
|
||||
bp_startup_disabled,
|
||||
bp_permanent /* There is a breakpoint instruction hard-wired into
|
||||
the target's code. Don't try to write another
|
||||
breakpoint instruction on top of it, or restore
|
||||
@ -765,8 +766,12 @@ extern void remove_thread_event_breakpoints (void);
|
||||
|
||||
extern void disable_breakpoints_in_shlibs (int silent);
|
||||
|
||||
extern void disable_breakpoints_at_startup (int silent);
|
||||
|
||||
extern void re_enable_breakpoints_in_shlibs (void);
|
||||
|
||||
void re_enable_breakpoints_at_startup (void);
|
||||
|
||||
extern void create_solib_load_event_breakpoint (char *, int, char *, char *);
|
||||
|
||||
extern void create_solib_unload_event_breakpoint (char *, int,
|
||||
|
@ -2120,6 +2120,11 @@ process_event_stop_test:
|
||||
code segments in shared libraries might be mapped in now. */
|
||||
re_enable_breakpoints_in_shlibs ();
|
||||
|
||||
/* For PIE executables, we dont really know where the
|
||||
breakpoints are going to be until we start up the
|
||||
inferior. */
|
||||
re_enable_breakpoints_at_startup ();
|
||||
|
||||
/* If requested, stop when the dynamic linker notifies
|
||||
gdb of events. This allows the user to get control
|
||||
and place breakpoints in initializer routines for
|
||||
|
@ -45,6 +45,9 @@
|
||||
#include "breakpoint.h"
|
||||
#include "block.h"
|
||||
#include "dictionary.h"
|
||||
#include "auxv.h"
|
||||
|
||||
#include "elf/common.h"
|
||||
|
||||
/* Prototypes for local functions */
|
||||
|
||||
@ -257,7 +260,12 @@ init_entry_point_info (struct objfile *objfile)
|
||||
CORE_ADDR
|
||||
entry_point_address (void)
|
||||
{
|
||||
return symfile_objfile ? symfile_objfile->ei.entry_point : 0;
|
||||
CORE_ADDR entry_addr = symfile_objfile ? symfile_objfile->ei.entry_point : 0;
|
||||
|
||||
/* Find the address of the entry point of the program from the
|
||||
auxv vector. */
|
||||
target_auxv_search (¤t_target, AT_ENTRY, &entry_addr);
|
||||
return entry_addr;
|
||||
}
|
||||
|
||||
/* Create the terminating entry of OBJFILE's minimal symbol table.
|
||||
|
@ -27,6 +27,7 @@
|
||||
#include "elf/common.h"
|
||||
#include "elf/mips.h"
|
||||
|
||||
#include "auxv.h"
|
||||
#include "symtab.h"
|
||||
#include "bfd.h"
|
||||
#include "symfile.h"
|
||||
@ -34,6 +35,7 @@
|
||||
#include "gdbcore.h"
|
||||
#include "target.h"
|
||||
#include "inferior.h"
|
||||
#include "command.h"
|
||||
|
||||
#include "solist.h"
|
||||
#include "solib-svr4.h"
|
||||
@ -179,7 +181,9 @@ static CORE_ADDR breakpoint_addr; /* Address where end bkpt is set */
|
||||
|
||||
/* Local function prototypes */
|
||||
|
||||
#if 0
|
||||
static int match_main (char *);
|
||||
#endif
|
||||
|
||||
static CORE_ADDR bfd_lookup_symbol (bfd *, char *, flagword);
|
||||
|
||||
@ -301,21 +305,32 @@ elf_locate_base (void)
|
||||
{
|
||||
struct bfd_section *dyninfo_sect;
|
||||
int dyninfo_sect_size;
|
||||
CORE_ADDR dyninfo_addr;
|
||||
CORE_ADDR dyninfo_addr, relocated_dyninfo_addr, entry_addr;
|
||||
char *buf;
|
||||
char *bufend;
|
||||
int arch_size;
|
||||
|
||||
/* Find the address of the entry point of the program from the
|
||||
auxv vector. */
|
||||
if (target_auxv_search (¤t_target, AT_ENTRY, &entry_addr) != 1)
|
||||
{
|
||||
/* No auxv info, maybe an older kernel. Fake our way through. */
|
||||
entry_addr = bfd_get_start_address (exec_bfd);
|
||||
}
|
||||
|
||||
/* Find the start address of the .dynamic section. */
|
||||
dyninfo_sect = bfd_get_section_by_name (exec_bfd, ".dynamic");
|
||||
if (dyninfo_sect == NULL)
|
||||
return 0;
|
||||
dyninfo_addr = bfd_section_vma (exec_bfd, dyninfo_sect);
|
||||
|
||||
relocated_dyninfo_addr = dyninfo_addr
|
||||
+ entry_addr - bfd_get_start_address(exec_bfd);
|
||||
|
||||
/* Read in .dynamic section, silently ignore errors. */
|
||||
dyninfo_sect_size = bfd_section_size (exec_bfd, dyninfo_sect);
|
||||
buf = alloca (dyninfo_sect_size);
|
||||
if (target_read_memory (dyninfo_addr, buf, dyninfo_sect_size))
|
||||
if (target_read_memory (relocated_dyninfo_addr, buf, dyninfo_sect_size))
|
||||
return 0;
|
||||
|
||||
/* Find the DT_DEBUG entry in the the .dynamic section.
|
||||
@ -636,7 +651,47 @@ svr4_current_sos (void)
|
||||
does have a name, so we can no longer use a missing name to
|
||||
decide when to ignore it. */
|
||||
if (IGNORE_FIRST_LINK_MAP_ENTRY (new))
|
||||
free_so (new);
|
||||
{
|
||||
/* It is the first link map entry, i.e. it is the main executable. */
|
||||
|
||||
if (bfd_get_start_address (exec_bfd) == entry_point_address ())
|
||||
{
|
||||
/* Non-pie case, main executable has not been relocated. */
|
||||
free_so (new);
|
||||
}
|
||||
else
|
||||
{
|
||||
/* Pie case, main executable has been relocated. */
|
||||
struct so_list *gdb_solib;
|
||||
|
||||
strncpy (new->so_name, exec_bfd->filename,
|
||||
SO_NAME_MAX_PATH_SIZE - 1);
|
||||
new->so_name[SO_NAME_MAX_PATH_SIZE - 1] = '\0';
|
||||
strcpy (new->so_original_name, new->so_name);
|
||||
new->main_relocated = 0;
|
||||
|
||||
for (gdb_solib = master_so_list ();
|
||||
gdb_solib;
|
||||
gdb_solib = gdb_solib->next)
|
||||
{
|
||||
if (strcmp (gdb_solib->so_name, new->so_name) == 0)
|
||||
if (gdb_solib->main_relocated)
|
||||
break;
|
||||
}
|
||||
|
||||
if ((gdb_solib && !gdb_solib->main_relocated) || (!gdb_solib))
|
||||
{
|
||||
add_to_target_sections (0 /*from_tty*/, ¤t_target, new);
|
||||
new->main = 1;
|
||||
}
|
||||
|
||||
/* We need this in the list of shared libs we return because
|
||||
solib_add_stub will loop through it and add the symbol file. */
|
||||
new->next = 0;
|
||||
*link_ptr = new;
|
||||
link_ptr = &new->next;
|
||||
}
|
||||
} /* End of IGNORE_FIRST_LINK_MAP_ENTRY */
|
||||
else
|
||||
{
|
||||
int errcode;
|
||||
@ -658,17 +713,10 @@ svr4_current_sos (void)
|
||||
strcpy (new->so_original_name, new->so_name);
|
||||
}
|
||||
|
||||
/* If this entry has no name, or its name matches the name
|
||||
for the main executable, don't include it in the list. */
|
||||
if (! new->so_name[0]
|
||||
|| match_main (new->so_name))
|
||||
free_so (new);
|
||||
else
|
||||
{
|
||||
new->next = 0;
|
||||
*link_ptr = new;
|
||||
link_ptr = &new->next;
|
||||
}
|
||||
new->next = 0;
|
||||
*link_ptr = new;
|
||||
link_ptr = &new->next;
|
||||
|
||||
}
|
||||
|
||||
discard_cleanups (old_chain);
|
||||
@ -754,6 +802,7 @@ svr4_fetch_objfile_link_map (struct objfile *objfile)
|
||||
the main executable file is by looking at its name. Return
|
||||
non-zero iff SONAME matches one of the known main executable names. */
|
||||
|
||||
#if 0
|
||||
static int
|
||||
match_main (char *soname)
|
||||
{
|
||||
@ -767,6 +816,7 @@ match_main (char *soname)
|
||||
|
||||
return (0);
|
||||
}
|
||||
#endif
|
||||
|
||||
/* Return 1 if PC lies in the dynamic symbol resolution code of the
|
||||
SVR4 run time loader. */
|
||||
@ -1239,6 +1289,8 @@ svr4_solib_create_inferior_hook (void)
|
||||
while (stop_signal != TARGET_SIGNAL_TRAP);
|
||||
stop_soon = NO_STOP_QUIETLY;
|
||||
#endif /* defined(_SCO_DS) */
|
||||
|
||||
disable_breakpoints_at_startup (1);
|
||||
}
|
||||
|
||||
static void
|
||||
|
@ -69,6 +69,8 @@ static char *solib_absolute_prefix = NULL;
|
||||
and LD_LIBRARY_PATH. */
|
||||
static char *solib_search_path = NULL;
|
||||
|
||||
void add_to_target_sections (int, struct target_ops *, struct so_list *);
|
||||
|
||||
/*
|
||||
|
||||
GLOBAL FUNCTION
|
||||
@ -355,15 +357,37 @@ symbol_add_stub (void *arg)
|
||||
/* Have we already loaded this shared object? */
|
||||
ALL_OBJFILES (so->objfile)
|
||||
{
|
||||
if (strcmp (so->objfile->name, so->so_name) == 0)
|
||||
/* Found an already loaded shared library. */
|
||||
if (strcmp (so->objfile->name, so->so_name) == 0
|
||||
&& !so->main)
|
||||
return 1;
|
||||
/* Found an already loaded main executable. This could happen in
|
||||
two circumstances.
|
||||
First case: the main file has already been read in
|
||||
as the first thing that gdb does at startup, and the file
|
||||
hasn't been relocated properly yet. Therefor we need to read
|
||||
it in with the proper section info.
|
||||
Second case: it has been read in with the correct relocation,
|
||||
and therefore we need to skip it. */
|
||||
if (strcmp (so->objfile->name, so->so_name) == 0
|
||||
&& so->main
|
||||
&& so->main_relocated)
|
||||
return 1;
|
||||
}
|
||||
|
||||
sap = build_section_addr_info_from_section_table (so->sections,
|
||||
so->sections_end);
|
||||
|
||||
so->objfile = symbol_file_add (so->so_name, so->from_tty,
|
||||
sap, 0, OBJF_SHARED);
|
||||
if (so->main)
|
||||
{
|
||||
so->objfile = symbol_file_add (so->so_name, /*so->from_tty*/ 0,
|
||||
sap, 1, 0);
|
||||
so->main_relocated = 1;
|
||||
}
|
||||
else
|
||||
so->objfile = symbol_file_add (so->so_name, so->from_tty,
|
||||
sap, 0, OBJF_SHARED);
|
||||
|
||||
free_section_addr_info (sap);
|
||||
|
||||
return (1);
|
||||
@ -538,36 +562,46 @@ update_solib_list (int from_tty, struct target_ops *target)
|
||||
/* Fill in the rest of each of the `struct so_list' nodes. */
|
||||
for (i = inferior; i; i = i->next)
|
||||
{
|
||||
i->from_tty = from_tty;
|
||||
|
||||
/* Fill in the rest of the `struct so_list' node. */
|
||||
catch_errors (solib_map_sections, i,
|
||||
"Error while mapping shared library sections:\n",
|
||||
RETURN_MASK_ALL);
|
||||
|
||||
/* If requested, add the shared object's sections to the TARGET's
|
||||
section table. Do this immediately after mapping the object so
|
||||
that later nodes in the list can query this object, as is needed
|
||||
in solib-osf.c. */
|
||||
if (target)
|
||||
{
|
||||
int count = (i->sections_end - i->sections);
|
||||
if (count > 0)
|
||||
{
|
||||
int space = target_resize_to_sections (target, count);
|
||||
memcpy (target->to_sections + space,
|
||||
i->sections,
|
||||
count * sizeof (i->sections[0]));
|
||||
}
|
||||
}
|
||||
|
||||
/* Notify any observer that the shared object has been
|
||||
loaded now that we've added it to GDB's tables. */
|
||||
observer_notify_solib_loaded (i);
|
||||
add_to_target_sections (from_tty, target, i);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
add_to_target_sections (int from_tty, struct target_ops *target, struct so_list *solib)
|
||||
{
|
||||
/* If this is set, then the sections have been already added to the
|
||||
target list. */
|
||||
if (solib->main)
|
||||
return;
|
||||
|
||||
solib->from_tty = from_tty;
|
||||
|
||||
/* Fill in the rest of the `struct so_list' node. */
|
||||
catch_errors (solib_map_sections, solib,
|
||||
"Error while mapping shared library sections:\n",
|
||||
RETURN_MASK_ALL);
|
||||
|
||||
/* If requested, add the shared object's sections to the TARGET's
|
||||
section table. Do this immediately after mapping the object so
|
||||
that later nodes in the list can query this object, as is needed
|
||||
in solib-osf.c. */
|
||||
if (target)
|
||||
{
|
||||
int count = (solib->sections_end - solib->sections);
|
||||
if (count > 0)
|
||||
{
|
||||
int space = target_resize_to_sections (target, count);
|
||||
memcpy (target->to_sections + space,
|
||||
solib->sections,
|
||||
count * sizeof (solib->sections[0]));
|
||||
}
|
||||
}
|
||||
/* Notify any observer that the shared object has been
|
||||
loaded now that we've added it to GDB's tables. */
|
||||
observer_notify_solib_loaded (solib);
|
||||
}
|
||||
|
||||
|
||||
/* GLOBAL FUNCTION
|
||||
|
||||
|
@ -62,6 +62,8 @@ struct so_list
|
||||
bfd *abfd;
|
||||
char symbols_loaded; /* flag: symbols read in yet? */
|
||||
char from_tty; /* flag: print msgs? */
|
||||
char main; /* flag: is this the main executable? */
|
||||
char main_relocated; /* flag: has it been relocated yet? */
|
||||
struct objfile *objfile; /* objfile for loaded lib */
|
||||
struct section_table *sections;
|
||||
struct section_table *sections_end;
|
||||
@ -113,9 +115,15 @@ void free_so (struct so_list *so);
|
||||
/* Return address of first so_list entry in master shared object list. */
|
||||
struct so_list *master_so_list (void);
|
||||
|
||||
/* Return address of first so_list entry in master shared object list. */
|
||||
struct so_list *master_so_list (void);
|
||||
|
||||
/* Find solib binary file and open it. */
|
||||
extern int solib_open (char *in_pathname, char **found_pathname);
|
||||
|
||||
/* Add the list of sections in so_list to the target to_sections. */
|
||||
extern void add_to_target_sections (int, struct target_ops *, struct so_list *);
|
||||
|
||||
/* FIXME: gdbarch needs to control this variable */
|
||||
extern struct target_so_ops *current_target_so_ops;
|
||||
|
||||
|
@ -100,7 +100,7 @@ symbol_file_add_from_memory (struct bfd *templ, CORE_ADDR addr, int from_tty)
|
||||
}
|
||||
|
||||
objf = symbol_file_add_from_bfd (nbfd, from_tty,
|
||||
sai, 0, OBJF_SHARED);
|
||||
sai, 2, OBJF_SHARED);
|
||||
|
||||
/* This might change our ideas about frames already looked at. */
|
||||
reinit_frame_cache ();
|
||||
|
@ -48,6 +48,7 @@
|
||||
#include "readline/readline.h"
|
||||
#include "gdb_assert.h"
|
||||
#include "block.h"
|
||||
#include "varobj.h"
|
||||
|
||||
#include <sys/types.h>
|
||||
#include <fcntl.h>
|
||||
@ -586,7 +587,7 @@ syms_from_objfile (struct objfile *objfile,
|
||||
|
||||
We no longer warn if the lowest section is not a text segment (as
|
||||
happens for the PA64 port. */
|
||||
if (!mainline && addrs && addrs->other[0].name)
|
||||
if (addrs && addrs->other[0].name)
|
||||
{
|
||||
asection *lower_sect;
|
||||
asection *sect;
|
||||
@ -987,6 +988,10 @@ symbol_file_clear (int from_tty)
|
||||
&& !query ("Discard symbol table from `%s'? ",
|
||||
symfile_objfile->name))
|
||||
error ("Not confirmed.");
|
||||
#ifdef CLEAR_SOLIB
|
||||
CLEAR_SOLIB ();
|
||||
#endif
|
||||
|
||||
free_all_objfiles ();
|
||||
|
||||
/* solib descriptors may have handles to objfiles. Since their
|
||||
@ -1979,6 +1984,8 @@ reread_symbols (void)
|
||||
/* Discard cleanups as symbol reading was successful. */
|
||||
discard_cleanups (old_cleanups);
|
||||
|
||||
init_entry_point_info (objfile);
|
||||
|
||||
/* If the mtime has changed between the time we set new_modtime
|
||||
and now, we *want* this to be out of date, so don't call stat
|
||||
again now. */
|
||||
@ -2338,6 +2345,7 @@ clear_symtab_users (void)
|
||||
clear_pc_function_cache ();
|
||||
if (deprecated_target_new_objfile_hook)
|
||||
deprecated_target_new_objfile_hook (NULL);
|
||||
varobj_refresh ();
|
||||
}
|
||||
|
||||
static void
|
||||
|
@ -854,6 +854,62 @@ varobj_list (struct varobj ***varlist)
|
||||
return rootcount;
|
||||
}
|
||||
|
||||
void
|
||||
varobj_refresh (void)
|
||||
{
|
||||
struct varobj *var;
|
||||
struct varobj_root *croot;
|
||||
int mycount = rootcount;
|
||||
char * name;
|
||||
|
||||
croot = rootlist;
|
||||
while ((croot != NULL) && (mycount > 0))
|
||||
{
|
||||
var = croot->rootvar;
|
||||
|
||||
/* Get rid of the memory for the old expression. This also
|
||||
leaves var->root->exp == NULL, which is ok for the parsing
|
||||
below. */
|
||||
free_current_contents ((char **) &var->root->exp);
|
||||
|
||||
value_free (var->value);
|
||||
var->type = NULL;
|
||||
|
||||
name = xstrdup (var->name);
|
||||
|
||||
/* Reparse the expression. Wrap the call to parse expression,
|
||||
so we can return a sensible error. */
|
||||
if (!gdb_parse_exp_1 (&name, var->root->valid_block, 0, &var->root->exp))
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
/* We definitively need to catch errors here.
|
||||
If evaluate_expression succeeds we got the value we wanted.
|
||||
But if it fails, we still go on with a call to evaluate_type() */
|
||||
if (gdb_evaluate_expression (var->root->exp, &var->value))
|
||||
{
|
||||
/* no error */
|
||||
release_value (var->value);
|
||||
if (VALUE_LAZY (var->value))
|
||||
gdb_value_fetch_lazy (var->value);
|
||||
}
|
||||
else
|
||||
var->value = evaluate_type (var->root->exp);
|
||||
|
||||
var->type = VALUE_TYPE (var->value);
|
||||
|
||||
mycount--;
|
||||
croot = croot->next;
|
||||
}
|
||||
|
||||
if (mycount || (croot != NULL))
|
||||
warning
|
||||
("varobj_refresh: assertion failed - wrong tally of root vars (%d:%d)",
|
||||
rootcount, mycount);
|
||||
}
|
||||
|
||||
|
||||
/* Update the values for a variable and its children. This is a
|
||||
two-pronged attack. First, re-parse the value for the root's
|
||||
expression to see if it's changed. Then go all the way
|
||||
|
@ -97,4 +97,6 @@ extern int varobj_list (struct varobj ***rootlist);
|
||||
|
||||
extern int varobj_update (struct varobj **varp, struct varobj ***changelist);
|
||||
|
||||
extern void varobj_refresh(void);
|
||||
|
||||
#endif /* VAROBJ_H */
|
||||
|
Loading…
Reference in New Issue
Block a user