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 17 namespace llvm { 18 namespace objcopy { 19 namespace wasm { 20 21 using namespace object; 22 using SectionPred = std::function<bool(const Section &Sec)>; 23 24 static bool isDebugSection(const Section &Sec) { 25 return Sec.Name.starts_with(".debug"); 26 } 27 28 static bool isLinkerSection(const Section &Sec) { 29 return Sec.Name.starts_with("reloc.") || Sec.Name == "linking"; 30 } 31 32 static 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. 36 static bool isCommentSection(const Section &Sec) { 37 return Sec.Name == "producers"; 38 } 39 40 static 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 60 static 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 112 static 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 144 Error 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