Exemplo n.º 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;
}
static int
hppa64_hpux_in_solib_call_trampoline (struct gdbarch *gdbarch, CORE_ADDR pc)
{
  enum bfd_endian byte_order = gdbarch_byte_order (gdbarch);

  /* PA64 has a completely different stub/trampoline scheme.  Is it
     better?  Maybe.  It's certainly harder to determine with any
     certainty that we are in a stub because we can not refer to the
     unwinders to help.

     The heuristic is simple.  Try to lookup the current PC value in th
     minimal symbol table.  If that fails, then assume we are not in a
     stub and return.

     Then see if the PC value falls within the section bounds for the
     section containing the minimal symbol we found in the first
     step.  If it does, then assume we are not in a stub and return.

     Finally peek at the instructions to see if they look like a stub.  */
  struct bound_minimal_symbol minsym;
  asection *sec;
  CORE_ADDR addr;
  int insn;

  minsym = lookup_minimal_symbol_by_pc (pc);
  if (! minsym.minsym)
    return 0;

  sec = MSYMBOL_OBJ_SECTION (minsym.objfile, minsym.minsym)->the_bfd_section;

  if (bfd_get_section_vma (sec->owner, sec) <= pc
      && pc < (bfd_get_section_vma (sec->owner, sec)
		 + bfd_section_size (sec->owner, sec)))
      return 0;

  /* We might be in a stub.  Peek at the instructions.  Stubs are 3
     instructions long.  */
  insn = read_memory_integer (pc, 4, byte_order);

  /* Find out where we think we are within the stub.  */
  if ((insn & 0xffffc00e) == 0x53610000)
    addr = pc;
  else if ((insn & 0xffffffff) == 0xe820d000)
    addr = pc - 4;
  else if ((insn & 0xffffc00e) == 0x537b0000)
    addr = pc - 8;
  else
    return 0;

  /* Now verify each insn in the range looks like a stub instruction.  */
  insn = read_memory_integer (addr, 4, byte_order);
  if ((insn & 0xffffc00e) != 0x53610000)
    return 0;
	
  /* Now verify each insn in the range looks like a stub instruction.  */
  insn = read_memory_integer (addr + 4, 4, byte_order);
  if ((insn & 0xffffffff) != 0xe820d000)
    return 0;
    
  /* Now verify each insn in the range looks like a stub instruction.  */
  insn = read_memory_integer (addr + 8, 4, byte_order);
  if ((insn & 0xffffc00e) != 0x537b0000)
    return 0;

  /* Looks like a stub.  */
  return 1;
}