mirror of
https://github.com/autc04/Retro68.git
synced 2024-06-19 19:29:54 +00:00
1841 lines
49 KiB
C++
1841 lines
49 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 <ar.h>
|
|
#include <ctype.h>
|
|
#include <sys/param.h>
|
|
|
|
#include "util.h"
|
|
#include "DbeSession.h"
|
|
#include "Experiment.h"
|
|
#include "DataObject.h"
|
|
#include "Function.h"
|
|
#include "DbeView.h"
|
|
#include "MetricList.h"
|
|
#include "Module.h"
|
|
#include "ClassFile.h"
|
|
#include "LoadObject.h"
|
|
#include "Disasm.h"
|
|
#include "CompCom.h"
|
|
#include "Dwarf.h"
|
|
#include "DbeFile.h"
|
|
#include "PathTree.h"
|
|
#include "Elf.h"
|
|
|
|
Module::Module ()
|
|
{
|
|
lang_code = Sp_lang_unknown;
|
|
flags = 0;
|
|
status = AE_NOTREAD;
|
|
openSourceFlag = AE_NOTREAD;
|
|
hexVisible = false;
|
|
disPath = NULL;
|
|
stabsPath = NULL;
|
|
stabsTmp = NULL;
|
|
disName = NULL;
|
|
stabsName = NULL;
|
|
indexStabsLink = NULL;
|
|
file_name = NULL;
|
|
functions = new Vector<Function*>;
|
|
loadobject = NULL;
|
|
dot_o_file = NULL;
|
|
main_source = dbeSession->get_Unknown_Source ();
|
|
srcContext = main_source;
|
|
includes = new Vector<SourceFile*>;
|
|
includes->append (main_source);
|
|
curr_inc = NULL;
|
|
fragmented = 0;
|
|
hwcprof = 0;
|
|
hdrOffset = 0;
|
|
hasDwarf = false;
|
|
hasStabs = false;
|
|
readStabs = false;
|
|
comComs = NULL;
|
|
infoList = NULL;
|
|
datatypes = NULL;
|
|
objStabs = NULL;
|
|
disasm = NULL;
|
|
comp_flags = NULL;
|
|
comp_dir = NULL;
|
|
linkerStabName = NULL;
|
|
disMTime = (time_t) 0;
|
|
stabsMTime = (time_t) 0;
|
|
real_timestamp = 0;
|
|
curr_timestamp = 0;
|
|
src_items = NULL;
|
|
dis_items = NULL;
|
|
data_items = NULL;
|
|
cur_dbev = NULL;
|
|
maximum = NULL;
|
|
maximum_inc = NULL;
|
|
empty = NULL;
|
|
inlinedSubr = NULL;
|
|
}
|
|
|
|
Module::~Module ()
|
|
{
|
|
removeStabsTmp ();
|
|
delete includes;
|
|
if (comComs != NULL)
|
|
{
|
|
comComs->destroy ();
|
|
delete comComs;
|
|
}
|
|
free (comp_flags);
|
|
free (comp_dir);
|
|
free (linkerStabName);
|
|
free (disPath);
|
|
free (stabsPath);
|
|
free (disName);
|
|
free (stabsName);
|
|
delete functions;
|
|
free (file_name);
|
|
if (indexStabsLink)
|
|
// Remove a link to the current module
|
|
indexStabsLink->indexStabsLink = NULL;
|
|
|
|
if (dot_o_file)
|
|
{
|
|
delete dot_o_file->dbeFile;
|
|
delete dot_o_file;
|
|
}
|
|
delete src_items;
|
|
delete dis_items;
|
|
delete disasm;
|
|
free (inlinedSubr);
|
|
if (lang_code != Sp_lang_java)
|
|
delete dbeFile;
|
|
|
|
}
|
|
|
|
Stabs *
|
|
Module::openDebugInfo ()
|
|
{
|
|
setFile ();
|
|
objStabs = loadobject->openDebugInfo (disPath);
|
|
return objStabs;
|
|
}
|
|
|
|
void
|
|
Module::removeStabsTmp ()
|
|
{
|
|
// Remove temporary *.o (got from *.a) after reading Stabs
|
|
if (stabsTmp != NULL)
|
|
{
|
|
unlink (stabsTmp);
|
|
free (stabsTmp);
|
|
stabsTmp = NULL;
|
|
}
|
|
}
|
|
|
|
int64_t
|
|
Module::get_size ()
|
|
{
|
|
Function *fp;
|
|
int index;
|
|
int64_t result = 0;
|
|
Vec_loop (Function*, functions, index, fp)
|
|
{
|
|
result += fp->size;
|
|
}
|
|
return result;
|
|
}
|
|
|
|
bool
|
|
Module::is_fortran ()
|
|
{
|
|
return Stabs::is_fortran (lang_code);
|
|
}
|
|
|
|
SourceFile *
|
|
Module::findSource (const char *fname, bool create)
|
|
{
|
|
SourceFile *sf = NULL;
|
|
if (loadobject && loadobject->firstExp)
|
|
sf = loadobject->firstExp->get_source (fname);
|
|
if (sf == NULL)
|
|
sf = dbeSession->createSourceFile (fname);
|
|
for (int i = 0, sz = includes ? includes->size () : 0; i < sz; i++)
|
|
{
|
|
SourceFile *sf1 = includes->fetch (i);
|
|
if (sf == sf1)
|
|
return sf;
|
|
}
|
|
if (create)
|
|
{
|
|
if (includes == NULL)
|
|
includes = new Vector<SourceFile*>;
|
|
includes->append (sf);
|
|
return sf;
|
|
}
|
|
return NULL;
|
|
}
|
|
|
|
SourceFile *
|
|
Module::setIncludeFile (char *includeFile)
|
|
{
|
|
curr_inc = NULL;
|
|
if (includeFile)
|
|
curr_inc = findSource (includeFile, true);
|
|
return curr_inc;
|
|
}
|
|
|
|
char *
|
|
Module::anno_str (char *fnm)
|
|
{
|
|
char timebuf1[26], timebuf2[26];
|
|
const time_t real_time = (time_t) (unsigned int) real_timestamp;
|
|
const time_t curr_time = (time_t) (unsigned int) curr_timestamp;
|
|
|
|
switch (status)
|
|
{
|
|
case AE_OK:
|
|
case AE_NOTREAD:
|
|
return NULL;
|
|
case AE_NOSRC:
|
|
return dbe_sprintf (GTXT ("Source file `%s' not readable"),
|
|
fnm ? fnm : file_name);
|
|
case AE_NOOBJ:
|
|
if (lang_code == Sp_lang_java)
|
|
{
|
|
Emsg *emsg = get_error ();
|
|
if (emsg)
|
|
{
|
|
char *s = dbe_strdup (emsg->get_msg ());
|
|
remove_msg (emsg);
|
|
return s;
|
|
}
|
|
return dbe_sprintf (GTXT ("Object file `%s.class' not readable"),
|
|
name);
|
|
}
|
|
return dbe_sprintf (GTXT ("Object file `%s' not readable"), get_name ());
|
|
case AE_NOLOBJ:
|
|
if (lang_code == Sp_lang_java)
|
|
return dbe_sprintf (GTXT ("Object file `%s' not readable"),
|
|
dbeFile ? dbeFile->get_name () : name);
|
|
return dbe_sprintf (GTXT ("Object file `%s' not readable"), loadobject->get_pathname ());
|
|
case AE_NOSTABS:
|
|
return dbe_sprintf (GTXT ("Error reading line-number information in object `%s'; source annotation not available"),
|
|
stabsPath ? stabsPath : NTXT (""));
|
|
case AE_NOSYMTAB:
|
|
return dbe_sprintf (GTXT ("Error reading symbol table in object `%s'; disassembly annotation not available"),
|
|
disPath ? disPath : NTXT (""));
|
|
case AE_TIMESRC:
|
|
return dbe_sprintf (GTXT ("Warning! Source file `%s' is newer than the experiment data"),
|
|
main_source->dbeFile->getResolvedPath ());
|
|
case AE_TIMEDIS:
|
|
return dbe_sprintf (GTXT ("Warning! Object file `%s' is newer than the experiment data"),
|
|
disName ? disName : NTXT (""));
|
|
case AE_TIMESTABS:
|
|
return dbe_sprintf (GTXT ("Warning! Object file `%s' is newer than the experiment data"),
|
|
stabsName ? stabsName : NTXT (""));
|
|
case AE_TIMESTABS_DIFF:
|
|
snprintf (timebuf1, sizeof (timebuf1), NTXT ("%s"), ctime (&curr_time));
|
|
snprintf (timebuf2, sizeof (timebuf2), NTXT ("%s"), ctime (&real_time));
|
|
timebuf1[24] = timebuf2[24] = '\0';
|
|
return dbe_sprintf (GTXT ("Warning! Object file `%s' is not the same one that was linked into executable.\n"
|
|
"\tObject file: `%s'\n\tcompiled on: %s\n"
|
|
"\tExecutable contains object file compiled on: %s"),
|
|
getResolvedObjectPath (), getResolvedObjectPath (),
|
|
timebuf1, timebuf2);
|
|
case AE_OTHER:
|
|
default:
|
|
return dbe_strdup (GTXT ("Annotation computation error"));
|
|
}
|
|
}//anno_str
|
|
|
|
LoadObject *
|
|
Module::createLoadObject (const char *lo_name)
|
|
{
|
|
LoadObject *lo = new LoadObject (lo_name);
|
|
lo->dbeFile->filetype |= DbeFile::F_DOT_O;
|
|
return lo;
|
|
}
|
|
|
|
static bool
|
|
tsIsNewer (time_t t1, time_t t2)
|
|
{
|
|
return t1 != 0 && t2 != 0 && t1 < t2;
|
|
}
|
|
|
|
Module::Anno_Errors
|
|
Module::checkTimeStamp (bool chkDis)
|
|
{
|
|
/* Check the linked and the real object timestamps due to bug #4796329 */
|
|
if (real_timestamp && curr_timestamp && real_timestamp != curr_timestamp)
|
|
return AE_TIMESTABS_DIFF;
|
|
|
|
time_t srctime = main_source->getMTime ();
|
|
for (int index = 0; index < dbeSession->nexps (); index++)
|
|
{
|
|
time_t mtime = dbeSession->get_exp (index)->get_mtime ();
|
|
if (tsIsNewer (mtime, srctime))
|
|
return AE_TIMESRC;
|
|
if (tsIsNewer (mtime, stabsMTime))
|
|
return AE_TIMESTABS;
|
|
if (chkDis && tsIsNewer (mtime, disMTime))
|
|
return AE_TIMEDIS;
|
|
}
|
|
return AE_OK;
|
|
}//checkTimeStamp
|
|
|
|
static size_t
|
|
get_ar_size (char *s, size_t len)
|
|
{
|
|
size_t sz = 0;
|
|
for (size_t i = 0; i < len; i++)
|
|
{
|
|
if (s[i] < '0' || s[i] > '9')
|
|
break;
|
|
sz = sz * 10 + (s[i] - '0');
|
|
}
|
|
return sz;
|
|
}
|
|
|
|
static void
|
|
dump_hdr_field (char *nm, char *s, size_t len)
|
|
{
|
|
Dprintf (DEBUG_READ_AR, NTXT (" %s "), nm);
|
|
for (size_t i = 0; i < len; i++)
|
|
Dprintf (DEBUG_READ_AR, "%c", isprint (s[i]) ? s[i] : '?');
|
|
Dprintf (DEBUG_READ_AR, NTXT (" "));
|
|
for (size_t i = 0; i < len; i++)
|
|
Dprintf (DEBUG_READ_AR, NTXT (" %d"), s[i]);
|
|
Dprintf (DEBUG_READ_AR, NTXT (" \n"));
|
|
}
|
|
|
|
static void
|
|
dump_ar_hdr (int lineNum, struct ar_hdr *hdr)
|
|
{
|
|
if (DEBUG_READ_AR)
|
|
{
|
|
Dprintf (DEBUG_READ_AR, NTXT ("Module::read_ar %d\n"), lineNum);
|
|
dump_hdr_field (NTXT ("ar_name"), hdr->ar_name, sizeof (hdr->ar_name));
|
|
dump_hdr_field (NTXT ("ar_date"), hdr->ar_date, sizeof (hdr->ar_date));
|
|
dump_hdr_field (NTXT ("ar_uid"), hdr->ar_uid, sizeof (hdr->ar_uid));
|
|
dump_hdr_field (NTXT ("ar_gid"), hdr->ar_gid, sizeof (hdr->ar_gid));
|
|
dump_hdr_field (NTXT ("ar_mode"), hdr->ar_mode, sizeof (hdr->ar_mode));
|
|
dump_hdr_field (NTXT ("ar_size"), hdr->ar_size, sizeof (hdr->ar_size));
|
|
dump_hdr_field (NTXT ("ar_fmag"), hdr->ar_fmag, sizeof (hdr->ar_fmag));
|
|
}
|
|
}
|
|
|
|
bool
|
|
Module::read_ar (int ar, int obj, char *obj_base)
|
|
{
|
|
struct ar_hdr hdr; // Archive header
|
|
char magic[SARMAG]; // Magic string from archive
|
|
Dprintf (DEBUG_READ_AR, "Module::read_ar %d %p %s %s \n", __LINE__,
|
|
this, STR (obj_base), STR (get_name ()));
|
|
// Check the magic string
|
|
if ((read_from_file (ar, magic, SARMAG) != SARMAG)
|
|
|| strncmp (magic, ARMAG, SARMAG))
|
|
return false;
|
|
|
|
// Read and skip the first file in the archive (index file to ld)
|
|
if (read_from_file (ar, &hdr, sizeof (hdr)) != sizeof (hdr))
|
|
return false;
|
|
DEBUG_CODE dump_ar_hdr (__LINE__, &hdr);
|
|
if (lseek (ar, get_ar_size (hdr.ar_size, sizeof (hdr.ar_size)), SEEK_CUR)
|
|
== -1)
|
|
return false;
|
|
|
|
// Read the string file where it keeps long file names (if exist)
|
|
if (read_from_file (ar, &hdr, sizeof (hdr)) != sizeof (hdr))
|
|
return false;
|
|
DEBUG_CODE dump_ar_hdr (__LINE__, &hdr);
|
|
char *longnames = NULL; // Area with names longer than ~13
|
|
size_t longnames_size = 0;
|
|
if (!strncmp (hdr.ar_name, NTXT ("//"), 2))
|
|
{
|
|
longnames_size = get_ar_size (hdr.ar_size, sizeof (hdr.ar_size));
|
|
longnames = (char *) malloc (longnames_size + 1);
|
|
int64_t cnt = read_from_file (ar, longnames, longnames_size);
|
|
if (cnt != (int64_t) longnames_size)
|
|
{
|
|
free (longnames);
|
|
return false;
|
|
}
|
|
longnames[longnames_size] = 0;
|
|
}
|
|
else
|
|
// back out, no long file names
|
|
lseek (ar, -(sizeof (hdr)), SEEK_CUR);
|
|
|
|
// Search the ar for the object file name
|
|
char ar_buf[sizeof (hdr.ar_name) + 1];
|
|
ar_buf[sizeof (hdr.ar_name)] = 0;
|
|
while (1)
|
|
{
|
|
if (read_from_file (ar, &hdr, sizeof (hdr)) != sizeof (hdr))
|
|
break;
|
|
DEBUG_CODE dump_ar_hdr (__LINE__, &hdr);
|
|
char *ar_name;
|
|
if (hdr.ar_name[0] != '/')
|
|
{ // Name is in the header
|
|
for (size_t i = 0; i < sizeof (hdr.ar_name); i++)
|
|
{
|
|
if (hdr.ar_name[i] == '/')
|
|
{
|
|
ar_buf[i] = 0;
|
|
break;
|
|
}
|
|
ar_buf[i] = hdr.ar_name[i];
|
|
}
|
|
ar_name = ar_buf;
|
|
}
|
|
else if (hdr.ar_name[1] == ' ')
|
|
{ // Name is blank
|
|
ar_buf[0] = 0;
|
|
ar_name = ar_buf;
|
|
}
|
|
else
|
|
{ // Name is in the string table
|
|
if (longnames == NULL)
|
|
break;
|
|
size_t offset = get_ar_size (hdr.ar_name + 1,
|
|
sizeof (hdr.ar_name) - 1);
|
|
if (offset >= longnames_size)
|
|
break;
|
|
for (size_t i = offset; i < longnames_size; i++)
|
|
{
|
|
if (longnames[i] == '/')
|
|
{
|
|
longnames[i] = 0;
|
|
break;
|
|
}
|
|
}
|
|
ar_name = longnames + offset;
|
|
}
|
|
Dprintf (DEBUG_READ_AR, "Module::read_ar %d ar_name=%s\n", __LINE__,
|
|
ar_name);
|
|
|
|
if (streq (ar_name, obj_base))
|
|
{ // create object file
|
|
free (longnames);
|
|
for (size_t objsize = get_ar_size (hdr.ar_size, sizeof (hdr.ar_size));
|
|
objsize > 0;)
|
|
{
|
|
char buf[MAXPATHLEN];
|
|
size_t n = objsize < sizeof (buf) ? objsize : sizeof (buf);
|
|
int64_t cnt = read_from_file (ar, buf, n);
|
|
if (cnt != (int64_t) n)
|
|
return false;
|
|
cnt = write (obj, buf, n);
|
|
if (cnt != (int64_t) n)
|
|
return false;
|
|
objsize -= n;
|
|
}
|
|
return true;
|
|
}
|
|
if (lseek (ar, get_ar_size (hdr.ar_size, sizeof (hdr.ar_size)),
|
|
SEEK_CUR) == -1)
|
|
break;
|
|
}
|
|
free (longnames);
|
|
return false;
|
|
}
|
|
|
|
static char *
|
|
get_obj_name_from_lib (char *nm)
|
|
{
|
|
char *base = strrchr (nm, '(');
|
|
if (base)
|
|
{
|
|
size_t last = strlen (base) - 1;
|
|
if (base[last] == ')')
|
|
return base;
|
|
}
|
|
return NULL;
|
|
}
|
|
|
|
bool
|
|
Module::setFile ()
|
|
{
|
|
if ((loadobject->flags & SEG_FLAG_DYNAMIC) != 0)
|
|
return true;
|
|
if ((loadobject->dbeFile->filetype & DbeFile::F_FICTION) != 0)
|
|
return false;
|
|
if ((flags & MOD_FLAG_UNKNOWN) != 0)
|
|
return true;
|
|
|
|
if (lang_code == Sp_lang_java)
|
|
{
|
|
if (dbeFile->get_need_refind ())
|
|
{
|
|
char *fnm = dbeFile->get_location ();
|
|
stabsPath = dbe_strdup (fnm);
|
|
stabsName = dbe_strdup (fnm);
|
|
disPath = dbe_strdup (fnm);
|
|
disName = dbe_strdup (fnm);
|
|
stabsMTime = dbeFile->sbuf.st_mtime;
|
|
}
|
|
return dbeFile->get_location () != NULL;
|
|
}
|
|
|
|
if (dbeFile == NULL)
|
|
{
|
|
char *objname = get_obj_name_from_lib (name);
|
|
if (objname)
|
|
{
|
|
// in the format of libpath(obj)
|
|
objname = dbe_strdup (objname + 1);
|
|
size_t last = strlen (objname) - 1;
|
|
objname[last] = '\0';
|
|
}
|
|
dbeFile = new DbeFile (objname ? objname : name);
|
|
free (objname);
|
|
dbeFile->filetype |= DbeFile::F_DOT_O;
|
|
}
|
|
if (dbeFile->get_need_refind ())
|
|
{
|
|
disMTime = (time_t) 0;
|
|
stabsMTime = (time_t) 0;
|
|
free (disName);
|
|
free (stabsName);
|
|
disName = NULL;
|
|
stabsName = NULL;
|
|
|
|
// Find the Executable/Shared-Object file of module
|
|
char *path = loadobject->dbeFile->get_location ();
|
|
if (path)
|
|
{
|
|
disPath = strdup (path);
|
|
disName = strdup (path);
|
|
disMTime = loadobject->dbeFile->sbuf.st_mtime;
|
|
}
|
|
|
|
char *objname = get_obj_name_from_lib (name);
|
|
if (objname)
|
|
{
|
|
// in the format of libpath(obj)
|
|
char *namebuf = dbe_strdup (name);
|
|
char *base = namebuf + (objname - name);
|
|
*base = '\0';
|
|
base++;
|
|
size_t last = strlen (base) - 1;
|
|
base[last] = '\0';
|
|
stabsTmp = dbeSession->get_tmp_file_name (base, false);
|
|
dbeSession->tmp_files->append (strdup (stabsTmp));
|
|
|
|
DbeFile *dbf = dbeSession->getDbeFile (namebuf,
|
|
DbeFile::F_DOT_A_LIB | DbeFile::F_FILE);
|
|
path = dbf->get_location ();
|
|
int ar = -1, obj = -1;
|
|
if (path != NULL)
|
|
{
|
|
ar = open64 (path, O_RDONLY | O_LARGEFILE);
|
|
if (ar != -1)
|
|
obj = open64 (stabsTmp, O_CREAT | O_WRONLY | O_LARGEFILE, 0600);
|
|
}
|
|
if (ar != -1 && obj != -1 && read_ar (ar, obj, base))
|
|
{
|
|
dbeFile->set_location (stabsTmp);
|
|
dbeFile->check_access (stabsTmp); // init 'sbuf'
|
|
dbeFile->sbuf.st_mtime = 0; // Don't check timestamps
|
|
dbeFile->container = dbf;
|
|
stabsPath = strdup (stabsTmp);
|
|
stabsName = strdup (path);
|
|
stabsMTime = dbeFile->sbuf.st_mtime;
|
|
}
|
|
else
|
|
{
|
|
removeStabsTmp ();
|
|
objname = NULL;
|
|
}
|
|
if (ar != -1)
|
|
close (ar);
|
|
if (obj != -1)
|
|
close (obj);
|
|
free (namebuf);
|
|
}
|
|
if (objname == NULL)
|
|
{
|
|
path = dbeFile->get_location ();
|
|
if (path != NULL)
|
|
{
|
|
stabsPath = strdup (path);
|
|
stabsName = strdup (path);
|
|
stabsMTime = hasDwarf ? 0 : dbeFile->sbuf.st_mtime;
|
|
}
|
|
}
|
|
|
|
// First, try to access the symbol table of the module itself
|
|
// If failed, access the symbol table of the executable
|
|
if (stabsPath == NULL)
|
|
{
|
|
if (disPath == NULL)
|
|
return false;
|
|
stabsPath = strdup (disPath);
|
|
stabsName = strdup (disName);
|
|
stabsMTime = disMTime;
|
|
}
|
|
else if (disPath == NULL)
|
|
{
|
|
disPath = strdup (stabsPath);
|
|
disName = strdup (stabsName);
|
|
disMTime = stabsMTime;
|
|
}
|
|
}
|
|
return stabsPath != NULL;
|
|
}
|
|
|
|
// openStabs -- open mappings from PCs to source lines
|
|
bool
|
|
Module::openStabs (bool all)
|
|
{
|
|
if ((loadobject->flags & SEG_FLAG_DYNAMIC) != 0
|
|
|| (flags & MOD_FLAG_UNKNOWN) != 0)
|
|
return true;
|
|
if (loadobject->platform == Java)
|
|
{
|
|
setIncludeFile (NULL);
|
|
readFile ();
|
|
return ( status == AE_OK);
|
|
}
|
|
if (readStabs)
|
|
return true;
|
|
|
|
// Read Stabs info.
|
|
int64_t Inode = main_source->getInode ();
|
|
char *fname = strrchr (file_name, (int) '/');
|
|
char *mname = strrchr (main_source->get_name (), (int) '/');
|
|
if (fname && mname && !streq (fname, mname))
|
|
{
|
|
SourceFile *sf = findSource (file_name, false);
|
|
if (sf != NULL)
|
|
Inode = sf->getInode ();
|
|
}
|
|
|
|
comComs = new Vector<ComC*>;
|
|
Stabs *stabs = openDebugInfo ();
|
|
if (stabs == NULL)
|
|
return false;
|
|
int st = stabs->read_stabs (Inode, this, comComs, true);
|
|
if (!hasDwarf && hasStabs && !streq (stabsPath, disPath))
|
|
{
|
|
// Read stabs from .o file
|
|
if (dot_o_file == NULL)
|
|
{
|
|
if (dbeFile->get_location ())
|
|
{
|
|
dot_o_file = createLoadObject (dbeFile->get_name ());
|
|
dot_o_file->dbeFile->set_location (dbeFile->get_location ());
|
|
dot_o_file->dbeFile->sbuf = dbeFile->sbuf;
|
|
dot_o_file->dbeFile->container = dbeFile->container;
|
|
}
|
|
}
|
|
if (dot_o_file
|
|
&& dot_o_file->sync_read_stabs () == LoadObject::ARCHIVE_SUCCESS)
|
|
{
|
|
Stabs *stabs_o = dot_o_file->objStabs;
|
|
if (stabs_o)
|
|
{
|
|
st = stabs_o->read_stabs (Inode, this,
|
|
comComs->size () > 0 ? NULL : comComs);
|
|
Elf *elf_o = stabs_o->openElf (false);
|
|
if (elf_o->dwarf)
|
|
stabs->read_dwarf_from_dot_o (this);
|
|
}
|
|
}
|
|
}
|
|
if (all)
|
|
read_hwcprof_info ();
|
|
|
|
readStabs = true;
|
|
return st == Stabs::DBGD_ERR_NONE;
|
|
}
|
|
|
|
char *
|
|
Module::get_disasm (uint64_t inst_address, uint64_t end_address,
|
|
uint64_t start_address, uint64_t address, int64_t &inst_size)
|
|
{
|
|
return disasm->get_disasm (inst_address, end_address, start_address,
|
|
address, inst_size);
|
|
}
|
|
|
|
void
|
|
Module::read_stabs (bool all)
|
|
{
|
|
if (openSourceFlag == AE_NOTREAD)
|
|
{
|
|
openSourceFlag = AE_OK;
|
|
if (lang_code == Sp_lang_java)
|
|
{
|
|
char *clpath = file_name;
|
|
if (clpath == NULL || strcmp (clpath, "<Unknown>") == 0)
|
|
clpath = ClassFile::get_java_file_name (name, false);
|
|
main_source = findSource (clpath, true);
|
|
main_source->dbeFile->filetype |= DbeFile::F_JAVA_SOURCE;
|
|
if (clpath != file_name)
|
|
free (clpath);
|
|
}
|
|
else
|
|
main_source = findSource (file_name, true);
|
|
if (setFile ())
|
|
openStabs (all);
|
|
}
|
|
}
|
|
|
|
bool
|
|
Module::openDisPC ()
|
|
{
|
|
if (disasm == NULL)
|
|
{
|
|
if (!(loadobject->flags & SEG_FLAG_DYNAMIC) && loadobject->platform != Java)
|
|
{
|
|
// Read Stabs & Symbol tables
|
|
if (openDebugInfo () == NULL)
|
|
return false;
|
|
if (!objStabs->read_symbols (functions))
|
|
return false;
|
|
}
|
|
disasm = new Disasm (loadobject->platform, objStabs);
|
|
}
|
|
return true;
|
|
}
|
|
|
|
static SourceFile *cmpSrcContext; // Use only for func_cmp
|
|
|
|
static int
|
|
func_cmp (const void *a, const void *b)
|
|
{
|
|
Function *fp1 = *((Function **) a);
|
|
Function *fp2 = *((Function **) b);
|
|
return fp1->func_cmp (fp2, cmpSrcContext);
|
|
}
|
|
|
|
bool
|
|
Module::computeMetrics (DbeView *dbev, Function *func, MetricList *metrics,
|
|
Histable::Type type, bool src_metric,
|
|
bool func_scope, SourceFile *source)
|
|
{
|
|
name_idx = metrics->get_listorder (NTXT ("name"), Metric::STATIC);
|
|
if (name_idx < 0)
|
|
{
|
|
metrics->print_metric_list (stderr,
|
|
GTXT ("Fatal: no name metric in Module::computeMetrics mlist:\n"),
|
|
1);
|
|
abort ();
|
|
}
|
|
|
|
// Now find the metrics for size and address, if present
|
|
size_index = metrics->get_listorder (NTXT ("size"), Metric::STATIC);
|
|
addr_index = metrics->get_listorder (NTXT ("address"), Metric::STATIC);
|
|
|
|
// free the old cached data for both src and disassembly
|
|
// If it's disassembly with visible source metrics, we use both
|
|
if (dis_items)
|
|
{
|
|
delete dis_items;
|
|
dis_items = NULL;
|
|
}
|
|
if (src_items)
|
|
{
|
|
delete src_items;
|
|
src_items = NULL;
|
|
}
|
|
|
|
// ask the DbeView to generate new data to be cached
|
|
if (src_metric || type == Histable::LINE)
|
|
{
|
|
Histable *obj = (func_scope) ? (Histable*) func : (Histable*)this;
|
|
if (lang_code == Sp_lang_java)
|
|
obj = func_scope ? (Histable *) func :
|
|
(source && source->get_type () == Histable::SOURCEFILE ?
|
|
(Histable *) source : (Histable *) this);
|
|
src_items = dbev->get_hist_data (metrics, Histable::LINE, 0,
|
|
Hist_data::MODL, obj, source);
|
|
}
|
|
if (type == Histable::INSTR)
|
|
dis_items = dbev->get_hist_data (metrics, Histable::INSTR, 0,
|
|
Hist_data::MODL,
|
|
func_scope ? (Histable*) func : (Histable*) this,
|
|
source);
|
|
|
|
Hist_data *cur_hist_data;
|
|
if (type == Histable::INSTR)
|
|
cur_hist_data = dis_items;
|
|
else
|
|
cur_hist_data = src_items;
|
|
|
|
Vector<Metric*> *items = cur_hist_data->get_metric_list ()->get_items ();
|
|
long sz = items->size ();
|
|
empty = new TValue[sz];
|
|
memset (empty, 0, sizeof (TValue) * sz);
|
|
for (long i = 0; i < sz; i++)
|
|
empty[i].tag = items->get (i)->get_vtype ();
|
|
return true;
|
|
}
|
|
|
|
// Method to get annotated source or disassembly for the module
|
|
// or a function within it
|
|
Hist_data *
|
|
Module::get_data (DbeView *dbev, MetricList *mlist, Histable::Type type,
|
|
TValue *ftotal, SourceFile *srcFile, Function *func,
|
|
Vector<int> *marks, int threshold, int vis_bits,
|
|
int src_visible, bool hex_vis, bool func_scope,
|
|
bool /*src_only*/, Vector<int_pair_t> *marks2d,
|
|
Vector<int_pair_t> *marks2d_inc)
|
|
{
|
|
cur_dbev = dbev;
|
|
srcContext = srcFile ? srcFile : main_source;
|
|
read_stabs ();
|
|
status = AE_OK;
|
|
dbev->warning_msg = NULL;
|
|
dbev->error_msg = NULL;
|
|
if (type == Histable::LINE)
|
|
{
|
|
if (!srcContext->readSource ())
|
|
{
|
|
status = AE_NOSRC;
|
|
dbev->error_msg = anno_str (srcContext->get_name ());
|
|
return NULL;
|
|
}
|
|
if (!computeMetrics (dbev, func, mlist, type, false, func_scope, srcContext))
|
|
{
|
|
status = AE_OTHER;
|
|
dbev->error_msg = anno_str ();
|
|
return NULL;
|
|
}
|
|
status = checkTimeStamp (false);
|
|
}
|
|
else
|
|
{ // Histable::INSTR
|
|
Anno_Errors src_status = AE_OK;
|
|
if (!srcContext->readSource ())
|
|
{
|
|
src_status = AE_NOSRC;
|
|
dbev->error_msg = anno_str (srcContext->get_name ());
|
|
}
|
|
if (!setFile ())
|
|
status = AE_NOLOBJ;
|
|
else
|
|
{
|
|
if (!openStabs ())
|
|
src_status = AE_NOSTABS;
|
|
if (!openDisPC ())
|
|
status = AE_NOSYMTAB;
|
|
}
|
|
if (status != AE_OK)
|
|
{
|
|
dbev->error_msg = anno_str ();
|
|
return NULL;
|
|
}
|
|
if (src_status != AE_OK && func != NULL)
|
|
{
|
|
if (loadobject->platform == Java && (func->flags & FUNC_FLAG_NATIVE) != 0)
|
|
{
|
|
append_msg (CMSG_ERROR,
|
|
GTXT ("`%s' is a native method; byte code not available\n"),
|
|
func->get_name ());
|
|
status = AE_NOOBJ;
|
|
dbev->error_msg = anno_str ();
|
|
return NULL;
|
|
}
|
|
func_scope = true;
|
|
}
|
|
// get the disassembly-line metric data
|
|
if (!computeMetrics (dbev, func, mlist, type,
|
|
(src_visible & SRC_METRIC) != 0,
|
|
func_scope, srcContext))
|
|
{
|
|
status = AE_OTHER;
|
|
dbev->error_msg = anno_str ();
|
|
return NULL;
|
|
}
|
|
status = checkTimeStamp (true);
|
|
}
|
|
total = ftotal;
|
|
|
|
// initialize line number
|
|
init_line ();
|
|
|
|
// initialize data -- get duplicate metric list for the line texts
|
|
// pick up the metric list from the computed data
|
|
MetricList *nmlist = NULL;
|
|
if (type == Histable::INSTR)
|
|
{
|
|
mlist = dis_items->get_metric_list ();
|
|
nmlist = new MetricList (mlist);
|
|
data_items = new Hist_data (nmlist, Histable::INSTR, Hist_data::MODL);
|
|
data_items->set_status (dis_items->get_status ());
|
|
set_dis_data (func, vis_bits, dbev->get_cmpline_visible (),
|
|
src_visible, hex_vis, func_scope,
|
|
dbev->get_funcline_visible ());
|
|
}
|
|
else
|
|
{
|
|
mlist = src_items->get_metric_list ();
|
|
nmlist = new MetricList (mlist);
|
|
data_items = new Hist_data (nmlist, Histable::LINE, Hist_data::MODL);
|
|
data_items->set_status (src_items->get_status ());
|
|
set_src_data (func_scope ? func : NULL, vis_bits,
|
|
dbev->get_cmpline_visible (),
|
|
dbev->get_funcline_visible ());
|
|
}
|
|
data_items->compute_minmax ();
|
|
|
|
Metric *mitem;
|
|
int index;
|
|
Hist_data::HistItem *max_item;
|
|
TValue *value;
|
|
Hist_data::HistItem *max_item_inc;
|
|
TValue *value_inc;
|
|
double dthreshold = threshold / 100.0;
|
|
|
|
int sz = data_items->get_metric_list ()->get_items ()->size ();
|
|
maximum = new TValue[sz];
|
|
maximum_inc = new TValue[sz];
|
|
memset (maximum, 0, sizeof (TValue) * sz);
|
|
memset (maximum_inc, 0, sizeof (TValue) * sz);
|
|
max_item = data_items->get_maximums ();
|
|
max_item_inc = data_items->get_maximums_inc ();
|
|
|
|
Vec_loop (Metric*, data_items->get_metric_list ()->get_items (), index, mitem)
|
|
{
|
|
maximum_inc[index].tag = maximum[index].tag = mitem->get_vtype ();
|
|
|
|
if (mitem->get_subtype () == Metric::STATIC)
|
|
continue;
|
|
if (!mitem->is_visible () && !mitem->is_tvisible ()
|
|
&& !mitem->is_pvisible ())
|
|
continue;
|
|
|
|
value = &max_item->value[index];
|
|
value_inc = &max_item_inc->value[index];
|
|
|
|
double dthresh;
|
|
if (mitem->is_zeroThreshold () == true)
|
|
dthresh = 0;
|
|
else
|
|
dthresh = dthreshold;
|
|
switch (value->tag)
|
|
{
|
|
case VT_INT:
|
|
maximum[index].i = (int) (dthresh * (double) value->i);
|
|
maximum_inc[index].i = (int) (dthresh * (double) value_inc->i);
|
|
break;
|
|
case VT_DOUBLE:
|
|
maximum[index].d = dthresh * value->d;
|
|
maximum_inc[index].d = dthresh * value_inc->d;
|
|
break;
|
|
case VT_LLONG:
|
|
maximum[index].ll = (unsigned long long) (dthresh * (double) value->ll);
|
|
maximum_inc[index].ll = (unsigned long long)
|
|
(dthresh * (double) value_inc->ll);
|
|
break;
|
|
case VT_ULLONG:
|
|
maximum[index].ull = (unsigned long long)
|
|
(dthresh * (double) value->ull);
|
|
maximum_inc[index].ull = (unsigned long long)
|
|
(dthresh * (double) value_inc->ull);
|
|
break;
|
|
default:
|
|
// not needed for non-numerical metrics
|
|
break;
|
|
}
|
|
}
|
|
|
|
// mark all high values
|
|
for (int index1 = 0; index1 < data_items->size (); index1++)
|
|
{
|
|
Hist_data::HistItem *hi = data_items->fetch (index1);
|
|
int index2;
|
|
Vec_loop (Metric*, nmlist->get_items (), index2, mitem)
|
|
{
|
|
bool mark = false;
|
|
if (mitem->get_subtype () == Metric::STATIC)
|
|
continue;
|
|
if (!mitem->is_visible () && !mitem->is_tvisible ()
|
|
&& !mitem->is_pvisible ())
|
|
continue;
|
|
|
|
switch (hi->value[index2].tag)
|
|
{
|
|
case VT_DOUBLE:
|
|
if (nmlist->get_type () == MET_SRCDIS
|
|
&& data_items->get_callsite_mark ()->get (hi->obj))
|
|
{
|
|
if (hi->value[index2].d > maximum_inc[index2].d)
|
|
mark = true;
|
|
break;
|
|
}
|
|
if (hi->value[index2].d > maximum[index2].d)
|
|
mark = true;
|
|
break;
|
|
case VT_INT:
|
|
if (nmlist->get_type () == MET_SRCDIS
|
|
&& data_items->get_callsite_mark ()->get (hi->obj))
|
|
{
|
|
if (hi->value[index2].i > maximum_inc[index2].i)
|
|
mark = true;
|
|
break;
|
|
}
|
|
if (hi->value[index2].i > maximum[index2].i)
|
|
mark = true;
|
|
break;
|
|
case VT_LLONG:
|
|
if (nmlist->get_type () == MET_SRCDIS
|
|
&& data_items->get_callsite_mark ()->get (hi->obj))
|
|
{
|
|
if (hi->value[index2].ll > maximum_inc[index2].ll)
|
|
mark = true;
|
|
break;
|
|
}
|
|
if (hi->value[index2].ll > maximum[index2].ll)
|
|
mark = true;
|
|
break;
|
|
case VT_ULLONG:
|
|
if (nmlist->get_type () == MET_SRCDIS
|
|
&& data_items->get_callsite_mark ()->get (hi->obj))
|
|
{
|
|
if (hi->value[index2].ull > maximum_inc[index2].ull)
|
|
mark = true;
|
|
break;
|
|
}
|
|
if (hi->value[index2].ull > maximum[index2].ull)
|
|
mark = true;
|
|
break;
|
|
// ignoring the following cases (why?)
|
|
case VT_SHORT:
|
|
case VT_FLOAT:
|
|
case VT_HRTIME:
|
|
case VT_LABEL:
|
|
case VT_ADDRESS:
|
|
case VT_OFFSET:
|
|
break;
|
|
}
|
|
if (mark)
|
|
{
|
|
marks->append (index1);
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
// mark all high values to marks2d
|
|
if (marks2d != NULL && marks2d_inc != NULL)
|
|
{
|
|
for (int index1 = 0; index1 < data_items->size (); index1++)
|
|
{
|
|
Hist_data::HistItem *hi = data_items->fetch (index1);
|
|
int index2;
|
|
Vec_loop (Metric*, nmlist->get_items (), index2, mitem)
|
|
{
|
|
Metric::SubType subType = mitem->get_subtype ();
|
|
if (subType == Metric::STATIC)
|
|
continue;
|
|
if (!mitem->is_visible () && !mitem->is_tvisible ()
|
|
&& !mitem->is_pvisible ())
|
|
continue;
|
|
switch (hi->value[index2].tag)
|
|
{
|
|
case VT_DOUBLE:
|
|
if (nmlist->get_type () == MET_SRCDIS
|
|
&& data_items->get_callsite_mark ()->get (hi->obj))
|
|
{
|
|
if (hi->value[index2].d > maximum_inc[index2].d)
|
|
{
|
|
int_pair_t pair = {index1, index2};
|
|
marks2d_inc->append (pair);
|
|
}
|
|
break;
|
|
}
|
|
if (hi->value[index2].d > maximum[index2].d)
|
|
{
|
|
int_pair_t pair = {index1, index2};
|
|
marks2d->append (pair);
|
|
}
|
|
break;
|
|
case VT_INT:
|
|
if (nmlist->get_type () == MET_SRCDIS
|
|
&& data_items->get_callsite_mark ()->get (hi->obj))
|
|
{
|
|
if (hi->value[index2].i > maximum_inc[index2].i)
|
|
{
|
|
int_pair_t pair = {index1, index2};
|
|
marks2d_inc->append (pair);
|
|
}
|
|
break;
|
|
}
|
|
if (hi->value[index2].i > maximum[index2].i)
|
|
{
|
|
int_pair_t pair = {index1, index2};
|
|
marks2d->append (pair);
|
|
}
|
|
break;
|
|
case VT_LLONG:
|
|
if (nmlist->get_type () == MET_SRCDIS
|
|
&& data_items->get_callsite_mark ()->get (hi->obj))
|
|
{
|
|
if (hi->value[index2].ll > maximum_inc[index2].ll)
|
|
{
|
|
int_pair_t pair = {index1, index2};
|
|
marks2d_inc->append (pair);
|
|
}
|
|
break;
|
|
}
|
|
if (hi->value[index2].ll > maximum[index2].ll)
|
|
{
|
|
int_pair_t pair = {index1, index2};
|
|
marks2d->append (pair);
|
|
}
|
|
break;
|
|
case VT_ULLONG:
|
|
if (nmlist->get_type () == MET_SRCDIS
|
|
&& data_items->get_callsite_mark ()->get (hi->obj))
|
|
{
|
|
if (hi->value[index2].ull > maximum_inc[index2].ull)
|
|
{
|
|
int_pair_t pair = {index1, index2};
|
|
marks2d_inc->append (pair);
|
|
}
|
|
break;
|
|
}
|
|
if (hi->value[index2].ull > maximum[index2].ull)
|
|
{
|
|
int_pair_t pair = {index1, index2};
|
|
marks2d->append (pair);
|
|
}
|
|
break;
|
|
case VT_SHORT:
|
|
case VT_FLOAT:
|
|
case VT_HRTIME:
|
|
case VT_LABEL:
|
|
case VT_ADDRESS:
|
|
case VT_OFFSET:
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
// free memory used by Computing & Printing metrics
|
|
delete[] maximum;
|
|
delete[] maximum_inc;
|
|
delete[] empty;
|
|
maximum = NULL;
|
|
maximum_inc = NULL;
|
|
empty = NULL;
|
|
dbev->warning_msg = anno_str ();
|
|
return data_items;
|
|
}
|
|
|
|
Vector<uint64_t> *
|
|
Module::getAddrs (Function *func)
|
|
{
|
|
uint64_t start_address = func->img_offset;
|
|
uint64_t end_address = start_address + func->size;
|
|
int64_t inst_size = 0;
|
|
|
|
// initialize "disasm" if necessary
|
|
if (!openDisPC ())
|
|
return NULL;
|
|
|
|
Vector<uint64_t> *addrs = new Vector<uint64_t>;
|
|
for (uint64_t inst_address = start_address; inst_address < end_address;)
|
|
{
|
|
char *s = disasm->get_disasm (inst_address, end_address, start_address,
|
|
func->img_offset, inst_size);
|
|
free (s);
|
|
addrs->append (inst_address - start_address);
|
|
inst_address += inst_size;
|
|
if (inst_size == 0)
|
|
break;
|
|
}
|
|
return addrs;
|
|
}
|
|
|
|
void
|
|
Module::init_line ()
|
|
{
|
|
// initialize the compiler commentary data
|
|
cindex = 0;
|
|
if (comComs != NULL && comComs->size () > 0)
|
|
cline = comComs->fetch (cindex)->line;
|
|
else
|
|
cline = -1;
|
|
|
|
sindex = 0;
|
|
if (src_items && src_items->size () > 0)
|
|
sline = ((DbeLine*) src_items->fetch (0)->obj)->lineno;
|
|
else
|
|
sline = -1;
|
|
|
|
dindex = 0;
|
|
mindex = 0;
|
|
mline = -1;
|
|
if (dis_items && dis_items->size () > 0)
|
|
{
|
|
daddr = (DbeInstr*) dis_items->fetch (0)->obj;
|
|
|
|
// After sorting all HistItems with PCLineFlag appear
|
|
// at the end of the list. Find the first one.
|
|
for (mindex = dis_items->size () - 1; mindex >= 0; mindex--)
|
|
{
|
|
Hist_data::HistItem *item = dis_items->fetch (mindex);
|
|
if (!(((DbeInstr*) item->obj)->flags & PCLineFlag))
|
|
break;
|
|
mline = (unsigned) (((DbeInstr*) item->obj)->addr);
|
|
}
|
|
mindex++;
|
|
}
|
|
else
|
|
daddr = NULL;
|
|
}
|
|
|
|
void
|
|
Module::set_src_data (Function *func, int vis_bits, int cmpline_visible,
|
|
int funcline_visible)
|
|
{
|
|
Function *curr_func = NULL;
|
|
|
|
// start at the top of the file, and loop over all lines in the file (source context)
|
|
for (curline = 1; curline <= srcContext->getLineCount (); curline++)
|
|
{
|
|
// Before writing the line, see if there's compiler commentary to insert
|
|
if (cline == curline)
|
|
set_ComCom (vis_bits);
|
|
|
|
// Find out if we need to print zero metrics with the line
|
|
DbeLine *dbeline = srcContext->find_dbeline (NULL, curline);
|
|
Anno_Types type = AT_SRC_ONLY;
|
|
if (dbeline->dbeline_func_next)
|
|
{
|
|
if (func)
|
|
for (DbeLine *dl = dbeline->dbeline_func_next; dl; dl = dl->dbeline_func_next)
|
|
{
|
|
if (dl->func == func)
|
|
{
|
|
type = AT_SRC;
|
|
break;
|
|
}
|
|
}
|
|
else
|
|
type = AT_SRC;
|
|
}
|
|
|
|
if (funcline_visible)
|
|
{ // show red lines
|
|
// is there a function index line to insert?
|
|
Function *func_next = NULL;
|
|
for (DbeLine *dl = dbeline; dl; dl = dl->dbeline_func_next)
|
|
{
|
|
Function *f = dl->func;
|
|
if (f && f->line_first == curline
|
|
&& f->getDefSrc () == srcContext)
|
|
{
|
|
if (lang_code == Sp_lang_java
|
|
&& (f->flags & FUNC_FLAG_DYNAMIC))
|
|
continue;
|
|
if (cur_dbev && cur_dbev->get_path_tree ()->get_func_nodeidx (f))
|
|
{
|
|
func_next = f;
|
|
break;
|
|
}
|
|
else if (func_next == NULL)
|
|
func_next = f;
|
|
}
|
|
}
|
|
if (func_next && curr_func != func_next)
|
|
{
|
|
curr_func = func_next;
|
|
char *func_name = curr_func->get_name ();
|
|
if (is_fortran () && streq (func_name, NTXT ("MAIN_")))
|
|
func_name = curr_func->get_match_name ();
|
|
Hist_data::HistItem *item =
|
|
src_items->new_hist_item (curr_func, AT_FUNC, empty);
|
|
item->value[name_idx].l = dbe_sprintf (GTXT ("<Function: %s>"),
|
|
func_name);
|
|
data_items->append_hist_item (item);
|
|
}
|
|
} // end of red line
|
|
set_src (type, dbeline); // add the source line
|
|
} // end of loop over source lines
|
|
|
|
// See if compiler flags are set; if so, append them
|
|
if (cmpline_visible && comp_flags)
|
|
{
|
|
Hist_data::HistItem *item = src_items->new_hist_item (NULL, AT_EMPTY,
|
|
empty);
|
|
item->value[name_idx].l = strdup (NTXT (""));
|
|
data_items->append_hist_item (item);
|
|
item = src_items->new_hist_item (NULL, AT_COM, empty);
|
|
item->value[name_idx].l = dbe_sprintf (GTXT ("Compile flags: %s"),
|
|
comp_flags);
|
|
data_items->append_hist_item (item);
|
|
}
|
|
}
|
|
|
|
void
|
|
Module::set_dis_data (Function *func, int vis_bits, int cmpline_visible,
|
|
int src_visible, bool hex_vis, bool func_scope,
|
|
int funcline_visible)
|
|
{
|
|
bool nextFile = false;
|
|
|
|
// initialize the source output, if any
|
|
curline = (srcContext->getLineCount () > 0) ? 1 : -1;
|
|
if (func)
|
|
nextFile = srcContext != func->getDefSrc ();
|
|
curr_inc = srcContext;
|
|
|
|
bool src_code = (src_visible & SRC_CODE);
|
|
Anno_Types src_type = (src_visible & SRC_METRIC) ? AT_SRC : AT_SRC_ONLY;
|
|
|
|
char *img_fname = func ? func->img_fname : NULL;
|
|
|
|
// Build a new Function list
|
|
Vector<Function*> *FuncLst = new Vector<Function*>;
|
|
if (func_scope)
|
|
{
|
|
if (func)
|
|
FuncLst->append (func);
|
|
}
|
|
else
|
|
{
|
|
for (int i = 0, sz = functions ? functions->size () : 0; i < sz; i++)
|
|
{
|
|
Function *fitem = functions->fetch (i);
|
|
if (fitem != fitem->cardinal ())
|
|
continue;
|
|
if (img_fname == NULL)
|
|
img_fname = fitem->img_fname;
|
|
if (fitem->img_fname == NULL || strcmp (fitem->img_fname, img_fname))
|
|
continue;
|
|
FuncLst->append (fitem);
|
|
}
|
|
}
|
|
if (FuncLst->size () == 0)
|
|
{ // no function is good
|
|
delete FuncLst;
|
|
return;
|
|
}
|
|
cmpSrcContext = srcContext;
|
|
FuncLst->sort (func_cmp);
|
|
|
|
disasm->set_hex_visible (hex_vis);
|
|
for (int index = 0, sz = FuncLst->size (); index < sz; index++)
|
|
{
|
|
Function *fitem = FuncLst->fetch (index);
|
|
uint64_t start_address, end_address;
|
|
int64_t inst_size;
|
|
if (fitem->getDefSrc () != srcContext && curline > 0)
|
|
{
|
|
// now flush the left source line, if available
|
|
for (; curline <= srcContext->getLineCount (); curline++)
|
|
{
|
|
// see if there's a compiler comment line to dump
|
|
if (cline == curline)
|
|
set_ComCom (vis_bits);
|
|
if (src_code)
|
|
set_src (src_type, srcContext->find_dbeline (curline));
|
|
}
|
|
curline = -1;
|
|
}
|
|
|
|
curr_inc = NULL;
|
|
// disassemble one function
|
|
start_address = objStabs ?
|
|
objStabs->mapOffsetToAddress (fitem->img_offset) : 0;
|
|
end_address = start_address + fitem->size;
|
|
inst_size = 0;
|
|
|
|
disasm->set_addr_end (end_address);
|
|
if ((loadobject->flags & SEG_FLAG_DYNAMIC)
|
|
&& loadobject->platform != Java)
|
|
disasm->set_img_name (img_fname);
|
|
|
|
for (uint64_t inst_address = start_address; inst_address < end_address;)
|
|
{
|
|
uint64_t address = inst_address - start_address;
|
|
DbeInstr *instr = fitem->find_dbeinstr (0, address);
|
|
DbeLine *dbeline = (DbeLine *) (instr->convertto (Histable::LINE));
|
|
if (instr->lineno == -1 && dbeline && dbeline->lineno > 0)
|
|
instr->lineno = dbeline->lineno;
|
|
|
|
// now write the unannotated source line, if available
|
|
if (curline > 0)
|
|
{ // source is present
|
|
int lineno = curline - 1;
|
|
if (instr->lineno != -1)
|
|
{
|
|
if (dbeline && streq (dbeline->sourceFile->get_name (),
|
|
srcContext->get_name ()))
|
|
lineno = instr->lineno;
|
|
}
|
|
else if (curr_inc == NULL && srcContext == fitem->def_source
|
|
&& fitem->line_first > 0)
|
|
lineno = fitem->line_first;
|
|
|
|
for (; curline <= lineno; curline++)
|
|
{
|
|
// see if there's a compiler comment line to dump
|
|
if (cline == curline)
|
|
set_ComCom (vis_bits);
|
|
if (mline == curline)
|
|
set_MPSlave ();
|
|
if (src_code)
|
|
set_src (src_type, srcContext->find_dbeline (curline));
|
|
if (curline >= srcContext->getLineCount ())
|
|
{
|
|
curline = -1;
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
if (funcline_visible)
|
|
{ // show red lines
|
|
if (!curr_inc || (dbeline && curr_inc != dbeline->sourceFile))
|
|
{
|
|
Hist_data::HistItem *item = dis_items->new_hist_item (dbeline, AT_FUNC, empty);
|
|
curr_inc = dbeline ? dbeline->sourceFile : srcContext;
|
|
char *str;
|
|
if (curr_inc != srcContext)
|
|
{
|
|
char *fileName = curr_inc->dbeFile->getResolvedPath ();
|
|
str = dbe_sprintf (GTXT ("<Function: %s, instructions from source file %s>"),
|
|
fitem->get_name (), fileName);
|
|
}
|
|
else
|
|
str = dbe_sprintf (GTXT ("<Function: %s>"),
|
|
fitem->get_name ());
|
|
item->value[name_idx].l = str;
|
|
data_items->append_hist_item (item);
|
|
}
|
|
}
|
|
|
|
char *dis_str = get_disasm (inst_address, end_address, start_address,
|
|
fitem->img_offset, inst_size);
|
|
if (inst_size == 0)
|
|
break;
|
|
else if (instr->size == 0)
|
|
instr->size = (unsigned int) inst_size;
|
|
inst_address += inst_size;
|
|
|
|
// stomp out control characters
|
|
for (size_t i = 0, len = strlen (dis_str); i < len; i++)
|
|
{
|
|
if (dis_str[i] == '\t')
|
|
dis_str[i] = ' ';
|
|
}
|
|
|
|
for (int i = 0; i < bTargets.size (); i++)
|
|
{
|
|
target_info_t *bTarget = bTargets.fetch (i);
|
|
if (bTarget->offset == fitem->img_offset + address)
|
|
{
|
|
// insert a new line for the bTarget
|
|
size_t colon = strcspn (dis_str, NTXT (":"));
|
|
char *msg = GTXT ("* <branch target>");
|
|
size_t len = colon + strlen (msg);
|
|
len = (len < 50) ? (50 - len) : 1;
|
|
char *new_dis_str = dbe_sprintf ("%.*s%s%*c <===----<<<",
|
|
(int) colon, dis_str, msg,
|
|
(int) len, ' ');
|
|
DbeInstr *bt = fitem->find_dbeinstr (PCTrgtFlag, address);
|
|
bt->lineno = instr->lineno;
|
|
bt->size = 0;
|
|
set_dis (bt, AT_DIS, nextFile, new_dis_str);
|
|
break;
|
|
}
|
|
}
|
|
|
|
// AnalyzerInfo/Datatype annotations
|
|
if (infoList != NULL)
|
|
{
|
|
inst_info_t *info = NULL;
|
|
int pinfo;
|
|
Vec_loop (inst_info_t*, infoList, pinfo, info)
|
|
{
|
|
if (info->offset == fitem->img_offset + address) break;
|
|
}
|
|
if (info != NULL)
|
|
{ // got a matching memop
|
|
char typetag[400];
|
|
typetag[0] = '\0';
|
|
long t;
|
|
datatype_t *dtype = NULL;
|
|
Vec_loop (datatype_t*, datatypes, t, dtype)
|
|
{
|
|
if (dtype->datatype_id == info->memop->datatype_id)
|
|
break;
|
|
}
|
|
if (datatypes != NULL)
|
|
{
|
|
size_t len = strlen (typetag);
|
|
if (dtype == NULL || t == datatypes->size ())
|
|
snprintf (typetag + len, sizeof (typetag) - len, "%s",
|
|
PTXT (DOBJ_UNSPECIFIED));
|
|
else if (dtype->dobj == NULL)
|
|
snprintf (typetag + len, sizeof (typetag) - len, "%s",
|
|
PTXT (DOBJ_UNDETERMINED));
|
|
else
|
|
snprintf (typetag + len, sizeof (typetag) - len, "%s",
|
|
dtype->dobj->get_name ());
|
|
}
|
|
if (strlen (typetag) > 1)
|
|
{
|
|
char *new_dis_str;
|
|
new_dis_str = dbe_sprintf ("%-50s %s", dis_str, typetag);
|
|
free (dis_str);
|
|
dis_str = new_dis_str;
|
|
}
|
|
}
|
|
}
|
|
set_dis (instr, AT_DIS, nextFile, dis_str);
|
|
}
|
|
}
|
|
|
|
// now flush the left source line, if available
|
|
if (curline > 0)
|
|
{ // source is present
|
|
for (; curline <= srcContext->getLineCount (); curline++)
|
|
{
|
|
// see if there's a compiler comment line to dump
|
|
if (cline == curline)
|
|
set_ComCom (vis_bits);
|
|
|
|
if (src_code)
|
|
set_src (src_type, srcContext->find_dbeline (curline));
|
|
}
|
|
}
|
|
|
|
// See if compiler flags are set; if so, append them
|
|
if (cmpline_visible && comp_flags)
|
|
{
|
|
Hist_data::HistItem *item = dis_items->new_hist_item (NULL, AT_EMPTY,
|
|
empty);
|
|
item->value[name_idx].l = dbe_strdup (NTXT (""));
|
|
data_items->append_hist_item (item);
|
|
item = dis_items->new_hist_item (NULL, AT_COM, empty);
|
|
item->value[name_idx].l = dbe_sprintf (GTXT ("Compile flags: %s"),
|
|
comp_flags);
|
|
data_items->append_hist_item (item);
|
|
}
|
|
delete FuncLst;
|
|
}
|
|
|
|
// set_src -- inserts one or more lines into the growing data list
|
|
void
|
|
Module::set_src (Anno_Types type, DbeLine *dbeline)
|
|
{
|
|
Hist_data::HistItem *item;
|
|
|
|
// Flush items that are not represented in source
|
|
while (sline >= 0 && sline < curline)
|
|
{
|
|
item = src_items->fetch (sindex);
|
|
if (((DbeLine*) item->obj)->lineno > 0)
|
|
set_one (item, AT_QUOTE, item->obj->get_name ());
|
|
|
|
if (++sindex < src_items->size ()) // get next line with metrics
|
|
sline = ((DbeLine*) src_items->fetch (sindex)->obj)->lineno;
|
|
else
|
|
sline = -1;
|
|
}
|
|
|
|
// write values in the metric fields for the given source line
|
|
if (curline == sline)
|
|
{ // got metrics for this line
|
|
item = src_items->fetch (sindex);
|
|
if (((DbeLine*) item->obj)->lineno > 0)
|
|
set_one (item, AT_SRC, srcContext->getLine (curline));
|
|
|
|
if (++sindex < src_items->size ()) // get next line metric index
|
|
sline = ((DbeLine*) src_items->fetch (sindex)->obj)->lineno;
|
|
else
|
|
sline = -1;
|
|
}
|
|
else
|
|
{
|
|
item = data_items->new_hist_item (dbeline, type, empty);
|
|
if (size_index != -1)
|
|
item->value[size_index].ll = dbeline->get_size ();
|
|
if (addr_index != -1)
|
|
item->value[addr_index].ll = dbeline->get_addr ();
|
|
item->value[name_idx].l = dbe_strdup (srcContext->getLine (curline));
|
|
data_items->append_hist_item (item);
|
|
}
|
|
}
|
|
|
|
void
|
|
Module::set_dis (DbeInstr *instr, Anno_Types type, bool nextFile, char *dis_str)
|
|
{
|
|
// Flush items that are not represented in disassembly
|
|
while (daddr && daddr->pc_cmp (instr) < 0)
|
|
{
|
|
if (!nextFile)
|
|
set_one (dis_items->fetch (dindex), AT_QUOTE, daddr->get_name ());
|
|
if (++dindex < dis_items->size ()) // get next line metric index
|
|
daddr = (DbeInstr*) dis_items->fetch (dindex)->obj;
|
|
else
|
|
daddr = NULL;
|
|
}
|
|
|
|
// Write values in the metric fields for the given pc index value
|
|
if (instr->inlinedInd >= 0)
|
|
{
|
|
StringBuilder sb;
|
|
sb.append (dis_str);
|
|
instr->add_inlined_info (&sb);
|
|
free (dis_str);
|
|
dis_str = sb.toString ();
|
|
}
|
|
if (daddr && daddr->pc_cmp (instr) == 0)
|
|
{
|
|
Hist_data::HistItem *item = data_items->new_hist_item (instr, type,
|
|
dis_items->fetch (dindex)->value);
|
|
item->value[name_idx].tag = VT_LABEL;
|
|
item->value[name_idx].l = dis_str;
|
|
data_items->append_hist_item (item);
|
|
if (dis_items->get_callsite_mark ()->get (dis_items->fetch (dindex)->obj))
|
|
data_items->get_callsite_mark ()->put (item->obj, 1);
|
|
|
|
if (++dindex < dis_items->size ()) // get next line metric index
|
|
daddr = (DbeInstr*) dis_items->fetch (dindex)->obj;
|
|
else
|
|
daddr = NULL;
|
|
}
|
|
else
|
|
{
|
|
// create a new item for this PC
|
|
Hist_data::HistItem *item = dis_items->new_hist_item (instr, type, empty);
|
|
if (size_index != -1)
|
|
item->value[size_index].ll = instr->size;
|
|
if (addr_index != -1)
|
|
item->value[addr_index].ll = instr->get_addr ();
|
|
item->value[name_idx].tag = VT_LABEL;
|
|
item->value[name_idx].l = dis_str;
|
|
data_items->append_hist_item (item);
|
|
}
|
|
}
|
|
|
|
void
|
|
Module::set_MPSlave ()
|
|
{
|
|
Hist_data::HistItem *item;
|
|
Function *fp;
|
|
int index;
|
|
|
|
// write the inclusive metrics for slave threads
|
|
while (mline == curline)
|
|
{
|
|
item = dis_items->fetch (mindex);
|
|
DbeInstr *instr = (DbeInstr *) item->obj;
|
|
Vec_loop (Function*, functions, index, fp)
|
|
{
|
|
if (fp->derivedNode == instr)
|
|
{
|
|
set_one (item, AT_QUOTE, (fp->isOutlineFunction) ?
|
|
GTXT ("<inclusive metrics for outlined functions>") :
|
|
GTXT ("<inclusive metrics for slave threads>"));
|
|
break;
|
|
}
|
|
}
|
|
|
|
mindex++;
|
|
if (mindex < dis_items->size ())
|
|
mline = (unsigned) ((DbeInstr*) (dis_items->fetch (mindex)->obj))->addr;
|
|
else
|
|
mline = -1;
|
|
}
|
|
}//set_MPSlave
|
|
|
|
void
|
|
Module::set_one (Hist_data::HistItem *org_item, Anno_Types type,
|
|
const char *text)
|
|
{
|
|
if (org_item == NULL)
|
|
return;
|
|
Hist_data::HistItem *item = data_items->new_hist_item (org_item->obj, type,
|
|
org_item->value);
|
|
item->value[name_idx].tag = VT_LABEL;
|
|
item->value[name_idx].l = dbe_strdup (text);
|
|
data_items->append_hist_item (item);
|
|
if (org_item != NULL && src_items != NULL
|
|
&& src_items->get_callsite_mark ()->get (org_item->obj))
|
|
data_items->get_callsite_mark ()->put (item->obj, 1);
|
|
}//set_one
|
|
|
|
void
|
|
Module::set_ComCom (int vis_bits)
|
|
{
|
|
Hist_data::HistItem *item;
|
|
Function *func = dbeSession->get_Unknown_Function ();
|
|
|
|
if (vis_bits)
|
|
{
|
|
// precede the compiler commentary with a blank line
|
|
item = data_items->new_hist_item (func, AT_EMPTY, empty);
|
|
item->value[name_idx].l = dbe_strdup (NTXT (""));
|
|
data_items->append_hist_item (item);
|
|
}
|
|
while (cline == curline)
|
|
{
|
|
ComC *comm = comComs->fetch (cindex);
|
|
if (comm->visible & vis_bits)
|
|
{
|
|
// write the compiler commentary
|
|
item = data_items->new_hist_item (func, AT_COM, empty);
|
|
item->value[name_idx].l = dbe_strdup (comm->com_str);
|
|
data_items->append_hist_item (item);
|
|
}
|
|
if (++cindex < comComs->size ())
|
|
cline = comComs->fetch (cindex)->line;
|
|
else
|
|
cline = -1;
|
|
}
|
|
}
|
|
|
|
void
|
|
Module::dump_dataobjects (FILE *out)
|
|
{
|
|
int index;
|
|
datatype_t *dtype;
|
|
Vec_loop (datatype_t*, datatypes, index, dtype)
|
|
{
|
|
fprintf (out, NTXT ("[0x%08X,%6lld] %4d %6d %s "), dtype->datatype_id,
|
|
dtype->dobj ? dtype->dobj->id : 0LL,
|
|
dtype->memop_refs, dtype->event_data,
|
|
(dtype->dobj != NULL ? (dtype->dobj->get_name () ?
|
|
dtype->dobj->get_name () : "<NULL>") : "<no object>"));
|
|
#if DEBUG
|
|
Histable* scope = dtype->dobj ? dtype->dobj->get_scope () : NULL;
|
|
if (scope != NULL)
|
|
{
|
|
switch (scope->get_type ())
|
|
{
|
|
case Histable::LOADOBJECT:
|
|
case Histable::FUNCTION:
|
|
fprintf (out, NTXT ("%s"), scope->get_name ());
|
|
break;
|
|
case Histable::MODULE:
|
|
{
|
|
char *filename = get_basename (scope->get_name ());
|
|
fprintf (out, NTXT ("%s"), filename);
|
|
break;
|
|
}
|
|
default:
|
|
fprintf (out, NTXT ("\tUnexpected scope %d:%s"),
|
|
scope->get_type (), scope->get_name ());
|
|
}
|
|
}
|
|
#endif
|
|
fprintf (out, NTXT ("\n"));
|
|
}
|
|
}
|
|
|
|
void
|
|
Module::set_name (char *str)
|
|
{
|
|
free (name);
|
|
name = str;
|
|
}
|
|
|
|
void
|
|
Module::read_hwcprof_info ()
|
|
{
|
|
if (hwcprof == 0)
|
|
{
|
|
hwcprof = 1;
|
|
Stabs *stabs = openDebugInfo ();
|
|
if (stabs)
|
|
stabs->read_hwcprof_info (this);
|
|
}
|
|
}
|
|
|
|
void
|
|
Module::reset_datatypes ()
|
|
{
|
|
for (int i = 0, sz = datatypes ? datatypes->size () : -1; i < sz; i++)
|
|
{
|
|
datatype_t *t = datatypes->fetch (i);
|
|
t->event_data = 0;
|
|
}
|
|
}
|
|
|
|
DataObject *
|
|
Module::get_dobj (uint32_t dtype_id)
|
|
{
|
|
read_hwcprof_info ();
|
|
for (int i = 0, sz = datatypes ? datatypes->size () : -1; i < sz; i++)
|
|
{
|
|
datatype_t *t = datatypes->fetch (i);
|
|
if (t->datatype_id == dtype_id)
|
|
{
|
|
t->event_data++;
|
|
return t->dobj;
|
|
}
|
|
}
|
|
return NULL;
|
|
}
|
|
|
|
int
|
|
Module::readFile ()
|
|
{
|
|
return AE_OK;
|
|
}
|
|
|
|
Vector<Histable*> *
|
|
Module::get_comparable_objs ()
|
|
{
|
|
update_comparable_objs ();
|
|
if (comparable_objs || dbeSession->expGroups->size () <= 1 || loadobject == NULL)
|
|
return comparable_objs;
|
|
Vector<Histable*> *comparableLoadObjs = loadobject->get_comparable_objs ();
|
|
if (comparableLoadObjs == NULL)
|
|
return NULL;
|
|
comparable_objs = new Vector<Histable*>(comparableLoadObjs->size ());
|
|
for (int i = 0, sz = comparableLoadObjs->size (); i < sz; i++)
|
|
{
|
|
Module *mod = NULL;
|
|
LoadObject *lo = (LoadObject*) comparableLoadObjs->fetch (i);
|
|
if (lo)
|
|
{
|
|
mod = lo->get_comparable_Module (this);
|
|
if (mod)
|
|
mod->comparable_objs = comparable_objs;
|
|
}
|
|
comparable_objs->store (i, mod);
|
|
}
|
|
dump_comparable_objs ();
|
|
return comparable_objs;
|
|
}
|
|
|
|
JMethod *
|
|
Module::find_jmethod (const char *nm, const char *sig)
|
|
{
|
|
// Vladimir: Probably we should not use linear search
|
|
for (long i = 0, sz = VecSize (functions); i < sz; i++)
|
|
{
|
|
JMethod *jmthd = (JMethod*) functions->get (i);
|
|
char *jmt_name = jmthd->get_name (Histable::SHORT);
|
|
if (strcmp (jmt_name, nm) == 0
|
|
&& strcmp (jmthd->get_signature (), sig) == 0)
|
|
return jmthd;
|
|
}
|
|
return NULL;
|
|
}
|