1/* Copyright (C) 2021 Free Software Foundation, Inc.
2   Contributed by Oracle.
3
4   This file is part of GNU Binutils.
5
6   This program is free software; you can redistribute it and/or modify
7   it under the terms of the GNU General Public License as published by
8   the Free Software Foundation; either version 3, or (at your option)
9   any later version.
10
11   This program is distributed in the hope that it will be useful,
12   but WITHOUT ANY WARRANTY; without even the implied warranty of
13   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14   GNU General Public License for more details.
15
16   You should have received a copy of the GNU General Public License
17   along with this program; if not, write to the Free Software
18   Foundation, 51 Franklin Street - Fifth Floor, Boston,
19   MA 02110-1301, USA.  */
20
21#include "config.h"
22#include <assert.h>
23#include <string.h>
24#include <ctype.h>
25
26#include "demangle.h"
27#include "util.h"
28#include "DbeSession.h"
29#include "Function.h"
30#include "Module.h"
31#include "LoadObject.h"
32#include "Settings.h"
33#include "DbeFile.h"
34#include "DbeView.h"
35
36struct SrcInfo
37{
38  DbeLine *src_line;
39  SrcInfo *included_from;
40  SrcInfo *next;
41};
42
43struct PCInfo
44{
45  int64_t offset;
46  int64_t size;
47  SrcInfo *src_info;
48};
49
50Function::Function (uint64_t _id)
51{
52  id = _id;
53  instr_id = id << 32;
54  derivedNode = NULL;
55  module = NULL;
56  line_first = line_last = -1;
57  isOutlineFunction = false;
58  name = NULL;
59  mangled_name = NULL;
60  match_name = NULL;
61  comparable_name = NULL;
62  img_fname = NULL;
63  img_offset = 0;
64  chksum = 0;
65  flags = 0;
66  size = 0;
67  save_addr = FUNC_NO_SAVE;
68  linetab = NULL;
69  def_source = NULL;
70  indexStabsLink = NULL;
71  elfSym = NULL;
72  sources = NULL;
73  instrs = new Vector<DbeInstr*>;
74  addrs = NULL;
75  name_buf = NULL;
76  current_name_format = Histable::NA;
77  curr_srcinfo = NULL;
78  curr_srcfile = NULL;
79  srcinfo_list = NULL;
80  defaultDbeLine = NULL;
81  usrfunc = NULL;
82  alias = NULL;
83  instHTable = NULL;
84  addrIndexHTable = NULL;
85  isUsed = false;
86  isHideFunc = false;
87  inlinedSubr = NULL;
88  inlinedSubrCnt = 0;
89}
90
91Function::~Function ()
92{
93  free (mangled_name);
94  free (match_name);
95  free (comparable_name);
96  free (name_buf);
97  Destroy (linetab);
98  Destroy (instrs);
99
100  while (srcinfo_list)
101    {
102      SrcInfo *t = srcinfo_list;
103      srcinfo_list = t->next;
104      delete t;
105    }
106  delete sources;
107  delete addrs;
108  delete[] instHTable;
109  delete[] addrIndexHTable;
110  if (indexStabsLink)
111    // Remove a link to the current function
112    indexStabsLink->indexStabsLink = NULL;
113}
114
115char *
116Function::get_name (NameFormat nfmt)
117{
118  if (nfmt == Histable::NA)
119    {
120      DbeView *dbeView = dbeSession->getView (0);
121      if (dbeView)
122	nfmt = dbeView->get_name_format ();
123    }
124  if (name_buf && (nfmt == current_name_format || nfmt == Histable::NA))
125    return name_buf;
126  free (name_buf);
127  current_name_format = nfmt;
128
129  bool soname_fmt = Histable::soname_fmt (nfmt);
130  int fname_fmt = Histable::fname_fmt (nfmt);
131  if (fname_fmt == Histable::MANGLED)
132    name_buf = strdup (mangled_name);
133  else
134    {
135      if (module && module->is_fortran ()
136	  && (streq (name, "MAIN") || streq (name, "MAIN_")))
137	name_buf = strdup (match_name);
138      else
139	name_buf = strdup (name);
140
141      if (fname_fmt == Histable::SHORT)
142	{
143	  int i = get_paren (name_buf);
144	  if (i != -1)
145	    name_buf[i] = (char) 0;
146	}
147    }
148  if (soname_fmt)
149    {
150      char *fname = dbe_sprintf (NTXT ("%s [%s]"), name_buf, module->loadobject->get_name ());
151      free (name_buf);
152      name_buf = fname;
153    }
154  return name_buf;
155}
156
157uint64_t
158Function::get_addr ()
159{
160  LoadObject *lo = module ? module->loadobject : NULL;
161  int seg_idx = lo ? lo->seg_idx : -1;
162  return MAKE_ADDRESS (seg_idx, img_offset);
163}
164
165Histable *
166Function::convertto (Histable_type type, Histable *obj)
167{
168  Histable *res = NULL;
169  SourceFile *source = (SourceFile*) obj;
170  switch (type)
171    {
172    case INSTR:
173      res = find_dbeinstr (0, 0);
174      break;
175    case LINE:
176      {
177	// mapPCtoLine will implicitly read line info if necessary
178	res = mapPCtoLine (0, source);
179	break;
180      }
181    case FUNCTION:
182      res = this;
183      break;
184    case SOURCEFILE:
185      res = def_source;
186      break;
187    default:
188      assert (0);
189    }
190  return res;
191}
192
193void
194Function::set_name (char *string)
195{
196  if (string == NULL)
197    return;
198  set_mangled_name (string);
199
200  // strip away any globalization prefix, and save result for matching
201  char *mname = string;
202  if (strncmp (string, "$X", 2) == 0 || strncmp (string, ".X", 2) == 0)
203    {
204      // name was globalized
205      char *n = strchr (string + 2, (int) '.');
206      if (n != NULL)
207	mname = n + 1;
208    }
209  set_match_name (mname);
210  name = NULL;
211  if (module)
212    {
213      if (name == NULL && *match_name == '_')
214	{
215	  int flag = DMGL_PARAMS;
216	  if (module->lang_code == Sp_lang_java)
217	    flag |= DMGL_JAVA;
218	  name = cplus_demangle (match_name, flag);
219	}
220    }
221  if (name == NULL)     // got demangled string
222    name = dbe_strdup (match_name);
223  set_comparable_name (name);
224}
225
226void
227Function::set_mangled_name (const char *string)
228{
229  if (string)
230    {
231      free (mangled_name);
232      mangled_name = dbe_strdup (string);
233    }
234}
235
236void
237Function::set_match_name (const char *string)
238{
239  if (string)
240    {
241      free (match_name);
242      match_name = dbe_strdup (string);
243    }
244}
245
246void
247Function::set_comparable_name (const char *string)
248{
249  if (string)
250    {
251      free (comparable_name);
252      comparable_name = dbe_strdup (string);
253
254      // remove blanks from comparable_name
255      for (char *s = comparable_name, *s1 = comparable_name;;)
256	{
257	  if (*s == 0)
258	    {
259	      *s1 = 0;
260	      break;
261	    }
262	  else if (*s != ' ')
263	    {
264	      *s1 = *s;
265	      s1++;
266	    }
267	  s++;
268	}
269    }
270}
271
272//  This function looks at the name of a function, and determines whether
273//	or not it may be a derived function -- outline, mtask, or clone --
274//	If it is, it writes the function name as demangled,
275//	and sets a pointer to the function from which it was derived
276void
277Function::findDerivedFunctions ()
278
279{
280  MPFuncTypes ftype;
281  int index;
282  Function *fitem;
283  unsigned long long line_no;
284  char *namefmt;
285  char *subname = mangled_name;
286  char *demname;
287
288  // see if we've already done this
289  if ((flags & FUNC_FLAG_RESDER) != 0)
290      return;
291
292  // set flag for future
293  flags = flags | FUNC_FLAG_RESDER;
294  if (module == NULL)
295    return;
296  if (*subname != '_' || subname[1] != '$')   // Not a specially named function
297    return;
298
299  // look for the current versions of naming
300  if (strncmp (subname + 2, NTXT ("d1"), 2) == 0)    // doall function
301    ftype = MPF_DOALL;
302  else if (strncmp (subname + 2, "p1", 2) == 0)     // parallel region function
303    ftype = MPF_PAR;
304  else if (strncmp (subname + 2, "l1", 2) == 0)     // single thread loop setup
305    ftype = MPF_DOALL;
306  else if (strncmp (subname + 2, "s1", 2) == 0)     // parallel section function
307    ftype = MPF_SECT;
308  else if (strncmp (subname + 2, "t1", 2) == 0)     // task function
309    ftype = MPF_TASK;
310  else if (strncmp (subname + 2, "o1", 2) == 0)     // outline function
311    {
312      ftype = MPF_OUTL;
313      isOutlineFunction = true;
314   }
315  else if (strncmp (subname + 2, "c1", 2) == 0)     // clone function
316    ftype = MPF_CLONE;
317  else    // Not an encoded name, just return
318    return;
319
320  // we know it's one of the above prefixes
321  char *sub = dbe_strdup (name + 4); // starting with base-26 number
322  char *p = sub;
323
324  // skip the base-26 number, and extract the line number
325  while (isalpha ((int) (*p)) != 0 && *p != 0)
326    p++;
327  line_no = atoll (p);
328
329  // skip past the number to to the .
330  while (*p != '.' && *p != 0)
331    p++;
332  if (*p == 0)
333    {
334      // can't be right
335      free (sub);
336      return;
337    }
338  // skip the trailing .
339  p++;
340  subname = p;
341  bool foundmatch = false;
342
343  // Find the function from which it is derived -- the one that matched subname
344  Vec_loop (Function*, module->functions, index, fitem)
345  {
346    if (streq (subname, fitem->mangled_name))
347      { // found it
348	foundmatch = true;
349	usrfunc = fitem;
350
351	// set the derived node
352	if ((fitem->flags & FUNC_FLAG_RESDER) == 0)
353	  // ensure that it, too, is resolved if derived
354	  fitem->findDerivedFunctions ();
355
356	// Build a demangled name
357	switch (ftype)
358	  {
359	  case MPF_OUTL:
360	    isOutlineFunction = true;
361	    namefmt = GTXT ("%s -- outline code from line %lld [%s]");
362	    derivedNode = fitem->find_dbeinstr (PCLineFlag, line_no);
363	    break;
364	  case MPF_PAR:
365	    namefmt = GTXT ("%s -- OMP parallel region from line %lld [%s]");
366	    break;
367	  case MPF_DOALL:
368	    namefmt = GTXT ("%s -- Parallel loop from line %lld [%s]");
369	    break;
370	  case MPF_SECT:
371	    namefmt = GTXT ("%s -- OMP sections from line %lld [%s]");
372	    break;
373	  case MPF_CLONE:
374	    // Note that clones are handled differently -- no line number and
375	    //	clones are NOT shown as called from the original
376	    //	so after constructing the name, just return
377	    //	later, establish link from clone to parent
378	    demname = dbe_sprintf (GTXT ("%s -- cloned version [%s]"),
379				   fitem->get_name (), name);
380	    free (name);
381	    // set the name to the demangled version
382	    name = demname;
383	    free (sub);
384	    derivedNode = fitem->find_dbeinstr (PCLineFlag, line_no);
385	    return;
386	  case MPF_TASK:
387	    namefmt = GTXT ("%s -- OMP task from line %lld [%s]");
388	    break;
389	  default:
390	    free (sub);
391	    return;
392
393	  }
394
395	// Finally, construct the demangled name
396	demname = dbe_sprintf (namefmt, fitem->get_name (), line_no, name);
397	free (name);
398	name = demname;
399	setLineFirst ((int) line_no);
400	break;
401      }
402  }
403
404  if (foundmatch == false && ftype == MPF_OUTL)
405    {
406      // Even if derived node was not found, we can demangle
407      demname = dbe_sprintf (GTXT ("%s -- outline code [%s]"), subname,
408			     mangled_name);
409      free (name);
410      name = demname;
411    }
412  free (sub);
413}
414
415SrcInfo *
416Function::new_srcInfo ()
417{
418  SrcInfo *t = new SrcInfo ();
419  t->next = srcinfo_list;
420  srcinfo_list = t;
421  return t;
422}
423
424void
425Function::pushSrcFile (SourceFile* source, int /*lineno*/)
426{
427  // create new file stack
428  if (curr_srcfile == NULL)
429    {
430      curr_srcfile = source;
431      return;
432    }
433
434  SrcInfo *src_info = new_srcInfo ();
435  // In the ideal world, we need a DbeLine(III) here,
436  // but right now it would make us later believe that there are
437  // instructions generated for #include lines. To avoid that,
438  // we ask for a DbeLine(II).
439  src_info->src_line = curr_srcfile->find_dbeline (this, 0 /*lineno*/);
440  if (src_info->src_line)
441    {
442      src_info->included_from = curr_srcinfo;
443      curr_srcinfo = src_info;
444    }
445  curr_srcfile = source;
446  setSource ();
447}
448
449SourceFile *
450Function::popSrcFile ()
451{
452  if (curr_srcinfo != NULL)
453    {
454      curr_srcfile = curr_srcinfo->src_line->sourceFile;
455      curr_srcinfo = curr_srcinfo->included_from;
456    }
457  else
458    curr_srcfile = NULL;
459  return curr_srcfile;
460}
461
462void
463Function::copy_PCInfo (Function *from)
464{
465  if (line_first <= 0)
466    line_first = from->line_first;
467  if (line_last <= 0)
468    line_last = from->line_last;
469  if (def_source == NULL)
470    def_source = from->def_source;
471  for (int i = 0, sz = from->linetab ? from->linetab->size () : 0; i < sz; i++)
472    {
473      PCInfo *pcinf = from->linetab->fetch (i);
474      DbeLine *dbeLine = pcinf->src_info->src_line;
475      add_PC_info (pcinf->offset, dbeLine->lineno, dbeLine->sourceFile);
476    }
477}
478
479void
480Function::add_PC_info (uint64_t offset, int lineno, SourceFile *cur_src)
481{
482  if (lineno <= 0 || size < 0 || offset >= (uint64_t) size)
483    return;
484  if (cur_src == NULL)
485    cur_src = curr_srcfile ? curr_srcfile : def_source;
486  if (linetab == NULL)
487    linetab = new Vector<PCInfo*>;
488
489  int left = 0;
490  int right = linetab->size () - 1;
491  DbeLine *dbeline;
492  while (left <= right)
493    {
494      int x = (left + right) / 2;
495      PCInfo *pcinf = linetab->fetch (x);
496      uint64_t pcinf_offset = ((uint64_t) pcinf->offset);
497      if (offset == pcinf_offset)
498	{
499	  dbeline = cur_src->find_dbeline (this, lineno);
500	  dbeline->init_Offset (offset);
501	  pcinf->src_info->src_line = dbeline;
502	  // Ignore duplicate offset
503	  return;
504	}
505      else if (offset > pcinf_offset)
506	left = x + 1;
507      else
508	right = x - 1;
509    }
510  PCInfo *pcinfo = new PCInfo;
511  pcinfo->offset = offset;
512
513  // Form new SrcInfo
514  SrcInfo *srcInfo = new_srcInfo ();
515  dbeline = cur_src->find_dbeline (this, lineno);
516  dbeline->init_Offset (offset);
517  srcInfo->src_line = dbeline;
518  // For now don't build included_from list.
519  // We need better compiler support for that.
520  //srcInfo->included_from = curr_srcinfo;
521  srcInfo->included_from = NULL;
522  pcinfo->src_info = srcInfo;
523
524  // Update the size of the current line in both structures:
525  // current PCInfo and corresponding DbeLine.
526  if (left < linetab->size ())
527    pcinfo->size = linetab->fetch (left)->offset - offset;
528  else
529    pcinfo->size = size - offset;
530  pcinfo->src_info->src_line->size += pcinfo->size;
531
532  // If not the first line, update the size of the previous line
533  if (left > 0)
534    {
535      PCInfo *pcinfo_prev = linetab->fetch (left - 1);
536      int64_t delta = (offset - pcinfo_prev->offset) - pcinfo_prev->size;
537      pcinfo_prev->size += delta;
538      pcinfo_prev->src_info->src_line->size += delta;
539    }
540
541  linetab->insert (left, pcinfo);
542  if (cur_src == def_source)
543    {
544      if (line_first <= 0)
545	setLineFirst (lineno);
546      if (line_last <= 0 || lineno > line_last)
547	line_last = lineno;
548    }
549}
550
551PCInfo *
552Function::lookup_PCInfo (uint64_t offset)
553{
554  module->read_stabs ();
555  if (linetab == NULL)
556    linetab = new Vector<PCInfo*>;
557
558  int left = 0;
559  int right = linetab->size () - 1;
560  while (left <= right)
561    {
562      int x = (left + right) / 2;
563      PCInfo *pcinfo = linetab->fetch (x);
564      if (offset >= ((uint64_t) pcinfo->offset))
565	{
566	  if (offset < (uint64_t) (pcinfo->offset + pcinfo->size))
567	    return pcinfo;
568	  left = x + 1;
569	}
570      else
571	right = x - 1;
572    }
573  return NULL;
574}
575
576DbeInstr*
577Function::mapLineToPc (DbeLine *dbeLine)
578{
579  if (dbeLine && linetab)
580    {
581      DbeLine *dbl = dbeLine->dbeline_base;
582      for (int i = 0, sz = linetab->size (); i < sz; i++)
583	{
584	  PCInfo *pcinfo = linetab->get (i);
585	  if (pcinfo->src_info
586	      && (pcinfo->src_info->src_line->dbeline_base == dbl))
587	    {
588	      DbeInstr *dbeInstr = find_dbeinstr (PCLineFlag, pcinfo->offset);
589	      if (dbeInstr)
590		{
591		  dbeInstr->lineno = dbeLine->lineno;
592		  return dbeInstr;
593		}
594	    }
595	}
596    }
597  return NULL;
598}
599
600DbeLine*
601Function::mapPCtoLine (uint64_t addr, SourceFile *src)
602{
603  PCInfo *pcinfo = lookup_PCInfo (addr);
604  if (pcinfo == NULL)
605    {
606      if (defaultDbeLine == NULL)
607	defaultDbeLine = getDefSrc ()->find_dbeline (this, 0);
608      return defaultDbeLine;
609    }
610  DbeLine *dbeline = pcinfo->src_info->src_line;
611
612  // If source-context is not specified return the line
613  // from which this pc has been generated.
614  if (src == NULL)
615    return dbeline;
616  if (dbeline->sourceFile == src)
617    return dbeline->dbeline_base;
618  return src->find_dbeline (this, 0);
619}
620
621DbeInstr *
622Function::find_dbeinstr (int flag, uint64_t addr)
623{
624  DbeInstr *instr;
625
626  enum
627  {
628    FuncInstHTableSize = 128
629  };
630
631  int hash = (((int) addr) >> 2) & (FuncInstHTableSize - 1);
632  if (instHTable == NULL)
633    {
634      if (size > 2048)
635	{
636	  instHTable = new DbeInstr*[FuncInstHTableSize];
637	  for (int i = 0; i < FuncInstHTableSize; i++)
638	    instHTable[i] = NULL;
639	}
640    }
641  else
642    {
643      instr = instHTable[hash];
644      if (instr && instr->addr == addr && instr->flags == flag)
645	return instr;
646    }
647
648  int left = 0;
649  int right = instrs->size () - 1;
650  while (left <= right)
651    {
652      int index = (left + right) / 2;
653      instr = instrs->fetch (index);
654      if (addr < instr->addr)
655	right = index - 1;
656      else if (addr > instr->addr)
657	left = index + 1;
658      else
659	{
660	  if (flag == instr->flags)
661	    {
662	      if (instHTable)
663		instHTable[hash] = instr;
664	      return instr;
665	    }
666	  else if (flag < instr->flags)
667	    right = index - 1;
668	  else
669	    left = index + 1;
670	}
671    }
672
673  // None found, create a new one
674  instr = new DbeInstr (instr_id++, flag, this, addr);
675  instrs->insert (left, instr);
676  if (instHTable)
677    instHTable[hash] = instr;
678  return instr;
679}
680
681// LIBRARY_VISIBILITY
682DbeInstr *
683Function::create_hide_instr (DbeInstr *instr)
684{
685  DbeInstr *new_instr = new DbeInstr (instr_id++, 0, this, instr->addr);
686  return new_instr;
687}
688
689uint64_t
690Function::find_previous_addr (uint64_t addr)
691{
692  if (addrs == NULL)
693    {
694      addrs = module->getAddrs (this);
695      if (addrs == NULL)
696	return addr;
697    }
698
699  int index = -1, not_found = 1;
700
701  enum
702  {
703    FuncAddrIndexHTableSize = 128
704  };
705  int hash = (((int) addr) >> 2) & (FuncAddrIndexHTableSize - 1);
706  if (addrIndexHTable == NULL)
707    {
708      if (size > 2048)
709	{
710	  addrIndexHTable = new int[FuncAddrIndexHTableSize];
711	  for (int i = 0; i < FuncAddrIndexHTableSize; i++)
712	    addrIndexHTable[i] = -1;
713	}
714    }
715  else
716    {
717      index = addrIndexHTable[hash];
718      if (index >= 0 && addrs->fetch (index) == addr)
719	not_found = 0;
720    }
721
722  int left = 0;
723  int right = addrs->size () - 1;
724  while (not_found && left <= right)
725    {
726      index = (left + right) / 2;
727      uint64_t addr_test = addrs->fetch (index);
728      if (addr < addr_test)
729	right = index - 1;
730      else if (addr > addr_test)
731	left = index + 1;
732      else
733	{
734	  if (addrIndexHTable)
735	    addrIndexHTable[hash] = index;
736	  not_found = 0;
737	}
738    }
739  if (not_found)
740    return addr;
741  if (index > 0)
742    index--;
743  return addrs->fetch (index);
744}
745
746void
747Function::setSource ()
748{
749  SourceFile *sf = module->getIncludeFile ();
750  if (sf == NULL)
751    sf = getDefSrc ();
752  if (def_source == NULL)
753    setDefSrc (sf);
754  if (sf == def_source)
755    return;
756  if (sources == NULL)
757    {
758      sources = new Vector<SourceFile*>;
759      sources->append (def_source);
760      sources->append (sf);
761    }
762  else if (sources->find (sf) < 0)
763    sources->append (sf);
764}
765
766void
767Function::setDefSrc (SourceFile *sf)
768{
769  if (sf)
770    {
771      def_source = sf;
772      if (line_first > 0)
773	add_PC_info (0, line_first, def_source);
774    }
775}
776
777void
778Function::setLineFirst (int lineno)
779{
780  if (lineno > 0)
781    {
782      line_first = lineno;
783      if (line_last <= 0)
784	line_last = lineno;
785      if (def_source)
786	add_PC_info (0, line_first, def_source);
787    }
788}
789
790Vector<SourceFile*> *
791Function::get_sources ()
792{
793  if (module)
794    module->read_stabs ();
795  if (sources == NULL)
796    {
797      sources = new Vector<SourceFile*>;
798      sources->append (getDefSrc ());
799    }
800  return sources;
801}
802
803SourceFile*
804Function::getDefSrc ()
805{
806  if (module)
807    module->read_stabs ();
808  if (def_source == NULL)
809    setDefSrc (module->getMainSrc ());
810  return def_source;
811}
812
813char *
814Function::getDefSrcName ()
815{
816  SourceFile *sf = getDefSrc ();
817  if (sf)
818    return sf->dbeFile->getResolvedPath ();
819  if (module)
820    return module->file_name;
821  sf = dbeSession->get_Unknown_Source ();
822  return sf->get_name ();
823}
824
825#define cmpValue(a, b) ((a) > (b) ? 1 : (a) == (b) ? 0 : -1)
826
827int
828Function::func_cmp (Function *func, SourceFile *srcContext)
829{
830  if (def_source != func->def_source)
831    {
832      if (srcContext == NULL)
833	srcContext = getDefSrc ();
834      if (def_source == srcContext)
835	return -1;
836      if (func->def_source == srcContext)
837	return 1;
838      return cmpValue (img_offset, func->img_offset);
839    }
840
841  if (line_first == func->line_first)
842    return cmpValue (img_offset, func->img_offset);
843  if (line_first <= 0)
844    {
845      if (func->line_first > 0)
846	return 1;
847      return cmpValue (img_offset, func->img_offset);
848    }
849  if (func->line_first <= 0)
850    return -1;
851  return cmpValue (line_first, func->line_first);
852}
853
854Vector<Histable*> *
855Function::get_comparable_objs ()
856{
857  update_comparable_objs ();
858  if (comparable_objs || dbeSession->expGroups->size () <= 1 || module == NULL)
859    return comparable_objs;
860  if (module == NULL || module->loadobject == NULL)
861    return NULL;
862  Vector<Histable*> *comparableModules = module->get_comparable_objs ();
863  if (comparableModules == NULL)
864    {
865      return NULL;
866    }
867  comparable_objs = new Vector<Histable*>(comparableModules->size ());
868  for (long i = 0, sz = comparableModules->size (); i < sz; i++)
869    {
870      Function *func = NULL;
871      comparable_objs->store (i, func);
872      Module *mod = (Module*) comparableModules->fetch (i);
873      if (mod == NULL)
874	continue;
875      if (mod == module)
876	func = this;
877      else
878	{
879	  for (long i1 = 0, sz1 = VecSize (mod->functions); i1 < sz1; i1++)
880	    {
881	      Function *f = mod->functions->get (i1);
882	      if ((f->comparable_objs == NULL)
883		   && (strcmp (f->comparable_name, comparable_name) == 0))
884		{
885		  func = f;
886		  func->comparable_objs = comparable_objs;
887		  break;
888		}
889	    }
890	}
891      comparable_objs->store (i, func);
892    }
893  Vector<Histable*> *comparableLoadObjs =
894	  module->loadobject->get_comparable_objs ();
895  if (VecSize (comparableLoadObjs) == VecSize (comparable_objs))
896    {
897      for (long i = 0, sz = VecSize (comparableLoadObjs); i < sz; i++)
898	{
899	  LoadObject *lo = (LoadObject *) comparableLoadObjs->get (i);
900	  Function *func = (Function *) comparable_objs->get (i);
901	  if (func || (lo == NULL))
902	    continue;
903	  if (module->loadobject == lo)
904	    func = this;
905	  else
906	    {
907	      for (long i1 = 0, sz1 = VecSize (lo->functions); i1 < sz1; i1++)
908		{
909		  Function *f = lo->functions->fetch (i1);
910		  if ((f->comparable_objs == NULL)
911		       && (strcmp (f->comparable_name, comparable_name) == 0))
912		    {
913		      func = f;
914		      func->comparable_objs = comparable_objs;
915		      break;
916		    }
917		}
918	    }
919	  comparable_objs->store (i, func);
920	}
921    }
922  dump_comparable_objs ();
923  return comparable_objs;
924}
925
926JMethod::JMethod (uint64_t _id) : Function (_id)
927{
928  mid = 0LL;
929  addr = (Vaddr) 0;
930  signature = NULL;
931  jni_function = NULL;
932}
933
934JMethod::~JMethod ()
935{
936  free (signature);
937}
938
939uint64_t
940JMethod::get_addr ()
941{
942  if (addr != (Vaddr) 0)
943    return addr;
944  else
945    return Function::get_addr ();
946}
947
948typedef struct
949{
950  size_t used_in;
951  size_t used_out;
952} MethodField;
953
954static void
955write_buf (char* buf, char* str)
956{
957  while ((*buf++ = *str++));
958}
959
960/** Translate one field from the nane buffer.
961 * return how many chars were read from name and how many bytes were used in buf.
962 */
963static MethodField
964translate_method_field (const char* name, char* buf)
965{
966  MethodField out, t;
967  switch (*name)
968    {
969    case 'L':
970      name++;
971      out.used_in = 1;
972      out.used_out = 0;
973      while (*name != ';')
974	{
975	  *buf = *name++;
976	  if (*buf == '/')
977	    *buf = '.';
978	  buf++;
979	  out.used_in++;
980	  out.used_out++;
981	}
982      out.used_in++; /* the ';' is also used. */
983      break;
984    case 'Z':
985      write_buf (buf, NTXT ("boolean"));
986      out.used_out = 7;
987      out.used_in = 1;
988      break;
989    case 'B':
990      write_buf (buf, NTXT ("byte"));
991      out.used_out = 4;
992      out.used_in = 1;
993      break;
994    case 'C':
995      write_buf (buf, NTXT ("char"));
996      out.used_out = 4;
997      out.used_in = 1;
998      break;
999    case 'S':
1000      write_buf (buf, NTXT ("short"));
1001      out.used_out = 5;
1002      out.used_in = 1;
1003      break;
1004    case 'I':
1005      write_buf (buf, NTXT ("int"));
1006      out.used_out = 3;
1007      out.used_in = 1;
1008      break;
1009    case 'J':
1010      write_buf (buf, NTXT ("long"));
1011      out.used_out = 4;
1012      out.used_in = 1;
1013      break;
1014    case 'F':
1015      write_buf (buf, NTXT ("float"));
1016      out.used_out = 5;
1017      out.used_in = 1;
1018      break;
1019    case 'D':
1020      write_buf (buf, NTXT ("double"));
1021      out.used_out = 6;
1022      out.used_in = 1;
1023      break;
1024    case 'V':
1025      write_buf (buf, NTXT ("void"));
1026      out.used_out = 4;
1027      out.used_in = 1;
1028      break;
1029    case '[':
1030      t = translate_method_field (name + 1, buf);
1031      write_buf (buf + t.used_out, NTXT ("[]"));
1032      out.used_out = t.used_out + 2;
1033      out.used_in = t.used_in + 1;
1034      break;
1035    default:
1036      out.used_out = 0;
1037      out.used_in = 0;
1038    }
1039  return out;
1040}
1041
1042/**
1043 * translate method name to full method signature
1044 * into the output buffer (buf).
1045 * ret_type - true for printing result type
1046 */
1047static bool
1048translate_method (char* mname, char *signature, bool ret_type, char* buf)
1049{
1050  MethodField p;
1051  size_t l;
1052  int first = 1;
1053  if (signature == NULL)
1054    return false;
1055
1056  const char *c = strchr (signature, ')');
1057  if (c == NULL)
1058    return false;
1059  if (ret_type)
1060    {
1061      p = translate_method_field (++c, buf);
1062      buf += p.used_out;
1063      *buf++ = ' ';
1064    }
1065
1066  l = strlen (mname);
1067  memcpy (buf, mname, l + 1);
1068  buf += l;
1069  // *buf++ = ' '; // space before ()
1070  *buf++ = '(';
1071
1072  c = signature + 1;
1073  while (*c != ')')
1074    {
1075      if (!first)
1076	{
1077	  *buf++ = ',';
1078	  *buf++ = ' ';
1079	}
1080      first = 0;
1081      p = translate_method_field (c, buf);
1082      c += p.used_in;
1083      buf += p.used_out;
1084    }
1085
1086  *buf++ = ')';
1087  *buf = '\0';
1088  return true;
1089}
1090
1091void
1092JMethod::set_name (char *string)
1093{
1094  if (string == NULL)
1095    return;
1096  set_mangled_name (string);
1097
1098  char buf[MAXDBUF];
1099  *buf = '\0';
1100  if (translate_method (string, signature, false, buf))
1101    {
1102      name = dbe_strdup (buf); // got translated string
1103      Dprintf (DUMP_JCLASS_READER,
1104	      "JMethod::set_name: true name=%s string=%s signature=%s\n",
1105	       STR (name), STR (string), STR (signature));
1106    }
1107  else
1108    {
1109      name = dbe_strdup (string);
1110      Dprintf (DUMP_JCLASS_READER,
1111	       "JMethod::set_name: false name=%s signature=%s\n",
1112	       STR (name), STR (signature));
1113    }
1114  set_match_name (name);
1115  set_comparable_name (name);
1116}
1117
1118bool
1119JMethod::jni_match (Function *func)
1120{
1121  if (func == NULL || (func->flags & FUNC_NOT_JNI) != 0)
1122    return false;
1123  if (jni_function == func)
1124    return true;
1125
1126  char *fname = func->get_name ();
1127  if ((func->flags & FUNC_JNI_CHECKED) == 0)
1128    {
1129      func->flags |= FUNC_JNI_CHECKED;
1130      if (strncmp (func->get_name (), NTXT ("Java_"), 5) != 0)
1131	{
1132	  func->flags |= FUNC_NOT_JNI;
1133	  return false;
1134	}
1135    }
1136
1137  char *d = name;
1138  char *s = fname + 5;
1139  while (*d && *d != '(' && *d != ' ')
1140    {
1141      if (*d == '.')
1142	{
1143	  if (*s++ != '_')
1144	    return false;
1145	  d++;
1146	}
1147      else if (*d == '_')
1148	{
1149	  if (*s++ != '_')
1150	    return false;
1151	  if (*s++ != '1')
1152	    return false;
1153	  d++;
1154	}
1155      else if (*d++ != *s++)
1156	return false;
1157    }
1158  jni_function = func;
1159  return true;
1160}
1161