diff --git a/llvm/test/tools/llvm-objcopy/MachO/dump-section.test b/llvm/test/tools/llvm-objcopy/MachO/dump-section.test new file mode 100644 --- /dev/null +++ b/llvm/test/tools/llvm-objcopy/MachO/dump-section.test @@ -0,0 +1,90 @@ +## Show that llvm-objcopy extracts section contents into files specified by +## --dump-section. + +# RUN: yaml2obj %s > %t + +## Extract section contents into files. +# RUN: llvm-objcopy --dump-section __TEXT,__text=%t.dump.text \ +# RUN: --dump-section __DATA,__data=%t.dump.data %t +# RUN: od -t x1 %t.dump.text | FileCheck %s --check-prefix=TEXT-CONTENT +# RUN: wc -c %t.dump.text | FileCheck %s --check-prefix=TEXT-SIZE +# RUN: od -t x1 %t.dump.data | FileCheck %s --check-prefix=DATA-CONTENT +# RUN: wc -c %t.dump.data | FileCheck %s --check-prefix=DATA-SIZE + +# TEXT-CONTENT: 0000000 aa bb cc dd +# TEXT-SIZE: 4 +# DATA-CONTENT: 0000000 ee ff ee ff +# DATA-SIZE: 4 + +## Error case 1: An invalid section name. +# RUN: not llvm-objcopy --dump-section __text=%t.invalid-section-name %t 2>&1 \ +# RUN: | FileCheck %s -DINPUT=%t --check-prefix=INVALID-SECTION-NAME +# INVALID-SECTION-NAME: error: '[[INPUT]]': invalid section name '__text' (should be formatted as ',
') + +## Error case 2: A non-existent section name. +# RUN: not llvm-objcopy --dump-section __TEXT,__foo=%t.no-such-section %t 2>&1 \ +# RUN: | FileCheck %s -DINPUT=%t --check-prefix=NO-SUCH-SECTION +# NO-SUCH-SECTION: error: '[[INPUT]]': section '__TEXT,__foo' not found + +--- !mach-o +FileHeader: + magic: 0xFEEDFACF + cputype: 0x01000007 + cpusubtype: 0x00000003 + filetype: 0x00000001 + ncmds: 1 + sizeofcmds: 312 + flags: 0x00002000 + reserved: 0x00000000 +LoadCommands: + - cmd: LC_SEGMENT_64 + cmdsize: 312 + segname: '' + vmaddr: 0 + vmsize: 12 + fileoff: 344 + filesize: 12 + maxprot: 7 + initprot: 7 + nsects: 3 + flags: 0 + Sections: + - sectname: __text + segname: __TEXT + addr: 0x0000000000000000 + content: 'AABBCCDD' + size: 4 + offset: 344 + align: 0 + reloff: 0x00000000 + nreloc: 0 + flags: 0x80000400 + reserved1: 0x00000000 + reserved2: 0x00000000 + reserved3: 0x00000000 + - sectname: __data + segname: __DATA + addr: 0x0000000000000004 + content: 'EEFFEEFF' + size: 4 + offset: 348 + align: 0 + reloff: 0x00000000 + nreloc: 0 + flags: 0x00000000 + reserved1: 0x00000000 + reserved2: 0x00000000 + reserved3: 0x00000000 + - sectname: __const + segname: __TEXT + addr: 0x0000000000000008 + content: 'EEFFEEFF' + size: 4 + offset: 352 + align: 0 + reloff: 0x00000000 + nreloc: 0 + flags: 0x00000000 + reserved1: 0x00000000 + reserved2: 0x00000000 + reserved3: 0x00000000 diff --git a/llvm/tools/llvm-objcopy/MachO/MachOObjcopy.cpp b/llvm/tools/llvm-objcopy/MachO/MachOObjcopy.cpp --- a/llvm/tools/llvm-objcopy/MachO/MachOObjcopy.cpp +++ b/llvm/tools/llvm-objcopy/MachO/MachOObjcopy.cpp @@ -97,6 +97,28 @@ return Error::success(); } +static Error dumpSectionToFile(StringRef SecName, StringRef Filename, + Object &Obj) { + for (LoadCommand &LC : Obj.LoadCommands) + for (Section &Sec : LC.Sections) { + if (Sec.CannonicalName == SecName) { + Expected> BufferOrErr = + FileOutputBuffer::create(Filename, Sec.Content.size()); + if (!BufferOrErr) + return BufferOrErr.takeError(); + std::unique_ptr Buf = std::move(*BufferOrErr); + std::copy(Sec.Content.begin(), Sec.Content.end(), + Buf->getBufferStart()); + if (Error E = Buf->commit()) + return E; + return Error::success(); + } + } + + return createStringError(object_error::parse_failed, "section '%s' not found", + SecName.str().c_str()); +} + static Error validateOptions(const CopyConfig &Config) { // TODO: Support section renaming in GNU objcopy for compatibility (see // http://lists.llvm.org/pipermail/llvm-dev/2019-May/132570.html). @@ -120,11 +142,11 @@ if (Config.AllowBrokenLinks || !Config.BuildIdLinkDir.empty() || Config.BuildIdLinkInput || Config.BuildIdLinkOutput || !Config.SplitDWO.empty() || !Config.SymbolsPrefix.empty() || - !Config.AllocSectionsPrefix.empty() || !Config.DumpSection.empty() || - !Config.KeepSection.empty() || !Config.SymbolsToGlobalize.empty() || - !Config.SymbolsToKeep.empty() || !Config.SymbolsToLocalize.empty() || - !Config.SymbolsToWeaken.empty() || !Config.SymbolsToKeepGlobal.empty() || - !Config.SectionsToRename.empty() || !Config.SymbolsToRename.empty() || + !Config.AllocSectionsPrefix.empty() || !Config.KeepSection.empty() || + !Config.SymbolsToGlobalize.empty() || !Config.SymbolsToKeep.empty() || + !Config.SymbolsToLocalize.empty() || !Config.SymbolsToWeaken.empty() || + !Config.SymbolsToKeepGlobal.empty() || !Config.SectionsToRename.empty() || + !Config.SymbolsToRename.empty() || !Config.UnneededSymbolsToRemove.empty() || !Config.SetSectionFlags.empty() || Config.ExtractDWO || Config.KeepFileSymbols || Config.LocalizeHidden || Config.PreserveDates || @@ -163,6 +185,16 @@ for (Section &Sec : LC.Sections) Sec.Relocations.clear(); + for (const auto &Flag : Config.DumpSection) { + std::pair SecPair = Flag.split("="); + StringRef SecName = SecPair.first; + StringRef File = SecPair.second; + if (Error E = isValidMachOCannonicalName(SecName)) + return E; + if (Error E = dumpSectionToFile(SecName, File, Obj)) + return E; + } + return Error::success(); }