#include "libiberty.h"
#include "gprof.h"
#include "search_list.h"
#include "source.h"
#include "symtab.h"
#include "corefile.h"
bfd *core_bfd;
int core_num_syms;
asymbol **core_syms;
asection *core_text_sect;
PTR core_text_space;
int min_insn_size;
int offset_to_code;
struct function_map *symbol_map;
unsigned int symbol_map_count;
static void read_function_mappings (const char *);
static int core_sym_class (asymbol *);
static bfd_boolean get_src_info
(bfd_vma, const char **, const char **, int *);
extern void i386_find_call (Sym *, bfd_vma, bfd_vma);
extern void alpha_find_call (Sym *, bfd_vma, bfd_vma);
extern void vax_find_call (Sym *, bfd_vma, bfd_vma);
extern void tahoe_find_call (Sym *, bfd_vma, bfd_vma);
extern void sparc_find_call (Sym *, bfd_vma, bfd_vma);
extern void mips_find_call (Sym *, bfd_vma, bfd_vma);
static void
read_function_mappings (const char *filename)
{
FILE *file = fopen (filename, "r");
char dummy[1024];
int count = 0;
if (!file)
{
fprintf (stderr, _("%s: could not open %s.\n"), whoami, filename);
done (1);
}
while (!feof (file))
{
int matches;
matches = fscanf (file, "%[^\n:]", dummy);
if (!matches)
{
fprintf (stderr, _("%s: unable to parse mapping file %s.\n"),
whoami, filename);
done (1);
}
if (!strncmp (dummy, "No symbols in ", 14))
{
fscanf (file, "\n");
continue;
}
fscanf (file, "%[^\n]\n", dummy);
count++;
}
symbol_map = ((struct function_map *)
xmalloc (count * sizeof (struct function_map)));
rewind (file);
count = 0;
while (!feof (file))
{
int matches;
char *tmp;
matches = fscanf (file, "%[^\n:]", dummy);
if (!matches)
{
fprintf (stderr, _("%s: unable to parse mapping file %s.\n"),
whoami, filename);
done (1);
}
if (!strncmp (dummy, "No symbols in ", 14))
{
fscanf (file, "\n");
continue;
}
symbol_map[count].file_name = xmalloc (strlen (dummy) + 1);
strcpy (symbol_map[count].file_name, dummy);
fscanf (file, "%[^\n]\n", dummy);
tmp = strrchr (dummy, ' ') + 1;
symbol_map[count].function_name = xmalloc (strlen (tmp) + 1);
strcpy (symbol_map[count].function_name, tmp);
count++;
}
symbol_map_count = count;
}
void
core_init (const char *aout_name)
{
int core_sym_bytes;
core_bfd = bfd_openr (aout_name, 0);
if (!core_bfd)
{
perror (aout_name);
done (1);
}
if (!bfd_check_format (core_bfd, bfd_object))
{
fprintf (stderr, _("%s: %s: not in a.out format\n"), whoami, aout_name);
done (1);
}
core_text_sect = bfd_get_section_by_name (core_bfd, ".text");
if (!core_text_sect)
{
core_text_sect = bfd_get_section_by_name (core_bfd, "$CODE$");
if (!core_text_sect)
{
fprintf (stderr, _("%s: can't find .text section in %s\n"),
whoami, aout_name);
done (1);
}
}
core_sym_bytes = bfd_get_symtab_upper_bound (core_bfd);
if (core_sym_bytes < 0)
{
fprintf (stderr, "%s: %s: %s\n", whoami, aout_name,
bfd_errmsg (bfd_get_error ()));
done (1);
}
core_syms = (asymbol **) xmalloc (core_sym_bytes);
core_num_syms = bfd_canonicalize_symtab (core_bfd, core_syms);
if (core_num_syms < 0)
{
fprintf (stderr, "%s: %s: %s\n", whoami, aout_name,
bfd_errmsg (bfd_get_error ()));
done (1);
}
min_insn_size = 1;
offset_to_code = 0;
switch (bfd_get_arch (core_bfd))
{
case bfd_arch_vax:
case bfd_arch_tahoe:
offset_to_code = 2;
break;
case bfd_arch_alpha:
min_insn_size = 4;
break;
default:
break;
}
if (function_mapping_file)
read_function_mappings (function_mapping_file);
}
void
core_get_text_space (bfd *cbfd)
{
core_text_space = malloc (bfd_get_section_size (core_text_sect));
if (!core_text_space)
{
fprintf (stderr, _("%s: ran out room for %lu bytes of text space\n"),
whoami, (unsigned long) bfd_get_section_size (core_text_sect));
done (1);
}
if (!bfd_get_section_contents (cbfd, core_text_sect, core_text_space,
0, bfd_get_section_size (core_text_sect)))
{
bfd_perror ("bfd_get_section_contents");
free (core_text_space);
core_text_space = 0;
}
if (!core_text_space)
fprintf (stderr, _("%s: can't do -c\n"), whoami);
}
void
find_call (Sym *parent, bfd_vma p_lowpc, bfd_vma p_highpc)
{
switch (bfd_get_arch (core_bfd))
{
case bfd_arch_i386:
i386_find_call (parent, p_lowpc, p_highpc);
break;
case bfd_arch_alpha:
alpha_find_call (parent, p_lowpc, p_highpc);
break;
case bfd_arch_vax:
vax_find_call (parent, p_lowpc, p_highpc);
break;
case bfd_arch_sparc:
sparc_find_call (parent, p_lowpc, p_highpc);
break;
case bfd_arch_tahoe:
tahoe_find_call (parent, p_lowpc, p_highpc);
break;
case bfd_arch_mips:
mips_find_call (parent, p_lowpc, p_highpc);
break;
default:
fprintf (stderr, _("%s: -c not supported on architecture %s\n"),
whoami, bfd_printable_name(core_bfd));
ignore_direct_calls = FALSE;
}
}
static int
core_sym_class (asymbol *sym)
{
symbol_info syminfo;
const char *name;
char sym_prefix;
int i;
if (sym->section == NULL || (sym->flags & BSF_DEBUGGING) != 0)
return 0;
if (ignore_static_funcs && (sym->flags & BSF_LOCAL))
{
DBG (AOUTDEBUG, printf ("[core_sym_class] %s: not a function\n",
sym->name));
return 0;
}
bfd_get_symbol_info (core_bfd, sym, &syminfo);
i = syminfo.type;
if (i == 'T')
return i;
if (i == 'W')
return 'T';
if (i != 't')
{
DBG (AOUTDEBUG, printf ("[core_sym_class] %s is of class %c\n",
sym->name, i));
return 0;
}
if (ignore_static_funcs)
return 0;
if (!sym->name || sym->name[0] == '\0')
return 0;
for (name = sym->name; *name; ++name)
{
if (*name == '.' || *name == '$')
return 0;
}
sym_prefix = bfd_get_symbol_leading_char (core_bfd);
if ((sym_prefix && sym_prefix != sym->name[0])
|| !strncmp (sym->name, "__gnu_compiled", 14)
|| !strncmp (sym->name, "___gnu_compiled", 15))
{
return 0;
}
if (ignore_non_functions && (sym->flags & BSF_FUNCTION) == 0)
return 0;
return 't';
}
static bfd_boolean
get_src_info (bfd_vma addr, const char **filename, const char **name, int *line_num)
{
const char *fname = 0, *func_name = 0;
int l = 0;
if (bfd_find_nearest_line (core_bfd, core_text_sect, core_syms,
addr - core_text_sect->vma,
&fname, &func_name, (unsigned int *) &l)
&& fname && func_name && l)
{
DBG (AOUTDEBUG, printf ("[get_src_info] 0x%lx -> %s:%d (%s)\n",
(unsigned long) addr, fname, l, func_name));
*filename = fname;
*name = func_name;
*line_num = l;
return TRUE;
}
else
{
DBG (AOUTDEBUG, printf ("[get_src_info] no info for 0x%lx (%s:%d,%s)\n",
(long) addr, fname ? fname : "<unknown>", l,
func_name ? func_name : "<unknown>"));
return FALSE;
}
}
void
core_create_function_syms ()
{
bfd_vma min_vma = ~(bfd_vma) 0;
bfd_vma max_vma = 0;
int class;
long i, found, skip;
unsigned int j;
symtab.len = 0;
for (i = 0; i < core_num_syms; ++i)
{
if (!core_sym_class (core_syms[i]))
continue;
skip = 0;
for (j = 0; j < symbol_map_count; j++)
if (!strcmp (core_syms[i]->name, symbol_map[j].function_name))
{
if (j > 0 && ! strcmp (symbol_map [j].file_name,
symbol_map [j - 1].file_name))
skip = 1;
break;
}
if (!skip)
++symtab.len;
}
if (symtab.len == 0)
{
fprintf (stderr, _("%s: file `%s' has no symbols\n"), whoami, a_out_name);
done (1);
}
symtab.base = (Sym *) xmalloc ((symtab.len + 2) * sizeof (Sym));
symtab.limit = symtab.base;
for (i = 0; i < core_num_syms; ++i)
{
asection *sym_sec;
class = core_sym_class (core_syms[i]);
if (!class)
{
DBG (AOUTDEBUG,
printf ("[core_create_function_syms] rejecting: 0x%lx %s\n",
(unsigned long) core_syms[i]->value,
core_syms[i]->name));
continue;
}
skip = 0;
found = 0;
for (j = 0; j < symbol_map_count; j++)
if (!strcmp (core_syms[i]->name, symbol_map[j].function_name))
{
if (j > 0 && ! strcmp (symbol_map [j].file_name,
symbol_map [j - 1].file_name))
skip = 1;
else
found = j;
break;
}
if (skip)
continue;
sym_init (symtab.limit);
sym_sec = core_syms[i]->section;
symtab.limit->addr = core_syms[i]->value;
if (sym_sec)
symtab.limit->addr += bfd_get_section_vma (sym_sec->owner, sym_sec);
if (symbol_map_count
&& !strcmp (core_syms[i]->name, symbol_map[found].function_name))
{
symtab.limit->name = symbol_map[found].file_name;
symtab.limit->mapped = 1;
}
else
{
symtab.limit->name = core_syms[i]->name;
symtab.limit->mapped = 0;
}
{
const char *filename, *func_name;
if (get_src_info (symtab.limit->addr, &filename, &func_name,
&symtab.limit->line_num))
{
symtab.limit->file = source_file_lookup_path (filename);
#ifdef __osf__
if (strcmp (symtab.limit->name, func_name) != 0)
{
DBG (AOUTDEBUG,
printf ("[core_create_function_syms: rej %s (maps to %s)\n",
symtab.limit->name, func_name));
continue;
}
#endif
}
}
symtab.limit->is_func = TRUE;
symtab.limit->is_bb_head = TRUE;
if (class == 't')
symtab.limit->is_static = TRUE;
min_vma = MIN (symtab.limit->addr, min_vma);
if (sym_sec)
max_vma = MAX (bfd_get_section_vma (sym_sec->owner, sym_sec)
+ bfd_section_size (sym_sec->owner, sym_sec) - 1,
max_vma);
else
max_vma = MAX (symtab.limit->addr, max_vma);
if (symtab.limit->name[0] == 'm' && discard_underscores
&& strcmp (symtab.limit->name, "main") == 0)
discard_underscores = 0;
DBG (AOUTDEBUG, printf ("[core_create_function_syms] %ld %s 0x%lx\n",
(long) (symtab.limit - symtab.base),
symtab.limit->name,
(unsigned long) symtab.limit->addr));
++symtab.limit;
}
sym_init (symtab.limit);
symtab.limit->name = "<locore>";
symtab.limit->addr = 0;
symtab.limit->end_addr = min_vma - 1;
++symtab.limit;
sym_init (symtab.limit);
symtab.limit->name = "<hicore>";
symtab.limit->addr = max_vma + 1;
symtab.limit->end_addr = ~(bfd_vma) 0;
++symtab.limit;
symtab.len = symtab.limit - symtab.base;
symtab_finalize (&symtab);
}
void
core_create_line_syms ()
{
char *prev_name, *prev_filename;
unsigned int prev_name_len, prev_filename_len;
bfd_vma vma, min_vma = ~(bfd_vma) 0, max_vma = 0;
Sym *prev, dummy, *sentinel, *sym;
const char *filename;
int prev_line_num;
Sym_Table ltab;
bfd_vma vma_high;
core_create_function_syms ();
prev_name_len = PATH_MAX;
prev_filename_len = PATH_MAX;
prev_name = xmalloc (prev_name_len);
prev_filename = xmalloc (prev_filename_len);
ltab.len = 0;
prev_line_num = 0;
vma_high = core_text_sect->vma + bfd_get_section_size (core_text_sect);
for (vma = core_text_sect->vma; vma < vma_high; vma += min_insn_size)
{
unsigned int len;
if (!get_src_info (vma, &filename, &dummy.name, &dummy.line_num)
|| (prev_line_num == dummy.line_num
&& prev_name != NULL
&& strcmp (prev_name, dummy.name) == 0
&& strcmp (prev_filename, filename) == 0))
continue;
++ltab.len;
prev_line_num = dummy.line_num;
len = strlen (dummy.name);
if (len >= prev_name_len)
{
prev_name_len = len + 1024;
free (prev_name);
prev_name = xmalloc (prev_name_len);
}
strcpy (prev_name, dummy.name);
len = strlen (filename);
if (len >= prev_filename_len)
{
prev_filename_len = len + 1024;
free (prev_filename);
prev_filename = xmalloc (prev_filename_len);
}
strcpy (prev_filename, filename);
min_vma = MIN (vma, min_vma);
max_vma = MAX (vma, max_vma);
}
free (prev_name);
free (prev_filename);
ltab.len += symtab.len;
ltab.base = (Sym *) xmalloc (ltab.len * sizeof (Sym));
ltab.limit = ltab.base;
prev = 0;
for (vma = core_text_sect->vma; vma < vma_high; vma += min_insn_size)
{
sym_init (ltab.limit);
if (!get_src_info (vma, &filename, <ab.limit->name, <ab.limit->line_num)
|| (prev && prev->line_num == ltab.limit->line_num
&& strcmp (prev->name, ltab.limit->name) == 0
&& strcmp (prev->file->name, filename) == 0))
continue;
ltab.limit->name = xstrdup (ltab.limit->name);
ltab.limit->file = source_file_lookup_path (filename);
ltab.limit->addr = vma;
if (prev && ltab.limit->file == prev->file &&
strcmp (ltab.limit->name, prev->name) == 0)
{
ltab.limit->is_static = prev->is_static;
}
else
{
sym = sym_lookup(&symtab, ltab.limit->addr);
ltab.limit->is_static = sym->is_static;
}
prev = ltab.limit;
if (ltab.limit->name[0] == 'm' && discard_underscores
&& strcmp (ltab.limit->name, "main") == 0)
discard_underscores = 0;
DBG (AOUTDEBUG, printf ("[core_create_line_syms] %lu %s 0x%lx\n",
(unsigned long) (ltab.limit - ltab.base),
ltab.limit->name,
(unsigned long) ltab.limit->addr));
++ltab.limit;
}
sentinel = sym_lookup (&symtab, (bfd_vma) 0);
if (sentinel
&& strcmp (sentinel->name, "<locore>") == 0
&& min_vma <= sentinel->end_addr)
sentinel->end_addr = min_vma - 1;
sentinel = sym_lookup (&symtab, ~(bfd_vma) 0);
if (sentinel
&& strcmp (sentinel->name, "<hicore>") == 0
&& max_vma >= sentinel->addr)
sentinel->addr = max_vma + 1;
memcpy (ltab.limit, symtab.base, symtab.len * sizeof (Sym));
ltab.limit += symtab.len;
if ((unsigned int) (ltab.limit - ltab.base) != ltab.len)
{
fprintf (stderr,
_("%s: somebody miscounted: ltab.len=%d instead of %ld\n"),
whoami, ltab.len, (long) (ltab.limit - ltab.base));
done (1);
}
symtab_finalize (<ab);
free (symtab.base);
symtab = ltab;
}