• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
2 // -*- Mode: C++ -*-
3 //
4 // Copyright (C) 2022 Red Hat, Inc.
5 //
6 // Author: Dodji Seketeli
7 
8 /// @file
9 ///
10 /// Elf reader stuff
11 
12 #include "abg-internal.h"
13 
14 #include <fcntl.h> /* For open(3) */
15 #include <unistd.h>
16 #include <iostream>
17 #include <cstring>
18 #include <libgen.h>
19 #include <fcntl.h>
20 #include <elfutils/libdwfl.h>
21 
22 
23 #include "abg-symtab-reader.h"
24 #include "abg-suppression-priv.h"
25 #include "abg-elf-helpers.h"
26 
27 // <headers defining libabigail's API go under here>
28 ABG_BEGIN_EXPORT_DECLARATIONS
29 #include "abg-elf-reader.h"
30 #include "abg-tools-utils.h"
31 ABG_END_EXPORT_DECLARATIONS
32 // </headers defining libabigail's API>
33 namespace abigail
34 {
35 
36 using namespace elf_helpers;
37 
38 namespace elf
39 {
40 
41 /// Find the file name of the alternate debug info file.
42 ///
43 /// @param elf_module the elf module to consider.
44 ///
45 /// @param out parameter.  Is set to the file name of the alternate
46 /// debug info file, iff this function returns true.
47 ///
48 /// @return true iff the location of the alternate debug info file was
49 /// found.
50 static bool
find_alt_dwarf_debug_info_link(Dwfl_Module * elf_module,string & alt_file_name)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
find_alt_dwarf_debug_info_path(const vector<char ** > root_dirs,const string & alt_file_name,string & alt_file_path)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 
136   for (vector<char**>::const_iterator i = root_dirs.begin();
137        i != root_dirs.end();
138        ++i)
139     if (tools_utils::find_file_under_dir(**i, altfile_name, alt_file_path))
140       return true;
141 
142   return false;
143 }
144 
145 /// Return the alternate debug info associated to a given main debug
146 /// info file.
147 ///
148 /// @param elf_module the elf module to consider.
149 ///
150 /// @param debug_root_dirs a set of root debuginfo directories under
151 /// which too look for the alternate debuginfo file.
152 ///
153 /// @param alt_file_name output parameter.  This is set to the file
154 /// path of the alternate debug info file associated to @p elf_module.
155 /// This is set iff the function returns a non-null result.
156 ///
157 /// @param alt_fd the file descriptor used to access the alternate
158 /// debug info.  If this parameter is set by the function, then the
159 /// caller needs to fclose it, otherwise the file descriptor is going
160 /// to be leaked.  Note however that on recent versions of elfutils
161 /// where libdw.h contains the function dwarf_getalt(), this parameter
162 /// is set to 0, so it doesn't need to be fclosed.
163 ///
164 /// Note that the alternate debug info file is a DWARF extension as of
165 /// DWARF 4 ans is decribed at
166 /// http://www.dwarfstd.org/ShowIssue.php?issue=120604.1.
167 ///
168 /// @return the alternate debuginfo, or null.  If @p alt_fd is
169 /// non-zero, then the caller of this function needs to call
170 /// dwarf_end() on the returned alternate debuginfo pointer,
171 /// otherwise, it's going to be leaked.
172 static Dwarf*
find_alt_dwarf_debug_info(Dwfl_Module * elf_module,const vector<char ** > debug_root_dirs,string & alt_file_name,int & alt_fd)173 find_alt_dwarf_debug_info(Dwfl_Module *elf_module,
174 			  const vector<char**> debug_root_dirs,
175 			  string& alt_file_name,
176 			  int& alt_fd)
177 {
178   if (elf_module == 0)
179     return 0;
180 
181   Dwarf* result = 0;
182   find_alt_dwarf_debug_info_link(elf_module, alt_file_name);
183 
184 #ifdef LIBDW_HAS_DWARF_GETALT
185   // We are on recent versions of elfutils where the function
186   // dwarf_getalt exists, so let's use it.
187   Dwarf_Addr bias = 0;
188   Dwarf* dwarf = dwfl_module_getdwarf(elf_module, &bias);
189   result = dwarf_getalt(dwarf);
190   alt_fd = 0;
191 #else
192   // We are on an old version of elfutils where the function
193   // dwarf_getalt doesn't exist yet, so let's open code its
194   // functionality
195   char *alt_name = 0;
196   const char *file_name = 0;
197   void **user_data = 0;
198   Dwarf_Addr low_addr = 0;
199   char *alt_file = 0;
200 
201   file_name = dwfl_module_info(elf_module, &user_data,
202 			       &low_addr, 0, 0, 0, 0, 0);
203 
204   alt_fd = dwfl_standard_find_debuginfo(elf_module, user_data,
205 					file_name, low_addr,
206 					alt_name, file_name,
207 					0, &alt_file);
208 
209   result = dwarf_begin(alt_fd, DWARF_C_READ);
210 #endif
211 
212   if (result == 0)
213     {
214       // So we didn't find the alternate debuginfo file from the
215       // information that is in the debuginfo file associated to
216       // elf_module.  Maybe the alternate debuginfo file is located
217       // under one of the directories in debug_root_dirs.  So let's
218       // look in there.
219       string alt_file_path;
220       if (!find_alt_dwarf_debug_info_path(debug_root_dirs,
221 					  alt_file_name,
222 					  alt_file_path))
223 	return result;
224 
225       // If we reach this point it means we have found the path to the
226       // alternate debuginfo file and it's in alt_file_path.  So let's
227       // open it and read it.
228       int fd = open(alt_file_path.c_str(), O_RDONLY);
229       if (fd == -1)
230 	return result;
231       result = dwarf_begin(fd, DWARF_C_READ);
232 
233 #ifdef LIBDW_HAS_DWARF_GETALT
234       Dwarf_Addr bias = 0;
235       Dwarf* dwarf = dwfl_module_getdwarf(elf_module, &bias);
236       dwarf_setalt(dwarf, result);
237 #endif
238     }
239 
240   return result;
241 }
242 
243 /// Private data of the @ref elf::reader type.
244 struct reader::priv
245 {
246   reader&				rdr;
247   Elf*					elf_handle		= nullptr;
248   Elf_Scn*				symtab_section		= nullptr;
249   string				elf_architecture;
250   vector<string>			dt_needed;
251   // An abstraction of the symbol table.  This is loaded lazily, on
252   // demand.
253   mutable symtab_reader::symtab_sptr	symt;
254   // Where split debug info is to be searched for on disk.
255   vector<char**>			debug_info_root_paths;
256   // Some very useful callback functions that elfutils needs to
257   // perform various tasks.
258   Dwfl_Callbacks			offline_callbacks;
259   // A pointer to the DWARF Front End Library handle of elfutils.
260   // This is useful to perform all kind of things at a higher level.
261   dwfl_sptr				dwfl_handle;
262   // The address range of the offline elf file we are looking at.
263   Dwfl_Module*				elf_module		= nullptr;
264   // A pointer to the DWARF debug info, if found by locate_dwarf_debug_info.
265   Dwarf*				dwarf_handle		= nullptr;
266   // A pointer to the ALT DWARF debug info, which is the debug info
267   // that is constructed by the DWZ tool.  It's made of all the type
268   // information that was redundant in the DWARF.  DWZ put it there
269   // and make the DWARF reference it in here.
270   Dwarf*				alt_dwarf_handle	= nullptr;
271   string				alt_dwarf_path;
272   int					alt_dwarf_fd		= 0;
273   Elf_Scn*				ctf_section		= nullptr;
274   Elf_Scn*				alt_ctf_section	= nullptr;
275 
privabigail::elf::reader::priv276   priv(reader& reeder, const std::string& elf_path,
277        const vector<char**>& debug_info_roots)
278     : rdr(reeder)
279   {
280     rdr.corpus_path(elf_path);
281     initialize(debug_info_roots);
282   }
283 
284   /// Reset the private data of @elf elf::reader.
285   ///
286   /// @param debug_info_roots the vector of new directories where to
287   /// look for split debug info file.
288   void
initializeabigail::elf::reader::priv289   initialize(const vector<char**>& debug_info_roots)
290   {
291     debug_info_root_paths = debug_info_roots;
292     symt.reset();
293     dwfl_handle.reset();
294     elf_module = nullptr;
295     elf_handle = nullptr;
296   }
297 
298   /// Setup the necessary plumbing to open the ELF file and find all
299   /// the associated split debug info files.
300   ///
301   /// This function also setup the various handles on the opened ELF
302   /// file and whatnot.
303   void
crack_open_elf_fileabigail::elf::reader::priv304   crack_open_elf_file()
305   {
306     // Initialize the callback functions used by elfutils.
307     elf_helpers::initialize_dwfl_callbacks(offline_callbacks,
308 					   debug_info_root_paths.empty()
309 					   ? nullptr
310 					   : debug_info_root_paths.front());
311 
312     // Create a handle to the DWARF Front End Library that we'll need.
313     dwfl_handle = elf_helpers::create_new_dwfl_handle(offline_callbacks);
314 
315     const string& elf_path = rdr.corpus_path();
316     // Get the set of addresses that make up the ELF file we are
317     // looking at.
318     elf_module =
319       dwfl_report_offline(dwfl_handle.get(),
320 			  basename(const_cast<char*>(elf_path.c_str())),
321 			  elf_path.c_str(), -1);
322     dwfl_report_end(dwfl_handle.get(), 0, 0);
323     ABG_ASSERT(elf_module);
324 
325     // Finally, get and handle at the representation of the ELF file
326     // we've just cracked open.
327     GElf_Addr bias = 0;
328     elf_handle = dwfl_module_getelf(elf_module, &bias);
329     ABG_ASSERT(elf_handle);
330   }
331 
332   /// Find the alternate debuginfo file associated to a given elf file.
333   ///
334   /// @param elf_module represents the elf file to consider.
335   ///
336   /// @param alt_file_name the resulting path to the alternate
337   /// debuginfo file found.  This is set iff the function returns a
338   /// non-nil value.
339   Dwarf*
find_alt_dwarf_debug_infoabigail::elf::reader::priv340   find_alt_dwarf_debug_info(Dwfl_Module*	elf_module,
341 			    string&		alt_file_name,
342 			    int&		alt_fd)
343   {
344     Dwarf *result = 0;
345     result = elf::find_alt_dwarf_debug_info(elf_module,
346 					    debug_info_root_paths,
347 					    alt_file_name, alt_fd);
348     return result;
349   }
350 
351   /// Locate the DWARF debug info in the ELF file.
352   ///
353   /// This also knows how to locate split debug info.
354   void
locate_dwarf_debug_infoabigail::elf::reader::priv355   locate_dwarf_debug_info()
356   {
357     ABG_ASSERT(dwfl_handle);
358 
359     if (dwarf_handle)
360       return;
361 
362     // First let's see if the ELF file that was cracked open does have
363     // some DWARF debug info embedded.
364     Dwarf_Addr bias = 0;
365     dwarf_handle = dwfl_module_getdwarf(elf_module, &bias);
366 
367     // If no debug info was found in the binary itself, then look for
368     // split debuginfo files under multiple possible debuginfo roots.
369     for (vector<char**>::const_iterator i = debug_info_root_paths.begin();
370 	 dwarf_handle == 0 && i != debug_info_root_paths.end();
371 	 ++i)
372       {
373 	offline_callbacks.debuginfo_path = *i;
374 	dwarf_handle = dwfl_module_getdwarf(elf_module, &bias);
375       }
376 
377     alt_dwarf_handle = find_alt_dwarf_debug_info(elf_module,
378 						 alt_dwarf_path,
379 						 alt_dwarf_fd);
380   }
381 
382   /// Locate the CTF "alternate" debug information associated with the
383   /// current ELF file ( and split out somewhere else).
384   ///
385   /// This is a sub-routine of @ref locate_ctf_debug_info().
386   void
locate_alt_ctf_debug_infoabigail::elf::reader::priv387   locate_alt_ctf_debug_info()
388   {
389     Elf_Scn *section =
390       elf_helpers::find_section(elf_handle,
391 				".gnu_debuglink",
392 				SHT_PROGBITS);
393 
394     std::string name;
395     Elf_Data *data;
396     if (section
397 	&& (data = elf_getdata(section, nullptr))
398 	&& data->d_size != 0)
399       name = (char *) data->d_buf;
400 
401     if (!name.empty())
402       for (const auto& path : rdr.debug_info_root_paths())
403 	{
404 	  std::string file_path;
405 	  if (!tools_utils::find_file_under_dir(*path, name, file_path))
406 	    continue;
407 
408 	  int fd;
409 	  if ((fd = open(file_path.c_str(), O_RDONLY)) == -1)
410 	    continue;
411 
412 	  Elf *hdl;
413 	  if ((hdl = elf_begin(fd, ELF_C_READ, nullptr)) == nullptr)
414 	    {
415 	      close(fd);
416 	      continue;
417 	    }
418 
419 	  // unlikely .ctf was designed to be present in stripped file
420 	  alt_ctf_section =
421 	    elf_helpers::find_section(hdl, ".ctf", SHT_PROGBITS);
422           break;
423 
424 	  elf_end(hdl);
425 	  close(fd);
426 	}
427   }
428 
429   /// Locate the CTF debug information associated with the current ELF
430   /// file.  It also locates the CTF debug information that is split
431   /// out in a separate file.
432   void
locate_ctf_debug_infoabigail::elf::reader::priv433   locate_ctf_debug_info()
434   {
435     ABG_ASSERT(elf_handle);
436 
437     ctf_section = elf_helpers::find_section_by_name(elf_handle, ".ctf");
438     if (ctf_section == nullptr)
439       {
440 	locate_alt_ctf_debug_info();
441 	ctf_section = alt_ctf_section;
442       }
443   }
444 }; //end reader::priv
445 
446 /// The constructor of the @ref elf::reader type.
447 ///
448 /// @param elf_path the path to the ELF file to read from.
449 ///
450 /// @param debug_info_root a vector of directory paths to look into
451 /// for split debug information files.
452 ///
453 /// @param env the environment which the reader operates in.
reader(const string & elf_path,const vector<char ** > & debug_info_roots,ir::environment & env)454 reader::reader(const string&		elf_path,
455 	       const vector<char**>&	debug_info_roots,
456 	       ir::environment&	env)
457   : fe_iface(elf_path, env),
458     priv_(new priv(*this, elf_path, debug_info_roots))
459 {
460   priv_->crack_open_elf_file();
461   priv_->locate_dwarf_debug_info();
462   priv_->locate_ctf_debug_info();
463 }
464 
465 /// The destructor of the @ref elf::reader type.
~reader()466 reader::~reader()
467 {delete priv_;}
468 
469 /// Resets (erase) the resources used by the current @ref
470 /// elf::reader type.
471 ///
472 /// This lets the reader in a state where it's ready to read from
473 /// another ELF file.
474 ///
475 /// @param elf_path the new ELF path to read from.
476 ///
477 /// @param debug_info_roots a vector of directory paths to look into
478 /// for split debug information files.
479 void
reset(const std::string & elf_path,const vector<char ** > & debug_info_roots)480 reader::reset(const std::string&	elf_path,
481 	      const vector<char**>&	debug_info_roots)
482 {
483   fe_iface::options_type opts = options();
484   fe_iface::reset(elf_path, opts.env);
485   corpus_path(elf_path);
486   priv_->initialize(debug_info_roots);
487   priv_->crack_open_elf_file();
488   priv_->locate_dwarf_debug_info();
489   priv_->locate_ctf_debug_info();
490 }
491 
492 /// Getter of the vector of directory paths to look into for split
493 /// debug information files.
494 ///
495 /// @return the vector of directory paths to look into for split
496 /// debug information files.
497 const vector<char**>&
debug_info_root_paths() const498 reader::debug_info_root_paths() const
499 {return priv_->debug_info_root_paths;}
500 
501 /// Getter of the functions used by the DWARF Front End library of
502 /// elfutils to locate DWARF debug information.
503 ///
504 /// @return the functions used by the DWARF Front End library of
505 const Dwfl_Callbacks&
dwfl_offline_callbacks() const506 reader::dwfl_offline_callbacks() const
507 {return priv_->offline_callbacks;}
508 
509 /// Getter of the functions used by the DWARF Front End library of
510 /// elfutils to locate DWARF debug information.
511 ///
512 /// @return the functions used by the DWARF Front End library of
513 Dwfl_Callbacks&
dwfl_offline_callbacks()514 reader::dwfl_offline_callbacks()
515 {return priv_->offline_callbacks;}
516 
517 /// Getter of the handle used to access ELF information from the
518 /// current ELF file.
519 ///
520 /// @return the handle used to access ELF information from the current
521 /// ELF file.
522 Elf*
elf_handle() const523 reader::elf_handle() const
524 {return priv_->elf_handle;}
525 
526 /// Getter of the handle used to access DWARF information from the
527 /// current ELF file.
528 ///
529 /// @return the handle used to access DWARF information from the
530 /// current ELF file.
531 const Dwarf*
dwarf_debug_info() const532 reader::dwarf_debug_info() const
533 {return priv_->dwarf_handle;}
534 
535 /// Test if the binary has DWARF debug info.
536 ///
537 /// @return true iff the binary has DWARF debug info.
538 bool
has_dwarf_debug_info() const539 reader::has_dwarf_debug_info() const
540 {return ((priv_->dwarf_handle != nullptr)
541 	  || (priv_->alt_dwarf_handle != nullptr));}
542 
543 /// Test if the binary has CTF debug info.
544 ///
545 /// @return true iff the binary has CTF debug info.
546 bool
has_ctf_debug_info() const547 reader::has_ctf_debug_info() const
548 {return (priv_->ctf_section != nullptr);}
549 
550 /// Getter of the handle use to access DWARF information from the
551 /// alternate split DWARF information.
552 ///
553 /// In other words, this accesses the factorized DWARF information
554 /// that has been constructed by the DWZ tool to de-duplicate DWARF
555 /// information on disk.
556 ///
557 /// @return the handle use to access DWARF information from the
558 /// alternate split DWARF information.
559 const Dwarf*
alternate_dwarf_debug_info() const560 reader::alternate_dwarf_debug_info() const
561 {return priv_->alt_dwarf_handle;}
562 
563 
564 /// Getter of the path to the alternate split DWARF information file,
565 /// on disk.  In othe words, this returns the path to the factorized
566 /// DWARF information used by the current ELF file, created by the
567 /// 'DWZ' tool.
568 ///
569 /// @return the path to the alternate split DWARF information file,
570 /// on disk.
571 const string&
alternate_dwarf_debug_info_path() const572 reader::alternate_dwarf_debug_info_path() const
573 {return priv_->alt_dwarf_path;}
574 
575 /// Check if the underlying elf file refers to an alternate debug info
576 /// file associated to it.
577 ///
578 /// Note that "alternate debug info sections" is a GNU extension as
579 /// of DWARF4 and is described at
580 /// http://www.dwarfstd.org/ShowIssue.php?issue=120604.1.
581 ///
582 /// @param alt_di the path to the alternate debug info file.  This is
583 /// set iff the function returns true.
584 ///
585 /// @return true if the ELF file refers to an alternate debug info
586 /// file.
587 bool
refers_to_alt_debug_info(string & alt_di_path) const588 reader::refers_to_alt_debug_info(string& alt_di_path) const
589 {
590   if (!alternate_dwarf_debug_info_path().empty())
591     {
592       alt_di_path = alternate_dwarf_debug_info_path();
593       return true;
594     }
595   return false;
596 }
597 
598 /// Find and return a pointer to the ELF symbol table
599 /// section.
600 ///
601 /// @return a pointer to the ELF symbol table section.
602 const Elf_Scn*
find_symbol_table_section() const603 reader::find_symbol_table_section() const
604 {
605   if (!priv_->symtab_section)
606       priv_->symtab_section =
607 	elf_helpers::find_symbol_table_section(elf_handle());
608     return priv_->symtab_section;
609 }
610 
611 /// Clear the pointer to the ELF symbol table section.
612 void
reset_symbol_table_section()613 reader::reset_symbol_table_section()
614 {priv_->symtab_section = nullptr;}
615 
616 /// Find and return a pointer to the the CTF section.
617 ///
618 /// @return a pointer to the the CTF section.
619 const Elf_Scn*
find_ctf_section() const620 reader::find_ctf_section() const
621 {
622   if (priv_->ctf_section == nullptr)
623     priv_->locate_ctf_debug_info();
624 
625   if (priv_->ctf_section)
626     return priv_->ctf_section;
627 
628   return priv_->alt_ctf_section;
629 }
630 
631 /// Find and return a pointer to the alternate CTF section of the
632 /// current ELF file.
633 ///
634 /// @return a pointer to the alternate CTF section of the current ELF
635 /// file.
636 const Elf_Scn*
find_alternate_ctf_section() const637 reader::find_alternate_ctf_section() const
638 {
639   if (priv_->alt_ctf_section == nullptr)
640     priv_->locate_alt_ctf_debug_info();
641 
642   return priv_->alt_ctf_section;
643 }
644 
645 /// Get the value of the DT_NEEDED property of the current ELF file.
646 ///
647 /// @return the value of the DT_NEEDED property.
648 const vector<string>&
dt_needed() const649 reader::dt_needed()const
650 {return priv_->dt_needed;}
651 
652 
653 /// Get the value of the 'ARCHITECTURE' property of the current ELF file.
654 ///
655 /// @return the value of the 'ARCHITECTURE' property of the current
656 /// ELF file.
657 const string&
elf_architecture() const658 reader::elf_architecture() const
659 {return priv_->elf_architecture;}
660 
661 /// Getter of an abstract representation of the symbol table of the
662 /// underlying ELF file.
663 ///
664 /// Note that the symbol table is loaded lazily, upon the first
665 /// invocation of this member function.
666 ///
667 /// @returnt the symbol table.
668 symtab_reader::symtab_sptr&
symtab() const669 reader::symtab() const
670 {
671   ABG_ASSERT(elf_handle());
672 
673   if (!priv_->symt)
674     priv_->symt = symtab_reader::symtab::load
675       (elf_handle(), options().env,
676        [&](const elf_symbol_sptr& symbol)
677        {return suppr::is_elf_symbol_suppressed(*this, symbol);});
678 
679   if (!priv_->symt)
680     std::cerr << "Symbol table of '" << corpus_path()
681 	      << "' could not be loaded\n";
682   return priv_->symt;
683 }
684 
685 /// Test if a given function symbol has been exported.
686 ///
687 /// @param symbol_address the address of the symbol we are looking
688 /// for.  Note that this address must be a relative offset from the
689 /// beginning of the .text section, just like the kind of addresses
690 /// that are present in the .symtab section.
691 ///
692 /// @return the elf symbol if found, or nil otherwise.
693 elf_symbol_sptr
function_symbol_is_exported(GElf_Addr symbol_address) const694 reader::function_symbol_is_exported(GElf_Addr symbol_address) const
695 {
696   elf_symbol_sptr symbol = symtab()->lookup_symbol(symbol_address);
697   if (!symbol)
698     return symbol;
699 
700   if (!symbol->is_function() || !symbol->is_public())
701     return elf_symbol_sptr();
702 
703   address_set_sptr set;
704   bool looking_at_linux_kernel_binary =
705     load_in_linux_kernel_mode() && elf_helpers::is_linux_kernel(elf_handle());
706 
707   if (looking_at_linux_kernel_binary)
708     {
709 	if (symbol->is_in_ksymtab())
710 	  return symbol;
711 	return elf_symbol_sptr();
712     }
713 
714   return symbol;
715 }
716 
717 /// Test if a given variable symbol has been exported.
718 ///
719 /// @param symbol_address the address of the symbol we are looking
720 /// for.  Note that this address must be a relative offset from the
721 /// beginning of the .text section, just like the kind of addresses
722 /// that are present in the .symtab section.
723 ///
724 /// @return the elf symbol if found, or nil otherwise.
725 elf_symbol_sptr
variable_symbol_is_exported(GElf_Addr symbol_address) const726 reader::variable_symbol_is_exported(GElf_Addr symbol_address) const
727 {
728   elf_symbol_sptr symbol = symtab()->lookup_symbol(symbol_address);
729   if (!symbol)
730     return symbol;
731 
732   if (!symbol->is_variable() || !symbol->is_public())
733     return elf_symbol_sptr();
734 
735   address_set_sptr set;
736   bool looking_at_linux_kernel_binary =
737     load_in_linux_kernel_mode() && elf_helpers::is_linux_kernel(elf_handle());
738 
739   if (looking_at_linux_kernel_binary)
740     {
741 	if (symbol->is_in_ksymtab())
742 	  return symbol;
743 	return elf_symbol_sptr();
744     }
745 
746   return symbol;
747 }
748 
749 /// Test if a given function symbol has been exported.
750 ///
751 /// @param name the name of the symbol we are looking for.
752 ///
753 /// @return the elf symbol if found, or nil otherwise.
754 elf_symbol_sptr
function_symbol_is_exported(const string & name) const755 reader::function_symbol_is_exported(const string& name) const
756 {
757   const elf_symbols& syms = symtab()->lookup_symbol(name);
758   for (auto s : syms)
759     {
760       if (s->is_function() && s->is_public())
761 	{
762 	  bool looking_at_linux_kernel_binary =
763 	    (load_in_linux_kernel_mode()
764 	     && elf_helpers::is_linux_kernel(elf_handle()));
765 
766 	  if (looking_at_linux_kernel_binary)
767 	    {
768 	      if (s->is_in_ksymtab())
769 		return s;
770 	    }
771 	  else
772 	    return s;
773 	}
774     }
775   return elf_symbol_sptr();
776 }
777 
778 /// Test if a given variable symbol has been exported.
779 ///
780 /// @param name the name of the symbol we are looking
781 /// for.
782 ///
783 /// @return the elf symbol if found, or nil otherwise.
784 elf_symbol_sptr
variable_symbol_is_exported(const string & name) const785 reader::variable_symbol_is_exported(const string& name) const
786 {
787   const elf_symbols& syms = symtab()->lookup_symbol(name);
788   for (auto s : syms)
789     {
790       if (s->is_variable() && s->is_public())
791 	{
792 	  bool looking_at_linux_kernel_binary =
793 	    (load_in_linux_kernel_mode()
794 	     && elf_helpers::is_linux_kernel(elf_handle()));
795 
796 	  if (looking_at_linux_kernel_binary)
797 	    {
798 	      if (s->is_in_ksymtab())
799 		return s;
800 	    }
801 	  else
802 	    return s;
803 	}
804     }
805   return elf_symbol_sptr();
806 }
807 /// Load the DT_NEEDED and DT_SONAME elf TAGS.
808 void
load_dt_soname_and_needed()809 reader::load_dt_soname_and_needed()
810 {
811   elf_helpers::lookup_data_tag_from_dynamic_segment(elf_handle(),
812 						    DT_NEEDED,
813 						    priv_->dt_needed);
814 
815   vector<string> dt_tag_data;
816   elf_helpers::lookup_data_tag_from_dynamic_segment(elf_handle(),
817 						    DT_SONAME,
818 						    dt_tag_data);
819   if (!dt_tag_data.empty())
820     dt_soname(dt_tag_data[0]);
821 }
822 
823 /// Read the string representing the architecture of the current ELF
824 /// file.
825 void
load_elf_architecture()826 reader::load_elf_architecture()
827 {
828   if (!elf_handle())
829     return;
830 
831   GElf_Ehdr eh_mem;
832   GElf_Ehdr* elf_header = gelf_getehdr(elf_handle(), &eh_mem);
833 
834   priv_->elf_architecture =
835     elf_helpers::e_machine_to_string(elf_header->e_machine);
836 }
837 
838 /// Load various ELF data.
839 ///
840 /// This function loads ELF data that are not symbol maps or debug
841 /// info.  That is, things like various tags, elf architecture and
842 /// so on.
843 void
load_elf_properties()844 reader::load_elf_properties()
845 {
846   // Note that we don't load the symbol table as it's loaded lazily,
847   // on demand.
848 
849   load_dt_soname_and_needed();
850   load_elf_architecture();
851 }
852 
853 /// Read the ELF information associated to the current ELF file and
854 /// construct an ABI representation from it.
855 ///
856 /// Note that this reader doesn't know how to interpret any debug
857 /// information so the resulting ABI corpus won't have any type
858 /// information.  Rather, it will only have ELF symbol representation.
859 ///
860 /// To have type information, consider using readers that know how to
861 /// interpret the symbolic type information comprised in DWARF, CTF or
862 /// other symbolic debug information format, like the @ref or
863 /// abigail::dwarf_reader::reader, @ref abigail::ctf_reader::reader
864 /// readers.
865 ///
866 /// @return the resulting ABI corpus.
867 ir::corpus_sptr
read_corpus(status & status)868 reader::read_corpus(status& status)
869 {
870   status = STATUS_UNKNOWN;
871 
872   corpus::origin origin = corpus()->get_origin();
873   origin |= corpus::ELF_ORIGIN;
874   if (is_linux_kernel(elf_handle()))
875     origin |= corpus::LINUX_KERNEL_BINARY_ORIGIN;
876   corpus()->set_origin(origin);
877 
878   load_elf_properties(); // DT_SONAME, DT_NEEDED, architecture
879   corpus()->set_soname(dt_soname());
880   corpus()->set_needed(dt_needed());
881   corpus()->set_architecture_name(elf_architecture());
882 
883   // See if we could find symbol tables.
884   if (!symtab() || !symtab()->has_symbols())
885     {
886       status |= STATUS_NO_SYMBOLS_FOUND;
887       // We found no ELF symbol, so we can't handle the binary.
888       return corpus_sptr();
889     }
890 
891   // Set symbols information to the corpus.
892   corpus()->set_symtab(symtab());
893 
894   // If we couldn't load debug info from the elf path, then say it.
895   if ((origin & abigail::ir::corpus::DWARF_ORIGIN)
896         && !has_dwarf_debug_info())
897     status |= STATUS_DEBUG_INFO_NOT_FOUND;
898   else if ((origin & abigail::ir::corpus::CTF_ORIGIN)
899              && !has_ctf_debug_info())
900     status |= STATUS_DEBUG_INFO_NOT_FOUND;
901 
902   status |= STATUS_OK;
903   return corpus();
904 }
905 
906 /// Get the SONAME property of a designated ELF file.
907 ///
908 /// @param path the path to the ELF file to consider.
909 ///
910 /// @param soname output parameter.  This is set to the SONAME of the
911 /// file located at @p path, iff this function return true.
912 ///
913 /// @return true iff the SONAME property was found in the ELF file
914 /// located at @p path and set into the argument of the parameter @p
915 /// soname.
916 bool
get_soname_of_elf_file(const string & path,string & soname)917 get_soname_of_elf_file(const string& path, string &soname)
918 {return elf_helpers::get_soname_of_elf_file(path, soname);}
919 
920 /// Convert the type of ELF file into @ref elf_type.
921 ///
922 /// @param elf the elf handle to use for the query.
923 ///
924 /// @return the @ref elf_type for a given elf type.
925 static elf::elf_type
elf_file_type(Elf * elf)926 elf_file_type(Elf* elf)
927 {
928   GElf_Ehdr ehdr_mem;
929   GElf_Ehdr *header = gelf_getehdr (elf, &ehdr_mem);
930   vector<string> dt_debug_data;
931 
932   switch (header->e_type)
933     {
934     case ET_DYN:
935       if (lookup_data_tag_from_dynamic_segment(elf, DT_DEBUG, dt_debug_data))
936 	return elf::ELF_TYPE_PI_EXEC;
937       else
938 	return elf::ELF_TYPE_DSO;
939     case ET_EXEC:
940       return elf::ELF_TYPE_EXEC;
941     case ET_REL:
942       return elf::ELF_TYPE_RELOCATABLE;
943     default:
944       return elf::ELF_TYPE_UNKNOWN;
945     }
946 }
947 
948 /// Get the type of a given elf type.
949 ///
950 /// @param path the absolute path to the ELF file to analyzed.
951 ///
952 /// @param type the kind of the ELF file designated by @p path.
953 ///
954 /// @param out parameter.  Is set to the type of ELF file of @p path.
955 /// This parameter is set iff the function returns true.
956 ///
957 /// @return true iff the file could be opened and analyzed.
958 bool
get_type_of_elf_file(const string & path,elf::elf_type & type)959 get_type_of_elf_file(const string& path, elf::elf_type& type)
960 {
961   int fd = open(path.c_str(), O_RDONLY);
962   if (fd == -1)
963     return false;
964 
965   elf_version (EV_CURRENT);
966   Elf *elf = elf_begin (fd, ELF_C_READ_MMAP, NULL);
967   type = elf_file_type(elf);
968   elf_end(elf);
969   close(fd);
970 
971   return true;
972 }
973 
974 }// end namespace elf
975 } // end namespace abigail
976