From a52faa1fcb7b54026ecfbef573d05568846e1aba Mon Sep 17 00:00:00 2001 From: Florian Apolloner Date: Mon, 6 Mar 2017 21:16:42 +0100 Subject: file: Add READ_ELF command to parse ELF binaries Leave it undocumented for now because we intend to use it internally and it cannot be made available everywhere. --- Source/cmFileCommand.cxx | 69 +++++++++++++++++++++++++++++++++ Source/cmFileCommand.h | 1 + Tests/RunCMake/file/READ_ELF-result.txt | 1 + Tests/RunCMake/file/READ_ELF-stderr.txt | 2 + Tests/RunCMake/file/READ_ELF.cmake | 2 + Tests/RunCMake/file/RunCMakeTest.cmake | 1 + 6 files changed, 76 insertions(+) create mode 100644 Tests/RunCMake/file/READ_ELF-result.txt create mode 100644 Tests/RunCMake/file/READ_ELF-stderr.txt create mode 100644 Tests/RunCMake/file/READ_ELF.cmake diff --git a/Source/cmFileCommand.cxx b/Source/cmFileCommand.cxx index 91cecb3..957b4cb 100644 --- a/Source/cmFileCommand.cxx +++ b/Source/cmFileCommand.cxx @@ -42,6 +42,10 @@ #include "cmFileLockResult.h" #endif +#if defined(CMAKE_USE_ELF_PARSER) +#include "cmELF.h" +#endif + class cmSystemToolsFileTime; // Table of permissions flags. @@ -166,6 +170,9 @@ bool cmFileCommand::InitialPass(std::vector const& args, if (subCommand == "RPATH_REMOVE") { return this->HandleRPathRemoveCommand(args); } + if (subCommand == "READ_ELF") { + return this->HandleReadElfCommand(args); + } if (subCommand == "RELATIVE_PATH") { return this->HandleRelativePathCommand(args); } @@ -2177,6 +2184,68 @@ bool cmFileCommand::HandleRPathCheckCommand( return true; } +bool cmFileCommand::HandleReadElfCommand(std::vector const& args) +{ + if (args.size() < 4) { + this->SetError("READ_ELF must be called with at least three additional " + "arguments."); + return false; + } + + cmCommandArgumentsHelper argHelper; + cmCommandArgumentGroup group; + + cmCAString readArg(&argHelper, "READ_ELF"); + cmCAString fileNameArg(&argHelper, CM_NULLPTR); + + cmCAString rpathArg(&argHelper, "RPATH", &group); + cmCAString runpathArg(&argHelper, "RUNPATH", &group); + cmCAString errorArg(&argHelper, "CAPTURE_ERROR", &group); + + readArg.Follows(CM_NULLPTR); + fileNameArg.Follows(&readArg); + group.Follows(&fileNameArg); + argHelper.Parse(&args, CM_NULLPTR); + + if (!cmSystemTools::FileExists(fileNameArg.GetString(), true)) { + std::ostringstream e; + e << "READ_ELF given FILE \"" << fileNameArg.GetString() + << "\" that does not exist."; + this->SetError(e.str()); + return false; + } + +#if defined(CMAKE_USE_ELF_PARSER) + cmELF elf(fileNameArg.GetCString()); + + if (!rpathArg.GetString().empty()) { + if (cmELF::StringEntry const* se_rpath = elf.GetRPath()) { + std::string rpath(se_rpath->Value); + std::replace(rpath.begin(), rpath.end(), ':', ';'); + this->Makefile->AddDefinition(rpathArg.GetString(), rpath.c_str()); + } + } + if (!runpathArg.GetString().empty()) { + if (cmELF::StringEntry const* se_runpath = elf.GetRunPath()) { + std::string runpath(se_runpath->Value); + std::replace(runpath.begin(), runpath.end(), ':', ';'); + this->Makefile->AddDefinition(runpathArg.GetString(), runpath.c_str()); + } + } + + return true; +#else + std::string error = "ELF parser not available on this platform."; + if (errorArg.GetString().empty()) { + this->SetError(error); + return false; + } else { + this->Makefile->AddDefinition(errorArg.GetString(), error.c_str()); + return true; + } +#endif +} + bool cmFileCommand::HandleInstallCommand(std::vector const& args) { cmFileInstaller installer(this); diff --git a/Source/cmFileCommand.h b/Source/cmFileCommand.h index 319864c..2d82a23 100644 --- a/Source/cmFileCommand.h +++ b/Source/cmFileCommand.h @@ -53,6 +53,7 @@ protected: bool HandleRelativePathCommand(std::vector const& args); bool HandleCMakePathCommand(std::vector const& args, bool nativePath); + bool HandleReadElfCommand(std::vector const& args); bool HandleRPathChangeCommand(std::vector const& args); bool HandleRPathCheckCommand(std::vector const& args); bool HandleRPathRemoveCommand(std::vector const& args); diff --git a/Tests/RunCMake/file/READ_ELF-result.txt b/Tests/RunCMake/file/READ_ELF-result.txt new file mode 100644 index 0000000..d00491f --- /dev/null +++ b/Tests/RunCMake/file/READ_ELF-result.txt @@ -0,0 +1 @@ +1 diff --git a/Tests/RunCMake/file/READ_ELF-stderr.txt b/Tests/RunCMake/file/READ_ELF-stderr.txt new file mode 100644 index 0000000..7b32804 --- /dev/null +++ b/Tests/RunCMake/file/READ_ELF-stderr.txt @@ -0,0 +1,2 @@ +.*file READ_ELF must be called with at least three additional arguments\. +.*file READ_ELF given FILE "XXX" that does not exist\. diff --git a/Tests/RunCMake/file/READ_ELF.cmake b/Tests/RunCMake/file/READ_ELF.cmake new file mode 100644 index 0000000..cd02c9b --- /dev/null +++ b/Tests/RunCMake/file/READ_ELF.cmake @@ -0,0 +1,2 @@ +file(READ_ELF XXX) +file(READ_ELF XXX RPATH YYY) diff --git a/Tests/RunCMake/file/RunCMakeTest.cmake b/Tests/RunCMake/file/RunCMakeTest.cmake index 7497544..3f3c0da 100644 --- a/Tests/RunCMake/file/RunCMakeTest.cmake +++ b/Tests/RunCMake/file/RunCMakeTest.cmake @@ -25,6 +25,7 @@ run_cmake(LOCK-error-no-timeout) run_cmake(LOCK-error-timeout) run_cmake(LOCK-error-unknown-option) run_cmake(LOCK-lowercase) +run_cmake(READ_ELF) run_cmake(GLOB) run_cmake(GLOB_RECURSE) # test is valid both for GLOB and GLOB_RECURSE -- cgit v0.12