[llvm-install-name-tool] Add -id option
authorSameer Arora <sameerarora101@fb.com>
Tue, 30 Jun 2020 18:01:45 +0000 (11:01 -0700)
committerShoaib Meenai <smeenai@fb.com>
Tue, 30 Jun 2020 18:28:53 +0000 (11:28 -0700)
Implement `-id` option for install-name-tool. Differences from cctool's
behavior:
 - Does **NOT** throw an error if multiple -id options are specified.
    Instead, picks the last one.
 - Throws an error in case empty id is specified.

Reviewed By: jhenderson, smeenai

Differential Revision: https://reviews.llvm.org/D82410

llvm/test/tools/llvm-objcopy/MachO/install-name-tool-id.test [new file with mode: 0644]
llvm/tools/llvm-objcopy/CopyConfig.cpp
llvm/tools/llvm-objcopy/CopyConfig.h
llvm/tools/llvm-objcopy/InstallNameToolOpts.td
llvm/tools/llvm-objcopy/MachO/MachOObjcopy.cpp

diff --git a/llvm/test/tools/llvm-objcopy/MachO/install-name-tool-id.test b/llvm/test/tools/llvm-objcopy/MachO/install-name-tool-id.test
new file mode 100644 (file)
index 0000000..e36f402
--- /dev/null
@@ -0,0 +1,67 @@
+## This test checks updating a dynamic shared library ID in a MachO binary.
+
+# RUN: yaml2obj %s --docnum=1 -o %t
+
+## Specifying -id once:
+# RUN: llvm-install-name-tool -id /usr/lib/A_long_long_test %t
+# RUN: llvm-objdump -p %t | FileCheck %s --check-prefix=ID --implicit-check-not=/usr
+
+# ID: /usr/lib/A_long_long_test
+
+## Specifying -id more than once:
+# RUN: llvm-install-name-tool -id /usr/lib/B_long -id /usr/lib/K_long -id /usr/A_short  %t
+# RUN: llvm-objdump -p %t | FileCheck %s --check-prefix=ID-MULTIPLE --implicit-check-not=/usr
+
+# ID-MULTIPLE: /usr/A_short
+
+## Specifying -id with empty string:
+# RUN: not llvm-install-name-tool -id '' %t 2>&1 | \
+# RUN:   FileCheck %s --check-prefix=EMPTY
+
+# EMPTY: cannot specify an empty id
+
+## Missing id argument:
+# RUN: not llvm-install-name-tool %t -id 2>&1 | \
+# RUN:   FileCheck %s --check-prefix=MISSING
+
+# MISSING: missing argument to -id option
+
+## Shared dylib binary
+--- !mach-o
+FileHeader:
+  magic:           0xFEEDFACF
+  cputype:         0x01000007
+  cpusubtype:      0x00000003
+  filetype:        0x00000006
+  ncmds:           1
+  sizeofcmds:      56
+  flags:           0x00002000
+  reserved:        0x00000000
+LoadCommands:
+  - cmd:                        LC_ID_DYLIB
+    cmdsize:                    56
+    dylib:
+        name:                   24
+        timestamp:              2
+        current_version:        82115073
+        compatibility_version:  65536
+    PayloadString:              '/usr/lib/A'
+
+# RUN: yaml2obj %s --docnum=2 -o %t
+
+## Check that -id option has no effect if binary is not a shared dylib:
+# RUN: cp %t %t1
+# RUN: llvm-install-name-tool -id /usr/lib/J %t
+# RUN: cmp %t %t1
+
+## Executable binary
+--- !mach-o
+FileHeader:
+  magic:           0xFEEDFACF
+  cputype:         0x01000007
+  cpusubtype:      0x00000003
+  filetype:        0x00000001
+  ncmds:           0
+  sizeofcmds:      0
+  flags:           0x00002000
+  reserved:        0x00000000
index b483116..20a7627 100644 (file)
@@ -904,6 +904,9 @@ parseInstallNameToolOptions(ArrayRef<const char *> ArgsArr) {
     Config.RPathsToUpdate.emplace_back(Old, New);
   }
 
+  if (auto *Arg = InputArgs.getLastArg(INSTALL_NAME_TOOL_id))
+    Config.SharedLibId = Arg->getValue();
+
   SmallVector<StringRef, 2> Positional;
   for (auto Arg : InputArgs.filtered(INSTALL_NAME_TOOL_UNKNOWN))
     return createStringError(errc::invalid_argument, "unknown argument '%s'",
index a492e46..19fcc2e 100644 (file)
@@ -181,6 +181,9 @@ struct CopyConfig {
   std::vector<std::pair<StringRef, StringRef>> RPathsToUpdate;
   DenseSet<StringRef> RPathsToRemove;
 
+  // install-name-tool's id option
+  Optional<StringRef> SharedLibId;
+
   // Section matchers
   NameMatcher KeepSection;
   NameMatcher OnlySection;
index cbdb878..12e27b9 100644 (file)
@@ -24,5 +24,8 @@ def delete_rpath: Option<["-", "--"], "delete_rpath", KIND_SEPARATE>,
 def rpath: MultiArg<["-", "--"], "rpath", 2>,
            HelpText<"Change rpath path name">;
 
+def id : Option<["-","--"], "id", KIND_SEPARATE>,
+                 HelpText<"Change dynamic shared library id">;
+
 def version : Flag<["--"], "version">,
               HelpText<"Print the version and exit.">;
index 1792881..d0bd602 100644 (file)
@@ -273,6 +273,19 @@ static Error handleArgs(const CopyConfig &Config, Object &Obj) {
       for (std::unique_ptr<Section> &Sec : LC.Sections)
         Sec->Relocations.clear();
 
+  if (Config.SharedLibId) {
+    StringRef Id = Config.SharedLibId.getValue();
+    if (Id.empty())
+      return createStringError(errc::invalid_argument,
+                               "cannot specify an empty id");
+    for (LoadCommand &LC : Obj.LoadCommands) {
+      if (LC.MachOLoadCommand.load_command_data.cmd == MachO::LC_ID_DYLIB) {
+        updateLoadCommandPayloadString<MachO::dylib_command>(LC, Id);
+        break;
+      }
+    }
+  }
+
   for (const auto &Flag : Config.AddSection) {
     std::pair<StringRef, StringRef> SecPair = Flag.split("=");
     StringRef SecName = SecPair.first;