1 // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
2 // -*- Mode: C++ -*-
3 //
4 // Copyright (C) 2022 Red Hat, Inc.
5 //
6 // Author: Dodji Seketeli
7
8 /// @file
9 ///
10 /// This file contains the definitions of the the fe_iface base type.
11
12 #include "abg-internal.h"
13 // <headers defining libabigail's API go under here>
14 ABG_BEGIN_EXPORT_DECLARATIONS
15
16 #include "abg-corpus.h"
17 #include "abg-fe-iface.h"
18
19 ABG_END_EXPORT_DECLARATIONS
20 // </headers defining libabigail's API>
21
22 namespace abigail
23 {
24
25 /// The private data structure for the @ref fe_iface type.
26 struct fe_iface::priv
27 {
28 std::string corpus_path;
29 std::string dt_soname;
30 fe_iface::options_type options;
31 suppr::suppressions_type suppressions;
32 ir::corpus_sptr corpus;
33 ir::corpus_group_sptr corpus_group;
34
privabigail::fe_iface::priv35 priv(const std::string& path, environment& e)
36 : corpus_path(path), options(e)
37 {
38 initialize();
39 }
40
41 /// This function resets the data of @ref fe_iface::priv data so
42 /// that it can be re-used again.
43 void
initializeabigail::fe_iface::priv44 initialize()
45 {
46 //TODO: initialize the options.
47 corpus_path.clear();
48 dt_soname.clear();
49 suppressions.clear();
50 corpus_group.reset();
51 }
52 }; //end struct fe_iface::priv
53
54 /// Constructor of the type @ref fe_iface::options_type.
55 ///
56 /// @param e the environment used by the Front End Interface.
options_type(environment & e)57 fe_iface::options_type::options_type(environment& e)
58 : env(e)
59 {
60 }
61
62 /// Constructor of the type @ref fe_iface.
63 ///
64 /// @param corpus_path the path to the file represented by the ABI
65 /// corpus that is going to be built by this Front End.
66 ///
67 /// @param e the environment in which the Front End operates.
fe_iface(const std::string & corpus_path,environment & e)68 fe_iface::fe_iface(const std::string& corpus_path, environment& e)
69 : priv_(new priv(corpus_path, e))
70 {
71 }
72
73 /// Desctructor of the Front End Interface.
~fe_iface()74 fe_iface::~fe_iface()
75 {delete priv_;}
76
77 /// Re-initialize the current Front End.
78 ///
79 /// @param corpus_path the path to the file for which a new corpus is
80 /// to be created.
81 ///
82 /// @param e the environment in which the Front End operates.
83 void
reset(const std::string & corpus_path,environment & e)84 fe_iface::reset(const std::string& corpus_path,
85 environment& e)
86 {
87 delete priv_;
88 priv_ = new fe_iface::priv(corpus_path, e);
89 }
90
91 /// Getter of the the options of the current Front End Interface.
92 ///
93 /// @return the options of the current Front End Interface.
94 const fe_iface::options_type&
options() const95 fe_iface::options() const
96 {return priv_->options;}
97
98 /// Getter of the the options of the current Front End Interface.
99 ///
100 /// @return the options of the current Front End Interface.
101 fe_iface::options_type&
options()102 fe_iface::options()
103 {return priv_->options;}
104
105 /// Getter of the path to the file which an ABI corpus is to be
106 /// created for.
107 ///
108 /// @return the path to the file which an ABI corpus is to be created
109 /// for.
110 const std::string&
corpus_path() const111 fe_iface::corpus_path() const
112 {return priv_->corpus_path;}
113
114 /// Setter of the path to the file which an ABI corpus is to be
115 /// created for.
116 ///
117 /// @param p the new path to the file which an ABI corpus is to be
118 /// created for.
119 void
corpus_path(const std::string & p)120 fe_iface::corpus_path(const std::string& p)
121 {priv_->corpus_path = p;}
122
123 /// Getter for the SONAME of the analyzed binary.
124 ///
125 /// @return the SONAME of the analyzed binary.
126 const string&
dt_soname() const127 fe_iface::dt_soname() const
128 {return priv_->dt_soname;}
129
130 /// Getter for the SONAME of the analyzed binary.
131 ///
132 /// @return the SONAME of the analyzed binary.
133 void
dt_soname(const string & soname)134 fe_iface::dt_soname(const string& soname)
135 {priv_->dt_soname = soname;}
136
137 /// Test if the input binary is to be considered as a Linux Kernel
138 /// binary.
139 ///
140 /// @return true iff the input binary is to be considered as a Linux
141 /// Kernel binary.
142 bool
load_in_linux_kernel_mode() const143 fe_iface::load_in_linux_kernel_mode() const
144 {return priv_->options.load_in_linux_kernel_mode;}
145
146 /// Getter of the vector of suppression specifications associated with
147 /// the current front-end.
148 ///
149 /// @return the vector of suppression specifications associated with
150 /// the current front-end.
151 suppr::suppressions_type&
suppressions()152 fe_iface::suppressions()
153 {return priv_->suppressions;}
154
155 /// Getter of the vector of suppression specifications associated with
156 /// the current front-end.
157 ///
158 /// @return the vector of suppression specifications associated with
159 /// the current front-end.
160 const suppr::suppressions_type&
suppressions() const161 fe_iface::suppressions() const
162 {return priv_->suppressions;}
163
164 /// Setter of the vector of suppression specifications associated with
165 /// the current front-end.
166 ///
167 /// @param supprs the new vector of suppression specifications
168 /// associated with the current front-end.
169 void
suppressions(suppr::suppressions_type & supprs)170 fe_iface::suppressions(suppr::suppressions_type& supprs)
171 {priv_->suppressions = supprs;}
172
173 /// Add suppressions specifications to the set of suppressions to be
174 /// used during the construction of the ABI internal representation
175 /// (the ABI corpus) from the input file.
176 ///
177 /// During the construction of the ABI corpus, ABI artifacts that
178 /// match a given suppression specification are dropped on the floor;
179 /// that is, they are discarded and won't be part of the final ABI
180 /// corpus. This is a way to reduce the amount of data held by the
181 /// final ABI corpus.
182 ///
183 /// Note that the suppression specifications provided to this function
184 /// are only considered during the construction of the ABI corpus.
185 /// For instance, they are not taken into account during e.g
186 /// comparisons of two ABI corpora that might happen later. If you
187 /// want to apply suppression specificatins to the comparison (or
188 /// reporting) of ABI corpora please refer to the documentation of the
189 /// @ref diff_context type to learn how to set suppressions that are
190 /// to be used in that context.
191 ///
192 /// @param supprs the suppression specifications to be applied during
193 /// the construction of the ABI corpus.
194 void
add_suppressions(const suppr::suppressions_type & supprs)195 fe_iface::add_suppressions(const suppr::suppressions_type& supprs)
196 {
197 for (const auto& s : supprs)
198 if (s->get_drops_artifact_from_ir())
199 suppressions().push_back(s);
200 }
201
202 /// Getter for the ABI corpus being built by the current front-end.
203 ///
204 /// @return the ABI corpus being built by the current front-end.
205 corpus_sptr
corpus()206 fe_iface::corpus()
207 {
208 if (!priv_->corpus)
209 {
210 priv_->corpus = std::make_shared<ir::corpus>(options().env,
211 corpus_path());
212 }
213 return priv_->corpus;
214 }
215
216 /// Getter for the ABI corpus being built by the current front-end.
217 ///
218 /// @return the ABI corpus being built by the current front-end.
219 const corpus_sptr
corpus() const220 fe_iface::corpus() const
221 {return const_cast<fe_iface*>(this)->corpus();}
222
223 /// Getter for the ABI corpus group being built by the current front-end.
224 ///
225 /// @return the ABI corpus group being built by the current front-end.
226 corpus_group_sptr&
corpus_group()227 fe_iface::corpus_group()
228 {return priv_->corpus_group;}
229
230 /// Getter for the ABI corpus group being built by the current front-end.
231 ///
232 /// @return the ABI corpus group being built by the current front-end.
233 const corpus_group_sptr&
corpus_group() const234 fe_iface::corpus_group() const
235 {return const_cast<fe_iface*>(this)->corpus_group();}
236
237 /// Setter for the ABI corpus group being built by the current
238 /// front-end.
239 ///
240 /// @param cg the new ABI corpus group being built by the current
241 /// front-end.
242 void
corpus_group(const ir::corpus_group_sptr & cg)243 fe_iface::corpus_group(const ir::corpus_group_sptr& cg)
244 {priv_->corpus_group = cg;}
245
246 /// Test if there is a corpus group being built.
247 ///
248 /// @return if there is a corpus group being built, false otherwise.
249 bool
has_corpus_group() const250 fe_iface::has_corpus_group() const
251 {return bool(corpus_group());}
252
253 /// Return the main corpus from the current corpus group, if any.
254 ///
255 /// @return the main corpus of the current corpus group, if any, nil
256 /// if no corpus group is being constructed.
257 corpus_sptr
main_corpus_from_current_group()258 fe_iface::main_corpus_from_current_group()
259 {
260 if (corpus_group())
261 return corpus_group()->get_main_corpus();
262 return corpus_sptr();
263 }
264
265 /// Test if the current corpus being built is the main corpus of the
266 /// current corpus group.
267 ///
268 /// @return return true iff the current corpus being built is the
269 /// main corpus of the current corpus group.
270 bool
current_corpus_is_main_corpus_from_current_group()271 fe_iface::current_corpus_is_main_corpus_from_current_group()
272 {
273 corpus_sptr main_corpus = main_corpus_from_current_group();
274
275 if (main_corpus.get() == corpus().get())
276 return true;
277
278 return false;
279 }
280
281 /// Return true if the current corpus is part of a corpus group
282 /// being built and if it's not the main corpus of the group.
283 ///
284 /// For instance, this would return true if we are loading a linux
285 /// kernel *module* that is part of the current corpus group that is
286 /// being built. In this case, it means we should re-use types
287 /// coming from the "vmlinux" binary that is the main corpus of the
288 /// group.
289 ///
290 /// @return the corpus group the current corpus belongs to, if the
291 /// current corpus is part of a corpus group being built. Nil otherwise.
292 corpus_sptr
should_reuse_type_from_corpus_group()293 fe_iface::should_reuse_type_from_corpus_group()
294 {
295 if (has_corpus_group())
296 if (corpus_sptr main_corpus = main_corpus_from_current_group())
297 if (!current_corpus_is_main_corpus_from_current_group())
298 return corpus_group();
299
300 return corpus_sptr();
301 }
302
303 /// Try and add the representation of the ABI of a function to the set
304 /// of exported declarations of the current corpus.
305 ///
306 /// @param fn the internal representation of the ABI of a function.
307 void
maybe_add_fn_to_exported_decls(const function_decl * fn)308 fe_iface::maybe_add_fn_to_exported_decls(const function_decl* fn)
309 {
310 if (fn)
311 if (corpus::exported_decls_builder* b =
312 corpus()->get_exported_decls_builder().get())
313 b->maybe_add_fn_to_exported_fns(fn);
314 }
315
316 /// Try and add the representation of the ABI of a variable to the set
317 /// of exported declarations of the current corpus.
318 ///
319 /// @param var the internal representation of the ABI of a variable.
320 void
maybe_add_var_to_exported_decls(const var_decl * var)321 fe_iface::maybe_add_var_to_exported_decls(const var_decl* var)
322 {
323 if (var)
324 if (corpus::exported_decls_builder* b =
325 corpus()->get_exported_decls_builder().get())
326 b->maybe_add_var_to_exported_vars(var);
327 }
328
329 /// The bitwise OR operator for the @ref fe_iface::status type.
330 ///
331 /// @param l the left-hand side operand.
332 ///
333 /// @param r the right-hand side operand.
334 ///
335 /// @return the result of the operation.
336 fe_iface::status
operator |(fe_iface::status l,fe_iface::status r)337 operator|(fe_iface::status l, fe_iface::status r)
338 {
339 return static_cast<fe_iface::status>(static_cast<unsigned>(l)
340 | static_cast<unsigned>(r));
341 }
342
343 /// The bitwise AND operator for the @ref fe_iface::status type.
344 ///
345 /// @param l the left-hand side operand.
346 ///
347 /// @param r the right-hand side operand.
348 ///
349 /// @return the result of the operation.
350 fe_iface::status
operator &(fe_iface::status l,fe_iface::status r)351 operator&(fe_iface::status l, fe_iface::status r)
352 {
353 return static_cast<fe_iface::status>(static_cast<unsigned>(l)
354 & static_cast<unsigned>(r));
355 }
356
357 /// The bitwise |= operator for the @ref fe_iface::status type.
358 ///
359 /// @param l the left-hand side operand.
360 ///
361 /// @param r the right-hand side operand.
362 ///
363 /// @return the result of the operation.
364 fe_iface::status&
operator |=(fe_iface::status & l,fe_iface::status r)365 operator|=(fe_iface::status& l, fe_iface::status r)
366 {
367 l = l | r;
368 return l;
369 }
370
371 /// The bitwise &= operator for the @ref fe_iface::status type.
372 ///
373 /// @param l the left-hand side operand.
374 ///
375 /// @param r the right-hand side operand.
376 ///
377 /// @return the result of the operation.
378 fe_iface::status&
operator &=(fe_iface::status & l,fe_iface::status r)379 operator&=(fe_iface::status& l, fe_iface::status r)
380 {
381 l = l & r;
382 return l;
383 }
384
385 /// Return a diagnostic status with english sentences to describe the
386 /// problems encoded in a given abigail::elf_reader::status, if
387 /// there is an error.
388 ///
389 /// @param status the status to diagnose
390 ///
391 /// @return a string containing sentences that describe the possible
392 /// errors encoded in @p s. If there is no error to encode, then the
393 /// empty string is returned.
394 std::string
status_to_diagnostic_string(fe_iface::status s)395 status_to_diagnostic_string(fe_iface::status s)
396 {
397 std::string str;
398
399 if (s & fe_iface::STATUS_DEBUG_INFO_NOT_FOUND)
400 str += "could not find debug info\n";
401
402 if (s & fe_iface::STATUS_ALT_DEBUG_INFO_NOT_FOUND)
403 str += "could not find alternate debug info\n";
404
405 if (s & fe_iface::STATUS_NO_SYMBOLS_FOUND)
406 str += "could not load ELF symbols\n";
407
408 return str;
409 }
410
411 }// namespace abigail
412