Blame gprof/symtab.c

Packit Service 72eb06
/* symtab.c
Packit Service 72eb06
Packit Service 72eb06
   Copyright (C) 1999-2018 Free Software Foundation, Inc.
Packit Service 72eb06
Packit Service 72eb06
   This file is part of GNU Binutils.
Packit Service 72eb06
Packit Service 72eb06
   This program is free software; you can redistribute it and/or modify
Packit Service 72eb06
   it under the terms of the GNU General Public License as published by
Packit Service 72eb06
   the Free Software Foundation; either version 3 of the License, or
Packit Service 72eb06
   (at your option) any later version.
Packit Service 72eb06
Packit Service 72eb06
   This program is distributed in the hope that it will be useful,
Packit Service 72eb06
   but WITHOUT ANY WARRANTY; without even the implied warranty of
Packit Service 72eb06
   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
Packit Service 72eb06
   GNU General Public License for more details.
Packit Service 72eb06
Packit Service 72eb06
   You should have received a copy of the GNU General Public License
Packit Service 72eb06
   along with this program; if not, write to the Free Software
Packit Service 72eb06
   Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston, MA
Packit Service 72eb06
   02110-1301, USA.  */
Packit Service 72eb06

Packit Service 72eb06
#include "gprof.h"
Packit Service 72eb06
#include "search_list.h"
Packit Service 72eb06
#include "source.h"
Packit Service 72eb06
#include "symtab.h"
Packit Service 72eb06
#include "cg_arcs.h"
Packit Service 72eb06
#include "corefile.h"
Packit Service 72eb06
Packit Service 72eb06
static int cmp_addr (const PTR, const PTR);
Packit Service 72eb06
Packit Service 72eb06
Sym_Table symtab;
Packit Service 72eb06
Packit Service 72eb06
Packit Service 72eb06
/* Initialize a symbol (so it's empty).  */
Packit Service 72eb06
Packit Service 72eb06
void
Packit Service 72eb06
sym_init (Sym *sym)
Packit Service 72eb06
{
Packit Service 72eb06
  memset (sym, 0, sizeof (*sym));
Packit Service 72eb06
Packit Service 72eb06
  /* It is not safe to assume that a binary zero corresponds
Packit Service 72eb06
     to a floating-point 0.0, so initialize floats explicitly.  */
Packit Service 72eb06
  sym->hist.time = 0.0;
Packit Service 72eb06
  sym->cg.child_time = 0.0;
Packit Service 72eb06
  sym->cg.prop.fract = 0.0;
Packit Service 72eb06
  sym->cg.prop.self = 0.0;
Packit Service 72eb06
  sym->cg.prop.child = 0.0;
Packit Service 72eb06
}
Packit Service 72eb06
Packit Service 72eb06
Packit Service 72eb06
/* Compare the function entry-point of two symbols and return <0, =0,
Packit Service 72eb06
   or >0 depending on whether the left value is smaller than, equal
Packit Service 72eb06
   to, or greater than the right value.  If two symbols are equal
Packit Service 72eb06
   but one has is_func set and the other doesn't, we make the
Packit Service 72eb06
   non-function symbol one "bigger" so that the function symbol will
Packit Service 72eb06
   survive duplicate removal.  Finally, if both symbols have the
Packit Service 72eb06
   same is_func value, we discriminate against is_static such that
Packit Service 72eb06
   the global symbol survives.  */
Packit Service 72eb06
Packit Service 72eb06
static int
Packit Service 72eb06
cmp_addr (const PTR lp, const PTR rp)
Packit Service 72eb06
{
Packit Service 72eb06
  const Sym *left = (const Sym *) lp;
Packit Service 72eb06
  const Sym *right = (const Sym *) rp;
Packit Service 72eb06
Packit Service 72eb06
  if (left->addr > right->addr)
Packit Service 72eb06
    return 1;
Packit Service 72eb06
  else if (left->addr < right->addr)
Packit Service 72eb06
    return -1;
Packit Service 72eb06
Packit Service 72eb06
  if (left->is_func != right->is_func)
Packit Service 72eb06
    return right->is_func - left->is_func;
Packit Service 72eb06
Packit Service 72eb06
  return left->is_static - right->is_static;
Packit Service 72eb06
}
Packit Service 72eb06
Packit Service 72eb06
Packit Service 72eb06
void
Packit Service 72eb06
symtab_finalize (Sym_Table *tab)
Packit Service 72eb06
{
Packit Service 72eb06
  Sym *src, *dst;
Packit Service 72eb06
  bfd_vma prev_addr;
Packit Service 72eb06
Packit Service 72eb06
  if (!tab->len)
Packit Service 72eb06
    return;
Packit Service 72eb06
Packit Service 72eb06
  /* Sort symbol table in order of increasing function addresses.  */
Packit Service 72eb06
  qsort (tab->base, tab->len, sizeof (Sym), cmp_addr);
Packit Service 72eb06
Packit Service 72eb06
  /* Remove duplicate entries to speed-up later processing and
Packit Service 72eb06
     set end_addr if its not set yet.  */
Packit Service 72eb06
  prev_addr = tab->base[0].addr + 1;
Packit Service 72eb06
Packit Service 72eb06
  for (src = dst = tab->base; src < tab->limit; ++src)
Packit Service 72eb06
    {
Packit Service 72eb06
      if (src->addr == prev_addr)
Packit Service 72eb06
	{
Packit Service 72eb06
	  /* If same address, favor global symbol over static one,
Packit Service 72eb06
	     then function over line number.  If both symbols are
Packit Service 72eb06
	     either static or global and either function or line, check
Packit Service 72eb06
	     whether one has name beginning with underscore while
Packit Service 72eb06
	     the other doesn't.  In such cases, keep sym without
Packit Service 72eb06
	     underscore.  This takes cares of compiler generated
Packit Service 72eb06
	     symbols (such as __gnu_compiled, __c89_used, etc.).  */
Packit Service 72eb06
	  if ((!src->is_static && dst[-1].is_static)
Packit Service 72eb06
	      || ((src->is_static == dst[-1].is_static)
Packit Service 72eb06
		  && ((src->is_func && !dst[-1].is_func)
Packit Service 72eb06
		      || ((src->is_func == dst[-1].is_func)
Packit Service 72eb06
			  && ((src->name[0] != '_' && dst[-1].name[0] == '_')
Packit Service 72eb06
			      || (src->name[0]
Packit Service 72eb06
				  && src->name[1] != '_'
Packit Service 72eb06
				  && dst[-1].name[1] == '_'))))))
Packit Service 72eb06
	    {
Packit Service 72eb06
	      DBG (AOUTDEBUG | IDDEBUG,
Packit Service 72eb06
		   printf ("[symtab_finalize] favor %s@%c%c over %s@%c%c",
Packit Service 72eb06
			   src->name, src->is_static ? 't' : 'T',
Packit Service 72eb06
			   src->is_func ? 'F' : 'f',
Packit Service 72eb06
			   dst[-1].name, dst[-1].is_static ? 't' : 'T',
Packit Service 72eb06
			   dst[-1].is_func ? 'F' : 'f');
Packit Service 72eb06
		   printf (" (addr=%lx)\n", (unsigned long) src->addr));
Packit Service 72eb06
Packit Service 72eb06
	      dst[-1] = *src;
Packit Service 72eb06
	    }
Packit Service 72eb06
	  else
Packit Service 72eb06
	    {
Packit Service 72eb06
	      DBG (AOUTDEBUG | IDDEBUG,
Packit Service 72eb06
		   printf ("[symtab_finalize] favor %s@%c%c over %s@%c%c",
Packit Service 72eb06
			   dst[-1].name, dst[-1].is_static ? 't' : 'T',
Packit Service 72eb06
			   dst[-1].is_func ? 'F' : 'f',
Packit Service 72eb06
			   src->name, src->is_static ? 't' : 'T',
Packit Service 72eb06
			   src->is_func ? 'F' : 'f');
Packit Service 72eb06
		   printf (" (addr=%lx)\n", (unsigned long) src->addr));
Packit Service 72eb06
	    }
Packit Service 72eb06
	}
Packit Service 72eb06
      else
Packit Service 72eb06
	{
Packit Service 72eb06
	  if (dst > tab->base && dst[-1].end_addr == 0)
Packit Service 72eb06
	    dst[-1].end_addr = src->addr - 1;
Packit Service 72eb06
Packit Service 72eb06
	  /* Retain sym only if it has a non-empty address range.  */
Packit Service 72eb06
	  if (!src->end_addr || src->addr <= src->end_addr)
Packit Service 72eb06
	    {
Packit Service 72eb06
	      *dst = *src;
Packit Service 72eb06
	      dst++;
Packit Service 72eb06
	      prev_addr = src->addr;
Packit Service 72eb06
	    }
Packit Service 72eb06
	}
Packit Service 72eb06
    }
Packit Service 72eb06
Packit Service 72eb06
  if (tab->len > 0 && dst[-1].end_addr == 0)
Packit Service 72eb06
    dst[-1].end_addr
Packit Service 72eb06
      = core_text_sect->vma + bfd_get_section_size (core_text_sect) - 1;
Packit Service 72eb06
Packit Service 72eb06
  DBG (AOUTDEBUG | IDDEBUG,
Packit Service 72eb06
       printf ("[symtab_finalize]: removed %d duplicate entries\n",
Packit Service 72eb06
	       tab->len - (int) (dst - tab->base)));
Packit Service 72eb06
Packit Service 72eb06
  tab->limit = dst;
Packit Service 72eb06
  tab->len = tab->limit - tab->base;
Packit Service 72eb06
Packit Service 72eb06
  DBG (AOUTDEBUG | IDDEBUG,
Packit Service 72eb06
       unsigned int j;
Packit Service 72eb06
Packit Service 72eb06
       for (j = 0; j < tab->len; ++j)
Packit Service 72eb06
	 {
Packit Service 72eb06
	   printf ("[symtab_finalize] 0x%lx-0x%lx\t%s\n",
Packit Service 72eb06
		   (unsigned long) tab->base[j].addr,
Packit Service 72eb06
		   (unsigned long) tab->base[j].end_addr,
Packit Service 72eb06
		   tab->base[j].name);
Packit Service 72eb06
	 }
Packit Service 72eb06
  );
Packit Service 72eb06
}
Packit Service 72eb06
Packit Service 72eb06
Packit Service 72eb06
#ifdef DEBUG
Packit Service 72eb06
Packit Service 72eb06
Sym *
Packit Service 72eb06
dbg_sym_lookup (Sym_Table *sym_tab, bfd_vma address)
Packit Service 72eb06
{
Packit Service 72eb06
  unsigned long low, mid, high;
Packit Service 72eb06
  Sym *sym;
Packit Service 72eb06
Packit Service 72eb06
  fprintf (stderr, "[dbg_sym_lookup] address 0x%lx\n",
Packit Service 72eb06
	   (unsigned long) address);
Packit Service 72eb06
Packit Service 72eb06
  sym = sym_tab->base;
Packit Service 72eb06
  for (low = 0, high = sym_tab->len - 1; low != high;)
Packit Service 72eb06
    {
Packit Service 72eb06
      mid = (high + low) >> 1;
Packit Service 72eb06
Packit Service 72eb06
      fprintf (stderr, "[dbg_sym_lookup] low=0x%lx, mid=0x%lx, high=0x%lx\n",
Packit Service 72eb06
	       low, mid, high);
Packit Service 72eb06
      fprintf (stderr, "[dbg_sym_lookup] sym[m]=0x%lx sym[m + 1]=0x%lx\n",
Packit Service 72eb06
	       (unsigned long) sym[mid].addr,
Packit Service 72eb06
	       (unsigned long) sym[mid + 1].addr);
Packit Service 72eb06
Packit Service 72eb06
      if (sym[mid].addr <= address && sym[mid + 1].addr > address)
Packit Service 72eb06
	return &sym[mid];
Packit Service 72eb06
Packit Service 72eb06
      if (sym[mid].addr > address)
Packit Service 72eb06
	high = mid;
Packit Service 72eb06
      else
Packit Service 72eb06
	low = mid + 1;
Packit Service 72eb06
    }
Packit Service 72eb06
Packit Service 72eb06
  fprintf (stderr, "[dbg_sym_lookup] binary search fails???\n");
Packit Service 72eb06
Packit Service 72eb06
  return 0;
Packit Service 72eb06
}
Packit Service 72eb06
Packit Service 72eb06
#endif	/* DEBUG */
Packit Service 72eb06
Packit Service 72eb06
Packit Service 72eb06
/* Look up an address in the symbol-table that is sorted by address.
Packit Service 72eb06
   If address does not hit any symbol, 0 is returned.  */
Packit Service 72eb06
Sym *
Packit Service 72eb06
sym_lookup (Sym_Table *sym_tab, bfd_vma address)
Packit Service 72eb06
{
Packit Service 72eb06
  long low, high;
Packit Service 72eb06
  long mid = -1;
Packit Service 72eb06
  Sym *sym;
Packit Service 72eb06
#ifdef DEBUG
Packit Service 72eb06
  int probes = 0;
Packit Service 72eb06
#endif /* DEBUG */
Packit Service 72eb06
Packit Service 72eb06
  if (!sym_tab->len)
Packit Service 72eb06
    return 0;
Packit Service 72eb06
Packit Service 72eb06
  sym = sym_tab->base;
Packit Service 72eb06
  for (low = 0, high = sym_tab->len - 1; low != high;)
Packit Service 72eb06
    {
Packit Service 72eb06
      DBG (LOOKUPDEBUG, ++probes);
Packit Service 72eb06
      mid = (high + low) / 2;
Packit Service 72eb06
Packit Service 72eb06
      if (sym[mid].addr <= address && sym[mid + 1].addr > address)
Packit Service 72eb06
	{
Packit Service 72eb06
	  if (address > sym[mid].end_addr)
Packit Service 72eb06
	    {
Packit Service 72eb06
	      /* Address falls into gap between
Packit Service 72eb06
		 sym[mid] and sym[mid + 1].  */
Packit Service 72eb06
	      return 0;
Packit Service 72eb06
	    }
Packit Service 72eb06
	  else
Packit Service 72eb06
	    {
Packit Service 72eb06
	      DBG (LOOKUPDEBUG,
Packit Service 72eb06
		   printf ("[sym_lookup] %d probes (symtab->len=%u)\n",
Packit Service 72eb06
			   probes, sym_tab->len - 1));
Packit Service 72eb06
	      return &sym[mid];
Packit Service 72eb06
	    }
Packit Service 72eb06
	}
Packit Service 72eb06
Packit Service 72eb06
      if (sym[mid].addr > address)
Packit Service 72eb06
	high = mid;
Packit Service 72eb06
      else
Packit Service 72eb06
	low = mid + 1;
Packit Service 72eb06
    }
Packit Service 72eb06
Packit Service 72eb06
  if (sym[mid + 1].addr <= address)
Packit Service 72eb06
    {
Packit Service 72eb06
      if (address > sym[mid + 1].end_addr)
Packit Service 72eb06
	{
Packit Service 72eb06
	  /* Address is beyond end of sym[mid + 1].  */
Packit Service 72eb06
	  return 0;
Packit Service 72eb06
	}
Packit Service 72eb06
      else
Packit Service 72eb06
	{
Packit Service 72eb06
	  DBG (LOOKUPDEBUG, printf ("[sym_lookup] %d (%u) probes, fall off\n",
Packit Service 72eb06
				    probes, sym_tab->len - 1));
Packit Service 72eb06
	  return &sym[mid + 1];
Packit Service 72eb06
	}
Packit Service 72eb06
    }
Packit Service 72eb06
Packit Service 72eb06
  return 0;
Packit Service 72eb06
}