summaryrefslogtreecommitdiff
path: root/gprofng/src/Function.cc
diff options
context:
space:
mode:
Diffstat (limited to 'gprofng/src/Function.cc')
-rw-r--r--gprofng/src/Function.cc1160
1 files changed, 1160 insertions, 0 deletions
diff --git a/gprofng/src/Function.cc b/gprofng/src/Function.cc
new file mode 100644
index 00000000000..b0e4a8ff16a
--- /dev/null
+++ b/gprofng/src/Function.cc
@@ -0,0 +1,1160 @@
+/* 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 <assert.h>
+#include <string.h>
+#include <ctype.h>
+
+#include "demangle.h"
+#include "util.h"
+#include "DbeSession.h"
+#include "Function.h"
+#include "Module.h"
+#include "LoadObject.h"
+#include "Settings.h"
+#include "DbeFile.h"
+#include "DbeView.h"
+
+struct SrcInfo
+{
+ DbeLine *src_line;
+ SrcInfo *included_from;
+ SrcInfo *next;
+};
+
+struct PCInfo
+{
+ int64_t offset;
+ int64_t size;
+ SrcInfo *src_info;
+};
+
+Function::Function (uint64_t _id)
+{
+ id = _id;
+ instr_id = id << 32;
+ derivedNode = NULL;
+ module = NULL;
+ line_first = line_last = -1;
+ isOutlineFunction = false;
+ name = NULL;
+ mangled_name = NULL;
+ match_name = NULL;
+ comparable_name = NULL;
+ img_fname = NULL;
+ img_offset = 0;
+ chksum = 0;
+ flags = 0;
+ size = 0;
+ save_addr = FUNC_NO_SAVE;
+ linetab = NULL;
+ def_source = NULL;
+ indexStabsLink = NULL;
+ elfSym = NULL;
+ sources = NULL;
+ instrs = new Vector<DbeInstr*>;
+ addrs = NULL;
+ name_buf = NULL;
+ current_name_format = Histable::NA;
+ curr_srcinfo = NULL;
+ curr_srcfile = NULL;
+ srcinfo_list = NULL;
+ defaultDbeLine = NULL;
+ usrfunc = NULL;
+ alias = NULL;
+ instHTable = NULL;
+ addrIndexHTable = NULL;
+ isUsed = false;
+ isHideFunc = false;
+ inlinedSubr = NULL;
+ inlinedSubrCnt = 0;
+}
+
+Function::~Function ()
+{
+ free (mangled_name);
+ free (match_name);
+ free (comparable_name);
+ free (name_buf);
+ Destroy (linetab);
+ Destroy (instrs);
+
+ while (srcinfo_list)
+ {
+ SrcInfo *t = srcinfo_list;
+ srcinfo_list = t->next;
+ delete t;
+ }
+ delete sources;
+ delete addrs;
+ delete[] instHTable;
+ delete[] addrIndexHTable;
+ if (indexStabsLink)
+ // Remove a link to the current function
+ indexStabsLink->indexStabsLink = NULL;
+}
+
+char *
+Function::get_name (NameFormat nfmt)
+{
+ if (nfmt == Histable::NA)
+ {
+ DbeView *dbeView = dbeSession->getView (0);
+ if (dbeView)
+ nfmt = dbeView->get_name_format ();
+ }
+ if (name_buf && (nfmt == current_name_format || nfmt == Histable::NA))
+ return name_buf;
+ free (name_buf);
+ current_name_format = nfmt;
+
+ bool soname_fmt = Histable::soname_fmt (nfmt);
+ int fname_fmt = Histable::fname_fmt (nfmt);
+ if (fname_fmt == Histable::MANGLED)
+ name_buf = strdup (mangled_name);
+ else
+ {
+ if (module && module->is_fortran ()
+ && (streq (name, "MAIN") || streq (name, "MAIN_")))
+ name_buf = strdup (match_name);
+ else
+ name_buf = strdup (name);
+
+ if (fname_fmt == Histable::SHORT)
+ {
+ int i = get_paren (name_buf);
+ if (i != -1)
+ name_buf[i] = (char) 0;
+ }
+ }
+ if (soname_fmt)
+ {
+ char *fname = dbe_sprintf (NTXT ("%s [%s]"), name_buf, module->loadobject->get_name ());
+ free (name_buf);
+ name_buf = fname;
+ }
+ return name_buf;
+}
+
+uint64_t
+Function::get_addr ()
+{
+ LoadObject *lo = module ? module->loadobject : NULL;
+ int seg_idx = lo ? lo->seg_idx : -1;
+ return MAKE_ADDRESS (seg_idx, img_offset);
+}
+
+Histable *
+Function::convertto (Histable_type type, Histable *obj)
+{
+ Histable *res = NULL;
+ SourceFile *source = (SourceFile*) obj;
+ switch (type)
+ {
+ case INSTR:
+ res = find_dbeinstr (0, 0);
+ break;
+ case LINE:
+ {
+ // mapPCtoLine will implicitly read line info if necessary
+ res = mapPCtoLine (0, source);
+ break;
+ }
+ case FUNCTION:
+ res = this;
+ break;
+ case SOURCEFILE:
+ res = def_source;
+ break;
+ default:
+ assert (0);
+ }
+ return res;
+}
+
+void
+Function::set_name (char *string)
+{
+ if (string == NULL)
+ return;
+ set_mangled_name (string);
+
+ // strip away any globalization prefix, and save result for matching
+ char *mname = string;
+ if (strncmp (string, "$X", 2) == 0 || strncmp (string, ".X", 2) == 0)
+ {
+ // name was globalized
+ char *n = strchr (string + 2, (int) '.');
+ if (n != NULL)
+ mname = n + 1;
+ }
+ set_match_name (mname);
+ name = NULL;
+ if (module)
+ {
+ if (name == NULL && *match_name == '_')
+ {
+ int flag = DMGL_PARAMS;
+ if (module->lang_code == Sp_lang_java)
+ flag |= DMGL_JAVA;
+ name = cplus_demangle (match_name, flag);
+ }
+ }
+ if (name == NULL) // got demangled string
+ name = dbe_strdup (match_name);
+ set_comparable_name (name);
+}
+
+void
+Function::set_mangled_name (const char *string)
+{
+ if (string)
+ {
+ free (mangled_name);
+ mangled_name = dbe_strdup (string);
+ }
+}
+
+void
+Function::set_match_name (const char *string)
+{
+ if (string)
+ {
+ free (match_name);
+ match_name = dbe_strdup (string);
+ }
+}
+
+void
+Function::set_comparable_name (const char *string)
+{
+ if (string)
+ {
+ free (comparable_name);
+ comparable_name = dbe_strdup (string);
+
+ // remove blanks from comparable_name
+ for (char *s = comparable_name, *s1 = comparable_name;;)
+ {
+ if (*s == 0)
+ {
+ *s1 = 0;
+ break;
+ }
+ else if (*s != ' ')
+ {
+ *s1 = *s;
+ s1++;
+ }
+ s++;
+ }
+ }
+}
+
+// This function looks at the name of a function, and determines whether
+// or not it may be a derived function -- outline, mtask, or clone --
+// If it is, it writes the function name as demangled,
+// and sets a pointer to the function from which it was derived
+void
+Function::findDerivedFunctions ()
+
+{
+ MPFuncTypes ftype;
+ int index;
+ Function *fitem;
+ unsigned long long line_no;
+ char *namefmt;
+ char *subname = mangled_name;
+ char *demname;
+
+ // see if we've already done this
+ if ((flags & FUNC_FLAG_RESDER) != 0)
+ return;
+
+ // set flag for future
+ flags = flags | FUNC_FLAG_RESDER;
+ if (module == NULL)
+ return;
+ if (*subname != '_' || subname[1] != '$') // Not a specially named function
+ return;
+
+ // look for the current versions of naming
+ if (strncmp (subname + 2, NTXT ("d1"), 2) == 0) // doall function
+ ftype = MPF_DOALL;
+ else if (strncmp (subname + 2, "p1", 2) == 0) // parallel region function
+ ftype = MPF_PAR;
+ else if (strncmp (subname + 2, "l1", 2) == 0) // single thread loop setup
+ ftype = MPF_DOALL;
+ else if (strncmp (subname + 2, "s1", 2) == 0) // parallel section function
+ ftype = MPF_SECT;
+ else if (strncmp (subname + 2, "t1", 2) == 0) // task function
+ ftype = MPF_TASK;
+ else if (strncmp (subname + 2, "o1", 2) == 0) // outline function
+ {
+ ftype = MPF_OUTL;
+ isOutlineFunction = true;
+ }
+ else if (strncmp (subname + 2, "c1", 2) == 0) // clone function
+ ftype = MPF_CLONE;
+ else // Not an encoded name, just return
+ return;
+
+ // we know it's one of the above prefixes
+ char *sub = dbe_strdup (name + 4); // starting with base-26 number
+ char *p = sub;
+
+ // skip the base-26 number, and extract the line number
+ while (isalpha ((int) (*p)) != 0 && *p != 0)
+ p++;
+ line_no = atoll (p);
+
+ // skip past the number to to the .
+ while (*p != '.' && *p != 0)
+ p++;
+ if (*p == 0)
+ {
+ // can't be right
+ free (sub);
+ return;
+ }
+ // skip the trailing .
+ p++;
+ subname = p;
+ bool foundmatch = false;
+
+ // Find the function from which it is derived -- the one that matched subname
+ Vec_loop (Function*, module->functions, index, fitem)
+ {
+ if (streq (subname, fitem->mangled_name))
+ { // found it
+ foundmatch = true;
+ usrfunc = fitem;
+
+ // set the derived node
+ if ((fitem->flags & FUNC_FLAG_RESDER) == 0)
+ // ensure that it, too, is resolved if derived
+ fitem->findDerivedFunctions ();
+
+ // Build a demangled name
+ switch (ftype)
+ {
+ case MPF_OUTL:
+ isOutlineFunction = true;
+ namefmt = GTXT ("%s -- outline code from line %lld [%s]");
+ derivedNode = fitem->find_dbeinstr (PCLineFlag, line_no);
+ break;
+ case MPF_PAR:
+ namefmt = GTXT ("%s -- OMP parallel region from line %lld [%s]");
+ break;
+ case MPF_DOALL:
+ namefmt = GTXT ("%s -- Parallel loop from line %lld [%s]");
+ break;
+ case MPF_SECT:
+ namefmt = GTXT ("%s -- OMP sections from line %lld [%s]");
+ break;
+ case MPF_CLONE:
+ // Note that clones are handled differently -- no line number and
+ // clones are NOT shown as called from the original
+ // so after constructing the name, just return
+ // later, establish link from clone to parent
+ demname = dbe_sprintf (GTXT ("%s -- cloned version [%s]"),
+ fitem->get_name (), name);
+ free (name);
+ // set the name to the demangled version
+ name = demname;
+ free (sub);
+ derivedNode = fitem->find_dbeinstr (PCLineFlag, line_no);
+ return;
+ case MPF_TASK:
+ namefmt = GTXT ("%s -- OMP task from line %lld [%s]");
+ break;
+ default:
+ free (sub);
+ return;
+
+ }
+
+ // Finally, construct the demangled name
+ demname = dbe_sprintf (namefmt, fitem->get_name (), line_no, name);
+ free (name);
+ name = demname;
+ setLineFirst ((int) line_no);
+ break;
+ }
+ }
+
+ if (foundmatch == false && ftype == MPF_OUTL)
+ {
+ // Even if derived node was not found, we can demangle
+ demname = dbe_sprintf (GTXT ("%s -- outline code [%s]"), subname,
+ mangled_name);
+ free (name);
+ name = demname;
+ }
+ free (sub);
+}
+
+SrcInfo *
+Function::new_srcInfo ()
+{
+ SrcInfo *t = new SrcInfo ();
+ t->next = srcinfo_list;
+ srcinfo_list = t;
+ return t;
+}
+
+void
+Function::pushSrcFile (SourceFile* source, int /*lineno*/)
+{
+ // create new file stack
+ if (curr_srcfile == NULL)
+ {
+ curr_srcfile = source;
+ return;
+ }
+
+ SrcInfo *src_info = new_srcInfo ();
+ // In the ideal world, we need a DbeLine(III) here,
+ // but right now it would make us later believe that there are
+ // instructions generated for #include lines. To avoid that,
+ // we ask for a DbeLine(II).
+ src_info->src_line = curr_srcfile->find_dbeline (this, 0 /*lineno*/);
+ if (src_info->src_line)
+ {
+ src_info->included_from = curr_srcinfo;
+ curr_srcinfo = src_info;
+ }
+ curr_srcfile = source;
+ setSource ();
+}
+
+SourceFile *
+Function::popSrcFile ()
+{
+ if (curr_srcinfo != NULL)
+ {
+ curr_srcfile = curr_srcinfo->src_line->sourceFile;
+ curr_srcinfo = curr_srcinfo->included_from;
+ }
+ else
+ curr_srcfile = NULL;
+ return curr_srcfile;
+}
+
+void
+Function::copy_PCInfo (Function *from)
+{
+ if (line_first <= 0)
+ line_first = from->line_first;
+ if (line_last <= 0)
+ line_last = from->line_last;
+ if (def_source == NULL)
+ def_source = from->def_source;
+ for (int i = 0, sz = from->linetab ? from->linetab->size () : 0; i < sz; i++)
+ {
+ PCInfo *pcinf = from->linetab->fetch (i);
+ DbeLine *dbeLine = pcinf->src_info->src_line;
+ add_PC_info (pcinf->offset, dbeLine->lineno, dbeLine->sourceFile);
+ }
+}
+
+void
+Function::add_PC_info (uint64_t offset, int lineno, SourceFile *cur_src)
+{
+ if (lineno <= 0 || size < 0 || offset >= (uint64_t) size)
+ return;
+ if (cur_src == NULL)
+ cur_src = curr_srcfile ? curr_srcfile : def_source;
+ if (linetab == NULL)
+ linetab = new Vector<PCInfo*>;
+
+ int left = 0;
+ int right = linetab->size () - 1;
+ DbeLine *dbeline;
+ while (left <= right)
+ {
+ int x = (left + right) / 2;
+ PCInfo *pcinf = linetab->fetch (x);
+ uint64_t pcinf_offset = ((uint64_t) pcinf->offset);
+ if (offset == pcinf_offset)
+ {
+ dbeline = cur_src->find_dbeline (this, lineno);
+ dbeline->init_Offset (offset);
+ pcinf->src_info->src_line = dbeline;
+ // Ignore duplicate offset
+ return;
+ }
+ else if (offset > pcinf_offset)
+ left = x + 1;
+ else
+ right = x - 1;
+ }
+ PCInfo *pcinfo = new PCInfo;
+ pcinfo->offset = offset;
+
+ // Form new SrcInfo
+ SrcInfo *srcInfo = new_srcInfo ();
+ dbeline = cur_src->find_dbeline (this, lineno);
+ dbeline->init_Offset (offset);
+ srcInfo->src_line = dbeline;
+ // For now don't build included_from list.
+ // We need better compiler support for that.
+ //srcInfo->included_from = curr_srcinfo;
+ srcInfo->included_from = NULL;
+ pcinfo->src_info = srcInfo;
+
+ // Update the size of the current line in both structures:
+ // current PCInfo and corresponding DbeLine.
+ if (left < linetab->size ())
+ pcinfo->size = linetab->fetch (left)->offset - offset;
+ else
+ pcinfo->size = size - offset;
+ pcinfo->src_info->src_line->size += pcinfo->size;
+
+ // If not the first line, update the size of the previous line
+ if (left > 0)
+ {
+ PCInfo *pcinfo_prev = linetab->fetch (left - 1);
+ int64_t delta = (offset - pcinfo_prev->offset) - pcinfo_prev->size;
+ pcinfo_prev->size += delta;
+ pcinfo_prev->src_info->src_line->size += delta;
+ }
+
+ linetab->insert (left, pcinfo);
+ if (cur_src == def_source)
+ {
+ if (line_first <= 0)
+ setLineFirst (lineno);
+ if (line_last <= 0 || lineno > line_last)
+ line_last = lineno;
+ }
+}
+
+PCInfo *
+Function::lookup_PCInfo (uint64_t offset)
+{
+ module->read_stabs ();
+ if (linetab == NULL)
+ linetab = new Vector<PCInfo*>;
+
+ int left = 0;
+ int right = linetab->size () - 1;
+ while (left <= right)
+ {
+ int x = (left + right) / 2;
+ PCInfo *pcinfo = linetab->fetch (x);
+ if (offset >= ((uint64_t) pcinfo->offset))
+ {
+ if (offset < (uint64_t) (pcinfo->offset + pcinfo->size))
+ return pcinfo;
+ left = x + 1;
+ }
+ else
+ right = x - 1;
+ }
+ return NULL;
+}
+
+DbeInstr*
+Function::mapLineToPc (DbeLine *dbeLine)
+{
+ if (dbeLine && linetab)
+ {
+ DbeLine *dbl = dbeLine->dbeline_base;
+ for (int i = 0, sz = linetab->size (); i < sz; i++)
+ {
+ PCInfo *pcinfo = linetab->get (i);
+ if (pcinfo->src_info
+ && (pcinfo->src_info->src_line->dbeline_base == dbl))
+ {
+ DbeInstr *dbeInstr = find_dbeinstr (PCLineFlag, pcinfo->offset);
+ if (dbeInstr)
+ {
+ dbeInstr->lineno = dbeLine->lineno;
+ return dbeInstr;
+ }
+ }
+ }
+ }
+ return NULL;
+}
+
+DbeLine*
+Function::mapPCtoLine (uint64_t addr, SourceFile *src)
+{
+ PCInfo *pcinfo = lookup_PCInfo (addr);
+ if (pcinfo == NULL)
+ {
+ if (defaultDbeLine == NULL)
+ defaultDbeLine = getDefSrc ()->find_dbeline (this, 0);
+ return defaultDbeLine;
+ }
+ DbeLine *dbeline = pcinfo->src_info->src_line;
+
+ // If source-context is not specified return the line
+ // from which this pc has been generated.
+ if (src == NULL)
+ return dbeline;
+ if (dbeline->sourceFile == src)
+ return dbeline->dbeline_base;
+ return src->find_dbeline (this, 0);
+}
+
+DbeInstr *
+Function::find_dbeinstr (int flag, uint64_t addr)
+{
+ DbeInstr *instr;
+
+ enum
+ {
+ FuncInstHTableSize = 128
+ };
+
+ int hash = (((int) addr) >> 2) & (FuncInstHTableSize - 1);
+ if (instHTable == NULL)
+ {
+ if (size > 2048)
+ {
+ instHTable = new DbeInstr*[FuncInstHTableSize];
+ for (int i = 0; i < FuncInstHTableSize; i++)
+ instHTable[i] = NULL;
+ }
+ }
+ else
+ {
+ instr = instHTable[hash];
+ if (instr && instr->addr == addr && instr->flags == flag)
+ return instr;
+ }
+
+ int left = 0;
+ int right = instrs->size () - 1;
+ while (left <= right)
+ {
+ int index = (left + right) / 2;
+ instr = instrs->fetch (index);
+ if (addr < instr->addr)
+ right = index - 1;
+ else if (addr > instr->addr)
+ left = index + 1;
+ else
+ {
+ if (flag == instr->flags)
+ {
+ if (instHTable)
+ instHTable[hash] = instr;
+ return instr;
+ }
+ else if (flag < instr->flags)
+ right = index - 1;
+ else
+ left = index + 1;
+ }
+ }
+
+ // None found, create a new one
+ instr = new DbeInstr (instr_id++, flag, this, addr);
+ instrs->insert (left, instr);
+ if (instHTable)
+ instHTable[hash] = instr;
+ return instr;
+}
+
+// LIBRARY_VISIBILITY
+DbeInstr *
+Function::create_hide_instr (DbeInstr *instr)
+{
+ DbeInstr *new_instr = new DbeInstr (instr_id++, 0, this, instr->addr);
+ return new_instr;
+}
+
+uint64_t
+Function::find_previous_addr (uint64_t addr)
+{
+ if (addrs == NULL)
+ {
+ addrs = module->getAddrs (this);
+ if (addrs == NULL)
+ return addr;
+ }
+
+ int index = -1, not_found = 1;
+
+ enum
+ {
+ FuncAddrIndexHTableSize = 128
+ };
+ int hash = (((int) addr) >> 2) & (FuncAddrIndexHTableSize - 1);
+ if (addrIndexHTable == NULL)
+ {
+ if (size > 2048)
+ {
+ addrIndexHTable = new int[FuncAddrIndexHTableSize];
+ for (int i = 0; i < FuncAddrIndexHTableSize; i++)
+ addrIndexHTable[i] = -1;
+ }
+ }
+ else
+ {
+ index = addrIndexHTable[hash];
+ if (index >= 0 && addrs->fetch (index) == addr)
+ not_found = 0;
+ }
+
+ int left = 0;
+ int right = addrs->size () - 1;
+ while (not_found && left <= right)
+ {
+ index = (left + right) / 2;
+ uint64_t addr_test = addrs->fetch (index);
+ if (addr < addr_test)
+ right = index - 1;
+ else if (addr > addr_test)
+ left = index + 1;
+ else
+ {
+ if (addrIndexHTable)
+ addrIndexHTable[hash] = index;
+ not_found = 0;
+ }
+ }
+ if (not_found)
+ return addr;
+ if (index > 0)
+ index--;
+ return addrs->fetch (index);
+}
+
+void
+Function::setSource ()
+{
+ SourceFile *sf = module->getIncludeFile ();
+ if (sf == NULL)
+ sf = getDefSrc ();
+ if (def_source == NULL)
+ setDefSrc (sf);
+ if (sf == def_source)
+ return;
+ if (sources == NULL)
+ {
+ sources = new Vector<SourceFile*>;
+ sources->append (def_source);
+ sources->append (sf);
+ }
+ else if (sources->find (sf) < 0)
+ sources->append (sf);
+}
+
+void
+Function::setDefSrc (SourceFile *sf)
+{
+ if (sf)
+ {
+ def_source = sf;
+ if (line_first > 0)
+ add_PC_info (0, line_first, def_source);
+ }
+}
+
+void
+Function::setLineFirst (int lineno)
+{
+ if (lineno > 0)
+ {
+ line_first = lineno;
+ if (line_last <= 0)
+ line_last = lineno;
+ if (def_source)
+ add_PC_info (0, line_first, def_source);
+ }
+}
+
+Vector<SourceFile*> *
+Function::get_sources ()
+{
+ if (module)
+ module->read_stabs ();
+ if (sources == NULL)
+ {
+ sources = new Vector<SourceFile*>;
+ sources->append (getDefSrc ());
+ }
+ return sources;
+}
+
+SourceFile*
+Function::getDefSrc ()
+{
+ if (module)
+ module->read_stabs ();
+ if (def_source == NULL)
+ setDefSrc (module->getMainSrc ());
+ return def_source;
+}
+
+char *
+Function::getDefSrcName ()
+{
+ SourceFile *sf = getDefSrc ();
+ if (sf)
+ return sf->dbeFile->getResolvedPath ();
+ if (module)
+ return module->file_name;
+ sf = dbeSession->get_Unknown_Source ();
+ return sf->get_name ();
+}
+
+#define cmpValue(a, b) ((a) > (b) ? 1 : (a) == (b) ? 0 : -1)
+
+int
+Function::func_cmp (Function *func, SourceFile *srcContext)
+{
+ if (def_source != func->def_source)
+ {
+ if (srcContext == NULL)
+ srcContext = getDefSrc ();
+ if (def_source == srcContext)
+ return -1;
+ if (func->def_source == srcContext)
+ return 1;
+ return cmpValue (img_offset, func->img_offset);
+ }
+
+ if (line_first == func->line_first)
+ return cmpValue (img_offset, func->img_offset);
+ if (line_first <= 0)
+ {
+ if (func->line_first > 0)
+ return 1;
+ return cmpValue (img_offset, func->img_offset);
+ }
+ if (func->line_first <= 0)
+ return -1;
+ return cmpValue (line_first, func->line_first);
+}
+
+Vector<Histable*> *
+Function::get_comparable_objs ()
+{
+ update_comparable_objs ();
+ if (comparable_objs || dbeSession->expGroups->size () <= 1 || module == NULL)
+ return comparable_objs;
+ if (module == NULL || module->loadobject == NULL)
+ return NULL;
+ Vector<Histable*> *comparableModules = module->get_comparable_objs ();
+ if (comparableModules == NULL)
+ {
+ return NULL;
+ }
+ comparable_objs = new Vector<Histable*>(comparableModules->size ());
+ for (long i = 0, sz = comparableModules->size (); i < sz; i++)
+ {
+ Function *func = NULL;
+ comparable_objs->store (i, func);
+ Module *mod = (Module*) comparableModules->fetch (i);
+ if (mod == NULL)
+ continue;
+ if (mod == module)
+ func = this;
+ else
+ {
+ for (long i1 = 0, sz1 = VecSize (mod->functions); i1 < sz1; i1++)
+ {
+ Function *f = mod->functions->get (i1);
+ if ((f->comparable_objs == NULL)
+ && (strcmp (f->comparable_name, comparable_name) == 0))
+ {
+ func = f;
+ func->comparable_objs = comparable_objs;
+ break;
+ }
+ }
+ }
+ comparable_objs->store (i, func);
+ }
+ Vector<Histable*> *comparableLoadObjs =
+ module->loadobject->get_comparable_objs ();
+ if (VecSize (comparableLoadObjs) == VecSize (comparable_objs))
+ {
+ for (long i = 0, sz = VecSize (comparableLoadObjs); i < sz; i++)
+ {
+ LoadObject *lo = (LoadObject *) comparableLoadObjs->get (i);
+ Function *func = (Function *) comparable_objs->get (i);
+ if (func || (lo == NULL))
+ continue;
+ if (module->loadobject == lo)
+ func = this;
+ else
+ {
+ for (long i1 = 0, sz1 = VecSize (lo->functions); i1 < sz1; i1++)
+ {
+ Function *f = lo->functions->fetch (i1);
+ if ((f->comparable_objs == NULL)
+ && (strcmp (f->comparable_name, comparable_name) == 0))
+ {
+ func = f;
+ func->comparable_objs = comparable_objs;
+ break;
+ }
+ }
+ }
+ comparable_objs->store (i, func);
+ }
+ }
+ dump_comparable_objs ();
+ return comparable_objs;
+}
+
+JMethod::JMethod (uint64_t _id) : Function (_id)
+{
+ mid = 0LL;
+ addr = (Vaddr) 0;
+ signature = NULL;
+ jni_function = NULL;
+}
+
+JMethod::~JMethod ()
+{
+ free (signature);
+}
+
+uint64_t
+JMethod::get_addr ()
+{
+ if (addr != (Vaddr) 0)
+ return addr;
+ else
+ return Function::get_addr ();
+}
+
+typedef struct
+{
+ size_t used_in;
+ size_t used_out;
+} MethodField;
+
+static void
+write_buf (char* buf, char* str)
+{
+ while ((*buf++ = *str++));
+}
+
+/** Translate one field from the nane buffer.
+ * return how many chars were read from name and how many bytes were used in buf.
+ */
+static MethodField
+translate_method_field (const char* name, char* buf)
+{
+ MethodField out, t;
+ switch (*name)
+ {
+ case 'L':
+ name++;
+ out.used_in = 1;
+ out.used_out = 0;
+ while (*name != ';')
+ {
+ *buf = *name++;
+ if (*buf == '/')
+ *buf = '.';
+ buf++;
+ out.used_in++;
+ out.used_out++;
+ }
+ out.used_in++; /* the ';' is also used. */
+ break;
+ case 'Z':
+ write_buf (buf, NTXT ("boolean"));
+ out.used_out = 7;
+ out.used_in = 1;
+ break;
+ case 'B':
+ write_buf (buf, NTXT ("byte"));
+ out.used_out = 4;
+ out.used_in = 1;
+ break;
+ case 'C':
+ write_buf (buf, NTXT ("char"));
+ out.used_out = 4;
+ out.used_in = 1;
+ break;
+ case 'S':
+ write_buf (buf, NTXT ("short"));
+ out.used_out = 5;
+ out.used_in = 1;
+ break;
+ case 'I':
+ write_buf (buf, NTXT ("int"));
+ out.used_out = 3;
+ out.used_in = 1;
+ break;
+ case 'J':
+ write_buf (buf, NTXT ("long"));
+ out.used_out = 4;
+ out.used_in = 1;
+ break;
+ case 'F':
+ write_buf (buf, NTXT ("float"));
+ out.used_out = 5;
+ out.used_in = 1;
+ break;
+ case 'D':
+ write_buf (buf, NTXT ("double"));
+ out.used_out = 6;
+ out.used_in = 1;
+ break;
+ case 'V':
+ write_buf (buf, NTXT ("void"));
+ out.used_out = 4;
+ out.used_in = 1;
+ break;
+ case '[':
+ t = translate_method_field (name + 1, buf);
+ write_buf (buf + t.used_out, NTXT ("[]"));
+ out.used_out = t.used_out + 2;
+ out.used_in = t.used_in + 1;
+ break;
+ default:
+ out.used_out = 0;
+ out.used_in = 0;
+ }
+ return out;
+}
+
+/**
+ * translate method name to full method signature
+ * into the output buffer (buf).
+ * ret_type - true for printing result type
+ */
+static bool
+translate_method (char* mname, char *signature, bool ret_type, char* buf)
+{
+ MethodField p;
+ size_t l;
+ int first = 1;
+ if (signature == NULL)
+ return false;
+
+ const char *c = strchr (signature, ')');
+ if (c == NULL)
+ return false;
+ if (ret_type)
+ {
+ p = translate_method_field (++c, buf);
+ buf += p.used_out;
+ *buf++ = ' ';
+ }
+
+ l = strlen (mname);
+ memcpy (buf, mname, l + 1);
+ buf += l;
+ // *buf++ = ' '; // space before ()
+ *buf++ = '(';
+
+ c = signature + 1;
+ while (*c != ')')
+ {
+ if (!first)
+ {
+ *buf++ = ',';
+ *buf++ = ' ';
+ }
+ first = 0;
+ p = translate_method_field (c, buf);
+ c += p.used_in;
+ buf += p.used_out;
+ }
+
+ *buf++ = ')';
+ *buf = '\0';
+ return true;
+}
+
+void
+JMethod::set_name (char *string)
+{
+ if (string == NULL)
+ return;
+ set_mangled_name (string);
+
+ char buf[MAXDBUF];
+ *buf = '\0';
+ if (translate_method (string, signature, false, buf))
+ {
+ name = dbe_strdup (buf); // got translated string
+ Dprintf (DUMP_JCLASS_READER,
+ "JMethod::set_name: true name=%s string=%s signature=%s\n",
+ STR (name), STR (string), STR (signature));
+ }
+ else
+ {
+ name = dbe_strdup (string);
+ Dprintf (DUMP_JCLASS_READER,
+ "JMethod::set_name: false name=%s signature=%s\n",
+ STR (name), STR (signature));
+ }
+ set_match_name (name);
+ set_comparable_name (name);
+}
+
+bool
+JMethod::jni_match (Function *func)
+{
+ if (func == NULL || (func->flags & FUNC_NOT_JNI) != 0)
+ return false;
+ if (jni_function == func)
+ return true;
+
+ char *fname = func->get_name ();
+ if ((func->flags & FUNC_JNI_CHECKED) == 0)
+ {
+ func->flags |= FUNC_JNI_CHECKED;
+ if (strncmp (func->get_name (), NTXT ("Java_"), 5) != 0)
+ {
+ func->flags |= FUNC_NOT_JNI;
+ return false;
+ }
+ }
+
+ char *d = name;
+ char *s = fname + 5;
+ while (*d && *d != '(' && *d != ' ')
+ {
+ if (*d == '.')
+ {
+ if (*s++ != '_')
+ return false;
+ d++;
+ }
+ else if (*d == '_')
+ {
+ if (*s++ != '_')
+ return false;
+ if (*s++ != '1')
+ return false;
+ d++;
+ }
+ else if (*d++ != *s++)
+ return false;
+ }
+ jni_function = func;
+ return true;
+}