X-Git-Url: http://git.efficios.com/?a=blobdiff_plain;f=gdb%2Fsolib-aix5.c;h=1a8c9dfeea94d8ae575f0e25eb25decb2803bd82;hb=ebc7896c3ce2248ea34b8c3f162ac590126840d5;hp=1eddafe612bf05bc18b4ac1a406a3af1c7113fcf;hpb=0579d647a61461ed960277ba423595bca55bc25a;p=deliverable%2Fbinutils-gdb.git diff --git a/gdb/solib-aix5.c b/gdb/solib-aix5.c index 1eddafe612..1a8c9dfeea 100644 --- a/gdb/solib-aix5.c +++ b/gdb/solib-aix5.c @@ -1,6 +1,6 @@ /* Handle AIX5 shared libraries for GDB, the GNU Debugger. - Copyright 1990, 1991, 1992, 1993, 1994, 1995, 1996, 1998, 1999, - 2000, 2001 + Copyright 1990, 1991, 1992, 1993, 1994, 1995, 1996, 1998, 1999, 2000, + 2001 Free Software Foundation, Inc. This file is part of GDB. @@ -49,22 +49,17 @@ /* Link map info to include in an allocated so_list entry */ -enum maptype { - MT_READONLY = 0, - MT_READWRITE = 1, - MT_LAST = 2 -}; - struct lm_info { - struct + int nmappings; /* number of mappings */ + struct lm_mapping { CORE_ADDR addr; /* base address */ CORE_ADDR size; /* size of mapped object */ CORE_ADDR offset; /* offset into mapped object */ long flags; /* MA_ protection and attribute flags */ CORE_ADDR gp; /* global pointer value */ - } mapping[MT_LAST]; + } *mapping; char *mapname; /* name in /proc/pid/object */ char *pathname; /* full pathname to object */ char *membername; /* member name in archive file */ @@ -105,7 +100,7 @@ static void aix5_relocate_main_executable (void); static CORE_ADDR bfd_lookup_symbol (bfd *abfd, char *symname) { - unsigned int storage_needed; + long storage_needed; asymbol *sym; asymbol **symbol_table; unsigned int number_of_symbols; @@ -118,7 +113,7 @@ bfd_lookup_symbol (bfd *abfd, char *symname) if (storage_needed > 0) { symbol_table = (asymbol **) xmalloc (storage_needed); - back_to = make_cleanup (free, (PTR) symbol_table); + back_to = make_cleanup (xfree, symbol_table); number_of_symbols = bfd_canonicalize_symtab (abfd, symbol_table); for (i = 0; i < number_of_symbols; i++) @@ -140,15 +135,11 @@ bfd_lookup_symbol (bfd *abfd, char *symname) /* Look for the symbol in the dynamic string table too. */ storage_needed = bfd_get_dynamic_symtab_upper_bound (abfd); -/* FIXME: This problem should be addressed in BFD. */ -#define REASONABLE_LIMIT 0x400000 - if (storage_needed > REASONABLE_LIMIT) - storage_needed = REASONABLE_LIMIT; if (storage_needed > 0) { symbol_table = (asymbol **) xmalloc (storage_needed); - back_to = make_cleanup (free, (PTR) symbol_table); + back_to = make_cleanup (xfree, symbol_table); number_of_symbols = bfd_canonicalize_dynamic_symtab (abfd, symbol_table); for (i = 0; i < number_of_symbols; i++) @@ -197,13 +188,14 @@ build_so_list_from_mapfile (int pid, long match_mask, long match_val) { int mapbuf_allocation_size = 8192; - char map_pathname[64]; + char *map_pathname; int map_fd; /* Open the map file */ - sprintf (map_pathname, "/proc/%d/map", pid); + xasprintf (&map_pathname, "/proc/%d/map", pid); map_fd = open (map_pathname, O_RDONLY); + xfree (map_pathname); if (map_fd < 0) return 0; @@ -212,7 +204,7 @@ build_so_list_from_mapfile (int pid, long match_mask, long match_val) { if (mapbuf) { - free (mapbuf); + xfree (mapbuf); mapbuf_allocation_size *= 2; lseek (map_fd, 0, SEEK_SET); } @@ -220,7 +212,7 @@ build_so_list_from_mapfile (int pid, long match_mask, long match_val) mapbuf_size = read (map_fd, mapbuf, mapbuf_allocation_size); if (mapbuf_size < 0) { - free (mapbuf); + xfree (mapbuf); /* FIXME: This warrants an error or a warning of some sort */ return 0; } @@ -235,7 +227,7 @@ build_so_list_from_mapfile (int pid, long match_mask, long match_val) { char *mapname, *pathname, *membername; struct so_list *sop; - enum maptype maptype; + int mapidx; if (prmap->pr_size == 0) break; @@ -270,18 +262,18 @@ build_so_list_from_mapfile (int pid, long match_mask, long match_val) if (sop == NULL) { - sop = xcalloc (sizeof (struct so_list), 1); - make_cleanup (free, sop); - sop->lm_info = xcalloc (sizeof (struct lm_info), 1); - make_cleanup (free, sop->lm_info); + sop = xcalloc (1, sizeof (struct so_list)); + make_cleanup (xfree, sop); + sop->lm_info = xcalloc (1, sizeof (struct lm_info)); + make_cleanup (xfree, sop->lm_info); sop->lm_info->mapname = xstrdup (mapname); - make_cleanup (free, sop->lm_info->mapname); + make_cleanup (xfree, sop->lm_info->mapname); /* FIXME: Eliminate the pathname field once length restriction is lifted on so_name and so_original_name. */ sop->lm_info->pathname = xstrdup (pathname); - make_cleanup (free, sop->lm_info->pathname); + make_cleanup (xfree, sop->lm_info->pathname); sop->lm_info->membername = xstrdup (membername); - make_cleanup (free, sop->lm_info->membername); + make_cleanup (xfree, sop->lm_info->membername); strncpy (sop->so_name, pathname, SO_NAME_MAX_PATH_SIZE - 1); sop->so_name[SO_NAME_MAX_PATH_SIZE - 1] = '\0'; @@ -291,15 +283,19 @@ build_so_list_from_mapfile (int pid, long match_mask, long match_val) sos = sop; } - maptype = (prmap->pr_mflags & MA_WRITE) ? MT_READWRITE : MT_READONLY; - sop->lm_info->mapping[maptype].addr = (CORE_ADDR) prmap->pr_vaddr; - sop->lm_info->mapping[maptype].size = prmap->pr_size; - sop->lm_info->mapping[maptype].offset = prmap->pr_off; - sop->lm_info->mapping[maptype].flags = prmap->pr_mflags; - sop->lm_info->mapping[maptype].gp = (CORE_ADDR) prmap->pr_gp; + mapidx = sop->lm_info->nmappings; + sop->lm_info->nmappings += 1; + sop->lm_info->mapping + = xrealloc (sop->lm_info->mapping, + sop->lm_info->nmappings * sizeof (struct lm_mapping)); + sop->lm_info->mapping[mapidx].addr = (CORE_ADDR) prmap->pr_vaddr; + sop->lm_info->mapping[mapidx].size = prmap->pr_size; + sop->lm_info->mapping[mapidx].offset = prmap->pr_off; + sop->lm_info->mapping[mapidx].flags = prmap->pr_mflags; + sop->lm_info->mapping[mapidx].gp = (CORE_ADDR) prmap->pr_gp; } - free (mapbuf); + xfree (mapbuf); return sos; } @@ -333,7 +329,7 @@ open_symbol_file_object (void *from_ttyp) struct cleanup *old_chain = make_cleanup (null_cleanup, 0); struct so_list *sos; - sos = build_so_list_from_mapfile (PIDGET (inferior_pid), + sos = build_so_list_from_mapfile (PIDGET (inferior_ptid), MA_MAINEXEC, MA_MAINEXEC); @@ -378,7 +374,7 @@ aix5_current_sos (void) struct so_list *sos; /* Fetch the list of mappings, excluding the main executable. */ - sos = build_so_list_from_mapfile (PIDGET (inferior_pid), MA_MAINEXEC, 0); + sos = build_so_list_from_mapfile (PIDGET (inferior_ptid), MA_MAINEXEC, 0); /* Reverse the list; it looks nicer when we print it if the mappings are in the same order as in the map file. */ @@ -409,9 +405,8 @@ static CORE_ADDR interp_text_sect_high; static CORE_ADDR interp_plt_sect_low; static CORE_ADDR interp_plt_sect_high; -/* FIXME: Does this belong here? (If it does, it ought to be renamed.) */ -int -in_svr4_dynsym_resolve_code (CORE_ADDR pc) +static int +aix5_in_dynsym_resolve_code (CORE_ADDR pc) { return ((pc >= interp_text_sect_low && pc < interp_text_sect_high) || (pc >= interp_plt_sect_low && pc < interp_plt_sect_high) @@ -496,7 +491,7 @@ enable_break (void) load_addr = read_pc () - tmp_bfd->start_address; /* Record the relocated start and end address of the dynamic linker - text and plt section for in_aix5_dynsym_resolve_code. */ + text and plt section for aix5_in_dynsym_resolve_code. */ interp_sect = bfd_get_section_by_name (tmp_bfd, ".text"); if (interp_sect) { @@ -567,6 +562,133 @@ aix5_special_symbol_handling (void) /* Nothing needed (yet) for AIX5. */ } +/* On AIX5, the /proc/PID/map information is used to determine + the relocation offsets needed for relocating the main executable. + There is no problem determining which map entries correspond + to the main executable, because these will have the MA_MAINEXEC + flag set. The tricky part is determining which sections correspond + to which map entries. To date, the following approaches have + been tried: + + - Use the MA_WRITE attribute of pr_mflags to distinguish the read-only + mapping from the read/write mapping. (This assumes that there are + only two mappings for the main executable.) All writable sections + are associated with the read/write mapping and all non-writable + sections are associated with the read-only mapping. + + This approach worked quite well until we came across executables + which didn't have a read-only mapping. Both mappings had the + same attributes represented in pr_mflags and it was impossible + to tell them apart. + + - Use the pr_off field (which represents the offset into the + executable) to determine the section-to-mapping relationship. + Unfortunately, this approach doesn't work either, because the + offset value contained in the mapping is rounded down by some + moderately large power-of-2 value (4096 is a typical value). + A small (e.g. "Hello World") program will appear to have all + of its sections belonging to both mappings. + + Also, the following approach has been considered, but dismissed: + + - The section vma values typically look (something) like + 0x00000001xxxxxxxx or 0x00000002xxxxxxxx. Furthermore, the + 0x00000001xxxxxxxx values always belong to one mapping and + the 0x00000002xxxxxxxx values always belong to the other. + Thus it seems conceivable that GDB could use the bit patterns + in the upper portion (for some definition of "upper") in a + section's vma to help determine the section-to-mapping + relationship. + + This approach was dismissed because there is nothing to prevent + the linker from lumping the section vmas together in one large + contiguous space and still expecting the dynamic linker to + separate them and relocate them independently. Also, different + linkers have been observed to use different patterns for the + upper portions of the vma addresses and it isn't clear what the + mask ought to be for distinguishing these patterns. + + The current (admittedly inelegant) approach uses a lookup + table which associates section names with the map index that + they're permitted to be in. This is inelegant because we are + making the following assumptions: + + 1) There will only be two mappings. + 2) The relevant (i.e. main executable) mappings will always appear + in the same order in the map file. + 3) The sections named in the table will always belong to the + indicated mapping. + 4) The table completely enumerates all possible section names. + + IMO, any of these deficiencies alone will normally be sufficient + to disqualify this approach, but I haven't been able to think of + a better way to do it. + + map_index_vs_section_name_okay() is a predicate which returns + true iff the section name NAME is associated with the map index + IDX in its builtin table. Of course, there's no guarantee that + this association is actually valid... */ + +static int +map_index_vs_section_name_okay (int idx, const char *name) +{ + static struct + { + char *name; + int idx; + } okay[] = + { + { ".interp", 0 }, + { ".hash", 0 }, + { ".dynsym", 0 }, + { ".dynstr", 0 }, + { ".rela.text", 0 }, + { ".rela.rodata", 0 }, + { ".rela.data", 0 }, + { ".rela.ctors", 0 }, + { ".rela.dtors", 0 }, + { ".rela.got", 0 }, + { ".rela.sdata", 0 }, + { ".rela.IA_64.pltoff", 0 }, + { ".rel.data", 0 }, + { ".rel.sdata", 0 }, + { ".rel.got", 0 }, + { ".rel.AIX.pfdesc", 0 }, + { ".rel.IA_64.pltoff", 0 }, + { ".dynamic", 0 }, + { ".init", 0 }, + { ".plt", 0 }, + { ".text", 0 }, + { ".fini", 0 }, + { ".rodata", 0 }, + { ".IA_64.unwind_info", 0 }, + { ".IA_64.unwind", 0 }, + { ".AIX.mustrel", 0 }, + + { ".data", 1 }, + { ".ctors", 1 }, + { ".dtors", 1 }, + { ".got", 1 }, + { ".dynamic", 1}, + { ".sdata", 1 }, + { ".IA_64.pltoff", 1 }, + { ".sbss", 1 }, + { ".bss", 1 }, + { ".AIX.pfdesc", 1 } + }; + int i; + + for (i = 0; i < sizeof (okay) / sizeof (okay[0]); i++) + { + if (strcmp (name, okay[i].name) == 0) + return idx == okay[i].idx; + } + + warning ("solib-aix5.c: Ignoring section %s when relocating the executable\n", + name); + return 0; +} + #define SECTMAPMASK (~ (CORE_ADDR) 0x03ffffff) static void @@ -579,7 +701,7 @@ aix5_relocate_main_executable (void) struct cleanup *old_chain = make_cleanup (null_cleanup, 0); /* Fetch the mappings for the main executable from the map file. */ - so = build_so_list_from_mapfile (PIDGET (inferior_pid), + so = build_so_list_from_mapfile (PIDGET (inferior_ptid), MA_MAINEXEC, MA_MAINEXEC); /* Make sure we actually have some mappings to work with. */ @@ -592,38 +714,40 @@ aix5_relocate_main_executable (void) /* Allocate the data structure which'll contain the new offsets to relocate by. Initialize it so it contains the current offsets. */ - new_offsets = xcalloc (sizeof (struct section_offsets), - symfile_objfile->num_sections); - make_cleanup (free, new_offsets); + new_offsets = xcalloc (symfile_objfile->num_sections, + sizeof (struct section_offsets)); + make_cleanup (xfree, new_offsets); for (i = 0; i < symfile_objfile->num_sections; i++) - ANOFFSET (new_offsets, i) = ANOFFSET (symfile_objfile->section_offsets, i); + new_offsets->offsets[i] = ANOFFSET (symfile_objfile->section_offsets, i); /* Iterate over the mappings in the main executable and compute the new offset value as appropriate. */ - for (i = 0; i < MT_LAST; i++) + for (i = 0; i < so->lm_info->nmappings; i++) { CORE_ADDR increment = 0; struct obj_section *sect; bfd *obfd = symfile_objfile->obfd; + struct lm_mapping *mapping = &so->lm_info->mapping[i]; ALL_OBJFILE_OSECTIONS (symfile_objfile, sect) { int flags = bfd_get_section_flags (obfd, sect->the_bfd_section); if (flags & SEC_ALLOC) { - if (((so->lm_info->mapping[i].flags & MA_WRITE) == 0) - == ((flags & SEC_READONLY) != 0)) + file_ptr filepos = sect->the_bfd_section->filepos; + if (map_index_vs_section_name_okay (i, + bfd_get_section_name (obfd, sect->the_bfd_section))) { int idx = sect->the_bfd_section->index; if (increment == 0) - increment = so->lm_info->mapping[i].addr + increment = mapping->addr - (bfd_section_vma (obfd, sect->the_bfd_section) & SECTMAPMASK); if (increment != ANOFFSET (new_offsets, idx)) { - ANOFFSET (new_offsets, idx) = increment; + new_offsets->offsets[idx] = increment; changed = 1; } } @@ -687,10 +811,10 @@ aix5_clear_solib (void) static void aix5_free_so (struct so_list *so) { - free (so->lm_info->mapname); - free (so->lm_info->pathname); - free (so->lm_info->membername); - free (so->lm_info); + xfree (so->lm_info->mapname); + xfree (so->lm_info->pathname); + xfree (so->lm_info->membername); + xfree (so->lm_info); } static void @@ -698,11 +822,27 @@ aix5_relocate_section_addresses (struct so_list *so, struct section_table *sec) { int flags = bfd_get_section_flags (sec->bfd, sec->the_bfd_section); + file_ptr filepos = sec->the_bfd_section->filepos; if (flags & SEC_ALLOC) { - int idx = (flags & SEC_READONLY) ? MT_READONLY : MT_READWRITE; - CORE_ADDR addr = so->lm_info->mapping[idx].addr; + int idx; + CORE_ADDR addr; + + for (idx = 0; idx < so->lm_info->nmappings; idx++) + { + struct lm_mapping *mapping = &so->lm_info->mapping[idx]; + if (mapping->offset <= filepos + && filepos <= mapping->offset + mapping->size) + break; + } + + if (idx >= so->lm_info->nmappings) + internal_error (__FILE__, __LINE__, + "aix_relocate_section_addresses: Can't find mapping for section %s", + bfd_get_section_name (sec->bfd, sec->the_bfd_section)); + + addr = so->lm_info->mapping[idx].addr; sec->addr += addr; sec->endaddr += addr; @@ -718,15 +858,31 @@ aix5_find_global_pointer (CORE_ADDR addr) CORE_ADDR global_pointer = 0; struct cleanup *old_chain = make_cleanup (null_cleanup, 0); - sos = build_so_list_from_mapfile (PIDGET (inferior_pid), 0, 0); + sos = build_so_list_from_mapfile (PIDGET (inferior_ptid), 0, 0); for (so = sos; so != NULL; so = so->next) { - if (so->lm_info->mapping[MT_READONLY].addr <= addr - && addr <= so->lm_info->mapping[MT_READONLY].addr - + so->lm_info->mapping[MT_READONLY].size) + int idx; + for (idx = 0; idx < so->lm_info->nmappings; idx++) + if (so->lm_info->mapping[idx].addr <= addr + && addr <= so->lm_info->mapping[idx].addr + + so->lm_info->mapping[idx].size) + { + break; + } + + if (idx < so->lm_info->nmappings) { - global_pointer = so->lm_info->mapping[MT_READWRITE].gp; + /* Look for a non-zero global pointer in the current set of + mappings. */ + for (idx = 0; idx < so->lm_info->nmappings; idx++) + if (so->lm_info->mapping[idx].gp != 0) + { + global_pointer = so->lm_info->mapping[idx].gp; + break; + } + /* Get out regardless of whether we found one or not. Mappings + don't overlap, so it would be pointless to continue. */ break; } } @@ -746,7 +902,7 @@ aix5_find_gate_addresses (CORE_ADDR *start, CORE_ADDR *end) struct cleanup *old_chain = make_cleanup (null_cleanup, 0); /* Fetch the mappings for the main executable from the map file. */ - so = build_so_list_from_mapfile (PIDGET (inferior_pid), + so = build_so_list_from_mapfile (PIDGET (inferior_ptid), MA_KERNTEXT, MA_KERNTEXT); /* Make sure we actually have some mappings to work with. */ @@ -763,8 +919,8 @@ aix5_find_gate_addresses (CORE_ADDR *start, CORE_ADDR *end) it'll be in the read-only (even though it's execute-only) mapping in the lm_info struct. */ - *start = so->lm_info->mapping[MT_READONLY].addr; - *end = *start + so->lm_info->mapping[MT_READONLY].size; + *start = so->lm_info->mapping[0].addr; + *end = *start + so->lm_info->mapping[0].size; /* Free up all the space we've allocated. */ do_cleanups (old_chain); @@ -792,6 +948,7 @@ _initialize_aix5_solib (void) aix5_so_ops.special_symbol_handling = aix5_special_symbol_handling; aix5_so_ops.current_sos = aix5_current_sos; aix5_so_ops.open_symbol_file_object = open_symbol_file_object; + aix5_so_ops.in_dynsym_resolve_code = aix5_in_dynsym_resolve_code; native_find_global_pointer = aix5_find_global_pointer; aix5_find_gate_addresses_hook = aix5_find_gate_addresses; @@ -799,4 +956,3 @@ _initialize_aix5_solib (void) /* FIXME: Don't do this here. *_gdbarch_init() should set so_ops. */ current_target_so_ops = &aix5_so_ops; } -