This is the mail archive of the gdb-patches@sourceware.org mailing list for the GDB project.


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]
Other format: [Raw text]

Re: [RFA 3/8] New port: TI C6x: shared library for dsbt


On 07/21/2011 01:36 AM, Pedro Alves wrote:
> On Wednesday 20 July 2011 03:07:05, Yao Qi wrote:
>> +      error (_("Error reading DSBT exec loadmap\n"));
>> +      exec_loadmap = NULL;
>> +      return;
> 
> Code after error is unreacheable.  More instances of this.
> 

Fixed here and other places.

>> +  LOCAL FUNCTION
>> +
>> +  open_symbol_file_object
>> +
>> +  SYNOPSIS
>> +
>> +  void open_symbol_file_object (void *from_tty)
> 
> Any reason to this style (bfd's?) of function comments here?  The
> GNU coding standards says:
> 
> "There is usually no purpose in restating the name of the function in the
> comment before it, because the reader can see that for himself. "

Because I followed the style in other solib-*.c files.  I agree with
you.  These stuffs are removed.

> 
>> +static CORE_ADDR interp_text_sect_low;
>> +static CORE_ADDR interp_text_sect_high;
>> +static CORE_ADDR interp_plt_sect_low;
>> +static CORE_ADDR interp_plt_sect_high;
> 
> It'd be nice if globals were moved to a per-pspace
> structure, like solib-svr4.c, for multi-process.
> 

They are moved to per-pspace structure, along with other globals in this
file.

>> +   function may be freed via a single call to xfree().  */
> 
> GNU's coding standards say:
> 
> "Please do not write â()â after a function name just to indicate it is a
> function. foo () is not a function, it is a function call with no arguments."
> 
> (several instances of this)
> 

This sentence of GNU coding standard is about manuals
(http://www.gnu.org/prep/standards/html_node/GNU-Manuals.html), and in
that context, "manual" means Texinfo file.  It is unclear that this rule
applies to comment, but I removed all "()" in comments.

>> +  if (0 >= target_read_alloc (&current_target, TARGET_OBJECT_FDPIC,
>> +                             "exec", (gdb_byte**)&buf))
> 
> Problem with the patch split?  TARGET_OBJECT_FDPIC isn't defined in
> this patch or any of the previous ones.
> 

TARGET_OBJECT_FDPIC is defined in [RFA 4/8] New port: TI C6x: Read
loadmap from gdbserver.  The order of patch 3/8 and patch 4/8 should be
inverted.

-- 
Yao (éå)
2011-07-19  Andrew Jenner  <andrew@codesourcery.com>
	    Bernd Schmidt  <bernds@codesourcery.com>
	    Yao Qi  <yao@codesourcery.com>

	gdb/
	*solib-dsbt.c: New file.  Support DSBT shared object.
---
 gdb/solib-dsbt.c | 1251 ++++++++++++++++++++++++++++++++++++++++++++++++++++++
 1 files changed, 1251 insertions(+), 0 deletions(-)
 create mode 100644 gdb/solib-dsbt.c

diff --git a/gdb/solib-dsbt.c b/gdb/solib-dsbt.c
new file mode 100644
index 0000000..8aaea1a
--- /dev/null
+++ b/gdb/solib-dsbt.c
@@ -0,0 +1,1251 @@
+/* Handle TIC6X (DSBT) shared libraries for GDB, the GNU Debugger.
+   Copyright (C) 2010, 2011 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 3 of the License, or
+   (at your option) any later version.
+
+   This program is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+   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, 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 "objfiles.h"
+#include "symtab.h"
+#include "language.h"
+#include "command.h"
+#include "gdbcmd.h"
+#include "elf-bfd.h"
+#include "exceptions.h"
+
+#define GOT_MODULE_OFFSET 4
+
+/* Flag which indicates whether internal debug messages should be printed.  */
+static int solib_dsbt_debug = 0;
+
+/* TIC6X pointers are four bytes wide.  */
+enum { TIC6X_PTR_SIZE = 4 };
+
+/* Representation of loadmap and related structs for the TIC6X DSBT.  */
+
+/* External versions; the size and alignment of the fields should be
+   the same as those on the target.  When loaded, the placement of
+   the bits in each field will be the same as on the target.  */
+typedef gdb_byte ext_Elf32_Half[2];
+typedef gdb_byte ext_Elf32_Addr[4];
+typedef gdb_byte ext_Elf32_Word[4];
+
+struct ext_elf32_dsbt_loadseg
+{
+  /* Core address to which the segment is mapped.  */
+  ext_Elf32_Addr addr;
+  /* VMA recorded in the program header.  */
+  ext_Elf32_Addr p_vaddr;
+  /* Size of this segment in memory.  */
+  ext_Elf32_Word p_memsz;
+};
+
+struct ext_elf32_dsbt_loadmap {
+  /* Protocol version number, must be zero.  */
+  ext_Elf32_Word version;
+  /* A pointer to the DSBT table; the DSBT size and the index of this
+     module.  */
+  ext_Elf32_Word dsbt_table_ptr;
+  ext_Elf32_Word dsbt_size;
+  ext_Elf32_Word dsbt_index;
+  /* Number of segments in this map.  */
+  ext_Elf32_Word nsegs;
+  /* The actual memory map.  */
+  struct ext_elf32_dsbt_loadseg segs[1 /* nsegs, actually */];
+};
+
+/* Internal versions; the types are GDB types and the data in each
+   of the fields is (or will be) decoded from the external struct
+   for ease of consumption.  */
+struct int_elf32_dsbt_loadseg
+{
+  /* Core address to which the segment is mapped.  */
+  CORE_ADDR addr;
+  /* VMA recorded in the program header.  */
+  CORE_ADDR p_vaddr;
+  /* Size of this segment in memory.  */
+  long p_memsz;
+};
+
+struct int_elf32_dsbt_loadmap
+{
+  /* Protocol version number, must be zero.  */
+  int version;
+  CORE_ADDR dsbt_table_ptr;
+  /* A pointer to the DSBT table; the DSBT size and the index of this
+     module.  */
+  int dsbt_size, dsbt_index;
+  /* Number of segments in this map.  */
+  int nsegs;
+  /* The actual memory map.  */
+  struct int_elf32_dsbt_loadseg segs[1 /* nsegs, actually */];
+};
+
+/* External link_map and elf32_dsbt_loadaddr struct definitions.  */
+
+typedef gdb_byte ext_ptr[4];
+
+struct ext_elf32_dsbt_loadaddr
+{
+  ext_ptr map;			/* struct elf32_dsbt_loadmap *map; */
+};
+
+struct ext_link_map
+{
+  struct ext_elf32_dsbt_loadaddr l_addr;
+
+  /* Absolute file name object was found in.  */
+  ext_ptr l_name;		/* char *l_name; */
+
+  /* Dynamic section of the shared object.  */
+  ext_ptr l_ld;			/* ElfW(Dyn) *l_ld; */
+
+  /* Chain of loaded objects.  */
+  ext_ptr l_next, l_prev;	/* struct link_map *l_next, *l_prev; */
+};
+
+/* Link map info to include in an allocated so_list entry */
+
+struct lm_info
+{
+  /* The loadmap, digested into an easier to use form.  */
+  struct int_elf32_dsbt_loadmap *map;
+};
+
+/* Per pspace dsbt specific data.  */
+
+struct dsbt_info
+{
+  /* The load map, got value, etc. are not available from the chain
+     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;
+
+/* Load maps for the main executable and the interpreter.
+   These are obtained from ptrace.  They are the starting point for getting
+   into the program, and are required to find the solib list with the
+   individual load maps for each module.  */
+  struct int_elf32_dsbt_loadmap *exec_loadmap;
+  struct int_elf32_dsbt_loadmap *interp_loadmap;
+
+  /* Cached value for lm_base, below.  */
+  CORE_ADDR lm_base_cache;
+
+  /* Link map address for main module.  */
+  CORE_ADDR main_lm_addr;
+
+  int enable_break2_done;
+
+  CORE_ADDR interp_text_sect_low;
+  CORE_ADDR interp_text_sect_high;
+  CORE_ADDR interp_plt_sect_low;
+  CORE_ADDR interp_plt_sect_high;
+};
+
+/* Per-program-space data key.  */
+static const struct program_space_data *solib_dsbt_pspace_data;
+
+static void
+dsbt_pspace_data_cleanup (struct program_space *pspace, void *arg)
+{
+  struct dsbt_info *info;
+
+  info = program_space_data (pspace, solib_dsbt_pspace_data);
+  xfree (info);
+}
+
+/* Get the current dsbt data.  If none is found yet, add it now.  This
+   function always returns a valid object.  */
+
+static struct dsbt_info *
+get_dsbt_info (void)
+{
+  struct dsbt_info *info;
+
+  info = program_space_data (current_program_space, solib_dsbt_pspace_data);
+  if (info != NULL)
+    return info;
+
+  info = XZALLOC (struct dsbt_info);
+  set_program_space_data (current_program_space, solib_dsbt_pspace_data, info);
+
+  info->enable_break2_done = 0;
+  info->lm_base_cache = 0;
+  info->main_lm_addr = 0;
+
+  return info;
+}
+
+
+static void
+dsbt_print_loadmap (struct int_elf32_dsbt_loadmap *map)
+{
+  int i;
+
+  if (map == NULL)
+    printf_filtered ("(null)\n");
+  else if (map->version != 0)
+    printf_filtered (_("Unsupported map version: %d\n"), map->version);
+  else
+    {
+      printf_filtered ("version %d\n", map->version);
+
+      for (i = 0; i < map->nsegs; i++)
+	printf_filtered ("0x%08x:0x%08x -> 0x%08x:0x%08x\n",
+			 (int)map->segs[i].p_vaddr,
+			 (int)(map->segs[i].p_vaddr + map->segs[i].p_memsz),
+			 (int)map->segs[i].addr,
+			 (int)(map->segs[i].addr + map->segs[i].p_memsz));
+    }
+}
+
+/* Decode int_elf32_dsbt_loadmap from BUF.  */
+
+static struct int_elf32_dsbt_loadmap *
+decode_loadmap (gdb_byte *buf)
+{
+  enum bfd_endian byte_order = gdbarch_byte_order (target_gdbarch);
+  struct ext_elf32_dsbt_loadmap *ext_ldmbuf;
+  struct int_elf32_dsbt_loadmap *int_ldmbuf;
+
+  int version, seg, nsegs;
+  int ext_ldmbuf_size, int_ldmbuf_size;
+
+  ext_ldmbuf = (struct ext_elf32_dsbt_loadmap *) buf;
+
+  /* Extract the version.  */
+  version = extract_unsigned_integer (ext_ldmbuf->version,
+				      sizeof ext_ldmbuf->version,
+				      byte_order);
+  if (version != 0)
+    {
+      /* We only handle version 0.  */
+      return NULL;
+    }
+
+  /* Extract the number of segments.  */
+  nsegs = extract_unsigned_integer (ext_ldmbuf->nsegs,
+				    sizeof ext_ldmbuf->nsegs,
+				    byte_order);
+
+  if (nsegs <= 0)
+    return NULL;
+
+  /* Allocate space into which to put information extract from the
+     external loadsegs.  I.e, allocate the internal loadsegs.  */
+  int_ldmbuf_size = sizeof (struct int_elf32_dsbt_loadmap)
+    + (nsegs - 1) * sizeof (struct int_elf32_dsbt_loadseg);
+  int_ldmbuf = xmalloc (int_ldmbuf_size);
+
+  /* Place extracted information in internal structs.  */
+  int_ldmbuf->version = version;
+  int_ldmbuf->nsegs = nsegs;
+  for (seg = 0; seg < nsegs; seg++)
+    {
+      int_ldmbuf->segs[seg].addr
+	= extract_unsigned_integer (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),
+				    byte_order);
+      int_ldmbuf->segs[seg].p_memsz
+	= extract_unsigned_integer (ext_ldmbuf->segs[seg].p_memsz,
+				    sizeof (ext_ldmbuf->segs[seg].p_memsz),
+				    byte_order);
+    }
+
+  xfree (ext_ldmbuf);
+  return int_ldmbuf;
+}
+
+
+static struct dsbt_info *get_dsbt_info (void);
+
+/* Interrogate the Linux kernel to find out where the program was loaded.
+   There are two load maps; one for the executable and one for the
+   interpreter (only in the case of a dynamically linked executable).  */
+
+static void
+dsbt_get_initial_loadmaps (void)
+{
+  gdb_byte *buf;
+  struct dsbt_info *info = get_dsbt_info ();
+
+  if (0 >= target_read_alloc (&current_target, TARGET_OBJECT_FDPIC,
+			      "exec", (gdb_byte**)&buf))
+    {
+      info->exec_loadmap = NULL;
+      error (_("Error reading DSBT exec loadmap\n"));
+    }
+  info->exec_loadmap = decode_loadmap (buf);
+  if (solib_dsbt_debug)
+    dsbt_print_loadmap (info->exec_loadmap);
+
+  if (0 >= target_read_alloc (&current_target, TARGET_OBJECT_FDPIC,
+			      "interp", (gdb_byte**)&buf))
+    {
+      info->interp_loadmap = NULL;
+      error (_("Error reading DSBT interp loadmap\n"));
+    }
+  info->interp_loadmap = decode_loadmap (buf);
+  if (solib_dsbt_debug)
+    dsbt_print_loadmap (info->interp_loadmap);
+}
+
+/* Given address LDMADDR, fetch and decode the loadmap at that address.
+   Return NULL if there is a problem reading the target memory or if
+   there doesn't appear to be a loadmap at the given address.  The
+   allocated space (representing the loadmap) returned by this
+   function may be freed via a single call to xfree.  */
+
+static struct int_elf32_dsbt_loadmap *
+fetch_loadmap (CORE_ADDR ldmaddr)
+{
+  enum bfd_endian byte_order = gdbarch_byte_order (target_gdbarch);
+  struct ext_elf32_dsbt_loadmap ext_ldmbuf_partial;
+  struct ext_elf32_dsbt_loadmap *ext_ldmbuf;
+  struct int_elf32_dsbt_loadmap *int_ldmbuf;
+  int ext_ldmbuf_size, int_ldmbuf_size;
+  int version, seg, nsegs;
+
+  /* Fetch initial portion of the loadmap.  */
+  if (target_read_memory (ldmaddr, (gdb_byte *) &ext_ldmbuf_partial,
+                          sizeof ext_ldmbuf_partial))
+    {
+      /* Problem reading the target's memory.  */
+      return NULL;
+    }
+
+  /* Extract the version.  */
+  version = extract_unsigned_integer (ext_ldmbuf_partial.version,
+                                      sizeof ext_ldmbuf_partial.version,
+				      byte_order);
+  if (version != 0)
+    {
+      /* We only handle version 0.  */
+      return NULL;
+    }
+
+  /* Extract the number of segments.  */
+  nsegs = extract_unsigned_integer (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_dsbt_loadmap)
+    + (nsegs - 1) * sizeof (struct ext_elf32_dsbt_loadseg);
+  ext_ldmbuf = xmalloc (ext_ldmbuf_size);
+
+  /* Copy over the portion of the loadmap that's already been read.  */
+  memcpy (ext_ldmbuf, &ext_ldmbuf_partial, sizeof ext_ldmbuf_partial);
+
+  /* Read the rest of the loadmap from the target.  */
+  if (target_read_memory (ldmaddr + sizeof ext_ldmbuf_partial,
+			  (gdb_byte *) ext_ldmbuf + sizeof ext_ldmbuf_partial,
+			  ext_ldmbuf_size - sizeof ext_ldmbuf_partial))
+    {
+      /* Couldn't read rest of the loadmap.  */
+      xfree (ext_ldmbuf);
+      return NULL;
+    }
+
+  /* Allocate space into which to put information extract from the
+     external loadsegs.  I.e, allocate the internal loadsegs.  */
+  int_ldmbuf_size = sizeof (struct int_elf32_dsbt_loadmap)
+    + (nsegs - 1) * sizeof (struct int_elf32_dsbt_loadseg);
+  int_ldmbuf = xmalloc (int_ldmbuf_size);
+
+  /* Place extracted information in internal structs.  */
+  int_ldmbuf->version = version;
+  int_ldmbuf->nsegs = nsegs;
+  for (seg = 0; seg < nsegs; seg++)
+    {
+      int_ldmbuf->segs[seg].addr
+	= extract_unsigned_integer (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),
+				    byte_order);
+      int_ldmbuf->segs[seg].p_memsz
+	= extract_unsigned_integer (ext_ldmbuf->segs[seg].p_memsz,
+				    sizeof (ext_ldmbuf->segs[seg].p_memsz),
+				    byte_order);
+    }
+
+  xfree (ext_ldmbuf);
+  return int_ldmbuf;
+}
+
+static void dsbt_relocate_main_executable (void);
+static int enable_break2 (void);
+
+/* Scan for DYNTAG in .dynamic section of ABFD. If DYNTAG is found 1 is
+   returned and the corresponding PTR is set.  */
+
+static int
+scan_dyntag (int dyntag, bfd *abfd, CORE_ADDR *ptr)
+{
+  int arch_size, step, sect_size;
+  long dyn_tag;
+  CORE_ADDR dyn_ptr, dyn_addr;
+  gdb_byte *bufend, *bufstart, *buf;
+  Elf32_External_Dyn *x_dynp_32;
+  Elf64_External_Dyn *x_dynp_64;
+  struct bfd_section *sect;
+  struct target_section *target_section;
+
+  if (abfd == NULL)
+    return 0;
+
+  if (bfd_get_flavour (abfd) != bfd_target_elf_flavour)
+    return 0;
+
+  arch_size = bfd_get_arch_size (abfd);
+  if (arch_size == -1)
+    return 0;
+
+  /* Find the start address of the .dynamic section.  */
+  sect = bfd_get_section_by_name (abfd, ".dynamic");
+  if (sect == NULL)
+    return 0;
+
+  for (target_section = current_target_sections->sections;
+       target_section < current_target_sections->sections_end;
+       target_section++)
+    if (sect == target_section->the_bfd_section)
+      break;
+  if (target_section < current_target_sections->sections_end)
+    dyn_addr = target_section->addr;
+  else
+    {
+      /* ABFD may come from OBJFILE acting only as a symbol file without being
+	 loaded into the target (see add_symbol_file_command).  This case is
+	 such fallback to the file VMA address without the possibility of
+	 having the section relocated to its actual in-memory address.  */
+
+      dyn_addr = bfd_section_vma (abfd, sect);
+    }
+
+  /* Read in .dynamic from the BFD.  We will get the actual value
+     from memory later.  */
+  sect_size = bfd_section_size (abfd, sect);
+  buf = bufstart = alloca (sect_size);
+  if (!bfd_get_section_contents (abfd, sect,
+				 buf, 0, sect_size))
+    return 0;
+
+  /* Iterate over BUF and scan for DYNTAG.  If found, set PTR and return.  */
+  step = (arch_size == 32) ? sizeof (Elf32_External_Dyn)
+			   : sizeof (Elf64_External_Dyn);
+  for (bufend = buf + sect_size;
+       buf < bufend;
+       buf += step)
+  {
+    if (arch_size == 32)
+      {
+	x_dynp_32 = (Elf32_External_Dyn *) buf;
+	dyn_tag = bfd_h_get_32 (abfd, (bfd_byte *) x_dynp_32->d_tag);
+	dyn_ptr = bfd_h_get_32 (abfd, (bfd_byte *) x_dynp_32->d_un.d_ptr);
+      }
+    else
+      {
+	x_dynp_64 = (Elf64_External_Dyn *) buf;
+	dyn_tag = bfd_h_get_64 (abfd, (bfd_byte *) x_dynp_64->d_tag);
+	dyn_ptr = bfd_h_get_64 (abfd, (bfd_byte *) x_dynp_64->d_un.d_ptr);
+      }
+     if (dyn_tag == DT_NULL)
+       return 0;
+     if (dyn_tag == dyntag)
+       {
+	 /* If requested, try to read the runtime value of this .dynamic
+	    entry.  */
+	 if (ptr)
+	   {
+	     struct type *ptr_type;
+	     gdb_byte ptr_buf[8];
+	     CORE_ADDR ptr_addr;
+
+	     ptr_type = builtin_type (target_gdbarch)->builtin_data_ptr;
+	     ptr_addr = dyn_addr + (buf - bufstart) + arch_size / 8;
+	     if (target_read_memory (ptr_addr, ptr_buf, arch_size / 8) == 0)
+	       dyn_ptr = extract_typed_address (ptr_buf, ptr_type);
+	     *ptr = dyn_ptr;
+	   }
+	 return 1;
+       }
+  }
+
+  return 0;
+}
+
+/* An expensive way to lookup the value of a single symbol for
+   bfd's that are only temporary anyway.  This is used by the
+   shared library support to find the address of the debugger
+   interface structures in the shared library.
+
+   Note that 0 is specifically allowed as an error return (no
+   such symbol).  */
+
+static CORE_ADDR
+bfd_lookup_symbol (bfd *abfd, char *symname)
+{
+  long storage_needed;
+  asymbol *sym;
+  asymbol **symbol_table;
+  unsigned int number_of_symbols;
+  unsigned int i;
+  struct cleanup *back_to;
+  CORE_ADDR symaddr = 0;
+
+  storage_needed = bfd_get_symtab_upper_bound (abfd);
+
+  if (storage_needed > 0)
+    {
+      symbol_table = (asymbol **) xmalloc (storage_needed);
+      back_to = make_cleanup (xfree, symbol_table);
+      number_of_symbols = bfd_canonicalize_symtab (abfd, symbol_table);
+
+      for (i = 0; i < number_of_symbols; i++)
+	{
+	  sym = *symbol_table++;
+	  if (strcmp (sym->name, symname) == 0)
+	    {
+	      /* Bfd symbols are section relative. */
+	      symaddr = sym->value + sym->section->vma;
+	      break;
+	    }
+	}
+      do_cleanups (back_to);
+    }
+
+  if (symaddr)
+    return symaddr;
+
+  /* Look for the symbol in the dynamic string table too.  */
+
+  storage_needed = bfd_get_dynamic_symtab_upper_bound (abfd);
+
+  if (storage_needed > 0)
+    {
+      symbol_table = (asymbol **) xmalloc (storage_needed);
+      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++)
+	{
+	  sym = *symbol_table++;
+	  if (strcmp (sym->name, symname) == 0)
+	    {
+	      /* Bfd symbols are section relative. */
+	      symaddr = sym->value + sym->section->vma;
+	      break;
+	    }
+	}
+      do_cleanups (back_to);
+    }
+
+  return symaddr;
+}
+
+
+/* If no open symbol file, attempt to locate and open the main symbol
+   file.
+
+   If FROM_TTYP dereferences to a non-zero integer, allow messages to
+   be printed.  This parameter is a pointer rather than an int because
+   open_symbol_file_object is called via catch_errors and
+   catch_errors requires a pointer argument. */
+
+static int
+open_symbol_file_object (void *from_ttyp)
+{
+  /* Unimplemented.  */
+  return 0;
+}
+
+/* Given a loadmap and an address, return the displacement needed
+   to relocate the address.  */
+
+static CORE_ADDR
+displacement_from_map (struct int_elf32_dsbt_loadmap *map,
+                       CORE_ADDR addr)
+{
+  int seg;
+
+  for (seg = 0; seg < map->nsegs; seg++)
+    if (map->segs[seg].p_vaddr <= addr
+	&& addr < map->segs[seg].p_vaddr + map->segs[seg].p_memsz)
+      return map->segs[seg].addr - map->segs[seg].p_vaddr;
+
+  return 0;
+}
+
+/* Return the address from which the link map chain may be found.  On
+   DSBT, a pointer to the start of the link map will be located at the
+   word found at base of GOT + GOT_MODULE_OFFSET.
+
+   The base of GOT may be found in a number of ways.  Assuming that the
+   main executable has already been relocated,
+   1 The easiest way to find this value is to look up the address of
+   _GLOBAL_OFFSET_TABLE_.
+   2 The other way is to look for tag DT_PLTGOT, which contains the virtual
+   address of Global Offset Table.  .*/
+
+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[TIC6X_PTR_SIZE];
+  struct dsbt_info *info = get_dsbt_info ();
+
+  /* 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 (info->main_executable_lm_info == 0)
+    return 0;
+
+  /* If we already have a cached value, return it.  */
+  if (info->lm_base_cache)
+    return info->lm_base_cache;
+
+  got_sym = lookup_minimal_symbol ("_GLOBAL_OFFSET_TABLE_", NULL,
+				   symfile_objfile);
+
+  if (got_sym != 0)
+    {
+      addr = SYMBOL_VALUE_ADDRESS (got_sym);
+      if (solib_dsbt_debug)
+	fprintf_unfiltered (gdb_stdlog,
+			    "lm_base: get addr %x by _GLOBAL_OFFSET_TABLE_.\n",
+			    (unsigned int) addr);
+    }
+  else if (scan_dyntag (DT_PLTGOT, exec_bfd, &addr))
+    {
+      struct int_elf32_dsbt_loadmap *ldm;
+
+      dsbt_get_initial_loadmaps ();
+      ldm = info->exec_loadmap;
+      addr += displacement_from_map (ldm, addr);
+      if (solib_dsbt_debug)
+	fprintf_unfiltered (gdb_stdlog,
+			    "lm_base: get addr %x by DT_PLTGOT.\n",
+			    (unsigned int) addr);
+    }
+  else
+    {
+      if (solib_dsbt_debug)
+	fprintf_unfiltered (gdb_stdlog,
+			    "lm_base: _GLOBAL_OFFSET_TABLE_ not found.\n");
+      return 0;
+    }
+  addr += GOT_MODULE_OFFSET;
+
+  if (solib_dsbt_debug)
+    fprintf_unfiltered (gdb_stdlog,
+			"lm_base: _GLOBAL_OFFSET_TABLE_ + %d = %s\n",
+			GOT_MODULE_OFFSET, hex_string_custom (addr, 8));
+
+  if (target_read_memory (addr, buf, sizeof buf) != 0)
+    return 0;
+  info->lm_base_cache = extract_unsigned_integer (buf, sizeof buf, byte_order);
+
+  if (solib_dsbt_debug)
+    fprintf_unfiltered (gdb_stdlog,
+			"lm_base: lm_base_cache = %s\n",
+			hex_string_custom (info->lm_base_cache, 8));
+
+  return info->lm_base_cache;
+}
+
+
+/* Build a list of `struct so_list' objects describing the shared
+   objects currently loaded in the inferior.  This list does not
+   include an entry for the main executable file.
+
+   Note that we only gather information directly available from the
+   inferior --- we don't examine any of the shared library files
+   themselves.  The declaration of `struct so_list' says which fields
+   we provide values for.  */
+
+static struct so_list *
+dsbt_current_sos (void)
+{
+  enum bfd_endian byte_order = gdbarch_byte_order (target_gdbarch);
+  CORE_ADDR lm_addr;
+  struct so_list *sos_head = NULL;
+  struct so_list **sos_next_ptr = &sos_head;
+  struct dsbt_info *info = get_dsbt_info ();
+
+  /* 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,
+     dsbt_current_sos, and also precedes the call to
+     SOLIB_CREATE_INFERIOR_HOOK.   (See post_create_inferior in
+     infcmd.c.)  */
+  if (info->main_executable_lm_info == 0 && core_bfd != NULL)
+    dsbt_relocate_main_executable ();
+
+  /* Locate the address of the first link map struct.  */
+  lm_addr = lm_base ();
+
+  /* We have at least one link map entry.  Fetch the the lot of them,
+     building the solist chain.  */
+  while (lm_addr)
+    {
+      struct ext_link_map lm_buf;
+      ext_Elf32_Word indexword;
+      CORE_ADDR map_addr;
+      int dsbt_index;
+      int ret;
+
+      if (solib_dsbt_debug)
+	fprintf_unfiltered (gdb_stdlog,
+			    "current_sos: reading link_map entry at %s\n",
+			    hex_string_custom (lm_addr, 8));
+
+      ret = target_read_memory (lm_addr, (gdb_byte *) &lm_buf, sizeof (lm_buf));
+      if (ret)
+	{
+	  warning (_("dsbt_current_sos: Unable to read link map entry."
+		     "  Shared object chain may be incomplete."));
+	  break;
+	}
+
+      /* Fetch the load map address.  */
+      map_addr = extract_unsigned_integer (lm_buf.l_addr.map,
+					   sizeof lm_buf.l_addr.map,
+					   byte_order);
+
+      ret = target_read_memory (map_addr + 12, (gdb_byte *) &indexword,
+				sizeof indexword);
+      if (ret)
+	{
+	  warning (_("dsbt_current_sos: Unable to read dsbt index."
+		     "  Shared object chain may be incomplete."));
+	  break;
+	}
+      dsbt_index = extract_unsigned_integer (indexword, sizeof indexword,
+					     byte_order);
+
+      /* If the DSBT index is zero, then we're looking at the entry
+	 for the main executable.  By convention, we don't include
+	 this in the list of shared objects.  */
+      if (dsbt_index != 0)
+	{
+	  int errcode;
+	  char *name_buf;
+	  struct int_elf32_dsbt_loadmap *loadmap;
+	  struct so_list *sop;
+	  CORE_ADDR addr;
+
+	  loadmap = fetch_loadmap (map_addr);
+	  if (loadmap == NULL)
+	    {
+	      warning (_("dsbt_current_sos: Unable to fetch load map."
+			 "  Shared object chain may be incomplete."));
+	      break;
+	    }
+
+	  sop = xcalloc (1, sizeof (struct so_list));
+	  sop->lm_info = xcalloc (1, sizeof (struct lm_info));
+	  sop->lm_info->map = loadmap;
+	  /* Fetch the name.  */
+	  addr = extract_unsigned_integer (lm_buf.l_name,
+					   sizeof (lm_buf.l_name),
+					   byte_order);
+	  target_read_string (addr, &name_buf, SO_NAME_MAX_PATH_SIZE - 1,
+			      &errcode);
+
+	  if (solib_dsbt_debug)
+	    fprintf_unfiltered (gdb_stdlog, "current_sos: name = %s\n",
+				name_buf);
+
+	  if (errcode != 0)
+	    warning (_("Can't read pathname for link map entry: %s."),
+		     safe_strerror (errcode));
+	  else
+	    {
+	      strncpy (sop->so_name, name_buf, SO_NAME_MAX_PATH_SIZE - 1);
+	      sop->so_name[SO_NAME_MAX_PATH_SIZE - 1] = '\0';
+	      xfree (name_buf);
+	      strcpy (sop->so_original_name, sop->so_name);
+	    }
+
+	  *sos_next_ptr = sop;
+	  sos_next_ptr = &sop->next;
+	}
+      else
+	{
+	  info->main_lm_addr = lm_addr;
+	}
+
+      lm_addr = extract_unsigned_integer (lm_buf.l_next,
+					  sizeof (lm_buf.l_next), byte_order);
+    }
+
+  enable_break2 ();
+
+  return sos_head;
+}
+
+/* Return 1 if PC lies in the dynamic symbol resolution code of the
+   run time loader.  */
+
+static int
+dsbt_in_dynsym_resolve_code (CORE_ADDR pc)
+{
+  struct dsbt_info *info = get_dsbt_info ();
+
+  return ((pc >= info->interp_text_sect_low && pc < info->interp_text_sect_high)
+	  || (pc >= info->interp_plt_sect_low && pc < info->interp_plt_sect_high)
+	  || in_plt_section (pc, NULL));
+}
+
+/* Print a warning about being unable to set the dynamic linker
+   breakpoint.  */
+
+static void
+enable_break_failure_warning (void)
+{
+  warning (_("Unable to find dynamic linker breakpoint function.\n"
+           "GDB will be unable to debug shared library initializers\n"
+	   "and track explicitly loaded dynamic code."));
+}
+
+/* The dynamic linkers has, as part of its debugger interface, support
+   for arranging for the inferior to hit a breakpoint after mapping in
+   the shared libraries.  This function enables that breakpoint.
+
+   On the TIC6X, using the shared library (DSBT), the symbol
+   _dl_debug_addr points to the r_debug struct which contains
+   a field called r_brk.  r_brk is the address of the function
+   descriptor upon which a breakpoint must be placed.  Being a
+   function descriptor, we must extract the entry point in order
+   to set the breakpoint.
+
+   Our strategy will be to get the .interp section from the
+   executable.  This section will provide us with the name of the
+   interpreter.  We'll open the interpreter and then look up
+   the address of _dl_debug_addr.  We then relocate this address
+   using the interpreter's loadmap.  Once the relocated address
+   is known, we fetch the value (address) corresponding to r_brk
+   and then use that value to fetch the entry point of the function
+   we're interested in.  */
+
+static int
+enable_break2 (void)
+{
+  enum bfd_endian byte_order = gdbarch_byte_order (target_gdbarch);
+  int success = 0;
+  char **bkpt_namep;
+  asection *interp_sect;
+  struct dsbt_info *info = get_dsbt_info ();
+
+  if (exec_bfd == NULL)
+    return 0;
+
+  if (!target_has_execution)
+    return 0;
+
+  if (info->enable_break2_done)
+    return 1;
+
+  info->interp_text_sect_low = 0;
+  info->interp_text_sect_high = 0;
+  info->interp_plt_sect_low = 0;
+  info->interp_plt_sect_high = 0;
+
+  /* Find the .interp section; if not found, warn the user and drop
+     into the old breakpoint at symbol code.  */
+  interp_sect = bfd_get_section_by_name (exec_bfd, ".interp");
+  if (interp_sect)
+    {
+      unsigned int interp_sect_size;
+      gdb_byte *buf;
+      bfd *tmp_bfd = NULL;
+      int status;
+      CORE_ADDR addr, interp_loadmap_addr;
+      gdb_byte addr_buf[TIC6X_PTR_SIZE];
+      struct int_elf32_dsbt_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.  */
+      interp_sect_size = bfd_section_size (exec_bfd, interp_sect);
+      buf = alloca (interp_sect_size);
+      bfd_get_section_contents (exec_bfd, interp_sect,
+				buf, 0, interp_sect_size);
+
+      /* Now we need to figure out where the dynamic linker was
+         loaded so that we can load its symbols and place a breakpoint
+         in the dynamic linker itself.  */
+
+      TRY_CATCH (ex, RETURN_MASK_ALL)
+        {
+          tmp_bfd = solib_bfd_open (buf);
+        }
+      if (tmp_bfd == NULL)
+	{
+	  enable_break_failure_warning ();
+	  return 0;
+	}
+
+      dsbt_get_initial_loadmaps ();
+      ldm = info->interp_loadmap;
+
+      /* Record the relocated start and end address of the dynamic linker
+         text and plt section for dsbt_in_dynsym_resolve_code.  */
+      interp_sect = bfd_get_section_by_name (tmp_bfd, ".text");
+      if (interp_sect)
+	{
+	  info->interp_text_sect_low
+	    = bfd_section_vma (tmp_bfd, interp_sect);
+	  info->interp_text_sect_low
+	    += displacement_from_map (ldm, info->interp_text_sect_low);
+	  info->interp_text_sect_high
+	    = info->interp_text_sect_low
+	    + bfd_section_size (tmp_bfd, interp_sect);
+	}
+      interp_sect = bfd_get_section_by_name (tmp_bfd, ".plt");
+      if (interp_sect)
+	{
+	  info->interp_plt_sect_low =
+	    bfd_section_vma (tmp_bfd, interp_sect);
+	  info->interp_plt_sect_low
+	    += displacement_from_map (ldm, info->interp_plt_sect_low);
+	  info->interp_plt_sect_high =
+	    info->interp_plt_sect_low + bfd_section_size (tmp_bfd, interp_sect);
+	}
+
+      addr = bfd_lookup_symbol (tmp_bfd, "_dl_debug_addr");
+      if (addr == 0)
+	{
+	  warning (_("Could not find symbol _dl_debug_addr in dynamic linker"));
+	  enable_break_failure_warning ();
+	  bfd_close (tmp_bfd);
+	  return 0;
+	}
+
+      if (solib_dsbt_debug)
+	fprintf_unfiltered (gdb_stdlog,
+	                    "enable_break: _dl_debug_addr (prior to relocation) = %s\n",
+			    hex_string_custom (addr, 8));
+
+      addr += displacement_from_map (ldm, addr);
+
+      if (solib_dsbt_debug)
+	fprintf_unfiltered (gdb_stdlog,
+	                    "enable_break: _dl_debug_addr (after relocation) = %s\n",
+			    hex_string_custom (addr, 8));
+
+      /* Fetch the address of the r_debug struct.  */
+      if (target_read_memory (addr, addr_buf, sizeof addr_buf) != 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, byte_order);
+
+      if (solib_dsbt_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_dsbt_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.  */
+      if (target_read_memory (addr + 8, addr_buf, sizeof addr_buf) != 0)
+	{
+	  warning (_("Unable to fetch _dl_debug_addr->r_brk "
+		     "(at address %s) from dynamic linker"),
+	           hex_string_custom (addr + 8, 8));
+	  enable_break_failure_warning ();
+	  bfd_close (tmp_bfd);
+	  return 0;
+	}
+      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 (target_gdbarch, addr);
+
+      info->enable_break2_done = 1;
+
+      return 1;
+    }
+
+  /* Tell the user we couldn't set a dynamic linker breakpoint.  */
+  enable_break_failure_warning ();
+
+  /* Failure return.  */
+  return 0;
+}
+
+static int
+enable_break (void)
+{
+  asection *interp_sect;
+  struct minimal_symbol *start;
+
+  /* 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 == NULL)
+    {
+      if (solib_dsbt_debug)
+	fprintf_unfiltered (gdb_stdlog,
+			    "enable_break: No .interp section found.\n");
+      return 0;
+    }
+
+  start = lookup_minimal_symbol ("_start", NULL, symfile_objfile);
+  if (start == NULL)
+    {
+      if (solib_dsbt_debug)
+	fprintf_unfiltered (gdb_stdlog,
+			    "enable_break: symbol _start is not found.\n");
+      return 0;
+    }
+
+  create_solib_event_breakpoint (target_gdbarch,
+				 SYMBOL_VALUE_ADDRESS (start));
+
+  if (solib_dsbt_debug)
+    fprintf_unfiltered (gdb_stdlog,
+			"enable_break: solib event breakpoint placed at : %s\n",
+			hex_string_custom (SYMBOL_VALUE_ADDRESS (start), 8));
+  return 1;
+}
+
+/* Once the symbols from a shared object have been loaded in the usual
+   way, we are called to do any system specific symbol handling that
+   is needed.  */
+
+static void
+dsbt_special_symbol_handling (void)
+{
+  /* Nothing needed (yet). */
+}
+
+static void
+dsbt_relocate_main_executable (void)
+{
+  int status;
+  CORE_ADDR exec_addr, interp_addr;
+  struct int_elf32_dsbt_loadmap *ldm;
+  struct cleanup *old_chain;
+  struct section_offsets *new_offsets;
+  int changed;
+  struct obj_section *osect;
+  struct dsbt_info *info = get_dsbt_info ();
+
+  dsbt_get_initial_loadmaps ();
+  ldm = info->exec_loadmap;
+
+  if (info->main_executable_lm_info)
+    xfree (info->main_executable_lm_info);
+  info->main_executable_lm_info = xcalloc (1, sizeof (struct lm_info));
+  info->main_executable_lm_info->map = ldm;
+
+  new_offsets = xcalloc (symfile_objfile->num_sections,
+			 sizeof (struct section_offsets));
+  old_chain = make_cleanup (xfree, new_offsets);
+  changed = 0;
+
+  ALL_OBJFILE_OSECTIONS (symfile_objfile, osect)
+    {
+      CORE_ADDR orig_addr, addr, offset;
+      int osect_idx;
+      int seg;
+
+      osect_idx = osect->the_bfd_section->index;
+
+      /* Current address of section.  */
+      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.  */
+      orig_addr = addr - offset;
+
+      for (seg = 0; seg < ldm->nsegs; seg++)
+	{
+	  if (ldm->segs[seg].p_vaddr <= orig_addr
+	      && orig_addr < ldm->segs[seg].p_vaddr + ldm->segs[seg].p_memsz)
+	    {
+	      new_offsets->offsets[osect_idx]
+		= ldm->segs[seg].addr - ldm->segs[seg].p_vaddr;
+
+	      if (new_offsets->offsets[osect_idx] != offset)
+		changed = 1;
+	      break;
+	    }
+	}
+    }
+
+  if (changed)
+    objfile_relocate (symfile_objfile, new_offsets);
+
+  do_cleanups (old_chain);
+
+  /* Now that symfile_objfile has been relocated, we can compute the
+     GOT value and stash it away.  */
+}
+
+/* When gdb starts up the inferior, it nurses it along (through the
+   shell) until it is ready to execute it's first instruction.  At this
+   point, this function gets called via expansion of the macro
+   SOLIB_CREATE_INFERIOR_HOOK.
+
+   For the DSBT shared library, the main executable needs to be relocated.
+   The shared library breakpoints also need to be enabled.
+ */
+
+static void
+dsbt_solib_create_inferior_hook (int from_tty)
+{
+  /* Relocate main executable.  */
+  dsbt_relocate_main_executable ();
+
+  /* Enable shared library breakpoints.  */
+  if (!enable_break ())
+    {
+      warning (_("shared library handler failed to enable breakpoint"));
+      return;
+    }
+}
+
+static void
+dsbt_clear_solib (void)
+{
+  struct dsbt_info *info = get_dsbt_info ();
+
+  info->lm_base_cache = 0;
+  info->enable_break2_done = 0;
+  info->main_lm_addr = 0;
+  if (info->main_executable_lm_info != 0)
+    {
+      xfree (info->main_executable_lm_info->map);
+      xfree (info->main_executable_lm_info);
+      info->main_executable_lm_info = 0;
+    }
+}
+
+static void
+dsbt_free_so (struct so_list *so)
+{
+  xfree (so->lm_info->map);
+  xfree (so->lm_info);
+}
+
+static void
+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;
+
+  for (seg = 0; seg < map->nsegs; seg++)
+    {
+      if (map->segs[seg].p_vaddr <= sec->addr
+          && 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;
+	}
+    }
+}
+
+struct target_so_ops dsbt_so_ops;
+
+/* Provide a prototype to silence -Wmissing-prototypes.  */
+extern initialize_file_ftype _initialize_dsbt_solib;
+
+void
+_initialize_dsbt_solib (void)
+{
+  solib_dsbt_pspace_data
+    = register_program_space_data_with_cleanup (dsbt_pspace_data_cleanup);
+
+  dsbt_so_ops.relocate_section_addresses = dsbt_relocate_section_addresses;
+  dsbt_so_ops.free_so = dsbt_free_so;
+  dsbt_so_ops.clear_solib = dsbt_clear_solib;
+  dsbt_so_ops.solib_create_inferior_hook = dsbt_solib_create_inferior_hook;
+  dsbt_so_ops.special_symbol_handling = dsbt_special_symbol_handling;
+  dsbt_so_ops.current_sos = dsbt_current_sos;
+  dsbt_so_ops.open_symbol_file_object = open_symbol_file_object;
+  dsbt_so_ops.in_dynsym_resolve_code = dsbt_in_dynsym_resolve_code;
+  dsbt_so_ops.bfd_open = solib_bfd_open;
+
+  /* Debug this file's internals.  */
+  add_setshow_zinteger_cmd ("solib-dsbt", class_maintenance,
+			    &solib_dsbt_debug, _("\
+Set internal debugging of shared library code for DSBT ELF."), _("\
+Show internal debugging of shared library code for DSBT ELF."), _("\
+When non-zero, DSBT solib specific internal debugging is enabled."),
+			    NULL,
+			    NULL, /* FIXME: i18n: */
+			    &setdebuglist, &showdebuglist);
+}
-- 
1.7.0.4


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]