/src/CMake/Source/cmELF.cxx
Line | Count | Source |
1 | | /* Distributed under the OSI-approved BSD 3-Clause License. See accompanying |
2 | | file LICENSE.rst or https://cmake.org/licensing for details. */ |
3 | | #include "cmELF.h" |
4 | | |
5 | | #include <algorithm> |
6 | | #include <cstddef> |
7 | | #include <cstdint> |
8 | | #include <map> |
9 | | #include <memory> |
10 | | #include <sstream> |
11 | | #include <utility> |
12 | | #include <vector> |
13 | | |
14 | | #include <cm/memory> |
15 | | #include <cmext/algorithm> |
16 | | |
17 | | #include <cm3p/kwiml/abi.h> |
18 | | |
19 | | #include "cmsys/FStream.hxx" |
20 | | |
21 | | #include "cmelf/elf32.h" |
22 | | #include "cmelf/elf64.h" |
23 | | #include "cmelf/elf_common.h" |
24 | | |
25 | | // Maximum reasonable values to prevent DoS/OOM from malformed files. |
26 | | static constexpr std::size_t kMaxSections = 65536; |
27 | | static constexpr std::size_t kMaxSectionSize = 1024 * 1024 * 256; |
28 | | static constexpr std::size_t kMaxDynamicEntries = 1024 * 1024; |
29 | | |
30 | | // Low-level byte swapping implementation. |
31 | | template <size_t s> |
32 | | struct cmELFByteSwapSize |
33 | | { |
34 | | }; |
35 | | static void cmELFByteSwap(char* data, cmELFByteSwapSize<2> /*unused*/) |
36 | 3.50k | { |
37 | 3.50k | char one_byte; |
38 | 3.50k | one_byte = data[0]; |
39 | 3.50k | data[0] = data[1]; |
40 | 3.50k | data[1] = one_byte; |
41 | 3.50k | } |
42 | | static void cmELFByteSwap(char* data, cmELFByteSwapSize<4> /*unused*/) |
43 | 40.8M | { |
44 | 40.8M | char one_byte; |
45 | 40.8M | one_byte = data[0]; |
46 | 40.8M | data[0] = data[3]; |
47 | 40.8M | data[3] = one_byte; |
48 | 40.8M | one_byte = data[1]; |
49 | 40.8M | data[1] = data[2]; |
50 | 40.8M | data[2] = one_byte; |
51 | 40.8M | } |
52 | | static void cmELFByteSwap(char* data, cmELFByteSwapSize<8> /*unused*/) |
53 | 37.7M | { |
54 | 37.7M | char one_byte; |
55 | 37.7M | one_byte = data[0]; |
56 | 37.7M | data[0] = data[7]; |
57 | 37.7M | data[7] = one_byte; |
58 | 37.7M | one_byte = data[1]; |
59 | 37.7M | data[1] = data[6]; |
60 | 37.7M | data[6] = one_byte; |
61 | 37.7M | one_byte = data[2]; |
62 | 37.7M | data[2] = data[5]; |
63 | 37.7M | data[5] = one_byte; |
64 | 37.7M | one_byte = data[3]; |
65 | 37.7M | data[3] = data[4]; |
66 | 37.7M | data[4] = one_byte; |
67 | 37.7M | } |
68 | | |
69 | | // Low-level byte swapping interface. |
70 | | template <typename T> |
71 | | void cmELFByteSwap(T& x) |
72 | 78.5M | { |
73 | 78.5M | cmELFByteSwap(reinterpret_cast<char*>(&x), cmELFByteSwapSize<sizeof(T)>()); |
74 | 78.5M | } void cmELFByteSwap<unsigned short>(unsigned short&) Line | Count | Source | 72 | 3.50k | { | 73 | 3.50k | cmELFByteSwap(reinterpret_cast<char*>(&x), cmELFByteSwapSize<sizeof(T)>()); | 74 | 3.50k | } |
void cmELFByteSwap<unsigned int>(unsigned int&) Line | Count | Source | 72 | 40.6M | { | 73 | 40.6M | cmELFByteSwap(reinterpret_cast<char*>(&x), cmELFByteSwapSize<sizeof(T)>()); | 74 | 40.6M | } |
void cmELFByteSwap<int>(int&) Line | Count | Source | 72 | 162k | { | 73 | 162k | cmELFByteSwap(reinterpret_cast<char*>(&x), cmELFByteSwapSize<sizeof(T)>()); | 74 | 162k | } |
void cmELFByteSwap<unsigned long>(unsigned long&) Line | Count | Source | 72 | 37.7M | { | 73 | 37.7M | cmELFByteSwap(reinterpret_cast<char*>(&x), cmELFByteSwapSize<sizeof(T)>()); | 74 | 37.7M | } |
void cmELFByteSwap<long>(long&) Line | Count | Source | 72 | 2.26k | { | 73 | 2.26k | cmELFByteSwap(reinterpret_cast<char*>(&x), cmELFByteSwapSize<sizeof(T)>()); | 74 | 2.26k | } |
|
75 | | |
76 | | class cmELFInternal |
77 | | { |
78 | | public: |
79 | | using StringEntry = cmELF::StringEntry; |
80 | | enum ByteOrderType |
81 | | { |
82 | | ByteOrderMSB, |
83 | | ByteOrderLSB |
84 | | }; |
85 | | |
86 | | // Construct and take ownership of the file stream object. |
87 | | cmELFInternal(cmELF* external, std::unique_ptr<std::istream> fin, |
88 | | ByteOrderType order) |
89 | 1.13k | : External(external) |
90 | 1.13k | , Stream(std::move(fin)) |
91 | 1.13k | , ByteOrder(order) |
92 | 1.13k | { |
93 | | // In most cases the processor-specific byte order will match that |
94 | | // of the target execution environment. If we choose wrong here |
95 | | // it is fixed when the header is read. |
96 | 1.13k | #if KWIML_ABI_ENDIAN_ID == KWIML_ABI_ENDIAN_ID_LITTLE |
97 | 1.13k | this->NeedSwap = (this->ByteOrder == ByteOrderMSB); |
98 | | #elif KWIML_ABI_ENDIAN_ID == KWIML_ABI_ENDIAN_ID_BIG |
99 | | this->NeedSwap = (this->ByteOrder == ByteOrderLSB); |
100 | | #else |
101 | | this->NeedSwap = false; // Final decision is at runtime anyway. |
102 | | #endif |
103 | | |
104 | | // We have not yet loaded the section info. |
105 | 1.13k | this->DynamicSectionIndex = -1; |
106 | 1.13k | } |
107 | | |
108 | | // Destruct and delete the file stream object. |
109 | 1.13k | virtual ~cmELFInternal() = default; |
110 | | |
111 | | // Forward to the per-class implementation. |
112 | | virtual std::size_t GetNumberOfSections() const = 0; |
113 | | virtual unsigned long GetDynamicEntryPosition(int j) = 0; |
114 | | virtual cmELF::DynamicEntryList GetDynamicEntries() = 0; |
115 | | virtual std::vector<char> EncodeDynamicEntries( |
116 | | cmELF::DynamicEntryList const&) = 0; |
117 | | virtual StringEntry const* GetDynamicSectionString(unsigned int tag) = 0; |
118 | | virtual bool IsMips() const = 0; |
119 | | virtual void PrintInfo(std::ostream& os) const = 0; |
120 | | |
121 | | /** Returns true if the ELF file has a dynamic section **/ |
122 | 12.6k | bool HasDynamicSection() const { return this->DynamicSectionIndex >= 0; } |
123 | | |
124 | | // Lookup the SONAME in the DYNAMIC section. |
125 | | StringEntry const* GetSOName() |
126 | 696 | { |
127 | 696 | return this->GetDynamicSectionString(DT_SONAME); |
128 | 696 | } |
129 | | |
130 | | // Lookup the RPATH in the DYNAMIC section. |
131 | | StringEntry const* GetRPath() |
132 | 615 | { |
133 | 615 | return this->GetDynamicSectionString(DT_RPATH); |
134 | 615 | } |
135 | | |
136 | | // Lookup the RUNPATH in the DYNAMIC section. |
137 | | StringEntry const* GetRunPath() |
138 | 336 | { |
139 | 336 | return this->GetDynamicSectionString(DT_RUNPATH); |
140 | 336 | } |
141 | | |
142 | | // Return the recorded ELF type. |
143 | 26.1k | cmELF::FileType GetFileType() const { return this->ELFType; } |
144 | | |
145 | | // Return the recorded machine. |
146 | 913 | std::uint16_t GetMachine() const { return this->Machine; } |
147 | | |
148 | | protected: |
149 | | // Data common to all ELF class implementations. |
150 | | |
151 | | // The external cmELF object. |
152 | | cmELF* External; |
153 | | |
154 | | // The stream from which to read. |
155 | | std::unique_ptr<std::istream> Stream; |
156 | | |
157 | | // The byte order of the ELF file. |
158 | | ByteOrderType ByteOrder; |
159 | | |
160 | | // The ELF file type. |
161 | | cmELF::FileType ELFType = cmELF::FileTypeInvalid; |
162 | | |
163 | | // The ELF architecture. |
164 | | std::uint16_t Machine; |
165 | | |
166 | | // Whether we need to byte-swap structures read from the stream. |
167 | | bool NeedSwap; |
168 | | |
169 | | // The section header index of the DYNAMIC section (-1 if none). |
170 | | int DynamicSectionIndex; |
171 | | |
172 | | // Helper methods for subclasses. |
173 | | void SetErrorMessage(char const* msg) |
174 | 692 | { |
175 | 692 | this->External->ErrorMessage = msg; |
176 | 692 | this->ELFType = cmELF::FileTypeInvalid; |
177 | 692 | } |
178 | | |
179 | | // Store string table entry states. |
180 | | std::map<unsigned int, StringEntry> DynamicSectionStrings; |
181 | | }; |
182 | | |
183 | | // Configure the implementation template for 32-bit ELF files. |
184 | | struct cmELFTypes32 |
185 | | { |
186 | | using ELF_Ehdr = Elf32_Ehdr; |
187 | | using ELF_Shdr = Elf32_Shdr; |
188 | | using ELF_Dyn = Elf32_Dyn; |
189 | | using ELF_Half = Elf32_Half; |
190 | | using tagtype = ::uint32_t; |
191 | 200 | static char const* GetName() { return "32-bit"; } |
192 | | }; |
193 | | |
194 | | // Configure the implementation template for 64-bit ELF files. |
195 | | struct cmELFTypes64 |
196 | | { |
197 | | using ELF_Ehdr = Elf64_Ehdr; |
198 | | using ELF_Shdr = Elf64_Shdr; |
199 | | using ELF_Dyn = Elf64_Dyn; |
200 | | using ELF_Half = Elf64_Half; |
201 | | using tagtype = ::uint64_t; |
202 | 245 | static char const* GetName() { return "64-bit"; } |
203 | | }; |
204 | | |
205 | | // Parser implementation template. |
206 | | template <class Types> |
207 | | class cmELFInternalImpl : public cmELFInternal |
208 | | { |
209 | | public: |
210 | | // Copy the ELF file format types from our configuration parameter. |
211 | | using ELF_Ehdr = typename Types::ELF_Ehdr; |
212 | | using ELF_Shdr = typename Types::ELF_Shdr; |
213 | | using ELF_Dyn = typename Types::ELF_Dyn; |
214 | | using ELF_Half = typename Types::ELF_Half; |
215 | | using tagtype = typename Types::tagtype; |
216 | | |
217 | | // Construct with a stream and byte swap indicator. |
218 | | cmELFInternalImpl(cmELF* external, std::unique_ptr<std::istream> fin, |
219 | | ByteOrderType order); |
220 | | |
221 | | // Return the number of sections as specified by the ELF header. |
222 | | std::size_t GetNumberOfSections() const override |
223 | 1.97k | { |
224 | 1.97k | std::size_t count = this->ELFHeader.e_shnum; |
225 | 1.97k | if (!this->SectionHeaders.empty()) { |
226 | 1.97k | count += static_cast<std::size_t>(this->SectionHeaders[0].sh_size); |
227 | 1.97k | } |
228 | | // Prevent OOM from malformed files. |
229 | 1.97k | if (count > kMaxSections) { |
230 | 673 | return kMaxSections; |
231 | 673 | } |
232 | 1.29k | return count; |
233 | 1.97k | } cmELFInternalImpl<cmELFTypes32>::GetNumberOfSections() const Line | Count | Source | 223 | 743 | { | 224 | 743 | std::size_t count = this->ELFHeader.e_shnum; | 225 | 743 | if (!this->SectionHeaders.empty()) { | 226 | 743 | count += static_cast<std::size_t>(this->SectionHeaders[0].sh_size); | 227 | 743 | } | 228 | | // Prevent OOM from malformed files. | 229 | 743 | if (count > kMaxSections) { | 230 | 295 | return kMaxSections; | 231 | 295 | } | 232 | 448 | return count; | 233 | 743 | } |
cmELFInternalImpl<cmELFTypes64>::GetNumberOfSections() const Line | Count | Source | 223 | 1.22k | { | 224 | 1.22k | std::size_t count = this->ELFHeader.e_shnum; | 225 | 1.22k | if (!this->SectionHeaders.empty()) { | 226 | 1.22k | count += static_cast<std::size_t>(this->SectionHeaders[0].sh_size); | 227 | 1.22k | } | 228 | | // Prevent OOM from malformed files. | 229 | 1.22k | if (count > kMaxSections) { | 230 | 378 | return kMaxSections; | 231 | 378 | } | 232 | 849 | return count; | 233 | 1.22k | } |
|
234 | | |
235 | | // Get the file position of a dynamic section entry. |
236 | | unsigned long GetDynamicEntryPosition(int j) override; |
237 | | |
238 | | cmELF::DynamicEntryList GetDynamicEntries() override; |
239 | | std::vector<char> EncodeDynamicEntries( |
240 | | cmELF::DynamicEntryList const&) override; |
241 | | |
242 | | // Lookup a string from the dynamic section with the given tag. |
243 | | StringEntry const* GetDynamicSectionString(unsigned int tag) override; |
244 | | |
245 | 913 | bool IsMips() const override { return this->ELFHeader.e_machine == EM_MIPS; }cmELFInternalImpl<cmELFTypes32>::IsMips() const Line | Count | Source | 245 | 354 | bool IsMips() const override { return this->ELFHeader.e_machine == EM_MIPS; } |
cmELFInternalImpl<cmELFTypes64>::IsMips() const Line | Count | Source | 245 | 559 | bool IsMips() const override { return this->ELFHeader.e_machine == EM_MIPS; } |
|
246 | | |
247 | | // Print information about the ELF file. |
248 | | void PrintInfo(std::ostream& os) const override |
249 | 445 | { |
250 | 445 | os << "ELF " << Types::GetName(); |
251 | 445 | if (this->ByteOrder == ByteOrderMSB) { |
252 | 63 | os << " MSB"; |
253 | 382 | } else if (this->ByteOrder == ByteOrderLSB) { |
254 | 382 | os << " LSB"; |
255 | 382 | } |
256 | 445 | switch (this->ELFType) { |
257 | 0 | case cmELF::FileTypeInvalid: |
258 | 0 | os << " invalid file"; |
259 | 0 | break; |
260 | 26 | case cmELF::FileTypeRelocatableObject: |
261 | 26 | os << " relocatable object"; |
262 | 26 | break; |
263 | 136 | case cmELF::FileTypeExecutable: |
264 | 136 | os << " executable"; |
265 | 136 | break; |
266 | 177 | case cmELF::FileTypeSharedLibrary: |
267 | 177 | os << " shared library"; |
268 | 177 | break; |
269 | 14 | case cmELF::FileTypeCore: |
270 | 14 | os << " core file"; |
271 | 14 | break; |
272 | 22 | case cmELF::FileTypeSpecificOS: |
273 | 22 | os << " os-specific type"; |
274 | 22 | break; |
275 | 70 | case cmELF::FileTypeSpecificProc: |
276 | 70 | os << " processor-specific type"; |
277 | 70 | break; |
278 | 445 | } |
279 | 445 | os << "\n"; |
280 | 445 | } cmELFInternalImpl<cmELFTypes32>::PrintInfo(std::__1::basic_ostream<char, std::__1::char_traits<char> >&) const Line | Count | Source | 249 | 200 | { | 250 | 200 | os << "ELF " << Types::GetName(); | 251 | 200 | if (this->ByteOrder == ByteOrderMSB) { | 252 | 19 | os << " MSB"; | 253 | 181 | } else if (this->ByteOrder == ByteOrderLSB) { | 254 | 181 | os << " LSB"; | 255 | 181 | } | 256 | 200 | switch (this->ELFType) { | 257 | 0 | case cmELF::FileTypeInvalid: | 258 | 0 | os << " invalid file"; | 259 | 0 | break; | 260 | 11 | case cmELF::FileTypeRelocatableObject: | 261 | 11 | os << " relocatable object"; | 262 | 11 | break; | 263 | 55 | case cmELF::FileTypeExecutable: | 264 | 55 | os << " executable"; | 265 | 55 | break; | 266 | 85 | case cmELF::FileTypeSharedLibrary: | 267 | 85 | os << " shared library"; | 268 | 85 | break; | 269 | 10 | case cmELF::FileTypeCore: | 270 | 10 | os << " core file"; | 271 | 10 | break; | 272 | 7 | case cmELF::FileTypeSpecificOS: | 273 | 7 | os << " os-specific type"; | 274 | 7 | break; | 275 | 32 | case cmELF::FileTypeSpecificProc: | 276 | 32 | os << " processor-specific type"; | 277 | 32 | break; | 278 | 200 | } | 279 | 200 | os << "\n"; | 280 | 200 | } |
cmELFInternalImpl<cmELFTypes64>::PrintInfo(std::__1::basic_ostream<char, std::__1::char_traits<char> >&) const Line | Count | Source | 249 | 245 | { | 250 | 245 | os << "ELF " << Types::GetName(); | 251 | 245 | if (this->ByteOrder == ByteOrderMSB) { | 252 | 44 | os << " MSB"; | 253 | 201 | } else if (this->ByteOrder == ByteOrderLSB) { | 254 | 201 | os << " LSB"; | 255 | 201 | } | 256 | 245 | switch (this->ELFType) { | 257 | 0 | case cmELF::FileTypeInvalid: | 258 | 0 | os << " invalid file"; | 259 | 0 | break; | 260 | 15 | case cmELF::FileTypeRelocatableObject: | 261 | 15 | os << " relocatable object"; | 262 | 15 | break; | 263 | 81 | case cmELF::FileTypeExecutable: | 264 | 81 | os << " executable"; | 265 | 81 | break; | 266 | 92 | case cmELF::FileTypeSharedLibrary: | 267 | 92 | os << " shared library"; | 268 | 92 | break; | 269 | 4 | case cmELF::FileTypeCore: | 270 | 4 | os << " core file"; | 271 | 4 | break; | 272 | 15 | case cmELF::FileTypeSpecificOS: | 273 | 15 | os << " os-specific type"; | 274 | 15 | break; | 275 | 38 | case cmELF::FileTypeSpecificProc: | 276 | 38 | os << " processor-specific type"; | 277 | 38 | break; | 278 | 245 | } | 279 | 245 | os << "\n"; | 280 | 245 | } |
|
281 | | |
282 | | private: |
283 | | static_assert(sizeof(ELF_Dyn().d_un.d_val) == sizeof(ELF_Dyn().d_un.d_ptr), |
284 | | "ByteSwap(ELF_Dyn) assumes d_val and d_ptr are the same size"); |
285 | | |
286 | | void ByteSwap(ELF_Ehdr& elf_header) |
287 | 348 | { |
288 | 348 | cmELFByteSwap(elf_header.e_type); |
289 | 348 | cmELFByteSwap(elf_header.e_machine); |
290 | 348 | cmELFByteSwap(elf_header.e_version); |
291 | 348 | cmELFByteSwap(elf_header.e_entry); |
292 | 348 | cmELFByteSwap(elf_header.e_phoff); |
293 | 348 | cmELFByteSwap(elf_header.e_shoff); |
294 | 348 | cmELFByteSwap(elf_header.e_flags); |
295 | 348 | cmELFByteSwap(elf_header.e_ehsize); |
296 | 348 | cmELFByteSwap(elf_header.e_phentsize); |
297 | 348 | cmELFByteSwap(elf_header.e_phnum); |
298 | 348 | cmELFByteSwap(elf_header.e_shentsize); |
299 | 348 | cmELFByteSwap(elf_header.e_shnum); |
300 | 348 | cmELFByteSwap(elf_header.e_shstrndx); |
301 | 348 | } cmELFInternalImpl<cmELFTypes32>::ByteSwap(Elf32_Ehdr&) Line | Count | Source | 287 | 89 | { | 288 | 89 | cmELFByteSwap(elf_header.e_type); | 289 | 89 | cmELFByteSwap(elf_header.e_machine); | 290 | 89 | cmELFByteSwap(elf_header.e_version); | 291 | 89 | cmELFByteSwap(elf_header.e_entry); | 292 | 89 | cmELFByteSwap(elf_header.e_phoff); | 293 | 89 | cmELFByteSwap(elf_header.e_shoff); | 294 | 89 | cmELFByteSwap(elf_header.e_flags); | 295 | 89 | cmELFByteSwap(elf_header.e_ehsize); | 296 | 89 | cmELFByteSwap(elf_header.e_phentsize); | 297 | 89 | cmELFByteSwap(elf_header.e_phnum); | 298 | 89 | cmELFByteSwap(elf_header.e_shentsize); | 299 | 89 | cmELFByteSwap(elf_header.e_shnum); | 300 | 89 | cmELFByteSwap(elf_header.e_shstrndx); | 301 | 89 | } |
cmELFInternalImpl<cmELFTypes64>::ByteSwap(Elf64_Ehdr&) Line | Count | Source | 287 | 259 | { | 288 | 259 | cmELFByteSwap(elf_header.e_type); | 289 | 259 | cmELFByteSwap(elf_header.e_machine); | 290 | 259 | cmELFByteSwap(elf_header.e_version); | 291 | 259 | cmELFByteSwap(elf_header.e_entry); | 292 | 259 | cmELFByteSwap(elf_header.e_phoff); | 293 | 259 | cmELFByteSwap(elf_header.e_shoff); | 294 | 259 | cmELFByteSwap(elf_header.e_flags); | 295 | 259 | cmELFByteSwap(elf_header.e_ehsize); | 296 | 259 | cmELFByteSwap(elf_header.e_phentsize); | 297 | 259 | cmELFByteSwap(elf_header.e_phnum); | 298 | 259 | cmELFByteSwap(elf_header.e_shentsize); | 299 | 259 | cmELFByteSwap(elf_header.e_shnum); | 300 | 259 | cmELFByteSwap(elf_header.e_shstrndx); | 301 | 259 | } |
|
302 | | |
303 | | void ByteSwap(ELF_Shdr& sec_header) |
304 | 7.82M | { |
305 | 7.82M | cmELFByteSwap(sec_header.sh_name); |
306 | 7.82M | cmELFByteSwap(sec_header.sh_type); |
307 | 7.82M | cmELFByteSwap(sec_header.sh_flags); |
308 | 7.82M | cmELFByteSwap(sec_header.sh_addr); |
309 | 7.82M | cmELFByteSwap(sec_header.sh_offset); |
310 | 7.82M | cmELFByteSwap(sec_header.sh_size); |
311 | 7.82M | cmELFByteSwap(sec_header.sh_link); |
312 | 7.82M | cmELFByteSwap(sec_header.sh_info); |
313 | 7.82M | cmELFByteSwap(sec_header.sh_addralign); |
314 | 7.82M | cmELFByteSwap(sec_header.sh_entsize); |
315 | 7.82M | } cmELFInternalImpl<cmELFTypes32>::ByteSwap(Elf32_Shdr&) Line | Count | Source | 304 | 1.53M | { | 305 | 1.53M | cmELFByteSwap(sec_header.sh_name); | 306 | 1.53M | cmELFByteSwap(sec_header.sh_type); | 307 | 1.53M | cmELFByteSwap(sec_header.sh_flags); | 308 | 1.53M | cmELFByteSwap(sec_header.sh_addr); | 309 | 1.53M | cmELFByteSwap(sec_header.sh_offset); | 310 | 1.53M | cmELFByteSwap(sec_header.sh_size); | 311 | 1.53M | cmELFByteSwap(sec_header.sh_link); | 312 | 1.53M | cmELFByteSwap(sec_header.sh_info); | 313 | 1.53M | cmELFByteSwap(sec_header.sh_addralign); | 314 | 1.53M | cmELFByteSwap(sec_header.sh_entsize); | 315 | 1.53M | } |
cmELFInternalImpl<cmELFTypes64>::ByteSwap(Elf64_Shdr&) Line | Count | Source | 304 | 6.29M | { | 305 | 6.29M | cmELFByteSwap(sec_header.sh_name); | 306 | 6.29M | cmELFByteSwap(sec_header.sh_type); | 307 | 6.29M | cmELFByteSwap(sec_header.sh_flags); | 308 | 6.29M | cmELFByteSwap(sec_header.sh_addr); | 309 | 6.29M | cmELFByteSwap(sec_header.sh_offset); | 310 | 6.29M | cmELFByteSwap(sec_header.sh_size); | 311 | 6.29M | cmELFByteSwap(sec_header.sh_link); | 312 | 6.29M | cmELFByteSwap(sec_header.sh_info); | 313 | 6.29M | cmELFByteSwap(sec_header.sh_addralign); | 314 | 6.29M | cmELFByteSwap(sec_header.sh_entsize); | 315 | 6.29M | } |
|
316 | | |
317 | | void ByteSwap(ELF_Dyn& dyn) |
318 | 164k | { |
319 | 164k | cmELFByteSwap(dyn.d_tag); |
320 | 164k | cmELFByteSwap(dyn.d_un.d_val); |
321 | 164k | } cmELFInternalImpl<cmELFTypes32>::ByteSwap(Elf32_Dyn&) Line | Count | Source | 318 | 162k | { | 319 | 162k | cmELFByteSwap(dyn.d_tag); | 320 | 162k | cmELFByteSwap(dyn.d_un.d_val); | 321 | 162k | } |
cmELFInternalImpl<cmELFTypes64>::ByteSwap(Elf64_Dyn&) Line | Count | Source | 318 | 2.26k | { | 319 | 2.26k | cmELFByteSwap(dyn.d_tag); | 320 | 2.26k | cmELFByteSwap(dyn.d_un.d_val); | 321 | 2.26k | } |
|
322 | | |
323 | | bool FileTypeValid(ELF_Half et) |
324 | 1.63k | { |
325 | 1.63k | unsigned int eti = static_cast<unsigned int>(et); |
326 | 1.63k | if (eti == ET_NONE || eti == ET_REL || eti == ET_EXEC || eti == ET_DYN || |
327 | 835 | eti == ET_CORE) { |
328 | 830 | return true; |
329 | 830 | } |
330 | 805 | if (eti >= ET_LOOS && eti <= ET_HIOS) { |
331 | 51 | return true; |
332 | 51 | } |
333 | 754 | if (eti >= ET_LOPROC && eti <= ET_HIPROC) { |
334 | 200 | return true; |
335 | 200 | } |
336 | 554 | return false; |
337 | 754 | } cmELFInternalImpl<cmELFTypes32>::FileTypeValid(unsigned short) Line | Count | Source | 324 | 518 | { | 325 | 518 | unsigned int eti = static_cast<unsigned int>(et); | 326 | 518 | if (eti == ET_NONE || eti == ET_REL || eti == ET_EXEC || eti == ET_DYN || | 327 | 311 | eti == ET_CORE) { | 328 | 311 | return true; | 329 | 311 | } | 330 | 207 | if (eti >= ET_LOOS && eti <= ET_HIOS) { | 331 | 20 | return true; | 332 | 20 | } | 333 | 187 | if (eti >= ET_LOPROC && eti <= ET_HIPROC) { | 334 | 73 | return true; | 335 | 73 | } | 336 | 114 | return false; | 337 | 187 | } |
cmELFInternalImpl<cmELFTypes64>::FileTypeValid(unsigned short) Line | Count | Source | 324 | 1.11k | { | 325 | 1.11k | unsigned int eti = static_cast<unsigned int>(et); | 326 | 1.11k | if (eti == ET_NONE || eti == ET_REL || eti == ET_EXEC || eti == ET_DYN || | 327 | 615 | eti == ET_CORE) { | 328 | 519 | return true; | 329 | 519 | } | 330 | 598 | if (eti >= ET_LOOS && eti <= ET_HIOS) { | 331 | 31 | return true; | 332 | 31 | } | 333 | 567 | if (eti >= ET_LOPROC && eti <= ET_HIPROC) { | 334 | 127 | return true; | 335 | 127 | } | 336 | 440 | return false; | 337 | 567 | } |
|
338 | | |
339 | | bool Read(ELF_Ehdr& x) |
340 | 1.13k | { |
341 | | // Read the header from the file. |
342 | 1.13k | if (!this->Stream->read(reinterpret_cast<char*>(&x), sizeof(x))) { |
343 | 5 | return false; |
344 | 5 | } |
345 | | |
346 | | // The byte order of ELF header fields may not match that of the |
347 | | // processor-specific data. The header fields are ordered to |
348 | | // match the target execution environment, so we may need to |
349 | | // memorize the order of all platforms based on the e_machine |
350 | | // value. As a heuristic, if the type is invalid but its |
351 | | // swapped value is okay then flip our swap mode. |
352 | 1.13k | ELF_Half et = x.e_type; |
353 | 1.13k | if (this->NeedSwap) { |
354 | 214 | cmELFByteSwap(et); |
355 | 214 | } |
356 | 1.13k | if (!this->FileTypeValid(et)) { |
357 | 503 | cmELFByteSwap(et); |
358 | 503 | if (this->FileTypeValid(et)) { |
359 | | // The previous byte order guess was wrong. Flip it. |
360 | 452 | this->NeedSwap = !this->NeedSwap; |
361 | 452 | } |
362 | 503 | } |
363 | | |
364 | | // Fix the byte order of the header. |
365 | 1.13k | if (this->NeedSwap) { |
366 | 348 | this->ByteSwap(x); |
367 | 348 | } |
368 | 1.13k | return true; |
369 | 1.13k | } cmELFInternalImpl<cmELFTypes32>::Read(Elf32_Ehdr&) Line | Count | Source | 340 | 432 | { | 341 | | // Read the header from the file. | 342 | 432 | if (!this->Stream->read(reinterpret_cast<char*>(&x), sizeof(x))) { | 343 | 2 | return false; | 344 | 2 | } | 345 | | | 346 | | // The byte order of ELF header fields may not match that of the | 347 | | // processor-specific data. The header fields are ordered to | 348 | | // match the target execution environment, so we may need to | 349 | | // memorize the order of all platforms based on the e_machine | 350 | | // value. As a heuristic, if the type is invalid but its | 351 | | // swapped value is okay then flip our swap mode. | 352 | 430 | ELF_Half et = x.e_type; | 353 | 430 | if (this->NeedSwap) { | 354 | 39 | cmELFByteSwap(et); | 355 | 39 | } | 356 | 430 | if (!this->FileTypeValid(et)) { | 357 | 88 | cmELFByteSwap(et); | 358 | 88 | if (this->FileTypeValid(et)) { | 359 | | // The previous byte order guess was wrong. Flip it. | 360 | 62 | this->NeedSwap = !this->NeedSwap; | 361 | 62 | } | 362 | 88 | } | 363 | | | 364 | | // Fix the byte order of the header. | 365 | 430 | if (this->NeedSwap) { | 366 | 89 | this->ByteSwap(x); | 367 | 89 | } | 368 | 430 | return true; | 369 | 432 | } |
cmELFInternalImpl<cmELFTypes64>::Read(Elf64_Ehdr&) Line | Count | Source | 340 | 705 | { | 341 | | // Read the header from the file. | 342 | 705 | if (!this->Stream->read(reinterpret_cast<char*>(&x), sizeof(x))) { | 343 | 3 | return false; | 344 | 3 | } | 345 | | | 346 | | // The byte order of ELF header fields may not match that of the | 347 | | // processor-specific data. The header fields are ordered to | 348 | | // match the target execution environment, so we may need to | 349 | | // memorize the order of all platforms based on the e_machine | 350 | | // value. As a heuristic, if the type is invalid but its | 351 | | // swapped value is okay then flip our swap mode. | 352 | 702 | ELF_Half et = x.e_type; | 353 | 702 | if (this->NeedSwap) { | 354 | 175 | cmELFByteSwap(et); | 355 | 175 | } | 356 | 702 | if (!this->FileTypeValid(et)) { | 357 | 415 | cmELFByteSwap(et); | 358 | 415 | if (this->FileTypeValid(et)) { | 359 | | // The previous byte order guess was wrong. Flip it. | 360 | 390 | this->NeedSwap = !this->NeedSwap; | 361 | 390 | } | 362 | 415 | } | 363 | | | 364 | | // Fix the byte order of the header. | 365 | 702 | if (this->NeedSwap) { | 366 | 259 | this->ByteSwap(x); | 367 | 259 | } | 368 | 702 | return true; | 369 | 705 | } |
|
370 | | bool Read(ELF_Shdr& x) |
371 | 27.2M | { |
372 | 27.2M | if (this->Stream->read(reinterpret_cast<char*>(&x), sizeof(x)) && |
373 | 27.2M | this->NeedSwap) { |
374 | 7.82M | this->ByteSwap(x); |
375 | 7.82M | } |
376 | 27.2M | return !this->Stream->fail(); |
377 | 27.2M | } cmELFInternalImpl<cmELFTypes32>::Read(Elf32_Shdr&) Line | Count | Source | 371 | 13.6M | { | 372 | 13.6M | if (this->Stream->read(reinterpret_cast<char*>(&x), sizeof(x)) && | 373 | 13.6M | this->NeedSwap) { | 374 | 1.53M | this->ByteSwap(x); | 375 | 1.53M | } | 376 | 13.6M | return !this->Stream->fail(); | 377 | 13.6M | } |
cmELFInternalImpl<cmELFTypes64>::Read(Elf64_Shdr&) Line | Count | Source | 371 | 13.6M | { | 372 | 13.6M | if (this->Stream->read(reinterpret_cast<char*>(&x), sizeof(x)) && | 373 | 13.6M | this->NeedSwap) { | 374 | 6.29M | this->ByteSwap(x); | 375 | 6.29M | } | 376 | 13.6M | return !this->Stream->fail(); | 377 | 13.6M | } |
|
378 | | bool Read(ELF_Dyn& x) |
379 | 1.72M | { |
380 | 1.72M | if (this->Stream->read(reinterpret_cast<char*>(&x), sizeof(x)) && |
381 | 1.72M | this->NeedSwap) { |
382 | 82.6k | this->ByteSwap(x); |
383 | 82.6k | } |
384 | 1.72M | return !this->Stream->fail(); |
385 | 1.72M | } cmELFInternalImpl<cmELFTypes32>::Read(Elf32_Dyn&) Line | Count | Source | 379 | 1.49M | { | 380 | 1.49M | if (this->Stream->read(reinterpret_cast<char*>(&x), sizeof(x)) && | 381 | 1.49M | this->NeedSwap) { | 382 | 81.4k | this->ByteSwap(x); | 383 | 81.4k | } | 384 | 1.49M | return !this->Stream->fail(); | 385 | 1.49M | } |
cmELFInternalImpl<cmELFTypes64>::Read(Elf64_Dyn&) Line | Count | Source | 379 | 228k | { | 380 | 228k | if (this->Stream->read(reinterpret_cast<char*>(&x), sizeof(x)) && | 381 | 228k | this->NeedSwap) { | 382 | 1.19k | this->ByteSwap(x); | 383 | 1.19k | } | 384 | 228k | return !this->Stream->fail(); | 385 | 228k | } |
|
386 | | |
387 | | bool LoadSectionHeader(std::size_t i) |
388 | 27.2M | { |
389 | | // Read the section header from the file. |
390 | 27.2M | this->Stream->seekg(this->ELFHeader.e_shoff + |
391 | 27.2M | this->ELFHeader.e_shentsize * i); |
392 | 27.2M | if (!this->Read(this->SectionHeaders[i])) { |
393 | 166 | this->SetErrorMessage("Failed to load section headers."); |
394 | 166 | return false; |
395 | 166 | } |
396 | | |
397 | | // Identify some important sections. |
398 | 27.2M | if (this->SectionHeaders[i].sh_type == SHT_DYNAMIC) { |
399 | 22.4M | this->DynamicSectionIndex = static_cast<int>(i); |
400 | 22.4M | } |
401 | 27.2M | return true; |
402 | 27.2M | } cmELFInternalImpl<cmELFTypes32>::LoadSectionHeader(unsigned long) Line | Count | Source | 388 | 13.6M | { | 389 | | // Read the section header from the file. | 390 | 13.6M | this->Stream->seekg(this->ELFHeader.e_shoff + | 391 | 13.6M | this->ELFHeader.e_shentsize * i); | 392 | 13.6M | if (!this->Read(this->SectionHeaders[i])) { | 393 | 49 | this->SetErrorMessage("Failed to load section headers."); | 394 | 49 | return false; | 395 | 49 | } | 396 | | | 397 | | // Identify some important sections. | 398 | 13.6M | if (this->SectionHeaders[i].sh_type == SHT_DYNAMIC) { | 399 | 11.8M | this->DynamicSectionIndex = static_cast<int>(i); | 400 | 11.8M | } | 401 | 13.6M | return true; | 402 | 13.6M | } |
cmELFInternalImpl<cmELFTypes64>::LoadSectionHeader(unsigned long) Line | Count | Source | 388 | 13.6M | { | 389 | | // Read the section header from the file. | 390 | 13.6M | this->Stream->seekg(this->ELFHeader.e_shoff + | 391 | 13.6M | this->ELFHeader.e_shentsize * i); | 392 | 13.6M | if (!this->Read(this->SectionHeaders[i])) { | 393 | 117 | this->SetErrorMessage("Failed to load section headers."); | 394 | 117 | return false; | 395 | 117 | } | 396 | | | 397 | | // Identify some important sections. | 398 | 13.6M | if (this->SectionHeaders[i].sh_type == SHT_DYNAMIC) { | 399 | 10.6M | this->DynamicSectionIndex = static_cast<int>(i); | 400 | 10.6M | } | 401 | 13.6M | return true; | 402 | 13.6M | } |
|
403 | | |
404 | | bool LoadDynamicSection(); |
405 | | |
406 | | // Store the main ELF header. |
407 | | ELF_Ehdr ELFHeader; |
408 | | |
409 | | // Store all the section headers. |
410 | | std::vector<ELF_Shdr> SectionHeaders; |
411 | | |
412 | | // Store all entries of the DYNAMIC section. |
413 | | std::vector<ELF_Dyn> DynamicSectionEntries; |
414 | | }; |
415 | | |
416 | | template <class Types> |
417 | | cmELFInternalImpl<Types>::cmELFInternalImpl(cmELF* external, |
418 | | std::unique_ptr<std::istream> fin, |
419 | | ByteOrderType order) |
420 | 1.13k | : cmELFInternal(external, std::move(fin), order) |
421 | 1.13k | { |
422 | | // Read the main header. |
423 | 1.13k | if (!this->Read(this->ELFHeader)) { |
424 | 5 | this->SetErrorMessage("Failed to read main ELF header."); |
425 | 5 | return; |
426 | 5 | } |
427 | | |
428 | | // Determine the ELF file type. |
429 | 1.13k | switch (this->ELFHeader.e_type) { |
430 | 2 | case ET_NONE: |
431 | 2 | this->SetErrorMessage("ELF file type is NONE."); |
432 | 2 | return; |
433 | 46 | case ET_REL: |
434 | 46 | this->ELFType = cmELF::FileTypeRelocatableObject; |
435 | 46 | break; |
436 | 338 | case ET_EXEC: |
437 | 338 | this->ELFType = cmELF::FileTypeExecutable; |
438 | 338 | break; |
439 | 414 | case ET_DYN: |
440 | 414 | this->ELFType = cmELF::FileTypeSharedLibrary; |
441 | 414 | break; |
442 | 30 | case ET_CORE: |
443 | 30 | this->ELFType = cmELF::FileTypeCore; |
444 | 30 | break; |
445 | 302 | default: { |
446 | 302 | unsigned int eti = static_cast<unsigned int>(this->ELFHeader.e_type); |
447 | 302 | if (eti >= ET_LOOS && eti <= ET_HIOS) { |
448 | 51 | this->ELFType = cmELF::FileTypeSpecificOS; |
449 | 51 | break; |
450 | 51 | } |
451 | 251 | if (eti >= ET_LOPROC && eti <= ET_HIPROC) { |
452 | 200 | this->ELFType = cmELF::FileTypeSpecificProc; |
453 | 200 | break; |
454 | 200 | } |
455 | 51 | std::ostringstream e; |
456 | 51 | e << "Unknown ELF file type " << eti; |
457 | 51 | this->SetErrorMessage(e.str().c_str()); |
458 | 51 | return; |
459 | 251 | } |
460 | 1.13k | } |
461 | | |
462 | 1.07k | this->Machine = this->ELFHeader.e_machine; |
463 | | |
464 | | // Load the section headers. |
465 | 1.07k | std::size_t const minSections = 1; |
466 | 1.07k | std::size_t numSections = this->ELFHeader.e_shnum; |
467 | | // Prevent OOM from malformed files. |
468 | 1.07k | if (numSections > kMaxSections) { |
469 | 0 | this->SetErrorMessage("ELF file has too many sections."); |
470 | 0 | return; |
471 | 0 | } |
472 | 1.07k | this->SectionHeaders.resize(std::max(numSections, minSections)); |
473 | 1.07k | if (!this->LoadSectionHeader(0)) { |
474 | 22 | return; |
475 | 22 | } |
476 | 1.05k | numSections = this->GetNumberOfSections(); |
477 | 1.05k | this->SectionHeaders.resize(std::max(numSections, minSections)); |
478 | 27.2M | for (std::size_t i = 1; i < numSections; ++i) { |
479 | 27.2M | if (!this->LoadSectionHeader(i)) { |
480 | 144 | return; |
481 | 144 | } |
482 | 27.2M | } |
483 | 1.05k | } cmELFInternalImpl<cmELFTypes32>::cmELFInternalImpl(cmELF*, std::__1::unique_ptr<std::__1::basic_istream<char, std::__1::char_traits<char> >, std::__1::default_delete<std::__1::basic_istream<char, std::__1::char_traits<char> > > >, cmELFInternal::ByteOrderType) Line | Count | Source | 420 | 432 | : cmELFInternal(external, std::move(fin), order) | 421 | 432 | { | 422 | | // Read the main header. | 423 | 432 | if (!this->Read(this->ELFHeader)) { | 424 | 2 | this->SetErrorMessage("Failed to read main ELF header."); | 425 | 2 | return; | 426 | 2 | } | 427 | | | 428 | | // Determine the ELF file type. | 429 | 430 | switch (this->ELFHeader.e_type) { | 430 | 1 | case ET_NONE: | 431 | 1 | this->SetErrorMessage("ELF file type is NONE."); | 432 | 1 | return; | 433 | 15 | case ET_REL: | 434 | 15 | this->ELFType = cmELF::FileTypeRelocatableObject; | 435 | 15 | break; | 436 | 126 | case ET_EXEC: | 437 | 126 | this->ELFType = cmELF::FileTypeExecutable; | 438 | 126 | break; | 439 | 156 | case ET_DYN: | 440 | 156 | this->ELFType = cmELF::FileTypeSharedLibrary; | 441 | 156 | break; | 442 | 13 | case ET_CORE: | 443 | 13 | this->ELFType = cmELF::FileTypeCore; | 444 | 13 | break; | 445 | 119 | default: { | 446 | 119 | unsigned int eti = static_cast<unsigned int>(this->ELFHeader.e_type); | 447 | 119 | if (eti >= ET_LOOS && eti <= ET_HIOS) { | 448 | 20 | this->ELFType = cmELF::FileTypeSpecificOS; | 449 | 20 | break; | 450 | 20 | } | 451 | 99 | if (eti >= ET_LOPROC && eti <= ET_HIPROC) { | 452 | 73 | this->ELFType = cmELF::FileTypeSpecificProc; | 453 | 73 | break; | 454 | 73 | } | 455 | 26 | std::ostringstream e; | 456 | 26 | e << "Unknown ELF file type " << eti; | 457 | 26 | this->SetErrorMessage(e.str().c_str()); | 458 | 26 | return; | 459 | 99 | } | 460 | 430 | } | 461 | | | 462 | 403 | this->Machine = this->ELFHeader.e_machine; | 463 | | | 464 | | // Load the section headers. | 465 | 403 | std::size_t const minSections = 1; | 466 | 403 | std::size_t numSections = this->ELFHeader.e_shnum; | 467 | | // Prevent OOM from malformed files. | 468 | 403 | if (numSections > kMaxSections) { | 469 | 0 | this->SetErrorMessage("ELF file has too many sections."); | 470 | 0 | return; | 471 | 0 | } | 472 | 403 | this->SectionHeaders.resize(std::max(numSections, minSections)); | 473 | 403 | if (!this->LoadSectionHeader(0)) { | 474 | 14 | return; | 475 | 14 | } | 476 | 389 | numSections = this->GetNumberOfSections(); | 477 | 389 | this->SectionHeaders.resize(std::max(numSections, minSections)); | 478 | 13.6M | for (std::size_t i = 1; i < numSections; ++i) { | 479 | 13.6M | if (!this->LoadSectionHeader(i)) { | 480 | 35 | return; | 481 | 35 | } | 482 | 13.6M | } | 483 | 389 | } |
cmELFInternalImpl<cmELFTypes64>::cmELFInternalImpl(cmELF*, std::__1::unique_ptr<std::__1::basic_istream<char, std::__1::char_traits<char> >, std::__1::default_delete<std::__1::basic_istream<char, std::__1::char_traits<char> > > >, cmELFInternal::ByteOrderType) Line | Count | Source | 420 | 705 | : cmELFInternal(external, std::move(fin), order) | 421 | 705 | { | 422 | | // Read the main header. | 423 | 705 | if (!this->Read(this->ELFHeader)) { | 424 | 3 | this->SetErrorMessage("Failed to read main ELF header."); | 425 | 3 | return; | 426 | 3 | } | 427 | | | 428 | | // Determine the ELF file type. | 429 | 702 | switch (this->ELFHeader.e_type) { | 430 | 1 | case ET_NONE: | 431 | 1 | this->SetErrorMessage("ELF file type is NONE."); | 432 | 1 | return; | 433 | 31 | case ET_REL: | 434 | 31 | this->ELFType = cmELF::FileTypeRelocatableObject; | 435 | 31 | break; | 436 | 212 | case ET_EXEC: | 437 | 212 | this->ELFType = cmELF::FileTypeExecutable; | 438 | 212 | break; | 439 | 258 | case ET_DYN: | 440 | 258 | this->ELFType = cmELF::FileTypeSharedLibrary; | 441 | 258 | break; | 442 | 17 | case ET_CORE: | 443 | 17 | this->ELFType = cmELF::FileTypeCore; | 444 | 17 | break; | 445 | 183 | default: { | 446 | 183 | unsigned int eti = static_cast<unsigned int>(this->ELFHeader.e_type); | 447 | 183 | if (eti >= ET_LOOS && eti <= ET_HIOS) { | 448 | 31 | this->ELFType = cmELF::FileTypeSpecificOS; | 449 | 31 | break; | 450 | 31 | } | 451 | 152 | if (eti >= ET_LOPROC && eti <= ET_HIPROC) { | 452 | 127 | this->ELFType = cmELF::FileTypeSpecificProc; | 453 | 127 | break; | 454 | 127 | } | 455 | 25 | std::ostringstream e; | 456 | 25 | e << "Unknown ELF file type " << eti; | 457 | 25 | this->SetErrorMessage(e.str().c_str()); | 458 | 25 | return; | 459 | 152 | } | 460 | 702 | } | 461 | | | 462 | 676 | this->Machine = this->ELFHeader.e_machine; | 463 | | | 464 | | // Load the section headers. | 465 | 676 | std::size_t const minSections = 1; | 466 | 676 | std::size_t numSections = this->ELFHeader.e_shnum; | 467 | | // Prevent OOM from malformed files. | 468 | 676 | if (numSections > kMaxSections) { | 469 | 0 | this->SetErrorMessage("ELF file has too many sections."); | 470 | 0 | return; | 471 | 0 | } | 472 | 676 | this->SectionHeaders.resize(std::max(numSections, minSections)); | 473 | 676 | if (!this->LoadSectionHeader(0)) { | 474 | 8 | return; | 475 | 8 | } | 476 | 668 | numSections = this->GetNumberOfSections(); | 477 | 668 | this->SectionHeaders.resize(std::max(numSections, minSections)); | 478 | 13.6M | for (std::size_t i = 1; i < numSections; ++i) { | 479 | 13.6M | if (!this->LoadSectionHeader(i)) { | 480 | 109 | return; | 481 | 109 | } | 482 | 13.6M | } | 483 | 668 | } |
|
484 | | |
485 | | template <class Types> |
486 | | bool cmELFInternalImpl<Types>::LoadDynamicSection() |
487 | 11.7k | { |
488 | | // If there is no dynamic section we are done. |
489 | 11.7k | if (!this->HasDynamicSection()) { |
490 | 240 | return false; |
491 | 240 | } |
492 | | |
493 | | // If the section was already loaded we are done. |
494 | 11.4k | if (!this->DynamicSectionEntries.empty()) { |
495 | 10.4k | return true; |
496 | 10.4k | } |
497 | | |
498 | | // If there are no entries we are done. |
499 | 1.01k | ELF_Shdr const& sec = this->SectionHeaders[this->DynamicSectionIndex]; |
500 | 1.01k | if (sec.sh_entsize == 0) { |
501 | 21 | return false; |
502 | 21 | } |
503 | | |
504 | | // Prevent OOM from malformed files. |
505 | 998 | if (sec.sh_size > kMaxSectionSize) { |
506 | 91 | this->SetErrorMessage("DYNAMIC section is too large."); |
507 | 91 | return false; |
508 | 91 | } |
509 | | |
510 | | // Allocate the dynamic section entries. |
511 | 907 | std::size_t n = static_cast<int>(sec.sh_size / sec.sh_entsize); |
512 | | // Prevent OOM from malformed files. |
513 | 907 | if (n > kMaxDynamicEntries) { |
514 | 17 | this->SetErrorMessage("DYNAMIC section has too many entries."); |
515 | 17 | return false; |
516 | 17 | } |
517 | 890 | this->DynamicSectionEntries.resize(n); |
518 | | |
519 | | // Read each entry. |
520 | 1.72M | for (std::size_t j = 0; j < n; ++j) { |
521 | | // Seek to the beginning of the section entry. |
522 | 1.72M | this->Stream->seekg(sec.sh_offset + sec.sh_entsize * j); |
523 | 1.72M | ELF_Dyn& dyn = this->DynamicSectionEntries[j]; |
524 | | |
525 | | // Try reading the entry. |
526 | 1.72M | if (!this->Read(dyn)) { |
527 | 75 | this->SetErrorMessage("Error reading entry from DYNAMIC section."); |
528 | 75 | this->DynamicSectionIndex = -1; |
529 | 75 | return false; |
530 | 75 | } |
531 | 1.72M | } |
532 | 815 | return true; |
533 | 890 | } cmELFInternalImpl<cmELFTypes32>::LoadDynamicSection() Line | Count | Source | 487 | 5.94k | { | 488 | | // If there is no dynamic section we are done. | 489 | 5.94k | if (!this->HasDynamicSection()) { | 490 | 87 | return false; | 491 | 87 | } | 492 | | | 493 | | // If the section was already loaded we are done. | 494 | 5.86k | if (!this->DynamicSectionEntries.empty()) { | 495 | 5.45k | return true; | 496 | 5.45k | } | 497 | | | 498 | | // If there are no entries we are done. | 499 | 409 | ELF_Shdr const& sec = this->SectionHeaders[this->DynamicSectionIndex]; | 500 | 409 | if (sec.sh_entsize == 0) { | 501 | 9 | return false; | 502 | 9 | } | 503 | | | 504 | | // Prevent OOM from malformed files. | 505 | 400 | if (sec.sh_size > kMaxSectionSize) { | 506 | 12 | this->SetErrorMessage("DYNAMIC section is too large."); | 507 | 12 | return false; | 508 | 12 | } | 509 | | | 510 | | // Allocate the dynamic section entries. | 511 | 388 | std::size_t n = static_cast<int>(sec.sh_size / sec.sh_entsize); | 512 | | // Prevent OOM from malformed files. | 513 | 388 | if (n > kMaxDynamicEntries) { | 514 | 10 | this->SetErrorMessage("DYNAMIC section has too many entries."); | 515 | 10 | return false; | 516 | 10 | } | 517 | 378 | this->DynamicSectionEntries.resize(n); | 518 | | | 519 | | // Read each entry. | 520 | 1.50M | for (std::size_t j = 0; j < n; ++j) { | 521 | | // Seek to the beginning of the section entry. | 522 | 1.49M | this->Stream->seekg(sec.sh_offset + sec.sh_entsize * j); | 523 | 1.49M | ELF_Dyn& dyn = this->DynamicSectionEntries[j]; | 524 | | | 525 | | // Try reading the entry. | 526 | 1.49M | if (!this->Read(dyn)) { | 527 | 41 | this->SetErrorMessage("Error reading entry from DYNAMIC section."); | 528 | 41 | this->DynamicSectionIndex = -1; | 529 | 41 | return false; | 530 | 41 | } | 531 | 1.49M | } | 532 | 337 | return true; | 533 | 378 | } |
cmELFInternalImpl<cmELFTypes64>::LoadDynamicSection() Line | Count | Source | 487 | 5.76k | { | 488 | | // If there is no dynamic section we are done. | 489 | 5.76k | if (!this->HasDynamicSection()) { | 490 | 153 | return false; | 491 | 153 | } | 492 | | | 493 | | // If the section was already loaded we are done. | 494 | 5.61k | if (!this->DynamicSectionEntries.empty()) { | 495 | 5.00k | return true; | 496 | 5.00k | } | 497 | | | 498 | | // If there are no entries we are done. | 499 | 610 | ELF_Shdr const& sec = this->SectionHeaders[this->DynamicSectionIndex]; | 500 | 610 | if (sec.sh_entsize == 0) { | 501 | 12 | return false; | 502 | 12 | } | 503 | | | 504 | | // Prevent OOM from malformed files. | 505 | 598 | if (sec.sh_size > kMaxSectionSize) { | 506 | 79 | this->SetErrorMessage("DYNAMIC section is too large."); | 507 | 79 | return false; | 508 | 79 | } | 509 | | | 510 | | // Allocate the dynamic section entries. | 511 | 519 | std::size_t n = static_cast<int>(sec.sh_size / sec.sh_entsize); | 512 | | // Prevent OOM from malformed files. | 513 | 519 | if (n > kMaxDynamicEntries) { | 514 | 7 | this->SetErrorMessage("DYNAMIC section has too many entries."); | 515 | 7 | return false; | 516 | 7 | } | 517 | 512 | this->DynamicSectionEntries.resize(n); | 518 | | | 519 | | // Read each entry. | 520 | 229k | for (std::size_t j = 0; j < n; ++j) { | 521 | | // Seek to the beginning of the section entry. | 522 | 228k | this->Stream->seekg(sec.sh_offset + sec.sh_entsize * j); | 523 | 228k | ELF_Dyn& dyn = this->DynamicSectionEntries[j]; | 524 | | | 525 | | // Try reading the entry. | 526 | 228k | if (!this->Read(dyn)) { | 527 | 34 | this->SetErrorMessage("Error reading entry from DYNAMIC section."); | 528 | 34 | this->DynamicSectionIndex = -1; | 529 | 34 | return false; | 530 | 34 | } | 531 | 228k | } | 532 | 478 | return true; | 533 | 512 | } |
|
534 | | |
535 | | template <class Types> |
536 | | unsigned long cmELFInternalImpl<Types>::GetDynamicEntryPosition(int j) |
537 | 9.85k | { |
538 | 9.85k | if (!this->LoadDynamicSection()) { |
539 | 0 | return 0; |
540 | 0 | } |
541 | 9.85k | if (j < 0 || j >= static_cast<int>(this->DynamicSectionEntries.size())) { |
542 | 0 | return 0; |
543 | 0 | } |
544 | 9.85k | ELF_Shdr const& sec = this->SectionHeaders[this->DynamicSectionIndex]; |
545 | 9.85k | return sec.sh_offset + sec.sh_entsize * static_cast<unsigned long>(j); |
546 | 9.85k | } cmELFInternalImpl<cmELFTypes32>::GetDynamicEntryPosition(int) Line | Count | Source | 537 | 5.19k | { | 538 | 5.19k | if (!this->LoadDynamicSection()) { | 539 | 0 | return 0; | 540 | 0 | } | 541 | 5.19k | if (j < 0 || j >= static_cast<int>(this->DynamicSectionEntries.size())) { | 542 | 0 | return 0; | 543 | 0 | } | 544 | 5.19k | ELF_Shdr const& sec = this->SectionHeaders[this->DynamicSectionIndex]; | 545 | 5.19k | return sec.sh_offset + sec.sh_entsize * static_cast<unsigned long>(j); | 546 | 5.19k | } |
cmELFInternalImpl<cmELFTypes64>::GetDynamicEntryPosition(int) Line | Count | Source | 537 | 4.65k | { | 538 | 4.65k | if (!this->LoadDynamicSection()) { | 539 | 0 | return 0; | 540 | 0 | } | 541 | 4.65k | if (j < 0 || j >= static_cast<int>(this->DynamicSectionEntries.size())) { | 542 | 0 | return 0; | 543 | 0 | } | 544 | 4.65k | ELF_Shdr const& sec = this->SectionHeaders[this->DynamicSectionIndex]; | 545 | 4.65k | return sec.sh_offset + sec.sh_entsize * static_cast<unsigned long>(j); | 546 | 4.65k | } |
|
547 | | |
548 | | template <class Types> |
549 | | cmELF::DynamicEntryList cmELFInternalImpl<Types>::GetDynamicEntries() |
550 | 515 | { |
551 | 515 | cmELF::DynamicEntryList result; |
552 | | |
553 | | // Ensure entries have been read from file |
554 | 515 | if (!this->LoadDynamicSection()) { |
555 | 194 | return result; |
556 | 194 | } |
557 | | |
558 | | // Copy into public array |
559 | 321 | result.reserve(this->DynamicSectionEntries.size()); |
560 | 1.71M | for (ELF_Dyn& dyn : this->DynamicSectionEntries) { |
561 | 1.71M | result.emplace_back(dyn.d_tag, dyn.d_un.d_val); |
562 | 1.71M | } |
563 | | |
564 | 321 | return result; |
565 | 515 | } cmELFInternalImpl<cmELFTypes32>::GetDynamicEntries() Line | Count | Source | 550 | 220 | { | 551 | 220 | cmELF::DynamicEntryList result; | 552 | | | 553 | | // Ensure entries have been read from file | 554 | 220 | if (!this->LoadDynamicSection()) { | 555 | 67 | return result; | 556 | 67 | } | 557 | | | 558 | | // Copy into public array | 559 | 153 | result.reserve(this->DynamicSectionEntries.size()); | 560 | 1.49M | for (ELF_Dyn& dyn : this->DynamicSectionEntries) { | 561 | 1.49M | result.emplace_back(dyn.d_tag, dyn.d_un.d_val); | 562 | 1.49M | } | 563 | | | 564 | 153 | return result; | 565 | 220 | } |
cmELFInternalImpl<cmELFTypes64>::GetDynamicEntries() Line | Count | Source | 550 | 295 | { | 551 | 295 | cmELF::DynamicEntryList result; | 552 | | | 553 | | // Ensure entries have been read from file | 554 | 295 | if (!this->LoadDynamicSection()) { | 555 | 127 | return result; | 556 | 127 | } | 557 | | | 558 | | // Copy into public array | 559 | 168 | result.reserve(this->DynamicSectionEntries.size()); | 560 | 221k | for (ELF_Dyn& dyn : this->DynamicSectionEntries) { | 561 | 221k | result.emplace_back(dyn.d_tag, dyn.d_un.d_val); | 562 | 221k | } | 563 | | | 564 | 168 | return result; | 565 | 295 | } |
|
566 | | |
567 | | template <class Types> |
568 | | std::vector<char> cmELFInternalImpl<Types>::EncodeDynamicEntries( |
569 | | cmELF::DynamicEntryList const& entries) |
570 | 183 | { |
571 | 183 | std::vector<char> result; |
572 | 183 | result.reserve(sizeof(ELF_Dyn) * entries.size()); |
573 | | |
574 | 1.71M | for (auto const& entry : entries) { |
575 | | // Store the entry in an ELF_Dyn, byteswap it, then serialize to chars |
576 | 1.71M | ELF_Dyn dyn; |
577 | 1.71M | dyn.d_tag = static_cast<tagtype>(entry.first); |
578 | 1.71M | dyn.d_un.d_val = static_cast<tagtype>(entry.second); |
579 | | |
580 | 1.71M | if (this->NeedSwap) { |
581 | 81.8k | this->ByteSwap(dyn); |
582 | 81.8k | } |
583 | | |
584 | 1.71M | char* pdyn = reinterpret_cast<char*>(&dyn); |
585 | 1.71M | cm::append(result, pdyn, pdyn + sizeof(ELF_Dyn)); |
586 | 1.71M | } |
587 | | |
588 | 183 | return result; |
589 | 183 | } cmELFInternalImpl<cmELFTypes32>::EncodeDynamicEntries(std::__1::vector<std::__1::pair<long, unsigned long>, std::__1::allocator<std::__1::pair<long, unsigned long> > > const&) Line | Count | Source | 570 | 94 | { | 571 | 94 | std::vector<char> result; | 572 | 94 | result.reserve(sizeof(ELF_Dyn) * entries.size()); | 573 | | | 574 | 1.49M | for (auto const& entry : entries) { | 575 | | // Store the entry in an ELF_Dyn, byteswap it, then serialize to chars | 576 | 1.49M | ELF_Dyn dyn; | 577 | 1.49M | dyn.d_tag = static_cast<tagtype>(entry.first); | 578 | 1.49M | dyn.d_un.d_val = static_cast<tagtype>(entry.second); | 579 | | | 580 | 1.49M | if (this->NeedSwap) { | 581 | 80.8k | this->ByteSwap(dyn); | 582 | 80.8k | } | 583 | | | 584 | 1.49M | char* pdyn = reinterpret_cast<char*>(&dyn); | 585 | 1.49M | cm::append(result, pdyn, pdyn + sizeof(ELF_Dyn)); | 586 | 1.49M | } | 587 | | | 588 | 94 | return result; | 589 | 94 | } |
cmELFInternalImpl<cmELFTypes64>::EncodeDynamicEntries(std::__1::vector<std::__1::pair<long, unsigned long>, std::__1::allocator<std::__1::pair<long, unsigned long> > > const&) Line | Count | Source | 570 | 89 | { | 571 | 89 | std::vector<char> result; | 572 | 89 | result.reserve(sizeof(ELF_Dyn) * entries.size()); | 573 | | | 574 | 221k | for (auto const& entry : entries) { | 575 | | // Store the entry in an ELF_Dyn, byteswap it, then serialize to chars | 576 | 221k | ELF_Dyn dyn; | 577 | 221k | dyn.d_tag = static_cast<tagtype>(entry.first); | 578 | 221k | dyn.d_un.d_val = static_cast<tagtype>(entry.second); | 579 | | | 580 | 221k | if (this->NeedSwap) { | 581 | 1.06k | this->ByteSwap(dyn); | 582 | 1.06k | } | 583 | | | 584 | 221k | char* pdyn = reinterpret_cast<char*>(&dyn); | 585 | 221k | cm::append(result, pdyn, pdyn + sizeof(ELF_Dyn)); | 586 | 221k | } | 587 | | | 588 | 89 | return result; | 589 | 89 | } |
|
590 | | |
591 | | template <class Types> |
592 | | cmELF::StringEntry const* cmELFInternalImpl<Types>::GetDynamicSectionString( |
593 | | unsigned int tag) |
594 | 1.64k | { |
595 | | // Short-circuit if already checked. |
596 | 1.64k | auto dssi = this->DynamicSectionStrings.find(tag); |
597 | 1.64k | if (dssi != this->DynamicSectionStrings.end()) { |
598 | 300 | if (dssi->second.Position > 0) { |
599 | 80 | return &dssi->second; |
600 | 80 | } |
601 | 220 | return nullptr; |
602 | 300 | } |
603 | | |
604 | | // Create an entry for this tag. Assume it is missing until found. |
605 | 1.34k | StringEntry& se = this->DynamicSectionStrings[tag]; |
606 | 1.34k | se.Position = 0; |
607 | 1.34k | se.Size = 0; |
608 | 1.34k | se.IndexInSection = -1; |
609 | | |
610 | | // Try reading the dynamic section. |
611 | 1.34k | if (!this->LoadDynamicSection()) { |
612 | 250 | return nullptr; |
613 | 250 | } |
614 | | |
615 | | // Get the string table referenced by the DYNAMIC section. |
616 | 1.09k | ELF_Shdr const& sec = this->SectionHeaders[this->DynamicSectionIndex]; |
617 | 1.09k | if (sec.sh_link >= this->SectionHeaders.size()) { |
618 | 101 | this->SetErrorMessage("Section DYNAMIC has invalid string table index."); |
619 | 101 | return nullptr; |
620 | 101 | } |
621 | 996 | ELF_Shdr const& strtab = this->SectionHeaders[sec.sh_link]; |
622 | | |
623 | | // Look for the requested entry. |
624 | 996 | for (auto di = this->DynamicSectionEntries.begin(); |
625 | 1.14M | di != this->DynamicSectionEntries.end(); ++di) { |
626 | 1.14M | ELF_Dyn& dyn = *di; |
627 | 1.14M | if (static_cast<tagtype>(dyn.d_tag) == static_cast<tagtype>(tag)) { |
628 | | // We found the tag requested. |
629 | | // Make sure the position given is within the string section. |
630 | 356 | if (dyn.d_un.d_val >= strtab.sh_size) { |
631 | 140 | this->SetErrorMessage("Section DYNAMIC references string beyond " |
632 | 140 | "the end of its string section."); |
633 | 140 | return nullptr; |
634 | 140 | } |
635 | | |
636 | | // Seek to the position reported by the entry. |
637 | 216 | unsigned long first = static_cast<unsigned long>(dyn.d_un.d_val); |
638 | 216 | unsigned long last = first; |
639 | 216 | unsigned long end = static_cast<unsigned long>(strtab.sh_size); |
640 | 216 | this->Stream->seekg(strtab.sh_offset + first); |
641 | | |
642 | | // Read the string. It may be followed by more than one NULL |
643 | | // terminator. Count the total size of the region allocated to |
644 | | // the string. This assumes that the next string in the table |
645 | | // is non-empty, but the "chrpath" tool makes the same |
646 | | // assumption. |
647 | 216 | bool terminated = false; |
648 | 216 | char c; |
649 | 661k | while (last != end && this->Stream->get(c) && !(terminated && c)) { |
650 | 661k | ++last; |
651 | 661k | if (c) { |
652 | 660k | se.Value += c; |
653 | 660k | } else { |
654 | 1.37k | terminated = true; |
655 | 1.37k | } |
656 | 661k | } |
657 | | |
658 | | // Make sure the whole value was read. |
659 | 216 | if (!(*this->Stream)) { |
660 | 44 | if (tag == cmELF::TagRPath) { |
661 | 27 | this->SetErrorMessage( |
662 | 27 | "Dynamic section specifies unreadable DT_RPATH"); |
663 | 27 | } else if (tag == cmELF::TagRunPath) { |
664 | 4 | this->SetErrorMessage( |
665 | 4 | "Dynamic section specifies unreadable DT_RUNPATH"); |
666 | 13 | } else if (tag == cmELF::TagMipsRldMapRel) { |
667 | 0 | this->SetErrorMessage( |
668 | 0 | "Dynamic section specifies unreadable DT_MIPS_RLD_MAP_REL"); |
669 | 13 | } else { |
670 | 13 | this->SetErrorMessage("Dynamic section specifies unreadable value" |
671 | 13 | " for unexpected attribute"); |
672 | 13 | } |
673 | 44 | se.Value = ""; |
674 | 44 | return nullptr; |
675 | 44 | } |
676 | | |
677 | | // The value has been read successfully. Report it. |
678 | 172 | se.Position = static_cast<unsigned long>(strtab.sh_offset + first); |
679 | 172 | se.Size = last - first; |
680 | 172 | se.IndexInSection = |
681 | 172 | static_cast<int>(di - this->DynamicSectionEntries.begin()); |
682 | 172 | return &se; |
683 | 216 | } |
684 | 1.14M | } |
685 | 640 | return nullptr; |
686 | 996 | } cmELFInternalImpl<cmELFTypes32>::GetDynamicSectionString(unsigned int) Line | Count | Source | 594 | 636 | { | 595 | | // Short-circuit if already checked. | 596 | 636 | auto dssi = this->DynamicSectionStrings.find(tag); | 597 | 636 | if (dssi != this->DynamicSectionStrings.end()) { | 598 | 104 | if (dssi->second.Position > 0) { | 599 | 37 | return &dssi->second; | 600 | 37 | } | 601 | 67 | return nullptr; | 602 | 104 | } | 603 | | | 604 | | // Create an entry for this tag. Assume it is missing until found. | 605 | 532 | StringEntry& se = this->DynamicSectionStrings[tag]; | 606 | 532 | se.Position = 0; | 607 | 532 | se.Size = 0; | 608 | 532 | se.IndexInSection = -1; | 609 | | | 610 | | // Try reading the dynamic section. | 611 | 532 | if (!this->LoadDynamicSection()) { | 612 | 92 | return nullptr; | 613 | 92 | } | 614 | | | 615 | | // Get the string table referenced by the DYNAMIC section. | 616 | 440 | ELF_Shdr const& sec = this->SectionHeaders[this->DynamicSectionIndex]; | 617 | 440 | if (sec.sh_link >= this->SectionHeaders.size()) { | 618 | 31 | this->SetErrorMessage("Section DYNAMIC has invalid string table index."); | 619 | 31 | return nullptr; | 620 | 31 | } | 621 | 409 | ELF_Shdr const& strtab = this->SectionHeaders[sec.sh_link]; | 622 | | | 623 | | // Look for the requested entry. | 624 | 409 | for (auto di = this->DynamicSectionEntries.begin(); | 625 | 600k | di != this->DynamicSectionEntries.end(); ++di) { | 626 | 599k | ELF_Dyn& dyn = *di; | 627 | 599k | if (static_cast<tagtype>(dyn.d_tag) == static_cast<tagtype>(tag)) { | 628 | | // We found the tag requested. | 629 | | // Make sure the position given is within the string section. | 630 | 152 | if (dyn.d_un.d_val >= strtab.sh_size) { | 631 | 49 | this->SetErrorMessage("Section DYNAMIC references string beyond " | 632 | 49 | "the end of its string section."); | 633 | 49 | return nullptr; | 634 | 49 | } | 635 | | | 636 | | // Seek to the position reported by the entry. | 637 | 103 | unsigned long first = static_cast<unsigned long>(dyn.d_un.d_val); | 638 | 103 | unsigned long last = first; | 639 | 103 | unsigned long end = static_cast<unsigned long>(strtab.sh_size); | 640 | 103 | this->Stream->seekg(strtab.sh_offset + first); | 641 | | | 642 | | // Read the string. It may be followed by more than one NULL | 643 | | // terminator. Count the total size of the region allocated to | 644 | | // the string. This assumes that the next string in the table | 645 | | // is non-empty, but the "chrpath" tool makes the same | 646 | | // assumption. | 647 | 103 | bool terminated = false; | 648 | 103 | char c; | 649 | 602k | while (last != end && this->Stream->get(c) && !(terminated && c)) { | 650 | 602k | ++last; | 651 | 602k | if (c) { | 652 | 601k | se.Value += c; | 653 | 601k | } else { | 654 | 658 | terminated = true; | 655 | 658 | } | 656 | 602k | } | 657 | | | 658 | | // Make sure the whole value was read. | 659 | 103 | if (!(*this->Stream)) { | 660 | 11 | if (tag == cmELF::TagRPath) { | 661 | 8 | this->SetErrorMessage( | 662 | 8 | "Dynamic section specifies unreadable DT_RPATH"); | 663 | 8 | } else if (tag == cmELF::TagRunPath) { | 664 | 1 | this->SetErrorMessage( | 665 | 1 | "Dynamic section specifies unreadable DT_RUNPATH"); | 666 | 2 | } else if (tag == cmELF::TagMipsRldMapRel) { | 667 | 0 | this->SetErrorMessage( | 668 | 0 | "Dynamic section specifies unreadable DT_MIPS_RLD_MAP_REL"); | 669 | 2 | } else { | 670 | 2 | this->SetErrorMessage("Dynamic section specifies unreadable value" | 671 | 2 | " for unexpected attribute"); | 672 | 2 | } | 673 | 11 | se.Value = ""; | 674 | 11 | return nullptr; | 675 | 11 | } | 676 | | | 677 | | // The value has been read successfully. Report it. | 678 | 92 | se.Position = static_cast<unsigned long>(strtab.sh_offset + first); | 679 | 92 | se.Size = last - first; | 680 | 92 | se.IndexInSection = | 681 | 92 | static_cast<int>(di - this->DynamicSectionEntries.begin()); | 682 | 92 | return &se; | 683 | 103 | } | 684 | 599k | } | 685 | 257 | return nullptr; | 686 | 409 | } |
cmELFInternalImpl<cmELFTypes64>::GetDynamicSectionString(unsigned int) Line | Count | Source | 594 | 1.01k | { | 595 | | // Short-circuit if already checked. | 596 | 1.01k | auto dssi = this->DynamicSectionStrings.find(tag); | 597 | 1.01k | if (dssi != this->DynamicSectionStrings.end()) { | 598 | 196 | if (dssi->second.Position > 0) { | 599 | 43 | return &dssi->second; | 600 | 43 | } | 601 | 153 | return nullptr; | 602 | 196 | } | 603 | | | 604 | | // Create an entry for this tag. Assume it is missing until found. | 605 | 815 | StringEntry& se = this->DynamicSectionStrings[tag]; | 606 | 815 | se.Position = 0; | 607 | 815 | se.Size = 0; | 608 | 815 | se.IndexInSection = -1; | 609 | | | 610 | | // Try reading the dynamic section. | 611 | 815 | if (!this->LoadDynamicSection()) { | 612 | 158 | return nullptr; | 613 | 158 | } | 614 | | | 615 | | // Get the string table referenced by the DYNAMIC section. | 616 | 657 | ELF_Shdr const& sec = this->SectionHeaders[this->DynamicSectionIndex]; | 617 | 657 | if (sec.sh_link >= this->SectionHeaders.size()) { | 618 | 70 | this->SetErrorMessage("Section DYNAMIC has invalid string table index."); | 619 | 70 | return nullptr; | 620 | 70 | } | 621 | 587 | ELF_Shdr const& strtab = this->SectionHeaders[sec.sh_link]; | 622 | | | 623 | | // Look for the requested entry. | 624 | 587 | for (auto di = this->DynamicSectionEntries.begin(); | 625 | 542k | di != this->DynamicSectionEntries.end(); ++di) { | 626 | 541k | ELF_Dyn& dyn = *di; | 627 | 541k | if (static_cast<tagtype>(dyn.d_tag) == static_cast<tagtype>(tag)) { | 628 | | // We found the tag requested. | 629 | | // Make sure the position given is within the string section. | 630 | 204 | if (dyn.d_un.d_val >= strtab.sh_size) { | 631 | 91 | this->SetErrorMessage("Section DYNAMIC references string beyond " | 632 | 91 | "the end of its string section."); | 633 | 91 | return nullptr; | 634 | 91 | } | 635 | | | 636 | | // Seek to the position reported by the entry. | 637 | 113 | unsigned long first = static_cast<unsigned long>(dyn.d_un.d_val); | 638 | 113 | unsigned long last = first; | 639 | 113 | unsigned long end = static_cast<unsigned long>(strtab.sh_size); | 640 | 113 | this->Stream->seekg(strtab.sh_offset + first); | 641 | | | 642 | | // Read the string. It may be followed by more than one NULL | 643 | | // terminator. Count the total size of the region allocated to | 644 | | // the string. This assumes that the next string in the table | 645 | | // is non-empty, but the "chrpath" tool makes the same | 646 | | // assumption. | 647 | 113 | bool terminated = false; | 648 | 113 | char c; | 649 | 59.3k | while (last != end && this->Stream->get(c) && !(terminated && c)) { | 650 | 59.2k | ++last; | 651 | 59.2k | if (c) { | 652 | 58.5k | se.Value += c; | 653 | 58.5k | } else { | 654 | 719 | terminated = true; | 655 | 719 | } | 656 | 59.2k | } | 657 | | | 658 | | // Make sure the whole value was read. | 659 | 113 | if (!(*this->Stream)) { | 660 | 33 | if (tag == cmELF::TagRPath) { | 661 | 19 | this->SetErrorMessage( | 662 | 19 | "Dynamic section specifies unreadable DT_RPATH"); | 663 | 19 | } else if (tag == cmELF::TagRunPath) { | 664 | 3 | this->SetErrorMessage( | 665 | 3 | "Dynamic section specifies unreadable DT_RUNPATH"); | 666 | 11 | } else if (tag == cmELF::TagMipsRldMapRel) { | 667 | 0 | this->SetErrorMessage( | 668 | 0 | "Dynamic section specifies unreadable DT_MIPS_RLD_MAP_REL"); | 669 | 11 | } else { | 670 | 11 | this->SetErrorMessage("Dynamic section specifies unreadable value" | 671 | 11 | " for unexpected attribute"); | 672 | 11 | } | 673 | 33 | se.Value = ""; | 674 | 33 | return nullptr; | 675 | 33 | } | 676 | | | 677 | | // The value has been read successfully. Report it. | 678 | 80 | se.Position = static_cast<unsigned long>(strtab.sh_offset + first); | 679 | 80 | se.Size = last - first; | 680 | 80 | se.IndexInSection = | 681 | 80 | static_cast<int>(di - this->DynamicSectionEntries.begin()); | 682 | 80 | return &se; | 683 | 113 | } | 684 | 541k | } | 685 | 383 | return nullptr; | 686 | 587 | } |
|
687 | | |
688 | | //============================================================================ |
689 | | // External class implementation. |
690 | | |
691 | | long const cmELF::TagRPath = DT_RPATH; |
692 | | long const cmELF::TagRunPath = DT_RUNPATH; |
693 | | long const cmELF::TagMipsRldMapRel = DT_MIPS_RLD_MAP_REL; |
694 | | |
695 | | cmELF::cmELF(char const* fname) |
696 | 1.21k | { |
697 | | // Try to open the file. |
698 | 1.21k | auto fin = cm::make_unique<cmsys::ifstream>(fname, std::ios::binary); |
699 | | |
700 | | // Quit now if the file could not be opened. |
701 | 1.21k | if (!fin || !*fin) { |
702 | 0 | this->ErrorMessage = "Error opening input file."; |
703 | 0 | return; |
704 | 0 | } |
705 | | |
706 | | // Read the ELF identification block. |
707 | 1.21k | char ident[EI_NIDENT]; |
708 | 1.21k | if (!fin->read(ident, EI_NIDENT)) { |
709 | 0 | this->ErrorMessage = "Error reading ELF identification."; |
710 | 0 | return; |
711 | 0 | } |
712 | 1.21k | if (!fin->seekg(0)) { |
713 | 0 | this->ErrorMessage = "Error seeking to beginning of file."; |
714 | 0 | return; |
715 | 0 | } |
716 | | |
717 | | // Verify the ELF identification. |
718 | 1.21k | if (!(ident[EI_MAG0] == ELFMAG0 && ident[EI_MAG1] == ELFMAG1 && |
719 | 1.18k | ident[EI_MAG2] == ELFMAG2 && ident[EI_MAG3] == ELFMAG3)) { |
720 | 59 | this->ErrorMessage = "File does not have a valid ELF identification."; |
721 | 59 | return; |
722 | 59 | } |
723 | | |
724 | | // Check the byte order in which the rest of the file is encoded. |
725 | 1.15k | cmELFInternal::ByteOrderType order; |
726 | 1.15k | if (ident[EI_DATA] == ELFDATA2LSB) { |
727 | | // File is LSB. |
728 | 930 | order = cmELFInternal::ByteOrderLSB; |
729 | 930 | } else if (ident[EI_DATA] == ELFDATA2MSB) { |
730 | | // File is MSB. |
731 | 217 | order = cmELFInternal::ByteOrderMSB; |
732 | 217 | } else { |
733 | 11 | this->ErrorMessage = "ELF file is not LSB or MSB encoded."; |
734 | 11 | return; |
735 | 11 | } |
736 | | |
737 | | // Check the class of the file and construct the corresponding |
738 | | // parser implementation. |
739 | 1.14k | if (ident[EI_CLASS] == ELFCLASS32) { |
740 | | // 32-bit ELF |
741 | 432 | this->Internal = cm::make_unique<cmELFInternalImpl<cmELFTypes32>>( |
742 | 432 | this, std::move(fin), order); |
743 | 715 | } else if (ident[EI_CLASS] == ELFCLASS64) { |
744 | | // 64-bit ELF |
745 | 705 | this->Internal = cm::make_unique<cmELFInternalImpl<cmELFTypes64>>( |
746 | 705 | this, std::move(fin), order); |
747 | 705 | } else { |
748 | 10 | this->ErrorMessage = "ELF file class is not 32-bit or 64-bit."; |
749 | 10 | return; |
750 | 10 | } |
751 | 1.14k | } |
752 | | |
753 | 1.21k | cmELF::~cmELF() = default; |
754 | | |
755 | | bool cmELF::Valid() const |
756 | 21.2k | { |
757 | 21.2k | return this->Internal && this->Internal->GetFileType() != FileTypeInvalid; |
758 | 21.2k | } |
759 | | |
760 | | cmELF::FileType cmELF::GetFileType() const |
761 | 913 | { |
762 | 913 | if (this->Valid()) { |
763 | 913 | return this->Internal->GetFileType(); |
764 | 913 | } |
765 | 0 | return FileTypeInvalid; |
766 | 913 | } |
767 | | |
768 | | std::uint16_t cmELF::GetMachine() const |
769 | 913 | { |
770 | 913 | if (this->Valid()) { |
771 | 913 | return this->Internal->GetMachine(); |
772 | 913 | } |
773 | 0 | return 0; |
774 | 913 | } |
775 | | |
776 | | std::size_t cmELF::GetNumberOfSections() const |
777 | 913 | { |
778 | 913 | if (this->Valid()) { |
779 | 913 | return this->Internal->GetNumberOfSections(); |
780 | 913 | } |
781 | 0 | return 0; |
782 | 913 | } |
783 | | |
784 | | unsigned long cmELF::GetDynamicEntryPosition(int index) const |
785 | 9.85k | { |
786 | 9.85k | if (this->Valid()) { |
787 | 9.85k | return this->Internal->GetDynamicEntryPosition(index); |
788 | 9.85k | } |
789 | 0 | return 0; |
790 | 9.85k | } |
791 | | |
792 | | cmELF::DynamicEntryList cmELF::GetDynamicEntries() const |
793 | 913 | { |
794 | 913 | if (this->Valid()) { |
795 | 515 | return this->Internal->GetDynamicEntries(); |
796 | 515 | } |
797 | | |
798 | 398 | return cmELF::DynamicEntryList(); |
799 | 913 | } |
800 | | |
801 | | std::vector<char> cmELF::EncodeDynamicEntries( |
802 | | cmELF::DynamicEntryList const& dentries) const |
803 | 183 | { |
804 | 183 | if (this->Valid()) { |
805 | 183 | return this->Internal->EncodeDynamicEntries(dentries); |
806 | 183 | } |
807 | | |
808 | 0 | return std::vector<char>(); |
809 | 183 | } |
810 | | |
811 | | bool cmELF::HasDynamicSection() const |
812 | 913 | { |
813 | 913 | return this->Valid() && this->Internal->HasDynamicSection(); |
814 | 913 | } |
815 | | |
816 | | bool cmELF::GetSOName(std::string& soname) |
817 | 913 | { |
818 | 913 | if (StringEntry const* se = this->GetSOName()) { |
819 | 100 | soname = se->Value; |
820 | 100 | return true; |
821 | 100 | } |
822 | 813 | return false; |
823 | 913 | } |
824 | | |
825 | | cmELF::StringEntry const* cmELF::GetSOName() |
826 | 1.82k | { |
827 | 1.82k | if (this->Valid() && |
828 | 1.73k | this->Internal->GetFileType() == cmELF::FileTypeSharedLibrary) { |
829 | 696 | return this->Internal->GetSOName(); |
830 | 696 | } |
831 | 1.13k | return nullptr; |
832 | 1.82k | } |
833 | | |
834 | | cmELF::StringEntry const* cmELF::GetRPath() |
835 | 913 | { |
836 | 913 | if (this->Valid() && |
837 | 817 | (this->Internal->GetFileType() == cmELF::FileTypeExecutable || |
838 | 615 | this->Internal->GetFileType() == cmELF::FileTypeSharedLibrary)) { |
839 | 615 | return this->Internal->GetRPath(); |
840 | 615 | } |
841 | 298 | return nullptr; |
842 | 913 | } |
843 | | |
844 | | cmELF::StringEntry const* cmELF::GetRunPath() |
845 | 913 | { |
846 | 913 | if (this->Valid() && |
847 | 538 | (this->Internal->GetFileType() == cmELF::FileTypeExecutable || |
848 | 398 | this->Internal->GetFileType() == cmELF::FileTypeSharedLibrary)) { |
849 | 336 | return this->Internal->GetRunPath(); |
850 | 336 | } |
851 | 577 | return nullptr; |
852 | 913 | } |
853 | | |
854 | | bool cmELF::IsMIPS() const |
855 | 913 | { |
856 | 913 | if (this->Valid()) { |
857 | 913 | return this->Internal->IsMips(); |
858 | 913 | } |
859 | 0 | return false; |
860 | 913 | } |
861 | | |
862 | | void cmELF::PrintInfo(std::ostream& os) const |
863 | 913 | { |
864 | 913 | if (this->Valid()) { |
865 | 445 | this->Internal->PrintInfo(os); |
866 | 468 | } else { |
867 | 468 | os << "Not a valid ELF file.\n"; |
868 | 468 | } |
869 | 913 | } |