libabigail
Loading...
Searching...
No Matches
abg-symtab-reader.h
Go to the documentation of this file.
1// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
2// -*- Mode: C++ -*-
3//
4// Copyright (C) 2020-2026 Google, Inc.
5//
6// Author: Matthias Maennich
7
8/// @file
9///
10/// This contains the declarations for the symtab reader.
11
12#ifndef __ABG_SYMTAB_READER_H__
13#define __ABG_SYMTAB_READER_H__
14
15#include <gelf.h>
16
17#include <functional>
18#include <iterator>
19#include <memory>
20#include <unordered_map>
21#include <vector>
22#include <mutex>
23
24#include "abg-cxx-compat.h" // for abg_compat::optional
25#include "abg-ir.h"
26
27namespace abigail
28{
29namespace symtab_reader
30{
31
32using std::mutex;
33
34/// The symtab filter is the object passed to the symtab object in order to
35/// iterate over the symbols in the symtab while applying filters.
36///
37/// The general idea is that it consists of a set of optionally enforced flags,
38/// such as 'functions' or 'variables'. If not set, those are not filtered for,
39/// neither inclusive nor exclusive. If set they are all ANDed together.
41{
42public:
43 // Default constructor disabling all features.
44 symtab_filter() {}
45
46 bool
47 matches(const elf_symbol& symbol) const;
48
49 /// Enable or disable function filtering
50 ///
51 /// @param new_value whether to filter for functions
52 void
53 set_functions(bool new_value = true)
54 {functions_ = new_value;};
55
56 /// Enable or disable variable filtering
57 ///
58 /// @param new_value whether to filter for variables
59 void
60 set_variables(bool new_value = true)
61 {variables_ = new_value;};
62
63 /// Enable or disable public symbol filtering
64 ///
65 /// @param new_value whether to filter for public symbols
66 void
67 set_public_symbols(bool new_value = true)
68 {public_symbols_ = new_value;};
69
70 /// Enable or disable undefined symbol filtering
71 ///
72 /// @param new_value whether to filter for undefined symbols
73 void
74 set_undefined_symbols(bool new_value = true)
75 {undefined_symbols_ = new_value;};
76
77 /// Enable or disable kernel symbol filtering
78 ///
79 /// @param new_value whether to filter for kernel symbols
80 void
81 set_kernel_symbols(bool new_value = true)
82 {kernel_symbols_ = new_value;};
83
84private:
85 // The symbol is a function (FUNC)
87
88 // The symbol is a variables (OBJECT)
90
91 // The symbol is publicly accessible (global/weak with default/protected
92 // visibility)
93 abg_compat::optional<bool> public_symbols_;
94
95 // The symbols is not defined (declared)
96 abg_compat::optional<bool> undefined_symbols_;
97
98 // The symbol is listed in the ksymtab (for Linux Kernel binaries).
99 abg_compat::optional<bool> kernel_symbols_;
100};
101
102/// Base iterator for our custom iterator based on whatever the const_iterator
103/// is for a vector of symbols.
104/// As of writing this, std::vector<elf_symbol_sptr>::const_iterator.
105using base_iterator = elf_symbols::const_iterator;
106
107/// An iterator to walk a vector of elf_symbols filtered by symtab_filter.
108///
109/// The implementation inherits all properties from the vector's
110/// const_iterator, but intercepts where necessary to allow effective
111/// filtering. This makes it a STL compatible iterator for general purpose
112/// usage.
114{
115public:
116 using value_type = base_iterator::value_type;
117 using reference = base_iterator::reference;
118 using pointer = base_iterator::pointer;
119 using difference_type = base_iterator::difference_type;
120 using iterator_category = std::forward_iterator_tag;
121 using iterator_concept = std::forward_iterator_tag;
122
123 /// Construct the iterator based on a pair of underlying iterators and a
124 /// symtab_filter object. Immediately fast forward to the next element that
125 /// matches the criteria (if any).
126 ///
127 /// @param begin the underlying begin iterator
128 ///
129 /// @param begin the underlying end iterator
130 ///
131 /// @param filter the symtab_filter to apply
133 base_iterator end,
134 const symtab_filter& filter = symtab_filter())
135 : base_iterator(begin), end_(end), filter_(filter)
136 {skip_to_next();}
137
138 /// Pre-increment operator to advance to the next matching element.
139 ///
140 /// @return itself after incrementing
143 {
144 base_iterator::operator++();
145 skip_to_next();
146 return *this;
147 }
148
149 /// Post-increment operator to advance to the next matching element.
150 ///
151 /// @return a copy of the iterator before incrementing
154 {
155 symtab_iterator result(*this);
156 ++(*this);
157 return result;
158 }
159
160private:
161 /// The end of the underlying iterator.
162 const base_iterator end_;
163
164 /// The symtab_filter used to determine when to advance.
165 const symtab_filter& filter_;
166
167 /// Skip to the next element that matches the filter criteria (if any). Hold
168 /// off when reaching the end of the underlying iterator.
169 void
170 skip_to_next()
171 {
172 while (*this != end_ && !filter_.matches(***this))
173 ++(*this);
174 }
175};
176
177/// Convenience declaration of a unique_ptr<symtab>
178class symtab;
179using symtab_ptr = std::unique_ptr<symtab>;
180
181/// symtab is the actual data container of the symtab_reader implementation.
182///
183/// The symtab is instantiated either via an Elf handle (from binary) or from a
184/// set of existing symbol maps (usually when instantiated from XML). It will
185/// then discover the symtab, possibly the ksymtab (for Linux Kernel binaries)
186/// and setup the data containers and lookup maps for later perusal.
187///
188/// The symtab is supposed to be used in a const context as all information is
189/// already computed at construction time. Symbols are stored sorted to allow
190/// deterministic reading of the entries.
191///
192/// An example use of the symtab class is
193///
194/// const auto symtab = symtab::load(elf_handle, env);
195/// symtab_filter filter = symtab->make_filter();
196/// filter.set_public_symbols();
197/// filter.set_functions();
198///
199/// for (const auto& symbol : filtered_symtab(*symtab, filter))
200/// {
201/// std::cout << symbol->get_name() << "\n";
202/// }
203///
204/// This uses the filtered_symtab proxy object to capture the filter.
206{
207public:
208 using symbol_predicate = std::function<bool(const elf_symbol_sptr&)>;
209
210 /// Indicate whether any (kernel) symbols have been seen at construction.
211 ///
212 /// @return true if there are symbols detected earlier.
213 bool
215 {return is_kernel_binary_ ? has_ksymtab_entries_ : !symbols_.empty();}
216
218 make_filter() const;
219
220 /// The (only) iterator type we offer is a const_iterator implemented by the
221 /// symtab_iterator.
223
224 /// Obtain an iterator to the beginning of the symtab according to the filter
225 /// criteria. Whenever this iterator advances, it skips elements that do not
226 /// match the filter criteria.
227 ///
228 /// @param filter the symtab_filter to match symbols against
229 ///
230 /// @return a filtering const_iterator of the underlying type
232 begin(const symtab_filter& filter) const
233 {return symtab_iterator(symbols_.begin(), symbols_.end(), filter);}
234
235 /// Obtain an iterator to the end of the symtab.
236 ///
237 /// @return an end iterator
239 end() const
240 {return symtab_iterator(symbols_.end(), symbols_.end());}
241
242 const elf_symbols&
243 lookup_symbol(const std::string& name) const;
244
245 const elf_symbol_sptr
246 lookup_symbol(GElf_Addr symbol_addr) const;
247
248 const elf_symbol_sptr
249 lookup_undefined_function_symbol(const std::string& name);
250
251 const elf_symbol_sptr
252 lookup_undefined_variable_symbol(const std::string& name);
253
255 function_symbol_is_exported(const string&);
256
258 function_symbol_is_exported(const GElf_Addr symbol_address);
259
261 variable_symbol_is_exported(const string&);
262
264 variable_symbol_is_exported(const GElf_Addr symbol_address);
265
267 function_symbol_is_undefined(const string&);
268
270 variable_symbol_is_undefined(const string&);
271
272 static symtab_ptr
273 load(Elf* elf_handle,
274 const ir::environment& env,
275 symbol_predicate is_suppressed = NULL);
276
277 static symtab_ptr
278 load(string_elf_symbols_map_sptr function_symbol_map,
279 string_elf_symbols_map_sptr variables_symbol_map);
280
281 void
282 update_main_symbol(GElf_Addr addr, const std::string& name);
283
284private:
285 /// Default constructor. Private to enforce creation by factory methods.
286 symtab();
287
288 mutable mutex big_mutex_;
289
290 /// The vector of symbols we discovered.
291 elf_symbols symbols_;
292
293 // A map of undefined function symbols to speedup the function
294 // lookup_undefined_function_symbol
295 unordered_map<string, elf_symbol_sptr> undefined_fn_symbols_;
296
297 // Similarly, a map of undefined variable symbols to speedup the
298 // function lookup_undefined_variable_symbol
299 unordered_map<string, elf_symbol_sptr> undefined_var_symbols_;
300
301 /// Whether this is a Linux Kernel binary
302 bool is_kernel_binary_;
303
304 /// Whether this kernel_binary has ksymtab entries
305 ///
306 /// A kernel module might not have a ksymtab if it does not export any
307 /// symbols. In order to quickly decide whether the symbol table is empty, we
308 /// remember whether we ever saw ksymtab entries.
309 bool has_ksymtab_entries_;
310
311 /// Lookup map name->symbol(s)
312 using name_symbol_map_type =
313 std::unordered_map<std::string, std::vector<elf_symbol_sptr>>;
314 name_symbol_map_type name_symbol_map_;
315
316 /// Lookup map addr->symbol
317 using addr_symbol_map_type = std::unordered_map<GElf_Addr, elf_symbol_sptr>;
318 addr_symbol_map_type addr_symbol_map_;
319
320 /// Lookup map function entry address -> symbol
321 addr_symbol_map_type entry_addr_symbol_map_;
322
323 mutable mutex map_mutex_;
324
325 /// Set of undefined function symbol names
326 std::unordered_set<std::string> undefined_function_linkage_names_;
327
328 /// of undefined variable function symbol names
329 std::unordered_set<std::string> undefined_variable_linkage_names_;
330
331 bool cached_undefined_symbol_names_;
332
333 bool
334 load_(Elf* elf_handle,
335 const ir::environment& env,
336 symbol_predicate is_suppressed);
337
338 bool
339 load_(string_elf_symbols_map_sptr function_symbol_map,
340 string_elf_symbols_map_sptr variables_symbol_map);
341
342 GElf_Addr
343 setup_symbol_lookup_tables(Elf* elf_handle,
344 GElf_Sym* elf_symbol,
345 const elf_symbol_sptr& symbol_sptr);
346
347 void
348 update_function_entry_address_symbol_map(Elf* elf_handle,
349 GElf_Sym* native_symbol,
350 const elf_symbol_sptr& symbol_sptr);
351
352 void
353 add_alternative_address_lookups(Elf* elf_handle);
354
355 void
356 collect_undefined_fns_and_vars_linkage_names();
357};
358
359/// Helper class to allow range-for loops on symtabs for C++11 and later code.
360/// It serves as a proxy for the symtab iterator and provides a begin() method
361/// without arguments, as required for range-for loops (and possibly other
362/// iterator based transformations).
363///
364/// Example usage:
365///
366/// for (const auto& symbol : filtered_symtab(tab, filter))
367/// {
368/// std::cout << symbol->get_name() << "\n";
369/// }
370///
372{
373 const symtab& tab_;
374 const symtab_filter filter_;
375
376public:
377 /// Construct the proxy object keeping references to the underlying symtab
378 /// and the filter object.
379 filtered_symtab(const symtab& tab, const symtab_filter& filter)
380 : tab_(tab), filter_(filter)
381 {}
382
383 /// Pass through symtab.begin(), but also pass on the filter.
385 begin() const
386 {return tab_.begin(filter_);}
387
388 /// Pass through symtab.end().
390 end() const
391 {return tab_.end();}
392};
393
394} // end namespace symtab_reader
395} // end namespace abigail
396
397#endif // __ABG_SYMTAB_READER_H__
Types of the main internal representation of libabigail.
Simplified implementation of std::optional just enough to be used as a replacement for our purposes a...
Abstraction of an elf symbol.
Definition abg-ir.h:959
This is an abstraction of the set of resources necessary to manage several aspects of the internal re...
Definition abg-ir.h:216
Helper class to allow range-for loops on symtabs for C++11 and later code. It serves as a proxy for t...
symtab::const_iterator begin() const
Pass through symtab.begin(), but also pass on the filter.
symtab::const_iterator end() const
Pass through symtab.end().
filtered_symtab(const symtab &tab, const symtab_filter &filter)
Construct the proxy object keeping references to the underlying symtab and the filter object.
The symtab filter is the object passed to the symtab object in order to iterate over the symbols in t...
void set_public_symbols(bool new_value=true)
Enable or disable public symbol filtering.
bool matches(const elf_symbol &symbol) const
symtab_filter implementations
void set_functions(bool new_value=true)
Enable or disable function filtering.
void set_kernel_symbols(bool new_value=true)
Enable or disable kernel symbol filtering.
void set_variables(bool new_value=true)
Enable or disable variable filtering.
void set_undefined_symbols(bool new_value=true)
Enable or disable undefined symbol filtering.
An iterator to walk a vector of elf_symbols filtered by symtab_filter.
symtab_iterator(base_iterator begin, base_iterator end, const symtab_filter &filter=symtab_filter())
Construct the iterator based on a pair of underlying iterators and a symtab_filter object....
symtab_iterator operator++(int)
Post-increment operator to advance to the next matching element.
symtab_iterator & operator++()
Pre-increment operator to advance to the next matching element.
symtab is the actual data container of the symtab_reader implementation.
const elf_symbol_sptr lookup_undefined_variable_symbol(const std::string &name)
Lookup an undefined variable symbol with a given name.
const_iterator begin(const symtab_filter &filter) const
Obtain an iterator to the beginning of the symtab according to the filter criteria....
const elf_symbols & lookup_symbol(const std::string &name) const
Get a vector of symbols that are associated with a certain name.
bool has_symbols() const
Indicate whether any (kernel) symbols have been seen at construction.
symtab_filter make_filter() const
symtab implementations
static symtab_ptr load(Elf *elf_handle, const ir::environment &env, symbol_predicate is_suppressed=NULL)
Construct a symtab object and instantiate it from an ELF handle. Also pass in the ir::environment we ...
elf_symbol_sptr function_symbol_is_undefined(const string &)
Test if a name is a the name of an undefined function symbol.
elf_symbol_sptr variable_symbol_is_undefined(const string &)
Test if a name is a the name of an undefined variable symbol.
elf_symbol_sptr function_symbol_is_exported(const string &)
Test if a given function symbol has been exported.
const_iterator end() const
Obtain an iterator to the end of the symtab.
elf_symbol_sptr variable_symbol_is_exported(const string &)
Test if a given variable symbol has been exported.
const elf_symbol_sptr lookup_undefined_function_symbol(const std::string &name)
Lookup an undefined function symbol with a given name.
void update_main_symbol(GElf_Addr addr, const std::string &name)
Notify the symtab about the name of the main symbol at a given address.
symtab_iterator const_iterator
The (only) iterator type we offer is a const_iterator implemented by the symtab_iterator.
shared_ptr< elf_symbol > elf_symbol_sptr
A convenience typedef for a shared pointer to elf_symbol.
Definition abg-ir.h:924
std::vector< elf_symbol_sptr > elf_symbols
Convenience typedef for a vector of elf_symbol.
Definition abg-ir.h:940
shared_ptr< string_elf_symbols_map_type > string_elf_symbols_map_sptr
Convenience typedef for a shared pointer to string_elf_symbols_map_type.
Definition abg-ir.h:949
Toplevel namespace for libabigail.