Home | History | Annotate | Download | only in wasm
      1 // Copyright 2015 the V8 project authors. All rights reserved.
      2 // Use of this source code is governed by a BSD-style license that can be
      3 // found in the LICENSE file.
      4 
      5 #ifndef V8_WASM_DECODER_H_
      6 #define V8_WASM_DECODER_H_
      7 
      8 #include "src/base/smart-pointers.h"
      9 #include "src/flags.h"
     10 #include "src/signature.h"
     11 #include "src/wasm/wasm-result.h"
     12 #include "src/zone-containers.h"
     13 
     14 namespace v8 {
     15 namespace internal {
     16 namespace wasm {
     17 
     18 #if DEBUG
     19 #define TRACE(...)                                    \
     20   do {                                                \
     21     if (FLAG_trace_wasm_decoder) PrintF(__VA_ARGS__); \
     22   } while (false)
     23 #else
     24 #define TRACE(...)
     25 #endif
     26 
     27 // A helper utility to decode bytes, integers, fields, varints, etc, from
     28 // a buffer of bytes.
     29 class Decoder {
     30  public:
     31   Decoder(const byte* start, const byte* end)
     32       : start_(start),
     33         pc_(start),
     34         limit_(end),
     35         error_pc_(nullptr),
     36         error_pt_(nullptr) {}
     37 
     38   virtual ~Decoder() {}
     39 
     40   // Reads a 8-bit unsigned integer (byte) and advances {pc_}.
     41   uint8_t u8(const char* name = nullptr) {
     42     TRACE("  +%d  %-20s: ", static_cast<int>(pc_ - start_),
     43           name ? name : "uint8_t");
     44     if (checkAvailable(1)) {
     45       byte val = *(pc_++);
     46       TRACE("%02x = %d\n", val, val);
     47       return val;
     48     } else {
     49       error("expected 1 byte, but fell off end");
     50       return traceOffEnd<uint8_t>();
     51     }
     52   }
     53 
     54   // Reads a 16-bit unsigned integer (little endian) and advances {pc_}.
     55   uint16_t u16(const char* name = nullptr) {
     56     TRACE("  +%d  %-20s: ", static_cast<int>(pc_ - start_),
     57           name ? name : "uint16_t");
     58     if (checkAvailable(2)) {
     59 #ifdef V8_TARGET_LITTLE_ENDIAN
     60       byte b0 = pc_[0];
     61       byte b1 = pc_[1];
     62 #else
     63       byte b1 = pc_[0];
     64       byte b0 = pc_[1];
     65 #endif
     66       uint16_t val = static_cast<uint16_t>(b1 << 8) | b0;
     67       TRACE("%02x %02x = %d\n", pc_[0], pc_[1], val);
     68       pc_ += 2;
     69       return val;
     70     } else {
     71       error("expected 2 bytes, but fell off end");
     72       return traceOffEnd<uint16_t>();
     73     }
     74   }
     75 
     76   // Reads a single 32-bit unsigned integer (little endian) and advances {pc_}.
     77   uint32_t u32(const char* name = nullptr) {
     78     TRACE("  +%d  %-20s: ", static_cast<int>(pc_ - start_),
     79           name ? name : "uint32_t");
     80     if (checkAvailable(4)) {
     81 #ifdef V8_TARGET_LITTLE_ENDIAN
     82       byte b0 = pc_[0];
     83       byte b1 = pc_[1];
     84       byte b2 = pc_[2];
     85       byte b3 = pc_[3];
     86 #else
     87       byte b3 = pc_[0];
     88       byte b2 = pc_[1];
     89       byte b1 = pc_[2];
     90       byte b0 = pc_[3];
     91 #endif
     92       uint32_t val = static_cast<uint32_t>(b3 << 24) |
     93                      static_cast<uint32_t>(b2 << 16) |
     94                      static_cast<uint32_t>(b1 << 8) | b0;
     95       TRACE("%02x %02x %02x %02x = %u\n", pc_[0], pc_[1], pc_[2], pc_[3], val);
     96       pc_ += 4;
     97       return val;
     98     } else {
     99       error("expected 4 bytes, but fell off end");
    100       return traceOffEnd<uint32_t>();
    101     }
    102   }
    103 
    104   // Reads a LEB128 variable-length 32-bit integer and advances {pc_}.
    105   uint32_t u32v(int* length, const char* name = nullptr) {
    106     TRACE("  +%d  %-20s: ", static_cast<int>(pc_ - start_),
    107           name ? name : "varint");
    108 
    109     if (!checkAvailable(1)) {
    110       error("expected at least 1 byte, but fell off end");
    111       return traceOffEnd<uint32_t>();
    112     }
    113 
    114     const byte* pos = pc_;
    115     const byte* end = pc_ + 5;
    116     if (end > limit_) end = limit_;
    117 
    118     uint32_t result = 0;
    119     int shift = 0;
    120     byte b = 0;
    121     while (pc_ < end) {
    122       b = *pc_++;
    123       TRACE("%02x ", b);
    124       result = result | ((b & 0x7F) << shift);
    125       if ((b & 0x80) == 0) break;
    126       shift += 7;
    127     }
    128 
    129     *length = static_cast<int>(pc_ - pos);
    130     if (pc_ == end && (b & 0x80)) {
    131       error(pc_ - 1, "varint too large");
    132     } else {
    133       TRACE("= %u\n", result);
    134     }
    135     return result;
    136   }
    137 
    138   // Check that at least {size} bytes exist between {pc_} and {limit_}.
    139   bool checkAvailable(int size) {
    140     if (pc_ < start_ || (pc_ + size) > limit_) {
    141       error(pc_, nullptr, "expected %d bytes, fell off end", size);
    142       return false;
    143     } else {
    144       return true;
    145     }
    146   }
    147 
    148   void error(const char* msg) { error(pc_, nullptr, msg); }
    149 
    150   void error(const byte* pc, const char* msg) { error(pc, nullptr, msg); }
    151 
    152   // Sets internal error state.
    153   void error(const byte* pc, const byte* pt, const char* format, ...) {
    154     if (ok()) {
    155 #if DEBUG
    156       if (FLAG_wasm_break_on_decoder_error) {
    157         base::OS::DebugBreak();
    158       }
    159 #endif
    160       const int kMaxErrorMsg = 256;
    161       char* buffer = new char[kMaxErrorMsg];
    162       va_list arguments;
    163       va_start(arguments, format);
    164       base::OS::VSNPrintF(buffer, kMaxErrorMsg - 1, format, arguments);
    165       va_end(arguments);
    166       error_msg_.Reset(buffer);
    167       error_pc_ = pc;
    168       error_pt_ = pt;
    169       onFirstError();
    170     }
    171   }
    172 
    173   // Behavior triggered on first error, overridden in subclasses.
    174   virtual void onFirstError() {}
    175 
    176   // Debugging helper to print bytes up to the end.
    177   template <typename T>
    178   T traceOffEnd() {
    179     T t = 0;
    180     for (const byte* ptr = pc_; ptr < limit_; ptr++) {
    181       TRACE("%02x ", *ptr);
    182     }
    183     TRACE("<end>\n");
    184     pc_ = limit_;
    185     return t;
    186   }
    187 
    188   // Converts the given value to a {Result}, copying the error if necessary.
    189   template <typename T>
    190   Result<T> toResult(T val) {
    191     Result<T> result;
    192     if (error_pc_) {
    193       result.error_code = kError;
    194       result.start = start_;
    195       result.error_pc = error_pc_;
    196       result.error_pt = error_pt_;
    197       result.error_msg = error_msg_;
    198       error_msg_.Reset(nullptr);
    199     } else {
    200       result.error_code = kSuccess;
    201     }
    202     result.val = val;
    203     return result;
    204   }
    205 
    206   // Resets the boundaries of this decoder.
    207   void Reset(const byte* start, const byte* end) {
    208     start_ = start;
    209     pc_ = start;
    210     limit_ = end;
    211     error_pc_ = nullptr;
    212     error_pt_ = nullptr;
    213     error_msg_.Reset(nullptr);
    214   }
    215 
    216   bool ok() const { return error_pc_ == nullptr; }
    217   bool failed() const { return error_pc_ != nullptr; }
    218 
    219  protected:
    220   const byte* start_;
    221   const byte* pc_;
    222   const byte* limit_;
    223   const byte* error_pc_;
    224   const byte* error_pt_;
    225   base::SmartArrayPointer<char> error_msg_;
    226 };
    227 
    228 #undef TRACE
    229 }  // namespace wasm
    230 }  // namespace internal
    231 }  // namespace v8
    232 
    233 #endif  // V8_WASM_DECODER_H_
    234