libabigail
abg-elf-helpers.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) 2020-2025 Google, Inc.
5
6/// @file
7///
8/// This contains the definitions of the ELF utilities for the dwarf reader.
9#include "config.h"
10#include <sys/types.h>
11#include <sys/stat.h>
12#include <fcntl.h>
13#include <unistd.h>
14#include <limits.h>
15#include <elfutils/libdwfl.h>
16#include <sstream>
17#include "abg-elf-helpers.h"
18#include "abg-tools-utils.h"
19
20namespace abigail
21{
22
23namespace elf_helpers
24{
25
26/// Convert an elf symbol type (given by the ELF{32,64}_ST_TYPE
27/// macros) into an elf_symbol::type value.
28///
29/// Note that this function aborts when given an unexpected value.
30///
31/// @param the symbol type value to convert.
32///
33/// @return the converted value.
35stt_to_elf_symbol_type(unsigned char stt)
36{
37 switch (stt)
38 {
39 case STT_NOTYPE:
40 return elf_symbol::NOTYPE_TYPE;
41 case STT_OBJECT:
42 return elf_symbol::OBJECT_TYPE;
43 case STT_FUNC:
44 return elf_symbol::FUNC_TYPE;
45 case STT_SECTION:
46 return elf_symbol::SECTION_TYPE;
47 case STT_FILE:
48 return elf_symbol::FILE_TYPE;
49 case STT_COMMON:
50 return elf_symbol::COMMON_TYPE;
51 case STT_TLS:
52 return elf_symbol::TLS_TYPE;
53 case STT_GNU_IFUNC:
54 return elf_symbol::GNU_IFUNC_TYPE;
55 default:
56 // An unknown value that probably ought to be supported? Let's
57 // abort right here rather than yielding garbage.
59 }
60}
61
62/// Convert an elf symbol binding (given by the ELF{32,64}_ST_BIND
63/// macros) into an elf_symbol::binding value.
64///
65/// Note that this function aborts when given an unexpected value.
66///
67/// @param the symbol binding value to convert.
68///
69/// @return the converted value.
71stb_to_elf_symbol_binding(unsigned char stb)
72{
73 switch (stb)
74 {
75 case STB_LOCAL:
76 return elf_symbol::LOCAL_BINDING;
77 case STB_GLOBAL:
78 return elf_symbol::GLOBAL_BINDING;
79 case STB_WEAK:
80 return elf_symbol::WEAK_BINDING;
81 case STB_GNU_UNIQUE:
82 return elf_symbol::GNU_UNIQUE_BINDING;
83 default:
85 }
86}
87
88/// Convert an ELF symbol visiblity given by the symbols ->st_other
89/// data member as returned by the GELF_ST_VISIBILITY macro into a
90/// elf_symbol::visiblity value.
91///
92/// @param stv the value of the ->st_other data member of the ELF
93/// symbol.
94///
95/// @return the converted elf_symbol::visiblity value.
98{
99 switch (stv)
100 {
101 case STV_DEFAULT:
102 return elf_symbol::DEFAULT_VISIBILITY;
103 case STV_INTERNAL:
104 return elf_symbol::INTERNAL_VISIBILITY;
105 case STV_HIDDEN:
106 return elf_symbol::HIDDEN_VISIBILITY;
107 case STV_PROTECTED:
108 return elf_symbol::PROTECTED_VISIBILITY;
109 default:
111 }
112}
113
114/// Convert the value of the e_machine field of GElf_Ehdr into a
115/// string. This is to get a string representing the architecture of
116/// the elf file at hand.
117///
118/// @param e_machine the value of GElf_Ehdr::e_machine.
119///
120/// @return the string representation of GElf_Ehdr::e_machine.
121std::string
122e_machine_to_string(GElf_Half e_machine)
123{
124 switch (e_machine)
125 {
126 case EM_NONE:
127 return "elf-no-arch";
128 case EM_M32:
129 return "elf-att-we-32100";
130 case EM_SPARC:
131 return "elf-sun-sparc";
132 case EM_386:
133 return "elf-intel-80386";
134 case EM_68K:
135 return "elf-motorola-68k";
136 case EM_88K:
137 return "elf-motorola-88k";
138 case EM_860:
139 return "elf-intel-80860";
140 case EM_MIPS:
141 return "elf-mips-r3000-be";
142 case EM_S370:
143 return "elf-ibm-s370";
144 case EM_MIPS_RS3_LE:
145 return "elf-mips-r3000-le";
146 case EM_PARISC:
147 return "elf-hp-parisc";
148 case EM_VPP500:
149 return "elf-fujitsu-vpp500";
150 case EM_SPARC32PLUS:
151 return "elf-sun-sparc-v8plus";
152 case EM_960:
153 return "elf-intel-80960";
154 case EM_PPC:
155 return "elf-powerpc";
156 case EM_PPC64:
157 return "elf-powerpc-64";
158 case EM_S390:
159 return "elf-ibm-s390";
160 case EM_V800:
161 return "elf-nec-v800";
162 case EM_FR20:
163 return "elf-fujitsu-fr20";
164 case EM_RH32:
165 return "elf-trw-rh32";
166 case EM_RCE:
167 return "elf-motorola-rce";
168 case EM_ARM:
169 return "elf-arm";
170 case EM_FAKE_ALPHA:
171 return "elf-digital-alpha";
172 case EM_SH:
173 return "elf-hitachi-sh";
174 case EM_SPARCV9:
175 return "elf-sun-sparc-v9-64";
176 case EM_TRICORE:
177 return "elf-siemens-tricore";
178 case EM_ARC:
179 return "elf-argonaut-risc-core";
180 case EM_H8_300:
181 return "elf-hitachi-h8-300";
182 case EM_H8_300H:
183 return "elf-hitachi-h8-300h";
184 case EM_H8S:
185 return "elf-hitachi-h8s";
186 case EM_H8_500:
187 return "elf-hitachi-h8-500";
188 case EM_IA_64:
189 return "elf-intel-ia-64";
190 case EM_MIPS_X:
191 return "elf-stanford-mips-x";
192 case EM_COLDFIRE:
193 return "elf-motorola-coldfire";
194 case EM_68HC12:
195 return "elf-motorola-68hc12";
196 case EM_MMA:
197 return "elf-fujitsu-mma";
198 case EM_PCP:
199 return "elf-siemens-pcp";
200 case EM_NCPU:
201 return "elf-sony-ncpu";
202 case EM_NDR1:
203 return "elf-denso-ndr1";
204 case EM_STARCORE:
205 return "elf-motorola-starcore";
206 case EM_ME16:
207 return "elf-toyota-me16";
208 case EM_ST100:
209 return "elf-stm-st100";
210 case EM_TINYJ:
211 return "elf-alc-tinyj";
212 case EM_X86_64:
213 return "elf-amd-x86_64";
214 case EM_PDSP:
215 return "elf-sony-pdsp";
216 case EM_FX66:
217 return "elf-siemens-fx66";
218 case EM_ST9PLUS:
219 return "elf-stm-st9+";
220 case EM_ST7:
221 return "elf-stm-st7";
222 case EM_68HC16:
223 return "elf-motorola-68hc16";
224 case EM_68HC11:
225 return "elf-motorola-68hc11";
226 case EM_68HC08:
227 return "elf-motorola-68hc08";
228 case EM_68HC05:
229 return "elf-motorola-68hc05";
230 case EM_SVX:
231 return "elf-sg-svx";
232 case EM_ST19:
233 return "elf-stm-st19";
234 case EM_VAX:
235 return "elf-digital-vax";
236 case EM_CRIS:
237 return "elf-axis-cris";
238 case EM_JAVELIN:
239 return "elf-infineon-javelin";
240 case EM_FIREPATH:
241 return "elf-firepath";
242 case EM_ZSP:
243 return "elf-lsi-zsp";
244 case EM_MMIX:
245 return "elf-don-knuth-mmix";
246 case EM_HUANY:
247 return "elf-harvard-huany";
248 case EM_PRISM:
249 return "elf-sitera-prism";
250 case EM_AVR:
251 return "elf-atmel-avr";
252 case EM_FR30:
253 return "elf-fujistu-fr30";
254 case EM_D10V:
255 return "elf-mitsubishi-d10v";
256 case EM_D30V:
257 return "elf-mitsubishi-d30v";
258 case EM_V850:
259 return "elf-nec-v850";
260 case EM_M32R:
261 return "elf-mitsubishi-m32r";
262 case EM_MN10300:
263 return "elf-matsushita-mn10300";
264 case EM_MN10200:
265 return "elf-matsushita-mn10200";
266 case EM_PJ:
267 return "elf-picojava";
268 case EM_OPENRISC:
269 return "elf-openrisc-32";
270 case EM_ARC_A5:
271 return "elf-arc-a5";
272 case EM_XTENSA:
273 return "elf-tensilica-xtensa";
274
275#ifdef HAVE_EM_AARCH64_MACRO
276 case EM_AARCH64:
277 return "elf-arm-aarch64";
278#endif
279
280#ifdef HAVE_EM_TILEPRO_MACRO
281 case EM_TILEPRO:
282 return "elf-tilera-tilepro";
283#endif
284
285#ifdef HAVE_EM_TILEGX_MACRO
286 case EM_TILEGX:
287 return "elf-tilera-tilegx";
288#endif
289
290#ifdef HAVE_EM_RISCV_MACRO
291 case EM_RISCV:
292 return "elf-riscv";
293#endif
294
295 case EM_NUM:
296 return "elf-last-arch-number";
297 case EM_ALPHA:
298 return "elf-non-official-alpha";
299 default:
300 {
301 std::ostringstream o;
302 o << "elf-unknown-arch-value-" << e_machine;
303 return o.str();
304 }
305 }
306}
307
308/// Find and return a section by its name.
309///
310/// @param elf_handle the elf handle to use.
311///
312/// @param name the section name.
313///
314/// @return the section found, nor nil if none was found.
315Elf_Scn*
316find_section_by_name(Elf* elf_handle, const std::string& name)
317{
318 size_t section_header_string_index = 0;
319 if (elf_getshdrstrndx (elf_handle, &section_header_string_index) < 0)
320 return 0;
321
322 Elf_Scn* section = 0;
323 GElf_Shdr header_mem, *header;
324 while ((section = elf_nextscn(elf_handle, section)) != 0)
325 {
326 header = gelf_getshdr(section, &header_mem);
327 if (header == NULL)
328 continue;
329
330 const char* section_name =
331 elf_strptr(elf_handle, section_header_string_index, header->sh_name);
332 if (section_name && name == section_name)
333 return section;
334 }
335
336 return 0;
337}
338
339/// Find and return a section by its name and its type.
340///
341/// @param elf_handle the elf handle to use.
342///
343/// @param name the name of the section.
344///
345/// @param section_type the type of the section. This is the
346/// Elf32_Shdr::sh_type (or Elf64_Shdr::sh_type) data member.
347/// Examples of values of this parameter are SHT_PROGBITS or SHT_NOBITS.
348///
349/// @return the section found, nor nil if none was found.
350Elf_Scn*
351find_section(Elf* elf_handle, const std::string& name, Elf64_Word section_type)
352{
353 size_t section_header_string_index = 0;
354 if (elf_getshdrstrndx (elf_handle, &section_header_string_index) < 0)
355 return 0;
356
357 Elf_Scn* section = 0;
358 GElf_Shdr header_mem, *header;
359 while ((section = elf_nextscn(elf_handle, section)) != 0)
360 {
361 header = gelf_getshdr(section, &header_mem);
362 if (header == NULL || header->sh_type != section_type)
363 continue;
364
365 const char* section_name =
366 elf_strptr(elf_handle, section_header_string_index, header->sh_name);
367 if (section_name && name == section_name)
368 return section;
369 }
370
371 return 0;
372}
373
374/// Find and return a section by its type.
375///
376/// @param elf_handle the elf handle to use.
377///
378/// @param section_type the type of the section. This is the
379/// Elf32_Shdr::sh_type (or Elf64_Shdr::sh_type) data member.
380/// Examples of values of this parameter are SHT_PROGBITS or SHT_NOBITS.
381///
382/// @return the section found, or nil if none was found.
383Elf_Scn*
384find_section(Elf* elf_handle, Elf64_Word section_type)
385{
386 Elf_Scn* section = nullptr;
387 while ((section = elf_nextscn(elf_handle, section)) != 0)
388 {
389 GElf_Shdr header_mem, *header;
390 header = gelf_getshdr(section, &header_mem);
391 if (header->sh_type == section_type)
392 break;
393 }
394 return section;
395}
396
397/// Find and return the .symtab section
398///
399/// @param elf_handle the elf handle to use.
400///
401/// @return the section found, or nil if none was found
402Elf_Scn*
403find_symtab_section(Elf* elf_handle)
404{
405 return find_section(elf_handle, SHT_SYMTAB);
406}
407
408/// Find and return the .symtab section
409///
410/// @param elf_handle the elf handle to use.
411///
412/// @return the section found, or nil if none was found
413Elf_Scn*
414find_dynsym_section(Elf* elf_handle)
415{
416 return find_section(elf_handle, SHT_DYNSYM);
417}
418
419/// Find the symbol table.
420///
421/// If we are looking at a relocatable or executable file, this
422/// function will return the .symtab symbol table (of type
423/// SHT_SYMTAB). But if we are looking at a DSO it returns the
424/// .dynsym symbol table (of type SHT_DYNSYM).
425///
426/// @param elf_handle the elf handle to consider.
427///
428/// @param symtab the symbol table found.
429///
430/// @return the symbol table section
431Elf_Scn*
433{
434 Elf_Scn *dynsym = find_dynsym_section(elf_handle),
435 *sym_tab = find_symtab_section(elf_handle);
436
437 if (dynsym || sym_tab)
438 {
439 GElf_Ehdr eh_mem;
440 GElf_Ehdr* elf_header = gelf_getehdr(elf_handle, &eh_mem);
441 if (elf_header->e_type == ET_REL
442 || elf_header->e_type == ET_EXEC)
443 return sym_tab ? sym_tab : dynsym;
444 else
445 return dynsym ? dynsym : sym_tab;
446 }
447 return nullptr;
448}
449
450/// Find the index (in the section headers table) of the symbol table
451/// section.
452///
453/// If we are looking at a relocatable or executable file, this
454/// function will return the index for the .symtab symbol table (of
455/// type SHT_SYMTAB). But if we are looking at a DSO it returns the
456/// index for the .dynsym symbol table (of type SHT_DYNSYM).
457///
458/// @param elf_handle the elf handle to use.
459///
460/// @param symtab_index the index of the symbol_table, that was found.
461///
462/// @return true iff the symbol table section index was found.
463bool
464find_symbol_table_section_index(Elf* elf_handle, size_t& symtab_index)
465{
466 Elf_Scn* section = find_symbol_table_section(elf_handle);
467
468 if (!section)
469 return false;
470
471 symtab_index = elf_ndxscn(section);
472 return true;
473}
474
475/// Get the offset offset of the hash table section.
476///
477/// @param elf_handle the elf handle to use.
478///
479/// @param ht_section_offset this is set to the resulting offset
480/// of the hash table section. This is set iff the function returns true.
481///
482/// @param symtab_section_offset the offset of the section of the
483/// symbol table the hash table refers to.
484hash_table_kind
486 size_t& ht_section_index,
487 size_t& symtab_section_index)
488{
489 if (!elf_handle)
490 return NO_HASH_TABLE_KIND;
491
492 GElf_Shdr header_mem, *section_header;
493 bool found_sysv_ht = false, found_gnu_ht = false;
494 for (Elf_Scn* section = elf_nextscn(elf_handle, 0);
495 section != 0;
496 section = elf_nextscn(elf_handle, section))
497 {
498 section_header= gelf_getshdr(section, &header_mem);
499 if (section_header->sh_type != SHT_HASH
500 && section_header->sh_type != SHT_GNU_HASH)
501 continue;
502
503 ht_section_index = elf_ndxscn(section);
504 symtab_section_index = section_header->sh_link;
505
506 if (section_header->sh_type == SHT_HASH)
507 found_sysv_ht = true;
508 else if (section_header->sh_type == SHT_GNU_HASH)
509 found_gnu_ht = true;
510 }
511
512 if (found_gnu_ht)
513 return GNU_HASH_TABLE_KIND;
514 else if (found_sysv_ht)
515 return SYSV_HASH_TABLE_KIND;
516 else
517 return NO_HASH_TABLE_KIND;
518}
519
520/// Find and return the .text section.
521///
522/// @param elf_handle the elf handle to use.
523///
524/// @return the .text section found.
525Elf_Scn*
526find_text_section(Elf* elf_handle)
527{return find_section(elf_handle, ".text", SHT_PROGBITS);}
528
529/// Find and return the .bss section.
530///
531/// @param elf_handle.
532///
533/// @return the .bss section found.
534Elf_Scn*
535find_bss_section(Elf* elf_handle)
536{return find_section(elf_handle, ".bss", SHT_NOBITS);}
537
538/// Find and return the .rodata section.
539///
540/// @param elf_handle.
541///
542/// @return the .rodata section found.
543Elf_Scn*
544find_rodata_section(Elf* elf_handle)
545{return find_section(elf_handle, ".rodata", SHT_PROGBITS);}
546
547/// Find and return the .data section.
548///
549/// @param elf_handle the elf handle to use.
550///
551/// @return the .data section found.
552Elf_Scn*
553find_data_section(Elf* elf_handle)
554{return find_section(elf_handle, ".data", SHT_PROGBITS);}
555
556/// Find and return the .data1 section.
557///
558/// @param elf_handle the elf handle to use.
559///
560/// @return the .data1 section found.
561Elf_Scn*
562find_data1_section(Elf* elf_handle)
563{return find_section(elf_handle, ".data1", SHT_PROGBITS);}
564
565/// Return the "Official Procedure descriptors section." This
566/// section is named .opd, and is usually present only on PPC64
567/// ELFv1 binaries.
568///
569/// @param elf_handle the elf handle to consider.
570///
571/// @return the .opd section, if found. Return nil otherwise.
572Elf_Scn*
573find_opd_section(Elf* elf_handle)
574{return find_section(elf_handle, ".opd", SHT_PROGBITS);}
575
576/// Return the SHT_GNU_versym, SHT_GNU_verdef and SHT_GNU_verneed
577/// sections that are involved in symbol versionning.
578///
579/// @param elf_handle the elf handle to use.
580///
581/// @param versym_section the SHT_GNU_versym section found. If the
582/// section wasn't found, this is set to nil.
583///
584/// @param verdef_section the SHT_GNU_verdef section found. If the
585/// section wasn't found, this is set to nil.
586///
587/// @param verneed_section the SHT_GNU_verneed section found. If the
588/// section wasn't found, this is set to nil.
589///
590/// @return true iff at least one of the sections where found.
591bool
593 Elf_Scn*& versym_section,
594 Elf_Scn*& verdef_section,
595 Elf_Scn*& verneed_section)
596{
597 Elf_Scn* section = NULL;
598 GElf_Shdr mem;
599 Elf_Scn* versym = NULL, *verdef = NULL, *verneed = NULL;
600
601 while ((section = elf_nextscn(elf_handle, section)) != NULL)
602 {
603 GElf_Shdr* h = gelf_getshdr(section, &mem);
604 if (h->sh_type == SHT_GNU_versym)
605 versym = section;
606 else if (h->sh_type == SHT_GNU_verdef)
607 verdef = section;
608 else if (h->sh_type == SHT_GNU_verneed)
609 verneed = section;
610 }
611
612 if (versym || verdef || verneed)
613 {
614 // At least one the versionning sections was found. Return it.
615 versym_section = versym;
616 verdef_section = verdef;
617 verneed_section = verneed;
618 return true;
619 }
620
621 return false;
622}
623
624/// Return the __ksymtab section of a linux kernel ELF file (either
625/// a vmlinux binary or a kernel module).
626///
627/// @param elf_handle the elf handle to consider.
628///
629/// @return the __ksymtab section if found, nil otherwise.
630Elf_Scn*
631find_ksymtab_section(Elf* elf_handle)
632{return find_section(elf_handle, "__ksymtab", SHT_PROGBITS);}
633
634/// Return the __ksymtab_gpl section of a linux kernel ELF file (either
635/// a vmlinux binary or a kernel module).
636///
637/// @param elf_handle the elf handle to consider.
638///
639/// @return the __ksymtab section if found, nil otherwise.
640Elf_Scn*
642{return find_section(elf_handle, "__ksymtab_gpl", SHT_PROGBITS);}
643
644/// Find the __ksymtab_strings section of a Linux kernel binary.
645///
646/// @param elf_handle the elf handle to use.
647///
648/// @return the find_ksymtab_strings_section of the linux kernel
649/// binary denoted by @p elf_handle, or nil if such a section could
650/// not be found.
651Elf_Scn*
653{
654 if (is_linux_kernel(elf_handle))
655 return find_section(elf_handle, "__ksymtab_strings", SHT_PROGBITS);
656 return 0;
657}
658
659/// Return the .rel{a,} section corresponding to a given section.
660///
661/// @param elf_handle the elf handle to consider.
662///
663/// @param target_section the section to search the relocation section for
664///
665/// @return the .rel{a,} section if found, null otherwise.
666Elf_Scn*
667find_relocation_section(Elf* elf_handle, Elf_Scn* target_section)
668{
669 if (target_section)
670 {
671 // the relo section we are searching for has this index as sh_info
672 size_t target_index = elf_ndxscn(target_section);
673
674 // now iterate over all the sections, look for relocation sections and
675 // find the one that points to the section we are searching for
676 Elf_Scn* section = 0;
677 GElf_Shdr header_mem, *header;
678 while ((section = elf_nextscn(elf_handle, section)) != 0)
679 {
680 header = gelf_getshdr(section, &header_mem);
681 if (header == NULL
682 || (header->sh_type != SHT_RELA && header->sh_type != SHT_REL))
683 continue;
684
685 if (header->sh_info == target_index)
686 return section;
687 }
688 }
689 return NULL;
690}
691
692/// Return the string table used by the given symbol table.
693///
694/// @param elf_handle the elf handle to use.
695///
696/// @param symtab_section section containing a symbol table.
697///
698/// @return the string table linked by the symtab, if it is not NULL.
699Elf_Scn*
700find_strtab_for_symtab_section(Elf* elf_handle, Elf_Scn* symtab_section)
701{
702 Elf_Scn *strtab_section = NULL;
703
704 if (symtab_section)
705 {
706 GElf_Shdr symtab_shdr_mem, *symtab_shdr;
707
708 symtab_shdr = gelf_getshdr(symtab_section, &symtab_shdr_mem);
709 strtab_section = elf_getscn(elf_handle, symtab_shdr->sh_link);
710 }
711
712 return strtab_section;
713}
714
715/// Get the version definition (from the SHT_GNU_verdef section) of a
716/// given symbol represented by a pointer to GElf_Versym.
717///
718/// @param elf_hande the elf handle to use.
719///
720/// @param versym the symbol to get the version definition for.
721///
722/// @param verdef_section the SHT_GNU_verdef section.
723///
724/// @param version the resulting version definition. This is set iff
725/// the function returns true.
726///
727/// @return true upon successful completion, false otherwise.
728bool
730 GElf_Versym* versym,
731 Elf_Scn* verdef_section,
732 elf_symbol::version& version)
733{
734 Elf_Data* verdef_data = elf_getdata(verdef_section, NULL);
735 GElf_Verdef verdef_mem;
736 GElf_Verdef* verdef = gelf_getverdef(verdef_data, 0, &verdef_mem);
737 size_t vd_offset = 0;
738
739 for (;; vd_offset += verdef->vd_next)
740 {
741 for (;verdef != 0;)
742 {
743 if (verdef->vd_ndx == (*versym & 0x7fff))
744 // Found the version of the symbol.
745 break;
746 vd_offset += verdef->vd_next;
747 verdef = (verdef->vd_next == 0
748 ? 0
749 : gelf_getverdef(verdef_data, vd_offset, &verdef_mem));
750 }
751
752 if (verdef != 0)
753 {
754 GElf_Verdaux verdaux_mem;
755 GElf_Verdaux *verdaux = gelf_getverdaux(verdef_data,
756 vd_offset + verdef->vd_aux,
757 &verdaux_mem);
758 GElf_Shdr header_mem;
759 GElf_Shdr* verdef_section_header = gelf_getshdr(verdef_section,
760 &header_mem);
761 size_t verdef_stridx = verdef_section_header->sh_link;
762 version.str(elf_strptr(elf_handle, verdef_stridx, verdaux->vda_name));
763 if (*versym & 0x8000)
764 version.is_default(false);
765 else
766 version.is_default(true);
767 return true;
768 }
769 if (!verdef || verdef->vd_next == 0)
770 break;
771 }
772 return false;
773}
774
775/// Get the version needed (from the SHT_GNU_verneed section) to
776/// resolve an undefined symbol represented by a pointer to
777/// GElf_Versym.
778///
779/// @param elf_hande the elf handle to use.
780///
781/// @param versym the symbol to get the version definition for.
782///
783/// @param verneed_section the SHT_GNU_verneed section.
784///
785/// @param version the resulting version definition. This is set iff
786/// the function returns true.
787///
788/// @return true upon successful completion, false otherwise.
789bool
791 GElf_Versym* versym,
792 Elf_Scn* verneed_section,
793 elf_symbol::version& version)
794{
795 if (versym == 0 || elf_handle == 0 || verneed_section == 0)
796 return false;
797
798 size_t vn_offset = 0;
799 Elf_Data* verneed_data = elf_getdata(verneed_section, NULL);
800 GElf_Verneed verneed_mem;
801 GElf_Verneed* verneed = gelf_getverneed(verneed_data, 0, &verneed_mem);
802
803 for (;verneed; vn_offset += verneed->vn_next)
804 {
805 size_t vna_offset = vn_offset;
806 GElf_Vernaux vernaux_mem;
807 GElf_Vernaux *vernaux = gelf_getvernaux(verneed_data,
808 vn_offset + verneed->vn_aux,
809 &vernaux_mem);
810 for (;vernaux != 0 && verneed;)
811 {
812 if (vernaux->vna_other == *versym)
813 // Found the version of the symbol.
814 break;
815 vna_offset += verneed->vn_next;
816 verneed = (verneed->vn_next == 0
817 ? 0
818 : gelf_getverneed(verneed_data, vna_offset, &verneed_mem));
819 }
820
821 if (verneed != 0 && vernaux != 0 && vernaux->vna_other == *versym)
822 {
823 GElf_Shdr header_mem;
824 GElf_Shdr* verneed_section_header = gelf_getshdr(verneed_section,
825 &header_mem);
826 size_t verneed_stridx = verneed_section_header->sh_link;
827 version.str(elf_strptr(elf_handle,
828 verneed_stridx,
829 vernaux->vna_name));
830 if (*versym & 0x8000)
831 version.is_default(false);
832 else
833 version.is_default(true);
834 return true;
835 }
836
837 if (!verneed || verneed->vn_next == 0)
838 break;
839 }
840 return false;
841}
842
843/// Return the version for a symbol that is at a given index in its
844/// SHT_SYMTAB section.
845///
846/// @param elf_handle the elf handle to use.
847///
848/// @param symbol_index the index of the symbol to consider.
849///
850/// @param get_def_version if this is true, it means that that we want
851/// the version for a defined symbol; in that case, the version is
852/// looked for in a section of type SHT_GNU_verdef. Otherwise, if
853/// this parameter is false, this means that we want the version for
854/// an undefined symbol; in that case, the version is the needed one
855/// for the symbol to be resolved; so the version is looked fo in a
856/// section of type SHT_GNU_verneed.
857///
858/// @param version the version found for symbol at @p symbol_index.
859///
860/// @return true iff a version was found for symbol at index @p
861/// symbol_index.
862bool
864 size_t symbol_index,
865 bool get_def_version,
866 elf_symbol::version& version)
867{
868 Elf_Scn *versym_section = NULL,
869 *verdef_section = NULL,
870 *verneed_section = NULL;
871
872 if (!get_symbol_versionning_sections(elf_handle,
873 versym_section,
874 verdef_section,
875 verneed_section))
876 return false;
877
878 GElf_Versym versym_mem;
879 Elf_Data* versym_data = (versym_section)
880 ? elf_getdata(versym_section, NULL)
881 : NULL;
882 GElf_Versym* versym = (versym_data)
883 ? gelf_getversym(versym_data, symbol_index, &versym_mem)
884 : NULL;
885
886 if (versym == 0 || *versym <= 1)
887 // I got these value from the code of readelf.c in elfutils.
888 // Apparently, if the symbol version entry has these values, the
889 // symbol must be discarded. This is not documented in the
890 // official specification.
891 return false;
892
893 if (get_def_version)
894 {
895 if (*versym == 0x8001)
896 // I got this value from the code of readelf.c in elfutils
897 // too. It's not really documented in the official
898 // specification.
899 return false;
900
901 if (verdef_section
902 && get_version_definition_for_versym(elf_handle, versym,
903 verdef_section, version))
904 return true;
905 }
906 else
907 {
908 if (verneed_section
909 && get_version_needed_for_versym(elf_handle, versym,
910 verneed_section, version))
911 return true;
912 }
913
914 return false;
915}
916
917/// Return the CRC from the "__crc_" symbol.
918///
919/// @param elf_handle the elf handle to use.
920///
921/// @param crc_symbol symbol containing CRC value.
922///
923/// @param crc_value the CRC found for @p crc_symbol.
924///
925/// @return true iff a CRC was found for given @p crc_symbol.
926bool
927get_crc_for_symbol(Elf* elf_handle, GElf_Sym* crc_symbol, uint32_t& crc_value)
928{
929 size_t crc_section_index = crc_symbol->st_shndx;
930 GElf_Addr crc_symbol_address =
931 maybe_adjust_et_rel_sym_addr_to_abs_addr(elf_handle, crc_symbol);
932 if (crc_section_index == SHN_ABS)
933 {
934 crc_value = crc_symbol_address;
935 return true;
936 }
937
938 Elf_Scn* kcrctab_section = elf_getscn(elf_handle, crc_section_index);
939 if (kcrctab_section == NULL)
940 return false;
941
942 GElf_Shdr sheader_mem;
943 GElf_Shdr* sheader = gelf_getshdr(kcrctab_section, &sheader_mem);
944 if (sheader == NULL)
945 return false;
946
947 Elf_Data* kcrctab_data = elf_rawdata(kcrctab_section, NULL);
948 if (kcrctab_data == NULL)
949 return false;
950
951 if (crc_symbol_address < sheader->sh_addr)
952 return false;
953
954 size_t offset = crc_symbol_address - sheader->sh_addr;
955 if (offset + sizeof(uint32_t) > kcrctab_data->d_size
956 || offset + sizeof(uint32_t) > sheader->sh_size)
957 return false;
958
959 crc_value = *reinterpret_cast<uint32_t*>(
960 reinterpret_cast<char*>(kcrctab_data->d_buf) + offset);
961
962 return true;
963}
964
965/// Test if the architecture of the current binary is ppc64.
966///
967/// @param elf_handle the ELF handle to consider.
968///
969/// @return true iff the architecture of the current binary is ppc64.
970bool
971architecture_is_ppc64(Elf* elf_handle)
972{
973 GElf_Ehdr eh_mem;
974 GElf_Ehdr* elf_header = gelf_getehdr(elf_handle, &eh_mem);
975 return (elf_header && elf_header->e_machine == EM_PPC64);
976}
977
978/// Test if the architecture of the current binary is ppc32.
979///
980/// @param elf_handle the ELF handle to consider.
981///
982/// @return true iff the architecture of the current binary is ppc32.
983bool
984architecture_is_ppc32(Elf* elf_handle)
985{
986 GElf_Ehdr eh_mem;
987 GElf_Ehdr* elf_header = gelf_getehdr(elf_handle, &eh_mem);
988 return (elf_header && elf_header->e_machine == EM_PPC);
989}
990
991/// Test if the architecture of the current binary is arm32.
992///
993/// @param elf_handle the ELF handle to consider.
994///
995/// @return true iff the architecture of the current binary is arm32.
996bool
997architecture_is_arm32(Elf* elf_handle)
998{
999 GElf_Ehdr eh_mem;
1000 GElf_Ehdr* elf_header = gelf_getehdr(elf_handle, &eh_mem);
1001 return (elf_header && elf_header->e_machine == EM_ARM);
1002}
1003
1004/// Test if the architecture of the current binary is arm64.
1005///
1006/// @param elf_handle the ELF handle to consider.
1007///
1008/// @return true iff the architecture of the current binary is arm64.
1009bool
1011{
1012#ifdef HAVE_EM_AARCH64_MACRO
1013 GElf_Ehdr eh_mem;
1014 GElf_Ehdr* elf_header = gelf_getehdr(elf_handle, &eh_mem);
1015 return (elf_header && elf_header->e_machine == EM_AARCH64);
1016#else
1017 return false;
1018#endif
1019}
1020
1021/// Test if the endianness of the current binary is Big Endian.
1022///
1023/// https://en.wikipedia.org/wiki/Endianness.
1024///
1025/// @param elf_handle the ELF handle to consider.
1026///
1027/// @return true iff the current binary is Big Endian.
1028bool
1030{
1031 GElf_Ehdr elf_header;
1032 gelf_getehdr(elf_handle, &elf_header);
1033
1034 bool is_big_endian = (elf_header.e_ident[EI_DATA] == ELFDATA2MSB);
1035
1036 if (!is_big_endian)
1037 ABG_ASSERT(elf_header.e_ident[EI_DATA] == ELFDATA2LSB);
1038
1039 return is_big_endian;
1040}
1041
1042/// Read N bytes and convert their value into an integer type T.
1043///
1044/// Note that N cannot be bigger than 8 for now. The type passed needs to be at
1045/// least of the size of number_of_bytes.
1046///
1047/// @param bytes the array of bytes to read the next 8 bytes from.
1048/// Note that this array must be at least 8 bytes long.
1049///
1050/// @param number_of_bytes the number of bytes to read. This number
1051/// cannot be bigger than 8.
1052///
1053/// @param is_big_endian if true, read the 8 bytes in Big Endian
1054/// mode, otherwise, read them in Little Endian.
1055///
1056/// @param result where to store the resuting integer that was read.
1057///
1058///
1059/// @param true if the 8 bytes could be read, false otherwise.
1060template <typename T>
1061bool
1062read_int_from_array_of_bytes(const uint8_t* bytes,
1063 unsigned char number_of_bytes,
1064 bool is_big_endian,
1065 T& result)
1066{
1067 if (!bytes)
1068 return false;
1069
1070 ABG_ASSERT(number_of_bytes <= 8);
1071 ABG_ASSERT(number_of_bytes <= sizeof(T));
1072
1073 T res = 0;
1074
1075 const uint8_t* cur = bytes;
1076 if (is_big_endian)
1077 {
1078 // In Big Endian, the most significant byte is at the lowest
1079 // address.
1080 const uint8_t* msb = cur;
1081 res = *msb;
1082
1083 // Now read the remaining least significant bytes.
1084 for (uint i = 1; i < number_of_bytes; ++i)
1085 res = (res << 8) | ((T)msb[i]);
1086 }
1087 else
1088 {
1089 // In Little Endian, the least significant byte is at the
1090 // lowest address.
1091 const uint8_t* lsb = cur;
1092 res = *lsb;
1093 // Now read the remaining most significant bytes.
1094 for (uint i = 1; i < number_of_bytes; ++i)
1095 res = res | (((T)lsb[i]) << i * 8);
1096 }
1097
1098 result = res;
1099 return true;
1100}
1101
1102/// Read 8 bytes and convert their value into an uint64_t.
1103///
1104/// @param bytes the array of bytes to read the next 8 bytes from.
1105/// Note that this array must be at least 8 bytes long.
1106///
1107/// @param result where to store the resuting uint64_t that was read.
1108///
1109/// @param is_big_endian if true, read the 8 bytes in Big Endian
1110/// mode, otherwise, read them in Little Endian.
1111///
1112/// @param true if the 8 bytes could be read, false otherwise.
1113bool
1115 bool is_big_endian,
1116 uint64_t& result)
1117{
1118 return read_int_from_array_of_bytes(bytes, 8, is_big_endian, result);
1119}
1120
1121
1122/// Lookup the address of the function entry point that corresponds
1123/// to the address of a given function descriptor.
1124///
1125/// On PPC64, a function pointer is the address of a function
1126/// descriptor. Function descriptors are located in the .opd
1127/// section. Each function descriptor is a triplet of three
1128/// addresses, each one on 64 bits. Among those three address only
1129/// the first one is of any interest to us: the address of the entry
1130/// point of the function.
1131///
1132/// This function returns the address of the entry point of the
1133/// function whose descriptor's address is given.
1134///
1135/// http://refspecs.linuxfoundation.org/ELF/ppc64/PPC-elf64abi.html#FUNC-DES
1136///
1137/// https://www.ibm.com/developerworks/community/blogs/5894415f-be62-4bc0-81c5-3956e82276f3/entry/deeply_understand_64_bit_powerpc_elf_abi_function_descriptors?lang=en
1138///
1139/// @param fn_desc_address the address of the function descriptor to
1140/// consider.
1141///
1142/// @return the address of the entry point of the function whose
1143/// descriptor has the address @p fn_desc_address. If there is no
1144/// .opd section (e.g because we are not on ppc64) or more generally
1145/// if the function descriptor could not be found then this function
1146/// just returns the address of the fuction descriptor.
1147GElf_Addr
1148lookup_ppc64_elf_fn_entry_point_address(Elf* elf_handle, GElf_Addr fn_desc_address)
1149{
1150 if (!elf_handle)
1151 return fn_desc_address;
1152
1153 if (!architecture_is_ppc64(elf_handle))
1154 return fn_desc_address;
1155
1156 bool is_big_endian = architecture_is_big_endian(elf_handle);
1157
1158 Elf_Scn* opd_section = find_opd_section(elf_handle);
1159 if (!opd_section)
1160 return fn_desc_address;
1161
1162 GElf_Shdr header_mem;
1163 // The section header of the .opd section.
1164 GElf_Shdr* opd_sheader = gelf_getshdr(opd_section, &header_mem);
1165
1166 // The offset of the function descriptor entry, in the .opd
1167 // section.
1168 size_t fn_desc_offset = fn_desc_address - opd_sheader->sh_addr;
1169 Elf_Data* elf_data = elf_rawdata(opd_section, 0);
1170
1171 // Ensure that the opd_section has at least 8 bytes, starting from
1172 // the offset we want read the data from.
1173 if (elf_data->d_size <= fn_desc_offset + 8)
1174 return fn_desc_address;
1175
1176 // A pointer to the data of the .opd section, that we can actually
1177 // do something with.
1178 uint8_t* bytes = (uint8_t*)elf_data->d_buf;
1179
1180 // The resulting address we are looking for is going to be formed
1181 // in this variable.
1182 GElf_Addr result = 0;
1183 ABG_ASSERT(read_uint64_from_array_of_bytes(bytes + fn_desc_offset,
1184 is_big_endian, result));
1185
1186 return result;
1187}
1188
1189/// Test if the ELF binary denoted by a given ELF handle is a Linux
1190/// Kernel Module.
1191///
1192/// @param elf_handle the ELF handle to consider.
1193///
1194/// @return true iff the binary denoted by @p elf_handle is a Linux
1195/// kernel module.
1196bool
1198{
1199 return (find_section(elf_handle, ".modinfo", SHT_PROGBITS)
1200 && find_section(elf_handle,
1201 ".gnu.linkonce.this_module",
1202 SHT_PROGBITS));
1203}
1204
1205/// Test if the ELF binary denoted by a given ELF handle is a Linux
1206/// Kernel binary (either vmlinux or a kernel module).
1207///
1208/// @param elf_handle the ELF handle to consider.
1209///
1210/// @return true iff the binary denoted by @p elf_handle is a Linux
1211/// kernel binary
1212bool
1213is_linux_kernel(Elf *elf_handle)
1214{
1215 return (find_section(elf_handle,
1216 "__ksymtab_strings",
1217 SHT_PROGBITS)
1218 || is_linux_kernel_module(elf_handle));
1219}
1220
1221/// Get the address at which a given binary is loaded in memory.
1222///
1223/// @param elf_handle the elf handle for the binary to consider.
1224///
1225/// @param load_address the address where the binary is loaded. This
1226/// is set by the function iff it returns true.
1227///
1228/// @return true if the function could get the binary load address
1229/// and assign @p load_address to it.
1230bool
1231get_binary_load_address(Elf* elf_handle, GElf_Addr& load_address)
1232{
1233 GElf_Ehdr elf_header;
1234 gelf_getehdr(elf_handle, &elf_header);
1235 size_t num_segments = elf_header.e_phnum;
1236 GElf_Phdr *program_header = NULL;
1237 GElf_Addr result;
1238 bool found_loaded_segment = false;
1239 GElf_Phdr ph_mem;
1240
1241 for (unsigned i = 0; i < num_segments; ++i)
1242 {
1243 program_header = gelf_getphdr(elf_handle, i, &ph_mem);
1244 if (program_header && program_header->p_type == PT_LOAD)
1245 {
1246 if (!found_loaded_segment)
1247 {
1248 result = program_header->p_vaddr;
1249 found_loaded_segment = true;
1250 }
1251
1252 if (program_header->p_vaddr < result)
1253 // The resulting load address we want is the lowest
1254 // load address of all the loaded segments.
1255 result = program_header->p_vaddr;
1256 }
1257 }
1258
1259 if (found_loaded_segment)
1260 {
1261 load_address = result;
1262 return true;
1263 }
1264 return false;
1265}
1266
1267/// Return the size of a word for the current architecture.
1268///
1269/// @param elf_handle the ELF handle to consider.
1270///
1271/// @return the size of a word.
1272unsigned char
1274{
1275 unsigned char word_size = 0;
1276 GElf_Ehdr elf_header;
1277 gelf_getehdr(elf_handle, &elf_header);
1278 if (elf_header.e_ident[EI_CLASS] == ELFCLASS32)
1279 word_size = 4;
1280 else if (elf_header.e_ident[EI_CLASS] == ELFCLASS64)
1281 word_size = 8;
1282 else
1284 return word_size;
1285}
1286
1287/// Test if the elf file being read is an executable.
1288///
1289/// @param elf_handle the ELF handle to consider.
1290///
1291/// @return true iff the elf file being read is an / executable.
1292bool
1293is_executable(Elf* elf_handle)
1294{
1295 GElf_Ehdr elf_header;
1296 gelf_getehdr(elf_handle, &elf_header);
1297 return elf_header.e_type == ET_EXEC;
1298}
1299
1300/// Test if the elf file being read is a dynamic shared / object.
1301///
1302/// @param elf_handle the ELF handle to consider.
1303///
1304/// @return true iff the elf file being read is a / dynamic shared object.
1305bool
1306is_dso(Elf* elf_handle)
1307{
1308 GElf_Ehdr elf_header;
1309 gelf_getehdr(elf_handle, &elf_header);
1310 return elf_header.e_type == ET_DYN;
1311}
1312
1313/// Translate a section-relative symbol address (i.e, symbol value)
1314/// into an absolute symbol address by adding the address of the
1315/// section the symbol belongs to, to the address value.
1316///
1317/// This is useful when looking at symbol values coming from
1318/// relocatable files (of ET_REL kind). If the binary is not
1319/// ET_REL, then the function does nothing and returns the input
1320/// address unchanged.
1321///
1322/// @param elf_handle the elf handle for the binary to consider.
1323///
1324/// @param sym the symbol whose address to possibly needs to be
1325/// translated.
1326///
1327/// @return the section-relative address, translated into an
1328/// absolute address, if @p sym is from an ET_REL binary.
1329/// Otherwise, return the address of @p sym, unchanged.
1330GElf_Addr
1331maybe_adjust_et_rel_sym_addr_to_abs_addr(Elf* elf_handle, GElf_Sym* sym)
1332{
1333 Elf_Scn* symbol_section = elf_getscn(elf_handle, sym->st_shndx);
1334 GElf_Addr addr = sym->st_value;
1335
1336 if (!symbol_section)
1337 return addr;
1338
1339 GElf_Ehdr elf_header;
1340 if (!gelf_getehdr(elf_handle, &elf_header))
1341 return addr;
1342
1343 if (elf_header.e_type != ET_REL)
1344 return addr;
1345
1346 GElf_Shdr section_header;
1347 if (!gelf_getshdr(symbol_section, &section_header))
1348 return addr;
1349
1350 return addr + section_header.sh_addr;
1351}
1352
1353/// Test if a given address is in a given section.
1354///
1355/// @param addr the address to consider.
1356///
1357/// @param section the section to consider.
1358///
1359/// @return true iff @p addr is in section @p section.
1360bool
1361address_is_in_section(Dwarf_Addr addr, Elf_Scn* section)
1362{
1363 if (!section)
1364 return false;
1365
1366 GElf_Shdr sheader_mem;
1367 GElf_Shdr* sheader = gelf_getshdr(section, &sheader_mem);
1368
1369 if (sheader->sh_addr <= addr && addr <= sheader->sh_addr + sheader->sh_size)
1370 return true;
1371
1372 return false;
1373}
1374
1375/// Return true if an address is in the ".opd" section that is
1376/// present on the ppc64 platform.
1377///
1378/// @param addr the address to consider.
1379///
1380/// @return true iff @p addr designates a word that is in the ".opd"
1381/// section.
1382bool
1383address_is_in_opd_section(Elf* elf_handle, Dwarf_Addr addr)
1384{
1385 Elf_Scn * opd_section = find_opd_section(elf_handle);
1386 if (!opd_section)
1387 return false;
1388 if (address_is_in_section(addr, opd_section))
1389 return true;
1390 return false;
1391}
1392
1393/// Get data tag information of an ELF file by looking up into its
1394/// dynamic segment
1395///
1396/// @param elf the elf handle to use for the query.
1397///
1398/// @param dt_tag data tag to look for in dynamic segment
1399/// @param dt_tag_data vector of found information for a given @p data_tag
1400///
1401/// @return true iff data tag @p data_tag was found
1402bool
1404 Elf64_Sxword data_tag,
1405 vector<string>& dt_tag_data)
1406{
1407 size_t num_prog_headers = 0;
1408 bool found = false;
1409 if (elf_getphdrnum(elf, &num_prog_headers) < 0)
1410 return found;
1411
1412 // Cycle through each program header.
1413 for (size_t i = 0; i < num_prog_headers; ++i)
1414 {
1415 GElf_Phdr phdr_mem;
1416 GElf_Phdr *phdr = gelf_getphdr(elf, i, &phdr_mem);
1417 if (phdr == NULL || phdr->p_type != PT_DYNAMIC)
1418 continue;
1419
1420 // Poke at the dynamic segment like a section, so that we can
1421 // get its section header information; also we'd like to read
1422 // the data of the segment by using elf_getdata() but that
1423 // function needs a Elf_Scn data structure to act on.
1424 // Elfutils doesn't really have any particular function to
1425 // access segment data, other than the functions used to
1426 // access section data.
1427 Elf_Scn *dynamic_section = gelf_offscn(elf, phdr->p_offset);
1428 GElf_Shdr shdr_mem;
1429 GElf_Shdr *dynamic_section_header = gelf_getshdr(dynamic_section,
1430 &shdr_mem);
1431 if (dynamic_section_header == NULL
1432 || dynamic_section_header->sh_type != SHT_DYNAMIC)
1433 continue;
1434
1435 // Get data of the dynamic segment (seen as a section).
1436 Elf_Data *data = elf_getdata(dynamic_section, NULL);
1437 if (data == NULL)
1438 continue;
1439
1440 // Get the index of the section headers string table.
1441 size_t string_table_index = 0;
1442 ABG_ASSERT (elf_getshdrstrndx(elf, &string_table_index) >= 0);
1443
1444 size_t dynamic_section_header_entry_size = gelf_fsize(elf,
1445 ELF_T_DYN, 1,
1446 EV_CURRENT);
1447
1448 GElf_Shdr link_mem;
1449 GElf_Shdr *link =
1450 gelf_getshdr(elf_getscn(elf,
1451 dynamic_section_header->sh_link),
1452 &link_mem);
1453 ABG_ASSERT(link != NULL);
1454
1455 size_t num_dynamic_section_entries =
1456 dynamic_section_header->sh_size / dynamic_section_header_entry_size;
1457
1458 // Now walk through all the DT_* data tags that are in the
1459 // segment/section
1460 for (size_t j = 0; j < num_dynamic_section_entries; ++j)
1461 {
1462 GElf_Dyn dynamic_section_mem;
1463 GElf_Dyn *dynamic_section = gelf_getdyn(data,
1464 j,
1465 &dynamic_section_mem);
1466 if (dynamic_section->d_tag == data_tag)
1467 {
1468 dt_tag_data.push_back(elf_strptr(elf,
1469 dynamic_section_header->sh_link,
1470 dynamic_section->d_un.d_val));
1471 found = true;
1472 }
1473 }
1474 }
1475 return found;
1476}
1477
1478const Dwfl_Callbacks&
1479initialize_dwfl_callbacks(Dwfl_Callbacks& cb,
1480 char** debug_info_root_path)
1481{
1482 cb.find_debuginfo = dwfl_standard_find_debuginfo;
1483 cb.section_address = dwfl_offline_section_address;
1484 cb.debuginfo_path = debug_info_root_path;
1485 return cb;
1486}
1487
1488dwfl_sptr
1489create_new_dwfl_handle(Dwfl_Callbacks& cb)
1490{
1491 dwfl_sptr handle(dwfl_begin(&cb), dwfl_deleter());
1492 return handle;
1493}
1494
1495/// Fetch the SONAME ELF property from an ELF binary file.
1496///
1497/// @param path The path to the elf file to consider.
1498///
1499/// @param soname out parameter. Set to the SONAME property of the
1500/// binary file, if it present in the ELF file.
1501///
1502/// return false if an error occured while looking for the SONAME
1503/// property in the binary, true otherwise.
1504bool
1505get_soname_of_elf_file(const string& path, string &soname)
1506{
1507
1508 int fd = open(path.c_str(), O_RDONLY);
1509 if (fd == -1)
1510 return false;
1511
1512 elf_version (EV_CURRENT);
1513 Elf* elf = elf_begin (fd, ELF_C_READ_MMAP, NULL);
1514
1515 GElf_Ehdr ehdr_mem;
1516 GElf_Ehdr* ehdr = gelf_getehdr (elf, &ehdr_mem);
1517 if (ehdr == NULL)
1518 return false;
1519
1520 for (int i = 0; i < ehdr->e_phnum; ++i)
1521 {
1522 GElf_Phdr phdr_mem;
1523 GElf_Phdr* phdr = gelf_getphdr (elf, i, &phdr_mem);
1524
1525 if (phdr != NULL && phdr->p_type == PT_DYNAMIC)
1526 {
1527 Elf_Scn* scn = gelf_offscn (elf, phdr->p_offset);
1528 GElf_Shdr shdr_mem;
1529 GElf_Shdr* shdr = gelf_getshdr (scn, &shdr_mem);
1530 if (!(shdr == NULL || (shdr->sh_type == SHT_DYNAMIC
1531 || shdr->sh_type == SHT_PROGBITS)))
1532 // This program header doesn't look like one we are
1533 // looking for. Skip to the next.
1534 continue;
1535
1536 size_t entsize = (shdr != NULL && shdr->sh_entsize != 0
1537 ? shdr->sh_entsize
1538 : gelf_fsize (elf, ELF_T_DYN, 1, EV_CURRENT));
1539 int maxcnt = (shdr != NULL
1540 ? shdr->sh_size / entsize : INT_MAX);
1541 Elf_Data* data = elf_getdata (scn, NULL);
1542 if (data == NULL)
1543 break;
1544
1545 for (int cnt = 0; cnt < maxcnt; ++cnt)
1546 {
1547 GElf_Dyn dynmem;
1548 GElf_Dyn* dyn = gelf_getdyn (data, cnt, &dynmem);
1549 if (dyn == NULL)
1550 continue;
1551
1552 if (dyn->d_tag == DT_NULL)
1553 break;
1554
1555 if (dyn->d_tag != DT_SONAME)
1556 continue;
1557
1558 soname = elf_strptr (elf, shdr->sh_link, dyn->d_un.d_val);
1559 break;
1560 }
1561 break;
1562 }
1563 }
1564
1565 elf_end(elf);
1566 close(fd);
1567
1568 return true;
1569}
1570
1571} // end namespace elf_helpers
1572} // 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 get_crc_for_symbol(Elf *elf_handle, GElf_Sym *crc_symbol, uint32_t &crc_value)
Return the CRC from the "__crc_" symbol.
unsigned char get_architecture_word_size(Elf *elf_handle)
Return the size of a word for the current architecture.
bool get_version_definition_for_versym(Elf *elf_handle, GElf_Versym *versym, Elf_Scn *verdef_section, elf_symbol::version &version)
Get the version definition (from the SHT_GNU_verdef section) of a given symbol represented by a point...
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 address_is_in_opd_section(Elf *elf_handle, Dwarf_Addr addr)
Return true if an address is in the ".opd" section that is present on the ppc64 platform.
bool architecture_is_arm64(Elf *elf_handle)
Test if the architecture of the current binary is arm64.
Elf_Scn * find_relocation_section(Elf *elf_handle, Elf_Scn *target_section)
Return the .rel{a,} section corresponding to a given section.
bool read_uint64_from_array_of_bytes(const uint8_t *bytes, bool is_big_endian, uint64_t &result)
Read 8 bytes and convert their value into an uint64_t.
bool read_int_from_array_of_bytes(const uint8_t *bytes, unsigned char number_of_bytes, bool is_big_endian, T &result)
Read N bytes and convert their value into an integer type T.
bool architecture_is_big_endian(Elf *elf_handle)
Test if the endianness of the current binary is Big Endian.
bool is_dso(Elf *elf_handle)
Test if the elf file being read is a dynamic shared / object.
bool architecture_is_ppc32(Elf *elf_handle)
Test if the architecture of the current binary is ppc32.
bool get_binary_load_address(Elf *elf_handle, GElf_Addr &load_address)
Get the address at which a given binary is loaded in memory.
GElf_Addr maybe_adjust_et_rel_sym_addr_to_abs_addr(Elf *elf_handle, GElf_Sym *sym)
Translate a section-relative symbol address (i.e, symbol value) into an absolute symbol address by ad...
bool get_version_needed_for_versym(Elf *elf_handle, GElf_Versym *versym, Elf_Scn *verneed_section, elf_symbol::version &version)
Get the version needed (from the SHT_GNU_verneed section) to resolve an undefined symbol represented ...
Elf_Scn * find_strtab_for_symtab_section(Elf *elf_handle, Elf_Scn *symtab_section)
Return the string table used by the given symbol table.
bool get_soname_of_elf_file(const string &path, string &soname)
Fetch the SONAME ELF property from an ELF binary file.
bool get_version_for_symbol(Elf *elf_handle, size_t symbol_index, bool get_def_version, elf_symbol::version &version)
Return the version for a symbol that is at a given index in its SHT_SYMTAB section.
elf_symbol::binding stb_to_elf_symbol_binding(unsigned char stb)
Convert an elf symbol binding (given by the ELF{32,64}_ST_BIND macros) into an elf_symbol::binding va...
Elf_Scn * find_ksymtab_gpl_section(Elf *elf_handle)
Return the __ksymtab_gpl section of a linux kernel ELF file (either a vmlinux binary or a kernel modu...
Elf_Scn * find_ksymtab_section(Elf *elf_handle)
Return the __ksymtab section of a linux kernel ELF file (either a vmlinux binary or a kernel module).
Elf_Scn * find_symtab_section(Elf *elf_handle)
Find and return the .symtab section.
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_text_section(Elf *elf_handle)
Find and return the .text section.
bool architecture_is_ppc64(Elf *elf_handle)
Test if the architecture of the current binary is ppc64.
Elf_Scn * find_rodata_section(Elf *elf_handle)
Find and return the .rodata section.
Elf_Scn * find_opd_section(Elf *elf_handle)
Return the "Official Procedure descriptors section." This section is named .opd, and is usually prese...
bool is_executable(Elf *elf_handle)
Test if the elf file being read is an executable.
Elf_Scn * find_data1_section(Elf *elf_handle)
Find and return the .data1 section.
GElf_Addr lookup_ppc64_elf_fn_entry_point_address(Elf *elf_handle, GElf_Addr fn_desc_address)
Lookup the address of the function entry point that corresponds to the address of a given function de...
bool address_is_in_section(Dwarf_Addr addr, Elf_Scn *section)
Test if a given address is in a given section.
elf_symbol::visibility stv_to_elf_symbol_visibility(unsigned char stv)
Convert an ELF symbol visiblity given by the symbols ->st_other data member as returned by the GELF_S...
bool find_symbol_table_section_index(Elf *elf_handle, size_t &symtab_index)
Find the index (in the section headers table) of the symbol table section.
bool get_symbol_versionning_sections(Elf *elf_handle, Elf_Scn *&versym_section, Elf_Scn *&verdef_section, Elf_Scn *&verneed_section)
Return the SHT_GNU_versym, SHT_GNU_verdef and SHT_GNU_verneed sections that are involved in symbol ve...
Elf_Scn * find_bss_section(Elf *elf_handle)
Find and return the .bss section.
Elf_Scn * find_dynsym_section(Elf *elf_handle)
Find and return the .symtab section.
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_symbol::type stt_to_elf_symbol_type(unsigned char stt)
Convert an elf symbol type (given by the ELF{32,64}_ST_TYPE macros) into an elf_symbol::type value.
bool architecture_is_arm32(Elf *elf_handle)
Test if the architecture of the current binary is arm32.
Elf_Scn * find_symbol_table_section(Elf *elf_handle)
Find the symbol table.
Elf_Scn * find_data_section(Elf *elf_handle)
Find and return the .data section.
bool is_linux_kernel_module(Elf *elf_handle)
Test if the ELF binary denoted by a given ELF handle is a Linux Kernel Module.
Elf_Scn * find_ksymtab_strings_section(Elf *elf_handle)
Find the __ksymtab_strings section of a Linux kernel binary.
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...
hash_table_kind find_hash_table_section_index(Elf *elf_handle, size_t &ht_section_index, size_t &symtab_section_index)
Get the offset offset of the hash table section.
This contains a set of ELF utilities used by the dwarf reader.
#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
#define ABG_ASSERT_NOT_REACHED
A macro that expands to aborting the program when executed.
The abstraction of the version of an ELF symbol.
Definition: abg-ir.h:1232
bool is_default() const
Getter for the 'is_default' property of the version.
Definition: abg-ir.cc:3219
const string & str() const
Getter for the version name.
Definition: abg-ir.cc:3205
binding
The binding of a symbol.
Definition: abg-ir.h:978
type
The type of a symbol.
Definition: abg-ir.h:965
visibility
The visibility of the symbol.
Definition: abg-ir.h:987
Toplevel namespace for libabigail.