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-2025 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 /// Private data of the @ref elf::reader type.
104 struct reader::priv
105 {
106  reader& rdr;
107  Elf* elf_handle = nullptr;
108  Elf_Scn* symtab_section = nullptr;
109  string elf_architecture;
110  vector<string> dt_needed;
111  // An abstraction of the symbol table. This is loaded lazily, on
112  // demand.
113  mutable symtab_reader::symtab_sptr symt;
114  // Where split debug info is to be searched for on disk.
115  vector<string> debug_info_root_paths;
116  // The formatted string version of debug_info_root_paths. The
117  // format is according to what elfutils expects. For the details of
118  // what elfutils expects, please read the comments of the function
119  // dwfl_build_id_find_elf in /usr/include/elfutils/libdwfl.h.
120  string formated_di_root_paths;
121  // A pointer to where the string held by formated_di_root_paths is.
122  // This is fed to elfutils.
123  char* raw_formated_di_root_paths = nullptr;
124  // Some very useful callback functions that elfutils needs to
125  // perform various tasks.
126  Dwfl_Callbacks offline_callbacks;
127  // A pointer to the DWARF Front End Library handle of elfutils.
128  // This is useful to perform all kind of things at a higher level.
129  dwfl_sptr dwfl_handle;
130  // The address range of the offline elf file we are looking at.
131  Dwfl_Module* elf_module = nullptr;
132  // A pointer to the DWARF debug info, if found by locate_dwarf_debug_info.
133  Dwarf* dwarf_handle = nullptr;
134  // A pointer to the ALT DWARF debug info, which is the debug info
135  // that is constructed by the DWZ tool. It's made of all the type
136  // information that was redundant in the DWARF. DWZ put it there
137  // and make the DWARF reference it in here.
138  Dwarf* alt_dwarf_handle = nullptr;
139  string alt_dwarf_path;
140  int alt_dwarf_fd = -1;
141  Elf_Scn* ctf_section = nullptr;
142  int alt_ctf_fd = -1;
143  Elf* alt_ctf_handle = nullptr;
144  Elf_Scn* alt_ctf_section = nullptr;
145  Elf_Scn* btf_section = nullptr;
146 
147  priv(reader& reeder, const std::string& elf_path,
148  const vector<string>& debug_info_roots)
149  : rdr(reeder)
150  {
151  rdr.corpus_path(elf_path);
152  initialize(debug_info_roots);
153  }
154 
155  ~priv()
156  {
157  clear_alt_dwarf_debug_info_data();
158  clear_alt_ctf_debug_info_data();
159  }
160 
161  /// Reset the private data of @elf elf::reader.
162  ///
163  /// @param debug_info_roots the vector of new directories where to
164  /// look for split debug info file.
165  void
166  initialize(const vector<string>& debug_info_roots)
167  {
168  clear_alt_dwarf_debug_info_data();
169  clear_alt_ctf_debug_info_data();
170 
171  elf_handle = nullptr;
172  symtab_section = nullptr;
173  elf_architecture.clear();
174  dt_needed.clear();
175  symt.reset();
176  debug_info_root_paths = debug_info_roots;
177  formated_di_root_paths.clear();
178  raw_formated_di_root_paths = nullptr;
179  memset(&offline_callbacks, 0, sizeof(offline_callbacks));
180  dwfl_handle.reset();
181  elf_module = nullptr;
182  dwarf_handle = nullptr;
183  alt_dwarf_handle = nullptr;
184  alt_dwarf_path.clear();
185  alt_dwarf_fd = -1;
186  ctf_section = nullptr;
187  alt_ctf_section = nullptr;
188  alt_ctf_handle = nullptr;
189  alt_ctf_fd = -1;
190  }
191 
192  /// Initialize the debug info root path. The format of this path is
193  /// described in /usr/include/elfutils/libdwfl.h in the comment for
194  /// the function dwfl_build_id_find_elf.
195  ///
196  /// The string must start with '-' to disable CRC32 checksum
197  /// validation. Directories must be separated by the ':' character.
198  /// The search order depends on if each path is absolute or relative
199  /// as described by that comment.
200  ///
201  /// In any case, let's format the debuginfo search path here for
202  /// elfutils consumption.
203  void
204  initialize_debug_info_root_paths()
205  {
206  vector<string> root_paths = debug_info_root_paths;
207 
208  for (auto path : debug_info_root_paths)
209  if (tools_utils::string_begins_with(path, "/"))
210  {
211  // For absolute root directories, let's add all the
212  // sub-directories of these directories that contain a
213  // (debug info) file. This can be helpful to help elfutils
214  // find alternate debuginfo files when the altdebuginfolink
215  // is itself an absolute file path that is contained under
216  // the root directory. This what we see in PR30329 and its
217  // associated regression test in test-abidiff-exit.cc
218  vector<string> additional_subdirs;
219  tools_utils::get_file_path_dirs_under_dir(path, additional_subdirs);
220  for (auto& subdir : additional_subdirs)
221  root_paths.push_back(subdir);
222  }
223 
224  for (auto path : root_paths)
225  {
226  if (formated_di_root_paths.empty())
227  formated_di_root_paths = "-";
228  if (!path.empty())
229  formated_di_root_paths += path + ":";
230  }
231  raw_formated_di_root_paths =
232  const_cast<char*>(formated_di_root_paths.c_str());
233  }
234 
235  /// Setup the necessary plumbing to open the ELF file and find all
236  /// the associated split debug info files.
237  ///
238  /// This function also setup the various handles on the opened ELF
239  /// file and whatnot.
240  void
241  crack_open_elf_file()
242  {
243  // Initialize the callback functions used by elfutils.
244  initialize_debug_info_root_paths();
245  elf_helpers::initialize_dwfl_callbacks(offline_callbacks,
246  formated_di_root_paths.empty()
247  ? nullptr
248  : &raw_formated_di_root_paths);
249 
250  // Create a handle to the DWARF Front End Library that we'll need.
251  dwfl_handle = elf_helpers::create_new_dwfl_handle(offline_callbacks);
252 
253  const string& elf_path = rdr.corpus_path();
254  // Get the set of addresses that make up the ELF file we are
255  // looking at.
256  elf_module =
257  dwfl_report_offline(dwfl_handle.get(),
258  basename(const_cast<char*>(elf_path.c_str())),
259  elf_path.c_str(), -1);
260  dwfl_report_end(dwfl_handle.get(), 0, 0);
261  ABG_ASSERT(elf_module);
262 
263  // Finally, get and handle at the representation of the ELF file
264  // we've just cracked open.
265  GElf_Addr bias = 0;
266  elf_handle = dwfl_module_getelf(elf_module, &bias);
267  ABG_ASSERT(elf_handle);
268  }
269 
270  /// Clear the resources related to the alternate DWARF data.
271  void
272  clear_alt_dwarf_debug_info_data()
273  {
274  if (alt_dwarf_fd != -1)
275  {
276  if (alt_dwarf_handle)
277  {
278  dwarf_end(alt_dwarf_handle);
279  alt_dwarf_handle = nullptr;
280  }
281  close(alt_dwarf_fd);
282  alt_dwarf_fd = -1;
283  }
284  alt_dwarf_path.clear();
285  }
286 
287  /// Locate the DWARF debug info in the ELF file.
288  ///
289  /// This also knows how to locate split debug info.
290  void
291  locate_dwarf_debug_info()
292  {
293  ABG_ASSERT(dwfl_handle);
294 
295  if (dwarf_handle)
296  return;
297 
298  Dwarf_Addr bias = 0;
299  dwarf_handle = dwfl_module_getdwarf(elf_module, &bias);
300  alt_dwarf_handle = dwarf_getalt(dwarf_handle);
301  find_alt_dwarf_debug_info_link(elf_module, alt_dwarf_path);
302  }
303 
304  /// Clear the resources related to the alternate CTF data.
305  void
306  clear_alt_ctf_debug_info_data()
307  {
308  if (alt_ctf_fd != -1)
309  {
310  close(alt_ctf_fd);
311  alt_ctf_fd = -1;
312  }
313  if (alt_ctf_handle)
314  {
315  elf_end(alt_ctf_handle);
316  alt_ctf_handle = nullptr;
317  }
318  }
319 
320  /// Locate the CTF "alternate" debug information associated with the
321  /// current ELF file ( and split out somewhere else).
322  ///
323  /// This is a sub-routine of @ref locate_ctf_debug_info().
324  void
325  locate_alt_ctf_debug_info()
326  {
327  if (alt_ctf_section)
328  return;
329 
330  Elf_Scn *section =
331  elf_helpers::find_section(elf_handle,
332  ".gnu_debuglink",
333  SHT_PROGBITS);
334 
335  std::string name;
336  Elf_Data *data;
337  if (section
338  && (data = elf_getdata(section, nullptr))
339  && data->d_size != 0)
340  name = (char *) data->d_buf;
341 
342  if (!name.empty())
343  for (const auto& path : rdr.debug_info_root_paths())
344  {
345  std::string file_path;
346  if (!tools_utils::find_file_under_dir(path, name, file_path))
347  continue;
348 
349  int fd;
350  if ((fd = open(file_path.c_str(), O_RDONLY)) == -1)
351  continue;
352 
353  Elf* handle;
354  if ((handle = elf_begin(fd, ELF_C_READ, nullptr)) == nullptr)
355  {
356  close(fd);
357  continue;
358  }
359 
360  // unlikely .ctf was designed to be present in stripped file
361  alt_ctf_section = elf_helpers::find_section(handle,
362  ".ctf",
363  SHT_PROGBITS);
364 
365  if (alt_ctf_section)
366  {
367  alt_ctf_fd = fd;
368  alt_ctf_handle = handle;
369  break;
370  }
371  close(fd);
372  elf_end(handle);
373  }
374  }
375 
376  /// Locate the CTF debug information associated with the current ELF
377  /// file. It also locates the CTF debug information that is split
378  /// out in a separate file.
379  void
380  locate_ctf_debug_info()
381  {
382  ABG_ASSERT(elf_handle);
383 
384  ctf_section = elf_helpers::find_section_by_name(elf_handle, ".ctf");
385  if (ctf_section == nullptr)
386  {
387  locate_alt_ctf_debug_info();
388  ctf_section = alt_ctf_section;
389  }
390  }
391 }; //end reader::priv
392 
393 /// The constructor of the @ref elf::reader type.
394 ///
395 /// @param elf_path the path to the ELF file to read from.
396 ///
397 /// @param debug_info_root a vector of directory paths to look into
398 /// for split debug information files.
399 ///
400 /// @param env the environment which the reader operates in.
401 reader::reader(const string& elf_path,
402  const vector<string>& debug_info_roots,
403  ir::environment& env)
404  : fe_iface(elf_path, env),
405  priv_(new priv(*this, elf_path, debug_info_roots))
406 {
407  priv_->crack_open_elf_file();
408  priv_->locate_dwarf_debug_info();
409  priv_->locate_ctf_debug_info();
410 }
411 
412 /// The destructor of the @ref elf::reader type.
413 reader::~reader()
414 {delete priv_;}
415 
416 /// Re-initialize the resources used by the current @ref elf::reader
417 /// type.
418 ///
419 /// This lets the reader in a state where it's ready to read from
420 /// another ELF file.
421 ///
422 /// @param elf_path the new ELF path to read from.
423 ///
424 /// @param debug_info_roots a vector of directory paths to look into
425 /// for split debug information files.
426 void
427 reader::initialize(const std::string& elf_path,
428  const vector<string>& debug_info_roots)
429 {
430  fe_iface::initialize(elf_path);
431  corpus_path(elf_path);
432  priv_->initialize(debug_info_roots);
433  priv_->crack_open_elf_file();
434  priv_->locate_dwarf_debug_info();
435  priv_->locate_ctf_debug_info();
436 }
437 
438 /// Re-initialize the resources used by the current @ref elf::reader
439 /// type.
440 ///
441 /// This lets the reader in a state where it's ready to read from
442 /// another ELF file.
443 ///
444 /// @param elf_path the new ELF path to read from.
445 void
446 reader::initialize(const std::string& elf_path)
447 {
448  vector<string> v;
449  initialize(elf_path, v);
450 }
451 
452 /// Getter of the vector of directory paths to look into for split
453 /// debug information files.
454 ///
455 /// @return the vector of directory paths to look into for split
456 /// debug information files.
457 const vector<string>&
458 reader::debug_info_root_paths() const
459 {return priv_->debug_info_root_paths;}
460 
461 /// Getter of the functions used by the DWARF Front End library of
462 /// elfutils to locate DWARF debug information.
463 ///
464 /// @return the functions used by the DWARF Front End library of
465 const Dwfl_Callbacks&
466 reader::dwfl_offline_callbacks() const
467 {return priv_->offline_callbacks;}
468 
469 /// Getter of the functions used by the DWARF Front End library of
470 /// elfutils to locate DWARF debug information.
471 ///
472 /// @return the functions used by the DWARF Front End library of
473 Dwfl_Callbacks&
474 reader::dwfl_offline_callbacks()
475 {return priv_->offline_callbacks;}
476 
477 /// Getter of the handle used to access ELF information from the
478 /// current ELF file.
479 ///
480 /// @return the handle used to access ELF information from the current
481 /// ELF file.
482 Elf*
483 reader::elf_handle() const
484 {return priv_->elf_handle;}
485 
486 /// Getter of the handle used to access DWARF information from the
487 /// current ELF file.
488 ///
489 /// @return the handle used to access DWARF information from the
490 /// current ELF file.
491 const Dwarf*
492 reader::dwarf_debug_info() const
493 {return priv_->dwarf_handle;}
494 
495 /// Test if the binary has DWARF debug info.
496 ///
497 /// @return true iff the binary has DWARF debug info.
498 bool
499 reader::has_dwarf_debug_info() const
500 {return ((priv_->dwarf_handle != nullptr)
501  || (priv_->alt_dwarf_handle != nullptr));}
502 
503 /// Test if the binary has CTF debug info.
504 ///
505 /// @return true iff the binary has CTF debug info.
506 bool
507 reader::has_ctf_debug_info() const
508 {return (priv_->ctf_section != nullptr);}
509 
510 /// Test if the binary has BTF debug info.
511 ///
512 /// @return true iff the binary has BTF debug info
513 bool
514 reader::has_btf_debug_info() const
515 {return (priv_->btf_section != nullptr);}
516 
517 /// Getter of the handle use to access DWARF information from the
518 /// alternate split DWARF information.
519 ///
520 /// In other words, this accesses the factorized DWARF information
521 /// that has been constructed by the DWZ tool to de-duplicate DWARF
522 /// information on disk.
523 ///
524 /// @return the handle use to access DWARF information from the
525 /// alternate split DWARF information.
526 const Dwarf*
527 reader::alternate_dwarf_debug_info() const
528 {return priv_->alt_dwarf_handle;}
529 
530 
531 /// Getter of the path to the alternate split DWARF information file,
532 /// on disk. In othe words, this returns the path to the factorized
533 /// DWARF information used by the current ELF file, created by the
534 /// 'DWZ' tool.
535 ///
536 /// @return the path to the alternate split DWARF information file,
537 /// on disk.
538 const string&
539 reader::alternate_dwarf_debug_info_path() const
540 {return priv_->alt_dwarf_path;}
541 
542 /// Check if the underlying elf file refers to an alternate debug info
543 /// file associated to it.
544 ///
545 /// Note that "alternate debug info sections" is a GNU extension as
546 /// of DWARF4 and is described at
547 /// http://www.dwarfstd.org/ShowIssue.php?issue=120604.1.
548 ///
549 /// @param alt_di the path to the alternate debug info file. This is
550 /// set iff the function returns true.
551 ///
552 /// @return true if the ELF file refers to an alternate debug info
553 /// file.
554 bool
555 reader::refers_to_alt_debug_info(string& alt_di_path) const
556 {
557  if (!alternate_dwarf_debug_info_path().empty())
558  {
559  alt_di_path = alternate_dwarf_debug_info_path();
560  return true;
561  }
562  return false;
563 }
564 
565 /// Find and return a pointer to the ELF symbol table
566 /// section.
567 ///
568 /// @return a pointer to the ELF symbol table section.
569 const Elf_Scn*
570 reader::find_symbol_table_section() const
571 {
572  if (!priv_->symtab_section)
573  priv_->symtab_section =
574  elf_helpers::find_symbol_table_section(elf_handle());
575  return priv_->symtab_section;
576 }
577 
578 /// Clear the pointer to the ELF symbol table section.
579 void
580 reader::reset_symbol_table_section()
581 {priv_->symtab_section = nullptr;}
582 
583 /// Find and return a pointer to the the CTF section.
584 ///
585 /// @return a pointer to the the CTF section.
586 const Elf_Scn*
587 reader::find_ctf_section() const
588 {
589  if (priv_->ctf_section == nullptr)
590  priv_->locate_ctf_debug_info();
591 
592  if (priv_->ctf_section)
593  return priv_->ctf_section;
594 
595  return priv_->alt_ctf_section;
596 }
597 
598 /// Find and return a pointer to the alternate CTF section of the
599 /// current ELF file.
600 ///
601 /// @return a pointer to the alternate CTF section of the current ELF
602 /// file.
603 const Elf_Scn*
604 reader::find_alternate_ctf_section() const
605 {
606  if (priv_->alt_ctf_section == nullptr)
607  priv_->locate_alt_ctf_debug_info();
608 
609  return priv_->alt_ctf_section;
610 }
611 
612 /// Find and return a pointer to the BTF section of the current ELF
613 /// file.
614 ///
615 /// @return a pointer to the BTF section of the current ELF file.
616 const Elf_Scn*
617 reader::find_btf_section() const
618 {
619  if (priv_->btf_section == nullptr)
620  priv_->btf_section =
621  elf_helpers::find_section(priv_->elf_handle,
622  ".BTF", SHT_PROGBITS);
623  return priv_->btf_section;
624 }
625 
626 /// Get the value of the DT_NEEDED property of the current ELF file.
627 ///
628 /// @return the value of the DT_NEEDED property.
629 const vector<string>&
630 reader::dt_needed()const
631 {return priv_->dt_needed;}
632 
633 
634 /// Get the value of the 'ARCHITECTURE' property of the current ELF file.
635 ///
636 /// @return the value of the 'ARCHITECTURE' property of the current
637 /// ELF file.
638 const string&
639 reader::elf_architecture() const
640 {return priv_->elf_architecture;}
641 
642 /// Getter of an abstract representation of the symbol table of the
643 /// underlying ELF file.
644 ///
645 /// Note that the symbol table is loaded lazily, upon the first
646 /// invocation of this member function.
647 ///
648 /// @returnt the symbol table.
649 symtab_reader::symtab_sptr&
650 reader::symtab() const
651 {
652  ABG_ASSERT(elf_handle());
653 
654  if (!priv_->symt)
655  priv_->symt = symtab_reader::symtab::load
656  (elf_handle(), options().env,
657  [&](const elf_symbol_sptr& symbol)
658  {
659  // This closure determines if a given symbol is suppressed by
660  // taking into accont symbol aliases. Basically, a symbol is
661  // suppressed if all its aliases are suppressed.
662  if (!symbol)
663  return false;
664  if (!suppr::is_elf_symbol_suppressed(*this, symbol))
665  return false;
666  for (elf_symbol_sptr a = symbol->get_next_alias();
667  a && a.get() != symbol->get_main_symbol().get();
668  a = a->get_next_alias())
669  {
670  if (!suppr::is_elf_symbol_suppressed(*this, a))
671  return false;
672  }
673  return true;
674  }
675  );
676 
677  if (!priv_->symt)
678  std::cerr << "Symbol table of '" << corpus_path()
679  << "' could not be loaded\n";
680  return priv_->symt;
681 }
682 
683 /// Test if a given function symbol has been exported.
684 ///
685 /// @param symbol_address the address of the symbol we are looking
686 /// for. Note that this address must be a relative offset from the
687 /// beginning of the .text section, just like the kind of addresses
688 /// that are present in the .symtab section.
689 ///
690 /// @return the elf symbol if found, or nil otherwise.
692 reader::function_symbol_is_exported(GElf_Addr symbol_address) const
693 {
694 
695  elf_symbol_sptr symbol =
696  symtab()->function_symbol_is_exported(symbol_address);
697  if (!symbol)
698  return symbol;
699 
700  address_set_sptr set;
701  bool looking_at_linux_kernel_binary =
702  load_in_linux_kernel_mode() && elf_helpers::is_linux_kernel(elf_handle());
703 
704  if (looking_at_linux_kernel_binary)
705  {
706  if (symbol->is_in_ksymtab())
707  return symbol;
708  return elf_symbol_sptr();
709  }
710 
711  return symbol;
712 }
713 
714 /// Test if a given variable symbol has been exported.
715 ///
716 /// @param symbol_address the address of the symbol we are looking
717 /// for. Note that this address must be a relative offset from the
718 /// beginning of the .text section, just like the kind of addresses
719 /// that are present in the .symtab section.
720 ///
721 /// @return the elf symbol if found, or nil otherwise.
723 reader::variable_symbol_is_exported(GElf_Addr symbol_address) const
724 {
725  elf_symbol_sptr symbol =
726  symtab()->variable_symbol_is_exported(symbol_address);
727  if (!symbol)
728  return symbol;
729 
730  address_set_sptr set;
731  bool looking_at_linux_kernel_binary =
732  load_in_linux_kernel_mode() && elf_helpers::is_linux_kernel(elf_handle());
733 
734  if (looking_at_linux_kernel_binary)
735  {
736  if (symbol->is_in_ksymtab())
737  return symbol;
738  return elf_symbol_sptr();
739  }
740 
741  return symbol;
742 }
743 
744 /// Test if a given function symbol has been exported.
745 ///
746 /// @param name the name of the symbol we are looking for.
747 ///
748 /// @return the elf symbol if found, or nil otherwise.
750 reader::function_symbol_is_exported(const string& name) const
751 {
752  const elf_symbol_sptr s = symtab()->function_symbol_is_exported(name);
753  if (s && s->is_function() && s->is_public())
754  {
755  bool looking_at_linux_kernel_binary =
756  (load_in_linux_kernel_mode()
757  && elf_helpers::is_linux_kernel(elf_handle()));
758 
759  if (looking_at_linux_kernel_binary)
760  {
761  if (s->is_in_ksymtab())
762  return s;
763  }
764  else
765  return s;
766  }
767  return elf_symbol_sptr();
768 }
769 
770 /// Test if a given variable symbol has been exported.
771 ///
772 /// @param name the name of the symbol we are looking
773 /// for.
774 ///
775 /// @return the elf symbol if found, or nil otherwise.
777 reader::variable_symbol_is_exported(const string& name) const
778 {
779  const elf_symbol_sptr s = symtab()->variable_symbol_is_exported(name);
780  if (s && s->is_variable() && s->is_public())
781  {
782  bool looking_at_linux_kernel_binary =
783  (load_in_linux_kernel_mode()
784  && elf_helpers::is_linux_kernel(elf_handle()));
785 
786  if (looking_at_linux_kernel_binary)
787  {
788  if (s->is_in_ksymtab())
789  return s;
790  }
791  else
792  return s;
793  }
794  return elf_symbol_sptr();
795 }
796 
797 /// Test if a name is the name of an undefined function symbol.
798 ///
799 /// @param name the symbol name to consider.
800 ///
801 /// @return the undefined function symbol or nil if none was found.
803 reader::function_symbol_is_undefined(const string& name) const
804 {return symtab()->function_symbol_is_undefined(name);}
805 
806 /// Test if a name is the name of an undefined variable symbol.
807 ///
808 /// @param name the symbol name to consider.
809 ///
810 /// @return the undefined variable symbol or nil if none was found.
812 reader::variable_symbol_is_undefined(const string& name) const
813 {return symtab()->variable_symbol_is_undefined(name);}
814 
815 /// Load the DT_NEEDED and DT_SONAME elf TAGS.
816 void
817 reader::load_dt_soname_and_needed()
818 {
819  elf_helpers::lookup_data_tag_from_dynamic_segment(elf_handle(),
820  DT_NEEDED,
821  priv_->dt_needed);
822 
823  vector<string> dt_tag_data;
824  elf_helpers::lookup_data_tag_from_dynamic_segment(elf_handle(),
825  DT_SONAME,
826  dt_tag_data);
827  if (!dt_tag_data.empty())
828  dt_soname(dt_tag_data[0]);
829 }
830 
831 /// Read the string representing the architecture of the current ELF
832 /// file.
833 void
834 reader::load_elf_architecture()
835 {
836  if (!elf_handle())
837  return;
838 
839  GElf_Ehdr eh_mem;
840  GElf_Ehdr* elf_header = gelf_getehdr(elf_handle(), &eh_mem);
841 
842  priv_->elf_architecture =
843  elf_helpers::e_machine_to_string(elf_header->e_machine);
844 }
845 
846 /// Load various ELF data.
847 ///
848 /// This function loads ELF data that are not symbol maps or debug
849 /// info. That is, things like various tags, elf architecture and
850 /// so on.
851 void
852 reader::load_elf_properties()
853 {
854  // Note that we don't load the symbol table as it's loaded lazily,
855  // on demand.
856 
857  load_dt_soname_and_needed();
858  load_elf_architecture();
859 }
860 
861 /// Read the ELF information associated to the current ELF file and
862 /// construct an ABI representation from it.
863 ///
864 /// Note that this reader doesn't know how to interpret any debug
865 /// information so the resulting ABI corpus won't have any type
866 /// information. Rather, it will only have ELF symbol representation.
867 ///
868 /// To have type information, consider using readers that know how to
869 /// interpret the symbolic type information comprised in DWARF, CTF or
870 /// other symbolic debug information format, like the @ref or
871 /// abigail::dwarf_reader::reader, @ref abigail::ctf_reader::reader
872 /// readers.
873 ///
874 /// @return the resulting ABI corpus.
875 ir::corpus_sptr
876 reader::read_corpus(status& status)
877 {
878  status = STATUS_UNKNOWN;
879 
880  corpus::origin origin = corpus()->get_origin();
881  origin |= corpus::ELF_ORIGIN;
882  if (is_linux_kernel(elf_handle()))
883  origin |= corpus::LINUX_KERNEL_BINARY_ORIGIN;
884  corpus()->set_origin(origin);
885 
886  load_elf_properties(); // DT_SONAME, DT_NEEDED, architecture
887  corpus()->set_soname(dt_soname());
888  corpus()->set_needed(dt_needed());
889  corpus()->set_architecture_name(elf_architecture());
890 
891  // See if we could find symbol tables.
892  if (!symtab())
893  {
894  status |= STATUS_NO_SYMBOLS_FOUND | STATUS_OK;
895  // We found no ELF symbol, so we can't handle the binary. Note
896  // that we could have found a symbol table with no defined &
897  // exported ELF symbols in it. Both cases are handled as an
898  // empty corpus.
899  return corpus();
900  }
901 
902  // Set symbols information to the corpus.
903  corpus()->set_symtab(symtab());
904 
905  // If we couldn't load debug info from the elf path, then say it.
906  if ((origin & abigail::ir::corpus::DWARF_ORIGIN)
907  && !has_dwarf_debug_info())
908  status |= STATUS_DEBUG_INFO_NOT_FOUND;
909  else if ((origin & abigail::ir::corpus::CTF_ORIGIN)
910  && !has_ctf_debug_info())
911  status |= STATUS_DEBUG_INFO_NOT_FOUND;
912 
913  status |= STATUS_OK;
914  return corpus();
915 }
916 
917 /// Get the SONAME property of a designated ELF file.
918 ///
919 /// @param path the path to the ELF file to consider.
920 ///
921 /// @param soname output parameter. This is set to the SONAME of the
922 /// file located at @p path, iff this function return true.
923 ///
924 /// @return true iff the SONAME property was found in the ELF file
925 /// located at @p path and set into the argument of the parameter @p
926 /// soname.
927 bool
928 get_soname_of_elf_file(const string& path, string &soname)
929 {return elf_helpers::get_soname_of_elf_file(path, soname);}
930 
931 /// Convert the type of ELF file into @ref elf_type.
932 ///
933 /// @param elf the elf handle to use for the query.
934 ///
935 /// @return the @ref elf_type for a given elf type.
936 static elf::elf_type
937 elf_file_type(Elf* elf)
938 {
939  GElf_Ehdr ehdr_mem;
940  GElf_Ehdr *header = gelf_getehdr (elf, &ehdr_mem);
941  vector<string> dt_debug_data;
942 
943  switch (header->e_type)
944  {
945  case ET_DYN:
946  if (lookup_data_tag_from_dynamic_segment(elf, DT_DEBUG, dt_debug_data))
947  return elf::ELF_TYPE_PI_EXEC;
948  else
949  return elf::ELF_TYPE_DSO;
950  case ET_EXEC:
951  return elf::ELF_TYPE_EXEC;
952  case ET_REL:
954  default:
955  return elf::ELF_TYPE_UNKNOWN;
956  }
957 }
958 
959 /// Get the type of a given elf type.
960 ///
961 /// @param path the absolute path to the ELF file to analyzed.
962 ///
963 /// @param type the kind of the ELF file designated by @p path.
964 ///
965 /// @param out parameter. Is set to the type of ELF file of @p path.
966 /// This parameter is set iff the function returns true.
967 ///
968 /// @return true iff the file could be opened and analyzed.
969 bool
970 get_type_of_elf_file(const string& path, elf::elf_type& type)
971 {
972  int fd = open(path.c_str(), O_RDONLY);
973  if (fd == -1)
974  return false;
975 
976  elf_version (EV_CURRENT);
977  // Note that the dwelf_elf_begin function supports decompressing the
978  // content of the input file, which is pretty cool.
979  Elf *elf = dwelf_elf_begin(fd);
980  type = elf_file_type(elf);
981  elf_end(elf);
982  close(fd);
983 
984  return true;
985 }
986 
987 }// end namespace elf
988 } // 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:1018
void set_architecture_name(const string &)
Setter for the architecture name of the corpus.
Definition: abg-corpus.cc:1062
This is the abstraction of a set of translation units (themselves seen as bundles of unitary abi arte...
Definition: abg-corpus.h:24
const vector< string > & debug_info_root_paths() const
Getter of the vector of directory paths to look into for split debug information files.
status
The status of the fe_iface::read_corpus call.
Definition: abg-fe-iface.h:37
void set_soname(const string &)
Setter for the soname property of the corpus.
Definition: abg-corpus.cc:1040
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.
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
This is an abstraction of the set of resources necessary to manage several aspects of the internal re...
Definition: abg-ir.h:147
This contains the private implementation of the suppression engine of libabigail. ...
bool string_begins_with(const string &str, const string &prefix)
Test if a given string begins with a particular prefix.
shared_ptr< elf_symbol > elf_symbol_sptr
A convenience typedef for a shared pointer to elf_symbol.
Definition: abg-ir.h:924
#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:1743
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.
bool get_file_path_dirs_under_dir(const string &root_dir, vector< string > &dirs)
Get all the sub-directories (which contain a regular file) of a given directory.
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.
void initialize()
The initialization function of libxml2 abstraction layer. This function must be called prior to using...
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:937
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:930
void set_symtab(symtab_reader::symtab_sptr)
Setter for the symtab object.
Definition: abg-corpus.cc:1121
virtual void initialize(const std::string &corpus_path)
Re-initialize the current Front End.
Definition: abg-fe-iface.cc:81
elf_type
The kind of ELF file we are looking at.