436 lines · cpp
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-exception6//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/LEB128.h"14#include "llvm/Support/YAMLTraits.h"15 16using namespace llvm;17using object::WasmSection;18 19namespace {20 21class WasmDumper {22 const object::WasmObjectFile &Obj;23 24public: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} // namespace34 35static WasmYAML::Limits makeLimits(const wasm::WasmLimits &Limits) {36 WasmYAML::Limits L;37 L.Flags = Limits.Flags;38 L.Minimum = Limits.Minimum;39 L.Maximum = Limits.Maximum;40 L.PageSize = Limits.PageSize;41 return L;42}43 44static WasmYAML::Table makeTable(uint32_t Index,45 const wasm::WasmTableType &Type) {46 WasmYAML::Table T;47 T.Index = Index;48 T.ElemType = (uint32_t)Type.ElemType;49 T.TableLimits = makeLimits(Type.Limits);50 return T;51}52 53std::unique_ptr<WasmYAML::CustomSection>54WasmDumper::dumpCustomSection(const WasmSection &WasmSec) {55 std::unique_ptr<WasmYAML::CustomSection> CustomSec;56 if (WasmSec.Name == "dylink" || WasmSec.Name == "dylink.0") {57 std::unique_ptr<WasmYAML::DylinkSection> DylinkSec =58 std::make_unique<WasmYAML::DylinkSection>();59 const wasm::WasmDylinkInfo& Info = Obj.dylinkInfo();60 DylinkSec->MemorySize = Info.MemorySize;61 DylinkSec->MemoryAlignment = Info.MemoryAlignment;62 DylinkSec->TableSize = Info.TableSize;63 DylinkSec->TableAlignment = Info.TableAlignment;64 DylinkSec->Needed = Info.Needed;65 DylinkSec->RuntimePath = Info.RuntimePath;66 for (const auto &Imp : Info.ImportInfo)67 DylinkSec->ImportInfo.push_back({Imp.Module, Imp.Field, Imp.Flags});68 for (const auto &Exp : Info.ExportInfo)69 DylinkSec->ExportInfo.push_back({Exp.Name, Exp.Flags});70 CustomSec = std::move(DylinkSec);71 } else if (WasmSec.Name == "name") {72 std::unique_ptr<WasmYAML::NameSection> NameSec =73 std::make_unique<WasmYAML::NameSection>();74 for (const llvm::wasm::WasmDebugName &Name : Obj.debugNames()) {75 WasmYAML::NameEntry NameEntry;76 NameEntry.Name = Name.Name;77 NameEntry.Index = Name.Index;78 if (Name.Type == llvm::wasm::NameType::FUNCTION) {79 NameSec->FunctionNames.push_back(NameEntry);80 } else if (Name.Type == llvm::wasm::NameType::GLOBAL) {81 NameSec->GlobalNames.push_back(NameEntry);82 } else {83 assert(Name.Type == llvm::wasm::NameType::DATA_SEGMENT);84 NameSec->DataSegmentNames.push_back(NameEntry);85 }86 }87 CustomSec = std::move(NameSec);88 } else if (WasmSec.Name == "linking") {89 std::unique_ptr<WasmYAML::LinkingSection> LinkingSec =90 std::make_unique<WasmYAML::LinkingSection>();91 LinkingSec->Version = Obj.linkingData().Version;92 93 ArrayRef<StringRef> Comdats = Obj.linkingData().Comdats;94 for (StringRef ComdatName : Comdats)95 LinkingSec->Comdats.emplace_back(WasmYAML::Comdat{ComdatName, {}});96 for (auto &Func : Obj.functions()) {97 if (Func.Comdat != UINT32_MAX) {98 LinkingSec->Comdats[Func.Comdat].Entries.emplace_back(99 WasmYAML::ComdatEntry{wasm::WASM_COMDAT_FUNCTION, Func.Index});100 }101 }102 103 uint32_t SegmentIndex = 0;104 for (const object::WasmSegment &Segment : Obj.dataSegments()) {105 if (!Segment.Data.Name.empty()) {106 WasmYAML::SegmentInfo SegmentInfo;107 SegmentInfo.Name = Segment.Data.Name;108 SegmentInfo.Index = SegmentIndex;109 SegmentInfo.Alignment = Segment.Data.Alignment;110 SegmentInfo.Flags = Segment.Data.LinkingFlags;111 LinkingSec->SegmentInfos.push_back(SegmentInfo);112 }113 if (Segment.Data.Comdat != UINT32_MAX) {114 LinkingSec->Comdats[Segment.Data.Comdat].Entries.emplace_back(115 WasmYAML::ComdatEntry{wasm::WASM_COMDAT_DATA, SegmentIndex});116 }117 SegmentIndex++;118 }119 uint32_t SectionIndex = 0;120 for (const auto &Sec : Obj.sections()) {121 const WasmSection &WasmSec = Obj.getWasmSection(Sec);122 if (WasmSec.Comdat != UINT32_MAX)123 LinkingSec->Comdats[WasmSec.Comdat].Entries.emplace_back(124 WasmYAML::ComdatEntry{wasm::WASM_COMDAT_SECTION, SectionIndex});125 SectionIndex++;126 }127 128 uint32_t SymbolIndex = 0;129 for (const object::SymbolRef &Sym : Obj.symbols()) {130 const wasm::WasmSymbolInfo &Symbol = Obj.getWasmSymbol(Sym).Info;131 WasmYAML::SymbolInfo Info;132 Info.Index = SymbolIndex++;133 Info.Kind = static_cast<uint32_t>(Symbol.Kind);134 Info.Name = Symbol.Name;135 Info.Flags = Symbol.Flags;136 switch (Symbol.Kind) {137 case wasm::WASM_SYMBOL_TYPE_DATA:138 Info.DataRef = Symbol.DataRef;139 break;140 case wasm::WASM_SYMBOL_TYPE_FUNCTION:141 case wasm::WASM_SYMBOL_TYPE_GLOBAL:142 case wasm::WASM_SYMBOL_TYPE_TABLE:143 case wasm::WASM_SYMBOL_TYPE_TAG:144 Info.ElementIndex = Symbol.ElementIndex;145 break;146 case wasm::WASM_SYMBOL_TYPE_SECTION:147 Info.ElementIndex = Symbol.ElementIndex;148 break;149 }150 LinkingSec->SymbolTable.emplace_back(Info);151 }152 153 for (const wasm::WasmInitFunc &Func : Obj.linkingData().InitFunctions) {154 WasmYAML::InitFunction F{Func.Priority, Func.Symbol};155 LinkingSec->InitFunctions.emplace_back(F);156 }157 158 CustomSec = std::move(LinkingSec);159 } else if (WasmSec.Name == "producers") {160 std::unique_ptr<WasmYAML::ProducersSection> ProducersSec =161 std::make_unique<WasmYAML::ProducersSection>();162 const llvm::wasm::WasmProducerInfo &Info = Obj.getProducerInfo();163 for (auto &E : Info.Languages) {164 WasmYAML::ProducerEntry Producer;165 Producer.Name = E.first;166 Producer.Version = E.second;167 ProducersSec->Languages.push_back(Producer);168 }169 for (auto &E : Info.Tools) {170 WasmYAML::ProducerEntry Producer;171 Producer.Name = E.first;172 Producer.Version = E.second;173 ProducersSec->Tools.push_back(Producer);174 }175 for (auto &E : Info.SDKs) {176 WasmYAML::ProducerEntry Producer;177 Producer.Name = E.first;178 Producer.Version = E.second;179 ProducersSec->SDKs.push_back(Producer);180 }181 CustomSec = std::move(ProducersSec);182 } else if (WasmSec.Name == "target_features") {183 std::unique_ptr<WasmYAML::TargetFeaturesSection> TargetFeaturesSec =184 std::make_unique<WasmYAML::TargetFeaturesSection>();185 for (auto &E : Obj.getTargetFeatures()) {186 WasmYAML::FeatureEntry Feature;187 Feature.Prefix = E.Prefix;188 Feature.Name = E.Name;189 TargetFeaturesSec->Features.push_back(Feature);190 }191 CustomSec = std::move(TargetFeaturesSec);192 } else {193 CustomSec = std::make_unique<WasmYAML::CustomSection>(WasmSec.Name);194 }195 CustomSec->Payload = yaml::BinaryRef(WasmSec.Content);196 return CustomSec;197}198 199ErrorOr<WasmYAML::Object *> WasmDumper::dump() {200 auto Y = std::make_unique<WasmYAML::Object>();201 202 // Dump header203 Y->Header.Version = Obj.getHeader().Version;204 205 // Dump sections206 for (const auto &Sec : Obj.sections()) {207 const WasmSection &WasmSec = Obj.getWasmSection(Sec);208 std::unique_ptr<WasmYAML::Section> S;209 switch (WasmSec.Type) {210 case wasm::WASM_SEC_CUSTOM: {211 if (WasmSec.Name.starts_with("reloc.")) {212 // Relocations are attached the sections they apply to rather than213 // being represented as a custom section in the YAML output.214 continue;215 }216 S = dumpCustomSection(WasmSec);217 break;218 }219 case wasm::WASM_SEC_TYPE: {220 auto TypeSec = std::make_unique<WasmYAML::TypeSection>();221 uint32_t Index = 0;222 for (const auto &FunctionSig : Obj.types()) {223 WasmYAML::Signature Sig;224 Sig.Index = Index++;225 for (const auto &ParamType : FunctionSig.Params)226 Sig.ParamTypes.emplace_back(static_cast<uint32_t>(ParamType));227 for (const auto &ReturnType : FunctionSig.Returns)228 Sig.ReturnTypes.emplace_back(static_cast<uint32_t>(ReturnType));229 TypeSec->Signatures.push_back(Sig);230 }231 S = std::move(TypeSec);232 break;233 }234 case wasm::WASM_SEC_IMPORT: {235 auto ImportSec = std::make_unique<WasmYAML::ImportSection>();236 for (auto &Import : Obj.imports()) {237 WasmYAML::Import Im;238 Im.Module = Import.Module;239 Im.Field = Import.Field;240 Im.Kind = Import.Kind;241 switch (Im.Kind) {242 case wasm::WASM_EXTERNAL_FUNCTION:243 Im.SigIndex = Import.SigIndex;244 break;245 case wasm::WASM_EXTERNAL_GLOBAL:246 Im.GlobalImport.Type = Import.Global.Type;247 Im.GlobalImport.Mutable = Import.Global.Mutable;248 break;249 case wasm::WASM_EXTERNAL_TAG:250 Im.SigIndex = Import.SigIndex;251 break;252 case wasm::WASM_EXTERNAL_TABLE:253 // FIXME: Currently we always output an index of 0 for any imported254 // table.255 Im.TableImport = makeTable(0, Import.Table);256 break;257 case wasm::WASM_EXTERNAL_MEMORY:258 Im.Memory = makeLimits(Import.Memory);259 break;260 }261 ImportSec->Imports.push_back(Im);262 }263 S = std::move(ImportSec);264 break;265 }266 case wasm::WASM_SEC_FUNCTION: {267 auto FuncSec = std::make_unique<WasmYAML::FunctionSection>();268 for (const auto &Func : Obj.functions()) {269 FuncSec->FunctionTypes.push_back(Func.SigIndex);270 }271 S = std::move(FuncSec);272 break;273 }274 case wasm::WASM_SEC_TABLE: {275 auto TableSec = std::make_unique<WasmYAML::TableSection>();276 for (const wasm::WasmTable &Table : Obj.tables()) {277 TableSec->Tables.push_back(makeTable(Table.Index, Table.Type));278 }279 S = std::move(TableSec);280 break;281 }282 case wasm::WASM_SEC_MEMORY: {283 auto MemorySec = std::make_unique<WasmYAML::MemorySection>();284 for (const wasm::WasmLimits &Memory : Obj.memories()) {285 MemorySec->Memories.push_back(makeLimits(Memory));286 }287 S = std::move(MemorySec);288 break;289 }290 case wasm::WASM_SEC_TAG: {291 auto TagSec = std::make_unique<WasmYAML::TagSection>();292 for (auto &Tag : Obj.tags()) {293 TagSec->TagTypes.push_back(Tag.SigIndex);294 }295 S = std::move(TagSec);296 break;297 }298 case wasm::WASM_SEC_GLOBAL: {299 auto GlobalSec = std::make_unique<WasmYAML::GlobalSection>();300 for (auto &Global : Obj.globals()) {301 WasmYAML::Global G;302 G.Index = Global.Index;303 G.Type = Global.Type.Type;304 G.Mutable = Global.Type.Mutable;305 G.Init.Extended = Global.InitExpr.Extended;306 if (Global.InitExpr.Extended) {307 G.Init.Body = Global.InitExpr.Body;308 } else {309 G.Init.Inst = Global.InitExpr.Inst;310 }311 GlobalSec->Globals.push_back(G);312 }313 S = std::move(GlobalSec);314 break;315 }316 case wasm::WASM_SEC_START: {317 auto StartSec = std::make_unique<WasmYAML::StartSection>();318 StartSec->StartFunction = Obj.startFunction();319 S = std::move(StartSec);320 break;321 }322 case wasm::WASM_SEC_EXPORT: {323 auto ExportSec = std::make_unique<WasmYAML::ExportSection>();324 for (auto &Export : Obj.exports()) {325 WasmYAML::Export Ex;326 Ex.Name = Export.Name;327 Ex.Kind = Export.Kind;328 Ex.Index = Export.Index;329 ExportSec->Exports.push_back(Ex);330 }331 S = std::move(ExportSec);332 break;333 }334 case wasm::WASM_SEC_ELEM: {335 auto ElemSec = std::make_unique<WasmYAML::ElemSection>();336 for (auto &Segment : Obj.elements()) {337 WasmYAML::ElemSegment Seg;338 Seg.Flags = Segment.Flags;339 Seg.TableNumber = Segment.TableNumber;340 Seg.ElemKind = (uint32_t)Segment.ElemKind;341 Seg.Offset.Extended = Segment.Offset.Extended;342 if (Seg.Offset.Extended) {343 Seg.Offset.Body = yaml::BinaryRef(Segment.Offset.Body);344 } else {345 Seg.Offset.Inst = Segment.Offset.Inst;346 }347 append_range(Seg.Functions, Segment.Functions);348 ElemSec->Segments.push_back(Seg);349 }350 S = std::move(ElemSec);351 break;352 }353 case wasm::WASM_SEC_CODE: {354 auto CodeSec = std::make_unique<WasmYAML::CodeSection>();355 for (auto &Func : Obj.functions()) {356 WasmYAML::Function Function;357 Function.Index = Func.Index;358 for (auto &Local : Func.Locals) {359 WasmYAML::LocalDecl LocalDecl;360 LocalDecl.Type = Local.Type;361 LocalDecl.Count = Local.Count;362 Function.Locals.push_back(LocalDecl);363 }364 Function.Body = yaml::BinaryRef(Func.Body);365 CodeSec->Functions.push_back(Function);366 }367 S = std::move(CodeSec);368 break;369 }370 case wasm::WASM_SEC_DATA: {371 auto DataSec = std::make_unique<WasmYAML::DataSection>();372 for (const object::WasmSegment &Segment : Obj.dataSegments()) {373 WasmYAML::DataSegment Seg;374 Seg.SectionOffset = Segment.SectionOffset;375 Seg.InitFlags = Segment.Data.InitFlags;376 Seg.MemoryIndex = Segment.Data.MemoryIndex;377 Seg.Offset.Extended = Segment.Data.Offset.Extended;378 if (Seg.Offset.Extended) {379 Seg.Offset.Body = yaml::BinaryRef(Segment.Data.Offset.Body);380 } else {381 Seg.Offset.Inst = Segment.Data.Offset.Inst;382 }383 Seg.Content = yaml::BinaryRef(Segment.Data.Content);384 DataSec->Segments.push_back(Seg);385 }386 S = std::move(DataSec);387 break;388 }389 case wasm::WASM_SEC_DATACOUNT: {390 auto DataCountSec = std::make_unique<WasmYAML::DataCountSection>();391 DataCountSec->Count = Obj.dataSegments().size();392 S = std::move(DataCountSec);393 break;394 }395 default:396 llvm_unreachable("Unknown section type");397 break;398 }399 400 // Only propagate the section size encoding length if it's not the minimal401 // size or 5 (the default "padded" value). This is to avoid having every402 // YAML output polluted with this value when we usually don't care about it403 // (and avoid rewriting all the test expectations).404 if (WasmSec.HeaderSecSizeEncodingLen &&405 WasmSec.HeaderSecSizeEncodingLen !=406 getULEB128Size(WasmSec.Content.size()) &&407 WasmSec.HeaderSecSizeEncodingLen != 5)408 S->HeaderSecSizeEncodingLen = WasmSec.HeaderSecSizeEncodingLen;409 410 for (const wasm::WasmRelocation &Reloc : WasmSec.Relocations) {411 WasmYAML::Relocation R;412 R.Type = Reloc.Type;413 R.Index = Reloc.Index;414 R.Offset = Reloc.Offset;415 R.Addend = Reloc.Addend;416 S->Relocations.push_back(R);417 }418 Y->Sections.push_back(std::move(S));419 }420 421 return Y.release();422}423 424std::error_code wasm2yaml(raw_ostream &Out, const object::WasmObjectFile &Obj) {425 WasmDumper Dumper(Obj);426 ErrorOr<WasmYAML::Object *> YAMLOrErr = Dumper.dump();427 if (std::error_code EC = YAMLOrErr.getError())428 return EC;429 430 std::unique_ptr<WasmYAML::Object> YAML(YAMLOrErr.get());431 yaml::Output Yout(Out);432 Yout << *YAML;433 434 return std::error_code();435}436