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