ENH: Make cmELF parser more general and powerful

- Add support to get RPATH and RUNPATH entries.
  - Add support to get file offsets to strings.
  - Add more DT_* tags to byte swapping.
This commit is contained in:
Brad King 2008-02-29 11:12:59 -05:00
parent 44f696f8da
commit 03ef00bc93
2 changed files with 153 additions and 29 deletions

View File

@ -65,6 +65,7 @@ void cmELFByteSwap(T& x)
class cmELFInternal class cmELFInternal
{ {
public: public:
typedef cmELF::StringEntry StringEntry;
enum ByteOrderType { ByteOrderMSB, ByteOrderLSB }; enum ByteOrderType { ByteOrderMSB, ByteOrderLSB };
// Construct and take ownership of the file stream object. // Construct and take ownership of the file stream object.
@ -95,9 +96,31 @@ public:
// Forward to the per-class implementation. // Forward to the per-class implementation.
virtual unsigned int GetNumberOfSections() const = 0; virtual unsigned int GetNumberOfSections() const = 0;
virtual bool GetSOName(std::string& soname) = 0; virtual StringEntry const* GetDynamicSectionString(int tag) = 0;
virtual void PrintInfo(std::ostream& os) const = 0; virtual void PrintInfo(std::ostream& os) const = 0;
// Lookup the SONAME in the DYNAMIC section.
StringEntry const* GetSOName()
{
return this->GetDynamicSectionString(DT_SONAME);
}
// Lookup the RPATH in the DYNAMIC section.
StringEntry const* GetRPath()
{
return this->GetDynamicSectionString(DT_RPATH);
}
// Lookup the RUNPATH in the DYNAMIC section.
StringEntry const* GetRunPath()
{
#if defined(DT_RUNPATH)
return this->GetDynamicSectionString(DT_RUNPATH);
#else
return 0;
#endif
}
// Return the recorded ELF type. // Return the recorded ELF type.
cmELF::FileType GetFileType() const { return this->ELFType; } cmELF::FileType GetFileType() const { return this->ELFType; }
protected: protected:
@ -127,6 +150,9 @@ protected:
this->External->ErrorMessage = msg; this->External->ErrorMessage = msg;
this->ELFType = cmELF::FileTypeInvalid; this->ELFType = cmELF::FileTypeInvalid;
} }
// Store string table entry states.
std::map<int, StringEntry> DynamicSectionStrings;
}; };
//---------------------------------------------------------------------------- //----------------------------------------------------------------------------
@ -173,8 +199,8 @@ public:
return static_cast<unsigned int>(this->ELFHeader.e_shnum); return static_cast<unsigned int>(this->ELFHeader.e_shnum);
} }
// Lookup the SONAME in the DYNAMIC section. // Lookup a string from the dynamic section with the given tag.
virtual bool GetSOName(std::string& soname); virtual StringEntry const* GetDynamicSectionString(int tag);
// Print information about the ELF file. // Print information about the ELF file.
virtual void PrintInfo(std::ostream& os) const virtual void PrintInfo(std::ostream& os) const
@ -270,6 +296,33 @@ private:
case DT_DEBUG: cmELFByteSwap(dyn.d_un.d_ptr); break; case DT_DEBUG: cmELFByteSwap(dyn.d_un.d_ptr); break;
case DT_TEXTREL: /* dyn.d_un ignored */ break; case DT_TEXTREL: /* dyn.d_un ignored */ break;
case DT_JMPREL: cmELFByteSwap(dyn.d_un.d_ptr); break; case DT_JMPREL: cmELFByteSwap(dyn.d_un.d_ptr); break;
#ifdef T_BIND_NOW
case T_BIND_NOW: /* dyn.d_un ignored */ break;
#endif
#ifdef DT_INIT_ARRAY
case DT_INIT_ARRAY: cmELFByteSwap(dyn.d_un.d_ptr); break;
#endif
#ifdef DT_FINI_ARRAY
case DT_FINI_ARRAY: cmELFByteSwap(dyn.d_un.d_ptr); break;
#endif
#ifdef DT_INIT_ARRAYSZ
case DT_INIT_ARRAYSZ: cmELFByteSwap(dyn.d_un.d_val); break;
#endif
#ifdef DT_FINI_ARRAYSZ
case DT_FINI_ARRAYSZ: cmELFByteSwap(dyn.d_un.d_val); break;
#endif
#ifdef DT_RUNPATH
case DT_RUNPATH: cmELFByteSwap(dyn.d_un.d_val); break;
#endif
#ifdef DT_FLAGS
case DT_FLAGS: cmELFByteSwap(dyn.d_un.d_val); break;
#endif
#ifdef DT_PREINIT_ARRAY
case DT_PREINIT_ARRAY: cmELFByteSwap(dyn.d_un.d_ptr); break;
#endif
#ifdef DT_PREINIT_ARRAYSZ
case DT_PREINIT_ARRAYSZ: cmELFByteSwap(dyn.d_un.d_val); break;
#endif
} }
} }
@ -329,10 +382,6 @@ private:
// Store all entries of the DYNAMIC section. // Store all entries of the DYNAMIC section.
std::vector<ELF_Dyn> DynamicSectionEntries; std::vector<ELF_Dyn> DynamicSectionEntries;
// Store the SOName if it has been loaded.
std::string SOName;
bool SONameChecked;
}; };
//---------------------------------------------------------------------------- //----------------------------------------------------------------------------
@ -343,9 +392,6 @@ cmELFInternalImpl<Types>
ByteOrderType order): ByteOrderType order):
cmELFInternal(external, fin, order) cmELFInternal(external, fin, order)
{ {
// Initialize state.
this->SONameChecked = false;
// Read the main header. // Read the main header.
if(!this->Read(this->ELFHeader)) if(!this->Read(this->ELFHeader))
{ {
@ -424,20 +470,29 @@ bool cmELFInternalImpl<Types>::LoadDynamicSection()
//---------------------------------------------------------------------------- //----------------------------------------------------------------------------
template <class Types> template <class Types>
bool cmELFInternalImpl<Types>::GetSOName(std::string& soname) cmELF::StringEntry const*
cmELFInternalImpl<Types>::GetDynamicSectionString(int tag)
{ {
// Short-circuit if already checked. // Short-circuit if already checked.
if(this->SONameChecked) std::map<int, StringEntry>::iterator dssi =
this->DynamicSectionStrings.find(tag);
if(dssi != this->DynamicSectionStrings.end())
{ {
soname = this->SOName; if(dssi->second.Position > 0)
return !soname.empty(); {
return &dssi->second;
} }
this->SONameChecked = true; return 0;
}
// Create an entry for this tag. Assume it is missing until found.
StringEntry& se = this->DynamicSectionStrings[tag];
se.Position = 0;
// Try reading the dynamic section. // Try reading the dynamic section.
if(!this->LoadDynamicSection()) if(!this->LoadDynamicSection())
{ {
return false; return 0;
} }
// Get the string table referenced by the DYNAMIC section. // Get the string table referenced by the DYNAMIC section.
@ -445,35 +500,43 @@ bool cmELFInternalImpl<Types>::GetSOName(std::string& soname)
if(sec.sh_link >= this->SectionHeaders.size()) if(sec.sh_link >= this->SectionHeaders.size())
{ {
this->SetErrorMessage("Section DYNAMIC has invalid string table index."); this->SetErrorMessage("Section DYNAMIC has invalid string table index.");
return false; return 0;
} }
ELF_Shdr const& strtab = this->SectionHeaders[sec.sh_link]; ELF_Shdr const& strtab = this->SectionHeaders[sec.sh_link];
// Look for the soname entry. // Look for the requested entry.
for(typename std::vector<ELF_Dyn>::iterator for(typename std::vector<ELF_Dyn>::iterator
di = this->DynamicSectionEntries.begin(); di = this->DynamicSectionEntries.begin();
di != this->DynamicSectionEntries.end(); ++di) di != this->DynamicSectionEntries.end(); ++di)
{ {
ELF_Dyn& dyn = *di; ELF_Dyn& dyn = *di;
if(dyn.d_tag == DT_SONAME) if(dyn.d_tag == tag)
{ {
// Seek to the position reported by the entry.
this->Stream.seekg(strtab.sh_offset + dyn.d_un.d_val); this->Stream.seekg(strtab.sh_offset + dyn.d_un.d_val);
// Read the string.
char c; char c;
while(this->Stream.get(c) && c != 0) while(this->Stream.get(c) && c != 0)
{ {
this->SOName += c; se.Value += c;
} }
// Make sure the whole value was read.
if(!this->Stream) if(!this->Stream)
{ {
this->SetErrorMessage("Dynamic section specifies unreadable SONAME."); this->SetErrorMessage("Dynamic section specifies unreadable RPATH.");
this->SOName = ""; se.Value = "";
return false; return 0;
} }
soname = this->SOName;
return true; // The value has been read successfully. Report it.
se.Position =
static_cast<unsigned long>(strtab.sh_offset + dyn.d_un.d_val);
return &se;
} }
} }
return false; return 0;
} }
//============================================================================ //============================================================================
@ -593,10 +656,10 @@ unsigned int cmELF::GetNumberOfSections() const
//---------------------------------------------------------------------------- //----------------------------------------------------------------------------
bool cmELF::GetSOName(std::string& soname) bool cmELF::GetSOName(std::string& soname)
{ {
if(this->Valid() && if(StringEntry const* se = this->GetSOName())
this->Internal->GetFileType() == cmELF::FileTypeSharedLibrary)
{ {
return this->Internal->GetSOName(soname); soname = se->Value;
return true;
} }
else else
{ {
@ -604,6 +667,50 @@ bool cmELF::GetSOName(std::string& soname)
} }
} }
//----------------------------------------------------------------------------
cmELF::StringEntry const* cmELF::GetSOName()
{
if(this->Valid() &&
this->Internal->GetFileType() == cmELF::FileTypeSharedLibrary)
{
return this->Internal->GetSOName();
}
else
{
return 0;
}
}
//----------------------------------------------------------------------------
cmELF::StringEntry const* cmELF::GetRPath()
{
if(this->Valid() &&
this->Internal->GetFileType() == cmELF::FileTypeExecutable ||
this->Internal->GetFileType() == cmELF::FileTypeSharedLibrary)
{
return this->Internal->GetRPath();
}
else
{
return 0;
}
}
//----------------------------------------------------------------------------
cmELF::StringEntry const* cmELF::GetRunPath()
{
if(this->Valid() &&
this->Internal->GetFileType() == cmELF::FileTypeExecutable ||
this->Internal->GetFileType() == cmELF::FileTypeSharedLibrary)
{
return this->Internal->GetRunPath();
}
else
{
return 0;
}
}
//---------------------------------------------------------------------------- //----------------------------------------------------------------------------
void cmELF::PrintInfo(std::ostream& os) const void cmELF::PrintInfo(std::ostream& os) const
{ {

View File

@ -54,6 +54,16 @@ public:
FileTypeCore FileTypeCore
}; };
/** Represent string table entries. */
struct StringEntry
{
// The string value itself.
std::string Value;
// The position in the file at which the string appears.
unsigned long Position;
};
/** Get the type of the file opened. */ /** Get the type of the file opened. */
FileType GetFileType() const; FileType GetFileType() const;
@ -62,6 +72,13 @@ public:
/** Get the SONAME field if any. */ /** Get the SONAME field if any. */
bool GetSOName(std::string& soname); bool GetSOName(std::string& soname);
StringEntry const* GetSOName();
/** Get the RPATH field if any. */
StringEntry const* GetRPath();
/** Get the RUNPATH field if any. */
StringEntry const* GetRunPath();
/** Print human-readable information about the ELF file. */ /** Print human-readable information about the ELF file. */
void PrintInfo(std::ostream& os) const; void PrintInfo(std::ostream& os) const;