1 //===- WasmObjectFile.cpp - Wasm object file implementation ---------------===// 2 // 3 // The LLVM Compiler Infrastructure 4 // 5 // This file is distributed under the University of Illinois Open Source 6 // License. See LICENSE.TXT for details. 7 // 8 //===----------------------------------------------------------------------===// 9 10 #include "llvm/ADT/ArrayRef.h" 11 #include "llvm/ADT/STLExtras.h" 12 #include "llvm/ADT/StringRef.h" 13 #include "llvm/ADT/Triple.h" 14 #include "llvm/Object/Binary.h" 15 #include "llvm/Object/Error.h" 16 #include "llvm/Object/ObjectFile.h" 17 #include "llvm/Object/SymbolicFile.h" 18 #include "llvm/Object/Wasm.h" 19 #include "llvm/Support/Endian.h" 20 #include "llvm/Support/Error.h" 21 #include "llvm/Support/ErrorHandling.h" 22 #include "llvm/Support/LEB128.h" 23 #include "llvm/Support/Wasm.h" 24 #include <algorithm> 25 #include <cstdint> 26 #include <system_error> 27 28 using namespace llvm; 29 using namespace object; 30 31 Expected<std::unique_ptr<WasmObjectFile>> 32 ObjectFile::createWasmObjectFile(MemoryBufferRef Buffer) { 33 Error Err = Error::success(); 34 auto ObjectFile = llvm::make_unique<WasmObjectFile>(Buffer, Err); 35 if (Err) 36 return std::move(Err); 37 38 return std::move(ObjectFile); 39 } 40 41 static uint32_t readUint32(const uint8_t *&Ptr) { 42 uint32_t Result = support::endian::read32le(Ptr); 43 Ptr += sizeof(Result); 44 return Result; 45 } 46 47 static uint64_t readULEB128(const uint8_t *&Ptr) { 48 unsigned Count; 49 uint64_t Result = decodeULEB128(Ptr, &Count); 50 Ptr += Count; 51 return Result; 52 } 53 54 static StringRef readString(const uint8_t *&Ptr) { 55 uint32_t StringLen = readULEB128(Ptr); 56 StringRef Return = StringRef(reinterpret_cast<const char *>(Ptr), StringLen); 57 Ptr += StringLen; 58 return Return; 59 } 60 61 static Error readSection(wasm::WasmSection &Section, const uint8_t *&Ptr, 62 const uint8_t *Start) { 63 // TODO(sbc): Avoid reading past EOF in the case of malformed files. 64 Section.Offset = Ptr - Start; 65 Section.Type = readULEB128(Ptr); 66 uint32_t Size = readULEB128(Ptr); 67 if (Size == 0) 68 return make_error<StringError>("Zero length section", 69 object_error::parse_failed); 70 Section.Content = ArrayRef<uint8_t>(Ptr, Size); 71 Ptr += Size; 72 return Error::success(); 73 } 74 75 WasmObjectFile::WasmObjectFile(MemoryBufferRef Buffer, Error &Err) 76 : ObjectFile(Binary::ID_Wasm, Buffer) { 77 ErrorAsOutParameter ErrAsOutParam(&Err); 78 Header.Magic = getData().substr(0, 4); 79 if (Header.Magic != StringRef("\0asm", 4)) { 80 Err = make_error<StringError>("Bad magic number", 81 object_error::parse_failed); 82 return; 83 } 84 const uint8_t *Ptr = getPtr(4); 85 Header.Version = readUint32(Ptr); 86 if (Header.Version != wasm::WasmVersion) { 87 Err = make_error<StringError>("Bad version number", 88 object_error::parse_failed); 89 return; 90 } 91 92 const uint8_t *Eof = getPtr(getData().size()); 93 wasm::WasmSection Sec; 94 while (Ptr < Eof) { 95 if ((Err = readSection(Sec, Ptr, getPtr(0)))) 96 return; 97 if (Sec.Type == wasm::WASM_SEC_CUSTOM) { 98 if ((Err = 99 parseCustomSection(Sec, Sec.Content.data(), Sec.Content.size()))) 100 return; 101 } 102 Sections.push_back(Sec); 103 } 104 } 105 106 Error WasmObjectFile::parseCustomSection(wasm::WasmSection &Sec, 107 const uint8_t *Ptr, size_t Length) { 108 Sec.Name = readString(Ptr); 109 return Error::success(); 110 } 111 112 const uint8_t *WasmObjectFile::getPtr(size_t Offset) const { 113 return reinterpret_cast<const uint8_t *>(getData().substr(Offset, 1).data()); 114 } 115 116 const wasm::WasmObjectHeader &WasmObjectFile::getHeader() const { 117 return Header; 118 } 119 120 void WasmObjectFile::moveSymbolNext(DataRefImpl &Symb) const { 121 llvm_unreachable("not yet implemented"); 122 } 123 124 std::error_code WasmObjectFile::printSymbolName(raw_ostream &OS, 125 DataRefImpl Symb) const { 126 llvm_unreachable("not yet implemented"); 127 return object_error::invalid_symbol_index; 128 } 129 130 uint32_t WasmObjectFile::getSymbolFlags(DataRefImpl Symb) const { 131 llvm_unreachable("not yet implemented"); 132 return 0; 133 } 134 135 basic_symbol_iterator WasmObjectFile::symbol_begin() const { 136 return BasicSymbolRef(DataRefImpl(), this); 137 } 138 139 basic_symbol_iterator WasmObjectFile::symbol_end() const { 140 return BasicSymbolRef(DataRefImpl(), this); 141 } 142 143 Expected<StringRef> WasmObjectFile::getSymbolName(DataRefImpl Symb) const { 144 llvm_unreachable("not yet implemented"); 145 return errorCodeToError(object_error::invalid_symbol_index); 146 } 147 148 Expected<uint64_t> WasmObjectFile::getSymbolAddress(DataRefImpl Symb) const { 149 llvm_unreachable("not yet implemented"); 150 return errorCodeToError(object_error::invalid_symbol_index); 151 } 152 153 uint64_t WasmObjectFile::getSymbolValueImpl(DataRefImpl Symb) const { 154 llvm_unreachable("not yet implemented"); 155 return 0; 156 } 157 158 uint32_t WasmObjectFile::getSymbolAlignment(DataRefImpl Symb) const { 159 llvm_unreachable("not yet implemented"); 160 return 0; 161 } 162 163 uint64_t WasmObjectFile::getCommonSymbolSizeImpl(DataRefImpl Symb) const { 164 llvm_unreachable("not yet implemented"); 165 return 0; 166 } 167 168 Expected<SymbolRef::Type> 169 WasmObjectFile::getSymbolType(DataRefImpl Symb) const { 170 llvm_unreachable("not yet implemented"); 171 return errorCodeToError(object_error::invalid_symbol_index); 172 } 173 174 Expected<section_iterator> 175 WasmObjectFile::getSymbolSection(DataRefImpl Symb) const { 176 llvm_unreachable("not yet implemented"); 177 return errorCodeToError(object_error::invalid_symbol_index); 178 } 179 180 void WasmObjectFile::moveSectionNext(DataRefImpl &Sec) const { Sec.d.a++; } 181 182 std::error_code WasmObjectFile::getSectionName(DataRefImpl Sec, 183 StringRef &Res) const { 184 const wasm::WasmSection &S = Sections[Sec.d.a]; 185 #define ECase(X) \ 186 case wasm::WASM_SEC_##X: \ 187 Res = #X; \ 188 break 189 switch (S.Type) { 190 ECase(TYPE); 191 ECase(IMPORT); 192 ECase(FUNCTION); 193 ECase(TABLE); 194 ECase(MEMORY); 195 ECase(GLOBAL); 196 ECase(EXPORT); 197 ECase(START); 198 ECase(ELEM); 199 ECase(CODE); 200 ECase(DATA); 201 case wasm::WASM_SEC_CUSTOM: 202 Res = S.Name; 203 break; 204 default: 205 return object_error::invalid_section_index; 206 } 207 #undef ECase 208 return std::error_code(); 209 } 210 211 uint64_t WasmObjectFile::getSectionAddress(DataRefImpl Sec) const { return 0; } 212 213 uint64_t WasmObjectFile::getSectionSize(DataRefImpl Sec) const { 214 const wasm::WasmSection &S = Sections[Sec.d.a]; 215 return S.Content.size(); 216 } 217 218 std::error_code WasmObjectFile::getSectionContents(DataRefImpl Sec, 219 StringRef &Res) const { 220 const wasm::WasmSection &S = Sections[Sec.d.a]; 221 // This will never fail since wasm sections can never be empty (user-sections 222 // must have a name and non-user sections each have a defined structure). 223 Res = StringRef(reinterpret_cast<const char *>(S.Content.data()), 224 S.Content.size()); 225 return std::error_code(); 226 } 227 228 uint64_t WasmObjectFile::getSectionAlignment(DataRefImpl Sec) const { 229 return 1; 230 } 231 232 bool WasmObjectFile::isSectionCompressed(DataRefImpl Sec) const { 233 return false; 234 } 235 236 bool WasmObjectFile::isSectionText(DataRefImpl Sec) const { 237 const wasm::WasmSection &S = Sections[Sec.d.a]; 238 return S.Type == wasm::WASM_SEC_CODE; 239 } 240 241 bool WasmObjectFile::isSectionData(DataRefImpl Sec) const { 242 const wasm::WasmSection &S = Sections[Sec.d.a]; 243 return S.Type == wasm::WASM_SEC_DATA; 244 } 245 246 bool WasmObjectFile::isSectionBSS(DataRefImpl Sec) const { return false; } 247 248 bool WasmObjectFile::isSectionVirtual(DataRefImpl Sec) const { return false; } 249 250 bool WasmObjectFile::isSectionBitcode(DataRefImpl Sec) const { return false; } 251 252 relocation_iterator WasmObjectFile::section_rel_begin(DataRefImpl Sec) const { 253 llvm_unreachable("not yet implemented"); 254 RelocationRef Rel; 255 return relocation_iterator(Rel); 256 } 257 258 relocation_iterator WasmObjectFile::section_rel_end(DataRefImpl Sec) const { 259 llvm_unreachable("not yet implemented"); 260 RelocationRef Rel; 261 return relocation_iterator(Rel); 262 } 263 264 section_iterator WasmObjectFile::getRelocatedSection(DataRefImpl Sec) const { 265 llvm_unreachable("not yet implemented"); 266 SectionRef Ref; 267 return section_iterator(Ref); 268 } 269 270 void WasmObjectFile::moveRelocationNext(DataRefImpl &Rel) const { 271 llvm_unreachable("not yet implemented"); 272 } 273 274 uint64_t WasmObjectFile::getRelocationOffset(DataRefImpl Rel) const { 275 llvm_unreachable("not yet implemented"); 276 return 0; 277 } 278 279 symbol_iterator WasmObjectFile::getRelocationSymbol(DataRefImpl Rel) const { 280 llvm_unreachable("not yet implemented"); 281 SymbolRef Ref; 282 return symbol_iterator(Ref); 283 } 284 285 uint64_t WasmObjectFile::getRelocationType(DataRefImpl Rel) const { 286 llvm_unreachable("not yet implemented"); 287 return 0; 288 } 289 290 void WasmObjectFile::getRelocationTypeName( 291 DataRefImpl Rel, SmallVectorImpl<char> &Result) const { 292 llvm_unreachable("not yet implemented"); 293 } 294 295 section_iterator WasmObjectFile::section_begin() const { 296 DataRefImpl Ref; 297 Ref.d.a = 0; 298 return section_iterator(SectionRef(Ref, this)); 299 } 300 301 section_iterator WasmObjectFile::section_end() const { 302 DataRefImpl Ref; 303 Ref.d.a = Sections.size(); 304 return section_iterator(SectionRef(Ref, this)); 305 } 306 307 uint8_t WasmObjectFile::getBytesInAddress() const { return 4; } 308 309 StringRef WasmObjectFile::getFileFormatName() const { return "WASM"; } 310 311 unsigned WasmObjectFile::getArch() const { return Triple::wasm32; } 312 313 SubtargetFeatures WasmObjectFile::getFeatures() const { 314 return SubtargetFeatures(); 315 } 316 317 bool WasmObjectFile::isRelocatableObject() const { return false; } 318 319 const wasm::WasmSection * 320 WasmObjectFile::getWasmSection(const SectionRef &Section) const { 321 return &Sections[Section.getRawDataRefImpl().d.a]; 322 } 323