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 9 : static INLINE uint8_t NCRemainingMemoryPeekInline(NCRemainingMemory* memory) {
70 : return (memory->cur_pos >= memory->mlimit)
71 9 : ? NC_MEMORY_OVERFLOW : *(memory->cur_pos);
72 9 : }
73 :
74 : /* Starts a new instruction at the current position in the memory
75 : * segment.
76 : */
77 9 : static INLINE void NCRemainingMemoryAdvanceInline(NCRemainingMemory* memory) {
78 9 : memory->mpc = memory->cur_pos;
79 9 : memory->read_length = 0;
80 9 : memory->overflow_count = 0;
81 9 : }
82 :
83 : /* Moves back to the beginning of the current instruction in
84 : * the memory segment.
85 : */
86 5 : static INLINE void NCRemainingMemoryResetInline(NCRemainingMemory* memory) {
87 5 : memory->cur_pos = memory->mpc;
88 5 : memory->next_byte = NCRemainingMemoryPeekInline(memory);
89 5 : memory->read_length = 0;
90 5 : memory->overflow_count = 0;
91 5 : }
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 5 : NCRemainingMemory* memory, ssize_t n) {
98 5 : if ((memory->cur_pos + n) < memory->mlimit) {
99 5 : return memory->cur_pos[n];
100 : } else {
101 3 : return NC_MEMORY_OVERFLOW;
102 : }
103 5 : }
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 6 : static INLINE uint8_t NCRemainingMemoryReadInline(NCRemainingMemory* memory) {
109 6 : uint8_t byte = memory->next_byte;
110 6 : if (memory->cur_pos == memory->mlimit) {
111 : /* If reached, next_byte already set to 0 by last read. */
112 4 : if (0 == memory->overflow_count) {
113 4 : memory->error_fn(NCRemainingMemoryOverflow, memory);
114 : }
115 4 : memory->overflow_count++;
116 4 : } else {
117 6 : memory->read_length++;
118 6 : memory->cur_pos++;
119 6 : memory->next_byte = NCRemainingMemoryPeekInline(memory);
120 : }
121 6 : return byte;
122 6 : }
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 2 : static INLINE uint8_t NCInstBytesPeekInline(NCInstBytes* bytes, ssize_t n) {
128 2 : return NCRemainingMemoryLookaheadInline(bytes->memory, n);
129 2 : }
130 :
131 : /* Peek at the nth character in the sequence of bytes being parsed (independent
132 : * of the current position).
133 : */
134 1 : static INLINE uint8_t NCInstByteInline(NCInstBytes* bytes, ssize_t n) {
135 1 : if (n < bytes->length) {
136 1 : return bytes->byte[n];
137 : } else {
138 0 : return NCRemainingMemoryLookaheadInline(bytes->memory, n - bytes->length);
139 : }
140 1 : }
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 5 : static INLINE uint8_t NCInstBytesReadInline(NCInstBytes* bytes) {
148 5 : uint8_t byte = NCRemainingMemoryReadInline(bytes->memory);
149 5 : if (bytes->length < MAX_INST_LENGTH) {
150 5 : bytes->byte[bytes->length++] = byte;
151 5 : } else {
152 1 : bytes->memory->error_fn(NCInstBufferOverflow, bytes->memory);
153 : }
154 5 : return byte;
155 5 : }
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 4 : static INLINE void NCInstBytesReadBytesInline(ssize_t n, NCInstBytes* bytes) {
162 : ssize_t i;
163 4 : for (i = 0; i < n; ++i) {
164 4 : NCInstBytesReadInline(bytes);
165 4 : }
166 4 : }
167 :
168 : /* Resets bytes back to the beginning of the current instruction. */
169 3 : static INLINE void NCInstBytesResetInline(NCInstBytes* buffer) {
170 : #if NCBUF_CLEAR_CACHE
171 : int i;
172 3 : for (i = 0; i < MAX_INST_LENGTH; ++i) {
173 3 : buffer->byte[i] = 0;
174 3 : }
175 : #endif
176 3 : NCRemainingMemoryResetInline(buffer->memory);
177 3 : buffer->length = 0;
178 3 : }
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 4 : static INLINE void NCInstBytesInitInline(NCInstBytes* buffer) {
188 : #if NCBUF_CLEAR_CACHE
189 : int i;
190 4 : for (i = 0; i < MAX_INST_LENGTH; ++i) {
191 4 : buffer->byte[i] = 0;
192 4 : }
193 : #endif
194 4 : NCRemainingMemoryAdvanceInline(buffer->memory);
195 4 : buffer->length = 0;
196 4 : }
197 :
198 : /* Returns the indexed byte pointed to by the instruction buffer pointer. */
199 4 : static INLINE uint8_t NCInstBytesByteInline(const NCInstBytesPtr* ptr, int n) {
200 4 : int index = ptr->pos + n;
201 4 : if (index < NCBUF_BYTES_LENGTH(ptr->bytes)) {
202 4 : return ptr->bytes->byte[index];
203 : } else {
204 0 : ptr->bytes->memory->error_fn(NCInstBufferOverflow, ptr->bytes->memory);
205 0 : return 0;
206 : }
207 4 : }
208 :
209 : #endif /* NATIVE_CLIENT_SRC_TRUSTED_VALIDATOR_X86_NCINSTBUFFER_INL_C__ */
|