xref: /openbsd-src/gnu/usr.bin/binutils-2.17/gprof/symtab.c (revision 3d8817e467ea46cf4772788d6804dd293abfb01a)
1*3d8817e4Smiod /* symtab.c
2*3d8817e4Smiod 
3*3d8817e4Smiod    Copyright 1999, 2000, 2001, 2002, 2004 Free Software Foundation, Inc.
4*3d8817e4Smiod 
5*3d8817e4Smiod    This file is part of GNU Binutils.
6*3d8817e4Smiod 
7*3d8817e4Smiod    This program is free software; you can redistribute it and/or modify
8*3d8817e4Smiod    it under the terms of the GNU General Public License as published by
9*3d8817e4Smiod    the Free Software Foundation; either version 2 of the License, or
10*3d8817e4Smiod    (at your option) any later version.
11*3d8817e4Smiod 
12*3d8817e4Smiod    This program is distributed in the hope that it will be useful,
13*3d8817e4Smiod    but WITHOUT ANY WARRANTY; without even the implied warranty of
14*3d8817e4Smiod    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15*3d8817e4Smiod    GNU General Public License for more details.
16*3d8817e4Smiod 
17*3d8817e4Smiod    You should have received a copy of the GNU General Public License
18*3d8817e4Smiod    along with this program; if not, write to the Free Software
19*3d8817e4Smiod    Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston, MA
20*3d8817e4Smiod    02110-1301, USA.  */
21*3d8817e4Smiod 
22*3d8817e4Smiod #include "gprof.h"
23*3d8817e4Smiod #include "search_list.h"
24*3d8817e4Smiod #include "source.h"
25*3d8817e4Smiod #include "symtab.h"
26*3d8817e4Smiod #include "cg_arcs.h"
27*3d8817e4Smiod #include "corefile.h"
28*3d8817e4Smiod 
29*3d8817e4Smiod static int cmp_addr (const PTR, const PTR);
30*3d8817e4Smiod 
31*3d8817e4Smiod Sym_Table symtab;
32*3d8817e4Smiod 
33*3d8817e4Smiod 
34*3d8817e4Smiod /* Initialize a symbol (so it's empty).  */
35*3d8817e4Smiod 
36*3d8817e4Smiod void
sym_init(Sym * sym)37*3d8817e4Smiod sym_init (Sym *sym)
38*3d8817e4Smiod {
39*3d8817e4Smiod   memset (sym, 0, sizeof (*sym));
40*3d8817e4Smiod 
41*3d8817e4Smiod   /* It is not safe to assume that a binary zero corresponds
42*3d8817e4Smiod      to a floating-point 0.0, so initialize floats explicitly.  */
43*3d8817e4Smiod   sym->hist.time = 0.0;
44*3d8817e4Smiod   sym->cg.child_time = 0.0;
45*3d8817e4Smiod   sym->cg.prop.fract = 0.0;
46*3d8817e4Smiod   sym->cg.prop.self = 0.0;
47*3d8817e4Smiod   sym->cg.prop.child = 0.0;
48*3d8817e4Smiod }
49*3d8817e4Smiod 
50*3d8817e4Smiod 
51*3d8817e4Smiod /* Compare the function entry-point of two symbols and return <0, =0,
52*3d8817e4Smiod    or >0 depending on whether the left value is smaller than, equal
53*3d8817e4Smiod    to, or greater than the right value.  If two symbols are equal
54*3d8817e4Smiod    but one has is_func set and the other doesn't, we make the
55*3d8817e4Smiod    non-function symbol one "bigger" so that the function symbol will
56*3d8817e4Smiod    survive duplicate removal.  Finally, if both symbols have the
57*3d8817e4Smiod    same is_func value, we discriminate against is_static such that
58*3d8817e4Smiod    the global symbol survives.  */
59*3d8817e4Smiod 
60*3d8817e4Smiod static int
cmp_addr(const PTR lp,const PTR rp)61*3d8817e4Smiod cmp_addr (const PTR lp, const PTR rp)
62*3d8817e4Smiod {
63*3d8817e4Smiod   const Sym *left = (const Sym *) lp;
64*3d8817e4Smiod   const Sym *right = (const Sym *) rp;
65*3d8817e4Smiod 
66*3d8817e4Smiod   if (left->addr > right->addr)
67*3d8817e4Smiod     return 1;
68*3d8817e4Smiod   else if (left->addr < right->addr)
69*3d8817e4Smiod     return -1;
70*3d8817e4Smiod 
71*3d8817e4Smiod   if (left->is_func != right->is_func)
72*3d8817e4Smiod     return right->is_func - left->is_func;
73*3d8817e4Smiod 
74*3d8817e4Smiod   return left->is_static - right->is_static;
75*3d8817e4Smiod }
76*3d8817e4Smiod 
77*3d8817e4Smiod 
78*3d8817e4Smiod void
symtab_finalize(Sym_Table * tab)79*3d8817e4Smiod symtab_finalize (Sym_Table *tab)
80*3d8817e4Smiod {
81*3d8817e4Smiod   Sym *src, *dst;
82*3d8817e4Smiod   bfd_vma prev_addr;
83*3d8817e4Smiod 
84*3d8817e4Smiod   if (!tab->len)
85*3d8817e4Smiod     return;
86*3d8817e4Smiod 
87*3d8817e4Smiod   /* Sort symbol table in order of increasing function addresses.  */
88*3d8817e4Smiod   qsort (tab->base, tab->len, sizeof (Sym), cmp_addr);
89*3d8817e4Smiod 
90*3d8817e4Smiod   /* Remove duplicate entries to speed-up later processing and
91*3d8817e4Smiod      set end_addr if its not set yet.  */
92*3d8817e4Smiod   prev_addr = tab->base[0].addr + 1;
93*3d8817e4Smiod 
94*3d8817e4Smiod   for (src = dst = tab->base; src < tab->limit; ++src)
95*3d8817e4Smiod     {
96*3d8817e4Smiod       if (src->addr == prev_addr)
97*3d8817e4Smiod 	{
98*3d8817e4Smiod 	  /* If same address, favor global symbol over static one,
99*3d8817e4Smiod 	     then function over line number.  If both symbols are
100*3d8817e4Smiod 	     either static or global and either function or line, check
101*3d8817e4Smiod 	     whether one has name beginning with underscore while
102*3d8817e4Smiod 	     the other doesn't.  In such cases, keep sym without
103*3d8817e4Smiod 	     underscore.  This takes cares of compiler generated
104*3d8817e4Smiod 	     symbols (such as __gnu_compiled, __c89_used, etc.).  */
105*3d8817e4Smiod 	  if ((!src->is_static && dst[-1].is_static)
106*3d8817e4Smiod 	      || ((src->is_static == dst[-1].is_static)
107*3d8817e4Smiod 		  && ((src->is_func && !dst[-1].is_func)
108*3d8817e4Smiod 		      || ((src->is_func == dst[-1].is_func)
109*3d8817e4Smiod 			  && ((src->name[0] != '_' && dst[-1].name[0] == '_')
110*3d8817e4Smiod 			      || (src->name[0]
111*3d8817e4Smiod 				  && src->name[1] != '_'
112*3d8817e4Smiod 				  && dst[-1].name[1] == '_'))))))
113*3d8817e4Smiod 	    {
114*3d8817e4Smiod 	      DBG (AOUTDEBUG | IDDEBUG,
115*3d8817e4Smiod 		   printf ("[symtab_finalize] favor %s@%c%c over %s@%c%c",
116*3d8817e4Smiod 			   src->name, src->is_static ? 't' : 'T',
117*3d8817e4Smiod 			   src->is_func ? 'F' : 'f',
118*3d8817e4Smiod 			   dst[-1].name, dst[-1].is_static ? 't' : 'T',
119*3d8817e4Smiod 			   dst[-1].is_func ? 'F' : 'f');
120*3d8817e4Smiod 		   printf (" (addr=%lx)\n", (unsigned long) src->addr));
121*3d8817e4Smiod 
122*3d8817e4Smiod 	      dst[-1] = *src;
123*3d8817e4Smiod 	    }
124*3d8817e4Smiod 	  else
125*3d8817e4Smiod 	    {
126*3d8817e4Smiod 	      DBG (AOUTDEBUG | IDDEBUG,
127*3d8817e4Smiod 		   printf ("[symtab_finalize] favor %s@%c%c over %s@%c%c",
128*3d8817e4Smiod 			   dst[-1].name, dst[-1].is_static ? 't' : 'T',
129*3d8817e4Smiod 			   dst[-1].is_func ? 'F' : 'f',
130*3d8817e4Smiod 			   src->name, src->is_static ? 't' : 'T',
131*3d8817e4Smiod 			   src->is_func ? 'F' : 'f');
132*3d8817e4Smiod 		   printf (" (addr=%lx)\n", (unsigned long) src->addr));
133*3d8817e4Smiod 	    }
134*3d8817e4Smiod 	}
135*3d8817e4Smiod       else
136*3d8817e4Smiod 	{
137*3d8817e4Smiod 	  if (dst > tab->base && dst[-1].end_addr == 0)
138*3d8817e4Smiod 	    dst[-1].end_addr = src->addr - 1;
139*3d8817e4Smiod 
140*3d8817e4Smiod 	  /* Retain sym only if it has a non-empty address range.  */
141*3d8817e4Smiod 	  if (!src->end_addr || src->addr <= src->end_addr)
142*3d8817e4Smiod 	    {
143*3d8817e4Smiod 	      *dst = *src;
144*3d8817e4Smiod 	      dst++;
145*3d8817e4Smiod 	      prev_addr = src->addr;
146*3d8817e4Smiod 	    }
147*3d8817e4Smiod 	}
148*3d8817e4Smiod     }
149*3d8817e4Smiod 
150*3d8817e4Smiod   if (tab->len > 0 && dst[-1].end_addr == 0)
151*3d8817e4Smiod     dst[-1].end_addr
152*3d8817e4Smiod       = core_text_sect->vma + bfd_get_section_size (core_text_sect) - 1;
153*3d8817e4Smiod 
154*3d8817e4Smiod   DBG (AOUTDEBUG | IDDEBUG,
155*3d8817e4Smiod        printf ("[symtab_finalize]: removed %d duplicate entries\n",
156*3d8817e4Smiod 	       tab->len - (int) (dst - tab->base)));
157*3d8817e4Smiod 
158*3d8817e4Smiod   tab->limit = dst;
159*3d8817e4Smiod   tab->len = tab->limit - tab->base;
160*3d8817e4Smiod 
161*3d8817e4Smiod   DBG (AOUTDEBUG | IDDEBUG,
162*3d8817e4Smiod        unsigned int j;
163*3d8817e4Smiod 
164*3d8817e4Smiod        for (j = 0; j < tab->len; ++j)
165*3d8817e4Smiod 	 {
166*3d8817e4Smiod 	   printf ("[symtab_finalize] 0x%lx-0x%lx\t%s\n",
167*3d8817e4Smiod 		 (long) tab->base[j].addr, (long) tab->base[j].end_addr,
168*3d8817e4Smiod 		 tab->base[j].name);
169*3d8817e4Smiod 	 }
170*3d8817e4Smiod   );
171*3d8817e4Smiod }
172*3d8817e4Smiod 
173*3d8817e4Smiod 
174*3d8817e4Smiod #ifdef DEBUG
175*3d8817e4Smiod 
176*3d8817e4Smiod Sym *
dbg_sym_lookup(Sym_Table * sym_tab,bfd_vma address)177*3d8817e4Smiod dbg_sym_lookup (Sym_Table *sym_tab, bfd_vma address)
178*3d8817e4Smiod {
179*3d8817e4Smiod   long low, mid, high;
180*3d8817e4Smiod   Sym *sym;
181*3d8817e4Smiod 
182*3d8817e4Smiod   fprintf (stderr, "[dbg_sym_lookup] address 0x%lx\n",
183*3d8817e4Smiod 	   (unsigned long) address);
184*3d8817e4Smiod 
185*3d8817e4Smiod   sym = sym_tab->base;
186*3d8817e4Smiod   for (low = 0, high = sym_tab->len - 1; low != high;)
187*3d8817e4Smiod     {
188*3d8817e4Smiod       mid = (high + low) >> 1;
189*3d8817e4Smiod 
190*3d8817e4Smiod       fprintf (stderr, "[dbg_sym_lookup] low=0x%lx, mid=0x%lx, high=0x%lx\n",
191*3d8817e4Smiod 	       low, mid, high);
192*3d8817e4Smiod       fprintf (stderr, "[dbg_sym_lookup] sym[m]=0x%lx sym[m + 1]=0x%lx\n",
193*3d8817e4Smiod 	       (unsigned long) sym[mid].addr,
194*3d8817e4Smiod 	       (unsigned long) sym[mid + 1].addr);
195*3d8817e4Smiod 
196*3d8817e4Smiod       if (sym[mid].addr <= address && sym[mid + 1].addr > address)
197*3d8817e4Smiod 	return &sym[mid];
198*3d8817e4Smiod 
199*3d8817e4Smiod       if (sym[mid].addr > address)
200*3d8817e4Smiod 	high = mid;
201*3d8817e4Smiod       else
202*3d8817e4Smiod 	low = mid + 1;
203*3d8817e4Smiod     }
204*3d8817e4Smiod 
205*3d8817e4Smiod   fprintf (stderr, "[dbg_sym_lookup] binary search fails???\n");
206*3d8817e4Smiod 
207*3d8817e4Smiod   return 0;
208*3d8817e4Smiod }
209*3d8817e4Smiod 
210*3d8817e4Smiod #endif	/* DEBUG */
211*3d8817e4Smiod 
212*3d8817e4Smiod 
213*3d8817e4Smiod /* Look up an address in the symbol-table that is sorted by address.
214*3d8817e4Smiod    If address does not hit any symbol, 0 is returned.  */
215*3d8817e4Smiod Sym *
sym_lookup(Sym_Table * sym_tab,bfd_vma address)216*3d8817e4Smiod sym_lookup (Sym_Table *sym_tab, bfd_vma address)
217*3d8817e4Smiod {
218*3d8817e4Smiod   long low, high;
219*3d8817e4Smiod   long mid = -1;
220*3d8817e4Smiod   Sym *sym;
221*3d8817e4Smiod #ifdef DEBUG
222*3d8817e4Smiod   int probes = 0;
223*3d8817e4Smiod #endif /* DEBUG */
224*3d8817e4Smiod 
225*3d8817e4Smiod   if (!sym_tab->len)
226*3d8817e4Smiod     return 0;
227*3d8817e4Smiod 
228*3d8817e4Smiod   sym = sym_tab->base;
229*3d8817e4Smiod   for (low = 0, high = sym_tab->len - 1; low != high;)
230*3d8817e4Smiod     {
231*3d8817e4Smiod       DBG (LOOKUPDEBUG, ++probes);
232*3d8817e4Smiod       mid = (high + low) / 2;
233*3d8817e4Smiod 
234*3d8817e4Smiod       if (sym[mid].addr <= address && sym[mid + 1].addr > address)
235*3d8817e4Smiod 	{
236*3d8817e4Smiod 	  if (address > sym[mid].end_addr)
237*3d8817e4Smiod 	    {
238*3d8817e4Smiod 	      /* Address falls into gap between
239*3d8817e4Smiod 		 sym[mid] and sym[mid + 1].  */
240*3d8817e4Smiod 	      return 0;
241*3d8817e4Smiod 	    }
242*3d8817e4Smiod 	  else
243*3d8817e4Smiod 	    {
244*3d8817e4Smiod 	      DBG (LOOKUPDEBUG,
245*3d8817e4Smiod 		   printf ("[sym_lookup] %d probes (symtab->len=%u)\n",
246*3d8817e4Smiod 			   probes, sym_tab->len - 1));
247*3d8817e4Smiod 	      return &sym[mid];
248*3d8817e4Smiod 	    }
249*3d8817e4Smiod 	}
250*3d8817e4Smiod 
251*3d8817e4Smiod       if (sym[mid].addr > address)
252*3d8817e4Smiod 	high = mid;
253*3d8817e4Smiod       else
254*3d8817e4Smiod 	low = mid + 1;
255*3d8817e4Smiod     }
256*3d8817e4Smiod 
257*3d8817e4Smiod   if (sym[mid + 1].addr <= address)
258*3d8817e4Smiod     {
259*3d8817e4Smiod       if (address > sym[mid + 1].end_addr)
260*3d8817e4Smiod 	{
261*3d8817e4Smiod 	  /* Address is beyond end of sym[mid + 1].  */
262*3d8817e4Smiod 	  return 0;
263*3d8817e4Smiod 	}
264*3d8817e4Smiod       else
265*3d8817e4Smiod 	{
266*3d8817e4Smiod 	  DBG (LOOKUPDEBUG, printf ("[sym_lookup] %d (%u) probes, fall off\n",
267*3d8817e4Smiod 				    probes, sym_tab->len - 1));
268*3d8817e4Smiod 	  return &sym[mid + 1];
269*3d8817e4Smiod 	}
270*3d8817e4Smiod     }
271*3d8817e4Smiod 
272*3d8817e4Smiod   return 0;
273*3d8817e4Smiod }
274