xref: /netbsd-src/external/gpl3/binutils/dist/gprof/source.c (revision cb63e24e8d6aae7ddac1859a9015f48b1d8bd90e)
12a6b7db3Sskrll /* source.c - Keep track of source files.
22a6b7db3Sskrll 
3*cb63e24eSchristos    Copyright (C) 2000-2024 Free Software Foundation, Inc.
42a6b7db3Sskrll 
52a6b7db3Sskrll    This file is part of GNU Binutils.
62a6b7db3Sskrll 
72a6b7db3Sskrll    This program is free software; you can redistribute it and/or modify
82a6b7db3Sskrll    it under the terms of the GNU General Public License as published by
92a6b7db3Sskrll    the Free Software Foundation; either version 3 of the License, or
102a6b7db3Sskrll    (at your option) any later version.
112a6b7db3Sskrll 
122a6b7db3Sskrll    This program is distributed in the hope that it will be useful,
132a6b7db3Sskrll    but WITHOUT ANY WARRANTY; without even the implied warranty of
142a6b7db3Sskrll    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
152a6b7db3Sskrll    GNU General Public License for more details.
162a6b7db3Sskrll 
172a6b7db3Sskrll    You should have received a copy of the GNU General Public License
182a6b7db3Sskrll    along with this program; if not, write to the Free Software
192a6b7db3Sskrll    Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston, MA
202a6b7db3Sskrll    02110-1301, USA.  */
212a6b7db3Sskrll 
222a6b7db3Sskrll #include "gprof.h"
232a6b7db3Sskrll #include "libiberty.h"
242a6b7db3Sskrll #include "filenames.h"
252a6b7db3Sskrll #include "search_list.h"
262a6b7db3Sskrll #include "source.h"
272a6b7db3Sskrll 
282a6b7db3Sskrll #define EXT_ANNO "-ann"		/* Postfix of annotated files.  */
292a6b7db3Sskrll 
302a6b7db3Sskrll /* Default option values.  */
314f645668Schristos bool create_annotation_files = false;
322a6b7db3Sskrll 
332a6b7db3Sskrll Search_List src_search_list = {0, 0};
342a6b7db3Sskrll Source_File *first_src_file = 0;
352a6b7db3Sskrll 
362a6b7db3Sskrll 
372a6b7db3Sskrll Source_File *
source_file_lookup_path(const char * path)382a6b7db3Sskrll source_file_lookup_path (const char *path)
392a6b7db3Sskrll {
402a6b7db3Sskrll   Source_File *sf;
412a6b7db3Sskrll 
422a6b7db3Sskrll   for (sf = first_src_file; sf; sf = sf->next)
432a6b7db3Sskrll     {
442a6b7db3Sskrll       if (FILENAME_CMP (path, sf->name) == 0)
452a6b7db3Sskrll 	break;
462a6b7db3Sskrll     }
472a6b7db3Sskrll 
482a6b7db3Sskrll   if (!sf)
492a6b7db3Sskrll     {
502a6b7db3Sskrll       /* Create a new source file descriptor.  */
512a6b7db3Sskrll       sf = (Source_File *) xmalloc (sizeof (*sf));
522a6b7db3Sskrll 
532a6b7db3Sskrll       memset (sf, 0, sizeof (*sf));
542a6b7db3Sskrll 
552a6b7db3Sskrll       sf->name = xstrdup (path);
562a6b7db3Sskrll       sf->next = first_src_file;
572a6b7db3Sskrll       first_src_file = sf;
582a6b7db3Sskrll     }
592a6b7db3Sskrll 
602a6b7db3Sskrll   return sf;
612a6b7db3Sskrll }
622a6b7db3Sskrll 
632a6b7db3Sskrll 
642a6b7db3Sskrll Source_File *
source_file_lookup_name(const char * filename)652a6b7db3Sskrll source_file_lookup_name (const char *filename)
662a6b7db3Sskrll {
672a6b7db3Sskrll   const char *fname;
682a6b7db3Sskrll   Source_File *sf;
692a6b7db3Sskrll 
702a6b7db3Sskrll   /* The user cannot know exactly how a filename will be stored in
712a6b7db3Sskrll      the debugging info (e.g., ../include/foo.h
722a6b7db3Sskrll      vs. /usr/include/foo.h).  So we simply compare the filename
732a6b7db3Sskrll      component of a path only.  */
742a6b7db3Sskrll   for (sf = first_src_file; sf; sf = sf->next)
752a6b7db3Sskrll     {
762a6b7db3Sskrll       fname = strrchr (sf->name, '/');
772a6b7db3Sskrll 
782a6b7db3Sskrll       if (fname)
792a6b7db3Sskrll 	++fname;
802a6b7db3Sskrll       else
812a6b7db3Sskrll 	fname = sf->name;
822a6b7db3Sskrll 
832a6b7db3Sskrll       if (FILENAME_CMP (filename, fname) == 0)
842a6b7db3Sskrll 	break;
852a6b7db3Sskrll     }
862a6b7db3Sskrll 
872a6b7db3Sskrll   return sf;
882a6b7db3Sskrll }
892a6b7db3Sskrll 
902a6b7db3Sskrll 
912a6b7db3Sskrll FILE *
annotate_source(Source_File * sf,unsigned int max_width,void (* annote)(char *,unsigned int,int,void *),void * arg)922a6b7db3Sskrll annotate_source (Source_File *sf, unsigned int max_width,
932a6b7db3Sskrll      void (*annote) (char *, unsigned int, int, void *),
942a6b7db3Sskrll      void *arg)
952a6b7db3Sskrll {
964f645668Schristos   static bool first_file = true;
972a6b7db3Sskrll   int i, line_num, nread;
984f645668Schristos   bool new_line;
992a6b7db3Sskrll   char buf[8192];
1004f645668Schristos   char *fname;
1012a6b7db3Sskrll   char *annotation, *name_only;
1022a6b7db3Sskrll   FILE *ifp, *ofp;
1032a6b7db3Sskrll   Search_List_Elem *sle = src_search_list.head;
1042a6b7db3Sskrll 
1052a6b7db3Sskrll   /* Open input file.  If open fails, walk along search-list until
1062a6b7db3Sskrll      open succeeds or reaching end of list.  */
1074f645668Schristos   fname = (char *) sf->name;
1082a6b7db3Sskrll 
1092a6b7db3Sskrll   if (IS_ABSOLUTE_PATH (sf->name))
1102a6b7db3Sskrll     sle = 0;			/* Don't use search list for absolute paths.  */
1112a6b7db3Sskrll 
1122a6b7db3Sskrll   name_only = 0;
1134f645668Schristos   while (true)
1142a6b7db3Sskrll     {
1152a6b7db3Sskrll       DBG (SRCDEBUG, printf ("[annotate_source]: looking for %s, trying %s\n",
1162a6b7db3Sskrll 			     sf->name, fname));
1172a6b7db3Sskrll 
1182a6b7db3Sskrll       ifp = fopen (fname, FOPEN_RB);
1194f645668Schristos       if (fname != sf->name)
1204f645668Schristos 	free (fname);
1212a6b7db3Sskrll       if (ifp)
1222a6b7db3Sskrll 	break;
1232a6b7db3Sskrll 
1242a6b7db3Sskrll       if (!sle && !name_only)
1252a6b7db3Sskrll 	{
1262a6b7db3Sskrll 	  name_only = strrchr (sf->name, '/');
1272a6b7db3Sskrll #ifdef HAVE_DOS_BASED_FILE_SYSTEM
1282a6b7db3Sskrll 	  {
1292a6b7db3Sskrll 	    char *bslash = strrchr (sf->name, '\\');
1302a6b7db3Sskrll 	    if (name_only == NULL || (bslash != NULL && bslash > name_only))
1312a6b7db3Sskrll 	      name_only = bslash;
1322a6b7db3Sskrll 	    if (name_only == NULL && sf->name[0] != '\0' && sf->name[1] == ':')
1332a6b7db3Sskrll 	      name_only = (char *)sf->name + 1;
1342a6b7db3Sskrll 	  }
1352a6b7db3Sskrll #endif
1362a6b7db3Sskrll 	  if (name_only)
1372a6b7db3Sskrll 	    {
1382a6b7db3Sskrll 	      /* Try search-list again, but this time with name only.  */
1392a6b7db3Sskrll 	      ++name_only;
1402a6b7db3Sskrll 	      sle = src_search_list.head;
1412a6b7db3Sskrll 	    }
1422a6b7db3Sskrll 	}
1432a6b7db3Sskrll 
1442a6b7db3Sskrll       if (sle)
1452a6b7db3Sskrll 	{
1464f645668Schristos 	  fname = xmalloc (strlen (sle->path) + 3
1474f645668Schristos 			   + strlen (name_only ? name_only : sf->name));
1482a6b7db3Sskrll 	  strcpy (fname, sle->path);
1492a6b7db3Sskrll #ifdef HAVE_DOS_BASED_FILE_SYSTEM
1502a6b7db3Sskrll 	  /* d:foo is not the same thing as d:/foo!  */
1512a6b7db3Sskrll 	  if (fname[strlen (fname) - 1] == ':')
1522a6b7db3Sskrll 	    strcat (fname, ".");
1532a6b7db3Sskrll #endif
1542a6b7db3Sskrll 	  strcat (fname, "/");
1552a6b7db3Sskrll 
1562a6b7db3Sskrll 	  if (name_only)
1572a6b7db3Sskrll 	    strcat (fname, name_only);
1582a6b7db3Sskrll 	  else
1592a6b7db3Sskrll 	    strcat (fname, sf->name);
1602a6b7db3Sskrll 
1612a6b7db3Sskrll 	  sle = sle->next;
1622a6b7db3Sskrll 	}
1632a6b7db3Sskrll       else
1642a6b7db3Sskrll 	{
1652a6b7db3Sskrll 	  if (errno == ENOENT)
1662a6b7db3Sskrll 	    fprintf (stderr, _("%s: could not locate `%s'\n"),
1672a6b7db3Sskrll 		     whoami, sf->name);
1682a6b7db3Sskrll 	  else
1692a6b7db3Sskrll 	    perror (sf->name);
1702a6b7db3Sskrll 
1712a6b7db3Sskrll 	  return 0;
1722a6b7db3Sskrll 	}
1732a6b7db3Sskrll     }
1742a6b7db3Sskrll 
1752a6b7db3Sskrll   ofp = stdout;
1762a6b7db3Sskrll 
1772a6b7db3Sskrll   if (create_annotation_files)
1782a6b7db3Sskrll     {
1792a6b7db3Sskrll       /* Try to create annotated source file.  */
1802a6b7db3Sskrll       const char *filename;
1812a6b7db3Sskrll 
1822a6b7db3Sskrll       /* Create annotation files in the current working directory.  */
1832a6b7db3Sskrll       filename = strrchr (sf->name, '/');
1842a6b7db3Sskrll #ifdef HAVE_DOS_BASED_FILE_SYSTEM
1852a6b7db3Sskrll 	{
1862a6b7db3Sskrll 	  char *bslash = strrchr (sf->name, '\\');
1872a6b7db3Sskrll 	  if (filename == NULL || (bslash != NULL && bslash > filename))
1882a6b7db3Sskrll 	    filename = bslash;
1892a6b7db3Sskrll 	  if (filename == NULL && sf->name[0] != '\0' && sf->name[1] == ':')
1902a6b7db3Sskrll 	    filename = sf->name + 1;
1912a6b7db3Sskrll 	}
1922a6b7db3Sskrll #endif
1932a6b7db3Sskrll       if (filename)
1942a6b7db3Sskrll 	++filename;
1952a6b7db3Sskrll       else
1962a6b7db3Sskrll 	filename = sf->name;
1972a6b7db3Sskrll 
1984f645668Schristos       fname = xmalloc (strlen (filename) + strlen (EXT_ANNO) + 1);
1992a6b7db3Sskrll       strcpy (fname, filename);
2002a6b7db3Sskrll       strcat (fname, EXT_ANNO);
2012a6b7db3Sskrll #ifdef __MSDOS__
2022a6b7db3Sskrll       {
2032a6b7db3Sskrll 	/* foo.cpp-ann can overwrite foo.cpp due to silent truncation of
2042a6b7db3Sskrll 	   file names on 8+3 filesystems.  Their `stat' better be good...  */
2052a6b7db3Sskrll 	struct stat buf1, buf2;
2062a6b7db3Sskrll 
2072a6b7db3Sskrll 	if (stat (filename, &buf1) == 0
2082a6b7db3Sskrll 	    && stat (fname, &buf2) == 0
2092a6b7db3Sskrll 	    && buf1.st_ino == buf2.st_ino)
2102a6b7db3Sskrll 	  {
2112a6b7db3Sskrll 	    char *dot = strrchr (fname, '.');
2122a6b7db3Sskrll 
2134f645668Schristos 	    if (!dot)
2144f645668Schristos 	      dot = fname + strlen (filename);
2154f645668Schristos 	    strcpy (dot, ".ann");
2162a6b7db3Sskrll 	  }
2172a6b7db3Sskrll       }
2182a6b7db3Sskrll #endif
2192a6b7db3Sskrll       ofp = fopen (fname, "w");
2202a6b7db3Sskrll 
2212a6b7db3Sskrll       if (!ofp)
2222a6b7db3Sskrll 	{
2232a6b7db3Sskrll 	  perror (fname);
2244f645668Schristos 	  free (fname);
2252a6b7db3Sskrll 	  return 0;
2262a6b7db3Sskrll 	}
2274f645668Schristos       free (fname);
2282a6b7db3Sskrll     }
2292a6b7db3Sskrll 
2302a6b7db3Sskrll   /* Print file names if output goes to stdout
2312a6b7db3Sskrll      and there are more than one source file.  */
2322a6b7db3Sskrll   if (ofp == stdout)
2332a6b7db3Sskrll     {
2342a6b7db3Sskrll       if (first_file)
2354f645668Schristos 	first_file = false;
2362a6b7db3Sskrll       else
2372a6b7db3Sskrll 	fputc ('\n', ofp);
2382a6b7db3Sskrll 
2392a6b7db3Sskrll       if (first_output)
2404f645668Schristos 	first_output = false;
2412a6b7db3Sskrll       else
2422a6b7db3Sskrll 	fprintf (ofp, "\f\n");
2432a6b7db3Sskrll 
2442a6b7db3Sskrll       fprintf (ofp, _("*** File %s:\n"), sf->name);
2452a6b7db3Sskrll     }
2462a6b7db3Sskrll 
247be12b8bcSchristos   annotation = (char *) xmalloc (max_width + 1);
2482a6b7db3Sskrll   line_num = 1;
2494f645668Schristos   new_line = true;
2502a6b7db3Sskrll 
2512a6b7db3Sskrll   while ((nread = fread (buf, 1, sizeof (buf), ifp)) > 0)
2522a6b7db3Sskrll     {
2532a6b7db3Sskrll       for (i = 0; i < nread; ++i)
2542a6b7db3Sskrll 	{
2552a6b7db3Sskrll 	  if (new_line)
2562a6b7db3Sskrll 	    {
2572a6b7db3Sskrll 	      (*annote) (annotation, max_width, line_num, arg);
2582a6b7db3Sskrll 	      fputs (annotation, ofp);
2592a6b7db3Sskrll 	      ++line_num;
2602a6b7db3Sskrll 	    }
2612a6b7db3Sskrll 
2622a6b7db3Sskrll 	  new_line = (buf[i] == '\n');
2632a6b7db3Sskrll 	  fputc (buf[i], ofp);
2642a6b7db3Sskrll 	}
2652a6b7db3Sskrll     }
2662a6b7db3Sskrll 
2672a6b7db3Sskrll   free (annotation);
2689573673dSchristos   fclose (ifp);
2692a6b7db3Sskrll   return ofp;
2702a6b7db3Sskrll }
271