blob: 1e61b429e95008deeab117e17a7ecfb9acf2f0e7 [file] [log] [blame]
/* 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;
}