1 //===------ utils/wasm2yaml.cpp - obj2yaml conversion tool ------*- C++ -*-===//
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 "obj2yaml.h"
10 #include "llvm/Object/COFF.h"
11 #include "llvm/ObjectYAML/WasmYAML.h"
12 #include "llvm/Support/ErrorHandling.h"
13 #include "llvm/Support/YAMLTraits.h"
14 
15 using namespace llvm;
16 using object::WasmSection;
17 
18 namespace {
19 
20 class WasmDumper {
21   const object::WasmObjectFile &Obj;
22 
23 public:
24   WasmDumper(const object::WasmObjectFile &O) : Obj(O) {}
25 
26   ErrorOr<WasmYAML::Object *> dump();
27 
28   std::unique_ptr<WasmYAML::CustomSection>
29   dumpCustomSection(const WasmSection &WasmSec);
30 };
31 
32 } // namespace
33 
34 static WasmYAML::Limits makeLimits(const wasm::WasmLimits &Limits) {
35   WasmYAML::Limits L;
36   L.Flags = Limits.Flags;
37   L.Initial = Limits.Initial;
38   L.Maximum = Limits.Maximum;
39   return L;
40 }
41 
42 static WasmYAML::Table makeTable(uint32_t Index,
43                                  const wasm::WasmTableType &Type) {
44   WasmYAML::Table T;
45   T.Index = Index;
46   T.ElemType = Type.ElemType;
47   T.TableLimits = makeLimits(Type.Limits);
48   return T;
49 }
50 
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         std::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         std::make_unique<WasmYAML::NameSection>();
67     for (const llvm::wasm::WasmDebugName &Name : Obj.debugNames()) {
68       WasmYAML::NameEntry NameEntry;
69       NameEntry.Name = Name.Name;
70       NameEntry.Index = Name.Index;
71       if (Name.Type == llvm::wasm::NameType::FUNCTION) {
72         NameSec->FunctionNames.push_back(NameEntry);
73       } else {
74         assert(Name.Type == llvm::wasm::NameType::GLOBAL);
75         NameSec->GlobalNames.push_back(NameEntry);
76       }
77     }
78     CustomSec = std::move(NameSec);
79   } else if (WasmSec.Name == "linking") {
80     std::unique_ptr<WasmYAML::LinkingSection> LinkingSec =
81         std::make_unique<WasmYAML::LinkingSection>();
82     LinkingSec->Version = Obj.linkingData().Version;
83 
84     ArrayRef<StringRef> Comdats = Obj.linkingData().Comdats;
85     for (StringRef ComdatName : Comdats)
86       LinkingSec->Comdats.emplace_back(WasmYAML::Comdat{ComdatName, {}});
87     for (auto &Func : Obj.functions()) {
88       if (Func.Comdat != UINT32_MAX) {
89         LinkingSec->Comdats[Func.Comdat].Entries.emplace_back(
90             WasmYAML::ComdatEntry{wasm::WASM_COMDAT_FUNCTION, Func.Index});
91       }
92     }
93 
94     uint32_t SegmentIndex = 0;
95     for (const object::WasmSegment &Segment : Obj.dataSegments()) {
96       if (!Segment.Data.Name.empty()) {
97         WasmYAML::SegmentInfo SegmentInfo;
98         SegmentInfo.Name = Segment.Data.Name;
99         SegmentInfo.Index = SegmentIndex;
100         SegmentInfo.Alignment = Segment.Data.Alignment;
101         SegmentInfo.Flags = Segment.Data.LinkerFlags;
102         LinkingSec->SegmentInfos.push_back(SegmentInfo);
103       }
104       if (Segment.Data.Comdat != UINT32_MAX) {
105         LinkingSec->Comdats[Segment.Data.Comdat].Entries.emplace_back(
106             WasmYAML::ComdatEntry{wasm::WASM_COMDAT_DATA, SegmentIndex});
107       }
108       SegmentIndex++;
109     }
110 
111     uint32_t SymbolIndex = 0;
112     for (const wasm::WasmSymbolInfo &Symbol : Obj.linkingData().SymbolTable) {
113       WasmYAML::SymbolInfo Info;
114       Info.Index = SymbolIndex++;
115       Info.Kind = static_cast<uint32_t>(Symbol.Kind);
116       Info.Name = Symbol.Name;
117       Info.Flags = Symbol.Flags;
118       switch (Symbol.Kind) {
119       case wasm::WASM_SYMBOL_TYPE_DATA:
120         Info.DataRef = Symbol.DataRef;
121         break;
122       case wasm::WASM_SYMBOL_TYPE_FUNCTION:
123       case wasm::WASM_SYMBOL_TYPE_GLOBAL:
124       case wasm::WASM_SYMBOL_TYPE_TABLE:
125       case wasm::WASM_SYMBOL_TYPE_EVENT:
126         Info.ElementIndex = Symbol.ElementIndex;
127         break;
128       case wasm::WASM_SYMBOL_TYPE_SECTION:
129         Info.ElementIndex = Symbol.ElementIndex;
130         break;
131       }
132       LinkingSec->SymbolTable.emplace_back(Info);
133     }
134 
135     for (const wasm::WasmInitFunc &Func : Obj.linkingData().InitFunctions) {
136       WasmYAML::InitFunction F{Func.Priority, Func.Symbol};
137       LinkingSec->InitFunctions.emplace_back(F);
138     }
139 
140     CustomSec = std::move(LinkingSec);
141   } else if (WasmSec.Name == "producers") {
142     std::unique_ptr<WasmYAML::ProducersSection> ProducersSec =
143         std::make_unique<WasmYAML::ProducersSection>();
144     const llvm::wasm::WasmProducerInfo &Info = Obj.getProducerInfo();
145     for (auto &E : Info.Languages) {
146       WasmYAML::ProducerEntry Producer;
147       Producer.Name = E.first;
148       Producer.Version = E.second;
149       ProducersSec->Languages.push_back(Producer);
150     }
151     for (auto &E : Info.Tools) {
152       WasmYAML::ProducerEntry Producer;
153       Producer.Name = E.first;
154       Producer.Version = E.second;
155       ProducersSec->Tools.push_back(Producer);
156     }
157     for (auto &E : Info.SDKs) {
158       WasmYAML::ProducerEntry Producer;
159       Producer.Name = E.first;
160       Producer.Version = E.second;
161       ProducersSec->SDKs.push_back(Producer);
162     }
163     CustomSec = std::move(ProducersSec);
164   } else if (WasmSec.Name == "target_features") {
165     std::unique_ptr<WasmYAML::TargetFeaturesSection> TargetFeaturesSec =
166         std::make_unique<WasmYAML::TargetFeaturesSection>();
167     for (auto &E : Obj.getTargetFeatures()) {
168       WasmYAML::FeatureEntry Feature;
169       Feature.Prefix = E.Prefix;
170       Feature.Name = E.Name;
171       TargetFeaturesSec->Features.push_back(Feature);
172     }
173     CustomSec = std::move(TargetFeaturesSec);
174   } else {
175     CustomSec = std::make_unique<WasmYAML::CustomSection>(WasmSec.Name);
176   }
177   CustomSec->Payload = yaml::BinaryRef(WasmSec.Content);
178   return CustomSec;
179 }
180 
181 ErrorOr<WasmYAML::Object *> WasmDumper::dump() {
182   auto Y = std::make_unique<WasmYAML::Object>();
183 
184   // Dump header
185   Y->Header.Version = Obj.getHeader().Version;
186 
187   // Dump sections
188   for (const auto &Sec : Obj.sections()) {
189     const WasmSection &WasmSec = Obj.getWasmSection(Sec);
190     std::unique_ptr<WasmYAML::Section> S;
191     switch (WasmSec.Type) {
192     case wasm::WASM_SEC_CUSTOM: {
193       if (WasmSec.Name.startswith("reloc.")) {
194         // Relocations are attached the sections they apply to rather than
195         // being represented as a custom section in the YAML output.
196         continue;
197       }
198       S = dumpCustomSection(WasmSec);
199       break;
200     }
201     case wasm::WASM_SEC_TYPE: {
202       auto TypeSec = std::make_unique<WasmYAML::TypeSection>();
203       uint32_t Index = 0;
204       for (const auto &FunctionSig : Obj.types()) {
205         WasmYAML::Signature Sig;
206         Sig.Index = Index++;
207         for (const auto &ParamType : FunctionSig.Params)
208           Sig.ParamTypes.emplace_back(static_cast<uint32_t>(ParamType));
209         for (const auto &ReturnType : FunctionSig.Returns)
210           Sig.ReturnTypes.emplace_back(static_cast<uint32_t>(ReturnType));
211         TypeSec->Signatures.push_back(Sig);
212       }
213       S = std::move(TypeSec);
214       break;
215     }
216     case wasm::WASM_SEC_IMPORT: {
217       auto ImportSec = std::make_unique<WasmYAML::ImportSection>();
218       for (auto &Import : Obj.imports()) {
219         WasmYAML::Import Im;
220         Im.Module = Import.Module;
221         Im.Field = Import.Field;
222         Im.Kind = Import.Kind;
223         switch (Im.Kind) {
224         case wasm::WASM_EXTERNAL_FUNCTION:
225           Im.SigIndex = Import.SigIndex;
226           break;
227         case wasm::WASM_EXTERNAL_GLOBAL:
228           Im.GlobalImport.Type = Import.Global.Type;
229           Im.GlobalImport.Mutable = Import.Global.Mutable;
230           break;
231         case wasm::WASM_EXTERNAL_EVENT:
232           Im.EventImport.Attribute = Import.Event.Attribute;
233           Im.EventImport.SigIndex = Import.Event.SigIndex;
234           break;
235         case wasm::WASM_EXTERNAL_TABLE:
236           // FIXME: Currently we always output an index of 0 for any imported
237           // table.
238           Im.TableImport = makeTable(0, Import.Table);
239           break;
240         case wasm::WASM_EXTERNAL_MEMORY:
241           Im.Memory = makeLimits(Import.Memory);
242           break;
243         }
244         ImportSec->Imports.push_back(Im);
245       }
246       S = std::move(ImportSec);
247       break;
248     }
249     case wasm::WASM_SEC_FUNCTION: {
250       auto FuncSec = std::make_unique<WasmYAML::FunctionSection>();
251       for (const auto &Func : Obj.functionTypes()) {
252         FuncSec->FunctionTypes.push_back(Func);
253       }
254       S = std::move(FuncSec);
255       break;
256     }
257     case wasm::WASM_SEC_TABLE: {
258       auto TableSec = std::make_unique<WasmYAML::TableSection>();
259       for (const wasm::WasmTable &Table : Obj.tables()) {
260         TableSec->Tables.push_back(makeTable(Table.Index, Table.Type));
261       }
262       S = std::move(TableSec);
263       break;
264     }
265     case wasm::WASM_SEC_MEMORY: {
266       auto MemorySec = std::make_unique<WasmYAML::MemorySection>();
267       for (const wasm::WasmLimits &Memory : Obj.memories()) {
268         MemorySec->Memories.push_back(makeLimits(Memory));
269       }
270       S = std::move(MemorySec);
271       break;
272     }
273     case wasm::WASM_SEC_EVENT: {
274       auto EventSec = std::make_unique<WasmYAML::EventSection>();
275       for (auto &Event : Obj.events()) {
276         WasmYAML::Event E;
277         E.Index = Event.Index;
278         E.Attribute = Event.Type.Attribute;
279         E.SigIndex = Event.Type.SigIndex;
280         EventSec->Events.push_back(E);
281       }
282       S = std::move(EventSec);
283       break;
284     }
285     case wasm::WASM_SEC_GLOBAL: {
286       auto GlobalSec = std::make_unique<WasmYAML::GlobalSection>();
287       for (auto &Global : Obj.globals()) {
288         WasmYAML::Global G;
289         G.Index = Global.Index;
290         G.Type = Global.Type.Type;
291         G.Mutable = Global.Type.Mutable;
292         G.InitExpr = Global.InitExpr;
293         GlobalSec->Globals.push_back(G);
294       }
295       S = std::move(GlobalSec);
296       break;
297     }
298     case wasm::WASM_SEC_START: {
299       auto StartSec = std::make_unique<WasmYAML::StartSection>();
300       StartSec->StartFunction = Obj.startFunction();
301       S = std::move(StartSec);
302       break;
303     }
304     case wasm::WASM_SEC_EXPORT: {
305       auto ExportSec = std::make_unique<WasmYAML::ExportSection>();
306       for (auto &Export : Obj.exports()) {
307         WasmYAML::Export Ex;
308         Ex.Name = Export.Name;
309         Ex.Kind = Export.Kind;
310         Ex.Index = Export.Index;
311         ExportSec->Exports.push_back(Ex);
312       }
313       S = std::move(ExportSec);
314       break;
315     }
316     case wasm::WASM_SEC_ELEM: {
317       auto ElemSec = std::make_unique<WasmYAML::ElemSection>();
318       for (auto &Segment : Obj.elements()) {
319         WasmYAML::ElemSegment Seg;
320         Seg.TableIndex = Segment.TableIndex;
321         Seg.Offset = Segment.Offset;
322         for (auto &Func : Segment.Functions) {
323           Seg.Functions.push_back(Func);
324         }
325         ElemSec->Segments.push_back(Seg);
326       }
327       S = std::move(ElemSec);
328       break;
329     }
330     case wasm::WASM_SEC_CODE: {
331       auto CodeSec = std::make_unique<WasmYAML::CodeSection>();
332       for (auto &Func : Obj.functions()) {
333         WasmYAML::Function Function;
334         Function.Index = Func.Index;
335         for (auto &Local : Func.Locals) {
336           WasmYAML::LocalDecl LocalDecl;
337           LocalDecl.Type = Local.Type;
338           LocalDecl.Count = Local.Count;
339           Function.Locals.push_back(LocalDecl);
340         }
341         Function.Body = yaml::BinaryRef(Func.Body);
342         CodeSec->Functions.push_back(Function);
343       }
344       S = std::move(CodeSec);
345       break;
346     }
347     case wasm::WASM_SEC_DATA: {
348       auto DataSec = std::make_unique<WasmYAML::DataSection>();
349       for (const object::WasmSegment &Segment : Obj.dataSegments()) {
350         WasmYAML::DataSegment Seg;
351         Seg.SectionOffset = Segment.SectionOffset;
352         Seg.InitFlags = Segment.Data.InitFlags;
353         Seg.MemoryIndex = Segment.Data.MemoryIndex;
354         Seg.Offset = Segment.Data.Offset;
355         Seg.Content = yaml::BinaryRef(Segment.Data.Content);
356         DataSec->Segments.push_back(Seg);
357       }
358       S = std::move(DataSec);
359       break;
360     }
361     case wasm::WASM_SEC_DATACOUNT: {
362       auto DataCountSec = std::make_unique<WasmYAML::DataCountSection>();
363       DataCountSec->Count = Obj.dataSegments().size();
364       S = std::move(DataCountSec);
365       break;
366     }
367     default:
368       llvm_unreachable("Unknown section type");
369       break;
370     }
371     for (const wasm::WasmRelocation &Reloc : WasmSec.Relocations) {
372       WasmYAML::Relocation R;
373       R.Type = Reloc.Type;
374       R.Index = Reloc.Index;
375       R.Offset = Reloc.Offset;
376       R.Addend = Reloc.Addend;
377       S->Relocations.push_back(R);
378     }
379     Y->Sections.push_back(std::move(S));
380   }
381 
382   return Y.release();
383 }
384 
385 std::error_code wasm2yaml(raw_ostream &Out, const object::WasmObjectFile &Obj) {
386   WasmDumper Dumper(Obj);
387   ErrorOr<WasmYAML::Object *> YAMLOrErr = Dumper.dump();
388   if (std::error_code EC = YAMLOrErr.getError())
389     return EC;
390 
391   std::unique_ptr<WasmYAML::Object> YAML(YAMLOrErr.get());
392   yaml::Output Yout(Out);
393   Yout << *YAML;
394 
395   return std::error_code();
396 }
397