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