blob: b0e4a8ff16a0014bdc235b7f7095346901832a0d [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 <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;
}