brintos

brintos / llvm-project-archived public Read only

0
0
Text · 11.9 KiB · 4382c73 Raw
398 lines · cpp
1//===- ObjCopyTest.cpp ----------------------------------------------------===//2//3// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.4// See https://llvm.org/LICENSE.txt for license information.5// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception6//7//===----------------------------------------------------------------------===//8 9#include "llvm/ObjCopy/ObjCopy.h"10#include "llvm/ObjCopy/ConfigManager.h"11#include "llvm/Object/ObjectFile.h"12#include "llvm/ObjectYAML/yaml2obj.h"13#include "llvm/Support/Error.h"14#include "llvm/Support/FileUtilities.h"15#include "llvm/Testing/Support/Error.h"16#include "gtest/gtest.h"17 18using namespace llvm;19using namespace object;20using namespace objcopy;21using namespace yaml;22 23const char *SimpleFileCOFFYAML = R"(24--- !COFF25header:26  Machine:         IMAGE_FILE_MACHINE_AMD6427  Characteristics: [  ]28sections:29  - Name:            .text30    Characteristics: [  ]31    Alignment:       432    SectionData:     E800000000C3C3C333symbols:34...35)";36 37const char *SimpleFileELFYAML = R"(38--- !ELF39FileHeader:40  Class:    ELFCLASS6441  Data:     ELFDATA2LSB42  Type:     ET_REL43Sections:44  - Name:            .text45    Type:            SHT_PROGBITS46    Flags:           [ SHF_ALLOC ]47    Content:        "12345678"48)";49 50const char *SimpleFileMachOYAML = R"(51--- !mach-o52FileHeader:53  magic:           0xFEEDFACF54  cputype:         0x0100000755  cpusubtype:      0x8000000356  filetype:        0x0000000157  ncmds:           158  sizeofcmds:      15259  flags:           0x0000200060  reserved:        0x0000000061LoadCommands:62  - cmd:             LC_SEGMENT_6463    cmdsize:         15264    segname:         __TEXT65    vmaddr:          066    vmsize:          467    fileoff:         18468    filesize:        469    maxprot:         770    initprot:        771    nsects:          172    flags:           073    Sections:74      - sectname:        __text75        segname:         __TEXT76        addr:            0x000000000000000077        content:         'AABBCCDD'78        size:            479        offset:          18480        align:           081        reloff:          0x0000000082        nreloc:          083        flags:           0x8000040084        reserved1:       0x0000000085        reserved2:       0x0000000086        reserved3:       0x0000000087...88)";89 90const char *SimpleFileWasmYAML = R"(91--- !WASM92FileHeader:93  Version:         0x0000000194Sections:95  - Type: CUSTOM96    Name: text97    Payload: ABC12398...99)";100 101// Create ObjectFile from \p YamlCreationString and do validation using \p102// IsValidFormat checker. \p Storage is a storage for data. \returns created103// ObjectFile.104Expected<std::unique_ptr<ObjectFile>> createObjectFileFromYamlDescription(105    const char *YamlCreationString, SmallVector<char> &Storage,106    function_ref<bool(const Binary &File)> IsValidFormat) {107  auto ErrHandler = [&](const Twine &Msg) { FAIL() << "Error: " << Msg; };108 109  std::unique_ptr<ObjectFile> Obj =110      yaml2ObjectFile(Storage, YamlCreationString, ErrHandler);111  if (!Obj)112    return createError("could not create ObjectFile from yaml description");113 114  if (!IsValidFormat(*Obj))115    return createError("wrong file format");116 117  return std::move(Obj);118}119 120// Call objcopy::executeObjcopyOnBinary for \p Config and \p In. \p DataVector121// is a holder for data. \returns Binary for copied data.122Expected<std::unique_ptr<Binary>>123callObjCopy(ConfigManager &Config, object::Binary &In,124            SmallVector<char> &DataVector,125            function_ref<bool(const Binary &File)> IsValidFormat) {126  raw_svector_ostream OutStream(DataVector);127 128  if (Error Err = objcopy::executeObjcopyOnBinary(Config, In, OutStream))129    return std::move(Err);130 131  MemoryBufferRef Buffer(StringRef(DataVector.data(), DataVector.size()),132                         Config.Common.OutputFilename);133 134  Expected<std::unique_ptr<Binary>> Result = createBinary(Buffer);135 136  // Check copied file.137  if (!Result)138    return Result;139 140  if (!IsValidFormat(**Result))141    return createError("wrong file format");142 143  if (!(*Result)->isObject())144    return createError("binary is not object file");145 146  return Result;147}148 149// \returns true if specified \p File has a section named \p SectionName.150bool hasSection(ObjectFile &File, StringRef SectionName) {151  for (const object::SectionRef &Sec : File.sections()) {152    Expected<StringRef> CurSecNameOrErr = Sec.getName();153    if (!CurSecNameOrErr)154      continue;155 156    if (*CurSecNameOrErr == SectionName)157      return true;158  }159 160  return false;161}162 163// Check that specified \p File has a section \p SectionName and its data164// matches \p SectionData.165void checkSectionData(ObjectFile &File, StringRef SectionName,166                      StringRef SectionData) {167  for (const object::SectionRef &Sec : File.sections()) {168    Expected<StringRef> CurSecNameOrErr = Sec.getName();169    ASSERT_THAT_EXPECTED(CurSecNameOrErr, Succeeded());170 171    if (*CurSecNameOrErr == SectionName) {172      Expected<StringRef> CurSectionData = Sec.getContents();173      ASSERT_THAT_EXPECTED(CurSectionData, Succeeded());174      EXPECT_TRUE(Sec.getSize() == SectionData.size());175      EXPECT_TRUE(memcmp(CurSectionData->data(), SectionData.data(),176                         SectionData.size()) == 0);177      return;178    }179  }180 181  // Section SectionName must be presented.182  EXPECT_TRUE(false);183}184 185void copySimpleInMemoryFileImpl(186    const char *YamlCreationString,187    function_ref<bool(const Binary &File)> IsValidFormat) {188  SCOPED_TRACE("copySimpleInMemoryFileImpl");189 190  // Create Object file from YAML description.191  SmallVector<char> Storage;192  Expected<std::unique_ptr<ObjectFile>> Obj =193      createObjectFileFromYamlDescription(YamlCreationString, Storage,194                                          IsValidFormat);195  ASSERT_THAT_EXPECTED(Obj, Succeeded());196 197  ConfigManager Config;198  Config.Common.OutputFilename = "a.out";199 200  // Call executeObjcopyOnBinary()201  SmallVector<char> DataVector;202  Expected<std::unique_ptr<Binary>> Result =203      callObjCopy(Config, *Obj.get(), DataVector, IsValidFormat);204  ASSERT_THAT_EXPECTED(Result, Succeeded());205}206 207TEST(CopySimpleInMemoryFile, COFF) {208  SCOPED_TRACE("CopySimpleInMemoryFileCOFF");209 210  copySimpleInMemoryFileImpl(SimpleFileCOFFYAML,211                             [](const Binary &File) { return File.isCOFF(); });212}213 214TEST(CopySimpleInMemoryFile, ELF) {215  SCOPED_TRACE("CopySimpleInMemoryFileELF");216 217  copySimpleInMemoryFileImpl(SimpleFileELFYAML,218                             [](const Binary &File) { return File.isELF(); });219}220 221TEST(CopySimpleInMemoryFile, MachO) {222  SCOPED_TRACE("CopySimpleInMemoryFileMachO");223 224  copySimpleInMemoryFileImpl(SimpleFileMachOYAML,225                             [](const Binary &File) { return File.isMachO(); });226}227 228TEST(CopySimpleInMemoryFile, Wasm) {229  SCOPED_TRACE("CopySimpleInMemoryFileWasm");230 231  copySimpleInMemoryFileImpl(SimpleFileWasmYAML,232                             [](const Binary &File) { return File.isWasm(); });233}234 235enum Action : uint8_t { AddSection, UpdateSection };236 237void addOrUpdateSectionToFileImpl(238    const char *YamlCreationString,239    function_ref<bool(const Binary &File)> IsValidFormat,240    StringRef NewSectionName, StringRef NewSectionData, Action SectionAction) {241  SCOPED_TRACE("addOrUpdateSectionToFileImpl");242 243  // Create Object file from YAML description.244  SmallVector<char> Storage;245  Expected<std::unique_ptr<ObjectFile>> Obj =246      createObjectFileFromYamlDescription(YamlCreationString, Storage,247                                          IsValidFormat);248  ASSERT_THAT_EXPECTED(Obj, Succeeded());249 250  std::unique_ptr<MemoryBuffer> NewSectionBuffer =251      MemoryBuffer::getMemBuffer(NewSectionData, NewSectionName, false);252  std::string Name;253  if ((*Obj)->isMachO())254    Name = "__TEXT," + NewSectionName.str();255  else256    Name = NewSectionName.str();257 258  ConfigManager Config;259  Config.Common.OutputFilename = "a.out";260  if (SectionAction == AddSection)261    Config.Common.AddSection.push_back({Name, std::move(NewSectionBuffer)});262  else263    Config.Common.UpdateSection.push_back({Name, std::move(NewSectionBuffer)});264 265  // Call executeObjcopyOnBinary()266  SmallVector<char> DataVector;267  Expected<std::unique_ptr<Binary>> Result =268      callObjCopy(Config, *Obj.get(), DataVector, IsValidFormat);269  ASSERT_THAT_EXPECTED(Result, Succeeded());270 271  // Check that copied file has the new section.272  checkSectionData(*static_cast<ObjectFile *>((*Result).get()), NewSectionName,273                   NewSectionData);274}275 276TEST(AddSection, COFF) {277  SCOPED_TRACE("addSectionToFileCOFF");278 279  addOrUpdateSectionToFileImpl(280      SimpleFileCOFFYAML, [](const Binary &File) { return File.isCOFF(); },281      ".foo", "1234", AddSection);282}283 284TEST(AddSection, ELF) {285  SCOPED_TRACE("addSectionToFileELF");286 287  addOrUpdateSectionToFileImpl(288      SimpleFileELFYAML, [](const Binary &File) { return File.isELF(); },289      ".foo", "1234", AddSection);290}291 292TEST(AddSection, MachO) {293  SCOPED_TRACE("addSectionToFileMachO");294 295  addOrUpdateSectionToFileImpl(296      SimpleFileMachOYAML, [](const Binary &File) { return File.isMachO(); },297      "__foo", "1234", AddSection);298}299 300TEST(AddSection, Wasm) {301  SCOPED_TRACE("addSectionToFileWasm");302 303  addOrUpdateSectionToFileImpl(304      SimpleFileWasmYAML, [](const Binary &File) { return File.isWasm(); },305      ".foo", "1234", AddSection);306}307 308TEST(UpdateSection, COFF) {309  SCOPED_TRACE("updateSectionToFileCOFF");310 311  addOrUpdateSectionToFileImpl(312      SimpleFileCOFFYAML, [](const Binary &File) { return File.isCOFF(); },313      ".text", "1234", UpdateSection);314}315 316TEST(UpdateSection, ELF) {317  SCOPED_TRACE("updateSectionToFileELF");318 319  addOrUpdateSectionToFileImpl(320      SimpleFileELFYAML, [](const Binary &File) { return File.isELF(); },321      ".text", "1234", UpdateSection);322}323 324TEST(UpdateSection, MachO) {325  SCOPED_TRACE("updateSectionToFileMachO");326 327  addOrUpdateSectionToFileImpl(328      SimpleFileMachOYAML, [](const Binary &File) { return File.isMachO(); },329      "__text", "1234", UpdateSection);330}331 332void removeSectionByPatternImpl(333    const char *YamlCreationString,334    function_ref<bool(const Binary &File)> IsValidFormat,335    StringRef SectionWildcard, StringRef SectionName) {336  SCOPED_TRACE("removeSectionByPatternImpl");337 338  // Create Object file from YAML description.339  SmallVector<char> Storage;340  Expected<std::unique_ptr<ObjectFile>> Obj =341      createObjectFileFromYamlDescription(YamlCreationString, Storage,342                                          IsValidFormat);343  ASSERT_THAT_EXPECTED(Obj, Succeeded());344 345  // Check that section is present.346  EXPECT_TRUE(hasSection(**Obj, SectionName));347 348  Expected<NameOrPattern> Pattern = objcopy::NameOrPattern::create(349      SectionWildcard, objcopy::MatchStyle::Wildcard,350      [](Error Err) { return Err; });351 352  ConfigManager Config;353  Config.Common.OutputFilename = "a.out";354  EXPECT_THAT_ERROR(Config.Common.ToRemove.addMatcher(std::move(Pattern)),355                    Succeeded());356 357  SmallVector<char> DataVector;358  Expected<std::unique_ptr<Binary>> Result =359      callObjCopy(Config, *Obj.get(), DataVector, IsValidFormat);360  ASSERT_THAT_EXPECTED(Result, Succeeded());361 362  // Check that section was removed.363  EXPECT_FALSE(364      hasSection(*static_cast<ObjectFile *>((*Result).get()), SectionName));365}366 367TEST(RemoveSectionByPattern, COFF) {368  SCOPED_TRACE("removeSectionByPatternCOFF");369 370  removeSectionByPatternImpl(371      SimpleFileCOFFYAML, [](const Binary &File) { return File.isCOFF(); },372      "\\.text*", ".text");373}374 375TEST(RemoveSectionByPattern, ELF) {376  SCOPED_TRACE("removeSectionByPatternELF");377 378  removeSectionByPatternImpl(379      SimpleFileELFYAML, [](const Binary &File) { return File.isELF(); },380      "\\.text*", ".text");381}382 383TEST(RemoveSectionByPattern, MachO) {384  SCOPED_TRACE("removeSectionByPatternMachO");385 386  removeSectionByPatternImpl(387      SimpleFileMachOYAML, [](const Binary &File) { return File.isMachO(); },388      "__TEXT,__text*", "__text");389}390 391TEST(RemoveSectionByPattern, Wasm) {392  SCOPED_TRACE("removeSectionByPatternWasm");393 394  removeSectionByPatternImpl(395      SimpleFileWasmYAML, [](const Binary &File) { return File.isWasm(); },396      "text*", "text");397}398