• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
2 // -*- Mode: C++ -*-
3 //
4 // Copyright (C) 2022-2023 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     corpus_path.clear();
47     dt_soname.clear();
48     suppressions.clear();
49     corpus_group.reset();
50     corpus.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 void
initialize(const std::string & corpus_path)82 fe_iface::initialize(const std::string& corpus_path)
83 {
84   priv_->initialize();
85   priv_->corpus_path = corpus_path;
86 }
87 
88 /// Getter of the the options of the current Front End Interface.
89 ///
90 /// @return the options of the current Front End Interface.
91 const fe_iface::options_type&
options() const92 fe_iface::options() const
93 {return priv_->options;}
94 
95 /// Getter of the the options of the current Front End Interface.
96 ///
97 /// @return the options of the current Front End Interface.
98 fe_iface::options_type&
options()99 fe_iface::options()
100 {return priv_->options;}
101 
102 /// Getter of the path to the file which an ABI corpus is to be
103 /// created for.
104 ///
105 /// @return the path to the file which an ABI corpus is to be created
106 /// for.
107 const std::string&
corpus_path() const108 fe_iface::corpus_path() const
109 {return priv_->corpus_path;}
110 
111 /// Setter of the path to the file which an ABI corpus is to be
112 /// created for.
113 ///
114 /// @param p the new path to the file which an ABI corpus is to be
115 /// created for.
116 void
corpus_path(const std::string & p)117 fe_iface::corpus_path(const std::string& p)
118 {priv_->corpus_path = p;}
119 
120 /// Getter for the SONAME of the analyzed binary.
121 ///
122 /// @return the SONAME of the analyzed binary.
123 const string&
dt_soname() const124 fe_iface::dt_soname() const
125 {return priv_->dt_soname;}
126 
127 /// Getter for the SONAME of the analyzed binary.
128 ///
129 /// @return the SONAME of the analyzed binary.
130 void
dt_soname(const string & soname)131 fe_iface::dt_soname(const string& soname)
132 {priv_->dt_soname = soname;}
133 
134 /// Test if the input binary is to be considered as a Linux Kernel
135 /// binary.
136 ///
137 /// @return true iff the input binary is to be considered as a Linux
138 /// Kernel binary.
139 bool
load_in_linux_kernel_mode() const140 fe_iface::load_in_linux_kernel_mode() const
141 {return priv_->options.load_in_linux_kernel_mode;}
142 
143 /// Getter of the vector of suppression specifications associated with
144 /// the current front-end.
145 ///
146 /// @return the vector of suppression specifications associated with
147 /// the current front-end.
148 suppr::suppressions_type&
suppressions()149 fe_iface::suppressions()
150 {return priv_->suppressions;}
151 
152 /// Getter of the vector of suppression specifications associated with
153 /// the current front-end.
154 ///
155 /// @return the vector of suppression specifications associated with
156 /// the current front-end.
157 const suppr::suppressions_type&
suppressions() const158 fe_iface::suppressions() const
159 {return priv_->suppressions;}
160 
161 /// Setter of the vector of suppression specifications associated with
162 /// the current front-end.
163 ///
164 /// @param supprs the new vector of suppression specifications
165 /// associated with the current front-end.
166 void
suppressions(suppr::suppressions_type & supprs)167 fe_iface::suppressions(suppr::suppressions_type& supprs)
168 {priv_->suppressions = supprs;}
169 
170 /// Add suppressions specifications to the set of suppressions to be
171 /// used during the construction of the ABI internal representation
172 /// (the ABI corpus) from the input file.
173 ///
174 /// During the construction of the ABI corpus, ABI artifacts that
175 /// match a given suppression specification are dropped on the floor;
176 /// that is, they are discarded and won't be part of the final ABI
177 /// corpus.  This is a way to reduce the amount of data held by the
178 /// final ABI corpus.
179 ///
180 /// Note that the suppression specifications provided to this function
181 /// are only considered during the construction of the ABI corpus.
182 /// For instance, they are not taken into account during e.g
183 /// comparisons of two ABI corpora that might happen later.  If you
184 /// want to apply suppression specificatins to the comparison (or
185 /// reporting) of ABI corpora please refer to the documentation of the
186 /// @ref diff_context type to learn how to set suppressions that are
187 /// to be used in that context.
188 ///
189 /// @param supprs the suppression specifications to be applied during
190 /// the construction of the ABI corpus.
191 void
add_suppressions(const suppr::suppressions_type & supprs)192 fe_iface::add_suppressions(const suppr::suppressions_type& supprs)
193 {
194   for (const auto& s : supprs)
195     if (s->get_drops_artifact_from_ir())
196       suppressions().push_back(s);
197 }
198 
199 /// Getter for the ABI corpus being built by the current front-end.
200 ///
201 /// @return the ABI corpus being built by the current front-end.
202 corpus_sptr
corpus()203 fe_iface::corpus()
204 {
205   if (!priv_->corpus)
206     {
207       priv_->corpus = std::make_shared<ir::corpus>(options().env,
208 						   corpus_path());
209     }
210   return priv_->corpus;
211 }
212 
213 /// Getter for the ABI corpus being built by the current front-end.
214 ///
215 /// @return the ABI corpus being built by the current front-end.
216 const corpus_sptr
corpus() const217 fe_iface::corpus() const
218 {return const_cast<fe_iface*>(this)->corpus();}
219 
220 /// Getter for the ABI corpus group being built by the current front-end.
221 ///
222 /// @return the ABI corpus group being built by the current front-end.
223 corpus_group_sptr&
corpus_group()224 fe_iface::corpus_group()
225 {return priv_->corpus_group;}
226 
227 /// Getter for the ABI corpus group being built by the current front-end.
228 ///
229 /// @return the ABI corpus group being built by the current front-end.
230 const corpus_group_sptr&
corpus_group() const231 fe_iface::corpus_group() const
232 {return const_cast<fe_iface*>(this)->corpus_group();}
233 
234 /// Setter for the ABI corpus group being built by the current
235 /// front-end.
236 ///
237 /// @param cg the new ABI corpus group being built by the current
238 /// front-end.
239 void
corpus_group(const ir::corpus_group_sptr & cg)240 fe_iface::corpus_group(const ir::corpus_group_sptr& cg)
241 {priv_->corpus_group = cg;}
242 
243 /// Test if there is a corpus group being built.
244 ///
245 /// @return if there is a corpus group being built, false otherwise.
246 bool
has_corpus_group() const247 fe_iface::has_corpus_group() const
248 {return bool(corpus_group());}
249 
250 /// Return the main corpus from the current corpus group, if any.
251 ///
252 /// @return the main corpus of the current corpus group, if any, nil
253 /// if no corpus group is being constructed.
254 corpus_sptr
main_corpus_from_current_group()255 fe_iface::main_corpus_from_current_group()
256 {
257   if (corpus_group())
258     return corpus_group()->get_main_corpus();
259   return corpus_sptr();
260 }
261 
262 /// Test if the current corpus being built is the main corpus of the
263 /// current corpus group.
264 ///
265 /// @return return true iff the current corpus being built is the
266 /// main corpus of the current corpus group.
267 bool
current_corpus_is_main_corpus_from_current_group()268 fe_iface::current_corpus_is_main_corpus_from_current_group()
269 {
270   corpus_sptr main_corpus = main_corpus_from_current_group();
271 
272   if (main_corpus.get() == corpus().get())
273     return true;
274 
275   return false;
276 }
277 
278 /// Return true if the current corpus is part of a corpus group
279 /// being built and if it's not the main corpus of the group.
280 ///
281 /// For instance, this would return true if we are loading a linux
282 /// kernel *module* that is part of the current corpus group that is
283 /// being built.  In this case, it means we should re-use types
284 /// coming from the "vmlinux" binary that is the main corpus of the
285 /// group.
286 ///
287 /// @return the corpus group the current corpus belongs to, if the
288 /// current corpus is part of a corpus group being built. Nil otherwise.
289 corpus_sptr
should_reuse_type_from_corpus_group()290 fe_iface::should_reuse_type_from_corpus_group()
291 {
292   if (has_corpus_group())
293     if (corpus_sptr main_corpus = main_corpus_from_current_group())
294 	if (!current_corpus_is_main_corpus_from_current_group())
295 	  return corpus_group();
296 
297   return corpus_sptr();
298 }
299 
300 /// Try and add the representation of the ABI of a function to the set
301 /// of exported declarations of the current corpus.
302 ///
303 /// @param fn the internal representation of the ABI of a function.
304 void
maybe_add_fn_to_exported_decls(const function_decl * fn)305 fe_iface::maybe_add_fn_to_exported_decls(const function_decl* fn)
306 {
307   if (fn)
308     if (corpus::exported_decls_builder* b =
309 	corpus()->get_exported_decls_builder().get())
310       b->maybe_add_fn_to_exported_fns(const_cast<function_decl*>(fn));
311 }
312 
313 /// Try and add the representation of the ABI of a variable to the set
314 /// of exported declarations of the current corpus.
315 ///
316 /// @param var the internal representation of the ABI of a variable.
317 void
maybe_add_var_to_exported_decls(const var_decl * var)318 fe_iface::maybe_add_var_to_exported_decls(const var_decl* var)
319 {
320   if (var)
321     if (corpus::exported_decls_builder* b =
322 	corpus()->get_exported_decls_builder().get())
323       b->maybe_add_var_to_exported_vars(var);
324 }
325 
326 /// The bitwise OR operator for the @ref fe_iface::status type.
327 ///
328 /// @param l the left-hand side operand.
329 ///
330 /// @param r the right-hand side operand.
331 ///
332 /// @return the result of the operation.
333 fe_iface::status
operator |(fe_iface::status l,fe_iface::status r)334 operator|(fe_iface::status l, fe_iface::status r)
335 {
336   return static_cast<fe_iface::status>(static_cast<unsigned>(l)
337 				       | static_cast<unsigned>(r));
338 }
339 
340 /// The bitwise AND operator for the @ref fe_iface::status type.
341 ///
342 /// @param l the left-hand side operand.
343 ///
344 /// @param r the right-hand side operand.
345 ///
346 /// @return the result of the operation.
347 fe_iface::status
operator &(fe_iface::status l,fe_iface::status r)348 operator&(fe_iface::status l, fe_iface::status r)
349 {
350   return static_cast<fe_iface::status>(static_cast<unsigned>(l)
351 				       & static_cast<unsigned>(r));
352 }
353 
354 /// The bitwise |= operator for the @ref fe_iface::status type.
355 ///
356 /// @param l the left-hand side operand.
357 ///
358 /// @param r the right-hand side operand.
359 ///
360 /// @return the result of the operation.
361 fe_iface::status&
operator |=(fe_iface::status & l,fe_iface::status r)362 operator|=(fe_iface::status& l, fe_iface::status r)
363 {
364   l = l | r;
365   return l;
366 }
367 
368 /// The bitwise &= operator for the @ref fe_iface::status type.
369 ///
370 /// @param l the left-hand side operand.
371 ///
372 /// @param r the right-hand side operand.
373 ///
374 /// @return the result of the operation.
375 fe_iface::status&
operator &=(fe_iface::status & l,fe_iface::status r)376 operator&=(fe_iface::status& l, fe_iface::status r)
377 {
378   l = l & r;
379   return l;
380 }
381 
382 /// Return a diagnostic status with english sentences to describe the
383 /// problems encoded in a given abigail::elf_reader::status, if
384 /// there is an error.
385 ///
386 /// @param status the status to diagnose
387 ///
388 /// @return a string containing sentences that describe the possible
389 /// errors encoded in @p s.  If there is no error to encode, then the
390 /// empty string is returned.
391 std::string
status_to_diagnostic_string(fe_iface::status s)392 status_to_diagnostic_string(fe_iface::status s)
393 {
394   std::string str;
395 
396   if (s & fe_iface::STATUS_DEBUG_INFO_NOT_FOUND)
397     str += "could not find debug info";
398 
399   if (s & fe_iface::STATUS_ALT_DEBUG_INFO_NOT_FOUND)
400     str += "could not find alternate debug info";
401 
402   if (s & fe_iface::STATUS_NO_SYMBOLS_FOUND)
403     str += "could not load ELF symbols";
404 
405   return str;
406 }
407 
408 }// namespace abigail
409