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/LEB128.h"
14 #include "llvm/Support/YAMLTraits.h"
17 using object::WasmSection
;
22 const object::WasmObjectFile
&Obj
;
25 WasmDumper(const object::WasmObjectFile
&O
) : Obj(O
) {}
27 ErrorOr
<WasmYAML::Object
*> dump();
29 std::unique_ptr
<WasmYAML::CustomSection
>
30 dumpCustomSection(const WasmSection
&WasmSec
);
35 static WasmYAML::Limits
makeLimits(const wasm::WasmLimits
&Limits
) {
37 L
.Flags
= Limits
.Flags
;
38 L
.Minimum
= Limits
.Minimum
;
39 L
.Maximum
= Limits
.Maximum
;
43 static WasmYAML::Table
makeTable(uint32_t Index
,
44 const wasm::WasmTableType
&Type
) {
47 T
.ElemType
= Type
.ElemType
;
48 T
.TableLimits
= makeLimits(Type
.Limits
);
52 std::unique_ptr
<WasmYAML::CustomSection
>
53 WasmDumper::dumpCustomSection(const WasmSection
&WasmSec
) {
54 std::unique_ptr
<WasmYAML::CustomSection
> CustomSec
;
55 if (WasmSec
.Name
== "dylink" || WasmSec
.Name
== "dylink.0") {
56 std::unique_ptr
<WasmYAML::DylinkSection
> DylinkSec
=
57 std::make_unique
<WasmYAML::DylinkSection
>();
58 const wasm::WasmDylinkInfo
& Info
= Obj
.dylinkInfo();
59 DylinkSec
->MemorySize
= Info
.MemorySize
;
60 DylinkSec
->MemoryAlignment
= Info
.MemoryAlignment
;
61 DylinkSec
->TableSize
= Info
.TableSize
;
62 DylinkSec
->TableAlignment
= Info
.TableAlignment
;
63 DylinkSec
->Needed
= Info
.Needed
;
64 for (const auto &Imp
: Info
.ImportInfo
)
65 DylinkSec
->ImportInfo
.push_back({Imp
.Module
, Imp
.Field
, Imp
.Flags
});
66 for (const auto &Exp
: Info
.ExportInfo
)
67 DylinkSec
->ExportInfo
.push_back({Exp
.Name
, Exp
.Flags
});
68 CustomSec
= std::move(DylinkSec
);
69 } else if (WasmSec
.Name
== "name") {
70 std::unique_ptr
<WasmYAML::NameSection
> NameSec
=
71 std::make_unique
<WasmYAML::NameSection
>();
72 for (const llvm::wasm::WasmDebugName
&Name
: Obj
.debugNames()) {
73 WasmYAML::NameEntry NameEntry
;
74 NameEntry
.Name
= Name
.Name
;
75 NameEntry
.Index
= Name
.Index
;
76 if (Name
.Type
== llvm::wasm::NameType::FUNCTION
) {
77 NameSec
->FunctionNames
.push_back(NameEntry
);
78 } else if (Name
.Type
== llvm::wasm::NameType::GLOBAL
) {
79 NameSec
->GlobalNames
.push_back(NameEntry
);
81 assert(Name
.Type
== llvm::wasm::NameType::DATA_SEGMENT
);
82 NameSec
->DataSegmentNames
.push_back(NameEntry
);
85 CustomSec
= std::move(NameSec
);
86 } else if (WasmSec
.Name
== "linking") {
87 std::unique_ptr
<WasmYAML::LinkingSection
> LinkingSec
=
88 std::make_unique
<WasmYAML::LinkingSection
>();
89 LinkingSec
->Version
= Obj
.linkingData().Version
;
91 ArrayRef
<StringRef
> Comdats
= Obj
.linkingData().Comdats
;
92 for (StringRef ComdatName
: Comdats
)
93 LinkingSec
->Comdats
.emplace_back(WasmYAML::Comdat
{ComdatName
, {}});
94 for (auto &Func
: Obj
.functions()) {
95 if (Func
.Comdat
!= UINT32_MAX
) {
96 LinkingSec
->Comdats
[Func
.Comdat
].Entries
.emplace_back(
97 WasmYAML::ComdatEntry
{wasm::WASM_COMDAT_FUNCTION
, Func
.Index
});
101 uint32_t SegmentIndex
= 0;
102 for (const object::WasmSegment
&Segment
: Obj
.dataSegments()) {
103 if (!Segment
.Data
.Name
.empty()) {
104 WasmYAML::SegmentInfo SegmentInfo
;
105 SegmentInfo
.Name
= Segment
.Data
.Name
;
106 SegmentInfo
.Index
= SegmentIndex
;
107 SegmentInfo
.Alignment
= Segment
.Data
.Alignment
;
108 SegmentInfo
.Flags
= Segment
.Data
.LinkingFlags
;
109 LinkingSec
->SegmentInfos
.push_back(SegmentInfo
);
111 if (Segment
.Data
.Comdat
!= UINT32_MAX
) {
112 LinkingSec
->Comdats
[Segment
.Data
.Comdat
].Entries
.emplace_back(
113 WasmYAML::ComdatEntry
{wasm::WASM_COMDAT_DATA
, SegmentIndex
});
117 uint32_t SectionIndex
= 0;
118 for (const auto &Sec
: Obj
.sections()) {
119 const WasmSection
&WasmSec
= Obj
.getWasmSection(Sec
);
120 if (WasmSec
.Comdat
!= UINT32_MAX
)
121 LinkingSec
->Comdats
[WasmSec
.Comdat
].Entries
.emplace_back(
122 WasmYAML::ComdatEntry
{wasm::WASM_COMDAT_SECTION
, SectionIndex
});
126 uint32_t SymbolIndex
= 0;
127 for (const wasm::WasmSymbolInfo
&Symbol
: Obj
.linkingData().SymbolTable
) {
128 WasmYAML::SymbolInfo Info
;
129 Info
.Index
= SymbolIndex
++;
130 Info
.Kind
= static_cast<uint32_t>(Symbol
.Kind
);
131 Info
.Name
= Symbol
.Name
;
132 Info
.Flags
= Symbol
.Flags
;
133 switch (Symbol
.Kind
) {
134 case wasm::WASM_SYMBOL_TYPE_DATA
:
135 Info
.DataRef
= Symbol
.DataRef
;
137 case wasm::WASM_SYMBOL_TYPE_FUNCTION
:
138 case wasm::WASM_SYMBOL_TYPE_GLOBAL
:
139 case wasm::WASM_SYMBOL_TYPE_TABLE
:
140 case wasm::WASM_SYMBOL_TYPE_TAG
:
141 Info
.ElementIndex
= Symbol
.ElementIndex
;
143 case wasm::WASM_SYMBOL_TYPE_SECTION
:
144 Info
.ElementIndex
= Symbol
.ElementIndex
;
147 LinkingSec
->SymbolTable
.emplace_back(Info
);
150 for (const wasm::WasmInitFunc
&Func
: Obj
.linkingData().InitFunctions
) {
151 WasmYAML::InitFunction F
{Func
.Priority
, Func
.Symbol
};
152 LinkingSec
->InitFunctions
.emplace_back(F
);
155 CustomSec
= std::move(LinkingSec
);
156 } else if (WasmSec
.Name
== "producers") {
157 std::unique_ptr
<WasmYAML::ProducersSection
> ProducersSec
=
158 std::make_unique
<WasmYAML::ProducersSection
>();
159 const llvm::wasm::WasmProducerInfo
&Info
= Obj
.getProducerInfo();
160 for (auto &E
: Info
.Languages
) {
161 WasmYAML::ProducerEntry Producer
;
162 Producer
.Name
= E
.first
;
163 Producer
.Version
= E
.second
;
164 ProducersSec
->Languages
.push_back(Producer
);
166 for (auto &E
: Info
.Tools
) {
167 WasmYAML::ProducerEntry Producer
;
168 Producer
.Name
= E
.first
;
169 Producer
.Version
= E
.second
;
170 ProducersSec
->Tools
.push_back(Producer
);
172 for (auto &E
: Info
.SDKs
) {
173 WasmYAML::ProducerEntry Producer
;
174 Producer
.Name
= E
.first
;
175 Producer
.Version
= E
.second
;
176 ProducersSec
->SDKs
.push_back(Producer
);
178 CustomSec
= std::move(ProducersSec
);
179 } else if (WasmSec
.Name
== "target_features") {
180 std::unique_ptr
<WasmYAML::TargetFeaturesSection
> TargetFeaturesSec
=
181 std::make_unique
<WasmYAML::TargetFeaturesSection
>();
182 for (auto &E
: Obj
.getTargetFeatures()) {
183 WasmYAML::FeatureEntry Feature
;
184 Feature
.Prefix
= E
.Prefix
;
185 Feature
.Name
= E
.Name
;
186 TargetFeaturesSec
->Features
.push_back(Feature
);
188 CustomSec
= std::move(TargetFeaturesSec
);
190 CustomSec
= std::make_unique
<WasmYAML::CustomSection
>(WasmSec
.Name
);
192 CustomSec
->Payload
= yaml::BinaryRef(WasmSec
.Content
);
196 ErrorOr
<WasmYAML::Object
*> WasmDumper::dump() {
197 auto Y
= std::make_unique
<WasmYAML::Object
>();
200 Y
->Header
.Version
= Obj
.getHeader().Version
;
203 for (const auto &Sec
: Obj
.sections()) {
204 const WasmSection
&WasmSec
= Obj
.getWasmSection(Sec
);
205 std::unique_ptr
<WasmYAML::Section
> S
;
206 switch (WasmSec
.Type
) {
207 case wasm::WASM_SEC_CUSTOM
: {
208 if (WasmSec
.Name
.startswith("reloc.")) {
209 // Relocations are attached the sections they apply to rather than
210 // being represented as a custom section in the YAML output.
213 S
= dumpCustomSection(WasmSec
);
216 case wasm::WASM_SEC_TYPE
: {
217 auto TypeSec
= std::make_unique
<WasmYAML::TypeSection
>();
219 for (const auto &FunctionSig
: Obj
.types()) {
220 WasmYAML::Signature Sig
;
222 for (const auto &ParamType
: FunctionSig
.Params
)
223 Sig
.ParamTypes
.emplace_back(static_cast<uint32_t>(ParamType
));
224 for (const auto &ReturnType
: FunctionSig
.Returns
)
225 Sig
.ReturnTypes
.emplace_back(static_cast<uint32_t>(ReturnType
));
226 TypeSec
->Signatures
.push_back(Sig
);
228 S
= std::move(TypeSec
);
231 case wasm::WASM_SEC_IMPORT
: {
232 auto ImportSec
= std::make_unique
<WasmYAML::ImportSection
>();
233 for (auto &Import
: Obj
.imports()) {
235 Im
.Module
= Import
.Module
;
236 Im
.Field
= Import
.Field
;
237 Im
.Kind
= Import
.Kind
;
239 case wasm::WASM_EXTERNAL_FUNCTION
:
240 Im
.SigIndex
= Import
.SigIndex
;
242 case wasm::WASM_EXTERNAL_GLOBAL
:
243 Im
.GlobalImport
.Type
= Import
.Global
.Type
;
244 Im
.GlobalImport
.Mutable
= Import
.Global
.Mutable
;
246 case wasm::WASM_EXTERNAL_TAG
:
247 Im
.SigIndex
= Import
.SigIndex
;
249 case wasm::WASM_EXTERNAL_TABLE
:
250 // FIXME: Currently we always output an index of 0 for any imported
252 Im
.TableImport
= makeTable(0, Import
.Table
);
254 case wasm::WASM_EXTERNAL_MEMORY
:
255 Im
.Memory
= makeLimits(Import
.Memory
);
258 ImportSec
->Imports
.push_back(Im
);
260 S
= std::move(ImportSec
);
263 case wasm::WASM_SEC_FUNCTION
: {
264 auto FuncSec
= std::make_unique
<WasmYAML::FunctionSection
>();
265 for (const auto &Func
: Obj
.functions()) {
266 FuncSec
->FunctionTypes
.push_back(Func
.SigIndex
);
268 S
= std::move(FuncSec
);
271 case wasm::WASM_SEC_TABLE
: {
272 auto TableSec
= std::make_unique
<WasmYAML::TableSection
>();
273 for (const wasm::WasmTable
&Table
: Obj
.tables()) {
274 TableSec
->Tables
.push_back(makeTable(Table
.Index
, Table
.Type
));
276 S
= std::move(TableSec
);
279 case wasm::WASM_SEC_MEMORY
: {
280 auto MemorySec
= std::make_unique
<WasmYAML::MemorySection
>();
281 for (const wasm::WasmLimits
&Memory
: Obj
.memories()) {
282 MemorySec
->Memories
.push_back(makeLimits(Memory
));
284 S
= std::move(MemorySec
);
287 case wasm::WASM_SEC_TAG
: {
288 auto TagSec
= std::make_unique
<WasmYAML::TagSection
>();
289 for (auto &Tag
: Obj
.tags()) {
290 TagSec
->TagTypes
.push_back(Tag
.SigIndex
);
292 S
= std::move(TagSec
);
295 case wasm::WASM_SEC_GLOBAL
: {
296 auto GlobalSec
= std::make_unique
<WasmYAML::GlobalSection
>();
297 for (auto &Global
: Obj
.globals()) {
299 G
.Index
= Global
.Index
;
300 G
.Type
= Global
.Type
.Type
;
301 G
.Mutable
= Global
.Type
.Mutable
;
302 G
.Init
.Extended
= Global
.InitExpr
.Extended
;
303 if (Global
.InitExpr
.Extended
) {
304 G
.Init
.Body
= Global
.InitExpr
.Body
;
306 G
.Init
.Inst
= Global
.InitExpr
.Inst
;
308 GlobalSec
->Globals
.push_back(G
);
310 S
= std::move(GlobalSec
);
313 case wasm::WASM_SEC_START
: {
314 auto StartSec
= std::make_unique
<WasmYAML::StartSection
>();
315 StartSec
->StartFunction
= Obj
.startFunction();
316 S
= std::move(StartSec
);
319 case wasm::WASM_SEC_EXPORT
: {
320 auto ExportSec
= std::make_unique
<WasmYAML::ExportSection
>();
321 for (auto &Export
: Obj
.exports()) {
323 Ex
.Name
= Export
.Name
;
324 Ex
.Kind
= Export
.Kind
;
325 Ex
.Index
= Export
.Index
;
326 ExportSec
->Exports
.push_back(Ex
);
328 S
= std::move(ExportSec
);
331 case wasm::WASM_SEC_ELEM
: {
332 auto ElemSec
= std::make_unique
<WasmYAML::ElemSection
>();
333 for (auto &Segment
: Obj
.elements()) {
334 WasmYAML::ElemSegment Seg
;
335 Seg
.Flags
= Segment
.Flags
;
336 Seg
.TableNumber
= Segment
.TableNumber
;
337 Seg
.ElemKind
= Segment
.ElemKind
;
338 Seg
.Offset
.Extended
= Segment
.Offset
.Extended
;
339 if (Seg
.Offset
.Extended
) {
340 Seg
.Offset
.Body
= yaml::BinaryRef(Segment
.Offset
.Body
);
342 Seg
.Offset
.Inst
= Segment
.Offset
.Inst
;
344 append_range(Seg
.Functions
, Segment
.Functions
);
345 ElemSec
->Segments
.push_back(Seg
);
347 S
= std::move(ElemSec
);
350 case wasm::WASM_SEC_CODE
: {
351 auto CodeSec
= std::make_unique
<WasmYAML::CodeSection
>();
352 for (auto &Func
: Obj
.functions()) {
353 WasmYAML::Function Function
;
354 Function
.Index
= Func
.Index
;
355 for (auto &Local
: Func
.Locals
) {
356 WasmYAML::LocalDecl LocalDecl
;
357 LocalDecl
.Type
= Local
.Type
;
358 LocalDecl
.Count
= Local
.Count
;
359 Function
.Locals
.push_back(LocalDecl
);
361 Function
.Body
= yaml::BinaryRef(Func
.Body
);
362 CodeSec
->Functions
.push_back(Function
);
364 S
= std::move(CodeSec
);
367 case wasm::WASM_SEC_DATA
: {
368 auto DataSec
= std::make_unique
<WasmYAML::DataSection
>();
369 for (const object::WasmSegment
&Segment
: Obj
.dataSegments()) {
370 WasmYAML::DataSegment Seg
;
371 Seg
.SectionOffset
= Segment
.SectionOffset
;
372 Seg
.InitFlags
= Segment
.Data
.InitFlags
;
373 Seg
.MemoryIndex
= Segment
.Data
.MemoryIndex
;
374 Seg
.Offset
.Extended
= Segment
.Data
.Offset
.Extended
;
375 if (Seg
.Offset
.Extended
) {
376 Seg
.Offset
.Body
= yaml::BinaryRef(Segment
.Data
.Offset
.Body
);
378 Seg
.Offset
.Inst
= Segment
.Data
.Offset
.Inst
;
380 Seg
.Content
= yaml::BinaryRef(Segment
.Data
.Content
);
381 DataSec
->Segments
.push_back(Seg
);
383 S
= std::move(DataSec
);
386 case wasm::WASM_SEC_DATACOUNT
: {
387 auto DataCountSec
= std::make_unique
<WasmYAML::DataCountSection
>();
388 DataCountSec
->Count
= Obj
.dataSegments().size();
389 S
= std::move(DataCountSec
);
393 llvm_unreachable("Unknown section type");
397 // Only propagate the section size encoding length if it's not the minimal
398 // size or 5 (the default "padded" value). This is to avoid having every
399 // YAML output polluted with this value when we usually don't care about it
400 // (and avoid rewriting all the test expectations).
401 if (WasmSec
.HeaderSecSizeEncodingLen
&&
402 WasmSec
.HeaderSecSizeEncodingLen
!=
403 getULEB128Size(WasmSec
.Content
.size()) &&
404 WasmSec
.HeaderSecSizeEncodingLen
!= 5)
405 S
->HeaderSecSizeEncodingLen
= WasmSec
.HeaderSecSizeEncodingLen
;
407 for (const wasm::WasmRelocation
&Reloc
: WasmSec
.Relocations
) {
408 WasmYAML::Relocation R
;
410 R
.Index
= Reloc
.Index
;
411 R
.Offset
= Reloc
.Offset
;
412 R
.Addend
= Reloc
.Addend
;
413 S
->Relocations
.push_back(R
);
415 Y
->Sections
.push_back(std::move(S
));
421 std::error_code
wasm2yaml(raw_ostream
&Out
, const object::WasmObjectFile
&Obj
) {
422 WasmDumper
Dumper(Obj
);
423 ErrorOr
<WasmYAML::Object
*> YAMLOrErr
= Dumper
.dump();
424 if (std::error_code EC
= YAMLOrErr
.getError())
427 std::unique_ptr
<WasmYAML::Object
> YAML(YAMLOrErr
.get());
428 yaml::Output
Yout(Out
);
431 return std::error_code();