Exemple #1
0
bound_minimal_symbol
lookup_minimal_symbol_by_pc_section (CORE_ADDR pc_in, struct obj_section *section,
				     lookup_msym_prefer prefer)
{
  int lo;
  int hi;
  int newobj;
  struct objfile *objfile;
  struct minimal_symbol *msymbol;
  struct minimal_symbol *best_symbol = NULL;
  struct objfile *best_objfile = NULL;
  struct bound_minimal_symbol result;

  if (section == NULL)
    {
      section = find_pc_section (pc_in);
      if (section == NULL)
	return {};
    }

  minimal_symbol_type want_type = msym_prefer_to_msym_type (prefer);

  /* We can not require the symbol found to be in section, because
     e.g. IRIX 6.5 mdebug relies on this code returning an absolute
     symbol - but find_pc_section won't return an absolute section and
     hence the code below would skip over absolute symbols.  We can
     still take advantage of the call to find_pc_section, though - the
     object file still must match.  In case we have separate debug
     files, search both the file and its separate debug file.  There's
     no telling which one will have the minimal symbols.  */

  gdb_assert (section != NULL);

  for (objfile = section->objfile;
       objfile != NULL;
       objfile = objfile_separate_debug_iterate (section->objfile, objfile))
    {
      CORE_ADDR pc = pc_in;

      /* If this objfile has a minimal symbol table, go search it using
         a binary search.  Note that a minimal symbol table always consists
         of at least two symbols, a "real" symbol and the terminating
         "null symbol".  If there are no real symbols, then there is no
         minimal symbol table at all.  */

      if (objfile->per_bfd->minimal_symbol_count > 0)
	{
	  int best_zero_sized = -1;

          msymbol = objfile->per_bfd->msymbols;
	  lo = 0;
	  hi = objfile->per_bfd->minimal_symbol_count - 1;

	  /* This code assumes that the minimal symbols are sorted by
	     ascending address values.  If the pc value is greater than or
	     equal to the first symbol's address, then some symbol in this
	     minimal symbol table is a suitable candidate for being the
	     "best" symbol.  This includes the last real symbol, for cases
	     where the pc value is larger than any address in this vector.

	     By iterating until the address associated with the current
	     hi index (the endpoint of the test interval) is less than
	     or equal to the desired pc value, we accomplish two things:
	     (1) the case where the pc value is larger than any minimal
	     symbol address is trivially solved, (2) the address associated
	     with the hi index is always the one we want when the interation
	     terminates.  In essence, we are iterating the test interval
	     down until the pc value is pushed out of it from the high end.

	     Warning: this code is trickier than it would appear at first.  */

	  if (frob_address (objfile, &pc)
	      && pc >= MSYMBOL_VALUE_RAW_ADDRESS (&msymbol[lo]))
	    {
	      while (MSYMBOL_VALUE_RAW_ADDRESS (&msymbol[hi]) > pc)
		{
		  /* pc is still strictly less than highest address.  */
		  /* Note "new" will always be >= lo.  */
		  newobj = (lo + hi) / 2;
		  if ((MSYMBOL_VALUE_RAW_ADDRESS (&msymbol[newobj]) >= pc)
		      || (lo == newobj))
		    {
		      hi = newobj;
		    }
		  else
		    {
		      lo = newobj;
		    }
		}

	      /* If we have multiple symbols at the same address, we want
	         hi to point to the last one.  That way we can find the
	         right symbol if it has an index greater than hi.  */
	      while (hi < objfile->per_bfd->minimal_symbol_count - 1
		     && (MSYMBOL_VALUE_RAW_ADDRESS (&msymbol[hi])
			 == MSYMBOL_VALUE_RAW_ADDRESS (&msymbol[hi + 1])))
		hi++;

	      /* Skip various undesirable symbols.  */
	      while (hi >= 0)
		{
		  /* Skip any absolute symbols.  This is apparently
		     what adb and dbx do, and is needed for the CM-5.
		     There are two known possible problems: (1) on
		     ELF, apparently end, edata, etc. are absolute.
		     Not sure ignoring them here is a big deal, but if
		     we want to use them, the fix would go in
		     elfread.c.  (2) I think shared library entry
		     points on the NeXT are absolute.  If we want
		     special handling for this it probably should be
		     triggered by a special mst_abs_or_lib or some
		     such.  */

		  if (MSYMBOL_TYPE (&msymbol[hi]) == mst_abs)
		    {
		      hi--;
		      continue;
		    }

		  /* If SECTION was specified, skip any symbol from
		     wrong section.  */
		  if (section
		      /* Some types of debug info, such as COFF,
			 don't fill the bfd_section member, so don't
			 throw away symbols on those platforms.  */
		      && MSYMBOL_OBJ_SECTION (objfile, &msymbol[hi]) != NULL
		      && (!matching_obj_sections
			  (MSYMBOL_OBJ_SECTION (objfile, &msymbol[hi]),
			   section)))
		    {
		      hi--;
		      continue;
		    }

		  /* If we are looking for a trampoline and this is a
		     text symbol, or the other way around, check the
		     preceding symbol too.  If they are otherwise
		     identical prefer that one.  */
		  if (hi > 0
		      && MSYMBOL_TYPE (&msymbol[hi]) != want_type
		      && MSYMBOL_TYPE (&msymbol[hi - 1]) == want_type
		      && (MSYMBOL_SIZE (&msymbol[hi])
			  == MSYMBOL_SIZE (&msymbol[hi - 1]))
		      && (MSYMBOL_VALUE_RAW_ADDRESS (&msymbol[hi])
			  == MSYMBOL_VALUE_RAW_ADDRESS (&msymbol[hi - 1]))
		      && (MSYMBOL_OBJ_SECTION (objfile, &msymbol[hi])
			  == MSYMBOL_OBJ_SECTION (objfile, &msymbol[hi - 1])))
		    {
		      hi--;
		      continue;
		    }

		  /* If the minimal symbol has a zero size, save it
		     but keep scanning backwards looking for one with
		     a non-zero size.  A zero size may mean that the
		     symbol isn't an object or function (e.g. a
		     label), or it may just mean that the size was not
		     specified.  */
		  if (MSYMBOL_SIZE (&msymbol[hi]) == 0)
		    {
		      if (best_zero_sized == -1)
			best_zero_sized = hi;
		      hi--;
		      continue;
		    }

		  /* If we are past the end of the current symbol, try
		     the previous symbol if it has a larger overlapping
		     size.  This happens on i686-pc-linux-gnu with glibc;
		     the nocancel variants of system calls are inside
		     the cancellable variants, but both have sizes.  */
		  if (hi > 0
		      && MSYMBOL_SIZE (&msymbol[hi]) != 0
		      && pc >= (MSYMBOL_VALUE_RAW_ADDRESS (&msymbol[hi])
				+ MSYMBOL_SIZE (&msymbol[hi]))
		      && pc < (MSYMBOL_VALUE_RAW_ADDRESS (&msymbol[hi - 1])
			       + MSYMBOL_SIZE (&msymbol[hi - 1])))
		    {
		      hi--;
		      continue;
		    }

		  /* Otherwise, this symbol must be as good as we're going
		     to get.  */
		  break;
		}

	      /* If HI has a zero size, and best_zero_sized is set,
		 then we had two or more zero-sized symbols; prefer
		 the first one we found (which may have a higher
		 address).  Also, if we ran off the end, be sure
		 to back up.  */
	      if (best_zero_sized != -1
		  && (hi < 0 || MSYMBOL_SIZE (&msymbol[hi]) == 0))
		hi = best_zero_sized;

	      /* If the minimal symbol has a non-zero size, and this
		 PC appears to be outside the symbol's contents, then
		 refuse to use this symbol.  If we found a zero-sized
		 symbol with an address greater than this symbol's,
		 use that instead.  We assume that if symbols have
		 specified sizes, they do not overlap.  */

	      if (hi >= 0
		  && MSYMBOL_SIZE (&msymbol[hi]) != 0
		  && pc >= (MSYMBOL_VALUE_RAW_ADDRESS (&msymbol[hi])
			    + MSYMBOL_SIZE (&msymbol[hi])))
		{
		  if (best_zero_sized != -1)
		    hi = best_zero_sized;
		  else
		    /* Go on to the next object file.  */
		    continue;
		}

	      /* The minimal symbol indexed by hi now is the best one in this
	         objfile's minimal symbol table.  See if it is the best one
	         overall.  */

	      if (hi >= 0
		  && ((best_symbol == NULL) ||
		      (MSYMBOL_VALUE_RAW_ADDRESS (best_symbol) <
		       MSYMBOL_VALUE_RAW_ADDRESS (&msymbol[hi]))))
		{
		  best_symbol = &msymbol[hi];
		  best_objfile = objfile;
		}
	    }
	}
    }

  result.minsym = best_symbol;
  result.objfile = best_objfile;
  return result;
}
Exemple #2
0
int
find_pc_partial_function_gnu_ifunc (CORE_ADDR pc, const char **name,
				    CORE_ADDR *address, CORE_ADDR *endaddr,
				    int *is_gnu_ifunc_p)
{
  struct obj_section *section;
  struct symbol *f;
  struct minimal_symbol *msymbol;
  struct symtab *symtab = NULL;
  struct objfile *objfile;
  int i;
  CORE_ADDR mapped_pc;

  /* To ensure that the symbol returned belongs to the correct setion
     (and that the last [random] symbol from the previous section
     isn't returned) try to find the section containing PC.  First try
     the overlay code (which by default returns NULL); and second try
     the normal section code (which almost always succeeds).  */
  section = find_pc_overlay (pc);
  if (section == NULL)
    section = find_pc_section (pc);

  mapped_pc = overlay_mapped_address (pc, section);

  if (mapped_pc >= cache_pc_function_low
      && mapped_pc < cache_pc_function_high
      && section == cache_pc_function_section)
    goto return_cached_value;

  msymbol = lookup_minimal_symbol_by_pc_section (mapped_pc, section);
  ALL_OBJFILES (objfile)
  {
    if (objfile->sf)
      symtab = objfile->sf->qf->find_pc_sect_symtab (objfile, msymbol,
						     mapped_pc, section, 0);
    if (symtab)
      break;
  }

  if (symtab)
    {
      /* Checking whether the msymbol has a larger value is for the
	 "pathological" case mentioned in print_frame_info.  */
      f = find_pc_sect_function (mapped_pc, section);
      if (f != NULL
	  && (msymbol == NULL
	      || (BLOCK_START (SYMBOL_BLOCK_VALUE (f))
		  >= SYMBOL_VALUE_ADDRESS (msymbol))))
	{
	  cache_pc_function_low = BLOCK_START (SYMBOL_BLOCK_VALUE (f));
	  cache_pc_function_high = BLOCK_END (SYMBOL_BLOCK_VALUE (f));
	  cache_pc_function_name = SYMBOL_LINKAGE_NAME (f);
	  cache_pc_function_section = section;
	  cache_pc_function_is_gnu_ifunc = TYPE_GNU_IFUNC (SYMBOL_TYPE (f));
	  goto return_cached_value;
	}
    }

  /* Not in the normal symbol tables, see if the pc is in a known
     section.  If it's not, then give up.  This ensures that anything
     beyond the end of the text seg doesn't appear to be part of the
     last function in the text segment.  */

  if (!section)
    msymbol = NULL;

  /* Must be in the minimal symbol table.  */
  if (msymbol == NULL)
    {
      /* No available symbol.  */
      if (name != NULL)
	*name = 0;
      if (address != NULL)
	*address = 0;
      if (endaddr != NULL)
	*endaddr = 0;
      if (is_gnu_ifunc_p != NULL)
	*is_gnu_ifunc_p = 0;
      return 0;
    }

  cache_pc_function_low = SYMBOL_VALUE_ADDRESS (msymbol);
  cache_pc_function_name = SYMBOL_LINKAGE_NAME (msymbol);
  cache_pc_function_section = section;
  cache_pc_function_is_gnu_ifunc = MSYMBOL_TYPE (msymbol) == mst_text_gnu_ifunc;

  /* If the minimal symbol has a size, use it for the cache.
     Otherwise use the lesser of the next minimal symbol in the same
     section, or the end of the section, as the end of the
     function.  */

  if (MSYMBOL_SIZE (msymbol) != 0)
    cache_pc_function_high = cache_pc_function_low + MSYMBOL_SIZE (msymbol);
  else
    {
      /* Step over other symbols at this same address, and symbols in
	 other sections, to find the next symbol in this section with
	 a different address.  */

      for (i = 1; SYMBOL_LINKAGE_NAME (msymbol + i) != NULL; i++)
	{
	  if (SYMBOL_VALUE_ADDRESS (msymbol + i)
	      != SYMBOL_VALUE_ADDRESS (msymbol)
	      && SYMBOL_OBJ_SECTION (msymbol + i)
	      == SYMBOL_OBJ_SECTION (msymbol))
	    break;
	}

      if (SYMBOL_LINKAGE_NAME (msymbol + i) != NULL
	  && SYMBOL_VALUE_ADDRESS (msymbol + i)
	  < obj_section_endaddr (section))
	cache_pc_function_high = SYMBOL_VALUE_ADDRESS (msymbol + i);
      else
	/* We got the start address from the last msymbol in the objfile.
	   So the end address is the end of the section.  */
	cache_pc_function_high = obj_section_endaddr (section);
    }

 return_cached_value:

  if (address)
    {
      if (pc_in_unmapped_range (pc, section))
	*address = overlay_unmapped_address (cache_pc_function_low, section);
      else
	*address = cache_pc_function_low;
    }

  if (name)
    *name = cache_pc_function_name;

  if (endaddr)
    {
      if (pc_in_unmapped_range (pc, section))
	{
	  /* Because the high address is actually beyond the end of
	     the function (and therefore possibly beyond the end of
	     the overlay), we must actually convert (high - 1) and
	     then add one to that.  */

	  *endaddr = 1 + overlay_unmapped_address (cache_pc_function_high - 1,
						   section);
	}
      else
	*endaddr = cache_pc_function_high;
    }

  if (is_gnu_ifunc_p)
    *is_gnu_ifunc_p = cache_pc_function_is_gnu_ifunc;

  return 1;
}
static void
elf_symtab_read (struct objfile *objfile, int dynamic)
{
  long storage_needed;
  asymbol *sym;
  asymbol **symbol_table;
  long number_of_symbols;
  long i;
  struct cleanup *back_to;
  CORE_ADDR symaddr;
  CORE_ADDR offset;
  enum minimal_symbol_type ms_type;
  /* If sectinfo is nonNULL, it contains section info that should end up
     filed in the objfile.  */
  struct stab_section_info *sectinfo = NULL;
  /* If filesym is nonzero, it points to a file symbol, but we haven't
     seen any section info for it yet.  */
  asymbol *filesym = 0;
#ifdef SOFUN_ADDRESS_MAYBE_MISSING
  /* Name of filesym, as saved on the objfile_obstack.  */
  char *filesymname = obsavestring ("", 0, &objfile->objfile_obstack);
#endif
  struct dbx_symfile_info *dbx = objfile->sym_stab_info;
  int stripped = (bfd_get_symcount (objfile->obfd) == 0);

  if (dynamic)
    {
      storage_needed = bfd_get_dynamic_symtab_upper_bound (objfile->obfd);

      /* Nothing to be done if there is no dynamic symtab.  */
      if (storage_needed < 0)
	return;
    }
  else
    {
      storage_needed = bfd_get_symtab_upper_bound (objfile->obfd);
      if (storage_needed < 0)
	error ("Can't read symbols from %s: %s", bfd_get_filename (objfile->obfd),
	       bfd_errmsg (bfd_get_error ()));
    }
  if (storage_needed > 0)
    {
      symbol_table = (asymbol **) xmalloc (storage_needed);
      back_to = make_cleanup (xfree, symbol_table);
      if (dynamic)
	number_of_symbols = bfd_canonicalize_dynamic_symtab (objfile->obfd,
							     symbol_table);
      else
	number_of_symbols = bfd_canonicalize_symtab (objfile->obfd, symbol_table);
      if (number_of_symbols < 0)
	error ("Can't read symbols from %s: %s", bfd_get_filename (objfile->obfd),
	       bfd_errmsg (bfd_get_error ()));

      for (i = 0; i < number_of_symbols; i++)
	{
	  sym = symbol_table[i];
	  if (sym->name == NULL || *sym->name == '\0')
	    {
	      /* Skip names that don't exist (shouldn't happen), or names
	         that are null strings (may happen). */
	      continue;
	    }

          offset = ANOFFSET (objfile->section_offsets, sym->section->index);
	  if (dynamic
	      && sym->section == &bfd_und_section
	      && (sym->flags & BSF_FUNCTION))
	    {
	      struct minimal_symbol *msym;

	      /* Symbol is a reference to a function defined in
	         a shared library.
	         If its value is non zero then it is usually the address
	         of the corresponding entry in the procedure linkage table,
	         plus the desired section offset.
	         If its value is zero then the dynamic linker has to resolve
	         the symbol. We are unable to find any meaningful address
	         for this symbol in the executable file, so we skip it.  */
	      symaddr = sym->value;
	      if (symaddr == 0)
		continue;
	      symaddr += offset;
	      msym = record_minimal_symbol
		((char *) sym->name, symaddr,
		 mst_solib_trampoline, sym->section, objfile);
#ifdef SOFUN_ADDRESS_MAYBE_MISSING
	      if (msym != NULL)
		msym->filename = filesymname;
#endif
	      continue;
	    }

	  /* If it is a nonstripped executable, do not enter dynamic
	     symbols, as the dynamic symbol table is usually a subset
	     of the main symbol table.  */
	  if (dynamic && !stripped)
	    continue;
	  if (sym->flags & BSF_FILE)
	    {
	      /* STT_FILE debugging symbol that helps stabs-in-elf debugging.
	         Chain any old one onto the objfile; remember new sym.  */
	      if (sectinfo != NULL)
		{
		  sectinfo->next = dbx->stab_section_info;
		  dbx->stab_section_info = sectinfo;
		  sectinfo = NULL;
		}
	      filesym = sym;
#ifdef SOFUN_ADDRESS_MAYBE_MISSING
	      filesymname =
		obsavestring ((char *) filesym->name, strlen (filesym->name),
			      &objfile->objfile_obstack);
#endif
	    }
	  else if (sym->flags & (BSF_GLOBAL | BSF_LOCAL | BSF_WEAK))
	    {
	      struct minimal_symbol *msym;

	      /* Select global/local/weak symbols.  Note that bfd puts abs
	         symbols in their own section, so all symbols we are
	         interested in will have a section. */
	      /* Bfd symbols are section relative. */
	      symaddr = sym->value + sym->section->vma;
	      /* Relocate all non-absolute symbols by the section offset.  */
	      if (sym->section != &bfd_abs_section)
		{
		  symaddr += offset;
		}
	      /* For non-absolute symbols, use the type of the section
	         they are relative to, to intuit text/data.  Bfd provides
	         no way of figuring this out for absolute symbols. */
	      if (sym->section == &bfd_abs_section)
		{
		  /* This is a hack to get the minimal symbol type
		     right for Irix 5, which has absolute addresses
		     with special section indices for dynamic symbols. */
		  unsigned short shndx =
		  ((elf_symbol_type *) sym)->internal_elf_sym.st_shndx;

		  switch (shndx)
		    {
		    case SHN_MIPS_TEXT:
		      ms_type = mst_text;
		      break;
		    case SHN_MIPS_DATA:
		      ms_type = mst_data;
		      break;
		    case SHN_MIPS_ACOMMON:
		      ms_type = mst_bss;
		      break;
		    default:
		      ms_type = mst_abs;
		    }

		  /* If it is an Irix dynamic symbol, skip section name
		     symbols, relocate all others by section offset. */
		  if (ms_type != mst_abs)
		    {
		      if (sym->name[0] == '.')
			continue;
		      symaddr += offset;
		    }
		}
	      else if (sym->section->flags & SEC_CODE)
		{
		  if (sym->flags & BSF_GLOBAL)
		    {
		      ms_type = mst_text;
		    }
		  else if ((sym->name[0] == '.' && sym->name[1] == 'L')
			   || ((sym->flags & BSF_LOCAL)
			       && sym->name[0] == '$'
			       && sym->name[1] == 'L'))
		    /* Looks like a compiler-generated label.  Skip
		       it.  The assembler should be skipping these (to
		       keep executables small), but apparently with
		       gcc on the (deleted) delta m88k SVR4, it loses.
		       So to have us check too should be harmless (but
		       I encourage people to fix this in the assembler
		       instead of adding checks here).  */
		    continue;
		  else
		    {
		      ms_type = mst_file_text;
		    }
		}
	      else if (sym->section->flags & SEC_ALLOC)
		{
		  if (sym->flags & (BSF_GLOBAL | BSF_WEAK))
		    {
		      if (sym->section->flags & SEC_LOAD)
			{
			  ms_type = mst_data;
			}
		      else
			{
			  ms_type = mst_bss;
			}
		    }
		  else if (sym->flags & BSF_LOCAL)
		    {
		      /* Named Local variable in a Data section.
		         Check its name for stabs-in-elf.  */
		      int special_local_sect;
		      if (strcmp ("Bbss.bss", sym->name) == 0)
			special_local_sect = SECT_OFF_BSS (objfile);
		      else if (strcmp ("Ddata.data", sym->name) == 0)
			special_local_sect = SECT_OFF_DATA (objfile);
		      else if (strcmp ("Drodata.rodata", sym->name) == 0)
			special_local_sect = SECT_OFF_RODATA (objfile);
		      else
			special_local_sect = -1;
		      if (special_local_sect >= 0)
			{
			  /* Found a special local symbol.  Allocate a
			     sectinfo, if needed, and fill it in.  */
			  if (sectinfo == NULL)
			    {
			      int max_index;
			      size_t size;

			      max_index 
				= max (SECT_OFF_BSS (objfile),
				       max (SECT_OFF_DATA (objfile),
					    SECT_OFF_RODATA (objfile)));

                              /* max_index is the largest index we'll
                                 use into this array, so we must
                                 allocate max_index+1 elements for it.
                                 However, 'struct stab_section_info'
                                 already includes one element, so we
                                 need to allocate max_index aadditional
                                 elements.  */
			      size = (sizeof (struct stab_section_info) 
				      + (sizeof (CORE_ADDR)
					 * max_index));
			      sectinfo = (struct stab_section_info *)
				xmmalloc (objfile->md, size);
			      memset (sectinfo, 0, size);
			      sectinfo->num_sections = max_index;
			      if (filesym == NULL)
				{
				  complaint (&symfile_complaints,
					     "elf/stab section information %s without a preceding file symbol",
					     sym->name);
				}
			      else
				{
				  sectinfo->filename =
				    (char *) filesym->name;
				}
			    }
			  if (sectinfo->sections[special_local_sect] != 0)
			    complaint (&symfile_complaints,
				       "duplicated elf/stab section information for %s",
				       sectinfo->filename);
			  /* BFD symbols are section relative.  */
			  symaddr = sym->value + sym->section->vma;
			  /* Relocate non-absolute symbols by the
                             section offset.  */
			  if (sym->section != &bfd_abs_section)
			    symaddr += offset;
			  sectinfo->sections[special_local_sect] = symaddr;
			  /* The special local symbols don't go in the
			     minimal symbol table, so ignore this one.  */
			  continue;
			}
		      /* Not a special stabs-in-elf symbol, do regular
		         symbol processing.  */
		      if (sym->section->flags & SEC_LOAD)
			{
			  ms_type = mst_file_data;
			}
		      else
			{
			  ms_type = mst_file_bss;
			}
		    }
		  else
		    {
		      ms_type = mst_unknown;
		    }
		}
	      else
		{
		  /* FIXME:  Solaris2 shared libraries include lots of
		     odd "absolute" and "undefined" symbols, that play 
		     hob with actions like finding what function the PC
		     is in.  Ignore them if they aren't text, data, or bss.  */
		  /* ms_type = mst_unknown; */
		  continue;	/* Skip this symbol. */
		}
	      msym = record_minimal_symbol
		((char *) sym->name, symaddr,
		 ms_type, sym->section, objfile);
	      if (msym)
	      {
		/* Pass symbol size field in via BFD.  FIXME!!!  */
		unsigned long size = ((elf_symbol_type *) sym)->internal_elf_sym.st_size;
		MSYMBOL_SIZE(msym) = size;
	      }
#ifdef SOFUN_ADDRESS_MAYBE_MISSING
	      if (msym != NULL)
		msym->filename = filesymname;
#endif
	      ELF_MAKE_MSYMBOL_SPECIAL (sym, msym);
	    }
	}
      do_cleanups (back_to);
    }
}
Exemple #4
0
static LONGEST
ld_so_xfer_auxv (gdb_byte *readbuf,
		 const gdb_byte *writebuf,
		 ULONGEST offset,
		 LONGEST len)
{
  struct minimal_symbol *msym;
  CORE_ADDR data_address, pointer_address;
  struct type *ptr_type = builtin_type (target_gdbarch)->builtin_data_ptr;
  size_t ptr_size = TYPE_LENGTH (ptr_type);
  size_t auxv_pair_size = 2 * ptr_size;
  gdb_byte *ptr_buf = alloca (ptr_size);
  LONGEST retval;
  size_t block;

  msym = lookup_minimal_symbol ("_dl_auxv", NULL, NULL);
  if (msym == NULL)
    return -1;

  if (MSYMBOL_SIZE (msym) != ptr_size)
    return -1;

  /* POINTER_ADDRESS is a location where the `_dl_auxv' variable
     resides.  DATA_ADDRESS is the inferior value present in
     `_dl_auxv', therefore the real inferior AUXV address.  */

  pointer_address = SYMBOL_VALUE_ADDRESS (msym);

  /* The location of the _dl_auxv symbol may no longer be correct if
     ld.so runs at a different address than the one present in the
     file.  This is very common case - for unprelinked ld.so or with a
     PIE executable.  PIE executable forces random address even for
     libraries already being prelinked to some address.  PIE
     executables themselves are never prelinked even on prelinked
     systems.  Prelinking of a PIE executable would block their
     purpose of randomizing load of everything including the
     executable.

     If the memory read fails, return -1 to fallback on another
     mechanism for retrieving the AUXV.

     In most cases of a PIE running under valgrind there is no way to
     find out the base addresses of any of ld.so, executable or AUXV
     as everything is randomized and /proc information is not relevant
     for the virtual executable running under valgrind.  We think that
     we might need a valgrind extension to make it work.  This is PR
     11440.  */

  if (target_read_memory (pointer_address, ptr_buf, ptr_size) != 0)
    return -1;

  data_address = extract_typed_address (ptr_buf, ptr_type);

  /* Possibly still not initialized such as during an inferior
     startup.  */
  if (data_address == 0)
    return -1;

  data_address += offset;

  if (writebuf != NULL)
    {
      if (target_write_memory (data_address, writebuf, len) == 0)
	return len;
      else
	return -1;
    }

  /* Stop if trying to read past the existing AUXV block.  The final
     AT_NULL was already returned before.  */

  if (offset >= auxv_pair_size)
    {
      if (target_read_memory (data_address - auxv_pair_size, ptr_buf,
			      ptr_size) != 0)
	return -1;

      if (extract_typed_address (ptr_buf, ptr_type) == AT_NULL)
	return 0;
    }

  retval = 0;
  block = 0x400;
  gdb_assert (block % auxv_pair_size == 0);

  while (len > 0)
    {
      if (block > len)
	block = len;

      /* Reading sizes smaller than AUXV_PAIR_SIZE is not supported.
	 Tails unaligned to AUXV_PAIR_SIZE will not be read during a
	 call (they should be completed during next read with
	 new/extended buffer).  */

      block &= -auxv_pair_size;
      if (block == 0)
	return retval;

      if (target_read_memory (data_address, readbuf, block) != 0)
	{
	  if (block <= auxv_pair_size)
	    return retval;

	  block = auxv_pair_size;
	  continue;
	}

      data_address += block;
      len -= block;

      /* Check terminal AT_NULL.  This function is being called
         indefinitely being extended its READBUF until it returns EOF
         (0).  */

      while (block >= auxv_pair_size)
	{
	  retval += auxv_pair_size;

	  if (extract_typed_address (readbuf, ptr_type) == AT_NULL)
	    return retval;

	  readbuf += auxv_pair_size;
	  block -= auxv_pair_size;
	}
    }

  return retval;
}
Exemple #5
0
int
find_pc_partial_function (CORE_ADDR pc, char **name, CORE_ADDR *address,
			  CORE_ADDR *endaddr)
{
  struct obj_section *section;
  struct partial_symtab *pst;
  struct symbol *f;
  struct minimal_symbol *msymbol;
  struct partial_symbol *psb;
  int i;
  CORE_ADDR mapped_pc;

  /* To ensure that the symbol returned belongs to the correct setion
     (and that the last [random] symbol from the previous section
     isn't returned) try to find the section containing PC.  First try
     the overlay code (which by default returns NULL); and second try
     the normal section code (which almost always succeeds).  */
  section = find_pc_overlay (pc);
  if (section == NULL)
    section = find_pc_section (pc);

  mapped_pc = overlay_mapped_address (pc, section);

  if (mapped_pc >= cache_pc_function_low
      && mapped_pc < cache_pc_function_high
      && section == cache_pc_function_section)
    goto return_cached_value;

  msymbol = lookup_minimal_symbol_by_pc_section (mapped_pc, section);
  pst = find_pc_sect_psymtab (mapped_pc, section);
  if (pst)
    {
      /* Need to read the symbols to get a good value for the end address.  */
      if (endaddr != NULL && !pst->readin)
	{
	  /* Need to get the terminal in case symbol-reading produces
	     output.  */
	  target_terminal_ours_for_output ();
	  PSYMTAB_TO_SYMTAB (pst);
	}

      if (pst->readin)
	{
	  /* Checking whether the msymbol has a larger value is for the
	     "pathological" case mentioned in print_frame_info.  */
	  f = find_pc_sect_function (mapped_pc, section);
	  if (f != NULL
	      && (msymbol == NULL
		  || (BLOCK_START (SYMBOL_BLOCK_VALUE (f))
		      >= SYMBOL_VALUE_ADDRESS (msymbol))))
	    {
	      cache_pc_function_low = BLOCK_START (SYMBOL_BLOCK_VALUE (f));
	      cache_pc_function_high = BLOCK_END (SYMBOL_BLOCK_VALUE (f));
	      cache_pc_function_name = SYMBOL_LINKAGE_NAME (f);
	      cache_pc_function_section = section;
	      goto return_cached_value;
	    }
	}
      else
	{
	  /* Now that static symbols go in the minimal symbol table, perhaps
	     we could just ignore the partial symbols.  But at least for now
	     we use the partial or minimal symbol, whichever is larger.  */
	  psb = find_pc_sect_psymbol (pst, mapped_pc, section);

	  if (psb
	      && (msymbol == NULL ||
		  (SYMBOL_VALUE_ADDRESS (psb)
		   >= SYMBOL_VALUE_ADDRESS (msymbol))))
	    {
	      /* This case isn't being cached currently. */
	      if (address)
		*address = SYMBOL_VALUE_ADDRESS (psb);
	      if (name)
		*name = SYMBOL_LINKAGE_NAME (psb);
	      /* endaddr non-NULL can't happen here.  */
	      return 1;
	    }
	}
    }

  /* Not in the normal symbol tables, see if the pc is in a known section.
     If it's not, then give up.  This ensures that anything beyond the end
     of the text seg doesn't appear to be part of the last function in the
     text segment.  */

  if (!section)
    msymbol = NULL;

  /* Must be in the minimal symbol table.  */
  if (msymbol == NULL)
    {
      /* No available symbol.  */
      if (name != NULL)
	*name = 0;
      if (address != NULL)
	*address = 0;
      if (endaddr != NULL)
	*endaddr = 0;
      return 0;
    }

  cache_pc_function_low = SYMBOL_VALUE_ADDRESS (msymbol);
  cache_pc_function_name = SYMBOL_LINKAGE_NAME (msymbol);
  cache_pc_function_section = section;

  /* If the minimal symbol has a size, use it for the cache.
     Otherwise use the lesser of the next minimal symbol in the same
     section, or the end of the section, as the end of the
     function.  */

  if (MSYMBOL_SIZE (msymbol) != 0)
    cache_pc_function_high = cache_pc_function_low + MSYMBOL_SIZE (msymbol);
  else
    {
      /* Step over other symbols at this same address, and symbols in
	 other sections, to find the next symbol in this section with
	 a different address.  */

      for (i = 1; SYMBOL_LINKAGE_NAME (msymbol + i) != NULL; i++)
	{
	  if (SYMBOL_VALUE_ADDRESS (msymbol + i) != SYMBOL_VALUE_ADDRESS (msymbol)
	      && SYMBOL_OBJ_SECTION (msymbol + i) == SYMBOL_OBJ_SECTION (msymbol))
	    break;
	}

      if (SYMBOL_LINKAGE_NAME (msymbol + i) != NULL
	  && SYMBOL_VALUE_ADDRESS (msymbol + i) < obj_section_endaddr (section))
	cache_pc_function_high = SYMBOL_VALUE_ADDRESS (msymbol + i);
      else
	/* We got the start address from the last msymbol in the objfile.
	   So the end address is the end of the section.  */
	cache_pc_function_high = obj_section_endaddr (section);
    }

 return_cached_value:

  if (address)
    {
      if (pc_in_unmapped_range (pc, section))
	*address = overlay_unmapped_address (cache_pc_function_low, section);
      else
	*address = cache_pc_function_low;
    }

  if (name)
    *name = cache_pc_function_name;

  if (endaddr)
    {
      if (pc_in_unmapped_range (pc, section))
	{
	  /* Because the high address is actually beyond the end of
	     the function (and therefore possibly beyond the end of
	     the overlay), we must actually convert (high - 1) and
	     then add one to that. */

	  *endaddr = 1 + overlay_unmapped_address (cache_pc_function_high - 1,
						   section);
	}
      else
	*endaddr = cache_pc_function_high;
    }

  return 1;
}