libabigail
abg-elf-reader.cc
Go to the documentation of this file.
1// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
2// -*- Mode: C++ -*-
3//
4// Copyright (C) 2022-2025 Red Hat, Inc.
5//
6// Author: Dodji Seketeli
7
8/// @file
9///
10/// Elf reader stuff
11
12#include "abg-internal.h"
13
14#include <fcntl.h> /* For open(3) */
15#include <unistd.h>
16#include <iostream>
17#include <cstring>
18#include <libgen.h>
19#include <fcntl.h>
20#include <elfutils/libdwfl.h>
21
22
23#include "abg-symtab-reader.h"
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 = 0;
141 Elf_Scn* ctf_section = nullptr;
142 int alt_ctf_fd = 0;
143 Elf* alt_ctf_handle = nullptr;
144 Elf_Scn* alt_ctf_section = nullptr;
145 Elf_Scn* btf_section = nullptr;
146
147 priv(reader& reeder, const std::string& elf_path,
148 const vector<string>& debug_info_roots)
149 : rdr(reeder)
150 {
151 rdr.corpus_path(elf_path);
152 initialize(debug_info_roots);
153 }
154
155 ~priv()
156 {
157 clear_alt_dwarf_debug_info_data();
158 clear_alt_ctf_debug_info_data();
159 }
160
161 /// Reset the private data of @elf elf::reader.
162 ///
163 /// @param debug_info_roots the vector of new directories where to
164 /// look for split debug info file.
165 void
166 initialize(const vector<string>& debug_info_roots)
167 {
168 clear_alt_dwarf_debug_info_data();
169 clear_alt_ctf_debug_info_data();
170
171 elf_handle = nullptr;
172 symtab_section = nullptr;
173 elf_architecture.clear();
174 dt_needed.clear();
175 symt.reset();
176 debug_info_root_paths = debug_info_roots;
177 formated_di_root_paths.clear();
178 raw_formated_di_root_paths = nullptr;
179 memset(&offline_callbacks, 0, sizeof(offline_callbacks));
180 dwfl_handle.reset();
181 elf_module = nullptr;
182 dwarf_handle = nullptr;
183 alt_dwarf_handle = nullptr;
184 alt_dwarf_path.clear();
185 alt_dwarf_fd = 0;
186 ctf_section = nullptr;
187 alt_ctf_section = nullptr;
188 alt_ctf_handle = nullptr;
189 alt_ctf_fd = 0;
190 }
191
192 /// Initialize the debug info root path. The format of this path is
193 /// described in /usr/include/elfutils/libdwfl.h in the comment for
194 /// the function dwfl_build_id_find_elf.
195 ///
196 /// The string must start with '-' to disable CRC32 checksum
197 /// validation. Directories must be separated by the ':' character.
198 /// The search order depends on if each path is absolute or relative
199 /// as described by that comment.
200 ///
201 /// In any case, let's format the debuginfo search path here for
202 /// elfutils consumption.
203 void
204 initialize_debug_info_root_paths()
205 {
206 vector<string> root_paths = debug_info_root_paths;
207
208 for (auto path : debug_info_root_paths)
209 if (tools_utils::string_begins_with(path, "/"))
210 {
211 // For absolute root directories, let's add all the
212 // sub-directories of these directories that contain a
213 // (debug info) file. This can be helpful to help elfutils
214 // find alternate debuginfo files when the altdebuginfolink
215 // is itself an absolute file path that is contained under
216 // the root directory. This what we see in PR30329 and its
217 // associated regression test in test-abidiff-exit.cc
218 vector<string> additional_subdirs;
219 tools_utils::get_file_path_dirs_under_dir(path, additional_subdirs);
220 for (auto& subdir : additional_subdirs)
221 root_paths.push_back(subdir);
222 }
223
224 for (auto path : root_paths)
225 {
226 if (formated_di_root_paths.empty())
227 formated_di_root_paths = "-";
228 if (!path.empty())
229 formated_di_root_paths += path + ":";
230 }
231 raw_formated_di_root_paths =
232 const_cast<char*>(formated_di_root_paths.c_str());
233 }
234
235 /// Setup the necessary plumbing to open the ELF file and find all
236 /// the associated split debug info files.
237 ///
238 /// This function also setup the various handles on the opened ELF
239 /// file and whatnot.
240 void
241 crack_open_elf_file()
242 {
243 // Initialize the callback functions used by elfutils.
244 initialize_debug_info_root_paths();
245 elf_helpers::initialize_dwfl_callbacks(offline_callbacks,
246 formated_di_root_paths.empty()
247 ? nullptr
248 : &raw_formated_di_root_paths);
249
250 // Create a handle to the DWARF Front End Library that we'll need.
251 dwfl_handle = elf_helpers::create_new_dwfl_handle(offline_callbacks);
252
253 const string& elf_path = rdr.corpus_path();
254 // Get the set of addresses that make up the ELF file we are
255 // looking at.
256 elf_module =
257 dwfl_report_offline(dwfl_handle.get(),
258 basename(const_cast<char*>(elf_path.c_str())),
259 elf_path.c_str(), -1);
260 dwfl_report_end(dwfl_handle.get(), 0, 0);
261 ABG_ASSERT(elf_module);
262
263 // Finally, get and handle at the representation of the ELF file
264 // we've just cracked open.
265 GElf_Addr bias = 0;
266 elf_handle = dwfl_module_getelf(elf_module, &bias);
268 }
269
270 /// Clear the resources related to the alternate DWARF data.
271 void
272 clear_alt_dwarf_debug_info_data()
273 {
274 if (alt_dwarf_fd)
275 {
276 if (alt_dwarf_handle)
277 {
278 dwarf_end(alt_dwarf_handle);
279 alt_dwarf_handle = nullptr;
280 }
281 close(alt_dwarf_fd);
282 alt_dwarf_fd = 0;
283 }
284 alt_dwarf_path.clear();
285 }
286
287 /// Locate the DWARF debug info in the ELF file.
288 ///
289 /// This also knows how to locate split debug info.
290 void
291 locate_dwarf_debug_info()
292 {
293 ABG_ASSERT(dwfl_handle);
294
295 if (dwarf_handle)
296 return;
297
298 Dwarf_Addr bias = 0;
299 dwarf_handle = dwfl_module_getdwarf(elf_module, &bias);
300 alt_dwarf_handle = dwarf_getalt(dwarf_handle);
301 find_alt_dwarf_debug_info_link(elf_module, alt_dwarf_path);
302 }
303
304 /// Clear the resources related to the alternate CTF data.
305 void
306 clear_alt_ctf_debug_info_data()
307 {
308 if (alt_ctf_fd)
309 {
310 close(alt_ctf_fd);
311 alt_ctf_fd = 0;
312 }
313 if (alt_ctf_handle)
314 {
315 elf_end(alt_ctf_handle);
316 alt_ctf_handle = nullptr;
317 }
318 }
319
320 /// Locate the CTF "alternate" debug information associated with the
321 /// current ELF file ( and split out somewhere else).
322 ///
323 /// This is a sub-routine of @ref locate_ctf_debug_info().
324 void
325 locate_alt_ctf_debug_info()
326 {
327 if (alt_ctf_section)
328 return;
329
330 Elf_Scn *section =
331 elf_helpers::find_section(elf_handle,
332 ".gnu_debuglink",
333 SHT_PROGBITS);
334
335 std::string name;
336 Elf_Data *data;
337 if (section
338 && (data = elf_getdata(section, nullptr))
339 && data->d_size != 0)
340 name = (char *) data->d_buf;
341
342 if (!name.empty())
343 for (const auto& path : rdr.debug_info_root_paths())
344 {
345 std::string file_path;
346 if (!tools_utils::find_file_under_dir(path, name, file_path))
347 continue;
348
349 if ((alt_ctf_fd = open(file_path.c_str(), O_RDONLY)) == -1)
350 continue;
351
352 if ((alt_ctf_handle = elf_begin(alt_ctf_fd,
353 ELF_C_READ,
354 nullptr)) == nullptr)
355 continue;
356
357 // unlikely .ctf was designed to be present in stripped file
358 alt_ctf_section =
359 elf_helpers::find_section(alt_ctf_handle, ".ctf", SHT_PROGBITS);
360
361 if (alt_ctf_section)
362 break;
363 }
364 }
365
366 /// Locate the CTF debug information associated with the current ELF
367 /// file. It also locates the CTF debug information that is split
368 /// out in a separate file.
369 void
370 locate_ctf_debug_info()
371 {
373
374 ctf_section = elf_helpers::find_section_by_name(elf_handle, ".ctf");
375 if (ctf_section == nullptr)
376 {
377 locate_alt_ctf_debug_info();
378 ctf_section = alt_ctf_section;
379 }
380 }
381}; //end reader::priv
382
383/// The constructor of the @ref elf::reader type.
384///
385/// @param elf_path the path to the ELF file to read from.
386///
387/// @param debug_info_root a vector of directory paths to look into
388/// for split debug information files.
389///
390/// @param env the environment which the reader operates in.
391reader::reader(const string& elf_path,
392 const vector<string>& debug_info_roots,
393 ir::environment& env)
394 : fe_iface(elf_path, env),
395 priv_(new priv(*this, elf_path, debug_info_roots))
396{
397 priv_->crack_open_elf_file();
398 priv_->locate_dwarf_debug_info();
399 priv_->locate_ctf_debug_info();
400}
401
402/// The destructor of the @ref elf::reader type.
404{delete priv_;}
405
406/// Re-initialize the resources used by the current @ref elf::reader
407/// type.
408///
409/// This lets the reader in a state where it's ready to read from
410/// another ELF file.
411///
412/// @param elf_path the new ELF path to read from.
413///
414/// @param debug_info_roots a vector of directory paths to look into
415/// for split debug information files.
416void
417reader::initialize(const std::string& elf_path,
418 const vector<string>& debug_info_roots)
419{
420 fe_iface::initialize(elf_path);
421 corpus_path(elf_path);
422 priv_->initialize(debug_info_roots);
423 priv_->crack_open_elf_file();
424 priv_->locate_dwarf_debug_info();
425 priv_->locate_ctf_debug_info();
426}
427
428/// Re-initialize the resources used by the current @ref elf::reader
429/// type.
430///
431/// This lets the reader in a state where it's ready to read from
432/// another ELF file.
433///
434/// @param elf_path the new ELF path to read from.
435void
436reader::initialize(const std::string& elf_path)
437{
438 vector<string> v;
439 initialize(elf_path, v);
440}
441
442/// Getter of the vector of directory paths to look into for split
443/// debug information files.
444///
445/// @return the vector of directory paths to look into for split
446/// debug information files.
447const vector<string>&
449{return priv_->debug_info_root_paths;}
450
451/// Getter of the functions used by the DWARF Front End library of
452/// elfutils to locate DWARF debug information.
453///
454/// @return the functions used by the DWARF Front End library of
455const Dwfl_Callbacks&
457{return priv_->offline_callbacks;}
458
459/// Getter of the functions used by the DWARF Front End library of
460/// elfutils to locate DWARF debug information.
461///
462/// @return the functions used by the DWARF Front End library of
463Dwfl_Callbacks&
465{return priv_->offline_callbacks;}
466
467/// Getter of the handle used to access ELF information from the
468/// current ELF file.
469///
470/// @return the handle used to access ELF information from the current
471/// ELF file.
472Elf*
474{return priv_->elf_handle;}
475
476/// Getter of the handle used to access DWARF information from the
477/// current ELF file.
478///
479/// @return the handle used to access DWARF information from the
480/// current ELF file.
481const Dwarf*
483{return priv_->dwarf_handle;}
484
485/// Test if the binary has DWARF debug info.
486///
487/// @return true iff the binary has DWARF debug info.
488bool
490{return ((priv_->dwarf_handle != nullptr)
491 || (priv_->alt_dwarf_handle != nullptr));}
492
493/// Test if the binary has CTF debug info.
494///
495/// @return true iff the binary has CTF debug info.
496bool
498{return (priv_->ctf_section != nullptr);}
499
500/// Test if the binary has BTF debug info.
501///
502/// @return true iff the binary has BTF debug info
503bool
505{return (priv_->btf_section != nullptr);}
506
507/// Getter of the handle use to access DWARF information from the
508/// alternate split DWARF information.
509///
510/// In other words, this accesses the factorized DWARF information
511/// that has been constructed by the DWZ tool to de-duplicate DWARF
512/// information on disk.
513///
514/// @return the handle use to access DWARF information from the
515/// alternate split DWARF information.
516const Dwarf*
518{return priv_->alt_dwarf_handle;}
519
520
521/// Getter of the path to the alternate split DWARF information file,
522/// on disk. In othe words, this returns the path to the factorized
523/// DWARF information used by the current ELF file, created by the
524/// 'DWZ' tool.
525///
526/// @return the path to the alternate split DWARF information file,
527/// on disk.
528const string&
530{return priv_->alt_dwarf_path;}
531
532/// Check if the underlying elf file refers to an alternate debug info
533/// file associated to it.
534///
535/// Note that "alternate debug info sections" is a GNU extension as
536/// of DWARF4 and is described at
537/// http://www.dwarfstd.org/ShowIssue.php?issue=120604.1.
538///
539/// @param alt_di the path to the alternate debug info file. This is
540/// set iff the function returns true.
541///
542/// @return true if the ELF file refers to an alternate debug info
543/// file.
544bool
545reader::refers_to_alt_debug_info(string& alt_di_path) const
546{
547 if (!alternate_dwarf_debug_info_path().empty())
548 {
549 alt_di_path = alternate_dwarf_debug_info_path();
550 return true;
551 }
552 return false;
553}
554
555/// Find and return a pointer to the ELF symbol table
556/// section.
557///
558/// @return a pointer to the ELF symbol table section.
559const Elf_Scn*
561{
562 if (!priv_->symtab_section)
563 priv_->symtab_section =
564 elf_helpers::find_symbol_table_section(elf_handle());
565 return priv_->symtab_section;
566}
567
568/// Clear the pointer to the ELF symbol table section.
569void
571{priv_->symtab_section = nullptr;}
572
573/// Find and return a pointer to the the CTF section.
574///
575/// @return a pointer to the the CTF section.
576const Elf_Scn*
578{
579 if (priv_->ctf_section == nullptr)
580 priv_->locate_ctf_debug_info();
581
582 if (priv_->ctf_section)
583 return priv_->ctf_section;
584
585 return priv_->alt_ctf_section;
586}
587
588/// Find and return a pointer to the alternate CTF section of the
589/// current ELF file.
590///
591/// @return a pointer to the alternate CTF section of the current ELF
592/// file.
593const Elf_Scn*
595{
596 if (priv_->alt_ctf_section == nullptr)
597 priv_->locate_alt_ctf_debug_info();
598
599 return priv_->alt_ctf_section;
600}
601
602/// Find and return a pointer to the BTF section of the current ELF
603/// file.
604///
605/// @return a pointer to the BTF section of the current ELF file.
606const Elf_Scn*
608{
609 if (priv_->btf_section == nullptr)
610 priv_->btf_section =
611 elf_helpers::find_section(priv_->elf_handle,
612 ".BTF", SHT_PROGBITS);
613 return priv_->btf_section;
614}
615
616/// Get the value of the DT_NEEDED property of the current ELF file.
617///
618/// @return the value of the DT_NEEDED property.
619const vector<string>&
621{return priv_->dt_needed;}
622
623
624/// Get the value of the 'ARCHITECTURE' property of the current ELF file.
625///
626/// @return the value of the 'ARCHITECTURE' property of the current
627/// ELF file.
628const string&
630{return priv_->elf_architecture;}
631
632/// Getter of an abstract representation of the symbol table of the
633/// underlying ELF file.
634///
635/// Note that the symbol table is loaded lazily, upon the first
636/// invocation of this member function.
637///
638/// @returnt the symbol table.
641{
643
644 if (!priv_->symt)
645 priv_->symt = symtab_reader::symtab::load
646 (elf_handle(), options().env,
647 [&](const elf_symbol_sptr& symbol)
648 {return suppr::is_elf_symbol_suppressed(*this, symbol);});
649
650 if (!priv_->symt)
651 std::cerr << "Symbol table of '" << corpus_path()
652 << "' could not be loaded\n";
653 return priv_->symt;
654}
655
656/// Test if a given function symbol has been exported.
657///
658/// @param symbol_address the address of the symbol we are looking
659/// for. Note that this address must be a relative offset from the
660/// beginning of the .text section, just like the kind of addresses
661/// that are present in the .symtab section.
662///
663/// @return the elf symbol if found, or nil otherwise.
665reader::function_symbol_is_exported(GElf_Addr symbol_address) const
666{
667
668 elf_symbol_sptr symbol =
669 symtab()->function_symbol_is_exported(symbol_address);
670 if (!symbol)
671 return symbol;
672
674 bool looking_at_linux_kernel_binary =
675 load_in_linux_kernel_mode() && elf_helpers::is_linux_kernel(elf_handle());
676
677 if (looking_at_linux_kernel_binary)
678 {
679 if (symbol->is_in_ksymtab())
680 return symbol;
681 return elf_symbol_sptr();
682 }
683
684 return symbol;
685}
686
687/// Test if a given variable symbol has been exported.
688///
689/// @param symbol_address the address of the symbol we are looking
690/// for. Note that this address must be a relative offset from the
691/// beginning of the .text section, just like the kind of addresses
692/// that are present in the .symtab section.
693///
694/// @return the elf symbol if found, or nil otherwise.
696reader::variable_symbol_is_exported(GElf_Addr symbol_address) const
697{
698 elf_symbol_sptr symbol =
699 symtab()->variable_symbol_is_exported(symbol_address);
700 if (!symbol)
701 return symbol;
702
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 function symbol has been exported.
718///
719/// @param name the name of the symbol we are looking for.
720///
721/// @return the elf symbol if found, or nil otherwise.
723reader::function_symbol_is_exported(const string& name) const
724{
725 const elf_symbol_sptr s = symtab()->function_symbol_is_exported(name);
726 if (s && s->is_function() && s->is_public())
727 {
728 bool looking_at_linux_kernel_binary =
730 && elf_helpers::is_linux_kernel(elf_handle()));
731
732 if (looking_at_linux_kernel_binary)
733 {
734 if (s->is_in_ksymtab())
735 return s;
736 }
737 else
738 return s;
739 }
740 return elf_symbol_sptr();
741}
742
743/// Test if a given variable symbol has been exported.
744///
745/// @param name the name of the symbol we are looking
746/// for.
747///
748/// @return the elf symbol if found, or nil otherwise.
750reader::variable_symbol_is_exported(const string& name) const
751{
752 const elf_symbol_sptr s = symtab()->variable_symbol_is_exported(name);
753 if (s && s->is_variable() && 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 name is the name of an undefined function symbol.
771///
772/// @param name the symbol name to consider.
773///
774/// @return the undefined function symbol or nil if none was found.
777{return symtab()->function_symbol_is_undefined(name);}
778
779/// Test if a name is the name of an undefined variable symbol.
780///
781/// @param name the symbol name to consider.
782///
783/// @return the undefined variable symbol or nil if none was found.
786{return symtab()->variable_symbol_is_undefined(name);}
787
788/// Load the DT_NEEDED and DT_SONAME elf TAGS.
789void
791{
792 elf_helpers::lookup_data_tag_from_dynamic_segment(elf_handle(),
793 DT_NEEDED,
794 priv_->dt_needed);
795
796 vector<string> dt_tag_data;
797 elf_helpers::lookup_data_tag_from_dynamic_segment(elf_handle(),
798 DT_SONAME,
799 dt_tag_data);
800 if (!dt_tag_data.empty())
801 dt_soname(dt_tag_data[0]);
802}
803
804/// Read the string representing the architecture of the current ELF
805/// file.
806void
808{
809 if (!elf_handle())
810 return;
811
812 GElf_Ehdr eh_mem;
813 GElf_Ehdr* elf_header = gelf_getehdr(elf_handle(), &eh_mem);
814
815 priv_->elf_architecture =
816 elf_helpers::e_machine_to_string(elf_header->e_machine);
817}
818
819/// Load various ELF data.
820///
821/// This function loads ELF data that are not symbol maps or debug
822/// info. That is, things like various tags, elf architecture and
823/// so on.
824void
826{
827 // Note that we don't load the symbol table as it's loaded lazily,
828 // on demand.
829
832}
833
834/// Read the ELF information associated to the current ELF file and
835/// construct an ABI representation from it.
836///
837/// Note that this reader doesn't know how to interpret any debug
838/// information so the resulting ABI corpus won't have any type
839/// information. Rather, it will only have ELF symbol representation.
840///
841/// To have type information, consider using readers that know how to
842/// interpret the symbolic type information comprised in DWARF, CTF or
843/// other symbolic debug information format, like the @ref or
844/// abigail::dwarf_reader::reader, @ref abigail::ctf_reader::reader
845/// readers.
846///
847/// @return the resulting ABI corpus.
848ir::corpus_sptr
850{
852
853 corpus::origin origin = corpus()->get_origin();
854 origin |= corpus::ELF_ORIGIN;
856 origin |= corpus::LINUX_KERNEL_BINARY_ORIGIN;
857 corpus()->set_origin(origin);
858
859 load_elf_properties(); // DT_SONAME, DT_NEEDED, architecture
860 corpus()->set_soname(dt_soname());
861 corpus()->set_needed(dt_needed());
862 corpus()->set_architecture_name(elf_architecture());
863
864 // See if we could find symbol tables.
865 if (!symtab())
866 {
868 // We found no ELF symbol, so we can't handle the binary. Note
869 // that we could have found a symbol table with no defined &
870 // exported ELF symbols in it. Both cases are handled as an
871 // empty corpus.
872 return corpus();
873 }
874
875 // Set symbols information to the corpus.
876 corpus()->set_symtab(symtab());
877
878 // If we couldn't load debug info from the elf path, then say it.
879 if ((origin & abigail::ir::corpus::DWARF_ORIGIN)
882 else if ((origin & abigail::ir::corpus::CTF_ORIGIN)
883 && !has_ctf_debug_info())
885
886 status |= STATUS_OK;
887 return corpus();
888}
889
890/// Get the SONAME property of a designated ELF file.
891///
892/// @param path the path to the ELF file to consider.
893///
894/// @param soname output parameter. This is set to the SONAME of the
895/// file located at @p path, iff this function return true.
896///
897/// @return true iff the SONAME property was found in the ELF file
898/// located at @p path and set into the argument of the parameter @p
899/// soname.
900bool
901get_soname_of_elf_file(const string& path, string &soname)
902{return elf_helpers::get_soname_of_elf_file(path, soname);}
903
904/// Convert the type of ELF file into @ref elf_type.
905///
906/// @param elf the elf handle to use for the query.
907///
908/// @return the @ref elf_type for a given elf type.
909static elf::elf_type
910elf_file_type(Elf* elf)
911{
912 GElf_Ehdr ehdr_mem;
913 GElf_Ehdr *header = gelf_getehdr (elf, &ehdr_mem);
914 vector<string> dt_debug_data;
915
916 switch (header->e_type)
917 {
918 case ET_DYN:
919 if (lookup_data_tag_from_dynamic_segment(elf, DT_DEBUG, dt_debug_data))
921 else
922 return elf::ELF_TYPE_DSO;
923 case ET_EXEC:
924 return elf::ELF_TYPE_EXEC;
925 case ET_REL:
927 default:
929 }
930}
931
932/// Get the type of a given elf type.
933///
934/// @param path the absolute path to the ELF file to analyzed.
935///
936/// @param type the kind of the ELF file designated by @p path.
937///
938/// @param out parameter. Is set to the type of ELF file of @p path.
939/// This parameter is set iff the function returns true.
940///
941/// @return true iff the file could be opened and analyzed.
942bool
943get_type_of_elf_file(const string& path, elf::elf_type& type)
944{
945 int fd = open(path.c_str(), O_RDONLY);
946 if (fd == -1)
947 return false;
948
949 elf_version (EV_CURRENT);
950 // Note that the dwelf_elf_begin function supports decompressing the
951 // content of the input file, which is pretty cool.
952 Elf *elf = dwelf_elf_begin(fd);
953 type = elf_file_type(elf);
954 elf_end(elf);
955 close(fd);
956
957 return true;
958}
959
960}// end namespace elf
961} // 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.
Definition: abg-fe-iface.h:29
status
The status of the fe_iface::read_corpus call.
Definition: abg-fe-iface.h:38
@ STATUS_NO_SYMBOLS_FOUND
This status is for when the symbols of the ELF binaries could not be read.
Definition: abg-fe-iface.h:54
@ STATUS_DEBUG_INFO_NOT_FOUND
This status is for when the debug info could not be read.
Definition: abg-fe-iface.h:46
@ STATUS_OK
This status is for when the call went OK.
Definition: abg-fe-iface.h:43
@ STATUS_UNKNOWN
The status is in an unknown state.
Definition: abg-fe-iface.h:40
const options_type & options() const
Getter of the the options of the current Front End Interface.
Definition: abg-fe-iface.cc:91
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.
Definition: abg-fe-iface.cc:81
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.