libabigail
abg-elf-reader.cc
Go to the documentation of this file.
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 /// Elf reader stuff
11 
12 #include "abg-internal.h"
13 
14 #include <fcntl.h> /* For open(3) */
15 #include <unistd.h>
16 #include <iostream>
17 #include <cstring>
18 #include <libgen.h>
19 #include <fcntl.h>
20 #include <elfutils/libdwfl.h>
21 
22 
23 #include "abg-symtab-reader.h"
24 #include "abg-suppression-priv.h"
25 #include "abg-elf-helpers.h"
26 
27 // <headers defining libabigail's API go under here>
28 ABG_BEGIN_EXPORT_DECLARATIONS
29 #include "abg-elf-reader.h"
30 #include "abg-tools-utils.h"
31 ABG_END_EXPORT_DECLARATIONS
32 // </headers defining libabigail's API>
33 namespace abigail
34 {
35 
36 using namespace elf_helpers;
37 
38 namespace elf
39 {
40 
41 /// Find the file name of the alternate debug info file.
42 ///
43 /// @param elf_module the elf module to consider.
44 ///
45 /// @param out parameter. Is set to the file name of the alternate
46 /// debug info file, iff this function returns true.
47 ///
48 /// @return true iff the location of the alternate debug info file was
49 /// found.
50 static bool
51 find_alt_dwarf_debug_info_link(Dwfl_Module *elf_module,
52  string &alt_file_name)
53 {
54  GElf_Addr bias = 0;
55  Dwarf *dwarf = dwfl_module_getdwarf(elf_module, &bias);
56  Elf *elf = dwarf_getelf(dwarf);
57  GElf_Ehdr ehmem, *elf_header;
58  elf_header = gelf_getehdr(elf, &ehmem);
59 
60  Elf_Scn* section = 0;
61  while ((section = elf_nextscn(elf, section)) != 0)
62  {
63  GElf_Shdr header_mem, *header;
64  header = gelf_getshdr(section, &header_mem);
65  if (header->sh_type != SHT_PROGBITS)
66  continue;
67 
68  const char *section_name = elf_strptr(elf,
69  elf_header->e_shstrndx,
70  header->sh_name);
71 
72  char *alt_name = 0;
73  char *buildid = 0;
74  size_t buildid_len = 0;
75  if (section_name != 0
76  && strcmp(section_name, ".gnu_debugaltlink") == 0)
77  {
78  Elf_Data *data = elf_getdata(section, 0);
79  if (data != 0 && data->d_size != 0)
80  {
81  alt_name = (char*) data->d_buf;
82  char *end_of_alt_name =
83  (char *) memchr(alt_name, '\0', data->d_size);
84  buildid_len = data->d_size - (end_of_alt_name - alt_name + 1);
85  if (buildid_len == 0)
86  return false;
87  buildid = end_of_alt_name + 1;
88  }
89  }
90  else
91  continue;
92 
93  if (buildid == 0 || alt_name == 0)
94  return false;
95 
96  alt_file_name = alt_name;
97  return true;
98  }
99 
100  return false;
101 }
102 
103 /// Find alternate debuginfo file of a given "link" under a set of
104 /// root directories.
105 ///
106 /// The link is a string that is read by the function
107 /// find_alt_dwarf_debug_info_link(). That link is a path that is relative
108 /// to a given debug info file, e.g, "../../../.dwz/something.debug".
109 /// It designates the alternate debug info file associated to a given
110 /// debug info file.
111 ///
112 /// This function will thus try to find the .dwz/something.debug file
113 /// under some given root directories.
114 ///
115 /// @param root_dirs the set of root directories to look from.
116 ///
117 /// @param alt_file_name a relative path to the alternate debug info
118 /// file to look for.
119 ///
120 /// @param alt_file_path the resulting absolute path to the alternate
121 /// debuginfo path denoted by @p alt_file_name and found under one of
122 /// the directories in @p root_dirs. This is set iff the function
123 /// returns true.
124 ///
125 /// @return true iff the function found the alternate debuginfo file.
126 static bool
127 find_alt_dwarf_debug_info_path(const vector<char**> root_dirs,
128  const string &alt_file_name,
129  string &alt_file_path)
130 {
131  if (alt_file_name.empty())
132  return false;
133 
134  string altfile_name = tools_utils::trim_leading_string(alt_file_name, "../");
135  // In case the alt dwarf debug info file is to be found under
136  // "/usr/lib/debug", look for it under the provided root directories
137  // instead.
138  altfile_name = tools_utils::trim_leading_string(altfile_name,
139  "/usr/lib/debug/");
140 
141  for (vector<char**>::const_iterator i = root_dirs.begin();
142  i != root_dirs.end();
143  ++i)
144  if (tools_utils::find_file_under_dir(**i, altfile_name, alt_file_path))
145  return true;
146 
147  return false;
148 }
149 
150 /// Return the alternate debug info associated to a given main debug
151 /// info file.
152 ///
153 /// @param elf_module the elf module to consider.
154 ///
155 /// @param debug_root_dirs a set of root debuginfo directories under
156 /// which too look for the alternate debuginfo file.
157 ///
158 /// @param alt_file_name output parameter. This is set to the file
159 /// path of the alternate debug info file associated to @p elf_module.
160 /// This is set iff the function returns a non-null result.
161 ///
162 /// @param alt_fd the file descriptor used to access the alternate
163 /// debug info. If this parameter is set by the function, then the
164 /// caller needs to fclose it, otherwise the file descriptor is going
165 /// to be leaked. Note however that on recent versions of elfutils
166 /// where libdw.h contains the function dwarf_getalt(), this parameter
167 /// is set to 0, so it doesn't need to be fclosed.
168 ///
169 /// Note that the alternate debug info file is a DWARF extension as of
170 /// DWARF 4 ans is decribed at
171 /// http://www.dwarfstd.org/ShowIssue.php?issue=120604.1.
172 ///
173 /// @return the alternate debuginfo, or null. If @p alt_fd is
174 /// non-zero, then the caller of this function needs to call
175 /// dwarf_end() on the returned alternate debuginfo pointer,
176 /// otherwise, it's going to be leaked.
177 static Dwarf*
178 find_alt_dwarf_debug_info(Dwfl_Module *elf_module,
179  const vector<char**> debug_root_dirs,
180  string& alt_file_name,
181  int& alt_fd)
182 {
183  if (elf_module == 0)
184  return 0;
185 
186  Dwarf* result = 0;
187  find_alt_dwarf_debug_info_link(elf_module, alt_file_name);
188 
189 #ifdef LIBDW_HAS_DWARF_GETALT
190  // We are on recent versions of elfutils where the function
191  // dwarf_getalt exists, so let's use it.
192  Dwarf_Addr bias = 0;
193  Dwarf* dwarf = dwfl_module_getdwarf(elf_module, &bias);
194  result = dwarf_getalt(dwarf);
195  alt_fd = 0;
196 #else
197  // We are on an old version of elfutils where the function
198  // dwarf_getalt doesn't exist yet, so let's open code its
199  // functionality
200  char *alt_name = 0;
201  const char *file_name = 0;
202  void **user_data = 0;
203  Dwarf_Addr low_addr = 0;
204  char *alt_file = 0;
205 
206  file_name = dwfl_module_info(elf_module, &user_data,
207  &low_addr, 0, 0, 0, 0, 0);
208 
209  alt_fd = dwfl_standard_find_debuginfo(elf_module, user_data,
210  file_name, low_addr,
211  alt_name, file_name,
212  0, &alt_file);
213 
214  result = dwarf_begin(alt_fd, DWARF_C_READ);
215 #endif
216 
217  if (result == 0)
218  {
219  // So we didn't find the alternate debuginfo file from the
220  // information that is in the debuginfo file associated to
221  // elf_module. Maybe the alternate debuginfo file is located
222  // under one of the directories in debug_root_dirs. So let's
223  // look in there.
224  string alt_file_path;
225  if (!find_alt_dwarf_debug_info_path(debug_root_dirs,
226  alt_file_name,
227  alt_file_path))
228  return result;
229 
230  // If we reach this point it means we have found the path to the
231  // alternate debuginfo file and it's in alt_file_path. So let's
232  // open it and read it.
233  alt_fd = open(alt_file_path.c_str(), O_RDONLY);
234  if (alt_fd == -1)
235  return result;
236  result = dwarf_begin(alt_fd, DWARF_C_READ);
237 
238 #ifdef LIBDW_HAS_DWARF_GETALT
239  Dwarf_Addr bias = 0;
240  Dwarf* dwarf = dwfl_module_getdwarf(elf_module, &bias);
241  dwarf_setalt(dwarf, result);
242 #endif
243  }
244 
245  return result;
246 }
247 
248 /// Private data of the @ref elf::reader type.
249 struct reader::priv
250 {
251  reader& rdr;
252  Elf* elf_handle = nullptr;
253  Elf_Scn* symtab_section = nullptr;
254  string elf_architecture;
255  vector<string> dt_needed;
256  // An abstraction of the symbol table. This is loaded lazily, on
257  // demand.
258  mutable symtab_reader::symtab_sptr symt;
259  // Where split debug info is to be searched for on disk.
260  vector<char**> debug_info_root_paths;
261  // Some very useful callback functions that elfutils needs to
262  // perform various tasks.
263  Dwfl_Callbacks offline_callbacks;
264  // A pointer to the DWARF Front End Library handle of elfutils.
265  // This is useful to perform all kind of things at a higher level.
266  dwfl_sptr dwfl_handle;
267  // The address range of the offline elf file we are looking at.
268  Dwfl_Module* elf_module = nullptr;
269  // A pointer to the DWARF debug info, if found by locate_dwarf_debug_info.
270  Dwarf* dwarf_handle = nullptr;
271  // A pointer to the ALT DWARF debug info, which is the debug info
272  // that is constructed by the DWZ tool. It's made of all the type
273  // information that was redundant in the DWARF. DWZ put it there
274  // and make the DWARF reference it in here.
275  Dwarf* alt_dwarf_handle = nullptr;
276  string alt_dwarf_path;
277  int alt_dwarf_fd = 0;
278  Elf_Scn* ctf_section = nullptr;
279  int alt_ctf_fd = 0;
280  Elf* alt_ctf_handle = nullptr;
281  Elf_Scn* alt_ctf_section = nullptr;
282  Elf_Scn* btf_section = nullptr;
283 
284  priv(reader& reeder, const std::string& elf_path,
285  const vector<char**>& debug_info_roots)
286  : rdr(reeder)
287  {
288  rdr.corpus_path(elf_path);
289  initialize(debug_info_roots);
290  }
291 
292  ~priv()
293  {
294  clear_alt_dwarf_debug_info_data();
295  clear_alt_ctf_debug_info_data();
296  }
297 
298  /// Reset the private data of @elf elf::reader.
299  ///
300  /// @param debug_info_roots the vector of new directories where to
301  /// look for split debug info file.
302  void
303  initialize(const vector<char**>& debug_info_roots)
304  {
305  clear_alt_dwarf_debug_info_data();
306  clear_alt_ctf_debug_info_data();
307 
308  elf_handle = nullptr;
309  symtab_section = nullptr;
310  elf_architecture.clear();
311  dt_needed.clear();
312  symt.reset();
313  debug_info_root_paths = debug_info_roots;
314  offline_callbacks = {};
315  dwfl_handle.reset();
316  elf_module = nullptr;
317  dwarf_handle = nullptr;
318  alt_dwarf_handle = nullptr;
319  alt_dwarf_path.clear();
320  alt_dwarf_fd = 0;
321  ctf_section = nullptr;
322  alt_ctf_section = nullptr;
323  alt_ctf_handle = nullptr;
324  alt_ctf_fd = 0;
325  }
326 
327  /// Setup the necessary plumbing to open the ELF file and find all
328  /// the associated split debug info files.
329  ///
330  /// This function also setup the various handles on the opened ELF
331  /// file and whatnot.
332  void
333  crack_open_elf_file()
334  {
335  // Initialize the callback functions used by elfutils.
336  elf_helpers::initialize_dwfl_callbacks(offline_callbacks,
337  debug_info_root_paths.empty()
338  ? nullptr
339  : debug_info_root_paths.front());
340 
341  // Create a handle to the DWARF Front End Library that we'll need.
342  dwfl_handle = elf_helpers::create_new_dwfl_handle(offline_callbacks);
343 
344  const string& elf_path = rdr.corpus_path();
345  // Get the set of addresses that make up the ELF file we are
346  // looking at.
347  elf_module =
348  dwfl_report_offline(dwfl_handle.get(),
349  basename(const_cast<char*>(elf_path.c_str())),
350  elf_path.c_str(), -1);
351  dwfl_report_end(dwfl_handle.get(), 0, 0);
352  ABG_ASSERT(elf_module);
353 
354  // Finally, get and handle at the representation of the ELF file
355  // we've just cracked open.
356  GElf_Addr bias = 0;
357  elf_handle = dwfl_module_getelf(elf_module, &bias);
358  ABG_ASSERT(elf_handle);
359  }
360 
361  /// Find the alternate debuginfo file associated to a given elf file.
362  ///
363  /// @param elf_module represents the elf file to consider.
364  ///
365  /// @param alt_file_name the resulting path to the alternate
366  /// debuginfo file found. This is set iff the function returns a
367  /// non-nil value.
368  Dwarf*
369  find_alt_dwarf_debug_info(Dwfl_Module* elf_module,
370  string& alt_file_name,
371  int& alt_fd)
372  {
373  Dwarf *result = 0;
374  result = elf::find_alt_dwarf_debug_info(elf_module,
375  debug_info_root_paths,
376  alt_file_name, alt_fd);
377  return result;
378  }
379 
380  /// Clear the resources related to the alternate DWARF data.
381  void
382  clear_alt_dwarf_debug_info_data()
383  {
384  if (alt_dwarf_fd)
385  {
386  if (alt_dwarf_handle)
387  {
388  dwarf_end(alt_dwarf_handle);
389  alt_dwarf_handle = nullptr;
390  }
391  close(alt_dwarf_fd);
392  alt_dwarf_fd = 0;
393  }
394  alt_dwarf_path.clear();
395  }
396 
397  /// Locate the DWARF debug info in the ELF file.
398  ///
399  /// This also knows how to locate split debug info.
400  void
401  locate_dwarf_debug_info()
402  {
403  ABG_ASSERT(dwfl_handle);
404 
405  if (dwarf_handle)
406  return;
407 
408  // First let's see if the ELF file that was cracked open does have
409  // some DWARF debug info embedded.
410  Dwarf_Addr bias = 0;
411  dwarf_handle = dwfl_module_getdwarf(elf_module, &bias);
412 
413  // If no debug info was found in the binary itself, then look for
414  // split debuginfo files under multiple possible debuginfo roots.
415  for (vector<char**>::const_iterator i = debug_info_root_paths.begin();
416  dwarf_handle == 0 && i != debug_info_root_paths.end();
417  ++i)
418  {
419  offline_callbacks.debuginfo_path = *i;
420  dwarf_handle = dwfl_module_getdwarf(elf_module, &bias);
421  }
422 
423  alt_dwarf_handle = find_alt_dwarf_debug_info(elf_module,
424  alt_dwarf_path,
425  alt_dwarf_fd);
426  }
427 
428  /// Clear the resources related to the alternate CTF data.
429  void
430  clear_alt_ctf_debug_info_data()
431  {
432  if (alt_ctf_fd)
433  {
434  close(alt_ctf_fd);
435  alt_ctf_fd = 0;
436  }
437  if (alt_ctf_handle)
438  {
439  elf_end(alt_ctf_handle);
440  alt_ctf_handle = nullptr;
441  }
442  }
443 
444  /// Locate the CTF "alternate" debug information associated with the
445  /// current ELF file ( and split out somewhere else).
446  ///
447  /// This is a sub-routine of @ref locate_ctf_debug_info().
448  void
449  locate_alt_ctf_debug_info()
450  {
451  if (alt_ctf_section)
452  return;
453 
454  Elf_Scn *section =
455  elf_helpers::find_section(elf_handle,
456  ".gnu_debuglink",
457  SHT_PROGBITS);
458 
459  std::string name;
460  Elf_Data *data;
461  if (section
462  && (data = elf_getdata(section, nullptr))
463  && data->d_size != 0)
464  name = (char *) data->d_buf;
465 
466  if (!name.empty())
467  for (const auto& path : rdr.debug_info_root_paths())
468  {
469  std::string file_path;
470  if (!tools_utils::find_file_under_dir(*path, name, file_path))
471  continue;
472 
473  if ((alt_ctf_fd = open(file_path.c_str(), O_RDONLY)) == -1)
474  continue;
475 
476  if ((alt_ctf_handle = elf_begin(alt_ctf_fd,
477  ELF_C_READ,
478  nullptr)) == nullptr)
479  continue;
480 
481  // unlikely .ctf was designed to be present in stripped file
482  alt_ctf_section =
483  elf_helpers::find_section(alt_ctf_handle, ".ctf", SHT_PROGBITS);
484 
485  if (alt_ctf_section)
486  break;
487  }
488  }
489 
490  /// Locate the CTF debug information associated with the current ELF
491  /// file. It also locates the CTF debug information that is split
492  /// out in a separate file.
493  void
494  locate_ctf_debug_info()
495  {
496  ABG_ASSERT(elf_handle);
497 
498  ctf_section = elf_helpers::find_section_by_name(elf_handle, ".ctf");
499  if (ctf_section == nullptr)
500  {
501  locate_alt_ctf_debug_info();
502  ctf_section = alt_ctf_section;
503  }
504  }
505 }; //end reader::priv
506 
507 /// The constructor of the @ref elf::reader type.
508 ///
509 /// @param elf_path the path to the ELF file to read from.
510 ///
511 /// @param debug_info_root a vector of directory paths to look into
512 /// for split debug information files.
513 ///
514 /// @param env the environment which the reader operates in.
515 reader::reader(const string& elf_path,
516  const vector<char**>& debug_info_roots,
517  ir::environment& env)
518  : fe_iface(elf_path, env),
519  priv_(new priv(*this, elf_path, debug_info_roots))
520 {
521  priv_->crack_open_elf_file();
522  priv_->locate_dwarf_debug_info();
523  priv_->locate_ctf_debug_info();
524 }
525 
526 /// The destructor of the @ref elf::reader type.
527 reader::~reader()
528 {delete priv_;}
529 
530 /// Resets (erase) the resources used by the current @ref
531 /// elf::reader type.
532 ///
533 /// This lets the reader in a state where it's ready to read from
534 /// another ELF file.
535 ///
536 /// @param elf_path the new ELF path to read from.
537 ///
538 /// @param debug_info_roots a vector of directory paths to look into
539 /// for split debug information files.
540 void
541 reader::reset(const std::string& elf_path,
542  const vector<char**>& debug_info_roots)
543 {
544  fe_iface::options_type opts = options();
545  fe_iface::reset(elf_path, opts.env);
546  corpus_path(elf_path);
547  priv_->initialize(debug_info_roots);
548  priv_->crack_open_elf_file();
549  priv_->locate_dwarf_debug_info();
550  priv_->locate_ctf_debug_info();
551 }
552 
553 /// Getter of the vector of directory paths to look into for split
554 /// debug information files.
555 ///
556 /// @return the vector of directory paths to look into for split
557 /// debug information files.
558 const vector<char**>&
559 reader::debug_info_root_paths() const
560 {return priv_->debug_info_root_paths;}
561 
562 /// Getter of the functions used by the DWARF Front End library of
563 /// elfutils to locate DWARF debug information.
564 ///
565 /// @return the functions used by the DWARF Front End library of
566 const Dwfl_Callbacks&
567 reader::dwfl_offline_callbacks() const
568 {return priv_->offline_callbacks;}
569 
570 /// Getter of the functions used by the DWARF Front End library of
571 /// elfutils to locate DWARF debug information.
572 ///
573 /// @return the functions used by the DWARF Front End library of
574 Dwfl_Callbacks&
575 reader::dwfl_offline_callbacks()
576 {return priv_->offline_callbacks;}
577 
578 /// Getter of the handle used to access ELF information from the
579 /// current ELF file.
580 ///
581 /// @return the handle used to access ELF information from the current
582 /// ELF file.
583 Elf*
584 reader::elf_handle() const
585 {return priv_->elf_handle;}
586 
587 /// Getter of the handle used to access DWARF information from the
588 /// current ELF file.
589 ///
590 /// @return the handle used to access DWARF information from the
591 /// current ELF file.
592 const Dwarf*
593 reader::dwarf_debug_info() const
594 {return priv_->dwarf_handle;}
595 
596 /// Test if the binary has DWARF debug info.
597 ///
598 /// @return true iff the binary has DWARF debug info.
599 bool
600 reader::has_dwarf_debug_info() const
601 {return ((priv_->dwarf_handle != nullptr)
602  || (priv_->alt_dwarf_handle != nullptr));}
603 
604 /// Test if the binary has CTF debug info.
605 ///
606 /// @return true iff the binary has CTF debug info.
607 bool
608 reader::has_ctf_debug_info() const
609 {return (priv_->ctf_section != nullptr);}
610 
611 /// Test if the binary has BTF debug info.
612 ///
613 /// @return true iff the binary has BTF debug info
614 bool
615 reader::has_btf_debug_info() const
616 {return (priv_->btf_section != nullptr);}
617 
618 /// Getter of the handle use to access DWARF information from the
619 /// alternate split DWARF information.
620 ///
621 /// In other words, this accesses the factorized DWARF information
622 /// that has been constructed by the DWZ tool to de-duplicate DWARF
623 /// information on disk.
624 ///
625 /// @return the handle use to access DWARF information from the
626 /// alternate split DWARF information.
627 const Dwarf*
628 reader::alternate_dwarf_debug_info() const
629 {return priv_->alt_dwarf_handle;}
630 
631 
632 /// Getter of the path to the alternate split DWARF information file,
633 /// on disk. In othe words, this returns the path to the factorized
634 /// DWARF information used by the current ELF file, created by the
635 /// 'DWZ' tool.
636 ///
637 /// @return the path to the alternate split DWARF information file,
638 /// on disk.
639 const string&
640 reader::alternate_dwarf_debug_info_path() const
641 {return priv_->alt_dwarf_path;}
642 
643 /// Check if the underlying elf file refers to an alternate debug info
644 /// file associated to it.
645 ///
646 /// Note that "alternate debug info sections" is a GNU extension as
647 /// of DWARF4 and is described at
648 /// http://www.dwarfstd.org/ShowIssue.php?issue=120604.1.
649 ///
650 /// @param alt_di the path to the alternate debug info file. This is
651 /// set iff the function returns true.
652 ///
653 /// @return true if the ELF file refers to an alternate debug info
654 /// file.
655 bool
656 reader::refers_to_alt_debug_info(string& alt_di_path) const
657 {
658  if (!alternate_dwarf_debug_info_path().empty())
659  {
660  alt_di_path = alternate_dwarf_debug_info_path();
661  return true;
662  }
663  return false;
664 }
665 
666 /// Find and return a pointer to the ELF symbol table
667 /// section.
668 ///
669 /// @return a pointer to the ELF symbol table section.
670 const Elf_Scn*
671 reader::find_symbol_table_section() const
672 {
673  if (!priv_->symtab_section)
674  priv_->symtab_section =
675  elf_helpers::find_symbol_table_section(elf_handle());
676  return priv_->symtab_section;
677 }
678 
679 /// Clear the pointer to the ELF symbol table section.
680 void
681 reader::reset_symbol_table_section()
682 {priv_->symtab_section = nullptr;}
683 
684 /// Find and return a pointer to the the CTF section.
685 ///
686 /// @return a pointer to the the CTF section.
687 const Elf_Scn*
688 reader::find_ctf_section() const
689 {
690  if (priv_->ctf_section == nullptr)
691  priv_->locate_ctf_debug_info();
692 
693  if (priv_->ctf_section)
694  return priv_->ctf_section;
695 
696  return priv_->alt_ctf_section;
697 }
698 
699 /// Find and return a pointer to the alternate CTF section of the
700 /// current ELF file.
701 ///
702 /// @return a pointer to the alternate CTF section of the current ELF
703 /// file.
704 const Elf_Scn*
705 reader::find_alternate_ctf_section() const
706 {
707  if (priv_->alt_ctf_section == nullptr)
708  priv_->locate_alt_ctf_debug_info();
709 
710  return priv_->alt_ctf_section;
711 }
712 
713 /// Find and return a pointer to the BTF section of the current ELF
714 /// file.
715 ///
716 /// @return a pointer to the BTF section of the current ELF file.
717 const Elf_Scn*
718 reader::find_btf_section() const
719 {
720  if (priv_->btf_section == nullptr)
721  priv_->btf_section =
722  elf_helpers::find_section(priv_->elf_handle,
723  ".BTF", SHT_PROGBITS);
724  return priv_->btf_section;
725 }
726 
727 /// Get the value of the DT_NEEDED property of the current ELF file.
728 ///
729 /// @return the value of the DT_NEEDED property.
730 const vector<string>&
731 reader::dt_needed()const
732 {return priv_->dt_needed;}
733 
734 
735 /// Get the value of the 'ARCHITECTURE' property of the current ELF file.
736 ///
737 /// @return the value of the 'ARCHITECTURE' property of the current
738 /// ELF file.
739 const string&
740 reader::elf_architecture() const
741 {return priv_->elf_architecture;}
742 
743 /// Getter of an abstract representation of the symbol table of the
744 /// underlying ELF file.
745 ///
746 /// Note that the symbol table is loaded lazily, upon the first
747 /// invocation of this member function.
748 ///
749 /// @returnt the symbol table.
751 reader::symtab() const
752 {
753  ABG_ASSERT(elf_handle());
754 
755  if (!priv_->symt)
756  priv_->symt = symtab_reader::symtab::load
757  (elf_handle(), options().env,
758  [&](const elf_symbol_sptr& symbol)
759  {return suppr::is_elf_symbol_suppressed(*this, symbol);});
760 
761  if (!priv_->symt)
762  std::cerr << "Symbol table of '" << corpus_path()
763  << "' could not be loaded\n";
764  return priv_->symt;
765 }
766 
767 /// Test if a given function symbol has been exported.
768 ///
769 /// @param symbol_address the address of the symbol we are looking
770 /// for. Note that this address must be a relative offset from the
771 /// beginning of the .text section, just like the kind of addresses
772 /// that are present in the .symtab section.
773 ///
774 /// @return the elf symbol if found, or nil otherwise.
776 reader::function_symbol_is_exported(GElf_Addr symbol_address) const
777 {
778  elf_symbol_sptr symbol = symtab()->lookup_symbol(symbol_address);
779  if (!symbol)
780  return symbol;
781 
782  if (!symbol->is_function() || !symbol->is_public())
783  return elf_symbol_sptr();
784 
785  address_set_sptr set;
786  bool looking_at_linux_kernel_binary =
787  load_in_linux_kernel_mode() && elf_helpers::is_linux_kernel(elf_handle());
788 
789  if (looking_at_linux_kernel_binary)
790  {
791  if (symbol->is_in_ksymtab())
792  return symbol;
793  return elf_symbol_sptr();
794  }
795 
796  return symbol;
797 }
798 
799 /// Test if a given variable symbol has been exported.
800 ///
801 /// @param symbol_address the address of the symbol we are looking
802 /// for. Note that this address must be a relative offset from the
803 /// beginning of the .text section, just like the kind of addresses
804 /// that are present in the .symtab section.
805 ///
806 /// @return the elf symbol if found, or nil otherwise.
808 reader::variable_symbol_is_exported(GElf_Addr symbol_address) const
809 {
810  elf_symbol_sptr symbol = symtab()->lookup_symbol(symbol_address);
811  if (!symbol)
812  return symbol;
813 
814  if (!symbol->is_variable() || !symbol->is_public())
815  return elf_symbol_sptr();
816 
817  address_set_sptr set;
818  bool looking_at_linux_kernel_binary =
819  load_in_linux_kernel_mode() && elf_helpers::is_linux_kernel(elf_handle());
820 
821  if (looking_at_linux_kernel_binary)
822  {
823  if (symbol->is_in_ksymtab())
824  return symbol;
825  return elf_symbol_sptr();
826  }
827 
828  return symbol;
829 }
830 
831 /// Test if a given function symbol has been exported.
832 ///
833 /// @param name the name of the symbol we are looking for.
834 ///
835 /// @return the elf symbol if found, or nil otherwise.
837 reader::function_symbol_is_exported(const string& name) const
838 {
839  const elf_symbols& syms = symtab()->lookup_symbol(name);
840  for (auto s : syms)
841  {
842  if (s->is_function() && s->is_public())
843  {
844  bool looking_at_linux_kernel_binary =
845  (load_in_linux_kernel_mode()
846  && elf_helpers::is_linux_kernel(elf_handle()));
847 
848  if (looking_at_linux_kernel_binary)
849  {
850  if (s->is_in_ksymtab())
851  return s;
852  }
853  else
854  return s;
855  }
856  }
857  return elf_symbol_sptr();
858 }
859 
860 /// Test if a given variable symbol has been exported.
861 ///
862 /// @param name the name of the symbol we are looking
863 /// for.
864 ///
865 /// @return the elf symbol if found, or nil otherwise.
867 reader::variable_symbol_is_exported(const string& name) const
868 {
869  const elf_symbols& syms = symtab()->lookup_symbol(name);
870  for (auto s : syms)
871  {
872  if (s->is_variable() && s->is_public())
873  {
874  bool looking_at_linux_kernel_binary =
875  (load_in_linux_kernel_mode()
876  && elf_helpers::is_linux_kernel(elf_handle()));
877 
878  if (looking_at_linux_kernel_binary)
879  {
880  if (s->is_in_ksymtab())
881  return s;
882  }
883  else
884  return s;
885  }
886  }
887  return elf_symbol_sptr();
888 }
889 /// Load the DT_NEEDED and DT_SONAME elf TAGS.
890 void
891 reader::load_dt_soname_and_needed()
892 {
893  elf_helpers::lookup_data_tag_from_dynamic_segment(elf_handle(),
894  DT_NEEDED,
895  priv_->dt_needed);
896 
897  vector<string> dt_tag_data;
898  elf_helpers::lookup_data_tag_from_dynamic_segment(elf_handle(),
899  DT_SONAME,
900  dt_tag_data);
901  if (!dt_tag_data.empty())
902  dt_soname(dt_tag_data[0]);
903 }
904 
905 /// Read the string representing the architecture of the current ELF
906 /// file.
907 void
908 reader::load_elf_architecture()
909 {
910  if (!elf_handle())
911  return;
912 
913  GElf_Ehdr eh_mem;
914  GElf_Ehdr* elf_header = gelf_getehdr(elf_handle(), &eh_mem);
915 
916  priv_->elf_architecture =
917  elf_helpers::e_machine_to_string(elf_header->e_machine);
918 }
919 
920 /// Load various ELF data.
921 ///
922 /// This function loads ELF data that are not symbol maps or debug
923 /// info. That is, things like various tags, elf architecture and
924 /// so on.
925 void
926 reader::load_elf_properties()
927 {
928  // Note that we don't load the symbol table as it's loaded lazily,
929  // on demand.
930 
931  load_dt_soname_and_needed();
932  load_elf_architecture();
933 }
934 
935 /// Read the ELF information associated to the current ELF file and
936 /// construct an ABI representation from it.
937 ///
938 /// Note that this reader doesn't know how to interpret any debug
939 /// information so the resulting ABI corpus won't have any type
940 /// information. Rather, it will only have ELF symbol representation.
941 ///
942 /// To have type information, consider using readers that know how to
943 /// interpret the symbolic type information comprised in DWARF, CTF or
944 /// other symbolic debug information format, like the @ref or
945 /// abigail::dwarf_reader::reader, @ref abigail::ctf_reader::reader
946 /// readers.
947 ///
948 /// @return the resulting ABI corpus.
949 ir::corpus_sptr
950 reader::read_corpus(status& status)
951 {
952  status = STATUS_UNKNOWN;
953 
954  corpus::origin origin = corpus()->get_origin();
955  origin |= corpus::ELF_ORIGIN;
956  if (is_linux_kernel(elf_handle()))
957  origin |= corpus::LINUX_KERNEL_BINARY_ORIGIN;
958  corpus()->set_origin(origin);
959 
960  load_elf_properties(); // DT_SONAME, DT_NEEDED, architecture
961  corpus()->set_soname(dt_soname());
962  corpus()->set_needed(dt_needed());
963  corpus()->set_architecture_name(elf_architecture());
964 
965  // See if we could find symbol tables.
966  if (!symtab())
967  {
968  status |= STATUS_NO_SYMBOLS_FOUND;
969  // We found no ELF symbol, so we can't handle the binary. Note
970  // that we could have found a symbol table with no defined &
971  // exported ELF symbols in it. That case is handled as an empty
972  // corpus, which is different from this case.
973  return corpus_sptr();
974  }
975 
976  // Set symbols information to the corpus.
977  corpus()->set_symtab(symtab());
978 
979  // If we couldn't load debug info from the elf path, then say it.
980  if ((origin & abigail::ir::corpus::DWARF_ORIGIN)
981  && !has_dwarf_debug_info())
982  status |= STATUS_DEBUG_INFO_NOT_FOUND;
983  else if ((origin & abigail::ir::corpus::CTF_ORIGIN)
984  && !has_ctf_debug_info())
985  status |= STATUS_DEBUG_INFO_NOT_FOUND;
986 
987  status |= STATUS_OK;
988  return corpus();
989 }
990 
991 /// Get the SONAME property of a designated ELF file.
992 ///
993 /// @param path the path to the ELF file to consider.
994 ///
995 /// @param soname output parameter. This is set to the SONAME of the
996 /// file located at @p path, iff this function return true.
997 ///
998 /// @return true iff the SONAME property was found in the ELF file
999 /// located at @p path and set into the argument of the parameter @p
1000 /// soname.
1001 bool
1002 get_soname_of_elf_file(const string& path, string &soname)
1003 {return elf_helpers::get_soname_of_elf_file(path, soname);}
1004 
1005 /// Convert the type of ELF file into @ref elf_type.
1006 ///
1007 /// @param elf the elf handle to use for the query.
1008 ///
1009 /// @return the @ref elf_type for a given elf type.
1010 static elf::elf_type
1011 elf_file_type(Elf* elf)
1012 {
1013  GElf_Ehdr ehdr_mem;
1014  GElf_Ehdr *header = gelf_getehdr (elf, &ehdr_mem);
1015  vector<string> dt_debug_data;
1016 
1017  switch (header->e_type)
1018  {
1019  case ET_DYN:
1020  if (lookup_data_tag_from_dynamic_segment(elf, DT_DEBUG, dt_debug_data))
1021  return elf::ELF_TYPE_PI_EXEC;
1022  else
1023  return elf::ELF_TYPE_DSO;
1024  case ET_EXEC:
1025  return elf::ELF_TYPE_EXEC;
1026  case ET_REL:
1028  default:
1029  return elf::ELF_TYPE_UNKNOWN;
1030  }
1031 }
1032 
1033 /// Get the type of a given elf type.
1034 ///
1035 /// @param path the absolute path to the ELF file to analyzed.
1036 ///
1037 /// @param type the kind of the ELF file designated by @p path.
1038 ///
1039 /// @param out parameter. Is set to the type of ELF file of @p path.
1040 /// This parameter is set iff the function returns true.
1041 ///
1042 /// @return true iff the file could be opened and analyzed.
1043 bool
1044 get_type_of_elf_file(const string& path, elf::elf_type& type)
1045 {
1046  int fd = open(path.c_str(), O_RDONLY);
1047  if (fd == -1)
1048  return false;
1049 
1050  elf_version (EV_CURRENT);
1051  Elf *elf = elf_begin (fd, ELF_C_READ_MMAP, NULL);
1052  type = elf_file_type(elf);
1053  elf_end(elf);
1054  close(fd);
1055 
1056  return true;
1057 }
1058 
1059 }// end namespace elf
1060 } // end namespace abigail
bool lookup_data_tag_from_dynamic_segment(Elf *elf, Elf64_Sxword data_tag, vector< string > &dt_tag_data)
Get data tag information of an ELF file by looking up into its dynamic segment.
bool is_linux_kernel(Elf *elf_handle)
Test if the ELF binary denoted by a given ELF handle is a Linux Kernel binary (either vmlinux or a ke...
This contains a set of ELF utilities used by the dwarf reader.
shared_ptr< address_set_type > address_set_sptr
Convenience typedef for a shared pointer to an address_set_type.
shared_ptr< Dwfl > dwfl_sptr
A convenience typedef for a shared pointer to a Dwfl.
This file contains the declarations for the fe_iface a.k.a "Front End Interface".
std::shared_ptr< symtab > symtab_sptr
Convenience typedef for a shared pointer to a symtab.
Definition: abg-fwd.h:1540
#define ABG_ASSERT(cond)
This is a wrapper around the 'assert' glibc call. It allows for its argument to have side effects,...
Definition: abg-fwd.h:1589
This contains the private implementation of the suppression engine of libabigail.
This contains the declarations for the symtab reader.
This is the interface an ELF reader.
const vector< char ** > & debug_info_root_paths() const
Getter of the vector of directory paths to look into for split debug information files.
The base class of all libabigail front-ends: The Front End Interface.
Definition: abg-fe-iface.h:29
status
The status of the fe_iface::read_corpus call.
Definition: abg-fe-iface.h:38
void reset(const std::string &corpus_path, environment &e)
Re-initialize the current Front End.
Definition: abg-fe-iface.cc:84
const std::string & corpus_path() const
Getter of the path to the file which an ABI corpus is to be created for.
This is the abstraction of a set of translation units (themselves seen as bundles of unitary abi arte...
Definition: abg-corpus.h:25
origin
This abstracts where the corpus comes from. That is, either it has been read from the native xml form...
Definition: abg-corpus.h:45
void set_soname(const string &)
Setter for the soname property of the corpus.
Definition: abg-corpus.cc:995
origin get_origin() const
Getter for the origin of the corpus.
Definition: abg-corpus.cc:885
void set_origin(origin)
Setter for the origin of the corpus.
Definition: abg-corpus.cc:892
void set_needed(const vector< string > &)
Setter of the needed property of the corpus.
Definition: abg-corpus.cc:973
void set_architecture_name(const string &)
Setter for the architecture name of the corpus.
Definition: abg-corpus.cc:1017
void set_symtab(symtab_reader::symtab_sptr)
Setter for the symtab object.
Definition: abg-corpus.cc:1076
This is an abstraction of the set of resources necessary to manage several aspects of the internal re...
Definition: abg-ir.h:140
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 ...
bool get_soname_of_elf_file(const string &path, string &soname)
Get the SONAME property of a designated ELF file.
elf_type
The kind of ELF file we are looking at.
@ ELF_TYPE_RELOCATABLE
A relocatalbe binary.
@ ELF_TYPE_UNKNOWN
An unknown kind of binary.
@ ELF_TYPE_PI_EXEC
A Position Independant Executable binary.
@ ELF_TYPE_EXEC
A normal executable binary.
@ ELF_TYPE_DSO
A dynamic shared object, a.k.a shared library binary.
bool get_type_of_elf_file(const string &path, elf::elf_type &type)
Get the type of a given elf type.
shared_ptr< elf_symbol > elf_symbol_sptr
A convenience typedef for a shared pointer to elf_symbol.
Definition: abg-ir.h:863
std::vector< elf_symbol_sptr > elf_symbols
Convenience typedef for a vector of elf_symbol.
Definition: abg-ir.h:881
bool is_elf_symbol_suppressed(const fe_iface &fe, const elf_symbol_sptr &symbol)
Test if an ELF symbol is suppressed by at least one of the suppression specifications associated with...
bool find_file_under_dir(const string &root_dir, const string &file_path_to_look_for, string &result)
Find a given file under a root directory and return its absolute path.
string trim_leading_string(const string &from, const string &to_trim)
Remove a string of pattern in front of a given string.
Toplevel namespace for libabigail.
The generic options that control the behaviour of all Front-End interfaces.
Definition: abg-fe-iface.h:60