xref: /netbsd-src/external/gpl3/binutils.old/dist/gprofng/src/Function.cc (revision c42dbd0ed2e61fe6eda8590caa852ccf34719964)
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 
36 struct SrcInfo
37 {
38   DbeLine *src_line;
39   SrcInfo *included_from;
40   SrcInfo *next;
41 };
42 
43 struct PCInfo
44 {
45   int64_t offset;
46   int64_t size;
47   SrcInfo *src_info;
48 };
49 
Function(uint64_t _id)50 Function::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 
~Function()91 Function::~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 
115 char *
get_name(NameFormat nfmt)116 Function::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 
157 uint64_t
get_addr()158 Function::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 
165 Histable *
convertto(Histable_type type,Histable * obj)166 Function::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 
193 void
set_name(char * string)194 Function::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 
226 void
set_mangled_name(const char * string)227 Function::set_mangled_name (const char *string)
228 {
229   if (string)
230     {
231       free (mangled_name);
232       mangled_name = dbe_strdup (string);
233     }
234 }
235 
236 void
set_match_name(const char * string)237 Function::set_match_name (const char *string)
238 {
239   if (string)
240     {
241       free (match_name);
242       match_name = dbe_strdup (string);
243     }
244 }
245 
246 void
set_comparable_name(const char * string)247 Function::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
276 void
findDerivedFunctions()277 Function::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 
415 SrcInfo *
new_srcInfo()416 Function::new_srcInfo ()
417 {
418   SrcInfo *t = new SrcInfo ();
419   t->next = srcinfo_list;
420   srcinfo_list = t;
421   return t;
422 }
423 
424 void
pushSrcFile(SourceFile * source,int)425 Function::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 
449 SourceFile *
popSrcFile()450 Function::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 
462 void
copy_PCInfo(Function * from)463 Function::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 
479 void
add_PC_info(uint64_t offset,int lineno,SourceFile * cur_src)480 Function::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 
551 PCInfo *
lookup_PCInfo(uint64_t offset)552 Function::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 
576 DbeInstr*
mapLineToPc(DbeLine * dbeLine)577 Function::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 
600 DbeLine*
mapPCtoLine(uint64_t addr,SourceFile * src)601 Function::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 
621 DbeInstr *
find_dbeinstr(int flag,uint64_t addr)622 Function::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
682 DbeInstr *
create_hide_instr(DbeInstr * instr)683 Function::create_hide_instr (DbeInstr *instr)
684 {
685   DbeInstr *new_instr = new DbeInstr (instr_id++, 0, this, instr->addr);
686   return new_instr;
687 }
688 
689 uint64_t
find_previous_addr(uint64_t addr)690 Function::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 
746 void
setSource()747 Function::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 
766 void
setDefSrc(SourceFile * sf)767 Function::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 
777 void
setLineFirst(int lineno)778 Function::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 
790 Vector<SourceFile*> *
get_sources()791 Function::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 
803 SourceFile*
getDefSrc()804 Function::getDefSrc ()
805 {
806   if (module)
807     module->read_stabs ();
808   if (def_source == NULL)
809     setDefSrc (module->getMainSrc ());
810   return def_source;
811 }
812 
813 char *
getDefSrcName()814 Function::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 
827 int
func_cmp(Function * func,SourceFile * srcContext)828 Function::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 
854 Vector<Histable*> *
get_comparable_objs()855 Function::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 
JMethod(uint64_t _id)926 JMethod::JMethod (uint64_t _id) : Function (_id)
927 {
928   mid = 0LL;
929   addr = (Vaddr) 0;
930   signature = NULL;
931   jni_function = NULL;
932 }
933 
~JMethod()934 JMethod::~JMethod ()
935 {
936   free (signature);
937 }
938 
939 uint64_t
get_addr()940 JMethod::get_addr ()
941 {
942   if (addr != (Vaddr) 0)
943     return addr;
944   else
945     return Function::get_addr ();
946 }
947 
948 typedef struct
949 {
950   size_t used_in;
951   size_t used_out;
952 } MethodField;
953 
954 static void
write_buf(char * buf,char * str)955 write_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  */
963 static MethodField
translate_method_field(const char * name,char * buf)964 translate_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  */
1047 static bool
translate_method(char * mname,char * signature,bool ret_type,char * buf)1048 translate_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 
1091 void
set_name(char * string)1092 JMethod::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 
1118 bool
jni_match(Function * func)1119 JMethod::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