summaryrefslogtreecommitdiff
path: root/gprofng/src/Module.cc
diff options
context:
space:
mode:
Diffstat (limited to 'gprofng/src/Module.cc')
-rw-r--r--gprofng/src/Module.cc1840
1 files changed, 1840 insertions, 0 deletions
diff --git a/gprofng/src/Module.cc b/gprofng/src/Module.cc
new file mode 100644
index 00000000000..1e61b429e95
--- /dev/null
+++ b/gprofng/src/Module.cc
@@ -0,0 +1,1840 @@
+/* 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;
+}