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