Lines 26-31
Link Here
|
26 |
#if defined(CMAKE_BUILD_WITH_CMAKE) |
26 |
#if defined(CMAKE_BUILD_WITH_CMAKE) |
27 |
# include <cmsys/Terminal.h> |
27 |
# include <cmsys/Terminal.h> |
28 |
#endif |
28 |
#endif |
|
|
29 |
#include <cmsys/stl/algorithm> |
29 |
|
30 |
|
30 |
#if defined(_WIN32) |
31 |
#if defined(_WIN32) |
31 |
# include <windows.h> |
32 |
# include <windows.h> |
Lines 2328-2333
std::string::size_type cmSystemToolsFindRPath(std::string const& have,
Link Here
|
2328 |
} |
2329 |
} |
2329 |
#endif |
2330 |
#endif |
2330 |
|
2331 |
|
|
|
2332 |
#if defined(CMAKE_USE_ELF_PARSER) |
2333 |
struct cmSystemToolsRPathInfo |
2334 |
{ |
2335 |
unsigned long Position; |
2336 |
unsigned long Size; |
2337 |
std::string Name; |
2338 |
std::string Value; |
2339 |
}; |
2340 |
#endif |
2341 |
|
2331 |
//---------------------------------------------------------------------------- |
2342 |
//---------------------------------------------------------------------------- |
2332 |
bool cmSystemTools::ChangeRPath(std::string const& file, |
2343 |
bool cmSystemTools::ChangeRPath(std::string const& file, |
2333 |
std::string const& oldRPath, |
2344 |
std::string const& oldRPath, |
Lines 2340-2376
bool cmSystemTools::ChangeRPath(std::string const& file,
Link Here
|
2340 |
{ |
2351 |
{ |
2341 |
*changed = false; |
2352 |
*changed = false; |
2342 |
} |
2353 |
} |
2343 |
unsigned long rpathPosition = 0; |
2354 |
int rp_count = 0; |
2344 |
unsigned long rpathSize = 0; |
2355 |
cmSystemToolsRPathInfo rp[2]; |
2345 |
std::string rpathPrefix; |
|
|
2346 |
std::string rpathSuffix; |
2347 |
{ |
2356 |
{ |
2348 |
// Parse the ELF binary. |
2357 |
// Parse the ELF binary. |
2349 |
cmELF elf(file.c_str()); |
2358 |
cmELF elf(file.c_str()); |
2350 |
|
2359 |
|
2351 |
// Get the RPATH or RUNPATH entry from it. |
2360 |
// Get the RPATH and RUNPATH entries from it. |
2352 |
cmELF::StringEntry const* se = elf.GetRPath(); |
2361 |
int se_count = 0; |
2353 |
if(!se) |
2362 |
cmELF::StringEntry const* se[2] = {0, 0}; |
|
|
2363 |
const char* se_name[2] = {0, 0}; |
2364 |
if(cmELF::StringEntry const* se_rpath = elf.GetRPath()) |
2354 |
{ |
2365 |
{ |
2355 |
se = elf.GetRunPath(); |
2366 |
se[se_count] = se_rpath; |
|
|
2367 |
se_name[se_count] = "RPATH"; |
2368 |
++se_count; |
2369 |
} |
2370 |
if(cmELF::StringEntry const* se_runpath = elf.GetRunPath()) |
2371 |
{ |
2372 |
se[se_count] = se_runpath; |
2373 |
se_name[se_count] = "RUNPATH"; |
2374 |
++se_count; |
2375 |
} |
2376 |
if(se_count == 0) |
2377 |
{ |
2378 |
if(newRPath.empty()) |
2379 |
{ |
2380 |
// The new rpath is empty and there is no rpath anyway so it is |
2381 |
// okay. |
2382 |
return true; |
2383 |
} |
2384 |
else |
2385 |
{ |
2386 |
if(emsg) |
2387 |
{ |
2388 |
*emsg = "No valid ELF RPATH or RUNPATH entry exists in the file; "; |
2389 |
*emsg += elf.GetErrorMessage(); |
2390 |
} |
2391 |
return false; |
2392 |
} |
2356 |
} |
2393 |
} |
2357 |
|
2394 |
|
2358 |
if(se) |
2395 |
for(int i=0; i < se_count; ++i) |
2359 |
{ |
2396 |
{ |
|
|
2397 |
// If both RPATH and RUNPATH refer to the same string literal it |
2398 |
// needs to be changed only once. |
2399 |
if(rp_count && rp[0].Position == se[i]->Position) |
2400 |
{ |
2401 |
continue; |
2402 |
} |
2403 |
|
2360 |
// Make sure the current rpath contains the old rpath. |
2404 |
// Make sure the current rpath contains the old rpath. |
2361 |
std::string::size_type pos = cmSystemToolsFindRPath(se->Value, oldRPath); |
2405 |
std::string::size_type pos = |
|
|
2406 |
cmSystemToolsFindRPath(se[i]->Value, oldRPath); |
2362 |
if(pos == std::string::npos) |
2407 |
if(pos == std::string::npos) |
2363 |
{ |
2408 |
{ |
2364 |
// If it contains the new rpath instead then it is okay. |
2409 |
// If it contains the new rpath instead then it is okay. |
2365 |
if(cmSystemToolsFindRPath(se->Value, newRPath) != std::string::npos) |
2410 |
if(cmSystemToolsFindRPath(se[i]->Value, newRPath) != std::string::npos) |
2366 |
{ |
2411 |
{ |
2367 |
return true; |
2412 |
continue; |
2368 |
} |
2413 |
} |
2369 |
if(emsg) |
2414 |
if(emsg) |
2370 |
{ |
2415 |
{ |
2371 |
cmOStringStream e; |
2416 |
cmOStringStream e; |
2372 |
e << "The current RPATH is:\n" |
2417 |
e << "The current " << se_name[i] << " is:\n" |
2373 |
<< " " << se->Value << "\n" |
2418 |
<< " " << se[i]->Value << "\n" |
2374 |
<< "which does not contain:\n" |
2419 |
<< "which does not contain:\n" |
2375 |
<< " " << oldRPath << "\n" |
2420 |
<< " " << oldRPath << "\n" |
2376 |
<< "as was expected."; |
2421 |
<< "as was expected."; |
Lines 2379-2425
bool cmSystemTools::ChangeRPath(std::string const& file,
Link Here
|
2379 |
return false; |
2424 |
return false; |
2380 |
} |
2425 |
} |
2381 |
|
2426 |
|
2382 |
// Store information about the entry. |
2427 |
// Store information about the entry in the file. |
2383 |
rpathPosition = se->Position; |
2428 |
rp[rp_count].Position = se[i]->Position; |
2384 |
rpathSize = se->Size; |
2429 |
rp[rp_count].Size = se[i]->Size; |
|
|
2430 |
rp[rp_count].Name = se_name[i]; |
2385 |
|
2431 |
|
2386 |
// Store the part of the path we must preserve. |
2432 |
// Construct the new value which preserves the part of the path |
2387 |
rpathPrefix = se->Value.substr(0, pos); |
2433 |
// not being changed. |
2388 |
rpathSuffix = se->Value.substr(pos+oldRPath.length(), oldRPath.npos); |
2434 |
rp[rp_count].Value = se[i]->Value.substr(0, pos); |
2389 |
} |
2435 |
rp[rp_count].Value += newRPath; |
2390 |
else if(newRPath.empty()) |
2436 |
rp[rp_count].Value += se[i]->Value.substr(pos+oldRPath.length(), |
2391 |
{ |
2437 |
oldRPath.npos); |
2392 |
// The new rpath is empty and there is no rpath anyway so it is |
2438 |
|
2393 |
// okay. |
2439 |
// Make sure there is enough room to store the new rpath and at |
2394 |
return true; |
2440 |
// least one null terminator. |
2395 |
} |
2441 |
if(rp[rp_count].Size < rp[rp_count].Value.length()+1) |
2396 |
else |
|
|
2397 |
{ |
2398 |
if(emsg) |
2399 |
{ |
2442 |
{ |
2400 |
*emsg = "No valid ELF RPATH entry exists in the file; "; |
2443 |
if(emsg) |
2401 |
*emsg += elf.GetErrorMessage(); |
2444 |
{ |
|
|
2445 |
*emsg = "The replacement path is too long for the "; |
2446 |
*emsg += se_name[i]; |
2447 |
*emsg += " entry."; |
2448 |
} |
2449 |
return false; |
2402 |
} |
2450 |
} |
2403 |
return false; |
2451 |
|
|
|
2452 |
// This entry is ready for update. |
2453 |
++rp_count; |
2404 |
} |
2454 |
} |
2405 |
} |
2455 |
} |
2406 |
// Compute the full new rpath. |
|
|
2407 |
std::string rpath = rpathPrefix; |
2408 |
rpath += newRPath; |
2409 |
rpath += rpathSuffix; |
2410 |
|
2456 |
|
2411 |
// Make sure there is enough room to store the new rpath and at |
2457 |
// If no runtime path needs to be changed, we are done. |
2412 |
// least one null terminator. |
2458 |
if(rp_count == 0) |
2413 |
if(rpathSize < rpath.length()+1) |
|
|
2414 |
{ |
2459 |
{ |
2415 |
if(emsg) |
2460 |
return true; |
2416 |
{ |
|
|
2417 |
*emsg = "The replacement RPATH is too long."; |
2418 |
} |
2419 |
return false; |
2420 |
} |
2461 |
} |
2421 |
|
2462 |
|
2422 |
// Open the file for update and seek to the RPATH position. |
2463 |
// Open the file for update. |
2423 |
std::ofstream f(file.c_str(), |
2464 |
std::ofstream f(file.c_str(), |
2424 |
std::ios::in | std::ios::out | std::ios::binary); |
2465 |
std::ios::in | std::ios::out | std::ios::binary); |
2425 |
if(!f) |
2466 |
if(!f) |
Lines 2430-2469
bool cmSystemTools::ChangeRPath(std::string const& file,
Link Here
|
2430 |
} |
2471 |
} |
2431 |
return false; |
2472 |
return false; |
2432 |
} |
2473 |
} |
2433 |
if(!f.seekp(rpathPosition)) |
2474 |
|
|
|
2475 |
// Store the new RPATH and RUNPATH strings. |
2476 |
for(int i=0; i < rp_count; ++i) |
2434 |
{ |
2477 |
{ |
2435 |
if(emsg) |
2478 |
// Seek to the RPATH position. |
|
|
2479 |
if(!f.seekp(rp[i].Position)) |
2436 |
{ |
2480 |
{ |
2437 |
*emsg = "Error seeking to RPATH position."; |
2481 |
if(emsg) |
|
|
2482 |
{ |
2483 |
*emsg = "Error seeking to "; |
2484 |
*emsg += rp[i].Name; |
2485 |
*emsg += " position."; |
2486 |
} |
2487 |
return false; |
2438 |
} |
2488 |
} |
2439 |
return false; |
|
|
2440 |
} |
2441 |
|
2489 |
|
2442 |
// Write the new rpath. Follow it with enough null terminators to |
2490 |
// Write the new rpath. Follow it with enough null terminators to |
2443 |
// fill the string table entry. |
2491 |
// fill the string table entry. |
2444 |
f << rpath; |
2492 |
f << rp[i].Value; |
2445 |
for(unsigned long i=rpath.length(); i < rpathSize; ++i) |
2493 |
for(unsigned long j=rp[i].Value.length(); j < rp[i].Size; ++j) |
2446 |
{ |
2494 |
{ |
2447 |
f << '\0'; |
2495 |
f << '\0'; |
2448 |
} |
2496 |
} |
2449 |
|
2497 |
|
2450 |
// Make sure everything was okay. |
2498 |
// Make sure it wrote correctly. |
2451 |
if(f) |
2499 |
if(!f) |
2452 |
{ |
|
|
2453 |
if(changed) |
2454 |
{ |
2500 |
{ |
2455 |
*changed = true; |
2501 |
if(emsg) |
|
|
2502 |
{ |
2503 |
*emsg = "Error writing the new "; |
2504 |
*emsg += rp[i].Name; |
2505 |
*emsg += " string to the file."; |
2506 |
} |
2507 |
return false; |
2456 |
} |
2508 |
} |
2457 |
return true; |
|
|
2458 |
} |
2509 |
} |
2459 |
else |
2510 |
|
|
|
2511 |
// Everything was updated successfully. |
2512 |
if(changed) |
2460 |
{ |
2513 |
{ |
2461 |
if(emsg) |
2514 |
*changed = true; |
2462 |
{ |
|
|
2463 |
*emsg = "Error writing the new rpath to the file."; |
2464 |
} |
2465 |
return false; |
2466 |
} |
2515 |
} |
|
|
2516 |
return true; |
2467 |
#else |
2517 |
#else |
2468 |
(void)file; |
2518 |
(void)file; |
2469 |
(void)oldRPath; |
2519 |
(void)oldRPath; |
Lines 2475-2531
bool cmSystemTools::ChangeRPath(std::string const& file,
Link Here
|
2475 |
} |
2525 |
} |
2476 |
|
2526 |
|
2477 |
//---------------------------------------------------------------------------- |
2527 |
//---------------------------------------------------------------------------- |
2478 |
bool cmSystemTools::RemoveRPath(std::string const& file, std::string* emsg) |
2528 |
bool cmSystemTools::RemoveRPath(std::string const& file, std::string* emsg, |
|
|
2529 |
bool* removed) |
2479 |
{ |
2530 |
{ |
2480 |
#if defined(CMAKE_USE_ELF_PARSER) |
2531 |
#if defined(CMAKE_USE_ELF_PARSER) |
2481 |
unsigned long rpathPosition = 0; |
2532 |
if(removed) |
2482 |
unsigned long rpathSize = 0; |
2533 |
{ |
2483 |
unsigned long rpathEntryPosition = 0; |
2534 |
*removed = false; |
|
|
2535 |
} |
2536 |
int zeroCount = 0; |
2537 |
unsigned long zeroPosition[2] = {0,0}; |
2538 |
unsigned long zeroSize[2] = {0,0}; |
2539 |
unsigned long bytesBegin = 0; |
2484 |
std::vector<char> bytes; |
2540 |
std::vector<char> bytes; |
2485 |
{ |
2541 |
{ |
2486 |
// Parse the ELF binary. |
2542 |
// Parse the ELF binary. |
2487 |
cmELF elf(file.c_str()); |
2543 |
cmELF elf(file.c_str()); |
2488 |
|
2544 |
|
2489 |
// Get the RPATH or RUNPATH entry from it. |
2545 |
// Get the RPATH and RUNPATH entries from it and sort them by index |
2490 |
cmELF::StringEntry const* se = elf.GetRPath(); |
2546 |
// in the dynamic section header. |
2491 |
if(!se) |
2547 |
int se_count = 0; |
|
|
2548 |
cmELF::StringEntry const* se[2] = {0, 0}; |
2549 |
if(cmELF::StringEntry const* se_rpath = elf.GetRPath()) |
2492 |
{ |
2550 |
{ |
2493 |
se = elf.GetRunPath(); |
2551 |
se[se_count++] = se_rpath; |
2494 |
} |
2552 |
} |
2495 |
|
2553 |
if(cmELF::StringEntry const* se_runpath = elf.GetRunPath()) |
2496 |
if(se) |
|
|
2497 |
{ |
2554 |
{ |
2498 |
// Store information about the entry. |
2555 |
se[se_count++] = se_runpath; |
2499 |
rpathPosition = se->Position; |
2556 |
} |
2500 |
rpathSize = se->Size; |
2557 |
if(se_count == 0) |
2501 |
rpathEntryPosition = elf.GetDynamicEntryPosition(se->IndexInSection); |
2558 |
{ |
|
|
2559 |
// There is no RPATH or RUNPATH anyway. |
2560 |
return true; |
2561 |
} |
2562 |
if(se_count == 2 && se[1]->IndexInSection < se[0]->IndexInSection) |
2563 |
{ |
2564 |
cmsys_stl::swap(se[0], se[1]); |
2565 |
} |
2502 |
|
2566 |
|
2503 |
// Get the file range containing the rest of the DYNAMIC table |
2567 |
// Get the size of the dynamic section header. |
2504 |
// after the RPATH entry. |
2568 |
unsigned int count = elf.GetDynamicEntryCount(); |
2505 |
unsigned long nextEntryPosition = |
2569 |
if(count == 0) |
2506 |
elf.GetDynamicEntryPosition(se->IndexInSection+1); |
2570 |
{ |
2507 |
unsigned int count = elf.GetDynamicEntryCount(); |
2571 |
// This should happen only for invalid ELF files where a DT_NULL |
2508 |
if(count == 0) |
2572 |
// appears before the end of the table. |
|
|
2573 |
if(emsg) |
2509 |
{ |
2574 |
{ |
2510 |
// This should happen only for invalid ELF files where a DT_NULL |
2575 |
*emsg = "DYNAMIC section contains a DT_NULL before the end."; |
2511 |
// appears before the end of the table. |
|
|
2512 |
if(emsg) |
2513 |
{ |
2514 |
*emsg = "DYNAMIC section contains a DT_NULL before the end."; |
2515 |
} |
2516 |
return false; |
2517 |
} |
2576 |
} |
2518 |
unsigned long nullEntryPosition = elf.GetDynamicEntryPosition(count); |
2577 |
return false; |
|
|
2578 |
} |
2579 |
|
2580 |
// Save information about the string entries to be zeroed. |
2581 |
zeroCount = se_count; |
2582 |
for(int i=0; i < se_count; ++i) |
2583 |
{ |
2584 |
zeroPosition[i] = se[i]->Position; |
2585 |
zeroSize[i] = se[i]->Size; |
2586 |
} |
2587 |
|
2588 |
// Get the range of file positions corresponding to each entry and |
2589 |
// the rest of the table after them. |
2590 |
unsigned long entryBegin[3] = {0,0,0}; |
2591 |
unsigned long entryEnd[2] = {0,0}; |
2592 |
for(int i=0; i < se_count; ++i) |
2593 |
{ |
2594 |
entryBegin[i] = elf.GetDynamicEntryPosition(se[i]->IndexInSection); |
2595 |
entryEnd[i] = elf.GetDynamicEntryPosition(se[i]->IndexInSection+1); |
2596 |
} |
2597 |
entryBegin[se_count] = elf.GetDynamicEntryPosition(count); |
2598 |
|
2599 |
// The data are to be written over the old table entries starting at |
2600 |
// the first one being removed. |
2601 |
bytesBegin = entryBegin[0]; |
2602 |
unsigned long bytesEnd = entryBegin[se_count]; |
2519 |
|
2603 |
|
2520 |
// Allocate and fill a buffer with zeros. |
2604 |
// Allocate a buffer to hold the part of the file to be written. |
2521 |
bytes.resize(nullEntryPosition - rpathEntryPosition, 0); |
2605 |
// Initialize it with zeros. |
|
|
2606 |
bytes.resize(bytesEnd - bytesBegin, 0); |
2522 |
|
2607 |
|
2523 |
// Read the part of the DYNAMIC section header that will move. |
2608 |
// Read the part of the DYNAMIC section header that will move. |
2524 |
// The remainder of the buffer will be left with zeros which |
2609 |
// The remainder of the buffer will be left with zeros which |
2525 |
// represent a DT_NULL entry. |
2610 |
// represent a DT_NULL entry. |
2526 |
if(!elf.ReadBytes(nextEntryPosition, |
2611 |
char* data = &bytes[0]; |
2527 |
nullEntryPosition - nextEntryPosition, |
2612 |
for(int i=0; i < se_count; ++i) |
2528 |
&bytes[0])) |
2613 |
{ |
|
|
2614 |
// Read data between the entries being removed. |
2615 |
unsigned long sz = entryBegin[i+1] - entryEnd[i]; |
2616 |
if(sz > 0 && !elf.ReadBytes(entryEnd[i], sz, data)) |
2529 |
{ |
2617 |
{ |
2530 |
if(emsg) |
2618 |
if(emsg) |
2531 |
{ |
2619 |
{ |
Lines 2533-2543
bool cmSystemTools::RemoveRPath(std::string const& file, std::string* emsg)
Link Here
|
2533 |
} |
2621 |
} |
2534 |
return false; |
2622 |
return false; |
2535 |
} |
2623 |
} |
2536 |
} |
2624 |
data += sz; |
2537 |
else |
|
|
2538 |
{ |
2539 |
// There is no RPATH or RUNPATH anyway. |
2540 |
return true; |
2541 |
} |
2625 |
} |
2542 |
} |
2626 |
} |
2543 |
|
2627 |
|
Lines 2554-2560
bool cmSystemTools::RemoveRPath(std::string const& file, std::string* emsg)
Link Here
|
2554 |
} |
2638 |
} |
2555 |
|
2639 |
|
2556 |
// Write the new DYNAMIC table header. |
2640 |
// Write the new DYNAMIC table header. |
2557 |
if(!f.seekp(rpathEntryPosition)) |
2641 |
if(!f.seekp(bytesBegin)) |
2558 |
{ |
2642 |
{ |
2559 |
if(emsg) |
2643 |
if(emsg) |
2560 |
{ |
2644 |
{ |
Lines 2571-2606
bool cmSystemTools::RemoveRPath(std::string const& file, std::string* emsg)
Link Here
|
2571 |
return false; |
2655 |
return false; |
2572 |
} |
2656 |
} |
2573 |
|
2657 |
|
2574 |
// Fill the RPATH string with zero bytes. |
2658 |
// Fill the RPATH and RUNPATH strings with zero bytes. |
2575 |
if(!f.seekp(rpathPosition)) |
2659 |
for(int i=0; i < zeroCount; ++i) |
2576 |
{ |
2660 |
{ |
2577 |
if(emsg) |
2661 |
if(!f.seekp(zeroPosition[i])) |
2578 |
{ |
2662 |
{ |
2579 |
*emsg = "Error seeking to RPATH position."; |
2663 |
if(emsg) |
|
|
2664 |
{ |
2665 |
*emsg = "Error seeking to RPATH position."; |
2666 |
} |
2667 |
return false; |
2668 |
} |
2669 |
for(unsigned long j=0; j < zeroSize[i]; ++j) |
2670 |
{ |
2671 |
f << '\0'; |
2672 |
} |
2673 |
if(!f) |
2674 |
{ |
2675 |
if(emsg) |
2676 |
{ |
2677 |
*emsg = "Error writing the empty rpath string to the file."; |
2678 |
} |
2679 |
return false; |
2580 |
} |
2680 |
} |
2581 |
return false; |
|
|
2582 |
} |
2583 |
for(unsigned long i=0; i < rpathSize; ++i) |
2584 |
{ |
2585 |
f << '\0'; |
2586 |
} |
2681 |
} |
2587 |
|
2682 |
|
2588 |
// Make sure everything was okay. |
2683 |
// Everything was updated successfully. |
2589 |
if(f) |
2684 |
if(removed) |
2590 |
{ |
|
|
2591 |
return true; |
2592 |
} |
2593 |
else |
2594 |
{ |
2685 |
{ |
2595 |
if(emsg) |
2686 |
*removed = true; |
2596 |
{ |
|
|
2597 |
*emsg = "Error writing the empty rpath to the file."; |
2598 |
} |
2599 |
return false; |
2600 |
} |
2687 |
} |
|
|
2688 |
return true; |
2601 |
#else |
2689 |
#else |
2602 |
(void)file; |
2690 |
(void)file; |
2603 |
(void)emsg; |
2691 |
(void)emsg; |
|
|
2692 |
(void)removed; |
2604 |
return false; |
2693 |
return false; |
2605 |
#endif |
2694 |
#endif |
2606 |
} |
2695 |
} |