xref: /netbsd-src/external/gpl3/binutils/dist/gprofng/src/Function.cc (revision cb63e24e8d6aae7ddac1859a9015f48b1d8bd90e)
1 /* Copyright (C) 2021-2024 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->src_line = NULL;
420   t->included_from = NULL;
421   t->next = srcinfo_list;
422   srcinfo_list = t;
423   return t;
424 }
425 
426 void
pushSrcFile(SourceFile * source,int)427 Function::pushSrcFile (SourceFile* source, int /*lineno*/)
428 {
429   // create new file stack
430   if (curr_srcfile == NULL)
431     {
432       curr_srcfile = source;
433       return;
434     }
435 
436   SrcInfo *src_info = new_srcInfo ();
437   // In the ideal world, we need a DbeLine(III) here,
438   // but right now it would make us later believe that there are
439   // instructions generated for #include lines. To avoid that,
440   // we ask for a DbeLine(II).
441   src_info->src_line = curr_srcfile->find_dbeline (this, 0 /*lineno*/);
442   if (src_info->src_line)
443     {
444       src_info->included_from = curr_srcinfo;
445       curr_srcinfo = src_info;
446     }
447   curr_srcfile = source;
448   setSource ();
449 }
450 
451 SourceFile *
popSrcFile()452 Function::popSrcFile ()
453 {
454   if (curr_srcinfo != NULL)
455     {
456       curr_srcfile = curr_srcinfo->src_line->sourceFile;
457       curr_srcinfo = curr_srcinfo->included_from;
458     }
459   else
460     curr_srcfile = NULL;
461   return curr_srcfile;
462 }
463 
464 void
copy_PCInfo(Function * from)465 Function::copy_PCInfo (Function *from)
466 {
467   if (line_first <= 0)
468     line_first = from->line_first;
469   if (line_last <= 0)
470     line_last = from->line_last;
471   if (def_source == NULL)
472     def_source = from->def_source;
473   for (int i = 0, sz = from->linetab ? from->linetab->size () : 0; i < sz; i++)
474     {
475       PCInfo *pcinf = from->linetab->fetch (i);
476       DbeLine *dbeLine = pcinf->src_info->src_line;
477       add_PC_info (pcinf->offset, dbeLine->lineno, dbeLine->sourceFile);
478     }
479 }
480 
481 void
add_PC_info(uint64_t offset,int lineno,SourceFile * cur_src)482 Function::add_PC_info (uint64_t offset, int lineno, SourceFile *cur_src)
483 {
484   if (lineno <= 0 || size < 0 || offset >= (uint64_t) size)
485     return;
486   if (cur_src == NULL)
487     cur_src = curr_srcfile ? curr_srcfile : def_source;
488   if (linetab == NULL)
489     linetab = new Vector<PCInfo*>;
490 
491   int left = 0;
492   int right = linetab->size () - 1;
493   DbeLine *dbeline;
494   while (left <= right)
495     {
496       int x = (left + right) / 2;
497       PCInfo *pcinf = linetab->fetch (x);
498       uint64_t pcinf_offset = ((uint64_t) pcinf->offset);
499       if (offset == pcinf_offset)
500 	{
501 	  dbeline = cur_src->find_dbeline (this, lineno);
502 	  dbeline->init_Offset (offset);
503 	  pcinf->src_info->src_line = dbeline;
504 	  // Ignore duplicate offset
505 	  return;
506 	}
507       else if (offset > pcinf_offset)
508 	left = x + 1;
509       else
510 	right = x - 1;
511     }
512   PCInfo *pcinfo = new PCInfo;
513   pcinfo->offset = offset;
514 
515   // Form new SrcInfo
516   SrcInfo *srcInfo = new_srcInfo ();
517   dbeline = cur_src->find_dbeline (this, lineno);
518   dbeline->init_Offset (offset);
519   srcInfo->src_line = dbeline;
520   // For now don't build included_from list.
521   // We need better compiler support for that.
522   //srcInfo->included_from = curr_srcinfo;
523   srcInfo->included_from = NULL;
524   pcinfo->src_info = srcInfo;
525 
526   // Update the size of the current line in both structures:
527   // current PCInfo and corresponding DbeLine.
528   if (left < linetab->size ())
529     pcinfo->size = linetab->fetch (left)->offset - offset;
530   else
531     pcinfo->size = size - offset;
532   pcinfo->src_info->src_line->size += pcinfo->size;
533 
534   // If not the first line, update the size of the previous line
535   if (left > 0)
536     {
537       PCInfo *pcinfo_prev = linetab->fetch (left - 1);
538       int64_t delta = (offset - pcinfo_prev->offset) - pcinfo_prev->size;
539       pcinfo_prev->size += delta;
540       pcinfo_prev->src_info->src_line->size += delta;
541     }
542 
543   linetab->insert (left, pcinfo);
544   if (cur_src == def_source)
545     {
546       if (line_first <= 0)
547 	setLineFirst (lineno);
548       if (line_last <= 0 || lineno > line_last)
549 	line_last = lineno;
550     }
551 }
552 
553 PCInfo *
lookup_PCInfo(uint64_t offset)554 Function::lookup_PCInfo (uint64_t offset)
555 {
556   module->read_stabs ();
557   if (linetab == NULL)
558     linetab = new Vector<PCInfo*>;
559 
560   int left = 0;
561   int right = linetab->size () - 1;
562   while (left <= right)
563     {
564       int x = (left + right) / 2;
565       PCInfo *pcinfo = linetab->fetch (x);
566       if (offset >= ((uint64_t) pcinfo->offset))
567 	{
568 	  if (offset < (uint64_t) (pcinfo->offset + pcinfo->size))
569 	    return pcinfo;
570 	  left = x + 1;
571 	}
572       else
573 	right = x - 1;
574     }
575   return NULL;
576 }
577 
578 DbeInstr*
mapLineToPc(DbeLine * dbeLine)579 Function::mapLineToPc (DbeLine *dbeLine)
580 {
581   if (dbeLine && linetab)
582     {
583       DbeLine *dbl = dbeLine->dbeline_base;
584       for (int i = 0, sz = linetab->size (); i < sz; i++)
585 	{
586 	  PCInfo *pcinfo = linetab->get (i);
587 	  if (pcinfo->src_info
588 	      && (pcinfo->src_info->src_line->dbeline_base == dbl))
589 	    {
590 	      DbeInstr *dbeInstr = find_dbeinstr (PCLineFlag, pcinfo->offset);
591 	      if (dbeInstr)
592 		{
593 		  dbeInstr->lineno = dbeLine->lineno;
594 		  return dbeInstr;
595 		}
596 	    }
597 	}
598     }
599   return NULL;
600 }
601 
602 DbeLine*
mapPCtoLine(uint64_t addr,SourceFile * src)603 Function::mapPCtoLine (uint64_t addr, SourceFile *src)
604 {
605   PCInfo *pcinfo = lookup_PCInfo (addr);
606   if (pcinfo == NULL)
607     {
608       if (defaultDbeLine == NULL)
609 	defaultDbeLine = getDefSrc ()->find_dbeline (this, 0);
610       return defaultDbeLine;
611     }
612   DbeLine *dbeline = pcinfo->src_info->src_line;
613 
614   // If source-context is not specified return the line
615   // from which this pc has been generated.
616   if (src == NULL)
617     return dbeline;
618   if (dbeline->sourceFile == src)
619     return dbeline->dbeline_base;
620   return src->find_dbeline (this, 0);
621 }
622 
623 DbeInstr *
find_dbeinstr(int flag,uint64_t addr)624 Function::find_dbeinstr (int flag, uint64_t addr)
625 {
626   DbeInstr *instr;
627 
628   enum
629   {
630     FuncInstHTableSize = 128
631   };
632 
633   int hash = (((int) addr) >> 2) & (FuncInstHTableSize - 1);
634   if (instHTable == NULL)
635     {
636       if (size > 2048)
637 	{
638 	  instHTable = new DbeInstr*[FuncInstHTableSize];
639 	  for (int i = 0; i < FuncInstHTableSize; i++)
640 	    instHTable[i] = NULL;
641 	}
642     }
643   else
644     {
645       instr = instHTable[hash];
646       if (instr && instr->addr == addr && instr->flags == flag)
647 	return instr;
648     }
649 
650   int left = 0;
651   int right = instrs->size () - 1;
652   while (left <= right)
653     {
654       int index = (left + right) / 2;
655       instr = instrs->fetch (index);
656       if (addr < instr->addr)
657 	right = index - 1;
658       else if (addr > instr->addr)
659 	left = index + 1;
660       else
661 	{
662 	  if (flag == instr->flags)
663 	    {
664 	      if (instHTable)
665 		instHTable[hash] = instr;
666 	      return instr;
667 	    }
668 	  else if (flag < instr->flags)
669 	    right = index - 1;
670 	  else
671 	    left = index + 1;
672 	}
673     }
674 
675   // None found, create a new one
676   instr = new DbeInstr (instr_id++, flag, this, addr);
677   instrs->insert (left, instr);
678   if (instHTable)
679     instHTable[hash] = instr;
680   return instr;
681 }
682 
683 // LIBRARY_VISIBILITY
684 DbeInstr *
create_hide_instr(DbeInstr * instr)685 Function::create_hide_instr (DbeInstr *instr)
686 {
687   DbeInstr *new_instr = new DbeInstr (instr_id++, 0, this, instr->addr);
688   return new_instr;
689 }
690 
691 uint64_t
find_previous_addr(uint64_t addr)692 Function::find_previous_addr (uint64_t addr)
693 {
694   if (addrs == NULL)
695     {
696       addrs = module->getAddrs (this);
697       if (addrs == NULL)
698 	return addr;
699     }
700 
701   int index = -1, not_found = 1;
702 
703   enum
704   {
705     FuncAddrIndexHTableSize = 128
706   };
707   int hash = (((int) addr) >> 2) & (FuncAddrIndexHTableSize - 1);
708   if (addrIndexHTable == NULL)
709     {
710       if (size > 2048)
711 	{
712 	  addrIndexHTable = new int[FuncAddrIndexHTableSize];
713 	  for (int i = 0; i < FuncAddrIndexHTableSize; i++)
714 	    addrIndexHTable[i] = -1;
715 	}
716     }
717   else
718     {
719       index = addrIndexHTable[hash];
720       if (index >= 0 && addrs->fetch (index) == addr)
721 	not_found = 0;
722     }
723 
724   int left = 0;
725   int right = addrs->size () - 1;
726   while (not_found && left <= right)
727     {
728       index = (left + right) / 2;
729       uint64_t addr_test = addrs->fetch (index);
730       if (addr < addr_test)
731 	right = index - 1;
732       else if (addr > addr_test)
733 	left = index + 1;
734       else
735 	{
736 	  if (addrIndexHTable)
737 	    addrIndexHTable[hash] = index;
738 	  not_found = 0;
739 	}
740     }
741   if (not_found)
742     return addr;
743   if (index > 0)
744     index--;
745   return addrs->fetch (index);
746 }
747 
748 void
setSource()749 Function::setSource ()
750 {
751   SourceFile *sf = module->getIncludeFile ();
752   if (sf == NULL)
753     sf = getDefSrc ();
754   if (def_source == NULL)
755     setDefSrc (sf);
756   if (sf == def_source)
757     return;
758   if (sources == NULL)
759     {
760       sources = new Vector<SourceFile*>;
761       sources->append (def_source);
762       sources->append (sf);
763     }
764   else if (sources->find (sf) < 0)
765     sources->append (sf);
766 }
767 
768 void
setDefSrc(SourceFile * sf)769 Function::setDefSrc (SourceFile *sf)
770 {
771   if (sf)
772     {
773       def_source = sf;
774       if (line_first > 0)
775 	add_PC_info (0, line_first, def_source);
776     }
777 }
778 
779 void
setLineFirst(int lineno)780 Function::setLineFirst (int lineno)
781 {
782   if (lineno > 0)
783     {
784       line_first = lineno;
785       if (line_last <= 0)
786 	line_last = lineno;
787       if (def_source)
788 	add_PC_info (0, line_first, def_source);
789     }
790 }
791 
792 Vector<SourceFile*> *
get_sources()793 Function::get_sources ()
794 {
795   if (module)
796     module->read_stabs ();
797   if (sources == NULL)
798     {
799       sources = new Vector<SourceFile*>;
800       sources->append (getDefSrc ());
801     }
802   return sources;
803 }
804 
805 SourceFile*
getDefSrc()806 Function::getDefSrc ()
807 {
808   if (module)
809     module->read_stabs ();
810   if (def_source == NULL)
811     setDefSrc (module->getMainSrc ());
812   return def_source;
813 }
814 
815 char *
getDefSrcName()816 Function::getDefSrcName ()
817 {
818   SourceFile *sf = getDefSrc ();
819   if (sf)
820     return sf->dbeFile->getResolvedPath ();
821   if (module)
822     return module->file_name;
823   sf = dbeSession->get_Unknown_Source ();
824   return sf->get_name ();
825 }
826 
827 #define cmpValue(a, b) ((a) > (b) ? 1 : (a) == (b) ? 0 : -1)
828 
829 int
func_cmp(Function * func,SourceFile * srcContext)830 Function::func_cmp (Function *func, SourceFile *srcContext)
831 {
832   if (def_source != func->def_source)
833     {
834       if (srcContext == NULL)
835 	srcContext = getDefSrc ();
836       if (def_source == srcContext)
837 	return -1;
838       if (func->def_source == srcContext)
839 	return 1;
840       return cmpValue (img_offset, func->img_offset);
841     }
842 
843   if (line_first == func->line_first)
844     return cmpValue (img_offset, func->img_offset);
845   if (line_first <= 0)
846     {
847       if (func->line_first > 0)
848 	return 1;
849       return cmpValue (img_offset, func->img_offset);
850     }
851   if (func->line_first <= 0)
852     return -1;
853   return cmpValue (line_first, func->line_first);
854 }
855 
856 Vector<Histable*> *
get_comparable_objs()857 Function::get_comparable_objs ()
858 {
859   update_comparable_objs ();
860   if (comparable_objs || dbeSession->expGroups->size () <= 1 || module == NULL)
861     return comparable_objs;
862   if (module == NULL || module->loadobject == NULL)
863     return NULL;
864   Vector<Histable*> *comparableModules = module->get_comparable_objs ();
865   if (comparableModules == NULL)
866     {
867       return NULL;
868     }
869   comparable_objs = new Vector<Histable*>(comparableModules->size ());
870   for (long i = 0, sz = comparableModules->size (); i < sz; i++)
871     {
872       Function *func = NULL;
873       comparable_objs->store (i, func);
874       Module *mod = (Module*) comparableModules->fetch (i);
875       if (mod == NULL)
876 	continue;
877       if (mod == module)
878 	func = this;
879       else
880 	{
881 	  for (long i1 = 0, sz1 = VecSize (mod->functions); i1 < sz1; i1++)
882 	    {
883 	      Function *f = mod->functions->get (i1);
884 	      if ((f->comparable_objs == NULL)
885 		   && (strcmp (f->comparable_name, comparable_name) == 0))
886 		{
887 		  func = f;
888 		  func->comparable_objs = comparable_objs;
889 		  break;
890 		}
891 	    }
892 	}
893       comparable_objs->store (i, func);
894     }
895   Vector<Histable*> *comparableLoadObjs =
896 	  module->loadobject->get_comparable_objs ();
897   if (VecSize (comparableLoadObjs) == VecSize (comparable_objs))
898     {
899       for (long i = 0, sz = VecSize (comparableLoadObjs); i < sz; i++)
900 	{
901 	  LoadObject *lo = (LoadObject *) comparableLoadObjs->get (i);
902 	  Function *func = (Function *) comparable_objs->get (i);
903 	  if (func || (lo == NULL))
904 	    continue;
905 	  if (module->loadobject == lo)
906 	    func = this;
907 	  else
908 	    {
909 	      for (long i1 = 0, sz1 = VecSize (lo->functions); i1 < sz1; i1++)
910 		{
911 		  Function *f = lo->functions->fetch (i1);
912 		  if ((f->comparable_objs == NULL)
913 		       && (strcmp (f->comparable_name, comparable_name) == 0))
914 		    {
915 		      func = f;
916 		      func->comparable_objs = comparable_objs;
917 		      break;
918 		    }
919 		}
920 	    }
921 	  comparable_objs->store (i, func);
922 	}
923     }
924   dump_comparable_objs ();
925   return comparable_objs;
926 }
927 
JMethod(uint64_t _id)928 JMethod::JMethod (uint64_t _id) : Function (_id)
929 {
930   mid = 0LL;
931   addr = (Vaddr) 0;
932   signature = NULL;
933   jni_function = NULL;
934 }
935 
~JMethod()936 JMethod::~JMethod ()
937 {
938   free (signature);
939 }
940 
941 uint64_t
get_addr()942 JMethod::get_addr ()
943 {
944   if (addr != (Vaddr) 0)
945     return addr;
946   else
947     return Function::get_addr ();
948 }
949 
950 typedef struct
951 {
952   size_t used_in;
953   size_t used_out;
954 } MethodField;
955 
956 static void
write_buf(char * buf,char * str)957 write_buf (char* buf, char* str)
958 {
959   while ((*buf++ = *str++));
960 }
961 
962 /** Translate one field from the nane buffer.
963  * return how many chars were read from name and how many bytes were used in buf.
964  */
965 static MethodField
translate_method_field(const char * name,char * buf)966 translate_method_field (const char* name, char* buf)
967 {
968   MethodField out, t;
969   switch (*name)
970     {
971     case 'L':
972       name++;
973       out.used_in = 1;
974       out.used_out = 0;
975       while (*name != ';')
976 	{
977 	  *buf = *name++;
978 	  if (*buf == '/')
979 	    *buf = '.';
980 	  buf++;
981 	  out.used_in++;
982 	  out.used_out++;
983 	}
984       out.used_in++; /* the ';' is also used. */
985       break;
986     case 'Z':
987       write_buf (buf, NTXT ("boolean"));
988       out.used_out = 7;
989       out.used_in = 1;
990       break;
991     case 'B':
992       write_buf (buf, NTXT ("byte"));
993       out.used_out = 4;
994       out.used_in = 1;
995       break;
996     case 'C':
997       write_buf (buf, NTXT ("char"));
998       out.used_out = 4;
999       out.used_in = 1;
1000       break;
1001     case 'S':
1002       write_buf (buf, NTXT ("short"));
1003       out.used_out = 5;
1004       out.used_in = 1;
1005       break;
1006     case 'I':
1007       write_buf (buf, NTXT ("int"));
1008       out.used_out = 3;
1009       out.used_in = 1;
1010       break;
1011     case 'J':
1012       write_buf (buf, NTXT ("long"));
1013       out.used_out = 4;
1014       out.used_in = 1;
1015       break;
1016     case 'F':
1017       write_buf (buf, NTXT ("float"));
1018       out.used_out = 5;
1019       out.used_in = 1;
1020       break;
1021     case 'D':
1022       write_buf (buf, NTXT ("double"));
1023       out.used_out = 6;
1024       out.used_in = 1;
1025       break;
1026     case 'V':
1027       write_buf (buf, NTXT ("void"));
1028       out.used_out = 4;
1029       out.used_in = 1;
1030       break;
1031     case '[':
1032       t = translate_method_field (name + 1, buf);
1033       write_buf (buf + t.used_out, NTXT ("[]"));
1034       out.used_out = t.used_out + 2;
1035       out.used_in = t.used_in + 1;
1036       break;
1037     default:
1038       out.used_out = 0;
1039       out.used_in = 0;
1040     }
1041   return out;
1042 }
1043 
1044 /**
1045  * translate method name to full method signature
1046  * into the output buffer (buf).
1047  * ret_type - true for printing result type
1048  */
1049 static bool
translate_method(char * mname,char * signature,bool ret_type,char * buf)1050 translate_method (char* mname, char *signature, bool ret_type, char* buf)
1051 {
1052   MethodField p;
1053   size_t l;
1054   int first = 1;
1055   if (signature == NULL)
1056     return false;
1057 
1058   const char *c = strchr (signature, ')');
1059   if (c == NULL)
1060     return false;
1061   if (ret_type)
1062     {
1063       p = translate_method_field (++c, buf);
1064       buf += p.used_out;
1065       *buf++ = ' ';
1066     }
1067 
1068   l = strlen (mname);
1069   memcpy (buf, mname, l + 1);
1070   buf += l;
1071   // *buf++ = ' '; // space before ()
1072   *buf++ = '(';
1073 
1074   c = signature + 1;
1075   while (*c != ')')
1076     {
1077       if (!first)
1078 	{
1079 	  *buf++ = ',';
1080 	  *buf++ = ' ';
1081 	}
1082       first = 0;
1083       p = translate_method_field (c, buf);
1084       c += p.used_in;
1085       buf += p.used_out;
1086     }
1087 
1088   *buf++ = ')';
1089   *buf = '\0';
1090   return true;
1091 }
1092 
1093 void
set_name(char * string)1094 JMethod::set_name (char *string)
1095 {
1096   if (string == NULL)
1097     return;
1098   set_mangled_name (string);
1099 
1100   char buf[MAXDBUF];
1101   *buf = '\0';
1102   if (translate_method (string, signature, false, buf))
1103     {
1104       name = dbe_strdup (buf); // got translated string
1105       Dprintf (DUMP_JCLASS_READER,
1106 	      "JMethod::set_name: true name=%s string=%s signature=%s\n",
1107 	       STR (name), STR (string), STR (signature));
1108     }
1109   else
1110     {
1111       name = dbe_strdup (string);
1112       Dprintf (DUMP_JCLASS_READER,
1113 	       "JMethod::set_name: false name=%s signature=%s\n",
1114 	       STR (name), STR (signature));
1115     }
1116   set_match_name (name);
1117   set_comparable_name (name);
1118 }
1119 
1120 bool
jni_match(Function * func)1121 JMethod::jni_match (Function *func)
1122 {
1123   if (func == NULL || (func->flags & FUNC_NOT_JNI) != 0)
1124     return false;
1125   if (jni_function == func)
1126     return true;
1127 
1128   char *fname = func->get_name ();
1129   if ((func->flags & FUNC_JNI_CHECKED) == 0)
1130     {
1131       func->flags |= FUNC_JNI_CHECKED;
1132       if (strncmp (func->get_name (), NTXT ("Java_"), 5) != 0)
1133 	{
1134 	  func->flags |= FUNC_NOT_JNI;
1135 	  return false;
1136 	}
1137     }
1138 
1139   char *d = name;
1140   char *s = fname + 5;
1141   while (*d && *d != '(' && *d != ' ')
1142     {
1143       if (*d == '.')
1144 	{
1145 	  if (*s++ != '_')
1146 	    return false;
1147 	  d++;
1148 	}
1149       else if (*d == '_')
1150 	{
1151 	  if (*s++ != '_')
1152 	    return false;
1153 	  if (*s++ != '1')
1154 	    return false;
1155 	  d++;
1156 	}
1157       else if (*d++ != *s++)
1158 	return false;
1159     }
1160   jni_function = func;
1161   return true;
1162 }
1163