Offset instrJumpTarget(PC instrs, Offset pos) { Offset* offset = instrJumpOffset(instrs + pos); if (!offset) { return InvalidAbsoluteOffset; } else { return *offset + pos; } }
Offset instrJumpTarget(const Opcode* instrs, Offset pos) { Offset* offset = instrJumpOffset(const_cast<Opcode*>(instrs + pos)); if (!offset) { return InvalidAbsoluteOffset; } else { return *offset + pos; } }
/** * Return the number of successor-edges including fall-through paths but not * implicit exception paths. */ int numSuccs(const Opcode* instr) { if (!instrIsControlFlow(*instr)) return 1; if ((instrFlags(*instr) & TF) != 0) { if (Op(*instr) == OpSwitch) return *(int*)(instr + 1); if (Op(*instr) == OpJmp) return 1; return 0; } if (instrJumpOffset(const_cast<Opcode*>(instr))) return 2; return 1; }
/** * Return the number of successor-edges including fall-through paths but not * implicit exception paths. */ int numSuccs(const Op* instr) { if ((instrFlags(*instr) & TF) != 0) { if (isSwitch(*instr)) { return *(int*)(instr + 1); } if (isUnconditionalJmp(*instr) || *instr == OpIterBreak) return 1; return 0; } if (!instrIsControlFlow(*instr)) return 1; if (instrJumpOffset(const_cast<Op*>(instr))) return 2; return 1; }
/** * Return the number of successor-edges including fall-through paths but not * implicit exception paths. */ int numSuccs(PC const origPC) { auto pc = origPC; auto const op = decode_op(pc); if ((instrFlags(op) & TF) != 0) { if (isSwitch(op)) { return decode_raw<int32_t>(pc); } if (isUnconditionalJmp(op) || op == OpIterBreak) return 1; return 0; } if (!instrIsControlFlow(op)) return 1; if (instrJumpOffset(origPC)) return 2; return 1; }
/* * This function returns the offset of instruction i's branch target. * This is normally the offset corresponding to the branch being * taken. However, if i does not break a trace and it's followed in * the trace by the instruction in the taken branch, then this * function returns the offset of the i's fall-through instruction. * In that case, the invertCond output argument is set to true; * otherwise it's set to false. */ static Offset getBranchTarget(const NormalizedInstruction& i, bool& invertCond) { assert(instrJumpOffset((Op*)(i.pc())) != nullptr); Offset targetOffset = i.offset() + i.imm[1].u_BA; invertCond = false; if (!i.endsRegion && i.nextOffset == targetOffset) { invertCond = true; Offset fallthruOffset = i.offset() + instrLen((Op*)i.pc()); targetOffset = fallthruOffset; } return targetOffset; }
/** * Return the number of successor-edges including fall-through paths but not * implicit exception paths. */ int numSuccs(PC const origPC) { auto pc = origPC; auto const op = decode_op(pc); if ((instrFlags(op) & TF) != 0) { if (isSwitch(op)) { if (op == Op::Switch) { decode_raw<SwitchKind>(pc); // skip bounded flag decode_raw<int64_t>(pc); // skip base } return decode_raw<int32_t>(pc); // vector length } if (isUnconditionalJmp(op) || op == OpIterBreak) return 1; return 0; } if (!instrIsControlFlow(op)) return 1; if (instrJumpOffset(origPC)) return 2; return 1; }
void BCPattern::matchAnchored(const Expr& pattern, PC start, PC end, Result& result) { auto pos = pattern.begin(); for (auto inst = start; inst != end; ) { // Detect a match. if (pos == pattern.end()) { result.m_start = start; result.m_end = inst; return; } auto const op = peek_op(inst); // Skip pattern-globally ignored opcodes. if (m_ignores.count(op)) { inst = next(inst); continue; } // Check for alternations whenever we fail to match. auto nomatch = [&] { if (!pos->hasAlt()) return result.erase(); // Pop the capture if we made one. if (pos->shouldCapture()) { result.m_captures.pop_back(); } for (auto const& atom : pos->getAlt()) { // Construct the full alternate pattern. auto alt = Expr { atom }; alt.insert(alt.end(), std::next(pos), pattern.end()); auto res = result; // Match on the alternate. matchAnchored(alt, inst, end, res); if (res.found()) { result = res; result.m_start = start; return; } } return result.erase(); }; // Capture the atom if desired. if (pos->shouldCapture()) { result.m_captures.push_back(inst); } // Check for shallow match. if (pos->op() != op) { return nomatch(); } auto filter = pos->getFilter(); // Check for deep match if desired. if (filter && !filter(inst, result.m_captures)) { return nomatch(); } if ((pos->op() == Op::JmpZ || pos->op() == Op::JmpNZ)) { // Match the taken block, if there is one. auto off = instrJumpOffset(inst); assert(off); auto res = result; matchAnchored(pos->getTaken(), inst + *off, end, res); if (!res.found()) { return nomatch(); } // Grab the captures. result.m_captures = res.m_captures; } if (pos->hasSeq()) { // Match the subsequence if we have one. auto res = result; matchAnchored(pos->getSeq(), next(inst), end, res); if (!res.found()) { return nomatch(); } // Set the PC. result.m_captures = res.m_captures; inst = res.m_end; } else { // Step the PC. inst = next(inst); } // Step the pattern. ++pos; } // Detect a terminal match. if (pos == pattern.end()) { result.m_start = start; result.m_end = end; } }
Offset instrJumpTarget(PC instrs, Offset pos) { auto offset = instrJumpOffset(instrs + pos); return offset ? *offset + pos : InvalidAbsoluteOffset; }