Beispiel #1
0
void XDebugServer::parseInput(folly::StringPiece in, String& cmd, Array& args) {
  // Always start with a blank array
  args = Array::Create();

  // Find the first space in the command. Everything before is assumed to be the
  // command string
  auto ptr = strchr(const_cast<char*>(in.data()), ' ');
  if (ptr != nullptr) {
    size_t size = ptr - in.data();
    cmd = String::attach(StringData::Make(in.data(), size, CopyString));
  } else if (in[0] != '\0') {
    // There are no spaces, the entire string is the command
    cmd = String::attach(StringData::Make(in.data(), CopyString));
    return;
  } else {
    throw_exn(Error::Parse);
  }

  // Loop starting after the space until the end of the string
  char opt;
  bool escaped = false;
  char* value = nullptr;
  ParseState state = ParseState::NORMAL;
  do {
    ptr++;
    switch (state) {
      // A new option which is prefixed with "-" is expected
      case ParseState::NORMAL:
        if (*ptr != '-') {
          throw_exn(Error::Parse);
        } else {
          state = ParseState::OPT_FOLLOWS;
        }
        break;
      // The option key follows
      case ParseState::OPT_FOLLOWS:
        opt = *ptr;
        state = ParseState::SEP_FOLLOWS;
        break;
      // Expect a " " separator to follow
      case ParseState::SEP_FOLLOWS:
        if (*ptr != ' ') {
          throw_exn(Error::Parse);
        } else {
          state = ParseState::VALUE_FOLLOWS_FIRST_CHAR;
          value = ptr + 1;
        }
        break;
      // Expect the option value's first character to follow. This character
      // could be either '"'or '-'
      case ParseState::VALUE_FOLLOWS_FIRST_CHAR:
        if (*ptr == '"' && opt != '-') {
          value = ptr + 1;
          state = ParseState::QUOTED;
        } else {
          state = ParseState::VALUE_FOLLOWS;
        }
        break;
      // The option's value should follow
      case ParseState::VALUE_FOLLOWS:
        if ((*ptr == ' ' && opt != '-') || *ptr == '\0') {
          if (args[opt].isNull()) {
            size_t size = ptr - value;
            StringData* val_data = StringData::Make(value, size, CopyString);
            args.set(opt, String::attach(val_data));
            state = ParseState::NORMAL;
          } else {
            throw_exn(Error::DupArg);
          }
        }
        break;
      // State when we are within a quoted string
      case ParseState::QUOTED:
        // if the quote is escaped, remain in ParseState::QUOTED.  This
        // will also handle other escaped chars, or an instance of
        // an escaped slash followed by a quote: \\"
        if (*ptr == '\\') {
          escaped = !escaped;
          break;
        } else if (*ptr != '"') {
          break;
        } else if (escaped) {
          escaped = false;
          break;
        }

        // Need to strip slashes before adding option
        if (args[opt].isNull()) {
          size_t size = ptr - value;
          StringData* val_data = StringData::Make(value, size, CopyString);
          args.set(opt, HHVM_FN(stripcslashes)(String::attach(val_data)));
          state = ParseState::SKIP_CHAR;
        } else {
          throw_exn(Error::DupArg);
        }
        break;
      // Do nothing
      case ParseState::SKIP_CHAR:
        state = ParseState::NORMAL;
        break;
    }
  } while (*ptr != '\0');
}
Beispiel #2
0
// Adding a breakpoint. Returns a unique id for the breakpoint.
int XDebugThreadBreakpoints::addBreakpoint(XDebugBreakpoint& bp) {
  auto const id = s_xdebug_breakpoints->m_nextBreakpointId;

  // php5 xdebug only accepts multiple breakpoints of the same type for
  // line breakpoints. A useful addition might be to allow multiple of all
  // types, but for now, multiple function or exception breakpoints results
  // in the most recent silently being used (matching php5 xdebug).
  switch (bp.type) {
    case BreakType::EXCEPTION: {
      // Remove duplicates then insert the name
      auto exceptionName = bp.exceptionName.toCppString();
      auto iter = EXCEPTION_MAP.find(exceptionName);
      if (iter != EXCEPTION_MAP.end()) {
        XDEBUG_REMOVE_BREAKPOINT(iter->second);
      }
      EXCEPTION_MAP[exceptionName] = id;
      break;
    }
    // Attempt to find the unit/line combo
    case BreakType::LINE: {
      const Unit* unit = find_unit(bp.fileName);
      if (unit == nullptr) {
        UNMATCHED.insert(id);
        break;
      }

      // If the file/line combo is invalid, throw an error
      if (!phpAddBreakPointLine(unit, bp.line)) {
        throw_exn(XDebugError::BreakpointInvalid);
      }
      add_line_breakpoint(id, bp, unit);
      break;
    }
    // Try to find the breakpoint's function
    case BreakType::CALL:
    case BreakType::RETURN: {
      const Class* cls = nullptr;
      const Func* func = nullptr;
      if (bp.className.isNull()) {
        func = Unit::lookupFunc(bp.funcName.get());
      } else {
        cls = Unit::lookupClass(bp.className.toString().get());
        if (cls != nullptr) {
          func = cls->lookupMethod(bp.funcName.get());
        }
      }

      // Either add the breakpoint or store it as unmatched. If the class
      // exists, we can verify that the method is valid.
      if (func != nullptr) {
        add_func_breakpoint(id, bp, func);
      } else if (!bp.className.isNull() && cls != nullptr) {
        throw_exn(XDebugError::BreakpointInvalid);
      } else {
        UNMATCHED.insert(id);
      }
      break;
    }
  }

  // Success, store the breakpoint and increment the id.
  BREAKPOINT_MAP[id] = bp;
  s_xdebug_breakpoints->m_nextBreakpointId++;
  return id;
}