Upstream version 11.39.266.0
[platform/framework/web/crosswalk.git] / src / native_client / src / trusted / validator / x86 / ncinstbuffer_inl.c
1 /*
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.
5  */
6
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
10  * 'Inline' suffix:
11  *
12  *   NCRemainingMemoryAdvance
13  *   NCRemainingMemoryReset
14  *   NCRemainingMemoryLookahead
15  *   NCRemainingMemoryRead
16  *   NCInstBytesPeek
17  *   NCInstByte
18  *   NCInstBytesRead
19  *   NCInstBytesReadBytes
20  *   NCInstBytesReset
21  *   NCInstBytesInit
22  *   NCInstBytesByte
23  *
24  * See ncinstbuffer.h for comments on how to use the corresponding inline
25  * functions.
26  */
27
28 #ifndef NATIVE_CLIENT_SRC_TRUSTED_VALIDATOR_X86_NCINSTBUFFER_INL_C__
29 #define NATIVE_CLIENT_SRC_TRUSTED_VALIDATOR_X86_NCINSTBUFFER_INL_C__
30
31 #include "native_client/src/trusted/validator/x86/ncinstbuffer.h"
32
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
37  * bytes.
38  *
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.
46  *
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.
49  *
50  * To debug this problem, set the flag NCBUF_CLEAR_CACHE to 0.
51  *
52  * TODO(karl) Fix the parser/printer so that NCBUF_CLEAR_CACHE can be set to 0.
53  */
54 #define NCBUF_CLEAR_CACHE 1
55
56 /* Defines the number of bytes in the buffer. */
57 #if NCBUF_CLEAR_CACHE
58 #define NCBUF_BYTES_LENGTH(bytes) MAX_INST_LENGTH
59 #else
60 #define NCBUF_BYTES_LENGTH(bytes) (bytes)->length
61 #endif
62
63 /* The constant to return if memory overflow occurs. */
64 # define NC_MEMORY_OVERFLOW 0
65
66 /* Returns the next byte in memory, or 0x00 if there are no more
67  * bytes in memory.
68  */
69 static INLINE uint8_t NCRemainingMemoryPeekInline(NCRemainingMemory* memory) {
70   return (memory->cur_pos >= memory->mlimit)
71       ? NC_MEMORY_OVERFLOW : *(memory->cur_pos);
72 }
73
74 /* Starts a new instruction at the current position in the memory
75  * segment.
76  */
77 static INLINE void NCRemainingMemoryAdvanceInline(NCRemainingMemory* memory) {
78   memory->mpc = memory->cur_pos;
79   memory->read_length = 0;
80   memory->overflow_count = 0;
81 }
82
83 /* Moves back to the beginning of the current instruction in
84  * the memory segment.
85  */
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;
91 }
92
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.
95  */
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];
100   } else {
101     return NC_MEMORY_OVERFLOW;
102   }
103 }
104
105 /* Reads and returns the next byte in the memory segment. Returns 0x00 if at
106  * the end of the memory segment.
107  */
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);
114     }
115     memory->overflow_count++;
116   } else {
117     memory->read_length++;
118     memory->cur_pos++;
119     memory->next_byte = NCRemainingMemoryPeekInline(memory);
120   }
121   return byte;
122 }
123
124 /* Peek ahead and return the nth (zero based) byte from the current position
125  * in the sequence of bytes being parsed.
126  */
127 static INLINE uint8_t NCInstBytesPeekInline(NCInstBytes* bytes, ssize_t n) {
128   return NCRemainingMemoryLookaheadInline(bytes->memory, n);
129 }
130
131 /* Peek at the nth character in the sequence of bytes being parsed (independent
132  * of the current position).
133  */
134 static INLINE uint8_t NCInstByteInline(NCInstBytes* bytes, ssize_t n) {
135   if (n < bytes->length)  {
136     return bytes->byte[n];
137   } else {
138     return NCRemainingMemoryLookaheadInline(bytes->memory, n - bytes->length);
139   }
140 }
141
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
145  * memory.
146  */
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;
151   } else {
152     bytes->memory->error_fn(NCInstBufferOverflow, bytes->memory);
153   }
154   return byte;
155 }
156
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
159  * memory.
160  */
161 static INLINE void NCInstBytesReadBytesInline(ssize_t n, NCInstBytes* bytes) {
162   ssize_t i;
163   for (i = 0; i < n; ++i) {
164     NCInstBytesReadInline(bytes);
165   }
166 }
167
168 /* Resets bytes back to the beginning of the current instruction. */
169 static INLINE void NCInstBytesResetInline(NCInstBytes* buffer) {
170 #if NCBUF_CLEAR_CACHE
171   int i;
172   for (i = 0; i < MAX_INST_LENGTH; ++i) {
173     buffer->byte[i] = 0;
174   }
175 #endif
176   NCRemainingMemoryResetInline(buffer->memory);
177   buffer->length = 0;
178 }
179
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
185  * memory.
186  */
187 static INLINE void NCInstBytesInitInline(NCInstBytes* buffer) {
188 #if NCBUF_CLEAR_CACHE
189   int i;
190   for (i = 0; i < MAX_INST_LENGTH; ++i) {
191     buffer->byte[i] = 0;
192   }
193 #endif
194   NCRemainingMemoryAdvanceInline(buffer->memory);
195   buffer->length = 0;
196 }
197
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];
203   } else {
204     ptr->bytes->memory->error_fn(NCInstBufferOverflow, ptr->bytes->memory);
205     return 0;
206   }
207 }
208
209 #endif  /* NATIVE_CLIENT_SRC_TRUSTED_VALIDATOR_X86_NCINSTBUFFER_INL_C__ */