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/// 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,
337 debug_info_root_paths.empty()
338 ? nullptr
339 : debug_info_root_paths.front());
340
341 // Create a handle to the DWARF Front End Library that we'll need.
342 dwfl_handle = elf_helpers::create_new_dwfl_handle(offline_callbacks);
343
344 const string& elf_path = rdr.corpus_path();
345 // Get the set of addresses that make up the ELF file we are
346 // looking at.
347 elf_module =
348 dwfl_report_offline(dwfl_handle.get(),
349 basename(const_cast<char*>(elf_path.c_str())),
350 elf_path.c_str(), -1);
351 dwfl_report_end(dwfl_handle.get(), 0, 0);
352 ABG_ASSERT(elf_module);
353
354 // Finally, get and handle at the representation of the ELF file
355 // we've just cracked open.
356 GElf_Addr bias = 0;
357 elf_handle = dwfl_module_getelf(elf_module, &bias);
358 ABG_ASSERT(elf_handle);
359 }
360
361 /// Find the alternate debuginfo file associated to a given elf file.
362 ///
363 /// @param elf_module represents the elf file to consider.
364 ///
365 /// @param alt_file_name the resulting path to the alternate
366 /// debuginfo file found. This is set iff the function returns a
367 /// non-nil value.
368 Dwarf*
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,
375 debug_info_root_paths,
376 alt_file_name, alt_fd);
377 return result;
378 }
379
380 /// Clear the resources related to the alternate DWARF data.
381 void
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 {
496 ABG_ASSERT(elf_handle);
497
498 ctf_section = elf_helpers::find_section_by_name(elf_handle, ".ctf");
499 if (ctf_section == nullptr)
500 {
501 locate_alt_ctf_debug_info();
502 ctf_section = alt_ctf_section;
503 }
504 }
505}; //end reader::priv
506
507/// The constructor of the @ref elf::reader type.
508///
509/// @param elf_path the path to the ELF file to read from.
510///
511/// @param debug_info_root a vector of directory paths to look into
512/// for split debug information files.
513///
514/// @param env the environment which the reader operates in.
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{
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 =
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 =
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 =
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 =
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 =
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{
917 DT_NEEDED,
918 priv_->dt_needed);
919
920 vector<string> dt_tag_data;
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
Elf_Scn * find_section_by_name(Elf *elf_handle, const std::string &name)
Find and return a section by its name.
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 get_soname_of_elf_file(const string &path, string &soname)
Fetch the SONAME ELF property from an ELF binary file.
std::string e_machine_to_string(GElf_Half e_machine)
Convert the value of the e_machine field of GElf_Ehdr into a string. This is to get a string represen...
Elf_Scn * find_section(Elf *elf_handle, const std::string &name, Elf64_Word section_type)
Find and return a section by its name and its type.
Elf_Scn * find_symbol_table_section(Elf *elf_handle)
Find the symbol table.
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 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 reader type.
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 ...
The namespace for the DWARF reader.
The namespace for the ELF Reader.
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.