2 * Copyright (c) 2011 The Native Client Authors. All rights reserved.
3 * Use of this source code is governed by a BSD-style license that can be
4 * found in the LICENSE file.
7 /* ncinstbuffer-inl.h - Holds nline functions for commonly used (simple)
8 * functions in ncinstbuffer.h. Used to speed up code. Inlineed routines
9 * correspond to the following functions in ncinstbuffer.h, but with an
12 * NCRemainingMemoryAdvance
13 * NCRemainingMemoryReset
14 * NCRemainingMemoryLookahead
15 * NCRemainingMemoryRead
19 * NCInstBytesReadBytes
24 * See ncinstbuffer.h for comments on how to use the corresponding inline
28 #ifndef NATIVE_CLIENT_SRC_TRUSTED_VALIDATOR_X86_NCINSTBUFFER_INL_C__
29 #define NATIVE_CLIENT_SRC_TRUSTED_VALIDATOR_X86_NCINSTBUFFER_INL_C__
31 #include "native_client/src/trusted/validator/x86/ncinstbuffer.h"
33 /* Constant NCBUF_CLEAR_CACHE controls the behaviour of the buffer containing
34 * the sequence of parsed bytes. Turn it on (1) to fill unused bytes with the
35 * constant zero, and to allow access to all bytes in the sequence of parsed
36 * bytes. Turn it off (0) to force access to only include the actual parsed
39 * Note: Ideally, we would like to turn this feature off. However, the current
40 * instruction parser (in ncdecode.c) and corresponding printer (in
41 * ncdis_util.c) are problematic. The parser allows a partial match of
42 * an instruction, without verifying that ALL necessary bytes are there. The
43 * corresponding printer, assumes that only complete matches (during parsing)
44 * were performed. The result is that the code sometimes assumes that many
45 * more bytes were parsed than were actually parsed.
47 * To quickly fix the code so that it doesn't do illegal memory accesses, but
48 * has consistent behaviour, the flag is currently sets NCBUF_CLEAR_CACHE to 1.
50 * To debug this problem, set the flag NCBUF_CLEAR_CACHE to 0.
52 * TODO(karl) Fix the parser/printer so that NCBUF_CLEAR_CACHE can be set to 0.
54 #define NCBUF_CLEAR_CACHE 1
56 /* Defines the number of bytes in the buffer. */
58 #define NCBUF_BYTES_LENGTH(bytes) MAX_INST_LENGTH
60 #define NCBUF_BYTES_LENGTH(bytes) (bytes)->length
63 /* The constant to return if memory overflow occurs. */
64 # define NC_MEMORY_OVERFLOW 0
66 /* Returns the next byte in memory, or 0x00 if there are no more
69 static INLINE uint8_t NCRemainingMemoryPeekInline(NCRemainingMemory* memory) {
70 return (memory->cur_pos >= memory->mlimit)
71 ? NC_MEMORY_OVERFLOW : *(memory->cur_pos);
74 /* Starts a new instruction at the current position in the memory
77 static INLINE void NCRemainingMemoryAdvanceInline(NCRemainingMemory* memory) {
78 memory->mpc = memory->cur_pos;
79 memory->read_length = 0;
80 memory->overflow_count = 0;
83 /* Moves back to the beginning of the current instruction in
86 static INLINE void NCRemainingMemoryResetInline(NCRemainingMemory* memory) {
87 memory->cur_pos = memory->mpc;
88 memory->next_byte = NCRemainingMemoryPeekInline(memory);
89 memory->read_length = 0;
90 memory->overflow_count = 0;
93 /* Looks ahead N bytes into the memory, and returns the corresponding
94 * byte, or 0x00 if at the end of memory. i is zero-based.
96 static INLINE uint8_t NCRemainingMemoryLookaheadInline(
97 NCRemainingMemory* memory, ssize_t n) {
98 if ((memory->cur_pos + n) < memory->mlimit) {
99 return memory->cur_pos[n];
101 return NC_MEMORY_OVERFLOW;
105 /* Reads and returns the next byte in the memory segment. Returns 0x00 if at
106 * the end of the memory segment.
108 static INLINE uint8_t NCRemainingMemoryReadInline(NCRemainingMemory* memory) {
109 uint8_t byte = memory->next_byte;
110 if (memory->cur_pos == memory->mlimit) {
111 /* If reached, next_byte already set to 0 by last read. */
112 if (0 == memory->overflow_count) {
113 memory->error_fn(NCRemainingMemoryOverflow, memory);
115 memory->overflow_count++;
117 memory->read_length++;
119 memory->next_byte = NCRemainingMemoryPeekInline(memory);
124 /* Peek ahead and return the nth (zero based) byte from the current position
125 * in the sequence of bytes being parsed.
127 static INLINE uint8_t NCInstBytesPeekInline(NCInstBytes* bytes, ssize_t n) {
128 return NCRemainingMemoryLookaheadInline(bytes->memory, n);
131 /* Peek at the nth character in the sequence of bytes being parsed (independent
132 * of the current position).
134 static INLINE uint8_t NCInstByteInline(NCInstBytes* bytes, ssize_t n) {
135 if (n < bytes->length) {
136 return bytes->byte[n];
138 return NCRemainingMemoryLookaheadInline(bytes->memory, n - bytes->length);
142 /* Reads a byte from the memory segment and adds it to the instruction buffer.
143 * Returns the read byte.
144 * Note: Assumes that NCInstBytesInitMemory has already been called to associate
147 static INLINE uint8_t NCInstBytesReadInline(NCInstBytes* bytes) {
148 uint8_t byte = NCRemainingMemoryReadInline(bytes->memory);
149 if (bytes->length < MAX_INST_LENGTH) {
150 bytes->byte[bytes->length++] = byte;
152 bytes->memory->error_fn(NCInstBufferOverflow, bytes->memory);
157 /* Reads n bytes from the memory segment and adds it to the instruction buffer.
158 * Note: Assumes that NCInstBytesInitMemory has already been called to associate
161 static INLINE void NCInstBytesReadBytesInline(ssize_t n, NCInstBytes* bytes) {
163 for (i = 0; i < n; ++i) {
164 NCInstBytesReadInline(bytes);
168 /* Resets bytes back to the beginning of the current instruction. */
169 static INLINE void NCInstBytesResetInline(NCInstBytes* buffer) {
170 #if NCBUF_CLEAR_CACHE
172 for (i = 0; i < MAX_INST_LENGTH; ++i) {
176 NCRemainingMemoryResetInline(buffer->memory);
180 /* Initializes the instruction buffer as the empty buffer, and
181 * advances the memory segment so that one is beginning the
182 * parsing of the current instruction at the current position
183 * in the memory segment.
184 * Note: Assumes that NCInstBytesInitMemory has already been called to associate
187 static INLINE void NCInstBytesInitInline(NCInstBytes* buffer) {
188 #if NCBUF_CLEAR_CACHE
190 for (i = 0; i < MAX_INST_LENGTH; ++i) {
194 NCRemainingMemoryAdvanceInline(buffer->memory);
198 /* Returns the indexed byte pointed to by the instruction buffer pointer. */
199 static INLINE uint8_t NCInstBytesByteInline(const NCInstBytesPtr* ptr, int n) {
200 int index = ptr->pos + n;
201 if (index < NCBUF_BYTES_LENGTH(ptr->bytes)) {
202 return ptr->bytes->byte[index];
204 ptr->bytes->memory->error_fn(NCInstBufferOverflow, ptr->bytes->memory);
209 #endif /* NATIVE_CLIENT_SRC_TRUSTED_VALIDATOR_X86_NCINSTBUFFER_INL_C__ */