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 19 using namespace llvm; 20 using namespace object; 21 22 namespace { 23 24 static 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 32 static 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 43 static 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 58 class WasmDumper : public ObjDumper { 59 public: 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 69 protected: 70 void printSymbol(const SymbolRef &Sym); 71 void printRelocation(const SectionRef &Section, const RelocationRef &Reloc); 72 73 private: 74 void printSymbols() override; 75 void printDynamicSymbols() override { llvm_unreachable("unimplemented"); } 76 77 const WasmObjectFile *Obj; 78 }; 79 80 void WasmDumper::printFileHeaders() { 81 W.printHex("Version", Obj->getHeader().Version); 82 } 83 84 void 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 121 void 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 148 void WasmDumper::printSymbols() { 149 ListScope Group(W, "Symbols"); 150 151 for (const SymbolRef &Symbol : Obj->symbols()) 152 printSymbol(Symbol); 153 } 154 155 void 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 216 void 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 242 namespace llvm { 243 244 std::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