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