[llvm] r348174 - [llvm-objcopy] Add --build-id-link-dir flag
Jake Ehrlich via llvm-commits
llvm-commits at lists.llvm.org
Mon Dec 3 11:49:23 PST 2018
Author: jakehehrlich
Date: Mon Dec 3 11:49:23 2018
New Revision: 348174
URL: http://llvm.org/viewvc/llvm-project?rev=348174&view=rev
Log:
[llvm-objcopy] Add --build-id-link-dir flag
This flag does not exist in GNU objcopy but has a major use case.
Debugging tools support the .build-id directory structure to find
debug binaries. There is no easy way to build this structure up
however. One way to do it is by using llvm-readelf and some crazy
shell magic. This implements the feature directly. It is most often
the case that you'll want to strip a file and send the original to
the .build-id directory but if you just want to send a file to the
.build-id directory you can copy to /dev/null instead.
Differential Revision: https://reviews.llvm.org/D54384
Added:
llvm/trunk/test/tools/llvm-objcopy/ELF/bad-build-id.test
llvm/trunk/test/tools/llvm-objcopy/ELF/build-id-link-dir.test
llvm/trunk/test/tools/llvm-objcopy/ELF/no-build-id-no-notes.test
llvm/trunk/test/tools/llvm-objcopy/ELF/no-build-id.test
Modified:
llvm/trunk/include/llvm/BinaryFormat/ELF.h
llvm/trunk/tools/llvm-objcopy/CopyConfig.cpp
llvm/trunk/tools/llvm-objcopy/CopyConfig.h
llvm/trunk/tools/llvm-objcopy/ELF/ELFObjcopy.cpp
llvm/trunk/tools/llvm-objcopy/ELF/Object.h
llvm/trunk/tools/llvm-objcopy/ObjcopyOpts.td
Modified: llvm/trunk/include/llvm/BinaryFormat/ELF.h
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/include/llvm/BinaryFormat/ELF.h?rev=348174&r1=348173&r2=348174&view=diff
==============================================================================
--- llvm/trunk/include/llvm/BinaryFormat/ELF.h (original)
+++ llvm/trunk/include/llvm/BinaryFormat/ELF.h Mon Dec 3 11:49:23 2018
@@ -1377,6 +1377,8 @@ enum {
GNU_ABI_TAG_NACL = 6,
};
+constexpr const char *ELF_NOTE_GNU = "GNU";
+
// Android packed relocation group flags.
enum {
RELOCATION_GROUPED_BY_INFO_FLAG = 1,
Added: llvm/trunk/test/tools/llvm-objcopy/ELF/bad-build-id.test
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/test/tools/llvm-objcopy/ELF/bad-build-id.test?rev=348174&view=auto
==============================================================================
--- llvm/trunk/test/tools/llvm-objcopy/ELF/bad-build-id.test (added)
+++ llvm/trunk/test/tools/llvm-objcopy/ELF/bad-build-id.test Mon Dec 3 11:49:23 2018
@@ -0,0 +1,21 @@
+# RUN: yaml2obj %s > %t
+# RUN: not llvm-objcopy --build-id-link-dir=%t-dir --build-id-link-input=.debug %t 2>&1 >/dev/null | FileCheck %s
+
+# CHECK: build ID in file {{.*}} is smaller than two bytes.
+
+--- !ELF
+FileHeader:
+ Class: ELFCLASS64
+ Data: ELFDATA2LSB
+ Type: ET_EXEC
+ Machine: EM_X86_64
+Sections:
+ - Name: .note.gnu.build-id
+ Type: SHT_NOTE
+ Flags: [ SHF_ALLOC ]
+ Content: 040000000100000003000000474E55004F000000
+ProgramHeaders:
+ - Type: PT_NOTE
+ Flags: [ PF_R ]
+ Sections:
+ - Section: .note.gnu.build-id
Added: llvm/trunk/test/tools/llvm-objcopy/ELF/build-id-link-dir.test
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/test/tools/llvm-objcopy/ELF/build-id-link-dir.test?rev=348174&view=auto
==============================================================================
--- llvm/trunk/test/tools/llvm-objcopy/ELF/build-id-link-dir.test (added)
+++ llvm/trunk/test/tools/llvm-objcopy/ELF/build-id-link-dir.test Mon Dec 3 11:49:23 2018
@@ -0,0 +1,56 @@
+# RUN: yaml2obj %s > %t
+# RUN: mkdir -p %t-dir
+
+# RUN: llvm-objcopy --build-id-link-dir=%t-dir %t %t2
+# RUN: not test -e %t-dir/4f/cb712aa6387724a9f465a32cd8c14b
+
+# RUN: llvm-objcopy --build-id-link-dir=%t-dir --build-id-link-input=.debug %t %t3
+# RUN: cmp %t-dir/4f/cb712aa6387724a9f465a32cd8c14b.debug %t
+# RUN: rm %t-dir/4f/cb712aa6387724a9f465a32cd8c14b.debug
+
+# RUN: llvm-objcopy --build-id-link-dir=%t-dir --build-id-link-output "" --strip-sections %t %t4
+# RUN: cmp %t-dir/4f/cb712aa6387724a9f465a32cd8c14b %t4
+# RUN: rm %t-dir/4f/cb712aa6387724a9f465a32cd8c14b
+
+# Linking the output of an inplace argument means that the file in the build-id
+# directory will be hard-linked to the resulting file.
+# RUN: cp %t %t5
+# RUN: llvm-objcopy --build-id-link-dir=%t-dir --build-id-link-output "" --strip-sections %t5
+# RUN: cmp %t-dir/4f/cb712aa6387724a9f465a32cd8c14b %t5
+# RUN: rm %t-dir/4f/cb712aa6387724a9f465a32cd8c14b
+
+# Linking the input of an inplace argument means that the file in the build-id
+# directory will be hard-linked to the original file.
+# RUN: cp %t %t6
+# RUN: llvm-objcopy --build-id-link-dir=%t-dir --build-id-link-input=.debug --strip-sections %t6
+# RUN: cmp %t-dir/4f/cb712aa6387724a9f465a32cd8c14b.debug %t
+# RUN: rm %t-dir/4f/cb712aa6387724a9f465a32cd8c14b.debug
+
+# You can use both at once.
+# RUN: llvm-objcopy --build-id-link-dir=%t-dir --build-id-link-output "" --build-id-link-input=.debug --strip-sections %t %t7
+# RUN: cmp %t-dir/4f/cb712aa6387724a9f465a32cd8c14b.debug %t
+# RUN: cmp %t-dir/4f/cb712aa6387724a9f465a32cd8c14b %t7
+# RUN: rm %t-dir/4f/cb712aa6387724a9f465a32cd8c14b.debug
+# RUN: rm %t-dir/4f/cb712aa6387724a9f465a32cd8c14b
+
+# --build-id-link-output can have a suffix as well
+# RUN: llvm-objcopy --build-id-link-dir=%t-dir --build-id-link-output=.debug --only-keep-debug %t %t8
+# RUN: cmp %t-dir/4f/cb712aa6387724a9f465a32cd8c14b.debug %t8
+# RUN: rm %t-dir/4f/cb712aa6387724a9f465a32cd8c14b.debug
+
+--- !ELF
+FileHeader:
+ Class: ELFCLASS64
+ Data: ELFDATA2LSB
+ Type: ET_EXEC
+ Machine: EM_X86_64
+Sections:
+ - Name: .note.gnu.build-id
+ Type: SHT_NOTE
+ Flags: [ SHF_ALLOC ]
+ Content: 040000001000000003000000474E55004FCB712AA6387724A9F465A32CD8C14B
+ProgramHeaders:
+ - Type: PT_NOTE
+ Flags: [ PF_R ]
+ Sections:
+ - Section: .note.gnu.build-id
Added: llvm/trunk/test/tools/llvm-objcopy/ELF/no-build-id-no-notes.test
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/test/tools/llvm-objcopy/ELF/no-build-id-no-notes.test?rev=348174&view=auto
==============================================================================
--- llvm/trunk/test/tools/llvm-objcopy/ELF/no-build-id-no-notes.test (added)
+++ llvm/trunk/test/tools/llvm-objcopy/ELF/no-build-id-no-notes.test Mon Dec 3 11:49:23 2018
@@ -0,0 +1,11 @@
+# RUN: yaml2obj %s > %t
+# RUN: not llvm-objcopy --build-id-link-dir=%t-dir --build-id-link-input=.debug %t 2>&1 >/dev/null | FileCheck %s
+
+# CHECK: Could not find build ID.
+
+--- !ELF
+FileHeader:
+ Class: ELFCLASS64
+ Data: ELFDATA2LSB
+ Type: ET_EXEC
+ Machine: EM_X86_64
Added: llvm/trunk/test/tools/llvm-objcopy/ELF/no-build-id.test
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/test/tools/llvm-objcopy/ELF/no-build-id.test?rev=348174&view=auto
==============================================================================
--- llvm/trunk/test/tools/llvm-objcopy/ELF/no-build-id.test (added)
+++ llvm/trunk/test/tools/llvm-objcopy/ELF/no-build-id.test Mon Dec 3 11:49:23 2018
@@ -0,0 +1,21 @@
+# RUN: yaml2obj %s > %t
+# RUN: not llvm-objcopy --build-id-link-dir=%t-dir --build-id-link-input=.debug %t 2>&1 >/dev/null | FileCheck %s
+
+# CHECK: Could not find build ID.
+
+--- !ELF
+FileHeader:
+ Class: ELFCLASS64
+ Data: ELFDATA2LSB
+ Type: ET_EXEC
+ Machine: EM_X86_64
+Sections:
+ - Name: .note.foo
+ Type: SHT_NOTE
+ Flags: [ SHF_ALLOC ]
+ Content: 000000000000000000000000
+ProgramHeaders:
+ - Type: PT_NOTE
+ Flags: [ PF_R ]
+ Sections:
+ - Section: .note.gnu.foo
Modified: llvm/trunk/tools/llvm-objcopy/CopyConfig.cpp
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/tools/llvm-objcopy/CopyConfig.cpp?rev=348174&r1=348173&r2=348174&view=diff
==============================================================================
--- llvm/trunk/tools/llvm-objcopy/CopyConfig.cpp (original)
+++ llvm/trunk/tools/llvm-objcopy/CopyConfig.cpp Mon Dec 3 11:49:23 2018
@@ -286,8 +286,15 @@ DriverConfig parseObjcopyOptions(ArrayRe
}
}
- Config.SplitDWO = InputArgs.getLastArgValue(OBJCOPY_split_dwo);
Config.AddGnuDebugLink = InputArgs.getLastArgValue(OBJCOPY_add_gnu_debuglink);
+ Config.BuildIdLinkDir = InputArgs.getLastArgValue(OBJCOPY_build_id_link_dir);
+ if (InputArgs.hasArg(OBJCOPY_build_id_link_input))
+ Config.BuildIdLinkInput =
+ InputArgs.getLastArgValue(OBJCOPY_build_id_link_input);
+ if (InputArgs.hasArg(OBJCOPY_build_id_link_output))
+ Config.BuildIdLinkOutput =
+ InputArgs.getLastArgValue(OBJCOPY_build_id_link_output);
+ Config.SplitDWO = InputArgs.getLastArgValue(OBJCOPY_split_dwo);
Config.SymbolsPrefix = InputArgs.getLastArgValue(OBJCOPY_prefix_symbols);
for (auto Arg : InputArgs.filtered(OBJCOPY_redefine_symbol)) {
Modified: llvm/trunk/tools/llvm-objcopy/CopyConfig.h
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/tools/llvm-objcopy/CopyConfig.h?rev=348174&r1=348173&r2=348174&view=diff
==============================================================================
--- llvm/trunk/tools/llvm-objcopy/CopyConfig.h (original)
+++ llvm/trunk/tools/llvm-objcopy/CopyConfig.h Mon Dec 3 11:49:23 2018
@@ -51,6 +51,9 @@ struct CopyConfig {
// Advanced options
StringRef AddGnuDebugLink;
+ StringRef BuildIdLinkDir;
+ Optional<StringRef> BuildIdLinkInput;
+ Optional<StringRef> BuildIdLinkOutput;
StringRef SplitDWO;
StringRef SymbolsPrefix;
Modified: llvm/trunk/tools/llvm-objcopy/ELF/ELFObjcopy.cpp
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/tools/llvm-objcopy/ELF/ELFObjcopy.cpp?rev=348174&r1=348173&r2=348174&view=diff
==============================================================================
--- llvm/trunk/tools/llvm-objcopy/ELF/ELFObjcopy.cpp (original)
+++ llvm/trunk/tools/llvm-objcopy/ELF/ELFObjcopy.cpp Mon Dec 3 11:49:23 2018
@@ -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> createWri
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 CopyCo
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
Modified: llvm/trunk/tools/llvm-objcopy/ELF/Object.h
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/tools/llvm-objcopy/ELF/Object.h?rev=348174&r1=348173&r2=348174&view=diff
==============================================================================
--- llvm/trunk/tools/llvm-objcopy/ELF/Object.h (original)
+++ llvm/trunk/tools/llvm-objcopy/ELF/Object.h Mon Dec 3 11:49:23 2018
@@ -254,7 +254,6 @@ private:
};
std::set<const SectionBase *, SectionCompare> Sections;
- ArrayRef<uint8_t> Contents;
public:
uint64_t Align;
@@ -269,6 +268,7 @@ public:
uint64_t OriginalOffset;
Segment *ParentSegment = nullptr;
+ ArrayRef<uint8_t> Contents;
explicit Segment(ArrayRef<uint8_t> Data) : Contents(Data) {}
Segment() {}
Modified: llvm/trunk/tools/llvm-objcopy/ObjcopyOpts.td
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/tools/llvm-objcopy/ObjcopyOpts.td?rev=348174&r1=348173&r2=348174&view=diff
==============================================================================
--- llvm/trunk/tools/llvm-objcopy/ObjcopyOpts.td (original)
+++ llvm/trunk/tools/llvm-objcopy/ObjcopyOpts.td Mon Dec 3 11:49:23 2018
@@ -166,3 +166,15 @@ defm prefix_symbols
def version : Flag<["-", "--"], "version">,
HelpText<"Print the version and exit.">;
def V : Flag<["-"], "V">, Alias<version>;
+defm build_id_link_dir
+ : Eq<"build-id-link-dir", "Set directory for --build-id-link-input and "
+ "--build-id-link-output to <dir>">,
+ MetaVarName<"dir">;
+defm build_id_link_input
+ : Eq<"build-id-link-input", "Hard-link the input to <dir>/xx/xxx<suffix> "
+ "name derived from hex build ID">,
+ MetaVarName<"suffix">;
+defm build_id_link_output
+ : Eq<"build-id-link-output", "Hard-link the output to <dir>/xx/xxx<suffix> "
+ "name derived from hex build ID">,
+ MetaVarName<"suffix">;
More information about the llvm-commits
mailing list