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 = false; 97 switch (RelocType) { 98 case wasm::R_WASM_MEMORY_ADDR_LEB: 99 case wasm::R_WASM_MEMORY_ADDR_SLEB: 100 case wasm::R_WASM_MEMORY_ADDR_I32: 101 case wasm::R_WASM_FUNCTION_OFFSET_I32: 102 case wasm::R_WASM_SECTION_OFFSET_I32: 103 HasAddend = true; 104 break; 105 default: 106 break; 107 } 108 if (opts::ExpandRelocs) { 109 DictScope Group(W, "Relocation"); 110 W.printNumber("Type", RelocTypeName, RelocType); 111 W.printHex("Offset", Reloc.getOffset()); 112 if (!SymName.empty()) 113 W.printString("Symbol", SymName); 114 else 115 W.printHex("Index", WasmReloc.Index); 116 if (HasAddend) 117 W.printNumber("Addend", WasmReloc.Addend); 118 } else { 119 raw_ostream &OS = W.startLine(); 120 OS << W.hex(Reloc.getOffset()) << " " << RelocTypeName << " "; 121 if (!SymName.empty()) 122 OS << SymName; 123 else 124 OS << WasmReloc.Index; 125 if (HasAddend) 126 OS << " " << WasmReloc.Addend; 127 OS << "\n"; 128 } 129 } 130 131 void WasmDumper::printRelocations() { 132 ListScope D(W, "Relocations"); 133 134 int SectionNumber = 0; 135 for (const SectionRef &Section : Obj->sections()) { 136 bool PrintedGroup = false; 137 StringRef Name = unwrapOrError(Obj->getFileName(), Section.getName()); 138 139 ++SectionNumber; 140 141 for (const RelocationRef &Reloc : Section.relocations()) { 142 if (!PrintedGroup) { 143 W.startLine() << "Section (" << SectionNumber << ") " << Name << " {\n"; 144 W.indent(); 145 PrintedGroup = true; 146 } 147 148 printRelocation(Section, Reloc); 149 } 150 151 if (PrintedGroup) { 152 W.unindent(); 153 W.startLine() << "}\n"; 154 } 155 } 156 } 157 158 void WasmDumper::printSymbols() { 159 ListScope Group(W, "Symbols"); 160 161 for (const SymbolRef &Symbol : Obj->symbols()) 162 printSymbol(Symbol); 163 } 164 165 void WasmDumper::printSectionHeaders() { 166 ListScope Group(W, "Sections"); 167 for (const SectionRef &Section : Obj->sections()) { 168 const WasmSection &WasmSec = Obj->getWasmSection(Section); 169 DictScope SectionD(W, "Section"); 170 W.printEnum("Type", WasmSec.Type, makeArrayRef(WasmSectionTypes)); 171 W.printNumber("Size", static_cast<uint64_t>(WasmSec.Content.size())); 172 W.printNumber("Offset", WasmSec.Offset); 173 switch (WasmSec.Type) { 174 case wasm::WASM_SEC_CUSTOM: 175 W.printString("Name", WasmSec.Name); 176 if (WasmSec.Name == "linking") { 177 const wasm::WasmLinkingData &LinkingData = Obj->linkingData(); 178 if (!LinkingData.InitFunctions.empty()) { 179 ListScope Group(W, "InitFunctions"); 180 for (const wasm::WasmInitFunc &F : LinkingData.InitFunctions) 181 W.startLine() << F.Symbol << " (priority=" << F.Priority << ")\n"; 182 } 183 } 184 break; 185 case wasm::WASM_SEC_DATA: { 186 ListScope Group(W, "Segments"); 187 for (const WasmSegment &Segment : Obj->dataSegments()) { 188 const wasm::WasmDataSegment &Seg = Segment.Data; 189 DictScope Group(W, "Segment"); 190 if (!Seg.Name.empty()) 191 W.printString("Name", Seg.Name); 192 W.printNumber("Size", static_cast<uint64_t>(Seg.Content.size())); 193 if (Seg.Offset.Opcode == wasm::WASM_OPCODE_I32_CONST) 194 W.printNumber("Offset", Seg.Offset.Value.Int32); 195 } 196 break; 197 } 198 case wasm::WASM_SEC_MEMORY: 199 ListScope Group(W, "Memories"); 200 for (const wasm::WasmLimits &Memory : Obj->memories()) { 201 DictScope Group(W, "Memory"); 202 W.printNumber("InitialPages", Memory.Initial); 203 if (Memory.Flags & wasm::WASM_LIMITS_FLAG_HAS_MAX) { 204 W.printNumber("MaxPages", WasmSec.Offset); 205 } 206 } 207 break; 208 } 209 210 if (opts::SectionRelocations) { 211 ListScope D(W, "Relocations"); 212 for (const RelocationRef &Reloc : Section.relocations()) 213 printRelocation(Section, Reloc); 214 } 215 216 if (opts::SectionData) { 217 W.printBinaryBlock("SectionData", WasmSec.Content); 218 } 219 } 220 } 221 222 void WasmDumper::printSymbol(const SymbolRef &Sym) { 223 DictScope D(W, "Symbol"); 224 WasmSymbol Symbol = Obj->getWasmSymbol(Sym.getRawDataRefImpl()); 225 W.printString("Name", Symbol.Info.Name); 226 W.printEnum("Type", Symbol.Info.Kind, makeArrayRef(WasmSymbolTypes)); 227 W.printFlags("Flags", Symbol.Info.Flags, makeArrayRef(WasmSymbolFlags)); 228 229 if (Symbol.Info.Flags & wasm::WASM_SYMBOL_UNDEFINED) { 230 W.printString("ImportName", Symbol.Info.ImportName); 231 W.printString("ImportModule", Symbol.Info.ImportModule); 232 } 233 if (Symbol.Info.Kind != wasm::WASM_SYMBOL_TYPE_DATA) { 234 W.printHex("ElementIndex", Symbol.Info.ElementIndex); 235 } else if (!(Symbol.Info.Flags & wasm::WASM_SYMBOL_UNDEFINED)) { 236 W.printHex("Offset", Symbol.Info.DataRef.Offset); 237 W.printHex("Segment", Symbol.Info.DataRef.Segment); 238 W.printHex("Size", Symbol.Info.DataRef.Size); 239 } 240 } 241 242 } // namespace 243 244 namespace llvm { 245 246 std::error_code createWasmDumper(const object::ObjectFile *Obj, 247 ScopedPrinter &Writer, 248 std::unique_ptr<ObjDumper> &Result) { 249 const auto *WasmObj = dyn_cast<WasmObjectFile>(Obj); 250 assert(WasmObj && "createWasmDumper called with non-wasm object"); 251 252 Result.reset(new WasmDumper(WasmObj, Writer)); 253 return readobj_error::success; 254 } 255 256 } // namespace llvm 257