1*44d95122SEugene Zelenko //===- WasmObjectFile.cpp - Wasm object file implementation ---------------===//
22c6f75ddSDerek Schuff //
32c6f75ddSDerek Schuff //                     The LLVM Compiler Infrastructure
42c6f75ddSDerek Schuff //
52c6f75ddSDerek Schuff // This file is distributed under the University of Illinois Open Source
62c6f75ddSDerek Schuff // License. See LICENSE.TXT for details.
72c6f75ddSDerek Schuff //
82c6f75ddSDerek Schuff //===----------------------------------------------------------------------===//
92c6f75ddSDerek Schuff 
10*44d95122SEugene Zelenko #include "llvm/ADT/ArrayRef.h"
11*44d95122SEugene Zelenko #include "llvm/ADT/STLExtras.h"
12*44d95122SEugene Zelenko #include "llvm/ADT/StringRef.h"
13*44d95122SEugene Zelenko #include "llvm/ADT/Triple.h"
14*44d95122SEugene Zelenko #include "llvm/Object/Binary.h"
15*44d95122SEugene Zelenko #include "llvm/Object/Error.h"
16*44d95122SEugene Zelenko #include "llvm/Object/ObjectFile.h"
17*44d95122SEugene Zelenko #include "llvm/Object/SymbolicFile.h"
182c6f75ddSDerek Schuff #include "llvm/Object/Wasm.h"
192c6f75ddSDerek Schuff #include "llvm/Support/Endian.h"
20*44d95122SEugene Zelenko #include "llvm/Support/Error.h"
21*44d95122SEugene Zelenko #include "llvm/Support/ErrorHandling.h"
222c6f75ddSDerek Schuff #include "llvm/Support/LEB128.h"
23*44d95122SEugene Zelenko #include "llvm/Support/Wasm.h"
24*44d95122SEugene Zelenko #include <algorithm>
25*44d95122SEugene Zelenko #include <cstdint>
26*44d95122SEugene Zelenko #include <system_error>
272c6f75ddSDerek Schuff 
28*44d95122SEugene Zelenko using namespace llvm;
29*44d95122SEugene Zelenko using namespace object;
302c6f75ddSDerek Schuff 
312c6f75ddSDerek Schuff Expected<std::unique_ptr<WasmObjectFile>>
322c6f75ddSDerek Schuff ObjectFile::createWasmObjectFile(MemoryBufferRef Buffer) {
332c6f75ddSDerek Schuff   Error Err = Error::success();
342c6f75ddSDerek Schuff   auto ObjectFile = llvm::make_unique<WasmObjectFile>(Buffer, Err);
352c6f75ddSDerek Schuff   if (Err)
362c6f75ddSDerek Schuff     return std::move(Err);
372c6f75ddSDerek Schuff 
382c6f75ddSDerek Schuff   return std::move(ObjectFile);
392c6f75ddSDerek Schuff }
402c6f75ddSDerek Schuff 
41*44d95122SEugene Zelenko static uint32_t readUint32(const uint8_t *&Ptr) {
422c6f75ddSDerek Schuff   uint32_t Result = support::endian::read32le(Ptr);
432c6f75ddSDerek Schuff   Ptr += sizeof(Result);
442c6f75ddSDerek Schuff   return Result;
452c6f75ddSDerek Schuff }
462c6f75ddSDerek Schuff 
47*44d95122SEugene Zelenko static uint64_t readULEB128(const uint8_t *&Ptr) {
482c6f75ddSDerek Schuff   unsigned Count;
492c6f75ddSDerek Schuff   uint64_t Result = decodeULEB128(Ptr, &Count);
502c6f75ddSDerek Schuff   Ptr += Count;
512c6f75ddSDerek Schuff   return Result;
522c6f75ddSDerek Schuff }
532c6f75ddSDerek Schuff 
54*44d95122SEugene Zelenko static StringRef readString(const uint8_t *&Ptr) {
552c6f75ddSDerek Schuff   uint32_t StringLen = readULEB128(Ptr);
562c6f75ddSDerek Schuff   StringRef Return = StringRef(reinterpret_cast<const char *>(Ptr), StringLen);
572c6f75ddSDerek Schuff   Ptr += StringLen;
582c6f75ddSDerek Schuff   return Return;
592c6f75ddSDerek Schuff }
602c6f75ddSDerek Schuff 
61*44d95122SEugene Zelenko static Error readSection(wasm::WasmSection &Section, const uint8_t *&Ptr,
622c6f75ddSDerek Schuff                          const uint8_t *Start) {
632c6f75ddSDerek Schuff   // TODO(sbc): Avoid reading past EOF in the case of malformed files.
642c6f75ddSDerek Schuff   Section.Offset = Ptr - Start;
652c6f75ddSDerek Schuff   Section.Type = readULEB128(Ptr);
662c6f75ddSDerek Schuff   uint32_t Size = readULEB128(Ptr);
672c6f75ddSDerek Schuff   if (Size == 0)
682c6f75ddSDerek Schuff     return make_error<StringError>("Zero length section",
692c6f75ddSDerek Schuff                                    object_error::parse_failed);
702c6f75ddSDerek Schuff   Section.Content = ArrayRef<uint8_t>(Ptr, Size);
712c6f75ddSDerek Schuff   Ptr += Size;
722c6f75ddSDerek Schuff   return Error::success();
732c6f75ddSDerek Schuff }
742c6f75ddSDerek Schuff 
752c6f75ddSDerek Schuff WasmObjectFile::WasmObjectFile(MemoryBufferRef Buffer, Error &Err)
762c6f75ddSDerek Schuff     : ObjectFile(Binary::ID_Wasm, Buffer) {
772c6f75ddSDerek Schuff   ErrorAsOutParameter ErrAsOutParam(&Err);
782c6f75ddSDerek Schuff   Header.Magic = getData().substr(0, 4);
792c6f75ddSDerek Schuff   if (Header.Magic != StringRef("\0asm", 4)) {
802c6f75ddSDerek Schuff     Err = make_error<StringError>("Bad magic number",
812c6f75ddSDerek Schuff                                   object_error::parse_failed);
822c6f75ddSDerek Schuff     return;
832c6f75ddSDerek Schuff   }
842c6f75ddSDerek Schuff   const uint8_t *Ptr = getPtr(4);
852c6f75ddSDerek Schuff   Header.Version = readUint32(Ptr);
862c6f75ddSDerek Schuff   if (Header.Version != wasm::WasmVersion) {
872c6f75ddSDerek Schuff     Err = make_error<StringError>("Bad version number",
882c6f75ddSDerek Schuff                                   object_error::parse_failed);
892c6f75ddSDerek Schuff     return;
902c6f75ddSDerek Schuff   }
912c6f75ddSDerek Schuff 
922c6f75ddSDerek Schuff   const uint8_t *Eof = getPtr(getData().size());
932c6f75ddSDerek Schuff   wasm::WasmSection Sec;
942c6f75ddSDerek Schuff   while (Ptr < Eof) {
952c6f75ddSDerek Schuff     if ((Err = readSection(Sec, Ptr, getPtr(0))))
962c6f75ddSDerek Schuff       return;
976d76b7b4SDerek Schuff     if (Sec.Type == wasm::WASM_SEC_CUSTOM) {
986d76b7b4SDerek Schuff       if ((Err =
996d76b7b4SDerek Schuff                parseCustomSection(Sec, Sec.Content.data(), Sec.Content.size())))
1002c6f75ddSDerek Schuff         return;
1012c6f75ddSDerek Schuff     }
1022c6f75ddSDerek Schuff     Sections.push_back(Sec);
1032c6f75ddSDerek Schuff   }
1042c6f75ddSDerek Schuff }
1052c6f75ddSDerek Schuff 
1066d76b7b4SDerek Schuff Error WasmObjectFile::parseCustomSection(wasm::WasmSection &Sec,
1072c6f75ddSDerek Schuff                                          const uint8_t *Ptr, size_t Length) {
1082c6f75ddSDerek Schuff   Sec.Name = readString(Ptr);
1092c6f75ddSDerek Schuff   return Error::success();
1102c6f75ddSDerek Schuff }
1112c6f75ddSDerek Schuff 
1122c6f75ddSDerek Schuff const uint8_t *WasmObjectFile::getPtr(size_t Offset) const {
1132c6f75ddSDerek Schuff   return reinterpret_cast<const uint8_t *>(getData().substr(Offset, 1).data());
1142c6f75ddSDerek Schuff }
1152c6f75ddSDerek Schuff 
1162c6f75ddSDerek Schuff const wasm::WasmObjectHeader &WasmObjectFile::getHeader() const {
1172c6f75ddSDerek Schuff   return Header;
1182c6f75ddSDerek Schuff }
1192c6f75ddSDerek Schuff 
1202c6f75ddSDerek Schuff void WasmObjectFile::moveSymbolNext(DataRefImpl &Symb) const {
1212c6f75ddSDerek Schuff   llvm_unreachable("not yet implemented");
1222c6f75ddSDerek Schuff }
1232c6f75ddSDerek Schuff 
1242c6f75ddSDerek Schuff std::error_code WasmObjectFile::printSymbolName(raw_ostream &OS,
1252c6f75ddSDerek Schuff                                                 DataRefImpl Symb) const {
1262c6f75ddSDerek Schuff   llvm_unreachable("not yet implemented");
1272c6f75ddSDerek Schuff   return object_error::invalid_symbol_index;
1282c6f75ddSDerek Schuff }
1292c6f75ddSDerek Schuff 
1302c6f75ddSDerek Schuff uint32_t WasmObjectFile::getSymbolFlags(DataRefImpl Symb) const {
1312c6f75ddSDerek Schuff   llvm_unreachable("not yet implemented");
1322c6f75ddSDerek Schuff   return 0;
1332c6f75ddSDerek Schuff }
1342c6f75ddSDerek Schuff 
1352c6f75ddSDerek Schuff basic_symbol_iterator WasmObjectFile::symbol_begin() const {
1362c6f75ddSDerek Schuff   return BasicSymbolRef(DataRefImpl(), this);
1372c6f75ddSDerek Schuff }
1382c6f75ddSDerek Schuff 
1392c6f75ddSDerek Schuff basic_symbol_iterator WasmObjectFile::symbol_end() const {
1402c6f75ddSDerek Schuff   return BasicSymbolRef(DataRefImpl(), this);
1412c6f75ddSDerek Schuff }
1422c6f75ddSDerek Schuff 
1432c6f75ddSDerek Schuff Expected<StringRef> WasmObjectFile::getSymbolName(DataRefImpl Symb) const {
1442c6f75ddSDerek Schuff   llvm_unreachable("not yet implemented");
1452c6f75ddSDerek Schuff   return errorCodeToError(object_error::invalid_symbol_index);
1462c6f75ddSDerek Schuff }
1472c6f75ddSDerek Schuff 
1482c6f75ddSDerek Schuff Expected<uint64_t> WasmObjectFile::getSymbolAddress(DataRefImpl Symb) const {
1492c6f75ddSDerek Schuff   llvm_unreachable("not yet implemented");
1502c6f75ddSDerek Schuff   return errorCodeToError(object_error::invalid_symbol_index);
1512c6f75ddSDerek Schuff }
1522c6f75ddSDerek Schuff 
1532c6f75ddSDerek Schuff uint64_t WasmObjectFile::getSymbolValueImpl(DataRefImpl Symb) const {
1542c6f75ddSDerek Schuff   llvm_unreachable("not yet implemented");
1552c6f75ddSDerek Schuff   return 0;
1562c6f75ddSDerek Schuff }
1572c6f75ddSDerek Schuff 
1582c6f75ddSDerek Schuff uint32_t WasmObjectFile::getSymbolAlignment(DataRefImpl Symb) const {
1592c6f75ddSDerek Schuff   llvm_unreachable("not yet implemented");
1602c6f75ddSDerek Schuff   return 0;
1612c6f75ddSDerek Schuff }
1622c6f75ddSDerek Schuff 
1632c6f75ddSDerek Schuff uint64_t WasmObjectFile::getCommonSymbolSizeImpl(DataRefImpl Symb) const {
1642c6f75ddSDerek Schuff   llvm_unreachable("not yet implemented");
1652c6f75ddSDerek Schuff   return 0;
1662c6f75ddSDerek Schuff }
1672c6f75ddSDerek Schuff 
1682c6f75ddSDerek Schuff Expected<SymbolRef::Type>
1692c6f75ddSDerek Schuff WasmObjectFile::getSymbolType(DataRefImpl Symb) const {
1702c6f75ddSDerek Schuff   llvm_unreachable("not yet implemented");
1712c6f75ddSDerek Schuff   return errorCodeToError(object_error::invalid_symbol_index);
1722c6f75ddSDerek Schuff }
1732c6f75ddSDerek Schuff 
1742c6f75ddSDerek Schuff Expected<section_iterator>
1752c6f75ddSDerek Schuff WasmObjectFile::getSymbolSection(DataRefImpl Symb) const {
1762c6f75ddSDerek Schuff   llvm_unreachable("not yet implemented");
1772c6f75ddSDerek Schuff   return errorCodeToError(object_error::invalid_symbol_index);
1782c6f75ddSDerek Schuff }
1792c6f75ddSDerek Schuff 
1802c6f75ddSDerek Schuff void WasmObjectFile::moveSectionNext(DataRefImpl &Sec) const { Sec.d.a++; }
1812c6f75ddSDerek Schuff 
1822c6f75ddSDerek Schuff std::error_code WasmObjectFile::getSectionName(DataRefImpl Sec,
1832c6f75ddSDerek Schuff                                                StringRef &Res) const {
1842c6f75ddSDerek Schuff   const wasm::WasmSection &S = Sections[Sec.d.a];
1852c6f75ddSDerek Schuff #define ECase(X)                                                               \
1862c6f75ddSDerek Schuff   case wasm::WASM_SEC_##X:                                                     \
1872c6f75ddSDerek Schuff     Res = #X;                                                                  \
1882c6f75ddSDerek Schuff     break
1892c6f75ddSDerek Schuff   switch (S.Type) {
1902c6f75ddSDerek Schuff     ECase(TYPE);
1912c6f75ddSDerek Schuff     ECase(IMPORT);
1922c6f75ddSDerek Schuff     ECase(FUNCTION);
1932c6f75ddSDerek Schuff     ECase(TABLE);
1942c6f75ddSDerek Schuff     ECase(MEMORY);
1952c6f75ddSDerek Schuff     ECase(GLOBAL);
1962c6f75ddSDerek Schuff     ECase(EXPORT);
1972c6f75ddSDerek Schuff     ECase(START);
1982c6f75ddSDerek Schuff     ECase(ELEM);
1992c6f75ddSDerek Schuff     ECase(CODE);
2002c6f75ddSDerek Schuff     ECase(DATA);
2016d76b7b4SDerek Schuff   case wasm::WASM_SEC_CUSTOM:
2022c6f75ddSDerek Schuff     Res = S.Name;
2032c6f75ddSDerek Schuff     break;
2042c6f75ddSDerek Schuff   default:
2052c6f75ddSDerek Schuff     return object_error::invalid_section_index;
2062c6f75ddSDerek Schuff   }
2072c6f75ddSDerek Schuff #undef ECase
2082c6f75ddSDerek Schuff   return std::error_code();
2092c6f75ddSDerek Schuff }
2102c6f75ddSDerek Schuff 
2112c6f75ddSDerek Schuff uint64_t WasmObjectFile::getSectionAddress(DataRefImpl Sec) const { return 0; }
2122c6f75ddSDerek Schuff 
2132c6f75ddSDerek Schuff uint64_t WasmObjectFile::getSectionSize(DataRefImpl Sec) const {
2142c6f75ddSDerek Schuff   const wasm::WasmSection &S = Sections[Sec.d.a];
2152c6f75ddSDerek Schuff   return S.Content.size();
2162c6f75ddSDerek Schuff }
2172c6f75ddSDerek Schuff 
2182c6f75ddSDerek Schuff std::error_code WasmObjectFile::getSectionContents(DataRefImpl Sec,
2192c6f75ddSDerek Schuff                                                    StringRef &Res) const {
2202c6f75ddSDerek Schuff   const wasm::WasmSection &S = Sections[Sec.d.a];
2212c6f75ddSDerek Schuff   // This will never fail since wasm sections can never be empty (user-sections
2222c6f75ddSDerek Schuff   // must have a name and non-user sections each have a defined structure).
2232c6f75ddSDerek Schuff   Res = StringRef(reinterpret_cast<const char *>(S.Content.data()),
2242c6f75ddSDerek Schuff                   S.Content.size());
2252c6f75ddSDerek Schuff   return std::error_code();
2262c6f75ddSDerek Schuff }
2272c6f75ddSDerek Schuff 
2282c6f75ddSDerek Schuff uint64_t WasmObjectFile::getSectionAlignment(DataRefImpl Sec) const {
2292c6f75ddSDerek Schuff   return 1;
2302c6f75ddSDerek Schuff }
2312c6f75ddSDerek Schuff 
2322c6f75ddSDerek Schuff bool WasmObjectFile::isSectionCompressed(DataRefImpl Sec) const {
2332c6f75ddSDerek Schuff   return false;
2342c6f75ddSDerek Schuff }
2352c6f75ddSDerek Schuff 
2362c6f75ddSDerek Schuff bool WasmObjectFile::isSectionText(DataRefImpl Sec) const {
2372c6f75ddSDerek Schuff   const wasm::WasmSection &S = Sections[Sec.d.a];
2382c6f75ddSDerek Schuff   return S.Type == wasm::WASM_SEC_CODE;
2392c6f75ddSDerek Schuff }
2402c6f75ddSDerek Schuff 
2412c6f75ddSDerek Schuff bool WasmObjectFile::isSectionData(DataRefImpl Sec) const {
2422c6f75ddSDerek Schuff   const wasm::WasmSection &S = Sections[Sec.d.a];
2432c6f75ddSDerek Schuff   return S.Type == wasm::WASM_SEC_DATA;
2442c6f75ddSDerek Schuff }
2452c6f75ddSDerek Schuff 
2462c6f75ddSDerek Schuff bool WasmObjectFile::isSectionBSS(DataRefImpl Sec) const { return false; }
2472c6f75ddSDerek Schuff 
2482c6f75ddSDerek Schuff bool WasmObjectFile::isSectionVirtual(DataRefImpl Sec) const { return false; }
2492c6f75ddSDerek Schuff 
2502c6f75ddSDerek Schuff bool WasmObjectFile::isSectionBitcode(DataRefImpl Sec) const { return false; }
2512c6f75ddSDerek Schuff 
2522c6f75ddSDerek Schuff relocation_iterator WasmObjectFile::section_rel_begin(DataRefImpl Sec) const {
2532c6f75ddSDerek Schuff   llvm_unreachable("not yet implemented");
2542c6f75ddSDerek Schuff   RelocationRef Rel;
2552c6f75ddSDerek Schuff   return relocation_iterator(Rel);
2562c6f75ddSDerek Schuff }
2572c6f75ddSDerek Schuff 
2582c6f75ddSDerek Schuff relocation_iterator WasmObjectFile::section_rel_end(DataRefImpl Sec) const {
2592c6f75ddSDerek Schuff   llvm_unreachable("not yet implemented");
2602c6f75ddSDerek Schuff   RelocationRef Rel;
2612c6f75ddSDerek Schuff   return relocation_iterator(Rel);
2622c6f75ddSDerek Schuff }
2632c6f75ddSDerek Schuff 
2642c6f75ddSDerek Schuff section_iterator WasmObjectFile::getRelocatedSection(DataRefImpl Sec) const {
2652c6f75ddSDerek Schuff   llvm_unreachable("not yet implemented");
2662c6f75ddSDerek Schuff   SectionRef Ref;
2672c6f75ddSDerek Schuff   return section_iterator(Ref);
2682c6f75ddSDerek Schuff }
2692c6f75ddSDerek Schuff 
2702c6f75ddSDerek Schuff void WasmObjectFile::moveRelocationNext(DataRefImpl &Rel) const {
2712c6f75ddSDerek Schuff   llvm_unreachable("not yet implemented");
2722c6f75ddSDerek Schuff }
2732c6f75ddSDerek Schuff 
2742c6f75ddSDerek Schuff uint64_t WasmObjectFile::getRelocationOffset(DataRefImpl Rel) const {
2752c6f75ddSDerek Schuff   llvm_unreachable("not yet implemented");
2762c6f75ddSDerek Schuff   return 0;
2772c6f75ddSDerek Schuff }
2782c6f75ddSDerek Schuff 
2792c6f75ddSDerek Schuff symbol_iterator WasmObjectFile::getRelocationSymbol(DataRefImpl Rel) const {
2802c6f75ddSDerek Schuff   llvm_unreachable("not yet implemented");
2812c6f75ddSDerek Schuff   SymbolRef Ref;
2822c6f75ddSDerek Schuff   return symbol_iterator(Ref);
2832c6f75ddSDerek Schuff }
2842c6f75ddSDerek Schuff 
2852c6f75ddSDerek Schuff uint64_t WasmObjectFile::getRelocationType(DataRefImpl Rel) const {
2862c6f75ddSDerek Schuff   llvm_unreachable("not yet implemented");
2872c6f75ddSDerek Schuff   return 0;
2882c6f75ddSDerek Schuff }
2892c6f75ddSDerek Schuff 
2902c6f75ddSDerek Schuff void WasmObjectFile::getRelocationTypeName(
2912c6f75ddSDerek Schuff     DataRefImpl Rel, SmallVectorImpl<char> &Result) const {
2922c6f75ddSDerek Schuff   llvm_unreachable("not yet implemented");
2932c6f75ddSDerek Schuff }
2942c6f75ddSDerek Schuff 
2952c6f75ddSDerek Schuff section_iterator WasmObjectFile::section_begin() const {
2962c6f75ddSDerek Schuff   DataRefImpl Ref;
2972c6f75ddSDerek Schuff   Ref.d.a = 0;
2982c6f75ddSDerek Schuff   return section_iterator(SectionRef(Ref, this));
2992c6f75ddSDerek Schuff }
3002c6f75ddSDerek Schuff 
3012c6f75ddSDerek Schuff section_iterator WasmObjectFile::section_end() const {
3022c6f75ddSDerek Schuff   DataRefImpl Ref;
3032c6f75ddSDerek Schuff   Ref.d.a = Sections.size();
3042c6f75ddSDerek Schuff   return section_iterator(SectionRef(Ref, this));
3052c6f75ddSDerek Schuff }
3062c6f75ddSDerek Schuff 
3072c6f75ddSDerek Schuff uint8_t WasmObjectFile::getBytesInAddress() const { return 4; }
3082c6f75ddSDerek Schuff 
3092c6f75ddSDerek Schuff StringRef WasmObjectFile::getFileFormatName() const { return "WASM"; }
3102c6f75ddSDerek Schuff 
3112c6f75ddSDerek Schuff unsigned WasmObjectFile::getArch() const { return Triple::wasm32; }
3122c6f75ddSDerek Schuff 
3132c6f75ddSDerek Schuff SubtargetFeatures WasmObjectFile::getFeatures() const {
3142c6f75ddSDerek Schuff   return SubtargetFeatures();
3152c6f75ddSDerek Schuff }
3162c6f75ddSDerek Schuff 
3172c6f75ddSDerek Schuff bool WasmObjectFile::isRelocatableObject() const { return false; }
3182c6f75ddSDerek Schuff 
3192c6f75ddSDerek Schuff const wasm::WasmSection *
3202c6f75ddSDerek Schuff WasmObjectFile::getWasmSection(const SectionRef &Section) const {
3212c6f75ddSDerek Schuff   return &Sections[Section.getRawDataRefImpl().d.a];
3222c6f75ddSDerek Schuff }
323