1 //===------ utils/wasm2yaml.cpp - obj2yaml conversion tool ------*- C++ -*-===//
2 //
3 //                     The LLVM Compiler Infrastructure
4 //
5 // This file is distributed under the University of Illinois Open Source
6 // License. See LICENSE.TXT for details.
7 //
8 //===----------------------------------------------------------------------===//
9 
10 #include "obj2yaml.h"
11 #include "llvm/Object/COFF.h"
12 #include "llvm/ObjectYAML/WasmYAML.h"
13 #include "llvm/Support/ErrorHandling.h"
14 #include "llvm/Support/YAMLTraits.h"
15 
16 using namespace llvm;
17 using object::WasmSection;
18 
19 namespace {
20 
21 class WasmDumper {
22   const object::WasmObjectFile &Obj;
23 
24 public:
25   WasmDumper(const object::WasmObjectFile &O) : Obj(O) {}
26 
27   ErrorOr<WasmYAML::Object *> dump();
28 
29   std::unique_ptr<WasmYAML::CustomSection>
30   dumpCustomSection(const WasmSection &WasmSec);
31 };
32 
33 } // namespace
34 
35 static WasmYAML::Table make_table(const wasm::WasmTable &Table) {
36   WasmYAML::Table T;
37   T.ElemType = Table.ElemType;
38   T.TableLimits.Flags = Table.Limits.Flags;
39   T.TableLimits.Initial = Table.Limits.Initial;
40   T.TableLimits.Maximum = Table.Limits.Maximum;
41   return T;
42 }
43 
44 static WasmYAML::Limits make_limits(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> WasmDumper::dumpCustomSection(const WasmSection &WasmSec) {
53   std::unique_ptr<WasmYAML::CustomSection> CustomSec;
54   if (WasmSec.Name == "name") {
55     std::unique_ptr<WasmYAML::NameSection> NameSec = make_unique<WasmYAML::NameSection>();
56     for (const object::SymbolRef& Sym: Obj.symbols()) {
57       uint32_t Flags = Sym.getFlags();
58       // Skip over symbols that come from imports or exports
59       if (Flags &
60           (object::SymbolRef::SF_Global | object::SymbolRef::SF_Undefined))
61         continue;
62       Expected<StringRef> NameOrError = Sym.getName();
63       if (!NameOrError)
64         continue;
65       WasmYAML::NameEntry NameEntry;
66       NameEntry.Name = *NameOrError;
67       NameEntry.Index = Sym.getValue();
68       NameSec->FunctionNames.push_back(NameEntry);
69     }
70     CustomSec = std::move(NameSec);
71   } else if (WasmSec.Name == "linking") {
72     std::unique_ptr<WasmYAML::LinkingSection> LinkingSec = make_unique<WasmYAML::LinkingSection>();
73     for (const object::SymbolRef& Sym: Obj.symbols()) {
74       const object::WasmSymbol Symbol = Obj.getWasmSymbol(Sym);
75       if (Symbol.Flags != 0) {
76         WasmYAML::SymbolInfo Info = { Symbol.Name, Symbol.Flags };
77         LinkingSec->SymbolInfos.push_back(Info);
78       }
79     }
80     LinkingSec->DataSize = Obj.linkingData().DataSize;
81     LinkingSec->DataAlignment = Obj.linkingData().DataAlignment;
82     CustomSec = std::move(LinkingSec);
83   } else {
84     CustomSec = make_unique<WasmYAML::CustomSection>(WasmSec.Name);
85   }
86   CustomSec->Payload = yaml::BinaryRef(WasmSec.Content);
87   return CustomSec;
88 }
89 
90 ErrorOr<WasmYAML::Object *> WasmDumper::dump() {
91   auto Y = make_unique<WasmYAML::Object>();
92 
93   // Dump header
94   Y->Header.Version = Obj.getHeader().Version;
95 
96   // Dump sections
97   for (const auto &Sec : Obj.sections()) {
98     const WasmSection &WasmSec = Obj.getWasmSection(Sec);
99     std::unique_ptr<WasmYAML::Section> S;
100     switch (WasmSec.Type) {
101     case wasm::WASM_SEC_CUSTOM: {
102       if (WasmSec.Name.startswith("reloc.")) {
103         // Relocations are attached the sections they apply to rather than
104         // being represented as a custom section in the YAML output.
105         continue;
106       }
107       S = dumpCustomSection(WasmSec);
108       break;
109     }
110     case wasm::WASM_SEC_TYPE: {
111       auto TypeSec = make_unique<WasmYAML::TypeSection>();
112       uint32_t Index = 0;
113       for (const auto &FunctionSig : Obj.types()) {
114         WasmYAML::Signature Sig;
115         Sig.Index = Index++;
116         Sig.ReturnType = FunctionSig.ReturnType;
117         for (const auto &ParamType : FunctionSig.ParamTypes)
118           Sig.ParamTypes.push_back(ParamType);
119         TypeSec->Signatures.push_back(Sig);
120       }
121       S = std::move(TypeSec);
122       break;
123     }
124     case wasm::WASM_SEC_IMPORT: {
125       auto ImportSec = make_unique<WasmYAML::ImportSection>();
126       for (auto &Import : Obj.imports()) {
127         WasmYAML::Import Im;
128         Im.Module = Import.Module;
129         Im.Field = Import.Field;
130         Im.Kind = Import.Kind;
131         switch (Im.Kind) {
132         case wasm::WASM_EXTERNAL_FUNCTION:
133           Im.SigIndex = Import.SigIndex;
134           break;
135         case wasm::WASM_EXTERNAL_GLOBAL:
136           Im.GlobalImport.Type = Import.Global.Type;
137           Im.GlobalImport.Mutable = Import.Global.Mutable;
138           break;
139         case wasm::WASM_EXTERNAL_TABLE:
140           Im.TableImport = make_table(Import.Table);
141           break;
142         case wasm::WASM_EXTERNAL_MEMORY:
143           Im.Memory = make_limits(Import.Memory);
144           break;
145         }
146         ImportSec->Imports.push_back(Im);
147       }
148       S = std::move(ImportSec);
149       break;
150     }
151     case wasm::WASM_SEC_FUNCTION: {
152       auto FuncSec = make_unique<WasmYAML::FunctionSection>();
153       for (const auto &Func : Obj.functionTypes()) {
154         FuncSec->FunctionTypes.push_back(Func);
155       }
156       S = std::move(FuncSec);
157       break;
158     }
159     case wasm::WASM_SEC_TABLE: {
160       auto TableSec = make_unique<WasmYAML::TableSection>();
161       for (const wasm::WasmTable &Table : Obj.tables()) {
162         TableSec->Tables.push_back(make_table(Table));
163       }
164       S = std::move(TableSec);
165       break;
166     }
167     case wasm::WASM_SEC_MEMORY: {
168       auto MemorySec = make_unique<WasmYAML::MemorySection>();
169       for (const wasm::WasmLimits &Memory : Obj.memories()) {
170         MemorySec->Memories.push_back(make_limits(Memory));
171       }
172       S = std::move(MemorySec);
173       break;
174     }
175     case wasm::WASM_SEC_GLOBAL: {
176       auto GlobalSec = make_unique<WasmYAML::GlobalSection>();
177       for (auto &Global : Obj.globals()) {
178         WasmYAML::Global G;
179         G.Type = Global.Type;
180         G.Mutable = Global.Mutable;
181         G.InitExpr = Global.InitExpr;
182         GlobalSec->Globals.push_back(G);
183       }
184       S = std::move(GlobalSec);
185       break;
186     }
187     case wasm::WASM_SEC_START: {
188       auto StartSec = make_unique<WasmYAML::StartSection>();
189       StartSec->StartFunction = Obj.startFunction();
190       S = std::move(StartSec);
191       break;
192     }
193     case wasm::WASM_SEC_EXPORT: {
194       auto ExportSec = make_unique<WasmYAML::ExportSection>();
195       for (auto &Export : Obj.exports()) {
196         WasmYAML::Export Ex;
197         Ex.Name = Export.Name;
198         Ex.Kind = Export.Kind;
199         Ex.Index = Export.Index;
200         ExportSec->Exports.push_back(Ex);
201       }
202       S = std::move(ExportSec);
203       break;
204     }
205     case wasm::WASM_SEC_ELEM: {
206       auto ElemSec = make_unique<WasmYAML::ElemSection>();
207       for (auto &Segment : Obj.elements()) {
208         WasmYAML::ElemSegment Seg;
209         Seg.TableIndex = Segment.TableIndex;
210         Seg.Offset = Segment.Offset;
211         for (auto &Func : Segment.Functions) {
212           Seg.Functions.push_back(Func);
213         }
214         ElemSec->Segments.push_back(Seg);
215       }
216       S = std::move(ElemSec);
217       break;
218     }
219     case wasm::WASM_SEC_CODE: {
220       auto CodeSec = make_unique<WasmYAML::CodeSection>();
221       for (auto &Func : Obj.functions()) {
222         WasmYAML::Function Function;
223         for (auto &Local : Func.Locals) {
224           WasmYAML::LocalDecl LocalDecl;
225           LocalDecl.Type = Local.Type;
226           LocalDecl.Count = Local.Count;
227           Function.Locals.push_back(LocalDecl);
228         }
229         Function.Body = yaml::BinaryRef(Func.Body);
230         CodeSec->Functions.push_back(Function);
231       }
232       S = std::move(CodeSec);
233       break;
234     }
235     case wasm::WASM_SEC_DATA: {
236       auto DataSec = make_unique<WasmYAML::DataSection>();
237       for (auto &Segment : Obj.dataSegments()) {
238         WasmYAML::DataSegment Seg;
239         Seg.Index = Segment.Index;
240         Seg.Offset = Segment.Offset;
241         Seg.Content = yaml::BinaryRef(Segment.Content);
242         DataSec->Segments.push_back(Seg);
243       }
244       S = std::move(DataSec);
245       break;
246     }
247     default:
248       llvm_unreachable("Unknown section type");
249       break;
250     }
251     for (const wasm::WasmRelocation &Reloc: WasmSec.Relocations) {
252       WasmYAML::Relocation R;
253       R.Type = Reloc.Type;
254       R.Index = Reloc.Index;
255       R.Offset = Reloc.Offset;
256       R.Addend = Reloc.Addend;
257       S->Relocations.push_back(R);
258     }
259     Y->Sections.push_back(std::move(S));
260   }
261 
262   return Y.release();
263 }
264 
265 std::error_code wasm2yaml(raw_ostream &Out, const object::WasmObjectFile &Obj) {
266   WasmDumper Dumper(Obj);
267   ErrorOr<WasmYAML::Object *> YAMLOrErr = Dumper.dump();
268   if (std::error_code EC = YAMLOrErr.getError())
269     return EC;
270 
271   std::unique_ptr<WasmYAML::Object> YAML(YAMLOrErr.get());
272   yaml::Output Yout(Out);
273   Yout << *YAML;
274 
275   return std::error_code();
276 }
277