xref: /netbsd-src/external/gpl3/binutils/dist/gprofng/src/SourceFile.cc (revision cb63e24e8d6aae7ddac1859a9015f48b1d8bd90e)
1 /* Copyright (C) 2021-2024 Free Software Foundation, Inc.
2    Contributed by Oracle.
3 
4    This file is part of GNU Binutils.
5 
6    This program is free software; you can redistribute it and/or modify
7    it under the terms of the GNU General Public License as published by
8    the Free Software Foundation; either version 3, or (at your option)
9    any later version.
10 
11    This program is distributed in the hope that it will be useful,
12    but WITHOUT ANY WARRANTY; without even the implied warranty of
13    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14    GNU General Public License for more details.
15 
16    You should have received a copy of the GNU General Public License
17    along with this program; if not, write to the Free Software
18    Foundation, 51 Franklin Street - Fifth Floor, Boston,
19    MA 02110-1301, USA.  */
20 
21 #include "config.h"
22 #include <unistd.h>
23 
24 #include "util.h"
25 #include "DbeSession.h"
26 #include "Function.h"
27 #include "SourceFile.h"
28 #include "DefaultMap.h"
29 #include "DbeFile.h"
30 #include "LoadObject.h"
31 #include "Module.h"
32 
33 int SourceFile::curId = 0;
34 
SourceFile(const char * file_name)35 SourceFile::SourceFile (const char *file_name)
36 {
37   status = OS_NOTREAD;
38   srcLines = NULL;
39   srcInode = -1;
40   lines = NULL;
41   dbeLines = NULL;
42   functions = new DefaultMap<Function *, Function *>();
43   dbeFile = new DbeFile (file_name);
44   dbeFile->filetype |= DbeFile::F_SOURCE | DbeFile::F_FILE;
45   set_name ((char *) file_name);
46   srcMTime = (time_t) 0;
47   isTmpFile = false;
48   flags = 0;
49   read_stabs = false;
50   id = (uint64_t) ((Histable::SOURCEFILE << 24) + curId) << 32;
51   curId++;
52 }
53 
~SourceFile()54 SourceFile::~SourceFile ()
55 {
56   destroy_map (DbeLine *, dbeLines);
57   delete functions;
58   delete dbeFile;
59   if (lines)
60     {
61       lines->destroy ();
62       delete lines;
63     }
64   if (srcLines)
65     {
66       free (srcLines->get (0));
67       delete srcLines;
68     }
69   if (isTmpFile)
70     unlink (name);
71 }
72 
73 void
set_name(char * _name)74 SourceFile::set_name (char* _name)
75 {
76   name = dbe_strdup (_name);
77 }
78 
79 char*
get_name(NameFormat)80 SourceFile::get_name (NameFormat)
81 {
82   return name;
83 }
84 
85 bool
readSource()86 SourceFile::readSource ()
87 {
88   if (srcLines)
89     return true;
90   status = OS_NOSRC;
91   char *location = dbeFile->get_location ();
92   if (location == NULL)
93     return false;
94   if (!isTmpFile)
95     srcMTime = dbeFile->sbuf.st_mtime;
96   srcInode = dbeFile->sbuf.st_ino;
97   size_t srcLen = dbeFile->sbuf.st_size;
98   int fd = open64 (location, O_RDONLY);
99   if (fd == -1)
100     {
101       status = OS_NOSRC;
102       return false;
103     }
104   char *srcMap = (char *) malloc (srcLen + 1);
105   int64_t sz = read_from_file (fd, srcMap, srcLen);
106   if (sz != (int64_t) srcLen)
107     append_msg (CMSG_ERROR, GTXT ("%s: Can read only %lld bytes instead %lld"),
108 		location, (long long) sz, (long long) srcLen);
109   srcMap[sz] = 0;
110   close (fd);
111 
112   // Count the number of lines in the file, converting <nl> to zero
113   srcLines = new Vector<char*>();
114   srcLines->append (srcMap);
115   for (int64_t i = 0; i < sz; i++)
116     {
117       if (srcMap[i] == '\r')
118 	{ // Window style
119 	  srcMap[i] = 0;
120 	  if (i + 1 < sz && srcMap[i + 1] != '\n')
121 	    srcLines->append (srcMap + i + 1);
122 	}
123       else if (srcMap[i] == '\n')
124 	{
125 	  srcMap[i] = '\0';
126 	  if (i + 1 < sz)
127 	    srcLines->append (srcMap + i + 1);
128 	}
129     }
130   if (dbeLines)
131     {
132       Vector<DbeLine *> *v = dbeLines->values ();
133       for (long i = 0, sz1 = v ? v->size () : 0; i < sz1; i++)
134 	{
135 	  DbeLine *p = v->get (i);
136 	  if (p->lineno >= srcLines->size ())
137 	    append_msg (CMSG_ERROR, GTXT ("Wrong line number %d. '%s' has only %d lines"),
138 			(int) p->lineno, dbeFile->get_location (),
139 			(int) srcLines->size ());
140 	}
141       delete v;
142     }
143   status = OS_OK;
144   return true;
145 }
146 
147 char *
getLine(int lineno)148 SourceFile::getLine (int lineno)
149 {
150   assert (srcLines != NULL);
151   if (lineno > 0 && lineno <= srcLines->size ())
152     return srcLines->get (lineno - 1);
153   return NTXT ("");
154 }
155 
156 DbeLine *
find_dbeline(Function * func,int lineno)157 SourceFile::find_dbeline (Function *func, int lineno)
158 {
159   if (lineno < 0 || (lineno == 0 && func == NULL))
160     return NULL;
161   DbeLine *dbeLine = NULL;
162   if (lines)
163     { // the source is available
164       if (lineno > lines->size ())
165 	{
166 	  if (dbeLines)
167 	    dbeLine = dbeLines->get (lineno);
168 	  if (dbeLine == NULL)
169 	    append_msg (CMSG_ERROR,
170 			GTXT ("Wrong line number %d. '%s' has only %d lines"),
171 			(int) lineno, dbeFile->get_location (),
172 			(int) lines->size ());
173 	}
174       else
175 	{
176 	  dbeLine = lines->fetch (lineno);
177 	  if (dbeLine == NULL)
178 	    {
179 	      dbeLine = new DbeLine (NULL, this, lineno);
180 	      lines->store (lineno, dbeLine);
181 	    }
182 	}
183     }
184   if (dbeLine == NULL)
185     { // the source is not yet read or lineno is wrong
186       if (dbeLines == NULL)
187 	dbeLines = new DefaultMap<int, DbeLine *>();
188       dbeLine = dbeLines->get (lineno);
189       if (dbeLine == NULL)
190 	{
191 	  dbeLine = new DbeLine (NULL, this, lineno);
192 	  dbeLines->put (lineno, dbeLine);
193 	}
194     }
195 
196   for (DbeLine *last = dbeLine;; last = last->dbeline_func_next)
197     {
198       if (last->func == func)
199 	return last;
200       if (last->dbeline_func_next == NULL)
201 	{
202 	  DbeLine *dl = new DbeLine (func, this, lineno);
203 	  if (functions->get (func) == NULL)
204 	    functions->put (func, func);
205 	  last->dbeline_func_next = dl;
206 	  dl->dbeline_base = dbeLine;
207 	  return dl;
208 	}
209     }
210 }
211 
212 Vector<Function *> *
get_functions()213 SourceFile::get_functions ()
214 {
215   if (!read_stabs)
216     {
217       // Create all DbeLines for this Source
218       read_stabs = true;
219       Vector<LoadObject *> *lobjs = dbeSession->get_LoadObjects ();
220       for (long i = 0, sz = VecSize (lobjs); i < sz; i++)
221 	{
222 	  LoadObject *lo = lobjs->get (i);
223 	  for (long i1 = 0, sz1 = VecSize (lo->seg_modules); i1 < sz1; i1++)
224 	    {
225 	      Module *mod = lo->seg_modules->get (i1);
226 	      mod->read_stabs ();
227 	    }
228 	}
229     }
230   return functions->keySet ();
231 }
232