diff --git a/Source/cmSystemTools.cxx b/Source/cmSystemTools.cxx index 477375501..4d25944d4 100644 --- a/Source/cmSystemTools.cxx +++ b/Source/cmSystemTools.cxx @@ -2463,3 +2463,173 @@ bool cmSystemTools::ChangeRPath(std::string const& file, return false; #endif } + +//---------------------------------------------------------------------------- +bool cmSystemTools::RemoveRPath(std::string const& file, std::string* emsg) +{ +#if defined(CMAKE_USE_ELF_PARSER) + unsigned long rpathPosition = 0; + unsigned long rpathSize = 0; + unsigned long rpathEntryPosition = 0; + std::vector bytes; + { + // Parse the ELF binary. + cmELF elf(file.c_str()); + + // Get the RPATH or RUNPATH entry from it. + cmELF::StringEntry const* se = elf.GetRPath(); + if(!se) + { + se = elf.GetRunPath(); + } + + if(se) + { + // Store information about the entry. + rpathPosition = se->Position; + rpathSize = se->Size; + rpathEntryPosition = elf.GetDynamicEntryPosition(se->IndexInSection); + + // Get the file range containing the rest of the DYNAMIC table + // after the RPATH entry. + unsigned long nextEntryPosition = + elf.GetDynamicEntryPosition(se->IndexInSection+1); + unsigned int count = elf.GetDynamicEntryCount(); + if(count == 0) + { + // This should happen only for invalid ELF files where a DT_NULL + // appears before the end of the table. + if(emsg) + { + *emsg = "DYNAMIC section contains a DT_NULL before the end."; + } + return false; + } + unsigned long nullEntryPosition = elf.GetDynamicEntryPosition(count); + + // Allocate and fill a buffer with zeros. + bytes.resize(nullEntryPosition - rpathEntryPosition, 0); + + // Read the part of the DYNAMIC section header that will move. + // The remainder of the buffer will be left with zeros which + // represent a DT_NULL entry. + if(!elf.ReadBytes(nextEntryPosition, + nullEntryPosition - nextEntryPosition, + &bytes[0])) + { + if(emsg) + { + *emsg = "Failed to read DYNAMIC section header."; + } + return false; + } + } + else + { + // There is no RPATH or RUNPATH anyway. + return true; + } + } + + // Open the file for update. + std::ofstream f(file.c_str(), + std::ios::in | std::ios::out | std::ios::binary); + if(!f) + { + if(emsg) + { + *emsg = "Error opening file for update."; + } + return false; + } + + // Write the new DYNAMIC table header. + if(!f.seekp(rpathEntryPosition)) + { + if(emsg) + { + *emsg = "Error seeking to DYNAMIC table header for RPATH."; + } + return false; + } + if(!f.write(&bytes[0], bytes.size())) + { + if(emsg) + { + *emsg = "Error replacing DYNAMIC table header."; + } + return false; + } + + // Fill the RPATH string with zero bytes. + if(!f.seekp(rpathPosition)) + { + if(emsg) + { + *emsg = "Error seeking to RPATH position."; + } + return false; + } + for(unsigned long i=0; i < rpathSize; ++i) + { + f << '\0'; + } + + // Make sure everything was okay. + if(f) + { + return true; + } + else + { + if(emsg) + { + *emsg = "Error writing the empty rpath to the file."; + } + return false; + } +#else + (void)file; + (void)emsg; + return false; +#endif +} + +//---------------------------------------------------------------------------- +bool cmSystemTools::CheckRPath(std::string const& file, + std::string const& newRPath) +{ +#if defined(CMAKE_USE_ELF_PARSER) + // Parse the ELF binary. + cmELF elf(file.c_str()); + + // Get the RPATH or RUNPATH entry from it. + cmELF::StringEntry const* se = elf.GetRPath(); + if(!se) + { + se = elf.GetRunPath(); + } + + // Make sure the current rpath contains the new rpath. + if(newRPath.empty()) + { + if(!se) + { + return true; + } + } + else + { + if(se && + cmSystemToolsFindRPath(se->Value, newRPath) != std::string::npos) + { + return true; + } + } + return false; +#else + (void)file; + (void)newRPath; + return false; +#endif +} diff --git a/Source/cmSystemTools.h b/Source/cmSystemTools.h index 18c4939aa..89cf407a2 100644 --- a/Source/cmSystemTools.h +++ b/Source/cmSystemTools.h @@ -393,6 +393,14 @@ public: std::string const& newRPath, std::string* emsg = 0); + /** Try to remove the RPATH from an ELF binary. */ + static bool RemoveRPath(std::string const& file, std::string* emsg = 0); + + /** Check whether the RPATH in an ELF binary contains the path + given. */ + static bool CheckRPath(std::string const& file, + std::string const& newRPath); + private: static bool s_ForceUnixPaths; static bool s_RunCommandHideConsole;