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