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"
24 #include "abg-suppression-priv.h"
25 #include "abg-elf-helpers.h"
26
27 // <headers defining libabigail's API go under here>
28 ABG_BEGIN_EXPORT_DECLARATIONS
29 #include "abg-elf-reader.h"
30 #include "abg-tools-utils.h"
31 ABG_END_EXPORT_DECLARATIONS
32 // </headers defining libabigail's API>
33 namespace abigail
34 {
35
36 using namespace elf_helpers;
37
38 namespace 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.
50 static bool
find_alt_dwarf_debug_info_link(Dwfl_Module * elf_module,string & alt_file_name)51 find_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.
126 static bool
find_alt_dwarf_debug_info_path(const vector<char ** > root_dirs,const string & alt_file_name,string & alt_file_path)127 find_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.
177 static Dwarf*
find_alt_dwarf_debug_info(Dwfl_Module * elf_module,const vector<char ** > debug_root_dirs,string & alt_file_name,int & alt_fd)178 find_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.
249 struct 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
privabigail::elf::reader::priv284 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
~privabigail::elf::reader::priv292 ~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
initializeabigail::elf::reader::priv303 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
crack_open_elf_fileabigail::elf::reader::priv333 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*
find_alt_dwarf_debug_infoabigail::elf::reader::priv369 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
clear_alt_dwarf_debug_info_dataabigail::elf::reader::priv382 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
locate_dwarf_debug_infoabigail::elf::reader::priv401 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
clear_alt_ctf_debug_info_dataabigail::elf::reader::priv430 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
locate_alt_ctf_debug_infoabigail::elf::reader::priv449 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
locate_ctf_debug_infoabigail::elf::reader::priv494 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.
reader(const string & elf_path,const vector<char ** > & debug_info_roots,ir::environment & env)515 reader::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.
~reader()527 reader::~reader()
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.
540 void
initialize(const std::string & elf_path,const vector<char ** > & debug_info_roots)541 reader::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.
559 void
initialize(const std::string & elf_path)560 reader::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.
571 const vector<char**>&
debug_info_root_paths() const572 reader::debug_info_root_paths() const
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
579 const Dwfl_Callbacks&
dwfl_offline_callbacks() const580 reader::dwfl_offline_callbacks() const
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
587 Dwfl_Callbacks&
dwfl_offline_callbacks()588 reader::dwfl_offline_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.
596 Elf*
elf_handle() const597 reader::elf_handle() const
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.
605 const Dwarf*
dwarf_debug_info() const606 reader::dwarf_debug_info() const
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.
612 bool
has_dwarf_debug_info() const613 reader::has_dwarf_debug_info() const
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.
620 bool
has_ctf_debug_info() const621 reader::has_ctf_debug_info() const
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
627 bool
has_btf_debug_info() const628 reader::has_btf_debug_info() const
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.
640 const Dwarf*
alternate_dwarf_debug_info() const641 reader::alternate_dwarf_debug_info() const
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.
652 const string&
alternate_dwarf_debug_info_path() const653 reader::alternate_dwarf_debug_info_path() const
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.
668 bool
refers_to_alt_debug_info(string & alt_di_path) const669 reader::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.
683 const Elf_Scn*
find_symbol_table_section() const684 reader::find_symbol_table_section() const
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.
693 void
reset_symbol_table_section()694 reader::reset_symbol_table_section()
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.
700 const Elf_Scn*
find_ctf_section() const701 reader::find_ctf_section() const
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.
717 const Elf_Scn*
find_alternate_ctf_section() const718 reader::find_alternate_ctf_section() const
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.
730 const Elf_Scn*
find_btf_section() const731 reader::find_btf_section() const
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.
743 const vector<string>&
dt_needed() const744 reader::dt_needed()const
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.
752 const string&
elf_architecture() const753 reader::elf_architecture() const
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.
763 symtab_reader::symtab_sptr&
symtab() const764 reader::symtab() const
765 {
766 ABG_ASSERT(elf_handle());
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.
788 elf_symbol_sptr
function_symbol_is_exported(GElf_Addr symbol_address) const789 reader::function_symbol_is_exported(GElf_Addr symbol_address) const
790 {
791 elf_symbol_sptr symbol = symtab()->lookup_symbol(symbol_address);
792 if (!symbol)
793 return symbol;
794
795 if (!symbol->is_function() || !symbol->is_public())
796 return elf_symbol_sptr();
797
798 address_set_sptr set;
799 bool looking_at_linux_kernel_binary =
800 load_in_linux_kernel_mode() && elf_helpers::is_linux_kernel(elf_handle());
801
802 if (looking_at_linux_kernel_binary)
803 {
804 if (symbol->is_in_ksymtab())
805 return symbol;
806 return elf_symbol_sptr();
807 }
808
809 return symbol;
810 }
811
812 /// Test if a given variable symbol has been exported.
813 ///
814 /// @param symbol_address the address of the symbol we are looking
815 /// for. Note that this address must be a relative offset from the
816 /// beginning of the .text section, just like the kind of addresses
817 /// that are present in the .symtab section.
818 ///
819 /// @return the elf symbol if found, or nil otherwise.
820 elf_symbol_sptr
variable_symbol_is_exported(GElf_Addr symbol_address) const821 reader::variable_symbol_is_exported(GElf_Addr symbol_address) const
822 {
823 elf_symbol_sptr symbol = symtab()->lookup_symbol(symbol_address);
824 if (!symbol)
825 return symbol;
826
827 if (!symbol->is_variable() || !symbol->is_public())
828 return elf_symbol_sptr();
829
830 address_set_sptr set;
831 bool looking_at_linux_kernel_binary =
832 load_in_linux_kernel_mode() && elf_helpers::is_linux_kernel(elf_handle());
833
834 if (looking_at_linux_kernel_binary)
835 {
836 if (symbol->is_in_ksymtab())
837 return symbol;
838 return elf_symbol_sptr();
839 }
840
841 return symbol;
842 }
843
844 /// Test if a given function symbol has been exported.
845 ///
846 /// @param name the name of the symbol we are looking for.
847 ///
848 /// @return the elf symbol if found, or nil otherwise.
849 elf_symbol_sptr
function_symbol_is_exported(const string & name) const850 reader::function_symbol_is_exported(const string& name) const
851 {
852 const elf_symbols& syms = symtab()->lookup_symbol(name);
853 for (auto s : syms)
854 {
855 if (s->is_function() && s->is_public())
856 {
857 bool looking_at_linux_kernel_binary =
858 (load_in_linux_kernel_mode()
859 && elf_helpers::is_linux_kernel(elf_handle()));
860
861 if (looking_at_linux_kernel_binary)
862 {
863 if (s->is_in_ksymtab())
864 return s;
865 }
866 else
867 return s;
868 }
869 }
870 return elf_symbol_sptr();
871 }
872
873 /// Test if a given variable symbol has been exported.
874 ///
875 /// @param name the name of the symbol we are looking
876 /// for.
877 ///
878 /// @return the elf symbol if found, or nil otherwise.
879 elf_symbol_sptr
variable_symbol_is_exported(const string & name) const880 reader::variable_symbol_is_exported(const string& name) const
881 {
882 const elf_symbols& syms = symtab()->lookup_symbol(name);
883 for (auto s : syms)
884 {
885 if (s->is_variable() && s->is_public())
886 {
887 bool looking_at_linux_kernel_binary =
888 (load_in_linux_kernel_mode()
889 && elf_helpers::is_linux_kernel(elf_handle()));
890
891 if (looking_at_linux_kernel_binary)
892 {
893 if (s->is_in_ksymtab())
894 return s;
895 }
896 else
897 return s;
898 }
899 }
900 return elf_symbol_sptr();
901 }
902 /// Load the DT_NEEDED and DT_SONAME elf TAGS.
903 void
load_dt_soname_and_needed()904 reader::load_dt_soname_and_needed()
905 {
906 elf_helpers::lookup_data_tag_from_dynamic_segment(elf_handle(),
907 DT_NEEDED,
908 priv_->dt_needed);
909
910 vector<string> dt_tag_data;
911 elf_helpers::lookup_data_tag_from_dynamic_segment(elf_handle(),
912 DT_SONAME,
913 dt_tag_data);
914 if (!dt_tag_data.empty())
915 dt_soname(dt_tag_data[0]);
916 }
917
918 /// Read the string representing the architecture of the current ELF
919 /// file.
920 void
load_elf_architecture()921 reader::load_elf_architecture()
922 {
923 if (!elf_handle())
924 return;
925
926 GElf_Ehdr eh_mem;
927 GElf_Ehdr* elf_header = gelf_getehdr(elf_handle(), &eh_mem);
928
929 priv_->elf_architecture =
930 elf_helpers::e_machine_to_string(elf_header->e_machine);
931 }
932
933 /// Load various ELF data.
934 ///
935 /// This function loads ELF data that are not symbol maps or debug
936 /// info. That is, things like various tags, elf architecture and
937 /// so on.
938 void
load_elf_properties()939 reader::load_elf_properties()
940 {
941 // Note that we don't load the symbol table as it's loaded lazily,
942 // on demand.
943
944 load_dt_soname_and_needed();
945 load_elf_architecture();
946 }
947
948 /// Read the ELF information associated to the current ELF file and
949 /// construct an ABI representation from it.
950 ///
951 /// Note that this reader doesn't know how to interpret any debug
952 /// information so the resulting ABI corpus won't have any type
953 /// information. Rather, it will only have ELF symbol representation.
954 ///
955 /// To have type information, consider using readers that know how to
956 /// interpret the symbolic type information comprised in DWARF, CTF or
957 /// other symbolic debug information format, like the @ref or
958 /// abigail::dwarf_reader::reader, @ref abigail::ctf_reader::reader
959 /// readers.
960 ///
961 /// @return the resulting ABI corpus.
962 ir::corpus_sptr
read_corpus(status & status)963 reader::read_corpus(status& status)
964 {
965 status = STATUS_UNKNOWN;
966
967 corpus::origin origin = corpus()->get_origin();
968 origin |= corpus::ELF_ORIGIN;
969 if (is_linux_kernel(elf_handle()))
970 origin |= corpus::LINUX_KERNEL_BINARY_ORIGIN;
971 corpus()->set_origin(origin);
972
973 load_elf_properties(); // DT_SONAME, DT_NEEDED, architecture
974 corpus()->set_soname(dt_soname());
975 corpus()->set_needed(dt_needed());
976 corpus()->set_architecture_name(elf_architecture());
977
978 // See if we could find symbol tables.
979 if (!symtab())
980 {
981 status |= STATUS_NO_SYMBOLS_FOUND | STATUS_OK;
982 // We found no ELF symbol, so we can't handle the binary. Note
983 // that we could have found a symbol table with no defined &
984 // exported ELF symbols in it. Both cases are handled as an
985 // empty corpus.
986 return corpus();
987 }
988
989 // Set symbols information to the corpus.
990 corpus()->set_symtab(symtab());
991
992 // If we couldn't load debug info from the elf path, then say it.
993 if ((origin & abigail::ir::corpus::DWARF_ORIGIN)
994 && !has_dwarf_debug_info())
995 status |= STATUS_DEBUG_INFO_NOT_FOUND;
996 else if ((origin & abigail::ir::corpus::CTF_ORIGIN)
997 && !has_ctf_debug_info())
998 status |= STATUS_DEBUG_INFO_NOT_FOUND;
999
1000 status |= STATUS_OK;
1001 return corpus();
1002 }
1003
1004 /// Get the SONAME property of a designated ELF file.
1005 ///
1006 /// @param path the path to the ELF file to consider.
1007 ///
1008 /// @param soname output parameter. This is set to the SONAME of the
1009 /// file located at @p path, iff this function return true.
1010 ///
1011 /// @return true iff the SONAME property was found in the ELF file
1012 /// located at @p path and set into the argument of the parameter @p
1013 /// soname.
1014 bool
get_soname_of_elf_file(const string & path,string & soname)1015 get_soname_of_elf_file(const string& path, string &soname)
1016 {return elf_helpers::get_soname_of_elf_file(path, soname);}
1017
1018 /// Convert the type of ELF file into @ref elf_type.
1019 ///
1020 /// @param elf the elf handle to use for the query.
1021 ///
1022 /// @return the @ref elf_type for a given elf type.
1023 static elf::elf_type
elf_file_type(Elf * elf)1024 elf_file_type(Elf* elf)
1025 {
1026 GElf_Ehdr ehdr_mem;
1027 GElf_Ehdr *header = gelf_getehdr (elf, &ehdr_mem);
1028 vector<string> dt_debug_data;
1029
1030 switch (header->e_type)
1031 {
1032 case ET_DYN:
1033 if (lookup_data_tag_from_dynamic_segment(elf, DT_DEBUG, dt_debug_data))
1034 return elf::ELF_TYPE_PI_EXEC;
1035 else
1036 return elf::ELF_TYPE_DSO;
1037 case ET_EXEC:
1038 return elf::ELF_TYPE_EXEC;
1039 case ET_REL:
1040 return elf::ELF_TYPE_RELOCATABLE;
1041 default:
1042 return elf::ELF_TYPE_UNKNOWN;
1043 }
1044 }
1045
1046 /// Get the type of a given elf type.
1047 ///
1048 /// @param path the absolute path to the ELF file to analyzed.
1049 ///
1050 /// @param type the kind of the ELF file designated by @p path.
1051 ///
1052 /// @param out parameter. Is set to the type of ELF file of @p path.
1053 /// This parameter is set iff the function returns true.
1054 ///
1055 /// @return true iff the file could be opened and analyzed.
1056 bool
get_type_of_elf_file(const string & path,elf::elf_type & type)1057 get_type_of_elf_file(const string& path, elf::elf_type& type)
1058 {
1059 int fd = open(path.c_str(), O_RDONLY);
1060 if (fd == -1)
1061 return false;
1062
1063 elf_version (EV_CURRENT);
1064 Elf *elf = elf_begin (fd, ELF_C_READ_MMAP, NULL);
1065 type = elf_file_type(elf);
1066 elf_end(elf);
1067 close(fd);
1068
1069 return true;
1070 }
1071
1072 }// end namespace elf
1073 } // end namespace abigail
1074