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