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"
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.
763 symtab_reader::symtab_sptr&
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 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...
The base class of all libabigail front-ends: The Front End Interface.
Definition: abg-fe-iface.h:28
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
This is the abstraction of a set of translation units (themselves seen as bundles of unitary abi arte...
Definition: abg-corpus.h:24
status
The status of the fe_iface::read_corpus call.
Definition: abg-fe-iface.h:37
string trim_leading_string(const string &from, const string &to_trim)
Remove a string of pattern in front of a given string.
void set_soname(const string &)
Setter for the soname property of the corpus.
Definition: abg-corpus.cc:1038
A normal executable binary.
This contains the declarations for the symtab reader.
An unknown kind of binary.
A Position Independant Executable binary.
Toplevel namespace for libabigail.
const vector< char ** > & debug_info_root_paths() const
Getter of the vector of directory paths to look into for split debug information files.
bool get_type_of_elf_file(const string &path, elf::elf_type &type)
Get the type of a given elf type.
origin
This abstracts where the corpus comes from. That is, either it has been read from the native xml form...
Definition: abg-corpus.h:50
void initialize()
This function needs to be called before any libabigail function.
This is an abstraction of the set of resources necessary to manage several aspects of the internal re...
Definition: abg-ir.h:139
This contains the private implementation of the suppression engine of libabigail. ...
shared_ptr< elf_symbol > elf_symbol_sptr
A convenience typedef for a shared pointer to elf_symbol.
Definition: abg-ir.h:886
#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
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.
This is the interface an ELF reader.
This file contains the declarations for the fe_iface a.k.a "Front End Interface". ...
bool get_soname_of_elf_file(const string &path, string &soname)
Get the SONAME property of a designated ELF file.
A dynamic shared object, a.k.a shared library binary.
const std::string & corpus_path() const
Getter of the path to the file which an ABI corpus is to be created for.
void set_origin(origin)
Setter for the origin of the corpus.
Definition: abg-corpus.cc:935
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 ...
This contains a set of ELF utilities used by the dwarf reader.
origin get_origin() const
Getter for the origin of the corpus.
Definition: abg-corpus.cc:928
void set_symtab(symtab_reader::symtab_sptr)
Setter for the symtab object.
Definition: abg-corpus.cc:1119
virtual void initialize(const std::string &corpus_path)
Re-initialize the current Front End.
Definition: abg-fe-iface.cc:82
elf_type
The kind of ELF file we are looking at.