/* Copyright (C) 2021 Free Software Foundation, Inc. Contributed by Oracle. This file is part of GNU Binutils. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 3, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, 51 Franklin Street - Fifth Floor, Boston, MA 02110-1301, USA. */ #include "config.h" #include #include "util.h" #include "DbeSession.h" #include "Function.h" #include "SourceFile.h" #include "DefaultMap.h" #include "DbeFile.h" #include "LoadObject.h" #include "Module.h" int SourceFile::curId = 0; SourceFile::SourceFile (const char *file_name) { status = OS_NOTREAD; srcLines = NULL; srcInode = -1; lines = NULL; dbeLines = NULL; functions = new DefaultMap(); dbeFile = new DbeFile (file_name); dbeFile->filetype |= DbeFile::F_SOURCE | DbeFile::F_FILE; set_name ((char *) file_name); srcMTime = (time_t) 0; isTmpFile = false; flags = 0; read_stabs = false; id = (uint64_t) ((Histable::SOURCEFILE << 24) + curId) << 32; curId++; } SourceFile::~SourceFile () { destroy_map (DbeLine *, dbeLines); delete functions; delete dbeFile; if (lines) { lines->destroy (); delete lines; } if (srcLines) { free (srcLines->get (0)); delete srcLines; } if (isTmpFile) unlink (name); } void SourceFile::set_name (char* _name) { name = dbe_strdup (_name); } char* SourceFile::get_name (NameFormat) { return name; } bool SourceFile::readSource () { if (srcLines) return true; status = OS_NOSRC; char *location = dbeFile->get_location (); if (location == NULL) return false; if (!isTmpFile) srcMTime = dbeFile->sbuf.st_mtime; srcInode = dbeFile->sbuf.st_ino; size_t srcLen = dbeFile->sbuf.st_size; int fd = open64 (location, O_RDONLY); if (fd == -1) { status = OS_NOSRC; return false; } char *srcMap = (char *) malloc (srcLen + 1); int64_t sz = read_from_file (fd, srcMap, srcLen); if (sz != (int64_t) srcLen) append_msg (CMSG_ERROR, GTXT ("%s: Can read only %lld bytes instead %lld"), location, (long long) sz, (long long) srcLen); srcMap[sz] = 0; close (fd); // Count the number of lines in the file, converting to zero srcLines = new Vector(); srcLines->append (srcMap); for (int64_t i = 0; i < sz; i++) { if (srcMap[i] == '\r') { // Window style srcMap[i] = 0; if (i + 1 < sz && srcMap[i + 1] != '\n') srcLines->append (srcMap + i + 1); } else if (srcMap[i] == '\n') { srcMap[i] = '\0'; if (i + 1 < sz) srcLines->append (srcMap + i + 1); } } if (dbeLines) { Vector *v = dbeLines->values (); for (long i = 0, sz1 = v ? v->size () : 0; i < sz1; i++) { DbeLine *p = v->get (i); if (p->lineno >= srcLines->size ()) append_msg (CMSG_ERROR, GTXT ("Wrong line number %d. '%s' has only %d lines"), p->lineno, dbeFile->get_location (), srcLines->size ()); } delete v; } status = OS_OK; return true; } char * SourceFile::getLine (int lineno) { assert (srcLines != NULL); if (lineno > 0 && lineno <= srcLines->size ()) return srcLines->get (lineno - 1); return NTXT (""); } DbeLine * SourceFile::find_dbeline (Function *func, int lineno) { if (lineno < 0 || (lineno == 0 && func == NULL)) return NULL; DbeLine *dbeLine = NULL; if (lines) { // the source is available if (lineno > lines->size ()) { if (dbeLines) dbeLine = dbeLines->get (lineno); if (dbeLine == NULL) append_msg (CMSG_ERROR, GTXT ("Wrong line number %d. '%s' has only %d lines"), lineno, dbeFile->get_location (), lines->size ()); } else { dbeLine = lines->fetch (lineno); if (dbeLine == NULL) { dbeLine = new DbeLine (NULL, this, lineno); lines->store (lineno, dbeLine); } } } if (dbeLine == NULL) { // the source is not yet read or lineno is wrong if (dbeLines == NULL) dbeLines = new DefaultMap(); dbeLine = dbeLines->get (lineno); if (dbeLine == NULL) { dbeLine = new DbeLine (NULL, this, lineno); dbeLines->put (lineno, dbeLine); } } for (DbeLine *last = dbeLine;; last = last->dbeline_func_next) { if (last->func == func) return last; if (last->dbeline_func_next == NULL) { DbeLine *dl = new DbeLine (func, this, lineno); if (functions->get (func) == NULL) functions->put (func, func); last->dbeline_func_next = dl; dl->dbeline_base = dbeLine; return dl; } } } Vector * SourceFile::get_functions () { if (!read_stabs) { // Create all DbeLines for this Source read_stabs = true; Vector *lobjs = dbeSession->get_LoadObjects (); for (long i = 0, sz = VecSize (lobjs); i < sz; i++) { LoadObject *lo = lobjs->get (i); for (long i1 = 0, sz1 = VecSize (lo->seg_modules); i1 < sz1; i1++) { Module *mod = lo->seg_modules->get (i1); mod->read_stabs (); } } } return functions->keySet (); }