diff options
Diffstat (limited to 'llvm/tools/llvm-objcopy/ELF/ELFObjcopy.cpp')
| -rw-r--r-- | llvm/tools/llvm-objcopy/ELF/ELFObjcopy.cpp | 77 |
1 files changed, 76 insertions, 1 deletions
diff --git a/llvm/tools/llvm-objcopy/ELF/ELFObjcopy.cpp b/llvm/tools/llvm-objcopy/ELF/ELFObjcopy.cpp index 045b34f7715..7430b19c772 100644 --- a/llvm/tools/llvm-objcopy/ELF/ELFObjcopy.cpp +++ b/llvm/tools/llvm-objcopy/ELF/ELFObjcopy.cpp @@ -10,8 +10,8 @@ #include "ELFObjcopy.h" #include "Buffer.h" #include "CopyConfig.h" -#include "llvm-objcopy.h" #include "Object.h" +#include "llvm-objcopy.h" #include "llvm/ADT/BitmaskEnum.h" #include "llvm/ADT/Optional.h" @@ -28,6 +28,7 @@ #include "llvm/Option/Option.h" #include "llvm/Support/Casting.h" #include "llvm/Support/Compression.h" +#include "llvm/Support/Errc.h" #include "llvm/Support/Error.h" #include "llvm/Support/ErrorHandling.h" #include "llvm/Support/ErrorOr.h" @@ -115,6 +116,63 @@ static std::unique_ptr<Writer> createWriter(const CopyConfig &Config, llvm_unreachable("Invalid output format"); } +template <class ELFT> +static Expected<ArrayRef<uint8_t>> +findBuildID(const object::ELFFile<ELFT> &In) { + for (const auto &Phdr : unwrapOrError(In.program_headers())) { + if (Phdr.p_type != PT_NOTE) + continue; + Error Err = Error::success(); + if (Err) + llvm_unreachable("Error::success() was an error."); + for (const auto &Note : In.notes(Phdr, Err)) { + if (Err) + return std::move(Err); + if (Note.getType() == NT_GNU_BUILD_ID && Note.getName() == ELF_NOTE_GNU) + return Note.getDesc(); + } + if (Err) + return std::move(Err); + } + return createStringError(llvm::errc::invalid_argument, + "Could not find build ID."); +} + +static Expected<ArrayRef<uint8_t>> +findBuildID(const object::ELFObjectFileBase &In) { + if (auto *O = dyn_cast<ELFObjectFile<ELF32LE>>(&In)) + return findBuildID(*O->getELFFile()); + else if (auto *O = dyn_cast<ELFObjectFile<ELF64LE>>(&In)) + return findBuildID(*O->getELFFile()); + else if (auto *O = dyn_cast<ELFObjectFile<ELF32BE>>(&In)) + return findBuildID(*O->getELFFile()); + else if (auto *O = dyn_cast<ELFObjectFile<ELF64BE>>(&In)) + return findBuildID(*O->getELFFile()); + + llvm_unreachable("Bad file format"); +} + +static void linkToBuildIdDir(const CopyConfig &Config, StringRef ToLink, + StringRef Suffix, ArrayRef<uint8_t> BuildIdBytes) { + SmallString<128> Path = Config.BuildIdLinkDir; + sys::path::append(Path, llvm::toHex(BuildIdBytes[0], /*LowerCase*/ true)); + if (auto EC = sys::fs::create_directories(Path)) + error("cannot create build ID link directory " + Path + ": " + + EC.message()); + + sys::path::append(Path, + llvm::toHex(BuildIdBytes.slice(1), /*LowerCase*/ true)); + Path += Suffix; + if (auto EC = sys::fs::create_hard_link(ToLink, Path)) { + // Hard linking failed, try to remove the file first if it exists. + if (sys::fs::exists(Path)) + sys::fs::remove(Path); + EC = sys::fs::create_hard_link(ToLink, Path); + if (EC) + error("cannot link " + ToLink + " to " + Path + ": " + EC.message()); + } +} + static void splitDWOToFile(const CopyConfig &Config, const Reader &Reader, StringRef File, ElfType OutputElfType) { auto DWOFile = Reader.create(); @@ -488,11 +546,28 @@ void executeObjcopyOnBinary(const CopyConfig &Config, ELFReader Reader(&In); std::unique_ptr<Object> Obj = Reader.create(); const ElfType OutputElfType = getOutputElfType(In); + ArrayRef<uint8_t> BuildIdBytes; + + if (!Config.BuildIdLinkDir.empty()) { + BuildIdBytes = unwrapOrError(findBuildID(In)); + if (BuildIdBytes.size() < 2) + error("build ID in file '" + Config.InputFilename + + "' is smaller than two bytes"); + } + + if (!Config.BuildIdLinkDir.empty() && Config.BuildIdLinkInput) { + linkToBuildIdDir(Config, Config.InputFilename, + Config.BuildIdLinkInput.getValue(), BuildIdBytes); + } handleArgs(Config, *Obj, Reader, OutputElfType); std::unique_ptr<Writer> Writer = createWriter(Config, *Obj, Out, OutputElfType); Writer->finalize(); Writer->write(); + if (!Config.BuildIdLinkDir.empty() && Config.BuildIdLinkOutput) { + linkToBuildIdDir(Config, Config.OutputFilename, + Config.BuildIdLinkOutput.getValue(), BuildIdBytes); + } } } // end namespace elf |

