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