BUG: Update both RPATH and RUNPATH entries
During installation the RPATH and RUNPATH entries of ELF binaries are edited to match the user specification. Usually either one entry is present or both entries refer to the same string literal. In the case that they are both present and refer to separate string literals we need to update both. I have never seen this case in practice, but we should do this just in case.
This commit is contained in:
parent
2a85f8289f
commit
485c3faea7
@ -2329,6 +2329,16 @@ std::string::size_type cmSystemToolsFindRPath(std::string const& have,
|
|||||||
}
|
}
|
||||||
#endif
|
#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,
|
bool cmSystemTools::ChangeRPath(std::string const& file,
|
||||||
std::string const& oldRPath,
|
std::string const& oldRPath,
|
||||||
@ -2341,37 +2351,71 @@ bool cmSystemTools::ChangeRPath(std::string const& file,
|
|||||||
{
|
{
|
||||||
*changed = false;
|
*changed = false;
|
||||||
}
|
}
|
||||||
unsigned long rpathPosition = 0;
|
int rp_count = 0;
|
||||||
unsigned long rpathSize = 0;
|
cmSystemToolsRPathInfo rp[2];
|
||||||
std::string rpathPrefix;
|
|
||||||
std::string rpathSuffix;
|
|
||||||
{
|
{
|
||||||
// Parse the ELF binary.
|
// Parse the ELF binary.
|
||||||
cmELF elf(file.c_str());
|
cmELF elf(file.c_str());
|
||||||
|
|
||||||
// Get the RPATH or RUNPATH entry from it.
|
// Get the RPATH and RUNPATH entries from it.
|
||||||
cmELF::StringEntry const* se = elf.GetRPath();
|
int se_count = 0;
|
||||||
if(!se)
|
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.
|
// 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(pos == std::string::npos)
|
||||||
{
|
{
|
||||||
// If it contains the new rpath instead then it is okay.
|
// 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)
|
if(emsg)
|
||||||
{
|
{
|
||||||
cmOStringStream e;
|
cmOStringStream e;
|
||||||
e << "The current RPATH is:\n"
|
e << "The current " << se_name[i] << " is:\n"
|
||||||
<< " " << se->Value << "\n"
|
<< " " << se[i]->Value << "\n"
|
||||||
<< "which does not contain:\n"
|
<< "which does not contain:\n"
|
||||||
<< " " << oldRPath << "\n"
|
<< " " << oldRPath << "\n"
|
||||||
<< "as was expected.";
|
<< "as was expected.";
|
||||||
@ -2380,47 +2424,43 @@ bool cmSystemTools::ChangeRPath(std::string const& file,
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Store information about the entry.
|
// Store information about the entry in the file.
|
||||||
rpathPosition = se->Position;
|
rp[rp_count].Position = se[i]->Position;
|
||||||
rpathSize = se->Size;
|
rp[rp_count].Size = se[i]->Size;
|
||||||
|
rp[rp_count].Name = se_name[i];
|
||||||
|
|
||||||
// Store the part of the path we must preserve.
|
// Construct the new value which preserves the part of the path
|
||||||
rpathPrefix = se->Value.substr(0, pos);
|
// not being changed.
|
||||||
rpathSuffix = se->Value.substr(pos+oldRPath.length(), oldRPath.npos);
|
rp[rp_count].Value = se[i]->Value.substr(0, pos);
|
||||||
}
|
rp[rp_count].Value += newRPath;
|
||||||
else if(newRPath.empty())
|
rp[rp_count].Value += se[i]->Value.substr(pos+oldRPath.length(),
|
||||||
{
|
oldRPath.npos);
|
||||||
// The new rpath is empty and there is no rpath anyway so it is
|
|
||||||
// okay.
|
// Make sure there is enough room to store the new rpath and at
|
||||||
return true;
|
// least one null terminator.
|
||||||
}
|
if(rp[rp_count].Size < rp[rp_count].Value.length()+1)
|
||||||
else
|
|
||||||
{
|
|
||||||
if(emsg)
|
|
||||||
{
|
{
|
||||||
*emsg = "No valid ELF RPATH entry exists in the file; ";
|
if(emsg)
|
||||||
*emsg += elf.GetErrorMessage();
|
{
|
||||||
|
*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
|
// If no runtime path needs to be changed, we are done.
|
||||||
// least one null terminator.
|
if(rp_count == 0)
|
||||||
if(rpathSize < rpath.length()+1)
|
|
||||||
{
|
{
|
||||||
if(emsg)
|
return true;
|
||||||
{
|
|
||||||
*emsg = "The replacement RPATH is too long.";
|
|
||||||
}
|
|
||||||
return false;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Open the file for update and seek to the RPATH position.
|
// Open the file for update.
|
||||||
std::ofstream f(file.c_str(),
|
std::ofstream f(file.c_str(),
|
||||||
std::ios::in | std::ios::out | std::ios::binary);
|
std::ios::in | std::ios::out | std::ios::binary);
|
||||||
if(!f)
|
if(!f)
|
||||||
@ -2431,40 +2471,49 @@ bool cmSystemTools::ChangeRPath(std::string const& file,
|
|||||||
}
|
}
|
||||||
return false;
|
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;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 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 it wrote correctly.
|
||||||
|
if(!f)
|
||||||
|
{
|
||||||
|
if(emsg)
|
||||||
|
{
|
||||||
|
*emsg = "Error writing the new ";
|
||||||
|
*emsg += rp[i].Name;
|
||||||
|
*emsg += " string to the file.";
|
||||||
|
}
|
||||||
|
return false;
|
||||||
}
|
}
|
||||||
return false;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Write the new rpath. Follow it with enough null terminators to
|
// Everything was updated successfully.
|
||||||
// fill the string table entry.
|
if(changed)
|
||||||
f << rpath;
|
|
||||||
for(unsigned long i=rpath.length(); i < rpathSize; ++i)
|
|
||||||
{
|
{
|
||||||
f << '\0';
|
*changed = true;
|
||||||
}
|
|
||||||
|
|
||||||
// Make sure everything was okay.
|
|
||||||
if(f)
|
|
||||||
{
|
|
||||||
if(changed)
|
|
||||||
{
|
|
||||||
*changed = true;
|
|
||||||
}
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
if(emsg)
|
|
||||||
{
|
|
||||||
*emsg = "Error writing the new rpath to the file.";
|
|
||||||
}
|
|
||||||
return false;
|
|
||||||
}
|
}
|
||||||
|
return true;
|
||||||
#else
|
#else
|
||||||
(void)file;
|
(void)file;
|
||||||
(void)oldRPath;
|
(void)oldRPath;
|
||||||
|
Loading…
x
Reference in New Issue
Block a user