diff --git a/llvm/include/llvm/ObjCopy/CommonConfig.h b/llvm/include/llvm/ObjCopy/CommonConfig.h --- a/llvm/include/llvm/ObjCopy/CommonConfig.h +++ b/llvm/include/llvm/ObjCopy/CommonConfig.h @@ -110,9 +110,40 @@ public: // ErrorCallback is used to handle recoverable errors. An Error returned // by the callback aborts the parsing and is then returned by this function. - static Expected + static inline Expected create(StringRef Pattern, MatchStyle MS, - llvm::function_ref ErrorCallback); + llvm::function_ref ErrorCallback) { + switch (MS) { + case MatchStyle::Literal: + return NameOrPattern(Pattern); + case MatchStyle::Wildcard: { + SmallVector Data; + bool IsPositiveMatch = true; + if (Pattern[0] == '!') { + IsPositiveMatch = false; + Pattern = Pattern.drop_front(); + } + Expected GlobOrErr = GlobPattern::create(Pattern); + + // If we couldn't create it as a glob, report the error, but try again + // with a literal if the error reporting is non-fatal. + if (!GlobOrErr) { + if (Error E = ErrorCallback(GlobOrErr.takeError())) + return std::move(E); + return create(Pattern, MatchStyle::Literal, ErrorCallback); + } + + return NameOrPattern(std::make_shared(*GlobOrErr), + IsPositiveMatch); + } + case MatchStyle::Regex: { + SmallVector Data; + return NameOrPattern(std::make_shared( + ("^" + Pattern.ltrim('^').rtrim('$') + "$").toStringRef(Data))); + } + } + llvm_unreachable("Unhandled llvm.objcopy.MatchStyle enum"); + } bool isPositiveMatch() const { return IsPositiveMatch; } Optional getName() const { diff --git a/llvm/tools/llvm-objcopy/ObjcopyOptions.cpp b/llvm/tools/llvm-objcopy/ObjcopyOptions.cpp --- a/llvm/tools/llvm-objcopy/ObjcopyOptions.cpp +++ b/llvm/tools/llvm-objcopy/ObjcopyOptions.cpp @@ -365,41 +365,6 @@ return Error::success(); } -Expected -NameOrPattern::create(StringRef Pattern, MatchStyle MS, - function_ref ErrorCallback) { - switch (MS) { - case MatchStyle::Literal: - return NameOrPattern(Pattern); - case MatchStyle::Wildcard: { - SmallVector Data; - bool IsPositiveMatch = true; - if (Pattern[0] == '!') { - IsPositiveMatch = false; - Pattern = Pattern.drop_front(); - } - Expected GlobOrErr = GlobPattern::create(Pattern); - - // If we couldn't create it as a glob, report the error, but try again with - // a literal if the error reporting is non-fatal. - if (!GlobOrErr) { - if (Error E = ErrorCallback(GlobOrErr.takeError())) - return std::move(E); - return create(Pattern, MatchStyle::Literal, ErrorCallback); - } - - return NameOrPattern(std::make_shared(*GlobOrErr), - IsPositiveMatch); - } - case MatchStyle::Regex: { - SmallVector Data; - return NameOrPattern(std::make_shared( - ("^" + Pattern.ltrim('^').rtrim('$') + "$").toStringRef(Data))); - } - } - llvm_unreachable("Unhandled llvm.objcopy.MatchStyle enum"); -} - static Error addSymbolsToRenameFromFile(StringMap &SymbolsToRename, BumpPtrAllocator &Alloc, StringRef Filename) { diff --git a/llvm/unittests/ObjCopy/ObjCopyTest.cpp b/llvm/unittests/ObjCopy/ObjCopyTest.cpp --- a/llvm/unittests/ObjCopy/ObjCopyTest.cpp +++ b/llvm/unittests/ObjCopy/ObjCopyTest.cpp @@ -365,3 +365,171 @@ [](const Binary &File) { return File.isMachO(); }, "__foo", "1234", UpdateSection); } + +void removeSectionByPatternImpl( + const char *YamlCreationString, + std::function IsValidFormat, + StringRef SectionWildcard, StringRef SectionName) { + auto ErrHandler = [&](const Twine &Msg) { FAIL() << "Error: " << Msg; }; + + // Create Object file from YAML description. + SmallVector Storage; + std::unique_ptr Obj = + yaml2ObjectFile(Storage, YamlCreationString, ErrHandler); + ASSERT_TRUE(Obj); + ASSERT_TRUE(IsValidFormat(*Obj)); + + // Check that section is presented. + bool HasSection = false; + for (const object::SectionRef &Sect : (*Obj).sections()) { + Expected SectNameOrErr = Sect.getName(); + ASSERT_THAT_EXPECTED(SectNameOrErr, Succeeded()); + + if ((*SectNameOrErr) == SectionName) { + HasSection = true; + break; + } + } + EXPECT_TRUE(HasSection); + + Expected Pattern = objcopy::NameOrPattern::create( + SectionWildcard, objcopy::MatchStyle::Wildcard, + [](Error Err) -> Error { return Err; }); + + ConfigManager Config; + Config.Common.OutputFilename = "a.out"; + EXPECT_THAT_ERROR(Config.Common.ToRemove.addMatcher(std::move(Pattern)), + Succeeded()); + + // Call executeObjcopyOnBinary() + SmallVector DataVector; + raw_svector_ostream OutStream(DataVector); + Error Err = objcopy::executeObjcopyOnBinary(Config, *Obj.get(), OutStream); + ASSERT_FALSE(std::move(Err)); + + MemoryBufferRef Buffer(StringRef(DataVector.data(), DataVector.size()), + Config.Common.OutputFilename); + + // Check copied file. + Expected> Result = createBinary(Buffer); + ASSERT_THAT_EXPECTED(Result, Succeeded()); + ASSERT_TRUE(IsValidFormat(**Result)); + ASSERT_TRUE((*Result)->isObject()); + + // Check that section was removed. + HasSection = false; + for (const object::SectionRef &Sect : + static_cast((*Result).get())->sections()) { + Expected SectNameOrErr = Sect.getName(); + ASSERT_THAT_EXPECTED(SectNameOrErr, Succeeded()); + + if ((*SectNameOrErr) == SectionName) { + HasSection = true; + break; + } + } + EXPECT_TRUE(!HasSection); +} + +TEST(RemoveSectionByPattern, COFF) { + SCOPED_TRACE("removeSectionByPatternCOFF"); + + removeSectionByPatternImpl( + R"( +--- !COFF +header: + Machine: IMAGE_FILE_MACHINE_AMD64 + Characteristics: [ ] +sections: + - Name: .foo + Characteristics: [ ] + Alignment: 4 + SectionData: E800000000C3C3C3 +symbols: +... +)", + [](const Binary &File) { return File.isCOFF(); }, "\\.foo*", ".foo"); +} + +TEST(RemoveSectionByPattern, ELF) { + SCOPED_TRACE("removeSectionByPatternELF"); + + removeSectionByPatternImpl( + R"( +--- !ELF +FileHeader: + Class: ELFCLASS64 + Data: ELFDATA2LSB + Type: ET_REL +Sections: + - Name: .foo + Type: SHT_PROGBITS + Flags: [ SHF_ALLOC ] + Content: "12345678" +)", + [](const Binary &File) { return File.isELF(); }, "\\.foo*", ".foo"); +} + +TEST(RemoveSectionByPattern, MachO) { + SCOPED_TRACE("removeSectionByPatternMachO"); + + removeSectionByPatternImpl( + R"( +--- !mach-o +FileHeader: + magic: 0xFEEDFACF + cputype: 0x01000007 + cpusubtype: 0x80000003 + filetype: 0x00000001 + ncmds: 1 + sizeofcmds: 152 + flags: 0x00002000 + reserved: 0x00000000 +LoadCommands: + - cmd: LC_SEGMENT_64 + cmdsize: 152 + segname: __TEXT + vmaddr: 0 + vmsize: 4 + fileoff: 184 + filesize: 4 + maxprot: 7 + initprot: 7 + nsects: 1 + flags: 0 + Sections: + - sectname: __foo + segname: __TEXT + addr: 0x0000000000000000 + content: 'AABBCCDD' + size: 4 + offset: 184 + align: 0 + reloff: 0x00000000 + nreloc: 0 + flags: 0x80000400 + reserved1: 0x00000000 + reserved2: 0x00000000 + reserved3: 0x00000000 +... +)", + [](const Binary &File) { return File.isMachO(); }, "__TEXT,__foo*", + "__foo"); +} + +TEST(RemoveSectionByPattern, Wasm) { + SCOPED_TRACE("removeSectionByPatternWasm"); + + removeSectionByPatternImpl( + R"( +--- !WASM +FileHeader: + Version: 0x00000001 +Sections: + - Type: CUSTOM + Name: foo + Payload: ABC123 +... +)", + [](const Binary &File) { return File.isWasm(); }, "foo*", "foo"); +}