summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--gdb/ChangeLog58
-rw-r--r--gdb/nto-tdep.c35
-rw-r--r--gdb/solib-aix.c62
-rw-r--r--gdb/solib-darwin.c13
-rw-r--r--gdb/solib-dsbt.c22
-rw-r--r--gdb/solib-frv.c49
-rw-r--r--gdb/solib-svr4.c111
-rw-r--r--gdb/solib-svr4.h23
-rw-r--r--gdb/solib-target.c85
-rw-r--r--gdb/solist.h10
-rw-r--r--gdb/windows-nat.c45
11 files changed, 291 insertions, 222 deletions
diff --git a/gdb/ChangeLog b/gdb/ChangeLog
index 8f7f552cb3..0b100ac37a 100644
--- a/gdb/ChangeLog
+++ b/gdb/ChangeLog
@@ -1,5 +1,63 @@
2017-04-28 Simon Marchi <simon.marchi@ericsson.com>
+ * solist.h (struct lm_info): Remove.
+ (struct lm_info_base): New class.
+ (struct so_list) <lm_info>: Change type to lm_info_base *.
+ * nto-tdep.c (struct lm_info): Remove.
+ (lm_addr): Adjust.
+ * solib-aix.c (struct lm_info): Rename to ...
+ (struct lm_info_aix): ... this. Extend lm_info_base.
+ (lm_info_p): Rename to ...
+ (lm_info_aix_p): ... this, and adjust.
+ (solib_aix_new_lm_info, solib_aix_xfree_lm_info,
+ solib_aix_parse_libraries, library_list_start_library,
+ solib_aix_free_library_list, solib_aix_parse_libraries,
+ solib_aix_get_library_list,
+ solib_aix_relocate_section_addresses, solib_aix_free_so,
+ solib_aix_get_section_offsets,
+ solib_aix_solib_create_inferior_hook, solib_aix_current_sos):
+ Adjust.
+ (struct solib_aix_inferior_data) <library_list>: Adjust.
+ * solib-darwin.c (struct lm_info): Rename to ...
+ (struct lm_info_darwin): ... this. Extend lm_info_base.
+ (darwin_current_sos, darwin_relocate_section_addresses): Adjust.
+ * solib-dsbt.c (struct lm_info): Rename to ...
+ (struct lm_info_dsbt): ... this. Extend lm_info_base.
+ (struct dsbt_info) <main_executable_lm_info): Adjust.
+ (dsbt_current_sos, dsbt_relocate_main_executable, dsbt_free_so,
+ dsbt_relocate_section_addresses): Adjust.
+ * solib-frv.c (struct lm_info): Rename to ...
+ (struct lm_info_frv): ... this. Extend lm_info_base.
+ (main_executable_lm_info): Adjust.
+ (frv_current_sos, frv_relocate_main_executable, frv_free_so,
+ frv_relocate_section_addresses, frv_fdpic_find_global_pointer,
+ find_canonical_descriptor_in_load_object,
+ frv_fdpic_find_canonical_descriptor): Adjust.
+ * solib-svr4.c (struct lm_info): Move to solib-svr4.h, renamed
+ to lm_info_svr4.
+ (lm_info_read, lm_addr_check, svr4_keep_data_in_core,
+ svr4_clear_so, svr4_copy_library_list,
+ library_list_start_library, svr4_default_sos, svr4_read_so_list,
+ svr4_current_sos, svr4_fetch_objfile_link_map,
+ solist_update_incremental): Adjust.
+ * solib-svr4.h (struct lm_info_svr4): Move here from
+ solib-svr4.c.
+ * solib-target.c (struct lm_info): Rename to ...
+ (struct lm_info_target): ... this. Extend lm_info_base.
+ (lm_info_p): Rename to ...
+ (lm_info_target_p): ... this.
+ (solib_target_parse_libraries, library_list_start_segment,
+ library_list_start_section, library_list_start_library,
+ library_list_end_library, solib_target_free_library_list,
+ solib_target_current_sos, solib_target_free_so,
+ solib_target_relocate_section_addresses): Adjust.
+ * windows-nat.c (struct lm_info): Rename to ...
+ (struct lm_info_windows): ... this. Extend lm_info_base.
+ (windows_make_so, handle_load_dll, handle_unload_dll,
+ windows_xfer_shared_libraries): Adjust.
+
+2017-04-28 Simon Marchi <simon.marchi@ericsson.com>
+
* solib-darwin.c (struct darwin_so_list): Remove.
(darwin_current_sos): Allocate an so_list object instead of a
darwin_so_list, separately allocate an lm_info object.
diff --git a/gdb/nto-tdep.c b/gdb/nto-tdep.c
index 8f8d1d5384..f9959ca9e0 100644
--- a/gdb/nto-tdep.c
+++ b/gdb/nto-tdep.c
@@ -239,43 +239,12 @@ nto_parse_redirection (char *pargv[], const char **pin, const char **pout,
return argv;
}
-/* The struct lm_info, lm_addr, and nto_truncate_ptr are copied from
- solib-svr4.c to support nto_relocate_section_addresses
- which is different from the svr4 version. */
-
-/* Link map info to include in an allocated so_list entry */
-
-struct lm_info
- {
- /* Pointer to copy of link map from inferior. The type is char *
- rather than void *, so that we may use byte offsets to find the
- various fields without the need for a cast. */
- gdb_byte *lm;
-
- /* Amount by which addresses in the binary should be relocated to
- match the inferior. This could most often be taken directly
- from lm, but when prelinking is involved and the prelink base
- address changes, we may need a different offset, we want to
- warn about the difference and compute it only once. */
- CORE_ADDR l_addr;
-
- /* The target location of lm. */
- CORE_ADDR lm_addr;
- };
-
-
static CORE_ADDR
lm_addr (struct so_list *so)
{
- if (so->lm_info->l_addr == (CORE_ADDR)-1)
- {
- struct link_map_offsets *lmo = nto_fetch_link_map_offsets ();
- struct type *ptr_type = builtin_type (target_gdbarch ())->builtin_data_ptr;
+ lm_info_svr4 *li = (lm_info_svr4 *) so->lm_info;
- so->lm_info->l_addr =
- extract_typed_address (so->lm_info->lm + lmo->l_addr_offset, ptr_type);
- }
- return so->lm_info->l_addr;
+ return li->l_addr;
}
static CORE_ADDR
diff --git a/gdb/solib-aix.c b/gdb/solib-aix.c
index 66add03054..54b8c38032 100644
--- a/gdb/solib-aix.c
+++ b/gdb/solib-aix.c
@@ -33,7 +33,7 @@ static int solib_aix_debug;
/* Our private data in struct so_list. */
-struct lm_info
+struct lm_info_aix : public lm_info_base
{
/* The name of the file mapped by the loader. Apart from the entry
for the main executable, this is usually a shared library (which,
@@ -58,17 +58,17 @@ struct lm_info
ULONGEST data_size;
};
-typedef struct lm_info *lm_info_p;
-DEF_VEC_P(lm_info_p);
+typedef lm_info_aix *lm_info_aix_p;
+DEF_VEC_P(lm_info_aix_p);
/* Return a deep copy of the given struct lm_info object. */
-static struct lm_info *
-solib_aix_new_lm_info (struct lm_info *info)
+static lm_info_aix *
+solib_aix_new_lm_info (lm_info_aix *info)
{
- struct lm_info *result = XNEW (struct lm_info);
+ lm_info_aix *result = XCNEW (lm_info_aix);
- memcpy (result, info, sizeof (struct lm_info));
+ memcpy (result, info, sizeof (lm_info_aix));
result->filename = xstrdup (info->filename);
if (info->member_name != NULL)
result->member_name = xstrdup (info->member_name);
@@ -79,7 +79,7 @@ solib_aix_new_lm_info (struct lm_info *info)
/* Free the memory allocated for the given lm_info. */
static void
-solib_aix_xfree_lm_info (struct lm_info *info)
+solib_aix_xfree_lm_info (lm_info_aix *info)
{
xfree (info->filename);
xfree (info->member_name);
@@ -98,7 +98,7 @@ struct solib_aix_inferior_data
the same principles applied to shared libraries also apply
to the main executable. So it's simpler to keep it as part
of this list. */
- VEC (lm_info_p) *library_list;
+ VEC (lm_info_aix_p) *library_list;
};
/* Key to our per-inferior data. */
@@ -127,7 +127,7 @@ get_solib_aix_inferior_data (struct inferior *inf)
/* Dummy implementation if XML support is not compiled in. */
-static VEC (lm_info_p) *
+static VEC (lm_info_aix_p) *
solib_aix_parse_libraries (const char *library)
{
static int have_warned;
@@ -161,8 +161,8 @@ library_list_start_library (struct gdb_xml_parser *parser,
void *user_data,
VEC (gdb_xml_value_s) *attributes)
{
- VEC (lm_info_p) **list = (VEC (lm_info_p) **) user_data;
- struct lm_info *item = XCNEW (struct lm_info);
+ VEC (lm_info_aix_p) **list = (VEC (lm_info_aix_p) **) user_data;
+ lm_info_aix *item = XCNEW (lm_info_aix);
struct gdb_xml_value *attr;
attr = xml_find_attribute (attributes, "name");
@@ -184,7 +184,7 @@ library_list_start_library (struct gdb_xml_parser *parser,
attr = xml_find_attribute (attributes, "data_size");
item->data_size = * (ULONGEST *) attr->value;
- VEC_safe_push (lm_info_p, *list, item);
+ VEC_safe_push (lm_info_aix_p, *list, item);
}
/* Handle the start of a <library-list-aix> element. */
@@ -207,16 +207,16 @@ library_list_start_list (struct gdb_xml_parser *parser,
static void
solib_aix_free_library_list (void *p)
{
- VEC (lm_info_p) **result = (VEC (lm_info_p) **) p;
- struct lm_info *info;
+ VEC (lm_info_aix_p) **result = (VEC (lm_info_aix_p) **) p;
+ lm_info_aix *info;
int ix;
if (solib_aix_debug)
fprintf_unfiltered (gdb_stdlog, "DEBUG: solib_aix_free_library_list\n");
- for (ix = 0; VEC_iterate (lm_info_p, *result, ix, info); ix++)
+ for (ix = 0; VEC_iterate (lm_info_aix_p, *result, ix, info); ix++)
solib_aix_xfree_lm_info (info);
- VEC_free (lm_info_p, *result);
+ VEC_free (lm_info_aix_p, *result);
*result = NULL;
}
@@ -256,14 +256,14 @@ static const struct gdb_xml_element library_list_elements[] =
};
/* Parse LIBRARY, a string containing the loader info in XML format,
- and return an lm_info_p vector.
+ and return an lm_info_aix_p vector.
Return NULL if the parsing failed. */
-static VEC (lm_info_p) *
+static VEC (lm_info_aix_p) *
solib_aix_parse_libraries (const char *library)
{
- VEC (lm_info_p) *result = NULL;
+ VEC (lm_info_aix_p) *result = NULL;
struct cleanup *back_to = make_cleanup (solib_aix_free_library_list,
&result);
@@ -291,7 +291,7 @@ solib_aix_parse_libraries (const char *library)
is not NULL, then print a warning including WARNING_MSG and
a description of the error. */
-static VEC (lm_info_p) *
+static VEC (lm_info_aix_p) *
solib_aix_get_library_list (struct inferior *inf, const char *warning_msg)
{
struct solib_aix_inferior_data *data;
@@ -394,7 +394,7 @@ solib_aix_relocate_section_addresses (struct so_list *so,
struct bfd_section *bfd_sect = sec->the_bfd_section;
bfd *abfd = bfd_sect->owner;
const char *section_name = bfd_section_name (abfd, bfd_sect);
- struct lm_info *info = so->lm_info;
+ lm_info_aix *info = (lm_info_aix *) so->lm_info;
if (strcmp (section_name, ".text") == 0)
{
@@ -446,7 +446,7 @@ solib_aix_free_so (struct so_list *so)
if (solib_aix_debug)
fprintf_unfiltered (gdb_stdlog, "DEBUG: solib_aix_free_so (%s)\n",
so->so_name);
- solib_aix_xfree_lm_info (so->lm_info);
+ solib_aix_xfree_lm_info ((lm_info_aix *) so->lm_info);
}
/* Implement the "clear_solib" target_so_ops method. */
@@ -465,7 +465,7 @@ solib_aix_clear_solib (void)
static struct section_offsets *
solib_aix_get_section_offsets (struct objfile *objfile,
- struct lm_info *info)
+ lm_info_aix *info)
{
struct section_offsets *offsets;
bfd *abfd = objfile->obfd;
@@ -519,8 +519,8 @@ static void
solib_aix_solib_create_inferior_hook (int from_tty)
{
const char *warning_msg = "unable to relocate main executable";
- VEC (lm_info_p) *library_list;
- struct lm_info *exec_info;
+ VEC (lm_info_aix_p) *library_list;
+ lm_info_aix *exec_info;
/* We need to relocate the main executable... */
@@ -529,13 +529,13 @@ solib_aix_solib_create_inferior_hook (int from_tty)
if (library_list == NULL)
return; /* Warning already printed. */
- if (VEC_length (lm_info_p, library_list) < 1)
+ if (VEC_length (lm_info_aix_p, library_list) < 1)
{
warning (_("unable to relocate main executable (no info from loader)"));
return;
}
- exec_info = VEC_index (lm_info_p, library_list, 0);
+ exec_info = VEC_index (lm_info_aix_p, library_list, 0);
if (symfile_objfile != NULL)
{
@@ -554,8 +554,8 @@ static struct so_list *
solib_aix_current_sos (void)
{
struct so_list *start = NULL, *last = NULL;
- VEC (lm_info_p) *library_list;
- struct lm_info *info;
+ VEC (lm_info_aix_p) *library_list;
+ lm_info_aix *info;
int ix;
library_list = solib_aix_get_library_list (current_inferior (), NULL);
@@ -565,7 +565,7 @@ solib_aix_current_sos (void)
/* Build a struct so_list for each entry on the list.
We skip the first entry, since this is the entry corresponding
to the main executable, not a shared library. */
- for (ix = 1; VEC_iterate (lm_info_p, library_list, ix, info); ix++)
+ for (ix = 1; VEC_iterate (lm_info_aix_p, library_list, ix, info); ix++)
{
struct so_list *new_solib = XCNEW (struct so_list);
char *so_name;
diff --git a/gdb/solib-darwin.c b/gdb/solib-darwin.c
index c507e13caf..03211cfb92 100644
--- a/gdb/solib-darwin.c
+++ b/gdb/solib-darwin.c
@@ -153,7 +153,7 @@ darwin_load_image_infos (struct darwin_info *info)
/* Link map info to include in an allocated so_list entry. */
-struct lm_info
+struct lm_info_darwin : public lm_info_base
{
/* The target location of lm. */
CORE_ADDR lm_addr;
@@ -296,13 +296,14 @@ darwin_current_sos (void)
newobj = XCNEW (struct so_list);
old_chain = make_cleanup (xfree, newobj);
- newobj->lm_info = XCNEW (struct lm_info);
+ lm_info_darwin *li = XCNEW (lm_info_darwin);
+ newobj->lm_info = li;
strncpy (newobj->so_name, file_path, SO_NAME_MAX_PATH_SIZE - 1);
newobj->so_name[SO_NAME_MAX_PATH_SIZE - 1] = '\0';
strcpy (newobj->so_original_name, newobj->so_name);
xfree (file_path);
- newobj->lm_info->lm_addr = load_addr;
+ li->lm_addr = load_addr;
if (head == NULL)
head = newobj;
@@ -587,8 +588,10 @@ static void
darwin_relocate_section_addresses (struct so_list *so,
struct target_section *sec)
{
- sec->addr += so->lm_info->lm_addr;
- sec->endaddr += so->lm_info->lm_addr;
+ lm_info_darwin *li = (lm_info_darwin *) so->lm_info;
+
+ sec->addr += li->lm_addr;
+ sec->endaddr += li->lm_addr;
/* Best effort to set addr_high/addr_low. This is used only by
'info sharedlibary'. */
diff --git a/gdb/solib-dsbt.c b/gdb/solib-dsbt.c
index c4071066f1..6d410ac90b 100644
--- a/gdb/solib-dsbt.c
+++ b/gdb/solib-dsbt.c
@@ -123,7 +123,7 @@ struct ext_link_map
/* Link map info to include in an allocated so_list entry */
-struct lm_info
+struct lm_info_dsbt : public lm_info_base
{
/* The loadmap, digested into an easier to use form. */
struct int_elf32_dsbt_loadmap *map;
@@ -137,7 +137,7 @@ struct dsbt_info
of loaded shared objects. ``main_executable_lm_info'' provides
a way to get at this information so that it doesn't need to be
frequently recomputed. Initialized by dsbt_relocate_main_executable. */
- struct lm_info *main_executable_lm_info;
+ struct lm_info_dsbt *main_executable_lm_info;
/* Load maps for the main executable and the interpreter. These are obtained
from ptrace. They are the starting point for getting into the program,
@@ -711,8 +711,9 @@ dsbt_current_sos (void)
}
sop = XCNEW (struct so_list);
- sop->lm_info = XCNEW (struct lm_info);
- sop->lm_info->map = loadmap;
+ lm_info_dsbt *li = XCNEW (lm_info_dsbt);
+ sop->lm_info = li;
+ li->map = loadmap;
/* Fetch the name. */
addr = extract_unsigned_integer (lm_buf.l_name,
sizeof (lm_buf.l_name),
@@ -930,7 +931,7 @@ dsbt_relocate_main_executable (void)
ldm = info->exec_loadmap;
xfree (info->main_executable_lm_info);
- info->main_executable_lm_info = XCNEW (struct lm_info);
+ info->main_executable_lm_info = XCNEW (lm_info_dsbt);
info->main_executable_lm_info->map = ldm;
new_offsets = XCNEWVEC (struct section_offsets,
@@ -1016,8 +1017,10 @@ dsbt_clear_solib (void)
static void
dsbt_free_so (struct so_list *so)
{
- xfree (so->lm_info->map);
- xfree (so->lm_info);
+ lm_info_dsbt *li = (lm_info_dsbt *) so->lm_info;
+
+ xfree (li->map);
+ xfree (li);
}
static void
@@ -1025,9 +1028,8 @@ dsbt_relocate_section_addresses (struct so_list *so,
struct target_section *sec)
{
int seg;
- struct int_elf32_dsbt_loadmap *map;
-
- map = so->lm_info->map;
+ lm_info_dsbt *li = (lm_info_dsbt *) so->lm_info;
+ int_elf32_dsbt_loadmap *map = li->map;
for (seg = 0; seg < map->nsegs; seg++)
{
diff --git a/gdb/solib-frv.c b/gdb/solib-frv.c
index e8d5f20d4f..0108d97815 100644
--- a/gdb/solib-frv.c
+++ b/gdb/solib-frv.c
@@ -202,7 +202,7 @@ struct ext_link_map
/* Link map info to include in an allocated so_list entry. */
-struct lm_info
+struct lm_info_frv : public lm_info_base
{
/* The loadmap, digested into an easier to use form. */
struct int_elf32_fdpic_loadmap *map;
@@ -231,7 +231,7 @@ struct lm_info
of loaded shared objects. ``main_executable_lm_info'' provides
a way to get at this information so that it doesn't need to be
frequently recomputed. Initialized by frv_relocate_main_executable(). */
-static struct lm_info *main_executable_lm_info;
+static lm_info_frv *main_executable_lm_info;
static void frv_relocate_main_executable (void);
static CORE_ADDR main_got (void);
@@ -389,10 +389,11 @@ frv_current_sos (void)
}
sop = XCNEW (struct so_list);
- sop->lm_info = XCNEW (struct lm_info);
- sop->lm_info->map = loadmap;
- sop->lm_info->got_value = got_addr;
- sop->lm_info->lm_addr = lm_addr;
+ lm_info_frv *li = XCNEW (lm_info_frv);
+ sop->lm_info = li;
+ li->map = loadmap;
+ li->got_value = got_addr;
+ li->lm_addr = lm_addr;
/* Fetch the name. */
addr = extract_unsigned_integer (lm_buf.l_name,
sizeof (lm_buf.l_name),
@@ -783,7 +784,7 @@ frv_relocate_main_executable (void)
if (main_executable_lm_info)
xfree (main_executable_lm_info);
- main_executable_lm_info = XCNEW (struct lm_info);
+ main_executable_lm_info = XCNEW (lm_info_frv);
main_executable_lm_info->map = ldm;
new_offsets = XCNEWVEC (struct section_offsets,
@@ -870,10 +871,12 @@ frv_clear_solib (void)
static void
frv_free_so (struct so_list *so)
{
- xfree (so->lm_info->map);
- xfree (so->lm_info->dyn_syms);
- xfree (so->lm_info->dyn_relocs);
- xfree (so->lm_info);
+ lm_info_frv *li = (lm_info_frv *) so->lm_info;
+
+ xfree (li->map);
+ xfree (li->dyn_syms);
+ xfree (li->dyn_relocs);
+ xfree (li);
}
static void
@@ -881,9 +884,8 @@ frv_relocate_section_addresses (struct so_list *so,
struct target_section *sec)
{
int seg;
- struct int_elf32_fdpic_loadmap *map;
-
- map = so->lm_info->map;
+ lm_info_frv *li = (lm_info_frv *) so->lm_info;
+ int_elf32_fdpic_loadmap *map = li->map;
for (seg = 0; seg < map->nsegs; seg++)
{
@@ -926,15 +928,14 @@ frv_fdpic_find_global_pointer (CORE_ADDR addr)
while (so)
{
int seg;
- struct int_elf32_fdpic_loadmap *map;
-
- map = so->lm_info->map;
+ lm_info_frv *li = (lm_info_frv *) so->lm_info;
+ int_elf32_fdpic_loadmap *map = li->map;
for (seg = 0; seg < map->nsegs; seg++)
{
if (map->segs[seg].addr <= addr
&& addr < map->segs[seg].addr + map->segs[seg].p_memsz)
- return so->lm_info->got_value;
+ return li->got_value;
}
so = so->next;
@@ -947,7 +948,7 @@ frv_fdpic_find_global_pointer (CORE_ADDR addr)
/* Forward declarations for frv_fdpic_find_canonical_descriptor(). */
static CORE_ADDR find_canonical_descriptor_in_load_object
- (CORE_ADDR, CORE_ADDR, const char *, bfd *, struct lm_info *);
+ (CORE_ADDR, CORE_ADDR, const char *, bfd *, lm_info_frv *);
/* Given a function entry point, attempt to find the canonical descriptor
associated with that entry point. Return 0 if no canonical descriptor
@@ -987,8 +988,10 @@ frv_fdpic_find_canonical_descriptor (CORE_ADDR entry_point)
so = master_so_list ();
while (so)
{
+ lm_info_frv *li = (lm_info_frv *) so->lm_info;
+
addr = find_canonical_descriptor_in_load_object
- (entry_point, got_value, name, so->abfd, so->lm_info);
+ (entry_point, got_value, name, so->abfd, li);
if (addr != 0)
break;
@@ -1003,7 +1006,7 @@ frv_fdpic_find_canonical_descriptor (CORE_ADDR entry_point)
static CORE_ADDR
find_canonical_descriptor_in_load_object
(CORE_ADDR entry_point, CORE_ADDR got_value, const char *name, bfd *abfd,
- struct lm_info *lm)
+ lm_info_frv *lm)
{
enum bfd_endian byte_order = gdbarch_byte_order (target_gdbarch ());
arelent *rel;
@@ -1141,8 +1144,10 @@ frv_fetch_objfile_link_map (struct objfile *objfile)
of shared libraries. */
for (so = master_so_list (); so; so = so->next)
{
+ lm_info_frv *li = (lm_info_frv *) so->lm_info;
+
if (so->objfile == objfile)
- return so->lm_info->lm_addr;
+ return li->lm_addr;
}
/* Not found! */
diff --git a/gdb/solib-svr4.c b/gdb/solib-svr4.c
index 4cb6127af3..6098d505da 100644
--- a/gdb/solib-svr4.c
+++ b/gdb/solib-svr4.c
@@ -51,27 +51,6 @@ static int svr4_have_link_map_offsets (void);
static void svr4_relocate_main_executable (void);
static void svr4_free_library_list (void *p_list);
-/* Link map info to include in an allocated so_list entry. */
-
-struct lm_info
- {
- /* Amount by which addresses in the binary should be relocated to
- match the inferior. The direct inferior value is L_ADDR_INFERIOR.
- When prelinking is involved and the prelink base address changes,
- we may need a different offset - the recomputed offset is in L_ADDR.
- It is commonly the same value. It is cached as we want to warn about
- the difference and compute it only once. L_ADDR is valid
- iff L_ADDR_P. */
- CORE_ADDR l_addr, l_addr_inferior;
- unsigned int l_addr_p : 1;
-
- /* The target location of lm. */
- CORE_ADDR lm_addr;
-
- /* Values read in from inferior's fields of the same name. */
- CORE_ADDR l_ld, l_next, l_prev, l_name;
- };
-
/* On SVR4 systems, a list of symbols in the dynamic linker where
GDB can try to place a breakpoint to monitor shared library
events.
@@ -189,12 +168,12 @@ svr4_same (struct so_list *gdb, struct so_list *inferior)
return (svr4_same_1 (gdb->so_original_name, inferior->so_original_name));
}
-static struct lm_info *
+static lm_info_svr4 *
lm_info_read (CORE_ADDR lm_addr)
{
struct link_map_offsets *lmo = svr4_fetch_link_map_offsets ();
gdb_byte *lm;
- struct lm_info *lm_info;
+ lm_info_svr4 *lm_info;
struct cleanup *back_to;
lm = (gdb_byte *) xmalloc (lmo->link_map_size);
@@ -210,7 +189,7 @@ lm_info_read (CORE_ADDR lm_addr)
{
struct type *ptr_type = builtin_type (target_gdbarch ())->builtin_data_ptr;
- lm_info = XCNEW (struct lm_info);
+ lm_info = XCNEW (lm_info_svr4);
lm_info->lm_addr = lm_addr;
lm_info->l_addr_inferior = extract_typed_address (&lm[lmo->l_addr_offset],
@@ -240,17 +219,19 @@ has_lm_dynamic_from_link_map (void)
static CORE_ADDR
lm_addr_check (const struct so_list *so, bfd *abfd)
{
- if (!so->lm_info->l_addr_p)
+ lm_info_svr4 *li = (lm_info_svr4 *) so->lm_info;
+
+ if (!li->l_addr_p)
{
struct bfd_section *dyninfo_sect;
CORE_ADDR l_addr, l_dynaddr, dynaddr;
- l_addr = so->lm_info->l_addr_inferior;
+ l_addr = li->l_addr_inferior;
if (! abfd || ! has_lm_dynamic_from_link_map ())
goto set_addr;
- l_dynaddr = so->lm_info->l_ld;
+ l_dynaddr = li->l_ld;
dyninfo_sect = bfd_get_section_by_name (abfd, ".dynamic");
if (dyninfo_sect == NULL)
@@ -333,11 +314,11 @@ lm_addr_check (const struct so_list *so, bfd *abfd)
}
set_addr:
- so->lm_info->l_addr = l_addr;
- so->lm_info->l_addr_p = 1;
+ li->l_addr = l_addr;
+ li->l_addr_p = 1;
}
- return so->lm_info->l_addr;
+ return li->l_addr;
}
/* Per pspace SVR4 specific data. */
@@ -994,9 +975,10 @@ svr4_keep_data_in_core (CORE_ADDR vaddr, unsigned long size)
newobj = XCNEW (struct so_list);
old_chain = make_cleanup (xfree, newobj);
- newobj->lm_info = lm_info_read (ldsomap);
+ lm_info_svr4 *li = lm_info_read (ldsomap);
+ newobj->lm_info = li;
make_cleanup (xfree, newobj->lm_info);
- name_lm = newobj->lm_info ? newobj->lm_info->l_name : 0;
+ name_lm = li != NULL ? li->l_name : 0;
do_cleanups (old_chain);
return (name_lm >= vaddr && name_lm < vaddr + size);
@@ -1106,8 +1088,10 @@ svr4_free_so (struct so_list *so)
static void
svr4_clear_so (struct so_list *so)
{
- if (so->lm_info != NULL)
- so->lm_info->l_addr_p = 0;
+ lm_info_svr4 *li = (lm_info_svr4 *) so->lm_info;
+
+ if (li != NULL)
+ li->l_addr_p = 0;
}
/* Free so_list built so far (called via cleanup). */
@@ -1141,8 +1125,8 @@ svr4_copy_library_list (struct so_list *src)
newobj = XNEW (struct so_list);
memcpy (newobj, src, sizeof (struct so_list));
- newobj->lm_info = XNEW (struct lm_info);
- memcpy (newobj->lm_info, src->lm_info, sizeof (struct lm_info));
+ newobj->lm_info = XNEW (lm_info_svr4);
+ memcpy (newobj->lm_info, src->lm_info, sizeof (lm_info_svr4));
newobj->next = NULL;
*link = newobj;
@@ -1178,10 +1162,11 @@ library_list_start_library (struct gdb_xml_parser *parser,
struct so_list *new_elem;
new_elem = XCNEW (struct so_list);
- new_elem->lm_info = XCNEW (struct lm_info);
- new_elem->lm_info->lm_addr = *lmp;
- new_elem->lm_info->l_addr_inferior = *l_addrp;
- new_elem->lm_info->l_ld = *l_ldp;
+ lm_info_svr4 *li = XCNEW (lm_info_svr4);
+ new_elem->lm_info = li;
+ li->lm_addr = *lmp;
+ li->l_addr_inferior = *l_addrp;
+ li->l_ld = *l_ldp;
strncpy (new_elem->so_name, name, sizeof (new_elem->so_name) - 1);
new_elem->so_name[sizeof (new_elem->so_name) - 1] = 0;
@@ -1332,12 +1317,12 @@ svr4_default_sos (void)
return NULL;
newobj = XCNEW (struct so_list);
-
- newobj->lm_info = XCNEW (struct lm_info);
+ lm_info_svr4 *li = XCNEW (lm_info_svr4);
+ newobj->lm_info = li;
/* Nothing will ever check the other fields if we set l_addr_p. */
- newobj->lm_info->l_addr = info->debug_loader_offset;
- newobj->lm_info->l_addr_p = 1;
+ li->l_addr = info->debug_loader_offset;
+ li->l_addr_p = 1;
strncpy (newobj->so_name, info->debug_loader_name, SO_NAME_MAX_PATH_SIZE - 1);
newobj->so_name[SO_NAME_MAX_PATH_SIZE - 1] = '\0';
@@ -1371,20 +1356,21 @@ svr4_read_so_list (CORE_ADDR lm, CORE_ADDR prev_lm,
newobj = XCNEW (struct so_list);
old_chain = make_cleanup_free_so (newobj);
- newobj->lm_info = lm_info_read (lm);
- if (newobj->lm_info == NULL)
+ lm_info_svr4 *li = lm_info_read (lm);
+ newobj->lm_info = li;
+ if (li == NULL)
{
do_cleanups (old_chain);
return 0;
}
- next_lm = newobj->lm_info->l_next;
+ next_lm = li->l_next;
- if (newobj->lm_info->l_prev != prev_lm)
+ if (li->l_prev != prev_lm)
{
warning (_("Corrupted shared library list: %s != %s"),
paddress (target_gdbarch (), prev_lm),
- paddress (target_gdbarch (), newobj->lm_info->l_prev));
+ paddress (target_gdbarch (), li->l_prev));
do_cleanups (old_chain);
return 0;
}
@@ -1394,26 +1380,26 @@ svr4_read_so_list (CORE_ADDR lm, CORE_ADDR prev_lm,
SVR4, it has no name. For others (Solaris 2.3 for example), it
does have a name, so we can no longer use a missing name to
decide when to ignore it. */
- if (ignore_first && newobj->lm_info->l_prev == 0)
+ if (ignore_first && li->l_prev == 0)
{
struct svr4_info *info = get_svr4_info ();
- first_l_name = newobj->lm_info->l_name;
- info->main_lm_addr = newobj->lm_info->lm_addr;
+ first_l_name = li->l_name;
+ info->main_lm_addr = li->lm_addr;
do_cleanups (old_chain);
continue;
}
/* Extract this shared object's name. */
- target_read_string (newobj->lm_info->l_name, &buffer,
- SO_NAME_MAX_PATH_SIZE - 1, &errcode);
+ target_read_string (li->l_name, &buffer, SO_NAME_MAX_PATH_SIZE - 1,
+ &errcode);
if (errcode != 0)
{
/* If this entry's l_name address matches that of the
inferior executable, then this is not a normal shared
object, but (most likely) a vDSO. In this case, silently
skip it; otherwise emit a warning. */
- if (first_l_name == 0 || newobj->lm_info->l_name != first_l_name)
+ if (first_l_name == 0 || li->l_name != first_l_name)
warning (_("Can't read pathname for load map: %s."),
safe_strerror (errcode));
do_cleanups (old_chain);
@@ -1594,7 +1580,10 @@ svr4_current_sos (void)
[...]
[ 9] .dynamic DYNAMIC ffffffffff700580 000580 0000f0
*/
- if (address_in_mem_range (so->lm_info->l_ld, &vsyscall_range))
+
+ lm_info_svr4 *li = (lm_info_svr4 *) so->lm_info;
+
+ if (address_in_mem_range (li->l_ld, &vsyscall_range))
{
*sop = so->next;
free_so (so);
@@ -1628,7 +1617,11 @@ svr4_fetch_objfile_link_map (struct objfile *objfile)
of shared libraries. */
for (so = master_so_list (); so; so = so->next)
if (so->objfile == objfile)
- return so->lm_info->lm_addr;
+ {
+ lm_info_svr4 *li = (lm_info_svr4 *) so->lm_info;
+
+ return li->lm_addr;
+ }
/* Not found! */
return 0;
@@ -1860,7 +1853,9 @@ solist_update_incremental (struct svr4_info *info, CORE_ADDR lm)
/* Walk to the end of the list. */
for (tail = info->solib_list; tail->next != NULL; tail = tail->next)
/* Nothing. */;
- prev_lm = tail->lm_info->lm_addr;
+
+ lm_info_svr4 *li = (lm_info_svr4 *) tail->lm_info;
+ prev_lm = li->lm_addr;
/* Read the new objects. */
if (info->using_xfer)
diff --git a/gdb/solib-svr4.h b/gdb/solib-svr4.h
index b97fbd62f5..a9b09aa56c 100644
--- a/gdb/solib-svr4.h
+++ b/gdb/solib-svr4.h
@@ -20,11 +20,34 @@
#ifndef SOLIB_SVR4_H
#define SOLIB_SVR4_H
+#include "solist.h"
+
struct objfile;
struct target_so_ops;
extern struct target_so_ops svr4_so_ops;
+/* Link map info to include in an allocated so_list entry. */
+
+struct lm_info_svr4 : public lm_info_base
+{
+ /* Amount by which addresses in the binary should be relocated to
+ match the inferior. The direct inferior value is L_ADDR_INFERIOR.
+ When prelinking is involved and the prelink base address changes,
+ we may need a different offset - the recomputed offset is in L_ADDR.
+ It is commonly the same value. It is cached as we want to warn about
+ the difference and compute it only once. L_ADDR is valid
+ iff L_ADDR_P. */
+ CORE_ADDR l_addr, l_addr_inferior;
+ unsigned int l_addr_p : 1;
+
+ /* The target location of lm. */
+ CORE_ADDR lm_addr;
+
+ /* Values read in from inferior's fields of the same name. */
+ CORE_ADDR l_ld, l_next, l_prev, l_name;
+};
+
/* Critical offsets and sizes which describe struct r_debug and
struct link_map on SVR4-like targets. All offsets and sizes are
in bytes unless otherwise specified. */
diff --git a/gdb/solib-target.c b/gdb/solib-target.c
index 1b10e4ea41..e40acc1823 100644
--- a/gdb/solib-target.c
+++ b/gdb/solib-target.c
@@ -27,7 +27,7 @@
#include "solib-target.h"
/* Private data for each loaded library. */
-struct lm_info
+struct lm_info_target : public lm_info_base
{
/* The library's name. The name is normally kept in the struct
so_list; it is only here during XML parsing. */
@@ -49,12 +49,12 @@ struct lm_info
struct section_offsets *offsets;
};
-typedef struct lm_info *lm_info_p;
-DEF_VEC_P(lm_info_p);
+typedef lm_info_target *lm_info_target_p;
+DEF_VEC_P(lm_info_target_p);
#if !defined(HAVE_LIBEXPAT)
-static VEC(lm_info_p) *
+static VEC(lm_info_target_p) *
solib_target_parse_libraries (const char *library)
{
static int have_warned;
@@ -80,8 +80,8 @@ library_list_start_segment (struct gdb_xml_parser *parser,
const struct gdb_xml_element *element,
void *user_data, VEC(gdb_xml_value_s) *attributes)
{
- VEC(lm_info_p) **list = (VEC(lm_info_p) **) user_data;
- struct lm_info *last = VEC_last (lm_info_p, *list);
+ VEC(lm_info_target_p) **list = (VEC(lm_info_target_p) **) user_data;
+ lm_info_target *last = VEC_last (lm_info_target_p, *list);
ULONGEST *address_p
= (ULONGEST *) xml_find_attribute (attributes, "address")->value;
CORE_ADDR address = (CORE_ADDR) *address_p;
@@ -98,8 +98,8 @@ library_list_start_section (struct gdb_xml_parser *parser,
const struct gdb_xml_element *element,
void *user_data, VEC(gdb_xml_value_s) *attributes)
{
- VEC(lm_info_p) **list = (VEC(lm_info_p) **) user_data;
- struct lm_info *last = VEC_last (lm_info_p, *list);
+ VEC(lm_info_target_p) **list = (VEC(lm_info_target_p) **) user_data;
+ lm_info_target *last = VEC_last (lm_info_target_p, *list);
ULONGEST *address_p
= (ULONGEST *) xml_find_attribute (attributes, "address")->value;
CORE_ADDR address = (CORE_ADDR) *address_p;
@@ -118,13 +118,13 @@ library_list_start_library (struct gdb_xml_parser *parser,
const struct gdb_xml_element *element,
void *user_data, VEC(gdb_xml_value_s) *attributes)
{
- VEC(lm_info_p) **list = (VEC(lm_info_p) **) user_data;
- struct lm_info *item = XCNEW (struct lm_info);
+ VEC(lm_info_target_p) **list = (VEC(lm_info_target_p) **) user_data;
+ lm_info_target *item = XCNEW (lm_info_target);
const char *name
= (const char *) xml_find_attribute (attributes, "name")->value;
item->name = xstrdup (name);
- VEC_safe_push (lm_info_p, *list, item);
+ VEC_safe_push (lm_info_target_p, *list, item);
}
static void
@@ -132,8 +132,8 @@ library_list_end_library (struct gdb_xml_parser *parser,
const struct gdb_xml_element *element,
void *user_data, const char *body_text)
{
- VEC(lm_info_p) **list = (VEC(lm_info_p) **) user_data;
- struct lm_info *lm_info = VEC_last (lm_info_p, *list);
+ VEC(lm_info_target_p) **list = (VEC(lm_info_target_p) **) user_data;
+ lm_info_target *lm_info = VEC_last (lm_info_target_p, *list);
if (lm_info->segment_bases == NULL
&& lm_info->section_bases == NULL)
@@ -168,18 +168,18 @@ library_list_start_list (struct gdb_xml_parser *parser,
static void
solib_target_free_library_list (void *p)
{
- VEC(lm_info_p) **result = (VEC(lm_info_p) **) p;
- struct lm_info *info;
+ VEC(lm_info_target_p) **result = (VEC(lm_info_target_p) **) p;
+ lm_info_target *info;
int ix;
- for (ix = 0; VEC_iterate (lm_info_p, *result, ix, info); ix++)
+ for (ix = 0; VEC_iterate (lm_info_target_p, *result, ix, info); ix++)
{
xfree (info->name);
VEC_free (CORE_ADDR, info->segment_bases);
VEC_free (CORE_ADDR, info->section_bases);
xfree (info);
}
- VEC_free (lm_info_p, *result);
+ VEC_free (lm_info_target_p, *result);
*result = NULL;
}
@@ -229,10 +229,10 @@ static const struct gdb_xml_element library_list_elements[] = {
{ NULL, NULL, NULL, GDB_XML_EF_NONE, NULL, NULL }
};
-static VEC(lm_info_p) *
+static VEC(lm_info_target_p) *
solib_target_parse_libraries (const char *library)
{
- VEC(lm_info_p) *result = NULL;
+ VEC(lm_info_target_p) *result = NULL;
struct cleanup *back_to = make_cleanup (solib_target_free_library_list,
&result);
@@ -255,8 +255,8 @@ solib_target_current_sos (void)
struct so_list *new_solib, *start = NULL, *last = NULL;
char *library_document;
struct cleanup *old_chain;
- VEC(lm_info_p) *library_list;
- struct lm_info *info;
+ VEC(lm_info_target_p) *library_list;
+ lm_info_target *info;
int ix;
/* Fetch the list of shared libraries. */
@@ -279,7 +279,7 @@ solib_target_current_sos (void)
return NULL;
/* Build a struct so_list for each entry on the list. */
- for (ix = 0; VEC_iterate (lm_info_p, library_list, ix, info); ix++)
+ for (ix = 0; VEC_iterate (lm_info_target_p, library_list, ix, info); ix++)
{
new_solib = XCNEW (struct so_list);
strncpy (new_solib->so_name, info->name, SO_NAME_MAX_PATH_SIZE - 1);
@@ -304,7 +304,7 @@ solib_target_current_sos (void)
}
/* Free the library list, but not its members. */
- VEC_free (lm_info_p, library_list);
+ VEC_free (lm_info_target_p, library_list);
return start;
}
@@ -324,10 +324,12 @@ solib_target_clear_solib (void)
static void
solib_target_free_so (struct so_list *so)
{
- gdb_assert (so->lm_info->name == NULL);
- xfree (so->lm_info->offsets);
- VEC_free (CORE_ADDR, so->lm_info->segment_bases);
- xfree (so->lm_info);
+ lm_info_target *li = (lm_info_target *) so->lm_info;
+
+ gdb_assert (li->name == NULL);
+ xfree (li->offsets);
+ VEC_free (CORE_ADDR, li->segment_bases);
+ xfree (li);
}
static void
@@ -335,23 +337,24 @@ solib_target_relocate_section_addresses (struct so_list *so,
struct target_section *sec)
{
CORE_ADDR offset;
+ lm_info_target *li = (lm_info_target *) so->lm_info;
/* Build the offset table only once per object file. We can not do
it any earlier, since we need to open the file first. */
- if (so->lm_info->offsets == NULL)
+ if (li->offsets == NULL)
{
int num_sections = gdb_bfd_count_sections (so->abfd);
- so->lm_info->offsets
+ li->offsets
= ((struct section_offsets *)
xzalloc (SIZEOF_N_SECTION_OFFSETS (num_sections)));
- if (so->lm_info->section_bases)
+ if (li->section_bases)
{
int i;
asection *sect;
int num_section_bases
- = VEC_length (CORE_ADDR, so->lm_info->section_bases);
+ = VEC_length (CORE_ADDR, li->section_bases);
int num_alloc_sections = 0;
for (i = 0, sect = so->abfd->sections;
@@ -371,7 +374,7 @@ Could not relocate shared library \"%s\": wrong number of ALLOC sections"),
CORE_ADDR *section_bases;
section_bases = VEC_address (CORE_ADDR,
- so->lm_info->section_bases);
+ li->section_bases);
so->addr_low = ~(CORE_ADDR) 0;
so->addr_high = 0;
@@ -395,7 +398,7 @@ Could not relocate shared library \"%s\": wrong number of ALLOC sections"),
gdb_assert (so->addr_low <= so->addr_high);
found_range = 1;
}
- so->lm_info->offsets->offsets[i]
+ li->offsets->offsets[i]
= section_bases[bases_index];
bases_index++;
}
@@ -404,7 +407,7 @@ Could not relocate shared library \"%s\": wrong number of ALLOC sections"),
gdb_assert (so->addr_low <= so->addr_high);
}
}
- else if (so->lm_info->segment_bases)
+ else if (li->segment_bases)
{
struct symfile_segment_data *data;
@@ -419,12 +422,10 @@ Could not relocate shared library \"%s\": no segments"), so->so_name);
int num_bases;
CORE_ADDR *segment_bases;
- num_bases = VEC_length (CORE_ADDR, so->lm_info->segment_bases);
- segment_bases = VEC_address (CORE_ADDR,
- so->lm_info->segment_bases);
+ num_bases = VEC_length (CORE_ADDR, li->segment_bases);
+ segment_bases = VEC_address (CORE_ADDR, li->segment_bases);
- if (!symfile_map_offsets_to_segments (so->abfd, data,
- so->lm_info->offsets,
+ if (!symfile_map_offsets_to_segments (so->abfd, data, li->offsets,
num_bases, segment_bases))
warning (_("\
Could not relocate shared library \"%s\": bad offsets"), so->so_name);
@@ -459,9 +460,9 @@ Could not relocate shared library \"%s\": bad offsets"), so->so_name);
}
}
- offset = so->lm_info->offsets->offsets[gdb_bfd_section_index
- (sec->the_bfd_section->owner,
- sec->the_bfd_section)];
+ offset = li->offsets->offsets[gdb_bfd_section_index
+ (sec->the_bfd_section->owner,
+ sec->the_bfd_section)];
sec->addr += offset;
sec->endaddr += offset;
}
diff --git a/gdb/solist.h b/gdb/solist.h
index 378d60d7b8..54c9902b4a 100644
--- a/gdb/solist.h
+++ b/gdb/solist.h
@@ -29,9 +29,11 @@
so != NULL; \
so = so->next)
-/* Forward declaration for target specific link map information. This
- struct is opaque to all but the target specific file. */
-struct lm_info;
+/* Base class for target-specific link map information. */
+
+struct lm_info_base
+{
+};
struct so_list
{
@@ -45,7 +47,7 @@ struct so_list
will be a copy of struct link_map from the user process, but
it need not be; it can be any collection of data needed to
traverse the dynamic linker's data structures. */
- struct lm_info *lm_info;
+ lm_info_base *lm_info;
/* Shared object file name, exactly as it appears in the
inferior's link map. This may be a relative path, or something
diff --git a/gdb/windows-nat.c b/gdb/windows-nat.c
index 805fb4358d..ef1c2914f1 100644
--- a/gdb/windows-nat.c
+++ b/gdb/windows-nat.c
@@ -585,7 +585,7 @@ struct safe_symbol_file_add_args
};
/* Maintain a linked list of "so" information. */
-struct lm_info
+struct lm_info_windows : public lm_info_base
{
LPVOID load_addr;
};
@@ -645,8 +645,9 @@ windows_make_so (const char *name, LPVOID load_addr)
}
#endif
so = XCNEW (struct so_list);
- so->lm_info = XNEW (struct lm_info);
- so->lm_info->load_addr = load_addr;
+ lm_info_windows *li = XCNEW (struct lm_info_windows);
+ so->lm_info = li;
+ li->load_addr = load_addr;
strcpy (so->so_original_name, name);
#ifndef __CYGWIN__
strcpy (so->so_name, buf);
@@ -772,8 +773,10 @@ handle_load_dll (void *dummy)
solib_end->next = windows_make_so (dll_name, event->lpBaseOfDll);
solib_end = solib_end->next;
+ lm_info_windows *li = (lm_info_windows *) solib_end->lm_info;
+
DEBUG_EVENTS (("gdb: Loading dll \"%s\" at %s.\n", solib_end->so_name,
- host_address_to_string (solib_end->lm_info->load_addr)));
+ host_address_to_string (li->load_addr)));
return 1;
}
@@ -801,18 +804,22 @@ handle_unload_dll (void *dummy)
struct so_list *so;
for (so = &solib_start; so->next != NULL; so = so->next)
- if (so->next->lm_info->load_addr == lpBaseOfDll)
- {
- struct so_list *sodel = so->next;
+ {
+ lm_info_windows *li_next = (lm_info_windows *) so->next->lm_info;
- so->next = sodel->next;
- if (!so->next)
- solib_end = so;
- DEBUG_EVENTS (("gdb: Unloading dll \"%s\".\n", sodel->so_name));
+ if (li_next->load_addr == lpBaseOfDll)
+ {
+ struct so_list *sodel = so->next;
- windows_free_so (sodel);
- return 1;
- }
+ so->next = sodel->next;
+ if (!so->next)
+ solib_end = so;
+ DEBUG_EVENTS (("gdb: Unloading dll \"%s\".\n", sodel->so_name));
+
+ windows_free_so (sodel);
+ return 1;
+ }
+ }
/* We did not find any DLL that was previously loaded at this address,
so register a complaint. We do not report an error, because we have
@@ -2842,9 +2849,13 @@ windows_xfer_shared_libraries (struct target_ops *ops,
obstack_init (&obstack);
obstack_grow_str (&obstack, "<library-list>\n");
for (so = solib_start.next; so; so = so->next)
- windows_xfer_shared_library (so->so_name, (CORE_ADDR)
- (uintptr_t) so->lm_info->load_addr,
- target_gdbarch (), &obstack);
+ {
+ lm_info_windows *li = (lm_info_windows *) so->lm_info;
+
+ windows_xfer_shared_library (so->so_name, (CORE_ADDR)
+ (uintptr_t) li->load_addr,
+ target_gdbarch (), &obstack);
+ }
obstack_grow_str0 (&obstack, "</library-list>\n");
buf = (const char *) obstack_finish (&obstack);