]> git.ipfire.org Git - pakfire.git/commitdiff
ELF: Move any source file handling
authorMichael Tremer <michael.tremer@ipfire.org>
Fri, 3 Jan 2025 06:04:06 +0000 (06:04 +0000)
committerMichael Tremer <michael.tremer@ipfire.org>
Fri, 3 Jan 2025 06:04:06 +0000 (06:04 +0000)
Signed-off-by: Michael Tremer <michael.tremer@ipfire.org>
src/libpakfire/elf.c
src/libpakfire/include/pakfire/elf.h
src/libpakfire/stripper.c

index f3bff5bf5982e9defd64c4d5bef2d5eb22acfacc..148cf254f408c1d1325a15312521b211d4cbbb5d 100644 (file)
@@ -26,6 +26,7 @@
 #include <pakfire/file.h>
 #include <pakfire/hex.h>
 #include <pakfire/logging.h>
+#include <pakfire/path.h>
 #include <pakfire/string.h>
 
 // libelf
@@ -854,3 +855,104 @@ int pakfire_elf_is_stripped(struct pakfire_elf* self) {
        // Otherwise we assume the binary being stripped
        return 1;
 }
+
+/*
+       libdw does not seem to export the error codes in their header files,
+       although there is a function to retrieve them...
+*/
+#ifndef DWARF_E_NO_DWARF
+#define DWARF_E_NO_DWARF 6
+#endif
+
+int pakfire_elf_foreach_source_file(struct pakfire_elf* self,
+               pakfire_elf_foreach_source_file_callback callback, void* data) {
+       const char* filename = NULL;
+       char basename[PATH_MAX];
+       char path[PATH_MAX];
+       Dwarf* dwarf = NULL;
+       Dwarf_Files* files = NULL;
+       Dwarf_Die* die = NULL;
+       Dwarf_Off offset = 0;
+       Dwarf_Off next_offset;
+       size_t cu_header_length;
+       Dwarf_Die die_mem;
+       size_t count;
+       int r;
+
+       // Read DWARF information
+       dwarf = dwarf_begin(self->fd, DWARF_C_READ);
+       if (!dwarf) {
+               switch (dwarf_errno()) {
+                       // If we don't have any DWARF information there is nothing to do
+                       case DWARF_E_NO_DWARF:
+                               r = 0;
+                               goto ERROR;
+
+                       default:
+                               ERROR(self->ctx, "Could not initialize DWARF context: %s\n", dwarf_errmsg(-1));
+                               r = -errno;
+                               goto ERROR;
+               }
+       }
+
+       for (;;) {
+               // Fetch the next compilation unit
+               r = dwarf_nextcu(dwarf, offset, &next_offset, &cu_header_length, NULL, NULL, NULL);
+               if (r < 0)
+                       goto ERROR;
+
+               // Fetch the Debug Information Entry
+               die = dwarf_offdie(dwarf, offset + cu_header_length, &die_mem);
+               if (!die)
+                       break;
+
+               // Fetch the source files
+               r = dwarf_getsrcfiles(die, &files, &count);
+               if (r < 0) {
+                       ERROR(self->ctx, "Could not fetch the source files: %s\n", dwarf_errmsg(-1));
+                       r = -errno;
+                       goto ERROR;
+               }
+
+               // Iterate over all files...
+               for (unsigned int i = 0; i < count; i++) {
+                       // Fetch the filename
+                       filename = dwarf_filesrc(files, i, NULL, NULL);
+
+                       // Copy to the stack
+                       r = pakfire_string_set(path, filename);
+                       if (r < 0)
+                               goto ERROR;
+
+                       // Normalize the path
+                       r = pakfire_path_normalize(path);
+                       if (r < 0)
+                               goto ERROR;
+
+                       // Determine the basename
+                       r = pakfire_path_basename(basename, filename);
+                       if (r < 0)
+                               goto ERROR;
+
+                       // Ignore things like <artificial> or <built-in>
+                       if (pakfire_string_startswith(basename, "<")
+                                       && pakfire_string_endswith(basename, ">"))
+                               continue;
+
+                       DEBUG(self->ctx, "Found source file: %s\n", path);
+
+                       // Call the callback
+                       r = callback(self->ctx, self, path, data);
+                       if (r)
+                               goto ERROR;
+               }
+
+               offset = next_offset;
+       }
+
+ERROR:
+       if (dwarf)
+               dwarf_end(dwarf);
+
+       return r;
+}
index 02de846d1f50eaf4d5c55951936a19a2249942ec..f723d52244ab125ab69e51c68df193926da7c840 100644 (file)
@@ -61,6 +61,13 @@ enum {
        PAKFIRE_ELF_MISSING_SHSTK = (1 << 3),
 };
 
+// Source Files
+typedef int (*pakfire_elf_foreach_source_file_callback)
+       (struct pakfire_ctx* ctx, struct pakfire_elf* elf, const char* filename, void* data);
+
+int pakfire_elf_foreach_source_file(struct pakfire_elf* self,
+       pakfire_elf_foreach_source_file_callback callback, void* data);
+
 #endif /* PAKFIRE_PRIVATE */
 
 #endif /* PAKFIRE_ELF_H */
index eaa9c3b0f41f0485a1924f7cfa8843f2b3e9852c..90546f6a65236219225b106086f23b579b3784d4 100644 (file)
 #############################################################################*/
 
 #include <errno.h>
+#include <fcntl.h>
 #include <stdlib.h>
 #include <sys/sendfile.h>
 #include <sys/stat.h>
 
-// libdw
-#include <elfutils/libdw.h>
-#include <elfutils/libdwelf.h>
-
 #include <pakfire/elf.h>
 #include <pakfire/filelist.h>
 #include <pakfire/hex.h>
@@ -52,8 +49,28 @@ struct pakfire_stripper {
 
        // Filelist
        struct pakfire_filelist* filelist;
+
+       // Source Directory
+       int sourcesfd;
 };
 
+static int pakfire_stripper_open_sources(struct pakfire_stripper* stripper) {
+       // Open the source directory
+       stripper->sourcesfd = pakfire_openat(stripper->pakfire, BUILD_SRC_DIR, O_DIRECTORY|O_PATH);
+       if (stripper->sourcesfd < 0) {
+               switch (errno) {
+                       case ENOENT:
+                               break;
+
+                       default:
+                               ERROR(stripper->ctx, "Could not open %s: %m\n", BUILD_SRC_DIR);
+                               return -errno;
+               }
+       }
+
+       return 0;
+}
+
 int pakfire_stripper_create(struct pakfire_stripper** stripper,
                struct pakfire* pakfire, struct pakfire_jail* jail, const char* path) {
        struct pakfire_stripper* s = NULL;
@@ -76,6 +93,9 @@ int pakfire_stripper_create(struct pakfire_stripper** stripper,
        // Initialize the reference counter
        s->nrefs = 1;
 
+       // Initialize file descriptors
+       s->sourcesfd = -EBADF;
+
        // Store the path
        r = pakfire_string_set(s->path, path);
        if (r < 0)
@@ -86,6 +106,11 @@ int pakfire_stripper_create(struct pakfire_stripper** stripper,
        if (r < 0)
                goto ERROR;
 
+       // Open the source directory
+       r = pakfire_stripper_open_sources(s);
+       if (r < 0)
+               goto ERROR;
+
        // Return the pointer
        *stripper = pakfire_stripper_ref(s);
 
@@ -97,6 +122,8 @@ ERROR:
 }
 
 static void pakfire_stripper_free(struct pakfire_stripper* stripper) {
+       if (stripper->sourcesfd)
+               close(stripper->sourcesfd);
        if (stripper->filelist)
                pakfire_filelist_unref(stripper->filelist);
        if (stripper->pakfire)
@@ -167,65 +194,58 @@ ERROR:
 }
 
 static int pakfire_stripper_copy_source_file(
-               struct pakfire_stripper* stripper, const char* filename) {
-       char srcpath[PATH_MAX];
-       char dstpath[PATH_MAX];
+               struct pakfire_ctx* ctx, struct pakfire_elf* elf, const char* filename, void* data) {
+       struct pakfire_stripper* stripper = data;
+       char path[PATH_MAX];
        struct stat st = {};
-       int r;
-
-       FILE* src = NULL;
        FILE* dst = NULL;
+       int fd = -EBADF;
+       int r;
 
-       // Make the source path absolute
-       r = pakfire_path(stripper->pakfire, srcpath, "%s", filename);
-       if (r < 0)
-               goto ERROR;
+       // If the source file is not in the right path, we ignore it
+       if (!pakfire_string_startswith(filename, DEBUG_SRC_DIR))
+               return 0;
 
        // Remove the original source path
-       r = pakfire_path_relative(dstpath, BUILD_SRC_DIR, filename);
-       if (r < 0)
-               goto ERROR;
-
-       // Add the debug directory source path
-       r = pakfire_path_append(dstpath, DEBUG_SRC_DIR, dstpath);
-       if (r < 0)
-               goto ERROR;
-
-       // Add the buildroot
-       r = pakfire_path_append(dstpath, stripper->path, dstpath);
+       r = pakfire_path_relative(path, DEBUG_SRC_DIR, filename);
        if (r < 0)
                goto ERROR;
 
        // Open the source file
-       src = fopen(srcpath, "r");
-       if (!src) {
+       fd = openat(stripper->sourcesfd, path, O_RDONLY);
+       if (fd < 0) {
                switch (errno) {
                        // If the source file does not exist, we cannot copy anything
-                       case ENOENT:
-                               goto ERROR;
+                       //case ENOENT:
+                       //      goto ERROR;
 
                        default:
-                               ERROR(stripper->ctx, "Could not open %s: %m\n", filename);
+                               ERROR(stripper->ctx, "Could not open %s: %m\n", path);
                                r = -errno;
                                goto ERROR;
                }
        }
 
        // Stat the source file
-       r = fstat(fileno(src), &st);
+       r = fstat(fd, &st);
        if (r < 0) {
-               ERROR(stripper->ctx, "Could not stat %s: %m\n", filename);
+               ERROR(stripper->ctx, "Could not stat %s: %m\n", path);
                r = -errno;
                goto ERROR;
        }
 
+       // Add the buildroot
+       r = pakfire_path_append(path, stripper->path, filename);
+       if (r < 0)
+               goto ERROR;
+
        // Create all directories
-       r = pakfire_mkparentdir(dstpath, 0755);
+       r = pakfire_mkparentdir(path, 0755);
        if (r < 0)
                goto ERROR;
 
        // Open the destination file
-       dst = fopen(dstpath, "wx");
+       dst = fopen(path, "wx");
        if (!dst) {
                switch (errno) {
                        // If the file exist already, we are done
@@ -233,14 +253,14 @@ static int pakfire_stripper_copy_source_file(
                                goto ERROR;
 
                        default:
-                               ERROR(stripper->ctx, "Could not open %s: %m\n", dstpath);
+                               ERROR(stripper->ctx, "Could not open %s: %m\n", path);
                                r = -errno;
                                goto ERROR;
                }
        }
 
        // Copy all content
-       ssize_t bytes_written = sendfile(fileno(dst), fileno(src), 0, st.st_size);
+       ssize_t bytes_written = sendfile(fileno(dst), fd, 0, st.st_size);
        if (bytes_written < st.st_size) {
                ERROR(stripper->ctx, "Failed to copy source file %s: %m\n", filename);
                r = -errno;
@@ -250,7 +270,7 @@ static int pakfire_stripper_copy_source_file(
        // Change permissions
        r = fchmod(fileno(dst), 0444);
        if (r < 0) {
-               ERROR(stripper->ctx, "Could not change permissions of %s: %m\n", dstpath);
+               ERROR(stripper->ctx, "Could not change permissions of %s: %m\n", path);
                r = -errno;
                goto ERROR;
        }
@@ -258,103 +278,8 @@ static int pakfire_stripper_copy_source_file(
 ERROR:
        if (dst)
                fclose(dst);
-       if (src)
-               fclose(src);
-
-       return r;
-}
-
-/*
-       libdw does not seem to export the error codes in their header files,
-       although there is a function to retrieve them...
-*/
-#ifndef DWARF_E_NO_DWARF
-#define DWARF_E_NO_DWARF 6
-#endif
-
-static int pakfire_stripper_copy_sources(
-               struct pakfire_stripper* stripper, struct pakfire_file* file, int fd) {
-       const char* filename = NULL;
-       char basename[PATH_MAX];
-       Dwarf* dwarf = NULL;
-       Dwarf_Files* files = NULL;
-       Dwarf_Die* die = NULL;
-       Dwarf_Off offset = 0;
-       Dwarf_Off next_offset;
-       size_t cu_header_length;
-       Dwarf_Die die_mem;
-       size_t count;
-       int r;
-
-       // Read DWARF information
-       dwarf = dwarf_begin(fd, DWARF_C_READ);
-       if (!dwarf) {
-               switch (dwarf_errno()) {
-                       // If we don't have any DWARF information there is nothing to do
-                       case DWARF_E_NO_DWARF:
-                               r = 0;
-                               goto ERROR;
-
-                       default:
-                               ERROR(stripper->ctx, "Could not initialize DWARF context: %s\n", dwarf_errmsg(-1));
-                               r = -errno;
-                               goto ERROR;
-               }
-       }
-
-       for (;;) {
-               // Fetch the next compilation unit
-               r = dwarf_nextcu(dwarf, offset, &next_offset, &cu_header_length, NULL, NULL, NULL);
-               if (r < 0)
-                       goto ERROR;
-
-               // Fetch the Debug Information Entry
-               die = dwarf_offdie(dwarf, offset + cu_header_length, &die_mem);
-               if (!die)
-                       break;
-
-               // Fetch the source files
-               r = dwarf_getsrcfiles(die, &files, &count);
-               if (r < 0) {
-                       ERROR(stripper->ctx, "Could not fetch the source files: %s\n", dwarf_errmsg(-1));
-                       r = -errno;
-                       goto ERROR;
-               }
-
-               // Iterate over all files...
-               for (unsigned int i = 0; i < count; i++) {
-                       // Fetch the filename
-                       filename = dwarf_filesrc(files, i, NULL, NULL);
-
-                       // If the source file is not in the right path, we ignore it
-                       if (!pakfire_string_startswith(filename, BUILD_SRC_DIR))
-                               continue;
-
-                       // Determine the basename
-                       r = pakfire_path_basename(basename, filename);
-                       if (r < 0)
-                               goto ERROR;
-
-                       // Ignore things like <artificial> or <built-in>
-                       if (pakfire_string_startswith(basename, "<") && pakfire_string_endswith(basename, ">"))
-                               continue;
-
-                       DEBUG(stripper->ctx, "Found source file: %s\n", filename);
-
-                       // Copy the file
-                       r = pakfire_stripper_copy_source_file(stripper, filename);
-                       if (r < 0) {
-                               ERROR(stripper->ctx, "Could not copy source file %s: %s\n", filename, strerror(-r));
-                               goto ERROR;
-                       }
-               }
-
-               offset = next_offset;
-       }
-
-ERROR:
-       if (dwarf)
-               dwarf_end(dwarf);
+       if (fd >= 0)
+               close(fd);
 
        return r;
 }
@@ -434,8 +359,8 @@ static int pakfire_stripper_strip_debug_sections(struct pakfire_stripper* stripp
 
        // The command returned an error
        } else if (r > 0) {
-               ERROR(stripper->ctx, "Could not extract debug sections from %s\n",
-                       pakfire_file_get_path(file));
+               ERROR(stripper->ctx, "Could not extract debug sections from %s: %d\n",
+                       pakfire_file_get_path(file), r);
                return -ENOTSUP;
        }
 
@@ -490,16 +415,8 @@ static int pakfire_stripper_strip(
                struct pakfire_ctx* ctx, struct pakfire_file* file, void* data) {
        struct pakfire_stripper* stripper = data;
        struct pakfire_elf* elf = NULL;
-       int fd = -EBADF;
        int r;
 
-       // Open the file
-       fd = pakfire_file_open(file, 0);
-       if (fd < 0) {
-               r = -errno;
-               goto ERROR;
-       }
-
        // Open the ELF file
        r = pakfire_elf_open_file(&elf, stripper->ctx, file);
        if (r < 0)
@@ -508,7 +425,8 @@ static int pakfire_stripper_strip(
        // Only strip if there is actually some debug information
        if (!pakfire_elf_is_stripped(elf)) {
                // Copy sources
-               r = pakfire_stripper_copy_sources(stripper, file, fd);
+               r = pakfire_elf_foreach_source_file(elf,
+                               pakfire_stripper_copy_source_file, stripper);
                if (r < 0)
                        goto ERROR;
 
@@ -521,8 +439,6 @@ static int pakfire_stripper_strip(
 ERROR:
        if (elf)
                pakfire_elf_unref(elf);
-       if (fd >= 0)
-               close(fd);
 
        return r;
 }