Esempio n. 1
0
/**
 * Takes two (primitive) coefficients over the same variable, makes them univariate by
 * substituting 0 for other variables (if any). Then it computes the
 * univariate gcd of these. If the coefficients were univariate already, or
 * the result is a constant (i.e. gcd = 1), the result is precise.
 */
int coefficient_gcd_pp_univariate(const lp_polynomial_context_t* ctx,
    coefficient_t* gcd, const coefficient_t* C1, const coefficient_t* C2) {

  assert(C1->type == COEFFICIENT_POLYNOMIAL);
  assert(C2->type == COEFFICIENT_POLYNOMIAL);

  if (trace_is_enabled("coefficient")) {
    tracef("coefficient_gcd_pp_univariate()\n");
    tracef("C1 = "); coefficient_print(ctx, C1, trace_out); tracef("\n");
    tracef("C2 = "); coefficient_print(ctx, C2, trace_out); tracef("\n");
  }

  int C1_vanishes = integer_is_zero(ctx->K, coefficient_get_constant(coefficient_lc(C1)));
  int C2_vanishes = integer_is_zero(ctx->K, coefficient_get_constant(coefficient_lc(C2)));

  if (C1_vanishes || C2_vanishes) {
    // One of C1 or C2 vanishes in the univariate conversion, we're not precise enough
    return 0;
  }

  lp_variable_t x = VAR(C1);
  assert(x == VAR(C2));

  lp_upolynomial_t* C1_u = coefficient_to_univariate(ctx, C1);
  lp_upolynomial_t* C2_u = coefficient_to_univariate(ctx, C2);
  lp_upolynomial_t* gcd_u = lp_upolynomial_gcd(C1_u, C2_u);

  coefficient_t gcd_tmp;
  coefficient_construct_from_univariate(ctx, &gcd_tmp, gcd_u, x);
  coefficient_swap(&gcd_tmp, gcd);
  coefficient_destruct(&gcd_tmp);

  lp_upolynomial_delete(C1_u);
  lp_upolynomial_delete(C2_u);
  lp_upolynomial_delete(gcd_u);

  if (trace_is_enabled("coefficient")) {
    tracef("coefficient_gcd_pp_univariate() => ");
    tracef("gcd = "); coefficient_print(ctx, gcd, trace_out); tracef("\n");
  }

  if (gcd->type == COEFFICIENT_NUMERIC) {
    integer_assign_int(ctx->K, &gcd->value.num, 1);
    return 1;
  } else if (coefficient_is_univariate(C1) && coefficient_is_univariate(C2)) {
    return 1;
  } else {
    return 0;
  }
}
Esempio n. 2
0
void
syscall_intern(struct proc *p)
{

	p->p_trace_enabled = trace_is_enabled(p);
	p->p_md.md_syscall = syscall;
}
Esempio n. 3
0
void coefficient_lcm(const lp_polynomial_context_t* ctx, coefficient_t* lcm, const coefficient_t* C1, const coefficient_t* C2) {
  TRACE("coefficient", "coefficient_lcm()\n");
  STAT(coefficient, lcm) ++;

  if (trace_is_enabled("coefficient")) {
    tracef("C1 = "); coefficient_print(ctx, C1, trace_out); tracef("\n");
    tracef("C2 = "); coefficient_print(ctx, C2, trace_out); tracef("\n");
  }

  assert(ctx->K == lp_Z);

  if (C1->type == COEFFICIENT_NUMERIC && C2->type == COEFFICIENT_NUMERIC) {
    // Integer LCM
    if (lcm->type == COEFFICIENT_POLYNOMIAL) {
      coefficient_destruct(lcm);
      coefficient_construct(ctx, lcm);
    }
    integer_lcm_Z(&lcm->value.num, &C1->value.num, &C2->value.num);
  } else {
    // LCM(C1, C2) = C1*C2/GCD(C1, C2)
    coefficient_t gcd;
    coefficient_construct(ctx, &gcd);
    coefficient_gcd(ctx, &gcd, C1, C2);
    if (coefficient_is_one(ctx, &gcd)) {
      coefficient_mul(ctx, lcm, C1, C2);
    } else {
      if (coefficient_cmp_type(ctx, C1, C2) <= 0) {
        coefficient_div(ctx, lcm, C1, &gcd);
        coefficient_mul(ctx, lcm, lcm, C2);
      } else {
        coefficient_div(ctx, lcm, C2, &gcd);
        coefficient_mul(ctx, lcm, lcm, C1);
      }
    }
    if (coefficient_lc_sgn(ctx, lcm) < 0) {
      coefficient_neg(ctx, lcm, lcm);
    }
    coefficient_destruct(&gcd);
  }

  if (trace_is_enabled("coefficient")) {
    tracef("coefficient_lcm() => "); coefficient_print(ctx, lcm, trace_out); tracef("\n");
  }

  assert(coefficient_is_normalized(ctx, lcm));
}
Esempio n. 4
0
void
EMULNAME(syscall_intern)(struct proc *p)
{
	if (trace_is_enabled(p))
		p->p_md.md_syscall = EMULNAME(syscall_fancy);
	else
		p->p_md.md_syscall = EMULNAME(syscall_plain);
}
Esempio n. 5
0
void
linux_syscall_intern(struct proc *p)
{
	if (trace_is_enabled(p))
		p->p_md.md_syscall = linux_syscall_fancy;
	else
		p->p_md.md_syscall = linux_syscall_plain;
}
Esempio n. 6
0
/** Adapted subresultant GCD */
lp_polynomial_vector_t* coefficient_mgcd_pp_subresultant(const lp_polynomial_context_t* ctx, const coefficient_t* C1, const coefficient_t* C2, const lp_assignment_t* m) {

  // Only for polynomials of the same type
  assert(C1->type == COEFFICIENT_POLYNOMIAL);
  assert(C2->type == COEFFICIENT_POLYNOMIAL);
  assert(coefficient_top_variable(C1) == coefficient_top_variable(C2));

  lp_variable_t x = coefficient_top_variable(C1);

  coefficient_t P, Q, cont;
  coefficient_construct_copy(ctx, &P, C1);
  coefficient_construct_copy(ctx, &Q, C2);
  coefficient_construct(ctx, &cont);

  if (trace_is_enabled("coefficient::mgcd")) {
    tracef("mgcd\n")
    tracef("P = "); coefficient_print(ctx, &P, trace_out); tracef("\n");
    tracef("Q = "); coefficient_print(ctx, &Q, trace_out); tracef("\n");
  }

  lp_polynomial_vector_t* assumptions = lp_polynomial_vector_new(ctx);

  // Get the reductums of P and Q
  coefficient_reductum_m(ctx, &P, &Q, m, assumptions);
  coefficient_reductum_m(ctx, &P, &Q, m, assumptions);

  // Get the primitive parts (reductum includes the sign of cont)
  coefficient_pp_cont(ctx, &P, &cont, &P);
  coefficient_pp_cont(ctx, &Q, &cont, &Q);

  // If one of the coefficient reduces to a constant, we're done
  if (coefficient_top_variable(&P) != x || coefficient_top_variable(&Q) != x) {
    return assumptions;
  }

  // Make sure that P >= Q
  if (SIZE(&P) < SIZE(&Q)) {
    coefficient_swap(&P, &Q);
  }

  coefficient_t R;
  coefficient_construct(ctx, &R);

  coefficient_t h, g;
  coefficient_construct_from_int(ctx, &g, 1);
  coefficient_construct_from_int(ctx, &h, 1);

  coefficient_t tmp1, tmp2;
  coefficient_construct(ctx, &tmp1);
  coefficient_construct(ctx, &tmp2);

  // Subresultant GCD
  //
  do {

    // d = deg(P) - deg(Q)
    assert(SIZE(&P) >= SIZE(&Q));
    unsigned delta = SIZE(&P) - SIZE(&Q);

    // One step reduction
    coefficient_reduce(ctx, &P, &Q, 0, 0, &R, REMAINDERING_PSEUDO_SPARSE);

    if (trace_is_enabled("coefficient::gcd")) {
      tracef("------------\n");
      tracef("P = "); coefficient_print(ctx, &P, trace_out); tracef("\n");
      tracef("Q = "); coefficient_print(ctx, &Q, trace_out); tracef("\n");
      tracef("h = "); coefficient_print(ctx, &h, trace_out); tracef("\n");
      tracef("g = "); coefficient_print(ctx, &g, trace_out); tracef("\n");
      tracef("d = %u\n", delta);
    }

    // Reduce R
    int cmp_type = coefficient_cmp_type(ctx, &Q, &R);
    if (coefficient_cmp_type(ctx, &Q, &R) == 0) {
      // Reduce R and pp
      coefficient_reductum_m(ctx, &R, &R, m, assumptions);
      coefficient_pp_cont(ctx, &R, &cont, &R);
    } else {
      assert(cmp_type > 0);
    }

    // We continue if x still there
    cmp_type = coefficient_cmp_type(ctx, &Q, &R);
    if (cmp_type == 0) {
      // P = Q
      coefficient_swap(&P, &Q);
      // Q = R/g*(h^delta)
      coefficient_div(ctx, &tmp1, &R, &g);
      coefficient_pow(ctx, &tmp2, &h, delta);
      coefficient_div(ctx, &Q, &tmp1, &tmp2);
      // g = lc(P)
      coefficient_assign(ctx, &g, coefficient_lc(&P));
      // h = h^(1-delta)*g^delta
      if (delta == 0) {
        // h = h, nothing to do
      } else if (delta == 1) {
        // h = g
        coefficient_assign(ctx, &h, &g);
      } else {
        // h = g^delta/h^(delta-1))
        coefficient_pow(ctx, &tmp1, &g, delta);
        coefficient_pow(ctx, &tmp2, &h, delta-1);
        coefficient_div(ctx, &h, &tmp1, &tmp2);
      }
    } else {
      assert(cmp_type > 0);
      if (!coefficient_is_constant(&R)) {
        lp_polynomial_vector_push_back_coeff(assumptions, &R);
      }
      break;
    }
  } while (1);

  coefficient_destruct(&R);
  coefficient_destruct(&h);
  coefficient_destruct(&g);
  coefficient_destruct(&tmp1);
  coefficient_destruct(&tmp2);
  coefficient_destruct(&cont);
  coefficient_destruct(&P);
  coefficient_destruct(&Q);

  return assumptions;
}
Esempio n. 7
0
lp_polynomial_vector_t* coefficient_mgcd_primitive(const lp_polynomial_context_t* ctx, const coefficient_t* C1, const coefficient_t* C2, const lp_assignment_t* m) {

  // Only for polynomials of the same type
  assert(C1->type == COEFFICIENT_POLYNOMIAL);
  assert(C2->type == COEFFICIENT_POLYNOMIAL);
  assert(coefficient_top_variable(C1) == coefficient_top_variable(C2));

  TRACE("coefficient", "coefficient_mgcd_primitive()\n");

  if (trace_is_enabled("coefficient")) {
    tracef("C1 = "); coefficient_print(ctx, C1, trace_out); tracef("\n");
    tracef("C2 = "); coefficient_print(ctx, C2, trace_out); tracef("\n");
  }

  lp_variable_t x = coefficient_top_variable(C1);

  coefficient_t A, B, P, R, cont;
  coefficient_construct_copy(ctx, &A, C1);
  coefficient_construct_copy(ctx, &B, C2);
  coefficient_construct(ctx, &P);
  coefficient_construct(ctx, &R);
  coefficient_construct(ctx, &cont);

  lp_polynomial_vector_t* assumptions = lp_polynomial_vector_new(ctx);

  // Get the reductums of A and B
  coefficient_reductum_m(ctx, &A, &A, m, assumptions);
  coefficient_reductum_m(ctx, &B, &B, m, assumptions);

  // Get the primitive parts (reductum includes the sign of cont)
  coefficient_pp_cont(ctx, &A, &cont, &A);
  coefficient_pp_cont(ctx, &B, &cont, &B);

  // If one of the coefficient reduces to a constant, we're done
  if (coefficient_top_variable(&A) != x || coefficient_top_variable(&B) != x) {
    return assumptions;
  }

  // Swap A and B if def(A) < deg(B)
  if (coefficient_degree(&A) < coefficient_degree(&B)) {
    coefficient_swap(&A, &B);
  }

  //
  // We compute the reduction of A and B in Z[y, x], i.e.
  //
  //   P*A = Q*B + R
  //
  // with P in Z[y], Q in Z[y, x], and deg(R) < deg(B) or deg(R) == 0.
  //
  // We keep the accumulating the assumptions of the reduction and keep A, B, R
  // such reduced my model and primitive.
  //
  do {

    if (trace_is_enabled("coefficient::mgcd")) {
      tracef("A = "); coefficient_print(ctx, &A, trace_out); tracef("\n");
      tracef("B = "); coefficient_print(ctx, &B, trace_out); tracef("\n");
    }

    // One step reduction, we get P*A = Q*B + R
    // If A, B have a common zero, this is also a zero of R (if R is in x)
    // If B, R have a common zero, this is also a zero of A if P != 0
    coefficient_reduce(ctx, &A, &B, &P, 0, &R, REMAINDERING_LCM_SPARSE);

    // Reduce R
    if (coefficient_cmp_type(ctx, &B, &R) == 0) {
      // Reduce R and pp
      coefficient_reductum_m(ctx, &R, &R, m, assumptions);
      coefficient_pp_cont(ctx, &R, &cont, &R);
    }

    // We continue if we didn't get a 'constant'
    int cmp_type = coefficient_cmp_type(ctx, &B, &R);
    if (cmp_type == 0) {
       // A = B, B = R (already reduced)
      coefficient_swap(&A, &B);
      coefficient_swap(&B, &R);
    } else {
      // Got to the GCD, but we need to maintain the sign of R
      if (!coefficient_is_constant(&R)) {
        lp_polynomial_vector_push_back_coeff(assumptions, &R);
      }
      break;
    }
  } while (1);

  // Return the assumptions
  return assumptions;
}
Esempio n. 8
0
void coefficient_pp_cont(const lp_polynomial_context_t* ctx, coefficient_t* pp, coefficient_t* cont, const coefficient_t* C) {

  TRACE("coefficient", "coefficient_pp_cont()\n");
  STAT(coefficient, pp_cont) ++;

  if (trace_is_enabled("coefficient")) {
    tracef("C = "); coefficient_print(ctx, C, trace_out); tracef("\n");
  }

  assert(ctx->K == lp_Z);

  int special = coefficient_pp_cont_special(ctx, pp, cont, C);
  if (special) {
    return;
  }

  switch (C->type) {
  case COEFFICIENT_NUMERIC:
    if (cont) {
      if (cont->type == COEFFICIENT_POLYNOMIAL) {
        coefficient_destruct(cont);
        coefficient_construct_copy(ctx, cont, C);
      } else {
        integer_assign(ctx->K, &cont->value.num, &C->value.num);
      }
    }
    if (pp) {
      if (pp->type == COEFFICIENT_POLYNOMIAL) {
        coefficient_destruct(pp);
        coefficient_construct_from_int(ctx, pp, 1);
      } else {
        integer_assign_int(ctx->K, &pp->value.num, 1);
      }
    }
    break;
  case COEFFICIENT_POLYNOMIAL:
  {
    int i;
    coefficient_t gcd;
    // Compute the gcd of coefficients starting with LC
    coefficient_construct_copy(ctx, &gcd, coefficient_lc(C));
    // Make if positive in case it's the only one
    if (coefficient_lc_sgn(ctx, &gcd) < 0) {
      coefficient_neg(ctx, &gcd, &gcd);
    }
    // Compute the rest of the gcd
    for (i = SIZE(C)-2; i >= 0 ; -- i) {
      if (!coefficient_is_zero(ctx, COEFF(C, i))) {
        coefficient_gcd(ctx, &gcd, &gcd, COEFF(C, i));
        if (coefficient_is_one(ctx, &gcd)) {
          break;
        }
      }
    }
    // GCD is positive, so if the leading coefficient of C is negative, flip it
    if (coefficient_lc_sgn(ctx, C) < 0) {
      coefficient_neg(ctx, &gcd, &gcd);
    }

    if (pp) {
      // Now compute the pp
      coefficient_div(ctx, pp, C, &gcd);
      assert(coefficient_is_normalized(ctx, pp));
    }
    if (cont) {
      coefficient_swap(&gcd, cont);
      assert(coefficient_is_normalized(ctx, cont));
    }
    coefficient_destruct(&gcd);
    break;
  }
  default:
    assert(0);
    break;
  }

  if (trace_is_enabled("coefficient")) {
    tracef("coefficient_pp_cont() => ");
    if (pp) { tracef("pp = "); coefficient_print(ctx, pp, trace_out); tracef("\n"); }
    if (cont) { tracef("cont = "); coefficient_print(ctx, cont, trace_out); tracef("\n"); }
  }
}
Esempio n. 9
0
/**
 * Extracts the largest monomial power out of P and Q and into gcd, also divide.
 * For example, P and Q in Z[y, x]
 *
 *  P = 4*y*x^2 + 2*y^2 = 2*y^2*(2*x^2 + 1)
 *  Q = 2*y^3*x^3
 *
 * gives
 *
 *  gcd = 2*y^2
 *  P = 2*x^2 + 1
 *  Q = 2*y*x^3
 */
void coefficient_gcd_monomial_extract(const lp_polynomial_context_t* ctx, coefficient_t* gcd, coefficient_t* P, coefficient_t* Q) {

  TRACE("coefficient", "coefficient_gcd_monomial_extract()\n");

  if (trace_is_enabled("coefficient")) {
    tracef("P = "); coefficient_print(ctx, P, trace_out); tracef("\n");
    tracef("Q = "); coefficient_print(ctx, Q, trace_out); tracef("\n");
  }

  assert(P != Q);

  lp_monomial_t m_P_gcd, m_Q_gcd, m_tmp;
  lp_monomial_construct(ctx, &m_P_gcd);
  lp_monomial_construct(ctx, &m_Q_gcd);
  lp_monomial_construct(ctx, &m_tmp);

  // Compute the gcd
  coefficient_traverse(ctx, P, monomial_gcd_visit, &m_tmp, &m_P_gcd);
  lp_monomial_clear(ctx, &m_tmp);
  coefficient_traverse(ctx, Q, monomial_gcd_visit, &m_tmp, &m_Q_gcd);

  if (trace_is_enabled("coefficient")) {
    tracef("P_gcd = "); monomial_print(ctx, &m_P_gcd, trace_out); tracef("\n");
    tracef("Q_gcd = "); monomial_print(ctx, &m_Q_gcd, trace_out); tracef("\n");
  }

  // Final gcd
  lp_monomial_t m_gcd;
  lp_monomial_construct(ctx, &m_gcd);
  lp_monomial_gcd(ctx, &m_gcd, &m_P_gcd, &m_Q_gcd);

  // Construct the result
  coefficient_t result;
  coefficient_construct(ctx, &result);
  coefficient_add_ordered_monomial(ctx, &m_gcd, &result);

  // Divide P and Q with their gcds
  coefficient_t P_gcd, Q_gcd;
  coefficient_construct(ctx, &P_gcd);
  coefficient_construct(ctx, &Q_gcd);
  coefficient_add_ordered_monomial(ctx, &m_P_gcd, &P_gcd);
  coefficient_add_ordered_monomial(ctx, &m_Q_gcd, &Q_gcd);
  coefficient_div(ctx, P, P, &P_gcd);
  coefficient_div(ctx, Q, Q, &Q_gcd);
  coefficient_destruct(&P_gcd);
  coefficient_destruct(&Q_gcd);

  // Output the result
  coefficient_swap(&result, gcd);
  coefficient_destruct(&result);

  lp_monomial_destruct(&m_gcd);
  lp_monomial_destruct(&m_tmp);
  lp_monomial_destruct(&m_Q_gcd);
  lp_monomial_destruct(&m_P_gcd);

  if (trace_is_enabled("coefficient")) {
    tracef("coefficient_gcd_monomial_extract() =>"); coefficient_print(ctx, gcd, trace_out); tracef("\n");
    tracef("P = "); coefficient_print(ctx, P, trace_out); tracef("\n");
    tracef("Q = "); coefficient_print(ctx, Q, trace_out); tracef("\n");
  }
}
Esempio n. 10
0
void coefficient_gcd(const lp_polynomial_context_t* ctx, coefficient_t* gcd, const coefficient_t* C1, const coefficient_t* C2) {
  TRACE("coefficient", "coefficient_gcd()\n");
  STAT(coefficient, gcd) ++;

  if (trace_is_enabled("coefficient")) {
    tracef("C1 = "); coefficient_print(ctx, C1, trace_out); tracef("\n");
    tracef("C2 = "); coefficient_print(ctx, C2, trace_out); tracef("\n");
  }

  assert(ctx->K == lp_Z);

  int cmp_type = coefficient_cmp_type(ctx, C1, C2);

  if (cmp_type < 0) {
    const coefficient_t* tmp = C1;
    C1 = C2;
    C2 = tmp;
    cmp_type = -cmp_type;
  }

  if (cmp_type == 0) {
    switch (C1->type) {
    case COEFFICIENT_NUMERIC:
      if (gcd->type == COEFFICIENT_POLYNOMIAL) {
        coefficient_destruct(gcd);
        coefficient_construct(ctx, gcd);
      }
      integer_gcd_Z(&gcd->value.num, &C1->value.num, &C2->value.num);
      break;
    case COEFFICIENT_POLYNOMIAL:
    {
      coefficient_t P, Q;
      if (SIZE(C1) > SIZE(C2)) {
        coefficient_construct_copy(ctx, &P, C1);
        coefficient_construct_copy(ctx, &Q, C2);
      } else {
        coefficient_construct_copy(ctx, &P, C2);
        coefficient_construct_copy(ctx, &Q, C1);
      }

      // Get the common power variables out
      coefficient_t gcd_mon;
      coefficient_construct(ctx, &gcd_mon);
      coefficient_gcd_monomial_extract(ctx, &gcd_mon, &P, &Q);

      // If monomial extraction changed the type, we need to go again
      if (coefficient_cmp_type(ctx, C1, &P) != 0 || coefficient_cmp_type(ctx, C2, &Q) != 0) {
        coefficient_gcd(ctx, gcd, &P, &Q);
      } else {
        // Normalize the P and Q to be primitive (and keep the content)
        coefficient_t P_cont, Q_cont;
        coefficient_construct(ctx, &P_cont);
        coefficient_construct(ctx, &Q_cont);
        coefficient_pp_cont(ctx, &P, &P_cont, &P);
        coefficient_pp_cont(ctx, &Q, &Q_cont, &Q);

        // Get the gcd of the content
        coefficient_t gcd_cont;
        coefficient_construct(ctx, &gcd_cont);
        coefficient_gcd(ctx, &gcd_cont, &P_cont, &Q_cont);

        // Get the gcd of the primitive parts
        coefficient_gcd_pp_euclid(ctx, gcd, &P, &Q);

        // Multiply in the content gcd
        coefficient_mul(ctx, gcd, gcd, &gcd_cont);

        coefficient_destruct(&P_cont);
        coefficient_destruct(&Q_cont);
        coefficient_destruct(&gcd_cont);
      }

      // Multiply in the monomial gcd
      coefficient_mul(ctx, gcd, gcd, &gcd_mon);

      // Remove temps
      coefficient_destruct(&P);
      coefficient_destruct(&Q);
      coefficient_destruct(&gcd_mon);
      break;
    }
    default:
      assert(0);
      break;
    }
  } else {
    // C1 in Z[y, x]
    // C2 in Z[y]
    // so GCD(C1, C2) = GCD(cont(C1), C2)
    coefficient_t cont;
    coefficient_construct(ctx, &cont);
    coefficient_cont(ctx, &cont, C1);
    coefficient_gcd(ctx, gcd, &cont, C2);
    coefficient_destruct(&cont);
  }

  if (trace_is_enabled("coefficient")) {
    tracef("coefficient_gcd() => "); coefficient_print(ctx, gcd, trace_out); tracef("\n");
  }

  if (trace_is_enabled("coefficient::gcd::sage")) {
    tracef("C1 = "); coefficient_print(ctx, C1, trace_out); tracef("\n");
    tracef("C2 = "); coefficient_print(ctx, C2, trace_out); tracef("\n");
    tracef("gcd = "); coefficient_print(ctx, gcd, trace_out); tracef("\n");
    tracef("gcd_sage = C1.gcd(C2)\n");
    tracef("if (gcd != gcd_sage):\n");
    tracef("\tprint 'C1 =', C1\n");
    tracef("\tprint 'C2 =', C2\n");
  }

  assert(coefficient_is_normalized(ctx, gcd));
}
Esempio n. 11
0
/**
 * Compute the gcd of two primitive polynomials P and Q. The polynomials P and
 * Q will be used and changed in the computation.
 */
void coefficient_gcd_pp_subresultant(const lp_polynomial_context_t* ctx, coefficient_t* gcd, coefficient_t* P, coefficient_t* Q) {

  TRACE("coefficient", "coefficient_gcd_pp_euclid()\n");
  STAT(coefficient, gcd_pp_subresultant) ++;

  if (trace_is_enabled("coefficient::gcd")) {
    tracef("gcd\n")
    tracef("P = "); coefficient_print(ctx, P, trace_out); tracef("\n");
    tracef("Q = "); coefficient_print(ctx, Q, trace_out); tracef("\n");
  }

  // Try to compute the univariate GCD first
  coefficient_t gcd_u;
  coefficient_construct(ctx, &gcd_u);

  int precise = coefficient_gcd_pp_univariate(ctx, &gcd_u, P, Q);
  if (precise) {
    // GCD = 1, just copy the univariate gcd
    coefficient_swap(gcd, &gcd_u);
  } else {

    // Make sure that P >= Q
    if (SIZE(P) < SIZE(Q)) {
      coefficient_t* tmp = P; P = Q; Q = tmp;
    }

    coefficient_t R;
    coefficient_construct(ctx, &R);

    coefficient_t h, g;
    coefficient_construct_from_int(ctx, &g, 1);
    coefficient_construct_from_int(ctx, &h, 1);

    coefficient_t tmp1, tmp2;
    coefficient_construct(ctx, &tmp1);
    coefficient_construct(ctx, &tmp2);

    // Subresultant GCD
    //
    do {

      // d = deg(P) - deg(Q)
      assert(SIZE(P) >= SIZE(Q));
      unsigned delta = SIZE(P) - SIZE(Q);

      // One step reduction
      coefficient_reduce(ctx, P, Q, 0, 0, &R, REMAINDERING_PSEUDO_SPARSE);

      if (trace_is_enabled("coefficient::gcd")) {
        tracef("------------\n");
        tracef("P = "); coefficient_print(ctx, P, trace_out); tracef("\n");
        tracef("Q = "); coefficient_print(ctx, Q, trace_out); tracef("\n");
        tracef("h = "); coefficient_print(ctx, &h, trace_out); tracef("\n");
        tracef("g = "); coefficient_print(ctx, &g, trace_out); tracef("\n");
        tracef("d = %u\n", delta);
      }

      int cmp_type = coefficient_cmp_type(ctx, Q, &R);
      if (cmp_type == 0) {
        // P = Q
        coefficient_swap(P, Q);
        // Q = R/g*(h^delta)
        coefficient_div(ctx, &tmp1, &R, &g);
        coefficient_pow(ctx, &tmp2, &h, delta);
        coefficient_div(ctx, Q, &tmp1, &tmp2);
        // g = lc(P)
        coefficient_assign(ctx, &g, coefficient_lc(P));
        // h = h^(1-delta)*g^delta
        if (delta == 0) {
          // h = h, nothing to do
        } else if (delta == 1) {
          // h = g
          coefficient_assign(ctx, &h, &g);
        } else {
          // h = g^delta/h^(delta-1))
          coefficient_pow(ctx, &tmp1, &g, delta);
          coefficient_pow(ctx, &tmp2, &h, delta-1);
          coefficient_div(ctx, &h, &tmp1, &tmp2);
        }
      } else {
        assert(cmp_type > 0);
        if (!coefficient_is_zero(ctx, &R)) {
          coefficient_destruct(Q);
          coefficient_construct_from_int(ctx, Q, 1);
        } else {
          coefficient_pp(ctx, Q, Q);
        }
        break;
      }
    } while (1);

    coefficient_swap(Q, gcd);
    coefficient_destruct(&R);

    coefficient_destruct(&h);
    coefficient_destruct(&g);
    coefficient_destruct(&tmp1);
    coefficient_destruct(&tmp2);
  }

  coefficient_destruct(&gcd_u);

  if (trace_is_enabled("coefficient")) {
    tracef("coefficient_gcd_pp() => "); coefficient_print(ctx, gcd, trace_out); tracef("\n");
  }
}
Esempio n. 12
0
/**
 * Compute the gcd of two primitive polynomials P and Q. The polynomials P and
 * Q will be used and changed in the computation.
 */
void coefficient_gcd_pp_euclid(const lp_polynomial_context_t* ctx, coefficient_t* gcd, coefficient_t* P, coefficient_t* Q) {

  TRACE("coefficient", "coefficient_gcd_pp()\n");
  STAT(coefficient, gcd_pp_euclid) ++;

  if (trace_is_enabled("coefficient::gcd")) {
    tracef("gcd\n")
    tracef("P = "); coefficient_print(ctx, P, trace_out); tracef("\n");
    tracef("Q = "); coefficient_print(ctx, Q, trace_out); tracef("\n");
  }

  // Try to compute the univariate GCD first
  coefficient_t gcd_u;
  coefficient_construct(ctx, &gcd_u);

  int precise = coefficient_gcd_pp_univariate(ctx, &gcd_u, P, Q);
  if (precise) {
    // GCD = 1, just copy the univariate gcd
    coefficient_swap(gcd, &gcd_u);
  } else {

    coefficient_t R;
    coefficient_construct(ctx, &R);

    //
    // We compute the reduction of P and Q in Z[y, x], i.e.
    //
    //   a*P = b*Q + R
    //
    // with a in Z[y], b in Z[y, x], and deg(R) < deg(Q) or deg(R) == 0.
    //
    // P and Q are primitive so GCD(P, Q) should be primitive, i.e. in
    // Z[y, x] or 1. therefore GCD(P, Q) = 1 if R != 0, or
    // GCD(P, Q) = po(Q) if R = 0
    //
    do {

      // One step reduction
      coefficient_reduce(ctx, P, Q, 0, 0, &R, REMAINDERING_PSEUDO_SPARSE);

      int cmp_type = coefficient_cmp_type(ctx, Q, &R);
      if (cmp_type == 0) {
        // P = Q
        // Q = pp(R)
        coefficient_swap(P, Q);
        coefficient_swap(Q, &R);
        coefficient_pp(ctx, Q, Q);
      } else {
        assert(cmp_type > 0);
        if (!coefficient_is_zero(ctx, &R)) {
          coefficient_destruct(Q);
          coefficient_construct_from_int(ctx, Q, 1);
        }
        break;
      }
    } while (1);

    coefficient_swap(Q, gcd);
    coefficient_destruct(&R);
  }

  coefficient_destruct(&gcd_u);

  if (trace_is_enabled("coefficient")) {
    tracef("coefficient_gcd_pp() => "); coefficient_print(ctx, gcd, trace_out); tracef("\n");
  }
}
Esempio n. 13
0
bool teb_tracer::enabled() const
{
	return trace_is_enabled( "tebshm" );
}
Esempio n. 14
0
/*
 * Process debugging system call.
 */
int
sys_ptrace(struct lwp *l, const struct sys_ptrace_args *uap, register_t *retval)
{
	/* {
		syscallarg(int) req;
		syscallarg(pid_t) pid;
		syscallarg(void *) addr;
		syscallarg(int) data;
	} */
	struct proc *p = l->l_proc;
	struct lwp *lt;
	struct proc *t;				/* target process */
	struct uio uio;
	struct iovec iov;
	struct ptrace_io_desc piod;
	struct ptrace_lwpinfo pl;
	struct vmspace *vm;
	int error, write, tmp, req, pheld;
	int signo;
	ksiginfo_t ksi;
#ifdef COREDUMP
	char *path;
#endif

	error = 0;
	req = SCARG(uap, req);

	/*
	 * If attaching or detaching, we need to get a write hold on the
	 * proclist lock so that we can re-parent the target process.
	 */
	mutex_enter(proc_lock);

	/* "A foolish consistency..." XXX */
	if (req == PT_TRACE_ME) {
		t = p;
		mutex_enter(t->p_lock);
	} else {
		/* Find the process we're supposed to be operating on. */
		if ((t = p_find(SCARG(uap, pid), PFIND_LOCKED)) == NULL) {
			mutex_exit(proc_lock);
			return (ESRCH);
		}

		/* XXX-elad */
		mutex_enter(t->p_lock);
		error = kauth_authorize_process(l->l_cred, KAUTH_PROCESS_CANSEE,
		    t, KAUTH_ARG(KAUTH_REQ_PROCESS_CANSEE_ENTRY), NULL, NULL);
		if (error) {
			mutex_exit(proc_lock);
			mutex_exit(t->p_lock);
			return (ESRCH);
		}
	}

	/*
	 * Grab a reference on the process to prevent it from execing or
	 * exiting.
	 */
	if (!rw_tryenter(&t->p_reflock, RW_READER)) {
		mutex_exit(proc_lock);
		mutex_exit(t->p_lock);
		return EBUSY;
	}

	/* Make sure we can operate on it. */
	switch (req) {
	case  PT_TRACE_ME:
		/* Saying that you're being traced is always legal. */
		break;

	case  PT_ATTACH:
		/*
		 * You can't attach to a process if:
		 *	(1) it's the process that's doing the attaching,
		 */
		if (t->p_pid == p->p_pid) {
			error = EINVAL;
			break;
		}

		/*
		 *  (2) it's a system process
		 */
		if (t->p_flag & PK_SYSTEM) {
			error = EPERM;
			break;
		}

		/*
		 *	(3) it's already being traced, or
		 */
		if (ISSET(t->p_slflag, PSL_TRACED)) {
			error = EBUSY;
			break;
		}

		/*
		 * 	(4) the tracer is chrooted, and its root directory is
		 * 	    not at or above the root directory of the tracee
		 */
		mutex_exit(t->p_lock);	/* XXXSMP */
		tmp = proc_isunder(t, l);
		mutex_enter(t->p_lock);	/* XXXSMP */
		if (!tmp) {
			error = EPERM;
			break;
		}
		break;

	case  PT_READ_I:
	case  PT_READ_D:
	case  PT_WRITE_I:
	case  PT_WRITE_D:
	case  PT_IO:
#ifdef PT_GETREGS
	case  PT_GETREGS:
#endif
#ifdef PT_SETREGS
	case  PT_SETREGS:
#endif
#ifdef PT_GETFPREGS
	case  PT_GETFPREGS:
#endif
#ifdef PT_SETFPREGS
	case  PT_SETFPREGS:
#endif
#ifdef __HAVE_PTRACE_MACHDEP
	PTRACE_MACHDEP_REQUEST_CASES
#endif
		/*
		 * You can't read/write the memory or registers of a process
		 * if the tracer is chrooted, and its root directory is not at
		 * or above the root directory of the tracee.
		 */
		mutex_exit(t->p_lock);	/* XXXSMP */
		tmp = proc_isunder(t, l);
		mutex_enter(t->p_lock);	/* XXXSMP */
		if (!tmp) {
			error = EPERM;
			break;
		}
		/*FALLTHROUGH*/

	case  PT_CONTINUE:
	case  PT_KILL:
	case  PT_DETACH:
	case  PT_LWPINFO:
	case  PT_SYSCALL:
#ifdef COREDUMP
	case  PT_DUMPCORE:
#endif
#ifdef PT_STEP
	case  PT_STEP:
#endif
		/*
		 * You can't do what you want to the process if:
		 *	(1) It's not being traced at all,
		 */
		if (!ISSET(t->p_slflag, PSL_TRACED)) {
			error = EPERM;
			break;
		}

		/*
		 *	(2) it's being traced by procfs (which has
		 *	    different signal delivery semantics),
		 */
		if (ISSET(t->p_slflag, PSL_FSTRACE)) {
			uprintf("file system traced\n");
			error = EBUSY;
			break;
		}

		/*
		 *	(3) it's not being traced by _you_, or
		 */
		if (t->p_pptr != p) {
			uprintf("parent %d != %d\n", t->p_pptr->p_pid, p->p_pid);
			error = EBUSY;
			break;
		}

		/*
		 *	(4) it's not currently stopped.
		 */
		if (t->p_stat != SSTOP || !t->p_waited /* XXXSMP */) {
			uprintf("stat %d flag %d\n", t->p_stat,
			    !t->p_waited);
			error = EBUSY;
			break;
		}
		break;

	default:			/* It was not a legal request. */
		error = EINVAL;
		break;
	}

	if (error == 0)
		error = kauth_authorize_process(l->l_cred,
		    KAUTH_PROCESS_PTRACE, t, KAUTH_ARG(req),
		    NULL, NULL);

	if (error != 0) {
		mutex_exit(proc_lock);
		mutex_exit(t->p_lock);
		rw_exit(&t->p_reflock);
		return error;
	}

	/* Do single-step fixup if needed. */
	FIX_SSTEP(t);

	/*
	 * XXX NJWLWP
	 *
	 * The entire ptrace interface needs work to be useful to a
	 * process with multiple LWPs. For the moment, we'll kluge
	 * this; memory access will be fine, but register access will
	 * be weird.
	 */
	lt = LIST_FIRST(&t->p_lwps);
	KASSERT(lt != NULL);
	lwp_addref(lt);

	/*
	 * Which locks do we need held? XXX Ugly.
	 */
	switch (req) {
#ifdef PT_STEP
	case PT_STEP:
#endif
	case PT_CONTINUE:
	case PT_DETACH:
	case PT_KILL:
	case PT_SYSCALL:
	case PT_ATTACH:
	case PT_TRACE_ME:
		pheld = 1;
		break;
	default:
		mutex_exit(proc_lock);
		mutex_exit(t->p_lock);
		pheld = 0;
		break;
	}

	/* Now do the operation. */
	write = 0;
	*retval = 0;
	tmp = 0;

	switch (req) {
	case  PT_TRACE_ME:
		/* Just set the trace flag. */
		SET(t->p_slflag, PSL_TRACED);
		t->p_opptr = t->p_pptr;
		break;

	case  PT_WRITE_I:		/* XXX no separate I and D spaces */
	case  PT_WRITE_D:
#if defined(__HAVE_RAS)
		/*
		 * Can't write to a RAS
		 */
		if (ras_lookup(t, SCARG(uap, addr)) != (void *)-1) {
			error = EACCES;
			break;
		}
#endif
		write = 1;
		tmp = SCARG(uap, data);
		/* FALLTHROUGH */

	case  PT_READ_I:		/* XXX no separate I and D spaces */
	case  PT_READ_D:
		/* write = 0 done above. */
		iov.iov_base = (void *)&tmp;
		iov.iov_len = sizeof(tmp);
		uio.uio_iov = &iov;
		uio.uio_iovcnt = 1;
		uio.uio_offset = (off_t)(unsigned long)SCARG(uap, addr);
		uio.uio_resid = sizeof(tmp);
		uio.uio_rw = write ? UIO_WRITE : UIO_READ;
		UIO_SETUP_SYSSPACE(&uio);

		error = process_domem(l, lt, &uio);
		if (!write)
			*retval = tmp;
		break;

	case  PT_IO:
		error = copyin(SCARG(uap, addr), &piod, sizeof(piod));
		if (error)
			break;
		switch (piod.piod_op) {
		case PIOD_READ_D:
		case PIOD_READ_I:
			uio.uio_rw = UIO_READ;
			break;
		case PIOD_WRITE_D:
		case PIOD_WRITE_I:
			/*
			 * Can't write to a RAS
			 */
			if (ras_lookup(t, SCARG(uap, addr)) != (void *)-1) {
				return (EACCES);
			}
			uio.uio_rw = UIO_WRITE;
			break;
		default:
			error = EINVAL;
			break;
		}
		if (error)
			break;
		error = proc_vmspace_getref(l->l_proc, &vm);
		if (error)
			break;
		iov.iov_base = piod.piod_addr;
		iov.iov_len = piod.piod_len;
		uio.uio_iov = &iov;
		uio.uio_iovcnt = 1;
		uio.uio_offset = (off_t)(unsigned long)piod.piod_offs;
		uio.uio_resid = piod.piod_len;
		uio.uio_vmspace = vm;

		error = process_domem(l, lt, &uio);
		piod.piod_len -= uio.uio_resid;
		(void) copyout(&piod, SCARG(uap, addr), sizeof(piod));
		uvmspace_free(vm);
		break;

#ifdef COREDUMP
	case  PT_DUMPCORE:
		if ((path = SCARG(uap, addr)) != NULL) {
			char *dst;
			int len = SCARG(uap, data);
			if (len < 0 || len >= MAXPATHLEN) {
				error = EINVAL;
				break;
			}
			dst = malloc(len + 1, M_TEMP, M_WAITOK);
			if ((error = copyin(path, dst, len)) != 0) {
				free(dst, M_TEMP);
				break;
			}
			path = dst;
			path[len] = '\0';
		}
		error = coredump(lt, path);
		if (path)
			free(path, M_TEMP);
		break;
#endif

#ifdef PT_STEP
	case  PT_STEP:
		/*
		 * From the 4.4BSD PRM:
		 * "Execution continues as in request PT_CONTINUE; however
		 * as soon as possible after execution of at least one
		 * instruction, execution stops again. [ ... ]"
		 */
#endif
	case  PT_CONTINUE:
	case  PT_SYSCALL:
	case  PT_DETACH:
		if (req == PT_SYSCALL) {
			if (!ISSET(t->p_slflag, PSL_SYSCALL)) {
				SET(t->p_slflag, PSL_SYSCALL);
#ifdef __HAVE_SYSCALL_INTERN
				(*t->p_emul->e_syscall_intern)(t);
#endif
			}
		} else {
			if (ISSET(t->p_slflag, PSL_SYSCALL)) {
				CLR(t->p_slflag, PSL_SYSCALL);
#ifdef __HAVE_SYSCALL_INTERN
				(*t->p_emul->e_syscall_intern)(t);
#endif
			}
		}
		p->p_trace_enabled = trace_is_enabled(p);

		/*
		 * From the 4.4BSD PRM:
		 * "The data argument is taken as a signal number and the
		 * child's execution continues at location addr as if it
		 * incurred that signal.  Normally the signal number will
		 * be either 0 to indicate that the signal that caused the
		 * stop should be ignored, or that value fetched out of
		 * the process's image indicating which signal caused
		 * the stop.  If addr is (int *)1 then execution continues
		 * from where it stopped."
		 */

		/* Check that the data is a valid signal number or zero. */
		if (SCARG(uap, data) < 0 || SCARG(uap, data) >= NSIG) {
			error = EINVAL;
			break;
		}

		uvm_lwp_hold(lt);

		/* If the address parameter is not (int *)1, set the pc. */
		if ((int *)SCARG(uap, addr) != (int *)1)
			if ((error = process_set_pc(lt, SCARG(uap, addr))) != 0) {
				uvm_lwp_rele(lt);
				break;
			}

#ifdef PT_STEP
		/*
		 * Arrange for a single-step, if that's requested and possible.
		 */
		error = process_sstep(lt, req == PT_STEP);
		if (error) {
			uvm_lwp_rele(lt);
			break;
		}
#endif

		uvm_lwp_rele(lt);

		if (req == PT_DETACH) {
			CLR(t->p_slflag, PSL_TRACED|PSL_FSTRACE|PSL_SYSCALL);

			/* give process back to original parent or init */
			if (t->p_opptr != t->p_pptr) {
				struct proc *pp = t->p_opptr;
				proc_reparent(t, pp ? pp : initproc);
			}

			/* not being traced any more */
			t->p_opptr = NULL;
		}

		signo = SCARG(uap, data);
	sendsig:
		/* Finally, deliver the requested signal (or none). */
		if (t->p_stat == SSTOP) {
			/*
			 * Unstop the process.  If it needs to take a
			 * signal, make all efforts to ensure that at
			 * an LWP runs to see it.
			 */
			t->p_xstat = signo;
			proc_unstop(t);
		} else if (signo != 0) {
			KSI_INIT_EMPTY(&ksi);
			ksi.ksi_signo = signo;
			kpsignal2(t, &ksi);
		}
		break;

	case  PT_KILL:
		/* just send the process a KILL signal. */
		signo = SIGKILL;
		goto sendsig;	/* in PT_CONTINUE, above. */

	case  PT_ATTACH:
		/*
		 * Go ahead and set the trace flag.
		 * Save the old parent (it's reset in
		 *   _DETACH, and also in kern_exit.c:wait4()
		 * Reparent the process so that the tracing
		 *   proc gets to see all the action.
		 * Stop the target.
		 */
		t->p_opptr = t->p_pptr;
		if (t->p_pptr != p) {
			struct proc *parent = t->p_pptr;

			if (parent->p_lock < t->p_lock) {
				if (!mutex_tryenter(parent->p_lock)) {
					mutex_exit(t->p_lock);
					mutex_enter(parent->p_lock);
				}
			} else if (parent->p_lock > t->p_lock) {
				mutex_enter(parent->p_lock);
			}
			parent->p_slflag |= PSL_CHTRACED;
			proc_reparent(t, p);
			if (parent->p_lock != t->p_lock)
				mutex_exit(parent->p_lock);
		}
		SET(t->p_slflag, PSL_TRACED);
		signo = SIGSTOP;
		goto sendsig;

	case PT_LWPINFO:
		if (SCARG(uap, data) != sizeof(pl)) {
			error = EINVAL;
			break;
		}
		error = copyin(SCARG(uap, addr), &pl, sizeof(pl));
		if (error)
			break;
		tmp = pl.pl_lwpid;
		lwp_delref(lt);
		mutex_enter(t->p_lock);
		if (tmp == 0)
			lt = LIST_FIRST(&t->p_lwps);
		else {
			lt = lwp_find(t, tmp);
			if (lt == NULL) {
				mutex_exit(t->p_lock);
				error = ESRCH;
				break;
			}
			lt = LIST_NEXT(lt, l_sibling);
		}
		while (lt != NULL && lt->l_stat == LSZOMB)
			lt = LIST_NEXT(lt, l_sibling);
		pl.pl_lwpid = 0;
		pl.pl_event = 0;
		if (lt) {
			lwp_addref(lt);
			pl.pl_lwpid = lt->l_lid;
			if (lt->l_lid == t->p_sigctx.ps_lwp)
				pl.pl_event = PL_EVENT_SIGNAL;
		}
		mutex_exit(t->p_lock);

		error = copyout(&pl, SCARG(uap, addr), sizeof(pl));
		break;

#ifdef PT_SETREGS
	case  PT_SETREGS:
		write = 1;
#endif
#ifdef PT_GETREGS
	case  PT_GETREGS:
		/* write = 0 done above. */
#endif
#if defined(PT_SETREGS) || defined(PT_GETREGS)
		tmp = SCARG(uap, data);
		if (tmp != 0 && t->p_nlwps > 1) {
			lwp_delref(lt);
			mutex_enter(t->p_lock);
			lt = lwp_find(t, tmp);
			if (lt == NULL) {
				mutex_exit(t->p_lock);
				error = ESRCH;
				break;
			}
			lwp_addref(lt);
			mutex_exit(t->p_lock);
		}
		if (!process_validregs(lt))
			error = EINVAL;
		else {
			error = proc_vmspace_getref(l->l_proc, &vm);
			if (error)
				break;
			iov.iov_base = SCARG(uap, addr);
			iov.iov_len = sizeof(struct reg);
			uio.uio_iov = &iov;
			uio.uio_iovcnt = 1;
			uio.uio_offset = 0;
			uio.uio_resid = sizeof(struct reg);
			uio.uio_rw = write ? UIO_WRITE : UIO_READ;
			uio.uio_vmspace = vm;

			error = process_doregs(l, lt, &uio);
			uvmspace_free(vm);
		}
		break;
#endif

#ifdef PT_SETFPREGS
	case  PT_SETFPREGS:
		write = 1;
#endif
#ifdef PT_GETFPREGS
	case  PT_GETFPREGS:
		/* write = 0 done above. */
#endif
#if defined(PT_SETFPREGS) || defined(PT_GETFPREGS)
		tmp = SCARG(uap, data);
		if (tmp != 0 && t->p_nlwps > 1) {
			lwp_delref(lt);
			mutex_enter(t->p_lock);
			lt = lwp_find(t, tmp);
			if (lt == NULL) {
				mutex_exit(t->p_lock);
				error = ESRCH;
				break;
			}
			lwp_addref(lt);
			mutex_exit(t->p_lock);
		}
		if (!process_validfpregs(lt))
			error = EINVAL;
		else {
			error = proc_vmspace_getref(l->l_proc, &vm);
			if (error)
				break;
			iov.iov_base = SCARG(uap, addr);
			iov.iov_len = sizeof(struct fpreg);
			uio.uio_iov = &iov;
			uio.uio_iovcnt = 1;
			uio.uio_offset = 0;
			uio.uio_resid = sizeof(struct fpreg);
			uio.uio_rw = write ? UIO_WRITE : UIO_READ;
			uio.uio_vmspace = vm;

			error = process_dofpregs(l, lt, &uio);
			uvmspace_free(vm);
		}
		break;
#endif

#ifdef __HAVE_PTRACE_MACHDEP
	PTRACE_MACHDEP_REQUEST_CASES
		error = ptrace_machdep_dorequest(l, lt,
		    req, SCARG(uap, addr), SCARG(uap, data));
		break;
#endif
	}

	if (pheld) {
		mutex_exit(t->p_lock);
		mutex_exit(proc_lock);
	}
	if (lt != NULL)
		lwp_delref(lt);
	rw_exit(&t->p_reflock);

	return error;
}
Esempio n. 15
0
/*
 * General fork call.  Note that another LWP in the process may call exec()
 * or exit() while we are forking.  It's safe to continue here, because
 * neither operation will complete until all LWPs have exited the process.
 */
int
fork1(struct lwp *l1, int flags, int exitsig, void *stack, size_t stacksize,
    void (*func)(void *), void *arg, register_t *retval,
    struct proc **rnewprocp)
{
	struct proc	*p1, *p2, *parent;
	struct plimit   *p1_lim;
	uid_t		uid;
	struct lwp	*l2;
	int		count;
	vaddr_t		uaddr;
	int		tnprocs;
	int		tracefork;
	int		error = 0;

	p1 = l1->l_proc;
	uid = kauth_cred_getuid(l1->l_cred);
	tnprocs = atomic_inc_uint_nv(&nprocs);

	/*
	 * Although process entries are dynamically created, we still keep
	 * a global limit on the maximum number we will create.
	 */
	if (__predict_false(tnprocs >= maxproc))
		error = -1;
	else
		error = kauth_authorize_process(l1->l_cred,
		    KAUTH_PROCESS_FORK, p1, KAUTH_ARG(tnprocs), NULL, NULL);

	if (error) {
		static struct timeval lasttfm;
		atomic_dec_uint(&nprocs);
		if (ratecheck(&lasttfm, &fork_tfmrate))
			tablefull("proc", "increase kern.maxproc or NPROC");
		if (forkfsleep)
			kpause("forkmx", false, forkfsleep, NULL);
		return EAGAIN;
	}

	/*
	 * Enforce limits.
	 */
	count = chgproccnt(uid, 1);
	if (__predict_false(count > p1->p_rlimit[RLIMIT_NPROC].rlim_cur)) {
		if (kauth_authorize_process(l1->l_cred, KAUTH_PROCESS_RLIMIT,
		    p1, KAUTH_ARG(KAUTH_REQ_PROCESS_RLIMIT_BYPASS),
		    &p1->p_rlimit[RLIMIT_NPROC], KAUTH_ARG(RLIMIT_NPROC)) != 0) {
			(void)chgproccnt(uid, -1);
			atomic_dec_uint(&nprocs);
			if (forkfsleep)
				kpause("forkulim", false, forkfsleep, NULL);
			return EAGAIN;
		}
	}

	/*
	 * Allocate virtual address space for the U-area now, while it
	 * is still easy to abort the fork operation if we're out of
	 * kernel virtual address space.
	 */
	uaddr = uvm_uarea_alloc();
	if (__predict_false(uaddr == 0)) {
		(void)chgproccnt(uid, -1);
		atomic_dec_uint(&nprocs);
		return ENOMEM;
	}

	/*
	 * We are now committed to the fork.  From here on, we may
	 * block on resources, but resource allocation may NOT fail.
	 */

	/* Allocate new proc. */
	p2 = proc_alloc();

	/*
	 * Make a proc table entry for the new process.
	 * Start by zeroing the section of proc that is zero-initialized,
	 * then copy the section that is copied directly from the parent.
	 */
	memset(&p2->p_startzero, 0,
	    (unsigned) ((char *)&p2->p_endzero - (char *)&p2->p_startzero));
	memcpy(&p2->p_startcopy, &p1->p_startcopy,
	    (unsigned) ((char *)&p2->p_endcopy - (char *)&p2->p_startcopy));

	TAILQ_INIT(&p2->p_sigpend.sp_info);

	LIST_INIT(&p2->p_lwps);
	LIST_INIT(&p2->p_sigwaiters);

	/*
	 * Duplicate sub-structures as needed.
	 * Increase reference counts on shared objects.
	 * Inherit flags we want to keep.  The flags related to SIGCHLD
	 * handling are important in order to keep a consistent behaviour
	 * for the child after the fork.  If we are a 32-bit process, the
	 * child will be too.
	 */
	p2->p_flag =
	    p1->p_flag & (PK_SUGID | PK_NOCLDWAIT | PK_CLDSIGIGN | PK_32);
	p2->p_emul = p1->p_emul;
	p2->p_execsw = p1->p_execsw;

	if (flags & FORK_SYSTEM) {
		/*
		 * Mark it as a system process.  Set P_NOCLDWAIT so that
		 * children are reparented to init(8) when they exit.
		 * init(8) can easily wait them out for us.
		 */
		p2->p_flag |= (PK_SYSTEM | PK_NOCLDWAIT);
	}

	mutex_init(&p2->p_stmutex, MUTEX_DEFAULT, IPL_HIGH);
	mutex_init(&p2->p_auxlock, MUTEX_DEFAULT, IPL_NONE);
	rw_init(&p2->p_reflock);
	cv_init(&p2->p_waitcv, "wait");
	cv_init(&p2->p_lwpcv, "lwpwait");

	/*
	 * Share a lock between the processes if they are to share signal
	 * state: we must synchronize access to it.
	 */
	if (flags & FORK_SHARESIGS) {
		p2->p_lock = p1->p_lock;
		mutex_obj_hold(p1->p_lock);
	} else
		p2->p_lock = mutex_obj_alloc(MUTEX_DEFAULT, IPL_NONE);

	kauth_proc_fork(p1, p2);

	p2->p_raslist = NULL;
#if defined(__HAVE_RAS)
	ras_fork(p1, p2);
#endif

	/* bump references to the text vnode (for procfs) */
	p2->p_textvp = p1->p_textvp;
	if (p2->p_textvp)
		vref(p2->p_textvp);

	if (flags & FORK_SHAREFILES)
		fd_share(p2);
	else if (flags & FORK_CLEANFILES)
		p2->p_fd = fd_init(NULL);
	else
		p2->p_fd = fd_copy();

	/* XXX racy */
	p2->p_mqueue_cnt = p1->p_mqueue_cnt;

	if (flags & FORK_SHARECWD)
		cwdshare(p2);
	else
		p2->p_cwdi = cwdinit();

	/*
	 * Note: p_limit (rlimit stuff) is copy-on-write, so normally
	 * we just need increase pl_refcnt.
	 */
	p1_lim = p1->p_limit;
	if (!p1_lim->pl_writeable) {
		lim_addref(p1_lim);
		p2->p_limit = p1_lim;
	} else {
		p2->p_limit = lim_copy(p1_lim);
	}

	if (flags & FORK_PPWAIT) {
		/* Mark ourselves as waiting for a child. */
		l1->l_pflag |= LP_VFORKWAIT;
		p2->p_lflag = PL_PPWAIT;
		p2->p_vforklwp = l1;
	} else {
		p2->p_lflag = 0;
	}
	p2->p_sflag = 0;
	p2->p_slflag = 0;
	parent = (flags & FORK_NOWAIT) ? initproc : p1;
	p2->p_pptr = parent;
	p2->p_ppid = parent->p_pid;
	LIST_INIT(&p2->p_children);

	p2->p_aio = NULL;

#ifdef KTRACE
	/*
	 * Copy traceflag and tracefile if enabled.
	 * If not inherited, these were zeroed above.
	 */
	if (p1->p_traceflag & KTRFAC_INHERIT) {
		mutex_enter(&ktrace_lock);
		p2->p_traceflag = p1->p_traceflag;
		if ((p2->p_tracep = p1->p_tracep) != NULL)
			ktradref(p2);
		mutex_exit(&ktrace_lock);
	}
#endif

	/*
	 * Create signal actions for the child process.
	 */
	p2->p_sigacts = sigactsinit(p1, flags & FORK_SHARESIGS);
	mutex_enter(p1->p_lock);
	p2->p_sflag |=
	    (p1->p_sflag & (PS_STOPFORK | PS_STOPEXEC | PS_NOCLDSTOP));
	sched_proc_fork(p1, p2);
	mutex_exit(p1->p_lock);

	p2->p_stflag = p1->p_stflag;

	/*
	 * p_stats.
	 * Copy parts of p_stats, and zero out the rest.
	 */
	p2->p_stats = pstatscopy(p1->p_stats);

	/*
	 * Set up the new process address space.
	 */
	uvm_proc_fork(p1, p2, (flags & FORK_SHAREVM) ? true : false);

	/*
	 * Finish creating the child process.
	 * It will return through a different path later.
	 */
	lwp_create(l1, p2, uaddr, (flags & FORK_PPWAIT) ? LWP_VFORK : 0,
	    stack, stacksize, (func != NULL) ? func : child_return, arg, &l2,
	    l1->l_class);

	/*
	 * Inherit l_private from the parent.
	 * Note that we cannot use lwp_setprivate() here since that
	 * also sets the CPU TLS register, which is incorrect if the
	 * process has changed that without letting the kernel know.
	 */
	l2->l_private = l1->l_private;

	/*
	 * If emulation has a process fork hook, call it now.
	 */
	if (p2->p_emul->e_proc_fork)
		(*p2->p_emul->e_proc_fork)(p2, l1, flags);

	/*
	 * ...and finally, any other random fork hooks that subsystems
	 * might have registered.
	 */
	doforkhooks(p2, p1);

	SDT_PROBE(proc,,,create, p2, p1, flags, 0, 0);

	/*
	 * It's now safe for the scheduler and other processes to see the
	 * child process.
	 */
	mutex_enter(proc_lock);

	if (p1->p_session->s_ttyvp != NULL && p1->p_lflag & PL_CONTROLT)
		p2->p_lflag |= PL_CONTROLT;

	LIST_INSERT_HEAD(&parent->p_children, p2, p_sibling);
	p2->p_exitsig = exitsig;		/* signal for parent on exit */

	/*
	 * We don't want to tracefork vfork()ed processes because they
	 * will not receive the SIGTRAP until it is too late.
	 */
	tracefork = (p1->p_slflag & (PSL_TRACEFORK|PSL_TRACED)) ==
	    (PSL_TRACEFORK|PSL_TRACED) && (flags && FORK_PPWAIT) == 0;
	if (tracefork) {
		p2->p_slflag |= PSL_TRACED;
		p2->p_opptr = p2->p_pptr;
		if (p2->p_pptr != p1->p_pptr) {
			struct proc *parent1 = p2->p_pptr;

			if (parent1->p_lock < p2->p_lock) {
				if (!mutex_tryenter(parent1->p_lock)) {
					mutex_exit(p2->p_lock);
					mutex_enter(parent1->p_lock);
				}
			} else if (parent1->p_lock > p2->p_lock) {
				mutex_enter(parent1->p_lock);
			}
			parent1->p_slflag |= PSL_CHTRACED;
			proc_reparent(p2, p1->p_pptr);
			if (parent1->p_lock != p2->p_lock)
				mutex_exit(parent1->p_lock);
		}

		/*
		 * Set ptrace status.
		 */
		p1->p_fpid = p2->p_pid;
		p2->p_fpid = p1->p_pid;
	}

	LIST_INSERT_AFTER(p1, p2, p_pglist);
	LIST_INSERT_HEAD(&allproc, p2, p_list);

	p2->p_trace_enabled = trace_is_enabled(p2);
#ifdef __HAVE_SYSCALL_INTERN
	(*p2->p_emul->e_syscall_intern)(p2);
#endif

	/*
	 * Update stats now that we know the fork was successful.
	 */
	uvmexp.forks++;
	if (flags & FORK_PPWAIT)
		uvmexp.forks_ppwait++;
	if (flags & FORK_SHAREVM)
		uvmexp.forks_sharevm++;

	/*
	 * Pass a pointer to the new process to the caller.
	 */
	if (rnewprocp != NULL)
		*rnewprocp = p2;

	if (ktrpoint(KTR_EMUL))
		p2->p_traceflag |= KTRFAC_TRC_EMUL;

	/*
	 * Notify any interested parties about the new process.
	 */
	if (!SLIST_EMPTY(&p1->p_klist)) {
		mutex_exit(proc_lock);
		KNOTE(&p1->p_klist, NOTE_FORK | p2->p_pid);
		mutex_enter(proc_lock);
	}

	/*
	 * Make child runnable, set start time, and add to run queue except
	 * if the parent requested the child to start in SSTOP state.
	 */
	mutex_enter(p2->p_lock);

	/*
	 * Start profiling.
	 */
	if ((p2->p_stflag & PST_PROFIL) != 0) {
		mutex_spin_enter(&p2->p_stmutex);
		startprofclock(p2);
		mutex_spin_exit(&p2->p_stmutex);
	}

	getmicrotime(&p2->p_stats->p_start);
	p2->p_acflag = AFORK;
	lwp_lock(l2);
	KASSERT(p2->p_nrlwps == 1);
	if (p2->p_sflag & PS_STOPFORK) {
		struct schedstate_percpu *spc = &l2->l_cpu->ci_schedstate;
		p2->p_nrlwps = 0;
		p2->p_stat = SSTOP;
		p2->p_waited = 0;
		p1->p_nstopchild++;
		l2->l_stat = LSSTOP;
		KASSERT(l2->l_wchan == NULL);
		lwp_unlock_to(l2, spc->spc_lwplock);
	} else {
		p2->p_nrlwps = 1;
		p2->p_stat = SACTIVE;
		l2->l_stat = LSRUN;
		sched_enqueue(l2, false);
		lwp_unlock(l2);
	}

	/*
	 * Return child pid to parent process,
	 * marking us as parent via retval[1].
	 */
	if (retval != NULL) {
		retval[0] = p2->p_pid;
		retval[1] = 0;
	}
	mutex_exit(p2->p_lock);

	/*
	 * Preserve synchronization semantics of vfork.  If waiting for
	 * child to exec or exit, sleep until it clears LP_VFORKWAIT.
	 */
#if 0
	while (l1->l_pflag & LP_VFORKWAIT) {
		cv_wait(&l1->l_waitcv, proc_lock);
	}
#else
	while (p2->p_lflag & PL_PPWAIT)
		cv_wait(&p1->p_waitcv, proc_lock);
#endif

	/*
	 * Let the parent know that we are tracing its child.
	 */
	if (tracefork) {
		ksiginfo_t ksi;

		KSI_INIT_EMPTY(&ksi);
		ksi.ksi_signo = SIGTRAP;
		ksi.ksi_lid = l1->l_lid;
		kpsignal(p1, &ksi, NULL);
	}
	mutex_exit(proc_lock);

	return 0;
}