Skip to content

Commit a9373fb

Browse files
committed
Util (Linux): add elf helper
1 parent 2e2cf64 commit a9373fb

File tree

8 files changed

+115
-0
lines changed

8 files changed

+115
-0
lines changed

CMakeLists.txt

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -69,6 +69,7 @@ cmake_dependent_option(ENABLE_FREETYPE "Enable freetype" ON "ANDROID" OFF)
6969
cmake_dependent_option(ENABLE_PULSE "Enable pulse" ON "LINUX OR SunOS" OFF)
7070
cmake_dependent_option(ENABLE_DDCUTIL "Enable ddcutil" ON "LINUX" OFF)
7171
cmake_dependent_option(ENABLE_DIRECTX_HEADERS "Enable DirectX headers for WSL" ON "LINUX" OFF)
72+
cmake_dependent_option(ENABLE_ELF "Enable libelf" ON "LINUX" OFF)
7273
cmake_dependent_option(ENABLE_THREADS "Enable multithreading" ON "Threads_FOUND" OFF)
7374

7475
option(ENABLE_SYSTEM_YYJSON "Use system provided (instead of fastfetch embedded) yyjson library" OFF)
@@ -480,6 +481,7 @@ if(LINUX)
480481
src/detection/wmtheme/wmtheme_linux.c
481482
src/detection/camera/camera_linux.c
482483
src/util/platform/FFPlatform_unix.c
484+
src/util/linux/elf.c
483485
)
484486
elseif(ANDROID)
485487
list(APPEND LIBFASTFETCH_SRC
@@ -1075,6 +1077,10 @@ ff_lib_enable(DDCUTIL
10751077
"ddcutil"
10761078
"Ddcutil"
10771079
)
1080+
ff_lib_enable(ELF
1081+
"libelf"
1082+
"libelf"
1083+
)
10781084
ff_lib_enable(DIRECTX_HEADERS
10791085
"DirectX-Headers"
10801086
"DirectX-Headers"

doc/json_schema.json

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -730,6 +730,10 @@
730730
"ddcutil": {
731731
"description": "Used for brightness detection of external displays (Linux)",
732732
"type": "string"
733+
},
734+
"elf": {
735+
"description": "Used for st terminal font detection and systemd version detection (Linux)",
736+
"type": "string"
733737
}
734738
}
735739
},

src/common/init.c

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -248,6 +248,9 @@ void ffListFeatures(void)
248248
#if FF_HAVE_DDCUTIL
249249
"libddcutil\n"
250250
#endif
251+
#if FF_HAVE_ELF
252+
"libelf\n"
253+
#endif
251254
#if FF_HAVE_DIRECTX_HEADERS
252255
"Directx Headers\n"
253256
#endif

src/data/help.json

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -935,6 +935,13 @@
935935
"arg": {
936936
"type": "path"
937937
}
938+
},
939+
{
940+
"long": "lib-elf",
941+
"desc": "Used for st terminal font detection and systemd version detection",
942+
"arg": {
943+
"type": "path"
944+
}
938945
}
939946
],
940947
"Module specific": [

src/options/library.c

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -66,6 +66,8 @@ const char* ffOptionsParseLibraryJsonConfig(FFOptionsLibrary* options, yyjson_va
6666
ffStrbufSetS(&options->libDdcutil, yyjson_get_str(val));
6767
else if (ffStrEqualsIgnCase(key, "drm"))
6868
ffStrbufSetS(&options->libdrm, yyjson_get_str(val));
69+
else if (ffStrEqualsIgnCase(key, "elf"))
70+
ffStrbufSetS(&options->libelf, yyjson_get_str(val));
6971
#endif
7072

7173
else
@@ -131,6 +133,8 @@ bool ffOptionsParseLibraryCommandLine(FFOptionsLibrary* options, const char* key
131133
ffOptionParseString(key, value, &options->libDdcutil);
132134
else if(ffStrEqualsIgnCase(subkey, "drm"))
133135
ffOptionParseString(key, value, &options->libdrm);
136+
else if(ffStrEqualsIgnCase(subkey, "elf"))
137+
ffOptionParseString(key, value, &options->libelf);
134138
#endif
135139

136140
else

src/options/library.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,7 @@ typedef struct FFOptionsLibrary
3232
FFstrbuf libPulse;
3333
FFstrbuf libDdcutil;
3434
FFstrbuf libdrm;
35+
FFstrbuf libelf;
3536
#endif
3637
} FFOptionsLibrary;
3738

src/util/linux/elf.c

Lines changed: 85 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,85 @@
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

src/util/linux/elf.h

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
#pragma once
2+
3+
#include "fastfetch.h"
4+
5+
const char* ffElfExtractStrings(const char* elfFile, bool (*cb)(const char* str, uint32_t len, void* userdata), void* userdata);

0 commit comments

Comments
 (0)