• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
2 // -*- mode: C++ -*-
3 //
4 // Copyright (C) 2013-2023 Red Hat, Inc.
5 
6 /// @file
7 
8 #include "config.h"
9 
10 #include <algorithm>
11 #include <cassert>
12 #include <cstdio>
13 #include <cstring>
14 #include <stdexcept>
15 #include <unordered_map>
16 #include <set>
17 
18 #include "abg-internal.h"
19 
20 // <headers defining libabigail's API go under here>
21 ABG_BEGIN_EXPORT_DECLARATIONS
22 
23 #include "abg-corpus.h"
24 #include "abg-ir.h"
25 #include "abg-reader.h"
26 #include "abg-sptr-utils.h"
27 #include "abg-symtab-reader.h"
28 #include "abg-tools-utils.h"
29 #include "abg-writer.h"
30 
31 ABG_END_EXPORT_DECLARATIONS
32 // </headers defining libabigail's API>
33 
34 #include "abg-corpus-priv.h"
35 #include "abg-ir-priv.h"
36 
37 namespace abigail
38 {
39 
40 namespace ir
41 {
42 
43 using std::ostringstream;
44 using std::unordered_map;
45 using std::list;
46 using std::vector;
47 
48 using regex::regex_t_sptr;
49 
50 /// Constructor of @ref corpus::exported_decls_builder.
51 ///
52 /// @param fns a reference to the vector of exported functions.
53 ///
54 /// @param vars a reference to the vector of exported variables.
55 ///
56 /// @param fns_suppress_regexps the regular expressions that designate
57 /// the functions to suppress from the exported functions set.
58 ///
59 /// @param vars_suppress_regexps the regular expressions that designate
60 /// the variables to suppress from the exported variables set.
61 ///
62 /// @param fns_keep_regexps the regular expressions that designate the
63 /// functions to keep in the exported functions set.
64 ///
65 /// @param fns_keep_regexps the regular expressions that designate the
66 /// functions to keep in the exported functions set.
67 ///
68 /// @param vars_keep_regexps the regular expressions that designate
69 /// the variables to keep in the exported variables set.
70 ///
71 /// @param sym_id_of_fns_to_keep the IDs of the functions to keep in
72 /// the exported functions set.
73 ///
74 /// @param sym_id_of_vars_to_keep the IDs of the variables to keep in
75 /// the exported variables set.
76 corpus::exported_decls_builder
exported_decls_builder(functions & fns,variables & vars,strings_type & fns_suppress_regexps,strings_type & vars_suppress_regexps,strings_type & fns_keep_regexps,strings_type & vars_keep_regexps,strings_type & sym_id_of_fns_to_keep,strings_type & sym_id_of_vars_to_keep)77 ::exported_decls_builder(functions&	fns,
78 			 variables&	vars,
79 			 strings_type&	fns_suppress_regexps,
80 			 strings_type&	vars_suppress_regexps,
81 			 strings_type&	fns_keep_regexps,
82 			 strings_type&	vars_keep_regexps,
83 			 strings_type&	sym_id_of_fns_to_keep,
84 			 strings_type&	sym_id_of_vars_to_keep)
85   : priv_(new priv(fns, vars,
86 		   fns_suppress_regexps,
87 		   vars_suppress_regexps,
88 		   fns_keep_regexps,
89 		   vars_keep_regexps,
90 		   sym_id_of_fns_to_keep,
91 		   sym_id_of_vars_to_keep))
92 {
93 }
94 
95 /// Getter for the reference to the vector of exported functions.
96 /// This vector is shared with with the @ref corpus.  It's where the
97 /// set of exported function is ultimately stored.
98 ///
99 /// @return a reference to the vector of exported functions.
100 const corpus::functions&
exported_functions() const101 corpus::exported_decls_builder::exported_functions() const
102 {return priv_->fns_;}
103 
104 /// Getter for the reference to the vector of exported functions.
105 /// This vector is shared with with the @ref corpus.  It's where the
106 /// set of exported function is ultimately stored.
107 ///
108 /// @return a reference to the vector of exported functions.
109 corpus::functions&
exported_functions()110 corpus::exported_decls_builder::exported_functions()
111 {return priv_->fns_;}
112 
113 /// Test if a given function ID maps to several functions in the same corpus.
114 ///
115 /// The magic of ELF symbol aliases makes it possible for an ELF
116 /// symbol alias to designate several different functions.  This
117 /// function tests if the ELF symbol of a given function has a aliases
118 /// that designates another function or not.
119 ///
120 /// @param fn the function to consider.
121 ///
122 /// @return the set of functions designated by the ELF symbol of @p
123 /// fn, or nullptr if the function ID maps to just @p fn.
124 std::unordered_set<function_decl*>*
fn_id_maps_to_several_fns(function_decl * fn)125 corpus::exported_decls_builder::fn_id_maps_to_several_fns(function_decl* fn)
126 {
127   std::unordered_set<function_decl*> *fns_for_id =
128     priv_->fn_id_is_in_id_fns_map(fn);
129   if (fns_for_id && fns_for_id->size() > 1)
130     return fns_for_id;
131 
132   return nullptr;
133 }
134 
135 /// Getter for the reference to the vector of exported variables.
136 /// This vector is shared with with the @ref corpus.  It's where the
137 /// set of exported variable is ultimately stored.
138 ///
139 /// @return a reference to the vector of exported variables.
140 const corpus::variables&
exported_variables() const141 corpus::exported_decls_builder::exported_variables() const
142 {return priv_->vars_;}
143 
144 /// Getter for the reference to the vector of exported variables.
145 /// This vector is shared with with the @ref corpus.  It's where the
146 /// set of exported variable is ultimately stored.
147 ///
148 /// @return a reference to the vector of exported variables.
149 corpus::variables&
exported_variables()150 corpus::exported_decls_builder::exported_variables()
151 {return priv_->vars_;}
152 
153 /// Consider at all the tunables that control wether a function should
154 /// be added to the set of exported function and if it fits in, add
155 /// the function to that set.
156 ///
157 /// @param fn the function to add the set of exported functions.
158 void
maybe_add_fn_to_exported_fns(function_decl * fn)159 corpus::exported_decls_builder::maybe_add_fn_to_exported_fns(function_decl* fn)
160 {
161   if (!fn->get_is_in_public_symbol_table())
162     return;
163 
164   const string& fn_id = priv_->get_id(*fn);
165   ABG_ASSERT(!fn_id.empty());
166 
167   if (priv_->fn_is_in_id_fns_map(fn))
168     return;
169 
170   if (priv_->keep_wrt_id_of_fns_to_keep(fn)
171       && priv_->keep_wrt_regex_of_fns_to_suppress(fn)
172       && priv_->keep_wrt_regex_of_fns_to_keep(fn))
173     priv_->add_fn_to_exported(fn);
174 }
175 
176 /// Consider at all the tunables that control wether a variable should
177 /// be added to the set of exported variable and if it fits in, add
178 /// the variable to that set.
179 ///
180 /// @param fn the variable to add the set of exported variables.
181 void
maybe_add_var_to_exported_vars(const var_decl * var)182 corpus::exported_decls_builder::maybe_add_var_to_exported_vars(const var_decl* var)
183 {
184   if (!var->get_is_in_public_symbol_table())
185     return;
186 
187   const string& var_id = priv_->get_id(*var);
188   ABG_ASSERT(!var_id.empty());
189 
190   if (priv_->var_id_is_in_id_var_map(var_id))
191     return;
192 
193   if (priv_->keep_wrt_id_of_vars_to_keep(var)
194       && priv_->keep_wrt_regex_of_vars_to_suppress(var)
195       && priv_->keep_wrt_regex_of_vars_to_keep(var))
196     priv_->add_var_to_exported(var);
197 }
198 
199 // </corpus::exported_decls_builder>
200 
201 /// Convenience typedef for a hash map of pointer to function_decl and
202 /// boolean.
203 typedef unordered_map<const function_decl*,
204 		      bool,
205 		      function_decl::hash,
206 		      function_decl::ptr_equal> fn_ptr_map_type;
207 
208 /// Convenience typedef for a hash map of string and pointer to
209 /// function_decl.
210 typedef unordered_map<string, const function_decl*> str_fn_ptr_map_type;
211 
212 /// Convenience typedef for a hash map of pointer to var_decl and boolean.
213 typedef unordered_map<const var_decl*,
214 		      bool,
215 		      var_decl::hash,
216 		      var_decl::ptr_equal> var_ptr_map_type;
217 
218 /// This is a comparison functor for comparing pointers to @ref
219 /// function_decl.
220 struct func_comp
221 {
222   /// The comparisong operator for pointers to @ref function_decl.  It
223   /// performs a string comparison of the mangled names of the
224   /// functions.  If the functions don't have mangled names, it
225   /// compares their names instead.
226   ///
227   /// @param first the first function to consider in the comparison.
228   ///
229   /// @param second the second function to consider in the comparison.
230   ///
231   /// @return true if the (mangled) name of the first function is less
232   /// than the (mangled)name of the second one, false otherwise.
233   bool
operator ()abigail::ir::func_comp234   operator()(const function_decl* first,
235 	     const function_decl* second) const
236   {
237     ABG_ASSERT(first != 0 && second != 0);
238 
239     string first_name, second_name;
240     first_name = first->get_linkage_name();
241     if (first_name.empty())
242       first_name = first->get_name();
243     ABG_ASSERT(!first_name.empty());
244 
245     second_name = second->get_linkage_name();
246     if (second_name.empty())
247       second_name = second->get_name();
248     ABG_ASSERT(!second_name.empty());
249 
250     return first_name < second_name;
251   }
252 };
253 
254 /// This is a comparison functor for comparing pointers to @ref
255 /// var_decl.
256 struct var_comp
257 {
258   /// The comparison operator for pointers to @ref var_decl.
259   ///
260   /// It perform a string comparison on the names of the variables.
261   ///
262   /// @param first the first variable to consider for the comparison.
263   ///
264   /// @param second the second variable to consider for the comparison.
265   ///
266   /// @return true if first is less than second, false otherwise.
267   bool
operator ()abigail::ir::var_comp268   operator()(const var_decl* first,
269 	     const var_decl* second) const
270   {
271     ABG_ASSERT(first != 0 && second != 0);
272 
273     string first_name, second_name;
274     first_name = first->get_linkage_name();
275     if (first_name.empty())
276       {
277 	first_name = first->get_pretty_representation();
278 	second_name = second->get_pretty_representation();
279 	ABG_ASSERT(!second_name.empty());
280       }
281     ABG_ASSERT(!first_name.empty());
282 
283     if (second_name.empty())
284       second_name = second->get_linkage_name();
285 
286     if (second_name.empty())
287       {
288 	second_name = second->get_pretty_representation();
289 	first_name = first->get_pretty_representation();
290 	ABG_ASSERT(!first_name.empty());
291       }
292     ABG_ASSERT(!second_name.empty());
293 
294     return first_name < second_name;
295   }
296 };
297 
298 
299 /// A comparison functor to compare elf_symbols for the purpose of
300 /// sorting.
301 struct comp_elf_symbols_functor
302 {
303   bool
operator ()abigail::ir::comp_elf_symbols_functor304   operator()(const elf_symbol& l,
305 	     const elf_symbol& r) const
306   {return l.get_id_string() < r.get_id_string();}
307 
308   bool
operator ()abigail::ir::comp_elf_symbols_functor309   operator()(const elf_symbol_sptr l,
310 	     const elf_symbol_sptr r) const
311   {return operator()(*l, *r);}
312 }; // end struct comp_elf_symbols_functor
313 
314 
315 // <corpus stuff>
316 
317 /// Get the maps that associate a name to a certain kind of type.
318 type_maps&
get_types()319 corpus::priv::get_types()
320 {return types_;}
321 
322 /// Get the maps that associate a name to a certain kind of type.
323 const type_maps&
get_types() const324 corpus::priv::get_types() const
325 {return types_;}
326 
327 /// Return a sorted vector of function symbols for this corpus.
328 ///
329 /// Note that the first time this function is called, the symbols are
330 /// sorted and cached.  Subsequent invocations of this function return
331 /// the cached vector that was built previously.
332 ///
333 /// @return the sorted list of function symbols.
334 const elf_symbols&
get_sorted_fun_symbols() const335 corpus::priv::get_sorted_fun_symbols() const
336 {
337   if (!sorted_fun_symbols)
338     {
339       if (symtab_)
340 	{
341 	  auto filter = symtab_->make_filter();
342 	  filter.set_functions();
343 	  sorted_fun_symbols = elf_symbols(symtab_->begin(filter),
344 					   symtab_->end());
345 	}
346       else
347 	sorted_fun_symbols = elf_symbols();
348     }
349   return *sorted_fun_symbols;
350 }
351 
352 /// Return a map from name to function symbol for this corpus.
353 ///
354 /// Note that the first time this function is called, the map is built.
355 /// Subsequent invocations of this function return the cached map that was
356 /// built previously.
357 ///
358 /// @return the name function symbol map
359 const string_elf_symbols_map_type&
get_fun_symbol_map() const360 corpus::priv::get_fun_symbol_map() const
361 {
362   if (!fun_symbol_map)
363     {
364       fun_symbol_map = string_elf_symbols_map_type();
365       for (const auto& symbol : get_sorted_fun_symbols())
366 	(*fun_symbol_map)[symbol->get_name()].push_back(symbol);
367     }
368   return *fun_symbol_map;
369 }
370 
371 /// Getter for a sorted vector of the function symbols undefined in
372 /// this corpus.
373 ///
374 /// @return a vector of the function symbols undefined in this corpus,
375 /// sorted by name and then version.
376 const elf_symbols&
get_sorted_undefined_fun_symbols() const377 corpus::priv::get_sorted_undefined_fun_symbols() const
378 {
379   if (!sorted_undefined_fun_symbols)
380     {
381       if (symtab_)
382 	{
383 	  auto filter = symtab_->make_filter();
384 	  filter.set_functions();
385 	  filter.set_undefined_symbols();
386 	  filter.set_public_symbols(false);
387 
388 	  sorted_undefined_fun_symbols =
389 	    elf_symbols(symtab_->begin(filter), symtab_->end());
390 	}
391       else
392 	sorted_undefined_fun_symbols = elf_symbols();
393     }
394   return *sorted_undefined_fun_symbols;
395 }
396 
397 /// Return a map from name to undefined function symbol for this corpus.
398 ///
399 /// Note that the first time this function is called, the map is built.
400 /// Subsequent invocations of this function return the cached map that was
401 /// built previously.
402 ///
403 /// @return the name function symbol map for undefined symbols
404 const string_elf_symbols_map_type&
get_undefined_fun_symbol_map() const405 corpus::priv::get_undefined_fun_symbol_map() const
406 {
407   if (!undefined_fun_symbol_map)
408     {
409       undefined_fun_symbol_map = string_elf_symbols_map_type();
410       for (const auto& symbol : get_sorted_undefined_fun_symbols())
411 	(*undefined_fun_symbol_map)[symbol->get_name()].push_back(symbol);
412     }
413   return *undefined_fun_symbol_map;
414 }
415 
416 /// Return a list of symbols that are not referenced by any function of
417 /// corpus::get_functions().
418 ///
419 /// Note that this function considers the list of function symbols to keep,
420 /// that is provided by corpus::get_sym_ids_of_fns_to_keep(). If a given
421 /// unreferenced function symbol is not in the list of functions to keep, then
422 /// that symbol is dropped and will not be part of the resulting table of
423 /// unreferenced symbol that is built.
424 ///
425 /// @return list of symbols that are not referenced by any function
426 const elf_symbols&
get_unreferenced_function_symbols() const427 corpus::priv::get_unreferenced_function_symbols() const
428 {
429   if (!unrefed_fun_symbols)
430     {
431       unrefed_fun_symbols = elf_symbols();
432       if (symtab_)
433 	{
434 	  unordered_map<string, bool> refed_funs;
435 
436 	  for (const auto& function : fns)
437 	    if (elf_symbol_sptr sym = function->get_symbol())
438 	      {
439 		refed_funs[sym->get_id_string()] = true;
440 		for (elf_symbol_sptr a = sym->get_next_alias();
441 		     a && !a->is_main_symbol(); a = a->get_next_alias())
442 		  refed_funs[a->get_id_string()] = true;
443 	      }
444 
445 	  auto filter = symtab_->make_filter();
446 	  filter.set_functions();
447 	  for (const auto& symbol :
448 	       symtab_reader::filtered_symtab(*symtab_, filter))
449 	    {
450 	      const std::string sym_id = symbol->get_id_string();
451 	      if (refed_funs.find(sym_id) == refed_funs.end())
452 		{
453 		  bool keep = sym_id_fns_to_keep.empty();
454 		  for (const auto& id : sym_id_fns_to_keep)
455 		    {
456 		      if (id == sym_id)
457 			{
458 			  keep = true;
459 			  break;
460 			}
461 		    }
462 		  if (keep)
463 		    unrefed_fun_symbols->push_back(symbol);
464 		}
465 	    }
466 	}
467     }
468   return *unrefed_fun_symbols;
469 }
470 
471 /// Getter for the sorted vector of variable symbols for this corpus.
472 ///
473 /// Note that the first time this function is called, it computes the
474 /// sorted vector, caches the result and returns it.  Subsequent
475 /// invocations of this function just return the cached vector.
476 ///
477 /// @return the sorted vector of variable symbols for this corpus.
478 const elf_symbols&
get_sorted_var_symbols() const479 corpus::priv::get_sorted_var_symbols() const
480 {
481   if (!sorted_var_symbols)
482     {
483       if (symtab_)
484 	{
485 	  auto filter = symtab_->make_filter();
486 	  filter.set_variables();
487 
488 	  sorted_var_symbols = elf_symbols(symtab_->begin(filter),
489 					   symtab_->end());
490 	}
491       else
492 	sorted_var_symbols = elf_symbols();
493     }
494   return *sorted_var_symbols;
495 }
496 
497 /// Return a map from name to variable symbol for this corpus.
498 ///
499 /// Note that the first time this function is called, the map is built.
500 /// Subsequent invocations of this function return the cached map that was
501 /// built previously.
502 ///
503 /// @return the name variable symbol map
504 const string_elf_symbols_map_type&
get_var_symbol_map() const505 corpus::priv::get_var_symbol_map() const
506 {
507   if (!var_symbol_map)
508     {
509       var_symbol_map = string_elf_symbols_map_type();
510       for (const auto& symbol : get_sorted_var_symbols())
511 	(*var_symbol_map)[symbol->get_name()].push_back(symbol);
512     }
513   return *var_symbol_map;
514 }
515 
516 /// Getter for a sorted vector of the variable symbols undefined in
517 /// this corpus.
518 ///
519 /// @return a vector of the variable symbols undefined in this corpus,
520 /// sorted by name and then version.
521 const elf_symbols&
get_sorted_undefined_var_symbols() const522 corpus::priv::get_sorted_undefined_var_symbols() const
523 {
524   if (!sorted_undefined_var_symbols)
525     {
526       if (symtab_)
527 	{
528 	  auto filter = symtab_->make_filter();
529 	  filter.set_variables();
530 	  filter.set_undefined_symbols();
531 	  filter.set_public_symbols(false);
532 
533 	  sorted_undefined_var_symbols =
534 	    elf_symbols(symtab_->begin(filter), symtab_->end());
535 	}
536       else
537 	sorted_undefined_var_symbols = elf_symbols();
538     }
539   return *sorted_undefined_var_symbols;
540 }
541 
542 /// Return a map from name to undefined variable symbol for this corpus.
543 ///
544 /// Note that the first time this function is called, the map is built.
545 /// Subsequent invocations of this function return the cached map that was
546 /// built previously.
547 ///
548 /// @return the name undefined variable symbol map
549 const string_elf_symbols_map_type&
get_undefined_var_symbol_map() const550 corpus::priv::get_undefined_var_symbol_map() const
551 {
552   if (!undefined_var_symbol_map)
553     {
554       undefined_var_symbol_map = string_elf_symbols_map_type();
555       for (const auto& symbol : get_sorted_undefined_var_symbols())
556 	(*undefined_var_symbol_map)[symbol->get_name()].push_back(symbol);
557     }
558   return *undefined_var_symbol_map;
559 }
560 
561 /// Return a list of symbols that are not referenced by any variable of
562 /// corpus::get_variables().
563 ///
564 /// Note that this function considers the list of variable symbols to keep,
565 /// that is provided by corpus::get_sym_ids_of_vars_to_keep(). If a given
566 /// unreferenced variable symbol is not in the list of variable to keep, then
567 /// that symbol is dropped and will not be part of the resulting table of
568 /// unreferenced symbol that is built.
569 ///
570 /// @return list of symbols that are not referenced by any variable
571 const elf_symbols&
get_unreferenced_variable_symbols() const572 corpus::priv::get_unreferenced_variable_symbols() const
573 {
574   if (!unrefed_var_symbols)
575     {
576       unrefed_var_symbols = elf_symbols();
577       if (symtab_)
578 	{
579 	  unordered_map<string, bool> refed_vars;
580 	  for (const auto& variable : vars)
581 	    if (elf_symbol_sptr sym = variable->get_symbol())
582 	      {
583 		refed_vars[sym->get_id_string()] = true;
584 		for (elf_symbol_sptr a = sym->get_next_alias();
585 		     a && !a->is_main_symbol(); a = a->get_next_alias())
586 		  refed_vars[a->get_id_string()] = true;
587 	      }
588 
589 	  auto filter = symtab_->make_filter();
590 	  filter.set_variables();
591 	  for (const auto& symbol :
592 	       symtab_reader::filtered_symtab(*symtab_, filter))
593 	    {
594 	      const std::string sym_id = symbol->get_id_string();
595 	      if (refed_vars.find(sym_id) == refed_vars.end())
596 		{
597 		  bool keep = sym_id_vars_to_keep.empty();
598 		  for (const auto& id : sym_id_vars_to_keep)
599 		    {
600 		      if (id == sym_id)
601 			{
602 			  keep = true;
603 			  break;
604 			}
605 		    }
606 		  if (keep)
607 		    unrefed_var_symbols->push_back(symbol);
608 		}
609 	    }
610 	}
611     }
612   return *unrefed_var_symbols;
613 }
614 
615 
616 /// Getter of the set of pretty representation of types that are
617 /// reachable from public interfaces (global functions and variables).
618 ///
619 /// @return the set of pretty representation of types that are
620 /// reachable from public interfaces (global functions and variables).
621 unordered_set<interned_string, hash_interned_string>*
get_public_types_pretty_representations()622 corpus::priv::get_public_types_pretty_representations()
623 {
624   if (group)
625     return group->get_public_types_pretty_representations();
626 
627   if (pub_type_pretty_reprs_ == 0)
628     pub_type_pretty_reprs_ =
629 	new unordered_set<interned_string, hash_interned_string>;
630   return pub_type_pretty_reprs_;
631 }
632 
633 /// Destructor of the @ref corpus::priv type.
~priv()634 corpus::priv::~priv()
635 {
636   delete pub_type_pretty_reprs_;
637 }
638 
639 /// Constructor of the @ref corpus type.
640 ///
641 /// @param env the environment of the corpus.
642 ///
643 /// @param path the path to the file containing the ABI corpus.
corpus(const ir::environment & env,const string & path)644 corpus::corpus(const ir::environment& env, const string& path)
645 {
646   priv_.reset(new priv(path, env));
647   init_format_version();
648 }
649 
650 corpus::~corpus() = default;
651 
652 /// Getter of the enviroment of the corpus.
653 ///
654 /// @return the environment of this corpus.
655 const environment&
get_environment() const656 corpus::get_environment() const
657 {return priv_->env;}
658 
659 /// Test if logging was requested.
660 ///
661 /// @return true iff logging was requested.
662 bool
do_log() const663 corpus::do_log() const
664 {return priv_->do_log;}
665 
666 /// Request logging, or not.
667 ///
668 /// @param f true iff logging is requested.
669 void
do_log(bool f)670 corpus::do_log(bool f)
671 {priv_->do_log = f;}
672 
673 /// Add a translation unit to the current ABI Corpus.
674 ///
675 /// Note that two translation units with the same path (as returned by
676 /// translation_unit::get_path) cannot be added to the same @ref
677 /// corpus.  If that happens, the library aborts.
678 ///
679 /// @param tu the new translation unit to add.
680 void
add(const translation_unit_sptr & tu)681 corpus::add(const translation_unit_sptr& tu)
682 {
683   ABG_ASSERT(priv_->members.insert(tu).second);
684 
685   if (!tu->get_absolute_path().empty())
686     {
687       // Update the path -> translation_unit map.
688       string_tu_map_type::const_iterator i =
689 	priv_->path_tu_map.find(tu->get_absolute_path());
690       ABG_ASSERT(i == priv_->path_tu_map.end());
691       priv_->path_tu_map[tu->get_absolute_path()] = tu;
692     }
693 
694   tu->set_corpus(this);
695 }
696 
697 /// Return the list of translation units of the current corpus.
698 ///
699 /// @return the list of translation units of the current corpus.
700 const translation_units&
get_translation_units() const701 corpus::get_translation_units() const
702 {return priv_->members;}
703 
704 /// Find the translation unit that has a given path.
705 ///
706 /// @param path the path of the translation unit to look for.
707 ///
708 /// @return the translation unit found, if any.  Otherwise, return
709 /// nil.
710 const translation_unit_sptr
find_translation_unit(const string & path) const711 corpus::find_translation_unit(const string &path) const
712 {
713   string_tu_map_type::const_iterator i =
714     priv_->path_tu_map.find(path);
715 
716   if (i == priv_->path_tu_map.end())
717     return translation_unit_sptr();
718   return i->second;
719 }
720 
721 /// Erase the translation units contained in this in-memory object.
722 ///
723 /// Note that the on-disk archive file that contains the serialized
724 /// representation of this object is not modified.
725 void
drop_translation_units()726 corpus::drop_translation_units()
727 {priv_->members.clear();}
728 
729 /// Get the maps that associate a name to a certain kind of type.
730 ///
731 /// @return the maps that associate a name to a certain kind of type.
732 type_maps&
get_types()733 corpus::get_types()
734 {return priv_->types_;}
735 
736 /// Get the maps that associate a name to a certain kind of type.
737 ///
738 /// @return the maps that associate a name to a certain kind of
739 /// type.
740 const type_maps&
get_types() const741 corpus::get_types() const
742 {return priv_->types_;}
743 
744 /// Get the maps that associate a location string to a certain kind of
745 /// type.
746 ///
747 /// The location string is the result of the invocation to the
748 /// function abigail::ir::location::expand().  It has the form
749 /// "file.c:4:1", with 'file.c' being the file name, '4' being the
750 /// line number and '1' being the column number.
751 ///
752 /// @return the maps.
753 const type_maps&
get_type_per_loc_map() const754 corpus::get_type_per_loc_map() const
755 {return priv_->type_per_loc_map_;}
756 
757 /// Test if the recording of reachable types (and thus, indirectly,
758 /// the recording of non-reachable types) is activated for the
759 /// current @ref corpus.
760 ///
761 /// @return true iff the recording of reachable types is activated for
762 /// the current @ref corpus.
763 bool
recording_types_reachable_from_public_interface_supported()764 corpus::recording_types_reachable_from_public_interface_supported()
765 {
766   return (priv_->get_public_types_pretty_representations()
767 	  && !priv_->get_public_types_pretty_representations()->empty());
768 }
769 
770 /// Record a type as being reachable from public interfaces (global
771 /// functions and variables).
772 ///
773 /// @param t the type to record as reachable.
774 void
record_type_as_reachable_from_public_interfaces(const type_base & t)775 corpus::record_type_as_reachable_from_public_interfaces(const type_base& t)
776 {
777   string repr = get_pretty_representation(&t, /*internal=*/false);
778   interned_string s = t.get_environment().intern(repr);
779   priv_->get_public_types_pretty_representations()->insert(s);
780 }
781 
782 /// Test if a type is reachable from public interfaces (global
783 /// functions and variables).
784 ///
785 /// For a type to be considered reachable from public interfaces, it
786 /// must have been previously marked as such by calling
787 /// corpus::record_type_as_reachable_from_public_interfaces.
788 ///
789 /// @param t the type to test for.
790 ///
791 /// @return true iff @p t is reachable from public interfaces.
792 bool
type_is_reachable_from_public_interfaces(const type_base & t) const793 corpus::type_is_reachable_from_public_interfaces(const type_base& t) const
794 {
795   string repr = get_pretty_representation(&t, /*internal=*/false);
796   interned_string s = t.get_environment().intern(repr);
797 
798   return (priv_->get_public_types_pretty_representations()->find(s)
799 	  !=  priv_->get_public_types_pretty_representations()->end());
800 }
801 
802 /// Getter of a sorted vector of the types that are *NOT* reachable
803 /// from public interfaces.
804 ///
805 /// Note that for this to be non-empty, the libabigail reader that
806 /// analyzed the input (be it a binary or an abixml file) must have be
807 /// configured to load types that are not reachable from public
808 /// interfaces.
809 ///
810 /// @return a reference to a vector of sorted types NON reachable from
811 /// public interfaces.
812 const vector<type_base_wptr>&
get_types_not_reachable_from_public_interfaces() const813 corpus::get_types_not_reachable_from_public_interfaces() const
814 {
815   if (priv_->types_not_reachable_from_pub_ifaces_.empty())
816     {
817       const type_maps& types = get_types();
818       for (vector<type_base_wptr>::const_iterator it =
819 	     types.get_types_sorted_by_name().begin();
820 	   it != types.get_types_sorted_by_name().end();
821 	   ++it)
822 	{
823 	  type_base_sptr t(*it);
824 	  if (!type_is_reachable_from_public_interfaces(*t))
825 	    priv_->types_not_reachable_from_pub_ifaces_.push_back(t);
826 	}
827     }
828 
829   return priv_->types_not_reachable_from_pub_ifaces_;
830 }
831 
832 /// Get the maps that associate a location string to a certain kind of
833 /// type.
834 ///
835 /// The location string is the result of the invocation to the
836 /// function abigail::ir::location::expand().  It has the form
837 /// "file.c:4:1", with 'file.c' being the file name, '4' being the
838 /// line number and '1' being the column number.
839 ///
840 /// @return the maps.
841 type_maps&
get_type_per_loc_map()842 corpus::get_type_per_loc_map()
843 {return priv_->type_per_loc_map_;}
844 
845 /// Getter of the group this corpus is a member of.
846 ///
847 /// @return the group this corpus is a member of, or nil if it's not
848 /// part of any @ref corpus_group.
849 const corpus_group*
get_group() const850 corpus::get_group() const
851 {return priv_->group;}
852 
853 /// Getter of the group this corpus belongs to.
854 ///
855 /// @return the group this corpus belong to, or nil if it's not part
856 /// of any @ref corpus_group.
857 corpus_group*
get_group()858 corpus::get_group()
859 {return priv_->group;}
860 
861 /// Setter of the group this corpus belongs to.
862 ///
863 /// @param g the new group.
864 void
set_group(corpus_group * g)865 corpus::set_group(corpus_group* g)
866 {priv_->group = g;}
867 
868 /// Initialize the abixml serialization format version number of the
869 /// corpus.
870 ///
871 /// This function sets the format version number ot the default one
872 /// supported by the current version of Libabigail.
873 void
init_format_version()874 corpus::init_format_version()
875 {
876   set_format_major_version_number
877     (priv_->env.get_config().get_format_major_version_number());
878   set_format_minor_version_number
879     (priv_->env.get_config().get_format_minor_version_number());
880 }
881 
882 /// Getter for the origin of the corpus.
883 ///
884 /// @return the origin of the corpus.
885 corpus::origin
get_origin() const886 corpus::get_origin() const
887 {return priv_->origin_;}
888 
889 /// Setter for the origin of the corpus.
890 ///
891 /// @param o the new origin for the corpus.
892 void
set_origin(origin o)893 corpus::set_origin(origin o)
894 {priv_->origin_ = o;}
895 
896 /// Getter of the major version number of the abixml serialization
897 /// format.
898 ///
899 /// @return the major version number of the abixml format.
900 string&
get_format_major_version_number() const901 corpus::get_format_major_version_number() const
902 {return priv_->format_major_version_number_;}
903 
904 /// Setter of the major version number of the abixml serialization
905 /// format.
906 ///
907 /// @param maj the new major version numberof the abixml format.
908 void
set_format_major_version_number(const string & maj)909 corpus::set_format_major_version_number(const string& maj)
910 {priv_->format_major_version_number_ = maj;}
911 
912 /// Getter of the minor version number of the abixml serialization
913 /// format.
914 ///
915 /// @return the minor version number of the abixml serialization
916 /// format.
917 string&
get_format_minor_version_number() const918 corpus::get_format_minor_version_number() const
919 {return priv_->format_minor_version_number_;}
920 
921 /// Setter of the minor version number of the abixml serialization
922 /// format.
923 ///
924 /// @param min the new minor version number of the abixml
925 /// serialization format.
926 void
set_format_minor_version_number(const string & min)927 corpus::set_format_minor_version_number(const string& min)
928 {priv_->format_minor_version_number_ = min;}
929 
930 /// Get the file path associated to the corpus file.
931 ///
932 /// A subsequent call to corpus::read will deserialize the content of
933 /// the abi file expected at this path; likewise, a call to
934 /// corpus::write will serialize the translation units contained in
935 /// the corpus object into the on-disk file at this path.
936 ///
937 /// @return the file path associated to the current corpus.
938 string&
get_path() const939 corpus::get_path() const
940 {return priv_->path;}
941 
942 /// Set the file path associated to the corpus file.
943 ///
944 /// A subsequent call to corpus::read will deserialize the content of
945 /// the abi file expected at this path; likewise, a call to
946 /// corpus::write will serialize the translation units contained in
947 /// the corpus object into the on-disk file at this path.
948 ///
949 /// @param path the new file path to assciate to the current corpus.
950 void
set_path(const string & path)951 corpus::set_path(const string& path)
952 {priv_->path = path;}
953 
954 /// Getter of the needed property of the corpus.
955 ///
956 /// This property is meaningful for, e.g, corpora built from ELF
957 /// shared library files.  In that case, this is a vector of names of
958 /// dependencies of the ELF shared library file.
959 ///
960 /// @return the vector of dependencies needed by this corpus.
961 const vector<string>&
get_needed() const962 corpus::get_needed() const
963 {return priv_->needed;}
964 
965 /// Setter of the needed property of the corpus.
966 ///
967 /// This property is meaningful for, e.g, corpora built from ELF
968 /// shared library files.  In that case, this is a vector of names of
969 /// dependencies of the ELF shared library file.
970 ///
971 /// @param needed the new vector of dependencies needed by this
972 /// corpus.
973 void
set_needed(const vector<string> & needed)974 corpus::set_needed(const vector<string>& needed)
975 {priv_->needed = needed;}
976 
977 /// Getter for the soname property of the corpus.
978 ///
979 /// This property is meaningful for, e.g, corpora built from ELF
980 /// shared library files.  In that case, this is the shared object
981 /// name exported by the shared library.
982 ///
983 /// @return the soname property of the corpus.
984 const string&
get_soname()985 corpus::get_soname()
986 {return priv_->soname;}
987 
988 /// Setter for the soname property of the corpus.
989 ///
990 /// This property is meaningful for, e.g, corpora built from ELF
991 /// shared library files.  In that case, this is the shared object
992 /// name exported by the shared library.
993 ///
994 /// @param soname the new soname property of the corpus.
995 void
set_soname(const string & soname)996 corpus::set_soname(const string& soname)
997 {priv_->soname = soname;}
998 
999 /// Getter for the architecture name of the corpus.
1000 ///
1001 /// This property is meaningful for e.g, corpora built from ELF shared
1002 /// library files.  In that case, this is a string representation of
1003 /// the Elf{32,64}_Ehdr::e_machine field.
1004 ///
1005 /// @return the architecture name string.
1006 const string&
get_architecture_name() const1007 corpus::get_architecture_name() const
1008 {return priv_->architecture_name;}
1009 
1010 /// Setter for the architecture name of the corpus.
1011 ///
1012 /// This property is meaningful for e.g, corpora built from ELF shared
1013 /// library files.  In that case, this is a string representation of
1014 /// the Elf{32,64}_Ehdr::e_machine field.
1015 ///
1016 /// @param arch the architecture name string.
1017 void
set_architecture_name(const string & arch)1018 corpus::set_architecture_name(const string& arch)
1019 {priv_->architecture_name = arch;}
1020 
1021 /// Tests if the corpus is empty from an ABI surface perspective. I.e. if all
1022 /// of these criteria are true:
1023 ///  - all translation units (members) are empty
1024 ///  - the maps function and variable symbols are not having entries
1025 ///  - for shared libraries:
1026 ///    - the soname is empty
1027 ///    - there are no DT_NEEDED entries
1028 ///
1029 /// @return true if the corpus contains no translation unit.
1030 bool
is_empty() const1031 corpus::is_empty() const
1032 {
1033   bool members_empty = true;
1034   for (translation_units::const_iterator i = priv_->members.begin(),
1035 					 e = priv_->members.end();
1036        i != e; ++i)
1037     {
1038       if (!(*i)->is_empty())
1039 	{
1040 	  members_empty = false;
1041 	  break;
1042 	}
1043     }
1044   return (members_empty
1045 	  && (!get_symtab() || !get_symtab()->has_symbols())
1046 	  && priv_->soname.empty()
1047 	  && priv_->needed.empty()
1048 	  && priv_->architecture_name.empty()
1049 	  && !priv_->group);
1050 }
1051 
1052 /// Compare the current @ref corpus against another one.
1053 ///
1054 /// @param other the other corpus to compare against.
1055 ///
1056 /// @return true if the two corpus are equal, false otherwise.
1057 bool
operator ==(const corpus & other) const1058 corpus::operator==(const corpus& other) const
1059 {
1060   translation_units::const_iterator i, j;
1061   for (i = get_translation_units().begin(),
1062 	 j = other.get_translation_units().begin();
1063        (i != get_translation_units().end()
1064 	&& j != other.get_translation_units().end());
1065        ++i, ++j)
1066     if ((**i) != (**j))
1067       return false;
1068 
1069   return (i == get_translation_units().end()
1070 	  && j == other.get_translation_units().end());
1071 }
1072 
1073 /// Setter for the symtab object.
1074 ///
1075 /// @param symtab a shared pointer to the new symtab object
1076 void
set_symtab(symtab_reader::symtab_sptr symtab)1077 corpus::set_symtab(symtab_reader::symtab_sptr symtab)
1078 {priv_->symtab_ = symtab;}
1079 
1080 /// Getter for the symtab object.
1081 ///
1082 /// @return a shared pointer to the symtab object
1083 const symtab_reader::symtab_sptr&
get_symtab() const1084 corpus::get_symtab() const
1085 {return priv_->symtab_;}
1086 
1087 /// Getter for the function symbols map.
1088 ///
1089 /// @return a reference to the function symbols map.
1090 const string_elf_symbols_map_type&
get_fun_symbol_map() const1091 corpus::get_fun_symbol_map() const
1092 {return priv_->get_fun_symbol_map();}
1093 
1094 /// Getter for the map of function symbols that are undefined in this
1095 /// corpus.
1096 ///
1097 /// @return the map of function symbols not defined in this corpus.
1098 /// The key of the map is the name of the function symbol.  The value
1099 /// is a vector of all the function symbols that have the same name.
1100 const string_elf_symbols_map_type&
get_undefined_fun_symbol_map() const1101 corpus::get_undefined_fun_symbol_map() const
1102 {return priv_->get_undefined_fun_symbol_map();}
1103 
1104 /// Return a sorted vector of function symbols for this corpus.
1105 ///
1106 /// Note that the first time this function is called, the symbols are
1107 /// sorted and cached.  Subsequent invocations of this function return
1108 /// the cached vector that was built previously.
1109 ///
1110 /// @return the sorted list of function symbols.
1111 const elf_symbols&
get_sorted_fun_symbols() const1112 corpus::get_sorted_fun_symbols() const
1113 {return priv_->get_sorted_fun_symbols();}
1114 
1115 /// Getter for a sorted vector of the function symbols undefined in
1116 /// this corpus.
1117 ///
1118 /// @return a vector of the function symbols undefined in this corpus,
1119 /// sorted by name and then version.
1120 const elf_symbols&
get_sorted_undefined_fun_symbols() const1121 corpus::get_sorted_undefined_fun_symbols() const
1122 {return priv_->get_sorted_undefined_fun_symbols();}
1123 
1124 /// Getter for the sorted vector of variable symbols for this corpus.
1125 ///
1126 /// Note that the first time this function is called, it computes the
1127 /// sorted vector, caches the result and returns it.  Subsequent
1128 /// invocations of this function just return the cached vector.
1129 ///
1130 /// @return the sorted vector of variable symbols for this corpus.
1131 const elf_symbols&
get_sorted_var_symbols() const1132 corpus::get_sorted_var_symbols() const
1133 {return priv_->get_sorted_var_symbols();}
1134 
1135 /// Getter for a sorted vector of the variable symbols undefined in
1136 /// this corpus.
1137 ///
1138 /// @return a vector of the variable symbols undefined in this corpus,
1139 /// sorted by name and then version.
1140 const elf_symbols&
get_sorted_undefined_var_symbols() const1141 corpus::get_sorted_undefined_var_symbols() const
1142 {return priv_->get_sorted_undefined_var_symbols();}
1143 
1144 /// Getter for the variable symbols map.
1145 ///
1146 /// @return a reference to the variabl symbols map.
1147 const string_elf_symbols_map_type&
get_var_symbol_map() const1148 corpus::get_var_symbol_map() const
1149 {return priv_->get_var_symbol_map();}
1150 
1151 /// Getter for the map of variable symbols that are undefined in this
1152 /// corpus.
1153 ///
1154 /// @return the map of variable symbols not defined in this corpus.
1155 /// The key of the map is the name of the variable symbol.  The value
1156 /// is a vector of all the variable symbols that have the same name.
1157 const string_elf_symbols_map_type&
get_undefined_var_symbol_map() const1158 corpus::get_undefined_var_symbol_map() const
1159 {return priv_->get_undefined_var_symbol_map();}
1160 
1161 /// Look in the function symbols map for a symbol with a given name.
1162 ///
1163 /// @param n the name of the symbol to look for.
1164 ///
1165 /// return the first symbol with the name @p n.
1166 const elf_symbol_sptr
lookup_function_symbol(const string & n) const1167 corpus::lookup_function_symbol(const string& n) const
1168 {
1169   if (get_fun_symbol_map().empty())
1170     return elf_symbol_sptr();
1171 
1172   string_elf_symbols_map_type::const_iterator it =
1173     get_fun_symbol_map().find(n);
1174   if ( it == get_fun_symbol_map().end())
1175     return elf_symbol_sptr();
1176   return it->second[0];
1177 }
1178 
1179 /// Look into a set of symbols and look for a symbol that has a given
1180 /// version.
1181 ///
1182 /// This is a sub-routine for corpus::lookup_function_symbol() and
1183 /// corpus::lookup_variable_symbol().
1184 ///
1185 /// @param version the version of the symbol to look for.
1186 ///
1187 /// @param symbols the set of symbols to consider.
1188 ///
1189 /// @return the symbol found, or nil if none was found.
1190 static const elf_symbol_sptr
find_symbol_by_version(const elf_symbol::version & version,const vector<elf_symbol_sptr> & symbols)1191 find_symbol_by_version(const elf_symbol::version& version,
1192 		       const vector<elf_symbol_sptr>& symbols)
1193 {
1194   if (version.is_empty())
1195     {
1196       // We are looing for a symbol with no version.
1197 
1198       // So first look for possible aliases with no version
1199       for (elf_symbols::const_iterator s = symbols.begin();
1200 	   s != symbols.end();
1201 	   ++s)
1202 	if ((*s)->get_version().is_empty())
1203 	  return *s;
1204 
1205       // Or, look for a version that is a default one!
1206       for (elf_symbols::const_iterator s = symbols.begin();
1207 	   s != symbols.end();
1208 	   ++s)
1209 	if ((*s)->get_version().is_default())
1210 	  return *s;
1211     }
1212   else
1213     // We are looking for a symbol with a particular defined version.
1214     for (elf_symbols::const_iterator s = symbols.begin();
1215 	 s != symbols.end();
1216 	 ++s)
1217       if ((*s)->get_version().str() == version.str())
1218 	return *s;
1219 
1220   return elf_symbol_sptr();
1221 }
1222 
1223 /// Look in the function symbols map for a symbol with a given name.
1224 ///
1225 /// @param symbol_name the name of the symbol to look for.
1226 ///
1227 /// @param version the version of the symbol to look for.
1228 ///
1229 /// return the symbol with name @p symbol_name and with version @p
1230 /// version, or nil if no symbol has been found with that name and
1231 /// version.
1232 const elf_symbol_sptr
lookup_function_symbol(const string & symbol_name,const elf_symbol::version & version) const1233 corpus::lookup_function_symbol(const string& symbol_name,
1234 			       const elf_symbol::version& version) const
1235 {
1236   if (get_fun_symbol_map().empty())
1237     return elf_symbol_sptr();
1238 
1239   string_elf_symbols_map_type::const_iterator it =
1240     get_fun_symbol_map().find(symbol_name);
1241   if ( it == get_fun_symbol_map().end())
1242     return elf_symbol_sptr();
1243 
1244   return find_symbol_by_version(version, it->second);
1245 }
1246 
1247 /// Look in the function symbols map for a symbol with the same name
1248 /// and version as a given symbol.
1249 ///
1250 /// @param symbol the symbol to look for.
1251 ///
1252 /// return the symbol with the same name and version as @p symbol.
1253 const elf_symbol_sptr
lookup_function_symbol(const elf_symbol & symbol) const1254 corpus::lookup_function_symbol(const elf_symbol& symbol) const
1255 {return lookup_function_symbol(symbol.get_name(), symbol.get_version());}
1256 
1257 /// Look in the variable symbols map for a symbol with a given name.
1258 ///
1259 /// @param n the name of the symbol to look for.
1260 ///
1261 /// return the first symbol with the name @p n.
1262 const elf_symbol_sptr
lookup_variable_symbol(const string & n) const1263 corpus::lookup_variable_symbol(const string& n) const
1264 {
1265   if (get_var_symbol_map().empty())
1266     return elf_symbol_sptr();
1267 
1268   string_elf_symbols_map_type::const_iterator it =
1269     get_var_symbol_map().find(n);
1270   if ( it == get_var_symbol_map().end())
1271     return elf_symbol_sptr();
1272   return it->second[0];
1273 }
1274 
1275 /// Look in the variable symbols map for a symbol with a given name.
1276 ///
1277 /// @param symbol_name the name of the symbol to look for.
1278 ///
1279 /// @param symbol_version the version of the symbol to look for.
1280 ///
1281 /// return the first symbol with the name @p symbol_name and with
1282 /// version @p version.
1283 const elf_symbol_sptr
lookup_variable_symbol(const string & symbol_name,const elf_symbol::version & version) const1284 corpus::lookup_variable_symbol(const string& symbol_name,
1285 			       const elf_symbol::version& version) const
1286 {
1287   if (get_var_symbol_map().empty())
1288     return elf_symbol_sptr();
1289 
1290   string_elf_symbols_map_type::const_iterator it =
1291     get_var_symbol_map().find(symbol_name);
1292   if ( it == get_var_symbol_map().end())
1293     return elf_symbol_sptr();
1294 
1295   return find_symbol_by_version(version, it->second);
1296 }
1297 
1298 /// Look in the variable symbols map for a symbol with the same name
1299 /// and version as a given symbol.
1300 ///
1301 /// @param symbol the symbol to look for.
1302 ///
1303 /// return the symbol with the same name and version as @p symbol.
1304 const elf_symbol_sptr
lookup_variable_symbol(const elf_symbol & symbol) const1305 corpus::lookup_variable_symbol(const elf_symbol& symbol) const
1306 {return lookup_variable_symbol(symbol.get_name(), symbol.get_version());}
1307 
1308 /// Return the functions public decl table of the current corpus.
1309 ///
1310 /// The function public decl tables is a vector of all the functions
1311 /// and member functions found in the current corpus.
1312 ///
1313 /// Note that the caller can suppress some functions from the vector
1314 /// supplying regular expressions describing the set of functions she
1315 /// want to see removed from the public decl table by populating the
1316 /// vector of regular expressions returned by
1317 /// corpus::get_regex_patterns_of_fns_to_suppress().
1318 ///
1319 /// @return the vector of functions of the public decl table.  The
1320 /// functions are sorted using their mangled name or name if they
1321 /// don't have mangle names.
1322 const corpus::functions&
get_functions() const1323 corpus::get_functions() const
1324 {return priv_->fns;}
1325 
1326 /// Lookup the function which has a given function ID.
1327 ///
1328 /// Note that there can have been several functions with the same ID.
1329 /// This is because debug info can declare the same function in
1330 /// several different translation units.  Normally, all these function
1331 /// should be equal.  But still, this function returns all these
1332 /// functions.
1333 ///
1334 /// @param id the ID of the function to lookup.  This ID must be
1335 /// either the result of invoking function::get_id() of
1336 /// elf_symbol::get_id_string().
1337 ///
1338 /// @return the vector functions which ID is @p id, or nil if no
1339 /// function with that ID was found.
1340 const std::unordered_set<function_decl*>*
lookup_functions(const string & id) const1341 corpus::lookup_functions(const string& id) const
1342 {
1343   exported_decls_builder_sptr b = get_exported_decls_builder();
1344   auto i = b->priv_->id_fns_map_.find(id);
1345   if (i == b->priv_->id_fns_map_.end())
1346     return 0;
1347   return &i->second;
1348 }
1349 
1350 /// Sort the set of functions exported by this corpus.
1351 ///
1352 /// Normally, you shouldn't be calling this as the code that creates
1353 /// the corpus for you should do it for you too.
1354 void
sort_functions()1355 corpus::sort_functions()
1356 {
1357   func_comp fc;
1358   std::sort(priv_->fns.begin(), priv_->fns.end(), fc);
1359 }
1360 
1361 /// Return the public decl table of the global variables of the
1362 /// current corpus.
1363 ///
1364 /// The variable public decls table is a vector of all the public
1365 /// global variables and static member variables found in the current
1366 /// corpus.
1367 ///
1368 /// Note that the caller can suppress some variables from the vector
1369 /// supplying regular expressions describing the set of variables she
1370 /// wants to see removed from the public decl table by populating the
1371 /// vector of regular expressions returned by
1372 /// corpus::get_regex_patterns_of_fns_to_suppress().
1373 ///
1374 /// @return the vector of variables of the public decl table.  The
1375 /// variables are sorted using their name.
1376 const corpus::variables&
get_variables() const1377 corpus::get_variables() const
1378 {return priv_->vars;}
1379 
1380 /// Sort the set of variables exported by this corpus.
1381 ///
1382 /// Normally, you shouldn't be calling this as the code that creates
1383 /// the corpus for you should do it for you too.
1384 void
sort_variables()1385 corpus::sort_variables()
1386 {
1387   var_comp vc;
1388   std::sort(priv_->vars.begin(), priv_->vars.end(), vc);
1389 }
1390 
1391 /// Getter of the set of function symbols that are not referenced by
1392 /// any function exported by the current corpus.
1393 ///
1394 /// When the corpus has been created from an ELF library or program,
1395 /// this function returns the set of function symbols not referenced
1396 /// by any debug information.
1397 ///
1398 /// @return the vector of function symbols not referenced by any
1399 /// function exported by the current corpus.
1400 const elf_symbols&
get_unreferenced_function_symbols() const1401 corpus::get_unreferenced_function_symbols() const
1402 {return priv_->get_unreferenced_function_symbols();}
1403 
1404 /// Getter of the set of variable symbols that are not referenced by
1405 /// any variable exported by the current corpus.
1406 ///
1407 /// When the corpus has been created from an ELF library or program,
1408 /// this function returns the set of variable symbols not referenced
1409 /// by any debug information.
1410 ///
1411 /// @return the vector of variable symbols not referenced by any
1412 /// variable exported by the current corpus.
1413 const elf_symbols&
get_unreferenced_variable_symbols() const1414 corpus::get_unreferenced_variable_symbols() const
1415 {return priv_->get_unreferenced_variable_symbols();}
1416 
1417 /// Accessor for the regex patterns describing the functions to drop
1418 /// from the public decl table.
1419 ///
1420 /// @return the regex patterns describing the functions to drop from
1421 /// the public decl table.
1422 vector<string>&
get_regex_patterns_of_fns_to_suppress()1423 corpus::get_regex_patterns_of_fns_to_suppress()
1424 {return priv_->regex_patterns_fns_to_suppress;}
1425 
1426 /// Accessor for the regex patterns describing the functions to drop
1427 /// from the public decl table.
1428 ///
1429 /// @return the regex patterns describing the functions to drop from
1430 /// the public decl table.
1431 const vector<string>&
get_regex_patterns_of_fns_to_suppress() const1432 corpus::get_regex_patterns_of_fns_to_suppress() const
1433 {return priv_->regex_patterns_fns_to_suppress;}
1434 
1435 /// Accessor for the regex patterns describing the variables to drop
1436 /// from the public decl table.
1437 ///
1438 /// @return the regex patterns describing the variables to drop from
1439 /// the public decl table.
1440 vector<string>&
get_regex_patterns_of_vars_to_suppress()1441 corpus::get_regex_patterns_of_vars_to_suppress()
1442 {return priv_->regex_patterns_vars_to_suppress;}
1443 
1444 /// Accessor for the regex patterns describing the variables to drop
1445 /// from the public decl table.
1446 ///
1447 /// @return the regex patterns describing the variables to drop from
1448 /// the public decl table.
1449 const vector<string>&
get_regex_patterns_of_vars_to_suppress() const1450 corpus::get_regex_patterns_of_vars_to_suppress() const
1451 {return priv_->regex_patterns_vars_to_suppress;}
1452 
1453 /// Accessor for the regex patterns describing the functions to keep
1454 /// into the public decl table.  The other functions not matches by these
1455 /// regexes are dropped from the public decl table.
1456 ///
1457 /// @return the regex patterns describing the functions to keep into
1458 /// the public decl table.
1459 vector<string>&
get_regex_patterns_of_fns_to_keep()1460 corpus::get_regex_patterns_of_fns_to_keep()
1461 {return priv_->regex_patterns_fns_to_keep;}
1462 
1463 /// Accessor for the regex patterns describing the functions to keep
1464 /// into the public decl table.  The other functions not matches by these
1465 /// regexes are dropped from the public decl table.
1466 ///
1467 /// @return the regex patterns describing the functions to keep into
1468 /// the public decl table.
1469 const vector<string>&
get_regex_patterns_of_fns_to_keep() const1470 corpus::get_regex_patterns_of_fns_to_keep() const
1471 {return priv_->regex_patterns_fns_to_keep;}
1472 
1473 /// Getter for the vector of function symbol IDs to keep.
1474 ///
1475 /// A symbol ID is a string made of the name of the symbol and its
1476 /// version, separated by one or two '@'.
1477 ///
1478 /// @return a vector of IDs of function symbols to keep.
1479 vector<string>&
get_sym_ids_of_fns_to_keep()1480 corpus::get_sym_ids_of_fns_to_keep()
1481 {return priv_->sym_id_fns_to_keep;}
1482 
1483 /// Getter for the vector of function symbol IDs to keep.
1484 ///
1485 /// A symbol ID is a string made of the name of the symbol and its
1486 /// version, separated by one or two '@'.
1487 ///
1488 /// @return a vector of IDs of function symbols to keep.
1489 const vector<string>&
get_sym_ids_of_fns_to_keep() const1490 corpus::get_sym_ids_of_fns_to_keep() const
1491 {return priv_->sym_id_fns_to_keep;}
1492 
1493 /// Accessor for the regex patterns describing the variables to keep
1494 /// into the public decl table.  The other variables not matches by these
1495 /// regexes are dropped from the public decl table.
1496 ///
1497 /// @return the regex patterns describing the variables to keep into
1498 /// the public decl table.
1499 vector<string>&
get_regex_patterns_of_vars_to_keep()1500 corpus::get_regex_patterns_of_vars_to_keep()
1501 {return priv_->regex_patterns_vars_to_keep;}
1502 
1503 /// Accessor for the regex patterns describing the variables to keep
1504 /// into the public decl table.  The other variables not matches by these
1505 /// regexes are dropped from the public decl table.
1506 ///
1507 /// @return the regex patterns describing the variables to keep into
1508 /// the public decl table.
1509 const vector<string>&
get_regex_patterns_of_vars_to_keep() const1510 corpus::get_regex_patterns_of_vars_to_keep() const
1511 {return priv_->regex_patterns_vars_to_keep;}
1512 
1513 /// Getter for the vector of variable symbol IDs to keep.
1514 ///
1515 /// A symbol ID is a string made of the name of the symbol and its
1516 /// version, separated by one or two '@'.
1517 ///
1518 /// @return a vector of IDs of variable symbols to keep.
1519 vector<string>&
get_sym_ids_of_vars_to_keep()1520 corpus::get_sym_ids_of_vars_to_keep()
1521 {return priv_->sym_id_vars_to_keep;}
1522 
1523 /// Getter for the vector of variable symbol IDs to keep.
1524 ///
1525 /// A symbol ID is a string made of the name of the symbol and its
1526 /// version, separated by one or two '@'.
1527 ///
1528 /// @return a vector of IDs of variable symbols to keep.
1529 const vector<string>&
get_sym_ids_of_vars_to_keep() const1530 corpus::get_sym_ids_of_vars_to_keep() const
1531 {return priv_->sym_id_vars_to_keep;}
1532 
1533 /// After the set of exported functions and variables have been built,
1534 /// consider all the tunables that control that set and see if some
1535 /// functions need to be removed from that set; if so, remove them.
1536 void
maybe_drop_some_exported_decls()1537 corpus::maybe_drop_some_exported_decls()
1538 {
1539   string sym_name, sym_version;
1540 
1541   vector<function_decl*> fns_to_keep;
1542   exported_decls_builder* b = get_exported_decls_builder().get();
1543   for (vector<function_decl*>::iterator f = priv_->fns.begin();
1544        f != priv_->fns.end();
1545        ++f)
1546     {
1547       if (b->priv_->keep_wrt_id_of_fns_to_keep(*f)
1548 	  && b->priv_->keep_wrt_regex_of_fns_to_suppress(*f)
1549 	  && b->priv_->keep_wrt_regex_of_fns_to_keep(*f))
1550 	fns_to_keep.push_back(*f);
1551     }
1552   priv_->fns = fns_to_keep;
1553 
1554   vector<var_decl*> vars_to_keep;
1555   for (vector<var_decl*>::iterator v = priv_->vars.begin();
1556        v != priv_->vars.end();
1557        ++v)
1558     {
1559       if (b->priv_->keep_wrt_id_of_vars_to_keep(*v)
1560 	  && b->priv_->keep_wrt_regex_of_vars_to_suppress(*v)
1561 	  && b->priv_->keep_wrt_regex_of_vars_to_keep(*v))
1562 	vars_to_keep.push_back(*v);
1563     }
1564   priv_->vars = vars_to_keep;
1565 }
1566 
1567 ///  Getter for the object that is responsible for determining what
1568 ///  decls ought to be in the set of exported decls.
1569 ///
1570 ///  The object does have methods to add the decls to the set of
1571 ///  exported decls, right at the place where the corpus expects it,
1572 ///  so that there is no unnecessary copying involved.
1573 ///
1574 ///  @return a (smart) pointer to the instance of @ref
1575 ///  corpus::exported_decls_builder that is responsible for determine
1576 ///  what decls ought to be in the set of exported decls.
1577 corpus::exported_decls_builder_sptr
get_exported_decls_builder() const1578 corpus::get_exported_decls_builder() const
1579 {
1580   if (!priv_->exported_decls_builder)
1581     {
1582       priv_->exported_decls_builder.reset
1583 	(new exported_decls_builder(priv_->fns,
1584 				    priv_->vars,
1585 				    priv_->regex_patterns_fns_to_suppress,
1586 				    priv_->regex_patterns_vars_to_suppress,
1587 				    priv_->regex_patterns_fns_to_keep,
1588 				    priv_->regex_patterns_vars_to_keep,
1589 				    priv_->sym_id_fns_to_keep,
1590 				    priv_->sym_id_vars_to_keep));
1591     }
1592   return priv_->exported_decls_builder;
1593 }
1594 
1595 /// Bitwise | operator for the corpus::origin type.
1596 ///
1597 /// @param l the left-hand side operand of the | operation.
1598 ///
1599 /// @param r the right-hand side operand of the | operation.
1600 ///
1601 /// @return the result of the operation.
1602 corpus::origin
operator |(corpus::origin l,corpus::origin r)1603 operator|(corpus::origin l, corpus::origin r)
1604 {
1605   return static_cast<corpus::origin>
1606     (static_cast<uint32_t>(l) |  static_cast<uint32_t>(r));
1607 }
1608 
1609 /// Bitwise |= operator for the corpus::origin type.
1610 ///
1611 /// @param l the left-hand side operand for the |= operation.
1612 ///
1613 /// @param r the right-hand side operand for the |= operation.
1614 ///
1615 /// @return the result of the operation.
1616 corpus::origin
operator |=(corpus::origin & l,corpus::origin r)1617 operator|=(corpus::origin &l, corpus::origin r)
1618 {
1619   l = l | r;
1620   return l;
1621 }
1622 
1623 /// Bitwise & operator for the corpus::origin type.
1624 ///
1625 /// @param l the left-hand side operand of the & operation.
1626 ///
1627 /// @param r the right-hand side operand of the & operation.
1628 ///
1629 /// @return the result of the operation.
1630 corpus::origin
operator &(corpus::origin l,corpus::origin r)1631 operator&(corpus::origin l, corpus::origin r)
1632 {
1633     return static_cast<corpus::origin>
1634     (static_cast<uint32_t>(l) & static_cast<uint32_t>(r));
1635 }
1636 
1637 /// Bitwise &= operator for the corpus::origin type.
1638 ///
1639 /// @param l the left-hand side operand of the &= operation.
1640 ///
1641 /// @param r the right-hand side operand of the &= operation.
1642 ///
1643 /// @return the result of the operation.
1644 corpus::origin
operator &=(corpus::origin & l,corpus::origin r)1645 operator&=(corpus::origin &l, corpus::origin r)
1646 {
1647   l = l & r;
1648   return l;
1649 }
1650 
1651 // </corpus stuff>
1652 
1653 // <corpus_group stuff>
1654 
1655 /// Type of the private data of @ref corpus_group
1656 struct corpus_group::priv
1657 {
1658   std::set<string>		corpora_paths;
1659   corpora_type			corpora;
1660   istring_function_decl_ptr_map_type fns_map;
1661   vector<function_decl*>	fns;
1662   istring_var_decl_ptr_map_type vars_map;
1663   vector<var_decl*>		vars;
1664   string_elf_symbols_map_type	var_symbol_map;
1665   string_elf_symbols_map_type	fun_symbol_map;
1666   elf_symbols			sorted_var_symbols;
1667   elf_symbols			sorted_fun_symbols;
1668   unordered_map<string, elf_symbol_sptr> unrefed_fun_symbol_map;
1669   elf_symbols			unrefed_fun_symbols;
1670   bool				unrefed_fun_symbols_built;
1671   unordered_map<string, elf_symbol_sptr> unrefed_var_symbol_map;
1672   elf_symbols			unrefed_var_symbols;
1673   bool				unrefed_var_symbols_built;
1674   unordered_set<interned_string, hash_interned_string> pub_type_pretty_reprs_;
1675 
privabigail::ir::corpus_group::priv1676   priv()
1677     : unrefed_fun_symbols_built(),
1678       unrefed_var_symbols_built()
1679   {}
1680 
1681   /// Add symbols to the set of corpus group function symbols that are
1682   /// *NOT* referenced by debug info.
1683   ///
1684   /// @param syms the set the symbols to add.
1685   void
add_unref_fun_symbolsabigail::ir::corpus_group::priv1686   add_unref_fun_symbols(const elf_symbols& syms)
1687   {
1688     for (elf_symbols::const_iterator e =
1689 	   syms.begin(); e != syms.end(); ++e)
1690       {
1691 	string sym_id = (*e)->get_id_string();
1692 	unordered_map<string, elf_symbol_sptr>::const_iterator j =
1693 	  unrefed_fun_symbol_map.find(sym_id);
1694 	if (j != unrefed_fun_symbol_map.end())
1695 	  continue;
1696 
1697 	unrefed_fun_symbol_map[sym_id] = *e;
1698 	unrefed_fun_symbols.push_back(*e);
1699       }
1700     unrefed_fun_symbols_built = true;
1701   }
1702 
1703   /// Add symbols to the set of corpus group variable symbols that are
1704   /// *NOT* referenced by debug info.
1705   ///
1706   /// @param syms the set the symbols to add.
1707   void
add_unref_var_symbolsabigail::ir::corpus_group::priv1708   add_unref_var_symbols(const elf_symbols& syms)
1709   {
1710     for (elf_symbols::const_iterator e =
1711 	   syms.begin(); e != syms.end(); ++e)
1712       {
1713 	string sym_id = (*e)->get_id_string();
1714 	unordered_map<string, elf_symbol_sptr>::const_iterator j =
1715 	  unrefed_var_symbol_map.find(sym_id);
1716 	if (j != unrefed_var_symbol_map.end())
1717 	  continue;
1718 
1719 	unrefed_var_symbol_map[sym_id] = *e;
1720 	unrefed_var_symbols.push_back(*e);
1721       }
1722     unrefed_var_symbols_built = true;
1723   }
1724 }; // end corpus_group::priv
1725 
1726 /// Constructor of the @ref corpus_group type.
1727 ///
1728 /// @param env the environment of the @ref corpus_group.
1729 ///
1730 /// @param path the path to the file represented by the corpus group.
corpus_group(const environment & env,const string & path="")1731 corpus_group::corpus_group(const environment& env, const string& path = "")
1732   : corpus(env, path), priv_(new priv)
1733 {}
1734 
1735 /// Desctructor of the @ref corpus_group type.
~corpus_group()1736 corpus_group::~corpus_group()
1737 {}
1738 
1739 /// Add a new corpus to the current instance of @ref corpus_group.
1740 ///
1741 /// @param corp the new corpus to add.
1742 void
add_corpus(const corpus_sptr & corp)1743 corpus_group::add_corpus(const corpus_sptr& corp)
1744 {
1745   if (!corp)
1746     return;
1747 
1748   if (!corp->get_path().empty()
1749       && has_corpus(corp->get_path()))
1750     return;
1751 
1752   // Ensure the new architecture name matches the current one.
1753   string cur_arch = get_architecture_name(),
1754     corp_arch = corp->get_architecture_name();
1755   if (cur_arch.empty())
1756     set_architecture_name(corp_arch);
1757   else if (cur_arch != corp_arch)
1758     {
1759       std::cerr << "corpus '" << corp->get_path() << "'"
1760 		<< " has architecture '" << corp_arch << "'"
1761 		<< " but expected '" << cur_arch << "'\n";
1762       ABG_ASSERT_NOT_REACHED;
1763     }
1764 
1765   priv_->corpora.push_back(corp);
1766   corp->set_group(this);
1767   priv_->corpora_paths.insert(corp->get_path());
1768 
1769   /// Add the unreferenced function and variable symbols of this
1770   /// corpus to the unreferenced symbols of the current corpus group.
1771   priv_->add_unref_fun_symbols(get_unreferenced_function_symbols());
1772   priv_->add_unref_var_symbols(get_unreferenced_variable_symbols());
1773 }
1774 
1775 /// Test if a corpus of a given path has been added to the group.
1776 ///
1777 /// @param path the path to the corpus to consider.
1778 ///
1779 /// @return true iff a corpus with path @p path is already present in
1780 /// the group⋅
1781 bool
has_corpus(const string & path)1782 corpus_group::has_corpus(const string& path)
1783 {
1784   if (priv_->corpora_paths.find(path) != priv_->corpora_paths.end())
1785     return true;
1786   return false;
1787 }
1788 
1789 /// Getter of the vector of corpora held by the current @ref
1790 /// corpus_group.
1791 ///
1792 /// @return the vector corpora.
1793 const corpus_group::corpora_type&
get_corpora() const1794 corpus_group::get_corpora() const
1795 {return priv_->corpora;}
1796 
1797 /// Getter of the first corpus added to this Group.
1798 ///
1799 /// @return the first corpus added to this Group.
1800 const corpus_sptr
get_main_corpus() const1801 corpus_group::get_main_corpus() const
1802 {return const_cast<corpus_group*>(this)->get_main_corpus();}
1803 
1804 /// Getter of the first corpus added to this Group.
1805 ///
1806 /// @return the first corpus added to this Group.
1807 corpus_sptr
get_main_corpus()1808 corpus_group::get_main_corpus()
1809 {
1810   if (!get_corpora().empty())
1811     return get_corpora().front();
1812   return corpus_sptr();
1813 }
1814 
1815 /// Test if the current corpus group is empty.
1816 ///
1817 /// @return true iff the current corpus group is empty.
1818 bool
is_empty() const1819 corpus_group::is_empty() const
1820 {return get_corpora().empty();}
1821 
1822 /// Get the functions exported by the corpora of the current corpus
1823 /// group.
1824 ///
1825 /// Upon its first invocation, this function walks the corpora
1826 /// contained in the corpus group and caches the functions they exported.
1827 ///
1828 /// Subsequent invocations just return the cached functions.
1829 ///
1830 /// @return the exported functions.
1831 const corpus::functions&
get_functions() const1832 corpus_group::get_functions() const
1833 {
1834   if (priv_->fns.empty())
1835     for (corpora_type::const_iterator i = get_corpora().begin();
1836 	 i != get_corpora().end();
1837 	 ++i)
1838       {
1839 	corpus_sptr c = *i;
1840 	for (corpus::functions::const_iterator f = c->get_functions().begin();
1841 	     f != c->get_functions().end();
1842 	     ++f)
1843 	  {
1844 	    interned_string fid = (*f)->get_id();
1845 	    istring_function_decl_ptr_map_type::const_iterator j =
1846 	      priv_->fns_map.find(fid);
1847 
1848 	    if (j != priv_->fns_map.end())
1849 	      // Don't cache the same function twice ...
1850 	      continue;
1851 
1852 	    priv_->fns_map[fid] = *f;
1853 	    // really cache the function now.
1854 	    priv_->fns.push_back(*f);
1855 	  }
1856       }
1857 
1858   return priv_->fns;
1859 }
1860 
1861 /// Get the global variables exported by the corpora of the current
1862 /// corpus group.
1863 ///
1864 /// Upon its first invocation, this function walks the corpora
1865 /// contained in the corpus group and caches the variables they
1866 /// export.
1867 ///
1868 /// @return the exported variables.
1869 const corpus::variables&
get_variables() const1870 corpus_group::get_variables() const
1871 {
1872   if (priv_->vars.empty())
1873     for (corpora_type::const_iterator i = get_corpora().begin();
1874 	 i != get_corpora().end();
1875 	 ++i)
1876       {
1877 	corpus_sptr c = *i;
1878 	for (corpus::variables::const_iterator v = c->get_variables().begin();
1879 	     v != c->get_variables().end();
1880 	     ++v)
1881 	  {
1882 	    interned_string vid = (*v)->get_id();
1883 	    istring_var_decl_ptr_map_type::const_iterator j =
1884 	      priv_->vars_map.find(vid);
1885 
1886 	    if (j != priv_->vars_map.end())
1887 	      // Don't cache the same variable twice ...
1888 	      continue;
1889 
1890 	    priv_->vars_map[vid] = *v;
1891 	    // Really cache the variable now.
1892 	    priv_->vars.push_back(*v);
1893 	  }
1894       }
1895 
1896   return priv_->vars;
1897 }
1898 
1899 /// Get the symbols of the global variables exported by the corpora of
1900 /// the current @ref corpus_group.
1901 ///
1902 /// @return the symbols of the global variables exported by the corpora
1903 const string_elf_symbols_map_type&
get_var_symbol_map() const1904 corpus_group::get_var_symbol_map() const
1905 {
1906   if (priv_->var_symbol_map.empty())
1907     for (corpora_type::const_iterator i = get_corpora().begin();
1908 	 i != get_corpora().end();
1909 	 ++i)
1910       priv_->var_symbol_map.insert((*i)->get_var_symbol_map().begin(),
1911 				     (*i)->get_var_symbol_map().end());
1912 
1913   return priv_->var_symbol_map;
1914 }
1915 
1916 /// Get the symbols of the global functions exported by the corpora of
1917 /// the current @ref corpus_group.
1918 ///
1919 /// @return the symbols of the global functions exported by the corpora
1920 const string_elf_symbols_map_type&
get_fun_symbol_map() const1921 corpus_group::get_fun_symbol_map() const
1922 {
1923   if (priv_->fun_symbol_map.empty())
1924     for (corpora_type::const_iterator i = get_corpora().begin();
1925 	 i != get_corpora().end();
1926 	 ++i)
1927       priv_->fun_symbol_map.insert((*i)->get_fun_symbol_map().begin(),
1928 				   (*i)->get_fun_symbol_map().end());
1929 
1930   return priv_->fun_symbol_map;
1931 }
1932 
1933 /// Get a sorted vector of the symbols of the functions exported by
1934 /// the corpora of the current group.
1935 ///
1936 /// @return the sorted vectors of the exported function symbols.
1937 const elf_symbols&
get_sorted_fun_symbols() const1938 corpus_group::get_sorted_fun_symbols() const
1939 {
1940   if (priv_->sorted_fun_symbols.empty()
1941       && !get_fun_symbol_map().empty())
1942     {
1943       for (corpora_type::const_iterator i = get_corpora().begin();
1944 	   i != get_corpora().end();
1945 	   ++i)
1946 	{
1947 	  corpus_sptr c = *i;
1948 	  for (string_elf_symbols_map_type::const_iterator j =
1949 		 c->get_fun_symbol_map().begin();
1950 	       j != c->get_fun_symbol_map().begin();
1951 	       ++j)
1952 	    priv_->sorted_fun_symbols.insert(priv_->sorted_fun_symbols.end(),
1953 					     j->second.begin(),
1954 					     j->second.end());
1955 	}
1956       comp_elf_symbols_functor comp;
1957       std::sort(priv_->sorted_fun_symbols.begin(),
1958 		priv_->sorted_fun_symbols.end(),
1959 		comp);
1960     }
1961 
1962   return priv_->sorted_fun_symbols;
1963 }
1964 
1965 /// Get a sorted vector of the symbols of the variables exported by
1966 /// the corpora of the current group.
1967 ///
1968 /// @return the sorted vectors of the exported variable symbols.
1969 const elf_symbols&
get_sorted_var_symbols() const1970 corpus_group::get_sorted_var_symbols() const
1971 {
1972   if (priv_->sorted_var_symbols.empty()
1973       && !get_var_symbol_map().empty())
1974     {
1975       for (corpora_type::const_iterator i = get_corpora().begin();
1976 	   i != get_corpora().end();
1977 	   ++i)
1978 	{
1979 	  corpus_sptr c = *i;
1980 	  for (string_elf_symbols_map_type::const_iterator j =
1981 		 c->get_var_symbol_map().begin();
1982 	       j != c->get_var_symbol_map().begin();
1983 	       ++j)
1984 	    priv_->sorted_var_symbols.insert(priv_->sorted_var_symbols.end(),
1985 					     j->second.begin(),
1986 					     j->second.end());
1987 	}
1988       comp_elf_symbols_functor comp;
1989       std::sort(priv_->sorted_var_symbols.begin(),
1990 		priv_->sorted_var_symbols.end(),
1991 		comp);
1992     }
1993 
1994   return priv_->sorted_var_symbols;
1995 }
1996 
1997 /// Get the set of function symbols not referenced by any debug info,
1998 /// from all the corpora of the current corpus group.
1999 ///
2000 /// Upon its first invocation, this function possibly walks all the
2001 /// copora of this corpus group and caches the unreferenced symbols
2002 /// they export.  The function then returns the cache.
2003 ///
2004 /// Upon subsequent invocations, this functions just returns the
2005 /// cached symbols.
2006 ///
2007 /// @return the unreferenced symbols.
2008 const elf_symbols&
get_unreferenced_function_symbols() const2009 corpus_group::get_unreferenced_function_symbols() const
2010 {
2011   if (!priv_->unrefed_fun_symbols_built)
2012     if (priv_->unrefed_fun_symbols.empty())
2013       {
2014 	for (corpora_type::const_iterator i = get_corpora().begin();
2015 	     i != get_corpora().end();
2016 	     ++i)
2017 	  {
2018 	    corpus_sptr c = *i;
2019 	    for (elf_symbols::const_iterator e =
2020 		   c->get_unreferenced_function_symbols().begin();
2021 		 e != c->get_unreferenced_function_symbols().end();
2022 		 ++e)
2023 	      {
2024 		string sym_id = (*e)->get_id_string();
2025 		unordered_map<string, elf_symbol_sptr>::const_iterator j =
2026 		  priv_->unrefed_fun_symbol_map.find(sym_id);
2027 		if (j != priv_->unrefed_fun_symbol_map.end())
2028 		  continue;
2029 
2030 		priv_->unrefed_fun_symbol_map[sym_id] = *e;
2031 		priv_->unrefed_fun_symbols.push_back(*e);
2032 	      }
2033 	  }
2034 	priv_->unrefed_fun_symbols_built = true;
2035       }
2036 
2037   return priv_->unrefed_fun_symbols;
2038 }
2039 
2040 /// Get the set of variable symbols not referenced by any debug info,
2041 /// from all the corpora of the current corpus group.
2042 ///
2043 /// Upon its first invocation, this function possibly walks all the
2044 /// copora of this corpus group and caches the unreferenced symbols
2045 /// they export.  The function then returns the cache.
2046 ///
2047 /// Upon subsequent invocations, this functions just returns the
2048 /// cached symbols.
2049 ///
2050 /// @return the unreferenced symbols.
2051 const elf_symbols&
get_unreferenced_variable_symbols() const2052 corpus_group::get_unreferenced_variable_symbols() const
2053 {
2054   if (!priv_->unrefed_var_symbols_built)
2055     if (priv_->unrefed_var_symbols.empty())
2056       {
2057 	for (corpora_type::const_iterator i = get_corpora().begin();
2058 	     i != get_corpora().end();
2059 	     ++i)
2060 	  {
2061 	    corpus_sptr c = *i;
2062 	    for (elf_symbols::const_iterator e =
2063 		   c->get_unreferenced_variable_symbols().begin();
2064 		 e != c->get_unreferenced_variable_symbols().end();
2065 		 ++e)
2066 	      {
2067 		string sym_id = (*e)->get_id_string();
2068 		unordered_map<string, elf_symbol_sptr>::const_iterator j =
2069 		  priv_->unrefed_var_symbol_map.find(sym_id);
2070 		if (j != priv_->unrefed_var_symbol_map.end())
2071 		  continue;
2072 
2073 		priv_->unrefed_var_symbol_map[sym_id] = *e;
2074 		priv_->unrefed_var_symbols.push_back(*e);
2075 	      }
2076 	  }
2077 	priv_->unrefed_var_symbols_built = true;
2078       }
2079 
2080   return priv_->unrefed_var_symbols;
2081 }
2082 
2083 /// Getter of a pointer to the set of types reachable from public
2084 /// interfaces of a given corpus group.
2085 unordered_set<interned_string, hash_interned_string>*
get_public_types_pretty_representations()2086 corpus_group::get_public_types_pretty_representations()
2087 {return &priv_->pub_type_pretty_reprs_;}
2088 
2089 /// Test if the recording of reachable types (and thus, indirectly,
2090 /// the recording of non-reachable types) is activated for the
2091 /// current @ref corpus_group.
2092 ///
2093 /// @return true iff the recording of reachable types is activated for
2094 /// the current @ref corpus_group.
2095 bool
recording_types_reachable_from_public_interface_supported()2096 corpus_group::recording_types_reachable_from_public_interface_supported()
2097 {return !get_public_types_pretty_representations()->empty();}
2098 
2099 // </corpus_group stuff>
2100 
2101 }// end namespace ir
2102 }// end namespace abigail
2103