1 //===------ utils/wasm2yaml.cpp - obj2yaml conversion tool ------*- C++ -*-===//
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 //===----------------------------------------------------------------------===//
10 #include "llvm/Object/COFF.h"
11 #include "llvm/ObjectYAML/WasmYAML.h"
12 #include "llvm/Support/ErrorHandling.h"
13 #include "llvm/Support/YAMLTraits.h"
16 using object::WasmSection
;
21 const object::WasmObjectFile
&Obj
;
24 WasmDumper(const object::WasmObjectFile
&O
) : Obj(O
) {}
26 ErrorOr
<WasmYAML::Object
*> dump();
28 std::unique_ptr
<WasmYAML::CustomSection
>
29 dumpCustomSection(const WasmSection
&WasmSec
);
34 static WasmYAML::Table
makeTable(const wasm::WasmTable
&Table
) {
36 T
.ElemType
= Table
.ElemType
;
37 T
.TableLimits
.Flags
= Table
.Limits
.Flags
;
38 T
.TableLimits
.Initial
= Table
.Limits
.Initial
;
39 T
.TableLimits
.Maximum
= Table
.Limits
.Maximum
;
43 static WasmYAML::Limits
makeLimits(const wasm::WasmLimits
&Limits
) {
45 L
.Flags
= Limits
.Flags
;
46 L
.Initial
= Limits
.Initial
;
47 L
.Maximum
= Limits
.Maximum
;
51 std::unique_ptr
<WasmYAML::CustomSection
>
52 WasmDumper::dumpCustomSection(const WasmSection
&WasmSec
) {
53 std::unique_ptr
<WasmYAML::CustomSection
> CustomSec
;
54 if (WasmSec
.Name
== "dylink") {
55 std::unique_ptr
<WasmYAML::DylinkSection
> DylinkSec
=
56 make_unique
<WasmYAML::DylinkSection
>();
57 const wasm::WasmDylinkInfo
& Info
= Obj
.dylinkInfo();
58 DylinkSec
->MemorySize
= Info
.MemorySize
;
59 DylinkSec
->MemoryAlignment
= Info
.MemoryAlignment
;
60 DylinkSec
->TableSize
= Info
.TableSize
;
61 DylinkSec
->TableAlignment
= Info
.TableAlignment
;
62 DylinkSec
->Needed
= Info
.Needed
;
63 CustomSec
= std::move(DylinkSec
);
64 } else if (WasmSec
.Name
== "name") {
65 std::unique_ptr
<WasmYAML::NameSection
> NameSec
=
66 make_unique
<WasmYAML::NameSection
>();
67 for (const llvm::wasm::WasmFunctionName
&Func
: Obj
.debugNames()) {
68 WasmYAML::NameEntry NameEntry
;
69 NameEntry
.Name
= Func
.Name
;
70 NameEntry
.Index
= Func
.Index
;
71 NameSec
->FunctionNames
.push_back(NameEntry
);
73 CustomSec
= std::move(NameSec
);
74 } else if (WasmSec
.Name
== "linking") {
75 std::unique_ptr
<WasmYAML::LinkingSection
> LinkingSec
=
76 make_unique
<WasmYAML::LinkingSection
>();
77 LinkingSec
->Version
= Obj
.linkingData().Version
;
79 ArrayRef
<StringRef
> Comdats
= Obj
.linkingData().Comdats
;
80 for (StringRef ComdatName
: Comdats
)
81 LinkingSec
->Comdats
.emplace_back(WasmYAML::Comdat
{ComdatName
, {}});
82 for (auto &Func
: Obj
.functions()) {
83 if (Func
.Comdat
!= UINT32_MAX
) {
84 LinkingSec
->Comdats
[Func
.Comdat
].Entries
.emplace_back(
85 WasmYAML::ComdatEntry
{wasm::WASM_COMDAT_FUNCTION
, Func
.Index
});
89 uint32_t SegmentIndex
= 0;
90 for (const object::WasmSegment
&Segment
: Obj
.dataSegments()) {
91 if (!Segment
.Data
.Name
.empty()) {
92 WasmYAML::SegmentInfo SegmentInfo
;
93 SegmentInfo
.Name
= Segment
.Data
.Name
;
94 SegmentInfo
.Index
= SegmentIndex
;
95 SegmentInfo
.Alignment
= Segment
.Data
.Alignment
;
96 SegmentInfo
.Flags
= Segment
.Data
.Flags
;
97 LinkingSec
->SegmentInfos
.push_back(SegmentInfo
);
99 if (Segment
.Data
.Comdat
!= UINT32_MAX
) {
100 LinkingSec
->Comdats
[Segment
.Data
.Comdat
].Entries
.emplace_back(
101 WasmYAML::ComdatEntry
{wasm::WASM_COMDAT_DATA
, SegmentIndex
});
106 uint32_t SymbolIndex
= 0;
107 for (const wasm::WasmSymbolInfo
&Symbol
: Obj
.linkingData().SymbolTable
) {
108 WasmYAML::SymbolInfo Info
;
109 Info
.Index
= SymbolIndex
++;
110 Info
.Kind
= static_cast<uint32_t>(Symbol
.Kind
);
111 Info
.Name
= Symbol
.Name
;
112 Info
.Flags
= Symbol
.Flags
;
113 switch (Symbol
.Kind
) {
114 case wasm::WASM_SYMBOL_TYPE_DATA
:
115 Info
.DataRef
= Symbol
.DataRef
;
117 case wasm::WASM_SYMBOL_TYPE_FUNCTION
:
118 case wasm::WASM_SYMBOL_TYPE_GLOBAL
:
119 case wasm::WASM_SYMBOL_TYPE_EVENT
:
120 Info
.ElementIndex
= Symbol
.ElementIndex
;
122 case wasm::WASM_SYMBOL_TYPE_SECTION
:
123 Info
.ElementIndex
= Symbol
.ElementIndex
;
126 LinkingSec
->SymbolTable
.emplace_back(Info
);
129 for (const wasm::WasmInitFunc
&Func
: Obj
.linkingData().InitFunctions
) {
130 WasmYAML::InitFunction F
{Func
.Priority
, Func
.Symbol
};
131 LinkingSec
->InitFunctions
.emplace_back(F
);
134 CustomSec
= std::move(LinkingSec
);
135 } else if (WasmSec
.Name
== "producers") {
136 std::unique_ptr
<WasmYAML::ProducersSection
> ProducersSec
=
137 make_unique
<WasmYAML::ProducersSection
>();
138 const llvm::wasm::WasmProducerInfo
&Info
= Obj
.getProducerInfo();
139 for (auto &E
: Info
.Languages
) {
140 WasmYAML::ProducerEntry Producer
;
141 Producer
.Name
= E
.first
;
142 Producer
.Version
= E
.second
;
143 ProducersSec
->Languages
.push_back(Producer
);
145 for (auto &E
: Info
.Tools
) {
146 WasmYAML::ProducerEntry Producer
;
147 Producer
.Name
= E
.first
;
148 Producer
.Version
= E
.second
;
149 ProducersSec
->Tools
.push_back(Producer
);
151 for (auto &E
: Info
.SDKs
) {
152 WasmYAML::ProducerEntry Producer
;
153 Producer
.Name
= E
.first
;
154 Producer
.Version
= E
.second
;
155 ProducersSec
->SDKs
.push_back(Producer
);
157 CustomSec
= std::move(ProducersSec
);
159 CustomSec
= make_unique
<WasmYAML::CustomSection
>(WasmSec
.Name
);
161 CustomSec
->Payload
= yaml::BinaryRef(WasmSec
.Content
);
165 ErrorOr
<WasmYAML::Object
*> WasmDumper::dump() {
166 auto Y
= make_unique
<WasmYAML::Object
>();
169 Y
->Header
.Version
= Obj
.getHeader().Version
;
172 for (const auto &Sec
: Obj
.sections()) {
173 const WasmSection
&WasmSec
= Obj
.getWasmSection(Sec
);
174 std::unique_ptr
<WasmYAML::Section
> S
;
175 switch (WasmSec
.Type
) {
176 case wasm::WASM_SEC_CUSTOM
: {
177 if (WasmSec
.Name
.startswith("reloc.")) {
178 // Relocations are attached the sections they apply to rather than
179 // being represented as a custom section in the YAML output.
182 S
= dumpCustomSection(WasmSec
);
185 case wasm::WASM_SEC_TYPE
: {
186 auto TypeSec
= make_unique
<WasmYAML::TypeSection
>();
188 for (const auto &FunctionSig
: Obj
.types()) {
189 WasmYAML::Signature Sig
;
191 Sig
.ReturnType
= wasm::WASM_TYPE_NORESULT
;
192 assert(FunctionSig
.Returns
.size() <= 1 &&
193 "Functions with multiple returns are not supported");
194 if (FunctionSig
.Returns
.size())
195 Sig
.ReturnType
= static_cast<uint32_t>(FunctionSig
.Returns
[0]);
196 for (const auto &ParamType
: FunctionSig
.Params
)
197 Sig
.ParamTypes
.emplace_back(static_cast<uint32_t>(ParamType
));
198 TypeSec
->Signatures
.push_back(Sig
);
200 S
= std::move(TypeSec
);
203 case wasm::WASM_SEC_IMPORT
: {
204 auto ImportSec
= make_unique
<WasmYAML::ImportSection
>();
205 for (auto &Import
: Obj
.imports()) {
207 Im
.Module
= Import
.Module
;
208 Im
.Field
= Import
.Field
;
209 Im
.Kind
= Import
.Kind
;
211 case wasm::WASM_EXTERNAL_FUNCTION
:
212 Im
.SigIndex
= Import
.SigIndex
;
214 case wasm::WASM_EXTERNAL_GLOBAL
:
215 Im
.GlobalImport
.Type
= Import
.Global
.Type
;
216 Im
.GlobalImport
.Mutable
= Import
.Global
.Mutable
;
218 case wasm::WASM_EXTERNAL_EVENT
:
219 Im
.EventImport
.Attribute
= Import
.Event
.Attribute
;
220 Im
.EventImport
.SigIndex
= Import
.Event
.SigIndex
;
222 case wasm::WASM_EXTERNAL_TABLE
:
223 Im
.TableImport
= makeTable(Import
.Table
);
225 case wasm::WASM_EXTERNAL_MEMORY
:
226 Im
.Memory
= makeLimits(Import
.Memory
);
229 ImportSec
->Imports
.push_back(Im
);
231 S
= std::move(ImportSec
);
234 case wasm::WASM_SEC_FUNCTION
: {
235 auto FuncSec
= make_unique
<WasmYAML::FunctionSection
>();
236 for (const auto &Func
: Obj
.functionTypes()) {
237 FuncSec
->FunctionTypes
.push_back(Func
);
239 S
= std::move(FuncSec
);
242 case wasm::WASM_SEC_TABLE
: {
243 auto TableSec
= make_unique
<WasmYAML::TableSection
>();
244 for (const wasm::WasmTable
&Table
: Obj
.tables()) {
245 TableSec
->Tables
.push_back(makeTable(Table
));
247 S
= std::move(TableSec
);
250 case wasm::WASM_SEC_MEMORY
: {
251 auto MemorySec
= make_unique
<WasmYAML::MemorySection
>();
252 for (const wasm::WasmLimits
&Memory
: Obj
.memories()) {
253 MemorySec
->Memories
.push_back(makeLimits(Memory
));
255 S
= std::move(MemorySec
);
258 case wasm::WASM_SEC_GLOBAL
: {
259 auto GlobalSec
= make_unique
<WasmYAML::GlobalSection
>();
260 for (auto &Global
: Obj
.globals()) {
262 G
.Index
= Global
.Index
;
263 G
.Type
= Global
.Type
.Type
;
264 G
.Mutable
= Global
.Type
.Mutable
;
265 G
.InitExpr
= Global
.InitExpr
;
266 GlobalSec
->Globals
.push_back(G
);
268 S
= std::move(GlobalSec
);
271 case wasm::WASM_SEC_EVENT
: {
272 auto EventSec
= make_unique
<WasmYAML::EventSection
>();
273 for (auto &Event
: Obj
.events()) {
275 E
.Index
= Event
.Index
;
276 E
.Attribute
= Event
.Type
.Attribute
;
277 E
.SigIndex
= Event
.Type
.SigIndex
;
278 EventSec
->Events
.push_back(E
);
280 S
= std::move(EventSec
);
283 case wasm::WASM_SEC_START
: {
284 auto StartSec
= make_unique
<WasmYAML::StartSection
>();
285 StartSec
->StartFunction
= Obj
.startFunction();
286 S
= std::move(StartSec
);
289 case wasm::WASM_SEC_EXPORT
: {
290 auto ExportSec
= make_unique
<WasmYAML::ExportSection
>();
291 for (auto &Export
: Obj
.exports()) {
293 Ex
.Name
= Export
.Name
;
294 Ex
.Kind
= Export
.Kind
;
295 Ex
.Index
= Export
.Index
;
296 ExportSec
->Exports
.push_back(Ex
);
298 S
= std::move(ExportSec
);
301 case wasm::WASM_SEC_ELEM
: {
302 auto ElemSec
= make_unique
<WasmYAML::ElemSection
>();
303 for (auto &Segment
: Obj
.elements()) {
304 WasmYAML::ElemSegment Seg
;
305 Seg
.TableIndex
= Segment
.TableIndex
;
306 Seg
.Offset
= Segment
.Offset
;
307 for (auto &Func
: Segment
.Functions
) {
308 Seg
.Functions
.push_back(Func
);
310 ElemSec
->Segments
.push_back(Seg
);
312 S
= std::move(ElemSec
);
315 case wasm::WASM_SEC_CODE
: {
316 auto CodeSec
= make_unique
<WasmYAML::CodeSection
>();
317 for (auto &Func
: Obj
.functions()) {
318 WasmYAML::Function Function
;
319 Function
.Index
= Func
.Index
;
320 for (auto &Local
: Func
.Locals
) {
321 WasmYAML::LocalDecl LocalDecl
;
322 LocalDecl
.Type
= Local
.Type
;
323 LocalDecl
.Count
= Local
.Count
;
324 Function
.Locals
.push_back(LocalDecl
);
326 Function
.Body
= yaml::BinaryRef(Func
.Body
);
327 CodeSec
->Functions
.push_back(Function
);
329 S
= std::move(CodeSec
);
332 case wasm::WASM_SEC_DATA
: {
333 auto DataSec
= make_unique
<WasmYAML::DataSection
>();
334 for (const object::WasmSegment
&Segment
: Obj
.dataSegments()) {
335 WasmYAML::DataSegment Seg
;
336 Seg
.SectionOffset
= Segment
.SectionOffset
;
337 Seg
.MemoryIndex
= Segment
.Data
.MemoryIndex
;
338 Seg
.Offset
= Segment
.Data
.Offset
;
339 Seg
.Content
= yaml::BinaryRef(Segment
.Data
.Content
);
340 DataSec
->Segments
.push_back(Seg
);
342 S
= std::move(DataSec
);
346 llvm_unreachable("Unknown section type");
349 for (const wasm::WasmRelocation
&Reloc
: WasmSec
.Relocations
) {
350 WasmYAML::Relocation R
;
352 R
.Index
= Reloc
.Index
;
353 R
.Offset
= Reloc
.Offset
;
354 R
.Addend
= Reloc
.Addend
;
355 S
->Relocations
.push_back(R
);
357 Y
->Sections
.push_back(std::move(S
));
363 std::error_code
wasm2yaml(raw_ostream
&Out
, const object::WasmObjectFile
&Obj
) {
364 WasmDumper
Dumper(Obj
);
365 ErrorOr
<WasmYAML::Object
*> YAMLOrErr
= Dumper
.dump();
366 if (std::error_code EC
= YAMLOrErr
.getError())
369 std::unique_ptr
<WasmYAML::Object
> YAML(YAMLOrErr
.get());
370 yaml::Output
Yout(Out
);
373 return std::error_code();