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
14namespace v8 {
15namespace internal {
16namespace 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.
29class 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