Loading...
Searching...
No Matches
ElfInspector.hpp
1#pragma once
2
3// Minimal ELF reader: lists the DT_NEEDED sonames of a 64-bit ELF binary.
4// Header-only and dependency-free so that both the linuxcheck diagnostic
5// tool and the plug-in hosts (e.g. the LV2 UI loader, which must refuse
6// UIs linked against a different Qt major) can share it.
7//
8// Extracted from linuxcheck/diagnostics.hpp.
9
10#if defined(__linux__)
11
12#include <elf.h>
13
14#include <fstream>
15#include <iostream>
16#include <memory>
17#include <optional>
18#include <stdexcept>
19#include <string>
20#include <string_view>
21#include <vector>
22
23namespace score
24{
25class ElfInspector
26{
27public:
30 std::optional<std::vector<std::string>>
31 try_get_dt_needed(std::string_view filename)
32 {
33 std::vector<std::string> libraries;
34
35 m_file.open(std::string(filename), std::ios::binary);
36 if(!m_file)
37 return std::nullopt;
38
39 // Read ELF magic and class
40 unsigned char e_ident[EI_NIDENT];
41 m_file.read(reinterpret_cast<char*>(e_ident), EI_NIDENT);
42 if(!m_file)
43 return std::nullopt;
44
45 if(e_ident[EI_MAG0] != ELFMAG0 || e_ident[EI_MAG1] != ELFMAG1
46 || e_ident[EI_MAG2] != ELFMAG2 || e_ident[EI_MAG3] != ELFMAG3)
47 return std::nullopt;
48
49 if(e_ident[EI_CLASS] != ELFCLASS64)
50 return std::nullopt;
51
52 try
53 {
54 process_elf64(libraries);
55 }
56 catch(...)
57 {
58 // Truncated / corrupt file
59 return std::nullopt;
60 }
61
62 return libraries;
63 }
64
67 std::vector<std::string> get_dt_needed(std::string_view filename)
68 {
69 if(auto res = try_get_dt_needed(filename))
70 return *std::move(res);
71
72 std::cerr << filename << " is not a readable, valid 64-bit ELF file\n";
73 return {};
74 }
75
76private:
77 template <typename T>
78 T read_at(std::streampos pos)
79 {
80 T value;
81 m_file.seekg(pos);
82 m_file.read(reinterpret_cast<char*>(&value), sizeof(T));
83 if(!m_file)
84 throw std::runtime_error("Failed to read from file");
85 return value;
86 }
87
88 std::string read_string_at(std::streampos pos)
89 {
90 m_file.seekg(pos);
91 std::string result;
92 char c;
93 while(m_file.get(c) && c != '\0')
94 result += c;
95 return result;
96 }
97
98 void process_elf64(std::vector<std::string>& libraries)
99 {
100 // Read ELF64 header
101 Elf64_Ehdr ehdr = read_at<Elf64_Ehdr>(0);
102
103 // Read program headers
104 auto phdrs = std::unique_ptr<Elf64_Phdr[]>(new Elf64_Phdr[ehdr.e_phnum]);
105 m_file.seekg(ehdr.e_phoff);
106 m_file.read(reinterpret_cast<char*>(phdrs.get()), ehdr.e_phnum * sizeof(Elf64_Phdr));
107 if(!m_file)
108 throw std::runtime_error("Failed to read program headers");
109
110 Elf64_Phdr* dynamic_phdr = nullptr;
111 for(int i = 0; i < ehdr.e_phnum; ++i)
112 {
113 if(phdrs[i].p_type == PT_DYNAMIC)
114 {
115 dynamic_phdr = &phdrs[i];
116 break;
117 }
118 }
119
120 if(!dynamic_phdr)
121 return; // Statically linked or no dynamic section
122
123 // Read dynamic section
124 std::vector<Elf64_Dyn> dyns(dynamic_phdr->p_filesz / sizeof(Elf64_Dyn));
125 m_file.seekg(dynamic_phdr->p_offset);
126 m_file.read(reinterpret_cast<char*>(dyns.data()), dynamic_phdr->p_filesz);
127 if(!m_file)
128 throw std::runtime_error("Failed to read dynamic section");
129
130 // Find string table address
131 Elf64_Addr strtab_addr = 0;
132 for(const auto& dyn : dyns)
133 {
134 if(dyn.d_tag == DT_STRTAB)
135 {
136 strtab_addr = dyn.d_un.d_ptr;
137 break;
138 }
139 }
140
141 if(!strtab_addr)
142 return;
143
144 // Convert virtual address to file offset
145 Elf64_Off strtab_offset = 0;
146 for(int i = 0; i < ehdr.e_phnum; ++i)
147 {
148 if(phdrs[i].p_type == PT_LOAD && strtab_addr >= phdrs[i].p_vaddr
149 && strtab_addr < phdrs[i].p_vaddr + phdrs[i].p_filesz)
150 {
151 strtab_offset = strtab_addr - phdrs[i].p_vaddr + phdrs[i].p_offset;
152 break;
153 }
154 }
155
156 if(!strtab_offset)
157 return;
158
159 // Extract DT_NEEDED entries
160 for(const auto& dyn : dyns)
161 {
162 if(dyn.d_tag == DT_NEEDED)
163 {
164 libraries.push_back(read_string_at(strtab_offset + dyn.d_un.d_val));
165 }
166 }
167 }
168
169 std::ifstream m_file;
170};
171}
172
173#endif
Base toolkit upon which the software is built.
Definition Application.cpp:117