1 /* Copyright (C) 2021 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 			p->lineno, dbeFile->get_location (), srcLines->size ());
139 	}
140       delete v;
141     }
142   status = OS_OK;
143   return true;
144 }
145 
146 char *
getLine(int lineno)147 SourceFile::getLine (int lineno)
148 {
149   assert (srcLines != NULL);
150   if (lineno > 0 && lineno <= srcLines->size ())
151     return srcLines->get (lineno - 1);
152   return NTXT ("");
153 }
154 
155 DbeLine *
find_dbeline(Function * func,int lineno)156 SourceFile::find_dbeline (Function *func, int lineno)
157 {
158   if (lineno < 0 || (lineno == 0 && func == NULL))
159     return NULL;
160   DbeLine *dbeLine = NULL;
161   if (lines)
162     { // the source is available
163       if (lineno > lines->size ())
164 	{
165 	  if (dbeLines)
166 	    dbeLine = dbeLines->get (lineno);
167 	  if (dbeLine == NULL)
168 	    append_msg (CMSG_ERROR,
169 			GTXT ("Wrong line number %d. '%s' has only %d lines"),
170 			lineno, dbeFile->get_location (), lines->size ());
171 	}
172       else
173 	{
174 	  dbeLine = lines->fetch (lineno);
175 	  if (dbeLine == NULL)
176 	    {
177 	      dbeLine = new DbeLine (NULL, this, lineno);
178 	      lines->store (lineno, dbeLine);
179 	    }
180 	}
181     }
182   if (dbeLine == NULL)
183     { // the source is not yet read or lineno is wrong
184       if (dbeLines == NULL)
185 	dbeLines = new DefaultMap<int, DbeLine *>();
186       dbeLine = dbeLines->get (lineno);
187       if (dbeLine == NULL)
188 	{
189 	  dbeLine = new DbeLine (NULL, this, lineno);
190 	  dbeLines->put (lineno, dbeLine);
191 	}
192     }
193 
194   for (DbeLine *last = dbeLine;; last = last->dbeline_func_next)
195     {
196       if (last->func == func)
197 	return last;
198       if (last->dbeline_func_next == NULL)
199 	{
200 	  DbeLine *dl = new DbeLine (func, this, lineno);
201 	  if (functions->get (func) == NULL)
202 	    functions->put (func, func);
203 	  last->dbeline_func_next = dl;
204 	  dl->dbeline_base = dbeLine;
205 	  return dl;
206 	}
207     }
208 }
209 
210 Vector<Function *> *
get_functions()211 SourceFile::get_functions ()
212 {
213   if (!read_stabs)
214     {
215       // Create all DbeLines for this Source
216       read_stabs = true;
217       Vector<LoadObject *> *lobjs = dbeSession->get_LoadObjects ();
218       for (long i = 0, sz = VecSize (lobjs); i < sz; i++)
219 	{
220 	  LoadObject *lo = lobjs->get (i);
221 	  for (long i1 = 0, sz1 = VecSize (lo->seg_modules); i1 < sz1; i1++)
222 	    {
223 	      Module *mod = lo->seg_modules->get (i1);
224 	      mod->read_stabs ();
225 	    }
226 	}
227     }
228   return functions->keySet ();
229 }
230