1 /*============================================================================
2 CMake - Cross Platform Makefile Generator
3 Copyright 2000-2009 Kitware, Inc., Insight Software Consortium
5 Distributed under the OSI-approved BSD License (the "License");
6 see accompanying file Copyright.txt for details.
8 This software is distributed WITHOUT ANY WARRANTY; without even the
9 implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
10 See the License for more information.
11 ============================================================================*/
12 #include "cmStandardIncludes.h" // to get CMAKE_USE_ELF_PARSER first
15 #include <cmsys/auto_ptr.hxx>
17 // Need the native byte order of the running CPU.
18 #define cmsys_CPU_UNKNOWN_OKAY // We can decide at runtime if not known.
19 #include <cmsys/CPU.h>
21 // Include the ELF format information system header.
22 #if defined(__OpenBSD__)
29 # include <sys/link.h> // For dynamic section information
32 //----------------------------------------------------------------------------
33 // Low-level byte swapping implementation.
34 template <size_t s> struct cmELFByteSwapSize {};
35 void cmELFByteSwap(char*, cmELFByteSwapSize<1> const&)
38 void cmELFByteSwap(char* data, cmELFByteSwapSize<2> const&)
41 one_byte = data[0]; data[0] = data[1]; data[1] = one_byte;
43 void cmELFByteSwap(char* data, cmELFByteSwapSize<4> const&)
46 one_byte = data[0]; data[0] = data[3]; data[3] = one_byte;
47 one_byte = data[1]; data[1] = data[2]; data[2] = one_byte;
49 void cmELFByteSwap(char* data, cmELFByteSwapSize<8> const&)
52 one_byte = data[0]; data[0] = data[7]; data[7] = one_byte;
53 one_byte = data[1]; data[1] = data[6]; data[6] = one_byte;
54 one_byte = data[2]; data[2] = data[5]; data[5] = one_byte;
55 one_byte = data[3]; data[3] = data[4]; data[4] = one_byte;
58 // Low-level byte swapping interface.
60 void cmELFByteSwap(T& x)
62 cmELFByteSwap(reinterpret_cast<char*>(&x), cmELFByteSwapSize<sizeof(T)>());
65 //----------------------------------------------------------------------------
69 typedef cmELF::StringEntry StringEntry;
70 enum ByteOrderType { ByteOrderMSB, ByteOrderLSB };
72 // Construct and take ownership of the file stream object.
73 cmELFInternal(cmELF* external,
74 cmsys::auto_ptr<std::ifstream>& fin,
77 Stream(*fin.release()),
79 ELFType(cmELF::FileTypeInvalid)
81 // In most cases the processor-specific byte order will match that
82 // of the target execution environment. If we choose wrong here
83 // it is fixed when the header is read.
84 #if cmsys_CPU_ENDIAN_ID == cmsys_CPU_ENDIAN_ID_LITTLE
85 this->NeedSwap = (this->ByteOrder == ByteOrderMSB);
86 #elif cmsys_CPU_ENDIAN_ID == cmsys_CPU_ENDIAN_ID_BIG
87 this->NeedSwap = (this->ByteOrder == ByteOrderLSB);
89 this->NeedSwap = false; // Final decision is at runtime anyway.
92 // We have not yet loaded the section info.
93 this->DynamicSectionIndex = -1;
96 // Destruct and delete the file stream object.
97 virtual ~cmELFInternal()
102 // Forward to the per-class implementation.
103 virtual unsigned int GetNumberOfSections() const = 0;
104 virtual unsigned int GetDynamicEntryCount() = 0;
105 virtual unsigned long GetDynamicEntryPosition(int j) = 0;
106 virtual StringEntry const* GetDynamicSectionString(int tag) = 0;
107 virtual void PrintInfo(std::ostream& os) const = 0;
109 bool ReadBytes(unsigned long pos, unsigned long size, char* buf)
111 this->Stream.seekg(pos);
112 this->Stream.read(buf, size);
113 return this->Stream?true:false;
116 // Lookup the SONAME in the DYNAMIC section.
117 StringEntry const* GetSOName()
119 return this->GetDynamicSectionString(DT_SONAME);
122 // Lookup the RPATH in the DYNAMIC section.
123 StringEntry const* GetRPath()
125 return this->GetDynamicSectionString(DT_RPATH);
128 // Lookup the RUNPATH in the DYNAMIC section.
129 StringEntry const* GetRunPath()
131 #if defined(DT_RUNPATH)
132 return this->GetDynamicSectionString(DT_RUNPATH);
138 // Return the recorded ELF type.
139 cmELF::FileType GetFileType() const { return this->ELFType; }
141 // Data common to all ELF class implementations.
143 // The external cmELF object.
146 // The stream from which to read.
147 std::istream& Stream;
149 // The byte order of the ELF file.
150 ByteOrderType ByteOrder;
152 // The ELF file type.
153 cmELF::FileType ELFType;
155 // Whether we need to byte-swap structures read from the stream.
158 // The section header index of the DYNAMIC section (-1 if none).
159 int DynamicSectionIndex;
161 // Helper methods for subclasses.
162 void SetErrorMessage(const char* msg)
164 this->External->ErrorMessage = msg;
165 this->ELFType = cmELF::FileTypeInvalid;
168 // Store string table entry states.
169 std::map<int, StringEntry> DynamicSectionStrings;
172 //----------------------------------------------------------------------------
173 // Configure the implementation template for 32-bit ELF files.
176 typedef Elf32_Ehdr ELF_Ehdr;
177 typedef Elf32_Shdr ELF_Shdr;
178 typedef Elf32_Dyn ELF_Dyn;
179 typedef Elf32_Half ELF_Half;
180 static const char* GetName() { return "32-bit"; }
183 // Configure the implementation template for 32-bit ELF files.
186 typedef Elf64_Ehdr ELF_Ehdr;
187 typedef Elf64_Shdr ELF_Shdr;
188 typedef Elf64_Dyn ELF_Dyn;
189 typedef Elf64_Half ELF_Half;
190 static const char* GetName() { return "64-bit"; }
193 //----------------------------------------------------------------------------
194 // Parser implementation template.
195 template <class Types>
196 class cmELFInternalImpl: public cmELFInternal
199 // Copy the ELF file format types from our configuration parameter.
200 typedef typename Types::ELF_Ehdr ELF_Ehdr;
201 typedef typename Types::ELF_Shdr ELF_Shdr;
202 typedef typename Types::ELF_Dyn ELF_Dyn;
203 typedef typename Types::ELF_Half ELF_Half;
205 // Construct with a stream and byte swap indicator.
206 cmELFInternalImpl(cmELF* external,
207 cmsys::auto_ptr<std::ifstream>& fin,
208 ByteOrderType order);
210 // Return the number of sections as specified by the ELF header.
211 virtual unsigned int GetNumberOfSections() const
213 return static_cast<unsigned int>(this->ELFHeader.e_shnum);
216 // Get the file position and size of a dynamic section entry.
217 virtual unsigned int GetDynamicEntryCount();
218 virtual unsigned long GetDynamicEntryPosition(int j);
220 // Lookup a string from the dynamic section with the given tag.
221 virtual StringEntry const* GetDynamicSectionString(int tag);
223 // Print information about the ELF file.
224 virtual void PrintInfo(std::ostream& os) const
226 os << "ELF " << Types::GetName();
227 if(this->ByteOrder == ByteOrderMSB)
231 else if(this->ByteOrder == ByteOrderLSB)
235 switch(this->ELFType)
237 case cmELF::FileTypeInvalid:
238 os << " invalid file";
240 case cmELF::FileTypeRelocatableObject:
241 os << " relocatable object";
243 case cmELF::FileTypeExecutable:
246 case cmELF::FileTypeSharedLibrary:
247 os << " shared library";
249 case cmELF::FileTypeCore:
252 case cmELF::FileTypeSpecificOS:
253 os << " os-specific type";
255 case cmELF::FileTypeSpecificProc:
256 os << " processor-specific type";
263 void ByteSwap(ELF_Ehdr& elf_header)
265 cmELFByteSwap(elf_header.e_type);
266 cmELFByteSwap(elf_header.e_machine);
267 cmELFByteSwap(elf_header.e_version);
268 cmELFByteSwap(elf_header.e_entry);
269 cmELFByteSwap(elf_header.e_phoff);
270 cmELFByteSwap(elf_header.e_shoff);
271 cmELFByteSwap(elf_header.e_flags);
272 cmELFByteSwap(elf_header.e_ehsize);
273 cmELFByteSwap(elf_header.e_phentsize);
274 cmELFByteSwap(elf_header.e_phnum);
275 cmELFByteSwap(elf_header.e_shentsize);
276 cmELFByteSwap(elf_header.e_shnum);
277 cmELFByteSwap(elf_header.e_shstrndx);
280 void ByteSwap(ELF_Shdr& sec_header)
282 cmELFByteSwap(sec_header.sh_name);
283 cmELFByteSwap(sec_header.sh_type);
284 cmELFByteSwap(sec_header.sh_flags);
285 cmELFByteSwap(sec_header.sh_addr);
286 cmELFByteSwap(sec_header.sh_offset);
287 cmELFByteSwap(sec_header.sh_size);
288 cmELFByteSwap(sec_header.sh_link);
289 cmELFByteSwap(sec_header.sh_info);
290 cmELFByteSwap(sec_header.sh_addralign);
291 cmELFByteSwap(sec_header.sh_entsize);
294 void ByteSwap(ELF_Dyn& dyn)
296 cmELFByteSwap(dyn.d_tag);
299 case DT_NULL: /* dyn.d_un ignored */ break;
300 case DT_NEEDED: cmELFByteSwap(dyn.d_un.d_val); break;
301 case DT_PLTRELSZ: cmELFByteSwap(dyn.d_un.d_val); break;
302 case DT_PLTGOT: cmELFByteSwap(dyn.d_un.d_ptr); break;
303 case DT_HASH: cmELFByteSwap(dyn.d_un.d_ptr); break;
304 case DT_STRTAB: cmELFByteSwap(dyn.d_un.d_ptr); break;
305 case DT_SYMTAB: cmELFByteSwap(dyn.d_un.d_ptr); break;
306 case DT_RELA: cmELFByteSwap(dyn.d_un.d_ptr); break;
307 case DT_RELASZ: cmELFByteSwap(dyn.d_un.d_val); break;
308 case DT_RELAENT: cmELFByteSwap(dyn.d_un.d_val); break;
309 case DT_STRSZ: cmELFByteSwap(dyn.d_un.d_val); break;
310 case DT_SYMENT: cmELFByteSwap(dyn.d_un.d_val); break;
311 case DT_INIT: cmELFByteSwap(dyn.d_un.d_ptr); break;
312 case DT_FINI: cmELFByteSwap(dyn.d_un.d_ptr); break;
313 case DT_SONAME: cmELFByteSwap(dyn.d_un.d_val); break;
314 case DT_RPATH: cmELFByteSwap(dyn.d_un.d_val); break;
315 case DT_SYMBOLIC: /* dyn.d_un ignored */ break;
316 case DT_REL: cmELFByteSwap(dyn.d_un.d_ptr); break;
317 case DT_RELSZ: cmELFByteSwap(dyn.d_un.d_val); break;
318 case DT_RELENT: cmELFByteSwap(dyn.d_un.d_val); break;
319 case DT_PLTREL: cmELFByteSwap(dyn.d_un.d_val); break;
320 case DT_DEBUG: cmELFByteSwap(dyn.d_un.d_ptr); break;
321 case DT_TEXTREL: /* dyn.d_un ignored */ break;
322 case DT_JMPREL: cmELFByteSwap(dyn.d_un.d_ptr); break;
324 case T_BIND_NOW: /* dyn.d_un ignored */ break;
327 case DT_INIT_ARRAY: cmELFByteSwap(dyn.d_un.d_ptr); break;
330 case DT_FINI_ARRAY: cmELFByteSwap(dyn.d_un.d_ptr); break;
332 #ifdef DT_INIT_ARRAYSZ
333 case DT_INIT_ARRAYSZ: cmELFByteSwap(dyn.d_un.d_val); break;
335 #ifdef DT_FINI_ARRAYSZ
336 case DT_FINI_ARRAYSZ: cmELFByteSwap(dyn.d_un.d_val); break;
339 case DT_RUNPATH: cmELFByteSwap(dyn.d_un.d_val); break;
342 case DT_FLAGS: cmELFByteSwap(dyn.d_un.d_val); break;
344 #ifdef DT_PREINIT_ARRAY
345 case DT_PREINIT_ARRAY: cmELFByteSwap(dyn.d_un.d_ptr); break;
347 #ifdef DT_PREINIT_ARRAYSZ
348 case DT_PREINIT_ARRAYSZ: cmELFByteSwap(dyn.d_un.d_val); break;
353 bool FileTypeValid(ELF_Half et)
355 unsigned int eti = static_cast<unsigned int>(et);
356 if(eti == ET_NONE || eti == ET_REL || eti == ET_EXEC ||
357 eti == ET_DYN || eti == ET_CORE)
361 #if defined(ET_LOOS) && defined(ET_HIOS)
362 if(eti >= ET_LOOS && eti <= ET_HIOS)
367 #if defined(ET_LOPROC) && defined(ET_HIPROC)
368 if(eti >= ET_LOPROC && eti <= ET_HIPROC)
376 bool Read(ELF_Ehdr& x)
378 // Read the header from the file.
379 if(!this->Stream.read(reinterpret_cast<char*>(&x), sizeof(x)))
384 // The byte order of ELF header fields may not match that of the
385 // processor-specific data. The header fields are ordered to
386 // match the target execution environment, so we may need to
387 // memorize the order of all platforms based on the e_machine
388 // value. As a heuristic, if the type is invalid but its
389 // swapped value is okay then flip our swap mode.
390 ELF_Half et = x.e_type;
395 if(!this->FileTypeValid(et))
398 if(this->FileTypeValid(et))
400 // The previous byte order guess was wrong. Flip it.
401 this->NeedSwap = !this->NeedSwap;
405 // Fix the byte order of the header.
412 bool Read(ELF_Shdr& x)
414 if(this->Stream.read(reinterpret_cast<char*>(&x), sizeof(x)) &&
419 return this->Stream? true:false;
421 bool Read(ELF_Dyn& x)
423 if(this->Stream.read(reinterpret_cast<char*>(&x), sizeof(x)) &&
428 return this->Stream? true:false;
431 bool LoadSectionHeader(ELF_Half i)
433 // Read the section header from the file.
434 this->Stream.seekg(this->ELFHeader.e_shoff +
435 this->ELFHeader.e_shentsize * i);
436 if(!this->Read(this->SectionHeaders[i]))
441 // Identify some important sections.
442 if(this->SectionHeaders[i].sh_type == SHT_DYNAMIC)
444 this->DynamicSectionIndex = i;
449 bool LoadDynamicSection();
451 // Store the main ELF header.
454 // Store all the section headers.
455 std::vector<ELF_Shdr> SectionHeaders;
457 // Store all entries of the DYNAMIC section.
458 std::vector<ELF_Dyn> DynamicSectionEntries;
461 //----------------------------------------------------------------------------
462 template <class Types>
463 cmELFInternalImpl<Types>
464 ::cmELFInternalImpl(cmELF* external,
465 cmsys::auto_ptr<std::ifstream>& fin,
466 ByteOrderType order):
467 cmELFInternal(external, fin, order)
469 // Read the main header.
470 if(!this->Read(this->ELFHeader))
472 this->SetErrorMessage("Failed to read main ELF header.");
476 // Determine the ELF file type.
477 switch(this->ELFHeader.e_type)
480 this->SetErrorMessage("ELF file type is NONE.");
483 this->ELFType = cmELF::FileTypeRelocatableObject;
486 this->ELFType = cmELF::FileTypeExecutable;
489 this->ELFType = cmELF::FileTypeSharedLibrary;
492 this->ELFType = cmELF::FileTypeCore;
496 unsigned int eti = static_cast<unsigned int>(this->ELFHeader.e_type);
497 #if defined(ET_LOOS) && defined(ET_HIOS)
498 if(eti >= ET_LOOS && eti <= ET_HIOS)
500 this->ELFType = cmELF::FileTypeSpecificOS;
504 #if defined(ET_LOPROC) && defined(ET_HIPROC)
505 if(eti >= ET_LOPROC && eti <= ET_HIPROC)
507 this->ELFType = cmELF::FileTypeSpecificProc;
512 e << "Unknown ELF file type " << eti;
513 this->SetErrorMessage(e.str().c_str());
518 // Load the section headers.
519 this->SectionHeaders.resize(this->ELFHeader.e_shnum);
520 for(ELF_Half i=0; i < this->ELFHeader.e_shnum; ++i)
522 if(!this->LoadSectionHeader(i))
524 this->SetErrorMessage("Failed to load section headers.");
530 //----------------------------------------------------------------------------
531 template <class Types>
532 bool cmELFInternalImpl<Types>::LoadDynamicSection()
534 // If there is no dynamic section we are done.
535 if(this->DynamicSectionIndex < 0)
540 // If the section was already loaded we are done.
541 if(!this->DynamicSectionEntries.empty())
546 // Allocate the dynamic section entries.
547 ELF_Shdr const& sec = this->SectionHeaders[this->DynamicSectionIndex];
548 int n = static_cast<int>(sec.sh_size / sec.sh_entsize);
549 this->DynamicSectionEntries.resize(n);
552 for(int j=0; j < n; ++j)
554 // Seek to the beginning of the section entry.
555 this->Stream.seekg(sec.sh_offset + sec.sh_entsize*j);
556 ELF_Dyn& dyn = this->DynamicSectionEntries[j];
558 // Try reading the entry.
561 this->SetErrorMessage("Error reading entry from DYNAMIC section.");
562 this->DynamicSectionIndex = -1;
569 //----------------------------------------------------------------------------
570 template <class Types>
571 unsigned int cmELFInternalImpl<Types>::GetDynamicEntryCount()
573 if(!this->LoadDynamicSection())
577 for(unsigned int i = 0; i < this->DynamicSectionEntries.size(); ++i)
579 if(this->DynamicSectionEntries[i].d_tag == DT_NULL)
584 return static_cast<unsigned int>(this->DynamicSectionEntries.size());
587 //----------------------------------------------------------------------------
588 template <class Types>
589 unsigned long cmELFInternalImpl<Types>::GetDynamicEntryPosition(int j)
591 if(!this->LoadDynamicSection())
595 if(j < 0 || j >= static_cast<int>(this->DynamicSectionEntries.size()))
599 ELF_Shdr const& sec = this->SectionHeaders[this->DynamicSectionIndex];
600 return static_cast<unsigned long>(sec.sh_offset + sec.sh_entsize*j);
603 //----------------------------------------------------------------------------
604 template <class Types>
605 cmELF::StringEntry const*
606 cmELFInternalImpl<Types>::GetDynamicSectionString(int tag)
608 // Short-circuit if already checked.
609 std::map<int, StringEntry>::iterator dssi =
610 this->DynamicSectionStrings.find(tag);
611 if(dssi != this->DynamicSectionStrings.end())
613 if(dssi->second.Position > 0)
615 return &dssi->second;
620 // Create an entry for this tag. Assume it is missing until found.
621 StringEntry& se = this->DynamicSectionStrings[tag];
624 se.IndexInSection = -1;
626 // Try reading the dynamic section.
627 if(!this->LoadDynamicSection())
632 // Get the string table referenced by the DYNAMIC section.
633 ELF_Shdr const& sec = this->SectionHeaders[this->DynamicSectionIndex];
634 if(sec.sh_link >= this->SectionHeaders.size())
636 this->SetErrorMessage("Section DYNAMIC has invalid string table index.");
639 ELF_Shdr const& strtab = this->SectionHeaders[sec.sh_link];
641 // Look for the requested entry.
642 for(typename std::vector<ELF_Dyn>::iterator
643 di = this->DynamicSectionEntries.begin();
644 di != this->DynamicSectionEntries.end(); ++di)
649 // We found the tag requested.
650 // Make sure the position given is within the string section.
651 if(dyn.d_un.d_val >= strtab.sh_size)
653 this->SetErrorMessage("Section DYNAMIC references string beyond "
654 "the end of its string section.");
658 // Seek to the position reported by the entry.
659 unsigned long first = static_cast<unsigned long>(dyn.d_un.d_val);
660 unsigned long last = first;
661 unsigned long end = static_cast<unsigned long>(strtab.sh_size);
662 this->Stream.seekg(strtab.sh_offset + first);
664 // Read the string. It may be followed by more than one NULL
665 // terminator. Count the total size of the region allocated to
666 // the string. This assumes that the next string in the table
667 // is non-empty, but the "chrpath" tool makes the same
669 bool terminated = false;
671 while(last != end && this->Stream.get(c) && !(terminated && c))
684 // Make sure the whole value was read.
687 this->SetErrorMessage("Dynamic section specifies unreadable RPATH.");
692 // The value has been read successfully. Report it.
693 se.Position = static_cast<unsigned long>(strtab.sh_offset + first);
694 se.Size = last - first;
696 static_cast<int>(di - this->DynamicSectionEntries.begin());
703 //============================================================================
704 // External class implementation.
706 //----------------------------------------------------------------------------
707 cmELF::cmELF(const char* fname): Internal(0)
709 // Try to open the file.
710 cmsys::auto_ptr<std::ifstream> fin(new std::ifstream(fname));
712 // Quit now if the file could not be opened.
713 if(!fin.get() || !*fin)
715 this->ErrorMessage = "Error opening input file.";
719 // Read the ELF identification block.
720 char ident[EI_NIDENT];
721 if(!fin->read(ident, EI_NIDENT))
723 this->ErrorMessage = "Error reading ELF identification.";
728 this->ErrorMessage = "Error seeking to beginning of file.";
732 // Verify the ELF identification.
733 if(!(ident[EI_MAG0] == ELFMAG0 &&
734 ident[EI_MAG1] == ELFMAG1 &&
735 ident[EI_MAG2] == ELFMAG2 &&
736 ident[EI_MAG3] == ELFMAG3))
738 this->ErrorMessage = "File does not have a valid ELF identification.";
742 // Check the byte order in which the rest of the file is encoded.
743 cmELFInternal::ByteOrderType order;
744 if(ident[EI_DATA] == ELFDATA2LSB)
747 order = cmELFInternal::ByteOrderLSB;
749 else if(ident[EI_DATA] == ELFDATA2MSB)
752 order = cmELFInternal::ByteOrderMSB;
756 this->ErrorMessage = "ELF file is not LSB or MSB encoded.";
760 // Check the class of the file and construct the corresponding
761 // parser implementation.
762 if(ident[EI_CLASS] == ELFCLASS32)
765 this->Internal = new cmELFInternalImpl<cmELFTypes32>(this, fin, order);
767 else if(ident[EI_CLASS] == ELFCLASS64)
770 this->Internal = new cmELFInternalImpl<cmELFTypes64>(this, fin, order);
774 this->ErrorMessage = "ELF file class is not 32-bit or 64-bit.";
779 //----------------------------------------------------------------------------
782 delete this->Internal;
785 //----------------------------------------------------------------------------
786 bool cmELF::Valid() const
788 return this->Internal && this->Internal->GetFileType() != FileTypeInvalid;
791 //----------------------------------------------------------------------------
792 cmELF::FileType cmELF::GetFileType() const
796 return this->Internal->GetFileType();
800 return FileTypeInvalid;
804 //----------------------------------------------------------------------------
805 unsigned int cmELF::GetNumberOfSections() const
809 return this->Internal->GetNumberOfSections();
817 //----------------------------------------------------------------------------
818 unsigned int cmELF::GetDynamicEntryCount() const
822 return this->Internal->GetDynamicEntryCount();
830 //----------------------------------------------------------------------------
831 unsigned long cmELF::GetDynamicEntryPosition(int index) const
835 return this->Internal->GetDynamicEntryPosition(index);
843 //----------------------------------------------------------------------------
844 bool cmELF::ReadBytes(unsigned long pos, unsigned long size, char* buf) const
848 return this->Internal->ReadBytes(pos, size, buf);
856 //----------------------------------------------------------------------------
857 bool cmELF::GetSOName(std::string& soname)
859 if(StringEntry const* se = this->GetSOName())
870 //----------------------------------------------------------------------------
871 cmELF::StringEntry const* cmELF::GetSOName()
874 this->Internal->GetFileType() == cmELF::FileTypeSharedLibrary)
876 return this->Internal->GetSOName();
884 //----------------------------------------------------------------------------
885 cmELF::StringEntry const* cmELF::GetRPath()
888 (this->Internal->GetFileType() == cmELF::FileTypeExecutable ||
889 this->Internal->GetFileType() == cmELF::FileTypeSharedLibrary))
891 return this->Internal->GetRPath();
899 //----------------------------------------------------------------------------
900 cmELF::StringEntry const* cmELF::GetRunPath()
903 (this->Internal->GetFileType() == cmELF::FileTypeExecutable ||
904 this->Internal->GetFileType() == cmELF::FileTypeSharedLibrary))
906 return this->Internal->GetRunPath();
914 //----------------------------------------------------------------------------
915 void cmELF::PrintInfo(std::ostream& os) const
919 this->Internal->PrintInfo(os);
923 os << "Not a valid ELF file.\n";