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 2962 : void NaClPrintExpFlags(struct Gio* file, NaClExpFlags flags) {
38 2962 : if (flags == 0) {
39 212 : gprintf(file, "0");
40 212 : } else {
41 2750 : NaClExpFlag f;
42 2750 : Bool is_first = TRUE;
43 93500 : for (f = 0; f < NaClExpFlagEnumSize; f++) {
44 44000 : if (flags & NACL_EFLAG(f)) {
45 5513 : if (is_first) {
46 2750 : is_first = FALSE;
47 2750 : } else {
48 2763 : gprintf(file, " | ");
49 : }
50 5513 : gprintf(file, "%s", NaClExpFlagName(f));
51 5513 : }
52 44000 : }
53 : }
54 2962 : }
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 26588 : int NaClExpKindRank(NaClExpKind kind) {
76 53176 : assert(kind == g_NaClExpKindDesc[kind].name);
77 26588 : 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 3110 : NaClOpKind NaClGetExpVectorRegister(NaClExpVector* vector,
89 3110 : int node) {
90 3110 : 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 4522 : static void NaClPrintLower(struct Gio* file, char* str) {
99 32084 : while (*str) {
100 23040 : gprintf(file, "%c", tolower(*str));
101 23040 : ++str;
102 23040 : }
103 4522 : }
104 :
105 : /* Print out the given constant expression node to the given file. */
106 : static void NaClPrintDisassembledConst(
107 1361 : struct Gio* file, NaClInstState* state, NaClExp* node) {
108 2722 : assert(node->kind == ExprConstant);
109 1361 : if (node->flags & NACL_EFLAG(ExprJumpTarget)) {
110 210 : NaClPcAddress target = NaClInstStatePrintableAddress(state)
111 210 : + state->bytes.length + (NaClPcNumber) NaClGetExprSignedValue(node);
112 210 : gprintf(file, "0x%"NACL_PRIxNaClPcAddress, target);
113 1361 : }else if (node->flags & NACL_EFLAG(ExprUnsignedHex)) {
114 443 : gprintf(file, "0x%"NACL_PRIx64, NaClGetExprUnsignedValue(node));
115 1151 : } else if (node->flags & NACL_EFLAG(ExprSignedHex)) {
116 401 : int64_t val = NaClGetExprSignedValue(node);
117 401 : if (val < 0) {
118 57 : val = -val;
119 57 : gprintf(file, "-0x%"NACL_PRIx64, val);
120 57 : } else {
121 344 : gprintf(file, "0x%"NACL_PRIx64, val);
122 : }
123 708 : } else if (node->flags & NACL_EFLAG(ExprUnsignedInt)) {
124 0 : gprintf(file, "%"NACL_PRIu64, NaClGetExprUnsignedValue(node));
125 0 : } else {
126 : /* Assume ExprSignedInt. */
127 307 : gprintf(file, "%"NACL_PRId64, NaClGetExprSignedValue(node));
128 : }
129 1361 : }
130 :
131 : #define NACLOP_REG_PREFIX "Reg"
132 :
133 6280 : size_t NaClOpRegName(NaClOpKind reg, char* buffer, size_t buffer_size) {
134 6280 : const char* name = NaClOpKindName(reg);
135 6280 : char* str;
136 6280 : size_t index;
137 :
138 : /* Fail if no room to put register name. */
139 6280 : if (buffer_size == 0) return 0;
140 6280 : buffer[0] = '\0'; /* To be safe, in case we exit prematurely. */
141 :
142 : /* Get name for register. */
143 6280 : name = NaClOpKindName(reg);
144 6280 : if (NULL == name) return 0;
145 :
146 : /* Strip off 'Reg' prefix from register name, if it exists. */
147 6280 : str = strstr(name, NACLOP_REG_PREFIX);
148 6280 : if (str != name) return 0;
149 6280 : str += strlen(NACLOP_REG_PREFIX);
150 :
151 : /* Copy the name, converting characters to lower case. */
152 51310 : for (index = 0; (index + 1) < buffer_size; ++index) {
153 25655 : char ch = tolower(str[index]);
154 31935 : if ('\0' == ch) break;
155 19375 : buffer[index] = tolower(str[index]);
156 19375 : }
157 :
158 : /* Be sure to add null character at end. */
159 6280 : buffer[index] = '\0';
160 6280 : return index;
161 6280 : }
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 6280 : static void NaClPrintDisassembledRegKind(struct Gio* file, NaClOpKind reg) {
169 6280 : char buffer[MAX_REGISTER_SIZE];
170 6280 : NaClOpRegName(reg, buffer, MAX_REGISTER_SIZE);
171 6280 : gprintf(file, "%c%s", '%', buffer);
172 6280 : }
173 :
174 4898 : static INLINE void NaClPrintDisassembledReg(struct Gio* file, NaClExp* node) {
175 4898 : NaClPrintDisassembledRegKind(file, NaClGetExpRegisterInline(node));
176 4898 : }
177 :
178 610 : void NaClExpVectorPrint(struct Gio* file, NaClInstState* state) {
179 610 : uint32_t i;
180 610 : NaClExpVector* vector = NaClInstStateExpVector(state);
181 610 : gprintf(file, "NaClExpVector[%d] = {\n", vector->number_expr_nodes);
182 7144 : for (i = 0; i < vector->number_expr_nodes; i++) {
183 2962 : NaClExp* node = &vector->node[i];
184 5924 : gprintf(file, " { %s[%d] , ",
185 2962 : NaClExpKindName(node->kind),
186 2962 : NaClExpKindRank(node->kind));
187 2962 : switch (node->kind) {
188 : case ExprRegister:
189 1177 : NaClPrintDisassembledReg(file, node);
190 1177 : break;
191 : case ExprConstant:
192 519 : NaClPrintDisassembledConst(file, state, node);
193 519 : break;
194 : default:
195 1266 : gprintf(file, "%"NACL_PRIu64, NaClGetExprUnsignedValue(node));
196 1266 : break;
197 : }
198 2962 : gprintf(file, ", ");
199 2962 : NaClPrintExpFlags(file, node->flags);
200 2962 : gprintf(file, " },\n");
201 2962 : }
202 610 : gprintf(file, "};\n");
203 610 : }
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 1113 : static int NaClPrintDisassembledMemOffset(struct Gio* file,
209 1113 : NaClInstState *state,
210 1113 : int index) {
211 1113 : NaClExpVector* vector = NaClInstStateExpVector(state);
212 1113 : int r1_index = index + 1;
213 1113 : int r2_index = r1_index + NaClExpWidth(vector, r1_index);
214 1113 : int scale_index = r2_index + NaClExpWidth(vector, r2_index);
215 1113 : int disp_index = scale_index + NaClExpWidth(vector, scale_index);
216 1113 : NaClOpKind r1 = NaClGetExpVectorRegister(vector, r1_index);
217 1113 : NaClOpKind r2 = NaClGetExpVectorRegister(vector, r2_index);
218 1113 : uint64_t scale = NaClGetExprUnsignedValue(&vector->node[scale_index]);
219 1113 : int64_t disp = NaClGetExprSignedValue(&vector->node[disp_index]);
220 2226 : assert(ExprMemOffset == vector->node[index].kind);
221 1113 : gprintf(file,"[");
222 1113 : if (r1 != RegUnknown) {
223 1045 : NaClPrintDisassembledRegKind(file, r1);
224 1045 : }
225 1113 : if (r2 != RegUnknown) {
226 337 : if (r1 != RegUnknown) {
227 329 : gprintf(file, "+");
228 329 : }
229 337 : NaClPrintDisassembledRegKind(file, r2);
230 337 : gprintf(file, "*%d", (uint32_t) scale);
231 337 : }
232 1113 : if (disp != 0) {
233 369 : if ((r1 != RegUnknown || r2 != RegUnknown) &&
234 257 : !NaClIsExpNegativeConstant(vector, disp_index)) {
235 219 : gprintf(file, "+");
236 219 : }
237 : /* Recurse to handle print using format flags. */
238 309 : NaClPrintDisassembledExp(file, state, disp_index);
239 1121 : } else if (r1 == RegUnknown && r2 == RegUnknown) {
240 : /* be sure to generate case: [0x0]. */
241 8 : NaClPrintDisassembledExp(file, state, disp_index);
242 8 : }
243 1113 : gprintf(file, "]");
244 1113 : return disp_index + NaClExpWidth(vector, disp_index);
245 : }
246 :
247 : /* Retrurns true if the segment register of the indexed segment address is DS,
248 : * and DS has been marked (by the instruction) as the default register
249 : * for the segment address.
250 : */
251 439 : static Bool IsSegmentAddressDsRegPair(NaClInstState* state,
252 439 : int index) {
253 439 : NaClExpVector* vector = NaClInstStateExpVector(state);
254 439 : NaClExp* segment_address = &vector->node[index];
255 439 : NaClExp* segment_register =
256 439 : &vector->node[NaClGetExpKidIndex(vector, index, 0)];
257 553 : return NaClHasBit(segment_address->flags, NACL_EFLAG(ExprDSrCase)) &&
258 : (segment_register->kind == ExprRegister) &&
259 114 : (RegDS == NaClGetExpRegisterInline(segment_register));
260 439 : }
261 :
262 : /* Retrurns true if the segment register of the index segment address is ES,
263 : * and ES has been marked (by the instruction) as the default register
264 : * for the segment address.
265 : */
266 325 : static Bool IsSegmentAddressEsRegPair(NaClInstState* state,
267 325 : int index) {
268 325 : NaClExpVector* vector = NaClInstStateExpVector(state);
269 325 : NaClExp* segment_address = &vector->node[index];
270 325 : NaClExp* segment_register =
271 325 : &vector->node[NaClGetExpKidIndex(vector, index, 0)];
272 583 : return NaClHasBit(segment_address->flags, NACL_EFLAG(ExprESrCase)) &&
273 : (segment_register->kind == ExprRegister) &&
274 258 : (RegES == NaClGetExpRegisterInline(segment_register));
275 325 : }
276 :
277 : /* Print out the given (segment address) expression node to the
278 : * given file. Returns the index of the node following the
279 : * given (indexed) segment address.
280 : */
281 439 : static int NaClPrintDisassembledSegmentAddr(struct Gio* file,
282 439 : NaClInstState* state,
283 439 : int index) {
284 439 : int memory_address;
285 439 : NaClExpVector* vector = NaClInstStateExpVector(state);
286 : /* If segment register is default. If so, do not print. */
287 439 : if (IsSegmentAddressDsRegPair(state, index) ||
288 325 : IsSegmentAddressEsRegPair(state, index)) {
289 : /* Segment register matches default. Don't print. */
290 372 : } else {
291 : /* Print the segment register associated with the segment address. */
292 67 : NaClPrintDisassembledExp(file, state, index + 1);
293 67 : gprintf(file, ":");
294 : }
295 439 : memory_address = NaClGetExpKidIndex(vector, index, 1);
296 439 : if (vector->node[memory_address].kind == ExprRegister) {
297 : /* Special case segment address, where the register corresponds to
298 : * a memory address. Print out the register in '[]' brackets to
299 : * communicate that it is a memory reference.
300 : */
301 372 : int result;
302 372 : gprintf(file, "[");
303 372 : result = NaClPrintDisassembledExp(file, state, memory_address);
304 372 : gprintf(file, "]");
305 372 : return result;
306 : } else {
307 : /* print out memory address associated with segment address. */
308 67 : return NaClPrintDisassembledExp(file, state, memory_address);
309 : }
310 439 : }
311 :
312 : /* Print out the given expression node to the given file.
313 : * Returns the index of the node following the given indexed
314 : * expression.
315 : */
316 11405 : static int NaClPrintDisassembledExp(struct Gio* file,
317 11405 : NaClInstState* state,
318 11405 : uint32_t index) {
319 11405 : NaClExp* node;
320 11405 : NaClExpVector* vector = NaClInstStateExpVector(state);
321 22810 : assert(index < vector->number_expr_nodes);
322 11405 : node = &vector->node[index];
323 11405 : switch (node->kind) {
324 : default:
325 0 : gprintf(file, "undefined");
326 0 : return index + 1;
327 : case ExprRegister:
328 3721 : NaClPrintDisassembledReg(file, node);
329 3721 : return index + 1;
330 : case OperandReference:
331 5290 : return NaClPrintDisassembledExp(file, state, index + 1);
332 : case ExprConstant:
333 842 : NaClPrintDisassembledConst(file, state, node);
334 842 : return index + 1;
335 : case ExprSegmentAddress:
336 439 : return NaClPrintDisassembledSegmentAddr(file, state, index);
337 : case ExprMemOffset:
338 1113 : return NaClPrintDisassembledMemOffset(file, state, index);
339 : case ExprNaClIllegal:
340 0 : gprintf(file, "*NaClIllegal*");
341 0 : return index + 1;
342 : }
343 11405 : }
344 :
345 : /* Returns true if there is a segment override in the segment address
346 : * node defined by vector[seg_addr_index].
347 : *
348 : * Parameters:
349 : * vector - The node expression tree associated with the instruction.
350 : * seg_addr_index - The index to the segment address node to check.
351 : * seg_eflag - The expr flag that must be associated with the
352 : * segment address node to be considered for an override.
353 : * seg_reg - The expected (i.e. default) segment register
354 : * to be associated with the segment address.
355 : */
356 102 : static Bool NaClHasSegmentOverride(NaClExpVector* vector,
357 102 : int seg_addr_index,
358 102 : NaClExpFlag seg_eflag,
359 102 : NaClOpKind seg_reg) {
360 102 : NaClExp* seg_node = &vector->node[seg_addr_index];
361 102 : if (seg_node->flags & NACL_EFLAG(seg_eflag)) {
362 52 : int seg_index = seg_addr_index + 1;
363 52 : NaClExp* node = &vector->node[seg_index];
364 104 : if ((ExprRegister == node->kind) &&
365 52 : (seg_reg != NaClGetExpRegisterInline(node))) {
366 2 : return TRUE;
367 : }
368 50 : }
369 100 : return FALSE;
370 102 : }
371 :
372 : /* Prints out the segment register associated with the segment
373 : * address node defined by vector[seg_addr_index].
374 : *
375 : * Parameters:
376 : * file - The Gio file to print the segment register to.
377 : * is_first - True if the first operand of the instruction.
378 : * vector - The node expression tree associated with the instruction.
379 : * seg_addr_index - The index to the segment address node to check.
380 : */
381 2 : static void NaClPrintSegmentOverride(struct Gio* file,
382 2 : Bool* is_first,
383 2 : NaClInstState* state,
384 2 : NaClExpVector* vector,
385 2 : int seg_addr_index) {
386 2 : int seg_index = seg_addr_index + 1;
387 2 : if (*is_first) {
388 2 : gprintf(file, " ");
389 2 : *is_first = FALSE;
390 2 : } else {
391 0 : gprintf(file, ", ");
392 : }
393 2 : NaClPrintDisassembledExp(file, state, seg_index);
394 2 : }
395 :
396 : /* Print the flag name if the flag is defined for the corresponding operand.
397 : * Used to print out set/use/zero extend information for partial instructions.
398 : */
399 3342 : static void NaClPrintAddOperandFlag(struct Gio* f,
400 3342 : const NaClOp* op,
401 3342 : NaClOpFlag flag,
402 3342 : const char* flag_name) {
403 3342 : if (op->flags & NACL_OPFLAG(flag)) {
404 1468 : gprintf(f, "%s", flag_name);
405 1468 : }
406 3342 : }
407 :
408 : /* Print the given instruction opcode of the give state, to the
409 : * given file.
410 : */
411 4522 : static void NaClPrintDisassembled(struct Gio* file,
412 4522 : NaClInstState* state,
413 4522 : const NaClInst* inst) {
414 4522 : uint32_t tree_index = 0;
415 4522 : Bool is_first = TRUE;
416 4522 : Bool not_printed_prefix_segment = TRUE;
417 4522 : NaClExp* node;
418 4522 : NaClExpVector* vector = NaClInstStateExpVector(state);
419 :
420 : /* Print the name of the instruction. */
421 4522 : if (NaClHasBit(inst->flags, NACL_IFLAG(PartialInstruction))) {
422 : /* Instruction has been simplified. Print out corresponding
423 : * hints to the reader, so that they know that the instruction
424 : * has been simplified.
425 : */
426 1294 : gprintf(file, "[P] ");
427 1294 : NaClPrintLower(file, (char*) NaClMnemonicName(inst->name));
428 1294 : if (NaClHasBit(inst->flags, NACL_IFLAG(NaClIllegal))) {
429 133 : gprintf(file, "(illegal)");
430 133 : }
431 1294 : } else {
432 3228 : NaClPrintLower(file, (char*) NaClMnemonicName(inst->name));
433 : }
434 :
435 : /* Use the generated expression tree to print out (non-implicit) operands
436 : * of the instruction.
437 : */
438 15118 : while (tree_index < vector->number_expr_nodes) {
439 6074 : node = &vector->node[tree_index];
440 12148 : if (node->kind != OperandReference ||
441 : (NACL_EMPTY_EFLAGS == (node->flags & NACL_EFLAG(ExprImplicit)))) {
442 5290 : if (is_first) {
443 2948 : gprintf(file, " ");
444 2948 : is_first = FALSE;
445 2948 : } else {
446 2342 : gprintf(file, ", ");
447 : }
448 5290 : NaClPrintDisassembledExp(file, state, tree_index);
449 :
450 : /* If this is a partial instruction, add set/use information
451 : * so that that it is more clear what was matched.
452 : */
453 6409 : if (NaClHasBit(inst->flags, NACL_IFLAG(PartialInstruction)) &&
454 : node->kind == OperandReference) {
455 1119 : const NaClOp* op =
456 2238 : NaClGetInstOperandInline(state->decoder_tables,
457 : inst,
458 1119 : (uint8_t) NaClGetExprUnsignedValue(node));
459 1119 : if (NaClHasBit(op->flags, (NACL_OPFLAG(OpSet) |
460 : NACL_OPFLAG(OpUse) |
461 : NACL_OPFLAG(OperandZeroExtends_v)))) {
462 1114 : gprintf(file, " (");
463 1114 : NaClPrintAddOperandFlag(file, op, OpSet, "s");
464 1114 : NaClPrintAddOperandFlag(file, op, OpUse, "u");
465 1114 : NaClPrintAddOperandFlag(file, op, OperandZeroExtends_v, "z");
466 1114 : gprintf(file, ")");
467 1114 : }
468 1119 : }
469 7642 : } else if (not_printed_prefix_segment &&
470 : (OperandReference == node->kind) &&
471 : (node->flags & NACL_EFLAG(ExprImplicit))) {
472 : /* Print out segment override of implicit segment address, if
473 : * applicable.
474 : */
475 784 : if (OperandReference == node->kind) {
476 784 : int seg_addr_index = tree_index + 1;
477 784 : if (ExprSegmentAddress == vector->node[seg_addr_index].kind) {
478 52 : if (NaClHasSegmentOverride(vector, seg_addr_index,
479 : ExprDSrCase, RegDS)) {
480 2 : NaClPrintSegmentOverride(file, &is_first, state, vector,
481 : seg_addr_index);
482 52 : } else if (NaClHasSegmentOverride(vector, seg_addr_index,
483 : ExprESrCase, RegES)) {
484 0 : NaClPrintSegmentOverride(file, &is_first, state, vector,
485 : seg_addr_index);
486 0 : }
487 52 : }
488 784 : }
489 784 : }
490 : /* Skip over expression to next expresssion. */
491 6074 : tree_index += NaClExpWidth(vector, tree_index);
492 6074 : }
493 4522 : }
494 :
495 4522 : void NaClInstStateInstPrint(struct Gio* file, NaClInstState* state) {
496 4522 : int i;
497 4522 : const NaClInst* inst;
498 :
499 : /* Print out the address and the inst bytes. */
500 4522 : int length = NaClInstStateLength(state);
501 :
502 : DEBUG_OR_ERASE(
503 : NaClInstPrint(file, state->decoder_tables, NaClInstStateInst(state)));
504 9044 : DEBUG(NaClExpVectorPrint(file, state));
505 9044 : gprintf(file, "%"NACL_PRIxNaClPcAddressAll": ",
506 4522 : NaClInstStatePrintableAddress(state));
507 37858 : for (i = 0; i < length; ++i) {
508 14407 : gprintf(file, "%02"NACL_PRIx8" ", NaClInstStateByte(state, i));
509 14407 : }
510 115890 : for (i = length; i < NACL_MAX_BYTES_PER_X86_INSTRUCTION; ++i) {
511 53423 : gprintf(file, " ");
512 53423 : }
513 :
514 : /* Print out the assembly instruction it disassembles to. */
515 4522 : inst = NaClInstStateInst(state);
516 4522 : NaClPrintDisassembled(file, state, inst);
517 4522 : gprintf(file, "\n");
518 4522 : }
519 :
520 : /* Defines a buffer size big enough to hold an instruction. */
521 : #define MAX_INST_TEXT_SIZE 256
522 :
523 0 : char* NaClInstStateInstructionToString(struct NaClInstState* state) {
524 : /* Print to a memory buffer, and then duplicate. */
525 0 : struct GioMemoryFile filemem;
526 0 : struct Gio *file = (struct Gio*) &filemem;
527 0 : char buffer[MAX_INST_TEXT_SIZE];
528 0 : char* result;
529 :
530 : /* Note: Be sure to leave an extra byte to add the null character to
531 : * the end of the string.
532 : */
533 0 : GioMemoryFileCtor(&filemem, buffer, MAX_INST_TEXT_SIZE - 1);
534 0 : NaClInstStateInstPrint(file, state);
535 0 : buffer[filemem.curpos < MAX_INST_TEXT_SIZE
536 : ? filemem.curpos : MAX_INST_TEXT_SIZE] ='\0';
537 0 : result = strdup(buffer);
538 0 : GioMemoryFileDtor(file);
539 0 : return result;
540 : }
541 :
542 23626 : int NaClExpWidth(NaClExpVector* vector, int node) {
543 23626 : int i;
544 23626 : int count = 1;
545 23626 : int num_kids = NaClExpKindRank(vector->node[node].kind);
546 70268 : for (i = 0; i < num_kids; i++) {
547 11508 : count += NaClExpWidth(vector, node + count);
548 11508 : }
549 23626 : return count;
550 : }
551 :
552 1648 : int NaClGetExpKidIndex(NaClExpVector* vector, int node, int kid) {
553 1648 : node++;
554 3884 : while (kid-- > 0) {
555 588 : node += NaClExpWidth(vector, node);
556 588 : }
557 1648 : return node;
558 : }
559 :
560 0 : int NaClGetExpParentIndex(NaClExpVector* vector, int index) {
561 0 : int node_rank;
562 0 : int num_kids = 1;
563 0 : while (index > 0) {
564 0 : --index;
565 0 : node_rank = NaClExpKindRank(vector->node[index].kind);
566 0 : if (node_rank >= num_kids) {
567 0 : return index;
568 : } else {
569 0 : num_kids -= (node_rank - 1);
570 : }
571 0 : }
572 0 : return -1;
573 0 : }
574 :
575 138 : int NaClGetNthExpKind(NaClExpVector* vector,
576 138 : NaClExpKind kind,
577 138 : int n) {
578 138 : if (n > 0) {
579 138 : uint32_t i;
580 828 : for (i = 0; i < vector->number_expr_nodes; ++i) {
581 414 : if (kind == vector->node[i].kind) {
582 276 : --n;
583 414 : if (n == 0) return i;
584 138 : }
585 276 : }
586 0 : }
587 0 : return -1;
588 138 : }
589 :
590 257 : Bool NaClIsExpNegativeConstant(NaClExpVector* vector, int index) {
591 257 : NaClExp* node = &vector->node[index];
592 257 : switch (node->kind) {
593 : case ExprConstant:
594 514 : if (node->flags & NACL_EFLAG(ExprUnsignedHex) ||
595 : node->flags & NACL_EFLAG(ExprUnsignedInt)) {
596 0 : return FALSE;
597 : } else {
598 : /* Assume signed value. */
599 257 : return NaClGetExprSignedValue(node) < 0;
600 : }
601 : break;
602 : default:
603 0 : break;
604 : }
605 0 : return FALSE;
606 257 : }
607 :
608 : /* Dummy routine to allow unreferenced NaClGetInstNumberOperandsInline
609 : * inline.
610 : */
611 0 : uint8_t NaClNcopExpsDummyNaClGetInstNumberOperands(const NaClInst* inst) {
612 0 : return NaClGetInstNumberOperandsInline(inst);
613 : }
|