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