Blame gprof/source.c

Packit bbfece
/* source.c - Keep track of source files.
Packit bbfece
Packit bbfece
   Copyright (C) 2000-2018 Free Software Foundation, Inc.
Packit bbfece
Packit bbfece
   This file is part of GNU Binutils.
Packit bbfece
Packit bbfece
   This program is free software; you can redistribute it and/or modify
Packit bbfece
   it under the terms of the GNU General Public License as published by
Packit bbfece
   the Free Software Foundation; either version 3 of the License, or
Packit bbfece
   (at your option) any later version.
Packit bbfece
Packit bbfece
   This program is distributed in the hope that it will be useful,
Packit bbfece
   but WITHOUT ANY WARRANTY; without even the implied warranty of
Packit bbfece
   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
Packit bbfece
   GNU General Public License for more details.
Packit bbfece
Packit bbfece
   You should have received a copy of the GNU General Public License
Packit bbfece
   along with this program; if not, write to the Free Software
Packit bbfece
   Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston, MA
Packit bbfece
   02110-1301, USA.  */
Packit bbfece

Packit bbfece
#include "gprof.h"
Packit bbfece
#include "libiberty.h"
Packit bbfece
#include "filenames.h"
Packit bbfece
#include "search_list.h"
Packit bbfece
#include "source.h"
Packit bbfece
Packit bbfece
#define EXT_ANNO "-ann"		/* Postfix of annotated files.  */
Packit bbfece
Packit bbfece
/* Default option values.  */
Packit bbfece
bfd_boolean create_annotation_files = FALSE;
Packit bbfece
Packit bbfece
Search_List src_search_list = {0, 0};
Packit bbfece
Source_File *first_src_file = 0;
Packit bbfece
Packit bbfece
Packit bbfece
Source_File *
Packit bbfece
source_file_lookup_path (const char *path)
Packit bbfece
{
Packit bbfece
  Source_File *sf;
Packit bbfece
Packit bbfece
  for (sf = first_src_file; sf; sf = sf->next)
Packit bbfece
    {
Packit bbfece
      if (FILENAME_CMP (path, sf->name) == 0)
Packit bbfece
	break;
Packit bbfece
    }
Packit bbfece
Packit bbfece
  if (!sf)
Packit bbfece
    {
Packit bbfece
      /* Create a new source file descriptor.  */
Packit bbfece
      sf = (Source_File *) xmalloc (sizeof (*sf));
Packit bbfece
Packit bbfece
      memset (sf, 0, sizeof (*sf));
Packit bbfece
Packit bbfece
      sf->name = xstrdup (path);
Packit bbfece
      sf->next = first_src_file;
Packit bbfece
      first_src_file = sf;
Packit bbfece
    }
Packit bbfece
Packit bbfece
  return sf;
Packit bbfece
}
Packit bbfece
Packit bbfece
Packit bbfece
Source_File *
Packit bbfece
source_file_lookup_name (const char *filename)
Packit bbfece
{
Packit bbfece
  const char *fname;
Packit bbfece
  Source_File *sf;
Packit bbfece
Packit bbfece
  /* The user cannot know exactly how a filename will be stored in
Packit bbfece
     the debugging info (e.g., ../include/foo.h
Packit bbfece
     vs. /usr/include/foo.h).  So we simply compare the filename
Packit bbfece
     component of a path only.  */
Packit bbfece
  for (sf = first_src_file; sf; sf = sf->next)
Packit bbfece
    {
Packit bbfece
      fname = strrchr (sf->name, '/');
Packit bbfece
Packit bbfece
      if (fname)
Packit bbfece
	++fname;
Packit bbfece
      else
Packit bbfece
	fname = sf->name;
Packit bbfece
Packit bbfece
      if (FILENAME_CMP (filename, fname) == 0)
Packit bbfece
	break;
Packit bbfece
    }
Packit bbfece
Packit bbfece
  return sf;
Packit bbfece
}
Packit bbfece
Packit bbfece
Packit bbfece
FILE *
Packit bbfece
annotate_source (Source_File *sf, unsigned int max_width,
Packit bbfece
     void (*annote) (char *, unsigned int, int, void *),
Packit bbfece
     void *arg)
Packit bbfece
{
Packit bbfece
  static bfd_boolean first_file = TRUE;
Packit bbfece
  int i, line_num, nread;
Packit bbfece
  bfd_boolean new_line;
Packit bbfece
  char buf[8192];
Packit bbfece
  char fname[PATH_MAX];
Packit bbfece
  char *annotation, *name_only;
Packit bbfece
  FILE *ifp, *ofp;
Packit bbfece
  Search_List_Elem *sle = src_search_list.head;
Packit bbfece
Packit bbfece
  /* Open input file.  If open fails, walk along search-list until
Packit bbfece
     open succeeds or reaching end of list.  */
Packit bbfece
  strcpy (fname, sf->name);
Packit bbfece
Packit bbfece
  if (IS_ABSOLUTE_PATH (sf->name))
Packit bbfece
    sle = 0;			/* Don't use search list for absolute paths.  */
Packit bbfece
Packit bbfece
  name_only = 0;
Packit bbfece
  while (TRUE)
Packit bbfece
    {
Packit bbfece
      DBG (SRCDEBUG, printf ("[annotate_source]: looking for %s, trying %s\n",
Packit bbfece
			     sf->name, fname));
Packit bbfece
Packit bbfece
      ifp = fopen (fname, FOPEN_RB);
Packit bbfece
      if (ifp)
Packit bbfece
	break;
Packit bbfece
Packit bbfece
      if (!sle && !name_only)
Packit bbfece
	{
Packit bbfece
	  name_only = strrchr (sf->name, '/');
Packit bbfece
#ifdef HAVE_DOS_BASED_FILE_SYSTEM
Packit bbfece
	  {
Packit bbfece
	    char *bslash = strrchr (sf->name, '\\');
Packit bbfece
	    if (name_only == NULL || (bslash != NULL && bslash > name_only))
Packit bbfece
	      name_only = bslash;
Packit bbfece
	    if (name_only == NULL && sf->name[0] != '\0' && sf->name[1] == ':')
Packit bbfece
	      name_only = (char *)sf->name + 1;
Packit bbfece
	  }
Packit bbfece
#endif
Packit bbfece
	  if (name_only)
Packit bbfece
	    {
Packit bbfece
	      /* Try search-list again, but this time with name only.  */
Packit bbfece
	      ++name_only;
Packit bbfece
	      sle = src_search_list.head;
Packit bbfece
	    }
Packit bbfece
	}
Packit bbfece
Packit bbfece
      if (sle)
Packit bbfece
	{
Packit bbfece
	  strcpy (fname, sle->path);
Packit bbfece
#ifdef HAVE_DOS_BASED_FILE_SYSTEM
Packit bbfece
	  /* d:foo is not the same thing as d:/foo!  */
Packit bbfece
	  if (fname[strlen (fname) - 1] == ':')
Packit bbfece
	    strcat (fname, ".");
Packit bbfece
#endif
Packit bbfece
	  strcat (fname, "/");
Packit bbfece
Packit bbfece
	  if (name_only)
Packit bbfece
	    strcat (fname, name_only);
Packit bbfece
	  else
Packit bbfece
	    strcat (fname, sf->name);
Packit bbfece
Packit bbfece
	  sle = sle->next;
Packit bbfece
	}
Packit bbfece
      else
Packit bbfece
	{
Packit bbfece
	  if (errno == ENOENT)
Packit bbfece
	    fprintf (stderr, _("%s: could not locate `%s'\n"),
Packit bbfece
		     whoami, sf->name);
Packit bbfece
	  else
Packit bbfece
	    perror (sf->name);
Packit bbfece
Packit bbfece
	  return 0;
Packit bbfece
	}
Packit bbfece
    }
Packit bbfece
Packit bbfece
  ofp = stdout;
Packit bbfece
Packit bbfece
  if (create_annotation_files)
Packit bbfece
    {
Packit bbfece
      /* Try to create annotated source file.  */
Packit bbfece
      const char *filename;
Packit bbfece
Packit bbfece
      /* Create annotation files in the current working directory.  */
Packit bbfece
      filename = strrchr (sf->name, '/');
Packit bbfece
#ifdef HAVE_DOS_BASED_FILE_SYSTEM
Packit bbfece
	{
Packit bbfece
	  char *bslash = strrchr (sf->name, '\\');
Packit bbfece
	  if (filename == NULL || (bslash != NULL && bslash > filename))
Packit bbfece
	    filename = bslash;
Packit bbfece
	  if (filename == NULL && sf->name[0] != '\0' && sf->name[1] == ':')
Packit bbfece
	    filename = sf->name + 1;
Packit bbfece
	}
Packit bbfece
#endif
Packit bbfece
      if (filename)
Packit bbfece
	++filename;
Packit bbfece
      else
Packit bbfece
	filename = sf->name;
Packit bbfece
Packit bbfece
      strcpy (fname, filename);
Packit bbfece
      strcat (fname, EXT_ANNO);
Packit bbfece
#ifdef __MSDOS__
Packit bbfece
      {
Packit bbfece
	/* foo.cpp-ann can overwrite foo.cpp due to silent truncation of
Packit bbfece
	   file names on 8+3 filesystems.  Their `stat' better be good...  */
Packit bbfece
	struct stat buf1, buf2;
Packit bbfece
Packit bbfece
	if (stat (filename, &buf1) == 0
Packit bbfece
	    && stat (fname, &buf2) == 0
Packit bbfece
	    && buf1.st_ino == buf2.st_ino)
Packit bbfece
	  {
Packit bbfece
	    char *dot = strrchr (fname, '.');
Packit bbfece
Packit bbfece
	    if (dot)
Packit bbfece
	      *dot = '\0';
Packit bbfece
	    strcat (fname, ".ann");
Packit bbfece
	  }
Packit bbfece
      }
Packit bbfece
#endif
Packit bbfece
      ofp = fopen (fname, "w");
Packit bbfece
Packit bbfece
      if (!ofp)
Packit bbfece
	{
Packit bbfece
	  perror (fname);
Packit bbfece
	  /* There is a potential resource leak here, but it is not important.  */
Packit bbfece
	  /* coverity[leaked_storage: FALSE] */
Packit bbfece
	  return 0;
Packit bbfece
	}
Packit bbfece
    }
Packit bbfece
Packit bbfece
  /* Print file names if output goes to stdout
Packit bbfece
     and there are more than one source file.  */
Packit bbfece
  if (ofp == stdout)
Packit bbfece
    {
Packit bbfece
      if (first_file)
Packit bbfece
	first_file = FALSE;
Packit bbfece
      else
Packit bbfece
	fputc ('\n', ofp);
Packit bbfece
Packit bbfece
      if (first_output)
Packit bbfece
	first_output = FALSE;
Packit bbfece
      else
Packit bbfece
	fprintf (ofp, "\f\n");
Packit bbfece
Packit bbfece
      fprintf (ofp, _("*** File %s:\n"), sf->name);
Packit bbfece
    }
Packit bbfece
Packit bbfece
  annotation = (char *) xmalloc (max_width + 1);
Packit bbfece
  line_num = 1;
Packit bbfece
  new_line = TRUE;
Packit bbfece
Packit bbfece
  while ((nread = fread (buf, 1, sizeof (buf), ifp)) > 0)
Packit bbfece
    {
Packit bbfece
      for (i = 0; i < nread; ++i)
Packit bbfece
	{
Packit bbfece
	  if (new_line)
Packit bbfece
	    {
Packit bbfece
	      (*annote) (annotation, max_width, line_num, arg);
Packit bbfece
	      fputs (annotation, ofp);
Packit bbfece
	      ++line_num;
Packit bbfece
	    }
Packit bbfece
Packit bbfece
	  new_line = (buf[i] == '\n');
Packit bbfece
	  fputc (buf[i], ofp);
Packit bbfece
	}
Packit bbfece
    }
Packit bbfece
Packit bbfece
  free (annotation);
Packit bbfece
  fclose (ifp);
Packit bbfece
  return ofp;
Packit bbfece
}