Coverage Report

Created: 2026-06-15 07:03

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 <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.48k
{
37
3.48k
  char one_byte;
38
3.48k
  one_byte = data[0];
39
3.48k
  data[0] = data[1];
40
3.48k
  data[1] = one_byte;
41
3.48k
}
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
40.6M
{
54
40.6M
  char one_byte;
55
40.6M
  one_byte = data[0];
56
40.6M
  data[0] = data[7];
57
40.6M
  data[7] = one_byte;
58
40.6M
  one_byte = data[1];
59
40.6M
  data[1] = data[6];
60
40.6M
  data[6] = one_byte;
61
40.6M
  one_byte = data[2];
62
40.6M
  data[2] = data[5];
63
40.6M
  data[5] = one_byte;
64
40.6M
  one_byte = data[3];
65
40.6M
  data[3] = data[4];
66
40.6M
  data[4] = one_byte;
67
40.6M
}
68
69
// Low-level byte swapping interface.
70
template <typename T>
71
void cmELFByteSwap(T& x)
72
81.2M
{
73
81.2M
  cmELFByteSwap(reinterpret_cast<char*>(&x), cmELFByteSwapSize<sizeof(T)>());
74
81.2M
}
void cmELFByteSwap<unsigned short>(unsigned short&)
Line
Count
Source
72
3.48k
{
73
3.48k
  cmELFByteSwap(reinterpret_cast<char*>(&x), cmELFByteSwapSize<sizeof(T)>());
74
3.48k
}
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
161k
{
73
161k
  cmELFByteSwap(reinterpret_cast<char*>(&x), cmELFByteSwapSize<sizeof(T)>());
74
161k
}
void cmELFByteSwap<unsigned long>(unsigned long&)
Line
Count
Source
72
40.6M
{
73
40.6M
  cmELFByteSwap(reinterpret_cast<char*>(&x), cmELFByteSwapSize<sizeof(T)>());
74
40.6M
}
Unexecuted instantiation: void cmELFByteSwap<long>(long&)
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.23k
    : External(external)
90
1.23k
    , Stream(std::move(fin))
91
1.23k
    , ByteOrder(order)
92
1.23k
  {
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.23k
#if KWIML_ABI_ENDIAN_ID == KWIML_ABI_ENDIAN_ID_LITTLE
97
1.23k
    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.23k
    this->DynamicSectionIndex = -1;
106
1.23k
  }
107
108
  // Destruct and delete the file stream object.
109
1.23k
  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
11.1k
  bool HasDynamicSection() const { return this->DynamicSectionIndex >= 0; }
123
124
  // Lookup the SONAME in the DYNAMIC section.
125
  StringEntry const* GetSOName()
126
668
  {
127
668
    return this->GetDynamicSectionString(DT_SONAME);
128
668
  }
129
130
  // Lookup the RPATH in the DYNAMIC section.
131
  StringEntry const* GetRPath()
132
631
  {
133
631
    return this->GetDynamicSectionString(DT_RPATH);
134
631
  }
135
136
  // Lookup the RUNPATH in the DYNAMIC section.
137
  StringEntry const* GetRunPath()
138
330
  {
139
330
    return this->GetDynamicSectionString(DT_RUNPATH);
140
330
  }
141
142
  // Return the recorded ELF type.
143
25.5k
  cmELF::FileType GetFileType() const { return this->ELFType; }
144
145
  // Return the recorded machine.
146
984
  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
769
  {
175
769
    this->External->ErrorMessage = msg;
176
769
    this->ELFType = cmELF::FileTypeInvalid;
177
769
  }
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
197
  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
264
  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
2.11k
  {
224
2.11k
    std::size_t count = this->ELFHeader.e_shnum;
225
2.11k
    if (!this->SectionHeaders.empty()) {
226
2.11k
      count += static_cast<std::size_t>(this->SectionHeaders[0].sh_size);
227
2.11k
    }
228
    // Prevent OOM from malformed files.
229
2.11k
    if (count > kMaxSections) {
230
657
      return kMaxSections;
231
657
    }
232
1.46k
    return count;
233
2.11k
  }
cmELFInternalImpl<cmELFTypes32>::GetNumberOfSections() const
Line
Count
Source
223
833
  {
224
833
    std::size_t count = this->ELFHeader.e_shnum;
225
833
    if (!this->SectionHeaders.empty()) {
226
833
      count += static_cast<std::size_t>(this->SectionHeaders[0].sh_size);
227
833
    }
228
    // Prevent OOM from malformed files.
229
833
    if (count > kMaxSections) {
230
315
      return kMaxSections;
231
315
    }
232
518
    return count;
233
833
  }
cmELFInternalImpl<cmELFTypes64>::GetNumberOfSections() const
Line
Count
Source
223
1.28k
  {
224
1.28k
    std::size_t count = this->ELFHeader.e_shnum;
225
1.28k
    if (!this->SectionHeaders.empty()) {
226
1.28k
      count += static_cast<std::size_t>(this->SectionHeaders[0].sh_size);
227
1.28k
    }
228
    // Prevent OOM from malformed files.
229
1.28k
    if (count > kMaxSections) {
230
342
      return kMaxSections;
231
342
    }
232
942
    return count;
233
1.28k
  }
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
984
  bool IsMips() const override { return this->ELFHeader.e_machine == EM_MIPS; }
cmELFInternalImpl<cmELFTypes32>::IsMips() const
Line
Count
Source
245
395
  bool IsMips() const override { return this->ELFHeader.e_machine == EM_MIPS; }
cmELFInternalImpl<cmELFTypes64>::IsMips() const
Line
Count
Source
245
589
  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
461
  {
250
461
    os << "ELF " << Types::GetName();
251
461
    if (this->ByteOrder == ByteOrderMSB) {
252
64
      os << " MSB";
253
397
    } else if (this->ByteOrder == ByteOrderLSB) {
254
397
      os << " LSB";
255
397
    }
256
461
    switch (this->ELFType) {
257
0
      case cmELF::FileTypeInvalid:
258
0
        os << " invalid file";
259
0
        break;
260
30
      case cmELF::FileTypeRelocatableObject:
261
30
        os << " relocatable object";
262
30
        break;
263
150
      case cmELF::FileTypeExecutable:
264
150
        os << " executable";
265
150
        break;
266
161
      case cmELF::FileTypeSharedLibrary:
267
161
        os << " shared library";
268
161
        break;
269
22
      case cmELF::FileTypeCore:
270
22
        os << " core file";
271
22
        break;
272
20
      case cmELF::FileTypeSpecificOS:
273
20
        os << " os-specific type";
274
20
        break;
275
78
      case cmELF::FileTypeSpecificProc:
276
78
        os << " processor-specific type";
277
78
        break;
278
461
    }
279
461
    os << "\n";
280
461
  }
cmELFInternalImpl<cmELFTypes32>::PrintInfo(std::__1::basic_ostream<char, std::__1::char_traits<char> >&) const
Line
Count
Source
249
197
  {
250
197
    os << "ELF " << Types::GetName();
251
197
    if (this->ByteOrder == ByteOrderMSB) {
252
25
      os << " MSB";
253
172
    } else if (this->ByteOrder == ByteOrderLSB) {
254
172
      os << " LSB";
255
172
    }
256
197
    switch (this->ELFType) {
257
0
      case cmELF::FileTypeInvalid:
258
0
        os << " invalid file";
259
0
        break;
260
13
      case cmELF::FileTypeRelocatableObject:
261
13
        os << " relocatable object";
262
13
        break;
263
49
      case cmELF::FileTypeExecutable:
264
49
        os << " executable";
265
49
        break;
266
90
      case cmELF::FileTypeSharedLibrary:
267
90
        os << " shared library";
268
90
        break;
269
10
      case cmELF::FileTypeCore:
270
10
        os << " core file";
271
10
        break;
272
8
      case cmELF::FileTypeSpecificOS:
273
8
        os << " os-specific type";
274
8
        break;
275
27
      case cmELF::FileTypeSpecificProc:
276
27
        os << " processor-specific type";
277
27
        break;
278
197
    }
279
197
    os << "\n";
280
197
  }
cmELFInternalImpl<cmELFTypes64>::PrintInfo(std::__1::basic_ostream<char, std::__1::char_traits<char> >&) const
Line
Count
Source
249
264
  {
250
264
    os << "ELF " << Types::GetName();
251
264
    if (this->ByteOrder == ByteOrderMSB) {
252
39
      os << " MSB";
253
225
    } else if (this->ByteOrder == ByteOrderLSB) {
254
225
      os << " LSB";
255
225
    }
256
264
    switch (this->ELFType) {
257
0
      case cmELF::FileTypeInvalid:
258
0
        os << " invalid file";
259
0
        break;
260
17
      case cmELF::FileTypeRelocatableObject:
261
17
        os << " relocatable object";
262
17
        break;
263
101
      case cmELF::FileTypeExecutable:
264
101
        os << " executable";
265
101
        break;
266
71
      case cmELF::FileTypeSharedLibrary:
267
71
        os << " shared library";
268
71
        break;
269
12
      case cmELF::FileTypeCore:
270
12
        os << " core file";
271
12
        break;
272
12
      case cmELF::FileTypeSpecificOS:
273
12
        os << " os-specific type";
274
12
        break;
275
51
      case cmELF::FileTypeSpecificProc:
276
51
        os << " processor-specific type";
277
51
        break;
278
264
    }
279
264
    os << "\n";
280
264
  }
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
84
  {
288
84
    cmELFByteSwap(elf_header.e_type);
289
84
    cmELFByteSwap(elf_header.e_machine);
290
84
    cmELFByteSwap(elf_header.e_version);
291
84
    cmELFByteSwap(elf_header.e_entry);
292
84
    cmELFByteSwap(elf_header.e_phoff);
293
84
    cmELFByteSwap(elf_header.e_shoff);
294
84
    cmELFByteSwap(elf_header.e_flags);
295
84
    cmELFByteSwap(elf_header.e_ehsize);
296
84
    cmELFByteSwap(elf_header.e_phentsize);
297
84
    cmELFByteSwap(elf_header.e_phnum);
298
84
    cmELFByteSwap(elf_header.e_shentsize);
299
84
    cmELFByteSwap(elf_header.e_shnum);
300
84
    cmELFByteSwap(elf_header.e_shstrndx);
301
84
  }
cmELFInternalImpl<cmELFTypes64>::ByteSwap(Elf64_Ehdr&)
Line
Count
Source
287
264
  {
288
264
    cmELFByteSwap(elf_header.e_type);
289
264
    cmELFByteSwap(elf_header.e_machine);
290
264
    cmELFByteSwap(elf_header.e_version);
291
264
    cmELFByteSwap(elf_header.e_entry);
292
264
    cmELFByteSwap(elf_header.e_phoff);
293
264
    cmELFByteSwap(elf_header.e_shoff);
294
264
    cmELFByteSwap(elf_header.e_flags);
295
264
    cmELFByteSwap(elf_header.e_ehsize);
296
264
    cmELFByteSwap(elf_header.e_phentsize);
297
264
    cmELFByteSwap(elf_header.e_phnum);
298
264
    cmELFByteSwap(elf_header.e_shentsize);
299
264
    cmELFByteSwap(elf_header.e_shnum);
300
264
    cmELFByteSwap(elf_header.e_shstrndx);
301
264
  }
302
303
  void ByteSwap(ELF_Shdr& sec_header)
304
8.08M
  {
305
8.08M
    cmELFByteSwap(sec_header.sh_name);
306
8.08M
    cmELFByteSwap(sec_header.sh_type);
307
8.08M
    cmELFByteSwap(sec_header.sh_flags);
308
8.08M
    cmELFByteSwap(sec_header.sh_addr);
309
8.08M
    cmELFByteSwap(sec_header.sh_offset);
310
8.08M
    cmELFByteSwap(sec_header.sh_size);
311
8.08M
    cmELFByteSwap(sec_header.sh_link);
312
8.08M
    cmELFByteSwap(sec_header.sh_info);
313
8.08M
    cmELFByteSwap(sec_header.sh_addralign);
314
8.08M
    cmELFByteSwap(sec_header.sh_entsize);
315
8.08M
  }
cmELFInternalImpl<cmELFTypes32>::ByteSwap(Elf32_Shdr&)
Line
Count
Source
304
1.31M
  {
305
1.31M
    cmELFByteSwap(sec_header.sh_name);
306
1.31M
    cmELFByteSwap(sec_header.sh_type);
307
1.31M
    cmELFByteSwap(sec_header.sh_flags);
308
1.31M
    cmELFByteSwap(sec_header.sh_addr);
309
1.31M
    cmELFByteSwap(sec_header.sh_offset);
310
1.31M
    cmELFByteSwap(sec_header.sh_size);
311
1.31M
    cmELFByteSwap(sec_header.sh_link);
312
1.31M
    cmELFByteSwap(sec_header.sh_info);
313
1.31M
    cmELFByteSwap(sec_header.sh_addralign);
314
1.31M
    cmELFByteSwap(sec_header.sh_entsize);
315
1.31M
  }
cmELFInternalImpl<cmELFTypes64>::ByteSwap(Elf64_Shdr&)
Line
Count
Source
304
6.76M
  {
305
6.76M
    cmELFByteSwap(sec_header.sh_name);
306
6.76M
    cmELFByteSwap(sec_header.sh_type);
307
6.76M
    cmELFByteSwap(sec_header.sh_flags);
308
6.76M
    cmELFByteSwap(sec_header.sh_addr);
309
6.76M
    cmELFByteSwap(sec_header.sh_offset);
310
6.76M
    cmELFByteSwap(sec_header.sh_size);
311
6.76M
    cmELFByteSwap(sec_header.sh_link);
312
6.76M
    cmELFByteSwap(sec_header.sh_info);
313
6.76M
    cmELFByteSwap(sec_header.sh_addralign);
314
6.76M
    cmELFByteSwap(sec_header.sh_entsize);
315
6.76M
  }
316
317
  void ByteSwap(ELF_Dyn& dyn)
318
161k
  {
319
161k
    cmELFByteSwap(dyn.d_tag);
320
161k
    cmELFByteSwap(dyn.d_un.d_val);
321
161k
  }
cmELFInternalImpl<cmELFTypes32>::ByteSwap(Elf32_Dyn&)
Line
Count
Source
318
161k
  {
319
161k
    cmELFByteSwap(dyn.d_tag);
320
161k
    cmELFByteSwap(dyn.d_un.d_val);
321
161k
  }
Unexecuted instantiation: cmELFInternalImpl<cmELFTypes64>::ByteSwap(Elf64_Dyn&)
322
323
  bool FileTypeValid(ELF_Half et)
324
1.72k
  {
325
1.72k
    unsigned int eti = static_cast<unsigned int>(et);
326
1.72k
    if (eti == ET_NONE || eti == ET_REL || eti == ET_EXEC || eti == ET_DYN ||
327
921
        eti == ET_CORE) {
328
921
      return true;
329
921
    }
330
805
    if (eti >= ET_LOOS && eti <= ET_HIOS) {
331
39
      return true;
332
39
    }
333
766
    if (eti >= ET_LOPROC && eti <= ET_HIPROC) {
334
207
      return true;
335
207
    }
336
559
    return false;
337
766
  }
cmELFInternalImpl<cmELFTypes32>::FileTypeValid(unsigned short)
Line
Count
Source
324
569
  {
325
569
    unsigned int eti = static_cast<unsigned int>(et);
326
569
    if (eti == ET_NONE || eti == ET_REL || eti == ET_EXEC || eti == ET_DYN ||
327
356
        eti == ET_CORE) {
328
356
      return true;
329
356
    }
330
213
    if (eti >= ET_LOOS && eti <= ET_HIOS) {
331
19
      return true;
332
19
    }
333
194
    if (eti >= ET_LOPROC && eti <= ET_HIPROC) {
334
79
      return true;
335
79
    }
336
115
    return false;
337
194
  }
cmELFInternalImpl<cmELFTypes64>::FileTypeValid(unsigned short)
Line
Count
Source
324
1.15k
  {
325
1.15k
    unsigned int eti = static_cast<unsigned int>(et);
326
1.15k
    if (eti == ET_NONE || eti == ET_REL || eti == ET_EXEC || eti == ET_DYN ||
327
611
        eti == ET_CORE) {
328
565
      return true;
329
565
    }
330
592
    if (eti >= ET_LOOS && eti <= ET_HIOS) {
331
20
      return true;
332
20
    }
333
572
    if (eti >= ET_LOPROC && eti <= ET_HIPROC) {
334
128
      return true;
335
128
    }
336
444
    return false;
337
572
  }
338
339
  bool Read(ELF_Ehdr& x)
340
1.23k
  {
341
    // Read the header from the file.
342
1.23k
    if (!this->Stream->read(reinterpret_cast<char*>(&x), sizeof(x))) {
343
6
      return false;
344
6
    }
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.22k
    ELF_Half et = x.e_type;
353
1.22k
    if (this->NeedSwap) {
354
203
      cmELFByteSwap(et);
355
203
    }
356
1.22k
    if (!this->FileTypeValid(et)) {
357
502
      cmELFByteSwap(et);
358
502
      if (this->FileTypeValid(et)) {
359
        // The previous byte order guess was wrong.  Flip it.
360
445
        this->NeedSwap = !this->NeedSwap;
361
445
      }
362
502
    }
363
364
    // Fix the byte order of the header.
365
1.22k
    if (this->NeedSwap) {
366
348
      this->ByteSwap(x);
367
348
    }
368
1.22k
    return true;
369
1.23k
  }
cmELFInternalImpl<cmELFTypes32>::Read(Elf32_Ehdr&)
Line
Count
Source
340
485
  {
341
    // Read the header from the file.
342
485
    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
482
    ELF_Half et = x.e_type;
353
482
    if (this->NeedSwap) {
354
47
      cmELFByteSwap(et);
355
47
    }
356
482
    if (!this->FileTypeValid(et)) {
357
87
      cmELFByteSwap(et);
358
87
      if (this->FileTypeValid(et)) {
359
        // The previous byte order guess was wrong.  Flip it.
360
59
        this->NeedSwap = !this->NeedSwap;
361
59
      }
362
87
    }
363
364
    // Fix the byte order of the header.
365
482
    if (this->NeedSwap) {
366
84
      this->ByteSwap(x);
367
84
    }
368
482
    return true;
369
485
  }
cmELFInternalImpl<cmELFTypes64>::Read(Elf64_Ehdr&)
Line
Count
Source
340
745
  {
341
    // Read the header from the file.
342
745
    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
742
    ELF_Half et = x.e_type;
353
742
    if (this->NeedSwap) {
354
156
      cmELFByteSwap(et);
355
156
    }
356
742
    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
386
        this->NeedSwap = !this->NeedSwap;
361
386
      }
362
415
    }
363
364
    // Fix the byte order of the header.
365
742
    if (this->NeedSwap) {
366
264
      this->ByteSwap(x);
367
264
    }
368
742
    return true;
369
745
  }
370
  bool Read(ELF_Shdr& x)
371
27.3M
  {
372
27.3M
    if (this->Stream->read(reinterpret_cast<char*>(&x), sizeof(x)) &&
373
27.3M
        this->NeedSwap) {
374
8.08M
      this->ByteSwap(x);
375
8.08M
    }
376
27.3M
    return !this->Stream->fail();
377
27.3M
  }
cmELFInternalImpl<cmELFTypes32>::Read(Elf32_Shdr&)
Line
Count
Source
371
14.0M
  {
372
14.0M
    if (this->Stream->read(reinterpret_cast<char*>(&x), sizeof(x)) &&
373
14.0M
        this->NeedSwap) {
374
1.31M
      this->ByteSwap(x);
375
1.31M
    }
376
14.0M
    return !this->Stream->fail();
377
14.0M
  }
cmELFInternalImpl<cmELFTypes64>::Read(Elf64_Shdr&)
Line
Count
Source
371
13.3M
  {
372
13.3M
    if (this->Stream->read(reinterpret_cast<char*>(&x), sizeof(x)) &&
373
13.3M
        this->NeedSwap) {
374
6.76M
      this->ByteSwap(x);
375
6.76M
    }
376
13.3M
    return !this->Stream->fail();
377
13.3M
  }
378
  bool Read(ELF_Dyn& x)
379
1.37M
  {
380
1.37M
    if (this->Stream->read(reinterpret_cast<char*>(&x), sizeof(x)) &&
381
1.37M
        this->NeedSwap) {
382
81.3k
      this->ByteSwap(x);
383
81.3k
    }
384
1.37M
    return !this->Stream->fail();
385
1.37M
  }
cmELFInternalImpl<cmELFTypes32>::Read(Elf32_Dyn&)
Line
Count
Source
379
1.22M
  {
380
1.22M
    if (this->Stream->read(reinterpret_cast<char*>(&x), sizeof(x)) &&
381
1.22M
        this->NeedSwap) {
382
81.3k
      this->ByteSwap(x);
383
81.3k
    }
384
1.22M
    return !this->Stream->fail();
385
1.22M
  }
cmELFInternalImpl<cmELFTypes64>::Read(Elf64_Dyn&)
Line
Count
Source
379
147k
  {
380
147k
    if (this->Stream->read(reinterpret_cast<char*>(&x), sizeof(x)) &&
381
147k
        this->NeedSwap) {
382
0
      this->ByteSwap(x);
383
0
    }
384
147k
    return !this->Stream->fail();
385
147k
  }
386
387
  bool LoadSectionHeader(std::size_t i)
388
27.3M
  {
389
    // Read the section header from the file.
390
27.3M
    this->Stream->seekg(this->ELFHeader.e_shoff +
391
27.3M
                        this->ELFHeader.e_shentsize * i);
392
27.3M
    if (!this->Read(this->SectionHeaders[i])) {
393
181
      this->SetErrorMessage("Failed to load section headers.");
394
181
      return false;
395
181
    }
396
397
    // Identify some important sections.
398
27.3M
    if (this->SectionHeaders[i].sh_type == SHT_DYNAMIC) {
399
21.2M
      this->DynamicSectionIndex = static_cast<int>(i);
400
21.2M
    }
401
27.3M
    return true;
402
27.3M
  }
cmELFInternalImpl<cmELFTypes32>::LoadSectionHeader(unsigned long)
Line
Count
Source
388
14.0M
  {
389
    // Read the section header from the file.
390
14.0M
    this->Stream->seekg(this->ELFHeader.e_shoff +
391
14.0M
                        this->ELFHeader.e_shentsize * i);
392
14.0M
    if (!this->Read(this->SectionHeaders[i])) {
393
58
      this->SetErrorMessage("Failed to load section headers.");
394
58
      return false;
395
58
    }
396
397
    // Identify some important sections.
398
14.0M
    if (this->SectionHeaders[i].sh_type == SHT_DYNAMIC) {
399
11.4M
      this->DynamicSectionIndex = static_cast<int>(i);
400
11.4M
    }
401
14.0M
    return true;
402
14.0M
  }
cmELFInternalImpl<cmELFTypes64>::LoadSectionHeader(unsigned long)
Line
Count
Source
388
13.3M
  {
389
    // Read the section header from the file.
390
13.3M
    this->Stream->seekg(this->ELFHeader.e_shoff +
391
13.3M
                        this->ELFHeader.e_shentsize * i);
392
13.3M
    if (!this->Read(this->SectionHeaders[i])) {
393
123
      this->SetErrorMessage("Failed to load section headers.");
394
123
      return false;
395
123
    }
396
397
    // Identify some important sections.
398
13.3M
    if (this->SectionHeaders[i].sh_type == SHT_DYNAMIC) {
399
9.81M
      this->DynamicSectionIndex = static_cast<int>(i);
400
9.81M
    }
401
13.3M
    return true;
402
13.3M
  }
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.23k
  : cmELFInternal(external, std::move(fin), order)
421
1.23k
{
422
  // Read the main header.
423
1.23k
  if (!this->Read(this->ELFHeader)) {
424
6
    this->SetErrorMessage("Failed to read main ELF header.");
425
6
    return;
426
6
  }
427
428
  // Determine the ELF file type.
429
1.22k
  switch (this->ELFHeader.e_type) {
430
2
    case ET_NONE:
431
2
      this->SetErrorMessage("ELF file type is NONE.");
432
2
      return;
433
50
    case ET_REL:
434
50
      this->ELFType = cmELF::FileTypeRelocatableObject;
435
50
      break;
436
402
    case ET_EXEC:
437
402
      this->ELFType = cmELF::FileTypeExecutable;
438
402
      break;
439
434
    case ET_DYN:
440
434
      this->ELFType = cmELF::FileTypeSharedLibrary;
441
434
      break;
442
33
    case ET_CORE:
443
33
      this->ELFType = cmELF::FileTypeCore;
444
33
      break;
445
303
    default: {
446
303
      unsigned int eti = static_cast<unsigned int>(this->ELFHeader.e_type);
447
303
      if (eti >= ET_LOOS && eti <= ET_HIOS) {
448
39
        this->ELFType = cmELF::FileTypeSpecificOS;
449
39
        break;
450
39
      }
451
264
      if (eti >= ET_LOPROC && eti <= ET_HIPROC) {
452
207
        this->ELFType = cmELF::FileTypeSpecificProc;
453
207
        break;
454
207
      }
455
57
      std::ostringstream e;
456
57
      e << "Unknown ELF file type " << eti;
457
57
      this->SetErrorMessage(e.str().c_str());
458
57
      return;
459
264
    }
460
1.22k
  }
461
462
1.16k
  this->Machine = this->ELFHeader.e_machine;
463
464
  // Load the section headers.
465
1.16k
  std::size_t const minSections = 1;
466
1.16k
  std::size_t numSections = this->ELFHeader.e_shnum;
467
  // Prevent OOM from malformed files.
468
1.16k
  if (numSections > kMaxSections) {
469
0
    this->SetErrorMessage("ELF file has too many sections.");
470
0
    return;
471
0
  }
472
1.16k
  this->SectionHeaders.resize(std::max(numSections, minSections));
473
1.16k
  if (!this->LoadSectionHeader(0)) {
474
32
    return;
475
32
  }
476
1.13k
  numSections = this->GetNumberOfSections();
477
1.13k
  this->SectionHeaders.resize(std::max(numSections, minSections));
478
27.3M
  for (std::size_t i = 1; i < numSections; ++i) {
479
27.3M
    if (!this->LoadSectionHeader(i)) {
480
149
      return;
481
149
    }
482
27.3M
  }
483
1.13k
}
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
485
  : cmELFInternal(external, std::move(fin), order)
421
485
{
422
  // Read the main header.
423
485
  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
482
  switch (this->ELFHeader.e_type) {
430
1
    case ET_NONE:
431
1
      this->SetErrorMessage("ELF file type is NONE.");
432
1
      return;
433
18
    case ET_REL:
434
18
      this->ELFType = cmELF::FileTypeRelocatableObject;
435
18
      break;
436
130
    case ET_EXEC:
437
130
      this->ELFType = cmELF::FileTypeExecutable;
438
130
      break;
439
193
    case ET_DYN:
440
193
      this->ELFType = cmELF::FileTypeSharedLibrary;
441
193
      break;
442
14
    case ET_CORE:
443
14
      this->ELFType = cmELF::FileTypeCore;
444
14
      break;
445
126
    default: {
446
126
      unsigned int eti = static_cast<unsigned int>(this->ELFHeader.e_type);
447
126
      if (eti >= ET_LOOS && eti <= ET_HIOS) {
448
19
        this->ELFType = cmELF::FileTypeSpecificOS;
449
19
        break;
450
19
      }
451
107
      if (eti >= ET_LOPROC && eti <= ET_HIPROC) {
452
79
        this->ELFType = cmELF::FileTypeSpecificProc;
453
79
        break;
454
79
      }
455
28
      std::ostringstream e;
456
28
      e << "Unknown ELF file type " << eti;
457
28
      this->SetErrorMessage(e.str().c_str());
458
28
      return;
459
107
    }
460
482
  }
461
462
453
  this->Machine = this->ELFHeader.e_machine;
463
464
  // Load the section headers.
465
453
  std::size_t const minSections = 1;
466
453
  std::size_t numSections = this->ELFHeader.e_shnum;
467
  // Prevent OOM from malformed files.
468
453
  if (numSections > kMaxSections) {
469
0
    this->SetErrorMessage("ELF file has too many sections.");
470
0
    return;
471
0
  }
472
453
  this->SectionHeaders.resize(std::max(numSections, minSections));
473
453
  if (!this->LoadSectionHeader(0)) {
474
15
    return;
475
15
  }
476
438
  numSections = this->GetNumberOfSections();
477
438
  this->SectionHeaders.resize(std::max(numSections, minSections));
478
14.0M
  for (std::size_t i = 1; i < numSections; ++i) {
479
14.0M
    if (!this->LoadSectionHeader(i)) {
480
43
      return;
481
43
    }
482
14.0M
  }
483
438
}
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
745
  : cmELFInternal(external, std::move(fin), order)
421
745
{
422
  // Read the main header.
423
745
  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
742
  switch (this->ELFHeader.e_type) {
430
1
    case ET_NONE:
431
1
      this->SetErrorMessage("ELF file type is NONE.");
432
1
      return;
433
32
    case ET_REL:
434
32
      this->ELFType = cmELF::FileTypeRelocatableObject;
435
32
      break;
436
272
    case ET_EXEC:
437
272
      this->ELFType = cmELF::FileTypeExecutable;
438
272
      break;
439
241
    case ET_DYN:
440
241
      this->ELFType = cmELF::FileTypeSharedLibrary;
441
241
      break;
442
19
    case ET_CORE:
443
19
      this->ELFType = cmELF::FileTypeCore;
444
19
      break;
445
177
    default: {
446
177
      unsigned int eti = static_cast<unsigned int>(this->ELFHeader.e_type);
447
177
      if (eti >= ET_LOOS && eti <= ET_HIOS) {
448
20
        this->ELFType = cmELF::FileTypeSpecificOS;
449
20
        break;
450
20
      }
451
157
      if (eti >= ET_LOPROC && eti <= ET_HIPROC) {
452
128
        this->ELFType = cmELF::FileTypeSpecificProc;
453
128
        break;
454
128
      }
455
29
      std::ostringstream e;
456
29
      e << "Unknown ELF file type " << eti;
457
29
      this->SetErrorMessage(e.str().c_str());
458
29
      return;
459
157
    }
460
742
  }
461
462
712
  this->Machine = this->ELFHeader.e_machine;
463
464
  // Load the section headers.
465
712
  std::size_t const minSections = 1;
466
712
  std::size_t numSections = this->ELFHeader.e_shnum;
467
  // Prevent OOM from malformed files.
468
712
  if (numSections > kMaxSections) {
469
0
    this->SetErrorMessage("ELF file has too many sections.");
470
0
    return;
471
0
  }
472
712
  this->SectionHeaders.resize(std::max(numSections, minSections));
473
712
  if (!this->LoadSectionHeader(0)) {
474
17
    return;
475
17
  }
476
695
  numSections = this->GetNumberOfSections();
477
695
  this->SectionHeaders.resize(std::max(numSections, minSections));
478
13.3M
  for (std::size_t i = 1; i < numSections; ++i) {
479
13.3M
    if (!this->LoadSectionHeader(i)) {
480
106
      return;
481
106
    }
482
13.3M
  }
483
695
}
484
485
template <class Types>
486
bool cmELFInternalImpl<Types>::LoadDynamicSection()
487
10.1k
{
488
  // If there is no dynamic section we are done.
489
10.1k
  if (!this->HasDynamicSection()) {
490
255
    return false;
491
255
  }
492
493
  // If the section was already loaded we are done.
494
9.87k
  if (!this->DynamicSectionEntries.empty()) {
495
8.79k
    return true;
496
8.79k
  }
497
498
  // If there are no entries we are done.
499
1.07k
  ELF_Shdr const& sec = this->SectionHeaders[this->DynamicSectionIndex];
500
1.07k
  if (sec.sh_entsize == 0) {
501
17
    return false;
502
17
  }
503
504
  // Prevent OOM from malformed files.
505
1.06k
  if (sec.sh_size > kMaxSectionSize) {
506
98
    this->SetErrorMessage("DYNAMIC section is too large.");
507
98
    return false;
508
98
  }
509
510
  // Allocate the dynamic section entries.
511
962
  std::size_t n = static_cast<int>(sec.sh_size / sec.sh_entsize);
512
  // Prevent OOM from malformed files.
513
962
  if (n > kMaxDynamicEntries) {
514
18
    this->SetErrorMessage("DYNAMIC section has too many entries.");
515
18
    return false;
516
18
  }
517
944
  this->DynamicSectionEntries.resize(n);
518
519
  // Read each entry.
520
1.37M
  for (std::size_t j = 0; j < n; ++j) {
521
    // Seek to the beginning of the section entry.
522
1.37M
    this->Stream->seekg(sec.sh_offset + sec.sh_entsize * j);
523
1.37M
    ELF_Dyn& dyn = this->DynamicSectionEntries[j];
524
525
    // Try reading the entry.
526
1.37M
    if (!this->Read(dyn)) {
527
88
      this->SetErrorMessage("Error reading entry from DYNAMIC section.");
528
88
      this->DynamicSectionIndex = -1;
529
88
      return false;
530
88
    }
531
1.37M
  }
532
856
  return true;
533
944
}
cmELFInternalImpl<cmELFTypes32>::LoadDynamicSection()
Line
Count
Source
487
5.67k
{
488
  // If there is no dynamic section we are done.
489
5.67k
  if (!this->HasDynamicSection()) {
490
123
    return false;
491
123
  }
492
493
  // If the section was already loaded we are done.
494
5.55k
  if (!this->DynamicSectionEntries.empty()) {
495
5.14k
    return true;
496
5.14k
  }
497
498
  // If there are no entries we are done.
499
411
  ELF_Shdr const& sec = this->SectionHeaders[this->DynamicSectionIndex];
500
411
  if (sec.sh_entsize == 0) {
501
8
    return false;
502
8
  }
503
504
  // Prevent OOM from malformed files.
505
403
  if (sec.sh_size > kMaxSectionSize) {
506
18
    this->SetErrorMessage("DYNAMIC section is too large.");
507
18
    return false;
508
18
  }
509
510
  // Allocate the dynamic section entries.
511
385
  std::size_t n = static_cast<int>(sec.sh_size / sec.sh_entsize);
512
  // Prevent OOM from malformed files.
513
385
  if (n > kMaxDynamicEntries) {
514
11
    this->SetErrorMessage("DYNAMIC section has too many entries.");
515
11
    return false;
516
11
  }
517
374
  this->DynamicSectionEntries.resize(n);
518
519
  // Read each entry.
520
1.22M
  for (std::size_t j = 0; j < n; ++j) {
521
    // Seek to the beginning of the section entry.
522
1.22M
    this->Stream->seekg(sec.sh_offset + sec.sh_entsize * j);
523
1.22M
    ELF_Dyn& dyn = this->DynamicSectionEntries[j];
524
525
    // Try reading the entry.
526
1.22M
    if (!this->Read(dyn)) {
527
54
      this->SetErrorMessage("Error reading entry from DYNAMIC section.");
528
54
      this->DynamicSectionIndex = -1;
529
54
      return false;
530
54
    }
531
1.22M
  }
532
320
  return true;
533
374
}
cmELFInternalImpl<cmELFTypes64>::LoadDynamicSection()
Line
Count
Source
487
4.44k
{
488
  // If there is no dynamic section we are done.
489
4.44k
  if (!this->HasDynamicSection()) {
490
132
    return false;
491
132
  }
492
493
  // If the section was already loaded we are done.
494
4.31k
  if (!this->DynamicSectionEntries.empty()) {
495
3.65k
    return true;
496
3.65k
  }
497
498
  // If there are no entries we are done.
499
666
  ELF_Shdr const& sec = this->SectionHeaders[this->DynamicSectionIndex];
500
666
  if (sec.sh_entsize == 0) {
501
9
    return false;
502
9
  }
503
504
  // Prevent OOM from malformed files.
505
657
  if (sec.sh_size > kMaxSectionSize) {
506
80
    this->SetErrorMessage("DYNAMIC section is too large.");
507
80
    return false;
508
80
  }
509
510
  // Allocate the dynamic section entries.
511
577
  std::size_t n = static_cast<int>(sec.sh_size / sec.sh_entsize);
512
  // Prevent OOM from malformed files.
513
577
  if (n > kMaxDynamicEntries) {
514
7
    this->SetErrorMessage("DYNAMIC section has too many entries.");
515
7
    return false;
516
7
  }
517
570
  this->DynamicSectionEntries.resize(n);
518
519
  // Read each entry.
520
148k
  for (std::size_t j = 0; j < n; ++j) {
521
    // Seek to the beginning of the section entry.
522
147k
    this->Stream->seekg(sec.sh_offset + sec.sh_entsize * j);
523
147k
    ELF_Dyn& dyn = this->DynamicSectionEntries[j];
524
525
    // Try reading the entry.
526
147k
    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
147k
  }
532
536
  return true;
533
570
}
534
535
template <class Types>
536
unsigned long cmELFInternalImpl<Types>::GetDynamicEntryPosition(int j)
537
8.23k
{
538
8.23k
  if (!this->LoadDynamicSection()) {
539
0
    return 0;
540
0
  }
541
8.23k
  if (j < 0 || j >= static_cast<int>(this->DynamicSectionEntries.size())) {
542
0
    return 0;
543
0
  }
544
8.23k
  ELF_Shdr const& sec = this->SectionHeaders[this->DynamicSectionIndex];
545
8.23k
  return sec.sh_offset + sec.sh_entsize * static_cast<unsigned long>(j);
546
8.23k
}
cmELFInternalImpl<cmELFTypes32>::GetDynamicEntryPosition(int)
Line
Count
Source
537
4.90k
{
538
4.90k
  if (!this->LoadDynamicSection()) {
539
0
    return 0;
540
0
  }
541
4.90k
  if (j < 0 || j >= static_cast<int>(this->DynamicSectionEntries.size())) {
542
0
    return 0;
543
0
  }
544
4.90k
  ELF_Shdr const& sec = this->SectionHeaders[this->DynamicSectionIndex];
545
4.90k
  return sec.sh_offset + sec.sh_entsize * static_cast<unsigned long>(j);
546
4.90k
}
cmELFInternalImpl<cmELFTypes64>::GetDynamicEntryPosition(int)
Line
Count
Source
537
3.33k
{
538
3.33k
  if (!this->LoadDynamicSection()) {
539
0
    return 0;
540
0
  }
541
3.33k
  if (j < 0 || j >= static_cast<int>(this->DynamicSectionEntries.size())) {
542
0
    return 0;
543
0
  }
544
3.33k
  ELF_Shdr const& sec = this->SectionHeaders[this->DynamicSectionIndex];
545
3.33k
  return sec.sh_offset + sec.sh_entsize * static_cast<unsigned long>(j);
546
3.33k
}
547
548
template <class Types>
549
cmELF::DynamicEntryList cmELFInternalImpl<Types>::GetDynamicEntries()
550
528
{
551
528
  cmELF::DynamicEntryList result;
552
553
  // Ensure entries have been read from file
554
528
  if (!this->LoadDynamicSection()) {
555
212
    return result;
556
212
  }
557
558
  // Copy into public array
559
316
  result.reserve(this->DynamicSectionEntries.size());
560
1.10M
  for (ELF_Dyn& dyn : this->DynamicSectionEntries) {
561
1.10M
    result.emplace_back(dyn.d_tag, dyn.d_un.d_val);
562
1.10M
  }
563
564
316
  return result;
565
528
}
cmELFInternalImpl<cmELFTypes32>::GetDynamicEntries()
Line
Count
Source
550
227
{
551
227
  cmELF::DynamicEntryList result;
552
553
  // Ensure entries have been read from file
554
227
  if (!this->LoadDynamicSection()) {
555
90
    return result;
556
90
  }
557
558
  // Copy into public array
559
137
  result.reserve(this->DynamicSectionEntries.size());
560
962k
  for (ELF_Dyn& dyn : this->DynamicSectionEntries) {
561
962k
    result.emplace_back(dyn.d_tag, dyn.d_un.d_val);
562
962k
  }
563
564
137
  return result;
565
227
}
cmELFInternalImpl<cmELFTypes64>::GetDynamicEntries()
Line
Count
Source
550
301
{
551
301
  cmELF::DynamicEntryList result;
552
553
  // Ensure entries have been read from file
554
301
  if (!this->LoadDynamicSection()) {
555
122
    return result;
556
122
  }
557
558
  // Copy into public array
559
179
  result.reserve(this->DynamicSectionEntries.size());
560
142k
  for (ELF_Dyn& dyn : this->DynamicSectionEntries) {
561
142k
    result.emplace_back(dyn.d_tag, dyn.d_un.d_val);
562
142k
  }
563
564
179
  return result;
565
301
}
566
567
template <class Types>
568
std::vector<char> cmELFInternalImpl<Types>::EncodeDynamicEntries(
569
  cmELF::DynamicEntryList const& entries)
570
186
{
571
186
  std::vector<char> result;
572
186
  result.reserve(sizeof(ELF_Dyn) * entries.size());
573
574
1.10M
  for (auto const& entry : entries) {
575
    // Store the entry in an ELF_Dyn, byteswap it, then serialize to chars
576
1.10M
    ELF_Dyn dyn;
577
1.10M
    dyn.d_tag = static_cast<tagtype>(entry.first);
578
1.10M
    dyn.d_un.d_val = static_cast<tagtype>(entry.second);
579
580
1.10M
    if (this->NeedSwap) {
581
80.6k
      this->ByteSwap(dyn);
582
80.6k
    }
583
584
1.10M
    char* pdyn = reinterpret_cast<char*>(&dyn);
585
1.10M
    cm::append(result, pdyn, pdyn + sizeof(ELF_Dyn));
586
1.10M
  }
587
588
186
  return result;
589
186
}
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
101
{
571
101
  std::vector<char> result;
572
101
  result.reserve(sizeof(ELF_Dyn) * entries.size());
573
574
962k
  for (auto const& entry : entries) {
575
    // Store the entry in an ELF_Dyn, byteswap it, then serialize to chars
576
962k
    ELF_Dyn dyn;
577
962k
    dyn.d_tag = static_cast<tagtype>(entry.first);
578
962k
    dyn.d_un.d_val = static_cast<tagtype>(entry.second);
579
580
962k
    if (this->NeedSwap) {
581
80.6k
      this->ByteSwap(dyn);
582
80.6k
    }
583
584
962k
    char* pdyn = reinterpret_cast<char*>(&dyn);
585
962k
    cm::append(result, pdyn, pdyn + sizeof(ELF_Dyn));
586
962k
  }
587
588
101
  return result;
589
101
}
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
85
{
571
85
  std::vector<char> result;
572
85
  result.reserve(sizeof(ELF_Dyn) * entries.size());
573
574
142k
  for (auto const& entry : entries) {
575
    // Store the entry in an ELF_Dyn, byteswap it, then serialize to chars
576
142k
    ELF_Dyn dyn;
577
142k
    dyn.d_tag = static_cast<tagtype>(entry.first);
578
142k
    dyn.d_un.d_val = static_cast<tagtype>(entry.second);
579
580
142k
    if (this->NeedSwap) {
581
0
      this->ByteSwap(dyn);
582
0
    }
583
584
142k
    char* pdyn = reinterpret_cast<char*>(&dyn);
585
142k
    cm::append(result, pdyn, pdyn + sizeof(ELF_Dyn));
586
142k
  }
587
588
85
  return result;
589
85
}
590
591
template <class Types>
592
cmELF::StringEntry const* cmELFInternalImpl<Types>::GetDynamicSectionString(
593
  unsigned int tag)
594
1.62k
{
595
  // Short-circuit if already checked.
596
1.62k
  auto dssi = this->DynamicSectionStrings.find(tag);
597
1.62k
  if (dssi != this->DynamicSectionStrings.end()) {
598
266
    if (dssi->second.Position > 0) {
599
65
      return &dssi->second;
600
65
    }
601
201
    return nullptr;
602
266
  }
603
604
  // Create an entry for this tag.  Assume it is missing until found.
605
1.36k
  StringEntry& se = this->DynamicSectionStrings[tag];
606
1.36k
  se.Position = 0;
607
1.36k
  se.Size = 0;
608
1.36k
  se.IndexInSection = -1;
609
610
  // Try reading the dynamic section.
611
1.36k
  if (!this->LoadDynamicSection()) {
612
264
    return nullptr;
613
264
  }
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
134
    this->SetErrorMessage("Section DYNAMIC has invalid string table index.");
619
134
    return nullptr;
620
134
  }
621
965
  ELF_Shdr const& strtab = this->SectionHeaders[sec.sh_link];
622
623
  // Look for the requested entry.
624
965
  for (auto di = this->DynamicSectionEntries.begin();
625
1.01M
       di != this->DynamicSectionEntries.end(); ++di) {
626
1.00M
    ELF_Dyn& dyn = *di;
627
1.00M
    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
339
      if (dyn.d_un.d_val >= strtab.sh_size) {
631
157
        this->SetErrorMessage("Section DYNAMIC references string beyond "
632
157
                              "the end of its string section.");
633
157
        return nullptr;
634
157
      }
635
636
      // Seek to the position reported by the entry.
637
182
      unsigned long first = static_cast<unsigned long>(dyn.d_un.d_val);
638
182
      unsigned long last = first;
639
182
      unsigned long end = static_cast<unsigned long>(strtab.sh_size);
640
182
      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
182
      bool terminated = false;
648
182
      char c;
649
543k
      while (last != end && this->Stream->get(c) && !(terminated && c)) {
650
543k
        ++last;
651
543k
        if (c) {
652
542k
          se.Value += c;
653
542k
        } else {
654
1.02k
          terminated = true;
655
1.02k
        }
656
543k
      }
657
658
      // Make sure the whole value was read.
659
182
      if (!(*this->Stream)) {
660
28
        if (tag == cmELF::TagRPath) {
661
18
          this->SetErrorMessage(
662
18
            "Dynamic section specifies unreadable DT_RPATH");
663
18
        } else if (tag == cmELF::TagRunPath) {
664
4
          this->SetErrorMessage(
665
4
            "Dynamic section specifies unreadable DT_RUNPATH");
666
6
        } else if (tag == cmELF::TagMipsRldMapRel) {
667
0
          this->SetErrorMessage(
668
0
            "Dynamic section specifies unreadable DT_MIPS_RLD_MAP_REL");
669
6
        } else {
670
6
          this->SetErrorMessage("Dynamic section specifies unreadable value"
671
6
                                " for unexpected attribute");
672
6
        }
673
28
        se.Value = "";
674
28
        return nullptr;
675
28
      }
676
677
      // The value has been read successfully.  Report it.
678
154
      se.Position = static_cast<unsigned long>(strtab.sh_offset + first);
679
154
      se.Size = last - first;
680
154
      se.IndexInSection =
681
154
        static_cast<int>(di - this->DynamicSectionEntries.begin());
682
154
      return &se;
683
182
    }
684
1.00M
  }
685
626
  return nullptr;
686
965
}
cmELFInternalImpl<cmELFTypes32>::GetDynamicSectionString(unsigned int)
Line
Count
Source
594
649
{
595
  // Short-circuit if already checked.
596
649
  auto dssi = this->DynamicSectionStrings.find(tag);
597
649
  if (dssi != this->DynamicSectionStrings.end()) {
598
99
    if (dssi->second.Position > 0) {
599
34
      return &dssi->second;
600
34
    }
601
65
    return nullptr;
602
99
  }
603
604
  // Create an entry for this tag.  Assume it is missing until found.
605
550
  StringEntry& se = this->DynamicSectionStrings[tag];
606
550
  se.Position = 0;
607
550
  se.Size = 0;
608
550
  se.IndexInSection = -1;
609
610
  // Try reading the dynamic section.
611
550
  if (!this->LoadDynamicSection()) {
612
124
    return nullptr;
613
124
  }
614
615
  // Get the string table referenced by the DYNAMIC section.
616
426
  ELF_Shdr const& sec = this->SectionHeaders[this->DynamicSectionIndex];
617
426
  if (sec.sh_link >= this->SectionHeaders.size()) {
618
52
    this->SetErrorMessage("Section DYNAMIC has invalid string table index.");
619
52
    return nullptr;
620
52
  }
621
374
  ELF_Shdr const& strtab = this->SectionHeaders[sec.sh_link];
622
623
  // Look for the requested entry.
624
374
  for (auto di = this->DynamicSectionEntries.begin();
625
616k
       di != this->DynamicSectionEntries.end(); ++di) {
626
615k
    ELF_Dyn& dyn = *di;
627
615k
    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
140
      if (dyn.d_un.d_val >= strtab.sh_size) {
631
54
        this->SetErrorMessage("Section DYNAMIC references string beyond "
632
54
                              "the end of its string section.");
633
54
        return nullptr;
634
54
      }
635
636
      // Seek to the position reported by the entry.
637
86
      unsigned long first = static_cast<unsigned long>(dyn.d_un.d_val);
638
86
      unsigned long last = first;
639
86
      unsigned long end = static_cast<unsigned long>(strtab.sh_size);
640
86
      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
86
      bool terminated = false;
648
86
      char c;
649
542k
      while (last != end && this->Stream->get(c) && !(terminated && c)) {
650
542k
        ++last;
651
542k
        if (c) {
652
542k
          se.Value += c;
653
542k
        } else {
654
547
          terminated = true;
655
547
        }
656
542k
      }
657
658
      // Make sure the whole value was read.
659
86
      if (!(*this->Stream)) {
660
9
        if (tag == cmELF::TagRPath) {
661
7
          this->SetErrorMessage(
662
7
            "Dynamic section specifies unreadable DT_RPATH");
663
7
        } else if (tag == cmELF::TagRunPath) {
664
1
          this->SetErrorMessage(
665
1
            "Dynamic section specifies unreadable DT_RUNPATH");
666
1
        } else if (tag == cmELF::TagMipsRldMapRel) {
667
0
          this->SetErrorMessage(
668
0
            "Dynamic section specifies unreadable DT_MIPS_RLD_MAP_REL");
669
1
        } else {
670
1
          this->SetErrorMessage("Dynamic section specifies unreadable value"
671
1
                                " for unexpected attribute");
672
1
        }
673
9
        se.Value = "";
674
9
        return nullptr;
675
9
      }
676
677
      // The value has been read successfully.  Report it.
678
77
      se.Position = static_cast<unsigned long>(strtab.sh_offset + first);
679
77
      se.Size = last - first;
680
77
      se.IndexInSection =
681
77
        static_cast<int>(di - this->DynamicSectionEntries.begin());
682
77
      return &se;
683
86
    }
684
615k
  }
685
234
  return nullptr;
686
374
}
cmELFInternalImpl<cmELFTypes64>::GetDynamicSectionString(unsigned int)
Line
Count
Source
594
980
{
595
  // Short-circuit if already checked.
596
980
  auto dssi = this->DynamicSectionStrings.find(tag);
597
980
  if (dssi != this->DynamicSectionStrings.end()) {
598
167
    if (dssi->second.Position > 0) {
599
31
      return &dssi->second;
600
31
    }
601
136
    return nullptr;
602
167
  }
603
604
  // Create an entry for this tag.  Assume it is missing until found.
605
813
  StringEntry& se = this->DynamicSectionStrings[tag];
606
813
  se.Position = 0;
607
813
  se.Size = 0;
608
813
  se.IndexInSection = -1;
609
610
  // Try reading the dynamic section.
611
813
  if (!this->LoadDynamicSection()) {
612
140
    return nullptr;
613
140
  }
614
615
  // Get the string table referenced by the DYNAMIC section.
616
673
  ELF_Shdr const& sec = this->SectionHeaders[this->DynamicSectionIndex];
617
673
  if (sec.sh_link >= this->SectionHeaders.size()) {
618
82
    this->SetErrorMessage("Section DYNAMIC has invalid string table index.");
619
82
    return nullptr;
620
82
  }
621
591
  ELF_Shdr const& strtab = this->SectionHeaders[sec.sh_link];
622
623
  // Look for the requested entry.
624
591
  for (auto di = this->DynamicSectionEntries.begin();
625
393k
       di != this->DynamicSectionEntries.end(); ++di) {
626
393k
    ELF_Dyn& dyn = *di;
627
393k
    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
199
      if (dyn.d_un.d_val >= strtab.sh_size) {
631
103
        this->SetErrorMessage("Section DYNAMIC references string beyond "
632
103
                              "the end of its string section.");
633
103
        return nullptr;
634
103
      }
635
636
      // Seek to the position reported by the entry.
637
96
      unsigned long first = static_cast<unsigned long>(dyn.d_un.d_val);
638
96
      unsigned long last = first;
639
96
      unsigned long end = static_cast<unsigned long>(strtab.sh_size);
640
96
      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
96
      bool terminated = false;
648
96
      char c;
649
1.13k
      while (last != end && this->Stream->get(c) && !(terminated && c)) {
650
1.03k
        ++last;
651
1.03k
        if (c) {
652
558
          se.Value += c;
653
558
        } else {
654
477
          terminated = true;
655
477
        }
656
1.03k
      }
657
658
      // Make sure the whole value was read.
659
96
      if (!(*this->Stream)) {
660
19
        if (tag == cmELF::TagRPath) {
661
11
          this->SetErrorMessage(
662
11
            "Dynamic section specifies unreadable DT_RPATH");
663
11
        } else if (tag == cmELF::TagRunPath) {
664
3
          this->SetErrorMessage(
665
3
            "Dynamic section specifies unreadable DT_RUNPATH");
666
5
        } else if (tag == cmELF::TagMipsRldMapRel) {
667
0
          this->SetErrorMessage(
668
0
            "Dynamic section specifies unreadable DT_MIPS_RLD_MAP_REL");
669
5
        } else {
670
5
          this->SetErrorMessage("Dynamic section specifies unreadable value"
671
5
                                " for unexpected attribute");
672
5
        }
673
19
        se.Value = "";
674
19
        return nullptr;
675
19
      }
676
677
      // The value has been read successfully.  Report it.
678
77
      se.Position = static_cast<unsigned long>(strtab.sh_offset + first);
679
77
      se.Size = last - first;
680
77
      se.IndexInSection =
681
77
        static_cast<int>(di - this->DynamicSectionEntries.begin());
682
77
      return &se;
683
96
    }
684
393k
  }
685
392
  return nullptr;
686
591
}
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.32k
{
697
  // Try to open the file.
698
1.32k
  auto fin = cm::make_unique<cmsys::ifstream>(fname, std::ios::binary);
699
700
  // Quit now if the file could not be opened.
701
1.32k
  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.32k
  char ident[EI_NIDENT];
708
1.32k
  if (!fin->read(ident, EI_NIDENT)) {
709
0
    this->ErrorMessage = "Error reading ELF identification.";
710
0
    return;
711
0
  }
712
1.32k
  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.32k
  if (!(ident[EI_MAG0] == ELFMAG0 && ident[EI_MAG1] == ELFMAG1 &&
719
1.28k
        ident[EI_MAG2] == ELFMAG2 && ident[EI_MAG3] == ELFMAG3)) {
720
68
    this->ErrorMessage = "File does not have a valid ELF identification.";
721
68
    return;
722
68
  }
723
724
  // Check the byte order in which the rest of the file is encoded.
725
1.25k
  cmELFInternal::ByteOrderType order;
726
1.25k
  if (ident[EI_DATA] == ELFDATA2LSB) {
727
    // File is LSB.
728
1.03k
    order = cmELFInternal::ByteOrderLSB;
729
1.03k
  } else if (ident[EI_DATA] == ELFDATA2MSB) {
730
    // File is MSB.
731
209
    order = cmELFInternal::ByteOrderMSB;
732
209
  } 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.24k
  if (ident[EI_CLASS] == ELFCLASS32) {
740
    // 32-bit ELF
741
485
    this->Internal = cm::make_unique<cmELFInternalImpl<cmELFTypes32>>(
742
485
      this, std::move(fin), order);
743
756
  } else if (ident[EI_CLASS] == ELFCLASS64) {
744
    // 64-bit ELF
745
745
    this->Internal = cm::make_unique<cmELFInternalImpl<cmELFTypes64>>(
746
745
      this, std::move(fin), order);
747
745
  } else {
748
11
    this->ErrorMessage = "ELF file class is not 32-bit or 64-bit.";
749
11
    return;
750
11
  }
751
1.24k
}
752
753
1.32k
cmELF::~cmELF() = default;
754
755
bool cmELF::Valid() const
756
20.5k
{
757
20.5k
  return this->Internal && this->Internal->GetFileType() != FileTypeInvalid;
758
20.5k
}
759
760
cmELF::FileType cmELF::GetFileType() const
761
984
{
762
984
  if (this->Valid()) {
763
984
    return this->Internal->GetFileType();
764
984
  }
765
0
  return FileTypeInvalid;
766
984
}
767
768
std::uint16_t cmELF::GetMachine() const
769
984
{
770
984
  if (this->Valid()) {
771
984
    return this->Internal->GetMachine();
772
984
  }
773
0
  return 0;
774
984
}
775
776
std::size_t cmELF::GetNumberOfSections() const
777
984
{
778
984
  if (this->Valid()) {
779
984
    return this->Internal->GetNumberOfSections();
780
984
  }
781
0
  return 0;
782
984
}
783
784
unsigned long cmELF::GetDynamicEntryPosition(int index) const
785
8.23k
{
786
8.23k
  if (this->Valid()) {
787
8.23k
    return this->Internal->GetDynamicEntryPosition(index);
788
8.23k
  }
789
0
  return 0;
790
8.23k
}
791
792
cmELF::DynamicEntryList cmELF::GetDynamicEntries() const
793
984
{
794
984
  if (this->Valid()) {
795
528
    return this->Internal->GetDynamicEntries();
796
528
  }
797
798
456
  return cmELF::DynamicEntryList();
799
984
}
800
801
std::vector<char> cmELF::EncodeDynamicEntries(
802
  cmELF::DynamicEntryList const& dentries) const
803
186
{
804
186
  if (this->Valid()) {
805
186
    return this->Internal->EncodeDynamicEntries(dentries);
806
186
  }
807
808
0
  return std::vector<char>();
809
186
}
810
811
bool cmELF::HasDynamicSection() const
812
984
{
813
984
  return this->Valid() && this->Internal->HasDynamicSection();
814
984
}
815
816
bool cmELF::GetSOName(std::string& soname)
817
984
{
818
984
  if (StringEntry const* se = this->GetSOName()) {
819
83
    soname = se->Value;
820
83
    return true;
821
83
  }
822
901
  return false;
823
984
}
824
825
cmELF::StringEntry const* cmELF::GetSOName()
826
1.96k
{
827
1.96k
  if (this->Valid() &&
828
1.83k
      this->Internal->GetFileType() == cmELF::FileTypeSharedLibrary) {
829
668
    return this->Internal->GetSOName();
830
668
  }
831
1.30k
  return nullptr;
832
1.96k
}
833
834
cmELF::StringEntry const* cmELF::GetRPath()
835
984
{
836
984
  if (this->Valid() &&
837
848
      (this->Internal->GetFileType() == cmELF::FileTypeExecutable ||
838
631
       this->Internal->GetFileType() == cmELF::FileTypeSharedLibrary)) {
839
631
    return this->Internal->GetRPath();
840
631
  }
841
353
  return nullptr;
842
984
}
843
844
cmELF::StringEntry const* cmELF::GetRunPath()
845
984
{
846
984
  if (this->Valid() &&
847
547
      (this->Internal->GetFileType() == cmELF::FileTypeExecutable ||
848
388
       this->Internal->GetFileType() == cmELF::FileTypeSharedLibrary)) {
849
330
    return this->Internal->GetRunPath();
850
330
  }
851
654
  return nullptr;
852
984
}
853
854
bool cmELF::IsMIPS() const
855
984
{
856
984
  if (this->Valid()) {
857
984
    return this->Internal->IsMips();
858
984
  }
859
0
  return false;
860
984
}
861
862
void cmELF::PrintInfo(std::ostream& os) const
863
984
{
864
984
  if (this->Valid()) {
865
461
    this->Internal->PrintInfo(os);
866
523
  } else {
867
523
    os << "Not a valid ELF file.\n";
868
523
  }
869
984
}