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:
WasmDumper(const WasmObjectFile * Obj,ScopedPrinter & Writer)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;
printDynamicSymbols()53   void printDynamicSymbols() override { llvm_unreachable("unimplemented"); }
printUnwindInfo()54   void printUnwindInfo() override { llvm_unreachable("unimplemented"); }
printStackMap() const55   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 
printFileHeaders()65 void WasmDumper::printFileHeaders() {
66   W.printHex("Version", Obj->getHeader().Version);
67 }
68 
printRelocation(const SectionRef & Section,const RelocationRef & Reloc)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 
printRelocations()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 
printSymbols()143 void WasmDumper::printSymbols() {
144   ListScope Group(W, "Symbols");
145 
146   for (const SymbolRef &Symbol : Obj->symbols())
147     printSymbol(Symbol);
148 }
149 
printSectionHeaders()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 
printSymbol(const SymbolRef & Sym)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 
createWasmDumper(const object::ObjectFile * Obj,ScopedPrinter & Writer,std::unique_ptr<ObjDumper> & Result)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