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-2023 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 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/// Resets (erase) the resources used by the current @ref
531/// elf::reader 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::reset(const std::string& elf_path,
542 const vector<char**>& debug_info_roots)
543{
545 fe_iface::reset(elf_path, opts.env);
546 corpus_path(elf_path);
547 priv_->initialize(debug_info_roots);
548 priv_->crack_open_elf_file();
549 priv_->locate_dwarf_debug_info();
550 priv_->locate_ctf_debug_info();
551}
552
553/// Getter of the vector of directory paths to look into for split
554/// debug information files.
555///
556/// @return the vector of directory paths to look into for split
557/// debug information files.
558const vector<char**>&
560{return priv_->debug_info_root_paths;}
561
562/// Getter of the functions used by the DWARF Front End library of
563/// elfutils to locate DWARF debug information.
564///
565/// @return the functions used by the DWARF Front End library of
566const Dwfl_Callbacks&
568{return priv_->offline_callbacks;}
569
570/// Getter of the functions used by the DWARF Front End library of
571/// elfutils to locate DWARF debug information.
572///
573/// @return the functions used by the DWARF Front End library of
574Dwfl_Callbacks&
576{return priv_->offline_callbacks;}
577
578/// Getter of the handle used to access ELF information from the
579/// current ELF file.
580///
581/// @return the handle used to access ELF information from the current
582/// ELF file.
583Elf*
585{return priv_->elf_handle;}
586
587/// Getter of the handle used to access DWARF information from the
588/// current ELF file.
589///
590/// @return the handle used to access DWARF information from the
591/// current ELF file.
592const Dwarf*
594{return priv_->dwarf_handle;}
595
596/// Test if the binary has DWARF debug info.
597///
598/// @return true iff the binary has DWARF debug info.
599bool
601{return ((priv_->dwarf_handle != nullptr)
602 || (priv_->alt_dwarf_handle != nullptr));}
603
604/// Test if the binary has CTF debug info.
605///
606/// @return true iff the binary has CTF debug info.
607bool
609{return (priv_->ctf_section != nullptr);}
610
611/// Test if the binary has BTF debug info.
612///
613/// @return true iff the binary has BTF debug info
614bool
616{return (priv_->btf_section != nullptr);}
617
618/// Getter of the handle use to access DWARF information from the
619/// alternate split DWARF information.
620///
621/// In other words, this accesses the factorized DWARF information
622/// that has been constructed by the DWZ tool to de-duplicate DWARF
623/// information on disk.
624///
625/// @return the handle use to access DWARF information from the
626/// alternate split DWARF information.
627const Dwarf*
629{return priv_->alt_dwarf_handle;}
630
631
632/// Getter of the path to the alternate split DWARF information file,
633/// on disk. In othe words, this returns the path to the factorized
634/// DWARF information used by the current ELF file, created by the
635/// 'DWZ' tool.
636///
637/// @return the path to the alternate split DWARF information file,
638/// on disk.
639const string&
641{return priv_->alt_dwarf_path;}
642
643/// Check if the underlying elf file refers to an alternate debug info
644/// file associated to it.
645///
646/// Note that "alternate debug info sections" is a GNU extension as
647/// of DWARF4 and is described at
648/// http://www.dwarfstd.org/ShowIssue.php?issue=120604.1.
649///
650/// @param alt_di the path to the alternate debug info file. This is
651/// set iff the function returns true.
652///
653/// @return true if the ELF file refers to an alternate debug info
654/// file.
655bool
656reader::refers_to_alt_debug_info(string& alt_di_path) const
657{
658 if (!alternate_dwarf_debug_info_path().empty())
659 {
660 alt_di_path = alternate_dwarf_debug_info_path();
661 return true;
662 }
663 return false;
664}
665
666/// Find and return a pointer to the ELF symbol table
667/// section.
668///
669/// @return a pointer to the ELF symbol table section.
670const Elf_Scn*
672{
673 if (!priv_->symtab_section)
674 priv_->symtab_section =
675 elf_helpers::find_symbol_table_section(elf_handle());
676 return priv_->symtab_section;
677}
678
679/// Clear the pointer to the ELF symbol table section.
680void
682{priv_->symtab_section = nullptr;}
683
684/// Find and return a pointer to the the CTF section.
685///
686/// @return a pointer to the the CTF section.
687const Elf_Scn*
689{
690 if (priv_->ctf_section == nullptr)
691 priv_->locate_ctf_debug_info();
692
693 if (priv_->ctf_section)
694 return priv_->ctf_section;
695
696 return priv_->alt_ctf_section;
697}
698
699/// Find and return a pointer to the alternate CTF section of the
700/// current ELF file.
701///
702/// @return a pointer to the alternate CTF section of the current ELF
703/// file.
704const Elf_Scn*
706{
707 if (priv_->alt_ctf_section == nullptr)
708 priv_->locate_alt_ctf_debug_info();
709
710 return priv_->alt_ctf_section;
711}
712
713/// Find and return a pointer to the BTF section of the current ELF
714/// file.
715///
716/// @return a pointer to the BTF section of the current ELF file.
717const Elf_Scn*
719{
720 if (priv_->btf_section == nullptr)
721 priv_->btf_section =
722 elf_helpers::find_section(priv_->elf_handle,
723 ".BTF", SHT_PROGBITS);
724 return priv_->btf_section;
725}
726
727/// Get the value of the DT_NEEDED property of the current ELF file.
728///
729/// @return the value of the DT_NEEDED property.
730const vector<string>&
732{return priv_->dt_needed;}
733
734
735/// Get the value of the 'ARCHITECTURE' property of the current ELF file.
736///
737/// @return the value of the 'ARCHITECTURE' property of the current
738/// ELF file.
739const string&
741{return priv_->elf_architecture;}
742
743/// Getter of an abstract representation of the symbol table of the
744/// underlying ELF file.
745///
746/// Note that the symbol table is loaded lazily, upon the first
747/// invocation of this member function.
748///
749/// @returnt the symbol table.
752{
754
755 if (!priv_->symt)
756 priv_->symt = symtab_reader::symtab::load
757 (elf_handle(), options().env,
758 [&](const elf_symbol_sptr& symbol)
759 {return suppr::is_elf_symbol_suppressed(*this, symbol);});
760
761 if (!priv_->symt)
762 std::cerr << "Symbol table of '" << corpus_path()
763 << "' could not be loaded\n";
764 return priv_->symt;
765}
766
767/// Test if a given function symbol has been exported.
768///
769/// @param symbol_address the address of the symbol we are looking
770/// for. Note that this address must be a relative offset from the
771/// beginning of the .text section, just like the kind of addresses
772/// that are present in the .symtab section.
773///
774/// @return the elf symbol if found, or nil otherwise.
776reader::function_symbol_is_exported(GElf_Addr symbol_address) const
777{
778 elf_symbol_sptr symbol = symtab()->lookup_symbol(symbol_address);
779 if (!symbol)
780 return symbol;
781
782 if (!symbol->is_function() || !symbol->is_public())
783 return elf_symbol_sptr();
784
786 bool looking_at_linux_kernel_binary =
787 load_in_linux_kernel_mode() && elf_helpers::is_linux_kernel(elf_handle());
788
789 if (looking_at_linux_kernel_binary)
790 {
791 if (symbol->is_in_ksymtab())
792 return symbol;
793 return elf_symbol_sptr();
794 }
795
796 return symbol;
797}
798
799/// Test if a given variable symbol has been exported.
800///
801/// @param symbol_address the address of the symbol we are looking
802/// for. Note that this address must be a relative offset from the
803/// beginning of the .text section, just like the kind of addresses
804/// that are present in the .symtab section.
805///
806/// @return the elf symbol if found, or nil otherwise.
808reader::variable_symbol_is_exported(GElf_Addr symbol_address) const
809{
810 elf_symbol_sptr symbol = symtab()->lookup_symbol(symbol_address);
811 if (!symbol)
812 return symbol;
813
814 if (!symbol->is_variable() || !symbol->is_public())
815 return elf_symbol_sptr();
816
818 bool looking_at_linux_kernel_binary =
819 load_in_linux_kernel_mode() && elf_helpers::is_linux_kernel(elf_handle());
820
821 if (looking_at_linux_kernel_binary)
822 {
823 if (symbol->is_in_ksymtab())
824 return symbol;
825 return elf_symbol_sptr();
826 }
827
828 return symbol;
829}
830
831/// Test if a given function symbol has been exported.
832///
833/// @param name the name of the symbol we are looking for.
834///
835/// @return the elf symbol if found, or nil otherwise.
837reader::function_symbol_is_exported(const string& name) const
838{
839 const elf_symbols& syms = symtab()->lookup_symbol(name);
840 for (auto s : syms)
841 {
842 if (s->is_function() && s->is_public())
843 {
844 bool looking_at_linux_kernel_binary =
846 && elf_helpers::is_linux_kernel(elf_handle()));
847
848 if (looking_at_linux_kernel_binary)
849 {
850 if (s->is_in_ksymtab())
851 return s;
852 }
853 else
854 return s;
855 }
856 }
857 return elf_symbol_sptr();
858}
859
860/// Test if a given variable symbol has been exported.
861///
862/// @param name the name of the symbol we are looking
863/// for.
864///
865/// @return the elf symbol if found, or nil otherwise.
867reader::variable_symbol_is_exported(const string& name) const
868{
869 const elf_symbols& syms = symtab()->lookup_symbol(name);
870 for (auto s : syms)
871 {
872 if (s->is_variable() && s->is_public())
873 {
874 bool looking_at_linux_kernel_binary =
876 && elf_helpers::is_linux_kernel(elf_handle()));
877
878 if (looking_at_linux_kernel_binary)
879 {
880 if (s->is_in_ksymtab())
881 return s;
882 }
883 else
884 return s;
885 }
886 }
887 return elf_symbol_sptr();
888}
889/// Load the DT_NEEDED and DT_SONAME elf TAGS.
890void
892{
893 elf_helpers::lookup_data_tag_from_dynamic_segment(elf_handle(),
894 DT_NEEDED,
895 priv_->dt_needed);
896
897 vector<string> dt_tag_data;
898 elf_helpers::lookup_data_tag_from_dynamic_segment(elf_handle(),
899 DT_SONAME,
900 dt_tag_data);
901 if (!dt_tag_data.empty())
902 dt_soname(dt_tag_data[0]);
903}
904
905/// Read the string representing the architecture of the current ELF
906/// file.
907void
909{
910 if (!elf_handle())
911 return;
912
913 GElf_Ehdr eh_mem;
914 GElf_Ehdr* elf_header = gelf_getehdr(elf_handle(), &eh_mem);
915
916 priv_->elf_architecture =
917 elf_helpers::e_machine_to_string(elf_header->e_machine);
918}
919
920/// Load various ELF data.
921///
922/// This function loads ELF data that are not symbol maps or debug
923/// info. That is, things like various tags, elf architecture and
924/// so on.
925void
927{
928 // Note that we don't load the symbol table as it's loaded lazily,
929 // on demand.
930
933}
934
935/// Read the ELF information associated to the current ELF file and
936/// construct an ABI representation from it.
937///
938/// Note that this reader doesn't know how to interpret any debug
939/// information so the resulting ABI corpus won't have any type
940/// information. Rather, it will only have ELF symbol representation.
941///
942/// To have type information, consider using readers that know how to
943/// interpret the symbolic type information comprised in DWARF, CTF or
944/// other symbolic debug information format, like the @ref or
945/// abigail::dwarf_reader::reader, @ref abigail::ctf_reader::reader
946/// readers.
947///
948/// @return the resulting ABI corpus.
949ir::corpus_sptr
951{
953
954 corpus::origin origin = corpus()->get_origin();
955 origin |= corpus::ELF_ORIGIN;
957 origin |= corpus::LINUX_KERNEL_BINARY_ORIGIN;
958 corpus()->set_origin(origin);
959
960 load_elf_properties(); // DT_SONAME, DT_NEEDED, architecture
961 corpus()->set_soname(dt_soname());
962 corpus()->set_needed(dt_needed());
963 corpus()->set_architecture_name(elf_architecture());
964
965 // See if we could find symbol tables.
966 if (!symtab())
967 {
969 // We found no ELF symbol, so we can't handle the binary. Note
970 // that we could have found a symbol table with no defined &
971 // exported ELF symbols in it. That case is handled as an empty
972 // corpus, which is different from this case.
973 return corpus_sptr();
974 }
975
976 // Set symbols information to the corpus.
977 corpus()->set_symtab(symtab());
978
979 // If we couldn't load debug info from the elf path, then say it.
980 if ((origin & abigail::ir::corpus::DWARF_ORIGIN)
983 else if ((origin & abigail::ir::corpus::CTF_ORIGIN)
984 && !has_ctf_debug_info())
986
987 status |= STATUS_OK;
988 return corpus();
989}
990
991/// Get the SONAME property of a designated ELF file.
992///
993/// @param path the path to the ELF file to consider.
994///
995/// @param soname output parameter. This is set to the SONAME of the
996/// file located at @p path, iff this function return true.
997///
998/// @return true iff the SONAME property was found in the ELF file
999/// located at @p path and set into the argument of the parameter @p
1000/// soname.
1001bool
1002get_soname_of_elf_file(const string& path, string &soname)
1003{return elf_helpers::get_soname_of_elf_file(path, soname);}
1004
1005/// Convert the type of ELF file into @ref elf_type.
1006///
1007/// @param elf the elf handle to use for the query.
1008///
1009/// @return the @ref elf_type for a given elf type.
1010static elf::elf_type
1011elf_file_type(Elf* elf)
1012{
1013 GElf_Ehdr ehdr_mem;
1014 GElf_Ehdr *header = gelf_getehdr (elf, &ehdr_mem);
1015 vector<string> dt_debug_data;
1016
1017 switch (header->e_type)
1018 {
1019 case ET_DYN:
1020 if (lookup_data_tag_from_dynamic_segment(elf, DT_DEBUG, dt_debug_data))
1021 return elf::ELF_TYPE_PI_EXEC;
1022 else
1023 return elf::ELF_TYPE_DSO;
1024 case ET_EXEC:
1025 return elf::ELF_TYPE_EXEC;
1026 case ET_REL:
1028 default:
1029 return elf::ELF_TYPE_UNKNOWN;
1030 }
1031}
1032
1033/// Get the type of a given elf type.
1034///
1035/// @param path the absolute path to the ELF file to analyzed.
1036///
1037/// @param type the kind of the ELF file designated by @p path.
1038///
1039/// @param out parameter. Is set to the type of ELF file of @p path.
1040/// This parameter is set iff the function returns true.
1041///
1042/// @return true iff the file could be opened and analyzed.
1043bool
1044get_type_of_elf_file(const string& path, elf::elf_type& type)
1045{
1046 int fd = open(path.c_str(), O_RDONLY);
1047 if (fd == -1)
1048 return false;
1049
1050 elf_version (EV_CURRENT);
1051 Elf *elf = elf_begin (fd, ELF_C_READ_MMAP, NULL);
1052 type = elf_file_type(elf);
1053 elf_end(elf);
1054 close(fd);
1055
1056 return true;
1057}
1058
1059}// end namespace elf
1060} // 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:1542
#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:1589
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,...
void load_elf_properties()
Load various ELF data.
void reset(const std::string &elf_path, const vector< char ** > &debug_info_roots)
Resets (erase) the resources used by the current elf::reader type.
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.
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:95
corpus_sptr corpus()
Getter for the ABI corpus being built by 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.
void reset(const std::string &corpus_path, environment &e)
Re-initialize the current Front End.
Definition: abg-fe-iface.cc:84
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:45
This is an abstraction of the set of resources necessary to manage several aspects of the internal re...
Definition: abg-ir.h:140
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:865
std::vector< elf_symbol_sptr > elf_symbols
Convenience typedef for a vector of elf_symbol.
Definition: abg-ir.h:881
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.
The generic options that control the behaviour of all Front-End interfaces.
Definition: abg-fe-iface.h:60