Retro68/binutils/gprofng/src/SourceFile.cc
Wolfgang Thaller f485e125c4 binutils 2.39
2022-10-27 20:45:45 +02:00

230 lines
5.5 KiB
C++

/* 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 <unistd.h>
#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<Function *, Function *>();
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 <nl> to zero
srcLines = new Vector<char*>();
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<DbeLine *> *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<int, DbeLine *>();
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<Function *> *
SourceFile::get_functions ()
{
if (!read_stabs)
{
// Create all DbeLines for this Source
read_stabs = true;
Vector<LoadObject *> *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 ();
}