| //===- WasmObjectFile.cpp - Wasm object file implementation -----*- C++ -*-===// |
| // |
| // The LLVM Compiler Infrastructure |
| // |
| // This file is distributed under the University of Illinois Open Source |
| // License. See LICENSE.TXT for details. |
| // |
| //===----------------------------------------------------------------------===// |
| |
| #include "llvm/Object/Wasm.h" |
| #include "llvm/Support/Endian.h" |
| #include "llvm/Support/LEB128.h" |
| |
| namespace llvm { |
| namespace object { |
| |
| Expected<std::unique_ptr<WasmObjectFile>> |
| ObjectFile::createWasmObjectFile(MemoryBufferRef Buffer) { |
| Error Err = Error::success(); |
| auto ObjectFile = llvm::make_unique<WasmObjectFile>(Buffer, Err); |
| if (Err) |
| return std::move(Err); |
| |
| return std::move(ObjectFile); |
| } |
| |
| namespace { |
| |
| uint32_t readUint32(const uint8_t *&Ptr) { |
| uint32_t Result = support::endian::read32le(Ptr); |
| Ptr += sizeof(Result); |
| return Result; |
| } |
| |
| uint64_t readULEB128(const uint8_t *&Ptr) { |
| unsigned Count; |
| uint64_t Result = decodeULEB128(Ptr, &Count); |
| Ptr += Count; |
| return Result; |
| } |
| |
| StringRef readString(const uint8_t *&Ptr) { |
| uint32_t StringLen = readULEB128(Ptr); |
| StringRef Return = StringRef(reinterpret_cast<const char *>(Ptr), StringLen); |
| Ptr += StringLen; |
| return Return; |
| } |
| |
| Error readSection(wasm::WasmSection &Section, const uint8_t *&Ptr, |
| const uint8_t *Start) { |
| // TODO(sbc): Avoid reading past EOF in the case of malformed files. |
| Section.Offset = Ptr - Start; |
| Section.Type = readULEB128(Ptr); |
| uint32_t Size = readULEB128(Ptr); |
| if (Size == 0) |
| return make_error<StringError>("Zero length section", |
| object_error::parse_failed); |
| Section.Content = ArrayRef<uint8_t>(Ptr, Size); |
| Ptr += Size; |
| return Error::success(); |
| } |
| } |
| |
| WasmObjectFile::WasmObjectFile(MemoryBufferRef Buffer, Error &Err) |
| : ObjectFile(Binary::ID_Wasm, Buffer) { |
| ErrorAsOutParameter ErrAsOutParam(&Err); |
| Header.Magic = getData().substr(0, 4); |
| if (Header.Magic != StringRef("\0asm", 4)) { |
| Err = make_error<StringError>("Bad magic number", |
| object_error::parse_failed); |
| return; |
| } |
| const uint8_t *Ptr = getPtr(4); |
| Header.Version = readUint32(Ptr); |
| if (Header.Version != wasm::WasmVersion) { |
| Err = make_error<StringError>("Bad version number", |
| object_error::parse_failed); |
| return; |
| } |
| |
| const uint8_t *Eof = getPtr(getData().size()); |
| wasm::WasmSection Sec; |
| 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()))) |
| return; |
| } |
| Sections.push_back(Sec); |
| } |
| } |
| |
| Error WasmObjectFile::parseUserSection(wasm::WasmSection &Sec, |
| const uint8_t *Ptr, size_t Length) { |
| Sec.Name = readString(Ptr); |
| return Error::success(); |
| } |
| |
| const uint8_t *WasmObjectFile::getPtr(size_t Offset) const { |
| return reinterpret_cast<const uint8_t *>(getData().substr(Offset, 1).data()); |
| } |
| |
| const wasm::WasmObjectHeader &WasmObjectFile::getHeader() const { |
| return Header; |
| } |
| |
| void WasmObjectFile::moveSymbolNext(DataRefImpl &Symb) const { |
| llvm_unreachable("not yet implemented"); |
| } |
| |
| std::error_code WasmObjectFile::printSymbolName(raw_ostream &OS, |
| DataRefImpl Symb) const { |
| llvm_unreachable("not yet implemented"); |
| return object_error::invalid_symbol_index; |
| } |
| |
| uint32_t WasmObjectFile::getSymbolFlags(DataRefImpl Symb) const { |
| llvm_unreachable("not yet implemented"); |
| return 0; |
| } |
| |
| basic_symbol_iterator WasmObjectFile::symbol_begin() const { |
| return BasicSymbolRef(DataRefImpl(), this); |
| } |
| |
| basic_symbol_iterator WasmObjectFile::symbol_end() const { |
| return BasicSymbolRef(DataRefImpl(), this); |
| } |
| |
| Expected<StringRef> WasmObjectFile::getSymbolName(DataRefImpl Symb) const { |
| llvm_unreachable("not yet implemented"); |
| return errorCodeToError(object_error::invalid_symbol_index); |
| } |
| |
| Expected<uint64_t> WasmObjectFile::getSymbolAddress(DataRefImpl Symb) const { |
| llvm_unreachable("not yet implemented"); |
| return errorCodeToError(object_error::invalid_symbol_index); |
| } |
| |
| uint64_t WasmObjectFile::getSymbolValueImpl(DataRefImpl Symb) const { |
| llvm_unreachable("not yet implemented"); |
| return 0; |
| } |
| |
| uint32_t WasmObjectFile::getSymbolAlignment(DataRefImpl Symb) const { |
| llvm_unreachable("not yet implemented"); |
| return 0; |
| } |
| |
| uint64_t WasmObjectFile::getCommonSymbolSizeImpl(DataRefImpl Symb) const { |
| llvm_unreachable("not yet implemented"); |
| return 0; |
| } |
| |
| Expected<SymbolRef::Type> |
| WasmObjectFile::getSymbolType(DataRefImpl Symb) const { |
| llvm_unreachable("not yet implemented"); |
| return errorCodeToError(object_error::invalid_symbol_index); |
| } |
| |
| Expected<section_iterator> |
| WasmObjectFile::getSymbolSection(DataRefImpl Symb) const { |
| llvm_unreachable("not yet implemented"); |
| return errorCodeToError(object_error::invalid_symbol_index); |
| } |
| |
| void WasmObjectFile::moveSectionNext(DataRefImpl &Sec) const { Sec.d.a++; } |
| |
| std::error_code WasmObjectFile::getSectionName(DataRefImpl Sec, |
| StringRef &Res) const { |
| const wasm::WasmSection &S = Sections[Sec.d.a]; |
| #define ECase(X) \ |
| case wasm::WASM_SEC_##X: \ |
| Res = #X; \ |
| break |
| switch (S.Type) { |
| ECase(TYPE); |
| ECase(IMPORT); |
| ECase(FUNCTION); |
| ECase(TABLE); |
| ECase(MEMORY); |
| ECase(GLOBAL); |
| ECase(EXPORT); |
| ECase(START); |
| ECase(ELEM); |
| ECase(CODE); |
| ECase(DATA); |
| case wasm::WASM_SEC_USER: |
| Res = S.Name; |
| break; |
| default: |
| return object_error::invalid_section_index; |
| } |
| #undef ECase |
| return std::error_code(); |
| } |
| |
| uint64_t WasmObjectFile::getSectionAddress(DataRefImpl Sec) const { return 0; } |
| |
| uint64_t WasmObjectFile::getSectionSize(DataRefImpl Sec) const { |
| const wasm::WasmSection &S = Sections[Sec.d.a]; |
| return S.Content.size(); |
| } |
| |
| std::error_code WasmObjectFile::getSectionContents(DataRefImpl Sec, |
| StringRef &Res) const { |
| const wasm::WasmSection &S = Sections[Sec.d.a]; |
| // This will never fail since wasm sections can never be empty (user-sections |
| // must have a name and non-user sections each have a defined structure). |
| Res = StringRef(reinterpret_cast<const char *>(S.Content.data()), |
| S.Content.size()); |
| return std::error_code(); |
| } |
| |
| uint64_t WasmObjectFile::getSectionAlignment(DataRefImpl Sec) const { |
| return 1; |
| } |
| |
| bool WasmObjectFile::isSectionCompressed(DataRefImpl Sec) const { |
| return false; |
| } |
| |
| bool WasmObjectFile::isSectionText(DataRefImpl Sec) const { |
| const wasm::WasmSection &S = Sections[Sec.d.a]; |
| return S.Type == wasm::WASM_SEC_CODE; |
| } |
| |
| bool WasmObjectFile::isSectionData(DataRefImpl Sec) const { |
| const wasm::WasmSection &S = Sections[Sec.d.a]; |
| return S.Type == wasm::WASM_SEC_DATA; |
| } |
| |
| bool WasmObjectFile::isSectionBSS(DataRefImpl Sec) const { return false; } |
| |
| bool WasmObjectFile::isSectionVirtual(DataRefImpl Sec) const { return false; } |
| |
| bool WasmObjectFile::isSectionBitcode(DataRefImpl Sec) const { return false; } |
| |
| relocation_iterator WasmObjectFile::section_rel_begin(DataRefImpl Sec) const { |
| llvm_unreachable("not yet implemented"); |
| RelocationRef Rel; |
| return relocation_iterator(Rel); |
| } |
| |
| relocation_iterator WasmObjectFile::section_rel_end(DataRefImpl Sec) const { |
| llvm_unreachable("not yet implemented"); |
| RelocationRef Rel; |
| return relocation_iterator(Rel); |
| } |
| |
| section_iterator WasmObjectFile::getRelocatedSection(DataRefImpl Sec) const { |
| llvm_unreachable("not yet implemented"); |
| SectionRef Ref; |
| return section_iterator(Ref); |
| } |
| |
| void WasmObjectFile::moveRelocationNext(DataRefImpl &Rel) const { |
| llvm_unreachable("not yet implemented"); |
| } |
| |
| uint64_t WasmObjectFile::getRelocationOffset(DataRefImpl Rel) const { |
| llvm_unreachable("not yet implemented"); |
| return 0; |
| } |
| |
| symbol_iterator WasmObjectFile::getRelocationSymbol(DataRefImpl Rel) const { |
| llvm_unreachable("not yet implemented"); |
| SymbolRef Ref; |
| return symbol_iterator(Ref); |
| } |
| |
| uint64_t WasmObjectFile::getRelocationType(DataRefImpl Rel) const { |
| llvm_unreachable("not yet implemented"); |
| return 0; |
| } |
| |
| void WasmObjectFile::getRelocationTypeName( |
| DataRefImpl Rel, SmallVectorImpl<char> &Result) const { |
| llvm_unreachable("not yet implemented"); |
| } |
| |
| section_iterator WasmObjectFile::section_begin() const { |
| DataRefImpl Ref; |
| Ref.d.a = 0; |
| return section_iterator(SectionRef(Ref, this)); |
| } |
| |
| section_iterator WasmObjectFile::section_end() const { |
| DataRefImpl Ref; |
| Ref.d.a = Sections.size(); |
| return section_iterator(SectionRef(Ref, this)); |
| } |
| |
| uint8_t WasmObjectFile::getBytesInAddress() const { return 4; } |
| |
| StringRef WasmObjectFile::getFileFormatName() const { return "WASM"; } |
| |
| unsigned WasmObjectFile::getArch() const { return Triple::wasm32; } |
| |
| SubtargetFeatures WasmObjectFile::getFeatures() const { |
| return SubtargetFeatures(); |
| } |
| |
| bool WasmObjectFile::isRelocatableObject() const { return false; } |
| |
| const wasm::WasmSection * |
| WasmObjectFile::getWasmSection(const SectionRef &Section) const { |
| return &Sections[Section.getRawDataRefImpl().d.a]; |
| } |
| |
| } // end namespace object |
| } // end namespace llvm |