xref: /third_party/libabigail/src/abg-corpus.cc (revision e01aa904)
1// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
2// -*- mode: C++ -*-
3//
4// Copyright (C) 2013-2022 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>
20ABG_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
30ABG_END_EXPORT_DECLARATIONS
31// </headers defining libabigail's API>
32
33#include "abg-corpus-priv.h"
34#include "abg-ir-priv.h"
35
36namespace abigail
37{
38
39namespace ir
40{
41
42using std::ostringstream;
43using std::unordered_map;
44using std::list;
45using std::vector;
46
47using 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.
75corpus::exported_decls_builder
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.
99const corpus::functions&
100corpus::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.
108corpus::functions&
109corpus::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.
117const corpus::variables&
118corpus::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.
126corpus::variables&
127corpus::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.
135void
136corpus::exported_decls_builder::maybe_add_fn_to_exported_fns(const 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.
158void
159corpus::exported_decls_builder::maybe_add_var_to_exported_vars(const 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.
180typedef 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.
187typedef 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.
190typedef 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.
197struct 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
211  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.
233struct 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
245  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.
278struct comp_elf_symbols_functor
279{
280  bool
281  operator()(const elf_symbol& l,
282	     const elf_symbol& r) const
283  {return l.get_id_string() < r.get_id_string();}
284
285  bool
286  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.
295type_maps&
296corpus::priv::get_types()
297{return types_;}
298
299/// Get the maps that associate a name to a certain kind of type.
300const type_maps&
301corpus::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.
311const elf_symbols&
312corpus::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
330const string_elf_symbols_map_type&
331corpus::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.
347const elf_symbols&
348corpus::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
370const string_elf_symbols_map_type&
371corpus::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
392const elf_symbols&
393corpus::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.
444const elf_symbols&
445corpus::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
464const string_elf_symbols_map_type&
465corpus::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.
481const elf_symbols&
482corpus::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
504const string_elf_symbols_map_type&
505corpus::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
526const elf_symbols&
527corpus::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).
576unordered_set<interned_string, hash_interned_string>*
577corpus::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.
589corpus::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.
599corpus::corpus(const ir::environment& env, const string& path)
600{
601  priv_.reset(new priv(path, env));
602  init_format_version();
603}
604
605corpus::~corpus() = default;
606
607/// Getter of the enviroment of the corpus.
608///
609/// @return the environment of this corpus.
610const environment&
611corpus::get_environment() const
612{return priv_->env;}
613
614/// Add a translation unit to the current ABI Corpus.
615///
616/// Note that two translation units with the same path (as returned by
617/// translation_unit::get_path) cannot be added to the same @ref
618/// corpus.  If that happens, the library aborts.
619///
620/// @param tu the new translation unit to add.
621void
622corpus::add(const translation_unit_sptr& tu)
623{
624  ABG_ASSERT(priv_->members.insert(tu).second);
625
626  if (!tu->get_absolute_path().empty())
627    {
628      // Update the path -> translation_unit map.
629      string_tu_map_type::const_iterator i =
630	priv_->path_tu_map.find(tu->get_absolute_path());
631      ABG_ASSERT(i == priv_->path_tu_map.end());
632      priv_->path_tu_map[tu->get_absolute_path()] = tu;
633    }
634
635  tu->set_corpus(this);
636}
637
638/// Return the list of translation units of the current corpus.
639///
640/// @return the list of translation units of the current corpus.
641const translation_units&
642corpus::get_translation_units() const
643{return priv_->members;}
644
645/// Find the translation unit that has a given path.
646///
647/// @param path the path of the translation unit to look for.
648///
649/// @return the translation unit found, if any.  Otherwise, return
650/// nil.
651const translation_unit_sptr
652corpus::find_translation_unit(const string &path) const
653{
654  string_tu_map_type::const_iterator i =
655    priv_->path_tu_map.find(path);
656
657  if (i == priv_->path_tu_map.end())
658    return translation_unit_sptr();
659  return i->second;
660}
661
662/// Erase the translation units contained in this in-memory object.
663///
664/// Note that the on-disk archive file that contains the serialized
665/// representation of this object is not modified.
666void
667corpus::drop_translation_units()
668{priv_->members.clear();}
669
670/// Get the maps that associate a name to a certain kind of type.
671///
672/// @return the maps that associate a name to a certain kind of type.
673type_maps&
674corpus::get_types()
675{return priv_->types_;}
676
677/// Get the maps that associate a name to a certain kind of type.
678///
679/// @return the maps that associate a name to a certain kind of
680/// type.
681const type_maps&
682corpus::get_types() const
683{return priv_->types_;}
684
685/// Get the maps that associate a location string to a certain kind of
686/// type.
687///
688/// The location string is the result of the invocation to the
689/// function abigail::ir::location::expand().  It has the form
690/// "file.c:4:1", with 'file.c' being the file name, '4' being the
691/// line number and '1' being the column number.
692///
693/// @return the maps.
694const type_maps&
695corpus::get_type_per_loc_map() const
696{return priv_->type_per_loc_map_;}
697
698/// Test if the recording of reachable types (and thus, indirectly,
699/// the recording of non-reachable types) is activated for the
700/// current @ref corpus.
701///
702/// @return true iff the recording of reachable types is activated for
703/// the current @ref corpus.
704bool
705corpus::recording_types_reachable_from_public_interface_supported()
706{
707  return (priv_->get_public_types_pretty_representations()
708	  && !priv_->get_public_types_pretty_representations()->empty());
709}
710
711/// Record a type as being reachable from public interfaces (global
712/// functions and variables).
713///
714/// @param t the type to record as reachable.
715void
716corpus::record_type_as_reachable_from_public_interfaces(const type_base& t)
717{
718  string repr = get_pretty_representation(&t, /*internal=*/true);
719  interned_string s = t.get_environment().intern(repr);
720  priv_->get_public_types_pretty_representations()->insert(s);
721}
722
723/// Test if a type is reachable from public interfaces (global
724/// functions and variables).
725///
726/// For a type to be considered reachable from public interfaces, it
727/// must have been previously marked as such by calling
728/// corpus::record_type_as_reachable_from_public_interfaces.
729///
730/// @param t the type to test for.
731///
732/// @return true iff @p t is reachable from public interfaces.
733bool
734corpus::type_is_reachable_from_public_interfaces(const type_base& t) const
735{
736  string repr = get_pretty_representation(&t, /*internal=*/true);
737  interned_string s = t.get_environment().intern(repr);
738
739  return (priv_->get_public_types_pretty_representations()->find(s)
740	  !=  priv_->get_public_types_pretty_representations()->end());
741}
742
743/// Getter of a sorted vector of the types that are *NOT* reachable
744/// from public interfaces.
745///
746/// Note that for this to be non-empty, the libabigail reader that
747/// analyzed the input (be it a binary or an abixml file) must have be
748/// configured to load types that are not reachable from public
749/// interfaces.
750///
751/// @return a reference to a vector of sorted types NON reachable from
752/// public interfaces.
753const vector<type_base_wptr>&
754corpus::get_types_not_reachable_from_public_interfaces() const
755{
756  if (priv_->types_not_reachable_from_pub_ifaces_.empty())
757    {
758      const type_maps& types = get_types();
759      for (vector<type_base_wptr>::const_iterator it =
760	     types.get_types_sorted_by_name().begin();
761	   it != types.get_types_sorted_by_name().end();
762	   ++it)
763	{
764	  type_base_sptr t(*it);
765	  if (!type_is_reachable_from_public_interfaces(*t))
766	    priv_->types_not_reachable_from_pub_ifaces_.push_back(t);
767	}
768    }
769
770  return priv_->types_not_reachable_from_pub_ifaces_;
771}
772
773/// Get the maps that associate a location string to a certain kind of
774/// type.
775///
776/// The location string is the result of the invocation to the
777/// function abigail::ir::location::expand().  It has the form
778/// "file.c:4:1", with 'file.c' being the file name, '4' being the
779/// line number and '1' being the column number.
780///
781/// @return the maps.
782type_maps&
783corpus::get_type_per_loc_map()
784{return priv_->type_per_loc_map_;}
785
786/// Getter of the group this corpus is a member of.
787///
788/// @return the group this corpus is a member of, or nil if it's not
789/// part of any @ref corpus_group.
790const corpus_group*
791corpus::get_group() const
792{return priv_->group;}
793
794/// Getter of the group this corpus belongs to.
795///
796/// @return the group this corpus belong to, or nil if it's not part
797/// of any @ref corpus_group.
798corpus_group*
799corpus::get_group()
800{return priv_->group;}
801
802/// Setter of the group this corpus belongs to.
803///
804/// @param g the new group.
805void
806corpus::set_group(corpus_group* g)
807{priv_->group = g;}
808
809/// Initialize the abixml serialization format version number of the
810/// corpus.
811///
812/// This function sets the format version number ot the default one
813/// supported by the current version of Libabigail.
814void
815corpus::init_format_version()
816{
817  set_format_major_version_number
818    (priv_->env.get_config().get_format_major_version_number());
819  set_format_minor_version_number
820    (priv_->env.get_config().get_format_minor_version_number());
821}
822
823/// Getter for the origin of the corpus.
824///
825/// @return the origin of the corpus.
826corpus::origin
827corpus::get_origin() const
828{return priv_->origin_;}
829
830/// Setter for the origin of the corpus.
831///
832/// @param o the new origin for the corpus.
833void
834corpus::set_origin(origin o)
835{priv_->origin_ = o;}
836
837/// Getter of the major version number of the abixml serialization
838/// format.
839///
840/// @return the major version number of the abixml format.
841string&
842corpus::get_format_major_version_number() const
843{return priv_->format_major_version_number_;}
844
845/// Setter of the major version number of the abixml serialization
846/// format.
847///
848/// @param maj the new major version numberof the abixml format.
849void
850corpus::set_format_major_version_number(const string& maj)
851{priv_->format_major_version_number_ = maj;}
852
853/// Getter of the minor version number of the abixml serialization
854/// format.
855///
856/// @return the minor version number of the abixml serialization
857/// format.
858string&
859corpus::get_format_minor_version_number() const
860{return priv_->format_minor_version_number_;}
861
862/// Setter of the minor version number of the abixml serialization
863/// format.
864///
865/// @param min the new minor version number of the abixml
866/// serialization format.
867void
868corpus::set_format_minor_version_number(const string& min)
869{priv_->format_minor_version_number_ = min;}
870
871/// Get the file path associated to the corpus file.
872///
873/// A subsequent call to corpus::read will deserialize the content of
874/// the abi file expected at this path; likewise, a call to
875/// corpus::write will serialize the translation units contained in
876/// the corpus object into the on-disk file at this path.
877///
878/// @return the file path associated to the current corpus.
879string&
880corpus::get_path() const
881{return priv_->path;}
882
883/// Set the file path associated to the corpus file.
884///
885/// A subsequent call to corpus::read will deserialize the content of
886/// the abi file expected at this path; likewise, a call to
887/// corpus::write will serialize the translation units contained in
888/// the corpus object into the on-disk file at this path.
889///
890/// @param path the new file path to assciate to the current corpus.
891void
892corpus::set_path(const string& path)
893{priv_->path = path;}
894
895/// Getter of the needed property of the corpus.
896///
897/// This property is meaningful for, e.g, corpora built from ELF
898/// shared library files.  In that case, this is a vector of names of
899/// dependencies of the ELF shared library file.
900///
901/// @return the vector of dependencies needed by this corpus.
902const vector<string>&
903corpus::get_needed() const
904{return priv_->needed;}
905
906/// Setter of the needed property of the corpus.
907///
908/// This property is meaningful for, e.g, corpora built from ELF
909/// shared library files.  In that case, this is a vector of names of
910/// dependencies of the ELF shared library file.
911///
912/// @param needed the new vector of dependencies needed by this
913/// corpus.
914void
915corpus::set_needed(const vector<string>& needed)
916{priv_->needed = needed;}
917
918/// Getter for the soname property of the corpus.
919///
920/// This property is meaningful for, e.g, corpora built from ELF
921/// shared library files.  In that case, this is the shared object
922/// name exported by the shared library.
923///
924/// @return the soname property of the corpus.
925const string&
926corpus::get_soname()
927{return priv_->soname;}
928
929/// Setter for the soname property of the corpus.
930///
931/// This property is meaningful for, e.g, corpora built from ELF
932/// shared library files.  In that case, this is the shared object
933/// name exported by the shared library.
934///
935/// @param soname the new soname property of the corpus.
936void
937corpus::set_soname(const string& soname)
938{priv_->soname = soname;}
939
940/// Getter for the architecture name of the corpus.
941///
942/// This property is meaningful for e.g, corpora built from ELF shared
943/// library files.  In that case, this is a string representation of
944/// the Elf{32,64}_Ehdr::e_machine field.
945///
946/// @return the architecture name string.
947const string&
948corpus::get_architecture_name() const
949{return priv_->architecture_name;}
950
951/// Setter for the architecture name of the corpus.
952///
953/// This property is meaningful for e.g, corpora built from ELF shared
954/// library files.  In that case, this is a string representation of
955/// the Elf{32,64}_Ehdr::e_machine field.
956///
957/// @param arch the architecture name string.
958void
959corpus::set_architecture_name(const string& arch)
960{priv_->architecture_name = arch;}
961
962/// Tests if the corpus is empty from an ABI surface perspective. I.e. if all
963/// of these criteria are true:
964///  - all translation units (members) are empty
965///  - the maps function and variable symbols are not having entries
966///  - for shared libraries:
967///    - the soname is empty
968///    - there are no DT_NEEDED entries
969///
970/// @return true if the corpus contains no translation unit.
971bool
972corpus::is_empty() const
973{
974  bool members_empty = true;
975  for (translation_units::const_iterator i = priv_->members.begin(),
976					 e = priv_->members.end();
977       i != e; ++i)
978    {
979      if (!(*i)->is_empty())
980	{
981	  members_empty = false;
982	  break;
983	}
984    }
985  return (members_empty
986	  && (!get_symtab() || !get_symtab()->has_symbols())
987	  && priv_->soname.empty()
988	  && priv_->needed.empty()
989	  && priv_->architecture_name.empty()
990	  && !priv_->group);
991}
992
993/// Compare the current @ref corpus against another one.
994///
995/// @param other the other corpus to compare against.
996///
997/// @return true if the two corpus are equal, false otherwise.
998bool
999corpus::operator==(const corpus& other) const
1000{
1001  translation_units::const_iterator i, j;
1002  for (i = get_translation_units().begin(),
1003	 j = other.get_translation_units().begin();
1004       (i != get_translation_units().end()
1005	&& j != other.get_translation_units().end());
1006       ++i, ++j)
1007    if ((**i) != (**j))
1008      return false;
1009
1010  return (i == get_translation_units().end()
1011	  && j == other.get_translation_units().end());
1012}
1013
1014/// Setter for the symtab object.
1015///
1016/// @param symtab a shared pointer to the new symtab object
1017void
1018corpus::set_symtab(symtab_reader::symtab_sptr symtab)
1019{priv_->symtab_ = symtab;}
1020
1021/// Getter for the symtab object.
1022///
1023/// @return a shared pointer to the symtab object
1024const symtab_reader::symtab_sptr&
1025corpus::get_symtab() const
1026{return priv_->symtab_;}
1027
1028/// Getter for the function symbols map.
1029///
1030/// @return a reference to the function symbols map.
1031const string_elf_symbols_map_type&
1032corpus::get_fun_symbol_map() const
1033{return priv_->get_fun_symbol_map();}
1034
1035/// Getter for the map of function symbols that are undefined in this
1036/// corpus.
1037///
1038/// @return the map of function symbols not defined in this corpus.
1039/// The key of the map is the name of the function symbol.  The value
1040/// is a vector of all the function symbols that have the same name.
1041const string_elf_symbols_map_type&
1042corpus::get_undefined_fun_symbol_map() const
1043{return priv_->get_undefined_fun_symbol_map();}
1044
1045/// Return a sorted vector of function symbols for this corpus.
1046///
1047/// Note that the first time this function is called, the symbols are
1048/// sorted and cached.  Subsequent invocations of this function return
1049/// the cached vector that was built previously.
1050///
1051/// @return the sorted list of function symbols.
1052const elf_symbols&
1053corpus::get_sorted_fun_symbols() const
1054{return priv_->get_sorted_fun_symbols();}
1055
1056/// Getter for a sorted vector of the function symbols undefined in
1057/// this corpus.
1058///
1059/// @return a vector of the function symbols undefined in this corpus,
1060/// sorted by name and then version.
1061const elf_symbols&
1062corpus::get_sorted_undefined_fun_symbols() const
1063{return priv_->get_sorted_undefined_fun_symbols();}
1064
1065/// Getter for the sorted vector of variable symbols for this corpus.
1066///
1067/// Note that the first time this function is called, it computes the
1068/// sorted vector, caches the result and returns it.  Subsequent
1069/// invocations of this function just return the cached vector.
1070///
1071/// @return the sorted vector of variable symbols for this corpus.
1072const elf_symbols&
1073corpus::get_sorted_var_symbols() const
1074{return priv_->get_sorted_var_symbols();}
1075
1076/// Getter for a sorted vector of the variable symbols undefined in
1077/// this corpus.
1078///
1079/// @return a vector of the variable symbols undefined in this corpus,
1080/// sorted by name and then version.
1081const elf_symbols&
1082corpus::get_sorted_undefined_var_symbols() const
1083{return priv_->get_sorted_undefined_var_symbols();}
1084
1085/// Getter for the variable symbols map.
1086///
1087/// @return a reference to the variabl symbols map.
1088const string_elf_symbols_map_type&
1089corpus::get_var_symbol_map() const
1090{return priv_->get_var_symbol_map();}
1091
1092/// Getter for the map of variable symbols that are undefined in this
1093/// corpus.
1094///
1095/// @return the map of variable symbols not defined in this corpus.
1096/// The key of the map is the name of the variable symbol.  The value
1097/// is a vector of all the variable symbols that have the same name.
1098const string_elf_symbols_map_type&
1099corpus::get_undefined_var_symbol_map() const
1100{return priv_->get_undefined_var_symbol_map();}
1101
1102/// Look in the function symbols map for a symbol with a given name.
1103///
1104/// @param n the name of the symbol to look for.
1105///
1106/// return the first symbol with the name @p n.
1107const elf_symbol_sptr
1108corpus::lookup_function_symbol(const string& n) const
1109{
1110  if (get_fun_symbol_map().empty())
1111    return elf_symbol_sptr();
1112
1113  string_elf_symbols_map_type::const_iterator it =
1114    get_fun_symbol_map().find(n);
1115  if ( it == get_fun_symbol_map().end())
1116    return elf_symbol_sptr();
1117  return it->second[0];
1118}
1119
1120/// Look into a set of symbols and look for a symbol that has a given
1121/// version.
1122///
1123/// This is a sub-routine for corpus::lookup_function_symbol() and
1124/// corpus::lookup_variable_symbol().
1125///
1126/// @param version the version of the symbol to look for.
1127///
1128/// @param symbols the set of symbols to consider.
1129///
1130/// @return the symbol found, or nil if none was found.
1131static const elf_symbol_sptr
1132find_symbol_by_version(const elf_symbol::version& version,
1133		       const vector<elf_symbol_sptr>& symbols)
1134{
1135  if (version.is_empty())
1136    {
1137      // We are looing for a symbol with no version.
1138
1139      // So first look for possible aliases with no version
1140      for (elf_symbols::const_iterator s = symbols.begin();
1141	   s != symbols.end();
1142	   ++s)
1143	if ((*s)->get_version().is_empty())
1144	  return *s;
1145
1146      // Or, look for a version that is a default one!
1147      for (elf_symbols::const_iterator s = symbols.begin();
1148	   s != symbols.end();
1149	   ++s)
1150	if ((*s)->get_version().is_default())
1151	  return *s;
1152    }
1153  else
1154    // We are looking for a symbol with a particular defined version.
1155    for (elf_symbols::const_iterator s = symbols.begin();
1156	 s != symbols.end();
1157	 ++s)
1158      if ((*s)->get_version().str() == version.str())
1159	return *s;
1160
1161  return elf_symbol_sptr();
1162}
1163
1164/// Look in the function symbols map for a symbol with a given name.
1165///
1166/// @param symbol_name the name of the symbol to look for.
1167///
1168/// @param version the version of the symbol to look for.
1169///
1170/// return the symbol with name @p symbol_name and with version @p
1171/// version, or nil if no symbol has been found with that name and
1172/// version.
1173const elf_symbol_sptr
1174corpus::lookup_function_symbol(const string& symbol_name,
1175			       const elf_symbol::version& version) const
1176{
1177  if (get_fun_symbol_map().empty())
1178    return elf_symbol_sptr();
1179
1180  string_elf_symbols_map_type::const_iterator it =
1181    get_fun_symbol_map().find(symbol_name);
1182  if ( it == get_fun_symbol_map().end())
1183    return elf_symbol_sptr();
1184
1185  return find_symbol_by_version(version, it->second);
1186}
1187
1188/// Look in the function symbols map for a symbol with the same name
1189/// and version as a given symbol.
1190///
1191/// @param symbol the symbol to look for.
1192///
1193/// return the symbol with the same name and version as @p symbol.
1194const elf_symbol_sptr
1195corpus::lookup_function_symbol(const elf_symbol& symbol) const
1196{return lookup_function_symbol(symbol.get_name(), symbol.get_version());}
1197
1198/// Look in the variable symbols map for a symbol with a given name.
1199///
1200/// @param n the name of the symbol to look for.
1201///
1202/// return the first symbol with the name @p n.
1203const elf_symbol_sptr
1204corpus::lookup_variable_symbol(const string& n) const
1205{
1206  if (get_var_symbol_map().empty())
1207    return elf_symbol_sptr();
1208
1209  string_elf_symbols_map_type::const_iterator it =
1210    get_var_symbol_map().find(n);
1211  if ( it == get_var_symbol_map().end())
1212    return elf_symbol_sptr();
1213  return it->second[0];
1214}
1215
1216/// Look in the variable symbols map for a symbol with a given name.
1217///
1218/// @param symbol_name the name of the symbol to look for.
1219///
1220/// @param symbol_version the version of the symbol to look for.
1221///
1222/// return the first symbol with the name @p symbol_name and with
1223/// version @p version.
1224const elf_symbol_sptr
1225corpus::lookup_variable_symbol(const string& symbol_name,
1226			       const elf_symbol::version& version) const
1227{
1228  if (get_var_symbol_map().empty())
1229    return elf_symbol_sptr();
1230
1231  string_elf_symbols_map_type::const_iterator it =
1232    get_var_symbol_map().find(symbol_name);
1233  if ( it == get_var_symbol_map().end())
1234    return elf_symbol_sptr();
1235
1236  return find_symbol_by_version(version, it->second);
1237}
1238
1239/// Look in the variable symbols map for a symbol with the same name
1240/// and version as a given symbol.
1241///
1242/// @param symbol the symbol to look for.
1243///
1244/// return the symbol with the same name and version as @p symbol.
1245const elf_symbol_sptr
1246corpus::lookup_variable_symbol(const elf_symbol& symbol) const
1247{return lookup_variable_symbol(symbol.get_name(), symbol.get_version());}
1248
1249/// Return the functions public decl table of the current corpus.
1250///
1251/// The function public decl tables is a vector of all the functions
1252/// and member functions found in the current corpus.
1253///
1254/// Note that the caller can suppress some functions from the vector
1255/// supplying regular expressions describing the set of functions she
1256/// want to see removed from the public decl table by populating the
1257/// vector of regular expressions returned by
1258/// corpus::get_regex_patterns_of_fns_to_suppress().
1259///
1260/// @return the vector of functions of the public decl table.  The
1261/// functions are sorted using their mangled name or name if they
1262/// don't have mangle names.
1263const corpus::functions&
1264corpus::get_functions() const
1265{return priv_->fns;}
1266
1267/// Lookup the function which has a given function ID.
1268///
1269/// Note that there can have been several functions with the same ID.
1270/// This is because debug info can declare the same function in
1271/// several different translation units.  Normally, all these function
1272/// should be equal.  But still, this function returns all these
1273/// functions.
1274///
1275/// @param id the ID of the function to lookup.  This ID must be
1276/// either the result of invoking function::get_id() of
1277/// elf_symbol::get_id_string().
1278///
1279/// @return the vector functions which ID is @p id, or nil if no
1280/// function with that ID was found.
1281const vector<function_decl*>*
1282corpus::lookup_functions(const string& id) const
1283{
1284  exported_decls_builder_sptr b = get_exported_decls_builder();
1285  str_fn_ptrs_map_type::const_iterator i =
1286    b->priv_->id_fns_map_.find(id);
1287  if (i == b->priv_->id_fns_map_.end())
1288    return 0;
1289  return &i->second;
1290}
1291
1292/// Sort the set of functions exported by this corpus.
1293///
1294/// Normally, you shouldn't be calling this as the code that creates
1295/// the corpus for you should do it for you too.
1296void
1297corpus::sort_functions()
1298{
1299  func_comp fc;
1300  std::sort(priv_->fns.begin(), priv_->fns.end(), fc);
1301}
1302
1303/// Return the public decl table of the global variables of the
1304/// current corpus.
1305///
1306/// The variable public decls table is a vector of all the public
1307/// global variables and static member variables found in the current
1308/// corpus.
1309///
1310/// Note that the caller can suppress some variables from the vector
1311/// supplying regular expressions describing the set of variables she
1312/// wants to see removed from the public decl table by populating the
1313/// vector of regular expressions returned by
1314/// corpus::get_regex_patterns_of_fns_to_suppress().
1315///
1316/// @return the vector of variables of the public decl table.  The
1317/// variables are sorted using their name.
1318const corpus::variables&
1319corpus::get_variables() const
1320{return priv_->vars;}
1321
1322/// Sort the set of variables exported by this corpus.
1323///
1324/// Normally, you shouldn't be calling this as the code that creates
1325/// the corpus for you should do it for you too.
1326void
1327corpus::sort_variables()
1328{
1329  var_comp vc;
1330  std::sort(priv_->vars.begin(), priv_->vars.end(), vc);
1331}
1332
1333/// Getter of the set of function symbols that are not referenced by
1334/// any function exported by the current corpus.
1335///
1336/// When the corpus has been created from an ELF library or program,
1337/// this function returns the set of function symbols not referenced
1338/// by any debug information.
1339///
1340/// @return the vector of function symbols not referenced by any
1341/// function exported by the current corpus.
1342const elf_symbols&
1343corpus::get_unreferenced_function_symbols() const
1344{return priv_->get_unreferenced_function_symbols();}
1345
1346/// Getter of the set of variable symbols that are not referenced by
1347/// any variable exported by the current corpus.
1348///
1349/// When the corpus has been created from an ELF library or program,
1350/// this function returns the set of variable symbols not referenced
1351/// by any debug information.
1352///
1353/// @return the vector of variable symbols not referenced by any
1354/// variable exported by the current corpus.
1355const elf_symbols&
1356corpus::get_unreferenced_variable_symbols() const
1357{return priv_->get_unreferenced_variable_symbols();}
1358
1359/// Accessor for the regex patterns describing the functions to drop
1360/// from the public decl table.
1361///
1362/// @return the regex patterns describing the functions to drop from
1363/// the public decl table.
1364vector<string>&
1365corpus::get_regex_patterns_of_fns_to_suppress()
1366{return priv_->regex_patterns_fns_to_suppress;}
1367
1368/// Accessor for the regex patterns describing the functions to drop
1369/// from the public decl table.
1370///
1371/// @return the regex patterns describing the functions to drop from
1372/// the public decl table.
1373const vector<string>&
1374corpus::get_regex_patterns_of_fns_to_suppress() const
1375{return priv_->regex_patterns_fns_to_suppress;}
1376
1377/// Accessor for the regex patterns describing the variables to drop
1378/// from the public decl table.
1379///
1380/// @return the regex patterns describing the variables to drop from
1381/// the public decl table.
1382vector<string>&
1383corpus::get_regex_patterns_of_vars_to_suppress()
1384{return priv_->regex_patterns_vars_to_suppress;}
1385
1386/// Accessor for the regex patterns describing the variables to drop
1387/// from the public decl table.
1388///
1389/// @return the regex patterns describing the variables to drop from
1390/// the public decl table.
1391const vector<string>&
1392corpus::get_regex_patterns_of_vars_to_suppress() const
1393{return priv_->regex_patterns_vars_to_suppress;}
1394
1395/// Accessor for the regex patterns describing the functions to keep
1396/// into the public decl table.  The other functions not matches by these
1397/// regexes are dropped from the public decl table.
1398///
1399/// @return the regex patterns describing the functions to keep into
1400/// the public decl table.
1401vector<string>&
1402corpus::get_regex_patterns_of_fns_to_keep()
1403{return priv_->regex_patterns_fns_to_keep;}
1404
1405/// Accessor for the regex patterns describing the functions to keep
1406/// into the public decl table.  The other functions not matches by these
1407/// regexes are dropped from the public decl table.
1408///
1409/// @return the regex patterns describing the functions to keep into
1410/// the public decl table.
1411const vector<string>&
1412corpus::get_regex_patterns_of_fns_to_keep() const
1413{return priv_->regex_patterns_fns_to_keep;}
1414
1415/// Getter for the vector of function symbol IDs to keep.
1416///
1417/// A symbol ID is a string made of the name of the symbol and its
1418/// version, separated by one or two '@'.
1419///
1420/// @return a vector of IDs of function symbols to keep.
1421vector<string>&
1422corpus::get_sym_ids_of_fns_to_keep()
1423{return priv_->sym_id_fns_to_keep;}
1424
1425/// Getter for the vector of function symbol IDs to keep.
1426///
1427/// A symbol ID is a string made of the name of the symbol and its
1428/// version, separated by one or two '@'.
1429///
1430/// @return a vector of IDs of function symbols to keep.
1431const vector<string>&
1432corpus::get_sym_ids_of_fns_to_keep() const
1433{return priv_->sym_id_fns_to_keep;}
1434
1435/// Accessor for the regex patterns describing the variables to keep
1436/// into the public decl table.  The other variables not matches by these
1437/// regexes are dropped from the public decl table.
1438///
1439/// @return the regex patterns describing the variables to keep into
1440/// the public decl table.
1441vector<string>&
1442corpus::get_regex_patterns_of_vars_to_keep()
1443{return priv_->regex_patterns_vars_to_keep;}
1444
1445/// Accessor for the regex patterns describing the variables to keep
1446/// into the public decl table.  The other variables not matches by these
1447/// regexes are dropped from the public decl table.
1448///
1449/// @return the regex patterns describing the variables to keep into
1450/// the public decl table.
1451const vector<string>&
1452corpus::get_regex_patterns_of_vars_to_keep() const
1453{return priv_->regex_patterns_vars_to_keep;}
1454
1455/// Getter for the vector of variable symbol IDs to keep.
1456///
1457/// A symbol ID is a string made of the name of the symbol and its
1458/// version, separated by one or two '@'.
1459///
1460/// @return a vector of IDs of variable symbols to keep.
1461vector<string>&
1462corpus::get_sym_ids_of_vars_to_keep()
1463{return priv_->sym_id_vars_to_keep;}
1464
1465/// Getter for the vector of variable symbol IDs to keep.
1466///
1467/// A symbol ID is a string made of the name of the symbol and its
1468/// version, separated by one or two '@'.
1469///
1470/// @return a vector of IDs of variable symbols to keep.
1471const vector<string>&
1472corpus::get_sym_ids_of_vars_to_keep() const
1473{return priv_->sym_id_vars_to_keep;}
1474
1475/// After the set of exported functions and variables have been built,
1476/// consider all the tunables that control that set and see if some
1477/// functions need to be removed from that set; if so, remove them.
1478void
1479corpus::maybe_drop_some_exported_decls()
1480{
1481  string sym_name, sym_version;
1482
1483  vector<function_decl*> fns_to_keep;
1484  exported_decls_builder* b = get_exported_decls_builder().get();
1485  for (vector<function_decl*>::iterator f = priv_->fns.begin();
1486       f != priv_->fns.end();
1487       ++f)
1488    {
1489      if (b->priv_->keep_wrt_id_of_fns_to_keep(*f)
1490	  && b->priv_->keep_wrt_regex_of_fns_to_suppress(*f)
1491	  && b->priv_->keep_wrt_regex_of_fns_to_keep(*f))
1492	fns_to_keep.push_back(*f);
1493    }
1494  priv_->fns = fns_to_keep;
1495
1496  vector<var_decl*> vars_to_keep;
1497  for (vector<var_decl*>::iterator v = priv_->vars.begin();
1498       v != priv_->vars.end();
1499       ++v)
1500    {
1501      if (b->priv_->keep_wrt_id_of_vars_to_keep(*v)
1502	  && b->priv_->keep_wrt_regex_of_vars_to_suppress(*v)
1503	  && b->priv_->keep_wrt_regex_of_vars_to_keep(*v))
1504	vars_to_keep.push_back(*v);
1505    }
1506  priv_->vars = vars_to_keep;
1507}
1508
1509///  Getter for the object that is responsible for determining what
1510///  decls ought to be in the set of exported decls.
1511///
1512///  The object does have methods to add the decls to the set of
1513///  exported decls, right at the place where the corpus expects it,
1514///  so that there is no unnecessary copying involved.
1515///
1516///  @return a (smart) pointer to the instance of @ref
1517///  corpus::exported_decls_builder that is responsible for determine
1518///  what decls ought to be in the set of exported decls.
1519corpus::exported_decls_builder_sptr
1520corpus::get_exported_decls_builder() const
1521{
1522  if (!priv_->exported_decls_builder)
1523    {
1524      priv_->exported_decls_builder.reset
1525	(new exported_decls_builder(priv_->fns,
1526				    priv_->vars,
1527				    priv_->regex_patterns_fns_to_suppress,
1528				    priv_->regex_patterns_vars_to_suppress,
1529				    priv_->regex_patterns_fns_to_keep,
1530				    priv_->regex_patterns_vars_to_keep,
1531				    priv_->sym_id_fns_to_keep,
1532				    priv_->sym_id_vars_to_keep));
1533    }
1534  return priv_->exported_decls_builder;
1535}
1536
1537/// Bitwise | operator for the corpus::origin type.
1538///
1539/// @param l the left-hand side operand of the | operation.
1540///
1541/// @param r the right-hand side operand of the | operation.
1542///
1543/// @return the result of the operation.
1544corpus::origin
1545operator|(corpus::origin l, corpus::origin r)
1546{
1547  return static_cast<corpus::origin>
1548    (static_cast<uint32_t>(l) |  static_cast<uint32_t>(r));
1549}
1550
1551/// Bitwise |= operator for the corpus::origin type.
1552///
1553/// @param l the left-hand side operand for the |= operation.
1554///
1555/// @param r the right-hand side operand for the |= operation.
1556///
1557/// @return the result of the operation.
1558corpus::origin
1559operator|=(corpus::origin &l, corpus::origin r)
1560{
1561  l = l | r;
1562  return l;
1563}
1564
1565/// Bitwise & operator for the corpus::origin type.
1566///
1567/// @param l the left-hand side operand of the & operation.
1568///
1569/// @param r the right-hand side operand of the & operation.
1570///
1571/// @return the result of the operation.
1572corpus::origin
1573operator&(corpus::origin l, corpus::origin r)
1574{
1575    return static_cast<corpus::origin>
1576    (static_cast<uint32_t>(l) & static_cast<uint32_t>(r));
1577}
1578
1579/// Bitwise &= operator for the corpus::origin type.
1580///
1581/// @param l the left-hand side operand of the &= operation.
1582///
1583/// @param r the right-hand side operand of the &= operation.
1584///
1585/// @return the result of the operation.
1586corpus::origin
1587operator&=(corpus::origin &l, corpus::origin r)
1588{
1589  l = l & r;
1590  return l;
1591}
1592
1593// </corpus stuff>
1594
1595// <corpus_group stuff>
1596
1597/// Type of the private data of @ref corpus_group
1598struct corpus_group::priv
1599{
1600  corpora_type			corpora;
1601  istring_function_decl_ptr_map_type fns_map;
1602  vector<function_decl*>	fns;
1603  istring_var_decl_ptr_map_type vars_map;
1604  vector<var_decl*>		vars;
1605  string_elf_symbols_map_type	var_symbol_map;
1606  string_elf_symbols_map_type	fun_symbol_map;
1607  elf_symbols			sorted_var_symbols;
1608  elf_symbols			sorted_fun_symbols;
1609  unordered_map<string, elf_symbol_sptr> unrefed_fun_symbol_map;
1610  elf_symbols			unrefed_fun_symbols;
1611  bool				unrefed_fun_symbols_built;
1612  unordered_map<string, elf_symbol_sptr> unrefed_var_symbol_map;
1613  elf_symbols			unrefed_var_symbols;
1614  bool				unrefed_var_symbols_built;
1615  unordered_set<interned_string, hash_interned_string> pub_type_pretty_reprs_;
1616
1617  priv()
1618    : unrefed_fun_symbols_built(),
1619      unrefed_var_symbols_built()
1620  {}
1621
1622  /// Add symbols to the set of corpus group function symbols that are
1623  /// *NOT* referenced by debug info.
1624  ///
1625  /// @param syms the set the symbols to add.
1626  void
1627  add_unref_fun_symbols(const elf_symbols& syms)
1628  {
1629    for (elf_symbols::const_iterator e =
1630	   syms.begin(); e != syms.end(); ++e)
1631      {
1632	string sym_id = (*e)->get_id_string();
1633	unordered_map<string, elf_symbol_sptr>::const_iterator j =
1634	  unrefed_fun_symbol_map.find(sym_id);
1635	if (j != unrefed_fun_symbol_map.end())
1636	  continue;
1637
1638	unrefed_fun_symbol_map[sym_id] = *e;
1639	unrefed_fun_symbols.push_back(*e);
1640      }
1641    unrefed_fun_symbols_built = true;
1642  }
1643
1644  /// Add symbols to the set of corpus group variable symbols that are
1645  /// *NOT* referenced by debug info.
1646  ///
1647  /// @param syms the set the symbols to add.
1648  void
1649  add_unref_var_symbols(const elf_symbols& syms)
1650  {
1651    for (elf_symbols::const_iterator e =
1652	   syms.begin(); e != syms.end(); ++e)
1653      {
1654	string sym_id = (*e)->get_id_string();
1655	unordered_map<string, elf_symbol_sptr>::const_iterator j =
1656	  unrefed_var_symbol_map.find(sym_id);
1657	if (j != unrefed_var_symbol_map.end())
1658	  continue;
1659
1660	unrefed_var_symbol_map[sym_id] = *e;
1661	unrefed_var_symbols.push_back(*e);
1662      }
1663    unrefed_var_symbols_built = true;
1664  }
1665}; // end corpus_group::priv
1666
1667/// Constructor of the @ref corpus_group type.
1668///
1669/// @param env the environment of the @ref corpus_group.
1670///
1671/// @param path the path to the file represented by the corpus group.
1672corpus_group::corpus_group(const environment& env, const string& path = "")
1673  : corpus(env, path), priv_(new priv)
1674{}
1675
1676/// Desctructor of the @ref corpus_group type.
1677corpus_group::~corpus_group()
1678{}
1679
1680/// Add a new corpus to the current instance of @ref corpus_group.
1681///
1682/// @param corp the new corpus to add.
1683void
1684corpus_group::add_corpus(const corpus_sptr& corp)
1685{
1686  if (!corp)
1687    return;
1688
1689  // Ensure the new architecture name matches the current one.
1690  string cur_arch = get_architecture_name(),
1691    corp_arch = corp->get_architecture_name();
1692  if (cur_arch.empty())
1693    set_architecture_name(corp_arch);
1694  else if (cur_arch != corp_arch)
1695    {
1696      std::cerr << "corpus '" << corp->get_path() << "'"
1697		<< " has architecture '" << corp_arch << "'"
1698		<< " but expected '" << cur_arch << "'\n";
1699      ABG_ASSERT_NOT_REACHED;
1700    }
1701
1702  priv_->corpora.push_back(corp);
1703  corp->set_group(this);
1704
1705  /// Add the unreferenced function and variable symbols of this
1706  /// corpus to the unreferenced symbols of the current corpus group.
1707  priv_->add_unref_fun_symbols(get_unreferenced_function_symbols());
1708  priv_->add_unref_var_symbols(get_unreferenced_variable_symbols());
1709}
1710
1711/// Getter of the vector of corpora held by the current @ref
1712/// corpus_group.
1713///
1714/// @return the vector corpora.
1715const corpus_group::corpora_type&
1716corpus_group::get_corpora() const
1717{return priv_->corpora;}
1718
1719/// Getter of the first corpus added to this Group.
1720///
1721/// @return the first corpus added to this Group.
1722const corpus_sptr
1723corpus_group::get_main_corpus() const
1724{return const_cast<corpus_group*>(this)->get_main_corpus();}
1725
1726/// Getter of the first corpus added to this Group.
1727///
1728/// @return the first corpus added to this Group.
1729corpus_sptr
1730corpus_group::get_main_corpus()
1731{
1732  if (!get_corpora().empty())
1733    return get_corpora().front();
1734  return corpus_sptr();
1735}
1736
1737/// Test if the current corpus group is empty.
1738///
1739/// @return true iff the current corpus group is empty.
1740bool
1741corpus_group::is_empty() const
1742{return get_corpora().empty();}
1743
1744/// Get the functions exported by the corpora of the current corpus
1745/// group.
1746///
1747/// Upon its first invocation, this function walks the corpora
1748/// contained in the corpus group and caches the functions they exported.
1749///
1750/// Subsequent invocations just return the cached functions.
1751///
1752/// @return the exported functions.
1753const corpus::functions&
1754corpus_group::get_functions() const
1755{
1756  if (priv_->fns.empty())
1757    for (corpora_type::const_iterator i = get_corpora().begin();
1758	 i != get_corpora().end();
1759	 ++i)
1760      {
1761	corpus_sptr c = *i;
1762	for (corpus::functions::const_iterator f = c->get_functions().begin();
1763	     f != c->get_functions().end();
1764	     ++f)
1765	  {
1766	    interned_string fid = (*f)->get_id();
1767	    istring_function_decl_ptr_map_type::const_iterator j =
1768	      priv_->fns_map.find(fid);
1769
1770	    if (j != priv_->fns_map.end())
1771	      // Don't cache the same function twice ...
1772	      continue;
1773
1774	    priv_->fns_map[fid] = *f;
1775	    // really cache the function now.
1776	    priv_->fns.push_back(*f);
1777	  }
1778      }
1779
1780  return priv_->fns;
1781}
1782
1783/// Get the global variables exported by the corpora of the current
1784/// corpus group.
1785///
1786/// Upon its first invocation, this function walks the corpora
1787/// contained in the corpus group and caches the variables they
1788/// export.
1789///
1790/// @return the exported variables.
1791const corpus::variables&
1792corpus_group::get_variables() const
1793{
1794  if (priv_->vars.empty())
1795    for (corpora_type::const_iterator i = get_corpora().begin();
1796	 i != get_corpora().end();
1797	 ++i)
1798      {
1799	corpus_sptr c = *i;
1800	for (corpus::variables::const_iterator v = c->get_variables().begin();
1801	     v != c->get_variables().end();
1802	     ++v)
1803	  {
1804	    interned_string vid = (*v)->get_id();
1805	    istring_var_decl_ptr_map_type::const_iterator j =
1806	      priv_->vars_map.find(vid);
1807
1808	    if (j != priv_->vars_map.end())
1809	      // Don't cache the same variable twice ...
1810	      continue;
1811
1812	    priv_->vars_map[vid] = *v;
1813	    // Really cache the variable now.
1814	    priv_->vars.push_back(*v);
1815	  }
1816      }
1817
1818  return priv_->vars;
1819}
1820
1821/// Get the symbols of the global variables exported by the corpora of
1822/// the current @ref corpus_group.
1823///
1824/// @return the symbols of the global variables exported by the corpora
1825const string_elf_symbols_map_type&
1826corpus_group::get_var_symbol_map() const
1827{
1828  if (priv_->var_symbol_map.empty())
1829    for (corpora_type::const_iterator i = get_corpora().begin();
1830	 i != get_corpora().end();
1831	 ++i)
1832      priv_->var_symbol_map.insert((*i)->get_var_symbol_map().begin(),
1833				     (*i)->get_var_symbol_map().end());
1834
1835  return priv_->var_symbol_map;
1836}
1837
1838/// Get the symbols of the global functions exported by the corpora of
1839/// the current @ref corpus_group.
1840///
1841/// @return the symbols of the global functions exported by the corpora
1842const string_elf_symbols_map_type&
1843corpus_group::get_fun_symbol_map() const
1844{
1845  if (priv_->fun_symbol_map.empty())
1846    for (corpora_type::const_iterator i = get_corpora().begin();
1847	 i != get_corpora().end();
1848	 ++i)
1849      priv_->fun_symbol_map.insert((*i)->get_fun_symbol_map().begin(),
1850				   (*i)->get_fun_symbol_map().end());
1851
1852  return priv_->fun_symbol_map;
1853}
1854
1855/// Get a sorted vector of the symbols of the functions exported by
1856/// the corpora of the current group.
1857///
1858/// @return the sorted vectors of the exported function symbols.
1859const elf_symbols&
1860corpus_group::get_sorted_fun_symbols() const
1861{
1862  if (priv_->sorted_fun_symbols.empty()
1863      && !get_fun_symbol_map().empty())
1864    {
1865      for (corpora_type::const_iterator i = get_corpora().begin();
1866	   i != get_corpora().end();
1867	   ++i)
1868	{
1869	  corpus_sptr c = *i;
1870	  for (string_elf_symbols_map_type::const_iterator j =
1871		 c->get_fun_symbol_map().begin();
1872	       j != c->get_fun_symbol_map().begin();
1873	       ++j)
1874	    priv_->sorted_fun_symbols.insert(priv_->sorted_fun_symbols.end(),
1875					     j->second.begin(),
1876					     j->second.end());
1877	}
1878      comp_elf_symbols_functor comp;
1879      std::sort(priv_->sorted_fun_symbols.begin(),
1880		priv_->sorted_fun_symbols.end(),
1881		comp);
1882    }
1883
1884  return priv_->sorted_fun_symbols;
1885}
1886
1887/// Get a sorted vector of the symbols of the variables exported by
1888/// the corpora of the current group.
1889///
1890/// @return the sorted vectors of the exported variable symbols.
1891const elf_symbols&
1892corpus_group::get_sorted_var_symbols() const
1893{
1894  if (priv_->sorted_var_symbols.empty()
1895      && !get_var_symbol_map().empty())
1896    {
1897      for (corpora_type::const_iterator i = get_corpora().begin();
1898	   i != get_corpora().end();
1899	   ++i)
1900	{
1901	  corpus_sptr c = *i;
1902	  for (string_elf_symbols_map_type::const_iterator j =
1903		 c->get_var_symbol_map().begin();
1904	       j != c->get_var_symbol_map().begin();
1905	       ++j)
1906	    priv_->sorted_var_symbols.insert(priv_->sorted_var_symbols.end(),
1907					     j->second.begin(),
1908					     j->second.end());
1909	}
1910      comp_elf_symbols_functor comp;
1911      std::sort(priv_->sorted_var_symbols.begin(),
1912		priv_->sorted_var_symbols.end(),
1913		comp);
1914    }
1915
1916  return priv_->sorted_var_symbols;
1917}
1918
1919/// Get the set of function symbols not referenced by any debug info,
1920/// from all the corpora of the current corpus group.
1921///
1922/// Upon its first invocation, this function possibly walks all the
1923/// copora of this corpus group and caches the unreferenced symbols
1924/// they export.  The function then returns the cache.
1925///
1926/// Upon subsequent invocations, this functions just returns the
1927/// cached symbols.
1928///
1929/// @return the unreferenced symbols.
1930const elf_symbols&
1931corpus_group::get_unreferenced_function_symbols() const
1932{
1933  if (!priv_->unrefed_fun_symbols_built)
1934    if (priv_->unrefed_fun_symbols.empty())
1935      {
1936	for (corpora_type::const_iterator i = get_corpora().begin();
1937	     i != get_corpora().end();
1938	     ++i)
1939	  {
1940	    corpus_sptr c = *i;
1941	    for (elf_symbols::const_iterator e =
1942		   c->get_unreferenced_function_symbols().begin();
1943		 e != c->get_unreferenced_function_symbols().end();
1944		 ++e)
1945	      {
1946		string sym_id = (*e)->get_id_string();
1947		unordered_map<string, elf_symbol_sptr>::const_iterator j =
1948		  priv_->unrefed_fun_symbol_map.find(sym_id);
1949		if (j != priv_->unrefed_fun_symbol_map.end())
1950		  continue;
1951
1952		priv_->unrefed_fun_symbol_map[sym_id] = *e;
1953		priv_->unrefed_fun_symbols.push_back(*e);
1954	      }
1955	  }
1956	priv_->unrefed_fun_symbols_built = true;
1957      }
1958
1959  return priv_->unrefed_fun_symbols;
1960}
1961
1962/// Get the set of variable symbols not referenced by any debug info,
1963/// from all the corpora of the current corpus group.
1964///
1965/// Upon its first invocation, this function possibly walks all the
1966/// copora of this corpus group and caches the unreferenced symbols
1967/// they export.  The function then returns the cache.
1968///
1969/// Upon subsequent invocations, this functions just returns the
1970/// cached symbols.
1971///
1972/// @return the unreferenced symbols.
1973const elf_symbols&
1974corpus_group::get_unreferenced_variable_symbols() const
1975{
1976  if (!priv_->unrefed_var_symbols_built)
1977    if (priv_->unrefed_var_symbols.empty())
1978      {
1979	for (corpora_type::const_iterator i = get_corpora().begin();
1980	     i != get_corpora().end();
1981	     ++i)
1982	  {
1983	    corpus_sptr c = *i;
1984	    for (elf_symbols::const_iterator e =
1985		   c->get_unreferenced_variable_symbols().begin();
1986		 e != c->get_unreferenced_variable_symbols().end();
1987		 ++e)
1988	      {
1989		string sym_id = (*e)->get_id_string();
1990		unordered_map<string, elf_symbol_sptr>::const_iterator j =
1991		  priv_->unrefed_var_symbol_map.find(sym_id);
1992		if (j != priv_->unrefed_var_symbol_map.end())
1993		  continue;
1994
1995		priv_->unrefed_var_symbol_map[sym_id] = *e;
1996		priv_->unrefed_var_symbols.push_back(*e);
1997	      }
1998	  }
1999	priv_->unrefed_var_symbols_built = true;
2000      }
2001
2002  return priv_->unrefed_var_symbols;
2003}
2004
2005/// Getter of a pointer to the set of types reachable from public
2006/// interfaces of a given corpus group.
2007unordered_set<interned_string, hash_interned_string>*
2008corpus_group::get_public_types_pretty_representations()
2009{return &priv_->pub_type_pretty_reprs_;}
2010
2011/// Test if the recording of reachable types (and thus, indirectly,
2012/// the recording of non-reachable types) is activated for the
2013/// current @ref corpus_group.
2014///
2015/// @return true iff the recording of reachable types is activated for
2016/// the current @ref corpus_group.
2017bool
2018corpus_group::recording_types_reachable_from_public_interface_supported()
2019{return !get_public_types_pretty_representations()->empty();}
2020
2021// </corpus_group stuff>
2022
2023}// end namespace ir
2024}// end namespace abigail
2025