HPCToolkit
Struct.cpp
Go to the documentation of this file.
1 // -*-Mode: C++;-*-
2 
3 // * BeginRiceCopyright *****************************************************
4 //
5 // $HeadURL$
6 // $Id$
7 //
8 // --------------------------------------------------------------------------
9 // Part of HPCToolkit (hpctoolkit.org)
10 //
11 // Information about sources of support for research and development of
12 // HPCToolkit is at 'hpctoolkit.org' and in 'README.Acknowledgments'.
13 // --------------------------------------------------------------------------
14 //
15 // Copyright ((c)) 2002-2019, Rice University
16 // All rights reserved.
17 //
18 // Redistribution and use in source and binary forms, with or without
19 // modification, are permitted provided that the following conditions are
20 // met:
21 //
22 // * Redistributions of source code must retain the above copyright
23 // notice, this list of conditions and the following disclaimer.
24 //
25 // * Redistributions in binary form must reproduce the above copyright
26 // notice, this list of conditions and the following disclaimer in the
27 // documentation and/or other materials provided with the distribution.
28 //
29 // * Neither the name of Rice University (RICE) nor the names of its
30 // contributors may be used to endorse or promote products derived from
31 // this software without specific prior written permission.
32 //
33 // This software is provided by RICE and contributors "as is" and any
34 // express or implied warranties, including, but not limited to, the
35 // implied warranties of merchantability and fitness for a particular
36 // purpose are disclaimed. In no event shall RICE or contributors be
37 // liable for any direct, indirect, incidental, special, exemplary, or
38 // consequential damages (including, but not limited to, procurement of
39 // substitute goods or services; loss of use, data, or profits; or
40 // business interruption) however caused and on any theory of liability,
41 // whether in contract, strict liability, or tort (including negligence
42 // or otherwise) arising in any way out of the use of this software, even
43 // if advised of the possibility of such damage.
44 //
45 // ******************************************************* EndRiceCopyright *
46 
47 // This file builds and prints an hpcstruct file with loops and inline
48 // sequences based on input from the ParseAPI Control-Flow Graph
49 // support in Dyninst. We no longer use Open Analysis or the
50 // Prof::Struct classes.
51 //
52 // The internal representation of the structure info is defined in two
53 // files:
54 //
55 // Struct-Skel.hpp -- defines the top-level skeleton classes for
56 // Files, Groups and Procedures (Functions).
57 //
58 // Struct-Inline.hpp -- defines the Inline Tree classes for Loops,
59 // Statements (Instructions) and inline sequences.
60 //
61 // Printing the internal objects in the hpcstruct XML format is
62 // handled in Struct-Output.cpp.
63 
64 //***************************************************************************
65 
66 #include <sys/types.h>
67 #include <sys/resource.h>
68 #include <sys/time.h>
69 #include <stdlib.h>
70 #include <string.h>
71 #include <include/uint.h>
72 
73 #include <algorithm>
74 #include <map>
75 #include <set>
76 #include <string>
77 #include <vector>
78 #include <mutex>
79 #include <ostream>
80 #include <sstream>
81 
85 #include <lib/support/FileUtil.hpp>
88 
89 #include <CFG.h>
90 #include <CodeObject.h>
91 #include <CodeSource.h>
92 #include <Function.h>
93 #include <Instruction.h>
94 #include <Module.h>
95 #include <Region.h>
96 #include <Symtab.h>
97 
98 #include <include/hpctoolkit-config.h>
99 
100 #include "ElfHelper.hpp"
101 #include "InputFile.hpp"
102 #include "Struct.hpp"
103 #include "Struct-Inline.hpp"
104 #include "Struct-Output.hpp"
105 #include "Struct-Skel.hpp"
106 
107 #ifdef ENABLE_OPENMP
108 #include <omp.h>
109 #endif
110 
111 using namespace Dyninst;
112 using namespace Inline;
113 using namespace InstructionAPI;
114 using namespace SymtabAPI;
115 using namespace ParseAPI;
116 using namespace std;
117 
118 
119 //******************************************************************************
120 // macros
121 //******************************************************************************
122 
123 #ifdef DYNINST_USE_CUDA
124 #define SYMTAB_ARCH_CUDA(symtab) \
125  ((symtab)->getArchitecture() == Dyninst::Arch_cuda)
126 #else
127 #define SYMTAB_ARCH_CUDA(symtab) 0
128 #endif
129 
130 #define DEBUG_CFG_SOURCE 0
131 #define DEBUG_MAKE_SKEL 0
132 #define DEBUG_SHOW_GAPS 0
133 #define DEBUG_SKEL_SUMMARY 0
134 
135 #if DEBUG_CFG_SOURCE || DEBUG_MAKE_SKEL || DEBUG_SHOW_GAPS
136 #define DEBUG_ANY_ON 1
137 #else
138 #define DEBUG_ANY_ON 0
139 #endif
140 
141 #define WORK_LIST_PCT 0.05
142 
143 #define MIN_BYTES_GLOBAL_VARIABLE 1024
144 
145 static int merge_irred_loops = 1;
146 
147 
148 //******************************************************************************
149 // variables
150 //******************************************************************************
151 
152 // Copied from lib/prof/Struct-Tree.cpp
153 static const string & unknown_file = "<unknown file>";
154 static const string & unknown_proc = "<unknown proc>";
155 static const string & unknown_link = "_unknown_proc_";
156 
157 // FIXME: temporary until the line map problems are resolved
158 static Symtab * the_symtab = NULL;
159 
161 
162 //----------------------------------------------------------------------
163 
164 namespace BAnal {
165 namespace Struct {
166 
167 class HeaderInfo;
168 class WorkEnv;
169 class WorkItem;
171 
172 typedef map <Block *, bool> BlockSet;
173 typedef map <VMA, HeaderInfo> HeaderList;
174 typedef map <VMA, Region *> RegionMap;
175 typedef vector <Statement::Ptr> StatementVector;
176 typedef vector <WorkItem *> WorkList;
177 
178 static FileMap *
179 makeSkeleton(CodeObject *, const string &);
180 
181 static void
182 doWorkItem(WorkItem *, string &, bool, bool);
183 
184 static void
185 makeWorkList(FileMap *, WorkList &, WorkList &);
186 
187 static void
188 makeVariables(ostream * outFile);
189 
190 static void
191 printWorkList(WorkList &, uint &, ostream *, ostream *, string &);
192 
193 static void
195 
196 static LoopList *
197 doLoopTree(WorkEnv &, FileInfo *, GroupInfo *, ParseAPI::Function *,
198  BlockSet &, LoopTreeNode *);
199 
200 static TreeNode *
201 doLoopLate(WorkEnv &, GroupInfo *, ParseAPI::Function *,
202  BlockSet &, Loop *, const string &);
203 
204 static void
205 doBlock(WorkEnv &, GroupInfo *, ParseAPI::Function *,
206  BlockSet &, Block *, TreeNode *);
207 
208 static void
210 
211 static void
212 doCudaFunction(WorkEnv &, GroupInfo *, ParseAPI::Function *, TreeNode *);
213 
214 static void
215 addGaps(WorkEnv & env, FileInfo *, GroupInfo *);
216 
217 static void
218 getStatement(StatementVector &, Offset, SymtabAPI::Function *);
219 
220 static LoopInfo *
221 findLoopHeader(WorkEnv & env, FileInfo *, GroupInfo *, ParseAPI::Function *,
222  TreeNode *, Loop *, const string &);
223 
224 static TreeNode *
226 
227 static void
229 
230 static void
232 
233 //----------------------------------------------------------------------
234 
235 #if DEBUG_ANY_ON
236 
237 #define DEBUG_ANY(expr) std::cout << expr
238 
239 static string
240 debugPrettyName(const string &);
241 
242 static void
243 debugElfHeader(ElfFile *);
244 
245 static void
246 debugFuncHeader(FileInfo *, ProcInfo *, long, long, string = "");
247 
248 static void
249 debugStmt(VMA, int, string &, SrcFile::ln, RealPathMgr *);
250 
251 static void
252 debugEdges(Block * block);
253 
254 static void
255 debugLoop(GroupInfo *, ParseAPI::Function *, Loop *, const string &,
256  vector <Edge *> &, HeaderList &, RealPathMgr *);
257 
258 static void
259 debugInlineTree(TreeNode *, LoopInfo *, HPC::StringTable &, int, bool);
260 
261 #else // ! DEBUG_ANY_ON
262 
263 #define DEBUG_ANY(expr)
264 
265 #endif
266 
267 #if DEBUG_CFG_SOURCE
268 #define DEBUG_CFG(expr) std::cout << expr
269 #else
270 #define DEBUG_CFG(expr)
271 #endif
272 
273 #if DEBUG_MAKE_SKEL
274 #define DEBUG_SKEL(expr) std::cout << expr
275 #else
276 #define DEBUG_SKEL(expr)
277 #endif
278 
279 #if DEBUG_SHOW_GAPS
280 #define DEBUG_GAPS(expr) std::cout << expr
281 #else
282 #define DEBUG_GAPS(expr)
283 #endif
284 
285 //----------------------------------------------------------------------
286 
287 // Info on candidates for loop header.
288 class HeaderInfo {
289 public:
290  Block * block;
291  bool is_src;
292  bool is_excl;
293  int depth;
296  long line_num;
297 
298  HeaderInfo(Block * blk = NULL)
299  {
300  block = blk;
301  is_src = false;
302  is_excl = false;
303  depth = 0;
304  file_index = 0;
305  base_index = 0;
306  line_num = 0;
307  }
308 };
309 
310 //----------------------------------------------------------------------
311 
312 // The environment for interpreting paths, strings, etc. We allocate
313 // one environ per thread to avoid lock contention.
314 //
315 class WorkEnv {
316 public:
319 
321  {
322  strTab = NULL;
323  realPath = NULL;
324  }
325 };
326 
327 // One item in the work list for openmp parallel region.
328 class WorkItem {
329 public:
333  double cost;
335  bool last_proc;
336  bool is_done;
337  bool promote;
338 
339  WorkItem(FileInfo * fi, GroupInfo * gi, bool first, bool last, double cst)
340  {
341  finfo = fi;
342  ginfo = gi;
343  cost = cst;
344  first_proc = first;
345  last_proc = last;
346  is_done = false;
347  promote = false;
348  }
349 };
350 
351 //----------------------------------------------------------------------
352 
353 // A simple cache of getStatement() that stores one line range. This
354 // saves extra calls to getSourceLines() if we don't need them.
355 //
357 private:
358  SymtabAPI::Function * sym_func;
360  string cache_filenm;
364 
365 public:
366  LineMapCache(SymtabAPI::Function * sf, RealPathMgr * rp)
367  {
368  sym_func = sf;
369  realPath = rp;
370  cache_filenm = "";
371  cache_line = 0;
372  start = 1;
373  end = 0;
374  }
375 
376  bool
377  getLineInfo(VMA vma, string & filenm, uint & line)
378  {
379  // try cache first
380  if (start <= vma && vma < end) {
381  filenm = cache_filenm;
382  line = cache_line;
383  return true;
384  }
385 
386  // lookup with getStatement() and getSourceLines()
387  StatementVector svec;
388  getStatement(svec, vma, sym_func);
389 
390  if (! svec.empty()) {
391  filenm = svec[0]->getFile();
392  line = svec[0]->getLine();
393  realPath->realpath(filenm);
394 
395  cache_filenm = filenm;
396  cache_line = line;
397  start = svec[0]->startAddr();
398  end = svec[0]->endAddr();
399 
400  return true;
401  }
402 
403  // no line info available
404  filenm = "";
405  line = 0;
406  return false;
407  }
408 };
409 
410 //----------------------------------------------------------------------
411 
412 // Comparison functions to sort blocks, edges, loops for more
413 // deterministic output.
414 
415 // Sort Blocks by start address, low to high.
416 static bool
417 BlockLessThan(Block * b1, Block * b2)
418 {
419  return b1->start() < b2->start();
420 }
421 
422 // Sort Edges first by target address (usually all the same), and then
423 // by source address.
424 static bool
425 EdgeLessThan(Edge * e1, Edge * e2)
426 {
427  return (e1->trg()->start() < e2->trg()->start())
428  || (e1->trg()->start() == e2->trg()->start()
429  && e1->src()->last() < e2->src()->last());
430 }
431 
432 // Sort Work Items by the expected 'cost' of their proc group, largest
433 // to smallest.
434 static bool
436 {
437  return w1->cost > w2->cost;
438 }
439 
440 // Returns: the min entry VMA for the loop, or else 0 if the loop is
441 // somehow invalid. Irreducible loops have more than one entry
442 // address.
443 static VMA
444 LoopMinEntryAddr(Loop * loop)
445 {
446  if (loop == NULL) {
447  return 0;
448  }
449 
450  vector <Block *> entBlocks;
451  int num_ents = loop->getLoopEntries(entBlocks);
452 
453  if (num_ents < 1) {
454  return 0;
455  }
456 
457  VMA ans = VMA_MAX;
458  for (int i = 0; i < num_ents; i++) {
459  ans = std::min(ans, entBlocks[i]->start());
460  }
461 
462  return ans;
463 }
464 
465 // Sort Loops (from their LoopTreeNodes) by min entry VMAs.
466 static bool
467 LoopTreeLessThan(LoopTreeNode * n1, LoopTreeNode * n2)
468 {
469  return LoopMinEntryAddr(n1->loop) < LoopMinEntryAddr(n2->loop);
470 }
471 
472 // Sort LoopInfo objects by min entry VMAs.
473 static bool
475 {
476  return l1->entry_vma < l2->entry_vma;
477 }
478 
479 //----------------------------------------------------------------------
480 
481 // Line map info from SymtabAPI. Try the Module associated with the
482 // Symtab Function as a hint first, else look for other modules that
483 // might contain vma.
484 //
485 static void
486 getStatement(StatementVector & svec, Offset vma, SymtabAPI::Function * sym_func)
487 {
488  svec.clear();
489 
490  // try the Module in sym_func first as a hint
491  if (sym_func != NULL) {
492  Module * mod = sym_func->getModule();
493 
494  if (mod != NULL) {
495  mod->getSourceLines(svec, vma);
496  }
497  }
498 
499  // else look for other modules
500  if (svec.empty()) {
501  set <Module *> modSet;
502  the_symtab->findModuleByOffset(modSet, vma);
503 
504  for (auto mit = modSet.begin(); mit != modSet.end(); ++mit) {
505  (*mit)->getSourceLines(svec, vma);
506  if (! svec.empty()) {
507  break;
508  }
509  }
510  }
511 
512  // a known file and unknown line is now legal, but we require that
513  // any line map must contain a file name
514  if (! svec.empty() && svec[0]->getFile() == "") {
515  svec.clear();
516  }
517 }
518 
519 //----------------------------------------------------------------------
520 
521 //
522 // Display time and space usage per phase in makeStructure.
523 //
524 static void
525 printTime(const char *label, struct timeval *tv_prev, struct rusage *ru_prev,
526  struct timeval *tv_now, struct rusage *ru_now)
527 {
528  gettimeofday(tv_now, NULL);
529  getrusage(RUSAGE_SELF, ru_now);
530 
531  float delta = (float)(tv_now->tv_sec - tv_prev->tv_sec)
532  + ((float)(tv_now->tv_usec - tv_prev->tv_usec))/1000000.0;
533 
534  printf("%s %8.1f sec %8ld meg %8ld meg", label, delta,
535  (ru_now->ru_maxrss - ru_prev->ru_maxrss)/1024,
536  ru_now->ru_maxrss/1024);
537 
538  cout << endl;
539 }
540 
541 //
542 // makeStructure -- the main entry point for hpcstruct realmain().
543 //
544 // Read the binutils load module and the parseapi code object, iterate
545 // over functions, loops and blocks, make an internal inline tree and
546 // write an hpcstruct file to 'outFile'.
547 //
548 // Fixme: may want to rethink the split between tool/hpcstruct and
549 // lib/banal.
550 //
551 void
552 makeStructure(string filename,
553  ostream * outFile,
554  ostream * gapsFile,
555  string gaps_filenm,
556  string search_path,
557  Struct::Options & structOpts)
558 {
559  struct timeval tv_init, tv_symtab, tv_parse, tv_fini;
560  struct rusage ru_init, ru_symtab, ru_parse, ru_fini;
561 
562  opts = structOpts;
563 
564 #ifdef ENABLE_OPENMP
565  omp_set_num_threads(opts.jobs_symtab);
566 #endif
567 
568  InputFile inputFile;
569  if (! inputFile.openFile(filename)) {
570  // error already printed by openFile
571  exit(1);
572  }
573 
574  ElfFileVector * elfFileVector = inputFile.fileVector();
575  string & sfilename = inputFile.fileName();
576  const char * cfilename = inputFile.CfileName();
577 
578  if (elfFileVector == NULL || elfFileVector->empty()) {
579  return;
580  }
581 
582  Output::printStructFileBegin(outFile, gapsFile, sfilename);
583 
584  for (uint i = 0; i < elfFileVector->size(); i++) {
585  ElfFile *elfFile = (*elfFileVector)[i];
586 
587  if (opts.show_time) {
588  cout << "file: " << elfFile->getFileName() << "\n"
589  << "symtab threads: " << opts.jobs_symtab
590  << " parse: " << opts.jobs_parse
591  << " struct: " << opts.jobs << "\n\n";
592  printTime("init: ", &tv_init, &ru_init, &tv_init, &ru_init);
593  }
594 
595 #if DEBUG_ANY_ON
596  debugElfHeader(elfFile);
597 #endif
598 
599 #ifdef ENABLE_OPENMP
600  omp_set_num_threads(opts.jobs_symtab);
601 #endif
602 
603  Symtab * symtab = Inline::openSymtab(elfFile);
604  if (symtab == NULL) {
605  continue;
606  }
607  the_symtab = symtab;
608  bool cuda_file = SYMTAB_ARCH_CUDA(symtab);
609 
610  // pre-compute line map info
611  vector <Module *> modVec;
612  the_symtab->getAllModules(modVec);
613 
614 #pragma omp parallel shared(modVec)
615  {
616 #pragma omp for schedule(dynamic, 1)
617  for (uint i = 0; i < modVec.size(); i++) {
618  Module * mod = modVec[i];
619  mod->parseLineInformation();
620  }
621  } // end parallel
622 
623  if (opts.show_time) {
624  printTime("symtab:", &tv_init, &ru_init, &tv_symtab, &ru_symtab);
625  }
626 
627 #ifdef ENABLE_OPENMP
628  omp_set_num_threads(opts.jobs_parse);
629 #endif
630 
631  SymtabCodeSource * code_src = new SymtabCodeSource(symtab);
632  CodeObject * code_obj = new CodeObject(code_src);
633 
634  // don't run parseapi on cuda binary
635  if (! cuda_file) {
636  code_obj->parse();
637  }
638 
639  if (opts.show_time) {
640  printTime("parse: ", &tv_symtab, &ru_symtab, &tv_parse, &ru_parse);
641  }
642 
643 #ifdef ENABLE_OPENMP
644  omp_set_num_threads(opts.jobs);
645 #endif
646 
647  string basename = FileUtil::basename(cfilename);
648  FileMap * fileMap = makeSkeleton(code_obj, basename);
649 
650  //
651  // make two work lists:
652  // wlPrint -- the output order in the struct file as determined
653  // by files and procs from makeSkeleton(),
654  // wlLaunch -- the order we launch doWorkItem(), mostly print
655  // order but with a few, very large funcs moved to the front of
656  // the list.
657  //
658  WorkList wlPrint;
659  WorkList wlLaunch;
660  uint num_done = 0;
661  mutex output_mtx;
662 
663  makeWorkList(fileMap, wlPrint, wlLaunch);
664 
665  Output::printLoadModuleBegin(outFile, elfFile->getFileName());
666 
667  makeVariables(outFile);
668 
669 #pragma omp parallel default(none) \
670  shared(wlPrint, wlLaunch, num_done, output_mtx) \
671  firstprivate(outFile, gapsFile, search_path, gaps_filenm, cuda_file)
672  {
673 #pragma omp for schedule(dynamic, 1)
674  for (uint i = 0; i < wlLaunch.size(); i++) {
675  doWorkItem(wlLaunch[i], search_path, cuda_file, gapsFile != NULL);
676 
677  // the printing must be single threaded
678  if (output_mtx.try_lock()) {
679  printWorkList(wlPrint, num_done, outFile, gapsFile, gaps_filenm);
680  output_mtx.unlock();
681  }
682  }
683  } // end parallel
684 
685  // with try_lock(), there are interleavings where not all items
686  // have been printed.
687  printWorkList(wlPrint, num_done, outFile, gapsFile, gaps_filenm);
688 
690 
691  if (opts.show_time) {
692  printTime("struct:", &tv_parse, &ru_parse, &tv_fini, &ru_fini);
693  printTime("total: ", &tv_init, &ru_init, &tv_fini, &ru_fini);
694  cout << "\nnum funcs: " << wlPrint.size() << "\n" << endl;
695  }
696 
697  // if this is the last (or only) elf file, then don't bother with
698  // piecemeal cleanup.
699  if (i + 1 < elfFileVector->size()) {
700  for (uint i = 0; i < wlPrint.size(); i++) {
701  delete wlPrint[i];
702  }
703 
704  delete code_obj;
705  delete code_src;
707  }
708  }
709 
710  Output::printStructFileEnd(outFile, gapsFile);
711 }
712 
713 //----------------------------------------------------------------------
714 
715 //
716 // Make the inline tree for funcs in one proc group. This much can
717 // run concurrently.
718 //
719 static void
720 doWorkItem(WorkItem * witem, string & search_path, bool cuda_file,
721  bool fullGaps)
722 {
723  FileInfo * finfo = witem->finfo;
724  GroupInfo * ginfo = witem->ginfo;
725 
726  // each work item gets its own string table and path manager to
727  // avoid lock contention.
728  HPC::StringTable * strTab = new HPC::StringTable;
729  strTab->str2index("");
730 
731  PathFindMgr * pathFind = new PathFindMgr;
732  PathReplacementMgr * pathReplace = new PathReplacementMgr;
733  RealPathMgr * realPath = new RealPathMgr(pathFind, pathReplace);
734  realPath->searchPaths(search_path);
735 
736  witem->env.strTab = strTab;
737  witem->env.realPath = realPath;
738 
739  if (cuda_file) {
740  doCudaList(witem->env, finfo, ginfo);
741  }
742  else {
743  doFunctionList(witem->env, finfo, ginfo, fullGaps);
744  }
745 
746  witem->is_done = true;
747 }
748 
749 //----------------------------------------------------------------------
750 
751 //
752 // Make work lists for the print order and parallel launch order from
753 // the skeleton file map. The launch order is mostly the print order
754 // with a few, very large funcs moved to the front.
755 //
756 // There are two extremes to avoid: (1) we don't want the printing to
757 // be blocked by one early func that was started late, and (2) we
758 // don't want one large func to run at the end when all the other
759 // threads are idle.
760 //
761 static void
762 makeWorkList(FileMap * fileMap, WorkList & wlPrint, WorkList & wlLaunch)
763 {
764  double total_cost = 0.0;
765 
766  wlPrint.clear();
767  wlLaunch.clear();
768 
769  // the print order is determined by the hierarchy of files and
770  // groups in the skeleton.
771  for (auto fit = fileMap->begin(); fit != fileMap->end(); ++fit) {
772  FileInfo * finfo = fit->second;
773  auto group_begin = finfo->groupMap.begin();
774  auto group_end = finfo->groupMap.end();
775 
776  for (auto git = group_begin; git != group_end; ++git) {
777  GroupInfo * ginfo = git->second;
778  auto next_git = git; ++next_git;
779 
780  // the estimated time is non-linear in the size of the region
781  double cost = ginfo->end - ginfo->start;
782  cost *= cost;
783  total_cost += cost;
784 
785  WorkItem * witem =
786  new WorkItem(finfo, ginfo, (git == group_begin), (next_git == group_end), cost);
787 
788  wlPrint.push_back(witem);
789  }
790  }
791 
792  // if single-threaded, then order doesn't matter
793  if (opts.jobs == 1) {
794  wlLaunch = wlPrint;
795  return;
796  }
797 
798  //
799  // if the expected cost of one function is more than 5% of the ideal
800  // parallel run time, then promote it to start early.
801  //
802  double threshold = WORK_LIST_PCT * total_cost / ((double) opts.jobs);
803 
804  for (auto wit = wlPrint.begin(); wit != wlPrint.end(); ++wit) {
805  WorkItem * witem = *wit;
806 
807  if (witem->cost > threshold) {
808  wlLaunch.push_back(witem);
809  witem->promote = true;
810  }
811  }
812  std::sort(wlLaunch.begin(), wlLaunch.end(), WorkItemGreaterThan);
813 
814  // add the small items in print order
815  for (auto wit = wlPrint.begin(); wit != wlPrint.end(); ++wit) {
816  WorkItem * witem = *wit;
817 
818  if (! witem->promote) {
819  wlLaunch.push_back(witem);
820  }
821  }
822 }
823 
824 //----------------------------------------------------------------------
825 
826 //
827 // Scan the work list from num_done to end for items that are ready to
828 // be printed. The output order is always work list order, regardless
829 // of order finished.
830 //
831 // Note: the output functions have state (index number), so this must
832 // be called locked or else single threaded.
833 //
834 static void
835 printWorkList(WorkList & workList, uint & num_done, ostream * outFile,
836  ostream * gapsFile, string & gaps_filenm)
837 {
838  while (num_done < workList.size() && workList[num_done]->is_done) {
839  WorkItem * witem = workList[num_done];
840  FileInfo * finfo = witem->finfo;
841  GroupInfo * ginfo = witem->ginfo;
842  HPC::StringTable * strTab = witem->env.strTab;
843 
844  if (witem->first_proc) {
845  Output::printFileBegin(outFile, finfo);
846  }
847 
848  for (auto pit = ginfo->procMap.begin(); pit != ginfo->procMap.end(); ++pit) {
849  ProcInfo * pinfo = pit->second;
850 
851  if (! pinfo->gap_only) {
852  Output::printProc(outFile, gapsFile, gaps_filenm, finfo, ginfo, pinfo, *strTab);
853  }
854  delete pinfo->root;
855  pinfo->root = NULL;
856  }
857 
858  if (witem->last_proc) {
859  Output::printFileEnd(outFile, finfo);
860  }
861 
862  // delete the work environment
863  delete strTab;
864  witem->env.strTab = NULL;
865 
866  delete witem->env.realPath;
867  witem->env.realPath = NULL;
868 
869  num_done++;
870  }
871 }
872 
873 //----------------------------------------------------------------------
874 
875 // codeMap is a map of all code regions from start vma to Region *.
876 // Used to find the region containing a vma and thus the region's end.
877 //
878 static void
879 makeCodeMap(RegionMap & codeMap)
880 {
881  DEBUG_SKEL("\n");
882 
883  vector <Region *> regVec;
884  the_symtab->getCodeRegions(regVec);
885 
886  codeMap.clear();
887 
888  for (auto it = regVec.begin(); it != regVec.end(); ++it) {
889  Region * reg = *it;
890  VMA start = reg->getMemOffset();
891 
892  codeMap[start] = reg;
893 
894  DEBUG_SKEL("code region: 0x" << hex << start
895  << "--0x" << (start + reg->getMemSize()) << dec
896  << " " << reg->getRegionName() << "\n");
897  }
898 
899 #if DEBUG_MAKE_SKEL
900  // print the list of modules
901  vector <Module *> modVec;
902  the_symtab->getAllModules(modVec);
903 
904  cout << "\n";
905  for (auto mit = modVec.begin(); mit != modVec.end(); ++mit) {
906  Module * mod = *mit;
907 
908  if (mod != NULL) {
909  cout << "module: 0x" << hex << mod->addr() << dec
910  << " (lang " << mod->language() << ")"
911  << " " << mod->fullName() << "\n";
912  }
913  }
914 #endif
915 }
916 
917 // Note: normally, code regions don't overlap, but if they do, then we
918 // find the Region with the highest start address that contains vma.
919 //
920 // Returns: the Region containing vma, or else NULL.
921 //
922 static Region *
923 findCodeRegion(RegionMap & codeMap, VMA vma)
924 {
925  auto it = codeMap.upper_bound(vma);
926 
927  // invariant: vma is not in range it...end
928  while (it != codeMap.begin()) {
929  --it;
930 
931  Region * reg = it->second;
932  VMA start = reg->getMemOffset();
933  VMA end = start + reg->getMemSize();
934 
935  if (start <= vma && vma < end) {
936  return reg;
937  }
938  }
939 
940  return NULL;
941 }
942 
943 //----------------------------------------------------------------------
944 
945 // getProcLineMap -- helper for makeSkeleton() to find line map info
946 // for the start of a Procedure.
947 //
948 // Some compilers, especially for CUDA binaries, and sometimes dyninst
949 // or libdwarf, omit or fail to read line map info for the first few
950 // bytes of a function. Rather than returning 'unknown file', we try
951 // scanning the first few hundred bytes in the proc.
952 //
953 static void
954 getProcLineMap(StatementVector & svec, Offset vma, Offset end,
955  SymtabAPI::Function * sym_func)
956 {
957  svec.clear();
958 
959  // try a full module lookup first
960  getStatement(svec, vma, sym_func);
961  if (! svec.empty()) {
962  return;
963  }
964 
965  // confine further searches to the primary module
966  if (sym_func == NULL) {
967  return;
968  }
969  Module * mod = sym_func->getModule();
970 
971  if (mod == NULL) {
972  return;
973  }
974 
975  // retry every 'step' bytes, but double the step every 8 tries to
976  // make a logarithmic search
977  const int init_step = 2;
978  const int max_tries = 8;
979  int step = init_step;
980  int num_tries = 0;
981  end = std::min(end, vma + 800);
982 
983  for (;;) {
984  // invariant: vma does not have line info, but next might
985  Offset next = vma + step;
986  if (next >= end) {
987  break;
988  }
989 
990  mod->getSourceLines(svec, next);
991  num_tries++;
992 
993  if (! svec.empty()) {
994  // rescan the range [vma, next) but start over with a small step
995  if (step <= init_step) {
996  break;
997  }
998  svec.clear();
999  step = init_step;
1000  num_tries = 0;
1001  }
1002  else {
1003  // advance vma and double the step after 8 tries
1004  vma = next;
1005  if (num_tries >= max_tries) {
1006  step *= 2;
1007  num_tries = 0;
1008  }
1009  }
1010  }
1011 }
1012 
1013 // addProc -- helper for makeSkeleton() to locate and add one ProcInfo
1014 // object into the global file map.
1015 //
1016 static void
1017 addProc(FileMap * fileMap, ProcInfo * pinfo, string & filenm,
1018  SymtabAPI::Function * sym_func, VMA start, VMA end, bool alt_file = false)
1019 {
1020  // locate in file map, or else insert
1021  FileInfo * finfo = NULL;
1022 
1023  auto fit = fileMap->find(filenm);
1024  if (fit != fileMap->end()) {
1025  finfo = fit->second;
1026  }
1027  else {
1028  finfo = new FileInfo(filenm);
1029  (*fileMap)[filenm] = finfo;
1030  }
1031 
1032  // locate in group map, or else insert
1033  GroupInfo * ginfo = NULL;
1034 
1035  auto git = finfo->groupMap.find(start);
1036  if (git != finfo->groupMap.end()) {
1037  ginfo = git->second;
1038  }
1039  else {
1040  ginfo = new GroupInfo(sym_func, start, end, alt_file);
1041  finfo->groupMap[start] = ginfo;
1042  }
1043 
1044  ginfo->procMap[pinfo->entry_vma] = pinfo;
1045 
1046 #if DEBUG_MAKE_SKEL
1047  cout << "link: " << pinfo->linkName << "\n"
1048  << "pretty: " << pinfo->prettyName << "\n"
1049  << (alt_file ? "alt-file: " : "file: ") << finfo->fileName << "\n"
1050  << "group: 0x" << hex << ginfo->start << "--0x" << ginfo->end << dec << "\n";
1051 #endif
1052 }
1053 
1054 
1055 static void
1056 makeVariables(ostream * outFile)
1057 {
1058  FileInfo file(unknown_file);
1059 
1060  Output::printFileBegin(outFile, &file);
1061 
1062  std::vector<Symbol*> symvec;
1063 
1064  the_symtab->getAllSymbolsByType(symvec, Symbol::ST_OBJECT);
1065 
1066  for (auto i=0; i<symvec.size(); i++) {
1067  Symbol *s = symvec[i];
1068  if (s->getOffset() == 0 || s->getSize()<MIN_BYTES_GLOBAL_VARIABLE)
1069  continue;
1070 
1071  VariableInfo vinfo;
1072  vinfo.line_num = 0;
1073  vinfo.prettyName = s->getPrettyName();
1074  vinfo.entry_vma = s->getOffset();
1075  vinfo.num_bytes = s->getSize();
1076 
1077  Output::printVariable(outFile, NULL, vinfo);
1078  }
1079 
1080  Output::printFileEnd(outFile, &file);
1081 }
1082 
1083 //----------------------------------------------------------------------
1084 
1085 // getFuncNames -- helper for makeSkeleton() to select the pretty and
1086 // link (mangled) names for a SymtabAPI::Function.
1087 //
1088 // Some functions have multiple symbols with different names for the
1089 // same addres (global and weak syms). We sort the symbol names to
1090 // make the choice deterministic. We could prefer a global symbol,
1091 // but global is not always unique.
1092 //
1093 // Note: prettynm and linknm are passed in with default (unknown proc)
1094 // values, so don't overwrite them unless there is at least one valid
1095 // name.
1096 //
1097 static void
1098 getFuncNames(SymtabAPI::Function * sym_func, string & prettynm,
1099  string & linknm, bool ourDemangle)
1100 {
1101  auto pretty_begin = sym_func->pretty_names_begin();
1102  auto pretty_end = sym_func->pretty_names_end();
1103  auto mangled_end = sym_func->mangled_names_end();
1104 
1105  auto pretty_it = pretty_begin;
1106  auto mangled_it = sym_func->mangled_names_begin();
1107 
1108  while (pretty_it != pretty_end && mangled_it != mangled_end) {
1109  string new_mangled = *mangled_it;
1110  string new_pretty =
1111  (ourDemangle) ? BinUtil::demangleProcName(new_mangled) : *pretty_it;
1112 
1113  if (pretty_it == pretty_begin || new_pretty.compare(prettynm) < 0) {
1114  prettynm = new_pretty;
1115  linknm = new_mangled;
1116  }
1117 
1118  ++pretty_it;
1119  ++mangled_it;
1120  }
1121 }
1122 
1123 //----------------------------------------------------------------------
1124 // makeSkeleton -- the new buildLMSkeleton
1125 //
1126 // In the ParseAPI version, we iterate over the ParseAPI list of
1127 // functions and match them up with the SymtabAPI functions by entry
1128 // address. We now use Symtab for the line map info.
1129 //
1130 // Note: several parseapi functions (targ410aa7) may map to the same
1131 // symtab proc, so we make a func list (group).
1132 //
1133 static FileMap *
1134 makeSkeleton(CodeObject * code_obj, const string & basename)
1135 {
1136  FileMap * fileMap = new FileMap;
1137  string unknown_base = unknown_file + " [" + basename + "]";
1138  bool is_shared = ! (the_symtab->isExec());
1139 
1140  // map of code regions to find end of region
1141  RegionMap codeMap;
1142  makeCodeMap(codeMap);
1143 
1144  // iterate over the ParseAPI Functions, order by vma
1145  const CodeObject::funclist & funcList = code_obj->funcs();
1146  map <VMA, ParseAPI::Function *> funcMap;
1147 
1148  for (auto flit = funcList.begin(); flit != funcList.end(); ++flit) {
1149  ParseAPI::Function * func = *flit;
1150  funcMap[func->addr()] = func;
1151  }
1152 
1153  for (auto fmit = funcMap.begin(); fmit != funcMap.end(); ++fmit) {
1154  ParseAPI::Function * func = fmit->second;
1155  SymtabAPI::Function * sym_func = NULL;
1156  VMA vma = func->addr();
1157 
1158  auto next_it = fmit; ++next_it;
1159  VMA next_vma = (next_it != funcMap.end()) ? next_it->second->addr() : 0;
1160 
1161  stringstream buf;
1162  buf << "0x" << hex << vma << dec;
1163  string vma_str = buf.str();
1164 
1165  DEBUG_SKEL("\nskel: " << vma_str << " " << func->name() << "\n");
1166 
1167  // see if entry vma lies within a valid symtab function
1168  bool found = the_symtab->getContainingFunction(vma, sym_func);
1169  VMA sym_start = 0;
1170  VMA sym_end = 0;
1171 
1172  Region * region = NULL;
1173  VMA reg_start = 0;
1174  VMA reg_end = 0;
1175 
1176  if (found && sym_func != NULL) {
1177  sym_start = sym_func->getOffset();
1178  sym_end = sym_start + sym_func->getSize();
1179 
1180  region = sym_func->getRegion();
1181  if (region != NULL) {
1182  reg_start = region->getMemOffset();
1183  reg_end = reg_start + region->getMemSize();
1184  }
1185  }
1186 
1187  DEBUG_SKEL("symbol: 0x" << hex << sym_start << "--0x" << sym_end
1188  << " next: 0x" << next_vma
1189  << " region: 0x" << reg_start << "--0x" << reg_end << dec << "\n");
1190 
1191  // symtab doesn't recognize plt funcs and puts them in the wrong
1192  // region. to be a valid symbol, the func entry must lie within
1193  // the symbol's region.
1194  if (found && sym_func != NULL && region != NULL
1195  && reg_start <= vma && vma < reg_end)
1196  {
1197  string filenm = unknown_base;
1198  string linknm = unknown_link + vma_str;
1199  string prettynm = unknown_proc + " " + vma_str + " [" + basename + "]";
1200  SrcFile::ln line = 0;
1201 
1202  // symtab lets some funcs (_init) spill into the next region
1203  if (sym_start < reg_end && reg_end < sym_end) {
1204  sym_end = reg_end;
1205  }
1206 
1207  // line map for symtab func
1208  vector <Statement::Ptr> svec;
1209  getProcLineMap(svec, sym_start, sym_end, sym_func);
1210 
1211  if (! svec.empty()) {
1212  filenm = svec[0]->getFile();
1213  line = svec[0]->getLine();
1214  RealPathMgr::singleton().realpath(filenm);
1215  }
1216 
1217  if (vma == sym_start) {
1218  //
1219  // case 1 -- group leader of a valid symtab func. take proc
1220  // names from symtab func. this is the normal case (but other
1221  // cases are also valid).
1222  //
1223  DEBUG_SKEL("(case 1)\n");
1224 
1225  getFuncNames(sym_func, prettynm, linknm, opts.ourDemangle);
1226  if (is_shared) {
1227  prettynm += " (" + basename + ")";
1228  }
1229 
1230  ProcInfo * pinfo = new ProcInfo(func, NULL, linknm, prettynm, line,
1231  sym_func->getFirstSymbol()->getIndex());
1232  addProc(fileMap, pinfo, filenm, sym_func, sym_start, sym_end);
1233  }
1234  else {
1235  // outline func -- see if parseapi and symtab file names match
1236  string parse_filenm = unknown_base;
1237  SrcFile::ln parse_line = 0;
1238 
1239  // line map for parseapi func
1240  vector <Statement::Ptr> pvec;
1241  getProcLineMap(pvec, vma, sym_end, sym_func);
1242 
1243  if (! pvec.empty()) {
1244  parse_filenm = pvec[0]->getFile();
1245  parse_line = pvec[0]->getLine();
1246  RealPathMgr::singleton().realpath(parse_filenm);
1247  }
1248 
1249  string parse_base = FileUtil::basename(parse_filenm.c_str());
1250  stringstream buf;
1251  buf << "outline " << parse_base << ":" << parse_line << " (" << vma_str << ")";
1252  if (is_shared) {
1253  buf << " (" << basename << ")";
1254  }
1255 
1256  linknm = func->name();
1257  prettynm = buf.str();
1258 
1259  if (filenm == parse_filenm) {
1260  //
1261  // case 2 -- outline func inside symtab func with same file
1262  // name. use 'outline 0xxxxxx' proc name.
1263  //
1264  DEBUG_SKEL("(case 2)\n");
1265 
1266  ProcInfo * pinfo = new ProcInfo(func, NULL, linknm, prettynm, parse_line);
1267  addProc(fileMap, pinfo, filenm, sym_func, sym_start, sym_end);
1268  }
1269  else {
1270  //
1271  // case 3 -- outline func but from a different file name.
1272  // add proc info to both files: outline file for full parse
1273  // (but no gaps), and symtab file for gap only.
1274  //
1275  DEBUG_SKEL("(case 3)\n");
1276 
1277  ProcInfo * pinfo = new ProcInfo(func, NULL, linknm, prettynm, parse_line);
1278  addProc(fileMap, pinfo, parse_filenm, sym_func, sym_start, sym_end, true);
1279 
1280  pinfo = new ProcInfo(func, NULL, "", "", 0, 0, true);
1281  addProc(fileMap, pinfo, filenm, sym_func, sym_start, sym_end);
1282  }
1283  }
1284  }
1285  else {
1286  //
1287  // case 4 -- no symtab symbol claiming this vma (and thus no
1288  // line map). make a fake group at the parseapi entry vma.
1289  // this normally only happens for plt funcs.
1290  //
1291  string linknm = func->name();
1292  string prettynm = BinUtil::demangleProcName(linknm);
1293  VMA end = 0;
1294 
1295  // symtab doesn't offer any guidance on demangling in this case
1296  if (linknm != prettynm
1297  && prettynm.find_first_of("()<>") == string::npos) {
1298  prettynm = linknm;
1299  }
1300 
1301  region = findCodeRegion(codeMap, vma);
1302  reg_start = (region != NULL) ? region->getMemOffset() : 0;
1303  reg_end = (region != NULL) ? (reg_start + region->getMemSize()) : 0;
1304 
1305  DEBUG_SKEL("region: 0x" << hex << reg_start << "--0x" << reg_end << dec << "\n");
1306  DEBUG_SKEL("(case 4)\n");
1307 
1308  if (next_it != funcMap.end()) {
1309  end = next_vma;
1310  if (region != NULL && vma < reg_end && reg_end < end) {
1311  end = reg_end;
1312  }
1313  }
1314  else if (region != NULL && vma < reg_end) {
1315  end = reg_end;
1316  }
1317  else {
1318  end = vma + 20;
1319  }
1320 
1321  // treat short parseapi functions with no symtab symbol as a plt
1322  // stub. not an ideal test, but I (krentel) can't find any
1323  // counter examples.
1324  if (end - vma <= 32) {
1325  int len = linknm.length();
1326  const char *str = linknm.c_str();
1327 
1328  if (len < 5 || strncasecmp(&str[len-4], "@plt", 4) != 0) {
1329  linknm += "@plt";
1330  prettynm += "@plt";
1331  }
1332  }
1333  if (is_shared) {
1334  prettynm += " (" + basename + ")";
1335  }
1336 
1337  ProcInfo * pinfo = new ProcInfo(func, NULL, linknm, prettynm, 0);
1338  addProc(fileMap, pinfo, unknown_base, NULL, vma, end);
1339  }
1340  }
1341 
1342 #if DEBUG_SKEL_SUMMARY
1343  // print the skeleton map
1344  cout << "\n------------------------------------------------------------\n";
1345 
1346  for (auto fit = fileMap->begin(); fit != fileMap->end(); ++fit) {
1347  auto finfo = fit->second;
1348 
1349  for (auto git = finfo->groupMap.begin(); git != finfo->groupMap.end(); ++git) {
1350  auto ginfo = git->second;
1351  long size = ginfo->procMap.size();
1352  long num = 0;
1353 
1354  for (auto pit = ginfo->procMap.begin(); pit != ginfo->procMap.end(); ++pit) {
1355  auto pinfo = pit->second;
1356  num++;
1357 
1358  cout << "\nentry: 0x" << hex << pinfo->entry_vma << dec
1359  << " (" << num << "/" << size << ")\n"
1360  << "group: 0x" << hex << ginfo->start
1361  << "--0x" << ginfo->end << dec << "\n"
1362  << "file: " << finfo->fileName << "\n"
1363  << "link: " << pinfo->linkName << "\n"
1364  << "pretty: " << pinfo->prettyName << "\n"
1365  << "parse: " << pinfo->func->name() << "\n"
1366  << "line: " << pinfo->line_num << "\n";
1367  }
1368  }
1369  }
1370  cout << "\n";
1371 #endif
1372 
1373  return fileMap;
1374 }
1375 
1376 //****************************************************************************
1377 // ParseAPI code for functions, loops and blocks
1378 //****************************************************************************
1379 
1380 // Remaining TO-DO items:
1381 //
1382 // 4. Irreducible loops -- study entry blocks, loop header, adjacent
1383 // nested loops. Some nested irreducible loops share entry blocks and
1384 // maybe should be merged.
1385 //
1386 // 5. Compute line ranges for loops and procs to help decide what is
1387 // alien code when the symtab inline info is not available.
1388 //
1389 // 6. Handle code movement wrt loops: loop fusion, fission, moving
1390 // code in/out of loops.
1391 //
1392 // 10. Decide how to handle basic blocks that belong to multiple
1393 // functions.
1394 //
1395 // 11. Improve demangle proc names -- the problem is more if/when to
1396 // demangle rather than how. Maybe keep a map of symtab mangled to
1397 // pretty names.
1398 
1399 //----------------------------------------------------------------------
1400 
1401 // Process the functions in one binutils group. For each ParseAPI
1402 // function in the group, create the inline tree and fill in the
1403 // TreeNode ptr in ProcInfo.
1404 //
1405 // One binutils proc may contain multiple embedded parseapi functions.
1406 // In that case, we create new proc/file scope nodes for each function
1407 // and strip the inline prefix at the call source from the embed
1408 // function. This often happens with openmp parallel pragmas.
1409 //
1410 static void
1411 doFunctionList(WorkEnv & env, FileInfo * finfo, GroupInfo * ginfo, bool fullGaps)
1412 {
1413  long num_funcs = ginfo->procMap.size();
1414  set <Address> coveredFuncs;
1415  VMAIntervalSet covered;
1416 
1417  // make a map of internal call edges (from target to source) across
1418  // all funcs in this group. we use this to strip the inline seqn at
1419  // the call source from the target func.
1420  //
1421  map <VMA, VMA> callMap;
1422 
1423  if (ginfo->sym_func != NULL && !ginfo->alt_file && num_funcs > 1) {
1424  for (auto pit = ginfo->procMap.begin(); pit != ginfo->procMap.end(); ++pit) {
1425  ParseAPI::Function * func = pit->second->func;
1426  const ParseAPI::Function::edgelist & elist = func->callEdges();
1427 
1428  for (auto eit = elist.begin(); eit != elist.end(); ++eit) {
1429  VMA src = (*eit)->src()->last();
1430  VMA targ = (*eit)->trg()->start();
1431  callMap[targ] = src;
1432  }
1433  }
1434  }
1435 
1436  // one binutils proc may contain several parseapi funcs
1437  long num = 0;
1438  for (auto pit = ginfo->procMap.begin(); pit != ginfo->procMap.end(); ++pit) {
1439  ProcInfo * pinfo = pit->second;
1440  ParseAPI::Function * func = pinfo->func;
1441  Address entry_addr = func->addr();
1442  num++;
1443 
1444  // only used for cuda functions
1445  pinfo->symbol_index = 0;
1446 
1447  // compute the inline seqn for the call site for this func, if
1448  // there is one.
1450  auto call_it = callMap.find(entry_addr);
1451 
1452  if (call_it != callMap.end()) {
1453  analyzeAddr(prefix, call_it->second, env.realPath);
1454  }
1455 
1456 #if DEBUG_CFG_SOURCE
1457  debugFuncHeader(finfo, pinfo, num, num_funcs);
1458 
1459  if (call_it != callMap.end()) {
1460  cout << "\ncall site prefix: 0x" << hex << call_it->second
1461  << " -> 0x" << call_it->first << dec << "\n";
1462  for (auto pit = prefix.begin(); pit != prefix.end(); ++pit) {
1463  cout << "inline: l=" << pit->getLineNum()
1464  << " f='" << pit->getFileName()
1465  << "' p='" << debugPrettyName(pit->getPrettyName()) << "'\n";
1466  }
1467  }
1468 #endif
1469 
1470  // see if this function is entirely contained within another
1471  // function (as determined by its entry block). if yes, then we
1472  // don't parse the func. but we still use its blocks for gaps,
1473  // unless we've already added the containing func.
1474  //
1475  int num_contain = func->entry()->containingFuncs();
1476  bool add_blocks = true;
1477 
1478  if (num_contain > 1) {
1479  vector <ParseAPI::Function *> funcVec;
1480  func->entry()->getFuncs(funcVec);
1481 
1482  // see if we've already added the containing func
1483  for (auto fit = funcVec.begin(); fit != funcVec.end(); ++fit) {
1484  Address entry = (*fit)->addr();
1485 
1486  if (coveredFuncs.find(entry) != coveredFuncs.end()) {
1487  add_blocks = false;
1488  break;
1489  }
1490  }
1491  }
1492 
1493  // skip duplicated function, blocks already added
1494  if (! add_blocks) {
1495  DEBUG_CFG("\nskipping duplicated function: '" << func->name() << "'\n");
1496  continue;
1497  }
1498 
1499  // basic blocks for this function. put into a vector and sort by
1500  // start VMA for deterministic output.
1501  vector <Block *> bvec;
1502  BlockSet visited;
1503 
1504  const ParseAPI::Function::blocklist & blist = func->blocks();
1505 
1506  for (auto bit = blist.begin(); bit != blist.end(); ++bit) {
1507  Block * block = *bit;
1508  bvec.push_back(block);
1509  visited[block] = false;
1510  }
1511 
1512  std::sort(bvec.begin(), bvec.end(), BlockLessThan);
1513 
1514  // add to the group's set of covered blocks
1515  if (! ginfo->alt_file) {
1516  for (auto bit = bvec.begin(); bit != bvec.end(); ++bit) {
1517  Block * block = *bit;
1518  covered.insert(block->start(), block->end());
1519  }
1520  coveredFuncs.insert(entry_addr);
1521  }
1522 
1523  // skip duplicated function, blocks added just now
1524  if (num_contain > 1) {
1525  DEBUG_CFG("\nskipping duplicated function: '" << func->name() << "'\n");
1526  continue;
1527  }
1528 
1529  // if the outline func file name does not match the enclosing
1530  // symtab func, then do the full parse in the outline file
1531  // (alt-file) and use the symtab file for gaps only.
1532  if (pinfo->gap_only) {
1533  DEBUG_CFG("\nskipping full parse (gap only) for function: '"
1534  << func->name() << "'\n");
1535  continue;
1536  }
1537 
1538  TreeNode * root = new TreeNode;
1539 
1540  // traverse the loop (Tarjan) tree
1541  LoopList *llist =
1542  doLoopTree(env, finfo, ginfo, func, visited, func->getLoopTree());
1543 
1544  DEBUG_CFG("\nnon-loop blocks:\n");
1545 
1546  // process any blocks not in a loop
1547  for (auto bit = bvec.begin(); bit != bvec.end(); ++bit) {
1548  Block * block = *bit;
1549  if (! visited[block]) {
1550  doBlock(env, ginfo, func, visited, block, root);
1551  }
1552  }
1553 
1554  // merge the loops into the proc's inline tree
1555  FLPSeqn empty;
1556 
1557  for (auto it = llist->begin(); it != llist->end(); ++it) {
1558  mergeInlineLoop(root, empty, *it);
1559  }
1560 
1561  // delete the inline prefix from this func, if non-empty
1562  if (! prefix.empty()) {
1563  root = deleteInlinePrefix(env, root, prefix);
1564  }
1565 
1566  // add inline tree to proc info
1567  pinfo->root = root;
1568 
1569 #if DEBUG_CFG_SOURCE
1570  cout << "\nfinal inline tree: (" << num << "/" << num_funcs << ")"
1571  << " link='" << pinfo->linkName << "'\n"
1572  << "parse: '" << func->name() << "'\n";
1573 
1574  if (call_it != callMap.end()) {
1575  cout << "\ncall site prefix: 0x" << hex << call_it->second
1576  << " -> 0x" << call_it->first << dec << "\n";
1577  for (auto pit = prefix.begin(); pit != prefix.end(); ++pit) {
1578  cout << "inline: l=" << pit->getLineNum()
1579  << " f='" << pit->getFileName()
1580  << "' p='" << debugPrettyName(pit->getPrettyName()) << "'\n";
1581  }
1582  }
1583  cout << "\n";
1584  debugInlineTree(root, NULL, *(env.strTab), 0, true);
1585  cout << "\nend proc: (" << num << "/" << num_funcs << ")"
1586  << " link='" << pinfo->linkName << "'\n"
1587  << "parse: '" << func->name() << "'\n";
1588 #endif
1589  }
1590 
1591  // add unclaimed regions (gaps) to the group leader, but skip groups
1592  // in an alternate file (handled in orig file).
1593  if (! ginfo->alt_file) {
1594  computeGaps(covered, ginfo->gapSet, ginfo->start, ginfo->end);
1595 
1596  if (! fullGaps) {
1597  addGaps(env, finfo, ginfo);
1598  }
1599  }
1600 
1601 #if DEBUG_SHOW_GAPS
1602  auto pit = ginfo->procMap.begin();
1603  ProcInfo * pinfo = pit->second;
1604 
1605  cout << "\nfunc: 0x" << hex << pinfo->entry_vma << dec
1606  << " (1/" << num_funcs << ")\n"
1607  << "link: " << pinfo->linkName << "\n"
1608  << "parse: " << pinfo->func->name() << "\n"
1609  << "0x" << hex << ginfo->start
1610  << "--0x" << ginfo->end << dec << "\n";
1611 
1612  if (! ginfo->alt_file) {
1613  cout << "\ncovered:\n"
1614  << covered.toString() << "\n"
1615  << "\ngaps:\n"
1616  << ginfo->gapSet.toString() << "\n";
1617  }
1618  else {
1619  cout << "\ngaps: alt-file\n";
1620  }
1621 #endif
1622 }
1623 
1624 //----------------------------------------------------------------------
1625 
1626 // Returns: list of LoopInfo objects.
1627 //
1628 // If the loop at this node is non-null (internal node), then the list
1629 // contains one element for that loop. If the loop is null (root),
1630 // then the list contains one element for each subtree.
1631 //
1632 static LoopList *
1633 doLoopTree(WorkEnv & env, FileInfo * finfo, GroupInfo * ginfo,
1634  ParseAPI::Function * func, BlockSet & visited, LoopTreeNode * ltnode)
1635 {
1636  LoopList * myList = new LoopList;
1637 
1638  if (ltnode == NULL) {
1639  return myList;
1640  }
1641  Loop *loop = ltnode->loop;
1642 
1643  // process the children of the loop tree
1644  vector <LoopTreeNode *> clist = ltnode->children;
1645 
1646  std::sort(clist.begin(), clist.end(), LoopTreeLessThan);
1647 
1648  for (uint i = 0; i < clist.size(); i++) {
1649  LoopList *subList =
1650  doLoopTree(env, finfo, ginfo, func, visited, clist[i]);
1651 
1652  for (auto sit = subList->begin(); sit != subList->end(); ++sit) {
1653  myList->push_back(*sit);
1654  }
1655  delete subList;
1656  }
1657 
1658  // if no loop at this node (root node), then return the list of
1659  // children.
1660  if (loop == NULL) {
1661  return myList;
1662  }
1663 
1664  // otherwise, finish this loop, put into LoopInfo format, insert the
1665  // subloops and return a list of one.
1666  string loopName = ltnode->name();
1667  FLPSeqn empty;
1668 
1669  TreeNode * myLoop =
1670  doLoopLate(env, ginfo, func, visited, loop, loopName);
1671 
1672  for (auto it = myList->begin(); it != myList->end(); ++it) {
1673  mergeInlineLoop(myLoop, empty, *it);
1674  }
1675 
1676  // reparent the tree and put into LoopInfo format
1677  LoopInfo * myInfo =
1678  findLoopHeader(env, finfo, ginfo, func, myLoop, loop, loopName);
1679 
1680  if (merge_irred_loops) {
1681  mergeIrredLoops(env, myInfo);
1682  }
1683 
1684  myList->clear();
1685  myList->push_back(myInfo);
1686 
1687  return myList;
1688 }
1689 
1690 //----------------------------------------------------------------------
1691 
1692 // Post-order process for one loop, after the subloops. Add any
1693 // leftover inclusive blocks, select the loop header, reparent as
1694 // needed, remove the top inline spine, and put into the LoopInfo
1695 // format.
1696 //
1697 // Returns: the raw inline tree for this loop.
1698 //
1699 static TreeNode *
1700 doLoopLate(WorkEnv & env, GroupInfo * ginfo, ParseAPI::Function * func,
1701  BlockSet & visited, Loop * loop, const string & loopName)
1702 {
1703  TreeNode * root = new TreeNode;
1704 
1705  DEBUG_CFG("\nbegin loop: " << loopName << " '" << func->name() << "'\n");
1706 
1707  // add the inclusive blocks not contained in a subloop
1708  vector <Block *> bvec;
1709  loop->getLoopBasicBlocks(bvec);
1710 
1711  std::sort(bvec.begin(), bvec.end(), BlockLessThan);
1712 
1713  for (uint i = 0; i < bvec.size(); i++) {
1714  if (! visited[bvec[i]]) {
1715  doBlock(env, ginfo, func, visited, bvec[i], root);
1716  }
1717  }
1718 
1719  return root;
1720 }
1721 
1722 //----------------------------------------------------------------------
1723 
1724 // Process one basic block.
1725 //
1726 static void
1727 doBlock(WorkEnv & env, GroupInfo * ginfo, ParseAPI::Function * func,
1728  BlockSet & visited, Block * block, TreeNode * root)
1729 {
1730  if (block == NULL || visited[block]) {
1731  return;
1732  }
1733  visited[block] = true;
1734 
1735  DEBUG_CFG("\nblock:\n");
1736 
1737  LineMapCache lmcache (ginfo->sym_func, env.realPath);
1738 
1739  // iterate through the instructions in this block
1740 #ifdef DYNINST_INSTRUCTION_PTR
1741  map <Offset, Instruction::Ptr> imap;
1742 #else
1743  map <Offset, Instruction> imap;
1744 #endif
1745  block->getInsns(imap);
1746 
1747  for (auto iit = imap.begin(); iit != imap.end(); ++iit) {
1748  Offset vma = iit->first;
1749  string filenm = "";
1750  uint line = 0;
1751 
1752 #ifdef DYNINST_INSTRUCTION_PTR
1753  int len = iit->second->size();
1754 #else
1755  int len = iit->second.size();
1756 #endif
1757 
1758  lmcache.getLineInfo(vma, filenm, line);
1759 
1760 #if DEBUG_CFG_SOURCE
1761  debugStmt(vma, len, filenm, line, env.realPath);
1762 #endif
1763 
1764  addStmtToTree(root, *(env.strTab), env.realPath, vma, len, filenm, line);
1765  }
1766 
1767 #if DEBUG_CFG_SOURCE
1768  debugEdges(block);
1769 #endif
1770 }
1771 
1772 //----------------------------------------------------------------------
1773 
1774 // CUDA functions
1775 //
1776 static void
1777 doCudaList(WorkEnv & env, FileInfo * finfo, GroupInfo * ginfo)
1778 {
1779  // not sure if cuda generates multiple functions, but we'll handle
1780  // this case until proven otherwise.
1781  long num = 0;
1782  for (auto pit = ginfo->procMap.begin(); pit != ginfo->procMap.end(); ++pit) {
1783  ProcInfo * pinfo = pit->second;
1784  ParseAPI::Function * func = pinfo->func;
1785  num++;
1786 
1787 #if DEBUG_CFG_SOURCE
1788  long num_funcs = ginfo->procMap.size();
1789  debugFuncHeader(finfo, pinfo, num, num_funcs, "cuda");
1790 #endif
1791 
1792  TreeNode * root = new TreeNode;
1793 
1794  doCudaFunction(env, ginfo, func, root);
1795 
1796  pinfo->root = root;
1797 
1798 #if DEBUG_CFG_SOURCE
1799  cout << "\nfinal cuda tree: '" << pinfo->linkName << "'\n\n";
1800  debugInlineTree(root, NULL, *(env.strTab), 0, true);
1801 #endif
1802  }
1803 }
1804 
1805 //----------------------------------------------------------------------
1806 
1807 // Process one cuda function.
1808 //
1809 // We don't have cuda instruction parsing (yet), so just one flat
1810 // block per function and no loops.
1811 //
1812 static void
1813 doCudaFunction(WorkEnv & env, GroupInfo * ginfo, ParseAPI::Function * func,
1814  TreeNode * root)
1815 {
1816  LineMapCache lmcache (ginfo->sym_func, env.realPath);
1817 
1818  DEBUG_CFG("\ncuda blocks:\n");
1819 
1820  int len = 4;
1821  for (Offset vma = ginfo->start; vma < ginfo->end; vma += len) {
1822  string filenm = "";
1823  uint line = 0;
1824 
1825  lmcache.getLineInfo(vma, filenm, line);
1826 
1827 #if DEBUG_CFG_SOURCE
1828  debugStmt(vma, len, filenm, line, env.realPath);
1829 #endif
1830 
1831  addStmtToTree(root, *(env.strTab), env.realPath, vma, len, filenm, line);
1832  }
1833 }
1834 
1835 //----------------------------------------------------------------------
1836 
1837 // Add unclaimed regions (gaps) to the group leader.
1838 //
1839 // This is the basic version -- if line map exists, add a top-level
1840 // stmt to the func for each line map range, else assign to the first
1841 // line of func. The full version is handled in Struct-Output.cpp.
1842 //
1843 static void
1844 addGaps(WorkEnv & env, FileInfo * finfo, GroupInfo * ginfo)
1845 {
1846  if (ginfo->procMap.begin() == ginfo->procMap.end()) {
1847  return;
1848  }
1849 
1850  ProcInfo * pinfo = ginfo->procMap.begin()->second;
1851 
1852  // if one function is entirely contained within another function,
1853  // then it's possible that ProcInfo has no statements and a NULL
1854  // TreeNode.
1855  if (pinfo->root == NULL) {
1856  pinfo->root = new TreeNode;
1857  }
1858  TreeNode * root = pinfo->root;
1859 
1860  for (auto git = ginfo->gapSet.begin(); git != ginfo->gapSet.end(); ++git) {
1861  VMA vma = git->beg();
1862  VMA end_gap = git->end();
1863 
1864  while (vma < end_gap) {
1865  StatementVector svec;
1866  getStatement(svec, vma, ginfo->sym_func);
1867 
1868  if (! svec.empty()) {
1869  string filenm = svec[0]->getFile();
1870  SrcFile::ln line = svec[0]->getLine();
1871  VMA end = std::min(((VMA) svec[0]->endAddr()), end_gap);
1872 
1873  addStmtToTree(root, *(env.strTab), env.realPath, vma, end - vma, filenm, line);
1874  vma = end;
1875  }
1876  else {
1877  // fixme: could be better at finding end of range
1878  VMA end = std::min(vma + 4, end_gap);
1879 
1880  addStmtToTree(root, *(env.strTab), env.realPath, vma, end - vma,
1881  finfo->fileName, pinfo->line_num);
1882  vma = end;
1883  }
1884  }
1885  }
1886 }
1887 
1888 //****************************************************************************
1889 // Support functions
1890 //****************************************************************************
1891 
1892 // New heuristic for identifying loop header inside inline tree.
1893 // Start at the root, descend the inline tree and try to find where
1894 // the loop begins. This is the central problem of all hpcstruct:
1895 // where to locate a loop inside an inline sequence.
1896 //
1897 // Note: loop "headers" are no longer tied to a specific VMA and
1898 // machine instruction. They are strictly file and line number.
1899 // (For some loops, there is no right VMA.)
1900 //
1901 // Returns: detached LoopInfo object.
1902 //
1903 static LoopInfo *
1904 findLoopHeader(WorkEnv & env, FileInfo * finfo, GroupInfo * ginfo,
1905  ParseAPI::Function * func, TreeNode * root, Loop * loop,
1906  const string & loopName)
1907 {
1908  HPC::StringTable * strTab = env.strTab;
1909  long empty_index = strTab->str2index("");
1910 
1911  //------------------------------------------------------------
1912  // Step 1 -- build the list of loop exit conditions
1913  //------------------------------------------------------------
1914 
1915  vector <Block *> inclBlocks;
1916  set <Block *> bset;
1917  HeaderList clist;
1918 
1919  loop->getLoopBasicBlocks(inclBlocks);
1920  for (auto bit = inclBlocks.begin(); bit != inclBlocks.end(); ++bit) {
1921  bset.insert(*bit);
1922  }
1923 
1924  // a stmt is a loop exit condition if it has outgoing edges to
1925  // blocks both inside and outside the loop. but don't include call
1926  // edges. (don't need to sort blocks and edges here because the
1927  // real answer is clist and clist is a map.)
1928  //
1929  for (auto bit = inclBlocks.begin(); bit != inclBlocks.end(); ++bit) {
1930  Block * block = *bit;
1931  const Block::edgelist & outEdges = block->targets();
1932  VMA src_vma = block->last();
1933  bool in_loop = false, out_loop = false;
1934 
1935  for (auto eit = outEdges.begin(); eit != outEdges.end(); ++eit) {
1936  Block *dest = (*eit)->trg();
1937  int type = (*eit)->type();
1938 
1939  if (type != ParseAPI::CALL && type != ParseAPI::CALL_FT) {
1940  if (bset.find(dest) != bset.end()) { in_loop = true; }
1941  else { out_loop = true; }
1942  }
1943  }
1944 
1945  if (in_loop && out_loop) {
1946  string filenm = "";
1947  SrcFile::ln line = 0;
1948 
1949  StatementVector svec;
1950  getStatement(svec, src_vma, ginfo->sym_func);
1951 
1952  if (! svec.empty()) {
1953  filenm = svec[0]->getFile();
1954  line = svec[0]->getLine();
1955  env.realPath->realpath(filenm);
1956  }
1957 
1958  InlineSeqn seqn;
1959  analyzeAddr(seqn, src_vma, env.realPath);
1960 
1961  clist[src_vma] = HeaderInfo(block);
1962  clist[src_vma].is_excl = loop->hasBlockExclusive(block);
1963  clist[src_vma].depth = seqn.size();
1964  clist[src_vma].file_index = strTab->str2index(filenm);
1965  clist[src_vma].base_index = strTab->str2index(FileUtil::basename(filenm));
1966  clist[src_vma].line_num = line;
1967  }
1968  }
1969 
1970  // see if stmt is also a back edge source. (we sort the back edges
1971  // only for debug output.)
1972  vector <Edge *> backEdges;
1973  loop->getBackEdges(backEdges);
1974 
1975  std::sort(backEdges.begin(), backEdges.end(), EdgeLessThan);
1976 
1977  for (auto eit = backEdges.begin(); eit != backEdges.end(); ++eit) {
1978  VMA src_vma = (*eit)->src()->last();
1979 
1980  auto it = clist.find(src_vma);
1981  if (it != clist.end()) {
1982  it->second.is_src = true;
1983  }
1984  }
1985 
1986 #if DEBUG_CFG_SOURCE
1987  cout << "\nraw inline tree: " << loopName
1988  << " '" << func->name() << "'\n"
1989  << "file: '" << finfo->fileName << "'\n\n";
1990  debugInlineTree(root, NULL, *strTab, 0, false);
1991  debugLoop(ginfo, func, loop, loopName, backEdges, clist, env.realPath);
1992  cout << "\nsearching inline tree:\n";
1993 #endif
1994 
1995  //------------------------------------------------------------
1996  // Step 2 -- find the right inline depth
1997  //------------------------------------------------------------
1998 
1999  // start at the root, descend the inline tree and try to find the
2000  // right level for the loop. an inline branch or subloop is an
2001  // absolute stopping point. the hard case is one inline subtree
2002  // plus statements. we stop if there is a loop condition, else
2003  // continue and reparent the stmts. always reparent any stmt in a
2004  // different file from the inline callsite.
2005 
2006  FLPSeqn path;
2007  StmtMap stmts;
2008  int depth_root = 0;
2009 
2010  while (root->nodeMap.size() == 1 && root->loopList.size() == 0) {
2011  FLPIndex flp = root->nodeMap.begin()->first;
2012 
2013  // look for loop cond at this level
2014  for (auto cit = clist.begin(); cit != clist.end(); ++cit) {
2015  VMA vma = cit->first;
2016 
2017  if (root->stmtMap.member(vma)) {
2018  goto found_level;
2019  }
2020 
2021  // reparented stmts must also match file name
2022  StmtInfo * sinfo = stmts.findStmt(vma);
2023  if (sinfo != NULL && sinfo->base_index == flp.base_index) {
2024  goto found_level;
2025  }
2026  }
2027 
2028  // reparent the stmts and proceed to the next level
2029  for (auto sit = root->stmtMap.begin(); sit != root->stmtMap.end(); ++sit) {
2030  stmts.insert(sit->second);
2031  }
2032  root->stmtMap.clear();
2033 
2034  TreeNode *subtree = root->nodeMap.begin()->second;
2035  root->nodeMap.clear();
2036  delete root;
2037  root = subtree;
2038  path.push_back(flp);
2039  depth_root++;
2040 
2041  DEBUG_CFG("inline: l=" << flp.line_num
2042  << " f='" << strTab->index2str(flp.file_index)
2043  << "' p='" << debugPrettyName(strTab->index2str(flp.pretty_index))
2044  << "'\n");
2045  }
2046 found_level:
2047 
2048 #if DEBUG_CFG_SOURCE
2049  if (root->nodeMap.size() > 0) {
2050  cout << "\nremaining inline subtrees:\n";
2051 
2052  for (auto nit = root->nodeMap.begin(); nit != root->nodeMap.end(); ++nit) {
2053  FLPIndex flp = nit->first;
2054  cout << "inline: l=" << flp.line_num
2055  << " f='" << strTab->index2str(flp.file_index)
2056  << "' p='" << debugPrettyName(strTab->index2str(flp.pretty_index))
2057  << "'\n";
2058  }
2059  }
2060 #endif
2061 
2062  //------------------------------------------------------------
2063  // Step 3 -- reattach stmts into this level
2064  //------------------------------------------------------------
2065 
2066  // fixme: want to attach some stmts below this level
2067 
2068  for (auto sit = stmts.begin(); sit != stmts.end(); ++sit) {
2069  root->stmtMap.insert(sit->second);
2070  }
2071  stmts.clear();
2072 
2073  //------------------------------------------------------------
2074  // Step 4 -- choose a loop header file/line at this level
2075  //------------------------------------------------------------
2076 
2077  // choose loop header file based on exit conditions, and then min
2078  // line within that file. ideally, we want a file that is both an
2079  // exit cond and matches some other anchor: either the enclosing
2080  // func (if top-level), or else an inline subtree.
2081 
2082  long proc_file = strTab->str2index(finfo->fileName);
2083  long proc_base = strTab->str2index(FileUtil::basename(finfo->fileName));
2084  long file_ans = empty_index;
2085  long base_ans = empty_index;
2086  long line_ans = 0;
2087 
2088  // first choice is the file for the enclosing func that matches some
2089  // exit cond at top-level, but only if no inline steps
2090  if (depth_root == 0) {
2091  for (auto cit = clist.begin(); cit != clist.end(); ++cit) {
2092  HeaderInfo * info = &(cit->second);
2093 
2094  if (info->depth == depth_root && info->base_index != empty_index
2095  && info->base_index == proc_base) {
2096  file_ans = proc_file;
2097  base_ans = proc_base;
2098  goto found_file;
2099  }
2100  }
2101  }
2102 
2103  // also good is an inline subtree that matches an exit cond
2104  for (auto nit = root->nodeMap.begin(); nit != root->nodeMap.end(); ++nit) {
2105  FLPIndex flp = nit->first;
2106 
2107  for (auto cit = clist.begin(); cit != clist.end(); ++cit) {
2108  HeaderInfo * info = &(cit->second);
2109 
2110  if (info->depth == depth_root && info->base_index != empty_index
2111  && info->base_index == flp.base_index) {
2112  file_ans = flp.file_index;
2113  base_ans = flp.base_index;
2114  goto found_file;
2115  }
2116  }
2117  }
2118 
2119  // settle for any exit cond at root level. this is the last of the
2120  // good answers.
2121  for (auto cit = clist.begin(); cit != clist.end(); ++cit) {
2122  HeaderInfo * info = &(cit->second);
2123 
2124  if (info->depth == depth_root && info->base_index != empty_index) {
2125  file_ans = info->file_index;
2126  base_ans = info->base_index;
2127  goto found_file;
2128  }
2129  }
2130 
2131  // enclosing func file, but without exit cond
2132  if (depth_root == 0 && proc_file != empty_index) {
2133  file_ans = proc_file;
2134  base_ans = proc_base;
2135  goto found_file;
2136  }
2137 
2138  // inline subtree, but without exit cond
2139  for (auto nit = root->nodeMap.begin(); nit != root->nodeMap.end(); ++nit) {
2140  FLPIndex flp = nit->first;
2141 
2142  if (flp.file_index != empty_index) {
2143  file_ans = flp.file_index;
2144  base_ans = flp.base_index;
2145  goto found_file;
2146  }
2147  }
2148 
2149  // subloop at root level
2150  for (auto lit = root->loopList.begin(); lit != root->loopList.end(); ++lit) {
2151  LoopInfo * linfo = *lit;
2152 
2153  if (linfo->file_index != empty_index) {
2154  file_ans = linfo->file_index;
2155  base_ans = linfo->base_index;
2156  goto found_file;
2157  }
2158  }
2159 
2160  // any stmt at root level
2161  for (auto sit = root->stmtMap.begin(); sit != root->stmtMap.end(); ++sit) {
2162  StmtInfo * sinfo = sit->second;
2163 
2164  if (sinfo->file_index != empty_index) {
2165  file_ans = sinfo->file_index;
2166  base_ans = sinfo->base_index;
2167  line_ans = sinfo->line_num;
2168  break;
2169  }
2170  }
2171 found_file:
2172 
2173  // min line of inline callsites
2174  // fixme: code motion breaks this
2175 #if 0
2176  for (auto nit = root->nodeMap.begin(); nit != root->nodeMap.end(); ++nit) {
2177  FLPIndex flp = nit->first;
2178 
2179  if (flp.base_index == base_ans
2180  && (line_ans == 0 || (flp.line_num > 0 && flp.line_num < line_ans))) {
2181  line_ans = flp.line_num;
2182  }
2183  }
2184 #endif
2185 
2186  // min line of subloops
2187  for (auto lit = root->loopList.begin(); lit != root->loopList.end(); ++lit) {
2188  LoopInfo * linfo = *lit;
2189 
2190  if (linfo->base_index == base_ans
2191  && (line_ans == 0 || (linfo->line_num > 0 && linfo->line_num < line_ans))) {
2192  line_ans = linfo->line_num;
2193  }
2194  }
2195 
2196  // min line of exit cond stmts at root level
2197  for (auto cit = clist.begin(); cit != clist.end(); ++cit) {
2198  HeaderInfo * info = &(cit->second);
2199 
2200  if (info->depth == depth_root
2201  && (line_ans == 0 || (info->line_num > 0 && info->line_num < line_ans))) {
2202  line_ans = info->line_num;
2203  }
2204  }
2205 
2206  DEBUG_CFG("\nheader: l=" << line_ans << " f='"
2207  << strTab->index2str(file_ans) << "'\n");
2208 
2209  vector <Block *> entryBlocks;
2210  loop->getLoopEntries(entryBlocks);
2211  VMA entry_vma = VMA_MAX;
2212 
2213  for (auto bit = entryBlocks.begin(); bit != entryBlocks.end(); ++bit) {
2214  entry_vma = std::min(entry_vma, (*bit)->start());
2215  }
2216 
2217  LoopInfo *info = new LoopInfo(root, path, loopName, entry_vma,
2218  file_ans, base_ans, line_ans,
2219  entryBlocks.size() > 1);
2220 
2221 #if DEBUG_CFG_SOURCE
2222  cout << "\nreparented inline tree: " << loopName
2223  << " '" << func->name() << "'\n\n";
2224  debugInlineTree(root, info, *strTab, 0, false);
2225 #endif
2226 
2227  return info;
2228 }
2229 
2230 //----------------------------------------------------------------------
2231 
2232 // Delete the inline sequence 'prefix' from root's tree and reparent
2233 // any statements or loops. We expect there to be no statements,
2234 // loops or subtrees along the deleted spine, but if there are, move
2235 // them to the subtree.
2236 //
2237 // Returns: the subtree at the end of prefix.
2238 //
2239 static TreeNode *
2241 {
2242  StmtMap stmts;
2243  LoopList loops;
2244 
2245  // walk the prefix and collect any stmts or loops
2246  for (auto pit = prefix.begin(); pit != prefix.end(); ++pit)
2247  {
2248  FLPIndex flp(*(env.strTab), *pit);
2249  auto nit = root->nodeMap.find(flp);
2250 
2251  if (nit != root->nodeMap.end()) {
2252  TreeNode * subtree = nit->second;
2253 
2254  // statements
2255  for (auto sit = root->stmtMap.begin(); sit != root->stmtMap.end(); ++sit) {
2256  stmts.insert(sit->second);
2257  }
2258  root->stmtMap.clear();
2259 
2260  // loops
2261  for (auto lit = root->loopList.begin(); lit != root->loopList.end(); ++lit) {
2262  loops.push_back(*lit);
2263  }
2264  root->loopList.clear();
2265 
2266  // subtrees
2267  for (auto it = root->nodeMap.begin(); it != root->nodeMap.end(); ++it) {
2268  TreeNode * node = it->second;
2269  if (node != subtree) {
2270  mergeInlineEdge(subtree, it->first, node);
2271  }
2272  }
2273  root->nodeMap.clear();
2274  delete root;
2275 
2276  root = subtree;
2277  }
2278  }
2279 
2280  // reattach the stmts and loops
2281  for (auto sit = stmts.begin(); sit != stmts.end(); ++sit) {
2282  root->stmtMap.insert(sit->second);
2283  }
2284  stmts.clear();
2285 
2286  for (auto lit = loops.begin(); lit != loops.end(); ++lit) {
2287  root->loopList.push_back(*lit);
2288  }
2289  loops.clear();
2290 
2291  return root;
2292 }
2293 
2294 //----------------------------------------------------------------------
2295 
2296 // Merge irreducible loops. If L1 is an irreducible loop and L2 is an
2297 // irreducible subloop and L1 and L2 have the same file and line
2298 // attribution, then it's likely there is really only one loop in the
2299 // source code, so merge L2 into L1.
2300 //
2301 // This only applies to irreducible loops. Natural (reducible) loops
2302 // are assumed to be correct.
2303 //
2304 static void
2306 {
2307  // if L1 is reducible, then do nothing
2308  if (L1 == NULL || ! L1->irred) {
2309  return;
2310  }
2311 
2312  TreeNode * node1 = L1->node;
2313  LoopList & list1 = node1->loopList;
2314 
2315  // if there are no irreducible subloops, then do nothing
2316  bool has_irred = false;
2317  for (auto it = list1.begin(); it != list1.end(); ++it) {
2318  LoopInfo * L2 = *it;
2319  if (L2->irred) { has_irred = true; break; }
2320  }
2321  if (! has_irred) {
2322  return;
2323  }
2324 
2325  DEBUG_CFG("\n");
2326 
2327  // iterate through L1's subloops and merge L2 into L1 when they
2328  // match. merging requires moving L2's subloops onto L1's list, the
2329  // very list we are iterating through. to maintain correctness, put
2330  // the loops on a new list and copy them back.
2331 
2332  vector <LoopInfo *> newList;
2333 
2334  for (auto it1 = list1.begin(); it1 != list1.end(); ++it1) {
2335  LoopInfo * L2 = *it1;
2336  TreeNode * node2 = L2->node;
2337  LoopList & list2 = node2->loopList;
2338 
2339  if (L2->irred && L1->base_index == L2->base_index && L1->line_num == L2->line_num)
2340  {
2341  // merge L2 into L1 and put L2's subloops on the new list
2342  DEBUG_CFG("merge: " << L2->name << " into " << L1->name << "\n");
2343 
2344  for (auto it2 = list2.begin(); it2 != list2.end(); ++it2) {
2345  newList.push_back(*it2);
2346  }
2347  list2.clear();
2348  mergeInlineTree(node1, node2);
2349  delete L2;
2350  }
2351  else {
2352  // do not merge, keep entire L2 intact on new list
2353  newList.push_back(L2);
2354  }
2355  }
2356 
2357  std::sort(newList.begin(), newList.end(), LoopInfoLessThan);
2358 
2359  // copy new list back to L1
2360  list1.clear();
2361  for (auto nit = newList.begin(); nit != newList.end(); ++nit) {
2362  list1.push_back(*nit);
2363  }
2364  newList.clear();
2365 
2366 #if DEBUG_CFG_SOURCE
2367  cout << "\n";
2368  debugInlineTree(node1, L1, *(env.strTab), 0, false);
2369 #endif
2370 }
2371 
2372 //----------------------------------------------------------------------
2373 
2374 // Compute gaps = the set of intervals in [start, end) that are not
2375 // covered in vset.
2376 //
2377 static void
2378 computeGaps(VMAIntervalSet & vset, VMAIntervalSet & gaps, VMA start, VMA end)
2379 {
2380  gaps.clear();
2381 
2382  auto it = vset.begin();
2383 
2384  while (start < end)
2385  {
2386  if (it == vset.end()) {
2387  gaps.insert(start, end);
2388  break;
2389  }
2390  else if (it->end() <= start) {
2391  // it entirely left of start
2392  ++it;
2393  }
2394  else if (it->beg() <= start) {
2395  // it contains start
2396  start = it->end();
2397  ++it;
2398  }
2399  else {
2400  // it entirely right of start
2401  VMA gap_end = std::min(it->beg(), end);
2402  gaps.insert(start, gap_end);
2403  start = it->end();
2404  ++it;
2405  }
2406  }
2407 }
2408 
2409 //****************************************************************************
2410 // Debug functions
2411 //****************************************************************************
2412 
2413 #if DEBUG_ANY_ON
2414 
2415 // Debug functions to display the raw input data from ParseAPI for
2416 // loops, blocks, stmts, file names, proc names and line numbers.
2417 
2418 #define INDENT " "
2419 
2420 // Cleanup and shorten the proc name: demangle plus collapse nested
2421 // <...> and (...) to just <> and (). For example:
2422 //
2423 // std::map<int,long>::myfunc(int) --> std::map<>::myfunc()
2424 //
2425 // This is only for more compact debug output. Internal decisions are
2426 // always made on the full string.
2427 //
2428 static string
2429 debugPrettyName(const string & procnm)
2430 {
2431  string str = procnm;
2432  string ans = "";
2433  size_t str_len = str.size();
2434  size_t pos = 0;
2435 
2436  while (pos < str_len) {
2437  size_t next = str.find_first_of("<(", pos);
2438  char open, close;
2439 
2440  if (next == string::npos) {
2441  ans += str.substr(pos);
2442  break;
2443  }
2444  if (str[next] == '<') { open = '<'; close = '>'; }
2445  else { open = '('; close = ')'; }
2446 
2447  ans += str.substr(pos, next - pos) + open + close;
2448 
2449  int depth = 1;
2450  for (pos = next + 1; pos < str_len && depth > 0; pos++) {
2451  if (str[pos] == open) { depth++; }
2452  else if (str[pos] == close) { depth--; }
2453  }
2454  }
2455 
2456  return ans;
2457 }
2458 
2459 //----------------------------------------------------------------------
2460 
2461 static void
2462 debugElfHeader(ElfFile * elfFile)
2463 {
2464  size_t len = elfFile->getLength();
2465 
2466  cout << "\n============================================================\n"
2467  << "Elf File: " << elfFile->getFileName() << "\n"
2468  << "length: 0x" << hex << len << dec << " (" << len << ")\n"
2469  << "============================================================\n";
2470 }
2471 
2472 //----------------------------------------------------------------------
2473 
2474 static void
2475 debugFuncHeader(FileInfo * finfo, ProcInfo * pinfo, long num, long num_funcs,
2476  string label)
2477 {
2478  ParseAPI::Function * func = pinfo->func;
2479  Address entry_addr = func->addr();
2480 
2481  cout << "\n------------------------------------------------------------\n";
2482 
2483  if (label != "") { cout << label << " "; }
2484 
2485  cout << "func: 0x" << hex << entry_addr << dec
2486  << " (" << num << "/" << num_funcs << ")"
2487  << " link='" << pinfo->linkName << "'\n"
2488  << "parse: '" << func->name() << "'\n"
2489  << "file: '" << finfo->fileName << "'\n";
2490 }
2491 
2492 //----------------------------------------------------------------------
2493 
2494 static void
2495 debugStmt(VMA vma, int len, string & filenm, SrcFile::ln line,
2496  RealPathMgr * realPath)
2497 
2498 {
2499  cout << "stmt: 0x" << hex << vma << dec << " (" << len << ")"
2500  << " l=" << line << " f='" << filenm << "'\n";
2501 
2502  Inline::InlineSeqn nodeList;
2503  Inline::analyzeAddr(nodeList, vma, realPath);
2504 
2505  // list is outermost to innermost
2506  for (auto nit = nodeList.begin(); nit != nodeList.end(); ++nit) {
2507  cout << INDENT << "inline: l=" << nit->getLineNum()
2508  << " f='" << nit->getFileName()
2509  << "' p='" << debugPrettyName(nit->getPrettyName()) << "'\n";
2510  }
2511 }
2512 
2513 //----------------------------------------------------------------------
2514 
2515 static string
2516 edgeType(int type)
2517 {
2518  if (type == ParseAPI::CALL) { return "call"; }
2519  if (type == ParseAPI::COND_TAKEN) { return "cond-take"; }
2520  if (type == ParseAPI::COND_NOT_TAKEN) { return "cond-not"; }
2521  if (type == ParseAPI::INDIRECT) { return "indirect"; }
2522  if (type == ParseAPI::DIRECT) { return "direct"; }
2523  if (type == ParseAPI::FALLTHROUGH) { return "fallthr"; }
2524  if (type == ParseAPI::CATCH) { return "catch"; }
2525  if (type == ParseAPI::CALL_FT) { return "call-ft"; }
2526  if (type == ParseAPI::RET) { return "return"; }
2527  return "unknown";
2528 }
2529 
2530 static void
2531 debugEdges(Block * block)
2532 {
2533  const Block::edgelist & outEdges = block->targets();
2534  vector <Edge *> edgeVec;
2535 
2536  for (auto eit = outEdges.begin(); eit != outEdges.end(); ++eit) {
2537  edgeVec.push_back(*eit);
2538  }
2539  std::sort(edgeVec.begin(), edgeVec.end(), EdgeLessThan);
2540 
2541  cout << "out edges:" << hex;
2542 
2543  for (auto eit = edgeVec.begin(); eit != edgeVec.end(); ++eit) {
2544  Edge * edge = *eit;
2545 
2546  cout << " 0x" << edge->trg()->start()
2547  << " (" << edgeType(edge->type());
2548 
2549  if (edge->interproc()) {
2550  cout << ", interproc";
2551  }
2552  cout << ")";
2553  }
2554 
2555  cout << dec << "\n";
2556 }
2557 
2558 //----------------------------------------------------------------------
2559 
2560 static void
2561 debugAddr(GroupInfo * ginfo, VMA vma, RealPathMgr * realPath)
2562 {
2563  StatementVector svec;
2564  string filenm = "";
2565  SrcFile::ln line = 0;
2566 
2567  getStatement(svec, vma, ginfo->sym_func);
2568 
2569  if (! svec.empty()) {
2570  filenm = svec[0]->getFile();
2571  line = svec[0]->getLine();
2572  realPath->realpath(filenm);
2573  }
2574 
2575  cout << "0x" << hex << vma << dec
2576  << " l=" << line << " f='" << filenm << "'\n";
2577 }
2578 
2579 //----------------------------------------------------------------------
2580 
2581 static void
2582 debugLoop(GroupInfo * ginfo, ParseAPI::Function * func,
2583  Loop * loop, const string & loopName,
2584  vector <Edge *> & backEdges, HeaderList & clist,
2585  RealPathMgr * realPath)
2586 {
2587  vector <Block *> entBlocks;
2588  int num_ents = loop->getLoopEntries(entBlocks);
2589 
2590  std::sort(entBlocks.begin(), entBlocks.end(), BlockLessThan);
2591 
2592  cout << "\nheader info: " << loopName
2593  << ((num_ents == 1) ? " (reducible)" : " (irreducible)")
2594  << " '" << func->name() << "'\n";
2595 
2596  cout << "\nfunc header:\n";
2597  debugAddr(ginfo, func->addr(), realPath);
2598 
2599  cout << "\nentry blocks:" << hex;
2600  for (auto bit = entBlocks.begin(); bit != entBlocks.end(); ++bit) {
2601  cout << " 0x" << (*bit)->start();
2602  }
2603 
2604  cout << "\nback edge sources:";
2605  for (auto eit = backEdges.begin(); eit != backEdges.end(); ++eit) {
2606  cout << " 0x" << (*eit)->src()->last();
2607  }
2608 
2609  cout << "\nback edge targets:";
2610  for (auto eit = backEdges.begin(); eit != backEdges.end(); ++eit) {
2611  cout << " 0x" << (*eit)->trg()->start();
2612  }
2613  cout << dec;
2614 
2615  cout << "\n\nexit conditions:\n";
2616  for (auto cit = clist.begin(); cit != clist.end(); ++cit) {
2617  VMA vma = cit->first;
2618  HeaderInfo * info = &(cit->second);
2619  SrcFile::ln line = 0;
2620  string filenm = "";
2621 
2622  InlineSeqn seqn;
2623  analyzeAddr(seqn, vma, realPath);
2624 
2625  StatementVector svec;
2626  getStatement(svec, vma, ginfo->sym_func);
2627 
2628  if (! svec.empty()) {
2629  filenm = svec[0]->getFile();
2630  line = svec[0]->getLine();
2631  realPath->realpath(filenm);
2632  }
2633 
2634  cout << "0x" << hex << vma << dec
2635  << " " << (info->is_src ? "src " : "cond")
2636  << " excl: " << info->is_excl
2637  << " depth: " << info->depth
2638  << " l=" << line
2639  << " f='" << filenm << "'\n";
2640  }
2641 }
2642 
2643 //----------------------------------------------------------------------
2644 
2645 // If LoopInfo is non-null, then treat 'node' as a detached loop and
2646 // prepend the FLP seqn from 'info' above the tree. Else, 'node' is
2647 // the tree.
2648 //
2649 static void
2650 debugInlineTree(TreeNode * node, LoopInfo * info, HPC::StringTable & strTab,
2651  int depth, bool expand_loops)
2652 {
2653  // treat node as a detached loop with FLP seqn above it.
2654  if (info != NULL) {
2655  depth = 0;
2656  for (auto pit = info->path.begin(); pit != info->path.end(); ++pit) {
2657  for (int i = 1; i <= depth; i++) {
2658  cout << INDENT;
2659  }
2660  FLPIndex flp = *pit;
2661 
2662  cout << "inline: l=" << flp.line_num
2663  << " f='" << strTab.index2str(flp.file_index)
2664  << "' p='" << debugPrettyName(strTab.index2str(flp.pretty_index))
2665  << "'\n";
2666  depth++;
2667  }
2668 
2669  for (int i = 1; i <= depth; i++) {
2670  cout << INDENT;
2671  }
2672  cout << "loop: " << info->name
2673  << (info->irred ? " (irred)" : "")
2674  << " l=" << info->line_num
2675  << " f='" << strTab.index2str(info->file_index) << "'\n";
2676  depth++;
2677  }
2678 
2679  // print the terminal statements
2680  for (auto sit = node->stmtMap.begin(); sit != node->stmtMap.end(); ++sit) {
2681  StmtInfo *sinfo = sit->second;
2682 
2683  for (int i = 1; i <= depth; i++) {
2684  cout << INDENT;
2685  }
2686  cout << "stmt: 0x" << hex << sinfo->vma << dec << " (" << sinfo->len << ")"
2687  << " l=" << sinfo->line_num
2688  << " f='" << strTab.index2str(sinfo->file_index) << "'\n";
2689  }
2690 
2691  // recur on the subtrees
2692  for (auto nit = node->nodeMap.begin(); nit != node->nodeMap.end(); ++nit) {
2693  FLPIndex flp = nit->first;
2694 
2695  for (int i = 1; i <= depth; i++) {
2696  cout << INDENT;
2697  }
2698  cout << "inline: l=" << flp.line_num
2699  << " f='" << strTab.index2str(flp.file_index)
2700  << "' p='" << debugPrettyName(strTab.index2str(flp.pretty_index))
2701  << "'\n";
2702 
2703  debugInlineTree(nit->second, NULL, strTab, depth + 1, expand_loops);
2704  }
2705 
2706  // recur on the loops
2707  for (auto lit = node->loopList.begin(); lit != node->loopList.end(); ++lit) {
2708  LoopInfo *info = *lit;
2709 
2710  for (int i = 1; i <= depth; i++) {
2711  cout << INDENT;
2712  }
2713 
2714  cout << "loop: " << info->name
2715  << (info->irred ? " (irred)" : "")
2716  << " l=" << info->line_num
2717  << " f='" << strTab.index2str(info->file_index) << "'\n";
2718 
2719  if (expand_loops) {
2720  debugInlineTree(info->node, NULL, strTab, depth + 1, expand_loops);
2721  }
2722  }
2723 }
2724 
2725 #endif // DEBUG_CFG_SOURCE
2726 
2727 } // namespace Struct
2728 } // namespace BAnal
HPC::StringTable * strTab
Definition: Struct.cpp:317
static void doWorkItem(WorkItem *, string &, bool, bool)
Definition: Struct.cpp:720
static void getProcLineMap(StatementVector &svec, Offset vma, Offset end, SymtabAPI::Function *sym_func)
Definition: Struct.cpp:954
list< InlineNode > InlineSeqn
HeaderInfo(Block *blk=NULL)
Definition: Struct.cpp:298
LineMapCache(SymtabAPI::Function *sf, RealPathMgr *rp)
Definition: Struct.cpp:366
void printProc(ostream *os, ostream *gaps, string gaps_file, FileInfo *finfo, GroupInfo *ginfo, ProcInfo *pinfo, HPC::StringTable &strTab)
unsigned int ln
Definition: SrcFile.hpp:66
void printStructFileEnd(ostream *os, ostream *gaps)
static const string & unknown_proc
Definition: Struct.cpp:154
long str2index(const std::string &str)
static TreeNode * doLoopLate(WorkEnv &, GroupInfo *, ParseAPI::Function *, BlockSet &, Loop *, const string &)
Definition: Struct.cpp:1700
bfd_vma VMA
Definition: ISATypes.hpp:79
list< LoopInfo * > LoopList
const char * CfileName()
Definition: InputFile.hpp:86
void printLoadModuleBegin(ostream *os, string lmName)
vector< Statement::Ptr > StatementVector
Definition: Struct.cpp:175
void insert(StmtInfo *)
SymtabAPI::Function * sym_func
Definition: Struct.cpp:358
static LoopList * doLoopTree(WorkEnv &, FileInfo *, GroupInfo *, ParseAPI::Function *, BlockSet &, LoopTreeNode *)
Definition: Struct.cpp:1633
static void addProc(FileMap *fileMap, ProcInfo *pinfo, string &filenm, SymtabAPI::Function *sym_func, VMA start, VMA end, bool alt_file=false)
Definition: Struct.cpp:1017
static void printTime(const char *label, struct timeval *tv_prev, struct rusage *ru_prev, struct timeval *tv_now, struct rusage *ru_now)
Definition: Struct.cpp:525
static void addGaps(WorkEnv &env, FileInfo *, GroupInfo *)
Definition: Struct.cpp:1844
static void getStatement(StatementVector &, Offset, SymtabAPI::Function *)
Definition: Struct.cpp:486
static void getFuncNames(SymtabAPI::Function *sym_func, string &prettynm, string &linknm, bool ourDemangle)
Definition: Struct.cpp:1098
static const string & unknown_file
Definition: Struct.cpp:153
WorkItem(FileInfo *fi, GroupInfo *gi, bool first, bool last, double cst)
Definition: Struct.cpp:339
cct_node_t * node
Definition: cct.c:128
static void doCudaList(WorkEnv &, FileInfo *, GroupInfo *)
Definition: Struct.cpp:1777
Symtab * openSymtab(ElfFile *elfFile)
static RealPathMgr & singleton()
#define DEBUG_SKEL(expr)
Definition: Struct.cpp:276
static void makeWorkList(FileMap *, WorkList &, WorkList &)
Definition: Struct.cpp:762
void mergeInlineLoop(TreeNode *dest, FLPSeqn &path, LoopInfo *info)
static int merge_irred_loops
Definition: Struct.cpp:145
static void doFunctionList(WorkEnv &, FileInfo *, GroupInfo *, bool)
Definition: Struct.cpp:1411
#define VMA_MAX
Definition: ISATypes.hpp:82
static bool BlockLessThan(Block *b1, Block *b2)
Definition: Struct.cpp:417
static char * prefix
Definition: common.c:164
std::string & fileName()
Definition: InputFile.hpp:85
void printVariable(ostream *os, FileInfo *finfo, VariableInfo vinfo)
static Region * findCodeRegion(RegionMap &codeMap, VMA vma)
Definition: Struct.cpp:923
map< Block *, bool > BlockSet
Definition: Struct.cpp:170
bool realpath(std::string &pathNm) const
void printLoadModuleEnd(ostream *os)
exit
Definition: names.cpp:1
void printFileBegin(ostream *os, FileInfo *finfo)
unsigned int uint
Definition: uint.h:124
static bool LoopInfoLessThan(LoopInfo *l1, LoopInfo *l2)
Definition: Struct.cpp:474
list< FLPIndex > FLPSeqn
void makeStructure(string filename, ostream *outFile, ostream *gapsFile, string gaps_filenm, string search_path, Struct::Options &structOpts)
Definition: Struct.cpp:552
bool closeSymtab()
void addStmtToTree(TreeNode *root, HPC::StringTable &strTab, RealPathMgr *realPath, VMA vma, int len, string &filenm, SrcFile::ln line)
static bool LoopTreeLessThan(LoopTreeNode *n1, LoopTreeNode *n2)
Definition: Struct.cpp:467
const std::string & index2str(long index)
static const string & unknown_link
Definition: Struct.cpp:155
static char buf[32]
Definition: StrUtil.cpp:240
static void mergeIrredLoops(WorkEnv &, LoopInfo *)
Definition: Struct.cpp:2305
map< VMA, Region * > RegionMap
Definition: Struct.cpp:174
std::string getFileName()
Definition: ElfHelper.hpp:88
#define DEBUG_CFG(expr)
Definition: Struct.cpp:270
static BAnal::Struct::Options opts
Definition: Struct.cpp:160
std::pair< iterator, bool > insert(const VMA beg, const VMA end)
std::string toString() const
void printFileEnd(ostream *os, FileInfo *finfo)
void mergeInlineEdge(TreeNode *dest, FLPIndex flp, TreeNode *src)
#define INDENT
map< string, FileInfo * > FileMap
Definition: Struct-Skel.hpp:80
ParseAPI::Function * func
const std::string & searchPaths() const
void mergeInlineTree(TreeNode *dest, TreeNode *src)
bool found
Definition: cct.c:129
bool member(VMA vma)
static bool WorkItemGreaterThan(WorkItem *w1, WorkItem *w2)
Definition: Struct.cpp:435
#define SYMTAB_ARCH_CUDA(symtab)
Definition: Struct.cpp:127
static void computeGaps(VMAIntervalSet &, VMAIntervalSet &, VMA, VMA)
Definition: Struct.cpp:2378
static void makeCodeMap(RegionMap &codeMap)
Definition: Struct.cpp:879
static void doBlock(WorkEnv &, GroupInfo *, ParseAPI::Function *, BlockSet &, Block *, TreeNode *)
Definition: Struct.cpp:1727
SymtabAPI::Function * sym_func
static void makeVariables(ostream *outFile)
Definition: Struct.cpp:1056
#define NULL
Definition: ElfHelper.cpp:85
RealPathMgr * realPath
Definition: Struct.cpp:359
bool getLineInfo(VMA vma, string &filenm, uint &line)
Definition: Struct.cpp:377
static Symtab * the_symtab
Definition: Struct.cpp:158
void printStructFileBegin(ostream *os, ostream *gaps, string filenm)
#define WORK_LIST_PCT
Definition: Struct.cpp:141
map< VMA, HeaderInfo > HeaderList
Definition: Struct.cpp:173
static bool EdgeLessThan(Edge *e1, Edge *e2)
Definition: Struct.cpp:425
string basename(const char *fName)
Definition: FileUtil.cpp:90
static int const threshold
static TreeNode * deleteInlinePrefix(WorkEnv &, TreeNode *, Inline::InlineSeqn)
Definition: Struct.cpp:2240
bool openFile(std::string &filename)
Definition: InputFile.cpp:128
static void doCudaFunction(WorkEnv &, GroupInfo *, ParseAPI::Function *, TreeNode *)
Definition: Struct.cpp:1813
static FileMap * makeSkeleton(CodeObject *, const string &)
Definition: Struct.cpp:1134
RealPathMgr * realPath
Definition: Struct.cpp:318
ElfFileVector * fileVector()
Definition: InputFile.hpp:87
vector< WorkItem * > WorkList
Definition: Struct.cpp:176
static char * last
Definition: tokenize.c:65
StmtInfo * findStmt(VMA vma)
static LoopInfo * findLoopHeader(WorkEnv &env, FileInfo *, GroupInfo *, ParseAPI::Function *, TreeNode *, Loop *, const string &)
Definition: Struct.cpp:1904
#define MIN_BYTES_GLOBAL_VARIABLE
Definition: Struct.cpp:143
static void printWorkList(WorkList &, uint &, ostream *, ostream *, string &)
Definition: Struct.cpp:835
bool analyzeAddr(InlineSeqn &nodelist, VMA addr, RealPathMgr *realPath)
size_t getLength()
Definition: ElfHelper.hpp:87
#define RET
string demangleProcName(const std::string &name)
Definition: BinUtils.cpp:86
static VMA LoopMinEntryAddr(Loop *loop)
Definition: Struct.cpp:444