/* Handle FR-V (FDPIC) shared libraries for GDB, the GNU Debugger.
- Copyright (C) 2004, 2007, 2008 Free Software Foundation, Inc.
+ Copyright (C) 2004, 2007, 2008, 2009, 2010 Free Software Foundation, Inc.
This file is part of GDB.
#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];
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;
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 (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)
+ if (interp_sect == NULL)
{
- 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 (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 (target_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;
*/
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)
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. */
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;
+ frv_so_ops.bfd_open = solib_bfd_open;
/* Debug this file's internals. */
add_setshow_zinteger_cmd ("solib-frv", class_maintenance,