|
|
#if defined(CMAKE_BUILD_WITH_CMAKE) | #if defined(CMAKE_BUILD_WITH_CMAKE) |
# include <cmsys/Terminal.h> | # include <cmsys/Terminal.h> |
#endif | #endif |
|
#include <cmsys/stl/algorithm> |
| |
#if defined(_WIN32) | #if defined(_WIN32) |
# include <windows.h> | # include <windows.h> |
|
Lines 2328-2333
std::string::size_type cmSystemToolsFindRPath(std::string const& have,
|
Link Here
|
|---|
|
} | } |
#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, |
|
Lines 2340-2376
bool cmSystemTools::ChangeRPath(std::string const& file,
|
Link Here
|
|---|
|
{ | { |
*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."; |
|
Lines 2379-2425
bool cmSystemTools::ChangeRPath(std::string const& file,
|
Link Here
|
|---|
|
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) |
|
Lines 2430-2469
bool cmSystemTools::ChangeRPath(std::string const& file,
|
Link Here
|
|---|
|
} | } |
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; |
} | } |
return false; |
|
} |
|
| |
// Write the new rpath. Follow it with enough null terminators to |
// Write the new rpath. Follow it with enough null terminators to |
// fill the string table entry. |
// fill the string table entry. |
f << rpath; |
f << rp[i].Value; |
for(unsigned long i=rpath.length(); i < rpathSize; ++i) |
for(unsigned long j=rp[i].Value.length(); j < rp[i].Size; ++j) |
{ |
{ |
f << '\0'; |
f << '\0'; |
} |
} |
| |
// Make sure everything was okay. |
// Make sure it wrote correctly. |
if(f) |
if(!f) |
{ |
|
if(changed) |
|
{ | { |
*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) |
*changed = true; |
{ |
|
*emsg = "Error writing the new rpath to the file."; |
|
} |
|
return false; |
|
} | } |
|
return true; |
#else | #else |
(void)file; | (void)file; |
(void)oldRPath; | (void)oldRPath; |
|
Lines 2475-2531
bool cmSystemTools::ChangeRPath(std::string const& file,
|
Link Here
|
|---|
|
} | } |
| |
//---------------------------------------------------------------------------- | //---------------------------------------------------------------------------- |
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) | #if defined(CMAKE_USE_ELF_PARSER) |
unsigned long rpathPosition = 0; |
if(removed) |
unsigned long rpathSize = 0; |
{ |
unsigned long rpathEntryPosition = 0; |
*removed = false; |
|
} |
|
int zeroCount = 0; |
|
unsigned long zeroPosition[2] = {0,0}; |
|
unsigned long zeroSize[2] = {0,0}; |
|
unsigned long bytesBegin = 0; |
std::vector<char> bytes; | std::vector<char> bytes; |
{ | { |
// 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 and sort them by index |
cmELF::StringEntry const* se = elf.GetRPath(); |
// in the dynamic section header. |
if(!se) |
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(cmELF::StringEntry const* se_runpath = elf.GetRunPath()) |
if(se) |
|
{ | { |
// Store information about the entry. |
se[se_count++] = se_runpath; |
rpathPosition = se->Position; |
} |
rpathSize = se->Size; |
if(se_count == 0) |
rpathEntryPosition = elf.GetDynamicEntryPosition(se->IndexInSection); |
{ |
|
// 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 |
// Get the size of the dynamic section header. |
// after the RPATH entry. |
unsigned int count = elf.GetDynamicEntryCount(); |
unsigned long nextEntryPosition = |
if(count == 0) |
elf.GetDynamicEntryPosition(se->IndexInSection+1); |
{ |
unsigned int count = elf.GetDynamicEntryCount(); |
// This should happen only for invalid ELF files where a DT_NULL |
if(count == 0) |
// appears before the end of the table. |
|
if(emsg) |
{ | { |
// This should happen only for invalid ELF files where a DT_NULL |
*emsg = "DYNAMIC section contains a DT_NULL before the end."; |
// 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); |
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. |
// Allocate a buffer to hold the part of the file to be written. |
bytes.resize(nullEntryPosition - rpathEntryPosition, 0); |
// Initialize it with zeros. |
|
bytes.resize(bytesEnd - bytesBegin, 0); |
| |
// Read the part of the DYNAMIC section header that will move. |
// Read the part of the DYNAMIC section header that will move. |
// The remainder of the buffer will be left with zeros which |
// The remainder of the buffer will be left with zeros which |
// represent a DT_NULL entry. |
// represent a DT_NULL entry. |
if(!elf.ReadBytes(nextEntryPosition, |
char* data = &bytes[0]; |
nullEntryPosition - nextEntryPosition, |
for(int i=0; i < se_count; ++i) |
&bytes[0])) |
{ |
|
// 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) | if(emsg) |
{ | { |
|
Lines 2533-2543
bool cmSystemTools::RemoveRPath(std::string const& file, std::string* emsg)
|
Link Here
|
|---|
|
} | } |
return false; | return false; |
} | } |
} |
data += sz; |
else |
|
{ |
|
// There is no RPATH or RUNPATH anyway. |
|
return true; |
|
} | } |
} | } |
| |
|
Lines 2554-2560
bool cmSystemTools::RemoveRPath(std::string const& file, std::string* emsg)
|
Link Here
|
|---|
|
} | } |
| |
// Write the new DYNAMIC table header. | // Write the new DYNAMIC table header. |
if(!f.seekp(rpathEntryPosition)) |
if(!f.seekp(bytesBegin)) |
{ | { |
if(emsg) | if(emsg) |
{ | { |
|
Lines 2571-2606
bool cmSystemTools::RemoveRPath(std::string const& file, std::string* emsg)
|
Link Here
|
|---|
|
return false; | return false; |
} | } |
| |
// Fill the RPATH string with zero bytes. |
// Fill the RPATH and RUNPATH strings with zero bytes. |
if(!f.seekp(rpathPosition)) |
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. |
// Everything was updated successfully. |
if(f) |
if(removed) |
{ |
|
return true; |
|
} |
|
else |
|
{ | { |
if(emsg) |
*removed = true; |
{ |
|
*emsg = "Error writing the empty rpath to the file."; |
|
} |
|
return false; |
|
} | } |
|
return true; |
#else | #else |
(void)file; | (void)file; |
(void)emsg; | (void)emsg; |
|
(void)removed; |
return false; | return false; |
#endif | #endif |
} | } |