1 /*#############################################################################
3 # Pakfire - The IPFire package management system #
4 # Copyright (C) 2025 Pakfire development team #
6 # This program is free software: you can redistribute it and/or modify #
7 # it under the terms of the GNU General Public License as published by #
8 # the Free Software Foundation, either version 3 of the License, or #
9 # (at your option) any later version. #
11 # This program is distributed in the hope that it will be useful, #
12 # but WITHOUT ANY WARRANTY; without even the implied warranty of #
13 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the #
14 # GNU General Public License for more details. #
16 # You should have received a copy of the GNU General Public License #
17 # along with this program. If not, see <http://www.gnu.org/licenses/>. #
19 #############################################################################*/
24 #include <pakfire/ctx.h>
25 #include <pakfire/elf.h>
26 #include <pakfire/file.h>
27 #include <pakfire/hex.h>
28 #include <pakfire/logging.h>
29 #include <pakfire/path.h>
30 #include <pakfire/string.h>
34 #include <elfutils/libdwelf.h>
37 struct pakfire_ctx
* ctx
;
52 // Number of Program Headers
59 const char* interpreter
;
68 const char* debuglink
;
71 static int pakfire_elf_init_libelf(struct pakfire_ctx
* ctx
) {
73 if (elf_version(EV_CURRENT
) == EV_NONE
) {
74 ERROR(ctx
, "Could not initialize libelf: %s\n", elf_errmsg(-1));
81 static int pakfire_elf_open_elf(struct pakfire_elf
* self
) {
82 GElf_Ehdr
* ehdr
= NULL
;
85 // Make sure libelf is initialized
86 r
= pakfire_elf_init_libelf(self
->ctx
);
91 self
->elf
= elf_begin(self
->fd
, ELF_C_READ
, NULL
);
93 ERROR(self
->ctx
, "Could not open ELF file: %m\n");
97 // Is this actually an ELF file?
98 switch (elf_kind(self
->elf
)) {
102 // Fail for everything else
107 // Fetch the ELF header
108 ehdr
= gelf_getehdr(self
->elf
, &self
->ehdr
);
110 ERROR(self
->ctx
, "Could not fetch the ELF header: %s\n", elf_errmsg(-1));
114 // Fetch the total numbers of program headers
115 r
= elf_getphdrnum(self
->elf
, &self
->phnum
);
118 "Could not fetch number of program headers: %s\n", elf_errmsg(-1));
123 r
= elf_getshdrstrndx(self
->elf
, &self
->shstrndx
);
125 ERROR(self
->ctx
, "elf_getshdrstrndx() failed: %s\n", elf_errmsg(-1));
132 static void pakfire_elf_free(struct pakfire_elf
* self
) {
134 free(self
->build_id
);
140 pakfire_ctx_unref(self
->ctx
);
144 int pakfire_elf_open(struct pakfire_elf
** elf
,
145 struct pakfire_ctx
* ctx
, const char* path
, int fd
) {
146 struct pakfire_elf
* self
= NULL
;
149 // Require a valid file descriptor
153 // Allocate a new object
154 self
= calloc(1, sizeof(*self
));
158 // Store a reference to the context
159 self
->ctx
= pakfire_ctx_ref(ctx
);
161 // Initialize the reference counter
165 r
= pakfire_string_set(self
->path
, path
);
169 // Store the file descriptor
172 ERROR(self
->ctx
, "Could not duplicate file descriptor: %m\n");
178 r
= pakfire_elf_open_elf(self
);
182 // Return the pointer
188 pakfire_elf_free(self
);
193 int pakfire_elf_open_file(struct pakfire_elf
** elf
,
194 struct pakfire_ctx
* ctx
, struct pakfire_file
* file
) {
195 const char* path
= NULL
;
200 path
= pakfire_file_get_path(file
);
203 fd
= pakfire_file_open(file
, 0);
207 // Open the ELF object
208 r
= pakfire_elf_open(elf
, ctx
, path
, fd
);
219 struct pakfire_elf
* pakfire_elf_ref(struct pakfire_elf
* self
) {
225 struct pakfire_elf
* pakfire_elf_unref(struct pakfire_elf
* self
) {
226 if (--self
->nrefs
> 0)
229 pakfire_elf_free(self
);
233 const char* pakfire_elf_path(struct pakfire_elf
* self
) {
237 int pakfire_elf_type(struct pakfire_elf
* self
) {
238 return self
->ehdr
.e_type
;
241 int pakfire_elf_machine(struct pakfire_elf
* self
) {
242 return self
->ehdr
.e_machine
;
245 int pakfire_elf_is_elf64(struct pakfire_elf
* self
) {
246 return self
->ehdr
.e_ident
[EI_CLASS
] = ELFCLASS64
;
249 int pakfire_elf_endianess(struct pakfire_elf
* self
) {
250 return self
->ehdr
.e_ident
[EI_DATA
];
253 const char* pakfire_elf_build_id(struct pakfire_elf
* self
) {
254 const void* buffer
= NULL
;
257 if (!self
->build_id
) {
258 // Extract the GNU Build ID
259 length
= dwelf_elf_gnu_build_id(self
->elf
, &buffer
);
261 ERROR(self
->ctx
, "Could not read the GNU Build ID from %s: %s\n",
262 self
->path
, elf_errmsg(-1));
266 // Return NULL if there is no Build ID
270 // Convert the Build ID to hex
271 self
->build_id
= __pakfire_hexlify(buffer
, length
);
272 if (!self
->build_id
) {
273 ERROR(self
->ctx
, "Could not convert the Build ID into hex format: %m\n");
277 DEBUG(self
->ctx
, "%s has Build ID %s\n", self
->path
, self
->build_id
);
280 return self
->build_id
;
283 const char* pakfire_elf_debuglink(struct pakfire_elf
* self
) {
286 // Fetch the debug link
287 if (!self
->debuglink
) {
288 self
->debuglink
= dwelf_elf_gnu_debuglink(self
->elf
, &crc32
);
289 if (!self
->debuglink
)
292 DEBUG(self
->ctx
, "%s has debug link pointing at %s\n",
293 self
->path
, self
->debuglink
);
296 return self
->debuglink
;
299 typedef int (*pakfire_elf_foreach_program_header_callback
)
300 (struct pakfire_elf
* self
, const GElf_Phdr
* phdr
, void* data
);
302 static int pakfire_elf_foreach_program_header(struct pakfire_elf
* self
,
303 pakfire_elf_foreach_program_header_callback callback
, void* data
) {
307 // Walk through all program headers
308 for (unsigned int i
= 0; i
< self
->phnum
; i
++) {
309 if (!gelf_getphdr(self
->elf
, i
, &phdr
)) {
310 ERROR(self
->ctx
, "Could not parse program header: %s\n", elf_errmsg(-1));
315 r
= callback(self
, &phdr
, data
);
323 static int pakfire_elf_get_section(struct pakfire_elf
* self
,
324 const Elf64_Word type
, const char* name
, Elf_Scn
** section
, GElf_Shdr
* header
, Elf_Data
** data
) {
325 const char* sname
= NULL
;
329 // Walk through all sections
331 s
= elf_nextscn(self
->elf
, s
);
335 // Fetch the section header
336 gelf_getshdr(s
, &shdr
);
338 // Return any matching sections
339 if (shdr
.sh_type
== type
) {
340 // If we have a name, check it too
342 sname
= elf_strptr(self
->elf
, self
->shstrndx
, shdr
.sh_name
);
346 // Skip if the name does not match
347 if (!pakfire_string_equals(name
, sname
))
351 // Return a pointer to the section
354 // Send header if requested
356 gelf_getshdr(s
, header
);
358 // Send data if requested
360 *data
= elf_getdata(s
, NULL
);
370 typedef int (*pakfire_elf_foreach_section_callback
)(struct pakfire_elf
* self
,
371 Elf_Scn
* section
, const GElf_Shdr
* shdr
, void* data
);
373 static int pakfire_elf_foreach_section(struct pakfire_elf
* self
,
374 const Elf64_Word type
, pakfire_elf_foreach_section_callback callback
, void* data
) {
375 Elf_Scn
* section
= NULL
;
379 // Walk through all sections
381 section
= elf_nextscn(self
->elf
, section
);
385 // Fetch the section header
386 if (!gelf_getshdr(section
, &shdr
)) {
387 ERROR(self
->ctx
, "%s: Could not fetch the ELF section header: %s\n",
388 self
->path
, elf_errmsg(-1));
392 // Skip sections that don't match
393 if (type
&& shdr
.sh_type
!= type
)
397 r
= callback(self
, section
, &shdr
, data
);
405 typedef int (*pakfire_elf_dyn_walk_callback
)
406 (struct pakfire_elf
* self
, const GElf_Shdr
* shdr
, const GElf_Dyn
* dyn
, void* data
);
408 static int pakfire_elf_dyn_walk(struct pakfire_elf
* self
,
409 pakfire_elf_dyn_walk_callback callback
, void* data
) {
410 Elf_Scn
* dynamic
= NULL
;
412 Elf_Data
* elf_data
= NULL
;
416 // Find the dynamic linking information
417 r
= pakfire_elf_get_section(self
, SHT_DYNAMIC
, NULL
, &dynamic
, &shdr
, &elf_data
);
419 DEBUG(self
->ctx
, "%s does not have a dynamic section\n", self
->path
);
423 // Walk through all entries...
424 for (unsigned int i
= 0; ; i
++) {
425 // Fetch the next entry
426 if (!gelf_getdyn(elf_data
, i
, &dyn
))
430 r
= callback(self
, &shdr
, &dyn
, data
);
438 static int pakfire_elf_fetch_interpreter(
439 struct pakfire_elf
* self
, const GElf_Phdr
* phdr
, void* data
) {
440 Elf_Data
* chunk
= NULL
;
442 switch (phdr
->p_type
) {
444 chunk
= elf_getdata_rawchunk(self
->elf
, phdr
->p_offset
, phdr
->p_filesz
, ELF_T_BYTE
);
445 if (!chunk
|| !chunk
->d_buf
) {
446 ERROR(self
->ctx
, "Failed to fetch the interpreter\n");
450 // Store the interpreter
451 self
->interpreter
= (const char*)chunk
->d_buf
;
461 const char* pakfire_elf_interpreter(struct pakfire_elf
* self
) {
464 // Fetch the interpreter if not available
465 if (!self
->interpreter
) {
466 r
= pakfire_elf_foreach_program_header(self
, pakfire_elf_fetch_interpreter
, NULL
);
471 return self
->interpreter
;
474 static int pakfire_elf_fetch_soname(struct pakfire_elf
* self
,
475 const GElf_Shdr
* shdr
, const GElf_Dyn
* dyn
, void* data
) {
476 switch (dyn
->d_tag
) {
478 self
->soname
= elf_strptr(self
->elf
, shdr
->sh_link
, dyn
->d_un
.d_val
);
486 const char* pakfire_elf_soname(struct pakfire_elf
* self
) {
489 // Fetch the SONAME if not available
491 r
= pakfire_elf_dyn_walk(self
, pakfire_elf_fetch_soname
, NULL
);
499 int pakfire_elf_is_pie(struct pakfire_elf
* self
) {
500 switch (pakfire_elf_type(self
)) {
501 // Shared Object files are good
505 // Everything else is bad
513 int pakfire_elf_has_ssp(struct pakfire_elf
* self
) {
514 GElf_Sym symbol
= {};
518 Elf_Scn
* dynsym
= NULL
;
519 GElf_Shdr symhdr
= {};
520 Elf_Data
* symdata
= NULL
;
523 Elf_Scn
* dynstr
= NULL
;
524 GElf_Shdr strhdr
= {};
525 Elf_Data
* strdata
= NULL
;
528 r
= pakfire_elf_get_section(self
, SHT_DYNSYM
, NULL
, &dynsym
, &symhdr
, &symdata
);
530 DEBUG(self
->ctx
, "%s has no .dynsym section\n", self
->path
);
535 r
= pakfire_elf_get_section(self
, SHT_STRTAB
, ".dynstr", &dynstr
, &strhdr
, &strdata
);
537 DEBUG(self
->ctx
, "%s has no .dynstr section\n", self
->path
);
541 // Count any global functions
544 // Walk through all symbols
545 for (unsigned int i
= 0; i
< symhdr
.sh_size
/ symhdr
.sh_entsize
; i
++) {
546 gelf_getsym(symdata
, i
, &symbol
);
548 // Fetch the symbol name
549 const char* name
= elf_strptr(self
->elf
, elf_ndxscn(dynstr
), symbol
.st_name
);
551 // Skip empty section names
555 // Exit if there is a symbol called "__stack_chk_fail"
556 if (pakfire_string_startswith(name
, "__stack_chk_fail"))
559 // Or if the symbol is called __stack_chk_guard
560 else if (pakfire_string_startswith(name
, "__stack_chk_guard"))
563 // Or if the symbol is called __intel_security_cookie
564 else if (pakfire_string_startswith(name
, "__intel_security_cookie"))
567 // Count any global functions
568 if ((ELF64_ST_BIND(symbol
.st_info
) == STB_GLOBAL
) &&
569 (ELF64_ST_TYPE(symbol
.st_info
) == STT_FUNC
))
573 // If we have something that does not have an exported function, we just assume yes
575 DEBUG(self
->ctx
, "%s has no functions. Skipping SSP check.\n", self
->path
);
582 static int pakfire_elf_check_execstack(
583 struct pakfire_elf
* self
, const GElf_Phdr
* phdr
, void* data
) {
584 switch (phdr
->p_type
) {
587 "%s: GNU_STACK flags: %c%c%c\n",
589 (phdr
->p_flags
& PF_R
) ? 'R' : '-',
590 (phdr
->p_flags
& PF_W
) ? 'W' : '-',
591 (phdr
->p_flags
& PF_X
) ? 'X' : '-'
594 // The stack cannot be writable and executable
595 if ((phdr
->p_flags
& PF_W
) && (phdr
->p_flags
& PF_X
))
605 int pakfire_elf_has_execstack(struct pakfire_elf
* self
) {
606 return pakfire_elf_foreach_program_header(self
, pakfire_elf_check_execstack
, NULL
);
609 static int pakfire_elf_has_bind_now(struct pakfire_elf
* self
,
610 const GElf_Shdr
* shdr
, const GElf_Dyn
* dyn
, void* data
) {
611 switch (dyn
->d_tag
) {
617 if (dyn
->d_un
.d_val
& DF_BIND_NOW
)
622 if (dyn
->d_un
.d_val
& DF_1_NOW
)
633 int pakfire_elf_is_fully_relro(struct pakfire_elf
* self
) {
634 return pakfire_elf_dyn_walk(self
, pakfire_elf_has_bind_now
, NULL
);
637 int pakfire_elf_is_partially_relro(struct pakfire_elf
* self
) {
640 // Walk through all program headers
641 for (unsigned int i
= 0;; i
++) {
642 if (!gelf_getphdr(self
->elf
, i
, &phdr
))
645 switch (phdr
.p_type
) {
657 static uint32_t read_4_bytes(const int endianess
, const char* data
) {
664 ((uint32_t)data
[1] << 8) |
665 ((uint32_t)data
[2] << 16) |
666 ((uint32_t)data
[3] << 24);
672 ((uint32_t)data
[2] << 8) |
673 ((uint32_t)data
[1] << 16) |
674 ((uint32_t)data
[0] << 24);
681 static int pakfire_elf_check_cf_protection_aarch64(struct pakfire_elf
* self
,
682 const int endianess
, const uint32_t type
, const char* payload
) {
686 case GNU_PROPERTY_AARCH64_FEATURE_1_AND
:
694 uint32_t property
= read_4_bytes(endianess
, payload
);
697 if (!(property
& GNU_PROPERTY_AARCH64_FEATURE_1_BTI
))
698 flags
|= PAKFIRE_ELF_MISSING_BTI
;
701 if (!(property
& GNU_PROPERTY_AARCH64_FEATURE_1_PAC
))
702 flags
|= PAKFIRE_ELF_MISSING_PAC
;
707 static int pakfire_elf_check_cf_protection_riscv64(struct pakfire_elf
* self
,
708 const int endianess
, const uint32_t type
, const char* payload
) {
709 // There is nothing to do here
713 static int pakfire_elf_check_cf_protection_x86_64(struct pakfire_elf
* self
,
714 const int endianess
, const uint32_t type
, const char* payload
) {
718 case GNU_PROPERTY_X86_FEATURE_1_AND
:
726 uint32_t property
= read_4_bytes(endianess
, payload
);
729 if (!(property
& GNU_PROPERTY_X86_FEATURE_1_IBT
))
730 flags
|= PAKFIRE_ELF_MISSING_IBT
;
732 // Check for Shadow Stack
733 if (!(property
& GNU_PROPERTY_X86_FEATURE_1_SHSTK
))
734 flags
|= PAKFIRE_ELF_MISSING_SHSTK
;
739 static int pakfire_elf_check_cf_protection(struct pakfire_elf
* self
,
740 Elf_Scn
* section
, const GElf_Shdr
* shdr
, void* data
) {
743 size_t offset_name
= 0;
744 size_t offset_data
= 0;
748 Elf_Data
* d
= elf_getdata(section
, NULL
);
750 // Fetch the .note header
751 offset
= gelf_getnote(d
, offset
, &nhdr
, &offset_name
, &offset_data
);
753 ERROR(self
->ctx
, "%s: Could not read note section: %s\n",
754 self
->path
, elf_errmsg(-1));
758 // Skip any other note headers
759 switch (nhdr
.n_type
) {
760 case NT_GNU_PROPERTY_TYPE_0
:
763 // We are not interested in this here
769 // Check if the name starts with "GNU"
770 if (nhdr
.n_namesz
== sizeof(ELF_NOTE_GNU
) {
771 if (strcmp(data
->d_buf
+ offset_name
, ELF_NOTE_GNU
) == 0)
776 size_t length
= nhdr
.n_descsz
;
778 // XXX Check if this is aligned to 8 bytes or 4 bytes on 32 bit
780 // Fetch the endianess
781 const int endianess
= pakfire_elf_endianess(self
);
783 const char* payload
= (const char*)d
->d_buf
+ offset_data
;
786 // Read the type and size of the .note section
787 const uint32_t type
= read_4_bytes(endianess
, payload
);
788 const uint32_t size
= read_4_bytes(endianess
, payload
+ 4);
791 length
-= sizeof(type
) + sizeof(size
);
792 payload
+= sizeof(type
) + sizeof(size
);
795 ERROR(self
->ctx
, "GNU Property note has an incorrect format\n");
799 switch (pakfire_elf_machine(self
)) {
801 r
= pakfire_elf_check_cf_protection_aarch64(self
, endianess
, type
, payload
);
807 r
= pakfire_elf_check_cf_protection_riscv64(self
, endianess
, type
, payload
);
813 r
= pakfire_elf_check_cf_protection_x86_64(self
, endianess
, type
, payload
);
819 ERROR(self
->ctx
, "Unsupported ELF type (%d)\n", pakfire_elf_machine(self
));
824 length
-= (size
+ 7) & ~7;
825 payload
+= (size
+ 7) & ~7;
831 int pakfire_elf_has_cf_protection(struct pakfire_elf
* self
) {
832 return pakfire_elf_foreach_section(self
, SHT_NOTE
, pakfire_elf_check_cf_protection
, NULL
);
835 static int pakfire_elf_check_runpath(struct pakfire_elf
* self
,
836 const GElf_Shdr
* shdr
, const GElf_Dyn
* dyn
, void* data
) {
837 const char* runpath
= NULL
;
838 const char* value
= NULL
;
839 char buffer
[PATH_MAX
];
844 char*** runpaths
= data
;
846 switch (dyn
->d_tag
) {
850 value
= elf_strptr(self
->elf
, shdr
->sh_link
, dyn
->d_un
.d_val
);
854 DEBUG(self
->ctx
, "%s has a RUNPATH: %s\n", self
->path
, value
);
856 // Copy the value into a buffer we can modify
857 r
= pakfire_string_set(buffer
, value
);
861 // Split the value by :
862 runpath
= strtok_r(buffer
, ":", &p
);
864 // Iterate over all elements
866 r
= pakfire_strings_append(runpaths
, runpath
);
870 // Move on to the next RUNPATH
871 runpath
= strtok_r(NULL
, ":", &p
);
882 pakfire_strings_free(*runpaths
);
889 int pakfire_elf_has_runpaths(struct pakfire_elf
* self
, char*** runpaths
) {
890 return pakfire_elf_dyn_walk(self
, pakfire_elf_check_runpath
, runpaths
);
893 static int __pakfire_elf_is_stripped(struct pakfire_elf
* self
,
894 Elf_Scn
* section
, const Elf64_Shdr
* shdr
, void* data
) {
895 // Fetch the section name
896 const char* name
= elf_strptr(self
->elf
, self
->shstrndx
, shdr
->sh_name
);
900 switch (shdr
->sh_type
) {
901 // We should not have .symtab
905 // We should not have .symstr
907 if (pakfire_string_equals(name
, ".symstr"))
912 // Sometimes we need to check by name...
914 // There should be nothing here starting with .debug_* or .zdebug_*
915 if (pakfire_string_startswith(name
, ".debug_"))
918 else if (pakfire_string_startswith(name
, ".zdebug_*"))
922 else if (pakfire_string_equals(name
, ".gdb_index"))
931 int pakfire_elf_is_stripped(struct pakfire_elf
* self
) {
934 switch (pakfire_elf_type(self
)) {
935 // Do not check Relocatable Objects
939 // Check everything else
944 // Run through all sections
945 r
= pakfire_elf_foreach_section(self
, SHT_NULL
, __pakfire_elf_is_stripped
, NULL
);
949 // If the callback found something, the binary is not stripped
953 // Otherwise we assume the binary being stripped
957 static int pakfire_elf_find_provides(struct pakfire_elf
* self
,
958 Elf_Scn
* section
, const GElf_Shdr
* shdr
, void* data
) {
959 GElf_Verdaux verdaux
= {};
960 GElf_Verdef verdef
= {};
961 const char* version
= NULL
;
962 const char* base
= NULL
;
963 char*** provides
= data
;
966 // Fetch the section data
967 Elf_Data
* d
= elf_getdata(section
, NULL
);
971 while (offset
< shdr
->sh_size
) {
972 if (!gelf_getverdef(d
, offset
, &verdef
))
975 size_t aux_offset
= offset
+ verdef
.vd_aux
;
977 for (int i
= 0; i
< verdef
.vd_cnt
; i
++) {
978 if (!gelf_getverdaux(d
, aux_offset
, &verdaux
))
981 // Fetch the version string
982 version
= elf_strptr(self
->elf
, shdr
->sh_link
, verdaux
.vda_name
);
984 // Skip empty versions
985 if (!version
|| !*version
)
989 if (verdef
.vd_flags
& VER_FLG_BASE
) {
994 // Add it to the list
995 r
= pakfire_strings_appendf(provides
, "%s(%s)%s",
996 base
, version
, pakfire_elf_is_elf64(self
) ? "(64bit)" : "");
1000 if (!verdaux
.vda_next
)
1003 aux_offset
+= verdaux
.vda_next
;
1006 if (!verdef
.vd_next
)
1009 offset
+= verdef
.vd_next
;
1015 int pakfire_elf_provides(struct pakfire_elf
* self
, char*** provides
) {
1019 const char* soname
= pakfire_elf_soname(self
);
1021 r
= pakfire_strings_appendf(provides
,
1022 "%s()%s", soname
, pakfire_elf_is_elf64(self
) ? "(64bit)" : "");
1027 return pakfire_elf_foreach_section(self
, SHT_GNU_verdef
, pakfire_elf_find_provides
, provides
);
1030 static int pakfire_elf_find_requires(struct pakfire_elf
* self
,
1031 Elf_Scn
* section
, const GElf_Shdr
* shdr
, void* data
) {
1032 GElf_Vernaux vernaux
= {};
1033 GElf_Verneed verneed
= {};
1034 const char* version
= NULL
;
1035 const char* name
= NULL
;
1036 char*** requires
= data
;
1042 // Fetch the section data
1043 Elf_Data
* d
= elf_getdata(section
, NULL
);
1045 switch (shdr
->sh_type
) {
1047 for (size_t i
= 0; i
< shdr
->sh_size
/ shdr
->sh_entsize
; i
++) {
1049 if (!gelf_getdyn(d
, i
, &dyn
))
1052 switch (dyn
.d_tag
) {
1054 name
= elf_strptr(self
->elf
, shdr
->sh_link
, dyn
.d_un
.d_val
);
1056 // Skip empty names (this should not happen)
1057 if (!name
|| !*name
)
1060 DEBUG(self
->ctx
, "%s depends on %s\n", self
->path
, name
);
1062 // Add it to the list
1063 r
= pakfire_strings_appendf(requires
, "%s()%s",
1064 name
, pakfire_elf_is_elf64(self
) ? "(64bit)" : "");
1072 case SHT_GNU_verneed
:
1075 while (offset
< shdr
->sh_size
) {
1076 if (!gelf_getverneed(d
, offset
, &verneed
))
1079 // Fetch the library name
1080 name
= elf_strptr(self
->elf
, shdr
->sh_link
, verneed
.vn_file
);
1081 if (!name
|| !*name
)
1084 aux_offset
= offset
+ verneed
.vn_aux
;
1086 for (int i
= 0; i
< verneed
.vn_cnt
; i
++) {
1087 if (!gelf_getvernaux(d
, aux_offset
, &vernaux
))
1090 // Fetch the version string
1091 version
= elf_strptr(self
->elf
, shdr
->sh_link
, vernaux
.vna_name
);
1093 // Skip empty versions
1094 if (!version
|| !*version
)
1097 // Add it to the list
1098 r
= pakfire_strings_appendf(requires
, "%s(%s)%s",
1099 name
, version
, pakfire_elf_is_elf64(self
) ? "(64bit)" : "");
1103 if (!vernaux
.vna_next
)
1106 aux_offset
+= vernaux
.vna_next
;
1109 if (!verneed
.vn_next
)
1112 offset
+= verneed
.vn_next
;
1123 int pakfire_elf_requires(struct pakfire_elf
* self
, char*** requires
) {
1124 return pakfire_elf_foreach_section(self
, SHT_NULL
, pakfire_elf_find_requires
, requires
);
1128 libdw does not seem to export the error codes in their header files,
1129 although there is a function to retrieve them...
1131 #ifndef DWARF_E_NO_DWARF
1132 #define DWARF_E_NO_DWARF 6
1135 int pakfire_elf_foreach_source_file(struct pakfire_elf
* self
,
1136 pakfire_elf_foreach_source_file_callback callback
, void* data
) {
1137 const char* filename
= NULL
;
1138 char basename
[PATH_MAX
];
1139 char path
[PATH_MAX
];
1140 Dwarf
* dwarf
= NULL
;
1141 Dwarf_Files
* files
= NULL
;
1142 Dwarf_Die
* die
= NULL
;
1143 Dwarf_Off offset
= 0;
1144 Dwarf_Off next_offset
;
1145 size_t cu_header_length
;
1150 // Read DWARF information
1151 dwarf
= dwarf_begin(self
->fd
, DWARF_C_READ
);
1153 switch (dwarf_errno()) {
1154 // If we don't have any DWARF information there is nothing to do
1155 case DWARF_E_NO_DWARF
:
1160 ERROR(self
->ctx
, "Could not initialize DWARF context: %s\n", dwarf_errmsg(-1));
1167 // Fetch the next compilation unit
1168 r
= dwarf_nextcu(dwarf
, offset
, &next_offset
, &cu_header_length
, NULL
, NULL
, NULL
);
1172 // Fetch the Debug Information Entry
1173 die
= dwarf_offdie(dwarf
, offset
+ cu_header_length
, &die_mem
);
1177 // Fetch the source files
1178 r
= dwarf_getsrcfiles(die
, &files
, &count
);
1182 // Iterate over all files...
1183 for (unsigned int i
= 0; i
< count
; i
++) {
1184 // Fetch the filename
1185 filename
= dwarf_filesrc(files
, i
, NULL
, NULL
);
1187 // Copy to the stack
1188 r
= pakfire_string_set(path
, filename
);
1192 // Normalize the path
1193 r
= pakfire_path_normalize(path
);
1197 // Determine the basename
1198 r
= pakfire_path_basename(basename
, filename
);
1202 // Ignore things like <artificial> or <built-in>
1203 if (pakfire_string_startswith(basename
, "<")
1204 && pakfire_string_endswith(basename
, ">"))
1207 // Call the callback
1208 r
= callback(self
->ctx
, self
, path
, data
);
1214 offset
= next_offset
;