From c20099fa53a07598f0cdcb5d981b14cc1ce71034 Mon Sep 17 00:00:00 2001 From: Derek Schuff Date: Mon, 30 Jan 2017 23:30:52 +0000 Subject: [PATCH] [WebAssembly] Add wasm support for llvm-readobj Create a WasmDumper subclass of ObjDumper to support Webassembly binary files. Patch by Sam Clegg Differential Revision: https://reviews.llvm.org/D27355 git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@293569 91177308-0d34-0410-b5e6-96231b3b80d8 --- include/llvm/Object/Wasm.h | 4 +- include/llvm/Support/Wasm.h | 2 +- lib/Object/WasmObjectFile.cpp | 11 +-- test/tools/llvm-readobj/Inputs/trivial.obj.wasm | Bin 0 -> 165 bytes test/tools/llvm-readobj/file-headers.test | 11 +++ test/tools/llvm-readobj/sections.test | 46 ++++++++++++ tools/llvm-readobj/CMakeLists.txt | 1 + tools/llvm-readobj/ObjDumper.h | 4 ++ tools/llvm-readobj/WasmDumper.cpp | 92 ++++++++++++++++++++++++ tools/llvm-readobj/llvm-readobj.cpp | 2 + 10 files changed, 165 insertions(+), 8 deletions(-) create mode 100644 test/tools/llvm-readobj/Inputs/trivial.obj.wasm create mode 100644 tools/llvm-readobj/WasmDumper.cpp diff --git a/include/llvm/Object/Wasm.h b/include/llvm/Object/Wasm.h index 2ece6a6c377..999d575943b 100644 --- a/include/llvm/Object/Wasm.h +++ b/include/llvm/Object/Wasm.h @@ -87,8 +87,8 @@ protected: private: const uint8_t *getPtr(size_t Offset) const; - Error parseUserSection(wasm::WasmSection &Sec, const uint8_t *Ptr, - size_t Length); + Error parseCustomSection(wasm::WasmSection &Sec, const uint8_t *Ptr, + size_t Length); wasm::WasmObjectHeader Header; std::vector Sections; diff --git a/include/llvm/Support/Wasm.h b/include/llvm/Support/Wasm.h index 8ac6b9038e9..b45149577a0 100644 --- a/include/llvm/Support/Wasm.h +++ b/include/llvm/Support/Wasm.h @@ -38,7 +38,7 @@ struct WasmSection { }; enum : unsigned { - WASM_SEC_USER = 0, // User-defined section + WASM_SEC_CUSTOM = 0, // Custom / User-defined section WASM_SEC_TYPE = 1, // Function signature declarations WASM_SEC_IMPORT = 2, // Import declarations WASM_SEC_FUNCTION = 3, // Function declarations diff --git a/lib/Object/WasmObjectFile.cpp b/lib/Object/WasmObjectFile.cpp index 2b61a8a034f..e61ae156a74 100644 --- a/lib/Object/WasmObjectFile.cpp +++ b/lib/Object/WasmObjectFile.cpp @@ -83,16 +83,17 @@ WasmObjectFile::WasmObjectFile(MemoryBufferRef Buffer, Error &Err) while (Ptr < Eof) { if ((Err = readSection(Sec, Ptr, getPtr(0)))) return; - if (Sec.Type == wasm::WASM_SEC_USER) { - if ((Err = parseUserSection(Sec, Sec.Content.data(), Sec.Content.size()))) + if (Sec.Type == wasm::WASM_SEC_CUSTOM) { + if ((Err = + parseCustomSection(Sec, Sec.Content.data(), Sec.Content.size()))) return; } Sections.push_back(Sec); } } -Error WasmObjectFile::parseUserSection(wasm::WasmSection &Sec, - const uint8_t *Ptr, size_t Length) { +Error WasmObjectFile::parseCustomSection(wasm::WasmSection &Sec, + const uint8_t *Ptr, size_t Length) { Sec.Name = readString(Ptr); return Error::success(); } @@ -186,7 +187,7 @@ std::error_code WasmObjectFile::getSectionName(DataRefImpl Sec, ECase(ELEM); ECase(CODE); ECase(DATA); - case wasm::WASM_SEC_USER: + case wasm::WASM_SEC_CUSTOM: Res = S.Name; break; default: diff --git a/test/tools/llvm-readobj/Inputs/trivial.obj.wasm b/test/tools/llvm-readobj/Inputs/trivial.obj.wasm new file mode 100644 index 0000000000000000000000000000000000000000..b24ac79c716374a77d9ffc06f183251720b1c438 GIT binary patch literal 165 zcmWNJ!3u&v6h-fSV+}P_wsmFTDq7?hg!Cg$k`OqKSwci+pWbXPhjZY%{s zu>_}5rZ2=$)!wU%?Lnmk63y6=)N2Xy4Mg{0c!3K|6fnecFB)gycQUDPd0^loprXiE)UT7$~O5QJkA?& literal 0 HcmV?d00001 diff --git a/test/tools/llvm-readobj/file-headers.test b/test/tools/llvm-readobj/file-headers.test index 662c9b6bd4d..4fcb2859d27 100644 --- a/test/tools/llvm-readobj/file-headers.test +++ b/test/tools/llvm-readobj/file-headers.test @@ -26,6 +26,12 @@ RUN: llvm-readobj -h %p/Inputs/magic.coff-importlib \ 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 +RUN: llvm-readobj -h %p/Inputs/trivial.obj.wasm \ +RUN: | FileCheck %s -check-prefix WASM COFF-ARM: File: {{(.*[/\\])?}}trivial.obj.coff-arm COFF-ARM-NEXT: Format: COFF-ARM @@ -367,3 +373,8 @@ ELF-LANAI-NEXT: SectionHeaderEntrySize: 40 ELF-LANAI-NEXT: SectionHeaderCount: 8 ELF-LANAI-NEXT: StringTableSectionIndex: 1 ELF-LANAI-NEXT: } + +WASM: Format: WASM +WASM-NEXT: Arch: wasm32 +WASM-NEXT: AddressSize: 32bit +WASM-NEXT: Version: 0xD diff --git a/test/tools/llvm-readobj/sections.test b/test/tools/llvm-readobj/sections.test index 54654e7070e..26a72d85e49 100644 --- a/test/tools/llvm-readobj/sections.test +++ b/test/tools/llvm-readobj/sections.test @@ -14,6 +14,8 @@ RUN: llvm-readobj -s %p/Inputs/trivial.obj.macho-ppc64 \ RUN: | FileCheck %s -check-prefix MACHO-PPC64 RUN: llvm-readobj -s %p/Inputs/trivial.obj.macho-arm \ RUN: | FileCheck %s -check-prefix MACHO-ARM +RUN: llvm-readobj -s %p/Inputs/trivial.obj.wasm \ +RUN: | FileCheck %s -check-prefix WASM COFF: Sections [ COFF-NEXT: Section { @@ -490,3 +492,47 @@ MACHO-ARM-NEXT: Reserved1: 0x0 MACHO-ARM-NEXT: Reserved2: 0x0 MACHO-ARM-NEXT: } 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: 44 +WASM-NEXT: Offset: 119 +WASM-NEXT: Name: name +WASM-NEXT: } +WASM-NEXT: ] diff --git a/tools/llvm-readobj/CMakeLists.txt b/tools/llvm-readobj/CMakeLists.txt index d4b7125dbbb..5fd45a8cff6 100644 --- a/tools/llvm-readobj/CMakeLists.txt +++ b/tools/llvm-readobj/CMakeLists.txt @@ -15,5 +15,6 @@ add_llvm_tool(llvm-readobj llvm-readobj.cpp MachODumper.cpp ObjDumper.cpp + WasmDumper.cpp Win64EHDumper.cpp ) diff --git a/tools/llvm-readobj/ObjDumper.h b/tools/llvm-readobj/ObjDumper.h index c91558ecbfa..75090312b21 100644 --- a/tools/llvm-readobj/ObjDumper.h +++ b/tools/llvm-readobj/ObjDumper.h @@ -96,6 +96,10 @@ std::error_code createMachODumper(const object::ObjectFile *Obj, ScopedPrinter &Writer, std::unique_ptr &Result); +std::error_code createWasmDumper(const object::ObjectFile *Obj, + ScopedPrinter &Writer, + std::unique_ptr &Result); + void dumpCOFFImportFile(const object::COFFImportFile *File); void dumpCodeViewMergedTypes(ScopedPrinter &Writer, diff --git a/tools/llvm-readobj/WasmDumper.cpp b/tools/llvm-readobj/WasmDumper.cpp new file mode 100644 index 00000000000..8f3ec575e47 --- /dev/null +++ b/tools/llvm-readobj/WasmDumper.cpp @@ -0,0 +1,92 @@ +//===-- WasmDumper.cpp - Wasm-specific object file dumper -----------------===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This file implements the Wasm-specific dumper for llvm-readobj. +// +//===----------------------------------------------------------------------===// + +#include "Error.h" +#include "ObjDumper.h" +#include "llvm/Object/Wasm.h" +#include "llvm/Support/ScopedPrinter.h" + +using namespace llvm; +using namespace object; + +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 ""; +} + +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 wasm::WasmSection *WasmSec = Obj->getWasmSection(Section); + DictScope SectionD(W, "Section"); + const char *Type = wasmSectionTypeToString(WasmSec->Type); + W.printHex("Type", Type, WasmSec->Type); + W.printNumber("Size", 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 printDynamicSymbols() override { llvm_unreachable("unimplemented"); } + void printUnwindInfo() override { llvm_unreachable("unimplemented"); } + void printStackMap() const override { llvm_unreachable("unimplemented"); } + +private: + const WasmObjectFile *Obj; +}; +} + +namespace llvm { + +std::error_code createWasmDumper(const object::ObjectFile *Obj, + ScopedPrinter &Writer, + std::unique_ptr &Result) { + const WasmObjectFile *WasmObj = dyn_cast(Obj); + assert(WasmObj && "createWasmDumper called with non-wasm object"); + + Result.reset(new WasmDumper(WasmObj, Writer)); + return readobj_error::success; +} + +} // namespace llvm diff --git a/tools/llvm-readobj/llvm-readobj.cpp b/tools/llvm-readobj/llvm-readobj.cpp index 970e1545de0..fffcd1790e3 100644 --- a/tools/llvm-readobj/llvm-readobj.cpp +++ b/tools/llvm-readobj/llvm-readobj.cpp @@ -358,6 +358,8 @@ static std::error_code createDumper(const ObjectFile *Obj, return createELFDumper(Obj, Writer, Result); if (Obj->isMachO()) return createMachODumper(Obj, Writer, Result); + if (Obj->isWasm()) + return createWasmDumper(Obj, Writer, Result); return readobj_error::unsupported_obj_file_format; } -- 2.11.0