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 = 0;
141  Elf_Scn* ctf_section = nullptr;
142  int alt_ctf_fd = 0;
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 = 0;
186  ctf_section = nullptr;
187  alt_ctf_section = nullptr;
188  alt_ctf_handle = nullptr;
189  alt_ctf_fd = 0;
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)
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 = 0;
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)
309  {
310  close(alt_ctf_fd);
311  alt_ctf_fd = 0;
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  if ((alt_ctf_fd = open(file_path.c_str(), O_RDONLY)) == -1)
350  continue;
351 
352  if ((alt_ctf_handle = elf_begin(alt_ctf_fd,
353  ELF_C_READ,
354  nullptr)) == nullptr)
355  continue;
356 
357  // unlikely .ctf was designed to be present in stripped file
358  alt_ctf_section =
359  elf_helpers::find_section(alt_ctf_handle, ".ctf", SHT_PROGBITS);
360 
361  if (alt_ctf_section)
362  break;
363  }
364  }
365 
366  /// Locate the CTF debug information associated with the current ELF
367  /// file. It also locates the CTF debug information that is split
368  /// out in a separate file.
369  void
370  locate_ctf_debug_info()
371  {
372  ABG_ASSERT(elf_handle);
373 
374  ctf_section = elf_helpers::find_section_by_name(elf_handle, ".ctf");
375  if (ctf_section == nullptr)
376  {
377  locate_alt_ctf_debug_info();
378  ctf_section = alt_ctf_section;
379  }
380  }
381 }; //end reader::priv
382 
383 /// The constructor of the @ref elf::reader type.
384 ///
385 /// @param elf_path the path to the ELF file to read from.
386 ///
387 /// @param debug_info_root a vector of directory paths to look into
388 /// for split debug information files.
389 ///
390 /// @param env the environment which the reader operates in.
391 reader::reader(const string& elf_path,
392  const vector<string>& debug_info_roots,
393  ir::environment& env)
394  : fe_iface(elf_path, env),
395  priv_(new priv(*this, elf_path, debug_info_roots))
396 {
397  priv_->crack_open_elf_file();
398  priv_->locate_dwarf_debug_info();
399  priv_->locate_ctf_debug_info();
400 }
401 
402 /// The destructor of the @ref elf::reader type.
403 reader::~reader()
404 {delete priv_;}
405 
406 /// Re-initialize the resources used by the current @ref elf::reader
407 /// type.
408 ///
409 /// This lets the reader in a state where it's ready to read from
410 /// another ELF file.
411 ///
412 /// @param elf_path the new ELF path to read from.
413 ///
414 /// @param debug_info_roots a vector of directory paths to look into
415 /// for split debug information files.
416 void
417 reader::initialize(const std::string& elf_path,
418  const vector<string>& debug_info_roots)
419 {
420  fe_iface::initialize(elf_path);
421  corpus_path(elf_path);
422  priv_->initialize(debug_info_roots);
423  priv_->crack_open_elf_file();
424  priv_->locate_dwarf_debug_info();
425  priv_->locate_ctf_debug_info();
426 }
427 
428 /// Re-initialize the resources used by the current @ref elf::reader
429 /// type.
430 ///
431 /// This lets the reader in a state where it's ready to read from
432 /// another ELF file.
433 ///
434 /// @param elf_path the new ELF path to read from.
435 void
436 reader::initialize(const std::string& elf_path)
437 {
438  vector<string> v;
439  initialize(elf_path, v);
440 }
441 
442 /// Getter of the vector of directory paths to look into for split
443 /// debug information files.
444 ///
445 /// @return the vector of directory paths to look into for split
446 /// debug information files.
447 const vector<string>&
448 reader::debug_info_root_paths() const
449 {return priv_->debug_info_root_paths;}
450 
451 /// Getter of the functions used by the DWARF Front End library of
452 /// elfutils to locate DWARF debug information.
453 ///
454 /// @return the functions used by the DWARF Front End library of
455 const Dwfl_Callbacks&
456 reader::dwfl_offline_callbacks() const
457 {return priv_->offline_callbacks;}
458 
459 /// Getter of the functions used by the DWARF Front End library of
460 /// elfutils to locate DWARF debug information.
461 ///
462 /// @return the functions used by the DWARF Front End library of
463 Dwfl_Callbacks&
464 reader::dwfl_offline_callbacks()
465 {return priv_->offline_callbacks;}
466 
467 /// Getter of the handle used to access ELF information from the
468 /// current ELF file.
469 ///
470 /// @return the handle used to access ELF information from the current
471 /// ELF file.
472 Elf*
473 reader::elf_handle() const
474 {return priv_->elf_handle;}
475 
476 /// Getter of the handle used to access DWARF information from the
477 /// current ELF file.
478 ///
479 /// @return the handle used to access DWARF information from the
480 /// current ELF file.
481 const Dwarf*
482 reader::dwarf_debug_info() const
483 {return priv_->dwarf_handle;}
484 
485 /// Test if the binary has DWARF debug info.
486 ///
487 /// @return true iff the binary has DWARF debug info.
488 bool
489 reader::has_dwarf_debug_info() const
490 {return ((priv_->dwarf_handle != nullptr)
491  || (priv_->alt_dwarf_handle != nullptr));}
492 
493 /// Test if the binary has CTF debug info.
494 ///
495 /// @return true iff the binary has CTF debug info.
496 bool
497 reader::has_ctf_debug_info() const
498 {return (priv_->ctf_section != nullptr);}
499 
500 /// Test if the binary has BTF debug info.
501 ///
502 /// @return true iff the binary has BTF debug info
503 bool
504 reader::has_btf_debug_info() const
505 {return (priv_->btf_section != nullptr);}
506 
507 /// Getter of the handle use to access DWARF information from the
508 /// alternate split DWARF information.
509 ///
510 /// In other words, this accesses the factorized DWARF information
511 /// that has been constructed by the DWZ tool to de-duplicate DWARF
512 /// information on disk.
513 ///
514 /// @return the handle use to access DWARF information from the
515 /// alternate split DWARF information.
516 const Dwarf*
517 reader::alternate_dwarf_debug_info() const
518 {return priv_->alt_dwarf_handle;}
519 
520 
521 /// Getter of the path to the alternate split DWARF information file,
522 /// on disk. In othe words, this returns the path to the factorized
523 /// DWARF information used by the current ELF file, created by the
524 /// 'DWZ' tool.
525 ///
526 /// @return the path to the alternate split DWARF information file,
527 /// on disk.
528 const string&
529 reader::alternate_dwarf_debug_info_path() const
530 {return priv_->alt_dwarf_path;}
531 
532 /// Check if the underlying elf file refers to an alternate debug info
533 /// file associated to it.
534 ///
535 /// Note that "alternate debug info sections" is a GNU extension as
536 /// of DWARF4 and is described at
537 /// http://www.dwarfstd.org/ShowIssue.php?issue=120604.1.
538 ///
539 /// @param alt_di the path to the alternate debug info file. This is
540 /// set iff the function returns true.
541 ///
542 /// @return true if the ELF file refers to an alternate debug info
543 /// file.
544 bool
545 reader::refers_to_alt_debug_info(string& alt_di_path) const
546 {
547  if (!alternate_dwarf_debug_info_path().empty())
548  {
549  alt_di_path = alternate_dwarf_debug_info_path();
550  return true;
551  }
552  return false;
553 }
554 
555 /// Find and return a pointer to the ELF symbol table
556 /// section.
557 ///
558 /// @return a pointer to the ELF symbol table section.
559 const Elf_Scn*
560 reader::find_symbol_table_section() const
561 {
562  if (!priv_->symtab_section)
563  priv_->symtab_section =
564  elf_helpers::find_symbol_table_section(elf_handle());
565  return priv_->symtab_section;
566 }
567 
568 /// Clear the pointer to the ELF symbol table section.
569 void
570 reader::reset_symbol_table_section()
571 {priv_->symtab_section = nullptr;}
572 
573 /// Find and return a pointer to the the CTF section.
574 ///
575 /// @return a pointer to the the CTF section.
576 const Elf_Scn*
577 reader::find_ctf_section() const
578 {
579  if (priv_->ctf_section == nullptr)
580  priv_->locate_ctf_debug_info();
581 
582  if (priv_->ctf_section)
583  return priv_->ctf_section;
584 
585  return priv_->alt_ctf_section;
586 }
587 
588 /// Find and return a pointer to the alternate CTF section of the
589 /// current ELF file.
590 ///
591 /// @return a pointer to the alternate CTF section of the current ELF
592 /// file.
593 const Elf_Scn*
594 reader::find_alternate_ctf_section() const
595 {
596  if (priv_->alt_ctf_section == nullptr)
597  priv_->locate_alt_ctf_debug_info();
598 
599  return priv_->alt_ctf_section;
600 }
601 
602 /// Find and return a pointer to the BTF section of the current ELF
603 /// file.
604 ///
605 /// @return a pointer to the BTF section of the current ELF file.
606 const Elf_Scn*
607 reader::find_btf_section() const
608 {
609  if (priv_->btf_section == nullptr)
610  priv_->btf_section =
611  elf_helpers::find_section(priv_->elf_handle,
612  ".BTF", SHT_PROGBITS);
613  return priv_->btf_section;
614 }
615 
616 /// Get the value of the DT_NEEDED property of the current ELF file.
617 ///
618 /// @return the value of the DT_NEEDED property.
619 const vector<string>&
620 reader::dt_needed()const
621 {return priv_->dt_needed;}
622 
623 
624 /// Get the value of the 'ARCHITECTURE' property of the current ELF file.
625 ///
626 /// @return the value of the 'ARCHITECTURE' property of the current
627 /// ELF file.
628 const string&
629 reader::elf_architecture() const
630 {return priv_->elf_architecture;}
631 
632 /// Getter of an abstract representation of the symbol table of the
633 /// underlying ELF file.
634 ///
635 /// Note that the symbol table is loaded lazily, upon the first
636 /// invocation of this member function.
637 ///
638 /// @returnt the symbol table.
639 symtab_reader::symtab_sptr&
640 reader::symtab() const
641 {
642  ABG_ASSERT(elf_handle());
643 
644  if (!priv_->symt)
645  priv_->symt = symtab_reader::symtab::load
646  (elf_handle(), options().env,
647  [&](const elf_symbol_sptr& symbol)
648  {
649  // This closure determines if a given symbol is suppressed by
650  // taking into accont symbol aliases. Basically, a symbol is
651  // suppressed if all its aliases are suppressed.
652  if (!symbol)
653  return false;
654  if (!suppr::is_elf_symbol_suppressed(*this, symbol))
655  return false;
656  for (elf_symbol_sptr a = symbol->get_next_alias();
657  a && a.get() != symbol->get_main_symbol().get();
658  a = a->get_next_alias())
659  {
660  if (!suppr::is_elf_symbol_suppressed(*this, a))
661  return false;
662  }
663  return true;
664  }
665  );
666 
667  if (!priv_->symt)
668  std::cerr << "Symbol table of '" << corpus_path()
669  << "' could not be loaded\n";
670  return priv_->symt;
671 }
672 
673 /// Test if a given function symbol has been exported.
674 ///
675 /// @param symbol_address the address of the symbol we are looking
676 /// for. Note that this address must be a relative offset from the
677 /// beginning of the .text section, just like the kind of addresses
678 /// that are present in the .symtab section.
679 ///
680 /// @return the elf symbol if found, or nil otherwise.
682 reader::function_symbol_is_exported(GElf_Addr symbol_address) const
683 {
684 
685  elf_symbol_sptr symbol =
686  symtab()->function_symbol_is_exported(symbol_address);
687  if (!symbol)
688  return symbol;
689 
690  address_set_sptr set;
691  bool looking_at_linux_kernel_binary =
692  load_in_linux_kernel_mode() && elf_helpers::is_linux_kernel(elf_handle());
693 
694  if (looking_at_linux_kernel_binary)
695  {
696  if (symbol->is_in_ksymtab())
697  return symbol;
698  return elf_symbol_sptr();
699  }
700 
701  return symbol;
702 }
703 
704 /// Test if a given variable symbol has been exported.
705 ///
706 /// @param symbol_address the address of the symbol we are looking
707 /// for. Note that this address must be a relative offset from the
708 /// beginning of the .text section, just like the kind of addresses
709 /// that are present in the .symtab section.
710 ///
711 /// @return the elf symbol if found, or nil otherwise.
713 reader::variable_symbol_is_exported(GElf_Addr symbol_address) const
714 {
715  elf_symbol_sptr symbol =
716  symtab()->variable_symbol_is_exported(symbol_address);
717  if (!symbol)
718  return symbol;
719 
720  address_set_sptr set;
721  bool looking_at_linux_kernel_binary =
722  load_in_linux_kernel_mode() && elf_helpers::is_linux_kernel(elf_handle());
723 
724  if (looking_at_linux_kernel_binary)
725  {
726  if (symbol->is_in_ksymtab())
727  return symbol;
728  return elf_symbol_sptr();
729  }
730 
731  return symbol;
732 }
733 
734 /// Test if a given function symbol has been exported.
735 ///
736 /// @param name the name of the symbol we are looking for.
737 ///
738 /// @return the elf symbol if found, or nil otherwise.
740 reader::function_symbol_is_exported(const string& name) const
741 {
742  const elf_symbol_sptr s = symtab()->function_symbol_is_exported(name);
743  if (s && s->is_function() && s->is_public())
744  {
745  bool looking_at_linux_kernel_binary =
746  (load_in_linux_kernel_mode()
747  && elf_helpers::is_linux_kernel(elf_handle()));
748 
749  if (looking_at_linux_kernel_binary)
750  {
751  if (s->is_in_ksymtab())
752  return s;
753  }
754  else
755  return s;
756  }
757  return elf_symbol_sptr();
758 }
759 
760 /// Test if a given variable symbol has been exported.
761 ///
762 /// @param name the name of the symbol we are looking
763 /// for.
764 ///
765 /// @return the elf symbol if found, or nil otherwise.
767 reader::variable_symbol_is_exported(const string& name) const
768 {
769  const elf_symbol_sptr s = symtab()->variable_symbol_is_exported(name);
770  if (s && s->is_variable() && s->is_public())
771  {
772  bool looking_at_linux_kernel_binary =
773  (load_in_linux_kernel_mode()
774  && elf_helpers::is_linux_kernel(elf_handle()));
775 
776  if (looking_at_linux_kernel_binary)
777  {
778  if (s->is_in_ksymtab())
779  return s;
780  }
781  else
782  return s;
783  }
784  return elf_symbol_sptr();
785 }
786 
787 /// Test if a name is the name of an undefined function symbol.
788 ///
789 /// @param name the symbol name to consider.
790 ///
791 /// @return the undefined function symbol or nil if none was found.
793 reader::function_symbol_is_undefined(const string& name) const
794 {return symtab()->function_symbol_is_undefined(name);}
795 
796 /// Test if a name is the name of an undefined variable symbol.
797 ///
798 /// @param name the symbol name to consider.
799 ///
800 /// @return the undefined variable symbol or nil if none was found.
802 reader::variable_symbol_is_undefined(const string& name) const
803 {return symtab()->variable_symbol_is_undefined(name);}
804 
805 /// Load the DT_NEEDED and DT_SONAME elf TAGS.
806 void
807 reader::load_dt_soname_and_needed()
808 {
809  elf_helpers::lookup_data_tag_from_dynamic_segment(elf_handle(),
810  DT_NEEDED,
811  priv_->dt_needed);
812 
813  vector<string> dt_tag_data;
814  elf_helpers::lookup_data_tag_from_dynamic_segment(elf_handle(),
815  DT_SONAME,
816  dt_tag_data);
817  if (!dt_tag_data.empty())
818  dt_soname(dt_tag_data[0]);
819 }
820 
821 /// Read the string representing the architecture of the current ELF
822 /// file.
823 void
824 reader::load_elf_architecture()
825 {
826  if (!elf_handle())
827  return;
828 
829  GElf_Ehdr eh_mem;
830  GElf_Ehdr* elf_header = gelf_getehdr(elf_handle(), &eh_mem);
831 
832  priv_->elf_architecture =
833  elf_helpers::e_machine_to_string(elf_header->e_machine);
834 }
835 
836 /// Load various ELF data.
837 ///
838 /// This function loads ELF data that are not symbol maps or debug
839 /// info. That is, things like various tags, elf architecture and
840 /// so on.
841 void
842 reader::load_elf_properties()
843 {
844  // Note that we don't load the symbol table as it's loaded lazily,
845  // on demand.
846 
847  load_dt_soname_and_needed();
848  load_elf_architecture();
849 }
850 
851 /// Read the ELF information associated to the current ELF file and
852 /// construct an ABI representation from it.
853 ///
854 /// Note that this reader doesn't know how to interpret any debug
855 /// information so the resulting ABI corpus won't have any type
856 /// information. Rather, it will only have ELF symbol representation.
857 ///
858 /// To have type information, consider using readers that know how to
859 /// interpret the symbolic type information comprised in DWARF, CTF or
860 /// other symbolic debug information format, like the @ref or
861 /// abigail::dwarf_reader::reader, @ref abigail::ctf_reader::reader
862 /// readers.
863 ///
864 /// @return the resulting ABI corpus.
865 ir::corpus_sptr
866 reader::read_corpus(status& status)
867 {
868  status = STATUS_UNKNOWN;
869 
870  corpus::origin origin = corpus()->get_origin();
871  origin |= corpus::ELF_ORIGIN;
872  if (is_linux_kernel(elf_handle()))
873  origin |= corpus::LINUX_KERNEL_BINARY_ORIGIN;
874  corpus()->set_origin(origin);
875 
876  load_elf_properties(); // DT_SONAME, DT_NEEDED, architecture
877  corpus()->set_soname(dt_soname());
878  corpus()->set_needed(dt_needed());
879  corpus()->set_architecture_name(elf_architecture());
880 
881  // See if we could find symbol tables.
882  if (!symtab())
883  {
884  status |= STATUS_NO_SYMBOLS_FOUND | STATUS_OK;
885  // We found no ELF symbol, so we can't handle the binary. Note
886  // that we could have found a symbol table with no defined &
887  // exported ELF symbols in it. Both cases are handled as an
888  // empty corpus.
889  return corpus();
890  }
891 
892  // Set symbols information to the corpus.
893  corpus()->set_symtab(symtab());
894 
895  // If we couldn't load debug info from the elf path, then say it.
896  if ((origin & abigail::ir::corpus::DWARF_ORIGIN)
897  && !has_dwarf_debug_info())
898  status |= STATUS_DEBUG_INFO_NOT_FOUND;
899  else if ((origin & abigail::ir::corpus::CTF_ORIGIN)
900  && !has_ctf_debug_info())
901  status |= STATUS_DEBUG_INFO_NOT_FOUND;
902 
903  status |= STATUS_OK;
904  return corpus();
905 }
906 
907 /// Get the SONAME property of a designated ELF file.
908 ///
909 /// @param path the path to the ELF file to consider.
910 ///
911 /// @param soname output parameter. This is set to the SONAME of the
912 /// file located at @p path, iff this function return true.
913 ///
914 /// @return true iff the SONAME property was found in the ELF file
915 /// located at @p path and set into the argument of the parameter @p
916 /// soname.
917 bool
918 get_soname_of_elf_file(const string& path, string &soname)
919 {return elf_helpers::get_soname_of_elf_file(path, soname);}
920 
921 /// Convert the type of ELF file into @ref elf_type.
922 ///
923 /// @param elf the elf handle to use for the query.
924 ///
925 /// @return the @ref elf_type for a given elf type.
926 static elf::elf_type
927 elf_file_type(Elf* elf)
928 {
929  GElf_Ehdr ehdr_mem;
930  GElf_Ehdr *header = gelf_getehdr (elf, &ehdr_mem);
931  vector<string> dt_debug_data;
932 
933  switch (header->e_type)
934  {
935  case ET_DYN:
936  if (lookup_data_tag_from_dynamic_segment(elf, DT_DEBUG, dt_debug_data))
937  return elf::ELF_TYPE_PI_EXEC;
938  else
939  return elf::ELF_TYPE_DSO;
940  case ET_EXEC:
941  return elf::ELF_TYPE_EXEC;
942  case ET_REL:
944  default:
945  return elf::ELF_TYPE_UNKNOWN;
946  }
947 }
948 
949 /// Get the type of a given elf type.
950 ///
951 /// @param path the absolute path to the ELF file to analyzed.
952 ///
953 /// @param type the kind of the ELF file designated by @p path.
954 ///
955 /// @param out parameter. Is set to the type of ELF file of @p path.
956 /// This parameter is set iff the function returns true.
957 ///
958 /// @return true iff the file could be opened and analyzed.
959 bool
960 get_type_of_elf_file(const string& path, elf::elf_type& type)
961 {
962  int fd = open(path.c_str(), O_RDONLY);
963  if (fd == -1)
964  return false;
965 
966  elf_version (EV_CURRENT);
967  // Note that the dwelf_elf_begin function supports decompressing the
968  // content of the input file, which is pretty cool.
969  Elf *elf = dwelf_elf_begin(fd);
970  type = elf_file_type(elf);
971  elf_end(elf);
972  close(fd);
973 
974  return true;
975 }
976 
977 }// end namespace elf
978 } // 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.