1//===-- WasmDumper.cpp - Wasm-specific object file dumper -----------------===// 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// This file implements the Wasm-specific dumper for llvm-readobj. 10// 11//===----------------------------------------------------------------------===// 12 13#include "Error.h" 14#include "ObjDumper.h" 15#include "llvm-readobj.h" 16#include "llvm/Object/Wasm.h" 17#include "llvm/Support/ScopedPrinter.h" 18 19using namespace llvm; 20using namespace object; 21 22namespace { 23 24static const EnumEntry<unsigned> WasmSymbolTypes[] = { 25#define ENUM_ENTRY(X) \ 26 { #X, wasm::WASM_SYMBOL_TYPE_##X } 27 ENUM_ENTRY(FUNCTION), ENUM_ENTRY(DATA), ENUM_ENTRY(GLOBAL), 28 ENUM_ENTRY(SECTION), ENUM_ENTRY(EVENT), 29#undef ENUM_ENTRY 30}; 31 32static const EnumEntry<uint32_t> WasmSectionTypes[] = { 33#define ENUM_ENTRY(X) \ 34 { #X, wasm::WASM_SEC_##X } 35 ENUM_ENTRY(CUSTOM), ENUM_ENTRY(TYPE), ENUM_ENTRY(IMPORT), 36 ENUM_ENTRY(FUNCTION), ENUM_ENTRY(TABLE), ENUM_ENTRY(MEMORY), 37 ENUM_ENTRY(GLOBAL), ENUM_ENTRY(EVENT), ENUM_ENTRY(EXPORT), 38 ENUM_ENTRY(START), ENUM_ENTRY(ELEM), ENUM_ENTRY(CODE), 39 ENUM_ENTRY(DATA), ENUM_ENTRY(DATACOUNT), 40#undef ENUM_ENTRY 41}; 42 43static const EnumEntry<unsigned> WasmSymbolFlags[] = { 44#define ENUM_ENTRY(X) \ 45 { #X, wasm::WASM_SYMBOL_##X } 46 ENUM_ENTRY(BINDING_GLOBAL), 47 ENUM_ENTRY(BINDING_WEAK), 48 ENUM_ENTRY(BINDING_LOCAL), 49 ENUM_ENTRY(VISIBILITY_DEFAULT), 50 ENUM_ENTRY(VISIBILITY_HIDDEN), 51 ENUM_ENTRY(UNDEFINED), 52 ENUM_ENTRY(EXPORTED), 53 ENUM_ENTRY(EXPLICIT_NAME), 54 ENUM_ENTRY(NO_STRIP), 55#undef ENUM_ENTRY 56}; 57 58class WasmDumper : public ObjDumper { 59public: 60 WasmDumper(const WasmObjectFile *Obj, ScopedPrinter &Writer) 61 : ObjDumper(Writer), Obj(Obj) {} 62 63 void printFileHeaders() override; 64 void printSectionHeaders() override; 65 void printRelocations() override; 66 void printUnwindInfo() override { llvm_unreachable("unimplemented"); } 67 void printStackMap() const override { llvm_unreachable("unimplemented"); } 68 69protected: 70 void printSymbol(const SymbolRef &Sym); 71 void printRelocation(const SectionRef &Section, const RelocationRef &Reloc); 72 73private: 74 void printSymbols() override; 75 void printDynamicSymbols() override { llvm_unreachable("unimplemented"); } 76 77 const WasmObjectFile *Obj; 78}; 79 80void WasmDumper::printFileHeaders() { 81 W.printHex("Version", Obj->getHeader().Version); 82} 83 84void WasmDumper::printRelocation(const SectionRef &Section, 85 const RelocationRef &Reloc) { 86 SmallString<64> RelocTypeName; 87 uint64_t RelocType = Reloc.getType(); 88 Reloc.getTypeName(RelocTypeName); 89 const wasm::WasmRelocation &WasmReloc = Obj->getWasmRelocation(Reloc); 90 91 StringRef SymName; 92 symbol_iterator SI = Reloc.getSymbol(); 93 if (SI != Obj->symbol_end()) 94 SymName = unwrapOrError(Obj->getFileName(), SI->getName()); 95 96 bool HasAddend = wasm::relocTypeHasAddend(static_cast<uint32_t>(RelocType)); 97 98 if (opts::ExpandRelocs) { 99 DictScope Group(W, "Relocation"); 100 W.printNumber("Type", RelocTypeName, RelocType); 101 W.printHex("Offset", Reloc.getOffset()); 102 if (!SymName.empty()) 103 W.printString("Symbol", SymName); 104 else 105 W.printHex("Index", WasmReloc.Index); 106 if (HasAddend) 107 W.printNumber("Addend", WasmReloc.Addend); 108 } else { 109 raw_ostream &OS = W.startLine(); 110 OS << W.hex(Reloc.getOffset()) << " " << RelocTypeName << " "; 111 if (!SymName.empty()) 112 OS << SymName; 113 else 114 OS << WasmReloc.Index; 115 if (HasAddend) 116 OS << " " << WasmReloc.Addend; 117 OS << "\n"; 118 } 119} 120 121void WasmDumper::printRelocations() { 122 ListScope D(W, "Relocations"); 123 124 int SectionNumber = 0; 125 for (const SectionRef &Section : Obj->sections()) { 126 bool PrintedGroup = false; 127 StringRef Name = unwrapOrError(Obj->getFileName(), Section.getName()); 128 129 ++SectionNumber; 130 131 for (const RelocationRef &Reloc : Section.relocations()) { 132 if (!PrintedGroup) { 133 W.startLine() << "Section (" << SectionNumber << ") " << Name << " {\n"; 134 W.indent(); 135 PrintedGroup = true; 136 } 137 138 printRelocation(Section, Reloc); 139 } 140 141 if (PrintedGroup) { 142 W.unindent(); 143 W.startLine() << "}\n"; 144 } 145 } 146} 147 148void WasmDumper::printSymbols() { 149 ListScope Group(W, "Symbols"); 150 151 for (const SymbolRef &Symbol : Obj->symbols()) 152 printSymbol(Symbol); 153} 154 155void WasmDumper::printSectionHeaders() { 156 ListScope Group(W, "Sections"); 157 for (const SectionRef &Section : Obj->sections()) { 158 const WasmSection &WasmSec = Obj->getWasmSection(Section); 159 DictScope SectionD(W, "Section"); 160 W.printEnum("Type", WasmSec.Type, makeArrayRef(WasmSectionTypes)); 161 W.printNumber("Size", static_cast<uint64_t>(WasmSec.Content.size())); 162 W.printNumber("Offset", WasmSec.Offset); 163 switch (WasmSec.Type) { 164 case wasm::WASM_SEC_CUSTOM: 165 W.printString("Name", WasmSec.Name); 166 if (WasmSec.Name == "linking") { 167 const wasm::WasmLinkingData &LinkingData = Obj->linkingData(); 168 if (!LinkingData.InitFunctions.empty()) { 169 ListScope Group(W, "InitFunctions"); 170 for (const wasm::WasmInitFunc &F : LinkingData.InitFunctions) 171 W.startLine() << F.Symbol << " (priority=" << F.Priority << ")\n"; 172 } 173 } 174 break; 175 case wasm::WASM_SEC_DATA: { 176 ListScope Group(W, "Segments"); 177 for (const WasmSegment &Segment : Obj->dataSegments()) { 178 const wasm::WasmDataSegment &Seg = Segment.Data; 179 DictScope Group(W, "Segment"); 180 if (!Seg.Name.empty()) 181 W.printString("Name", Seg.Name); 182 W.printNumber("Size", static_cast<uint64_t>(Seg.Content.size())); 183 if (Seg.Offset.Opcode == wasm::WASM_OPCODE_I32_CONST) 184 W.printNumber("Offset", Seg.Offset.Value.Int32); 185 else if (Seg.Offset.Opcode == wasm::WASM_OPCODE_I64_CONST) 186 W.printNumber("Offset", Seg.Offset.Value.Int64); 187 else 188 llvm_unreachable("unknown init expr opcode"); 189 } 190 break; 191 } 192 case wasm::WASM_SEC_MEMORY: 193 ListScope Group(W, "Memories"); 194 for (const wasm::WasmLimits &Memory : Obj->memories()) { 195 DictScope Group(W, "Memory"); 196 W.printNumber("InitialPages", Memory.Initial); 197 if (Memory.Flags & wasm::WASM_LIMITS_FLAG_HAS_MAX) { 198 W.printNumber("MaxPages", WasmSec.Offset); 199 } 200 } 201 break; 202 } 203 204 if (opts::SectionRelocations) { 205 ListScope D(W, "Relocations"); 206 for (const RelocationRef &Reloc : Section.relocations()) 207 printRelocation(Section, Reloc); 208 } 209 210 if (opts::SectionData) { 211 W.printBinaryBlock("SectionData", WasmSec.Content); 212 } 213 } 214} 215 216void WasmDumper::printSymbol(const SymbolRef &Sym) { 217 DictScope D(W, "Symbol"); 218 WasmSymbol Symbol = Obj->getWasmSymbol(Sym.getRawDataRefImpl()); 219 W.printString("Name", Symbol.Info.Name); 220 W.printEnum("Type", Symbol.Info.Kind, makeArrayRef(WasmSymbolTypes)); 221 W.printFlags("Flags", Symbol.Info.Flags, makeArrayRef(WasmSymbolFlags)); 222 223 if (Symbol.Info.Flags & wasm::WASM_SYMBOL_UNDEFINED) { 224 if (Symbol.Info.ImportName) { 225 W.printString("ImportName", *Symbol.Info.ImportName); 226 } 227 if (Symbol.Info.ImportModule) { 228 W.printString("ImportModule", *Symbol.Info.ImportModule); 229 } 230 } 231 if (Symbol.Info.Kind != wasm::WASM_SYMBOL_TYPE_DATA) { 232 W.printHex("ElementIndex", Symbol.Info.ElementIndex); 233 } else if (!(Symbol.Info.Flags & wasm::WASM_SYMBOL_UNDEFINED)) { 234 W.printHex("Offset", Symbol.Info.DataRef.Offset); 235 W.printHex("Segment", Symbol.Info.DataRef.Segment); 236 W.printHex("Size", Symbol.Info.DataRef.Size); 237 } 238} 239 240} // namespace 241 242namespace llvm { 243 244std::error_code createWasmDumper(const object::ObjectFile *Obj, 245 ScopedPrinter &Writer, 246 std::unique_ptr<ObjDumper> &Result) { 247 const auto *WasmObj = dyn_cast<WasmObjectFile>(Obj); 248 assert(WasmObj && "createWasmDumper called with non-wasm object"); 249 250 Result.reset(new WasmDumper(WasmObj, Writer)); 251 return readobj_error::success; 252} 253 254} // namespace llvm 255