Index: llvm/trunk/include/llvm/Object/Wasm.h =================================================================== --- llvm/trunk/include/llvm/Object/Wasm.h +++ llvm/trunk/include/llvm/Object/Wasm.h @@ -84,7 +84,6 @@ const ArrayRef& code() const { return CodeSection; } uint32_t startFunction() const { return StartFunction; } -protected: void moveSymbolNext(DataRefImpl &Symb) const override; uint32_t getSymbolFlags(DataRefImpl Symb) const override; Index: llvm/trunk/test/tools/llvm-nm/lit.local.cfg =================================================================== --- llvm/trunk/test/tools/llvm-nm/lit.local.cfg +++ llvm/trunk/test/tools/llvm-nm/lit.local.cfg @@ -1,2 +1,4 @@ if not 'X86' in config.root.targets: config.unsupported = True + +config.suffixes = ['.s', '.test', '.yaml'] Index: llvm/trunk/test/tools/llvm-nm/wasm/exports.yaml =================================================================== --- llvm/trunk/test/tools/llvm-nm/wasm/exports.yaml +++ llvm/trunk/test/tools/llvm-nm/wasm/exports.yaml @@ -0,0 +1,22 @@ +# RUN: yaml2obj < %s | llvm-nm - | FileCheck %s + +--- !WASM +FileHeader: + Version: 0x00000001 +Sections: + - Type: TYPE + Signatures: + - ReturnType: I32 + ParamTypes: + - I32 + - Type: EXPORT + Exports: + - Name: foo + Kind: FUNCTION + Index: 0x00000000 + - Name: bar + Kind: GLOBAL + Index: 0x00000000 + +# CHECK: 00000001 D bar +# CHECK: 00000000 T foo Index: llvm/trunk/test/tools/llvm-nm/wasm/imports.yaml =================================================================== --- llvm/trunk/test/tools/llvm-nm/wasm/imports.yaml +++ llvm/trunk/test/tools/llvm-nm/wasm/imports.yaml @@ -0,0 +1,25 @@ +# RUN: yaml2obj < %s | llvm-nm - | FileCheck %s + +--- !WASM +FileHeader: + Version: 0x00000001 +Sections: + - Type: TYPE + Signatures: + - ReturnType: I32 + ParamTypes: + - I32 + - Type: IMPORT + Imports: + - Module: env + Field: foo + Kind: FUNCTION + SigIndex: 0 + - Module: env + Field: bar + Kind: GLOBAL + GlobalType: I32 + GlobalMutable: false + +# CHECK: U bar +# CHECK: U foo Index: llvm/trunk/test/tools/llvm-readobj/file-headers.test =================================================================== --- llvm/trunk/test/tools/llvm-readobj/file-headers.test +++ llvm/trunk/test/tools/llvm-readobj/file-headers.test @@ -26,10 +26,9 @@ RUN: | FileCheck %s -check-prefix COFF-IMPORTLIB RUN: llvm-readobj -h %p/Inputs/trivial.obj.elf-lanai \ RUN: | FileCheck %s -check-prefix ELF-LANAI -# trivial.obj.wasm was generated using wast2wasm which is part of the wabt -# project (https://github.com/WebAssembly/wabt) using the following command: -# $ wast2wasm --debug-names ./test/roundtrip/generate-some-names.txt -o \ -# trivial.obj.wasm +# trivial.obj.wasm was generated using the following command: +# echo "extern int bar, baz; int foo() { return bar + baz + (int)&foo; }" | \ +# ./bin/clang -c -o trivial.obj.wasm -target wasm32-unknown-unknown-wasm -x c - RUN: llvm-readobj -h %p/Inputs/trivial.obj.wasm \ RUN: | FileCheck %s -check-prefix WASM Index: llvm/trunk/test/tools/llvm-readobj/relocations.test =================================================================== --- llvm/trunk/test/tools/llvm-readobj/relocations.test +++ llvm/trunk/test/tools/llvm-readobj/relocations.test @@ -16,6 +16,8 @@ RUN: | FileCheck %s -check-prefix MACHO-PPC64 RUN: llvm-readobj -r -expand-relocs %p/Inputs/trivial.obj.macho-arm \ RUN: | FileCheck %s -check-prefix MACHO-ARM +RUN: llvm-readobj -r --expand-relocs %p/Inputs/trivial.obj.wasm \ +RUN: | FileCheck %s -check-prefix WASM COFF: Relocations [ COFF-NEXT: Section (1) .text { @@ -283,3 +285,26 @@ MACHO-ARM-NEXT: } MACHO-ARM-NEXT: } MACHO-ARM-NEXT: ] + +WASM: Relocations [ +WASM-NEXT: Section (8) CODE { +WASM-NEXT: Relocation { +WASM-NEXT: Type: R_WEBASSEMBLY_TABLE_INDEX_SLEB (1) +WASM-NEXT: Offset: 0x6 +WASM-NEXT: Index: 0x0 +WASM-NEXT: Addend: 0x0 +WASM-NEXT: } +WASM-NEXT: Relocation { +WASM-NEXT: Type: R_WEBASSEMBLY_GLOBAL_ADDR_LEB (3) +WASM-NEXT: Offset: 0x15 +WASM-NEXT: Index: 0x0 +WASM-NEXT: Addend: 0x0 +WASM-NEXT: } +WASM-NEXT: Relocation { +WASM-NEXT: Type: R_WEBASSEMBLY_GLOBAL_ADDR_LEB (3) +WASM-NEXT: Offset: 0x24 +WASM-NEXT: Index: 0x1 +WASM-NEXT: Addend: 0x0 +WASM-NEXT: } +WASM-NEXT: } +WASM-NEXT: ] Index: llvm/trunk/test/tools/llvm-readobj/sections.test =================================================================== --- llvm/trunk/test/tools/llvm-readobj/sections.test +++ llvm/trunk/test/tools/llvm-readobj/sections.test @@ -494,45 +494,56 @@ MACHO-ARM-NEXT:] WASM: Sections [ -WASM-NEXT: Section { -WASM-NEXT: Type: TYPE (0x1) -WASM-NEXT: Size: 15 -WASM-NEXT: Offset: 8 -WASM-NEXT: } -WASM-NEXT: Section { -WASM-NEXT: Type: IMPORT (0x2) -WASM-NEXT: Size: 11 -WASM-NEXT: Offset: 25 -WASM-NEXT: } -WASM-NEXT: Section { -WASM-NEXT: Type: FUNCTION (0x3) -WASM-NEXT: Size: 3 -WASM-NEXT: Offset: 38 -WASM-NEXT: } -WASM-NEXT: Section { -WASM-NEXT: Type: TABLE (0x4) -WASM-NEXT: Size: 5 -WASM-NEXT: Offset: 43 -WASM-NEXT: } -WASM-NEXT: Section { -WASM-NEXT: Type: EXPORT (0x7) -WASM-NEXT: Size: 14 -WASM-NEXT: Offset: 50 -WASM-NEXT: } -WASM-NEXT: Section { -WASM-NEXT: Type: ELEM (0x9) -WASM-NEXT: Size: 7 -WASM-NEXT: Offset: 66 -WASM-NEXT: } -WASM-NEXT: Section { -WASM-NEXT: Type: CODE (0xA) -WASM-NEXT: Size: 42 -WASM-NEXT: Offset: 75 -WASM-NEXT: } -WASM-NEXT: Section { -WASM-NEXT: Type: CUSTOM (0x0) -WASM-NEXT: Size: 60 -WASM-NEXT: Offset: 119 -WASM-NEXT: Name: name -WASM-NEXT: } -WASM-NEXT: ] +WASM-NEXT: Section { +WASM-NEXT: Type: TYPE (0x1) +WASM-NEXT: Size: 5 +WASM-NEXT: Offset: 8 +WASM-NEXT: } +WASM-NEXT: Section { +WASM-NEXT: Type: IMPORT (0x2) +WASM-NEXT: Size: 23 +WASM-NEXT: Offset: 19 +WASM-NEXT: } +WASM-NEXT: Section { +WASM-NEXT: Type: FUNCTION (0x3) +WASM-NEXT: Size: 2 +WASM-NEXT: Offset: 48 +WASM-NEXT: } +WASM-NEXT: Section { +WASM-NEXT: Type: TABLE (0x4) +WASM-NEXT: Size: 4 +WASM-NEXT: Offset: 56 +WASM-NEXT: } +WASM-NEXT: Section { +WASM-NEXT: Type: MEMORY (0x5) +WASM-NEXT: Size: 3 +WASM-NEXT: Offset: 66 +WASM-NEXT: } +WASM-NEXT: Section { +WASM-NEXT: Type: EXPORT (0x7) +WASM-NEXT: Size: 7 +WASM-NEXT: Offset: 75 +WASM-NEXT: } +WASM-NEXT: Section { +WASM-NEXT: Type: ELEM (0x9) +WASM-NEXT: Size: 7 +WASM-NEXT: Offset: 88 +WASM-NEXT: } +WASM-NEXT: Section { +WASM-NEXT: Type: CODE (0xA) +WASM-NEXT: Size: 61 +WASM-NEXT: Offset: 101 +WASM-NEXT: } +WASM-NEXT: Section { +WASM-NEXT: Type: CUSTOM (0x0) +WASM-NEXT: Size: 17 +WASM-NEXT: Offset: 168 +WASM-NEXT: Name: name +WASM-NEXT: } +WASM-NEXT: Section { +WASM-NEXT: Type: CUSTOM (0x0) +WASM-NEXT: Size: 24 +WASM-NEXT: Offset: 191 +WASM-NEXT: Name: reloc.CODE +WASM-NEXT: } +WASM-NEXT:] Index: llvm/trunk/test/tools/llvm-readobj/symbols.test =================================================================== --- llvm/trunk/test/tools/llvm-readobj/symbols.test +++ llvm/trunk/test/tools/llvm-readobj/symbols.test @@ -2,6 +2,8 @@ RUN: | FileCheck %s -check-prefix COFF RUN: llvm-readobj -t %p/Inputs/trivial.obj.elf-i386 \ RUN: | FileCheck %s -check-prefix ELF +RUN: llvm-readobj -t %p/Inputs/trivial.obj.wasm \ +RUN: | FileCheck %s -check-prefix WASM COFF: Symbols [ COFF-NEXT: Symbol { @@ -68,3 +70,22 @@ ELF-NEXT: Other: 0 ELF-NEXT: Section: .rodata.str1.1 (0x5) ELF-NEXT: } + +WASM: Symbols [ +WASM-NEXT: Symbol { +WASM-NEXT: Name: bar +WASM-NEXT: Type: GLOBAL_IMPORT (0x2) +WASM-NEXT: } +WASM-NEXT: Symbol { +WASM-NEXT: Name: baz +WASM-NEXT: Type: GLOBAL_IMPORT (0x2) +WASM-NEXT: } +WASM-NEXT: Symbol { +WASM-NEXT: Name: foo +WASM-NEXT: Type: FUNCTION_EXPORT (0x1) +WASM-NEXT: } +WASM-NEXT: Symbol { +WASM-NEXT: Name: foo +WASM-NEXT: Type: DEBUG_FUNCTION_NAME (0x4) +WASM-NEXT: } +WASM-NEXT: ] Index: llvm/trunk/tools/llvm-nm/llvm-nm.cpp =================================================================== --- llvm/trunk/tools/llvm-nm/llvm-nm.cpp +++ llvm/trunk/tools/llvm-nm/llvm-nm.cpp @@ -29,6 +29,7 @@ #include "llvm/Object/MachO.h" #include "llvm/Object/MachOUniversal.h" #include "llvm/Object/ObjectFile.h" +#include "llvm/Object/Wasm.h" #include "llvm/Support/COFF.h" #include "llvm/Support/CommandLine.h" #include "llvm/Support/FileSystem.h" @@ -270,6 +271,8 @@ return Triple(IRObj->getTargetTriple()).isArch64Bit(); if (isa(Obj)) return false; + if (isa(Obj)) + return false; if (MachOObjectFile *MachO = dyn_cast(&Obj)) return MachO->is64Bit(); return cast(Obj).getBytesInAddress() == 8; @@ -883,6 +886,13 @@ return '?'; } +static char getSymbolNMTypeChar(WasmObjectFile &Obj, basic_symbol_iterator I) { + uint32_t Flags = I->getFlags(); + if (Flags & SymbolRef::SF_Executable) + return 't'; + return 'd'; +} + static char getSymbolNMTypeChar(IRObjectFile &Obj, basic_symbol_iterator I) { uint32_t Flags = I->getFlags(); // FIXME: should we print 'b'? At the IR level we cannot be sure if this @@ -924,6 +934,8 @@ Ret = getSymbolNMTypeChar(*COFF, I); else if (MachOObjectFile *MachO = dyn_cast(&Obj)) Ret = getSymbolNMTypeChar(*MachO, I); + else if (WasmObjectFile *Wasm = dyn_cast(&Obj)) + Ret = getSymbolNMTypeChar(*Wasm, I); else Ret = getSymbolNMTypeChar(cast(Obj), I); Index: llvm/trunk/tools/llvm-readobj/WasmDumper.cpp =================================================================== --- llvm/trunk/tools/llvm-readobj/WasmDumper.cpp +++ llvm/trunk/tools/llvm-readobj/WasmDumper.cpp @@ -13,6 +13,7 @@ #include "Error.h" #include "ObjDumper.h" +#include "llvm-readobj.h" #include "llvm/Object/Wasm.h" #include "llvm/Support/ScopedPrinter.h" @@ -21,60 +22,144 @@ namespace { -const char *wasmSectionTypeToString(uint32_t Type) { -#define ECase(X) \ - case wasm::WASM_SEC_##X: \ - return #X; - switch (Type) { - ECase(CUSTOM); - ECase(TYPE); - ECase(IMPORT); - ECase(FUNCTION); - ECase(TABLE); - ECase(MEMORY); - ECase(GLOBAL); - ECase(EXPORT); - ECase(START); - ECase(ELEM); - ECase(CODE); - ECase(DATA); - } -#undef ECase - return ""; -} +static const EnumEntry WasmSymbolTypes[] = { +#define ENUM_ENTRY(X) { #X, static_cast(WasmSymbol::SymbolType::X) } + ENUM_ENTRY(FUNCTION_IMPORT), + ENUM_ENTRY(FUNCTION_EXPORT), + ENUM_ENTRY(GLOBAL_IMPORT), + ENUM_ENTRY(GLOBAL_EXPORT), + ENUM_ENTRY(DEBUG_FUNCTION_NAME), +#undef ENUM_ENTRY +}; + +static const EnumEntry WasmSectionTypes[] = { +#define ENUM_ENTRY(X) { #X, wasm::WASM_SEC_##X } + ENUM_ENTRY(CUSTOM), + ENUM_ENTRY(TYPE), + ENUM_ENTRY(IMPORT), + ENUM_ENTRY(FUNCTION), + ENUM_ENTRY(TABLE), + ENUM_ENTRY(MEMORY), + ENUM_ENTRY(GLOBAL), + ENUM_ENTRY(EXPORT), + ENUM_ENTRY(START), + ENUM_ENTRY(ELEM), + ENUM_ENTRY(CODE), + ENUM_ENTRY(DATA), +#undef ENUM_ENTRY +}; class WasmDumper : public ObjDumper { public: WasmDumper(const WasmObjectFile *Obj, ScopedPrinter &Writer) : ObjDumper(Writer), Obj(Obj) {} - void printFileHeaders() override { - W.printHex("Version", Obj->getHeader().Version); - } - - void printSections() override { - ListScope Group(W, "Sections"); - for (const SectionRef &Section : Obj->sections()) { - const WasmSection &WasmSec = Obj->getWasmSection(Section); - DictScope SectionD(W, "Section"); - const char *Type = wasmSectionTypeToString(WasmSec.Type); - W.printHex("Type", Type, WasmSec.Type); - W.printNumber("Size", (uint64_t)WasmSec.Content.size()); - W.printNumber("Offset", WasmSec.Offset); - if (WasmSec.Type == wasm::WASM_SEC_CUSTOM) { - W.printString("Name", WasmSec.Name); - } - } - } - void printRelocations() override { llvm_unreachable("unimplemented"); } - void printSymbols() override { llvm_unreachable("unimplemented"); } + void printFileHeaders() override; + void printSections() override; + void printRelocations() override; + void printSymbols() override; void printDynamicSymbols() override { llvm_unreachable("unimplemented"); } void printUnwindInfo() override { llvm_unreachable("unimplemented"); } void printStackMap() const override { llvm_unreachable("unimplemented"); } +protected: + void printSymbol(const SymbolRef &Sym); + void printRelocation(const SectionRef &Section, const RelocationRef &Reloc); + private: const WasmObjectFile *Obj; }; + +void WasmDumper::printFileHeaders() { + W.printHex("Version", Obj->getHeader().Version); +} + +void WasmDumper::printRelocation(const SectionRef &Section, + const RelocationRef &Reloc) { + SmallString<64> RelocTypeName; + uint64_t RelocType = Reloc.getType(); + Reloc.getTypeName(RelocTypeName); + const wasm::WasmRelocation &WasmReloc = Obj->getWasmRelocation(Reloc); + + if (opts::ExpandRelocs) { + DictScope Group(W, "Relocation"); + W.printNumber("Type", RelocTypeName, RelocType); + W.printHex("Offset", Reloc.getOffset()); + W.printHex("Index", WasmReloc.Index); + W.printHex("Addend", WasmReloc.Addend); + } else { + raw_ostream& OS = W.startLine(); + OS << W.hex(Reloc.getOffset()) + << " " << RelocTypeName << "[" << WasmReloc.Index << "]" + << " " << W.hex(WasmReloc.Addend) << "\n"; + } +} + +void WasmDumper::printRelocations() { + ListScope D(W, "Relocations"); + + int SectionNumber = 0; + for (const SectionRef &Section : Obj->sections()) { + bool PrintedGroup = false; + StringRef Name; + error(Section.getName(Name)); + ++SectionNumber; + + for (const RelocationRef &Reloc : Section.relocations()) { + if (!PrintedGroup) { + W.startLine() << "Section (" << SectionNumber << ") " << Name << " {\n"; + W.indent(); + PrintedGroup = true; + } + + printRelocation(Section, Reloc); + } + + if (PrintedGroup) { + W.unindent(); + W.startLine() << "}\n"; + } + } +} + +void WasmDumper::printSymbols() { + ListScope Group(W, "Symbols"); + + for (const SymbolRef &Symbol : Obj->symbols()) + printSymbol(Symbol); +} + +void WasmDumper::printSections() { + ListScope Group(W, "Sections"); + for (const SectionRef &Section : Obj->sections()) { + const WasmSection &WasmSec = Obj->getWasmSection(Section); + DictScope SectionD(W, "Section"); + W.printEnum("Type", WasmSec.Type, makeArrayRef(WasmSectionTypes)); + W.printNumber("Size", (uint64_t)WasmSec.Content.size()); + W.printNumber("Offset", WasmSec.Offset); + if (WasmSec.Type == wasm::WASM_SEC_CUSTOM) { + W.printString("Name", WasmSec.Name); + } + + if (opts::SectionRelocations) { + ListScope D(W, "Relocations"); + for (const RelocationRef &Reloc : Section.relocations()) + printRelocation(Section, Reloc); + } + + if (opts::SectionData) { + W.printBinaryBlock("SectionData", WasmSec.Content); + } + } +} + +void WasmDumper::printSymbol(const SymbolRef &Sym) { + DictScope D(W, "Symbol"); + WasmSymbol Symbol = Obj->getWasmSymbol(Sym.getRawDataRefImpl()); + W.printString("Name", Symbol.Name); + W.printEnum("Type", static_cast(Symbol.Type), makeArrayRef(WasmSymbolTypes)); +} + } namespace llvm {