diff options
Diffstat (limited to 'llvm/tools/llvm-readobj/WasmDumper.cpp')
-rw-r--r-- | llvm/tools/llvm-readobj/WasmDumper.cpp | 256 |
1 files changed, 256 insertions, 0 deletions
diff --git a/llvm/tools/llvm-readobj/WasmDumper.cpp b/llvm/tools/llvm-readobj/WasmDumper.cpp new file mode 100644 index 000000000000..dfab9f40d71b --- /dev/null +++ b/llvm/tools/llvm-readobj/WasmDumper.cpp @@ -0,0 +1,256 @@ +//===-- WasmDumper.cpp - Wasm-specific object file dumper -----------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// +// +// This file implements the Wasm-specific dumper for llvm-readobj. +// +//===----------------------------------------------------------------------===// + +#include "Error.h" +#include "ObjDumper.h" +#include "llvm-readobj.h" +#include "llvm/Object/Wasm.h" +#include "llvm/Support/ScopedPrinter.h" + +using namespace llvm; +using namespace object; + +namespace { + +static const EnumEntry<unsigned> WasmSymbolTypes[] = { +#define ENUM_ENTRY(X) \ + { #X, wasm::WASM_SYMBOL_TYPE_##X } + ENUM_ENTRY(FUNCTION), ENUM_ENTRY(DATA), ENUM_ENTRY(GLOBAL), + ENUM_ENTRY(SECTION), ENUM_ENTRY(EVENT), +#undef ENUM_ENTRY +}; + +static const EnumEntry<uint32_t> WasmSectionTypes[] = { +#define ENUM_ENTRY(X) \ + { #X, wasm::WASM_SEC_##X } + ENUM_ENTRY(CUSTOM), ENUM_ENTRY(TYPE), ENUM_ENTRY(IMPORT), + ENUM_ENTRY(FUNCTION), ENUM_ENTRY(TABLE), ENUM_ENTRY(MEMORY), + ENUM_ENTRY(GLOBAL), ENUM_ENTRY(EVENT), ENUM_ENTRY(EXPORT), + ENUM_ENTRY(START), ENUM_ENTRY(ELEM), ENUM_ENTRY(CODE), + ENUM_ENTRY(DATA), ENUM_ENTRY(DATACOUNT), +#undef ENUM_ENTRY +}; + +static const EnumEntry<unsigned> WasmSymbolFlags[] = { +#define ENUM_ENTRY(X) \ + { #X, wasm::WASM_SYMBOL_##X } + ENUM_ENTRY(BINDING_GLOBAL), + ENUM_ENTRY(BINDING_WEAK), + ENUM_ENTRY(BINDING_LOCAL), + ENUM_ENTRY(VISIBILITY_DEFAULT), + ENUM_ENTRY(VISIBILITY_HIDDEN), + ENUM_ENTRY(UNDEFINED), + ENUM_ENTRY(EXPORTED), + ENUM_ENTRY(EXPLICIT_NAME), + ENUM_ENTRY(NO_STRIP), +#undef ENUM_ENTRY +}; + +class WasmDumper : public ObjDumper { +public: + WasmDumper(const WasmObjectFile *Obj, ScopedPrinter &Writer) + : ObjDumper(Writer), Obj(Obj) {} + + void printFileHeaders() override; + void printSectionHeaders() override; + void printRelocations() override; + void printUnwindInfo() override { llvm_unreachable("unimplemented"); } + void printStackMap() const override { llvm_unreachable("unimplemented"); } + +protected: + void printSymbol(const SymbolRef &Sym); + void printRelocation(const SectionRef &Section, const RelocationRef &Reloc); + +private: + void printSymbols() override; + void printDynamicSymbols() override { llvm_unreachable("unimplemented"); } + + const WasmObjectFile *Obj; +}; + +void WasmDumper::printFileHeaders() { + W.printHex("Version", Obj->getHeader().Version); +} + +void WasmDumper::printRelocation(const SectionRef &Section, + const RelocationRef &Reloc) { + SmallString<64> RelocTypeName; + uint64_t RelocType = Reloc.getType(); + Reloc.getTypeName(RelocTypeName); + const wasm::WasmRelocation &WasmReloc = Obj->getWasmRelocation(Reloc); + + StringRef SymName; + symbol_iterator SI = Reloc.getSymbol(); + if (SI != Obj->symbol_end()) + SymName = unwrapOrError(Obj->getFileName(), SI->getName()); + + bool HasAddend = false; + switch (RelocType) { + case wasm::R_WASM_MEMORY_ADDR_LEB: + case wasm::R_WASM_MEMORY_ADDR_SLEB: + case wasm::R_WASM_MEMORY_ADDR_I32: + case wasm::R_WASM_FUNCTION_OFFSET_I32: + case wasm::R_WASM_SECTION_OFFSET_I32: + HasAddend = true; + break; + default: + break; + } + if (opts::ExpandRelocs) { + DictScope Group(W, "Relocation"); + W.printNumber("Type", RelocTypeName, RelocType); + W.printHex("Offset", Reloc.getOffset()); + if (!SymName.empty()) + W.printString("Symbol", SymName); + else + W.printHex("Index", WasmReloc.Index); + if (HasAddend) + W.printNumber("Addend", WasmReloc.Addend); + } else { + raw_ostream &OS = W.startLine(); + OS << W.hex(Reloc.getOffset()) << " " << RelocTypeName << " "; + if (!SymName.empty()) + OS << SymName; + else + OS << WasmReloc.Index; + if (HasAddend) + OS << " " << WasmReloc.Addend; + OS << "\n"; + } +} + +void WasmDumper::printRelocations() { + ListScope D(W, "Relocations"); + + int SectionNumber = 0; + for (const SectionRef &Section : Obj->sections()) { + bool PrintedGroup = false; + StringRef Name = unwrapOrError(Obj->getFileName(), Section.getName()); + + ++SectionNumber; + + for (const RelocationRef &Reloc : Section.relocations()) { + if (!PrintedGroup) { + W.startLine() << "Section (" << SectionNumber << ") " << Name << " {\n"; + W.indent(); + PrintedGroup = true; + } + + printRelocation(Section, Reloc); + } + + if (PrintedGroup) { + W.unindent(); + W.startLine() << "}\n"; + } + } +} + +void WasmDumper::printSymbols() { + ListScope Group(W, "Symbols"); + + for (const SymbolRef &Symbol : Obj->symbols()) + printSymbol(Symbol); +} + +void WasmDumper::printSectionHeaders() { + ListScope Group(W, "Sections"); + for (const SectionRef &Section : Obj->sections()) { + const WasmSection &WasmSec = Obj->getWasmSection(Section); + DictScope SectionD(W, "Section"); + W.printEnum("Type", WasmSec.Type, makeArrayRef(WasmSectionTypes)); + W.printNumber("Size", static_cast<uint64_t>(WasmSec.Content.size())); + W.printNumber("Offset", WasmSec.Offset); + switch (WasmSec.Type) { + case wasm::WASM_SEC_CUSTOM: + W.printString("Name", WasmSec.Name); + if (WasmSec.Name == "linking") { + const wasm::WasmLinkingData &LinkingData = Obj->linkingData(); + if (!LinkingData.InitFunctions.empty()) { + ListScope Group(W, "InitFunctions"); + for (const wasm::WasmInitFunc &F : LinkingData.InitFunctions) + W.startLine() << F.Symbol << " (priority=" << F.Priority << ")\n"; + } + } + break; + case wasm::WASM_SEC_DATA: { + ListScope Group(W, "Segments"); + for (const WasmSegment &Segment : Obj->dataSegments()) { + const wasm::WasmDataSegment &Seg = Segment.Data; + DictScope Group(W, "Segment"); + if (!Seg.Name.empty()) + W.printString("Name", Seg.Name); + W.printNumber("Size", static_cast<uint64_t>(Seg.Content.size())); + if (Seg.Offset.Opcode == wasm::WASM_OPCODE_I32_CONST) + W.printNumber("Offset", Seg.Offset.Value.Int32); + } + break; + } + case wasm::WASM_SEC_MEMORY: + ListScope Group(W, "Memories"); + for (const wasm::WasmLimits &Memory : Obj->memories()) { + DictScope Group(W, "Memory"); + W.printNumber("InitialPages", Memory.Initial); + if (Memory.Flags & wasm::WASM_LIMITS_FLAG_HAS_MAX) { + W.printNumber("MaxPages", WasmSec.Offset); + } + } + break; + } + + if (opts::SectionRelocations) { + ListScope D(W, "Relocations"); + for (const RelocationRef &Reloc : Section.relocations()) + printRelocation(Section, Reloc); + } + + if (opts::SectionData) { + W.printBinaryBlock("SectionData", WasmSec.Content); + } + } +} + +void WasmDumper::printSymbol(const SymbolRef &Sym) { + DictScope D(W, "Symbol"); + WasmSymbol Symbol = Obj->getWasmSymbol(Sym.getRawDataRefImpl()); + W.printString("Name", Symbol.Info.Name); + W.printEnum("Type", Symbol.Info.Kind, makeArrayRef(WasmSymbolTypes)); + W.printFlags("Flags", Symbol.Info.Flags, makeArrayRef(WasmSymbolFlags)); + + if (Symbol.Info.Flags & wasm::WASM_SYMBOL_UNDEFINED) { + W.printString("ImportName", Symbol.Info.ImportName); + W.printString("ImportModule", Symbol.Info.ImportModule); + } + if (Symbol.Info.Kind != wasm::WASM_SYMBOL_TYPE_DATA) { + W.printHex("ElementIndex", Symbol.Info.ElementIndex); + } else if (!(Symbol.Info.Flags & wasm::WASM_SYMBOL_UNDEFINED)) { + W.printHex("Offset", Symbol.Info.DataRef.Offset); + W.printHex("Segment", Symbol.Info.DataRef.Segment); + W.printHex("Size", Symbol.Info.DataRef.Size); + } +} + +} // namespace + +namespace llvm { + +std::error_code createWasmDumper(const object::ObjectFile *Obj, + ScopedPrinter &Writer, + std::unique_ptr<ObjDumper> &Result) { + const auto *WasmObj = dyn_cast<WasmObjectFile>(Obj); + assert(WasmObj && "createWasmDumper called with non-wasm object"); + + Result.reset(new WasmDumper(WasmObj, Writer)); + return readobj_error::success; +} + +} // namespace llvm |