void NaClExpVectorPrint(struct Gio* file, NaClInstState* state) { uint32_t i; NaClExpVector* vector = NaClInstStateExpVector(state); gprintf(file, "NaClExpVector[%d] = {\n", vector->number_expr_nodes); for (i = 0; i < vector->number_expr_nodes; i++) { NaClExp* node = &vector->node[i]; gprintf(file, " { %s[%d] , ", NaClExpKindName(node->kind), NaClExpKindRank(node->kind)); switch (node->kind) { case ExprRegister: NaClPrintDisassembledReg(file, node); break; case ExprConstant: NaClPrintDisassembledConst(file, state, node); break; default: gprintf(file, "%"NACL_PRIu64, NaClGetExprUnsignedValue(node)); break; } gprintf(file, ", "); NaClPrintExpFlags(file, node->flags); gprintf(file, " },\n"); } gprintf(file, "};\n"); }
/* Print out the given constant expression node to the given file. */ static void NaClPrintDisassembledConst( struct Gio* file, NaClInstState* state, NaClExp* node) { assert(node->kind == ExprConstant); if (node->flags & NACL_EFLAG(ExprJumpTarget)) { NaClPcAddress target = NaClInstStatePrintableAddress(state) + state->bytes.length + (NaClPcNumber) NaClGetExprSignedValue(node); gprintf(file, "0x%"NACL_PRIxNaClPcAddress, target); }else if (node->flags & NACL_EFLAG(ExprUnsignedHex)) { gprintf(file, "0x%"NACL_PRIx64, NaClGetExprUnsignedValue(node)); } else if (node->flags & NACL_EFLAG(ExprSignedHex)) { int64_t val = NaClGetExprSignedValue(node); if (val < 0) { val = -val; gprintf(file, "-0x%"NACL_PRIx64, val); } else { gprintf(file, "0x%"NACL_PRIx64, val); } } else if (node->flags & NACL_EFLAG(ExprUnsignedInt)) { gprintf(file, "%"NACL_PRIu64, NaClGetExprUnsignedValue(node)); } else { /* Assume ExprSignedInt. */ gprintf(file, "%"NACL_PRId64, NaClGetExprSignedValue(node)); } }
/* Returns the 32-bit register for instructions of the form * * and %reg32, MASK * * where MASK is all 1/s except for the alignment mask bits, which must be zero. * * It is assumed that opcode 0x83 is used for the AND operation, and hence, the * mask is a single byte. * * Returns RegUnknown if the instruction doesn't match the form listed above. */ static NaClOpKind NaClGetAndMaskReg32(NaClValidatorState* vstate, size_t distance) { NaClInstState* state; const NaClInst* inst; int op_1, op_2; NaClExpVector* nodes; NaClExp* node; uint8_t mask; NaClOpKind reg32; NaClInstIter* iter = vstate->cur_iter; /* Get the corresponding and instruction. */ if (!NaClInstIterHasLookbackStateInline(iter, distance)) return RegUnknown; state = NaClInstIterGetLookbackStateInline(iter, distance); inst = NaClInstStateInst(state); if ((InstAnd != inst->name) || (state->num_opcode_bytes == 0) || (0x83 != state->bytes.byte[state->num_prefix_bytes])) return RegUnknown; DEBUG(NaClLog(LOG_INFO, "inst(%d): and mask: ", (int) distance); NaClInstStateInstPrint(NaClLogGetGio(), state)); /* Extract the values of the two operands for the and. */ if (!NaClExtractBinaryOperandIndices(state, &op_1, &op_2)) return RegUnknown; /* Extract the destination register of the and. */ nodes = NaClInstStateExpVector(state); node = &nodes->node[op_1]; if (ExprRegister != node->kind) return RegUnknown; reg32 = NaClGetExpRegisterInline(node); DEBUG(NaClLog(LOG_INFO, "and mask reg = %s\n", NaClOpKindName(reg32))); /* Check that the mask is ok. */ mask = NaClGetJumpMask(vstate); DEBUG(NaClLog(LOG_INFO, "mask = %"NACL_PRIx8"\n", mask)); assert(0xf0 == mask || 0xe0 == mask); /* alignment must be either 16 or 32. */ node = &nodes->node[op_2]; /* Technically the operand is a signed value, but "mask" has not been sign * extended, so treat the value as an unsigned byte. */ if (ExprConstant != node->kind || mask != NaClGetExprUnsignedValue(node)) return RegUnknown; DEBUG(NaClLog(LOG_INFO, "is mask constant\n")); return reg32; }
/* Print out the given (memory offset) expression node to the given file. * Returns the index of the node following the given (indexed) memory offset. */ static int NaClPrintDisassembledMemOffset(struct Gio* file, NaClInstState *state, int index) { NaClExpVector* vector = NaClInstStateExpVector(state); int r1_index = index + 1; int r2_index = r1_index + NaClExpWidth(vector, r1_index); int scale_index = r2_index + NaClExpWidth(vector, r2_index); int disp_index = scale_index + NaClExpWidth(vector, scale_index); NaClOpKind r1 = NaClGetExpVectorRegister(vector, r1_index); NaClOpKind r2 = NaClGetExpVectorRegister(vector, r2_index); uint64_t scale = NaClGetExprUnsignedValue(&vector->node[scale_index]); int64_t disp = NaClGetExprSignedValue(&vector->node[disp_index]); assert(ExprMemOffset == vector->node[index].kind); gprintf(file,"["); if (r1 != RegUnknown) { NaClPrintDisassembledRegKind(file, r1); } if (r2 != RegUnknown) { if (r1 != RegUnknown) { gprintf(file, "+"); } NaClPrintDisassembledRegKind(file, r2); gprintf(file, "*%d", (uint32_t) scale); } if (disp != 0) { if ((r1 != RegUnknown || r2 != RegUnknown) && !NaClIsExpNegativeConstant(vector, disp_index)) { gprintf(file, "+"); } /* Recurse to handle print using format flags. */ NaClPrintDisassembledExp(file, state, disp_index); } else if (r1 == RegUnknown && r2 == RegUnknown) { /* be sure to generate case: [0x0]. */ NaClPrintDisassembledExp(file, state, disp_index); } gprintf(file, "]"); return disp_index + NaClExpWidth(vector, disp_index); }
/* Print the given instruction opcode of the give state, to the * given file. */ static void NaClPrintDisassembled(struct Gio* file, NaClInstState* state, const NaClInst* inst) { uint32_t tree_index = 0; Bool is_first = TRUE; Bool not_printed_prefix_segment = TRUE; NaClExp* node; NaClExpVector* vector = NaClInstStateExpVector(state); /* Print the name of the instruction. */ if (NaClHasBit(inst->flags, NACL_IFLAG(PartialInstruction))) { /* Instruction has been simplified. Print out corresponding * hints to the reader, so that they know that the instruction * has been simplified. */ gprintf(file, "[P] "); NaClPrintLower(file, (char*) NaClMnemonicName(inst->name)); if (NaClHasBit(inst->flags, NACL_IFLAG(NaClIllegal))) { gprintf(file, "(illegal)"); } } else { NaClPrintLower(file, (char*) NaClMnemonicName(inst->name)); } /* Use the generated expression tree to print out (non-implicit) operands * of the instruction. */ while (tree_index < vector->number_expr_nodes) { node = &vector->node[tree_index]; if (node->kind != OperandReference || (NACL_EMPTY_EFLAGS == (node->flags & NACL_EFLAG(ExprImplicit)))) { if (is_first) { gprintf(file, " "); is_first = FALSE; } else { gprintf(file, ", "); } NaClPrintDisassembledExp(file, state, tree_index); /* If this is a partial instruction, add set/use information * so that that it is more clear what was matched. */ if (NaClHasBit(inst->flags, NACL_IFLAG(PartialInstruction)) && node->kind == OperandReference) { const NaClOp* op = NaClGetInstOperandInline(state->decoder_tables, inst, (uint8_t) NaClGetExprUnsignedValue(node)); if (NaClHasBit(op->flags, (NACL_OPFLAG(OpSet) | NACL_OPFLAG(OpUse) | NACL_OPFLAG(OperandZeroExtends_v)))) { gprintf(file, " ("); NaClPrintAddOperandFlag(file, op, OpSet, "s"); NaClPrintAddOperandFlag(file, op, OpUse, "u"); NaClPrintAddOperandFlag(file, op, OperandZeroExtends_v, "z"); gprintf(file, ")"); } } } else if (not_printed_prefix_segment && (OperandReference == node->kind) && (node->flags & NACL_EFLAG(ExprImplicit))) { /* Print out segment override of implicit segment address, if * applicable. */ if (OperandReference == node->kind) { int seg_addr_index = tree_index + 1; if (ExprSegmentAddress == vector->node[seg_addr_index].kind) { if (NaClHasSegmentOverride(vector, seg_addr_index, ExprDSrCase, RegDS)) { NaClPrintSegmentOverride(file, &is_first, state, vector, seg_addr_index); } else if (NaClHasSegmentOverride(vector, seg_addr_index, ExprESrCase, RegES)) { NaClPrintSegmentOverride(file, &is_first, state, vector, seg_addr_index); } } } } /* Skip over expression to next expresssion. */ tree_index += NaClExpWidth(vector, tree_index); } }