|
| 1 | +#include "elf.h" |
| 2 | + |
| 3 | +#ifdef FF_HAVE_ELF |
| 4 | + |
| 5 | +#include "common/io/io.h" |
| 6 | +#include "common/library.h" |
| 7 | +#include "util/stringUtils.h" |
| 8 | + |
| 9 | +#include <libelf.h> |
| 10 | +#include <fcntl.h> |
| 11 | + |
| 12 | +const char* ffElfExtractStrings(const char* elfFile, bool (*cb)(const char* str, uint32_t len, void* userdata), void* userdata) |
| 13 | +{ |
| 14 | + FF_LIBRARY_LOAD(libelf, &instance.config.library.libelf, "dlopen libelf" FF_LIBRARY_EXTENSION " failed", "libelf" FF_LIBRARY_EXTENSION, 1); |
| 15 | + FF_LIBRARY_LOAD_SYMBOL_MESSAGE(libelf, elf_version) |
| 16 | + FF_LIBRARY_LOAD_SYMBOL_MESSAGE(libelf, elf_begin) |
| 17 | + FF_LIBRARY_LOAD_SYMBOL_MESSAGE(libelf, elf_getshdrstrndx) |
| 18 | + FF_LIBRARY_LOAD_SYMBOL_MESSAGE(libelf, elf_nextscn) |
| 19 | + FF_LIBRARY_LOAD_SYMBOL_MESSAGE(libelf, elf64_getshdr) |
| 20 | + FF_LIBRARY_LOAD_SYMBOL_MESSAGE(libelf, elf32_getshdr) |
| 21 | + FF_LIBRARY_LOAD_SYMBOL_MESSAGE(libelf, elf_getdata) |
| 22 | + FF_LIBRARY_LOAD_SYMBOL_MESSAGE(libelf, elf_strptr) |
| 23 | + FF_LIBRARY_LOAD_SYMBOL_MESSAGE(libelf, elf_end) |
| 24 | + |
| 25 | + if (ffelf_version(EV_CURRENT) == EV_NONE) return "elf_version() failed"; |
| 26 | + |
| 27 | + FF_AUTO_CLOSE_FD int fd = open(elfFile, O_RDONLY, 0); |
| 28 | + if (fd < 0) return "open() failed"; |
| 29 | + |
| 30 | + Elf* elf = ffelf_begin(fd, ELF_C_READ, NULL); |
| 31 | + if (elf == NULL) return "elf_begin() failed"; |
| 32 | + |
| 33 | + size_t shstrndx = 0; |
| 34 | + if (ffelf_getshdrstrndx(elf, &shstrndx) < 0) |
| 35 | + { |
| 36 | + ffelf_end(elf); |
| 37 | + return "elf_getshdrstrndx() failed"; |
| 38 | + } |
| 39 | + |
| 40 | + Elf_Scn* scn = NULL; |
| 41 | + FF_STRBUF_AUTO_DESTROY buffer = ffStrbufCreate(); |
| 42 | + while ((scn = ffelf_nextscn(elf, scn)) != NULL) |
| 43 | + { |
| 44 | + Elf64_Shdr* shdr64 = ffelf64_getshdr(scn); |
| 45 | + Elf32_Shdr* shdr32 = NULL; |
| 46 | + if (shdr64 == NULL) |
| 47 | + { |
| 48 | + shdr32 = ffelf32_getshdr(scn); |
| 49 | + if (shdr32 == NULL) continue; |
| 50 | + } |
| 51 | + |
| 52 | + const char* name = ffelf_strptr(elf, shstrndx, shdr64 ? shdr64->sh_name : shdr32->sh_name); |
| 53 | + if (name == NULL || !ffStrEquals(name, ".rodata")) continue; |
| 54 | + |
| 55 | + Elf_Data* data = ffelf_getdata(scn, NULL); |
| 56 | + if (data == NULL) continue; |
| 57 | + |
| 58 | + for (size_t off = 0; off < data->d_size; ++off) |
| 59 | + { |
| 60 | + const char* p = (const char*) data->d_buf + off; |
| 61 | + if (*p == '\0') continue; |
| 62 | + uint32_t len = (uint32_t) strlen(p); |
| 63 | + if (*p >= ' ' && *p <= '~') // Ignore control characters |
| 64 | + { |
| 65 | + if (!cb(p, len, userdata)) break; |
| 66 | + } |
| 67 | + off += len; |
| 68 | + } |
| 69 | + |
| 70 | + break; |
| 71 | + } |
| 72 | + |
| 73 | + ffelf_end(elf); |
| 74 | + return NULL; |
| 75 | +} |
| 76 | + |
| 77 | +#else |
| 78 | + |
| 79 | +const char* ffElfExtractStrings(const char* elfFile, bool (*cb)(const char* str, uint32_t len, void* userdata), void* userdata) |
| 80 | +{ |
| 81 | + FF_UNUSED(elfFile, cb, userdata); |
| 82 | + return "Fastfetch was built without libelf support"; |
| 83 | +} |
| 84 | + |
| 85 | +#endif |
0 commit comments