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>
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(const function_decl * fn)136 corpus::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.
158 void
maybe_add_var_to_exported_vars(const var_decl * var)159 corpus::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.
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(const ir::environment & env,const string & path)599 corpus::corpus(const 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 /// 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.
621 void
add(const translation_unit_sptr & tu)622 corpus::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.
641 const translation_units&
get_translation_units() const642 corpus::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.
651 const translation_unit_sptr
find_translation_unit(const string & path) const652 corpus::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.
666 void
drop_translation_units()667 corpus::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.
673 type_maps&
get_types()674 corpus::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.
681 const type_maps&
get_types() const682 corpus::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.
694 const type_maps&
get_type_per_loc_map() const695 corpus::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.
704 bool
recording_types_reachable_from_public_interface_supported()705 corpus::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.
715 void
record_type_as_reachable_from_public_interfaces(const type_base & t)716 corpus::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.
733 bool
type_is_reachable_from_public_interfaces(const type_base & t) const734 corpus::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.
753 const vector<type_base_wptr>&
get_types_not_reachable_from_public_interfaces() const754 corpus::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.
782 type_maps&
get_type_per_loc_map()783 corpus::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.
790 const corpus_group*
get_group() const791 corpus::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.
798 corpus_group*
get_group()799 corpus::get_group()
800 {return priv_->group;}
801
802 /// Setter of the group this corpus belongs to.
803 ///
804 /// @param g the new group.
805 void
set_group(corpus_group * g)806 corpus::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.
814 void
init_format_version()815 corpus::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.
826 corpus::origin
get_origin() const827 corpus::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.
833 void
set_origin(origin o)834 corpus::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.
841 string&
get_format_major_version_number() const842 corpus::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.
849 void
set_format_major_version_number(const string & maj)850 corpus::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.
858 string&
get_format_minor_version_number() const859 corpus::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.
867 void
set_format_minor_version_number(const string & min)868 corpus::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.
879 string&
get_path() const880 corpus::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.
891 void
set_path(const string & path)892 corpus::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.
902 const vector<string>&
get_needed() const903 corpus::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.
914 void
set_needed(const vector<string> & needed)915 corpus::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.
925 const string&
get_soname()926 corpus::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.
936 void
set_soname(const string & soname)937 corpus::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.
947 const string&
get_architecture_name() const948 corpus::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.
958 void
set_architecture_name(const string & arch)959 corpus::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.
971 bool
is_empty() const972 corpus::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.
998 bool
operator ==(const corpus & other) const999 corpus::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
1017 void
set_symtab(symtab_reader::symtab_sptr symtab)1018 corpus::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
1024 const symtab_reader::symtab_sptr&
get_symtab() const1025 corpus::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.
1031 const string_elf_symbols_map_type&
get_fun_symbol_map() const1032 corpus::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.
1041 const string_elf_symbols_map_type&
get_undefined_fun_symbol_map() const1042 corpus::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.
1052 const elf_symbols&
get_sorted_fun_symbols() const1053 corpus::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.
1061 const elf_symbols&
get_sorted_undefined_fun_symbols() const1062 corpus::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.
1072 const elf_symbols&
get_sorted_var_symbols() const1073 corpus::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.
1081 const elf_symbols&
get_sorted_undefined_var_symbols() const1082 corpus::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.
1088 const string_elf_symbols_map_type&
get_var_symbol_map() const1089 corpus::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.
1098 const string_elf_symbols_map_type&
get_undefined_var_symbol_map() const1099 corpus::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.
1107 const elf_symbol_sptr
lookup_function_symbol(const string & n) const1108 corpus::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.
1131 static const elf_symbol_sptr
find_symbol_by_version(const elf_symbol::version & version,const vector<elf_symbol_sptr> & symbols)1132 find_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.
1173 const elf_symbol_sptr
lookup_function_symbol(const string & symbol_name,const elf_symbol::version & version) const1174 corpus::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.
1194 const elf_symbol_sptr
lookup_function_symbol(const elf_symbol & symbol) const1195 corpus::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.
1203 const elf_symbol_sptr
lookup_variable_symbol(const string & n) const1204 corpus::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.
1224 const elf_symbol_sptr
lookup_variable_symbol(const string & symbol_name,const elf_symbol::version & version) const1225 corpus::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.
1245 const elf_symbol_sptr
lookup_variable_symbol(const elf_symbol & symbol) const1246 corpus::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.
1263 const corpus::functions&
get_functions() const1264 corpus::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.
1281 const vector<function_decl*>*
lookup_functions(const string & id) const1282 corpus::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.
1296 void
sort_functions()1297 corpus::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.
1318 const corpus::variables&
get_variables() const1319 corpus::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.
1326 void
sort_variables()1327 corpus::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.
1342 const elf_symbols&
get_unreferenced_function_symbols() const1343 corpus::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.
1355 const elf_symbols&
get_unreferenced_variable_symbols() const1356 corpus::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.
1364 vector<string>&
get_regex_patterns_of_fns_to_suppress()1365 corpus::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.
1373 const vector<string>&
get_regex_patterns_of_fns_to_suppress() const1374 corpus::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.
1382 vector<string>&
get_regex_patterns_of_vars_to_suppress()1383 corpus::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.
1391 const vector<string>&
get_regex_patterns_of_vars_to_suppress() const1392 corpus::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.
1401 vector<string>&
get_regex_patterns_of_fns_to_keep()1402 corpus::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.
1411 const vector<string>&
get_regex_patterns_of_fns_to_keep() const1412 corpus::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.
1421 vector<string>&
get_sym_ids_of_fns_to_keep()1422 corpus::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.
1431 const vector<string>&
get_sym_ids_of_fns_to_keep() const1432 corpus::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.
1441 vector<string>&
get_regex_patterns_of_vars_to_keep()1442 corpus::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.
1451 const vector<string>&
get_regex_patterns_of_vars_to_keep() const1452 corpus::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.
1461 vector<string>&
get_sym_ids_of_vars_to_keep()1462 corpus::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.
1471 const vector<string>&
get_sym_ids_of_vars_to_keep() const1472 corpus::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.
1478 void
maybe_drop_some_exported_decls()1479 corpus::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.
1519 corpus::exported_decls_builder_sptr
get_exported_decls_builder() const1520 corpus::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.
1544 corpus::origin
operator |(corpus::origin l,corpus::origin r)1545 operator|(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.
1558 corpus::origin
operator |=(corpus::origin & l,corpus::origin r)1559 operator|=(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.
1572 corpus::origin
operator &(corpus::origin l,corpus::origin r)1573 operator&(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.
1586 corpus::origin
operator &=(corpus::origin & l,corpus::origin r)1587 operator&=(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
1598 struct 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
privabigail::ir::corpus_group::priv1617 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
add_unref_fun_symbolsabigail::ir::corpus_group::priv1627 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
add_unref_var_symbolsabigail::ir::corpus_group::priv1649 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.
corpus_group(const environment & env,const string & path="")1672 corpus_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.
~corpus_group()1677 corpus_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.
1683 void
add_corpus(const corpus_sptr & corp)1684 corpus_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.
1715 const corpus_group::corpora_type&
get_corpora() const1716 corpus_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.
1722 const corpus_sptr
get_main_corpus() const1723 corpus_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.
1729 corpus_sptr
get_main_corpus()1730 corpus_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.
1740 bool
is_empty() const1741 corpus_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.
1753 const corpus::functions&
get_functions() const1754 corpus_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.
1791 const corpus::variables&
get_variables() const1792 corpus_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
1825 const string_elf_symbols_map_type&
get_var_symbol_map() const1826 corpus_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
1842 const string_elf_symbols_map_type&
get_fun_symbol_map() const1843 corpus_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.
1859 const elf_symbols&
get_sorted_fun_symbols() const1860 corpus_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.
1891 const elf_symbols&
get_sorted_var_symbols() const1892 corpus_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.
1930 const elf_symbols&
get_unreferenced_function_symbols() const1931 corpus_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.
1973 const elf_symbols&
get_unreferenced_variable_symbols() const1974 corpus_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.
2007 unordered_set<interned_string, hash_interned_string>*
get_public_types_pretty_representations()2008 corpus_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.
2017 bool
recording_types_reachable_from_public_interface_supported()2018 corpus_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