175fd0b74Schristos /* corefile.c
275fd0b74Schristos
3*e992f068Schristos Copyright (C) 1999-2022 Free Software Foundation, Inc.
475fd0b74Schristos
575fd0b74Schristos This file is part of GNU Binutils.
675fd0b74Schristos
775fd0b74Schristos This program is free software; you can redistribute it and/or modify
875fd0b74Schristos it under the terms of the GNU General Public License as published by
975fd0b74Schristos the Free Software Foundation; either version 3 of the License, or
1075fd0b74Schristos (at your option) any later version.
1175fd0b74Schristos
1275fd0b74Schristos This program is distributed in the hope that it will be useful,
1375fd0b74Schristos but WITHOUT ANY WARRANTY; without even the implied warranty of
1475fd0b74Schristos MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
1575fd0b74Schristos GNU General Public License for more details.
1675fd0b74Schristos
1775fd0b74Schristos You should have received a copy of the GNU General Public License
1875fd0b74Schristos along with this program; if not, write to the Free Software
1975fd0b74Schristos Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston, MA
2075fd0b74Schristos 02110-1301, USA. */
2175fd0b74Schristos
2275fd0b74Schristos #include "gprof.h"
2375fd0b74Schristos #include "libiberty.h"
2475fd0b74Schristos #include "filenames.h"
2575fd0b74Schristos #include "search_list.h"
2675fd0b74Schristos #include "source.h"
2775fd0b74Schristos #include "symtab.h"
2875fd0b74Schristos #include "hist.h"
2975fd0b74Schristos #include "corefile.h"
3075fd0b74Schristos #include "safe-ctype.h"
31ede78133Schristos #include <limits.h> /* For UINT_MAX. */
3275fd0b74Schristos
3375fd0b74Schristos #include <stdlib.h>
3475fd0b74Schristos
3575fd0b74Schristos bfd *core_bfd;
3675fd0b74Schristos static int core_num_syms;
3775fd0b74Schristos static asymbol **core_syms;
3875fd0b74Schristos asection *core_text_sect;
3975fd0b74Schristos void * core_text_space;
4075fd0b74Schristos
4175fd0b74Schristos static int min_insn_size;
4275fd0b74Schristos int offset_to_code;
4375fd0b74Schristos
4475fd0b74Schristos /* For mapping symbols to specific .o files during file ordering. */
4575fd0b74Schristos struct function_map * symbol_map;
4675fd0b74Schristos unsigned int symbol_map_count;
4775fd0b74Schristos
4875fd0b74Schristos static void read_function_mappings (const char *);
4975fd0b74Schristos static int core_sym_class (asymbol *);
50*e992f068Schristos static bool get_src_info
5175fd0b74Schristos (bfd_vma, const char **, const char **, int *);
5275fd0b74Schristos
5375fd0b74Schristos extern void i386_find_call (Sym *, bfd_vma, bfd_vma);
5475fd0b74Schristos extern void alpha_find_call (Sym *, bfd_vma, bfd_vma);
5575fd0b74Schristos extern void vax_find_call (Sym *, bfd_vma, bfd_vma);
5675fd0b74Schristos extern void sparc_find_call (Sym *, bfd_vma, bfd_vma);
5775fd0b74Schristos extern void mips_find_call (Sym *, bfd_vma, bfd_vma);
5875fd0b74Schristos extern void aarch64_find_call (Sym *, bfd_vma, bfd_vma);
5975fd0b74Schristos
6075fd0b74Schristos static void
parse_error(const char * filename)6175fd0b74Schristos parse_error (const char *filename)
6275fd0b74Schristos {
6375fd0b74Schristos fprintf (stderr, _("%s: unable to parse mapping file %s.\n"), whoami, filename);
6475fd0b74Schristos done (1);
6575fd0b74Schristos }
6675fd0b74Schristos
6775fd0b74Schristos /* Compare two function_map structs based on function name.
6875fd0b74Schristos We want to sort in ascending order. */
6975fd0b74Schristos
7075fd0b74Schristos static int
cmp_symbol_map(const void * l,const void * r)7175fd0b74Schristos cmp_symbol_map (const void * l, const void * r)
7275fd0b74Schristos {
7375fd0b74Schristos return strcmp (((struct function_map *) l)->function_name,
7475fd0b74Schristos ((struct function_map *) r)->function_name);
7575fd0b74Schristos }
7675fd0b74Schristos
77ede78133Schristos #define BUFSIZE (1024)
78ede78133Schristos /* This is BUFSIZE - 1 as a string. Suitable for use in fprintf/sscanf format strings. */
79ede78133Schristos #define STR_BUFSIZE "1023"
80ede78133Schristos
8175fd0b74Schristos static void
read_function_mappings(const char * filename)8275fd0b74Schristos read_function_mappings (const char *filename)
8375fd0b74Schristos {
8475fd0b74Schristos FILE * file = fopen (filename, "r");
85ede78133Schristos char dummy[BUFSIZE];
8675fd0b74Schristos int count = 0;
8775fd0b74Schristos unsigned int i;
8875fd0b74Schristos
8975fd0b74Schristos if (!file)
9075fd0b74Schristos {
9175fd0b74Schristos fprintf (stderr, _("%s: could not open %s.\n"), whoami, filename);
9275fd0b74Schristos done (1);
9375fd0b74Schristos }
9475fd0b74Schristos
9575fd0b74Schristos /* First parse the mapping file so we know how big we need to
9675fd0b74Schristos make our tables. We also do some sanity checks at this
9775fd0b74Schristos time. */
9875fd0b74Schristos while (!feof (file))
9975fd0b74Schristos {
10075fd0b74Schristos int matches;
10175fd0b74Schristos
102ede78133Schristos matches = fscanf (file, "%" STR_BUFSIZE "[^\n:]", dummy);
10375fd0b74Schristos if (!matches)
10475fd0b74Schristos parse_error (filename);
10575fd0b74Schristos
10675fd0b74Schristos /* Just skip messages about files with no symbols. */
10775fd0b74Schristos if (!strncmp (dummy, "No symbols in ", 14))
10875fd0b74Schristos {
10975fd0b74Schristos matches = fscanf (file, "\n");
11075fd0b74Schristos if (matches == EOF)
11175fd0b74Schristos parse_error (filename);
11275fd0b74Schristos continue;
11375fd0b74Schristos }
11475fd0b74Schristos
11575fd0b74Schristos /* Don't care what else is on this line at this point. */
116ede78133Schristos matches = fscanf (file, "%" STR_BUFSIZE "[^\n]\n", dummy);
11775fd0b74Schristos if (!matches)
11875fd0b74Schristos parse_error (filename);
11975fd0b74Schristos count++;
12075fd0b74Schristos }
12175fd0b74Schristos
12275fd0b74Schristos /* Now we know how big we need to make our table. */
12375fd0b74Schristos symbol_map = ((struct function_map *)
12475fd0b74Schristos xmalloc (count * sizeof (struct function_map)));
12575fd0b74Schristos
12675fd0b74Schristos /* Rewind the input file so we can read it again. */
12775fd0b74Schristos rewind (file);
12875fd0b74Schristos
12975fd0b74Schristos /* Read each entry and put it into the table. */
13075fd0b74Schristos count = 0;
13175fd0b74Schristos while (!feof (file))
13275fd0b74Schristos {
13375fd0b74Schristos int matches;
13475fd0b74Schristos char *tmp;
13575fd0b74Schristos
136ede78133Schristos matches = fscanf (file, "%" STR_BUFSIZE "[^\n:]", dummy);
13775fd0b74Schristos if (!matches)
13875fd0b74Schristos parse_error (filename);
13975fd0b74Schristos
14075fd0b74Schristos /* Just skip messages about files with no symbols. */
14175fd0b74Schristos if (!strncmp (dummy, "No symbols in ", 14))
14275fd0b74Schristos {
14375fd0b74Schristos matches = fscanf (file, "\n");
14475fd0b74Schristos if (matches == EOF)
14575fd0b74Schristos parse_error (filename);
14675fd0b74Schristos continue;
14775fd0b74Schristos }
14875fd0b74Schristos
14975fd0b74Schristos /* dummy has the filename, go ahead and copy it. */
15075fd0b74Schristos symbol_map[count].file_name = (char *) xmalloc (strlen (dummy) + 1);
15175fd0b74Schristos strcpy (symbol_map[count].file_name, dummy);
15275fd0b74Schristos
15375fd0b74Schristos /* Now we need the function name. */
154ede78133Schristos matches = fscanf (file, "%" STR_BUFSIZE "[^\n]\n", dummy);
15575fd0b74Schristos if (!matches)
15675fd0b74Schristos parse_error (filename);
15775fd0b74Schristos tmp = strrchr (dummy, ' ') + 1;
15875fd0b74Schristos symbol_map[count].function_name = (char *) xmalloc (strlen (tmp) + 1);
15975fd0b74Schristos strcpy (symbol_map[count].function_name, tmp);
16075fd0b74Schristos count++;
16175fd0b74Schristos }
16275fd0b74Schristos
16375fd0b74Schristos /* Record the size of the map table for future reference. */
16475fd0b74Schristos symbol_map_count = count;
16575fd0b74Schristos
16675fd0b74Schristos for (i = 0; i < symbol_map_count; ++i)
16775fd0b74Schristos if (i == 0
16875fd0b74Schristos || filename_cmp (symbol_map[i].file_name, symbol_map[i - 1].file_name))
16975fd0b74Schristos symbol_map[i].is_first = 1;
17075fd0b74Schristos
17175fd0b74Schristos qsort (symbol_map, symbol_map_count, sizeof (struct function_map), cmp_symbol_map);
17275fd0b74Schristos
17375fd0b74Schristos fclose (file);
17475fd0b74Schristos }
17575fd0b74Schristos
17675fd0b74Schristos void
core_init(const char * aout_name)17775fd0b74Schristos core_init (const char * aout_name)
17875fd0b74Schristos {
17975fd0b74Schristos int core_sym_bytes;
18075fd0b74Schristos asymbol *synthsyms;
18175fd0b74Schristos long synth_count;
18275fd0b74Schristos
18375fd0b74Schristos core_bfd = bfd_openr (aout_name, 0);
18475fd0b74Schristos
18575fd0b74Schristos if (!core_bfd)
18675fd0b74Schristos {
18775fd0b74Schristos perror (aout_name);
18875fd0b74Schristos done (1);
18975fd0b74Schristos }
19075fd0b74Schristos
191012573ebSchristos core_bfd->flags |= BFD_DECOMPRESS;
192012573ebSchristos
19375fd0b74Schristos if (!bfd_check_format (core_bfd, bfd_object))
19475fd0b74Schristos {
19575fd0b74Schristos fprintf (stderr, _("%s: %s: not in executable format\n"), whoami, aout_name);
19675fd0b74Schristos done (1);
19775fd0b74Schristos }
19875fd0b74Schristos
19975fd0b74Schristos /* Get core's text section. */
20075fd0b74Schristos core_text_sect = bfd_get_section_by_name (core_bfd, ".text");
20175fd0b74Schristos if (!core_text_sect)
20275fd0b74Schristos {
20375fd0b74Schristos core_text_sect = bfd_get_section_by_name (core_bfd, "$CODE$");
20475fd0b74Schristos if (!core_text_sect)
20575fd0b74Schristos {
20675fd0b74Schristos fprintf (stderr, _("%s: can't find .text section in %s\n"),
20775fd0b74Schristos whoami, aout_name);
20875fd0b74Schristos done (1);
20975fd0b74Schristos }
21075fd0b74Schristos }
21175fd0b74Schristos
21275fd0b74Schristos /* Read core's symbol table. */
21375fd0b74Schristos
21475fd0b74Schristos /* This will probably give us more than we need, but that's ok. */
21575fd0b74Schristos core_sym_bytes = bfd_get_symtab_upper_bound (core_bfd);
21675fd0b74Schristos if (core_sym_bytes < 0)
21775fd0b74Schristos {
21875fd0b74Schristos fprintf (stderr, "%s: %s: %s\n", whoami, aout_name,
21975fd0b74Schristos bfd_errmsg (bfd_get_error ()));
22075fd0b74Schristos done (1);
22175fd0b74Schristos }
22275fd0b74Schristos
22375fd0b74Schristos core_syms = (asymbol **) xmalloc (core_sym_bytes);
22475fd0b74Schristos core_num_syms = bfd_canonicalize_symtab (core_bfd, core_syms);
22575fd0b74Schristos
22675fd0b74Schristos if (core_num_syms < 0)
22775fd0b74Schristos {
22875fd0b74Schristos fprintf (stderr, "%s: %s: %s\n", whoami, aout_name,
22975fd0b74Schristos bfd_errmsg (bfd_get_error ()));
23075fd0b74Schristos done (1);
23175fd0b74Schristos }
23275fd0b74Schristos
23375fd0b74Schristos synth_count = bfd_get_synthetic_symtab (core_bfd, core_num_syms, core_syms,
23475fd0b74Schristos 0, NULL, &synthsyms);
23575fd0b74Schristos if (synth_count > 0)
23675fd0b74Schristos {
23775fd0b74Schristos asymbol **symp;
23875fd0b74Schristos long new_size;
23975fd0b74Schristos long i;
24075fd0b74Schristos
24175fd0b74Schristos new_size = (core_num_syms + synth_count + 1) * sizeof (*core_syms);
24275fd0b74Schristos core_syms = (asymbol **) xrealloc (core_syms, new_size);
24375fd0b74Schristos symp = core_syms + core_num_syms;
24475fd0b74Schristos core_num_syms += synth_count;
24575fd0b74Schristos for (i = 0; i < synth_count; i++)
24675fd0b74Schristos *symp++ = synthsyms + i;
24775fd0b74Schristos *symp = 0;
24875fd0b74Schristos }
24975fd0b74Schristos
25075fd0b74Schristos min_insn_size = 1;
25175fd0b74Schristos offset_to_code = 0;
25275fd0b74Schristos
25375fd0b74Schristos switch (bfd_get_arch (core_bfd))
25475fd0b74Schristos {
25575fd0b74Schristos case bfd_arch_vax:
25675fd0b74Schristos offset_to_code = 2;
25775fd0b74Schristos break;
25875fd0b74Schristos
25975fd0b74Schristos case bfd_arch_alpha:
26075fd0b74Schristos min_insn_size = 4;
26175fd0b74Schristos break;
26275fd0b74Schristos
26375fd0b74Schristos default:
26475fd0b74Schristos break;
26575fd0b74Schristos }
26675fd0b74Schristos
26775fd0b74Schristos if (function_mapping_file)
26875fd0b74Schristos read_function_mappings (function_mapping_file);
26975fd0b74Schristos }
27075fd0b74Schristos
27175fd0b74Schristos /* Read in the text space of an a.out file. */
27275fd0b74Schristos
27375fd0b74Schristos void
core_get_text_space(bfd * cbfd)27475fd0b74Schristos core_get_text_space (bfd *cbfd)
27575fd0b74Schristos {
276012573ebSchristos core_text_space = malloc (bfd_section_size (core_text_sect));
27775fd0b74Schristos
27875fd0b74Schristos if (!core_text_space)
27975fd0b74Schristos {
28075fd0b74Schristos fprintf (stderr, _("%s: ran out room for %lu bytes of text space\n"),
281012573ebSchristos whoami, (unsigned long) bfd_section_size (core_text_sect));
28275fd0b74Schristos done (1);
28375fd0b74Schristos }
28475fd0b74Schristos
28575fd0b74Schristos if (!bfd_get_section_contents (cbfd, core_text_sect, core_text_space,
286012573ebSchristos 0, bfd_section_size (core_text_sect)))
28775fd0b74Schristos {
28875fd0b74Schristos bfd_perror ("bfd_get_section_contents");
28975fd0b74Schristos free (core_text_space);
29075fd0b74Schristos core_text_space = 0;
29175fd0b74Schristos }
29275fd0b74Schristos
29375fd0b74Schristos if (!core_text_space)
29475fd0b74Schristos fprintf (stderr, _("%s: can't do -c\n"), whoami);
29575fd0b74Schristos }
29675fd0b74Schristos
29775fd0b74Schristos
29875fd0b74Schristos void
find_call(Sym * parent,bfd_vma p_lowpc,bfd_vma p_highpc)29975fd0b74Schristos find_call (Sym *parent, bfd_vma p_lowpc, bfd_vma p_highpc)
30075fd0b74Schristos {
30175fd0b74Schristos if (core_text_space == 0)
30275fd0b74Schristos return;
30375fd0b74Schristos
30475fd0b74Schristos hist_clip_symbol_address (&p_lowpc, &p_highpc);
30575fd0b74Schristos
30675fd0b74Schristos switch (bfd_get_arch (core_bfd))
30775fd0b74Schristos {
30875fd0b74Schristos case bfd_arch_i386:
30975fd0b74Schristos i386_find_call (parent, p_lowpc, p_highpc);
31075fd0b74Schristos break;
31175fd0b74Schristos
31275fd0b74Schristos case bfd_arch_alpha:
31375fd0b74Schristos alpha_find_call (parent, p_lowpc, p_highpc);
31475fd0b74Schristos break;
31575fd0b74Schristos
31675fd0b74Schristos case bfd_arch_vax:
31775fd0b74Schristos vax_find_call (parent, p_lowpc, p_highpc);
31875fd0b74Schristos break;
31975fd0b74Schristos
32075fd0b74Schristos case bfd_arch_sparc:
32175fd0b74Schristos sparc_find_call (parent, p_lowpc, p_highpc);
32275fd0b74Schristos break;
32375fd0b74Schristos
32475fd0b74Schristos case bfd_arch_mips:
32575fd0b74Schristos mips_find_call (parent, p_lowpc, p_highpc);
32675fd0b74Schristos break;
32775fd0b74Schristos
32875fd0b74Schristos case bfd_arch_aarch64:
32975fd0b74Schristos aarch64_find_call (parent, p_lowpc, p_highpc);
33075fd0b74Schristos break;
33175fd0b74Schristos
33275fd0b74Schristos default:
33375fd0b74Schristos fprintf (stderr, _("%s: -c not supported on architecture %s\n"),
33475fd0b74Schristos whoami, bfd_printable_name(core_bfd));
33575fd0b74Schristos
33675fd0b74Schristos /* Don't give the error more than once. */
337*e992f068Schristos ignore_direct_calls = false;
33875fd0b74Schristos }
33975fd0b74Schristos }
34075fd0b74Schristos
34175fd0b74Schristos /* Return class of symbol SYM. The returned class can be any of:
34275fd0b74Schristos 0 -> symbol is not interesting to us
34375fd0b74Schristos 'T' -> symbol is a global name
34475fd0b74Schristos 't' -> symbol is a local (static) name. */
34575fd0b74Schristos
34675fd0b74Schristos static int
core_sym_class(asymbol * sym)34775fd0b74Schristos core_sym_class (asymbol *sym)
34875fd0b74Schristos {
34975fd0b74Schristos symbol_info syminfo;
35075fd0b74Schristos const char *name;
35175fd0b74Schristos char sym_prefix;
35275fd0b74Schristos int i;
35375fd0b74Schristos
35475fd0b74Schristos if (sym->section == NULL || (sym->flags & BSF_DEBUGGING) != 0)
35575fd0b74Schristos return 0;
35675fd0b74Schristos
35775fd0b74Schristos /* Must be a text symbol, and static text symbols
35875fd0b74Schristos don't qualify if ignore_static_funcs set. */
35975fd0b74Schristos if (ignore_static_funcs && (sym->flags & BSF_LOCAL))
36075fd0b74Schristos {
36175fd0b74Schristos DBG (AOUTDEBUG, printf ("[core_sym_class] %s: not a function\n",
36275fd0b74Schristos sym->name));
36375fd0b74Schristos return 0;
36475fd0b74Schristos }
36575fd0b74Schristos
36675fd0b74Schristos bfd_get_symbol_info (core_bfd, sym, &syminfo);
36775fd0b74Schristos i = syminfo.type;
36875fd0b74Schristos
36975fd0b74Schristos if (i == 'T')
37075fd0b74Schristos return i; /* It's a global symbol. */
37175fd0b74Schristos
37275fd0b74Schristos if (i == 'W')
37375fd0b74Schristos /* Treat weak symbols as text symbols. FIXME: a weak symbol may
37475fd0b74Schristos also be a data symbol. */
37575fd0b74Schristos return 'T';
37675fd0b74Schristos
37775fd0b74Schristos if (i != 't')
37875fd0b74Schristos {
37975fd0b74Schristos /* Not a static text symbol. */
38075fd0b74Schristos DBG (AOUTDEBUG, printf ("[core_sym_class] %s is of class %c\n",
38175fd0b74Schristos sym->name, i));
38275fd0b74Schristos return 0;
38375fd0b74Schristos }
38475fd0b74Schristos
38575fd0b74Schristos /* Do some more filtering on static function-names. */
38675fd0b74Schristos if (ignore_static_funcs)
38775fd0b74Schristos return 0;
38875fd0b74Schristos
38975fd0b74Schristos /* Can't zero-length name or funny characters in name, where
39075fd0b74Schristos `funny' includes: `.' (.o file names) and `$' (Pascal labels). */
39175fd0b74Schristos if (!sym->name || sym->name[0] == '\0')
39275fd0b74Schristos return 0;
39375fd0b74Schristos
39475fd0b74Schristos for (name = sym->name; *name; ++name)
39575fd0b74Schristos {
39675fd0b74Schristos if (*name == '$')
39775fd0b74Schristos return 0;
39875fd0b74Schristos
39975fd0b74Schristos while (*name == '.')
40075fd0b74Schristos {
40175fd0b74Schristos /* Allow both nested subprograms (which end with ".NNN", where N is
40275fd0b74Schristos a digit) and GCC cloned functions (which contain ".clone").
40375fd0b74Schristos Allow for multiple iterations of both - apparently GCC can clone
40475fd0b74Schristos clones and subprograms. */
40575fd0b74Schristos int digit_seen = 0;
40675fd0b74Schristos #define CLONE_NAME ".clone."
40775fd0b74Schristos #define CLONE_NAME_LEN strlen (CLONE_NAME)
40875fd0b74Schristos #define CONSTPROP_NAME ".constprop."
40975fd0b74Schristos #define CONSTPROP_NAME_LEN strlen (CONSTPROP_NAME)
41075fd0b74Schristos
41175fd0b74Schristos if (strlen (name) > CLONE_NAME_LEN
41275fd0b74Schristos && strncmp (name, CLONE_NAME, CLONE_NAME_LEN) == 0)
41375fd0b74Schristos name += CLONE_NAME_LEN - 1;
41475fd0b74Schristos
41575fd0b74Schristos else if (strlen (name) > CONSTPROP_NAME_LEN
41675fd0b74Schristos && strncmp (name, CONSTPROP_NAME, CONSTPROP_NAME_LEN) == 0)
41775fd0b74Schristos name += CONSTPROP_NAME_LEN - 1;
41875fd0b74Schristos
41975fd0b74Schristos for (name++; *name; name++)
42075fd0b74Schristos if (digit_seen && *name == '.')
42175fd0b74Schristos break;
42275fd0b74Schristos else if (ISDIGIT (*name))
42375fd0b74Schristos digit_seen = 1;
42475fd0b74Schristos else
42575fd0b74Schristos return 0;
42675fd0b74Schristos }
42775fd0b74Schristos }
42875fd0b74Schristos
42975fd0b74Schristos /* On systems where the C compiler adds an underscore to all
43075fd0b74Schristos names, static names without underscores seem usually to be
43175fd0b74Schristos labels in hand written assembler in the library. We don't want
43275fd0b74Schristos these names. This is certainly necessary on a Sparc running
43375fd0b74Schristos SunOS 4.1 (try profiling a program that does a lot of
43475fd0b74Schristos division). I don't know whether it has harmful side effects on
43575fd0b74Schristos other systems. Perhaps it should be made configurable. */
43675fd0b74Schristos sym_prefix = bfd_get_symbol_leading_char (core_bfd);
43775fd0b74Schristos
43875fd0b74Schristos if ((sym_prefix && sym_prefix != sym->name[0])
43975fd0b74Schristos /* GCC may add special symbols to help gdb figure out the file
44075fd0b74Schristos language. We want to ignore these, since sometimes they mask
44175fd0b74Schristos the real function. (dj@ctron) */
44275fd0b74Schristos || !strncmp (sym->name, "__gnu_compiled", 14)
44375fd0b74Schristos || !strncmp (sym->name, "___gnu_compiled", 15))
44475fd0b74Schristos {
44575fd0b74Schristos return 0;
44675fd0b74Schristos }
44775fd0b74Schristos
44875fd0b74Schristos /* If the object file supports marking of function symbols, then
44975fd0b74Schristos we can zap anything that doesn't have BSF_FUNCTION set. */
45075fd0b74Schristos if (ignore_non_functions && (sym->flags & BSF_FUNCTION) == 0)
45175fd0b74Schristos return 0;
45275fd0b74Schristos
45375fd0b74Schristos return 't'; /* It's a static text symbol. */
45475fd0b74Schristos }
45575fd0b74Schristos
45675fd0b74Schristos /* Get whatever source info we can get regarding address ADDR. */
45775fd0b74Schristos
458*e992f068Schristos static bool
get_src_info(bfd_vma addr,const char ** filename,const char ** name,int * line_num)459*e992f068Schristos get_src_info (bfd_vma addr, const char **filename, const char **name,
460*e992f068Schristos int *line_num)
46175fd0b74Schristos {
46275fd0b74Schristos const char *fname = 0, *func_name = 0;
46375fd0b74Schristos int l = 0;
46475fd0b74Schristos
46575fd0b74Schristos if (bfd_find_nearest_line (core_bfd, core_text_sect, core_syms,
46675fd0b74Schristos addr - core_text_sect->vma,
46775fd0b74Schristos &fname, &func_name, (unsigned int *) &l)
46875fd0b74Schristos && fname && func_name && l)
46975fd0b74Schristos {
47075fd0b74Schristos DBG (AOUTDEBUG, printf ("[get_src_info] 0x%lx -> %s:%d (%s)\n",
47175fd0b74Schristos (unsigned long) addr, fname, l, func_name));
47275fd0b74Schristos *filename = fname;
47375fd0b74Schristos *name = func_name;
47475fd0b74Schristos *line_num = l;
475*e992f068Schristos return true;
47675fd0b74Schristos }
47775fd0b74Schristos else
47875fd0b74Schristos {
47975fd0b74Schristos DBG (AOUTDEBUG, printf ("[get_src_info] no info for 0x%lx (%s:%d,%s)\n",
48075fd0b74Schristos (unsigned long) addr,
48175fd0b74Schristos fname ? fname : "<unknown>", l,
48275fd0b74Schristos func_name ? func_name : "<unknown>"));
483*e992f068Schristos return false;
48475fd0b74Schristos }
48575fd0b74Schristos }
48675fd0b74Schristos
487ede78133Schristos static char buf[BUFSIZE];
488ede78133Schristos static char address[BUFSIZE];
489ede78133Schristos static char name[BUFSIZE];
490ede78133Schristos
49175fd0b74Schristos /* Return number of symbols in a symbol-table file. */
49275fd0b74Schristos
493ede78133Schristos static unsigned int
num_of_syms_in(FILE * f)49475fd0b74Schristos num_of_syms_in (FILE * f)
49575fd0b74Schristos {
49675fd0b74Schristos char type;
497ede78133Schristos unsigned int num = 0;
49875fd0b74Schristos
49975fd0b74Schristos while (!feof (f) && fgets (buf, BUFSIZE - 1, f))
50075fd0b74Schristos {
501ede78133Schristos if (sscanf (buf, "%" STR_BUFSIZE "s %c %" STR_BUFSIZE "s", address, &type, name) == 3)
50275fd0b74Schristos if (type == 't' || type == 'T')
503ede78133Schristos {
504ede78133Schristos /* PR 20499 - prevent integer overflow computing argument to xmalloc. */
505ede78133Schristos if (++num >= UINT_MAX / sizeof (Sym))
506ede78133Schristos return -1U;
50775fd0b74Schristos }
508ede78133Schristos }
50975fd0b74Schristos
51075fd0b74Schristos return num;
51175fd0b74Schristos }
51275fd0b74Schristos
51375fd0b74Schristos /* Read symbol table from a file. */
51475fd0b74Schristos
51575fd0b74Schristos void
core_create_syms_from(const char * sym_table_file)51675fd0b74Schristos core_create_syms_from (const char * sym_table_file)
51775fd0b74Schristos {
51875fd0b74Schristos char type;
51975fd0b74Schristos bfd_vma min_vma = ~(bfd_vma) 0;
52075fd0b74Schristos bfd_vma max_vma = 0;
52175fd0b74Schristos FILE * f;
52275fd0b74Schristos
52375fd0b74Schristos f = fopen (sym_table_file, "r");
52475fd0b74Schristos if (!f)
52575fd0b74Schristos {
52675fd0b74Schristos fprintf (stderr, _("%s: could not open %s.\n"), whoami, sym_table_file);
52775fd0b74Schristos done (1);
52875fd0b74Schristos }
52975fd0b74Schristos
53075fd0b74Schristos /* Pass 1 - determine upper bound on number of function names. */
53175fd0b74Schristos symtab.len = num_of_syms_in (f);
53275fd0b74Schristos
53375fd0b74Schristos if (symtab.len == 0)
53475fd0b74Schristos {
53575fd0b74Schristos fprintf (stderr, _("%s: file `%s' has no symbols\n"), whoami, sym_table_file);
53675fd0b74Schristos done (1);
53775fd0b74Schristos }
538ede78133Schristos else if (symtab.len == -1U)
539ede78133Schristos {
540ede78133Schristos fprintf (stderr, _("%s: file `%s' has too many symbols\n"),
541ede78133Schristos whoami, sym_table_file);
542ede78133Schristos done (1);
543ede78133Schristos }
54475fd0b74Schristos
54575fd0b74Schristos symtab.base = (Sym *) xmalloc (symtab.len * sizeof (Sym));
54675fd0b74Schristos
54775fd0b74Schristos /* Pass 2 - create symbols. */
54875fd0b74Schristos symtab.limit = symtab.base;
54975fd0b74Schristos
55075fd0b74Schristos if (fseek (f, 0, SEEK_SET) != 0)
55175fd0b74Schristos {
55275fd0b74Schristos perror (sym_table_file);
55375fd0b74Schristos done (1);
55475fd0b74Schristos }
55575fd0b74Schristos
55675fd0b74Schristos while (!feof (f) && fgets (buf, BUFSIZE - 1, f))
55775fd0b74Schristos {
558ede78133Schristos if (sscanf (buf, "%" STR_BUFSIZE "s %c %" STR_BUFSIZE "s", address, &type, name) != 3)
559ede78133Schristos continue;
56075fd0b74Schristos if (type != 't' && type != 'T')
56175fd0b74Schristos continue;
56275fd0b74Schristos
56375fd0b74Schristos sym_init (symtab.limit);
56475fd0b74Schristos
56575fd0b74Schristos sscanf (address, "%" BFD_VMA_FMT "x", &(symtab.limit->addr) );
56675fd0b74Schristos
56775fd0b74Schristos symtab.limit->name = (char *) xmalloc (strlen (name) + 1);
56875fd0b74Schristos strcpy ((char *) symtab.limit->name, name);
56975fd0b74Schristos symtab.limit->mapped = 0;
570*e992f068Schristos symtab.limit->is_func = true;
571*e992f068Schristos symtab.limit->is_bb_head = true;
57275fd0b74Schristos symtab.limit->is_static = (type == 't');
57375fd0b74Schristos min_vma = MIN (symtab.limit->addr, min_vma);
57475fd0b74Schristos max_vma = MAX (symtab.limit->addr, max_vma);
57575fd0b74Schristos
57675fd0b74Schristos ++symtab.limit;
57775fd0b74Schristos }
57875fd0b74Schristos fclose (f);
57975fd0b74Schristos
58075fd0b74Schristos symtab.len = symtab.limit - symtab.base;
58175fd0b74Schristos symtab_finalize (&symtab);
58275fd0b74Schristos }
58375fd0b74Schristos
58475fd0b74Schristos static int
search_mapped_symbol(const void * l,const void * r)58575fd0b74Schristos search_mapped_symbol (const void * l, const void * r)
58675fd0b74Schristos {
58775fd0b74Schristos return strcmp ((const char *) l, ((const struct function_map *) r)->function_name);
58875fd0b74Schristos }
58975fd0b74Schristos
59075fd0b74Schristos /* Read in symbol table from core.
59175fd0b74Schristos One symbol per function is entered. */
59275fd0b74Schristos
59375fd0b74Schristos void
core_create_function_syms(void)59475fd0b74Schristos core_create_function_syms (void)
59575fd0b74Schristos {
59675fd0b74Schristos bfd_vma min_vma = ~ (bfd_vma) 0;
59775fd0b74Schristos bfd_vma max_vma = 0;
59875fd0b74Schristos int cxxclass;
59975fd0b74Schristos long i;
60075fd0b74Schristos struct function_map * found = NULL;
60175fd0b74Schristos int core_has_func_syms = 0;
60275fd0b74Schristos
60375fd0b74Schristos switch (core_bfd->xvec->flavour)
60475fd0b74Schristos {
60575fd0b74Schristos default:
60675fd0b74Schristos break;
60775fd0b74Schristos case bfd_target_coff_flavour:
60875fd0b74Schristos case bfd_target_ecoff_flavour:
60975fd0b74Schristos case bfd_target_xcoff_flavour:
61075fd0b74Schristos case bfd_target_elf_flavour:
61175fd0b74Schristos case bfd_target_som_flavour:
61275fd0b74Schristos core_has_func_syms = 1;
61375fd0b74Schristos }
61475fd0b74Schristos
61575fd0b74Schristos /* Pass 1 - determine upper bound on number of function names. */
61675fd0b74Schristos symtab.len = 0;
61775fd0b74Schristos
61875fd0b74Schristos for (i = 0; i < core_num_syms; ++i)
61975fd0b74Schristos {
62075fd0b74Schristos if (!core_sym_class (core_syms[i]))
62175fd0b74Schristos continue;
62275fd0b74Schristos
62375fd0b74Schristos /* Don't create a symtab entry for a function that has
62475fd0b74Schristos a mapping to a file, unless it's the first function
62575fd0b74Schristos in the file. */
62675fd0b74Schristos if (symbol_map_count != 0)
62775fd0b74Schristos {
62875fd0b74Schristos /* Note: some systems (SunOS 5.8) crash if bsearch base argument
62975fd0b74Schristos is NULL. */
63075fd0b74Schristos found = (struct function_map *) bsearch
63175fd0b74Schristos (core_syms[i]->name, symbol_map, symbol_map_count,
63275fd0b74Schristos sizeof (struct function_map), search_mapped_symbol);
63375fd0b74Schristos }
63475fd0b74Schristos if (found == NULL || found->is_first)
63575fd0b74Schristos ++symtab.len;
63675fd0b74Schristos }
63775fd0b74Schristos
63875fd0b74Schristos if (symtab.len == 0)
63975fd0b74Schristos {
64075fd0b74Schristos fprintf (stderr, _("%s: file `%s' has no symbols\n"), whoami, a_out_name);
64175fd0b74Schristos done (1);
64275fd0b74Schristos }
64375fd0b74Schristos
64475fd0b74Schristos symtab.base = (Sym *) xmalloc (symtab.len * sizeof (Sym));
64575fd0b74Schristos
64675fd0b74Schristos /* Pass 2 - create symbols. */
64775fd0b74Schristos symtab.limit = symtab.base;
64875fd0b74Schristos
64975fd0b74Schristos for (i = 0; i < core_num_syms; ++i)
65075fd0b74Schristos {
65175fd0b74Schristos asection *sym_sec;
65275fd0b74Schristos
65375fd0b74Schristos cxxclass = core_sym_class (core_syms[i]);
65475fd0b74Schristos
65575fd0b74Schristos if (!cxxclass)
65675fd0b74Schristos {
65775fd0b74Schristos DBG (AOUTDEBUG,
65875fd0b74Schristos printf ("[core_create_function_syms] rejecting: 0x%lx %s\n",
65975fd0b74Schristos (unsigned long) core_syms[i]->value,
66075fd0b74Schristos core_syms[i]->name));
66175fd0b74Schristos continue;
66275fd0b74Schristos }
66375fd0b74Schristos
66475fd0b74Schristos if (symbol_map_count != 0)
66575fd0b74Schristos {
66675fd0b74Schristos /* Note: some systems (SunOS 5.8) crash if bsearch base argument
66775fd0b74Schristos is NULL. */
66875fd0b74Schristos found = (struct function_map *) bsearch
66975fd0b74Schristos (core_syms[i]->name, symbol_map, symbol_map_count,
67075fd0b74Schristos sizeof (struct function_map), search_mapped_symbol);
67175fd0b74Schristos }
67275fd0b74Schristos if (found && ! found->is_first)
67375fd0b74Schristos continue;
67475fd0b74Schristos
67575fd0b74Schristos sym_init (symtab.limit);
67675fd0b74Schristos
67775fd0b74Schristos /* Symbol offsets are always section-relative. */
67875fd0b74Schristos sym_sec = core_syms[i]->section;
67975fd0b74Schristos symtab.limit->addr = core_syms[i]->value;
68075fd0b74Schristos if (sym_sec)
681012573ebSchristos symtab.limit->addr += bfd_section_vma (sym_sec);
68275fd0b74Schristos
68375fd0b74Schristos if (found)
68475fd0b74Schristos {
68575fd0b74Schristos symtab.limit->name = found->file_name;
68675fd0b74Schristos symtab.limit->mapped = 1;
68775fd0b74Schristos }
68875fd0b74Schristos else
68975fd0b74Schristos {
69075fd0b74Schristos symtab.limit->name = core_syms[i]->name;
69175fd0b74Schristos symtab.limit->mapped = 0;
69275fd0b74Schristos }
69375fd0b74Schristos
69475fd0b74Schristos /* Lookup filename and line number, if we can. */
69575fd0b74Schristos {
69675fd0b74Schristos const char * filename;
69775fd0b74Schristos const char * func_name;
69875fd0b74Schristos
69975fd0b74Schristos if (get_src_info (symtab.limit->addr, & filename, & func_name,
70075fd0b74Schristos & symtab.limit->line_num))
70175fd0b74Schristos {
70275fd0b74Schristos symtab.limit->file = source_file_lookup_path (filename);
70375fd0b74Schristos
70475fd0b74Schristos /* FIXME: Checking __osf__ here does not work with a cross
70575fd0b74Schristos gprof. */
70675fd0b74Schristos #ifdef __osf__
70775fd0b74Schristos /* Suppress symbols that are not function names. This is
70875fd0b74Schristos useful to suppress code-labels and aliases.
70975fd0b74Schristos
71075fd0b74Schristos This is known to be useful under DEC's OSF/1. Under SunOS 4.x,
71175fd0b74Schristos labels do not appear in the symbol table info, so this isn't
71275fd0b74Schristos necessary. */
71375fd0b74Schristos
71475fd0b74Schristos if (strcmp (symtab.limit->name, func_name) != 0)
71575fd0b74Schristos {
71675fd0b74Schristos /* The symbol's address maps to a different name, so
71775fd0b74Schristos it can't be a function-entry point. This happens
71875fd0b74Schristos for labels, for example. */
71975fd0b74Schristos DBG (AOUTDEBUG,
72075fd0b74Schristos printf ("[core_create_function_syms: rej %s (maps to %s)\n",
72175fd0b74Schristos symtab.limit->name, func_name));
72275fd0b74Schristos continue;
72375fd0b74Schristos }
72475fd0b74Schristos #endif
72575fd0b74Schristos }
72675fd0b74Schristos }
72775fd0b74Schristos
72875fd0b74Schristos symtab.limit->is_func = (!core_has_func_syms
72975fd0b74Schristos || (core_syms[i]->flags & BSF_FUNCTION) != 0);
730*e992f068Schristos symtab.limit->is_bb_head = true;
73175fd0b74Schristos
73275fd0b74Schristos if (cxxclass == 't')
733*e992f068Schristos symtab.limit->is_static = true;
73475fd0b74Schristos
73575fd0b74Schristos /* Keep track of the minimum and maximum vma addresses used by all
73675fd0b74Schristos symbols. When computing the max_vma, use the ending address of the
73775fd0b74Schristos section containing the symbol, if available. */
73875fd0b74Schristos min_vma = MIN (symtab.limit->addr, min_vma);
73975fd0b74Schristos if (sym_sec)
740012573ebSchristos max_vma = MAX (bfd_section_vma (sym_sec)
741012573ebSchristos + bfd_section_size (sym_sec) - 1,
74275fd0b74Schristos max_vma);
74375fd0b74Schristos else
74475fd0b74Schristos max_vma = MAX (symtab.limit->addr, max_vma);
74575fd0b74Schristos
74675fd0b74Schristos DBG (AOUTDEBUG, printf ("[core_create_function_syms] %ld %s 0x%lx\n",
74775fd0b74Schristos (long) (symtab.limit - symtab.base),
74875fd0b74Schristos symtab.limit->name,
74975fd0b74Schristos (unsigned long) symtab.limit->addr));
75075fd0b74Schristos ++symtab.limit;
75175fd0b74Schristos }
75275fd0b74Schristos
75375fd0b74Schristos symtab.len = symtab.limit - symtab.base;
75475fd0b74Schristos symtab_finalize (&symtab);
75575fd0b74Schristos }
75675fd0b74Schristos
75775fd0b74Schristos /* Read in symbol table from core.
75875fd0b74Schristos One symbol per line of source code is entered. */
75975fd0b74Schristos
76075fd0b74Schristos void
core_create_line_syms(void)76175fd0b74Schristos core_create_line_syms (void)
76275fd0b74Schristos {
76375fd0b74Schristos char *prev_name, *prev_filename;
76475fd0b74Schristos unsigned int prev_name_len, prev_filename_len;
76575fd0b74Schristos bfd_vma vma, min_vma = ~(bfd_vma) 0, max_vma = 0;
76675fd0b74Schristos Sym *prev, dummy, *sym;
76775fd0b74Schristos const char *filename;
76875fd0b74Schristos int prev_line_num;
76975fd0b74Schristos Sym_Table ltab;
77075fd0b74Schristos bfd_vma vma_high;
77175fd0b74Schristos
77275fd0b74Schristos /* Create symbols for functions as usual. This is necessary in
77375fd0b74Schristos cases where parts of a program were not compiled with -g. For
77475fd0b74Schristos those parts we still want to get info at the function level. */
77575fd0b74Schristos core_create_function_syms ();
77675fd0b74Schristos
77775fd0b74Schristos /* Pass 1: count the number of symbols. */
77875fd0b74Schristos
77975fd0b74Schristos /* To find all line information, walk through all possible
78075fd0b74Schristos text-space addresses (one by one!) and get the debugging
78175fd0b74Schristos info for each address. When the debugging info changes,
78275fd0b74Schristos it is time to create a new symbol.
78375fd0b74Schristos
78475fd0b74Schristos Of course, this is rather slow and it would be better if
78575fd0b74Schristos BFD would provide an iterator for enumerating all line infos. */
786*e992f068Schristos prev_name_len = 1024;
787*e992f068Schristos prev_filename_len = 1024;
78875fd0b74Schristos prev_name = (char *) xmalloc (prev_name_len);
78975fd0b74Schristos prev_filename = (char *) xmalloc (prev_filename_len);
79075fd0b74Schristos ltab.len = 0;
79175fd0b74Schristos prev_line_num = 0;
79275fd0b74Schristos
793012573ebSchristos vma_high = core_text_sect->vma + bfd_section_size (core_text_sect);
79475fd0b74Schristos for (vma = core_text_sect->vma; vma < vma_high; vma += min_insn_size)
79575fd0b74Schristos {
79675fd0b74Schristos unsigned int len;
79775fd0b74Schristos
79875fd0b74Schristos if (!get_src_info (vma, &filename, &dummy.name, &dummy.line_num)
79975fd0b74Schristos || (prev_line_num == dummy.line_num
80075fd0b74Schristos && prev_name != NULL
80175fd0b74Schristos && strcmp (prev_name, dummy.name) == 0
80275fd0b74Schristos && filename_cmp (prev_filename, filename) == 0))
80375fd0b74Schristos continue;
80475fd0b74Schristos
80575fd0b74Schristos ++ltab.len;
80675fd0b74Schristos prev_line_num = dummy.line_num;
80775fd0b74Schristos
80875fd0b74Schristos len = strlen (dummy.name);
80975fd0b74Schristos if (len >= prev_name_len)
81075fd0b74Schristos {
81175fd0b74Schristos prev_name_len = len + 1024;
81275fd0b74Schristos free (prev_name);
81375fd0b74Schristos prev_name = (char *) xmalloc (prev_name_len);
81475fd0b74Schristos }
81575fd0b74Schristos
81675fd0b74Schristos strcpy (prev_name, dummy.name);
81775fd0b74Schristos len = strlen (filename);
81875fd0b74Schristos
81975fd0b74Schristos if (len >= prev_filename_len)
82075fd0b74Schristos {
82175fd0b74Schristos prev_filename_len = len + 1024;
82275fd0b74Schristos free (prev_filename);
82375fd0b74Schristos prev_filename = (char *) xmalloc (prev_filename_len);
82475fd0b74Schristos }
82575fd0b74Schristos
82675fd0b74Schristos strcpy (prev_filename, filename);
82775fd0b74Schristos
82875fd0b74Schristos min_vma = MIN (vma, min_vma);
82975fd0b74Schristos max_vma = MAX (vma, max_vma);
83075fd0b74Schristos }
83175fd0b74Schristos
83275fd0b74Schristos free (prev_name);
83375fd0b74Schristos free (prev_filename);
83475fd0b74Schristos
83575fd0b74Schristos /* Make room for function symbols, too. */
83675fd0b74Schristos ltab.len += symtab.len;
83775fd0b74Schristos ltab.base = (Sym *) xmalloc (ltab.len * sizeof (Sym));
83875fd0b74Schristos ltab.limit = ltab.base;
83975fd0b74Schristos
84075fd0b74Schristos /* Pass 2 - create symbols. */
84175fd0b74Schristos
84275fd0b74Schristos /* We now set is_static as we go along, rather than by running
84375fd0b74Schristos through the symbol table at the end.
84475fd0b74Schristos
84575fd0b74Schristos The old way called symtab_finalize before the is_static pass,
84675fd0b74Schristos causing a problem since symtab_finalize uses is_static as part of
84775fd0b74Schristos its address conflict resolution algorithm. Since global symbols
848ede78133Schristos were preferred over static symbols, and all line symbols were
84975fd0b74Schristos global at that point, static function names that conflicted with
85075fd0b74Schristos their own line numbers (static, but labeled as global) were
85175fd0b74Schristos rejected in favor of the line num.
85275fd0b74Schristos
85375fd0b74Schristos This was not the desired functionality. We always want to keep
85475fd0b74Schristos our function symbols and discard any conflicting line symbols.
85575fd0b74Schristos Perhaps symtab_finalize should be modified to make this
85675fd0b74Schristos distinction as well, but the current fix works and the code is a
85775fd0b74Schristos lot cleaner now. */
85875fd0b74Schristos prev = 0;
85975fd0b74Schristos
86075fd0b74Schristos for (vma = core_text_sect->vma; vma < vma_high; vma += min_insn_size)
86175fd0b74Schristos {
86275fd0b74Schristos sym_init (ltab.limit);
86375fd0b74Schristos
86475fd0b74Schristos if (!get_src_info (vma, &filename, <ab.limit->name, <ab.limit->line_num)
86575fd0b74Schristos || (prev && prev->line_num == ltab.limit->line_num
86675fd0b74Schristos && strcmp (prev->name, ltab.limit->name) == 0
86775fd0b74Schristos && filename_cmp (prev->file->name, filename) == 0))
86875fd0b74Schristos continue;
86975fd0b74Schristos
87075fd0b74Schristos /* Make name pointer a malloc'ed string. */
87175fd0b74Schristos ltab.limit->name = xstrdup (ltab.limit->name);
87275fd0b74Schristos ltab.limit->file = source_file_lookup_path (filename);
87375fd0b74Schristos
87475fd0b74Schristos ltab.limit->addr = vma;
87575fd0b74Schristos
87675fd0b74Schristos /* Set is_static based on the enclosing function, using either:
87775fd0b74Schristos 1) the previous symbol, if it's from the same function, or
87875fd0b74Schristos 2) a symtab lookup. */
87975fd0b74Schristos if (prev && ltab.limit->file == prev->file &&
88075fd0b74Schristos strcmp (ltab.limit->name, prev->name) == 0)
88175fd0b74Schristos {
88275fd0b74Schristos ltab.limit->is_static = prev->is_static;
88375fd0b74Schristos }
88475fd0b74Schristos else
88575fd0b74Schristos {
88675fd0b74Schristos sym = sym_lookup(&symtab, ltab.limit->addr);
88775fd0b74Schristos if (sym)
88875fd0b74Schristos ltab.limit->is_static = sym->is_static;
88975fd0b74Schristos }
89075fd0b74Schristos
89175fd0b74Schristos prev = ltab.limit;
89275fd0b74Schristos
89375fd0b74Schristos DBG (AOUTDEBUG, printf ("[core_create_line_syms] %lu %s 0x%lx\n",
89475fd0b74Schristos (unsigned long) (ltab.limit - ltab.base),
89575fd0b74Schristos ltab.limit->name,
89675fd0b74Schristos (unsigned long) ltab.limit->addr));
89775fd0b74Schristos ++ltab.limit;
89875fd0b74Schristos }
89975fd0b74Schristos
90075fd0b74Schristos /* Copy in function symbols. */
90175fd0b74Schristos memcpy (ltab.limit, symtab.base, symtab.len * sizeof (Sym));
90275fd0b74Schristos ltab.limit += symtab.len;
90375fd0b74Schristos
90475fd0b74Schristos if ((unsigned int) (ltab.limit - ltab.base) != ltab.len)
90575fd0b74Schristos {
90675fd0b74Schristos fprintf (stderr,
90775fd0b74Schristos _("%s: somebody miscounted: ltab.len=%d instead of %ld\n"),
90875fd0b74Schristos whoami, ltab.len, (long) (ltab.limit - ltab.base));
90975fd0b74Schristos done (1);
91075fd0b74Schristos }
91175fd0b74Schristos
91275fd0b74Schristos /* Finalize ltab and make it symbol table. */
91375fd0b74Schristos symtab_finalize (<ab);
91475fd0b74Schristos free (symtab.base);
91575fd0b74Schristos symtab = ltab;
91675fd0b74Schristos }
917