1 //===- WasmObjcopy.cpp ----------------------------------------------------===//
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
7 //===----------------------------------------------------------------------===//
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"
21 using namespace object
;
22 using SectionPred
= std::function
<bool(const Section
&Sec
)>;
24 static bool isDebugSection(const Section
&Sec
) {
25 return Sec
.Name
.starts_with(".debug") || Sec
.Name
.starts_with("reloc..debug");
28 static bool isLinkerSection(const Section
&Sec
) {
29 return Sec
.Name
.starts_with("reloc.") || Sec
.Name
== "linking";
32 static bool isNameSection(const Section
&Sec
) { return Sec
.Name
== "name"; }
34 // Sections which are known to be "comments" or informational and do not affect
36 static bool isCommentSection(const Section
&Sec
) {
37 return Sec
.Name
== "producers";
40 static Error
dumpSectionToFile(StringRef SecName
, StringRef Filename
,
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());
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())
53 return Error::success();
56 return createStringError(errc::invalid_argument
, "section '%s' not found",
57 SecName
.str().c_str());
60 static void removeSections(const CommonConfig
&Config
, Object
&Obj
) {
61 SectionPred RemovePred
= [](const Section
&) { return false; };
63 // Explicitly-requested sections.
64 if (!Config
.ToRemove
.empty()) {
65 RemovePred
= [&Config
](const Section
&Sec
) {
66 return Config
.ToRemove
.matches(Sec
.Name
);
70 if (Config
.StripDebug
) {
71 RemovePred
= [RemovePred
](const Section
&Sec
) {
72 return RemovePred(Sec
) || isDebugSection(Sec
);
76 if (Config
.StripAll
) {
77 RemovePred
= [RemovePred
](const Section
&Sec
) {
78 return RemovePred(Sec
) || isDebugSection(Sec
) || isLinkerSection(Sec
) ||
79 isNameSection(Sec
) || isCommentSection(Sec
);
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
);
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
);
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
))
104 // Otherwise defer to RemovePred.
105 return RemovePred(Sec
);
109 Obj
.removeSections(RemovePred
);
112 static Error
handleArgs(const CommonConfig
&Config
, Object
&Obj
) {
113 // Only support AddSection, DumpSection, RemoveSection for now.
114 for (StringRef Flag
: Config
.DumpSection
) {
117 std::tie(SecName
, FileName
) = Flag
.split("=");
118 if (Error E
= dumpSectionToFile(SecName
, FileName
, Obj
))
119 return createFileError(FileName
, std::move(E
));
122 removeSections(Config
, Obj
);
124 for (const NewSectionInfo
&NewSection
: Config
.AddSection
) {
126 Sec
.SectionType
= llvm::wasm::WASM_SEC_CUSTOM
;
127 Sec
.Name
= NewSection
.SectionName
;
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());
138 Obj
.addSectionWithOwnedContents(Sec
, std::move(BufferCopy
));
141 return Error::success();
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();
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
))
154 Writer
TheWriter(*Obj
, Out
);
155 if (Error E
= TheWriter
.write())
156 return createFileError(Config
.OutputFilename
, std::move(E
));
157 return Error::success();
160 } // end namespace wasm
161 } // end namespace objcopy
162 } // end namespace llvm