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