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  memset(&offline_callbacks, 0, sizeof(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 /// Re-initialize the resources used by the current @ref elf::reader
531 /// 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::initialize(const std::string& elf_path,
542  const vector<char**>& debug_info_roots)
543 {
544  fe_iface::initialize(elf_path);
545  corpus_path(elf_path);
546  priv_->initialize(debug_info_roots);
547  priv_->crack_open_elf_file();
548  priv_->locate_dwarf_debug_info();
549  priv_->locate_ctf_debug_info();
550 }
551 
552 /// Re-initialize the resources used by the current @ref elf::reader
553 /// type.
554 ///
555 /// This lets the reader in a state where it's ready to read from
556 /// another ELF file.
557 ///
558 /// @param elf_path the new ELF path to read from.
559 void
560 reader::initialize(const std::string& elf_path)
561 {
562  vector<char**> v;
563  initialize(elf_path, v);
564 }
565 
566 /// Getter of the vector of directory paths to look into for split
567 /// debug information files.
568 ///
569 /// @return the vector of directory paths to look into for split
570 /// debug information files.
571 const vector<char**>&
572 reader::debug_info_root_paths() const
573 {return priv_->debug_info_root_paths;}
574 
575 /// Getter of the functions used by the DWARF Front End library of
576 /// elfutils to locate DWARF debug information.
577 ///
578 /// @return the functions used by the DWARF Front End library of
579 const Dwfl_Callbacks&
580 reader::dwfl_offline_callbacks() const
581 {return priv_->offline_callbacks;}
582 
583 /// Getter of the functions used by the DWARF Front End library of
584 /// elfutils to locate DWARF debug information.
585 ///
586 /// @return the functions used by the DWARF Front End library of
587 Dwfl_Callbacks&
588 reader::dwfl_offline_callbacks()
589 {return priv_->offline_callbacks;}
590 
591 /// Getter of the handle used to access ELF information from the
592 /// current ELF file.
593 ///
594 /// @return the handle used to access ELF information from the current
595 /// ELF file.
596 Elf*
597 reader::elf_handle() const
598 {return priv_->elf_handle;}
599 
600 /// Getter of the handle used to access DWARF information from the
601 /// current ELF file.
602 ///
603 /// @return the handle used to access DWARF information from the
604 /// current ELF file.
605 const Dwarf*
606 reader::dwarf_debug_info() const
607 {return priv_->dwarf_handle;}
608 
609 /// Test if the binary has DWARF debug info.
610 ///
611 /// @return true iff the binary has DWARF debug info.
612 bool
613 reader::has_dwarf_debug_info() const
614 {return ((priv_->dwarf_handle != nullptr)
615  || (priv_->alt_dwarf_handle != nullptr));}
616 
617 /// Test if the binary has CTF debug info.
618 ///
619 /// @return true iff the binary has CTF debug info.
620 bool
621 reader::has_ctf_debug_info() const
622 {return (priv_->ctf_section != nullptr);}
623 
624 /// Test if the binary has BTF debug info.
625 ///
626 /// @return true iff the binary has BTF debug info
627 bool
628 reader::has_btf_debug_info() const
629 {return (priv_->btf_section != nullptr);}
630 
631 /// Getter of the handle use to access DWARF information from the
632 /// alternate split DWARF information.
633 ///
634 /// In other words, this accesses the factorized DWARF information
635 /// that has been constructed by the DWZ tool to de-duplicate DWARF
636 /// information on disk.
637 ///
638 /// @return the handle use to access DWARF information from the
639 /// alternate split DWARF information.
640 const Dwarf*
641 reader::alternate_dwarf_debug_info() const
642 {return priv_->alt_dwarf_handle;}
643 
644 
645 /// Getter of the path to the alternate split DWARF information file,
646 /// on disk. In othe words, this returns the path to the factorized
647 /// DWARF information used by the current ELF file, created by the
648 /// 'DWZ' tool.
649 ///
650 /// @return the path to the alternate split DWARF information file,
651 /// on disk.
652 const string&
653 reader::alternate_dwarf_debug_info_path() const
654 {return priv_->alt_dwarf_path;}
655 
656 /// Check if the underlying elf file refers to an alternate debug info
657 /// file associated to it.
658 ///
659 /// Note that "alternate debug info sections" is a GNU extension as
660 /// of DWARF4 and is described at
661 /// http://www.dwarfstd.org/ShowIssue.php?issue=120604.1.
662 ///
663 /// @param alt_di the path to the alternate debug info file. This is
664 /// set iff the function returns true.
665 ///
666 /// @return true if the ELF file refers to an alternate debug info
667 /// file.
668 bool
669 reader::refers_to_alt_debug_info(string& alt_di_path) const
670 {
671  if (!alternate_dwarf_debug_info_path().empty())
672  {
673  alt_di_path = alternate_dwarf_debug_info_path();
674  return true;
675  }
676  return false;
677 }
678 
679 /// Find and return a pointer to the ELF symbol table
680 /// section.
681 ///
682 /// @return a pointer to the ELF symbol table section.
683 const Elf_Scn*
684 reader::find_symbol_table_section() const
685 {
686  if (!priv_->symtab_section)
687  priv_->symtab_section =
688  elf_helpers::find_symbol_table_section(elf_handle());
689  return priv_->symtab_section;
690 }
691 
692 /// Clear the pointer to the ELF symbol table section.
693 void
694 reader::reset_symbol_table_section()
695 {priv_->symtab_section = nullptr;}
696 
697 /// Find and return a pointer to the the CTF section.
698 ///
699 /// @return a pointer to the the CTF section.
700 const Elf_Scn*
701 reader::find_ctf_section() const
702 {
703  if (priv_->ctf_section == nullptr)
704  priv_->locate_ctf_debug_info();
705 
706  if (priv_->ctf_section)
707  return priv_->ctf_section;
708 
709  return priv_->alt_ctf_section;
710 }
711 
712 /// Find and return a pointer to the alternate CTF section of the
713 /// current ELF file.
714 ///
715 /// @return a pointer to the alternate CTF section of the current ELF
716 /// file.
717 const Elf_Scn*
718 reader::find_alternate_ctf_section() const
719 {
720  if (priv_->alt_ctf_section == nullptr)
721  priv_->locate_alt_ctf_debug_info();
722 
723  return priv_->alt_ctf_section;
724 }
725 
726 /// Find and return a pointer to the BTF section of the current ELF
727 /// file.
728 ///
729 /// @return a pointer to the BTF section of the current ELF file.
730 const Elf_Scn*
731 reader::find_btf_section() const
732 {
733  if (priv_->btf_section == nullptr)
734  priv_->btf_section =
735  elf_helpers::find_section(priv_->elf_handle,
736  ".BTF", SHT_PROGBITS);
737  return priv_->btf_section;
738 }
739 
740 /// Get the value of the DT_NEEDED property of the current ELF file.
741 ///
742 /// @return the value of the DT_NEEDED property.
743 const vector<string>&
744 reader::dt_needed()const
745 {return priv_->dt_needed;}
746 
747 
748 /// Get the value of the 'ARCHITECTURE' property of the current ELF file.
749 ///
750 /// @return the value of the 'ARCHITECTURE' property of the current
751 /// ELF file.
752 const string&
753 reader::elf_architecture() const
754 {return priv_->elf_architecture;}
755 
756 /// Getter of an abstract representation of the symbol table of the
757 /// underlying ELF file.
758 ///
759 /// Note that the symbol table is loaded lazily, upon the first
760 /// invocation of this member function.
761 ///
762 /// @returnt the symbol table.
764 reader::symtab() const
765 {
766  ABG_ASSERT(elf_handle());
767 
768  if (!priv_->symt)
769  priv_->symt = symtab_reader::symtab::load
770  (elf_handle(), options().env,
771  [&](const elf_symbol_sptr& symbol)
772  {return suppr::is_elf_symbol_suppressed(*this, symbol);});
773 
774  if (!priv_->symt)
775  std::cerr << "Symbol table of '" << corpus_path()
776  << "' could not be loaded\n";
777  return priv_->symt;
778 }
779 
780 /// Test if a given function symbol has been exported.
781 ///
782 /// @param symbol_address the address of the symbol we are looking
783 /// for. Note that this address must be a relative offset from the
784 /// beginning of the .text section, just like the kind of addresses
785 /// that are present in the .symtab section.
786 ///
787 /// @return the elf symbol if found, or nil otherwise.
789 reader::function_symbol_is_exported(GElf_Addr symbol_address) const
790 {
791 
792  elf_symbol_sptr symbol =
793  symtab()->function_symbol_is_exported(symbol_address);
794  if (!symbol)
795  return symbol;
796 
797  address_set_sptr set;
798  bool looking_at_linux_kernel_binary =
799  load_in_linux_kernel_mode() && elf_helpers::is_linux_kernel(elf_handle());
800 
801  if (looking_at_linux_kernel_binary)
802  {
803  if (symbol->is_in_ksymtab())
804  return symbol;
805  return elf_symbol_sptr();
806  }
807 
808  return symbol;
809 }
810 
811 /// Test if a given variable symbol has been exported.
812 ///
813 /// @param symbol_address the address of the symbol we are looking
814 /// for. Note that this address must be a relative offset from the
815 /// beginning of the .text section, just like the kind of addresses
816 /// that are present in the .symtab section.
817 ///
818 /// @return the elf symbol if found, or nil otherwise.
820 reader::variable_symbol_is_exported(GElf_Addr symbol_address) const
821 {
822  elf_symbol_sptr symbol =
823  symtab()->variable_symbol_is_exported(symbol_address);
824  if (!symbol)
825  return symbol;
826 
827  address_set_sptr set;
828  bool looking_at_linux_kernel_binary =
829  load_in_linux_kernel_mode() && elf_helpers::is_linux_kernel(elf_handle());
830 
831  if (looking_at_linux_kernel_binary)
832  {
833  if (symbol->is_in_ksymtab())
834  return symbol;
835  return elf_symbol_sptr();
836  }
837 
838  return symbol;
839 }
840 
841 /// Test if a given function symbol has been exported.
842 ///
843 /// @param name the name of the symbol we are looking for.
844 ///
845 /// @return the elf symbol if found, or nil otherwise.
847 reader::function_symbol_is_exported(const string& name) const
848 {
849  const elf_symbol_sptr s = symtab()->function_symbol_is_exported(name);
850  if (s && s->is_function() && s->is_public())
851  {
852  bool looking_at_linux_kernel_binary =
853  (load_in_linux_kernel_mode()
854  && elf_helpers::is_linux_kernel(elf_handle()));
855 
856  if (looking_at_linux_kernel_binary)
857  {
858  if (s->is_in_ksymtab())
859  return s;
860  }
861  else
862  return s;
863  }
864  return elf_symbol_sptr();
865 }
866 
867 /// Test if a given variable symbol has been exported.
868 ///
869 /// @param name the name of the symbol we are looking
870 /// for.
871 ///
872 /// @return the elf symbol if found, or nil otherwise.
874 reader::variable_symbol_is_exported(const string& name) const
875 {
876  const elf_symbol_sptr s = symtab()->variable_symbol_is_exported(name);
877  if (s->is_variable() && s->is_public())
878  {
879  bool looking_at_linux_kernel_binary =
880  (load_in_linux_kernel_mode()
881  && elf_helpers::is_linux_kernel(elf_handle()));
882 
883  if (looking_at_linux_kernel_binary)
884  {
885  if (s->is_in_ksymtab())
886  return s;
887  }
888  else
889  return s;
890  }
891  return elf_symbol_sptr();
892 }
893 
894 /// Test if a name is the name of an undefined function symbol.
895 ///
896 /// @param name the symbol name to consider.
897 ///
898 /// @return the undefined function symbol or nil if none was found.
900 reader::function_symbol_is_undefined(const string& name) const
901 {return symtab()->function_symbol_is_undefined(name);}
902 
903 /// Test if a name is the name of an undefined variable symbol.
904 ///
905 /// @param name the symbol name to consider.
906 ///
907 /// @return the undefined variable symbol or nil if none was found.
909 reader::variable_symbol_is_undefined(const string& name) const
910 {return symtab()->variable_symbol_is_undefined(name);}
911 
912 /// Load the DT_NEEDED and DT_SONAME elf TAGS.
913 void
914 reader::load_dt_soname_and_needed()
915 {
916  elf_helpers::lookup_data_tag_from_dynamic_segment(elf_handle(),
917  DT_NEEDED,
918  priv_->dt_needed);
919 
920  vector<string> dt_tag_data;
921  elf_helpers::lookup_data_tag_from_dynamic_segment(elf_handle(),
922  DT_SONAME,
923  dt_tag_data);
924  if (!dt_tag_data.empty())
925  dt_soname(dt_tag_data[0]);
926 }
927 
928 /// Read the string representing the architecture of the current ELF
929 /// file.
930 void
931 reader::load_elf_architecture()
932 {
933  if (!elf_handle())
934  return;
935 
936  GElf_Ehdr eh_mem;
937  GElf_Ehdr* elf_header = gelf_getehdr(elf_handle(), &eh_mem);
938 
939  priv_->elf_architecture =
940  elf_helpers::e_machine_to_string(elf_header->e_machine);
941 }
942 
943 /// Load various ELF data.
944 ///
945 /// This function loads ELF data that are not symbol maps or debug
946 /// info. That is, things like various tags, elf architecture and
947 /// so on.
948 void
949 reader::load_elf_properties()
950 {
951  // Note that we don't load the symbol table as it's loaded lazily,
952  // on demand.
953 
954  load_dt_soname_and_needed();
955  load_elf_architecture();
956 }
957 
958 /// Read the ELF information associated to the current ELF file and
959 /// construct an ABI representation from it.
960 ///
961 /// Note that this reader doesn't know how to interpret any debug
962 /// information so the resulting ABI corpus won't have any type
963 /// information. Rather, it will only have ELF symbol representation.
964 ///
965 /// To have type information, consider using readers that know how to
966 /// interpret the symbolic type information comprised in DWARF, CTF or
967 /// other symbolic debug information format, like the @ref or
968 /// abigail::dwarf_reader::reader, @ref abigail::ctf_reader::reader
969 /// readers.
970 ///
971 /// @return the resulting ABI corpus.
972 ir::corpus_sptr
973 reader::read_corpus(status& status)
974 {
975  status = STATUS_UNKNOWN;
976 
977  corpus::origin origin = corpus()->get_origin();
978  origin |= corpus::ELF_ORIGIN;
979  if (is_linux_kernel(elf_handle()))
980  origin |= corpus::LINUX_KERNEL_BINARY_ORIGIN;
981  corpus()->set_origin(origin);
982 
983  load_elf_properties(); // DT_SONAME, DT_NEEDED, architecture
984  corpus()->set_soname(dt_soname());
985  corpus()->set_needed(dt_needed());
986  corpus()->set_architecture_name(elf_architecture());
987 
988  // See if we could find symbol tables.
989  if (!symtab())
990  {
991  status |= STATUS_NO_SYMBOLS_FOUND | STATUS_OK;
992  // We found no ELF symbol, so we can't handle the binary. Note
993  // that we could have found a symbol table with no defined &
994  // exported ELF symbols in it. Both cases are handled as an
995  // empty corpus.
996  return corpus();
997  }
998 
999  // Set symbols information to the corpus.
1000  corpus()->set_symtab(symtab());
1001 
1002  // If we couldn't load debug info from the elf path, then say it.
1003  if ((origin & abigail::ir::corpus::DWARF_ORIGIN)
1004  && !has_dwarf_debug_info())
1005  status |= STATUS_DEBUG_INFO_NOT_FOUND;
1006  else if ((origin & abigail::ir::corpus::CTF_ORIGIN)
1007  && !has_ctf_debug_info())
1008  status |= STATUS_DEBUG_INFO_NOT_FOUND;
1009 
1010  status |= STATUS_OK;
1011  return corpus();
1012 }
1013 
1014 /// Get the SONAME property of a designated ELF file.
1015 ///
1016 /// @param path the path to the ELF file to consider.
1017 ///
1018 /// @param soname output parameter. This is set to the SONAME of the
1019 /// file located at @p path, iff this function return true.
1020 ///
1021 /// @return true iff the SONAME property was found in the ELF file
1022 /// located at @p path and set into the argument of the parameter @p
1023 /// soname.
1024 bool
1025 get_soname_of_elf_file(const string& path, string &soname)
1026 {return elf_helpers::get_soname_of_elf_file(path, soname);}
1027 
1028 /// Convert the type of ELF file into @ref elf_type.
1029 ///
1030 /// @param elf the elf handle to use for the query.
1031 ///
1032 /// @return the @ref elf_type for a given elf type.
1033 static elf::elf_type
1034 elf_file_type(Elf* elf)
1035 {
1036  GElf_Ehdr ehdr_mem;
1037  GElf_Ehdr *header = gelf_getehdr (elf, &ehdr_mem);
1038  vector<string> dt_debug_data;
1039 
1040  switch (header->e_type)
1041  {
1042  case ET_DYN:
1043  if (lookup_data_tag_from_dynamic_segment(elf, DT_DEBUG, dt_debug_data))
1044  return elf::ELF_TYPE_PI_EXEC;
1045  else
1046  return elf::ELF_TYPE_DSO;
1047  case ET_EXEC:
1048  return elf::ELF_TYPE_EXEC;
1049  case ET_REL:
1051  default:
1052  return elf::ELF_TYPE_UNKNOWN;
1053  }
1054 }
1055 
1056 /// Get the type of a given elf type.
1057 ///
1058 /// @param path the absolute path to the ELF file to analyzed.
1059 ///
1060 /// @param type the kind of the ELF file designated by @p path.
1061 ///
1062 /// @param out parameter. Is set to the type of ELF file of @p path.
1063 /// This parameter is set iff the function returns true.
1064 ///
1065 /// @return true iff the file could be opened and analyzed.
1066 bool
1067 get_type_of_elf_file(const string& path, elf::elf_type& type)
1068 {
1069  int fd = open(path.c_str(), O_RDONLY);
1070  if (fd == -1)
1071  return false;
1072 
1073  elf_version (EV_CURRENT);
1074  Elf *elf = elf_begin (fd, ELF_C_READ_MMAP, NULL);
1075  type = elf_file_type(elf);
1076  elf_end(elf);
1077  close(fd);
1078 
1079  return true;
1080 }
1081 
1082 }// end namespace elf
1083 } // 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:1665
#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:1714
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
virtual void initialize(const std::string &corpus_path)
Re-initialize the current Front End.
Definition: abg-fe-iface.cc:82
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:51
void set_soname(const string &)
Setter for the soname property of the corpus.
Definition: abg-corpus.cc:1038
origin get_origin() const
Getter for the origin of the corpus.
Definition: abg-corpus.cc:928
void set_origin(origin)
Setter for the origin of the corpus.
Definition: abg-corpus.cc:935
void set_needed(const vector< string > &)
Setter of the needed property of the corpus.
Definition: abg-corpus.cc:1016
void set_architecture_name(const string &)
Setter for the architecture name of the corpus.
Definition: abg-corpus.cc:1060
void set_symtab(symtab_reader::symtab_sptr)
Setter for the symtab object.
Definition: abg-corpus.cc:1119
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:886
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.
void initialize()
This function needs to be called before any libabigail function.
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.