Home | History | Annotate | Line # | Download | only in gprof
source.c revision 1.1.1.8
      1      1.1  christos /* source.c - Keep track of source files.
      2      1.1  christos 
      3  1.1.1.8  christos    Copyright (C) 2000-2025 Free Software Foundation, Inc.
      4      1.1  christos 
      5      1.1  christos    This file is part of GNU Binutils.
      6      1.1  christos 
      7      1.1  christos    This program is free software; you can redistribute it and/or modify
      8      1.1  christos    it under the terms of the GNU General Public License as published by
      9      1.1  christos    the Free Software Foundation; either version 3 of the License, or
     10      1.1  christos    (at your option) any later version.
     11      1.1  christos 
     12      1.1  christos    This program is distributed in the hope that it will be useful,
     13      1.1  christos    but WITHOUT ANY WARRANTY; without even the implied warranty of
     14      1.1  christos    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
     15      1.1  christos    GNU General Public License for more details.
     16      1.1  christos 
     17      1.1  christos    You should have received a copy of the GNU General Public License
     18      1.1  christos    along with this program; if not, write to the Free Software
     19      1.1  christos    Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston, MA
     20      1.1  christos    02110-1301, USA.  */
     21  1.1.1.8  christos 
     22      1.1  christos #include "gprof.h"
     23      1.1  christos #include "libiberty.h"
     24      1.1  christos #include "filenames.h"
     25      1.1  christos #include "search_list.h"
     26      1.1  christos #include "source.h"
     27      1.1  christos 
     28      1.1  christos #define EXT_ANNO "-ann"		/* Postfix of annotated files.  */
     29      1.1  christos 
     30      1.1  christos /* Default option values.  */
     31  1.1.1.6  christos bool create_annotation_files = false;
     32      1.1  christos 
     33      1.1  christos Search_List src_search_list = {0, 0};
     34      1.1  christos Source_File *first_src_file = 0;
     35      1.1  christos 
     36      1.1  christos 
     37      1.1  christos Source_File *
     38      1.1  christos source_file_lookup_path (const char *path)
     39      1.1  christos {
     40      1.1  christos   Source_File *sf;
     41      1.1  christos 
     42      1.1  christos   for (sf = first_src_file; sf; sf = sf->next)
     43      1.1  christos     {
     44      1.1  christos       if (FILENAME_CMP (path, sf->name) == 0)
     45      1.1  christos 	break;
     46      1.1  christos     }
     47      1.1  christos 
     48      1.1  christos   if (!sf)
     49      1.1  christos     {
     50      1.1  christos       /* Create a new source file descriptor.  */
     51      1.1  christos       sf = (Source_File *) xmalloc (sizeof (*sf));
     52      1.1  christos 
     53      1.1  christos       memset (sf, 0, sizeof (*sf));
     54      1.1  christos 
     55      1.1  christos       sf->name = xstrdup (path);
     56      1.1  christos       sf->next = first_src_file;
     57      1.1  christos       first_src_file = sf;
     58      1.1  christos     }
     59      1.1  christos 
     60      1.1  christos   return sf;
     61      1.1  christos }
     62      1.1  christos 
     63      1.1  christos 
     64      1.1  christos Source_File *
     65      1.1  christos source_file_lookup_name (const char *filename)
     66      1.1  christos {
     67      1.1  christos   const char *fname;
     68      1.1  christos   Source_File *sf;
     69      1.1  christos 
     70      1.1  christos   /* The user cannot know exactly how a filename will be stored in
     71      1.1  christos      the debugging info (e.g., ../include/foo.h
     72      1.1  christos      vs. /usr/include/foo.h).  So we simply compare the filename
     73      1.1  christos      component of a path only.  */
     74      1.1  christos   for (sf = first_src_file; sf; sf = sf->next)
     75      1.1  christos     {
     76      1.1  christos       fname = strrchr (sf->name, '/');
     77      1.1  christos 
     78      1.1  christos       if (fname)
     79      1.1  christos 	++fname;
     80      1.1  christos       else
     81      1.1  christos 	fname = sf->name;
     82      1.1  christos 
     83      1.1  christos       if (FILENAME_CMP (filename, fname) == 0)
     84      1.1  christos 	break;
     85      1.1  christos     }
     86      1.1  christos 
     87      1.1  christos   return sf;
     88      1.1  christos }
     89      1.1  christos 
     90      1.1  christos 
     91      1.1  christos FILE *
     92      1.1  christos annotate_source (Source_File *sf, unsigned int max_width,
     93      1.1  christos      void (*annote) (char *, unsigned int, int, void *),
     94      1.1  christos      void *arg)
     95      1.1  christos {
     96  1.1.1.6  christos   static bool first_file = true;
     97      1.1  christos   int i, line_num, nread;
     98  1.1.1.6  christos   bool new_line;
     99      1.1  christos   char buf[8192];
    100  1.1.1.6  christos   char *fname;
    101      1.1  christos   char *annotation, *name_only;
    102      1.1  christos   FILE *ifp, *ofp;
    103      1.1  christos   Search_List_Elem *sle = src_search_list.head;
    104      1.1  christos 
    105      1.1  christos   /* Open input file.  If open fails, walk along search-list until
    106      1.1  christos      open succeeds or reaching end of list.  */
    107  1.1.1.6  christos   fname = (char *) sf->name;
    108      1.1  christos 
    109      1.1  christos   if (IS_ABSOLUTE_PATH (sf->name))
    110      1.1  christos     sle = 0;			/* Don't use search list for absolute paths.  */
    111      1.1  christos 
    112      1.1  christos   name_only = 0;
    113  1.1.1.6  christos   while (true)
    114      1.1  christos     {
    115      1.1  christos       DBG (SRCDEBUG, printf ("[annotate_source]: looking for %s, trying %s\n",
    116      1.1  christos 			     sf->name, fname));
    117      1.1  christos 
    118      1.1  christos       ifp = fopen (fname, FOPEN_RB);
    119  1.1.1.6  christos       if (fname != sf->name)
    120  1.1.1.6  christos 	free (fname);
    121      1.1  christos       if (ifp)
    122      1.1  christos 	break;
    123      1.1  christos 
    124      1.1  christos       if (!sle && !name_only)
    125      1.1  christos 	{
    126      1.1  christos 	  name_only = strrchr (sf->name, '/');
    127      1.1  christos #ifdef HAVE_DOS_BASED_FILE_SYSTEM
    128      1.1  christos 	  {
    129      1.1  christos 	    char *bslash = strrchr (sf->name, '\\');
    130      1.1  christos 	    if (name_only == NULL || (bslash != NULL && bslash > name_only))
    131      1.1  christos 	      name_only = bslash;
    132      1.1  christos 	    if (name_only == NULL && sf->name[0] != '\0' && sf->name[1] == ':')
    133      1.1  christos 	      name_only = (char *)sf->name + 1;
    134      1.1  christos 	  }
    135      1.1  christos #endif
    136      1.1  christos 	  if (name_only)
    137      1.1  christos 	    {
    138      1.1  christos 	      /* Try search-list again, but this time with name only.  */
    139      1.1  christos 	      ++name_only;
    140      1.1  christos 	      sle = src_search_list.head;
    141      1.1  christos 	    }
    142      1.1  christos 	}
    143      1.1  christos 
    144      1.1  christos       if (sle)
    145      1.1  christos 	{
    146  1.1.1.6  christos 	  fname = xmalloc (strlen (sle->path) + 3
    147  1.1.1.6  christos 			   + strlen (name_only ? name_only : sf->name));
    148      1.1  christos 	  strcpy (fname, sle->path);
    149      1.1  christos #ifdef HAVE_DOS_BASED_FILE_SYSTEM
    150      1.1  christos 	  /* d:foo is not the same thing as d:/foo!  */
    151      1.1  christos 	  if (fname[strlen (fname) - 1] == ':')
    152      1.1  christos 	    strcat (fname, ".");
    153      1.1  christos #endif
    154      1.1  christos 	  strcat (fname, "/");
    155      1.1  christos 
    156      1.1  christos 	  if (name_only)
    157      1.1  christos 	    strcat (fname, name_only);
    158      1.1  christos 	  else
    159      1.1  christos 	    strcat (fname, sf->name);
    160      1.1  christos 
    161      1.1  christos 	  sle = sle->next;
    162      1.1  christos 	}
    163      1.1  christos       else
    164      1.1  christos 	{
    165      1.1  christos 	  if (errno == ENOENT)
    166      1.1  christos 	    fprintf (stderr, _("%s: could not locate `%s'\n"),
    167      1.1  christos 		     whoami, sf->name);
    168      1.1  christos 	  else
    169      1.1  christos 	    perror (sf->name);
    170      1.1  christos 
    171      1.1  christos 	  return 0;
    172      1.1  christos 	}
    173      1.1  christos     }
    174      1.1  christos 
    175      1.1  christos   ofp = stdout;
    176      1.1  christos 
    177      1.1  christos   if (create_annotation_files)
    178      1.1  christos     {
    179      1.1  christos       /* Try to create annotated source file.  */
    180      1.1  christos       const char *filename;
    181      1.1  christos 
    182      1.1  christos       /* Create annotation files in the current working directory.  */
    183      1.1  christos       filename = strrchr (sf->name, '/');
    184      1.1  christos #ifdef HAVE_DOS_BASED_FILE_SYSTEM
    185      1.1  christos 	{
    186      1.1  christos 	  char *bslash = strrchr (sf->name, '\\');
    187      1.1  christos 	  if (filename == NULL || (bslash != NULL && bslash > filename))
    188      1.1  christos 	    filename = bslash;
    189      1.1  christos 	  if (filename == NULL && sf->name[0] != '\0' && sf->name[1] == ':')
    190      1.1  christos 	    filename = sf->name + 1;
    191      1.1  christos 	}
    192      1.1  christos #endif
    193      1.1  christos       if (filename)
    194      1.1  christos 	++filename;
    195      1.1  christos       else
    196      1.1  christos 	filename = sf->name;
    197      1.1  christos 
    198  1.1.1.6  christos       fname = xmalloc (strlen (filename) + strlen (EXT_ANNO) + 1);
    199      1.1  christos       strcpy (fname, filename);
    200      1.1  christos       strcat (fname, EXT_ANNO);
    201      1.1  christos #ifdef __MSDOS__
    202      1.1  christos       {
    203      1.1  christos 	/* foo.cpp-ann can overwrite foo.cpp due to silent truncation of
    204      1.1  christos 	   file names on 8+3 filesystems.  Their `stat' better be good...  */
    205      1.1  christos 	struct stat buf1, buf2;
    206      1.1  christos 
    207      1.1  christos 	if (stat (filename, &buf1) == 0
    208      1.1  christos 	    && stat (fname, &buf2) == 0
    209      1.1  christos 	    && buf1.st_ino == buf2.st_ino)
    210      1.1  christos 	  {
    211      1.1  christos 	    char *dot = strrchr (fname, '.');
    212      1.1  christos 
    213  1.1.1.6  christos 	    if (!dot)
    214  1.1.1.6  christos 	      dot = fname + strlen (filename);
    215  1.1.1.6  christos 	    strcpy (dot, ".ann");
    216      1.1  christos 	  }
    217      1.1  christos       }
    218      1.1  christos #endif
    219      1.1  christos       ofp = fopen (fname, "w");
    220      1.1  christos 
    221      1.1  christos       if (!ofp)
    222      1.1  christos 	{
    223      1.1  christos 	  perror (fname);
    224  1.1.1.6  christos 	  free (fname);
    225      1.1  christos 	  return 0;
    226      1.1  christos 	}
    227  1.1.1.6  christos       free (fname);
    228      1.1  christos     }
    229      1.1  christos 
    230      1.1  christos   /* Print file names if output goes to stdout
    231      1.1  christos      and there are more than one source file.  */
    232      1.1  christos   if (ofp == stdout)
    233      1.1  christos     {
    234      1.1  christos       if (first_file)
    235  1.1.1.6  christos 	first_file = false;
    236      1.1  christos       else
    237      1.1  christos 	fputc ('\n', ofp);
    238      1.1  christos 
    239      1.1  christos       if (first_output)
    240  1.1.1.6  christos 	first_output = false;
    241      1.1  christos       else
    242      1.1  christos 	fprintf (ofp, "\f\n");
    243      1.1  christos 
    244      1.1  christos       fprintf (ofp, _("*** File %s:\n"), sf->name);
    245      1.1  christos     }
    246      1.1  christos 
    247      1.1  christos   annotation = (char *) xmalloc (max_width + 1);
    248      1.1  christos   line_num = 1;
    249  1.1.1.6  christos   new_line = true;
    250      1.1  christos 
    251      1.1  christos   while ((nread = fread (buf, 1, sizeof (buf), ifp)) > 0)
    252      1.1  christos     {
    253      1.1  christos       for (i = 0; i < nread; ++i)
    254      1.1  christos 	{
    255      1.1  christos 	  if (new_line)
    256      1.1  christos 	    {
    257      1.1  christos 	      (*annote) (annotation, max_width, line_num, arg);
    258      1.1  christos 	      fputs (annotation, ofp);
    259      1.1  christos 	      ++line_num;
    260      1.1  christos 	    }
    261      1.1  christos 
    262      1.1  christos 	  new_line = (buf[i] == '\n');
    263      1.1  christos 	  fputc (buf[i], ofp);
    264      1.1  christos 	}
    265      1.1  christos     }
    266      1.1  christos 
    267      1.1  christos   free (annotation);
    268  1.1.1.2  christos   fclose (ifp);
    269      1.1  christos   return ofp;
    270      1.1  christos }
    271