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