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