1//===- WasmObjcopy.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-exception 6// 7//===----------------------------------------------------------------------===// 8 9#include "llvm/ObjCopy/wasm/WasmObjcopy.h" 10#include "WasmObject.h" 11#include "WasmReader.h" 12#include "WasmWriter.h" 13#include "llvm/ObjCopy/CommonConfig.h" 14#include "llvm/Support/Errc.h" 15#include "llvm/Support/FileOutputBuffer.h" 16 17namespace llvm { 18namespace objcopy { 19namespace wasm { 20 21using namespace object; 22using SectionPred = std::function<bool(const Section &Sec)>; 23 24static bool isDebugSection(const Section &Sec) { 25 return Sec.Name.starts_with(".debug"); 26} 27 28static bool isLinkerSection(const Section &Sec) { 29 return Sec.Name.starts_with("reloc.") || Sec.Name == "linking"; 30} 31 32static bool isNameSection(const Section &Sec) { return Sec.Name == "name"; } 33 34// Sections which are known to be "comments" or informational and do not affect 35// program semantics. 36static bool isCommentSection(const Section &Sec) { 37 return Sec.Name == "producers"; 38} 39 40static Error dumpSectionToFile(StringRef SecName, StringRef Filename, 41 Object &Obj) { 42 for (const Section &Sec : Obj.Sections) { 43 if (Sec.Name == SecName) { 44 ArrayRef<uint8_t> Contents = Sec.Contents; 45 Expected<std::unique_ptr<FileOutputBuffer>> BufferOrErr = 46 FileOutputBuffer::create(Filename, Contents.size()); 47 if (!BufferOrErr) 48 return BufferOrErr.takeError(); 49 std::unique_ptr<FileOutputBuffer> Buf = std::move(*BufferOrErr); 50 std::copy(Contents.begin(), Contents.end(), Buf->getBufferStart()); 51 if (Error E = Buf->commit()) 52 return E; 53 return Error::success(); 54 } 55 } 56 return createStringError(errc::invalid_argument, "section '%s' not found", 57 SecName.str().c_str()); 58} 59 60static void removeSections(const CommonConfig &Config, Object &Obj) { 61 SectionPred RemovePred = [](const Section &) { return false; }; 62 63 // Explicitly-requested sections. 64 if (!Config.ToRemove.empty()) { 65 RemovePred = [&Config](const Section &Sec) { 66 return Config.ToRemove.matches(Sec.Name); 67 }; 68 } 69 70 if (Config.StripDebug) { 71 RemovePred = [RemovePred](const Section &Sec) { 72 return RemovePred(Sec) || isDebugSection(Sec); 73 }; 74 } 75 76 if (Config.StripAll) { 77 RemovePred = [RemovePred](const Section &Sec) { 78 return RemovePred(Sec) || isDebugSection(Sec) || isLinkerSection(Sec) || 79 isNameSection(Sec) || isCommentSection(Sec); 80 }; 81 } 82 83 if (Config.OnlyKeepDebug) { 84 RemovePred = [&Config](const Section &Sec) { 85 // Keep debug sections, unless explicitly requested to remove. 86 // Remove everything else, including known sections. 87 return Config.ToRemove.matches(Sec.Name) || !isDebugSection(Sec); 88 }; 89 } 90 91 if (!Config.OnlySection.empty()) { 92 RemovePred = [&Config](const Section &Sec) { 93 // Explicitly keep these sections regardless of previous removes. 94 // Remove everything else, inluding known sections. 95 return !Config.OnlySection.matches(Sec.Name); 96 }; 97 } 98 99 if (!Config.KeepSection.empty()) { 100 RemovePred = [&Config, RemovePred](const Section &Sec) { 101 // Explicitly keep these sections regardless of previous removes. 102 if (Config.KeepSection.matches(Sec.Name)) 103 return false; 104 // Otherwise defer to RemovePred. 105 return RemovePred(Sec); 106 }; 107 } 108 109 Obj.removeSections(RemovePred); 110} 111 112static Error handleArgs(const CommonConfig &Config, Object &Obj) { 113 // Only support AddSection, DumpSection, RemoveSection for now. 114 for (StringRef Flag : Config.DumpSection) { 115 StringRef SecName; 116 StringRef FileName; 117 std::tie(SecName, FileName) = Flag.split("="); 118 if (Error E = dumpSectionToFile(SecName, FileName, Obj)) 119 return createFileError(FileName, std::move(E)); 120 } 121 122 removeSections(Config, Obj); 123 124 for (const NewSectionInfo &NewSection : Config.AddSection) { 125 Section Sec; 126 Sec.SectionType = llvm::wasm::WASM_SEC_CUSTOM; 127 Sec.Name = NewSection.SectionName; 128 129 llvm::StringRef InputData = 130 llvm::StringRef(NewSection.SectionData->getBufferStart(), 131 NewSection.SectionData->getBufferSize()); 132 std::unique_ptr<MemoryBuffer> BufferCopy = MemoryBuffer::getMemBufferCopy( 133 InputData, NewSection.SectionData->getBufferIdentifier()); 134 Sec.Contents = ArrayRef<uint8_t>( 135 reinterpret_cast<const uint8_t *>(BufferCopy->getBufferStart()), 136 BufferCopy->getBufferSize()); 137 138 Obj.addSectionWithOwnedContents(Sec, std::move(BufferCopy)); 139 } 140 141 return Error::success(); 142} 143 144Error executeObjcopyOnBinary(const CommonConfig &Config, const WasmConfig &, 145 object::WasmObjectFile &In, raw_ostream &Out) { 146 Reader TheReader(In); 147 Expected<std::unique_ptr<Object>> ObjOrErr = TheReader.create(); 148 if (!ObjOrErr) 149 return createFileError(Config.InputFilename, ObjOrErr.takeError()); 150 Object *Obj = ObjOrErr->get(); 151 assert(Obj && "Unable to deserialize Wasm object"); 152 if (Error E = handleArgs(Config, *Obj)) 153 return E; 154 Writer TheWriter(*Obj, Out); 155 if (Error E = TheWriter.write()) 156 return createFileError(Config.OutputFilename, std::move(E)); 157 return Error::success(); 158} 159 160} // end namespace wasm 161} // end namespace objcopy 162} // end namespace llvm 163