This commit was generated by cvs2svn to track changes on a CVS vendor
[platform/upstream/binutils.git] / gprof / core.c
index bb849e7..597355e 100644 (file)
@@ -9,6 +9,108 @@ asymbol **core_syms;
 asection *core_text_sect;
 PTR core_text_space;
 
+int min_insn_size;
+int offset_to_code;
+
+/* For mapping symbols to specific .o files during file ordering.  */
+struct function_map {
+  char *function_name;
+  char *file_name;
+};
+
+struct function_map *symbol_map;
+int symbol_map_count;
+
+extern void i386_find_call PARAMS ((Sym *, bfd_vma, bfd_vma));
+extern void alpha_find_call PARAMS ((Sym *, bfd_vma, bfd_vma));
+extern void vax_find_call PARAMS ((Sym *, bfd_vma, bfd_vma));
+extern void tahoe_find_call PARAMS ((Sym *, bfd_vma, bfd_vma));
+extern void sparc_find_call PARAMS ((Sym *, bfd_vma, bfd_vma));
+
+static void
+DEFUN (read_function_mappings, (filename), 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);
+    }
+
+  /* First parse the mapping file so we know how big we need to
+     make our tables.  We also do some sanity checks at this
+     time.  */
+  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);
+       }
+
+      /* Just skip messages about files with no symbols.  */
+      if (!strncmp (dummy, "No symbols in ", 14))
+       {
+         fscanf (file, "\n");
+         continue;
+       }
+
+      /* Don't care what else is on this line at this point.  */
+      fscanf (file, "%[^\n]\n", dummy);
+      count++;
+    }
+
+  /* Now we know how big we need to make our table.  */
+  symbol_map = ((struct function_map *)
+               xmalloc (count * sizeof (struct function_map)));
+
+  /* Rewind the input file so we can read it again.  */
+  rewind (file);
+
+  /* Read each entry and put it into the table.  */
+  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);
+       }
+
+      /* Just skip messages about files with no symbols.  */
+      if (!strncmp (dummy, "No symbols in ", 14))
+       {
+         fscanf (file, "\n");
+         continue;
+       }
+
+      /* dummy has the filename, go ahead and copy it.  */
+      symbol_map[count].file_name = xmalloc (strlen (dummy) + 1);
+      strcpy (symbol_map[count].file_name, dummy);
+
+      /* Now we need the function name.  */
+      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++;
+    }
+
+  /* Record the size of the map table for future reference.  */
+  symbol_map_count = count;
+}
 
 void
 DEFUN (core_init, (a_out_name), const char *a_out_name)
@@ -59,6 +161,27 @@ DEFUN (core_init, (a_out_name), const char *a_out_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);
 }
 
 
@@ -90,6 +213,41 @@ DEFUN (core_get_text_space, (core_bfd), bfd * core_bfd)
 }
 
 
+void
+DEFUN (find_call, (parent, p_lowpc, p_highpc),
+       Sym * parent AND bfd_vma p_lowpc AND 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;
+
+    default:
+      fprintf (stderr, "%s: -c not supported on architecture %s\n",
+              whoami, bfd_printable_name(core_bfd));
+
+      /* Don't give the error more than once.  */
+      ignore_direct_calls = FALSE;
+    }
+}
+
 /*
  * Return class of symbol SYM.  The returned class can be any of:
  *      0   -> symbol is not interesting to us
@@ -104,15 +262,15 @@ DEFUN (core_sym_class, (sym), asymbol * sym)
   char sym_prefix;
   int i;
 
-  /*
-   * Must be a text symbol, and static text symbols don't qualify if
-   * ignore_static_funcs set.
-   */
-  if (!sym->section)
+  if (sym->section == NULL || (sym->flags & BSF_DEBUGGING) != 0)
     {
       return 0;
     }
 
+  /*
+   * Must be a text symbol, and static text symbols don't qualify if
+   * ignore_static_funcs set.
+   */
   if (ignore_static_funcs && (sym->flags & BSF_LOCAL))
     {
       DBG (AOUTDEBUG, printf ("[core_sym_class] %s: not a function\n",
@@ -128,6 +286,13 @@ DEFUN (core_sym_class, (sym), asymbol * sym)
       return i;                        /* it's a global symbol */
     }
 
+  if (i == 'W')
+    {
+      /* Treat weak symbols as text symbols.  FIXME: a weak symbol may
+         also be a data symbol.  */
+      return 'T';
+    }
+
   if (i != 't')
     {
       /* not a static text symbol */
@@ -168,7 +333,7 @@ DEFUN (core_sym_class, (sym), asymbol * sym)
    * other systems.  Perhaps it should be made configurable.
    */
   sym_prefix = bfd_get_symbol_leading_char (core_bfd);
-  if (sym_prefix && sym_prefix != sym->name[0]
+  if ((sym_prefix && sym_prefix != sym->name[0])
   /*
    * GCC may add special symbols to help gdb figure out the file
    * language.  We want to ignore these, since sometimes they mask
@@ -179,6 +344,12 @@ DEFUN (core_sym_class, (sym), asymbol * sym)
     {
       return 0;
     }
+
+  /* If the object file supports marking of function symbols, then we can
+     zap anything that doesn't have BSF_FUNCTION set.  */
+  if (ignore_non_functions && (sym->flags & BSF_FUNCTION) == 0)
+    return 0;
+
   return 't';                  /* it's a static text symbol */
 }
 
@@ -196,7 +367,7 @@ DEFUN (get_src_info, (addr, filename, name, line_num),
 
   if (bfd_find_nearest_line (core_bfd, core_text_sect, core_syms,
                             addr - core_text_sect->vma,
-                            &fname, &func_name, &l)
+                            &fname, &func_name, (unsigned int *) &l)
       && fname && func_name && l)
     {
       DBG (AOUTDEBUG, printf ("[get_src_info] 0x%lx -> %s:%d (%s)\n",
@@ -224,9 +395,8 @@ void
 DEFUN (core_create_function_syms, (core_bfd), bfd * core_bfd)
 {
   bfd_vma min_vma = ~0, max_vma = 0;
-  const char *filename, *func_name;
   int class;
-  long i;
+  long i, j, found, skip;
 
   /* pass 1 - determine upper bound on number of function names: */
   symtab.len = 0;
@@ -236,7 +406,24 @@ DEFUN (core_create_function_syms, (core_bfd), bfd * core_bfd)
        {
          continue;
        }
-      ++symtab.len;
+
+      /* This should be replaced with a binary search or hashed
+        search.  Gross. 
+
+        Don't create a symtab entry for a function that has
+        a mapping to a file, unless it's the first function
+        in the file.  */
+      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)
@@ -261,42 +448,79 @@ DEFUN (core_create_function_syms, (core_bfd), bfd * core_bfd)
                       core_syms[i]->value, core_syms[i]->name));
          continue;
        }
+      /* This should be replaced with a binary search or hashed
+        search.  Gross.   */
+
+      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);
 
       /* symbol offsets are always section-relative: */
 
       symtab.limit->addr = core_syms[i]->value + core_syms[i]->section->vma;
-      symtab.limit->name = core_syms[i]->name;
-
-#ifdef __osf__
-      /*
-       * Suppress symbols that are not function names.  This is
-       * useful to suppress code-labels and aliases.
-       *
-       * This is known to be useful under DEC's OSF/1.  Under SunOS 4.x,
-       * labels do not appear in the symbol table info, so this isn't
-       * necessary.
-       */
-      if (get_src_info (symtab.limit->addr, &filename, &func_name,
-                       &symtab.limit->line_num))
+      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->file = source_file_lookup_path (filename);
-
-         if (strcmp (symtab.limit->name, func_name) != 0)
-           {
-             /*
-              * The symbol's address maps to a different name, so
-              * it can't be a function-entry point.  This happens
-              * for labels, for example.
-              */
-             DBG (AOUTDEBUG,
-               printf ("[core_create_function_syms: rej %s (maps to %s)\n",
-                       symtab.limit->name, func_name));
-             continue;
-           }
+         symtab.limit->name = core_syms[i]->name;
+         symtab.limit->mapped = 0;
        }
+
+      /* Lookup filename and line number, if we can */
+
+      {
+       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);
+
+           /* FIXME: Checking __osf__ here does not work with a cross
+               gprof.  */
+#ifdef __osf__
+           /*
+            * Suppress symbols that are not function names.  This is
+            * useful to suppress code-labels and aliases.
+            *
+            * This is known to be useful under DEC's OSF/1.  Under SunOS 4.x,
+            * labels do not appear in the symbol table info, so this isn't
+            * necessary.
+            */
+
+           if (strcmp (symtab.limit->name, func_name) != 0)
+             {
+               /*
+                * The symbol's address maps to a different name, so
+                * it can't be a function-entry point.  This happens
+                * for labels, for example.
+                */
+               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;
@@ -352,10 +576,10 @@ DEFUN (core_create_line_syms, (core_bfd), bfd * core_bfd)
 {
   char prev_name[PATH_MAX], prev_filename[PATH_MAX];
   bfd_vma vma, min_vma = ~0, max_vma = 0;
-  bfd_vma offset, prev_offset, min_dist;
+  bfd_vma offset;
   Sym *prev, dummy, *sentinel, *sym;
   const char *filename;
-  int prev_line_num, i;
+  int prev_line_num;
   Sym_Table ltab;
   /*
    * Create symbols for functions as usual.  This is necessary in
@@ -373,18 +597,13 @@ DEFUN (core_create_line_syms, (core_bfd), bfd * core_bfd)
    * it is time to create a new symbol.
    *
    * Of course, this is rather slow and it would be better if
-   * bfd would provide an iterator for enumerating all line
-   * infos, but for now, we try to speed up the second pass
-   * by determining what the minimum code distance between two
-   * lines is.
+   * bfd would provide an iterator for enumerating all line infos
    */
   prev_name[0] = '\0';
   ltab.len = 0;
-  min_dist = core_text_sect->_raw_size;
-  prev_offset = -min_dist;
   prev_filename[0] = '\0';
   prev_line_num = 0;
-  for (offset = 0; offset < core_text_sect->_raw_size; ++offset)
+  for (offset = 0; offset < core_text_sect->_raw_size; offset += min_insn_size)
     {
       vma = core_text_sect->vma + offset;
       if (!get_src_info (vma, &filename, &dummy.name, &dummy.line_num)
@@ -400,18 +619,10 @@ DEFUN (core_create_line_syms, (core_bfd), bfd * core_bfd)
       strcpy (prev_name, dummy.name);
       strcpy (prev_filename, filename);
 
-      if (offset - prev_offset < min_dist)
-       {
-         min_dist = offset - prev_offset;
-       }
-      prev_offset = offset;
-
       min_vma = MIN (vma, min_vma);
       max_vma = MAX (vma, max_vma);
     }
 
-  DBG (AOUTDEBUG, printf ("[core_create_line_syms] min_dist=%lx\n", min_dist));
-
   /* make room for function symbols, too: */
   ltab.len += symtab.len;
   ltab.base = (Sym *) xmalloc (ltab.len * sizeof (Sym));
@@ -419,8 +630,25 @@ DEFUN (core_create_line_syms, (core_bfd), bfd * core_bfd)
 
   /* pass 2 - create symbols: */
 
+  /* We now set is_static as we go along, rather than by running
+     through the symbol table at the end.
+
+     The old way called symtab_finalize before the is_static pass,
+     causing a problem since symtab_finalize uses is_static as part of
+     its address conflict resolution algorithm.  Since global symbols
+     were prefered over static symbols, and all line symbols were
+     global at that point, static function names that conflicted with
+     their own line numbers (static, but labeled as global) were
+     rejected in favor of the line num.
+
+     This was not the desired functionality.  We always want to keep
+     our function symbols and discard any conflicting line symbols.
+     Perhaps symtab_finalize should be modified to make this
+     distinction as well, but the current fix works and the code is a
+     lot cleaner now.  */
+
   prev = 0;
-  for (offset = 0; offset < core_text_sect->_raw_size; offset += min_dist)
+  for (offset = 0; offset < core_text_sect->_raw_size; offset += min_insn_size)
     {
       sym_init (ltab.limit);
       if (!get_src_info (core_text_sect->vma + offset, &filename,
@@ -433,10 +661,27 @@ DEFUN (core_create_line_syms, (core_bfd), bfd * core_bfd)
        }
 
       /* make name pointer a malloc'ed string: */
-      ltab.limit->name = strdup (ltab.limit->name);
+      ltab.limit->name = xstrdup (ltab.limit->name);
       ltab.limit->file = source_file_lookup_path (filename);
 
       ltab.limit->addr = core_text_sect->vma + offset;
+
+      /* Set is_static based on the enclosing function, using either:
+       * 1) the previous symbol, if it's from the same function, or
+       * 2) a symtab lookup
+       */
+
+      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;
 
       /*
@@ -450,7 +695,7 @@ DEFUN (core_create_line_syms, (core_bfd), bfd * core_bfd)
        }
 
       DBG (AOUTDEBUG, printf ("[core_create_line_syms] %d %s 0x%lx\n",
-                             ltab.len, ltab.limit->name,
+                             ltab.limit - ltab.base, ltab.limit->name,
                              ltab.limit->addr));
       ++ltab.limit;
     }
@@ -477,8 +722,8 @@ DEFUN (core_create_line_syms, (core_bfd), bfd * core_bfd)
   if (ltab.limit - ltab.base != ltab.len)
     {
       fprintf (stderr,
-              "%s: somebody miscounted: ltab.len=%ld instead of %d\n",
-              whoami, (long) (ltab.limit - ltab.base), ltab.len);
+              "%s: somebody miscounted: ltab.len=%d instead of %ld\n",
+              whoami, ltab.len, (long) (ltab.limit - ltab.base));
       done (1);
     }
 
@@ -488,21 +733,4 @@ DEFUN (core_create_line_syms, (core_bfd), bfd * core_bfd)
   free (symtab.base);
   symtab = ltab;
 
-  /* now go through all core symbols and set is_static accordingly: */
-
-  for (i = 0; i < core_num_syms; ++i)
-    {
-      if (core_sym_class (core_syms[i]) == 't')
-       {
-         sym = sym_lookup (&symtab, core_syms[i]->value
-                           + core_syms[i]->section->vma);
-         do
-           {
-             sym++->is_static = TRUE;
-           }
-         while (sym->file == sym[-1].file &&
-                strcmp (sym->name, sym[-1].name) == 0);
-       }
-    }
-
 }