diff --git cmake-2.6.1-orig/Source/cmFileCommand.cxx cmake-2.6.1/Source/cmFileCommand.cxx index 6ac6bcc..e8e64a4 100644 --- cmake-2.6.1-orig/Source/cmFileCommand.cxx +++ cmake-2.6.1/Source/cmFileCommand.cxx @@ -1486,7 +1486,8 @@ cmFileCommand::HandleRPathRemoveCommand(std::vector const& args) cmSystemToolsFileTime* ft = cmSystemTools::FileTimeNew(); bool have_ft = cmSystemTools::FileTimeGet(file, ft); std::string emsg; - if(!cmSystemTools::RemoveRPath(file, &emsg)) + bool removed; + if(!cmSystemTools::RemoveRPath(file, &emsg, &removed)) { cmOStringStream e; e << "RPATH_REMOVE could not remove RPATH from file:\n" @@ -1495,9 +1496,19 @@ cmFileCommand::HandleRPathRemoveCommand(std::vector const& args) this->SetError(e.str().c_str()); success = false; } - if(success && have_ft) + if(success) { - cmSystemTools::FileTimeSet(file, ft); + if(removed) + { + std::string message = "Removed runtime path from \""; + message += file; + message += "\""; + this->Makefile->DisplayStatus(message.c_str(), -1); + } + if(have_ft) + { + cmSystemTools::FileTimeSet(file, ft); + } } cmSystemTools::FileTimeDelete(ft); return success; diff --git cmake-2.6.1-orig/Source/cmSystemTools.cxx cmake-2.6.1/Source/cmSystemTools.cxx index 4e1f945..f333a4c 100644 --- cmake-2.6.1-orig/Source/cmSystemTools.cxx +++ cmake-2.6.1/Source/cmSystemTools.cxx @@ -26,6 +26,7 @@ #if defined(CMAKE_BUILD_WITH_CMAKE) # include #endif +#include #if defined(_WIN32) # include @@ -2328,6 +2329,16 @@ std::string::size_type cmSystemToolsFindRPath(std::string const& have, } #endif +#if defined(CMAKE_USE_ELF_PARSER) +struct cmSystemToolsRPathInfo +{ + unsigned long Position; + unsigned long Size; + std::string Name; + std::string Value; +}; +#endif + //---------------------------------------------------------------------------- bool cmSystemTools::ChangeRPath(std::string const& file, std::string const& oldRPath, @@ -2340,37 +2351,71 @@ bool cmSystemTools::ChangeRPath(std::string const& file, { *changed = false; } - unsigned long rpathPosition = 0; - unsigned long rpathSize = 0; - std::string rpathPrefix; - std::string rpathSuffix; + int rp_count = 0; + cmSystemToolsRPathInfo rp[2]; { // 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) + // Get the RPATH and RUNPATH entries from it. + int se_count = 0; + cmELF::StringEntry const* se[2] = {0, 0}; + const char* se_name[2] = {0, 0}; + if(cmELF::StringEntry const* se_rpath = elf.GetRPath()) { - se = elf.GetRunPath(); + se[se_count] = se_rpath; + se_name[se_count] = "RPATH"; + ++se_count; + } + if(cmELF::StringEntry const* se_runpath = elf.GetRunPath()) + { + se[se_count] = se_runpath; + se_name[se_count] = "RUNPATH"; + ++se_count; + } + if(se_count == 0) + { + if(newRPath.empty()) + { + // The new rpath is empty and there is no rpath anyway so it is + // okay. + return true; + } + else + { + if(emsg) + { + *emsg = "No valid ELF RPATH or RUNPATH entry exists in the file; "; + *emsg += elf.GetErrorMessage(); + } + return false; + } } - if(se) + for(int i=0; i < se_count; ++i) { + // If both RPATH and RUNPATH refer to the same string literal it + // needs to be changed only once. + if(rp_count && rp[0].Position == se[i]->Position) + { + continue; + } + // Make sure the current rpath contains the old rpath. - std::string::size_type pos = cmSystemToolsFindRPath(se->Value, oldRPath); + std::string::size_type pos = + cmSystemToolsFindRPath(se[i]->Value, oldRPath); if(pos == std::string::npos) { // If it contains the new rpath instead then it is okay. - if(cmSystemToolsFindRPath(se->Value, newRPath) != std::string::npos) + if(cmSystemToolsFindRPath(se[i]->Value, newRPath) != std::string::npos) { - return true; + continue; } if(emsg) { cmOStringStream e; - e << "The current RPATH is:\n" - << " " << se->Value << "\n" + e << "The current " << se_name[i] << " is:\n" + << " " << se[i]->Value << "\n" << "which does not contain:\n" << " " << oldRPath << "\n" << "as was expected."; @@ -2379,47 +2424,43 @@ bool cmSystemTools::ChangeRPath(std::string const& file, return false; } - // Store information about the entry. - rpathPosition = se->Position; - rpathSize = se->Size; + // Store information about the entry in the file. + rp[rp_count].Position = se[i]->Position; + rp[rp_count].Size = se[i]->Size; + rp[rp_count].Name = se_name[i]; - // Store the part of the path we must preserve. - rpathPrefix = se->Value.substr(0, pos); - rpathSuffix = se->Value.substr(pos+oldRPath.length(), oldRPath.npos); - } - else if(newRPath.empty()) - { - // The new rpath is empty and there is no rpath anyway so it is - // okay. - return true; - } - else - { - if(emsg) + // Construct the new value which preserves the part of the path + // not being changed. + rp[rp_count].Value = se[i]->Value.substr(0, pos); + rp[rp_count].Value += newRPath; + rp[rp_count].Value += se[i]->Value.substr(pos+oldRPath.length(), + oldRPath.npos); + + // Make sure there is enough room to store the new rpath and at + // least one null terminator. + if(rp[rp_count].Size < rp[rp_count].Value.length()+1) { - *emsg = "No valid ELF RPATH entry exists in the file; "; - *emsg += elf.GetErrorMessage(); + if(emsg) + { + *emsg = "The replacement path is too long for the "; + *emsg += se_name[i]; + *emsg += " entry."; + } + return false; } - return false; + + // This entry is ready for update. + ++rp_count; } } - // Compute the full new rpath. - std::string rpath = rpathPrefix; - rpath += newRPath; - rpath += rpathSuffix; - // Make sure there is enough room to store the new rpath and at - // least one null terminator. - if(rpathSize < rpath.length()+1) + // If no runtime path needs to be changed, we are done. + if(rp_count == 0) { - if(emsg) - { - *emsg = "The replacement RPATH is too long."; - } - return false; + return true; } - // Open the file for update and seek to the RPATH position. + // Open the file for update. std::ofstream f(file.c_str(), std::ios::in | std::ios::out | std::ios::binary); if(!f) @@ -2430,40 +2471,49 @@ bool cmSystemTools::ChangeRPath(std::string const& file, } return false; } - if(!f.seekp(rpathPosition)) + + // Store the new RPATH and RUNPATH strings. + for(int i=0; i < rp_count; ++i) { - if(emsg) + // Seek to the RPATH position. + if(!f.seekp(rp[i].Position)) { - *emsg = "Error seeking to RPATH position."; + if(emsg) + { + *emsg = "Error seeking to "; + *emsg += rp[i].Name; + *emsg += " position."; + } + return false; } - return false; - } - // Write the new rpath. Follow it with enough null terminators to - // fill the string table entry. - f << rpath; - for(unsigned long i=rpath.length(); i < rpathSize; ++i) - { - f << '\0'; - } + // Write the new rpath. Follow it with enough null terminators to + // fill the string table entry. + f << rp[i].Value; + for(unsigned long j=rp[i].Value.length(); j < rp[i].Size; ++j) + { + f << '\0'; + } - // Make sure everything was okay. - if(f) - { - if(changed) + // Make sure it wrote correctly. + if(!f) { - *changed = true; + if(emsg) + { + *emsg = "Error writing the new "; + *emsg += rp[i].Name; + *emsg += " string to the file."; + } + return false; } - return true; } - else + + // Everything was updated successfully. + if(changed) { - if(emsg) - { - *emsg = "Error writing the new rpath to the file."; - } - return false; + *changed = true; } + return true; #else (void)file; (void)oldRPath; @@ -2475,57 +2525,95 @@ bool cmSystemTools::ChangeRPath(std::string const& file, } //---------------------------------------------------------------------------- -bool cmSystemTools::RemoveRPath(std::string const& file, std::string* emsg) +bool cmSystemTools::RemoveRPath(std::string const& file, std::string* emsg, + bool* removed) { #if defined(CMAKE_USE_ELF_PARSER) - unsigned long rpathPosition = 0; - unsigned long rpathSize = 0; - unsigned long rpathEntryPosition = 0; + if(removed) + { + *removed = false; + } + int zeroCount = 0; + unsigned long zeroPosition[2] = {0,0}; + unsigned long zeroSize[2] = {0,0}; + unsigned long bytesBegin = 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) + // Get the RPATH and RUNPATH entries from it and sort them by index + // in the dynamic section header. + int se_count = 0; + cmELF::StringEntry const* se[2] = {0, 0}; + if(cmELF::StringEntry const* se_rpath = elf.GetRPath()) { - se = elf.GetRunPath(); + se[se_count++] = se_rpath; } - - if(se) + if(cmELF::StringEntry const* se_runpath = elf.GetRunPath()) { - // Store information about the entry. - rpathPosition = se->Position; - rpathSize = se->Size; - rpathEntryPosition = elf.GetDynamicEntryPosition(se->IndexInSection); + se[se_count++] = se_runpath; + } + if(se_count == 0) + { + // There is no RPATH or RUNPATH anyway. + return true; + } + if(se_count == 2 && se[1]->IndexInSection < se[0]->IndexInSection) + { + cmsys_stl::swap(se[0], se[1]); + } - // 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) + // Get the size of the dynamic section header. + 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) { - // 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; + *emsg = "DYNAMIC section contains a DT_NULL before the end."; } - unsigned long nullEntryPosition = elf.GetDynamicEntryPosition(count); + return false; + } + + // Save information about the string entries to be zeroed. + zeroCount = se_count; + for(int i=0; i < se_count; ++i) + { + zeroPosition[i] = se[i]->Position; + zeroSize[i] = se[i]->Size; + } + + // Get the range of file positions corresponding to each entry and + // the rest of the table after them. + unsigned long entryBegin[3] = {0,0,0}; + unsigned long entryEnd[2] = {0,0}; + for(int i=0; i < se_count; ++i) + { + entryBegin[i] = elf.GetDynamicEntryPosition(se[i]->IndexInSection); + entryEnd[i] = elf.GetDynamicEntryPosition(se[i]->IndexInSection+1); + } + entryBegin[se_count] = elf.GetDynamicEntryPosition(count); + + // The data are to be written over the old table entries starting at + // the first one being removed. + bytesBegin = entryBegin[0]; + unsigned long bytesEnd = entryBegin[se_count]; - // Allocate and fill a buffer with zeros. - bytes.resize(nullEntryPosition - rpathEntryPosition, 0); + // Allocate a buffer to hold the part of the file to be written. + // Initialize it with zeros. + bytes.resize(bytesEnd - bytesBegin, 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])) + // 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. + char* data = &bytes[0]; + for(int i=0; i < se_count; ++i) + { + // Read data between the entries being removed. + unsigned long sz = entryBegin[i+1] - entryEnd[i]; + if(sz > 0 && !elf.ReadBytes(entryEnd[i], sz, data)) { if(emsg) { @@ -2533,11 +2621,7 @@ bool cmSystemTools::RemoveRPath(std::string const& file, std::string* emsg) } return false; } - } - else - { - // There is no RPATH or RUNPATH anyway. - return true; + data += sz; } } @@ -2554,7 +2638,7 @@ bool cmSystemTools::RemoveRPath(std::string const& file, std::string* emsg) } // Write the new DYNAMIC table header. - if(!f.seekp(rpathEntryPosition)) + if(!f.seekp(bytesBegin)) { if(emsg) { @@ -2571,36 +2655,41 @@ bool cmSystemTools::RemoveRPath(std::string const& file, std::string* emsg) return false; } - // Fill the RPATH string with zero bytes. - if(!f.seekp(rpathPosition)) + // Fill the RPATH and RUNPATH strings with zero bytes. + for(int i=0; i < zeroCount; ++i) { - if(emsg) + if(!f.seekp(zeroPosition[i])) { - *emsg = "Error seeking to RPATH position."; + if(emsg) + { + *emsg = "Error seeking to RPATH position."; + } + return false; + } + for(unsigned long j=0; j < zeroSize[i]; ++j) + { + f << '\0'; + } + if(!f) + { + if(emsg) + { + *emsg = "Error writing the empty rpath string to the file."; + } + return false; } - return false; - } - for(unsigned long i=0; i < rpathSize; ++i) - { - f << '\0'; } - // Make sure everything was okay. - if(f) - { - return true; - } - else + // Everything was updated successfully. + if(removed) { - if(emsg) - { - *emsg = "Error writing the empty rpath to the file."; - } - return false; + *removed = true; } + return true; #else (void)file; (void)emsg; + (void)removed; return false; #endif } diff --git cmake-2.6.1-orig/Source/cmSystemTools.h cmake-2.6.1/Source/cmSystemTools.h index 493ff71..1ff12bf 100644 --- cmake-2.6.1-orig/Source/cmSystemTools.h +++ cmake-2.6.1/Source/cmSystemTools.h @@ -396,7 +396,8 @@ public: bool* changed = 0); /** Try to remove the RPATH from an ELF binary. */ - static bool RemoveRPath(std::string const& file, std::string* emsg = 0); + static bool RemoveRPath(std::string const& file, std::string* emsg = 0, + bool* removed = 0); /** Check whether the RPATH in an ELF binary contains the path given. */