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) { #X, static_cast<unsigned>(WasmSymbol::SymbolType::X) } 27 ENUM_ENTRY(FUNCTION_IMPORT), 28 ENUM_ENTRY(FUNCTION_EXPORT), 29 ENUM_ENTRY(GLOBAL_IMPORT), 30 ENUM_ENTRY(GLOBAL_EXPORT), 31 ENUM_ENTRY(DEBUG_FUNCTION_NAME), 32 #undef ENUM_ENTRY 33 }; 34 35 static const EnumEntry<uint32_t> WasmSectionTypes[] = { 36 #define ENUM_ENTRY(X) { #X, wasm::WASM_SEC_##X } 37 ENUM_ENTRY(CUSTOM), 38 ENUM_ENTRY(TYPE), 39 ENUM_ENTRY(IMPORT), 40 ENUM_ENTRY(FUNCTION), 41 ENUM_ENTRY(TABLE), 42 ENUM_ENTRY(MEMORY), 43 ENUM_ENTRY(GLOBAL), 44 ENUM_ENTRY(EXPORT), 45 ENUM_ENTRY(START), 46 ENUM_ENTRY(ELEM), 47 ENUM_ENTRY(CODE), 48 ENUM_ENTRY(DATA), 49 #undef ENUM_ENTRY 50 }; 51 52 class WasmDumper : public ObjDumper { 53 public: 54 WasmDumper(const WasmObjectFile *Obj, ScopedPrinter &Writer) 55 : ObjDumper(Writer), Obj(Obj) {} 56 57 void printFileHeaders() override; 58 void printSections() override; 59 void printRelocations() override; 60 void printSymbols() override; 61 void printDynamicSymbols() override { llvm_unreachable("unimplemented"); } 62 void printUnwindInfo() override { llvm_unreachable("unimplemented"); } 63 void printStackMap() const override { llvm_unreachable("unimplemented"); } 64 65 protected: 66 void printSymbol(const SymbolRef &Sym); 67 void printRelocation(const SectionRef &Section, const RelocationRef &Reloc); 68 69 private: 70 const WasmObjectFile *Obj; 71 }; 72 73 void WasmDumper::printFileHeaders() { 74 W.printHex("Version", Obj->getHeader().Version); 75 } 76 77 void WasmDumper::printRelocation(const SectionRef &Section, 78 const RelocationRef &Reloc) { 79 SmallString<64> RelocTypeName; 80 uint64_t RelocType = Reloc.getType(); 81 Reloc.getTypeName(RelocTypeName); 82 const wasm::WasmRelocation &WasmReloc = Obj->getWasmRelocation(Reloc); 83 84 bool HasAddend = false; 85 switch (RelocType) { 86 case wasm::R_WEBASSEMBLY_GLOBAL_ADDR_LEB: 87 case wasm::R_WEBASSEMBLY_GLOBAL_ADDR_SLEB: 88 case wasm::R_WEBASSEMBLY_GLOBAL_ADDR_I32: 89 HasAddend = true; 90 break; 91 default: 92 break; 93 } 94 if (opts::ExpandRelocs) { 95 DictScope Group(W, "Relocation"); 96 W.printNumber("Type", RelocTypeName, RelocType); 97 W.printHex("Offset", Reloc.getOffset()); 98 W.printHex("Index", WasmReloc.Index); 99 if (HasAddend) 100 W.printNumber("Addend", WasmReloc.Addend); 101 } else { 102 raw_ostream& OS = W.startLine(); 103 OS << W.hex(Reloc.getOffset()) 104 << " " << RelocTypeName << "[" << WasmReloc.Index << "]"; 105 if (HasAddend) 106 OS << " " << WasmReloc.Addend; 107 OS << "\n"; 108 } 109 } 110 111 void WasmDumper::printRelocations() { 112 ListScope D(W, "Relocations"); 113 114 int SectionNumber = 0; 115 for (const SectionRef &Section : Obj->sections()) { 116 bool PrintedGroup = false; 117 StringRef Name; 118 error(Section.getName(Name)); 119 ++SectionNumber; 120 121 for (const RelocationRef &Reloc : Section.relocations()) { 122 if (!PrintedGroup) { 123 W.startLine() << "Section (" << SectionNumber << ") " << Name << " {\n"; 124 W.indent(); 125 PrintedGroup = true; 126 } 127 128 printRelocation(Section, Reloc); 129 } 130 131 if (PrintedGroup) { 132 W.unindent(); 133 W.startLine() << "}\n"; 134 } 135 } 136 } 137 138 void WasmDumper::printSymbols() { 139 ListScope Group(W, "Symbols"); 140 141 for (const SymbolRef &Symbol : Obj->symbols()) 142 printSymbol(Symbol); 143 } 144 145 void WasmDumper::printSections() { 146 ListScope Group(W, "Sections"); 147 for (const SectionRef &Section : Obj->sections()) { 148 const WasmSection &WasmSec = Obj->getWasmSection(Section); 149 DictScope SectionD(W, "Section"); 150 W.printEnum("Type", WasmSec.Type, makeArrayRef(WasmSectionTypes)); 151 W.printNumber("Size", (uint64_t)WasmSec.Content.size()); 152 W.printNumber("Offset", WasmSec.Offset); 153 switch (WasmSec.Type) { 154 case wasm::WASM_SEC_CUSTOM: 155 W.printString("Name", WasmSec.Name); 156 if (WasmSec.Name == "linking") { 157 const wasm::WasmLinkingData &LinkingData = Obj->linkingData(); 158 W.printNumber("DataSize", LinkingData.DataSize); 159 if (LinkingData.DataAlignment) 160 W.printNumber("DataAlignment", LinkingData.DataAlignment); 161 } 162 break; 163 case wasm::WASM_SEC_MEMORY: 164 ListScope Group(W, "Memories"); 165 for (const wasm::WasmLimits &Memory : Obj->memories()) { 166 DictScope Group(W, "Memory"); 167 W.printNumber("InitialPages", Memory.Initial); 168 if (Memory.Flags & wasm::WASM_LIMITS_FLAG_HAS_MAX) { 169 W.printNumber("MaxPages", WasmSec.Offset); 170 } 171 } 172 break; 173 } 174 175 if (opts::SectionRelocations) { 176 ListScope D(W, "Relocations"); 177 for (const RelocationRef &Reloc : Section.relocations()) 178 printRelocation(Section, Reloc); 179 } 180 181 if (opts::SectionData) { 182 W.printBinaryBlock("SectionData", WasmSec.Content); 183 } 184 } 185 } 186 187 void WasmDumper::printSymbol(const SymbolRef &Sym) { 188 DictScope D(W, "Symbol"); 189 WasmSymbol Symbol = Obj->getWasmSymbol(Sym.getRawDataRefImpl()); 190 W.printString("Name", Symbol.Name); 191 W.printEnum("Type", static_cast<unsigned>(Symbol.Type), makeArrayRef(WasmSymbolTypes)); 192 W.printHex("Flags", Symbol.Flags); 193 } 194 195 } 196 197 namespace llvm { 198 199 std::error_code createWasmDumper(const object::ObjectFile *Obj, 200 ScopedPrinter &Writer, 201 std::unique_ptr<ObjDumper> &Result) { 202 const WasmObjectFile *WasmObj = dyn_cast<WasmObjectFile>(Obj); 203 assert(WasmObj && "createWasmDumper called with non-wasm object"); 204 205 Result.reset(new WasmDumper(WasmObj, Writer)); 206 return readobj_error::success; 207 } 208 209 } // namespace llvm 210