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