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