/* Handle FR-V (FDPIC) shared libraries for GDB, the GNU Debugger.
- Copyright (C) 2004
- Free Software Foundation, Inc.
+ Copyright (C) 2004, 2007, 2008, 2009, 2010 Free Software Foundation, Inc.
This file is part of GDB.
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
- the Free Software Foundation; either version 2 of the License, or
+ the Free Software Foundation; either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
- along with this program; if not, write to the Free Software
- Foundation, Inc., 51 Franklin Street, Fifth Floor,
- Boston, MA 02110-1301, USA. */
+ along with this program. If not, see <http://www.gnu.org/licenses/>. */
#include "defs.h"
#include "gdb_string.h"
#include "inferior.h"
#include "gdbcore.h"
+#include "solib.h"
#include "solist.h"
#include "frv-tdep.h"
#include "objfiles.h"
#include "command.h"
#include "gdbcmd.h"
#include "elf/frv.h"
+#include "exceptions.h"
/* Flag which indicates whether internal debug messages should be printed. */
static int solib_frv_debug;
static struct int_elf32_fdpic_loadmap *
fetch_loadmap (CORE_ADDR ldmaddr)
{
+ enum bfd_endian byte_order = gdbarch_byte_order (target_gdbarch);
struct ext_elf32_fdpic_loadmap ext_ldmbuf_partial;
struct ext_elf32_fdpic_loadmap *ext_ldmbuf;
struct int_elf32_fdpic_loadmap *int_ldmbuf;
/* Extract the version. */
version = extract_unsigned_integer (ext_ldmbuf_partial.version,
- sizeof ext_ldmbuf_partial.version);
+ sizeof ext_ldmbuf_partial.version,
+ byte_order);
if (version != 0)
{
/* We only handle version 0. */
/* Extract the number of segments. */
nsegs = extract_unsigned_integer (ext_ldmbuf_partial.nsegs,
- sizeof ext_ldmbuf_partial.nsegs);
+ sizeof ext_ldmbuf_partial.nsegs,
+ byte_order);
+
+ if (nsegs <= 0)
+ return NULL;
/* Allocate space for the complete (external) loadmap. */
ext_ldmbuf_size = sizeof (struct ext_elf32_fdpic_loadmap)
{
int_ldmbuf->segs[seg].addr
= extract_unsigned_integer (ext_ldmbuf->segs[seg].addr,
- sizeof (ext_ldmbuf->segs[seg].addr));
+ sizeof (ext_ldmbuf->segs[seg].addr),
+ byte_order);
int_ldmbuf->segs[seg].p_vaddr
= extract_unsigned_integer (ext_ldmbuf->segs[seg].p_vaddr,
- sizeof (ext_ldmbuf->segs[seg].p_vaddr));
+ sizeof (ext_ldmbuf->segs[seg].p_vaddr),
+ byte_order);
int_ldmbuf->segs[seg].p_memsz
= extract_unsigned_integer (ext_ldmbuf->segs[seg].p_memsz,
- sizeof (ext_ldmbuf->segs[seg].p_memsz));
+ sizeof (ext_ldmbuf->segs[seg].p_memsz),
+ byte_order);
}
xfree (ext_ldmbuf);
static CORE_ADDR
lm_base (void)
{
+ enum bfd_endian byte_order = gdbarch_byte_order (target_gdbarch);
struct minimal_symbol *got_sym;
CORE_ADDR addr;
gdb_byte buf[FRV_PTR_SIZE];
+ /* One of our assumptions is that the main executable has been relocated.
+ Bail out if this has not happened. (Note that post_create_inferior()
+ in infcmd.c will call solib_add prior to solib_create_inferior_hook().
+ If we allow this to happen, lm_base_cache will be initialized with
+ a bogus value. */
+ if (main_executable_lm_info == 0)
+ return 0;
+
/* If we already have a cached value, return it. */
if (lm_base_cache)
return lm_base_cache;
if (target_read_memory (addr, buf, sizeof buf) != 0)
return 0;
- lm_base_cache = extract_unsigned_integer (buf, sizeof buf);
+ lm_base_cache = extract_unsigned_integer (buf, sizeof buf, byte_order);
if (solib_frv_debug)
fprintf_unfiltered (gdb_stdlog,
static struct so_list *
frv_current_sos (void)
{
+ enum bfd_endian byte_order = gdbarch_byte_order (target_gdbarch);
CORE_ADDR lm_addr, mgot;
struct so_list *sos_head = NULL;
struct so_list **sos_next_ptr = &sos_head;
+ /* Make sure that the main executable has been relocated. This is
+ required in order to find the address of the global offset table,
+ which in turn is used to find the link map info. (See lm_base()
+ for details.)
+
+ Note that the relocation of the main executable is also performed
+ by SOLIB_CREATE_INFERIOR_HOOK(), however, in the case of core
+ files, this hook is called too late in order to be of benefit to
+ SOLIB_ADD. SOLIB_ADD eventually calls this this function,
+ frv_current_sos, and also precedes the call to
+ SOLIB_CREATE_INFERIOR_HOOK(). (See post_create_inferior() in
+ infcmd.c.) */
+ if (main_executable_lm_info == 0 && core_bfd != NULL)
+ frv_relocate_main_executable ();
+
+ /* Fetch the GOT corresponding to the main executable. */
mgot = main_got ();
/* Locate the address of the first link map struct. */
got_addr
= extract_unsigned_integer (lm_buf.l_addr.got_value,
- sizeof (lm_buf.l_addr.got_value));
+ sizeof (lm_buf.l_addr.got_value),
+ byte_order);
/* If the got_addr is the same as mgotr, then we're looking at the
entry for the main executable. By convention, we don't include
this in the list of shared objects. */
/* Fetch the load map address. */
addr = extract_unsigned_integer (lm_buf.l_addr.map,
- sizeof lm_buf.l_addr.map);
+ sizeof lm_buf.l_addr.map,
+ byte_order);
loadmap = fetch_loadmap (addr);
if (loadmap == NULL)
{
sop->lm_info->lm_addr = lm_addr;
/* Fetch the name. */
addr = extract_unsigned_integer (lm_buf.l_name,
- sizeof (lm_buf.l_name));
+ sizeof (lm_buf.l_name),
+ byte_order);
target_read_string (addr, &name_buf, SO_NAME_MAX_PATH_SIZE - 1,
&errcode);
main_lm_addr = lm_addr;
}
- lm_addr = extract_unsigned_integer (lm_buf.l_next, sizeof (lm_buf.l_next));
+ lm_addr = extract_unsigned_integer (lm_buf.l_next,
+ sizeof (lm_buf.l_next), byte_order);
}
enable_break2 ();
/* Given a loadmap and an address, return the displacement needed
to relocate the address. */
-CORE_ADDR
+static CORE_ADDR
displacement_from_map (struct int_elf32_fdpic_loadmap *map,
CORE_ADDR addr)
{
*/
-static int enable_break1_done = 0;
static int enable_break2_done = 0;
static int
enable_break2 (void)
{
+ enum bfd_endian byte_order = gdbarch_byte_order (target_gdbarch);
int success = 0;
char **bkpt_namep;
asection *interp_sect;
- if (!enable_break1_done || enable_break2_done)
+ if (enable_break2_done)
return 1;
- enable_break2_done = 1;
-
- /* First, remove all the solib event breakpoints. Their addresses
- may have changed since the last time we ran the program. */
- remove_solib_event_breakpoints ();
-
interp_text_sect_low = interp_text_sect_high = 0;
interp_plt_sect_low = interp_plt_sect_high = 0;
unsigned int interp_sect_size;
gdb_byte *buf;
bfd *tmp_bfd = NULL;
- int tmp_fd = -1;
- char *tmp_pathname = NULL;
int status;
CORE_ADDR addr, interp_loadmap_addr;
gdb_byte addr_buf[FRV_PTR_SIZE];
struct int_elf32_fdpic_loadmap *ldm;
+ volatile struct gdb_exception ex;
/* Read the contents of the .interp section into a local buffer;
the contents specify the dynamic linker this program uses. */
be trivial on GNU/Linux). Therefore, we have to try an alternate
mechanism to find the dynamic linker's base address. */
- tmp_fd = solib_open (buf, &tmp_pathname);
- if (tmp_fd >= 0)
- tmp_bfd = bfd_fopen (tmp_pathname, gnutarget, FOPEN_RB, tmp_fd);
-
+ TRY_CATCH (ex, RETURN_MASK_ALL)
+ {
+ tmp_bfd = solib_bfd_open (buf);
+ }
if (tmp_bfd == NULL)
{
enable_break_failure_warning ();
return 0;
}
- /* Make sure the dynamic linker is really a useful object. */
- if (!bfd_check_format (tmp_bfd, bfd_object))
- {
- warning (_("Unable to grok dynamic linker %s as an object file"), buf);
- enable_break_failure_warning ();
- bfd_close (tmp_bfd);
- return 0;
- }
-
- status = frv_fdpic_loadmap_addresses (current_gdbarch,
+ status = frv_fdpic_loadmap_addresses (target_gdbarch,
&interp_loadmap_addr, 0);
if (status < 0)
{
warning (_("Unable to fetch contents of _dl_debug_addr (at address %s) from dynamic linker"),
hex_string_custom (addr, 8));
}
- addr = extract_unsigned_integer (addr_buf, sizeof addr_buf);
+ addr = extract_unsigned_integer (addr_buf, sizeof addr_buf, byte_order);
+
+ if (solib_frv_debug)
+ fprintf_unfiltered (gdb_stdlog,
+ "enable_break: _dl_debug_addr[0..3] = %s\n",
+ hex_string_custom (addr, 8));
+
+ /* If it's zero, then the ldso hasn't initialized yet, and so
+ there are no shared libs yet loaded. */
+ if (addr == 0)
+ {
+ if (solib_frv_debug)
+ fprintf_unfiltered (gdb_stdlog,
+ "enable_break: ldso not yet initialized\n");
+ /* Do not warn, but mark to run again. */
+ return 0;
+ }
/* Fetch the r_brk field. It's 8 bytes from the start of
_dl_debug_addr. */
bfd_close (tmp_bfd);
return 0;
}
- addr = extract_unsigned_integer (addr_buf, sizeof addr_buf);
+ addr = extract_unsigned_integer (addr_buf, sizeof addr_buf, byte_order);
/* Now fetch the function entry point. */
if (target_read_memory (addr, addr_buf, sizeof addr_buf) != 0)
bfd_close (tmp_bfd);
return 0;
}
- addr = extract_unsigned_integer (addr_buf, sizeof addr_buf);
+ addr = extract_unsigned_integer (addr_buf, sizeof addr_buf, byte_order);
/* We're done with the temporary bfd. */
bfd_close (tmp_bfd);
/* We're also done with the loadmap. */
xfree (ldm);
+ /* Remove all the solib event breakpoints. Their addresses
+ may have changed since the last time we ran the program. */
+ remove_solib_event_breakpoints ();
+
/* Now (finally!) create the solib breakpoint. */
- create_solib_event_breakpoint (addr);
+ create_solib_event_breakpoint (target_gdbarch, addr);
+
+ enable_break2_done = 1;
return 1;
}
{
asection *interp_sect;
- /* Remove all the solib event breakpoints. Their addresses
- may have changed since the last time we ran the program. */
- remove_solib_event_breakpoints ();
+ if (symfile_objfile == NULL)
+ {
+ if (solib_frv_debug)
+ fprintf_unfiltered (gdb_stdlog,
+ "enable_break: No symbol file found.\n");
+ return 0;
+ }
+
+ if (!symfile_objfile->ei.entry_point_p)
+ {
+ if (solib_frv_debug)
+ fprintf_unfiltered (gdb_stdlog,
+ "enable_break: Symbol file has no entry point.\n");
+ return 0;
+ }
/* Check for the presence of a .interp section. If there is no
such section, the executable is statically linked. */
interp_sect = bfd_get_section_by_name (exec_bfd, ".interp");
- if (interp_sect)
- {
- enable_break1_done = 1;
- create_solib_event_breakpoint (symfile_objfile->ei.entry_point);
-
- if (solib_frv_debug)
- fprintf_unfiltered (gdb_stdlog,
- "enable_break: solib event breakpoint placed at entry point: %s\n",
- hex_string_custom
- (symfile_objfile->ei.entry_point, 8));
- }
- else
+ if (interp_sect == NULL)
{
if (solib_frv_debug)
fprintf_unfiltered (gdb_stdlog,
- "enable_break: No .interp section found.\n");
+ "enable_break: No .interp section found.\n");
+ return 0;
}
+ create_solib_event_breakpoint (target_gdbarch,
+ symfile_objfile->ei.entry_point);
+
+ if (solib_frv_debug)
+ fprintf_unfiltered (gdb_stdlog,
+ "enable_break: solib event breakpoint placed at entry point: %s\n",
+ hex_string_custom (symfile_objfile->ei.entry_point, 8));
return 1;
}
frv_relocate_main_executable (void)
{
int status;
- CORE_ADDR exec_addr;
+ CORE_ADDR exec_addr, interp_addr;
struct int_elf32_fdpic_loadmap *ldm;
struct cleanup *old_chain;
struct section_offsets *new_offsets;
int changed;
struct obj_section *osect;
- status = frv_fdpic_loadmap_addresses (current_gdbarch, 0, &exec_addr);
+ status = frv_fdpic_loadmap_addresses (target_gdbarch,
+ &interp_addr, &exec_addr);
- if (status < 0)
+ if (status < 0 || (exec_addr == 0 && interp_addr == 0))
{
/* Not using FDPIC ABI, so do nothing. */
return;
osect_idx = osect->the_bfd_section->index;
/* Current address of section. */
- addr = osect->addr;
+ addr = obj_section_addr (osect);
/* Offset from where this section started. */
offset = ANOFFSET (symfile_objfile->section_offsets, osect_idx);
/* Original address prior to any past relocations. */
*/
static void
-frv_solib_create_inferior_hook (void)
+frv_solib_create_inferior_hook (int from_tty)
{
/* Relocate main executable. */
frv_relocate_main_executable ();
frv_clear_solib (void)
{
lm_base_cache = 0;
- enable_break1_done = 0;
enable_break2_done = 0;
main_lm_addr = 0;
+ if (main_executable_lm_info != 0)
+ {
+ xfree (main_executable_lm_info->map);
+ xfree (main_executable_lm_info->dyn_syms);
+ xfree (main_executable_lm_info->dyn_relocs);
+ xfree (main_executable_lm_info);
+ main_executable_lm_info = 0;
+ }
}
static void
static void
frv_relocate_section_addresses (struct so_list *so,
- struct section_table *sec)
+ struct target_section *sec)
{
int seg;
struct int_elf32_fdpic_loadmap *map;
&& sec->addr < map->segs[seg].p_vaddr + map->segs[seg].p_memsz)
{
CORE_ADDR displ = map->segs[seg].addr - map->segs[seg].p_vaddr;
+
sec->addr += displ;
sec->endaddr += displ;
break;
(CORE_ADDR entry_point, CORE_ADDR got_value, char *name, bfd *abfd,
struct lm_info *lm)
{
+ enum bfd_endian byte_order = gdbarch_byte_order (target_gdbarch);
arelent *rel;
unsigned int i;
CORE_ADDR addr = 0;
/* Fetch address of candidate descriptor. */
if (target_read_memory (addr, buf, sizeof buf) != 0)
continue;
- addr = extract_unsigned_integer (buf, sizeof buf);
+ addr = extract_unsigned_integer (buf, sizeof buf, byte_order);
/* Check for matching entry point. */
if (target_read_memory (addr, buf, sizeof buf) != 0)
continue;
- if (extract_unsigned_integer (buf, sizeof buf) != entry_point)
+ if (extract_unsigned_integer (buf, sizeof buf, byte_order)
+ != entry_point)
continue;
/* Check for matching got value. */
if (target_read_memory (addr + 4, buf, sizeof buf) != 0)
continue;
- if (extract_unsigned_integer (buf, sizeof buf) != got_value)
+ if (extract_unsigned_integer (buf, sizeof buf, byte_order)
+ != got_value)
continue;
/* Match was successful! Exit loop. */
return 0;
}
-static struct target_so_ops frv_so_ops;
+struct target_so_ops frv_so_ops;
+
+/* Provide a prototype to silence -Wmissing-prototypes. */
+extern initialize_file_ftype _initialize_frv_solib;
void
_initialize_frv_solib (void)
frv_so_ops.current_sos = frv_current_sos;
frv_so_ops.open_symbol_file_object = open_symbol_file_object;
frv_so_ops.in_dynsym_resolve_code = frv_in_dynsym_resolve_code;
-
- /* FIXME: Don't do this here. *_gdbarch_init() should set so_ops. */
- current_target_so_ops = &frv_so_ops;
+ frv_so_ops.bfd_open = solib_bfd_open;
/* Debug this file's internals. */
add_setshow_zinteger_cmd ("solib-frv", class_maintenance,