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 33int SourceFile::curId = 0; 34 35SourceFile::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 54SourceFile::~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 73void 74SourceFile::set_name (char* _name) 75{ 76 name = dbe_strdup (_name); 77} 78 79char* 80SourceFile::get_name (NameFormat) 81{ 82 return name; 83} 84 85bool 86SourceFile::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 146char * 147SourceFile::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 155DbeLine * 156SourceFile::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 210Vector<Function *> * 211SourceFile::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