mirror of
https://github.com/RPCS3/llvm-mirror.git
synced 2024-11-22 18:54:02 +01:00
[WebAssembly] Improve readobj and nm support for wasm
Now that the libObect support for wasm is better we can have readobj and nm produce more useful output too. Differential Revision: https://reviews.llvm.org/D31514 llvm-svn: 300365
This commit is contained in:
parent
0ee9395084
commit
c688dd181f
@ -84,7 +84,6 @@ public:
|
||||
const ArrayRef<uint8_t>& code() const { return CodeSection; }
|
||||
uint32_t startFunction() const { return StartFunction; }
|
||||
|
||||
protected:
|
||||
void moveSymbolNext(DataRefImpl &Symb) const override;
|
||||
|
||||
uint32_t getSymbolFlags(DataRefImpl Symb) const override;
|
||||
|
@ -1,2 +1,4 @@
|
||||
if not 'X86' in config.root.targets:
|
||||
config.unsupported = True
|
||||
|
||||
config.suffixes = ['.s', '.test', '.yaml']
|
||||
|
22
test/tools/llvm-nm/wasm/exports.yaml
Normal file
22
test/tools/llvm-nm/wasm/exports.yaml
Normal file
@ -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
|
25
test/tools/llvm-nm/wasm/imports.yaml
Normal file
25
test/tools/llvm-nm/wasm/imports.yaml
Normal file
@ -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
|
Binary file not shown.
@ -26,10 +26,9 @@ 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
|
||||
# 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
|
||||
|
||||
|
@ -16,6 +16,8 @@ RUN: llvm-readobj -r --expand-relocs %p/Inputs/trivial.obj.macho-ppc64 \
|
||||
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: Value: 0x4
|
||||
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: ]
|
||||
|
@ -494,45 +494,56 @@ 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: 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:]
|
||||
|
@ -2,6 +2,8 @@ RUN: llvm-readobj -t %p/Inputs/trivial.obj.coff-i386 \
|
||||
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: Type: Object (0x1)
|
||||
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: ]
|
||||
|
@ -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 @@ static char isSymbolList64Bit(SymbolicFile &Obj) {
|
||||
return Triple(IRObj->getTargetTriple()).isArch64Bit();
|
||||
if (isa<COFFObjectFile>(Obj))
|
||||
return false;
|
||||
if (isa<WasmObjectFile>(Obj))
|
||||
return false;
|
||||
if (MachOObjectFile *MachO = dyn_cast<MachOObjectFile>(&Obj))
|
||||
return MachO->is64Bit();
|
||||
return cast<ELFObjectFileBase>(Obj).getBytesInAddress() == 8;
|
||||
@ -883,6 +886,13 @@ static char getSymbolNMTypeChar(MachOObjectFile &Obj, basic_symbol_iterator I) {
|
||||
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 @@ static char getNMTypeChar(SymbolicFile &Obj, basic_symbol_iterator I) {
|
||||
Ret = getSymbolNMTypeChar(*COFF, I);
|
||||
else if (MachOObjectFile *MachO = dyn_cast<MachOObjectFile>(&Obj))
|
||||
Ret = getSymbolNMTypeChar(*MachO, I);
|
||||
else if (WasmObjectFile *Wasm = dyn_cast<WasmObjectFile>(&Obj))
|
||||
Ret = getSymbolNMTypeChar(*Wasm, I);
|
||||
else
|
||||
Ret = getSymbolNMTypeChar(cast<ELFObjectFileBase>(Obj), I);
|
||||
|
||||
|
@ -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 @@ 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 "";
|
||||
}
|
||||
static const EnumEntry<unsigned> WasmSymbolTypes[] = {
|
||||
#define ENUM_ENTRY(X) { #X, static_cast<unsigned>(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<uint32_t> 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<unsigned>(Symbol.Type), makeArrayRef(WasmSymbolTypes));
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
namespace llvm {
|
||||
|
Loading…
Reference in New Issue
Block a user