1 : /*
2 : * Copyright (c) 2012 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 : #include "native_client/src/trusted/validator/x86/decoder/ncop_exps.h"
8 :
9 : #include <stdio.h>
10 : #include <ctype.h>
11 : #include <string.h>
12 : #include <assert.h>
13 : #include <sys/stat.h>
14 :
15 : #include "native_client/src/include/portability.h"
16 : #include "native_client/src/shared/platform/nacl_log.h"
17 : #include "native_client/src/shared/utils/types.h"
18 : #include "native_client/src/trusted/validator/x86/decoder/gen/ncop_expr_node_flag_impl.h"
19 : #include "native_client/src/trusted/validator/x86/decoder/gen/ncop_expr_node_kind_impl.h"
20 : #include "native_client/src/trusted/validator/x86/decoder/nc_decode_tables_types.h"
21 : #include "native_client/src/trusted/validator/x86/decoder/nc_inst_state_internal.h"
22 :
23 : /* To turn on debugging of instruction decoding, change value of
24 : * DEBUGGING to 1.
25 : *
26 : * WARNING: Debugging messages inside of print messages must be sent to the
27 : * same gio stream as being printed, since they may be used by another
28 : * nacl log message that has locked the access to NaClLogGetGio().
29 : */
30 : #define DEBUGGING 0
31 :
32 : #include "native_client/src/shared/utils/debugging.h"
33 :
34 : #include "native_client/src/trusted/validator/x86/decoder/ncopcode_desc_inl.c"
35 : #include "native_client/src/trusted/validator/x86/decoder/ncop_exps_inl.c"
36 :
37 144 : void NaClPrintExpFlags(struct Gio* file, NaClExpFlags flags) {
38 144 : if (flags == 0) {
39 6 : gprintf(file, "0");
40 : } else {
41 : NaClExpFlag f;
42 138 : Bool is_first = TRUE;
43 2346 : for (f = 0; f < NaClExpFlagEnumSize; f++) {
44 2208 : if (flags & NACL_EFLAG(f)) {
45 282 : if (is_first) {
46 138 : is_first = FALSE;
47 : } else {
48 144 : gprintf(file, " | ");
49 : }
50 282 : gprintf(file, "%s", NaClExpFlagName(f));
51 : }
52 : }
53 : }
54 144 : }
55 :
56 : typedef struct NaClExpKindDescriptor {
57 : /* The name of the expression operator. */
58 : NaClExpKind name;
59 : /* The rank (i.e. number of children) the expression operator has. */
60 : const int rank;
61 : } NaClExpKindDescriptor;
62 :
63 : /* The print names of valid NaClExpKind values. */
64 : static const NaClExpKindDescriptor
65 : g_NaClExpKindDesc[NaClExpKindEnumSize + 1]= {
66 : {UndefinedExp, 0},
67 : {ExprRegister, 0},
68 : {OperandReference, 1},
69 : {ExprConstant, 0},
70 : {ExprSegmentAddress, 2},
71 : {ExprMemOffset, 4},
72 : {ExprNaClIllegal, 0},
73 : };
74 :
75 3672 : int NaClExpKindRank(NaClExpKind kind) {
76 3672 : assert(kind == g_NaClExpKindDesc[kind].name);
77 3672 : return g_NaClExpKindDesc[kind].rank;
78 : }
79 :
80 : /* Returns the register defined by the given node. */
81 0 : NaClOpKind NaClGetExpRegister(NaClExp* node) {
82 0 : return NaClGetExpRegisterInline(node);
83 : }
84 :
85 : /* Returns the name of the register defined by the indexed node in the
86 : * vector of nodes.
87 : */
88 : NaClOpKind NaClGetExpVectorRegister(NaClExpVector* vector,
89 418 : int node) {
90 418 : return NaClGetExpRegisterInline(&vector->node[node]);
91 : }
92 :
93 : static int NaClPrintDisassembledExp(struct Gio* file,
94 : NaClInstState* state,
95 : uint32_t index);
96 :
97 : /* Print the characters in the given string using lower case. */
98 727 : static void NaClPrintLower(struct Gio* file, char* str) {
99 3788 : while (*str) {
100 2334 : gprintf(file, "%c", tolower(*str));
101 2334 : ++str;
102 : }
103 727 : }
104 :
105 : /* Print out the given constant expression node to the given file. */
106 : static void NaClPrintDisassembledConst(
107 232 : struct Gio* file, NaClInstState* state, NaClExp* node) {
108 232 : assert(node->kind == ExprConstant);
109 232 : if (node->flags & NACL_EFLAG(ExprJumpTarget)) {
110 : NaClPcAddress target = NaClInstStatePrintableAddress(state)
111 39 : + state->bytes.length + (NaClPcNumber) NaClGetExprSignedValue(node);
112 39 : gprintf(file, "0x%"NACL_PRIxNaClPcAddress, target);
113 193 : }else if (node->flags & NACL_EFLAG(ExprUnsignedHex)) {
114 101 : gprintf(file, "0x%"NACL_PRIx64, NaClGetExprUnsignedValue(node));
115 92 : } else if (node->flags & NACL_EFLAG(ExprSignedHex)) {
116 79 : int64_t val = NaClGetExprSignedValue(node);
117 79 : if (val < 0) {
118 34 : val = -val;
119 34 : gprintf(file, "-0x%"NACL_PRIx64, val);
120 : } else {
121 45 : gprintf(file, "0x%"NACL_PRIx64, val);
122 : }
123 13 : } else if (node->flags & NACL_EFLAG(ExprUnsignedInt)) {
124 0 : gprintf(file, "%"NACL_PRIu64, NaClGetExprUnsignedValue(node));
125 : } else {
126 : /* Assume ExprSignedInt. */
127 13 : gprintf(file, "%"NACL_PRId64, NaClGetExprSignedValue(node));
128 : }
129 232 : }
130 :
131 : #define NACLOP_REG_PREFIX "Reg"
132 :
133 802 : size_t NaClOpRegName(NaClOpKind reg, char* buffer, size_t buffer_size) {
134 802 : const char* name = NaClOpKindName(reg);
135 : char* str;
136 : size_t index;
137 :
138 : /* Fail if no room to put register name. */
139 802 : if (buffer_size == 0) return 0;
140 802 : buffer[0] = '\0'; /* To be safe, in case we exit prematurely. */
141 :
142 : /* Get name for register. */
143 802 : name = NaClOpKindName(reg);
144 802 : if (NULL == name) return 0;
145 :
146 : /* Strip off 'Reg' prefix from register name, if it exists. */
147 802 : str = strstr(name, NACLOP_REG_PREFIX);
148 802 : if (str != name) return 0;
149 802 : str += strlen(NACLOP_REG_PREFIX);
150 :
151 : /* Copy the name, converting characters to lower case. */
152 2963 : for (index = 0; (index + 1) < buffer_size; ++index) {
153 2963 : char ch = tolower(str[index]);
154 2963 : if ('\0' == ch) break;
155 2161 : buffer[index] = tolower(str[index]);
156 : }
157 :
158 : /* Be sure to add null character at end. */
159 802 : buffer[index] = '\0';
160 802 : return index;
161 : }
162 :
163 : #define MAX_REGISTER_SIZE 256
164 :
165 : /* Print out the disassembled representation of the given register
166 : * to the given file.
167 : */
168 802 : static void NaClPrintDisassembledRegKind(struct Gio* file, NaClOpKind reg) {
169 : char buffer[MAX_REGISTER_SIZE];
170 802 : NaClOpRegName(reg, buffer, MAX_REGISTER_SIZE);
171 802 : gprintf(file, "%c%s", '%', buffer);
172 802 : }
173 :
174 557 : static INLINE void NaClPrintDisassembledReg(struct Gio* file, NaClExp* node) {
175 557 : NaClPrintDisassembledRegKind(file, NaClGetExpRegisterInline(node));
176 557 : }
177 :
178 34 : void NaClExpVectorPrint(struct Gio* file, NaClInstState* state) {
179 : uint32_t i;
180 34 : NaClExpVector* vector = NaClInstStateExpVector(state);
181 34 : gprintf(file, "NaClExpVector[%d] = {\n", vector->number_expr_nodes);
182 178 : for (i = 0; i < vector->number_expr_nodes; i++) {
183 144 : NaClExp* node = &vector->node[i];
184 144 : gprintf(file, " { %s[%d] , ",
185 : NaClExpKindName(node->kind),
186 : NaClExpKindRank(node->kind));
187 144 : switch (node->kind) {
188 : case ExprRegister:
189 57 : NaClPrintDisassembledReg(file, node);
190 57 : break;
191 : case ExprConstant:
192 25 : NaClPrintDisassembledConst(file, state, node);
193 25 : break;
194 : default:
195 62 : gprintf(file, "%"NACL_PRIu64, NaClGetExprUnsignedValue(node));
196 : break;
197 : }
198 144 : gprintf(file, ", ");
199 144 : NaClPrintExpFlags(file, node->flags);
200 144 : gprintf(file, " },\n");
201 : }
202 34 : gprintf(file, "};\n");
203 34 : }
204 :
205 : /* Print out the given (memory offset) expression node to the given file.
206 : * Returns the index of the node following the given (indexed) memory offset.
207 : */
208 : static int NaClPrintDisassembledMemOffset(struct Gio* file,
209 : NaClInstState *state,
210 209 : int index) {
211 209 : NaClExpVector* vector = NaClInstStateExpVector(state);
212 209 : int r1_index = index + 1;
213 209 : int r2_index = r1_index + NaClExpWidth(vector, r1_index);
214 209 : int scale_index = r2_index + NaClExpWidth(vector, r2_index);
215 209 : int disp_index = scale_index + NaClExpWidth(vector, scale_index);
216 209 : NaClOpKind r1 = NaClGetExpVectorRegister(vector, r1_index);
217 209 : NaClOpKind r2 = NaClGetExpVectorRegister(vector, r2_index);
218 209 : uint64_t scale = NaClGetExprUnsignedValue(&vector->node[scale_index]);
219 209 : int64_t disp = NaClGetExprSignedValue(&vector->node[disp_index]);
220 209 : assert(ExprMemOffset == vector->node[index].kind);
221 209 : gprintf(file,"[");
222 209 : if (r1 != RegUnknown) {
223 180 : NaClPrintDisassembledRegKind(file, r1);
224 : }
225 209 : if (r2 != RegUnknown) {
226 65 : if (r1 != RegUnknown) {
227 56 : gprintf(file, "+");
228 : }
229 65 : NaClPrintDisassembledRegKind(file, r2);
230 65 : gprintf(file, "*%d", (uint32_t) scale);
231 : }
232 209 : if (disp != 0) {
233 79 : if ((r1 != RegUnknown || r2 != RegUnknown) &&
234 : !NaClIsExpNegativeConstant(vector, disp_index)) {
235 34 : gprintf(file, "+");
236 : }
237 : /* Recurse to handle print using format flags. */
238 79 : NaClPrintDisassembledExp(file, state, disp_index);
239 130 : } else if (r1 == RegUnknown && r2 == RegUnknown) {
240 : /* be sure to generate case: [0x0]. */
241 8 : NaClPrintDisassembledExp(file, state, disp_index);
242 : }
243 209 : gprintf(file, "]");
244 209 : return disp_index + NaClExpWidth(vector, disp_index);
245 : }
246 :
247 : /* Print out the given (segment address) expression node to the
248 : * given file. Returns the index of the node following the
249 : * given (indexed) segment address.
250 : */
251 : static int NaClPrintDisassembledSegmentAddr(struct Gio* file,
252 : NaClInstState* state,
253 197 : int index) {
254 197 : assert(ExprSegmentAddress == NaClInstStateExpVector(state)->node[index].kind);
255 197 : index = NaClPrintDisassembledExp(file, state, index + 1);
256 197 : gprintf(file, ":");
257 197 : return NaClPrintDisassembledExp(file, state, index);
258 : }
259 :
260 : /* Print out the given expression node to the given file.
261 : * Returns the index of the node following the given indexed
262 : * expression.
263 : */
264 : static int NaClPrintDisassembledExp(struct Gio* file,
265 : NaClInstState* state,
266 1751 : uint32_t index) {
267 : NaClExp* node;
268 1751 : NaClExpVector* vector = NaClInstStateExpVector(state);
269 1751 : assert(index < vector->number_expr_nodes);
270 1751 : node = &vector->node[index];
271 1751 : switch (node->kind) {
272 : default:
273 0 : gprintf(file, "undefined");
274 0 : return index + 1;
275 : case ExprRegister:
276 500 : NaClPrintDisassembledReg(file, node);
277 500 : return index + 1;
278 : case OperandReference:
279 635 : return NaClPrintDisassembledExp(file, state, index + 1);
280 : case ExprConstant:
281 207 : NaClPrintDisassembledConst(file, state, node);
282 207 : return index + 1;
283 : case ExprSegmentAddress:
284 197 : return NaClPrintDisassembledSegmentAddr(file, state, index);
285 : case ExprMemOffset:
286 209 : return NaClPrintDisassembledMemOffset(file, state, index);
287 : case ExprNaClIllegal:
288 3 : gprintf(file, "*NaClIllegal*");
289 3 : return index + 1;
290 : }
291 : }
292 :
293 : /* Returns true if there is a segment override in the segment address
294 : * node defined by vector[seg_addr_index].
295 : *
296 : * Parameters:
297 : * vector - The node expression tree associated with the instruction.
298 : * seg_addr_index - The index to the segment address node to check.
299 : * seg_eflag - The expr flag that must be associated with the
300 : * segment address node to be considered for an override.
301 : * seg_reg - The expected (i.e. default) segment register
302 : * to be associated with the segment address.
303 : */
304 : static Bool NaClHasSegmentOverride(NaClExpVector* vector,
305 : int seg_addr_index,
306 : NaClExpFlag seg_eflag,
307 2 : NaClOpKind seg_reg) {
308 2 : NaClExp* seg_node = &vector->node[seg_addr_index];
309 2 : if (seg_node->flags & NACL_EFLAG(seg_eflag)) {
310 1 : int seg_index = seg_addr_index + 1;
311 1 : NaClExp* node = &vector->node[seg_index];
312 1 : if ((ExprRegister == node->kind) &&
313 : (seg_reg != NaClGetExpRegisterInline(node))) {
314 0 : return TRUE;
315 : }
316 : }
317 2 : return FALSE;
318 : }
319 :
320 : /* Prints out the segment register associated with the segment
321 : * address node defined by vector[seg_addr_index].
322 : *
323 : * Parameters:
324 : * file - The Gio file to print the segment register to.
325 : * is_first - True if the first operand of the instruction.
326 : * vector - The node expression tree associated with the instruction.
327 : * seg_addr_index - The index to the segment address node to check.
328 : */
329 : static void NaClPrintSegmentOverride(struct Gio* file,
330 : Bool* is_first,
331 : NaClInstState* state,
332 : NaClExpVector* vector,
333 0 : int seg_addr_index) {
334 0 : int seg_index = seg_addr_index + 1;
335 0 : if (*is_first) {
336 0 : gprintf(file, " ");
337 0 : *is_first = FALSE;
338 : } else {
339 0 : gprintf(file, ", ");
340 : }
341 0 : NaClPrintDisassembledExp(file, state, seg_index);
342 0 : }
343 :
344 : /* Print the flag name if the flag is defined for the corresponding operand.
345 : * Used to print out set/use/zero extend information for partial instructions.
346 : */
347 : static void NaClPrintAddOperandFlag(struct Gio* f,
348 : const NaClOp* op,
349 : NaClOpFlag flag,
350 0 : const char* flag_name) {
351 0 : if (op->flags & NACL_OPFLAG(flag)) {
352 0 : gprintf(f, "%s", flag_name);
353 : }
354 0 : }
355 :
356 : /* Print the given instruction opcode of the give state, to the
357 : * given file.
358 : */
359 : static void NaClPrintDisassembled(struct Gio* file,
360 : NaClInstState* state,
361 727 : const NaClInst* inst) {
362 727 : uint32_t tree_index = 0;
363 727 : Bool is_first = TRUE;
364 727 : Bool not_printed_prefix_segment = TRUE;
365 : NaClExp* node;
366 727 : NaClExpVector* vector = NaClInstStateExpVector(state);
367 :
368 : /* Print the name of the instruction. */
369 727 : if (NaClHasBit(inst->flags, NACL_IFLAG(PartialInstruction))) {
370 : /* Instruction has been simplified. Print out corresponding
371 : * hints to the reader, so that they know that the instruction
372 : * has been simplified.
373 : */
374 0 : gprintf(file, "[P] ");
375 0 : NaClPrintLower(file, (char*) NaClMnemonicName(inst->name));
376 0 : if (NaClHasBit(inst->flags, NACL_IFLAG(NaClIllegal))) {
377 0 : gprintf(file, "(illegal)");
378 : }
379 : } else {
380 727 : NaClPrintLower(file, (char*) NaClMnemonicName(inst->name));
381 : }
382 :
383 : /* Use the generated expression tree to print out (non-implicit) operands
384 : * of the instruction.
385 : */
386 2184 : while (tree_index < vector->number_expr_nodes) {
387 730 : node = &vector->node[tree_index];
388 1365 : if (node->kind != OperandReference ||
389 : (NACL_EMPTY_EFLAGS == (node->flags & NACL_EFLAG(ExprImplicit)))) {
390 635 : if (is_first) {
391 348 : gprintf(file, " ");
392 348 : is_first = FALSE;
393 : } else {
394 287 : gprintf(file, ", ");
395 : }
396 635 : NaClPrintDisassembledExp(file, state, tree_index);
397 :
398 : /* If this is a partial instruction, add set/use information
399 : * so that that it is more clear what was matched.
400 : */
401 635 : if (NaClHasBit(inst->flags, NACL_IFLAG(PartialInstruction)) &&
402 : node->kind == OperandReference) {
403 : const NaClOp* op =
404 : NaClGetInstOperandInline(state->decoder_tables,
405 : inst,
406 0 : (uint8_t) NaClGetExprUnsignedValue(node));
407 0 : if (NaClHasBit(op->flags, (NACL_OPFLAG(OpSet) |
408 : NACL_OPFLAG(OpUse) |
409 : NACL_OPFLAG(OperandZeroExtends_v)))) {
410 0 : gprintf(file, " (");
411 0 : NaClPrintAddOperandFlag(file, op, OpSet, "s");
412 0 : NaClPrintAddOperandFlag(file, op, OpUse, "u");
413 0 : NaClPrintAddOperandFlag(file, op, OperandZeroExtends_v, "z");
414 0 : gprintf(file, ")");
415 : }
416 : }
417 95 : } else if (not_printed_prefix_segment &&
418 : (OperandReference == node->kind) &&
419 : (node->flags & NACL_EFLAG(ExprImplicit))) {
420 : /* Print out segment override of implicit segment address, if
421 : * applicable.
422 : */
423 95 : if (OperandReference == node->kind) {
424 95 : int seg_addr_index = tree_index + 1;
425 95 : if (ExprSegmentAddress == vector->node[seg_addr_index].kind) {
426 1 : if (NaClHasSegmentOverride(vector, seg_addr_index,
427 : ExprDSrCase, RegDS)) {
428 0 : NaClPrintSegmentOverride(file, &is_first, state, vector,
429 : seg_addr_index);
430 1 : } else if (NaClHasSegmentOverride(vector, seg_addr_index,
431 : ExprESrCase, RegES)) {
432 0 : NaClPrintSegmentOverride(file, &is_first, state, vector,
433 : seg_addr_index);
434 : }
435 : }
436 : }
437 : }
438 : /* Skip over expression to next expresssion. */
439 730 : tree_index += NaClExpWidth(vector, tree_index);
440 : }
441 727 : }
442 :
443 727 : void NaClInstStateInstPrint(struct Gio* file, NaClInstState* state) {
444 : int i;
445 : const NaClInst* inst;
446 :
447 : /* Print out the address and the inst bytes. */
448 727 : int length = NaClInstStateLength(state);
449 :
450 : DEBUG_OR_ERASE(
451 : NaClInstPrint(file, state->decoder_tables, NaClInstStateInst(state)));
452 : DEBUG(NaClExpVectorPrint(file, state));
453 727 : gprintf(file, "%"NACL_PRIxNaClPcAddressAll": ",
454 : NaClInstStatePrintableAddress(state));
455 2956 : for (i = 0; i < length; ++i) {
456 2229 : gprintf(file, "%02"NACL_PRIx8" ", NaClInstStateByte(state, i));
457 : }
458 9403 : for (i = length; i < NACL_MAX_BYTES_PER_X86_INSTRUCTION; ++i) {
459 8676 : gprintf(file, " ");
460 : }
461 :
462 : /* Print out the assembly instruction it disassembles to. */
463 727 : inst = NaClInstStateInst(state);
464 727 : NaClPrintDisassembled(file, state, inst);
465 727 : gprintf(file, "\n");
466 727 : }
467 :
468 0 : char* NaClInstStateInstructionToString(struct NaClInstState* state) {
469 : struct GioFile gfile;
470 : char* out_string;
471 : struct stat st;
472 : size_t file_size;
473 : size_t fread_items;
474 0 : FILE* file = NULL;
475 0 : struct Gio* g = NULL;
476 :
477 : do {
478 0 : file = fopen("out_file", "w");
479 0 : if (file == NULL) break;
480 :
481 0 : g = (struct Gio*) &gfile;
482 0 : if (0 == GioFileRefCtor(&gfile, file)) {
483 0 : GioFileDtor(g);
484 0 : g = NULL;
485 0 : break;
486 : }
487 :
488 : #if NACL_LINUX || NACL_OSX
489 0 : chmod("out_file", S_IRUSR | S_IWUSR);
490 : #endif
491 :
492 0 : NaClInstStateInstPrint(g, state);
493 0 : GioFileClose(g);
494 :
495 0 : if (stat("out_file", &st)) break;
496 :
497 0 : file_size = (size_t) st.st_size;
498 0 : if (file_size == 0) break;
499 :
500 0 : out_string = (char*) malloc(file_size + 1);
501 0 : if (out_string == NULL) break;
502 :
503 0 : file = fopen("out_file", "r");
504 0 : if (file == NULL) break;
505 :
506 0 : fread_items = fread(out_string, file_size, 1, file);
507 0 : if (fread_items != 1) break;
508 :
509 0 : fclose(file);
510 0 : unlink("out_file");
511 0 : out_string[file_size] = 0;
512 0 : return out_string;
513 : } while (0);
514 :
515 : /* failure */
516 0 : if (g != NULL) {
517 0 : GioFileClose(g);
518 0 : file = NULL;
519 : }
520 0 : if (file != NULL) fclose(file);
521 0 : unlink("out_file");
522 0 : return NULL;
523 : }
524 :
525 3528 : int NaClExpWidth(NaClExpVector* vector, int node) {
526 : int i;
527 3528 : int count = 1;
528 3528 : int num_kids = NaClExpKindRank(vector->node[node].kind);
529 5490 : for (i = 0; i < num_kids; i++) {
530 1962 : count += NaClExpWidth(vector, node + count);
531 : }
532 3528 : return count;
533 : }
534 :
535 0 : int NaClGetExpKidIndex(NaClExpVector* vector, int node, int kid) {
536 0 : node++;
537 0 : while (kid-- > 0) {
538 0 : node += NaClExpWidth(vector, node);
539 : }
540 0 : return node;
541 : }
542 :
543 0 : int NaClGetExpParentIndex(NaClExpVector* vector, int index) {
544 : int node_rank;
545 0 : int num_kids = 1;
546 0 : while (index > 0) {
547 0 : --index;
548 0 : node_rank = NaClExpKindRank(vector->node[index].kind);
549 0 : if (node_rank >= num_kids) {
550 0 : return index;
551 : } else {
552 0 : num_kids -= (node_rank - 1);
553 : }
554 : }
555 0 : return -1;
556 : }
557 :
558 : int NaClGetNthExpKind(NaClExpVector* vector,
559 : NaClExpKind kind,
560 0 : int n) {
561 0 : if (n > 0) {
562 : uint32_t i;
563 0 : for (i = 0; i < vector->number_expr_nodes; ++i) {
564 0 : if (kind == vector->node[i].kind) {
565 0 : --n;
566 0 : if (n == 0) return i;
567 : }
568 : }
569 : }
570 0 : return -1;
571 : }
572 :
573 67 : Bool NaClIsExpNegativeConstant(NaClExpVector* vector, int index) {
574 67 : NaClExp* node = &vector->node[index];
575 67 : switch (node->kind) {
576 : case ExprConstant:
577 67 : if (node->flags & NACL_EFLAG(ExprUnsignedHex) ||
578 : node->flags & NACL_EFLAG(ExprUnsignedInt)) {
579 0 : return FALSE;
580 : } else {
581 : /* Assume signed value. */
582 67 : return NaClGetExprSignedValue(node) < 0;
583 : }
584 : break;
585 : default:
586 : break;
587 : }
588 0 : return FALSE;
589 : }
590 :
591 : /* Dummy routine to allow unreferenced NaClGetInstNumberOperandsInline
592 : * inline.
593 : */
594 0 : uint8_t NaClNcopExpsDummyNaClGetInstNumberOperands(const NaClInst* inst) {
595 0 : return NaClGetInstNumberOperandsInline(inst);
596 : }
|