Files
binutils-gdb/gprofng/src/Function.cc
T
Alan Modra 76bdc7266a Update year range in gprofng copyright notices
This adds 'Innovative Computing Labs' as an external author to
update-copyright.py, to cover the copyright notice in
gprofng/common/opteron_pcbe.c, and uses that plus another external
author 'Oracle and' to update gprofng copyright dates.  I'm not going
to commit 'Oracle and' as an accepted author, but that covers the
string "Copyright (c) 2006, 2012, Oracle and/or its affiliates. All
rights reserved." found in gprofng/testsuite/gprofng.display/jsynprog
files.
2023-01-01 23:26:30 +10:30

1163 lines
26 KiB
C++

/* Copyright (C) 2021-2023 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->src_line = NULL;
t->included_from = NULL;
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;
}