diff options
Diffstat (limited to 'gprofng/src/Function.cc')
-rw-r--r-- | gprofng/src/Function.cc | 1160 |
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; +} |