Coverage Report

Created: 2026-10-28 06:38

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/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 <utility>
11
#include <vector>
12
13
#include <cm/memory>
14
#include <cmext/algorithm>
15
16
#include <cm3p/kwiml/abi.h>
17
18
#include "cmsys/FStream.hxx"
19
20
#include "cmStringAlgorithms.h"
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.36k
{
37
3.36k
  char one_byte;
38
3.36k
  one_byte = data[0];
39
3.36k
  data[0] = data[1];
40
3.36k
  data[1] = one_byte;
41
3.36k
}
42
static void cmELFByteSwap(char* data, cmELFByteSwapSize<4> /*unused*/)
43
40.5M
{
44
40.5M
  char one_byte;
45
40.5M
  one_byte = data[0];
46
40.5M
  data[0] = data[3];
47
40.5M
  data[3] = one_byte;
48
40.5M
  one_byte = data[1];
49
40.5M
  data[1] = data[2];
50
40.5M
  data[2] = one_byte;
51
40.5M
}
52
static void cmELFByteSwap(char* data, cmELFByteSwapSize<8> /*unused*/)
53
41.1M
{
54
41.1M
  char one_byte;
55
41.1M
  one_byte = data[0];
56
41.1M
  data[0] = data[7];
57
41.1M
  data[7] = one_byte;
58
41.1M
  one_byte = data[1];
59
41.1M
  data[1] = data[6];
60
41.1M
  data[6] = one_byte;
61
41.1M
  one_byte = data[2];
62
41.1M
  data[2] = data[5];
63
41.1M
  data[5] = one_byte;
64
41.1M
  one_byte = data[3];
65
41.1M
  data[3] = data[4];
66
41.1M
  data[4] = one_byte;
67
41.1M
}
68
69
// Low-level byte swapping interface.
70
template <typename T>
71
void cmELFByteSwap(T& x)
72
81.7M
{
73
81.7M
  cmELFByteSwap(reinterpret_cast<char*>(&x), cmELFByteSwapSize<sizeof(T)>());
74
81.7M
}
void cmELFByteSwap<unsigned short>(unsigned short&)
Line
Count
Source
72
3.36k
{
73
3.36k
  cmELFByteSwap(reinterpret_cast<char*>(&x), cmELFByteSwapSize<sizeof(T)>());
74
3.36k
}
void cmELFByteSwap<unsigned int>(unsigned int&)
Line
Count
Source
72
40.4M
{
73
40.4M
  cmELFByteSwap(reinterpret_cast<char*>(&x), cmELFByteSwapSize<sizeof(T)>());
74
40.4M
}
void cmELFByteSwap<int>(int&)
Line
Count
Source
72
136k
{
73
136k
  cmELFByteSwap(reinterpret_cast<char*>(&x), cmELFByteSwapSize<sizeof(T)>());
74
136k
}
void cmELFByteSwap<unsigned long>(unsigned long&)
Line
Count
Source
72
41.1M
{
73
41.1M
  cmELFByteSwap(reinterpret_cast<char*>(&x), cmELFByteSwapSize<sizeof(T)>());
74
41.1M
}
void cmELFByteSwap<long>(long&)
Line
Count
Source
72
1.94k
{
73
1.94k
  cmELFByteSwap(reinterpret_cast<char*>(&x), cmELFByteSwapSize<sizeof(T)>());
74
1.94k
}
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.12k
    : External(external)
90
1.12k
    , Stream(std::move(fin))
91
1.12k
    , ByteOrder(order)
92
1.12k
  {
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.12k
#if KWIML_ABI_ENDIAN_ID == KWIML_ABI_ENDIAN_ID_LITTLE
97
1.12k
    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.12k
    this->DynamicSectionIndex = -1;
106
1.12k
  }
107
108
  // Destruct and delete the file stream object.
109
1.12k
  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.2k
  bool HasDynamicSection() const { return this->DynamicSectionIndex >= 0; }
123
124
  // Lookup the SONAME in the DYNAMIC section.
125
  StringEntry const* GetSOName()
126
641
  {
127
641
    return this->GetDynamicSectionString(DT_SONAME);
128
641
  }
129
130
  // Lookup the RPATH in the DYNAMIC section.
131
  StringEntry const* GetRPath()
132
534
  {
133
534
    return this->GetDynamicSectionString(DT_RPATH);
134
534
  }
135
136
  // Lookup the RUNPATH in the DYNAMIC section.
137
  StringEntry const* GetRunPath()
138
316
  {
139
316
    return this->GetDynamicSectionString(DT_RUNPATH);
140
316
  }
141
142
  // Return the recorded ELF type.
143
25.7k
  cmELF::FileType GetFileType() const { return this->ELFType; }
144
145
  // Return the recorded machine.
146
911
  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
694
  {
175
694
    this->External->ErrorMessage = msg;
176
694
    this->ELFType = cmELF::FileTypeInvalid;
177
694
  }
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
190
  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
240
  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.94k
  {
224
1.94k
    std::size_t count = this->ELFHeader.e_shnum;
225
1.94k
    if (!this->SectionHeaders.empty()) {
226
1.94k
      count += static_cast<std::size_t>(this->SectionHeaders[0].sh_size);
227
1.94k
    }
228
    // Prevent OOM from malformed files.
229
1.94k
    if (count > kMaxSections) {
230
746
      return kMaxSections;
231
746
    }
232
1.20k
    return count;
233
1.94k
  }
cmELFInternalImpl<cmELFTypes32>::GetNumberOfSections() const
Line
Count
Source
223
730
  {
224
730
    std::size_t count = this->ELFHeader.e_shnum;
225
730
    if (!this->SectionHeaders.empty()) {
226
730
      count += static_cast<std::size_t>(this->SectionHeaders[0].sh_size);
227
730
    }
228
    // Prevent OOM from malformed files.
229
730
    if (count > kMaxSections) {
230
297
      return kMaxSections;
231
297
    }
232
433
    return count;
233
730
  }
cmELFInternalImpl<cmELFTypes64>::GetNumberOfSections() const
Line
Count
Source
223
1.21k
  {
224
1.21k
    std::size_t count = this->ELFHeader.e_shnum;
225
1.21k
    if (!this->SectionHeaders.empty()) {
226
1.21k
      count += static_cast<std::size_t>(this->SectionHeaders[0].sh_size);
227
1.21k
    }
228
    // Prevent OOM from malformed files.
229
1.21k
    if (count > kMaxSections) {
230
449
      return kMaxSections;
231
449
    }
232
770
    return count;
233
1.21k
  }
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
911
  bool IsMips() const override { return this->ELFHeader.e_machine == EM_MIPS; }
cmELFInternalImpl<cmELFTypes32>::IsMips() const
Line
Count
Source
245
350
  bool IsMips() const override { return this->ELFHeader.e_machine == EM_MIPS; }
cmELFInternalImpl<cmELFTypes64>::IsMips() const
Line
Count
Source
245
561
  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
430
  {
250
430
    os << "ELF " << Types::GetName();
251
430
    if (this->ByteOrder == ByteOrderMSB) {
252
51
      os << " MSB";
253
379
    } else if (this->ByteOrder == ByteOrderLSB) {
254
379
      os << " LSB";
255
379
    }
256
430
    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
131
      case cmELF::FileTypeExecutable:
264
131
        os << " executable";
265
131
        break;
266
157
      case cmELF::FileTypeSharedLibrary:
267
157
        os << " shared library";
268
157
        break;
269
21
      case cmELF::FileTypeCore:
270
21
        os << " core file";
271
21
        break;
272
21
      case cmELF::FileTypeSpecificOS:
273
21
        os << " os-specific type";
274
21
        break;
275
74
      case cmELF::FileTypeSpecificProc:
276
74
        os << " processor-specific type";
277
74
        break;
278
430
    }
279
430
    os << "\n";
280
430
  }
cmELFInternalImpl<cmELFTypes32>::PrintInfo(std::__1::basic_ostream<char, std::__1::char_traits<char> >&) const
Line
Count
Source
249
190
  {
250
190
    os << "ELF " << Types::GetName();
251
190
    if (this->ByteOrder == ByteOrderMSB) {
252
19
      os << " MSB";
253
171
    } else if (this->ByteOrder == ByteOrderLSB) {
254
171
      os << " LSB";
255
171
    }
256
190
    switch (this->ELFType) {
257
0
      case cmELF::FileTypeInvalid:
258
0
        os << " invalid file";
259
0
        break;
260
12
      case cmELF::FileTypeRelocatableObject:
261
12
        os << " relocatable object";
262
12
        break;
263
57
      case cmELF::FileTypeExecutable:
264
57
        os << " executable";
265
57
        break;
266
77
      case cmELF::FileTypeSharedLibrary:
267
77
        os << " shared library";
268
77
        break;
269
12
      case cmELF::FileTypeCore:
270
12
        os << " core file";
271
12
        break;
272
8
      case cmELF::FileTypeSpecificOS:
273
8
        os << " os-specific type";
274
8
        break;
275
24
      case cmELF::FileTypeSpecificProc:
276
24
        os << " processor-specific type";
277
24
        break;
278
190
    }
279
190
    os << "\n";
280
190
  }
cmELFInternalImpl<cmELFTypes64>::PrintInfo(std::__1::basic_ostream<char, std::__1::char_traits<char> >&) const
Line
Count
Source
249
240
  {
250
240
    os << "ELF " << Types::GetName();
251
240
    if (this->ByteOrder == ByteOrderMSB) {
252
32
      os << " MSB";
253
208
    } else if (this->ByteOrder == ByteOrderLSB) {
254
208
      os << " LSB";
255
208
    }
256
240
    switch (this->ELFType) {
257
0
      case cmELF::FileTypeInvalid:
258
0
        os << " invalid file";
259
0
        break;
260
14
      case cmELF::FileTypeRelocatableObject:
261
14
        os << " relocatable object";
262
14
        break;
263
74
      case cmELF::FileTypeExecutable:
264
74
        os << " executable";
265
74
        break;
266
80
      case cmELF::FileTypeSharedLibrary:
267
80
        os << " shared library";
268
80
        break;
269
9
      case cmELF::FileTypeCore:
270
9
        os << " core file";
271
9
        break;
272
13
      case cmELF::FileTypeSpecificOS:
273
13
        os << " os-specific type";
274
13
        break;
275
50
      case cmELF::FileTypeSpecificProc:
276
50
        os << " processor-specific type";
277
50
        break;
278
240
    }
279
240
    os << "\n";
280
240
  }
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
332
  {
288
332
    cmELFByteSwap(elf_header.e_type);
289
332
    cmELFByteSwap(elf_header.e_machine);
290
332
    cmELFByteSwap(elf_header.e_version);
291
332
    cmELFByteSwap(elf_header.e_entry);
292
332
    cmELFByteSwap(elf_header.e_phoff);
293
332
    cmELFByteSwap(elf_header.e_shoff);
294
332
    cmELFByteSwap(elf_header.e_flags);
295
332
    cmELFByteSwap(elf_header.e_ehsize);
296
332
    cmELFByteSwap(elf_header.e_phentsize);
297
332
    cmELFByteSwap(elf_header.e_phnum);
298
332
    cmELFByteSwap(elf_header.e_shentsize);
299
332
    cmELFByteSwap(elf_header.e_shnum);
300
332
    cmELFByteSwap(elf_header.e_shstrndx);
301
332
  }
cmELFInternalImpl<cmELFTypes32>::ByteSwap(Elf32_Ehdr&)
Line
Count
Source
287
77
  {
288
77
    cmELFByteSwap(elf_header.e_type);
289
77
    cmELFByteSwap(elf_header.e_machine);
290
77
    cmELFByteSwap(elf_header.e_version);
291
77
    cmELFByteSwap(elf_header.e_entry);
292
77
    cmELFByteSwap(elf_header.e_phoff);
293
77
    cmELFByteSwap(elf_header.e_shoff);
294
77
    cmELFByteSwap(elf_header.e_flags);
295
77
    cmELFByteSwap(elf_header.e_ehsize);
296
77
    cmELFByteSwap(elf_header.e_phentsize);
297
77
    cmELFByteSwap(elf_header.e_phnum);
298
77
    cmELFByteSwap(elf_header.e_shentsize);
299
77
    cmELFByteSwap(elf_header.e_shnum);
300
77
    cmELFByteSwap(elf_header.e_shstrndx);
301
77
  }
cmELFInternalImpl<cmELFTypes64>::ByteSwap(Elf64_Ehdr&)
Line
Count
Source
287
255
  {
288
255
    cmELFByteSwap(elf_header.e_type);
289
255
    cmELFByteSwap(elf_header.e_machine);
290
255
    cmELFByteSwap(elf_header.e_version);
291
255
    cmELFByteSwap(elf_header.e_entry);
292
255
    cmELFByteSwap(elf_header.e_phoff);
293
255
    cmELFByteSwap(elf_header.e_shoff);
294
255
    cmELFByteSwap(elf_header.e_flags);
295
255
    cmELFByteSwap(elf_header.e_ehsize);
296
255
    cmELFByteSwap(elf_header.e_phentsize);
297
255
    cmELFByteSwap(elf_header.e_phnum);
298
255
    cmELFByteSwap(elf_header.e_shentsize);
299
255
    cmELFByteSwap(elf_header.e_shnum);
300
255
    cmELFByteSwap(elf_header.e_shstrndx);
301
255
  }
302
303
  void ByteSwap(ELF_Shdr& sec_header)
304
8.14M
  {
305
8.14M
    cmELFByteSwap(sec_header.sh_name);
306
8.14M
    cmELFByteSwap(sec_header.sh_type);
307
8.14M
    cmELFByteSwap(sec_header.sh_flags);
308
8.14M
    cmELFByteSwap(sec_header.sh_addr);
309
8.14M
    cmELFByteSwap(sec_header.sh_offset);
310
8.14M
    cmELFByteSwap(sec_header.sh_size);
311
8.14M
    cmELFByteSwap(sec_header.sh_link);
312
8.14M
    cmELFByteSwap(sec_header.sh_info);
313
8.14M
    cmELFByteSwap(sec_header.sh_addralign);
314
8.14M
    cmELFByteSwap(sec_header.sh_entsize);
315
8.14M
  }
cmELFInternalImpl<cmELFTypes32>::ByteSwap(Elf32_Shdr&)
Line
Count
Source
304
1.28M
  {
305
1.28M
    cmELFByteSwap(sec_header.sh_name);
306
1.28M
    cmELFByteSwap(sec_header.sh_type);
307
1.28M
    cmELFByteSwap(sec_header.sh_flags);
308
1.28M
    cmELFByteSwap(sec_header.sh_addr);
309
1.28M
    cmELFByteSwap(sec_header.sh_offset);
310
1.28M
    cmELFByteSwap(sec_header.sh_size);
311
1.28M
    cmELFByteSwap(sec_header.sh_link);
312
1.28M
    cmELFByteSwap(sec_header.sh_info);
313
1.28M
    cmELFByteSwap(sec_header.sh_addralign);
314
1.28M
    cmELFByteSwap(sec_header.sh_entsize);
315
1.28M
  }
cmELFInternalImpl<cmELFTypes64>::ByteSwap(Elf64_Shdr&)
Line
Count
Source
304
6.85M
  {
305
6.85M
    cmELFByteSwap(sec_header.sh_name);
306
6.85M
    cmELFByteSwap(sec_header.sh_type);
307
6.85M
    cmELFByteSwap(sec_header.sh_flags);
308
6.85M
    cmELFByteSwap(sec_header.sh_addr);
309
6.85M
    cmELFByteSwap(sec_header.sh_offset);
310
6.85M
    cmELFByteSwap(sec_header.sh_size);
311
6.85M
    cmELFByteSwap(sec_header.sh_link);
312
6.85M
    cmELFByteSwap(sec_header.sh_info);
313
6.85M
    cmELFByteSwap(sec_header.sh_addralign);
314
6.85M
    cmELFByteSwap(sec_header.sh_entsize);
315
6.85M
  }
316
317
  void ByteSwap(ELF_Dyn& dyn)
318
138k
  {
319
138k
    cmELFByteSwap(dyn.d_tag);
320
138k
    cmELFByteSwap(dyn.d_un.d_val);
321
138k
  }
cmELFInternalImpl<cmELFTypes32>::ByteSwap(Elf32_Dyn&)
Line
Count
Source
318
136k
  {
319
136k
    cmELFByteSwap(dyn.d_tag);
320
136k
    cmELFByteSwap(dyn.d_un.d_val);
321
136k
  }
cmELFInternalImpl<cmELFTypes64>::ByteSwap(Elf64_Dyn&)
Line
Count
Source
318
1.94k
  {
319
1.94k
    cmELFByteSwap(dyn.d_tag);
320
1.94k
    cmELFByteSwap(dyn.d_un.d_val);
321
1.94k
  }
322
323
  bool FileTypeValid(ELF_Half et)
324
1.62k
  {
325
1.62k
    unsigned int eti = static_cast<unsigned int>(et);
326
1.62k
    if (eti == ET_NONE || eti == ET_REL || eti == ET_EXEC || eti == ET_DYN ||
327
865
        eti == ET_CORE) {
328
789
      return true;
329
789
    }
330
839
    if (eti >= ET_LOOS && eti <= ET_HIOS) {
331
61
      return true;
332
61
    }
333
778
    if (eti >= ET_LOPROC && eti <= ET_HIPROC) {
334
211
      return true;
335
211
    }
336
567
    return false;
337
778
  }
cmELFInternalImpl<cmELFTypes32>::FileTypeValid(unsigned short)
Line
Count
Source
324
504
  {
325
504
    unsigned int eti = static_cast<unsigned int>(et);
326
504
    if (eti == ET_NONE || eti == ET_REL || eti == ET_EXEC || eti == ET_DYN ||
327
321
        eti == ET_CORE) {
328
321
      return true;
329
321
    }
330
183
    if (eti >= ET_LOOS && eti <= ET_HIOS) {
331
16
      return true;
332
16
    }
333
167
    if (eti >= ET_LOPROC && eti <= ET_HIPROC) {
334
54
      return true;
335
54
    }
336
113
    return false;
337
167
  }
cmELFInternalImpl<cmELFTypes64>::FileTypeValid(unsigned short)
Line
Count
Source
324
1.12k
  {
325
1.12k
    unsigned int eti = static_cast<unsigned int>(et);
326
1.12k
    if (eti == ET_NONE || eti == ET_REL || eti == ET_EXEC || eti == ET_DYN ||
327
670
        eti == ET_CORE) {
328
468
      return true;
329
468
    }
330
656
    if (eti >= ET_LOOS && eti <= ET_HIOS) {
331
45
      return true;
332
45
    }
333
611
    if (eti >= ET_LOPROC && eti <= ET_HIPROC) {
334
157
      return true;
335
157
    }
336
454
    return false;
337
611
  }
338
339
  bool Read(ELF_Ehdr& x)
340
1.12k
  {
341
    // Read the header from the file.
342
1.12k
    if (!this->Stream->read(reinterpret_cast<char*>(&x), sizeof(x))) {
343
4
      return false;
344
4
    }
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.12k
    ELF_Half et = x.e_type;
353
1.12k
    if (this->NeedSwap) {
354
199
      cmELFByteSwap(et);
355
199
    }
356
1.12k
    if (!this->FileTypeValid(et)) {
357
508
      cmELFByteSwap(et);
358
508
      if (this->FileTypeValid(et)) {
359
        // The previous byte order guess was wrong.  Flip it.
360
449
        this->NeedSwap = !this->NeedSwap;
361
449
      }
362
508
    }
363
364
    // Fix the byte order of the header.
365
1.12k
    if (this->NeedSwap) {
366
332
      this->ByteSwap(x);
367
332
    }
368
1.12k
    return true;
369
1.12k
  }
cmELFInternalImpl<cmELFTypes32>::Read(Elf32_Ehdr&)
Line
Count
Source
340
422
  {
341
    // Read the header from the file.
342
422
    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
420
    ELF_Half et = x.e_type;
353
420
    if (this->NeedSwap) {
354
32
      cmELFByteSwap(et);
355
32
    }
356
420
    if (!this->FileTypeValid(et)) {
357
84
      cmELFByteSwap(et);
358
84
      if (this->FileTypeValid(et)) {
359
        // The previous byte order guess was wrong.  Flip it.
360
55
        this->NeedSwap = !this->NeedSwap;
361
55
      }
362
84
    }
363
364
    // Fix the byte order of the header.
365
420
    if (this->NeedSwap) {
366
77
      this->ByteSwap(x);
367
77
    }
368
420
    return true;
369
422
  }
cmELFInternalImpl<cmELFTypes64>::Read(Elf64_Ehdr&)
Line
Count
Source
340
702
  {
341
    // Read the header from the file.
342
702
    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
700
    ELF_Half et = x.e_type;
353
700
    if (this->NeedSwap) {
354
167
      cmELFByteSwap(et);
355
167
    }
356
700
    if (!this->FileTypeValid(et)) {
357
424
      cmELFByteSwap(et);
358
424
      if (this->FileTypeValid(et)) {
359
        // The previous byte order guess was wrong.  Flip it.
360
394
        this->NeedSwap = !this->NeedSwap;
361
394
      }
362
424
    }
363
364
    // Fix the byte order of the header.
365
700
    if (this->NeedSwap) {
366
255
      this->ByteSwap(x);
367
255
    }
368
700
    return true;
369
702
  }
370
  bool Read(ELF_Shdr& x)
371
29.6M
  {
372
29.6M
    if (this->Stream->read(reinterpret_cast<char*>(&x), sizeof(x)) &&
373
29.6M
        this->NeedSwap) {
374
8.14M
      this->ByteSwap(x);
375
8.14M
    }
376
29.6M
    return !this->Stream->fail();
377
29.6M
  }
cmELFInternalImpl<cmELFTypes32>::Read(Elf32_Shdr&)
Line
Count
Source
371
13.2M
  {
372
13.2M
    if (this->Stream->read(reinterpret_cast<char*>(&x), sizeof(x)) &&
373
13.2M
        this->NeedSwap) {
374
1.28M
      this->ByteSwap(x);
375
1.28M
    }
376
13.2M
    return !this->Stream->fail();
377
13.2M
  }
cmELFInternalImpl<cmELFTypes64>::Read(Elf64_Shdr&)
Line
Count
Source
371
16.4M
  {
372
16.4M
    if (this->Stream->read(reinterpret_cast<char*>(&x), sizeof(x)) &&
373
16.4M
        this->NeedSwap) {
374
6.85M
      this->ByteSwap(x);
375
6.85M
    }
376
16.4M
    return !this->Stream->fail();
377
16.4M
  }
378
  bool Read(ELF_Dyn& x)
379
1.70M
  {
380
1.70M
    if (this->Stream->read(reinterpret_cast<char*>(&x), sizeof(x)) &&
381
1.70M
        this->NeedSwap) {
382
69.7k
      this->ByteSwap(x);
383
69.7k
    }
384
1.70M
    return !this->Stream->fail();
385
1.70M
  }
cmELFInternalImpl<cmELFTypes32>::Read(Elf32_Dyn&)
Line
Count
Source
379
1.39M
  {
380
1.39M
    if (this->Stream->read(reinterpret_cast<char*>(&x), sizeof(x)) &&
381
1.39M
        this->NeedSwap) {
382
68.7k
      this->ByteSwap(x);
383
68.7k
    }
384
1.39M
    return !this->Stream->fail();
385
1.39M
  }
cmELFInternalImpl<cmELFTypes64>::Read(Elf64_Dyn&)
Line
Count
Source
379
311k
  {
380
311k
    if (this->Stream->read(reinterpret_cast<char*>(&x), sizeof(x)) &&
381
311k
        this->NeedSwap) {
382
1.03k
      this->ByteSwap(x);
383
1.03k
    }
384
311k
    return !this->Stream->fail();
385
311k
  }
386
387
  bool LoadSectionHeader(std::size_t i)
388
29.6M
  {
389
    // Read the section header from the file.
390
29.6M
    this->Stream->seekg(this->ELFHeader.e_shoff +
391
29.6M
                        this->ELFHeader.e_shentsize * i);
392
29.6M
    if (!this->Read(this->SectionHeaders[i])) {
393
148
      this->SetErrorMessage("Failed to load section headers.");
394
148
      return false;
395
148
    }
396
397
    // Identify some important sections.
398
29.6M
    if (this->SectionHeaders[i].sh_type == SHT_DYNAMIC) {
399
24.8M
      this->DynamicSectionIndex = static_cast<int>(i);
400
24.8M
    }
401
29.6M
    return true;
402
29.6M
  }
cmELFInternalImpl<cmELFTypes32>::LoadSectionHeader(unsigned long)
Line
Count
Source
388
13.2M
  {
389
    // Read the section header from the file.
390
13.2M
    this->Stream->seekg(this->ELFHeader.e_shoff +
391
13.2M
                        this->ELFHeader.e_shentsize * i);
392
13.2M
    if (!this->Read(this->SectionHeaders[i])) {
393
40
      this->SetErrorMessage("Failed to load section headers.");
394
40
      return false;
395
40
    }
396
397
    // Identify some important sections.
398
13.2M
    if (this->SectionHeaders[i].sh_type == SHT_DYNAMIC) {
399
11.3M
      this->DynamicSectionIndex = static_cast<int>(i);
400
11.3M
    }
401
13.2M
    return true;
402
13.2M
  }
cmELFInternalImpl<cmELFTypes64>::LoadSectionHeader(unsigned long)
Line
Count
Source
388
16.4M
  {
389
    // Read the section header from the file.
390
16.4M
    this->Stream->seekg(this->ELFHeader.e_shoff +
391
16.4M
                        this->ELFHeader.e_shentsize * i);
392
16.4M
    if (!this->Read(this->SectionHeaders[i])) {
393
108
      this->SetErrorMessage("Failed to load section headers.");
394
108
      return false;
395
108
    }
396
397
    // Identify some important sections.
398
16.4M
    if (this->SectionHeaders[i].sh_type == SHT_DYNAMIC) {
399
13.4M
      this->DynamicSectionIndex = static_cast<int>(i);
400
13.4M
    }
401
16.4M
    return true;
402
16.4M
  }
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.12k
  : cmELFInternal(external, std::move(fin), order)
421
1.12k
{
422
  // Read the main header.
423
1.12k
  if (!this->Read(this->ELFHeader)) {
424
4
    this->SetErrorMessage("Failed to read main ELF header.");
425
4
    return;
426
4
  }
427
428
  // Determine the ELF file type.
429
1.12k
  switch (this->ELFHeader.e_type) {
430
2
    case ET_NONE:
431
2
      this->SetErrorMessage("ELF file type is NONE.");
432
2
      return;
433
52
    case ET_REL:
434
52
      this->ELFType = cmELF::FileTypeRelocatableObject;
435
52
      break;
436
301
    case ET_EXEC:
437
301
      this->ELFType = cmELF::FileTypeExecutable;
438
301
      break;
439
408
    case ET_DYN:
440
408
      this->ELFType = cmELF::FileTypeSharedLibrary;
441
408
      break;
442
26
    case ET_CORE:
443
26
      this->ELFType = cmELF::FileTypeCore;
444
26
      break;
445
331
    default: {
446
331
      unsigned int eti = static_cast<unsigned int>(this->ELFHeader.e_type);
447
331
      if (eti >= ET_LOOS && eti <= ET_HIOS) {
448
61
        this->ELFType = cmELF::FileTypeSpecificOS;
449
61
        break;
450
61
      }
451
270
      if (eti >= ET_LOPROC && eti <= ET_HIPROC) {
452
211
        this->ELFType = cmELF::FileTypeSpecificProc;
453
211
        break;
454
211
      }
455
59
      this->SetErrorMessage(cmStrCat("Unknown ELF file type ", eti).c_str());
456
59
      return;
457
270
    }
458
1.12k
  }
459
460
1.05k
  this->Machine = this->ELFHeader.e_machine;
461
462
  // Load the section headers.
463
1.05k
  std::size_t const minSections = 1;
464
1.05k
  std::size_t numSections = this->ELFHeader.e_shnum;
465
  // Prevent OOM from malformed files.
466
1.05k
  if (numSections > kMaxSections) {
467
0
    this->SetErrorMessage("ELF file has too many sections.");
468
0
    return;
469
0
  }
470
1.05k
  this->SectionHeaders.resize(std::max(numSections, minSections));
471
1.05k
  if (!this->LoadSectionHeader(0)) {
472
21
    return;
473
21
  }
474
1.03k
  numSections = this->GetNumberOfSections();
475
1.03k
  this->SectionHeaders.resize(std::max(numSections, minSections));
476
29.6M
  for (std::size_t i = 1; i < numSections; ++i) {
477
29.6M
    if (!this->LoadSectionHeader(i)) {
478
127
      return;
479
127
    }
480
29.6M
  }
481
1.03k
}
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
422
  : cmELFInternal(external, std::move(fin), order)
421
422
{
422
  // Read the main header.
423
422
  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
420
  switch (this->ELFHeader.e_type) {
430
1
    case ET_NONE:
431
1
      this->SetErrorMessage("ELF file type is NONE.");
432
1
      return;
433
13
    case ET_REL:
434
13
      this->ELFType = cmELF::FileTypeRelocatableObject;
435
13
      break;
436
128
    case ET_EXEC:
437
128
      this->ELFType = cmELF::FileTypeExecutable;
438
128
      break;
439
167
    case ET_DYN:
440
167
      this->ELFType = cmELF::FileTypeSharedLibrary;
441
167
      break;
442
12
    case ET_CORE:
443
12
      this->ELFType = cmELF::FileTypeCore;
444
12
      break;
445
99
    default: {
446
99
      unsigned int eti = static_cast<unsigned int>(this->ELFHeader.e_type);
447
99
      if (eti >= ET_LOOS && eti <= ET_HIOS) {
448
16
        this->ELFType = cmELF::FileTypeSpecificOS;
449
16
        break;
450
16
      }
451
83
      if (eti >= ET_LOPROC && eti <= ET_HIPROC) {
452
54
        this->ELFType = cmELF::FileTypeSpecificProc;
453
54
        break;
454
54
      }
455
29
      this->SetErrorMessage(cmStrCat("Unknown ELF file type ", eti).c_str());
456
29
      return;
457
83
    }
458
420
  }
459
460
390
  this->Machine = this->ELFHeader.e_machine;
461
462
  // Load the section headers.
463
390
  std::size_t const minSections = 1;
464
390
  std::size_t numSections = this->ELFHeader.e_shnum;
465
  // Prevent OOM from malformed files.
466
390
  if (numSections > kMaxSections) {
467
0
    this->SetErrorMessage("ELF file has too many sections.");
468
0
    return;
469
0
  }
470
390
  this->SectionHeaders.resize(std::max(numSections, minSections));
471
390
  if (!this->LoadSectionHeader(0)) {
472
10
    return;
473
10
  }
474
380
  numSections = this->GetNumberOfSections();
475
380
  this->SectionHeaders.resize(std::max(numSections, minSections));
476
13.2M
  for (std::size_t i = 1; i < numSections; ++i) {
477
13.2M
    if (!this->LoadSectionHeader(i)) {
478
30
      return;
479
30
    }
480
13.2M
  }
481
380
}
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
702
  : cmELFInternal(external, std::move(fin), order)
421
702
{
422
  // Read the main header.
423
702
  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
700
  switch (this->ELFHeader.e_type) {
430
1
    case ET_NONE:
431
1
      this->SetErrorMessage("ELF file type is NONE.");
432
1
      return;
433
39
    case ET_REL:
434
39
      this->ELFType = cmELF::FileTypeRelocatableObject;
435
39
      break;
436
173
    case ET_EXEC:
437
173
      this->ELFType = cmELF::FileTypeExecutable;
438
173
      break;
439
241
    case ET_DYN:
440
241
      this->ELFType = cmELF::FileTypeSharedLibrary;
441
241
      break;
442
14
    case ET_CORE:
443
14
      this->ELFType = cmELF::FileTypeCore;
444
14
      break;
445
232
    default: {
446
232
      unsigned int eti = static_cast<unsigned int>(this->ELFHeader.e_type);
447
232
      if (eti >= ET_LOOS && eti <= ET_HIOS) {
448
45
        this->ELFType = cmELF::FileTypeSpecificOS;
449
45
        break;
450
45
      }
451
187
      if (eti >= ET_LOPROC && eti <= ET_HIPROC) {
452
157
        this->ELFType = cmELF::FileTypeSpecificProc;
453
157
        break;
454
157
      }
455
30
      this->SetErrorMessage(cmStrCat("Unknown ELF file type ", eti).c_str());
456
30
      return;
457
187
    }
458
700
  }
459
460
669
  this->Machine = this->ELFHeader.e_machine;
461
462
  // Load the section headers.
463
669
  std::size_t const minSections = 1;
464
669
  std::size_t numSections = this->ELFHeader.e_shnum;
465
  // Prevent OOM from malformed files.
466
669
  if (numSections > kMaxSections) {
467
0
    this->SetErrorMessage("ELF file has too many sections.");
468
0
    return;
469
0
  }
470
669
  this->SectionHeaders.resize(std::max(numSections, minSections));
471
669
  if (!this->LoadSectionHeader(0)) {
472
11
    return;
473
11
  }
474
658
  numSections = this->GetNumberOfSections();
475
658
  this->SectionHeaders.resize(std::max(numSections, minSections));
476
16.4M
  for (std::size_t i = 1; i < numSections; ++i) {
477
16.4M
    if (!this->LoadSectionHeader(i)) {
478
97
      return;
479
97
    }
480
16.4M
  }
481
658
}
482
483
template <class Types>
484
bool cmELFInternalImpl<Types>::LoadDynamicSection()
485
11.3k
{
486
  // If there is no dynamic section we are done.
487
11.3k
  if (!this->HasDynamicSection()) {
488
196
    return false;
489
196
  }
490
491
  // If the section was already loaded we are done.
492
11.1k
  if (!this->DynamicSectionEntries.empty()) {
493
10.0k
    return true;
494
10.0k
  }
495
496
  // If there are no entries we are done.
497
1.06k
  ELF_Shdr const& sec = this->SectionHeaders[this->DynamicSectionIndex];
498
1.06k
  if (sec.sh_entsize == 0) {
499
20
    return false;
500
20
  }
501
502
  // Prevent OOM from malformed files.
503
1.04k
  if (sec.sh_size > kMaxSectionSize) {
504
99
    this->SetErrorMessage("DYNAMIC section is too large.");
505
99
    return false;
506
99
  }
507
508
  // Allocate the dynamic section entries.
509
946
  std::size_t n = static_cast<int>(sec.sh_size / sec.sh_entsize);
510
  // Prevent OOM from malformed files.
511
946
  if (n > kMaxDynamicEntries) {
512
21
    this->SetErrorMessage("DYNAMIC section has too many entries.");
513
21
    return false;
514
21
  }
515
925
  this->DynamicSectionEntries.resize(n);
516
517
  // Read each entry.
518
1.70M
  for (std::size_t j = 0; j < n; ++j) {
519
    // Seek to the beginning of the section entry.
520
1.70M
    this->Stream->seekg(sec.sh_offset + sec.sh_entsize * j);
521
1.70M
    ELF_Dyn& dyn = this->DynamicSectionEntries[j];
522
523
    // Try reading the entry.
524
1.70M
    if (!this->Read(dyn)) {
525
72
      this->SetErrorMessage("Error reading entry from DYNAMIC section.");
526
72
      this->DynamicSectionIndex = -1;
527
72
      return false;
528
72
    }
529
1.70M
  }
530
853
  return true;
531
925
}
cmELFInternalImpl<cmELFTypes32>::LoadDynamicSection()
Line
Count
Source
485
5.87k
{
486
  // If there is no dynamic section we are done.
487
5.87k
  if (!this->HasDynamicSection()) {
488
96
    return false;
489
96
  }
490
491
  // If the section was already loaded we are done.
492
5.77k
  if (!this->DynamicSectionEntries.empty()) {
493
5.37k
    return true;
494
5.37k
  }
495
496
  // If there are no entries we are done.
497
401
  ELF_Shdr const& sec = this->SectionHeaders[this->DynamicSectionIndex];
498
401
  if (sec.sh_entsize == 0) {
499
8
    return false;
500
8
  }
501
502
  // Prevent OOM from malformed files.
503
393
  if (sec.sh_size > kMaxSectionSize) {
504
16
    this->SetErrorMessage("DYNAMIC section is too large.");
505
16
    return false;
506
16
  }
507
508
  // Allocate the dynamic section entries.
509
377
  std::size_t n = static_cast<int>(sec.sh_size / sec.sh_entsize);
510
  // Prevent OOM from malformed files.
511
377
  if (n > kMaxDynamicEntries) {
512
11
    this->SetErrorMessage("DYNAMIC section has too many entries.");
513
11
    return false;
514
11
  }
515
366
  this->DynamicSectionEntries.resize(n);
516
517
  // Read each entry.
518
1.39M
  for (std::size_t j = 0; j < n; ++j) {
519
    // Seek to the beginning of the section entry.
520
1.39M
    this->Stream->seekg(sec.sh_offset + sec.sh_entsize * j);
521
1.39M
    ELF_Dyn& dyn = this->DynamicSectionEntries[j];
522
523
    // Try reading the entry.
524
1.39M
    if (!this->Read(dyn)) {
525
39
      this->SetErrorMessage("Error reading entry from DYNAMIC section.");
526
39
      this->DynamicSectionIndex = -1;
527
39
      return false;
528
39
    }
529
1.39M
  }
530
327
  return true;
531
366
}
cmELFInternalImpl<cmELFTypes64>::LoadDynamicSection()
Line
Count
Source
485
5.48k
{
486
  // If there is no dynamic section we are done.
487
5.48k
  if (!this->HasDynamicSection()) {
488
100
    return false;
489
100
  }
490
491
  // If the section was already loaded we are done.
492
5.38k
  if (!this->DynamicSectionEntries.empty()) {
493
4.72k
    return true;
494
4.72k
  }
495
496
  // If there are no entries we are done.
497
664
  ELF_Shdr const& sec = this->SectionHeaders[this->DynamicSectionIndex];
498
664
  if (sec.sh_entsize == 0) {
499
12
    return false;
500
12
  }
501
502
  // Prevent OOM from malformed files.
503
652
  if (sec.sh_size > kMaxSectionSize) {
504
83
    this->SetErrorMessage("DYNAMIC section is too large.");
505
83
    return false;
506
83
  }
507
508
  // Allocate the dynamic section entries.
509
569
  std::size_t n = static_cast<int>(sec.sh_size / sec.sh_entsize);
510
  // Prevent OOM from malformed files.
511
569
  if (n > kMaxDynamicEntries) {
512
10
    this->SetErrorMessage("DYNAMIC section has too many entries.");
513
10
    return false;
514
10
  }
515
559
  this->DynamicSectionEntries.resize(n);
516
517
  // Read each entry.
518
312k
  for (std::size_t j = 0; j < n; ++j) {
519
    // Seek to the beginning of the section entry.
520
311k
    this->Stream->seekg(sec.sh_offset + sec.sh_entsize * j);
521
311k
    ELF_Dyn& dyn = this->DynamicSectionEntries[j];
522
523
    // Try reading the entry.
524
311k
    if (!this->Read(dyn)) {
525
33
      this->SetErrorMessage("Error reading entry from DYNAMIC section.");
526
33
      this->DynamicSectionIndex = -1;
527
33
      return false;
528
33
    }
529
311k
  }
530
526
  return true;
531
559
}
532
533
template <class Types>
534
unsigned long cmELFInternalImpl<Types>::GetDynamicEntryPosition(int j)
535
9.58k
{
536
9.58k
  if (!this->LoadDynamicSection()) {
537
0
    return 0;
538
0
  }
539
9.58k
  if (j < 0 || j >= static_cast<int>(this->DynamicSectionEntries.size())) {
540
0
    return 0;
541
0
  }
542
9.58k
  ELF_Shdr const& sec = this->SectionHeaders[this->DynamicSectionIndex];
543
9.58k
  return sec.sh_offset + sec.sh_entsize * static_cast<unsigned long>(j);
544
9.58k
}
cmELFInternalImpl<cmELFTypes32>::GetDynamicEntryPosition(int)
Line
Count
Source
535
5.14k
{
536
5.14k
  if (!this->LoadDynamicSection()) {
537
0
    return 0;
538
0
  }
539
5.14k
  if (j < 0 || j >= static_cast<int>(this->DynamicSectionEntries.size())) {
540
0
    return 0;
541
0
  }
542
5.14k
  ELF_Shdr const& sec = this->SectionHeaders[this->DynamicSectionIndex];
543
5.14k
  return sec.sh_offset + sec.sh_entsize * static_cast<unsigned long>(j);
544
5.14k
}
cmELFInternalImpl<cmELFTypes64>::GetDynamicEntryPosition(int)
Line
Count
Source
535
4.44k
{
536
4.44k
  if (!this->LoadDynamicSection()) {
537
0
    return 0;
538
0
  }
539
4.44k
  if (j < 0 || j >= static_cast<int>(this->DynamicSectionEntries.size())) {
540
0
    return 0;
541
0
  }
542
4.44k
  ELF_Shdr const& sec = this->SectionHeaders[this->DynamicSectionIndex];
543
4.44k
  return sec.sh_offset + sec.sh_entsize * static_cast<unsigned long>(j);
544
4.44k
}
545
546
template <class Types>
547
cmELF::DynamicEntryList cmELFInternalImpl<Types>::GetDynamicEntries()
548
526
{
549
526
  cmELF::DynamicEntryList result;
550
551
  // Ensure entries have been read from file
552
526
  if (!this->LoadDynamicSection()) {
553
208
    return result;
554
208
  }
555
556
  // Copy into public array
557
318
  result.reserve(this->DynamicSectionEntries.size());
558
1.69M
  for (ELF_Dyn& dyn : this->DynamicSectionEntries) {
559
1.69M
    result.emplace_back(dyn.d_tag, dyn.d_un.d_val);
560
1.69M
  }
561
562
318
  return result;
563
526
}
cmELFInternalImpl<cmELFTypes32>::GetDynamicEntries()
Line
Count
Source
548
201
{
549
201
  cmELF::DynamicEntryList result;
550
551
  // Ensure entries have been read from file
552
201
  if (!this->LoadDynamicSection()) {
553
60
    return result;
554
60
  }
555
556
  // Copy into public array
557
141
  result.reserve(this->DynamicSectionEntries.size());
558
1.39M
  for (ELF_Dyn& dyn : this->DynamicSectionEntries) {
559
1.39M
    result.emplace_back(dyn.d_tag, dyn.d_un.d_val);
560
1.39M
  }
561
562
141
  return result;
563
201
}
cmELFInternalImpl<cmELFTypes64>::GetDynamicEntries()
Line
Count
Source
548
325
{
549
325
  cmELF::DynamicEntryList result;
550
551
  // Ensure entries have been read from file
552
325
  if (!this->LoadDynamicSection()) {
553
148
    return result;
554
148
  }
555
556
  // Copy into public array
557
177
  result.reserve(this->DynamicSectionEntries.size());
558
302k
  for (ELF_Dyn& dyn : this->DynamicSectionEntries) {
559
302k
    result.emplace_back(dyn.d_tag, dyn.d_un.d_val);
560
302k
  }
561
562
177
  return result;
563
325
}
564
565
template <class Types>
566
std::vector<char> cmELFInternalImpl<Types>::EncodeDynamicEntries(
567
  cmELF::DynamicEntryList const& entries)
568
169
{
569
169
  std::vector<char> result;
570
169
  result.reserve(sizeof(ELF_Dyn) * entries.size());
571
572
1.69M
  for (auto const& entry : entries) {
573
    // Store the entry in an ELF_Dyn, byteswap it, then serialize to chars
574
1.69M
    ELF_Dyn dyn;
575
1.69M
    dyn.d_tag = static_cast<tagtype>(entry.first);
576
1.69M
    dyn.d_un.d_val = static_cast<tagtype>(entry.second);
577
578
1.69M
    if (this->NeedSwap) {
579
69.0k
      this->ByteSwap(dyn);
580
69.0k
    }
581
582
1.69M
    char* pdyn = reinterpret_cast<char*>(&dyn);
583
1.69M
    cm::append(result, pdyn, pdyn + sizeof(ELF_Dyn));
584
1.69M
  }
585
586
169
  return result;
587
169
}
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
568
86
{
569
86
  std::vector<char> result;
570
86
  result.reserve(sizeof(ELF_Dyn) * entries.size());
571
572
1.39M
  for (auto const& entry : entries) {
573
    // Store the entry in an ELF_Dyn, byteswap it, then serialize to chars
574
1.39M
    ELF_Dyn dyn;
575
1.39M
    dyn.d_tag = static_cast<tagtype>(entry.first);
576
1.39M
    dyn.d_un.d_val = static_cast<tagtype>(entry.second);
577
578
1.39M
    if (this->NeedSwap) {
579
68.1k
      this->ByteSwap(dyn);
580
68.1k
    }
581
582
1.39M
    char* pdyn = reinterpret_cast<char*>(&dyn);
583
1.39M
    cm::append(result, pdyn, pdyn + sizeof(ELF_Dyn));
584
1.39M
  }
585
586
86
  return result;
587
86
}
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
568
83
{
569
83
  std::vector<char> result;
570
83
  result.reserve(sizeof(ELF_Dyn) * entries.size());
571
572
302k
  for (auto const& entry : entries) {
573
    // Store the entry in an ELF_Dyn, byteswap it, then serialize to chars
574
302k
    ELF_Dyn dyn;
575
302k
    dyn.d_tag = static_cast<tagtype>(entry.first);
576
302k
    dyn.d_un.d_val = static_cast<tagtype>(entry.second);
577
578
302k
    if (this->NeedSwap) {
579
907
      this->ByteSwap(dyn);
580
907
    }
581
582
302k
    char* pdyn = reinterpret_cast<char*>(&dyn);
583
302k
    cm::append(result, pdyn, pdyn + sizeof(ELF_Dyn));
584
302k
  }
585
586
83
  return result;
587
83
}
588
589
template <class Types>
590
cmELF::StringEntry const* cmELFInternalImpl<Types>::GetDynamicSectionString(
591
  unsigned int tag)
592
1.49k
{
593
  // Short-circuit if already checked.
594
1.49k
  auto dssi = this->DynamicSectionStrings.find(tag);
595
1.49k
  if (dssi != this->DynamicSectionStrings.end()) {
596
251
    if (dssi->second.Position > 0) {
597
94
      return &dssi->second;
598
94
    }
599
157
    return nullptr;
600
251
  }
601
602
  // Create an entry for this tag.  Assume it is missing until found.
603
1.24k
  StringEntry& se = this->DynamicSectionStrings[tag];
604
1.24k
  se.Position = 0;
605
1.24k
  se.Size = 0;
606
1.24k
  se.IndexInSection = -1;
607
608
  // Try reading the dynamic section.
609
1.24k
  if (!this->LoadDynamicSection()) {
610
200
    return nullptr;
611
200
  }
612
613
  // Get the string table referenced by the DYNAMIC section.
614
1.04k
  ELF_Shdr const& sec = this->SectionHeaders[this->DynamicSectionIndex];
615
1.04k
  if (sec.sh_link >= this->SectionHeaders.size()) {
616
107
    this->SetErrorMessage("Section DYNAMIC has invalid string table index.");
617
107
    return nullptr;
618
107
  }
619
933
  ELF_Shdr const& strtab = this->SectionHeaders[sec.sh_link];
620
621
  // Look for the requested entry.
622
933
  for (auto di = this->DynamicSectionEntries.begin();
623
1.02M
       di != this->DynamicSectionEntries.end(); ++di) {
624
1.02M
    ELF_Dyn& dyn = *di;
625
1.02M
    if (static_cast<tagtype>(dyn.d_tag) == static_cast<tagtype>(tag)) {
626
      // We found the tag requested.
627
      // Make sure the position given is within the string section.
628
363
      if (dyn.d_un.d_val >= strtab.sh_size) {
629
141
        this->SetErrorMessage("Section DYNAMIC references string beyond "
630
141
                              "the end of its string section.");
631
141
        return nullptr;
632
141
      }
633
634
      // Seek to the position reported by the entry.
635
222
      unsigned long first = static_cast<unsigned long>(dyn.d_un.d_val);
636
222
      unsigned long last = first;
637
222
      unsigned long end = static_cast<unsigned long>(strtab.sh_size);
638
222
      this->Stream->seekg(strtab.sh_offset + first);
639
640
      // Read the string.  It may be followed by more than one NULL
641
      // terminator.  Count the total size of the region allocated to
642
      // the string.  This assumes that the next string in the table
643
      // is non-empty, but the "chrpath" tool makes the same
644
      // assumption.
645
222
      bool terminated = false;
646
222
      char c;
647
477k
      while (last != end && this->Stream->get(c) && !(terminated && c)) {
648
477k
        ++last;
649
477k
        if (c) {
650
475k
          se.Value += c;
651
475k
        } else {
652
1.65k
          terminated = true;
653
1.65k
        }
654
477k
      }
655
656
      // Make sure the whole value was read.
657
222
      if (!(*this->Stream)) {
658
41
        if (tag == cmELF::TagRPath) {
659
23
          this->SetErrorMessage(
660
23
            "Dynamic section specifies unreadable DT_RPATH");
661
23
        } else if (tag == cmELF::TagRunPath) {
662
6
          this->SetErrorMessage(
663
6
            "Dynamic section specifies unreadable DT_RUNPATH");
664
12
        } else if (tag == cmELF::TagMipsRldMapRel) {
665
0
          this->SetErrorMessage(
666
0
            "Dynamic section specifies unreadable DT_MIPS_RLD_MAP_REL");
667
12
        } else {
668
12
          this->SetErrorMessage("Dynamic section specifies unreadable value"
669
12
                                " for unexpected attribute");
670
12
        }
671
41
        se.Value = "";
672
41
        return nullptr;
673
41
      }
674
675
      // The value has been read successfully.  Report it.
676
181
      se.Position = static_cast<unsigned long>(strtab.sh_offset + first);
677
181
      se.Size = last - first;
678
181
      se.IndexInSection =
679
181
        static_cast<int>(di - this->DynamicSectionEntries.begin());
680
181
      return &se;
681
222
    }
682
1.02M
  }
683
570
  return nullptr;
684
933
}
cmELFInternalImpl<cmELFTypes32>::GetDynamicSectionString(unsigned int)
Line
Count
Source
592
617
{
593
  // Short-circuit if already checked.
594
617
  auto dssi = this->DynamicSectionStrings.find(tag);
595
617
  if (dssi != this->DynamicSectionStrings.end()) {
596
92
    if (dssi->second.Position > 0) {
597
39
      return &dssi->second;
598
39
    }
599
53
    return nullptr;
600
92
  }
601
602
  // Create an entry for this tag.  Assume it is missing until found.
603
525
  StringEntry& se = this->DynamicSectionStrings[tag];
604
525
  se.Position = 0;
605
525
  se.Size = 0;
606
525
  se.IndexInSection = -1;
607
608
  // Try reading the dynamic section.
609
525
  if (!this->LoadDynamicSection()) {
610
110
    return nullptr;
611
110
  }
612
613
  // Get the string table referenced by the DYNAMIC section.
614
415
  ELF_Shdr const& sec = this->SectionHeaders[this->DynamicSectionIndex];
615
415
  if (sec.sh_link >= this->SectionHeaders.size()) {
616
38
    this->SetErrorMessage("Section DYNAMIC has invalid string table index.");
617
38
    return nullptr;
618
38
  }
619
377
  ELF_Shdr const& strtab = this->SectionHeaders[sec.sh_link];
620
621
  // Look for the requested entry.
622
377
  for (auto di = this->DynamicSectionEntries.begin();
623
406k
       di != this->DynamicSectionEntries.end(); ++di) {
624
406k
    ELF_Dyn& dyn = *di;
625
406k
    if (static_cast<tagtype>(dyn.d_tag) == static_cast<tagtype>(tag)) {
626
      // We found the tag requested.
627
      // Make sure the position given is within the string section.
628
134
      if (dyn.d_un.d_val >= strtab.sh_size) {
629
46
        this->SetErrorMessage("Section DYNAMIC references string beyond "
630
46
                              "the end of its string section.");
631
46
        return nullptr;
632
46
      }
633
634
      // Seek to the position reported by the entry.
635
88
      unsigned long first = static_cast<unsigned long>(dyn.d_un.d_val);
636
88
      unsigned long last = first;
637
88
      unsigned long end = static_cast<unsigned long>(strtab.sh_size);
638
88
      this->Stream->seekg(strtab.sh_offset + first);
639
640
      // Read the string.  It may be followed by more than one NULL
641
      // terminator.  Count the total size of the region allocated to
642
      // the string.  This assumes that the next string in the table
643
      // is non-empty, but the "chrpath" tool makes the same
644
      // assumption.
645
88
      bool terminated = false;
646
88
      char c;
647
385k
      while (last != end && this->Stream->get(c) && !(terminated && c)) {
648
385k
        ++last;
649
385k
        if (c) {
650
384k
          se.Value += c;
651
384k
        } else {
652
470
          terminated = true;
653
470
        }
654
385k
      }
655
656
      // Make sure the whole value was read.
657
88
      if (!(*this->Stream)) {
658
10
        if (tag == cmELF::TagRPath) {
659
6
          this->SetErrorMessage(
660
6
            "Dynamic section specifies unreadable DT_RPATH");
661
6
        } else if (tag == cmELF::TagRunPath) {
662
1
          this->SetErrorMessage(
663
1
            "Dynamic section specifies unreadable DT_RUNPATH");
664
3
        } else if (tag == cmELF::TagMipsRldMapRel) {
665
0
          this->SetErrorMessage(
666
0
            "Dynamic section specifies unreadable DT_MIPS_RLD_MAP_REL");
667
3
        } else {
668
3
          this->SetErrorMessage("Dynamic section specifies unreadable value"
669
3
                                " for unexpected attribute");
670
3
        }
671
10
        se.Value = "";
672
10
        return nullptr;
673
10
      }
674
675
      // The value has been read successfully.  Report it.
676
78
      se.Position = static_cast<unsigned long>(strtab.sh_offset + first);
677
78
      se.Size = last - first;
678
78
      se.IndexInSection =
679
78
        static_cast<int>(di - this->DynamicSectionEntries.begin());
680
78
      return &se;
681
88
    }
682
406k
  }
683
243
  return nullptr;
684
377
}
cmELFInternalImpl<cmELFTypes64>::GetDynamicSectionString(unsigned int)
Line
Count
Source
592
874
{
593
  // Short-circuit if already checked.
594
874
  auto dssi = this->DynamicSectionStrings.find(tag);
595
874
  if (dssi != this->DynamicSectionStrings.end()) {
596
159
    if (dssi->second.Position > 0) {
597
55
      return &dssi->second;
598
55
    }
599
104
    return nullptr;
600
159
  }
601
602
  // Create an entry for this tag.  Assume it is missing until found.
603
715
  StringEntry& se = this->DynamicSectionStrings[tag];
604
715
  se.Position = 0;
605
715
  se.Size = 0;
606
715
  se.IndexInSection = -1;
607
608
  // Try reading the dynamic section.
609
715
  if (!this->LoadDynamicSection()) {
610
90
    return nullptr;
611
90
  }
612
613
  // Get the string table referenced by the DYNAMIC section.
614
625
  ELF_Shdr const& sec = this->SectionHeaders[this->DynamicSectionIndex];
615
625
  if (sec.sh_link >= this->SectionHeaders.size()) {
616
69
    this->SetErrorMessage("Section DYNAMIC has invalid string table index.");
617
69
    return nullptr;
618
69
  }
619
556
  ELF_Shdr const& strtab = this->SectionHeaders[sec.sh_link];
620
621
  // Look for the requested entry.
622
556
  for (auto di = this->DynamicSectionEntries.begin();
623
614k
       di != this->DynamicSectionEntries.end(); ++di) {
624
614k
    ELF_Dyn& dyn = *di;
625
614k
    if (static_cast<tagtype>(dyn.d_tag) == static_cast<tagtype>(tag)) {
626
      // We found the tag requested.
627
      // Make sure the position given is within the string section.
628
229
      if (dyn.d_un.d_val >= strtab.sh_size) {
629
95
        this->SetErrorMessage("Section DYNAMIC references string beyond "
630
95
                              "the end of its string section.");
631
95
        return nullptr;
632
95
      }
633
634
      // Seek to the position reported by the entry.
635
134
      unsigned long first = static_cast<unsigned long>(dyn.d_un.d_val);
636
134
      unsigned long last = first;
637
134
      unsigned long end = static_cast<unsigned long>(strtab.sh_size);
638
134
      this->Stream->seekg(strtab.sh_offset + first);
639
640
      // Read the string.  It may be followed by more than one NULL
641
      // terminator.  Count the total size of the region allocated to
642
      // the string.  This assumes that the next string in the table
643
      // is non-empty, but the "chrpath" tool makes the same
644
      // assumption.
645
134
      bool terminated = false;
646
134
      char c;
647
92.4k
      while (last != end && this->Stream->get(c) && !(terminated && c)) {
648
92.3k
        ++last;
649
92.3k
        if (c) {
650
91.1k
          se.Value += c;
651
91.1k
        } else {
652
1.18k
          terminated = true;
653
1.18k
        }
654
92.3k
      }
655
656
      // Make sure the whole value was read.
657
134
      if (!(*this->Stream)) {
658
31
        if (tag == cmELF::TagRPath) {
659
17
          this->SetErrorMessage(
660
17
            "Dynamic section specifies unreadable DT_RPATH");
661
17
        } else if (tag == cmELF::TagRunPath) {
662
5
          this->SetErrorMessage(
663
5
            "Dynamic section specifies unreadable DT_RUNPATH");
664
9
        } else if (tag == cmELF::TagMipsRldMapRel) {
665
0
          this->SetErrorMessage(
666
0
            "Dynamic section specifies unreadable DT_MIPS_RLD_MAP_REL");
667
9
        } else {
668
9
          this->SetErrorMessage("Dynamic section specifies unreadable value"
669
9
                                " for unexpected attribute");
670
9
        }
671
31
        se.Value = "";
672
31
        return nullptr;
673
31
      }
674
675
      // The value has been read successfully.  Report it.
676
103
      se.Position = static_cast<unsigned long>(strtab.sh_offset + first);
677
103
      se.Size = last - first;
678
103
      se.IndexInSection =
679
103
        static_cast<int>(di - this->DynamicSectionEntries.begin());
680
103
      return &se;
681
134
    }
682
614k
  }
683
327
  return nullptr;
684
556
}
685
686
//============================================================================
687
// External class implementation.
688
689
long const cmELF::TagRPath = DT_RPATH;
690
long const cmELF::TagRunPath = DT_RUNPATH;
691
long const cmELF::TagMipsRldMapRel = DT_MIPS_RLD_MAP_REL;
692
693
cmELF::cmELF(char const* fname)
694
1.19k
{
695
  // Try to open the file.
696
1.19k
  auto fin = cm::make_unique<cmsys::ifstream>(fname, std::ios::binary);
697
698
  // Quit now if the file could not be opened.
699
1.19k
  if (!fin || !*fin) {
700
0
    this->ErrorMessage = "Error opening input file.";
701
0
    return;
702
0
  }
703
704
  // Read the ELF identification block.
705
1.19k
  char ident[EI_NIDENT];
706
1.19k
  if (!fin->read(ident, EI_NIDENT)) {
707
0
    this->ErrorMessage = "Error reading ELF identification.";
708
0
    return;
709
0
  }
710
1.19k
  if (!fin->seekg(0)) {
711
0
    this->ErrorMessage = "Error seeking to beginning of file.";
712
0
    return;
713
0
  }
714
715
  // Verify the ELF identification.
716
1.19k
  if (!(ident[EI_MAG0] == ELFMAG0 && ident[EI_MAG1] == ELFMAG1 &&
717
1.17k
        ident[EI_MAG2] == ELFMAG2 && ident[EI_MAG3] == ELFMAG3)) {
718
52
    this->ErrorMessage = "File does not have a valid ELF identification.";
719
52
    return;
720
52
  }
721
722
  // Check the byte order in which the rest of the file is encoded.
723
1.14k
  cmELFInternal::ByteOrderType order;
724
1.14k
  if (ident[EI_DATA] == ELFDATA2LSB) {
725
    // File is LSB.
726
930
    order = cmELFInternal::ByteOrderLSB;
727
930
  } else if (ident[EI_DATA] == ELFDATA2MSB) {
728
    // File is MSB.
729
206
    order = cmELFInternal::ByteOrderMSB;
730
206
  } else {
731
10
    this->ErrorMessage = "ELF file is not LSB or MSB encoded.";
732
10
    return;
733
10
  }
734
735
  // Check the class of the file and construct the corresponding
736
  // parser implementation.
737
1.13k
  if (ident[EI_CLASS] == ELFCLASS32) {
738
    // 32-bit ELF
739
422
    this->Internal = cm::make_unique<cmELFInternalImpl<cmELFTypes32>>(
740
422
      this, std::move(fin), order);
741
714
  } else if (ident[EI_CLASS] == ELFCLASS64) {
742
    // 64-bit ELF
743
702
    this->Internal = cm::make_unique<cmELFInternalImpl<cmELFTypes64>>(
744
702
      this, std::move(fin), order);
745
702
  } else {
746
12
    this->ErrorMessage = "ELF file class is not 32-bit or 64-bit.";
747
12
    return;
748
12
  }
749
1.13k
}
750
751
1.19k
cmELF::~cmELF() = default;
752
753
bool cmELF::Valid() const
754
20.9k
{
755
20.9k
  return this->Internal && this->Internal->GetFileType() != FileTypeInvalid;
756
20.9k
}
757
758
cmELF::FileType cmELF::GetFileType() const
759
911
{
760
911
  if (this->Valid()) {
761
911
    return this->Internal->GetFileType();
762
911
  }
763
0
  return FileTypeInvalid;
764
911
}
765
766
std::uint16_t cmELF::GetMachine() const
767
911
{
768
911
  if (this->Valid()) {
769
911
    return this->Internal->GetMachine();
770
911
  }
771
0
  return 0;
772
911
}
773
774
std::size_t cmELF::GetNumberOfSections() const
775
911
{
776
911
  if (this->Valid()) {
777
911
    return this->Internal->GetNumberOfSections();
778
911
  }
779
0
  return 0;
780
911
}
781
782
unsigned long cmELF::GetDynamicEntryPosition(int index) const
783
9.58k
{
784
9.58k
  if (this->Valid()) {
785
9.58k
    return this->Internal->GetDynamicEntryPosition(index);
786
9.58k
  }
787
0
  return 0;
788
9.58k
}
789
790
cmELF::DynamicEntryList cmELF::GetDynamicEntries() const
791
911
{
792
911
  if (this->Valid()) {
793
526
    return this->Internal->GetDynamicEntries();
794
526
  }
795
796
385
  return cmELF::DynamicEntryList();
797
911
}
798
799
std::vector<char> cmELF::EncodeDynamicEntries(
800
  cmELF::DynamicEntryList const& dentries) const
801
169
{
802
169
  if (this->Valid()) {
803
169
    return this->Internal->EncodeDynamicEntries(dentries);
804
169
  }
805
806
0
  return std::vector<char>();
807
169
}
808
809
bool cmELF::HasDynamicSection() const
810
911
{
811
911
  return this->Valid() && this->Internal->HasDynamicSection();
812
911
}
813
814
bool cmELF::GetSOName(std::string& soname)
815
911
{
816
911
  if (StringEntry const* se = this->GetSOName()) {
817
120
    soname = se->Value;
818
120
    return true;
819
120
  }
820
791
  return false;
821
911
}
822
823
cmELF::StringEntry const* cmELF::GetSOName()
824
1.82k
{
825
1.82k
  if (this->Valid() &&
826
1.68k
      this->Internal->GetFileType() == cmELF::FileTypeSharedLibrary) {
827
641
    return this->Internal->GetSOName();
828
641
  }
829
1.18k
  return nullptr;
830
1.82k
}
831
832
cmELF::StringEntry const* cmELF::GetRPath()
833
911
{
834
911
  if (this->Valid() &&
835
772
      (this->Internal->GetFileType() == cmELF::FileTypeExecutable ||
836
534
       this->Internal->GetFileType() == cmELF::FileTypeSharedLibrary)) {
837
534
    return this->Internal->GetRPath();
838
534
  }
839
377
  return nullptr;
840
911
}
841
842
cmELF::StringEntry const* cmELF::GetRunPath()
843
911
{
844
911
  if (this->Valid() &&
845
554
      (this->Internal->GetFileType() == cmELF::FileTypeExecutable ||
846
417
       this->Internal->GetFileType() == cmELF::FileTypeSharedLibrary)) {
847
316
    return this->Internal->GetRunPath();
848
316
  }
849
595
  return nullptr;
850
911
}
851
852
bool cmELF::IsMIPS() const
853
911
{
854
911
  if (this->Valid()) {
855
911
    return this->Internal->IsMips();
856
911
  }
857
0
  return false;
858
911
}
859
860
void cmELF::PrintInfo(std::ostream& os) const
861
911
{
862
911
  if (this->Valid()) {
863
430
    this->Internal->PrintInfo(os);
864
481
  } else {
865
481
    os << "Not a valid ELF file.\n";
866
481
  }
867
911
}